@pantoken/css 0.3.11 → 0.4.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pantoken/css",
3
- "version": "0.3.11",
3
+ "version": "0.4.1",
4
4
  "description": "Emit Instructure design tokens as @property-typed CSS with light-dark() and icon data-URIs, from the pantoken IR.",
5
5
  "homepage": "https://pantoken.app",
6
6
  "bugs": "https://github.com/thedannywahl/pantoken/issues",
@@ -28,6 +28,11 @@
28
28
  "./style.canvas.lean.css": "./dist/style.canvas.lean.css",
29
29
  "./style.canvas-high-contrast.css": "./dist/style.canvas-high-contrast.css",
30
30
  "./style.canvas-high-contrast.lean.css": "./dist/style.canvas-high-contrast.lean.css",
31
+ "./properties.css": "./dist/properties.css",
32
+ "./properties.lean.css": "./dist/properties.lean.css",
33
+ "./scope.css": "./dist/scope.css",
34
+ "./scope.lean.css": "./dist/scope.lean.css",
35
+ "./schemes.css": "./dist/schemes.css",
31
36
  "./package.json": "./package.json"
32
37
  },
33
38
  "publishConfig": {
@@ -35,17 +40,17 @@
35
40
  "provenance": true
36
41
  },
37
42
  "dependencies": {
38
- "@pantoken/model": "0.4.0",
39
- "@pantoken/plugin-kit": "0.3.1",
40
- "@pantoken/tokens": "0.5.0",
41
- "@pantoken/utils": "1.0.3"
43
+ "@pantoken/model": "0.5.0",
44
+ "@pantoken/plugin-kit": "0.3.3",
45
+ "@pantoken/tokens": "0.7.0",
46
+ "@pantoken/utils": "1.2.0"
42
47
  },
43
48
  "devDependencies": {
44
49
  "@pantoken/plugin-props-minify": "0.1.4",
45
- "@types/node": "^26.5.1",
50
+ "@types/node": "^26.6.3",
46
51
  "typescript": "^7.0.2",
47
- "vite": "npm:@voidzero-dev/vite-plus-core@0.3.2",
48
- "vite-plus": "0.3.2"
52
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.0.0-rc.0",
53
+ "vite-plus": "1.0.0-rc.0"
49
54
  },
50
55
  "engines": {
51
56
  "node": ">=22.18.0"
@@ -1,257 +0,0 @@
1
- import { checkPlugins, definePlugin } from "@pantoken/plugin-kit";
2
- import { elevationDeclarations, focusOutlineDeclarations } from "@pantoken/utils";
3
- import { byTheme } from "@pantoken/tokens";
4
- //#region src/foundation.ts
5
- /**
6
- * The elevation (`--instui-elevation-*`) and focus-outline (`--instui-focus-outline-*`) composite
7
- * custom properties shared by the ready-made token sheets and docs-only themed token sheet.
8
- */
9
- const foundationPlugin = definePlugin({
10
- name: "pantoken-foundation",
11
- css: () => ({
12
- marker: "pantoken foundation — elevation + focus-outline custom properties",
13
- declarations: [...elevationDeclarations(), ...focusOutlineDeclarations()]
14
- })
15
- });
16
- //#endregion
17
- //#region src/theme-variants.ts
18
- const ICON_TOKEN_PREFIX = "--instui-icon-";
19
- function withoutIcons(tokens) {
20
- return tokens.filter((t) => !t.name.startsWith(ICON_TOKEN_PREFIX));
21
- }
22
- function lightBranch(value) {
23
- const trimmed = value.trim();
24
- if (!trimmed.startsWith("light-dark(") || !trimmed.endsWith(")")) return null;
25
- const inner = trimmed.slice(11, -1);
26
- let depth = 0;
27
- for (let i = 0; i < inner.length; i += 1) {
28
- const char = inner[i];
29
- if (char === "(") depth += 1;
30
- else if (char === ")") depth = Math.max(0, depth - 1);
31
- else if (char === "," && depth === 0) return inner.slice(0, i).trim();
32
- }
33
- return null;
34
- }
35
- function rebrandLightOnly(tokens) {
36
- return tokens.map((token) => {
37
- const light = lightBranch(token.value);
38
- if (!light) return token;
39
- return {
40
- ...token,
41
- value: light,
42
- themed: false
43
- };
44
- });
45
- }
46
- /** Build a theme token set with optional icon removal and rebrand light-only collapse. */
47
- function themedTokens(theme, options) {
48
- const { includeIcons = true, lightOnly = false } = options ?? {};
49
- const themeTokens = byTheme(theme);
50
- const modeTokens = lightOnly ? rebrandLightOnly(themeTokens) : themeTokens;
51
- return includeIcons ? modeTokens : withoutIcons(modeTokens);
52
- }
53
- //#endregion
54
- //#region src/emit.ts
55
- function renderSection(scope, { layer, pairs }) {
56
- const declarations = [
57
- ` ${scope} {`,
58
- ...pairs.map(([name, val]) => ` ${name}: ${val.trim()};`),
59
- " }"
60
- ];
61
- return layer ? [
62
- `@layer ${layer} {`,
63
- ...declarations,
64
- "}"
65
- ].join("\n") : declarations.join("\n");
66
- }
67
- function renderProperty({ name, syntax, value }, inherits) {
68
- return [
69
- `@property ${name} {`,
70
- ` syntax: "${syntax}";`,
71
- ` inherits: ${inherits};`,
72
- ` initial-value: ${value.trim()};`,
73
- `}`
74
- ].join("\n");
75
- }
76
- /**
77
- * Build a CSS file string: typed `@property` registrations (top-level, theme-agnostic) followed by
78
- * one or more scoped declaration sections (whose selector the consuming build may rewrite).
79
- *
80
- * @example Register one typed property and emit a scoped declaration
81
- * ```ts
82
- * import { buildCssFile } from "@pantoken/css";
83
- *
84
- * buildCssFile({
85
- * comments: ["/* my tokens *\/"],
86
- * scope: ":root",
87
- * properties: [{ name: "--instui-color-brand", syntax: "<color>", value: "#0374b5" }],
88
- * sections: [{ pairs: [["--instui-color-text-base", "var(--instui-color-brand)"]] }],
89
- * });
90
- * ```
91
- *
92
- * @example Wrap a section in a CSS cascade layer
93
- * ```ts
94
- * import { buildCssFile } from "@pantoken/css";
95
- *
96
- * buildCssFile({
97
- * comments: [],
98
- * scope: ":root",
99
- * sections: [{ layer: "pantoken", pairs: [["--instui-spacing-space-md", "1rem"]] }],
100
- * });
101
- * ```
102
- */
103
- function buildCssFile({ comments, scope, properties = [], sections, inherits = true }) {
104
- const blocks = [properties.map((p) => renderProperty(p, inherits)).join("\n\n"), ...sections.filter((s) => s.pairs.length > 0).map((s) => renderSection(scope, s))].filter(Boolean);
105
- return [
106
- `/* DO NOT EDIT — generated by @pantoken/css */`,
107
- "",
108
- ...comments,
109
- "",
110
- ...blocks,
111
- ""
112
- ].join("\n");
113
- }
114
- //#endregion
115
- //#region src/to-css.ts
116
- /**
117
- * `toCss` — turn the token IR into CSS: concrete tokens become typed `@property` registrations,
118
- * themed/reference tokens become scoped declarations. Plugins can contribute or post-process CSS.
119
- *
120
- * @module
121
- */
122
- /** True when a value cannot be a typed `@property` initial-value (`var()` / `light-dark()`). */
123
- function isContextual(value) {
124
- return /var\(|light-dark\(/.test(value);
125
- }
126
- function marked(marker, css) {
127
- return marker ? `/* ${marker} */\n${css}` : css;
128
- }
129
- /**
130
- * Emit CSS for a token IR.
131
- *
132
- * @param tokens - The IR (e.g. from `@pantoken/tokens`).
133
- * @param options - {@link ToCssOptions}.
134
- * @returns The CSS string.
135
- *
136
- * @example Build the default stylesheet
137
- * ```ts
138
- * import { toCss } from "@pantoken/css";
139
- * import { tokens } from "@pantoken/tokens";
140
- *
141
- * const stylesheet = toCss(tokens); // declarations under :root
142
- * ```
143
- *
144
- * @example Scope declarations to a class and build another theme
145
- * ```ts
146
- * import { toCss } from "@pantoken/css";
147
- * import { byTheme } from "@pantoken/tokens";
148
- *
149
- * toCss(byTheme("canvas"), { scope: '[class*="instui"]' });
150
- * ```
151
- *
152
- * @example Post-process with a plugin css hook
153
- * ```ts
154
- * import { toCss } from "@pantoken/css";
155
- * import { tokens } from "@pantoken/tokens";
156
- *
157
- * toCss(tokens, {
158
- * plugins: [
159
- * {
160
- * name: "focus",
161
- * css: () => ({ append: ":focus-visible { outline: 2px solid var(--instui-focus-color); }" }),
162
- * },
163
- * ],
164
- * });
165
- * ```
166
- */
167
- function toCss(tokens, options = {}) {
168
- const { scope = ":root", plugins = [] } = options;
169
- const properties = [];
170
- const declarations = [];
171
- for (const token of tokens) if (isContextual(token.value)) declarations.push([token.name, token.value]);
172
- else properties.push({
173
- name: token.name,
174
- syntax: token.syntax,
175
- value: token.value
176
- });
177
- let css = buildCssFile({
178
- comments: ["/* Instructure design tokens + icon set (pantoken) */", "/* Concrete tokens are registered with @property; themed/reference tokens are declarations. */"],
179
- scope,
180
- properties,
181
- sections: [{ pairs: declarations }]
182
- });
183
- const prepends = [];
184
- const appends = [];
185
- for (const plugin of checkPlugins(plugins, "css")) {
186
- const c = plugin.css?.({
187
- tokens,
188
- css
189
- });
190
- if (!c) continue;
191
- appendContribution(c, prepends, appends);
192
- }
193
- return [
194
- ...prepends,
195
- css,
196
- ...appends
197
- ].filter(Boolean).join("\n\n");
198
- }
199
- function appendContribution(c, prepends, appends) {
200
- if (c.prepend) prepends.push(marked(c.marker, c.prepend));
201
- const typedProps = [];
202
- const declPairs = [...c.declarations ?? []];
203
- for (const p of c.properties ?? []) if (isContextual(p.value)) declPairs.push([p.name, p.value]);
204
- else typedProps.push(p);
205
- const block = [
206
- typedProps.map((p) => `@property ${p.name} {\n syntax: "${p.syntax}";\n inherits: true;\n initial-value: ${p.value};\n}`).join("\n\n"),
207
- declPairs.length ? `:root {\n${declPairs.map(([n, v]) => ` ${n}: ${v};`).join("\n")}\n}` : "",
208
- c.append
209
- ].filter(Boolean).join("\n\n");
210
- if (block) appends.push(marked(c.marker, block));
211
- }
212
- //#endregion
213
- //#region src/index.ts
214
- /**
215
- * `@pantoken/css` — emit Instructure design tokens as `@property`-typed CSS.
216
- *
217
- * {@link toCss} turns any token IR into CSS; {@link css} is the ready-made `rebrand` stylesheet and
218
- * {@link leanCss} is a lean variant that drops the full `--instui-icon-*` set (the ~1,777 icon data-URIs
219
- * that dominate the sheet) for CDN/embed delivery — ~a sixth the size over the wire. Both carry the
220
- * elevation + focus-outline foundation (composite custom properties whose pure builders live in
221
- * `@pantoken/utils`), so a component sheet resolves its shadows and focus ring against the token sheet
222
- * alone. A DOM side-effect entry lives at `@pantoken/css/inject`; static files at
223
- * `@pantoken/css/style.css` and `@pantoken/css/style.lean.css`.
224
- *
225
- * @module
226
- * @beta
227
- */
228
- function themedCss(theme, options) {
229
- return toCss(themedTokens(theme, options), { plugins: [foundationPlugin] });
230
- }
231
- /**
232
- * The ready-made `rebrand` stylesheet string (typed: concrete tokens as `@property` registrations).
233
- *
234
- * @example
235
- * ```ts
236
- * import { css } from "@pantoken/css";
237
- *
238
- * document.head.insertAdjacentHTML("beforeend", `<style>${css}</style>`);
239
- * ```
240
- */
241
- const css = themedCss("rebrand");
242
- /**
243
- * The lean `rebrand` stylesheet string — the full sheet minus the `--instui-icon-*` glyph tokens (the
244
- * ~1,777 icon data-URIs that make up most of {@link css}). Roughly a sixth the size over the wire; the
245
- * recommended foundation for CDN/embed delivery. Components reference only a handful of icons, shipped
246
- * separately as `@pantoken/components`'s `component-icons.css`; consumers who use `var(--instui-icon-*)`
247
- * broadly should load the full {@link css} (or the `icons.css` glyph sheet). See
248
- * `@pantoken/css/style.lean.css`.
249
- *
250
- * @example
251
- * ```ts
252
- * import { leanCss } from "@pantoken/css";
253
- * ```
254
- */
255
- const leanCss = toCss(themedTokens("rebrand", { includeIcons: false }), { plugins: [foundationPlugin] });
256
- //#endregion
257
- export { buildCssFile as i, leanCss as n, toCss as r, css as t };