@orangelogic/design-system 4.28.0 → 4.29.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.
Files changed (70) hide show
  1. package/library/chunks/{asset-link-format.BEJh0Fqs.js → asset-link-format.DLmg4fTR.js} +387 -381
  2. package/library/chunks/{audio.BZJvTs_4.js → audio.BVQX3_8E.js} +6 -3
  3. package/library/chunks/{bicolor-picker.C0PxxFzf.js → bicolor-picker.C9XSuhnX.js} +1 -1
  4. package/library/chunks/{block-width.CU2PEBrV.js → block-width.rWsXJkoW.js} +553 -529
  5. package/library/chunks/{border-input-group.w-T10AEY.js → border-input-group.DESRXoh1.js} +1 -1
  6. package/library/chunks/{color-picker.CDUhOLEs.js → color-picker.DUEghDon.js} +2 -2
  7. package/library/chunks/{color-swatch-group.DUskDB_p.js → color-swatch-group.Cf9NcMte.js} +45 -45
  8. package/library/chunks/{config-manager.C9OGzzbe.js → config-manager.FRWbPVTc.js} +17 -17
  9. package/library/chunks/{configs-controller.D3dYYbfz.js → configs-controller.R67BMWep.js} +26 -26
  10. package/library/chunks/{document-viewer.C7WOv7ns.js → document-viewer.DZp_IRF7.js} +16 -7
  11. package/library/chunks/{file-on-demand.DUWFRJnE.js → file-on-demand.C_2vBGS3.js} +3 -3
  12. package/library/chunks/{header.qIpzHeNc.js → header.BaWpIXRz.js} +5 -5
  13. package/library/chunks/{image.DzFSYcXq.js → image.BD0t8XU4.js} +1 -1
  14. package/library/chunks/{masonry.D7YK0FcU.js → masonry.B3G5f-eL.js} +1 -1
  15. package/library/chunks/{shadow-input-group.C9DU0Ehy.js → shadow-input-group.CFb61kzG.js} +1 -1
  16. package/library/chunks/src.DKYroWZc.js +720 -0
  17. package/library/chunks/{src.QS2741a8.js → src.fDrPRx_j.js} +8 -8
  18. package/library/chunks/{tab-group.DP9EvXFy.js → tab-group.oiueox5q.js} +627 -627
  19. package/library/chunks/{tab.C2OFvGGj.js → tab.Dd0cNxxc.js} +12 -8
  20. package/library/chunks/{url.CZO_DV8Y.js → url.BCc06dE7.js} +15 -6
  21. package/library/chunks/{video.BHfy8igQ.js → video.Ba5xl_3K.js} +1 -1
  22. package/library/components/asset-link-format.js +1 -1
  23. package/library/components/atoms.js +9 -9
  24. package/library/components/audio.js +1 -1
  25. package/library/components/bicolor-picker.js +1 -1
  26. package/library/components/border-input-group.js +1 -1
  27. package/library/components/color-picker.js +1 -1
  28. package/library/components/color-swatch-group.js +1 -1
  29. package/library/components/document-viewer.js +1 -1
  30. package/library/components/file-on-demand.js +1 -1
  31. package/library/components/header.js +1 -1
  32. package/library/components/image.js +1 -1
  33. package/library/components/masonry.js +1 -1
  34. package/library/components/molecules.js +4 -4
  35. package/library/components/organisms.js +3 -3
  36. package/library/components/shadow-input-group.js +1 -1
  37. package/library/components/tab-group.js +1 -1
  38. package/library/components/tab.js +1 -1
  39. package/library/components/types.js +12189 -12008
  40. package/library/components/video.js +1 -1
  41. package/library/package.json +1 -1
  42. package/library/packages/atoms/src/components/audio/audio.d.ts +2 -0
  43. package/library/packages/atoms/src/components/document-viewer/document-viewer.d.ts +6 -0
  44. package/library/packages/atoms/src/components/tab-group/tab-group.d.ts +65 -7
  45. package/library/packages/events/src/events.d.ts +0 -4
  46. package/library/packages/hybrid/rich-text/src/rich-text.d.ts +9 -0
  47. package/library/packages/organisms/src/content-builder/blocks/audio/audio.d.ts +13 -0
  48. package/library/packages/organisms/src/content-builder/blocks/button/button.d.ts +8 -0
  49. package/library/packages/organisms/src/content-builder/blocks/column/column.d.ts +5 -0
  50. package/library/packages/organisms/src/content-builder/blocks/column-group/column-group.d.ts +5 -0
  51. package/library/packages/organisms/src/content-builder/blocks/document-viewer/document-viewer.d.ts +8 -0
  52. package/library/packages/organisms/src/content-builder/blocks/image/image.d.ts +16 -13
  53. package/library/packages/organisms/src/content-builder/blocks/timeline/timeline.d.ts +0 -2
  54. package/library/packages/organisms/src/content-builder/blocks/video/video.d.ts +9 -0
  55. package/library/packages/organisms/src/content-builder/components/template-manager/template-manager.d.ts +11 -0
  56. package/library/packages/organisms/src/content-builder/content-builder.d.ts +17 -1
  57. package/library/packages/organisms/src/content-builder-viewer/content-builder-viewer.d.ts +15 -6
  58. package/library/packages/organisms/src/form/control-renderer/control-renderer.d.ts +1 -1
  59. package/library/packages/tools/src/fetch-asset/fetch-asset.d.ts +2 -1
  60. package/library/packages/tools/src/fetch-image/fetch-image.d.ts +28 -0
  61. package/library/packages/utils/src/asset-url-mode/asset-url-mode.d.ts +22 -0
  62. package/library/packages/utils/src/asset-url-mode/index.d.ts +1 -0
  63. package/library/packages/utils/src/url/url.d.ts +7 -0
  64. package/library/react-web-component.d.ts +25 -1
  65. package/library/utils.js +28 -706
  66. package/package.json +1 -1
  67. package/library/packages/events/src/cx-image-src-resolved.d.ts +0 -9
  68. package/library/packages/events/src/cx-timeline-data-resolved.d.ts +0 -9
  69. package/library/packages/events/src/cx-video-src-resolved.d.ts +0 -8
  70. package/library/packages/events/src/cx-video-thumbnail-resolved.d.ts +0 -8
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "../chunks/video.BHfy8igQ.js";
1
+ import { n as e, t } from "../chunks/video.Ba5xl_3K.js";
2
2
  export { t as VIDEO_BACKGROUND_SIZE_BY_OBJECT_FIT, e as default };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orangelogic/design-system",
3
3
  "type": "module",
4
- "version": "4.28.0",
4
+ "version": "4.29.0",
5
5
  "license": "UNLICENSED",
6
6
  "types": "library/types.d.ts",
7
7
  "scripts": {
@@ -77,6 +77,8 @@ export default class CxAudio extends ResizableElement {
77
77
  * `--waves-color` and `--background-color`.
78
78
  */
79
79
  waveformSrc: string;
80
+ /** Runtime source hook for wrappers resolving waveform URLs without changing saved attributes. */
81
+ protected get waveformSource(): string;
80
82
  /**
81
83
  * Playback start position in seconds. The UI time counter starts from 0 relative to this point.
82
84
  * `cx-time-update` emits `time` relative to this value.
@@ -39,6 +39,10 @@ export default class CxDocumentViewer extends ResizableElement {
39
39
  identifier: string;
40
40
  /** True when the current image source failed to load. */
41
41
  private hasImageError;
42
+ /** Runtime source hook for wrappers that resolve delivery URLs without mutating `src`. */
43
+ protected get documentSource(): string;
44
+ /** Runtime representative hook for wrappers that resolve URLs without mutating the model. */
45
+ protected get representativeSource(): string;
42
46
  get isPptx(): boolean;
43
47
  get isPdf(): boolean;
44
48
  get isExtensionSupported(): boolean;
@@ -47,6 +51,8 @@ export default class CxDocumentViewer extends ResizableElement {
47
51
  updated(changedProps: Map<string, unknown>): void;
48
52
  private handleSizeChange;
49
53
  private handleImageError;
54
+ /** Clears an image error when a subclass supplies a newly resolved runtime URL. */
55
+ protected resetImageError(): void;
50
56
  private renderPdfViewer;
51
57
  private renderExtensionFallback;
52
58
  private renderRepresentativeImage;
@@ -8,6 +8,7 @@ import { default as CxIconButton } from '../icon-button/icon-button';
8
8
  import { default as CxMenu } from '../menu/menu';
9
9
  import { default as CxMenuItem } from '../menu-item/menu-item';
10
10
  import { default as CxTab } from '../tab/tab';
11
+ import { default as CxTabPanel } from '../tab-panel/tab-panel';
11
12
  /**
12
13
  * @summary Tab groups organize content into a container that shows one section at a time.
13
14
  *
@@ -18,12 +19,14 @@ import { default as CxTab } from '../tab/tab';
18
19
  * (default) adds scroll buttons, `dropdown` collapses the overflow into a trigger and menu, and `pagination`
19
20
  * splits the tabs into fixed-size pages. With `overflow-variant="dropdown"`, `promote-active-overflow-tab`
20
21
  * keeps a selected hidden tab visible next to the trigger by swapping it with the tab it displaces, without
21
- * reordering either tab in the light DOM.
22
+ * reordering either tab in the light DOM. The dropdown trigger sits outside the tablist as its own tab stop and
23
+ * follows the menu button pattern; arrow keys, Home and End in the tablist only move between the visible tabs.
22
24
  *
23
25
  * @slot (default) - Used for grouping tab panels in the tab group. Must be `<cx-tab-panel>` elements.
24
26
  * @slot nav - Used for grouping tabs in the tab group. Must be `<cx-tab>` elements.
25
27
  *
26
- * @event {{ name: String }} cx-tab-show - Emitted when a tab is shown.
28
+ * @event {{ name: String }} cx-tab-show - Emitted when a tab is shown. With `force-on-change`, also emitted when
29
+ * the user selects the active tab again.
27
30
  * @event {{ name: String }} cx-tab-hide - Emitted when a tab is hidden.
28
31
  *
29
32
  * @csspart base - The component's base wrapper.
@@ -44,7 +47,10 @@ import { default as CxTab } from '../tab/tab';
44
47
  * @cssproperty --track-color - The color of the indicator's track (the line that separates tabs from panels).
45
48
  * @cssproperty --track-width - The width of the indicator's track (the line that separates tabs from panels).
46
49
  * @cssproperty [--tab-dropdown-trigger-max-width=150px] - The maximum width of the dropdown button.
50
+ * @cssproperty [--tab-dropdown-menu-max-width=300px] - The maximum width of each item in the dropdown menu, which the
51
+ * menu shrinks to. Longer tab labels are truncated with an ellipsis.
47
52
  * @cssproperty [--tab-group-nav-padding=0] - The padding around the tab group's navigation container.
53
+ * @cssproperty [--tab-group-tabs-gap=normal] - The horizontal gap between tabs.
48
54
  * @cssproperty [--tab-group-tabs-padding=var(--cx-spacing-2x-small)] - The padding around the tabs in the button variant.
49
55
  * @cssproperty [--tab-group-top-gap=var(--cx-spacing-small)] - The gap between the nav and body when placement is top.
50
56
  */
@@ -58,6 +64,7 @@ export default class CxTabGroup extends CortexElement {
58
64
  'cx-menu-item': typeof CxMenuItem;
59
65
  'cx-resize-observer': typeof CxResizeObserver;
60
66
  'cx-tab': typeof CxTab;
67
+ 'cx-tab-panel': typeof CxTabPanel;
61
68
  };
62
69
  private readonly localize;
63
70
  private mutationObserver;
@@ -72,12 +79,15 @@ export default class CxTabGroup extends CortexElement {
72
79
  * dropdownOffset and the tabs' hidden marker with outdated results.
73
80
  */
74
81
  private overflowObserver?;
82
+ /**
83
+ * Waits for the group to become visible to apply the initial active tab. Tracked so disconnectedCallback() can
84
+ * release it when the group is removed before it was ever shown.
85
+ */
86
+ private initialTabObserver?;
75
87
  /** Tab kept visible next to the dropdown trigger by promote-active-overflow-tab. */
76
88
  private promotedTab?;
77
89
  /** Tab to refocus once its promotion's fit-loop pass clears the hidden attribute (see restorePromotedTabFocus). */
78
90
  private promotedTabPendingFocus?;
79
- /** Keyboard "position" for arrow-key nav, independent of tabIndex (which always mirrors selection). */
80
- private focusedTab?;
81
91
  private tabs;
82
92
  private focusableTabs;
83
93
  private panels;
@@ -139,6 +149,11 @@ export default class CxTabGroup extends CortexElement {
139
149
  minTabWidth: number;
140
150
  /** When overflow-variant is "dropdown", keeps a selected hidden tab visible next to the trigger. */
141
151
  promoteActiveOverflowTab: boolean;
152
+ /**
153
+ * When set to true, the `cx-tab-show` event will be emitted when the user selects the active tab again,
154
+ * even if the active tab is not changed.
155
+ */
156
+ forceOnChange: boolean;
142
157
  /** Minimum clamp width - The minimum width of the tab not to be clamped */
143
158
  private static readonly MIN_CLAMP_WIDTH;
144
159
  private static readonly HIDDEN_TAB_ATTRIBUTE;
@@ -161,6 +176,10 @@ export default class CxTabGroup extends CortexElement {
161
176
  private getAllTabs;
162
177
  private getAllPanels;
163
178
  private getActiveTab;
179
+ /**
180
+ * The column gap between tabs (--tab-group-tabs-gap) in pixels; `normal` reads as 0.
181
+ */
182
+ private getTabGap;
164
183
  /**
165
184
  * If dropdown overflow but placement is start and end, count as scroll overflow
166
185
  */
@@ -171,6 +190,8 @@ export default class CxTabGroup extends CortexElement {
171
190
  * this getter is what the fit loop reads so a stale reservation can never keep the feature switched on.
172
191
  */
173
192
  private get activePromotedTab();
193
+ /** Whether promote-active-overflow-tab currently applies (it needs the dropdown overflow to be in effect). */
194
+ private get isPromotionEnabled();
174
195
  /**
175
196
  * Get the height of the body
176
197
  */
@@ -181,15 +202,46 @@ export default class CxTabGroup extends CortexElement {
181
202
  private get caretDirection();
182
203
  private handleClick;
183
204
  private handleKeyDown;
205
+ /**
206
+ * The tab that an arrow key, Home or End moves focus to: the first, last, previous or next enabled tab that is in
207
+ * the tablist, wrapping at both ends. Tabs hidden in the dropdown are menu items, not tabs, so they are skipped.
208
+ */
209
+ private getKeyboardTargetTab;
184
210
  private handleScrollToStart;
185
211
  private handleScrollToEnd;
186
- private handleDropdownAfterShow;
187
- /** Opens the dropdown from the last visible tab without activating anything; see handleDropdownAfterShow() for the item focus. */
188
- private enterDropdownFromTabStrip;
212
+ /**
213
+ * Promotes a tab that is already active when the group first renders (e.g. server-rendered after a round trip),
214
+ * so the first overflow pass never hides it. A display:none tab can't hold focus, so a host focusing it right
215
+ * after mount would otherwise lose focus. This can't wait for the first-load callback in connectedCallback():
216
+ * that callback runs a frame later, after the first overflow pass has already hidden the tab.
217
+ * Sets promotedTab only; the caller's syncTabsAndPanels() applies it.
218
+ */
219
+ private promoteInitialActiveTab;
220
+ /**
221
+ * The tab to select on first load: the first enabled `active` tab, else the first enabled tab. When a tab is
222
+ * explicitly active it matches what promoteInitialActiveTab() promoted.
223
+ * Skipping disabled tabs matters because setActiveTab() refuses them, which would leave nothing selected.
224
+ */
225
+ private findInitialTab;
189
226
  /** Marks tab as promoted (see promotedTab) without moving it in the DOM. */
190
227
  private promoteHiddenActiveTab;
191
228
  /** Queues tab to be refocused in syncTabAndPanels() once promoteHiddenActiveTab()'s fit-loop pass makes it visible again. */
192
229
  private restorePromotedTabFocus;
230
+ /**
231
+ * Single entry point for user and API activation, so every path keeps the promoted active tab visible.
232
+ * promoteHiddenActiveTab() only schedules the overflow pass, which runs later in an IntersectionObserver callback,
233
+ * so setActiveTab() still sees the tab hidden. restorePromotedTabFocus() must come first: promoteHiddenActiveTab()
234
+ * drops the refocus it queues when no pass is needed.
235
+ * Pass restoreFocus only when focus is on the tab itself (click, Enter/Space), not when it moves elsewhere.
236
+ * Pass isUserSelection only for an explicit pick (click, Enter/Space): with force-on-change it re-emits
237
+ * cx-tab-show for the active tab, which programmatic and arrow-key paths must not do.
238
+ */
239
+ private activateTab;
240
+ /**
241
+ * Roving tabindex: the active tab is the tablist's only tab stop. While the active tab is hidden in the dropdown,
242
+ * the first visible enabled tab takes its place so Tab can still reach the tablist.
243
+ */
244
+ private syncTabStop;
193
245
  private setActiveTab;
194
246
  private setAriaLabels;
195
247
  private repositionIndicator;
@@ -250,6 +302,12 @@ export default class CxTabGroup extends CortexElement {
250
302
  private handlePaginationDotClick;
251
303
  private handlePaginationDotKeyDown;
252
304
  private renderPaginationDot;
305
+ /**
306
+ * The overflow trigger and its menu follow the menu button pattern and sit outside the tablist, which may only own
307
+ * tabs. cx-dropdown and cx-menu provide the keyboard behavior (arrow keys wrap, Home/End, Escape returns focus to
308
+ * the trigger).
309
+ */
310
+ private renderDropdown;
253
311
  render(): import('lit-html').TemplateResult<1>;
254
312
  }
255
313
  declare global {
@@ -112,7 +112,6 @@ export * from './cx-hub-connection-disconnected';
112
112
  export * from './cx-hub-connection-reconnected';
113
113
  export * from './cx-hub-connection-reconnecting';
114
114
  export * from './cx-image-click';
115
- export * from './cx-image-src-resolved';
116
115
  export * from './cx-import-settings';
117
116
  export * from './cx-initial-focus';
118
117
  export * from './cx-input';
@@ -228,7 +227,6 @@ export * from './cx-table-switch-change';
228
227
  export * from './cx-table-validation-change';
229
228
  export * from './cx-time-based-change';
230
229
  export * from './cx-time-update';
231
- export * from './cx-timeline-data-resolved';
232
230
  export * from './cx-tiptap-code-block-doc-request';
233
231
  export * from './cx-tiptap-image-doc-request';
234
232
  export * from './cx-tiptap-image-host-feedback';
@@ -248,7 +246,6 @@ export * from './cx-video-comment-mouseleave';
248
246
  export * from './cx-video-comment-mouseover';
249
247
  export * from './cx-video-context-change';
250
248
  export * from './cx-video-editor-track-canvas-ready';
251
- export * from './cx-video-src-resolved';
252
249
  export * from './cx-video-editor-track-click';
253
250
  export * from './cx-video-editor-transition-click';
254
251
  export * from './cx-video-editor-events';
@@ -263,7 +260,6 @@ export * from './cx-video-seeked';
263
260
  export * from './cx-video-segment-change';
264
261
  export * from './cx-video-media';
265
262
  export * from './cx-video-time-update';
266
- export * from './cx-video-thumbnail-resolved';
267
263
  export * from './cx-view-and-sort-action-click';
268
264
  export * from './cx-view-logs';
269
265
  export * from './cx-xml-editor-asset-type-change';
@@ -19,6 +19,13 @@ import { RichTextMenuBarSpec, RichTextStyleFormat, RichTextToolbarSpec } from '.
19
19
  * @cssproperty --width - The width of the rich text editor
20
20
  * @cssproperty --rich-text-background-color - The background color of the rich text editor
21
21
  * @cssproperty --rich-text-font-family - The font family applied to the editor content area. Inherits from the page font when not set.
22
+ * @cssproperty --rich-text-border - The border around the rich text editor
23
+ * @cssproperty --rich-text-border-radius - The border radius of the rich text editor
24
+ * @cssproperty --rich-text-toolbar-background-color - The background color of the toolbar
25
+ * @cssproperty --rich-text-toolbar-border-color - The color of the line between the toolbar and the content
26
+ * @cssproperty --rich-text-table-resize-handle-color - The color of the table column and row resize handles
27
+ * @cssproperty --rich-text-inline-code-color - The text color of inline code
28
+ * @cssproperty --rich-text-inline-code-background-color - The background color of inline code
22
29
  *
23
30
  * @description When `editable` is true, a `cx-rich-text-toolbar` is rendered above the editor using the same `Editor`
24
31
  * instance for formatting commands. Set **`show-toolbar`** to false to hide only the formatting **icon row** (menu bar is unchanged).
@@ -99,6 +106,8 @@ export default class CxRichText extends CortexElement {
99
106
  * skipped when `getHTML()` is unchanged.
100
107
  */
101
108
  private lastContent;
109
+ /** False until this component's onCreate ran; updates before it are the editor normalising its own content. */
110
+ private editorCreated;
102
111
  content: string;
103
112
  editable: boolean;
104
113
  /**
@@ -37,12 +37,25 @@ export default class CxSbAudio extends CxAudio {
37
37
  * own asset metadata and maps this data into state instead.
38
38
  */
39
39
  fetchedAssetData: Record<string, unknown>;
40
+ private lastAppliedWaveformSrc;
41
+ private sourceResolveVersion;
42
+ private forceSourceResolution;
43
+ private resolvedWaveformSrc;
44
+ protected get waveformSource(): string;
40
45
  /**
41
46
  * Support CMS5 edit mode for the audio.
42
47
  */
43
48
  get isInEditMode(): boolean;
44
49
  runConnectedCallback(): void;
45
50
  handleSrcChange(): Promise<void>;
51
+ handleSourceIdentityChange(): void;
52
+ private resolveWaveformSource;
53
+ /**
54
+ * Re-resolves a stored URL that has expired, from `record-id` + `format`. Returns the stored URL
55
+ * unchanged when there is nothing to recover from, or when the fresh resolve fails.
56
+ */
57
+ private recoverStoredSrc;
58
+ disconnectedCallback(): void;
46
59
  handleRecordIdChange(): Promise<void>;
47
60
  handleFetchedAssetDataChange(): void;
48
61
  private applyAssetData;
@@ -35,6 +35,7 @@ export default class CxSbButton extends CxButton {
35
35
  */
36
36
  assetSrc: string;
37
37
  recordId: string;
38
+ siteBuilderToken: string;
38
39
  recordName: string;
39
40
  dataLabel: string;
40
41
  dataIconName: {
@@ -105,6 +106,13 @@ export default class CxSbButton extends CxButton {
105
106
  spaces?: TeamSpace[];
106
107
  /** Space URL re-resolved when the stored one points at a space that moved. */
107
108
  private resolvedClickSpace;
109
+ /** Runtime-only asset URL resolved for the active permanent/expiring mode. */
110
+ private resolvedAssetSrc;
111
+ private fetchImageController?;
112
+ private fetchAssetController?;
113
+ private assetResolveVersion;
114
+ resolveAssetSrcFromRecordId(): Promise<void>;
115
+ private get renderedAssetSrc();
108
116
  handleClickSpaceChange(): void;
109
117
  /**
110
118
  * `outline` is a boolean on `cx-button`, but the block carries every appearance
@@ -32,6 +32,8 @@ export default class CxColumn extends CortexElement {
32
32
  };
33
33
  private readonly localize;
34
34
  private readonly hasSlotController;
35
+ private fetchImageController?;
36
+ private backgroundResolveVersion;
35
37
  containerEl: HTMLDivElement;
36
38
  defaultSlot: HTMLSlotElement;
37
39
  resizable: boolean;
@@ -81,6 +83,7 @@ export default class CxColumn extends CortexElement {
81
83
  * The asset transformations applied to the background image.
82
84
  */
83
85
  backgroundTransformations: Transformation[];
86
+ siteBuilderToken: string;
84
87
  /**
85
88
  * The object-fit-style crop applied to the background image.
86
89
  */
@@ -101,6 +104,7 @@ export default class CxColumn extends CortexElement {
101
104
  */
102
105
  nestedBandLayout: boolean;
103
106
  private showAddBlockButton;
107
+ private resolvedBackgroundSrc;
104
108
  /**
105
109
  * Whether the add-block button overlays the column (`--column-add-block-position: absolute`).
106
110
  * An overlaid button cannot rely on selecting the column to appear — a full column offers no
@@ -183,6 +187,7 @@ export default class CxColumn extends CortexElement {
183
187
  private handleScroll;
184
188
  private syncHasDamViewChild;
185
189
  private handleSlotChange;
190
+ handleBackgroundAssetChange(): Promise<void>;
186
191
  get resolvedBackgroundImageUrl(): string | undefined;
187
192
  render(): TemplateResult;
188
193
  }
@@ -14,6 +14,8 @@ export default class CxColumnGroup extends CortexElement {
14
14
  'cx-divider': typeof CxDivider;
15
15
  };
16
16
  private mutationObserver;
17
+ private fetchImageController?;
18
+ private backgroundResolveVersion;
17
19
  containerEl: HTMLDivElement;
18
20
  private readonly assignedColumns;
19
21
  trigger: ColumnTriggerMode;
@@ -54,11 +56,13 @@ export default class CxColumnGroup extends CortexElement {
54
56
  * The asset transformations applied to the background image.
55
57
  */
56
58
  backgroundTransformations: Transformation[];
59
+ siteBuilderToken: string;
57
60
  /**
58
61
  * Breakpoints for responsive design.
59
62
  */
60
63
  breakpoints: [number, number, number];
61
64
  private columnCount;
65
+ private resolvedBackgroundSrc;
62
66
  private isDeprecated;
63
67
  constructor();
64
68
  connectedCallback(): void;
@@ -70,6 +74,7 @@ export default class CxColumnGroup extends CortexElement {
70
74
  private handleMutation;
71
75
  private checkIsDeprecated;
72
76
  handleSlotChange(): Promise<void>;
77
+ handleBackgroundAssetChange(): Promise<void>;
73
78
  get resolvedBackgroundImageUrl(): string | undefined;
74
79
  render(): TemplateResult;
75
80
  }
@@ -20,10 +20,18 @@ export default class CxSbDocumentViewer extends CxDocumentViewer {
20
20
  static readonly styles: CSSResultGroup;
21
21
  /** The asset record ID, used to open the asset overview when can-open-asset is enabled. */
22
22
  recordId: string;
23
+ siteBuilderToken: string;
23
24
  /** When true, renders a corner overlay button that opens the asset overview on hover and click. */
24
25
  canOpenAsset: boolean;
26
+ private resolvedDocumentSource;
27
+ private resolvedRepresentativeSource;
28
+ private fetchAssetController?;
29
+ private assetResolveVersion;
25
30
  private get isInEditMode();
31
+ protected get documentSource(): string;
32
+ protected get representativeSource(): string;
26
33
  constructor();
34
+ resolveAssetSourcesFromRecordId(): Promise<void>;
27
35
  private handleOpenAssetButtonClick;
28
36
  private renderOpenAssetButton;
29
37
  render(): import('lit-html').TemplateResult<1>;
@@ -156,6 +156,8 @@ export default class CxSbImage extends CxImage {
156
156
  * delivery URL from the `path_*` fields here rather than searching for one.
157
157
  */
158
158
  fetchedAssetData: Record<string, unknown>;
159
+ /** Batched data for the dark variant; retained independently of the light asset. */
160
+ fetchedAssetDataDarkMode: Record<string, unknown>;
159
161
  private renderedImageSrc;
160
162
  /**
161
163
  * Indicates whether the image is currently zoomed.
@@ -209,6 +211,13 @@ export default class CxSbImage extends CxImage {
209
211
  private srcResolveVersion;
210
212
  /** A source recovery is already queued for the current update cycle. */
211
213
  private sourceRecoveryScheduled;
214
+ /** Serializes Search calls so metadata updates cannot invalidate each other forever. */
215
+ private sourceRecoveryInFlight?;
216
+ /** Runs one final recovery after inputs change during an in-flight request. */
217
+ private sourceRecoveryPending;
218
+ /** Last successfully resolved edit-mode input keys, one per image variant. */
219
+ private resolvedSrcKey;
220
+ private resolvedSrcDarkModeKey;
212
221
  /**
213
222
  * Support CMS5 edit mode for the image.
214
223
  */
@@ -305,6 +314,7 @@ export default class CxSbImage extends CxImage {
305
314
  */
306
315
  handleRecordIdChangeForExtension(): void;
307
316
  handleFetchedAssetDataChange(): void;
317
+ handleProvidedVariantChange(): void;
308
318
  protected update(changedProps: PropertyValues): void;
309
319
  protected handleLoad(event: Event): void;
310
320
  /**
@@ -345,20 +355,13 @@ export default class CxSbImage extends CxImage {
345
355
  * itself — one call per page instead of one (or more) per block.
346
356
  */
347
357
  private get hasAssetDataProvider();
348
- /**
349
- * Picks one variant's delivery URL out of the viewer's batched data. Mirrors
350
- * `FetchAssetController.refetchFormatUrl`: the original-file proxy is only used for a
351
- * browser-displayable original and otherwise falls back to the transcoded one. Empty
352
- * until the batch lands, and for a variant the batch did not cover.
353
- */
358
+ /** Selects metadata by identity, independently of which theme was initially loaded. */
359
+ private getProvidedAssetData;
360
+ /** Picks a variant's delivery URL, with a transcoded fallback for non-image originals. */
354
361
  private readProvidedSource;
355
- /**
356
- * When a stored URL has expired, or none was stored, resolve one from the block's
357
- * `record-id` + `format` (light and dark variants independently). Fires on every
358
- * `src` / `srcDarkMode` / record change and no-ops for non-expired URLs, so working
359
- * paths are untouched. On failure it leaves the stored URL in place and lets the
360
- * existing `@error` / fallback path handle it.
361
- */
362
+ /** Each batched variant has its own extension and file size for Auto format. */
363
+ private resolveProvidedAutoFormat;
364
+ /** Resolves light and dark URLs independently without changing their saved sources. */
362
365
  private recoverExpiredSources;
363
366
  private recoverExpiredSource;
364
367
  private get renderedSrc();
@@ -12,7 +12,6 @@ import { CSSResultGroup } from 'lit';
12
12
  * @summary CxTimeline
13
13
  */
14
14
  export default class CxTimeline extends CortexElement {
15
- #private;
16
15
  static readonly styles: CSSResultGroup;
17
16
  static readonly dependencies: {
18
17
  'cx-icon-button': typeof CxIconButton;
@@ -67,7 +66,6 @@ export default class CxTimeline extends CortexElement {
67
66
  /** Proxy URLs and their `srcset` candidates resolved from asset fetch, keyed by item.id. */
68
67
  private resolvedThumbnails;
69
68
  handleDataChange(): Promise<void>;
70
- private persistResolvedThumbnailsToData;
71
69
  private handlePreviousClick;
72
70
  private handleNextClick;
73
71
  render(): import('lit-html').TemplateResult<1>;
@@ -146,6 +146,13 @@ export default class CxSbVideo extends CxVideo {
146
146
  private resolvedClickSpace;
147
147
  /** Lazily created; recovers a fresh signed URL when the stored one expires. */
148
148
  private fetchAssetController?;
149
+ /** Lazily resolves the poster from its record id for the active URL mode. */
150
+ private posterFetchImageController?;
151
+ /** Runtime-only poster URL. Signed URLs must never be reflected into the document. */
152
+ private resolvedPoster;
153
+ /** Monotonic token to drop stale poster lookups. */
154
+ private posterResolveVersion;
155
+ private forceSourceResolution;
149
156
  /**
150
157
  * Support CMS5 edit mode for the video.
151
158
  */
@@ -186,8 +193,10 @@ export default class CxSbVideo extends CxVideo {
186
193
  private resolveClickSpace;
187
194
  handleThumbnailChange(): void;
188
195
  handlePosterChange(): Promise<void>;
196
+ resolvePosterFromRecordId(): Promise<void>;
189
197
  handleFetchedAssetDataChange(): void;
190
198
  handleSrcChange(): Promise<void>;
199
+ handleSourceIdentityChange(): void;
191
200
  /**
192
201
  * Returns the URL to hand to the player
193
202
  */
@@ -84,6 +84,13 @@ export default class CxTemplateManager extends CortexElement {
84
84
  * @default false
85
85
  */
86
86
  enableAssetFormatControls: boolean;
87
+ /**
88
+ * Whether the server mints expiring asset URLs for this instance (42ASN5). When set, resolutions stop
89
+ * asking for permanent asset paths, which on the server would create the permanent anonymous link this
90
+ * feature removes. When this and `enable-asset-format-controls` are both true,
91
+ * expiring URLs take precedence and the incompatible controls stay disabled.
92
+ */
93
+ useExpiringAssetUrls: boolean;
87
94
  /**
88
95
  * Exposes the font family / style / weight pickers in the block config sidebar.
89
96
  * Should match the host `cx-content-builder` setting.
@@ -146,7 +153,11 @@ export default class CxTemplateManager extends CortexElement {
146
153
  private _apiGetTemplates;
147
154
  private _apiGetTemplatesForType;
148
155
  private _apiUpdateTemplate;
156
+ /** Keep standalone template editing on the same URL mode as the page host. */
157
+ protected willUpdate(): void;
149
158
  handleLoadedChange(): Promise<void>;
159
+ /** Expiring asset URLs cannot be rewritten by format or transformation controls. */
160
+ private get resolvedEnableAssetFormatControls();
150
161
  private resetState;
151
162
  handleTemplateChange(): void;
152
163
  private handleEdit;
@@ -15,7 +15,9 @@ import { CxRTEBubbleMenu, CxRTETableGenerator } from './plugins';
15
15
  *
16
16
  * Set `enable-asset-format-controls` to expose the asset format, transformation,
17
17
  * download-format, and asset-format-picker controls on image, video, gallery,
18
- * carousel, column-group, and timeline blocks. Off by default.
18
+ * carousel, column-group, and timeline blocks. Off by default. When
19
+ * `use-expiring-asset-urls` is also set, expiring URLs take precedence and the
20
+ * incompatible format and transformation controls stay disabled.
19
21
  *
20
22
  * `default-image-format`, `default-video-poster-format`, `default-timeline-format`,
21
23
  * `default-gallery-format` and `default-carousel-format` are retained for backward
@@ -135,6 +137,13 @@ export default class CxContentBuilder extends CortexElement {
135
137
  * @default false
136
138
  */
137
139
  enableAssetFormatControls: boolean;
140
+ /**
141
+ * Whether the server mints expiring asset URLs for this instance (42ASN5). When set, resolutions stop
142
+ * asking for permanent asset paths, which on the server would create the permanent anonymous link this
143
+ * feature removes. When this and `enable-asset-format-controls` are both true,
144
+ * expiring URLs take precedence and the incompatible controls stay disabled.
145
+ */
146
+ useExpiringAssetUrls: boolean;
138
147
  /**
139
148
  * Whether the content builder emits `ol:ui-metric` events timing each user action,
140
149
  * for collection as browser OpenTelemetry histograms.
@@ -331,6 +340,13 @@ export default class CxContentBuilder extends CortexElement {
331
340
  private get measuredOnRequestDownloadFormat();
332
341
  private get measuredOnConfigureWorkflow();
333
342
  private get measuredOnRequestAssetFormat();
343
+ /** Expiring asset URLs cannot be rewritten by format or transformation controls. */
344
+ private get resolvedEnableAssetFormatControls();
345
+ /**
346
+ * 42ASN5: one mode per page. The template manager reuses the block config sidebar, so the mode is set
347
+ * here once on first update rather than in each consumer — a second read could disagree with the viewer.
348
+ */
349
+ protected willUpdate(): void;
334
350
  get isDesigner(): boolean;
335
351
  get isTemplateEditable(): boolean;
336
352
  get isMultiLanguage(): boolean;
@@ -1,4 +1,5 @@
1
1
  import { default as CortexLightElement } from '../../../base/src/cortex-light-element.ts';
2
+ import { PropertyValues } from 'lit';
2
3
  /**
3
4
  * @summary Wraps content-builder output — read mode and the editor canvas alike —
4
5
  * supplying its blocks with data they would otherwise each fetch for themselves.
@@ -9,10 +10,10 @@ import { default as CortexLightElement } from '../../../base/src/cortex-light-el
9
10
  * `cx-sb-video` linking to a space, and `cx-gallery` showing space cards), fetching
10
11
  * the space list once and assigning it as `spaces`. It also distributes its
11
12
  * `securityBypassToken` to the record-id children that still search for themselves
12
- * (`cx-sb-video`, `cx-sb-audio`, `cx-timeline`, and `cx-details-group` for section backgrounds); an
13
- * image block takes its URL from the batch instead. Renders no UI. Blocks skip their own fetch whenever an ancestor supplies
14
- * it, so they must sit inside this element for that to apply — in the editor that means
15
- * inside the canvas document.
13
+ * (`cx-sb-video`, `cx-sb-audio`, `cx-timeline`, background containers, buttons, and document
14
+ * viewers); an image block takes its URL from the batch instead. Renders no UI. Blocks skip
15
+ * their own fetch whenever an ancestor supplies it, so they must sit inside this element for
16
+ * that to apply - in the editor that means inside the canvas document.
16
17
  *
17
18
  * Space URLs are re-resolved per scan because they break when the space moves domain;
18
19
  * doing it per block would repeat one identical request each and race this assignment.
@@ -26,6 +27,12 @@ export default class CxContentBuilderViewer extends CortexLightElement {
26
27
  * (which consume it as `siteBuilderToken`). Empty on authenticated/preview pages.
27
28
  */
28
29
  securityBypassToken: string;
30
+ /**
31
+ * Whether the server minted expiring asset URLs for this page (42ASN5). When present, resolutions must
32
+ * not ask for permanent asset paths — on the server that request creates the permanent anonymous link
33
+ * this feature removes. Set from the host attribute, same as `security-bypass-token`.
34
+ */
35
+ useExpiringAssetUrls: boolean;
29
36
  /** Blocks already populated by a previous asset-data scan; skipped on re-scans. */
30
37
  private readonly processedFetchableBlocks;
31
38
  /** Blocks already populated by a previous space-list scan; skipped on re-scans. */
@@ -38,6 +45,8 @@ export default class CxContentBuilderViewer extends CortexLightElement {
38
45
  createRenderRoot(): this;
39
46
  connectedCallback(): void;
40
47
  disconnectedCallback(): void;
48
+ protected willUpdate(changedProperties: PropertyValues<this>): void;
49
+ private syncAssetUrlMode;
41
50
  /** Blocks arrive in bursts as the page parses, so scans are collapsed. */
42
51
  private scheduleScan;
43
52
  private scanAndFetch;
@@ -45,8 +54,8 @@ export default class CxContentBuilderViewer extends CortexLightElement {
45
54
  private distributeToken;
46
55
  private scanAndFetchAssetData;
47
56
  private collectFetchableBlocks;
48
- /** The record ID a block would use if it fetched its own asset data right now. */
49
- private getPrimaryRecordId;
57
+ /** Fetch both image variants so a theme switch needs no additional request. */
58
+ private getRecordIds;
50
59
  /** Every field a block could map from fetched asset data. */
51
60
  private getRequestedFields;
52
61
  /**
@@ -157,7 +157,7 @@ export declare class ControlRenderer {
157
157
  */
158
158
  private resolveAssetFormatSrc;
159
159
  /** Resolves the URL and intrinsic ratio from the same selected media field. */
160
- resolveAssetFormat(recordId: string, format: string): Promise<{
160
+ resolveAssetFormat(recordId: string, format: string, resolveExpiringImagePath: boolean): Promise<{
161
161
  aspectRatio: number;
162
162
  src: string;
163
163
  }>;
@@ -23,9 +23,10 @@ export declare class FetchAssetController implements ReactiveController {
23
23
  * `apiGetAssets` maps a `path_<format>` media field to its `.URI` string, so the
24
24
  * fresh URL is read straight back off the requested field.
25
25
  */
26
- refetchFormatUrl({ format, recordId, securityByPassToken, token, }: {
26
+ refetchFormatUrl({ format, recordId, resolveExpiringImagePath, securityByPassToken, token, }: {
27
27
  format: string;
28
28
  recordId: string;
29
+ resolveExpiringImagePath?: boolean;
29
30
  securityByPassToken?: string;
30
31
  token?: string;
31
32
  }): Promise<string>;