@persona/design-system 0.5.1 → 0.6.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/CHANGELOG.md +6 -0
- package/dist/{Breadcrumbs-ClKHNIr-.mjs → Breadcrumbs-CR-xdruP.mjs} +3 -3
- package/dist/{Breadcrumbs-ClKHNIr-.mjs.map → Breadcrumbs-CR-xdruP.mjs.map} +1 -1
- package/dist/Card2.d.mts +2 -2
- package/dist/{CardV2-CFTjYWoO.mjs → CardV2-CBjhsfrn.mjs} +5 -5
- package/dist/{CardV2-CFTjYWoO.mjs.map → CardV2-CBjhsfrn.mjs.map} +1 -1
- package/dist/{Checkbox-CyeitZ5q.mjs → Checkbox-BHZ7c7_6.mjs} +2 -2
- package/dist/{Checkbox-CyeitZ5q.mjs.map → Checkbox-BHZ7c7_6.mjs.map} +1 -1
- package/dist/{Combobox-Ddas5FN-.mjs → Combobox-BCYLeZDP.mjs} +6 -6
- package/dist/{Combobox-Ddas5FN-.mjs.map → Combobox-BCYLeZDP.mjs.map} +1 -1
- package/dist/{Combobox-DX4DLe1b.d.mts → Combobox-DMN3nc7E.d.mts} +3 -3
- package/dist/Combobox.d.mts +2 -2
- package/dist/{ComboboxBase-Ds_i3K2m.d.mts → ComboboxBase-DBLJYQrh.d.mts} +2 -2
- package/dist/ComboboxBase.d.mts +1 -1
- package/dist/{ComboboxMultiSelect-S6oFJcOS.d.mts → ComboboxMultiSelect-CZRLyM_y.d.mts} +2 -2
- package/dist/ComboboxMultiSelect.d.mts +1 -1
- package/dist/{ComboboxSingleSelect-DFzCwW1Y.d.mts → ComboboxSingleSelect-BS6pZpU_.d.mts} +3 -3
- package/dist/ComboboxSingleSelect.d.mts +1 -1
- package/dist/{ConfigFormGroup-DcsM-u8o.mjs → ConfigFormGroup-BnRDAs0j.mjs} +2 -2
- package/dist/{ConfigFormGroup-DcsM-u8o.mjs.map → ConfigFormGroup-BnRDAs0j.mjs.map} +1 -1
- package/dist/{DatePicker-DTT-mJ8r.mjs → DatePicker-BcjrAr7o.mjs} +6 -6
- package/dist/{DatePicker-DTT-mJ8r.mjs.map → DatePicker-BcjrAr7o.mjs.map} +1 -1
- package/dist/{DropdownButton-DV5if_uG.mjs → DropdownButton-l-fzkb5_.mjs} +2 -2
- package/dist/{DropdownButton-DV5if_uG.mjs.map → DropdownButton-l-fzkb5_.mjs.map} +1 -1
- package/dist/DropdownButton.d.mts +1 -1
- package/dist/{DropdownMenu-CbhEzWy1.d.mts → DropdownMenu-Bg68vvxx.d.mts} +2 -2
- package/dist/{DropdownMenu-DovtBJBs.mjs → DropdownMenu-C0WK4bM0.mjs} +2 -2
- package/dist/{DropdownMenu-DovtBJBs.mjs.map → DropdownMenu-C0WK4bM0.mjs.map} +1 -1
- package/dist/DropdownMenu.d.mts +1 -1
- package/dist/{FormControl-BvRzRknE.mjs → FormControl-BzMbbgr0.mjs} +3 -3
- package/dist/{FormControl-BvRzRknE.mjs.map → FormControl-BzMbbgr0.mjs.map} +1 -1
- package/dist/{FormField-BDJ6zNE6.mjs → FormField-2sNS5PzN.mjs} +14 -14
- package/dist/{FormField-BDJ6zNE6.mjs.map → FormField-2sNS5PzN.mjs.map} +1 -1
- package/dist/{HoverCopyableField-WP6DPjy1.mjs → HoverCopyableField-CeJ0UP87.mjs} +2 -2
- package/dist/{HoverCopyableField-WP6DPjy1.mjs.map → HoverCopyableField-CeJ0UP87.mjs.map} +1 -1
- package/dist/InlineCombobox.d.mts +1 -1
- package/dist/InlineInput.d.mts +1 -1
- package/dist/{Input-DbfwNzS_.mjs → Input-DGWThZlt.mjs} +2 -2
- package/dist/{Input-DbfwNzS_.mjs.map → Input-DGWThZlt.mjs.map} +1 -1
- package/dist/{ListBox-P1eTecdo.d.mts → ListBox-Awtw7Xy_.d.mts} +2 -2
- package/dist/{ListBox-CXh9Jfb-.mjs → ListBox-DqII8giL.mjs} +6 -6
- package/dist/{ListBox-CXh9Jfb-.mjs.map → ListBox-DqII8giL.mjs.map} +1 -1
- package/dist/ListBox.d.mts +1 -1
- package/dist/ListBoxField.d.mts +2 -2
- package/dist/{LoadingShimmer-DeVCDCjT.mjs → LoadingShimmer-ZyzJs5Vi.mjs} +1 -1
- package/dist/{LoadingShimmer-DeVCDCjT.mjs.map → LoadingShimmer-ZyzJs5Vi.mjs.map} +1 -1
- package/dist/{LogicRow-DtZYOzQ8.d.mts → LogicRow-DIn0gLEq.d.mts} +2 -2
- package/dist/LogicRow.d.mts +1 -1
- package/dist/{Menu-CAGTCBqj.mjs → Menu-CeV3lL2g.mjs} +1 -1
- package/dist/{Menu-CAGTCBqj.mjs.map → Menu-CeV3lL2g.mjs.map} +1 -1
- package/dist/{Menu-_loh8pe3.d.mts → Menu-DdHN-drQ.d.mts} +2 -2
- package/dist/Menu.d.mts +1 -1
- package/dist/{PageHeader-wpvRRTaa.mjs → PageHeader-UI_6yImi.mjs} +2 -2
- package/dist/{PageHeader-wpvRRTaa.mjs.map → PageHeader-UI_6yImi.mjs.map} +1 -1
- package/dist/{Pagination-wjr3W3xf.mjs → Pagination-DgA0U1fa.mjs} +3 -3
- package/dist/{Pagination-wjr3W3xf.mjs.map → Pagination-DgA0U1fa.mjs.map} +1 -1
- package/dist/{Pii-Bm-qkweh.mjs → Pii-bxG0qu3t.mjs} +1 -1
- package/dist/{Pii-Bm-qkweh.mjs.map → Pii-bxG0qu3t.mjs.map} +1 -1
- package/dist/{Popover-DUyzmq3e.mjs → Popover-UiOUt5up.mjs} +1 -1
- package/dist/{Popover-DUyzmq3e.mjs.map → Popover-UiOUt5up.mjs.map} +1 -1
- package/dist/{Radio-CkugnL91.mjs → Radio-BrQzZhwP.mjs} +2 -2
- package/dist/{Radio-CkugnL91.mjs.map → Radio-BrQzZhwP.mjs.map} +1 -1
- package/dist/{RadioGroup-8dI8gljw.mjs → RadioGroup-Bl9oXPIo.mjs} +2 -2
- package/dist/{RadioGroup-8dI8gljw.mjs.map → RadioGroup-Bl9oXPIo.mjs.map} +1 -1
- package/dist/{SegmentedControl-DQE0hN57.mjs → SegmentedControl-BozydMtT.mjs} +2 -2
- package/dist/{SegmentedControl-DQE0hN57.mjs.map → SegmentedControl-BozydMtT.mjs.map} +1 -1
- package/dist/{Select-D9OVjzPR.mjs → Select-CktsIrzf.mjs} +4 -4
- package/dist/{Select-D9OVjzPR.mjs.map → Select-CktsIrzf.mjs.map} +1 -1
- package/dist/{Select-wnr46ROZ.d.mts → Select-yPqzqe5k.d.mts} +2 -2
- package/dist/Select.d.mts +1 -1
- package/dist/{Spinner-gBNWIwOn.mjs → Spinner-Dpw3-3JS.mjs} +1 -1
- package/dist/{Spinner-gBNWIwOn.mjs.map → Spinner-Dpw3-3JS.mjs.map} +1 -1
- package/dist/{TabBar-B__54oO3.mjs → TabBar-Dw3xE_B-.mjs} +1 -1
- package/dist/{TabBar-B__54oO3.mjs.map → TabBar-Dw3xE_B-.mjs.map} +1 -1
- package/dist/{Table-CqIi5mVF.mjs → Table-ELLvSvH4.mjs} +2 -2
- package/dist/{Table-CqIi5mVF.mjs.map → Table-ELLvSvH4.mjs.map} +1 -1
- package/dist/{TableBox-C-8RxZT4.mjs → TableBox-CCfha6G2.mjs} +7 -7
- package/dist/{TableBox-C-8RxZT4.mjs.map → TableBox-CCfha6G2.mjs.map} +1 -1
- package/dist/TableBox.d.mts +1 -1
- package/dist/{TableBoxCell-CQ3zT1jG.d.mts → TableBoxCell-xnzuHPV1.d.mts} +4 -4
- package/dist/TableBoxCell.d.mts +1 -1
- package/dist/TableBoxField.d.mts +3 -3
- package/dist/{TableBoxRow-ClK2pceY.d.mts → TableBoxRow-BBDMh5xl.d.mts} +2 -2
- package/dist/TableBoxRow.d.mts +1 -1
- package/dist/{TableBoxRowActions-CoF3DuUQ.d.mts → TableBoxRowActions-DCfol4GC.d.mts} +2 -2
- package/dist/TableBoxRowActions.d.mts +1 -1
- package/dist/{TableControls-DplArh-9.mjs → TableControls-C-yb5EYU.mjs} +11 -11
- package/dist/{TableControls-DplArh-9.mjs.map → TableControls-C-yb5EYU.mjs.map} +1 -1
- package/dist/{TechnicalSticker-D6MO_IfT.mjs → TechnicalSticker-CLbNA0kp.mjs} +1 -1
- package/dist/{TechnicalSticker-D6MO_IfT.mjs.map → TechnicalSticker-CLbNA0kp.mjs.map} +1 -1
- package/dist/{TextArea-CYirq-B2.mjs → TextArea-oAK1DKId.mjs} +2 -2
- package/dist/{TextArea-CYirq-B2.mjs.map → TextArea-oAK1DKId.mjs.map} +1 -1
- package/dist/{Toggle-CqgFNIYS.mjs → Toggle-DZzirZ8p.mjs} +2 -2
- package/dist/{Toggle-CqgFNIYS.mjs.map → Toggle-DZzirZ8p.mjs.map} +1 -1
- package/dist/components/BottomPanel/index.mjs +1 -1
- package/dist/components/Breadcrumbs/index.mjs +1 -1
- package/dist/components/ButtonGroup/index.mjs +1 -1
- package/dist/components/CardV2/index.mjs +1 -1
- package/dist/components/Checkbox/index.mjs +1 -1
- package/dist/components/Combobox/index.d.mts +2 -2
- package/dist/components/Combobox/index.mjs +1 -1
- package/dist/components/ConfigFormGroup/index.mjs +2 -2
- package/dist/components/DataTable/TableControls/index.mjs +1 -1
- package/dist/components/DataTable/index.mjs +7 -7
- package/dist/components/DataTable/types.d.mts +1 -1
- package/dist/components/DatePicker/index.mjs +1 -1
- package/dist/components/DropdownButton/index.mjs +1 -1
- package/dist/components/DropdownMenu/index.d.mts +1 -1
- package/dist/components/DropdownMenu/index.mjs +1 -1
- package/dist/components/FormControl/index.mjs +2 -2
- package/dist/components/FormField/index.mjs +1 -1
- package/dist/components/HoverCopyableField/index.mjs +1 -1
- package/dist/components/ImageTile/index.mjs +3 -3
- package/dist/components/Input/index.mjs +1 -1
- package/dist/components/ListBox/index.d.mts +3 -3
- package/dist/components/ListBox/index.mjs +1 -1
- package/dist/components/LoadingShimmer/index.mjs +1 -1
- package/dist/components/MaskedInput/index.mjs +1 -1
- package/dist/components/Menu/index.d.mts +1 -1
- package/dist/components/Menu/index.mjs +1 -1
- package/dist/components/Modal/index.mjs +3 -65
- package/dist/components/Modal/index.mjs.map +1 -1
- package/dist/components/PageHeader/index.mjs +1 -1
- package/dist/components/Pagination/index.mjs +1 -1
- package/dist/components/Pii/index.mjs +1 -1
- package/dist/components/Popover/index.mjs +1 -1
- package/dist/components/Radio/index.mjs +1 -1
- package/dist/components/RadioGroup/index.mjs +1 -1
- package/dist/components/RightPanel/index.mjs +1 -1
- package/dist/components/SegmentedControl/index.mjs +1 -1
- package/dist/components/Select/index.d.mts +1 -1
- package/dist/components/Select/index.mjs +1 -1
- package/dist/components/Slider/index.mjs +1 -1
- package/dist/components/SmartTextInput/parser/method-chain/grammar.pegjs +219 -0
- package/dist/components/SmartTextInput/parser/smart-text/grammar.pegjs +154 -0
- package/dist/components/Spinner/index.mjs +1 -1
- package/dist/components/TabBar/index.mjs +1 -1
- package/dist/components/Table/index.mjs +1 -1
- package/dist/components/TableBox/index.d.mts +1 -1
- package/dist/components/TableBox/index.mjs +1 -1
- package/dist/components/TechnicalSticker/index.mjs +1 -1
- package/dist/components/TextArea/index.mjs +1 -1
- package/dist/components/Toggle/index.mjs +1 -1
- package/dist/fieldPickerOptions.d.mts +1 -1
- package/dist/{index-BJr_obTf.d.mts → index-CBWvk6Ch.d.mts} +3 -3
- package/dist/inputFields.d.mts +3 -3
- package/dist/{intersperse-CRUnXmnu.mjs → intersperse-vOYvFOfF.mjs} +1 -1
- package/dist/{intersperse-CRUnXmnu.mjs.map → intersperse-vOYvFOfF.mjs.map} +1 -1
- package/dist/lib/useModalInsetRight.mjs +69 -0
- package/dist/lib/useModalInsetRight.mjs.map +1 -0
- package/dist/patterns/LayoutLoadingShimmer/index.mjs +4 -4
- package/dist/useComboboxFooterAction.d.mts +1 -1
- package/dist/{useFormField-C-K1lgmv.mjs → useFormField-DhYd6bNn.mjs} +2 -2
- package/dist/{useFormField-C-K1lgmv.mjs.map → useFormField-DhYd6bNn.mjs.map} +1 -1
- package/dist/{useFormGroup-y-duFylq.mjs → useFormGroup-DWVW7A9f.mjs} +1 -1
- package/dist/{useFormGroup-y-duFylq.mjs.map → useFormGroup-DWVW7A9f.mjs.map} +1 -1
- package/dist/useTruncation.d.mts +1 -1
- package/llms.txt +1 -0
- package/package.json +3 -1
- package/skills/design-system-component-authoring/SKILL.md +79 -0
- package/skills/design-system-component-authoring/clarifying-scope.md +18 -0
- package/skills/design-system-component-authoring/component-conventions.md +70 -0
- package/skills/design-system-component-authoring/prop-interface-patterns.md +30 -0
- /package/dist/{useModalInsetRight.d.mts → lib/useModalInsetRight.d.mts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as useFormGroup } from "./useFormGroup-
|
|
1
|
+
import { n as useFormGroup } from "./useFormGroup-DWVW7A9f.mjs";
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
3
|
//#region components/FormControl/useFormField.ts
|
|
4
4
|
const FormControlContext = createContext({});
|
|
@@ -22,4 +22,4 @@ const useFormField = (props) => {
|
|
|
22
22
|
//#endregion
|
|
23
23
|
export { useFormField as n, FormControlContext as t };
|
|
24
24
|
|
|
25
|
-
//# sourceMappingURL=useFormField-
|
|
25
|
+
//# sourceMappingURL=useFormField-DhYd6bNn.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormField-
|
|
1
|
+
{"version":3,"file":"useFormField-DhYd6bNn.mjs","names":[],"sources":["../components/FormControl/useFormField.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport useFormGroup from 'design-system/components/ConfigFormGroup/useFormGroup';\nimport type ErrorProps from 'design-system/types/ErrorProps';\n\nexport interface FormControlContextProps extends ErrorProps {\n inputId?: string;\n helperTextId?: string;\n errorTextId?: string;\n warningTextId?: string;\n labelId?: string;\n disabled?: boolean;\n maxLength?: number;\n configField?: boolean;\n}\n\nexport const FormControlContext = createContext<FormControlContextProps>({});\n\nconst useFormField = (props: Partial<FormControlContextProps>) => {\n const group = useFormGroup();\n const field = useContext(FormControlContext);\n\n const inputId = props.inputId ?? field.inputId;\n\n return {\n configField: props.configField ?? group.configField,\n hasError: props.hasError ?? field.hasError,\n hasWarning: props.hasWarning ?? field.hasWarning,\n inputId,\n helperTextId: props.helperTextId ?? field.helperTextId,\n errorTextId: props.errorTextId ?? field.errorTextId,\n warningTextId: props.warningTextId ?? field.warningTextId,\n labelId: props.labelId ?? field.labelId,\n disabled: props.disabled ?? field.disabled,\n maxLength: props.maxLength ?? field.maxLength,\n };\n};\n\nexport default useFormField;\n"],"mappings":";;;AAgBA,MAAa,qBAAqB,cAAuC,EAAE,CAAC;AAE5E,MAAM,gBAAgB,UAA4C;CAChE,MAAM,QAAQ,cAAc;CAC5B,MAAM,QAAQ,WAAW,mBAAmB;CAE5C,MAAM,UAAU,MAAM,WAAW,MAAM;AAEvC,QAAO;EACL,aAAa,MAAM,eAAe,MAAM;EACxC,UAAU,MAAM,YAAY,MAAM;EAClC,YAAY,MAAM,cAAc,MAAM;EACtC;EACA,cAAc,MAAM,gBAAgB,MAAM;EAC1C,aAAa,MAAM,eAAe,MAAM;EACxC,eAAe,MAAM,iBAAiB,MAAM;EAC5C,SAAS,MAAM,WAAW,MAAM;EAChC,UAAU,MAAM,YAAY,MAAM;EAClC,WAAW,MAAM,aAAa,MAAM;EACrC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormGroup-
|
|
1
|
+
{"version":3,"file":"useFormGroup-DWVW7A9f.mjs","names":[],"sources":["../components/ConfigFormGroup/useFormGroup.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nexport interface FormGroupContextProps {\n configField?: boolean;\n /**\n * The z-index to use when labels are rendered as tooltips (e.g. when configField is true).\n */\n labelTooltipZIndex?: number;\n}\n\nexport const FormGroupContext = createContext<FormGroupContextProps>({});\n\nconst useFormGroup = (props?: Partial<FormGroupContextProps>) => {\n const field = useContext(FormGroupContext);\n\n return {\n configField: props?.configField ?? field.configField,\n labelTooltipZIndex: props?.labelTooltipZIndex ?? field.labelTooltipZIndex,\n };\n};\n\nexport default useFormGroup;\n"],"mappings":";;AAUA,MAAa,mBAAmB,cAAqC,EAAE,CAAC;AAExE,MAAM,gBAAgB,UAA2C;CAC/D,MAAM,QAAQ,WAAW,iBAAiB;AAE1C,QAAO;EACL,aAAa,OAAO,eAAe,MAAM;EACzC,oBAAoB,OAAO,sBAAsB,MAAM;EACxD"}
|
package/dist/useTruncation.d.mts
CHANGED
package/llms.txt
CHANGED
|
@@ -17,6 +17,7 @@ For exact prop types, prefer the published type declarations (`dist/**/*.d.mts`,
|
|
|
17
17
|
- [Tokens](skills/ui-authoring/TOKENS.md): Color / Spacing / Typography selection and catalog, radius, charts
|
|
18
18
|
- [Patterns](skills/ui-authoring/PATTERNS.md): forms, layout, indicators, feedback, empty states, charts, panels
|
|
19
19
|
- [Components](skills/ui-authoring/COMPONENTS.md): which PDS component to use (and its import path); APIs live in that component's `.mdx` when one exists, otherwise in `dist/components/<Name>/index.d.mts`
|
|
20
|
+
- [design-system-component-authoring](skills/design-system-component-authoring/SKILL.md): authoring a new PDS component in this repo — clarifying scope, component conventions, prop interface patterns
|
|
20
21
|
|
|
21
22
|
## Imports
|
|
22
23
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@persona/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "React components for Persona UI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tanstack-intent"
|
|
@@ -114,6 +114,7 @@
|
|
|
114
114
|
"./lib/useControlled": "./dist/lib/useControlled.mjs",
|
|
115
115
|
"./lib/useEmbeddedSurface": "./dist/lib/useEmbeddedSurface.mjs",
|
|
116
116
|
"./lib/useIsOverflow": "./dist/lib/useIsOverflow.mjs",
|
|
117
|
+
"./lib/useModalInsetRight": "./dist/lib/useModalInsetRight.mjs",
|
|
117
118
|
"./lib/useOutsideClick": "./dist/lib/useOutsideClick.mjs",
|
|
118
119
|
"./lib/useResizablePanel": "./dist/lib/useResizablePanel.mjs",
|
|
119
120
|
"./lib/useScrollOverflow": "./dist/lib/useScrollOverflow.mjs",
|
|
@@ -346,6 +347,7 @@
|
|
|
346
347
|
"./lib/useControlled": "./dist/lib/useControlled.mjs",
|
|
347
348
|
"./lib/useEmbeddedSurface": "./dist/lib/useEmbeddedSurface.mjs",
|
|
348
349
|
"./lib/useIsOverflow": "./dist/lib/useIsOverflow.mjs",
|
|
350
|
+
"./lib/useModalInsetRight": "./dist/lib/useModalInsetRight.mjs",
|
|
349
351
|
"./lib/useOutsideClick": "./dist/lib/useOutsideClick.mjs",
|
|
350
352
|
"./lib/useResizablePanel": "./dist/lib/useResizablePanel.mjs",
|
|
351
353
|
"./lib/useScrollOverflow": "./dist/lib/useScrollOverflow.mjs",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-system-component-authoring
|
|
3
|
+
description: Use when building a new Persona design system component under packages/design-system/components/, or turning a designer's description, Figma frame, or AI-generated first draft into one. Also use when determining prop interfaces, weighing `children` vs a typed `items` array, questioning a composer pattern, spotting props that allow impossible states, finding hardcoded colors or missing tokens, or seeing a component rebuild what an existing DS primitive already does.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Design System Component Authoring
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Core principle: **model the real requirement with the smallest prop interface that makes impossible
|
|
11
|
+
states unrepresentable, compose existing design-system components instead of rebuilding them, and
|
|
12
|
+
ask before inventing scope.** A first pass built this way needs almost no engineer refactoring.
|
|
13
|
+
|
|
14
|
+
These components usually start from a designer's description (the designer may not code), so the
|
|
15
|
+
failure mode is predictable: guessing at scope, inventing props, reaching for the most
|
|
16
|
+
flexible-looking type. Prefer clarifying questions and small, correct interfaces over feature-rich
|
|
17
|
+
guesses.
|
|
18
|
+
|
|
19
|
+
## When to use
|
|
20
|
+
|
|
21
|
+
- Building a new component under `packages/design-system/components/`.
|
|
22
|
+
- Turning a designer's description, a Figma frame, or an AI draft into a real DS component.
|
|
23
|
+
|
|
24
|
+
**REQUIRED BACKGROUND — load this too:**
|
|
25
|
+
|
|
26
|
+
- `ui-authoring` — design tokens (`Color`, `Spacing`, `Typography`), when to use `Stack`/`HStack`/`Text` instead of styled elements, and its `COMPONENTS.md`/`PATTERNS.md` catalog of existing components to compose from (also browse `packages/design-system/components/`).
|
|
27
|
+
|
|
28
|
+
## Canonical example
|
|
29
|
+
|
|
30
|
+
`packages/design-system/components/Breadcrumbs/` is the example to imitate: a constrained
|
|
31
|
+
`BreadcrumbsItemProps[]` rendered by a private `Breadcrumb`; `onEdit?` gating inline editing with no
|
|
32
|
+
`editable` boolean; composition from `IconButton`, `Input`, `Link`, `HStack`, `Paragraph`,
|
|
33
|
+
`Tooltip`; semantic theme tokens; a `DEFAULT_EDIT_MAX_LENGTH` constant; and a barrel `index.ts`
|
|
34
|
+
plus `Breadcrumbs.mdx` with `<Controls />`.
|
|
35
|
+
|
|
36
|
+
## Step 1 — Clarify before building (do NOT assume)
|
|
37
|
+
|
|
38
|
+
Ask the designer whenever scope, states, sizes, max lengths, content shape, or state ownership are
|
|
39
|
+
unspecified — and never add props the designer didn't ask for. **REQUIRED:** read
|
|
40
|
+
`clarifying-scope.md` (in this skill directory) for the exact questions to ask.
|
|
41
|
+
|
|
42
|
+
## Step 2 — Design the prop interface
|
|
43
|
+
|
|
44
|
+
The props ARE the contract; make incorrect usage impossible to express. **REQUIRED:** read
|
|
45
|
+
`prop-interface-patterns.md` (in this skill directory) for the rules, the do/don't table, and the
|
|
46
|
+
rationalizations that lead to bad interfaces.
|
|
47
|
+
|
|
48
|
+
## Step 3 — Build it
|
|
49
|
+
|
|
50
|
+
Compose from existing DS components (never copy their CSS), style only with design tokens, follow
|
|
51
|
+
the standard file layout with a barrel `index.ts`, use real aria affordances, and ship a
|
|
52
|
+
`ComponentName.mdx`. Also add a row to
|
|
53
|
+
`packages/design-system/skills/ui-authoring/COMPONENTS.md` (Component / Use for / Import) so UI
|
|
54
|
+
authors pick the new component instead of reinventing it. **REQUIRED:** read
|
|
55
|
+
`component-conventions.md` (in this skill directory) for each of those in detail.
|
|
56
|
+
|
|
57
|
+
## Step 4 — Handoff
|
|
58
|
+
|
|
59
|
+
Add a component `.mdx` page in `persona-id/design-site`, following the structure of existing
|
|
60
|
+
component docs, and open a separate PR. If this session cannot access or write to that repository,
|
|
61
|
+
explicitly flag the documentation PR as a required follow-up rather than marking it complete.
|
|
62
|
+
|
|
63
|
+
If you open a PR, open it as a **draft** so an engineer can pick it up and review before it goes to
|
|
64
|
+
wider engineering review.
|
|
65
|
+
|
|
66
|
+
## Red flags — STOP and reconsider (or ask the designer)
|
|
67
|
+
|
|
68
|
+
- A boolean and a callback that mean the same thing (`editable` + `onEdit`).
|
|
69
|
+
- `loading` and `data` (or `error` and `value`) that can both be set at once.
|
|
70
|
+
- A `variant`/status string union with exactly two options.
|
|
71
|
+
- `title` / `label` / tooltip text typed as `ReactNode`.
|
|
72
|
+
- `children` accepted where the design wants a fixed set of items.
|
|
73
|
+
- `styled(SomeDSComponent)` with hardcoded color overrides or arbitrary restyling — layout-only tweaks (margin/width/alignment) are fine — or CSS copied from another component.
|
|
74
|
+
- A prop, variant, or feature the designer never asked for (`fullWidth`, extra sizes), or spreading arbitrary `...props` onto the root.
|
|
75
|
+
- A context provider whose only job is passing a `size`/`variant`.
|
|
76
|
+
- Hardcoded hex/px, or `Core*` foundational tokens where a semantic token exists.
|
|
77
|
+
- Missing `index.ts`, `.mdx`, aria attributes, or a `COMPONENTS.md` picker row.
|
|
78
|
+
- You assumed a constraint (some items editable, a specific max length) instead of asking.
|
|
79
|
+
- MDX docs with long, difficult-to-scan prose.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Clarifying scope with the designer
|
|
2
|
+
|
|
3
|
+
Stop and ask when any of the following is unspecified. **Never invent constraints or scope.** A
|
|
4
|
+
short question now prevents a rebuild later.
|
|
5
|
+
|
|
6
|
+
| Designer says / leaves unstated | Ask before coding |
|
|
7
|
+
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
8
|
+
| "the items can be editable" | Are **all** items editable, or only some? Default: assume all behave the same. Do **not** invent a per-item `editable` flag. |
|
|
9
|
+
| A text/rename input | What is the max length we'd reasonably allow? Pick a sensible default and confirm it. |
|
|
10
|
+
| A "status" / "loading" component | What are the exact, mutually-exclusive states? (drives the prop interface) |
|
|
11
|
+
| Sizes/variants mentioned loosely | Which sizes/variants actually exist? Don't add extras "for completeness". |
|
|
12
|
+
| "designers can put whatever they want inside" | Should the contents be a constrained set of typed items (`items: ItemProps[]` + private child) or a genuinely open `children` slot? Surface this tradeoff — don't silently default to `children`. |
|
|
13
|
+
| Nothing about ownership | Should the caller own the value (`value` + `onChange`) or should the component manage it internally? |
|
|
14
|
+
|
|
15
|
+
Do **not** add props, variants, or features the designer did not ask for (e.g. `fullWidth`, extra
|
|
16
|
+
variants, spreading arbitrary `...props` onto the root). A single optional `className` for external
|
|
17
|
+
layout composition is fine (see `BreadcrumbsProps`); inventing feature props is not. If you think
|
|
18
|
+
one is needed, propose it and ask — don't ship it silently.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Component conventions (compose, tokens, structure, a11y, docs)
|
|
2
|
+
|
|
3
|
+
## Compose, don't recreate
|
|
4
|
+
|
|
5
|
+
- Build from existing DS components — `Button`/`IconButton`, `Link`, `Input`, `Stack`/`HStack`,
|
|
6
|
+
`Text` (`Heading`/`Paragraph`/`Label`), `Tooltip`, `Spinner`, `Sticker`, etc. Check the
|
|
7
|
+
`ui-authoring` component catalog (`COMPONENTS.md`, `PATTERNS.md`) and
|
|
8
|
+
`packages/design-system/components/` before writing anything custom.
|
|
9
|
+
- **Use each component directly and keep its built-in styles.** Never copy/paste a DS component's
|
|
10
|
+
CSS into a `styled.div`. Wrapping a DS component with `styled(Component)` for _layout/positioning_
|
|
11
|
+
tweaks (margin, width, alignment) is fine, and adjusting a state with a _semantic token_ (e.g. `theme.color.text.tertiary`) is acceptable — but don't hardcode colors or arbitrarily change a component's visual identity. If the design truly needs a different look, that's a question for the designer/engineer, not a silent restyle.
|
|
12
|
+
- Replace raw flex wrappers with `Stack`/`HStack`. Do not re-implement `display: flex; gap` that
|
|
13
|
+
`HStack` already provides.
|
|
14
|
+
- Reach for a semantic HTML element (`nav`, `ul`/`li`, `button`) only when **no** DS component
|
|
15
|
+
covers the need.
|
|
16
|
+
|
|
17
|
+
## Style with tokens
|
|
18
|
+
|
|
19
|
+
- All CSS values come from design tokens (see `ui-authoring`). No hardcoded hex or px.
|
|
20
|
+
- **Prefer semantic tokens over foundational ones:** `theme.color.text.tertiary` /
|
|
21
|
+
`Color.TextPrimary` over `Color.CorePurple500`. Foundational `Core*` colors are a last resort and
|
|
22
|
+
need a comment.
|
|
23
|
+
- Consolidate nested styled elements — every wrapper must earn its place.
|
|
24
|
+
|
|
25
|
+
## File structure
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
packages/design-system/components/ComponentName/
|
|
29
|
+
├── ComponentName.tsx # public component (+ a private child .tsx if using an items array)
|
|
30
|
+
├── index.ts # barrel export
|
|
31
|
+
├── ComponentName.stories.tsx # stories per variant/state
|
|
32
|
+
├── ComponentName.spec.tsx # tests
|
|
33
|
+
└── ComponentName.mdx # docs
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- **Name files/exports for what they are.** Name a plural + singular pair `Breadcrumbs` +
|
|
37
|
+
`Breadcrumb` (each file exports the component of its own name), not `Breadcrumbs` +
|
|
38
|
+
`BreadcrumbSingle`. When the singular is a constrained-items child, keep it a _private_ child —
|
|
39
|
+
don't barrel-export it.
|
|
40
|
+
- `index.ts` re-exports the public component (default + named) and its public types only, not
|
|
41
|
+
private children. See `Breadcrumbs/index.ts`: it exports `Breadcrumbs` and the item/size types,
|
|
42
|
+
but not the private `Breadcrumb`.
|
|
43
|
+
- Extract self-contained logic (clipboard, inline-edit lifecycle, debouncing) into a `useX` hook so
|
|
44
|
+
the component file stays focused on presentation and structure.
|
|
45
|
+
- **Don't over-engineer.** Do not add a context provider just to thread a `size`/`variant` — pass it
|
|
46
|
+
as a prop. Context is for genuinely cross-cutting state shared across deeply nested descendants.
|
|
47
|
+
|
|
48
|
+
## Accessibility
|
|
49
|
+
|
|
50
|
+
Use proper roles/landmarks and aria affordances: `aria-label`, `aria-current`, `aria-busy`,
|
|
51
|
+
`aria-hidden` on decorative elements, and label association for inputs. Manage focus for interactive
|
|
52
|
+
widgets. Stories should set `parameters: { a11y: { test: 'error' } }`, and tests should target
|
|
53
|
+
accessible roles/labels (avoid `data-testid`).
|
|
54
|
+
|
|
55
|
+
## Document in Storybook
|
|
56
|
+
|
|
57
|
+
Add `ComponentName.mdx` alongside the stories:
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { Canvas, Controls, Meta } from '@storybook/addon-docs/blocks';
|
|
61
|
+
import * as stories from './ComponentName.stories';
|
|
62
|
+
|
|
63
|
+
<Meta of={stories} />
|
|
64
|
+
|
|
65
|
+
<Canvas of={stories.Playground} />
|
|
66
|
+
<Controls of={stories.Playground} />
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Keep MDX prose readable and follow the repository's Storybook conventions for titles and Chromatic
|
|
70
|
+
settings.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Prop interface patterns
|
|
2
|
+
|
|
3
|
+
The props ARE the contract. Make incorrect usage impossible to express.
|
|
4
|
+
|
|
5
|
+
| Rule | Instead of | Prefer |
|
|
6
|
+
| ------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
7
|
+
| Callback implies capability | `editable: boolean; onEdit: () => void` | `onEdit?: (v: string) => void` — editability = `onEdit != null` |
|
|
8
|
+
| Make impossible states unrepresentable | `loading?: boolean; data?: Data` (both can be set) | one discriminated field: `state: { kind: 'loading' } \| { kind: 'ready'; data: Data }`, or derive loading from `data == null` |
|
|
9
|
+
| Boolean over a 2-value union | `variant: 'default' \| 'compact'` | `compact?: boolean` — use a string union only for **3+** real, mutually-exclusive variants |
|
|
10
|
+
| Text is a string | `title: ReactNode` | `title: string` (+ optional `icon?: IconType` if it needs one). Two typed props beat an arbitrary node |
|
|
11
|
+
| Props are the interface | a parallel `interface FooState` layered on `interface FooProps` | let the props type be the interface. One item-shape type for an array (like `BreadcrumbsItemProps`) is fine; a redundant second interface is not |
|
|
12
|
+
| Constrain content when callers shouldn't style it | `children: ReactNode` | `items: ItemProps[]` rendered by a private child component. Use `children` only for genuinely open containers |
|
|
13
|
+
| Right owner for each piece of state | everything internal, or everything external | caller owns meaningful data (`value`/`onChange`); component keeps transient UI state (`isOpen`, `isEditing`) internal |
|
|
14
|
+
|
|
15
|
+
**Impossible-states rule of thumb:** if two optional props describe the same thing at different
|
|
16
|
+
times (loading vs loaded data, error vs value), collapse them so only one can exist at a time.
|
|
17
|
+
|
|
18
|
+
## Common rationalizations
|
|
19
|
+
|
|
20
|
+
| Rationalization | Reality |
|
|
21
|
+
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
22
|
+
| "I'll add `editable` for clarity even though `onEdit` exists" | Redundant state that can contradict itself. Presence of `onEdit` _is_ editability. |
|
|
23
|
+
| "Separate optional `loading` and `data` is flexible" | It lets callers represent impossible states. Model one-or-the-other. |
|
|
24
|
+
| "A `variant` union is more extensible than a boolean" | Two-value unions add ceremony now for a third case that may never come. Boolean until there are 3+ real variants. |
|
|
25
|
+
| "A `ReactNode` title is more flexible" | It invites arbitrary markup you can't style or constrain. `string` (+ optional `icon`) covers the real need. |
|
|
26
|
+
| "`children` lets designers compose freely" | For DS components that usually means inconsistent, unstyleable content. Prefer a typed `items[]` + private child unless it's truly an open container. |
|
|
27
|
+
| "I'll add `fullWidth`/`className` while I'm here" | Unrequested API surface. Ask first. |
|
|
28
|
+
| "Some list items are probably not editable" | Don't invent constraints. Assume uniform behavior or ask the designer. |
|
|
29
|
+
| "A context provider is cleaner for size" | Overkill for one value. Pass the prop. |
|
|
30
|
+
| "I'll copy the Button styles so it matches" | Duplicated styles drift. Use `Button` directly and keep its styles. |
|
|
File without changes
|