@hubspot/cms-component-library 0.1.0 → 0.3.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 +26 -4
- package/components/componentLibrary/Button/index.module.scss +22 -14
- package/components/componentLibrary/Button/index.tsx +6 -6
- package/components/componentLibrary/Button/llm.txt +5 -1
- 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/Button/types.ts +6 -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 +6 -3
- /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,11 +1,11 @@
|
|
|
1
1
|
import { RichTextField } from '@hubspot/cms-components/fields';
|
|
2
2
|
import type { ContentFieldsProps } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const ContentFields = ({
|
|
5
5
|
contentLabel = 'Content',
|
|
6
6
|
contentName = 'content',
|
|
7
7
|
contentDefault = '<p>Accordion content goes here. You can add multiple lines of text.</p>',
|
|
8
|
-
}: ContentFieldsProps) {
|
|
8
|
+
}: ContentFieldsProps) => {
|
|
9
9
|
return (
|
|
10
10
|
// Todo: consider migrating over field library
|
|
11
11
|
<RichTextField
|
|
@@ -14,4 +14,6 @@ export default function ContentFields({
|
|
|
14
14
|
default={contentDefault}
|
|
15
15
|
/>
|
|
16
16
|
);
|
|
17
|
-
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default ContentFields;
|
|
@@ -1,11 +1,11 @@
|
|
|
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
|
variantLabel = 'Variant',
|
|
6
6
|
variantName = 'variant',
|
|
7
7
|
variantDefault = 'variant1',
|
|
8
|
-
}: StyleFieldsProps) {
|
|
8
|
+
}: StyleFieldsProps) => {
|
|
9
9
|
return (
|
|
10
10
|
<ChoiceField
|
|
11
11
|
label={variantLabel}
|
|
@@ -22,4 +22,6 @@ export default function StyleFields({
|
|
|
22
22
|
default={variantDefault}
|
|
23
23
|
/>
|
|
24
24
|
);
|
|
25
|
-
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default StyleFields;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
.accordionItem {
|
|
2
|
-
border: var(--hscl-accordion-
|
|
2
|
+
border: var(--hscl-accordion-borderWidth, 1px) solid
|
|
3
3
|
var(--hscl-accordion-borderColor, #e0e0e0);
|
|
4
4
|
border-radius: var(--hscl-accordion-borderRadius, 4px);
|
|
5
5
|
background-color: var(--hscl-accordion-backgroundColor, transparent);
|
|
6
|
-
color: var(--hscl-accordion-
|
|
6
|
+
color: var(--hscl-accordion-color, inherit);
|
|
7
7
|
overflow: hidden;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -17,10 +17,10 @@ const AccordionItemComponent = ({
|
|
|
17
17
|
? mapVariantToCssVars('--hscl-accordion', variant, [
|
|
18
18
|
'borderColor',
|
|
19
19
|
'borderRadius',
|
|
20
|
-
'
|
|
20
|
+
'borderWidth',
|
|
21
21
|
'backgroundColor',
|
|
22
|
-
'
|
|
23
|
-
'icon-
|
|
22
|
+
'color',
|
|
23
|
+
'icon-fill',
|
|
24
24
|
])
|
|
25
25
|
: {};
|
|
26
26
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { TextField, ChoiceField } from '@hubspot/cms-components/fields';
|
|
2
2
|
import type { ContentFieldsProps } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const ContentFields = ({
|
|
5
5
|
titleLabel = 'Title',
|
|
6
6
|
titleName = 'title',
|
|
7
7
|
titleDefault = 'Accordion Title',
|
|
8
8
|
iconLabel = 'Icon',
|
|
9
9
|
iconName = 'icon',
|
|
10
10
|
iconDefault = 'chevron',
|
|
11
|
-
}: ContentFieldsProps) {
|
|
11
|
+
}: ContentFieldsProps) => {
|
|
12
12
|
return (
|
|
13
13
|
<>
|
|
14
14
|
<ChoiceField
|
|
@@ -26,4 +26,6 @@ export default function ContentFields({
|
|
|
26
26
|
<TextField label={titleLabel} name={titleName} default={titleDefault} />
|
|
27
27
|
</>
|
|
28
28
|
);
|
|
29
|
-
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default ContentFields;
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
.accordionTitleText {
|
|
16
16
|
font-size: var(--hscl-accordion-title-fontSize, 24px);
|
|
17
17
|
font-weight: var(--hscl-accordion-title-fontWeight, 600);
|
|
18
|
-
margin-inline-end: var(--hscl-accordion-title-
|
|
18
|
+
margin-inline-end: var(--hscl-accordion-title-marginInlineEnd, 16px);
|
|
19
19
|
flex: 1;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
.accordionIcon {
|
|
23
23
|
flex-shrink: 0;
|
|
24
24
|
align-self: center;
|
|
25
|
-
fill: var(--hscl-accordion-icon-
|
|
25
|
+
fill: var(--hscl-accordion-icon-fill, currentColor);
|
|
26
26
|
margin-inline-start: auto;
|
|
27
27
|
transition: transform 0.3s ease;
|
|
28
28
|
display: block;
|
|
@@ -6,7 +6,7 @@ import Accordion, {
|
|
|
6
6
|
} from '../index.js';
|
|
7
7
|
import { AccordionProps } from '../types.js';
|
|
8
8
|
import { withAccordionStyles } from './AccordionDecorator.js';
|
|
9
|
-
import { SBContainer } from '@sb-utils
|
|
9
|
+
import { SBContainer, SBFocusWrapper } from '@sb-utils';
|
|
10
10
|
|
|
11
11
|
const meta: Meta<AccordionProps> = {
|
|
12
12
|
title: 'Component Library/Accordion',
|
|
@@ -462,3 +462,82 @@ export const EdgeCases: Story = {
|
|
|
462
462
|
</SBContainer>
|
|
463
463
|
),
|
|
464
464
|
};
|
|
465
|
+
|
|
466
|
+
export const InteractionStates: Story = {
|
|
467
|
+
name: 'Interaction States',
|
|
468
|
+
render: () => (
|
|
469
|
+
<SBContainer flex direction="column" gap="large" width="800px">
|
|
470
|
+
<SBContainer addBackground>
|
|
471
|
+
<h4>Keyboard Navigation</h4>
|
|
472
|
+
<p>
|
|
473
|
+
<strong>Try:</strong> Press Tab to focus on accordion titles, then
|
|
474
|
+
press Enter or Space to expand/collapse them
|
|
475
|
+
</p>
|
|
476
|
+
<Accordion>
|
|
477
|
+
<AccordionItem>
|
|
478
|
+
<AccordionTitle>First accordion item</AccordionTitle>
|
|
479
|
+
<AccordionContent>
|
|
480
|
+
<p>
|
|
481
|
+
Accordion titles (summary elements) are natively keyboard
|
|
482
|
+
accessible. Tab to focus, Enter/Space to toggle.
|
|
483
|
+
</p>
|
|
484
|
+
</AccordionContent>
|
|
485
|
+
</AccordionItem>
|
|
486
|
+
<AccordionItem>
|
|
487
|
+
<AccordionTitle>Second accordion item</AccordionTitle>
|
|
488
|
+
<AccordionContent>
|
|
489
|
+
<p>
|
|
490
|
+
Focus rings appear automatically when navigating with the
|
|
491
|
+
keyboard, providing clear visual feedback.
|
|
492
|
+
</p>
|
|
493
|
+
</AccordionContent>
|
|
494
|
+
</AccordionItem>
|
|
495
|
+
<AccordionItem>
|
|
496
|
+
<AccordionTitle>Third accordion item</AccordionTitle>
|
|
497
|
+
<AccordionContent>
|
|
498
|
+
<p>
|
|
499
|
+
This demonstrates how users can navigate through all accordion
|
|
500
|
+
items using only the keyboard.
|
|
501
|
+
</p>
|
|
502
|
+
</AccordionContent>
|
|
503
|
+
</AccordionItem>
|
|
504
|
+
</Accordion>
|
|
505
|
+
</SBContainer>
|
|
506
|
+
|
|
507
|
+
<SBContainer addBackground>
|
|
508
|
+
<h4>Focus State</h4>
|
|
509
|
+
<p>
|
|
510
|
+
In production, this focus outline appears when navigating with the
|
|
511
|
+
keyboard (Tab key). This Storybook demo auto-applies the focus state
|
|
512
|
+
to show how it looks.
|
|
513
|
+
</p>
|
|
514
|
+
<SBFocusWrapper>
|
|
515
|
+
<Accordion>
|
|
516
|
+
<AccordionItem>
|
|
517
|
+
<AccordionTitle>Focused accordion item</AccordionTitle>
|
|
518
|
+
<AccordionContent>
|
|
519
|
+
<p>
|
|
520
|
+
This accordion title automatically receives focus to
|
|
521
|
+
demonstrate the focus ring appearance.
|
|
522
|
+
</p>
|
|
523
|
+
</AccordionContent>
|
|
524
|
+
</AccordionItem>
|
|
525
|
+
</Accordion>
|
|
526
|
+
</SBFocusWrapper>
|
|
527
|
+
</SBContainer>
|
|
528
|
+
|
|
529
|
+
<SBContainer addBackground>
|
|
530
|
+
<h4>Hover State</h4>
|
|
531
|
+
<p>Hover over accordion titles to see the hover effect</p>
|
|
532
|
+
<Accordion>
|
|
533
|
+
<AccordionItem>
|
|
534
|
+
<AccordionTitle>Hover over this title</AccordionTitle>
|
|
535
|
+
<AccordionContent>
|
|
536
|
+
<p>The title shows a subtle background change on hover.</p>
|
|
537
|
+
</AccordionContent>
|
|
538
|
+
</AccordionItem>
|
|
539
|
+
</Accordion>
|
|
540
|
+
</SBContainer>
|
|
541
|
+
</SBContainer>
|
|
542
|
+
),
|
|
543
|
+
};
|
|
@@ -2,36 +2,36 @@ import type { Decorator } from '@storybook/react';
|
|
|
2
2
|
import type { CSSVariables } from '../../utils/types.js';
|
|
3
3
|
|
|
4
4
|
const defaultAccordionStyles: CSSVariables = {
|
|
5
|
-
'--hscl-listItem-
|
|
6
|
-
'--hscl-listItem-
|
|
5
|
+
'--hscl-listItem-color-primary': '#33475b',
|
|
6
|
+
'--hscl-listItem-color-secondary': '#516f90',
|
|
7
7
|
|
|
8
8
|
'--hscl-accordion-variant1-borderColor': '#e0e0e0',
|
|
9
9
|
'--hscl-accordion-variant1-borderRadius': '4px',
|
|
10
|
-
'--hscl-accordion-variant1-
|
|
10
|
+
'--hscl-accordion-variant1-borderWidth': '1px',
|
|
11
11
|
'--hscl-accordion-variant1-backgroundColor': 'transparent',
|
|
12
|
-
'--hscl-accordion-variant1-
|
|
13
|
-
'--hscl-accordion-variant1-icon-
|
|
12
|
+
'--hscl-accordion-variant1-color': '#33475b',
|
|
13
|
+
'--hscl-accordion-variant1-icon-fill': '#33475b',
|
|
14
14
|
|
|
15
15
|
'--hscl-accordion-variant2-borderColor': '#cbd6e2',
|
|
16
16
|
'--hscl-accordion-variant2-borderRadius': '8px',
|
|
17
|
-
'--hscl-accordion-variant2-
|
|
17
|
+
'--hscl-accordion-variant2-borderWidth': '1px',
|
|
18
18
|
'--hscl-accordion-variant2-backgroundColor': '#f5f8fa',
|
|
19
|
-
'--hscl-accordion-variant2-
|
|
20
|
-
'--hscl-accordion-variant2-icon-
|
|
19
|
+
'--hscl-accordion-variant2-color': '#33475b',
|
|
20
|
+
'--hscl-accordion-variant2-icon-fill': '#516f90',
|
|
21
21
|
|
|
22
22
|
'--hscl-accordion-variant3-borderColor': '#ff7a59',
|
|
23
23
|
'--hscl-accordion-variant3-borderRadius': '0',
|
|
24
|
-
'--hscl-accordion-variant3-
|
|
24
|
+
'--hscl-accordion-variant3-borderWidth': '2px',
|
|
25
25
|
'--hscl-accordion-variant3-backgroundColor': 'transparent',
|
|
26
|
-
'--hscl-accordion-variant3-
|
|
27
|
-
'--hscl-accordion-variant3-icon-
|
|
26
|
+
'--hscl-accordion-variant3-color': '#33475b',
|
|
27
|
+
'--hscl-accordion-variant3-icon-fill': '#ff7a59',
|
|
28
28
|
|
|
29
29
|
'--hscl-accordion-variant4-borderColor': '#33475b',
|
|
30
30
|
'--hscl-accordion-variant4-borderRadius': '12px',
|
|
31
|
-
'--hscl-accordion-variant4-
|
|
31
|
+
'--hscl-accordion-variant4-borderWidth': '1px',
|
|
32
32
|
'--hscl-accordion-variant4-backgroundColor': '#eaf0f6',
|
|
33
|
-
'--hscl-accordion-variant4-
|
|
34
|
-
'--hscl-accordion-variant4-icon-
|
|
33
|
+
'--hscl-accordion-variant4-color': '#33475b',
|
|
34
|
+
'--hscl-accordion-variant4-icon-fill': '#33475b',
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export const withAccordionStyles: Decorator = Story => (
|
|
@@ -2,7 +2,7 @@ import { TextField, LinkField } from '@hubspot/cms-components/fields';
|
|
|
2
2
|
import Icon from '../Icon/index.js';
|
|
3
3
|
import { ContentFieldsProps } from './types.js';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const ContentFields = ({
|
|
6
6
|
buttonTextLabel = 'Button text',
|
|
7
7
|
buttonTextName = 'buttonText',
|
|
8
8
|
buttonTextDefault = 'Click me',
|
|
@@ -22,7 +22,7 @@ export default function ContentFields({
|
|
|
22
22
|
showIconLabel = 'Show button icon',
|
|
23
23
|
showIconName,
|
|
24
24
|
showIconDefault,
|
|
25
|
-
}: ContentFieldsProps) {
|
|
25
|
+
}: ContentFieldsProps) => {
|
|
26
26
|
const iconContentFieldsProps = {
|
|
27
27
|
iconLabel,
|
|
28
28
|
iconName,
|
|
@@ -49,4 +49,6 @@ export default function ContentFields({
|
|
|
49
49
|
<Icon.ContentFields addIconToggle={true} {...iconContentFieldsProps} />
|
|
50
50
|
</>
|
|
51
51
|
);
|
|
52
|
-
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default ContentFields;
|
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
import { ChoiceField } from '@hubspot/cms-components/fields';
|
|
1
|
+
import { ChoiceField, Visibility } from '@hubspot/cms-components/fields';
|
|
2
2
|
import { StyleFieldsProps } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const StyleFields = ({
|
|
5
5
|
buttonVariantLabel = 'Button variant',
|
|
6
6
|
buttonVariantName = 'buttonVariant',
|
|
7
7
|
buttonVariantDefault = 'primary',
|
|
8
|
-
|
|
8
|
+
buttonIconPositionLabel = 'Icon position',
|
|
9
|
+
buttonIconPositionName = 'buttonIconPosition',
|
|
10
|
+
buttonIconPositionDefault = 'right',
|
|
11
|
+
}: StyleFieldsProps) => {
|
|
12
|
+
// iconComponentShowIcon is the hardcoded id in @components/componentLibrary/Icon/ContentFields.tsx
|
|
13
|
+
const iconPositionVisibility: Visibility = {
|
|
14
|
+
operator: 'EQUAL',
|
|
15
|
+
controlling_field: 'iconComponentShowIcon',
|
|
16
|
+
controlling_value_regex: 'true',
|
|
17
|
+
};
|
|
18
|
+
|
|
9
19
|
return (
|
|
10
20
|
<>
|
|
11
21
|
<ChoiceField
|
|
@@ -18,6 +28,18 @@ export default function StyleFields({
|
|
|
18
28
|
]}
|
|
19
29
|
default={buttonVariantDefault}
|
|
20
30
|
/>
|
|
31
|
+
<ChoiceField
|
|
32
|
+
label={buttonIconPositionLabel}
|
|
33
|
+
name={buttonIconPositionName}
|
|
34
|
+
choices={[
|
|
35
|
+
['left', 'Left'],
|
|
36
|
+
['right', 'Right'],
|
|
37
|
+
]}
|
|
38
|
+
default={buttonIconPositionDefault}
|
|
39
|
+
visibility={iconPositionVisibility}
|
|
40
|
+
/>
|
|
21
41
|
</>
|
|
22
42
|
);
|
|
23
|
-
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default StyleFields;
|
|
@@ -17,21 +17,32 @@
|
|
|
17
17
|
transition: all 0.2s ease;
|
|
18
18
|
text-decoration: none;
|
|
19
19
|
|
|
20
|
+
@media (prefers-reduced-motion: reduce) {
|
|
21
|
+
transition: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
&:hover {
|
|
21
|
-
background-color: var(--hscl-button-backgroundColor-hover);
|
|
22
|
-
color: var(--hscl-button-color-hover);
|
|
23
|
-
border-width: var(--hscl-button-borderWidth-hover);
|
|
24
|
-
border-color: var(--hscl-button-borderColor-hover);
|
|
25
|
+
background-color: var(--hscl-button-backgroundColor-hover, var(--hscl-button-backgroundColor));
|
|
26
|
+
color: var(--hscl-button-color-hover, var(--hscl-button-color));
|
|
27
|
+
border-width: var(--hscl-button-borderWidth-hover, var(--hscl-button-borderWidth));
|
|
28
|
+
border-color: var(--hscl-button-borderColor-hover, var(--hscl-button-borderColor));
|
|
25
29
|
text-decoration: none;
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
&:focus {
|
|
29
|
-
background-color: var(--hscl-button-backgroundColor-focus);
|
|
30
|
-
color: var(--hscl-button-color-focus);
|
|
31
|
-
border-width: var(--hscl-button-borderWidth-focus);
|
|
32
|
-
border-color: var(--hscl-button-borderColor-focus);
|
|
33
|
-
outline: var(--hscl-button-outlineWidth-focus) solid var(--hscl-button-outlineColor-focus);
|
|
34
|
-
outline-offset: var(--hscl-button-outlineOffset-focus);
|
|
32
|
+
&:focus-visible {
|
|
33
|
+
background-color: var(--hscl-button-backgroundColor-focus, var(--hscl-button-backgroundColor));
|
|
34
|
+
color: var(--hscl-button-color-focus, var(--hscl-button-color));
|
|
35
|
+
border-width: var(--hscl-button-borderWidth-focus, var(--hscl-button-borderWidth));
|
|
36
|
+
border-color: var(--hscl-button-borderColor-focus, var(--hscl-button-borderColor));
|
|
37
|
+
outline: var(--hscl-button-outlineWidth-focus, 2px) solid var(--hscl-button-outlineColor-focus, currentColor);
|
|
38
|
+
outline-offset: var(--hscl-button-outlineOffset-focus, 2px);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&:active {
|
|
42
|
+
background-color: var(--hscl-button-backgroundColor-active, var(--hscl-button-backgroundColor));
|
|
43
|
+
color: var(--hscl-button-color-active, var(--hscl-button-color));
|
|
44
|
+
border-width: var(--hscl-button-borderWidth-active, var(--hscl-button-borderWidth));
|
|
45
|
+
border-color: var(--hscl-button-borderColor-active, var(--hscl-button-borderColor));
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
&:disabled {
|
|
@@ -39,7 +50,6 @@
|
|
|
39
50
|
cursor: not-allowed;
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
|
|
43
53
|
svg {
|
|
44
54
|
display: inline-flex;
|
|
45
55
|
align-items: center;
|
|
@@ -47,5 +57,3 @@
|
|
|
47
57
|
fill: var(--hscl-button-icon-fill);
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
|
-
|
|
51
|
-
|
|
@@ -56,7 +56,7 @@ const ButtonComponent = ({
|
|
|
56
56
|
);
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
const renderButton = ({
|
|
60
60
|
onClick,
|
|
61
61
|
disabled = false,
|
|
62
62
|
children,
|
|
@@ -67,7 +67,7 @@ const ButtonComponent = ({
|
|
|
67
67
|
iconPurpose,
|
|
68
68
|
iconTitle,
|
|
69
69
|
...rest
|
|
70
|
-
}: Omit<ButtonAsButtonProps, 'buttonType'> & Partial<BaseButtonProps>) {
|
|
70
|
+
}: Omit<ButtonAsButtonProps, 'buttonType'> & Partial<BaseButtonProps>) => {
|
|
71
71
|
const iconProps = {
|
|
72
72
|
iconFieldPath,
|
|
73
73
|
iconSize,
|
|
@@ -81,9 +81,9 @@ const ButtonComponent = ({
|
|
|
81
81
|
<RenderWithIcon {...iconProps}>{children}</RenderWithIcon>
|
|
82
82
|
</button>
|
|
83
83
|
);
|
|
84
|
-
}
|
|
84
|
+
};
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
const renderLink = ({
|
|
87
87
|
href = '',
|
|
88
88
|
target = '_self',
|
|
89
89
|
rel = '',
|
|
@@ -95,7 +95,7 @@ const ButtonComponent = ({
|
|
|
95
95
|
iconPurpose,
|
|
96
96
|
iconTitle,
|
|
97
97
|
...rest
|
|
98
|
-
}: Omit<ButtonAsLinkProps, 'buttonType'> & Partial<BaseButtonProps>) {
|
|
98
|
+
}: Omit<ButtonAsLinkProps, 'buttonType'> & Partial<BaseButtonProps>) => {
|
|
99
99
|
const iconProps = {
|
|
100
100
|
iconFieldPath,
|
|
101
101
|
iconSize,
|
|
@@ -109,7 +109,7 @@ const ButtonComponent = ({
|
|
|
109
109
|
<RenderWithIcon {...iconProps}>{children}</RenderWithIcon>
|
|
110
110
|
</a>
|
|
111
111
|
);
|
|
112
|
-
}
|
|
112
|
+
};
|
|
113
113
|
|
|
114
114
|
// TypeScript properly discriminates based on buttonType
|
|
115
115
|
if (buttonType === 'button') return renderButton(rest);
|
|
@@ -234,18 +234,22 @@ Configurable props for customizing field labels, names, and defaults:
|
|
|
234
234
|
|
|
235
235
|
#### StyleFields.tsx
|
|
236
236
|
|
|
237
|
-
Configurable props for variant
|
|
237
|
+
Configurable props for variant and icon position:
|
|
238
238
|
|
|
239
239
|
```tsx
|
|
240
240
|
<Button.StyleFields
|
|
241
241
|
buttonVariantLabel="Button variant"
|
|
242
242
|
buttonVariantName="buttonVariant"
|
|
243
243
|
buttonVariantDefault="primary"
|
|
244
|
+
buttonIconPositionLabel="Icon position"
|
|
245
|
+
buttonIconPositionName="buttonIconPosition"
|
|
246
|
+
buttonIconPositionDefault="right"
|
|
244
247
|
/>
|
|
245
248
|
```
|
|
246
249
|
|
|
247
250
|
**Fields:**
|
|
248
251
|
- `buttonVariant`: ChoiceField for selecting visual style (primary, secondary, tertiary)
|
|
252
|
+
- `buttonIconPosition`: ChoiceField for selecting icon placement (left, right). This field has a hardcoded visibility rule — it is only shown when the icon toggle is enabled (`iconComponentShowIcon === true`), which corresponds to the `BooleanField` id hardcoded in `Icon.ContentFields`.
|
|
249
253
|
|
|
250
254
|
### Module Usage Example
|
|
251
255
|
|
|
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
2
2
|
import Button from '../index.js';
|
|
3
3
|
import { ButtonAsButtonProps } from '../types.js';
|
|
4
4
|
import { withButtonStyles } from './ButtonDecorator.js';
|
|
5
|
-
import { SBContainer } from '@sb-utils
|
|
5
|
+
import { SBContainer, SBFocusWrapper } from '@sb-utils';
|
|
6
6
|
|
|
7
7
|
const meta: Meta<ButtonAsButtonProps> = {
|
|
8
8
|
title: 'Component Library/Button/As Button',
|
|
@@ -64,3 +64,32 @@ export const DisabledStates: Story = {
|
|
|
64
64
|
</SBContainer>
|
|
65
65
|
),
|
|
66
66
|
};
|
|
67
|
+
|
|
68
|
+
export const InteractionStates: Story = {
|
|
69
|
+
name: 'Interaction States',
|
|
70
|
+
render: () => (
|
|
71
|
+
<SBContainer flex direction="column" gap="large">
|
|
72
|
+
<SBContainer addBackground>
|
|
73
|
+
<h4>Hover State</h4>
|
|
74
|
+
<p>Hover over the button to see the hover effect</p>
|
|
75
|
+
<Button buttonType="button" variant="primary">
|
|
76
|
+
Hover me
|
|
77
|
+
</Button>
|
|
78
|
+
</SBContainer>
|
|
79
|
+
|
|
80
|
+
<SBContainer addBackground>
|
|
81
|
+
<h4>Focus State</h4>
|
|
82
|
+
<p>
|
|
83
|
+
In production, this focus outline appears when navigating with the
|
|
84
|
+
keyboard (Tab key). This Storybook demo auto-applies the focus state
|
|
85
|
+
to show how it looks.
|
|
86
|
+
</p>
|
|
87
|
+
<SBFocusWrapper>
|
|
88
|
+
<Button buttonType="button" variant="primary">
|
|
89
|
+
Focused button
|
|
90
|
+
</Button>
|
|
91
|
+
</SBFocusWrapper>
|
|
92
|
+
</SBContainer>
|
|
93
|
+
</SBContainer>
|
|
94
|
+
),
|
|
95
|
+
};
|
|
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
2
2
|
import Button from '../index.js';
|
|
3
3
|
import { ButtonAsLinkProps } from '../types.js';
|
|
4
4
|
import { withButtonStyles } from './ButtonDecorator.js';
|
|
5
|
-
import { SBContainer } from '@sb-utils
|
|
5
|
+
import { SBContainer, SBFocusWrapper } from '@sb-utils';
|
|
6
6
|
|
|
7
7
|
const meta: Meta<ButtonAsLinkProps> = {
|
|
8
8
|
title: 'Component Library/Button/As Link',
|
|
@@ -68,3 +68,40 @@ export const LinkTargets: Story = {
|
|
|
68
68
|
</SBContainer>
|
|
69
69
|
),
|
|
70
70
|
};
|
|
71
|
+
|
|
72
|
+
export const InteractionStates: Story = {
|
|
73
|
+
name: 'Interaction States',
|
|
74
|
+
render: () => (
|
|
75
|
+
<SBContainer flex direction="column" gap="large">
|
|
76
|
+
<SBContainer addBackground>
|
|
77
|
+
<h4>Hover State</h4>
|
|
78
|
+
<p>Hover over the button to see the hover effect</p>
|
|
79
|
+
<Button
|
|
80
|
+
buttonType="link"
|
|
81
|
+
href="https://www.hubspot.com"
|
|
82
|
+
variant="primary"
|
|
83
|
+
>
|
|
84
|
+
Hover me
|
|
85
|
+
</Button>
|
|
86
|
+
</SBContainer>
|
|
87
|
+
|
|
88
|
+
<SBContainer addBackground>
|
|
89
|
+
<h4>Focus State</h4>
|
|
90
|
+
<p>
|
|
91
|
+
In production, this focus outline appears when navigating with the
|
|
92
|
+
keyboard (Tab key). This Storybook demo auto-applies the focus state
|
|
93
|
+
to show how it looks.
|
|
94
|
+
</p>
|
|
95
|
+
<SBFocusWrapper>
|
|
96
|
+
<Button
|
|
97
|
+
buttonType="link"
|
|
98
|
+
href="https://www.hubspot.com"
|
|
99
|
+
variant="primary"
|
|
100
|
+
>
|
|
101
|
+
Focused button
|
|
102
|
+
</Button>
|
|
103
|
+
</SBFocusWrapper>
|
|
104
|
+
</SBContainer>
|
|
105
|
+
</SBContainer>
|
|
106
|
+
),
|
|
107
|
+
};
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
} from '@hubspot/cms-components/fields';
|
|
5
5
|
import { IconContentFieldsWithToggleProps } from '../Icon/types.js';
|
|
6
6
|
|
|
7
|
+
export type IconPositionHorizontal = 'left' | 'right';
|
|
8
|
+
|
|
7
9
|
// Base props shared by all variants
|
|
8
10
|
export type BaseButtonProps = {
|
|
9
11
|
variant?: 'primary' | 'secondary' | 'tertiary'; // !todo: not used atm but keeping for when we need to add variant system.
|
|
@@ -11,7 +13,7 @@ export type BaseButtonProps = {
|
|
|
11
13
|
style?: React.CSSProperties;
|
|
12
14
|
children?: React.ReactNode;
|
|
13
15
|
iconFieldPath?: string;
|
|
14
|
-
iconPosition?:
|
|
16
|
+
iconPosition?: IconPositionHorizontal;
|
|
15
17
|
iconSize?: number;
|
|
16
18
|
showIcon?: boolean;
|
|
17
19
|
iconPurpose?: 'SEMANTIC' | 'DECORATIVE';
|
|
@@ -56,6 +58,9 @@ export type StyleFieldsProps = {
|
|
|
56
58
|
buttonVariantLabel?: string;
|
|
57
59
|
buttonVariantName?: string;
|
|
58
60
|
buttonVariantDefault?: string;
|
|
61
|
+
buttonIconPositionLabel?: string;
|
|
62
|
+
buttonIconPositionName?: string;
|
|
63
|
+
buttonIconPositionDefault?: IconPositionHorizontal;
|
|
59
64
|
};
|
|
60
65
|
|
|
61
66
|
export type RenderWithIconProps = Pick<
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ChoiceField, NumberField } from '@hubspot/cms-components/fields';
|
|
2
2
|
import { StyleFieldsProps } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const StyleFields = ({
|
|
5
5
|
variantLabel = 'Card Variant',
|
|
6
6
|
variantName = 'variant',
|
|
7
7
|
variantDefault = 'elevated',
|
|
8
8
|
borderRadiusLabel = 'Border Radius',
|
|
9
9
|
borderRadiusName = 'borderRadius',
|
|
10
10
|
borderRadiusDefault = 8,
|
|
11
|
-
}: StyleFieldsProps) {
|
|
11
|
+
}: StyleFieldsProps) => {
|
|
12
12
|
return (
|
|
13
13
|
<>
|
|
14
14
|
<ChoiceField
|
|
@@ -31,4 +31,6 @@ export default function StyleFields({
|
|
|
31
31
|
/>
|
|
32
32
|
</>
|
|
33
33
|
);
|
|
34
|
-
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default StyleFields;
|