@orangelogic/design-system 2.191.0 → 2.192.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 (61) hide show
  1. package/library/chunks/{asset-link-format.CEDcHah6.js → asset-link-format.CDd4iPA2.js} +1141 -992
  2. package/library/chunks/{color-swatch-group.tnhiQ0jp.js → color-swatch-group.NOcRP-23.js} +4 -3
  3. package/library/chunks/{confirm-popover.CrQKEChc.js → confirm-popover.jCP9CdcD.js} +1 -1
  4. package/library/chunks/content-builder.BX4pHujE.js +60 -0
  5. package/library/chunks/{dialog.CWGtufDA.js → dialog.B6hZ7fvn.js} +2 -2
  6. package/library/chunks/{document-viewer.C90j1Xrr.js → document-viewer.CRluR-_W.js} +3 -2
  7. package/library/chunks/{image.CTMzUqCC.js → image.CiQwSDfe.js} +186 -187
  8. package/library/chunks/{toast.CXEAfCvN.js → toast.C5Ir5yKA.js} +1 -1
  9. package/library/chunks/transformation.BfIEi4p4.js +300 -0
  10. package/library/components/asset-link-format.js +2 -2
  11. package/library/components/atoms.js +3 -3
  12. package/library/components/color-swatch-group.js +3 -3
  13. package/library/components/confirm-popover.js +2 -2
  14. package/library/components/cropper.js +1 -1
  15. package/library/components/dialog.js +1 -1
  16. package/library/components/document-viewer.js +2 -2
  17. package/library/components/drawer.js +2 -2
  18. package/library/components/file-on-demand.js +2 -2
  19. package/library/components/image.js +2 -3
  20. package/library/components/masonry.js +136 -107
  21. package/library/components/molecules.js +1 -1
  22. package/library/components/organisms.js +2 -2
  23. package/library/components/popup.js +100 -97
  24. package/library/components/select.js +16 -11
  25. package/library/components/types.js +21757 -21460
  26. package/library/components/video.js +1 -1
  27. package/library/package.json +1 -1
  28. package/library/packages/atoms/src/components/image/image.d.ts +36 -4
  29. package/library/packages/atoms/src/components/popup/popup.d.ts +11 -0
  30. package/library/packages/atoms/src/components/select/select.d.ts +8 -0
  31. package/library/packages/events/src/cx-asset-transformation-dialog-confirm.d.ts +2 -0
  32. package/library/packages/molecules/src/cropper/cropper.d.ts +0 -1
  33. package/library/packages/molecules/src/cropper/react/Cropper.d.ts +0 -1
  34. package/library/packages/molecules/src/gallery-item/gallery-item.d.ts +10 -0
  35. package/library/packages/molecules/src/masonry/masonry.d.ts +24 -0
  36. package/library/packages/organisms/src/asset-link-format/asset-link-format.d.ts +46 -2
  37. package/library/packages/organisms/src/asset-link-format/components/asset-link-format-proxy/asset-link-format-proxy.d.ts +36 -1
  38. package/library/packages/organisms/src/asset-transformation-dialog/asset-transformation-dialog.d.ts +20 -2
  39. package/library/packages/organisms/src/bento-grid/bento-grid.d.ts +101 -0
  40. package/library/packages/organisms/src/carousel/carousel.d.ts +26 -0
  41. package/library/packages/organisms/src/content-builder/blocks/image/image.d.ts +65 -1
  42. package/library/packages/organisms/src/content-builder/blocks/video/video.d.ts +5 -0
  43. package/library/packages/organisms/src/content-builder/components/config-form/config-form.d.ts +2 -1
  44. package/library/packages/organisms/src/content-builder/components/gallery-picker/gallery-picker.d.ts +6 -0
  45. package/library/packages/organisms/src/content-builder/configs/carousel.d.ts +1 -0
  46. package/library/packages/organisms/src/content-builder/configs/gallery.d.ts +1 -0
  47. package/library/packages/organisms/src/content-builder/configs/image.d.ts +2 -0
  48. package/library/packages/organisms/src/content-builder/configs/timeline.d.ts +1 -0
  49. package/library/packages/organisms/src/content-builder/configs/video.d.ts +1 -0
  50. package/library/packages/organisms/src/content-builder/configs-controller.d.ts +10 -0
  51. package/library/packages/organisms/src/content-builder/styleController.d.ts +2 -0
  52. package/library/packages/tools/src/fetch-image/fetch-image.d.ts +28 -5
  53. package/library/packages/types/src/asset-link-format.d.ts +0 -1
  54. package/library/packages/types/src/content-builder.d.ts +7 -0
  55. package/library/packages/types/src/gallery-item.d.ts +1 -0
  56. package/library/packages/types/src/masonry.d.ts +1 -0
  57. package/library/packages/utils/src/transformation/transformation.d.ts +91 -0
  58. package/library/react-web-component.d.ts +63 -7
  59. package/library/utils.js +192 -182
  60. package/package.json +1 -1
  61. package/library/chunks/transformation.8uLv6uwG.js +0 -264
@@ -1,7 +1,7 @@
1
1
  import { _ as kd, a as Sa, b as Be, c as Je } from "../chunks/inheritsLoose.BuSn_CvZ.js";
2
2
  import { c as ps, a as Bn } from "../chunks/_commonjsHelpers.DQNKXVTB.js";
3
3
  import { r as Sb } from "../chunks/___vite-browser-external_commonjs-proxy.C2tf3HsQ.js";
4
- import { C as Cb } from "../chunks/image.CTMzUqCC.js";
4
+ import { C as Cb } from "../chunks/image.CiQwSDfe.js";
5
5
  import Mb from "./resize-observer.js";
6
6
  import { r as Db, R as Pb, a as Rp, b as Lb } from "../chunks/resizable-component.styles.CAfXABBc.js";
7
7
  import { c as Rb } from "../chunks/component.styles.CRO4Odto.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orangelogic/design-system",
3
3
  "type": "module",
4
- "version": "2.191.0",
4
+ "version": "2.192.0",
5
5
  "license": "UNLICENSED",
6
6
  "types": "library/types.d.ts",
7
7
  "scripts": {
@@ -9,15 +9,18 @@ import { default as CxPopup } from '../popup/popup';
9
9
  import { default as CxResizeObserver } from '../resize-observer/resize-observer';
10
10
  import { default as CxSkeleton } from '../skeleton/skeleton';
11
11
  import { default as CxSpace } from '../space/space';
12
- import { default as CxSpinner } from '../spinner/spinner';
13
12
 
14
13
  /**
15
14
  * @summary Images are wrappers for img elements with built-in lazy loading, skeleton, and fallback support.
16
15
  * The cx-image component is a simple way to display images in your application.
17
16
  *
17
+ * @description Set `srcset` and `sizes` to let the browser download and decode only the
18
+ * pixels the layout needs. This is what bounds memory on image-heavy pages: a large
19
+ * original decodes to `naturalWidth × naturalHeight × 4` bytes no matter how small it
20
+ * is displayed, so many full-resolution images on one page can exhaust the renderer.
21
+ *
18
22
  * @csspart image - The `img` element.
19
- * @csspart skeleton - The skeleton element, will be shown while the image is loading and the `skeleton` property is set.
20
- * @csspart retry-spinner - The spinner overlay shown while a failed load is being retried (when `retry-on-error` is enabled).
23
+ * @csspart skeleton - The skeleton element, shown while the image is loading (including while a failed load is being retried) and the `skeleton` property is set.
21
24
  * @csspart fallback - The fallback element, always shown when the image fails to load (after retries, when applicable).
22
25
  * @csspart base - The component’s outer wrapper.
23
26
  * @csspart fallback-icon - The icon rendered inside the fallback slot.
@@ -48,7 +51,6 @@ export default class CxImage extends ResizableElement {
48
51
  'cx-resize-observer': typeof CxResizeObserver;
49
52
  'cx-skeleton': typeof CxSkeleton;
50
53
  'cx-space': typeof CxSpace;
51
- 'cx-spinner': typeof CxSpinner;
52
54
  };
53
55
  readonly localize: LocalizeController;
54
56
  imageElement?: HTMLImageElement;
@@ -66,6 +68,21 @@ export default class CxImage extends ResizableElement {
66
68
  * The path to the image to load.
67
69
  */
68
70
  src: string;
71
+ /**
72
+ * Candidate sources for the underlying `<img>`, as a standard `srcset` value
73
+ * (e.g. `"…/re_w_400/img.jpg 400w, …/re_w_800/img.jpg 800w"`).
74
+ *
75
+ * Lets the browser fetch and decode only the pixels the layout needs, which is what
76
+ * bounds memory on image-heavy pages — a large original decodes to
77
+ * `naturalWidth × naturalHeight × 4` bytes regardless of its display size.
78
+ * Pair with `sizes`; without it the browser assumes the image is `100vw` wide.
79
+ */
80
+ srcset: string;
81
+ /**
82
+ * The `sizes` attribute for the underlying `<img>`, describing the rendered width
83
+ * (e.g. `"400px"`). Only meaningful together with `srcset`.
84
+ */
85
+ sizes: string;
69
86
  /**
70
87
  * The path to the placeholder image to be shown if src is not available.
71
88
  */
@@ -122,6 +139,12 @@ export default class CxImage extends ResizableElement {
122
139
  retryOnError: boolean;
123
140
  /**
124
141
  * Maximum number of retry attempts when `retry-on-error` is enabled.
142
+ *
143
+ * Set high enough to outlast a transient backend overload: a page full of images
144
+ * can push the transform service into 503s, and those images need to keep retrying
145
+ * until it recovers rather than falling back to a broken-image icon. The backoff is
146
+ * exponential and capped at 10s per attempt, so the attempts spread out instead of
147
+ * adding to the load.
125
148
  */
126
149
  maxRetries: number;
127
150
  /**
@@ -151,6 +174,15 @@ export default class CxImage extends ResizableElement {
151
174
  };
152
175
  /** The crossorigin value for the `<img>`; `undefined` (attribute omitted) when `noCrossorigin` is set. */
153
176
  get crossorigin(): string | undefined;
177
+ /**
178
+ * Whether to hold the box with a skeleton rather than the loaded image.
179
+ *
180
+ * Retries are included: a retry is still "not loaded yet", so it keeps the same
181
+ * skeleton instead of swapping in a spinner. A spinner would restate what the
182
+ * skeleton already shows while changing the visual weight of the cell mid-load,
183
+ * which reads as a layout change on an image-heavy page.
184
+ */
185
+ protected get showPlaceholderSkeleton(): boolean;
154
186
  /**
155
187
  * Whether the image have zoom action.
156
188
  */
@@ -42,6 +42,16 @@ export default class CxPopup extends CortexElement {
42
42
  static styles: CSSResultGroup;
43
43
  private anchorEl;
44
44
  private cleanup;
45
+ /**
46
+ * Set when the element disconnects, cleared when it reconnects.
47
+ *
48
+ * `start()` is debounced, so a pending invocation can still run after
49
+ * `disconnectedCallback()` has already executed `stopImmediate()` — at which
50
+ * point nothing is left to release the `autoUpdate()` listeners it registers
51
+ * on `window`. Checked alongside `isConnected`, which a popup inside a shadow
52
+ * tree that is discarded as a whole can still report as `true`.
53
+ */
54
+ private isTornDown;
45
55
  private readonly localize;
46
56
  /** A reference to the internal popup container. Useful for animating and styling the popup with JavaScript. */
47
57
  popup: HTMLElement;
@@ -172,6 +182,7 @@ export default class CxPopup extends CortexElement {
172
182
  */
173
183
  autoWidthFactor: number;
174
184
  private get isSizeMiddleWareUsed();
185
+ connectedCallback(): void;
175
186
  disconnectedCallback(): void;
176
187
  connectedUpdatedCallback(): void;
177
188
  updated(changedProps: Map<string, unknown>): Promise<void>;
@@ -68,6 +68,13 @@ export default class CxSelect extends CortexElement implements CortexFormControl
68
68
  private readonly localize;
69
69
  private typeToSelectString;
70
70
  private closeWatcher;
71
+ /**
72
+ * The root node the `focusin` listener was attached to, captured at attach
73
+ * time. `getRootNode()` returns a different node once the element is
74
+ * detached, so re-calling it during cleanup would fail to remove the
75
+ * listener that was actually added.
76
+ */
77
+ private openListenersRoot;
71
78
  popup: CxPopup;
72
79
  combobox: HTMLSlotElement;
73
80
  displayInput: HTMLInputElement;
@@ -310,6 +317,7 @@ export default class CxSelect extends CortexElement implements CortexFormControl
310
317
  */
311
318
  filterCallback(option: HTMLElement, value: string): boolean;
312
319
  connectedCallback(): void;
320
+ disconnectedCallback(): void;
313
321
  runFirstUpdated(): void;
314
322
  private addOpenListeners;
315
323
  private removeOpenListeners;
@@ -2,6 +2,8 @@ import { Transformation } from '../../types/src/asset-link-format';
2
2
 
3
3
  export type CxAssetTransformationDialogConfirmEvent = CustomEvent<{
4
4
  format: string;
5
+ /** False when the format follows the asset's file extension instead of an explicit pick. */
6
+ manualFormat: boolean;
5
7
  transformations: Transformation[];
6
8
  }>;
7
9
  declare global {
@@ -28,7 +28,6 @@ export default class CxCropper extends CortexElement {
28
28
  image: {
29
29
  extension: string;
30
30
  height: number;
31
- originalUrl: string;
32
31
  rotation: number;
33
32
  url: string;
34
33
  width: number;
@@ -17,7 +17,6 @@ type Props = {
17
17
  image: {
18
18
  extension: string;
19
19
  height: number;
20
- originalUrl: string;
21
20
  rotation: number;
22
21
  url: string;
23
22
  width: number;
@@ -85,6 +85,16 @@ export default class CxGalleryItem extends HighlightableElement {
85
85
  * The source of the image.
86
86
  */
87
87
  src: string | undefined;
88
+ /**
89
+ * Candidate sources forwarded to the inner `<cx-image>` as a standard `srcset` value,
90
+ * so the browser downloads and decodes only the pixels the grid cell needs.
91
+ */
92
+ srcset: string;
93
+ /**
94
+ * The rendered width forwarded to the inner `<cx-image>` as `sizes` (e.g. `"400px"`).
95
+ * Only meaningful together with `srcset`.
96
+ */
97
+ sizes: string;
88
98
  /**
89
99
  * The alt text for the image.
90
100
  */
@@ -59,6 +59,19 @@ export default class CxMasonry extends CortexElement {
59
59
  * The key to use for the id of the items in the masonry layout.
60
60
  */
61
61
  idKey: keyof MasonryItem;
62
+ /**
63
+ * The proxy format the item images were resolved with.
64
+ *
65
+ * Only used to decide whether a `srcset` may be generated: an original-file format
66
+ * paired with an animated source must be delivered untouched.
67
+ */
68
+ format: string;
69
+ /**
70
+ * Whether `format` was picked by hand. When false each item's format follows its own
71
+ * file extension instead, so a mixed list can serve animated originals and resizable
72
+ * raster proxies side by side.
73
+ */
74
+ manualFormat: boolean;
62
75
  /**
63
76
  * When true, forwards `no-crossorigin` to each inner `<cx-image>`, disabling CORS mode
64
77
  * (e.g. in Site Builder contexts where CORS headers are absent).
@@ -81,6 +94,17 @@ export default class CxMasonry extends CortexElement {
81
94
  handleSortableChange(): void;
82
95
  connectedUpdatedCallback(): void;
83
96
  disconnectedCallback(): void;
97
+ /**
98
+ * The `sizes` hint for item images, expressed as a viewport fraction.
99
+ *
100
+ * The layout is CSS-column based, so no exact pixel width is available the way a
101
+ * measured grid provides one. Each item spans exactly one of `cols` columns, which
102
+ * makes the fraction an accurate upper bound and keeps the browser from assuming
103
+ * the default `100vw`.
104
+ */
105
+ private get itemSizes();
106
+ /** The format one item is served under: the configured one, or derived from its extension. */
107
+ private resolveItemFormat;
84
108
  handleItemClick(event: MouseEvent, item: MasonryItem): void;
85
109
  handleSortableUpdate(event: Sortable.SortableEvent): void;
86
110
  renderActions(item: MasonryItem): import('lit').TemplateResult<1>;
@@ -111,6 +111,18 @@ export default class CxAssetLinkFormat extends CortexElement {
111
111
  * This is a string that represents the ID of the selected proxy format from the list of available proxies.
112
112
  */
113
113
  defaultProxy: string;
114
+ /**
115
+ * Whether the format listbox offers an `Auto` entry, which derives the proxy from the
116
+ * asset's file extension instead of the author naming one.
117
+ */
118
+ canAutoFormat: boolean;
119
+ /**
120
+ * Whether `Auto` is the current choice.
121
+ *
122
+ * Tracked next to `selectedProxy` rather than encoded into it, so `selectedProxy` stays
123
+ * a real proxy id for every consumer that reads it — only the origin of that id differs.
124
+ */
125
+ autoFormat: boolean;
114
126
  useCustomExtension: boolean;
115
127
  noMetadata: boolean;
116
128
  noFormat: boolean;
@@ -133,13 +145,12 @@ export default class CxAssetLinkFormat extends CortexElement {
133
145
  activeSetting: string;
134
146
  /**
135
147
  * The currently selected format for the asset link.
136
- * This is an object that contains details about the selected format, such as `extension`, `height`, `keepMetadata`, `originalUrl`, `proxyUrl`, `quality`, `rotation`, `url`, `width`, `x`, and `y`.
148
+ * This is an object that contains details about the selected format, such as `extension`, `height`, `keepMetadata`, `proxyUrl`, `quality`, `rotation`, `url`, `width`, `x`, and `y`.
137
149
  */
138
150
  selectedFormat: {
139
151
  extension: string;
140
152
  height: number;
141
153
  keepMetadata: boolean;
142
- originalUrl: string;
143
154
  quality: number;
144
155
  rotation: number;
145
156
  url: string;
@@ -194,6 +205,10 @@ export default class CxAssetLinkFormat extends CortexElement {
194
205
  private frozenIndex;
195
206
  /** Snapshot saved on Reset to allow one Undo step back to the pre-reset state. */
196
207
  private preResetTransformations;
208
+ /** The `Auto` state saved alongside `preResetTransformations`, restored by the same Undo. */
209
+ private preResetAutoFormat;
210
+ /** The proxy saved alongside `preResetAutoFormat`, so Undo restores the pair together. */
211
+ private preResetSelectedProxy;
197
212
  /** True when there are transformations beyond the frozen index (i.e. user has added new ones). */
198
213
  private get hasUnfrozenTransformations();
199
214
  private apiGetTransformAssetLink;
@@ -319,6 +334,13 @@ export default class CxAssetLinkFormat extends CortexElement {
319
334
  private handleCropperElementChange;
320
335
  private handleCropperSelectorChange;
321
336
  private handleAssetChange;
337
+ /**
338
+ * The proxy id to fall back to when none is set or the current one is not in the list.
339
+ *
340
+ * Under `Auto` the asset's extension decides, so the first proxy in the list is only a
341
+ * last resort — used when the mapped format is not offered for this asset.
342
+ */
343
+ private resolveFallbackProxyId;
322
344
  private handleProxiesChange;
323
345
  handleSelectedProxyChange(oldValue: unknown): Promise<void>;
324
346
  handleLoadingChange(): void;
@@ -332,6 +354,14 @@ export default class CxAssetLinkFormat extends CortexElement {
332
354
  private onCropDragStart;
333
355
  private onDetailsShow;
334
356
  private onDetailsHide;
357
+ /**
358
+ * The proxy id that `Auto` resolves to for the current asset, or `''` when the mapped
359
+ * format is not among the available proxies.
360
+ *
361
+ * `resolveAutoFormat` yields a proxy *name* (`TRX` / `TR1`) while `selectedProxy` holds
362
+ * a proxy *id*, so the name has to be looked up in `proxies` rather than used directly.
363
+ */
364
+ private get autoResolvedProxyId();
335
365
  private onProxyChange;
336
366
  private onCropModeChange;
337
367
  private onCropFocusModeChange;
@@ -347,6 +377,20 @@ export default class CxAssetLinkFormat extends CortexElement {
347
377
  private onMetadataChange;
348
378
  private onExtensionChange;
349
379
  private syncQuality;
380
+ /**
381
+ * Whether there is anything for Reset to undo.
382
+ *
383
+ * Transformations are one way to diverge from the defaults; leaving `Auto` for an
384
+ * explicit format is another, and Reset is what puts that back.
385
+ */
386
+ private get hasResettableState();
387
+ /**
388
+ * Drops the one-step Reset snapshot.
389
+ *
390
+ * Called whenever the user applies a new transformation: at that point Undo means
391
+ * "remove that transformation", not "go back to before the Reset".
392
+ */
393
+ private clearResetSnapshot;
350
394
  private handleUndo;
351
395
  private handleReset;
352
396
  render(): TemplateResult;
@@ -1,5 +1,6 @@
1
1
  import { default as CxButton } from '../../../../../atoms/src/components/button/button.ts';
2
2
  import { default as CxDetails } from '../../../../../atoms/src/components/details/details.ts';
3
+ import { default as CxDivider } from '../../../../../atoms/src/components/divider/divider.ts';
3
4
  import { default as CxIcon } from '../../../../../atoms/src/components/icon/icon.ts';
4
5
  import { default as CxOption } from '../../../../../atoms/src/components/option/option.ts';
5
6
  import { default as CxSelect } from '../../../../../atoms/src/components/select/select.ts';
@@ -9,7 +10,23 @@ import { default as CortexElement } from '../../../../../base/src/cortex-element
9
10
  import { Proxy } from '../../../../../types/src/asset-link-format';
10
11
  import { CSSResultGroup, TemplateResult } from 'lit';
11
12
 
12
- export type CxAssetLinkFormatProxyChangeEvent = CustomEvent<Proxy>;
13
+ /**
14
+ * Listbox value for the `Auto` entry. Not a proxy id — no `Proxy` can ever carry it, so it
15
+ * is safe to distinguish the two cases by comparing against this constant.
16
+ */
17
+ export declare const AUTO_FORMAT_OPTION_VALUE = "auto";
18
+ /**
19
+ * Either a named proxy or the `Auto` choice.
20
+ *
21
+ * `Auto` carries no proxy: this component does not own the asset, so it cannot resolve
22
+ * which format the extension maps to. The parent does that and sets `selectedProxy`.
23
+ */
24
+ export type CxAssetLinkFormatProxyChangeDetail = (Proxy & {
25
+ autoFormat?: false;
26
+ }) | {
27
+ autoFormat: true;
28
+ };
29
+ export type CxAssetLinkFormatProxyChangeEvent = CustomEvent<CxAssetLinkFormatProxyChangeDetail>;
13
30
  /**
14
31
  * @summary The `cx-asset-link-format-proxy` component is used to select a proxy format for an asset link.
15
32
  *
@@ -20,6 +37,7 @@ export default class CxAssetLinkFormatProxy extends CortexElement {
20
37
  static readonly dependencies: {
21
38
  'cx-button': typeof CxButton;
22
39
  'cx-details': typeof CxDetails;
40
+ 'cx-divider': typeof CxDivider;
23
41
  'cx-icon': typeof CxIcon;
24
42
  'cx-option': typeof CxOption;
25
43
  'cx-select': typeof CxSelect;
@@ -50,6 +68,18 @@ export default class CxAssetLinkFormatProxy extends CortexElement {
50
68
  * @default []
51
69
  */
52
70
  items: Proxy[];
71
+ /**
72
+ * Whether the listbox offers an `Auto` entry that derives the format from the asset's
73
+ * file extension instead of naming one.
74
+ * @default false
75
+ */
76
+ canAutoFormat: boolean;
77
+ /**
78
+ * Whether `Auto` is the current choice. Kept separate from `value` so the resolved
79
+ * format stays readable while the listbox still shows `Auto` as selected.
80
+ * @default false
81
+ */
82
+ autoFormat: boolean;
53
83
  /**
54
84
  * The loading state of the component.
55
85
  * This is used to indicate that an operation is in progress, such as applying a new quality value.
@@ -63,6 +93,11 @@ export default class CxAssetLinkFormatProxy extends CortexElement {
63
93
  * @default ''
64
94
  */
65
95
  scopedValue: string;
96
+ /**
97
+ * The listbox value that represents the committed choice: the `Auto` entry when that is
98
+ * active, otherwise the resolved proxy id.
99
+ */
100
+ private get committedValue();
66
101
  handleValueChange(): void;
67
102
  handleOpenChange(): void;
68
103
  private handleProxyChange;
@@ -20,7 +20,7 @@ import { default as CxAssetLinkFormat } from '../asset-link-format/asset-link-fo
20
20
  * `cx-icon-button`. Automatically disabled when `asset-id` is not set.
21
21
  *
22
22
  * @event cx-asset-transformation-dialog-cancel - Emitted when the user closes or cancels the dialog.
23
- * @event {{ detail: { format: string; transformations: Transformation[] } }} cx-asset-transformation-dialog-confirm - Emitted when the user saves, with the selected proxy id and transformation array.
23
+ * @event {{ detail: { format: string; manualFormat: boolean; transformations: Transformation[] } }} cx-asset-transformation-dialog-confirm - Emitted when the user saves, with the resolved proxy id, whether that id was picked by hand rather than derived from the asset extension, and the transformation array.
24
24
  * @event cx-asset-transformation-dialog-delete - Emitted when the user resets the format to its default and clears the saved transformations via the reset button.
25
25
  */
26
26
  export default class CxAssetTransformationDialog extends CortexElement {
@@ -64,6 +64,11 @@ export default class CxAssetTransformationDialog extends CortexElement {
64
64
  format: string;
65
65
  /** The default format to fall back to if the asset has no transformations or selected proxy. */
66
66
  defaultFormat: string;
67
+ /**
68
+ * Whether the author picked the format by hand rather than letting it follow the asset's
69
+ * file extension. `false` (the default) means `Auto`.
70
+ */
71
+ manualFormat: boolean;
67
72
  /** Optional label rendered as the dialog title. Falls back to the localized "Asset format" term. */
68
73
  dialogLabel: string;
69
74
  /** The transformations applied when the user last saved, passed back into cx-asset-link-format on reopen. */
@@ -86,8 +91,21 @@ export default class CxAssetTransformationDialog extends CortexElement {
86
91
  private proxies;
87
92
  /** False while the authorization check is in flight or after it confirms no access. */
88
93
  private canAccess;
94
+ /**
95
+ * Whether the author changed anything away from the block's defaults, which is what the
96
+ * Reset control acts on.
97
+ *
98
+ * `Auto` is the default, so any manual format counts as an edit — including one that
99
+ * happens to resolve to the same proxy as `defaultFormat`. Comparing the codes instead
100
+ * would leave the author no way back to `Auto` from that format.
101
+ */
89
102
  private get hasTransformations();
90
- /** Resolves the selected format code to its proxy label, falling back to the raw code. */
103
+ /**
104
+ * The label shown in the settings row.
105
+ *
106
+ * Under `Auto` the stored format is only what the extension happened to resolve to, so
107
+ * naming it would read as an explicit choice the author never made.
108
+ */
91
109
  private get resolvedFormatLabel();
92
110
  handleAssetIdChange(): Promise<void>;
93
111
  handleCanAccessChange(): void;
@@ -23,6 +23,13 @@ export default class CxBentoGrid extends CortexElement {
23
23
  static readonly styles: CSSResultGroup;
24
24
  /** Minimum scroll delta (px) required to trigger a virtual range update. */
25
25
  private static readonly SCROLL_THRESHOLD;
26
+ /**
27
+ * Longest a row may block the next release while waiting for its images.
28
+ *
29
+ * Bounds the adaptive wait so a hanging request or an image that never fires
30
+ * `load`/`error` cannot stall the remaining rows indefinitely.
31
+ */
32
+ private static readonly ROW_RELEASE_TIMEOUT;
26
33
  static readonly dependencies: {
27
34
  'cx-gallery-item': typeof CxGalleryItem;
28
35
  'cx-tooltip': typeof CxTooltip;
@@ -109,6 +116,31 @@ export default class CxBentoGrid extends CortexElement {
109
116
  * Unloaded slots are approximated as 1×1 items.
110
117
  */
111
118
  totalItems: number;
119
+ /**
120
+ * The proxy format the item images were resolved with.
121
+ *
122
+ * Only used to decide whether a `srcset` may be generated: an original-file format
123
+ * paired with an animated source must be delivered untouched.
124
+ */
125
+ format: string;
126
+ /**
127
+ * Whether `format` was picked by hand. When false each item's format follows its own
128
+ * file extension instead, so a mixed grid can serve animated originals and resizable
129
+ * raster proxies side by side.
130
+ */
131
+ manualFormat: boolean;
132
+ /**
133
+ * Delay in milliseconds between releasing one row of images and the next.
134
+ *
135
+ * Images are held back until their row is released, so the browser opens roughly one
136
+ * row's worth of requests at a time instead of one per rendered item. Each transform
137
+ * URL is an uncached backend render, and enough of them in parallel returns 503.
138
+ *
139
+ * A row also waits for the previous row's images to finish (capped by
140
+ * `ROW_RELEASE_TIMEOUT`), so this is the floor between releases rather than the exact
141
+ * cadence. Set to `0` to disable gating and let every rendered row load immediately.
142
+ */
143
+ rowReleaseDelay: number;
112
144
  /**
113
145
  * The show content type.
114
146
  */
@@ -198,6 +230,29 @@ export default class CxBentoGrid extends CortexElement {
198
230
  private virtualFirst;
199
231
  /** Inclusive index of the last item in the rendered virtual window. */
200
232
  private virtualLast;
233
+ /**
234
+ * Exclusive upper bound of the grid rows whose images are allowed to load.
235
+ *
236
+ * A row's worth of items entering the DOM together makes the browser open that many
237
+ * image requests at once, and each distinct transform URL is an uncached backend
238
+ * render — enough parallelism there returns 503. Releasing one row at a time keeps
239
+ * the request count bounded by the row width instead of the rendered range.
240
+ *
241
+ * `Infinity` disables gating entirely (see `rowReleaseDelay`).
242
+ */
243
+ private releasedRowCount;
244
+ /** Pending timer for the next row release; null when no release is scheduled. */
245
+ private rowReleaseTimer;
246
+ /**
247
+ * Images still loading in the most recently released row, by item index.
248
+ *
249
+ * The next row waits for this to drain so releases track real network progress
250
+ * rather than a fixed cadence, with `ROW_RELEASE_TIMEOUT` as the upper bound so a
251
+ * hanging or broken image cannot stall the rest of the grid.
252
+ */
253
+ private readonly pendingRowImages;
254
+ /** Guards against scheduling a release while one is already in flight. */
255
+ private isRowReleaseScheduled;
201
256
  private isTooltipShown;
202
257
  protected galleryItemTag: string;
203
258
  /**
@@ -249,6 +304,43 @@ export default class CxBentoGrid extends CortexElement {
249
304
  private computeLayout;
250
305
  /** Recalculates which items fall within the current scroll viewport. */
251
306
  private updateActiveRange;
307
+ /**
308
+ * Highest row index currently rendered, or -1 when nothing is rendered.
309
+ *
310
+ * Releases stop here rather than at the dataset's last row so scrolled-away rows are
311
+ * not fetched ahead of the ones the viewer is actually looking at.
312
+ */
313
+ private get lastRenderedRow();
314
+ /**
315
+ * Whether the item at `index` may load its image yet.
316
+ *
317
+ * Items in unreleased rows render their cell and skeleton but receive no `src`, which
318
+ * is what keeps the grid's shape stable while images fill in progressively.
319
+ */
320
+ protected isRowReleased(index: number): boolean;
321
+ /**
322
+ * Marks every rendered item in `row` as awaiting its image, synchronously.
323
+ *
324
+ * Runs in the same tick as the release so `scheduleRowRelease()` sees a non-empty
325
+ * set on its next call. Items without a `src` are skipped: they never fire
326
+ * `cx-load` / `cx-error`, so they would hold the queue open until the timeout.
327
+ */
328
+ private markRowImagesPending;
329
+ /**
330
+ * Clears an item from the in-flight set once its image settles (loaded or failed) and
331
+ * lets the next row through as soon as the row drains.
332
+ */
333
+ private handleItemImageSettled;
334
+ /**
335
+ * Queues the next row release, if one is warranted and not already pending.
336
+ *
337
+ * Waits `rowReleaseDelay` when the previous row has drained, or up to
338
+ * `ROW_RELEASE_TIMEOUT` when it has not, so a stuck image only delays the grid
339
+ * instead of stopping it.
340
+ */
341
+ private scheduleRowRelease;
342
+ /** Clears any pending release and resets the gate back to its initial state. */
343
+ private resetRowRelease;
252
344
  /**
253
345
  * Returns the index of the last item whose rowStart is within maxRows.
254
346
  */
@@ -291,6 +383,15 @@ export default class CxBentoGrid extends CortexElement {
291
383
  * changes on every computeLayout() call, including resize-driven reflows) or
292
384
  * the sync-row-content-height flag itself is toggled.
293
385
  */
386
+ /**
387
+ * Restarts row gating when the dataset shrinks or is replaced wholesale.
388
+ *
389
+ * Row indices refer to a specific layout, so keeping a release count across a new
390
+ * dataset would let its rows load all at once — the burst this gate exists to prevent.
391
+ * A dataset that only grew is treated as an appended page: the already-released rows
392
+ * still hold the same items, so their progress is kept and the new rows queue behind.
393
+ */
394
+ handleDataChangeForRowRelease(oldData?: unknown, newData?: unknown): void;
294
395
  handleRowContentHeightSync(): Promise<void>;
295
396
  /**
296
397
  * Get content position based on the size of the item.
@@ -72,6 +72,19 @@ export default class CxCarousel extends CortexElement {
72
72
  * The real total number of data in the carousel. Not affected by chunking.
73
73
  */
74
74
  totalData: number;
75
+ /**
76
+ * The proxy format the slide images were resolved with.
77
+ *
78
+ * Only used to decide whether a `srcset` may be generated: an original-file format
79
+ * paired with an animated source must be delivered untouched.
80
+ */
81
+ format: string;
82
+ /**
83
+ * Whether `format` was picked by hand. When false each slide's format follows its own
84
+ * file extension instead, so a mixed carousel can serve animated originals and
85
+ * resizable raster proxies side by side.
86
+ */
87
+ manualFormat: boolean;
75
88
  /**
76
89
  * When set, allows the user to navigate the carousel in the same direction indefinitely.
77
90
  */
@@ -257,6 +270,19 @@ export default class CxCarousel extends CortexElement {
257
270
  get selectedCarouselItem(): string;
258
271
  get canMoveCarouselItem(): boolean;
259
272
  get canDeleteCarouselItem(): boolean;
273
+ /**
274
+ * The `sizes` hint for slide images, derived from the slide layout rather than a
275
+ * measured width: the carousel sizes slides purely in CSS, so no pixel width is
276
+ * available at render time.
277
+ *
278
+ * Vertical carousels stack slides, so each one spans the full width regardless of
279
+ * `slidesPerPage` — only the horizontal layout divides the row.
280
+ *
281
+ * This uses the viewport rather than the carousel's own box, so a carousel rendered
282
+ * in a narrow column over-estimates and requests one ladder rung too large. That is
283
+ * still far better than the full-resolution original served without `sizes`.
284
+ */
285
+ private get slideSizes();
260
286
  constructor();
261
287
  connectedUpdatedCallback(): void;
262
288
  runFirstUpdated(): void;