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/llms.txt
CHANGED
|
@@ -64,6 +64,10 @@ https://cdn.jsdelivr.net/npm/claude-artifact-framework/dist/index.global.js
|
|
|
64
64
|
13. Brand is zero-asset-first: monogram/gradient/emoji defaults before URLs;
|
|
65
65
|
inline <svg> over remote images; one icon style per app (emoji-first);
|
|
66
66
|
avatar: true instead of hand-built initials circles.
|
|
67
|
+
14. Column grids in custom (kanban, week views) branch on ctx.viewport
|
|
68
|
+
("mobile" < 720px | "desktop", reactive) — stack columns on mobile; half
|
|
69
|
+
the viewers are on a phone. The framework never clips (wide custom
|
|
70
|
+
content scrolls), but scrolling is the fallback, not the design.
|
|
67
71
|
|
|
68
72
|
## Canonical example
|
|
69
73
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-artifact-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Utilities for building apps inside Claude Artifacts: platform storage, chat tool-calling loops, and other primitives verified against the real runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.esm.js",
|
package/src/app.js
CHANGED
|
@@ -1029,6 +1029,17 @@ export function createApp(spec = {}) {
|
|
|
1029
1029
|
);
|
|
1030
1030
|
}
|
|
1031
1031
|
const [, force] = useState(0);
|
|
1032
|
+
// ctx.viewport shares the 720px breakpoint the block grid already uses,
|
|
1033
|
+
// so a custom block that branches on it flips in sync with the layout.
|
|
1034
|
+
const [narrow, setNarrow] = useState(
|
|
1035
|
+
() => typeof window !== "undefined" && window.matchMedia("(max-width: 719px)").matches
|
|
1036
|
+
);
|
|
1037
|
+
useEffect(() => {
|
|
1038
|
+
const mq = window.matchMedia("(max-width: 719px)");
|
|
1039
|
+
const onChange = (e) => setNarrow(e.matches);
|
|
1040
|
+
mq.addEventListener("change", onChange);
|
|
1041
|
+
return () => mq.removeEventListener("change", onChange);
|
|
1042
|
+
}, []);
|
|
1032
1043
|
const [libsState, setLibsState] = useState(spec.libs && spec.libs.length ? "loading" : "ready");
|
|
1033
1044
|
const [libsError, setLibsError] = useState(null);
|
|
1034
1045
|
useEffect(() => {
|
|
@@ -1081,6 +1092,7 @@ export function createApp(spec = {}) {
|
|
|
1081
1092
|
setTab: (key, i) => state.setView({ tabs: { ...state.getView().tabs, [key]: i } }),
|
|
1082
1093
|
toggleCollapsed: (key, val) => state.setView({ collapsed: { ...state.getView().collapsed, [key]: val } }),
|
|
1083
1094
|
colors: (n) => seriesColors(spec.theme && spec.theme.seed, n),
|
|
1095
|
+
viewport: narrow ? "mobile" : "desktop",
|
|
1084
1096
|
machine: spec.machine || null,
|
|
1085
1097
|
send: spec.machine
|
|
1086
1098
|
? (eventName, payload) => runMachineEvent(spec.machine, state.update, eventName, payload)
|
|
@@ -1390,4 +1402,12 @@ const BASE_CSS = `
|
|
|
1390
1402
|
.caf-block-error { border-color: var(--caf-danger); gap: 0.4rem; }
|
|
1391
1403
|
.caf-block-error strong { font-size: 0.9rem; color: var(--caf-danger); }
|
|
1392
1404
|
.caf-block-error code { font-size: 0.78rem; color: var(--caf-muted); word-break: break-word; }
|
|
1405
|
+
/* Never-clip guarantee: content inside a custom block that is wider than the
|
|
1406
|
+
phone (column grids, week views) must scroll, not disappear off-screen. */
|
|
1407
|
+
.caf-custom { overflow-x: auto; }
|
|
1408
|
+
/* Touch devices get tappable framework controls regardless of the spec. */
|
|
1409
|
+
@media (pointer: coarse) {
|
|
1410
|
+
.caf-btn, .caf-tab, .caf-field input, .caf-field select { min-height: 44px; }
|
|
1411
|
+
.caf-btn-sm, .caf-doc-close, .caf-item-remove { min-height: 40px; }
|
|
1412
|
+
}
|
|
1393
1413
|
`;
|
package/src/blocks.js
CHANGED
|
@@ -485,7 +485,10 @@ export function CustomBlock({ spec, ctx }) {
|
|
|
485
485
|
const rendered = spec.custom(ctx);
|
|
486
486
|
// `fill: true` frees the block from the card chrome so it can own a large
|
|
487
487
|
// scrollable surface (a viewer, a canvas) — the workspace main-area case.
|
|
488
|
-
|
|
488
|
+
// caf-custom guarantees a custom block can never CLIP its content on a
|
|
489
|
+
// narrow screen: wide hand-built grids become scrollable, not amputated
|
|
490
|
+
// (measured: a week grid cut off its last column at 390px with no way in).
|
|
491
|
+
const cls = spec.fill ? "caf-block caf-block-fill caf-custom" : "caf-block caf-custom";
|
|
489
492
|
if (typeof rendered === "string") {
|
|
490
493
|
return h("div", { className: cls, dangerouslySetInnerHTML: { __html: rendered } });
|
|
491
494
|
}
|