Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | 155x 6x 152x 66x 86x 60x 60x 11x 32x 27x 49x 49x 155x 155x 155x 70x 94x 94x 94x 5x 92x 31x 94x 94x 12x 94x 94x 94x 7x 32x 22x 94x | /**
* Class Name Rules
*
* Builds conditional class name rules from UIF modifiers, states, and variants.
*/
import type { ResolvedUIF, ResolvedModifier, ResolvedStructure } from '@fds-uif/schema';
import { getVariants } from '@fds-uif/core/browser';
import type { ClassNameRule } from '../types/index.js';
import { sanitizeIdentifier } from '../types/index.js';
/**
* Convert a static class attribute value (string or string[]) to a flat array of class tokens.
*/
function parseStaticClass(staticClass: unknown): string[] {
if (Array.isArray(staticClass)) {
return staticClass.flatMap((c) => String(c).split(' ').filter(Boolean));
}
if (typeof staticClass === 'string') {
return staticClass.split(' ').filter(Boolean);
}
return [];
}
/**
* Build conditional class entries from a single modifier.
* Grouped modifiers (with options) produce one equality condition per option;
* boolean modifiers produce a single presence condition.
*/
function modifierToConditionals(modifier: ResolvedModifier): Array<{ classes: string[]; condition: string }> {
Iif (modifier.attribute !== 'class') return [];
if (modifier.options && modifier.options.length > 0) {
return modifier.options
.filter((o) => o.value)
.map((o) => ({
classes: [o.value],
condition: `${sanitizeIdentifier(modifier.name)} === '${o.propValue}'`,
}));
}
Eif (modifier.value) {
return [{ classes: [modifier.value], condition: sanitizeIdentifier(modifier.name) }];
}
return [];
}
/**
* Build class name rules for a single structure node from its own static class
* and modifiers. Used by `analyzeStructure` to attach per-node class rules to
* non-root elements that declare modifiers (e.g. a child `svg` with size options).
*
* Boolean modifiers produce a boolean condition; grouped modifiers (with `options`)
* produce variant-style equality conditions so they resolve against `state.variants`.
*/
export function buildNodeClassNameRules(structure: ResolvedStructure): ClassNameRule[] {
const baseClasses = parseStaticClass(structure.attributes?.static?.class);
const conditional = (structure.modifiers ?? []).flatMap(modifierToConditionals);
if (baseClasses.length === 0 && conditional.length === 0) return [];
return [{ base: baseClasses, conditional }];
}
/**
* Build class name rules for the ROOT element of a component from its
* root-level modifiers, state classes, and root-level variants.
*
* Child-element modifiers are intentionally excluded here — they are handled
* by `buildNodeClassNameRules` attached to each child `StructureMetadata`.
*/
export function buildClassNameRules(
uif: ResolvedUIF,
modifiers: ResolvedModifier[],
stateClasses: Array<{ state: string; class: string }>,
): ClassNameRule[] {
const baseClasses: string[] = [];
// Extract base class from structure.attributes.static.class (string or string[])
const staticClass = uif.structure.attributes?.static?.class;
if (Array.isArray(staticClass)) {
baseClasses.push(...staticClass.flatMap((c) => String(c).split(' ').filter(Boolean)));
} else if (typeof staticClass === 'string') {
baseClasses.push(...staticClass.split(' ').filter(Boolean));
}
// Build conditional rules
const conditional: Array<{ classes: string[]; condition: string }> = [];
// stateClasses → conditional on the active state
for (const sc of stateClasses) {
conditional.push({
classes: [sc.class],
condition: sanitizeIdentifier(sc.state),
});
}
// Root-level modifiers → conditional classes (boolean and grouped)
conditional.push(...modifiers.flatMap(modifierToConditionals));
// Root-level variants → conditional classes (switch-style, value-based)
const variants = getVariants(uif);
for (const variant of variants) {
for (const option of variant.options) {
if (option.class) {
conditional.push({
classes: [option.class],
condition: `${sanitizeIdentifier(variant.name)} === '${option.value}'`,
});
}
}
}
return [{ base: baseClasses, conditional }];
}
|