@joewinke/jatui 0.1.31 → 0.2.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/CLAUDE.md +22 -0
- package/dist/actions/attention.d.ts +24 -0
- package/dist/actions/attention.js +94 -0
- package/dist/actions/collapse.js +29 -15
- package/dist/actions/floating.d.ts +53 -0
- package/dist/actions/floating.js +158 -0
- package/dist/actions/listNav.js +137 -108
- package/dist/actions/railNav.js +89 -72
- package/dist/actions/staggerEntrance.d.ts +28 -0
- package/dist/actions/staggerEntrance.js +71 -0
- package/dist/actions/tooltip.d.ts +28 -0
- package/dist/actions/tooltip.js +186 -0
- package/dist/assets/sounds/README.md +47 -0
- package/dist/assets/sounds/error.d.ts +1 -0
- package/dist/assets/sounds/error.js +4 -0
- package/dist/assets/sounds/notify.d.ts +1 -0
- package/dist/assets/sounds/notify.js +4 -0
- package/dist/assets/sounds/pop.d.ts +1 -0
- package/dist/assets/sounds/pop.js +4 -0
- package/dist/assets/sounds/send.d.ts +1 -0
- package/dist/assets/sounds/send.js +4 -0
- package/dist/assets/sounds/success.d.ts +1 -0
- package/dist/assets/sounds/success.js +4 -0
- package/dist/assets/sounds/toggle.d.ts +1 -0
- package/dist/assets/sounds/toggle.js +4 -0
- package/dist/components/AnimatedNumber.svelte +112 -0
- package/dist/components/AnimatedNumber.svelte.d.ts +8 -0
- package/dist/components/Badge.svelte +75 -4
- package/dist/components/Badge.svelte.d.ts +6 -1
- package/dist/components/Button.svelte +196 -21
- package/dist/components/Button.svelte.d.ts +10 -1
- package/dist/components/Carousel.svelte +265 -0
- package/dist/components/Carousel.svelte.d.ts +21 -0
- package/dist/components/ChipInput.svelte +63 -3
- package/dist/components/Collapse.svelte +70 -14
- package/dist/components/Collapse.svelte.d.ts +11 -0
- package/dist/components/ColorSelector.svelte +21 -24
- package/dist/components/CommandPalette.svelte +475 -0
- package/dist/components/CommandPalette.svelte.d.ts +3 -0
- package/dist/components/ContextMenu.svelte +9 -73
- package/dist/components/CopyButton.svelte +156 -0
- package/dist/components/CopyButton.svelte.d.ts +12 -0
- package/dist/components/HoldToConfirm.svelte +183 -0
- package/dist/components/HoldToConfirm.svelte.d.ts +11 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte +54 -8
- package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +3 -0
- package/dist/components/PasswordMeter.svelte +87 -0
- package/dist/components/PasswordMeter.svelte.d.ts +8 -0
- package/dist/components/PinInput.svelte +186 -0
- package/dist/components/PinInput.svelte.d.ts +13 -0
- package/dist/components/QuantityStepper.svelte +185 -0
- package/dist/components/QuantityStepper.svelte.d.ts +12 -0
- package/dist/components/Skeleton.svelte +123 -0
- package/dist/components/Skeleton.svelte.d.ts +12 -0
- package/dist/components/SpeechForm.svelte +37 -0
- package/dist/components/StatusBadge.svelte +31 -3
- package/dist/components/StatusBadge.svelte.d.ts +0 -5
- package/dist/components/Tabs.svelte +270 -0
- package/dist/components/Tabs.svelte.d.ts +15 -0
- package/dist/components/TextInput.svelte +138 -38
- package/dist/components/TextInput.svelte.d.ts +9 -1
- package/dist/components/VoicePlayer.svelte +51 -0
- package/dist/components/basic/Alert.svelte +36 -0
- package/dist/components/basic/Alert.svelte.d.ts +9 -0
- package/dist/components/basic/Breadcrumb.svelte +27 -0
- package/dist/components/basic/Breadcrumb.svelte.d.ts +11 -0
- package/dist/components/basic/ButtonGroup.svelte +15 -0
- package/dist/components/basic/ButtonGroup.svelte.d.ts +8 -0
- package/dist/components/basic/Checkbox.svelte +85 -0
- package/dist/components/basic/Checkbox.svelte.d.ts +15 -0
- package/dist/components/basic/Empty.svelte +17 -0
- package/dist/components/basic/Empty.svelte.d.ts +8 -0
- package/dist/components/basic/Kbd.svelte +16 -0
- package/dist/components/basic/Kbd.svelte.d.ts +8 -0
- package/dist/components/basic/Pagination.svelte +104 -0
- package/dist/components/basic/Pagination.svelte.d.ts +12 -0
- package/dist/components/basic/RadioGroup.svelte +71 -0
- package/dist/components/basic/RadioGroup.svelte.d.ts +18 -0
- package/dist/components/basic/Separator.svelte +19 -0
- package/dist/components/basic/Separator.svelte.d.ts +8 -0
- package/dist/components/basic/Slider.svelte +72 -0
- package/dist/components/basic/Slider.svelte.d.ts +17 -0
- package/dist/components/basic/Switch.svelte +88 -0
- package/dist/components/basic/Switch.svelte.d.ts +14 -0
- package/dist/components/basic/Toggle.svelte +43 -0
- package/dist/components/basic/Toggle.svelte.d.ts +14 -0
- package/dist/components/graph/GraphCanvas.svelte +103 -0
- package/dist/components/graph/GraphCanvas.svelte.d.ts +22 -0
- package/dist/components/graph/JatuiNode.svelte +128 -0
- package/dist/components/graph/JatuiNode.svelte.d.ts +14 -0
- package/dist/components/graph/theme.d.ts +27 -0
- package/dist/components/graph/theme.js +136 -0
- package/dist/components/markup.js +62 -59
- package/dist/components/messaging/MessageItem.svelte +92 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +5 -0
- package/dist/components/messaging/TypingIndicator.svelte +63 -0
- package/dist/components/messaging/TypingIndicator.svelte.d.ts +7 -0
- package/dist/components/pipeline/PipelineColumn.svelte +44 -3
- package/dist/components/progress/ProgressBar.svelte +189 -0
- package/dist/components/progress/ProgressBar.svelte.d.ts +17 -0
- package/dist/components/progress/ProgressRing.svelte +138 -0
- package/dist/components/progress/ProgressRing.svelte.d.ts +12 -0
- package/dist/components/progress/Steps.svelte +195 -0
- package/dist/components/progress/Steps.svelte.d.ts +14 -0
- package/dist/components/session-nav/transcriptModel.js +66 -49
- package/dist/components/shell/NavigationMenu.svelte +422 -0
- package/dist/components/shell/NavigationMenu.svelte.d.ts +43 -0
- package/dist/components/shell/Sidebar.svelte +276 -0
- package/dist/components/shell/Sidebar.svelte.d.ts +32 -0
- package/dist/components/shell/SidebarGroup.svelte +180 -0
- package/dist/components/shell/SidebarGroup.svelte.d.ts +19 -0
- package/dist/components/shell/SidebarItem.svelte +170 -0
- package/dist/components/shell/SidebarItem.svelte.d.ts +24 -0
- package/dist/components/shell/shell.d.ts +30 -0
- package/dist/components/shell/shell.js +65 -0
- package/dist/components/table/DataTable.svelte +364 -0
- package/dist/components/table/DataTable.svelte.d.ts +4 -0
- package/dist/components/table/flexRender.d.ts +31 -0
- package/dist/components/table/flexRender.js +32 -0
- package/dist/components/table/types.d.ts +28 -0
- package/dist/components/table/types.js +1 -0
- package/dist/components/toast/ToastHost.svelte +21 -0
- package/dist/components/toast/ToastHost.svelte.d.ts +3 -0
- package/dist/components/toast/ToastItem.svelte +287 -0
- package/dist/components/toast/ToastItem.svelte.d.ts +9 -0
- package/dist/data/emojis.js +4 -4
- package/dist/dnd/autoScroll.js +12 -10
- package/dist/dnd/createDndBoard.svelte.js +110 -76
- package/dist/dnd/createDndBoard.test.js +161 -85
- package/dist/dnd/draggable.js +23 -15
- package/dist/dnd/dropTarget.js +29 -15
- package/dist/dnd/index.d.ts +0 -1
- package/dist/dnd/index.js +0 -1
- package/dist/dnd/types.d.ts +0 -9
- package/dist/dnd/types.js +14 -2
- package/dist/index.d.ts +60 -6
- package/dist/index.js +73 -6
- package/dist/showcase/AnimatedBeam.svelte +183 -0
- package/dist/showcase/AnimatedBeam.svelte.d.ts +26 -0
- package/dist/showcase/AuroraDrift.svelte +74 -0
- package/dist/showcase/AuroraDrift.svelte.d.ts +9 -0
- package/dist/showcase/BentoCard.svelte +50 -0
- package/dist/showcase/BentoCard.svelte.d.ts +14 -0
- package/dist/showcase/BentoGrid.svelte +43 -0
- package/dist/showcase/BentoGrid.svelte.d.ts +12 -0
- package/dist/showcase/BorderBeam.svelte +79 -0
- package/dist/showcase/BorderBeam.svelte.d.ts +12 -0
- package/dist/showcase/ClipWipe.svelte +82 -0
- package/dist/showcase/ClipWipe.svelte.d.ts +12 -0
- package/dist/showcase/Confetti.svelte +71 -0
- package/dist/showcase/Confetti.svelte.d.ts +10 -0
- package/dist/showcase/CursorSpotlight.svelte +85 -0
- package/dist/showcase/CursorSpotlight.svelte.d.ts +9 -0
- package/dist/showcase/DeviceMock.svelte +186 -0
- package/dist/showcase/DeviceMock.svelte.d.ts +11 -0
- package/dist/showcase/Dock.svelte +123 -0
- package/dist/showcase/Dock.svelte.d.ts +17 -0
- package/dist/showcase/FlipCard.svelte +103 -0
- package/dist/showcase/FlipCard.svelte.d.ts +10 -0
- package/dist/showcase/FocusReveal.svelte +83 -0
- package/dist/showcase/FocusReveal.svelte.d.ts +11 -0
- package/dist/showcase/Globe.svelte +202 -0
- package/dist/showcase/Globe.svelte.d.ts +16 -0
- package/dist/showcase/KenBurns.svelte +105 -0
- package/dist/showcase/KenBurns.svelte.d.ts +13 -0
- package/dist/showcase/Marquee.svelte +89 -0
- package/dist/showcase/Marquee.svelte.d.ts +9 -0
- package/dist/showcase/ParallaxTilt.svelte +98 -0
- package/dist/showcase/ParallaxTilt.svelte.d.ts +10 -0
- package/dist/showcase/ScrambleText.svelte +98 -0
- package/dist/showcase/ScrambleText.svelte.d.ts +11 -0
- package/dist/showcase/ShineSweep.svelte +81 -0
- package/dist/showcase/ShineSweep.svelte.d.ts +9 -0
- package/dist/showcase/Terminal.svelte +230 -0
- package/dist/showcase/Terminal.svelte.d.ts +18 -0
- package/dist/showcase/TextSplitReveal.svelte +146 -0
- package/dist/showcase/TextSplitReveal.svelte.d.ts +13 -0
- package/dist/showcase/TextWave.svelte +55 -0
- package/dist/showcase/TextWave.svelte.d.ts +8 -0
- package/dist/showcase/TypewriterText.svelte +130 -0
- package/dist/showcase/TypewriterText.svelte.d.ts +9 -0
- package/dist/showcase/backdrop/GrainGradient.svelte +126 -0
- package/dist/showcase/backdrop/GrainGradient.svelte.d.ts +23 -0
- package/dist/showcase/backdrop/MeshGradient.svelte +104 -0
- package/dist/showcase/backdrop/MeshGradient.svelte.d.ts +20 -0
- package/dist/showcase/backdrop/Metaballs.svelte +116 -0
- package/dist/showcase/backdrop/Metaballs.svelte.d.ts +18 -0
- package/dist/showcase/backdrop/NeuroNoise.svelte +115 -0
- package/dist/showcase/backdrop/NeuroNoise.svelte.d.ts +20 -0
- package/dist/showcase/backdrop/ShowcaseBackdrop.svelte +48 -0
- package/dist/showcase/backdrop/ShowcaseBackdrop.svelte.d.ts +12 -0
- package/dist/showcase/generative/GenerativeBackdrop.svelte +234 -0
- package/dist/showcase/generative/GenerativeBackdrop.svelte.d.ts +9 -0
- package/dist/showcase/generative/intent.d.ts +7 -0
- package/dist/showcase/generative/intent.js +67 -0
- package/dist/showcase/generative/manifest.d.ts +9 -0
- package/dist/showcase/generative/manifest.js +97 -0
- package/dist/showcase/generative/types.d.ts +48 -0
- package/dist/showcase/generative/types.js +8 -0
- package/dist/showcase/index.d.ts +36 -0
- package/dist/showcase/index.js +46 -0
- package/dist/showcase/scroll/SmoothScroll.svelte +49 -0
- package/dist/showcase/scroll/SmoothScroll.svelte.d.ts +12 -0
- package/dist/showcase/scroll/scrollProgress.d.ts +24 -0
- package/dist/showcase/scroll/scrollProgress.js +65 -0
- package/dist/showcase/scroll/scrollReveal.d.ts +30 -0
- package/dist/showcase/scroll/scrollReveal.js +70 -0
- package/dist/stores/commandPalette.svelte.d.ts +24 -0
- package/dist/stores/commandPalette.svelte.js +82 -0
- package/dist/stores/confirmDialog.svelte.js +5 -5
- package/dist/stores/inputDialog.svelte.js +5 -5
- package/dist/stores/toast.svelte.d.ts +28 -0
- package/dist/stores/toast.svelte.js +33 -0
- package/dist/styles/motion.css +46 -0
- package/dist/styles/tokens.css +31 -0
- package/dist/transitions/glide.d.ts +31 -0
- package/dist/transitions/glide.js +58 -0
- package/dist/types/booking.js +4 -4
- package/dist/types/comments.js +2 -2
- package/dist/types/messaging.js +3 -3
- package/dist/types/pipeline.js +2 -2
- package/dist/utils/currency.js +4 -2
- package/dist/utils/daisyuiColors.js +27 -25
- package/dist/utils/dateFormatters.d.ts +20 -0
- package/dist/utils/dateFormatters.js +65 -44
- package/dist/utils/googleMapsLoader.js +100 -46
- package/dist/utils/mentionParser.js +30 -30
- package/dist/utils/phone.js +27 -21
- package/dist/utils/phoneFormat.js +9 -9
- package/dist/utils/sound.d.ts +6 -0
- package/dist/utils/sound.js +113 -0
- package/dist/utils/splitText.d.ts +25 -0
- package/dist/utils/splitText.js +94 -0
- package/dist/utils/taskUtils.js +1 -1
- package/dist/utils/themeWipe.d.ts +21 -0
- package/dist/utils/themeWipe.js +94 -0
- package/dist/utils/viewTransition.d.ts +23 -0
- package/dist/utils/viewTransition.js +75 -0
- package/package.json +56 -4
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import '@xyflow/svelte/dist/style.css'
|
|
3
|
+
|
|
4
|
+
import { SvelteFlow, Background, Controls, MiniMap, type Node, type Edge } from '@xyflow/svelte'
|
|
5
|
+
import JatuiNode from './JatuiNode.svelte'
|
|
6
|
+
import { watchAndApplyTheme } from './theme.js'
|
|
7
|
+
|
|
8
|
+
import type { NodeEventWithPointer } from '@xyflow/svelte'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
/** Flow nodes — bindable for interactive graphs. */
|
|
12
|
+
nodes: Node[]
|
|
13
|
+
/** Flow edges — bindable for interactive graphs. */
|
|
14
|
+
edges: Edge[]
|
|
15
|
+
/** When true, disables pan/zoom/selection interactions. */
|
|
16
|
+
readonly?: boolean
|
|
17
|
+
/** Fit the graph to the viewport on first render. */
|
|
18
|
+
fitView?: boolean
|
|
19
|
+
/** Show the minimap panel. */
|
|
20
|
+
minimap?: boolean
|
|
21
|
+
/** Fired when the user clicks a node. */
|
|
22
|
+
onNodeClick?: NodeEventWithPointer<MouseEvent | TouchEvent>
|
|
23
|
+
/** Height of the canvas container (CSS value). Defaults to 100%. */
|
|
24
|
+
height?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
nodes = $bindable([]),
|
|
29
|
+
edges = $bindable([]),
|
|
30
|
+
readonly = false,
|
|
31
|
+
fitView = true,
|
|
32
|
+
minimap = false,
|
|
33
|
+
onNodeClick,
|
|
34
|
+
height = '100%',
|
|
35
|
+
}: Props = $props()
|
|
36
|
+
|
|
37
|
+
const nodeTypes = { jatuiNode: JatuiNode }
|
|
38
|
+
|
|
39
|
+
let flowEl: HTMLDivElement | null = $state(null)
|
|
40
|
+
let stopWatch: (() => void) | null = null
|
|
41
|
+
|
|
42
|
+
$effect(() => {
|
|
43
|
+
if (!flowEl) return
|
|
44
|
+
stopWatch?.()
|
|
45
|
+
stopWatch = watchAndApplyTheme(flowEl)
|
|
46
|
+
return () => {
|
|
47
|
+
stopWatch?.()
|
|
48
|
+
stopWatch = null
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<div class="graph-canvas" style:height bind:this={flowEl}>
|
|
54
|
+
<SvelteFlow
|
|
55
|
+
{nodes}
|
|
56
|
+
{edges}
|
|
57
|
+
{nodeTypes}
|
|
58
|
+
{fitView}
|
|
59
|
+
nodesDraggable={!readonly}
|
|
60
|
+
nodesConnectable={!readonly}
|
|
61
|
+
elementsSelectable={!readonly}
|
|
62
|
+
panOnDrag={!readonly}
|
|
63
|
+
zoomOnScroll={!readonly}
|
|
64
|
+
onnodeclick={onNodeClick as NodeEventWithPointer<MouseEvent | TouchEvent> | undefined}
|
|
65
|
+
fitViewOptions={{ padding: 0.2 }}
|
|
66
|
+
attributionPosition="bottom-right"
|
|
67
|
+
>
|
|
68
|
+
<Background gap={16} size={1} />
|
|
69
|
+
<Controls showLock={false} />
|
|
70
|
+
{#if minimap}
|
|
71
|
+
<MiniMap />
|
|
72
|
+
{/if}
|
|
73
|
+
</SvelteFlow>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<style>
|
|
77
|
+
.graph-canvas {
|
|
78
|
+
width: 100%;
|
|
79
|
+
position: relative;
|
|
80
|
+
/* Contain the xyflow absolute-positioned layers */
|
|
81
|
+
overflow: hidden;
|
|
82
|
+
border-radius: var(--jatui-radius-box);
|
|
83
|
+
border: var(--jatui-border-w) solid var(--color-base-300, oklch(0.9 0 0));
|
|
84
|
+
background: var(--color-base-100, oklch(0.98 0 0));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Strip xyflow's built-in node box-shadow (house rule: no at-rest shadows) */
|
|
88
|
+
:global(.svelte-flow .svelte-flow__node) {
|
|
89
|
+
box-shadow: none !important;
|
|
90
|
+
filter: none !important;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Edge animation uses opacity+stroke transitions, not layout — allowed */
|
|
94
|
+
:global(.svelte-flow .svelte-flow__edge path) {
|
|
95
|
+
transition: stroke var(--motion-fast) var(--motion-glide);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@media (prefers-reduced-motion: reduce) {
|
|
99
|
+
:global(.svelte-flow .svelte-flow__edge path) {
|
|
100
|
+
transition: none;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import '@xyflow/svelte/dist/style.css';
|
|
2
|
+
import { type Node, type Edge } from '@xyflow/svelte';
|
|
3
|
+
import type { NodeEventWithPointer } from '@xyflow/svelte';
|
|
4
|
+
interface Props {
|
|
5
|
+
/** Flow nodes — bindable for interactive graphs. */
|
|
6
|
+
nodes: Node[];
|
|
7
|
+
/** Flow edges — bindable for interactive graphs. */
|
|
8
|
+
edges: Edge[];
|
|
9
|
+
/** When true, disables pan/zoom/selection interactions. */
|
|
10
|
+
readonly?: boolean;
|
|
11
|
+
/** Fit the graph to the viewport on first render. */
|
|
12
|
+
fitView?: boolean;
|
|
13
|
+
/** Show the minimap panel. */
|
|
14
|
+
minimap?: boolean;
|
|
15
|
+
/** Fired when the user clicks a node. */
|
|
16
|
+
onNodeClick?: NodeEventWithPointer<MouseEvent | TouchEvent>;
|
|
17
|
+
/** Height of the canvas container (CSS value). Defaults to 100%. */
|
|
18
|
+
height?: string;
|
|
19
|
+
}
|
|
20
|
+
declare const GraphCanvas: import("svelte").Component<Props, {}, "nodes" | "edges">;
|
|
21
|
+
type GraphCanvas = ReturnType<typeof GraphCanvas>;
|
|
22
|
+
export default GraphCanvas;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Handle, Position } from '@xyflow/svelte'
|
|
3
|
+
import type { NodeProps } from '@xyflow/svelte'
|
|
4
|
+
import type { NodeStatus } from './theme.js'
|
|
5
|
+
|
|
6
|
+
interface JatuiNodeData {
|
|
7
|
+
label?: string
|
|
8
|
+
status?: NodeStatus
|
|
9
|
+
/** Extra text below the label — e.g. type or description */
|
|
10
|
+
sublabel?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Props = NodeProps & { data: JatuiNodeData }
|
|
14
|
+
|
|
15
|
+
let { data, selected = false, sourcePosition = Position.Bottom, targetPosition = Position.Top }: Props = $props()
|
|
16
|
+
|
|
17
|
+
const STATUS_TINT: Record<NodeStatus, string> = {
|
|
18
|
+
default: '',
|
|
19
|
+
primary: 'bg-primary/10 border-primary text-primary',
|
|
20
|
+
secondary: 'bg-secondary/10 border-secondary text-secondary',
|
|
21
|
+
info: 'bg-info/10 border-info text-info',
|
|
22
|
+
success: 'bg-success/10 border-success text-success',
|
|
23
|
+
warning: 'bg-warning/10 border-warning text-warning',
|
|
24
|
+
error: 'bg-error/10 border-error text-error',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const STATUS_DOT: Record<NodeStatus, string> = {
|
|
28
|
+
default: '',
|
|
29
|
+
primary: 'bg-primary',
|
|
30
|
+
secondary: 'bg-secondary',
|
|
31
|
+
info: 'bg-info',
|
|
32
|
+
success: 'bg-success',
|
|
33
|
+
warning: 'bg-warning',
|
|
34
|
+
error: 'bg-error',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const status = $derived(data?.status ?? 'default')
|
|
38
|
+
const tintClass = $derived(STATUS_TINT[status])
|
|
39
|
+
const dotClass = $derived(STATUS_DOT[status])
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<Handle type="target" position={targetPosition} />
|
|
43
|
+
|
|
44
|
+
<div
|
|
45
|
+
class="jatui-node"
|
|
46
|
+
class:jatui-node--selected={selected}
|
|
47
|
+
class:jatui-node--tinted={status !== 'default'}
|
|
48
|
+
>
|
|
49
|
+
<div class="jatui-node__inner {tintClass}">
|
|
50
|
+
{#if status !== 'default'}
|
|
51
|
+
<span class="jatui-node__dot {dotClass}" aria-hidden="true"></span>
|
|
52
|
+
{/if}
|
|
53
|
+
<span class="jatui-node__label">{data?.label ?? ''}</span>
|
|
54
|
+
{#if data?.sublabel}
|
|
55
|
+
<span class="jatui-node__sublabel">{data.sublabel}</span>
|
|
56
|
+
{/if}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<Handle type="source" position={sourcePosition} />
|
|
61
|
+
|
|
62
|
+
<style>
|
|
63
|
+
.jatui-node {
|
|
64
|
+
min-width: 120px;
|
|
65
|
+
max-width: 240px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.jatui-node__inner {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: var(--jatui-space-sm);
|
|
72
|
+
padding: var(--jatui-space-base) var(--jatui-space-lg);
|
|
73
|
+
background: var(--color-base-200, oklch(0.96 0 0));
|
|
74
|
+
border: var(--jatui-border-w) solid var(--color-base-300, oklch(0.9 0 0));
|
|
75
|
+
border-radius: var(--jatui-radius-box);
|
|
76
|
+
transition:
|
|
77
|
+
border-color var(--motion-fast) var(--motion-glide),
|
|
78
|
+
background var(--motion-fast) var(--motion-glide);
|
|
79
|
+
cursor: default;
|
|
80
|
+
user-select: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* Tinted nodes: bg-X/10 and border-X classes applied via class binding */
|
|
84
|
+
.jatui-node--tinted .jatui-node__inner {
|
|
85
|
+
/* colors come from DaisyUI utility classes in the markup */
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Selected ring — uses primary without shadows (house rule) */
|
|
89
|
+
.jatui-node--selected .jatui-node__inner {
|
|
90
|
+
border-color: var(--color-primary, oklch(0.6 0.2 264));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.jatui-node__dot {
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
width: 6px;
|
|
96
|
+
height: 6px;
|
|
97
|
+
border-radius: 50%;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.jatui-node__label {
|
|
101
|
+
font-size: 0.8125rem; /* 13px */
|
|
102
|
+
font-weight: 500;
|
|
103
|
+
color: var(--color-base-content, currentColor);
|
|
104
|
+
line-height: 1.3;
|
|
105
|
+
word-break: break-word;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Tinted label inherits color from the tint utility class text-* */
|
|
109
|
+
.jatui-node--tinted .jatui-node__inner .jatui-node__label {
|
|
110
|
+
color: inherit;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.jatui-node__sublabel {
|
|
114
|
+
display: block;
|
|
115
|
+
font-size: 0.6875rem; /* 11px */
|
|
116
|
+
color: var(--color-base-content, currentColor);
|
|
117
|
+
opacity: 0.55;
|
|
118
|
+
line-height: 1.3;
|
|
119
|
+
margin-top: 2px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Reduced motion: strip transitions */
|
|
123
|
+
@media (prefers-reduced-motion: reduce) {
|
|
124
|
+
.jatui-node__inner {
|
|
125
|
+
transition: none;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NodeProps } from '@xyflow/svelte';
|
|
2
|
+
import type { NodeStatus } from './theme.js';
|
|
3
|
+
interface JatuiNodeData {
|
|
4
|
+
label?: string;
|
|
5
|
+
status?: NodeStatus;
|
|
6
|
+
/** Extra text below the label — e.g. type or description */
|
|
7
|
+
sublabel?: string;
|
|
8
|
+
}
|
|
9
|
+
type Props = NodeProps & {
|
|
10
|
+
data: JatuiNodeData;
|
|
11
|
+
};
|
|
12
|
+
declare const JatuiNode: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type JatuiNode = ReturnType<typeof JatuiNode>;
|
|
14
|
+
export default JatuiNode;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphCanvas theme bridge — maps DaisyUI --color-* custom properties onto
|
|
3
|
+
* xyflow CSS vars so the graph follows the active DaisyUI theme at runtime.
|
|
4
|
+
*
|
|
5
|
+
* Call applyXyflowTheme(el) after mount and whenever the theme changes.
|
|
6
|
+
* el should be the .svelte-flow wrapper element.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Status colors available for JatuiNode status-tinting.
|
|
10
|
+
* Returns a map of status → resolved CSS color string.
|
|
11
|
+
*/
|
|
12
|
+
export type NodeStatus = 'default' | 'info' | 'success' | 'warning' | 'error' | 'primary' | 'secondary';
|
|
13
|
+
export declare function getStatusColor(status: NodeStatus): {
|
|
14
|
+
bg: string;
|
|
15
|
+
border: string;
|
|
16
|
+
text: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Apply DaisyUI-derived xyflow CSS vars to the flow container element.
|
|
20
|
+
* Safe to call multiple times — just re-sets the vars.
|
|
21
|
+
*/
|
|
22
|
+
export declare function applyXyflowTheme(el: HTMLElement): void;
|
|
23
|
+
/**
|
|
24
|
+
* Setup watcher: re-applies theme whenever DaisyUI theme changes.
|
|
25
|
+
* Returns cleanup fn.
|
|
26
|
+
*/
|
|
27
|
+
export declare function watchAndApplyTheme(el: HTMLElement): () => void;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphCanvas theme bridge — maps DaisyUI --color-* custom properties onto
|
|
3
|
+
* xyflow CSS vars so the graph follows the active DaisyUI theme at runtime.
|
|
4
|
+
*
|
|
5
|
+
* Call applyXyflowTheme(el) after mount and whenever the theme changes.
|
|
6
|
+
* el should be the .svelte-flow wrapper element.
|
|
7
|
+
*/
|
|
8
|
+
import { getDaisyUIColor, watchThemeChanges } from '../../utils/daisyuiColors.js';
|
|
9
|
+
/** All xyflow CSS vars we override, plus the fallback xyflow var they replace. */
|
|
10
|
+
var THEME_MAP = [
|
|
11
|
+
// Edges
|
|
12
|
+
['--xy-edge-stroke', 'var(--color-base-content, #b1b1b7)'],
|
|
13
|
+
['--xy-edge-stroke-selected', 'var(--color-primary, #555)'],
|
|
14
|
+
['--xy-connectionline-stroke', 'var(--color-base-content, #b1b1b7)'],
|
|
15
|
+
// Background canvas
|
|
16
|
+
['--xy-background-color', 'var(--color-base-100, transparent)'],
|
|
17
|
+
['--xy-background-pattern-dots-color', 'var(--color-base-300, #91919a)'],
|
|
18
|
+
['--xy-background-pattern-lines-color', 'var(--color-base-200, #eee)'],
|
|
19
|
+
['--xy-background-pattern-cross-color', 'var(--color-base-300, #e2e2e2)'],
|
|
20
|
+
// Node defaults
|
|
21
|
+
['--xy-node-color', 'var(--color-base-content, #333)'],
|
|
22
|
+
['--xy-node-border', '1px solid var(--color-base-300, #bbb)'],
|
|
23
|
+
['--xy-node-border-selected', '1px solid var(--color-primary, #555)'],
|
|
24
|
+
['--xy-node-background-color', 'var(--color-base-200, #fff)'],
|
|
25
|
+
// Handle
|
|
26
|
+
['--xy-handle-background-color', 'var(--color-base-content, #333)'],
|
|
27
|
+
['--xy-handle-border-color', 'var(--color-base-100, #fff)'],
|
|
28
|
+
// Minimap
|
|
29
|
+
['--xy-minimap-background-color', 'var(--color-base-100, #fff)'],
|
|
30
|
+
['--xy-minimap-mask-background-color', 'color-mix(in oklch, var(--color-base-200, #f0f0f0) 60%, transparent)'],
|
|
31
|
+
['--xy-minimap-node-background-color', 'var(--color-base-200, #e2e2e2)'],
|
|
32
|
+
// Selection box
|
|
33
|
+
['--xy-selection-background-color', 'color-mix(in oklch, var(--color-primary, #6366f1) 10%, transparent)'],
|
|
34
|
+
['--xy-selection-border', '1px dotted color-mix(in oklch, var(--color-primary, #6366f1) 50%, transparent)'],
|
|
35
|
+
// Attribution
|
|
36
|
+
['--xy-attribution-background-color', 'color-mix(in oklch, var(--color-base-100, #fff) 80%, transparent)'],
|
|
37
|
+
];
|
|
38
|
+
export function getStatusColor(status) {
|
|
39
|
+
switch (status) {
|
|
40
|
+
case 'primary':
|
|
41
|
+
return {
|
|
42
|
+
bg: getDaisyUIColor('primary'),
|
|
43
|
+
border: getDaisyUIColor('primary'),
|
|
44
|
+
text: getDaisyUIColor('primary-content'),
|
|
45
|
+
};
|
|
46
|
+
case 'secondary':
|
|
47
|
+
return {
|
|
48
|
+
bg: getDaisyUIColor('secondary'),
|
|
49
|
+
border: getDaisyUIColor('secondary'),
|
|
50
|
+
text: getDaisyUIColor('secondary-content'),
|
|
51
|
+
};
|
|
52
|
+
case 'info':
|
|
53
|
+
return {
|
|
54
|
+
bg: getDaisyUIColor('info'),
|
|
55
|
+
border: getDaisyUIColor('info'),
|
|
56
|
+
text: getDaisyUIColor('info-content'),
|
|
57
|
+
};
|
|
58
|
+
case 'success':
|
|
59
|
+
return {
|
|
60
|
+
bg: getDaisyUIColor('success'),
|
|
61
|
+
border: getDaisyUIColor('success'),
|
|
62
|
+
text: getDaisyUIColor('success-content'),
|
|
63
|
+
};
|
|
64
|
+
case 'warning':
|
|
65
|
+
return {
|
|
66
|
+
bg: getDaisyUIColor('warning'),
|
|
67
|
+
border: getDaisyUIColor('warning'),
|
|
68
|
+
text: getDaisyUIColor('warning-content'),
|
|
69
|
+
};
|
|
70
|
+
case 'error':
|
|
71
|
+
return {
|
|
72
|
+
bg: getDaisyUIColor('error'),
|
|
73
|
+
border: getDaisyUIColor('error'),
|
|
74
|
+
text: getDaisyUIColor('error-content'),
|
|
75
|
+
};
|
|
76
|
+
default:
|
|
77
|
+
return { bg: '', border: '', text: '' };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Apply DaisyUI-derived xyflow CSS vars to the flow container element.
|
|
82
|
+
* Safe to call multiple times — just re-sets the vars.
|
|
83
|
+
*/
|
|
84
|
+
export function applyXyflowTheme(el) {
|
|
85
|
+
for (var _i = 0, THEME_MAP_1 = THEME_MAP; _i < THEME_MAP_1.length; _i++) {
|
|
86
|
+
var prop = THEME_MAP_1[_i][0];
|
|
87
|
+
// We set the vars as CSS custom properties on the element itself.
|
|
88
|
+
// xyflow reads them from .svelte-flow context, so setting on the wrapper is correct.
|
|
89
|
+
var cssVarName = prop.replace('--xy-', '--xy-'); // identity — keep readable
|
|
90
|
+
// Read the DaisyUI value dynamically then set
|
|
91
|
+
var mappedValue = resolveThemeValue(prop);
|
|
92
|
+
el.style.setProperty(cssVarName, mappedValue);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function resolveThemeValue(prop) {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
// Map the xyflow prop name to the DaisyUI color resolution
|
|
98
|
+
var propToColor = {
|
|
99
|
+
'--xy-edge-stroke': function () { return getDaisyUIColor('base-content'); },
|
|
100
|
+
'--xy-edge-stroke-selected': function () { return getDaisyUIColor('primary'); },
|
|
101
|
+
'--xy-connectionline-stroke': function () { return getDaisyUIColor('base-content'); },
|
|
102
|
+
'--xy-background-color': function () { return getDaisyUIColor('base-100'); },
|
|
103
|
+
'--xy-background-pattern-dots-color': function () { return getDaisyUIColor('base-300'); },
|
|
104
|
+
'--xy-background-pattern-lines-color': function () { return getDaisyUIColor('base-200'); },
|
|
105
|
+
'--xy-background-pattern-cross-color': function () { return getDaisyUIColor('base-300'); },
|
|
106
|
+
'--xy-node-color': function () { return getDaisyUIColor('base-content'); },
|
|
107
|
+
'--xy-node-border': function () { return "1px solid ".concat(getDaisyUIColor('base-300')); },
|
|
108
|
+
'--xy-node-border-selected': function () { return "1px solid ".concat(getDaisyUIColor('primary')); },
|
|
109
|
+
'--xy-node-background-color': function () { return getDaisyUIColor('base-200'); },
|
|
110
|
+
'--xy-handle-background-color': function () { return getDaisyUIColor('base-content'); },
|
|
111
|
+
'--xy-handle-border-color': function () { return getDaisyUIColor('base-100'); },
|
|
112
|
+
'--xy-minimap-background-color': function () { return getDaisyUIColor('base-100'); },
|
|
113
|
+
'--xy-minimap-mask-background-color': function () {
|
|
114
|
+
return "color-mix(in oklch, ".concat(getDaisyUIColor('base-200'), " 60%, transparent)");
|
|
115
|
+
},
|
|
116
|
+
'--xy-minimap-node-background-color': function () { return getDaisyUIColor('base-200'); },
|
|
117
|
+
'--xy-selection-background-color': function () {
|
|
118
|
+
return "color-mix(in oklch, ".concat(getDaisyUIColor('primary'), " 10%, transparent)");
|
|
119
|
+
},
|
|
120
|
+
'--xy-selection-border': function () {
|
|
121
|
+
return "1px dotted color-mix(in oklch, ".concat(getDaisyUIColor('primary'), " 50%, transparent)");
|
|
122
|
+
},
|
|
123
|
+
'--xy-attribution-background-color': function () {
|
|
124
|
+
return "color-mix(in oklch, ".concat(getDaisyUIColor('base-100'), " 80%, transparent)");
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
return (_b = (_a = propToColor[prop]) === null || _a === void 0 ? void 0 : _a.call(propToColor)) !== null && _b !== void 0 ? _b : '';
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Setup watcher: re-applies theme whenever DaisyUI theme changes.
|
|
131
|
+
* Returns cleanup fn.
|
|
132
|
+
*/
|
|
133
|
+
export function watchAndApplyTheme(el) {
|
|
134
|
+
applyXyflowTheme(el);
|
|
135
|
+
return watchThemeChanges(function () { return applyXyflowTheme(el); });
|
|
136
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Markup drawing primitives for construction drawing redlining
|
|
2
2
|
// Adapted from JAT feedback annotation engine with cloud bubble tool added
|
|
3
|
-
export
|
|
3
|
+
export var MARKUP_COLORS = [
|
|
4
4
|
"#ef4444",
|
|
5
5
|
"#eab308",
|
|
6
6
|
"#22c55e",
|
|
@@ -8,13 +8,13 @@ export const MARKUP_COLORS = [
|
|
|
8
8
|
"#ffffff",
|
|
9
9
|
"#111827",
|
|
10
10
|
];
|
|
11
|
-
export
|
|
12
|
-
|
|
11
|
+
export var DEFAULT_STROKE_WIDTH = 3;
|
|
12
|
+
var _nextId = 1;
|
|
13
13
|
export function nextShapeId() {
|
|
14
14
|
return _nextId++;
|
|
15
15
|
}
|
|
16
16
|
function drawArrow(ctx, shape) {
|
|
17
|
-
|
|
17
|
+
var start = shape.start, end = shape.end, color = shape.color, strokeWidth = shape.strokeWidth;
|
|
18
18
|
ctx.strokeStyle = color;
|
|
19
19
|
ctx.lineWidth = strokeWidth;
|
|
20
20
|
ctx.lineCap = "round";
|
|
@@ -24,9 +24,9 @@ function drawArrow(ctx, shape) {
|
|
|
24
24
|
ctx.lineTo(end.x, end.y);
|
|
25
25
|
ctx.stroke();
|
|
26
26
|
// Arrowhead
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
var angle = Math.atan2(end.y - start.y, end.x - start.x);
|
|
28
|
+
var headLen = 14;
|
|
29
|
+
var headAngle = Math.PI / 7;
|
|
30
30
|
ctx.beginPath();
|
|
31
31
|
ctx.moveTo(end.x, end.y);
|
|
32
32
|
ctx.lineTo(end.x - headLen * Math.cos(angle - headAngle), end.y - headLen * Math.sin(angle - headAngle));
|
|
@@ -35,24 +35,24 @@ function drawArrow(ctx, shape) {
|
|
|
35
35
|
ctx.stroke();
|
|
36
36
|
}
|
|
37
37
|
function drawRectangle(ctx, shape) {
|
|
38
|
-
|
|
38
|
+
var start = shape.start, end = shape.end, color = shape.color, strokeWidth = shape.strokeWidth;
|
|
39
39
|
ctx.strokeStyle = color;
|
|
40
40
|
ctx.lineWidth = strokeWidth;
|
|
41
41
|
ctx.lineJoin = "round";
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
var x = Math.min(start.x, end.x);
|
|
43
|
+
var y = Math.min(start.y, end.y);
|
|
44
|
+
var w = Math.abs(end.x - start.x);
|
|
45
|
+
var h = Math.abs(end.y - start.y);
|
|
46
46
|
ctx.strokeRect(x, y, w, h);
|
|
47
47
|
}
|
|
48
48
|
function drawEllipse(ctx, shape) {
|
|
49
|
-
|
|
49
|
+
var start = shape.start, end = shape.end, color = shape.color, strokeWidth = shape.strokeWidth;
|
|
50
50
|
ctx.strokeStyle = color;
|
|
51
51
|
ctx.lineWidth = strokeWidth;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
var cx = (start.x + end.x) / 2;
|
|
53
|
+
var cy = (start.y + end.y) / 2;
|
|
54
|
+
var rx = Math.abs(end.x - start.x) / 2;
|
|
55
|
+
var ry = Math.abs(end.y - start.y) / 2;
|
|
56
56
|
if (rx < 1 || ry < 1)
|
|
57
57
|
return;
|
|
58
58
|
ctx.beginPath();
|
|
@@ -64,51 +64,53 @@ function drawEllipse(ctx, shape) {
|
|
|
64
64
|
* Standard construction markup tool for highlighting areas of change.
|
|
65
65
|
*/
|
|
66
66
|
function drawCloud(ctx, shape) {
|
|
67
|
-
|
|
67
|
+
var start = shape.start, end = shape.end, color = shape.color, strokeWidth = shape.strokeWidth;
|
|
68
68
|
ctx.strokeStyle = color;
|
|
69
69
|
ctx.lineWidth = strokeWidth;
|
|
70
70
|
ctx.lineCap = "round";
|
|
71
71
|
ctx.lineJoin = "round";
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
var x = Math.min(start.x, end.x);
|
|
73
|
+
var y = Math.min(start.y, end.y);
|
|
74
|
+
var w = Math.abs(end.x - start.x);
|
|
75
|
+
var h = Math.abs(end.y - start.y);
|
|
76
76
|
if (w < 4 || h < 4)
|
|
77
77
|
return;
|
|
78
78
|
// Generate perimeter points, then draw arcs between them
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
var arcSize = Math.min(w, h, 30); // arc diameter adapts to shape size
|
|
80
|
+
var perimeter = 2 * (w + h);
|
|
81
|
+
var numArcs = Math.max(8, Math.round(perimeter / arcSize));
|
|
82
82
|
// Collect points along the rectangle perimeter
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
var points = [];
|
|
84
|
+
var segLengths = [w, h, w, h];
|
|
85
|
+
var segDirs = [
|
|
86
86
|
{ dx: 1, dy: 0 },
|
|
87
87
|
{ dx: 0, dy: 1 },
|
|
88
88
|
{ dx: -1, dy: 0 },
|
|
89
89
|
{ dx: 0, dy: -1 },
|
|
90
90
|
];
|
|
91
|
-
|
|
92
|
-
{ x, y },
|
|
93
|
-
{ x: x + w, y },
|
|
91
|
+
var segStarts = [
|
|
92
|
+
{ x: x, y: y },
|
|
93
|
+
{ x: x + w, y: y },
|
|
94
94
|
{ x: x + w, y: y + h },
|
|
95
|
-
{ x, y: y + h },
|
|
95
|
+
{ x: x, y: y + h },
|
|
96
96
|
];
|
|
97
|
-
|
|
98
|
-
for (
|
|
97
|
+
var totalLen = 0;
|
|
98
|
+
for (var _i = 0, segLengths_1 = segLengths; _i < segLengths_1.length; _i++) {
|
|
99
|
+
var l = segLengths_1[_i];
|
|
99
100
|
totalLen += l;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
}
|
|
102
|
+
var step = totalLen / numArcs;
|
|
103
|
+
var dist = 0;
|
|
104
|
+
var segIdx = 0;
|
|
105
|
+
var segDist = 0;
|
|
106
|
+
for (var i = 0; i < numArcs; i++) {
|
|
107
|
+
var target = i * step;
|
|
106
108
|
while (dist + segLengths[segIdx] - segDist < target && segIdx < 3) {
|
|
107
109
|
dist += segLengths[segIdx] - segDist;
|
|
108
110
|
segIdx++;
|
|
109
111
|
segDist = 0;
|
|
110
112
|
}
|
|
111
|
-
|
|
113
|
+
var remaining = target - dist;
|
|
112
114
|
points.push({
|
|
113
115
|
x: segStarts[segIdx].x + segDirs[segIdx].dx * (segDist + remaining),
|
|
114
116
|
y: segStarts[segIdx].y + segDirs[segIdx].dy * (segDist + remaining),
|
|
@@ -116,20 +118,20 @@ function drawCloud(ctx, shape) {
|
|
|
116
118
|
}
|
|
117
119
|
// Draw arcs between consecutive points
|
|
118
120
|
ctx.beginPath();
|
|
119
|
-
for (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
for (var i = 0; i < points.length; i++) {
|
|
122
|
+
var p1 = points[i];
|
|
123
|
+
var p2 = points[(i + 1) % points.length];
|
|
124
|
+
var mx = (p1.x + p2.x) / 2;
|
|
125
|
+
var my = (p1.y + p2.y) / 2;
|
|
124
126
|
// Bulge outward from center of rectangle
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
var cx = x + w / 2;
|
|
128
|
+
var cy = y + h / 2;
|
|
129
|
+
var dx = mx - cx;
|
|
130
|
+
var dy = my - cy;
|
|
131
|
+
var len = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
132
|
+
var bulge = arcSize * 0.35;
|
|
133
|
+
var ctrlX = mx + (dx / len) * bulge;
|
|
134
|
+
var ctrlY = my + (dy / len) * bulge;
|
|
133
135
|
if (i === 0) {
|
|
134
136
|
ctx.moveTo(p1.x, p1.y);
|
|
135
137
|
}
|
|
@@ -139,7 +141,7 @@ function drawCloud(ctx, shape) {
|
|
|
139
141
|
ctx.stroke();
|
|
140
142
|
}
|
|
141
143
|
function drawFreehand(ctx, shape) {
|
|
142
|
-
|
|
144
|
+
var points = shape.points, color = shape.color, strokeWidth = shape.strokeWidth;
|
|
143
145
|
if (points.length < 2)
|
|
144
146
|
return;
|
|
145
147
|
ctx.strokeStyle = color;
|
|
@@ -148,16 +150,16 @@ function drawFreehand(ctx, shape) {
|
|
|
148
150
|
ctx.lineJoin = "round";
|
|
149
151
|
ctx.beginPath();
|
|
150
152
|
ctx.moveTo(points[0].x, points[0].y);
|
|
151
|
-
for (
|
|
153
|
+
for (var i = 1; i < points.length; i++) {
|
|
152
154
|
ctx.lineTo(points[i].x, points[i].y);
|
|
153
155
|
}
|
|
154
156
|
ctx.stroke();
|
|
155
157
|
}
|
|
156
158
|
function drawText(ctx, shape) {
|
|
157
|
-
|
|
159
|
+
var position = shape.position, content = shape.content, color = shape.color, fontSize = shape.fontSize;
|
|
158
160
|
if (!content)
|
|
159
161
|
return;
|
|
160
|
-
ctx.font =
|
|
162
|
+
ctx.font = "bold ".concat(fontSize, "px sans-serif");
|
|
161
163
|
ctx.textBaseline = "top";
|
|
162
164
|
// Black outline for contrast on construction drawings
|
|
163
165
|
ctx.strokeStyle = "#000000";
|
|
@@ -192,7 +194,8 @@ export function renderShape(ctx, shape) {
|
|
|
192
194
|
ctx.restore();
|
|
193
195
|
}
|
|
194
196
|
export function renderAllShapes(ctx, shapes) {
|
|
195
|
-
for (
|
|
197
|
+
for (var _i = 0, shapes_1 = shapes; _i < shapes_1.length; _i++) {
|
|
198
|
+
var shape = shapes_1[_i];
|
|
196
199
|
renderShape(ctx, shape);
|
|
197
200
|
}
|
|
198
201
|
}
|