font-switcher 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,405 @@
1
+ "use client";
2
+
3
+ // src/component.tsx
4
+ import { useState, useEffect, useCallback } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var PANEL_STORAGE_KEY = "font-switcher-ui";
7
+ var DEFAULT_RENDER = {
8
+ textRendering: "auto",
9
+ webkitSmoothing: "auto",
10
+ mozSmoothing: "auto"
11
+ };
12
+ var POSITIONS = {
13
+ "bottom-right": { bottom: "16px", right: "16px" },
14
+ "bottom-left": { bottom: "16px", left: "16px" },
15
+ "top-right": { top: "16px", right: "16px" },
16
+ "top-left": { top: "16px", left: "16px" }
17
+ };
18
+ function buildFeatureMeta(fonts, detected) {
19
+ const result = {};
20
+ for (const font of fonts) {
21
+ const fromConfig = font.features ?? [];
22
+ const fromDetected = detected[font.key] ?? [];
23
+ const configTags = new Set(fromConfig.map((f) => f.tag));
24
+ const merged = [...fromConfig, ...fromDetected.filter((f) => !configTags.has(f.tag))];
25
+ if (merged.length) result[font.key] = merged;
26
+ }
27
+ return result;
28
+ }
29
+ function applyRuntimeStyles(activeKey, featureEnabled, render) {
30
+ let el = document.getElementById("font-switcher-rt");
31
+ if (!el) {
32
+ el = document.createElement("style");
33
+ el.id = "font-switcher-rt";
34
+ document.head.appendChild(el);
35
+ }
36
+ const fontTags = featureEnabled[activeKey];
37
+ const featureStr = fontTags && Object.keys(fontTags).length ? Object.entries(fontTags).map(([tag, on]) => `"${tag}" ${on ? 1 : 0}`).join(", ") : "normal";
38
+ el.textContent = [
39
+ "html {",
40
+ ` font-feature-settings: ${featureStr};`,
41
+ ` text-rendering: ${render.textRendering};`,
42
+ ` -webkit-font-smoothing: ${render.webkitSmoothing};`,
43
+ ` -moz-osx-font-smoothing: ${render.mozSmoothing};`,
44
+ "}"
45
+ ].join("\n");
46
+ }
47
+ function FontSwitcher({ config, position = "bottom-right" }) {
48
+ const {
49
+ fonts,
50
+ defaultFont,
51
+ storageKey = "font-switcher-active",
52
+ revealParam = "fonts",
53
+ revealShortcut = "ctrl+shift+f",
54
+ finalFont
55
+ } = config;
56
+ const [visible, setVisible] = useState(false);
57
+ const [active, setActive] = useState(defaultFont);
58
+ const [featureMeta, setFeatureMeta] = useState({});
59
+ const [featureEnabled, setFeatureEnabled] = useState({});
60
+ const [renderSettings, setRenderSettings] = useState(DEFAULT_RENDER);
61
+ useEffect(() => {
62
+ if (finalFont) return;
63
+ try {
64
+ const stored = localStorage.getItem(storageKey);
65
+ if (stored && fonts.some((f) => f.key === stored)) setActive(stored);
66
+ } catch {
67
+ }
68
+ const params = new URLSearchParams(window.location.search);
69
+ if (params.has(revealParam)) {
70
+ setVisible(true);
71
+ try {
72
+ localStorage.setItem(PANEL_STORAGE_KEY, "on");
73
+ } catch {
74
+ }
75
+ } else {
76
+ try {
77
+ if (localStorage.getItem(PANEL_STORAGE_KEY) === "on") setVisible(true);
78
+ } catch {
79
+ }
80
+ }
81
+ const parts = revealShortcut.toLowerCase().split("+");
82
+ const targetKey = parts[parts.length - 1];
83
+ const mods = new Set(parts.slice(0, -1));
84
+ const onKey = (e) => {
85
+ if (e.key.toLowerCase() !== targetKey) return;
86
+ if (mods.has("ctrl") !== e.ctrlKey) return;
87
+ if (mods.has("shift") !== e.shiftKey) return;
88
+ if (mods.has("alt") !== e.altKey) return;
89
+ if (mods.has("meta") !== e.metaKey) return;
90
+ e.preventDefault();
91
+ setVisible((v) => {
92
+ const next = !v;
93
+ try {
94
+ localStorage.setItem(PANEL_STORAGE_KEY, next ? "on" : "off");
95
+ } catch {
96
+ }
97
+ return next;
98
+ });
99
+ };
100
+ window.addEventListener("keydown", onKey);
101
+ const detected = window.__fontSwitcherFeatures ?? {};
102
+ const meta = buildFeatureMeta(fonts, detected);
103
+ setFeatureMeta(meta);
104
+ const defaults = Object.fromEntries(
105
+ Object.entries(meta).map(([key, features]) => [
106
+ key,
107
+ Object.fromEntries(features.map((f) => [f.tag, f.enabled]))
108
+ ])
109
+ );
110
+ try {
111
+ const stored = localStorage.getItem(`${storageKey}-features`);
112
+ if (stored) {
113
+ const parsed = JSON.parse(stored);
114
+ for (const [fontKey, tags] of Object.entries(parsed)) {
115
+ if (defaults[fontKey]) Object.assign(defaults[fontKey], tags);
116
+ }
117
+ }
118
+ } catch {
119
+ }
120
+ setFeatureEnabled(defaults);
121
+ try {
122
+ const stored = localStorage.getItem(`${storageKey}-render`);
123
+ if (stored) setRenderSettings((r) => ({ ...r, ...JSON.parse(stored) }));
124
+ } catch {
125
+ }
126
+ return () => window.removeEventListener("keydown", onKey);
127
+ }, []);
128
+ useEffect(() => {
129
+ if (finalFont) return;
130
+ applyRuntimeStyles(active, featureEnabled, renderSettings);
131
+ }, [active, featureEnabled, renderSettings, finalFont]);
132
+ const switchFont = useCallback(
133
+ (key) => {
134
+ document.documentElement.dataset.font = key;
135
+ try {
136
+ localStorage.setItem(storageKey, key);
137
+ } catch {
138
+ }
139
+ setActive(key);
140
+ },
141
+ [storageKey]
142
+ );
143
+ const reset = useCallback(() => {
144
+ delete document.documentElement.dataset.font;
145
+ try {
146
+ localStorage.removeItem(storageKey);
147
+ } catch {
148
+ }
149
+ setActive(defaultFont);
150
+ }, [defaultFont, storageKey]);
151
+ const toggleFeature = useCallback(
152
+ (fontKey, tag) => {
153
+ setFeatureEnabled((prev) => {
154
+ const next = {
155
+ ...prev,
156
+ [fontKey]: { ...prev[fontKey], [tag]: !prev[fontKey]?.[tag] }
157
+ };
158
+ try {
159
+ localStorage.setItem(`${storageKey}-features`, JSON.stringify(next));
160
+ } catch {
161
+ }
162
+ return next;
163
+ });
164
+ },
165
+ [storageKey]
166
+ );
167
+ const updateRender = useCallback(
168
+ (key, value) => {
169
+ setRenderSettings((prev) => {
170
+ const next = { ...prev, [key]: value };
171
+ try {
172
+ localStorage.setItem(`${storageKey}-render`, JSON.stringify(next));
173
+ } catch {
174
+ }
175
+ return next;
176
+ });
177
+ },
178
+ [storageKey]
179
+ );
180
+ if (finalFont || !visible) return null;
181
+ const activeFeatures = featureMeta[active] ?? [];
182
+ return /* @__PURE__ */ jsxs(
183
+ "div",
184
+ {
185
+ style: {
186
+ position: "fixed",
187
+ zIndex: 9999,
188
+ background: "#fff",
189
+ border: "1px solid #e0e0e0",
190
+ padding: "6px",
191
+ minWidth: "200px",
192
+ maxWidth: "280px",
193
+ maxHeight: "80vh",
194
+ overflowY: "auto",
195
+ boxShadow: "0 2px 8px rgba(0,0,0,0.12)",
196
+ fontFamily: "system-ui, sans-serif",
197
+ ...POSITIONS[position]
198
+ },
199
+ children: [
200
+ fonts.map((font) => /* @__PURE__ */ jsxs(
201
+ "button",
202
+ {
203
+ onClick: () => switchFont(font.key),
204
+ style: {
205
+ display: "flex",
206
+ alignItems: "center",
207
+ justifyContent: "space-between",
208
+ width: "100%",
209
+ padding: "5px 8px",
210
+ border: "none",
211
+ background: active === font.key ? "#f5f5f5" : "transparent",
212
+ cursor: "pointer",
213
+ fontFamily: font.cssFamily,
214
+ fontSize: "13px",
215
+ letterSpacing: 0,
216
+ textAlign: "left"
217
+ },
218
+ children: [
219
+ /* @__PURE__ */ jsx("span", { children: font.label }),
220
+ active === font.key && /* @__PURE__ */ jsx("span", { style: { fontSize: "8px", color: "#999", marginLeft: "8px" }, children: "\u25CF" })
221
+ ]
222
+ },
223
+ font.key
224
+ )),
225
+ /* @__PURE__ */ jsx("div", { style: { borderTop: "1px solid #e8e8e8", marginTop: "4px", paddingTop: "4px" }, children: /* @__PURE__ */ jsx(
226
+ "button",
227
+ {
228
+ onClick: reset,
229
+ style: {
230
+ display: "block",
231
+ width: "100%",
232
+ padding: "4px 8px",
233
+ border: "none",
234
+ background: "transparent",
235
+ cursor: "pointer",
236
+ fontSize: "11px",
237
+ color: "#aaa",
238
+ textAlign: "left",
239
+ letterSpacing: 0
240
+ },
241
+ children: "Reset"
242
+ }
243
+ ) }),
244
+ activeFeatures.length > 0 && /* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid #e8e8e8", marginTop: "4px", paddingTop: "4px" }, children: [
245
+ /* @__PURE__ */ jsx(
246
+ "div",
247
+ {
248
+ style: {
249
+ padding: "2px 8px 4px",
250
+ fontSize: "10px",
251
+ color: "#bbb",
252
+ textTransform: "uppercase",
253
+ letterSpacing: "0.06em"
254
+ },
255
+ children: "Features"
256
+ }
257
+ ),
258
+ activeFeatures.map((feat) => {
259
+ const on = featureEnabled[active]?.[feat.tag] ?? feat.enabled;
260
+ return /* @__PURE__ */ jsxs(
261
+ "button",
262
+ {
263
+ onClick: () => toggleFeature(active, feat.tag),
264
+ title: `font-feature-settings: "${feat.tag}" ${on ? 1 : 0}`,
265
+ style: {
266
+ display: "flex",
267
+ alignItems: "center",
268
+ justifyContent: "space-between",
269
+ width: "100%",
270
+ padding: "4px 8px",
271
+ border: "none",
272
+ background: "transparent",
273
+ cursor: "pointer",
274
+ fontSize: "12px",
275
+ textAlign: "left",
276
+ color: on ? "#111" : "#ccc",
277
+ fontFamily: "system-ui, sans-serif"
278
+ },
279
+ children: [
280
+ /* @__PURE__ */ jsx("span", { children: feat.label }),
281
+ /* @__PURE__ */ jsx(
282
+ "span",
283
+ {
284
+ style: {
285
+ fontSize: "9px",
286
+ fontFamily: "monospace",
287
+ color: on ? "#bbb" : "#ddd",
288
+ marginLeft: "8px",
289
+ flexShrink: 0
290
+ },
291
+ children: feat.tag
292
+ }
293
+ )
294
+ ]
295
+ },
296
+ feat.tag
297
+ );
298
+ })
299
+ ] }),
300
+ /* @__PURE__ */ jsxs("div", { style: { borderTop: "1px solid #e8e8e8", marginTop: "4px", paddingTop: "4px" }, children: [
301
+ /* @__PURE__ */ jsx(
302
+ "div",
303
+ {
304
+ style: {
305
+ padding: "2px 8px 4px",
306
+ fontSize: "10px",
307
+ color: "#bbb",
308
+ textTransform: "uppercase",
309
+ letterSpacing: "0.06em"
310
+ },
311
+ children: "Rendering"
312
+ }
313
+ ),
314
+ /* @__PURE__ */ jsx(
315
+ RenderSelect,
316
+ {
317
+ label: "text-rendering",
318
+ title: "text-rendering",
319
+ value: renderSettings.textRendering,
320
+ options: ["auto", "optimizeLegibility", "optimizeSpeed", "geometricPrecision"],
321
+ onChange: (v) => updateRender("textRendering", v)
322
+ }
323
+ ),
324
+ /* @__PURE__ */ jsx(
325
+ RenderSelect,
326
+ {
327
+ label: "webkit-smoothing",
328
+ title: "-webkit-font-smoothing",
329
+ value: renderSettings.webkitSmoothing,
330
+ options: ["auto", "none", "antialiased", "subpixel-antialiased"],
331
+ onChange: (v) => updateRender("webkitSmoothing", v)
332
+ }
333
+ ),
334
+ /* @__PURE__ */ jsx(
335
+ RenderSelect,
336
+ {
337
+ label: "moz-osx-smoothing",
338
+ title: "-moz-osx-font-smoothing",
339
+ value: renderSettings.mozSmoothing,
340
+ options: ["auto", "grayscale"],
341
+ onChange: (v) => updateRender("mozSmoothing", v)
342
+ }
343
+ )
344
+ ] })
345
+ ]
346
+ }
347
+ );
348
+ }
349
+ function RenderSelect({
350
+ label,
351
+ title,
352
+ value,
353
+ options,
354
+ onChange
355
+ }) {
356
+ return /* @__PURE__ */ jsxs(
357
+ "div",
358
+ {
359
+ style: {
360
+ display: "flex",
361
+ alignItems: "center",
362
+ justifyContent: "space-between",
363
+ padding: "3px 8px",
364
+ gap: "8px"
365
+ },
366
+ children: [
367
+ /* @__PURE__ */ jsx(
368
+ "span",
369
+ {
370
+ title,
371
+ style: {
372
+ fontSize: "11px",
373
+ color: "#888",
374
+ fontFamily: "monospace",
375
+ flexShrink: 0,
376
+ cursor: "default"
377
+ },
378
+ children: label
379
+ }
380
+ ),
381
+ /* @__PURE__ */ jsx(
382
+ "select",
383
+ {
384
+ value,
385
+ onChange: (e) => onChange(e.target.value),
386
+ style: {
387
+ fontSize: "11px",
388
+ border: "1px solid #e0e0e0",
389
+ background: "#fafafa",
390
+ padding: "2px 4px",
391
+ cursor: "pointer",
392
+ minWidth: 0,
393
+ maxWidth: "130px",
394
+ color: "#444"
395
+ },
396
+ children: options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
397
+ }
398
+ )
399
+ ]
400
+ }
401
+ );
402
+ }
403
+ export {
404
+ FontSwitcher
405
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/script.ts
21
+ var script_exports = {};
22
+ __export(script_exports, {
23
+ getFOUCScript: () => getFOUCScript
24
+ });
25
+ module.exports = __toCommonJS(script_exports);
26
+ function getFOUCScript(config) {
27
+ if (config.finalFont) return "";
28
+ const storageKey = config.storageKey ?? "font-switcher-active";
29
+ const validKeys = config.fonts.map((f) => f.key);
30
+ const featureDefaults = {};
31
+ for (const f of config.fonts) {
32
+ if (f.features?.length) {
33
+ featureDefaults[f.key] = Object.fromEntries(f.features.map((ft) => [ft.tag, ft.enabled]));
34
+ }
35
+ }
36
+ return `(function(){try{
37
+ var SK=${JSON.stringify(storageKey)},VK=${JSON.stringify(validKeys)},FD=${JSON.stringify(featureDefaults)},DF=${JSON.stringify(config.defaultFont)};
38
+ var k=localStorage.getItem(SK),af=(k&&VK.indexOf(k)!==-1)?k:DF;
39
+ if(k&&VK.indexOf(k)!==-1){document.documentElement.dataset.font=k;}
40
+ var tags=Object.assign({},FD[af]||{}),sf=localStorage.getItem(SK+'-features');
41
+ if(sf){var pf=JSON.parse(sf);if(pf&&pf[af])Object.assign(tags,pf[af]);}
42
+ var ks=Object.keys(tags),fs=ks.length?ks.map(function(t){return '"'+t+'" '+(tags[t]?1:0);}).join(', '):'normal';
43
+ var rd={textRendering:'auto',webkitSmoothing:'auto',mozSmoothing:'auto'},sr=localStorage.getItem(SK+'-render');
44
+ if(sr){var pr=JSON.parse(sr);for(var rk in pr){rd[rk]=pr[rk];}}
45
+ var css='html {\\n font-feature-settings: '+fs+';\\n text-rendering: '+rd.textRendering+';\\n -webkit-font-smoothing: '+rd.webkitSmoothing+';\\n -moz-osx-font-smoothing: '+rd.mozSmoothing+';\\n}';
46
+ var el=document.getElementById('font-switcher-rt');
47
+ if(!el){el=document.createElement('style');el.id='font-switcher-rt';document.head.appendChild(el);}
48
+ el.textContent=css;
49
+ }catch(e){}})();`;
50
+ }
51
+ // Annotate the CommonJS export names for ESM import in node:
52
+ 0 && (module.exports = {
53
+ getFOUCScript
54
+ });
@@ -0,0 +1,52 @@
1
+ interface FontFeature {
2
+ tag: string;
3
+ label: string;
4
+ enabled: boolean;
5
+ }
6
+ interface FontMetrics {
7
+ capHeight: number;
8
+ ascent: number;
9
+ descent: number;
10
+ lineGap: number;
11
+ unitsPerEm: number;
12
+ xHeight: number;
13
+ }
14
+ interface FontConfig {
15
+ key: string;
16
+ label: string;
17
+ /** Value for CSS font-family — can be a var() ref or a literal stack */
18
+ cssFamily: string;
19
+ /** Raw font metrics. If @capsizecss/core is installed, trims are computed from these. */
20
+ metrics?: FontMetrics;
21
+ /** OpenType feature settings. If omitted, auto-detected from font file by the Vite plugin. */
22
+ features?: FontFeature[];
23
+ }
24
+ interface FontSwitcherConfig {
25
+ fonts: FontConfig[];
26
+ defaultFont: string;
27
+ /** Path to CSS file scanned for @font-face and --font-* declarations. Default: 'src/styles/index.css' */
28
+ cssFile?: string;
29
+ /** localStorage key for the active font. Default: 'font-switcher-active' */
30
+ storageKey?: string;
31
+ /** URL param that reveals the panel. Default: 'fonts' */
32
+ revealParam?: string;
33
+ /** Keyboard shortcut that toggles the panel. Default: 'ctrl+shift+f' */
34
+ revealShortcut?: string;
35
+ /** CSS selector for capsize elements. Set false to disable trim injection. Default: '.capsize' */
36
+ capsizeSelector?: string | false;
37
+ /** Font size in px used for capsize trim computation. Default: 16 */
38
+ fontSize?: number;
39
+ /** When set: locks the font, disables all switcher output. Set this when client decides, then remove the package. */
40
+ finalFont?: string;
41
+ }
42
+
43
+ /**
44
+ * Returns a small inline script string that applies the stored font before first paint,
45
+ * preventing a flash of the default font on reload.
46
+ *
47
+ * Inject into <head> before other content:
48
+ * <script dangerouslySetInnerHTML={{ __html: getFOUCScript(config) }} />
49
+ */
50
+ declare function getFOUCScript(config: FontSwitcherConfig): string;
51
+
52
+ export { getFOUCScript };
@@ -0,0 +1,52 @@
1
+ interface FontFeature {
2
+ tag: string;
3
+ label: string;
4
+ enabled: boolean;
5
+ }
6
+ interface FontMetrics {
7
+ capHeight: number;
8
+ ascent: number;
9
+ descent: number;
10
+ lineGap: number;
11
+ unitsPerEm: number;
12
+ xHeight: number;
13
+ }
14
+ interface FontConfig {
15
+ key: string;
16
+ label: string;
17
+ /** Value for CSS font-family — can be a var() ref or a literal stack */
18
+ cssFamily: string;
19
+ /** Raw font metrics. If @capsizecss/core is installed, trims are computed from these. */
20
+ metrics?: FontMetrics;
21
+ /** OpenType feature settings. If omitted, auto-detected from font file by the Vite plugin. */
22
+ features?: FontFeature[];
23
+ }
24
+ interface FontSwitcherConfig {
25
+ fonts: FontConfig[];
26
+ defaultFont: string;
27
+ /** Path to CSS file scanned for @font-face and --font-* declarations. Default: 'src/styles/index.css' */
28
+ cssFile?: string;
29
+ /** localStorage key for the active font. Default: 'font-switcher-active' */
30
+ storageKey?: string;
31
+ /** URL param that reveals the panel. Default: 'fonts' */
32
+ revealParam?: string;
33
+ /** Keyboard shortcut that toggles the panel. Default: 'ctrl+shift+f' */
34
+ revealShortcut?: string;
35
+ /** CSS selector for capsize elements. Set false to disable trim injection. Default: '.capsize' */
36
+ capsizeSelector?: string | false;
37
+ /** Font size in px used for capsize trim computation. Default: 16 */
38
+ fontSize?: number;
39
+ /** When set: locks the font, disables all switcher output. Set this when client decides, then remove the package. */
40
+ finalFont?: string;
41
+ }
42
+
43
+ /**
44
+ * Returns a small inline script string that applies the stored font before first paint,
45
+ * preventing a flash of the default font on reload.
46
+ *
47
+ * Inject into <head> before other content:
48
+ * <script dangerouslySetInnerHTML={{ __html: getFOUCScript(config) }} />
49
+ */
50
+ declare function getFOUCScript(config: FontSwitcherConfig): string;
51
+
52
+ export { getFOUCScript };
package/dist/script.js ADDED
@@ -0,0 +1,29 @@
1
+ // src/script.ts
2
+ function getFOUCScript(config) {
3
+ if (config.finalFont) return "";
4
+ const storageKey = config.storageKey ?? "font-switcher-active";
5
+ const validKeys = config.fonts.map((f) => f.key);
6
+ const featureDefaults = {};
7
+ for (const f of config.fonts) {
8
+ if (f.features?.length) {
9
+ featureDefaults[f.key] = Object.fromEntries(f.features.map((ft) => [ft.tag, ft.enabled]));
10
+ }
11
+ }
12
+ return `(function(){try{
13
+ var SK=${JSON.stringify(storageKey)},VK=${JSON.stringify(validKeys)},FD=${JSON.stringify(featureDefaults)},DF=${JSON.stringify(config.defaultFont)};
14
+ var k=localStorage.getItem(SK),af=(k&&VK.indexOf(k)!==-1)?k:DF;
15
+ if(k&&VK.indexOf(k)!==-1){document.documentElement.dataset.font=k;}
16
+ var tags=Object.assign({},FD[af]||{}),sf=localStorage.getItem(SK+'-features');
17
+ if(sf){var pf=JSON.parse(sf);if(pf&&pf[af])Object.assign(tags,pf[af]);}
18
+ var ks=Object.keys(tags),fs=ks.length?ks.map(function(t){return '"'+t+'" '+(tags[t]?1:0);}).join(', '):'normal';
19
+ var rd={textRendering:'auto',webkitSmoothing:'auto',mozSmoothing:'auto'},sr=localStorage.getItem(SK+'-render');
20
+ if(sr){var pr=JSON.parse(sr);for(var rk in pr){rd[rk]=pr[rk];}}
21
+ var css='html {\\n font-feature-settings: '+fs+';\\n text-rendering: '+rd.textRendering+';\\n -webkit-font-smoothing: '+rd.webkitSmoothing+';\\n -moz-osx-font-smoothing: '+rd.mozSmoothing+';\\n}';
22
+ var el=document.getElementById('font-switcher-rt');
23
+ if(!el){el=document.createElement('style');el.id='font-switcher-rt';document.head.appendChild(el);}
24
+ el.textContent=css;
25
+ }catch(e){}})();`;
26
+ }
27
+ export {
28
+ getFOUCScript
29
+ };