@heyramzi/ui 2.11.0 → 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/components/tags-input/tags-input.svelte +2 -0
- package/src/editor/markdown.ts +30 -35
|
@@ -1,7 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one skin for a dashboard data table. Classes, not a component: two
|
|
3
|
+
* dashboards share nothing but the look, and each drew its own slightly different one.
|
|
4
|
+
*/
|
|
5
|
+
// Heads aren't uppercase. `SectionLabel` already is, and a nine-column head in
|
|
6
|
+
// the same style fights the panel title and reads worse where density matters.
|
|
1
7
|
export const dataTableClass = "w-full text-sm";
|
|
2
8
|
export const dataTheadClass = "bg-muted/40 text-xs text-muted-foreground";
|
|
3
9
|
export const dataThClass = "px-4 py-2.5 text-left font-medium";
|
|
10
|
+
/** A head over numbers. Right-aligned to the digits under it. */
|
|
4
11
|
export const dataThNumClass = "px-4 py-2.5 text-right font-medium";
|
|
5
12
|
export const dataTrClass = "border-b border-border transition-colors last:border-0 hover:bg-muted/40";
|
|
6
13
|
export const dataTdClass = "px-4 py-2.5 align-top";
|
|
14
|
+
/**
|
|
15
|
+
* A cell holding a number. `tabular-nums` is required: proportional digits make
|
|
16
|
+
* a spend column ragged, and then nobody can scan it.
|
|
17
|
+
*/
|
|
7
18
|
export const dataTdNumClass = "px-4 py-2.5 text-right align-top tabular-nums";
|
package/dist/charts/edge-fade.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/** `true` fades this much of the width at each side. */
|
|
2
|
+
export const EDGE_FADE_DEFAULT = .08;
|
|
3
|
+
/**
|
|
4
|
+
* Turns an `edgeFade` prop into the fraction of the width to fade at each side.
|
|
5
|
+
* `false` (or 0) means no mask is rendered at all.
|
|
6
|
+
*/
|
|
2
7
|
export function resolveEdgeFade(value, fallback = EDGE_FADE_DEFAULT) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
if (value === false) return 0;
|
|
9
|
+
if (value === true || value == null) return fallback;
|
|
10
|
+
if (!Number.isFinite(value)) return 0;
|
|
11
|
+
return Math.min(.45, Math.max(0, value));
|
|
7
12
|
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
/** How far the hover band reaches each side of the point, as a share of the gap to its neighbour. */
|
|
2
|
+
export const HOVER_BAND_REACH = .8;
|
|
3
|
+
/**
|
|
4
|
+
* The hovered segment's clip, centered on the point at `xs[i]`.
|
|
5
|
+
* Both sides take the shorter neighbour gap, so the dot always sits in the middle.
|
|
6
|
+
*/
|
|
2
7
|
export function hoverBand(xs, i, width, reach = HOVER_BAND_REACH) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
if (i < 0 || i >= xs.length) return null;
|
|
9
|
+
const at = xs[i];
|
|
10
|
+
const before = i > 0 ? at - xs[i - 1] : Infinity;
|
|
11
|
+
const after = i < xs.length - 1 ? xs[i + 1] - at : Infinity;
|
|
12
|
+
const gap = Math.min(before, after);
|
|
13
|
+
const half = (Number.isFinite(gap) ? gap : width) * reach;
|
|
14
|
+
return {
|
|
15
|
+
x: at - half,
|
|
16
|
+
width: half * 2
|
|
17
|
+
};
|
|
13
18
|
}
|
package/dist/charts/index.js
CHANGED
|
@@ -8,7 +8,6 @@ export { default as TimeSeriesChart } from "../../src/charts/time-series-chart.s
|
|
|
8
8
|
export { default as GaugeChart } from "../../src/charts/gauge-chart.svelte";
|
|
9
9
|
export { default as RingChart } from "../../src/charts/ring-chart.svelte";
|
|
10
10
|
export { default as Legend } from "../../src/charts/legend.svelte";
|
|
11
|
-
export { } from "../../src/charts/reference-line.svelte";
|
|
12
11
|
export { default as StatCard } from "../../src/charts/stat-card.svelte";
|
|
13
12
|
export { default as NumberChart } from "../../src/charts/number-chart.svelte";
|
|
14
13
|
export { default as Figure } from "../../src/charts/figure.svelte";
|
package/dist/charts/motion.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { cubicInOut } from "svelte/easing";
|
|
2
|
+
/** Mirrors `--chart-motion-reveal` in charts.css, for when no element is mounted to read it from. */
|
|
2
3
|
export const REVEAL_MS = 1100;
|
|
4
|
+
/** Rescales the axes when the data changes; the first render never animates. */
|
|
3
5
|
export const DOMAIN_MOTION = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
type: "tween",
|
|
7
|
+
duration: 500,
|
|
8
|
+
easing: cubicInOut
|
|
7
9
|
};
|
|
10
|
+
/** The tooltip sits beside the hovered point at the top of the plot, so it never chases the cursor. */
|
|
8
11
|
export const TOOLTIP_TOP = 8;
|
|
9
12
|
export const TOOLTIP_GAP = 16;
|
|
13
|
+
/** A chart duration token in ms, read off a mounted element; both `ms` and `s` parse. */
|
|
10
14
|
export function tokenMs(el, name, fallback) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
const raw = getComputedStyle(el).getPropertyValue(name).trim();
|
|
16
|
+
const n = Number.parseFloat(raw);
|
|
17
|
+
if (Number.isNaN(n)) return fallback;
|
|
18
|
+
return raw.endsWith("ms") ? n : n * 1e3;
|
|
15
19
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { getContext, setContext } from "svelte";
|
|
2
2
|
export const THEMES = {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
light: "",
|
|
4
|
+
dark: ".dark"
|
|
5
5
|
};
|
|
6
6
|
export function getPayloadConfigFromPayload(config, item, key) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
if (typeof item !== "object" || item === null) return undefined;
|
|
8
|
+
let configLabelKey = key;
|
|
9
|
+
if (item.key === key) {
|
|
10
|
+
configLabelKey = item.key;
|
|
11
|
+
} else if (item.label === key) {
|
|
12
|
+
configLabelKey = item.label;
|
|
13
|
+
}
|
|
14
|
+
return configLabelKey in config ? config[configLabelKey] : config[key];
|
|
15
15
|
}
|
|
16
16
|
const chartContextKey = Symbol("chart-context");
|
|
17
17
|
export function setChartContext(value) {
|
|
18
|
-
|
|
18
|
+
return setContext(chartContextKey, value);
|
|
19
19
|
}
|
|
20
20
|
export function useChart() {
|
|
21
|
-
|
|
21
|
+
return getContext(chartContextKey);
|
|
22
22
|
}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one write to the clipboard. A rejected permission, a missing gesture and
|
|
3
|
+
* an insecure origin get one answer: false. The caller decides what to show.
|
|
4
|
+
*/
|
|
5
|
+
/** Plain text. Returns false when the browser refused the write. */
|
|
1
6
|
export async function copyText(value) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
try {
|
|
8
|
+
await navigator.clipboard.writeText(value);
|
|
9
|
+
return true;
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
8
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* HTML plus a plain-text twin: Gmail keeps the formatting, Cmd+Shift+V stays
|
|
16
|
+
* readable. Falls back to plain text.
|
|
17
|
+
*/
|
|
9
18
|
export async function copyRichText(html, plainText) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
text
|
|
21
|
-
], {
|
|
22
|
-
type: "text/plain"
|
|
23
|
-
})
|
|
24
|
-
})
|
|
25
|
-
]);
|
|
26
|
-
return true;
|
|
27
|
-
} catch {
|
|
28
|
-
return copyText(text);
|
|
29
|
-
}
|
|
19
|
+
const text = plainText ?? htmlToPlainText(html);
|
|
20
|
+
try {
|
|
21
|
+
await navigator.clipboard.write([new ClipboardItem({
|
|
22
|
+
"text/html": new Blob([html], { type: "text/html" }),
|
|
23
|
+
"text/plain": new Blob([text], { type: "text/plain" })
|
|
24
|
+
})]);
|
|
25
|
+
return true;
|
|
26
|
+
} catch {
|
|
27
|
+
return copyText(text);
|
|
28
|
+
}
|
|
30
29
|
}
|
|
30
|
+
/** The plain-text twin of an HTML fragment. */
|
|
31
31
|
export function htmlToPlainText(html) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
if (typeof document === "undefined") {
|
|
33
|
+
return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<\/li>/gi, "\n").replace(/<li>/gi, "• ").replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").trim();
|
|
34
|
+
}
|
|
35
|
+
const div = document.createElement("div");
|
|
36
|
+
div.innerHTML = html;
|
|
37
|
+
return div.textContent || div.innerText || "";
|
|
38
38
|
}
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
import { copyText } from "./clipboard.js";
|
|
2
|
+
/**
|
|
3
|
+
* The copied flag for a surface whose affordance is a whole row or card rather
|
|
4
|
+
* than a `CopyButton`. Keyed, so one instance serves a list of rows.
|
|
5
|
+
*/
|
|
2
6
|
export class Copied {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
7
|
+
/** The key that last copied, or null. Empty string when a surface has one. */
|
|
8
|
+
key = $state(null);
|
|
9
|
+
#timer = null;
|
|
10
|
+
/** True when anything copied; with a key, true only for that one. */
|
|
11
|
+
is(key = "") {
|
|
12
|
+
return this.key === key;
|
|
13
|
+
}
|
|
14
|
+
/** Writes, then holds the check for `hold` ms. False when the write failed. */
|
|
15
|
+
async copy(value, key = "", hold = 1400) {
|
|
16
|
+
if (!await copyText(value)) return false;
|
|
17
|
+
this.mark(key, hold);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
/** The confirmation without the write, for a copy this class did not make. */
|
|
21
|
+
mark(key = "", hold = 1400) {
|
|
22
|
+
this.key = key;
|
|
23
|
+
if (this.#timer) clearTimeout(this.#timer);
|
|
24
|
+
this.#timer = setTimeout(() => {
|
|
25
|
+
this.key = null;
|
|
26
|
+
this.#timer = null;
|
|
27
|
+
}, hold);
|
|
28
|
+
}
|
|
29
|
+
reset() {
|
|
30
|
+
if (this.#timer) clearTimeout(this.#timer);
|
|
31
|
+
this.#timer = null;
|
|
32
|
+
this.key = null;
|
|
33
|
+
}
|
|
26
34
|
}
|
|
@@ -1,55 +1,55 @@
|
|
|
1
1
|
export function normalizeQuery(query) {
|
|
2
|
-
|
|
2
|
+
return query.trim().toLowerCase();
|
|
3
3
|
}
|
|
4
4
|
export function containsQuery(value, query) {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if (!query) return true;
|
|
6
|
+
return value?.toLowerCase().includes(query) ?? false;
|
|
7
7
|
}
|
|
8
8
|
export function anyContainsQuery(values, query) {
|
|
9
|
-
|
|
9
|
+
return values.some((value) => containsQuery(value, query));
|
|
10
10
|
}
|
|
11
|
+
// ========================= FUNCTIONS
|
|
11
12
|
export function toggleSort(current, key) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
if (current?.key !== key) return {
|
|
14
|
+
key,
|
|
15
|
+
direction: "asc"
|
|
16
|
+
};
|
|
17
|
+
if (current.direction === "asc") return {
|
|
18
|
+
key,
|
|
19
|
+
direction: "desc"
|
|
20
|
+
};
|
|
21
|
+
return null;
|
|
21
22
|
}
|
|
22
23
|
export function sortRows(rows, sort) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return multiplier * String(aVal).localeCompare(String(bVal));
|
|
41
|
-
});
|
|
24
|
+
if (!sort) return rows;
|
|
25
|
+
const { key, direction } = sort;
|
|
26
|
+
const multiplier = direction === "asc" ? 1 : -1;
|
|
27
|
+
return [...rows].sort((a, b) => {
|
|
28
|
+
const aVal = a[key];
|
|
29
|
+
const bVal = b[key];
|
|
30
|
+
if (aVal == null && bVal == null) return 0;
|
|
31
|
+
if (aVal == null) return 1;
|
|
32
|
+
if (bVal == null) return -1;
|
|
33
|
+
if (typeof aVal === "string" && typeof bVal === "string") {
|
|
34
|
+
return multiplier * aVal.localeCompare(bVal);
|
|
35
|
+
}
|
|
36
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
37
|
+
return multiplier * (aVal - bVal);
|
|
38
|
+
}
|
|
39
|
+
return multiplier * String(aVal).localeCompare(String(bVal));
|
|
40
|
+
});
|
|
42
41
|
}
|
|
43
42
|
export function paginateRows(rows, page, pageSize) {
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const start = (page - 1) * pageSize;
|
|
44
|
+
return rows.slice(start, start + pageSize);
|
|
46
45
|
}
|
|
47
46
|
export function totalPages(total, pageSize) {
|
|
48
|
-
|
|
47
|
+
return Math.max(1, Math.ceil(total / pageSize));
|
|
49
48
|
}
|
|
50
49
|
export function formatCount(visible, total, label) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
const singular = label.endsWith("s") ? label.slice(0, -1) : label;
|
|
51
|
+
// The noun agrees with the total: "0 of 1 item", not "0 of 1 items".
|
|
52
|
+
const noun = total === 1 ? singular : label;
|
|
53
|
+
if (visible === total) return `${total.toLocaleString()} ${noun}`;
|
|
54
|
+
return `${visible.toLocaleString()} of ${total.toLocaleString()} ${noun}`;
|
|
55
55
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The documentation anatomy: one page component and the contents rail inside it.
|
|
3
|
+
* A surface supplies a title and a body, and never lays a document out itself.
|
|
4
|
+
*/
|
|
1
5
|
export { default as DocPage } from "../../../src/components/docs/doc-page.svelte";
|
|
2
6
|
export { default as OnThisPage } from "../../../src/components/docs/on-this-page.svelte";
|
|
3
7
|
export { ScrollSpy, READ_LINE } from "./scroll-spy.svelte.js";
|
|
@@ -1,71 +1,76 @@
|
|
|
1
|
+
/** How far below the scroller's top edge a heading counts as "reached" and lands. */
|
|
1
2
|
export const READ_LINE = 80;
|
|
2
3
|
export class ScrollSpy {
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
4
|
+
active = $state("");
|
|
5
|
+
#scroller = null;
|
|
6
|
+
#items = [];
|
|
7
|
+
#locate;
|
|
8
|
+
#frame = 0;
|
|
9
|
+
/** Point the spy at a scroller and a list. Returns the cleanup. */
|
|
10
|
+
attach(scroller, items, locate) {
|
|
11
|
+
this.#scroller = scroller;
|
|
12
|
+
this.#items = items;
|
|
13
|
+
this.#locate = locate;
|
|
14
|
+
if (!scroller || items.length === 0) {
|
|
15
|
+
this.active = "";
|
|
16
|
+
return () => {};
|
|
17
|
+
}
|
|
18
|
+
const schedule = () => {
|
|
19
|
+
this.#frame ||= requestAnimationFrame(() => {
|
|
20
|
+
this.#frame = 0;
|
|
21
|
+
this.update();
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
scroller.addEventListener("scroll", schedule, { passive: true });
|
|
25
|
+
const observer = new ResizeObserver(schedule);
|
|
26
|
+
observer.observe(scroller);
|
|
27
|
+
// A document that grows after load (a diagram, a chart) moves every
|
|
28
|
+
// heading below it, so watch the content too.
|
|
29
|
+
for (const child of scroller.children) observer.observe(child);
|
|
30
|
+
this.update();
|
|
31
|
+
return () => {
|
|
32
|
+
scroller.removeEventListener("scroll", schedule);
|
|
33
|
+
observer.disconnect();
|
|
34
|
+
if (this.#frame) cancelAnimationFrame(this.#frame);
|
|
35
|
+
this.#frame = 0;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
topOf(id) {
|
|
39
|
+
const scroller = this.#scroller;
|
|
40
|
+
if (!scroller) return null;
|
|
41
|
+
if (this.#locate) return this.#locate(id);
|
|
42
|
+
const el = scroller.querySelector(`#${CSS.escape(id)}`);
|
|
43
|
+
if (!el) return null;
|
|
44
|
+
return el.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
|
|
45
|
+
}
|
|
46
|
+
update() {
|
|
47
|
+
const scroller = this.#scroller;
|
|
48
|
+
if (!scroller || this.#items.length === 0) return;
|
|
49
|
+
// At the very bottom the last heading wins, or a short final section could
|
|
50
|
+
// never be the current one.
|
|
51
|
+
const atEnd = scroller.scrollTop + scroller.clientHeight >= scroller.scrollHeight - 2;
|
|
52
|
+
if (atEnd && scroller.scrollTop > 0) {
|
|
53
|
+
this.active = this.#items[this.#items.length - 1].id;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const line = scroller.scrollTop + READ_LINE + 1;
|
|
57
|
+
let current = this.#items[0].id;
|
|
58
|
+
for (const item of this.#items) {
|
|
59
|
+
const top = this.topOf(item.id);
|
|
60
|
+
if (top !== null && top <= line) current = item.id;
|
|
61
|
+
}
|
|
62
|
+
this.active = current;
|
|
63
|
+
}
|
|
64
|
+
/** Scroll so the heading lands on the read line, instant under reduced motion. */
|
|
65
|
+
jump(id) {
|
|
66
|
+
const scroller = this.#scroller;
|
|
67
|
+
const top = this.topOf(id);
|
|
68
|
+
if (!scroller || top === null) return;
|
|
69
|
+
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
70
|
+
this.active = id;
|
|
71
|
+
scroller.scrollTo({
|
|
72
|
+
top: Math.max(0, top - READ_LINE),
|
|
73
|
+
behavior: reduced ? "auto" : "smooth"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
71
76
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
+
// The header for each control group in a toolbar popover, in one place so
|
|
3
|
+
// sections can't drift in size or weight.
|
|
4
|
+
// `first:` drops the leading header's top padding, since the popover pads itself.
|
|
2
5
|
export function filterSectionClass(className) {
|
|
3
|
-
|
|
6
|
+
return cn("px-2 pt-2 pb-1 text-[11px] font-medium uppercase tracking-wide text-muted-foreground first:pt-1", className);
|
|
4
7
|
}
|
|
@@ -19,6 +19,8 @@ export { filterSectionClass } from "./filter-section.js";
|
|
|
19
19
|
export { default as GroupedList } from "../../../src/components/list-page/grouped-list.svelte";
|
|
20
20
|
export { default as ListPageShell } from "../../../src/components/list-page/list-page-shell.svelte";
|
|
21
21
|
export { default as MasterDetail } from "../../../src/components/list-page/master-detail.svelte";
|
|
22
|
+
// The segmented control isn't re-exported here. Two import paths drifted, so
|
|
23
|
+
// its one home is `@heyramzi/ui/components/segmented`.
|
|
22
24
|
export { default as ToolbarSearch } from "../../../src/components/toolbar/toolbar-search.svelte";
|
|
23
25
|
export { toolbarTriggerClass } from "../toolbar/toolbar-trigger.js";
|
|
24
26
|
export { listTable } from "./list-table.js";
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { cn } from "../../lib/utils.js";
|
|
2
|
+
/**
|
|
3
|
+
* The list-page table rhythm, Attio's: one 40px row, a hairline under each, a flat hover.
|
|
4
|
+
*/
|
|
2
5
|
export const listTable = {
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
/** The header row: 36px, a hairline under it. On the cells: `thead` zeroes its row's border. */
|
|
7
|
+
headRow: (className) => cn("hover:translate-y-0 hover:bg-transparent hover:shadow-none [&>th]:h-9 [&>th]:border-b [&>th]:border-border", className),
|
|
8
|
+
/** A body row. The shared row lifts on hover; a flush list row does not. */
|
|
9
|
+
row: (className) => cn("border-b border-border/50 last:border-b-0 hover:translate-y-0 hover:bg-muted/40 hover:shadow-none [&>td]:h-10 [&>td]:py-0", className)
|
|
5
10
|
};
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rail surface of a queue page, passed to `MasterDetail`'s `railClass`.
|
|
3
|
+
* A class, not a wrapper: the shell's `<aside>` already owns the scroll height.
|
|
4
|
+
*/
|
|
5
|
+
// Copies of this string drifted to `rounded-lg`, the control radius, not the container one.
|
|
1
6
|
export const queueRailClass = "flex flex-col overflow-hidden rounded-xl border border-border bg-card";
|
|
7
|
+
/**
|
|
8
|
+
* The rail column track, passed to `MasterDetail`'s `railWidth`. One page ran
|
|
9
|
+
* 20px wider, so the detail pane jumped between pages.
|
|
10
|
+
*/
|
|
11
|
+
// 280px fits a two-line thread title. Past 340px the list competes with the record.
|
|
2
12
|
export const queueRailWidth = "minmax(280px, 340px)";
|
|
13
|
+
/**
|
|
14
|
+
* Context key for the pane `MasterDetail` shows on a phone. Picking a row moves
|
|
15
|
+
* to the record, so `RailRow` reads this instead of each page passing a callback.
|
|
16
|
+
*/
|
|
3
17
|
export const MASTER_DETAIL_PANE = Symbol("master-detail-pane");
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { getContext, setContext } from "svelte";
|
|
2
|
+
// WHY context: the shell decides the strip once and ninety pages draw it, so a prop on every page would be ninety edits.
|
|
2
3
|
const KEY = Symbol("list-page.section-host");
|
|
4
|
+
/** Call once in the layout that owns the section strip. */
|
|
3
5
|
export function setSectionHost(host) {
|
|
4
|
-
|
|
6
|
+
setContext(KEY, host);
|
|
5
7
|
}
|
|
6
8
|
export function getSectionHost() {
|
|
7
|
-
|
|
9
|
+
return getContext(KEY);
|
|
8
10
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
/** The id `by` rows away from `current`, or null at either end or when `current` isn't listed. */
|
|
1
2
|
export function stepTo(ids, current, by) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const index = current ? ids.indexOf(current) : -1;
|
|
4
|
+
if (index < 0) return null;
|
|
5
|
+
return ids[index + by] ?? null;
|
|
5
6
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|