@kestack/web-platform 0.0.0 → 0.0.2
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 +6 -0
- package/dist/components/viewers/diff-viewer/diff-viewer.js +1 -1
- package/dist/components/viewers/source-explorer/source-explorer.js +1 -1
- package/dist/pwa/shared/config/config.js +1 -1
- package/dist/pwa/worker/requests/strategies/strategies.js +1 -1
- package/dist/recipes/devtools-dock/devtools-dock.d.ts +23 -0
- package/dist/recipes/devtools-dock/devtools-dock.d.ts.map +1 -0
- package/dist/recipes/devtools-dock/devtools-dock.js +343 -0
- package/dist/recipes/devtools-dock/devtools-dock.js.map +1 -0
- package/dist/recipes/devtools-dock/index.d.ts +2 -0
- package/dist/recipes/devtools-dock/index.js +2 -0
- package/dist/recipes/kabuki-devtools/kabuki-devtools.d.ts.map +1 -1
- package/dist/recipes/kabuki-devtools/kabuki-devtools.js +4 -1
- package/dist/recipes/kabuki-devtools/kabuki-devtools.js.map +1 -1
- package/dist/recipes/kabuki-devtools/map/canvas/canvas.d.ts.map +1 -1
- package/dist/recipes/kabuki-devtools/map/canvas/canvas.js +13 -0
- package/dist/recipes/kabuki-devtools/map/canvas/canvas.js.map +1 -1
- package/dist/recipes/kabuki-devtools/scene/tree.js +1 -1
- package/dist/recipes/kabuki-devtools/scene/tree.js.map +1 -1
- package/dist/recipes/kabuki-devtools/sheet/sheet.d.ts.map +1 -1
- package/dist/recipes/kabuki-devtools/sheet/sheet.js +84 -78
- package/dist/recipes/kabuki-devtools/sheet/sheet.js.map +1 -1
- package/dist/recipes/kabuki-devtools/timeline/timeline.d.ts +6 -1
- package/dist/recipes/kabuki-devtools/timeline/timeline.d.ts.map +1 -1
- package/dist/recipes/kabuki-devtools/timeline/timeline.js +202 -16
- package/dist/recipes/kabuki-devtools/timeline/timeline.js.map +1 -1
- package/package.json +17 -17
- package/src/recipes/devtools-dock/devtools-dock.tsx +505 -0
- package/src/recipes/devtools-dock/index.ts +2 -0
- package/src/recipes/kabuki-devtools/kabuki-devtools.tsx +4 -0
- package/src/recipes/kabuki-devtools/map/canvas/canvas.tsx +17 -1
- package/src/recipes/kabuki-devtools/scene/tree.ts +1 -1
- package/src/recipes/kabuki-devtools/sheet/sheet.tsx +95 -107
- package/src/recipes/kabuki-devtools/timeline/timeline.tsx +238 -19
|
@@ -1,22 +1,109 @@
|
|
|
1
1
|
import { cn } from "../../../components/lib/utils.js";
|
|
2
|
+
import { Select, SelectContent, SelectItem, SelectSeparator, SelectTrigger, SelectValue } from "../../../components/ui/select.js";
|
|
2
3
|
import { ink } from "../ink/ink.js";
|
|
3
|
-
import { useEffect, useRef } from "react";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
|
5
7
|
import { ChevronLeft, ChevronRight, GitBranch } from "lucide-react";
|
|
6
8
|
//#region src/recipes/kabuki-devtools/timeline/timeline.tsx
|
|
7
|
-
|
|
9
|
+
const PRESETS = [
|
|
10
|
+
1,
|
|
11
|
+
2,
|
|
12
|
+
5,
|
|
13
|
+
10,
|
|
14
|
+
25,
|
|
15
|
+
50,
|
|
16
|
+
100,
|
|
17
|
+
500
|
|
18
|
+
];
|
|
19
|
+
const HINTS = {
|
|
20
|
+
1: "Snapshot only",
|
|
21
|
+
2: "last change"
|
|
22
|
+
};
|
|
23
|
+
function Timeline({ steps, shown, live, onShow: showStep, onLive, head = false, branches = [], branch, onBranch, window, onWindow }) {
|
|
8
24
|
const track = useRef(null);
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
track.current?.querySelector("[aria-current=\"step\"]")?.scrollIntoView({
|
|
11
|
-
block: "nearest",
|
|
12
|
-
inline: "nearest"
|
|
13
|
-
});
|
|
14
|
-
}, [shown]);
|
|
15
25
|
const step = steps[shown];
|
|
16
26
|
const last = steps.length - 1;
|
|
27
|
+
const onShow = (index) => head && index === last ? onLive() : showStep(index);
|
|
28
|
+
const nameOf = (index) => index === 0 ? "init" : head && index === last && !live ? `${steps[index].label} · go live` : steps[index].label;
|
|
29
|
+
const bar = useRef(null);
|
|
30
|
+
const still = useReducedMotion();
|
|
31
|
+
const [near, setNear] = useState();
|
|
32
|
+
/** The tick nearest the pointer, gaps included, and its middle in the bar. */
|
|
33
|
+
/** The tick nearest a point across the track, gaps included. */
|
|
34
|
+
const nearestTo = (clientX) => {
|
|
35
|
+
const ticks = [...track.current.children];
|
|
36
|
+
let index = 0;
|
|
37
|
+
let best = Infinity;
|
|
38
|
+
ticks.forEach((tick, at) => {
|
|
39
|
+
const { left, width } = tick.getBoundingClientRect();
|
|
40
|
+
const off = Math.abs(left + width / 2 - clientX);
|
|
41
|
+
if (off < best) [index, best] = [at, off];
|
|
42
|
+
});
|
|
43
|
+
return index;
|
|
44
|
+
};
|
|
45
|
+
/** Where the mouse is over the track, to follow it as the row glides. */
|
|
46
|
+
const pointer = useRef(void 0);
|
|
47
|
+
const point = () => {
|
|
48
|
+
if (pointer.current === void 0) return;
|
|
49
|
+
const index = nearestTo(pointer.current);
|
|
50
|
+
const { left, width } = track.current.children[index].getBoundingClientRect();
|
|
51
|
+
const x = left + width / 2 - bar.current.getBoundingClientRect().left;
|
|
52
|
+
setNear((was) => was?.index === index && was.x === x ? was : {
|
|
53
|
+
index,
|
|
54
|
+
x
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const at = track.current;
|
|
59
|
+
const tick = at?.children[shown];
|
|
60
|
+
if (!at || !tick) return;
|
|
61
|
+
at.scrollTo({
|
|
62
|
+
left: tick.offsetLeft + tick.offsetWidth / 2 - at.clientWidth / 2,
|
|
63
|
+
behavior: still ? "instant" : "smooth"
|
|
64
|
+
});
|
|
65
|
+
}, [
|
|
66
|
+
shown,
|
|
67
|
+
steps.length,
|
|
68
|
+
still
|
|
69
|
+
]);
|
|
17
70
|
return /* @__PURE__ */ jsxs("div", {
|
|
18
|
-
|
|
71
|
+
ref: bar,
|
|
72
|
+
className: "bg-background/90 relative flex h-14 shrink-0 items-center gap-2 border-t px-2 backdrop-blur-sm @md:gap-3 @md:px-3",
|
|
73
|
+
style: { paddingRight: "calc(var(--dock-reserve, 0px) + 0.75rem)" },
|
|
19
74
|
children: [
|
|
75
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: near && steps[near.index] && /* @__PURE__ */ jsx(motion.div, {
|
|
76
|
+
role: "tooltip",
|
|
77
|
+
className: "bg-popover text-popover-foreground pointer-events-none absolute bottom-full left-0 mb-1.5 rounded-md border px-2 py-1 text-xs font-medium whitespace-nowrap shadow-[0_1px_2px_rgb(0_0_0/0.06),0_4px_12px_rgb(0_0_0/0.1)]",
|
|
78
|
+
initial: {
|
|
79
|
+
opacity: 0,
|
|
80
|
+
y: 4,
|
|
81
|
+
x: near.x,
|
|
82
|
+
translateX: "-50%"
|
|
83
|
+
},
|
|
84
|
+
animate: {
|
|
85
|
+
opacity: 1,
|
|
86
|
+
y: 0,
|
|
87
|
+
x: near.x,
|
|
88
|
+
translateX: "-50%"
|
|
89
|
+
},
|
|
90
|
+
exit: {
|
|
91
|
+
opacity: 0,
|
|
92
|
+
y: 4
|
|
93
|
+
},
|
|
94
|
+
transition: still ? { duration: 0 } : {
|
|
95
|
+
x: {
|
|
96
|
+
type: "spring",
|
|
97
|
+
stiffness: 700,
|
|
98
|
+
damping: 45
|
|
99
|
+
},
|
|
100
|
+
default: {
|
|
101
|
+
duration: .12,
|
|
102
|
+
ease: "easeOut"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
children: nameOf(near.index)
|
|
106
|
+
}, "tip") }),
|
|
20
107
|
/* @__PURE__ */ jsxs("div", {
|
|
21
108
|
className: "flex",
|
|
22
109
|
children: [/* @__PURE__ */ jsx(Press, {
|
|
@@ -26,7 +113,7 @@ function Timeline({ steps, shown, live, onShow, onLive, branches = [], branch, o
|
|
|
26
113
|
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
27
114
|
}), /* @__PURE__ */ jsx(Press, {
|
|
28
115
|
label: "Step on",
|
|
29
|
-
disabled: shown >= last,
|
|
116
|
+
disabled: shown >= last && (live || !head),
|
|
30
117
|
onClick: () => onShow(shown + 1),
|
|
31
118
|
children: /* @__PURE__ */ jsx(ChevronRight, {})
|
|
32
119
|
})]
|
|
@@ -35,7 +122,20 @@ function Timeline({ steps, shown, live, onShow, onLive, branches = [], branch, o
|
|
|
35
122
|
ref: track,
|
|
36
123
|
role: "list",
|
|
37
124
|
"aria-label": "Steps",
|
|
38
|
-
className: "flex h-full min-w-0 flex-1 items-center gap-[3px] overflow-x-auto px-1 [scrollbar-width:none]",
|
|
125
|
+
className: "relative flex h-full min-w-0 flex-1 touch-pan-x items-center gap-[3px] overflow-x-auto overscroll-x-contain px-1 [scrollbar-width:none]",
|
|
126
|
+
onPointerMove: (event) => {
|
|
127
|
+
if (event.pointerType !== "mouse") return;
|
|
128
|
+
pointer.current = event.clientX;
|
|
129
|
+
point();
|
|
130
|
+
},
|
|
131
|
+
onPointerLeave: () => {
|
|
132
|
+
pointer.current = void 0;
|
|
133
|
+
setNear(void 0);
|
|
134
|
+
},
|
|
135
|
+
onScroll: point,
|
|
136
|
+
onClick: (event) => {
|
|
137
|
+
if (event.target === event.currentTarget) onShow(nearestTo(event.clientX));
|
|
138
|
+
},
|
|
39
139
|
children: steps.map((each, index) => /* @__PURE__ */ jsx("button", {
|
|
40
140
|
type: "button",
|
|
41
141
|
role: "listitem",
|
|
@@ -45,8 +145,8 @@ function Timeline({ steps, shown, live, onShow, onLive, branches = [], branch, o
|
|
|
45
145
|
onClick: () => onShow(index),
|
|
46
146
|
className: "group grid h-8 w-2.5 shrink-0 place-items-center outline-none",
|
|
47
147
|
children: /* @__PURE__ */ jsx("span", {
|
|
48
|
-
className: cn("w-[3px] rounded-full transition-[height,background-color] duration-150", index === shown ? "h-6" : "
|
|
49
|
-
style: { backgroundColor: index === shown ? ink("message") : index < shown ? ink("line-lit") : ink("line") }
|
|
148
|
+
className: cn("w-[3px] rounded-full transition-[height,background-color] duration-150 ease-out", index === shown ? "h-6" : index === near?.index ? "h-5" : "h-3 group-focus-visible:h-5"),
|
|
149
|
+
style: { backgroundColor: index === shown ? ink("message") : index === near?.index ? "var(--foreground)" : index < shown ? ink("line-lit") : ink("line") }
|
|
50
150
|
})
|
|
51
151
|
}, each.id))
|
|
52
152
|
}),
|
|
@@ -56,7 +156,7 @@ function Timeline({ steps, shown, live, onShow, onLive, branches = [], branch, o
|
|
|
56
156
|
className: "truncate text-xs font-medium",
|
|
57
157
|
children: shown === 0 ? "init" : step.label
|
|
58
158
|
}), /* @__PURE__ */ jsxs("span", {
|
|
59
|
-
className: "text-muted-foreground text-[10.5px] tabular-nums",
|
|
159
|
+
className: "text-muted-foreground text-[10.5px] whitespace-nowrap tabular-nums",
|
|
60
160
|
children: [
|
|
61
161
|
shown,
|
|
62
162
|
" of ",
|
|
@@ -87,7 +187,7 @@ function Timeline({ steps, shown, live, onShow, onLive, branches = [], branch, o
|
|
|
87
187
|
type: "button",
|
|
88
188
|
onClick: onLive,
|
|
89
189
|
disabled: live,
|
|
90
|
-
className: cn("flex h-9 items-center gap-2 rounded-md border px-3 text-xs font-medium transition-[background-color,color,scale] duration-150 outline-none focus-visible:ring-2 active:scale-[0.97]", live ? "text-foreground cursor-default" : "text-muted-foreground hover:bg-muted hover:text-foreground"),
|
|
190
|
+
className: cn("flex h-9 shrink-0 items-center gap-2 rounded-md border px-3 text-xs font-medium transition-[background-color,color,scale] duration-150 outline-none focus-visible:ring-2 active:scale-[0.97]", live ? "text-foreground cursor-default" : "text-muted-foreground hover:bg-muted hover:text-foreground"),
|
|
91
191
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
92
192
|
className: "relative grid size-2 place-items-center",
|
|
93
193
|
children: [live && /* @__PURE__ */ jsx("span", {
|
|
@@ -100,11 +200,97 @@ function Timeline({ steps, shown, live, onShow, onLive, branches = [], branch, o
|
|
|
100
200
|
borderColor: ink("active")
|
|
101
201
|
} : { borderColor: "currentColor" }
|
|
102
202
|
})]
|
|
103
|
-
}),
|
|
203
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
204
|
+
className: "grid whitespace-nowrap",
|
|
205
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
206
|
+
"aria-hidden": true,
|
|
207
|
+
className: "invisible col-start-1 row-start-1",
|
|
208
|
+
children: "Go live"
|
|
209
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
210
|
+
className: "col-start-1 row-start-1",
|
|
211
|
+
children: live ? "Live" : "Go live"
|
|
212
|
+
})]
|
|
213
|
+
})]
|
|
214
|
+
}),
|
|
215
|
+
onWindow && /* @__PURE__ */ jsx(WindowPicker, {
|
|
216
|
+
window: window ?? null,
|
|
217
|
+
onWindow
|
|
104
218
|
})
|
|
105
219
|
]
|
|
106
220
|
});
|
|
107
221
|
}
|
|
222
|
+
function WindowPicker({ window, onWindow }) {
|
|
223
|
+
const [typing, setTyping] = useState(false);
|
|
224
|
+
if (typing) return /* @__PURE__ */ jsxs("label", {
|
|
225
|
+
className: "text-muted-foreground focus-within:text-foreground hidden h-9 items-center gap-1.5 rounded-md border px-2.5 text-xs focus-within:ring-2 @md:flex",
|
|
226
|
+
children: [/* @__PURE__ */ jsx("span", { children: "Keep" }), /* @__PURE__ */ jsx("input", {
|
|
227
|
+
autoFocus: true,
|
|
228
|
+
type: "number",
|
|
229
|
+
min: 1,
|
|
230
|
+
step: 1,
|
|
231
|
+
inputMode: "numeric",
|
|
232
|
+
defaultValue: window ?? "",
|
|
233
|
+
"aria-label": "Entries the History keeps",
|
|
234
|
+
onKeyDown: (event) => {
|
|
235
|
+
if (event.key === "Enter") event.currentTarget.blur();
|
|
236
|
+
if (event.key === "Escape") setTyping(false);
|
|
237
|
+
},
|
|
238
|
+
onBlur: (event) => {
|
|
239
|
+
const typed = event.currentTarget.valueAsNumber;
|
|
240
|
+
if (Number.isInteger(typed) && typed >= 1 && typed !== window) onWindow(typed);
|
|
241
|
+
setTyping(false);
|
|
242
|
+
},
|
|
243
|
+
className: "text-foreground w-14 bg-transparent text-base tabular-nums outline-none @md:text-xs"
|
|
244
|
+
})]
|
|
245
|
+
});
|
|
246
|
+
const sizes = window === null || PRESETS.includes(window) ? PRESETS : [...PRESETS, window].sort((a, b) => a - b);
|
|
247
|
+
const items = {
|
|
248
|
+
all: "all",
|
|
249
|
+
...Object.fromEntries(sizes.map((each) => [`${each}`, `${each}`])),
|
|
250
|
+
custom: "Custom…"
|
|
251
|
+
};
|
|
252
|
+
return /* @__PURE__ */ jsxs(Select, {
|
|
253
|
+
items,
|
|
254
|
+
value: window === null ? "all" : `${window}`,
|
|
255
|
+
onValueChange: (value) => {
|
|
256
|
+
if (value === "custom") setTyping(true);
|
|
257
|
+
else if (value) onWindow(value === "all" ? null : Number(value));
|
|
258
|
+
},
|
|
259
|
+
children: [/* @__PURE__ */ jsxs(SelectTrigger, {
|
|
260
|
+
size: "sm",
|
|
261
|
+
"aria-label": "Entries the History keeps",
|
|
262
|
+
className: "hidden text-xs @md:flex",
|
|
263
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
264
|
+
className: "text-muted-foreground",
|
|
265
|
+
children: "Keep"
|
|
266
|
+
}), /* @__PURE__ */ jsx(SelectValue, { className: "tabular-nums" })]
|
|
267
|
+
}), /* @__PURE__ */ jsxs(SelectContent, {
|
|
268
|
+
className: "min-w-44",
|
|
269
|
+
children: [
|
|
270
|
+
/* @__PURE__ */ jsxs(SelectItem, {
|
|
271
|
+
value: "all",
|
|
272
|
+
children: ["all ", /* @__PURE__ */ jsx(Hint, { children: "unbounded" })]
|
|
273
|
+
}),
|
|
274
|
+
sizes.map((each) => /* @__PURE__ */ jsxs(SelectItem, {
|
|
275
|
+
value: `${each}`,
|
|
276
|
+
className: "tabular-nums",
|
|
277
|
+
children: [each, HINTS[each] && /* @__PURE__ */ jsx(Hint, { children: HINTS[each] })]
|
|
278
|
+
}, each)),
|
|
279
|
+
/* @__PURE__ */ jsx(SelectSeparator, {}),
|
|
280
|
+
/* @__PURE__ */ jsx(SelectItem, {
|
|
281
|
+
value: "custom",
|
|
282
|
+
children: "Custom…"
|
|
283
|
+
})
|
|
284
|
+
]
|
|
285
|
+
})]
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function Hint({ children }) {
|
|
289
|
+
return /* @__PURE__ */ jsx("span", {
|
|
290
|
+
className: "text-muted-foreground ml-auto text-xs",
|
|
291
|
+
children
|
|
292
|
+
});
|
|
293
|
+
}
|
|
108
294
|
function Press({ label, disabled, onClick, children }) {
|
|
109
295
|
return /* @__PURE__ */ jsx("button", {
|
|
110
296
|
type: "button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.js","names":[],"sources":["../../../../src/recipes/kabuki-devtools/timeline/timeline.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { ChevronLeft, ChevronRight, GitBranch } from 'lucide-react';\nimport { cn } from '../../../components/lib/utils.ts';\nimport { ink } from '../ink/index.ts';\n\n/*\n * The Timeline: the bar under the Map for picking the Step shown.\n *\n * 1. Step one step back or on.\n * 2. Track one tick per Step on the Branch in view, init first; the one\n * shown stands taller, and stays scrolled into view.\n * 3. Read the Step shown: its place and its Message, once there is room.\n * 4. Branch bring another Branch into view, when there is more than one.\n * 5. Live back to the Head, or the sign that it is there.\n */\n\nexport interface TimelineStep {\n readonly id: string;\n readonly label: string;\n}\n\nexport interface TimelineBranch {\n readonly id: string;\n readonly label: string;\n}\n\nexport function Timeline({\n steps,\n shown,\n live,\n onShow,\n onLive,\n branches = [],\n branch,\n onBranch,\n}: {\n /** Every Step on the Branch in view, init first. */\n readonly steps: ReadonlyArray<TimelineStep>;\n /** The place of the Step shown. */\n readonly shown: number;\n /** Showing the Head of the running app. */\n readonly live: boolean;\n readonly onShow: (index: number) => void;\n readonly onLive: () => void;\n readonly branches?: ReadonlyArray<TimelineBranch>;\n /** The Branch in view. */\n readonly branch?: string;\n readonly onBranch?: (id: string) => void;\n}) {\n const track = useRef<HTMLDivElement>(null);\n useEffect(() => {\n track.current\n ?.querySelector<HTMLElement>('[aria-current=\"step\"]')\n ?.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }, [shown]);\n\n const step = steps[shown];\n const last = steps.length - 1;\n\n return (\n <div className=\"bg-background/90 flex h-14 shrink-0 items-center gap-2 border-t px-2 backdrop-blur-sm @md:gap-3 @md:px-3\">\n {/* 1. Step */}\n <div className=\"flex\">\n <Press\n label=\"Step back\"\n disabled={shown <= 0}\n onClick={() => onShow(shown - 1)}\n >\n <ChevronLeft />\n </Press>\n <Press\n label=\"Step on\"\n disabled={shown >= last}\n onClick={() => onShow(shown + 1)}\n >\n <ChevronRight />\n </Press>\n </div>\n\n {/* 2. Track */}\n <div\n ref={track}\n role=\"list\"\n aria-label=\"Steps\"\n className=\"flex h-full min-w-0 flex-1 items-center gap-[3px] overflow-x-auto px-1 [scrollbar-width:none]\"\n >\n {steps.map((each, index) => (\n <button\n key={each.id}\n type=\"button\"\n role=\"listitem\"\n title={`${index === 0 ? 'init' : `${index}. ${each.label}`}`}\n aria-label={index === 0 ? 'init' : `Step ${index}, ${each.label}`}\n aria-current={index === shown ? 'step' : undefined}\n onClick={() => onShow(index)}\n className=\"group grid h-8 w-2.5 shrink-0 place-items-center outline-none\"\n >\n <span\n className={cn(\n 'w-[3px] rounded-full transition-[height,background-color] duration-150',\n index === shown\n ? 'h-6'\n : 'group-hover:bg-foreground/50 h-3 group-focus-visible:h-5',\n )}\n style={{\n backgroundColor:\n index === shown\n ? ink('message')\n : index < shown\n ? ink('line-lit')\n : ink('line'),\n }}\n />\n </button>\n ))}\n </div>\n\n {/* 3. Read */}\n {step && (\n <div className=\"hidden min-w-0 flex-col items-end leading-tight @md:flex\">\n <span className=\"truncate text-xs font-medium\">\n {shown === 0 ? 'init' : step.label}\n </span>\n <span className=\"text-muted-foreground text-[10.5px] tabular-nums\">\n {shown} of {last}\n </span>\n </div>\n )}\n\n {/* 4. Branch */}\n {branches.length > 1 && onBranch && (\n <label className=\"text-muted-foreground hover:text-foreground relative flex h-9 items-center gap-1.5 rounded-md border px-2 text-xs transition-colors duration-150 focus-within:ring-2\">\n <GitBranch className=\"size-3.5\" />\n <span className=\"sr-only\">Branch in view</span>\n <select\n value={branch}\n onChange={(event) => onBranch(event.target.value)}\n className=\"bg-transparent outline-none\"\n >\n {branches.map((each) => (\n <option key={each.id} value={each.id}>\n {each.label}\n </option>\n ))}\n </select>\n </label>\n )}\n\n {/* 5. Live */}\n <button\n type=\"button\"\n onClick={onLive}\n disabled={live}\n className={cn(\n 'flex h-9 items-center gap-2 rounded-md border px-3 text-xs font-medium transition-[background-color,color,scale] duration-150 outline-none focus-visible:ring-2 active:scale-[0.97]',\n live\n ? 'text-foreground cursor-default'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n <span className=\"relative grid size-2 place-items-center\">\n {live && (\n <span\n className=\"absolute inset-0 animate-ping rounded-full opacity-60 motion-reduce:hidden\"\n style={{ backgroundColor: ink('active') }}\n />\n )}\n <span\n className=\"size-2 rounded-full border\"\n style={\n live\n ? { backgroundColor: ink('active'), borderColor: ink('active') }\n : { borderColor: 'currentColor' }\n }\n />\n </span>\n {live ? 'Live' : 'Go live'}\n </button>\n </div>\n );\n}\n\nfunction Press({\n label,\n disabled,\n onClick,\n children,\n}: {\n readonly label: string;\n readonly disabled: boolean;\n readonly onClick: () => void;\n readonly children: React.ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={onClick}\n className=\"text-muted-foreground hover:text-foreground hover:bg-muted grid size-9 place-items-center rounded-md transition-colors duration-150 outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-40 [&_svg]:size-4\"\n >\n {children}\n </button>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timeline.js","names":[],"sources":["../../../../src/recipes/kabuki-devtools/timeline/timeline.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { ChevronLeft, ChevronRight, GitBranch } from 'lucide-react';\nimport { AnimatePresence, motion, useReducedMotion } from 'motion/react';\nimport { cn } from '../../../components/lib/utils.ts';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n} from '#components/ui/select';\nimport { ink } from '../ink/index.ts';\n\n/*\n * The Timeline: the bar under the Map for picking the Step shown.\n *\n * 1. Step one step back or on.\n * 2. Track one tick per Step on the Branch in view, init first; the one\n * shown stands taller. When they do not all fit, the row glides\n * to keep the one shown in the middle, stopping at either end,\n * and live it rests at its right end; a finger or a trackpad\n * can still swipe it. The tick nearest the pointer rises with\n * its Message's name over it, and a click or tap anywhere on the\n * track picks the nearest. The last tick, when it is the Head,\n * goes live.\n * 3. Read the Step shown: its place and its Message, once there is room.\n * 4. Branch bring another Branch into view, when there is more than one.\n * 5. Live back to the Head, or the sign that it is there.\n * 6. Window how many entries the History keeps: a preset, or any number\n * typed in, set on Enter or blur. A smaller one Compacts at once,\n * and cannot be undone. 1 keeps only the Snapshot; 2 is the least\n * that still shows a change.\n */\n\nconst PRESETS = [1, 2, 5, 10, 25, 50, 100, 500];\nconst HINTS: Partial<Record<number, string>> = {\n 1: 'Snapshot only',\n 2: 'last change',\n};\n\nexport interface TimelineStep {\n readonly id: string;\n readonly label: string;\n}\n\nexport interface TimelineBranch {\n readonly id: string;\n readonly label: string;\n}\n\nexport function Timeline({\n steps,\n shown,\n live,\n onShow: showStep,\n onLive,\n head = false,\n branches = [],\n branch,\n onBranch,\n window,\n onWindow,\n}: {\n /** Every Step on the Branch in view, init first. */\n readonly steps: ReadonlyArray<TimelineStep>;\n /** The place of the Step shown. */\n readonly shown: number;\n /** Showing the Head of the running app. */\n readonly live: boolean;\n readonly onShow: (index: number) => void;\n readonly onLive: () => void;\n /** The last Step is the Head: picking it goes live. */\n readonly head?: boolean;\n readonly branches?: ReadonlyArray<TimelineBranch>;\n /** The Branch in view. */\n readonly branch?: string;\n readonly onBranch?: (id: string) => void;\n /** How many entries the History keeps on the Head's Branch, `null` for every one. */\n readonly window?: number | null;\n readonly onWindow?: (window: number | null) => void;\n}) {\n const track = useRef<HTMLDivElement>(null);\n\n const step = steps[shown];\n const last = steps.length - 1;\n const onShow = (index: number) =>\n head && index === last ? onLive() : showStep(index);\n const nameOf = (index: number) =>\n index === 0\n ? 'init'\n : head && index === last && !live\n ? `${steps[index]!.label} · go live`\n : steps[index]!.label;\n\n const bar = useRef<HTMLDivElement>(null);\n const still = useReducedMotion();\n const [near, setNear] = useState<{ index: number; x: number }>();\n /** The tick nearest the pointer, gaps included, and its middle in the bar. */\n /** The tick nearest a point across the track, gaps included. */\n const nearestTo = (clientX: number) => {\n const ticks = [...track.current!.children];\n let index = 0;\n let best = Infinity;\n ticks.forEach((tick, at) => {\n const { left, width } = tick.getBoundingClientRect();\n const off = Math.abs(left + width / 2 - clientX);\n if (off < best) [index, best] = [at, off];\n });\n return index;\n };\n /** Where the mouse is over the track, to follow it as the row glides. */\n const pointer = useRef<number | undefined>(undefined);\n const point = () => {\n if (pointer.current === undefined) return;\n const index = nearestTo(pointer.current);\n const { left, width } =\n track.current!.children[index]!.getBoundingClientRect();\n const x = left + width / 2 - bar.current!.getBoundingClientRect().left;\n setNear((was) =>\n was?.index === index && was.x === x ? was : { index, x },\n );\n };\n\n // The Step shown in the middle of the track, or as near as its ends allow.\n useEffect(() => {\n const at = track.current;\n const tick = at?.children[shown] as HTMLElement | undefined;\n if (!at || !tick) return;\n at.scrollTo({\n left: tick.offsetLeft + tick.offsetWidth / 2 - at.clientWidth / 2,\n behavior: still ? 'instant' : 'smooth',\n });\n }, [shown, steps.length, still]);\n\n return (\n <div\n ref={bar}\n className=\"bg-background/90 relative flex h-14 shrink-0 items-center gap-2 border-t px-2 backdrop-blur-sm @md:gap-3 @md:px-3\"\n // Clear of a button laid over its right end, such as the Devtools Dock's.\n style={{ paddingRight: 'calc(var(--dock-reserve, 0px) + 0.75rem)' }}\n >\n <AnimatePresence>\n {near && steps[near.index] && (\n <motion.div\n key=\"tip\"\n role=\"tooltip\"\n className=\"bg-popover text-popover-foreground pointer-events-none absolute bottom-full left-0 mb-1.5 rounded-md border px-2 py-1 text-xs font-medium whitespace-nowrap shadow-[0_1px_2px_rgb(0_0_0/0.06),0_4px_12px_rgb(0_0_0/0.1)]\"\n initial={{ opacity: 0, y: 4, x: near.x, translateX: '-50%' }}\n animate={{ opacity: 1, y: 0, x: near.x, translateX: '-50%' }}\n exit={{ opacity: 0, y: 4 }}\n transition={\n still\n ? { duration: 0 }\n : {\n x: { type: 'spring', stiffness: 700, damping: 45 },\n default: { duration: 0.12, ease: 'easeOut' },\n }\n }\n >\n {nameOf(near.index)}\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* 1. Step */}\n <div className=\"flex\">\n <Press\n label=\"Step back\"\n disabled={shown <= 0}\n onClick={() => onShow(shown - 1)}\n >\n <ChevronLeft />\n </Press>\n <Press\n label=\"Step on\"\n disabled={shown >= last && (live || !head)}\n onClick={() => onShow(shown + 1)}\n >\n <ChevronRight />\n </Press>\n </div>\n\n {/* 2. Track */}\n <div\n ref={track}\n role=\"list\"\n aria-label=\"Steps\"\n className=\"relative flex h-full min-w-0 flex-1 touch-pan-x items-center gap-[3px] overflow-x-auto overscroll-x-contain px-1 [scrollbar-width:none]\"\n onPointerMove={(event) => {\n if (event.pointerType !== 'mouse') return;\n pointer.current = event.clientX;\n point();\n }}\n onPointerLeave={() => {\n pointer.current = undefined;\n setNear(undefined);\n }}\n onScroll={point}\n onClick={(event) => {\n if (event.target === event.currentTarget)\n onShow(nearestTo(event.clientX));\n }}\n >\n {steps.map((each, index) => (\n <button\n key={each.id}\n type=\"button\"\n role=\"listitem\"\n title={`${index === 0 ? 'init' : `${index}. ${each.label}`}`}\n aria-label={index === 0 ? 'init' : `Step ${index}, ${each.label}`}\n aria-current={index === shown ? 'step' : undefined}\n onClick={() => onShow(index)}\n className=\"group grid h-8 w-2.5 shrink-0 place-items-center outline-none\"\n >\n <span\n className={cn(\n 'w-[3px] rounded-full transition-[height,background-color] duration-150 ease-out',\n index === shown\n ? 'h-6'\n : index === near?.index\n ? 'h-5'\n : 'h-3 group-focus-visible:h-5',\n )}\n style={{\n backgroundColor:\n index === shown\n ? ink('message')\n : index === near?.index\n ? 'var(--foreground)'\n : index < shown\n ? ink('line-lit')\n : ink('line'),\n }}\n />\n </button>\n ))}\n </div>\n\n {/* 3. Read */}\n {step && (\n <div className=\"hidden min-w-0 flex-col items-end leading-tight @md:flex\">\n <span className=\"truncate text-xs font-medium\">\n {shown === 0 ? 'init' : step.label}\n </span>\n <span className=\"text-muted-foreground text-[10.5px] whitespace-nowrap tabular-nums\">\n {shown} of {last}\n </span>\n </div>\n )}\n\n {/* 4. Branch */}\n {branches.length > 1 && onBranch && (\n <label className=\"text-muted-foreground hover:text-foreground relative flex h-9 items-center gap-1.5 rounded-md border px-2 text-xs transition-colors duration-150 focus-within:ring-2\">\n <GitBranch className=\"size-3.5\" />\n <span className=\"sr-only\">Branch in view</span>\n <select\n value={branch}\n onChange={(event) => onBranch(event.target.value)}\n className=\"bg-transparent outline-none\"\n >\n {branches.map((each) => (\n <option key={each.id} value={each.id}>\n {each.label}\n </option>\n ))}\n </select>\n </label>\n )}\n\n {/* 5. Live */}\n <button\n type=\"button\"\n onClick={onLive}\n disabled={live}\n className={cn(\n 'flex h-9 shrink-0 items-center gap-2 rounded-md border px-3 text-xs font-medium transition-[background-color,color,scale] duration-150 outline-none focus-visible:ring-2 active:scale-[0.97]',\n live\n ? 'text-foreground cursor-default'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n <span className=\"relative grid size-2 place-items-center\">\n {live && (\n <span\n className=\"absolute inset-0 animate-ping rounded-full opacity-60 motion-reduce:hidden\"\n style={{ backgroundColor: ink('active') }}\n />\n )}\n <span\n className=\"size-2 rounded-full border\"\n style={\n live\n ? { backgroundColor: ink('active'), borderColor: ink('active') }\n : { borderColor: 'currentColor' }\n }\n />\n </span>\n {/* As wide as its longer word either way, so nothing beside it moves. */}\n <span className=\"grid whitespace-nowrap\">\n <span aria-hidden className=\"invisible col-start-1 row-start-1\">\n Go live\n </span>\n <span className=\"col-start-1 row-start-1\">\n {live ? 'Live' : 'Go live'}\n </span>\n </span>\n </button>\n\n {/* 6. Window */}\n {onWindow && <WindowPicker window={window ?? null} onWindow={onWindow} />}\n </div>\n );\n}\n\nfunction WindowPicker({\n window,\n onWindow,\n}: {\n readonly window: number | null;\n readonly onWindow: (window: number | null) => void;\n}) {\n const [typing, setTyping] = useState(false);\n\n if (typing)\n return (\n <label className=\"text-muted-foreground focus-within:text-foreground hidden h-9 items-center gap-1.5 rounded-md border px-2.5 text-xs focus-within:ring-2 @md:flex\">\n <span>Keep</span>\n <input\n autoFocus\n type=\"number\"\n min={1}\n step={1}\n inputMode=\"numeric\"\n defaultValue={window ?? ''}\n aria-label=\"Entries the History keeps\"\n onKeyDown={(event) => {\n if (event.key === 'Enter') event.currentTarget.blur();\n if (event.key === 'Escape') setTyping(false);\n }}\n onBlur={(event) => {\n const typed = event.currentTarget.valueAsNumber;\n if (Number.isInteger(typed) && typed >= 1 && typed !== window)\n onWindow(typed);\n setTyping(false);\n }}\n className=\"text-foreground w-14 bg-transparent text-base tabular-nums outline-none @md:text-xs\"\n />\n </label>\n );\n\n const sizes =\n window === null || PRESETS.includes(window)\n ? PRESETS\n : [...PRESETS, window].sort((a, b) => a - b);\n const items = {\n all: 'all',\n ...Object.fromEntries(sizes.map((each) => [`${each}`, `${each}`])),\n custom: 'Custom…',\n };\n return (\n <Select\n items={items}\n value={window === null ? 'all' : `${window}`}\n onValueChange={(value) => {\n if (value === 'custom') setTyping(true);\n else if (value) onWindow(value === 'all' ? null : Number(value));\n }}\n >\n <SelectTrigger\n size=\"sm\"\n aria-label=\"Entries the History keeps\"\n className=\"hidden text-xs @md:flex\"\n >\n <span className=\"text-muted-foreground\">Keep</span>\n <SelectValue className=\"tabular-nums\" />\n </SelectTrigger>\n <SelectContent className=\"min-w-44\">\n <SelectItem value=\"all\">\n all <Hint>unbounded</Hint>\n </SelectItem>\n {sizes.map((each) => (\n <SelectItem key={each} value={`${each}`} className=\"tabular-nums\">\n {each}\n {HINTS[each] && <Hint>{HINTS[each]}</Hint>}\n </SelectItem>\n ))}\n <SelectSeparator />\n <SelectItem value=\"custom\">Custom…</SelectItem>\n </SelectContent>\n </Select>\n );\n}\n\nfunction Hint({ children }: { readonly children: ReactNode }) {\n return (\n <span className=\"text-muted-foreground ml-auto text-xs\">{children}</span>\n );\n}\n\nfunction Press({\n label,\n disabled,\n onClick,\n children,\n}: {\n readonly label: string;\n readonly disabled: boolean;\n readonly onClick: () => void;\n readonly children: React.ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={onClick}\n className=\"text-muted-foreground hover:text-foreground hover:bg-muted grid size-9 place-items-center rounded-md transition-colors duration-150 outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-40 [&_svg]:size-4\"\n >\n {children}\n </button>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kestack/web-platform",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The way to build a kstack app: one config made into a PWA on TanStack Start with its Theme, its APIs on a cloud or a device Backend, several Accounts with one Session each, the screens before sign-in, and the server; plus the components, input, forms and Recipes to build screens with.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -190,14 +190,14 @@
|
|
|
190
190
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
|
191
191
|
"vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
|
|
192
192
|
"vitest": "5.0.1",
|
|
193
|
-
"@kestack/
|
|
194
|
-
"@kestack/
|
|
195
|
-
"@kestack/
|
|
196
|
-
"@kestack/
|
|
197
|
-
"use-
|
|
198
|
-
"@kestack/kabuki": "0.0.
|
|
199
|
-
"laymos": "0.0.
|
|
200
|
-
"
|
|
193
|
+
"@kestack/auth-toolkit": "0.0.2",
|
|
194
|
+
"@kestack/rpc-toolkit": "0.0.2",
|
|
195
|
+
"@kestack/use-gesture": "0.0.1",
|
|
196
|
+
"@kestack/std-toolkit": "0.0.2",
|
|
197
|
+
"@kestack/use-keys": "0.0.1",
|
|
198
|
+
"@kestack/kabuki": "0.0.2",
|
|
199
|
+
"laymos": "0.0.13",
|
|
200
|
+
"use-effect-ts": "0.0.12"
|
|
201
201
|
},
|
|
202
202
|
"peerDependencies": {
|
|
203
203
|
"@cloudflare/workers-types": "5.20260904.1",
|
|
@@ -207,14 +207,14 @@
|
|
|
207
207
|
"react": "^19.0.0",
|
|
208
208
|
"react-dom": "^19.0.0",
|
|
209
209
|
"vite": "^8.0.0",
|
|
210
|
-
"@kestack/auth-toolkit": "0.0.
|
|
211
|
-
"@kestack/
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"@kestack/
|
|
215
|
-
"
|
|
216
|
-
"use-
|
|
217
|
-
"@kestack/
|
|
210
|
+
"@kestack/auth-toolkit": "0.0.2",
|
|
211
|
+
"@kestack/use-keys": "0.0.1",
|
|
212
|
+
"use-effect-ts": "0.0.12",
|
|
213
|
+
"laymos": "0.0.13",
|
|
214
|
+
"@kestack/rpc-toolkit": "0.0.2",
|
|
215
|
+
"@kestack/kabuki": "0.0.2",
|
|
216
|
+
"@kestack/use-gesture": "0.0.1",
|
|
217
|
+
"@kestack/std-toolkit": "0.0.2"
|
|
218
218
|
},
|
|
219
219
|
"peerDependenciesMeta": {
|
|
220
220
|
"@cloudflare/workers-types": {
|