@sorb/leaf 0.2.1 → 0.4.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 +8 -2
- package/dist/core.js +723 -0
- package/dist/core.js.map +7 -0
- package/dist/core.mjs +701 -0
- package/dist/core.mjs.map +7 -0
- package/dist/index.js +985 -65
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +983 -63
- package/dist/index.mjs.map +4 -4
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -27,18 +27,40 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
29
|
// src/index.js
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
30
|
+
var src_exports2 = {};
|
|
31
|
+
__export(src_exports2, {
|
|
32
|
+
MODE_STYLESHEET_ID: () => MODE_STYLESHEET_ID,
|
|
32
33
|
PreviewBanner: () => PreviewBanner,
|
|
33
34
|
SorbProvider: () => SorbProvider,
|
|
35
|
+
ThemeToggle: () => ThemeToggle,
|
|
36
|
+
angularMaterialTarget: () => angularMaterialTarget,
|
|
37
|
+
applyLegacyMap: () => applyLegacyMap,
|
|
38
|
+
buildModeStylesheet: () => buildModeStylesheet,
|
|
39
|
+
clearLegacyMap: () => clearLegacyMap,
|
|
40
|
+
clearModeStylesheet: () => clearModeStylesheet,
|
|
41
|
+
computeLegacyOverride: () => computeLegacyOverride,
|
|
42
|
+
dataThemeDarkMode: () => dataThemeDarkMode,
|
|
43
|
+
indexLegacyMap: () => indexLegacyMap,
|
|
44
|
+
injectModeStylesheet: () => injectModeStylesheet,
|
|
45
|
+
mantineTarget: () => mantineTarget,
|
|
46
|
+
muiTarget: () => muiTarget,
|
|
47
|
+
normalizeProp: () => normalizeProp,
|
|
48
|
+
normalizeValue: () => normalizeValue,
|
|
49
|
+
primevueTarget: () => primevueTarget,
|
|
50
|
+
reactBootstrapTarget: () => reactBootstrapTarget,
|
|
34
51
|
sanitizeCssValue: () => sanitizeCssValue,
|
|
52
|
+
shadcnTarget: () => shadcnTarget,
|
|
53
|
+
sorbInit: () => sorbInit,
|
|
54
|
+
tailwindDarkMode: () => tailwindDarkMode,
|
|
55
|
+
tailwindV4Target: () => tailwindV4Target,
|
|
35
56
|
useIsPreview: () => useIsPreview,
|
|
36
57
|
usePreviewState: () => usePreviewState,
|
|
58
|
+
useTheme: () => useTheme,
|
|
37
59
|
useToken: () => useToken,
|
|
38
60
|
useTokens: () => useTokens,
|
|
39
61
|
verifyResolved: () => verifyResolved
|
|
40
62
|
});
|
|
41
|
-
module.exports = __toCommonJS(
|
|
63
|
+
module.exports = __toCommonJS(src_exports2);
|
|
42
64
|
|
|
43
65
|
// src/TokenProvider.jsx
|
|
44
66
|
var import_react2 = __toESM(require("react"));
|
|
@@ -134,6 +156,170 @@ var applyTokens = (tokens) => {
|
|
|
134
156
|
root.style.setProperty(`--${key}`, result.value);
|
|
135
157
|
});
|
|
136
158
|
};
|
|
159
|
+
var clearTokenOverrides = (tokens) => {
|
|
160
|
+
const root = document.documentElement;
|
|
161
|
+
Object.keys(tokens).forEach((key) => {
|
|
162
|
+
root.style.removeProperty(`--${key}`);
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
var MODE_STYLESHEET_ID = "sorb-tokens";
|
|
166
|
+
var injectModeStylesheet = (css) => {
|
|
167
|
+
let tag = document.getElementById(MODE_STYLESHEET_ID);
|
|
168
|
+
if (!tag) {
|
|
169
|
+
tag = document.createElement("style");
|
|
170
|
+
tag.id = MODE_STYLESHEET_ID;
|
|
171
|
+
document.head.appendChild(tag);
|
|
172
|
+
}
|
|
173
|
+
tag.textContent = css;
|
|
174
|
+
};
|
|
175
|
+
var clearModeStylesheet = () => {
|
|
176
|
+
const tag = document.getElementById(MODE_STYLESHEET_ID);
|
|
177
|
+
if (tag && tag.parentNode) tag.parentNode.removeChild(tag);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// src/modeStylesheet.js
|
|
181
|
+
var buildModeStylesheet = (lightVars, darkVars, darkMode) => {
|
|
182
|
+
const lightDecls = normalizeDecls(lightVars);
|
|
183
|
+
const hasDark = !!darkMode && !!darkVars && Object.keys(darkVars).length > 0;
|
|
184
|
+
if (!hasDark) {
|
|
185
|
+
return `:root {
|
|
186
|
+
${indent(lightDecls)}
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
}
|
|
190
|
+
const darkDecls = normalizeDecls(darkVars);
|
|
191
|
+
const darkSelector = darkMode.darkSelector;
|
|
192
|
+
const lightSelector = darkMode.lightSelector;
|
|
193
|
+
const mediaScopeSelector = lightSelector ? `:root:not(${lightSelector})` : ":root";
|
|
194
|
+
const lines = [];
|
|
195
|
+
lines.push(":root {");
|
|
196
|
+
lines.push(indent([...lightDecls, "color-scheme: light;"]));
|
|
197
|
+
lines.push("}");
|
|
198
|
+
lines.push("@media (prefers-color-scheme: dark) {");
|
|
199
|
+
lines.push(` ${mediaScopeSelector} {`);
|
|
200
|
+
lines.push(indent([...darkDecls, "color-scheme: dark;"], 2));
|
|
201
|
+
lines.push(" }");
|
|
202
|
+
lines.push("}");
|
|
203
|
+
lines.push(`${darkSelector} {`);
|
|
204
|
+
lines.push(indent([...darkDecls, "color-scheme: dark;"]));
|
|
205
|
+
lines.push("}");
|
|
206
|
+
if (lightSelector) {
|
|
207
|
+
lines.push(`${lightSelector} {`);
|
|
208
|
+
lines.push(indent([...lightDecls, "color-scheme: light;"]));
|
|
209
|
+
lines.push("}");
|
|
210
|
+
}
|
|
211
|
+
return `${lines.join("\n")}
|
|
212
|
+
`;
|
|
213
|
+
};
|
|
214
|
+
var normalizeDecls = (vars) => {
|
|
215
|
+
if (!vars) return [];
|
|
216
|
+
return Object.entries(vars).reduce((acc, [key, value]) => {
|
|
217
|
+
const result = sanitizeCssValue(String(value));
|
|
218
|
+
if (!result.ok) return acc;
|
|
219
|
+
const cssVar = key.startsWith("--") ? key : `--${key}`;
|
|
220
|
+
acc.push(`${cssVar}: ${result.value};`);
|
|
221
|
+
return acc;
|
|
222
|
+
}, []);
|
|
223
|
+
};
|
|
224
|
+
var indent = (lines, level = 1) => {
|
|
225
|
+
const pad = " ".repeat(level);
|
|
226
|
+
return lines.map((l) => `${pad}${l}`).join("\n");
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// node_modules/@sorb/core/src/index.js
|
|
230
|
+
var TIERS = Object.freeze(["component", "semantic", "primitive"]);
|
|
231
|
+
var TIER_RANK = Object.freeze({ component: 0, semantic: 1, primitive: 2 });
|
|
232
|
+
var DEFAULT_ROLE_IDS = Object.freeze({
|
|
233
|
+
color: Object.freeze([
|
|
234
|
+
"color.surface",
|
|
235
|
+
"color.surface-raised",
|
|
236
|
+
"color.surface-sunken",
|
|
237
|
+
"color.ink",
|
|
238
|
+
"color.ink-muted",
|
|
239
|
+
"color.ink-on-brand",
|
|
240
|
+
"color.brand",
|
|
241
|
+
"color.brand-hover",
|
|
242
|
+
"color.brand-contrast",
|
|
243
|
+
"color.accent",
|
|
244
|
+
"color.accent-hover",
|
|
245
|
+
"color.accent-contrast",
|
|
246
|
+
"color.danger",
|
|
247
|
+
"color.danger-hover",
|
|
248
|
+
"color.success",
|
|
249
|
+
"color.success-hover",
|
|
250
|
+
"color.focus-ring",
|
|
251
|
+
"color.border",
|
|
252
|
+
"color.border-subtle",
|
|
253
|
+
"color.border-strong"
|
|
254
|
+
]),
|
|
255
|
+
radius: Object.freeze(["radius.control", "radius.card", "radius.pill"]),
|
|
256
|
+
shadow: Object.freeze(["shadow.raised", "shadow.overlay"]),
|
|
257
|
+
typography: Object.freeze([
|
|
258
|
+
"typography.display.fontSize",
|
|
259
|
+
"typography.display.fontWeight",
|
|
260
|
+
"typography.display.lineHeight",
|
|
261
|
+
"typography.heading.fontSize",
|
|
262
|
+
"typography.heading.fontWeight",
|
|
263
|
+
"typography.heading.lineHeight",
|
|
264
|
+
"typography.body.fontSize",
|
|
265
|
+
"typography.body.fontWeight",
|
|
266
|
+
"typography.body.lineHeight",
|
|
267
|
+
"typography.caption.fontSize",
|
|
268
|
+
"typography.caption.fontWeight",
|
|
269
|
+
"typography.caption.lineHeight"
|
|
270
|
+
])
|
|
271
|
+
});
|
|
272
|
+
var ALL_ROLE_IDS = Object.freeze([
|
|
273
|
+
...DEFAULT_ROLE_IDS.color,
|
|
274
|
+
...DEFAULT_ROLE_IDS.radius,
|
|
275
|
+
...DEFAULT_ROLE_IDS.shadow,
|
|
276
|
+
...DEFAULT_ROLE_IDS.typography
|
|
277
|
+
]);
|
|
278
|
+
var connectors = Object.freeze({
|
|
279
|
+
source: /* @__PURE__ */ new Map(),
|
|
280
|
+
codeSource: /* @__PURE__ */ new Map(),
|
|
281
|
+
target: /* @__PURE__ */ new Map()
|
|
282
|
+
});
|
|
283
|
+
function registerTarget(adapter) {
|
|
284
|
+
if (!adapter || typeof adapter.id !== "string" || !adapter.id) {
|
|
285
|
+
throw new Error("registerTarget: adapter.id must be a non-empty string");
|
|
286
|
+
}
|
|
287
|
+
if (typeof adapter.emitFormat !== "string" || !adapter.emitFormat) {
|
|
288
|
+
throw new Error(`registerTarget(${JSON.stringify(adapter.id)}): emitFormat must be a non-empty string`);
|
|
289
|
+
}
|
|
290
|
+
if (!Array.isArray(adapter.expectPrefixes)) {
|
|
291
|
+
throw new Error(`registerTarget(${JSON.stringify(adapter.id)}): expectPrefixes must be an array`);
|
|
292
|
+
}
|
|
293
|
+
if (connectors.target.has(adapter.id)) {
|
|
294
|
+
console.warn(`registerTarget: overwriting existing target adapter ${JSON.stringify(adapter.id)}`);
|
|
295
|
+
}
|
|
296
|
+
connectors.target.set(adapter.id, adapter);
|
|
297
|
+
return adapter;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/targets/reactBootstrap.js
|
|
301
|
+
var SORB_TOKENSET_FORMAT_ID = "sorb/tokenset-esm";
|
|
302
|
+
var reactBootstrapTarget = {
|
|
303
|
+
id: "react-bootstrap",
|
|
304
|
+
emitFormat: SORB_TOKENSET_FORMAT_ID,
|
|
305
|
+
// The Bootstrap-styled vocab namespace (matches `sorb-demo/src/sorbConfig.js`'s
|
|
306
|
+
// `preview.expectPrefixes: ['bs-']`).
|
|
307
|
+
expectPrefixes: ["bs-"],
|
|
308
|
+
// Left undefined on purpose — see file header.
|
|
309
|
+
inject: void 0,
|
|
310
|
+
// Bootstrap 5.3's native dark-mode convention (real-dark-mode spec D1): a
|
|
311
|
+
// `data-bs-theme` attribute on any ancestor (Bootstrap recommends
|
|
312
|
+
// `<html>`) selects the mode; absent ⇒ OS `prefers-color-scheme` governs.
|
|
313
|
+
darkMode: {
|
|
314
|
+
strategy: "attribute",
|
|
315
|
+
attribute: "data-bs-theme",
|
|
316
|
+
darkSelector: '[data-bs-theme="dark"]',
|
|
317
|
+
lightSelector: '[data-bs-theme="light"]'
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
if (typeof registerTarget === "function") {
|
|
321
|
+
registerTarget(reactBootstrapTarget);
|
|
322
|
+
}
|
|
137
323
|
|
|
138
324
|
// src/previewGuard.js
|
|
139
325
|
var DEFAULT_ORIGIN = "http://localhost:7777";
|
|
@@ -176,6 +362,26 @@ var shouldLoadPreview = (config) => {
|
|
|
176
362
|
return { allowed: false, origin, reason: "origin-not-allowlisted" };
|
|
177
363
|
};
|
|
178
364
|
|
|
365
|
+
// src/previewVocab.js
|
|
366
|
+
var countMatchingPrefixes = (tokens, prefixes) => {
|
|
367
|
+
const list = Array.isArray(prefixes) ? prefixes : [];
|
|
368
|
+
return Object.keys(tokens || {}).filter((key) => list.some((p) => key.startsWith(p))).length;
|
|
369
|
+
};
|
|
370
|
+
var checkPreviewVocabulary = ({ tokens, expectPrefixes, previewId }) => {
|
|
371
|
+
if (!Array.isArray(expectPrefixes) || expectPrefixes.length === 0) return false;
|
|
372
|
+
const appliedCount = Object.keys(tokens || {}).length;
|
|
373
|
+
if (appliedCount === 0) return false;
|
|
374
|
+
const matched = countMatchingPrefixes(tokens, expectPrefixes);
|
|
375
|
+
if (matched > 0) return false;
|
|
376
|
+
try {
|
|
377
|
+
console.warn(
|
|
378
|
+
`[Sorb] preview ${previewId ? `"${previewId}" ` : ""}applied ${appliedCount} tokens but none match expected prefixes ${JSON.stringify(expectPrefixes)} \u2014 the app may not visibly re-skin (token-vocabulary mismatch).`
|
|
379
|
+
);
|
|
380
|
+
} catch (e) {
|
|
381
|
+
}
|
|
382
|
+
return true;
|
|
383
|
+
};
|
|
384
|
+
|
|
179
385
|
// src/bridgeAuth.js
|
|
180
386
|
var bridgeHeaders = (key, base) => {
|
|
181
387
|
const headers = base ? { ...base } : {};
|
|
@@ -185,8 +391,163 @@ var bridgeHeaders = (key, base) => {
|
|
|
185
391
|
return headers;
|
|
186
392
|
};
|
|
187
393
|
|
|
188
|
-
// src/
|
|
189
|
-
var
|
|
394
|
+
// src/connection.js
|
|
395
|
+
var DEFAULT_CLOUD_BASE = "https://api.sorbcloud.com";
|
|
396
|
+
var getOrgKey = (config) => {
|
|
397
|
+
if (!config) return null;
|
|
398
|
+
const key = config.orgKey || config.publishableKey;
|
|
399
|
+
return typeof key === "string" && key.trim() !== "" ? key.trim() : null;
|
|
400
|
+
};
|
|
401
|
+
var shouldResolveOrgConnection = (config) => {
|
|
402
|
+
const key = getOrgKey(config);
|
|
403
|
+
if (!key) return false;
|
|
404
|
+
const explicitOrigin = config && config.preview && config.preview.origin;
|
|
405
|
+
return !(typeof explicitOrigin === "string" && explicitOrigin.trim() !== "");
|
|
406
|
+
};
|
|
407
|
+
var resolveOrgConnection = async (orgKey, opts) => {
|
|
408
|
+
const { cloudBase = DEFAULT_CLOUD_BASE, fetchImpl } = opts || {};
|
|
409
|
+
const doFetch = fetchImpl || (typeof fetch !== "undefined" ? fetch : null);
|
|
410
|
+
if (!doFetch || typeof orgKey !== "string" || orgKey.trim() === "") return null;
|
|
411
|
+
try {
|
|
412
|
+
const base = cloudBase.replace(/\/$/, "");
|
|
413
|
+
const url = `${base}/api/orgs/resolve?key=${encodeURIComponent(orgKey.trim())}`;
|
|
414
|
+
const res = await doFetch(url);
|
|
415
|
+
if (!res || !res.ok) return null;
|
|
416
|
+
const data = await res.json();
|
|
417
|
+
if (!data || typeof data !== "object") return null;
|
|
418
|
+
if (typeof data.bridgeUrl !== "string" || data.bridgeUrl.trim() === "") return null;
|
|
419
|
+
const bridgeMode = typeof data.bridgeMode === "string" ? data.bridgeMode : "C";
|
|
420
|
+
return {
|
|
421
|
+
bridgeMode,
|
|
422
|
+
bridgeUrl: data.bridgeUrl,
|
|
423
|
+
orgId: typeof data.orgId === "string" ? data.orgId : null,
|
|
424
|
+
tokenSource: typeof data.tokenSource === "string" ? data.tokenSource : null,
|
|
425
|
+
// sorb-cloud's /api/orgs/resolve returns this as a boolean (entitlement
|
|
426
|
+
// flag), not an object — see cloud src/lib/orgResolve.ts.
|
|
427
|
+
previewPersistence: typeof data.previewPersistence === "boolean" ? data.previewPersistence : null,
|
|
428
|
+
transport: data.transport === "poll" || data.transport === "sse" ? data.transport : bridgeMode === "A" ? "sse" : "poll"
|
|
429
|
+
};
|
|
430
|
+
} catch (e) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
var buildEffectivePreviewConfig = (config, resolved) => {
|
|
435
|
+
const base = config && config.preview || {};
|
|
436
|
+
if (!resolved) return base;
|
|
437
|
+
const orgKey = getOrgKey(config);
|
|
438
|
+
return {
|
|
439
|
+
...base,
|
|
440
|
+
enabled: true,
|
|
441
|
+
origin: resolved.bridgeUrl,
|
|
442
|
+
allowedOrigins: [...Array.isArray(base.allowedOrigins) ? base.allowedOrigins : [], resolved.bridgeUrl],
|
|
443
|
+
key: base.key || orgKey || void 0
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
var buildEffectiveConfig = (config, resolved) => {
|
|
447
|
+
if (!resolved) return config;
|
|
448
|
+
return { ...config, preview: buildEffectivePreviewConfig(config, resolved) };
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// src/sse.js
|
|
452
|
+
var buildSubscribeUrl = (bridgeUrl, orgId, previewId, key) => {
|
|
453
|
+
const base = String(bridgeUrl).replace(/\/$/, "");
|
|
454
|
+
const path = `${base}/orgs/${encodeURIComponent(orgId)}/preview/${encodeURIComponent(previewId)}/subscribe`;
|
|
455
|
+
if (typeof key === "string" && key.trim() !== "") {
|
|
456
|
+
return `${path}?key=${encodeURIComponent(key.trim())}`;
|
|
457
|
+
}
|
|
458
|
+
return path;
|
|
459
|
+
};
|
|
460
|
+
var parsePreviewFrame = (raw) => {
|
|
461
|
+
let frame;
|
|
462
|
+
try {
|
|
463
|
+
frame = JSON.parse(raw);
|
|
464
|
+
} catch (e) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
if (!frame || typeof frame !== "object") return null;
|
|
468
|
+
if (frame.type === "ping") return { type: "ping" };
|
|
469
|
+
if (frame.type === "delete") return { type: "delete", tokens: null };
|
|
470
|
+
if ((frame.type === "snapshot" || frame.type === "update") && frame.tokens && typeof frame.tokens === "object") {
|
|
471
|
+
return { type: frame.type, tokens: frame.tokens };
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
};
|
|
475
|
+
var createPreviewSubscription = ({ EventSourceImpl, url, onTokens, onDelete, onError }) => {
|
|
476
|
+
if (typeof EventSourceImpl !== "function") return null;
|
|
477
|
+
const es = new EventSourceImpl(url);
|
|
478
|
+
es.onmessage = (evt) => {
|
|
479
|
+
const parsed = parsePreviewFrame(evt && evt.data);
|
|
480
|
+
if (!parsed || parsed.type === "ping") return;
|
|
481
|
+
if (parsed.type === "delete") {
|
|
482
|
+
if (onDelete) onDelete();
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
onTokens(parsed.tokens);
|
|
486
|
+
};
|
|
487
|
+
const handleError = (evt) => {
|
|
488
|
+
if (onError) onError(evt);
|
|
489
|
+
};
|
|
490
|
+
if (typeof es.addEventListener === "function") {
|
|
491
|
+
es.addEventListener("error", handleError);
|
|
492
|
+
} else {
|
|
493
|
+
es.onerror = handleError;
|
|
494
|
+
}
|
|
495
|
+
return () => {
|
|
496
|
+
try {
|
|
497
|
+
es.close();
|
|
498
|
+
} catch (e) {
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
// src/previewMode.js
|
|
504
|
+
var isModeAwarePreviewBody = (body) => !!body && typeof body === "object" && !Array.isArray(body) && "tokens" in body;
|
|
505
|
+
var resolvePreviewBody = (body, fallbackDarkMode) => {
|
|
506
|
+
if (!isModeAwarePreviewBody(body)) {
|
|
507
|
+
return { kind: "flat", tokens: (
|
|
508
|
+
/** @type {import('./types').TokenSet} */
|
|
509
|
+
body
|
|
510
|
+
) };
|
|
511
|
+
}
|
|
512
|
+
const wrapper = (
|
|
513
|
+
/** @type {{ tokens: import('./types').TokenSet, darkTokens?: import('./types').TokenSet, darkMode?: import('@sorb/core').DarkModeConvention }} */
|
|
514
|
+
body
|
|
515
|
+
);
|
|
516
|
+
const darkTokens = wrapper.darkTokens;
|
|
517
|
+
if (darkTokens && Object.keys(darkTokens).length > 0) {
|
|
518
|
+
return {
|
|
519
|
+
kind: "mode-aware",
|
|
520
|
+
lightTokens: wrapper.tokens,
|
|
521
|
+
darkTokens,
|
|
522
|
+
darkMode: wrapper.darkMode ?? fallbackDarkMode
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
return { kind: "flat", tokens: wrapper.tokens };
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
// src/modeAction.js
|
|
529
|
+
var darkClassName = (darkModeConvention) => {
|
|
530
|
+
const selector = String(darkModeConvention?.darkSelector || "").trim();
|
|
531
|
+
const match = /^\.([a-zA-Z0-9_-]+)$/.exec(selector);
|
|
532
|
+
return match ? match[1] : "dark";
|
|
533
|
+
};
|
|
534
|
+
var resolveModeAction = (darkModeConvention, next) => {
|
|
535
|
+
const strategy = darkModeConvention?.strategy || "attribute";
|
|
536
|
+
if (strategy === "media") {
|
|
537
|
+
return { type: "none" };
|
|
538
|
+
}
|
|
539
|
+
if (strategy === "class") {
|
|
540
|
+
const className = darkClassName(darkModeConvention);
|
|
541
|
+
return next === "dark" ? { type: "class-add", className } : { type: "class-remove", className };
|
|
542
|
+
}
|
|
543
|
+
const attribute = darkModeConvention?.attribute || "data-bs-theme";
|
|
544
|
+
return next === "auto" ? { type: "attr-remove", attribute } : { type: "attr-set", attribute, value: next };
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
// src/core.js
|
|
548
|
+
var EventSourceCtor = typeof EventSource !== "undefined" ? EventSource : null;
|
|
549
|
+
var matchMediaFn = typeof matchMedia !== "undefined" ? matchMedia : null;
|
|
550
|
+
var DARK_MEDIA_QUERY = "(prefers-color-scheme: dark)";
|
|
190
551
|
var devWarn = (msg) => {
|
|
191
552
|
try {
|
|
192
553
|
if (typeof process !== "undefined" && process.env && true) {
|
|
@@ -195,54 +556,187 @@ var devWarn = (msg) => {
|
|
|
195
556
|
} catch (e) {
|
|
196
557
|
}
|
|
197
558
|
};
|
|
198
|
-
var
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
);
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
559
|
+
var warnedDeprecations = /* @__PURE__ */ new Set();
|
|
560
|
+
function warnDeprecated(resolved) {
|
|
561
|
+
if (typeof process !== "undefined" && false) return;
|
|
562
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
563
|
+
const token = resolved[i];
|
|
564
|
+
if (!token.deprecated) continue;
|
|
565
|
+
if (warnedDeprecations.has(token.id)) continue;
|
|
566
|
+
warnedDeprecations.add(token.id);
|
|
567
|
+
const replacedBy = token.replacedBy || token.$extensions && token.$extensions.sorb && token.$extensions.sorb.replacedBy || null;
|
|
568
|
+
if (replacedBy) {
|
|
569
|
+
console.warn("[@sorb/leaf] Deprecated token: " + token.id + " \u2014 use " + replacedBy + " instead");
|
|
570
|
+
} else {
|
|
571
|
+
console.warn("[@sorb/leaf] Deprecated token: " + token.id + " is deprecated");
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function sorbInit(config) {
|
|
576
|
+
let activeTokens = config.tokens;
|
|
577
|
+
let isPreview = false;
|
|
578
|
+
let previewId = null;
|
|
579
|
+
let previewMismatch = false;
|
|
580
|
+
let pollId = null;
|
|
581
|
+
let cancelled = false;
|
|
582
|
+
let unsubscribeSSE = null;
|
|
583
|
+
const hasDarkMode = !!(config.darkTokens && Object.keys(config.darkTokens).length > 0);
|
|
584
|
+
const darkModeConvention = config.darkModeConvention || reactBootstrapTarget.darkMode;
|
|
585
|
+
let mode = "auto";
|
|
586
|
+
let systemScheme = matchMediaFn ? matchMediaFn(DARK_MEDIA_QUERY).matches ? "dark" : "light" : "light";
|
|
587
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
588
|
+
const getState = () => ({
|
|
589
|
+
tokens: activeTokens,
|
|
590
|
+
isPreview,
|
|
591
|
+
previewId,
|
|
592
|
+
previewMismatch,
|
|
593
|
+
mode,
|
|
594
|
+
resolvedScheme: mode === "auto" ? systemScheme : mode
|
|
595
|
+
});
|
|
596
|
+
const notify = () => {
|
|
597
|
+
const state = getState();
|
|
598
|
+
listeners.forEach((listener) => listener(state));
|
|
599
|
+
};
|
|
600
|
+
const subscribe = (listener) => {
|
|
601
|
+
listeners.add(listener);
|
|
602
|
+
return () => listeners.delete(listener);
|
|
603
|
+
};
|
|
604
|
+
let mql = null;
|
|
605
|
+
const onSchemeChange = (e) => {
|
|
606
|
+
systemScheme = e.matches ? "dark" : "light";
|
|
607
|
+
notify();
|
|
608
|
+
};
|
|
609
|
+
if (matchMediaFn) {
|
|
610
|
+
mql = matchMediaFn(DARK_MEDIA_QUERY);
|
|
611
|
+
if (typeof mql.addEventListener === "function") mql.addEventListener("change", onSchemeChange);
|
|
612
|
+
else if (typeof mql.addListener === "function") mql.addListener(onSchemeChange);
|
|
613
|
+
}
|
|
614
|
+
let inlineTokens = null;
|
|
615
|
+
const applyFlat = (tokens) => {
|
|
616
|
+
clearModeStylesheet();
|
|
617
|
+
applyTokens(tokens);
|
|
618
|
+
inlineTokens = tokens;
|
|
619
|
+
};
|
|
620
|
+
const applyModeAware = (lightTokens, darkTokens, convention) => {
|
|
621
|
+
if (inlineTokens) {
|
|
622
|
+
clearTokenOverrides(inlineTokens);
|
|
623
|
+
inlineTokens = null;
|
|
624
|
+
}
|
|
625
|
+
injectModeStylesheet(buildModeStylesheet(lightTokens, darkTokens, convention));
|
|
626
|
+
};
|
|
627
|
+
const loadCommitted = () => {
|
|
628
|
+
if (hasDarkMode) {
|
|
629
|
+
applyModeAware(config.tokens, config.darkTokens, darkModeConvention);
|
|
630
|
+
} else {
|
|
631
|
+
applyFlat(config.tokens);
|
|
632
|
+
}
|
|
633
|
+
activeTokens = config.tokens;
|
|
634
|
+
isPreview = false;
|
|
635
|
+
previewId = null;
|
|
636
|
+
previewMismatch = false;
|
|
637
|
+
notify();
|
|
638
|
+
};
|
|
639
|
+
const applyPreviewTokens = (body, id, effectiveConfig) => {
|
|
640
|
+
const resolved = resolvePreviewBody(body, darkModeConvention);
|
|
641
|
+
let flatTokens;
|
|
642
|
+
if (resolved.kind === "mode-aware") {
|
|
643
|
+
applyModeAware(resolved.lightTokens, resolved.darkTokens, resolved.darkMode);
|
|
644
|
+
flatTokens = resolved.lightTokens;
|
|
645
|
+
} else {
|
|
646
|
+
applyFlat(resolved.tokens);
|
|
647
|
+
flatTokens = resolved.tokens;
|
|
648
|
+
}
|
|
649
|
+
activeTokens = flatTokens;
|
|
650
|
+
isPreview = true;
|
|
651
|
+
previewId = id;
|
|
652
|
+
previewMismatch = checkPreviewVocabulary({
|
|
653
|
+
tokens: flatTokens,
|
|
654
|
+
expectPrefixes: effectiveConfig.preview?.expectPrefixes,
|
|
655
|
+
previewId: id
|
|
656
|
+
});
|
|
657
|
+
notify();
|
|
658
|
+
};
|
|
659
|
+
const loadPreview = async (id, effectiveConfig) => {
|
|
660
|
+
const cfg = effectiveConfig || config;
|
|
661
|
+
const guard = shouldLoadPreview(cfg);
|
|
662
|
+
if (!guard.allowed) {
|
|
663
|
+
loadCommitted();
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
const origin = guard.origin;
|
|
667
|
+
try {
|
|
668
|
+
const res = await fetch(`${origin}/preview/${id}`, {
|
|
669
|
+
headers: bridgeHeaders(cfg.preview?.key)
|
|
670
|
+
});
|
|
671
|
+
if (!res.ok) throw new Error("preview not found");
|
|
672
|
+
const tokens = await res.json();
|
|
673
|
+
applyPreviewTokens(tokens, id, cfg);
|
|
674
|
+
return true;
|
|
675
|
+
} catch (e) {
|
|
676
|
+
loadCommitted();
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
const clearPreview = () => {
|
|
681
|
+
if (pollId) {
|
|
682
|
+
clearInterval(pollId);
|
|
683
|
+
pollId = null;
|
|
684
|
+
}
|
|
685
|
+
if (typeof location !== "undefined" && typeof history !== "undefined") {
|
|
686
|
+
const params = new URLSearchParams(location.search);
|
|
687
|
+
params.delete("preview");
|
|
688
|
+
const qs = params.toString();
|
|
689
|
+
history.replaceState(null, "", qs ? `?${qs}` : location.pathname);
|
|
690
|
+
}
|
|
241
691
|
loadCommitted();
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
692
|
+
};
|
|
693
|
+
const setMode = (next) => {
|
|
694
|
+
mode = next;
|
|
695
|
+
if (typeof document !== "undefined") {
|
|
696
|
+
const action = resolveModeAction(darkModeConvention, next);
|
|
697
|
+
switch (action.type) {
|
|
698
|
+
case "attr-set":
|
|
699
|
+
document.documentElement.setAttribute(action.attribute, action.value);
|
|
700
|
+
break;
|
|
701
|
+
case "attr-remove":
|
|
702
|
+
document.documentElement.removeAttribute(action.attribute);
|
|
703
|
+
break;
|
|
704
|
+
case "class-add":
|
|
705
|
+
document.documentElement.classList.add(action.className);
|
|
706
|
+
break;
|
|
707
|
+
case "class-remove":
|
|
708
|
+
document.documentElement.classList.remove(action.className);
|
|
709
|
+
break;
|
|
710
|
+
case "none":
|
|
711
|
+
default:
|
|
712
|
+
break;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
notify();
|
|
716
|
+
};
|
|
717
|
+
const destroy = () => {
|
|
718
|
+
cancelled = true;
|
|
719
|
+
if (pollId) clearInterval(pollId);
|
|
720
|
+
if (unsubscribeSSE) unsubscribeSSE();
|
|
721
|
+
if (mql) {
|
|
722
|
+
if (typeof mql.removeEventListener === "function") mql.removeEventListener("change", onSchemeChange);
|
|
723
|
+
else if (typeof mql.removeListener === "function") mql.removeListener(onSchemeChange);
|
|
724
|
+
}
|
|
725
|
+
listeners.clear();
|
|
726
|
+
};
|
|
727
|
+
const init = async () => {
|
|
728
|
+
if (config.resolved && config.resolved.length) warnDeprecated(config.resolved);
|
|
729
|
+
let effectiveConfig = config;
|
|
730
|
+
let resolvedConnection = null;
|
|
731
|
+
if (shouldResolveOrgConnection(config)) {
|
|
732
|
+
resolvedConnection = await resolveOrgConnection(getOrgKey(config), {
|
|
733
|
+
cloudBase: config.cloudBase
|
|
734
|
+
});
|
|
735
|
+
if (cancelled) return;
|
|
736
|
+
effectiveConfig = buildEffectiveConfig(config, resolvedConnection);
|
|
737
|
+
}
|
|
738
|
+
const guard = shouldLoadPreview(effectiveConfig);
|
|
739
|
+
const id = typeof location !== "undefined" ? new URLSearchParams(location.search).get("preview") : null;
|
|
246
740
|
if (!guard.allowed || !id) {
|
|
247
741
|
if (id && !guard.allowed) {
|
|
248
742
|
devWarn(
|
|
@@ -252,16 +746,213 @@ var SorbProvider = ({ config, children }) => {
|
|
|
252
746
|
loadCommitted();
|
|
253
747
|
return;
|
|
254
748
|
}
|
|
255
|
-
loadPreview(id)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
749
|
+
const ok = await loadPreview(id, effectiveConfig);
|
|
750
|
+
if (!ok || cancelled) return;
|
|
751
|
+
const useSSE = resolvedConnection && resolvedConnection.transport === "sse" && resolvedConnection.orgId && EventSourceCtor;
|
|
752
|
+
if (useSSE) {
|
|
753
|
+
const url = buildSubscribeUrl(
|
|
754
|
+
resolvedConnection.bridgeUrl,
|
|
755
|
+
resolvedConnection.orgId,
|
|
756
|
+
id,
|
|
757
|
+
effectiveConfig.preview?.key
|
|
758
|
+
);
|
|
759
|
+
unsubscribeSSE = createPreviewSubscription({
|
|
760
|
+
EventSourceImpl: EventSourceCtor,
|
|
761
|
+
url,
|
|
762
|
+
onTokens: (tokens) => applyPreviewTokens(tokens, id, effectiveConfig),
|
|
763
|
+
onDelete: () => loadCommitted(),
|
|
764
|
+
onError: () => devWarn("SSE preview subscription error \u2014 preview may be stale")
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
if (!unsubscribeSSE) {
|
|
768
|
+
const interval = effectiveConfig.preview?.pollInterval ?? 1500;
|
|
769
|
+
pollId = setInterval(() => loadPreview(id, effectiveConfig), interval);
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
init();
|
|
773
|
+
return { getState, subscribe, setMode, clearPreview, destroy };
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/legacyMap.js
|
|
777
|
+
var normalizeProp = (prop) => {
|
|
778
|
+
if (typeof prop !== "string") return "";
|
|
779
|
+
return prop.trim().replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
|
|
780
|
+
};
|
|
781
|
+
var canonicalizeColor = (v) => {
|
|
782
|
+
const hex = v.match(/^#([0-9a-f]{3,8})$/);
|
|
783
|
+
if (hex) {
|
|
784
|
+
let h = hex[1];
|
|
785
|
+
if (h.length === 3 || h.length === 4) {
|
|
786
|
+
h = h.split("").map((c) => c + c).join("");
|
|
787
|
+
}
|
|
788
|
+
if (h.length !== 6 && h.length !== 8) return null;
|
|
789
|
+
const r = parseInt(h.slice(0, 2), 16);
|
|
790
|
+
const g = parseInt(h.slice(2, 4), 16);
|
|
791
|
+
const b = parseInt(h.slice(4, 6), 16);
|
|
792
|
+
if (h.length === 8) {
|
|
793
|
+
const a = parseInt(h.slice(6, 8), 16) / 255;
|
|
794
|
+
const as = String(Math.round(a * 1e3) / 1e3);
|
|
795
|
+
return `rgba(${r}, ${g}, ${b}, ${as})`;
|
|
796
|
+
}
|
|
797
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
798
|
+
}
|
|
799
|
+
const fn = v.match(/^(rgba?)\(([^)]*)\)$/);
|
|
800
|
+
if (fn) {
|
|
801
|
+
const parts = fn[2].split(",").map((p) => p.trim()).filter((p) => p !== "");
|
|
802
|
+
if (parts.length === 3) return `rgb(${parts[0]}, ${parts[1]}, ${parts[2]})`;
|
|
803
|
+
if (parts.length === 4) return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${parts[3]})`;
|
|
804
|
+
}
|
|
805
|
+
return null;
|
|
806
|
+
};
|
|
807
|
+
var normalizeValue = (value) => {
|
|
808
|
+
if (value == null) return "";
|
|
809
|
+
let v = String(value).trim().toLowerCase();
|
|
810
|
+
if (v === "") return "";
|
|
811
|
+
v = v.replace(/\s+/g, " ");
|
|
812
|
+
const color = canonicalizeColor(v);
|
|
813
|
+
if (color) return color;
|
|
814
|
+
if (/^-?\d*\.?\d+$/.test(v)) v = `${v}px`;
|
|
815
|
+
return v;
|
|
816
|
+
};
|
|
817
|
+
var indexLegacyMap = (legacyMap) => {
|
|
818
|
+
const idx = /* @__PURE__ */ new Map();
|
|
819
|
+
if (!Array.isArray(legacyMap)) return idx;
|
|
820
|
+
for (const row of legacyMap) {
|
|
821
|
+
if (!row || row.cssVar == null || row.raw == null || row.prop == null) continue;
|
|
822
|
+
const p = normalizeProp(row.prop);
|
|
823
|
+
const entry = {
|
|
824
|
+
normValue: normalizeValue(row.raw),
|
|
825
|
+
cssVar: String(row.cssVar).replace(/^--/, ""),
|
|
826
|
+
raw: String(row.raw)
|
|
827
|
+
};
|
|
828
|
+
const list = idx.get(p);
|
|
829
|
+
if (list) list.push(entry);
|
|
830
|
+
else idx.set(p, [entry]);
|
|
831
|
+
}
|
|
832
|
+
return idx;
|
|
833
|
+
};
|
|
834
|
+
var computeLegacyOverride = (prop, computedValue, legacyMap) => {
|
|
835
|
+
const idx = legacyMap instanceof Map ? legacyMap : indexLegacyMap(legacyMap);
|
|
836
|
+
const list = idx.get(normalizeProp(prop));
|
|
837
|
+
if (!list || list.length === 0) return null;
|
|
838
|
+
const target = normalizeValue(computedValue);
|
|
839
|
+
if (target === "") return null;
|
|
840
|
+
for (const entry of list) {
|
|
841
|
+
if (entry.normValue === target) {
|
|
842
|
+
return `var(--${entry.cssVar}, ${entry.raw})`;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return null;
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// src/legacyDom.js
|
|
849
|
+
var applyLegacyMap = (root, legacyMap) => {
|
|
850
|
+
const restores = [];
|
|
851
|
+
const handle = { restores };
|
|
852
|
+
if (typeof document === "undefined") return handle;
|
|
853
|
+
const start = root ?? document.body;
|
|
854
|
+
if (!start || !Array.isArray(legacyMap) || legacyMap.length === 0) return handle;
|
|
855
|
+
const idx = indexLegacyMap(legacyMap);
|
|
856
|
+
if (idx.size === 0) return handle;
|
|
857
|
+
const props = Array.from(idx.keys());
|
|
858
|
+
const getView = () => {
|
|
859
|
+
const doc = start.ownerDocument || (start.nodeType === 9 ? start : document);
|
|
860
|
+
return doc.defaultView || (typeof window !== "undefined" ? window : null);
|
|
861
|
+
};
|
|
862
|
+
const view = getView();
|
|
863
|
+
if (!view || typeof view.getComputedStyle !== "function") return handle;
|
|
864
|
+
const visit = (el) => {
|
|
865
|
+
if (!el || el.nodeType !== 1) return;
|
|
866
|
+
const cs = view.getComputedStyle(el);
|
|
867
|
+
for (const prop of props) {
|
|
868
|
+
const computed = cs.getPropertyValue(prop);
|
|
869
|
+
const override = computeLegacyOverride(prop, computed, idx);
|
|
870
|
+
if (override == null) continue;
|
|
871
|
+
const prev = el.style.getPropertyValue(prop);
|
|
872
|
+
restores.push({ el: (
|
|
873
|
+
/** @type {HTMLElement} */
|
|
874
|
+
el
|
|
875
|
+
), prop, prev });
|
|
876
|
+
el.style.setProperty(prop, override);
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
if (start.nodeType === 1) visit(
|
|
880
|
+
/** @type {Element} */
|
|
881
|
+
start
|
|
882
|
+
);
|
|
883
|
+
const all = start.querySelectorAll ? start.querySelectorAll("*") : [];
|
|
884
|
+
for (const el of all) visit(el);
|
|
885
|
+
return handle;
|
|
886
|
+
};
|
|
887
|
+
var clearLegacyMap = (handle) => {
|
|
888
|
+
if (!handle || !Array.isArray(handle.restores)) return;
|
|
889
|
+
for (const { el, prop, prev } of handle.restores) {
|
|
890
|
+
if (!el || !el.style) continue;
|
|
891
|
+
if (prev === "" || prev == null) el.style.removeProperty(prop);
|
|
892
|
+
else el.style.setProperty(prop, prev);
|
|
893
|
+
}
|
|
894
|
+
handle.restores = [];
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
// src/TokenProvider.jsx
|
|
898
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
899
|
+
var matchMediaFn2 = typeof matchMedia !== "undefined" ? matchMedia : null;
|
|
900
|
+
var DARK_MEDIA_QUERY2 = "(prefers-color-scheme: dark)";
|
|
901
|
+
var SorbProvider = ({ config, legacyMap, children }) => {
|
|
902
|
+
const instanceRef = (0, import_react2.useRef)(null);
|
|
903
|
+
const legacyHandleRef = (0, import_react2.useRef)(null);
|
|
904
|
+
const [state, setState] = import_react2.default.useState(() => ({
|
|
905
|
+
tokens: config.tokens,
|
|
906
|
+
isPreview: false,
|
|
907
|
+
previewId: null,
|
|
908
|
+
previewMismatch: false,
|
|
909
|
+
mode: "auto",
|
|
910
|
+
resolvedScheme: matchMediaFn2 ? matchMediaFn2(DARK_MEDIA_QUERY2).matches ? "dark" : "light" : "light"
|
|
911
|
+
}));
|
|
912
|
+
const resolvedLegacyMap = legacyMap ?? config.legacyMap ?? null;
|
|
913
|
+
(0, import_react2.useEffect)(() => {
|
|
914
|
+
const instance = sorbInit(config);
|
|
915
|
+
instanceRef.current = instance;
|
|
916
|
+
setState(instance.getState());
|
|
917
|
+
const unsubscribe = instance.subscribe(setState);
|
|
260
918
|
return () => {
|
|
261
|
-
|
|
919
|
+
unsubscribe();
|
|
920
|
+
instance.destroy();
|
|
921
|
+
instanceRef.current = null;
|
|
262
922
|
};
|
|
263
923
|
}, []);
|
|
264
|
-
|
|
924
|
+
(0, import_react2.useEffect)(() => {
|
|
925
|
+
if (!resolvedLegacyMap || resolvedLegacyMap.length === 0) return void 0;
|
|
926
|
+
if (typeof document === "undefined") return void 0;
|
|
927
|
+
if (legacyHandleRef.current) clearLegacyMap(legacyHandleRef.current);
|
|
928
|
+
legacyHandleRef.current = applyLegacyMap(document.body, resolvedLegacyMap);
|
|
929
|
+
return () => {
|
|
930
|
+
if (legacyHandleRef.current) {
|
|
931
|
+
clearLegacyMap(legacyHandleRef.current);
|
|
932
|
+
legacyHandleRef.current = null;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
}, [resolvedLegacyMap, state.tokens]);
|
|
936
|
+
const setMode = (0, import_react2.useCallback)((next) => {
|
|
937
|
+
if (instanceRef.current) instanceRef.current.setMode(next);
|
|
938
|
+
}, []);
|
|
939
|
+
const clearPreview = (0, import_react2.useCallback)(() => {
|
|
940
|
+
if (instanceRef.current) instanceRef.current.clearPreview();
|
|
941
|
+
}, []);
|
|
942
|
+
const value = (0, import_react2.useMemo)(
|
|
943
|
+
() => ({
|
|
944
|
+
tokens: state.tokens,
|
|
945
|
+
isPreview: state.isPreview,
|
|
946
|
+
previewId: state.previewId,
|
|
947
|
+
previewMismatch: state.previewMismatch,
|
|
948
|
+
clearPreview,
|
|
949
|
+
mode: state.mode,
|
|
950
|
+
setMode,
|
|
951
|
+
resolvedScheme: state.resolvedScheme
|
|
952
|
+
}),
|
|
953
|
+
[state, clearPreview, setMode]
|
|
954
|
+
);
|
|
955
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TokenContext.Provider, { value, children });
|
|
265
956
|
};
|
|
266
957
|
|
|
267
958
|
// src/PreviewBanner.jsx
|
|
@@ -283,15 +974,21 @@ var useIsPreview = () => {
|
|
|
283
974
|
return useTokenContext().isPreview;
|
|
284
975
|
};
|
|
285
976
|
var usePreviewState = () => {
|
|
286
|
-
const { isPreview, previewId, clearPreview } = useTokenContext();
|
|
287
|
-
return { isPreview, previewId, clearPreview };
|
|
977
|
+
const { isPreview, previewId, previewMismatch, clearPreview } = useTokenContext();
|
|
978
|
+
return { isPreview, previewId, previewMismatch, clearPreview };
|
|
979
|
+
};
|
|
980
|
+
var useTheme = () => {
|
|
981
|
+
const { mode, setMode, resolvedScheme } = useTokenContext();
|
|
982
|
+
return { mode, setMode, resolvedScheme };
|
|
288
983
|
};
|
|
289
984
|
|
|
290
985
|
// src/PreviewBanner.jsx
|
|
291
986
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
292
987
|
var PreviewBanner = () => {
|
|
293
|
-
const { isPreview, previewId, clearPreview } = usePreviewState();
|
|
988
|
+
const { isPreview, previewId, previewMismatch, clearPreview } = usePreviewState();
|
|
294
989
|
if (!isPreview) return null;
|
|
990
|
+
const background = previewMismatch ? "var(--sorb-preview-warning-bg, #B54708)" : "#3B5BDB";
|
|
991
|
+
const accent = previewMismatch ? "var(--sorb-preview-warning-accent, #F59E0B)" : "transparent";
|
|
295
992
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
296
993
|
"div",
|
|
297
994
|
{
|
|
@@ -302,7 +999,8 @@ var PreviewBanner = () => {
|
|
|
302
999
|
bottom: 0,
|
|
303
1000
|
left: 0,
|
|
304
1001
|
right: 0,
|
|
305
|
-
background
|
|
1002
|
+
background,
|
|
1003
|
+
borderTop: `3px solid ${accent}`,
|
|
306
1004
|
color: "#fff",
|
|
307
1005
|
padding: "10px 20px",
|
|
308
1006
|
display: "flex",
|
|
@@ -317,7 +1015,7 @@ var PreviewBanner = () => {
|
|
|
317
1015
|
},
|
|
318
1016
|
children: [
|
|
319
1017
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
320
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { style: { fontWeight: 600 }, children: "Sorb preview active" }),
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { style: { fontWeight: 600 }, children: previewMismatch ? "Sorb preview active \u2014 may not re-skin" : "Sorb preview active" }),
|
|
321
1019
|
previewId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
322
1020
|
"code",
|
|
323
1021
|
{
|
|
@@ -332,7 +1030,7 @@ var PreviewBanner = () => {
|
|
|
332
1030
|
children: previewId
|
|
333
1031
|
}
|
|
334
1032
|
),
|
|
335
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { marginLeft: "8px", opacity: 0.75, fontSize: "12px" }, children: "Token changes from Figma are live" })
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { marginLeft: "8px", opacity: 0.75, fontSize: "12px" }, children: previewMismatch ? "No matching tokens for this app \u2014 colours may be unchanged" : "Token changes from Figma are live" })
|
|
336
1034
|
] }),
|
|
337
1035
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
338
1036
|
"button",
|
|
@@ -360,6 +1058,55 @@ var PreviewBanner = () => {
|
|
|
360
1058
|
);
|
|
361
1059
|
};
|
|
362
1060
|
|
|
1061
|
+
// src/ThemeToggle.jsx
|
|
1062
|
+
var import_react4 = __toESM(require("react"));
|
|
1063
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1064
|
+
var OPTIONS = [
|
|
1065
|
+
{ value: "light", label: "Light" },
|
|
1066
|
+
{ value: "dark", label: "Dark" },
|
|
1067
|
+
{ value: "auto", label: "Auto" }
|
|
1068
|
+
];
|
|
1069
|
+
var ThemeToggle = ({ className } = {}) => {
|
|
1070
|
+
const { mode, setMode } = useTheme();
|
|
1071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1072
|
+
"div",
|
|
1073
|
+
{
|
|
1074
|
+
role: "radiogroup",
|
|
1075
|
+
"aria-label": "Color mode",
|
|
1076
|
+
className,
|
|
1077
|
+
style: {
|
|
1078
|
+
display: "inline-flex",
|
|
1079
|
+
gap: "4px",
|
|
1080
|
+
fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
1081
|
+
fontSize: "13px"
|
|
1082
|
+
},
|
|
1083
|
+
children: OPTIONS.map(({ value, label }) => {
|
|
1084
|
+
const active = mode === value;
|
|
1085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1086
|
+
"button",
|
|
1087
|
+
{
|
|
1088
|
+
type: "button",
|
|
1089
|
+
role: "radio",
|
|
1090
|
+
"aria-checked": active,
|
|
1091
|
+
onClick: () => setMode(value),
|
|
1092
|
+
style: {
|
|
1093
|
+
padding: "4px 10px",
|
|
1094
|
+
borderRadius: "6px",
|
|
1095
|
+
border: "1px solid rgba(0,0,0,0.15)",
|
|
1096
|
+
background: active ? "var(--sorb-theme-toggle-active-bg, #3B5BDB)" : "transparent",
|
|
1097
|
+
color: active ? "#fff" : "inherit",
|
|
1098
|
+
cursor: "pointer",
|
|
1099
|
+
fontWeight: active ? 600 : 400
|
|
1100
|
+
},
|
|
1101
|
+
children: label
|
|
1102
|
+
},
|
|
1103
|
+
value
|
|
1104
|
+
);
|
|
1105
|
+
})
|
|
1106
|
+
}
|
|
1107
|
+
);
|
|
1108
|
+
};
|
|
1109
|
+
|
|
363
1110
|
// src/verify.js
|
|
364
1111
|
var toCssVar = (name) => {
|
|
365
1112
|
const s = String(name).trim();
|
|
@@ -404,4 +1151,177 @@ var verifyResolved = async (tokens, { origin = "http://localhost:7777", key, fet
|
|
|
404
1151
|
return { ok: false, reason: "bridge-unreachable", error: e && e.message };
|
|
405
1152
|
}
|
|
406
1153
|
};
|
|
1154
|
+
|
|
1155
|
+
// src/darkModeConventions.js
|
|
1156
|
+
var tailwindDarkMode = {
|
|
1157
|
+
strategy: "class",
|
|
1158
|
+
darkSelector: ".dark"
|
|
1159
|
+
};
|
|
1160
|
+
var dataThemeDarkMode = {
|
|
1161
|
+
strategy: "attribute",
|
|
1162
|
+
attribute: "data-theme",
|
|
1163
|
+
darkSelector: '[data-theme="dark"]',
|
|
1164
|
+
lightSelector: '[data-theme="light"]'
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
// src/targets/mantine.js
|
|
1168
|
+
var SORB_MANTINE_VARS_FORMAT_ID = "sorb/mantine-vars";
|
|
1169
|
+
var mantineTarget = {
|
|
1170
|
+
id: "mantine",
|
|
1171
|
+
emitFormat: SORB_MANTINE_VARS_FORMAT_ID,
|
|
1172
|
+
// Kit-vocab expectPrefixes (field-correction, non-negotiable): the
|
|
1173
|
+
// payload-side kit namespace, NEVER the framework's own `mantine-`
|
|
1174
|
+
// var prefix — a framework-prefix guard false-positives on every working
|
|
1175
|
+
// preview (verified P2/P3 across the demo program). Overridable via
|
|
1176
|
+
// `config.preview.expectPrefixes`.
|
|
1177
|
+
expectPrefixes: ["color-", "button-", "radius-"],
|
|
1178
|
+
// Left undefined on purpose — see file header.
|
|
1179
|
+
inject: void 0,
|
|
1180
|
+
// CONVENTION-DECLARED, NOT demo-verified — the Mantine JJ demo never built
|
|
1181
|
+
// dark mode (acid-wash is a variant push, not a mode). Mantine v7's
|
|
1182
|
+
// documented color-scheme convention sets a `data-mantine-color-scheme`
|
|
1183
|
+
// attribute (MantineProvider manages it; `useMantineColorScheme` /
|
|
1184
|
+
// `<ColorSchemeScript>` toggle it). Feeds the real-dark-mode program's D1
|
|
1185
|
+
// phase; verification lands there, not here.
|
|
1186
|
+
darkMode: {
|
|
1187
|
+
strategy: "attribute",
|
|
1188
|
+
attribute: "data-mantine-color-scheme",
|
|
1189
|
+
darkSelector: '[data-mantine-color-scheme="dark"]',
|
|
1190
|
+
lightSelector: '[data-mantine-color-scheme="light"]'
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
if (typeof registerTarget === "function") {
|
|
1194
|
+
registerTarget(mantineTarget);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// src/targets/tailwindV4.js
|
|
1198
|
+
var SORB_TAILWIND_FORMAT_ID = "sorb/tailwind-theme";
|
|
1199
|
+
var tailwindV4Target = {
|
|
1200
|
+
id: "tailwind-v4",
|
|
1201
|
+
emitFormat: SORB_TAILWIND_FORMAT_ID,
|
|
1202
|
+
// Payload-side KIT vocabulary (framework-targets-productization field-
|
|
1203
|
+
// correction), never a framework var prefix — a plain Sorb kit's own
|
|
1204
|
+
// token-family prefixes, matching what `@theme inline` references.
|
|
1205
|
+
expectPrefixes: ["color-", "radius-", "space-", "font-"],
|
|
1206
|
+
// Left undefined on purpose — see file header.
|
|
1207
|
+
inject: void 0,
|
|
1208
|
+
// CONVENTION-DECLARED, not demo-verified (the JJ demos never built dark
|
|
1209
|
+
// mode): Tailwind's documented `darkMode: 'class'` convention — a `.dark`
|
|
1210
|
+
// class toggled on `documentElement`. Feeds the real-dark-mode program's D1
|
|
1211
|
+
// phase; verification lands there.
|
|
1212
|
+
darkMode: tailwindDarkMode
|
|
1213
|
+
};
|
|
1214
|
+
if (typeof registerTarget === "function") {
|
|
1215
|
+
registerTarget(tailwindV4Target);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// src/targets/shadcn.js
|
|
1219
|
+
var SORB_SHADCN_FORMAT_ID = "sorb/shadcn-theme";
|
|
1220
|
+
var shadcnTarget = {
|
|
1221
|
+
id: "shadcn",
|
|
1222
|
+
emitFormat: SORB_SHADCN_FORMAT_ID,
|
|
1223
|
+
// Payload-side KIT vocabulary (framework-targets-productization field-
|
|
1224
|
+
// correction), never a framework/shadcn var prefix — shadcn's own vars
|
|
1225
|
+
// (`--background`, `--primary`, …) are the OUTPUT of this format, not the
|
|
1226
|
+
// guarded payload; the guard is against the underlying Sorb kit vocab the
|
|
1227
|
+
// format's :root map references.
|
|
1228
|
+
expectPrefixes: ["color-", "radius-", "space-", "font-"],
|
|
1229
|
+
// Left undefined on purpose — see file header.
|
|
1230
|
+
inject: void 0,
|
|
1231
|
+
// CONVENTION-DECLARED, not demo-verified (the JJ demos never built dark
|
|
1232
|
+
// mode): shadcn ships on top of Tailwind's `darkMode: 'class'` convention
|
|
1233
|
+
// (a `.dark` class toggled on `documentElement`, per shadcn/ui's own
|
|
1234
|
+
// docs). Feeds the real-dark-mode program's D1 phase; verification lands
|
|
1235
|
+
// there.
|
|
1236
|
+
darkMode: tailwindDarkMode
|
|
1237
|
+
};
|
|
1238
|
+
if (typeof registerTarget === "function") {
|
|
1239
|
+
registerTarget(shadcnTarget);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// src/targets/primevue.js
|
|
1243
|
+
var SORB_PRIMEVUE_PRESET_FORMAT_ID = "sorb/primevue-preset";
|
|
1244
|
+
var primevueTarget = {
|
|
1245
|
+
id: "primevue",
|
|
1246
|
+
emitFormat: SORB_PRIMEVUE_PRESET_FORMAT_ID,
|
|
1247
|
+
// Kit-vocab expectPrefixes (field-correction, non-negotiable): the
|
|
1248
|
+
// payload-side kit namespace, NEVER a PrimeVue-owned prefix (`p-`) — a
|
|
1249
|
+
// framework-prefix guard false-positives on every working preview
|
|
1250
|
+
// (verified P2/P3 across the demo program). This target's preset draws
|
|
1251
|
+
// from a wider slice of the kit vocab than Mantine/MUI (component-tier
|
|
1252
|
+
// overrides for Tag/Toast/Menubar), hence the longer list. Overridable via
|
|
1253
|
+
// `config.preview.expectPrefixes`.
|
|
1254
|
+
expectPrefixes: ["color-", "button-", "card-", "badge-", "input-", "nav-", "toast-", "radius-"],
|
|
1255
|
+
// Left undefined on purpose — see file header.
|
|
1256
|
+
inject: void 0,
|
|
1257
|
+
// CONVENTION-DECLARED, NOT demo-verified — the PrimeVue JJ demo never
|
|
1258
|
+
// built dark mode (acid-wash is a variant push, not a mode). PrimeVue v4's
|
|
1259
|
+
// documented dark-mode convention is a `.p-dark` selector class (default
|
|
1260
|
+
// `darkModeSelector` in `definePreset`/PrimeVue config), toggled on an
|
|
1261
|
+
// ancestor (typically `<html>`). Feeds the real-dark-mode program's D1
|
|
1262
|
+
// phase; verification lands there, not here.
|
|
1263
|
+
darkMode: {
|
|
1264
|
+
strategy: "class",
|
|
1265
|
+
darkSelector: ".p-dark"
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
if (typeof registerTarget === "function") {
|
|
1269
|
+
registerTarget(primevueTarget);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/targets/mui.js
|
|
1273
|
+
var SORB_MUI_VARS_FORMAT_ID = "sorb/mui-vars";
|
|
1274
|
+
var muiTarget = {
|
|
1275
|
+
id: "mui",
|
|
1276
|
+
emitFormat: SORB_MUI_VARS_FORMAT_ID,
|
|
1277
|
+
// Kit-vocab expectPrefixes (field-correction, non-negotiable): the
|
|
1278
|
+
// payload-side kit namespace, NEVER the framework's own `mui-` var
|
|
1279
|
+
// prefix — a framework-prefix guard false-positives on every working
|
|
1280
|
+
// preview (verified P2/P3 across the demo program). Overridable via
|
|
1281
|
+
// `config.preview.expectPrefixes`.
|
|
1282
|
+
expectPrefixes: ["color-", "radius-"],
|
|
1283
|
+
// Left undefined on purpose — see file header.
|
|
1284
|
+
inject: void 0,
|
|
1285
|
+
// CONVENTION-DECLARED, NOT demo-verified — the MUI JJ demo never built
|
|
1286
|
+
// dark mode (acid-wash is a variant push, not a mode). MUI v6's documented
|
|
1287
|
+
// `cssVariables: { colorSchemeSelector: 'data' }` convention sets a
|
|
1288
|
+
// `data-mui-color-scheme` attribute (`InitColorSchemeScript` / MUI's
|
|
1289
|
+
// `ThemeProvider` manage it). Feeds the real-dark-mode program's D1 phase;
|
|
1290
|
+
// verification lands there, not here.
|
|
1291
|
+
darkMode: {
|
|
1292
|
+
strategy: "attribute",
|
|
1293
|
+
attribute: "data-mui-color-scheme",
|
|
1294
|
+
darkSelector: '[data-mui-color-scheme="dark"]',
|
|
1295
|
+
lightSelector: '[data-mui-color-scheme="light"]'
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
if (typeof registerTarget === "function") {
|
|
1299
|
+
registerTarget(muiTarget);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// src/targets/angularMaterial.js
|
|
1303
|
+
var SORB_MAT_SYS_VARS_FORMAT_ID = "sorb/mat-sys-vars";
|
|
1304
|
+
var angularMaterialTarget = {
|
|
1305
|
+
id: "angular-material",
|
|
1306
|
+
emitFormat: SORB_MAT_SYS_VARS_FORMAT_ID,
|
|
1307
|
+
// Kit-vocab expectPrefixes (field-correction, non-negotiable): the
|
|
1308
|
+
// payload-side kit namespace, NEVER Angular Material's own `mat-sys-`
|
|
1309
|
+
// var prefix — a framework-prefix guard false-positives on every working
|
|
1310
|
+
// preview (verified P2/P3 across the demo program). Overridable via
|
|
1311
|
+
// `config.preview.expectPrefixes`.
|
|
1312
|
+
expectPrefixes: ["color-", "radius-"],
|
|
1313
|
+
// Left undefined on purpose — see file header. Non-React (Angular) target;
|
|
1314
|
+
// the leaf-core inject seam stays deferred.
|
|
1315
|
+
inject: void 0,
|
|
1316
|
+
// CONVENTION-DECLARED + UNCONFIRMED — see file header "DARK MODE" section.
|
|
1317
|
+
// Best-known default given Angular Material 20's `light-dark()`/
|
|
1318
|
+
// `color-scheme` mechanism has no single canonical selector name.
|
|
1319
|
+
darkMode: {
|
|
1320
|
+
strategy: "class",
|
|
1321
|
+
darkSelector: ".dark"
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
if (typeof registerTarget === "function") {
|
|
1325
|
+
registerTarget(angularMaterialTarget);
|
|
1326
|
+
}
|
|
407
1327
|
//# sourceMappingURL=index.js.map
|