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