@discourser/design-system 0.25.3 → 0.27.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/README.md +76 -73
- package/dist/{chunk-ZPECW4N2.js → chunk-4XOWPACJ.js} +257 -105
- package/dist/chunk-4XOWPACJ.js.map +1 -0
- package/dist/{chunk-QNCZYFUJ.cjs → chunk-AZ6QU2L2.cjs} +257 -105
- package/dist/chunk-AZ6QU2L2.cjs.map +1 -0
- package/dist/{chunk-TBLDQATQ.cjs → chunk-EBDNCZF6.cjs} +94 -54
- package/dist/chunk-EBDNCZF6.cjs.map +1 -0
- package/dist/{chunk-UHSL4N44.js → chunk-MAVUSE4F.js} +94 -55
- package/dist/chunk-MAVUSE4F.js.map +1 -0
- package/dist/components/Checkbox.d.ts +1 -1
- package/dist/components/Icons/LeftArrowIcon.d.ts +6 -0
- package/dist/components/Icons/LeftArrowIcon.d.ts.map +1 -0
- package/dist/components/Icons/RightArrowIcon.d.ts.map +1 -1
- package/dist/components/Icons/index.d.ts +1 -0
- package/dist/components/Icons/index.d.ts.map +1 -1
- package/dist/components/index.cjs +79 -75
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/contracts/design-language.contract.d.ts +52 -18
- package/dist/contracts/design-language.contract.d.ts.map +1 -1
- package/dist/figma-codex.json +2 -2
- package/dist/index.cjs +83 -79
- package/dist/index.js +2 -2
- package/dist/languages/material3.language.d.ts.map +1 -1
- package/dist/languages/transform.d.ts +5 -5
- package/dist/languages/transform.d.ts.map +1 -1
- package/dist/preset/index.cjs +2 -2
- package/dist/preset/index.js +1 -1
- package/docs/component-catalog.md +469 -0
- package/docs/superpowers/plans/2026-04-03-component-catalog-pipeline.md +667 -0
- package/docs/token-name-mapping.json +614 -42
- package/docs/token-name-mapping.md +117 -29
- package/package.json +3 -2
- package/src/components/Icons/LeftArrowIcon.tsx +28 -0
- package/src/components/Icons/RightArrowIcon.tsx +7 -2
- package/src/components/Icons/index.ts +1 -0
- package/src/components/__tests__/AbsoluteCenter.test.tsx +31 -0
- package/src/components/__tests__/Divider.test.tsx +38 -0
- package/src/components/__tests__/Group.test.tsx +34 -0
- package/src/components/__tests__/Icon.test.tsx +31 -0
- package/src/components/__tests__/SettingsPopover.test.tsx +39 -0
- package/src/components/__tests__/StudioControls.test.tsx +59 -0
- package/src/components/__tests__/Toaster.test.tsx +24 -0
- package/src/components/index.ts +1 -0
- package/src/contracts/design-language.contract.ts +69 -20
- package/src/languages/material3.language.ts +249 -80
- package/src/languages/transform.ts +45 -48
- package/src/preset/__tests__/translation-token-accuracy.test.ts +13 -0
- package/src/stories/foundations/Colors.mdx +9 -1
- package/src/stories/foundations/Elevation.mdx +23 -17
- package/src/stories/foundations/TokenReference.stories.tsx +970 -0
- package/src/stories/foundations/TonalPaletteDerivation.stories.tsx +782 -0
- package/src/stories/foundations/Typography.mdx +125 -25
- package/dist/chunk-QNCZYFUJ.cjs.map +0 -1
- package/dist/chunk-TBLDQATQ.cjs.map +0 -1
- package/dist/chunk-UHSL4N44.js.map +0 -1
- package/dist/chunk-ZPECW4N2.js.map +0 -1
- package/docs/context-share/ELEVATION_FIX_PLAN.md +0 -903
- package/docs/context-share/fix-checkbox-radio-tokens.md +0 -145
- package/docs/context-share/icon-component-prompt.md +0 -154
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# Fix: Checkbox, Radio Button, and Input Error State Token Resolution
|
|
2
|
-
|
|
3
|
-
## Problem Summary
|
|
4
|
-
|
|
5
|
-
Multiple Park UI recipes reference semantic color tokens (`border`, `error`) as shorthand strings like `borderColor: 'border'` and `borderColor: 'error'`. In Park UI's upstream preset, these are **flat** semantic tokens with a direct `value` property. In the Discourser Design System, they were defined as **nested** tokens (with `default`/`muted` children but no root `value`), which causes Panda CSS to pass the literal string through to CSS instead of resolving it to a CSS variable.
|
|
6
|
-
|
|
7
|
-
**Affected CSS output (broken):**
|
|
8
|
-
```css
|
|
9
|
-
.checkbox__control { border-color: border; } /* literal string, not a color */
|
|
10
|
-
.input--variant_outline:is(:invalid) { border-color: error; } /* same problem */
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
**Expected CSS output (working):**
|
|
14
|
-
```css
|
|
15
|
-
.checkbox__control { border-color: var(--colors-border); }
|
|
16
|
-
.input--variant_outline:is(:invalid) { border-color: var(--colors-error); }
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Root Cause
|
|
20
|
-
|
|
21
|
-
In `panda.config.ts`, the semantic token aliases section defines:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
border: {
|
|
25
|
-
default: { value: { base: '{colors.gray.6}', _dark: '{colors.gray.6}' } },
|
|
26
|
-
muted: { value: { base: '{colors.gray.4}', _dark: '{colors.gray.4}' } },
|
|
27
|
-
},
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Park UI upstream (`park-ui/packages/preset/src/index.ts`) defines:
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
border: { value: { _light: '{colors.gray.4}', _dark: '{colors.gray.4}' } },
|
|
34
|
-
error: { value: { _light: '{colors.red.9}', _dark: '{colors.red.9}' } },
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
When Panda CSS encounters `borderColor: 'border'` in a recipe, it looks for a token with a `value` at the `colors.border` path. The Discourser config has no `value` at that level — only `colors.border.default` and `colors.border.muted` exist. Panda falls through and emits the literal string.
|
|
38
|
-
|
|
39
|
-
The `error` token is **completely missing** from the Discourser config.
|
|
40
|
-
|
|
41
|
-
## Fix Instructions
|
|
42
|
-
|
|
43
|
-
### File: `panda.config.ts`
|
|
44
|
-
|
|
45
|
-
Location: Inside `theme.extend.semanticTokens.colors`, the `border` definition (around line ~130).
|
|
46
|
-
|
|
47
|
-
**Change the `border` token from:**
|
|
48
|
-
```ts
|
|
49
|
-
border: {
|
|
50
|
-
default: {
|
|
51
|
-
value: { base: '{colors.gray.6}', _dark: '{colors.gray.6}' },
|
|
52
|
-
},
|
|
53
|
-
muted: {
|
|
54
|
-
value: { base: '{colors.gray.4}', _dark: '{colors.gray.4}' },
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**To:**
|
|
60
|
-
```ts
|
|
61
|
-
border: {
|
|
62
|
-
value: { base: '{colors.gray.6}', _dark: '{colors.gray.6}' },
|
|
63
|
-
default: {
|
|
64
|
-
value: { base: '{colors.gray.6}', _dark: '{colors.gray.6}' },
|
|
65
|
-
},
|
|
66
|
-
muted: {
|
|
67
|
-
value: { base: '{colors.gray.4}', _dark: '{colors.gray.4}' },
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
This adds a root-level `value` that generates `--colors-border` as a CSS variable, while preserving the nested `border.default` and `border.muted` sub-tokens. The root `value` matches `border.default` because that is the semantic equivalent — when recipes say `borderColor: 'border'` they mean the default border color.
|
|
73
|
-
|
|
74
|
-
**Then add the missing `error` token.** Place it right after the `border` block, before `...m3SemanticTokens`:
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
error: {
|
|
78
|
-
value: { base: '{colors.red.9}', _dark: '{colors.red.9}' },
|
|
79
|
-
},
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
This matches Park UI upstream exactly. The `error` token is referenced by Input, Textarea, Select, and other form component recipes for invalid/error states.
|
|
83
|
-
|
|
84
|
-
### No recipe file changes needed
|
|
85
|
-
|
|
86
|
-
Do NOT modify any recipe files (`checkbox.ts`, `radio-group.ts`, `input.ts`, etc.). They are character-identical to Park UI upstream and are correct. The fix is entirely in the token definitions.
|
|
87
|
-
|
|
88
|
-
### No story file changes needed for this fix
|
|
89
|
-
|
|
90
|
-
The checkbox stories may benefit from adding `colorPalette="primary"` to demonstrate the solid variant's checked state properly, but that is a story improvement, not a bug fix. The rendering fix is the token change above.
|
|
91
|
-
|
|
92
|
-
## Verification Steps
|
|
93
|
-
|
|
94
|
-
After making the change:
|
|
95
|
-
|
|
96
|
-
1. **Rebuild Panda CSS:**
|
|
97
|
-
```bash
|
|
98
|
-
pnpm panda codegen
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
2. **Check that `--colors-border` now exists in the generated CSS.** Look in `styled-system/styles.css` or rebuild Storybook and check the output CSS. You should see:
|
|
102
|
-
```css
|
|
103
|
-
--colors-border: var(--colors-gray-6);
|
|
104
|
-
--colors-border-default: var(--colors-gray-6);
|
|
105
|
-
--colors-border-muted: var(--colors-gray-4);
|
|
106
|
-
--colors-error: var(--colors-red-9);
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
3. **Check checkbox renders with visible border.** The `.checkbox__control` rule should now show:
|
|
110
|
-
```css
|
|
111
|
-
border-color: var(--colors-border);
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
4. **Check input error states work.** The `.input--variant_outline:is(:invalid)` rule should show:
|
|
115
|
-
```css
|
|
116
|
-
border-color: var(--colors-error);
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
5. **Run Storybook** and visually confirm:
|
|
120
|
-
- Checkbox: unchecked state shows a visible border (gray ring around the box)
|
|
121
|
-
- Checkbox solid variant: checked state fills with `colorPalette` color
|
|
122
|
-
- Radio: unchecked state shows a visible circle border (this already works via the `boxShadow` pattern using `gray.surface.border`, but verify no regression)
|
|
123
|
-
- Input: invalid states show red border
|
|
124
|
-
|
|
125
|
-
## Scope of Impact
|
|
126
|
-
|
|
127
|
-
This fix affects every component recipe that references the bare `'border'` or `'error'` token strings. Based on CSS analysis, these components currently have broken token resolution:
|
|
128
|
-
|
|
129
|
-
**`border` literal (fixed by adding root `value`):**
|
|
130
|
-
- Checkbox (base `control` + solid variant `control`)
|
|
131
|
-
- Stepper (`indicator` border-color)
|
|
132
|
-
- Slider (`track` background — uses `background: border`)
|
|
133
|
-
- Tabs enclosed variant (`--shadow-color: border`)
|
|
134
|
-
|
|
135
|
-
**`error` literal (fixed by adding `error` token):**
|
|
136
|
-
- Input (outline, surface, subtle, flushed variants — invalid state `border-color`)
|
|
137
|
-
- Textarea (outline, surface, subtle, flushed variants — invalid state)
|
|
138
|
-
- Input flushed variant (`--shadow-color: error` on focus+invalid)
|
|
139
|
-
- Textarea flushed variant (`--shadow-color: error` on focus+invalid)
|
|
140
|
-
|
|
141
|
-
## Why Radio Buttons Already Work
|
|
142
|
-
|
|
143
|
-
The radio button recipe uses a different pattern: `boxShadow: 'inset 0 0 0 1px {colors.gray.surface.border}'` with `--shadow-color` set to the fully-qualified token path `gray.surface.border`. This resolves correctly because `gray.surface.border` has a direct `value` in the color palette definitions. No fix needed for radio unchecked state visibility.
|
|
144
|
-
|
|
145
|
-
If radio buttons appear invisible in Storybook, the issue is likely CSS specificity or a missing `colorPalette` prop on the story — not a token resolution problem. The CSS output for radio is correct: `--shadow-color: var(--colors-gray-surface-border)` which resolves to `var(--colors-neutral-6)` → `#91918B`.
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# Icon Component Creation Prompt
|
|
2
|
-
# Target: Claude Code in Discourser-Design-System repo
|
|
3
|
-
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## Task
|
|
7
|
-
|
|
8
|
-
Create 17 new icon components in the DDS, add them all to the Icons story gallery, add each one to the index, and create a Figma Code Connect file for each.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Reference Pattern
|
|
13
|
-
|
|
14
|
-
Before writing any code, read these files to understand the exact pattern to follow:
|
|
15
|
-
|
|
16
|
-
- `src/components/Icons/AccountIcon.tsx` — icon component pattern
|
|
17
|
-
- `src/components/Icons/DiscourserLogo.figma.tsx` — Code Connect file pattern
|
|
18
|
-
- `stories/Icons.stories.tsx` — existing story to extend (Gallery story)
|
|
19
|
-
- `src/components/Icons/index.ts` — barrel export to extend
|
|
20
|
-
|
|
21
|
-
**Component pattern summary:**
|
|
22
|
-
```typescript
|
|
23
|
-
import { ark } from '@ark-ui/react/factory';
|
|
24
|
-
import type { ComponentProps } from 'react';
|
|
25
|
-
import { styled } from 'styled-system/jsx';
|
|
26
|
-
|
|
27
|
-
const StyledSvg = styled(ark.svg);
|
|
28
|
-
|
|
29
|
-
export type {ComponentName}Props = ComponentProps<typeof StyledSvg>;
|
|
30
|
-
|
|
31
|
-
export const {ComponentName} = (props: {ComponentName}Props) => (
|
|
32
|
-
<StyledSvg
|
|
33
|
-
viewBox="{viewBox from SVG}"
|
|
34
|
-
fill="none"
|
|
35
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
36
|
-
width="1em"
|
|
37
|
-
height="1em"
|
|
38
|
-
{...props}
|
|
39
|
-
>
|
|
40
|
-
{/* paths here */}
|
|
41
|
-
</StyledSvg>
|
|
42
|
-
);
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**⚠️ CRITICAL — currentColor rule:**
|
|
46
|
-
Every SVG has hardcoded color values (`#6B7A1F`, `#518500`, `#FFFDFA`, `#F2F2F2`, `#D9E57A`, etc.). These MUST ALL be replaced with `currentColor` so icons inherit color from their parent via the token system. No hardcoded color values anywhere in any component.
|
|
47
|
-
|
|
48
|
-
- `stroke="#6B7A1F"` → `stroke="currentColor"`
|
|
49
|
-
- `fill="#6B7A1F"` → `fill="currentColor"`
|
|
50
|
-
- `stroke="#FFFDFA"` → `stroke="currentColor"`
|
|
51
|
-
- `fill="#FFFDFA"` → `fill="currentColor"`
|
|
52
|
-
- Any other hardcoded hex → `currentColor`
|
|
53
|
-
|
|
54
|
-
For icons that use BOTH `fill` and `stroke` on the same path (mixed rendering), use `fill="currentColor"` where fill is the primary visual and `stroke="none"`, or `stroke="currentColor"` and `fill="none"` — match the visual intent of the original. When in doubt, prefer `stroke="currentColor"` with `fill="none"` as that matches the majority of existing icons.
|
|
55
|
-
|
|
56
|
-
**Code Connect pattern:**
|
|
57
|
-
```typescript
|
|
58
|
-
import figma from '@figma/code-connect';
|
|
59
|
-
import { {ComponentName} } from './{ComponentName}';
|
|
60
|
-
|
|
61
|
-
figma.connect(
|
|
62
|
-
{ComponentName},
|
|
63
|
-
'https://www.figma.com/design/GaHmFfmvO4loUzuZS4TgEz/Discourser.AI--V1?node-id={NODE_ID}',
|
|
64
|
-
{
|
|
65
|
-
example: () => <{ComponentName} />,
|
|
66
|
-
},
|
|
67
|
-
);
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## Icons to Create
|
|
73
|
-
|
|
74
|
-
All SVG source files are in `docs/context-share/icons/`. Create each component in `src/components/Icons/`.
|
|
75
|
-
|
|
76
|
-
| SVG File | Component Name | viewBox | Node ID |
|
|
77
|
-
|----------|---------------|---------|---------|
|
|
78
|
-
| `Timer.svg` | `TimerIcon` | `0 0 35 39` | `38-9817` |
|
|
79
|
-
| `ClipBoard.svg` | `ClipBoardIcon` | `0 0 40 39` | `38-9804` |
|
|
80
|
-
| `Microphone.svg` | `MicrophoneIcon` | `0 0 40 45` | `38-9821` |
|
|
81
|
-
| `Audience.svg` | `AudienceIcon` | `0 0 40 44` | `38-9825` |
|
|
82
|
-
| `Record.svg` | `RecordIcon` | `0 0 36 39` | `38-9843` |
|
|
83
|
-
| `NotebookPen.svg` | `NotebookPenIcon` | `0 0 42 42` | `38-9871` |
|
|
84
|
-
| `Sparkles.svg` | `SparklesIcon` | `0 0 24 27` | `38-9872` |
|
|
85
|
-
| `ScrollText.svg` | `ScrollTextIcon` | `0 0 42 42` | `38-9873` |
|
|
86
|
-
| `RepeatQuestion.svg` | `RepeatQuestionIcon` | `0 0 64 63` | `38-9863` |
|
|
87
|
-
| `ExitStudio.svg` | `ExitStudioIcon` | `0 0 64 64` | `38-9853` |
|
|
88
|
-
| `PausePlay.svg` | `PausePlayIcon` | `0 0 64 64` | `38-9849` |
|
|
89
|
-
| `StopPlay.svg` | `StopPlayIcon` | `0 0 64 64` | `38-9857` |
|
|
90
|
-
| `BookmarkPlus.svg` | `BookmarkPlusIcon` | `0 0 42 42` | `38-9870` |
|
|
91
|
-
| `AudioSpeaker.svg` | `AudioSpeakerIcon` | `0 0 40 28` | `38-9812` |
|
|
92
|
-
| `UserProfile.svg` | `UserProfileIcon` | `0 0 42 42` | `38-9874` |
|
|
93
|
-
| `Play.svg` | `PlayIcon` | `0 0 63 63` | `38-9861` |
|
|
94
|
-
| `Speech.svg` | `SpeechIcon` | `0 0 60 60` | `618-5193` |
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Files to CREATE (per icon — 17 × 2 = 34 files)
|
|
99
|
-
|
|
100
|
-
For each icon in the table above:
|
|
101
|
-
|
|
102
|
-
1. `src/components/Icons/{ComponentName}.tsx` — the component
|
|
103
|
-
2. `src/components/Icons/{ComponentName}.figma.tsx` — the Code Connect file
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## Files to UPDATE (2 files)
|
|
108
|
-
|
|
109
|
-
### 1. `src/components/Icons/index.ts`
|
|
110
|
-
Add an export for every new component:
|
|
111
|
-
```typescript
|
|
112
|
-
export { TimerIcon, type TimerIconProps } from './TimerIcon';
|
|
113
|
-
export { ClipBoardIcon, type ClipBoardIconProps } from './ClipBoardIcon';
|
|
114
|
-
// ... all 17
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### 2. `stories/Icons.stories.tsx`
|
|
118
|
-
- Add an import for every new component at the top
|
|
119
|
-
- Add every new icon to the existing `Gallery` story's `HStack` — same pattern as existing icons:
|
|
120
|
-
```tsx
|
|
121
|
-
<VStack gap="2" alignItems="center">
|
|
122
|
-
<TimerIcon w="6" h="6" color="fg.default" />
|
|
123
|
-
<span className={label}>TimerIcon</span>
|
|
124
|
-
</VStack>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## Special Notes Per Icon
|
|
130
|
-
|
|
131
|
-
**StopPlay** — has a `<rect>` element with `fill="#FFFDFA"`. Replace with `fill="currentColor"`. Keep the `rx="8"` attribute.
|
|
132
|
-
|
|
133
|
-
**ExitStudio** — has a `<circle>` element with `stroke="#FFFDFA"`. Replace with `stroke="currentColor"` and `fill="none"`.
|
|
134
|
-
|
|
135
|
-
**PausePlay** — has a `<circle>` with `stroke="#FFFDFA"`. Replace with `stroke="currentColor"` and `fill="none"`.
|
|
136
|
-
|
|
137
|
-
**Play** — has a `<circle>` outline and triangle path, both `stroke="white"`. Replace both with `stroke="currentColor"` and `fill="none"`.
|
|
138
|
-
|
|
139
|
-
**Audience** — uses `fill="#6B7A1F"` (not stroke) on all paths. Replace with `fill="currentColor"`. Remove any `stroke` attributes if present. Set top-level `fill` prop to `"currentColor"` instead of `"none"` for this component only.
|
|
140
|
-
|
|
141
|
-
**ClipBoard** — has two different hardcoded stroke colors (`#6B7A1F` and `#54643F`) on different paths. Replace both with `currentColor` — they should unify to a single color when tokenized.
|
|
142
|
-
|
|
143
|
-
**RepeatQuestion** — uses `stroke="#F2F2F2"`. Replace with `currentColor`.
|
|
144
|
-
|
|
145
|
-
**Speech** — uses `stroke="#D9E57A"`. Replace with `currentColor`.
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Quality Gate
|
|
150
|
-
|
|
151
|
-
After creating all files, verify:
|
|
152
|
-
- `pnpm type-check` — 0 errors
|
|
153
|
-
- `pnpm build` — builds cleanly
|
|
154
|
-
- No hardcoded hex color values remain in any new component file (grep check: `grep -r "#[0-9A-Fa-f]" src/components/Icons/` should return no new files)
|