@orangelogic/design-system 2.190.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 (64) hide show
  1. package/library/chunks/{asset-link-format.D--xQVgR.js → asset-link-format.CDd4iPA2.js} +1149 -1001
  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 +22267 -21934
  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/asset-picker/asset-picker.d.ts +20 -1
  33. package/library/packages/molecules/src/cropper/cropper.d.ts +0 -1
  34. package/library/packages/molecules/src/cropper/react/Cropper.d.ts +0 -1
  35. package/library/packages/molecules/src/gallery-item/gallery-item.d.ts +10 -0
  36. package/library/packages/molecules/src/masonry/masonry.d.ts +24 -0
  37. package/library/packages/organisms/src/asset-link-format/asset-link-format.d.ts +46 -2
  38. package/library/packages/organisms/src/asset-link-format/components/asset-link-format-proxy/asset-link-format-proxy.d.ts +36 -1
  39. package/library/packages/organisms/src/asset-transformation-dialog/asset-transformation-dialog.d.ts +20 -2
  40. package/library/packages/organisms/src/bento-grid/bento-grid.d.ts +101 -0
  41. package/library/packages/organisms/src/carousel/carousel.d.ts +26 -0
  42. package/library/packages/organisms/src/content-builder/blocks/image/image.d.ts +65 -1
  43. package/library/packages/organisms/src/content-builder/blocks/video/video.d.ts +5 -0
  44. package/library/packages/organisms/src/content-builder/components/config-form/config-form.d.ts +2 -1
  45. package/library/packages/organisms/src/content-builder/components/gallery-picker/gallery-picker.d.ts +6 -0
  46. package/library/packages/organisms/src/content-builder/configs/carousel.d.ts +1 -0
  47. package/library/packages/organisms/src/content-builder/configs/gallery.d.ts +1 -0
  48. package/library/packages/organisms/src/content-builder/configs/image.d.ts +2 -0
  49. package/library/packages/organisms/src/content-builder/configs/timeline.d.ts +1 -0
  50. package/library/packages/organisms/src/content-builder/configs/video.d.ts +1 -0
  51. package/library/packages/organisms/src/content-builder/configs-controller.d.ts +10 -0
  52. package/library/packages/organisms/src/content-builder/content-builder.d.ts +31 -6
  53. package/library/packages/organisms/src/content-builder/styleController.d.ts +2 -0
  54. package/library/packages/tools/src/fetch-image/fetch-image.d.ts +28 -5
  55. package/library/packages/types/src/asset-link-format.d.ts +0 -1
  56. package/library/packages/types/src/content-builder.d.ts +7 -0
  57. package/library/packages/types/src/gallery-item.d.ts +1 -0
  58. package/library/packages/types/src/masonry.d.ts +1 -0
  59. package/library/packages/utils/src/transformation/transformation.d.ts +91 -0
  60. package/library/react-web-component.d.ts +67 -7
  61. package/library/utils.js +192 -182
  62. package/package.json +1 -1
  63. package/library/chunks/transformation.8uLv6uwG.js +0 -264
  64. package/library/packages/types/src/download-format-picker.d.ts +0 -7
@@ -41,12 +41,13 @@ export default class CxSbImage extends CxImage {
41
41
  'cx-resize-observer': typeof import('../../../../../atoms/src/index.ts').CxResizeObserver;
42
42
  'cx-skeleton': typeof import('../../../../../atoms/src/index.ts').CxSkeleton;
43
43
  'cx-space': typeof import('../../../../../atoms/src/index.ts').CxSpace;
44
- 'cx-spinner': typeof import('../../../../../atoms/src/index.ts').CxSpinner;
45
44
  };
46
45
  /**
47
46
  * Override the default behavior of retrying to load the image when it fails to load.
48
47
  */
49
48
  retryOnError: boolean;
49
+ /** Content-builder images keep their measured box visible while the asset loads. */
50
+ skeleton: boolean;
50
51
  /**
51
52
  * The path to the image to load in dark mode.
52
53
  */
@@ -87,6 +88,14 @@ export default class CxSbImage extends CxImage {
87
88
  * Asset transformation proxy format key for dark mode.
88
89
  */
89
90
  formatDarkMode: string;
91
+ /**
92
+ * Whether `format` was picked by hand. When false the format follows the asset's file
93
+ * extension instead, so an animated GIF keeps its original file and everything else
94
+ * takes the transcoded raster proxy that `srcset` is allowed to resize.
95
+ */
96
+ manualFormat: boolean;
97
+ /** Whether `formatDarkMode` was picked by hand. See `manualFormat`. */
98
+ manualFormatDarkMode: boolean;
90
99
  /**
91
100
  * Asset transformations applied to the image.
92
101
  */
@@ -162,6 +171,20 @@ export default class CxSbImage extends CxImage {
162
171
  private resolvedSrc;
163
172
  /** Fresh URL re-resolved when the stored `srcDarkMode` has expired. */
164
173
  private resolvedSrcDarkMode;
174
+ /**
175
+ * The asset's file extension. Lets an animated GIF opt out of `srcset`, which a
176
+ * server-side resize would flatten to a still frame.
177
+ */
178
+ private assetExtension;
179
+ /**
180
+ * Whether an asset fetch has reported back for the current record.
181
+ *
182
+ * Tracked separately from `assetExtension` because "no extension" is a legitimate
183
+ * answer — a missing asset or a record without the field both yield an empty string.
184
+ * Gating on the empty string alone would hold `srcset` back forever in those cases;
185
+ * gating on this flag releases it as soon as the answer is in, whatever it says.
186
+ */
187
+ private hasResolvedAssetExtension;
165
188
  /**
166
189
  * Space list supplied by `cx-content-builder-viewer`, which fetches it once per
167
190
  * surface. The only source — this block never fetches the list itself.
@@ -192,6 +215,24 @@ export default class CxSbImage extends CxImage {
192
215
  get currentRecordId(): string;
193
216
  get currentSrc(): string;
194
217
  get currentTransformations(): Transformation[];
218
+ /** Whether the variant being displayed had its format picked by hand. */
219
+ get isCurrentFormatManual(): boolean;
220
+ /**
221
+ * The proxy format of the variant actually being displayed.
222
+ *
223
+ * Under `Auto` the asset's extension decides, so this stays a real proxy name and every
224
+ * consumer — the transformation URL and `srcset` alike — reads the same resolved value.
225
+ */
226
+ get currentFormat(): string;
227
+ /**
228
+ * Fields the child `cx-asset-data-display` must fetch for this block.
229
+ *
230
+ * The extension is always requested rather than only for the format that can serve
231
+ * an animated original. Requesting it unconditionally keeps the fetch shape stable
232
+ * (it does not change when the author switches format) and means `srcset` never has
233
+ * to wait on a follow-up fetch to learn whether this asset may be resized.
234
+ */
235
+ private get requestedAssetFields();
195
236
  get highlighterTabindex(): "0" | undefined;
196
237
  get highlighterRole(): "button" | "img";
197
238
  get highlighterClass(): {
@@ -214,10 +255,25 @@ export default class CxSbImage extends CxImage {
214
255
  * Whether the image has an click action.
215
256
  */
216
257
  private get hasClickAction();
258
+ /**
259
+ * The rendered width in CSS pixels, used as the `sizes` hint so the browser can pick
260
+ * the smallest `srcset` candidate that still covers the box.
261
+ *
262
+ * A `%` width carries no pixel value, so the measured `clientWidth` is used instead.
263
+ * Returns 0 when neither is known yet (before first layout), which makes the caller
264
+ * omit `sizes` and fall back to the browser's default `100vw` assumption.
265
+ */
266
+ private get displayWidth();
217
267
  handleClickActionChange(): Promise<void>;
218
268
  handleClickSpaceChange(): void;
219
269
  handleObjectFitChange(): Promise<void>;
220
270
  handleSrcChange(): void;
271
+ /**
272
+ * Drops a cached extension once the asset it described is replaced, so a new record
273
+ * cannot inherit the previous one's answer about whether it may be resized — nor its
274
+ * resolved flag, which would let `srcset` be built before the new answer arrives.
275
+ */
276
+ handleRecordIdChangeForExtension(): void;
221
277
  handleFetchedAssetDataChange(): void;
222
278
  /**
223
279
  * Support CMS5 click action for the image.
@@ -230,6 +286,14 @@ export default class CxSbImage extends CxImage {
230
286
  * own `cx-asset-data-display` fetch) into alt text and overlay content.
231
287
  */
232
288
  private applyFetchedAssetData;
289
+ /**
290
+ * Captures the asset's extension from a fetch result and marks the answer as in.
291
+ *
292
+ * A blank value leaves any previously known extension in place — a response that
293
+ * omitted the field says nothing about the asset — but still resolves the wait, so a
294
+ * record whose extension never arrives does not block `srcset` indefinitely.
295
+ */
296
+ private applyExtensionFromAssetData;
233
297
  /**
234
298
  * A stored space URL breaks once the space moves domain, so the link target is
235
299
  * re-resolved against the list the viewer supplies. Without that list the stored
@@ -72,6 +72,11 @@ export default class CxSbVideo extends CxVideo {
72
72
  * Thumbnail proxy format key (e.g. "webp", "jpg").
73
73
  */
74
74
  thumbnailFormat: string;
75
+ /**
76
+ * Whether `thumbnailFormat` was picked by hand. When false the thumbnail's format
77
+ * follows the poster asset's file extension instead.
78
+ */
79
+ manualThumbnailFormat: boolean;
75
80
  /**
76
81
  * Transformations applied to the thumbnail image.
77
82
  */
@@ -27,7 +27,6 @@ import { default as CxTooltip } from '../../../../../atoms/src/components/toolti
27
27
  import { default as CxTypography } from '../../../../../atoms/src/components/typography/typography.ts';
28
28
  import { default as CxVisuallyHidden } from '../../../../../atoms/src/components/visually-hidden/visually-hidden.ts';
29
29
  import { default as CortexElement } from '../../../../../base/src/cortex-element.ts';
30
- import { CxFontPicker, CxIconPicker } from '../../../../../molecules/src/index.ts';
31
30
  import { default as CxAssetFormatPicker } from '../../../../../molecules/src/asset-format-picker/asset-format-picker.ts';
32
31
  import { default as CxAssetPicker } from '../../../../../molecules/src/asset-picker/asset-picker.ts';
33
32
  import { default as CxBicolorPicker } from '../../../../../molecules/src/bicolor-picker/bicolor-picker.ts';
@@ -36,6 +35,8 @@ import { default as CxConfirmPopover } from '../../../../../molecules/src/confir
36
35
  import { default as CxCornerPositionInputGroup } from '../../../../../molecules/src/corner-position-input-group/corner-position-input-group.ts';
37
36
  import { default as CxDownloadFormatPicker } from '../../../../../molecules/src/download-format-picker/download-format-picker.ts';
38
37
  import { default as CxDynamicSelect } from '../../../../../molecules/src/dynamic-select/dynamic-select.ts';
38
+ import { default as CxFontPicker } from '../../../../../molecules/src/font-picker/font-picker.ts';
39
+ import { default as CxIconPicker } from '../../../../../molecules/src/icon-picker/icon-picker.ts';
39
40
  import { default as CxPaddingInputGroup } from '../../../../../molecules/src/padding-input-group/padding-input-group.ts';
40
41
  import { default as CxPositionPicker } from '../../../../../molecules/src/position-picker/position-picker.ts';
41
42
  import { default as CxShadowInputGroup } from '../../../../../molecules/src/shadow-input-group/shadow-input-group.ts';
@@ -55,6 +55,11 @@ export default class CxGalleryPicker extends CortexElement implements CortexForm
55
55
  * The asset format code used to resolve image src URLs.
56
56
  */
57
57
  format: string;
58
+ /**
59
+ * Whether `format` was picked by hand. When false each item's format follows its own
60
+ * file extension instead.
61
+ */
62
+ manualFormat: boolean;
58
63
  /**
59
64
  * The boundary property of the confirm popover's dropdown/dialog popup.
60
65
  */
@@ -69,6 +74,7 @@ export default class CxGalleryPicker extends CortexElement implements CortexForm
69
74
  loading: boolean;
70
75
  masonryData: Array<{
71
76
  alt?: string;
77
+ extension?: string;
72
78
  id: string;
73
79
  rawId?: string;
74
80
  src?: string;
@@ -27,6 +27,7 @@ type Attributes = {
27
27
  'highlight-drop-shadow': boolean;
28
28
  'item-height': string;
29
29
  loop: boolean;
30
+ 'manual-format'?: boolean;
30
31
  navigation: string;
31
32
  orientation: string;
32
33
  'peek-slides': boolean;
@@ -29,6 +29,7 @@ type Attribute = {
29
29
  'highlight-siblings-fade-out': boolean;
30
30
  'item-height': string;
31
31
  'large-content-position': GalleryItemContentPosition;
32
+ 'manual-format'?: boolean;
32
33
  'max-rows': string;
33
34
  navigation: 'both' | 'arrows' | 'pagination';
34
35
  orientation: Orientation;
@@ -32,6 +32,8 @@ type Attribute = {
32
32
  'highlight-border'?: CxImage['highlightBorder'];
33
33
  'highlight-color-overlay'?: CxImage['highlightColorOverlay'];
34
34
  'highlight-drop-shadow'?: CxImage['highlightDropShadow'];
35
+ 'manual-format'?: CxImage['manualFormat'];
36
+ 'manual-format-dark-mode'?: CxImage['manualFormatDarkMode'];
35
37
  'object-fit': CxImage['objectFit'];
36
38
  'open-in-new-tab'?: CxImage['openInNewTab'];
37
39
  'page-url'?: CxImage['pageUrl'];
@@ -4,6 +4,7 @@ import { LocalizeController } from '../../../../utils/src/custom-element/i18n';
4
4
  type Attributes = {
5
5
  data: string;
6
6
  format: string;
7
+ 'manual-format'?: boolean;
7
8
  'min-tab-width': string;
8
9
  'multi-language': boolean;
9
10
  'navigation-arrows': boolean;
@@ -30,6 +30,7 @@ type Attribute = {
30
30
  height: CxVideo['height'];
31
31
  'height-mode': CxVideo['heightMode'];
32
32
  loop: CxVideo['loop'];
33
+ 'manual-thumbnail-format'?: boolean;
33
34
  name: CxVideo['name'];
34
35
  'name-source-field': CxVideo['nameSourceField'];
35
36
  'open-in-new-tab'?: CxVideo['openInNewTab'];
@@ -70,6 +70,7 @@ export default class ConfigsController {
70
70
  'highlight-drop-shadow': boolean;
71
71
  'item-height': string;
72
72
  loop: boolean;
73
+ 'manual-format'?: boolean;
73
74
  navigation: string;
74
75
  orientation: string;
75
76
  'peek-slides': boolean;
@@ -204,6 +205,7 @@ export default class ConfigsController {
204
205
  'highlight-siblings-fade-out': boolean;
205
206
  'item-height': string;
206
207
  'large-content-position': import('../../../types/src/highlightable-element').HighlightableElementContentPosition;
208
+ 'manual-format'?: boolean;
207
209
  'max-rows': string;
208
210
  navigation: "both" | "arrows" | "pagination";
209
211
  orientation: import('../../../types/src/index.ts').Orientation;
@@ -264,6 +266,8 @@ export default class ConfigsController {
264
266
  'highlight-border'?: import('./blocks/image/image').default["highlightBorder"];
265
267
  'highlight-color-overlay'?: import('./blocks/image/image').default["highlightColorOverlay"];
266
268
  'highlight-drop-shadow'?: import('./blocks/image/image').default["highlightDropShadow"];
269
+ 'manual-format'?: import('./blocks/image/image').default["manualFormat"];
270
+ 'manual-format-dark-mode'?: import('./blocks/image/image').default["manualFormatDarkMode"];
267
271
  'object-fit': import('./blocks/image/image').default["objectFit"];
268
272
  'open-in-new-tab'?: import('./blocks/image/image').default["openInNewTab"];
269
273
  'page-url'?: import('./blocks/image/image').default["pageUrl"];
@@ -299,6 +303,7 @@ export default class ConfigsController {
299
303
  }>[] | import('../../../types/src/content-builder').PropertyConfig<{
300
304
  data: string;
301
305
  format: string;
306
+ 'manual-format'?: boolean;
302
307
  'min-tab-width': string;
303
308
  'multi-language': boolean;
304
309
  'navigation-arrows': boolean;
@@ -332,6 +337,7 @@ export default class ConfigsController {
332
337
  height: import('./blocks/video/video').default["height"];
333
338
  'height-mode': import('./blocks/video/video').default["heightMode"];
334
339
  loop: import('./blocks/video/video').default["loop"];
340
+ 'manual-thumbnail-format'?: boolean;
335
341
  name: import('./blocks/video/video').default["name"];
336
342
  'name-source-field': import('./blocks/video/video').default["nameSourceField"];
337
343
  'open-in-new-tab'?: import('./blocks/video/video').default["openInNewTab"];
@@ -412,6 +418,7 @@ export default class ConfigsController {
412
418
  'highlight-drop-shadow': boolean;
413
419
  'item-height': string;
414
420
  loop: boolean;
421
+ 'manual-format'?: boolean;
415
422
  navigation: string;
416
423
  orientation: string;
417
424
  'peek-slides': boolean;
@@ -543,6 +550,7 @@ export default class ConfigsController {
543
550
  'highlight-siblings-fade-out': boolean;
544
551
  'item-height': string;
545
552
  'large-content-position': import('../../../types/src/highlightable-element').HighlightableElementContentPosition;
553
+ 'manual-format'?: boolean;
546
554
  'max-rows': string;
547
555
  navigation: "both" | "arrows" | "pagination";
548
556
  orientation: import('../../../types/src/index.ts').Orientation;
@@ -575,6 +583,7 @@ export default class ConfigsController {
575
583
  } | {
576
584
  data: string;
577
585
  format: string;
586
+ 'manual-format'?: boolean;
578
587
  'min-tab-width': string;
579
588
  'multi-language': boolean;
580
589
  'navigation-arrows': boolean;
@@ -608,6 +617,7 @@ export default class ConfigsController {
608
617
  height: import('./blocks/video/video').default["height"];
609
618
  'height-mode': import('./blocks/video/video').default["heightMode"];
610
619
  loop: import('./blocks/video/video').default["loop"];
620
+ 'manual-thumbnail-format'?: boolean;
611
621
  name: import('./blocks/video/video').default["name"];
612
622
  'name-source-field': import('./blocks/video/video').default["nameSourceField"];
613
623
  'open-in-new-tab'?: import('./blocks/video/video').default["openInNewTab"];
@@ -5,7 +5,7 @@ import { default as CxSpinner } from '../../../atoms/src/components/spinner/spin
5
5
  import { default as CortexElement } from '../../../base/src/cortex-element.ts';
6
6
  import { AssetFormatValue } from '../../../types/src/asset-format-picker';
7
7
  import { Asset, AssetTypeString, Device, EditorMode, TeamSpaceRole } from '../../../types/src/content-builder';
8
- import { Component, Editor, StyleProps } from 'grapesjs';
8
+ import { Component, Editor } from 'grapesjs';
9
9
  import { TemplateResult } from 'lit';
10
10
  import { CxBlockPicker } from './components/block-picker';
11
11
  import { CxConfigManager } from './components/config-manager';
@@ -326,6 +326,35 @@ export default class CxContentBuilder extends CortexElement {
326
326
  private handleCanvasScroll;
327
327
  private handleHorizontalScroll;
328
328
  private handleRootToolbarRightClick;
329
+ /**
330
+ * Re-applies the toolbar position GrapesJS computed, clamped to the visible
331
+ * canvas so the toolbar never gets clipped.
332
+ *
333
+ * `getTargetToElementFixed` derives `left` from `elRect.width - toolbarWidth`
334
+ * (right-aligned to the selected element) and clamps it with
335
+ * `canvasLiftLimit`, which is measured against the frame rather than the
336
+ * visible canvas viewport. On an element near the left edge of the visible
337
+ * area that limit still allows a negative offset, so the toolbar overflows
338
+ * past the canvas and gets clipped. Clamping against the real canvas box
339
+ * turns that case into left-alignment.
340
+ *
341
+ * Both `left` and `top` are relative to the tools wrapper, which GrapesJS
342
+ * sizes to the selected element's box — hence the wrapper-to-canvas delta.
343
+ *
344
+ * Values are written with `important` so stylesheet rules on `.gjs-toolbar`
345
+ * cannot override the computed placement.
346
+ */
347
+ private clampToolbarPosition;
348
+ /**
349
+ * Wraps `updateToolbarPos` so the toolbar position is re-applied after
350
+ * GrapesJS writes its own inline position.
351
+ *
352
+ * `updateToolbarPos` lives on the `select-comp` command (GrapesJS'
353
+ * `SelectComponent`), which owns the component toolbar / badge / highlight
354
+ * boxes — not on `CanvasView`. It is absent from the published `grapesjs`
355
+ * typings, so the command is narrowed through a local structural type.
356
+ */
357
+ private patchToolbarPositioning;
329
358
  private handleCanvasClick;
330
359
  private handleCanvasKeydown;
331
360
  private handleTemplateManagerUpdated;
@@ -388,11 +417,7 @@ export default class CxContentBuilder extends CortexElement {
388
417
  * @param components - The components to be updated in the component.
389
418
  * @param styleProps - The style properties to be set for the component.
390
419
  */
391
- updateComponent(component: Component, { attributes, properties, styleProps, }: {
392
- attributes?: Record<string, string>;
393
- properties?: Record<string, unknown>;
394
- styleProps?: StyleProps;
395
- }): void;
420
+ private updateComponent;
396
421
  private handleOtherChange;
397
422
  private handleMouseMove;
398
423
  private getScrollableElements;
@@ -59,6 +59,7 @@ export default class StyleController {
59
59
  defaultFormat?: string;
60
60
  dialogLabel?: string;
61
61
  formatKey?: string;
62
+ manualFormatKey?: string;
62
63
  multiple?: boolean;
63
64
  noCrop?: boolean;
64
65
  noResize?: boolean;
@@ -102,6 +103,7 @@ export default class StyleController {
102
103
  galleryPickerConfigs?: {
103
104
  dialog: import('../../../types/src/content-builder').DialogType;
104
105
  formatKey?: string;
106
+ manualFormatKey?: string;
105
107
  transformationRecordIdKey?: string;
106
108
  transformationsKey?: string;
107
109
  };
@@ -28,46 +28,69 @@ export declare class FetchImageController implements ReactiveController {
28
28
  constructor(host: ReactiveElement, options?: FetchImageControllerOptions);
29
29
  get totalDataCount(): number;
30
30
  setSecurityByPassToken(token: string | undefined): void;
31
- fetchImages({ end, extraFields, format, start, transformations, }: {
31
+ /**
32
+ * Changes how many items each request asks for.
33
+ *
34
+ * A new size moves every page boundary, so cached pages are dropped and the next fetch
35
+ * starts from page 1. `data` is kept — it is indexed absolutely, so the refetch
36
+ * overwrites in place instead of blanking the grid.
37
+ *
38
+ * Shrinking is ignored once pages are cached: collapsing already has what it needs.
39
+ */
40
+ setPageSize(pageSize: number): void;
41
+ fetchImages({ end, extraFields, format, manualFormat, start, transformations, }: {
32
42
  end: number;
33
43
  extraFields: string[];
34
44
  format?: string;
45
+ /**
46
+ * When false, `format` is ignored and each item resolves its own from its file
47
+ * extension. Defaults to true so existing callers keep their explicit format.
48
+ */
49
+ manualFormat?: boolean;
35
50
  start: number;
36
51
  transformations?: Transformation[];
37
52
  }): Promise<ExtendedGalleryItem[] | undefined>;
38
- fetchImagesInFolderBySlide({ activeSlide, extraFields, folderId, forceRefetch, format, minLimit, noPlaceholders, transformations, }: {
53
+ fetchImagesInFolderBySlide({ activeSlide, extraFields, folderId, forceRefetch, format, manualFormat, minLimit, noPlaceholders, transformations, }: {
39
54
  activeSlide: number;
40
55
  extraFields?: string[];
41
56
  folderId: string;
42
57
  forceRefetch?: boolean;
43
58
  format?: string;
59
+ manualFormat?: boolean;
44
60
  minLimit?: number;
45
61
  noPlaceholders?: boolean;
46
62
  transformations?: Transformation[];
47
63
  }): Promise<ExtendedGalleryItem[]>;
48
- fetchImagesByIDs({ extraFields, format, recordIds, transformations, }: {
64
+ fetchImagesByIDs({ extraFields, format, manualFormat, recordIds, transformations, }: {
49
65
  extraFields?: string[];
50
66
  format?: string;
67
+ /**
68
+ * When false, `format` is ignored and each item resolves its own from its file
69
+ * extension. Defaults to true so existing callers keep their explicit format.
70
+ */
71
+ manualFormat?: boolean;
51
72
  recordIds: string[];
52
73
  transformations?: Transformation[];
53
74
  }): Promise<ExtendedGalleryItem[]>;
54
- fetchImagesInFolderByPage({ extraFields, folderId, forceRefetch, format, noPlaceholders, page, pageSize, transformations, }: {
75
+ fetchImagesInFolderByPage({ extraFields, folderId, forceRefetch, format, manualFormat, noPlaceholders, page, pageSize, transformations, }: {
55
76
  extraFields?: string[];
56
77
  folderId: string;
57
78
  forceRefetch?: boolean;
58
79
  format?: string;
80
+ manualFormat?: boolean;
59
81
  noPlaceholders?: boolean;
60
82
  page: number;
61
83
  pageSize?: number;
62
84
  transformations?: Transformation[];
63
85
  }): Promise<ExtendedGalleryItem[]>;
64
- fetchImagesInFolderByChunk({ chunkSize: rawChunkSize, end, extraFields, folderId, forceRefetch, format, start, transformations, }: {
86
+ fetchImagesInFolderByChunk({ chunkSize: rawChunkSize, end, extraFields, folderId, forceRefetch, format, manualFormat, start, transformations, }: {
65
87
  chunkSize?: number;
66
88
  end?: number;
67
89
  extraFields?: string[];
68
90
  folderId: string;
69
91
  forceRefetch?: boolean;
70
92
  format?: string;
93
+ manualFormat?: boolean;
71
94
  start?: number;
72
95
  transformations?: Transformation[];
73
96
  }): AsyncGenerator<ExtendedGalleryItem[], void, unknown>;
@@ -58,7 +58,6 @@ export type Asset = {
58
58
  identifier: string;
59
59
  imageUrl: string;
60
60
  name: string;
61
- originalUrl: string;
62
61
  scrubUrl: string;
63
62
  size: string;
64
63
  tags: string;
@@ -64,6 +64,11 @@ export type PropertyConfig<T = Record<string, any>> = Omit<TraitProperties, 'opt
64
64
  defaultFormat?: string;
65
65
  dialogLabel?: string;
66
66
  formatKey?: string;
67
+ /**
68
+ * The block-attribute key that records whether the format was picked by hand. When
69
+ * absent or false the format follows the asset's file extension.
70
+ */
71
+ manualFormatKey?: string;
67
72
  multiple?: boolean;
68
73
  noCrop?: boolean;
69
74
  noResize?: boolean;
@@ -114,6 +119,8 @@ export type PropertyConfig<T = Record<string, any>> = Omit<TraitProperties, 'opt
114
119
  dialog: DialogType;
115
120
  /** The block-attribute key for the format used to resolve records' src URLs after picking. */
116
121
  formatKey?: string;
122
+ /** The block-attribute key recording whether that format was picked by hand. */
123
+ manualFormatKey?: string;
117
124
  transformationRecordIdKey?: string;
118
125
  transformationsKey?: string;
119
126
  };
@@ -25,6 +25,7 @@ export type GalleryItem = {
25
25
  className?: string;
26
26
  details?: string;
27
27
  docType?: MediaType | '';
28
+ extension?: string;
28
29
  filler?: boolean;
29
30
  header?: string;
30
31
  id: string;
@@ -6,6 +6,7 @@ export declare enum MasonryVariant {
6
6
  }
7
7
  export type MasonryItem = {
8
8
  alt?: string;
9
+ extension?: string;
9
10
  hasError?: boolean;
10
11
  id: string;
11
12
  loading?: boolean;
@@ -1,5 +1,12 @@
1
1
  import { Asset, Parameter, Transformation } from '../../../types/src/asset-link-format';
2
2
 
3
+ /**
4
+ * Width ladder used for `srcset` candidates, in CSS pixels.
5
+ *
6
+ * Kept as a small fixed ladder rather than a per-item computed width so that many
7
+ * items sharing a display size resolve to the same URLs and stay CDN-cache friendly.
8
+ */
9
+ export declare const SRCSET_WIDTH_LADDER: readonly [400, 800, 1200, 1600, 2400];
3
10
  export declare function buildTransformationString({ asset, baseUrl, extension, options, parameters, transformations, useSession, }: {
4
11
  asset?: Asset;
5
12
  baseUrl?: string;
@@ -19,3 +26,87 @@ export declare function buildTransformationString({ asset, baseUrl, extension, o
19
26
  * and merged into an existing `/t/`. Other URLs keep the plain append behavior.
20
27
  */
21
28
  export declare function applyTransformationsToUrl(url: string, transformations: Transformation[]): string;
29
+ /**
30
+ * Inserts a width-only resize into an asset-link URL, preserving any transformations
31
+ * already present.
32
+ *
33
+ * `applyTransformationsToUrl` is deliberately not reused here: it *replaces* an existing
34
+ * `/t/` segment (dropping a configured crop/rotate/quality) and drops the prettyName tail
35
+ * when doing so. This function prepends the resize to an existing segment instead, so a
36
+ * user's configured transformations survive.
37
+ *
38
+ * Returns the URL unchanged when it is not an asset-link URL, so arbitrary external
39
+ * sources are never rewritten.
40
+ */
41
+ export declare function applyWidthToAssetUrl(url: string, width: number): string;
42
+ /**
43
+ * Whether the URL already carries a transformation segment.
44
+ *
45
+ * An existing `/t/` means a width was already chosen deliberately (a configured resize,
46
+ * crop or proxy format), so a ladder must not add a competing one.
47
+ */
48
+ export declare function hasTransformSegment(url: string): boolean;
49
+ /** Proxy format that is always transcoded to a raster image, whatever the source file is. */
50
+ export declare const AUTO_FALLBACK_FORMAT = "TR1";
51
+ /**
52
+ * Largest original file `Auto` will serve untouched, in bytes.
53
+ *
54
+ * Past this the transcoded proxy wins even for extensions that would normally keep their
55
+ * original: delivering a very large original costs the viewer more than the animation or
56
+ * alpha it preserves.
57
+ */
58
+ export declare const AUTO_ORIGINAL_FORMAT_MAX_BYTES: number;
59
+ /**
60
+ * Reads an asset file size into bytes, or `undefined` when the value says nothing usable.
61
+ *
62
+ * `CoreField.FileSize` is typed as a string and has been observed both as a plain byte
63
+ * count (`'1024'`) and as a formatted value (`'63.47 KB'`), so both are accepted. A bare
64
+ * number is read as bytes, matching the raw form.
65
+ *
66
+ * Returns `undefined` rather than `0` for unusable input so callers can tell "no size
67
+ * reported" apart from "genuinely empty file" — the two lead to different decisions.
68
+ */
69
+ export declare function parseFileSizeToBytes(size: string | number | null | undefined): number | undefined;
70
+ /**
71
+ * Picks the proxy format an asset should be served under when the author chose `Auto`
72
+ * instead of naming a format.
73
+ *
74
+ * Extensions that would lose something to a transcode (animation, alpha, bit depth) take
75
+ * the original-file proxy, but only up to `AUTO_ORIGINAL_FORMAT_MAX_BYTES`; everything
76
+ * else takes the transcoded raster proxy, which is the one `buildAssetSrcset` may resize.
77
+ *
78
+ * An unknown or missing extension resolves to the raster proxy — the safe default for the
79
+ * majority of assets, and the same value the format ladders already fall back to.
80
+ *
81
+ * An unknown *size* does not: a size the API did not report is treated as within the
82
+ * limit, so a missing field never silently strips a GIF of its animation.
83
+ */
84
+ export declare function resolveAutoFormat(extension: string | null | undefined, size?: string | number | null): string;
85
+ /**
86
+ * Builds a `srcset` value for an asset-link URL by emitting one width-only resize
87
+ * candidate per ladder entry, letting the browser fetch and decode only the pixels
88
+ * the layout actually needs.
89
+ *
90
+ * Candidates wider than `maxWidth` are dropped so the backend is never asked to
91
+ * upscale past the asset's real dimensions. When `maxWidth` falls below the whole
92
+ * ladder, the smallest candidate is still emitted so a `srcset` is always produced
93
+ * for an eligible URL.
94
+ *
95
+ * Returns an empty string when the URL is not an asset link, when it already carries
96
+ * a transformation (the width was configured upstream), or when it is an animated GIF
97
+ * served as the original file — resizing that flattens it to a still frame, so the
98
+ * original has to be delivered untouched.
99
+ */
100
+ export declare function buildAssetSrcset(url: string, options?: {
101
+ extension?: string | null;
102
+ format?: string;
103
+ maxWidth?: number;
104
+ widths?: readonly number[];
105
+ }): string;
106
+ /**
107
+ * Builds a `sizes` value from a known display width in CSS pixels.
108
+ *
109
+ * Rounded up to `step` so small layout changes (a resize that shifts a grid cell by a
110
+ * few pixels) do not produce a new value on every frame.
111
+ */
112
+ export declare function buildSizesFromDisplayWidth(displayWidth: number, step?: number): string;