@heyramzi/ui 1.54.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +3 -2
- package/README.md +34 -9
- package/package.json +198 -6
- package/src/ai/generation-progress/GenerationProgress.svelte +12 -12
- package/src/ambient.d.ts +8 -0
- package/src/brand/brand.test.ts +67 -0
- package/src/brand/index.ts +137 -0
- package/src/canvas/README.md +236 -0
- package/src/canvas/card/card-frame.svelte +61 -0
- package/src/canvas/card/card.css +39 -0
- package/src/canvas/card/resize-handles.svelte +119 -0
- package/src/canvas/card/resize.ts +33 -0
- package/src/canvas/chrome/chrome-zoom.svelte +120 -0
- package/src/canvas/chrome/chrome.css +231 -0
- package/src/canvas/chrome/lock-badge.svelte +18 -0
- package/src/canvas/chrome/side-handles.svelte +30 -0
- package/src/canvas/chrome/size-chip.svelte +45 -0
- package/src/canvas/chrome/snap-guides.svelte +69 -0
- package/src/canvas/components/icons/ToolIcon.svelte +30 -0
- package/src/canvas/components/shared/svg/PreviewSvg.svelte +67 -0
- package/src/canvas/components/shared/svg/ShapeOutline.svelte +76 -0
- package/src/canvas/components/shared/svg/StrokeNode.svelte +69 -0
- package/src/canvas/components/shared/svg/TextRule.svelte +37 -0
- package/src/canvas/edges/bend-handle.svelte +76 -0
- package/src/canvas/edges/edge-gradient.svelte +30 -0
- package/src/canvas/edges/edge-path.test.ts +58 -0
- package/src/canvas/edges/edge-path.ts +293 -0
- package/src/canvas/edges/gradient-edge.svelte +43 -0
- package/src/canvas/editor/context-menu.test.ts +65 -0
- package/src/canvas/editor/context-menu.ts +48 -0
- package/src/canvas/editor/dispatch.svelte.test.ts +243 -0
- package/src/canvas/editor/dispatch.svelte.ts +205 -0
- package/src/canvas/editor/editor-context.ts +62 -0
- package/src/canvas/editor/editor-mode.ts +67 -0
- package/src/canvas/editor/frame.ts +98 -0
- package/src/canvas/editor/hand-context.ts +15 -0
- package/src/canvas/editor/history-core.test.ts +239 -0
- package/src/canvas/editor/history-core.ts +247 -0
- package/src/canvas/editor/keymap.test.ts +161 -0
- package/src/canvas/editor/keymap.ts +151 -0
- package/src/canvas/editor/layout-actions.test.ts +156 -0
- package/src/canvas/editor/layout-actions.ts +219 -0
- package/src/canvas/editor/lock.test.ts +68 -0
- package/src/canvas/editor/lock.ts +87 -0
- package/src/canvas/editor/rebase.test.ts +208 -0
- package/src/canvas/editor/rebase.ts +272 -0
- package/src/canvas/editor/style.ts +184 -0
- package/src/canvas/editor/text-field-context.ts +41 -0
- package/src/canvas/editor/z-order.test.ts +75 -0
- package/src/canvas/editor/z-order.ts +87 -0
- package/src/canvas/headless/alignment.test.ts +59 -0
- package/src/canvas/headless/alignment.ts +23 -0
- package/src/canvas/headless/break-apart-find.ts +418 -0
- package/src/canvas/headless/break-apart-pieces.ts +104 -0
- package/src/canvas/headless/break-apart-plan.ts +439 -0
- package/src/canvas/headless/break-apart-style.ts +106 -0
- package/src/canvas/headless/break-apart.ts +244 -0
- package/src/canvas/headless/canvas-cleanup.test.ts +181 -0
- package/src/canvas/headless/canvas-cleanup.ts +102 -0
- package/src/canvas/headless/edge-anchors.test.ts +70 -0
- package/src/canvas/headless/edge-anchors.ts +143 -0
- package/src/canvas/headless/edge-memo.test.ts +58 -0
- package/src/canvas/headless/edge-memo.ts +32 -0
- package/src/canvas/headless/edge-serialization.test.ts +55 -0
- package/src/canvas/headless/edge-serialization.ts +32 -0
- package/src/canvas/headless/figure-geometry.ts +293 -0
- package/src/canvas/headless/fit-viewport.test.ts +85 -0
- package/src/canvas/headless/fit-viewport.ts +137 -0
- package/src/canvas/headless/grid.test.ts +34 -0
- package/src/canvas/headless/grid.ts +94 -0
- package/src/canvas/headless/icon-node.test.ts +23 -0
- package/src/canvas/headless/icon-node.ts +66 -0
- package/src/canvas/headless/index.ts +9 -0
- package/src/canvas/headless/linkify.test.ts +23 -0
- package/src/canvas/headless/linkify.ts +25 -0
- package/src/canvas/headless/pen-marks.ts +133 -0
- package/src/canvas/headless/sketch.test.ts +99 -0
- package/src/canvas/headless/sketch.ts +302 -0
- package/src/canvas/headless/snap-guides.test.ts +61 -0
- package/src/canvas/headless/snap-guides.ts +146 -0
- package/src/canvas/headless/svg-figure.test.ts +49 -0
- package/src/canvas/headless/svg-figure.ts +176 -0
- package/src/canvas/headless/table-layout.test.ts +158 -0
- package/src/canvas/headless/table-layout.ts +309 -0
- package/src/canvas/index.ts +35 -0
- package/src/canvas/lod/lod-mode.svelte.ts +30 -0
- package/src/canvas/lod/lod-switch.svelte +140 -0
- package/src/canvas/lod/render-all.svelte.ts +52 -0
- package/src/canvas/ops/arrange.ts +108 -0
- package/src/canvas/ops/ops.test.ts +98 -0
- package/src/canvas/ops/ops.ts +347 -0
- package/src/canvas/pen/PenField.svelte +128 -0
- package/src/canvas/pen/PenField.test.ts +87 -0
- package/src/canvas/pen/PenOverlay.svelte +172 -0
- package/src/canvas/pen/ShapeNode.svelte +64 -0
- package/src/canvas/pen/TextNode.svelte +97 -0
- package/src/canvas/pen/colors.ts +28 -0
- package/src/canvas/pen/eraser.ts +46 -0
- package/src/canvas/pen/geometry.ts +148 -0
- package/src/canvas/pen/host-field.test.svelte +13 -0
- package/src/canvas/pen/index.ts +40 -0
- package/src/canvas/pen/ops.ts +16 -0
- package/src/canvas/pen/pen-session.ts +177 -0
- package/src/canvas/pen/pen.css +149 -0
- package/src/canvas/pen/plugin.ts +139 -0
- package/src/canvas/pen/shapes.ts +104 -0
- package/src/canvas/pen/stroke-path.ts +54 -0
- package/src/canvas/pen/types.ts +96 -0
- package/src/canvas/pen/ui.ts +26 -0
- package/src/canvas/plugin.test.ts +45 -0
- package/src/canvas/plugin.ts +159 -0
- package/src/canvas/screen/GlyphIcon.svelte +25 -0
- package/src/canvas/screen/PartView.svelte +176 -0
- package/src/canvas/screen/ScreenBody.svelte +142 -0
- package/src/canvas/screen/ScreenCard.svelte +32 -0
- package/src/canvas/screen/glyphs/button.svg +1 -0
- package/src/canvas/screen/glyphs/close.svg +1 -0
- package/src/canvas/screen/glyphs/down.svg +1 -0
- package/src/canvas/screen/glyphs/header.svg +1 -0
- package/src/canvas/screen/glyphs/hills.svg +1 -0
- package/src/canvas/screen/glyphs/image.svg +1 -0
- package/src/canvas/screen/glyphs/input.svg +1 -0
- package/src/canvas/screen/glyphs/list.svg +1 -0
- package/src/canvas/screen/glyphs/modal.svg +1 -0
- package/src/canvas/screen/glyphs/plus.svg +1 -0
- package/src/canvas/screen/glyphs/up.svg +1 -0
- package/src/canvas/screen/glyphs.ts +40 -0
- package/src/canvas/screen/labels.ts +41 -0
- package/src/canvas/screen/parts.ts +164 -0
- package/src/canvas/screen/plugin.ts +67 -0
- package/src/canvas/screen/screen.css +593 -0
- package/src/canvas/screen/types.ts +47 -0
- package/src/canvas/screen/ui.ts +13 -0
- package/src/canvas/test-utils.ts +18 -0
- package/src/canvas/types.ts +53 -0
- package/src/canvas/ui/CanvasToolbar.svelte +169 -0
- package/src/canvas/ui/FrameLayer.svelte +116 -0
- package/src/canvas/ui/PenLayer.svelte +39 -0
- package/src/canvas/ui/StylePanel.svelte +268 -0
- package/src/canvas/ui/canvas-grid.svelte +156 -0
- package/src/canvas/ui/canvas-ui.css +350 -0
- package/src/canvas/ui/forward-wheel.ts +29 -0
- package/src/canvas/ui/icons.ts +124 -0
- package/src/canvas/ui/place-panel.ts +80 -0
- package/src/canvas/ui/shortcut-tip.test.ts +16 -0
- package/src/canvas/ui/shortcut-tip.ts +17 -0
- package/src/canvas/ui/tools.ts +146 -0
- package/src/charts/README.md +104 -0
- package/src/charts/ambient.d.ts +4 -0
- package/src/charts/animated-value.css +7 -0
- package/src/charts/animated-value.svelte +110 -0
- package/src/charts/area-chart.css +29 -0
- package/src/charts/area-chart.svelte +204 -0
- package/src/charts/bar-chart.css +119 -0
- package/src/charts/bar-chart.svelte +275 -0
- package/src/charts/charts.css +201 -0
- package/src/charts/crosshair.svelte +35 -0
- package/src/charts/dashboard/chart.ts +5 -0
- package/src/charts/dashboard/dashboard-empty.svelte +55 -0
- package/src/charts/dashboard/dashboard-section.svelte +58 -0
- package/src/charts/dashboard/data-panel.svelte +81 -0
- package/src/charts/dashboard/data-sort-head.svelte +102 -0
- package/src/charts/dashboard/data-table.svelte +278 -0
- package/src/charts/dashboard/data-table.ts +26 -0
- package/src/charts/dashboard/index.ts +25 -0
- package/src/charts/dashboard/panel-grid.svelte +43 -0
- package/src/charts/dashboard/period-filter.svelte +53 -0
- package/src/charts/dashboard/rating-chip.svelte +35 -0
- package/src/charts/dashboard/stat-band.svelte +47 -0
- package/src/charts/dashboard/stat-tile.svelte +176 -0
- package/src/charts/dashboard/windows.ts +8 -0
- package/src/charts/donut-chart.css +56 -0
- package/src/charts/donut-chart.svelte +158 -0
- package/src/charts/edge-fade.svelte +43 -0
- package/src/charts/edge-fade.ts +16 -0
- package/src/charts/figure.css +100 -0
- package/src/charts/figure.svelte +122 -0
- package/src/charts/gauge-chart.css +94 -0
- package/src/charts/gauge-chart.svelte +302 -0
- package/src/charts/hover-band.test.ts +30 -0
- package/src/charts/hover-band.ts +21 -0
- package/src/charts/hover-focus.svelte +85 -0
- package/src/charts/index.ts +31 -0
- package/src/charts/legend.css +136 -0
- package/src/charts/legend.svelte +112 -0
- package/src/charts/line-chart.css +26 -0
- package/src/charts/line-chart.svelte +256 -0
- package/src/charts/motion.ts +19 -0
- package/src/charts/number-chart.css +179 -0
- package/src/charts/number-chart.svelte +187 -0
- package/src/charts/primitives/chart-container.svelte +57 -0
- package/src/charts/primitives/chart-style.svelte +36 -0
- package/src/charts/primitives/chart-tooltip.svelte +161 -0
- package/src/charts/primitives/chart-utils.ts +54 -0
- package/src/charts/primitives/index.ts +11 -0
- package/src/charts/reference-line.css +18 -0
- package/src/charts/reference-line.svelte +31 -0
- package/src/charts/reveal.svelte +61 -0
- package/src/charts/ring-chart.css +104 -0
- package/src/charts/ring-chart.svelte +166 -0
- package/src/charts/sparkline.css +45 -0
- package/src/charts/sparkline.svelte +141 -0
- package/src/charts/stat-card.css +105 -0
- package/src/charts/stat-card.svelte +267 -0
- package/src/charts/time-series-chart.css +28 -0
- package/src/charts/time-series-chart.svelte +179 -0
- package/src/charts/trend-pill.css +38 -0
- package/src/charts/trend-pill.svelte +48 -0
- package/src/components/copy/copy-button.svelte +1 -1
- package/src/components/docs/doc-page.svelte +1 -1
- package/src/components/docs/on-this-page.svelte +2 -2
- package/src/components/list-page/empty-state.svelte +1 -1
- package/src/components/list-page/filter-popover.svelte +1 -1
- package/src/components/list-page/section-label.svelte +1 -1
- package/src/components/segmented/segment.svelte +4 -4
- package/src/components/theme/theme-provider.svelte +6 -4
- package/src/components/toolbar/index.ts +5 -0
- package/src/components/toolbar/toolbar.svelte +168 -0
- package/src/components/toolbar/toolbar.test.ts +66 -0
- package/src/editor/README.md +58 -0
- package/src/editor/ambient.d.ts +1 -0
- package/src/editor/block-id.ts +77 -0
- package/src/editor/block-ops.test.ts +237 -0
- package/src/editor/block-ops.ts +157 -0
- package/src/editor/content.css +418 -0
- package/src/editor/editor-toolbar.svelte +303 -0
- package/src/editor/editor.svelte +462 -0
- package/src/editor/extensions.ts +145 -0
- package/src/editor/image-toolbar.svelte +123 -0
- package/src/editor/index.ts +17 -0
- package/src/editor/inline-editor.svelte +261 -0
- package/src/editor/markdown-escaping.test.ts +158 -0
- package/src/editor/markdown-marks.test.ts +89 -0
- package/src/editor/markdown-test-helpers.ts +13 -0
- package/src/editor/markdown-youtube.test.ts +93 -0
- package/src/editor/markdown.test.ts +250 -0
- package/src/editor/markdown.ts +511 -0
- package/src/editor/renderer.svelte +92 -0
- package/src/editor/serializer.test.ts +133 -0
- package/src/editor/serializer.ts +370 -0
- package/src/editor/slash-items.ts +115 -0
- package/src/editor/slash-menu.svelte +159 -0
- package/src/editor/youtube-url.ts +35 -0
- package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +13 -13
- package/src/lib/result.ts +19 -0
- package/src/onboarding/README.md +120 -0
- package/src/onboarding/define-tours.test.ts +50 -0
- package/src/onboarding/define-tours.ts +31 -0
- package/src/onboarding/demo.svelte +86 -0
- package/src/onboarding/index.ts +12 -0
- package/src/onboarding/onboarding-provider.svelte +120 -0
- package/src/onboarding/onboarding.svelte.ts +24 -0
- package/src/onboarding/pick.test.ts +79 -0
- package/src/onboarding/pick.ts +36 -0
- package/src/onboarding/stores.test.ts +103 -0
- package/src/onboarding/stores.ts +58 -0
- package/src/onboarding/tour-card.svelte +70 -0
- package/src/onboarding/tour-runner.svelte +197 -0
- package/src/onboarding/types.ts +34 -0
- package/src/onboarding/wait.ts +29 -0
- package/src/shadcn/command/command-input.svelte +1 -1
- package/src/slides/Controls.svelte +138 -0
- package/src/slides/Deck.svelte +271 -0
- package/src/slides/Fragment.svelte +71 -0
- package/src/slides/Overview.svelte +113 -0
- package/src/slides/Presenter.svelte +292 -0
- package/src/slides/README.md +89 -0
- package/src/slides/Slide.svelte +179 -0
- package/src/slides/SlideList.svelte +19 -0
- package/src/slides/ambient.d.ts +1 -0
- package/src/slides/bridges.ts +69 -0
- package/src/slides/deck-controller.svelte.ts +292 -0
- package/src/slides/demo-slides.svelte +358 -0
- package/src/slides/demo.svelte +176 -0
- package/src/slides/export/capture.ts +113 -0
- package/src/slides/export/ffmpeg.ts +120 -0
- package/src/slides/export/index.ts +9 -0
- package/src/slides/export/launch.ts +10 -0
- package/src/slides/export/pdf.ts +152 -0
- package/src/slides/export/types.ts +48 -0
- package/src/slides/index.ts +19 -0
- package/src/slides/labels.ts +48 -0
- package/src/slides/layout.ts +51 -0
- package/src/slides/model.ts +47 -0
- package/src/slides/navigation.ts +100 -0
- package/src/slides/theme.css +205 -0
- package/src/slides/types.ts +86 -0
- package/src/tasks/README.md +312 -0
- package/src/tasks/ambient.d.ts +3 -0
- package/src/tasks/board-order.ts +137 -0
- package/src/tasks/dates.ts +31 -0
- package/src/tasks/define-statuses.ts +32 -0
- package/src/tasks/demo.svelte +389 -0
- package/src/tasks/detail/detail-demo.svelte +186 -0
- package/src/tasks/detail/detail-types.ts +54 -0
- package/src/tasks/detail/task-chip.svelte +28 -0
- package/src/tasks/detail/task-detail.svelte +315 -0
- package/src/tasks/detail/task-property.svelte +17 -0
- package/src/tasks/detail/task-thread.svelte +258 -0
- package/src/tasks/gantt/gantt-bar.svelte +243 -0
- package/src/tasks/gantt/gantt-grid.svelte +94 -0
- package/src/tasks/gantt/gantt-group-row.svelte +55 -0
- package/src/tasks/gantt/gantt-header.svelte +71 -0
- package/src/tasks/gantt/gantt-task-row.svelte +186 -0
- package/src/tasks/gantt/gantt.css +22 -0
- package/src/tasks/gantt/gantt.test.ts +77 -0
- package/src/tasks/gantt/logic.test.ts +163 -0
- package/src/tasks/gantt/logic.ts +248 -0
- package/src/tasks/inbox/inbox-card.svelte +283 -0
- package/src/tasks/inbox/inbox-draft.svelte +84 -0
- package/src/tasks/inbox/inbox-logic.ts +55 -0
- package/src/tasks/inbox/inbox-statuses.ts +48 -0
- package/src/tasks/inbox/inbox-trace.svelte +45 -0
- package/src/tasks/inbox/inbox-types.ts +108 -0
- package/src/tasks/inbox/inbox.svelte +203 -0
- package/src/tasks/inbox/index.ts +23 -0
- package/src/tasks/index.ts +85 -0
- package/src/tasks/kanban-board.svelte +561 -0
- package/src/tasks/kanban-column.svelte +117 -0
- package/src/tasks/kanban-drag.ts +38 -0
- package/src/tasks/kanban-types.ts +65 -0
- package/src/tasks/presets/sales.ts +16 -0
- package/src/tasks/record/demo-data.ts +286 -0
- package/src/tasks/record/field-section.svelte +53 -0
- package/src/tasks/record/fields.ts +142 -0
- package/src/tasks/record/format.ts +87 -0
- package/src/tasks/record/gutter.ts +2 -0
- package/src/tasks/record/index.ts +54 -0
- package/src/tasks/record/info-list.svelte +316 -0
- package/src/tasks/record/kinds.ts +42 -0
- package/src/tasks/record/logic.ts +324 -0
- package/src/tasks/record/next-up.svelte +70 -0
- package/src/tasks/record/project-list.svelte +133 -0
- package/src/tasks/record/record-demo.svelte +324 -0
- package/src/tasks/record/record-header.svelte +70 -0
- package/src/tasks/record/record-shell.svelte +138 -0
- package/src/tasks/record/record-stats.svelte +48 -0
- package/src/tasks/record/record-timeline.svelte +231 -0
- package/src/tasks/record/record.test.ts +350 -0
- package/src/tasks/record/steps-rail.svelte +474 -0
- package/src/tasks/record/types.ts +280 -0
- package/src/tasks/record/where-we-are.svelte +121 -0
- package/src/tasks/reorder.ts +19 -0
- package/src/tasks/side-panel-types.ts +16 -0
- package/src/tasks/side-panel.svelte +193 -0
- package/src/tasks/status-badge.svelte +63 -0
- package/src/tasks/status-dot.svelte +228 -0
- package/src/tasks/status-icon.svelte +30 -0
- package/src/tasks/status-types.ts +40 -0
- package/src/tasks/task-gantt.svelte +230 -0
- package/src/tasks/task-list.svelte +470 -0
- package/src/tasks/task-types.ts +33 -0
- package/src/tasks/time/duration.ts +69 -0
- package/src/tasks/time/time-chip.svelte +62 -0
- package/src/tasks/time/time-dot.svelte +58 -0
- package/src/tasks/time/time-ring.svelte +74 -0
- package/src/tasks/time/time-tracker.svelte +565 -0
- package/src/tasks/time/time-types.ts +74 -0
- package/src/tasks/use-kanban-dnd.svelte.ts +173 -0
- package/src/tokens/base.css +5 -5
- package/src/tokens/palette.css +115 -120
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { TONE_COLOR } from "../lib/tone.js";
|
|
4
|
+
import type { StatusDotVariant, Statuses } from "./status-types.js";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
/** A registry from `defineStatuses`. Resolves color, variant and progress. */
|
|
8
|
+
statuses?: Statuses;
|
|
9
|
+
status?: string;
|
|
10
|
+
/** Explicit color, overrides the registry and tone. */
|
|
11
|
+
color?: string;
|
|
12
|
+
variant?: StatusDotVariant;
|
|
13
|
+
progress?: number;
|
|
14
|
+
size?: number;
|
|
15
|
+
animate?: boolean;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
statuses,
|
|
21
|
+
status,
|
|
22
|
+
color,
|
|
23
|
+
variant,
|
|
24
|
+
progress,
|
|
25
|
+
size = 14,
|
|
26
|
+
animate = true,
|
|
27
|
+
class: className,
|
|
28
|
+
}: Props = $props();
|
|
29
|
+
|
|
30
|
+
const INNER_R = 2;
|
|
31
|
+
const INNER_CIRC = 2 * Math.PI * INNER_R;
|
|
32
|
+
|
|
33
|
+
function clamp01(n: number): number {
|
|
34
|
+
return Math.max(0, Math.min(1, n));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let resolvedColor = $derived(
|
|
38
|
+
color ??
|
|
39
|
+
(statuses && status ? statuses.color(status) : undefined) ??
|
|
40
|
+
(statuses && status ? TONE_COLOR[statuses.tone(status)] : undefined) ??
|
|
41
|
+
TONE_COLOR.neutral,
|
|
42
|
+
);
|
|
43
|
+
let resolvedVariant = $derived(
|
|
44
|
+
variant ?? (statuses && status ? statuses.variant(status) : "open"),
|
|
45
|
+
);
|
|
46
|
+
let resolvedProgress = $derived(
|
|
47
|
+
progress ?? (statuses && status ? statuses.progress(status) : undefined),
|
|
48
|
+
);
|
|
49
|
+
let fraction = $derived(
|
|
50
|
+
resolvedVariant === "progress" && typeof resolvedProgress === "number"
|
|
51
|
+
? clamp01(resolvedProgress)
|
|
52
|
+
: undefined,
|
|
53
|
+
);
|
|
54
|
+
let dasharray = $derived(
|
|
55
|
+
fraction != null
|
|
56
|
+
? `${INNER_CIRC * fraction} ${INNER_CIRC * (1 - fraction)}`
|
|
57
|
+
: undefined,
|
|
58
|
+
);
|
|
59
|
+
let dashoffset = $derived(fraction != null ? INNER_CIRC * 0.25 : undefined);
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
{#if resolvedVariant === "completed"}
|
|
63
|
+
<svg
|
|
64
|
+
width={size}
|
|
65
|
+
height={size}
|
|
66
|
+
viewBox="0 0 14 14"
|
|
67
|
+
fill="none"
|
|
68
|
+
aria-hidden="true"
|
|
69
|
+
class={cn("sd", className)}
|
|
70
|
+
>
|
|
71
|
+
<circle cx="7" cy="7" r="6" fill={resolvedColor} class={animate ? "sd-pop" : ""}></circle>
|
|
72
|
+
<polyline
|
|
73
|
+
points="4.5,7 6.5,9 9.5,5"
|
|
74
|
+
fill="none"
|
|
75
|
+
class={cn("sd-mark", animate && "sd-check")}
|
|
76
|
+
stroke-width="1.5"
|
|
77
|
+
stroke-linecap="round"
|
|
78
|
+
stroke-linejoin="round"
|
|
79
|
+
></polyline>
|
|
80
|
+
</svg>
|
|
81
|
+
{:else if resolvedVariant === "lost"}
|
|
82
|
+
<svg
|
|
83
|
+
width={size}
|
|
84
|
+
height={size}
|
|
85
|
+
viewBox="0 0 14 14"
|
|
86
|
+
fill="none"
|
|
87
|
+
aria-hidden="true"
|
|
88
|
+
class={cn("sd", className)}
|
|
89
|
+
>
|
|
90
|
+
<circle cx="7" cy="7" r="6" fill={resolvedColor} class={animate ? "sd-pop" : ""}></circle>
|
|
91
|
+
<g class="sd-mark" stroke-width="1.5" stroke-linecap="round">
|
|
92
|
+
<line x1="5" y1="5" x2="9" y2="9" class={animate ? "sd-cross" : ""}></line>
|
|
93
|
+
<line x1="9" y1="5" x2="5" y2="9" class={animate ? "sd-cross sd-cross-second" : ""}></line>
|
|
94
|
+
</g>
|
|
95
|
+
</svg>
|
|
96
|
+
{:else if resolvedVariant === "filled"}
|
|
97
|
+
<svg
|
|
98
|
+
width={size}
|
|
99
|
+
height={size}
|
|
100
|
+
viewBox="0 0 14 14"
|
|
101
|
+
fill="none"
|
|
102
|
+
aria-hidden="true"
|
|
103
|
+
class={cn("sd", className)}
|
|
104
|
+
>
|
|
105
|
+
<circle cx="7" cy="7" r="6" fill={resolvedColor} class={animate ? "sd-pop" : ""}></circle>
|
|
106
|
+
</svg>
|
|
107
|
+
{:else}
|
|
108
|
+
<svg
|
|
109
|
+
width={size}
|
|
110
|
+
height={size}
|
|
111
|
+
viewBox="0 0 14 14"
|
|
112
|
+
fill="none"
|
|
113
|
+
aria-hidden="true"
|
|
114
|
+
class={cn("sd", className)}
|
|
115
|
+
>
|
|
116
|
+
<circle
|
|
117
|
+
cx="7"
|
|
118
|
+
cy="7"
|
|
119
|
+
r="5.5"
|
|
120
|
+
stroke={resolvedColor}
|
|
121
|
+
stroke-width="1.5"
|
|
122
|
+
class={resolvedVariant === "dashed" ? "sd-dashed" : ""}
|
|
123
|
+
></circle>
|
|
124
|
+
{#if dasharray}
|
|
125
|
+
<circle
|
|
126
|
+
cx="7"
|
|
127
|
+
cy="7"
|
|
128
|
+
r={INNER_R}
|
|
129
|
+
fill="none"
|
|
130
|
+
stroke={resolvedColor}
|
|
131
|
+
stroke-width="4"
|
|
132
|
+
stroke-dasharray={dasharray}
|
|
133
|
+
stroke-dashoffset={dashoffset}
|
|
134
|
+
transform="rotate(-90 7 7)"
|
|
135
|
+
class={animate ? "sd-fill" : ""}
|
|
136
|
+
></circle>
|
|
137
|
+
{/if}
|
|
138
|
+
</svg>
|
|
139
|
+
{/if}
|
|
140
|
+
|
|
141
|
+
<style>
|
|
142
|
+
.sd {
|
|
143
|
+
flex-shrink: 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* The tick and cross read as cut out of the disc. A host sets the mark to its own ground. */
|
|
147
|
+
.sd-mark {
|
|
148
|
+
stroke: var(--status-dot-mark, white);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* 12 dashes that close evenly: 2 * PI * 5.5 = 34.56, cut into 12 periods of 2.88. */
|
|
152
|
+
.sd-dashed {
|
|
153
|
+
stroke-dasharray: 1.3 1.58;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.sd-fill {
|
|
157
|
+
transform-origin: 7px 7px;
|
|
158
|
+
animation: sd-fill-in var(--duration-slow, 320ms) var(--ease-smooth-out, ease-out) forwards;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@keyframes sd-fill-in {
|
|
162
|
+
from {
|
|
163
|
+
transform: rotate(-90deg) scale(0.4);
|
|
164
|
+
opacity: 0;
|
|
165
|
+
}
|
|
166
|
+
to {
|
|
167
|
+
transform: rotate(-90deg) scale(1);
|
|
168
|
+
opacity: 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.sd-pop {
|
|
173
|
+
transform-origin: 7px 7px;
|
|
174
|
+
animation: sd-pop-in var(--duration-medium, 240ms) var(--ease-smooth-out, ease-out) forwards;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@keyframes sd-pop-in {
|
|
178
|
+
from {
|
|
179
|
+
transform: scale(0.4);
|
|
180
|
+
opacity: 0;
|
|
181
|
+
}
|
|
182
|
+
60% {
|
|
183
|
+
transform: scale(1.08);
|
|
184
|
+
opacity: 1;
|
|
185
|
+
}
|
|
186
|
+
to {
|
|
187
|
+
transform: scale(1);
|
|
188
|
+
opacity: 1;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.sd-check {
|
|
193
|
+
stroke-dasharray: 12;
|
|
194
|
+
stroke-dashoffset: 12;
|
|
195
|
+
animation: sd-trace var(--duration-medium, 240ms) var(--ease-smooth-out, ease-out)
|
|
196
|
+
var(--duration-quick, 120ms) forwards;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.sd-cross {
|
|
200
|
+
stroke-dasharray: 6;
|
|
201
|
+
stroke-dashoffset: 6;
|
|
202
|
+
animation: sd-trace calc(var(--duration-fast, 160ms) / 2) var(--ease-smooth-out, ease-out)
|
|
203
|
+
var(--duration-quick, 120ms) forwards;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.sd-cross-second {
|
|
207
|
+
animation-delay: calc(var(--duration-quick, 120ms) + var(--duration-fast, 160ms) / 2);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@keyframes sd-trace {
|
|
211
|
+
to {
|
|
212
|
+
stroke-dashoffset: 0;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@media (prefers-reduced-motion: reduce) {
|
|
217
|
+
.sd-fill,
|
|
218
|
+
.sd-pop,
|
|
219
|
+
.sd-check,
|
|
220
|
+
.sd-cross {
|
|
221
|
+
animation: none;
|
|
222
|
+
}
|
|
223
|
+
.sd-check,
|
|
224
|
+
.sd-cross {
|
|
225
|
+
stroke-dashoffset: 0;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Component } from "svelte";
|
|
3
|
+
import StatusDot from "./status-dot.svelte";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { TONE_ICON } from "../lib/tone.js";
|
|
6
|
+
import type { Statuses } from "./status-types.js";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
statuses: Statuses;
|
|
10
|
+
status: string;
|
|
11
|
+
size?: number;
|
|
12
|
+
animate?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
let { statuses, status, size = 14, animate = true, class: className }: Props = $props();
|
|
17
|
+
|
|
18
|
+
// An icon in the map wins; otherwise the status falls back to its dot.
|
|
19
|
+
let icon = $derived(
|
|
20
|
+
statuses.icon(status) as Component<{ size?: number; class?: string }> | undefined,
|
|
21
|
+
);
|
|
22
|
+
let tone = $derived(statuses.tone(status));
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
{#if icon}
|
|
26
|
+
{@const Icon = icon}
|
|
27
|
+
<Icon {size} class={cn("shrink-0", TONE_ICON[tone], className)} />
|
|
28
|
+
{:else}
|
|
29
|
+
<StatusDot {statuses} {status} {size} {animate} class={className} />
|
|
30
|
+
{/if}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
import type { Tone } from "../lib/tone.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The shape the dot can take. `progress` needs a `progress` value between 0 and 1.
|
|
6
|
+
* `dashed` is an open ring cut into dashes, for an aggregate such as "All".
|
|
7
|
+
*/
|
|
8
|
+
export type StatusDotVariant = "open" | "dashed" | "progress" | "filled" | "completed" | "lost";
|
|
9
|
+
|
|
10
|
+
export type StatusDef = {
|
|
11
|
+
label: string;
|
|
12
|
+
tone?: Tone;
|
|
13
|
+
/** Any Svelte component, for example a Phosphor icon. Renders inside StatusIcon. */
|
|
14
|
+
icon?: Component;
|
|
15
|
+
variant?: StatusDotVariant;
|
|
16
|
+
/** 0 to 1. Only used by the `progress` variant. */
|
|
17
|
+
progress?: number;
|
|
18
|
+
/** Optional CSS color. Overrides the tone color for the dot and icon. */
|
|
19
|
+
color?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type StatusMap = Record<string, StatusDef>;
|
|
24
|
+
|
|
25
|
+
export type StatusId<M extends StatusMap> = keyof M & string;
|
|
26
|
+
|
|
27
|
+
/** What the components accept. `defineStatuses` returns this plus a typed `ids`. */
|
|
28
|
+
export type Statuses = {
|
|
29
|
+
/** The raw map. Kept loose so a registry with specific keys is assignable here. */
|
|
30
|
+
map: StatusMap;
|
|
31
|
+
ids: string[];
|
|
32
|
+
has(id: string): boolean;
|
|
33
|
+
get(id: string): StatusDef | undefined;
|
|
34
|
+
label(id: string): string;
|
|
35
|
+
tone(id: string): Tone;
|
|
36
|
+
icon(id: string): Component | undefined;
|
|
37
|
+
variant(id: string): StatusDotVariant;
|
|
38
|
+
progress(id: string): number | undefined;
|
|
39
|
+
color(id: string): string | undefined;
|
|
40
|
+
};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { dayNumber, isoFromDay, todayIso } from "./dates.js";
|
|
5
|
+
import GanttGrid from "./gantt/gantt-grid.svelte";
|
|
6
|
+
import GanttGroupRow from "./gantt/gantt-group-row.svelte";
|
|
7
|
+
import GanttHeader from "./gantt/gantt-header.svelte";
|
|
8
|
+
import GanttTaskRow from "./gantt/gantt-task-row.svelte";
|
|
9
|
+
import {
|
|
10
|
+
buildArrows,
|
|
11
|
+
buildDays,
|
|
12
|
+
buildMonths,
|
|
13
|
+
buildRows,
|
|
14
|
+
dayX,
|
|
15
|
+
rangeLabel,
|
|
16
|
+
rangeOf,
|
|
17
|
+
type Drag,
|
|
18
|
+
type Layout,
|
|
19
|
+
type Span,
|
|
20
|
+
} from "./gantt/logic.js";
|
|
21
|
+
import type { KanbanColumn as KanbanColumnDef } from "./kanban-types.js";
|
|
22
|
+
import type { GanttChange, GanttLabelContext } from "./task-types.js";
|
|
23
|
+
|
|
24
|
+
interface Props<T> {
|
|
25
|
+
items: T[];
|
|
26
|
+
getId: (item: T) => string;
|
|
27
|
+
getTitle: (item: T) => string;
|
|
28
|
+
/**
|
|
29
|
+
* ISO date, inclusive. Null or empty means undated: with an end date alone the task
|
|
30
|
+
* starts the same day, and with neither it has no bar of its own.
|
|
31
|
+
*/
|
|
32
|
+
getStart: (item: T) => string | null | undefined;
|
|
33
|
+
/** ISO date, inclusive. See `getStart`. */
|
|
34
|
+
getEnd: (item: T) => string | null | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The id of the task this one sits under. Children nest under their parent, indented
|
|
37
|
+
* and foldable. A parent with no dates of its own draws the span of what is below it.
|
|
38
|
+
*/
|
|
39
|
+
getParent?: (item: T) => string | null | undefined;
|
|
40
|
+
/** Draws a flag at the end date instead of a bar. Milestones are not draggable. */
|
|
41
|
+
isMilestone?: (item: T) => boolean;
|
|
42
|
+
/** Parent ids that start folded. */
|
|
43
|
+
collapsed?: string[];
|
|
44
|
+
/** Shown in place of a bar for an undated task. */
|
|
45
|
+
noDatesLabel?: string;
|
|
46
|
+
/** Any CSS color for the bar. Falls back to the group hue, then the primary color. */
|
|
47
|
+
getHue?: (item: T) => string | undefined;
|
|
48
|
+
/** 0 to 1. Fills the bar from the left. */
|
|
49
|
+
getProgress?: (item: T) => number | undefined;
|
|
50
|
+
/** Ids this task waits on. Draws an arrow from each one's end to this one's start. */
|
|
51
|
+
getDependsOn?: (item: T) => string[] | undefined;
|
|
52
|
+
/** Group rows under a header, in the order given. Same shape as board columns. */
|
|
53
|
+
groups?: KanbanColumnDef[];
|
|
54
|
+
getGroup?: (item: T) => string;
|
|
55
|
+
/** Called after a bar is dragged, resized or nudged. Leave it out for a read-only chart. */
|
|
56
|
+
onChange?: (id: string, change: GanttChange) => void | Promise<void>;
|
|
57
|
+
/** Called on a click or Enter that did not move the bar. */
|
|
58
|
+
onSelect?: (id: string) => void;
|
|
59
|
+
/** The left column for a row. Defaults to the title. */
|
|
60
|
+
renderLabel?: Snippet<[T, GanttLabelContext]>;
|
|
61
|
+
/** First and last day shown. Default: the tasks' span, padded, starting on a Monday. */
|
|
62
|
+
from?: string;
|
|
63
|
+
to?: string;
|
|
64
|
+
/** The day the today line marks. Defaults to the viewer's today. */
|
|
65
|
+
today?: string;
|
|
66
|
+
dayWidth?: number;
|
|
67
|
+
rowHeight?: number;
|
|
68
|
+
/** Width of the task column in px. It never takes more than 40% of a narrow screen. */
|
|
69
|
+
labelWidth?: number;
|
|
70
|
+
labelHeading?: string;
|
|
71
|
+
locale?: string;
|
|
72
|
+
/** Drops the card chrome (border, radius, fill) so the chart sits flat on the page. */
|
|
73
|
+
flat?: boolean;
|
|
74
|
+
class?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let {
|
|
78
|
+
items,
|
|
79
|
+
getId,
|
|
80
|
+
getTitle,
|
|
81
|
+
getStart,
|
|
82
|
+
getEnd,
|
|
83
|
+
getParent,
|
|
84
|
+
isMilestone,
|
|
85
|
+
collapsed = [],
|
|
86
|
+
noDatesLabel = "No dates",
|
|
87
|
+
getHue,
|
|
88
|
+
getProgress,
|
|
89
|
+
getDependsOn,
|
|
90
|
+
groups,
|
|
91
|
+
getGroup,
|
|
92
|
+
onChange,
|
|
93
|
+
onSelect,
|
|
94
|
+
renderLabel,
|
|
95
|
+
from,
|
|
96
|
+
to,
|
|
97
|
+
today = todayIso(),
|
|
98
|
+
dayWidth = 32,
|
|
99
|
+
rowHeight = 40,
|
|
100
|
+
labelWidth = 240,
|
|
101
|
+
labelHeading = "Task",
|
|
102
|
+
locale = "en-US",
|
|
103
|
+
flat = false,
|
|
104
|
+
class: className,
|
|
105
|
+
}: Props<T> = $props();
|
|
106
|
+
|
|
107
|
+
// Bars past this row enter together, so a long chart never waits on its stagger.
|
|
108
|
+
const STAGGER_CAP = 10;
|
|
109
|
+
// A bar narrower than this shows its title outside, to the right.
|
|
110
|
+
const INLINE_TITLE_MIN = 72;
|
|
111
|
+
const INDENT = 14;
|
|
112
|
+
|
|
113
|
+
let scroller = $state<HTMLDivElement>();
|
|
114
|
+
let corner = $state<HTMLDivElement>();
|
|
115
|
+
let drag = $state<Drag | null>(null);
|
|
116
|
+
let hoveredId = $state<string | null>(null);
|
|
117
|
+
let scrolledToToday = false;
|
|
118
|
+
// svelte-ignore state_referenced_locally
|
|
119
|
+
let folded = $state(new Set(collapsed));
|
|
120
|
+
|
|
121
|
+
let todayDay = $derived(dayNumber(today));
|
|
122
|
+
let range = $derived(rangeOf(items, { getStart, getEnd }, todayDay, from, to));
|
|
123
|
+
let dayCount = $derived(range.last - range.first + 1);
|
|
124
|
+
let layout = $derived<Layout>({
|
|
125
|
+
first: range.first,
|
|
126
|
+
last: range.last,
|
|
127
|
+
dayWidth,
|
|
128
|
+
rowHeight,
|
|
129
|
+
// Under 18px a day is too narrow for a gap either side of a bar.
|
|
130
|
+
inset: dayWidth >= 18 ? 3 : 0,
|
|
131
|
+
timelineWidth: dayCount * dayWidth,
|
|
132
|
+
todayDay,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
let days = $derived(buildDays(range.first, dayCount));
|
|
136
|
+
let monthFormat = $derived(new Intl.DateTimeFormat(locale, { month: "long", year: "numeric", timeZone: "UTC" }));
|
|
137
|
+
let dayFormat = $derived(new Intl.DateTimeFormat(locale, { month: "short", day: "numeric", timeZone: "UTC" }));
|
|
138
|
+
let months = $derived(buildMonths(days, monthFormat));
|
|
139
|
+
let rows = $derived(buildRows(items, { getId, getStart, getEnd, getParent, groups, getGroup, folded, drag }));
|
|
140
|
+
let arrows = $derived(getDependsOn ? buildArrows(rows, layout, getDependsOn) : []);
|
|
141
|
+
let groupHue = $derived(new Map((groups ?? []).map((g) => [g.id, g.hue])));
|
|
142
|
+
|
|
143
|
+
function toggle(id: string): void {
|
|
144
|
+
const next = new Set(folded);
|
|
145
|
+
if (next.has(id)) next.delete(id);
|
|
146
|
+
else next.add(id);
|
|
147
|
+
folded = next;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function hueOf(item: T): string {
|
|
151
|
+
return getHue?.(item) ?? (getGroup ? groupHue.get(getGroup(item)) : undefined) ?? "var(--color-primary)";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function hover(id: string, on: boolean): void {
|
|
155
|
+
if (on) hoveredId = id;
|
|
156
|
+
else if (hoveredId === id) hoveredId = null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function describe(span: Span): string {
|
|
160
|
+
return rangeLabel(span, dayFormat);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Open on today, a third of the way in, so past work and what's next both show.
|
|
164
|
+
$effect(() => {
|
|
165
|
+
if (!scroller || scrolledToToday) return;
|
|
166
|
+
scrolledToToday = true;
|
|
167
|
+
const label = corner?.offsetWidth ?? 0;
|
|
168
|
+
scroller.scrollLeft = Math.max(0, dayX(layout, todayDay) - (scroller.clientWidth - label) / 3);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
/** Scroll the today line into view. */
|
|
172
|
+
export function scrollToToday(): void {
|
|
173
|
+
if (!scroller) return;
|
|
174
|
+
const label = corner?.offsetWidth ?? 0;
|
|
175
|
+
scroller.scrollTo({ left: Math.max(0, dayX(layout, todayDay) - (scroller.clientWidth - label) / 3), behavior: "smooth" });
|
|
176
|
+
}
|
|
177
|
+
</script>
|
|
178
|
+
|
|
179
|
+
<div
|
|
180
|
+
bind:this={scroller}
|
|
181
|
+
class={cn(
|
|
182
|
+
"task-gantt relative min-h-0 flex-1 overflow-auto overscroll-x-contain",
|
|
183
|
+
flat ? "bg-background" : "rounded-xl border border-border bg-card text-card-foreground",
|
|
184
|
+
drag && "select-none",
|
|
185
|
+
className,
|
|
186
|
+
)}
|
|
187
|
+
style:--g-label="min({labelWidth}px, 40vw)"
|
|
188
|
+
style:--g-day="{dayWidth}px"
|
|
189
|
+
style:--g-row="{rowHeight}px"
|
|
190
|
+
>
|
|
191
|
+
<div class="relative" style:width="calc(var(--g-label) + {layout.timelineWidth}px)">
|
|
192
|
+
<GanttHeader {layout} {days} {months} {labelHeading} {locale} bind:corner />
|
|
193
|
+
|
|
194
|
+
<div class="relative">
|
|
195
|
+
<GanttGrid {layout} {days} {arrows} rowCount={rows.length} {hoveredId} draggingId={drag?.id ?? null} />
|
|
196
|
+
|
|
197
|
+
<div role="list" aria-label="Timeline">
|
|
198
|
+
{#each rows as row, index (row.kind === "group" ? `g:${row.group.id}` : row.id)}
|
|
199
|
+
{#if row.kind === "group"}
|
|
200
|
+
<GanttGroupRow {row} {index} {layout} staggerCap={STAGGER_CAP} />
|
|
201
|
+
{:else}
|
|
202
|
+
<GanttTaskRow
|
|
203
|
+
{row}
|
|
204
|
+
{layout}
|
|
205
|
+
title={getTitle(row.item)}
|
|
206
|
+
hue={hueOf(row.item)}
|
|
207
|
+
progress={Math.max(0, Math.min(1, getProgress?.(row.item) ?? 0))}
|
|
208
|
+
milestone={isMilestone?.(row.item) ?? false}
|
|
209
|
+
nested={!!getParent}
|
|
210
|
+
indent={INDENT}
|
|
211
|
+
staggerCap={STAGGER_CAP}
|
|
212
|
+
inlineTitleMin={INLINE_TITLE_MIN}
|
|
213
|
+
{noDatesLabel}
|
|
214
|
+
hovered={hoveredId === row.id}
|
|
215
|
+
tipBelow={row.order === 0 && !groups}
|
|
216
|
+
{drag}
|
|
217
|
+
setDrag={(next) => (drag = next)}
|
|
218
|
+
onhover={hover}
|
|
219
|
+
onToggle={toggle}
|
|
220
|
+
{onChange}
|
|
221
|
+
{onSelect}
|
|
222
|
+
{renderLabel}
|
|
223
|
+
{describe}
|
|
224
|
+
/>
|
|
225
|
+
{/if}
|
|
226
|
+
{/each}
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|