claude-artifact-framework 0.20.0 → 0.20.1

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.esm.js CHANGED
@@ -672,7 +672,10 @@ function validateField(field, value) {
672
672
  return null;
673
673
  }
674
674
  function Field({ field, value, onChange, data }) {
675
- const error = validateField(field, value);
675
+ const [touched, setTouched] = useState(false);
676
+ const rawError = validateField(field, value);
677
+ const pristineEmpty = !touched && (value === "" || value === null || value === void 0);
678
+ const error = pristineEmpty ? null : rawError;
676
679
  const id = `caf-f-${field.key}`;
677
680
  const numeric = field.type === "number" || field.type === "money" || field.type === "percent";
678
681
  if (field.type === "file") {
@@ -706,6 +709,7 @@ function Field({ field, value, onChange, data }) {
706
709
  id,
707
710
  value: value === null || value === void 0 ? "" : value,
708
711
  "aria-invalid": error ? "true" : void 0,
712
+ onBlur: () => setTouched(true),
709
713
  onChange: (e) => onChange(numeric ? toNumber(e.target.value) : e.target.value)
710
714
  };
711
715
  let control;
@@ -803,15 +807,16 @@ function StatGrid({ items, title }) {
803
807
  createElement(
804
808
  "div",
805
809
  { className: "caf-output-grid" },
806
- items.map(
807
- (item, i) => createElement(
810
+ items.map((item, i) => {
811
+ const neg = (item.format === "money" || item.format === "number") && Number(item.value) < 0;
812
+ return createElement(
808
813
  "div",
809
814
  { key: item.label || i, className: item.big ? "caf-stat caf-stat-big" : "caf-stat" },
810
815
  createElement("span", { className: "caf-stat-label" }, item.label),
811
- createElement("span", { className: "caf-stat-value" }, formatValue(item.value, item.format)),
816
+ createElement("span", { className: neg ? "caf-stat-value caf-stat-neg" : "caf-stat-value" }, formatValue(item.value, item.format)),
812
817
  item.hint ? createElement("small", { className: "caf-hint" }, item.hint) : null
813
- )
814
- )
818
+ );
819
+ })
815
820
  )
816
821
  );
817
822
  }
@@ -2756,7 +2761,10 @@ var BASE_CSS = `
2756
2761
  .caf-doc-close:hover { color: var(--caf-danger); }
2757
2762
  .caf-doc-add { font-size: 1rem; font-weight: 650; }
2758
2763
  .caf-empty .caf-btn { margin-top: 0.6rem; }
2759
- .caf-records-block { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
2764
+ /* Tight gap: the block title is a SECTION head for the cards below \u2014 it
2765
+ must hug its group, not float equidistant (audited on the retro board). */
2766
+ .caf-records-block { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
2767
+ .caf-stat-neg, .caf-stat-big .caf-stat-value.caf-stat-neg { color: var(--caf-danger); }
2760
2768
  .caf-doc-typemenu { display: flex; gap: 0.5rem; flex-wrap: wrap; }
2761
2769
  .caf-header-brand { display: flex; align-items: center; gap: 0.8rem; }
2762
2770
  /* Where the page has a gutter, the logo lives in it: the title keeps the
@@ -2768,7 +2776,7 @@ var BASE_CSS = `
2768
2776
  .caf-header-brand .caf-logo { position: absolute; right: 100%; margin-right: 0.85rem; top: 0.1rem; }
2769
2777
  }
2770
2778
  .caf-header-text { min-width: 0; }
2771
- .caf-logo { flex: none; width: 40px; height: 40px; border-radius: 9px; object-fit: contain; }
2779
+ .caf-logo { flex: none; width: 40px; height: 40px; border-radius: 9px; object-fit: contain; overflow: hidden; }
2772
2780
  .caf-logo-emoji { display: flex; align-items: center; justify-content: center; font-size: 1.7rem; background: var(--caf-surface); border: 1px solid var(--caf-border); }
2773
2781
  .caf-logo-mono {
2774
2782
  display: flex; align-items: center; justify-content: center;