@vectoriox/iox-ui 4.16.1 → 4.17.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.
|
@@ -2275,37 +2275,45 @@ class GalleryLoop {
|
|
|
2275
2275
|
* same index 0 — so the static frame and the first live frame match and there is no hydration flash.
|
|
2276
2276
|
*/
|
|
2277
2277
|
class ClientGalleryComponent {
|
|
2278
|
+
/** Manual images — `GalleryImage[]` or a plain `string[]` of URLs (normalised on set). */
|
|
2279
|
+
set images(v) {
|
|
2280
|
+
this._images = v ?? [];
|
|
2281
|
+
this.urls = resolveGalleryUrls(this.normalizeImages(), null);
|
|
2282
|
+
// A live edit (image added/removed/reordered) while the loop runs → restart on the new set so
|
|
2283
|
+
// the canvas reflects it and the loop cycles through the new count.
|
|
2284
|
+
if (this.loopActive)
|
|
2285
|
+
this.startLoop();
|
|
2286
|
+
}
|
|
2287
|
+
get images() { return this._images; }
|
|
2288
|
+
set showDuration(v) { this._showDuration = v; this.loop?.setDurations(v, this._fadeDuration); }
|
|
2289
|
+
get showDuration() { return this._showDuration; }
|
|
2290
|
+
set fadeDuration(v) { this._fadeDuration = v; this.loop?.setDurations(this._showDuration, v); }
|
|
2291
|
+
get fadeDuration() { return this._fadeDuration; }
|
|
2278
2292
|
constructor(platformId, cdr) {
|
|
2279
2293
|
this.cdr = cdr;
|
|
2280
2294
|
this.nodeId = '';
|
|
2281
|
-
/** Manual images — `GalleryImage[]` or a plain `string[]` of URLs (normalised on set). */
|
|
2282
|
-
this.images = [];
|
|
2283
2295
|
this.effect = 'fade';
|
|
2284
|
-
this.showDuration = 4000;
|
|
2285
|
-
this.fadeDuration = 1000;
|
|
2286
2296
|
this.autoStart = true;
|
|
2287
2297
|
/** Layout mode — only `'stack'` is rendered in v1 (`'grid'` scaffolded for later). */
|
|
2288
2298
|
this.layout = 'stack';
|
|
2289
|
-
|
|
2299
|
+
// ── Inputs that mutate live state use SETTERS, not ngOnChanges ──────────────────────────────
|
|
2300
|
+
// The builder trait panel pushes edits via DIRECT property assignment (`instance.images = v`),
|
|
2301
|
+
// which does NOT trigger ngOnChanges — so a gallery that recomputed in ngOnChanges never refreshed
|
|
2302
|
+
// when you added an image on the canvas. A setter fires on BOTH direct assignment (builder panel)
|
|
2303
|
+
// and setInput (SSR engine / render.directive), so it's the one path that works everywhere.
|
|
2304
|
+
this._images = [];
|
|
2305
|
+
this._showDuration = 4000;
|
|
2306
|
+
this._fadeDuration = 1000;
|
|
2307
|
+
/** The flat, display-ready URLs the loop cycles. Recomputed whenever `images` is set. */
|
|
2290
2308
|
this.urls = [];
|
|
2291
2309
|
this.currentIndex = 0;
|
|
2292
2310
|
this.fadingOutIndex = null;
|
|
2293
2311
|
this.started = false;
|
|
2312
|
+
/** True once the loop has been started (in ngAfterViewInit) — gates the setter-driven restart. */
|
|
2313
|
+
this.loopActive = false;
|
|
2294
2314
|
this.loop = null;
|
|
2295
2315
|
this.isBrowser = isPlatformBrowser(platformId);
|
|
2296
2316
|
}
|
|
2297
|
-
ngOnChanges(changes) {
|
|
2298
|
-
if (changes['images']) {
|
|
2299
|
-
this.urls = resolveGalleryUrls(this.normalizeImages(), null);
|
|
2300
|
-
}
|
|
2301
|
-
if (this.loop && (changes['showDuration'] || changes['fadeDuration'])) {
|
|
2302
|
-
this.loop.setDurations(this.showDuration, this.fadeDuration);
|
|
2303
|
-
}
|
|
2304
|
-
// If the image set changed after the loop was already running, restart it on the new count.
|
|
2305
|
-
if (this.loop && changes['images'] && !changes['images'].firstChange) {
|
|
2306
|
-
this.startLoop();
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
2317
|
ngAfterViewInit() {
|
|
2310
2318
|
if (this.isBrowser && this.autoStart) {
|
|
2311
2319
|
this.startLoop();
|
|
@@ -2314,6 +2322,7 @@ class ClientGalleryComponent {
|
|
|
2314
2322
|
ngOnDestroy() {
|
|
2315
2323
|
this.loop?.stop();
|
|
2316
2324
|
this.loop = null;
|
|
2325
|
+
this.loopActive = false;
|
|
2317
2326
|
}
|
|
2318
2327
|
/** Per-slide inline style. Before the loop activates (server + no-JS + pre-first-frame) the first
|
|
2319
2328
|
* image is the visible static frame; once running, the effect owns each slide's look. */
|
|
@@ -2333,6 +2342,7 @@ class ClientGalleryComponent {
|
|
|
2333
2342
|
startLoop() {
|
|
2334
2343
|
if (!this.isBrowser)
|
|
2335
2344
|
return;
|
|
2345
|
+
this.loopActive = true;
|
|
2336
2346
|
this.loop?.stop();
|
|
2337
2347
|
this.loop = new GalleryLoop({
|
|
2338
2348
|
showMs: this.showDuration,
|
|
@@ -2350,7 +2360,7 @@ class ClientGalleryComponent {
|
|
|
2350
2360
|
return (this.images ?? []).map(img => (typeof img === 'string' ? { url: img } : img));
|
|
2351
2361
|
}
|
|
2352
2362
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: ClientGalleryComponent, deps: [{ token: PLATFORM_ID }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2353
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: ClientGalleryComponent, isStandalone: false, selector: "iox-gallery", inputs: { nodeId: "nodeId",
|
|
2363
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: ClientGalleryComponent, isStandalone: false, selector: "iox-gallery", inputs: { nodeId: "nodeId", effect: "effect", autoStart: "autoStart", layout: "layout", images: "images", showDuration: "showDuration", fadeDuration: "fadeDuration" }, ngImport: i0, template: `
|
|
2354
2364
|
<div class="iox-gallery" [class]="'iox-node-' + nodeId">
|
|
2355
2365
|
<div *ngFor="let url of urls; index as i"
|
|
2356
2366
|
class="iox-gallery__img"
|
|
@@ -2376,18 +2386,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
|
|
|
2376
2386
|
args: [PLATFORM_ID]
|
|
2377
2387
|
}] }, { type: i0.ChangeDetectorRef }], propDecorators: { nodeId: [{
|
|
2378
2388
|
type: Input
|
|
2379
|
-
}], images: [{
|
|
2380
|
-
type: Input
|
|
2381
2389
|
}], effect: [{
|
|
2382
2390
|
type: Input
|
|
2383
|
-
}], showDuration: [{
|
|
2384
|
-
type: Input
|
|
2385
|
-
}], fadeDuration: [{
|
|
2386
|
-
type: Input
|
|
2387
2391
|
}], autoStart: [{
|
|
2388
2392
|
type: Input
|
|
2389
2393
|
}], layout: [{
|
|
2390
2394
|
type: Input
|
|
2395
|
+
}], images: [{
|
|
2396
|
+
type: Input
|
|
2397
|
+
}], showDuration: [{
|
|
2398
|
+
type: Input
|
|
2399
|
+
}], fadeDuration: [{
|
|
2400
|
+
type: Input
|
|
2391
2401
|
}] } });
|
|
2392
2402
|
|
|
2393
2403
|
const COMPONENTS = [
|
|
@@ -2835,6 +2845,83 @@ function composeVirtualTraits(raw, base = raw) {
|
|
|
2835
2845
|
return result;
|
|
2836
2846
|
}
|
|
2837
2847
|
|
|
2848
|
+
/**
|
|
2849
|
+
* tree-relations — framework-agnostic helpers for reasoning about a rendered node
|
|
2850
|
+
* tree's structural relationships. Lives in @vectoriox/iox-ui because BOTH renderers
|
|
2851
|
+
* depend on iox-ui (the engine does NOT depend on iox-builder), so the same logic
|
|
2852
|
+
* drives the builder canvas AND the SSR site — no fork.
|
|
2853
|
+
* See iox-ai-guidance `architecture/builder/targeted-hover-state-plan.md`.
|
|
2854
|
+
*/
|
|
2855
|
+
/** The css id a node contributes to selectors: its clone `styleId`, else its own `id`. */
|
|
2856
|
+
function nodeCssId(node) {
|
|
2857
|
+
return node.styleId ?? node.id;
|
|
2858
|
+
}
|
|
2859
|
+
/**
|
|
2860
|
+
* Path of css ids from the root down to (and including) the node whose css id === `cssId`.
|
|
2861
|
+
* Returns `null` when no node matches. First match wins (depth-first, pre-order).
|
|
2862
|
+
*/
|
|
2863
|
+
function pathToCssId(nodes, cssId) {
|
|
2864
|
+
for (const node of nodes) {
|
|
2865
|
+
const ownId = nodeCssId(node);
|
|
2866
|
+
if (ownId === cssId)
|
|
2867
|
+
return [ownId];
|
|
2868
|
+
if (node.children?.length) {
|
|
2869
|
+
const childPath = pathToCssId(node.children, cssId);
|
|
2870
|
+
if (childPath)
|
|
2871
|
+
return ownId ? [ownId, ...childPath] : childPath;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
return null;
|
|
2875
|
+
}
|
|
2876
|
+
/**
|
|
2877
|
+
* The css id of the NEAREST COMMON ANCESTOR of two nodes (identified by their css ids),
|
|
2878
|
+
* used to scope a `:has()` targeted-state selector so it stays repetition-safe.
|
|
2879
|
+
*
|
|
2880
|
+
* The result may equal `styledCssId` (the trigger sits INSIDE the styled node) or
|
|
2881
|
+
* `triggerCssId` (the styled node sits inside the trigger) — both are valid scopes;
|
|
2882
|
+
* `buildTargetedStateSelector` picks the right selector shape for each. Returns
|
|
2883
|
+
* `undefined` only when a valid scope can't exist: an id is blank, the two ids are the
|
|
2884
|
+
* same node, or they share no ancestor in `root`. Callers MUST skip emitting the rule
|
|
2885
|
+
* when this is `undefined` — never emit an unscoped (page-global) `:has()`, which would
|
|
2886
|
+
* break under repetition.
|
|
2887
|
+
*/
|
|
2888
|
+
function nearestCommonAncestorId(root, styledCssId, triggerCssId) {
|
|
2889
|
+
if (!styledCssId || !triggerCssId || styledCssId === triggerCssId)
|
|
2890
|
+
return undefined;
|
|
2891
|
+
const styledPath = pathToCssId(root, styledCssId);
|
|
2892
|
+
const triggerPath = pathToCssId(root, triggerCssId);
|
|
2893
|
+
if (!styledPath || !triggerPath)
|
|
2894
|
+
return undefined;
|
|
2895
|
+
// Walk both paths together; the last shared prefix element is the common ancestor.
|
|
2896
|
+
let common;
|
|
2897
|
+
const shorter = Math.min(styledPath.length, triggerPath.length);
|
|
2898
|
+
for (let i = 0; i < shorter; i++) {
|
|
2899
|
+
if (styledPath[i] !== triggerPath[i])
|
|
2900
|
+
break;
|
|
2901
|
+
common = styledPath[i];
|
|
2902
|
+
}
|
|
2903
|
+
return common;
|
|
2904
|
+
}
|
|
2905
|
+
/**
|
|
2906
|
+
* Build the selector BODY (no leading `.`, matching the builder's `compile()` convention)
|
|
2907
|
+
* for a targeted state, given the resolved scope. Three topologies, one shared rule:
|
|
2908
|
+
*
|
|
2909
|
+
* - trigger INSIDE styled (scope === styled): `iox-node-{styled}:has(.iox-node-{trigger}:{base})`
|
|
2910
|
+
* - styled INSIDE trigger (scope === trigger): `iox-node-{trigger}:{base} .iox-node-{styled}`
|
|
2911
|
+
* - separate subtrees (scope is above both): `iox-node-{scope}:has(.iox-node-{trigger}:{base}) .iox-node-{styled}`
|
|
2912
|
+
*
|
|
2913
|
+
* `scopeCssId` MUST be a value returned by `nearestCommonAncestorId` for the same pair.
|
|
2914
|
+
*/
|
|
2915
|
+
function buildTargetedStateSelector(scopeCssId, triggerCssId, styledCssId, base) {
|
|
2916
|
+
if (scopeCssId === styledCssId) {
|
|
2917
|
+
return `iox-node-${styledCssId}:has(.iox-node-${triggerCssId}:${base})`;
|
|
2918
|
+
}
|
|
2919
|
+
if (scopeCssId === triggerCssId) {
|
|
2920
|
+
return `iox-node-${triggerCssId}:${base} .iox-node-${styledCssId}`;
|
|
2921
|
+
}
|
|
2922
|
+
return `iox-node-${scopeCssId}:has(.iox-node-${triggerCssId}:${base}) .iox-node-${styledCssId}`;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2838
2925
|
/**
|
|
2839
2926
|
* Shared RELATIVE (route-context) data resolving — the SINGLE source of truth for how a detail page
|
|
2840
2927
|
* derives values FROM its current route item, consumed by BOTH the page builder (iox-cms-client) and
|
|
@@ -3540,5 +3627,5 @@ function effectiveTransitionId(anim) {
|
|
|
3540
3627
|
* Generated bundle index. Do not edit.
|
|
3541
3628
|
*/
|
|
3542
3629
|
|
|
3543
|
-
export { AOSService, AnalyticsService, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CMSClientInfraModule, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ConsentService, ContainerComponent, ContentService, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_WIDTH_BY_TYPE, ENVIRONMENT, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, 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, parseUrlList, planDataSource, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolvePageTransition, resolveRelativeInto, resolveRepeaterItems, resolveSiblings, resolveSingleItemId, rewriteViewportUnits, stripSuppressedProps, styleKeyToKebab };
|
|
3630
|
+
export { AOSService, AnalyticsService, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CMSClientInfraModule, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ConsentService, ContainerComponent, ContentService, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_WIDTH_BY_TYPE, ENVIRONMENT, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, 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, buildTargetedStateSelector, buildTransitionTimeline, collectReferencedAliases, compileDeclarations, composeVirtualTraits, computeRelative, dataSourcePlanToRequest, effectiveTransitionId, excludeSelf, feelFor, getByPath, isReservedAlias, legacyEnterToTransition, matchRouteParams, nearestCommonAncestorId, nodeCssId, normalizeCollectionResult, parseUrlList, planDataSource, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resolveDerivedInto, resolveGalleryEffect, resolveGalleryUrls, resolvePageTransition, resolveRelativeInto, resolveRepeaterItems, resolveSiblings, resolveSingleItemId, rewriteViewportUnits, stripSuppressedProps, styleKeyToKebab };
|
|
3544
3631
|
//# sourceMappingURL=vectoriox-iox-ui.mjs.map
|