@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 +18 -1
- package/dist/arrows-Dcnwi9T-.js +25 -0
- package/dist/arrows-Dcnwi9T-.js.map +1 -0
- package/dist/arrows-DdDu3O3y.cjs +42 -0
- package/dist/arrows-DdDu3O3y.cjs.map +1 -0
- package/dist/connector-CzqD6NJY.js +249 -0
- package/dist/connector-CzqD6NJY.js.map +1 -0
- package/dist/connector-D6Al4Deu.cjs +255 -0
- package/dist/connector-D6Al4Deu.cjs.map +1 -0
- package/dist/index.cjs +228 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -10
- package/dist/index.d.ts +53 -10
- package/dist/index.js +226 -26
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-D6Al4Deu.cjs","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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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_arrows = require("./arrows-DdDu3O3y.cjs");
|
|
2
3
|
let _docentjs_core = require("@docentjs/core");
|
|
3
4
|
//#region src/content.ts
|
|
4
5
|
const SAFE_SCHEMES = /* @__PURE__ */ new Set([
|
|
@@ -267,16 +268,41 @@ function clipToViewport(rect, viewport) {
|
|
|
267
268
|
}
|
|
268
269
|
//#endregion
|
|
269
270
|
//#region src/overlay.ts
|
|
270
|
-
/**
|
|
271
|
-
* Full-viewport backdrop with a rounded cutout. The cutout is a `clip-path`
|
|
272
|
-
* so pointer events pass through the hole to the page for free; a separate
|
|
273
|
-
* blocker element covers it when the step forbids interaction.
|
|
274
|
-
*/
|
|
275
271
|
function holePath(viewport, hole, radius) {
|
|
276
272
|
const r = Math.max(0, Math.min(radius, hole.width / 2, hole.height / 2));
|
|
277
273
|
const { x, y, width: w, height: h } = hole;
|
|
278
274
|
return `path(evenodd, "${`M0 0H${viewport.width}V${viewport.height}H0Z`}${`M${x + r} ${y}H${x + w - r}A${r} ${r} 0 0 1 ${x + w} ${y + r}V${y + h - r}A${r} ${r} 0 0 1 ${x + w - r} ${y + h}H${x + r}A${r} ${r} 0 0 1 ${x} ${y + h - r}V${y + r}A${r} ${r} 0 0 1 ${x + r} ${y}Z`}")`;
|
|
279
275
|
}
|
|
276
|
+
/** The padded cutout and its corner radius for a shape. */
|
|
277
|
+
function holeFor(target, padding, radius, shape = "rounded") {
|
|
278
|
+
if (shape === "circle") {
|
|
279
|
+
const cx = target.x + target.width / 2;
|
|
280
|
+
const cy = target.y + target.height / 2;
|
|
281
|
+
const rr = Math.hypot(target.width, target.height) / 2 + padding;
|
|
282
|
+
return {
|
|
283
|
+
hole: {
|
|
284
|
+
x: cx - rr,
|
|
285
|
+
y: cy - rr,
|
|
286
|
+
width: rr * 2,
|
|
287
|
+
height: rr * 2
|
|
288
|
+
},
|
|
289
|
+
radius: rr
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const hole = inflate(target, padding);
|
|
293
|
+
if (shape === "rect") return {
|
|
294
|
+
hole,
|
|
295
|
+
radius: 0
|
|
296
|
+
};
|
|
297
|
+
if (shape === "pill") return {
|
|
298
|
+
hole,
|
|
299
|
+
radius: Math.min(hole.width, hole.height) / 2
|
|
300
|
+
};
|
|
301
|
+
return {
|
|
302
|
+
hole,
|
|
303
|
+
radius: Math.max(0, Math.min(radius, hole.width / 2, hole.height / 2))
|
|
304
|
+
};
|
|
305
|
+
}
|
|
280
306
|
var Overlay = class {
|
|
281
307
|
el;
|
|
282
308
|
blocker;
|
|
@@ -309,13 +335,13 @@ var Overlay = class {
|
|
|
309
335
|
get hole() {
|
|
310
336
|
return this.lastHole;
|
|
311
337
|
}
|
|
312
|
-
update(viewport, { target, padding, radius }, block) {
|
|
313
|
-
if (target)
|
|
314
|
-
else {
|
|
338
|
+
update(viewport, { target, padding, radius, shape }, block) {
|
|
339
|
+
if (!target) {
|
|
315
340
|
const c = this.lastHole;
|
|
316
341
|
const cx = c ? c.x + c.width / 2 : viewport.width / 2;
|
|
317
342
|
const cy = c ? c.y + c.height / 2 : viewport.height / 2;
|
|
318
343
|
this.lastHole = null;
|
|
344
|
+
this.setCentre(cx, cy);
|
|
319
345
|
this.el.style.clipPath = holePath(viewport, {
|
|
320
346
|
x: cx,
|
|
321
347
|
y: cy,
|
|
@@ -331,9 +357,11 @@ var Overlay = class {
|
|
|
331
357
|
this.blocker.hidden = true;
|
|
332
358
|
return;
|
|
333
359
|
}
|
|
334
|
-
const hole =
|
|
335
|
-
this.
|
|
336
|
-
this.
|
|
360
|
+
const { hole, radius: r } = holeFor(target, padding, radius, shape);
|
|
361
|
+
this.lastHole = hole;
|
|
362
|
+
this.setCentre(hole.x + hole.width / 2, hole.y + hole.height / 2);
|
|
363
|
+
this.el.style.clipPath = holePath(viewport, hole, r);
|
|
364
|
+
this.placeRing(hole, r, true);
|
|
337
365
|
this.blocker.hidden = !block;
|
|
338
366
|
if (block) {
|
|
339
367
|
this.blocker.style.transform = `translate(${hole.x}px, ${hole.y}px)`;
|
|
@@ -341,6 +369,11 @@ var Overlay = class {
|
|
|
341
369
|
this.blocker.style.height = `${hole.height}px`;
|
|
342
370
|
}
|
|
343
371
|
}
|
|
372
|
+
/** Exposed for the vignette style, which is centred on the cutout. */
|
|
373
|
+
setCentre(x, y) {
|
|
374
|
+
this.el.style.setProperty("--docent-hole-x", `${Math.round(x)}px`);
|
|
375
|
+
this.el.style.setProperty("--docent-hole-y", `${Math.round(y)}px`);
|
|
376
|
+
}
|
|
344
377
|
};
|
|
345
378
|
//#endregion
|
|
346
379
|
//#region src/popover.ts
|
|
@@ -540,7 +573,7 @@ function buildHeadlessShell(doc) {
|
|
|
540
573
|
* are ink tinted toward the Docent hue (OKLCH 285). Light is the default;
|
|
541
574
|
* dark is opt-in through tokens or the `dark` preset.
|
|
542
575
|
*/
|
|
543
|
-
const STYLES = `:host{--docent-bg:oklch(99.4% 0.003 285);--docent-fg:oklch(23% 0.018 285);--docent-muted:oklch(52% 0.014 285);--docent-accent:oklch(26% 0.02 285);--docent-accent-fg:oklch(98.5% 0.004 285);--docent-radius:14px;--docent-shadow:0 1px 2px oklch(23% 0.02 285 / 0.06),0 8px 24px -6px oklch(23% 0.02 285 / 0.16),0 28px 56px -16px oklch(23% 0.02 285 / 0.24);--docent-width:344px;--docent-overlay:oklch(20% 0.02 285);--docent-overlay-opacity:0.52;--docent-duration:220ms;--docent-easing:cubic-bezier(0.2,0.8,0.2,1);--_line:color-mix(in oklch,var(--docent-fg) 11%,transparent);--_soft:color-mix(in oklch,var(--docent-fg) 6%,transparent);--_body:color-mix(in oklch,var(--docent-fg) 80%,var(--docent-bg));position:fixed;inset:0;z-index:var(--docent-z,2147483000);pointer-events:none;color:var(--docent-fg);font-family:var(--docent-font);font-size:14px;font-weight:400;font-style:normal;line-height:1.55;letter-spacing:normal;text-transform:none;text-align:start;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*{box-sizing:border-box}.overlay{
|
|
576
|
+
const STYLES = `:host{--docent-bg:oklch(99.4% 0.003 285);--docent-fg:oklch(23% 0.018 285);--docent-muted:oklch(52% 0.014 285);--docent-accent:oklch(26% 0.02 285);--docent-accent-fg:oklch(98.5% 0.004 285);--docent-radius:14px;--docent-shadow:0 1px 2px oklch(23% 0.02 285 / 0.06),0 8px 24px -6px oklch(23% 0.02 285 / 0.16),0 28px 56px -16px oklch(23% 0.02 285 / 0.24);--docent-width:344px;--docent-overlay:oklch(20% 0.02 285);--docent-overlay-opacity:0.52;--docent-duration:220ms;--docent-easing:cubic-bezier(0.2,0.8,0.2,1);--_line:color-mix(in oklch,var(--docent-fg) 11%,transparent);--_soft:color-mix(in oklch,var(--docent-fg) 6%,transparent);--_body:color-mix(in oklch,var(--docent-fg) 80%,var(--docent-bg));position:fixed;inset:0;z-index:var(--docent-z,2147483000);pointer-events:none;color:var(--docent-fg);font-family:var(--docent-font);font-size:14px;font-weight:400;font-style:normal;line-height:1.55;letter-spacing:normal;text-transform:none;text-align:start;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*{box-sizing:border-box}.overlay{--_scrim:color-mix(in oklch,var(--docent-overlay) calc(var(--docent-overlay-opacity) * 100%),transparent);position:absolute;inset:0;background:var(--_scrim);pointer-events:auto;transition:clip-path var(--docent-duration) var(--docent-easing)}:host([data-overlay="blur"]) .overlay{-webkit-backdrop-filter:blur(var(--docent-blur,4px));backdrop-filter:blur(var(--docent-blur,4px))}:host([data-overlay="vignette"]) .overlay{background:radial-gradient( circle at var(--docent-hole-x,50%) var(--docent-hole-y,50%),transparent 0,color-mix(in oklch,var(--docent-overlay) calc(var(--docent-overlay-opacity) * 30%),transparent) 22%,var(--_scrim) 78% )}:host([data-overlay="none"]) .overlay{background:transparent;pointer-events:none}.blocker{position:absolute;left:0;top:0;pointer-events:auto}.ring{position:absolute;left:0;top:0;pointer-events:none;color:var(--docent-ring,oklch(98% 0.004 285));box-shadow:0 0 0 1px color-mix(in oklch,currentColor 58%,transparent),0 0 0 6px color-mix(in oklch,currentColor 8%,transparent);transition:transform var(--docent-duration) var(--docent-easing),width var(--docent-duration) var(--docent-easing),height var(--docent-duration) var(--docent-easing),border-radius var(--docent-duration) var(--docent-easing),opacity var(--docent-duration) var(--docent-easing)}:host([data-overlay="none"]) .ring{color:var(--docent-ring,var(--docent-accent))}:host([data-ring="none"]) .ring{box-shadow:none}:host([data-ring="glow"]) .ring{box-shadow:0 0 0 1.5px color-mix(in oklch,currentColor 85%,transparent),0 0 20px 4px color-mix(in oklch,currentColor 42%,transparent)}:host([data-ring="solid"]) .ring{box-shadow:0 0 0 2px currentColor}:host([data-ring="dashed"]) .ring{box-shadow:none;outline:1.5px dashed color-mix(in oklch,currentColor 85%,transparent);outline-offset:3px}:host([data-ring="pulse"]) .ring::after{content:"";position:absolute;inset:0;border-radius:inherit;animation:docent-pulse 1.8s var(--docent-easing) infinite}@keyframes docent-pulse{from{box-shadow:0 0 0 0 color-mix(in oklch,currentColor 60%,transparent)}to{box-shadow:0 0 0 14px transparent}}:host(:not([data-arrow="caret"])) .arrow{display:none}:host([data-tracking]) .overlay,:host([data-tracking]) .ring,:host([data-tracking]) .popover{transition:none}.popover{position:absolute;left:0;top:0;display:flex;flex-direction:column;width:var(--docent-width);max-width:calc(100vw - 32px);padding:20px 20px 16px;background:var(--docent-bg);border-radius:var(--docent-radius);box-shadow:0 0 0 1px var(--_line),var(--docent-shadow);pointer-events:auto;outline:none;transition:transform var(--docent-duration) var(--docent-easing),opacity var(--docent-duration) var(--docent-easing),scale var(--docent-duration) var(--docent-easing)}.popover[data-side="bottom"]{transform-origin:50% 0}.popover[data-side="top"]{transform-origin:50% 100%}.popover[data-side="right"]{transform-origin:0 50%}.popover[data-side="left"]{transform-origin:100% 50%}.popover[data-entering]{opacity:0;scale:0.97;transition:none}.popover[data-moving]>*{animation:docent-swap 160ms ease-out}@keyframes docent-swap{from{opacity:0}to{opacity:1}}.popover.headless{width:auto;max-width:none;padding:0;background:none;box-shadow:none;border-radius:0}.arrow{position:absolute;width:12px;height:12px;background:var(--docent-bg);transform:rotate(45deg)}.popover[data-side="bottom"] .arrow{top:-6px;border-top:1px solid var(--_line);border-left:1px solid var(--_line);border-top-left-radius:2px}.popover[data-side="top"] .arrow{bottom:-6px;border-bottom:1px solid var(--_line);border-right:1px solid var(--_line);border-bottom-right-radius:2px}.popover[data-side="right"] .arrow{left:-6px;border-bottom:1px solid var(--_line);border-left:1px solid var(--_line);border-bottom-left-radius:2px}.popover[data-side="left"] .arrow{right:-6px;border-top:1px solid var(--_line);border-right:1px solid var(--_line);border-top-right-radius:2px}.popover[data-side="center"] .arrow,.popover[data-side="sheet"] .arrow{display:none}.header{display:flex;align-items:flex-start;gap:12px}.title{flex:1;min-width:0;margin:0;font-size:18px;font-weight:600;line-height:1.3;letter-spacing:-0.012em;color:var(--docent-fg);text-wrap:balance}.close{flex:none;display:grid;place-items:center;width:28px;height:28px;margin:-3px -8px -3px 0;padding:0;border:0;border-radius:8px;background:transparent;color:var(--docent-muted);cursor:pointer;transition:background-color 120ms ease-out,color 120ms ease-out}.close svg{width:14px;height:14px}.close:hover{background:var(--_soft);color:var(--docent-fg)}.body{margin-top:6px;color:var(--_body);text-wrap:pretty}.body p{margin:0}.body p + p{margin-top:8px}.body strong{font-weight:600;color:var(--docent-fg)}.body a{color:var(--docent-fg);text-decoration:underline;text-decoration-color:color-mix(in oklch,var(--docent-fg) 32%,transparent);text-decoration-thickness:1px;text-underline-offset:3px;transition:text-decoration-color 120ms ease-out}.body a:hover{text-decoration-color:currentColor}.body code{font-family:ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;font-size:0.88em;padding:1px 5px;border-radius:5px;background:var(--_soft);color:var(--docent-fg)}.media{margin-top:14px}.media img,.media video{display:block;width:100%;border-radius:8px;box-shadow:0 0 0 1px var(--_line)}.footer{display:flex;align-items:center;gap:12px;margin-top:20px}.progress{flex:1;display:flex;align-items:center;gap:8px;min-width:0;color:var(--docent-muted);font-size:12px;font-variant-numeric:tabular-nums;letter-spacing:0.01em;white-space:nowrap}.meter{flex:none;width:28px;height:3px;border-radius:999px;background:linear-gradient(var(--docent-fg),var(--docent-fg)) 0 0 / calc(var(--docent-step) / var(--docent-steps) * 100%) 100% no-repeat,var(--_line)}.buttons{display:flex;align-items:center;gap:6px}.button{appearance:none;display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;border:0;border-radius:8px;background:transparent;color:var(--docent-fg);font:inherit;font-size:13px;font-weight:500;line-height:1;letter-spacing:-0.003em;white-space:nowrap;cursor:pointer;transition:background-color 120ms ease-out,color 120ms ease-out,scale 80ms ease-out}.button:hover{background:var(--_soft)}.button:active{scale:0.97}[part~="button-skip"]{color:var(--docent-muted);padding:0 8px}[part~="button-skip"]:hover{color:var(--docent-fg);background:transparent}.button.primary{padding:0 14px;background:var(--docent-accent);color:var(--docent-accent-fg);font-weight:600;box-shadow:inset 0 1px 0 color-mix(in oklch,var(--docent-accent-fg) 14%,transparent)}.button.primary .icon{width:12px;height:12px;margin:0 -2px 0 6px;transition:translate 160ms var(--docent-easing)}.button.primary:hover .icon{translate:2px 0}.button.primary:hover{background:color-mix(in oklch,var(--docent-accent) 86%,var(--docent-accent-fg))}.button:focus-visible,.close:focus-visible{outline:2px solid var(--docent-accent);outline-offset:2px}.popover.sheet{max-width:none;padding:20px 20px max(16px,env(safe-area-inset-bottom));border-radius:var(--docent-radius) var(--docent-radius) 0 0;box-shadow:0 0 0 1px var(--_line),0 -12px 40px -12px oklch(23% 0.02 285 / 0.28)}@media (pointer:coarse){:host{font-size:15px}.button{min-height:44px;padding:0 16px;font-size:14px}.close{width:40px;height:40px;margin:-9px -12px -9px 0}}@media (prefers-reduced-motion:reduce){.overlay,.popover,.ring{transition:none}.ring::after{animation:none !important}.popover[data-moving]>*{animation:none}}`;
|
|
544
577
|
//#endregion
|
|
545
578
|
//#region src/target.ts
|
|
546
579
|
/** Attribute that `{ name }` targets resolve through. */
|
|
@@ -641,7 +674,9 @@ const THEME_VARS = {
|
|
|
641
674
|
overlay: "overlay",
|
|
642
675
|
overlayOpacity: "overlay-opacity",
|
|
643
676
|
duration: "duration",
|
|
644
|
-
zIndex: "z"
|
|
677
|
+
zIndex: "z",
|
|
678
|
+
connector: "connector",
|
|
679
|
+
ring: "ring"
|
|
645
680
|
};
|
|
646
681
|
/** Write theme tokens as inline custom properties on an element. Clears unset ones. */
|
|
647
682
|
function applyTheme(el, theme) {
|
|
@@ -657,6 +692,11 @@ function mergeThemes(...themes) {
|
|
|
657
692
|
}
|
|
658
693
|
//#endregion
|
|
659
694
|
//#region src/renderer.ts
|
|
695
|
+
const DEFAULT_LOOK = {
|
|
696
|
+
arrow: "caret",
|
|
697
|
+
spotlight: {},
|
|
698
|
+
overlay: {}
|
|
699
|
+
};
|
|
660
700
|
const FOCUSABLE = "a[href], button:not([disabled]), input, select, textarea, [tabindex]:not([tabindex=\"-1\"])";
|
|
661
701
|
var DomRenderer = class {
|
|
662
702
|
doc;
|
|
@@ -675,6 +715,17 @@ var DomRenderer = class {
|
|
|
675
715
|
previousFocus = null;
|
|
676
716
|
/** Set once per step after the sheet has scrolled the target clear. */
|
|
677
717
|
sheetAdjusted = false;
|
|
718
|
+
connector;
|
|
719
|
+
/** Loaded on first use: connector styles cost nothing for tours that never use them. */
|
|
720
|
+
connectorModule;
|
|
721
|
+
connectorLoading;
|
|
722
|
+
/** Arrow, spotlight and overlay settings for the current step. */
|
|
723
|
+
look = DEFAULT_LOOK;
|
|
724
|
+
/** Until then the step's own transition runs; scroll updates may animate. */
|
|
725
|
+
settleUntil = 0;
|
|
726
|
+
/** Play the connector draw-in on its next render. */
|
|
727
|
+
drawConnector = false;
|
|
728
|
+
trackingFrame;
|
|
678
729
|
constructor(options = {}) {
|
|
679
730
|
this.options = options;
|
|
680
731
|
this.doc = options.document ?? document;
|
|
@@ -702,6 +753,9 @@ var DomRenderer = class {
|
|
|
702
753
|
const template = this.template(ctx);
|
|
703
754
|
applyTheme(host, mergeThemes(this.options.theme, template?.theme, ctx.tour.options?.theme));
|
|
704
755
|
this.setTemplateCss(template?.css);
|
|
756
|
+
this.applyLook(host, this.resolveLook(ctx, template));
|
|
757
|
+
this.settleUntil = performance.now() + this.duration(host) * 1.5;
|
|
758
|
+
this.drawConnector = true;
|
|
705
759
|
const initialFocus = this.options.headless ? this.buildHeadless(ctx, host, this.options.headless) : this.buildDefault(ctx, host, template);
|
|
706
760
|
if (this.popover && from) {
|
|
707
761
|
this.popover.style.transform = from;
|
|
@@ -732,31 +786,34 @@ var DomRenderer = class {
|
|
|
732
786
|
this.host = void 0;
|
|
733
787
|
this.shadow = void 0;
|
|
734
788
|
this.overlay = void 0;
|
|
789
|
+
this.connector = void 0;
|
|
735
790
|
this.templateStyle = void 0;
|
|
736
791
|
}
|
|
737
792
|
const prev = this.previousFocus;
|
|
738
793
|
this.previousFocus = null;
|
|
739
794
|
if (prev instanceof HTMLElement && prev.isConnected) prev.focus({ preventScroll: true });
|
|
740
795
|
}
|
|
741
|
-
/**
|
|
742
|
-
|
|
796
|
+
/**
|
|
797
|
+
* Re-measure and re-position everything. Safe to call often. `tracking`
|
|
798
|
+
* marks updates caused by scroll or resize: once the step's own transition
|
|
799
|
+
* has finished, those follow the target instantly instead of trailing it.
|
|
800
|
+
*/
|
|
801
|
+
update(tracking = false) {
|
|
743
802
|
const ctx = this.ctx;
|
|
744
803
|
const overlay = this.overlay;
|
|
745
804
|
const popover = this.popover;
|
|
746
805
|
const win = this.doc.defaultView;
|
|
747
806
|
if (!ctx || !overlay || !popover || !win) return;
|
|
807
|
+
if (tracking && performance.now() > this.settleUntil) this.markTracking();
|
|
748
808
|
const viewport = this.viewport();
|
|
749
809
|
const overlaySize = {
|
|
750
810
|
width: overlay.el.offsetWidth,
|
|
751
811
|
height: overlay.el.offsetHeight
|
|
752
812
|
};
|
|
753
|
-
const spotlight =
|
|
754
|
-
...this.options.spotlight,
|
|
755
|
-
...ctx.tour.options?.spotlight,
|
|
756
|
-
...ctx.step.spotlight
|
|
757
|
-
};
|
|
813
|
+
const spotlight = this.look.spotlight;
|
|
758
814
|
const padding = spotlight.padding ?? 8;
|
|
759
815
|
const radius = spotlight.radius ?? 10;
|
|
816
|
+
const shape = spotlight.shape ?? "rounded";
|
|
760
817
|
const external = this.headlessContainer;
|
|
761
818
|
const sheet = this.isSheet(viewport);
|
|
762
819
|
popover.classList.toggle("sheet", sheet);
|
|
@@ -770,8 +827,10 @@ var DomRenderer = class {
|
|
|
770
827
|
overlay.update(overlaySize, {
|
|
771
828
|
target: rect,
|
|
772
829
|
padding,
|
|
773
|
-
radius
|
|
830
|
+
radius,
|
|
831
|
+
shape
|
|
774
832
|
}, this.blocksInteraction(ctx.step));
|
|
833
|
+
this.connector?.clear();
|
|
775
834
|
const vx = viewport.x ?? 0;
|
|
776
835
|
const top = (viewport.y ?? 0) + viewport.height - floating.height;
|
|
777
836
|
popover.style.transform = `translate(${vx}px, ${top}px)`;
|
|
@@ -786,6 +845,7 @@ var DomRenderer = class {
|
|
|
786
845
|
padding,
|
|
787
846
|
radius
|
|
788
847
|
}, false);
|
|
848
|
+
this.connector?.clear();
|
|
789
849
|
const { x, y } = centerPosition(floating, viewport);
|
|
790
850
|
popover.style.transform = `translate(${x}px, ${y}px)`;
|
|
791
851
|
popover.setAttribute("data-side", "center");
|
|
@@ -796,14 +856,16 @@ var DomRenderer = class {
|
|
|
796
856
|
overlay.update(overlaySize, {
|
|
797
857
|
target: rect,
|
|
798
858
|
padding,
|
|
799
|
-
radius
|
|
859
|
+
radius,
|
|
860
|
+
shape
|
|
800
861
|
}, this.blocksInteraction(ctx.step));
|
|
862
|
+
const hole = overlay.hole ?? rect;
|
|
801
863
|
const pos = computePosition({
|
|
802
|
-
anchor: clipToViewport(
|
|
864
|
+
anchor: clipToViewport(hole, viewport),
|
|
803
865
|
floating,
|
|
804
866
|
viewport,
|
|
805
867
|
placement: ctx.step.placement ?? "auto",
|
|
806
|
-
gap: this.options.gap ??
|
|
868
|
+
gap: this.options.gap ?? require_arrows.arrowGap(this.look.arrow)
|
|
807
869
|
});
|
|
808
870
|
popover.style.transform = `translate(${pos.x}px, ${pos.y}px)`;
|
|
809
871
|
popover.setAttribute("data-side", pos.side);
|
|
@@ -816,6 +878,142 @@ var DomRenderer = class {
|
|
|
816
878
|
external.setAttribute("data-side", pos.side);
|
|
817
879
|
external.style.setProperty("--docent-arrow", `${pos.arrow}px`);
|
|
818
880
|
}
|
|
881
|
+
this.renderConnector(pos, floating, hole);
|
|
882
|
+
}
|
|
883
|
+
/** Draw the connector for connector arrow styles; clear it otherwise. */
|
|
884
|
+
renderConnector(pos, floating, hole) {
|
|
885
|
+
const style = this.look.arrow;
|
|
886
|
+
if (!require_arrows.isConnector(style)) {
|
|
887
|
+
this.connector?.clear();
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const mod = this.connectorModule;
|
|
891
|
+
const connector = this.connector;
|
|
892
|
+
if (!mod || !connector) {
|
|
893
|
+
this.loadConnector();
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
const inset = 6;
|
|
897
|
+
const clampX = (x) => Math.min(Math.max(x, hole.x + 10), hole.x + hole.width - 10);
|
|
898
|
+
const clampY = (y) => Math.min(Math.max(y, hole.y + 10), hole.y + hole.height - 10);
|
|
899
|
+
const cx = hole.x + hole.width / 2;
|
|
900
|
+
const cy = hole.y + hole.height / 2;
|
|
901
|
+
const alongX = pos.x + floating.width * (cx < pos.x + floating.width / 2 ? .3 : .7);
|
|
902
|
+
const alongY = pos.y + floating.height * (cy < pos.y + floating.height / 2 ? .3 : .7);
|
|
903
|
+
let from;
|
|
904
|
+
let to;
|
|
905
|
+
switch (pos.side) {
|
|
906
|
+
case "bottom":
|
|
907
|
+
from = {
|
|
908
|
+
x: alongX,
|
|
909
|
+
y: pos.y
|
|
910
|
+
};
|
|
911
|
+
to = {
|
|
912
|
+
x: clampX(cx),
|
|
913
|
+
y: hole.y + hole.height + inset
|
|
914
|
+
};
|
|
915
|
+
break;
|
|
916
|
+
case "top":
|
|
917
|
+
from = {
|
|
918
|
+
x: alongX,
|
|
919
|
+
y: pos.y + floating.height
|
|
920
|
+
};
|
|
921
|
+
to = {
|
|
922
|
+
x: clampX(cx),
|
|
923
|
+
y: hole.y - inset
|
|
924
|
+
};
|
|
925
|
+
break;
|
|
926
|
+
case "right":
|
|
927
|
+
from = {
|
|
928
|
+
x: pos.x,
|
|
929
|
+
y: alongY
|
|
930
|
+
};
|
|
931
|
+
to = {
|
|
932
|
+
x: hole.x + hole.width + inset,
|
|
933
|
+
y: clampY(cy)
|
|
934
|
+
};
|
|
935
|
+
break;
|
|
936
|
+
default:
|
|
937
|
+
from = {
|
|
938
|
+
x: pos.x + floating.width,
|
|
939
|
+
y: alongY
|
|
940
|
+
};
|
|
941
|
+
to = {
|
|
942
|
+
x: hole.x - inset,
|
|
943
|
+
y: clampY(cy)
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
const bend = pos.side === "top" || pos.side === "bottom" ? to.x < from.x ? 1 : -1 : to.y < from.y ? -1 : 1;
|
|
947
|
+
connector.render(mod.connectorShape(style, from, to, pos.side === "top" || pos.side === "left" ? -bend : bend), this.drawConnector);
|
|
948
|
+
this.drawConnector = false;
|
|
949
|
+
}
|
|
950
|
+
/** Fetch the connector module once, then draw with it. */
|
|
951
|
+
loadConnector() {
|
|
952
|
+
this.connectorLoading ??= Promise.resolve().then(() => require("./connector-D6Al4Deu.cjs")).then((mod) => {
|
|
953
|
+
this.connectorModule = mod;
|
|
954
|
+
if (this.shadow) this.attachConnector(this.shadow, mod);
|
|
955
|
+
this.update();
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
/** Add the connector layer and its styles, beneath any popover. */
|
|
959
|
+
attachConnector(shadow, mod) {
|
|
960
|
+
if (this.connector) return;
|
|
961
|
+
const style = this.doc.createElement("style");
|
|
962
|
+
style.textContent = mod.CONNECTOR_STYLES_CSS;
|
|
963
|
+
this.connector = new mod.Connector(this.doc);
|
|
964
|
+
const before = this.popover ?? null;
|
|
965
|
+
shadow.insertBefore(style, before);
|
|
966
|
+
shadow.insertBefore(this.connector.el, before);
|
|
967
|
+
}
|
|
968
|
+
resolveLook(ctx, template) {
|
|
969
|
+
const tour = ctx.tour.options ?? {};
|
|
970
|
+
const step = ctx.step;
|
|
971
|
+
return {
|
|
972
|
+
arrow: step.arrow ?? tour.arrow ?? template?.arrow ?? this.options.arrow ?? "caret",
|
|
973
|
+
spotlight: {
|
|
974
|
+
...this.options.spotlight,
|
|
975
|
+
...template?.spotlight,
|
|
976
|
+
...tour.spotlight,
|
|
977
|
+
...step.spotlight
|
|
978
|
+
},
|
|
979
|
+
overlay: {
|
|
980
|
+
...this.options.overlay,
|
|
981
|
+
...template?.overlay,
|
|
982
|
+
...tour.overlay,
|
|
983
|
+
...step.overlay
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
/** Expose the look to the stylesheet as host attributes and variables. */
|
|
988
|
+
applyLook(host, look) {
|
|
989
|
+
this.look = look;
|
|
990
|
+
host.setAttribute("data-arrow", look.arrow);
|
|
991
|
+
host.setAttribute("data-ring", look.spotlight.ring ?? "hairline");
|
|
992
|
+
host.setAttribute("data-shape", look.spotlight.shape ?? "rounded");
|
|
993
|
+
host.setAttribute("data-overlay", look.overlay.style ?? "dim");
|
|
994
|
+
const { color, opacity, blur } = look.overlay;
|
|
995
|
+
if (color !== void 0) host.style.setProperty("--docent-overlay", color);
|
|
996
|
+
if (opacity !== void 0) host.style.setProperty("--docent-overlay-opacity", String(opacity));
|
|
997
|
+
if (blur !== void 0) host.style.setProperty("--docent-blur", `${blur}px`);
|
|
998
|
+
else host.style.removeProperty("--docent-blur");
|
|
999
|
+
}
|
|
1000
|
+
/** The current transition duration in ms, from the --docent-duration token. */
|
|
1001
|
+
duration(host) {
|
|
1002
|
+
const raw = this.doc.defaultView?.getComputedStyle(host).getPropertyValue("--docent-duration").trim() ?? "";
|
|
1003
|
+
const n = Number.parseFloat(raw);
|
|
1004
|
+
if (Number.isNaN(n)) return 220;
|
|
1005
|
+
return raw.endsWith("ms") ? n : n * 1e3;
|
|
1006
|
+
}
|
|
1007
|
+
/** Disable transitions for this frame so scroll-driven moves stay glued to the target. */
|
|
1008
|
+
markTracking() {
|
|
1009
|
+
const host = this.host;
|
|
1010
|
+
if (!host) return;
|
|
1011
|
+
host.setAttribute("data-tracking", "");
|
|
1012
|
+
if (this.trackingFrame !== void 0) cancelAnimationFrame(this.trackingFrame);
|
|
1013
|
+
this.trackingFrame = requestAnimationFrame(() => {
|
|
1014
|
+
this.trackingFrame = void 0;
|
|
1015
|
+
host.removeAttribute("data-tracking");
|
|
1016
|
+
});
|
|
819
1017
|
}
|
|
820
1018
|
/**
|
|
821
1019
|
* The visible area in layout-viewport coordinates. Uses the visual viewport
|
|
@@ -954,6 +1152,7 @@ var DomRenderer = class {
|
|
|
954
1152
|
shadow.appendChild(overlay.el);
|
|
955
1153
|
shadow.appendChild(overlay.ring);
|
|
956
1154
|
shadow.appendChild(overlay.blocker);
|
|
1155
|
+
if (this.connectorModule) this.attachConnector(shadow, this.connectorModule);
|
|
957
1156
|
this.doc.body.appendChild(host);
|
|
958
1157
|
this.host = host;
|
|
959
1158
|
this.shadow = shadow;
|
|
@@ -967,6 +1166,7 @@ var DomRenderer = class {
|
|
|
967
1166
|
this.frame = void 0;
|
|
968
1167
|
this.popover?.remove();
|
|
969
1168
|
this.popover = void 0;
|
|
1169
|
+
this.connector?.clear();
|
|
970
1170
|
this.arrow = void 0;
|
|
971
1171
|
this.ctx = void 0;
|
|
972
1172
|
this.target = null;
|
|
@@ -1010,7 +1210,7 @@ var DomRenderer = class {
|
|
|
1010
1210
|
if (this.frame !== void 0) return;
|
|
1011
1211
|
this.frame = requestAnimationFrame(() => {
|
|
1012
1212
|
this.frame = void 0;
|
|
1013
|
-
this.update();
|
|
1213
|
+
this.update(true);
|
|
1014
1214
|
});
|
|
1015
1215
|
};
|
|
1016
1216
|
listen() {
|
|
@@ -1281,6 +1481,7 @@ function createDocent(options = {}) {
|
|
|
1281
1481
|
});
|
|
1282
1482
|
}
|
|
1283
1483
|
//#endregion
|
|
1484
|
+
exports.CONNECTOR_STYLES = require_arrows.CONNECTOR_STYLES;
|
|
1284
1485
|
exports.DEFAULT_LABELS = DEFAULT_LABELS;
|
|
1285
1486
|
exports.DomRenderer = DomRenderer;
|
|
1286
1487
|
exports.DomTourController = DomTourController;
|
|
@@ -1288,6 +1489,7 @@ exports.NAME_ATTRIBUTE = NAME_ATTRIBUTE;
|
|
|
1288
1489
|
exports.Overlay = Overlay;
|
|
1289
1490
|
exports.THEME_VARS = THEME_VARS;
|
|
1290
1491
|
exports.applyTheme = applyTheme;
|
|
1492
|
+
exports.arrowGap = require_arrows.arrowGap;
|
|
1291
1493
|
exports.availableSpace = availableSpace;
|
|
1292
1494
|
exports.buildHeadlessShell = buildHeadlessShell;
|
|
1293
1495
|
exports.buildPopover = buildPopover;
|
|
@@ -1308,6 +1510,7 @@ exports.findOccluder = findOccluder;
|
|
|
1308
1510
|
exports.formatProgress = formatProgress;
|
|
1309
1511
|
exports.holePath = holePath;
|
|
1310
1512
|
exports.inflate = inflate;
|
|
1513
|
+
exports.isConnector = require_arrows.isConnector;
|
|
1311
1514
|
exports.isSafeUrl = isSafeUrl;
|
|
1312
1515
|
exports.mergeThemes = mergeThemes;
|
|
1313
1516
|
exports.parsePlacement = parsePlacement;
|