@uni-design-system/uni-core 7.3.0 → 8.0.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/cjs/index.cjs +393 -7
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +380 -8
- package/dist/esm/index.js.map +1 -1
- package/dist/types/concepts/component/component.types.d.ts +1 -1
- package/dist/types/concepts/component/component.types.d.ts.map +1 -1
- package/dist/types/concepts/generation/theme-file.emitter.d.ts.map +1 -1
- package/dist/types/concepts/generation/theme.generator.d.ts +9 -2
- package/dist/types/concepts/generation/theme.generator.d.ts.map +1 -1
- package/dist/types/concepts/style/index.d.ts +1 -0
- package/dist/types/concepts/style/index.d.ts.map +1 -1
- package/dist/types/concepts/style/selectors.constants.d.ts +18 -0
- package/dist/types/concepts/style/selectors.constants.d.ts.map +1 -0
- package/dist/types/concepts/theme/index.d.ts +1 -0
- package/dist/types/concepts/theme/index.d.ts.map +1 -1
- package/dist/types/concepts/theme/theme.types.d.ts +7 -0
- package/dist/types/concepts/theme/theme.types.d.ts.map +1 -1
- package/dist/types/concepts/theme/theme.validation.d.ts +51 -0
- package/dist/types/concepts/theme/theme.validation.d.ts.map +1 -0
- package/dist/types/concepts/theme/theme.validation.spec.d.ts +2 -0
- package/dist/types/concepts/theme/theme.validation.spec.d.ts.map +1 -0
- package/dist/types/concepts/theme/themes/base.theme.d.ts +16 -0
- package/dist/types/concepts/theme/themes/base.theme.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -930,6 +930,25 @@ var BaseIcons = {
|
|
|
930
930
|
spinner: "data:image/svg+xml;charset=UTF-8,%3csvg stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3e%3cstyle%3e .oui_spinner %7b transform-origin: center; animation: rotate_360 2s linear infinite;%7d .oui_spinner circle %7b stroke-linecap: round; animation: dash 1.5s ease-in-out infinite;%7d %40keyframes rotate_360 %7b 100%25 %7b transform: rotate(360deg);%7d %7d %40keyframes dash %7b 0%25 %7b stroke-dasharray: 0 150; stroke-dashoffset: 0;%7d 47.5%25 %7b stroke-dasharray: 42 150; stroke-dashoffset: -16;%7d 95%25, 100%25 %7b stroke-dasharray: 42 150; stroke-dashoffset: -59;%7d %7d %3c/style%3e%3cg class='oui_spinner'%3e%3ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3e%3c/circle%3e%3c/g%3e%3c/svg%3e "
|
|
931
931
|
};
|
|
932
932
|
//#endregion
|
|
933
|
+
//#region src/concepts/style/selectors.constants.ts
|
|
934
|
+
/**
|
|
935
|
+
* The highlight state for roving-focus composites (menus, and any other widget
|
|
936
|
+
* that moves focus programmatically): pointer hover, or focus the user drove
|
|
937
|
+
* from the keyboard.
|
|
938
|
+
*
|
|
939
|
+
* Why not plain `:focus` — a roving-focus composite calls `.focus()` on an item
|
|
940
|
+
* every time it opens, including pointer opens, and `:focus` would paint that
|
|
941
|
+
* as a highlight the mouse user never asked for, reading as a preselected
|
|
942
|
+
* item. `:focus-visible` excludes programmatic focus that follows a click while
|
|
943
|
+
* still matching keyboard navigation.
|
|
944
|
+
*
|
|
945
|
+
* Shared as a constant because Emotion merges styles by **exact selector
|
|
946
|
+
* text**: a component's base rule and any theme variant restyling that rule
|
|
947
|
+
* must key both with this value, or the variant silently fails to override and
|
|
948
|
+
* reintroduces the phantom highlight.
|
|
949
|
+
*/
|
|
950
|
+
var HOVER_OR_KEYBOARD_FOCUS = "&:hover, &:focus-visible";
|
|
951
|
+
//#endregion
|
|
933
952
|
//#region src/concepts/theme/themes/base.theme.ts
|
|
934
953
|
var BaseTypography = {
|
|
935
954
|
"display-large": {
|
|
@@ -1127,6 +1146,25 @@ var buildBorders = (c) => ({
|
|
|
1127
1146
|
dark: `1px solid ${c["on-background"]}`,
|
|
1128
1147
|
dotted: `1px dotted ${c["on-background"]}`
|
|
1129
1148
|
});
|
|
1149
|
+
/**
|
|
1150
|
+
* One tag colour role across all three tones. `soft` is the resting look (the
|
|
1151
|
+
* container pair), `solid` fills with the role itself, `outline` keeps the
|
|
1152
|
+
* surface and draws the edge — so every role stays consistent and a theme can
|
|
1153
|
+
* still override any single cell.
|
|
1154
|
+
*/
|
|
1155
|
+
var tagVariant = (c, role) => ({ [role]: {
|
|
1156
|
+
backgroundColor: c[`${role}-container`],
|
|
1157
|
+
color: c[`on-${role}-container`],
|
|
1158
|
+
"&.tone-solid": {
|
|
1159
|
+
backgroundColor: c[role],
|
|
1160
|
+
color: c[`on-${role}`]
|
|
1161
|
+
},
|
|
1162
|
+
"&.tone-outline": {
|
|
1163
|
+
backgroundColor: "transparent",
|
|
1164
|
+
color: c[role],
|
|
1165
|
+
borderColor: c[`on-${role}-container-border`] ?? c[role]
|
|
1166
|
+
}
|
|
1167
|
+
} });
|
|
1130
1168
|
var buildComponents = (c) => ({
|
|
1131
1169
|
alert: { options: {
|
|
1132
1170
|
topPosition: 40,
|
|
@@ -1297,7 +1335,7 @@ var buildComponents = (c) => ({
|
|
|
1297
1335
|
},
|
|
1298
1336
|
variants: { warn: {
|
|
1299
1337
|
color: c.warn,
|
|
1300
|
-
|
|
1338
|
+
[HOVER_OR_KEYBOARD_FOCUS]: {
|
|
1301
1339
|
backgroundColor: c["warn-container"],
|
|
1302
1340
|
color: c["on-warn-container"]
|
|
1303
1341
|
}
|
|
@@ -1351,6 +1389,79 @@ var buildComponents = (c) => ({
|
|
|
1351
1389
|
focusOutlineOffset: 2
|
|
1352
1390
|
} },
|
|
1353
1391
|
badge: { options: { borderRadius: "xxs" } },
|
|
1392
|
+
tag: {
|
|
1393
|
+
options: {
|
|
1394
|
+
borderRadius: "max",
|
|
1395
|
+
typeface: "tag",
|
|
1396
|
+
gap: "xs",
|
|
1397
|
+
removeIcon: "close",
|
|
1398
|
+
selectedIcon: "check"
|
|
1399
|
+
},
|
|
1400
|
+
fixed: {
|
|
1401
|
+
display: "inline-flex",
|
|
1402
|
+
alignItems: "center",
|
|
1403
|
+
maxWidth: "100%",
|
|
1404
|
+
border: "1px solid transparent",
|
|
1405
|
+
transition: "background-color .2s ease, color .2s ease"
|
|
1406
|
+
},
|
|
1407
|
+
variants: {
|
|
1408
|
+
...tagVariant(c, "primary"),
|
|
1409
|
+
...tagVariant(c, "secondary"),
|
|
1410
|
+
...tagVariant(c, "tertiary"),
|
|
1411
|
+
...tagVariant(c, "warn"),
|
|
1412
|
+
...tagVariant(c, "success"),
|
|
1413
|
+
ghost: {
|
|
1414
|
+
backgroundColor: "transparent",
|
|
1415
|
+
color: c["on-background"],
|
|
1416
|
+
"&.tone-solid": {
|
|
1417
|
+
backgroundColor: c["surface-variant"],
|
|
1418
|
+
color: c["on-surface-variant"]
|
|
1419
|
+
},
|
|
1420
|
+
"&.tone-outline": {
|
|
1421
|
+
backgroundColor: "transparent",
|
|
1422
|
+
borderColor: c.outline
|
|
1423
|
+
}
|
|
1424
|
+
},
|
|
1425
|
+
disabled: {
|
|
1426
|
+
backgroundColor: c["disabled-container"],
|
|
1427
|
+
color: c["on-disabled"],
|
|
1428
|
+
"&.tone-solid": {
|
|
1429
|
+
backgroundColor: c.disabled,
|
|
1430
|
+
color: c["on-disabled"]
|
|
1431
|
+
},
|
|
1432
|
+
"&.tone-outline": {
|
|
1433
|
+
backgroundColor: "transparent",
|
|
1434
|
+
borderColor: c.disabled
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
},
|
|
1438
|
+
sizes: {
|
|
1439
|
+
sm: {
|
|
1440
|
+
height: 20,
|
|
1441
|
+
fontSize: 12,
|
|
1442
|
+
padding: "0 8px"
|
|
1443
|
+
},
|
|
1444
|
+
md: {
|
|
1445
|
+
height: 24,
|
|
1446
|
+
fontSize: 13,
|
|
1447
|
+
padding: "0 10px"
|
|
1448
|
+
},
|
|
1449
|
+
lg: {
|
|
1450
|
+
height: 32,
|
|
1451
|
+
fontSize: 15,
|
|
1452
|
+
padding: "0 12px"
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
},
|
|
1456
|
+
tagInput: { options: {
|
|
1457
|
+
chipGap: "xs",
|
|
1458
|
+
chipSize: "md",
|
|
1459
|
+
minInputWidth: "12ch",
|
|
1460
|
+
listColor: "primary-surface",
|
|
1461
|
+
listShadow: "menu",
|
|
1462
|
+
listBorderRadius: "xs",
|
|
1463
|
+
maxSuggestions: 8
|
|
1464
|
+
} },
|
|
1354
1465
|
button: {
|
|
1355
1466
|
options: {
|
|
1356
1467
|
borderRadius: "max",
|
|
@@ -1654,11 +1765,11 @@ var buildComponents = (c) => ({
|
|
|
1654
1765
|
typeface: "label"
|
|
1655
1766
|
} }
|
|
1656
1767
|
});
|
|
1657
|
-
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1768
|
+
var isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1658
1769
|
var deepMerge = (base, override) => {
|
|
1659
1770
|
if (!override) return base;
|
|
1660
1771
|
const out = { ...base };
|
|
1661
|
-
for (const [key, value] of Object.entries(override)) out[key] = isRecord(value) && isRecord(out[key]) ? deepMerge(out[key], value) : value;
|
|
1772
|
+
for (const [key, value] of Object.entries(override)) out[key] = isRecord$1(value) && isRecord$1(out[key]) ? deepMerge(out[key], value) : value;
|
|
1662
1773
|
return out;
|
|
1663
1774
|
};
|
|
1664
1775
|
var createTheme = ({ id, name, colors, icons = {}, radii = BaseRadii, shadows = BaseShadows, borders, components }) => ({
|
|
@@ -1678,6 +1789,31 @@ var createTheme = ({ id, name, colors, icons = {}, radii = BaseRadii, shadows =
|
|
|
1678
1789
|
components: deepMerge(buildComponents(colors), components)
|
|
1679
1790
|
});
|
|
1680
1791
|
/**
|
|
1792
|
+
* Re-attach the built-in icon set to a theme that traveled without it.
|
|
1793
|
+
*
|
|
1794
|
+
* A serialized theme is ~50 KB, ~71% of which is {@link BaseIcons} — bytes
|
|
1795
|
+
* every uni-core consumer already ships. Transports (MCP tool results, theme
|
|
1796
|
+
* JSON over HTTP) send the {@link dehydrateTheme} form and the receiver
|
|
1797
|
+
* hydrates, applying exactly the `{...BaseIcons, ...icons}` contract
|
|
1798
|
+
* {@link createTheme} applies at construction: the theme's own icons win,
|
|
1799
|
+
* built-ins fill the rest.
|
|
1800
|
+
*/
|
|
1801
|
+
var hydrateTheme = (theme) => ({
|
|
1802
|
+
...theme,
|
|
1803
|
+
icons: {
|
|
1804
|
+
...BaseIcons,
|
|
1805
|
+
...theme.icons
|
|
1806
|
+
}
|
|
1807
|
+
});
|
|
1808
|
+
/**
|
|
1809
|
+
* The wire form of a theme: icons identical to the built-in set are dropped,
|
|
1810
|
+
* so only genuine overrides travel. Reverse with {@link hydrateTheme}.
|
|
1811
|
+
*/
|
|
1812
|
+
var dehydrateTheme = (theme) => ({
|
|
1813
|
+
...theme,
|
|
1814
|
+
icons: Object.fromEntries(Object.entries(theme.icons).filter(([name, uri]) => BaseIcons[name] !== uri))
|
|
1815
|
+
});
|
|
1816
|
+
/**
|
|
1681
1817
|
* Build a full {@link UniTheme} straight from a {@link PaletteConfig} — the
|
|
1682
1818
|
* one-call path a theme builder uses to turn a brand color (or a seed +
|
|
1683
1819
|
* scheme + category) into a complete, ready-to-apply theme.
|
|
@@ -1825,11 +1961,17 @@ var generateThemes = (input) => {
|
|
|
1825
1961
|
};
|
|
1826
1962
|
};
|
|
1827
1963
|
/**
|
|
1964
|
+
* One-line human summary of a {@link ContrastReport}. Shared so the generated
|
|
1965
|
+
* theme file's header and the MCP's theme tools report identical wording.
|
|
1966
|
+
*/
|
|
1967
|
+
var summarizeContrast = (report) => `${report.checks.length} contrast pairs checked · worst ${report.worstRatio}:1 · ${report.pass ? "all AA" : `${report.checks.filter((check) => !check.pass).length} failing`}`;
|
|
1968
|
+
/**
|
|
1828
1969
|
* Convenience wrapper: {@link generateThemes} piped through `createTheme()`,
|
|
1829
|
-
* returning a registration-ready light/dark {@link UniTheme} pair
|
|
1970
|
+
* returning a registration-ready light/dark {@link UniTheme} pair alongside
|
|
1971
|
+
* the contrast report the colors were audited against.
|
|
1830
1972
|
*/
|
|
1831
1973
|
var generateUniThemes = (input) => {
|
|
1832
|
-
const { lightColors, darkColors, radii, lightShadows, darkShadows } = generateThemes(input);
|
|
1974
|
+
const { lightColors, darkColors, radii, lightShadows, darkShadows, report } = generateThemes(input);
|
|
1833
1975
|
const name = input.name ?? "Brand";
|
|
1834
1976
|
const id = name.replace(/\W+/g, "") || "Brand";
|
|
1835
1977
|
return {
|
|
@@ -1846,7 +1988,8 @@ var generateUniThemes = (input) => {
|
|
|
1846
1988
|
colors: darkColors,
|
|
1847
1989
|
radii,
|
|
1848
1990
|
shadows: darkShadows
|
|
1849
|
-
})
|
|
1991
|
+
}),
|
|
1992
|
+
report
|
|
1850
1993
|
};
|
|
1851
1994
|
};
|
|
1852
1995
|
//#endregion
|
|
@@ -1905,7 +2048,7 @@ var emitThemeFile = (input) => {
|
|
|
1905
2048
|
input.shape && `--shape=${input.shape}`,
|
|
1906
2049
|
!darkMode && "--dark-mode=false"
|
|
1907
2050
|
].filter(Boolean).join(" ");
|
|
1908
|
-
const reportSummary =
|
|
2051
|
+
const reportSummary = summarizeContrast(report);
|
|
1909
2052
|
const modes = [{
|
|
1910
2053
|
exportName: `${id}Light`,
|
|
1911
2054
|
displayName: `${name} Light`,
|
|
@@ -2198,6 +2341,235 @@ var UniThemes = {
|
|
|
2198
2341
|
};
|
|
2199
2342
|
var DefaultThemeId = Object.keys(UniThemes)[0];
|
|
2200
2343
|
//#endregion
|
|
2344
|
+
//#region src/concepts/theme/theme.validation.ts
|
|
2345
|
+
/**
|
|
2346
|
+
* Color tokens components cannot render without: the default variant pairs,
|
|
2347
|
+
* the base surfaces, and the disabled/warn states. Themes may define any
|
|
2348
|
+
* further tokens; these must exist.
|
|
2349
|
+
*/
|
|
2350
|
+
var REQUIRED_COLOR_TOKENS = [
|
|
2351
|
+
"primary",
|
|
2352
|
+
"on-primary",
|
|
2353
|
+
"primary-container",
|
|
2354
|
+
"on-primary-container",
|
|
2355
|
+
"primary-surface",
|
|
2356
|
+
"on-primary-surface",
|
|
2357
|
+
"surface",
|
|
2358
|
+
"on-surface",
|
|
2359
|
+
"background",
|
|
2360
|
+
"on-background",
|
|
2361
|
+
"warn",
|
|
2362
|
+
"on-warn",
|
|
2363
|
+
"disabled",
|
|
2364
|
+
"on-disabled",
|
|
2365
|
+
"outline",
|
|
2366
|
+
"transparent"
|
|
2367
|
+
];
|
|
2368
|
+
/** The canonical type scale; every theme must style each role. */
|
|
2369
|
+
var REQUIRED_TEXT_ROLES = [
|
|
2370
|
+
"display-large",
|
|
2371
|
+
"display-medium",
|
|
2372
|
+
"display-small",
|
|
2373
|
+
"headline-large",
|
|
2374
|
+
"headline-medium",
|
|
2375
|
+
"headline-small",
|
|
2376
|
+
"title-large",
|
|
2377
|
+
"title-medium",
|
|
2378
|
+
"title-small",
|
|
2379
|
+
"body-1-long",
|
|
2380
|
+
"body-1-short",
|
|
2381
|
+
"body-2-long",
|
|
2382
|
+
"body-2-short",
|
|
2383
|
+
"subtitle-1",
|
|
2384
|
+
"subtitle-2",
|
|
2385
|
+
"label",
|
|
2386
|
+
"button",
|
|
2387
|
+
"caption",
|
|
2388
|
+
"overline",
|
|
2389
|
+
"paragraph",
|
|
2390
|
+
"quote",
|
|
2391
|
+
"note"
|
|
2392
|
+
];
|
|
2393
|
+
var REQUIRED_SPACING_SIZES = [
|
|
2394
|
+
"none",
|
|
2395
|
+
"xxs",
|
|
2396
|
+
"xs",
|
|
2397
|
+
"sm",
|
|
2398
|
+
"md",
|
|
2399
|
+
"lg",
|
|
2400
|
+
"xl"
|
|
2401
|
+
];
|
|
2402
|
+
var REQUIRED_RADII_SIZES = [
|
|
2403
|
+
"none",
|
|
2404
|
+
"xxs",
|
|
2405
|
+
"xs",
|
|
2406
|
+
"sm",
|
|
2407
|
+
"md",
|
|
2408
|
+
"lg",
|
|
2409
|
+
"max"
|
|
2410
|
+
];
|
|
2411
|
+
var REQUIRED_SHADOWS = [
|
|
2412
|
+
"raised",
|
|
2413
|
+
"menu",
|
|
2414
|
+
"dialog",
|
|
2415
|
+
"warn"
|
|
2416
|
+
];
|
|
2417
|
+
var REQUIRED_THICKNESSES = [
|
|
2418
|
+
"thin",
|
|
2419
|
+
"standard",
|
|
2420
|
+
"thick"
|
|
2421
|
+
];
|
|
2422
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2423
|
+
var isCssValue = (value) => typeof value === "string" || typeof value === "number";
|
|
2424
|
+
/** Nested style expression: string/number leaves, objects for selectors. */
|
|
2425
|
+
var checkStyleExpression = (value, path, issues) => {
|
|
2426
|
+
if (!isRecord(value)) {
|
|
2427
|
+
issues.push({
|
|
2428
|
+
path,
|
|
2429
|
+
message: "must be a style object"
|
|
2430
|
+
});
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2434
|
+
if (entry === void 0 || isCssValue(entry)) continue;
|
|
2435
|
+
if (isRecord(entry)) checkStyleExpression(entry, `${path}.${key}`, issues);
|
|
2436
|
+
else issues.push({
|
|
2437
|
+
path: `${path}.${key}`,
|
|
2438
|
+
message: "must be a string, number, or nested style object"
|
|
2439
|
+
});
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
2442
|
+
var checkStringRecord = (value, path, issues, required = [], allowNumbers = false) => {
|
|
2443
|
+
if (!isRecord(value)) {
|
|
2444
|
+
issues.push({
|
|
2445
|
+
path,
|
|
2446
|
+
message: "must be an object"
|
|
2447
|
+
});
|
|
2448
|
+
return;
|
|
2449
|
+
}
|
|
2450
|
+
for (const key of required) if (!(key in value)) issues.push({
|
|
2451
|
+
path: `${path}.${key}`,
|
|
2452
|
+
message: "is required"
|
|
2453
|
+
});
|
|
2454
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2455
|
+
if (entry === void 0) continue;
|
|
2456
|
+
if (!(allowNumbers ? isCssValue(entry) : typeof entry === "string")) issues.push({
|
|
2457
|
+
path: `${path}.${key}`,
|
|
2458
|
+
message: allowNumbers ? "must be a string or number" : "must be a string"
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
};
|
|
2462
|
+
var checkTypography = (value, issues) => {
|
|
2463
|
+
if (!isRecord(value)) {
|
|
2464
|
+
issues.push({
|
|
2465
|
+
path: "typography",
|
|
2466
|
+
message: "must be an object"
|
|
2467
|
+
});
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
for (const role of REQUIRED_TEXT_ROLES) if (!(role in value)) issues.push({
|
|
2471
|
+
path: `typography.${role}`,
|
|
2472
|
+
message: "is required"
|
|
2473
|
+
});
|
|
2474
|
+
for (const [role, style] of Object.entries(value)) {
|
|
2475
|
+
if (!isRecord(style)) {
|
|
2476
|
+
issues.push({
|
|
2477
|
+
path: `typography.${role}`,
|
|
2478
|
+
message: "must be a TextStyle object"
|
|
2479
|
+
});
|
|
2480
|
+
continue;
|
|
2481
|
+
}
|
|
2482
|
+
if (typeof style["fontFamily"] !== "string") issues.push({
|
|
2483
|
+
path: `typography.${role}.fontFamily`,
|
|
2484
|
+
message: "must be a string"
|
|
2485
|
+
});
|
|
2486
|
+
for (const field of ["fontSize", "lineHeight"]) if (!isCssValue(style[field])) issues.push({
|
|
2487
|
+
path: `typography.${role}.${field}`,
|
|
2488
|
+
message: "must be a string or number"
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2491
|
+
};
|
|
2492
|
+
var checkComponents = (value, issues) => {
|
|
2493
|
+
if (!isRecord(value)) {
|
|
2494
|
+
issues.push({
|
|
2495
|
+
path: "components",
|
|
2496
|
+
message: "must be an object"
|
|
2497
|
+
});
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
2501
|
+
if (entry === void 0) continue;
|
|
2502
|
+
if (!isRecord(entry)) {
|
|
2503
|
+
issues.push({
|
|
2504
|
+
path: `components.${name}`,
|
|
2505
|
+
message: "must be a component theme object"
|
|
2506
|
+
});
|
|
2507
|
+
continue;
|
|
2508
|
+
}
|
|
2509
|
+
if (entry["fixed"] !== void 0) checkStyleExpression(entry["fixed"], `components.${name}.fixed`, issues);
|
|
2510
|
+
for (const section of ["variants", "sizes"]) {
|
|
2511
|
+
const styles = entry[section];
|
|
2512
|
+
if (styles === void 0) continue;
|
|
2513
|
+
if (!isRecord(styles)) {
|
|
2514
|
+
issues.push({
|
|
2515
|
+
path: `components.${name}.${section}`,
|
|
2516
|
+
message: "must be an object"
|
|
2517
|
+
});
|
|
2518
|
+
continue;
|
|
2519
|
+
}
|
|
2520
|
+
for (const [key, style] of Object.entries(styles)) if (style !== void 0) checkStyleExpression(style, `components.${name}.${section}.${key}`, issues);
|
|
2521
|
+
}
|
|
2522
|
+
if (entry["options"] !== void 0 && !isRecord(entry["options"])) issues.push({
|
|
2523
|
+
path: `components.${name}.options`,
|
|
2524
|
+
message: "must be an object"
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
};
|
|
2528
|
+
/**
|
|
2529
|
+
* Validate a candidate theme, collecting every structural issue. Never
|
|
2530
|
+
* throws; a failed result carries the complete repair list.
|
|
2531
|
+
*/
|
|
2532
|
+
var parseTheme = (input) => {
|
|
2533
|
+
const issues = [];
|
|
2534
|
+
if (!isRecord(input)) return {
|
|
2535
|
+
success: false,
|
|
2536
|
+
issues: [{
|
|
2537
|
+
path: "",
|
|
2538
|
+
message: "theme must be an object"
|
|
2539
|
+
}]
|
|
2540
|
+
};
|
|
2541
|
+
for (const field of ["id", "name"]) if (typeof input[field] !== "string" || input[field] === "") issues.push({
|
|
2542
|
+
path: field,
|
|
2543
|
+
message: "must be a non-empty string"
|
|
2544
|
+
});
|
|
2545
|
+
checkStringRecord(input["colors"], "colors", issues, REQUIRED_COLOR_TOKENS);
|
|
2546
|
+
checkTypography(input["typography"], issues);
|
|
2547
|
+
checkStringRecord(input["borders"], "borders", issues);
|
|
2548
|
+
checkStringRecord(input["radii"], "radii", issues, REQUIRED_RADII_SIZES);
|
|
2549
|
+
checkStringRecord(input["shadows"], "shadows", issues, REQUIRED_SHADOWS);
|
|
2550
|
+
checkStringRecord(input["spacing"], "spacing", issues, REQUIRED_SPACING_SIZES, true);
|
|
2551
|
+
checkStringRecord(input["thicknesses"], "thicknesses", issues, REQUIRED_THICKNESSES, true);
|
|
2552
|
+
checkStringRecord(input["icons"], "icons", issues);
|
|
2553
|
+
checkComponents(input["components"], issues);
|
|
2554
|
+
return issues.length === 0 ? {
|
|
2555
|
+
success: true,
|
|
2556
|
+
theme: input,
|
|
2557
|
+
issues: []
|
|
2558
|
+
} : {
|
|
2559
|
+
success: false,
|
|
2560
|
+
issues
|
|
2561
|
+
};
|
|
2562
|
+
};
|
|
2563
|
+
/** Format issues for logs and error messages. */
|
|
2564
|
+
var formatThemeIssues = (issues) => issues.map(({ path, message }) => path ? `${path} ${message}` : message).join("; ");
|
|
2565
|
+
/** Validate or throw, with every reason in the error message. */
|
|
2566
|
+
var assertTheme = (input) => {
|
|
2567
|
+
const result = parseTheme(input);
|
|
2568
|
+
if (!result.success) throw new Error(`Invalid UniTheme: ${formatThemeIssues(result.issues)}`);
|
|
2569
|
+
return result.theme;
|
|
2570
|
+
};
|
|
2571
|
+
var isUniTheme = (input) => parseTheme(input).success;
|
|
2572
|
+
//#endregion
|
|
2201
2573
|
//#region src/concepts/typography/typography.records.ts
|
|
2202
2574
|
var FontWeightMap = {
|
|
2203
2575
|
thin: 100,
|
|
@@ -2261,10 +2633,17 @@ exports.EXPAND_MAX_DURATION = EXPAND_MAX_DURATION;
|
|
|
2261
2633
|
exports.EXPAND_MIN_DURATION = EXPAND_MIN_DURATION;
|
|
2262
2634
|
exports.EXPAND_REFERENCE_HEIGHT = EXPAND_REFERENCE_HEIGHT;
|
|
2263
2635
|
exports.FontWeightMap = FontWeightMap;
|
|
2636
|
+
exports.HOVER_OR_KEYBOARD_FOCUS = HOVER_OR_KEYBOARD_FOCUS;
|
|
2264
2637
|
exports.HSLAToString = HSLAToString;
|
|
2265
2638
|
exports.HSLToHex = HSLToHex;
|
|
2266
2639
|
exports.HSLToRGB = HSLToRGB;
|
|
2267
2640
|
exports.LightTheme = LightTheme;
|
|
2641
|
+
exports.REQUIRED_COLOR_TOKENS = REQUIRED_COLOR_TOKENS;
|
|
2642
|
+
exports.REQUIRED_RADII_SIZES = REQUIRED_RADII_SIZES;
|
|
2643
|
+
exports.REQUIRED_SHADOWS = REQUIRED_SHADOWS;
|
|
2644
|
+
exports.REQUIRED_SPACING_SIZES = REQUIRED_SPACING_SIZES;
|
|
2645
|
+
exports.REQUIRED_TEXT_ROLES = REQUIRED_TEXT_ROLES;
|
|
2646
|
+
exports.REQUIRED_THICKNESSES = REQUIRED_THICKNESSES;
|
|
2268
2647
|
exports.RGBToHSL = RGBToHSL;
|
|
2269
2648
|
exports.RGBToString = RGBToString;
|
|
2270
2649
|
exports.RoleHues = RoleHues;
|
|
@@ -2273,6 +2652,7 @@ exports.ShadowMap = ShadowMap;
|
|
|
2273
2652
|
exports.ShapeRadii = ShapeRadii;
|
|
2274
2653
|
exports.UniThemes = UniThemes;
|
|
2275
2654
|
exports.Z_INDEX = Z_INDEX;
|
|
2655
|
+
exports.assertTheme = assertTheme;
|
|
2276
2656
|
exports.classifyScheme = classifyScheme;
|
|
2277
2657
|
exports.collapseFadeOut = collapseFadeOut;
|
|
2278
2658
|
exports.contrastRatio = contrastRatio;
|
|
@@ -2281,12 +2661,14 @@ exports.createThemeFromPalette = createThemeFromPalette;
|
|
|
2281
2661
|
exports.cycle = cycle;
|
|
2282
2662
|
exports.darkColors = darkColors;
|
|
2283
2663
|
exports.debounce = debounce;
|
|
2664
|
+
exports.dehydrateTheme = dehydrateTheme;
|
|
2284
2665
|
exports.emitDtcgTokens = emitDtcgTokens;
|
|
2285
2666
|
exports.emitThemeFile = emitThemeFile;
|
|
2286
2667
|
exports.expandDuration = expandDuration;
|
|
2287
2668
|
exports.expandFadeIn = expandFadeIn;
|
|
2288
2669
|
exports.fadeIn = fadeIn;
|
|
2289
2670
|
exports.fadeOut = fadeOut;
|
|
2671
|
+
exports.formatThemeIssues = formatThemeIssues;
|
|
2290
2672
|
exports.generateColors = generateColors;
|
|
2291
2673
|
exports.generatePalette = generatePalette;
|
|
2292
2674
|
exports.generateShadows = generateShadows;
|
|
@@ -2303,14 +2685,18 @@ exports.gradient = gradient;
|
|
|
2303
2685
|
exports.hexToHSL = hexToHSL;
|
|
2304
2686
|
exports.hexToOklch = hexToOklch;
|
|
2305
2687
|
exports.hexToRgb = hexToRgb;
|
|
2688
|
+
exports.hydrateTheme = hydrateTheme;
|
|
2306
2689
|
exports.inferCategory = inferCategory;
|
|
2690
|
+
exports.isUniTheme = isUniTheme;
|
|
2307
2691
|
exports.lightColors = lightColors;
|
|
2308
2692
|
exports.oklchToHex = oklchToHex;
|
|
2693
|
+
exports.parseTheme = parseTheme;
|
|
2309
2694
|
exports.randomRangeValue = randomRangeValue;
|
|
2310
2695
|
exports.relativeLuminance = relativeLuminance;
|
|
2311
2696
|
exports.removeInputPlatformStyling = removeInputPlatformStyling;
|
|
2312
2697
|
exports.rgbToHex = rgbToHex;
|
|
2313
2698
|
exports.schemeHues = schemeHues;
|
|
2699
|
+
exports.summarizeContrast = summarizeContrast;
|
|
2314
2700
|
exports.svgToIconUri = svgToIconUri;
|
|
2315
2701
|
exports.toTypeface = toTypeface;
|
|
2316
2702
|
exports.toTypefaces = toTypefaces;
|