@vectoriox/iox-ui 4.14.1 → 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.
@@ -2653,6 +2653,106 @@ function resolveRelativeInto(dataSources, resolved, routeParams = {}) {
2653
2653
  return resolved;
2654
2654
  }
2655
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
+
2656
2756
  /**
2657
2757
  * Cinematic page-transition presets — the SINGLE SOURCE OF TRUTH shared by the page builder
2658
2758
  * (preview) and the SSR client engine (production). Pure, transport-agnostic: this module only
@@ -3087,5 +3187,5 @@ function effectiveTransitionId(anim) {
3087
3187
  * Generated bundle index. Do not edit.
3088
3188
  */
3089
3189
 
3090
- 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 };
3091
3191
  //# sourceMappingURL=vectoriox-iox-ui.mjs.map