claude-artifact-framework 0.6.0 → 0.7.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.
package/README.md CHANGED
@@ -12,7 +12,7 @@ mirrors npm packages automatically.
12
12
  ### As a global script (`<script>` tag)
13
13
 
14
14
  ```html
15
- <script src="https://cdn.jsdelivr.net/npm/claude-artifact-framework@0.6.0/dist/index.global.js"></script>
15
+ <script src="https://cdn.jsdelivr.net/npm/claude-artifact-framework@0.7.0/dist/index.global.js"></script>
16
16
  <script>
17
17
  const { storage, createStore, createPersistedStore, createSharedStore } = ArtifactKit;
18
18
  </script>
@@ -27,11 +27,11 @@ mirrors npm packages automatically.
27
27
  createStore,
28
28
  createPersistedStore,
29
29
  createSharedStore,
30
- } from "https://cdn.jsdelivr.net/npm/claude-artifact-framework@0.6.0/dist/index.esm.js";
30
+ } from "https://cdn.jsdelivr.net/npm/claude-artifact-framework@0.7.0/dist/index.esm.js";
31
31
  </script>
32
32
  ```
33
33
 
34
- Pin a version (`@0.6.0`) for reproducible artifacts, or drop the version
34
+ Pin a version (`@0.7.0`) for reproducible artifacts, or drop the version
35
35
  (`claude-artifact-framework/dist/...`) to always get the latest release.
36
36
 
37
37
  ### Inside a React artifact
@@ -334,7 +334,8 @@ else — the collection lives at `d.records`.
334
334
 
335
335
  **Field types** (`type:` on any field): `text` (default), `textarea`,
336
336
  `number`, `money`, `percent`, `check` (checkbox), `date`, `select` (needs
337
- `options`). Other field keys: `key` (required), `label`, `value` (initial),
337
+ `options` an array, or `(d) => [...]` for choices that come from the
338
+ app's data, e.g. a "who paid" select fed by a user-entered group). Other field keys: `key` (required), `label`, `value` (initial),
338
339
  `required`, `min`, `max`, `step`, `placeholder`, `hint`, `rows`, `options`.
339
340
  An unknown `type` throws naming the valid ones.
340
341
 
@@ -350,7 +351,21 @@ keys must be unique across steps.
350
351
  `{ description, input, run(input, ctx) }`.
351
352
 
352
353
  **Formats** (`format:` on output/chart/compute items): `money`, `percent`,
353
- `number`, `date`.
354
+ `number`, `date`. `percent` expects 0–100 (pass `ratio * 100`, not the raw
355
+ ratio).
356
+
357
+ **Quick-add pattern** — a lightweight alternative to `records` when you just
358
+ need "type something, press a button, it lands in a list":
359
+
360
+ ```js
361
+ blocks: [
362
+ { fields: [{ key: "nueva", label: "Persona", type: "text" }] },
363
+ { actions: [{ label: "Agregar", kind: "primary", run: (d) => {
364
+ if (d.nueva && d.nueva.trim()) { d.personas = [...(d.personas || []), d.nueva.trim()]; d.nueva = ""; }
365
+ }}]},
366
+ { text: (d) => (d.personas || []).join(", ") || "Sin personas todavía" },
367
+ ]
368
+ ```
354
369
 
355
370
  ## `storage`
356
371
 
package/dist/index.esm.js CHANGED
@@ -403,7 +403,7 @@ function validateField(field, value) {
403
403
  }
404
404
  return null;
405
405
  }
406
- function Field({ field, value, onChange }) {
406
+ function Field({ field, value, onChange, data }) {
407
407
  const error = validateField(field, value);
408
408
  const id = `caf-f-${field.key}`;
409
409
  const numeric = field.type === "number" || field.type === "money" || field.type === "percent";
@@ -430,11 +430,12 @@ function Field({ field, value, onChange }) {
430
430
  if (field.type === "textarea") {
431
431
  control = createElement("textarea", { ...common, rows: field.rows || 3 });
432
432
  } else if (field.type === "select") {
433
+ const options = typeof field.options === "function" ? field.options(data) || [] : field.options || [];
433
434
  control = createElement(
434
435
  "select",
435
436
  common,
436
437
  createElement("option", { value: "" }, field.placeholder || "Select\u2026"),
437
- (field.options || []).map((opt) => {
438
+ options.map((opt) => {
438
439
  const val = typeof opt === "string" ? opt : opt.value;
439
440
  const label = typeof opt === "string" ? opt : opt.label;
440
441
  return createElement("option", { key: val, value: val }, label);
@@ -474,6 +475,7 @@ function FieldsBlock({ spec, ctx }) {
474
475
  (field) => createElement(Field, {
475
476
  key: field.key,
476
477
  field,
478
+ data: ctx.data,
477
479
  value: ctx.data[field.key],
478
480
  onChange: (v) => ctx.update((d) => {
479
481
  d[field.key] = v;
@@ -517,13 +519,15 @@ function TextBlock({ spec, ctx }) {
517
519
  }
518
520
  function ListBlock({ spec, ctx }) {
519
521
  const rows = (typeof spec.list === "function" ? spec.list(ctx.data) : spec.list) || [];
522
+ const heading = typeof spec.title === "string" ? spec.title : null;
523
+ const rowTitle2 = typeof spec.title === "function" ? spec.title : (r) => r.title ?? r.name ?? r.label ?? r.text ?? String(r);
520
524
  if (!rows.length) {
521
525
  return createElement("div", { className: "caf-block caf-empty" }, spec.empty || "Nothing here yet.");
522
526
  }
523
- const title = spec.title || ((r) => r.title ?? r.name ?? r.label ?? String(r));
524
527
  return createElement(
525
528
  "div",
526
529
  { className: "caf-block caf-list" },
530
+ heading ? createElement("h2", { className: "caf-block-title" }, heading) : null,
527
531
  rows.map(
528
532
  (row, i) => createElement(
529
533
  "button",
@@ -533,7 +537,7 @@ function ListBlock({ spec, ctx }) {
533
537
  type: "button",
534
538
  onClick: spec.onSelect ? () => spec.onSelect(row, ctx) : void 0
535
539
  },
536
- createElement("span", { className: "caf-row-title" }, title(row)),
540
+ createElement("span", { className: "caf-row-title" }, rowTitle2(row)),
537
541
  spec.subtitle ? createElement("span", { className: "caf-row-sub" }, spec.subtitle(row)) : null
538
542
  )
539
543
  )
@@ -890,6 +894,7 @@ function DetailScreen({ spec, ctx, record }) {
890
894
  (field) => createElement(Field, {
891
895
  key: field.key,
892
896
  field,
897
+ data: ctx.data,
893
898
  value: record[field.key],
894
899
  onChange: (v) => ctx.update((d) => {
895
900
  const rec = d.records.find((r) => r.id === record.id);
@@ -950,6 +955,7 @@ function ItemsEditor({ spec, ctx, record }) {
950
955
  (field) => createElement(Field, {
951
956
  key: field.key,
952
957
  field,
958
+ data: ctx.data,
953
959
  value: item[field.key],
954
960
  onChange: (v) => mutate((rec) => {
955
961
  const it = rec.items.find((x) => x.id === item.id);
@@ -1047,6 +1053,7 @@ function StepsLayout({ spec, ctx }) {
1047
1053
  (field) => createElement(Field, {
1048
1054
  key: field.key,
1049
1055
  field,
1056
+ data: ctx.data,
1050
1057
  value: ctx.data[field.key],
1051
1058
  onChange: (v) => ctx.update((d) => {
1052
1059
  d[field.key] = v;
@@ -1316,6 +1323,11 @@ function checkFields(fields, where) {
1316
1323
  `claude-artifact-framework: field "${f.key}" in ${where} has unknown type "${f.type}". Valid types: ${FIELD_TYPES.join(", ")}.`
1317
1324
  );
1318
1325
  }
1326
+ if (f.type === "select" && f.options !== void 0 && !Array.isArray(f.options) && typeof f.options !== "function") {
1327
+ throw new Error(
1328
+ `claude-artifact-framework: field "${f.key}" in ${where}: \`options\` must be an array or a function of data returning one.`
1329
+ );
1330
+ }
1319
1331
  }
1320
1332
  }
1321
1333
  var ACTION_KEYS = ["label", "run", "when", "kind"];