@docentjs/dom 0.4.0 → 0.5.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @docentjs/dom
2
2
 
3
- Web renderer for [Docent](https://github.com/FgrReloaded/docentjs), a guided product tour library. Overlay with a rounded spotlight, custom positioning, an accessible popover in a Shadow Root, keyboard and focus handling, a mobile bottom sheet, and a customization layer with theme tokens, slots, templates and headless mode. About 11 kB compressed including the core.
3
+ Web renderer for [Docent](https://github.com/FgrReloaded/docentjs), a guided product tour library. Overlay with a rounded spotlight, custom positioning, an accessible popover in a Shadow Root, keyboard and focus handling, a mobile bottom sheet, and a customization layer with theme tokens, slots, templates and headless mode. About 13 kB compressed including the core.
4
4
 
5
5
  ```sh
6
6
  pnpm add @docentjs/dom
@@ -53,6 +53,23 @@ createTour(tour, {
53
53
 
54
54
  Tours can also carry `options.theme` and `options.template` in their JSON.
55
55
 
56
+ ## Arrows, spotlight and overlay
57
+
58
+ ```ts
59
+ defineTour({
60
+ id: 'welcome',
61
+ options: {
62
+ arrow: 'curve', // caret, none, line, dashed, dotted, curve,
63
+ // curve-dashed, squiggle, loop, elbow, sketch, pin
64
+ spotlight: { shape: 'pill', ring: 'pulse' }, // rounded, rect, pill, circle / hairline, none, glow, pulse, dashed, solid
65
+ overlay: { style: 'blur', blur: 6 }, // dim, blur, vignette, none
66
+ },
67
+ steps: [{ id: 'save', target: '#save', title: 'Save', arrow: 'pin' }], // or per step
68
+ })
69
+ ```
70
+
71
+ The default is a small caret, a rounded spotlight with a hairline ring, and a dimmed page. Drawn arrows load on first use as a separate 1.8 kB chunk, so tours that keep the caret never download them.
72
+
56
73
  ## Also
57
74
 
58
75
  - `createLocalStorage()` persistence adapter.
@@ -0,0 +1,25 @@
1
+ //#region src/arrows.ts
2
+ const CONNECTOR_STYLES = [
3
+ "line",
4
+ "dashed",
5
+ "dotted",
6
+ "curve",
7
+ "curve-dashed",
8
+ "squiggle",
9
+ "loop",
10
+ "elbow",
11
+ "sketch",
12
+ "pin"
13
+ ];
14
+ function isConnector(style) {
15
+ return CONNECTOR_STYLES.includes(style);
16
+ }
17
+ /** Space between target and popover for a style: connectors need room to be seen. */
18
+ function arrowGap(style) {
19
+ if (!isConnector(style)) return 12;
20
+ return style === "loop" || style === "squiggle" ? 72 : 60;
21
+ }
22
+ //#endregion
23
+ export { arrowGap as n, isConnector as r, CONNECTOR_STYLES as t };
24
+
25
+ //# sourceMappingURL=arrows-Dcnwi9T-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrows-Dcnwi9T-.js","names":[],"sources":["../src/arrows.ts"],"sourcesContent":["/**\n * Arrow style names and spacing. Tiny and always loaded; the drawing code for\n * connector styles (connector.ts) is loaded only when a tour uses one.\n */\n\nimport type { ArrowStyle } from '@docentjs/core'\n\nexport const CONNECTOR_STYLES = [\n 'line',\n 'dashed',\n 'dotted',\n 'curve',\n 'curve-dashed',\n 'squiggle',\n 'loop',\n 'elbow',\n 'sketch',\n 'pin',\n] as const satisfies readonly ArrowStyle[]\n\nexport type ConnectorStyle = (typeof CONNECTOR_STYLES)[number]\n\nexport function isConnector(style: ArrowStyle): style is ConnectorStyle {\n return (CONNECTOR_STYLES as readonly string[]).includes(style)\n}\n\n/** Space between target and popover for a style: connectors need room to be seen. */\nexport function arrowGap(style: ArrowStyle): number {\n if (!isConnector(style)) return 12\n return style === 'loop' || style === 'squiggle' ? 72 : 60\n}\n"],"mappings":";AAOA,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAIA,SAAgB,YAAY,OAA4C;CACtE,OAAQ,iBAAuC,SAAS,KAAK;AAC/D;;AAGA,SAAgB,SAAS,OAA2B;CAClD,IAAI,CAAC,YAAY,KAAK,GAAG,OAAO;CAChC,OAAO,UAAU,UAAU,UAAU,aAAa,KAAK;AACzD"}
@@ -0,0 +1,42 @@
1
+ //#region src/arrows.ts
2
+ const CONNECTOR_STYLES = [
3
+ "line",
4
+ "dashed",
5
+ "dotted",
6
+ "curve",
7
+ "curve-dashed",
8
+ "squiggle",
9
+ "loop",
10
+ "elbow",
11
+ "sketch",
12
+ "pin"
13
+ ];
14
+ function isConnector(style) {
15
+ return CONNECTOR_STYLES.includes(style);
16
+ }
17
+ /** Space between target and popover for a style: connectors need room to be seen. */
18
+ function arrowGap(style) {
19
+ if (!isConnector(style)) return 12;
20
+ return style === "loop" || style === "squiggle" ? 72 : 60;
21
+ }
22
+ //#endregion
23
+ Object.defineProperty(exports, "CONNECTOR_STYLES", {
24
+ enumerable: true,
25
+ get: function() {
26
+ return CONNECTOR_STYLES;
27
+ }
28
+ });
29
+ Object.defineProperty(exports, "arrowGap", {
30
+ enumerable: true,
31
+ get: function() {
32
+ return arrowGap;
33
+ }
34
+ });
35
+ Object.defineProperty(exports, "isConnector", {
36
+ enumerable: true,
37
+ get: function() {
38
+ return isConnector;
39
+ }
40
+ });
41
+
42
+ //# sourceMappingURL=arrows-DdDu3O3y.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrows-DdDu3O3y.cjs","names":[],"sources":["../src/arrows.ts"],"sourcesContent":["/**\n * Arrow style names and spacing. Tiny and always loaded; the drawing code for\n * connector styles (connector.ts) is loaded only when a tour uses one.\n */\n\nimport type { ArrowStyle } from '@docentjs/core'\n\nexport const CONNECTOR_STYLES = [\n 'line',\n 'dashed',\n 'dotted',\n 'curve',\n 'curve-dashed',\n 'squiggle',\n 'loop',\n 'elbow',\n 'sketch',\n 'pin',\n] as const satisfies readonly ArrowStyle[]\n\nexport type ConnectorStyle = (typeof CONNECTOR_STYLES)[number]\n\nexport function isConnector(style: ArrowStyle): style is ConnectorStyle {\n return (CONNECTOR_STYLES as readonly string[]).includes(style)\n}\n\n/** Space between target and popover for a style: connectors need room to be seen. */\nexport function arrowGap(style: ArrowStyle): number {\n if (!isConnector(style)) return 12\n return style === 'loop' || style === 'squiggle' ? 72 : 60\n}\n"],"mappings":";AAOA,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAIA,SAAgB,YAAY,OAA4C;CACtE,OAAQ,iBAAuC,SAAS,KAAK;AAC/D;;AAGA,SAAgB,SAAS,OAA2B;CAClD,IAAI,CAAC,YAAY,KAAK,GAAG,OAAO;CAChC,OAAO,UAAU,UAAU,UAAU,aAAa,KAAK;AACzD"}
@@ -0,0 +1,249 @@
1
+ import { n as arrowGap, r as isConnector, t as CONNECTOR_STYLES } from "./arrows-Dcnwi9T-.js";
2
+ //#region src/connector.ts
3
+ const r = (n) => Math.round(n * 10) / 10;
4
+ const pt = (p) => `${r(p.x)} ${r(p.y)}`;
5
+ function frame(a, b) {
6
+ const dx = b.x - a.x;
7
+ const dy = b.y - a.y;
8
+ const length = Math.hypot(dx, dy) || 1;
9
+ const u = {
10
+ x: dx / length,
11
+ y: dy / length
12
+ };
13
+ const n = {
14
+ x: -u.y,
15
+ y: u.x
16
+ };
17
+ const at = (along, across) => ({
18
+ x: a.x + u.x * along + n.x * across,
19
+ y: a.y + u.y * along + n.y * across
20
+ });
21
+ return {
22
+ length,
23
+ u,
24
+ n,
25
+ at
26
+ };
27
+ }
28
+ function polyline(points) {
29
+ return points.map((p, i) => `${i ? "L" : "M"}${pt(p)}`).join("");
30
+ }
31
+ /** Open chevron at `tip`, pointing along `dir` (unit vector). */
32
+ function arrowHead(tip, dir, size = 7) {
33
+ const angle = .5;
34
+ const back = (s) => ({
35
+ x: tip.x - size * (dir.x * Math.cos(angle) - s * dir.y * Math.sin(angle)),
36
+ y: tip.y - size * (dir.y * Math.cos(angle) + s * dir.x * Math.sin(angle))
37
+ });
38
+ return `M${pt(back(1))}L${pt(tip)}L${pt(back(-1))}`;
39
+ }
40
+ function unit(from, to) {
41
+ const l = Math.hypot(to.x - from.x, to.y - from.y) || 1;
42
+ return {
43
+ x: (to.x - from.x) / l,
44
+ y: (to.y - from.y) / l
45
+ };
46
+ }
47
+ /** Polyline with rounded interior corners. */
48
+ function rounded(points, radius) {
49
+ let d = `M${pt(points[0])}`;
50
+ for (let i = 1; i < points.length - 1; i++) {
51
+ const p = points[i];
52
+ const prev = points[i - 1];
53
+ const next = points[i + 1];
54
+ const inLen = Math.hypot(p.x - prev.x, p.y - prev.y);
55
+ const outLen = Math.hypot(next.x - p.x, next.y - p.y);
56
+ const c = Math.min(radius, inLen / 2, outLen / 2);
57
+ const a = unit(p, prev);
58
+ const b = unit(p, next);
59
+ d += `L${pt({
60
+ x: p.x + a.x * c,
61
+ y: p.y + a.y * c
62
+ })}Q${pt(p)} ${pt({
63
+ x: p.x + b.x * c,
64
+ y: p.y + b.y * c
65
+ })}`;
66
+ }
67
+ return `${d}L${pt(points[points.length - 1])}`;
68
+ }
69
+ /**
70
+ * Paths for a connector from `from` (popover edge) to `to` (just outside the
71
+ * target). `bend` flips curves to the other side (1 or -1).
72
+ */
73
+ function connectorShape(style, from, to, bend = 1) {
74
+ const f = frame(from, to);
75
+ const L = f.length;
76
+ const straight = `M${pt(from)}L${pt(to)}`;
77
+ const head = (dir) => arrowHead(to, dir);
78
+ switch (style) {
79
+ case "line": return {
80
+ paths: [{ d: straight }],
81
+ head: head(f.u)
82
+ };
83
+ case "dashed": return {
84
+ paths: [{
85
+ d: straight,
86
+ dash: "5 5"
87
+ }],
88
+ head: head(f.u)
89
+ };
90
+ case "dotted": return {
91
+ paths: [{
92
+ d: straight,
93
+ dash: "0 6",
94
+ width: 2.4
95
+ }],
96
+ head: head(f.u)
97
+ };
98
+ case "curve":
99
+ case "curve-dashed": {
100
+ const c = f.at(L / 2, bend * L * .32);
101
+ const path = { d: `M${pt(from)}Q${pt(c)} ${pt(to)}` };
102
+ if (style === "curve-dashed") path.dash = "5 5";
103
+ return {
104
+ paths: [path],
105
+ head: head(unit(c, to))
106
+ };
107
+ }
108
+ case "squiggle": {
109
+ const steps = Math.max(24, Math.round(L / 2));
110
+ const wave = 15;
111
+ const points = [];
112
+ for (let i = 0; i <= steps; i++) {
113
+ const t = i / steps;
114
+ const envelope = Math.min(1, t * 5, (1 - t) * 5);
115
+ points.push(f.at(L * t, bend * 4.5 * envelope * Math.sin(2 * Math.PI * L * t / wave)));
116
+ }
117
+ return {
118
+ paths: [{ d: polyline(points) }],
119
+ head: head(unit(points[points.length - 3], to))
120
+ };
121
+ }
122
+ case "loop": {
123
+ const R = Math.min(22, Math.max(9, L / 5.5));
124
+ const steps = 48;
125
+ const points = [];
126
+ for (let i = 0; i <= steps; i++) {
127
+ const t = i / steps;
128
+ points.push(f.at(L * t - R * Math.sin(2 * Math.PI * t), bend * .75 * R * (1 - Math.cos(2 * Math.PI * t))));
129
+ }
130
+ return {
131
+ paths: [{ d: polyline(points) }],
132
+ head: head(unit(points[points.length - 3], to))
133
+ };
134
+ }
135
+ case "elbow": {
136
+ const dx = to.x - from.x;
137
+ const dy = to.y - from.y;
138
+ if (Math.abs(dx) < 6 || Math.abs(dy) < 6) return {
139
+ paths: [{ d: straight }],
140
+ head: head(f.u)
141
+ };
142
+ const points = Math.abs(dy) >= Math.abs(dx) ? [
143
+ from,
144
+ {
145
+ x: from.x,
146
+ y: from.y + dy / 2
147
+ },
148
+ {
149
+ x: to.x,
150
+ y: from.y + dy / 2
151
+ },
152
+ to
153
+ ] : [
154
+ from,
155
+ {
156
+ x: from.x + dx / 2,
157
+ y: from.y
158
+ },
159
+ {
160
+ x: from.x + dx / 2,
161
+ y: to.y
162
+ },
163
+ to
164
+ ];
165
+ return {
166
+ paths: [{ d: rounded(points, 10) }],
167
+ head: head(unit(points[2], to))
168
+ };
169
+ }
170
+ case "sketch": {
171
+ const c1 = f.at(L * .45, bend * L * .12);
172
+ const c2 = f.at(L * .55, bend * L * .04 - 3);
173
+ const start2 = f.at(2, 2);
174
+ const end2 = {
175
+ x: to.x + f.n.x * 2,
176
+ y: to.y + f.n.y * 2
177
+ };
178
+ return {
179
+ paths: [{ d: `M${pt(from)}Q${pt(c1)} ${pt(to)}` }, {
180
+ d: `M${pt(start2)}Q${pt(c2)} ${pt(end2)}`,
181
+ opacity: .55,
182
+ width: 1.2
183
+ }],
184
+ head: `${head(unit(c1, to))}${arrowHead(end2, unit(c2, end2), 6.5)}`
185
+ };
186
+ }
187
+ case "pin": {
188
+ const end = f.at(Math.max(0, L - 4), 0);
189
+ return {
190
+ paths: [{
191
+ d: `M${pt(from)}L${pt(end)}`,
192
+ dash: "0 5",
193
+ width: 2.2
194
+ }],
195
+ dot: to
196
+ };
197
+ }
198
+ }
199
+ }
200
+ /** Styles for the connector layer, injected into the shadow root when first used. */
201
+ const CONNECTOR_STYLES_CSS = `.connector{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;color:var(--docent-connector,oklch(98% 0.004 285 / 0.92))}:host([data-overlay="none"]) .connector{color:var(--docent-connector,var(--docent-accent))}.connector .stroke{fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.connector .dot{fill:currentColor}.connector .dot-halo{fill:currentColor;opacity:0.2}.connector.animate .draw{stroke-dasharray:1;stroke-dashoffset:1;animation:docent-draw calc(var(--docent-duration) * 1.6) var(--docent-easing) var(--docent-duration) forwards}.connector.animate .fade,.connector.animate .head{opacity:0;animation:docent-fade var(--docent-duration) ease-out calc(var(--docent-duration) * 1.6) forwards}@keyframes docent-draw{to{stroke-dashoffset:0}}@keyframes docent-fade{to{opacity:1}}@media (prefers-reduced-motion:reduce){.connector.animate .draw,.connector.animate .fade,.connector.animate .head{animation:none;stroke-dashoffset:0;opacity:1}}`;
202
+ const SVG_NS = "http://www.w3.org/2000/svg";
203
+ /** SVG layer in the shadow root that draws the current connector. */
204
+ var Connector = class {
205
+ el;
206
+ doc;
207
+ constructor(doc) {
208
+ this.doc = doc;
209
+ this.el = doc.createElementNS(SVG_NS, "svg");
210
+ this.el.setAttribute("class", "connector");
211
+ this.el.setAttribute("part", "connector");
212
+ this.el.setAttribute("aria-hidden", "true");
213
+ }
214
+ clear() {
215
+ this.el.replaceChildren();
216
+ }
217
+ /** Draw a shape. `animate` plays the draw-in (after the popover settles). */
218
+ render(shape, animate) {
219
+ const make = (d, cls) => {
220
+ const path = this.doc.createElementNS(SVG_NS, "path");
221
+ path.setAttribute("d", d);
222
+ path.setAttribute("class", cls);
223
+ return path;
224
+ };
225
+ const nodes = shape.paths.map((p) => {
226
+ const path = make(p.d, p.dash ? "stroke fade" : "stroke draw");
227
+ if (p.dash) path.setAttribute("stroke-dasharray", p.dash);
228
+ else path.setAttribute("pathLength", "1");
229
+ if (p.width) path.setAttribute("stroke-width", String(p.width));
230
+ if (p.opacity) path.setAttribute("opacity", String(p.opacity));
231
+ return path;
232
+ });
233
+ if (shape.head) nodes.push(make(shape.head, "stroke head"));
234
+ if (shape.dot) for (const [radius, cls] of [[8, "dot-halo"], [3.5, "dot"]]) {
235
+ const c = this.doc.createElementNS(SVG_NS, "circle");
236
+ c.setAttribute("cx", String(shape.dot.x));
237
+ c.setAttribute("cy", String(shape.dot.y));
238
+ c.setAttribute("r", String(radius));
239
+ c.setAttribute("class", `${cls} head`);
240
+ nodes.push(c);
241
+ }
242
+ this.el.classList.toggle("animate", animate);
243
+ this.el.replaceChildren(...nodes);
244
+ }
245
+ };
246
+ //#endregion
247
+ export { CONNECTOR_STYLES, CONNECTOR_STYLES_CSS, Connector, arrowGap, arrowHead, connectorShape, isConnector };
248
+
249
+ //# sourceMappingURL=connector-CzqD6NJY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector-CzqD6NJY.js","names":[],"sources":["../src/connector.ts"],"sourcesContent":["/**\n * Drawn connectors between the popover and its target: the arrow styles other\n * than the default caret. Geometry is pure (tested without a browser); the\n * Connector class turns it into SVG inside the shadow root.\n */\n\nexport interface Point {\n x: number\n y: number\n}\n\nexport interface ConnectorPath {\n d: string\n /** SVG stroke-dasharray. Dashed paths fade in instead of drawing. */\n dash?: string\n width?: number\n opacity?: number\n}\n\nexport interface ConnectorShape {\n paths: ConnectorPath[]\n /** Arrowhead (open chevron) at the target end. */\n head?: string\n /** Filled dot at the target end (`pin`). */\n dot?: Point\n}\n\nimport type { ConnectorStyle } from './arrows'\n\nexport { arrowGap, CONNECTOR_STYLES, type ConnectorStyle, isConnector } from './arrows'\n\nconst r = (n: number) => Math.round(n * 10) / 10\nconst pt = (p: Point) => `${r(p.x)} ${r(p.y)}`\n\nfunction frame(a: Point, b: Point) {\n const dx = b.x - a.x\n const dy = b.y - a.y\n const length = Math.hypot(dx, dy) || 1\n const u = { x: dx / length, y: dy / length }\n const n = { x: -u.y, y: u.x }\n const at = (along: number, across: number): Point => ({\n x: a.x + u.x * along + n.x * across,\n y: a.y + u.y * along + n.y * across,\n })\n return { length, u, n, at }\n}\n\nfunction polyline(points: Point[]): string {\n return points.map((p, i) => `${i ? 'L' : 'M'}${pt(p)}`).join('')\n}\n\n/** Open chevron at `tip`, pointing along `dir` (unit vector). */\nexport function arrowHead(tip: Point, dir: Point, size = 7): string {\n const angle = 0.5\n const back = (s: number) => ({\n x: tip.x - size * (dir.x * Math.cos(angle) - s * dir.y * Math.sin(angle)),\n y: tip.y - size * (dir.y * Math.cos(angle) + s * dir.x * Math.sin(angle)),\n })\n return `M${pt(back(1))}L${pt(tip)}L${pt(back(-1))}`\n}\n\nfunction unit(from: Point, to: Point): Point {\n const l = Math.hypot(to.x - from.x, to.y - from.y) || 1\n return { x: (to.x - from.x) / l, y: (to.y - from.y) / l }\n}\n\n/** Polyline with rounded interior corners. */\nfunction rounded(points: Point[], radius: number): string {\n let d = `M${pt(points[0] as Point)}`\n for (let i = 1; i < points.length - 1; i++) {\n const p = points[i] as Point\n const prev = points[i - 1] as Point\n const next = points[i + 1] as Point\n const inLen = Math.hypot(p.x - prev.x, p.y - prev.y)\n const outLen = Math.hypot(next.x - p.x, next.y - p.y)\n const c = Math.min(radius, inLen / 2, outLen / 2)\n const a = unit(p, prev)\n const b = unit(p, next)\n d += `L${pt({ x: p.x + a.x * c, y: p.y + a.y * c })}Q${pt(p)} ${pt({ x: p.x + b.x * c, y: p.y + b.y * c })}`\n }\n return `${d}L${pt(points[points.length - 1] as Point)}`\n}\n\n/**\n * Paths for a connector from `from` (popover edge) to `to` (just outside the\n * target). `bend` flips curves to the other side (1 or -1).\n */\nexport function connectorShape(\n style: ConnectorStyle,\n from: Point,\n to: Point,\n bend = 1,\n): ConnectorShape {\n const f = frame(from, to)\n const L = f.length\n const straight = `M${pt(from)}L${pt(to)}`\n const head = (dir: Point) => arrowHead(to, dir)\n\n switch (style) {\n case 'line':\n return { paths: [{ d: straight }], head: head(f.u) }\n case 'dashed':\n return { paths: [{ d: straight, dash: '5 5' }], head: head(f.u) }\n case 'dotted':\n return { paths: [{ d: straight, dash: '0 6', width: 2.4 }], head: head(f.u) }\n case 'curve':\n case 'curve-dashed': {\n const c = f.at(L / 2, bend * L * 0.32)\n const path: ConnectorPath = { d: `M${pt(from)}Q${pt(c)} ${pt(to)}` }\n if (style === 'curve-dashed') path.dash = '5 5'\n return { paths: [path], head: head(unit(c, to)) }\n }\n case 'squiggle': {\n const steps = Math.max(24, Math.round(L / 2))\n const wave = 15\n const points: Point[] = []\n for (let i = 0; i <= steps; i++) {\n const t = i / steps\n const envelope = Math.min(1, t * 5, (1 - t) * 5)\n points.push(f.at(L * t, bend * 4.5 * envelope * Math.sin((2 * Math.PI * L * t) / wave)))\n }\n return {\n paths: [{ d: polyline(points) }],\n head: head(unit(points[points.length - 3] as Point, to)),\n }\n }\n case 'loop': {\n // A prolate cycloid: one small loop, then on to the target.\n const R = Math.min(22, Math.max(9, L / 5.5))\n const steps = 48\n const points: Point[] = []\n for (let i = 0; i <= steps; i++) {\n const t = i / steps\n points.push(\n f.at(\n L * t - R * Math.sin(2 * Math.PI * t),\n bend * 0.75 * R * (1 - Math.cos(2 * Math.PI * t)),\n ),\n )\n }\n return {\n paths: [{ d: polyline(points) }],\n head: head(unit(points[points.length - 3] as Point, to)),\n }\n }\n case 'elbow': {\n const dx = to.x - from.x\n const dy = to.y - from.y\n if (Math.abs(dx) < 6 || Math.abs(dy) < 6) return { paths: [{ d: straight }], head: head(f.u) }\n const vertical = Math.abs(dy) >= Math.abs(dx)\n const points = vertical\n ? [from, { x: from.x, y: from.y + dy / 2 }, { x: to.x, y: from.y + dy / 2 }, to]\n : [from, { x: from.x + dx / 2, y: from.y }, { x: from.x + dx / 2, y: to.y }, to]\n return { paths: [{ d: rounded(points, 10) }], head: head(unit(points[2] as Point, to)) }\n }\n case 'sketch': {\n // Two slightly different strokes read as hand-drawn; deterministic, so it never flickers.\n const c1 = f.at(L * 0.45, bend * L * 0.12)\n const c2 = f.at(L * 0.55, bend * L * 0.04 - 3)\n const start2 = f.at(2, 2)\n const end2 = { x: to.x + f.n.x * 2, y: to.y + f.n.y * 2 }\n return {\n paths: [\n { d: `M${pt(from)}Q${pt(c1)} ${pt(to)}` },\n { d: `M${pt(start2)}Q${pt(c2)} ${pt(end2)}`, opacity: 0.55, width: 1.2 },\n ],\n head: `${head(unit(c1, to))}${arrowHead(end2, unit(c2, end2), 6.5)}`,\n }\n }\n case 'pin': {\n const end = f.at(Math.max(0, L - 4), 0)\n return { paths: [{ d: `M${pt(from)}L${pt(end)}`, dash: '0 5', width: 2.2 }], dot: to }\n }\n }\n}\n\n/** Styles for the connector layer, injected into the shadow root when first used. */\nexport const CONNECTOR_STYLES_CSS = `\n/* Connectors: drawn arrows from the popover to the target. */\n.connector {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n overflow: visible;\n pointer-events: none;\n color: var(--docent-connector, oklch(98% 0.004 285 / 0.92));\n}\n:host([data-overlay=\"none\"]) .connector { color: var(--docent-connector, var(--docent-accent)); }\n.connector .stroke {\n fill: none;\n stroke: currentColor;\n stroke-width: 1.6;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n.connector .dot { fill: currentColor; }\n.connector .dot-halo { fill: currentColor; opacity: 0.2; }\n/* Drawn after the popover settles, so the line never trails it. */\n.connector.animate .draw {\n stroke-dasharray: 1;\n stroke-dashoffset: 1;\n animation: docent-draw calc(var(--docent-duration) * 1.6) var(--docent-easing) var(--docent-duration) forwards;\n}\n.connector.animate .fade,\n.connector.animate .head {\n opacity: 0;\n animation: docent-fade var(--docent-duration) ease-out calc(var(--docent-duration) * 1.6) forwards;\n}\n@keyframes docent-draw { to { stroke-dashoffset: 0; } }\n@keyframes docent-fade { to { opacity: 1; } }\n@media (prefers-reduced-motion: reduce) {\n .connector.animate .draw, .connector.animate .fade, .connector.animate .head { animation: none; stroke-dashoffset: 0; opacity: 1; }\n}\n`\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\n\n/** SVG layer in the shadow root that draws the current connector. */\nexport class Connector {\n readonly el: SVGSVGElement\n private readonly doc: Document\n\n constructor(doc: Document) {\n this.doc = doc\n this.el = doc.createElementNS(SVG_NS, 'svg')\n this.el.setAttribute('class', 'connector')\n this.el.setAttribute('part', 'connector')\n this.el.setAttribute('aria-hidden', 'true')\n }\n\n clear(): void {\n this.el.replaceChildren()\n }\n\n /** Draw a shape. `animate` plays the draw-in (after the popover settles). */\n render(shape: ConnectorShape, animate: boolean): void {\n const make = (d: string, cls: string) => {\n const path = this.doc.createElementNS(SVG_NS, 'path')\n path.setAttribute('d', d)\n path.setAttribute('class', cls)\n return path\n }\n const nodes: SVGElement[] = shape.paths.map((p) => {\n const path = make(p.d, p.dash ? 'stroke fade' : 'stroke draw')\n if (p.dash) path.setAttribute('stroke-dasharray', p.dash)\n // Solid strokes draw on by animating a normalised dash.\n else path.setAttribute('pathLength', '1')\n if (p.width) path.setAttribute('stroke-width', String(p.width))\n if (p.opacity) path.setAttribute('opacity', String(p.opacity))\n return path\n })\n if (shape.head) nodes.push(make(shape.head, 'stroke head'))\n if (shape.dot) {\n for (const [radius, cls] of [\n [8, 'dot-halo'],\n [3.5, 'dot'],\n ] as const) {\n const c = this.doc.createElementNS(SVG_NS, 'circle')\n c.setAttribute('cx', String(shape.dot.x))\n c.setAttribute('cy', String(shape.dot.y))\n c.setAttribute('r', String(radius))\n c.setAttribute('class', `${cls} head`)\n nodes.push(c)\n }\n }\n this.el.classList.toggle('animate', animate)\n this.el.replaceChildren(...nodes)\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,255 @@
1
+ const require_arrows = require("./arrows-DdDu3O3y.cjs");
2
+ //#region src/connector.ts
3
+ const r = (n) => Math.round(n * 10) / 10;
4
+ const pt = (p) => `${r(p.x)} ${r(p.y)}`;
5
+ function frame(a, b) {
6
+ const dx = b.x - a.x;
7
+ const dy = b.y - a.y;
8
+ const length = Math.hypot(dx, dy) || 1;
9
+ const u = {
10
+ x: dx / length,
11
+ y: dy / length
12
+ };
13
+ const n = {
14
+ x: -u.y,
15
+ y: u.x
16
+ };
17
+ const at = (along, across) => ({
18
+ x: a.x + u.x * along + n.x * across,
19
+ y: a.y + u.y * along + n.y * across
20
+ });
21
+ return {
22
+ length,
23
+ u,
24
+ n,
25
+ at
26
+ };
27
+ }
28
+ function polyline(points) {
29
+ return points.map((p, i) => `${i ? "L" : "M"}${pt(p)}`).join("");
30
+ }
31
+ /** Open chevron at `tip`, pointing along `dir` (unit vector). */
32
+ function arrowHead(tip, dir, size = 7) {
33
+ const angle = .5;
34
+ const back = (s) => ({
35
+ x: tip.x - size * (dir.x * Math.cos(angle) - s * dir.y * Math.sin(angle)),
36
+ y: tip.y - size * (dir.y * Math.cos(angle) + s * dir.x * Math.sin(angle))
37
+ });
38
+ return `M${pt(back(1))}L${pt(tip)}L${pt(back(-1))}`;
39
+ }
40
+ function unit(from, to) {
41
+ const l = Math.hypot(to.x - from.x, to.y - from.y) || 1;
42
+ return {
43
+ x: (to.x - from.x) / l,
44
+ y: (to.y - from.y) / l
45
+ };
46
+ }
47
+ /** Polyline with rounded interior corners. */
48
+ function rounded(points, radius) {
49
+ let d = `M${pt(points[0])}`;
50
+ for (let i = 1; i < points.length - 1; i++) {
51
+ const p = points[i];
52
+ const prev = points[i - 1];
53
+ const next = points[i + 1];
54
+ const inLen = Math.hypot(p.x - prev.x, p.y - prev.y);
55
+ const outLen = Math.hypot(next.x - p.x, next.y - p.y);
56
+ const c = Math.min(radius, inLen / 2, outLen / 2);
57
+ const a = unit(p, prev);
58
+ const b = unit(p, next);
59
+ d += `L${pt({
60
+ x: p.x + a.x * c,
61
+ y: p.y + a.y * c
62
+ })}Q${pt(p)} ${pt({
63
+ x: p.x + b.x * c,
64
+ y: p.y + b.y * c
65
+ })}`;
66
+ }
67
+ return `${d}L${pt(points[points.length - 1])}`;
68
+ }
69
+ /**
70
+ * Paths for a connector from `from` (popover edge) to `to` (just outside the
71
+ * target). `bend` flips curves to the other side (1 or -1).
72
+ */
73
+ function connectorShape(style, from, to, bend = 1) {
74
+ const f = frame(from, to);
75
+ const L = f.length;
76
+ const straight = `M${pt(from)}L${pt(to)}`;
77
+ const head = (dir) => arrowHead(to, dir);
78
+ switch (style) {
79
+ case "line": return {
80
+ paths: [{ d: straight }],
81
+ head: head(f.u)
82
+ };
83
+ case "dashed": return {
84
+ paths: [{
85
+ d: straight,
86
+ dash: "5 5"
87
+ }],
88
+ head: head(f.u)
89
+ };
90
+ case "dotted": return {
91
+ paths: [{
92
+ d: straight,
93
+ dash: "0 6",
94
+ width: 2.4
95
+ }],
96
+ head: head(f.u)
97
+ };
98
+ case "curve":
99
+ case "curve-dashed": {
100
+ const c = f.at(L / 2, bend * L * .32);
101
+ const path = { d: `M${pt(from)}Q${pt(c)} ${pt(to)}` };
102
+ if (style === "curve-dashed") path.dash = "5 5";
103
+ return {
104
+ paths: [path],
105
+ head: head(unit(c, to))
106
+ };
107
+ }
108
+ case "squiggle": {
109
+ const steps = Math.max(24, Math.round(L / 2));
110
+ const wave = 15;
111
+ const points = [];
112
+ for (let i = 0; i <= steps; i++) {
113
+ const t = i / steps;
114
+ const envelope = Math.min(1, t * 5, (1 - t) * 5);
115
+ points.push(f.at(L * t, bend * 4.5 * envelope * Math.sin(2 * Math.PI * L * t / wave)));
116
+ }
117
+ return {
118
+ paths: [{ d: polyline(points) }],
119
+ head: head(unit(points[points.length - 3], to))
120
+ };
121
+ }
122
+ case "loop": {
123
+ const R = Math.min(22, Math.max(9, L / 5.5));
124
+ const steps = 48;
125
+ const points = [];
126
+ for (let i = 0; i <= steps; i++) {
127
+ const t = i / steps;
128
+ points.push(f.at(L * t - R * Math.sin(2 * Math.PI * t), bend * .75 * R * (1 - Math.cos(2 * Math.PI * t))));
129
+ }
130
+ return {
131
+ paths: [{ d: polyline(points) }],
132
+ head: head(unit(points[points.length - 3], to))
133
+ };
134
+ }
135
+ case "elbow": {
136
+ const dx = to.x - from.x;
137
+ const dy = to.y - from.y;
138
+ if (Math.abs(dx) < 6 || Math.abs(dy) < 6) return {
139
+ paths: [{ d: straight }],
140
+ head: head(f.u)
141
+ };
142
+ const points = Math.abs(dy) >= Math.abs(dx) ? [
143
+ from,
144
+ {
145
+ x: from.x,
146
+ y: from.y + dy / 2
147
+ },
148
+ {
149
+ x: to.x,
150
+ y: from.y + dy / 2
151
+ },
152
+ to
153
+ ] : [
154
+ from,
155
+ {
156
+ x: from.x + dx / 2,
157
+ y: from.y
158
+ },
159
+ {
160
+ x: from.x + dx / 2,
161
+ y: to.y
162
+ },
163
+ to
164
+ ];
165
+ return {
166
+ paths: [{ d: rounded(points, 10) }],
167
+ head: head(unit(points[2], to))
168
+ };
169
+ }
170
+ case "sketch": {
171
+ const c1 = f.at(L * .45, bend * L * .12);
172
+ const c2 = f.at(L * .55, bend * L * .04 - 3);
173
+ const start2 = f.at(2, 2);
174
+ const end2 = {
175
+ x: to.x + f.n.x * 2,
176
+ y: to.y + f.n.y * 2
177
+ };
178
+ return {
179
+ paths: [{ d: `M${pt(from)}Q${pt(c1)} ${pt(to)}` }, {
180
+ d: `M${pt(start2)}Q${pt(c2)} ${pt(end2)}`,
181
+ opacity: .55,
182
+ width: 1.2
183
+ }],
184
+ head: `${head(unit(c1, to))}${arrowHead(end2, unit(c2, end2), 6.5)}`
185
+ };
186
+ }
187
+ case "pin": {
188
+ const end = f.at(Math.max(0, L - 4), 0);
189
+ return {
190
+ paths: [{
191
+ d: `M${pt(from)}L${pt(end)}`,
192
+ dash: "0 5",
193
+ width: 2.2
194
+ }],
195
+ dot: to
196
+ };
197
+ }
198
+ }
199
+ }
200
+ /** Styles for the connector layer, injected into the shadow root when first used. */
201
+ const CONNECTOR_STYLES_CSS = `.connector{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;color:var(--docent-connector,oklch(98% 0.004 285 / 0.92))}:host([data-overlay="none"]) .connector{color:var(--docent-connector,var(--docent-accent))}.connector .stroke{fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}.connector .dot{fill:currentColor}.connector .dot-halo{fill:currentColor;opacity:0.2}.connector.animate .draw{stroke-dasharray:1;stroke-dashoffset:1;animation:docent-draw calc(var(--docent-duration) * 1.6) var(--docent-easing) var(--docent-duration) forwards}.connector.animate .fade,.connector.animate .head{opacity:0;animation:docent-fade var(--docent-duration) ease-out calc(var(--docent-duration) * 1.6) forwards}@keyframes docent-draw{to{stroke-dashoffset:0}}@keyframes docent-fade{to{opacity:1}}@media (prefers-reduced-motion:reduce){.connector.animate .draw,.connector.animate .fade,.connector.animate .head{animation:none;stroke-dashoffset:0;opacity:1}}`;
202
+ const SVG_NS = "http://www.w3.org/2000/svg";
203
+ /** SVG layer in the shadow root that draws the current connector. */
204
+ var Connector = class {
205
+ el;
206
+ doc;
207
+ constructor(doc) {
208
+ this.doc = doc;
209
+ this.el = doc.createElementNS(SVG_NS, "svg");
210
+ this.el.setAttribute("class", "connector");
211
+ this.el.setAttribute("part", "connector");
212
+ this.el.setAttribute("aria-hidden", "true");
213
+ }
214
+ clear() {
215
+ this.el.replaceChildren();
216
+ }
217
+ /** Draw a shape. `animate` plays the draw-in (after the popover settles). */
218
+ render(shape, animate) {
219
+ const make = (d, cls) => {
220
+ const path = this.doc.createElementNS(SVG_NS, "path");
221
+ path.setAttribute("d", d);
222
+ path.setAttribute("class", cls);
223
+ return path;
224
+ };
225
+ const nodes = shape.paths.map((p) => {
226
+ const path = make(p.d, p.dash ? "stroke fade" : "stroke draw");
227
+ if (p.dash) path.setAttribute("stroke-dasharray", p.dash);
228
+ else path.setAttribute("pathLength", "1");
229
+ if (p.width) path.setAttribute("stroke-width", String(p.width));
230
+ if (p.opacity) path.setAttribute("opacity", String(p.opacity));
231
+ return path;
232
+ });
233
+ if (shape.head) nodes.push(make(shape.head, "stroke head"));
234
+ if (shape.dot) for (const [radius, cls] of [[8, "dot-halo"], [3.5, "dot"]]) {
235
+ const c = this.doc.createElementNS(SVG_NS, "circle");
236
+ c.setAttribute("cx", String(shape.dot.x));
237
+ c.setAttribute("cy", String(shape.dot.y));
238
+ c.setAttribute("r", String(radius));
239
+ c.setAttribute("class", `${cls} head`);
240
+ nodes.push(c);
241
+ }
242
+ this.el.classList.toggle("animate", animate);
243
+ this.el.replaceChildren(...nodes);
244
+ }
245
+ };
246
+ //#endregion
247
+ exports.CONNECTOR_STYLES = require_arrows.CONNECTOR_STYLES;
248
+ exports.CONNECTOR_STYLES_CSS = CONNECTOR_STYLES_CSS;
249
+ exports.Connector = Connector;
250
+ exports.arrowGap = require_arrows.arrowGap;
251
+ exports.arrowHead = arrowHead;
252
+ exports.connectorShape = connectorShape;
253
+ exports.isConnector = require_arrows.isConnector;
254
+
255
+ //# sourceMappingURL=connector-D6Al4Deu.cjs.map