@heyramzi/ui 2.11.1 → 2.11.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/dist/agents/helpers.js +38 -38
- package/dist/agents/page-state.js +49 -50
- package/dist/agents/vendor/color.js +146 -127
- package/dist/agents/vendor/draw.js +617 -508
- package/dist/agents/vendor/engine.js +698 -599
- package/dist/agents/vendor/mesh.js +653 -683
- package/dist/agents/vendor/plastic.js +3913 -3112
- package/dist/agents/vendor/presets.js +163 -164
- package/dist/agents/vendor/shapes.js +21 -20
- package/dist/agents/vendor/ticker.js +41 -42
- package/dist/agents/vendor/types.js +1 -0
- package/dist/agents/vendor/wear.js +1421 -1448
- package/dist/ai/confirmation/confirmation-context.svelte.js +6 -6
- package/dist/ai/confirmation/index.js +3 -1
- package/dist/ai/index.js +33 -0
- package/dist/ai/prompt-input/index.js +3 -1
- package/dist/ai/reasoning/index.js +3 -1
- package/dist/ai/reasoning/reasoning-context.svelte.js +6 -6
- package/dist/ai/suggestion/index.js +3 -1
- package/dist/ai/typing-dots/index.js +3 -1
- package/dist/animations/text-swap.js +24 -24
- package/dist/brand/index.js +54 -48
- package/dist/canvas/card/resize.js +5 -3
- package/dist/canvas/edges/edge-path.js +255 -242
- package/dist/canvas/editor/context-menu.js +39 -36
- package/dist/canvas/editor/dispatch.svelte.js +154 -151
- package/dist/canvas/editor/editor-context.js +7 -2
- package/dist/canvas/editor/editor-mode.js +1 -0
- package/dist/canvas/editor/frame.js +73 -76
- package/dist/canvas/editor/hand-context.js +5 -2
- package/dist/canvas/editor/history-core.js +163 -191
- package/dist/canvas/editor/keymap.js +95 -169
- package/dist/canvas/editor/layout-actions.js +143 -144
- package/dist/canvas/editor/lock.js +52 -51
- package/dist/canvas/editor/rebase.js +217 -240
- package/dist/canvas/editor/style.js +132 -137
- package/dist/canvas/editor/text-field-context.js +7 -2
- package/dist/canvas/editor/z-order.js +65 -70
- package/dist/canvas/headless/alignment.js +22 -16
- package/dist/canvas/headless/break-apart-find.js +286 -279
- package/dist/canvas/headless/break-apart-pieces.js +62 -58
- package/dist/canvas/headless/break-apart-plan.js +299 -325
- package/dist/canvas/headless/break-apart-style.js +75 -70
- package/dist/canvas/headless/break-apart.js +188 -181
- package/dist/canvas/headless/canvas-cleanup.js +78 -58
- package/dist/canvas/headless/edge-anchors.js +115 -116
- package/dist/canvas/headless/edge-memo.js +24 -22
- package/dist/canvas/headless/edge-serialization.js +17 -27
- package/dist/canvas/headless/figure-geometry.js +232 -264
- package/dist/canvas/headless/fit-viewport.js +84 -67
- package/dist/canvas/headless/grid.js +88 -86
- package/dist/canvas/headless/icon-node.js +44 -36
- package/dist/canvas/headless/index.js +1 -0
- package/dist/canvas/headless/linkify.js +17 -19
- package/dist/canvas/headless/pen-marks.js +101 -95
- package/dist/canvas/headless/sketch.js +231 -209
- package/dist/canvas/headless/snap-guides.js +99 -83
- package/dist/canvas/headless/svg-figure.js +133 -117
- package/dist/canvas/headless/table-layout.js +146 -107
- package/dist/canvas/index.js +2 -0
- package/dist/canvas/lod/lod-mode.svelte.js +20 -18
- package/dist/canvas/lod/render-all.svelte.js +36 -39
- package/dist/canvas/ops/arrange.js +78 -71
- package/dist/canvas/ops/ops.js +260 -255
- package/dist/canvas/pen/colors.js +37 -35
- package/dist/canvas/pen/eraser.js +28 -27
- package/dist/canvas/pen/geometry.js +120 -130
- package/dist/canvas/pen/index.js +1 -0
- package/dist/canvas/pen/ops.js +11 -11
- package/dist/canvas/pen/pen-session.js +150 -159
- package/dist/canvas/pen/plugin.js +107 -104
- package/dist/canvas/pen/shapes.js +73 -68
- package/dist/canvas/pen/stroke-path.js +32 -30
- package/dist/canvas/pen/types.js +21 -21
- package/dist/canvas/pen/ui.js +10 -8
- package/dist/canvas/plugin.js +46 -46
- package/dist/canvas/screen/glyphs.js +12 -11
- package/dist/canvas/screen/labels.js +22 -22
- package/dist/canvas/screen/parts.js +98 -111
- package/dist/canvas/screen/plugin.js +47 -56
- package/dist/canvas/screen/types.js +30 -35
- package/dist/canvas/screen/ui.js +7 -7
- package/dist/canvas/test-utils.js +14 -14
- package/dist/canvas/types.js +1 -0
- package/dist/canvas/ui/forward-wheel.js +24 -25
- package/dist/canvas/ui/icons.js +64 -131
- package/dist/canvas/ui/place-panel.js +58 -49
- package/dist/canvas/ui/shortcut-tip.js +14 -12
- package/dist/canvas/ui/tools.js +300 -385
- package/dist/charts/dashboard/chart.js +4 -0
- package/dist/charts/dashboard/data-table.js +11 -0
- package/dist/charts/dashboard/windows.js +8 -3
- package/dist/charts/edge-fade.js +10 -5
- package/dist/charts/hover-band.js +16 -11
- package/dist/charts/index.js +0 -1
- package/dist/charts/motion.js +11 -7
- package/dist/charts/primitives/chart-utils.js +12 -12
- package/dist/components/copy/clipboard.js +32 -32
- package/dist/components/copy/copied.svelte.js +31 -23
- package/dist/components/data-table/data-table.js +39 -39
- package/dist/components/docs/index.js +4 -0
- package/dist/components/docs/scroll-spy.svelte.js +73 -68
- package/dist/components/list-page/filter-section.js +4 -1
- package/dist/components/list-page/index.js +2 -0
- package/dist/components/list-page/list-table.js +7 -2
- package/dist/components/list-page/queue-rail.js +14 -0
- package/dist/components/list-page/section-host.js +4 -2
- package/dist/components/list-page/step.js +4 -3
- package/dist/components/list-page/types.js +1 -0
- package/dist/components/picker/trigger.js +48 -30
- package/dist/components/picker/types.js +1 -0
- package/dist/components/segmented/collapse.js +38 -27
- package/dist/components/segmented/index.js +8 -0
- package/dist/components/segmented/segmented.js +67 -42
- package/dist/components/star-rating-input/index.js +3 -1
- package/dist/components/table-view/types.js +1 -0
- package/dist/components/tags-input/tags.js +81 -69
- package/dist/components/theme/index.js +4 -0
- package/dist/components/toolbar/index.js +4 -0
- package/dist/components/toolbar/toolbar-trigger.js +14 -1
- package/dist/editor/anchors.js +17 -13
- package/dist/editor/block-id.js +52 -51
- package/dist/editor/block-ops.js +108 -80
- package/dist/editor/doc-blocks.js +155 -166
- package/dist/editor/extensions.js +139 -180
- package/dist/editor/index.js +4 -0
- package/dist/editor/markdown-test-helpers.js +4 -2
- package/dist/editor/markdown.js +420 -408
- package/dist/editor/serializer.js +204 -200
- package/dist/editor/slash-items.js +89 -101
- package/dist/editor/youtube-url.js +25 -20
- package/dist/effects/animated-beam/path-calculator.svelte.js +43 -38
- package/dist/effects/animated-beam/types.js +1 -0
- package/dist/effects/border-beam/css.js +92 -78
- package/dist/effects/border-beam/presets.js +1705 -1720
- package/dist/effects/border-beam/register-properties.js +43 -33
- package/dist/effects/border-beam/types.js +1 -0
- package/dist/effects/image-comparison/compare.js +3 -2
- package/dist/effects/image-reveal/types.js +1 -0
- package/dist/effects/magnetic/magnetic.js +58 -52
- package/dist/effects/reveal/observe.js +50 -40
- package/dist/effects/reveal/types.js +1 -0
- package/dist/effects/shader-gradient/color.js +36 -29
- package/dist/effects/shader-gradient/renderer.js +384 -295
- package/dist/effects/shader-gradient/shaders.js +31 -0
- package/dist/effects/shader-gradient/types.js +1 -0
- package/dist/icons/apple-symbol-exports.js +99 -124
- package/dist/icons/sf-symbols.js +357 -461
- package/dist/icons/trades.js +43 -28
- package/dist/inbox/index.js +1 -0
- package/dist/inbox/logic.js +126 -122
- package/dist/inbox/types.js +43 -43
- package/dist/lib/arrive.js +19 -12
- package/dist/lib/icon-types.js +1 -0
- package/dist/lib/initials.js +16 -10
- package/dist/lib/layout.js +5 -0
- package/dist/lib/panel.js +13 -0
- package/dist/lib/result.js +22 -22
- package/dist/lib/sliding-pill.js +59 -44
- package/dist/lib/theme-transition.js +43 -43
- package/dist/lib/tone.js +31 -24
- package/dist/lib/utils.js +3 -1
- package/dist/onboarding/define-tours.js +24 -23
- package/dist/onboarding/onboarding.svelte.js +16 -12
- package/dist/onboarding/pick.js +10 -6
- package/dist/onboarding/stores.js +40 -41
- package/dist/onboarding/wait.js +24 -23
- package/dist/panel/side-panel-types.js +1 -0
- package/dist/record/demo-data.js +459 -486
- package/dist/record/fields.js +129 -131
- package/dist/record/format.js +70 -82
- package/dist/record/gutter.js +1 -0
- package/dist/record/kinds.js +95 -105
- package/dist/record/logic.js +238 -219
- package/dist/record/types.js +49 -48
- package/dist/shadcn/accordion/index.js +3 -1
- package/dist/shadcn/alert/index.js +3 -1
- package/dist/shadcn/alert-dialog/index.js +3 -1
- package/dist/shadcn/attachment/index.js +3 -1
- package/dist/shadcn/avatar/index.js +3 -1
- package/dist/shadcn/breadcrumb/index.js +3 -1
- package/dist/shadcn/bubble/index.js +3 -1
- package/dist/shadcn/button/index.js +3 -1
- package/dist/shadcn/calendar/index.js +3 -1
- package/dist/shadcn/card/index.js +3 -1
- package/dist/shadcn/checkbox/index.js +3 -1
- package/dist/shadcn/code-block/index.js +3 -1
- package/dist/shadcn/collapsible/index.js +3 -1
- package/dist/shadcn/command/index.js +4 -1
- package/dist/shadcn/context-menu/index.js +3 -1
- package/dist/shadcn/dialog/index.js +3 -1
- package/dist/shadcn/dropdown-menu/menu-item.js +40 -20
- package/dist/shadcn/empty/index.js +3 -1
- package/dist/shadcn/field/index.js +3 -1
- package/dist/shadcn/hooks/highlighter.js +77 -75
- package/dist/shadcn/hooks/is-mobile.svelte.js +3 -3
- package/dist/shadcn/hooks/use-highlighted-code.svelte.js +62 -62
- package/dist/shadcn/input/index.js +3 -1
- package/dist/shadcn/kbd/index.js +3 -1
- package/dist/shadcn/label/index.js +3 -1
- package/dist/shadcn/marker/index.js +3 -1
- package/dist/shadcn/message/index.js +3 -1
- package/dist/shadcn/message-scroller/index.js +3 -1
- package/dist/shadcn/popover/index.js +3 -1
- package/dist/shadcn/progress/index.js +3 -1
- package/dist/shadcn/progress/tone.js +8 -7
- package/dist/shadcn/radio-group/index.js +3 -1
- package/dist/shadcn/scroll-area/index.js +3 -1
- package/dist/shadcn/select/index.js +3 -1
- package/dist/shadcn/separator/index.js +3 -1
- package/dist/shadcn/sheet/index.js +3 -1
- package/dist/shadcn/sidebar/context.svelte.js +42 -28
- package/dist/shadcn/sidebar/index.js +3 -1
- package/dist/shadcn/skeleton/index.js +3 -1
- package/dist/shadcn/slider/index.js +3 -1
- package/dist/shadcn/switch/index.js +3 -1
- package/dist/shadcn/table/index.js +3 -1
- package/dist/shadcn/tabs/index.js +3 -1
- package/dist/shadcn/textarea/index.js +3 -1
- package/dist/shadcn/toggle/index.js +3 -1
- package/dist/shadcn/toggle-group/index.js +3 -1
- package/dist/shadcn/tooltip/context.js +7 -2
- package/dist/shadcn/tooltip/index.js +3 -1
- package/dist/shadcn/trace/index.js +3 -1
- package/dist/slides/bridges.js +65 -59
- package/dist/slides/deck-controller.svelte.js +210 -207
- package/dist/slides/export/capture.js +66 -71
- package/dist/slides/export/ffmpeg.js +76 -72
- package/dist/slides/export/index.js +3 -0
- package/dist/slides/export/launch.js +9 -6
- package/dist/slides/export/pdf.js +60 -54
- package/dist/slides/export/types.js +1 -0
- package/dist/slides/labels.js +24 -24
- package/dist/slides/layout.js +39 -41
- package/dist/slides/model.js +9 -7
- package/dist/slides/navigation.js +78 -73
- package/dist/slides/types.js +2 -2
- package/dist/status/define-statuses.js +18 -14
- package/dist/status/status-types.js +1 -0
- package/dist/test-setup.js +24 -20
- package/dist/thread/logic.js +73 -77
- package/dist/thread/types.js +21 -21
- package/dist/work/board-order.js +94 -90
- package/dist/work/dates.js +16 -9
- package/dist/work/detail/detail-types.js +18 -18
- package/dist/work/docs/edited.js +32 -29
- package/dist/work/docs/index.js +4 -0
- package/dist/work/docs/labels.js +34 -34
- package/dist/work/docs/menu.js +113 -106
- package/dist/work/docs/outline.js +39 -29
- package/dist/work/gantt/logic.js +211 -235
- package/dist/work/inbox/inbox-logic.js +71 -75
- package/dist/work/inbox/inbox-statuses.js +75 -72
- package/dist/work/inbox/inbox-types.js +1 -0
- package/dist/work/kanban-drag.js +27 -22
- package/dist/work/kanban-types.js +1 -0
- package/dist/work/presets/sales.js +36 -32
- package/dist/work/reorder.js +9 -8
- package/dist/work/task-types.js +1 -0
- package/dist/work/time/duration.js +51 -46
- package/dist/work/time/time-types.js +23 -23
- package/dist/work/use-kanban-dnd.svelte.js +126 -125
- package/package.json +3 -1
- package/src/components/list-page/master-detail.svelte +3 -1
- package/src/components/list-page/rail-row.svelte +4 -4
- package/src/editor/markdown.ts +30 -35
package/dist/lib/sliding-pill.js
CHANGED
|
@@ -1,45 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
/** The travelling highlight behind the active tab. Attach it to a span inside the list. */
|
|
2
|
+
// WHY attach to the pill, not the list: the pill finds its list via
|
|
3
|
+
// `parentElement`, so any strip that renders one span gets the motion.
|
|
4
|
+
// WHY measure: the active item's width is its label. The selector covers the
|
|
5
|
+
// three ways a strip marks it: a tab, a nav link, a toggle.
|
|
6
|
+
// Per transitions.dev `tabs-sliding`: first paint and resizes write the
|
|
7
|
+
// position with the transition off, so the pill snaps in instead of flying.
|
|
8
|
+
const ACTIVE = "[data-state=\"active\"],[aria-current=\"page\"],[aria-pressed=\"true\"]";
|
|
9
|
+
export const slidingPill = (pill) => {
|
|
10
|
+
const list = pill.parentElement;
|
|
11
|
+
if (!list) return;
|
|
12
|
+
let settled = false;
|
|
13
|
+
const move = (animate) => {
|
|
14
|
+
const active = list.querySelector(ACTIVE);
|
|
15
|
+
if (!active) {
|
|
16
|
+
pill.style.opacity = "0";
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
pill.style.opacity = "1";
|
|
20
|
+
if (animate) {
|
|
21
|
+
pill.style.transform = `translateX(${active.offsetLeft}px)`;
|
|
22
|
+
pill.style.width = `${active.offsetWidth}px`;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Suspend, write, reflow, restore. Without the reflow the browser
|
|
26
|
+
// coalesces the two writes and the snap animates anyway.
|
|
27
|
+
pill.style.transition = "none";
|
|
28
|
+
pill.style.transform = `translateX(${active.offsetLeft}px)`;
|
|
29
|
+
pill.style.width = `${active.offsetWidth}px`;
|
|
30
|
+
void pill.offsetWidth;
|
|
31
|
+
pill.style.transition = "";
|
|
32
|
+
};
|
|
33
|
+
// Position first, THEN hand the highlight over. Swapped, one frame draws both
|
|
34
|
+
// the trigger's own background and a zero-width pill: a flicker on hydration.
|
|
35
|
+
move(false);
|
|
36
|
+
list.dataset.pill = "on";
|
|
37
|
+
settled = true;
|
|
38
|
+
// The selection lives in an attribute bits-ui owns, and a badge arriving
|
|
39
|
+
// changes a trigger's width without any attribute changing.
|
|
40
|
+
const attributes = new MutationObserver(() => move(settled));
|
|
41
|
+
attributes.observe(list, {
|
|
42
|
+
subtree: true,
|
|
43
|
+
childList: true,
|
|
44
|
+
attributes: true,
|
|
45
|
+
attributeFilter: [
|
|
46
|
+
"data-state",
|
|
47
|
+
"aria-current",
|
|
48
|
+
"aria-pressed"
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
// A list that reflows (a rail collapsing, a font landing) re-measures
|
|
52
|
+
// without motion: nothing was chosen, so nothing should travel.
|
|
53
|
+
const resize = new ResizeObserver(() => move(false));
|
|
54
|
+
resize.observe(list);
|
|
55
|
+
return () => {
|
|
56
|
+
attributes.disconnect();
|
|
57
|
+
resize.disconnect();
|
|
58
|
+
delete list.dataset.pill;
|
|
59
|
+
};
|
|
45
60
|
};
|
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
const DEFAULT_DURATION = 300;
|
|
2
2
|
const STYLE_ID = "heyramzi-reveal-theme";
|
|
3
|
+
/**
|
|
4
|
+
* Run `apply` inside a circular wipe from the clicked element or a point, falling back to
|
|
5
|
+
* plain `apply()` without view transitions, under reduced motion, or with `skip`.
|
|
6
|
+
*/
|
|
3
7
|
export function revealTheme(origin, apply, options = {}) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
duration,
|
|
25
|
-
easing,
|
|
26
|
-
pseudoElement: "::view-transition-new(root)"
|
|
27
|
-
});
|
|
28
|
-
});
|
|
8
|
+
const { skip = false, duration = DEFAULT_DURATION, easing = "cubic-bezier(0.77, 0, 0.175, 1)" } = options;
|
|
9
|
+
const point = resolveOrigin(origin);
|
|
10
|
+
const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
11
|
+
if (skip || prefersReduced || !document.startViewTransition || !point) {
|
|
12
|
+
apply();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const { x, y } = point;
|
|
16
|
+
const endRadius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y));
|
|
17
|
+
ensureStyles();
|
|
18
|
+
const transition = document.startViewTransition(() => {
|
|
19
|
+
apply();
|
|
20
|
+
});
|
|
21
|
+
transition.ready.then(() => {
|
|
22
|
+
document.documentElement.animate({ clipPath: [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`] }, {
|
|
23
|
+
duration,
|
|
24
|
+
easing,
|
|
25
|
+
pseudoElement: "::view-transition-new(root)"
|
|
26
|
+
});
|
|
27
|
+
});
|
|
29
28
|
}
|
|
30
29
|
function centreOf(element) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
const rect = element.getBoundingClientRect();
|
|
31
|
+
return {
|
|
32
|
+
x: rect.left + rect.width / 2,
|
|
33
|
+
y: rect.top + rect.height / 2
|
|
34
|
+
};
|
|
36
35
|
}
|
|
36
|
+
// A click on a child still wipes from the control that owns the handler.
|
|
37
37
|
function resolveOrigin(origin) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
if (origin instanceof Element) return centreOf(origin);
|
|
39
|
+
if (origin instanceof MouseEvent) {
|
|
40
|
+
return origin.currentTarget instanceof Element ? centreOf(origin.currentTarget) : {
|
|
41
|
+
x: origin.clientX,
|
|
42
|
+
y: origin.clientY
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return origin;
|
|
46
46
|
}
|
|
47
47
|
function ensureStyles() {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
49
|
+
const style = document.createElement("style");
|
|
50
|
+
style.id = STYLE_ID;
|
|
51
|
+
style.textContent = `::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal;}`;
|
|
52
|
+
document.head.appendChild(style);
|
|
53
53
|
}
|
package/dist/lib/tone.js
CHANGED
|
@@ -1,32 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The severity scale as chip classes and dot colors. Accent reads `--tone-accent` before
|
|
3
|
+
* `--color-primary`, for a host whose primary is a neutral.
|
|
4
|
+
*/
|
|
1
5
|
export const TONE_CLASS = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
neutral: "border-border bg-muted/40 text-muted-foreground",
|
|
7
|
+
accent: "border-[color-mix(in_oklab,var(--tone-accent,var(--color-primary))_30%,transparent)] bg-[color-mix(in_oklab,var(--tone-accent,var(--color-primary))_10%,transparent)] text-[color:var(--tone-accent,var(--color-primary))]",
|
|
8
|
+
info: "border-info/30 bg-info/10 text-info-800 dark:text-info-400",
|
|
9
|
+
success: "border-success/30 bg-success/10 text-success-800 dark:text-success-400",
|
|
10
|
+
warning: "border-warning/30 bg-warning/10 text-warning-800 dark:text-warning-400",
|
|
11
|
+
destructive: "border-destructive/30 bg-destructive/10 text-destructive-ink"
|
|
8
12
|
};
|
|
13
|
+
/** The same scale as text, for a verdict inside a line of muted facts. */
|
|
9
14
|
export const TONE_TEXT = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
neutral: "text-muted-foreground",
|
|
16
|
+
accent: "text-[color:var(--tone-accent,var(--color-primary))]",
|
|
17
|
+
info: "text-info-800 dark:text-info-400",
|
|
18
|
+
success: "text-success-800 dark:text-success-400",
|
|
19
|
+
warning: "text-warning-800 dark:text-warning-400",
|
|
20
|
+
destructive: "text-destructive"
|
|
16
21
|
};
|
|
22
|
+
/** The same scale as icon color. */
|
|
17
23
|
export const TONE_ICON = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
neutral: "text-muted-foreground",
|
|
25
|
+
accent: "text-[color:var(--tone-accent,var(--color-primary))]",
|
|
26
|
+
info: "text-info",
|
|
27
|
+
success: "text-success",
|
|
28
|
+
warning: "text-warning",
|
|
29
|
+
destructive: "text-destructive"
|
|
24
30
|
};
|
|
31
|
+
/** The scale as CSS colors, for the SVG dot. */
|
|
25
32
|
export const TONE_COLOR = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
neutral: "var(--color-muted-foreground)",
|
|
34
|
+
accent: "var(--tone-accent,var(--color-primary))",
|
|
35
|
+
info: "var(--color-info)",
|
|
36
|
+
success: "var(--color-success)",
|
|
37
|
+
warning: "var(--color-warning)",
|
|
38
|
+
destructive: "var(--color-destructive)"
|
|
32
39
|
};
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
// The class merge and prop types every shadcn primitive uses, kept here, not in a shared utils
|
|
2
|
+
// package, so this public package installs with nothing private behind it.
|
|
1
3
|
import { clsx } from "clsx";
|
|
2
4
|
import { twMerge } from "tailwind-merge";
|
|
3
5
|
export function cn(...inputs) {
|
|
4
|
-
|
|
6
|
+
return twMerge(clsx(inputs));
|
|
5
7
|
}
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import { MAX_STEPS } from "./types.js";
|
|
2
2
|
function fail(id, problem) {
|
|
3
|
-
|
|
3
|
+
throw new Error(`tour "${id}": ${problem}`);
|
|
4
4
|
}
|
|
5
|
+
/** Returns the tours as written, after checking what a typo would hide until a user hits it. */
|
|
5
6
|
export function defineTours(tours) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
7
|
+
const ids = new Set();
|
|
8
|
+
for (const tour of tours) {
|
|
9
|
+
const { id } = tour;
|
|
10
|
+
if (!id || !id.trim()) throw new Error("a tour needs an id");
|
|
11
|
+
if (ids.has(id)) fail(id, "its id is used twice");
|
|
12
|
+
ids.add(id);
|
|
13
|
+
if (!tour.route.startsWith("/")) fail(id, `route "${tour.route}" is not a route id`);
|
|
14
|
+
const version = tour.version ?? 1;
|
|
15
|
+
if (!Number.isInteger(version) || version < 1) fail(id, "version is a whole number from 1");
|
|
16
|
+
if (tour.kind === "intro") {
|
|
17
|
+
if (!tour.title || !tour.body) fail(id, "an intro needs a title and a body");
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (tour.steps.length < 1 || tour.steps.length > MAX_STEPS) {
|
|
21
|
+
fail(id, `has ${tour.steps.length} steps, and a tour takes 1 to ${MAX_STEPS}`);
|
|
22
|
+
}
|
|
23
|
+
tour.steps.forEach((step, i) => {
|
|
24
|
+
if (!step.target.trim()) fail(id, `step ${i + 1} has no target`);
|
|
25
|
+
if (!step.title || !step.body) fail(id, `step ${i + 1} needs a title and a body`);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return tours;
|
|
28
29
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
class Onboarding {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
/** True when the current page has a tour, so a menu item can hide itself. */
|
|
3
|
+
hasTour = $state(false);
|
|
4
|
+
/** True while a tour is on screen. */
|
|
5
|
+
running = $state(false);
|
|
6
|
+
#replay = null;
|
|
7
|
+
/** The provider registers itself here. Returns the undo for cleanup. */
|
|
8
|
+
bind(replay) {
|
|
9
|
+
this.#replay = replay;
|
|
10
|
+
return () => {
|
|
11
|
+
if (this.#replay === replay) this.#replay = null;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Restarts this page's tour, or the one named. Writes no seen-state. False when nothing started. */
|
|
15
|
+
replay(tourId) {
|
|
16
|
+
return this.#replay ? this.#replay(tourId) : Promise.resolve(false);
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
19
|
export const onboarding = new Onboarding();
|
package/dist/onboarding/pick.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
/** The seen version has to reach the tour's own, so bumping `version` shows it again. */
|
|
1
2
|
export function isSeen(tour, seen) {
|
|
2
|
-
|
|
3
|
+
return (seen[tour.id] ?? 0) >= (tour.version ?? 1);
|
|
3
4
|
}
|
|
4
5
|
export function toursForRoute(tours, routeId) {
|
|
5
|
-
|
|
6
|
+
return routeId ? tours.filter((tour) => tour.route === routeId) : [];
|
|
6
7
|
}
|
|
8
|
+
/** The first unseen tour on a route, in the order they were defined. One per page view. */
|
|
7
9
|
export function pickTour(tours, routeId, seen) {
|
|
8
|
-
|
|
10
|
+
return toursForRoute(tours, routeId).find((tour) => !isSeen(tour, seen));
|
|
9
11
|
}
|
|
12
|
+
/** What replay starts: a named tour, or the page's first one whether or not it was seen. */
|
|
10
13
|
export function pickForReplay(tours, routeId, tourId) {
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
if (tourId) return tours.find((tour) => tour.id === tourId);
|
|
15
|
+
return toursForRoute(tours, routeId)[0];
|
|
13
16
|
}
|
|
17
|
+
/** Keeps the steps whose target is on the page. A tour with none left starts nothing. */
|
|
14
18
|
export function keepFoundSteps(steps, exists) {
|
|
15
|
-
|
|
19
|
+
return steps.filter((step) => exists(step.target));
|
|
16
20
|
}
|
|
@@ -1,50 +1,49 @@
|
|
|
1
1
|
import { tryCatch } from "../lib/result.js";
|
|
2
|
+
/** Holds seen-state in memory. Tests and previews. */
|
|
2
3
|
export function memoryStore(initial = {}) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (tourId === undefined) seen = {};
|
|
17
|
-
else delete seen[tourId];
|
|
18
|
-
}
|
|
19
|
-
};
|
|
4
|
+
let seen = { ...initial };
|
|
5
|
+
return {
|
|
6
|
+
async load() {
|
|
7
|
+
return { ...seen };
|
|
8
|
+
},
|
|
9
|
+
async markSeen(tourId, version, _outcome) {
|
|
10
|
+
seen[tourId] = Math.max(seen[tourId] ?? 0, version);
|
|
11
|
+
},
|
|
12
|
+
async reset(tourId) {
|
|
13
|
+
if (tourId === undefined) seen = {};
|
|
14
|
+
else delete seen[tourId];
|
|
15
|
+
}
|
|
16
|
+
};
|
|
20
17
|
}
|
|
21
18
|
function readSeen(key) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const read = tryCatch(() => JSON.parse(localStorage.getItem(key) ?? "{}"));
|
|
20
|
+
const parsed = read.ok ? read.value : null;
|
|
21
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
22
|
+
return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === "number"));
|
|
26
23
|
}
|
|
24
|
+
// Blocked storage (private mode, a full disk) means the tour shows again next visit, which beats an error.
|
|
27
25
|
function writeSeen(key, seen) {
|
|
28
|
-
|
|
26
|
+
tryCatch(() => localStorage.setItem(key, JSON.stringify(seen)));
|
|
29
27
|
}
|
|
28
|
+
/** Keeps seen-state in this browser. Demos and signed-out pages. */
|
|
30
29
|
export function localStorageStore(key = "heyramzi:onboarding") {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
30
|
+
return {
|
|
31
|
+
async load() {
|
|
32
|
+
return readSeen(key);
|
|
33
|
+
},
|
|
34
|
+
async markSeen(tourId, version, _outcome) {
|
|
35
|
+
const seen = readSeen(key);
|
|
36
|
+
seen[tourId] = Math.max(seen[tourId] ?? 0, version);
|
|
37
|
+
writeSeen(key, seen);
|
|
38
|
+
},
|
|
39
|
+
async reset(tourId) {
|
|
40
|
+
if (tourId === undefined) {
|
|
41
|
+
tryCatch(() => localStorage.removeItem(key));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const seen = readSeen(key);
|
|
45
|
+
delete seen[tourId];
|
|
46
|
+
writeSeen(key, seen);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
50
49
|
}
|
package/dist/onboarding/wait.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
const find = (selector)=>document.querySelector(selector);
|
|
1
|
+
const find = (selector) => document.querySelector(selector);
|
|
2
|
+
/** Resolves with the element once the selector matches, or null after `timeoutMs` or an abort. */
|
|
2
3
|
export function waitForElement(selector, timeoutMs, signal) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
4
|
+
return new Promise((resolve) => {
|
|
5
|
+
const now = find(selector);
|
|
6
|
+
if (now) return resolve(now);
|
|
7
|
+
if (signal?.aborted) return resolve(null);
|
|
8
|
+
const finish = (el) => {
|
|
9
|
+
observer.disconnect();
|
|
10
|
+
clearTimeout(timer);
|
|
11
|
+
signal?.removeEventListener("abort", onAbort);
|
|
12
|
+
resolve(el);
|
|
13
|
+
};
|
|
14
|
+
const onAbort = () => finish(null);
|
|
15
|
+
const observer = new MutationObserver(() => {
|
|
16
|
+
const el = find(selector);
|
|
17
|
+
if (el) finish(el);
|
|
18
|
+
});
|
|
19
|
+
const timer = setTimeout(() => finish(find(selector)), timeoutMs);
|
|
20
|
+
observer.observe(document.documentElement, {
|
|
21
|
+
childList: true,
|
|
22
|
+
subtree: true
|
|
23
|
+
});
|
|
24
|
+
signal?.addEventListener("abort", onAbort);
|
|
25
|
+
});
|
|
25
26
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|