@vectoriox/iox-ui 5.40.0 → 5.41.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/composite-core/index.d.ts +210 -12
- package/design-core/index.d.ts +694 -17
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs +4 -3
- package/fesm2022/vectoriox-iox-ui-actions-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs +535 -121
- package/fesm2022/vectoriox-iox-ui-composite-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +843 -45
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +801 -17
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +3945 -3914
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/generation-core/index.d.ts +563 -4
- package/index.d.ts +22 -1
- package/package.json +1 -1
- package/src/actions-core/element-actions.ts +4 -3
- package/src/composite-core/accordion.ts +1 -0
- package/src/composite-core/composite-kinds.ts +42 -6
- package/src/composite-core/exclusive-runtime.ts +60 -10
- package/src/composite-core/exclusive.ts +64 -0
- package/src/composite-core/public-api.ts +5 -2
- package/src/composite-core/segmented.ts +349 -0
- package/src/composite-core/structure.ts +6 -1
- package/src/composite-core/tabs.ts +6 -3
- package/src/design-core/contrast-audit.ts +8 -3
- package/src/design-core/flavor-spec.generated.ts +832 -41
- package/src/generation-core/compose-site.ts +169 -12
- package/src/generation-core/node-baselines.generated.ts +49 -0
- package/src/generation-core/patterns.ts +20 -0
- package/src/generation-core/site-spec.generated.ts +595 -0
- package/styles/iox-design.css +19 -0
package/index.d.ts
CHANGED
|
@@ -1726,6 +1726,16 @@ declare const ON_STATE_ROLES: ReadonlyArray<string>;
|
|
|
1726
1726
|
* the same Item open state with a picked trigger.
|
|
1727
1727
|
*/
|
|
1728
1728
|
declare function componentStatesFor(type: string | null | undefined, role?: string | null, insideItem?: boolean, itemsToPick?: boolean): ComponentState[];
|
|
1729
|
+
/**
|
|
1730
|
+
* The states a node's rules are emitted LAST in (CC4b): `on` (`[data-iox-on]`) and `focus` (`:focus-visible`) tie on
|
|
1731
|
+
* specificity, so whichever comes later wins — a focused Segmented option that is ON must keep its focus ring over the
|
|
1732
|
+
* on shadow (board 10). Every renderer emits a node's state rules in `orderStatesForEmit` order.
|
|
1733
|
+
*/
|
|
1734
|
+
declare const LAST_EMITTED_STATES: ReadonlyArray<string>;
|
|
1735
|
+
/** `states` in the order their rules are emitted: as given, with the LAST_EMITTED_STATES moved to the end. */
|
|
1736
|
+
declare function orderStatesForEmit<T extends string>(states: ReadonlyArray<T>): T[];
|
|
1737
|
+
/** True when a rule key (`<nodeId>:<state>`) holds a state emitted last. */
|
|
1738
|
+
declare function isLastEmittedStateKey(key: string): boolean;
|
|
1729
1739
|
/**
|
|
1730
1740
|
* What follows `.iox-node-<id>` in a stored state's rule: `:hover`, `:focus-visible`, or a component
|
|
1731
1741
|
* state's attribute selector (`[aria-current="page"]`). Shared by the builder canvas and both engine paths.
|
|
@@ -2044,6 +2054,9 @@ declare const CURRENT_LINK_TYPES: ReadonlyArray<string>;
|
|
|
2044
2054
|
/** The types that are pure decoration to assistive technology (an Icon has no name of its own). */
|
|
2045
2055
|
declare const DECORATIVE_TYPES: ReadonlyArray<string>;
|
|
2046
2056
|
declare const DIALOG_NODE_TYPE = "Dialog";
|
|
2057
|
+
/** A Segmented control's root (CC4b) is a radio group that must be named (board 10: an empty name is an audit
|
|
2058
|
+
* finding). The main entry does not import composite-core, so the role is spelled here — a11y spec pins it. */
|
|
2059
|
+
declare const NAMED_GROUP_ROLES: ReadonlyArray<string>;
|
|
2047
2060
|
/** Carries the min-width (px) at which an open dialog closes itself; the engine listens on it. */
|
|
2048
2061
|
declare const DIALOG_CLOSE_ABOVE_ATTRIBUTE = "data-iox-dialog-close-above";
|
|
2049
2062
|
declare enum A11yAttribute {
|
|
@@ -2100,6 +2113,14 @@ declare function syncNodeA11yAttributes(el: {
|
|
|
2100
2113
|
declare function needsAccessibleName(node: (A11yNodeSource & {
|
|
2101
2114
|
children?: ReadonlyArray<unknown> | null;
|
|
2102
2115
|
}) | null | undefined): boolean;
|
|
2116
|
+
/**
|
|
2117
|
+
* True for a GROUP that must be named and is not — a Segmented control's radio group (CC4b, board 10): a screen reader
|
|
2118
|
+
* says "radio group" and nothing about what is being chosen. The responsive audit flags it; named in Bindings ▸
|
|
2119
|
+
* Accessibility.
|
|
2120
|
+
*/
|
|
2121
|
+
declare function needsGroupName(node: (A11yNodeSource & {
|
|
2122
|
+
role?: string | null;
|
|
2123
|
+
}) | null | undefined): boolean;
|
|
2103
2124
|
|
|
2104
2125
|
/**
|
|
2105
2126
|
* Reduced motion (CC1, R1 — complex-components plan §2d). The token sheet already collapses the
|
|
@@ -3404,5 +3425,5 @@ declare class GalleryLoop {
|
|
|
3404
3425
|
private emit;
|
|
3405
3426
|
}
|
|
3406
3427
|
|
|
3407
|
-
export { A11yAttribute, A11yTrait, ACCESSIBLE_NAME_TYPES, AOSService, ARIA_CURRENT_PAGE, BACKDROP_TWIN_KEY, BACKDROP_WHOLE_KEY, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, COMPONENT_STATE_SELECTOR, CONTAINER_HTML_TAGS, CONTEXT_ACTION_TYPES, CURRENT_LINK_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ComponentState, ContainerComponent, ContextStore, DECORATIVE_TYPES, 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, DIALOG_CLOSE_ABOVE_ATTRIBUTE, DIALOG_NODE_TYPE, DataSourceSortDir, DeclarationContext, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, HOVER_DEFAULT_TRANSITION, HOVER_STATES, INTERACTION_HIDDEN_ATTRIBUTE, 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, IoxVideoComponent, LEGACY_DIRECTION_KEY, LEGACY_HOVER_TRANSITION, LEGACY_SWIPER_CONTROLS, LinkedContainerComponent, MANAGED_A11Y_ATTRIBUTES, MAX_LINES_KEY, ON_STATE_ROLES, PAGE_STYLE_TOKENS, PAGE_TOKEN_FALLBACKS, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PART_PAGINATION_MODIFIER, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, PageStyleField, PageStyleSource, REDUCED_MOTION_QUERY, RESERVED_ALIAS_PREFIX, SLIDER_INPUTS_ATTRIBUTE, SLIDER_INPUT_NAMES, SORT_PARAM, STATE_PSEUDO_CLASS, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_A11Y_OPTIONS, SWIPER_RESPONSIVE_TRAITS, SWIPER_TRIGGER_EVENTS, SectionComponent, SwiperModuleName, TARGETED_STATE_SUFFIX, TEXT_ALIGN_KEY, TEXT_DIRECTION_KEY, TRANSITION_FEELS, TextAlign, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, VisibilityActionType, activeActions, applyBindingPipes, applyFeel, bootSlider, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildInteractionKeyframes, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTargetedSuffixSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, closeAboveMediaQuery, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, componentStatesFor, composeVirtualTraits, computeRelative, containerHtmlTag, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, decomposeBackdropFilter, defaultHoverTransition, defaultMessageResolver, deriveSeoFromContent, describePageStyle, describeSeoFields, dialogCloseAboveMinWidth, domHasSliderParts, effectiveActionType, effectiveTransitionId, entrancePreStateStyle, excludeSelf, feelFor, finalKeyframe, getByPath, getSeoValue, hasHoverState, hasOwnTransition, initialSlotValues, isActionEnabled, isContextAction, isCurrentLink, isExternalOrFragment, isGradientPaint, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, isWholeBackdropSet, keyframePropertyName, keyframeStyleEntries, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, migrateLegacyDirection, migrateLegacyTextAlign, motionAllowed, nearestCommonAncestorId, needsAccessibleName, nodeA11yAttributes, nodeCssId, nodeTraitValue, nodeUsesContext, normalizeAppPath, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, planSwiperOptions, prefersReducedMotion, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetPageStyleField, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveToggleVisibility, resolveValueChain, rewriteViewportUnits, safeSetInput, serializeA11yAttributes, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, sliderControlElements, sliderInputsFromProps, sliderInputsOf, sortParamValue, stateNamesIn, statePseudoClass, stateSelectorSuffix, stripSuppressedProps, swiperAutoplayAllowed, swiperLoopOptions, swiperModuleNames, syncNodeA11yAttributes, targetedStateSelector, variableAliases, variableItemsFrom, withContextSlots, withDefaultHoverTransition, wrapInBreakpointQuery, wrapInMediaQuery };
|
|
3428
|
+
export { A11yAttribute, A11yTrait, ACCESSIBLE_NAME_TYPES, AOSService, ARIA_CURRENT_PAGE, BACKDROP_TWIN_KEY, BACKDROP_WHOLE_KEY, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, COMPONENT_STATE_SELECTOR, CONTAINER_HTML_TAGS, CONTEXT_ACTION_TYPES, CURRENT_LINK_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ComponentState, ContainerComponent, ContextStore, DECORATIVE_TYPES, 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, DIALOG_CLOSE_ABOVE_ATTRIBUTE, DIALOG_NODE_TYPE, DataSourceSortDir, DeclarationContext, ENTRANCE_ACTION_TYPES, EXIT_ACTION_TYPES, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, HOVER_DEFAULT_TRANSITION, HOVER_STATES, INTERACTION_HIDDEN_ATTRIBUTE, 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, IoxVideoComponent, LAST_EMITTED_STATES, LEGACY_DIRECTION_KEY, LEGACY_HOVER_TRANSITION, LEGACY_SWIPER_CONTROLS, LinkedContainerComponent, MANAGED_A11Y_ATTRIBUTES, MAX_LINES_KEY, NAMED_GROUP_ROLES, ON_STATE_ROLES, PAGE_STYLE_TOKENS, PAGE_TOKEN_FALLBACKS, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PART_PAGINATION_MODIFIER, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, PageStyleField, PageStyleSource, REDUCED_MOTION_QUERY, RESERVED_ALIAS_PREFIX, SLIDER_INPUTS_ATTRIBUTE, SLIDER_INPUT_NAMES, SORT_PARAM, STATE_PSEUDO_CLASS, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_A11Y_OPTIONS, SWIPER_RESPONSIVE_TRAITS, SWIPER_TRIGGER_EVENTS, SectionComponent, SwiperModuleName, TARGETED_STATE_SUFFIX, TEXT_ALIGN_KEY, TEXT_DIRECTION_KEY, TRANSITION_FEELS, TextAlign, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, VisibilityActionType, activeActions, applyBindingPipes, applyFeel, bootSlider, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildInteractionKeyframes, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTargetedSuffixSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, closeAboveMediaQuery, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, componentStatesFor, composeVirtualTraits, computeRelative, containerHtmlTag, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, decomposeBackdropFilter, defaultHoverTransition, defaultMessageResolver, deriveSeoFromContent, describePageStyle, describeSeoFields, dialogCloseAboveMinWidth, domHasSliderParts, effectiveActionType, effectiveTransitionId, entrancePreStateStyle, excludeSelf, feelFor, finalKeyframe, getByPath, getSeoValue, hasHoverState, hasOwnTransition, initialSlotValues, isActionEnabled, isContextAction, isCurrentLink, isExternalOrFragment, isGradientPaint, isInputOverriddenAt, isLastEmittedStateKey, isOverriddenAt, isReservedAlias, isValidSlotKey, isWholeBackdropSet, keyframePropertyName, keyframeStyleEntries, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, migrateLegacyDirection, migrateLegacyTextAlign, motionAllowed, nearestCommonAncestorId, needsAccessibleName, needsGroupName, nodeA11yAttributes, nodeCssId, nodeTraitValue, nodeUsesContext, normalizeAppPath, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, orderStatesForEmit, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, planSwiperOptions, prefersReducedMotion, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetPageStyleField, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveToggleVisibility, resolveValueChain, rewriteViewportUnits, safeSetInput, serializeA11yAttributes, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, sliderControlElements, sliderInputsFromProps, sliderInputsOf, sortParamValue, stateNamesIn, statePseudoClass, stateSelectorSuffix, stripSuppressedProps, swiperAutoplayAllowed, swiperLoopOptions, swiperModuleNames, syncNodeA11yAttributes, targetedStateSelector, variableAliases, variableItemsFrom, withContextSlots, withDefaultHoverTransition, wrapInBreakpointQuery, wrapInMediaQuery };
|
|
3408
3429
|
export type { A11yNodeSource, BoundValueSpec, BreakpointDef, BuildRelatedFilterOptions, ContextActionEffect, ContextActionLike, ContextItemRef, ContextSlotDefault, ContextValueSpec, ContextWriteScope, CurrentLinkOptions, DataSourceDomain, DataSourceEndpoints, DataSourceMode, DataSourcePlan, DataSourceQueryFilter, DataSourceRequest, DataSourceRequestSpec, DataSourceRouteFilter, DataSourceSort, DataSourceSpec, FormMessageResolver, GalleryBoundSource, GalleryDurations, GalleryEffect, GalleryEffectDescriptor, GalleryImage, GalleryLoopOptions, GalleryLoopScheduler, GalleryLoopState, GallerySlideState, IBuilderEventEmitter, InputMap, InteractionKeyframe, IoxContextSlot, IoxPipe, MatchMediaHost, NodeA11yContext, OverrideBreakpoint, PageStyleFieldState, PageStyleOptions, PageStyleSettings, PageTransitionCategory, PageTransitionCategoryMeta, PageTransitionOptions, PageTransitionPreset, PipeArgSpec, PipeContext, PipeDescriptor, RelativeInputs, RelativeSourceKind, RelativeSourceSpec, ResolveSiblingsOptions, ResolvedPageTransition, ResponsiveLayer, ResponsiveOverrides, ResponsiveRuleSet, RouteContext, SeoDerivedContent, SeoFieldSource, SeoFieldState, SeoResolveContext, SetContextParams, SiblingsResult, SliderBootOptions, SliderControlElements, SliderInputs, StateStyleMap, StyleMap, StyleTreeNode, SwiperBreakpointMap, SwiperModuleFlags, SwiperPlan, SwiperPlanContext, ToggleableAction, TransitionFeel, TransitionPhase, TransitionTimelineInput, ValueSource, VirtualTraitGroup };
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { AccordionRole, CompositeItemAction, DisclosureRole, SLIDE_TO_ROW, TabsRole } from '@vectoriox/iox-ui/composite-core';
|
|
1
|
+
import { AccordionRole, CompositeItemAction, DisclosureRole, SegmentedRole, SLIDE_TO_ROW, TabsRole } from '@vectoriox/iox-ui/composite-core';
|
|
2
2
|
|
|
3
3
|
import { ActionDescriptor } from './action.model';
|
|
4
4
|
|
|
5
5
|
/** The items an item action may target: an accordion's item, or a disclosure (its own one item). */
|
|
6
6
|
const ITEM_TARGET_ROLES = [AccordionRole.Item, DisclosureRole.Disclosure];
|
|
7
|
-
/** Open also takes a TAB (CC4a)
|
|
8
|
-
|
|
7
|
+
/** Open also takes a TAB (CC4a) and a Segmented control's OPTION (CC4b, "Turn on"): it turns it on. Both always show
|
|
8
|
+
* one, so Close and Toggle never aim at either. */
|
|
9
|
+
const OPEN_TARGET_ROLES = [...ITEM_TARGET_ROLES, TabsRole.Trigger, SegmentedRole.Option];
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* The ELEMENT action catalog (actions plan A1) — what a node can DO, as data. One list feeds the
|
|
@@ -481,6 +481,7 @@ const DOM_ID_PREFIX: Readonly<Record<CompositeKind, string>> = {
|
|
|
481
481
|
[CompositeKind.Accordion]: 'iox-acc',
|
|
482
482
|
[CompositeKind.Disclosure]: 'iox-dis',
|
|
483
483
|
[CompositeKind.Tabs]: 'iox-tab',
|
|
484
|
+
[CompositeKind.Segmented]: 'iox-seg',
|
|
484
485
|
};
|
|
485
486
|
|
|
486
487
|
/** The ARIA pairing ids of an item: unique per composite (its SCOPE id — `compositeScopeId`) and per item (its key). */
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* The composites' kinds and roles. Two families:
|
|
3
3
|
* - OPEN/CLOSE (CC2 Accordion, CC2.1 Disclosure — composite plan T9 / T21): a Disclosure is a one-item accordion whose
|
|
4
4
|
* ROOT is its item, so both run the same state machine, attribute planners and runtime (`accordion-runtime.ts`);
|
|
5
|
-
* - EXCLUSIVE (CC4 Tabs — composite T17; the Segmented control
|
|
6
|
-
* its panel
|
|
5
|
+
* - EXCLUSIVE (CC4 Tabs — composite T17; CC4b the Segmented control — T32): exactly one item is on; a Tabs' trigger
|
|
6
|
+
* and its panel pair by `itemKey` (`tabs.ts`), a Segmented control's options have no panel (`segmented.ts`); both run
|
|
7
|
+
* `exclusive-runtime.ts`.
|
|
7
8
|
* Every consumer that treats "an item", "a trigger" or "a panel" alike asks these predicates, never a role literal.
|
|
8
9
|
*/
|
|
9
10
|
|
|
@@ -11,12 +12,13 @@ export enum CompositeKind {
|
|
|
11
12
|
Accordion = 'accordion',
|
|
12
13
|
Disclosure = 'disclosure',
|
|
13
14
|
Tabs = 'tabs',
|
|
15
|
+
Segmented = 'segmented',
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
/** The kinds the open/close runtime runs (`AccordionRuntime`). */
|
|
17
19
|
export type ToggleCompositeKind = CompositeKind.Accordion | CompositeKind.Disclosure;
|
|
18
20
|
/** The kinds the exclusive runtime runs (`ExclusiveRuntime`): one item on at a time, always one. */
|
|
19
|
-
export type ExclusiveCompositeKind = CompositeKind.Tabs;
|
|
21
|
+
export type ExclusiveCompositeKind = CompositeKind.Tabs | CompositeKind.Segmented;
|
|
20
22
|
|
|
21
23
|
export enum AccordionRole {
|
|
22
24
|
Accordion = 'accordion',
|
|
@@ -53,6 +55,17 @@ export enum TabsRole {
|
|
|
53
55
|
Panel = 'tabs.panel',
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
/**
|
|
59
|
+
* SEGMENTED (CC4b — composite T32; complex-components board 10). One of a few, always one on, FIXED options (R3): the
|
|
60
|
+
* root IS the radio group and holds the options directly — no list, no panels. An option may hold the optional saving
|
|
61
|
+
* badge (inside it, so its words join the option's accessible name).
|
|
62
|
+
*/
|
|
63
|
+
export enum SegmentedRole {
|
|
64
|
+
Segmented = 'segmented',
|
|
65
|
+
Option = 'segmented.option',
|
|
66
|
+
Badge = 'segmented.badge',
|
|
67
|
+
}
|
|
68
|
+
|
|
56
69
|
interface RoleLike { role?: string | null }
|
|
57
70
|
|
|
58
71
|
/** The roles each open/close kind plays in the shared runtime. */
|
|
@@ -69,11 +82,12 @@ export const COMPOSITE_KIND_ROLES: Readonly<Record<ToggleCompositeKind, Composit
|
|
|
69
82
|
[CompositeKind.Disclosure]: { root: DisclosureRole.Disclosure, item: DisclosureRole.Disclosure, trigger: DisclosureRole.Trigger, panel: DisclosureRole.Panel, icon: DisclosureRole.Icon },
|
|
70
83
|
};
|
|
71
84
|
|
|
72
|
-
/** The roles each EXCLUSIVE kind plays: its root, the holder of its triggers
|
|
73
|
-
* a panel (Tabs; a Segmented control has none) — the
|
|
85
|
+
/** The roles each EXCLUSIVE kind plays: its root, the holder of its triggers (null when the root holds them — a
|
|
86
|
+
* Segmented control), its triggers, and — when its items show a panel (Tabs; a Segmented control has none) — the
|
|
87
|
+
* holder of its panels and the panels. */
|
|
74
88
|
export interface ExclusiveKindRoles {
|
|
75
89
|
root: string;
|
|
76
|
-
list: string;
|
|
90
|
+
list: string | null;
|
|
77
91
|
trigger: string;
|
|
78
92
|
panels: string | null;
|
|
79
93
|
panel: string | null;
|
|
@@ -81,6 +95,7 @@ export interface ExclusiveKindRoles {
|
|
|
81
95
|
|
|
82
96
|
export const EXCLUSIVE_KIND_ROLES: Readonly<Record<ExclusiveCompositeKind, ExclusiveKindRoles>> = {
|
|
83
97
|
[CompositeKind.Tabs]: { root: TabsRole.Tabs, list: TabsRole.List, trigger: TabsRole.Trigger, panels: TabsRole.Panels, panel: TabsRole.Panel },
|
|
98
|
+
[CompositeKind.Segmented]: { root: SegmentedRole.Segmented, list: null, trigger: SegmentedRole.Option, panels: null, panel: null },
|
|
84
99
|
};
|
|
85
100
|
|
|
86
101
|
const KINDS = Object.values(CompositeKind);
|
|
@@ -200,6 +215,27 @@ export function isTabsPart(node: RoleLike | null | undefined): boolean {
|
|
|
200
215
|
return compositeKindOfRole(node?.role) === CompositeKind.Tabs;
|
|
201
216
|
}
|
|
202
217
|
|
|
218
|
+
/** True for any part of a Segmented control (its root included). */
|
|
219
|
+
export function isSegmentedPart(node: RoleLike | null | undefined): boolean {
|
|
220
|
+
return compositeKindOfRole(node?.role) === CompositeKind.Segmented;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The exclusive kind a node's role belongs to (`segmented.option` → Segmented), or null. */
|
|
224
|
+
export function exclusiveKindOf(node: RoleLike | null | undefined): ExclusiveCompositeKind | null {
|
|
225
|
+
const kind = compositeKindOfRole(node?.role);
|
|
226
|
+
return isExclusiveKind(kind) ? kind : null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** True when an exclusive root holds its triggers itself (a Segmented control), not in a list part. */
|
|
230
|
+
export function exclusiveRootHoldsTriggers(kind: ExclusiveCompositeKind): boolean {
|
|
231
|
+
return EXCLUSIVE_KIND_ROLES[kind].list === null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** True when an exclusive kind's items show a panel (Tabs), so a trigger and its panel are a pair. */
|
|
235
|
+
export function exclusiveKindHasPanels(kind: ExclusiveCompositeKind | null | undefined): boolean {
|
|
236
|
+
return !!kind && EXCLUSIVE_KIND_ROLES[kind].panel !== null;
|
|
237
|
+
}
|
|
238
|
+
|
|
203
239
|
/** A root of either family — anything that runs a composite runtime. */
|
|
204
240
|
export function isAnyCompositeRoot(node: RoleLike | null | undefined): boolean {
|
|
205
241
|
return isCompositeRoot(node) || isExclusiveRoot(node);
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { roleClass } from '@vectoriox/iox-ui/design-core';
|
|
2
2
|
|
|
3
|
-
import { accordionDomIds, accordionFocusIndex, COMPOSITE_ATTRIBUTE, ITEM_KEY_ATTRIBUTE, ON_ATTRIBUTE, SCOPE_ATTRIBUTE } from './accordion';
|
|
3
|
+
import { accordionDomIds, accordionFocusIndex, COMPOSITE_ATTRIBUTE, DEFAULT_ON_ATTRIBUTE, ITEM_KEY_ATTRIBUTE, ON_ATTRIBUTE, SCOPE_ATTRIBUTE } from './accordion';
|
|
4
4
|
import { ITEM_OFF_EVENT, ITEM_ON_EVENT } from './accordion-runtime';
|
|
5
|
-
import { CompositeKind, EXCLUSIVE_KIND_ROLES, ExclusiveCompositeKind, isExclusiveKind } from './composite-kinds';
|
|
5
|
+
import { CompositeKind, EXCLUSIVE_KIND_ROLES, ExclusiveCompositeKind, exclusiveRootHoldsTriggers, isExclusiveKind } from './composite-kinds';
|
|
6
|
+
import { segmentedKeyAction } from './segmented';
|
|
6
7
|
import {
|
|
7
8
|
ACTIVATE_ON_ATTRIBUTE, ORIENTATION_ATTRIBUTE, TABS_ACTIVATE_ONS, TABS_ORIENTATIONS, TabsActivateOn, TabsBehaviour, tabsKeyAction, TabsOrientation,
|
|
8
9
|
} from './tabs';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* The EXCLUSIVE composites' RUNTIME (CC4a Tabs; the Segmented control
|
|
12
|
-
*
|
|
12
|
+
* The EXCLUSIVE composites' RUNTIME (CC4a Tabs; CC4b the Segmented control) — ONE copy, DOM only, for the builder canvas
|
|
13
|
+
* and the live site (both engine paths render the same markup from `tabs.ts`'s and `segmented.ts`'s attribute planners):
|
|
13
14
|
*
|
|
14
15
|
* [root] data-iox-composite="tabs" data-iox-activate-on data-iox-orientation [data-iox-scope]
|
|
15
16
|
* .iox-role-tabs-list role=tablist [aria-orientation=vertical]
|
|
@@ -25,9 +26,20 @@ import {
|
|
|
25
26
|
* `iox-item-off` on the trigger AND its panel (the `itemOn` / `itemOff` interaction triggers). The item shown is
|
|
26
27
|
* FORCED ?? LIVE: the builder forces one (a selection inside an inactive panel); the live site forces nothing. The
|
|
27
28
|
* server's first state is trusted (no flash).
|
|
29
|
+
*
|
|
30
|
+
* A SEGMENTED control (CC4b) is the same machine with no panels and the APG RADIO GROUP's markup and keys:
|
|
31
|
+
*
|
|
32
|
+
* [root] data-iox-composite="segmented" role=radiogroup aria-label data-iox-default-on [data-iox-scope]
|
|
33
|
+
* .iox-role-segmented-option role=radio aria-checked tabindex 0|-1 data-iox-item-key [data-iox-on]
|
|
34
|
+
*
|
|
35
|
+
* ← → move along the row (mirrored under RTL), ↑ ↓ the DOM order, each move wrapping and turning the option on; with no
|
|
36
|
+
* server state the option on is the root's default (`data-iox-default-on`).
|
|
28
37
|
*/
|
|
29
38
|
|
|
30
39
|
export interface ExclusiveRuntimeOptions {
|
|
40
|
+
/** The kind it runs (else the root's `data-iox-composite`, else a Tabs) — the builder canvas knows it from the node
|
|
41
|
+
* before the attribute is on the element. */
|
|
42
|
+
kind?: ExclusiveCompositeKind;
|
|
31
43
|
/** The scope id the ARIA ids are built from (else `data-iox-scope`, else the root's `iox-node-<id>`). A function is
|
|
32
44
|
* read at every stamp (the builder canvas: a preview row's index is known once it is in the page). */
|
|
33
45
|
rootId?: string | (() => string);
|
|
@@ -41,6 +53,9 @@ export interface ExclusiveRuntimeOptions {
|
|
|
41
53
|
onChange?: (key: string) => void;
|
|
42
54
|
/** Re-stamp when the markup under the root changes (the builder canvas re-renders parts). */
|
|
43
55
|
observe?: boolean;
|
|
56
|
+
/** The key on when there is no server state (the builder canvas: a Segmented control's On by default), else the
|
|
57
|
+
* root's `data-iox-default-on`, else the first item. */
|
|
58
|
+
defaultKey?: () => string | null;
|
|
44
59
|
}
|
|
45
60
|
|
|
46
61
|
const KIND_ROOT = (kind: ExclusiveCompositeKind) => `[${COMPOSITE_ATTRIBUTE}="${kind}"]`;
|
|
@@ -104,14 +119,14 @@ export class ExclusiveRuntime {
|
|
|
104
119
|
readonly kind: ExclusiveCompositeKind;
|
|
105
120
|
|
|
106
121
|
constructor(readonly root: HTMLElement, private readonly options: ExclusiveRuntimeOptions = {}) {
|
|
107
|
-
this.kind = kindOf(root);
|
|
122
|
+
this.kind = options.kind ?? kindOf(root);
|
|
108
123
|
this.behaviourValue = options.behaviour ?? behaviourOf(root);
|
|
109
124
|
root.setAttribute(COMPOSITE_ATTRIBUTE, this.kind);
|
|
110
125
|
EXCLUSIVE_RUNTIMES.set(root, this);
|
|
111
|
-
// The server rendered the first state (every trigger keyed, one on); with no server state the
|
|
126
|
+
// The server rendered the first state (every trigger keyed, one on); with no server state the default is on.
|
|
112
127
|
const triggers = this.triggers();
|
|
113
128
|
const serverOn = !options.behaviour ? triggers.find(t => t.hasAttribute(ON_ATTRIBUTE) && t.hasAttribute(ITEM_KEY_ATTRIBUTE)) : undefined;
|
|
114
|
-
this.live = serverOn ? this.keyOf(serverOn) :
|
|
129
|
+
this.live = serverOn ? this.keyOf(serverOn) : this.defaultKey();
|
|
115
130
|
this.awaitingItems = !triggers.length;
|
|
116
131
|
// Capture: on the builder canvas every part's own listener stops the click (it selects that part), and the tab
|
|
117
132
|
// must still turn on — the canvas is a live runtime.
|
|
@@ -205,6 +220,18 @@ export class ExclusiveRuntime {
|
|
|
205
220
|
return this.triggers().map(t => this.keyOf(t));
|
|
206
221
|
}
|
|
207
222
|
|
|
223
|
+
/** The key on with no server state: the asked default when it names an item, else the first item. */
|
|
224
|
+
private defaultKey(): string | null {
|
|
225
|
+
const keys = this.keys();
|
|
226
|
+
const asked = this.options.defaultKey?.() ?? this.root.getAttribute(DEFAULT_ON_ATTRIBUTE);
|
|
227
|
+
return asked && keys.includes(asked) ? asked : keys[0] ?? null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** True for a Segmented control: the root IS its radio group and holds its options. */
|
|
231
|
+
private get holdsTriggers(): boolean {
|
|
232
|
+
return exclusiveRootHoldsTriggers(this.kind);
|
|
233
|
+
}
|
|
234
|
+
|
|
208
235
|
/** The element(s) that ARE the tablist: the ones a renderer already gave the role (the engine's component-path
|
|
209
236
|
* Repeater puts it on its inner root, which holds the tabs), else the elements carrying the list's role class. */
|
|
210
237
|
private lists(): HTMLElement[] {
|
|
@@ -234,12 +261,13 @@ export class ExclusiveRuntime {
|
|
|
234
261
|
const keys = triggers.map(t => this.keyOf(t));
|
|
235
262
|
if (this.awaitingItems && keys.length) {
|
|
236
263
|
this.awaitingItems = false;
|
|
237
|
-
this.live =
|
|
264
|
+
this.live = this.defaultKey();
|
|
238
265
|
first = true;
|
|
239
266
|
}
|
|
240
|
-
if (this.live === null || !keys.includes(this.live)) this.live =
|
|
267
|
+
if (this.live === null || !keys.includes(this.live)) this.live = this.defaultKey();
|
|
241
268
|
const forced = this.options.forced?.() ?? null;
|
|
242
269
|
const next = forced !== null && keys.includes(forced) ? forced : this.live;
|
|
270
|
+
if (this.holdsTriggers) return this.stampRadioGroup(triggers, next, first);
|
|
243
271
|
const rootId = this.rootId();
|
|
244
272
|
const vertical = this.behaviourValue.orientation === TabsOrientation.Vertical;
|
|
245
273
|
for (const list of this.lists()) {
|
|
@@ -274,6 +302,28 @@ export class ExclusiveRuntime {
|
|
|
274
302
|
setAttr(panel, ON_ATTRIBUTE, on ? '' : null);
|
|
275
303
|
setAttr(panel, 'hidden', on ? null : '');
|
|
276
304
|
}
|
|
305
|
+
this.announce(triggers, next, first, panelOf);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** A Segmented control's markup (CC4b): the root a named radio group, each option a radio, one checked. */
|
|
309
|
+
private stampRadioGroup(options: HTMLElement[], next: string | null, first: boolean): void {
|
|
310
|
+
setAttr(this.root, 'role', 'radiogroup');
|
|
311
|
+
if (this.options.label) setAttr(this.root, 'aria-label', this.options.label() || null);
|
|
312
|
+
for (const option of options) {
|
|
313
|
+
const key = this.keyOf(option);
|
|
314
|
+
const on = key === next;
|
|
315
|
+
setAttr(option, ITEM_KEY_ATTRIBUTE, key);
|
|
316
|
+
setAttr(option, 'type', option.tagName === 'BUTTON' ? 'button' : null);
|
|
317
|
+
setAttr(option, 'role', 'radio');
|
|
318
|
+
setAttr(option, 'aria-checked', on ? 'true' : 'false');
|
|
319
|
+
setAttr(option, 'tabindex', on ? '0' : '-1');
|
|
320
|
+
setAttr(option, ON_ATTRIBUTE, on ? '' : null);
|
|
321
|
+
}
|
|
322
|
+
this.announce(options, next, first);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Move the shown key; dispatch iox-item-off on what was on and iox-item-on on what is on now. */
|
|
326
|
+
private announce(triggers: HTMLElement[], next: string | null, first: boolean, panelOf: (key: string) => HTMLElement | null = () => null): void {
|
|
277
327
|
const was = first ? null : this.shown;
|
|
278
328
|
this.shown = next;
|
|
279
329
|
if (was === next && !first) return;
|
|
@@ -310,7 +360,7 @@ export class ExclusiveRuntime {
|
|
|
310
360
|
const trigger = this.ownTrigger(e.target);
|
|
311
361
|
if (!trigger) return;
|
|
312
362
|
const rtl = isRtl(trigger);
|
|
313
|
-
const action = tabsKeyAction(e.key, this.behaviourValue.orientation, rtl);
|
|
363
|
+
const action = this.holdsTriggers ? segmentedKeyAction(e.key, rtl) : tabsKeyAction(e.key, this.behaviourValue.orientation, rtl);
|
|
314
364
|
if (!action) return;
|
|
315
365
|
const triggers = this.triggers();
|
|
316
366
|
const target = triggers[accordionFocusIndex(action, triggers.indexOf(trigger), triggers.length)];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { DomAttributes } from './accordion';
|
|
2
|
+
import { CompositeKind, exclusiveKindOf } from './composite-kinds';
|
|
3
|
+
import { CompositeNode } from './composite-node';
|
|
4
|
+
import {
|
|
5
|
+
isSegmentedRoot, SEGMENTED_BEHAVIOUR, segmentedDefaultOn, segmentedLabel, segmentedOptionLabel, segmentedPartAttributes, segmentedRootAttributesOf,
|
|
6
|
+
segmentedScopeFor,
|
|
7
|
+
} from './segmented';
|
|
8
|
+
import { tabLabel, TabsBehaviour, tabsBehaviour, tabsLabel, tabsListOf, tabsPartAttributes, tabsRootAttributes, TabsScope, tabsScopeFor } from './tabs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* ONE render decision for every EXCLUSIVE composite — a Tabs (CC4a) or a Segmented control (CC4b) — so both engine paths
|
|
12
|
+
* (the string renderer and the component path) and the composer ask by kind once and never by role literal: the scope
|
|
13
|
+
* a root renders its parts with, the root's own attributes, and each part's.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export type ExclusiveScope = TabsScope;
|
|
17
|
+
|
|
18
|
+
const REPEATER = 'Repeater';
|
|
19
|
+
|
|
20
|
+
/** The scope an exclusive root renders its parts with: a Segmented control's options and default, or a Tabs' keys —
|
|
21
|
+
* From content, the rows its list's Repeater resolved (`rowsOf`). `rowKeys` = the repeated rows around the root. */
|
|
22
|
+
export function exclusiveScopeFor(root: CompositeNode, rootCssId: string, rowsOf: (list: CompositeNode) => ReadonlyArray<unknown> | null,
|
|
23
|
+
rowKeys: ReadonlyArray<string> = []): ExclusiveScope {
|
|
24
|
+
if (isSegmentedRoot(root)) return segmentedScopeFor(root, rootCssId, rowKeys);
|
|
25
|
+
const list = tabsListOf(root);
|
|
26
|
+
return tabsScopeFor(root, rootCssId, list?.type === REPEATER ? rowsOf(list) : null, rowKeys);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The attributes an exclusive ROOT writes on its own element, read off the node (its scope id when it sits in
|
|
30
|
+
* repeated rows). */
|
|
31
|
+
export function exclusiveRootAttributesOf(root: CompositeNode, scopeId?: string): DomAttributes {
|
|
32
|
+
return isSegmentedRoot(root) ? segmentedRootAttributesOf(root, scopeId) : tabsRootAttributes(tabsBehaviour(root), scopeId);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** True when `node` is a part of the kind `scope` renders (a tab inside a Tabs' scope; an option inside a Segmented's). */
|
|
36
|
+
export function isPartOfExclusiveScope(node: { role?: string | null } | null | undefined, scope: ExclusiveScope): boolean {
|
|
37
|
+
const kind = exclusiveKindOf(node);
|
|
38
|
+
return !!kind && kind === (scope.kind ?? CompositeKind.Tabs);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The attributes a part of an exclusive composite writes on its own element (both engine paths, SSR included). */
|
|
42
|
+
export function exclusivePartAttributes(node: { role?: string | null }, scope: ExclusiveScope, key: string | null, rowScoped = false): DomAttributes {
|
|
43
|
+
return scope.kind === CompositeKind.Segmented ? segmentedPartAttributes(node, scope, key, rowScoped) : tabsPartAttributes(node, scope, key, rowScoped);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The behaviour an exclusive root runs with (a Segmented control: a click, a row — it has no Behaviour traits). */
|
|
47
|
+
export function exclusiveBehaviourOf(root: CompositeNode | null | undefined): TabsBehaviour {
|
|
48
|
+
return isSegmentedRoot(root) ? { ...SEGMENTED_BEHAVIOUR } : tabsBehaviour(root);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The accessible name an exclusive root gives its group (a Tabs' list, a Segmented control's radio group). */
|
|
52
|
+
export function exclusiveLabelOf(root: CompositeNode | null | undefined): string {
|
|
53
|
+
return isSegmentedRoot(root) ? segmentedLabel(root) : tabsLabel(root);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The item an exclusive root shows with no other say (a Segmented control's On by default), or null (a Tabs: its first). */
|
|
57
|
+
export function exclusiveDefaultOf(root: CompositeNode | null | undefined): string | null {
|
|
58
|
+
return isSegmentedRoot(root) ? segmentedDefaultOn(root) : null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** An exclusive item's words — a tab's, an option's (never its badge's) — for the pickers, the tree and the switchers. */
|
|
62
|
+
export function exclusiveItemLabel(part: CompositeNode): string {
|
|
63
|
+
return exclusiveKindOf(part) === CompositeKind.Segmented ? segmentedOptionLabel(part) : tabLabel(part);
|
|
64
|
+
}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* plan §3a). FRAMEWORK-FREE: the builder, the SSR engine and iox-cms (generation-core's composer, the site
|
|
4
4
|
* build) read the same recipes, roles and structure rules. Card v2 + Badge / Chip (T23 / T25) are the
|
|
5
5
|
* first; the Accordion (CC2) adds the first composite RUNTIME (accordion-runtime.ts — DOM only, no
|
|
6
|
-
* framework), which the Disclosure (CC2.1) runs too — a one-item accordion whose root is its item; Tabs (CC4a)
|
|
7
|
-
* EXCLUSIVE runtime (exclusive-runtime.ts — one item always on
|
|
6
|
+
* framework), which the Disclosure (CC2.1) runs too — a one-item accordion whose root is its item; Tabs (CC4a) and the
|
|
7
|
+
* Segmented control (CC4b) run the EXCLUSIVE runtime (exclusive-runtime.ts — one item always on; exclusive.ts the one
|
|
8
|
+
* render decision by kind); composite-runtime.ts is the one door to both families.
|
|
8
9
|
* ⚠️ Consumers wire the usual trio — ng-package raw-ts assets, jest moduleNameMapper, tsconfig paths.
|
|
9
10
|
*/
|
|
10
11
|
export * from './composite-node';
|
|
@@ -19,5 +20,7 @@ export * from './slider';
|
|
|
19
20
|
export * from './slider-runtime';
|
|
20
21
|
export * from './lightbox';
|
|
21
22
|
export * from './tabs';
|
|
23
|
+
export * from './segmented';
|
|
24
|
+
export * from './exclusive';
|
|
22
25
|
export * from './exclusive-runtime';
|
|
23
26
|
export * from './composite-runtime';
|