@aglyn/besigner-ui 1.0.0-beta.221 → 1.0.0-beta.223

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/element-props-form.component.d.ts +21 -20
  3. package/src/lib/components/element-props-form.component.js +63 -75
  4. package/src/lib/components/element-props-form.component.js.map +1 -1
  5. package/src/lib/components/empty-document-slot.d.ts +4 -1
  6. package/src/lib/components/empty-document-slot.js +7 -2
  7. package/src/lib/components/empty-document-slot.js.map +1 -1
  8. package/src/lib/components/node-leaf.d.ts +8 -5
  9. package/src/lib/components/node-leaf.js +39 -12
  10. package/src/lib/components/node-leaf.js.map +1 -1
  11. package/src/lib/components/viewport-frame.component.js +18 -2
  12. package/src/lib/components/viewport-frame.component.js.map +1 -1
  13. package/src/lib/contexts/canvas-page-record-context.d.ts +35 -0
  14. package/src/lib/contexts/canvas-page-record-context.js +31 -0
  15. package/src/lib/contexts/canvas-page-record-context.js.map +1 -0
  16. package/src/lib/contexts/repeat-record-context.d.ts +3 -4
  17. package/src/lib/contexts/repeat-record-context.js.map +1 -1
  18. package/src/lib/contexts/repeat-rows-context.d.ts +1 -1
  19. package/src/lib/contexts/repeat-rows-context.js.map +1 -1
  20. package/src/lib/hooks/use-besigner-document.d.ts +17 -2
  21. package/src/lib/hooks/use-besigner-document.js +39 -3
  22. package/src/lib/hooks/use-besigner-document.js.map +1 -1
  23. package/src/lib/hooks/use-insert-token-options.js +5 -5
  24. package/src/lib/hooks/use-insert-token-options.js.map +1 -1
  25. package/src/lib/hooks/use-node-with-bindings.d.ts +44 -0
  26. package/src/lib/hooks/use-node-with-bindings.js +72 -0
  27. package/src/lib/hooks/use-node-with-bindings.js.map +1 -0
  28. package/src/lib/hooks/use-repeat-preview.d.ts +16 -3
  29. package/src/lib/hooks/use-repeat-preview.js +16 -3
  30. package/src/lib/hooks/use-repeat-preview.js.map +1 -1
  31. package/src/lib/utils/docs-help.generated.d.ts +2 -2
  32. package/src/lib/utils/docs-help.generated.js +3 -0
  33. package/src/lib/utils/docs-help.generated.js.map +1 -1
  34. package/src/lib/utils/normalize-canvas-binding-tokens.d.ts +52 -0
  35. package/src/lib/utils/normalize-canvas-binding-tokens.js +63 -0
  36. package/src/lib/utils/normalize-canvas-binding-tokens.js.map +1 -0
  37. package/src/lib/utils/record-canvas-rendered-widths.d.ts +48 -0
  38. package/src/lib/utils/record-canvas-rendered-widths.js +72 -0
  39. package/src/lib/utils/record-canvas-rendered-widths.js.map +1 -0
  40. package/src/lib/utils/token-segments.js +9 -2
  41. package/src/lib/utils/token-segments.js.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/besigner-ui",
3
- "version": "1.0.0-beta.221",
3
+ "version": "1.0.0-beta.223",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,22 +25,22 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.221",
29
- "@aglyn/aglyn-markdown-editor": "1.0.0-beta.221",
30
- "@aglyn/aglyn-node-renderer": "1.0.0-beta.221",
31
- "@aglyn/besigner": "1.0.0-beta.221",
32
- "@aglyn/shared-data-enums": "1.0.0-beta.221",
33
- "@aglyn/shared-data-mdi": "1.0.0-beta.221",
34
- "@aglyn/shared-data-types": "1.0.0-beta.221",
35
- "@aglyn/shared-svg-icons": "1.0.0-beta.221",
36
- "@aglyn/shared-ui-json-editor": "1.0.0-beta.221",
37
- "@aglyn/shared-ui-jsx": "1.0.0-beta.221",
38
- "@aglyn/shared-ui-jsx-forms": "1.0.0-beta.221",
39
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.221",
40
- "@aglyn/shared-ui-theme": "1.0.0-beta.221",
41
- "@aglyn/shared-util-dom": "1.0.0-beta.221",
42
- "@aglyn/shared-util-tools": "1.0.0-beta.221",
43
- "@aglyn/shared-util-vendor": "1.0.0-beta.221",
28
+ "@aglyn/aglyn": "1.0.0-beta.223",
29
+ "@aglyn/aglyn-markdown-editor": "1.0.0-beta.223",
30
+ "@aglyn/aglyn-node-renderer": "1.0.0-beta.223",
31
+ "@aglyn/besigner": "1.0.0-beta.223",
32
+ "@aglyn/shared-data-enums": "1.0.0-beta.223",
33
+ "@aglyn/shared-data-mdi": "1.0.0-beta.223",
34
+ "@aglyn/shared-data-types": "1.0.0-beta.223",
35
+ "@aglyn/shared-svg-icons": "1.0.0-beta.223",
36
+ "@aglyn/shared-ui-json-editor": "1.0.0-beta.223",
37
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.223",
38
+ "@aglyn/shared-ui-jsx-forms": "1.0.0-beta.223",
39
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.223",
40
+ "@aglyn/shared-ui-theme": "1.0.0-beta.223",
41
+ "@aglyn/shared-util-dom": "1.0.0-beta.223",
42
+ "@aglyn/shared-util-tools": "1.0.0-beta.223",
43
+ "@aglyn/shared-util-vendor": "1.0.0-beta.223",
44
44
  "@dnd-kit/core": "^6.3.1",
45
45
  "@dnd-kit/utilities": "^3.2.2",
46
46
  "@react-aria/utils": "^3.34.1",
@@ -440,21 +440,22 @@ export declare function buildRepeatFields(options: {
440
440
  resolveKeyField: (field: Record<string, unknown>) => Record<string, unknown>;
441
441
  }): Array<Record<string, unknown>>;
442
442
  /**
443
- * The list each entity picker DISPLAYS, keyed by the attribute type a
444
- * component schema declares.
445
- *
446
- * One table rather than two switches, because the demand signal and the
447
- * option list have to agree about which list a picker means. When they
448
- * disagreed the failure was silent and total: the panel would open a
449
- * listener on one collection and read its options out of another, and the
450
- * dropdown stayed empty on a site full of data.
451
- *
452
- * `DATASET_FIELD_SELECT` is deliberately absent. Its options are the model
453
- * fields of the dataset an ANCESTOR chose, so it needs the dataset list to
454
- * resolve against but is not itself a picker OF datasets — it asks for the
455
- * list below and renders its own options.
443
+ * The kind of entity an attribute type's picker DISPLAYS, or `undefined` for
444
+ * an attribute that is no picker.
445
+ *
446
+ * Read from the kinds the plugins declare (`plugin-entity-pickers`), the one
447
+ * table the provider reads too, because the demand signal and the option list
448
+ * have to agree about which list a picker means. When they disagreed the
449
+ * failure was silent and total: the panel would open a listener on one
450
+ * collection and read its options out of another, and the dropdown stayed
451
+ * empty on a site full of data.
452
+ *
453
+ * A field attribute — `DATASET_FIELD_SELECT` — is deliberately not a picker
454
+ * of its kind. Its options are the fields of the entity an ANCESTOR chose, so
455
+ * it needs that kind's list to resolve against but is not itself a picker OF
456
+ * it — it asks for the list below and renders its own options.
456
457
  */
457
- export declare const ENTITY_PICKER_KINDS: Readonly<Partial<Record<Aglyn.FieldComponentType, Aglyn.EntityPickerKind>>>;
458
+ export declare function entityPickerKindOf(component: string | undefined): Aglyn.EntityPickerKind | undefined;
458
459
  /**
459
460
  * The label on an entity picker's empty first option.
460
461
  *
@@ -561,14 +562,14 @@ export declare function buildEntityPickerField<T extends Aglyn.AglynAttributeSch
561
562
  * editing sessions never open. This is the demand signal that replaced that:
562
563
  * a node whose schema declares the picker.
563
564
  *
564
- * `DATASET_FIELD_SELECT` asks for `datasets` and not for some list of its
565
- * own, which is the one mapping worth stating: its options are the model
566
- * fields of the dataset an ANCESTOR chose, so it cannot resolve one without
567
- * the dataset list to resolve it against.
565
+ * A field attribute (`DATASET_FIELD_SELECT`) asks for the kind whose fields it
566
+ * offers and not for some list of its own, which is the one mapping worth
567
+ * stating: its options are the fields of the entity an ANCESTOR chose, so it
568
+ * cannot resolve one without that kind's list to resolve it against.
568
569
  *
569
570
  * Exported for the test that pins the mapping — a picker silently missing
570
- * from {@link ENTITY_PICKER_KINDS} renders as a permanently empty dropdown,
571
- * which looks exactly like a site with no products.
571
+ * from the declarations renders as a permanently empty dropdown, which looks
572
+ * exactly like a site with no products.
572
573
  */
573
574
  export declare function entityKindsForAttributes(attributes: readonly Aglyn.AglynAttributeSchema[] | undefined): Aglyn.EntityPickerKind[];
574
575
  export declare const ElementPropsForm: import("react").ForwardRefExoticComponent<ElementPropsFormProps & import("react").RefAttributes<any>> & import("react").NamedExoticComponent<ElementPropsFormProps & import("react").RefAttributes<any>> & {
@@ -17,11 +17,12 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
17
17
  * See the License for the specific language governing permissions and
18
18
  * limitations under the License.
19
19
  */ import PluginSettingsField, { PLUGIN_SETTINGS_FIELD_COMPONENT } from "./plugin-settings-field.component.js";
20
- import { ANIMATION_DEFAULT_DELAY_MS, ANIMATION_DEFAULT_DURATION_MS, ANIMATION_DEFAULT_EASE, ANIMATION_DEFAULT_STAGGER_STEP_MS, ANIMATION_DEFAULT_TRIGGER, ANIMATION_MAX_DURATION_MS, ANIMATION_MAX_STAGGER_STEP_MS, ANIMATION_NONE, ANIMATION_PRESETS, canvas, COMPONENT_PROP_NAME_PATTERN, components, displayBindingTokens, ENTITY_PICKER_BROWSE_LIMIT, entityListState, EntityPickerContext, entityValueNeedsResolution, FEATURE_FLAG, FieldComponentType, getKnownPluginInstalls, getKnownPluginInstallsVersion, hasBindings, inheritedMediaAlt, intrinsicMediaSize, linkTargetKind, VIDEO_COMPONENT_ID, videoMediaProps, MISSING_BINDING_LABEL, NODE_ANIMATION_DELAY_PROP, NODE_ANIMATION_DURATION_PROP, NODE_ANIMATION_EASE_PROP, NODE_ANIMATION_PROP, NODE_ANIMATION_REPEAT_PROP, NODE_ANIMATION_STAGGER_PROP, NODE_ANIMATION_STAGGER_STEP_PROP, NODE_ANIMATION_TRIGGER_PROP, NODE_HIDE_IF_PROP, isPlacedFormNode, NODE_HIDE_UNLESS_PROP, normalizeBindingTokens, readInstanceIconValue, readReusablePropValue, readYesNoValue, reusablePropConditionValue, reusablePropDefaultValue, reusablePropKind, reusablePropTakesSeveral, evaluateReusablePropRule, REUSABLE_INSTANCE_COMPONENT_ID, REUSABLE_INSTANCE_PROP_VALUES_KEY, ScreenLinkContext, screenLinkTargetOptions, subscribeKnownPluginInstalls, unresolvedScreenOption } from "@aglyn/aglyn";
20
+ import { ANIMATION_DEFAULT_DELAY_MS, ANIMATION_DEFAULT_DURATION_MS, ANIMATION_DEFAULT_EASE, ANIMATION_DEFAULT_STAGGER_STEP_MS, ANIMATION_DEFAULT_TRIGGER, ANIMATION_MAX_DURATION_MS, ANIMATION_MAX_STAGGER_STEP_MS, ANIMATION_NONE, ANIMATION_PRESETS, canvas, COMPONENT_PROP_NAME_PATTERN, components, displayBindingTokens, ENTITY_PICKER_BROWSE_LIMIT, entityListState, EntityPickerContext, entityValueNeedsResolution, FEATURE_FLAG, FieldComponentType, getKnownPluginInstalls, getKnownPluginInstallsVersion, hasBindings, inheritedMediaAlt, intrinsicMediaSize, linkTargetKind, VIDEO_COMPONENT_ID, videoMediaProps, MISSING_BINDING_LABEL, NODE_ANIMATION_DELAY_PROP, NODE_ANIMATION_DURATION_PROP, NODE_ANIMATION_EASE_PROP, NODE_ANIMATION_PROP, NODE_ANIMATION_REPEAT_PROP, NODE_ANIMATION_STAGGER_PROP, NODE_ANIMATION_STAGGER_STEP_PROP, NODE_ANIMATION_TRIGGER_PROP, NODE_HIDE_IF_PROP, isPlacedFormNode, formPropsOnBind, FORM_COMPONENT_ID, NODE_HIDE_UNLESS_PROP, normalizeBindingTokens, readInstanceIconValue, readReusablePropValue, readYesNoValue, reusablePropConditionValue, reusablePropDefaultValue, reusablePropKind, reusablePropTakesSeveral, evaluateReusablePropRule, REUSABLE_INSTANCE_COMPONENT_ID, REUSABLE_INSTANCE_PROP_VALUES_KEY, ScreenLinkContext, screenLinkTargetOptions, subscribeKnownPluginInstalls, unresolvedScreenOption } from "@aglyn/aglyn";
21
21
  // By path, not the `@aglyn/aglyn` barrel: a repeat's bounds and the sources
22
22
  // an editor offers are editor business, and a published page must not pull
23
23
  // either in behind them.
24
24
  import { repeatScope } from "@aglyn/aglyn/app-utils/expand-repeatables";
25
+ import { entityFieldsPickerForAttribute, entityPickerForAttribute, pluginEntityPicker } from "@aglyn/aglyn/plugin-manager/plugin-entity-pickers";
25
26
  import { REPEAT_NODE_CAPABILITY } from "@aglyn/aglyn/app-utils/node-capabilities";
26
27
  import { repeatSourceOf } from "@aglyn/aglyn/app-utils/repeat-sources";
27
28
  import { useAglynSiteTheme } from "@aglyn/aglyn-node-renderer";
@@ -798,12 +799,13 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
798
799
  }
799
800
  if (field.component === FieldComponentType.DATASET_FIELD_SELECT) {
800
801
  var _ref;
801
- var _entityOptions_entityFields_datasets, _entityOptions_entityFields;
802
+ var _entityFieldsPickerForAttribute, _entityOptions_entityFields_fieldsKind, _entityOptions_entityFields;
802
803
  // Declared order, never alphabetized — it mirrors the schema dialog. A
803
804
  // field naming its own dataset (a Dataset field property) reads that
804
805
  // one; every other reads the nearest ancestor's.
805
806
  const boundId = typeof field['datasetId'] === 'string' && field['datasetId'] ? field['datasetId'] : ancestorDatasetId;
806
- const modelFields = boundId ? (_ref = (_entityOptions_entityFields = entityOptions.entityFields) == null ? void 0 : (_entityOptions_entityFields_datasets = _entityOptions_entityFields.datasets) == null ? void 0 : _entityOptions_entityFields_datasets[boundId]) != null ? _ref : [] : [];
807
+ const fieldsKind = (_entityFieldsPickerForAttribute = entityFieldsPickerForAttribute(field.component)) == null ? void 0 : _entityFieldsPickerForAttribute.kind;
808
+ const modelFields = boundId && fieldsKind ? (_ref = (_entityOptions_entityFields = entityOptions.entityFields) == null ? void 0 : (_entityOptions_entityFields_fieldsKind = _entityOptions_entityFields[fieldsKind]) == null ? void 0 : _entityOptions_entityFields_fieldsKind[boundId]) != null ? _ref : [] : [];
807
809
  return _extends({}, field, {
808
810
  component: FieldComponentType.SELECT,
809
811
  options: [
@@ -824,7 +826,7 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
824
826
  // of one that is not there. The stored value travels with the field: a
825
827
  // selection outside the browse window is offered from its own keyed read,
826
828
  // so a bound element never renders as unbound.
827
- const entityKind = ENTITY_PICKER_KINDS[field.component];
829
+ const entityKind = entityPickerKindOf(field.component);
828
830
  if (entityKind) {
829
831
  return buildEntityPickerField(field, entityKind, entityOptions, stored);
830
832
  }
@@ -1270,53 +1272,35 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1270
1272
  ];
1271
1273
  }
1272
1274
  /**
1273
- * The list each entity picker DISPLAYS, keyed by the attribute type a
1274
- * component schema declares.
1275
+ * The kind of entity an attribute type's picker DISPLAYS, or `undefined` for
1276
+ * an attribute that is no picker.
1275
1277
  *
1276
- * One table rather than two switches, because the demand signal and the
1277
- * option list have to agree about which list a picker means. When they
1278
- * disagreed the failure was silent and total: the panel would open a
1279
- * listener on one collection and read its options out of another, and the
1280
- * dropdown stayed empty on a site full of data.
1278
+ * Read from the kinds the plugins declare (`plugin-entity-pickers`), the one
1279
+ * table the provider reads too, because the demand signal and the option list
1280
+ * have to agree about which list a picker means. When they disagreed the
1281
+ * failure was silent and total: the panel would open a listener on one
1282
+ * collection and read its options out of another, and the dropdown stayed
1283
+ * empty on a site full of data.
1281
1284
  *
1282
- * `DATASET_FIELD_SELECT` is deliberately absent. Its options are the model
1283
- * fields of the dataset an ANCESTOR chose, so it needs the dataset list to
1284
- * resolve against but is not itself a picker OF datasets — it asks for the
1285
- * list below and renders its own options.
1286
- */ export const ENTITY_PICKER_KINDS = {
1287
- [FieldComponentType.PRODUCT_SELECT]: 'products',
1288
- [FieldComponentType.COLLECTION_SELECT]: 'collections',
1289
- [FieldComponentType.CATEGORY_SELECT]: 'categories',
1290
- [FieldComponentType.DATASET_SELECT]: 'datasets',
1291
- [FieldComponentType.FORM_SELECT]: 'forms'
1292
- };
1293
- /** Where an author makes more of each kind, named in the empty picker. */ const ENTITY_PICKER_ORIGIN = {
1294
- products: {
1295
- singular: 'product',
1296
- plural: 'products',
1297
- page: 'the Products page'
1298
- },
1299
- collections: {
1300
- singular: 'collection',
1301
- plural: 'collections',
1302
- page: 'the Collections page'
1303
- },
1304
- categories: {
1305
- singular: 'category',
1306
- plural: 'categories',
1307
- page: 'the Categories page'
1308
- },
1309
- datasets: {
1310
- singular: 'dataset',
1311
- plural: 'datasets',
1312
- page: 'the Data page'
1313
- },
1314
- forms: {
1315
- singular: 'form',
1316
- plural: 'forms',
1317
- page: 'the Forms page'
1318
- }
1319
- };
1285
+ * A field attribute — `DATASET_FIELD_SELECT` — is deliberately not a picker
1286
+ * of its kind. Its options are the fields of the entity an ANCESTOR chose, so
1287
+ * it needs that kind's list to resolve against but is not itself a picker OF
1288
+ * it — it asks for the list below and renders its own options.
1289
+ */ export function entityPickerKindOf(component) {
1290
+ var _entityPickerForAttribute;
1291
+ return (_entityPickerForAttribute = entityPickerForAttribute(component)) == null ? void 0 : _entityPickerForAttribute.kind;
1292
+ }
1293
+ /**
1294
+ * Where an author makes more of a kind, named in the empty picker — the words
1295
+ * its plugin declares, or the kind itself for one no plugin here declares.
1296
+ */ function entityPickerWords(kind) {
1297
+ const declared = pluginEntityPicker(kind);
1298
+ return declared != null ? declared : {
1299
+ singular: kind,
1300
+ plural: kind,
1301
+ page: 'its page'
1302
+ };
1303
+ }
1320
1304
  /**
1321
1305
  * The label on an entity picker's empty first option.
1322
1306
  *
@@ -1326,7 +1310,7 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1326
1310
  * settled one claims anything about the site.
1327
1311
  */ export function entityPickerPlaceholder(kind, state, count) {
1328
1312
  if (count > 0) return 'None';
1329
- const { plural, page } = ENTITY_PICKER_ORIGIN[kind];
1313
+ const { plural, page } = entityPickerWords(kind);
1330
1314
  switch(state){
1331
1315
  case 'error':
1332
1316
  return `Could not load ${plural} — reopen this panel to try again`;
@@ -1354,7 +1338,7 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1354
1338
  */ export function entityPickerBrowseNotice(kind, context) {
1355
1339
  var _context_truncated, _context_searchable;
1356
1340
  if (!(context == null ? void 0 : (_context_truncated = context.truncated) == null ? void 0 : _context_truncated[kind])) return undefined;
1357
- const { plural } = ENTITY_PICKER_ORIGIN[kind];
1341
+ const { plural } = entityPickerWords(kind);
1358
1342
  const first = `Showing the first ${ENTITY_PICKER_BROWSE_LIMIT} ${plural} — this site has more. `;
1359
1343
  return ((_context_searchable = context.searchable) == null ? void 0 : _context_searchable[kind]) ? `${first}Type to search all of them.` : `${first}Typing narrows these ${ENTITY_PICKER_BROWSE_LIMIT} only.`;
1360
1344
  }
@@ -1367,7 +1351,7 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1367
1351
  * and makes a second one.
1368
1352
  */ export function entityPickerNoMatchText(kind, context) {
1369
1353
  var _context_truncated, _context_searchable;
1370
- const { plural } = ENTITY_PICKER_ORIGIN[kind];
1354
+ const { plural } = entityPickerWords(kind);
1371
1355
  if ((context == null ? void 0 : (_context_truncated = context.truncated) == null ? void 0 : _context_truncated[kind]) && !(context == null ? void 0 : (_context_searchable = context.searchable) == null ? void 0 : _context_searchable[kind])) {
1372
1356
  return `No match in the first ${ENTITY_PICKER_BROWSE_LIMIT} ${plural} — this site has more.`;
1373
1357
  }
@@ -1396,10 +1380,10 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1396
1380
  * a free-text caption stored where an id belongs looks like.
1397
1381
  */ export function entitySelectionOption(context, kind, value) {
1398
1382
  var _ref;
1399
- var _context_resolved_kind, _context_resolved;
1383
+ var _context_options, _context_resolved_kind, _context_resolved;
1400
1384
  const id = typeof value === 'string' ? value.trim() : '';
1401
1385
  if (!id) return undefined;
1402
- if (((_ref = context == null ? void 0 : context[kind]) != null ? _ref : []).some((entity)=>entity.id === id)) {
1386
+ if (((_ref = context == null ? void 0 : (_context_options = context.options) == null ? void 0 : _context_options[kind]) != null ? _ref : []).some((entity)=>entity.id === id)) {
1403
1387
  return undefined;
1404
1388
  }
1405
1389
  const resolved = context == null ? void 0 : (_context_resolved = context.resolved) == null ? void 0 : (_context_resolved_kind = _context_resolved[kind]) == null ? void 0 : _context_resolved_kind[id];
@@ -1407,7 +1391,7 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1407
1391
  value: id,
1408
1392
  label: resolved.label
1409
1393
  };
1410
- const { singular } = ENTITY_PICKER_ORIGIN[kind];
1394
+ const { singular } = entityPickerWords(kind);
1411
1395
  if (resolved === null) {
1412
1396
  return {
1413
1397
  value: id,
@@ -1447,7 +1431,8 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1447
1431
  * selection is a keyed read; this is where its answer is offered.
1448
1432
  */ export function buildEntityPickerField(field, kind, context, value) {
1449
1433
  var _ref;
1450
- const entities = (_ref = context == null ? void 0 : context[kind]) != null ? _ref : [];
1434
+ var _context_options;
1435
+ const entities = (_ref = context == null ? void 0 : (_context_options = context.options) == null ? void 0 : _context_options[kind]) != null ? _ref : [];
1451
1436
  const selected = entitySelectionOption(context, kind, value);
1452
1437
  const notice = entityPickerBrowseNotice(kind, context);
1453
1438
  const search = context == null ? void 0 : context.search;
@@ -1506,22 +1491,20 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1506
1491
  * editing sessions never open. This is the demand signal that replaced that:
1507
1492
  * a node whose schema declares the picker.
1508
1493
  *
1509
- * `DATASET_FIELD_SELECT` asks for `datasets` and not for some list of its
1510
- * own, which is the one mapping worth stating: its options are the model
1511
- * fields of the dataset an ANCESTOR chose, so it cannot resolve one without
1512
- * the dataset list to resolve it against.
1494
+ * A field attribute (`DATASET_FIELD_SELECT`) asks for the kind whose fields it
1495
+ * offers and not for some list of its own, which is the one mapping worth
1496
+ * stating: its options are the fields of the entity an ANCESTOR chose, so it
1497
+ * cannot resolve one without that kind's list to resolve it against.
1513
1498
  *
1514
1499
  * Exported for the test that pins the mapping — a picker silently missing
1515
- * from {@link ENTITY_PICKER_KINDS} renders as a permanently empty dropdown,
1516
- * which looks exactly like a site with no products.
1500
+ * from the declarations renders as a permanently empty dropdown, which looks
1501
+ * exactly like a site with no products.
1517
1502
  */ export function entityKindsForAttributes(attributes) {
1518
1503
  const kinds = new Set();
1519
1504
  for (const field of attributes != null ? attributes : []){
1520
- if (field.component === FieldComponentType.DATASET_FIELD_SELECT) {
1521
- kinds.add('datasets');
1522
- continue;
1523
- }
1524
- const kind = ENTITY_PICKER_KINDS[field.component];
1505
+ var _entityPickerKindOf;
1506
+ var _entityFieldsPickerForAttribute;
1507
+ const kind = (_entityPickerKindOf = entityPickerKindOf(field.component)) != null ? _entityPickerKindOf : (_entityFieldsPickerForAttribute = entityFieldsPickerForAttribute(field.component)) == null ? void 0 : _entityFieldsPickerForAttribute.kind;
1525
1508
  if (kind) kinds.add(kind);
1526
1509
  }
1527
1510
  return [
@@ -1530,7 +1513,7 @@ export const elementPropsComponentMapper = _extends({}, simpleComponentMapper, {
1530
1513
  }
1531
1514
  const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1532
1515
  var _ref, _ref1, _interactions_automations, _interactions_sectionExperiments;
1533
- var _schema_flags, _shownNode_props;
1516
+ var _entityFieldsPickerForAttribute, _entityOptions_options, _schema_flags, _shownNode_props;
1534
1517
  const { node } = props, rest = _object_without_properties_loose(props, [
1535
1518
  "node"
1536
1519
  ]);
@@ -1612,7 +1595,7 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1612
1595
  useEffect(()=>{
1613
1596
  if (!resolveEntity) return;
1614
1597
  for (const field of demandAttributes){
1615
- const kind = ENTITY_PICKER_KINDS[field.component];
1598
+ const kind = entityPickerKindOf(field.component);
1616
1599
  if (!kind) continue;
1617
1600
  const id = entityValueNeedsResolution(entityOptions, kind, readAttributeFieldValue(nodeProps, field.name));
1618
1601
  if (id) resolveEntity(kind, id);
@@ -1637,7 +1620,7 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1637
1620
  const repeat = repeatSourceOf({
1638
1621
  props: nodeProps
1639
1622
  });
1640
- const kind = repeat && ENTITY_PICKER_KINDS[repeat.source.keyAttribute.component];
1623
+ const kind = repeat && entityPickerKindOf(repeat.source.keyAttribute.component);
1641
1624
  if (!kind) return;
1642
1625
  const id = entityValueNeedsResolution(entityOptions, kind, repeat == null ? void 0 : repeat.key);
1643
1626
  if (id) resolveEntity(kind, id);
@@ -1675,6 +1658,9 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1675
1658
  // ancestor persists the dataset id; legacy nodes carrying only a name
1676
1659
  // resolve it by matching the current display labels.
1677
1660
  const hasDatasetFieldSelect = demandAttributes.some((field)=>field.component === FieldComponentType.DATASET_FIELD_SELECT);
1661
+ // The kind those fields come from, whose list a legacy name is matched in.
1662
+ const fieldsKind = (_entityFieldsPickerForAttribute = entityFieldsPickerForAttribute(FieldComponentType.DATASET_FIELD_SELECT)) == null ? void 0 : _entityFieldsPickerForAttribute.kind;
1663
+ const fieldsKindOptions = fieldsKind ? (_entityOptions_options = entityOptions.options) == null ? void 0 : _entityOptions_options[fieldsKind] : undefined;
1678
1664
  const ancestorDatasetId = useMemo(()=>{
1679
1665
  if (!hasDatasetFieldSelect || !(node == null ? void 0 : node.$id)) return undefined;
1680
1666
  const nodes = canvas.toJSON().nodes;
@@ -1686,8 +1672,7 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1686
1672
  return props.datasetId;
1687
1673
  }
1688
1674
  if (typeof props.datasetName === 'string' && props.datasetName) {
1689
- var _entityOptions_datasets;
1690
- const byLabel = ((_entityOptions_datasets = entityOptions.datasets) != null ? _entityOptions_datasets : []).find((dataset)=>dataset.label === props.datasetName);
1675
+ const byLabel = (fieldsKindOptions != null ? fieldsKindOptions : []).find((dataset)=>dataset.label === props.datasetName);
1691
1676
  if (byLabel) return byLabel.id;
1692
1677
  }
1693
1678
  current = current.parentId ? nodes[current.parentId] : undefined;
@@ -1697,7 +1682,7 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1697
1682
  }, [
1698
1683
  hasDatasetFieldSelect,
1699
1684
  node,
1700
- entityOptions.datasets
1685
+ fieldsKindOptions
1701
1686
  ]);
1702
1687
  // Insert-picker options + pill display-name inputs (AGL-583/586),
1703
1688
  // assembled from this node's ancestor context — shared with the
@@ -1888,7 +1873,7 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
1888
1873
  // The key as an author knows it, when the source's control is a picker
1889
1874
  // that can name it. A source drawn with anything else — and a picker
1890
1875
  // whose list has not answered — is named by the stored key itself.
1891
- const kind = ENTITY_PICKER_KINDS[repeat.source.keyAttribute.component];
1876
+ const kind = entityPickerKindOf(repeat.source.keyAttribute.component);
1892
1877
  const label = (_ref = kind ? (_entitySelectionOption = entitySelectionOption(entityOptions, kind, repeat.key)) == null ? void 0 : _entitySelectionOption.label : undefined) != null ? _ref : repeat.key;
1893
1878
  return repeatScope({
1894
1879
  props: nodeProps,
@@ -2202,7 +2187,10 @@ const ElementPropsFormRaw = /*#__PURE__*/ forwardRef((props, ref)=>{
2202
2187
  // Denormalize each picked icon's SVG path next to its id (AGL-1212) —
2203
2188
  // see `iconPathsForSave` for why a miss does not always clear it.
2204
2189
  Object.assign(normalized, iconPathsForSave(node == null ? void 0 : (_node_componentSchema = node.componentSchema) == null ? void 0 : _node_componentSchema.attributes, normalized, node == null ? void 0 : node.props));
2205
- canvas.updateNodeProps(node, normalized);
2190
+ // Picking a saved form drops what the page's form node started with
2191
+ // (AGL-3494) — a preset's button text kept here would mask the form's
2192
+ // own for good. See `formPropsOnBind`.
2193
+ canvas.updateNodeProps(node, (node == null ? void 0 : node.componentId) === FORM_COMPONENT_ID ? formPropsOnBind(node == null ? void 0 : node.props, normalized) : normalized);
2206
2194
  }, [
2207
2195
  node,
2208
2196
  bindingVariables,