@kalink-ui/seedly 0.34.4 → 0.35.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 +12 -0
- package/README.md +34 -0
- package/docs/component-theming.md +295 -0
- package/docs/theming-strategy.md +69 -0
- package/docs/tone-system.md +139 -0
- package/docs/value-and-scope.md +65 -0
- package/package.json +4 -3
- package/src/components/alert-dialog/alert-dialog-action.tsx +0 -2
- package/src/components/alert-dialog/alert-dialog-cancel.tsx +0 -1
- package/src/components/alert-dialog/alert-dialog-content.css.ts +1 -1
- package/src/components/alert-dialog/alert-dialog-content.tsx +13 -6
- package/src/components/alert-dialog/alert-dialog-footer.css.ts +3 -3
- package/src/components/alert-dialog/alert-dialog-footer.tsx +2 -2
- package/src/components/alert-dialog/alert-dialog-header.tsx +4 -4
- package/src/components/alert-dialog/index.ts +9 -0
- package/src/components/box/box.css.ts +137 -39
- package/src/components/box/box.responsive.ts +2 -2
- package/src/components/box/box.tsx +2 -3
- package/src/components/box/index.ts +1 -1
- package/src/components/button/button.css.ts +142 -149
- package/src/components/button/button.responsive.ts +2 -2
- package/src/components/button/button.tsx +44 -31
- package/src/components/button/index.ts +2 -2
- package/src/components/button-icon/button-icon.css.ts +26 -62
- package/src/components/button-icon/button-icon.responsive.ts +2 -2
- package/src/components/button-icon/button-icon.tsx +5 -7
- package/src/components/card/card.css.ts +1 -5
- package/src/components/card/card.tsx +11 -11
- package/src/components/center/center.css.ts +61 -21
- package/src/components/center/center.responsive.ts +2 -2
- package/src/components/center/center.tsx +4 -6
- package/src/components/center/index.ts +1 -1
- package/src/components/cluster/cluster.css.ts +37 -99
- package/src/components/cluster/cluster.responsive.ts +13 -2
- package/src/components/cluster/cluster.tsx +6 -5
- package/src/components/cluster/index.ts +5 -1
- package/src/components/command/command-empty.tsx +36 -4
- package/src/components/command/command-group.css.ts +23 -7
- package/src/components/command/command-group.tsx +30 -6
- package/src/components/command/command-input.css.ts +2 -2
- package/src/components/command/command-item.tsx +26 -2
- package/src/components/command/command-list.css.ts +2 -2
- package/src/components/command/command-list.responsive.ts +2 -2
- package/src/components/command/command-list.tsx +1 -2
- package/src/components/command/command-separator.tsx +7 -5
- package/src/components/cover/cover.css.ts +29 -8
- package/src/components/cover/cover.tsx +13 -13
- package/src/components/cover/index.ts +2 -2
- package/src/components/divider/divider.css.ts +9 -4
- package/src/components/form-field/form-field-context.ts +3 -0
- package/src/components/form-field/form-field-item.tsx +3 -3
- package/src/components/form-field/form-field-message.tsx +34 -3
- package/src/components/form-field/form-field.css.ts +78 -16
- package/src/components/form-field/form-field.tsx +5 -0
- package/src/components/form-field/index.ts +1 -1
- package/src/components/frame/frame.css.ts +96 -59
- package/src/components/frame/frame.responsive.ts +9 -0
- package/src/components/frame/frame.tsx +11 -5
- package/src/components/frame/index.ts +1 -1
- package/src/components/grid/grid-child.tsx +14 -10
- package/src/components/grid/grid.css.ts +56 -148
- package/src/components/grid/grid.tsx +40 -18
- package/src/components/grid/index.ts +4 -3
- package/src/components/heading/heading.css.ts +4 -4
- package/src/components/heading/heading.responsive.ts +6 -6
- package/src/components/heading/heading.tsx +3 -4
- package/src/components/heading/index.ts +1 -1
- package/src/components/input/index.ts +4 -1
- package/src/components/input/input-wrapper.tsx +20 -8
- package/src/components/input/input.css.ts +121 -93
- package/src/components/input/input.responsive.ts +9 -0
- package/src/components/input/input.tsx +7 -1
- package/src/components/label/label.css.ts +2 -2
- package/src/components/label/label.tsx +23 -3
- package/src/components/layout-maps.ts +120 -0
- package/src/components/loader/index.ts +2 -1
- package/src/components/loader/loader.css.ts +91 -54
- package/src/components/loader/moon-loader.responsive.ts +2 -2
- package/src/components/loader/moon-loader.tsx +4 -5
- package/src/components/loader-overlay/loader-overlay.css.ts +3 -3
- package/src/components/loader-overlay/loader-overlay.tsx +5 -2
- package/src/components/menu/index.ts +2 -2
- package/src/components/menu/menu-item.css.ts +102 -46
- package/src/components/menu/menu-separator.css.ts +27 -15
- package/src/components/menu/menu-separator.responsive.ts +2 -2
- package/src/components/overlay/overlay.css.ts +1 -1
- package/src/components/popover/index.ts +1 -1
- package/src/components/popover/popover-content.css.ts +69 -52
- package/src/components/popover/popover-content.tsx +22 -6
- package/src/components/scroll-area/scroll-area.css.ts +3 -3
- package/src/components/scroll-area/scroll-bar.tsx +2 -2
- package/src/components/select/index.ts +4 -5
- package/src/components/select/select-content.css.ts +1 -1
- package/src/components/select/select-content.tsx +2 -2
- package/src/components/select/select-item.tsx +11 -3
- package/src/components/select/select-trigger.css.ts +14 -18
- package/src/components/select/select-trigger.tsx +18 -8
- package/src/components/select/select.tsx +10 -6
- package/src/components/sheet/index.ts +9 -0
- package/src/components/sheet/sheet-content.css.ts +2 -2
- package/src/components/sheet/sheet-content.tsx +25 -7
- package/src/components/sheet/sheet-description.tsx +5 -7
- package/src/components/sheet/sheet-footer.tsx +3 -1
- package/src/components/sheet/sheet-header.css.ts +1 -1
- package/src/components/sheet/sheet-header.tsx +3 -3
- package/src/components/sheet/sheet-overlay.tsx +3 -4
- package/src/components/sheet/sheet-title.tsx +1 -1
- package/src/components/sidebar/index.ts +5 -1
- package/src/components/sidebar/sidebar.css.ts +35 -9
- package/src/components/sidebar/sidebar.tsx +7 -10
- package/src/components/skeleton/skeleton.css.ts +23 -14
- package/src/components/skeleton/skeleton.tsx +26 -7
- package/src/components/stack/index.ts +1 -1
- package/src/components/stack/stack.css.ts +18 -46
- package/src/components/stack/stack.tsx +1 -2
- package/src/components/switcher/index.ts +5 -1
- package/src/components/switcher/switcher.css.ts +105 -72
- package/src/components/switcher/switcher.responsive.ts +2 -2
- package/src/components/switcher/switcher.tsx +5 -5
- package/src/components/text/text.css.ts +93 -105
- package/src/components/text/text.responsive.ts +3 -63
- package/src/components/text/text.tsx +16 -28
- package/src/components/text-field/index.ts +1 -2
- package/src/components/text-field/text-field.tsx +5 -7
- package/src/components/textarea/textarea-input.tsx +30 -3
- package/src/components/textarea/textarea.css.ts +12 -7
- package/src/components/textarea/textarea.tsx +9 -3
- package/src/components/visually-hidden/visually-hidden.css.ts +16 -10
- package/src/styles/define-responsive-properties.ts +5 -1
- package/src/styles/index.ts +12 -0
- package/src/styles/responsive.ts +72 -43
- package/src/styles/system-contract.css.ts +22 -3
- package/src/styles/theme/sprout-ref.css.ts +107 -0
- package/src/styles/theme/sprout.css.ts +259 -0
- package/src/styles/tone.ts +69 -0
- package/src/styles/typography.responsive.css.ts +35 -0
- package/src/styles/typography.responsive.ts +104 -0
- package/src/utils/arg-types/index.ts +1 -0
- package/src/utils/arg-types/responsive-arg.ts +28 -0
- package/src/utils/index.ts +1 -0
- package/src/components/command/command-item.css.ts +0 -32
- package/src/components/select/select.css.ts +0 -3
- package/src/components/sheet/sheet-body.css.ts +0 -68
- package/src/components/text-field/text-field.css.ts +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @kalink-ui/seedly
|
|
2
2
|
|
|
3
|
+
## 0.35.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e06ff34: Add responsive typography generation and wire it into text-bearing components.
|
|
8
|
+
- 63a0911: Align theming and responsive APIs across components with shared tone helpers.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- 89cc8dc: Add a responsive argType helper and refine typography story controls.
|
|
13
|
+
- eae06e2: Align surface and tone token usage with the updated theme contract.
|
|
14
|
+
|
|
3
15
|
## 0.34.4
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# `seedly`
|
|
2
|
+
|
|
3
|
+
Seedly is a React UI component library powered by vanilla-extract and the Kalink UI design system.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @kalink-ui/seedly
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Next.js setup
|
|
12
|
+
|
|
13
|
+
Seedly ships TypeScript and vanilla-extract sources, so Next.js must transpile the package.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// next.config.ts
|
|
17
|
+
import { createVanillaExtractPlugin } from '@vanilla-extract/next-plugin';
|
|
18
|
+
|
|
19
|
+
const withVanillaExtract = createVanillaExtractPlugin();
|
|
20
|
+
|
|
21
|
+
const nextConfig = {
|
|
22
|
+
transpilePackages: ['@kalink-ui/seedly'],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default withVanillaExtract(nextConfig);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Import Seedly layers and your system theme once in `app/layout.tsx`:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import '@kalink-ui/seedly/styles/reset';
|
|
32
|
+
import '@kalink-ui/seedly/styles/layers';
|
|
33
|
+
import '../style/system-theme.css';
|
|
34
|
+
```
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# Component theming contract (internal)
|
|
2
|
+
|
|
3
|
+
This document defines the **target standard** for Seedly component theming. It is
|
|
4
|
+
intended for internal implementation guidance and will later be adapted for
|
|
5
|
+
external documentation.
|
|
6
|
+
|
|
7
|
+
## Principles
|
|
8
|
+
|
|
9
|
+
- **Vanilla Extract is mandatory**. Components must expose theming hooks as VE
|
|
10
|
+
contracts, not runtime styles or plain CSS.
|
|
11
|
+
- **Semantic naming over CSS naming**. Use neutral, role-based semantics so the
|
|
12
|
+
API describes intent instead of implementation details.
|
|
13
|
+
- **Structure and appearance are both tokenized**. Spacing, typography, shape,
|
|
14
|
+
elevation, motion, and color/border/shadow must map to `sys` tokens and
|
|
15
|
+
component vars.
|
|
16
|
+
- **Vars are the primary override surface**. Variants should only mutate vars,
|
|
17
|
+
not hard-code raw values.
|
|
18
|
+
- **Slots are opt-in escape hatches**. Export slot classes when components have
|
|
19
|
+
internal structure.
|
|
20
|
+
- **System tokens are the base**. Default component vars must map to `sys` tokens
|
|
21
|
+
(or other component vars) before any literals.
|
|
22
|
+
|
|
23
|
+
## Contract naming rules
|
|
24
|
+
|
|
25
|
+
### Structure vs appearance
|
|
26
|
+
|
|
27
|
+
Structure (spacing, typography, shape, elevation, motion, layout) and appearance
|
|
28
|
+
(color, borders, shadows, emphasis) are **organizational categories only**. Both
|
|
29
|
+
must be expressed through system tokens and component vars so they are fully
|
|
30
|
+
overridable.
|
|
31
|
+
|
|
32
|
+
### System tokens
|
|
33
|
+
|
|
34
|
+
System tokens live in `sys` and are **semantic**: `sys.surface.background`,
|
|
35
|
+
`sys.state.hovered.opacity`, `sys.shape.corner.rounded`.
|
|
36
|
+
|
|
37
|
+
### Component contracts
|
|
38
|
+
|
|
39
|
+
Component contracts (`ComponentVars`) must stay semantic and scoped to the
|
|
40
|
+
component. Favor neutral, role-based terminology:
|
|
41
|
+
|
|
42
|
+
- `color.container` (surface background)
|
|
43
|
+
- `color.content` (text/icon color)
|
|
44
|
+
- `color.outline` (borders, focus ring)
|
|
45
|
+
- `shape.corner` (border radius)
|
|
46
|
+
- `elevation.level` (shadow)
|
|
47
|
+
- `spacing.inline` / `spacing.block` (layout spacing)
|
|
48
|
+
- `typography.kind` (font or style anchor if needed)
|
|
49
|
+
|
|
50
|
+
CSS-names are only allowed for leaf-level spacing/size values where the intent is
|
|
51
|
+
unambiguous.
|
|
52
|
+
|
|
53
|
+
## Variants
|
|
54
|
+
|
|
55
|
+
Variants are semantic and should only **assign vars**.
|
|
56
|
+
|
|
57
|
+
### Variant naming
|
|
58
|
+
|
|
59
|
+
- Preferred: `filled`, `outlined`, `text`, `elevated`, `tonal`.
|
|
60
|
+
- Allowed alternates: `ghost`, `plain`, `link` if a component requires them.
|
|
61
|
+
- Avoid: `primary`, `secondary` (these are **tones**, not visual treatments).
|
|
62
|
+
|
|
63
|
+
### Variant rules
|
|
64
|
+
|
|
65
|
+
- Variants set component vars via `assignVars` for both structure and appearance.
|
|
66
|
+
- Variants should not set hard-coded CSS values except for layout primitives
|
|
67
|
+
(e.g., `display`, `gap`), and only when those are not intended for theming.
|
|
68
|
+
|
|
69
|
+
## Size and density
|
|
70
|
+
|
|
71
|
+
Size and density are separate axes:
|
|
72
|
+
|
|
73
|
+
- **Size** controls typography scale and overall component scale.
|
|
74
|
+
- **Density** controls padding and spacing.
|
|
75
|
+
|
|
76
|
+
### Naming
|
|
77
|
+
|
|
78
|
+
- **Size**: `sm`, `md`, `lg` (universal).
|
|
79
|
+
- **Density**: `compact`, `comfortable`, `spacious` (use only when necessary).
|
|
80
|
+
|
|
81
|
+
### Rules
|
|
82
|
+
|
|
83
|
+
- Size variants should assign typography and scale-related vars.
|
|
84
|
+
- Density variants should only assign spacing vars.
|
|
85
|
+
- Components can implement size only if density is not relevant.
|
|
86
|
+
|
|
87
|
+
## Export surface
|
|
88
|
+
|
|
89
|
+
Every component must export the following, when applicable:
|
|
90
|
+
|
|
91
|
+
- `ComponentVars` contract (e.g. `buttonVars`).
|
|
92
|
+
- `componentRecipe` and `ComponentVariants` type.
|
|
93
|
+
- Slot classes (e.g. `buttonLabel`, `buttonSlot`) for structured components.
|
|
94
|
+
- Optional variant maps (`componentVariantStyles`, `componentSizeStyles`) when
|
|
95
|
+
responsive recipes or overrides are needed.
|
|
96
|
+
|
|
97
|
+
## Canonical component template
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { assignVars, createThemeContract } from '@vanilla-extract/css';
|
|
101
|
+
import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
|
|
102
|
+
|
|
103
|
+
import { sys } from '../../styles';
|
|
104
|
+
import { components } from '../../styles/layers.css';
|
|
105
|
+
|
|
106
|
+
export const componentVars = createThemeContract({
|
|
107
|
+
color: {
|
|
108
|
+
container: null,
|
|
109
|
+
content: null,
|
|
110
|
+
outline: null,
|
|
111
|
+
},
|
|
112
|
+
spacing: {
|
|
113
|
+
block: null,
|
|
114
|
+
inline: null,
|
|
115
|
+
},
|
|
116
|
+
shape: {
|
|
117
|
+
corner: null,
|
|
118
|
+
},
|
|
119
|
+
typography: {
|
|
120
|
+
size: null,
|
|
121
|
+
weight: null,
|
|
122
|
+
lineHeight: null,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export const componentVariantStyles = {
|
|
127
|
+
filled: {
|
|
128
|
+
'@layer': {
|
|
129
|
+
[components]: {
|
|
130
|
+
vars: {
|
|
131
|
+
...assignVars(componentVars.color, {
|
|
132
|
+
container: sys.surface.foreground,
|
|
133
|
+
content: sys.surface.background,
|
|
134
|
+
outline: 'transparent',
|
|
135
|
+
}),
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
outlined: {
|
|
141
|
+
'@layer': {
|
|
142
|
+
[components]: {
|
|
143
|
+
vars: {
|
|
144
|
+
...assignVars(componentVars.color, {
|
|
145
|
+
container: 'transparent',
|
|
146
|
+
content: sys.surface.foreground,
|
|
147
|
+
outline: sys.surface.foreground,
|
|
148
|
+
}),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
} as const;
|
|
154
|
+
|
|
155
|
+
export const componentSizeStyles = {
|
|
156
|
+
sm: {
|
|
157
|
+
'@layer': {
|
|
158
|
+
[components]: {
|
|
159
|
+
vars: assignVars(componentVars.spacing, {
|
|
160
|
+
block: sys.spacing[1],
|
|
161
|
+
inline: sys.spacing[2],
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
md: {
|
|
167
|
+
'@layer': {
|
|
168
|
+
[components]: {
|
|
169
|
+
vars: assignVars(componentVars.spacing, {
|
|
170
|
+
block: sys.spacing[2],
|
|
171
|
+
inline: sys.spacing[4],
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
lg: {
|
|
177
|
+
'@layer': {
|
|
178
|
+
[components]: {
|
|
179
|
+
vars: assignVars(componentVars.spacing, {
|
|
180
|
+
block: sys.spacing[3],
|
|
181
|
+
inline: sys.spacing[6],
|
|
182
|
+
}),
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
} as const;
|
|
187
|
+
|
|
188
|
+
export const componentRecipe = recipe({
|
|
189
|
+
base: {
|
|
190
|
+
'@layer': {
|
|
191
|
+
[components]: {
|
|
192
|
+
color: componentVars.color.content,
|
|
193
|
+
backgroundColor: componentVars.color.container,
|
|
194
|
+
borderColor: componentVars.color.outline,
|
|
195
|
+
borderRadius: componentVars.shape.corner,
|
|
196
|
+
paddingBlock: componentVars.spacing.block,
|
|
197
|
+
paddingInline: componentVars.spacing.inline,
|
|
198
|
+
fontSize: componentVars.typography.size,
|
|
199
|
+
fontWeight: componentVars.typography.weight,
|
|
200
|
+
lineHeight: componentVars.typography.lineHeight,
|
|
201
|
+
|
|
202
|
+
vars: {
|
|
203
|
+
...assignVars(componentVars.color, {
|
|
204
|
+
container: sys.surface.background,
|
|
205
|
+
content: sys.surface.foreground,
|
|
206
|
+
outline: 'transparent',
|
|
207
|
+
}),
|
|
208
|
+
...assignVars(componentVars.spacing, {
|
|
209
|
+
block: sys.spacing[2],
|
|
210
|
+
inline: sys.spacing[4],
|
|
211
|
+
}),
|
|
212
|
+
...assignVars(componentVars.shape, {
|
|
213
|
+
corner: sys.shape.corner.none,
|
|
214
|
+
}),
|
|
215
|
+
...assignVars(componentVars.typography, {
|
|
216
|
+
size: sys.typography.body.medium.size,
|
|
217
|
+
weight: sys.typography.body.medium.weight,
|
|
218
|
+
lineHeight: sys.typography.body.medium.lineHeight,
|
|
219
|
+
}),
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
variants: {
|
|
225
|
+
variant: componentVariantStyles,
|
|
226
|
+
size: componentSizeStyles,
|
|
227
|
+
},
|
|
228
|
+
defaultVariants: {
|
|
229
|
+
variant: 'filled',
|
|
230
|
+
size: 'md',
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
export type ComponentVariants = NonNullable<
|
|
235
|
+
RecipeVariants<typeof componentRecipe>
|
|
236
|
+
>;
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Component example: Button
|
|
240
|
+
|
|
241
|
+
### Contract
|
|
242
|
+
|
|
243
|
+
Use semantic keys and map to system tokens by default:
|
|
244
|
+
|
|
245
|
+
- `buttonVars.color.container` → `sys.surface.foreground`
|
|
246
|
+
- `buttonVars.color.content` → `sys.surface.background`
|
|
247
|
+
- `buttonVars.color.outline` → `sys.surface.foreground`
|
|
248
|
+
- `buttonVars.spacing.block` / `inline` → `sys.spacing`
|
|
249
|
+
- `buttonVars.shape.corner` → `sys.shape.corner`
|
|
250
|
+
- `buttonVars.elevation.level` → `sys.elevation`
|
|
251
|
+
|
|
252
|
+
### Variant strategy
|
|
253
|
+
|
|
254
|
+
- `filled`: container + content set via vars.
|
|
255
|
+
- `outlined`: outline set, container transparent.
|
|
256
|
+
- `text`: container transparent, no outline, hover uses state tokens.
|
|
257
|
+
|
|
258
|
+
### Size strategy
|
|
259
|
+
|
|
260
|
+
- `sm/md/lg` adjust typography + spacing vars.
|
|
261
|
+
- If density is introduced, keep size tied to typography and use density to
|
|
262
|
+
adjust spacing only.
|
|
263
|
+
|
|
264
|
+
## Consumer override example
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import { assignVars } from '@vanilla-extract/css';
|
|
268
|
+
import { buttonVars } from '@kalink-ui/seedly/button';
|
|
269
|
+
|
|
270
|
+
export const marketingButton = style({
|
|
271
|
+
vars: assignVars(buttonVars, {
|
|
272
|
+
color: {
|
|
273
|
+
container: '#111',
|
|
274
|
+
content: '#fff',
|
|
275
|
+
outline: '#111',
|
|
276
|
+
},
|
|
277
|
+
spacing: {
|
|
278
|
+
block: '10px',
|
|
279
|
+
inline: '20px',
|
|
280
|
+
},
|
|
281
|
+
shape: {
|
|
282
|
+
corner: '9999px',
|
|
283
|
+
},
|
|
284
|
+
}),
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Notes
|
|
289
|
+
|
|
290
|
+
- If a component does not need variants or slots, omit them. Do not add empty
|
|
291
|
+
contracts or classes.
|
|
292
|
+
- If a component needs a tone system, model it as **data** (`tone` variant), but
|
|
293
|
+
keep visual treatment in `variant` (`filled/outlined/text`).
|
|
294
|
+
- Structural overrides (spacing, typography, shape, elevation, motion) should be
|
|
295
|
+
expressed through vars, not hard-coded values.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Seedly theming strategy (internal)
|
|
2
|
+
|
|
3
|
+
This document explains Seedly’s **theming philosophy** and the intended balance
|
|
4
|
+
between being “unstyled” and still offering strong, composable primitives.
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
|
|
8
|
+
Seedly aims to be **opinionated on functionality** but **neutral on appearance**.
|
|
9
|
+
Components should be usable out-of-the-box, while giving consumers complete
|
|
10
|
+
control of styling through Vanilla Extract contracts.
|
|
11
|
+
|
|
12
|
+
## Core principles
|
|
13
|
+
|
|
14
|
+
### 1) Separate structure from appearance
|
|
15
|
+
|
|
16
|
+
- **Structure** = layout, DOM shape, spacing relationships, focus handling, and
|
|
17
|
+
accessibility.
|
|
18
|
+
- **Appearance** = color, borders, radius, shadows, typography, and decorative
|
|
19
|
+
effects.
|
|
20
|
+
|
|
21
|
+
**Rule:** both structure and appearance must be expressed through system tokens
|
|
22
|
+
and component vars so they are fully overridable. The separation is
|
|
23
|
+
organizational, not technical.
|
|
24
|
+
|
|
25
|
+
### 2) System tokens are semantic and minimal
|
|
26
|
+
|
|
27
|
+
- `sys` represents **semantic roles**, not palettes.
|
|
28
|
+
- Roles must stay neutral so Seedly is not locked to any single design language.
|
|
29
|
+
- Consumers map their `refs` layer into `sys.surface`, `sys.tone`, and other
|
|
30
|
+
system roles in userland.
|
|
31
|
+
|
|
32
|
+
### 3) Component contracts carry the styling surface
|
|
33
|
+
|
|
34
|
+
- `ComponentVars` are the primary styling API.
|
|
35
|
+
- Variants should **assign vars**, not hard-code raw values.
|
|
36
|
+
- Slots are opt-in escape hatches for structured components.
|
|
37
|
+
|
|
38
|
+
### 4) Optional presets, never mandatory
|
|
39
|
+
|
|
40
|
+
Seedly can ship a **reference theme** as an optional layer. It must live
|
|
41
|
+
separately from contracts so consumers can ignore or replace it.
|
|
42
|
+
|
|
43
|
+
## What “unstyled” means in Seedly
|
|
44
|
+
|
|
45
|
+
Seedly is **unstyled in appearance**, not in structure. Components should:
|
|
46
|
+
|
|
47
|
+
- Provide accessible structure and layout.
|
|
48
|
+
- Avoid locking consumers into a specific visual language.
|
|
49
|
+
- Still render with a usable default look when paired with a reference theme.
|
|
50
|
+
|
|
51
|
+
## Expected consumer workflow
|
|
52
|
+
|
|
53
|
+
1. Define palette (`refs`) and map it to semantic roles (`sys`).
|
|
54
|
+
2. Optionally apply a reference theme for quick setup.
|
|
55
|
+
3. Override per-component vars when deeper customization is required.
|
|
56
|
+
|
|
57
|
+
## Non-goals
|
|
58
|
+
|
|
59
|
+
- Runtime theming is not a priority.
|
|
60
|
+
- CSS-only overrides are not a primary target.
|
|
61
|
+
- Seedly should not encode a full external design spec in its system contract.
|
|
62
|
+
|
|
63
|
+
## Summary
|
|
64
|
+
|
|
65
|
+
Seedly stays in the middle by:
|
|
66
|
+
|
|
67
|
+
- Keeping system roles **semantic and minimal**.
|
|
68
|
+
- Exposing **component-level contracts** as the main styling surface.
|
|
69
|
+
- Allowing **optional presets** for convenience without locking consumers in.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Tone system (internal)
|
|
2
|
+
|
|
3
|
+
This document defines the **tone system** for Seedly's semantic color
|
|
4
|
+
architecture. It is intended for internal implementation guidance and will later
|
|
5
|
+
be adapted for external documentation.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Seedly separates colors into two distinct concerns:
|
|
10
|
+
|
|
11
|
+
1. **Surface colors** (`sys.surface`) — The page-level canvas
|
|
12
|
+
2. **Tone colors** (`sys.tone`) — Semantic colors for interactive and stateful
|
|
13
|
+
elements
|
|
14
|
+
|
|
15
|
+
Surface expresses the neutral canvas of the application, so components can
|
|
16
|
+
anchor their defaults against a consistent base layer before applying tones for
|
|
17
|
+
emphasis.
|
|
18
|
+
|
|
19
|
+
This separation exists because a neutral interactive element sitting on a page
|
|
20
|
+
is visually distinct from the page background itself. Keeping them separate
|
|
21
|
+
gives consumers full control over both layers.
|
|
22
|
+
|
|
23
|
+
## Surface colors
|
|
24
|
+
|
|
25
|
+
Surface colors define the default page/app appearance:
|
|
26
|
+
|
|
27
|
+
| Token | Purpose |
|
|
28
|
+
| ------------------------ | -------------------------------- |
|
|
29
|
+
| `sys.surface.background` | Page or app background |
|
|
30
|
+
| `sys.surface.foreground` | Default text color on background |
|
|
31
|
+
|
|
32
|
+
These tokens are the canvas on which components are rendered. They can also
|
|
33
|
+
serve as a neutral foundation for components that should blend with the base
|
|
34
|
+
surface before tones are applied.
|
|
35
|
+
|
|
36
|
+
## Tone colors
|
|
37
|
+
|
|
38
|
+
Tones are semantic color pairs for interactive elements and stateful feedback.
|
|
39
|
+
Each tone consists of two tokens following the `on{Name}` convention:
|
|
40
|
+
|
|
41
|
+
| Pattern | Purpose |
|
|
42
|
+
| ------------------- | ------------------------------------------ |
|
|
43
|
+
| `sys.tone.{name}` | The tone's base color (container/surface) |
|
|
44
|
+
| `sys.tone.on{Name}` | The contrasting color (content/text on it) |
|
|
45
|
+
|
|
46
|
+
### Defined tones
|
|
47
|
+
|
|
48
|
+
| Tone | Purpose |
|
|
49
|
+
| ------------- | ---------------------------------------------- |
|
|
50
|
+
| `neutral` | Default interactive elements without emphasis |
|
|
51
|
+
| `primary` | Brand emphasis, main calls-to-action |
|
|
52
|
+
| `destructive` | Errors, dangerous/irreversible actions |
|
|
53
|
+
| `success` | Positive feedback, confirmations, valid states |
|
|
54
|
+
|
|
55
|
+
## Why separate surface from tones?
|
|
56
|
+
|
|
57
|
+
A neutral button needs to stand out from the page surface. If they shared the
|
|
58
|
+
same token, you could not style a neutral button differently from the page
|
|
59
|
+
background.
|
|
60
|
+
|
|
61
|
+
Keeping them separate allows:
|
|
62
|
+
|
|
63
|
+
- Neutral elements to be visually distinct from the surface
|
|
64
|
+
- Surface to change independently of component tones
|
|
65
|
+
- Consumers to alias them if their design requires it
|
|
66
|
+
|
|
67
|
+
## Component integration
|
|
68
|
+
|
|
69
|
+
Components use `tone` as a variant axis to apply semantic colors. The `variant`
|
|
70
|
+
axis controls visual treatment (filled, outlined, text). These are orthogonal
|
|
71
|
+
concerns.
|
|
72
|
+
|
|
73
|
+
### Variant and tone interaction
|
|
74
|
+
|
|
75
|
+
The `variant` controls how tones are applied:
|
|
76
|
+
|
|
77
|
+
| Variant | Container | Content | Outline |
|
|
78
|
+
| ---------- | ----------------- | ------------------- | ----------------- |
|
|
79
|
+
| `filled` | `sys.tone.{tone}` | `sys.tone.on{Tone}` | `transparent` |
|
|
80
|
+
| `outlined` | `transparent` | `sys.tone.{tone}` | `sys.tone.{tone}` |
|
|
81
|
+
| `text` | `transparent` | `sys.tone.{tone}` | `transparent` |
|
|
82
|
+
|
|
83
|
+
Component vars (e.g. `buttonVars.color.outline`) map to tone tokens when a tone
|
|
84
|
+
is active, but can be overridden independently at the component level.
|
|
85
|
+
|
|
86
|
+
### State modifiers
|
|
87
|
+
|
|
88
|
+
Tones rely on global state tokens for hover, pressed, and disabled styling:
|
|
89
|
+
|
|
90
|
+
- `sys.state.hovered.opacity`
|
|
91
|
+
- `sys.state.pressed.opacity`
|
|
92
|
+
- `sys.state.muted.light`
|
|
93
|
+
- `sys.state.muted.dark`
|
|
94
|
+
|
|
95
|
+
Disabled states should reduce contrast using the muted tokens, regardless of the
|
|
96
|
+
active tone.
|
|
97
|
+
|
|
98
|
+
### Form field error states
|
|
99
|
+
|
|
100
|
+
Form components use the `destructive` tone for error states and the `success`
|
|
101
|
+
tone for valid states. This is applied via data attributes or internal state,
|
|
102
|
+
not as a variant.
|
|
103
|
+
|
|
104
|
+
## Design decisions
|
|
105
|
+
|
|
106
|
+
### Why not expand `sys.surface` with semantic slots?
|
|
107
|
+
|
|
108
|
+
The theming strategy states that Seedly should not encode a full external design
|
|
109
|
+
spec in its system contract. Adding `primary`, `destructive`, etc. directly to
|
|
110
|
+
`sys.surface` would mix surface concerns with interactive semantics. The
|
|
111
|
+
`sys.tone` namespace keeps them organized and purpose-clear.
|
|
112
|
+
|
|
113
|
+
### Why flat tokens instead of nested?
|
|
114
|
+
|
|
115
|
+
Flat structure (`sys.tone.primary`, `sys.tone.onPrimary`) instead of nested
|
|
116
|
+
(`sys.tone.primary.base`, `sys.tone.primary.onBase`) because:
|
|
117
|
+
|
|
118
|
+
- Shorter paths in component code
|
|
119
|
+
- Matches established design system conventions
|
|
120
|
+
- Simpler mental model
|
|
121
|
+
|
|
122
|
+
### Why these four tones?
|
|
123
|
+
|
|
124
|
+
| Tone | Justification |
|
|
125
|
+
| ------------- | -------------------------------------------------- |
|
|
126
|
+
| `neutral` | Every design system needs a default |
|
|
127
|
+
| `primary` | Brand emphasis is universal |
|
|
128
|
+
| `destructive` | Error states and dangerous actions are unavoidable |
|
|
129
|
+
| `success` | Form validation requires both error and success |
|
|
130
|
+
|
|
131
|
+
Additional tones can be added later if needed, but these four cover the
|
|
132
|
+
essential use cases without over-specifying a design language.
|
|
133
|
+
|
|
134
|
+
## Summary
|
|
135
|
+
|
|
136
|
+
- `sys.surface` defines the page-level surface (background/foreground)
|
|
137
|
+
- `sys.tone` defines semantic interactive colors
|
|
138
|
+
- Components expose `tone` as a variant axis alongside `variant` and `size`
|
|
139
|
+
- Tones use flat pairs: `{tone}` and `on{Tone}`
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Seedly value and scope (internal)
|
|
2
|
+
|
|
3
|
+
This document explains **why Seedly exists**, what it is good at, and what it
|
|
4
|
+
intentionally does not try to solve.
|
|
5
|
+
|
|
6
|
+
## Value statement
|
|
7
|
+
|
|
8
|
+
Seedly exists to make **consistent, accessible, themeable UI** sustainable at
|
|
9
|
+
scale. It provides composable primitives with a clear styling surface so teams
|
|
10
|
+
can move fast without drifting into bespoke, inconsistent patterns.
|
|
11
|
+
|
|
12
|
+
Seedly is not about speed to the first UI. It is about **speed to maintainable
|
|
13
|
+
UI**.
|
|
14
|
+
|
|
15
|
+
## Strengths
|
|
16
|
+
|
|
17
|
+
- **Consistency at scale**: shared primitives reduce design drift across teams.
|
|
18
|
+
- **Token-driven theming**: system roles + component contracts enable
|
|
19
|
+
multi-brand or multi-product theming without rewriting markup.
|
|
20
|
+
- **Accessible behavior**: wrapping headless primitives (e.g. Radix) provides
|
|
21
|
+
robust interaction patterns out of the box.
|
|
22
|
+
- **Composable API**: slots, variants, and responsive patterns create predictable
|
|
23
|
+
integration points.
|
|
24
|
+
- **Build-time styling**: Vanilla Extract produces static CSS with type-safe
|
|
25
|
+
contracts.
|
|
26
|
+
|
|
27
|
+
## Shortcomings and trade-offs
|
|
28
|
+
|
|
29
|
+
- **Slower iteration** than Tailwind-first or LLM-generated UI for one-off
|
|
30
|
+
screens.
|
|
31
|
+
- **Higher onboarding cost**: consumers must learn tokens, contracts, and VE.
|
|
32
|
+
- **Less suited to bespoke design**: one-off visual treatments require more work.
|
|
33
|
+
- **Wrapper maintenance**: upstream headless changes must be tracked carefully.
|
|
34
|
+
- **Not optimized for runtime theming**: compile-time theming is the default.
|
|
35
|
+
|
|
36
|
+
## Scope boundaries
|
|
37
|
+
|
|
38
|
+
Seedly focuses on **functional primitives** with a robust styling surface. It is
|
|
39
|
+
not a full design system or a complete UI kit.
|
|
40
|
+
|
|
41
|
+
### In scope
|
|
42
|
+
|
|
43
|
+
- Accessible, composable primitives with stable APIs.
|
|
44
|
+
- System roles and component contracts for structure and appearance.
|
|
45
|
+
- Variant, size, tone, and responsive patterns.
|
|
46
|
+
- Optional reference themes for bootstrapping.
|
|
47
|
+
|
|
48
|
+
### Out of scope
|
|
49
|
+
|
|
50
|
+
- A prescriptive visual design language.
|
|
51
|
+
- Rapid prototyping or ad-hoc UI generation.
|
|
52
|
+
- Runtime theming as a first-class feature.
|
|
53
|
+
- App-specific layouts or product-level design patterns.
|
|
54
|
+
|
|
55
|
+
## When to use Seedly
|
|
56
|
+
|
|
57
|
+
- You need **consistency across teams** or products.
|
|
58
|
+
- You expect **theme reuse** or multi-brand support.
|
|
59
|
+
- You value **maintainable, accessible UI** over quick, bespoke styling.
|
|
60
|
+
|
|
61
|
+
## When not to use Seedly
|
|
62
|
+
|
|
63
|
+
- You prioritize **iteration speed** over long-term consistency.
|
|
64
|
+
- Your UI is **highly bespoke** and unlikely to be reused.
|
|
65
|
+
- You are building a one-off prototype or marketing site.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kalink-ui/seedly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "A set of components for building UIs with React and TypeScript",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css.ts"
|
|
@@ -85,8 +85,9 @@
|
|
|
85
85
|
"lint:fix": "pnpm lint --fix",
|
|
86
86
|
"build-storybook": "storybook build",
|
|
87
87
|
"dev": "storybook dev -p 6006 --no-open",
|
|
88
|
-
"test": "vitest run",
|
|
89
|
-
"test:watch": "vitest",
|
|
88
|
+
"test": "vitest run --project=unit",
|
|
89
|
+
"test:watch": "vitest --project=unit",
|
|
90
|
+
"test-storybook": "vitest run --project=storybook",
|
|
90
91
|
"tsc": "tsc -b"
|
|
91
92
|
}
|
|
92
93
|
}
|