@pie-players/pie-theme 0.3.65 → 0.3.66

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.
@@ -0,0 +1,168 @@
1
+ /**
2
+ * The one table that says which DaisyUI slot each `--pie-*` token comes from,
3
+ * and one renderer that turns it into variables.
4
+ *
5
+ * It exists because the same 47-row table was written out four times — the
6
+ * provider adapter here, two mappers in `@pie-players/pie-theme-daisyui`, and
7
+ * that package's `bridge.css` — and copies drift. Two defects lived in the drift:
8
+ * `--pie-missing` was corrected to `--color-warning` in one copy while three kept
9
+ * it on `--color-error`, and the parity test that was supposed to catch this
10
+ * compared only the token names, never the slot each one derived from.
11
+ *
12
+ * CSS cannot import a table, so `bridge.css` stays hand-written and is held to
13
+ * this one by `tests/daisyui-mapping-parity.test.mjs` instead.
14
+ */
15
+ import { LEGIBLE_NON_TEXT_MINIMUM, LEGIBLE_TEXT_MINIMUM, UNMEASURED_HUE_WEIGHT, UNMEASURED_NON_TEXT_HUE_WEIGHT, legibleColorAgainst, } from "./contrast.js";
16
+ export const DAISY_SLOT_CSS_VARIABLES = {
17
+ base100: "--color-base-100",
18
+ base200: "--color-base-200",
19
+ base300: "--color-base-300",
20
+ baseContent: "--color-base-content",
21
+ primary: "--color-primary",
22
+ secondary: "--color-secondary",
23
+ accent: "--color-accent",
24
+ neutral: "--color-neutral",
25
+ neutralContent: "--color-neutral-content",
26
+ success: "--color-success",
27
+ error: "--color-error",
28
+ warning: "--color-warning",
29
+ };
30
+ const legible = (token, from) => ({
31
+ token,
32
+ kind: "legible",
33
+ from,
34
+ minimum: LEGIBLE_TEXT_MINIMUM,
35
+ fallbackWeight: UNMEASURED_HUE_WEIGHT,
36
+ });
37
+ const boundary = (token, from) => ({
38
+ token,
39
+ kind: "legible",
40
+ from,
41
+ minimum: LEGIBLE_NON_TEXT_MINIMUM,
42
+ fallbackWeight: UNMEASURED_NON_TEXT_HUE_WEIGHT,
43
+ });
44
+ const direct = (token, from) => ({
45
+ token,
46
+ kind: "direct",
47
+ from,
48
+ });
49
+ const mix = (token, from, towards, weight) => ({ token, kind: "mix", from, towards, weight });
50
+ export const DAISYUI_PIE_TOKEN_MAP = [
51
+ direct("--pie-background", "base100"),
52
+ direct("--pie-background-dark", "base200"),
53
+ direct("--pie-secondary-background", "base200"),
54
+ direct("--pie-dropdown-background", "base300"),
55
+ direct("--pie-text", "baseContent"),
56
+ direct("--pie-primary", "primary"),
57
+ mix("--pie-primary-light", "primary", "base100", 60),
58
+ mix("--pie-primary-dark", "primary", "baseContent", 75),
59
+ mix("--pie-faded-primary", "primary", "base100", 20),
60
+ direct("--pie-secondary", "secondary"),
61
+ mix("--pie-secondary-light", "secondary", "base100", 60),
62
+ mix("--pie-secondary-dark", "secondary", "baseContent", 75),
63
+ direct("--pie-tertiary", "accent"),
64
+ mix("--pie-tertiary-light", "accent", "base100", 60),
65
+ // Boundaries. `--color-base-300` is a surface tint, so an outline painted with
66
+ // it sits at 1.09:1 to 1.53:1 across the shipped themes against the 3:1 SC
67
+ // 1.4.11 asks -- and since `--pie-button-bg` is `--color-base-100`, the page's
68
+ // own colour, that outline is the only thing separating a button from the page.
69
+ boundary("--pie-border", "base300"),
70
+ // Not corrected: the players use this one for card edges and pane dividers,
71
+ // which 1.4.11 exempts, and a 3:1 outline around every item card would be a
72
+ // visual regression rather than a fix.
73
+ direct("--pie-border-light", "base200"),
74
+ boundary("--pie-border-dark", "neutral"),
75
+ boundary("--pie-border-gray", "base300"),
76
+ // Foregrounds. DaisyUI's semantic slots are chosen to sit behind their
77
+ // `-content` counterparts; PIE paints these as `color:`.
78
+ legible("--pie-correct", "success"),
79
+ mix("--pie-correct-secondary", "success", "base100", 20),
80
+ legible("--pie-correct-tertiary", "success"),
81
+ legible("--pie-correct-icon", "success"),
82
+ // Authored red emphasis inside content. Taken from the error slot through the
83
+ // legible correction rather than mixed from a bare red: a red-toward-ink mix
84
+ // falls under 4.5:1 on seven of the 35 shipped themes (2.91:1 on `aqua`),
85
+ // while the corrected error family clears it on all of them.
86
+ legible("--pie-content-emphasis", "error"),
87
+ legible("--pie-incorrect", "error"),
88
+ mix("--pie-incorrect-secondary", "error", "base100", 20),
89
+ legible("--pie-incorrect-icon", "error"),
90
+ // Warning, not error: an unanswered question is not a wrong one, and both on
91
+ // `--color-error` made the two states the same colour in every theme. This is
92
+ // the mapping the rest of PIE declares -- pie-elements-ng keys `--pie-missing`
93
+ // to `warning`, and the assessment toolkit's `.pie-warning` rule paints it.
94
+ legible("--pie-missing", "warning"),
95
+ legible("--pie-missing-icon", "warning"),
96
+ direct("--pie-disabled", "base300"),
97
+ direct("--pie-disabled-secondary", "base200"),
98
+ mix("--pie-focus-checked", "primary", "base100", 20),
99
+ direct("--pie-focus-checked-border", "primary"),
100
+ direct("--pie-focus-unchecked", "base200"),
101
+ direct("--pie-focus-unchecked-border", "base300"),
102
+ direct("--pie-blue-grey-100", "base100"),
103
+ direct("--pie-blue-grey-300", "base200"),
104
+ direct("--pie-blue-grey-600", "base300"),
105
+ direct("--pie-blue-grey-900", "baseContent"),
106
+ direct("--pie-black", "neutralContent"),
107
+ direct("--pie-white", "base100"),
108
+ direct("--pie-button-bg", "base100"),
109
+ boundary("--pie-button-border", "base300"),
110
+ direct("--pie-button-color", "baseContent"),
111
+ direct("--pie-button-hover-bg", "base200"),
112
+ boundary("--pie-button-hover-border", "base300"),
113
+ direct("--pie-button-hover-color", "baseContent"),
114
+ // DaisyUI guarantees base-content against the page, not every deeper surface.
115
+ // `valentine` is 4.17:1 on base-300. A 70% share is the nearest 5% step
116
+ // toward base-100 that keeps the pair at 4.5:1 across all shipped themes.
117
+ mix("--pie-button-active-bg", "base300", "base100", 70),
118
+ // The keyboard focus indicator, and the one token here that is only ever an
119
+ // `outline` -- eight declarations across the tools, never a fill. It takes
120
+ // `--color-primary`, which DaisyUI pairs with `--color-primary-content` for
121
+ // fills rather than choosing for contrast against the page, so it inherited
122
+ // 1.90:1 in `business`. `--pie-primary` itself cannot be corrected the same
123
+ // way: PIE paints it as a foreground in some places and as a button fill in
124
+ // others, and a value legible against the page is the wrong one behind
125
+ // `--color-primary-content`.
126
+ boundary("--pie-button-focus-outline", "primary"),
127
+ ];
128
+ /**
129
+ * @param read one DaisyUI slot's value, or `undefined` when this source has none
130
+ * @param measure resolves a colour so `legible` entries can be corrected against
131
+ * a measured ratio. Omit it where the values are `var()` references rather than
132
+ * colours: those cannot be measured, and every `legible` entry then takes its
133
+ * pessimistic fixed weight instead.
134
+ */
135
+ export function resolveDaisyPieVariables(args) {
136
+ const { read, measure } = args;
137
+ const resolved = {};
138
+ for (const entry of DAISYUI_PIE_TOKEN_MAP) {
139
+ const from = read(entry.from);
140
+ if (!from) {
141
+ continue;
142
+ }
143
+ let value;
144
+ if (entry.kind === "direct") {
145
+ value = from;
146
+ }
147
+ else if (entry.kind === "mix") {
148
+ const towards = read(entry.towards);
149
+ value = towards
150
+ ? `color-mix(in srgb, ${from} ${entry.weight}%, ${towards})`
151
+ : undefined;
152
+ }
153
+ else {
154
+ value = legibleColorAgainst({
155
+ hue: from,
156
+ text: read("baseContent"),
157
+ background: read("base100"),
158
+ measure,
159
+ minimum: entry.minimum,
160
+ unmeasuredHueWeight: entry.fallbackWeight,
161
+ });
162
+ }
163
+ if (value) {
164
+ resolved[entry.token] = value;
165
+ }
166
+ }
167
+ return resolved;
168
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { PieThemeElement, definePieTheme } from "./theme-element.js";
2
2
  export { PieThemeElement, definePieTheme };
3
- export { DAISYUI_THEME_PROVIDER_ADAPTER, getPieThemeProvider, listPieThemeProviders, registerPieThemeProvider, resolveProviderVariables, unregisterPieThemeProvider, type ThemeProviderAdapter, } from "./providers.js";
4
- export { isThemeMode, isThemeScope, normalizePieThemeVariables, type ThemeMode, type ThemeScope, type ThemeVariables, } from "./theme-types.js";
5
- export { DARK_THEME_VARS, LIGHT_THEME_VARS } from "./theme-defaults.js";
6
- export { BUILTIN_PIE_COLOR_SCHEMES, getPieColorScheme, listPieColorSchemes, registerPieColorSchemes, resolvePieColorSchemeVariables, unregisterPieColorScheme, type PieColorSchemeDefinition, type PieColorSchemePreview, } from "./color-schemes.js";
3
+ export { DAISYUI_THEME_PROVIDER_ADAPTER, getPieThemeProvider, PIE_THEME_PROVIDER_NONE, listPieThemeProviders, registerPieThemeProvider, resolveProviderVariables, unregisterPieThemeProvider, type ThemeProviderAdapter, } from "./providers.js";
4
+ export { DAISY_SLOT_CSS_VARIABLES, DAISYUI_PIE_TOKEN_MAP, resolveDaisyPieVariables, type DaisyMappingEntry, type DaisySlot, } from "./daisyui-mapping.js";
5
+ export { createCanvasColorMeasure, type ColorMeasure, } from "./contrast.js";
6
+ export { isThemeMode, isThemeScope, normalizePieThemeVariables, type ColorSchemeSnapshot, type PieColorSchemeDescriptor, type PieColorSchemePreview, type PieThemeDiagnostic, type PieThemeDiagnosticCode, type PieThemeObserver, type PieThemeResolutionStatus, type RegisteredPieColorScheme, type RegistrationReceipt, type ResolvePieThemeInput, type ThemeResolution, type ThemeMode, type ThemeScope, type ThemeTokenName, type ThemeVariables, type Unsubscribe, } from "./theme-types.js";
7
+ export type { PieThemeSchemeParticipation, PieThemeTokenRegistry, PieThemeTokenRegistryEntry, PieThemeTokenScope, PieThemeTokenStatus, } from "./token-registry-types.js";
8
+ export { listPieColorSchemes, observePieColorSchemes, registerPieColorSchemes, resolvePieTheme, } from "./color-schemes.js";
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { PieThemeElement, definePieTheme } from "./theme-element.js";
2
2
  export { PieThemeElement, definePieTheme };
3
- export { DAISYUI_THEME_PROVIDER_ADAPTER, getPieThemeProvider, listPieThemeProviders, registerPieThemeProvider, resolveProviderVariables, unregisterPieThemeProvider, } from "./providers.js";
3
+ export { DAISYUI_THEME_PROVIDER_ADAPTER, getPieThemeProvider, PIE_THEME_PROVIDER_NONE, listPieThemeProviders, registerPieThemeProvider, resolveProviderVariables, unregisterPieThemeProvider, } from "./providers.js";
4
+ export { DAISY_SLOT_CSS_VARIABLES, DAISYUI_PIE_TOKEN_MAP, resolveDaisyPieVariables, } from "./daisyui-mapping.js";
5
+ export { createCanvasColorMeasure, } from "./contrast.js";
4
6
  export { isThemeMode, isThemeScope, normalizePieThemeVariables, } from "./theme-types.js";
5
- export { DARK_THEME_VARS, LIGHT_THEME_VARS } from "./theme-defaults.js";
6
- export { BUILTIN_PIE_COLOR_SCHEMES, getPieColorScheme, listPieColorSchemes, registerPieColorSchemes, resolvePieColorSchemeVariables, unregisterPieColorScheme, } from "./color-schemes.js";
7
+ export { listPieColorSchemes, observePieColorSchemes, registerPieColorSchemes, resolvePieTheme, } from "./color-schemes.js";
7
8
  definePieTheme();
@@ -4,9 +4,25 @@ export interface ThemeProviderAdapter {
4
4
  canRead(target: HTMLElement): boolean;
5
5
  read(target: HTMLElement): ThemeVariables;
6
6
  }
7
+ /**
8
+ * Provider mode that resolves nothing, leaving this package's shipped defaults
9
+ * in place.
10
+ *
11
+ * `"auto"` lets any registered adapter that can read the target win, which on a
12
+ * DaisyUI page means PIE tokens follow `--color-*`. This is how a host asks for
13
+ * the palette it would have had before adopting a provider — the first question
14
+ * to answer when colours differ between two environments.
15
+ *
16
+ * Distinct from naming an unregistered provider, which lands in the same place
17
+ * by accident. `unregisterPieThemeProvider` cannot remove this one because it is
18
+ * not in the registry at all, so the mode cannot be taken away from a host.
19
+ */
20
+ export declare const PIE_THEME_PROVIDER_NONE = "none";
7
21
  export declare const DAISYUI_THEME_PROVIDER_ADAPTER: ThemeProviderAdapter;
8
22
  export declare function registerPieThemeProvider(adapter: ThemeProviderAdapter): void;
9
23
  export declare function unregisterPieThemeProvider(providerId: string): void;
24
+ /** Package-internal invalidation used by connected pie-theme elements. */
25
+ export declare function observePieThemeProviders(listener: () => void): () => void;
10
26
  export declare function listPieThemeProviders(): ThemeProviderAdapter[];
11
27
  export declare function getPieThemeProvider(providerId: string): ThemeProviderAdapter | undefined;
12
28
  export declare function resolveProviderVariables(args: {
package/dist/providers.js CHANGED
@@ -1,102 +1,52 @@
1
+ import { createCanvasColorMeasure } from "./contrast.js";
2
+ import { DAISY_SLOT_CSS_VARIABLES, resolveDaisyPieVariables, } from "./daisyui-mapping.js";
1
3
  import { normalizePieThemeVariables, } from "./theme-types.js";
2
4
  const themeProviderRegistry = new Map();
5
+ const themeProviderObservers = new Set();
6
+ function notifyThemeProviderObservers() {
7
+ for (const listener of [...themeProviderObservers]) {
8
+ try {
9
+ listener();
10
+ }
11
+ catch {
12
+ console.warn("[pie-theme] A theme-provider observer threw while receiving an update.");
13
+ }
14
+ }
15
+ }
16
+ /**
17
+ * Provider mode that resolves nothing, leaving this package's shipped defaults
18
+ * in place.
19
+ *
20
+ * `"auto"` lets any registered adapter that can read the target win, which on a
21
+ * DaisyUI page means PIE tokens follow `--color-*`. This is how a host asks for
22
+ * the palette it would have had before adopting a provider — the first question
23
+ * to answer when colours differ between two environments.
24
+ *
25
+ * Distinct from naming an unregistered provider, which lands in the same place
26
+ * by accident. `unregisterPieThemeProvider` cannot remove this one because it is
27
+ * not in the registry at all, so the mode cannot be taken away from a host.
28
+ */
29
+ export const PIE_THEME_PROVIDER_NONE = "none";
3
30
  function trimCssVar(value) {
4
31
  const trimmed = value.trim();
5
32
  return trimmed ? trimmed : undefined;
6
33
  }
7
- function mixResolvedColors(args) {
8
- if (!args.left || !args.right) {
9
- return undefined;
34
+ let cachedColorMeasure;
35
+ /**
36
+ * One measurer for the lifetime of the page. Parsing a colour does not depend on
37
+ * which document asked, and a resolution pass touches every corrected slot.
38
+ */
39
+ function colorMeasure() {
40
+ if (cachedColorMeasure === undefined) {
41
+ cachedColorMeasure = createCanvasColorMeasure();
10
42
  }
11
- return `color-mix(in srgb, ${args.left} ${args.leftWeight}, ${args.right})`;
43
+ return cachedColorMeasure;
12
44
  }
13
45
  function mapComputedDaisyVars(computed) {
14
- const value = (key) => trimCssVar(computed.getPropertyValue(key));
15
- return normalizePieThemeVariables({
16
- "--pie-background": value("--color-base-100"),
17
- "--pie-background-dark": value("--color-base-200"),
18
- "--pie-secondary-background": value("--color-base-200"),
19
- "--pie-dropdown-background": value("--color-base-300"),
20
- "--pie-text": value("--color-base-content"),
21
- "--pie-primary": value("--color-primary"),
22
- "--pie-primary-light": mixResolvedColors({
23
- left: value("--color-primary"),
24
- right: value("--color-base-100"),
25
- leftWeight: "60%",
26
- }),
27
- "--pie-primary-dark": mixResolvedColors({
28
- left: value("--color-primary"),
29
- right: value("--color-base-content"),
30
- leftWeight: "75%",
31
- }),
32
- "--pie-faded-primary": mixResolvedColors({
33
- left: value("--color-primary"),
34
- right: value("--color-base-100"),
35
- leftWeight: "20%",
36
- }),
37
- "--pie-secondary": value("--color-secondary"),
38
- "--pie-secondary-light": mixResolvedColors({
39
- left: value("--color-secondary"),
40
- right: value("--color-base-100"),
41
- leftWeight: "60%",
42
- }),
43
- "--pie-secondary-dark": mixResolvedColors({
44
- left: value("--color-secondary"),
45
- right: value("--color-base-content"),
46
- leftWeight: "75%",
47
- }),
48
- "--pie-tertiary": value("--color-accent"),
49
- "--pie-tertiary-light": mixResolvedColors({
50
- left: value("--color-accent"),
51
- right: value("--color-base-100"),
52
- leftWeight: "60%",
53
- }),
54
- "--pie-border": value("--color-base-300"),
55
- "--pie-border-light": value("--color-base-200"),
56
- "--pie-border-dark": value("--color-neutral"),
57
- "--pie-border-gray": value("--color-base-300"),
58
- "--pie-correct": value("--color-success"),
59
- "--pie-correct-secondary": mixResolvedColors({
60
- left: value("--color-success"),
61
- right: value("--color-base-100"),
62
- leftWeight: "20%",
63
- }),
64
- "--pie-correct-tertiary": value("--color-success"),
65
- "--pie-correct-icon": value("--color-success"),
66
- "--pie-incorrect": value("--color-error"),
67
- "--pie-incorrect-secondary": mixResolvedColors({
68
- left: value("--color-error"),
69
- right: value("--color-base-100"),
70
- leftWeight: "20%",
71
- }),
72
- "--pie-incorrect-icon": value("--color-error"),
73
- "--pie-missing": value("--color-error"),
74
- "--pie-missing-icon": value("--color-error"),
75
- "--pie-disabled": value("--color-base-300"),
76
- "--pie-disabled-secondary": value("--color-base-200"),
77
- "--pie-focus-checked": mixResolvedColors({
78
- left: value("--color-primary"),
79
- right: value("--color-base-100"),
80
- leftWeight: "20%",
81
- }),
82
- "--pie-focus-checked-border": value("--color-primary"),
83
- "--pie-focus-unchecked": value("--color-base-200"),
84
- "--pie-focus-unchecked-border": value("--color-base-300"),
85
- "--pie-blue-grey-100": value("--color-base-100"),
86
- "--pie-blue-grey-300": value("--color-base-200"),
87
- "--pie-blue-grey-600": value("--color-base-300"),
88
- "--pie-blue-grey-900": value("--color-base-content"),
89
- "--pie-black": value("--color-neutral-content"),
90
- "--pie-white": value("--color-base-100"),
91
- "--pie-button-bg": value("--color-base-100"),
92
- "--pie-button-border": value("--color-base-300"),
93
- "--pie-button-color": value("--color-base-content"),
94
- "--pie-button-hover-bg": value("--color-base-200"),
95
- "--pie-button-hover-border": value("--color-base-300"),
96
- "--pie-button-hover-color": value("--color-base-content"),
97
- "--pie-button-active-bg": value("--color-base-300"),
98
- "--pie-button-focus-outline": value("--color-primary"),
99
- });
46
+ return normalizePieThemeVariables(resolveDaisyPieVariables({
47
+ read: (slot) => trimCssVar(computed.getPropertyValue(DAISY_SLOT_CSS_VARIABLES[slot])),
48
+ measure: colorMeasure(),
49
+ }));
100
50
  }
101
51
  export const DAISYUI_THEME_PROVIDER_ADAPTER = {
102
52
  id: "daisyui",
@@ -115,7 +65,15 @@ export function registerPieThemeProvider(adapter) {
115
65
  if (!adapter?.id) {
116
66
  return;
117
67
  }
68
+ if (adapter.id === PIE_THEME_PROVIDER_NONE) {
69
+ console.warn(`[pie-theme] Theme-provider id "${PIE_THEME_PROVIDER_NONE}" is reserved.`);
70
+ return;
71
+ }
72
+ if (themeProviderRegistry.get(adapter.id) === adapter) {
73
+ return;
74
+ }
118
75
  themeProviderRegistry.set(adapter.id, adapter);
76
+ notifyThemeProviderObservers();
119
77
  }
120
78
  export function unregisterPieThemeProvider(providerId) {
121
79
  if (!providerId) {
@@ -124,7 +82,20 @@ export function unregisterPieThemeProvider(providerId) {
124
82
  if (providerId === DAISYUI_THEME_PROVIDER_ADAPTER.id) {
125
83
  return;
126
84
  }
127
- themeProviderRegistry.delete(providerId);
85
+ if (themeProviderRegistry.delete(providerId)) {
86
+ notifyThemeProviderObservers();
87
+ }
88
+ }
89
+ /** Package-internal invalidation used by connected pie-theme elements. */
90
+ export function observePieThemeProviders(listener) {
91
+ themeProviderObservers.add(listener);
92
+ let active = true;
93
+ return () => {
94
+ if (!active)
95
+ return;
96
+ active = false;
97
+ themeProviderObservers.delete(listener);
98
+ };
128
99
  }
129
100
  export function listPieThemeProviders() {
130
101
  return [...themeProviderRegistry.values()];
@@ -134,6 +105,12 @@ export function getPieThemeProvider(providerId) {
134
105
  }
135
106
  export function resolveProviderVariables(args) {
136
107
  const providerMode = args.provider?.trim() || "auto";
108
+ // Before the registry lookup and before the documentElement retry below: the
109
+ // point of this mode is that nothing resolves, and a retry against a themed
110
+ // <html> would put the provider's values back.
111
+ if (providerMode === PIE_THEME_PROVIDER_NONE) {
112
+ return {};
113
+ }
137
114
  const resolveFromTarget = (target) => {
138
115
  if (providerMode && providerMode !== "auto") {
139
116
  const provider = themeProviderRegistry.get(providerMode);
@@ -0,0 +1,88 @@
1
+ export declare const PIE_THEME_SCHEME_PARTICIPATION: {
2
+ readonly "--pie-answer-eliminator-strike-color": "optional";
3
+ readonly "--pie-background": "required";
4
+ readonly "--pie-background-dark": "required";
5
+ readonly "--pie-background-light": "excluded";
6
+ readonly "--pie-black": "required";
7
+ readonly "--pie-blue-grey-100": "required";
8
+ readonly "--pie-blue-grey-300": "required";
9
+ readonly "--pie-blue-grey-600": "required";
10
+ readonly "--pie-blue-grey-900": "required";
11
+ readonly "--pie-border": "required";
12
+ readonly "--pie-border-dark": "required";
13
+ readonly "--pie-border-gray": "required";
14
+ readonly "--pie-border-light": "required";
15
+ readonly "--pie-button-active-bg": "required";
16
+ readonly "--pie-button-background-color": "excluded";
17
+ readonly "--pie-button-bg": "required";
18
+ readonly "--pie-button-border": "required";
19
+ readonly "--pie-button-border-color": "excluded";
20
+ readonly "--pie-button-color": "required";
21
+ readonly "--pie-button-focus-outline": "required";
22
+ readonly "--pie-button-hover-background-color": "excluded";
23
+ readonly "--pie-button-hover-bg": "required";
24
+ readonly "--pie-button-hover-border": "required";
25
+ readonly "--pie-button-hover-color": "required";
26
+ readonly "--pie-content-styles": "excluded";
27
+ readonly "--pie-content-emphasis": "required";
28
+ readonly "--pie-correct": "required";
29
+ readonly "--pie-correct-icon": "required";
30
+ readonly "--pie-correct-secondary": "required";
31
+ readonly "--pie-correct-tertiary": "required";
32
+ readonly "--pie-disabled": "required";
33
+ readonly "--pie-disabled-secondary": "required";
34
+ readonly "--pie-dropdown-background": "required";
35
+ readonly "--pie-faded-primary": "required";
36
+ readonly "--pie-fixed-hue-collapse": "required";
37
+ readonly "--pie-focus-checked": "required";
38
+ readonly "--pie-focus-checked-border": "required";
39
+ readonly "--pie-focus-outline": "excluded";
40
+ readonly "--pie-focus-ring-color": "excluded";
41
+ readonly "--pie-focus-unchecked": "required";
42
+ readonly "--pie-focus-unchecked-border": "required";
43
+ readonly "--pie-font-scale": "excluded";
44
+ readonly "--pie-incorrect": "required";
45
+ readonly "--pie-incorrect-icon": "required";
46
+ readonly "--pie-incorrect-secondary": "required";
47
+ readonly "--pie-missing": "required";
48
+ readonly "--pie-missing-icon": "required";
49
+ readonly "--pie-passage-header-background": "optional";
50
+ readonly "--pie-primary": "required";
51
+ readonly "--pie-primary-dark": "required";
52
+ readonly "--pie-primary-light": "required";
53
+ readonly "--pie-secondary": "required";
54
+ readonly "--pie-secondary-background": "required";
55
+ readonly "--pie-secondary-dark": "required";
56
+ readonly "--pie-secondary-light": "required";
57
+ readonly "--pie-section-player-card-header-background": "optional";
58
+ readonly "--pie-section-player-card-header-radius": "excluded";
59
+ readonly "--pie-section-player-card-radius": "excluded";
60
+ readonly "--pie-section-player-item-media-aspect-ratio": "excluded";
61
+ readonly "--pie-section-player-item-media-min-height": "excluded";
62
+ readonly "--pie-section-player-item-media-max-height": "excluded";
63
+ readonly "--pie-section-player-layout-max-width": "excluded";
64
+ readonly "--pie-section-player-tab-active-background": "optional";
65
+ readonly "--pie-section-player-tab-active-color": "optional";
66
+ readonly "--pie-section-player-tab-background": "optional";
67
+ readonly "--pie-section-player-tab-color": "optional";
68
+ readonly "--pie-section-player-tab-gap": "excluded";
69
+ readonly "--pie-section-player-tab-padding-block": "excluded";
70
+ readonly "--pie-section-player-tab-track-padding": "excluded";
71
+ readonly "--pie-section-player-tab-track-radius": "excluded";
72
+ readonly "--pie-section-player-tab-zoom-comp": "excluded";
73
+ readonly "--pie-tertiary": "required";
74
+ readonly "--pie-tertiary-light": "required";
75
+ readonly "--pie-text": "required";
76
+ readonly "--pie-annotation-underline": "required";
77
+ readonly "--pie-annotation-underline-dark": "required";
78
+ readonly "--pie-tool-annotation-toolbar-border": "required";
79
+ readonly "--pie-tool-line-reader-control-color": "excluded";
80
+ readonly "--pie-tool-line-reader-frame-color": "excluded";
81
+ readonly "--pie-tool-line-reader-frame-opacity": "excluded";
82
+ readonly "--pie-tool-trigger-active-background": "optional";
83
+ readonly "--pie-tool-trigger-active-border-color": "optional";
84
+ readonly "--pie-tool-trigger-active-color": "optional";
85
+ readonly "--pie-toolbar-tools-row-height": "excluded";
86
+ readonly "--pie-tts-controls-row-height": "excluded";
87
+ readonly "--pie-white": "required";
88
+ };
@@ -0,0 +1,89 @@
1
+ /* Generated from token-registry.json by scripts/generate-theme-css.ts. */
2
+ export const PIE_THEME_SCHEME_PARTICIPATION = {
3
+ "--pie-answer-eliminator-strike-color": "optional",
4
+ "--pie-background": "required",
5
+ "--pie-background-dark": "required",
6
+ "--pie-background-light": "excluded",
7
+ "--pie-black": "required",
8
+ "--pie-blue-grey-100": "required",
9
+ "--pie-blue-grey-300": "required",
10
+ "--pie-blue-grey-600": "required",
11
+ "--pie-blue-grey-900": "required",
12
+ "--pie-border": "required",
13
+ "--pie-border-dark": "required",
14
+ "--pie-border-gray": "required",
15
+ "--pie-border-light": "required",
16
+ "--pie-button-active-bg": "required",
17
+ "--pie-button-background-color": "excluded",
18
+ "--pie-button-bg": "required",
19
+ "--pie-button-border": "required",
20
+ "--pie-button-border-color": "excluded",
21
+ "--pie-button-color": "required",
22
+ "--pie-button-focus-outline": "required",
23
+ "--pie-button-hover-background-color": "excluded",
24
+ "--pie-button-hover-bg": "required",
25
+ "--pie-button-hover-border": "required",
26
+ "--pie-button-hover-color": "required",
27
+ "--pie-content-styles": "excluded",
28
+ "--pie-content-emphasis": "required",
29
+ "--pie-correct": "required",
30
+ "--pie-correct-icon": "required",
31
+ "--pie-correct-secondary": "required",
32
+ "--pie-correct-tertiary": "required",
33
+ "--pie-disabled": "required",
34
+ "--pie-disabled-secondary": "required",
35
+ "--pie-dropdown-background": "required",
36
+ "--pie-faded-primary": "required",
37
+ "--pie-fixed-hue-collapse": "required",
38
+ "--pie-focus-checked": "required",
39
+ "--pie-focus-checked-border": "required",
40
+ "--pie-focus-outline": "excluded",
41
+ "--pie-focus-ring-color": "excluded",
42
+ "--pie-focus-unchecked": "required",
43
+ "--pie-focus-unchecked-border": "required",
44
+ "--pie-font-scale": "excluded",
45
+ "--pie-incorrect": "required",
46
+ "--pie-incorrect-icon": "required",
47
+ "--pie-incorrect-secondary": "required",
48
+ "--pie-missing": "required",
49
+ "--pie-missing-icon": "required",
50
+ "--pie-passage-header-background": "optional",
51
+ "--pie-primary": "required",
52
+ "--pie-primary-dark": "required",
53
+ "--pie-primary-light": "required",
54
+ "--pie-secondary": "required",
55
+ "--pie-secondary-background": "required",
56
+ "--pie-secondary-dark": "required",
57
+ "--pie-secondary-light": "required",
58
+ "--pie-section-player-card-header-background": "optional",
59
+ "--pie-section-player-card-header-radius": "excluded",
60
+ "--pie-section-player-card-radius": "excluded",
61
+ "--pie-section-player-item-media-aspect-ratio": "excluded",
62
+ "--pie-section-player-item-media-min-height": "excluded",
63
+ "--pie-section-player-item-media-max-height": "excluded",
64
+ "--pie-section-player-layout-max-width": "excluded",
65
+ "--pie-section-player-tab-active-background": "optional",
66
+ "--pie-section-player-tab-active-color": "optional",
67
+ "--pie-section-player-tab-background": "optional",
68
+ "--pie-section-player-tab-color": "optional",
69
+ "--pie-section-player-tab-gap": "excluded",
70
+ "--pie-section-player-tab-padding-block": "excluded",
71
+ "--pie-section-player-tab-track-padding": "excluded",
72
+ "--pie-section-player-tab-track-radius": "excluded",
73
+ "--pie-section-player-tab-zoom-comp": "excluded",
74
+ "--pie-tertiary": "required",
75
+ "--pie-tertiary-light": "required",
76
+ "--pie-text": "required",
77
+ "--pie-annotation-underline": "required",
78
+ "--pie-annotation-underline-dark": "required",
79
+ "--pie-tool-annotation-toolbar-border": "required",
80
+ "--pie-tool-line-reader-control-color": "excluded",
81
+ "--pie-tool-line-reader-frame-color": "excluded",
82
+ "--pie-tool-line-reader-frame-opacity": "excluded",
83
+ "--pie-tool-trigger-active-background": "optional",
84
+ "--pie-tool-trigger-active-border-color": "optional",
85
+ "--pie-tool-trigger-active-color": "optional",
86
+ "--pie-toolbar-tools-row-height": "excluded",
87
+ "--pie-tts-controls-row-height": "excluded",
88
+ "--pie-white": "required",
89
+ };
@@ -0,0 +1,5 @@
1
+ /** Package-internal pure renderer for the two checked-in CSS adapters. */
2
+ export declare function renderPieThemeCss(): Readonly<{
3
+ tokensCss: string;
4
+ colorSchemesCss: string;
5
+ }>;
@@ -0,0 +1,26 @@
1
+ import { assertCanonicalThemeDefinitions, getBaseThemeVariables, listBuiltInColorSchemeDefinitions, } from "./theme-definitions.js";
2
+ const GENERATED_HEADER = "/* Generated by @pie-players/pie-theme. Run `bun run generate:css`; do not edit. */";
3
+ function renderDeclarations(variables) {
4
+ return Object.entries(variables)
5
+ .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
6
+ .map(([token, value]) => `\t${token}: ${value};`)
7
+ .join("\n");
8
+ }
9
+ function renderRule(selectors, variables) {
10
+ return `${selectors.join(",\n")} {\n${renderDeclarations(variables)}\n}`;
11
+ }
12
+ function renderTokensCss() {
13
+ return `${GENERATED_HEADER}\n\n${renderRule([":root", '[data-theme="light"]', ':where(pie-theme[theme="light"])'], getBaseThemeVariables("light"))}\n\n${renderRule(['[data-theme="dark"]', ':where(pie-theme[theme="dark"])'], getBaseThemeVariables("dark"))}\n`;
14
+ }
15
+ function renderColorSchemesCss() {
16
+ const rules = listBuiltInColorSchemeDefinitions().map((scheme) => renderRule([`[data-color-scheme="${scheme.id}"]`], scheme.variables));
17
+ return `${GENERATED_HEADER}\n\n${rules.join("\n\n")}\n`;
18
+ }
19
+ /** Package-internal pure renderer for the two checked-in CSS adapters. */
20
+ export function renderPieThemeCss() {
21
+ assertCanonicalThemeDefinitions();
22
+ return Object.freeze({
23
+ tokensCss: renderTokensCss(),
24
+ colorSchemesCss: renderColorSchemesCss(),
25
+ });
26
+ }
@@ -0,0 +1,21 @@
1
+ import type { PieThemeSchemeParticipation } from "./token-registry-types.js";
2
+ import type { PieColorSchemeDescriptor, PieColorSchemePreview, PieThemeDiagnostic, ThemeTokenName, ThemeVariables } from "./theme-types.js";
3
+ type BuiltInColorSchemeDefinition = Readonly<{
4
+ id: string;
5
+ name: string;
6
+ description?: string;
7
+ variables: Readonly<ThemeVariables>;
8
+ }>;
9
+ export declare function diagnoseThemeContrast(variables: Readonly<ThemeVariables>, schemeId?: string, relevantTokens?: ReadonlySet<string>): readonly PieThemeDiagnostic[];
10
+ export declare function getBaseThemeVariables(baseTheme: "light" | "dark"): Readonly<ThemeVariables>;
11
+ export declare function listBuiltInColorSchemeDefinitions(): readonly BuiltInColorSchemeDefinition[];
12
+ export declare function getBuiltInColorSchemeDefinition(id: string): BuiltInColorSchemeDefinition | undefined;
13
+ export declare function getDefaultColorSchemeDescriptor(): PieColorSchemeDescriptor;
14
+ export declare function createPieColorSchemePreview(variables: Readonly<ThemeVariables>): PieColorSchemePreview;
15
+ export declare function getSchemeParticipation(token: string): PieThemeSchemeParticipation | undefined;
16
+ export declare function getRequiredSchemeTokens(): readonly ThemeTokenName[];
17
+ export declare function getOptionalSchemeTokens(): readonly ThemeTokenName[];
18
+ export declare function createBuiltInColorSchemeDescriptor(definition: BuiltInColorSchemeDefinition): PieColorSchemeDescriptor;
19
+ /** Build-time invariant check; browser entries only read the frozen definitions. */
20
+ export declare function assertCanonicalThemeDefinitions(): void;
21
+ export {};