claude-artifact-framework 0.8.1 → 0.9.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 +19 -2
- package/dist/index.esm.js +61 -26
- package/dist/index.esm.js.map +2 -2
- package/dist/index.global.js +52 -30
- package/dist/index.global.js.map +3 -3
- package/package.json +1 -1
- package/src/app.js +66 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-artifact-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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
|
@@ -419,7 +419,9 @@ function Panel({ spec, ctx }) {
|
|
|
419
419
|
(spec.blocks || []).map((block, i) =>
|
|
420
420
|
h(
|
|
421
421
|
"section",
|
|
422
|
-
|
|
422
|
+
// A collapsible is always full-width: half-width accordions leave an
|
|
423
|
+
// orphaned right edge on desktop and change width across breakpoints.
|
|
424
|
+
{ key: i, className: block.wide || block.collapsible ? "caf-slot caf-slot-wide" : "caf-slot" },
|
|
423
425
|
h(Block, { block, ctx })
|
|
424
426
|
)
|
|
425
427
|
)
|
|
@@ -444,7 +446,9 @@ function RecordsWithBlocks({ spec, ctx }) {
|
|
|
444
446
|
spec.blocks.map((block, i) =>
|
|
445
447
|
h(
|
|
446
448
|
"section",
|
|
447
|
-
|
|
449
|
+
// A collapsible is always full-width: half-width accordions leave an
|
|
450
|
+
// orphaned right edge on desktop and change width across breakpoints.
|
|
451
|
+
{ key: i, className: block.wide || block.collapsible ? "caf-slot caf-slot-wide" : "caf-slot" },
|
|
448
452
|
h(Block, { block, ctx })
|
|
449
453
|
)
|
|
450
454
|
)
|
|
@@ -482,7 +486,19 @@ function loadScript(src) {
|
|
|
482
486
|
const tag = document.createElement("script");
|
|
483
487
|
tag.src = src;
|
|
484
488
|
tag.onload = () => { tag.dataset.cafReady = "1"; resolve(); };
|
|
485
|
-
tag.onerror = () =>
|
|
489
|
+
tag.onerror = () => {
|
|
490
|
+
// Models guess file paths inside packages and get them wrong more often
|
|
491
|
+
// than they get versions wrong (measured: marked@13's UMD lives at
|
|
492
|
+
// lib/marked.umd.js, not the root the model wrote). jsDelivr serves a
|
|
493
|
+
// package's default build at the bare npm/<pkg>@<version> URL, so one
|
|
494
|
+
// retry there absorbs the whole failure class.
|
|
495
|
+
const m = src.match(/^(https:\/\/cdn\.jsdelivr\.net\/npm\/(?:@[^/]+\/)?[^/]+)\/.+/);
|
|
496
|
+
if (m && m[1] !== src) {
|
|
497
|
+
loadScript(m[1]).then(resolve, () => reject(new Error(`failed to load ${src} (also tried package default ${m[1]})`)));
|
|
498
|
+
} else {
|
|
499
|
+
reject(new Error(`failed to load ${src}`));
|
|
500
|
+
}
|
|
501
|
+
};
|
|
486
502
|
document.head.appendChild(tag);
|
|
487
503
|
});
|
|
488
504
|
}
|
|
@@ -540,7 +556,9 @@ export function createApp(spec = {}) {
|
|
|
540
556
|
|
|
541
557
|
return h(
|
|
542
558
|
"div",
|
|
543
|
-
|
|
559
|
+
// The layout class lets shared CSS follow the active container width —
|
|
560
|
+
// e.g. the header must share the workspace's wider axis, not panel's.
|
|
561
|
+
{ className: `caf-root caf-layout-${layout}` },
|
|
544
562
|
h("style", { dangerouslySetInnerHTML: { __html: css } }),
|
|
545
563
|
h(
|
|
546
564
|
"header",
|
|
@@ -565,6 +583,10 @@ export function createApp(spec = {}) {
|
|
|
565
583
|
const BASE_CSS = `
|
|
566
584
|
.caf-root {
|
|
567
585
|
--caf-radius: 10px;
|
|
586
|
+
--caf-control-radius: 7px; /* one radius for every control: buttons, inputs, rows */
|
|
587
|
+
--caf-btn-pad-y: 0.45rem;
|
|
588
|
+
--caf-btn-pad-x: 0.8rem;
|
|
589
|
+
--caf-num-primary: 2.1rem; /* the one size for a block's dominant number */
|
|
568
590
|
box-sizing: border-box;
|
|
569
591
|
min-height: 100vh;
|
|
570
592
|
padding: 2rem 1.25rem 4rem;
|
|
@@ -575,9 +597,12 @@ const BASE_CSS = `
|
|
|
575
597
|
}
|
|
576
598
|
.caf-root *, .caf-root *::before, .caf-root *::after { box-sizing: inherit; }
|
|
577
599
|
.caf-header { max-width: 760px; margin: 0 auto 1.5rem; }
|
|
600
|
+
/* One left axis per screen: the header adopts the workspace's wider container. */
|
|
601
|
+
.caf-layout-workspace .caf-header { max-width: 1200px; }
|
|
578
602
|
.caf-header h1 { margin: 0; font-size: 1.5rem; font-weight: 650; letter-spacing: -0.01em; text-wrap: balance; }
|
|
579
603
|
.caf-header p { margin: 0.4rem 0 0; color: var(--caf-muted); font-size: 0.95rem; line-height: 1.5; }
|
|
580
|
-
|
|
604
|
+
/* Between-card air must beat within-card padding (1.1rem), or groups dissolve. */
|
|
605
|
+
.caf-panel { max-width: 760px; margin: 0 auto; display: grid; grid-template-columns: 1fr 1fr; gap: 1.75rem 1rem; }
|
|
581
606
|
.caf-slot { grid-column: span 2; min-width: 0; }
|
|
582
607
|
@media (min-width: 720px) { .caf-slot { grid-column: span 1; } .caf-slot-wide { grid-column: span 2; } }
|
|
583
608
|
.caf-block {
|
|
@@ -590,12 +615,12 @@ const BASE_CSS = `
|
|
|
590
615
|
gap: 0.8rem;
|
|
591
616
|
height: 100%;
|
|
592
617
|
}
|
|
593
|
-
.caf-block-title { margin: 0; font-size: 0.
|
|
618
|
+
.caf-block-title { margin: 0; font-size: 0.78rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--caf-muted); }
|
|
594
619
|
.caf-field { display: flex; flex-direction: column; gap: 0.3rem; }
|
|
595
|
-
.caf-field label { font-size: 0.
|
|
620
|
+
.caf-field label { font-size: 0.72rem; font-weight: 500; color: var(--caf-muted); letter-spacing: 0.02em; }
|
|
596
621
|
.caf-field input, .caf-field select, .caf-field textarea {
|
|
597
622
|
font: inherit; font-size: 0.95rem; padding: 0.5rem 0.6rem;
|
|
598
|
-
border-radius:
|
|
623
|
+
border-radius: var(--caf-control-radius); border: 1px solid var(--caf-border);
|
|
599
624
|
background: var(--caf-sunken); color: var(--caf-text); width: 100%;
|
|
600
625
|
}
|
|
601
626
|
.caf-field input:focus-visible, .caf-field select:focus-visible, .caf-field textarea:focus-visible,
|
|
@@ -604,17 +629,21 @@ const BASE_CSS = `
|
|
|
604
629
|
.caf-check { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; }
|
|
605
630
|
.caf-hint { color: var(--caf-muted); font-size: 0.75rem; }
|
|
606
631
|
.caf-error { color: var(--caf-danger); font-size: 0.75rem; font-weight: 600; }
|
|
607
|
-
.caf-output-grid { display:
|
|
608
|
-
|
|
609
|
-
.caf-stat
|
|
610
|
-
.caf-stat-
|
|
611
|
-
.caf-stat-
|
|
612
|
-
.caf-stat-big
|
|
632
|
+
.caf-output-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 0.9rem 1.1rem; }
|
|
633
|
+
/* Every stat shares one axis: label above value, both flush left. */
|
|
634
|
+
.caf-stat { display: flex; flex-direction: column; align-items: flex-start; gap: 0.1rem; }
|
|
635
|
+
.caf-stat-label { color: var(--caf-muted); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.02em; }
|
|
636
|
+
.caf-stat-value { font-size: 1.05rem; font-weight: 650; font-variant-numeric: tabular-nums; }
|
|
637
|
+
.caf-stat-big { grid-column: 1 / -1; }
|
|
638
|
+
/* The divider exists to separate the hero from stats below it — alone in the
|
|
639
|
+
grid it would be an orphaned rule, so it only renders when followed. */
|
|
640
|
+
.caf-stat-big:not(:last-child) { padding-bottom: 0.5rem; border-bottom: 1px solid var(--caf-border); }
|
|
641
|
+
.caf-stat-big .caf-stat-value { font-size: var(--caf-num-primary); font-weight: 700; letter-spacing: -0.02em; color: var(--caf-accent); line-height: 1.15; }
|
|
613
642
|
.caf-list { padding: 0.4rem; gap: 0; }
|
|
614
643
|
.caf-row {
|
|
615
644
|
font: inherit; text-align: left; cursor: pointer;
|
|
616
645
|
display: flex; flex-direction: column; gap: 0.15rem;
|
|
617
|
-
padding: 0.65rem 0.7rem; border: none; border-radius:
|
|
646
|
+
padding: 0.65rem 0.7rem; border: none; border-radius: var(--caf-control-radius);
|
|
618
647
|
background: transparent; color: inherit; width: 100%;
|
|
619
648
|
}
|
|
620
649
|
.caf-row:hover { background: var(--caf-sunken); }
|
|
@@ -626,8 +655,9 @@ const BASE_CSS = `
|
|
|
626
655
|
.caf-count { font-size: 0.8rem; color: var(--caf-muted); font-variant-numeric: tabular-nums; }
|
|
627
656
|
.caf-btn {
|
|
628
657
|
font: inherit; font-size: 0.85rem; font-weight: 600; cursor: pointer;
|
|
629
|
-
padding:
|
|
630
|
-
border: 1px solid var(--caf-border); background: var(--caf-
|
|
658
|
+
padding: var(--caf-btn-pad-y) var(--caf-btn-pad-x); border-radius: var(--caf-control-radius);
|
|
659
|
+
border: 1px solid var(--caf-border); background: var(--caf-surface); color: var(--caf-text);
|
|
660
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
631
661
|
}
|
|
632
662
|
.caf-btn:hover { filter: brightness(0.97); }
|
|
633
663
|
.caf-btn:focus-visible { outline: 2px solid var(--caf-accent); outline-offset: 1px; }
|
|
@@ -648,14 +678,16 @@ const BASE_CSS = `
|
|
|
648
678
|
.caf-donut { display: flex; align-items: center; gap: 1.1rem; flex-wrap: wrap; }
|
|
649
679
|
.caf-donut-svg { width: 110px; height: 110px; flex: none; transform: rotate(0.001deg); }
|
|
650
680
|
.caf-donut-seg { fill: none; stroke-width: 6; }
|
|
651
|
-
|
|
681
|
+
/* Capped width keeps each value NEXT TO its label in wide cards — the pair
|
|
682
|
+
must read as a pair regardless of container width. */
|
|
683
|
+
.caf-donut-legend { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; flex: 1; max-width: 260px; }
|
|
652
684
|
.caf-legend-row { display: flex; align-items: center; gap: 0.5rem; font-size: 0.84rem; }
|
|
653
685
|
.caf-legend-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
|
|
654
686
|
.caf-legend-label { color: var(--caf-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
655
687
|
.caf-legend-value { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
656
688
|
.caf-timer { align-items: center; text-align: center; }
|
|
657
689
|
.caf-timer .caf-bar-track { width: 100%; }
|
|
658
|
-
.caf-timer-time { font-size:
|
|
690
|
+
.caf-timer-time { font-size: var(--caf-num-primary); font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--caf-accent); }
|
|
659
691
|
.caf-timer-done { color: var(--caf-accent); }
|
|
660
692
|
.caf-timer-fill { transition: width 0.9s linear; }
|
|
661
693
|
.caf-timer-controls { display: flex; gap: 0.6rem; }
|
|
@@ -672,8 +704,11 @@ const BASE_CSS = `
|
|
|
672
704
|
.caf-msg-tools { align-self: flex-start; font-size: 0.74rem; color: var(--caf-muted); padding: 0.15rem 0.55rem; border: 1px solid var(--caf-border); border-radius: 999px; }
|
|
673
705
|
.caf-msg-error { align-self: stretch; max-width: none; display: flex; flex-direction: column; gap: 0.2rem; background: transparent; border: 1px solid var(--caf-danger); }
|
|
674
706
|
.caf-msg-error strong { color: var(--caf-danger); font-size: 0.85rem; }
|
|
675
|
-
.caf-chat-input {
|
|
676
|
-
|
|
707
|
+
.caf-chat-input {
|
|
708
|
+
display: flex; gap: 0.6rem; margin-top: 1rem; padding: 0.6rem;
|
|
709
|
+
background: var(--caf-surface); border: 1px solid var(--caf-border); border-radius: var(--caf-radius);
|
|
710
|
+
}
|
|
711
|
+
.caf-chat-input input { flex: 1; font: inherit; font-size: 0.95rem; padding: 0.55rem 0.7rem; border-radius: var(--caf-control-radius); border: 1px solid var(--caf-border); background: var(--caf-sunken); color: var(--caf-text); }
|
|
677
712
|
.caf-chat-input input:focus-visible { outline: 2px solid var(--caf-accent); outline-offset: 1px; }
|
|
678
713
|
.caf-search {
|
|
679
714
|
font: inherit; font-size: 0.9rem; width: 100%;
|
|
@@ -687,7 +722,7 @@ const BASE_CSS = `
|
|
|
687
722
|
.caf-row-wrap { display: flex; align-items: center; gap: 0.4rem; }
|
|
688
723
|
.caf-row-wrap .caf-row { flex: 1; min-width: 0; }
|
|
689
724
|
.caf-row-actions { display: flex; gap: 0.35rem; flex: none; padding-right: 0.3rem; }
|
|
690
|
-
.caf-btn-sm { font-size: 0.78rem; padding:
|
|
725
|
+
.caf-btn-sm { font-size: 0.78rem; padding: calc(var(--caf-btn-pad-y) * 0.67) calc(var(--caf-btn-pad-x) * 0.75); }
|
|
691
726
|
.caf-items { display: flex; flex-direction: column; gap: 0.5rem; border-top: 1px solid var(--caf-border); padding-top: 0.7rem; }
|
|
692
727
|
.caf-item-row { display: flex; align-items: flex-end; gap: 0.5rem; }
|
|
693
728
|
.caf-item-row .caf-field { flex: 1; min-width: 0; }
|
|
@@ -719,15 +754,20 @@ const BASE_CSS = `
|
|
|
719
754
|
}
|
|
720
755
|
.caf-tab:hover { color: var(--caf-text); }
|
|
721
756
|
.caf-tab:focus-visible { outline: 2px solid var(--caf-accent); outline-offset: -2px; }
|
|
722
|
-
|
|
757
|
+
/* :hover on the active tab must not win the specificity race and mute it. */
|
|
758
|
+
.caf-tab-active, .caf-tab-active:hover { color: var(--caf-accent); border-bottom-color: var(--caf-accent); }
|
|
723
759
|
.caf-tabs-body { display: flex; flex-direction: column; gap: 0.8rem; }
|
|
724
760
|
.caf-collapse { display: flex; flex-direction: column; gap: 0.5rem; min-width: 0; }
|
|
725
761
|
.caf-collapse-head {
|
|
726
|
-
|
|
762
|
+
/* Same treatment as .caf-block-title: a collapsible header IS a card title. */
|
|
763
|
+
font: inherit; font-size: 0.78rem; font-weight: 650; text-transform: uppercase;
|
|
764
|
+
letter-spacing: 0.06em; color: var(--caf-muted); cursor: pointer;
|
|
727
765
|
display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
|
|
728
|
-
padding: 0.7rem 1rem; border: 1px solid var(--caf-border); border-radius: var(--caf-radius);
|
|
729
|
-
background: var(--caf-surface);
|
|
766
|
+
padding: 0.7rem 1.1rem; border: 1px solid var(--caf-border); border-radius: var(--caf-radius);
|
|
767
|
+
background: var(--caf-surface); width: 100%; text-align: left;
|
|
730
768
|
}
|
|
769
|
+
.caf-collapse-head { box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); }
|
|
770
|
+
.caf-collapse-head:hover { filter: brightness(0.97); }
|
|
731
771
|
.caf-collapse-head:focus-visible { outline: 2px solid var(--caf-accent); outline-offset: 1px; }
|
|
732
772
|
.caf-chevron { transition: transform 0.15s ease; color: var(--caf-muted); }
|
|
733
773
|
.caf-chevron-closed { transform: rotate(-90deg); }
|