@stridge/noctis-design-tokens 1.0.0-beta.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 +226 -0
- package/dist/apply-scopes.d.ts +12 -0
- package/dist/apply-scopes.js +30 -0
- package/dist/css.d.ts +10 -0
- package/dist/css.js +36 -0
- package/dist/graph/components.d.ts +6 -0
- package/dist/graph/components.js +4488 -0
- package/dist/graph/index.d.ts +11 -0
- package/dist/graph/index.js +26 -0
- package/dist/graph/inputs.d.ts +1 -0
- package/dist/graph/inputs.js +23 -0
- package/dist/graph/model.d.ts +205 -0
- package/dist/graph/model.js +282 -0
- package/dist/graph/registry.d.ts +67 -0
- package/dist/graph/registry.js +118 -0
- package/dist/graph/roles.d.ts +5 -0
- package/dist/graph/roles.js +151 -0
- package/dist/graph/scales.d.ts +1 -0
- package/dist/graph/scales.js +1296 -0
- package/dist/graph/serialize.d.ts +16 -0
- package/dist/graph/serialize.js +25 -0
- package/dist/graph/statics.d.ts +1 -0
- package/dist/graph/statics.js +419 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +25 -0
- package/dist/palettes.d.ts +70 -0
- package/dist/palettes.js +114 -0
- package/dist/react/provider.d.ts +23 -0
- package/dist/react/provider.js +28 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.js +3 -0
- package/dist/scales.d.ts +186 -0
- package/dist/scales.js +186 -0
- package/dist/semantic.d.ts +36 -0
- package/dist/semantic.js +49 -0
- package/dist/swatches.d.ts +24 -0
- package/dist/swatches.js +57 -0
- package/dist/tokens.css +2607 -0
- package/dist/tokens.dtcg.json +3475 -0
- package/dist/tokens.json +14658 -0
- package/dist/tokens.tailwind.css +479 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# @stridge/noctis-design-tokens
|
|
2
|
+
|
|
3
|
+
The semantic token layer on top of `@stridge/noctis-theme-engine`. The engine generates the private
|
|
4
|
+
primitive ramp; this package maps it to intent-named **semantic roles** as framework-neutral CSS
|
|
5
|
+
variables (`--noctis-color-*`), ships the foundation scales, and wires the **elevation scopes**.
|
|
6
|
+
The Tailwind bridge is one optional consumer of those roles. Components style with the roles below
|
|
7
|
+
— never the primitives.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
The token CSS stands alone — it is `@import`ed by `@stridge/noctis/styles.css`, and needs no
|
|
12
|
+
styling framework. Import it directly only when consuming this package standalone:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
// app CSS entry
|
|
16
|
+
@import "@stridge/noctis-design-tokens/tokens.css";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Tailwind authors who want the roles as utilities additionally import the bridge stylesheet
|
|
20
|
+
(`@stridge/noctis-design-tokens/tokens.tailwind.css`).
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
// app root — keeps the root theme + elevation scopes in sync across theme changes
|
|
24
|
+
import { ThemeProvider } from "@stridge/noctis-design-tokens/react";
|
|
25
|
+
|
|
26
|
+
<ThemeProvider>{children}</ThemeProvider>;
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`SEMANTIC_ROLES` and `ELEVATION_SCOPES` export the catalog as data (for the debug swatch
|
|
30
|
+
page); `defaultThemeCss()` returns the build-time default `:root` CSS; `applyThemeWithScopes`
|
|
31
|
+
applies a theme + both scopes to an element.
|
|
32
|
+
|
|
33
|
+
## Token grammar
|
|
34
|
+
|
|
35
|
+
Every token serializes to a canonical CSS custom property under one closed grammar. The
|
|
36
|
+
`{category}` segment is drawn from the structural-category vocabulary, never written into the
|
|
37
|
+
id; `cssVarName` composes the namespace, tier, and category segments around the serialized
|
|
38
|
+
name body.
|
|
39
|
+
|
|
40
|
+
| Form | Stratum | Shape |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| Foundation | `foundation` | `--noctis-{category}-{name}` |
|
|
43
|
+
| Semantic | `semantic` | `--noctis-{category}-{name}`, and for color roles specifically `--noctis-color-{role}` |
|
|
44
|
+
| Seed | `seed` | `--noctis-seed-{name}` |
|
|
45
|
+
| Component mint | `component` | `--noctis-{component}(-{anatomy})-{property}(-{state})` |
|
|
46
|
+
| Slot internal | (recipe) | `--_{component}-*` |
|
|
47
|
+
|
|
48
|
+
Foundation and semantic tokens carry a structural category; seeds and component mints do not.
|
|
49
|
+
Semantic tokens are always category `color`, so a semantic role serializes as
|
|
50
|
+
`--noctis-color-{role}`. A component mint omits any segment it lacks, in fixed order
|
|
51
|
+
(`component` → `anatomy` → `property` → `state`); the rest (no-state) form drops the trailing
|
|
52
|
+
state segment. Slot internals live in the `--_` namespace a recipe declares on its slot to
|
|
53
|
+
carry the resolution chain.
|
|
54
|
+
|
|
55
|
+
The 18 structural categories (`TOKEN_CATEGORIES`):
|
|
56
|
+
|
|
57
|
+
`color` · `space` · `size` · `text` · `leading` · `radius` · `shadow` · `duration` · `ease` ·
|
|
58
|
+
`z` · `font` · `tracking` · `breakpoint` · `container` · `border` · `opacity` · `blur` ·
|
|
59
|
+
`animate`.
|
|
60
|
+
|
|
61
|
+
## Namespace contract
|
|
62
|
+
|
|
63
|
+
Every canonical token serializes under the `--noctis` prefix (`ROLE_VAR_PREFIX`).
|
|
64
|
+
|
|
65
|
+
`--noctis-engine-*` is the engine's **reserved private namespace**. The graph validator
|
|
66
|
+
rejects any graph token whose canonical name serializes into it — the engine owns that
|
|
67
|
+
namespace for its primitive ramp, and no foundation, semantic, seed, or component token may
|
|
68
|
+
collide with it.
|
|
69
|
+
|
|
70
|
+
Canonical names are consumed through the **bridge**: via the Tailwind bridge utilities the
|
|
71
|
+
generator emits (`bg-*`, `text-*`, `border-*`, the named `shadow-*`, the scale keys), or, in a
|
|
72
|
+
recipe, via a minted `--_` internal. A recipe never references the canonical literal directly —
|
|
73
|
+
that boundary is enforced by `stridge/banned-namespaces`.
|
|
74
|
+
|
|
75
|
+
## Role catalog
|
|
76
|
+
|
|
77
|
+
Each role is a Tailwind utility backed by one engine primitive. The default Tailwind palette
|
|
78
|
+
is disabled, so these are the only colors available.
|
|
79
|
+
|
|
80
|
+
### Surfaces
|
|
81
|
+
|
|
82
|
+
| Utility | Role |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `bg-background` | App canvas |
|
|
85
|
+
| `bg-hover` | Hover on a canvas row |
|
|
86
|
+
| `bg-surface` / `bg-surface-hover` | Card / panel + its hover |
|
|
87
|
+
| `bg-surface-raised` | Highest neutral surface |
|
|
88
|
+
| `bg-sunken` | Recessed wells |
|
|
89
|
+
| `bg-selected` / `bg-selected-hover` | Selected row + its hover |
|
|
90
|
+
| `bg-focus` | Keyboard-focused row |
|
|
91
|
+
| `bg-overlay` | Dialog scrim |
|
|
92
|
+
| `bg-sidebar-item` / `bg-sidebar-item-active` | Sidebar item hover / active |
|
|
93
|
+
|
|
94
|
+
### Text
|
|
95
|
+
|
|
96
|
+
`text-foreground` (primary) · `text-muted` (secondary) · `text-subtle` (faint) · `text-link`.
|
|
97
|
+
|
|
98
|
+
### Borders & ring
|
|
99
|
+
|
|
100
|
+
`border-faint` · `border-border` (default) · `border-strong` · `border-selected` ·
|
|
101
|
+
`border-field` · `bg-divider` / `border-divider` · `ring-ring`.
|
|
102
|
+
|
|
103
|
+
### Primary
|
|
104
|
+
|
|
105
|
+
The neutral (white) emphasis, decoupled from the chromatic accent: `bg-primary` ·
|
|
106
|
+
`text-primary-foreground` · `bg-primary-hover` / `bg-primary-active` (the white dimmed toward the
|
|
107
|
+
seed — real opaque tokens that re-derive per elevation, never a translucent white).
|
|
108
|
+
|
|
109
|
+
### Accent
|
|
110
|
+
|
|
111
|
+
`bg-accent` · `text-accent-foreground` · `bg-accent-hover` · `bg-accent-active` ·
|
|
112
|
+
`bg-accent-muted`.
|
|
113
|
+
|
|
114
|
+
### Controls & fields
|
|
115
|
+
|
|
116
|
+
Controls are a derived neutral tier off the seed (their own gentle gain), so each step is a solid
|
|
117
|
+
fill — not an opacity wash — and re-derives inside every elevation scope:
|
|
118
|
+
|
|
119
|
+
`bg-control` + `text-control-foreground` / `bg-control-hover` / `bg-control-selected` /
|
|
120
|
+
`bg-control-selected-hover` (secondary buttons, segmented) · `bg-control-ghost` /
|
|
121
|
+
`bg-control-ghost-hover` / `bg-control-ghost-selected` / `bg-control-ghost-selected-hover` (ghost
|
|
122
|
+
buttons, tabs, menu items) · `bg-field` / `bg-field-hover` / `bg-field-focus` + `border-field`
|
|
123
|
+
(inputs). Filled chromatic controls take a desaturated on-fill label (`text-accent-foreground`,
|
|
124
|
+
`text-danger-foreground`); disabled controls dim with `opacity-disabled`, never a color swap.
|
|
125
|
+
|
|
126
|
+
### Status
|
|
127
|
+
|
|
128
|
+
For `danger` / `success` / `warning` / `info`: `bg-*` (fill), `text-*-foreground` (on-fill),
|
|
129
|
+
`bg-*-muted` (soft surface), `text-*-muted-foreground` (on-muted).
|
|
130
|
+
|
|
131
|
+
### Shadows & type
|
|
132
|
+
|
|
133
|
+
`shadow-card` / `shadow-popover` / `shadow-modal` / `shadow-inset`; the named size scale
|
|
134
|
+
`text-micro … text-title-1` (all scaled live by the root `--noctis-seed-font-scale` multiplier); families
|
|
135
|
+
`font-sans` / `font-mono`; the radius scale `rounded-xs … rounded-xl` (`min()`-capped surfaces) plus
|
|
136
|
+
`rounded-control` (buttons/chips — follows the `--noctis-seed-radius` knob uncapped, so it pills at the Pill
|
|
137
|
+
setting) and `rounded-full` (circles); `ease-standard|in|out|in-out`.
|
|
138
|
+
|
|
139
|
+
## Elevation scopes
|
|
140
|
+
|
|
141
|
+
A scope is a full re-generation of the theme at a shifted base lightness — text re-solves its
|
|
142
|
+
contrast and borders re-derive — so a raised surface is a genuinely different, internally
|
|
143
|
+
consistent color, not a tint. Set a `data-elevation` attribute; everything inside keeps using
|
|
144
|
+
the normal roles and resolves to that scope:
|
|
145
|
+
|
|
146
|
+
- `data-elevation="elevated"` — dialogs, sheets, drawers, popovers, tooltips.
|
|
147
|
+
- `data-elevation="menu"` — the highest float: dropdown and context menus, select listboxes, the command palette (lifts a touch more than `elevated`).
|
|
148
|
+
- `data-elevation="sunken"` — recessed content wells and insets.
|
|
149
|
+
|
|
150
|
+
Page-level chrome (header, sidebar, rail) stays at the **root** level — no scope — so it sits flush with
|
|
151
|
+
the canvas it frames, set off by a border. Only overlays float (`elevated`/`menu`) and only wells recede (`sunken`).
|
|
152
|
+
|
|
153
|
+
**Portals** overlay to `<body>`, so set `data-elevation` on the **portalled node itself**
|
|
154
|
+
(`Popover.Popup`, `Menu.Popup`, …), not a JSX ancestor. Scopes are **absolute and
|
|
155
|
+
single-level** — computed from the active theme's base, they do not compound when nested.
|
|
156
|
+
|
|
157
|
+
**Paint a control-hosting elevated surface with `bg-background`, not `bg-surface`.** Controls
|
|
158
|
+
derive off their scope's *base* (`bg-1`), so a ghost or secondary control only separates from the
|
|
159
|
+
surface it sits on when that surface **is** the scope base. A dialog, sheet, rail, or menu therefore
|
|
160
|
+
uses `bg-background` inside its `data-elevation` scope (the scope's lift, border, and shadow give it
|
|
161
|
+
presence) — then a ghost button's hover clears the panel by the full control delta. `bg-surface`
|
|
162
|
+
(`bg-3`) is for **non-interactive** raised content (cards, wells); a ghost control placed on it would
|
|
163
|
+
hover almost invisibly. The invariant: an elevated surface that hosts controls paints its
|
|
164
|
+
elevation's own base, and controls re-derive off that same base — so surface and control can never
|
|
165
|
+
drift apart.
|
|
166
|
+
|
|
167
|
+
## Component consumption contract
|
|
168
|
+
|
|
169
|
+
Every planned surface is expressible with roles alone:
|
|
170
|
+
|
|
171
|
+
- **Card / Panel:** `bg-surface border border-border shadow-card`; clickable → `hover:bg-surface-hover`.
|
|
172
|
+
- **Input / Textarea / Select:** `bg-field border border-field shadow-inset`; hover → `hover:bg-field-hover hover:border-field-hover`; focus → `bg-field-focus focus-visible:ring ring-ring border-field-focus`; invalid → `border-field-invalid`.
|
|
173
|
+
- **Button — primary (neutral white):** `bg-primary text-primary-foreground hover:bg-primary-hover active:bg-primary-active`.
|
|
174
|
+
- **Button — accent:** `bg-accent text-accent-foreground hover:bg-accent-hover active:bg-accent-active`.
|
|
175
|
+
- **Button — secondary:** `bg-control text-control-foreground border border-border hover:bg-control-hover`; pressed → `bg-control-selected`.
|
|
176
|
+
- **Button — ghost / Tab / Menu item:** `bg-control-ghost text-muted hover:bg-control-ghost-hover hover:text-foreground`; active → `bg-control-ghost-selected`.
|
|
177
|
+
- **Menu / Select content:** portalled `data-elevation="menu"`, `bg-background border border-border shadow-popover`; items use ghost-control roles; keyboard item → `bg-focus`.
|
|
178
|
+
- **Popover:** `data-elevation="elevated"` + `bg-background border-border shadow-popover` (control-hosting; a pure-content popover may use `bg-surface`).
|
|
179
|
+
- **Dialog / Drawer / Sheet:** scrim `bg-overlay`; panel `data-elevation="elevated"` `bg-background border-border shadow-modal`.
|
|
180
|
+
- **Sidebar / Rail:** page chrome at the root level — `bg-background` set off by a border (no `data-elevation`); items `hover:bg-sidebar-item` or ghost-control roles, active → `bg-sidebar-item-active text-foreground`.
|
|
181
|
+
- **Table rows:** `hover:bg-surface-hover`; selected `bg-selected`, selected+hover `bg-selected-hover`, keyboard `bg-focus`.
|
|
182
|
+
- **Separator:** the standalone hairline fills from the neutral `border` role; heavier group dividers drawn _inside_ a menu/list step up to `divider`.
|
|
183
|
+
|
|
184
|
+
## Status families
|
|
185
|
+
|
|
186
|
+
Each of `danger` / `success` / `warning` / `info` exposes a complete sub-role set: `bg-<s>`
|
|
187
|
+
(solid fill) · `text-<s>` (colored text on neutral) · `text-<s>-foreground` (on-fill text) ·
|
|
188
|
+
`bg-<s>-hover` · `bg-<s>-muted` + `text-<s>-muted-foreground` (soft surface) · `bg-<s>-faint`
|
|
189
|
+
(row wash) · `border-<s>` (solid outline) · `border-<s>-subtle` (muted-callout outline). A
|
|
190
|
+
status-tint **gradient** (`bg-<s>-gradient`, faint hue → neutral) backs "In review" / "On
|
|
191
|
+
hold" status cards. Destructive button: `bg-danger hover:bg-danger-hover text-danger-foreground`.
|
|
192
|
+
|
|
193
|
+
## Charts & avatars (static, accent-independent)
|
|
194
|
+
|
|
195
|
+
Chart and avatar palettes are **authored, not engine-derived** — categorical identity must
|
|
196
|
+
stay stable when the accent changes, so they do **not** re-theme. They carry light and dark
|
|
197
|
+
values and switch on the resolved mode (`data-theme`).
|
|
198
|
+
|
|
199
|
+
- **Charts:** `bg-chart-1` … `bg-chart-8` (categorical series, hue- and lightness-separated
|
|
200
|
+
for color-vision-deficiency safety) · `text-chart-positive` / `text-chart-negative` /
|
|
201
|
+
`text-chart-neutral` (= success / danger / muted) · `border-chart-grid` · `text-chart-axis`
|
|
202
|
+
· `bg-chart-track` · `bg-chart-tooltip`.
|
|
203
|
+
- **Avatars:** `bg-avatar-1` … `bg-avatar-10` chosen by `avatarIndex(id)` (a stable hash);
|
|
204
|
+
`text-avatar-foreground` is the knockout for initials.
|
|
205
|
+
|
|
206
|
+
## States: disabled, inverse, fields, forms
|
|
207
|
+
|
|
208
|
+
- **Disabled = opacity, not a color family.** Apply `opacity-disabled` (the `--noctis-opacity-disabled`
|
|
209
|
+
scalar) to disabled controls. `text-disabled` is the one explicit disabled color, for text
|
|
210
|
+
that must stay legible where dimming the whole element is wrong.
|
|
211
|
+
- **Inverse:** `bg-inverse` + `text-inverse` for inverted chips/snackbars; tooltips reuse the
|
|
212
|
+
same `bg-inverse` + `text-inverse` — there is **no** dedicated tooltip color role.
|
|
213
|
+
- **Fields:** `bg-field border border-field`; state fills `bg-field-hover` (rest hover) and
|
|
214
|
+
`bg-field-focus` (accent-tinted focus surface); state borders `border-field-hover`,
|
|
215
|
+
`border-field-focus`, `border-field-invalid`.
|
|
216
|
+
- **Form elements:** `bg-toggle-track-{off,on}` (+ hover; the on-track stays full accent when
|
|
217
|
+
disabled) + `bg-toggle-thumb`; `bg-checkbox` + `border-checkbox` (+`-hover`) + `bg-checkbox-checked`
|
|
218
|
+
+ `text-checkbox-check`; `bg-radio-checked` + `border-radio`.
|
|
219
|
+
- **Chrome / utilities:** `bg-header`; `bg-scrollbar-thumb` / `bg-scrollbar-track`;
|
|
220
|
+
`bg-code` + `text-code-foreground`; `bg-kbd` + `border-kbd`; `text-menu-shortcut`;
|
|
221
|
+
`bg-data-grid-header` / `bg-data-grid-row-hover(-strong)` / `border-data-grid` /
|
|
222
|
+
`border-data-grid-selected`; `shadow-focus`.
|
|
223
|
+
|
|
224
|
+
`SEMANTIC_ROLES` (engine-backed) and `STATIC_TOKENS` (authored) export the full catalog as
|
|
225
|
+
data; the docs site's `/foundations/tokens` page renders the full token graph — every scale,
|
|
226
|
+
role, and component token.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GenerateThemeOptions, ThemeInput } from "@stridge/noctis-theme-engine";
|
|
2
|
+
|
|
3
|
+
//#region src/apply-scopes.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generate `input` and emit it — root primitives plus the elevated/menu/sunken scope namespaces —
|
|
6
|
+
* for `root` (default the document element), as one rule in the engine layer. `options.overrides`
|
|
7
|
+
* thread into every set: root entries participate in the root derivation and shift the scope
|
|
8
|
+
* bases; scope-qualified entries (`"el-bg-3"`) act inside their scope's generation only.
|
|
9
|
+
*/
|
|
10
|
+
declare function applyThemeWithScopes(input: ThemeInput, root?: Element, options?: GenerateThemeOptions): void;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { applyThemeWithScopes };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { applyEngineVars, generateScopeTheme, generateTheme, scopedEngineVar } from "@stridge/noctis-theme-engine";
|
|
2
|
+
//#region src/apply-scopes.ts
|
|
3
|
+
/**
|
|
4
|
+
* Runtime theme application with elevation scopes.
|
|
5
|
+
*
|
|
6
|
+
* Emits the root primitives plus the `elevated` (`--noctis-engine-el-*`), `menu`
|
|
7
|
+
* (`--noctis-engine-mn-*`), and `sunken` (`--noctis-engine-su-*`) scope sets for a single target
|
|
8
|
+
* (default `:root`) through the per-document engine sheet, inside `@layer noctis.engine`. One
|
|
9
|
+
* root write re-themes every `[data-elevation]` subtree through the static indirection in
|
|
10
|
+
* `tokens.css` — no per-element work, so any number of dynamically-mounted overlays stay correct
|
|
11
|
+
* across a theme change.
|
|
12
|
+
*/
|
|
13
|
+
function addNamespaced(vars, map, prefix) {
|
|
14
|
+
for (const key in map) vars[scopedEngineVar(key, prefix)] = map[key];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate `input` and emit it — root primitives plus the elevated/menu/sunken scope namespaces —
|
|
18
|
+
* for `root` (default the document element), as one rule in the engine layer. `options.overrides`
|
|
19
|
+
* thread into every set: root entries participate in the root derivation and shift the scope
|
|
20
|
+
* bases; scope-qualified entries (`"el-bg-3"`) act inside their scope's generation only.
|
|
21
|
+
*/
|
|
22
|
+
function applyThemeWithScopes(input, root, options) {
|
|
23
|
+
const vars = { ...generateTheme(input, options) };
|
|
24
|
+
addNamespaced(vars, generateScopeTheme(input, "elevated", options), "el");
|
|
25
|
+
addNamespaced(vars, generateScopeTheme(input, "menu", options), "mn");
|
|
26
|
+
addNamespaced(vars, generateScopeTheme(input, "sunken", options), "su");
|
|
27
|
+
applyEngineVars(vars, root);
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { applyThemeWithScopes };
|
package/dist/css.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GenerateThemeOptions } from "@stridge/noctis-theme-engine";
|
|
2
|
+
|
|
3
|
+
//#region src/css.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The default theme's engine primitives — root plus the elevated/menu/sunken scopes — as a
|
|
6
|
+
* static rule inside `@layer noctis.engine`.
|
|
7
|
+
*/
|
|
8
|
+
declare function defaultThemeCss(selector?: string, options?: GenerateThemeOptions): string;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { defaultThemeCss };
|
package/dist/css.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ENGINE_LAYER, declarationsFor, defaultPreset, generateScopeTheme, generateTheme, scopedEngineVar } from "@stridge/noctis-theme-engine";
|
|
2
|
+
//#region src/css.ts
|
|
3
|
+
/**
|
|
4
|
+
* Build-time default theme CSS.
|
|
5
|
+
*
|
|
6
|
+
* Emits the default brand theme's primitive variables as a static `:root` rule so the app's
|
|
7
|
+
* first paint is correct with zero JavaScript. Alongside the root primitives it emits the
|
|
8
|
+
* `elevated`, `menu`, and `sunken` scope sets under the `--noctis-engine-el-*` /
|
|
9
|
+
* `--noctis-engine-mn-*` / `--noctis-engine-su-*` namespaces; the `[data-elevation]` selectors in
|
|
10
|
+
* `tokens.css` re-point the base roles to these, so raised, floating, and recessed surfaces are
|
|
11
|
+
* correct on first paint too. Rendered into the document head by the app layout.
|
|
12
|
+
*
|
|
13
|
+
* The rule lives in `@layer noctis.engine` — the same layer the runtime sheet declares into — so
|
|
14
|
+
* SSR and CSR emission carry identical names, values, and cascade position, and any unlayered
|
|
15
|
+
* author rule on an engine variable beats both. A cascade override replaces one variable's value
|
|
16
|
+
* only; dependents do not re-derive (pass `overrides` for derivation-participating overrides).
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Serialize a theme map with the scope-set namespace
|
|
20
|
+
* (`--noctis-engine-bg-1` → `--noctis-engine-el-bg-1`). Routes through {@link scopedEngineVar} so
|
|
21
|
+
* the static first-paint names match the runtime writer and the `tokens.css` scope blocks exactly.
|
|
22
|
+
*/
|
|
23
|
+
function namespaced(map, prefix) {
|
|
24
|
+
let out = "";
|
|
25
|
+
for (const key in map) out += `${scopedEngineVar(key, prefix)}:${map[key]};`;
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The default theme's engine primitives — root plus the elevated/menu/sunken scopes — as a
|
|
30
|
+
* static rule inside `@layer noctis.engine`.
|
|
31
|
+
*/
|
|
32
|
+
function defaultThemeCss(selector = ":root", options) {
|
|
33
|
+
return `@layer ${ENGINE_LAYER}{${selector}{${declarationsFor(generateTheme(defaultPreset, options))}${namespaced(generateScopeTheme(defaultPreset, "elevated", options), "el")}${namespaced(generateScopeTheme(defaultPreset, "menu", options), "mn")}${namespaced(generateScopeTheme(defaultPreset, "sunken", options), "su")}}}`;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { defaultThemeCss };
|