@hubspot/cms-component-library 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/componentLibrary/Accordion/AccordionContent/ContentFields.tsx +5 -3
- package/components/componentLibrary/Accordion/AccordionItem/StyleFields.tsx +5 -3
- package/components/componentLibrary/Accordion/AccordionItem/index.module.scss +2 -2
- package/components/componentLibrary/Accordion/AccordionItem/index.tsx +3 -3
- package/components/componentLibrary/Accordion/AccordionTitle/ContentFields.tsx +5 -3
- package/components/componentLibrary/Accordion/AccordionTitle/index.module.scss +2 -2
- package/components/componentLibrary/Accordion/stories/Accordion.stories.tsx +80 -1
- package/components/componentLibrary/Accordion/stories/AccordionDecorator.tsx +14 -14
- package/components/componentLibrary/Button/ContentFields.tsx +5 -3
- package/components/componentLibrary/Button/StyleFields.tsx +5 -3
- package/components/componentLibrary/Button/index.module.scss +22 -14
- package/components/componentLibrary/Button/index.tsx +6 -6
- package/components/componentLibrary/Button/stories/Button.AsButton.stories.tsx +30 -1
- package/components/componentLibrary/Button/stories/Button.AsLink.stories.tsx +38 -1
- package/components/componentLibrary/Button/stories/ButtonDecorator.tsx +1 -1
- package/components/componentLibrary/Card/StyleFields.tsx +5 -3
- package/components/componentLibrary/Card/stories/Card.stories.tsx +46 -1
- package/components/componentLibrary/Card/stories/CardDecorator.tsx +1 -1
- package/components/componentLibrary/Divider/ContentFields.tsx +5 -3
- package/components/componentLibrary/Divider/StyleFields.tsx +5 -3
- package/components/componentLibrary/Divider/index.module.scss +6 -6
- package/components/componentLibrary/Divider/index.tsx +7 -3
- package/components/componentLibrary/Divider/stories/Divider.stories.tsx +44 -50
- package/components/componentLibrary/Divider/stories/{DividerDecorator.module.css → DividerDecorator.module.scss} +5 -4
- package/components/componentLibrary/Divider/stories/DividerDecorator.tsx +1 -1
- package/components/componentLibrary/Divider/types.ts +3 -1
- package/components/componentLibrary/Drawer/hooks/index.tsx +13 -0
- package/components/componentLibrary/Drawer/index.module.scss +94 -0
- package/components/componentLibrary/Drawer/index.tsx +131 -0
- package/components/componentLibrary/Drawer/llm.txt +416 -0
- package/components/componentLibrary/Drawer/stories/Drawer.stories.tsx +512 -0
- package/components/componentLibrary/Drawer/stories/DrawerDecorator.module.scss +8 -0
- package/components/componentLibrary/Drawer/stories/DrawerDecorator.tsx +18 -0
- package/components/componentLibrary/Drawer/types.ts +25 -0
- package/components/componentLibrary/Flex/stories/FlexDecorator.tsx +1 -1
- package/components/componentLibrary/Flex/types.ts +3 -1
- package/components/componentLibrary/Grid/stories/Grid.stories.tsx +454 -152
- package/components/componentLibrary/Grid/stories/GridDecorator.tsx +2 -2
- package/components/componentLibrary/Heading/ContentFields.tsx +5 -3
- package/components/componentLibrary/Heading/StyleFields.tsx +11 -9
- package/components/componentLibrary/Heading/index.tsx +3 -3
- package/components/componentLibrary/Heading/llm.txt +8 -8
- package/components/componentLibrary/Heading/stories/Heading.stories.tsx +3 -3
- package/components/componentLibrary/Heading/stories/HeadingDecorator.tsx +1 -1
- package/components/componentLibrary/Heading/types.ts +4 -4
- package/components/componentLibrary/Icon/ContentFields.tsx +5 -3
- package/components/componentLibrary/Icon/stories/Icon.stories.tsx +1 -1
- package/components/componentLibrary/Icon/stories/IconDecorator.tsx +1 -1
- package/components/componentLibrary/Image/ContentFields.tsx +5 -3
- package/components/componentLibrary/Image/index.tsx +4 -4
- package/components/componentLibrary/Image/llm.txt +17 -17
- package/components/componentLibrary/Image/stories/Image.stories.tsx +61 -18
- package/components/componentLibrary/Image/stories/ImageDecorator.tsx +1 -1
- package/components/componentLibrary/Image/types.ts +2 -2
- package/components/componentLibrary/LanguageSwitcher/ContentFields.tsx +18 -0
- package/components/componentLibrary/LanguageSwitcher/LanguageOptions.module.scss +37 -0
- package/components/componentLibrary/LanguageSwitcher/LanguageOptions.tsx +65 -0
- package/components/componentLibrary/LanguageSwitcher/StyleFields.tsx +48 -0
- package/components/componentLibrary/LanguageSwitcher/_dummyData.tsx +247 -0
- package/components/componentLibrary/LanguageSwitcher/assets/Globe.tsx +16 -0
- package/components/componentLibrary/LanguageSwitcher/index.module.scss +58 -0
- package/components/componentLibrary/LanguageSwitcher/index.tsx +125 -0
- package/components/componentLibrary/LanguageSwitcher/llm.txt +380 -0
- package/components/componentLibrary/LanguageSwitcher/stories/LanguageSwitcher.stories.tsx +349 -0
- package/components/componentLibrary/LanguageSwitcher/stories/LanguageSwitcherDecorator.module.scss +5 -0
- package/components/componentLibrary/LanguageSwitcher/stories/LanguageSwitcherDecorator.tsx +8 -0
- package/components/componentLibrary/LanguageSwitcher/types.ts +48 -0
- package/components/componentLibrary/LanguageSwitcher/utils.tsx +38 -0
- package/components/componentLibrary/Link/ContentFields.tsx +5 -3
- package/components/componentLibrary/Link/StyleFields.tsx +5 -3
- package/components/componentLibrary/Link/index.module.scss +10 -0
- package/components/componentLibrary/Link/index.tsx +24 -14
- package/components/componentLibrary/Link/stories/Link.stories.tsx +35 -5
- package/components/componentLibrary/Link/stories/LinkDecorator.tsx +11 -1
- package/components/componentLibrary/Link/types.ts +22 -13
- package/components/componentLibrary/List/ContentFields.tsx +5 -3
- package/components/componentLibrary/List/ListItem/ContentFields.tsx +6 -17
- package/components/componentLibrary/List/ListItem/index.module.scss +1 -13
- package/components/componentLibrary/List/ListItem/index.tsx +3 -30
- package/components/componentLibrary/List/ListItem/types.ts +1 -16
- package/components/componentLibrary/List/StyleFields.tsx +15 -18
- package/components/componentLibrary/List/index.module.scss +3 -0
- package/components/componentLibrary/List/index.tsx +5 -2
- package/components/componentLibrary/List/llm.txt +73 -103
- package/components/componentLibrary/List/stories/List.stories.tsx +56 -80
- package/components/componentLibrary/List/stories/ListDecorator.tsx +3 -6
- package/components/componentLibrary/List/types.ts +1 -3
- package/components/componentLibrary/Logo/_dummyLogoData.ts +12 -0
- package/components/componentLibrary/Logo/assets/hubspot-logo.png +0 -0
- package/components/componentLibrary/Logo/index.module.scss +22 -0
- package/components/componentLibrary/Logo/index.tsx +73 -0
- package/components/componentLibrary/Logo/llm.txt +262 -0
- package/components/componentLibrary/Logo/stories/Logo.stories.tsx +88 -0
- package/components/componentLibrary/Logo/stories/LogoDecorator.module.scss +10 -0
- package/components/componentLibrary/Logo/stories/LogoDecorator.tsx +8 -0
- package/components/componentLibrary/Logo/types.tsx +16 -0
- package/components/componentLibrary/Menu/ContentFields.tsx +16 -0
- package/components/componentLibrary/Menu/MenuItem/Chevron/index.module.scss +6 -0
- package/components/componentLibrary/Menu/MenuItem/Chevron/index.tsx +17 -0
- package/components/componentLibrary/Menu/MenuItem/index.module.scss +7 -0
- package/components/componentLibrary/Menu/MenuItem/index.tsx +266 -0
- package/components/componentLibrary/Menu/MenuItem/types.ts +17 -0
- package/components/componentLibrary/Menu/NavigationMenu/ContentFields.tsx +20 -0
- package/components/componentLibrary/Menu/NavigationMenu/index.tsx +18 -0
- package/components/componentLibrary/Menu/NavigationMenu/islands/NavigationMenuIsland.tsx +95 -0
- package/components/componentLibrary/Menu/NavigationMenu/islands/index.module.scss +100 -0
- package/components/componentLibrary/Menu/NavigationMenu/islands/types.ts +19 -0
- package/components/componentLibrary/Menu/NavigationMenu/llm.txt +197 -0
- package/components/componentLibrary/Menu/NavigationMenu/stories/NavigationMenu.stories.tsx +286 -0
- package/components/componentLibrary/Menu/NavigationMenu/stories/NavigationMenuDecorator.module.scss +15 -0
- package/components/componentLibrary/Menu/NavigationMenu/stories/NavigationMenuDecorator.tsx +12 -0
- package/components/componentLibrary/Menu/NavigationMenu/types.ts +3 -0
- package/components/componentLibrary/Menu/VerticalMenu/ContentFields.tsx +20 -0
- package/components/componentLibrary/Menu/VerticalMenu/index.tsx +18 -0
- package/components/componentLibrary/Menu/VerticalMenu/islands/index.module.scss +53 -0
- package/components/componentLibrary/Menu/VerticalMenu/islands/verticalMenuIsland.tsx +78 -0
- package/components/componentLibrary/Menu/VerticalMenu/llm.txt +177 -0
- package/components/componentLibrary/Menu/VerticalMenu/stories/VerticalMenu.stories.tsx +242 -0
- package/components/componentLibrary/Menu/VerticalMenu/stories/VerticalMenuDecorator.module.scss +19 -0
- package/components/componentLibrary/Menu/VerticalMenu/stories/VerticalMenuDecorator.tsx +12 -0
- package/components/componentLibrary/Menu/VerticalMenu/types.ts +21 -0
- package/components/componentLibrary/Menu/_dummyMenuData.js +1346 -0
- package/components/componentLibrary/Menu/types.ts +56 -0
- package/components/componentLibrary/Menu/utils/transformMenuData.ts +11 -0
- package/components/componentLibrary/_patterns/README.md +15 -17
- package/components/componentLibrary/_patterns/checklist-and-examples.md +17 -17
- package/components/componentLibrary/_patterns/component-structure.md +21 -23
- package/components/componentLibrary/_patterns/css-patterns.md +170 -18
- package/components/componentLibrary/_patterns/field-patterns.md +97 -27
- package/components/componentLibrary/_patterns/function-declaration-patterns.md +281 -0
- package/components/componentLibrary/_patterns/llm-txt.template.md +4 -2
- package/components/componentLibrary/_patterns/prop-naming-patterns.md +208 -0
- package/components/componentLibrary/_patterns/storybook-patterns.md +25 -8
- package/components/componentLibrary/_patterns/typescript-patterns.md +6 -3
- package/package.json +4 -2
- /package/components/componentLibrary/Button/stories/{ButtonDecorator.module.css → ButtonDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Card/stories/{CardDecorator.module.css → CardDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Flex/stories/{FlexDecorator.module.css → FlexDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Grid/stories/{GridDecorator.module.css → GridDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Heading/stories/{HeadingDecorator.module.css → HeadingDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Icon/stories/{IconDecorator.module.css → IconDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Image/stories/{ImageDecorator.module.css → ImageDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Image/stories/assets/{catSmile.jpg → cat-smile.jpg} +0 -0
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
import { LinkFieldDefaults } from '@hubspot/cms-components/fields';
|
|
2
2
|
import { LinkFieldValue } from '../utils/linkField.js';
|
|
3
3
|
|
|
4
|
-
type BaseLinkProps = {
|
|
4
|
+
export type BaseLinkProps = {
|
|
5
5
|
variant?: 'primary' | 'secondary' | 'tertiary';
|
|
6
6
|
className?: string;
|
|
7
7
|
style?: React.CSSProperties;
|
|
8
8
|
children?: React.ReactNode;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
rel
|
|
16
|
-
|
|
11
|
+
// added this so that TS doesn't get mad about duplicate properties
|
|
12
|
+
// since we want to enforce required props in some of these type definitions
|
|
13
|
+
export type LinkHTMLProps = Omit<
|
|
14
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
15
|
+
'href' | 'target' | 'rel' | 'className' | 'style' | 'children'
|
|
16
|
+
>;
|
|
17
17
|
|
|
18
|
-
type
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
type LinkWithField = BaseLinkProps &
|
|
19
|
+
LinkHTMLProps & {
|
|
20
|
+
linkField: LinkFieldValue;
|
|
21
|
+
href?: never;
|
|
22
|
+
target?: never;
|
|
23
|
+
rel?: never;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type LinkWithoutField = BaseLinkProps &
|
|
27
|
+
LinkHTMLProps & {
|
|
28
|
+
linkField?: never;
|
|
29
|
+
href: string;
|
|
30
|
+
target?: '_self' | '_blank' | '_parent' | '_top';
|
|
31
|
+
rel?: string;
|
|
32
|
+
};
|
|
24
33
|
|
|
25
34
|
export type LinkProps = LinkWithField | LinkWithoutField;
|
|
26
35
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ChoiceField } from '@hubspot/cms-components/fields';
|
|
2
2
|
import type { ContentFieldsProps } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const ContentFields = ({
|
|
5
5
|
listTypeName = 'listType',
|
|
6
6
|
listTypeLabel = 'List type',
|
|
7
7
|
listTypeDefault = 'unordered',
|
|
8
|
-
}: ContentFieldsProps) {
|
|
8
|
+
}: ContentFieldsProps) => {
|
|
9
9
|
return (
|
|
10
10
|
<ChoiceField
|
|
11
11
|
label={listTypeLabel}
|
|
@@ -17,4 +17,6 @@ export default function ContentFields({
|
|
|
17
17
|
]}
|
|
18
18
|
/>
|
|
19
19
|
);
|
|
20
|
-
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default ContentFields;
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import { TextField } from '@hubspot/cms-components/fields';
|
|
2
2
|
import type { ContentFieldsProps } from './types.js';
|
|
3
|
-
import Icon from '../../Icon/index.js';
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
const ContentFields = ({
|
|
6
5
|
textName = 'text',
|
|
7
6
|
textLabel = 'Item text',
|
|
8
7
|
textDefault = 'Add a list item here.',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<>
|
|
15
|
-
<TextField label={textLabel} name={textName} default={textDefault} />
|
|
16
|
-
<Icon.ContentFields
|
|
17
|
-
iconName={iconName}
|
|
18
|
-
iconLabel={iconLabel}
|
|
19
|
-
iconDefault={iconDefault}
|
|
20
|
-
/>
|
|
21
|
-
</>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
8
|
+
}: ContentFieldsProps) => {
|
|
9
|
+
return <TextField label={textLabel} name={textName} default={textDefault} />;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default ContentFields;
|
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
.listItem {
|
|
2
|
-
|
|
3
|
-
align-items: flex-start;
|
|
4
|
-
column-gap: 8px;
|
|
5
|
-
color: var(--hscl-list-item-text-color);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.listItemContent {
|
|
9
|
-
flex: 1;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.listItemDefault {
|
|
13
|
-
display: list-item;
|
|
14
|
-
color: var(--hscl-list-item-text-color);
|
|
2
|
+
color: var(--hscl-list-item-color);
|
|
15
3
|
}
|
|
16
4
|
|
|
@@ -2,45 +2,18 @@ import styles from './index.module.scss';
|
|
|
2
2
|
import ContentFields from './ContentFields.js';
|
|
3
3
|
import cx from '../../utils/classname.js';
|
|
4
4
|
import { ListItemProps } from './types.js';
|
|
5
|
-
import Icon from '../../Icon/index.js';
|
|
6
5
|
|
|
7
6
|
const ListItemComponent = ({
|
|
8
|
-
children
|
|
9
|
-
index,
|
|
10
|
-
itemsFieldPath,
|
|
11
|
-
iconName = 'icon',
|
|
12
|
-
iconSize = 16,
|
|
13
|
-
iconFill,
|
|
14
|
-
showIcon = true,
|
|
15
|
-
iconPurpose = 'DECORATIVE',
|
|
16
|
-
iconTitle,
|
|
7
|
+
children,
|
|
17
8
|
className = '',
|
|
18
9
|
style = {},
|
|
19
10
|
...rest
|
|
20
11
|
}: ListItemProps) => {
|
|
21
|
-
const
|
|
22
|
-
const combinedClasses = cx(itemClass, className);
|
|
23
|
-
|
|
24
|
-
const iconFieldPath =
|
|
25
|
-
itemsFieldPath && index !== undefined
|
|
26
|
-
? `${itemsFieldPath}[${index}].${iconName}`
|
|
27
|
-
: undefined;
|
|
12
|
+
const combinedClasses = cx(styles.listItem, className);
|
|
28
13
|
|
|
29
14
|
return (
|
|
30
15
|
<li className={combinedClasses} style={style} {...rest}>
|
|
31
|
-
{
|
|
32
|
-
<div>
|
|
33
|
-
<Icon
|
|
34
|
-
fieldPath={iconFieldPath}
|
|
35
|
-
height={iconSize}
|
|
36
|
-
fill={iconFill}
|
|
37
|
-
showIcon={showIcon}
|
|
38
|
-
purpose={iconPurpose}
|
|
39
|
-
title={iconTitle}
|
|
40
|
-
/>
|
|
41
|
-
</div>
|
|
42
|
-
)}
|
|
43
|
-
<span className={styles.listItemContent}>{children}</span>
|
|
16
|
+
{children}
|
|
44
17
|
</li>
|
|
45
18
|
);
|
|
46
19
|
};
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
TextFieldDefaults,
|
|
3
|
-
IconFieldDefaults,
|
|
4
|
-
} from '@hubspot/cms-components/fields';
|
|
5
|
-
import type { IconPurpose } from '../../Icon/types.js';
|
|
1
|
+
import { TextFieldDefaults } from '@hubspot/cms-components/fields';
|
|
6
2
|
|
|
7
3
|
export type ListItemProps = {
|
|
8
4
|
children?: React.ReactNode;
|
|
9
|
-
index?: number;
|
|
10
|
-
itemsFieldPath?: string;
|
|
11
|
-
iconName?: string;
|
|
12
|
-
iconSize?: number;
|
|
13
|
-
iconFill?: string;
|
|
14
|
-
showIcon?: boolean;
|
|
15
|
-
iconPurpose?: IconPurpose;
|
|
16
|
-
iconTitle?: string;
|
|
17
5
|
className?: string;
|
|
18
6
|
style?: React.CSSProperties;
|
|
19
7
|
};
|
|
@@ -22,7 +10,4 @@ export type ContentFieldsProps = {
|
|
|
22
10
|
textName?: string;
|
|
23
11
|
textLabel?: string;
|
|
24
12
|
textDefault?: typeof TextFieldDefaults;
|
|
25
|
-
iconName?: string;
|
|
26
|
-
iconLabel?: string;
|
|
27
|
-
iconDefault?: typeof IconFieldDefaults;
|
|
28
13
|
};
|
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
import { ChoiceField } from '@hubspot/cms-components/fields';
|
|
2
2
|
import type { StyleFieldsProps } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const StyleFields = ({
|
|
5
5
|
variantName = 'variant',
|
|
6
6
|
variantLabel = 'Variant',
|
|
7
7
|
variantDefault = 'primary',
|
|
8
|
-
|
|
9
|
-
gapLabel = 'Gap',
|
|
10
|
-
gapDefault = '0px',
|
|
11
|
-
}: StyleFieldsProps) {
|
|
8
|
+
}: StyleFieldsProps) => {
|
|
12
9
|
return (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/>
|
|
24
|
-
</>
|
|
10
|
+
<ChoiceField
|
|
11
|
+
label={variantLabel}
|
|
12
|
+
name={variantName}
|
|
13
|
+
default={variantDefault}
|
|
14
|
+
choices={[
|
|
15
|
+
['primary', 'Primary'],
|
|
16
|
+
['secondary', 'Secondary'],
|
|
17
|
+
['tertiary', 'Tertiary'],
|
|
18
|
+
]}
|
|
19
|
+
/>
|
|
25
20
|
);
|
|
26
|
-
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default StyleFields;
|
|
@@ -11,18 +11,21 @@ const ListComponent = ({
|
|
|
11
11
|
listType = 'unordered',
|
|
12
12
|
variant = 'primary',
|
|
13
13
|
gap = '0px',
|
|
14
|
+
showMarker = true,
|
|
14
15
|
className = '',
|
|
15
16
|
style = {},
|
|
16
17
|
children,
|
|
17
18
|
...rest
|
|
18
19
|
}: ListProps) => {
|
|
19
20
|
const ListTag = listType === 'ordered' ? 'ol' : 'ul';
|
|
20
|
-
const defaultClasses = cx(styles.list
|
|
21
|
+
const defaultClasses = cx(styles.list, {
|
|
22
|
+
[styles.noMarker]: !showMarker,
|
|
23
|
+
});
|
|
21
24
|
const combinedClasses = cx(defaultClasses, className);
|
|
22
25
|
|
|
23
26
|
// !todo: placeholder values until we work out how variant system works.
|
|
24
27
|
const cssVariables: CSSVariables = {
|
|
25
|
-
'--hscl-list-item-
|
|
28
|
+
'--hscl-list-item-color': `var(--hscl-listItem-color-${variant})`,
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
return (
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# List Component
|
|
2
2
|
|
|
3
|
-
A flexible list component that renders ordered (`<ol>`) or unordered (`<ul>`) lists with customizable spacing, variants, and
|
|
3
|
+
A flexible list component that renders ordered (`<ol>`) or unordered (`<ul>`) lists with customizable spacing, variants, and marker visibility.
|
|
4
4
|
|
|
5
5
|
## Import path
|
|
6
6
|
```tsx
|
|
@@ -9,7 +9,7 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
9
9
|
|
|
10
10
|
## Purpose
|
|
11
11
|
|
|
12
|
-
The List component provides a consistent way to render lists in HubSpot CMS projects. It combines the semantic correctness of native HTML list elements with the flexibility of the Flex component for layout control. The component supports both ordered (numbered) and unordered (bulleted) lists, with
|
|
12
|
+
The List component provides a consistent way to render lists in HubSpot CMS projects. It combines the semantic correctness of native HTML list elements with the flexibility of the Flex component for layout control. The component supports both ordered (numbered) and unordered (bulleted) lists, with configurable marker visibility.
|
|
13
13
|
|
|
14
14
|
## Compositional Component Pattern
|
|
15
15
|
|
|
@@ -21,15 +21,15 @@ The List component follows a **parent/child compositional pattern**, consisting
|
|
|
21
21
|
| `ListItem` | Child | `<li>` |
|
|
22
22
|
|
|
23
23
|
**Why this pattern?**
|
|
24
|
-
- **Separation of concerns**: List handles container semantics (ordered vs unordered, gap, variant), while ListItem handles individual item presentation
|
|
25
|
-
- **Flexibility**:
|
|
24
|
+
- **Separation of concerns**: List handles container semantics (ordered vs unordered, gap, variant, marker visibility), while ListItem handles individual item presentation
|
|
25
|
+
- **Flexibility**: Modules can pass any content as children to ListItem, including custom icons
|
|
26
26
|
- **HubSpot CMS integration**: Each component has its own field definitions, allowing RepeatedGroup usage for dynamic lists
|
|
27
27
|
- **Type safety**: Props are scoped to their respective components, preventing invalid configurations
|
|
28
28
|
|
|
29
29
|
**Key relationships:**
|
|
30
30
|
- ListItem should **always** be used inside a List component
|
|
31
|
-
- List passes layout context (gap, variant styling) to children via CSS
|
|
32
|
-
- ListItem
|
|
31
|
+
- List passes layout context (gap, variant styling, marker visibility) to children via CSS
|
|
32
|
+
- ListItem renders children directly in the `<li>` element
|
|
33
33
|
|
|
34
34
|
This pattern is distinct from the "Compound Component Pattern" (e.g., `Button.ContentFields`) which attaches field definitions—List uses *both* patterns together.
|
|
35
35
|
|
|
@@ -40,12 +40,12 @@ List/
|
|
|
40
40
|
├── index.tsx # Main List component with render logic
|
|
41
41
|
├── types.ts # TypeScript type definitions
|
|
42
42
|
├── ContentFields.tsx # HubSpot field definitions for list type
|
|
43
|
-
├── StyleFields.tsx # HubSpot field definitions for variant
|
|
43
|
+
├── StyleFields.tsx # HubSpot field definitions for variant and marker
|
|
44
44
|
├── index.module.scss # CSS module for list styling
|
|
45
45
|
├── ListItem/
|
|
46
46
|
│ ├── index.tsx # ListItem component
|
|
47
47
|
│ ├── types.ts # ListItem TypeScript types
|
|
48
|
-
│ ├── ContentFields.tsx # HubSpot field definitions for list
|
|
48
|
+
│ ├── ContentFields.tsx # HubSpot field definitions for list item text
|
|
49
49
|
│ └── index.module.scss # CSS module for list item styling
|
|
50
50
|
└── stories/
|
|
51
51
|
├── List.stories.tsx # Storybook examples
|
|
@@ -65,6 +65,7 @@ List/
|
|
|
65
65
|
listType?: 'ordered' | 'unordered'; // List type - 'ordered' renders <ol>, 'unordered' renders <ul>
|
|
66
66
|
variant?: 'primary' | 'secondary' | 'tertiary'; // Visual style variant
|
|
67
67
|
gap?: string; // Space between list items (any valid CSS length value, e.g., '16px', '1rem', '0')
|
|
68
|
+
showMarker?: boolean; // Show list markers (bullets/numbers) - default: true
|
|
68
69
|
className?: string; // Additional CSS classes
|
|
69
70
|
style?: CSSVariables; // Inline styles (including CSS custom properties)
|
|
70
71
|
children?: React.ReactNode; // ListItem components
|
|
@@ -73,20 +74,12 @@ List/
|
|
|
73
74
|
|
|
74
75
|
### ListItem (Child Component)
|
|
75
76
|
|
|
76
|
-
**Purpose:** Individual list item component that renders an `<li>` element
|
|
77
|
+
**Purpose:** Individual list item component that renders an `<li>` element. Children are rendered directly inside the `<li>`.
|
|
77
78
|
|
|
78
79
|
**Props:**
|
|
79
80
|
```tsx
|
|
80
81
|
{
|
|
81
|
-
children?: React.ReactNode; // List item content (text, elements, etc.)
|
|
82
|
-
index?: number; // Item index (for field path generation)
|
|
83
|
-
itemsFieldPath?: string; // Parent field path for icon lookup
|
|
84
|
-
iconName?: string; // Field name for icon (default: 'icon')
|
|
85
|
-
iconSize?: number; // Icon size in pixels (default: 16)
|
|
86
|
-
iconFill?: string; // Icon fill color
|
|
87
|
-
showIcon?: boolean; // Toggle icon visibility (default: true)
|
|
88
|
-
iconPurpose?: 'SEMANTIC' | 'DECORATIVE'; // Icon accessibility role (defaults to 'DECORATIVE')
|
|
89
|
-
iconTitle?: string; // Icon title for screen readers
|
|
82
|
+
children?: React.ReactNode; // List item content (text, elements, icons, etc.)
|
|
90
83
|
className?: string; // Additional CSS classes
|
|
91
84
|
style?: React.CSSProperties; // Inline styles
|
|
92
85
|
}
|
|
@@ -100,9 +93,9 @@ List/
|
|
|
100
93
|
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
101
94
|
|
|
102
95
|
<List listType="unordered" variant="primary">
|
|
103
|
-
<ListItem
|
|
104
|
-
<ListItem
|
|
105
|
-
<ListItem
|
|
96
|
+
<ListItem>First item</ListItem>
|
|
97
|
+
<ListItem>Second item</ListItem>
|
|
98
|
+
<ListItem>Third item</ListItem>
|
|
106
99
|
</List>
|
|
107
100
|
```
|
|
108
101
|
|
|
@@ -112,9 +105,21 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
112
105
|
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
113
106
|
|
|
114
107
|
<List listType="ordered" variant="primary">
|
|
115
|
-
<ListItem
|
|
116
|
-
<ListItem
|
|
117
|
-
<ListItem
|
|
108
|
+
<ListItem>Step one</ListItem>
|
|
109
|
+
<ListItem>Step two</ListItem>
|
|
110
|
+
<ListItem>Step three</ListItem>
|
|
111
|
+
</List>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### List without Markers
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
118
|
+
|
|
119
|
+
<List listType="unordered" variant="primary" showMarker={false}>
|
|
120
|
+
<ListItem>Item without bullet</ListItem>
|
|
121
|
+
<ListItem>Another item without bullet</ListItem>
|
|
122
|
+
<ListItem>Third item without bullet</ListItem>
|
|
118
123
|
</List>
|
|
119
124
|
```
|
|
120
125
|
|
|
@@ -124,37 +129,28 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
124
129
|
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
125
130
|
|
|
126
131
|
<List listType="unordered" variant="primary" gap="1rem">
|
|
127
|
-
<ListItem
|
|
128
|
-
<ListItem
|
|
129
|
-
<ListItem
|
|
132
|
+
<ListItem>Spaced item one</ListItem>
|
|
133
|
+
<ListItem>Spaced item two</ListItem>
|
|
134
|
+
<ListItem>Spaced item three</ListItem>
|
|
130
135
|
</List>
|
|
131
136
|
```
|
|
132
137
|
|
|
133
|
-
### List Items with Icons
|
|
138
|
+
### List Items with Custom Content (Icons)
|
|
139
|
+
|
|
140
|
+
When you need icons or custom content in list items, set `showMarker={false}` to hide bullets/numbers, then handle your own layout:
|
|
134
141
|
|
|
135
142
|
```tsx
|
|
136
143
|
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
144
|
+
import Icon from '@hubspot/cms-component-library/Icon';
|
|
137
145
|
|
|
138
|
-
<List listType="unordered" variant="primary">
|
|
139
|
-
<ListItem
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
iconSize={20}
|
|
143
|
-
itemsFieldPath="items"
|
|
144
|
-
index={0}
|
|
145
|
-
iconPurpose="DECORATIVE"
|
|
146
|
-
>
|
|
147
|
-
Item with icon
|
|
146
|
+
<List listType="unordered" variant="primary" showMarker={false} gap="0.5rem">
|
|
147
|
+
<ListItem style={{ display: 'flex', gap: '8px', alignItems: 'flex-start' }}>
|
|
148
|
+
<Icon name="check" size={16} />
|
|
149
|
+
<span>Item with custom icon</span>
|
|
148
150
|
</ListItem>
|
|
149
|
-
<ListItem
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
iconSize={20}
|
|
153
|
-
itemsFieldPath="items"
|
|
154
|
-
index={1}
|
|
155
|
-
iconPurpose="DECORATIVE"
|
|
156
|
-
>
|
|
157
|
-
Another item with icon
|
|
151
|
+
<ListItem style={{ display: 'flex', gap: '8px', alignItems: 'flex-start' }}>
|
|
152
|
+
<Icon name="check" size={16} />
|
|
153
|
+
<span>Another item with icon</span>
|
|
158
154
|
</ListItem>
|
|
159
155
|
</List>
|
|
160
156
|
```
|
|
@@ -171,7 +167,7 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
171
167
|
className="custom-list-class"
|
|
172
168
|
style={{ maxWidth: '500px' }}
|
|
173
169
|
>
|
|
174
|
-
<ListItem
|
|
170
|
+
<ListItem>Custom styled item</ListItem>
|
|
175
171
|
</List>
|
|
176
172
|
```
|
|
177
173
|
|
|
@@ -198,18 +194,22 @@ Configurable props for list type selection:
|
|
|
198
194
|
|
|
199
195
|
#### List.StyleFields
|
|
200
196
|
|
|
201
|
-
Configurable props for variant selection:
|
|
197
|
+
Configurable props for variant and marker selection:
|
|
202
198
|
|
|
203
199
|
```tsx
|
|
204
200
|
<List.StyleFields
|
|
205
201
|
variantName="variant"
|
|
206
202
|
variantLabel="Variant"
|
|
207
203
|
variantDefault="primary"
|
|
204
|
+
showMarkerName="showMarker"
|
|
205
|
+
showMarkerLabel="Show list markers"
|
|
206
|
+
showMarkerDefault={true}
|
|
208
207
|
/>
|
|
209
208
|
```
|
|
210
209
|
|
|
211
210
|
**Fields:**
|
|
212
211
|
- `variant`: ChoiceField for selecting visual style (primary, secondary, tertiary)
|
|
212
|
+
- `showMarker`: BooleanField for toggling marker visibility
|
|
213
213
|
|
|
214
214
|
**Note:** Gap must be set directly via the `gap` prop on the List component, as there is no field definition for it in StyleFields.
|
|
215
215
|
|
|
@@ -222,15 +222,11 @@ Configurable props for list item content:
|
|
|
222
222
|
textName="text"
|
|
223
223
|
textLabel="Item text"
|
|
224
224
|
textDefault="Add a list item here."
|
|
225
|
-
iconName="icon"
|
|
226
|
-
iconLabel="Icon"
|
|
227
|
-
iconDefault={{ name: 'check', unicode: 'f00c', type: 'SOLID' }} // FontAwesome icon set
|
|
228
225
|
/>
|
|
229
226
|
```
|
|
230
227
|
|
|
231
228
|
**Fields:**
|
|
232
229
|
- `text`: TextField for list item text content
|
|
233
|
-
- `icon`: Icon field using Icon.ContentFields
|
|
234
230
|
|
|
235
231
|
### Module Usage Example
|
|
236
232
|
|
|
@@ -244,6 +240,7 @@ type FeatureListModuleProps = {
|
|
|
244
240
|
style?: {
|
|
245
241
|
variant?: 'primary' | 'secondary' | 'tertiary';
|
|
246
242
|
gap?: GapValue;
|
|
243
|
+
showMarker?: boolean;
|
|
247
244
|
};
|
|
248
245
|
listItems?: Array<{
|
|
249
246
|
text?: string;
|
|
@@ -257,22 +254,17 @@ export const Component = ({
|
|
|
257
254
|
}: FeatureListModuleProps) => {
|
|
258
255
|
const variant = style?.variant ?? 'primary';
|
|
259
256
|
const gap = style?.gap ?? '0px';
|
|
257
|
+
const showMarker = style?.showMarker ?? true;
|
|
260
258
|
|
|
261
259
|
return (
|
|
262
260
|
<List
|
|
263
261
|
listType={listType}
|
|
264
262
|
variant={variant}
|
|
265
263
|
gap={gap}
|
|
264
|
+
showMarker={showMarker}
|
|
266
265
|
>
|
|
267
266
|
{listItems.map(({ text }, index) => (
|
|
268
|
-
<ListItem
|
|
269
|
-
key={index}
|
|
270
|
-
index={index}
|
|
271
|
-
itemsFieldPath="listItems"
|
|
272
|
-
iconFill={`var(--hscl-listItem-iconColor-${variant})`}
|
|
273
|
-
>
|
|
274
|
-
{text}
|
|
275
|
-
</ListItem>
|
|
267
|
+
<ListItem key={index}>{text}</ListItem>
|
|
276
268
|
))}
|
|
277
269
|
</List>
|
|
278
270
|
);
|
|
@@ -299,7 +291,6 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
299
291
|
|
|
300
292
|
const defaultItem = {
|
|
301
293
|
text: 'Add a list item here.',
|
|
302
|
-
icon: { name: 'check', unicode: 'f00c', type: 'SOLID' }, // FontAwesome icon set
|
|
303
294
|
};
|
|
304
295
|
|
|
305
296
|
export const fields = (
|
|
@@ -342,11 +333,6 @@ The List component uses CSS variables for theming and customization:
|
|
|
342
333
|
- `--hscl-listItem-textColor-secondary`: Secondary variant text color
|
|
343
334
|
- `--hscl-listItem-textColor-tertiary`: Tertiary variant text color
|
|
344
335
|
|
|
345
|
-
**List Item Icon:**
|
|
346
|
-
- `--hscl-listItem-iconColor-primary`: Primary variant icon color
|
|
347
|
-
- `--hscl-listItem-iconColor-secondary`: Secondary variant icon color
|
|
348
|
-
- `--hscl-listItem-iconColor-tertiary`: Tertiary variant icon color
|
|
349
|
-
|
|
350
336
|
### Custom Styling Example
|
|
351
337
|
|
|
352
338
|
```tsx
|
|
@@ -359,7 +345,7 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
359
345
|
'--hscl-list-item-text-color': '#333333',
|
|
360
346
|
}}
|
|
361
347
|
>
|
|
362
|
-
<ListItem
|
|
348
|
+
<ListItem>Custom colored item</ListItem>
|
|
363
349
|
</List>
|
|
364
350
|
```
|
|
365
351
|
|
|
@@ -367,12 +353,12 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
367
353
|
|
|
368
354
|
**List (`index.module.scss`):**
|
|
369
355
|
- `.list`: Base list styles (removes default padding/margin, positions bullets inside)
|
|
356
|
+
- `.withMarker`: Applies `display: list-item` to children (shows bullets/numbers)
|
|
357
|
+
- `.noMarker`: Applies `list-style: none` (hides markers—modules handle their own internal layout)
|
|
370
358
|
- Nested `.list`: Indented styling for nested lists
|
|
371
359
|
|
|
372
360
|
**ListItem (`ListItem/index.module.scss`):**
|
|
373
|
-
- `.listItem`:
|
|
374
|
-
- `.listItemDefault`: Standard list-item display for items without icons
|
|
375
|
-
- `.listItemContent`: Flex content wrapper
|
|
361
|
+
- `.listItem`: Base list item styles with text color
|
|
376
362
|
|
|
377
363
|
## Accessibility
|
|
378
364
|
|
|
@@ -380,45 +366,36 @@ The List component follows accessibility best practices:
|
|
|
380
366
|
|
|
381
367
|
- **Semantic HTML**: Renders appropriate elements (`<ol>` for ordered, `<ul>` for unordered)
|
|
382
368
|
- **List Semantics**: Proper `<li>` elements maintain screen reader list navigation
|
|
383
|
-
- **Icon Accessibility**:
|
|
384
|
-
- `iconPurpose="SEMANTIC"`: Icon conveys meaning (includes accessible title)
|
|
385
|
-
- `iconPurpose="DECORATIVE"`: Icon is visual only (aria-hidden)
|
|
386
|
-
- `iconTitle` provides screen reader description for semantic icons
|
|
387
369
|
- **Keyboard Navigation**: Native list keyboard navigation is preserved
|
|
388
370
|
- **Content Structure**: Lists help screen reader users understand grouped content
|
|
389
371
|
|
|
390
372
|
## Best Practices
|
|
391
373
|
|
|
392
374
|
- **Choose the right list type**: Use `ordered` for sequential steps or rankings, `unordered` for non-sequential items
|
|
393
|
-
- **
|
|
394
|
-
- **showIcon prop**: Set `showIcon={false}` to use default bullet/number styling, `showIcon={true}` for custom icons
|
|
375
|
+
- **Marker visibility**: Use `showMarker={true}` (default) for standard lists, `showMarker={false}` when providing custom markers or icons as children
|
|
395
376
|
- **Consistent variants**: Use the same variant across related lists for visual consistency
|
|
396
377
|
- **Gap selection**: Use any valid CSS length value (e.g., '0', '0.5rem', '1rem', '16px') for spacing between items
|
|
397
378
|
- **Dynamic rendering**: Always provide unique `key` props when mapping arrays to ListItems
|
|
398
379
|
- **CSS Variables**: Override design tokens using CSS variables rather than hardcoding values
|
|
399
|
-
- **
|
|
380
|
+
- **Custom icons**: When using custom icons, set `showMarker={false}` and pass icons as part of ListItem children
|
|
381
|
+
- **Custom content layout**: When using `showMarker={false}`, markers are hidden but no layout is imposed. Modules are responsible for their own internal layout—use `style={{ display: 'flex', gap: '8px', alignItems: 'flex-start' }}` on ListItem or wrap content in a styled container
|
|
400
382
|
|
|
401
383
|
## Common Patterns
|
|
402
384
|
|
|
403
|
-
### Feature List with Icons
|
|
385
|
+
### Feature List with Custom Icons
|
|
404
386
|
|
|
405
387
|
```tsx
|
|
406
388
|
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
389
|
+
import Icon from '@hubspot/cms-component-library/Icon';
|
|
390
|
+
|
|
391
|
+
const itemStyle = { display: 'flex', gap: '8px', alignItems: 'flex-start' };
|
|
407
392
|
|
|
408
393
|
const FeatureList = ({ features, variant = 'primary' }) => (
|
|
409
|
-
<List listType="unordered" variant={variant} gap="0.5rem">
|
|
394
|
+
<List listType="unordered" variant={variant} showMarker={false} gap="0.5rem">
|
|
410
395
|
{features.map((feature, index) => (
|
|
411
|
-
<ListItem
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
iconName="icon"
|
|
415
|
-
iconSize={20}
|
|
416
|
-
itemsFieldPath="features"
|
|
417
|
-
index={index}
|
|
418
|
-
iconPurpose="DECORATIVE"
|
|
419
|
-
iconFill={`var(--hscl-listItem-iconColor-${variant})`}
|
|
420
|
-
>
|
|
421
|
-
{feature.text}
|
|
396
|
+
<ListItem key={index} style={itemStyle}>
|
|
397
|
+
<Icon name="check" size={20} fill={`var(--hscl-listItem-iconColor-${variant})`} />
|
|
398
|
+
<span>{feature.text}</span>
|
|
422
399
|
</ListItem>
|
|
423
400
|
))}
|
|
424
401
|
</List>
|
|
@@ -433,14 +410,7 @@ import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
|
433
410
|
const StepList = ({ steps, variant = 'primary' }) => (
|
|
434
411
|
<List listType="ordered" variant={variant} gap="1rem">
|
|
435
412
|
{steps.map((step, index) => (
|
|
436
|
-
<ListItem
|
|
437
|
-
key={index}
|
|
438
|
-
showIcon={false}
|
|
439
|
-
index={index}
|
|
440
|
-
itemsFieldPath="steps"
|
|
441
|
-
>
|
|
442
|
-
{step.text}
|
|
443
|
-
</ListItem>
|
|
413
|
+
<ListItem key={index}>{step.text}</ListItem>
|
|
444
414
|
))}
|
|
445
415
|
</List>
|
|
446
416
|
);
|
|
@@ -452,13 +422,13 @@ const StepList = ({ steps, variant = 'primary' }) => (
|
|
|
452
422
|
import List, { ListItem } from '@hubspot/cms-component-library/List';
|
|
453
423
|
|
|
454
424
|
<List listType="unordered" variant="primary">
|
|
455
|
-
<ListItem
|
|
456
|
-
<ListItem
|
|
457
|
-
<ListItem
|
|
425
|
+
<ListItem>Simple item one</ListItem>
|
|
426
|
+
<ListItem>Simple item two</ListItem>
|
|
427
|
+
<ListItem>Simple item three</ListItem>
|
|
458
428
|
</List>
|
|
459
429
|
```
|
|
460
430
|
|
|
461
431
|
## Related Components
|
|
462
432
|
|
|
463
433
|
- **Flex**: Used internally for list layout control. The List component extends Flex capabilities.
|
|
464
|
-
- **Icon**:
|
|
434
|
+
- **Icon**: Can be used as children in ListItem for custom icon lists.
|