@vectoriox/iox-ui 5.17.0 → 5.19.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/design-core/index.d.ts +90 -5
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +195 -13
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/package.json +1 -1
- package/src/design-core/design-apply.ts +43 -0
- package/src/design-core/flavor-spec.generated.ts +13 -2
- package/src/design-core/fonts.ts +184 -11
package/design-core/index.d.ts
CHANGED
|
@@ -1241,14 +1241,17 @@ declare const SPEC_ELEMENT_STYLES: readonly [{
|
|
|
1241
1241
|
readonly id: "box";
|
|
1242
1242
|
readonly label: "Box (no look)";
|
|
1243
1243
|
readonly group: "Layout";
|
|
1244
|
-
readonly appliesTo: readonly ["Container", "LinkedContainer", "Section"];
|
|
1245
|
-
readonly base: {
|
|
1244
|
+
readonly appliesTo: readonly ["Container", "LinkedContainer", "Section", "List", "ListItem", "Repeater"];
|
|
1245
|
+
readonly base: {
|
|
1246
|
+
readonly color: "inherit";
|
|
1247
|
+
};
|
|
1246
1248
|
}, {
|
|
1247
1249
|
readonly id: "card";
|
|
1248
1250
|
readonly label: "Card";
|
|
1249
1251
|
readonly group: "Layout";
|
|
1250
1252
|
readonly appliesTo: readonly ["Container", "LinkedContainer", "Card"];
|
|
1251
1253
|
readonly base: {
|
|
1254
|
+
readonly color: "inherit";
|
|
1252
1255
|
readonly backgroundColor: "var(--iox-card-bg)";
|
|
1253
1256
|
readonly borderWidth: "var(--iox-card-border-width)";
|
|
1254
1257
|
readonly borderStyle: "solid";
|
|
@@ -1272,6 +1275,7 @@ declare const SPEC_ELEMENT_STYLES: readonly [{
|
|
|
1272
1275
|
readonly group: "Layout";
|
|
1273
1276
|
readonly appliesTo: readonly ["Container", "LinkedContainer"];
|
|
1274
1277
|
readonly base: {
|
|
1278
|
+
readonly color: "inherit";
|
|
1275
1279
|
readonly backgroundColor: "var(--iox-panel-bg)";
|
|
1276
1280
|
readonly borderRadius: "var(--iox-panel-radius)";
|
|
1277
1281
|
readonly padding: "var(--iox-panel-pad)";
|
|
@@ -1282,6 +1286,7 @@ declare const SPEC_ELEMENT_STYLES: readonly [{
|
|
|
1282
1286
|
readonly group: "Layout";
|
|
1283
1287
|
readonly appliesTo: readonly ["Container"];
|
|
1284
1288
|
readonly base: {
|
|
1289
|
+
readonly color: "inherit";
|
|
1285
1290
|
readonly backgroundColor: "var(--iox-nav-bg)";
|
|
1286
1291
|
readonly borderWidth: "var(--iox-nav-border-width)";
|
|
1287
1292
|
readonly borderStyle: "solid";
|
|
@@ -1378,6 +1383,9 @@ declare const SPEC_DEFAULT_ELEMENT_STYLE: {
|
|
|
1378
1383
|
readonly Section: "section";
|
|
1379
1384
|
readonly Container: "box";
|
|
1380
1385
|
readonly LinkedContainer: "box";
|
|
1386
|
+
readonly List: "box";
|
|
1387
|
+
readonly ListItem: "box";
|
|
1388
|
+
readonly Repeater: "box";
|
|
1381
1389
|
readonly Card: "card";
|
|
1382
1390
|
readonly ButtonBlock: "button-primary";
|
|
1383
1391
|
readonly SubmitButton: "button-primary";
|
|
@@ -8694,8 +8702,43 @@ declare const FONT_FAMILY_TOKENS: readonly ["font-display", "font-body", "font-l
|
|
|
8694
8702
|
* uploaded family named `</style><script>` would otherwise close the element.
|
|
8695
8703
|
*/
|
|
8696
8704
|
declare function cssString(value: string): string;
|
|
8697
|
-
/**
|
|
8705
|
+
/** The file extensions a studio may upload as a font, and the descriptor format each one IS (§5b). */
|
|
8706
|
+
declare const FONT_FILE_FORMATS: Readonly<Record<string, FontFormat>>;
|
|
8707
|
+
declare const FONT_FILE_EXTENSIONS: ReadonlyArray<string>;
|
|
8708
|
+
/** For a file input's `accept` — the same list the server validates against. */
|
|
8709
|
+
declare const FONT_FILE_ACCEPT: string;
|
|
8710
|
+
/** The CSS weights a face can be declared at, for an editor that offers them. */
|
|
8711
|
+
declare const FONT_WEIGHTS: ReadonlyArray<number>;
|
|
8712
|
+
declare const FONT_STYLES: ReadonlyArray<FontStyle>;
|
|
8713
|
+
/** A stored key's original file name: the folder prefix and the `-<timestamp>` upload suffix removed. */
|
|
8714
|
+
declare function fontFileName(key: string | null | undefined): string;
|
|
8715
|
+
/** The descriptor format of a font file, from its extension — null for anything we do not serve. */
|
|
8716
|
+
declare function fontFormatOf(fileNameOrKey: string | null | undefined): FontFormat | null;
|
|
8717
|
+
/** The family a file had before DS5 — its name without the extension. Legacy files with no parsed
|
|
8718
|
+
* name table keep it, so a page saved with `font-family: 'Rubik-Regular'` keeps its face (D5). */
|
|
8719
|
+
declare function fontFileStem(key: string | null | undefined): string;
|
|
8720
|
+
/** A weight as CSS can use it: 100–900, a bad value → 400. */
|
|
8721
|
+
declare function normalizeFontWeight(w: unknown): number;
|
|
8722
|
+
declare function normalizeFontStyle(style: unknown): FontStyle;
|
|
8723
|
+
/** CSS family names match case-insensitively; this is the one comparison key. */
|
|
8724
|
+
declare function fontFamilyKey(family: string | null | undefined): string;
|
|
8725
|
+
/**
|
|
8726
|
+
* One `@font-face` per FACE (family × weight × style), carrying its real weight and style — so bold is
|
|
8727
|
+
* never synthesised. Files that declare the same face (a woff2 and a ttf of one cut) share one rule
|
|
8728
|
+
* whose `src` lists them best format first, which is what the two retired forks did per file stem.
|
|
8729
|
+
*/
|
|
8698
8730
|
declare function buildFontFaceCss(descriptors: ReadonlyArray<FontDescriptor> | null | undefined): string;
|
|
8731
|
+
/** An uploaded family: every file sharing a family name (case-insensitively), with its real cuts. */
|
|
8732
|
+
interface FontFamilyGroup {
|
|
8733
|
+
family: string;
|
|
8734
|
+
/** Distinct weights, ascending. */
|
|
8735
|
+
weights: number[];
|
|
8736
|
+
styles: FontStyle[];
|
|
8737
|
+
/** Every file of the family, lightest first. */
|
|
8738
|
+
faces: FontDescriptor[];
|
|
8739
|
+
}
|
|
8740
|
+
/** Files → families (§5b "Group into families"): the Files tile, the typeface dropdown and Design ▸ Type. */
|
|
8741
|
+
declare function groupFontFamilies(descriptors: ReadonlyArray<FontDescriptor> | null | undefined): FontFamilyGroup[];
|
|
8699
8742
|
/** The family names in a CSS `font-family` stack, unquoted, in order. */
|
|
8700
8743
|
declare function parseFontFamilies(stack: string): string[];
|
|
8701
8744
|
/** Where Google serves the stylesheets, and the origin the font FILES come from (preconnect). */
|
|
@@ -8719,6 +8762,28 @@ interface FontsForTokensOptions {
|
|
|
8719
8762
|
* one bad id cannot sink the others), in role order.
|
|
8720
8763
|
*/
|
|
8721
8764
|
declare function fontsForTokens(tokens: ReadonlyArray<DesignTokenLike> | null | undefined, opts?: FontsForTokensOptions): string[];
|
|
8765
|
+
type FontFamilyToken = (typeof FONT_FAMILY_TOKENS)[number];
|
|
8766
|
+
/** True when `stack` (a CSS `font-family` value) names `family` anywhere in it. */
|
|
8767
|
+
declare function stackNamesFamily(stack: string | null | undefined, family: string | null | undefined): boolean;
|
|
8768
|
+
/**
|
|
8769
|
+
* The font tokens whose value names `family` — what the delete guard asks before an uploaded family's
|
|
8770
|
+
* last file goes (§5b): deleting it would silently drop those roles to their fallback.
|
|
8771
|
+
*/
|
|
8772
|
+
declare function fontRoleReferences(tokens: ReadonlyArray<DesignTokenLike> | null | undefined, family: string | null | undefined): FontFamilyToken[];
|
|
8773
|
+
/**
|
|
8774
|
+
* The face CSS font matching picks for `weight` from `faces` (CSS Fonts §5.2): 400 tries 500 next,
|
|
8775
|
+
* 500 tries 400; lighter weights look down first, heavier ones up. So an `h1` at 600 over a family
|
|
8776
|
+
* uploaded at 400 + 700 renders the real 700 cut — the one worth preloading.
|
|
8777
|
+
*/
|
|
8778
|
+
declare function matchFontWeight<T extends {
|
|
8779
|
+
weight: number;
|
|
8780
|
+
}>(faces: ReadonlyArray<T>, weight: number): T | null;
|
|
8781
|
+
/**
|
|
8782
|
+
* The uploaded files the SSR head preloads (§5b — no flash of the fallback face): for the display and
|
|
8783
|
+
* body roles, the family each token names (its first uploaded family), the woff2 normal-style cut CSS
|
|
8784
|
+
* matching would pick for that role's weights. One file per weight that renders, never the family.
|
|
8785
|
+
*/
|
|
8786
|
+
declare function fontPreloads(descriptors: ReadonlyArray<FontDescriptor> | null | undefined, tokens: ReadonlyArray<DesignTokenLike> | null | undefined): FontDescriptor[];
|
|
8722
8787
|
|
|
8723
8788
|
/**
|
|
8724
8789
|
* Which `--iox-<name>` a piece of COMPONENT CSS may reference (design-system §3b-bis: "component CSS
|
|
@@ -8857,6 +8922,26 @@ interface SwissMigration {
|
|
|
8857
8922
|
* cycle; it migrates like any other Swiss row.
|
|
8858
8923
|
*/
|
|
8859
8924
|
declare function planSwissMigration(existing: ReadonlyArray<StoredDesignTokenRow>, stored: StoredDesign): SwissMigration | null;
|
|
8925
|
+
/** What deleting an uploaded family does to the look (§5b delete guard). */
|
|
8926
|
+
interface FontFamilyRemoval {
|
|
8927
|
+
/** The font tokens that name the family — empty means nothing references it and nothing changes. */
|
|
8928
|
+
roles: FontFamilyToken[];
|
|
8929
|
+
/** The design without the family: every font role it held goes back to the pack's pairing. */
|
|
8930
|
+
choices: DesignChoices;
|
|
8931
|
+
/** The token writes: the look's own merge, plus any OTHER row still naming the family (one typed
|
|
8932
|
+
* in the Tokens panel), rewritten to the pack's value too — a deleted face must not stay named. */
|
|
8933
|
+
plan: FlavorSeedPlan;
|
|
8934
|
+
/** Per role, the family it falls back to — what the guard tells the author before they confirm. */
|
|
8935
|
+
fallbacks: Array<{
|
|
8936
|
+
role: FontFamilyToken;
|
|
8937
|
+
family: string;
|
|
8938
|
+
}>;
|
|
8939
|
+
}
|
|
8940
|
+
/**
|
|
8941
|
+
* Plan the removal of an uploaded family from the look: the roles naming it fall back to the pack's
|
|
8942
|
+
* own font (the design's pairing), as the guard promises — "Nothing else changes".
|
|
8943
|
+
*/
|
|
8944
|
+
declare function planFontFamilyRemoval(existing: ReadonlyArray<StoredDesignTokenRow>, previous: StoredDesign, family: string): FontFamilyRemoval;
|
|
8860
8945
|
|
|
8861
|
-
export { ACCENT_TOKEN_NAMES, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, OwnedTraitLink, PALETTE_PRESETS, REDUCED_MOTION_OVERRIDES, REDUCED_TRANSPARENCY_OVERRIDES, REVERT_WINDOW_MS, SPEC_A11Y, SPEC_AXES, SPEC_BUTTON_VARIANT_TO_STYLE, SPEC_CONTRAST, SPEC_DEFAULT_ELEMENT_STYLE, SPEC_ELEMENT_STYLES, SPEC_FIELD_CLASS_BASELINE, SPEC_FLAVORS, SPEC_FLAVOR_PACKS, SPEC_FONTS, SPEC_FONT_ROLES, SPEC_LEGACY_ALIASES, SPEC_PALETTE_PRESETS, SPEC_SCHEMES, SPEC_SPRINGS, SPEC_TIERS, SPEC_TIER_IDS, SPEC_TOKEN_TYPES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, choicesForPack, colorSchemeClass, colorSchemeOf, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSourceStamp, fontsForTokens, googleFontHref, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isRetiredFlavorId, legacyRuleTokenReferences, missingDesignRows, nodeDesignClasses, oklabToRgb, ownedTraitStatus, packDesignChoices, parseFontFamilies, parseHexColor, planDesignApply, planFlavorRevert, planFlavorSeed, planSwissMigration, readDesignConfig, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, userFontStack, validateFlavorPack, wcagContrastRatio };
|
|
8862
|
-
export type { AccentBackgrounds, AccentTokenName, ApplyElementStyleResult, DensityId, DesignChoices, DesignClassSource, DesignConfigEntry, DesignMode, DesignTokenGroup, DesignTokenLike, DesignTokenRow, DesignTokenTier, DesignTokenType, ElementStyle, ElementStyleTarget, ElementStyleTraitLike, FlavorPack, FlavorPackV2, FlavorRevertPlan, FlavorRevertSnapshot, FlavorSeedPlan, FlavorSpecToken, FlavorTokenDef, FontDescriptor, FontFormat, FontPair, FontRoleToken, FontStyle, FontsForTokensOptions, LinearSpring, MotionId, OkLab, OwnedTrait, OwnedTraitStatus, PalettePreset, ResolvedMode, Rgb, SchemeId, SeedBaseline, SeedExpectation, ShapeId, StoredDesign, StoredDesignTokenRow, SwissMigration, SwitchElementStyleResult, TokenCssBlocks, TokenCssOptions };
|
|
8946
|
+
export { ACCENT_TOKEN_NAMES, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, FONT_FILE_ACCEPT, FONT_FILE_EXTENSIONS, FONT_FILE_FORMATS, FONT_STYLES, FONT_WEIGHTS, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, OwnedTraitLink, PALETTE_PRESETS, REDUCED_MOTION_OVERRIDES, REDUCED_TRANSPARENCY_OVERRIDES, REVERT_WINDOW_MS, SPEC_A11Y, SPEC_AXES, SPEC_BUTTON_VARIANT_TO_STYLE, SPEC_CONTRAST, SPEC_DEFAULT_ELEMENT_STYLE, SPEC_ELEMENT_STYLES, SPEC_FIELD_CLASS_BASELINE, SPEC_FLAVORS, SPEC_FLAVOR_PACKS, SPEC_FONTS, SPEC_FONT_ROLES, SPEC_LEGACY_ALIASES, SPEC_PALETTE_PRESETS, SPEC_SCHEMES, SPEC_SPRINGS, SPEC_TIERS, SPEC_TIER_IDS, SPEC_TOKEN_TYPES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, choicesForPack, colorSchemeClass, colorSchemeOf, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSourceStamp, fontFamilyKey, fontFileName, fontFileStem, fontFormatOf, fontPreloads, fontRoleReferences, fontsForTokens, googleFontHref, groupFontFamilies, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isRetiredFlavorId, legacyRuleTokenReferences, matchFontWeight, missingDesignRows, nodeDesignClasses, normalizeFontStyle, normalizeFontWeight, oklabToRgb, ownedTraitStatus, packDesignChoices, parseFontFamilies, parseHexColor, planDesignApply, planFlavorRevert, planFlavorSeed, planFontFamilyRemoval, planSwissMigration, readDesignConfig, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, stackNamesFamily, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, userFontStack, validateFlavorPack, wcagContrastRatio };
|
|
8947
|
+
export type { AccentBackgrounds, AccentTokenName, ApplyElementStyleResult, DensityId, DesignChoices, DesignClassSource, DesignConfigEntry, DesignMode, DesignTokenGroup, DesignTokenLike, DesignTokenRow, DesignTokenTier, DesignTokenType, ElementStyle, ElementStyleTarget, ElementStyleTraitLike, FlavorPack, FlavorPackV2, FlavorRevertPlan, FlavorRevertSnapshot, FlavorSeedPlan, FlavorSpecToken, FlavorTokenDef, FontDescriptor, FontFamilyGroup, FontFamilyRemoval, FontFamilyToken, FontFormat, FontPair, FontRoleToken, FontStyle, FontsForTokensOptions, LinearSpring, MotionId, OkLab, OwnedTrait, OwnedTraitStatus, PalettePreset, ResolvedMode, Rgb, SchemeId, SeedBaseline, SeedExpectation, ShapeId, StoredDesign, StoredDesignTokenRow, SwissMigration, SwitchElementStyleResult, TokenCssBlocks, TokenCssOptions };
|
|
@@ -1481,9 +1481,14 @@ const SPEC_ELEMENT_STYLES = [
|
|
|
1481
1481
|
"appliesTo": [
|
|
1482
1482
|
"Container",
|
|
1483
1483
|
"LinkedContainer",
|
|
1484
|
-
"Section"
|
|
1484
|
+
"Section",
|
|
1485
|
+
"List",
|
|
1486
|
+
"ListItem",
|
|
1487
|
+
"Repeater"
|
|
1485
1488
|
],
|
|
1486
|
-
"base": {
|
|
1489
|
+
"base": {
|
|
1490
|
+
"color": "inherit"
|
|
1491
|
+
}
|
|
1487
1492
|
},
|
|
1488
1493
|
{
|
|
1489
1494
|
"id": "card",
|
|
@@ -1495,6 +1500,7 @@ const SPEC_ELEMENT_STYLES = [
|
|
|
1495
1500
|
"Card"
|
|
1496
1501
|
],
|
|
1497
1502
|
"base": {
|
|
1503
|
+
"color": "inherit",
|
|
1498
1504
|
"backgroundColor": "var(--iox-card-bg)",
|
|
1499
1505
|
"borderWidth": "var(--iox-card-border-width)",
|
|
1500
1506
|
"borderStyle": "solid",
|
|
@@ -1522,6 +1528,7 @@ const SPEC_ELEMENT_STYLES = [
|
|
|
1522
1528
|
"LinkedContainer"
|
|
1523
1529
|
],
|
|
1524
1530
|
"base": {
|
|
1531
|
+
"color": "inherit",
|
|
1525
1532
|
"backgroundColor": "var(--iox-panel-bg)",
|
|
1526
1533
|
"borderRadius": "var(--iox-panel-radius)",
|
|
1527
1534
|
"padding": "var(--iox-panel-pad)"
|
|
@@ -1535,6 +1542,7 @@ const SPEC_ELEMENT_STYLES = [
|
|
|
1535
1542
|
"Container"
|
|
1536
1543
|
],
|
|
1537
1544
|
"base": {
|
|
1545
|
+
"color": "inherit",
|
|
1538
1546
|
"backgroundColor": "var(--iox-nav-bg)",
|
|
1539
1547
|
"borderWidth": "var(--iox-nav-border-width)",
|
|
1540
1548
|
"borderStyle": "solid",
|
|
@@ -1658,6 +1666,9 @@ const SPEC_DEFAULT_ELEMENT_STYLE = {
|
|
|
1658
1666
|
"Section": "section",
|
|
1659
1667
|
"Container": "box",
|
|
1660
1668
|
"LinkedContainer": "box",
|
|
1669
|
+
"List": "box",
|
|
1670
|
+
"ListItem": "box",
|
|
1671
|
+
"Repeater": "box",
|
|
1661
1672
|
"Card": "card",
|
|
1662
1673
|
"ButtonBlock": "button-primary",
|
|
1663
1674
|
"SubmitButton": "button-primary",
|
|
@@ -10461,28 +10472,107 @@ function cssString(value) {
|
|
|
10461
10472
|
.replace(/>/g, '\\3e ');
|
|
10462
10473
|
return `'${body}'`;
|
|
10463
10474
|
}
|
|
10464
|
-
|
|
10475
|
+
/** The file extensions a studio may upload as a font, and the descriptor format each one IS (§5b). */
|
|
10476
|
+
const FONT_FILE_FORMATS = Object.freeze({
|
|
10477
|
+
woff2: 'woff2', woff: 'woff', ttf: 'truetype', otf: 'opentype',
|
|
10478
|
+
});
|
|
10479
|
+
const FONT_FILE_EXTENSIONS = Object.keys(FONT_FILE_FORMATS);
|
|
10480
|
+
/** For a file input's `accept` — the same list the server validates against. */
|
|
10481
|
+
const FONT_FILE_ACCEPT = FONT_FILE_EXTENSIONS.map(ext => `.${ext}`).join(',');
|
|
10482
|
+
/** The CSS weights a face can be declared at, for an editor that offers them. */
|
|
10483
|
+
const FONT_WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
10484
|
+
const FONT_STYLES = ['normal', 'italic'];
|
|
10485
|
+
/** When two files declare the same face, the browser should try the smallest, best-supported first. */
|
|
10486
|
+
const FORMAT_PREFERENCE = ['woff2', 'woff', 'opentype', 'truetype'];
|
|
10487
|
+
const UPLOAD_SUFFIX = /-\d+$/;
|
|
10488
|
+
/** A stored key's original file name: the folder prefix and the `-<timestamp>` upload suffix removed. */
|
|
10489
|
+
function fontFileName(key) {
|
|
10490
|
+
const name = String(key ?? '');
|
|
10491
|
+
return name.substring(name.lastIndexOf('/') + 1).replace(UPLOAD_SUFFIX, '');
|
|
10492
|
+
}
|
|
10493
|
+
/** The descriptor format of a font file, from its extension — null for anything we do not serve. */
|
|
10494
|
+
function fontFormatOf(fileNameOrKey) {
|
|
10495
|
+
const ext = /\.([a-z0-9]+)$/i.exec(fontFileName(fileNameOrKey))?.[1]?.toLowerCase() ?? '';
|
|
10496
|
+
return FONT_FILE_FORMATS[ext] ?? null;
|
|
10497
|
+
}
|
|
10498
|
+
/** The family a file had before DS5 — its name without the extension. Legacy files with no parsed
|
|
10499
|
+
* name table keep it, so a page saved with `font-family: 'Rubik-Regular'` keeps its face (D5). */
|
|
10500
|
+
function fontFileStem(key) {
|
|
10501
|
+
return fontFileName(key).replace(/\.[^.]+$/, '');
|
|
10502
|
+
}
|
|
10503
|
+
/** A weight as CSS can use it: 100–900, a bad value → 400. */
|
|
10504
|
+
function normalizeFontWeight(w) {
|
|
10465
10505
|
const n = Math.round(Number(w));
|
|
10466
10506
|
return Number.isFinite(n) && n > 0 ? Math.min(MAX_WEIGHT, Math.max(MIN_WEIGHT, n)) : DEFAULT_WEIGHT;
|
|
10507
|
+
}
|
|
10508
|
+
function normalizeFontStyle(style) {
|
|
10509
|
+
return style === 'italic' ? 'italic' : 'normal';
|
|
10510
|
+
}
|
|
10511
|
+
/** CSS family names match case-insensitively; this is the one comparison key. */
|
|
10512
|
+
function fontFamilyKey(family) {
|
|
10513
|
+
return String(family ?? '').trim().toLowerCase();
|
|
10514
|
+
}
|
|
10515
|
+
const usableDescriptor = (d) => !!d && typeof d.family === 'string' && d.family.trim() !== '' && typeof d.url === 'string' && d.url !== '';
|
|
10516
|
+
const preference = (format) => {
|
|
10517
|
+
const i = FORMAT_PREFERENCE.indexOf(format);
|
|
10518
|
+
return i < 0 ? FORMAT_PREFERENCE.length : i;
|
|
10467
10519
|
};
|
|
10468
|
-
/**
|
|
10520
|
+
/**
|
|
10521
|
+
* One `@font-face` per FACE (family × weight × style), carrying its real weight and style — so bold is
|
|
10522
|
+
* never synthesised. Files that declare the same face (a woff2 and a ttf of one cut) share one rule
|
|
10523
|
+
* whose `src` lists them best format first, which is what the two retired forks did per file stem.
|
|
10524
|
+
*/
|
|
10469
10525
|
function buildFontFaceCss(descriptors) {
|
|
10470
|
-
|
|
10471
|
-
|
|
10472
|
-
.
|
|
10473
|
-
const
|
|
10526
|
+
const faces = new Map();
|
|
10527
|
+
for (const d of (descriptors ?? []).filter(usableDescriptor)) {
|
|
10528
|
+
const family = d.family.trim();
|
|
10529
|
+
const weight = normalizeFontWeight(d.weight);
|
|
10530
|
+
const style = normalizeFontStyle(d.style);
|
|
10531
|
+
const id = `${fontFamilyKey(family)}|${weight}|${style}`;
|
|
10532
|
+
const face = faces.get(id) ?? { family, weight, style, files: [] };
|
|
10533
|
+
face.files.push(d);
|
|
10534
|
+
faces.set(id, face);
|
|
10535
|
+
}
|
|
10536
|
+
return [...faces.values()]
|
|
10537
|
+
.map(face => {
|
|
10538
|
+
const src = [...face.files]
|
|
10539
|
+
.sort((a, b) => preference(a.format) - preference(b.format))
|
|
10540
|
+
.map(d => `url(${cssString(d.url)})${FONT_FORMATS.includes(d.format) ? ` format(${cssString(d.format)})` : ''}`)
|
|
10541
|
+
.join(', ');
|
|
10474
10542
|
return [
|
|
10475
10543
|
'@font-face {',
|
|
10476
|
-
` font-family: ${cssString(
|
|
10477
|
-
` src:
|
|
10478
|
-
` font-weight: ${
|
|
10479
|
-
` font-style: ${
|
|
10544
|
+
` font-family: ${cssString(face.family)};`,
|
|
10545
|
+
` src: ${src};`,
|
|
10546
|
+
` font-weight: ${face.weight};`,
|
|
10547
|
+
` font-style: ${face.style};`,
|
|
10480
10548
|
' font-display: swap;',
|
|
10481
10549
|
'}',
|
|
10482
10550
|
].join('\n');
|
|
10483
10551
|
})
|
|
10484
10552
|
.join('\n');
|
|
10485
10553
|
}
|
|
10554
|
+
/** Files → families (§5b "Group into families"): the Files tile, the typeface dropdown and Design ▸ Type. */
|
|
10555
|
+
function groupFontFamilies(descriptors) {
|
|
10556
|
+
const groups = new Map();
|
|
10557
|
+
for (const d of (descriptors ?? []).filter(usableDescriptor)) {
|
|
10558
|
+
const key = fontFamilyKey(d.family);
|
|
10559
|
+
const group = groups.get(key) ?? { family: d.family.trim(), weights: [], styles: [], faces: [] };
|
|
10560
|
+
group.faces.push(d);
|
|
10561
|
+
groups.set(key, group);
|
|
10562
|
+
}
|
|
10563
|
+
return [...groups.values()]
|
|
10564
|
+
.map(g => {
|
|
10565
|
+
const faces = [...g.faces].sort((a, b) => normalizeFontWeight(a.weight) - normalizeFontWeight(b.weight)
|
|
10566
|
+
|| normalizeFontStyle(a.style).localeCompare(normalizeFontStyle(b.style)));
|
|
10567
|
+
return {
|
|
10568
|
+
family: g.family,
|
|
10569
|
+
weights: [...new Set(faces.map(f => normalizeFontWeight(f.weight)))].sort((a, b) => a - b),
|
|
10570
|
+
styles: FONT_STYLES.filter(s => faces.some(f => normalizeFontStyle(f.style) === s)),
|
|
10571
|
+
faces,
|
|
10572
|
+
};
|
|
10573
|
+
})
|
|
10574
|
+
.sort((a, b) => a.family.localeCompare(b.family));
|
|
10575
|
+
}
|
|
10486
10576
|
/** The family names in a CSS `font-family` stack, unquoted, in order. */
|
|
10487
10577
|
function parseFontFamilies(stack) {
|
|
10488
10578
|
return String(stack ?? '')
|
|
@@ -10529,6 +10619,70 @@ function fontsForTokens(tokens, opts = {}) {
|
|
|
10529
10619
|
}
|
|
10530
10620
|
return ids;
|
|
10531
10621
|
}
|
|
10622
|
+
/** True when `stack` (a CSS `font-family` value) names `family` anywhere in it. */
|
|
10623
|
+
function stackNamesFamily(stack, family) {
|
|
10624
|
+
const key = fontFamilyKey(family);
|
|
10625
|
+
return key !== '' && parseFontFamilies(stack ?? '').some(f => fontFamilyKey(f) === key);
|
|
10626
|
+
}
|
|
10627
|
+
/**
|
|
10628
|
+
* The font tokens whose value names `family` — what the delete guard asks before an uploaded family's
|
|
10629
|
+
* last file goes (§5b): deleting it would silently drop those roles to their fallback.
|
|
10630
|
+
*/
|
|
10631
|
+
function fontRoleReferences(tokens, family) {
|
|
10632
|
+
const rows = (tokens ?? []).filter(t => !!t && typeof t.name === 'string');
|
|
10633
|
+
return FONT_FAMILY_TOKENS.filter(role => rows.some(t => t.name === role && stackNamesFamily(t.value, family)));
|
|
10634
|
+
}
|
|
10635
|
+
/**
|
|
10636
|
+
* The face CSS font matching picks for `weight` from `faces` (CSS Fonts §5.2): 400 tries 500 next,
|
|
10637
|
+
* 500 tries 400; lighter weights look down first, heavier ones up. So an `h1` at 600 over a family
|
|
10638
|
+
* uploaded at 400 + 700 renders the real 700 cut — the one worth preloading.
|
|
10639
|
+
*/
|
|
10640
|
+
function matchFontWeight(faces, weight) {
|
|
10641
|
+
if (!faces?.length)
|
|
10642
|
+
return null;
|
|
10643
|
+
const want = normalizeFontWeight(weight);
|
|
10644
|
+
const exact = faces.find(f => normalizeFontWeight(f.weight) === want);
|
|
10645
|
+
if (exact)
|
|
10646
|
+
return exact;
|
|
10647
|
+
const w = (f) => normalizeFontWeight(f.weight);
|
|
10648
|
+
const below = (max) => [...faces].filter(f => w(f) < max).sort((a, b) => w(b) - w(a))[0] ?? null;
|
|
10649
|
+
const above = (min) => [...faces].filter(f => w(f) > min).sort((a, b) => w(a) - w(b))[0] ?? null;
|
|
10650
|
+
if (want >= 400 && want <= 500) {
|
|
10651
|
+
const within = [...faces].filter(f => w(f) > want && w(f) <= 500).sort((a, b) => w(a) - w(b))[0];
|
|
10652
|
+
return within ?? below(want) ?? above(500);
|
|
10653
|
+
}
|
|
10654
|
+
return want < 400 ? (below(want) ?? above(want)) : (above(want) ?? below(want));
|
|
10655
|
+
}
|
|
10656
|
+
/** The roles a preload serves, and the weight tokens whose cuts render above the fold. */
|
|
10657
|
+
const PRELOAD_ROLES = [
|
|
10658
|
+
{ role: 'font-display', weights: ['weight-display', 'weight-heading'], fallback: 700 },
|
|
10659
|
+
{ role: 'font-body', weights: ['weight-body', 'weight-strong'], fallback: DEFAULT_WEIGHT },
|
|
10660
|
+
];
|
|
10661
|
+
const PRELOAD_FORMAT = 'woff2';
|
|
10662
|
+
/**
|
|
10663
|
+
* The uploaded files the SSR head preloads (§5b — no flash of the fallback face): for the display and
|
|
10664
|
+
* body roles, the family each token names (its first uploaded family), the woff2 normal-style cut CSS
|
|
10665
|
+
* matching would pick for that role's weights. One file per weight that renders, never the family.
|
|
10666
|
+
*/
|
|
10667
|
+
function fontPreloads(descriptors, tokens) {
|
|
10668
|
+
const families = groupFontFamilies(descriptors);
|
|
10669
|
+
if (!families.length)
|
|
10670
|
+
return [];
|
|
10671
|
+
const resolved = resolveTokenValues(tokens);
|
|
10672
|
+
const out = new Map();
|
|
10673
|
+
for (const { role, weights, fallback } of PRELOAD_ROLES) {
|
|
10674
|
+
const named = parseFontFamilies(resolved[role] ?? '').map(fontFamilyKey);
|
|
10675
|
+
const family = named.map(key => families.find(f => fontFamilyKey(f.family) === key)).find(Boolean);
|
|
10676
|
+
const faces = family?.faces.filter(f => f.format === PRELOAD_FORMAT && normalizeFontStyle(f.style) === 'normal') ?? [];
|
|
10677
|
+
for (const token of weights) {
|
|
10678
|
+
const weight = Number.parseInt(resolved[token] ?? '', 10);
|
|
10679
|
+
const face = matchFontWeight(faces, Number.isFinite(weight) ? weight : fallback);
|
|
10680
|
+
if (face)
|
|
10681
|
+
out.set(face.url, face);
|
|
10682
|
+
}
|
|
10683
|
+
}
|
|
10684
|
+
return [...out.values()];
|
|
10685
|
+
}
|
|
10532
10686
|
|
|
10533
10687
|
/**
|
|
10534
10688
|
* A flavor's COMPLETE token set for a studio's choices (design-system plan §3a/§3e). A flavor IS
|
|
@@ -11057,6 +11211,34 @@ function planSwissMigration(existing, stored) {
|
|
|
11057
11211
|
}
|
|
11058
11212
|
return { choices, plan };
|
|
11059
11213
|
}
|
|
11214
|
+
/**
|
|
11215
|
+
* Plan the removal of an uploaded family from the look: the roles naming it fall back to the pack's
|
|
11216
|
+
* own font (the design's pairing), as the guard promises — "Nothing else changes".
|
|
11217
|
+
*/
|
|
11218
|
+
function planFontFamilyRemoval(existing, previous, family) {
|
|
11219
|
+
const roles = fontRoleReferences(existing, family);
|
|
11220
|
+
const fonts = Object.fromEntries(Object.entries(previous.choices.fonts ?? {})
|
|
11221
|
+
.filter(([, chosen]) => fontFamilyKey(chosen) !== fontFamilyKey(family)));
|
|
11222
|
+
const choices = { ...previous.choices };
|
|
11223
|
+
if (Object.keys(fonts).length)
|
|
11224
|
+
choices.fonts = fonts;
|
|
11225
|
+
else
|
|
11226
|
+
delete choices.fonts;
|
|
11227
|
+
if (!roles.length)
|
|
11228
|
+
return { roles, choices: previous.choices, plan: { create: [], update: [], kept: [] }, fallbacks: [] };
|
|
11229
|
+
const plan = planDesignApply(existing, previous, choices);
|
|
11230
|
+
const desired = new Map(designTokenRows(choices).map(r => [r.name, r]));
|
|
11231
|
+
const planned = new Set(plan.update.map(u => u.id));
|
|
11232
|
+
for (const row of existing ?? []) {
|
|
11233
|
+
const want = desired.get(row.name);
|
|
11234
|
+
if (!row._id || !want || planned.has(row._id) || !roles.includes(row.name))
|
|
11235
|
+
continue;
|
|
11236
|
+
plan.update.push({ id: row._id, data: { value: want.value, values: want.values ?? {}, source: want.source } });
|
|
11237
|
+
plan.kept = plan.kept.filter(name => name !== row.name);
|
|
11238
|
+
}
|
|
11239
|
+
const fallbacks = roles.map(role => ({ role, family: parseFontFamilies(desired.get(role)?.value ?? '')[0] ?? '' }));
|
|
11240
|
+
return { roles, choices, plan, fallbacks };
|
|
11241
|
+
}
|
|
11060
11242
|
|
|
11061
11243
|
/**
|
|
11062
11244
|
* @vectoriox/iox-ui/design-core — the shared, FRAMEWORK-FREE core of the design system
|
|
@@ -11073,5 +11255,5 @@ function planSwissMigration(existing, stored) {
|
|
|
11073
11255
|
* Generated bundle index. Do not edit.
|
|
11074
11256
|
*/
|
|
11075
11257
|
|
|
11076
|
-
export { ACCENT_TOKEN_NAMES, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, OwnedTraitLink, PALETTE_PRESETS, REDUCED_MOTION_OVERRIDES, REDUCED_TRANSPARENCY_OVERRIDES, REVERT_WINDOW_MS, SPEC_A11Y, SPEC_AXES, SPEC_BUTTON_VARIANT_TO_STYLE, SPEC_CONTRAST, SPEC_DEFAULT_ELEMENT_STYLE, SPEC_ELEMENT_STYLES, SPEC_FIELD_CLASS_BASELINE, SPEC_FLAVORS, SPEC_FLAVOR_PACKS, SPEC_FONTS, SPEC_FONT_ROLES, SPEC_LEGACY_ALIASES, SPEC_PALETTE_PRESETS, SPEC_SCHEMES, SPEC_SPRINGS, SPEC_TIERS, SPEC_TIER_IDS, SPEC_TOKEN_TYPES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, choicesForPack, colorSchemeClass, colorSchemeOf, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSourceStamp, fontsForTokens, googleFontHref, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isRetiredFlavorId, legacyRuleTokenReferences, missingDesignRows, nodeDesignClasses, oklabToRgb, ownedTraitStatus, packDesignChoices, parseFontFamilies, parseHexColor, planDesignApply, planFlavorRevert, planFlavorSeed, planSwissMigration, readDesignConfig, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, userFontStack, validateFlavorPack, wcagContrastRatio };
|
|
11258
|
+
export { ACCENT_TOKEN_NAMES, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, FONT_FILE_ACCEPT, FONT_FILE_EXTENSIONS, FONT_FILE_FORMATS, FONT_STYLES, FONT_WEIGHTS, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, OwnedTraitLink, PALETTE_PRESETS, REDUCED_MOTION_OVERRIDES, REDUCED_TRANSPARENCY_OVERRIDES, REVERT_WINDOW_MS, SPEC_A11Y, SPEC_AXES, SPEC_BUTTON_VARIANT_TO_STYLE, SPEC_CONTRAST, SPEC_DEFAULT_ELEMENT_STYLE, SPEC_ELEMENT_STYLES, SPEC_FIELD_CLASS_BASELINE, SPEC_FLAVORS, SPEC_FLAVOR_PACKS, SPEC_FONTS, SPEC_FONT_ROLES, SPEC_LEGACY_ALIASES, SPEC_PALETTE_PRESETS, SPEC_SCHEMES, SPEC_SPRINGS, SPEC_TIERS, SPEC_TIER_IDS, SPEC_TOKEN_TYPES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, choicesForPack, colorSchemeClass, colorSchemeOf, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSourceStamp, fontFamilyKey, fontFileName, fontFileStem, fontFormatOf, fontPreloads, fontRoleReferences, fontsForTokens, googleFontHref, groupFontFamilies, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isRetiredFlavorId, legacyRuleTokenReferences, matchFontWeight, missingDesignRows, nodeDesignClasses, normalizeFontStyle, normalizeFontWeight, oklabToRgb, ownedTraitStatus, packDesignChoices, parseFontFamilies, parseHexColor, planDesignApply, planFlavorRevert, planFlavorSeed, planFontFamilyRemoval, planSwissMigration, readDesignConfig, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, stackNamesFamily, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, userFontStack, validateFlavorPack, wcagContrastRatio };
|
|
11077
11259
|
//# sourceMappingURL=vectoriox-iox-ui-design-core.mjs.map
|