@vectoriox/iox-ui 5.1.0 → 5.3.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.
@@ -1,3 +1,5 @@
1
+ export { FORM_SUBMIT_ACTION_DESCRIPTORS as ACTION_DESCRIPTORS, ActionDescriptor, addableActions } from '@vectoriox/iox-ui/actions-core';
2
+
1
3
  /** What the visitor actually types into. Chosen by a trait; it also implies a validation rule. */
2
4
  declare enum ControlType {
3
5
  Text = "text",
@@ -291,21 +293,6 @@ declare const PATTERN_PRESET_OPTIONS: readonly {
291
293
  value: PatternPreset;
292
294
  labelKey: string;
293
295
  }[];
294
- /** Destinations an author can add to a form, for the After-submit list. */
295
- interface ActionDescriptor {
296
- type: string;
297
- labelKey: string;
298
- /** Always present and not removable. */
299
- locked?: boolean;
300
- /** Not offered yet — shown greyed with a "coming soon" note rather than hidden, so the roadmap
301
- * is visible rather than the feature looking absent. */
302
- planned?: boolean;
303
- }
304
- declare const ACTION_DESCRIPTORS: readonly ActionDescriptor[];
305
- /** Destinations that can still be added — each at most once, and never a planned one. */
306
- declare function addableActions(existing?: readonly {
307
- type: string;
308
- }[]): ActionDescriptor[];
309
296
 
310
297
  /**
311
298
  * The submit transport CONTRACT — what a host must provide to make a form actually send.
@@ -372,5 +359,5 @@ declare function withAntiSpamFields(values: Record<string, any>, renderedAt: num
372
359
  */
373
360
  declare function interpretSubmitResponse(body: any): SubmitResponse;
374
361
 
375
- export { ACTION_DESCRIPTORS, ControlType, DEFAULT_EN_MESSAGES, FIELD_NODE_TYPE, FORM_ERROR_KEYS, FORM_NODE_TYPE, FeedbackTiming, HONEYPOT_FIELD, IMPLIED_PATTERN, INITIAL_FORM_STATE, MESSAGE_NAMESPACE, MULTI_VALUE_CONTROLS, PATTERN_MESSAGE_KEYS, PATTERN_PRESETS, PATTERN_PRESET_OPTIONS, PatternPreset, RENDERED_AT_FIELD, RULE_DESCRIPTORS, RULE_MESSAGE_KEYS, RuleName, RuleParamKind, STORE_ACTION, addableActions, addableRules, applyServerErrors, collectFieldNodes, collectFormSpec, deriveFieldName, firstInvalidField, interpretSubmitResponse, onFieldBlur, onFieldChange, onSubmitAttempt, resetFormState, rulesFor, shouldShowError, submitEndpointPath, uniqueFieldName, validateField, validateForm, withAntiSpamFields };
376
- export type { ActionDescriptor, FieldError, FieldOption, FieldOptionSource, FieldResult, FieldSpec, FormNodeLike, FormResult, FormRuntimeState, FormSpec, FormTransport, RuleDescriptor, SubmitAction, SubmitRequest, SubmitResponse, ValidationRule };
362
+ export { ControlType, DEFAULT_EN_MESSAGES, FIELD_NODE_TYPE, FORM_ERROR_KEYS, FORM_NODE_TYPE, FeedbackTiming, HONEYPOT_FIELD, IMPLIED_PATTERN, INITIAL_FORM_STATE, MESSAGE_NAMESPACE, MULTI_VALUE_CONTROLS, PATTERN_MESSAGE_KEYS, PATTERN_PRESETS, PATTERN_PRESET_OPTIONS, PatternPreset, RENDERED_AT_FIELD, RULE_DESCRIPTORS, RULE_MESSAGE_KEYS, RuleName, RuleParamKind, STORE_ACTION, addableRules, applyServerErrors, collectFieldNodes, collectFormSpec, deriveFieldName, firstInvalidField, interpretSubmitResponse, onFieldBlur, onFieldChange, onSubmitAttempt, resetFormState, rulesFor, shouldShowError, submitEndpointPath, uniqueFieldName, validateField, validateForm, withAntiSpamFields };
363
+ export type { FieldError, FieldOption, FieldOptionSource, FieldResult, FieldSpec, FormNodeLike, FormResult, FormRuntimeState, FormSpec, FormTransport, RuleDescriptor, SubmitAction, SubmitRequest, SubmitResponse, ValidationRule };
package/index.d.ts CHANGED
@@ -1549,6 +1549,66 @@ declare function compileTokenCss(tokens: ReadonlyArray<DesignTokenLike> | null |
1549
1549
  dark: string;
1550
1550
  };
1551
1551
 
1552
+ /**
1553
+ * Flavors (flavors-and-theming-plan.md, F1): the design language a studio launches with,
1554
+ * expressed as data. THE invariant — a flavor never writes a literal into a node; it writes
1555
+ * tokens, and element defaults that REFERENCE tokens. To that end a pack's `defaults` map
1556
+ * holds TOKEN NAMES, not CSS values: the resolver builds `var(--iox-<name>, <packValue>)`,
1557
+ * so smuggling a literal in is impossible by construction, and the validator only has to
1558
+ * check that every referenced token exists.
1559
+ *
1560
+ * The fallback is the bootstrap: until F2 seeds the org's `designtokens` rows, no `--iox-*`
1561
+ * var is defined anywhere, and `var(--iox-radius-control, 4px)` must still paint identically
1562
+ * in the builder canvas and the SSR page. Once tokens ARE seeded (or re-themed), the var wins
1563
+ * over the fallback everywhere — which is exactly the §3 propagation story.
1564
+ */
1565
+ interface FlavorTokenDef {
1566
+ name: string;
1567
+ value: string;
1568
+ /** Dark-scheme override, seeded into DesignToken.values.dark at F2. */
1569
+ values?: {
1570
+ dark?: string;
1571
+ };
1572
+ type?: 'color' | 'spacing' | 'size' | 'font' | 'other';
1573
+ /** Tokens-panel grouping (flavors plan §10 C5). */
1574
+ group?: 'colour' | 'type' | 'space' | 'radius' | 'shadow' | 'motion';
1575
+ }
1576
+ interface FlavorPack {
1577
+ id: string;
1578
+ /** Bumped when the pack's values change; seeding stamps `flavor:<id>@<version>` as DesignToken.source. */
1579
+ version: number;
1580
+ label: string;
1581
+ blurb: string;
1582
+ tokens: FlavorTokenDef[];
1583
+ /** type → styleTrait → TOKEN NAME (never a CSS value — see the module header). */
1584
+ defaults: Record<string, Record<string, string>>;
1585
+ }
1586
+ /** trait → `var(--iox-<token>, <packValue>)` for one node type. Unknown type → {}. */
1587
+ declare function resolveFlavorDefaults(type: string, pack: FlavorPack | null | undefined): Record<string, string>;
1588
+ /**
1589
+ * The ENGINE's half of the cascade: kebab `prop: var(…)` declarations for every pack default
1590
+ * the node's persisted styleProps does NOT set. Appended beside renderDefaultDeclarations —
1591
+ * same guard-on-undefined discipline, so a node saved post-F1 (var already serialised via the
1592
+ * builder's trait defaults) is untouched, and a legacy node picks the pack default up at
1593
+ * render time. Node styleProps always wins.
1594
+ */
1595
+ declare function flavorDefaultDeclarations(type: string, styleProps: Record<string, any> | null | undefined, pack: FlavorPack | null | undefined): string[];
1596
+ /**
1597
+ * The CI gate (flavors plan §10 C4): a pack may only name types and traits that exist in the
1598
+ * live component registry, and tokens it defines itself. Returns human-readable errors; a
1599
+ * consumer spec feeds it the REAL registry and asserts [].
1600
+ */
1601
+ declare function validateFlavorPack(pack: FlavorPack, knownTraitsByType: Record<string, ReadonlySet<string> | string[]>): string[];
1602
+ /**
1603
+ * Swiss — the default pack (flavors plan §8: "the flavor that can never embarrass anyone").
1604
+ * Deliberately SMALL at F1: radius + control padding on the clickables, surface radius on Card.
1605
+ * Colour, type and motion arrive with the brand step (F2) — a colour default here would repaint
1606
+ * legacy pages before anyone chose anything.
1607
+ */
1608
+ declare const SWISS_FLAVOR: FlavorPack;
1609
+ /** What both renderers use until F2 lets an org choose. */
1610
+ declare const DEFAULT_FLAVOR: FlavorPack;
1611
+
1552
1612
  /**
1553
1613
  * page-style — the ONE compiler that turns a page's style settings into CSS.
1554
1614
  *
@@ -2718,5 +2778,5 @@ declare class GalleryLoop {
2718
2778
  private emit;
2719
2779
  }
2720
2780
 
2721
- export { AOSService, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, 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, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, 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, 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, compileTokenCss, composeVirtualTraits, computeRelative, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, defaultMessageResolver, deriveSeoFromContent, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, getByPath, getSeoValue, 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, stripSuppressedProps, styleKeyToKebab, tokensToDarkVarMap, tokensToVarMap, variableAliases, variableItemsFrom, withContextSlots, wrapInBreakpointQuery, wrapInMediaQuery };
2722
- export type { BoundValueSpec, BreakpointDef, BuildRelatedFilterOptions, ContextActionEffect, ContextActionLike, ContextItemRef, ContextSlotDefault, ContextValueSpec, ContextWriteScope, DataSourceDomain, DataSourceEndpoints, DataSourceMode, DataSourcePlan, DataSourceQueryFilter, DataSourceRequest, DataSourceRequestSpec, DataSourceRouteFilter, DataSourceSpec, DesignTokenLike, 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 };
2781
+ export { AOSService, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CONTEXT_ACTION_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ContainerComponent, ContextStore, DEFAULT_FLAVOR, 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, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, 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, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_RESPONSIVE_TRAITS, SWISS_FLAVOR, 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, compileTokenCss, composeVirtualTraits, computeRelative, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, defaultMessageResolver, deriveSeoFromContent, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, flavorDefaultDeclarations, getByPath, getSeoValue, 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, resolveFlavorDefaults, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveValueChain, rewriteViewportUnits, safeSetInput, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, stripSuppressedProps, styleKeyToKebab, tokensToDarkVarMap, tokensToVarMap, validateFlavorPack, variableAliases, variableItemsFrom, withContextSlots, wrapInBreakpointQuery, wrapInMediaQuery };
2782
+ export type { BoundValueSpec, BreakpointDef, BuildRelatedFilterOptions, ContextActionEffect, ContextActionLike, ContextItemRef, ContextSlotDefault, ContextValueSpec, ContextWriteScope, DataSourceDomain, DataSourceEndpoints, DataSourceMode, DataSourcePlan, DataSourceQueryFilter, DataSourceRequest, DataSourceRequestSpec, DataSourceRouteFilter, DataSourceSpec, DesignTokenLike, FlavorPack, FlavorTokenDef, 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectoriox/iox-ui",
3
- "version": "5.1.0",
3
+ "version": "5.3.0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=20.0.0",
6
6
  "@angular/core": ">=20.0.0",
@@ -19,6 +19,10 @@
19
19
  "types": "./index.d.ts",
20
20
  "default": "./fesm2022/vectoriox-iox-ui.mjs"
21
21
  },
22
+ "./actions-core": {
23
+ "types": "./actions-core/index.d.ts",
24
+ "default": "./fesm2022/vectoriox-iox-ui-actions-core.mjs"
25
+ },
22
26
  "./forms-core": {
23
27
  "types": "./forms-core/index.d.ts",
24
28
  "default": "./fesm2022/vectoriox-iox-ui-forms-core.mjs"
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The ONE descriptor shape for everything an author can put in an ordered action list —
3
+ * a form's after-submit steps today, element behaviour actions (A1) next. Promoted out of
4
+ * `forms-core` because a button action importing from the forms module would be a lie; the
5
+ * forms catalog lives here now and `forms-core` re-exports it unchanged.
6
+ * See iox-ai-guidance `architecture/builder/actions-framework-plan.md` §4 (A0).
7
+ */
8
+
9
+ /** How a step executes — decides which editor fields appear (timing only for `animated`). */
10
+ export type ActionKind = 'animated' | 'instant' | 'server';
11
+
12
+ /** Picker grouping. Flat lists die at ~10 entries; the group is data, never a second list. */
13
+ export type ActionGroup =
14
+ | 'motion' | 'visibility' | 'navigate' | 'dialog' | 'form' | 'data' | 'service';
15
+
16
+ /**
17
+ * What a step does inside the live builder canvas (the canvas RUNS interactions):
18
+ * `run` for real (open the dialog), `simulate` announce-only (navigate), `inert` with a
19
+ * "runs on the live site" note (anything server-side or costing money).
20
+ */
21
+ export type BuilderBehaviour = 'run' | 'simulate' | 'inert';
22
+
23
+ /** A configurable parameter, same shape ComponentMethodDef.params already uses. */
24
+ export interface ActionParamSpec {
25
+ name: string;
26
+ type: 'number' | 'string' | 'boolean' | 'page' | 'node' | 'form';
27
+ label: string;
28
+ }
29
+
30
+ /** Does this action point at another node — and may it be any node or only certain types? */
31
+ export interface ActionTargetSpec {
32
+ required: boolean;
33
+ types?: string[];
34
+ }
35
+
36
+ /**
37
+ * One row of an action catalog. Every field beyond `type`/`labelKey` is optional so the
38
+ * pre-A0 forms descriptors remain valid verbatim.
39
+ */
40
+ export interface ActionDescriptor {
41
+ type: string;
42
+ labelKey: string;
43
+ kind?: ActionKind;
44
+ group?: ActionGroup;
45
+ builderBehaviour?: BuilderBehaviour;
46
+ target?: ActionTargetSpec;
47
+ params?: ActionParamSpec[];
48
+ /** The connector that must be configured & healthy before this action is offerable. */
49
+ connector?: string;
50
+ /** Plan-entitlement key (AI plan D5). Absent = never gated by plan. */
51
+ entitlement?: string;
52
+ /** Always present in the list and not removable (forms: `store`). */
53
+ locked?: boolean;
54
+ /** Not offered yet — shown greyed with a "coming soon" note, so the roadmap is visible. */
55
+ planned?: boolean;
56
+ }
57
+
58
+ /**
59
+ * The FORM after-submit catalog (moved verbatim from forms-core; `forms-core` re-exports it
60
+ * under its old name `ACTION_DESCRIPTORS`). A1's element catalog is a SEPARATE constant —
61
+ * the two lists share this shape, never one bucket.
62
+ */
63
+ export const FORM_SUBMIT_ACTION_DESCRIPTORS: readonly ActionDescriptor[] = Object.freeze([
64
+ { type: 'store', labelKey: 'forms.actions.store', locked: true, kind: 'server', group: 'data', builderBehaviour: 'inert' },
65
+ { type: 'email', labelKey: 'forms.actions.email', kind: 'server', group: 'service', builderBehaviour: 'inert', connector: 'mailer' },
66
+ { type: 'redirect', labelKey: 'forms.actions.redirect', kind: 'instant', group: 'navigate', builderBehaviour: 'simulate' },
67
+ { type: 'createItem', labelKey: 'forms.actions.createItem', planned: true, kind: 'server', group: 'data', builderBehaviour: 'inert' },
68
+ { type: 'webhook', labelKey: 'forms.actions.webhook', planned: true, kind: 'server', group: 'service', builderBehaviour: 'inert' },
69
+ { type: 'autoReply', labelKey: 'forms.actions.autoReply', planned: true, kind: 'server', group: 'service', builderBehaviour: 'inert', connector: 'mailer' },
70
+ ]);
71
+
72
+ /** Steps that can still be added to a list — each at most once, and never a planned one. */
73
+ export function addableActions(
74
+ existing: readonly { type: string }[] = [],
75
+ catalog: readonly ActionDescriptor[] = FORM_SUBMIT_ACTION_DESCRIPTORS,
76
+ ): ActionDescriptor[] {
77
+ const used = new Set(existing.map(action => action.type));
78
+ return catalog.filter(action => !action.locked && !action.planned && !used.has(action.type));
79
+ }
@@ -0,0 +1,46 @@
1
+ import { ActionDescriptor } from './action.model';
2
+
3
+ /**
4
+ * K4 of the actions plan: four different reasons a catalog row is unavailable, four different
5
+ * sentences — *coming soon* · *always on* · *connect X first* · *upgrade*. One resolver feeds
6
+ * the picker AND the AI composer's validation, so they can never disagree.
7
+ */
8
+ export type ActionAvailabilityState =
9
+ | 'available'
10
+ | 'planned' // not built yet — greyed, "coming soon"
11
+ | 'locked' // always present, not addable/removable
12
+ | 'connector-missing' // the named connector is not configured/healthy
13
+ | 'entitlement-missing'; // the plan does not include it
14
+
15
+ export interface ActionAvailability {
16
+ state: ActionAvailabilityState;
17
+ /** Set when state is connector-missing / entitlement-missing — what to name in the message. */
18
+ connector?: string;
19
+ entitlement?: string;
20
+ }
21
+
22
+ export interface ActionAvailabilityContext {
23
+ /** Connector health by name. An absent map, or an absent key, means "not known" → allowed. */
24
+ connectors?: Partial<Record<string, boolean>>;
25
+ /**
26
+ * Plan entitlements by key. `Plan.entitlements` does not exist yet anywhere (the known gap),
27
+ * so an ABSENT map means "no gating" and every entitlement passes — the hook is live the day
28
+ * the control plane starts sending them.
29
+ */
30
+ entitlements?: Partial<Record<string, boolean>>;
31
+ }
32
+
33
+ export function resolveActionAvailability(
34
+ descriptor: ActionDescriptor,
35
+ ctx: ActionAvailabilityContext = {},
36
+ ): ActionAvailability {
37
+ if (descriptor.planned) return { state: 'planned' };
38
+ if (descriptor.locked) return { state: 'locked' };
39
+ if (descriptor.connector && ctx.connectors && ctx.connectors[descriptor.connector] === false) {
40
+ return { state: 'connector-missing', connector: descriptor.connector };
41
+ }
42
+ if (descriptor.entitlement && ctx.entitlements && ctx.entitlements[descriptor.entitlement] === false) {
43
+ return { state: 'entitlement-missing', entitlement: descriptor.entitlement };
44
+ }
45
+ return { state: 'available' };
46
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @vectoriox/iox-ui/actions-core — the shared, FRAMEWORK-FREE action vocabulary.
3
+ *
4
+ * One `ActionDescriptor` shape for every ordered action list in the product: the forms
5
+ * after-submit steps (whose catalog moved here; `forms-core` re-exports it unchanged) and
6
+ * the element behaviour actions of A1. Framework-free for the same reason as `forms-core`
7
+ * and `seo-core`: `iox-cms` consumes it under plain Node.
8
+ * ⚠️ Consumers wire the usual trio — ng-package raw-ts assets, jest moduleNameMapper, and
9
+ * tsconfig paths — or `nest start` dies with ERR_REQUIRE_ESM while jest and build pass.
10
+ */
11
+ export * from './action.model';
12
+ export * from './availability';
@@ -108,28 +108,9 @@ export const PATTERN_PRESET_OPTIONS: readonly { value: PatternPreset; labelKey:
108
108
  { value: PatternPreset.Slug, labelKey: 'forms.rules.preset.slug' },
109
109
  ]);
110
110
 
111
- /** Destinations an author can add to a form, for the After-submit list. */
112
- export interface ActionDescriptor {
113
- type: string;
114
- labelKey: string;
115
- /** Always present and not removable. */
116
- locked?: boolean;
117
- /** Not offered yet — shown greyed with a "coming soon" note rather than hidden, so the roadmap
118
- * is visible rather than the feature looking absent. */
119
- planned?: boolean;
120
- }
121
-
122
- export const ACTION_DESCRIPTORS: readonly ActionDescriptor[] = Object.freeze([
123
- { type: 'store', labelKey: 'forms.actions.store', locked: true },
124
- { type: 'email', labelKey: 'forms.actions.email' },
125
- { type: 'redirect', labelKey: 'forms.actions.redirect' },
126
- { type: 'createItem', labelKey: 'forms.actions.createItem', planned: true },
127
- { type: 'webhook', labelKey: 'forms.actions.webhook', planned: true },
128
- { type: 'autoReply', labelKey: 'forms.actions.autoReply', planned: true },
129
- ]);
130
-
131
- /** Destinations that can still be added — each at most once, and never a planned one. */
132
- export function addableActions(existing: readonly { type: string }[] = []): ActionDescriptor[] {
133
- const used = new Set(existing.map(action => action.type));
134
- return ACTION_DESCRIPTORS.filter(action => !action.locked && !action.planned && !used.has(action.type));
135
- }
111
+ // ── MOVED to @vectoriox/iox-ui/actions-core (A0) ─────────────────────────────
112
+ // The descriptor shape and the after-submit catalog are the ONE action vocabulary the whole
113
+ // product shares; element actions (A1) consume the same shape. Re-exported here under the
114
+ // original names so no forms consumer changes a line.
115
+ export type { ActionDescriptor } from '@vectoriox/iox-ui/actions-core';
116
+ export { FORM_SUBMIT_ACTION_DESCRIPTORS as ACTION_DESCRIPTORS, addableActions } from '@vectoriox/iox-ui/actions-core';