@camstack/ui-library 1.2.260 → 1.2.261

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/dist/index.cjs CHANGED
@@ -29241,6 +29241,13 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
29241
29241
  };
29242
29242
  const canRemove = rows.length > minRows;
29243
29243
  const canAdd = rows.length < maxRows;
29244
+ const idKey = field.itemIdKey ?? "id";
29245
+ const rowReactKey = (row, idx) => {
29246
+ const raw = row[idKey];
29247
+ if (typeof raw === "string" && raw.length > 0) return raw;
29248
+ if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
29249
+ return `row-${String(idx)}`;
29250
+ };
29244
29251
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
29245
29252
  className: "col-span-full space-y-2",
29246
29253
  children: [
@@ -29287,7 +29294,7 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
29287
29294
  onAction
29288
29295
  }, sub.key))
29289
29296
  })]
29290
- }, idx))
29297
+ }, rowReactKey(row, idx)))
29291
29298
  }),
29292
29299
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
29293
29300
  type: "button",
@@ -30166,23 +30173,44 @@ var Chevron$1 = ({ open }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg",
30166
30173
  "aria-hidden": true,
30167
30174
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polyline", { points: "9 18 15 12 9 6" })
30168
30175
  });
30176
+ function isValueBearingField(f) {
30177
+ return f.type !== "separator" && f.type !== "info" && f.type !== "button" && f.type !== "group";
30178
+ }
30169
30179
  function extractValues(schema) {
30170
30180
  const out = {};
30171
30181
  if (!schema) return out;
30172
30182
  for (const s of schema.sections) for (const f of s.fields) {
30173
- if (f.type === "separator" || f.type === "info" || f.type === "button" || f.type === "group") continue;
30183
+ if (!isValueBearingField(f)) continue;
30174
30184
  const key = f.key;
30175
30185
  out[key] = f.value;
30176
30186
  }
30177
30187
  return out;
30178
30188
  }
30189
+ /** Paint operator edits into the hydrated schema so controlled inputs keep focus. */
30190
+ function applyValuesToSchema(schema, nextValues) {
30191
+ return {
30192
+ ...schema,
30193
+ sections: schema.sections.map((s) => ({
30194
+ ...s,
30195
+ fields: s.fields.map((f) => {
30196
+ if (!isValueBearingField(f)) return f;
30197
+ const key = f.key;
30198
+ if (!(key in nextValues)) return f;
30199
+ return {
30200
+ ...f,
30201
+ value: nextValues[key]
30202
+ };
30203
+ })
30204
+ }))
30205
+ };
30206
+ }
30179
30207
  function stripValues(schema) {
30180
30208
  return {
30181
30209
  ...schema,
30182
30210
  sections: schema.sections.map((s) => ({
30183
30211
  ...s,
30184
30212
  fields: s.fields.map((f) => {
30185
- if (f.type === "separator" || f.type === "info" || f.type === "button" || f.type === "group") return f;
30213
+ if (!isValueBearingField(f)) return f;
30186
30214
  const { value: _drop, ...rest } = f;
30187
30215
  return rest;
30188
30216
  })
@@ -30198,6 +30226,8 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30198
30226
  const [open, setOpen] = (0, react$1.useState)(defaultOpen ?? false);
30199
30227
  const [overrideValues, setOverrideValues] = (0, react$1.useState)({});
30200
30228
  const [baseValues, setBaseValues] = (0, react$1.useState)(null);
30229
+ /** Bumps on every persist edit; a stale refetch must not clobber a newer local paint. */
30230
+ const persistSeq = (0, react$1.useRef)(0);
30201
30231
  (0, react$1.useEffect)(() => {
30202
30232
  setBaseValues(null);
30203
30233
  setOverrideValues({});
@@ -30266,7 +30296,10 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30266
30296
  const patch = {};
30267
30297
  for (const k of Object.keys(nextValues)) if (nextValues[k] !== values[k]) patch[k] = nextValues[k];
30268
30298
  if (Object.keys(patch).length === 0) return;
30299
+ const seq = ++persistSeq.current;
30300
+ setHydrated((prev) => prev === null ? prev : applyValuesToSchema(prev, nextValues));
30269
30301
  setSaving(true);
30302
+ setError(null);
30270
30303
  try {
30271
30304
  await trpc.addonSettings.updateGlobalSettings.mutate({
30272
30305
  addonId,
@@ -30277,12 +30310,12 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30277
30310
  addonId,
30278
30311
  nodeId
30279
30312
  });
30280
- if (next) setHydrated(next);
30281
- onAfterChange?.();
30313
+ if (next && seq === persistSeq.current) setHydrated(next);
30314
+ if (seq === persistSeq.current) onAfterChange?.();
30282
30315
  } catch (err) {
30283
- setError(err instanceof Error ? err.message : String(err));
30316
+ if (seq === persistSeq.current) setError(err instanceof Error ? err.message : String(err));
30284
30317
  } finally {
30285
- setSaving(false);
30318
+ if (seq === persistSeq.current) setSaving(false);
30286
30319
  }
30287
30320
  };
30288
30321
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -30314,15 +30347,23 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30314
30347
  ...values,
30315
30348
  ...overrideValues
30316
30349
  } : values;
30317
- const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [effectiveMode === "override" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30318
- className: "mb-2 text-[11px] text-foreground-subtle",
30319
- children: "Benchmark override — applies to this run only. The addon's saved settings are not changed."
30320
- }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigFormBuilder, {
30321
- schema: schemaNoValues,
30322
- values: effectiveValues,
30323
- onChange: handleChange,
30324
- disabled: disabled === true || saving
30325
- })] });
30350
+ const body = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
30351
+ effectiveMode === "override" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30352
+ className: "mb-2 text-[11px] text-foreground-subtle",
30353
+ children: "Benchmark override — applies to this run only. The addon's saved settings are not changed."
30354
+ }) : null,
30355
+ saving ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
30356
+ className: "mb-2 text-[11px] text-foreground-subtle",
30357
+ "aria-live": "polite",
30358
+ children: "Saving…"
30359
+ }) : null,
30360
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfigFormBuilder, {
30361
+ schema: schemaNoValues,
30362
+ values: effectiveValues,
30363
+ onChange: handleChange,
30364
+ disabled: disabled === true
30365
+ })
30366
+ ] });
30326
30367
  if (collapsible === true) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
30327
30368
  className: "rounded-lg border border-border bg-surface overflow-hidden",
30328
30369
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
package/dist/index.js CHANGED
@@ -29217,6 +29217,13 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
29217
29217
  };
29218
29218
  const canRemove = rows.length > minRows;
29219
29219
  const canAdd = rows.length < maxRows;
29220
+ const idKey = field.itemIdKey ?? "id";
29221
+ const rowReactKey = (row, idx) => {
29222
+ const raw = row[idKey];
29223
+ if (typeof raw === "string" && raw.length > 0) return raw;
29224
+ if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
29225
+ return `row-${String(idx)}`;
29226
+ };
29220
29227
  return /* @__PURE__ */ jsxs("div", {
29221
29228
  className: "col-span-full space-y-2",
29222
29229
  children: [
@@ -29263,7 +29270,7 @@ function EditableArrayField({ field, value, onChange, disabled, translationFn, o
29263
29270
  onAction
29264
29271
  }, sub.key))
29265
29272
  })]
29266
- }, idx))
29273
+ }, rowReactKey(row, idx)))
29267
29274
  }),
29268
29275
  /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("button", {
29269
29276
  type: "button",
@@ -30142,23 +30149,44 @@ var Chevron$1 = ({ open }) => /* @__PURE__ */ jsx("svg", {
30142
30149
  "aria-hidden": true,
30143
30150
  children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
30144
30151
  });
30152
+ function isValueBearingField(f) {
30153
+ return f.type !== "separator" && f.type !== "info" && f.type !== "button" && f.type !== "group";
30154
+ }
30145
30155
  function extractValues(schema) {
30146
30156
  const out = {};
30147
30157
  if (!schema) return out;
30148
30158
  for (const s of schema.sections) for (const f of s.fields) {
30149
- if (f.type === "separator" || f.type === "info" || f.type === "button" || f.type === "group") continue;
30159
+ if (!isValueBearingField(f)) continue;
30150
30160
  const key = f.key;
30151
30161
  out[key] = f.value;
30152
30162
  }
30153
30163
  return out;
30154
30164
  }
30165
+ /** Paint operator edits into the hydrated schema so controlled inputs keep focus. */
30166
+ function applyValuesToSchema(schema, nextValues) {
30167
+ return {
30168
+ ...schema,
30169
+ sections: schema.sections.map((s) => ({
30170
+ ...s,
30171
+ fields: s.fields.map((f) => {
30172
+ if (!isValueBearingField(f)) return f;
30173
+ const key = f.key;
30174
+ if (!(key in nextValues)) return f;
30175
+ return {
30176
+ ...f,
30177
+ value: nextValues[key]
30178
+ };
30179
+ })
30180
+ }))
30181
+ };
30182
+ }
30155
30183
  function stripValues(schema) {
30156
30184
  return {
30157
30185
  ...schema,
30158
30186
  sections: schema.sections.map((s) => ({
30159
30187
  ...s,
30160
30188
  fields: s.fields.map((f) => {
30161
- if (f.type === "separator" || f.type === "info" || f.type === "button" || f.type === "group") return f;
30189
+ if (!isValueBearingField(f)) return f;
30162
30190
  const { value: _drop, ...rest } = f;
30163
30191
  return rest;
30164
30192
  })
@@ -30174,6 +30202,8 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30174
30202
  const [open, setOpen] = useState(defaultOpen ?? false);
30175
30203
  const [overrideValues, setOverrideValues] = useState({});
30176
30204
  const [baseValues, setBaseValues] = useState(null);
30205
+ /** Bumps on every persist edit; a stale refetch must not clobber a newer local paint. */
30206
+ const persistSeq = useRef(0);
30177
30207
  useEffect(() => {
30178
30208
  setBaseValues(null);
30179
30209
  setOverrideValues({});
@@ -30242,7 +30272,10 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30242
30272
  const patch = {};
30243
30273
  for (const k of Object.keys(nextValues)) if (nextValues[k] !== values[k]) patch[k] = nextValues[k];
30244
30274
  if (Object.keys(patch).length === 0) return;
30275
+ const seq = ++persistSeq.current;
30276
+ setHydrated((prev) => prev === null ? prev : applyValuesToSchema(prev, nextValues));
30245
30277
  setSaving(true);
30278
+ setError(null);
30246
30279
  try {
30247
30280
  await trpc.addonSettings.updateGlobalSettings.mutate({
30248
30281
  addonId,
@@ -30253,12 +30286,12 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30253
30286
  addonId,
30254
30287
  nodeId
30255
30288
  });
30256
- if (next) setHydrated(next);
30257
- onAfterChange?.();
30289
+ if (next && seq === persistSeq.current) setHydrated(next);
30290
+ if (seq === persistSeq.current) onAfterChange?.();
30258
30291
  } catch (err) {
30259
- setError(err instanceof Error ? err.message : String(err));
30292
+ if (seq === persistSeq.current) setError(err instanceof Error ? err.message : String(err));
30260
30293
  } finally {
30261
- setSaving(false);
30294
+ if (seq === persistSeq.current) setSaving(false);
30262
30295
  }
30263
30296
  };
30264
30297
  if (loading) return /* @__PURE__ */ jsxs("div", {
@@ -30290,15 +30323,23 @@ function AddonGlobalSettingsForm({ trpc, addonId, nodeId, title, disabled, onAft
30290
30323
  ...values,
30291
30324
  ...overrideValues
30292
30325
  } : values;
30293
- const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [effectiveMode === "override" ? /* @__PURE__ */ jsx("div", {
30294
- className: "mb-2 text-[11px] text-foreground-subtle",
30295
- children: "Benchmark override — applies to this run only. The addon's saved settings are not changed."
30296
- }) : null, /* @__PURE__ */ jsx(ConfigFormBuilder, {
30297
- schema: schemaNoValues,
30298
- values: effectiveValues,
30299
- onChange: handleChange,
30300
- disabled: disabled === true || saving
30301
- })] });
30326
+ const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [
30327
+ effectiveMode === "override" ? /* @__PURE__ */ jsx("div", {
30328
+ className: "mb-2 text-[11px] text-foreground-subtle",
30329
+ children: "Benchmark override — applies to this run only. The addon's saved settings are not changed."
30330
+ }) : null,
30331
+ saving ? /* @__PURE__ */ jsx("div", {
30332
+ className: "mb-2 text-[11px] text-foreground-subtle",
30333
+ "aria-live": "polite",
30334
+ children: "Saving…"
30335
+ }) : null,
30336
+ /* @__PURE__ */ jsx(ConfigFormBuilder, {
30337
+ schema: schemaNoValues,
30338
+ values: effectiveValues,
30339
+ onChange: handleChange,
30340
+ disabled: disabled === true
30341
+ })
30342
+ ] });
30302
30343
  if (collapsible === true) return /* @__PURE__ */ jsxs("section", {
30303
30344
  className: "rounded-lg border border-border bg-surface overflow-hidden",
30304
30345
  children: [/* @__PURE__ */ jsxs("button", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/ui-library",
3
- "version": "1.2.260",
3
+ "version": "1.2.261",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",