@vectoriox/iox-ui 4.14.0 → 4.15.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.
|
@@ -2434,21 +2434,27 @@ function referencedDataSources(nodes, all) {
|
|
|
2434
2434
|
const aliases = collectReferencedAliases(nodes);
|
|
2435
2435
|
return (all ?? []).filter(ds => aliases.has(ds?.alias));
|
|
2436
2436
|
}
|
|
2437
|
-
/** Like `referencedDataSources`, but also pulls in
|
|
2438
|
-
*
|
|
2439
|
-
*
|
|
2440
|
-
*
|
|
2437
|
+
/** Like `referencedDataSources`, but also pulls in a referenced source's DEPENDENCIES (transitively),
|
|
2438
|
+
* none of which the layout names directly:
|
|
2439
|
+
* - a `derived` alias needs its `request.derived.from` parent;
|
|
2440
|
+
* - a `relative` (route-context) alias needs its `request.relative.subjectFrom` (the current item)
|
|
2441
|
+
* and `request.relative.from` (the collection it navigates).
|
|
2442
|
+
* Use this when RESOLVING (the engine) so derived views and siblings/related don't resolve to nothing. */
|
|
2441
2443
|
function referencedDataSourcesDeep(nodes, all) {
|
|
2442
2444
|
const byAlias = new Map((all ?? []).map(d => [d?.alias, d]));
|
|
2443
2445
|
const wanted = collectReferencedAliases(nodes);
|
|
2444
2446
|
const queue = [...wanted];
|
|
2447
|
+
const enqueue = (alias) => {
|
|
2448
|
+
if (alias && !wanted.has(alias)) {
|
|
2449
|
+
wanted.add(alias);
|
|
2450
|
+
queue.push(alias);
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2445
2453
|
while (queue.length) {
|
|
2446
2454
|
const ds = byAlias.get(queue.pop());
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
queue.push(from);
|
|
2451
|
-
}
|
|
2455
|
+
enqueue(ds?.request?.derived?.from);
|
|
2456
|
+
enqueue(ds?.request?.relative?.subjectFrom);
|
|
2457
|
+
enqueue(ds?.request?.relative?.from);
|
|
2452
2458
|
}
|
|
2453
2459
|
return (all ?? []).filter(d => wanted.has(d?.alias));
|
|
2454
2460
|
}
|
|
@@ -2647,6 +2653,106 @@ function resolveRelativeInto(dataSources, resolved, routeParams = {}) {
|
|
|
2647
2653
|
return resolved;
|
|
2648
2654
|
}
|
|
2649
2655
|
|
|
2656
|
+
/**
|
|
2657
|
+
* Binding pipes — render-time value transforms (UI label: "Filters").
|
|
2658
|
+
*
|
|
2659
|
+
* A binding resolves a raw value (`resolvePath(sourceData, path)`); a pipe chain then reshapes it for
|
|
2660
|
+
* display (format a timestamp, upper-case, truncate, …). This is the SINGLE shared implementation used
|
|
2661
|
+
* by BOTH the builder canvas and the SSR engine — the engine renders layout JSON to a STRING and can't
|
|
2662
|
+
* use Angular pipes, and `resolvePath` is already duplicated across the apply points, so the transform
|
|
2663
|
+
* MUST be one pure, transport-agnostic function applied identically everywhere. Never fork it.
|
|
2664
|
+
*
|
|
2665
|
+
* See iox-ai-guidance/architecture/builder/binding-filters-plan.md.
|
|
2666
|
+
*/
|
|
2667
|
+
// ── Date / time (Intl locale presets — locale-aware, zero-dep, browser + Node identical) ──────────
|
|
2668
|
+
const DATE_PRESETS = {
|
|
2669
|
+
short: { dateStyle: 'short' },
|
|
2670
|
+
medium: { dateStyle: 'medium' },
|
|
2671
|
+
long: { dateStyle: 'long' },
|
|
2672
|
+
full: { dateStyle: 'full' },
|
|
2673
|
+
};
|
|
2674
|
+
const DATETIME_PRESETS = {
|
|
2675
|
+
short: { dateStyle: 'short', timeStyle: 'short' },
|
|
2676
|
+
medium: { dateStyle: 'medium', timeStyle: 'short' },
|
|
2677
|
+
long: { dateStyle: 'long', timeStyle: 'medium' },
|
|
2678
|
+
full: { dateStyle: 'full', timeStyle: 'long' },
|
|
2679
|
+
};
|
|
2680
|
+
/** Coerce an ISO string / epoch number / Date to a valid Date, or null (→ pipes pass the value through). */
|
|
2681
|
+
function toDate(value) {
|
|
2682
|
+
if (value instanceof Date)
|
|
2683
|
+
return isNaN(value.getTime()) ? null : value;
|
|
2684
|
+
if (typeof value === 'number') {
|
|
2685
|
+
const d = new Date(value);
|
|
2686
|
+
return isNaN(d.getTime()) ? null : d;
|
|
2687
|
+
}
|
|
2688
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
2689
|
+
const d = new Date(value);
|
|
2690
|
+
return isNaN(d.getTime()) ? null : d;
|
|
2691
|
+
}
|
|
2692
|
+
return null;
|
|
2693
|
+
}
|
|
2694
|
+
function formatDate(value, args, ctx, presets) {
|
|
2695
|
+
const d = toDate(value);
|
|
2696
|
+
if (!d)
|
|
2697
|
+
return value; // never throw — unparseable input passes through unchanged
|
|
2698
|
+
const preset = args[0] || 'medium';
|
|
2699
|
+
return new Intl.DateTimeFormat(ctx.locale, presets[preset] ?? presets['medium']).format(d);
|
|
2700
|
+
}
|
|
2701
|
+
/** The registry — adding a pipe here (+ a descriptor below) makes it work on both sides and appear in
|
|
2702
|
+
* the authoring UI. Keyed by name; unknown names are passed through by `applyBindingPipes`. */
|
|
2703
|
+
const PIPE_REGISTRY = {
|
|
2704
|
+
date: (v, args, ctx) => formatDate(v, args, ctx, DATE_PRESETS),
|
|
2705
|
+
datetime: (v, args, ctx) => formatDate(v, args, ctx, DATETIME_PRESETS),
|
|
2706
|
+
uppercase: (v) => (v == null ? v : String(v).toUpperCase()),
|
|
2707
|
+
lowercase: (v) => (v == null ? v : String(v).toLowerCase()),
|
|
2708
|
+
truncate: (v, args) => {
|
|
2709
|
+
if (v == null)
|
|
2710
|
+
return v;
|
|
2711
|
+
const s = String(v);
|
|
2712
|
+
const len = Number(args[0]) || 100;
|
|
2713
|
+
const suffix = args[1] != null ? String(args[1]) : '…';
|
|
2714
|
+
return s.length > len ? s.slice(0, len) + suffix : s;
|
|
2715
|
+
},
|
|
2716
|
+
number: (v, args, ctx) => {
|
|
2717
|
+
const n = typeof v === 'number' ? v : parseFloat(v);
|
|
2718
|
+
if (!Number.isFinite(n))
|
|
2719
|
+
return v;
|
|
2720
|
+
const opts = {};
|
|
2721
|
+
if (args[0] != null && args[0] !== '') {
|
|
2722
|
+
opts.minimumFractionDigits = Number(args[0]);
|
|
2723
|
+
opts.maximumFractionDigits = Number(args[0]);
|
|
2724
|
+
}
|
|
2725
|
+
return new Intl.NumberFormat(ctx.locale, opts).format(n);
|
|
2726
|
+
},
|
|
2727
|
+
};
|
|
2728
|
+
/**
|
|
2729
|
+
* Apply a binding's pipe chain to a resolved value, LEFT→RIGHT. Pure. An empty/undefined chain returns
|
|
2730
|
+
* the value untouched; an unknown pipe name is skipped (forward-compatible with newer authored pipes).
|
|
2731
|
+
* Call this at every binding-resolution point (builder canvas + engine SSR + engine hydration).
|
|
2732
|
+
*/
|
|
2733
|
+
function applyBindingPipes(value, pipes, ctx = {}) {
|
|
2734
|
+
if (!pipes?.length)
|
|
2735
|
+
return value;
|
|
2736
|
+
return pipes.reduce((v, p) => {
|
|
2737
|
+
const fn = p && PIPE_REGISTRY[p.name];
|
|
2738
|
+
return fn ? fn(v, p.args ?? [], ctx) : v;
|
|
2739
|
+
}, value);
|
|
2740
|
+
}
|
|
2741
|
+
const PRESET_OPTIONS = [
|
|
2742
|
+
{ label: 'Short', value: 'short' },
|
|
2743
|
+
{ label: 'Medium', value: 'medium' },
|
|
2744
|
+
{ label: 'Long', value: 'long' },
|
|
2745
|
+
{ label: 'Full', value: 'full' },
|
|
2746
|
+
];
|
|
2747
|
+
const PIPE_DESCRIPTORS = [
|
|
2748
|
+
{ name: 'date', label: 'Date', args: [{ key: 'preset', label: 'Format', control: 'select', options: PRESET_OPTIONS, default: 'medium' }] },
|
|
2749
|
+
{ name: 'datetime', label: 'Date & time', args: [{ key: 'preset', label: 'Format', control: 'select', options: PRESET_OPTIONS, default: 'medium' }] },
|
|
2750
|
+
{ name: 'uppercase', label: 'UPPERCASE', args: [] },
|
|
2751
|
+
{ name: 'lowercase', label: 'lowercase', args: [] },
|
|
2752
|
+
{ name: 'truncate', label: 'Truncate', args: [{ key: 'length', label: 'Max length', control: 'number', default: 100 }] },
|
|
2753
|
+
{ name: 'number', label: 'Number', args: [{ key: 'decimals', label: 'Decimals', control: 'number', default: null }] },
|
|
2754
|
+
];
|
|
2755
|
+
|
|
2650
2756
|
/**
|
|
2651
2757
|
* Cinematic page-transition presets — the SINGLE SOURCE OF TRUTH shared by the page builder
|
|
2652
2758
|
* (preview) and the SSR client engine (production). Pure, transport-agnostic: this module only
|
|
@@ -3081,5 +3187,5 @@ function effectiveTransitionId(anim) {
|
|
|
3081
3187
|
* Generated bundle index. Do not edit.
|
|
3082
3188
|
*/
|
|
3083
3189
|
|
|
3084
|
-
export { AOSService, AnalyticsService, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CMSClientInfraModule, CardComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ConsentService, ContainerComponent, ContentService, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_WIDTH_BY_TYPE, ENVIRONMENT, IOX_BUILDER_EVENTS, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxPageComponent, IoxPageModule, IoxUiModule, LinkedContainerComponent, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PageScrollProvider, PrivacyModalComponent, PrivacyModalService, PrivacyModelEvent, RESERVED_ALIAS_PREFIX, SUPPRESSED_STYLE_PROPS_BY_TYPE, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, WebSettingsService, applyFeel, buildDataSourceFilter, buildRelatedFilter, buildTransitionTimeline, collectReferencedAliases, compileDeclarations, composeVirtualTraits, computeRelative, dataSourcePlanToRequest, effectiveTransitionId, excludeSelf, feelFor, getByPath, isReservedAlias, legacyEnterToTransition, matchRouteParams, normalizeCollectionResult, planDataSource, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resolveDerivedInto, resolvePageTransition, resolveRelativeInto, resolveRepeaterItems, resolveSiblings, resolveSingleItemId, rewriteViewportUnits, stripSuppressedProps, styleKeyToKebab };
|
|
3190
|
+
export { AOSService, AnalyticsService, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CMSClientInfraModule, CardComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ConsentService, ContainerComponent, ContentService, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_WIDTH_BY_TYPE, ENVIRONMENT, IOX_BUILDER_EVENTS, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxPageComponent, IoxPageModule, IoxUiModule, LinkedContainerComponent, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, PrivacyModalComponent, PrivacyModalService, PrivacyModelEvent, RESERVED_ALIAS_PREFIX, SUPPRESSED_STYLE_PROPS_BY_TYPE, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, WebSettingsService, applyBindingPipes, applyFeel, buildDataSourceFilter, buildRelatedFilter, buildTransitionTimeline, collectReferencedAliases, compileDeclarations, composeVirtualTraits, computeRelative, dataSourcePlanToRequest, effectiveTransitionId, excludeSelf, feelFor, getByPath, isReservedAlias, legacyEnterToTransition, matchRouteParams, normalizeCollectionResult, planDataSource, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resolveDerivedInto, resolvePageTransition, resolveRelativeInto, resolveRepeaterItems, resolveSiblings, resolveSingleItemId, rewriteViewportUnits, stripSuppressedProps, styleKeyToKebab };
|
|
3085
3191
|
//# sourceMappingURL=vectoriox-iox-ui.mjs.map
|