@kalink-ui/seedly 0.34.3 → 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.
Files changed (144) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +34 -0
  3. package/docs/component-theming.md +295 -0
  4. package/docs/theming-strategy.md +69 -0
  5. package/docs/tone-system.md +139 -0
  6. package/docs/value-and-scope.md +65 -0
  7. package/package.json +4 -3
  8. package/src/components/alert-dialog/alert-dialog-action.tsx +0 -2
  9. package/src/components/alert-dialog/alert-dialog-cancel.tsx +0 -1
  10. package/src/components/alert-dialog/alert-dialog-content.css.ts +1 -1
  11. package/src/components/alert-dialog/alert-dialog-content.tsx +13 -6
  12. package/src/components/alert-dialog/alert-dialog-footer.css.ts +3 -3
  13. package/src/components/alert-dialog/alert-dialog-footer.tsx +2 -2
  14. package/src/components/alert-dialog/alert-dialog-header.tsx +4 -4
  15. package/src/components/alert-dialog/index.ts +9 -0
  16. package/src/components/box/box.css.ts +137 -39
  17. package/src/components/box/box.responsive.ts +2 -2
  18. package/src/components/box/box.tsx +2 -3
  19. package/src/components/box/index.ts +1 -1
  20. package/src/components/button/button.css.ts +142 -149
  21. package/src/components/button/button.responsive.ts +2 -2
  22. package/src/components/button/button.tsx +44 -31
  23. package/src/components/button/index.ts +2 -2
  24. package/src/components/button-icon/button-icon.css.ts +26 -62
  25. package/src/components/button-icon/button-icon.responsive.ts +2 -2
  26. package/src/components/button-icon/button-icon.tsx +5 -7
  27. package/src/components/card/card.css.ts +1 -5
  28. package/src/components/card/card.tsx +11 -11
  29. package/src/components/center/center.css.ts +61 -21
  30. package/src/components/center/center.responsive.ts +2 -2
  31. package/src/components/center/center.tsx +4 -6
  32. package/src/components/center/index.ts +1 -1
  33. package/src/components/cluster/cluster.css.ts +37 -99
  34. package/src/components/cluster/cluster.responsive.ts +13 -2
  35. package/src/components/cluster/cluster.tsx +6 -5
  36. package/src/components/cluster/index.ts +5 -1
  37. package/src/components/command/command-empty.tsx +36 -4
  38. package/src/components/command/command-group.css.ts +23 -7
  39. package/src/components/command/command-group.tsx +30 -6
  40. package/src/components/command/command-input.css.ts +2 -2
  41. package/src/components/command/command-item.tsx +26 -2
  42. package/src/components/command/command-list.css.ts +2 -2
  43. package/src/components/command/command-list.responsive.ts +2 -2
  44. package/src/components/command/command-list.tsx +1 -2
  45. package/src/components/command/command-separator.tsx +7 -5
  46. package/src/components/cover/cover.css.ts +29 -8
  47. package/src/components/cover/cover.tsx +13 -13
  48. package/src/components/cover/index.ts +2 -2
  49. package/src/components/divider/divider.css.ts +9 -4
  50. package/src/components/form-field/form-field-context.ts +3 -0
  51. package/src/components/form-field/form-field-item.tsx +3 -3
  52. package/src/components/form-field/form-field-message.tsx +34 -3
  53. package/src/components/form-field/form-field.css.ts +78 -16
  54. package/src/components/form-field/form-field.tsx +5 -0
  55. package/src/components/form-field/index.ts +1 -1
  56. package/src/components/frame/frame.css.ts +96 -59
  57. package/src/components/frame/frame.responsive.ts +9 -0
  58. package/src/components/frame/frame.tsx +11 -5
  59. package/src/components/frame/index.ts +1 -1
  60. package/src/components/grid/grid-child.tsx +14 -10
  61. package/src/components/grid/grid.css.ts +56 -148
  62. package/src/components/grid/grid.tsx +40 -18
  63. package/src/components/grid/index.ts +4 -3
  64. package/src/components/heading/heading.css.ts +4 -4
  65. package/src/components/heading/heading.responsive.ts +6 -6
  66. package/src/components/heading/heading.tsx +3 -4
  67. package/src/components/heading/index.ts +1 -1
  68. package/src/components/input/index.ts +4 -1
  69. package/src/components/input/input-wrapper.tsx +20 -8
  70. package/src/components/input/input.css.ts +121 -93
  71. package/src/components/input/input.responsive.ts +9 -0
  72. package/src/components/input/input.tsx +7 -1
  73. package/src/components/label/label.css.ts +2 -2
  74. package/src/components/label/label.tsx +23 -3
  75. package/src/components/layout-maps.ts +120 -0
  76. package/src/components/loader/index.ts +2 -1
  77. package/src/components/loader/loader.css.ts +91 -54
  78. package/src/components/loader/moon-loader.responsive.ts +2 -2
  79. package/src/components/loader/moon-loader.tsx +4 -5
  80. package/src/components/loader-overlay/loader-overlay.css.ts +3 -3
  81. package/src/components/loader-overlay/loader-overlay.tsx +5 -2
  82. package/src/components/menu/index.ts +2 -2
  83. package/src/components/menu/menu-item.css.ts +102 -46
  84. package/src/components/menu/menu-separator.css.ts +27 -15
  85. package/src/components/menu/menu-separator.responsive.ts +2 -2
  86. package/src/components/overlay/overlay.css.ts +1 -1
  87. package/src/components/popover/index.ts +1 -1
  88. package/src/components/popover/popover-content.css.ts +69 -52
  89. package/src/components/popover/popover-content.tsx +22 -6
  90. package/src/components/scroll-area/scroll-area.css.ts +3 -3
  91. package/src/components/scroll-area/scroll-bar.tsx +2 -2
  92. package/src/components/select/index.ts +4 -5
  93. package/src/components/select/select-content.css.ts +1 -1
  94. package/src/components/select/select-content.tsx +2 -2
  95. package/src/components/select/select-item.tsx +11 -3
  96. package/src/components/select/select-trigger.css.ts +14 -18
  97. package/src/components/select/select-trigger.tsx +18 -8
  98. package/src/components/select/select.tsx +10 -6
  99. package/src/components/sheet/index.ts +12 -0
  100. package/src/components/sheet/sheet-content.css.ts +2 -2
  101. package/src/components/sheet/sheet-content.tsx +25 -7
  102. package/src/components/sheet/sheet-description.tsx +5 -7
  103. package/src/components/sheet/sheet-footer.tsx +3 -1
  104. package/src/components/sheet/sheet-header.css.ts +1 -1
  105. package/src/components/sheet/sheet-header.tsx +3 -3
  106. package/src/components/sheet/sheet-overlay.tsx +3 -4
  107. package/src/components/sheet/sheet-title.tsx +1 -1
  108. package/src/components/sidebar/index.ts +5 -1
  109. package/src/components/sidebar/sidebar.css.ts +35 -9
  110. package/src/components/sidebar/sidebar.tsx +7 -10
  111. package/src/components/skeleton/skeleton.css.ts +23 -14
  112. package/src/components/skeleton/skeleton.tsx +26 -7
  113. package/src/components/stack/index.ts +1 -1
  114. package/src/components/stack/stack.css.ts +18 -46
  115. package/src/components/stack/stack.tsx +1 -2
  116. package/src/components/switcher/index.ts +5 -1
  117. package/src/components/switcher/switcher.css.ts +105 -72
  118. package/src/components/switcher/switcher.responsive.ts +2 -2
  119. package/src/components/switcher/switcher.tsx +5 -5
  120. package/src/components/text/text.css.ts +93 -105
  121. package/src/components/text/text.responsive.ts +3 -63
  122. package/src/components/text/text.tsx +16 -28
  123. package/src/components/text-field/index.ts +1 -2
  124. package/src/components/text-field/text-field.tsx +5 -7
  125. package/src/components/textarea/textarea-input.tsx +30 -3
  126. package/src/components/textarea/textarea.css.ts +12 -7
  127. package/src/components/textarea/textarea.tsx +9 -3
  128. package/src/components/visually-hidden/visually-hidden.css.ts +16 -10
  129. package/src/styles/define-responsive-properties.ts +5 -1
  130. package/src/styles/index.ts +12 -0
  131. package/src/styles/responsive.ts +72 -43
  132. package/src/styles/system-contract.css.ts +22 -3
  133. package/src/styles/theme/sprout-ref.css.ts +107 -0
  134. package/src/styles/theme/sprout.css.ts +259 -0
  135. package/src/styles/tone.ts +69 -0
  136. package/src/styles/typography.responsive.css.ts +35 -0
  137. package/src/styles/typography.responsive.ts +104 -0
  138. package/src/utils/arg-types/index.ts +1 -0
  139. package/src/utils/arg-types/responsive-arg.ts +28 -0
  140. package/src/utils/index.ts +1 -0
  141. package/src/components/command/command-item.css.ts +0 -32
  142. package/src/components/select/select.css.ts +0 -3
  143. package/src/components/sheet/sheet-body.css.ts +0 -68
  144. package/src/components/text-field/text-field.css.ts +0 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
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
+
15
+ ## 0.34.4
16
+
17
+ ### Patch Changes
18
+
19
+ - 3b84777: Re-export the SheetBody, SheetFooter, and SheetOverlay components from the sheet entrypoint.
20
+
3
21
  ## 0.34.3
4
22
 
5
23
  ### 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.34.3",
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
  }
@@ -9,9 +9,7 @@ export type AlertDialogActionProps = ComponentPropsWithRef<typeof Action> &
9
9
  };
10
10
 
11
11
  export function AlertDialogAction({
12
- className,
13
12
  children,
14
- loading,
15
13
  ...props
16
14
  }: AlertDialogActionProps) {
17
15
  return (
@@ -7,7 +7,6 @@ export type AlertDialogCancelProps = ComponentPropsWithRef<typeof Cancel> &
7
7
  ButtonProps<'button'>;
8
8
 
9
9
  export function AlertDialogCancel({
10
- className,
11
10
  children,
12
11
  ...props
13
12
  }: AlertDialogCancelProps) {
@@ -26,7 +26,7 @@ const exitAnimation = keyframes({
26
26
  },
27
27
  });
28
28
 
29
- export const alertDialogContent = recipe({
29
+ export const alertDialogContentRecipe = recipe({
30
30
  base: {
31
31
  '@layer': {
32
32
  [components]: {