@taprootio/espalier 6.1.0 → 6.2.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.
@@ -19461,87 +19461,71 @@
19461
19461
  },
19462
19462
  {
19463
19463
  "kind": "javascript-module",
19464
- "path": "dist/empty-state/esp-empty-state.js",
19464
+ "path": "dist/file-upload/esp-file-upload.js",
19465
19465
  "declarations": [
19466
19466
  {
19467
19467
  "kind": "class",
19468
- "description": "A centered empty-state layout for list, grid, and page-level\nzero-item states.\n\n```html\n<esp-empty-state icon=\"photo-up\">\n <span slot=\"heading\">No images yet</span>\n Upload the first image to start building this library.\n <esp-button slot=\"action\" label=\"Upload Image\"></esp-button>\n</esp-empty-state>\n\n<esp-empty-state size=\"large\" icon=\"users\">\n <span slot=\"heading\">No members yet</span>\n Invite teammates when you are ready to collaborate.\n</esp-empty-state>\n```",
19469
- "name": "EspalierEmptyState",
19470
- "slots": [
19471
- {
19472
- "description": "Primary empty-state message.",
19473
- "name": "heading"
19474
- },
19475
- {
19476
- "description": "Supporting body text.",
19477
- "name": ""
19478
- },
19479
- {
19480
- "description": "Optional custom icon. When provided, it overrides the generated SVG from the `icon` attribute.",
19481
- "name": "icon"
19482
- },
19483
- {
19484
- "description": "Optional call-to-action button or link.",
19485
- "name": "action"
19486
- }
19487
- ],
19468
+ "description": "Used to upload files.\n\n```html\n<esp-file-upload choose-text=\"Upload Document\"></esp-file-upload>\n<script>\n const theFileUpload = findByTagName(\"esp-file-upload\")[0];\n theFileUpload.addEventListener(\"esp-file-upload-files-selected\", () => {\n showToast({\n message: `You selected a file!`,\n icon: \"info-i\",\n duration: 2,\n onClosed: () => {\n theFileUpload.finishedProcessingFiles();\n },\n });\n });\n</script>\n```",
19469
+ "name": "EspalierFileUpload",
19488
19470
  "members": [
19489
19471
  {
19490
19472
  "kind": "field",
19491
- "name": "iconSlot",
19492
- "privacy": "private",
19493
- "default": "new SlottedIconController(this)"
19494
- },
19495
- {
19496
- "kind": "field",
19497
- "name": "actionSlot",
19473
+ "name": "uploadInput",
19498
19474
  "privacy": "private"
19499
19475
  },
19500
19476
  {
19501
19477
  "kind": "field",
19502
- "name": "sizeBacker",
19478
+ "name": "processingFiles",
19503
19479
  "type": {
19504
- "text": "EspalierEmptyStateSize"
19480
+ "text": "boolean"
19505
19481
  },
19506
19482
  "privacy": "private",
19507
- "default": "\"medium\""
19483
+ "default": "false"
19508
19484
  },
19509
19485
  {
19510
19486
  "kind": "field",
19511
- "name": "hasSlottedAction",
19487
+ "name": "accept",
19512
19488
  "type": {
19513
- "text": "boolean"
19489
+ "text": "string"
19514
19490
  },
19515
- "privacy": "private",
19516
- "default": "false"
19491
+ "privacy": "public",
19492
+ "default": "\"*\"",
19493
+ "description": "The accepted file types. For example, to allow JPEG, PNG, and WebP images:\n\n`image/jpeg, image/png, image/webp`",
19494
+ "attribute": "accept"
19517
19495
  },
19518
19496
  {
19519
19497
  "kind": "field",
19520
- "name": "icon",
19498
+ "name": "chooseText",
19521
19499
  "type": {
19522
19500
  "text": "string"
19523
19501
  },
19524
19502
  "privacy": "public",
19525
- "default": "\"\"",
19526
- "description": "Optional icon name from the Espalier SVG sprite.",
19527
- "attribute": "icon"
19503
+ "default": "\"Choose File\"",
19504
+ "description": "The text to display on the button.",
19505
+ "attribute": "choose-text"
19528
19506
  },
19529
19507
  {
19530
19508
  "kind": "field",
19531
- "name": "size",
19509
+ "name": "multiple",
19532
19510
  "type": {
19533
- "text": "EspalierEmptyStateSize"
19511
+ "text": "boolean"
19534
19512
  },
19535
19513
  "privacy": "public",
19536
- "description": "Empty-state scale.",
19537
- "attribute": "size",
19538
- "reflects": true
19514
+ "default": "false",
19515
+ "description": "Allow multiple files to be selected.",
19516
+ "attribute": "multiple"
19539
19517
  },
19540
19518
  {
19541
19519
  "kind": "field",
19542
- "name": "handleActionSlotChange",
19520
+ "name": "filesSelected",
19543
19521
  "privacy": "private"
19544
19522
  },
19523
+ {
19524
+ "kind": "method",
19525
+ "name": "finishedProcessingFiles",
19526
+ "privacy": "public",
19527
+ "description": "The `esp-file-upload-files-selected` event sets the file upload to a processing state.\nCall this method when you have finished processing the selected files\nto reset the file upload."
19528
+ },
19545
19529
  {
19546
19530
  "kind": "field",
19547
19531
  "name": "seedColorBacker",
@@ -20267,23 +20251,42 @@
20267
20251
  }
20268
20252
  }
20269
20253
  ],
20254
+ "events": [
20255
+ {
20256
+ "type": {
20257
+ "text": "CustomEvent<FileList>"
20258
+ },
20259
+ "description": "Fired after the user selects one or more files.",
20260
+ "name": "esp-file-upload-files-selected"
20261
+ }
20262
+ ],
20270
20263
  "attributes": [
20271
20264
  {
20272
- "name": "icon",
20265
+ "name": "accept",
20273
20266
  "type": {
20274
20267
  "text": "string"
20275
20268
  },
20276
- "default": "\"\"",
20277
- "description": "Optional icon name from the Espalier SVG sprite.",
20278
- "fieldName": "icon"
20269
+ "default": "\"*\"",
20270
+ "description": "The accepted file types. For example, to allow JPEG, PNG, and WebP images:\n\n`image/jpeg, image/png, image/webp`",
20271
+ "fieldName": "accept"
20279
20272
  },
20280
20273
  {
20281
- "name": "size",
20274
+ "name": "choose-text",
20282
20275
  "type": {
20283
- "text": "EspalierEmptyStateSize"
20276
+ "text": "string"
20284
20277
  },
20285
- "description": "Empty-state scale.",
20286
- "fieldName": "size"
20278
+ "default": "\"Choose File\"",
20279
+ "description": "The text to display on the button.",
20280
+ "fieldName": "chooseText"
20281
+ },
20282
+ {
20283
+ "name": "multiple",
20284
+ "type": {
20285
+ "text": "boolean"
20286
+ },
20287
+ "default": "false",
20288
+ "description": "Allow multiple files to be selected.",
20289
+ "fieldName": "multiple"
20287
20290
  },
20288
20291
  {
20289
20292
  "name": "scheme",
@@ -20327,28 +20330,28 @@
20327
20330
  "name": "EspalierElementBase",
20328
20331
  "module": "dist/shared/esp-element-base.js"
20329
20332
  },
20333
+ "tagName": "esp-file-upload",
20334
+ "customElement": true,
20330
20335
  "docPageTitle": {
20331
- "name": "Empty",
20332
- "description": "State"
20336
+ "name": "File",
20337
+ "description": "Upload"
20333
20338
  },
20334
20339
  "docUrl": {
20335
- "name": "/components/empty-state",
20340
+ "name": "/components/file-upload",
20336
20341
  "description": ""
20337
20342
  },
20338
20343
  "menuGroup": {
20339
- "name": "Feedback",
20340
- "description": ""
20344
+ "name": "Form",
20345
+ "description": "Controls"
20341
20346
  },
20342
20347
  "menuLabel": {
20343
- "name": "Empty",
20344
- "description": "State"
20348
+ "name": "File",
20349
+ "description": "Upload"
20345
20350
  },
20346
20351
  "menuIcon": {
20347
- "name": "box",
20352
+ "name": "upload",
20348
20353
  "description": ""
20349
20354
  },
20350
- "tagName": "esp-empty-state",
20351
- "customElement": true,
20352
20355
  "cssProperties": [
20353
20356
  {
20354
20357
  "description": "Background color of the shared field shell. Defaults to `var(--esp-color-layer-2)`.",
@@ -20406,96 +20409,111 @@
20406
20409
  "module": "dist/shared/esp-element-base.js"
20407
20410
  }
20408
20411
  }
20409
- ],
20410
- "events": []
20412
+ ]
20411
20413
  }
20412
20414
  ],
20413
20415
  "exports": [
20414
20416
  {
20415
20417
  "kind": "js",
20416
- "name": "EspalierEmptyState",
20418
+ "name": "EspalierFileUpload",
20417
20419
  "declaration": {
20418
- "name": "EspalierEmptyState",
20419
- "module": "dist/empty-state/esp-empty-state.js"
20420
+ "name": "EspalierFileUpload",
20421
+ "module": "dist/file-upload/esp-file-upload.js"
20420
20422
  }
20421
20423
  },
20422
20424
  {
20423
20425
  "kind": "custom-element-definition",
20424
- "name": "esp-empty-state",
20426
+ "name": "esp-file-upload",
20425
20427
  "declaration": {
20426
- "name": "EspalierEmptyState",
20427
- "module": "dist/empty-state/esp-empty-state.js"
20428
+ "name": "EspalierFileUpload",
20429
+ "module": "dist/file-upload/esp-file-upload.js"
20428
20430
  }
20429
20431
  }
20430
20432
  ]
20431
20433
  },
20432
20434
  {
20433
20435
  "kind": "javascript-module",
20434
- "path": "dist/file-upload/esp-file-upload.js",
20436
+ "path": "dist/empty-state/esp-empty-state.js",
20435
20437
  "declarations": [
20436
20438
  {
20437
20439
  "kind": "class",
20438
- "description": "Used to upload files.\n\n```html\n<esp-file-upload choose-text=\"Upload Document\"></esp-file-upload>\n<script>\n const theFileUpload = findByTagName(\"esp-file-upload\")[0];\n theFileUpload.addEventListener(\"esp-file-upload-files-selected\", () => {\n showToast({\n message: `You selected a file!`,\n icon: \"info-i\",\n duration: 2,\n onClosed: () => {\n theFileUpload.finishedProcessingFiles();\n },\n });\n });\n</script>\n```",
20439
- "name": "EspalierFileUpload",
20440
+ "description": "A centered empty-state layout for list, grid, and page-level\nzero-item states.\n\n```html\n<esp-empty-state icon=\"photo-up\">\n <span slot=\"heading\">No images yet</span>\n Upload the first image to start building this library.\n <esp-button slot=\"action\" label=\"Upload Image\"></esp-button>\n</esp-empty-state>\n\n<esp-empty-state size=\"large\" icon=\"users\">\n <span slot=\"heading\">No members yet</span>\n Invite teammates when you are ready to collaborate.\n</esp-empty-state>\n```",
20441
+ "name": "EspalierEmptyState",
20442
+ "slots": [
20443
+ {
20444
+ "description": "Primary empty-state message.",
20445
+ "name": "heading"
20446
+ },
20447
+ {
20448
+ "description": "Supporting body text.",
20449
+ "name": ""
20450
+ },
20451
+ {
20452
+ "description": "Optional custom icon. When provided, it overrides the generated SVG from the `icon` attribute.",
20453
+ "name": "icon"
20454
+ },
20455
+ {
20456
+ "description": "Optional call-to-action button or link.",
20457
+ "name": "action"
20458
+ }
20459
+ ],
20440
20460
  "members": [
20441
20461
  {
20442
20462
  "kind": "field",
20443
- "name": "uploadInput",
20463
+ "name": "iconSlot",
20464
+ "privacy": "private",
20465
+ "default": "new SlottedIconController(this)"
20466
+ },
20467
+ {
20468
+ "kind": "field",
20469
+ "name": "actionSlot",
20444
20470
  "privacy": "private"
20445
20471
  },
20446
20472
  {
20447
20473
  "kind": "field",
20448
- "name": "processingFiles",
20474
+ "name": "sizeBacker",
20449
20475
  "type": {
20450
- "text": "boolean"
20476
+ "text": "EspalierEmptyStateSize"
20451
20477
  },
20452
20478
  "privacy": "private",
20453
- "default": "false"
20479
+ "default": "\"medium\""
20454
20480
  },
20455
20481
  {
20456
20482
  "kind": "field",
20457
- "name": "accept",
20483
+ "name": "hasSlottedAction",
20458
20484
  "type": {
20459
- "text": "string"
20485
+ "text": "boolean"
20460
20486
  },
20461
- "privacy": "public",
20462
- "default": "\"*\"",
20463
- "description": "The accepted file types. For example, to allow JPEG, PNG, and WebP images:\n\n`image/jpeg, image/png, image/webp`",
20464
- "attribute": "accept"
20487
+ "privacy": "private",
20488
+ "default": "false"
20465
20489
  },
20466
20490
  {
20467
20491
  "kind": "field",
20468
- "name": "chooseText",
20492
+ "name": "icon",
20469
20493
  "type": {
20470
20494
  "text": "string"
20471
20495
  },
20472
20496
  "privacy": "public",
20473
- "default": "\"Choose File\"",
20474
- "description": "The text to display on the button.",
20475
- "attribute": "choose-text"
20497
+ "default": "\"\"",
20498
+ "description": "Optional icon name from the Espalier SVG sprite.",
20499
+ "attribute": "icon"
20476
20500
  },
20477
20501
  {
20478
20502
  "kind": "field",
20479
- "name": "multiple",
20503
+ "name": "size",
20480
20504
  "type": {
20481
- "text": "boolean"
20505
+ "text": "EspalierEmptyStateSize"
20482
20506
  },
20483
20507
  "privacy": "public",
20484
- "default": "false",
20485
- "description": "Allow multiple files to be selected.",
20486
- "attribute": "multiple"
20508
+ "description": "Empty-state scale.",
20509
+ "attribute": "size",
20510
+ "reflects": true
20487
20511
  },
20488
20512
  {
20489
20513
  "kind": "field",
20490
- "name": "filesSelected",
20514
+ "name": "handleActionSlotChange",
20491
20515
  "privacy": "private"
20492
20516
  },
20493
- {
20494
- "kind": "method",
20495
- "name": "finishedProcessingFiles",
20496
- "privacy": "public",
20497
- "description": "The `esp-file-upload-files-selected` event sets the file upload to a processing state.\nCall this method when you have finished processing the selected files\nto reset the file upload."
20498
- },
20499
20517
  {
20500
20518
  "kind": "field",
20501
20519
  "name": "seedColorBacker",
@@ -21221,42 +21239,23 @@
21221
21239
  }
21222
21240
  }
21223
21241
  ],
21224
- "events": [
21225
- {
21226
- "type": {
21227
- "text": "CustomEvent<FileList>"
21228
- },
21229
- "description": "Fired after the user selects one or more files.",
21230
- "name": "esp-file-upload-files-selected"
21231
- }
21232
- ],
21233
21242
  "attributes": [
21234
21243
  {
21235
- "name": "accept",
21236
- "type": {
21237
- "text": "string"
21238
- },
21239
- "default": "\"*\"",
21240
- "description": "The accepted file types. For example, to allow JPEG, PNG, and WebP images:\n\n`image/jpeg, image/png, image/webp`",
21241
- "fieldName": "accept"
21242
- },
21243
- {
21244
- "name": "choose-text",
21244
+ "name": "icon",
21245
21245
  "type": {
21246
21246
  "text": "string"
21247
21247
  },
21248
- "default": "\"Choose File\"",
21249
- "description": "The text to display on the button.",
21250
- "fieldName": "chooseText"
21248
+ "default": "\"\"",
21249
+ "description": "Optional icon name from the Espalier SVG sprite.",
21250
+ "fieldName": "icon"
21251
21251
  },
21252
21252
  {
21253
- "name": "multiple",
21253
+ "name": "size",
21254
21254
  "type": {
21255
- "text": "boolean"
21255
+ "text": "EspalierEmptyStateSize"
21256
21256
  },
21257
- "default": "false",
21258
- "description": "Allow multiple files to be selected.",
21259
- "fieldName": "multiple"
21257
+ "description": "Empty-state scale.",
21258
+ "fieldName": "size"
21260
21259
  },
21261
21260
  {
21262
21261
  "name": "scheme",
@@ -21300,28 +21299,28 @@
21300
21299
  "name": "EspalierElementBase",
21301
21300
  "module": "dist/shared/esp-element-base.js"
21302
21301
  },
21303
- "tagName": "esp-file-upload",
21304
- "customElement": true,
21305
21302
  "docPageTitle": {
21306
- "name": "File",
21307
- "description": "Upload"
21303
+ "name": "Empty",
21304
+ "description": "State"
21308
21305
  },
21309
21306
  "docUrl": {
21310
- "name": "/components/file-upload",
21307
+ "name": "/components/empty-state",
21311
21308
  "description": ""
21312
21309
  },
21313
21310
  "menuGroup": {
21314
- "name": "Form",
21315
- "description": "Controls"
21311
+ "name": "Feedback",
21312
+ "description": ""
21316
21313
  },
21317
21314
  "menuLabel": {
21318
- "name": "File",
21319
- "description": "Upload"
21315
+ "name": "Empty",
21316
+ "description": "State"
21320
21317
  },
21321
21318
  "menuIcon": {
21322
- "name": "upload",
21319
+ "name": "box",
21323
21320
  "description": ""
21324
21321
  },
21322
+ "tagName": "esp-empty-state",
21323
+ "customElement": true,
21325
21324
  "cssProperties": [
21326
21325
  {
21327
21326
  "description": "Background color of the shared field shell. Defaults to `var(--esp-color-layer-2)`.",
@@ -21379,24 +21378,25 @@
21379
21378
  "module": "dist/shared/esp-element-base.js"
21380
21379
  }
21381
21380
  }
21382
- ]
21381
+ ],
21382
+ "events": []
21383
21383
  }
21384
21384
  ],
21385
21385
  "exports": [
21386
21386
  {
21387
21387
  "kind": "js",
21388
- "name": "EspalierFileUpload",
21388
+ "name": "EspalierEmptyState",
21389
21389
  "declaration": {
21390
- "name": "EspalierFileUpload",
21391
- "module": "dist/file-upload/esp-file-upload.js"
21390
+ "name": "EspalierEmptyState",
21391
+ "module": "dist/empty-state/esp-empty-state.js"
21392
21392
  }
21393
21393
  },
21394
21394
  {
21395
21395
  "kind": "custom-element-definition",
21396
- "name": "esp-file-upload",
21396
+ "name": "esp-empty-state",
21397
21397
  "declaration": {
21398
- "name": "EspalierFileUpload",
21399
- "module": "dist/file-upload/esp-file-upload.js"
21398
+ "name": "EspalierEmptyState",
21399
+ "module": "dist/empty-state/esp-empty-state.js"
21400
21400
  }
21401
21401
  }
21402
21402
  ]
@@ -36826,6 +36826,14 @@
36826
36826
  "description": "Space between the headline and supporting copy in a copy stack; the action sits twice as far below. Defaults to `var(--esp-size-small)`.",
36827
36827
  "name": "--esp-image-overlay-gap"
36828
36828
  },
36829
+ {
36830
+ "description": "A soft height cap for a banner: the ratio-sized height is the smaller of the ratio height and this length, and copy that would not fit (spacing included) grows the banner past it. In the compact band it caps only the image box. Unlike `max-block-size`, it never clips copy. Defaults to none.",
36831
+ "name": "--esp-image-banner-max-block-size"
36832
+ },
36833
+ {
36834
+ "description": "A soft height target for a banner: it replaces the ratio as the banner height (viewport-fill banners), and copy that would not fit grows the banner past it. In the compact band it sizes only the image box. Unlike `block-size`, it never clips copy. Defaults to none.",
36835
+ "name": "--esp-image-banner-block-size"
36836
+ },
36829
36837
  {
36830
36838
  "description": "Read only by the static `banner-static.css` stylesheet before upgrade: the `ratio` value, e.g. `3 / 1`. A server sets it inline beside the attribute.",
36831
36839
  "name": "--esp-image-static-ratio"
@@ -37266,6 +37274,16 @@
37266
37274
  "default": "false",
37267
37275
  "description": "Whether the overlay copy outgrew the ratio's frame; see `syncGrowth`."
37268
37276
  },
37277
+ {
37278
+ "kind": "field",
37279
+ "name": "softHeight",
37280
+ "type": {
37281
+ "text": "boolean"
37282
+ },
37283
+ "privacy": "private",
37284
+ "default": "false",
37285
+ "description": "Whether a soft height (`--esp-image-banner-max-block-size` or\n`--esp-image-banner-block-size`) sizes this banner; see `readSoftHeight`."
37286
+ },
37269
37287
  {
37270
37288
  "kind": "field",
37271
37289
  "name": "growthWidth",
@@ -37637,6 +37655,28 @@
37637
37655
  ],
37638
37656
  "description": "Whether the copy's own boxes reach past the frame's padding box, so text\nis cut off. Padding and margins that do not fit only bring the copy\ncloser to the edge, and a banner laid out that way keeps its ratio\nexactly as it always has. (A grown banner gives its ratio back only\nonce everything, spacing included, fits again; see syncGrowth.)"
37639
37657
  },
37658
+ {
37659
+ "kind": "method",
37660
+ "name": "readSoftHeight",
37661
+ "privacy": "private",
37662
+ "return": {
37663
+ "type": {
37664
+ "text": "boolean"
37665
+ }
37666
+ },
37667
+ "description": "A soft height puts an overlay-mode banner in the grown geometry for good:\nthe spacer takes the ratio, capped by the soft cap or replaced by the\nsoft target, and copy grows the frame past it in plain CSS, so the\ngrowth state machine has nothing to do. A banner with neither property\nkeeps the ratio on the host. Read from computed style, so a media query\nor script can set either one; see the re-reads in measureScrimReach and\nhandleWindowResize."
37668
+ },
37669
+ {
37670
+ "kind": "method",
37671
+ "name": "syncSoftHeight",
37672
+ "privacy": "private",
37673
+ "return": {
37674
+ "type": {
37675
+ "text": "boolean"
37676
+ }
37677
+ },
37678
+ "description": "Re-read the soft height; returns whether it changed (an update follows)."
37679
+ },
37640
37680
  {
37641
37681
  "kind": "method",
37642
37682
  "name": "grownActive",
@@ -39119,24 +39159,24 @@
39119
39159
  },
39120
39160
  {
39121
39161
  "kind": "javascript-module",
39122
- "path": "dist/image-upload/esp-image-preview.js",
39162
+ "path": "dist/image-picker/esp-image-picker.js",
39123
39163
  "declarations": [
39124
39164
  {
39125
39165
  "kind": "class",
39126
- "description": "An image preview for the upload component.\n\nRemoval and retry requests are private coordination events consumed by\nthe owning `esp-image-upload`.",
39127
- "name": "EspalierImagePreview",
39166
+ "description": "A form-associated image picker with large image choices and a selected preview.\n\nThe component is controlled: set `images` and `value` from consumer state,\nthen use `esp-value-changed` to persist a user's next selection. An empty\n`value` means the Automatic choice. Labels are optional; unlabeled images use\ntheir alternative text or a numbered name. Images are shown without cropping.\n\nThe large preview sits above the control by default. Set\n`preview-placement=\"beside\"` for a compact preview beside the control.\nSize the preview and option images with the CSS properties below.\n\n```html\n<esp-form-item label=\"Page cover\">\n <esp-image-picker name=\"cover\" value=\"field\"></esp-image-picker>\n</esp-form-item>\n<script>\n const picker = document.querySelector(\"esp-image-picker\");\n picker.images = [\n { id: \"field\", src: \"/assets/focus-picker-unsplash.jpg\" },\n { id: \"paper\", src: \"/assets/espalier-paper-texture.png\" },\n ];\n picker.addEventListener(\"esp-value-changed\", (event) => {\n picker.value = event.detail;\n });\n</script>\n```",
39167
+ "name": "EspalierImagePicker",
39128
39168
  "cssProperties": [
39129
39169
  {
39130
- "description": "The border color of the preview.",
39131
- "name": "--esp-image-preview-border-color"
39170
+ "description": "Height of the large preview above the control. Default 16rem.",
39171
+ "name": "--esp-image-picker-preview-height"
39132
39172
  },
39133
39173
  {
39134
- "description": "The text color of the remove button.",
39135
- "name": "--esp-image-preview-remove-color"
39174
+ "description": "Width of dropdown images, capped at 40vw on narrow screens. Default 12rem.",
39175
+ "name": "--esp-image-picker-option-width"
39136
39176
  },
39137
39177
  {
39138
- "description": "The text color used by upload and failure overlays.",
39139
- "name": "--esp-image-preview-overlay-text"
39178
+ "description": "Height of dropdown images. Images retain their aspect ratio. Default 8rem.",
39179
+ "name": "--esp-image-picker-option-height"
39140
39180
  },
39141
39181
  {
39142
39182
  "description": "Background color of the shared field shell. Defaults to `var(--esp-color-layer-2)`.",
@@ -39198,218 +39238,197 @@
39198
39238
  "members": [
39199
39239
  {
39200
39240
  "kind": "field",
39201
- "name": "image"
39202
- },
39203
- {
39204
- "kind": "field",
39205
- "name": "url",
39206
- "type": {
39207
- "text": "string"
39208
- },
39209
- "default": "\"\"",
39210
- "attribute": "url"
39211
- },
39212
- {
39213
- "kind": "field",
39214
- "name": "alt",
39215
- "type": {
39216
- "text": "string"
39217
- },
39218
- "default": "\"\"",
39219
- "description": "Alternative text for the preview image (typically the file name).",
39220
- "attribute": "alt"
39221
- },
39222
- {
39223
- "kind": "field",
39224
- "name": "progress",
39241
+ "name": "formAssociated",
39225
39242
  "type": {
39226
- "text": "number | null | undefined"
39243
+ "text": "boolean"
39227
39244
  },
39228
- "description": "Upload progress for this image.\n- `undefined` — no overlay (not uploading)\n- `null` — indeterminate spinner (upload started, no progress yet)\n- `0–100` — determinate progress ring",
39229
- "attribute": "progress"
39245
+ "static": true,
39246
+ "default": "true"
39230
39247
  },
39231
39248
  {
39232
39249
  "kind": "field",
39233
- "name": "failed",
39234
- "type": {
39235
- "text": "boolean"
39236
- },
39237
- "default": "false",
39238
- "description": "Whether the upload for this image has failed.\nShows an error overlay with a retry button.",
39239
- "attribute": "failed"
39250
+ "name": "internals",
39251
+ "privacy": "private"
39240
39252
  },
39241
39253
  {
39242
39254
  "kind": "field",
39243
- "name": "sourceToken",
39244
- "type": {
39245
- "text": "number"
39246
- },
39255
+ "name": "formCtrl",
39247
39256
  "privacy": "private",
39248
- "default": "0",
39249
- "description": "The source token keys a fresh image element for every exact-URL retry."
39257
+ "default": "new FormFieldController({ host: this, internals: this.internals, getFormValue: () => (this.selectedImage ? this.value : null), getValidity: () => null, onReset: () => { this.value = \"\"; }, onRestore: (state: string) => { this.value = state; }, onDisabled: (isDisabled: boolean) => { this.disabled = isDisabled; }, })"
39250
39258
  },
39251
39259
  {
39252
39260
  "kind": "field",
39253
- "name": "admittedUrl",
39254
- "type": {
39255
- "text": "string"
39256
- },
39261
+ "name": "formItemRelay",
39257
39262
  "privacy": "private",
39258
- "default": "\"\"",
39259
- "description": "The remote URL currently assigned to an admitted image element."
39263
+ "default": "new FormItemRelay(() => this.picker as EspalierFormField | undefined)"
39260
39264
  },
39261
39265
  {
39262
39266
  "kind": "field",
39263
- "name": "remoteImageLoaded",
39267
+ "name": "synchronizingPicker",
39264
39268
  "type": {
39265
39269
  "text": "boolean"
39266
39270
  },
39267
39271
  "privacy": "private",
39268
- "default": "false",
39269
- "description": "A successful image stays rendered without holding a shared queue slot."
39272
+ "default": "true"
39270
39273
  },
39271
39274
  {
39272
39275
  "kind": "field",
39273
- "name": "imageLoadFailed",
39276
+ "name": "pickerSyncGeneration",
39274
39277
  "type": {
39275
- "text": "boolean"
39278
+ "text": "number"
39276
39279
  },
39277
39280
  "privacy": "private",
39278
- "default": "false",
39279
- "description": "True after automatic retries are exhausted, until the user retries the image."
39281
+ "default": "0"
39280
39282
  },
39281
39283
  {
39282
39284
  "kind": "field",
39283
- "name": "automaticRetryCount",
39285
+ "name": "images",
39284
39286
  "type": {
39285
- "text": "number"
39287
+ "text": "ImagePickerImage[]"
39286
39288
  },
39287
- "privacy": "private",
39288
- "default": "0",
39289
- "description": "Number of automatic retries already scheduled for the current URL."
39289
+ "privacy": "public",
39290
+ "default": "[]",
39291
+ "description": "Image candidates, kept in the supplied order.",
39292
+ "attribute": "images"
39290
39293
  },
39291
39294
  {
39292
39295
  "kind": "field",
39293
- "name": "remotePreviewVisible",
39296
+ "name": "value",
39294
39297
  "type": {
39295
- "text": "boolean"
39298
+ "text": "string"
39296
39299
  },
39297
- "privacy": "private",
39298
- "default": "false",
39299
- "description": "Whether IntersectionObserver currently considers this preview visible."
39300
+ "privacy": "public",
39301
+ "default": "\"\"",
39302
+ "description": "Selected image ID. An empty string selects Automatic.",
39303
+ "attribute": "value"
39300
39304
  },
39301
39305
  {
39302
39306
  "kind": "field",
39303
- "name": "visibilityObserver",
39307
+ "name": "previewPlacement",
39304
39308
  "type": {
39305
- "text": "IntersectionObserver | null"
39309
+ "text": "\"above\" | \"beside\""
39306
39310
  },
39307
- "privacy": "private",
39308
- "default": "null"
39311
+ "privacy": "public",
39312
+ "default": "\"above\"",
39313
+ "description": "Preview placement: above (default, large) or beside (compact).",
39314
+ "attribute": "preview-placement",
39315
+ "reflects": true
39309
39316
  },
39310
39317
  {
39311
39318
  "kind": "field",
39312
- "name": "queuedLoadCancel",
39319
+ "name": "disabled",
39313
39320
  "type": {
39314
- "text": "(() => void) | null"
39321
+ "text": "boolean"
39315
39322
  },
39316
- "privacy": "private",
39317
- "default": "null"
39323
+ "privacy": "public",
39324
+ "default": "false",
39325
+ "description": "Disables the picker trigger.",
39326
+ "attribute": "disabled",
39327
+ "reflects": true
39318
39328
  },
39319
39329
  {
39320
39330
  "kind": "field",
39321
- "name": "loadSlotRelease",
39331
+ "name": "loading",
39322
39332
  "type": {
39323
- "text": "(() => void) | null"
39333
+ "text": "boolean"
39324
39334
  },
39325
- "privacy": "private",
39326
- "default": "null"
39335
+ "privacy": "public",
39336
+ "default": "false",
39337
+ "description": "Shows a loading state while candidates are being fetched.",
39338
+ "attribute": "loading",
39339
+ "reflects": true
39327
39340
  },
39328
39341
  {
39329
39342
  "kind": "field",
39330
- "name": "retryTimer",
39343
+ "name": "emptyMessage",
39331
39344
  "type": {
39332
- "text": "ReturnType<typeof setTimeout> | null"
39345
+ "text": "string"
39333
39346
  },
39334
- "privacy": "private",
39335
- "default": "null"
39347
+ "privacy": "public",
39348
+ "default": "\"No images available.\"",
39349
+ "description": "Message shown when no image candidates are available.",
39350
+ "attribute": "empty-message"
39336
39351
  },
39337
39352
  {
39338
39353
  "kind": "field",
39339
- "name": "loadTimeoutTimer",
39354
+ "name": "automaticLabel",
39340
39355
  "type": {
39341
- "text": "ReturnType<typeof setTimeout> | null"
39356
+ "text": "string"
39342
39357
  },
39343
- "privacy": "private",
39344
- "default": "null"
39358
+ "privacy": "public",
39359
+ "default": "\"Automatic\"",
39360
+ "description": "Label for the empty-value choice.",
39361
+ "attribute": "automatic-label"
39345
39362
  },
39346
39363
  {
39347
39364
  "kind": "field",
39348
- "name": "activeSourceToken",
39365
+ "name": "name",
39349
39366
  "type": {
39350
- "text": "number | null"
39367
+ "text": "string"
39351
39368
  },
39352
- "privacy": "private",
39353
- "default": "null"
39369
+ "privacy": "public",
39370
+ "default": "\"\"",
39371
+ "description": "The name used when this picker participates in a `<form>`.",
39372
+ "attribute": "name",
39373
+ "reflects": true
39354
39374
  },
39355
39375
  {
39356
39376
  "kind": "method",
39357
- "name": "startCurrentPreview",
39358
- "privacy": "private",
39377
+ "name": "focus",
39378
+ "privacy": "public",
39359
39379
  "return": {
39360
39380
  "type": {
39361
39381
  "text": "void"
39362
39382
  }
39363
- }
39383
+ },
39384
+ "parameters": [
39385
+ {
39386
+ "name": "options",
39387
+ "optional": true,
39388
+ "type": {
39389
+ "text": "FocusOptions"
39390
+ }
39391
+ }
39392
+ ],
39393
+ "description": "Focus the composed picker trigger."
39364
39394
  },
39365
39395
  {
39366
39396
  "kind": "method",
39367
- "name": "stopVisibilityObserver",
39368
- "privacy": "private",
39397
+ "name": "validate",
39398
+ "privacy": "public",
39369
39399
  "return": {
39370
39400
  "type": {
39371
39401
  "text": "void"
39372
39402
  }
39373
- }
39374
- },
39403
+ },
39404
+ "description": "Re-run form validation."
39405
+ },
39375
39406
  {
39376
39407
  "kind": "method",
39377
- "name": "requestRemoteLoad",
39378
- "privacy": "private",
39408
+ "name": "checkValidity",
39409
+ "privacy": "public",
39379
39410
  "return": {
39380
39411
  "type": {
39381
- "text": "void"
39412
+ "text": "boolean"
39382
39413
  }
39383
- }
39414
+ },
39415
+ "description": "Check form validity."
39384
39416
  },
39385
39417
  {
39386
39418
  "kind": "method",
39387
- "name": "handleImageLoad",
39388
- "privacy": "private",
39419
+ "name": "formResetCallback",
39420
+ "privacy": "public",
39389
39421
  "return": {
39390
39422
  "type": {
39391
39423
  "text": "void"
39392
39424
  }
39393
39425
  },
39394
- "parameters": [
39395
- {
39396
- "name": "event",
39397
- "type": {
39398
- "text": "Event"
39399
- }
39400
- },
39401
- {
39402
- "name": "token",
39403
- "type": {
39404
- "text": "number"
39405
- }
39406
- }
39407
- ]
39426
+ "description": "Called by the browser when the owning form resets."
39408
39427
  },
39409
39428
  {
39410
39429
  "kind": "method",
39411
- "name": "handleImageError",
39412
- "privacy": "private",
39430
+ "name": "formStateRestoreCallback",
39431
+ "privacy": "public",
39413
39432
  "return": {
39414
39433
  "type": {
39415
39434
  "text": "void"
@@ -39417,55 +39436,69 @@
39417
39436
  },
39418
39437
  "parameters": [
39419
39438
  {
39420
- "name": "event",
39421
- "type": {
39422
- "text": "Event"
39423
- }
39424
- },
39425
- {
39426
- "name": "token",
39439
+ "name": "state",
39427
39440
  "type": {
39428
- "text": "number"
39441
+ "text": "string"
39429
39442
  }
39430
39443
  }
39431
- ]
39444
+ ],
39445
+ "description": "Called by the browser when form state is restored."
39432
39446
  },
39433
39447
  {
39434
39448
  "kind": "method",
39435
- "name": "isActiveImageEvent",
39436
- "privacy": "private",
39449
+ "name": "formDisabledCallback",
39450
+ "privacy": "public",
39437
39451
  "return": {
39438
39452
  "type": {
39439
- "text": "boolean"
39453
+ "text": "void"
39440
39454
  }
39441
39455
  },
39442
39456
  "parameters": [
39443
39457
  {
39444
- "name": "event",
39445
- "type": {
39446
- "text": "Event"
39447
- }
39448
- },
39449
- {
39450
- "name": "token",
39458
+ "name": "isDisabled",
39451
39459
  "type": {
39452
- "text": "number"
39460
+ "text": "boolean"
39453
39461
  }
39454
39462
  }
39455
- ]
39463
+ ],
39464
+ "description": "Called by the browser when an ancestor fieldset changes disabled state."
39465
+ },
39466
+ {
39467
+ "kind": "field",
39468
+ "name": "picker",
39469
+ "type": {
39470
+ "text": "EspalierPickOne | undefined"
39471
+ },
39472
+ "privacy": "private",
39473
+ "readonly": true
39474
+ },
39475
+ {
39476
+ "kind": "field",
39477
+ "name": "selectedImage",
39478
+ "type": {
39479
+ "text": "ImagePickerImage | undefined"
39480
+ },
39481
+ "privacy": "private",
39482
+ "readonly": true
39456
39483
  },
39457
39484
  {
39458
39485
  "kind": "method",
39459
- "name": "handleImageFailure",
39486
+ "name": "imageLabel",
39460
39487
  "privacy": "private",
39461
39488
  "return": {
39462
39489
  "type": {
39463
- "text": "void"
39490
+ "text": "string"
39464
39491
  }
39465
39492
  },
39466
39493
  "parameters": [
39467
39494
  {
39468
- "name": "token",
39495
+ "name": "image",
39496
+ "type": {
39497
+ "text": "ImagePickerImage"
39498
+ }
39499
+ },
39500
+ {
39501
+ "name": "index",
39469
39502
  "type": {
39470
39503
  "text": "number"
39471
39504
  }
@@ -39473,69 +39506,41 @@
39473
39506
  ]
39474
39507
  },
39475
39508
  {
39476
- "kind": "method",
39477
- "name": "completeActiveLoad",
39478
- "privacy": "private",
39479
- "return": {
39480
- "type": {
39481
- "text": "void"
39482
- }
39483
- }
39484
- },
39485
- {
39486
- "kind": "method",
39487
- "name": "abandonActiveLoad",
39488
- "privacy": "private",
39489
- "return": {
39490
- "type": {
39491
- "text": "void"
39492
- }
39509
+ "kind": "field",
39510
+ "name": "pickerItems",
39511
+ "type": {
39512
+ "text": "PickerItem[]"
39493
39513
  },
39494
- "description": "Cancel an in-flight browser request before returning its shared slot.\nA settled image never reaches this path, so its successfully loaded source\nremains visible through a disconnect or later update."
39495
- },
39496
- {
39497
- "kind": "method",
39498
- "name": "releaseActiveLoad",
39499
- "privacy": "private",
39500
- "return": {
39501
- "type": {
39502
- "text": "void"
39503
- }
39504
- }
39505
- },
39506
- {
39507
- "kind": "method",
39508
- "name": "cancelQueuedLoad",
39509
39514
  "privacy": "private",
39510
- "return": {
39511
- "type": {
39512
- "text": "void"
39513
- }
39514
- }
39515
+ "readonly": true
39515
39516
  },
39516
39517
  {
39517
39518
  "kind": "method",
39518
- "name": "cancelRemoteWork",
39519
+ "name": "thumbnailNode",
39519
39520
  "privacy": "private",
39520
39521
  "return": {
39521
39522
  "type": {
39522
- "text": "void"
39523
+ "text": "HTMLImageElement"
39523
39524
  }
39524
- }
39525
- },
39526
- {
39527
- "kind": "method",
39528
- "name": "retryImage",
39529
- "privacy": "private",
39530
- "return": {
39531
- "type": {
39532
- "text": "void"
39525
+ },
39526
+ "parameters": [
39527
+ {
39528
+ "name": "image",
39529
+ "type": {
39530
+ "text": "ImagePickerImage"
39531
+ }
39532
+ },
39533
+ {
39534
+ "name": "alt",
39535
+ "type": {
39536
+ "text": "string"
39537
+ }
39533
39538
  }
39534
- }
39539
+ ]
39535
39540
  },
39536
39541
  {
39537
- "kind": "method",
39538
- "name": "renderImage",
39542
+ "kind": "field",
39543
+ "name": "handlePickerValueChanged",
39539
39544
  "privacy": "private"
39540
39545
  },
39541
39546
  {
@@ -40263,41 +40268,94 @@
40263
40268
  }
40264
40269
  }
40265
40270
  ],
40266
- "events": [],
40271
+ "events": [
40272
+ {
40273
+ "type": {
40274
+ "text": "CustomEvent<string>"
40275
+ },
40276
+ "description": "Fired when a user chooses an image or Automatic. The detail is the selected image ID, or an empty string for Automatic.",
40277
+ "name": "esp-value-changed"
40278
+ },
40279
+ {
40280
+ "type": {
40281
+ "text": "CustomEvent<{ valid: boolean; message: string }>"
40282
+ },
40283
+ "description": "Fired whenever form validation runs.",
40284
+ "name": "esp-validity-changed"
40285
+ }
40286
+ ],
40267
40287
  "attributes": [
40268
40288
  {
40269
- "name": "url",
40289
+ "name": "images",
40270
40290
  "type": {
40271
- "text": "string"
40291
+ "text": "ImagePickerImage[]"
40272
40292
  },
40273
- "default": "\"\"",
40274
- "fieldName": "url"
40293
+ "default": "[]",
40294
+ "description": "Image candidates, kept in the supplied order.",
40295
+ "fieldName": "images"
40275
40296
  },
40276
40297
  {
40277
- "name": "alt",
40298
+ "name": "value",
40278
40299
  "type": {
40279
40300
  "text": "string"
40280
40301
  },
40281
40302
  "default": "\"\"",
40282
- "description": "Alternative text for the preview image (typically the file name).",
40283
- "fieldName": "alt"
40303
+ "description": "Selected image ID. An empty string selects Automatic.",
40304
+ "fieldName": "value"
40284
40305
  },
40285
40306
  {
40286
- "name": "progress",
40307
+ "name": "preview-placement",
40287
40308
  "type": {
40288
- "text": "number | null | undefined"
40309
+ "text": "\"above\" | \"beside\""
40289
40310
  },
40290
- "description": "Upload progress for this image.\n- `undefined` — no overlay (not uploading)\n- `null` — indeterminate spinner (upload started, no progress yet)\n- `0–100` — determinate progress ring",
40291
- "fieldName": "progress"
40311
+ "default": "\"above\"",
40312
+ "description": "Preview placement: above (default, large) or beside (compact).",
40313
+ "fieldName": "previewPlacement"
40292
40314
  },
40293
40315
  {
40294
- "name": "failed",
40316
+ "name": "disabled",
40295
40317
  "type": {
40296
40318
  "text": "boolean"
40297
40319
  },
40298
40320
  "default": "false",
40299
- "description": "Whether the upload for this image has failed.\nShows an error overlay with a retry button.",
40300
- "fieldName": "failed"
40321
+ "description": "Disables the picker trigger.",
40322
+ "fieldName": "disabled"
40323
+ },
40324
+ {
40325
+ "name": "loading",
40326
+ "type": {
40327
+ "text": "boolean"
40328
+ },
40329
+ "default": "false",
40330
+ "description": "Shows a loading state while candidates are being fetched.",
40331
+ "fieldName": "loading"
40332
+ },
40333
+ {
40334
+ "name": "empty-message",
40335
+ "type": {
40336
+ "text": "string"
40337
+ },
40338
+ "default": "\"No images available.\"",
40339
+ "description": "Message shown when no image candidates are available.",
40340
+ "fieldName": "emptyMessage"
40341
+ },
40342
+ {
40343
+ "name": "automatic-label",
40344
+ "type": {
40345
+ "text": "string"
40346
+ },
40347
+ "default": "\"Automatic\"",
40348
+ "description": "Label for the empty-value choice.",
40349
+ "fieldName": "automaticLabel"
40350
+ },
40351
+ {
40352
+ "name": "name",
40353
+ "type": {
40354
+ "text": "string"
40355
+ },
40356
+ "default": "\"\"",
40357
+ "description": "The name used when this picker participates in a `<form>`.",
40358
+ "fieldName": "name"
40301
40359
  },
40302
40360
  {
40303
40361
  "name": "scheme",
@@ -40341,41 +40399,65 @@
40341
40399
  "name": "EspalierElementBase",
40342
40400
  "module": "dist/shared/esp-element-base.js"
40343
40401
  },
40344
- "tagName": "esp-image-preview",
40345
- "customElement": true
40402
+ "tagName": "esp-image-picker",
40403
+ "customElement": true,
40404
+ "docPageTitle": {
40405
+ "name": "Image",
40406
+ "description": "Picker"
40407
+ },
40408
+ "docUrl": {
40409
+ "name": "/components/image-picker",
40410
+ "description": ""
40411
+ },
40412
+ "menuGroup": {
40413
+ "name": "Form",
40414
+ "description": "Controls"
40415
+ },
40416
+ "menuLabel": {
40417
+ "name": "Image",
40418
+ "description": "Picker"
40419
+ }
40346
40420
  }
40347
40421
  ],
40348
40422
  "exports": [
40349
40423
  {
40350
40424
  "kind": "js",
40351
- "name": "EspalierImagePreview",
40425
+ "name": "EspalierImagePicker",
40352
40426
  "declaration": {
40353
- "name": "EspalierImagePreview",
40354
- "module": "dist/image-upload/esp-image-preview.js"
40427
+ "name": "EspalierImagePicker",
40428
+ "module": "dist/image-picker/esp-image-picker.js"
40355
40429
  }
40356
40430
  },
40357
40431
  {
40358
40432
  "kind": "custom-element-definition",
40359
- "name": "esp-image-preview",
40433
+ "name": "esp-image-picker",
40360
40434
  "declaration": {
40361
- "name": "EspalierImagePreview",
40362
- "module": "dist/image-upload/esp-image-preview.js"
40435
+ "name": "EspalierImagePicker",
40436
+ "module": "dist/image-picker/esp-image-picker.js"
40363
40437
  }
40364
40438
  }
40365
40439
  ]
40366
40440
  },
40367
40441
  {
40368
40442
  "kind": "javascript-module",
40369
- "path": "dist/image-upload/esp-image-upload.js",
40443
+ "path": "dist/image-upload/esp-image-preview.js",
40370
40444
  "declarations": [
40371
40445
  {
40372
40446
  "kind": "class",
40373
- "description": "Used to upload images.\n\n```html\n<esp-image-upload></esp-image-upload>\n```\n\n**Uploading new images**\n\nThe `esp-image-upload-file-selected` event detail provides the `image`\nreference (the actual object in `uploadedImages`) plus\n`onProgress`, `onComplete`, and `onFailed` callbacks\nbound to it, and a `signal` that aborts if the user removes\nthe image while it is still uploading. The same shape is\nused for `esp-image-upload-retry`.\n\n```html\n<script>\n // Stubs — replace with your real upload/delete logic.\n function uploadToServer(file, opts) {\n let pct = 0;\n const id = setInterval(() => {\n pct = Math.min(pct + 20, 100);\n if (opts.onProgress) opts.onProgress(pct);\n if (pct >= 100) { clearInterval(id); }\n }, 200);\n return new Promise((r) => setTimeout(() => r(\"id-\" + file.name), 1200));\n }\n function deleteFromServer(id) { console.log(\"delete\", id); }\n\n const uploader = findByTagName(\"esp-image-upload\")[0];\n uploader.addEventListener(\"esp-image-upload-file-selected\", (e) => {\n const { image, signal, onProgress, onComplete, onFailed } = e.detail;\n // Pass `signal` to fetch/XHR so removing the image cancels the upload.\n uploadToServer(image.file, {\n signal,\n onProgress: (pct) => onProgress(pct),\n }).then((id) => onComplete(id))\n .catch(() => onFailed());\n });\n uploader.addEventListener(\"esp-image-upload-retry\", (e) => {\n const { image, signal, onProgress, onComplete } = e.detail;\n uploadToServer(image.file, {\n signal,\n onProgress: (pct) => onProgress(pct),\n }).then((id) => onComplete(id));\n });\n uploader.addEventListener(\"esp-image-upload-file-removed\", (e) => {\n deleteFromServer(e.detail.uploadedId);\n });\n</script>\n<esp-image-upload></esp-image-upload>\n```\n\n**Simulated upload progress demo**\n\nSelect images to see simulated progress. The second file\nwill fail — click Retry to re-upload it.\n\n```html\n<script>\n const uploader = findByTagName(\"esp-image-upload\")[0];\n let fileIndex = 0;\n\n function simulateUpload(detail, shouldFail) {\n let progress = 0;\n const interval = setInterval(() => {\n progress += Math.floor(Math.random() * 11) + 5;\n if (shouldFail && progress >= 45) {\n clearInterval(interval);\n detail.onFailed();\n return;\n }\n if (progress >= 100) {\n clearInterval(interval);\n detail.onProgress(100);\n setTimeout(() => detail.onComplete(\"id-\" + detail.image.file.name), 500);\n return;\n }\n detail.onProgress(progress);\n }, 300 + Math.random() * 300);\n }\n\n uploader.addEventListener(\"esp-image-upload-file-selected\", (e) => {\n const idx = fileIndex++;\n simulateUpload(e.detail, idx === 1);\n });\n\n uploader.addEventListener(\"esp-image-upload-retry\", (e) => {\n simulateUpload(e.detail, false);\n });\n</script>\n<esp-image-upload></esp-image-upload>\n```\n\n**Editing with existing images**\n\nPre-populate with server images via `setExistingImages`.\nExisting images never show upload overlays.\n\n```html\n<script>\n const uploader = findByTagName(\"esp-image-upload\")[0];\n uploader.setExistingImages([\n { url: \"https://picsum.photos/id/29/1200/800\", width: 1200, height: 800, uploadedId: \"img-1\" },\n { url: \"https://picsum.photos/id/15/900/1200\", width: 900, height: 1200, uploadedId: \"img-2\" },\n ]);\n uploader.addEventListener(\"esp-image-upload-file-removed\", (e) => {\n if (e.detail.source === \"existing\") {\n console.log(\"Mark for deletion:\", e.detail.uploadedId);\n }\n });\n</script>\n<esp-image-upload></esp-image-upload>\n```",
40374
- "name": "EspalierImageUpload",
40447
+ "description": "An image preview for the upload component.\n\nRemoval and retry requests are private coordination events consumed by\nthe owning `esp-image-upload`.",
40448
+ "name": "EspalierImagePreview",
40375
40449
  "cssProperties": [
40376
40450
  {
40377
- "description": "The background color of the image preview area.",
40378
- "name": "--esp-image-upload-preview-background"
40451
+ "description": "The border color of the preview.",
40452
+ "name": "--esp-image-preview-border-color"
40453
+ },
40454
+ {
40455
+ "description": "The text color of the remove button.",
40456
+ "name": "--esp-image-preview-remove-color"
40457
+ },
40458
+ {
40459
+ "description": "The text color used by upload and failure overlays.",
40460
+ "name": "--esp-image-preview-overlay-text"
40379
40461
  },
40380
40462
  {
40381
40463
  "description": "Background color of the shared field shell. Defaults to `var(--esp-color-layer-2)`.",
@@ -40437,580 +40519,388 @@
40437
40519
  "members": [
40438
40520
  {
40439
40521
  "kind": "field",
40440
- "name": "uploadInput",
40441
- "privacy": "private"
40442
- },
40443
- {
40444
- "kind": "field",
40445
- "name": "previewsDiv",
40446
- "privacy": "private"
40447
- },
40448
- {
40449
- "kind": "field",
40450
- "name": "dropAreaDiv",
40451
- "privacy": "private"
40522
+ "name": "image"
40452
40523
  },
40453
40524
  {
40454
40525
  "kind": "field",
40455
- "name": "draggingOver",
40526
+ "name": "url",
40456
40527
  "type": {
40457
- "text": "boolean"
40528
+ "text": "string"
40458
40529
  },
40459
- "privacy": "private",
40460
- "default": "false"
40530
+ "default": "\"\"",
40531
+ "attribute": "url"
40461
40532
  },
40462
40533
  {
40463
40534
  "kind": "field",
40464
- "name": "uploadedImages",
40535
+ "name": "alt",
40465
40536
  "type": {
40466
- "text": "Array<EspalierUploadImage>"
40537
+ "text": "string"
40467
40538
  },
40468
- "default": "[]"
40539
+ "default": "\"\"",
40540
+ "description": "Alternative text for the preview image (typically the file name).",
40541
+ "attribute": "alt"
40469
40542
  },
40470
40543
  {
40471
40544
  "kind": "field",
40472
- "name": "accept",
40545
+ "name": "progress",
40473
40546
  "type": {
40474
- "text": "string"
40547
+ "text": "number | null | undefined"
40475
40548
  },
40476
- "default": "\"image/jpeg, image/png, image/webp\"",
40477
- "description": "Comma-separated list of accepted file types, in the same format as the\nnative input `accept` attribute: MIME types (`image/png`), MIME\nwildcards (`image/*`), or extensions (`.png`). Files outside this list\nare skipped and reported via the `esp-image-upload-files-rejected` event.",
40478
- "attribute": "accept"
40549
+ "description": "Upload progress for this image.\n- `undefined` — no overlay (not uploading)\n- `null` — indeterminate spinner (upload started, no progress yet)\n- `0–100` — determinate progress ring",
40550
+ "attribute": "progress"
40479
40551
  },
40480
40552
  {
40481
40553
  "kind": "field",
40482
- "name": "maxImagesPerRow",
40554
+ "name": "failed",
40483
40555
  "type": {
40484
- "text": "number"
40556
+ "text": "boolean"
40485
40557
  },
40486
- "description": "Maximum number of image previews in each justified row. Positive integers\ncreate a hard row boundary; omitted, non-finite, non-integer, and\nnonpositive values leave rows unlimited.",
40487
- "attribute": "max-images-per-row"
40558
+ "default": "false",
40559
+ "description": "Whether the upload for this image has failed.\nShows an error overlay with a retry button.",
40560
+ "attribute": "failed"
40488
40561
  },
40489
40562
  {
40490
40563
  "kind": "field",
40491
- "name": "maxRowHeightVh",
40492
- "default": "DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH",
40493
- "description": "Maximum preview-row height as a percentage of the layout viewport. Values\noutside the inclusive integer range `1…100` fall back to 90.",
40564
+ "name": "sourceToken",
40494
40565
  "type": {
40495
40566
  "text": "number"
40496
40567
  },
40497
- "attribute": "max-row-height-vh"
40568
+ "privacy": "private",
40569
+ "default": "0",
40570
+ "description": "The source token keys a fresh image element for every exact-URL retry."
40498
40571
  },
40499
40572
  {
40500
40573
  "kind": "field",
40501
- "name": "_rejectionNotice",
40574
+ "name": "admittedUrl",
40502
40575
  "type": {
40503
40576
  "text": "string"
40504
40577
  },
40505
40578
  "privacy": "private",
40506
40579
  "default": "\"\"",
40507
- "description": "Transient inline message describing skipped files."
40580
+ "description": "The remote URL currently assigned to an admitted image element."
40508
40581
  },
40509
40582
  {
40510
40583
  "kind": "field",
40511
- "name": "_noticeTimer",
40584
+ "name": "remoteImageLoaded",
40512
40585
  "type": {
40513
- "text": "ReturnType<typeof setTimeout> | undefined"
40586
+ "text": "boolean"
40514
40587
  },
40515
- "privacy": "private"
40516
- },
40517
- {
40518
- "kind": "field",
40519
- "name": "_uploadState",
40520
40588
  "privacy": "private",
40521
- "default": "new WeakMap<EspalierUploadImage, UploadTrackingState>()"
40589
+ "default": "false",
40590
+ "description": "A successful image stays rendered without holding a shared queue slot."
40522
40591
  },
40523
40592
  {
40524
40593
  "kind": "field",
40525
- "name": "_selectionGeneration",
40594
+ "name": "imageLoadFailed",
40526
40595
  "type": {
40527
- "text": "number"
40596
+ "text": "boolean"
40528
40597
  },
40529
40598
  "privacy": "private",
40530
- "default": "0",
40531
- "description": "Bumped whenever the image list is replaced or the component unmounts so\nstill-decoding selections from before the change are discarded instead\nof landing in the new list."
40599
+ "default": "false",
40600
+ "description": "True after automatic retries are exhausted, until the user retries the image."
40532
40601
  },
40533
40602
  {
40534
40603
  "kind": "field",
40535
- "name": "_chromeWidth",
40604
+ "name": "automaticRetryCount",
40536
40605
  "type": {
40537
- "text": "number | null"
40606
+ "text": "number"
40538
40607
  },
40539
40608
  "privacy": "private",
40540
- "default": "null",
40541
- "description": "Cached horizontal chrome (previews padding + field border); re-measured after resize."
40542
- },
40543
- {
40544
- "kind": "field",
40545
- "name": "_resizeObserver",
40546
- "privacy": "private",
40547
- "default": "new ResizeObserver(() => { this._chromeWidth = null; this.requestUpdate(); })"
40548
- },
40549
- {
40550
- "kind": "field",
40551
- "name": "_handleViewportResize",
40552
- "privacy": "private",
40553
- "description": "Recalculate the viewport-derived row ceiling when only height changes."
40609
+ "default": "0",
40610
+ "description": "Number of automatic retries already scheduled for the current URL."
40554
40611
  },
40555
40612
  {
40556
40613
  "kind": "field",
40557
- "name": "_dragPointerId",
40614
+ "name": "remotePreviewVisible",
40558
40615
  "type": {
40559
- "text": "number | null"
40616
+ "text": "boolean"
40560
40617
  },
40561
40618
  "privacy": "private",
40562
- "default": "null",
40563
- "description": "The pointerId that initiated the drag — ignore events from other pointers."
40619
+ "default": "false",
40620
+ "description": "Whether IntersectionObserver currently considers this preview visible."
40564
40621
  },
40565
40622
  {
40566
40623
  "kind": "field",
40567
- "name": "_dragSourceIndex",
40624
+ "name": "visibilityObserver",
40568
40625
  "type": {
40569
- "text": "number | null"
40626
+ "text": "IntersectionObserver | null"
40570
40627
  },
40571
40628
  "privacy": "private",
40572
40629
  "default": "null"
40573
40630
  },
40574
40631
  {
40575
40632
  "kind": "field",
40576
- "name": "_dragOverIndex",
40633
+ "name": "queuedLoadCancel",
40577
40634
  "type": {
40578
- "text": "number | null"
40635
+ "text": "(() => void) | null"
40579
40636
  },
40580
40637
  "privacy": "private",
40581
40638
  "default": "null"
40582
40639
  },
40583
40640
  {
40584
40641
  "kind": "field",
40585
- "name": "_dragStartX",
40642
+ "name": "loadSlotRelease",
40586
40643
  "type": {
40587
- "text": "number"
40644
+ "text": "(() => void) | null"
40588
40645
  },
40589
40646
  "privacy": "private",
40590
- "default": "0"
40647
+ "default": "null"
40591
40648
  },
40592
40649
  {
40593
40650
  "kind": "field",
40594
- "name": "_dragStartY",
40651
+ "name": "retryTimer",
40595
40652
  "type": {
40596
- "text": "number"
40653
+ "text": "ReturnType<typeof setTimeout> | null"
40597
40654
  },
40598
40655
  "privacy": "private",
40599
- "default": "0"
40656
+ "default": "null"
40600
40657
  },
40601
40658
  {
40602
40659
  "kind": "field",
40603
- "name": "_dragActive",
40660
+ "name": "loadTimeoutTimer",
40604
40661
  "type": {
40605
- "text": "boolean"
40662
+ "text": "ReturnType<typeof setTimeout> | null"
40606
40663
  },
40607
40664
  "privacy": "private",
40608
- "default": "false"
40665
+ "default": "null"
40609
40666
  },
40610
40667
  {
40611
40668
  "kind": "field",
40612
- "name": "_ghostEl",
40669
+ "name": "activeSourceToken",
40613
40670
  "type": {
40614
- "text": "HTMLElement | null"
40671
+ "text": "number | null"
40615
40672
  },
40616
40673
  "privacy": "private",
40617
40674
  "default": "null"
40618
40675
  },
40619
40676
  {
40620
- "kind": "field",
40621
- "name": "_ghostHalfW",
40622
- "type": {
40623
- "text": "number"
40624
- },
40677
+ "kind": "method",
40678
+ "name": "startCurrentPreview",
40625
40679
  "privacy": "private",
40626
- "default": "0",
40627
- "description": "Cached ghost half-width/height so pointermove avoids offsetWidth/Height."
40680
+ "return": {
40681
+ "type": {
40682
+ "text": "void"
40683
+ }
40684
+ }
40628
40685
  },
40629
40686
  {
40630
- "kind": "field",
40631
- "name": "_ghostHalfH",
40632
- "type": {
40633
- "text": "number"
40634
- },
40687
+ "kind": "method",
40688
+ "name": "stopVisibilityObserver",
40635
40689
  "privacy": "private",
40636
- "default": "0"
40690
+ "return": {
40691
+ "type": {
40692
+ "text": "void"
40693
+ }
40694
+ }
40637
40695
  },
40638
40696
  {
40639
- "kind": "field",
40640
- "name": "_arrowEl",
40641
- "type": {
40642
- "text": "HTMLElement | null"
40643
- },
40697
+ "kind": "method",
40698
+ "name": "requestRemoteLoad",
40644
40699
  "privacy": "private",
40645
- "default": "null"
40700
+ "return": {
40701
+ "type": {
40702
+ "text": "void"
40703
+ }
40704
+ }
40646
40705
  },
40647
40706
  {
40648
- "kind": "field",
40649
- "name": "_cachedPreviews",
40650
- "type": {
40651
- "text": "{ el: HTMLElement; rect: DOMRect }[] | null"
40652
- },
40707
+ "kind": "method",
40708
+ "name": "handleImageLoad",
40653
40709
  "privacy": "private",
40654
- "default": "null",
40655
- "description": "Cached preview elements + bounding rects, set once when drag activates."
40656
- },
40657
- {
40658
- "kind": "field",
40659
- "name": "_lastDropHit",
40660
- "type": {
40661
- "text": "{ index: number; after: boolean } | null"
40662
- },
40663
- "privacy": "private",
40664
- "default": "null",
40665
- "description": "Last drop-target state to avoid redundant DOM updates in pointermove."
40666
- },
40667
- {
40668
- "kind": "field",
40669
- "name": "_savedBodyUserSelect",
40670
- "type": {
40671
- "text": "string"
40672
- },
40673
- "privacy": "private",
40674
- "default": "\"\"",
40675
- "description": "Saved body userSelect value to restore after drag."
40676
- },
40677
- {
40678
- "kind": "field",
40679
- "name": "_DRAG_THRESHOLD",
40680
- "type": {
40681
- "text": "number"
40682
- },
40683
- "privacy": "private",
40684
- "static": true,
40685
- "readonly": true,
40686
- "default": "8"
40710
+ "return": {
40711
+ "type": {
40712
+ "text": "void"
40713
+ }
40714
+ },
40715
+ "parameters": [
40716
+ {
40717
+ "name": "event",
40718
+ "type": {
40719
+ "text": "Event"
40720
+ }
40721
+ },
40722
+ {
40723
+ "name": "token",
40724
+ "type": {
40725
+ "text": "number"
40726
+ }
40727
+ }
40728
+ ]
40687
40729
  },
40688
40730
  {
40689
40731
  "kind": "method",
40690
- "name": "_getPreviewIndex",
40732
+ "name": "handleImageError",
40691
40733
  "privacy": "private",
40692
40734
  "return": {
40693
40735
  "type": {
40694
- "text": "number | null"
40736
+ "text": "void"
40695
40737
  }
40696
40738
  },
40697
40739
  "parameters": [
40698
40740
  {
40699
- "name": "ev",
40741
+ "name": "event",
40700
40742
  "type": {
40701
40743
  "text": "Event"
40702
40744
  }
40745
+ },
40746
+ {
40747
+ "name": "token",
40748
+ "type": {
40749
+ "text": "number"
40750
+ }
40703
40751
  }
40704
- ],
40705
- "description": "Find the preview index from a composedPath."
40706
- },
40707
- {
40708
- "kind": "field",
40709
- "name": "_handleDragPointerDown",
40710
- "privacy": "private"
40711
- },
40712
- {
40713
- "kind": "field",
40714
- "name": "_onDocPointerMove",
40715
- "privacy": "private"
40716
- },
40717
- {
40718
- "kind": "field",
40719
- "name": "_onDocPointerUp",
40720
- "privacy": "private"
40721
- },
40722
- {
40723
- "kind": "method",
40724
- "name": "_clearDragState",
40725
- "privacy": "private"
40752
+ ]
40726
40753
  },
40727
40754
  {
40728
40755
  "kind": "method",
40729
- "name": "_createGhost",
40756
+ "name": "isActiveImageEvent",
40730
40757
  "privacy": "private",
40758
+ "return": {
40759
+ "type": {
40760
+ "text": "boolean"
40761
+ }
40762
+ },
40731
40763
  "parameters": [
40732
40764
  {
40733
- "name": "x",
40765
+ "name": "event",
40734
40766
  "type": {
40735
- "text": "number"
40767
+ "text": "Event"
40736
40768
  }
40737
40769
  },
40738
40770
  {
40739
- "name": "y",
40771
+ "name": "token",
40740
40772
  "type": {
40741
40773
  "text": "number"
40742
40774
  }
40743
40775
  }
40744
- ],
40745
- "description": "Create a ghost thumbnail that follows the cursor."
40746
- },
40747
- {
40748
- "kind": "field",
40749
- "name": "_arrowColor",
40750
- "type": {
40751
- "text": "string | null"
40752
- },
40753
- "privacy": "private",
40754
- "default": "null",
40755
- "description": "Cached arrow color so we don't call getComputedStyle on every update."
40776
+ ]
40756
40777
  },
40757
40778
  {
40758
40779
  "kind": "method",
40759
- "name": "_updateDropTargets",
40780
+ "name": "handleImageFailure",
40760
40781
  "privacy": "private",
40782
+ "return": {
40783
+ "type": {
40784
+ "text": "void"
40785
+ }
40786
+ },
40761
40787
  "parameters": [
40762
40788
  {
40763
- "name": "previews",
40764
- "type": {
40765
- "text": "HTMLElement[]"
40766
- }
40767
- },
40768
- {
40769
- "name": "hitIndex",
40789
+ "name": "token",
40770
40790
  "type": {
40771
40791
  "text": "number"
40772
40792
  }
40773
- },
40774
- {
40775
- "name": "insertAfter",
40776
- "type": {
40777
- "text": "boolean"
40778
- }
40779
40793
  }
40780
- ],
40781
- "description": "Show a drop-target overlay on the hovered preview."
40794
+ ]
40782
40795
  },
40783
40796
  {
40784
40797
  "kind": "method",
40785
- "name": "_clearDropTargets",
40798
+ "name": "completeActiveLoad",
40786
40799
  "privacy": "private",
40787
- "description": "Clear all drop-target overlays."
40800
+ "return": {
40801
+ "type": {
40802
+ "text": "void"
40803
+ }
40804
+ }
40788
40805
  },
40789
40806
  {
40790
40807
  "kind": "method",
40791
- "name": "getContainerWidth",
40808
+ "name": "abandonActiveLoad",
40792
40809
  "privacy": "private",
40793
40810
  "return": {
40794
40811
  "type": {
40795
- "text": "number"
40812
+ "text": "void"
40796
40813
  }
40797
40814
  },
40798
- "description": "Gets the container width for layout calculation based on responsive breakpoints.\nBreakpoints chosen to maintain consistent visual appearance across devices:\n- Mobile (< 640px): Full width minus padding\n- Tablet (640px - 1024px): 90% width\n- Desktop (> 1024px): 85% width with max 1400px"
40815
+ "description": "Cancel an in-flight browser request before returning its shared slot.\nA settled image never reaches this path, so its successfully loaded source\nremains visible through a disconnect or later update."
40799
40816
  },
40800
40817
  {
40801
40818
  "kind": "method",
40802
- "name": "_isAccepted",
40819
+ "name": "releaseActiveLoad",
40803
40820
  "privacy": "private",
40804
40821
  "return": {
40805
40822
  "type": {
40806
- "text": "boolean"
40807
- }
40808
- },
40809
- "parameters": [
40810
- {
40811
- "name": "file",
40812
- "type": {
40813
- "text": "File"
40814
- }
40823
+ "text": "void"
40815
40824
  }
40816
- ],
40817
- "description": "Check a file against the `accept` list (MIME, MIME wildcard, or extension)."
40825
+ }
40818
40826
  },
40819
40827
  {
40820
- "kind": "field",
40821
- "name": "filesSelected",
40822
- "privacy": "private"
40828
+ "kind": "method",
40829
+ "name": "cancelQueuedLoad",
40830
+ "privacy": "private",
40831
+ "return": {
40832
+ "type": {
40833
+ "text": "void"
40834
+ }
40835
+ }
40823
40836
  },
40824
40837
  {
40825
40838
  "kind": "method",
40826
- "name": "_addSelectedImage",
40839
+ "name": "cancelRemoteWork",
40827
40840
  "privacy": "private",
40828
- "parameters": [
40829
- {
40830
- "name": "batch",
40831
- "type": {
40832
- "text": "(SelectedUploadImage | null)[]"
40833
- }
40834
- },
40835
- {
40836
- "name": "index",
40837
- "type": {
40838
- "text": "number"
40839
- }
40840
- },
40841
- {
40842
- "name": "image",
40843
- "type": {
40844
- "text": "SelectedUploadImage"
40845
- }
40841
+ "return": {
40842
+ "type": {
40843
+ "text": "void"
40846
40844
  }
40847
- ],
40848
- "description": "Insert a processed image at its selection-order position. Anchors on\nalready-inserted batch neighbors so concurrent completions, removals,\nand reorders mid-batch cannot scramble the order."
40845
+ }
40849
40846
  },
40850
40847
  {
40851
40848
  "kind": "method",
40852
- "name": "_reportRejectedFiles",
40849
+ "name": "retryImage",
40853
40850
  "privacy": "private",
40854
- "parameters": [
40855
- {
40856
- "name": "detail",
40857
- "type": {
40858
- "text": "FilesRejectedDetail"
40859
- }
40851
+ "return": {
40852
+ "type": {
40853
+ "text": "void"
40860
40854
  }
40861
- ],
40862
- "description": "Dispatch `esp-image-upload-files-rejected` and show the transient inline notice."
40855
+ }
40856
+ },
40857
+ {
40858
+ "kind": "method",
40859
+ "name": "renderImage",
40860
+ "privacy": "private"
40863
40861
  },
40864
40862
  {
40865
40863
  "kind": "field",
40866
- "name": "_makeCallbacks",
40864
+ "name": "seedColorBacker",
40865
+ "type": {
40866
+ "text": "string"
40867
+ },
40867
40868
  "privacy": "private",
40868
- "description": "Create upload callbacks bound to a specific image.\nClosures capture the image reference directly — no filename lookup."
40869
+ "default": "\"oklch(0.7 0.125 216)\"",
40870
+ "inheritedFrom": {
40871
+ "name": "EspalierElementBase",
40872
+ "module": "dist/shared/esp-element-base.js"
40873
+ }
40869
40874
  },
40870
40875
  {
40871
40876
  "kind": "field",
40872
- "name": "_THUMBNAIL_UPSCALE_SLACK",
40877
+ "name": "espRoot",
40873
40878
  "type": {
40874
- "text": "number"
40879
+ "text": "EspalierRoot | null"
40875
40880
  },
40876
40881
  "privacy": "private",
40877
- "static": true,
40878
- "readonly": true,
40879
- "default": "1.1",
40880
- "description": "Allowed upscale factor before a preview switches to its full-resolution source."
40882
+ "default": "null",
40883
+ "inheritedFrom": {
40884
+ "name": "EspalierElementBase",
40885
+ "module": "dist/shared/esp-element-base.js"
40886
+ }
40881
40887
  },
40882
40888
  {
40883
40889
  "kind": "field",
40884
- "name": "_fullPreviewUrls",
40890
+ "name": "contextBacker",
40891
+ "type": {
40892
+ "text": "string"
40893
+ },
40885
40894
  "privacy": "private",
40886
- "default": "new Map<SelectedUploadImage, string>()",
40887
- "description": "Full-resolution object URLs for selected images rendered beyond thumbnail capacity."
40895
+ "default": "\"\"",
40896
+ "inheritedFrom": {
40897
+ "name": "EspalierElementBase",
40898
+ "module": "dist/shared/esp-element-base.js"
40899
+ }
40888
40900
  },
40889
40901
  {
40890
- "kind": "method",
40891
- "name": "_previewUrlFor",
40892
- "privacy": "private",
40893
- "return": {
40894
- "type": {
40895
- "text": "string"
40896
- }
40897
- },
40898
- "parameters": [
40899
- {
40900
- "name": "image",
40901
- "type": {
40902
- "text": "EspalierUploadImage"
40903
- }
40904
- },
40905
- {
40906
- "name": "renderedHeight",
40907
- "type": {
40908
- "text": "number"
40909
- }
40910
- },
40911
- {
40912
- "name": "renderedWidth",
40913
- "optional": true,
40914
- "type": {
40915
- "text": "number"
40916
- }
40917
- }
40918
- ],
40919
- "description": "Resolve the URL needed to cover both dimensions of the rendered cell.\nThumbnails cover rows near the target height; images stretched well\nbeyond thumbnail capacity (clamped tall rows, single images) lazily\nswitch to a full-resolution object URL so they don't upscale blurry."
40920
- },
40921
- {
40922
- "kind": "method",
40923
- "name": "_pickExistingPreviewUrl",
40924
- "privacy": "private",
40925
- "return": {
40926
- "type": {
40927
- "text": "string"
40928
- }
40929
- },
40930
- "parameters": [
40931
- {
40932
- "name": "image",
40933
- "type": {
40934
- "text": "ExistingUploadImage"
40935
- }
40936
- },
40937
- {
40938
- "name": "renderedHeight",
40939
- "type": {
40940
- "text": "number"
40941
- }
40942
- }
40943
- ],
40944
- "description": "For a server image, pick the smallest responsive variant that covers the\npreview's rendered box (× DPR), falling back to the largest variant — and to\nthe single `url` when no responsive set was supplied. The supplied height is the full source height\nrequired for cover (including any clipped overflow), so the required width\nis `renderedHeight × aspect`."
40945
- },
40946
- {
40947
- "kind": "method",
40948
- "name": "_releaseFullPreviewUrl",
40949
- "privacy": "private",
40950
- "parameters": [
40951
- {
40952
- "name": "image",
40953
- "type": {
40954
- "text": "EspalierUploadImage"
40955
- }
40956
- }
40957
- ],
40958
- "description": "Revoke the full-resolution preview URL for one image, if it exists."
40959
- },
40960
- {
40961
- "kind": "method",
40962
- "name": "_releaseSelectedImages",
40963
- "privacy": "private",
40964
- "description": "Abort in-flight uploads and revoke preview object URLs for selected images."
40965
- },
40966
- {
40967
- "kind": "field",
40968
- "name": "setExistingImages",
40969
- "privacy": "public",
40970
- "description": "Populate the component with images that already exist on the server.\nEach entry must provide a display URL, dimensions for layout, and\nan `uploadedId` that identifies the server-side image.\n\nEntries with missing `url`/`uploadedId` or non-finite/non-positive\ndimensions are silently filtered out."
40971
- },
40972
- {
40973
- "kind": "field",
40974
- "name": "seedColorBacker",
40975
- "type": {
40976
- "text": "string"
40977
- },
40978
- "privacy": "private",
40979
- "default": "\"oklch(0.7 0.125 216)\"",
40980
- "inheritedFrom": {
40981
- "name": "EspalierElementBase",
40982
- "module": "dist/shared/esp-element-base.js"
40983
- }
40984
- },
40985
- {
40986
- "kind": "field",
40987
- "name": "espRoot",
40988
- "type": {
40989
- "text": "EspalierRoot | null"
40990
- },
40991
- "privacy": "private",
40992
- "default": "null",
40993
- "inheritedFrom": {
40994
- "name": "EspalierElementBase",
40995
- "module": "dist/shared/esp-element-base.js"
40996
- }
40997
- },
40998
- {
40999
- "kind": "field",
41000
- "name": "contextBacker",
41001
- "type": {
41002
- "text": "string"
41003
- },
41004
- "privacy": "private",
41005
- "default": "\"\"",
41006
- "inheritedFrom": {
41007
- "name": "EspalierElementBase",
41008
- "module": "dist/shared/esp-element-base.js"
41009
- }
41010
- },
41011
- {
41012
- "kind": "field",
41013
- "name": "scopedTokenOriginalValues",
40902
+ "kind": "field",
40903
+ "name": "scopedTokenOriginalValues",
41014
40904
  "privacy": "private",
41015
40905
  "readonly": true,
41016
40906
  "default": "new Map< string, { generatedPriority: string; generatedValue: string; originalPriority: string; originalValue: string | null; } >()",
@@ -41694,69 +41584,41 @@
41694
41584
  }
41695
41585
  }
41696
41586
  ],
41697
- "events": [
41698
- {
41699
- "type": {
41700
- "text": "CustomEvent<EspalierUploadImage>"
41701
- },
41702
- "description": "Fired when an image has been removed by the user. Narrow on `detail.source` to distinguish newly selected images from pre-existing server images. If the image's upload was still in flight, its `signal` aborts.",
41703
- "name": "esp-image-upload-file-removed"
41704
- },
41705
- {
41706
- "type": {
41707
- "text": "CustomEvent<UploadEventDetail>"
41708
- },
41709
- "description": "Fired when an image has been selected by the user. `detail.image` is the actual object stored in `uploadedImages`; `detail.onProgress`, `detail.onComplete`, and `detail.onFailed` are callbacks bound to that image. `detail.signal` aborts if the image is removed mid-upload — pass it to fetch/XHR.",
41710
- "name": "esp-image-upload-file-selected"
41711
- },
41712
- {
41713
- "type": {
41714
- "text": "CustomEvent<UploadEventDetail>"
41715
- },
41716
- "description": "Fired when the user clicks Retry on a failed upload. `detail.image` is the same object reference; fresh callbacks and a fresh `signal` are provided. The component automatically resets the image to indeterminate progress.",
41717
- "name": "esp-image-upload-retry"
41718
- },
41587
+ "events": [],
41588
+ "attributes": [
41719
41589
  {
41590
+ "name": "url",
41720
41591
  "type": {
41721
- "text": "CustomEvent<ImagesReorderedDetail>"
41592
+ "text": "string"
41722
41593
  },
41723
- "description": "Fired after the user drags an image to a new position. `detail.images` is the reordered array (same references, new order).",
41724
- "name": "esp-image-upload-images-reordered"
41594
+ "default": "\"\"",
41595
+ "fieldName": "url"
41725
41596
  },
41726
41597
  {
41727
- "type": {
41728
- "text": "CustomEvent<FilesRejectedDetail>"
41729
- },
41730
- "description": "Fired when selected files are skipped, either because their type is not accepted (`detail.unsupported`) or because they could not be read or decoded (`detail.unreadable`). The component also shows a transient inline notice.",
41731
- "name": "esp-image-upload-files-rejected"
41732
- }
41733
- ],
41734
- "attributes": [
41735
- {
41736
- "name": "accept",
41598
+ "name": "alt",
41737
41599
  "type": {
41738
41600
  "text": "string"
41739
41601
  },
41740
- "default": "\"image/jpeg, image/png, image/webp\"",
41741
- "description": "Comma-separated list of accepted file types, in the same format as the\nnative input `accept` attribute: MIME types (`image/png`), MIME\nwildcards (`image/*`), or extensions (`.png`). Files outside this list\nare skipped and reported via the `esp-image-upload-files-rejected` event.",
41742
- "fieldName": "accept"
41602
+ "default": "\"\"",
41603
+ "description": "Alternative text for the preview image (typically the file name).",
41604
+ "fieldName": "alt"
41743
41605
  },
41744
41606
  {
41745
- "name": "max-images-per-row",
41607
+ "name": "progress",
41746
41608
  "type": {
41747
- "text": "number"
41609
+ "text": "number | null | undefined"
41748
41610
  },
41749
- "description": "Maximum number of image previews in each justified row. Positive integers\ncreate a hard row boundary; omitted, non-finite, non-integer, and\nnonpositive values leave rows unlimited.",
41750
- "fieldName": "maxImagesPerRow"
41611
+ "description": "Upload progress for this image.\n- `undefined` — no overlay (not uploading)\n- `null` — indeterminate spinner (upload started, no progress yet)\n- `0–100` — determinate progress ring",
41612
+ "fieldName": "progress"
41751
41613
  },
41752
41614
  {
41753
- "name": "max-row-height-vh",
41754
- "default": "DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH",
41755
- "description": "Maximum preview-row height as a percentage of the layout viewport. Values\noutside the inclusive integer range `1…100` fall back to 90.",
41615
+ "name": "failed",
41756
41616
  "type": {
41757
- "text": "number"
41617
+ "text": "boolean"
41758
41618
  },
41759
- "fieldName": "maxRowHeightVh"
41619
+ "default": "false",
41620
+ "description": "Whether the upload for this image has failed.\nShows an error overlay with a retry button.",
41621
+ "fieldName": "failed"
41760
41622
  },
41761
41623
  {
41762
41624
  "name": "scheme",
@@ -41800,173 +41662,56 @@
41800
41662
  "name": "EspalierElementBase",
41801
41663
  "module": "dist/shared/esp-element-base.js"
41802
41664
  },
41803
- "docPageTitle": {
41804
- "name": "Image",
41805
- "description": "Upload"
41806
- },
41807
- "docUrl": {
41808
- "name": "/components/image-upload",
41809
- "description": ""
41810
- },
41811
- "menuGroup": {
41812
- "name": "Form",
41813
- "description": "Controls"
41814
- },
41815
- "menuLabel": {
41816
- "name": "Image",
41817
- "description": "Upload"
41818
- },
41819
- "menuIcon": {
41820
- "name": "photo-up",
41821
- "description": ""
41822
- },
41823
- "tagName": "esp-image-upload",
41665
+ "tagName": "esp-image-preview",
41824
41666
  "customElement": true
41825
41667
  }
41826
41668
  ],
41827
41669
  "exports": [
41828
41670
  {
41829
41671
  "kind": "js",
41830
- "name": "EspalierImageUpload",
41672
+ "name": "EspalierImagePreview",
41831
41673
  "declaration": {
41832
- "name": "EspalierImageUpload",
41833
- "module": "dist/image-upload/esp-image-upload.js"
41674
+ "name": "EspalierImagePreview",
41675
+ "module": "dist/image-upload/esp-image-preview.js"
41834
41676
  }
41835
41677
  },
41836
41678
  {
41837
41679
  "kind": "custom-element-definition",
41838
- "name": "esp-image-upload",
41680
+ "name": "esp-image-preview",
41839
41681
  "declaration": {
41840
- "name": "EspalierImageUpload",
41841
- "module": "dist/image-upload/esp-image-upload.js"
41682
+ "name": "EspalierImagePreview",
41683
+ "module": "dist/image-upload/esp-image-preview.js"
41842
41684
  }
41843
41685
  }
41844
41686
  ]
41845
41687
  },
41846
41688
  {
41847
41689
  "kind": "javascript-module",
41848
- "path": "dist/image-upload/image-helpers.js",
41690
+ "path": "dist/image-upload/esp-image-upload.js",
41849
41691
  "declarations": [
41850
41692
  {
41851
- "kind": "function",
41852
- "name": "getImageDetails",
41853
- "return": {
41854
- "type": {
41855
- "text": "Promise<SelectedUploadImage>"
41856
- }
41857
- },
41858
- "parameters": [
41693
+ "kind": "class",
41694
+ "description": "Used to upload images.\n\n```html\n<esp-image-upload></esp-image-upload>\n```\n\n**Uploading new images**\n\nThe `esp-image-upload-file-selected` event detail provides the `image`\nreference (the actual object in `uploadedImages`) plus\n`onProgress`, `onComplete`, and `onFailed` callbacks\nbound to it, and a `signal` that aborts if the user removes\nthe image while it is still uploading. The same shape is\nused for `esp-image-upload-retry`.\n\n```html\n<script>\n // Stubs — replace with your real upload/delete logic.\n function uploadToServer(file, opts) {\n let pct = 0;\n const id = setInterval(() => {\n pct = Math.min(pct + 20, 100);\n if (opts.onProgress) opts.onProgress(pct);\n if (pct >= 100) { clearInterval(id); }\n }, 200);\n return new Promise((r) => setTimeout(() => r(\"id-\" + file.name), 1200));\n }\n function deleteFromServer(id) { console.log(\"delete\", id); }\n\n const uploader = findByTagName(\"esp-image-upload\")[0];\n uploader.addEventListener(\"esp-image-upload-file-selected\", (e) => {\n const { image, signal, onProgress, onComplete, onFailed } = e.detail;\n // Pass `signal` to fetch/XHR so removing the image cancels the upload.\n uploadToServer(image.file, {\n signal,\n onProgress: (pct) => onProgress(pct),\n }).then((id) => onComplete(id))\n .catch(() => onFailed());\n });\n uploader.addEventListener(\"esp-image-upload-retry\", (e) => {\n const { image, signal, onProgress, onComplete } = e.detail;\n uploadToServer(image.file, {\n signal,\n onProgress: (pct) => onProgress(pct),\n }).then((id) => onComplete(id));\n });\n uploader.addEventListener(\"esp-image-upload-file-removed\", (e) => {\n deleteFromServer(e.detail.uploadedId);\n });\n</script>\n<esp-image-upload></esp-image-upload>\n```\n\n**Simulated upload progress demo**\n\nSelect images to see simulated progress. The second file\nwill fail — click Retry to re-upload it.\n\n```html\n<script>\n const uploader = findByTagName(\"esp-image-upload\")[0];\n let fileIndex = 0;\n\n function simulateUpload(detail, shouldFail) {\n let progress = 0;\n const interval = setInterval(() => {\n progress += Math.floor(Math.random() * 11) + 5;\n if (shouldFail && progress >= 45) {\n clearInterval(interval);\n detail.onFailed();\n return;\n }\n if (progress >= 100) {\n clearInterval(interval);\n detail.onProgress(100);\n setTimeout(() => detail.onComplete(\"id-\" + detail.image.file.name), 500);\n return;\n }\n detail.onProgress(progress);\n }, 300 + Math.random() * 300);\n }\n\n uploader.addEventListener(\"esp-image-upload-file-selected\", (e) => {\n const idx = fileIndex++;\n simulateUpload(e.detail, idx === 1);\n });\n\n uploader.addEventListener(\"esp-image-upload-retry\", (e) => {\n simulateUpload(e.detail, false);\n });\n</script>\n<esp-image-upload></esp-image-upload>\n```\n\n**Editing with existing images**\n\nPre-populate with server images via `setExistingImages`.\nExisting images never show upload overlays.\n\n```html\n<script>\n const uploader = findByTagName(\"esp-image-upload\")[0];\n uploader.setExistingImages([\n { url: \"https://picsum.photos/id/29/1200/800\", width: 1200, height: 800, uploadedId: \"img-1\" },\n { url: \"https://picsum.photos/id/15/900/1200\", width: 900, height: 1200, uploadedId: \"img-2\" },\n ]);\n uploader.addEventListener(\"esp-image-upload-file-removed\", (e) => {\n if (e.detail.source === \"existing\") {\n console.log(\"Mark for deletion:\", e.detail.uploadedId);\n }\n });\n</script>\n<esp-image-upload></esp-image-upload>\n```",
41695
+ "name": "EspalierImageUpload",
41696
+ "cssProperties": [
41859
41697
  {
41860
- "name": "file",
41861
- "type": {
41862
- "text": "File"
41863
- }
41698
+ "description": "The background color of the image preview area.",
41699
+ "name": "--esp-image-upload-preview-background"
41864
41700
  },
41865
41701
  {
41866
- "name": "options",
41867
- "optional": true,
41868
- "type": {
41869
- "text": "ImageDetailsOptions"
41702
+ "description": "Background color of the shared field shell. Defaults to `var(--esp-color-layer-2)`.",
41703
+ "name": "--esp-field-background",
41704
+ "inheritedFrom": {
41705
+ "name": "EspalierElementBase",
41706
+ "module": "dist/shared/esp-element-base.js"
41870
41707
  }
41871
- }
41872
- ],
41873
- "description": "Measure a selected file and produce a `SelectedUploadImage` whose `url`\nis a lightweight object URL suitable for previews (downscaled for large\nraster images). Rejects when the file cannot be read or decoded.\n\nThe returned `url` is an object URL owned by the caller — release it\nwith releasePreviewUrl when the image is discarded."
41874
- },
41875
- {
41876
- "kind": "function",
41877
- "name": "releasePreviewUrl",
41878
- "return": {
41879
- "type": {
41880
- "text": "void"
41881
- }
41882
- },
41883
- "parameters": [
41708
+ },
41884
41709
  {
41885
- "name": "image",
41886
- "type": {
41887
- "text": "EspalierUploadImage"
41888
- }
41889
- }
41890
- ],
41891
- "description": "Release the object URL backing a selected image's preview. Safe to call\non existing images — server URLs are never revoked."
41892
- }
41893
- ],
41894
- "exports": [
41895
- {
41896
- "kind": "js",
41897
- "name": "getImageDetails",
41898
- "declaration": {
41899
- "name": "getImageDetails",
41900
- "module": "dist/image-upload/image-helpers.js"
41901
- }
41902
- },
41903
- {
41904
- "kind": "js",
41905
- "name": "releasePreviewUrl",
41906
- "declaration": {
41907
- "name": "releasePreviewUrl",
41908
- "module": "dist/image-upload/image-helpers.js"
41909
- }
41910
- }
41911
- ]
41912
- },
41913
- {
41914
- "kind": "javascript-module",
41915
- "path": "dist/image-upload/preview-load-queue.js",
41916
- "declarations": [
41917
- {
41918
- "kind": "variable",
41919
- "name": "previewLoadQueue",
41920
- "default": "new PreviewLoadQueue(4)",
41921
- "description": "Four remote downloads is enough to fill a row without overwhelming an image service."
41922
- }
41923
- ],
41924
- "exports": [
41925
- {
41926
- "kind": "js",
41927
- "name": "previewLoadQueue",
41928
- "declaration": {
41929
- "name": "previewLoadQueue",
41930
- "module": "dist/image-upload/preview-load-queue.js"
41931
- }
41932
- }
41933
- ]
41934
- },
41935
- {
41936
- "kind": "javascript-module",
41937
- "path": "dist/image-picker/esp-image-picker.js",
41938
- "declarations": [
41939
- {
41940
- "kind": "class",
41941
- "description": "A form-associated image picker with large image choices and a selected preview.\n\nThe component is controlled: set `images` and `value` from consumer state,\nthen use `esp-value-changed` to persist a user's next selection. An empty\n`value` means the Automatic choice. Labels are optional; unlabeled images use\ntheir alternative text or a numbered name. Images are shown without cropping.\n\nThe large preview sits above the control by default. Set\n`preview-placement=\"beside\"` for a compact preview beside the control.\nSize the preview and option images with the CSS properties below.\n\n```html\n<esp-form-item label=\"Page cover\">\n <esp-image-picker name=\"cover\" value=\"field\"></esp-image-picker>\n</esp-form-item>\n<script>\n const picker = document.querySelector(\"esp-image-picker\");\n picker.images = [\n { id: \"field\", src: \"/assets/focus-picker-unsplash.jpg\" },\n { id: \"paper\", src: \"/assets/espalier-paper-texture.png\" },\n ];\n picker.addEventListener(\"esp-value-changed\", (event) => {\n picker.value = event.detail;\n });\n</script>\n```",
41942
- "name": "EspalierImagePicker",
41943
- "cssProperties": [
41944
- {
41945
- "description": "Height of the large preview above the control. Default 16rem.",
41946
- "name": "--esp-image-picker-preview-height"
41947
- },
41948
- {
41949
- "description": "Width of dropdown images, capped at 40vw on narrow screens. Default 12rem.",
41950
- "name": "--esp-image-picker-option-width"
41951
- },
41952
- {
41953
- "description": "Height of dropdown images. Images retain their aspect ratio. Default 8rem.",
41954
- "name": "--esp-image-picker-option-height"
41955
- },
41956
- {
41957
- "description": "Background color of the shared field shell. Defaults to `var(--esp-color-layer-2)`.",
41958
- "name": "--esp-field-background",
41959
- "inheritedFrom": {
41960
- "name": "EspalierElementBase",
41961
- "module": "dist/shared/esp-element-base.js"
41962
- }
41963
- },
41964
- {
41965
- "description": "Border color of the shared field shell. Defaults to `var(--esp-color-border)`.",
41966
- "name": "--esp-field-border-color",
41967
- "inheritedFrom": {
41968
- "name": "EspalierElementBase",
41969
- "module": "dist/shared/esp-element-base.js"
41710
+ "description": "Border color of the shared field shell. Defaults to `var(--esp-color-border)`.",
41711
+ "name": "--esp-field-border-color",
41712
+ "inheritedFrom": {
41713
+ "name": "EspalierElementBase",
41714
+ "module": "dist/shared/esp-element-base.js"
41970
41715
  }
41971
41716
  },
41972
41717
  {
@@ -42013,252 +41758,490 @@
42013
41758
  "members": [
42014
41759
  {
42015
41760
  "kind": "field",
42016
- "name": "formAssociated",
42017
- "type": {
42018
- "text": "boolean"
42019
- },
42020
- "static": true,
42021
- "default": "true"
41761
+ "name": "uploadInput",
41762
+ "privacy": "private"
42022
41763
  },
42023
41764
  {
42024
41765
  "kind": "field",
42025
- "name": "internals",
41766
+ "name": "previewsDiv",
42026
41767
  "privacy": "private"
42027
41768
  },
42028
41769
  {
42029
41770
  "kind": "field",
42030
- "name": "formCtrl",
42031
- "privacy": "private",
42032
- "default": "new FormFieldController({ host: this, internals: this.internals, getFormValue: () => (this.selectedImage ? this.value : null), getValidity: () => null, onReset: () => { this.value = \"\"; }, onRestore: (state: string) => { this.value = state; }, onDisabled: (isDisabled: boolean) => { this.disabled = isDisabled; }, })"
41771
+ "name": "dropAreaDiv",
41772
+ "privacy": "private"
42033
41773
  },
42034
41774
  {
42035
41775
  "kind": "field",
42036
- "name": "formItemRelay",
41776
+ "name": "draggingOver",
41777
+ "type": {
41778
+ "text": "boolean"
41779
+ },
42037
41780
  "privacy": "private",
42038
- "default": "new FormItemRelay(() => this.picker as EspalierFormField | undefined)"
41781
+ "default": "false"
42039
41782
  },
42040
41783
  {
42041
41784
  "kind": "field",
42042
- "name": "synchronizingPicker",
41785
+ "name": "uploadedImages",
42043
41786
  "type": {
42044
- "text": "boolean"
41787
+ "text": "Array<EspalierUploadImage>"
42045
41788
  },
42046
- "privacy": "private",
42047
- "default": "true"
41789
+ "default": "[]"
42048
41790
  },
42049
41791
  {
42050
41792
  "kind": "field",
42051
- "name": "pickerSyncGeneration",
41793
+ "name": "accept",
41794
+ "type": {
41795
+ "text": "string"
41796
+ },
41797
+ "default": "\"image/jpeg, image/png, image/webp\"",
41798
+ "description": "Comma-separated list of accepted file types, in the same format as the\nnative input `accept` attribute: MIME types (`image/png`), MIME\nwildcards (`image/*`), or extensions (`.png`). Files outside this list\nare skipped and reported via the `esp-image-upload-files-rejected` event.",
41799
+ "attribute": "accept"
41800
+ },
41801
+ {
41802
+ "kind": "field",
41803
+ "name": "maxImagesPerRow",
42052
41804
  "type": {
42053
41805
  "text": "number"
42054
41806
  },
42055
- "privacy": "private",
42056
- "default": "0"
41807
+ "description": "Maximum number of image previews in each justified row. Positive integers\ncreate a hard row boundary; omitted, non-finite, non-integer, and\nnonpositive values leave rows unlimited.",
41808
+ "attribute": "max-images-per-row"
42057
41809
  },
42058
41810
  {
42059
41811
  "kind": "field",
42060
- "name": "images",
41812
+ "name": "maxRowHeightVh",
41813
+ "default": "DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH",
41814
+ "description": "Maximum preview-row height as a percentage of the layout viewport. Values\noutside the inclusive integer range `1…100` fall back to 90.",
42061
41815
  "type": {
42062
- "text": "ImagePickerImage[]"
41816
+ "text": "number"
42063
41817
  },
42064
- "privacy": "public",
42065
- "default": "[]",
42066
- "description": "Image candidates, kept in the supplied order.",
42067
- "attribute": "images"
41818
+ "attribute": "max-row-height-vh"
42068
41819
  },
42069
41820
  {
42070
41821
  "kind": "field",
42071
- "name": "value",
41822
+ "name": "_rejectionNotice",
42072
41823
  "type": {
42073
41824
  "text": "string"
42074
41825
  },
42075
- "privacy": "public",
41826
+ "privacy": "private",
42076
41827
  "default": "\"\"",
42077
- "description": "Selected image ID. An empty string selects Automatic.",
42078
- "attribute": "value"
41828
+ "description": "Transient inline message describing skipped files."
42079
41829
  },
42080
41830
  {
42081
41831
  "kind": "field",
42082
- "name": "previewPlacement",
41832
+ "name": "_noticeTimer",
42083
41833
  "type": {
42084
- "text": "\"above\" | \"beside\""
41834
+ "text": "ReturnType<typeof setTimeout> | undefined"
42085
41835
  },
42086
- "privacy": "public",
42087
- "default": "\"above\"",
42088
- "description": "Preview placement: above (default, large) or beside (compact).",
42089
- "attribute": "preview-placement",
42090
- "reflects": true
41836
+ "privacy": "private"
42091
41837
  },
42092
41838
  {
42093
41839
  "kind": "field",
42094
- "name": "disabled",
41840
+ "name": "_uploadState",
41841
+ "privacy": "private",
41842
+ "default": "new WeakMap<EspalierUploadImage, UploadTrackingState>()"
41843
+ },
41844
+ {
41845
+ "kind": "field",
41846
+ "name": "_selectionGeneration",
42095
41847
  "type": {
42096
- "text": "boolean"
41848
+ "text": "number"
42097
41849
  },
42098
- "privacy": "public",
42099
- "default": "false",
42100
- "description": "Disables the picker trigger.",
42101
- "attribute": "disabled",
42102
- "reflects": true
41850
+ "privacy": "private",
41851
+ "default": "0",
41852
+ "description": "Bumped whenever the image list is replaced or the component unmounts so\nstill-decoding selections from before the change are discarded instead\nof landing in the new list."
42103
41853
  },
42104
41854
  {
42105
41855
  "kind": "field",
42106
- "name": "loading",
41856
+ "name": "_chromeWidth",
42107
41857
  "type": {
42108
- "text": "boolean"
41858
+ "text": "number | null"
42109
41859
  },
42110
- "privacy": "public",
42111
- "default": "false",
42112
- "description": "Shows a loading state while candidates are being fetched.",
42113
- "attribute": "loading",
42114
- "reflects": true
41860
+ "privacy": "private",
41861
+ "default": "null",
41862
+ "description": "Cached horizontal chrome (previews padding + field border); re-measured after resize."
42115
41863
  },
42116
41864
  {
42117
41865
  "kind": "field",
42118
- "name": "emptyMessage",
41866
+ "name": "_resizeObserver",
41867
+ "privacy": "private",
41868
+ "default": "new ResizeObserver(() => { this._chromeWidth = null; this.requestUpdate(); })"
41869
+ },
41870
+ {
41871
+ "kind": "field",
41872
+ "name": "_handleViewportResize",
41873
+ "privacy": "private",
41874
+ "description": "Recalculate the viewport-derived row ceiling when only height changes."
41875
+ },
41876
+ {
41877
+ "kind": "field",
41878
+ "name": "_dragPointerId",
42119
41879
  "type": {
42120
- "text": "string"
41880
+ "text": "number | null"
42121
41881
  },
42122
- "privacy": "public",
42123
- "default": "\"No images available.\"",
42124
- "description": "Message shown when no image candidates are available.",
42125
- "attribute": "empty-message"
41882
+ "privacy": "private",
41883
+ "default": "null",
41884
+ "description": "The pointerId that initiated the drag — ignore events from other pointers."
42126
41885
  },
42127
41886
  {
42128
41887
  "kind": "field",
42129
- "name": "automaticLabel",
41888
+ "name": "_dragSourceIndex",
42130
41889
  "type": {
42131
- "text": "string"
41890
+ "text": "number | null"
42132
41891
  },
42133
- "privacy": "public",
42134
- "default": "\"Automatic\"",
42135
- "description": "Label for the empty-value choice.",
42136
- "attribute": "automatic-label"
41892
+ "privacy": "private",
41893
+ "default": "null"
42137
41894
  },
42138
41895
  {
42139
41896
  "kind": "field",
42140
- "name": "name",
41897
+ "name": "_dragOverIndex",
42141
41898
  "type": {
42142
- "text": "string"
41899
+ "text": "number | null"
42143
41900
  },
42144
- "privacy": "public",
42145
- "default": "\"\"",
42146
- "description": "The name used when this picker participates in a `<form>`.",
42147
- "attribute": "name",
42148
- "reflects": true
41901
+ "privacy": "private",
41902
+ "default": "null"
42149
41903
  },
42150
41904
  {
42151
- "kind": "method",
42152
- "name": "focus",
42153
- "privacy": "public",
42154
- "return": {
42155
- "type": {
42156
- "text": "void"
42157
- }
41905
+ "kind": "field",
41906
+ "name": "_dragStartX",
41907
+ "type": {
41908
+ "text": "number"
42158
41909
  },
42159
- "parameters": [
42160
- {
42161
- "name": "options",
42162
- "optional": true,
42163
- "type": {
42164
- "text": "FocusOptions"
42165
- }
42166
- }
42167
- ],
42168
- "description": "Focus the composed picker trigger."
41910
+ "privacy": "private",
41911
+ "default": "0"
42169
41912
  },
42170
41913
  {
42171
- "kind": "method",
42172
- "name": "validate",
42173
- "privacy": "public",
42174
- "return": {
42175
- "type": {
42176
- "text": "void"
42177
- }
41914
+ "kind": "field",
41915
+ "name": "_dragStartY",
41916
+ "type": {
41917
+ "text": "number"
42178
41918
  },
42179
- "description": "Re-run form validation."
41919
+ "privacy": "private",
41920
+ "default": "0"
41921
+ },
41922
+ {
41923
+ "kind": "field",
41924
+ "name": "_dragActive",
41925
+ "type": {
41926
+ "text": "boolean"
41927
+ },
41928
+ "privacy": "private",
41929
+ "default": "false"
41930
+ },
41931
+ {
41932
+ "kind": "field",
41933
+ "name": "_ghostEl",
41934
+ "type": {
41935
+ "text": "HTMLElement | null"
41936
+ },
41937
+ "privacy": "private",
41938
+ "default": "null"
41939
+ },
41940
+ {
41941
+ "kind": "field",
41942
+ "name": "_ghostHalfW",
41943
+ "type": {
41944
+ "text": "number"
41945
+ },
41946
+ "privacy": "private",
41947
+ "default": "0",
41948
+ "description": "Cached ghost half-width/height so pointermove avoids offsetWidth/Height."
41949
+ },
41950
+ {
41951
+ "kind": "field",
41952
+ "name": "_ghostHalfH",
41953
+ "type": {
41954
+ "text": "number"
41955
+ },
41956
+ "privacy": "private",
41957
+ "default": "0"
41958
+ },
41959
+ {
41960
+ "kind": "field",
41961
+ "name": "_arrowEl",
41962
+ "type": {
41963
+ "text": "HTMLElement | null"
41964
+ },
41965
+ "privacy": "private",
41966
+ "default": "null"
41967
+ },
41968
+ {
41969
+ "kind": "field",
41970
+ "name": "_cachedPreviews",
41971
+ "type": {
41972
+ "text": "{ el: HTMLElement; rect: DOMRect }[] | null"
41973
+ },
41974
+ "privacy": "private",
41975
+ "default": "null",
41976
+ "description": "Cached preview elements + bounding rects, set once when drag activates."
41977
+ },
41978
+ {
41979
+ "kind": "field",
41980
+ "name": "_lastDropHit",
41981
+ "type": {
41982
+ "text": "{ index: number; after: boolean } | null"
41983
+ },
41984
+ "privacy": "private",
41985
+ "default": "null",
41986
+ "description": "Last drop-target state to avoid redundant DOM updates in pointermove."
41987
+ },
41988
+ {
41989
+ "kind": "field",
41990
+ "name": "_savedBodyUserSelect",
41991
+ "type": {
41992
+ "text": "string"
41993
+ },
41994
+ "privacy": "private",
41995
+ "default": "\"\"",
41996
+ "description": "Saved body userSelect value to restore after drag."
41997
+ },
41998
+ {
41999
+ "kind": "field",
42000
+ "name": "_DRAG_THRESHOLD",
42001
+ "type": {
42002
+ "text": "number"
42003
+ },
42004
+ "privacy": "private",
42005
+ "static": true,
42006
+ "readonly": true,
42007
+ "default": "8"
42180
42008
  },
42181
42009
  {
42182
42010
  "kind": "method",
42183
- "name": "checkValidity",
42184
- "privacy": "public",
42011
+ "name": "_getPreviewIndex",
42012
+ "privacy": "private",
42185
42013
  "return": {
42186
42014
  "type": {
42187
- "text": "boolean"
42015
+ "text": "number | null"
42188
42016
  }
42189
42017
  },
42190
- "description": "Check form validity."
42018
+ "parameters": [
42019
+ {
42020
+ "name": "ev",
42021
+ "type": {
42022
+ "text": "Event"
42023
+ }
42024
+ }
42025
+ ],
42026
+ "description": "Find the preview index from a composedPath."
42027
+ },
42028
+ {
42029
+ "kind": "field",
42030
+ "name": "_handleDragPointerDown",
42031
+ "privacy": "private"
42032
+ },
42033
+ {
42034
+ "kind": "field",
42035
+ "name": "_onDocPointerMove",
42036
+ "privacy": "private"
42037
+ },
42038
+ {
42039
+ "kind": "field",
42040
+ "name": "_onDocPointerUp",
42041
+ "privacy": "private"
42191
42042
  },
42192
42043
  {
42193
42044
  "kind": "method",
42194
- "name": "formResetCallback",
42195
- "privacy": "public",
42045
+ "name": "_clearDragState",
42046
+ "privacy": "private"
42047
+ },
42048
+ {
42049
+ "kind": "method",
42050
+ "name": "_createGhost",
42051
+ "privacy": "private",
42052
+ "parameters": [
42053
+ {
42054
+ "name": "x",
42055
+ "type": {
42056
+ "text": "number"
42057
+ }
42058
+ },
42059
+ {
42060
+ "name": "y",
42061
+ "type": {
42062
+ "text": "number"
42063
+ }
42064
+ }
42065
+ ],
42066
+ "description": "Create a ghost thumbnail that follows the cursor."
42067
+ },
42068
+ {
42069
+ "kind": "field",
42070
+ "name": "_arrowColor",
42071
+ "type": {
42072
+ "text": "string | null"
42073
+ },
42074
+ "privacy": "private",
42075
+ "default": "null",
42076
+ "description": "Cached arrow color so we don't call getComputedStyle on every update."
42077
+ },
42078
+ {
42079
+ "kind": "method",
42080
+ "name": "_updateDropTargets",
42081
+ "privacy": "private",
42082
+ "parameters": [
42083
+ {
42084
+ "name": "previews",
42085
+ "type": {
42086
+ "text": "HTMLElement[]"
42087
+ }
42088
+ },
42089
+ {
42090
+ "name": "hitIndex",
42091
+ "type": {
42092
+ "text": "number"
42093
+ }
42094
+ },
42095
+ {
42096
+ "name": "insertAfter",
42097
+ "type": {
42098
+ "text": "boolean"
42099
+ }
42100
+ }
42101
+ ],
42102
+ "description": "Show a drop-target overlay on the hovered preview."
42103
+ },
42104
+ {
42105
+ "kind": "method",
42106
+ "name": "_clearDropTargets",
42107
+ "privacy": "private",
42108
+ "description": "Clear all drop-target overlays."
42109
+ },
42110
+ {
42111
+ "kind": "method",
42112
+ "name": "getContainerWidth",
42113
+ "privacy": "private",
42196
42114
  "return": {
42197
42115
  "type": {
42198
- "text": "void"
42116
+ "text": "number"
42199
42117
  }
42200
42118
  },
42201
- "description": "Called by the browser when the owning form resets."
42119
+ "description": "Gets the container width for layout calculation based on responsive breakpoints.\nBreakpoints chosen to maintain consistent visual appearance across devices:\n- Mobile (< 640px): Full width minus padding\n- Tablet (640px - 1024px): 90% width\n- Desktop (> 1024px): 85% width with max 1400px"
42202
42120
  },
42203
42121
  {
42204
42122
  "kind": "method",
42205
- "name": "formStateRestoreCallback",
42206
- "privacy": "public",
42123
+ "name": "_isAccepted",
42124
+ "privacy": "private",
42207
42125
  "return": {
42208
42126
  "type": {
42209
- "text": "void"
42127
+ "text": "boolean"
42210
42128
  }
42211
42129
  },
42212
42130
  "parameters": [
42213
42131
  {
42214
- "name": "state",
42132
+ "name": "file",
42215
42133
  "type": {
42216
- "text": "string"
42134
+ "text": "File"
42217
42135
  }
42218
42136
  }
42219
42137
  ],
42220
- "description": "Called by the browser when form state is restored."
42138
+ "description": "Check a file against the `accept` list (MIME, MIME wildcard, or extension)."
42139
+ },
42140
+ {
42141
+ "kind": "field",
42142
+ "name": "filesSelected",
42143
+ "privacy": "private"
42221
42144
  },
42222
42145
  {
42223
42146
  "kind": "method",
42224
- "name": "formDisabledCallback",
42225
- "privacy": "public",
42226
- "return": {
42227
- "type": {
42228
- "text": "void"
42147
+ "name": "_addSelectedImage",
42148
+ "privacy": "private",
42149
+ "parameters": [
42150
+ {
42151
+ "name": "batch",
42152
+ "type": {
42153
+ "text": "(SelectedUploadImage | null)[]"
42154
+ }
42155
+ },
42156
+ {
42157
+ "name": "index",
42158
+ "type": {
42159
+ "text": "number"
42160
+ }
42161
+ },
42162
+ {
42163
+ "name": "image",
42164
+ "type": {
42165
+ "text": "SelectedUploadImage"
42166
+ }
42229
42167
  }
42230
- },
42168
+ ],
42169
+ "description": "Insert a processed image at its selection-order position. Anchors on\nalready-inserted batch neighbors so concurrent completions, removals,\nand reorders mid-batch cannot scramble the order."
42170
+ },
42171
+ {
42172
+ "kind": "method",
42173
+ "name": "_reportRejectedFiles",
42174
+ "privacy": "private",
42231
42175
  "parameters": [
42232
42176
  {
42233
- "name": "isDisabled",
42177
+ "name": "detail",
42234
42178
  "type": {
42235
- "text": "boolean"
42179
+ "text": "FilesRejectedDetail"
42236
42180
  }
42237
42181
  }
42238
42182
  ],
42239
- "description": "Called by the browser when an ancestor fieldset changes disabled state."
42183
+ "description": "Dispatch `esp-image-upload-files-rejected` and show the transient inline notice."
42240
42184
  },
42241
42185
  {
42242
42186
  "kind": "field",
42243
- "name": "picker",
42244
- "type": {
42245
- "text": "EspalierPickOne | undefined"
42246
- },
42187
+ "name": "_makeCallbacks",
42247
42188
  "privacy": "private",
42248
- "readonly": true
42189
+ "description": "Create upload callbacks bound to a specific image.\nClosures capture the image reference directly — no filename lookup."
42249
42190
  },
42250
42191
  {
42251
42192
  "kind": "field",
42252
- "name": "selectedImage",
42193
+ "name": "_THUMBNAIL_UPSCALE_SLACK",
42253
42194
  "type": {
42254
- "text": "ImagePickerImage | undefined"
42195
+ "text": "number"
42255
42196
  },
42256
42197
  "privacy": "private",
42257
- "readonly": true
42198
+ "static": true,
42199
+ "readonly": true,
42200
+ "default": "1.1",
42201
+ "description": "Allowed upscale factor before a preview switches to its full-resolution source."
42202
+ },
42203
+ {
42204
+ "kind": "field",
42205
+ "name": "_fullPreviewUrls",
42206
+ "privacy": "private",
42207
+ "default": "new Map<SelectedUploadImage, string>()",
42208
+ "description": "Full-resolution object URLs for selected images rendered beyond thumbnail capacity."
42209
+ },
42210
+ {
42211
+ "kind": "method",
42212
+ "name": "_previewUrlFor",
42213
+ "privacy": "private",
42214
+ "return": {
42215
+ "type": {
42216
+ "text": "string"
42217
+ }
42218
+ },
42219
+ "parameters": [
42220
+ {
42221
+ "name": "image",
42222
+ "type": {
42223
+ "text": "EspalierUploadImage"
42224
+ }
42225
+ },
42226
+ {
42227
+ "name": "renderedHeight",
42228
+ "type": {
42229
+ "text": "number"
42230
+ }
42231
+ },
42232
+ {
42233
+ "name": "renderedWidth",
42234
+ "optional": true,
42235
+ "type": {
42236
+ "text": "number"
42237
+ }
42238
+ }
42239
+ ],
42240
+ "description": "Resolve the URL needed to cover both dimensions of the rendered cell.\nThumbnails cover rows near the target height; images stretched well\nbeyond thumbnail capacity (clamped tall rows, single images) lazily\nswitch to a full-resolution object URL so they don't upscale blurry."
42258
42241
  },
42259
42242
  {
42260
42243
  "kind": "method",
42261
- "name": "imageLabel",
42244
+ "name": "_pickExistingPreviewUrl",
42262
42245
  "privacy": "private",
42263
42246
  "return": {
42264
42247
  "type": {
@@ -42269,54 +42252,43 @@
42269
42252
  {
42270
42253
  "name": "image",
42271
42254
  "type": {
42272
- "text": "ImagePickerImage"
42255
+ "text": "ExistingUploadImage"
42273
42256
  }
42274
42257
  },
42275
42258
  {
42276
- "name": "index",
42259
+ "name": "renderedHeight",
42277
42260
  "type": {
42278
42261
  "text": "number"
42279
42262
  }
42280
42263
  }
42281
- ]
42282
- },
42283
- {
42284
- "kind": "field",
42285
- "name": "pickerItems",
42286
- "type": {
42287
- "text": "PickerItem[]"
42288
- },
42289
- "privacy": "private",
42290
- "readonly": true
42264
+ ],
42265
+ "description": "For a server image, pick the smallest responsive variant that covers the\npreview's rendered box (× DPR), falling back to the largest variant — and to\nthe single `url` when no responsive set was supplied. The supplied height is the full source height\nrequired for cover (including any clipped overflow), so the required width\nis `renderedHeight × aspect`."
42291
42266
  },
42292
42267
  {
42293
42268
  "kind": "method",
42294
- "name": "thumbnailNode",
42269
+ "name": "_releaseFullPreviewUrl",
42295
42270
  "privacy": "private",
42296
- "return": {
42297
- "type": {
42298
- "text": "HTMLImageElement"
42299
- }
42300
- },
42301
42271
  "parameters": [
42302
42272
  {
42303
42273
  "name": "image",
42304
42274
  "type": {
42305
- "text": "ImagePickerImage"
42306
- }
42307
- },
42308
- {
42309
- "name": "alt",
42310
- "type": {
42311
- "text": "string"
42275
+ "text": "EspalierUploadImage"
42312
42276
  }
42313
42277
  }
42314
- ]
42278
+ ],
42279
+ "description": "Revoke the full-resolution preview URL for one image, if it exists."
42280
+ },
42281
+ {
42282
+ "kind": "method",
42283
+ "name": "_releaseSelectedImages",
42284
+ "privacy": "private",
42285
+ "description": "Abort in-flight uploads and revoke preview object URLs for selected images."
42315
42286
  },
42316
42287
  {
42317
42288
  "kind": "field",
42318
- "name": "handlePickerValueChanged",
42319
- "privacy": "private"
42289
+ "name": "setExistingImages",
42290
+ "privacy": "public",
42291
+ "description": "Populate the component with images that already exist on the server.\nEach entry must provide a display URL, dimensions for layout, and\nan `uploadedId` that identifies the server-side image.\n\nEntries with missing `url`/`uploadedId` or non-finite/non-positive\ndimensions are silently filtered out."
42320
42292
  },
42321
42293
  {
42322
42294
  "kind": "field",
@@ -43046,91 +43018,66 @@
43046
43018
  "events": [
43047
43019
  {
43048
43020
  "type": {
43049
- "text": "CustomEvent<string>"
43050
- },
43051
- "description": "Fired when a user chooses an image or Automatic. The detail is the selected image ID, or an empty string for Automatic.",
43052
- "name": "esp-value-changed"
43053
- },
43054
- {
43055
- "type": {
43056
- "text": "CustomEvent<{ valid: boolean; message: string }>"
43057
- },
43058
- "description": "Fired whenever form validation runs.",
43059
- "name": "esp-validity-changed"
43060
- }
43061
- ],
43062
- "attributes": [
43063
- {
43064
- "name": "images",
43065
- "type": {
43066
- "text": "ImagePickerImage[]"
43021
+ "text": "CustomEvent<EspalierUploadImage>"
43067
43022
  },
43068
- "default": "[]",
43069
- "description": "Image candidates, kept in the supplied order.",
43070
- "fieldName": "images"
43023
+ "description": "Fired when an image has been removed by the user. Narrow on `detail.source` to distinguish newly selected images from pre-existing server images. If the image's upload was still in flight, its `signal` aborts.",
43024
+ "name": "esp-image-upload-file-removed"
43071
43025
  },
43072
43026
  {
43073
- "name": "value",
43074
43027
  "type": {
43075
- "text": "string"
43028
+ "text": "CustomEvent<UploadEventDetail>"
43076
43029
  },
43077
- "default": "\"\"",
43078
- "description": "Selected image ID. An empty string selects Automatic.",
43079
- "fieldName": "value"
43030
+ "description": "Fired when an image has been selected by the user. `detail.image` is the actual object stored in `uploadedImages`; `detail.onProgress`, `detail.onComplete`, and `detail.onFailed` are callbacks bound to that image. `detail.signal` aborts if the image is removed mid-upload — pass it to fetch/XHR.",
43031
+ "name": "esp-image-upload-file-selected"
43080
43032
  },
43081
43033
  {
43082
- "name": "preview-placement",
43083
43034
  "type": {
43084
- "text": "\"above\" | \"beside\""
43035
+ "text": "CustomEvent<UploadEventDetail>"
43085
43036
  },
43086
- "default": "\"above\"",
43087
- "description": "Preview placement: above (default, large) or beside (compact).",
43088
- "fieldName": "previewPlacement"
43037
+ "description": "Fired when the user clicks Retry on a failed upload. `detail.image` is the same object reference; fresh callbacks and a fresh `signal` are provided. The component automatically resets the image to indeterminate progress.",
43038
+ "name": "esp-image-upload-retry"
43089
43039
  },
43090
43040
  {
43091
- "name": "disabled",
43092
43041
  "type": {
43093
- "text": "boolean"
43042
+ "text": "CustomEvent<ImagesReorderedDetail>"
43094
43043
  },
43095
- "default": "false",
43096
- "description": "Disables the picker trigger.",
43097
- "fieldName": "disabled"
43044
+ "description": "Fired after the user drags an image to a new position. `detail.images` is the reordered array (same references, new order).",
43045
+ "name": "esp-image-upload-images-reordered"
43098
43046
  },
43099
43047
  {
43100
- "name": "loading",
43101
43048
  "type": {
43102
- "text": "boolean"
43049
+ "text": "CustomEvent<FilesRejectedDetail>"
43103
43050
  },
43104
- "default": "false",
43105
- "description": "Shows a loading state while candidates are being fetched.",
43106
- "fieldName": "loading"
43107
- },
43051
+ "description": "Fired when selected files are skipped, either because their type is not accepted (`detail.unsupported`) or because they could not be read or decoded (`detail.unreadable`). The component also shows a transient inline notice.",
43052
+ "name": "esp-image-upload-files-rejected"
43053
+ }
43054
+ ],
43055
+ "attributes": [
43108
43056
  {
43109
- "name": "empty-message",
43057
+ "name": "accept",
43110
43058
  "type": {
43111
43059
  "text": "string"
43112
43060
  },
43113
- "default": "\"No images available.\"",
43114
- "description": "Message shown when no image candidates are available.",
43115
- "fieldName": "emptyMessage"
43061
+ "default": "\"image/jpeg, image/png, image/webp\"",
43062
+ "description": "Comma-separated list of accepted file types, in the same format as the\nnative input `accept` attribute: MIME types (`image/png`), MIME\nwildcards (`image/*`), or extensions (`.png`). Files outside this list\nare skipped and reported via the `esp-image-upload-files-rejected` event.",
43063
+ "fieldName": "accept"
43116
43064
  },
43117
43065
  {
43118
- "name": "automatic-label",
43066
+ "name": "max-images-per-row",
43119
43067
  "type": {
43120
- "text": "string"
43068
+ "text": "number"
43121
43069
  },
43122
- "default": "\"Automatic\"",
43123
- "description": "Label for the empty-value choice.",
43124
- "fieldName": "automaticLabel"
43070
+ "description": "Maximum number of image previews in each justified row. Positive integers\ncreate a hard row boundary; omitted, non-finite, non-integer, and\nnonpositive values leave rows unlimited.",
43071
+ "fieldName": "maxImagesPerRow"
43125
43072
  },
43126
43073
  {
43127
- "name": "name",
43074
+ "name": "max-row-height-vh",
43075
+ "default": "DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH",
43076
+ "description": "Maximum preview-row height as a percentage of the layout viewport. Values\noutside the inclusive integer range `1…100` fall back to 90.",
43128
43077
  "type": {
43129
- "text": "string"
43078
+ "text": "number"
43130
43079
  },
43131
- "default": "\"\"",
43132
- "description": "The name used when this picker participates in a `<form>`.",
43133
- "fieldName": "name"
43080
+ "fieldName": "maxRowHeightVh"
43134
43081
  },
43135
43082
  {
43136
43083
  "name": "scheme",
@@ -43174,14 +43121,12 @@
43174
43121
  "name": "EspalierElementBase",
43175
43122
  "module": "dist/shared/esp-element-base.js"
43176
43123
  },
43177
- "tagName": "esp-image-picker",
43178
- "customElement": true,
43179
43124
  "docPageTitle": {
43180
43125
  "name": "Image",
43181
- "description": "Picker"
43126
+ "description": "Upload"
43182
43127
  },
43183
43128
  "docUrl": {
43184
- "name": "/components/image-picker",
43129
+ "name": "/components/image-upload",
43185
43130
  "description": ""
43186
43131
  },
43187
43132
  "menuGroup": {
@@ -43190,25 +43135,120 @@
43190
43135
  },
43191
43136
  "menuLabel": {
43192
43137
  "name": "Image",
43193
- "description": "Picker"
43194
- }
43138
+ "description": "Upload"
43139
+ },
43140
+ "menuIcon": {
43141
+ "name": "photo-up",
43142
+ "description": ""
43143
+ },
43144
+ "tagName": "esp-image-upload",
43145
+ "customElement": true
43195
43146
  }
43196
43147
  ],
43197
43148
  "exports": [
43198
43149
  {
43199
43150
  "kind": "js",
43200
- "name": "EspalierImagePicker",
43151
+ "name": "EspalierImageUpload",
43201
43152
  "declaration": {
43202
- "name": "EspalierImagePicker",
43203
- "module": "dist/image-picker/esp-image-picker.js"
43153
+ "name": "EspalierImageUpload",
43154
+ "module": "dist/image-upload/esp-image-upload.js"
43204
43155
  }
43205
43156
  },
43206
43157
  {
43207
43158
  "kind": "custom-element-definition",
43208
- "name": "esp-image-picker",
43159
+ "name": "esp-image-upload",
43209
43160
  "declaration": {
43210
- "name": "EspalierImagePicker",
43211
- "module": "dist/image-picker/esp-image-picker.js"
43161
+ "name": "EspalierImageUpload",
43162
+ "module": "dist/image-upload/esp-image-upload.js"
43163
+ }
43164
+ }
43165
+ ]
43166
+ },
43167
+ {
43168
+ "kind": "javascript-module",
43169
+ "path": "dist/image-upload/image-helpers.js",
43170
+ "declarations": [
43171
+ {
43172
+ "kind": "function",
43173
+ "name": "getImageDetails",
43174
+ "return": {
43175
+ "type": {
43176
+ "text": "Promise<SelectedUploadImage>"
43177
+ }
43178
+ },
43179
+ "parameters": [
43180
+ {
43181
+ "name": "file",
43182
+ "type": {
43183
+ "text": "File"
43184
+ }
43185
+ },
43186
+ {
43187
+ "name": "options",
43188
+ "optional": true,
43189
+ "type": {
43190
+ "text": "ImageDetailsOptions"
43191
+ }
43192
+ }
43193
+ ],
43194
+ "description": "Measure a selected file and produce a `SelectedUploadImage` whose `url`\nis a lightweight object URL suitable for previews (downscaled for large\nraster images). Rejects when the file cannot be read or decoded.\n\nThe returned `url` is an object URL owned by the caller — release it\nwith releasePreviewUrl when the image is discarded."
43195
+ },
43196
+ {
43197
+ "kind": "function",
43198
+ "name": "releasePreviewUrl",
43199
+ "return": {
43200
+ "type": {
43201
+ "text": "void"
43202
+ }
43203
+ },
43204
+ "parameters": [
43205
+ {
43206
+ "name": "image",
43207
+ "type": {
43208
+ "text": "EspalierUploadImage"
43209
+ }
43210
+ }
43211
+ ],
43212
+ "description": "Release the object URL backing a selected image's preview. Safe to call\non existing images — server URLs are never revoked."
43213
+ }
43214
+ ],
43215
+ "exports": [
43216
+ {
43217
+ "kind": "js",
43218
+ "name": "getImageDetails",
43219
+ "declaration": {
43220
+ "name": "getImageDetails",
43221
+ "module": "dist/image-upload/image-helpers.js"
43222
+ }
43223
+ },
43224
+ {
43225
+ "kind": "js",
43226
+ "name": "releasePreviewUrl",
43227
+ "declaration": {
43228
+ "name": "releasePreviewUrl",
43229
+ "module": "dist/image-upload/image-helpers.js"
43230
+ }
43231
+ }
43232
+ ]
43233
+ },
43234
+ {
43235
+ "kind": "javascript-module",
43236
+ "path": "dist/image-upload/preview-load-queue.js",
43237
+ "declarations": [
43238
+ {
43239
+ "kind": "variable",
43240
+ "name": "previewLoadQueue",
43241
+ "default": "new PreviewLoadQueue(4)",
43242
+ "description": "Four remote downloads is enough to fill a row without overwhelming an image service."
43243
+ }
43244
+ ],
43245
+ "exports": [
43246
+ {
43247
+ "kind": "js",
43248
+ "name": "previewLoadQueue",
43249
+ "declaration": {
43250
+ "name": "previewLoadQueue",
43251
+ "module": "dist/image-upload/preview-load-queue.js"
43212
43252
  }
43213
43253
  }
43214
43254
  ]