@sproutsocial/seeds-theme 0.1.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 (42) hide show
  1. package/README.md +259 -0
  2. package/dist/css-tokens.json +134 -0
  3. package/dist/legacy-dark.css +437 -0
  4. package/dist/legacy-light.css +437 -0
  5. package/dist/legacy.css +659 -0
  6. package/dist/schema.json +11798 -0
  7. package/dist/shadcn-dark.css +2 -0
  8. package/dist/shadcn-light.css +2 -0
  9. package/dist/shadcn.css +2 -0
  10. package/dist/shadcn.registry.json +77 -0
  11. package/dist/source/shadcn-dark.tokens.json +169 -0
  12. package/dist/source/shadcn-light.tokens.json +169 -0
  13. package/dist/source/theme-dark.tokens.json +1945 -0
  14. package/dist/source/theme-light.tokens.json +1945 -0
  15. package/dist/styled-components/index.cjs +1648 -0
  16. package/dist/styled-components/index.d.ts +3654 -0
  17. package/dist/styled-components/index.js +1641 -0
  18. package/dist/styled-components/index.ts +5285 -0
  19. package/dist/tailwind.css +40 -0
  20. package/dist/theme-dark.css +388 -0
  21. package/dist/theme-dark.d.ts +420 -0
  22. package/dist/theme-dark.js +401 -0
  23. package/dist/theme-dark.json +712 -0
  24. package/dist/theme-light.css +388 -0
  25. package/dist/theme-light.d.ts +420 -0
  26. package/dist/theme-light.js +400 -0
  27. package/dist/theme-light.json +712 -0
  28. package/dist/theme.css +611 -0
  29. package/mode-authoring.md +54 -0
  30. package/package.json +96 -0
  31. package/src/cli.js +42 -0
  32. package/src/compiler.d.ts +9 -0
  33. package/src/compiler.js +533 -0
  34. package/src/config.d.ts +39 -0
  35. package/src/config.js +280 -0
  36. package/src/contract.js +351 -0
  37. package/src/extension-schema.js +88 -0
  38. package/src/extension.d.ts +18 -0
  39. package/src/extension.js +81 -0
  40. package/src/index.d.ts +90 -0
  41. package/src/index.js +9 -0
  42. package/src/primitives.js +98 -0
package/README.md ADDED
@@ -0,0 +1,259 @@
1
+ # @sproutsocial/seeds-theme
2
+
3
+ Seeds provides the default Sprout appearance in light and dark mode. It also
4
+ provides defaults for shadcn variable names such as `--background`, `--primary`,
5
+ and `--card`. Applications can use these defaults immediately and override only
6
+ what differs in their product theme.
7
+
8
+ ## Choose an entry point
9
+
10
+ The descriptions below distinguish theme values from the Tailwind configuration
11
+ that makes those values available through utility classes. Import paths shown
12
+ here are relative to `@sproutsocial/seeds-theme`.
13
+
14
+ | Import | What to call it | What it does |
15
+ | -------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
16
+ | `/css/theme` | **Seeds theme defaults** | Provides light and dark values for familiar Seeds variables and all shadcn names in the package's mapping. This is the normal CSS entry point. |
17
+ | `/css/tailwind` | **Tailwind utility mappings** | Connects utilities such as `bg-primary` and `text-foreground` to the shadcn variables. It contains no light/dark color choices. |
18
+ | `/css/shadcn` | **Seeds defaults + Tailwind mappings** | Convenience entry point importing the two files above. It does not define another theme. Choose this or the two explicit imports. |
19
+ | `/schema` | **Theme override autocomplete** | Describes supported token paths, types, and references for editors. It is JSON Schema, not CSS and not a set of theme values. |
20
+ | `/extension` | **Product theme builder** | Builds one CSS file containing a product's light/dark overrides. Unchanged values inherit Seeds. |
21
+ | `/css/legacy` | **Historical Seeds CSS names** | Preserves CSS variable names and behavior needed by existing integrations. |
22
+ | `/styled-components` | **Existing React theme objects** | Supplies the compatibility objects used by `seeds-react-theme`. Existing applications keep their current `seeds-react-theme` imports. |
23
+
24
+ For a shadcn application, use `/css/shadcn` after the required primitive
25
+ stylesheets shown below. If the application already has equivalent Tailwind
26
+ mappings, use `/css/theme` and keep that mapping in one place.
27
+
28
+ ## How theme defaults and Tailwind mappings work together
29
+
30
+ Seeds assigns the light/dark values. The Tailwind mapping connects a utility
31
+ name to a variable, and that connection stays the same in both modes:
32
+
33
+ ```text
34
+ bg-primary
35
+ → --primary shadcn variable
36
+ → --colors-button-primary-background-base Seeds theme choice
37
+ → --color-blue-700 existing design token (light default)
38
+ ```
39
+
40
+ For example, `tailwind.css` contains:
41
+
42
+ ```css
43
+ @theme inline {
44
+ --color-primary: var(--primary);
45
+ }
46
+ ```
47
+
48
+ Tailwind uses this to generate `bg-primary` with
49
+ `background-color: var(--primary)`. When the root receives `.dark`, the theme
50
+ changes the underlying value and the same utility follows it. There is no
51
+ separate dark Tailwind mapping file to load. The `@custom-variant dark` rule also
52
+ enables explicit `dark:*` utilities for cases that need a different CSS rule.
53
+
54
+ Product CSS can remap a shadcn variable directly. The current JSON authoring API
55
+ and autocomplete expose the familiar Seeds paths; changing
56
+ `colors.button.primary.background.base` changes the default `--primary` value.
57
+ Direct shadcn-name overrides in the JSON authoring API are a separate, pending
58
+ improvement. The shadcn light/dark defaults are already provided.
59
+
60
+ ## Read and edit the theme
61
+
62
+ Start with these three source files:
63
+
64
+ - [tokens/base.tokens.json](tokens/base.tokens.json): **shared theme choices**,
65
+ used in both modes and referencing the existing design-token packages.
66
+ - [tokens/light.tokens.json](tokens/light.tokens.json): **light-mode theme choices**.
67
+ - [tokens/dark.tokens.json](tokens/dark.tokens.json): **dark-mode theme choices**.
68
+
69
+ The paths mirror the existing object API. `theme.colors.container.background.base`
70
+ becomes `colors.container.background.base` in the token file. Button states,
71
+ form colors, navigation, listening, growth, and the other Sprout additions use
72
+ their existing names. The `theme` wrapper is unnecessary inside a theme file.
73
+
74
+ ```json
75
+ {
76
+ "colors": {
77
+ "$type": "color",
78
+ "container": {
79
+ "background": {
80
+ "base": { "$value": "{color.neutral.0}" }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ Existing design-token packages own palette, spacing, typography, border, depth,
88
+ and motion values. The compiler reads their public exports for reference
89
+ resolution; the theme does not author a second set of those values. `color`
90
+ (singular) references the existing palette; `colors` contains familiar theme roles.
91
+ Declare `$type` once on a group. Leaves inherit it; exceptional values such as
92
+ color gradients declare `$type: "string"`.
93
+
94
+ Modern CSS, JSON, JavaScript, and token outputs contain theme roles and shadcn
95
+ aliases, without exporting the underlying primitive scales. Historical palette,
96
+ spacing, and typography fields exist only in the compatibility output, with
97
+ [compatibility/scales.tokens.json](compatibility/scales.tokens.json) mapping their
98
+ old paths to the existing packages by reference.
99
+
100
+ The two historical `colors.gradient.ai-stop-2` colors have no exact palette
101
+ match. They remain documented, theme-owned tokens in light and dark, each
102
+ authored once and referenced by both gradient expressions. Other gradient stops
103
+ and alpha colors reference existing tokens; no nearby colors are substituted.
104
+ Every historical compatibility value is retained, including arrays, numeric
105
+ values, CSS expressions, and alpha spelling. The files use Style Dictionary's DTCG-style `$type` / `$value`
106
+ authoring conventions; historical CSS color and dimension strings are preserved.
107
+ They are not a claim of strict DTCG 2025 composite-value conformance.
108
+
109
+ ## Load the theme defaults
110
+
111
+ ```css
112
+ /* Include each primitive stylesheet once, if the app does not already load it. */
113
+ @import "@sproutsocial/seeds-color/dist/seeds-color.css";
114
+ @import "@sproutsocial/seeds-border/dist/seeds-border.css";
115
+ @import "@sproutsocial/seeds-depth/dist/seeds-depth.css";
116
+ @import "@sproutsocial/seeds-theme/css/theme";
117
+ ```
118
+
119
+ The theme import includes both modes and the Seeds-provided defaults for shadcn's CSS variable names. Add `.dark` to the root
120
+ for dark mode. Seeds remains the baseline when a product theme is selected with
121
+ `data-theme`, so a product can override only the values it needs.
122
+
123
+ `colors.container.background.base` generates
124
+ `--colors-container-background-base: var(--color-neutral-0)` in light mode.
125
+ The shadcn `--card` variable references that theme role. The primitive declaration
126
+ itself remains in `seeds-color`.
127
+ [tokens/adapters/css.json](tokens/adapters/css.json) is a name-to-token mapping;
128
+ it contains no independently authored color values.
129
+
130
+ For Tailwind v4, add the utility mappings with
131
+ `@sproutsocial/seeds-theme/css/tailwind`, or replace the theme import with
132
+ `@sproutsocial/seeds-theme/css/shadcn` to load defaults and mappings together. Concrete colors
133
+ owned by the theme use Style Dictionary's OKLCH transform. Existing colors stay
134
+ live references to `seeds-color`; applications can alternatively load its
135
+ `seeds-color-oklch.css` output. Additional references to space, typography, motion,
136
+ or network tokens require the corresponding package's CSS too. Importing a
137
+ package's JavaScript values alone does not load its stylesheet.
138
+
139
+ ## Author product theme overrides
140
+
141
+ Author `light.tokens.json` and `dark.tokens.json`. Each file contains only its
142
+ mode's overrides, using the same familiar paths:
143
+
144
+ ```json
145
+ {
146
+ "$schema": "./node_modules/@sproutsocial/seeds-theme/dist/schema.json",
147
+ "colors": {
148
+ "$type": "color",
149
+ "container": {
150
+ "background": {
151
+ "base": { "$value": "{color.neutral.100}" }
152
+ }
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ Adjust `$schema` relative to the file's directory. The published `/schema` is
159
+ generated from the actual Seeds tokens; editors complete the existing nested
160
+ names and expected types. Use `{colors.button.primary.background.base}` references
161
+ instead of CSS `var()` expressions when making tokens depend on one another.
162
+ The schema also completes reference values such as `{color.blue.400}` and
163
+ `{space.size.300}`. Primitive tokens are read-only inputs: reference them rather
164
+ than overriding them. Reserve `product` for genuinely new product-owned tokens;
165
+ do not copy a palette that already exists.
166
+
167
+ ```js
168
+ import fs from "node:fs/promises";
169
+ import { buildThemeExtension } from "@sproutsocial/seeds-theme/extension";
170
+
171
+ const read = async (file) => JSON.parse(await fs.readFile(file, "utf8"));
172
+ await buildThemeExtension(
173
+ {
174
+ name: "sprout-one",
175
+ extends: "seeds",
176
+ modes: {
177
+ light: await read("themes/sprout-one/light.tokens.json"),
178
+ dark: await read("themes/sprout-one/dark.tokens.json"),
179
+ },
180
+ },
181
+ { outputFile: "src/styles/sprout-one.css" }
182
+ );
183
+ ```
184
+
185
+ Import Seeds CSS once and the generated product CSS after it. Select the product
186
+ with `<html data-theme="sprout-one">`; add `.dark` independently for dark mode.
187
+ The builder validates paths, types, mode coverage, references, and cycles, then
188
+ uses Style Dictionary's native `.extend()`. Its `extends: "seeds"` option chooses
189
+ the Seeds baseline; it is not the DTCG `$extends` group property.
190
+
191
+ Only changed declarations are emitted. Aliases remain CSS references, and dark
192
+ mode restores an inherited value when a light-only product override would hide it.
193
+ Product selectors outrank both Seeds baseline blocks regardless of import order.
194
+ An optional `common` object is supported, but two mode files are sufficient.
195
+
196
+ ## Existing styled-components consumers
197
+
198
+ Keep using `@sproutsocial/seeds-react-theme` exactly as today. Its `theme`,
199
+ `darkTheme`, `sproutLightTheme`, and `sproutDarkTheme` exports retain their values,
200
+ shapes, array properties, and shared object identities. The old base `theme`
201
+ export remains its historical subset; it does not acquire the Sprout-only keys.
202
+
203
+ `@sproutsocial/seeds-theme/styled-components` supplies those compatibility
204
+ objects. `seeds-react-theme` embeds the generated `/styled-components/source`
205
+ at build time, so existing consumers do not acquire a runtime dependency on
206
+ Style Dictionary or its newer Node requirement. [compatibility/seeds-paths.json](compatibility/seeds-paths.json) and
207
+ [compatibility/sprout-paths.json](compatibility/sprout-paths.json) contain only
208
+ historical paths. Their values come from the canonical theme references and compatibility bindings into existing design-token packages.
209
+ Pre-migration snapshots exist only under `test/fixtures/legacy` as independent
210
+ regression fixtures.
211
+
212
+ Historical `--color-*` names and selectors remain available through `/css/legacy`,
213
+ `/css/legacy-light`, and `/css/legacy-dark`. Those outputs retain their original
214
+ strings and require the historical `seeds-color` primitive CSS. They are checked
215
+ against the full Sprout objects during the package build.
216
+
217
+ ## Additional build outputs
218
+
219
+ Everything in `dist` is generated. Edit the authored token files above and
220
+ rebuild; do not edit the generated files. Most applications only need the entry
221
+ points in the first table.
222
+
223
+ - **Separate mode defaults:** `theme-light.css` and `theme-dark.css` contain
224
+ complete per-mode declarations. Their `shadcn-*` wrappers add Tailwind mappings.
225
+ Normal applications use the combined theme entry point instead.
226
+ - **Theme token definitions:** `source/*.tokens.json` retain references and
227
+ metadata for the compiler and extension builder.
228
+ - **Resolved theme values:** `theme-*.json` contain nested values;
229
+ `theme-*.js` contain flattened constants. Their `.d.ts` files describe those
230
+ constants. These are concrete snapshots rather than live CSS references, and
231
+ the JavaScript constants are not the styled-components theme objects.
232
+ - **Compatibility build input:** `styled-components/index.ts` is copied into
233
+ `seeds-react-theme` during its build. The neighboring `.js`, `.cjs`, and `.d.ts`
234
+ files provide the existing theme objects in the supported module formats.
235
+ - **Shadcn mapping metadata:** `css-tokens.json` records which Seeds token supplies
236
+ each shadcn variable. `shadcn.registry.json` is for registry distribution.
237
+
238
+ `/tokens/light` and `/tokens/dark` expose composed token graphs for tooling.
239
+ `/json/light`, `/json/dark`, `/light`, and `/dark` expose Style Dictionary's
240
+ resolved JSON or JavaScript outputs. `/css-tokens` exposes the shadcn alias map;
241
+ `/shadcn/registry` supplies a shadcn registry theme.
242
+
243
+ The lower-level `/config` API and CLI can build a complete product package with
244
+ custom selectors and an output manifest. The `/extension` example above is the
245
+ normal consumer API for sparse overrides.
246
+
247
+ ## Verification and scope
248
+
249
+ Run `yarn workspace @sproutsocial/seeds-theme test` and
250
+ `yarn workspace @sproutsocial/seeds-theme build`. Tests compare all four generated
251
+ compatibility objects with independent historical fixtures, check inheritance and
252
+ CSS references, and verify light/dark output. They also reject copied primitive
253
+ values, duplicate primitive output, missing CSS references, and primitive
254
+ overrides. The build checks legacy CSS parity.
255
+
256
+ Experience Platform integration is a later phase. Its extra component aliases,
257
+ layout choices, preference migration, and CSS file removal are not part of this
258
+ package's theme model. A combined light/dark authoring format is also deferred;
259
+ see [mode-authoring.md](mode-authoring.md) for the options.
@@ -0,0 +1,134 @@
1
+ {
2
+ "background": {
3
+ "path": "colors.app.background.base",
4
+ "$description": "Background CSS alias for colors.app.background.base."
5
+ },
6
+ "foreground": {
7
+ "path": "colors.text.body",
8
+ "$description": "Foreground CSS alias for colors.text.body."
9
+ },
10
+ "card": {
11
+ "path": "colors.container.background.base",
12
+ "$description": "Card CSS alias for colors.container.background.base."
13
+ },
14
+ "card-foreground": {
15
+ "path": "colors.text.headline",
16
+ "$description": "Card foreground CSS alias for colors.text.headline."
17
+ },
18
+ "popover": {
19
+ "path": "colors.container.background.base",
20
+ "$description": "Popover CSS alias for colors.container.background.base."
21
+ },
22
+ "popover-foreground": {
23
+ "path": "colors.text.body",
24
+ "$description": "Popover foreground CSS alias for colors.text.body."
25
+ },
26
+ "primary": {
27
+ "path": "colors.button.primary.background.base",
28
+ "$description": "Primary CSS alias for colors.button.primary.background.base."
29
+ },
30
+ "primary-foreground": {
31
+ "path": "colors.button.primary.text.base",
32
+ "$description": "Primary foreground CSS alias for colors.button.primary.text.base."
33
+ },
34
+ "secondary": {
35
+ "path": "colors.container.border.base",
36
+ "$description": "Secondary CSS alias for colors.container.border.base."
37
+ },
38
+ "secondary-foreground": {
39
+ "path": "colors.text.body",
40
+ "$description": "Secondary foreground CSS alias for colors.text.body."
41
+ },
42
+ "muted": {
43
+ "path": "colors.container.background.decorative.neutral",
44
+ "$description": "Muted CSS alias for colors.container.background.decorative.neutral."
45
+ },
46
+ "muted-foreground": {
47
+ "path": "colors.text.subtext",
48
+ "$description": "Muted foreground CSS alias for colors.text.subtext."
49
+ },
50
+ "accent": {
51
+ "path": "colors.listItem.background.hover",
52
+ "$description": "Accent CSS alias for colors.listItem.background.hover."
53
+ },
54
+ "accent-foreground": {
55
+ "path": "colors.text.body",
56
+ "$description": "Accent foreground CSS alias for colors.text.body."
57
+ },
58
+ "destructive": {
59
+ "path": "colors.button.destructive.background.base",
60
+ "$description": "Destructive CSS alias for colors.button.destructive.background.base."
61
+ },
62
+ "destructive-foreground": {
63
+ "path": "colors.button.destructive.text.base",
64
+ "$description": "Destructive foreground CSS alias for colors.button.destructive.text.base."
65
+ },
66
+ "border": {
67
+ "path": "colors.container.border.base",
68
+ "$description": "Border CSS alias for colors.container.border.base."
69
+ },
70
+ "input": {
71
+ "path": "colors.form.border.base",
72
+ "$description": "Input CSS alias for colors.form.border.base."
73
+ },
74
+ "ring": {
75
+ "path": "colors.form.border.selected",
76
+ "$description": "Ring CSS alias for colors.form.border.selected."
77
+ },
78
+ "radius": {
79
+ "path": "radii.inner",
80
+ "$description": "Radius CSS alias for radii.inner."
81
+ },
82
+ "sidebar": {
83
+ "path": "colors.navigation.main.background.base",
84
+ "$description": "Sidebar CSS alias for colors.navigation.main.background.base."
85
+ },
86
+ "sidebar-foreground": {
87
+ "path": "colors.navigation.text.base",
88
+ "$description": "Sidebar foreground CSS alias for colors.navigation.text.base."
89
+ },
90
+ "sidebar-primary": {
91
+ "path": "colors.navigation.listItem.background.selected",
92
+ "$description": "Sidebar primary CSS alias for colors.navigation.listItem.background.selected."
93
+ },
94
+ "sidebar-primary-foreground": {
95
+ "path": "colors.navigation.text.base",
96
+ "$description": "Sidebar primary foreground CSS alias for colors.navigation.text.base."
97
+ },
98
+ "sidebar-accent": {
99
+ "path": "colors.navigation.listItem.background.hover",
100
+ "$description": "Sidebar accent CSS alias for colors.navigation.listItem.background.hover."
101
+ },
102
+ "sidebar-accent-foreground": {
103
+ "path": "colors.navigation.text.hover",
104
+ "$description": "Sidebar accent foreground CSS alias for colors.navigation.text.hover."
105
+ },
106
+ "sidebar-border": {
107
+ "path": "colors.navigation.main.border.base",
108
+ "$description": "Sidebar border CSS alias for colors.navigation.main.border.base."
109
+ },
110
+ "sidebar-ring": {
111
+ "path": "colors.form.border.selected",
112
+ "$description": "Sidebar ring CSS alias for colors.form.border.selected."
113
+ },
114
+ "chart-1": {
115
+ "path": "colors.dataviz.map.1",
116
+ "$description": "Chart 1 CSS alias for colors.dataviz.map.1."
117
+ },
118
+ "chart-2": {
119
+ "path": "colors.dataviz.map.2",
120
+ "$description": "Chart 2 CSS alias for colors.dataviz.map.2."
121
+ },
122
+ "chart-3": {
123
+ "path": "colors.dataviz.map.3",
124
+ "$description": "Chart 3 CSS alias for colors.dataviz.map.3."
125
+ },
126
+ "chart-4": {
127
+ "path": "colors.dataviz.map.4",
128
+ "$description": "Chart 4 CSS alias for colors.dataviz.map.4."
129
+ },
130
+ "chart-5": {
131
+ "path": "colors.dataviz.map.5",
132
+ "$description": "Chart 5 CSS alias for colors.dataviz.map.5."
133
+ }
134
+ }