@nanisoft/prism-ui 0.5.1 → 0.7.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/dist/.tsbuildinfo +1 -1
- package/dist/blocks/cta-01/cta.d.ts +66 -6
- package/dist/blocks/cta-01/cta.d.ts.map +1 -1
- package/dist/blocks/cta-01/cta.js +8 -3
- package/dist/blocks/cta-01/index.d.ts +1 -0
- package/dist/blocks/cta-01/index.d.ts.map +1 -1
- package/dist/blocks/feature-grid-01/feature-grid.d.ts +57 -6
- package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -1
- package/dist/blocks/feature-grid-01/feature-grid.js +12 -2
- package/dist/blocks/feature-grid-01/index.d.ts +1 -0
- package/dist/blocks/feature-grid-01/index.d.ts.map +1 -1
- package/dist/blocks/hero-01/hero.d.ts +30 -1
- package/dist/blocks/hero-01/hero.d.ts.map +1 -1
- package/dist/blocks/hero-01/hero.js +14 -2
- package/dist/blocks/index.d.ts +10 -0
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/blocks/index.js +9 -0
- package/dist/blocks/instrument-panel-01/index.d.ts +3 -0
- package/dist/blocks/instrument-panel-01/index.d.ts.map +1 -0
- package/dist/blocks/instrument-panel-01/index.js +1 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.d.ts +114 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.d.ts.map +1 -0
- package/dist/blocks/instrument-panel-01/instrument-panel.js +64 -0
- package/dist/blocks/logo-strip-01/index.d.ts +3 -0
- package/dist/blocks/logo-strip-01/index.d.ts.map +1 -0
- package/dist/blocks/logo-strip-01/index.js +1 -0
- package/dist/blocks/logo-strip-01/logo-strip.d.ts +84 -0
- package/dist/blocks/logo-strip-01/logo-strip.d.ts.map +1 -0
- package/dist/blocks/logo-strip-01/logo-strip.js +40 -0
- package/dist/blocks/note-grid-01/index.d.ts +3 -0
- package/dist/blocks/note-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/note-grid-01/index.js +1 -0
- package/dist/blocks/note-grid-01/note-grid.d.ts +79 -0
- package/dist/blocks/note-grid-01/note-grid.d.ts.map +1 -0
- package/dist/blocks/note-grid-01/note-grid.js +37 -0
- package/dist/blocks/pricing-01/pricing.js +1 -1
- package/dist/blocks/process-rail-01/index.d.ts +3 -0
- package/dist/blocks/process-rail-01/index.d.ts.map +1 -0
- package/dist/blocks/process-rail-01/index.js +1 -0
- package/dist/blocks/process-rail-01/process-rail.d.ts +99 -0
- package/dist/blocks/process-rail-01/process-rail.d.ts.map +1 -0
- package/dist/blocks/process-rail-01/process-rail.js +58 -0
- package/dist/blocks/product-grid-01/index.d.ts +3 -0
- package/dist/blocks/product-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/product-grid-01/index.js +1 -0
- package/dist/blocks/product-grid-01/product-grid.d.ts +114 -0
- package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -0
- package/dist/blocks/product-grid-01/product-grid.js +51 -0
- package/dist/blocks/site-footer/index.d.ts +3 -0
- package/dist/blocks/site-footer/index.d.ts.map +1 -0
- package/dist/blocks/site-footer/index.js +1 -0
- package/dist/blocks/site-footer/site-footer.d.ts +135 -0
- package/dist/blocks/site-footer/site-footer.d.ts.map +1 -0
- package/dist/blocks/site-footer/site-footer.js +41 -0
- package/dist/blocks/site-header/index.d.ts +3 -0
- package/dist/blocks/site-header/index.d.ts.map +1 -0
- package/dist/blocks/site-header/index.js +1 -0
- package/dist/blocks/site-header/site-header.d.ts +142 -0
- package/dist/blocks/site-header/site-header.d.ts.map +1 -0
- package/dist/blocks/site-header/site-header.js +46 -0
- package/dist/blocks/stack-grid-01/index.d.ts +3 -0
- package/dist/blocks/stack-grid-01/index.d.ts.map +1 -0
- package/dist/blocks/stack-grid-01/index.js +1 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +118 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -0
- package/dist/blocks/stack-grid-01/stack-grid.js +49 -0
- package/dist/blocks/status-ledger-01/index.d.ts +3 -0
- package/dist/blocks/status-ledger-01/index.d.ts.map +1 -0
- package/dist/blocks/status-ledger-01/index.js +1 -0
- package/dist/blocks/status-ledger-01/status-ledger.d.ts +131 -0
- package/dist/blocks/status-ledger-01/status-ledger.d.ts.map +1 -0
- package/dist/blocks/status-ledger-01/status-ledger.js +80 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +180 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +6 -0
- package/dist/components/ui/card.d.ts +25 -0
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/card.js +25 -0
- package/dist/components/ui/cta-link.d.ts +45 -0
- package/dist/components/ui/cta-link.d.ts.map +1 -0
- package/dist/components/ui/cta-link.js +81 -0
- package/dist/components/ui/diagram.d.ts +154 -0
- package/dist/components/ui/diagram.d.ts.map +1 -0
- package/dist/components/ui/diagram.js +150 -0
- package/dist/components/ui/fact-list.d.ts +90 -0
- package/dist/components/ui/fact-list.d.ts.map +1 -0
- package/dist/components/ui/fact-list.js +38 -0
- package/dist/components/ui/product-mark.d.ts +115 -0
- package/dist/components/ui/product-mark.d.ts.map +1 -0
- package/dist/components/ui/product-mark.js +82 -0
- package/dist/components/ui/product-switcher.d.ts +108 -0
- package/dist/components/ui/product-switcher.d.ts.map +1 -0
- package/dist/components/ui/product-switcher.js +47 -0
- package/dist/components/ui/prose.d.ts +88 -0
- package/dist/components/ui/prose.d.ts.map +1 -0
- package/dist/components/ui/prose.js +53 -0
- package/dist/components/ui/section.d.ts +24 -1
- package/dist/components/ui/section.d.ts.map +1 -1
- package/dist/components/ui/section.js +11 -2
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/slider.js +7 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/pages/blog-post-page/index.d.ts +174 -0
- package/dist/pages/blog-post-page/index.d.ts.map +1 -0
- package/dist/pages/blog-post-page/index.js +49 -0
- package/dist/pages/docs-shell/docs-shell.d.ts +250 -0
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -0
- package/dist/pages/docs-shell/docs-shell.js +197 -0
- package/dist/pages/docs-shell/index.d.ts +3 -0
- package/dist/pages/docs-shell/index.d.ts.map +1 -0
- package/dist/pages/docs-shell/index.js +1 -0
- package/dist/pages/index.d.ts +13 -2
- package/dist/pages/index.d.ts.map +1 -1
- package/dist/pages/index.js +10 -2
- package/dist/pages/not-found-page/index.d.ts +112 -0
- package/dist/pages/not-found-page/index.d.ts.map +1 -0
- package/dist/pages/not-found-page/index.js +46 -0
- package/dist/provider/provider.d.ts +5 -0
- package/dist/provider/provider.d.ts.map +1 -1
- package/dist/provider/provider.js +129 -38
- package/dist/provider/theme-script.d.ts +41 -3
- package/dist/provider/theme-script.d.ts.map +1 -1
- package/dist/provider/theme-script.js +68 -17
- package/dist/styles.css +555 -12
- package/dist/theming/index.d.ts +132 -2
- package/dist/theming/index.d.ts.map +1 -1
- package/dist/theming/index.js +127 -1
- package/package.json +14 -4
|
@@ -9,67 +9,158 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
9
9
|
* the same two markup attributes the declarative form uses. There is no
|
|
10
10
|
* override, merge, token, className or style prop: the provider's only outputs
|
|
11
11
|
* are the document-element attributes and context (ticket 07).
|
|
12
|
+
*
|
|
13
|
+
* It resolves through `resolveTheme`, the one rule the boot script also
|
|
14
|
+
* implements, and it never writes `THEME_ORIGIN_ATTRIBUTE`: the script is that
|
|
15
|
+
* attribute's only writer, and two writers would turn a record of the origin
|
|
16
|
+
* into a race.
|
|
12
17
|
*/
|
|
13
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
|
|
14
|
-
import { DEFAULT_STORAGE_KEY,
|
|
18
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
|
|
19
|
+
import { DEFAULT_STORAGE_KEY, PACK_ATTRIBUTE, readLegacyMode, resolveTheme, themeAttributes, } from '../theming';
|
|
15
20
|
const PrismThemeContext = createContext(null);
|
|
16
21
|
function applyDocumentAttributes(pack, mode) {
|
|
17
22
|
const root = document.documentElement;
|
|
18
23
|
const { 'data-pack': packAttribute, className } = themeAttributes({ pack, mode });
|
|
19
24
|
if (packAttribute)
|
|
20
|
-
root.setAttribute(
|
|
25
|
+
root.setAttribute(PACK_ATTRIBUTE, packAttribute);
|
|
21
26
|
else
|
|
22
|
-
root.removeAttribute(
|
|
27
|
+
root.removeAttribute(PACK_ATTRIBUTE);
|
|
23
28
|
if (className)
|
|
24
29
|
root.classList.add('dark');
|
|
25
30
|
else
|
|
26
31
|
root.classList.remove('dark');
|
|
27
32
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
/** One guarded read. A blocked or full store must not break the page. */
|
|
34
|
+
function read(key) {
|
|
35
|
+
try {
|
|
36
|
+
return localStorage.getItem(key);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** One guarded write. The attributes are already applied when this fails. */
|
|
43
|
+
function persist(key, pack, mode) {
|
|
44
|
+
try {
|
|
45
|
+
localStorage.setItem(key, JSON.stringify({ pack, mode }));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// A blocked or full localStorage must not break theme switching. The
|
|
49
|
+
// attributes are already applied, so the visible behaviour is unchanged.
|
|
50
|
+
}
|
|
33
51
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
52
|
+
function retire(key) {
|
|
53
|
+
try {
|
|
54
|
+
localStorage.removeItem(key);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Nothing to do: a key that cannot be removed is read again next load,
|
|
58
|
+
// recovers the same decision, and writes the same pair.
|
|
59
|
+
}
|
|
36
60
|
}
|
|
37
61
|
export function PrismProvider({ defaultPack = 'default', defaultMode = 'light', storageKey = DEFAULT_STORAGE_KEY, children, }) {
|
|
38
|
-
const [pack, setPackState] = useState(defaultPack);
|
|
39
|
-
const [mode, setModeState] = useState(defaultMode);
|
|
40
|
-
const [resolved, setResolved] = useState(false);
|
|
41
62
|
/*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
63
|
+
* The resolution, and whether a decision has been made. Two pieces of state
|
|
64
|
+
* for two different questions, which is why the old `resolved` flag was not
|
|
65
|
+
* enough on its own:
|
|
66
|
+
*
|
|
67
|
+
* - `theme` is null until the store has been read. It gates APPLY, because
|
|
68
|
+
* applying the default over a server-rendered pack before resolution is
|
|
69
|
+
* the flash the resolution order exists to prevent. It carries the
|
|
70
|
+
* origin, so the recovery below can read it without a second lookup.
|
|
71
|
+
* - `decided` is a ref, not state, because it must be readable by the write
|
|
72
|
+
* effect without causing a render, and settable synchronously by a caller
|
|
73
|
+
* whose state update has not been committed yet. It gates WRITE.
|
|
74
|
+
*
|
|
75
|
+
* A ref also cannot be re-rendered into an extra effect pass, which is what
|
|
76
|
+
* would have made the write fire once for the flag and once for the value.
|
|
77
|
+
*/
|
|
78
|
+
const [theme, setTheme] = useState(null);
|
|
79
|
+
const decided = useRef(false);
|
|
80
|
+
/*
|
|
81
|
+
* Resolution on mount, through the one shared rule: the stored value, then a
|
|
82
|
+
* key this line no longer writes, then what the server rendered, then the
|
|
83
|
+
* defaults. A server-rendered pack therefore survives hydration.
|
|
45
84
|
*/
|
|
46
85
|
useEffect(() => {
|
|
47
|
-
const
|
|
48
|
-
const next =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
86
|
+
const recovered = readLegacyMode(read);
|
|
87
|
+
const next = resolveTheme({
|
|
88
|
+
stored: read(storageKey),
|
|
89
|
+
legacy: recovered?.mode ?? null,
|
|
90
|
+
documentPack: document.documentElement.getAttribute(PACK_ATTRIBUTE),
|
|
91
|
+
documentDark: document.documentElement.classList.contains('dark'),
|
|
92
|
+
defaultPack,
|
|
93
|
+
defaultMode,
|
|
94
|
+
});
|
|
95
|
+
if (next.origin === 'legacy' && recovered) {
|
|
96
|
+
/*
|
|
97
|
+
* The recovery write. A decision taken from a key this line no longer
|
|
98
|
+
* writes is put in the key it does write, and the old key is retired in
|
|
99
|
+
* the same breath, which is what makes the clause self-disabling: the
|
|
100
|
+
* next load finds nothing to recover, so a reader is migrated once and
|
|
101
|
+
* the population the clause can still reach only ever shrinks.
|
|
102
|
+
*/
|
|
103
|
+
persist(storageKey, next.pack, next.mode);
|
|
104
|
+
retire(recovered.key);
|
|
105
|
+
}
|
|
106
|
+
// A caller that decided in a layout effect before this ran keeps its value.
|
|
107
|
+
if (!decided.current)
|
|
108
|
+
setTheme(next);
|
|
52
109
|
}, [storageKey, defaultPack, defaultMode]);
|
|
53
110
|
/*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
111
|
+
* Apply always, once there is a resolution; persist only on a decision.
|
|
112
|
+
*
|
|
113
|
+
* The first resolution from the document or the defaults writes nothing, so a
|
|
114
|
+
* visitor who never touched the toggle ends the load with an empty store and
|
|
115
|
+
* a site that changes its default reaches everyone who has not chosen.
|
|
56
116
|
*/
|
|
57
117
|
useEffect(() => {
|
|
58
|
-
if (!
|
|
118
|
+
if (!theme)
|
|
59
119
|
return;
|
|
60
|
-
applyDocumentAttributes(pack, mode);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
120
|
+
applyDocumentAttributes(theme.pack, theme.mode);
|
|
121
|
+
if (decided.current)
|
|
122
|
+
persist(storageKey, theme.pack, theme.mode);
|
|
123
|
+
}, [theme, storageKey]);
|
|
124
|
+
const setPack = useCallback((next) => {
|
|
125
|
+
decided.current = true;
|
|
126
|
+
setTheme((current) => ({
|
|
127
|
+
pack: next,
|
|
128
|
+
mode: current?.mode ?? defaultMode,
|
|
129
|
+
origin: 'stored',
|
|
130
|
+
}));
|
|
131
|
+
}, [defaultMode]);
|
|
132
|
+
const setMode = useCallback((next) => {
|
|
133
|
+
decided.current = true;
|
|
134
|
+
setTheme((current) => ({
|
|
135
|
+
pack: current?.pack ?? defaultPack,
|
|
136
|
+
mode: next,
|
|
137
|
+
origin: 'stored',
|
|
138
|
+
}));
|
|
139
|
+
}, [defaultPack]);
|
|
140
|
+
/*
|
|
141
|
+
* The pair is a closed union of two members, so the other one is the other
|
|
142
|
+
* member. Spelling it out costs nothing and does not hide the coupling behind
|
|
143
|
+
* an index into a list this file does not otherwise need.
|
|
144
|
+
*
|
|
145
|
+
* The three setters all fall back to the consumer's own default rather than
|
|
146
|
+
* to the neutral one, so a decision taken before the store has been read
|
|
147
|
+
* pairs the chosen axis with the site's default and not with a guess.
|
|
148
|
+
*/
|
|
149
|
+
const toggleMode = useCallback(() => {
|
|
150
|
+
decided.current = true;
|
|
151
|
+
setTheme((current) => ({
|
|
152
|
+
pack: current?.pack ?? defaultPack,
|
|
153
|
+
mode: current?.mode === 'dark' ? 'light' : 'dark',
|
|
154
|
+
origin: 'stored',
|
|
155
|
+
}));
|
|
156
|
+
}, [defaultPack]);
|
|
157
|
+
const value = useMemo(() => ({
|
|
158
|
+
pack: theme?.pack ?? defaultPack,
|
|
159
|
+
mode: theme?.mode ?? defaultMode,
|
|
160
|
+
setPack,
|
|
161
|
+
setMode,
|
|
162
|
+
toggleMode,
|
|
163
|
+
}), [theme, defaultPack, defaultMode, setPack, setMode, toggleMode]);
|
|
73
164
|
return _jsx(PrismThemeContext.Provider, { value: value, children: children });
|
|
74
165
|
}
|
|
75
166
|
/**
|
|
@@ -3,11 +3,49 @@
|
|
|
3
3
|
*
|
|
4
4
|
* A Server Component that renders one blocking script. Placed in `<head>`, it
|
|
5
5
|
* applies the stored pack and mode before React hydrates, so the first paint is
|
|
6
|
-
* already correct.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* already correct. It is safe to omit; a consumer who renders the attributes on
|
|
7
|
+
* `<html>` needs no client runtime at all.
|
|
8
|
+
*
|
|
9
|
+
* It is the only writer of `THEME_ORIGIN_ATTRIBUTE`, and it writes that
|
|
10
|
+
* attribute on every path it reaches, so the origin of the active theme is
|
|
11
|
+
* always readable and never merely absent.
|
|
12
|
+
*
|
|
13
|
+
* The string below is a second implementation of `resolveTheme`, not a copy of
|
|
14
|
+
* it that has been kept in step. A function cannot be shared with a string that
|
|
15
|
+
* a minifier rewrites: a renamed identifier inside the script's own `try` throws
|
|
16
|
+
* there, the catch swallows it, and the theme silently stops applying on every
|
|
17
|
+
* page. So the string implements the rule and
|
|
18
|
+
* `scripts/check-theme-resolution.mjs` runs BOTH over one table of stored
|
|
19
|
+
* values, which is the only thing that can hold them together.
|
|
20
|
+
*
|
|
21
|
+
* Its price is a separate ceiling, `scripts/check-boot-budget.mjs`, because this
|
|
22
|
+
* string runs before paint on every page and adding it to a table of component
|
|
23
|
+
* bundle sizes would corrupt the unit that table exists to measure.
|
|
9
24
|
*/
|
|
10
25
|
import { type Mode, type PackId } from '../theming';
|
|
26
|
+
/**
|
|
27
|
+
* The first half of the storage-migration clause: read one key this line no
|
|
28
|
+
* longer writes.
|
|
29
|
+
*
|
|
30
|
+
* Exported because `check-boot-budget.mjs` prices the clause rather than
|
|
31
|
+
* guessing at it. The emitted string contains this fragment verbatim, so its
|
|
32
|
+
* byte count is the clause's cost and not an estimate of it.
|
|
33
|
+
*/
|
|
34
|
+
export declare const THEME_MIGRATION_READ: string;
|
|
35
|
+
/**
|
|
36
|
+
* The second half: the clause retires itself.
|
|
37
|
+
*
|
|
38
|
+
* The recovery is the only write this string performs, and it writes the
|
|
39
|
+
* recovered pair into the key this line does write and removes the key it came
|
|
40
|
+
* from, in one guarded step. That is the clause's expiry by rule rather than by
|
|
41
|
+
* number: it fires only while a retired key still holds a mode, it fires at
|
|
42
|
+
* most once per reader because its own write is what makes the second load find
|
|
43
|
+
* nothing, and it is retired for good by deleting the last entry of
|
|
44
|
+
* `LEGACY_MODE_STORAGE_KEYS`. There is no date and no version constant in it,
|
|
45
|
+
* and the gate reports how many keys are still live so the number is visible
|
|
46
|
+
* rather than remembered.
|
|
47
|
+
*/
|
|
48
|
+
export declare const THEME_MIGRATION_RETIRE = "if(G===\"legacy\"){try{localStorage.setItem(K,JSON.stringify({pack:pack,mode:m}));localStorage.removeItem(LK);}catch(e){}}";
|
|
11
49
|
export type PrismThemeScriptProps = {
|
|
12
50
|
storageKey?: string;
|
|
13
51
|
defaultPack?: PackId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../../src/provider/theme-script.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"theme-script.d.ts","sourceRoot":"","sources":["../../src/provider/theme-script.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAOL,KAAK,IAAI,EACT,KAAK,MAAM,EACZ,MAAM,YAAY,CAAA;AAEnB;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,QAEvB,CAAA;AAEV;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,+HACyF,CAAA;AAE5H,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,IAAI,CAAA;CACnB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,UAAgC,EAChC,WAAuB,EACvB,WAAqB,GACtB,EAAE,qBAAqB,+BA+BvB"}
|
|
@@ -4,25 +4,76 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
*
|
|
5
5
|
* A Server Component that renders one blocking script. Placed in `<head>`, it
|
|
6
6
|
* applies the stored pack and mode before React hydrates, so the first paint is
|
|
7
|
-
* already correct.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* already correct. It is safe to omit; a consumer who renders the attributes on
|
|
8
|
+
* `<html>` needs no client runtime at all.
|
|
9
|
+
*
|
|
10
|
+
* It is the only writer of `THEME_ORIGIN_ATTRIBUTE`, and it writes that
|
|
11
|
+
* attribute on every path it reaches, so the origin of the active theme is
|
|
12
|
+
* always readable and never merely absent.
|
|
13
|
+
*
|
|
14
|
+
* The string below is a second implementation of `resolveTheme`, not a copy of
|
|
15
|
+
* it that has been kept in step. A function cannot be shared with a string that
|
|
16
|
+
* a minifier rewrites: a renamed identifier inside the script's own `try` throws
|
|
17
|
+
* there, the catch swallows it, and the theme silently stops applying on every
|
|
18
|
+
* page. So the string implements the rule and
|
|
19
|
+
* `scripts/check-theme-resolution.mjs` runs BOTH over one table of stored
|
|
20
|
+
* values, which is the only thing that can hold them together.
|
|
21
|
+
*
|
|
22
|
+
* Its price is a separate ceiling, `scripts/check-boot-budget.mjs`, because this
|
|
23
|
+
* string runs before paint on every page and adding it to a table of component
|
|
24
|
+
* bundle sizes would corrupt the unit that table exists to measure.
|
|
25
|
+
*/
|
|
26
|
+
import { DEFAULT_STORAGE_KEY, LEGACY_MODE_STORAGE_KEYS, MODES, PACKS, PACK_ATTRIBUTE, THEME_ORIGIN_ATTRIBUTE, } from '../theming';
|
|
27
|
+
/**
|
|
28
|
+
* The first half of the storage-migration clause: read one key this line no
|
|
29
|
+
* longer writes.
|
|
30
|
+
*
|
|
31
|
+
* Exported because `check-boot-budget.mjs` prices the clause rather than
|
|
32
|
+
* guessing at it. The emitted string contains this fragment verbatim, so its
|
|
33
|
+
* byte count is the clause's cost and not an estimate of it.
|
|
34
|
+
*/
|
|
35
|
+
export const THEME_MIGRATION_READ = LEGACY_MODE_STORAGE_KEYS.map((key) => `try{var g=localStorage.getItem(${JSON.stringify(key)});if(M.indexOf(g)>-1){L=g;LK=${JSON.stringify(key)};}}catch(e){}`).join('');
|
|
36
|
+
/**
|
|
37
|
+
* The second half: the clause retires itself.
|
|
38
|
+
*
|
|
39
|
+
* The recovery is the only write this string performs, and it writes the
|
|
40
|
+
* recovered pair into the key this line does write and removes the key it came
|
|
41
|
+
* from, in one guarded step. That is the clause's expiry by rule rather than by
|
|
42
|
+
* number: it fires only while a retired key still holds a mode, it fires at
|
|
43
|
+
* most once per reader because its own write is what makes the second load find
|
|
44
|
+
* nothing, and it is retired for good by deleting the last entry of
|
|
45
|
+
* `LEGACY_MODE_STORAGE_KEYS`. There is no date and no version constant in it,
|
|
46
|
+
* and the gate reports how many keys are still live so the number is visible
|
|
47
|
+
* rather than remembered.
|
|
10
48
|
*/
|
|
11
|
-
|
|
49
|
+
export const THEME_MIGRATION_RETIRE = 'if(G==="legacy"){try{localStorage.setItem(K,JSON.stringify({pack:pack,mode:m}));localStorage.removeItem(LK);}catch(e){}}';
|
|
12
50
|
export function PrismThemeScript({ storageKey = DEFAULT_STORAGE_KEY, defaultPack = 'default', defaultMode = 'light', }) {
|
|
13
51
|
const script = '(function(){try{' +
|
|
14
|
-
'var
|
|
15
|
-
`
|
|
16
|
-
`
|
|
17
|
-
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
'
|
|
26
|
-
'
|
|
52
|
+
'var r=document.documentElement,' +
|
|
53
|
+
`P=${JSON.stringify(PACKS)},` +
|
|
54
|
+
`M=${JSON.stringify(MODES)},` +
|
|
55
|
+
`K=${JSON.stringify(storageKey)},` +
|
|
56
|
+
`A=${JSON.stringify(PACK_ATTRIBUTE)},` +
|
|
57
|
+
`O=${JSON.stringify(THEME_ORIGIN_ATTRIBUTE)},` +
|
|
58
|
+
`DP=${JSON.stringify(defaultPack)},` +
|
|
59
|
+
`DM=${JSON.stringify(defaultMode)},` +
|
|
60
|
+
'L=null,LK=null,S=null,T=null;' +
|
|
61
|
+
'try{var t=localStorage.getItem(K);if(t){T=t;S=JSON.parse(t);}}catch(e){}' +
|
|
62
|
+
THEME_MIGRATION_READ +
|
|
63
|
+
'var a=r.getAttribute(A),' +
|
|
64
|
+
'DPK=P.indexOf(a)>-1?a:null,' +
|
|
65
|
+
'DK=r.classList.contains("dark")?"dark":null,' +
|
|
66
|
+
'U=S&&typeof S=="object"&&P.indexOf(S.pack)>-1&&M.indexOf(S.mode)>-1,' +
|
|
67
|
+
'pack,m,G;' +
|
|
68
|
+
'if(U){pack=S.pack;m=S.mode;G="stored";}' +
|
|
69
|
+
'else if(T){pack=DPK||DP;m=DK||DM;G="unparsed";}' +
|
|
70
|
+
'else if(L){pack=DP;m=L;G="legacy";}' +
|
|
71
|
+
'else if(DPK||DK){pack=DPK||DP;m=DK||DM;G="document";}' +
|
|
72
|
+
'else{pack=DP;m=DM;G="default";}' +
|
|
73
|
+
THEME_MIGRATION_RETIRE +
|
|
74
|
+
'if(pack!=="default"){r.setAttribute(A,pack);}else{r.removeAttribute(A);}' +
|
|
75
|
+
'r.classList.toggle("dark",m==="dark");' +
|
|
76
|
+
'r.setAttribute(O,G);' +
|
|
77
|
+
'}catch(e){}})();';
|
|
27
78
|
return _jsx("script", { dangerouslySetInnerHTML: { __html: script } });
|
|
28
79
|
}
|