@commercetools/nimbus 0.0.2 → 0.0.3
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/dist/index.d.ts +1412 -0
- package/dist/index.js +11183 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +27 -0
- package/dist/index.umd.cjs.map +1 -0
- package/package.json +63 -39
- package/.storybook/apca-check/index.ts +0 -150
- package/.storybook/main.ts +0 -64
- package/.storybook/preview.tsx +0 -92
- package/.storybook/vitest.setup.ts +0 -13
- package/docs/architecture-decisions/adr-0001-consumer-component-apis.md +0 -177
- package/docs/architecture-decisions/adr-0002-compound-component-extraction.md +0 -82
- package/src/components/accordion/accordion-context.tsx +0 -17
- package/src/components/accordion/accordion.mdx +0 -172
- package/src/components/accordion/accordion.recipe.tsx +0 -98
- package/src/components/accordion/accordion.slots.tsx +0 -39
- package/src/components/accordion/accordion.stories.tsx +0 -188
- package/src/components/accordion/accordion.tsx +0 -16
- package/src/components/accordion/accordion.types.tsx +0 -54
- package/src/components/accordion/components/accordion-content.tsx +0 -28
- package/src/components/accordion/components/accordion-group.tsx +0 -27
- package/src/components/accordion/components/accordion-header.tsx +0 -63
- package/src/components/accordion/components/accordion-item.tsx +0 -87
- package/src/components/accordion/index.ts +0 -2
- package/src/components/alert/alert.mdx +0 -92
- package/src/components/alert/alert.recipe.tsx +0 -65
- package/src/components/alert/alert.slots.tsx +0 -46
- package/src/components/alert/alert.stories.tsx +0 -308
- package/src/components/alert/alert.tsx +0 -18
- package/src/components/alert/alert.types.tsx +0 -70
- package/src/components/alert/components/alert.actions.tsx +0 -27
- package/src/components/alert/components/alert.description.tsx +0 -27
- package/src/components/alert/components/alert.dismiss-button.tsx +0 -41
- package/src/components/alert/components/alert.root.tsx +0 -92
- package/src/components/alert/components/alert.title.tsx +0 -29
- package/src/components/alert/index.ts +0 -2
- package/src/components/avatar/avatar.mdx +0 -80
- package/src/components/avatar/avatar.recipe.tsx +0 -36
- package/src/components/avatar/avatar.slots.tsx +0 -16
- package/src/components/avatar/avatar.stories.tsx +0 -136
- package/src/components/avatar/avatar.tsx +0 -34
- package/src/components/avatar/avatar.types.ts +0 -33
- package/src/components/avatar/index.ts +0 -2
- package/src/components/badge/badge.mdx +0 -91
- package/src/components/badge/badge.recipe.tsx +0 -72
- package/src/components/badge/badge.slots.tsx +0 -8
- package/src/components/badge/badge.stories.tsx +0 -124
- package/src/components/badge/badge.tsx +0 -35
- package/src/components/badge/badge.types.tsx +0 -40
- package/src/components/badge/index.ts +0 -2
- package/src/components/bleed/bleed.tsx +0 -1
- package/src/components/bleed/index.ts +0 -1
- package/src/components/box/box.mdx +0 -115
- package/src/components/box/box.stories.tsx +0 -71
- package/src/components/box/box.tsx +0 -11
- package/src/components/box/index.ts +0 -1
- package/src/components/button/button.mdx +0 -169
- package/src/components/button/button.recipe.ts +0 -185
- package/src/components/button/button.slots.tsx +0 -45
- package/src/components/button/button.stories.tsx +0 -369
- package/src/components/button/button.tsx +0 -37
- package/src/components/button/button.types.ts +0 -14
- package/src/components/button/index.ts +0 -2
- package/src/components/card/card.mdx +0 -92
- package/src/components/card/card.recipe.tsx +0 -71
- package/src/components/card/card.slots.tsx +0 -50
- package/src/components/card/card.stories.tsx +0 -175
- package/src/components/card/card.tsx +0 -9
- package/src/components/card/card.types.ts +0 -22
- package/src/components/card/components/card.content.tsx +0 -29
- package/src/components/card/components/card.header.tsx +0 -28
- package/src/components/card/components/card.root.tsx +0 -62
- package/src/components/card/index.ts +0 -2
- package/src/components/checkbox/checkbox.mdx +0 -78
- package/src/components/checkbox/checkbox.recipe.tsx +0 -116
- package/src/components/checkbox/checkbox.slots.tsx +0 -33
- package/src/components/checkbox/checkbox.stories.tsx +0 -200
- package/src/components/checkbox/checkbox.tsx +0 -77
- package/src/components/checkbox/checkbox.types.tsx +0 -22
- package/src/components/checkbox/index.ts +0 -2
- package/src/components/code/code.mdx +0 -17
- package/src/components/code/code.recipe.ts +0 -63
- package/src/components/code/code.tsx +0 -1
- package/src/components/code/index.ts +0 -1
- package/src/components/dialog/dialog.mdx +0 -20
- package/src/components/dialog/dialog.recipe.ts +0 -254
- package/src/components/dialog/dialog.tsx +0 -61
- package/src/components/dialog/index.ts +0 -1
- package/src/components/em/em.mdx +0 -17
- package/src/components/em/em.tsx +0 -1
- package/src/components/em/index.ts +0 -1
- package/src/components/flex/flex.mdx +0 -41
- package/src/components/flex/flex.tsx +0 -1
- package/src/components/flex/index.ts +0 -1
- package/src/components/grid/grid.mdx +0 -156
- package/src/components/grid/grid.stories.tsx +0 -151
- package/src/components/grid/grid.tsx +0 -29
- package/src/components/grid/index.ts +0 -1
- package/src/components/heading/heading.mdx +0 -23
- package/src/components/heading/heading.recipe.ts +0 -49
- package/src/components/heading/heading.tsx +0 -1
- package/src/components/heading/index.ts +0 -1
- package/src/components/highlight/highlight.mdx +0 -18
- package/src/components/highlight/highlight.tsx +0 -1
- package/src/components/highlight/index.ts +0 -1
- package/src/components/icon-button/icon-button.mdx +0 -98
- package/src/components/icon-button/icon-button.stories.tsx +0 -188
- package/src/components/icon-button/icon-button.tsx +0 -21
- package/src/components/icon-button/icon-button.types.tsx +0 -10
- package/src/components/icon-button/index.ts +0 -2
- package/src/components/index.ts +0 -33
- package/src/components/input/index.ts +0 -1
- package/src/components/input/input.mdx +0 -20
- package/src/components/input/input.recipe.ts +0 -95
- package/src/components/input/input.tsx +0 -1
- package/src/components/input-group/index.ts +0 -1
- package/src/components/input-group/input-group.mdx +0 -20
- package/src/components/input-group/input-group.tsx +0 -44
- package/src/components/kbd/index.ts +0 -1
- package/src/components/kbd/kbd.mdx +0 -18
- package/src/components/kbd/kbd.recipe.ts +0 -57
- package/src/components/kbd/kbd.tsx +0 -1
- package/src/components/link/index.ts +0 -2
- package/src/components/link/link.mdx +0 -77
- package/src/components/link/link.recipe.ts +0 -52
- package/src/components/link/link.slots.tsx +0 -29
- package/src/components/link/link.stories.tsx +0 -204
- package/src/components/link/link.tsx +0 -38
- package/src/components/link/link.types.tsx +0 -26
- package/src/components/list/index.ts +0 -1
- package/src/components/list/list.mdx +0 -18
- package/src/components/list/list.recipe.ts +0 -68
- package/src/components/list/list.tsx +0 -9
- package/src/components/loading-spinner/index.ts +0 -2
- package/src/components/loading-spinner/loading-spinner.mdx +0 -92
- package/src/components/loading-spinner/loading-spinner.recipe.tsx +0 -70
- package/src/components/loading-spinner/loading-spinner.slots.tsx +0 -38
- package/src/components/loading-spinner/loading-spinner.stories.tsx +0 -97
- package/src/components/loading-spinner/loading-spinner.tsx +0 -50
- package/src/components/loading-spinner/loading-spinner.types.tsx +0 -21
- package/src/components/nimbus-provider/color-mode.tsx +0 -32
- package/src/components/nimbus-provider/index.ts +0 -2
- package/src/components/nimbus-provider/nimbus-provider.mdx +0 -21
- package/src/components/nimbus-provider/nimbus-provider.tsx +0 -51
- package/src/components/select/components/select.clear-button.tsx +0 -31
- package/src/components/select/components/select.option-group.tsx +0 -48
- package/src/components/select/components/select.option.tsx +0 -21
- package/src/components/select/components/select.options.tsx +0 -23
- package/src/components/select/components/select.root.tsx +0 -81
- package/src/components/select/index.ts +0 -2
- package/src/components/select/select.mdx +0 -170
- package/src/components/select/select.recipe.tsx +0 -216
- package/src/components/select/select.slots.tsx +0 -58
- package/src/components/select/select.stories.tsx +0 -841
- package/src/components/select/select.tsx +0 -18
- package/src/components/select/select.types.tsx +0 -37
- package/src/components/simple-grid/index.ts +0 -1
- package/src/components/simple-grid/simple-grid.mdx +0 -133
- package/src/components/simple-grid/simple-grid.stories.tsx +0 -143
- package/src/components/simple-grid/simple-grid.tsx +0 -31
- package/src/components/stack/index.ts +0 -1
- package/src/components/stack/stack.mdx +0 -88
- package/src/components/stack/stack.stories.tsx +0 -82
- package/src/components/stack/stack.tsx +0 -15
- package/src/components/table/index.ts +0 -1
- package/src/components/table/table.mdx +0 -23
- package/src/components/table/table.recipe.ts +0 -170
- package/src/components/table/table.tsx +0 -43
- package/src/components/text/index.ts +0 -1
- package/src/components/text/text.mdx +0 -244
- package/src/components/text/text.tsx +0 -23
- package/src/components/text-input/index.ts +0 -2
- package/src/components/text-input/text-input.mdx +0 -118
- package/src/components/text-input/text-input.recipe.tsx +0 -68
- package/src/components/text-input/text-input.slots.tsx +0 -24
- package/src/components/text-input/text-input.stories.tsx +0 -282
- package/src/components/text-input/text-input.tsx +0 -39
- package/src/components/text-input/text-input.types.ts +0 -7
- package/src/components/toggle-button-group/components/toggle-button-group.button.tsx +0 -14
- package/src/components/toggle-button-group/components/toggle-button-group.root.tsx +0 -15
- package/src/components/toggle-button-group/index.ts +0 -2
- package/src/components/toggle-button-group/toggle-button-group.mdx +0 -94
- package/src/components/toggle-button-group/toggle-button-group.recipe.tsx +0 -64
- package/src/components/toggle-button-group/toggle-button-group.slots.tsx +0 -26
- package/src/components/toggle-button-group/toggle-button-group.stories.tsx +0 -311
- package/src/components/toggle-button-group/toggle-button-group.tsx +0 -12
- package/src/components/toggle-button-group/toggle-button-group.types.tsx +0 -62
- package/src/components/tooltip/index.ts +0 -4
- package/src/components/tooltip/make-element-focusable.stories.tsx +0 -56
- package/src/components/tooltip/make-element-focusable.tsx +0 -57
- package/src/components/tooltip/tooltip-trigger.stories.tsx +0 -157
- package/src/components/tooltip/tooltip-trigger.tsx +0 -15
- package/src/components/tooltip/tooltip.mdx +0 -48
- package/src/components/tooltip/tooltip.recipe.ts +0 -26
- package/src/components/tooltip/tooltip.slots.ts +0 -35
- package/src/components/tooltip/tooltip.stories.tsx +0 -139
- package/src/components/tooltip/tooltip.tsx +0 -31
- package/src/components/tooltip/tooltip.types.ts +0 -44
- package/src/components/visually-hidden/index.ts +0 -1
- package/src/components/visually-hidden/visually-hidden.mdx +0 -61
- package/src/components/visually-hidden/visually-hidden.stories.tsx +0 -124
- package/src/components/visually-hidden/visually-hidden.tsx +0 -18
- package/src/docs/accessibility.mdx +0 -21
- package/src/docs/background.mdx +0 -154
- package/src/docs/border.mdx +0 -226
- package/src/docs/changelog.mdx +0 -17
- package/src/docs/components-layout.mdx +0 -22
- package/src/docs/components.mdx +0 -17
- package/src/docs/data-display.mdx +0 -23
- package/src/docs/display.mdx +0 -55
- package/src/docs/effects.mdx +0 -73
- package/src/docs/feedback.mdx +0 -22
- package/src/docs/filters.mdx +0 -268
- package/src/docs/flex-and-grid.mdx +0 -445
- package/src/docs/forms.mdx +0 -22
- package/src/docs/generated/index.mdx +0 -16
- package/src/docs/getting-started.mdx +0 -17
- package/src/docs/home.mdx +0 -56
- package/src/docs/hooks.mdx +0 -16
- package/src/docs/inputs.mdx +0 -21
- package/src/docs/installation.mdx +0 -60
- package/src/docs/interactivity.mdx +0 -278
- package/src/docs/known-issues.mdx +0 -19
- package/src/docs/layout.mdx +0 -301
- package/src/docs/list.mdx +0 -82
- package/src/docs/markdown.mdx +0 -234
- package/src/docs/media.mdx +0 -22
- package/src/docs/naivgation.mdx +0 -22
- package/src/docs/playground.mdx +0 -16
- package/src/docs/rfcs-component-structure-rfcs.mdx +0 -17
- package/src/docs/rfcs-component-structure.mdx +0 -74
- package/src/docs/rfcs-hook-structure.mdx +0 -59
- package/src/docs/sizing.mdx +0 -210
- package/src/docs/spacing.mdx +0 -193
- package/src/docs/style-props-typography.mdx +0 -373
- package/src/docs/style-props.mdx +0 -15
- package/src/docs/svg.mdx +0 -58
- package/src/docs/tables.mdx +0 -95
- package/src/docs/toc.mdx +0 -39
- package/src/docs/tokens/animations.mdx +0 -68
- package/src/docs/tokens/aspect-ratios.mdx +0 -21
- package/src/docs/tokens/blurs.mdx +0 -20
- package/src/docs/tokens/borders.mdx +0 -25
- package/src/docs/tokens/breakpoints.mdx +0 -35
- package/src/docs/tokens/colors.mdx +0 -86
- package/src/docs/tokens/cursors.mdx +0 -21
- package/src/docs/tokens/radii.mdx +0 -23
- package/src/docs/tokens/shadows.mdx +0 -21
- package/src/docs/tokens/sizes.mdx +0 -54
- package/src/docs/tokens/spacing.mdx +0 -35
- package/src/docs/tokens/typography.mdx +0 -61
- package/src/docs/tokens/z-indices.mdx +0 -23
- package/src/docs/tokens-other.mdx +0 -17
- package/src/docs/tokens.mdx +0 -16
- package/src/docs/transforms.mdx +0 -150
- package/src/docs/transitions.mdx +0 -164
- package/src/docs/typography.mdx +0 -17
- package/src/docs/utilities.mdx +0 -17
- package/src/hooks/index.ts +0 -2
- package/src/hooks/use-copy-to-clipboard/use-copy-to-clipboard.mdx +0 -54
- package/src/hooks/use-copy-to-clipboard/use-copy-to-clipboard.ts +0 -1
- package/src/hooks/use-hotkeys/use-hotkeys.mdx +0 -48
- package/src/hooks/use-hotkeys/use-hotkeys.stories.tsx +0 -69
- package/src/hooks/use-hotkeys/use-hotkeys.ts +0 -1
- package/src/index.ts +0 -3
- package/src/test/utils.tsx +0 -20
- package/src/theme/animation-styles.ts +0 -52
- package/src/theme/breakpoints.ts +0 -32
- package/src/theme/global-css.ts +0 -53
- package/src/theme/index.ts +0 -35
- package/src/theme/keyframes.ts +0 -192
- package/src/theme/layer-styles.ts +0 -12
- package/src/theme/recipes/index.ts +0 -21
- package/src/theme/semantic-tokens/colors.ts +0 -55
- package/src/theme/semantic-tokens/index.ts +0 -9
- package/src/theme/semantic-tokens/radii.ts +0 -3
- package/src/theme/semantic-tokens/shadows.ts +0 -4
- package/src/theme/slot-recipes/index.ts +0 -15
- package/src/theme/text-styles.ts +0 -8
- package/src/theme/tokens/animations.ts +0 -4
- package/src/theme/tokens/aspect-ratios.ts +0 -5
- package/src/theme/tokens/blurs.ts +0 -5
- package/src/theme/tokens/borders.ts +0 -4
- package/src/theme/tokens/colors.ts +0 -8
- package/src/theme/tokens/cursor.ts +0 -4
- package/src/theme/tokens/durations.ts +0 -4
- package/src/theme/tokens/easings.ts +0 -4
- package/src/theme/tokens/font-sizes.ts +0 -4
- package/src/theme/tokens/font-weights.ts +0 -4
- package/src/theme/tokens/fonts.ts +0 -4
- package/src/theme/tokens/index.ts +0 -57
- package/src/theme/tokens/letter-spacings.ts +0 -24
- package/src/theme/tokens/line-heights.ts +0 -4
- package/src/theme/tokens/radii.ts +0 -4
- package/src/theme/tokens/sizes.ts +0 -120
- package/src/theme/tokens/spacing.ts +0 -4
- package/src/theme/tokens/z-index.ts +0 -4
- package/src/utils/extractStyleProps.ts +0 -26
- package/src/utils/fixedForwardRef.ts +0 -17
- package/tsconfig.json +0 -38
- package/vite.config.ts +0 -54
- package/vitest.config.ts +0 -50
package/package.json
CHANGED
|
@@ -1,59 +1,83 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools/nimbus",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"main": "./dist/index.umd.cjs",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.umd.cjs"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
8
23
|
"publishConfig": {
|
|
9
24
|
"access": "public"
|
|
10
25
|
},
|
|
11
|
-
"sideEffects":
|
|
26
|
+
"sideEffects": [
|
|
27
|
+
"*.css"
|
|
28
|
+
],
|
|
29
|
+
"source": "src/index.ts",
|
|
30
|
+
"typesVersions": {
|
|
31
|
+
"*": {
|
|
32
|
+
"*": [
|
|
33
|
+
"./dist/index.d.ts"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
12
37
|
"devDependencies": {
|
|
13
|
-
"@chakra-ui/cli": "
|
|
14
|
-
"@pandacss/types": "
|
|
15
|
-
"@storybook/addon-a11y": "
|
|
16
|
-
"@storybook/addon-essentials": "
|
|
17
|
-
"@storybook/experimental-addon-test": "
|
|
18
|
-
"@storybook/preview-api": "
|
|
19
|
-
"@storybook/react": "
|
|
20
|
-
"@storybook/react-vite": "
|
|
21
|
-
"@storybook/test": "
|
|
22
|
-
"@testing-library/react": "
|
|
23
|
-
"@testing-library/user-event": "
|
|
24
|
-
"@types/react": "
|
|
25
|
-
"@types/react-dom": "
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
28
|
-
"@vitest/
|
|
29
|
-
"@vitest/coverage-v8": "^3.1.1",
|
|
38
|
+
"@chakra-ui/cli": "catalog:react",
|
|
39
|
+
"@pandacss/types": "catalog:react",
|
|
40
|
+
"@storybook/addon-a11y": "catalog:tooling",
|
|
41
|
+
"@storybook/addon-essentials": "catalog:tooling",
|
|
42
|
+
"@storybook/experimental-addon-test": "catalog:tooling",
|
|
43
|
+
"@storybook/preview-api": "catalog:tooling",
|
|
44
|
+
"@storybook/react": "catalog:tooling",
|
|
45
|
+
"@storybook/react-vite": "catalog:tooling",
|
|
46
|
+
"@storybook/test": "catalog:tooling",
|
|
47
|
+
"@testing-library/react": "catalog:tooling",
|
|
48
|
+
"@testing-library/user-event": "catalog:tooling",
|
|
49
|
+
"@types/react": "catalog:react",
|
|
50
|
+
"@types/react-dom": "catalog:react",
|
|
51
|
+
"@vitejs/plugin-react": "catalog:tooling",
|
|
52
|
+
"@vitest/browser": "catalog:tooling",
|
|
53
|
+
"@vitest/coverage-v8": "catalog:tooling",
|
|
30
54
|
"apca-w3": "^0.1.9",
|
|
31
55
|
"axe-core": "^4.10.2",
|
|
32
|
-
"playwright": "
|
|
33
|
-
"storybook": "
|
|
34
|
-
"storybook-dark-mode": "
|
|
35
|
-
"vite": "
|
|
36
|
-
"vite-plugin-dts": "
|
|
37
|
-
"vite-tsconfig-paths": "
|
|
38
|
-
"vitest": "
|
|
56
|
+
"playwright": "catalog:tooling",
|
|
57
|
+
"storybook": "catalog:tooling",
|
|
58
|
+
"storybook-dark-mode": "catalog:tooling",
|
|
59
|
+
"vite": "catalog:tooling",
|
|
60
|
+
"vite-plugin-dts": "catalog:tooling",
|
|
61
|
+
"vite-tsconfig-paths": "catalog:tooling",
|
|
62
|
+
"vitest": "catalog:tooling"
|
|
39
63
|
},
|
|
40
64
|
"peerDependencies": {
|
|
41
|
-
"react": "
|
|
42
|
-
"react-dom": "
|
|
43
|
-
"typescript": "
|
|
65
|
+
"react": "catalog:react",
|
|
66
|
+
"react-dom": "catalog:react",
|
|
67
|
+
"typescript": "catalog:tooling"
|
|
44
68
|
},
|
|
45
69
|
"dependencies": {
|
|
46
|
-
"@
|
|
47
|
-
"@
|
|
70
|
+
"@commercetools/nimbus-icons": "workspace:^",
|
|
71
|
+
"@commercetools/nimbus-tokens": "workspace:^",
|
|
72
|
+
"@chakra-ui/react": "catalog:react",
|
|
73
|
+
"@emotion/is-prop-valid": "catalog:react",
|
|
48
74
|
"@react-aria/optimize-locales-plugin": "^1.1.4",
|
|
49
|
-
"next-themes": "
|
|
50
|
-
"react-aria": "
|
|
51
|
-
"react-aria-components": "
|
|
75
|
+
"next-themes": "catalog:react",
|
|
76
|
+
"react-aria": "catalog:react",
|
|
77
|
+
"react-aria-components": "catalog:react",
|
|
52
78
|
"react-hotkeys-hook": "^4.6.1",
|
|
53
|
-
"react-stately": "
|
|
54
|
-
"react-use": "^17.5.1"
|
|
55
|
-
"@commercetools/nimbus-icons": "^0.0.2",
|
|
56
|
-
"@commercetools/nimbus-tokens": "^0.0.2"
|
|
79
|
+
"react-stately": "catalog:react",
|
|
80
|
+
"react-use": "^17.5.1"
|
|
57
81
|
},
|
|
58
82
|
"scripts": {
|
|
59
83
|
"build": "pnpm run build-theme-typings && pnpm run build-lib",
|
|
@@ -64,4 +88,4 @@
|
|
|
64
88
|
"storybook": "storybook dev -p 6006",
|
|
65
89
|
"build-storybook": "storybook build"
|
|
66
90
|
}
|
|
67
|
-
}
|
|
91
|
+
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import axe, { type Check, Rule } from "axe-core";
|
|
2
|
-
import { calcAPCA } from "apca-w3";
|
|
3
|
-
|
|
4
|
-
type ConformanceLevel = "custom";
|
|
5
|
-
|
|
6
|
-
type ConformanceThresholdFn = (
|
|
7
|
-
fontSize: string,
|
|
8
|
-
fontWeight: string
|
|
9
|
-
) => number | null;
|
|
10
|
-
|
|
11
|
-
// Augment Axe types to include the color utilities we use in this file
|
|
12
|
-
// https://github.com/dequelabs/axe-core/blob/develop/lib/commons/color/color.js
|
|
13
|
-
type Color = {
|
|
14
|
-
red: number;
|
|
15
|
-
green: number;
|
|
16
|
-
blue: number;
|
|
17
|
-
alpha: number;
|
|
18
|
-
toHexString: () => string;
|
|
19
|
-
};
|
|
20
|
-
declare module "axe-core" {
|
|
21
|
-
interface Commons {
|
|
22
|
-
color: {
|
|
23
|
-
getForegroundColor: (
|
|
24
|
-
node: HTMLElement,
|
|
25
|
-
_: unknown,
|
|
26
|
-
bgColor: Color | null
|
|
27
|
-
) => Color | null;
|
|
28
|
-
getBackgroundColor: (node: HTMLElement) => Color | null;
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const generateColorContrastAPCAConformanceCheck = (
|
|
34
|
-
conformanceLevel: string,
|
|
35
|
-
conformanceThresholdFn: ConformanceThresholdFn
|
|
36
|
-
): Check => ({
|
|
37
|
-
id: `color-contrast-apca-${conformanceLevel}-conformance`,
|
|
38
|
-
metadata: {
|
|
39
|
-
impact: "serious",
|
|
40
|
-
messages: {
|
|
41
|
-
pass:
|
|
42
|
-
"Element has sufficient APCA " +
|
|
43
|
-
conformanceLevel +
|
|
44
|
-
" level lightness contrast (Lc) of ${data.apcaContrast}Lc (foreground color: ${data.fgColor}, background color: ${data.bgColor}, font size: ${data.fontSize}, font weight: ${data.fontWeight}). Expected minimum APCA contrast of ${data.apcaThreshold}}",
|
|
45
|
-
fail: {
|
|
46
|
-
default:
|
|
47
|
-
"Element has insufficient APCA " +
|
|
48
|
-
conformanceLevel +
|
|
49
|
-
" level contrast of ${data.apcaContrast}Lc (foreground color: ${data.fgColor}, background color: ${data.bgColor}, font size: ${data.fontSize}, font weight: ${data.fontWeight}). Expected minimum APCA lightness contrast of ${data.apcaThreshold}Lc",
|
|
50
|
-
increaseFont:
|
|
51
|
-
"Element has insufficient APCA " +
|
|
52
|
-
conformanceLevel +
|
|
53
|
-
" level contrast of ${data.apcaContrast}Lc (foreground color: ${data.fgColor}, background color: ${data.bgColor}, font size: ${data.fontSize}, font weight: ${data.fontWeight}). Increase font size and/or font weight to meet APCA conformance minimums",
|
|
54
|
-
placeholder:
|
|
55
|
-
"Element has insufficient APCA " +
|
|
56
|
-
conformanceLevel +
|
|
57
|
-
" level contrast of ${data.apcaContrast}Lc (foreground color: ${data.fgColor}, background color: ${data.bgColor}, font size: ${data.fontSize}, font weight: ${data.fontWeight}). Using reduced threshold of 30Lc for placeholder",
|
|
58
|
-
},
|
|
59
|
-
incomplete: "Unable to determine APCA lightness contrast (Lc)",
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
evaluate(n) {
|
|
63
|
-
const node = n as HTMLElement;
|
|
64
|
-
const nodeStyle = window.getComputedStyle(node);
|
|
65
|
-
const fontSize = nodeStyle.getPropertyValue("font-size");
|
|
66
|
-
const fontWeight = nodeStyle.getPropertyValue("font-weight");
|
|
67
|
-
|
|
68
|
-
const bgColor: Color | null = axe.commons.color.getBackgroundColor(node);
|
|
69
|
-
const fgColor: Color | null = axe.commons.color.getForegroundColor(
|
|
70
|
-
node,
|
|
71
|
-
false,
|
|
72
|
-
bgColor
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
// missing data to determine APCA contrast for this node
|
|
76
|
-
if (!bgColor || !fgColor || !fontSize || !fontWeight) {
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const toRGBA = (color: Color) => {
|
|
81
|
-
return `rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha})`;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const apcaContrast = Math.abs(
|
|
85
|
-
calcAPCA(toRGBA(fgColor), toRGBA(bgColor)) as number
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// Check if element has data-placeholder attribute
|
|
89
|
-
const hasPlaceholderAttr = node.hasAttribute("data-placeholder");
|
|
90
|
-
const originalThreshold = conformanceThresholdFn(fontSize, fontWeight);
|
|
91
|
-
|
|
92
|
-
// Use reduced threshold of 30 for placeholders, otherwise use original threshold
|
|
93
|
-
const apcaThreshold = hasPlaceholderAttr ? 30 : originalThreshold;
|
|
94
|
-
|
|
95
|
-
this.data({
|
|
96
|
-
fgColor: fgColor.toHexString(),
|
|
97
|
-
bgColor: bgColor.toHexString(),
|
|
98
|
-
fontSize: `${((parseFloat(fontSize) * 72) / 96).toFixed(
|
|
99
|
-
1
|
|
100
|
-
)}pt (${parseFloat(fontSize)}px)`,
|
|
101
|
-
fontWeight: fontWeight,
|
|
102
|
-
apcaContrast: Math.round(apcaContrast * 100) / 100,
|
|
103
|
-
apcaThreshold: apcaThreshold,
|
|
104
|
-
messageKey:
|
|
105
|
-
apcaThreshold === null
|
|
106
|
-
? "increaseFont"
|
|
107
|
-
: hasPlaceholderAttr
|
|
108
|
-
? "placeholder"
|
|
109
|
-
: "default",
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
return apcaThreshold ? apcaContrast >= apcaThreshold : false;
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const generateColorContrastAPCARule = (conformanceLevel: string): Rule => ({
|
|
117
|
-
id: `color-contrast-apca-${conformanceLevel}`,
|
|
118
|
-
impact: "serious",
|
|
119
|
-
matches: "color-contrast-matches",
|
|
120
|
-
metadata: {
|
|
121
|
-
description: `Ensures the contrast between foreground and background colors meets APCA ${conformanceLevel} level conformance minimums thresholds`,
|
|
122
|
-
help: "Elements must meet APCA conformance minimums thresholds",
|
|
123
|
-
helpUrl:
|
|
124
|
-
"https://readtech.org/ARC/tests/visual-readability-contrast/?tn=criterion",
|
|
125
|
-
},
|
|
126
|
-
all: [`color-contrast-apca-${conformanceLevel}-conformance`],
|
|
127
|
-
tags: ["apca", "wcag3", `apca-${conformanceLevel}`],
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const registerAPCACheck = (
|
|
131
|
-
conformanceLevel: ConformanceLevel,
|
|
132
|
-
conformanceThresholdFn: ConformanceThresholdFn
|
|
133
|
-
) => {
|
|
134
|
-
if (typeof conformanceThresholdFn !== "function") {
|
|
135
|
-
throw new Error("Conformance threshold function is required");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
rules: [generateColorContrastAPCARule(conformanceLevel)],
|
|
140
|
-
checks: [
|
|
141
|
-
generateColorContrastAPCAConformanceCheck(
|
|
142
|
-
conformanceLevel,
|
|
143
|
-
conformanceThresholdFn
|
|
144
|
-
),
|
|
145
|
-
],
|
|
146
|
-
};
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
export type { ConformanceLevel, ConformanceThresholdFn };
|
|
150
|
-
export default registerAPCACheck;
|
package/.storybook/main.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { StorybookConfig } from "@storybook/react-vite";
|
|
2
|
-
|
|
3
|
-
import { join, dirname } from "path";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* This function is used to resolve the absolute path of a package.
|
|
7
|
-
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
|
|
8
|
-
*/
|
|
9
|
-
function getAbsolutePackagePath(value: string): any {
|
|
10
|
-
return dirname(require.resolve(join(value, "package.json")));
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const config: StorybookConfig = {
|
|
14
|
-
stories: ["../src/**/*.stories.tsx"],
|
|
15
|
-
addons: [
|
|
16
|
-
getAbsolutePackagePath("@storybook/addon-essentials"),
|
|
17
|
-
getAbsolutePackagePath("@storybook/addon-a11y"),
|
|
18
|
-
getAbsolutePackagePath("storybook-dark-mode"),
|
|
19
|
-
getAbsolutePackagePath("@storybook/experimental-addon-test"),
|
|
20
|
-
],
|
|
21
|
-
framework: {
|
|
22
|
-
name: getAbsolutePackagePath("@storybook/react-vite"),
|
|
23
|
-
options: {},
|
|
24
|
-
},
|
|
25
|
-
refs: {
|
|
26
|
-
"@chakra-ui/react": {
|
|
27
|
-
disable: true,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
core: {
|
|
31
|
-
disableTelemetry: true,
|
|
32
|
-
},
|
|
33
|
-
typescript: {
|
|
34
|
-
reactDocgen: "react-docgen-typescript",
|
|
35
|
-
// Provide your own options if necessary.
|
|
36
|
-
// See https://storybook.js.org/docs/configure/typescript for more information.
|
|
37
|
-
reactDocgenTypescriptOptions: {
|
|
38
|
-
compilerOptions: {
|
|
39
|
-
allowSyntheticDefaultImports: false,
|
|
40
|
-
esModuleInterop: false,
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
// Extend if needed...
|
|
44
|
-
propFilter: (prop) => {
|
|
45
|
-
// ... common props that every component may have
|
|
46
|
-
const whitelistedProps = ["ref", "colorScheme", "asChild"];
|
|
47
|
-
|
|
48
|
-
// ... props coming from the nimbus package
|
|
49
|
-
const isOneOfOurTypes = !!prop.parent?.fileName.includes("nimbus/src");
|
|
50
|
-
|
|
51
|
-
// ... props coming from the react-aria package
|
|
52
|
-
const isReactAriaProp =
|
|
53
|
-
!!prop.parent?.fileName.includes("@react-types");
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
isOneOfOurTypes ||
|
|
57
|
-
isReactAriaProp ||
|
|
58
|
-
whitelistedProps.includes(prop.name)
|
|
59
|
-
);
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
export default config;
|
package/.storybook/preview.tsx
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
2
|
-
import type { Preview } from "@storybook/react";
|
|
3
|
-
import { NimbusProvider } from "../src";
|
|
4
|
-
import { DARK_MODE_EVENT_NAME } from "storybook-dark-mode";
|
|
5
|
-
import { addons } from "@storybook/preview-api";
|
|
6
|
-
|
|
7
|
-
import APCACheck from "./apca-check";
|
|
8
|
-
|
|
9
|
-
const apca = APCACheck("custom", (fontSize: string) => {
|
|
10
|
-
const size = parseFloat(fontSize);
|
|
11
|
-
switch (true) {
|
|
12
|
-
case size >= 32:
|
|
13
|
-
return 45;
|
|
14
|
-
default:
|
|
15
|
-
return 60;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
// get channel to listen to event emitter
|
|
20
|
-
const channel = addons.getChannel();
|
|
21
|
-
|
|
22
|
-
const ThemeDecorator = ({ children }) => {
|
|
23
|
-
const [isDark, setDark] = useState(false);
|
|
24
|
-
const theme = isDark ? "dark" : "light";
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
const { current } = JSON.parse(
|
|
28
|
-
// TODO: find out if there is a more elegant solution
|
|
29
|
-
localStorage.getItem("sb-addon-themes-3") || "{}"
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
setDark(current === "dark");
|
|
33
|
-
|
|
34
|
-
channel.on(DARK_MODE_EVENT_NAME, (darkMode) => {
|
|
35
|
-
setDark(darkMode);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return () => channel.off(DARK_MODE_EVENT_NAME, setDark);
|
|
39
|
-
}, [channel]);
|
|
40
|
-
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
document.documentElement.classList.remove("light", "dark");
|
|
43
|
-
document.documentElement.classList.add(theme);
|
|
44
|
-
}, [theme]);
|
|
45
|
-
|
|
46
|
-
return <NimbusProvider defaultTheme={theme}>{children}</NimbusProvider>;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const preview: Preview = {
|
|
50
|
-
parameters: {
|
|
51
|
-
darkMode: {
|
|
52
|
-
stylePreview: true,
|
|
53
|
-
classTarget: "html",
|
|
54
|
-
},
|
|
55
|
-
backgrounds: {
|
|
56
|
-
disable: true,
|
|
57
|
-
},
|
|
58
|
-
a11y: {
|
|
59
|
-
config: {
|
|
60
|
-
checks: [...apca.checks],
|
|
61
|
-
rules: [
|
|
62
|
-
{
|
|
63
|
-
// disabled, as radix is using APCA algorithm while Storybook uses WCAG
|
|
64
|
-
// @see https://web.dev/articles/color-and-contrast-accessibility#apca)
|
|
65
|
-
|
|
66
|
-
id: "color-contrast",
|
|
67
|
-
enabled: false,
|
|
68
|
-
},
|
|
69
|
-
...apca.rules,
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
/*
|
|
73
|
-
* Axe's options parameter
|
|
74
|
-
* See https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter
|
|
75
|
-
* to learn more about the available options.
|
|
76
|
-
*/
|
|
77
|
-
options: {},
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
tags: ["autodocs", "a11y-test"],
|
|
81
|
-
decorators: [
|
|
82
|
-
(Story) => {
|
|
83
|
-
return (
|
|
84
|
-
<ThemeDecorator>
|
|
85
|
-
<Story />
|
|
86
|
-
</ThemeDecorator>
|
|
87
|
-
);
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
export default preview;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
|
|
2
|
-
import { beforeAll } from "vitest";
|
|
3
|
-
import { setProjectAnnotations } from "@storybook/react";
|
|
4
|
-
import * as projectAnnotations from "./preview";
|
|
5
|
-
|
|
6
|
-
// This is an important step to apply the right configuration when testing your stories.
|
|
7
|
-
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
|
|
8
|
-
const project = setProjectAnnotations([
|
|
9
|
-
a11yAddonAnnotations,
|
|
10
|
-
projectAnnotations,
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
beforeAll(project.beforeAll);
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# ADR: On Consumer Component API's
|
|
2
|
-
|
|
3
|
-
## Context
|
|
4
|
-
|
|
5
|
-
We needed an Alert component to show informational or warning messages. The
|
|
6
|
-
component should allow:
|
|
7
|
-
|
|
8
|
-
- A title and description.
|
|
9
|
-
- An optional dismiss button.
|
|
10
|
-
- Additional buttons or controls.
|
|
11
|
-
- Spacing/styling overrides (e.g. px, py).
|
|
12
|
-
|
|
13
|
-
In early explorations, we tried to expose everything via props on the main
|
|
14
|
-
`Alert`—this seemed convenient but would quickly became unwieldy when
|
|
15
|
-
requirements changed. This led to a discussion about how to structure the API
|
|
16
|
-
for components in a way that is both flexible and maintainable.
|
|
17
|
-
|
|
18
|
-
## Early Attempts
|
|
19
|
-
|
|
20
|
-
### Attempt A: One Big Alert with Child Buttons
|
|
21
|
-
|
|
22
|
-
```jsx
|
|
23
|
-
<Alert
|
|
24
|
-
title="title"
|
|
25
|
-
description="description"
|
|
26
|
-
onDismiss={() => void}
|
|
27
|
-
px="4"
|
|
28
|
-
py="2"
|
|
29
|
-
>
|
|
30
|
-
<button>Dismiss</button>
|
|
31
|
-
<button>Click me</button>
|
|
32
|
-
</Alert>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
1. title and description are top-level props.
|
|
36
|
-
2. children are the alert's buttons.
|
|
37
|
-
|
|
38
|
-
**Issue**: If we need new kinds of controls (e.g., a link, extra text, or
|
|
39
|
-
re-positioned buttons), we must keep adding or repurposing props. The line
|
|
40
|
-
between "belongs in children" vs. "belongs in dedicated props" can become
|
|
41
|
-
blurry.
|
|
42
|
-
|
|
43
|
-
### Attempt B: Specialized Props for Each Slot
|
|
44
|
-
|
|
45
|
-
```jsx
|
|
46
|
-
<Alert
|
|
47
|
-
alertTitleStyle="bold"
|
|
48
|
-
title="title"
|
|
49
|
-
description="description"
|
|
50
|
-
onDismiss={() => void}
|
|
51
|
-
px="4"
|
|
52
|
-
py="2"
|
|
53
|
-
alertControls={
|
|
54
|
-
<>
|
|
55
|
-
<button>Dismiss</button>
|
|
56
|
-
<button>Click me</button>
|
|
57
|
-
</>
|
|
58
|
-
}
|
|
59
|
-
/>
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
1. We introduced an alertControls prop for the buttons.
|
|
63
|
-
2. We also added alertTitleStyle to control how the title looks.
|
|
64
|
-
|
|
65
|
-
**Issue**: As the design evolves (e.g., "Now we need the title right‐aligned, or
|
|
66
|
-
a sub‐title below the main title"), we keep adding ad-hoc props like
|
|
67
|
-
titlePosition, alertControlsAlignment, etc. The `<Alert>` props list grows large
|
|
68
|
-
and messy.
|
|
69
|
-
|
|
70
|
-
### Attempt C: Even More Props for Layout / Positioning
|
|
71
|
-
|
|
72
|
-
```jsx
|
|
73
|
-
<Alert
|
|
74
|
-
alertTitleStyle="bold"
|
|
75
|
-
title="title"
|
|
76
|
-
titlePosition="right"
|
|
77
|
-
description="description"
|
|
78
|
-
onDismiss={() => void}
|
|
79
|
-
px="4"
|
|
80
|
-
py="2"
|
|
81
|
-
alertControls={
|
|
82
|
-
<>
|
|
83
|
-
<button>Dismiss</button>
|
|
84
|
-
<button>Click me</button>
|
|
85
|
-
</>
|
|
86
|
-
}
|
|
87
|
-
/>
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Issue**: The top-level `<Alert>` component now has numerous styling, layout,
|
|
91
|
-
and content props all jumbled together. If a new design wants a second dismiss
|
|
92
|
-
button or a multi-line description, we must add more props. This is non-scalable
|
|
93
|
-
and not very semantic.
|
|
94
|
-
|
|
95
|
-
## Final Decision: Compound Components
|
|
96
|
-
|
|
97
|
-
We decided to adopt compound components (a pattern in which sub-elements are
|
|
98
|
-
also React components). The final API looks like:
|
|
99
|
-
|
|
100
|
-
```jsx
|
|
101
|
-
<Alert px="4" py="2">
|
|
102
|
-
<Alert.Title fontStyle="bold">
|
|
103
|
-
Alert Title
|
|
104
|
-
</Alert.Title>
|
|
105
|
-
<Alert.Description>
|
|
106
|
-
A short alert description.
|
|
107
|
-
</Alert.Description>
|
|
108
|
-
<Alert.DismissButton onClick={() => void} />
|
|
109
|
-
</Alert>
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Key Changes:
|
|
113
|
-
|
|
114
|
-
1. Children become semantic slots: `<Alert.Title>`, `<Alert.Description>`, and
|
|
115
|
-
`<Alert.DismissButton>`.
|
|
116
|
-
2. Each slot can handle its own styling or props. For instance, Alert.Title
|
|
117
|
-
might accept a fontStyle prop, Alert.DismissButton handles its own click
|
|
118
|
-
event.
|
|
119
|
-
3. The root `<Alert>` only handles general layout or high-level variant props
|
|
120
|
-
(e.g., px, py, severity).
|
|
121
|
-
|
|
122
|
-
### Why this is better:
|
|
123
|
-
|
|
124
|
-
- **Clear separation of concerns**: Layout/styling for each slot belongs to that
|
|
125
|
-
slot. The main `<Alert>` only handles spacing or theming.
|
|
126
|
-
- **Easier to extend**: If we need a second sub-element (e.g., `<Alert.Icon>` or
|
|
127
|
-
`<Alert.Footer>`), we just introduce a new subcomponent. We don't clog
|
|
128
|
-
`<Alert>` with more props.
|
|
129
|
-
- **Semantic**: `<Alert.Title>` and `<Alert.Description>` are more descriptive
|
|
130
|
-
than `title="..."` or `alertControls={...}`.
|
|
131
|
-
|
|
132
|
-
## Consequences
|
|
133
|
-
|
|
134
|
-
- We have a more verbose but much more flexible API.
|
|
135
|
-
- Consumers build their alert in a semantic, composable way.
|
|
136
|
-
- We can add or rearrange subcomponents without rewriting the main `<Alert>`
|
|
137
|
-
props or code.
|
|
138
|
-
- If developers want quick usage (like a single short message), they might find
|
|
139
|
-
passing a couple props simpler – but we've prioritized long-term
|
|
140
|
-
maintainability and clarity.
|
|
141
|
-
|
|
142
|
-
## Examples in Practice
|
|
143
|
-
|
|
144
|
-
### 1. Basic Alert
|
|
145
|
-
|
|
146
|
-
```jsx
|
|
147
|
-
<Alert>
|
|
148
|
-
<Alert.Title>Warning!</Alert.Title>
|
|
149
|
-
<Alert.Description>Please fill out all required fields.</Alert.Description>
|
|
150
|
-
<Alert.DismissButton onClick={onClose} />
|
|
151
|
-
</Alert>
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### 2. Alert with Extra Controls
|
|
155
|
-
|
|
156
|
-
```jsx
|
|
157
|
-
<Alert px="4" py="3">
|
|
158
|
-
<Alert.Title fontStyle="bold">Network Error</Alert.Title>
|
|
159
|
-
<Alert.Description>
|
|
160
|
-
We could not reach the server. Please try again.
|
|
161
|
-
</Alert.Description>
|
|
162
|
-
<Alert.DismissButton onClick={onClose} />
|
|
163
|
-
<Alert.Controls>
|
|
164
|
-
<Button onClick={onRetry}>Retry</Button>
|
|
165
|
-
</Alert.Controls>
|
|
166
|
-
</Alert>
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
## Summary
|
|
170
|
-
|
|
171
|
-
- Inline props for major sections quickly lead to "prop creep."
|
|
172
|
-
- Compound components keep `<Alert>` minimal and delegate content/markup details
|
|
173
|
-
to semantically named subcomponents.
|
|
174
|
-
- Layout changes or extra features do not require new top-level props on
|
|
175
|
-
`<Alert>`.
|
|
176
|
-
|
|
177
|
-
This approach scales better and is more maintainable as the design evolves.
|