feat(SW-3173): Added support for one or two columns for the list inside the RTE
Approved-by: Matilda Landström
This commit is contained in:
@@ -60,11 +60,8 @@
|
||||
|
||||
.ul,
|
||||
.ol {
|
||||
display: grid;
|
||||
gap: var(--Space-x1);
|
||||
padding: 0;
|
||||
margin-top: var(--Space-x2);
|
||||
margin-bottom: var(--Space-x2);
|
||||
margin: var(--Space-x2) 0;
|
||||
}
|
||||
|
||||
.ol > li::marker {
|
||||
@@ -73,16 +70,7 @@
|
||||
|
||||
.li {
|
||||
margin-left: var(--Space-x3);
|
||||
}
|
||||
|
||||
.heart > .li::before,
|
||||
.li:has(.heart)::before {
|
||||
content: url('/_static/icons/heart.svg');
|
||||
position: relative;
|
||||
height: 8px;
|
||||
top: 3px;
|
||||
margin-right: var(--Space-x1);
|
||||
margin-left: calc(var(--Space-x3) * -1);
|
||||
margin-bottom: var(--Space-x05);
|
||||
}
|
||||
|
||||
.heart > .li,
|
||||
@@ -90,16 +78,27 @@
|
||||
.li:has(.check),
|
||||
.li:has(.heart) {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.heart > .li::before,
|
||||
.li:has(.heart)::before,
|
||||
.check > .li::before,
|
||||
.li:has(.check)::before {
|
||||
position: relative;
|
||||
height: 8px;
|
||||
top: 3px;
|
||||
margin-right: var(--Space-x1);
|
||||
}
|
||||
|
||||
.check > .li::before,
|
||||
.li:has(.check)::before {
|
||||
content: url('/_static/icons/check-ring.svg');
|
||||
position: relative;
|
||||
height: 8px;
|
||||
top: 3px;
|
||||
margin-right: var(--Space-x1);
|
||||
margin-left: calc(var(--Space-x3) * -1);
|
||||
}
|
||||
|
||||
.heart > .li::before,
|
||||
.li:has(.heart)::before {
|
||||
content: url('/_static/icons/heart.svg');
|
||||
}
|
||||
|
||||
.li > p {
|
||||
@@ -127,17 +126,24 @@
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.ol:has(li:nth-last-child(n + 5)),
|
||||
.ul:has(li:nth-last-child(n + 5)) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-flow: column;
|
||||
.ol,
|
||||
.ul {
|
||||
&.two-column,
|
||||
&.two-columns,
|
||||
&:has(.two-column, .two-columns) {
|
||||
column-count: 2;
|
||||
column-gap: var(--Space-x3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@container sidebar (max-width: 360px) {
|
||||
.ol,
|
||||
.ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
&.two-column,
|
||||
&.two-columns,
|
||||
&:has(.two-column, .two-columns) {
|
||||
column-count: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import Table from '../Table'
|
||||
import { Typography } from '../Typography'
|
||||
|
||||
import {
|
||||
extractAvailableListClassNames,
|
||||
hasAvailableParagraphFormat,
|
||||
hasAvailableULFormat,
|
||||
makeCssModuleCompatibleClassName,
|
||||
} from './utils'
|
||||
|
||||
import styles from './jsontohtml.module.css'
|
||||
|
||||
import { insertResponseToImageVaultAsset } from './insertResponseToImageVaultAsset'
|
||||
import type { EmbedByUid } from './JsonToHtml'
|
||||
import type { Attributes, RTEImageVaultAttrs } from './types/rte/attrs'
|
||||
import {
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
type RTETextNode,
|
||||
} from './types/rte/node'
|
||||
import type { RenderOptions } from './types/rte/option'
|
||||
import { insertResponseToImageVaultAsset } from './insertResponseToImageVaultAsset'
|
||||
|
||||
function noNestedLinksOrReferences(node: RTENode) {
|
||||
if ('type' in node) {
|
||||
@@ -255,15 +254,12 @@ export const renderOptions: RenderOptions = {
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const { className, ...props } = extractPossibleAttributes(node.attrs)
|
||||
const compatibleClassName = makeCssModuleCompatibleClassName(
|
||||
className,
|
||||
'ul'
|
||||
)
|
||||
const compatibleClassNames = extractAvailableListClassNames(className)
|
||||
return (
|
||||
<li
|
||||
key={node.uid}
|
||||
{...props}
|
||||
className={cx(styles.li, compatibleClassName)}
|
||||
className={cx(styles.li, compatibleClassNames)}
|
||||
>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</li>
|
||||
@@ -277,26 +273,11 @@ export const renderOptions: RenderOptions = {
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const { className, ...props } = extractPossibleAttributes(node.attrs)
|
||||
|
||||
// Set the number of rows dynamically to create even rows for each column. We want the li:s
|
||||
// to flow with the column, so therefore this is needed.
|
||||
let numberOfRows: number | undefined
|
||||
if (node.children.length > 4) {
|
||||
const half = node.children.length / 2
|
||||
numberOfRows = Math.ceil(half)
|
||||
}
|
||||
const compatibleClassNames = extractAvailableListClassNames(className)
|
||||
|
||||
return (
|
||||
<Typography key={node.uid} variant="Body/Paragraph/mdRegular">
|
||||
<ol
|
||||
className={cx(styles.ol, className)}
|
||||
{...props}
|
||||
style={
|
||||
numberOfRows
|
||||
? { gridTemplateRows: `repeat(${numberOfRows}, auto)` }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<ol className={cx(styles.ol, compatibleClassNames)} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</ol>
|
||||
</Typography>
|
||||
@@ -340,8 +321,9 @@ export const renderOptions: RenderOptions = {
|
||||
let propsClassName = className
|
||||
|
||||
if (className) {
|
||||
if (hasAvailableULFormat(className)) {
|
||||
propsClassName = styles[className]
|
||||
const availableClassNames = extractAvailableListClassNames(className)
|
||||
if (availableClassNames.length) {
|
||||
propsClassName = cx(availableClassNames)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,8 +343,9 @@ export const renderOptions: RenderOptions = {
|
||||
let propsClassName = className
|
||||
|
||||
if (className) {
|
||||
if (hasAvailableULFormat(className)) {
|
||||
propsClassName = styles[className]
|
||||
const availableClassNames = extractAvailableListClassNames(className)
|
||||
if (availableClassNames.length) {
|
||||
propsClassName = cx(availableClassNames)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,32 +639,11 @@ export const renderOptions: RenderOptions = {
|
||||
fullRenderOptions: RenderOptions
|
||||
) => {
|
||||
const { className, ...props } = extractPossibleAttributes(node.attrs)
|
||||
const compatibleClassName = makeCssModuleCompatibleClassName(
|
||||
className,
|
||||
'ul'
|
||||
)
|
||||
|
||||
// Set the number of rows dynamically to create even rows for each column. We want the li:s
|
||||
// to flow with the column, so therefore this is needed.
|
||||
let numberOfRows: number | undefined
|
||||
if (node.children.length > 4) {
|
||||
const half = node.children.length / 2
|
||||
numberOfRows = Math.ceil(half)
|
||||
}
|
||||
const compatibleClassNames = extractAvailableListClassNames(className)
|
||||
|
||||
return (
|
||||
<Typography key={node.uid} variant="Body/Paragraph/mdRegular">
|
||||
<ul
|
||||
className={cx(styles.ul, compatibleClassName)}
|
||||
{...props}
|
||||
style={
|
||||
numberOfRows
|
||||
? {
|
||||
gridTemplateRows: `repeat(${numberOfRows}, auto)`,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<ul className={cx(styles.ul, compatibleClassNames)} {...props}>
|
||||
{next(node.children, embeds, fullRenderOptions)}
|
||||
</ul>
|
||||
</Typography>
|
||||
@@ -747,8 +709,9 @@ export const renderOptions: RenderOptions = {
|
||||
}
|
||||
|
||||
if (className) {
|
||||
if (hasAvailableULFormat(className)) {
|
||||
propsClassName = styles[className]
|
||||
const availableClassNames = extractAvailableListClassNames(className)
|
||||
if (availableClassNames.length) {
|
||||
propsClassName = cx(availableClassNames)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export const AVAILABLE_LIST_FORMATS = [
|
||||
'heart',
|
||||
'check',
|
||||
'two-column',
|
||||
'two-columns',
|
||||
]
|
||||
@@ -63,11 +63,6 @@ export enum AvailableParagraphFormatEnum {
|
||||
'subtitle-2' = 'subtitle-2',
|
||||
}
|
||||
|
||||
export enum AvailableULFormatEnum {
|
||||
'heart' = 'heart',
|
||||
'check' = 'check',
|
||||
}
|
||||
|
||||
export type ContentBlockType =
|
||||
| 'AccountPage'
|
||||
| 'CampaignOverviewPage'
|
||||
|
||||
@@ -4,13 +4,11 @@ import { renderOptions } from './renderOptions'
|
||||
|
||||
import styles from './jsontohtml.module.css'
|
||||
|
||||
import type { Node, Embeds } from './JsonToHtml'
|
||||
import type { Embeds, Node } from './JsonToHtml'
|
||||
|
||||
import {
|
||||
AvailableParagraphFormatEnum,
|
||||
AvailableULFormatEnum,
|
||||
RTETypeEnum,
|
||||
} from './types/rte/enums'
|
||||
import { EmbedByUid } from './JsonToHtml'
|
||||
import { AVAILABLE_LIST_FORMATS } from './types/rte/constants'
|
||||
import { AvailableParagraphFormatEnum, RTETypeEnum } from './types/rte/enums'
|
||||
import {
|
||||
RTEMarkType,
|
||||
type RTENode,
|
||||
@@ -19,7 +17,6 @@ import {
|
||||
type RTETextNode,
|
||||
} from './types/rte/node'
|
||||
import type { RenderOptions } from './types/rte/option'
|
||||
import { EmbedByUid } from './JsonToHtml'
|
||||
|
||||
export function groupEmbedsByUid(embedsArray: Node<Embeds>[]) {
|
||||
const embedsByUid = embedsArray.reduce<EmbedByUid>((acc, embed) => {
|
||||
@@ -109,11 +106,14 @@ export function hasAvailableParagraphFormat(className?: string) {
|
||||
return Object.keys(AvailableParagraphFormatEnum).includes(className)
|
||||
}
|
||||
|
||||
export function hasAvailableULFormat(className?: string) {
|
||||
export function extractAvailableListClassNames(className?: string) {
|
||||
if (!className) {
|
||||
return false
|
||||
return []
|
||||
}
|
||||
return Object.keys(AvailableULFormatEnum).includes(className)
|
||||
const classNames = className.split(' ')
|
||||
return classNames
|
||||
.filter((name) => AVAILABLE_LIST_FORMATS.includes(name))
|
||||
.map((item) => styles[item] || item)
|
||||
}
|
||||
|
||||
export function nodeToHtml(
|
||||
@@ -165,20 +165,3 @@ export function nodesToHtml(
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function makeCssModuleCompatibleClassName(
|
||||
className: string | undefined,
|
||||
formatType: 'ul'
|
||||
): string {
|
||||
if (!className) return ''
|
||||
|
||||
if (formatType === 'ul' && hasAvailableULFormat(className)) {
|
||||
// TODO: REMOVE
|
||||
// @ats-expect-error: We want to set css modules classNames even if it does not correspond
|
||||
// to an existing class in the module style sheet. Due to our css modules plugin for
|
||||
// typescript, we cannot do this without the ts-ignore
|
||||
return styles[className] || className
|
||||
}
|
||||
|
||||
return className
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user