declarative-forms 2.1.0 → 2.1.2

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.
package/README.md CHANGED
@@ -95,6 +95,14 @@ provider, and no prop drilling, because there is no tree to lift through.
95
95
  dialog per entry, which is the natural shape for a record, and awkward to do
96
96
  inline.
97
97
 
98
+ **Editing is the same call with the object in it.** `prompt()` takes a starting
99
+ value; so does this. One field list serves both directions — extra keys on the
100
+ object you pass are ignored, so the record you already have goes in as-is.
101
+
102
+ ```ts
103
+ const updated = await ask(userFields, { defaultValues: user });
104
+ ```
105
+
98
106
  **Works anywhere, because it needs nothing.** Plain DOM plus one web component,
99
107
  no runtime dependencies. Call it from React, Vue, Svelte, Angular, an Electron
100
108
  main-window script, or a `<script type="module">` tag in a static page. It never
package/dist/index.cjs CHANGED
@@ -944,8 +944,6 @@ function injectStyles() {
944
944
  // src/components/DlSelect.ts
945
945
  var SVG_NS = "http://www.w3.org/2000/svg";
946
946
  var ARROW_PATH = "M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z";
947
- var MIN_LOADING_MS = 1500;
948
- var LOADING_DELAY_MS = 100;
949
947
  var CustomElementBase = typeof HTMLElement === "undefined" ? class {
950
948
  } : HTMLElement;
951
949
  var DlOption = class extends CustomElementBase {
@@ -958,7 +956,23 @@ var DlOption = class extends CustomElementBase {
958
956
  return this.getAttribute("displayWhenSelected") ?? this.innerText;
959
957
  }
960
958
  };
961
- var DlSelect = class extends CustomElementBase {
959
+ var DlSelect = class _DlSelect extends CustomElementBase {
960
+ /**
961
+ * How long a load may run before the skeleton is shown at all. A load that
962
+ * finishes inside this window never flashes one.
963
+ */
964
+ static showLoadingAfterMs = 100;
965
+ /**
966
+ * Once the skeleton *has* been shown, it is held for at least this long, so
967
+ * it cannot appear and vanish in the same instant.
968
+ *
969
+ * Both are statics so a test suite can set them to 0. They are deliberate
970
+ * pauses for human eyes; to a test they are pure latency, and they are why
971
+ * suites end up sleeping around these selects instead of waiting on a
972
+ * condition. Wait on `isLoading` rather than the `dl-select-loading` class:
973
+ * `isLoading` flips synchronously, the class lags by `showLoadingAfterMs`.
974
+ */
975
+ static minLoadingMs = 1500;
962
976
  optionsWrapper;
963
977
  inputWrapper;
964
978
  noMatchesHint;
@@ -1067,14 +1081,14 @@ var DlSelect = class extends CustomElementBase {
1067
1081
  this.classList.add("dl-select-loading");
1068
1082
  this.optionsWrapper.remove();
1069
1083
  this.loadingStartedAt = Date.now();
1070
- }, LOADING_DELAY_MS)
1084
+ }, _DlSelect.showLoadingAfterMs)
1071
1085
  );
1072
1086
  }
1073
1087
  unsetLoadingStatus() {
1074
1088
  for (const timeout of this.loadingTimeouts) clearTimeout(timeout);
1075
1089
  this.loadingTimeouts = [];
1076
1090
  const elapsed = this.loadingStartedAt ? Date.now() - this.loadingStartedAt : 0;
1077
- const delay = this.loadingStartedAt ? Math.max(0, MIN_LOADING_MS - elapsed) : 0;
1091
+ const delay = this.loadingStartedAt ? Math.max(0, _DlSelect.minLoadingMs - elapsed) : 0;
1078
1092
  const finish = () => {
1079
1093
  this.appendChild(this.optionsWrapper);
1080
1094
  this.classList.remove("dl-select-loading");
@@ -1366,10 +1380,11 @@ var SelectField = class extends Field {
1366
1380
  async loadOptions(opts = {}) {
1367
1381
  const isCurrent = this.context.scheduler.claim(`options:${this.descriptor.name}`);
1368
1382
  const source = this.descriptor.options;
1369
- const requested = typeof source === "function" ? source(this.context.contextFor(this.descriptor)) : source;
1370
- const isAsync = requested instanceof Promise;
1371
- if (isAsync) this.select.setLoadingStatus();
1383
+ let isAsync = false;
1372
1384
  try {
1385
+ const requested = typeof source === "function" ? source(this.context.contextFor(this.descriptor)) : source;
1386
+ isAsync = requested instanceof Promise;
1387
+ if (isAsync) this.select.setLoadingStatus();
1373
1388
  const options = await requested ?? [];
1374
1389
  if (!isCurrent()) return;
1375
1390
  if (opts.reload) this.context.tooltips.reset(this.descriptor.name);
@@ -2144,6 +2159,7 @@ var DeclarativeForm = class _DeclarativeForm {
2144
2159
  }
2145
2160
  const field = this.registry.create(descriptor, context);
2146
2161
  field.applyStaticDefaultValue();
2162
+ this.applySeedValue(field);
2147
2163
  this.fieldList.push(field);
2148
2164
  this.fieldsByName.set(descriptor.name, field);
2149
2165
  this.tooltips.register(descriptor.name, field.tooltipMarker);
@@ -2186,8 +2202,24 @@ var DeclarativeForm = class _DeclarativeForm {
2186
2202
  await Promise.allSettled(
2187
2203
  this.fieldList.map((field) => this.scheduler.track(field.applyDefaultValue()))
2188
2204
  );
2205
+ for (const field of this.fieldList) this.applySeedValue(field);
2189
2206
  await this.update();
2190
2207
  }
2208
+ /**
2209
+ * Seed one field from {@link DeclarativeFormOptions.defaultValues}.
2210
+ *
2211
+ * Run twice: once at build time so the first paint and the `isActive`
2212
+ * predicates behind it already see the record being edited, and once after
2213
+ * the `defaultValue` pass — which is async, and would otherwise overwrite the
2214
+ * seeded value with the field's own default for the create case.
2215
+ */
2216
+ applySeedValue(field) {
2217
+ const values = this.options.defaultValues;
2218
+ if (!values) return;
2219
+ if (!Object.prototype.hasOwnProperty.call(values, field.name)) return;
2220
+ const value = values[field.name];
2221
+ if (value !== void 0) field.setValue(value);
2222
+ }
2191
2223
  /** Resolves once initial options and default values have been applied. */
2192
2224
  whenReady() {
2193
2225
  return this.ready.then(() => this.scheduler.whenSettled());