@vectoriox/iox-ui 5.12.1 → 5.13.1
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 +61 -7
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +102 -10
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +68 -18
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/index.d.ts +26 -7
- package/package.json +1 -1
- package/src/design-core/element-styles.ts +51 -0
- package/src/design-core/flavor-spec.generated.ts +26 -6
- package/src/design-core/public-api.ts +1 -0
- package/src/design-core/token-names.ts +32 -0
- package/styles/iox-forms.css +73 -58
package/index.d.ts
CHANGED
|
@@ -1399,16 +1399,21 @@ declare const HOVER_STATES: ReadonlyArray<string>;
|
|
|
1399
1399
|
declare function hasHoverState(stateStyles: Record<string, Record<string, any> | undefined> | null | undefined): boolean;
|
|
1400
1400
|
/**
|
|
1401
1401
|
* The base-rule transition a hovering node gets when it declares none of its own, so a hover
|
|
1402
|
-
* animates instead of snapping.
|
|
1403
|
-
*
|
|
1404
|
-
*
|
|
1402
|
+
* animates instead of snapping. ONE copy for the builder canvas, the style panel and the engine.
|
|
1403
|
+
*
|
|
1404
|
+
* Two values, chosen by the element-style MARKER (§3b-bis): a node wearing an element style takes
|
|
1405
|
+
* the motion tokens; a node without one (saved before DS2, not adopted) keeps the pre-DS2 literal
|
|
1406
|
+
* byte-for-byte — seeding an org's tokens must never change how a legacy page hovers.
|
|
1405
1407
|
*/
|
|
1406
|
-
declare const HOVER_DEFAULT_TRANSITION = "all var(--iox-dur-fast
|
|
1408
|
+
declare const HOVER_DEFAULT_TRANSITION = "all var(--iox-dur-fast) var(--iox-ease-standard)";
|
|
1409
|
+
declare const LEGACY_HOVER_TRANSITION = "all 0.2s ease";
|
|
1410
|
+
/** The default hover transition for a node that wears `elementStyle` (or none). */
|
|
1411
|
+
declare function defaultHoverTransition(elementStyle?: string | null): string;
|
|
1407
1412
|
/** True when the RAW style map already yields a transition (an explicit one, or the composed
|
|
1408
1413
|
* transitionDuration/TimingFunction an element style writes). */
|
|
1409
1414
|
declare function hasOwnTransition(styleProps: Record<string, any> | null | undefined): boolean;
|
|
1410
1415
|
/** `styleProps` plus the default hover transition when the node hovers and sets none itself. */
|
|
1411
|
-
declare function withDefaultHoverTransition(styleProps: Record<string, any>, stateStyles: Record<string, Record<string, any> | undefined> | null | undefined): Record<string, any>;
|
|
1416
|
+
declare function withDefaultHoverTransition(styleProps: Record<string, any>, stateStyles: Record<string, Record<string, any> | undefined> | null | undefined, elementStyle?: string | null): Record<string, any>;
|
|
1412
1417
|
/**
|
|
1413
1418
|
* Per-type default `width` that the builder applies from each component's config
|
|
1414
1419
|
* (NOT persisted in styleProps — see render-parity.md "saved node is not
|
|
@@ -1429,8 +1434,9 @@ declare const DEFAULT_WIDTH_BY_TYPE: Readonly<Record<string, string>>;
|
|
|
1429
1434
|
* @param type Node type (registry key).
|
|
1430
1435
|
* @param styleProps The node's persisted styleProps.
|
|
1431
1436
|
* @param hasHoverState Whether the node has a non-empty hover / parent-hover state.
|
|
1437
|
+
* @param elementStyle The element style the node wears — picks the default hover transition.
|
|
1432
1438
|
*/
|
|
1433
|
-
declare function renderDefaultDeclarations(type: string, styleProps: Record<string, any>, hasHoverState: boolean): string[];
|
|
1439
|
+
declare function renderDefaultDeclarations(type: string, styleProps: Record<string, any>, hasHoverState: boolean, elementStyle?: string | null): string[];
|
|
1434
1440
|
|
|
1435
1441
|
/**
|
|
1436
1442
|
* One composed output property and the virtual traits it is built from.
|
|
@@ -1457,6 +1463,19 @@ declare const BACKDROP_TWIN_KEY = "WebkitBackdropFilter";
|
|
|
1457
1463
|
declare const VIRTUAL_TRAIT_GROUPS: readonly VirtualTraitGroup[];
|
|
1458
1464
|
/** Every virtual trait key — derived from the groups so there is one list to maintain. */
|
|
1459
1465
|
declare const VIRTUAL_TRAIT_KEYS: Set<string>;
|
|
1466
|
+
/** True when the whole-value `backdropFilter` trait is SET — it then wins over the composed
|
|
1467
|
+
* backdrop* controls (`none` / empty is its unset value). The Style panel hides those controls on
|
|
1468
|
+
* exactly this condition, so what the panel shows live is what the compiler emits. */
|
|
1469
|
+
declare function isWholeBackdropSet(value: unknown): boolean;
|
|
1470
|
+
/**
|
|
1471
|
+
* The inverse of the backdrop composition: a resolved whole value (`blur(16px) saturate(1.4)`) →
|
|
1472
|
+
* the composed traits, every one of the group present (its default when absent; `140%` → `1.4` for
|
|
1473
|
+
* the factor sliders), so Detach can hand
|
|
1474
|
+
* a token's look back to the part controls. `none` / empty → all defaults. A value using anything
|
|
1475
|
+
* the group cannot express (another function, a `var()`, a percentage-free form it cannot read)
|
|
1476
|
+
* → null: the caller keeps it whole rather than silently dropping part of the look.
|
|
1477
|
+
*/
|
|
1478
|
+
declare function decomposeBackdropFilter(value: string | null | undefined): Record<string, string> | null;
|
|
1460
1479
|
/**
|
|
1461
1480
|
* Strip virtual trait keys from `raw` and emit their composed CSS equivalents.
|
|
1462
1481
|
*
|
|
@@ -2753,5 +2772,5 @@ declare class GalleryLoop {
|
|
|
2753
2772
|
private emit;
|
|
2754
2773
|
}
|
|
2755
2774
|
|
|
2756
|
-
export { AOSService, BACKDROP_TWIN_KEY, BACKDROP_WHOLE_KEY, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CONTAINER_HTML_TAGS, CONTEXT_ACTION_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ContainerComponent, ContextStore, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_PHOSPHOR_WEIGHT, DEFAULT_WIDTH_BY_TYPE, DeclarationContext, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, HOVER_DEFAULT_TRANSITION, HOVER_STATES, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxDialogComponent, IoxFieldComponent, IoxFormComponent, IoxFormErrorComponent, IoxFormSuccessComponent, IoxPageComponent, IoxPageModule, IoxSubmitButtonComponent, IoxUiModule, LinkedContainerComponent, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, RESERVED_ALIAS_PREFIX, STATE_PSEUDO_CLASS, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_RESPONSIVE_TRAITS, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, activeActions, applyBindingPipes, applyFeel, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, composeVirtualTraits, computeRelative, containerHtmlTag, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, defaultMessageResolver, deriveSeoFromContent, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, getByPath, getSeoValue, hasHoverState, hasOwnTransition, initialSlotValues, isActionEnabled, isContextAction, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, nearestCommonAncestorId, nodeCssId, nodeUsesContext, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveValueChain, rewriteViewportUnits, safeSetInput, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, statePseudoClass, stripSuppressedProps, variableAliases, variableItemsFrom, withContextSlots, withDefaultHoverTransition, wrapInBreakpointQuery, wrapInMediaQuery };
|
|
2775
|
+
export { AOSService, BACKDROP_TWIN_KEY, BACKDROP_WHOLE_KEY, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CONTAINER_HTML_TAGS, CONTEXT_ACTION_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ContainerComponent, ContextStore, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_PHOSPHOR_WEIGHT, DEFAULT_WIDTH_BY_TYPE, DeclarationContext, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, HOVER_DEFAULT_TRANSITION, HOVER_STATES, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxDialogComponent, IoxFieldComponent, IoxFormComponent, IoxFormErrorComponent, IoxFormSuccessComponent, IoxPageComponent, IoxPageModule, IoxSubmitButtonComponent, IoxUiModule, LEGACY_HOVER_TRANSITION, LinkedContainerComponent, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, RESERVED_ALIAS_PREFIX, STATE_PSEUDO_CLASS, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_RESPONSIVE_TRAITS, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, activeActions, applyBindingPipes, applyFeel, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, composeVirtualTraits, computeRelative, containerHtmlTag, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, decomposeBackdropFilter, defaultHoverTransition, defaultMessageResolver, deriveSeoFromContent, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, getByPath, getSeoValue, hasHoverState, hasOwnTransition, initialSlotValues, isActionEnabled, isContextAction, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, isWholeBackdropSet, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, nearestCommonAncestorId, nodeCssId, nodeUsesContext, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveValueChain, rewriteViewportUnits, safeSetInput, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, statePseudoClass, stripSuppressedProps, variableAliases, variableItemsFrom, withContextSlots, withDefaultHoverTransition, wrapInBreakpointQuery, wrapInMediaQuery };
|
|
2757
2776
|
export type { BoundValueSpec, BreakpointDef, BuildRelatedFilterOptions, ContextActionEffect, ContextActionLike, ContextItemRef, ContextSlotDefault, ContextValueSpec, ContextWriteScope, DataSourceDomain, DataSourceEndpoints, DataSourceMode, DataSourcePlan, DataSourceQueryFilter, DataSourceRequest, DataSourceRequestSpec, DataSourceRouteFilter, DataSourceSpec, FormMessageResolver, GalleryBoundSource, GalleryDurations, GalleryEffect, GalleryEffectDescriptor, GalleryImage, GalleryLoopOptions, GalleryLoopScheduler, GalleryLoopState, GallerySlideState, IBuilderEventEmitter, InputMap, IoxContextSlot, IoxPipe, OverrideBreakpoint, PageStyleSettings, PageTransitionCategory, PageTransitionCategoryMeta, PageTransitionOptions, PageTransitionPreset, PipeArgSpec, PipeContext, PipeDescriptor, RelativeInputs, RelativeSourceKind, RelativeSourceSpec, ResolveSiblingsOptions, ResolvedPageTransition, ResponsiveLayer, ResponsiveOverrides, ResponsiveRuleSet, RouteContext, SeoDerivedContent, SeoFieldSource, SeoFieldState, SeoResolveContext, SetContextParams, SiblingsResult, StateStyleMap, StyleMap, StyleTreeNode, SwiperBreakpointMap, ToggleableAction, TransitionFeel, TransitionPhase, TransitionTimelineInput, ValueSource, VirtualTraitGroup };
|
package/package.json
CHANGED
|
@@ -269,3 +269,54 @@ export function switchElementStyle(
|
|
|
269
269
|
writeEntries(target, to, kept);
|
|
270
270
|
return { applied: true, kept };
|
|
271
271
|
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* The element-style MARKER (design-system §3b-bis, spec `elementStyleMarker`). A node that wears an
|
|
275
|
+
* element style renders `iox-es iox-es-<id>` in BOTH renderers; every piece of component CSS that
|
|
276
|
+
* carries the system look is scoped to it, so a node saved before DS2 (no `elementStyle`) keeps its
|
|
277
|
+
* exact pre-DS2 component CSS no matter which tokens the org holds. This is the ONLY thing a
|
|
278
|
+
* renderer reads `elementStyle` for.
|
|
279
|
+
*/
|
|
280
|
+
export const ELEMENT_STYLE_MARKER_CLASS = 'iox-es';
|
|
281
|
+
|
|
282
|
+
const MARKER_PREFIX = `${ELEMENT_STYLE_MARKER_CLASS}-`;
|
|
283
|
+
|
|
284
|
+
/** `iox-es-<id>` for a known style, else null — an unknown id never reaches a class attribute. */
|
|
285
|
+
export function elementStyleClass(id: string | null | undefined): string | null {
|
|
286
|
+
return elementStyleById(id) ? `${MARKER_PREFIX}${id}` : null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** The marker classes a node renders: `'iox-es iox-es-<id>'`, or `''` for a node with no (known) style. */
|
|
290
|
+
export function elementStyleClasses(node: { elementStyle?: string | null } | null | undefined): string {
|
|
291
|
+
const own = elementStyleClass(node?.elementStyle);
|
|
292
|
+
return own ? `${ELEMENT_STYLE_MARKER_CLASS} ${own}` : '';
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Make an element's marker match `elementStyle` — the live switch on the canvas, and the
|
|
296
|
+
* component path's one-time stamp. Removes a stale `iox-es-<old>`; touches no other class. */
|
|
297
|
+
export function syncElementStyleMarker(el: { classList: DOMTokenList } | null | undefined, elementStyle: string | null | undefined): void {
|
|
298
|
+
if (!el?.classList) return;
|
|
299
|
+
const stale = Array.from(el.classList).filter(c => c === ELEMENT_STYLE_MARKER_CLASS || c.startsWith(MARKER_PREFIX));
|
|
300
|
+
for (const c of stale) el.classList.remove(c);
|
|
301
|
+
const classes = elementStyleClasses({ elementStyle });
|
|
302
|
+
if (classes) el.classList.add(...classes.split(' '));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* The spec's `headingLevelRule`: changing a Heading's level moves it to the new level's DEFAULT
|
|
307
|
+
* style only when it still wears its old level's default (author changes kept, via
|
|
308
|
+
* `switchElementStyle`); a Heading wearing any other style — or none — is left alone. Returns null
|
|
309
|
+
* when nothing switched.
|
|
310
|
+
*/
|
|
311
|
+
export function applyHeadingLevelRule(
|
|
312
|
+
target: ElementStyleTarget,
|
|
313
|
+
oldLevel: string | null | undefined,
|
|
314
|
+
newLevel: string | null | undefined,
|
|
315
|
+
baseline: Readonly<Record<string, unknown>> = {},
|
|
316
|
+
): SwitchElementStyleResult | null {
|
|
317
|
+
if (target.type !== 'Heading' || oldLevel === newLevel) return null;
|
|
318
|
+
const from = defaultElementStyleFor('Heading', { level: oldLevel });
|
|
319
|
+
const to = defaultElementStyleFor('Heading', { level: newLevel });
|
|
320
|
+
if (!from || !to || target.elementStyle !== from || from === to) return null;
|
|
321
|
+
return switchElementStyle(target, from, to, baseline);
|
|
322
|
+
}
|
|
@@ -1607,6 +1607,24 @@ export const SPEC_ELEMENT_STYLES = [
|
|
|
1607
1607
|
"borderColor": "var(--iox-dialog-border)"
|
|
1608
1608
|
}
|
|
1609
1609
|
},
|
|
1610
|
+
{
|
|
1611
|
+
"id": "form",
|
|
1612
|
+
"label": "Form",
|
|
1613
|
+
"group": "Forms",
|
|
1614
|
+
"appliesTo": [
|
|
1615
|
+
"Form"
|
|
1616
|
+
],
|
|
1617
|
+
"base": {}
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
"id": "field",
|
|
1621
|
+
"label": "Field",
|
|
1622
|
+
"group": "Forms",
|
|
1623
|
+
"appliesTo": [
|
|
1624
|
+
"Field"
|
|
1625
|
+
],
|
|
1626
|
+
"base": {}
|
|
1627
|
+
},
|
|
1610
1628
|
{
|
|
1611
1629
|
"id": "notice-success",
|
|
1612
1630
|
"label": "Success message",
|
|
@@ -1655,6 +1673,8 @@ export const SPEC_DEFAULT_ELEMENT_STYLE = {
|
|
|
1655
1673
|
"Divider": "rule",
|
|
1656
1674
|
"Icon": "icon",
|
|
1657
1675
|
"Dialog": "dialog",
|
|
1676
|
+
"Form": "form",
|
|
1677
|
+
"Field": "field",
|
|
1658
1678
|
"FormSuccess": "notice-success",
|
|
1659
1679
|
"FormError": "notice-error"
|
|
1660
1680
|
} as const;
|
|
@@ -1703,7 +1723,7 @@ export const SPEC_PALETTE_PRESETS = [
|
|
|
1703
1723
|
] as const;
|
|
1704
1724
|
|
|
1705
1725
|
export const SPEC_FIELD_CLASS_BASELINE = {
|
|
1706
|
-
".iox-field__control": {
|
|
1726
|
+
".iox-es-field .iox-field__control": {
|
|
1707
1727
|
"background": "var(--iox-field-bg)",
|
|
1708
1728
|
"color": "var(--iox-field-ink)",
|
|
1709
1729
|
"border-width": "var(--iox-field-border-width)",
|
|
@@ -1715,26 +1735,26 @@ export const SPEC_FIELD_CLASS_BASELINE = {
|
|
|
1715
1735
|
"font-size": "var(--iox-size-body)",
|
|
1716
1736
|
"transition": "border-color var(--iox-dur-base) var(--iox-ease-standard), box-shadow var(--iox-dur-base) var(--iox-ease-standard)"
|
|
1717
1737
|
},
|
|
1718
|
-
".iox-field__control:focus-visible": {
|
|
1738
|
+
".iox-es-field .iox-field__control:focus-visible": {
|
|
1719
1739
|
"border-color": "var(--iox-accent)",
|
|
1720
1740
|
"box-shadow": "var(--iox-field-focus)",
|
|
1721
1741
|
"outline": "none"
|
|
1722
1742
|
},
|
|
1723
|
-
".iox-field__label": {
|
|
1743
|
+
".iox-es-field .iox-field__label": {
|
|
1724
1744
|
"font-family": "var(--iox-font-body)",
|
|
1725
1745
|
"font-size": "var(--iox-field-label-size)",
|
|
1726
1746
|
"font-weight": "var(--iox-field-label-weight)",
|
|
1727
1747
|
"color": "var(--iox-text)"
|
|
1728
1748
|
},
|
|
1729
|
-
".iox-field__help": {
|
|
1749
|
+
".iox-es-field .iox-field__help": {
|
|
1730
1750
|
"font-size": "var(--iox-size-small)",
|
|
1731
1751
|
"color": "var(--iox-text-muted)"
|
|
1732
1752
|
},
|
|
1733
|
-
".iox-field__error": {
|
|
1753
|
+
".iox-es-field .iox-field__error": {
|
|
1734
1754
|
"font-size": "var(--iox-size-small)",
|
|
1735
1755
|
"color": "var(--iox-danger)"
|
|
1736
1756
|
},
|
|
1737
|
-
".iox-invalid .iox-field__control": {
|
|
1757
|
+
".iox-es-field.iox-invalid .iox-field__control": {
|
|
1738
1758
|
"border-color": "var(--iox-danger)"
|
|
1739
1759
|
}
|
|
1740
1760
|
} as const;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SPEC_LEGACY_ALIASES, SPEC_TIERS } from './flavor-spec.generated';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Which `--iox-<name>` a piece of COMPONENT CSS may reference (design-system §3b-bis: "component CSS
|
|
5
|
+
* may reference ONLY tokens defined in this spec"). DS2 shipped seven names nobody defines
|
|
6
|
+
* (`card-media-gap`, `gallery-overlay`, `dialog-close-bg`…): a token the contract does not define can
|
|
7
|
+
* never be set by a flavor, so it is a literal wearing a costume. One guard, run over BOTH
|
|
8
|
+
* renderers' component CSS (iox-ui's spec; the engine's `verify:token-names`).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** The 161 names of the contract's two tiers, plus its legacy aliases. */
|
|
12
|
+
export function specTokenNames(): ReadonlySet<string> {
|
|
13
|
+
return new Set([
|
|
14
|
+
...SPEC_TIERS.semantic.map(t => t.name),
|
|
15
|
+
...SPEC_TIERS.component.map(t => t.name),
|
|
16
|
+
...Object.keys(SPEC_LEGACY_ALIASES),
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const REFERENCE = /var\(\s*--iox-([a-z0-9-]+)/gi;
|
|
21
|
+
|
|
22
|
+
/** Every distinct token a stylesheet READS (`var(--iox-x…)`), in first-seen order. */
|
|
23
|
+
export function tokenReferences(css: string): string[] {
|
|
24
|
+
return [...new Set(Array.from(css.matchAll(REFERENCE), m => m[1]))];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The referenced names that are neither spec tokens nor in `alsoAllowed`. */
|
|
28
|
+
export function unknownTokenReferences(css: string, alsoAllowed: Iterable<string> = []): string[] {
|
|
29
|
+
const spec = specTokenNames();
|
|
30
|
+
const extra = new Set(alsoAllowed);
|
|
31
|
+
return tokenReferences(css).filter(name => !spec.has(name) && !extra.has(name));
|
|
32
|
+
}
|
package/styles/iox-forms.css
CHANGED
|
@@ -49,74 +49,25 @@
|
|
|
49
49
|
.iox-field__error { margin: 4px 0 0; }
|
|
50
50
|
.iox-submit { font: inherit; border: none; cursor: pointer; }
|
|
51
51
|
|
|
52
|
-
/* ── Visual baseline — EXACTLY the spec's `fieldClassBaseline` (design-system plan DS2) ──────────
|
|
53
|
-
* Every value is a token, so a re-theme restyles every form with no page write. Each var() carries
|
|
54
|
-
* today's value as its fallback (trap T6) — `inherit` where the structural rule above inherits, the
|
|
55
|
-
* engine reset's `0` for padding, and `revert` (the UA default, which is what rendered before) for
|
|
56
|
-
* everything nothing declared — so an org whose tokens are not seeded renders as it did.
|
|
57
|
-
* Two spec values are bare keywords and cannot fall back: `border-style: solid` (the UA inset
|
|
58
|
-
* border becomes solid) and the focus ring's `outline: none`, whose box-shadow therefore falls back
|
|
59
|
-
* to a visible system-colour ring rather than to nothing. */
|
|
60
|
-
.iox-field__control {
|
|
61
|
-
background: var(--iox-field-bg, revert);
|
|
62
|
-
color: var(--iox-field-ink, inherit);
|
|
63
|
-
border-width: var(--iox-field-border-width, revert);
|
|
64
|
-
border-style: solid;
|
|
65
|
-
border-color: var(--iox-field-border, revert);
|
|
66
|
-
border-radius: var(--iox-field-radius, revert);
|
|
67
|
-
padding: var(--iox-field-pad, 0);
|
|
68
|
-
font-family: var(--iox-font-body, inherit);
|
|
69
|
-
font-size: var(--iox-size-body, inherit);
|
|
70
|
-
transition: border-color var(--iox-dur-base, 0s) var(--iox-ease-standard, ease), box-shadow var(--iox-dur-base, 0s) var(--iox-ease-standard, ease);
|
|
71
|
-
}
|
|
72
|
-
.iox-field__control:focus-visible {
|
|
73
|
-
border-color: var(--iox-accent, revert);
|
|
74
|
-
box-shadow: var(--iox-field-focus, 0 0 0 2px Highlight);
|
|
75
|
-
outline: none;
|
|
76
|
-
}
|
|
77
|
-
.iox-field__label {
|
|
78
|
-
font-family: var(--iox-font-body, inherit);
|
|
79
|
-
font-size: var(--iox-field-label-size, inherit);
|
|
80
|
-
font-weight: var(--iox-field-label-weight, inherit);
|
|
81
|
-
color: var(--iox-text, inherit);
|
|
82
|
-
}
|
|
83
|
-
.iox-field__help {
|
|
84
|
-
font-size: var(--iox-size-small, inherit);
|
|
85
|
-
color: var(--iox-text-muted, inherit);
|
|
86
|
-
}
|
|
87
|
-
.iox-field__error {
|
|
88
|
-
font-size: var(--iox-size-small, inherit);
|
|
89
|
-
color: var(--iox-danger, inherit);
|
|
90
|
-
}
|
|
91
|
-
.iox-invalid .iox-field__control {
|
|
92
|
-
border-color: var(--iox-danger, revert);
|
|
93
|
-
}
|
|
94
|
-
/* Native-appearance controls (checkbox, radio, range — and the switch, a checkbox) draw themselves:
|
|
95
|
-
the box baseline must not frame them. `:where()` keeps this at the baseline's specificity, so the
|
|
96
|
-
switch rules below still paint the track. */
|
|
97
|
-
.iox-field__control:where([type='checkbox'], [type='radio'], [type='range']) {
|
|
98
|
-
border: none;
|
|
99
|
-
padding: 0;
|
|
100
|
-
background: transparent;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
52
|
/* Visually hidden, still announced — a label may be hidden, never deleted. */
|
|
104
53
|
.iox-field__label--hidden {
|
|
105
54
|
position: absolute; width: 1px; height: 1px; margin: -1px;
|
|
106
55
|
padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
|
|
107
56
|
}
|
|
108
57
|
|
|
109
|
-
/* ── switch (control='switch') — a checkbox in switch clothing
|
|
58
|
+
/* ── switch (control='switch') — a checkbox in switch clothing. A Field saved before element styles
|
|
59
|
+
keeps exactly this look WHATEVER tokens the org holds (§3b-bis, D5): literals only, because a
|
|
60
|
+
token read here (the old `--iox-line` / `--iox-brand-500`) changes the moment seeding writes it. ── */
|
|
110
61
|
.iox-field__control--switch {
|
|
111
62
|
appearance: none;
|
|
112
63
|
-webkit-appearance: none;
|
|
113
64
|
width: 38px;
|
|
114
65
|
height: 22px;
|
|
115
66
|
border-radius: 999px;
|
|
116
|
-
background:
|
|
67
|
+
background: #d8d4d1;
|
|
117
68
|
position: relative;
|
|
118
69
|
cursor: pointer;
|
|
119
|
-
transition: background
|
|
70
|
+
transition: background 150ms ease-out;
|
|
120
71
|
flex-shrink: 0;
|
|
121
72
|
}
|
|
122
73
|
.iox-field__control--switch::before {
|
|
@@ -127,11 +78,11 @@
|
|
|
127
78
|
width: 16px;
|
|
128
79
|
height: 16px;
|
|
129
80
|
border-radius: 999px;
|
|
130
|
-
background:
|
|
131
|
-
transition: transform
|
|
81
|
+
background: #ffffff;
|
|
82
|
+
transition: transform 150ms ease-out;
|
|
132
83
|
}
|
|
133
84
|
.iox-field__control--switch:checked {
|
|
134
|
-
background:
|
|
85
|
+
background: #1f1d1b;
|
|
135
86
|
}
|
|
136
87
|
.iox-field__control--switch:checked::before {
|
|
137
88
|
transform: translateX(16px);
|
|
@@ -143,5 +94,69 @@
|
|
|
143
94
|
/* ── range (control='range') ── */
|
|
144
95
|
.iox-field__control--range {
|
|
145
96
|
width: 100%;
|
|
146
|
-
accent-color:
|
|
97
|
+
accent-color: #1f1d1b;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* ══ The system look — ONLY under the element-style marker (design-system §3b-bis) ═══════════════
|
|
101
|
+
* A Field wearing the `field` element style renders `iox-es iox-es-field`; everything below is
|
|
102
|
+
* scoped to it, so a Field saved before DS2 renders exactly as above whatever tokens the org holds,
|
|
103
|
+
* and seeding an org's tokens never restyles a live legacy form.
|
|
104
|
+
* The first six rules ARE the spec's `fieldClassBaseline`, selectors and values verbatim (pinned by
|
|
105
|
+
* iox-ui's field-baseline spec). Values are bare spec tokens: a marked Field only exists where the
|
|
106
|
+
* builder seeded them. */
|
|
107
|
+
.iox-es-field .iox-field__control {
|
|
108
|
+
background: var(--iox-field-bg);
|
|
109
|
+
color: var(--iox-field-ink);
|
|
110
|
+
border-width: var(--iox-field-border-width);
|
|
111
|
+
border-style: solid;
|
|
112
|
+
border-color: var(--iox-field-border);
|
|
113
|
+
border-radius: var(--iox-field-radius);
|
|
114
|
+
padding: var(--iox-field-pad);
|
|
115
|
+
font-family: var(--iox-font-body);
|
|
116
|
+
font-size: var(--iox-size-body);
|
|
117
|
+
transition: border-color var(--iox-dur-base) var(--iox-ease-standard), box-shadow var(--iox-dur-base) var(--iox-ease-standard);
|
|
118
|
+
}
|
|
119
|
+
.iox-es-field .iox-field__control:focus-visible {
|
|
120
|
+
border-color: var(--iox-accent);
|
|
121
|
+
box-shadow: var(--iox-field-focus);
|
|
122
|
+
outline: none;
|
|
123
|
+
}
|
|
124
|
+
.iox-es-field .iox-field__label {
|
|
125
|
+
font-family: var(--iox-font-body);
|
|
126
|
+
font-size: var(--iox-field-label-size);
|
|
127
|
+
font-weight: var(--iox-field-label-weight);
|
|
128
|
+
color: var(--iox-text);
|
|
129
|
+
}
|
|
130
|
+
.iox-es-field .iox-field__help {
|
|
131
|
+
font-size: var(--iox-size-small);
|
|
132
|
+
color: var(--iox-text-muted);
|
|
133
|
+
}
|
|
134
|
+
.iox-es-field .iox-field__error {
|
|
135
|
+
font-size: var(--iox-size-small);
|
|
136
|
+
color: var(--iox-danger);
|
|
137
|
+
}
|
|
138
|
+
.iox-es-field.iox-invalid .iox-field__control {
|
|
139
|
+
border-color: var(--iox-danger);
|
|
140
|
+
}
|
|
141
|
+
/* Native-appearance controls (checkbox, radio, range — and the switch, a checkbox) draw themselves:
|
|
142
|
+
the box baseline must not frame them. `:where()` keeps this at the baseline's specificity, so the
|
|
143
|
+
switch rules below still paint the track. */
|
|
144
|
+
.iox-es-field .iox-field__control:where([type='checkbox'], [type='radio'], [type='range']) {
|
|
145
|
+
border: none;
|
|
146
|
+
padding: 0;
|
|
147
|
+
background: transparent;
|
|
148
|
+
}
|
|
149
|
+
.iox-es-field .iox-field__control--switch {
|
|
150
|
+
background: var(--iox-line);
|
|
151
|
+
transition: background var(--iox-dur-fast) var(--iox-ease-standard);
|
|
152
|
+
}
|
|
153
|
+
.iox-es-field .iox-field__control--switch::before {
|
|
154
|
+
background: var(--iox-accent-ink);
|
|
155
|
+
transition: transform var(--iox-dur-fast) var(--iox-ease-standard);
|
|
156
|
+
}
|
|
157
|
+
.iox-es-field .iox-field__control--switch:checked {
|
|
158
|
+
background: var(--iox-accent);
|
|
159
|
+
}
|
|
160
|
+
.iox-es-field .iox-field__control--range {
|
|
161
|
+
accent-color: var(--iox-accent);
|
|
147
162
|
}
|