claude-artifact-framework 0.15.0 → 0.16.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 +26 -3
- package/dist/index.esm.js +19 -1
- package/dist/index.esm.js.map +2 -2
- package/dist/index.global.js +16 -8
- package/dist/index.global.js.map +3 -3
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/src/app.js +20 -0
- package/src/blocks.js +4 -1
package/README.md
CHANGED
|
@@ -801,10 +801,30 @@ custom: (ctx) => React.createElement("div", {
|
|
|
801
801
|
`d.preview` can kill persistence for the entire app. Big things (data
|
|
802
802
|
URLs, file contents, parse results) live in `React.useState` or come from
|
|
803
803
|
`ctx.files`; `data` holds what is small and serializable.
|
|
804
|
+
- **Column grids ask `ctx.viewport`.** Half of artifact viewers are on a
|
|
805
|
+
phone. `ctx.viewport` is `"mobile"` (< 720px) or `"desktop"`, and the
|
|
806
|
+
block re-renders when it changes. A layout that lays columns side by side
|
|
807
|
+
(kanban boards, week calendars, dashboards of mini-cards) must stack or
|
|
808
|
+
reduce them on `"mobile"` — 3 columns squeezed into 390px are ~90px each
|
|
809
|
+
and unreadable:
|
|
810
|
+
|
|
811
|
+
```js
|
|
812
|
+
custom: (ctx) => {
|
|
813
|
+
const cols = ctx.viewport === "mobile" ? "1fr" : "repeat(3, 1fr)";
|
|
814
|
+
return React.createElement("div",
|
|
815
|
+
{ style: { display: "grid", gridTemplateColumns: cols, gap: "0.6rem" } },
|
|
816
|
+
/* ...columnas... */);
|
|
817
|
+
}
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
As a safety net the framework never clips: custom content wider than the
|
|
821
|
+
screen scrolls horizontally instead of disappearing. But scrolling a
|
|
822
|
+
squeezed board is the fallback, not the design — branch on `ctx.viewport`.
|
|
804
823
|
- Custom re-renders whenever `data` or `view` change; it receives the full
|
|
805
|
-
`ctx` (`data`, `update`, `view`, `files`, `viewerId`, `colors`,
|
|
806
|
-
`back`) and lives inside the block error boundary — a
|
|
807
|
-
code shows a named error in its slot, never a blank
|
|
824
|
+
`ctx` (`data`, `update`, `view`, `files`, `viewerId`, `colors`,
|
|
825
|
+
`viewport`, `go`, `back`) and lives inside the block error boundary — a
|
|
826
|
+
bug in your custom code shows a named error in its slot, never a blank
|
|
827
|
+
app.
|
|
808
828
|
|
|
809
829
|
## API reference
|
|
810
830
|
|
|
@@ -963,3 +983,6 @@ The rules that decide whether a generated app works, all in one place
|
|
|
963
983
|
13. **Brand is zero-asset-first** — monogram/gradient/emoji defaults before
|
|
964
984
|
URLs; inline `<svg>` over remote images; one icon style per app
|
|
965
985
|
(emoji-first); `avatar: true` instead of hand-built initials circles.
|
|
986
|
+
14. **Column grids in `custom` branch on `ctx.viewport`** — stack kanban
|
|
987
|
+
columns / week grids when it says `"mobile"`; half the viewers are on
|
|
988
|
+
a phone.
|
package/dist/index.esm.js
CHANGED
|
@@ -1023,7 +1023,7 @@ function ActionsBlock({ spec, ctx }) {
|
|
|
1023
1023
|
}
|
|
1024
1024
|
function CustomBlock({ spec, ctx }) {
|
|
1025
1025
|
const rendered = spec.custom(ctx);
|
|
1026
|
-
const cls = spec.fill ? "caf-block caf-block-fill" : "caf-block";
|
|
1026
|
+
const cls = spec.fill ? "caf-block caf-block-fill caf-custom" : "caf-block caf-custom";
|
|
1027
1027
|
if (typeof rendered === "string") {
|
|
1028
1028
|
return createElement("div", { className: cls, dangerouslySetInnerHTML: { __html: rendered } });
|
|
1029
1029
|
}
|
|
@@ -2321,6 +2321,15 @@ function createApp(spec = {}) {
|
|
|
2321
2321
|
);
|
|
2322
2322
|
}
|
|
2323
2323
|
const [, force] = useState(0);
|
|
2324
|
+
const [narrow, setNarrow] = useState(
|
|
2325
|
+
() => typeof window !== "undefined" && window.matchMedia("(max-width: 719px)").matches
|
|
2326
|
+
);
|
|
2327
|
+
useEffect(() => {
|
|
2328
|
+
const mq = window.matchMedia("(max-width: 719px)");
|
|
2329
|
+
const onChange = (e) => setNarrow(e.matches);
|
|
2330
|
+
mq.addEventListener("change", onChange);
|
|
2331
|
+
return () => mq.removeEventListener("change", onChange);
|
|
2332
|
+
}, []);
|
|
2324
2333
|
const [libsState, setLibsState] = useState(spec.libs && spec.libs.length ? "loading" : "ready");
|
|
2325
2334
|
const [libsError, setLibsError] = useState(null);
|
|
2326
2335
|
useEffect(() => {
|
|
@@ -2366,6 +2375,7 @@ function createApp(spec = {}) {
|
|
|
2366
2375
|
setTab: (key, i) => state.setView({ tabs: { ...state.getView().tabs, [key]: i } }),
|
|
2367
2376
|
toggleCollapsed: (key, val) => state.setView({ collapsed: { ...state.getView().collapsed, [key]: val } }),
|
|
2368
2377
|
colors: (n) => seriesColors(spec.theme && spec.theme.seed, n),
|
|
2378
|
+
viewport: narrow ? "mobile" : "desktop",
|
|
2369
2379
|
machine: spec.machine || null,
|
|
2370
2380
|
send: spec.machine ? (eventName, payload) => runMachineEvent(spec.machine, state.update, eventName, payload) : () => {
|
|
2371
2381
|
throw new Error("claude-artifact-framework: ctx.send() needs a `machine` declared at the top level.");
|
|
@@ -2649,6 +2659,14 @@ var BASE_CSS = `
|
|
|
2649
2659
|
.caf-block-error { border-color: var(--caf-danger); gap: 0.4rem; }
|
|
2650
2660
|
.caf-block-error strong { font-size: 0.9rem; color: var(--caf-danger); }
|
|
2651
2661
|
.caf-block-error code { font-size: 0.78rem; color: var(--caf-muted); word-break: break-word; }
|
|
2662
|
+
/* Never-clip guarantee: content inside a custom block that is wider than the
|
|
2663
|
+
phone (column grids, week views) must scroll, not disappear off-screen. */
|
|
2664
|
+
.caf-custom { overflow-x: auto; }
|
|
2665
|
+
/* Touch devices get tappable framework controls regardless of the spec. */
|
|
2666
|
+
@media (pointer: coarse) {
|
|
2667
|
+
.caf-btn, .caf-tab, .caf-field input, .caf-field select { min-height: 44px; }
|
|
2668
|
+
.caf-btn-sm, .caf-doc-close, .caf-item-remove { min-height: 40px; }
|
|
2669
|
+
}
|
|
2652
2670
|
`;
|
|
2653
2671
|
export {
|
|
2654
2672
|
contrast,
|