mesurer 0.0.8 → 0.0.9
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/CHANGELOG.md +13 -0
- package/README.md +4 -0
- package/dist/index.cjs +2291 -543
- package/dist/index.d.cts +39 -2
- package/dist/index.d.ts +39 -2
- package/dist/index.js +2274 -529
- package/dist/styles.css +34 -0
- package/package.json +11 -10
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// measurer.tsx
|
|
2
2
|
import {
|
|
3
3
|
useCallback as useCallback6,
|
|
4
|
-
useEffect as
|
|
4
|
+
useEffect as useEffect5,
|
|
5
5
|
useMemo as useMemo2,
|
|
6
|
-
useRef as
|
|
7
|
-
useState as
|
|
6
|
+
useRef as useRef9,
|
|
7
|
+
useState as useState8,
|
|
8
8
|
useSyncExternalStore
|
|
9
9
|
} from "react";
|
|
10
10
|
import { createPortal } from "react-dom";
|
|
11
11
|
|
|
12
|
-
// constants.ts
|
|
12
|
+
// core/constants.ts
|
|
13
13
|
var MEASURE_LABEL_OFFSET = 2;
|
|
14
14
|
var GUIDE_SNAP_DISTANCE = 10;
|
|
15
15
|
var GUIDE_HITBOX_SIZE = 14;
|
|
@@ -22,15 +22,17 @@ var ANCESTOR_KEEP_COVERAGE = 0.92;
|
|
|
22
22
|
var MIN_SINGLE_TARGET_SIZE = 8;
|
|
23
23
|
var MIN_SINGLE_ELEMENT_COVERAGE = 0.15;
|
|
24
24
|
|
|
25
|
-
// style-inject.ts
|
|
25
|
+
// runtime/style-inject.ts
|
|
26
26
|
var MESURER_STYLE_ID = "mesurer-styles";
|
|
27
|
+
var isDocument = (target) => target.nodeType === 9;
|
|
28
|
+
var isShadowRoot = (target) => target.nodeType === 11;
|
|
27
29
|
var getStyleTarget = (target) => {
|
|
28
30
|
if (typeof document === "undefined") return null;
|
|
29
31
|
if (!target) return document;
|
|
30
|
-
if (target
|
|
32
|
+
if (isShadowRoot(target)) return target;
|
|
31
33
|
const rootNode = target.getRootNode();
|
|
32
|
-
if (rootNode
|
|
33
|
-
return document;
|
|
34
|
+
if (rootNode.nodeType === 11) return rootNode;
|
|
35
|
+
return target.ownerDocument ?? document;
|
|
34
36
|
};
|
|
35
37
|
function ensureMeasurerStyles(cssText, target) {
|
|
36
38
|
if (typeof document === "undefined") return;
|
|
@@ -38,31 +40,32 @@ function ensureMeasurerStyles(cssText, target) {
|
|
|
38
40
|
const styleTarget = getStyleTarget(target);
|
|
39
41
|
if (!styleTarget) return;
|
|
40
42
|
if (styleTarget.querySelector(`#${MESURER_STYLE_ID}`)) return;
|
|
41
|
-
const
|
|
43
|
+
const ownerDocument = isDocument(styleTarget) ? styleTarget : styleTarget.ownerDocument;
|
|
44
|
+
if (!ownerDocument) return;
|
|
45
|
+
const style = ownerDocument.createElement("style");
|
|
42
46
|
style.id = MESURER_STYLE_ID;
|
|
43
47
|
style.textContent = cssText;
|
|
44
|
-
if (styleTarget
|
|
48
|
+
if (isShadowRoot(styleTarget)) {
|
|
45
49
|
styleTarget.appendChild(style);
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
|
-
|
|
52
|
+
ownerDocument.head.appendChild(style);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
// styles.generated.ts
|
|
52
|
-
var MESURER_STYLES = '/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root, :host {\n --msr-font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",\n "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";\n --msr-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",\n "Courier New", monospace;\n --msr-color-black: #000;\n --msr-color-white: #fff;\n --msr-spacing: 0.25rem;\n --msr-radius-md: 0.375rem;\n --msr-radius-lg: 0.5rem;\n --msr-default-transition-duration: 150ms;\n --msr-default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --msr-default-font-family: var(--msr-font-sans);\n --msr-default-mono-font-family: var(--msr-font-mono);\n --msr-color-ink-50: var(--color-ink-50);\n --msr-color-ink-200: var(--color-ink-200);\n --msr-color-ink-700: var(--color-ink-700);\n --msr-color-ink-900: var(--color-ink-900);\n }\n}\n@layer base {\n *, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--msr-default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");\n font-feature-settings: var(--msr-default-font-feature-settings, normal);\n font-variation-settings: var(--msr-default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b, strong {\n font-weight: bolder;\n }\n code, kbd, samp, pre {\n font-family: var(--msr-default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);\n font-feature-settings: var(--msr-default-mono-font-feature-settings, normal);\n font-variation-settings: var(--msr-default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol, ul, menu {\n list-style: none;\n }\n img, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n }\n img, video {\n max-width: 100%;\n height: auto;\n }\n button, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden="until-found"])) {\n display: none !important;\n }\n}\n@layer utilities {\n .msr\\:pointer-events-auto {\n pointer-events: auto;\n }\n .msr\\:pointer-events-none {\n pointer-events: none;\n }\n .msr\\:absolute {\n position: absolute;\n }\n .msr\\:fixed {\n position: fixed;\n }\n .msr\\:relative {\n position: relative;\n }\n .msr\\:inset-0 {\n inset: calc(var(--msr-spacing) * 0);\n }\n .msr\\:top-0 {\n top: calc(var(--msr-spacing) * 0);\n }\n .msr\\:top-full {\n top: 100%;\n }\n .msr\\:right-0 {\n right: calc(var(--msr-spacing) * 0);\n }\n .msr\\:bottom-0 {\n bottom: calc(var(--msr-spacing) * 0);\n }\n .msr\\:bottom-full {\n bottom: 100%;\n }\n .msr\\:left-0 {\n left: calc(var(--msr-spacing) * 0);\n }\n .msr\\:left-1\\/2 {\n left: calc(1 / 2 * 100%);\n }\n .msr\\:z-50 {\n z-index: 50;\n }\n .msr\\:z-\\[70\\] {\n z-index: 70;\n }\n .msr\\:z-\\[90\\] {\n z-index: 90;\n }\n .msr\\:mt-2 {\n margin-top: calc(var(--msr-spacing) * 2);\n }\n .msr\\:mb-2 {\n margin-bottom: calc(var(--msr-spacing) * 2);\n }\n .msr\\:-ml-1 {\n margin-left: calc(var(--msr-spacing) * -1);\n }\n .msr\\:flex {\n display: flex;\n }\n .msr\\:size-8 {\n width: calc(var(--msr-spacing) * 8);\n height: calc(var(--msr-spacing) * 8);\n }\n .msr\\:h-8 {\n height: calc(var(--msr-spacing) * 8);\n }\n .msr\\:h-full {\n height: 100%;\n }\n .msr\\:h-px {\n height: 1px;\n }\n .msr\\:w-4 {\n width: calc(var(--msr-spacing) * 4);\n }\n .msr\\:w-44 {\n width: calc(var(--msr-spacing) * 44);\n }\n .msr\\:w-full {\n width: 100%;\n }\n .msr\\:w-px {\n width: 1px;\n }\n .msr\\:flex-1 {\n flex: 1;\n }\n .msr\\:-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .msr\\:-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .msr\\:rotate-90 {\n rotate: 90deg;\n }\n .msr\\:rotate-\\[45deg\\] {\n rotate: 45deg;\n }\n .msr\\:rotate-\\[135deg\\] {\n rotate: 135deg;\n }\n .msr\\:cursor-crosshair {\n cursor: crosshair;\n }\n .msr\\:cursor-default {\n cursor: default;\n }\n .msr\\:flex-col {\n flex-direction: column;\n }\n .msr\\:items-center {\n align-items: center;\n }\n .msr\\:items-stretch {\n align-items: stretch;\n }\n .msr\\:justify-center {\n justify-content: center;\n }\n .msr\\:gap-1 {\n gap: calc(var(--msr-spacing) * 1);\n }\n .msr\\:gap-2 {\n gap: calc(var(--msr-spacing) * 2);\n }\n .msr\\:gap-px {\n gap: 1px;\n }\n .msr\\:rounded {\n border-radius: 0.25rem;\n }\n .msr\\:rounded-\\[6px\\] {\n border-radius: 6px;\n }\n .msr\\:rounded-\\[8px\\] {\n border-radius: 8px;\n }\n .msr\\:rounded-\\[12px\\] {\n border-radius: 12px;\n }\n .msr\\:rounded-lg {\n border-radius: var(--msr-radius-lg);\n }\n .msr\\:rounded-md {\n border-radius: var(--msr-radius-md);\n }\n .msr\\:border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n .msr\\:border-t {\n border-top-style: var(--tw-border-style);\n border-top-width: 1px;\n }\n .msr\\:border-l {\n border-left-style: var(--tw-border-style);\n border-left-width: 1px;\n }\n .msr\\:border-dashed {\n --tw-border-style: dashed;\n border-style: dashed;\n }\n .msr\\:border-\\[\\#2563eb\\]\\/70 {\n border-color: color-mix(in oklab, #2563eb 70%, transparent);\n }\n .msr\\:border-ink-200 {\n border-color: var(--msr-color-ink-200);\n }\n .msr\\:bg-\\[\\#0d99ff\\] {\n background-color: #0d99ff;\n }\n .msr\\:bg-\\[\\#2563eb\\] {\n background-color: #2563eb;\n }\n .msr\\:bg-\\[\\#fff\\] {\n background-color: #fff;\n }\n .msr\\:bg-black {\n background-color: var(--msr-color-black);\n }\n .msr\\:bg-black\\/10 {\n background-color: var(--msr-color-black);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-black) 10%, transparent);\n }\n }\n .msr\\:bg-ink-900\\/90 {\n background-color: var(--msr-color-ink-900);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-ink-900) 90%, transparent);\n }\n }\n .msr\\:bg-transparent {\n background-color: transparent;\n }\n .msr\\:bg-white {\n background-color: var(--msr-color-white);\n }\n .msr\\:p-1 {\n padding: calc(var(--msr-spacing) * 1);\n }\n .msr\\:px-1 {\n padding-inline: calc(var(--msr-spacing) * 1);\n }\n .msr\\:px-2 {\n padding-inline: calc(var(--msr-spacing) * 2);\n }\n .msr\\:py-0\\.5 {\n padding-block: calc(var(--msr-spacing) * 0.5);\n }\n .msr\\:py-1 {\n padding-block: calc(var(--msr-spacing) * 1);\n }\n .msr\\:py-1\\.5 {\n padding-block: calc(var(--msr-spacing) * 1.5);\n }\n .msr\\:text-left {\n text-align: left;\n }\n .msr\\:text-\\[10px\\] {\n font-size: 10px;\n }\n .msr\\:text-\\[11px\\] {\n font-size: 11px;\n }\n .msr\\:text-\\[12px\\] {\n font-size: 12px;\n }\n .msr\\:whitespace-nowrap {\n white-space: nowrap;\n }\n .msr\\:text-black {\n color: var(--msr-color-black);\n }\n .msr\\:text-ink-50 {\n color: var(--msr-color-ink-50);\n }\n .msr\\:text-ink-700 {\n color: var(--msr-color-ink-700);\n }\n .msr\\:text-white {\n color: var(--msr-color-white);\n }\n .msr\\:text-white\\/60 {\n color: var(--msr-color-white);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--msr-color-white) 60%, transparent);\n }\n }\n .msr\\:tabular-nums {\n --tw-numeric-spacing: tabular-nums;\n font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);\n }\n .msr\\:opacity-0 {\n opacity: 0%;\n }\n .msr\\:opacity-100 {\n opacity: 100%;\n }\n .msr\\:outline {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n .msr\\:outline-transparent {\n outline-color: transparent;\n }\n .msr\\:transition-opacity {\n transition-property: opacity;\n transition-timing-function: var(--tw-ease, var(--msr-default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--msr-default-transition-duration));\n }\n .msr\\:duration-150 {\n --tw-duration: 150ms;\n transition-duration: 150ms;\n }\n .msr\\:outline-none {\n --tw-outline-style: none;\n outline-style: none;\n }\n .msr\\:select-none {\n -webkit-user-select: none;\n user-select: none;\n }\n .msr\\:hover\\:bg-\\[\\#0d99ff\\] {\n &:hover {\n @media (hover: hover) {\n background-color: #0d99ff;\n }\n }\n }\n .msr\\:hover\\:bg-black\\/4 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--msr-color-black);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-black) 4%, transparent);\n }\n }\n }\n }\n .msr\\:hover\\:bg-black\\/10 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--msr-color-black);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-black) 10%, transparent);\n }\n }\n }\n }\n .msr\\:hover\\:text-white {\n &:hover {\n @media (hover: hover) {\n color: var(--msr-color-white);\n }\n }\n }\n .msr\\:focus\\:outline-none {\n &:focus {\n --tw-outline-style: none;\n outline-style: none;\n }\n }\n}\n:root, :host {\n --color-ink-50: #f8fafc;\n --color-ink-200: #e2e8f0;\n --color-ink-500: #64748b;\n --color-ink-700: #334155;\n --color-ink-900: #0f172a;\n}\n.mesurer-toolbar-surface {\n box-shadow: 0 0 0.5px rgba(0, 0, 0, 0.18), 0 3px 8px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n.mesurer-menu-surface {\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);\n}\n.mesurer-root {\n --msr-spacing: 4px;\n}\n@property --tw-translate-x {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-border-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-ordinal {\n syntax: "*";\n inherits: false;\n}\n@property --tw-slashed-zero {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-figure {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-spacing {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-fraction {\n syntax: "*";\n inherits: false;\n}\n@property --tw-outline-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-duration {\n syntax: "*";\n inherits: false;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-border-style: solid;\n --tw-ordinal: initial;\n --tw-slashed-zero: initial;\n --tw-numeric-figure: initial;\n --tw-numeric-spacing: initial;\n --tw-numeric-fraction: initial;\n --tw-outline-style: solid;\n --tw-duration: initial;\n }\n }\n}\n';
|
|
56
|
+
var MESURER_STYLES = '/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root, :host {\n --msr-font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",\n "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";\n --msr-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",\n "Courier New", monospace;\n --msr-color-black: #000;\n --msr-color-white: #fff;\n --msr-spacing: 0.25rem;\n --msr-radius-md: 0.375rem;\n --msr-radius-lg: 0.5rem;\n --msr-default-transition-duration: 150ms;\n --msr-default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --msr-default-font-family: var(--msr-font-sans);\n --msr-default-mono-font-family: var(--msr-font-mono);\n --msr-color-ink-50: var(--color-ink-50);\n --msr-color-ink-200: var(--color-ink-200);\n --msr-color-ink-700: var(--color-ink-700);\n --msr-color-ink-900: var(--color-ink-900);\n }\n}\n@layer base {\n *, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--msr-default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");\n font-feature-settings: var(--msr-default-font-feature-settings, normal);\n font-variation-settings: var(--msr-default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b, strong {\n font-weight: bolder;\n }\n code, kbd, samp, pre {\n font-family: var(--msr-default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);\n font-feature-settings: var(--msr-default-mono-font-feature-settings, normal);\n font-variation-settings: var(--msr-default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol, ul, menu {\n list-style: none;\n }\n img, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n }\n img, video {\n max-width: 100%;\n height: auto;\n }\n button, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden="until-found"])) {\n display: none !important;\n }\n}\n@layer utilities {\n .msr\\:pointer-events-auto {\n pointer-events: auto;\n }\n .msr\\:pointer-events-none {\n pointer-events: none;\n }\n .msr\\:absolute {\n position: absolute;\n }\n .msr\\:fixed {\n position: fixed;\n }\n .msr\\:relative {\n position: relative;\n }\n .msr\\:inset-0 {\n inset: calc(var(--msr-spacing) * 0);\n }\n .msr\\:top-0 {\n top: calc(var(--msr-spacing) * 0);\n }\n .msr\\:top-\\[18px\\] {\n top: 18px;\n }\n .msr\\:top-full {\n top: 100%;\n }\n .msr\\:right-0 {\n right: calc(var(--msr-spacing) * 0);\n }\n .msr\\:bottom-0 {\n bottom: calc(var(--msr-spacing) * 0);\n }\n .msr\\:bottom-full {\n bottom: 100%;\n }\n .msr\\:left-0 {\n left: calc(var(--msr-spacing) * 0);\n }\n .msr\\:left-1\\/2 {\n left: calc(1 / 2 * 100%);\n }\n .msr\\:left-\\[18px\\] {\n left: 18px;\n }\n .msr\\:z-50 {\n z-index: 50;\n }\n .msr\\:z-\\[70\\] {\n z-index: 70;\n }\n .msr\\:z-\\[90\\] {\n z-index: 90;\n }\n .msr\\:mt-2 {\n margin-top: calc(var(--msr-spacing) * 2);\n }\n .msr\\:mb-2 {\n margin-bottom: calc(var(--msr-spacing) * 2);\n }\n .msr\\:-ml-1 {\n margin-left: calc(var(--msr-spacing) * -1);\n }\n .msr\\:block {\n display: block;\n }\n .msr\\:flex {\n display: flex;\n }\n .msr\\:size-8 {\n width: calc(var(--msr-spacing) * 8);\n height: calc(var(--msr-spacing) * 8);\n }\n .msr\\:size-\\[18px\\] {\n width: 18px;\n height: 18px;\n }\n .msr\\:h-6 {\n height: calc(var(--msr-spacing) * 6);\n }\n .msr\\:h-8 {\n height: calc(var(--msr-spacing) * 8);\n }\n .msr\\:h-full {\n height: 100%;\n }\n .msr\\:h-px {\n height: 1px;\n }\n .msr\\:w-4 {\n width: calc(var(--msr-spacing) * 4);\n }\n .msr\\:w-6 {\n width: calc(var(--msr-spacing) * 6);\n }\n .msr\\:w-44 {\n width: calc(var(--msr-spacing) * 44);\n }\n .msr\\:w-\\[18px\\] {\n width: 18px;\n }\n .msr\\:w-full {\n width: 100%;\n }\n .msr\\:w-px {\n width: 1px;\n }\n .msr\\:flex-1 {\n flex: 1;\n }\n .msr\\:-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .msr\\:-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .msr\\:rotate-90 {\n rotate: 90deg;\n }\n .msr\\:rotate-\\[45deg\\] {\n rotate: 45deg;\n }\n .msr\\:rotate-\\[135deg\\] {\n rotate: 135deg;\n }\n .msr\\:cursor-crosshair {\n cursor: crosshair;\n }\n .msr\\:cursor-default {\n cursor: default;\n }\n .msr\\:flex-col {\n flex-direction: column;\n }\n .msr\\:items-center {\n align-items: center;\n }\n .msr\\:items-stretch {\n align-items: stretch;\n }\n .msr\\:justify-center {\n justify-content: center;\n }\n .msr\\:gap-1 {\n gap: calc(var(--msr-spacing) * 1);\n }\n .msr\\:gap-2 {\n gap: calc(var(--msr-spacing) * 2);\n }\n .msr\\:gap-px {\n gap: 1px;\n }\n .msr\\:overflow-hidden {\n overflow: hidden;\n }\n .msr\\:rounded {\n border-radius: 0.25rem;\n }\n .msr\\:rounded-\\[6px\\] {\n border-radius: 6px;\n }\n .msr\\:rounded-\\[8px\\] {\n border-radius: 8px;\n }\n .msr\\:rounded-\\[12px\\] {\n border-radius: 12px;\n }\n .msr\\:rounded-lg {\n border-radius: var(--msr-radius-lg);\n }\n .msr\\:rounded-md {\n border-radius: var(--msr-radius-md);\n }\n .msr\\:border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n .msr\\:border-t {\n border-top-style: var(--tw-border-style);\n border-top-width: 1px;\n }\n .msr\\:border-l {\n border-left-style: var(--tw-border-style);\n border-left-width: 1px;\n }\n .msr\\:border-dashed {\n --tw-border-style: dashed;\n border-style: dashed;\n }\n .msr\\:border-\\[\\#2563eb\\]\\/70 {\n border-color: color-mix(in oklab, #2563eb 70%, transparent);\n }\n .msr\\:border-ink-200 {\n border-color: var(--msr-color-ink-200);\n }\n .msr\\:bg-\\[\\#0d99ff\\] {\n background-color: #0d99ff;\n }\n .msr\\:bg-\\[\\#2563eb\\] {\n background-color: #2563eb;\n }\n .msr\\:bg-\\[\\#fff\\] {\n background-color: #fff;\n }\n .msr\\:bg-black {\n background-color: var(--msr-color-black);\n }\n .msr\\:bg-black\\/10 {\n background-color: var(--msr-color-black);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-black) 10%, transparent);\n }\n }\n .msr\\:bg-ink-900\\/90 {\n background-color: var(--msr-color-ink-900);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-ink-900) 90%, transparent);\n }\n }\n .msr\\:bg-transparent {\n background-color: transparent;\n }\n .msr\\:bg-white {\n background-color: var(--msr-color-white);\n }\n .msr\\:p-1 {\n padding: calc(var(--msr-spacing) * 1);\n }\n .msr\\:px-1 {\n padding-inline: calc(var(--msr-spacing) * 1);\n }\n .msr\\:px-2 {\n padding-inline: calc(var(--msr-spacing) * 2);\n }\n .msr\\:py-0\\.5 {\n padding-block: calc(var(--msr-spacing) * 0.5);\n }\n .msr\\:py-1 {\n padding-block: calc(var(--msr-spacing) * 1);\n }\n .msr\\:py-1\\.5 {\n padding-block: calc(var(--msr-spacing) * 1.5);\n }\n .msr\\:text-left {\n text-align: left;\n }\n .msr\\:text-\\[9px\\] {\n font-size: 9px;\n }\n .msr\\:text-\\[10px\\] {\n font-size: 10px;\n }\n .msr\\:text-\\[11px\\] {\n font-size: 11px;\n }\n .msr\\:text-\\[12px\\] {\n font-size: 12px;\n }\n .msr\\:whitespace-nowrap {\n white-space: nowrap;\n }\n .msr\\:text-\\[\\#64748b\\] {\n color: #64748b;\n }\n .msr\\:text-black {\n color: var(--msr-color-black);\n }\n .msr\\:text-ink-50 {\n color: var(--msr-color-ink-50);\n }\n .msr\\:text-ink-700 {\n color: var(--msr-color-ink-700);\n }\n .msr\\:text-white {\n color: var(--msr-color-white);\n }\n .msr\\:text-white\\/60 {\n color: var(--msr-color-white);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--msr-color-white) 60%, transparent);\n }\n }\n .msr\\:tabular-nums {\n --tw-numeric-spacing: tabular-nums;\n font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);\n }\n .msr\\:opacity-0 {\n opacity: 0%;\n }\n .msr\\:opacity-100 {\n opacity: 100%;\n }\n .msr\\:outline {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n .msr\\:outline-transparent {\n outline-color: transparent;\n }\n .msr\\:transition-opacity {\n transition-property: opacity;\n transition-timing-function: var(--tw-ease, var(--msr-default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--msr-default-transition-duration));\n }\n .msr\\:transition-none {\n transition-property: none;\n }\n .msr\\:duration-150 {\n --tw-duration: 150ms;\n transition-duration: 150ms;\n }\n .msr\\:outline-none {\n --tw-outline-style: none;\n outline-style: none;\n }\n .msr\\:select-none {\n -webkit-user-select: none;\n user-select: none;\n }\n .msr\\:hover\\:bg-\\[\\#0d99ff\\] {\n &:hover {\n @media (hover: hover) {\n background-color: #0d99ff;\n }\n }\n }\n .msr\\:hover\\:bg-black\\/4 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--msr-color-black);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-black) 4%, transparent);\n }\n }\n }\n }\n .msr\\:hover\\:bg-black\\/10 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--msr-color-black);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--msr-color-black) 10%, transparent);\n }\n }\n }\n }\n .msr\\:hover\\:text-white {\n &:hover {\n @media (hover: hover) {\n color: var(--msr-color-white);\n }\n }\n }\n .msr\\:focus\\:outline-none {\n &:focus {\n --tw-outline-style: none;\n outline-style: none;\n }\n }\n}\n:root, :host {\n --color-ink-50: #f8fafc;\n --color-ink-200: #e2e8f0;\n --color-ink-500: #64748b;\n --color-ink-700: #334155;\n --color-ink-900: #0f172a;\n}\n.mesurer-toolbar-surface {\n box-shadow: 0 0 0.5px rgba(0, 0, 0, 0.18), 0 3px 8px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n.mesurer-menu-surface {\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);\n}\n.mesurer-root {\n --msr-spacing: 4px;\n}\n@property --tw-translate-x {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-border-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-ordinal {\n syntax: "*";\n inherits: false;\n}\n@property --tw-slashed-zero {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-figure {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-spacing {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-fraction {\n syntax: "*";\n inherits: false;\n}\n@property --tw-outline-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-duration {\n syntax: "*";\n inherits: false;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-border-style: solid;\n --tw-ordinal: initial;\n --tw-slashed-zero: initial;\n --tw-numeric-figure: initial;\n --tw-numeric-spacing: initial;\n --tw-numeric-fraction: initial;\n --tw-outline-style: solid;\n --tw-duration: initial;\n }\n }\n}\n';
|
|
53
57
|
|
|
54
58
|
// components/toolbar.tsx
|
|
55
59
|
import {
|
|
56
60
|
forwardRef,
|
|
57
61
|
memo,
|
|
58
62
|
useCallback,
|
|
59
|
-
useEffect,
|
|
60
63
|
useLayoutEffect,
|
|
61
64
|
useRef,
|
|
62
65
|
useState
|
|
63
66
|
} from "react";
|
|
64
67
|
|
|
65
|
-
// utils.ts
|
|
68
|
+
// core/utils.ts
|
|
66
69
|
var formatValue = (value) => Math.round(value);
|
|
67
70
|
var cn = (...inputs) => inputs.filter(Boolean).join(" ");
|
|
68
71
|
var createId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now()}-${Math.random()}`;
|
|
@@ -82,9 +85,57 @@ var IconBase = ({ size = 24, ...props }) => /* @__PURE__ */ jsx(
|
|
|
82
85
|
);
|
|
83
86
|
var CursorIcon = ({ size = 20, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M166.59,134.1a1.91,1.91,0,0,1-.55-1.79,2,2,0,0,1,1.08-1.42l46.25-17.76.24-.1A14,14,0,0,0,212.38,87L52.29,34.7A13.95,13.95,0,0,0,34.7,52.29L87,212.38a13.82,13.82,0,0,0,12.6,9.6c.23,0,.46,0,.69,0A13.84,13.84,0,0,0,113,213.61a2.44,2.44,0,0,0,.1-.24l17.76-46.25a2,2,0,0,1,3.21-.53l51.31,51.31a14,14,0,0,0,19.8,0l12.69-12.69a14,14,0,0,0,0-19.8Zm42.82,62.63-12.68,12.68a2,2,0,0,1-2.83,0L142.59,158.1a14,14,0,0,0-22.74,4.32,2.44,2.44,0,0,0-.1.24L102,208.91a2,2,0,0,1-3.61-.26L46.11,48.57a1.87,1.87,0,0,1,.47-2A1.92,1.92,0,0,1,47.93,46a2.22,2.22,0,0,1,.64.1L208.65,98.38a2,2,0,0,1,.26,3.61l-46.25,17.76-.24.1a14,14,0,0,0-4.32,22.74h0l51.31,51.31A2,2,0,0,1,209.41,196.73Z" }) });
|
|
84
87
|
var RulerIcon = ({ size = 20, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M233.91,74.79,181.22,22.1a14,14,0,0,0-19.8,0L22.09,161.41a14,14,0,0,0,0,19.8L74.78,233.9a14,14,0,0,0,19.8,0L233.91,94.59A14,14,0,0,0,233.91,74.79ZM225.42,86.1,86.1,225.41h0a2,2,0,0,1-2.83,0L30.58,172.73a2,2,0,0,1,0-2.83L64,136.48l27.76,27.76a6,6,0,1,0,8.48-8.48L72.48,128,96,104.48l27.76,27.76a6,6,0,0,0,8.48-8.48L104.48,96,128,72.49l27.76,27.75a6,6,0,0,0,8.48-8.48L136.49,64,169.9,30.59a2,2,0,0,1,2.83,0l52.69,52.68A2,2,0,0,1,225.42,86.1Z" }) });
|
|
88
|
+
var XrayIcon = ({ size = 20, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx(
|
|
89
|
+
"path",
|
|
90
|
+
{
|
|
91
|
+
fill: "none",
|
|
92
|
+
stroke: "currentColor",
|
|
93
|
+
strokeLinecap: "round",
|
|
94
|
+
strokeLinejoin: "round",
|
|
95
|
+
strokeWidth: "12",
|
|
96
|
+
strokeOpacity: "0.78",
|
|
97
|
+
d: "M76 48h96a16 16 0 0 1 16 16v96a16 16 0 0 1-16 16H76a16 16 0 0 1-16-16V64a16 16 0 0 1 16-16Zm32 32h96a16 16 0 0 1 16 16v96a16 16 0 0 1-16 16h-96a16 16 0 0 1-16-16V96a16 16 0 0 1 16-16Z"
|
|
98
|
+
}
|
|
99
|
+
) });
|
|
100
|
+
var RulersIcon = ({ size = 20, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx(
|
|
101
|
+
"path",
|
|
102
|
+
{
|
|
103
|
+
fill: "none",
|
|
104
|
+
stroke: "currentColor",
|
|
105
|
+
strokeLinecap: "round",
|
|
106
|
+
strokeLinejoin: "round",
|
|
107
|
+
strokeWidth: "12",
|
|
108
|
+
d: "M48 208V48h160M80 48v24m32-24v24m32-24v24m32-24v24M48 80h24M48 112h24m-24 32h24m-24 32h24"
|
|
109
|
+
}
|
|
110
|
+
) });
|
|
85
111
|
var CaretDownIcon = ({ size = 8, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z" }) });
|
|
86
112
|
var CheckIcon = ({ size = 12, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M232.49,80.49l-128,128a12,12,0,0,1-17,0l-56-56a12,12,0,1,1,17-17L96,183,215.51,63.51a12,12,0,0,1,17,17Z" }) });
|
|
87
113
|
var MinusIcon = ({ size = 12, ...props }) => /* @__PURE__ */ jsx(IconBase, { size, ...props, children: /* @__PURE__ */ jsx("path", { d: "M228,128a12,12,0,0,1-12,12H40a12,12,0,0,1,0-24H216A12,12,0,0,1,228,128Z" }) });
|
|
114
|
+
var TextInspectorIcon = ({ size = 20, ...props }) => /* @__PURE__ */ jsx(
|
|
115
|
+
"svg",
|
|
116
|
+
{
|
|
117
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
118
|
+
width: size,
|
|
119
|
+
height: size,
|
|
120
|
+
viewBox: "0 0 256 256",
|
|
121
|
+
fill: "currentColor",
|
|
122
|
+
...props,
|
|
123
|
+
children: /* @__PURE__ */ jsx(
|
|
124
|
+
"text",
|
|
125
|
+
{
|
|
126
|
+
x: "50%",
|
|
127
|
+
y: "60%",
|
|
128
|
+
textAnchor: "middle",
|
|
129
|
+
dominantBaseline: "middle",
|
|
130
|
+
fill: "currentColor",
|
|
131
|
+
fontFamily: "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif",
|
|
132
|
+
fontWeight: 300,
|
|
133
|
+
fontSize: 220,
|
|
134
|
+
children: "Aa"
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
);
|
|
88
139
|
|
|
89
140
|
// components/toolbar.tsx
|
|
90
141
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
@@ -99,6 +150,7 @@ function ToolbarButton({
|
|
|
99
150
|
shortcut,
|
|
100
151
|
onClick,
|
|
101
152
|
tooltipVisible,
|
|
153
|
+
tooltipInstant,
|
|
102
154
|
tooltipSide,
|
|
103
155
|
onTooltipEnter,
|
|
104
156
|
onTooltipLeave,
|
|
@@ -116,6 +168,7 @@ function ToolbarButton({
|
|
|
116
168
|
{
|
|
117
169
|
type: "button",
|
|
118
170
|
"aria-label": `${label} (${shortcut})`,
|
|
171
|
+
"aria-pressed": active,
|
|
119
172
|
title: `${label} (${shortcut})`,
|
|
120
173
|
className: cn(
|
|
121
174
|
"msr:flex msr:size-8 msr:items-center msr:justify-center msr:rounded-[8px] msr:outline-none",
|
|
@@ -129,7 +182,10 @@ function ToolbarButton({
|
|
|
129
182
|
"span",
|
|
130
183
|
{
|
|
131
184
|
className: cn(
|
|
132
|
-
|
|
185
|
+
cn(
|
|
186
|
+
"msr:pointer-events-none msr:absolute msr:left-1/2 msr:-translate-x-1/2 msr:whitespace-nowrap msr:rounded msr:bg-black msr:px-2 msr:py-1 msr:text-[11px] msr:text-white msr:transition-opacity msr:duration-150 msr:select-none",
|
|
187
|
+
tooltipInstant && "msr:transition-none"
|
|
188
|
+
),
|
|
133
189
|
tooltipSide === "top" ? "msr:bottom-full msr:mb-2" : "msr:top-full msr:mt-2",
|
|
134
190
|
tooltipVisible ? "msr:opacity-100" : "msr:opacity-0"
|
|
135
191
|
),
|
|
@@ -148,6 +204,7 @@ function useToolbarTooltip() {
|
|
|
148
204
|
const [visibleTooltipId, setVisibleTooltipId] = useState(null);
|
|
149
205
|
const timerRef = useRef(null);
|
|
150
206
|
const instantRef = useRef(false);
|
|
207
|
+
const [tooltipInstant, setTooltipInstant] = useState(false);
|
|
151
208
|
const clearTimer = useCallback(() => {
|
|
152
209
|
if (timerRef.current === null) return;
|
|
153
210
|
window.clearTimeout(timerRef.current);
|
|
@@ -157,9 +214,11 @@ function useToolbarTooltip() {
|
|
|
157
214
|
(id) => {
|
|
158
215
|
clearTimer();
|
|
159
216
|
if (instantRef.current) {
|
|
217
|
+
setTooltipInstant(true);
|
|
160
218
|
setVisibleTooltipId(id);
|
|
161
219
|
return;
|
|
162
220
|
}
|
|
221
|
+
setTooltipInstant(false);
|
|
163
222
|
timerRef.current = window.setTimeout(() => {
|
|
164
223
|
setVisibleTooltipId(id);
|
|
165
224
|
instantRef.current = true;
|
|
@@ -179,15 +238,17 @@ function useToolbarTooltip() {
|
|
|
179
238
|
clearTimer();
|
|
180
239
|
setVisibleTooltipId(null);
|
|
181
240
|
instantRef.current = false;
|
|
241
|
+
setTooltipInstant(false);
|
|
182
242
|
}, [clearTimer]);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
243
|
+
return {
|
|
244
|
+
visibleTooltipId,
|
|
245
|
+
tooltipInstant,
|
|
246
|
+
onTooltipEnter,
|
|
247
|
+
onTooltipLeave,
|
|
248
|
+
onToolbarLeave
|
|
249
|
+
};
|
|
189
250
|
}
|
|
190
|
-
function useToolbarDrag(initialPosition) {
|
|
251
|
+
function useToolbarDrag(initialPosition, eventTarget) {
|
|
191
252
|
const [position, setPosition] = useState(initialPosition);
|
|
192
253
|
const suppressClickRef = useRef(false);
|
|
193
254
|
const detachListenersRef = useRef(null);
|
|
@@ -230,8 +291,8 @@ function useToolbarDrag(initialPosition) {
|
|
|
230
291
|
}
|
|
231
292
|
if (!current.active) return;
|
|
232
293
|
current.didDrag = true;
|
|
233
|
-
const maxX = Math.max(8,
|
|
234
|
-
const maxY = Math.max(8,
|
|
294
|
+
const maxX = Math.max(8, eventTarget.innerWidth - current.width - 8);
|
|
295
|
+
const maxY = Math.max(8, eventTarget.innerHeight - current.height - 8);
|
|
235
296
|
setPosition({
|
|
236
297
|
x: Math.min(maxX, Math.max(8, current.originX + dx)),
|
|
237
298
|
y: Math.min(maxY, Math.max(8, current.originY + dy))
|
|
@@ -245,21 +306,21 @@ function useToolbarDrag(initialPosition) {
|
|
|
245
306
|
current.active = false;
|
|
246
307
|
current.didDrag = false;
|
|
247
308
|
current.pointerId = -1;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
309
|
+
eventTarget.removeEventListener("pointermove", handlePointerMove);
|
|
310
|
+
eventTarget.removeEventListener("pointerup", handlePointerEnd);
|
|
311
|
+
eventTarget.removeEventListener("pointercancel", handlePointerEnd);
|
|
251
312
|
detachListenersRef.current = null;
|
|
252
313
|
};
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
314
|
+
eventTarget.addEventListener("pointermove", handlePointerMove);
|
|
315
|
+
eventTarget.addEventListener("pointerup", handlePointerEnd);
|
|
316
|
+
eventTarget.addEventListener("pointercancel", handlePointerEnd);
|
|
256
317
|
detachListenersRef.current = () => {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
318
|
+
eventTarget.removeEventListener("pointermove", handlePointerMove);
|
|
319
|
+
eventTarget.removeEventListener("pointerup", handlePointerEnd);
|
|
320
|
+
eventTarget.removeEventListener("pointercancel", handlePointerEnd);
|
|
260
321
|
};
|
|
261
322
|
},
|
|
262
|
-
[position.x, position.y]
|
|
323
|
+
[eventTarget, position.x, position.y]
|
|
263
324
|
);
|
|
264
325
|
const onClickCapture = useCallback(
|
|
265
326
|
(event) => {
|
|
@@ -276,15 +337,24 @@ function ToolbarComponent({
|
|
|
276
337
|
toolMode,
|
|
277
338
|
setEnabled,
|
|
278
339
|
setToolMode,
|
|
340
|
+
rulersVisible,
|
|
341
|
+
setRulersVisible,
|
|
279
342
|
guideOrientation,
|
|
280
343
|
setGuideOrientation,
|
|
281
|
-
onInteract
|
|
344
|
+
onInteract,
|
|
345
|
+
eventTarget
|
|
282
346
|
}, ref) {
|
|
283
347
|
const { position, onPointerDown, onClickCapture } = useToolbarDrag({
|
|
284
348
|
x: 16,
|
|
285
349
|
y: 16
|
|
286
|
-
});
|
|
287
|
-
const {
|
|
350
|
+
}, eventTarget);
|
|
351
|
+
const {
|
|
352
|
+
visibleTooltipId,
|
|
353
|
+
tooltipInstant,
|
|
354
|
+
onTooltipEnter,
|
|
355
|
+
onTooltipLeave,
|
|
356
|
+
onToolbarLeave
|
|
357
|
+
} = useToolbarTooltip();
|
|
288
358
|
const [guideMenuOpen, setGuideMenuOpen] = useState(false);
|
|
289
359
|
const guideMenuRef = useRef(null);
|
|
290
360
|
const [activeMenuIndex, setActiveMenuIndex] = useState(0);
|
|
@@ -298,13 +368,13 @@ function ToolbarComponent({
|
|
|
298
368
|
setMenuAlign("left");
|
|
299
369
|
return;
|
|
300
370
|
}
|
|
301
|
-
if (leftAlignedRight >
|
|
371
|
+
if (leftAlignedRight > eventTarget.innerWidth - VIEWPORT_PADDING) {
|
|
302
372
|
setMenuAlign("right");
|
|
303
373
|
return;
|
|
304
374
|
}
|
|
305
375
|
setMenuAlign("right");
|
|
306
|
-
}, []);
|
|
307
|
-
const viewportHeight =
|
|
376
|
+
}, [eventTarget]);
|
|
377
|
+
const viewportHeight = eventTarget.innerHeight || 0;
|
|
308
378
|
const nearTop = position.y < 56;
|
|
309
379
|
const nearBottom = viewportHeight > 0 && position.y > viewportHeight - 56;
|
|
310
380
|
const tooltipSide = nearTop && !nearBottom ? "bottom" : "top";
|
|
@@ -319,6 +389,23 @@ function ToolbarComponent({
|
|
|
319
389
|
setToolMode((prev) => prev === "guides" ? "none" : "guides");
|
|
320
390
|
onInteract();
|
|
321
391
|
}, [onInteract, setEnabled, setToolMode]);
|
|
392
|
+
const textInspectorMode = useCallback(() => {
|
|
393
|
+
setEnabled(true);
|
|
394
|
+
setToolMode(
|
|
395
|
+
(prev) => prev === "text-inspector" ? "none" : "text-inspector"
|
|
396
|
+
);
|
|
397
|
+
onInteract();
|
|
398
|
+
}, [onInteract, setEnabled, setToolMode]);
|
|
399
|
+
const xrayMode = useCallback(() => {
|
|
400
|
+
setEnabled(true);
|
|
401
|
+
setToolMode((prev) => prev === "xray" ? "none" : "xray");
|
|
402
|
+
onInteract();
|
|
403
|
+
}, [onInteract, setEnabled, setToolMode]);
|
|
404
|
+
const rulersMode = useCallback(() => {
|
|
405
|
+
setEnabled(true);
|
|
406
|
+
setRulersVisible((prev) => !prev);
|
|
407
|
+
onInteract();
|
|
408
|
+
}, [onInteract, setEnabled, setRulersVisible]);
|
|
322
409
|
const selectGuideOrientation = useCallback(
|
|
323
410
|
(orientation) => {
|
|
324
411
|
setEnabled(true);
|
|
@@ -331,7 +418,7 @@ function ToolbarComponent({
|
|
|
331
418
|
);
|
|
332
419
|
useLayoutEffect(() => {
|
|
333
420
|
if (!guideMenuOpen) return;
|
|
334
|
-
const frame = requestAnimationFrame(() => {
|
|
421
|
+
const frame = eventTarget.requestAnimationFrame(() => {
|
|
335
422
|
guideMenuRef.current?.querySelector("[role='menu']")?.focus();
|
|
336
423
|
});
|
|
337
424
|
const handlePointerDown = (event) => {
|
|
@@ -344,14 +431,14 @@ function ToolbarComponent({
|
|
|
344
431
|
const handleResize = () => {
|
|
345
432
|
updateMenuAlign();
|
|
346
433
|
};
|
|
347
|
-
|
|
348
|
-
|
|
434
|
+
eventTarget.addEventListener("pointerdown", handlePointerDown);
|
|
435
|
+
eventTarget.addEventListener("resize", handleResize);
|
|
349
436
|
return () => {
|
|
350
|
-
cancelAnimationFrame(frame);
|
|
351
|
-
|
|
352
|
-
|
|
437
|
+
eventTarget.cancelAnimationFrame(frame);
|
|
438
|
+
eventTarget.removeEventListener("pointerdown", handlePointerDown);
|
|
439
|
+
eventTarget.removeEventListener("resize", handleResize);
|
|
353
440
|
};
|
|
354
|
-
}, [guideMenuOpen, guideOrientation, updateMenuAlign]);
|
|
441
|
+
}, [eventTarget, guideMenuOpen, guideOrientation, updateMenuAlign]);
|
|
355
442
|
return /* @__PURE__ */ jsxs(
|
|
356
443
|
"div",
|
|
357
444
|
{
|
|
@@ -374,12 +461,61 @@ function ToolbarComponent({
|
|
|
374
461
|
shortcut: "S",
|
|
375
462
|
onClick: selectMode,
|
|
376
463
|
tooltipVisible: visibleTooltipId === "select",
|
|
464
|
+
tooltipInstant,
|
|
377
465
|
tooltipSide,
|
|
378
466
|
onTooltipEnter,
|
|
379
467
|
onTooltipLeave,
|
|
380
468
|
children: /* @__PURE__ */ jsx2(CursorIcon, { size: 20 })
|
|
381
469
|
}
|
|
382
470
|
),
|
|
471
|
+
/* @__PURE__ */ jsx2(
|
|
472
|
+
ToolbarButton,
|
|
473
|
+
{
|
|
474
|
+
id: "xray",
|
|
475
|
+
active: toolMode === "xray",
|
|
476
|
+
label: "X-ray",
|
|
477
|
+
shortcut: "X",
|
|
478
|
+
onClick: xrayMode,
|
|
479
|
+
tooltipVisible: visibleTooltipId === "xray",
|
|
480
|
+
tooltipInstant,
|
|
481
|
+
tooltipSide,
|
|
482
|
+
onTooltipEnter,
|
|
483
|
+
onTooltipLeave,
|
|
484
|
+
children: /* @__PURE__ */ jsx2(XrayIcon, { size: 20 })
|
|
485
|
+
}
|
|
486
|
+
),
|
|
487
|
+
/* @__PURE__ */ jsx2(
|
|
488
|
+
ToolbarButton,
|
|
489
|
+
{
|
|
490
|
+
id: "rulers",
|
|
491
|
+
active: rulersVisible,
|
|
492
|
+
label: "Rulers",
|
|
493
|
+
shortcut: "R",
|
|
494
|
+
onClick: rulersMode,
|
|
495
|
+
tooltipVisible: visibleTooltipId === "rulers",
|
|
496
|
+
tooltipInstant,
|
|
497
|
+
tooltipSide,
|
|
498
|
+
onTooltipEnter,
|
|
499
|
+
onTooltipLeave,
|
|
500
|
+
children: /* @__PURE__ */ jsx2(RulersIcon, { size: 20 })
|
|
501
|
+
}
|
|
502
|
+
),
|
|
503
|
+
/* @__PURE__ */ jsx2(
|
|
504
|
+
ToolbarButton,
|
|
505
|
+
{
|
|
506
|
+
id: "text-inspector",
|
|
507
|
+
active: toolMode === "text-inspector",
|
|
508
|
+
label: "Text inspector",
|
|
509
|
+
shortcut: "A",
|
|
510
|
+
onClick: textInspectorMode,
|
|
511
|
+
tooltipVisible: visibleTooltipId === "text-inspector",
|
|
512
|
+
tooltipInstant,
|
|
513
|
+
tooltipSide,
|
|
514
|
+
onTooltipEnter,
|
|
515
|
+
onTooltipLeave,
|
|
516
|
+
children: /* @__PURE__ */ jsx2(TextInspectorIcon, { size: 20, "aria-hidden": "true" })
|
|
517
|
+
}
|
|
518
|
+
),
|
|
383
519
|
/* @__PURE__ */ jsx2(
|
|
384
520
|
ToolbarButton,
|
|
385
521
|
{
|
|
@@ -389,6 +525,7 @@ function ToolbarComponent({
|
|
|
389
525
|
shortcut: "G",
|
|
390
526
|
onClick: guidesMode,
|
|
391
527
|
tooltipVisible: visibleTooltipId === "guides",
|
|
528
|
+
tooltipInstant,
|
|
392
529
|
tooltipSide,
|
|
393
530
|
onTooltipEnter,
|
|
394
531
|
onTooltipLeave,
|
|
@@ -548,23 +685,328 @@ function ToolbarComponent({
|
|
|
548
685
|
}
|
|
549
686
|
var Toolbar = memo(forwardRef(ToolbarComponent));
|
|
550
687
|
|
|
688
|
+
// components/rulers-overlay.tsx
|
|
689
|
+
import { memo as memo2, useRef as useRef2, useState as useState2 } from "react";
|
|
690
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
691
|
+
var RULER_SIZE = 18;
|
|
692
|
+
var RULER_LENGTH = 4e3;
|
|
693
|
+
var TICK_STEP = 5;
|
|
694
|
+
var ticks = Array.from(
|
|
695
|
+
{ length: RULER_LENGTH / TICK_STEP + 1 },
|
|
696
|
+
(_, index) => index * TICK_STEP
|
|
697
|
+
);
|
|
698
|
+
var RulersOverlay = memo2(function RulersOverlay2({
|
|
699
|
+
onStartGuide,
|
|
700
|
+
onMoveGuide,
|
|
701
|
+
onFinishGuide,
|
|
702
|
+
onCancelGuide,
|
|
703
|
+
guides,
|
|
704
|
+
selectedGuideIds
|
|
705
|
+
}) {
|
|
706
|
+
const [dragPosition, setDragPosition] = useState2(null);
|
|
707
|
+
const [dragOrientation, setDragOrientation] = useState2(null);
|
|
708
|
+
const dragRef = useRef2(null);
|
|
709
|
+
const beginGuideDrag = (orientation, event) => {
|
|
710
|
+
if (event.button !== 0) return;
|
|
711
|
+
event.stopPropagation();
|
|
712
|
+
const position = orientation === "horizontal" ? event.clientY : event.clientX;
|
|
713
|
+
setDragPosition(position);
|
|
714
|
+
setDragOrientation(orientation);
|
|
715
|
+
dragRef.current = {
|
|
716
|
+
orientation,
|
|
717
|
+
pointerId: event.pointerId,
|
|
718
|
+
id: onStartGuide(orientation, position)
|
|
719
|
+
};
|
|
720
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
721
|
+
};
|
|
722
|
+
const moveGuide = (event) => {
|
|
723
|
+
const drag = dragRef.current;
|
|
724
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
725
|
+
event.stopPropagation();
|
|
726
|
+
const position = drag.orientation === "horizontal" ? event.clientY : event.clientX;
|
|
727
|
+
setDragPosition(position);
|
|
728
|
+
onMoveGuide(drag.id, position);
|
|
729
|
+
};
|
|
730
|
+
const finishGuideDrag = (event) => {
|
|
731
|
+
const drag = dragRef.current;
|
|
732
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
733
|
+
event.stopPropagation();
|
|
734
|
+
const position = drag.orientation === "horizontal" ? event.clientY : event.clientX;
|
|
735
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
736
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
737
|
+
}
|
|
738
|
+
dragRef.current = null;
|
|
739
|
+
setDragPosition(null);
|
|
740
|
+
setDragOrientation(null);
|
|
741
|
+
onMoveGuide(drag.id, position);
|
|
742
|
+
onFinishGuide(drag.id);
|
|
743
|
+
};
|
|
744
|
+
const cancelGuideDrag = (event) => {
|
|
745
|
+
const drag = dragRef.current;
|
|
746
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
747
|
+
dragRef.current = null;
|
|
748
|
+
setDragPosition(null);
|
|
749
|
+
setDragOrientation(null);
|
|
750
|
+
onCancelGuide(drag.id);
|
|
751
|
+
};
|
|
752
|
+
const selectedVerticalGuides = guides.filter(
|
|
753
|
+
(guide) => guide.orientation === "vertical" && selectedGuideIds.includes(guide.id)
|
|
754
|
+
);
|
|
755
|
+
const selectedHorizontalGuides = guides.filter(
|
|
756
|
+
(guide) => guide.orientation === "horizontal" && selectedGuideIds.includes(guide.id)
|
|
757
|
+
);
|
|
758
|
+
return /* @__PURE__ */ jsxs2(
|
|
759
|
+
"div",
|
|
760
|
+
{
|
|
761
|
+
"aria-hidden": "true",
|
|
762
|
+
className: "msr:pointer-events-none msr:absolute msr:inset-0 msr:select-none msr:text-[9px] msr:text-[#64748b]",
|
|
763
|
+
children: [
|
|
764
|
+
/* @__PURE__ */ jsx3(
|
|
765
|
+
"div",
|
|
766
|
+
{
|
|
767
|
+
className: "msr:absolute msr:left-[18px] msr:right-0 msr:top-0 msr:overflow-hidden msr:bg-white",
|
|
768
|
+
style: {
|
|
769
|
+
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.12)",
|
|
770
|
+
height: RULER_SIZE,
|
|
771
|
+
cursor: "ns-resize",
|
|
772
|
+
pointerEvents: "auto"
|
|
773
|
+
},
|
|
774
|
+
onPointerDown: (event) => beginGuideDrag("horizontal", event),
|
|
775
|
+
onPointerMove: moveGuide,
|
|
776
|
+
onPointerUp: finishGuideDrag,
|
|
777
|
+
onPointerCancel: cancelGuideDrag,
|
|
778
|
+
children: /* @__PURE__ */ jsxs2(
|
|
779
|
+
"svg",
|
|
780
|
+
{
|
|
781
|
+
className: "msr:block msr:h-6",
|
|
782
|
+
width: RULER_LENGTH,
|
|
783
|
+
height: RULER_SIZE,
|
|
784
|
+
viewBox: `0 0 ${RULER_LENGTH} ${RULER_SIZE}`,
|
|
785
|
+
children: [
|
|
786
|
+
/* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsxs2(
|
|
787
|
+
"linearGradient",
|
|
788
|
+
{
|
|
789
|
+
id: "ruler-label-fade-x",
|
|
790
|
+
x1: "0%",
|
|
791
|
+
x2: "100%",
|
|
792
|
+
gradientUnits: "objectBoundingBox",
|
|
793
|
+
children: [
|
|
794
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0", stopColor: "white", stopOpacity: "0" }),
|
|
795
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0.2", stopColor: "white" }),
|
|
796
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0.8", stopColor: "white" }),
|
|
797
|
+
/* @__PURE__ */ jsx3("stop", { offset: "1", stopColor: "white", stopOpacity: "0" })
|
|
798
|
+
]
|
|
799
|
+
}
|
|
800
|
+
) }),
|
|
801
|
+
ticks.map((x) => {
|
|
802
|
+
const major = x % 100 === 0;
|
|
803
|
+
const medium = x % 50 === 0;
|
|
804
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
805
|
+
/* @__PURE__ */ jsx3(
|
|
806
|
+
"line",
|
|
807
|
+
{
|
|
808
|
+
x1: x,
|
|
809
|
+
y1: RULER_SIZE,
|
|
810
|
+
x2: x,
|
|
811
|
+
y2: major ? 8 : medium ? 13 : 17,
|
|
812
|
+
stroke: "currentColor",
|
|
813
|
+
strokeWidth: "1"
|
|
814
|
+
}
|
|
815
|
+
),
|
|
816
|
+
major ? /* @__PURE__ */ jsx3("text", { x, y: "8", textAnchor: "middle", fill: "currentColor", children: x }) : null
|
|
817
|
+
] }, x);
|
|
818
|
+
}),
|
|
819
|
+
selectedVerticalGuides.map((guide) => /* @__PURE__ */ jsxs2("g", { children: [
|
|
820
|
+
/* @__PURE__ */ jsx3(
|
|
821
|
+
"rect",
|
|
822
|
+
{
|
|
823
|
+
x: guide.position - RULER_SIZE - 8,
|
|
824
|
+
y: "-1",
|
|
825
|
+
width: "48",
|
|
826
|
+
height: "12",
|
|
827
|
+
fill: "url(#ruler-label-fade-x)"
|
|
828
|
+
}
|
|
829
|
+
),
|
|
830
|
+
/* @__PURE__ */ jsx3(
|
|
831
|
+
"text",
|
|
832
|
+
{
|
|
833
|
+
x: guide.position - RULER_SIZE + 16,
|
|
834
|
+
y: "8",
|
|
835
|
+
textAnchor: "middle",
|
|
836
|
+
fill: "#ef4444",
|
|
837
|
+
fontWeight: "600",
|
|
838
|
+
children: Math.round(guide.position - RULER_SIZE)
|
|
839
|
+
}
|
|
840
|
+
)
|
|
841
|
+
] }, guide.id)),
|
|
842
|
+
dragOrientation === "vertical" && dragPosition !== null ? /* @__PURE__ */ jsxs2("g", { children: [
|
|
843
|
+
/* @__PURE__ */ jsx3(
|
|
844
|
+
"rect",
|
|
845
|
+
{
|
|
846
|
+
x: dragPosition - RULER_SIZE - 8,
|
|
847
|
+
y: "-1",
|
|
848
|
+
width: "48",
|
|
849
|
+
height: "12",
|
|
850
|
+
fill: "url(#ruler-label-fade-x)"
|
|
851
|
+
}
|
|
852
|
+
),
|
|
853
|
+
/* @__PURE__ */ jsx3(
|
|
854
|
+
"text",
|
|
855
|
+
{
|
|
856
|
+
x: dragPosition - RULER_SIZE + 16,
|
|
857
|
+
y: "8",
|
|
858
|
+
textAnchor: "middle",
|
|
859
|
+
fill: "#ef4444",
|
|
860
|
+
fontWeight: "600",
|
|
861
|
+
children: Math.round(dragPosition - RULER_SIZE)
|
|
862
|
+
}
|
|
863
|
+
)
|
|
864
|
+
] }) : null
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
)
|
|
868
|
+
}
|
|
869
|
+
),
|
|
870
|
+
/* @__PURE__ */ jsx3(
|
|
871
|
+
"div",
|
|
872
|
+
{
|
|
873
|
+
className: "msr:absolute msr:bottom-0 msr:left-0 msr:top-[18px] msr:w-[18px] msr:overflow-hidden msr:bg-white",
|
|
874
|
+
style: {
|
|
875
|
+
boxShadow: "1px 0 3px rgba(0, 0, 0, 0.12)",
|
|
876
|
+
width: RULER_SIZE,
|
|
877
|
+
cursor: "ew-resize",
|
|
878
|
+
pointerEvents: "auto"
|
|
879
|
+
},
|
|
880
|
+
onPointerDown: (event) => beginGuideDrag("vertical", event),
|
|
881
|
+
onPointerMove: moveGuide,
|
|
882
|
+
onPointerUp: finishGuideDrag,
|
|
883
|
+
onPointerCancel: cancelGuideDrag,
|
|
884
|
+
children: /* @__PURE__ */ jsxs2(
|
|
885
|
+
"svg",
|
|
886
|
+
{
|
|
887
|
+
className: "msr:block msr:w-6",
|
|
888
|
+
width: RULER_SIZE,
|
|
889
|
+
height: RULER_LENGTH,
|
|
890
|
+
viewBox: `0 0 ${RULER_SIZE} ${RULER_LENGTH}`,
|
|
891
|
+
children: [
|
|
892
|
+
/* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsxs2(
|
|
893
|
+
"linearGradient",
|
|
894
|
+
{
|
|
895
|
+
id: "ruler-label-fade-y",
|
|
896
|
+
y1: "0%",
|
|
897
|
+
y2: "100%",
|
|
898
|
+
gradientUnits: "objectBoundingBox",
|
|
899
|
+
children: [
|
|
900
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0", stopColor: "white", stopOpacity: "0" }),
|
|
901
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0.2", stopColor: "white" }),
|
|
902
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0.8", stopColor: "white" }),
|
|
903
|
+
/* @__PURE__ */ jsx3("stop", { offset: "1", stopColor: "white", stopOpacity: "0" })
|
|
904
|
+
]
|
|
905
|
+
}
|
|
906
|
+
) }),
|
|
907
|
+
ticks.map((y) => {
|
|
908
|
+
const major = y % 100 === 0;
|
|
909
|
+
const medium = y % 50 === 0;
|
|
910
|
+
return /* @__PURE__ */ jsxs2("g", { children: [
|
|
911
|
+
/* @__PURE__ */ jsx3(
|
|
912
|
+
"line",
|
|
913
|
+
{
|
|
914
|
+
x1: RULER_SIZE,
|
|
915
|
+
y1: y,
|
|
916
|
+
x2: major ? 8 : medium ? 13 : 17,
|
|
917
|
+
y2: y,
|
|
918
|
+
stroke: "currentColor",
|
|
919
|
+
strokeWidth: "1"
|
|
920
|
+
}
|
|
921
|
+
),
|
|
922
|
+
major ? /* @__PURE__ */ jsx3(
|
|
923
|
+
"text",
|
|
924
|
+
{
|
|
925
|
+
x: "8",
|
|
926
|
+
y: y + 10,
|
|
927
|
+
fill: "currentColor",
|
|
928
|
+
transform: `rotate(-90 8 ${y + 10})`,
|
|
929
|
+
children: y
|
|
930
|
+
}
|
|
931
|
+
) : null
|
|
932
|
+
] }, y);
|
|
933
|
+
}),
|
|
934
|
+
selectedHorizontalGuides.map((guide) => /* @__PURE__ */ jsxs2("g", { children: [
|
|
935
|
+
/* @__PURE__ */ jsx3(
|
|
936
|
+
"rect",
|
|
937
|
+
{
|
|
938
|
+
x: "-3",
|
|
939
|
+
y: guide.position - RULER_SIZE - 38,
|
|
940
|
+
width: "24",
|
|
941
|
+
height: "48",
|
|
942
|
+
fill: "url(#ruler-label-fade-y)"
|
|
943
|
+
}
|
|
944
|
+
),
|
|
945
|
+
/* @__PURE__ */ jsx3(
|
|
946
|
+
"text",
|
|
947
|
+
{
|
|
948
|
+
x: "9",
|
|
949
|
+
y: guide.position - RULER_SIZE - 16,
|
|
950
|
+
textAnchor: "middle",
|
|
951
|
+
fill: "#ef4444",
|
|
952
|
+
fontWeight: "600",
|
|
953
|
+
transform: `rotate(-90 9 ${guide.position - RULER_SIZE - 16})`,
|
|
954
|
+
children: Math.round(guide.position - RULER_SIZE)
|
|
955
|
+
}
|
|
956
|
+
)
|
|
957
|
+
] }, guide.id)),
|
|
958
|
+
dragOrientation === "horizontal" && dragPosition !== null ? /* @__PURE__ */ jsxs2("g", { children: [
|
|
959
|
+
/* @__PURE__ */ jsx3(
|
|
960
|
+
"rect",
|
|
961
|
+
{
|
|
962
|
+
x: "-3",
|
|
963
|
+
y: dragPosition - RULER_SIZE - 38,
|
|
964
|
+
width: "24",
|
|
965
|
+
height: "48",
|
|
966
|
+
fill: "url(#ruler-label-fade-y)"
|
|
967
|
+
}
|
|
968
|
+
),
|
|
969
|
+
/* @__PURE__ */ jsx3(
|
|
970
|
+
"text",
|
|
971
|
+
{
|
|
972
|
+
x: "9",
|
|
973
|
+
y: dragPosition - RULER_SIZE - 16,
|
|
974
|
+
textAnchor: "middle",
|
|
975
|
+
fill: "#ef4444",
|
|
976
|
+
fontWeight: "600",
|
|
977
|
+
transform: `rotate(-90 9 ${dragPosition - RULER_SIZE - 16})`,
|
|
978
|
+
children: Math.round(dragPosition - RULER_SIZE)
|
|
979
|
+
}
|
|
980
|
+
)
|
|
981
|
+
] }) : null
|
|
982
|
+
]
|
|
983
|
+
}
|
|
984
|
+
)
|
|
985
|
+
}
|
|
986
|
+
),
|
|
987
|
+
/* @__PURE__ */ jsx3("div", { className: "msr:absolute msr:left-0 msr:top-0 msr:size-[18px] msr:bg-white" })
|
|
988
|
+
]
|
|
989
|
+
}
|
|
990
|
+
);
|
|
991
|
+
});
|
|
992
|
+
|
|
551
993
|
// hooks/use-drag-state.ts
|
|
552
|
-
import { useState as
|
|
994
|
+
import { useState as useState3 } from "react";
|
|
553
995
|
var useDragState = () => {
|
|
554
|
-
const [start, setStart] =
|
|
555
|
-
const [end, setEnd] =
|
|
556
|
-
const [isDragging, setIsDragging] =
|
|
996
|
+
const [start, setStart] = useState3(null);
|
|
997
|
+
const [end, setEnd] = useState3(null);
|
|
998
|
+
const [isDragging, setIsDragging] = useState3(false);
|
|
557
999
|
return { start, setStart, end, setEnd, isDragging, setIsDragging };
|
|
558
1000
|
};
|
|
559
1001
|
|
|
560
1002
|
// hooks/use-guide-drag-hold.ts
|
|
561
|
-
import { useCallback as useCallback2, useRef as
|
|
562
|
-
var useGuideDragHold = () => {
|
|
563
|
-
const guideDragHoldTimerRef =
|
|
564
|
-
const guideDragHoldGuideIdRef =
|
|
1003
|
+
import { useCallback as useCallback2, useRef as useRef3 } from "react";
|
|
1004
|
+
var useGuideDragHold = (eventTarget) => {
|
|
1005
|
+
const guideDragHoldTimerRef = useRef3(null);
|
|
1006
|
+
const guideDragHoldGuideIdRef = useRef3(null);
|
|
565
1007
|
const clearGuideDragHold = useCallback2(() => {
|
|
566
1008
|
if (guideDragHoldTimerRef.current !== null) {
|
|
567
|
-
|
|
1009
|
+
eventTarget.clearTimeout(guideDragHoldTimerRef.current);
|
|
568
1010
|
guideDragHoldTimerRef.current = null;
|
|
569
1011
|
}
|
|
570
1012
|
guideDragHoldGuideIdRef.current = null;
|
|
@@ -573,7 +1015,7 @@ var useGuideDragHold = () => {
|
|
|
573
1015
|
(id, onHold) => {
|
|
574
1016
|
clearGuideDragHold();
|
|
575
1017
|
guideDragHoldGuideIdRef.current = id;
|
|
576
|
-
guideDragHoldTimerRef.current =
|
|
1018
|
+
guideDragHoldTimerRef.current = eventTarget.setTimeout(() => {
|
|
577
1019
|
if (guideDragHoldGuideIdRef.current === id) {
|
|
578
1020
|
onHold(id);
|
|
579
1021
|
}
|
|
@@ -588,11 +1030,11 @@ var useGuideDragHold = () => {
|
|
|
588
1030
|
};
|
|
589
1031
|
|
|
590
1032
|
// hooks/use-guide-state.ts
|
|
591
|
-
import { useState as
|
|
1033
|
+
import { useState as useState4 } from "react";
|
|
592
1034
|
var useGuideState = (options = {}) => {
|
|
593
|
-
const [guides, setGuides] =
|
|
594
|
-
const [draggingGuideId, setDraggingGuideId] =
|
|
595
|
-
const [selectedGuideIds, setSelectedGuideIds] =
|
|
1035
|
+
const [guides, setGuides] = useState4(options.initialGuides ?? []);
|
|
1036
|
+
const [draggingGuideId, setDraggingGuideId] = useState4(null);
|
|
1037
|
+
const [selectedGuideIds, setSelectedGuideIds] = useState4(
|
|
596
1038
|
options.initialSelectedGuideIds ?? []
|
|
597
1039
|
);
|
|
598
1040
|
return {
|
|
@@ -606,19 +1048,37 @@ var useGuideState = (options = {}) => {
|
|
|
606
1048
|
};
|
|
607
1049
|
|
|
608
1050
|
// hooks/use-hotkeys.ts
|
|
609
|
-
import { useEffect
|
|
1051
|
+
import { useEffect } from "react";
|
|
610
1052
|
var useHotkeys = (options) => {
|
|
611
|
-
|
|
1053
|
+
useEffect(() => {
|
|
1054
|
+
const target = options.eventTarget;
|
|
612
1055
|
const handleKeyDown = (event) => {
|
|
613
1056
|
if (event.key === "Escape") {
|
|
614
1057
|
options.clearAll();
|
|
615
1058
|
return;
|
|
616
1059
|
}
|
|
1060
|
+
if (event.metaKey || event.ctrlKey) {
|
|
1061
|
+
if (event.key.toLowerCase() !== "z") return;
|
|
1062
|
+
if (event.shiftKey) {
|
|
1063
|
+
event.preventDefault();
|
|
1064
|
+
options.redo();
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
event.preventDefault();
|
|
1068
|
+
options.undo();
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
617
1071
|
if (event.key.toLowerCase() === "m") {
|
|
618
1072
|
options.setEnabled((prev) => !prev);
|
|
619
1073
|
}
|
|
620
1074
|
const key = event.key.toLowerCase();
|
|
621
1075
|
if (options.isOverlayActive()) {
|
|
1076
|
+
if (key === "a") {
|
|
1077
|
+
options.setToolMode(
|
|
1078
|
+
(prev) => prev === "text-inspector" ? "none" : "text-inspector"
|
|
1079
|
+
);
|
|
1080
|
+
options.onInteract();
|
|
1081
|
+
}
|
|
622
1082
|
if (key === "s") {
|
|
623
1083
|
options.setToolMode((prev) => prev === "select" ? "none" : "select");
|
|
624
1084
|
options.onInteract();
|
|
@@ -627,6 +1087,14 @@ var useHotkeys = (options) => {
|
|
|
627
1087
|
options.setToolMode((prev) => prev === "guides" ? "none" : "guides");
|
|
628
1088
|
options.onInteract();
|
|
629
1089
|
}
|
|
1090
|
+
if (key === "x") {
|
|
1091
|
+
options.setToolMode((prev) => prev === "xray" ? "none" : "xray");
|
|
1092
|
+
options.onInteract();
|
|
1093
|
+
}
|
|
1094
|
+
if (key === "r") {
|
|
1095
|
+
options.setRulersVisible((prev) => !prev);
|
|
1096
|
+
options.onInteract();
|
|
1097
|
+
}
|
|
630
1098
|
if (key === "h") {
|
|
631
1099
|
options.setGuideOrientation("horizontal");
|
|
632
1100
|
options.onInteract();
|
|
@@ -651,22 +1119,22 @@ var useHotkeys = (options) => {
|
|
|
651
1119
|
options.setAltPressed(false);
|
|
652
1120
|
}
|
|
653
1121
|
};
|
|
654
|
-
|
|
655
|
-
|
|
1122
|
+
target.addEventListener("keydown", handleKeyDown);
|
|
1123
|
+
target.addEventListener("keyup", handleKeyUp);
|
|
656
1124
|
return () => {
|
|
657
|
-
|
|
658
|
-
|
|
1125
|
+
target.removeEventListener("keydown", handleKeyDown);
|
|
1126
|
+
target.removeEventListener("keyup", handleKeyUp);
|
|
659
1127
|
};
|
|
660
1128
|
}, [options]);
|
|
661
1129
|
};
|
|
662
1130
|
|
|
663
1131
|
// hooks/use-live-element-tracking.ts
|
|
664
|
-
import { useEffect as
|
|
1132
|
+
import { useEffect as useEffect2, useRef as useRef4 } from "react";
|
|
665
1133
|
|
|
666
|
-
// geometry.ts
|
|
667
|
-
var getViewportSize = () => ({
|
|
668
|
-
width: typeof window === "undefined" ? 1 : window.innerWidth || 1,
|
|
669
|
-
height: typeof window === "undefined" ? 1 : window.innerHeight || 1
|
|
1134
|
+
// core/geometry.ts
|
|
1135
|
+
var getViewportSize = (ownerWindow) => ({
|
|
1136
|
+
width: ownerWindow?.innerWidth || (typeof window === "undefined" ? 1 : window.innerWidth) || 1,
|
|
1137
|
+
height: ownerWindow?.innerHeight || (typeof window === "undefined" ? 1 : window.innerHeight) || 1
|
|
670
1138
|
});
|
|
671
1139
|
var normalizeRect = (rect, viewport = getViewportSize()) => ({
|
|
672
1140
|
left: rect.left / viewport.width,
|
|
@@ -708,9 +1176,9 @@ var getDistanceToRect = (point, rect) => {
|
|
|
708
1176
|
return Math.hypot(dx, dy);
|
|
709
1177
|
};
|
|
710
1178
|
|
|
711
|
-
// distances.ts
|
|
712
|
-
var getDistanceOverlay = (rectA, rectB, elementRefA, elementRefB) => {
|
|
713
|
-
const viewport = getViewportSize();
|
|
1179
|
+
// core/distances.ts
|
|
1180
|
+
var getDistanceOverlay = (rectA, rectB, elementRefA, elementRefB, ownerWindow = window) => {
|
|
1181
|
+
const viewport = getViewportSize(ownerWindow);
|
|
714
1182
|
const normalizedRectA = normalizeRect(rectA, viewport);
|
|
715
1183
|
const normalizedRectB = normalizeRect(rectB, viewport);
|
|
716
1184
|
const rightA = rectA.left + rectA.width;
|
|
@@ -751,10 +1219,10 @@ var getDistanceOverlay = (rectA, rectB, elementRefA, elementRefB) => {
|
|
|
751
1219
|
}
|
|
752
1220
|
}
|
|
753
1221
|
const normalizedConnectors = connectors.map((segment) => ({
|
|
754
|
-
x1: clamp(segment.x1, 0,
|
|
755
|
-
y1: clamp(segment.y1, 0,
|
|
756
|
-
x2: clamp(segment.x2, 0,
|
|
757
|
-
y2: clamp(segment.y2, 0,
|
|
1222
|
+
x1: clamp(segment.x1, 0, ownerWindow.innerWidth),
|
|
1223
|
+
y1: clamp(segment.y1, 0, ownerWindow.innerHeight),
|
|
1224
|
+
x2: clamp(segment.x2, 0, ownerWindow.innerWidth),
|
|
1225
|
+
y2: clamp(segment.y2, 0, ownerWindow.innerHeight)
|
|
758
1226
|
})).filter(
|
|
759
1227
|
(segment) => Math.abs(segment.x1 - segment.x2) > 0.5 || Math.abs(segment.y1 - segment.y2) > 0.5
|
|
760
1228
|
);
|
|
@@ -771,17 +1239,17 @@ var getDistanceOverlay = (rectA, rectB, elementRefA, elementRefB) => {
|
|
|
771
1239
|
connectors: normalizedConnectors
|
|
772
1240
|
};
|
|
773
1241
|
};
|
|
774
|
-
var updateDistanceForResize = (distance, viewport = getViewportSize()) => {
|
|
775
|
-
const normalizedRectA = distance.normalizedRectA ?? normalizeRect(distance.rectA);
|
|
776
|
-
const normalizedRectB = distance.normalizedRectB ?? normalizeRect(distance.rectB);
|
|
1242
|
+
var updateDistanceForResize = (distance, viewport = getViewportSize(), ownerDocument = document, ownerWindow = window) => {
|
|
1243
|
+
const normalizedRectA = distance.normalizedRectA ?? normalizeRect(distance.rectA, viewport);
|
|
1244
|
+
const normalizedRectB = distance.normalizedRectB ?? normalizeRect(distance.rectB, viewport);
|
|
777
1245
|
let rectA = distance.rectA;
|
|
778
1246
|
let rectB = distance.rectB;
|
|
779
|
-
if (distance.elementRefA &&
|
|
1247
|
+
if (distance.elementRefA && ownerDocument.contains(distance.elementRefA)) {
|
|
780
1248
|
rectA = distance.elementRefA.getBoundingClientRect();
|
|
781
1249
|
} else {
|
|
782
1250
|
rectA = denormalizeRect(normalizedRectA, viewport);
|
|
783
1251
|
}
|
|
784
|
-
if (distance.elementRefB &&
|
|
1252
|
+
if (distance.elementRefB && ownerDocument.contains(distance.elementRefB)) {
|
|
785
1253
|
rectB = distance.elementRefB.getBoundingClientRect();
|
|
786
1254
|
} else {
|
|
787
1255
|
rectB = denormalizeRect(normalizedRectB, viewport);
|
|
@@ -790,7 +1258,8 @@ var updateDistanceForResize = (distance, viewport = getViewportSize()) => {
|
|
|
790
1258
|
rectA,
|
|
791
1259
|
rectB,
|
|
792
1260
|
distance.elementRefA,
|
|
793
|
-
distance.elementRefB
|
|
1261
|
+
distance.elementRefB,
|
|
1262
|
+
ownerWindow
|
|
794
1263
|
);
|
|
795
1264
|
return {
|
|
796
1265
|
...updated,
|
|
@@ -798,7 +1267,7 @@ var updateDistanceForResize = (distance, viewport = getViewportSize()) => {
|
|
|
798
1267
|
};
|
|
799
1268
|
};
|
|
800
1269
|
|
|
801
|
-
// dom.ts
|
|
1270
|
+
// core/dom.ts
|
|
802
1271
|
var getElementLabel = (element) => {
|
|
803
1272
|
const tag = element.tagName.toLowerCase();
|
|
804
1273
|
const id = element.id ? `#${element.id}` : "";
|
|
@@ -831,24 +1300,38 @@ var getRectFromDomCached = (element) => {
|
|
|
831
1300
|
};
|
|
832
1301
|
var cachedElements = [];
|
|
833
1302
|
var cachedFrame = -1;
|
|
1303
|
+
var cachedDocument = null;
|
|
834
1304
|
var getFrameToken = () => {
|
|
835
1305
|
if (typeof performance === "undefined") return 0;
|
|
836
1306
|
return Math.floor(performance.now() / 16);
|
|
837
1307
|
};
|
|
838
|
-
var getBodyElementsCached = () => {
|
|
1308
|
+
var getBodyElementsCached = (ownerDocument = document) => {
|
|
839
1309
|
const frame = getFrameToken();
|
|
840
|
-
if (frame === cachedFrame && cachedElements.length > 0) {
|
|
1310
|
+
if (frame === cachedFrame && cachedDocument === ownerDocument && cachedElements.length > 0) {
|
|
841
1311
|
return cachedElements;
|
|
842
1312
|
}
|
|
843
1313
|
cachedFrame = frame;
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1314
|
+
cachedDocument = ownerDocument;
|
|
1315
|
+
const elements = [];
|
|
1316
|
+
const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement ?? HTMLElement;
|
|
1317
|
+
const visit = (root) => {
|
|
1318
|
+
const walker = ownerDocument.createTreeWalker(root, 1);
|
|
1319
|
+
let node = walker.nextNode();
|
|
1320
|
+
while (node) {
|
|
1321
|
+
if (node instanceof HTMLElementConstructor) {
|
|
1322
|
+
elements.push(node);
|
|
1323
|
+
if (node.shadowRoot) visit(node.shadowRoot);
|
|
1324
|
+
}
|
|
1325
|
+
node = walker.nextNode();
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
if (ownerDocument.body) visit(ownerDocument.body);
|
|
1329
|
+
cachedElements = elements;
|
|
847
1330
|
return cachedElements;
|
|
848
1331
|
};
|
|
849
|
-
var getInspectMeasurement = (element) => {
|
|
1332
|
+
var getInspectMeasurement = (element, ownerWindow = window) => {
|
|
850
1333
|
const rect = element.getBoundingClientRect();
|
|
851
|
-
const style =
|
|
1334
|
+
const style = ownerWindow.getComputedStyle(element);
|
|
852
1335
|
const padding = {
|
|
853
1336
|
top: parseEdge(style.paddingTop),
|
|
854
1337
|
right: parseEdge(style.paddingRight),
|
|
@@ -889,9 +1372,9 @@ var getInspectMeasurement = (element) => {
|
|
|
889
1372
|
elementRef: element
|
|
890
1373
|
};
|
|
891
1374
|
};
|
|
892
|
-
var updateMeasurementForResize = (measurement, viewport = getViewportSize()) => {
|
|
1375
|
+
var updateMeasurementForResize = (measurement, viewport = getViewportSize(), ownerDocument = document) => {
|
|
893
1376
|
let rect = measurement.rect;
|
|
894
|
-
if (measurement.elementRef &&
|
|
1377
|
+
if (measurement.elementRef && ownerDocument.contains(measurement.elementRef)) {
|
|
895
1378
|
rect = getRectFromDom(measurement.elementRef);
|
|
896
1379
|
} else if (measurement.normalizedRect) {
|
|
897
1380
|
rect = denormalizeRect(measurement.normalizedRect, viewport);
|
|
@@ -906,11 +1389,11 @@ var updateMeasurementForResize = (measurement, viewport = getViewportSize()) =>
|
|
|
906
1389
|
|
|
907
1390
|
// hooks/use-live-element-tracking.ts
|
|
908
1391
|
var useLiveElementTracking = (params) => {
|
|
909
|
-
const frameRef =
|
|
910
|
-
|
|
1392
|
+
const frameRef = useRef4(null);
|
|
1393
|
+
useEffect2(() => {
|
|
911
1394
|
if (!params.enabled) {
|
|
912
1395
|
if (frameRef.current) {
|
|
913
|
-
cancelAnimationFrame(frameRef.current);
|
|
1396
|
+
params.window.cancelAnimationFrame(frameRef.current);
|
|
914
1397
|
}
|
|
915
1398
|
frameRef.current = null;
|
|
916
1399
|
return;
|
|
@@ -918,7 +1401,7 @@ var useLiveElementTracking = (params) => {
|
|
|
918
1401
|
const tick = () => {
|
|
919
1402
|
params.setMeasurements(
|
|
920
1403
|
(prev) => prev.map((measurement) => {
|
|
921
|
-
if (!measurement.elementRef || !document.contains(measurement.elementRef)) {
|
|
1404
|
+
if (!measurement.elementRef || !params.document.contains(measurement.elementRef)) {
|
|
922
1405
|
return measurement;
|
|
923
1406
|
}
|
|
924
1407
|
const rect = getRectFromDom(measurement.elementRef);
|
|
@@ -932,7 +1415,7 @@ var useLiveElementTracking = (params) => {
|
|
|
932
1415
|
})
|
|
933
1416
|
);
|
|
934
1417
|
params.setActiveMeasurement((prev) => {
|
|
935
|
-
if (!prev?.elementRef || !document.contains(prev.elementRef))
|
|
1418
|
+
if (!prev?.elementRef || !params.document.contains(prev.elementRef))
|
|
936
1419
|
return prev;
|
|
937
1420
|
const rect = getRectFromDom(prev.elementRef);
|
|
938
1421
|
if (rectAlmostEqual(rect, prev.rect)) return prev;
|
|
@@ -945,8 +1428,8 @@ var useLiveElementTracking = (params) => {
|
|
|
945
1428
|
});
|
|
946
1429
|
params.setHeldDistances(
|
|
947
1430
|
(prev) => prev.map((distance) => {
|
|
948
|
-
const canTrackA = distance.elementRefA && document.contains(distance.elementRefA);
|
|
949
|
-
const canTrackB = distance.elementRefB && document.contains(distance.elementRefB);
|
|
1431
|
+
const canTrackA = distance.elementRefA && params.document.contains(distance.elementRefA);
|
|
1432
|
+
const canTrackB = distance.elementRefB && params.document.contains(distance.elementRefB);
|
|
950
1433
|
if (!canTrackA && !canTrackB) return distance;
|
|
951
1434
|
const rectA = canTrackA ? getRectFromDom(distance.elementRefA) : distance.rectA;
|
|
952
1435
|
const rectB = canTrackB ? getRectFromDom(distance.elementRefB) : distance.rectB;
|
|
@@ -957,7 +1440,8 @@ var useLiveElementTracking = (params) => {
|
|
|
957
1440
|
rectA,
|
|
958
1441
|
rectB,
|
|
959
1442
|
distance.elementRefA,
|
|
960
|
-
distance.elementRefB
|
|
1443
|
+
distance.elementRefB,
|
|
1444
|
+
params.window
|
|
961
1445
|
);
|
|
962
1446
|
return {
|
|
963
1447
|
...updated,
|
|
@@ -966,19 +1450,19 @@ var useLiveElementTracking = (params) => {
|
|
|
966
1450
|
})
|
|
967
1451
|
);
|
|
968
1452
|
const selected = params.selectedElementRef.current;
|
|
969
|
-
if (selected && document.contains(selected)) {
|
|
1453
|
+
if (selected && params.document.contains(selected)) {
|
|
970
1454
|
params.setSelectedMeasurement((prev) => {
|
|
971
|
-
const next = getInspectMeasurement(selected);
|
|
1455
|
+
const next = getInspectMeasurement(selected, params.window);
|
|
972
1456
|
if (prev && rectAlmostEqual(prev.rect, next.rect)) return prev;
|
|
973
1457
|
return next;
|
|
974
1458
|
});
|
|
975
1459
|
}
|
|
976
1460
|
params.setSelectedMeasurements(
|
|
977
1461
|
(prev) => prev.map((measurement) => {
|
|
978
|
-
if (!measurement.elementRef || !document.contains(measurement.elementRef)) {
|
|
1462
|
+
if (!measurement.elementRef || !params.document.contains(measurement.elementRef)) {
|
|
979
1463
|
return measurement;
|
|
980
1464
|
}
|
|
981
|
-
const next = getInspectMeasurement(measurement.elementRef);
|
|
1465
|
+
const next = getInspectMeasurement(measurement.elementRef, params.window);
|
|
982
1466
|
if (rectAlmostEqual(next.rect, measurement.rect)) return measurement;
|
|
983
1467
|
return {
|
|
984
1468
|
...next,
|
|
@@ -987,18 +1471,18 @@ var useLiveElementTracking = (params) => {
|
|
|
987
1471
|
})
|
|
988
1472
|
);
|
|
989
1473
|
const hover = params.hoverElementRef.current;
|
|
990
|
-
if (hover && document.contains(hover)) {
|
|
1474
|
+
if (hover && params.document.contains(hover)) {
|
|
991
1475
|
const rect = getRectFromDom(hover);
|
|
992
1476
|
params.setHoverRect(
|
|
993
1477
|
(prev) => prev && rectAlmostEqual(prev, rect) ? prev : rect
|
|
994
1478
|
);
|
|
995
1479
|
}
|
|
996
|
-
frameRef.current = requestAnimationFrame(tick);
|
|
1480
|
+
frameRef.current = params.window.requestAnimationFrame(tick);
|
|
997
1481
|
};
|
|
998
|
-
frameRef.current = requestAnimationFrame(tick);
|
|
1482
|
+
frameRef.current = params.window.requestAnimationFrame(tick);
|
|
999
1483
|
return () => {
|
|
1000
1484
|
if (frameRef.current) {
|
|
1001
|
-
cancelAnimationFrame(frameRef.current);
|
|
1485
|
+
params.window.cancelAnimationFrame(frameRef.current);
|
|
1002
1486
|
}
|
|
1003
1487
|
frameRef.current = null;
|
|
1004
1488
|
};
|
|
@@ -1006,13 +1490,16 @@ var useLiveElementTracking = (params) => {
|
|
|
1006
1490
|
};
|
|
1007
1491
|
|
|
1008
1492
|
// hooks/use-measure-toggles.ts
|
|
1009
|
-
import { useState as
|
|
1493
|
+
import { useState as useState5 } from "react";
|
|
1010
1494
|
var useMeasureToggles = (options = {}) => {
|
|
1011
|
-
const [enabled, setEnabled] =
|
|
1012
|
-
const [altPressed, setAltPressed] =
|
|
1013
|
-
const [toolMode, setToolMode] =
|
|
1495
|
+
const [enabled, setEnabled] = useState5(options.initialEnabled ?? true);
|
|
1496
|
+
const [altPressed, setAltPressed] = useState5(false);
|
|
1497
|
+
const [toolMode, setToolMode] = useState5(
|
|
1014
1498
|
options.initialToolMode ?? "none"
|
|
1015
1499
|
);
|
|
1500
|
+
const [rulersVisible, setRulersVisible] = useState5(
|
|
1501
|
+
options.initialRulersVisible ?? false
|
|
1502
|
+
);
|
|
1016
1503
|
const holdEnabled = false;
|
|
1017
1504
|
const multiMeasureEnabled = false;
|
|
1018
1505
|
const snapGuidesEnabled = true;
|
|
@@ -1026,6 +1513,8 @@ var useMeasureToggles = (options = {}) => {
|
|
|
1026
1513
|
setAltPressed,
|
|
1027
1514
|
toolMode,
|
|
1028
1515
|
setToolMode,
|
|
1516
|
+
rulersVisible,
|
|
1517
|
+
setRulersVisible,
|
|
1029
1518
|
guidesEnabled,
|
|
1030
1519
|
multiMeasureEnabled,
|
|
1031
1520
|
snapGuidesEnabled,
|
|
@@ -1034,16 +1523,16 @@ var useMeasureToggles = (options = {}) => {
|
|
|
1034
1523
|
};
|
|
1035
1524
|
|
|
1036
1525
|
// hooks/use-measurement-state.ts
|
|
1037
|
-
import { useState as
|
|
1526
|
+
import { useState as useState6 } from "react";
|
|
1038
1527
|
var useMeasurementState = (options = {}) => {
|
|
1039
|
-
const [activeMeasurement, setActiveMeasurement] =
|
|
1040
|
-
const [measurements, setMeasurements] =
|
|
1528
|
+
const [activeMeasurement, setActiveMeasurement] = useState6(options.initialActiveMeasurement ?? null);
|
|
1529
|
+
const [measurements, setMeasurements] = useState6(
|
|
1041
1530
|
options.initialMeasurements ?? []
|
|
1042
1531
|
);
|
|
1043
|
-
const [selectedMeasurement, setSelectedMeasurement] =
|
|
1044
|
-
const [selectedMeasurements, setSelectedMeasurements] =
|
|
1045
|
-
const [hoverRect, setHoverRect] =
|
|
1046
|
-
const [heldDistances, setHeldDistances] =
|
|
1532
|
+
const [selectedMeasurement, setSelectedMeasurement] = useState6(null);
|
|
1533
|
+
const [selectedMeasurements, setSelectedMeasurements] = useState6([]);
|
|
1534
|
+
const [hoverRect, setHoverRect] = useState6(null);
|
|
1535
|
+
const [heldDistances, setHeldDistances] = useState6(
|
|
1047
1536
|
options.initialHeldDistances ?? []
|
|
1048
1537
|
);
|
|
1049
1538
|
return {
|
|
@@ -1065,7 +1554,7 @@ var useMeasurementState = (options = {}) => {
|
|
|
1065
1554
|
// hooks/use-measurer-derived.ts
|
|
1066
1555
|
import { useMemo } from "react";
|
|
1067
1556
|
|
|
1068
|
-
// edge-visibility.ts
|
|
1557
|
+
// core/edge-visibility.ts
|
|
1069
1558
|
var rangesOverlap = (a1, a2, b1, b2) => Math.min(a2, b2) - Math.max(a1, b1) > 0;
|
|
1070
1559
|
var getEdgeVisibilityForRects = (rects, epsilon = 1) => {
|
|
1071
1560
|
const visibility = rects.map(() => ({
|
|
@@ -1105,24 +1594,25 @@ var getEdgeVisibilityForRects = (rects, epsilon = 1) => {
|
|
|
1105
1594
|
return visibility;
|
|
1106
1595
|
};
|
|
1107
1596
|
|
|
1108
|
-
// guides.ts
|
|
1109
|
-
var getGuideRect = (guide) => {
|
|
1110
|
-
const viewport = getViewportSize();
|
|
1597
|
+
// core/guides.ts
|
|
1598
|
+
var getGuideRect = (guide, ownerWindow = window) => {
|
|
1599
|
+
const viewport = getViewportSize(ownerWindow);
|
|
1111
1600
|
return guide.orientation === "vertical" ? { left: guide.position, top: 0, width: 1, height: viewport.height } : { left: 0, top: guide.position, width: viewport.width, height: 1 };
|
|
1112
1601
|
};
|
|
1113
1602
|
var getGuideDistance = (guide, point) => guide.orientation === "vertical" ? Math.abs(guide.position - point.x) : Math.abs(guide.position - point.y);
|
|
1114
1603
|
var getSnapGuidePosition = (params) => {
|
|
1604
|
+
const ownerDocument = params.document ?? document;
|
|
1115
1605
|
const { orientation, point, snapGuidesEnabled, overlayNode, guides } = params;
|
|
1116
1606
|
if (!snapGuidesEnabled) {
|
|
1117
1607
|
return orientation === "vertical" ? point.x : point.y;
|
|
1118
1608
|
}
|
|
1119
|
-
const elements = getBodyElementsCached();
|
|
1609
|
+
const elements = getBodyElementsCached(ownerDocument);
|
|
1120
1610
|
let bestValue = orientation === "vertical" ? point.x : point.y;
|
|
1121
1611
|
let bestDistance = GUIDE_SNAP_DISTANCE + 1;
|
|
1122
1612
|
for (const element of elements) {
|
|
1123
|
-
if (!(element instanceof HTMLElement)) continue;
|
|
1613
|
+
if (!(element instanceof (ownerDocument.defaultView?.HTMLElement ?? HTMLElement))) continue;
|
|
1124
1614
|
if (overlayNode && overlayNode.contains(element)) continue;
|
|
1125
|
-
if (element ===
|
|
1615
|
+
if (element === ownerDocument.body || element === ownerDocument.documentElement)
|
|
1126
1616
|
continue;
|
|
1127
1617
|
const rect = getRectFromDomCached(element);
|
|
1128
1618
|
if (rect.width <= 2 || rect.height <= 2) continue;
|
|
@@ -1158,7 +1648,7 @@ var getSnapGuidePosition = (params) => {
|
|
|
1158
1648
|
return bestDistance <= GUIDE_SNAP_DISTANCE ? bestValue : orientation === "vertical" ? point.x : point.y;
|
|
1159
1649
|
};
|
|
1160
1650
|
|
|
1161
|
-
// option-measurements.ts
|
|
1651
|
+
// core/option-measurements.ts
|
|
1162
1652
|
var getHoveredGuide = (point, guides) => {
|
|
1163
1653
|
if (!point || guides.length === 0) return null;
|
|
1164
1654
|
let closest = null;
|
|
@@ -1179,6 +1669,8 @@ var getSelectedGuide = (guides, selectedGuideIds) => {
|
|
|
1179
1669
|
return guides.find((guide) => guide.id === lastId) ?? null;
|
|
1180
1670
|
};
|
|
1181
1671
|
var getOptionPairOverlay = (params) => {
|
|
1672
|
+
const ownerDocument = params.document ?? document;
|
|
1673
|
+
const ownerWindow = params.window ?? window;
|
|
1182
1674
|
if (!params.altPressed) return null;
|
|
1183
1675
|
if (!params.selectedGuide && !params.primarySelectedMeasurement) return null;
|
|
1184
1676
|
const primary = params.primarySelectedMeasurement;
|
|
@@ -1207,10 +1699,13 @@ var getOptionPairOverlay = (params) => {
|
|
|
1207
1699
|
selectedTarget.rect,
|
|
1208
1700
|
hoverTarget.rect,
|
|
1209
1701
|
selectedTarget.element ?? null,
|
|
1210
|
-
hoverTarget.element ?? null
|
|
1702
|
+
hoverTarget.element ?? null,
|
|
1703
|
+
ownerWindow
|
|
1211
1704
|
);
|
|
1212
1705
|
};
|
|
1213
1706
|
var getOptionContainerLines = (params) => {
|
|
1707
|
+
const ownerDocument = params.document ?? document;
|
|
1708
|
+
const ownerWindow = params.window ?? window;
|
|
1214
1709
|
if (!params.altPressed || !params.primarySelectedMeasurement || params.optionPairOverlay)
|
|
1215
1710
|
return null;
|
|
1216
1711
|
if (params.selectedGuideIds.length > 0) return null;
|
|
@@ -1218,11 +1713,11 @@ var getOptionContainerLines = (params) => {
|
|
|
1218
1713
|
if (params.selectedElement && params.hoverElement && params.hoverElement !== params.selectedElement && params.hoverElement.contains(params.selectedElement)) {
|
|
1219
1714
|
containerElement = params.hoverElement;
|
|
1220
1715
|
}
|
|
1221
|
-
const containerRect = containerElement && containerElement !==
|
|
1716
|
+
const containerRect = containerElement && containerElement !== ownerDocument.body && containerElement !== ownerDocument.documentElement ? getRectFromDom(containerElement) : {
|
|
1222
1717
|
left: 0,
|
|
1223
1718
|
top: 0,
|
|
1224
|
-
width:
|
|
1225
|
-
height:
|
|
1719
|
+
width: ownerWindow.innerWidth,
|
|
1720
|
+
height: ownerWindow.innerHeight
|
|
1226
1721
|
};
|
|
1227
1722
|
const rect = params.primarySelectedMeasurement.rect;
|
|
1228
1723
|
const right = rect.left + rect.width;
|
|
@@ -1261,18 +1756,20 @@ var getOptionContainerLines = (params) => {
|
|
|
1261
1756
|
};
|
|
1262
1757
|
};
|
|
1263
1758
|
|
|
1264
|
-
// selection-helpers.ts
|
|
1759
|
+
// core/selection-helpers.ts
|
|
1265
1760
|
var getOverlayHost = (overlayNode) => {
|
|
1266
1761
|
if (!overlayNode) return null;
|
|
1267
1762
|
const rootNode = overlayNode.getRootNode();
|
|
1268
|
-
return rootNode
|
|
1763
|
+
return rootNode.nodeType === 11 ? rootNode.host : null;
|
|
1269
1764
|
};
|
|
1270
1765
|
var getPrimarySelectedMeasurement = (selectedMeasurements, selectedMeasurement) => selectedMeasurements.length > 0 ? selectedMeasurements[selectedMeasurements.length - 1] : selectedMeasurement;
|
|
1271
1766
|
var getSelectedMeasurementHit = (params) => {
|
|
1767
|
+
const ownerDocument = params.document ?? document;
|
|
1768
|
+
const HTMLElementConstructor = ownerDocument.defaultView?.HTMLElement ?? HTMLElement;
|
|
1272
1769
|
const overlayHost = getOverlayHost(params.overlayNode);
|
|
1273
1770
|
const candidates = params.selectedMeasurements.map((measurement) => {
|
|
1274
1771
|
const element = measurement.elementRef;
|
|
1275
|
-
if (!element || !
|
|
1772
|
+
if (!element || !ownerDocument.contains(element)) return null;
|
|
1276
1773
|
const rect = getRectFromDom(element);
|
|
1277
1774
|
return {
|
|
1278
1775
|
measurement,
|
|
@@ -1282,9 +1779,9 @@ var getSelectedMeasurementHit = (params) => {
|
|
|
1282
1779
|
};
|
|
1283
1780
|
}).filter((item) => item !== null).sort((a, b) => a.area - b.area);
|
|
1284
1781
|
if (candidates.length === 0) return null;
|
|
1285
|
-
const stack =
|
|
1782
|
+
const stack = ownerDocument.elementsFromPoint(params.point.x, params.point.y);
|
|
1286
1783
|
for (const element of stack) {
|
|
1287
|
-
if (!(element instanceof
|
|
1784
|
+
if (!(element instanceof HTMLElementConstructor)) continue;
|
|
1288
1785
|
if (params.overlayNode && params.overlayNode.contains(element)) continue;
|
|
1289
1786
|
if (overlayHost && element === overlayHost) continue;
|
|
1290
1787
|
for (const candidate of candidates) {
|
|
@@ -1303,6 +1800,8 @@ var getSelectedMeasurementHit = (params) => {
|
|
|
1303
1800
|
|
|
1304
1801
|
// hooks/use-measurer-derived.ts
|
|
1305
1802
|
var useMeasurerDerived = ({
|
|
1803
|
+
document: document2,
|
|
1804
|
+
window: window2,
|
|
1306
1805
|
start,
|
|
1307
1806
|
end,
|
|
1308
1807
|
selectedMeasurements,
|
|
@@ -1387,7 +1886,9 @@ var useMeasurerDerived = ({
|
|
|
1387
1886
|
selectedGuide,
|
|
1388
1887
|
hoverGuide,
|
|
1389
1888
|
hoverElement,
|
|
1390
|
-
selectedElementRef: selectedElement
|
|
1889
|
+
selectedElementRef: selectedElement,
|
|
1890
|
+
document: document2,
|
|
1891
|
+
window: window2
|
|
1391
1892
|
});
|
|
1392
1893
|
}, [
|
|
1393
1894
|
altPressed,
|
|
@@ -1404,7 +1905,9 @@ var useMeasurerDerived = ({
|
|
|
1404
1905
|
optionPairOverlay,
|
|
1405
1906
|
selectedGuideIds,
|
|
1406
1907
|
selectedElement,
|
|
1407
|
-
hoverElement
|
|
1908
|
+
hoverElement,
|
|
1909
|
+
document: document2,
|
|
1910
|
+
window: window2
|
|
1408
1911
|
});
|
|
1409
1912
|
}, [
|
|
1410
1913
|
altPressed,
|
|
@@ -1418,8 +1921,11 @@ var useMeasurerDerived = ({
|
|
|
1418
1921
|
if (!altPressed || !guidesEnabled) return null;
|
|
1419
1922
|
if (selectedGuide && hoverGuide && selectedGuide.id !== hoverGuide.id) {
|
|
1420
1923
|
return getDistanceOverlay(
|
|
1421
|
-
getGuideRect(selectedGuide),
|
|
1422
|
-
getGuideRect(hoverGuide)
|
|
1924
|
+
getGuideRect(selectedGuide, window2),
|
|
1925
|
+
getGuideRect(hoverGuide, window2),
|
|
1926
|
+
null,
|
|
1927
|
+
null,
|
|
1928
|
+
window2
|
|
1423
1929
|
);
|
|
1424
1930
|
}
|
|
1425
1931
|
if (!guidePreview) return null;
|
|
@@ -1442,8 +1948,11 @@ var useMeasurerDerived = ({
|
|
|
1442
1948
|
);
|
|
1443
1949
|
if (!nearest) return null;
|
|
1444
1950
|
return getDistanceOverlay(
|
|
1445
|
-
getGuideRect(previewGuide),
|
|
1446
|
-
getGuideRect(nearest.guide)
|
|
1951
|
+
getGuideRect(previewGuide, window2),
|
|
1952
|
+
getGuideRect(nearest.guide, window2),
|
|
1953
|
+
null,
|
|
1954
|
+
null,
|
|
1955
|
+
window2
|
|
1447
1956
|
);
|
|
1448
1957
|
}, [
|
|
1449
1958
|
altPressed,
|
|
@@ -1513,7 +2022,7 @@ var useMeasurerDerived = ({
|
|
|
1513
2022
|
};
|
|
1514
2023
|
|
|
1515
2024
|
// hooks/use-measurer-history.ts
|
|
1516
|
-
import { useCallback as useCallback3,
|
|
2025
|
+
import { useCallback as useCallback3, useRef as useRef5 } from "react";
|
|
1517
2026
|
var HISTORY_LIMIT = 50;
|
|
1518
2027
|
var useMeasurerHistory = ({
|
|
1519
2028
|
toggles,
|
|
@@ -1559,9 +2068,9 @@ var useMeasurerHistory = ({
|
|
|
1559
2068
|
setSelectedElement,
|
|
1560
2069
|
clearSelectionRect
|
|
1561
2070
|
} = transient;
|
|
1562
|
-
const historyRef =
|
|
1563
|
-
const futureRef =
|
|
1564
|
-
const historySignatureRef =
|
|
2071
|
+
const historyRef = useRef5([]);
|
|
2072
|
+
const futureRef = useRef5([]);
|
|
2073
|
+
const historySignatureRef = useRef5(null);
|
|
1565
2074
|
const captureSnapshot = useCallback3(() => {
|
|
1566
2075
|
return {
|
|
1567
2076
|
enabled,
|
|
@@ -1723,49 +2232,32 @@ var useMeasurerHistory = ({
|
|
|
1723
2232
|
committed = true;
|
|
1724
2233
|
};
|
|
1725
2234
|
}, [recordSnapshot]);
|
|
1726
|
-
useEffect4(() => {
|
|
1727
|
-
const handleKeyDown = (event) => {
|
|
1728
|
-
if (!(event.metaKey || event.ctrlKey)) return;
|
|
1729
|
-
if (event.key.toLowerCase() !== "z") return;
|
|
1730
|
-
if (event.shiftKey) {
|
|
1731
|
-
if (futureRef.current.length === 0) return;
|
|
1732
|
-
event.preventDefault();
|
|
1733
|
-
redo();
|
|
1734
|
-
return;
|
|
1735
|
-
}
|
|
1736
|
-
if (historyRef.current.length === 0) return;
|
|
1737
|
-
event.preventDefault();
|
|
1738
|
-
undo();
|
|
1739
|
-
};
|
|
1740
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
1741
|
-
return () => {
|
|
1742
|
-
window.removeEventListener("keydown", handleKeyDown);
|
|
1743
|
-
};
|
|
1744
|
-
}, [redo, undo]);
|
|
1745
2235
|
return {
|
|
1746
2236
|
recordSnapshot,
|
|
1747
2237
|
createActionCommit,
|
|
1748
2238
|
setToolModeWithHistory,
|
|
1749
2239
|
setGuideOrientationWithHistory,
|
|
1750
|
-
setEnabledWithHistory
|
|
2240
|
+
setEnabledWithHistory,
|
|
2241
|
+
undo,
|
|
2242
|
+
redo
|
|
1751
2243
|
};
|
|
1752
2244
|
};
|
|
1753
2245
|
|
|
1754
2246
|
// hooks/use-measurer-local-state.ts
|
|
1755
|
-
import { useCallback as useCallback4, useState as
|
|
2247
|
+
import { useCallback as useCallback4, useState as useState7 } from "react";
|
|
1756
2248
|
var useMeasurerLocalState = ({
|
|
1757
2249
|
selectedElementRef,
|
|
1758
2250
|
hoverElementRef,
|
|
1759
2251
|
selectionRectRef
|
|
1760
2252
|
}) => {
|
|
1761
|
-
const [selectionOriginRect, setSelectionOriginRect] =
|
|
2253
|
+
const [selectionOriginRect, setSelectionOriginRect] = useState7(
|
|
1762
2254
|
null
|
|
1763
2255
|
);
|
|
1764
|
-
const [hoverPointer, setHoverPointer] =
|
|
1765
|
-
const [hoverElement, setHoverElementState] =
|
|
2256
|
+
const [hoverPointer, setHoverPointer] = useState7(null);
|
|
2257
|
+
const [hoverElement, setHoverElementState] = useState7(
|
|
1766
2258
|
null
|
|
1767
2259
|
);
|
|
1768
|
-
const [selectedElement, setSelectedElementState] =
|
|
2260
|
+
const [selectedElement, setSelectedElementState] = useState7(null);
|
|
1769
2261
|
const setSelectedElement = useCallback4(
|
|
1770
2262
|
(element) => {
|
|
1771
2263
|
selectedElementRef.current = element;
|
|
@@ -1798,9 +2290,9 @@ var useMeasurerLocalState = ({
|
|
|
1798
2290
|
};
|
|
1799
2291
|
|
|
1800
2292
|
// hooks/use-measurer-pointer.ts
|
|
1801
|
-
import { useCallback as useCallback5, useEffect as
|
|
2293
|
+
import { useCallback as useCallback5, useEffect as useEffect3, useRef as useRef6 } from "react";
|
|
1802
2294
|
|
|
1803
|
-
// targets.ts
|
|
2295
|
+
// core/targets.ts
|
|
1804
2296
|
var pickMultiTargets = (selectionRect, items) => {
|
|
1805
2297
|
const candidates = items.map(({ element, rect }) => {
|
|
1806
2298
|
const overlapArea = intersectionArea(selectionRect, rect);
|
|
@@ -1865,28 +2357,39 @@ var pickPointTarget = (point, items) => {
|
|
|
1865
2357
|
return scored[0].element;
|
|
1866
2358
|
};
|
|
1867
2359
|
|
|
1868
|
-
// selection.ts
|
|
2360
|
+
// core/selection.ts
|
|
1869
2361
|
var getOverlayHost2 = (overlayNode) => {
|
|
1870
2362
|
if (!overlayNode) return null;
|
|
1871
2363
|
const rootNode = overlayNode.getRootNode();
|
|
1872
|
-
return rootNode
|
|
2364
|
+
return rootNode.nodeType === 11 ? rootNode.host : null;
|
|
1873
2365
|
};
|
|
1874
2366
|
var isOverlayElement = (element, overlayNode, overlayHost) => {
|
|
1875
2367
|
if (overlayNode && overlayNode.contains(element)) return true;
|
|
1876
2368
|
if (overlayHost && element === overlayHost) return true;
|
|
1877
2369
|
return false;
|
|
1878
2370
|
};
|
|
1879
|
-
var
|
|
2371
|
+
var getDeepestElementAt = (element, point) => {
|
|
2372
|
+
let current = element;
|
|
2373
|
+
const HTMLElementConstructor = element.ownerDocument.defaultView?.HTMLElement ?? HTMLElement;
|
|
2374
|
+
while (current instanceof HTMLElementConstructor && current.shadowRoot) {
|
|
2375
|
+
const nested = current.shadowRoot.elementFromPoint(point.x, point.y);
|
|
2376
|
+
if (!nested || nested === current) break;
|
|
2377
|
+
current = nested;
|
|
2378
|
+
}
|
|
2379
|
+
return current;
|
|
2380
|
+
};
|
|
2381
|
+
var getTargetElement = (point, overlayNode, ownerDocument = document) => {
|
|
1880
2382
|
const overlayHost = getOverlayHost2(overlayNode);
|
|
1881
2383
|
if (overlayNode) {
|
|
1882
2384
|
const previous = overlayNode.style.pointerEvents;
|
|
1883
2385
|
overlayNode.style.pointerEvents = "none";
|
|
1884
|
-
const elements2 =
|
|
2386
|
+
const elements2 = ownerDocument.elementsFromPoint(point.x, point.y);
|
|
1885
2387
|
overlayNode.style.pointerEvents = previous;
|
|
1886
|
-
for (const
|
|
1887
|
-
|
|
2388
|
+
for (const rawElement of elements2) {
|
|
2389
|
+
const element = getDeepestElementAt(rawElement, point);
|
|
2390
|
+
if (!(element instanceof (ownerDocument.defaultView?.HTMLElement ?? HTMLElement))) continue;
|
|
1888
2391
|
if (isOverlayElement(element, overlayNode, overlayHost)) continue;
|
|
1889
|
-
if (element ===
|
|
2392
|
+
if (element === ownerDocument.body || element === ownerDocument.documentElement)
|
|
1890
2393
|
continue;
|
|
1891
2394
|
const rect = element.getBoundingClientRect();
|
|
1892
2395
|
if (rect.width <= 2 || rect.height <= 2) continue;
|
|
@@ -1894,11 +2397,12 @@ var getTargetElement = (point, overlayNode) => {
|
|
|
1894
2397
|
}
|
|
1895
2398
|
return null;
|
|
1896
2399
|
}
|
|
1897
|
-
const elements =
|
|
1898
|
-
for (const
|
|
1899
|
-
|
|
2400
|
+
const elements = ownerDocument.elementsFromPoint(point.x, point.y);
|
|
2401
|
+
for (const rawElement of elements) {
|
|
2402
|
+
const element = getDeepestElementAt(rawElement, point);
|
|
2403
|
+
if (!(element instanceof (ownerDocument.defaultView?.HTMLElement ?? HTMLElement))) continue;
|
|
1900
2404
|
if (isOverlayElement(element, overlayNode, overlayHost)) continue;
|
|
1901
|
-
if (element ===
|
|
2405
|
+
if (element === ownerDocument.body || element === ownerDocument.documentElement)
|
|
1902
2406
|
continue;
|
|
1903
2407
|
const rect = element.getBoundingClientRect();
|
|
1904
2408
|
if (rect.width <= 2 || rect.height <= 2) continue;
|
|
@@ -1906,34 +2410,34 @@ var getTargetElement = (point, overlayNode) => {
|
|
|
1906
2410
|
}
|
|
1907
2411
|
return null;
|
|
1908
2412
|
};
|
|
1909
|
-
var getSnappedClickTarget = (point, overlayNode, snapEnabled) => {
|
|
1910
|
-
if (!snapEnabled) return getTargetElement(point, overlayNode);
|
|
2413
|
+
var getSnappedClickTarget = (point, overlayNode, snapEnabled, ownerDocument = document) => {
|
|
2414
|
+
if (!snapEnabled) return getTargetElement(point, overlayNode, ownerDocument);
|
|
1911
2415
|
const probeRect = {
|
|
1912
2416
|
left: point.x - 20,
|
|
1913
2417
|
top: point.y - 20,
|
|
1914
2418
|
width: 40,
|
|
1915
2419
|
height: 40
|
|
1916
2420
|
};
|
|
1917
|
-
const entries = getSelectionEntries(probeRect, overlayNode);
|
|
1918
|
-
return pickPointTarget(point, entries) ?? pickSingleTarget(probeRect, point, entries) ?? getTargetElement(point, overlayNode);
|
|
2421
|
+
const entries = getSelectionEntries(probeRect, overlayNode, ownerDocument);
|
|
2422
|
+
return pickPointTarget(point, entries) ?? pickSingleTarget(probeRect, point, entries) ?? getTargetElement(point, overlayNode, ownerDocument);
|
|
1919
2423
|
};
|
|
1920
|
-
var getSelectionEntries = (rect, overlayNode) => {
|
|
2424
|
+
var getSelectionEntries = (rect, overlayNode, ownerDocument = document) => {
|
|
1921
2425
|
const overlayHost = getOverlayHost2(overlayNode);
|
|
1922
2426
|
const frame = getFrameToken();
|
|
1923
2427
|
const key = `${Math.round(rect.left)}:${Math.round(rect.top)}:${Math.round(
|
|
1924
2428
|
rect.width
|
|
1925
2429
|
)}:${Math.round(rect.height)}`;
|
|
1926
|
-
if (frame === cachedSelectionFrame && cachedSelectionKey === key && cachedOverlayNode === overlayNode) {
|
|
2430
|
+
if (frame === cachedSelectionFrame && cachedSelectionKey === key && cachedOverlayNode === overlayNode && cachedSelectionDocument === ownerDocument) {
|
|
1927
2431
|
return cachedSelectionEntries;
|
|
1928
2432
|
}
|
|
1929
2433
|
const minLeft = rect.left - 1;
|
|
1930
2434
|
const minTop = rect.top - 1;
|
|
1931
2435
|
const maxRight = rect.left + rect.width + 1;
|
|
1932
2436
|
const maxBottom = rect.top + rect.height + 1;
|
|
1933
|
-
const elements = getBodyElementsCached();
|
|
2437
|
+
const elements = getBodyElementsCached(ownerDocument);
|
|
1934
2438
|
const entries = elements.map((element) => ({ element, rect: getRectFromDomCached(element) })).filter(({ element, rect: elementRect }) => {
|
|
1935
2439
|
if (isOverlayElement(element, overlayNode, overlayHost)) return false;
|
|
1936
|
-
if (element ===
|
|
2440
|
+
if (element === ownerDocument.body || element === ownerDocument.documentElement)
|
|
1937
2441
|
return false;
|
|
1938
2442
|
if (elementRect.width < MIN_MULTI_TARGET_SIZE || elementRect.height < MIN_MULTI_TARGET_SIZE) {
|
|
1939
2443
|
return false;
|
|
@@ -1947,6 +2451,7 @@ var getSelectionEntries = (rect, overlayNode) => {
|
|
|
1947
2451
|
cachedSelectionFrame = frame;
|
|
1948
2452
|
cachedSelectionKey = key;
|
|
1949
2453
|
cachedOverlayNode = overlayNode;
|
|
2454
|
+
cachedSelectionDocument = ownerDocument;
|
|
1950
2455
|
cachedSelectionEntries = entries;
|
|
1951
2456
|
return entries;
|
|
1952
2457
|
};
|
|
@@ -1954,30 +2459,33 @@ var cachedSelectionFrame = -1;
|
|
|
1954
2459
|
var cachedSelectionKey = "";
|
|
1955
2460
|
var cachedSelectionEntries = [];
|
|
1956
2461
|
var cachedOverlayNode = null;
|
|
2462
|
+
var cachedSelectionDocument = null;
|
|
1957
2463
|
var getSelectionCacheKey = (rect) => `${Math.round(rect.left)}:${Math.round(rect.top)}:${Math.round(
|
|
1958
2464
|
rect.width
|
|
1959
2465
|
)}:${Math.round(rect.height)}`;
|
|
1960
|
-
var getSelectionEntriesCached = (rect, overlayNode, cache) => {
|
|
2466
|
+
var getSelectionEntriesCached = (rect, overlayNode, cache, ownerDocument = document) => {
|
|
1961
2467
|
const frame = getFrameToken();
|
|
1962
2468
|
const key = getSelectionCacheKey(rect);
|
|
1963
2469
|
if (cache.key === key && cache.overlayNode === overlayNode && cache.frame === frame) {
|
|
1964
2470
|
return cache.entries;
|
|
1965
2471
|
}
|
|
1966
|
-
const entries = getSelectionEntries(rect, overlayNode);
|
|
2472
|
+
const entries = getSelectionEntries(rect, overlayNode, ownerDocument);
|
|
1967
2473
|
cache.key = key;
|
|
1968
2474
|
cache.overlayNode = overlayNode;
|
|
1969
2475
|
cache.frame = frame;
|
|
1970
2476
|
cache.entries = entries;
|
|
1971
2477
|
return entries;
|
|
1972
2478
|
};
|
|
1973
|
-
var getElementsInRectCached = (rect, overlayNode, cache) => {
|
|
1974
|
-
const entries = getSelectionEntriesCached(rect, overlayNode, cache);
|
|
2479
|
+
var getElementsInRectCached = (rect, overlayNode, cache, ownerDocument = document) => {
|
|
2480
|
+
const entries = getSelectionEntriesCached(rect, overlayNode, cache, ownerDocument);
|
|
1975
2481
|
if (entries.length === 0) return [];
|
|
1976
2482
|
return pickMultiTargets(rect, entries);
|
|
1977
2483
|
};
|
|
1978
2484
|
|
|
1979
2485
|
// hooks/use-measurer-pointer.ts
|
|
1980
2486
|
var useMeasurerPointer = ({
|
|
2487
|
+
document: document2,
|
|
2488
|
+
window: window2,
|
|
1981
2489
|
toolbarRef,
|
|
1982
2490
|
overlayRef,
|
|
1983
2491
|
selectionRectRef,
|
|
@@ -2021,46 +2529,26 @@ var useMeasurerPointer = ({
|
|
|
2021
2529
|
setHoverPointer,
|
|
2022
2530
|
clearSelectionRect
|
|
2023
2531
|
}) => {
|
|
2024
|
-
const hoverFrameRef =
|
|
2025
|
-
const hoverPointRef =
|
|
2026
|
-
const selectionCacheRef =
|
|
2532
|
+
const hoverFrameRef = useRef6(null);
|
|
2533
|
+
const hoverPointRef = useRef6(null);
|
|
2534
|
+
const selectionCacheRef = useRef6({
|
|
2027
2535
|
key: "",
|
|
2028
2536
|
entries: [],
|
|
2029
2537
|
overlayNode: null,
|
|
2030
2538
|
frame: -1
|
|
2031
2539
|
});
|
|
2032
|
-
const shiftDragRef =
|
|
2033
|
-
const shiftToggleElementRef =
|
|
2034
|
-
|
|
2035
|
-
const guidesRef = useRef5(guides);
|
|
2036
|
-
const snapGuidesEnabledRef = useRef5(snapGuidesEnabled);
|
|
2037
|
-
const draggingGuideIdRef = useRef5(draggingGuideId);
|
|
2038
|
-
const guideOrientationRef = useRef5(guideOrientation);
|
|
2039
|
-
useEffect5(() => {
|
|
2540
|
+
const shiftDragRef = useRef6(false);
|
|
2541
|
+
const shiftToggleElementRef = useRef6(null);
|
|
2542
|
+
useEffect3(() => {
|
|
2040
2543
|
return () => {
|
|
2041
2544
|
if (hoverFrameRef.current) {
|
|
2042
|
-
cancelAnimationFrame(hoverFrameRef.current);
|
|
2545
|
+
window2.cancelAnimationFrame(hoverFrameRef.current);
|
|
2043
2546
|
}
|
|
2044
2547
|
};
|
|
2045
2548
|
}, []);
|
|
2046
|
-
useEffect5(() => {
|
|
2047
|
-
guidesEnabledRef.current = guidesEnabled;
|
|
2048
|
-
}, [guidesEnabled]);
|
|
2049
|
-
useEffect5(() => {
|
|
2050
|
-
guidesRef.current = guides;
|
|
2051
|
-
}, [guides]);
|
|
2052
|
-
useEffect5(() => {
|
|
2053
|
-
snapGuidesEnabledRef.current = snapGuidesEnabled;
|
|
2054
|
-
}, [snapGuidesEnabled]);
|
|
2055
|
-
useEffect5(() => {
|
|
2056
|
-
guideOrientationRef.current = guideOrientation;
|
|
2057
|
-
}, [guideOrientation]);
|
|
2058
|
-
useEffect5(() => {
|
|
2059
|
-
draggingGuideIdRef.current = draggingGuideId;
|
|
2060
|
-
}, [draggingGuideId]);
|
|
2061
2549
|
const updateHoverTarget = useCallback5(
|
|
2062
2550
|
(point) => {
|
|
2063
|
-
const target = getTargetElement(point, overlayRef.current);
|
|
2551
|
+
const target = getTargetElement(point, overlayRef.current, document2);
|
|
2064
2552
|
if (target) {
|
|
2065
2553
|
const rect = target.getBoundingClientRect();
|
|
2066
2554
|
setHoverRect({
|
|
@@ -2075,14 +2563,14 @@ var useMeasurerPointer = ({
|
|
|
2075
2563
|
setHoverElement(null);
|
|
2076
2564
|
}
|
|
2077
2565
|
},
|
|
2078
|
-
[overlayRef, setHoverElement, setHoverRect]
|
|
2566
|
+
[document2, overlayRef, setHoverElement, setHoverRect]
|
|
2079
2567
|
);
|
|
2080
2568
|
const updateHoverElement = useCallback5(
|
|
2081
2569
|
(point) => {
|
|
2082
|
-
const target = getTargetElement(point, overlayRef.current);
|
|
2570
|
+
const target = getTargetElement(point, overlayRef.current, document2);
|
|
2083
2571
|
setHoverElement(target);
|
|
2084
2572
|
},
|
|
2085
|
-
[overlayRef, setHoverElement]
|
|
2573
|
+
[document2, overlayRef, setHoverElement]
|
|
2086
2574
|
);
|
|
2087
2575
|
const handlePointerDown = useCallback5(
|
|
2088
2576
|
(event) => {
|
|
@@ -2097,7 +2585,8 @@ var useMeasurerPointer = ({
|
|
|
2097
2585
|
shiftToggleElementRef.current = event.shiftKey ? getSelectedMeasurementHit({
|
|
2098
2586
|
point,
|
|
2099
2587
|
selectedMeasurements,
|
|
2100
|
-
overlayNode: overlayRef.current
|
|
2588
|
+
overlayNode: overlayRef.current,
|
|
2589
|
+
document: document2
|
|
2101
2590
|
})?.elementRef ?? null : null;
|
|
2102
2591
|
selectionCacheRef.current.key = "";
|
|
2103
2592
|
if (altPressed && optionPairOverlay) {
|
|
@@ -2119,10 +2608,11 @@ var useMeasurerPointer = ({
|
|
|
2119
2608
|
snapGuidesEnabled,
|
|
2120
2609
|
overlayNode: overlayRef.current,
|
|
2121
2610
|
guides,
|
|
2122
|
-
draggingGuideId
|
|
2611
|
+
draggingGuideId,
|
|
2612
|
+
document: document2
|
|
2123
2613
|
});
|
|
2124
2614
|
const id = createId();
|
|
2125
|
-
setSelectedGuideIds([]);
|
|
2615
|
+
setSelectedGuideIds([id]);
|
|
2126
2616
|
setGuides((prev) => [
|
|
2127
2617
|
...prev,
|
|
2128
2618
|
{ id, orientation: guideOrientation, position }
|
|
@@ -2145,6 +2635,7 @@ var useMeasurerPointer = ({
|
|
|
2145
2635
|
clearSelectionRect,
|
|
2146
2636
|
createActionCommit,
|
|
2147
2637
|
draggingGuideId,
|
|
2638
|
+
document2,
|
|
2148
2639
|
enabled,
|
|
2149
2640
|
guideOrientation,
|
|
2150
2641
|
guides,
|
|
@@ -2186,31 +2677,32 @@ var useMeasurerPointer = ({
|
|
|
2186
2677
|
}
|
|
2187
2678
|
hoverPointRef.current = point;
|
|
2188
2679
|
if (!hoverFrameRef.current) {
|
|
2189
|
-
hoverFrameRef.current = requestAnimationFrame(() => {
|
|
2680
|
+
hoverFrameRef.current = window2.requestAnimationFrame(() => {
|
|
2190
2681
|
const latest = hoverPointRef.current;
|
|
2191
|
-
if (latest && !
|
|
2682
|
+
if (latest && !draggingGuideId) {
|
|
2192
2683
|
if (hoverHighlightEnabled) {
|
|
2193
2684
|
updateHoverTarget(latest);
|
|
2194
2685
|
} else {
|
|
2195
2686
|
updateHoverElement(latest);
|
|
2196
2687
|
}
|
|
2197
2688
|
}
|
|
2198
|
-
if (latest &&
|
|
2689
|
+
if (latest && guides.length > 0) {
|
|
2199
2690
|
setHoverPointer(latest);
|
|
2200
2691
|
} else {
|
|
2201
2692
|
setHoverPointer(null);
|
|
2202
2693
|
}
|
|
2203
|
-
if (
|
|
2694
|
+
if (guidesEnabled && latest && !draggingGuideId) {
|
|
2204
2695
|
const position = getSnapGuidePosition({
|
|
2205
|
-
orientation:
|
|
2696
|
+
orientation: guideOrientation,
|
|
2206
2697
|
point: latest,
|
|
2207
|
-
snapGuidesEnabled
|
|
2698
|
+
snapGuidesEnabled,
|
|
2208
2699
|
overlayNode: overlayRef.current,
|
|
2209
|
-
guides
|
|
2210
|
-
draggingGuideId
|
|
2700
|
+
guides,
|
|
2701
|
+
draggingGuideId,
|
|
2702
|
+
document: document2
|
|
2211
2703
|
});
|
|
2212
2704
|
setGuidePreview({
|
|
2213
|
-
orientation:
|
|
2705
|
+
orientation: guideOrientation,
|
|
2214
2706
|
position
|
|
2215
2707
|
});
|
|
2216
2708
|
} else {
|
|
@@ -2227,10 +2719,11 @@ var useMeasurerPointer = ({
|
|
|
2227
2719
|
position: getSnapGuidePosition({
|
|
2228
2720
|
orientation: guide.orientation,
|
|
2229
2721
|
point,
|
|
2230
|
-
snapGuidesEnabled
|
|
2722
|
+
snapGuidesEnabled,
|
|
2231
2723
|
overlayNode: overlayRef.current,
|
|
2232
|
-
guides
|
|
2233
|
-
draggingGuideId
|
|
2724
|
+
guides,
|
|
2725
|
+
draggingGuideId,
|
|
2726
|
+
document: document2
|
|
2234
2727
|
})
|
|
2235
2728
|
} : guide
|
|
2236
2729
|
)
|
|
@@ -2252,8 +2745,11 @@ var useMeasurerPointer = ({
|
|
|
2252
2745
|
draggingGuideId,
|
|
2253
2746
|
enabled,
|
|
2254
2747
|
hoverHighlightEnabled,
|
|
2748
|
+
guides,
|
|
2749
|
+
guidesEnabled,
|
|
2255
2750
|
isDragging,
|
|
2256
2751
|
overlayRef,
|
|
2752
|
+
guideOrientation,
|
|
2257
2753
|
setAltPressed,
|
|
2258
2754
|
setEnd,
|
|
2259
2755
|
setGuidePreview,
|
|
@@ -2262,6 +2758,7 @@ var useMeasurerPointer = ({
|
|
|
2262
2758
|
setHoverPointer,
|
|
2263
2759
|
setHoverRect,
|
|
2264
2760
|
setIsDragging,
|
|
2761
|
+
snapGuidesEnabled,
|
|
2265
2762
|
start,
|
|
2266
2763
|
toolMode,
|
|
2267
2764
|
toolbarRef,
|
|
@@ -2315,7 +2812,8 @@ var useMeasurerPointer = ({
|
|
|
2315
2812
|
const elements = getElementsInRectCached(
|
|
2316
2813
|
selectionRect,
|
|
2317
2814
|
overlayRef.current,
|
|
2318
|
-
selectionCacheRef.current
|
|
2815
|
+
selectionCacheRef.current,
|
|
2816
|
+
document2
|
|
2319
2817
|
);
|
|
2320
2818
|
const hasSameSelection = elements.length === selectedMeasurements.length && elements.every(
|
|
2321
2819
|
(element, index) => selectedMeasurements[index]?.elementRef === element
|
|
@@ -2326,7 +2824,7 @@ var useMeasurerPointer = ({
|
|
|
2326
2824
|
if (!hasSameSelection) {
|
|
2327
2825
|
commit();
|
|
2328
2826
|
const nextMeasurements = elements.map((element) => ({
|
|
2329
|
-
...getInspectMeasurement(element),
|
|
2827
|
+
...getInspectMeasurement(element, window2),
|
|
2330
2828
|
originRect: selectionRect
|
|
2331
2829
|
}));
|
|
2332
2830
|
setSelectedMeasurements(nextMeasurements);
|
|
@@ -2360,7 +2858,8 @@ var useMeasurerPointer = ({
|
|
|
2360
2858
|
) ?? null : getSelectedMeasurementHit({
|
|
2361
2859
|
point,
|
|
2362
2860
|
selectedMeasurements,
|
|
2363
|
-
overlayNode: overlayRef.current
|
|
2861
|
+
overlayNode: overlayRef.current,
|
|
2862
|
+
document: document2
|
|
2364
2863
|
});
|
|
2365
2864
|
if (event.shiftKey && selectedHit) {
|
|
2366
2865
|
commit();
|
|
@@ -2390,9 +2889,9 @@ var useMeasurerPointer = ({
|
|
|
2390
2889
|
resetDragState();
|
|
2391
2890
|
return;
|
|
2392
2891
|
}
|
|
2393
|
-
const target = event.shiftKey ? getTargetElement(point, overlayRef.current) ?? getSnappedClickTarget(point, overlayRef.current, snapEnabled) : getSnappedClickTarget(point, overlayRef.current, snapEnabled);
|
|
2892
|
+
const target = event.shiftKey ? getTargetElement(point, overlayRef.current, document2) ?? getSnappedClickTarget(point, overlayRef.current, snapEnabled, document2) : getSnappedClickTarget(point, overlayRef.current, snapEnabled, document2);
|
|
2394
2893
|
if (target) {
|
|
2395
|
-
const inspectMeasurement = getInspectMeasurement(target);
|
|
2894
|
+
const inspectMeasurement = getInspectMeasurement(target, window2);
|
|
2396
2895
|
clearTransientMeasurements();
|
|
2397
2896
|
if (event.shiftKey) {
|
|
2398
2897
|
const alreadySelected = selectedMeasurements.some(
|
|
@@ -2491,41 +2990,48 @@ var useMeasurerPointer = ({
|
|
|
2491
2990
|
};
|
|
2492
2991
|
|
|
2493
2992
|
// hooks/use-overlay-refs.ts
|
|
2494
|
-
import { useRef as
|
|
2993
|
+
import { useRef as useRef7 } from "react";
|
|
2495
2994
|
var useOverlayRefs = () => {
|
|
2496
|
-
const overlayRef =
|
|
2497
|
-
const selectedElementRef =
|
|
2498
|
-
const hoverElementRef =
|
|
2995
|
+
const overlayRef = useRef7(null);
|
|
2996
|
+
const selectedElementRef = useRef7(null);
|
|
2997
|
+
const hoverElementRef = useRef7(null);
|
|
2499
2998
|
return { overlayRef, selectedElementRef, hoverElementRef };
|
|
2500
2999
|
};
|
|
2501
3000
|
|
|
2502
3001
|
// hooks/use-resize-sync.ts
|
|
2503
|
-
import { useEffect as
|
|
3002
|
+
import { useEffect as useEffect4, useRef as useRef8 } from "react";
|
|
2504
3003
|
var useResizeSync = (params) => {
|
|
2505
|
-
const resizeFrameRef =
|
|
2506
|
-
const viewportRef =
|
|
2507
|
-
|
|
3004
|
+
const resizeFrameRef = useRef8(null);
|
|
3005
|
+
const viewportRef = useRef8(getViewportSize(params.window));
|
|
3006
|
+
useEffect4(() => {
|
|
2508
3007
|
const handleResize = () => {
|
|
2509
3008
|
if (resizeFrameRef.current) {
|
|
2510
|
-
cancelAnimationFrame(resizeFrameRef.current);
|
|
3009
|
+
params.window.cancelAnimationFrame(resizeFrameRef.current);
|
|
2511
3010
|
}
|
|
2512
|
-
resizeFrameRef.current = requestAnimationFrame(() => {
|
|
2513
|
-
const viewport = getViewportSize();
|
|
3011
|
+
resizeFrameRef.current = params.window.requestAnimationFrame(() => {
|
|
3012
|
+
const viewport = getViewportSize(params.window);
|
|
2514
3013
|
const previousViewport = viewportRef.current;
|
|
2515
3014
|
params.setMeasurements(
|
|
2516
3015
|
(prev) => prev.map(
|
|
2517
|
-
(measurement) => updateMeasurementForResize(measurement, viewport)
|
|
3016
|
+
(measurement) => updateMeasurementForResize(measurement, viewport, params.document)
|
|
2518
3017
|
)
|
|
2519
3018
|
);
|
|
2520
3019
|
params.setActiveMeasurement(
|
|
2521
|
-
(prev) => prev ? updateMeasurementForResize(prev, viewport) : prev
|
|
3020
|
+
(prev) => prev ? updateMeasurementForResize(prev, viewport, params.document) : prev
|
|
2522
3021
|
);
|
|
2523
3022
|
params.setHeldDistances(
|
|
2524
|
-
(prev) => prev.map(
|
|
3023
|
+
(prev) => prev.map(
|
|
3024
|
+
(distance) => updateDistanceForResize(
|
|
3025
|
+
distance,
|
|
3026
|
+
viewport,
|
|
3027
|
+
params.document,
|
|
3028
|
+
params.window
|
|
3029
|
+
)
|
|
3030
|
+
)
|
|
2525
3031
|
);
|
|
2526
|
-
if (params.selectedElementRef.current) {
|
|
3032
|
+
if (params.selectedElementRef.current && params.document.contains(params.selectedElementRef.current)) {
|
|
2527
3033
|
params.setSelectedMeasurement(
|
|
2528
|
-
getInspectMeasurement(params.selectedElementRef.current)
|
|
3034
|
+
getInspectMeasurement(params.selectedElementRef.current, params.window)
|
|
2529
3035
|
);
|
|
2530
3036
|
}
|
|
2531
3037
|
if (previousViewport.width > 0 && previousViewport.height > 0) {
|
|
@@ -2540,27 +3046,27 @@ var useResizeSync = (params) => {
|
|
|
2540
3046
|
viewportRef.current = viewport;
|
|
2541
3047
|
});
|
|
2542
3048
|
};
|
|
2543
|
-
window.addEventListener("resize", handleResize);
|
|
3049
|
+
params.window.addEventListener("resize", handleResize);
|
|
2544
3050
|
return () => {
|
|
2545
3051
|
if (resizeFrameRef.current) {
|
|
2546
|
-
cancelAnimationFrame(resizeFrameRef.current);
|
|
3052
|
+
params.window.cancelAnimationFrame(resizeFrameRef.current);
|
|
2547
3053
|
}
|
|
2548
|
-
window.removeEventListener("resize", handleResize);
|
|
3054
|
+
params.window.removeEventListener("resize", handleResize);
|
|
2549
3055
|
};
|
|
2550
3056
|
}, [params]);
|
|
2551
3057
|
};
|
|
2552
3058
|
|
|
2553
3059
|
// render/measurer-overlay.tsx
|
|
2554
|
-
import { memo as
|
|
3060
|
+
import { memo as memo6 } from "react";
|
|
2555
3061
|
|
|
2556
3062
|
// components/measure-tag.tsx
|
|
2557
|
-
import { jsx as
|
|
3063
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
2558
3064
|
function MeasureTag({
|
|
2559
3065
|
children,
|
|
2560
3066
|
className = "",
|
|
2561
3067
|
style
|
|
2562
3068
|
}) {
|
|
2563
|
-
return /* @__PURE__ */
|
|
3069
|
+
return /* @__PURE__ */ jsx4(
|
|
2564
3070
|
"div",
|
|
2565
3071
|
{
|
|
2566
3072
|
className: cn(
|
|
@@ -2574,31 +3080,21 @@ function MeasureTag({
|
|
|
2574
3080
|
}
|
|
2575
3081
|
|
|
2576
3082
|
// components/measurement-box.tsx
|
|
2577
|
-
import { memo as
|
|
2578
|
-
import { jsx as
|
|
3083
|
+
import { memo as memo3 } from "react";
|
|
3084
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2579
3085
|
var formatValue2 = (value) => Math.round(value);
|
|
2580
|
-
var MeasurementBox =
|
|
3086
|
+
var MeasurementBox = memo3(function MeasurementBox2({
|
|
2581
3087
|
measurement,
|
|
2582
3088
|
transitionMs,
|
|
2583
3089
|
labelOffset,
|
|
2584
3090
|
edgeVisibility
|
|
2585
3091
|
}) {
|
|
2586
|
-
const [rect, setRect] = useState7(
|
|
2587
|
-
measurement.originRect ?? measurement.rect
|
|
2588
|
-
);
|
|
2589
|
-
useEffect7(() => {
|
|
2590
|
-
if (!measurement.originRect) return;
|
|
2591
|
-
const frame = requestAnimationFrame(() => {
|
|
2592
|
-
setRect(measurement.rect);
|
|
2593
|
-
});
|
|
2594
|
-
return () => cancelAnimationFrame(frame);
|
|
2595
|
-
}, [measurement]);
|
|
2596
3092
|
const edges = edgeVisibility ?? { top: true, right: true, bottom: true, left: true };
|
|
2597
|
-
const displayRect = measurement.
|
|
3093
|
+
const displayRect = measurement.rect;
|
|
2598
3094
|
const outlineColor = "color-mix(in oklch, oklch(0.62 0.18 255) 80%, transparent)";
|
|
2599
3095
|
const fillColor = "color-mix(in oklch, oklch(0.62 0.18 255) 8%, transparent)";
|
|
2600
|
-
return /* @__PURE__ */
|
|
2601
|
-
/* @__PURE__ */
|
|
3096
|
+
return /* @__PURE__ */ jsxs3("div", { className: "msr:pointer-events-none", children: [
|
|
3097
|
+
/* @__PURE__ */ jsxs3(
|
|
2602
3098
|
"div",
|
|
2603
3099
|
{
|
|
2604
3100
|
className: "msr:absolute",
|
|
@@ -2608,31 +3104,31 @@ var MeasurementBox = memo2(function MeasurementBox2({
|
|
|
2608
3104
|
width: displayRect.width,
|
|
2609
3105
|
height: displayRect.height,
|
|
2610
3106
|
backgroundColor: fillColor,
|
|
2611
|
-
transition:
|
|
3107
|
+
transition: `left ${transitionMs}ms ease, top ${transitionMs}ms ease, width ${transitionMs}ms ease, height ${transitionMs}ms ease`
|
|
2612
3108
|
},
|
|
2613
3109
|
children: [
|
|
2614
|
-
edges.top ? /* @__PURE__ */
|
|
3110
|
+
edges.top ? /* @__PURE__ */ jsx5(
|
|
2615
3111
|
"div",
|
|
2616
3112
|
{
|
|
2617
3113
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-px msr:w-full",
|
|
2618
3114
|
style: { backgroundColor: outlineColor }
|
|
2619
3115
|
}
|
|
2620
3116
|
) : null,
|
|
2621
|
-
edges.right ? /* @__PURE__ */
|
|
3117
|
+
edges.right ? /* @__PURE__ */ jsx5(
|
|
2622
3118
|
"div",
|
|
2623
3119
|
{
|
|
2624
3120
|
className: "msr:absolute msr:right-0 msr:top-0 msr:h-full msr:w-px",
|
|
2625
3121
|
style: { backgroundColor: outlineColor }
|
|
2626
3122
|
}
|
|
2627
3123
|
) : null,
|
|
2628
|
-
edges.bottom ? /* @__PURE__ */
|
|
3124
|
+
edges.bottom ? /* @__PURE__ */ jsx5(
|
|
2629
3125
|
"div",
|
|
2630
3126
|
{
|
|
2631
3127
|
className: "msr:absolute msr:bottom-0 msr:left-0 msr:h-px msr:w-full",
|
|
2632
3128
|
style: { backgroundColor: outlineColor }
|
|
2633
3129
|
}
|
|
2634
3130
|
) : null,
|
|
2635
|
-
edges.left ? /* @__PURE__ */
|
|
3131
|
+
edges.left ? /* @__PURE__ */ jsx5(
|
|
2636
3132
|
"div",
|
|
2637
3133
|
{
|
|
2638
3134
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-full msr:w-px",
|
|
@@ -2642,14 +3138,14 @@ var MeasurementBox = memo2(function MeasurementBox2({
|
|
|
2642
3138
|
]
|
|
2643
3139
|
}
|
|
2644
3140
|
),
|
|
2645
|
-
/* @__PURE__ */
|
|
3141
|
+
/* @__PURE__ */ jsxs3(
|
|
2646
3142
|
MeasureTag,
|
|
2647
3143
|
{
|
|
2648
3144
|
className: "msr:-translate-x-1/2 msr:bg-ink-900/90",
|
|
2649
3145
|
style: {
|
|
2650
3146
|
left: displayRect.left + displayRect.width / 2,
|
|
2651
3147
|
top: displayRect.top + displayRect.height + labelOffset,
|
|
2652
|
-
transition:
|
|
3148
|
+
transition: `left ${transitionMs}ms ease, top ${transitionMs}ms ease`
|
|
2653
3149
|
},
|
|
2654
3150
|
children: [
|
|
2655
3151
|
formatValue2(displayRect.width),
|
|
@@ -2662,31 +3158,21 @@ var MeasurementBox = memo2(function MeasurementBox2({
|
|
|
2662
3158
|
});
|
|
2663
3159
|
|
|
2664
3160
|
// components/selected-measurement-box.tsx
|
|
2665
|
-
import { memo as
|
|
2666
|
-
import { jsx as
|
|
3161
|
+
import { memo as memo4 } from "react";
|
|
3162
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2667
3163
|
var formatValue3 = (value) => Math.round(value);
|
|
2668
|
-
var SelectedMeasurementBox =
|
|
3164
|
+
var SelectedMeasurementBox = memo4(function SelectedMeasurementBox2({
|
|
2669
3165
|
measurement,
|
|
2670
3166
|
transitionMs,
|
|
2671
3167
|
labelOffset,
|
|
2672
3168
|
edgeVisibility
|
|
2673
3169
|
}) {
|
|
2674
|
-
const [rect, setRect] = useState8(
|
|
2675
|
-
measurement.originRect ?? measurement.rect
|
|
2676
|
-
);
|
|
2677
|
-
useEffect8(() => {
|
|
2678
|
-
if (!measurement.originRect) return;
|
|
2679
|
-
const frame = requestAnimationFrame(() => {
|
|
2680
|
-
setRect(measurement.rect);
|
|
2681
|
-
});
|
|
2682
|
-
return () => cancelAnimationFrame(frame);
|
|
2683
|
-
}, [measurement]);
|
|
2684
3170
|
const edges = edgeVisibility ?? { top: true, right: true, bottom: true, left: true };
|
|
2685
|
-
const displayRect = measurement.
|
|
3171
|
+
const displayRect = measurement.rect;
|
|
2686
3172
|
const outlineColor = "color-mix(in oklch, oklch(0.62 0.18 255) 80%, transparent)";
|
|
2687
3173
|
const fillColor = "color-mix(in oklch, oklch(0.62 0.18 255) 8%, transparent)";
|
|
2688
|
-
return /* @__PURE__ */
|
|
2689
|
-
/* @__PURE__ */
|
|
3174
|
+
return /* @__PURE__ */ jsxs4("div", { className: "msr:pointer-events-none", children: [
|
|
3175
|
+
/* @__PURE__ */ jsxs4(
|
|
2690
3176
|
"div",
|
|
2691
3177
|
{
|
|
2692
3178
|
className: "msr:absolute",
|
|
@@ -2696,31 +3182,31 @@ var SelectedMeasurementBox = memo3(function SelectedMeasurementBox2({
|
|
|
2696
3182
|
width: displayRect.width,
|
|
2697
3183
|
height: displayRect.height,
|
|
2698
3184
|
backgroundColor: fillColor,
|
|
2699
|
-
transition:
|
|
3185
|
+
transition: `left ${transitionMs}ms ease, top ${transitionMs}ms ease, width ${transitionMs}ms ease, height ${transitionMs}ms ease`
|
|
2700
3186
|
},
|
|
2701
3187
|
children: [
|
|
2702
|
-
edges.top ? /* @__PURE__ */
|
|
3188
|
+
edges.top ? /* @__PURE__ */ jsx6(
|
|
2703
3189
|
"div",
|
|
2704
3190
|
{
|
|
2705
3191
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-px msr:w-full",
|
|
2706
3192
|
style: { backgroundColor: outlineColor }
|
|
2707
3193
|
}
|
|
2708
3194
|
) : null,
|
|
2709
|
-
edges.right ? /* @__PURE__ */
|
|
3195
|
+
edges.right ? /* @__PURE__ */ jsx6(
|
|
2710
3196
|
"div",
|
|
2711
3197
|
{
|
|
2712
3198
|
className: "msr:absolute msr:right-0 msr:top-0 msr:h-full msr:w-px",
|
|
2713
3199
|
style: { backgroundColor: outlineColor }
|
|
2714
3200
|
}
|
|
2715
3201
|
) : null,
|
|
2716
|
-
edges.bottom ? /* @__PURE__ */
|
|
3202
|
+
edges.bottom ? /* @__PURE__ */ jsx6(
|
|
2717
3203
|
"div",
|
|
2718
3204
|
{
|
|
2719
3205
|
className: "msr:absolute msr:bottom-0 msr:left-0 msr:h-px msr:w-full",
|
|
2720
3206
|
style: { backgroundColor: outlineColor }
|
|
2721
3207
|
}
|
|
2722
3208
|
) : null,
|
|
2723
|
-
edges.left ? /* @__PURE__ */
|
|
3209
|
+
edges.left ? /* @__PURE__ */ jsx6(
|
|
2724
3210
|
"div",
|
|
2725
3211
|
{
|
|
2726
3212
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-full msr:w-px",
|
|
@@ -2730,14 +3216,14 @@ var SelectedMeasurementBox = memo3(function SelectedMeasurementBox2({
|
|
|
2730
3216
|
]
|
|
2731
3217
|
}
|
|
2732
3218
|
),
|
|
2733
|
-
/* @__PURE__ */
|
|
3219
|
+
/* @__PURE__ */ jsxs4(
|
|
2734
3220
|
MeasureTag,
|
|
2735
3221
|
{
|
|
2736
3222
|
className: "msr:-translate-x-1/2 msr:bg-ink-900/90",
|
|
2737
3223
|
style: {
|
|
2738
3224
|
left: displayRect.left + displayRect.width / 2,
|
|
2739
3225
|
top: displayRect.top + displayRect.height + labelOffset,
|
|
2740
|
-
transition:
|
|
3226
|
+
transition: `left ${transitionMs}ms ease, top ${transitionMs}ms ease`
|
|
2741
3227
|
},
|
|
2742
3228
|
children: [
|
|
2743
3229
|
formatValue3(displayRect.width),
|
|
@@ -2750,14 +3236,14 @@ var SelectedMeasurementBox = memo3(function SelectedMeasurementBox2({
|
|
|
2750
3236
|
});
|
|
2751
3237
|
|
|
2752
3238
|
// render/distance-overlay-item.tsx
|
|
2753
|
-
import { memo as
|
|
2754
|
-
import { Fragment, jsx as
|
|
2755
|
-
var DistanceOverlayItem =
|
|
3239
|
+
import { memo as memo5 } from "react";
|
|
3240
|
+
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
3241
|
+
var DistanceOverlayItem = memo5(function DistanceOverlayItem2({
|
|
2756
3242
|
distance,
|
|
2757
3243
|
labelOffset,
|
|
2758
3244
|
onRemove
|
|
2759
3245
|
}) {
|
|
2760
|
-
return /* @__PURE__ */
|
|
3246
|
+
return /* @__PURE__ */ jsxs5(
|
|
2761
3247
|
"div",
|
|
2762
3248
|
{
|
|
2763
3249
|
className: onRemove ? "msr:pointer-events-auto" : "msr:pointer-events-none",
|
|
@@ -2766,7 +3252,7 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2766
3252
|
onRemove(distance.id);
|
|
2767
3253
|
} : void 0,
|
|
2768
3254
|
children: [
|
|
2769
|
-
/* @__PURE__ */
|
|
3255
|
+
/* @__PURE__ */ jsx7(
|
|
2770
3256
|
"div",
|
|
2771
3257
|
{
|
|
2772
3258
|
className: "msr:absolute msr:rounded msr:border msr:border-[#2563eb]/70",
|
|
@@ -2778,7 +3264,7 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2778
3264
|
}
|
|
2779
3265
|
}
|
|
2780
3266
|
),
|
|
2781
|
-
/* @__PURE__ */
|
|
3267
|
+
/* @__PURE__ */ jsx7(
|
|
2782
3268
|
"div",
|
|
2783
3269
|
{
|
|
2784
3270
|
className: "msr:absolute msr:rounded msr:border msr:border-[#2563eb]/70",
|
|
@@ -2791,7 +3277,7 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2791
3277
|
}
|
|
2792
3278
|
),
|
|
2793
3279
|
distance.connectors.map(
|
|
2794
|
-
(connector, index) => Math.abs(connector.x1 - connector.x2) < 1 ? /* @__PURE__ */
|
|
3280
|
+
(connector, index) => Math.abs(connector.x1 - connector.x2) < 1 ? /* @__PURE__ */ jsx7(
|
|
2795
3281
|
"div",
|
|
2796
3282
|
{
|
|
2797
3283
|
className: "msr:absolute msr:border-l msr:border-dashed msr:border-[#2563eb]/70",
|
|
@@ -2802,7 +3288,7 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2802
3288
|
}
|
|
2803
3289
|
},
|
|
2804
3290
|
`${distance.id}-connector-${index}`
|
|
2805
|
-
) : /* @__PURE__ */
|
|
3291
|
+
) : /* @__PURE__ */ jsx7(
|
|
2806
3292
|
"div",
|
|
2807
3293
|
{
|
|
2808
3294
|
className: "msr:absolute msr:border-t msr:border-dashed msr:border-[#2563eb]/70",
|
|
@@ -2815,8 +3301,8 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2815
3301
|
`${distance.id}-connector-${index}`
|
|
2816
3302
|
)
|
|
2817
3303
|
),
|
|
2818
|
-
distance.horizontal && distance.horizontal.value > 0 ? /* @__PURE__ */
|
|
2819
|
-
/* @__PURE__ */
|
|
3304
|
+
distance.horizontal && distance.horizontal.value > 0 ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
3305
|
+
/* @__PURE__ */ jsx7(
|
|
2820
3306
|
"div",
|
|
2821
3307
|
{
|
|
2822
3308
|
className: "msr:absolute msr:h-px msr:bg-[#2563eb]",
|
|
@@ -2827,7 +3313,7 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2827
3313
|
}
|
|
2828
3314
|
}
|
|
2829
3315
|
),
|
|
2830
|
-
/* @__PURE__ */
|
|
3316
|
+
/* @__PURE__ */ jsx7(
|
|
2831
3317
|
MeasureTag,
|
|
2832
3318
|
{
|
|
2833
3319
|
className: "msr:-translate-x-1/2 msr:bg-ink-900/90",
|
|
@@ -2839,8 +3325,8 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2839
3325
|
}
|
|
2840
3326
|
)
|
|
2841
3327
|
] }) : null,
|
|
2842
|
-
distance.vertical && distance.vertical.value > 0 ? /* @__PURE__ */
|
|
2843
|
-
/* @__PURE__ */
|
|
3328
|
+
distance.vertical && distance.vertical.value > 0 ? /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
3329
|
+
/* @__PURE__ */ jsx7(
|
|
2844
3330
|
"div",
|
|
2845
3331
|
{
|
|
2846
3332
|
className: "msr:absolute msr:w-px msr:bg-[#2563eb]",
|
|
@@ -2851,7 +3337,7 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2851
3337
|
}
|
|
2852
3338
|
}
|
|
2853
3339
|
),
|
|
2854
|
-
/* @__PURE__ */
|
|
3340
|
+
/* @__PURE__ */ jsx7(
|
|
2855
3341
|
MeasureTag,
|
|
2856
3342
|
{
|
|
2857
3343
|
className: "msr:-translate-y-1/2 msr:bg-ink-900/90",
|
|
@@ -2869,10 +3355,11 @@ var DistanceOverlayItem = memo4(function DistanceOverlayItem2({
|
|
|
2869
3355
|
});
|
|
2870
3356
|
|
|
2871
3357
|
// render/measurer-overlay.tsx
|
|
2872
|
-
import { Fragment as Fragment2, jsx as
|
|
2873
|
-
var MeasurerOverlay =
|
|
3358
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3359
|
+
var MeasurerOverlay = memo6(function MeasurerOverlay2({
|
|
2874
3360
|
enabled,
|
|
2875
3361
|
toolMode,
|
|
3362
|
+
guidePointerEvents,
|
|
2876
3363
|
guidesEnabled,
|
|
2877
3364
|
altPressed,
|
|
2878
3365
|
isDragging,
|
|
@@ -2909,16 +3396,20 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
2909
3396
|
onGuidePointerUp,
|
|
2910
3397
|
onGuidePointerCancel
|
|
2911
3398
|
}) {
|
|
2912
|
-
|
|
3399
|
+
const overlayVisible = enabled;
|
|
3400
|
+
const overlayInteractive = overlayVisible && toolMode !== "none" && toolMode !== "text-inspector" && toolMode !== "xray" && toolMode !== "rulers";
|
|
3401
|
+
const selectionVisible = toolMode === "select";
|
|
3402
|
+
return /* @__PURE__ */ jsxs6(
|
|
2913
3403
|
"div",
|
|
2914
3404
|
{
|
|
2915
|
-
className: `msr:absolute msr:inset-0 ${
|
|
3405
|
+
className: `msr:absolute msr:inset-0 ${overlayVisible ? `msr:pointer-events-auto ${guidesEnabled ? hoverGuide || draggingGuideId ? "msr:cursor-default" : "msr:cursor-crosshair" : "msr:cursor-default"} msr:opacity-100` : "msr:pointer-events-none msr:opacity-0"}`,
|
|
3406
|
+
style: { pointerEvents: overlayInteractive ? "auto" : "none" },
|
|
2916
3407
|
onPointerDown,
|
|
2917
3408
|
onPointerMove,
|
|
2918
3409
|
onPointerUp,
|
|
2919
3410
|
onPointerLeave,
|
|
2920
3411
|
children: [
|
|
2921
|
-
|
|
3412
|
+
selectionVisible ? displayedMeasurements.map((measurement, index) => /* @__PURE__ */ jsx8(
|
|
2922
3413
|
MeasurementBox,
|
|
2923
3414
|
{
|
|
2924
3415
|
measurement,
|
|
@@ -2928,8 +3419,8 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
2928
3419
|
},
|
|
2929
3420
|
measurement.id
|
|
2930
3421
|
)) : null,
|
|
2931
|
-
|
|
2932
|
-
/* @__PURE__ */
|
|
3422
|
+
selectionVisible && activeRect && isDragging ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
3423
|
+
/* @__PURE__ */ jsxs6(
|
|
2933
3424
|
"div",
|
|
2934
3425
|
{
|
|
2935
3426
|
className: "msr:pointer-events-none msr:absolute",
|
|
@@ -2941,28 +3432,28 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
2941
3432
|
backgroundColor: fillColor
|
|
2942
3433
|
},
|
|
2943
3434
|
children: [
|
|
2944
|
-
/* @__PURE__ */
|
|
3435
|
+
/* @__PURE__ */ jsx8(
|
|
2945
3436
|
"div",
|
|
2946
3437
|
{
|
|
2947
3438
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-px msr:w-full",
|
|
2948
3439
|
style: { backgroundColor: outlineColor }
|
|
2949
3440
|
}
|
|
2950
3441
|
),
|
|
2951
|
-
/* @__PURE__ */
|
|
3442
|
+
/* @__PURE__ */ jsx8(
|
|
2952
3443
|
"div",
|
|
2953
3444
|
{
|
|
2954
3445
|
className: "msr:absolute msr:right-0 msr:top-0 msr:h-full msr:w-px",
|
|
2955
3446
|
style: { backgroundColor: outlineColor }
|
|
2956
3447
|
}
|
|
2957
3448
|
),
|
|
2958
|
-
/* @__PURE__ */
|
|
3449
|
+
/* @__PURE__ */ jsx8(
|
|
2959
3450
|
"div",
|
|
2960
3451
|
{
|
|
2961
3452
|
className: "msr:absolute msr:bottom-0 msr:left-0 msr:h-px msr:w-full",
|
|
2962
3453
|
style: { backgroundColor: outlineColor }
|
|
2963
3454
|
}
|
|
2964
3455
|
),
|
|
2965
|
-
/* @__PURE__ */
|
|
3456
|
+
/* @__PURE__ */ jsx8(
|
|
2966
3457
|
"div",
|
|
2967
3458
|
{
|
|
2968
3459
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-full msr:w-px",
|
|
@@ -2972,7 +3463,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
2972
3463
|
]
|
|
2973
3464
|
}
|
|
2974
3465
|
),
|
|
2975
|
-
/* @__PURE__ */
|
|
3466
|
+
/* @__PURE__ */ jsxs6(
|
|
2976
3467
|
MeasureTag,
|
|
2977
3468
|
{
|
|
2978
3469
|
className: "msr:-translate-x-1/2 msr:bg-ink-900/90",
|
|
@@ -2988,7 +3479,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
2988
3479
|
}
|
|
2989
3480
|
)
|
|
2990
3481
|
] }) : null,
|
|
2991
|
-
|
|
3482
|
+
selectionVisible && hoverRectToShow ? /* @__PURE__ */ jsxs6(
|
|
2992
3483
|
"div",
|
|
2993
3484
|
{
|
|
2994
3485
|
className: "msr:pointer-events-none msr:absolute",
|
|
@@ -3000,28 +3491,28 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3000
3491
|
backgroundColor: fillColor
|
|
3001
3492
|
},
|
|
3002
3493
|
children: [
|
|
3003
|
-
hoverEdgeVisibility?.top ? /* @__PURE__ */
|
|
3494
|
+
hoverEdgeVisibility?.top ? /* @__PURE__ */ jsx8(
|
|
3004
3495
|
"div",
|
|
3005
3496
|
{
|
|
3006
3497
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-px msr:w-full",
|
|
3007
3498
|
style: { backgroundColor: outlineColor }
|
|
3008
3499
|
}
|
|
3009
3500
|
) : null,
|
|
3010
|
-
hoverEdgeVisibility?.right ? /* @__PURE__ */
|
|
3501
|
+
hoverEdgeVisibility?.right ? /* @__PURE__ */ jsx8(
|
|
3011
3502
|
"div",
|
|
3012
3503
|
{
|
|
3013
3504
|
className: "msr:absolute msr:right-0 msr:top-0 msr:h-full msr:w-px",
|
|
3014
3505
|
style: { backgroundColor: outlineColor }
|
|
3015
3506
|
}
|
|
3016
3507
|
) : null,
|
|
3017
|
-
hoverEdgeVisibility?.bottom ? /* @__PURE__ */
|
|
3508
|
+
hoverEdgeVisibility?.bottom ? /* @__PURE__ */ jsx8(
|
|
3018
3509
|
"div",
|
|
3019
3510
|
{
|
|
3020
3511
|
className: "msr:absolute msr:bottom-0 msr:left-0 msr:h-px msr:w-full",
|
|
3021
3512
|
style: { backgroundColor: outlineColor }
|
|
3022
3513
|
}
|
|
3023
3514
|
) : null,
|
|
3024
|
-
hoverEdgeVisibility?.left ? /* @__PURE__ */
|
|
3515
|
+
hoverEdgeVisibility?.left ? /* @__PURE__ */ jsx8(
|
|
3025
3516
|
"div",
|
|
3026
3517
|
{
|
|
3027
3518
|
className: "msr:absolute msr:left-0 msr:top-0 msr:h-full msr:w-px",
|
|
@@ -3031,7 +3522,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3031
3522
|
]
|
|
3032
3523
|
}
|
|
3033
3524
|
) : null,
|
|
3034
|
-
guidesEnabled && guidePreview ? /* @__PURE__ */
|
|
3525
|
+
guidesEnabled && guidePreview ? /* @__PURE__ */ jsx8(
|
|
3035
3526
|
"div",
|
|
3036
3527
|
{
|
|
3037
3528
|
className: "msr:pointer-events-none msr:absolute",
|
|
@@ -3046,7 +3537,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3046
3537
|
height: GUIDE_HITBOX_SIZE,
|
|
3047
3538
|
width: "100%"
|
|
3048
3539
|
},
|
|
3049
|
-
children: /* @__PURE__ */
|
|
3540
|
+
children: /* @__PURE__ */ jsx8(
|
|
3050
3541
|
"div",
|
|
3051
3542
|
{
|
|
3052
3543
|
className: "msr:absolute",
|
|
@@ -3067,7 +3558,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3067
3558
|
)
|
|
3068
3559
|
}
|
|
3069
3560
|
) : null,
|
|
3070
|
-
|
|
3561
|
+
selectionVisible ? displayedSelectedMeasurements.map((measurement, index) => /* @__PURE__ */ jsx8(
|
|
3071
3562
|
SelectedMeasurementBox,
|
|
3072
3563
|
{
|
|
3073
3564
|
measurement,
|
|
@@ -3077,7 +3568,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3077
3568
|
},
|
|
3078
3569
|
measurement.id
|
|
3079
3570
|
)) : null,
|
|
3080
|
-
heldDistances.map((distance) => /* @__PURE__ */
|
|
3571
|
+
heldDistances.map((distance) => /* @__PURE__ */ jsx8(
|
|
3081
3572
|
DistanceOverlayItem,
|
|
3082
3573
|
{
|
|
3083
3574
|
distance,
|
|
@@ -3086,7 +3577,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3086
3577
|
},
|
|
3087
3578
|
`held-${distance.id}`
|
|
3088
3579
|
)),
|
|
3089
|
-
|
|
3580
|
+
selectionVisible && altPressed && optionPairOverlay ? /* @__PURE__ */ jsx8(
|
|
3090
3581
|
DistanceOverlayItem,
|
|
3091
3582
|
{
|
|
3092
3583
|
distance: optionPairOverlay,
|
|
@@ -3094,7 +3585,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3094
3585
|
},
|
|
3095
3586
|
`option-${optionPairOverlay.id}`
|
|
3096
3587
|
) : null,
|
|
3097
|
-
guidesEnabled && altPressed && guideDistanceOverlay ? /* @__PURE__ */
|
|
3588
|
+
guidesEnabled && altPressed && guideDistanceOverlay ? /* @__PURE__ */ jsx8(
|
|
3098
3589
|
DistanceOverlayItem,
|
|
3099
3590
|
{
|
|
3100
3591
|
distance: guideDistanceOverlay,
|
|
@@ -3102,9 +3593,9 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3102
3593
|
},
|
|
3103
3594
|
`guide-preview-${guideDistanceOverlay.id}`
|
|
3104
3595
|
) : null,
|
|
3105
|
-
|
|
3106
|
-
optionContainerLines.top.value > 0 ? /* @__PURE__ */
|
|
3107
|
-
/* @__PURE__ */
|
|
3596
|
+
selectionVisible && altPressed && optionContainerLines ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
3597
|
+
optionContainerLines.top.value > 0 ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
3598
|
+
/* @__PURE__ */ jsx8(
|
|
3108
3599
|
"div",
|
|
3109
3600
|
{
|
|
3110
3601
|
className: "msr:absolute msr:w-px msr:bg-[#2563eb]",
|
|
@@ -3115,7 +3606,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3115
3606
|
}
|
|
3116
3607
|
}
|
|
3117
3608
|
),
|
|
3118
|
-
/* @__PURE__ */
|
|
3609
|
+
/* @__PURE__ */ jsx8(
|
|
3119
3610
|
MeasureTag,
|
|
3120
3611
|
{
|
|
3121
3612
|
className: "msr:-translate-y-1/2 msr:bg-ink-900/90",
|
|
@@ -3127,8 +3618,8 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3127
3618
|
}
|
|
3128
3619
|
)
|
|
3129
3620
|
] }) : null,
|
|
3130
|
-
optionContainerLines.bottom.value > 0 ? /* @__PURE__ */
|
|
3131
|
-
/* @__PURE__ */
|
|
3621
|
+
optionContainerLines.bottom.value > 0 ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
3622
|
+
/* @__PURE__ */ jsx8(
|
|
3132
3623
|
"div",
|
|
3133
3624
|
{
|
|
3134
3625
|
className: "msr:absolute msr:w-px msr:bg-[#2563eb]",
|
|
@@ -3139,7 +3630,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3139
3630
|
}
|
|
3140
3631
|
}
|
|
3141
3632
|
),
|
|
3142
|
-
/* @__PURE__ */
|
|
3633
|
+
/* @__PURE__ */ jsx8(
|
|
3143
3634
|
MeasureTag,
|
|
3144
3635
|
{
|
|
3145
3636
|
className: "msr:-translate-y-1/2 msr:bg-ink-900/90",
|
|
@@ -3151,8 +3642,8 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3151
3642
|
}
|
|
3152
3643
|
)
|
|
3153
3644
|
] }) : null,
|
|
3154
|
-
optionContainerLines.left.value > 0 ? /* @__PURE__ */
|
|
3155
|
-
/* @__PURE__ */
|
|
3645
|
+
optionContainerLines.left.value > 0 ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
3646
|
+
/* @__PURE__ */ jsx8(
|
|
3156
3647
|
"div",
|
|
3157
3648
|
{
|
|
3158
3649
|
className: "msr:absolute msr:h-px msr:bg-[#2563eb]",
|
|
@@ -3163,7 +3654,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3163
3654
|
}
|
|
3164
3655
|
}
|
|
3165
3656
|
),
|
|
3166
|
-
/* @__PURE__ */
|
|
3657
|
+
/* @__PURE__ */ jsx8(
|
|
3167
3658
|
MeasureTag,
|
|
3168
3659
|
{
|
|
3169
3660
|
className: "msr:-translate-x-1/2 msr:bg-ink-900/90",
|
|
@@ -3175,8 +3666,8 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3175
3666
|
}
|
|
3176
3667
|
)
|
|
3177
3668
|
] }) : null,
|
|
3178
|
-
optionContainerLines.right.value > 0 ? /* @__PURE__ */
|
|
3179
|
-
/* @__PURE__ */
|
|
3669
|
+
optionContainerLines.right.value > 0 ? /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
3670
|
+
/* @__PURE__ */ jsx8(
|
|
3180
3671
|
"div",
|
|
3181
3672
|
{
|
|
3182
3673
|
className: "msr:absolute msr:h-px msr:bg-[#2563eb]",
|
|
@@ -3187,7 +3678,7 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3187
3678
|
}
|
|
3188
3679
|
}
|
|
3189
3680
|
),
|
|
3190
|
-
/* @__PURE__ */
|
|
3681
|
+
/* @__PURE__ */ jsx8(
|
|
3191
3682
|
MeasureTag,
|
|
3192
3683
|
{
|
|
3193
3684
|
className: "msr:-translate-x-1/2 msr:bg-ink-900/90",
|
|
@@ -3205,25 +3696,28 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3205
3696
|
const isHovered = hoverGuide?.id === guide.id;
|
|
3206
3697
|
const strokeWidth = isSelected || isHovered ? 2 : 1;
|
|
3207
3698
|
const strokeColor = isSelected ? guideColorActive : isHovered ? guideColorHover : guideColorDefault;
|
|
3208
|
-
return /* @__PURE__ */
|
|
3699
|
+
return /* @__PURE__ */ jsx8(
|
|
3209
3700
|
"div",
|
|
3210
3701
|
{
|
|
3211
3702
|
className: "msr:absolute",
|
|
3703
|
+
"data-mesurer-guide": "true",
|
|
3212
3704
|
style: guide.orientation === "vertical" ? {
|
|
3213
3705
|
left: guide.position - GUIDE_HITBOX_SIZE / 2,
|
|
3214
3706
|
top: 0,
|
|
3215
3707
|
width: GUIDE_HITBOX_SIZE,
|
|
3216
|
-
height: "100%"
|
|
3708
|
+
height: "100%",
|
|
3709
|
+
pointerEvents: guidePointerEvents ? "auto" : "none"
|
|
3217
3710
|
} : {
|
|
3218
3711
|
top: guide.position - GUIDE_HITBOX_SIZE / 2,
|
|
3219
3712
|
left: 0,
|
|
3220
3713
|
height: GUIDE_HITBOX_SIZE,
|
|
3221
|
-
width: "100%"
|
|
3714
|
+
width: "100%",
|
|
3715
|
+
pointerEvents: guidePointerEvents ? "auto" : "none"
|
|
3222
3716
|
},
|
|
3223
3717
|
onPointerDown: (event) => onGuidePointerDown(guide, event),
|
|
3224
3718
|
onPointerUp: (event) => onGuidePointerUp(guide, event),
|
|
3225
3719
|
onPointerCancel: (event) => onGuidePointerCancel(guide, event),
|
|
3226
|
-
children: /* @__PURE__ */
|
|
3720
|
+
children: /* @__PURE__ */ jsx8(
|
|
3227
3721
|
"div",
|
|
3228
3722
|
{
|
|
3229
3723
|
className: "msr:absolute",
|
|
@@ -3251,60 +3745,1005 @@ var MeasurerOverlay = memo5(function MeasurerOverlay2({
|
|
|
3251
3745
|
);
|
|
3252
3746
|
});
|
|
3253
3747
|
|
|
3254
|
-
//
|
|
3255
|
-
|
|
3256
|
-
var
|
|
3748
|
+
// runtime/text-inspector-dom.ts
|
|
3749
|
+
var INK_50 = "#f8fafc";
|
|
3750
|
+
var INK_200 = "#e2e8f0";
|
|
3751
|
+
var INK_500 = "#64748b";
|
|
3752
|
+
var INK_900 = "#0f172a";
|
|
3753
|
+
var makeEdge = (document2, side, color) => {
|
|
3754
|
+
const edge = document2.createElement("div");
|
|
3755
|
+
Object.assign(edge.style, {
|
|
3756
|
+
position: "absolute",
|
|
3757
|
+
backgroundColor: color,
|
|
3758
|
+
...side === "top" || side === "bottom" ? { left: "0", [side]: "0", width: "100%", height: "1px" } : { top: "0", [side]: "0", width: "1px", height: "100%" }
|
|
3759
|
+
});
|
|
3760
|
+
return edge;
|
|
3257
3761
|
};
|
|
3258
|
-
var
|
|
3259
|
-
|
|
3260
|
-
(
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
});
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
}
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3762
|
+
var makeBox = (document2, fill, outline) => {
|
|
3763
|
+
const box = document2.createElement("div");
|
|
3764
|
+
Object.assign(box.style, {
|
|
3765
|
+
position: "fixed",
|
|
3766
|
+
zIndex: "0",
|
|
3767
|
+
pointerEvents: "none",
|
|
3768
|
+
backgroundColor: fill,
|
|
3769
|
+
boxSizing: "border-box"
|
|
3770
|
+
});
|
|
3771
|
+
box.className = "mesurer-ti-box";
|
|
3772
|
+
box.dataset.state = "hidden";
|
|
3773
|
+
for (const side of ["top", "right", "bottom", "left"]) {
|
|
3774
|
+
box.appendChild(makeEdge(document2, side, outline));
|
|
3775
|
+
}
|
|
3776
|
+
return box;
|
|
3777
|
+
};
|
|
3778
|
+
var positionBox = (box, rect) => {
|
|
3779
|
+
Object.assign(box.style, {
|
|
3780
|
+
left: `${rect.left}px`,
|
|
3781
|
+
top: `${rect.top}px`,
|
|
3782
|
+
width: `${rect.width}px`,
|
|
3783
|
+
height: `${rect.height}px`
|
|
3784
|
+
});
|
|
3785
|
+
};
|
|
3786
|
+
var makeCard = (document2, pinned) => {
|
|
3787
|
+
const card = document2.createElement("div");
|
|
3788
|
+
Object.assign(card.style, {
|
|
3789
|
+
position: "fixed",
|
|
3790
|
+
zIndex: "1",
|
|
3791
|
+
pointerEvents: pinned ? "auto" : "none",
|
|
3792
|
+
background: "#ffffff",
|
|
3793
|
+
color: INK_900,
|
|
3794
|
+
borderRadius: "13px",
|
|
3795
|
+
padding: "10px 12px",
|
|
3796
|
+
fontSize: "11px",
|
|
3797
|
+
lineHeight: "1.5",
|
|
3798
|
+
fontFamily: "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif",
|
|
3799
|
+
fontVariantNumeric: "tabular-nums",
|
|
3800
|
+
userSelect: "none",
|
|
3801
|
+
whiteSpace: "nowrap",
|
|
3802
|
+
width: "320px",
|
|
3803
|
+
minWidth: "320px",
|
|
3804
|
+
maxWidth: "320px",
|
|
3805
|
+
boxSizing: "border-box",
|
|
3806
|
+
boxShadow: "0px 0px 0.5px rgba(0, 0, 0, 0.18), 0px 3px 8px rgba(0, 0, 0, 0.1), 0px 1px 3px rgba(0, 0, 0, 0.1)"
|
|
3807
|
+
});
|
|
3808
|
+
card.className = pinned ? "mesurer-ti-card mesurer-ti-card--pinned" : "mesurer-ti-card";
|
|
3809
|
+
card.dataset.state = "hidden";
|
|
3810
|
+
return card;
|
|
3811
|
+
};
|
|
3812
|
+
var populateCard = (document2, card, info, pinned) => {
|
|
3813
|
+
card.replaceChildren();
|
|
3814
|
+
const header = document2.createElement("div");
|
|
3815
|
+
Object.assign(header.style, {
|
|
3816
|
+
display: "flex",
|
|
3817
|
+
alignItems: "center",
|
|
3818
|
+
gap: "8px",
|
|
3819
|
+
marginBottom: "8px",
|
|
3820
|
+
paddingBottom: "6px"
|
|
3821
|
+
});
|
|
3822
|
+
const tag = document2.createElement("span");
|
|
3823
|
+
Object.assign(tag.style, {
|
|
3824
|
+
color: INK_50,
|
|
3825
|
+
background: INK_900,
|
|
3826
|
+
borderRadius: "4px",
|
|
3827
|
+
padding: "1px 5px",
|
|
3828
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
3829
|
+
fontSize: "10px",
|
|
3830
|
+
fontWeight: "500"
|
|
3831
|
+
});
|
|
3832
|
+
tag.textContent = info.tagName;
|
|
3833
|
+
header.appendChild(tag);
|
|
3834
|
+
if (info.textSnippet) {
|
|
3835
|
+
const snippet = document2.createElement("span");
|
|
3836
|
+
Object.assign(snippet.style, {
|
|
3837
|
+
color: INK_500,
|
|
3838
|
+
overflow: "hidden",
|
|
3839
|
+
textOverflow: "ellipsis",
|
|
3840
|
+
whiteSpace: "nowrap",
|
|
3841
|
+
flex: "1",
|
|
3842
|
+
minWidth: "0",
|
|
3843
|
+
fontSize: "10px"
|
|
3844
|
+
});
|
|
3845
|
+
snippet.textContent = info.textSnippet;
|
|
3846
|
+
header.appendChild(snippet);
|
|
3847
|
+
}
|
|
3848
|
+
if (pinned) {
|
|
3849
|
+
const close = document2.createElement("button");
|
|
3850
|
+
close.type = "button";
|
|
3851
|
+
close.className = "mesurer-ti-close";
|
|
3852
|
+
close.setAttribute("aria-label", "Close");
|
|
3853
|
+
close.textContent = "\xD7";
|
|
3854
|
+
Object.assign(close.style, {
|
|
3855
|
+
all: "unset",
|
|
3856
|
+
marginLeft: info.textSnippet ? "0" : "auto",
|
|
3857
|
+
flex: "0 0 auto",
|
|
3858
|
+
width: "16px",
|
|
3859
|
+
height: "16px",
|
|
3860
|
+
lineHeight: "14px",
|
|
3861
|
+
textAlign: "center",
|
|
3862
|
+
borderRadius: "4px",
|
|
3863
|
+
color: INK_500,
|
|
3864
|
+
fontSize: "14px"
|
|
3865
|
+
});
|
|
3866
|
+
header.appendChild(close);
|
|
3867
|
+
}
|
|
3868
|
+
card.appendChild(header);
|
|
3869
|
+
const grid = document2.createElement("div");
|
|
3870
|
+
Object.assign(grid.style, {
|
|
3871
|
+
display: "grid",
|
|
3872
|
+
gridTemplateColumns: "auto 1fr",
|
|
3873
|
+
columnGap: "12px",
|
|
3874
|
+
rowGap: "3px",
|
|
3875
|
+
alignItems: "baseline"
|
|
3876
|
+
});
|
|
3877
|
+
for (const row of info.rows) {
|
|
3878
|
+
const label = document2.createElement("span");
|
|
3879
|
+
label.style.color = INK_500;
|
|
3880
|
+
label.style.fontSize = "11px";
|
|
3881
|
+
label.textContent = row.label;
|
|
3882
|
+
const value = document2.createElement("span");
|
|
3883
|
+
Object.assign(value.style, {
|
|
3884
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
3885
|
+
fontSize: "11px",
|
|
3886
|
+
color: INK_900,
|
|
3887
|
+
overflow: "hidden",
|
|
3888
|
+
textOverflow: "ellipsis",
|
|
3889
|
+
whiteSpace: "nowrap"
|
|
3890
|
+
});
|
|
3891
|
+
if (!row.varName) {
|
|
3892
|
+
value.textContent = row.value;
|
|
3893
|
+
} else {
|
|
3894
|
+
const variable = document2.createElement("span");
|
|
3895
|
+
variable.textContent = row.value;
|
|
3896
|
+
const separator = document2.createElement("span");
|
|
3897
|
+
separator.style.color = INK_200;
|
|
3898
|
+
separator.style.margin = "0 6px";
|
|
3899
|
+
separator.textContent = "\xB7";
|
|
3900
|
+
const name = document2.createElement("span");
|
|
3901
|
+
name.style.color = "#0369a1";
|
|
3902
|
+
name.textContent = row.varName;
|
|
3903
|
+
value.append(variable, separator, name);
|
|
3904
|
+
}
|
|
3905
|
+
grid.append(label, value);
|
|
3906
|
+
}
|
|
3907
|
+
card.appendChild(grid);
|
|
3908
|
+
};
|
|
3909
|
+
var positionCard = (window2, card, rect, offsetX = 0, offsetY = 0) => {
|
|
3910
|
+
const center = rect.left + rect.width / 2 + offsetX;
|
|
3911
|
+
card.style.left = `${center}px`;
|
|
3912
|
+
const size = card.getBoundingClientRect();
|
|
3913
|
+
let top = rect.bottom + 4 + offsetY;
|
|
3914
|
+
if (top + size.height > window2.innerHeight - 8) {
|
|
3915
|
+
top = rect.top - size.height - 4 + offsetY;
|
|
3916
|
+
}
|
|
3917
|
+
card.style.top = `${Math.max(8, top)}px`;
|
|
3918
|
+
const half = size.width / 2;
|
|
3919
|
+
card.style.left = `${Math.min(
|
|
3920
|
+
Math.max(center, 8 + half),
|
|
3921
|
+
window2.innerWidth - 8 - half
|
|
3922
|
+
)}px`;
|
|
3923
|
+
};
|
|
3924
|
+
|
|
3925
|
+
// runtime/text-inspector-typography.ts
|
|
3926
|
+
var FONT_WEIGHT_KEYWORD = {
|
|
3927
|
+
"100": "thin",
|
|
3928
|
+
"200": "extralight",
|
|
3929
|
+
"300": "light",
|
|
3930
|
+
"400": "normal",
|
|
3931
|
+
"500": "medium",
|
|
3932
|
+
"600": "semibold",
|
|
3933
|
+
"700": "bold",
|
|
3934
|
+
"800": "extrabold",
|
|
3935
|
+
"900": "black"
|
|
3936
|
+
};
|
|
3937
|
+
var TYPO_PROPS = [
|
|
3938
|
+
"font-family",
|
|
3939
|
+
"font-size",
|
|
3940
|
+
"font-weight",
|
|
3941
|
+
"line-height",
|
|
3942
|
+
"letter-spacing"
|
|
3943
|
+
];
|
|
3944
|
+
var TYPO_LABELS = {
|
|
3945
|
+
Family: "font-family",
|
|
3946
|
+
Size: "font-size",
|
|
3947
|
+
Weight: "font-weight",
|
|
3948
|
+
Line: "line-height",
|
|
3949
|
+
Tracking: "letter-spacing"
|
|
3950
|
+
};
|
|
3951
|
+
var formatPx = (raw) => {
|
|
3952
|
+
if (!raw || raw === "normal") return raw || "normal";
|
|
3953
|
+
const match = /^(-?[\d.]+)px$/.exec(raw);
|
|
3954
|
+
if (!match) return raw;
|
|
3955
|
+
return `${Math.round(Number(match[1]) * 10) / 10}px`;
|
|
3956
|
+
};
|
|
3957
|
+
var firstFontFamily = (families) => (families.split(",")[0] ?? "").trim().replace(/^['"]|['"]$/g, "");
|
|
3958
|
+
var weightWithKeyword = (weight) => {
|
|
3959
|
+
const keyword = FONT_WEIGHT_KEYWORD[weight];
|
|
3960
|
+
return keyword ? `${weight} / ${keyword}` : weight;
|
|
3961
|
+
};
|
|
3962
|
+
var extractVarName = (value) => {
|
|
3963
|
+
if (!value) return null;
|
|
3964
|
+
return /var\(\s*(--[a-zA-Z0-9_-]+)/.exec(value)?.[1] ?? null;
|
|
3965
|
+
};
|
|
3966
|
+
var selectorSpecificity = (selector) => {
|
|
3967
|
+
const ids = (selector.match(/#[\w-]+/g) ?? []).length;
|
|
3968
|
+
const classes = (selector.match(/\.[\w-]+|\[[^\]]+\]|:[\w-]+/g) ?? []).length;
|
|
3969
|
+
const elements = (selector.match(/(?:^|[ >+~])([a-zA-Z][\w-]*)/g) ?? []).length;
|
|
3970
|
+
return ids * 1e4 + classes * 100 + elements;
|
|
3971
|
+
};
|
|
3972
|
+
var wins = (next, previous) => {
|
|
3973
|
+
if (!previous) return true;
|
|
3974
|
+
if (next.important !== previous.important) return next.important;
|
|
3975
|
+
if (next.specificity !== previous.specificity) {
|
|
3976
|
+
return next.specificity > previous.specificity;
|
|
3977
|
+
}
|
|
3978
|
+
return next.order > previous.order;
|
|
3979
|
+
};
|
|
3980
|
+
var TypographyInspector = class {
|
|
3981
|
+
constructor(document2, window2) {
|
|
3982
|
+
this.document = document2;
|
|
3983
|
+
this.window = window2;
|
|
3984
|
+
}
|
|
3985
|
+
collectRules(rules, output, mediaOk, order) {
|
|
3986
|
+
for (let i = 0; i < rules.length; i++) {
|
|
3987
|
+
const rule = rules[i];
|
|
3988
|
+
const currentOrder = order.value++;
|
|
3989
|
+
if (rule.type === 4) {
|
|
3990
|
+
const mediaRule = rule;
|
|
3991
|
+
let matches = mediaOk;
|
|
3992
|
+
try {
|
|
3993
|
+
matches = mediaOk && this.window.matchMedia(mediaRule.media.mediaText).matches;
|
|
3994
|
+
} catch {
|
|
3995
|
+
matches = false;
|
|
3996
|
+
}
|
|
3997
|
+
this.collectRules(mediaRule.cssRules, output, matches, order);
|
|
3998
|
+
} else if (rule.type === 12) {
|
|
3999
|
+
this.collectRules(rule.cssRules, output, mediaOk, order);
|
|
4000
|
+
} else if (rule.type === 1) {
|
|
4001
|
+
output.push({
|
|
4002
|
+
rule,
|
|
4003
|
+
mediaOk,
|
|
4004
|
+
order: currentOrder
|
|
4005
|
+
});
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
getRules() {
|
|
4010
|
+
const rules = [];
|
|
4011
|
+
const order = { value: 0 };
|
|
4012
|
+
for (const sheet of Array.from(this.document.styleSheets)) {
|
|
4013
|
+
try {
|
|
4014
|
+
this.collectRules(sheet.cssRules, rules, true, order);
|
|
4015
|
+
} catch {
|
|
4016
|
+
continue;
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
return rules;
|
|
4020
|
+
}
|
|
4021
|
+
findVarReferences(el) {
|
|
4022
|
+
const result = Object.fromEntries(
|
|
4023
|
+
TYPO_PROPS.map((prop) => [prop, null])
|
|
4024
|
+
);
|
|
4025
|
+
const rules = this.getRules();
|
|
4026
|
+
for (const prop of TYPO_PROPS) {
|
|
4027
|
+
let node = el;
|
|
4028
|
+
while (node && result[prop] === null) {
|
|
4029
|
+
let winner;
|
|
4030
|
+
const inlineValue = node.style.getPropertyValue(prop);
|
|
4031
|
+
const inlineName = extractVarName(inlineValue);
|
|
4032
|
+
if (inlineName) {
|
|
4033
|
+
winner = {
|
|
4034
|
+
name: inlineName,
|
|
4035
|
+
specificity: Number.MAX_SAFE_INTEGER,
|
|
4036
|
+
order: Number.MAX_SAFE_INTEGER,
|
|
4037
|
+
important: node.style.getPropertyPriority(prop) === "important"
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
for (const { rule, mediaOk, order } of rules) {
|
|
4041
|
+
if (!mediaOk) continue;
|
|
4042
|
+
let matches = false;
|
|
4043
|
+
try {
|
|
4044
|
+
matches = node.matches(rule.selectorText);
|
|
4045
|
+
} catch {
|
|
4046
|
+
continue;
|
|
4047
|
+
}
|
|
4048
|
+
if (!matches) continue;
|
|
4049
|
+
const name = extractVarName(rule.style.getPropertyValue(prop));
|
|
4050
|
+
if (!name) continue;
|
|
4051
|
+
const candidate = {
|
|
4052
|
+
name,
|
|
4053
|
+
specificity: selectorSpecificity(rule.selectorText),
|
|
4054
|
+
order,
|
|
4055
|
+
important: rule.style.getPropertyPriority(prop) === "important"
|
|
4056
|
+
};
|
|
4057
|
+
if (wins(candidate, winner)) winner = candidate;
|
|
4058
|
+
}
|
|
4059
|
+
if (winner) result[prop] = winner.name;
|
|
4060
|
+
node = node.parentElement;
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
4063
|
+
return result;
|
|
4064
|
+
}
|
|
4065
|
+
getFast(el) {
|
|
4066
|
+
const styles = this.window.getComputedStyle(el);
|
|
4067
|
+
const rows = [
|
|
4068
|
+
{ label: "Family", value: firstFontFamily(styles.fontFamily), varName: null },
|
|
4069
|
+
{ label: "Size", value: formatPx(styles.fontSize), varName: null },
|
|
4070
|
+
{
|
|
4071
|
+
label: "Weight",
|
|
4072
|
+
value: weightWithKeyword(styles.fontWeight),
|
|
4073
|
+
varName: null
|
|
4074
|
+
},
|
|
4075
|
+
{
|
|
4076
|
+
label: "Line",
|
|
4077
|
+
value: styles.lineHeight === "normal" ? "normal" : formatPx(styles.lineHeight),
|
|
4078
|
+
varName: null
|
|
4079
|
+
},
|
|
4080
|
+
{
|
|
4081
|
+
label: "Tracking",
|
|
4082
|
+
value: styles.letterSpacing === "normal" ? "normal" : formatPx(styles.letterSpacing),
|
|
4083
|
+
varName: null
|
|
4084
|
+
}
|
|
4085
|
+
];
|
|
4086
|
+
const directText = Array.from(el.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).map((node) => node.nodeValue?.trim() ?? "").filter(Boolean).join(" ").replace(/\s+/g, " ");
|
|
4087
|
+
return {
|
|
4088
|
+
rows,
|
|
4089
|
+
tagName: el.tagName.toLowerCase(),
|
|
4090
|
+
textSnippet: directText.length > 40 ? `${directText.slice(0, 40)}\u2026` : directText
|
|
4091
|
+
};
|
|
4092
|
+
}
|
|
4093
|
+
getFull(el, base = this.getFast(el)) {
|
|
4094
|
+
const vars = this.findVarReferences(el);
|
|
4095
|
+
return {
|
|
4096
|
+
...base,
|
|
4097
|
+
rows: base.rows.map((row) => ({
|
|
4098
|
+
...row,
|
|
4099
|
+
varName: vars[TYPO_LABELS[row.label]]
|
|
4100
|
+
}))
|
|
4101
|
+
};
|
|
4102
|
+
}
|
|
4103
|
+
};
|
|
4104
|
+
|
|
4105
|
+
// runtime/text-inspector.ts
|
|
4106
|
+
var DEFAULT_EXTENSION_HOST_ID = "mesurer-extension-host";
|
|
4107
|
+
var DEFAULT_OVERLAY_ID = "mesurer-text-inspector-overlay";
|
|
4108
|
+
var DEFAULT_STYLE_ID = "mesurer-text-inspector-styles";
|
|
4109
|
+
var DEFAULT_BODY_MODE_CLASS = "mesurer-text-inspect-mode";
|
|
4110
|
+
var inspectorInstanceCount = 0;
|
|
4111
|
+
var FILL_HOVER = "color-mix(in oklch, oklch(0.62 0.18 255) 8%, transparent)";
|
|
4112
|
+
var OUTLINE_HOVER = "color-mix(in oklch, oklch(0.62 0.18 255) 80%, transparent)";
|
|
4113
|
+
var FILL_PINNED = "color-mix(in oklch, oklch(0.62 0.18 255) 4%, transparent)";
|
|
4114
|
+
var OUTLINE_PINNED = "color-mix(in oklch, oklch(0.62 0.18 255) 35%, transparent)";
|
|
4115
|
+
var DEFAULT_SKIP_TAGS = [
|
|
4116
|
+
"HTML",
|
|
4117
|
+
"BODY",
|
|
4118
|
+
"SCRIPT",
|
|
4119
|
+
"STYLE",
|
|
4120
|
+
"META",
|
|
4121
|
+
"LINK",
|
|
4122
|
+
"NOSCRIPT",
|
|
4123
|
+
"IMG",
|
|
4124
|
+
"VIDEO",
|
|
4125
|
+
"AUDIO",
|
|
4126
|
+
"IFRAME"
|
|
4127
|
+
];
|
|
4128
|
+
var createInspectorStyles = (extensionHostId, overlayId, bodyModeClass) => `
|
|
4129
|
+
.${bodyModeClass},
|
|
4130
|
+
.${bodyModeClass} * {
|
|
4131
|
+
cursor: help !important;
|
|
4132
|
+
}
|
|
4133
|
+
.${bodyModeClass} #${extensionHostId},
|
|
4134
|
+
.${bodyModeClass} #${extensionHostId} * {
|
|
4135
|
+
cursor: auto !important;
|
|
4136
|
+
}
|
|
4137
|
+
#${overlayId} .mesurer-ti-card--pinned {
|
|
4138
|
+
cursor: grab;
|
|
4139
|
+
}
|
|
4140
|
+
#${overlayId} .mesurer-ti-card--pinned:active {
|
|
4141
|
+
cursor: grabbing;
|
|
4142
|
+
}
|
|
4143
|
+
#${overlayId} .mesurer-ti-close {
|
|
4144
|
+
cursor: pointer;
|
|
4145
|
+
}
|
|
4146
|
+
#${overlayId} .mesurer-ti-close:hover {
|
|
4147
|
+
background: rgba(15, 23, 42, 0.06);
|
|
4148
|
+
color: #0f172a;
|
|
4149
|
+
}
|
|
4150
|
+
#${overlayId} .mesurer-ti-box,
|
|
4151
|
+
#${overlayId} .mesurer-ti-card {
|
|
4152
|
+
opacity: 1;
|
|
4153
|
+
}
|
|
4154
|
+
#${overlayId} .mesurer-ti-box[data-state="hidden"],
|
|
4155
|
+
#${overlayId} .mesurer-ti-card[data-state="hidden"] {
|
|
4156
|
+
opacity: 0;
|
|
4157
|
+
}
|
|
4158
|
+
#${overlayId} .mesurer-ti-card {
|
|
4159
|
+
transform: translateX(-50%);
|
|
4160
|
+
}
|
|
4161
|
+
`;
|
|
4162
|
+
var createIdleScheduler = (window2) => {
|
|
4163
|
+
const browser = window2;
|
|
4164
|
+
if (browser.requestIdleCallback) {
|
|
4165
|
+
return {
|
|
4166
|
+
request: (callback) => browser.requestIdleCallback(
|
|
4167
|
+
() => callback(),
|
|
4168
|
+
{ timeout: 250 }
|
|
4169
|
+
),
|
|
4170
|
+
cancel: (id) => browser.cancelIdleCallback?.(id)
|
|
4171
|
+
};
|
|
4172
|
+
}
|
|
4173
|
+
return {
|
|
4174
|
+
request: (callback) => window2.setTimeout(callback, 32),
|
|
4175
|
+
cancel: (id) => window2.clearTimeout(id)
|
|
4176
|
+
};
|
|
4177
|
+
};
|
|
4178
|
+
var createTextInspector = (options = {}, legacy = false) => {
|
|
4179
|
+
const portalDocument = options.portalTarget?.ownerDocument;
|
|
4180
|
+
const availableDocument = portalDocument ?? (typeof globalThis.document === "undefined" ? null : globalThis.document);
|
|
4181
|
+
const availableWindow = availableDocument?.defaultView ?? (typeof globalThis.window === "undefined" ? null : globalThis.window);
|
|
4182
|
+
const document2 = availableDocument;
|
|
4183
|
+
const window2 = availableWindow;
|
|
4184
|
+
const realm = availableWindow;
|
|
4185
|
+
const HTMLElementConstructor = realm?.HTMLElement ?? globalThis.HTMLElement;
|
|
4186
|
+
const SVGElementConstructor = realm?.SVGElement ?? globalThis.SVGElement;
|
|
4187
|
+
const extensionHostId = DEFAULT_EXTENSION_HOST_ID;
|
|
4188
|
+
const instanceId = (options.id ?? (legacy ? DEFAULT_OVERLAY_ID : `mesurer-text-inspector-${++inspectorInstanceCount}`)).replace(
|
|
4189
|
+
/[^a-zA-Z0-9_-]/g,
|
|
4190
|
+
"-"
|
|
4191
|
+
);
|
|
4192
|
+
const overlayId = legacy ? DEFAULT_OVERLAY_ID : `${instanceId}-overlay`;
|
|
4193
|
+
const styleId = legacy ? DEFAULT_STYLE_ID : `${instanceId}-styles`;
|
|
4194
|
+
const bodyModeClass = legacy ? DEFAULT_BODY_MODE_CLASS : `${instanceId}-mode`;
|
|
4195
|
+
const skipTags = new Set(
|
|
4196
|
+
(options.ignoredTags ?? DEFAULT_SKIP_TAGS).map((tag) => tag.toUpperCase())
|
|
4197
|
+
);
|
|
4198
|
+
const maxPinned = Number.isFinite(options.maxPinned) ? Math.max(1, Math.floor(options.maxPinned)) : Infinity;
|
|
4199
|
+
const inspectorStyles = createInspectorStyles(
|
|
4200
|
+
extensionHostId,
|
|
4201
|
+
overlayId,
|
|
4202
|
+
bodyModeClass
|
|
4203
|
+
);
|
|
4204
|
+
const EXTENSION_HOST_ID = extensionHostId;
|
|
4205
|
+
const OVERLAY_ID = overlayId;
|
|
4206
|
+
const STYLE_ID = styleId;
|
|
4207
|
+
const BODY_MODE_CLASS = bodyModeClass;
|
|
4208
|
+
const SKIP_TAGS = skipTags;
|
|
4209
|
+
const INSPECTOR_STYLES = inspectorStyles;
|
|
4210
|
+
const portalIsShadowRoot = options.portalTarget?.nodeType === 11;
|
|
4211
|
+
const typography = new TypographyInspector(document2, window2);
|
|
4212
|
+
const pinned = [];
|
|
4213
|
+
const history = [];
|
|
4214
|
+
const future = [];
|
|
4215
|
+
let enabled = false;
|
|
4216
|
+
let overlay = null;
|
|
4217
|
+
let hoverBox = null;
|
|
4218
|
+
let hoverCard = null;
|
|
4219
|
+
let hoveredEl = null;
|
|
4220
|
+
let pointerX = 0;
|
|
4221
|
+
let pointerY = 0;
|
|
4222
|
+
let frameScheduled = false;
|
|
4223
|
+
let pendingElement = null;
|
|
4224
|
+
let pendingIdleId = -1;
|
|
4225
|
+
let idleScheduler = null;
|
|
4226
|
+
const getIdleScheduler = () => {
|
|
4227
|
+
idleScheduler ?? (idleScheduler = createIdleScheduler(window2));
|
|
4228
|
+
return idleScheduler;
|
|
4229
|
+
};
|
|
4230
|
+
const hasDirectText = (el) => Array.from(el.childNodes).some(
|
|
4231
|
+
(node) => node.nodeType === Node.TEXT_NODE && !!node.nodeValue?.trim()
|
|
4232
|
+
);
|
|
4233
|
+
const isInspectable = (el) => !!el && el instanceof HTMLElementConstructor && !SKIP_TAGS.has(el.tagName) && !(el instanceof SVGElementConstructor) && hasDirectText(el);
|
|
4234
|
+
const isOverlayNode = (node) => {
|
|
4235
|
+
for (let current = node; current; current = current.parentNode) {
|
|
4236
|
+
if (current instanceof HTMLElementConstructor) {
|
|
4237
|
+
const element = current;
|
|
4238
|
+
if (element.id === OVERLAY_ID || element.id === EXTENSION_HOST_ID) {
|
|
4239
|
+
return true;
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
}
|
|
4243
|
+
return false;
|
|
4244
|
+
};
|
|
4245
|
+
const pickElementAt = (x, y) => {
|
|
4246
|
+
return document2.elementsFromPoint(x, y).find(
|
|
4247
|
+
(el) => !isOverlayNode(el) && isInspectable(el)
|
|
4248
|
+
) ?? null;
|
|
4249
|
+
};
|
|
4250
|
+
const pointerOverToolbar = (x, y) => {
|
|
4251
|
+
const shadow = document2.getElementById(EXTENSION_HOST_ID)?.shadowRoot;
|
|
4252
|
+
const element = shadow?.elementFromPoint(x, y);
|
|
4253
|
+
if (!element) return false;
|
|
4254
|
+
for (let node = element; node; node = node.parentElement) {
|
|
4255
|
+
if (node.classList.contains("mesurer-toolbar-surface")) return true;
|
|
4256
|
+
}
|
|
4257
|
+
return false;
|
|
4258
|
+
};
|
|
4259
|
+
const ensureStyles = () => {
|
|
4260
|
+
const append = (root) => {
|
|
4261
|
+
if (root.querySelector(`#${STYLE_ID}`)) return;
|
|
4262
|
+
const style = document2.createElement("style");
|
|
4263
|
+
style.id = STYLE_ID;
|
|
4264
|
+
style.textContent = INSPECTOR_STYLES;
|
|
4265
|
+
root.nodeType === 9 ? root.head.appendChild(style) : root.appendChild(style);
|
|
4266
|
+
};
|
|
4267
|
+
append(document2);
|
|
4268
|
+
if (portalIsShadowRoot) append(options.portalTarget);
|
|
4269
|
+
};
|
|
4270
|
+
const ensureOverlay = () => {
|
|
4271
|
+
if (overlay?.isConnected) return overlay;
|
|
4272
|
+
overlay = document2.createElement("div");
|
|
4273
|
+
overlay.id = OVERLAY_ID;
|
|
4274
|
+
Object.assign(overlay.style, {
|
|
4275
|
+
position: "fixed",
|
|
4276
|
+
inset: "0",
|
|
4277
|
+
pointerEvents: "none",
|
|
4278
|
+
zIndex: "2147483646"
|
|
4279
|
+
});
|
|
4280
|
+
(options.portalTarget ?? document2.body).appendChild(overlay);
|
|
4281
|
+
return overlay;
|
|
4282
|
+
};
|
|
4283
|
+
const setState = (element, visible) => {
|
|
4284
|
+
element.dataset.state = visible ? "visible" : "hidden";
|
|
4285
|
+
};
|
|
4286
|
+
const ensureHover = () => {
|
|
4287
|
+
const root = ensureOverlay();
|
|
4288
|
+
hoverBox ?? (hoverBox = makeBox(document2, FILL_HOVER, OUTLINE_HOVER));
|
|
4289
|
+
hoverCard ?? (hoverCard = makeCard(document2, false));
|
|
4290
|
+
if (!hoverBox.parentNode) root.appendChild(hoverBox);
|
|
4291
|
+
if (!hoverCard.parentNode) root.appendChild(hoverCard);
|
|
4292
|
+
};
|
|
4293
|
+
const scheduleEnrichment = (element, fast) => {
|
|
4294
|
+
if (pendingElement === element) return;
|
|
4295
|
+
if (pendingIdleId !== -1) getIdleScheduler().cancel(pendingIdleId);
|
|
4296
|
+
pendingElement = element;
|
|
4297
|
+
pendingIdleId = getIdleScheduler().request(() => {
|
|
4298
|
+
pendingIdleId = -1;
|
|
4299
|
+
pendingElement = null;
|
|
4300
|
+
if (!enabled) return;
|
|
4301
|
+
const full = typography.getFull(element, fast);
|
|
4302
|
+
if (hoveredEl !== element || !hoverCard) return;
|
|
4303
|
+
populateCard(document2, hoverCard, full, false);
|
|
4304
|
+
positionCard(window2, hoverCard, element.getBoundingClientRect());
|
|
4305
|
+
options.onInspect?.(element, full);
|
|
4306
|
+
});
|
|
4307
|
+
};
|
|
4308
|
+
const inspect = (element) => {
|
|
4309
|
+
if (!enabled || !isInspectable(element)) return false;
|
|
4310
|
+
ensureHover();
|
|
4311
|
+
const rect = element.getBoundingClientRect();
|
|
4312
|
+
hoveredEl = element;
|
|
4313
|
+
const fast = typography.getFast(element);
|
|
4314
|
+
populateCard(document2, hoverCard, fast, false);
|
|
4315
|
+
scheduleEnrichment(element, fast);
|
|
4316
|
+
positionBox(hoverBox, rect);
|
|
4317
|
+
positionCard(window2, hoverCard, rect);
|
|
4318
|
+
setState(hoverBox, true);
|
|
4319
|
+
setState(hoverCard, true);
|
|
4320
|
+
return true;
|
|
4321
|
+
};
|
|
4322
|
+
const updateHover = () => {
|
|
4323
|
+
if (!enabled || pointerOverToolbar(pointerX, pointerY)) {
|
|
4324
|
+
hideHover();
|
|
4325
|
+
return;
|
|
4326
|
+
}
|
|
4327
|
+
const element = pickElementAt(pointerX, pointerY);
|
|
4328
|
+
if (!element) {
|
|
4329
|
+
hideHover();
|
|
4330
|
+
return;
|
|
4331
|
+
}
|
|
4332
|
+
if (element !== hoveredEl) inspect(element);
|
|
4333
|
+
else {
|
|
4334
|
+
positionBox(hoverBox, element.getBoundingClientRect());
|
|
4335
|
+
positionCard(window2, hoverCard, element.getBoundingClientRect());
|
|
4336
|
+
}
|
|
4337
|
+
};
|
|
4338
|
+
const hideHover = () => {
|
|
4339
|
+
hoveredEl = null;
|
|
4340
|
+
if (hoverBox) setState(hoverBox, false);
|
|
4341
|
+
if (hoverCard) setState(hoverCard, false);
|
|
4342
|
+
};
|
|
4343
|
+
const snapshotPins = () => pinned.map((pin) => {
|
|
4344
|
+
const rect = pin.card.getBoundingClientRect();
|
|
4345
|
+
return {
|
|
4346
|
+
sourceEl: pin.sourceEl,
|
|
4347
|
+
left: pin.userPlaced ? rect.left + rect.width / 2 : 0,
|
|
4348
|
+
top: pin.userPlaced ? rect.top : 0,
|
|
4349
|
+
userPlaced: pin.userPlaced
|
|
4350
|
+
};
|
|
4351
|
+
});
|
|
4352
|
+
const recordPinState = () => {
|
|
4353
|
+
history.push(snapshotPins());
|
|
4354
|
+
future.length = 0;
|
|
4355
|
+
};
|
|
4356
|
+
const removePin = (pin, record = true, notify = record) => {
|
|
4357
|
+
const index = pinned.indexOf(pin);
|
|
4358
|
+
if (index === -1) return;
|
|
4359
|
+
if (record) recordPinState();
|
|
4360
|
+
pinned.splice(index, 1);
|
|
4361
|
+
pin.detach();
|
|
4362
|
+
pin.box.remove();
|
|
4363
|
+
pin.card.remove();
|
|
4364
|
+
if (notify) options.onUnpin?.(pin.sourceEl);
|
|
4365
|
+
};
|
|
4366
|
+
const clearPins = (notify = false) => {
|
|
4367
|
+
while (pinned.length) {
|
|
4368
|
+
removePin(pinned[pinned.length - 1], false, notify);
|
|
4369
|
+
}
|
|
4370
|
+
};
|
|
4371
|
+
const attachDrag = (pin) => {
|
|
4372
|
+
let pointerId = -1;
|
|
4373
|
+
let startX = 0;
|
|
4374
|
+
let startY = 0;
|
|
4375
|
+
let originLeft = 0;
|
|
4376
|
+
let originTop = 0;
|
|
4377
|
+
let active = false;
|
|
4378
|
+
let dragged = false;
|
|
4379
|
+
let historyRecorded = false;
|
|
4380
|
+
const slop = 6;
|
|
4381
|
+
const onMove = (event) => {
|
|
4382
|
+
if (event.pointerId !== pointerId) return;
|
|
4383
|
+
const dx = event.clientX - startX;
|
|
4384
|
+
const dy = event.clientY - startY;
|
|
4385
|
+
if (!active) active = Math.abs(dx) > slop || Math.abs(dy) > slop;
|
|
4386
|
+
if (!active) return;
|
|
4387
|
+
if (!historyRecorded) {
|
|
4388
|
+
recordPinState();
|
|
4389
|
+
historyRecorded = true;
|
|
4390
|
+
}
|
|
4391
|
+
dragged = true;
|
|
4392
|
+
pin.card.style.left = `${Math.min(
|
|
4393
|
+
window2.innerWidth - 8,
|
|
4394
|
+
Math.max(8, originLeft + dx)
|
|
4395
|
+
)}px`;
|
|
4396
|
+
pin.card.style.top = `${Math.min(
|
|
4397
|
+
window2.innerHeight - 8,
|
|
4398
|
+
Math.max(8, originTop + dy)
|
|
4399
|
+
)}px`;
|
|
4400
|
+
pin.userPlaced = true;
|
|
4401
|
+
};
|
|
4402
|
+
const onEnd = (event) => {
|
|
4403
|
+
if (event.pointerId !== pointerId && pointerId !== -1) return;
|
|
4404
|
+
window2.removeEventListener("pointermove", onMove);
|
|
4405
|
+
window2.removeEventListener("pointerup", onEnd);
|
|
4406
|
+
window2.removeEventListener("pointercancel", onEnd);
|
|
4407
|
+
pointerId = -1;
|
|
4408
|
+
active = false;
|
|
4409
|
+
historyRecorded = false;
|
|
4410
|
+
if (dragged) {
|
|
4411
|
+
const swallow = (click) => {
|
|
4412
|
+
click.preventDefault();
|
|
4413
|
+
click.stopPropagation();
|
|
4414
|
+
window2.removeEventListener("click", swallow, true);
|
|
4415
|
+
};
|
|
4416
|
+
window2.addEventListener("click", swallow, true);
|
|
4417
|
+
}
|
|
4418
|
+
dragged = false;
|
|
4419
|
+
};
|
|
4420
|
+
const onDown = (event) => {
|
|
4421
|
+
if (event.button !== 0) return;
|
|
4422
|
+
if (event.target?.classList.contains("mesurer-ti-close")) {
|
|
4423
|
+
return;
|
|
4424
|
+
}
|
|
4425
|
+
const rect = pin.card.getBoundingClientRect();
|
|
4426
|
+
originLeft = rect.left + rect.width / 2;
|
|
4427
|
+
originTop = rect.top;
|
|
4428
|
+
startX = event.clientX;
|
|
4429
|
+
startY = event.clientY;
|
|
4430
|
+
pointerId = event.pointerId;
|
|
4431
|
+
active = false;
|
|
4432
|
+
dragged = false;
|
|
4433
|
+
window2.addEventListener("pointermove", onMove);
|
|
4434
|
+
window2.addEventListener("pointerup", onEnd);
|
|
4435
|
+
window2.addEventListener("pointercancel", onEnd);
|
|
4436
|
+
};
|
|
4437
|
+
pin.card.addEventListener("pointerdown", onDown);
|
|
4438
|
+
return () => {
|
|
4439
|
+
pin.card.removeEventListener("pointerdown", onDown);
|
|
4440
|
+
window2.removeEventListener("pointermove", onMove);
|
|
4441
|
+
window2.removeEventListener("pointerup", onEnd);
|
|
4442
|
+
window2.removeEventListener("pointercancel", onEnd);
|
|
4443
|
+
};
|
|
4444
|
+
};
|
|
4445
|
+
const createPin = (sourceEl, state, record = true, notify = record) => {
|
|
4446
|
+
const existing = pinned.find((pin2) => pin2.sourceEl === sourceEl);
|
|
4447
|
+
if (existing) {
|
|
4448
|
+
const root2 = ensureOverlay();
|
|
4449
|
+
root2.append(existing.box, existing.card);
|
|
4450
|
+
return;
|
|
4451
|
+
}
|
|
4452
|
+
if (record) {
|
|
4453
|
+
recordPinState();
|
|
4454
|
+
if (pinned.length >= maxPinned) removePin(pinned[0], false, true);
|
|
4455
|
+
}
|
|
4456
|
+
const root = ensureOverlay();
|
|
4457
|
+
const box = makeBox(document2, FILL_PINNED, OUTLINE_PINNED);
|
|
4458
|
+
const card = makeCard(document2, true);
|
|
4459
|
+
const info = typography.getFull(sourceEl);
|
|
4460
|
+
populateCard(document2, card, info, true);
|
|
4461
|
+
root.append(box, card);
|
|
4462
|
+
const pin = {
|
|
4463
|
+
sourceEl,
|
|
4464
|
+
box,
|
|
4465
|
+
card,
|
|
4466
|
+
userPlaced: state?.userPlaced ?? false,
|
|
4467
|
+
detach: () => {
|
|
4468
|
+
}
|
|
4469
|
+
};
|
|
4470
|
+
const rect = sourceEl.getBoundingClientRect();
|
|
4471
|
+
positionBox(box, rect);
|
|
4472
|
+
positionCard(window2, card, rect);
|
|
4473
|
+
if (state?.userPlaced) {
|
|
4474
|
+
card.style.left = `${state.left}px`;
|
|
4475
|
+
card.style.top = `${state.top}px`;
|
|
4476
|
+
}
|
|
4477
|
+
setState(box, true);
|
|
4478
|
+
setState(card, true);
|
|
4479
|
+
pinned.push(pin);
|
|
4480
|
+
card.querySelector(".mesurer-ti-close")?.addEventListener(
|
|
4481
|
+
"click",
|
|
4482
|
+
(event) => {
|
|
4483
|
+
event.preventDefault();
|
|
4484
|
+
event.stopPropagation();
|
|
4485
|
+
removePin(pin);
|
|
4486
|
+
}
|
|
4487
|
+
);
|
|
4488
|
+
pin.detach = attachDrag(pin);
|
|
4489
|
+
if (notify) options.onPin?.(sourceEl, info);
|
|
4490
|
+
};
|
|
4491
|
+
const restorePins = (states) => {
|
|
4492
|
+
clearPins(false);
|
|
4493
|
+
for (const state of states) {
|
|
4494
|
+
if (state.sourceEl.isConnected) createPin(state.sourceEl, state, false, false);
|
|
4495
|
+
}
|
|
4496
|
+
};
|
|
4497
|
+
const undo = () => {
|
|
4498
|
+
const previous = history.pop();
|
|
4499
|
+
if (!previous) return false;
|
|
4500
|
+
future.push(snapshotPins());
|
|
4501
|
+
restorePins(previous);
|
|
4502
|
+
return true;
|
|
4503
|
+
};
|
|
4504
|
+
const redo = () => {
|
|
4505
|
+
const next = future.pop();
|
|
4506
|
+
if (!next) return false;
|
|
4507
|
+
history.push(snapshotPins());
|
|
4508
|
+
restorePins(next);
|
|
4509
|
+
return true;
|
|
4510
|
+
};
|
|
4511
|
+
const clear = () => {
|
|
4512
|
+
if (!pinned.length) return;
|
|
4513
|
+
recordPinState();
|
|
4514
|
+
clearPins(true);
|
|
4515
|
+
};
|
|
4516
|
+
const syncPins = () => {
|
|
4517
|
+
for (const pin of [...pinned]) {
|
|
4518
|
+
if (!pin.sourceEl.isConnected) {
|
|
4519
|
+
removePin(pin, false);
|
|
4520
|
+
continue;
|
|
4521
|
+
}
|
|
4522
|
+
const rect = pin.sourceEl.getBoundingClientRect();
|
|
4523
|
+
positionBox(pin.box, rect);
|
|
4524
|
+
if (!pin.userPlaced) positionCard(window2, pin.card, rect);
|
|
4525
|
+
const visible = rect.bottom >= 0 && rect.right >= 0 && rect.left <= window2.innerWidth && rect.top <= window2.innerHeight;
|
|
4526
|
+
setState(pin.box, visible);
|
|
4527
|
+
setState(pin.card, visible);
|
|
4528
|
+
pin.card.style.pointerEvents = visible ? "auto" : "none";
|
|
4529
|
+
}
|
|
4530
|
+
};
|
|
4531
|
+
const scheduleFrame = () => {
|
|
4532
|
+
if (frameScheduled) return;
|
|
4533
|
+
frameScheduled = true;
|
|
4534
|
+
requestAnimationFrame(() => {
|
|
4535
|
+
frameScheduled = false;
|
|
4536
|
+
if (!enabled) return;
|
|
4537
|
+
updateHover();
|
|
4538
|
+
syncPins();
|
|
4539
|
+
});
|
|
4540
|
+
};
|
|
4541
|
+
const onMouseMove = (event) => {
|
|
4542
|
+
pointerX = event.clientX;
|
|
4543
|
+
pointerY = event.clientY;
|
|
4544
|
+
scheduleFrame();
|
|
4545
|
+
};
|
|
4546
|
+
const onMouseOut = (event) => {
|
|
4547
|
+
if (!event.relatedTarget) hideHover();
|
|
4548
|
+
};
|
|
4549
|
+
const onScrollOrResize = () => scheduleFrame();
|
|
4550
|
+
const isInspectorUIEvent = (event) => event.composedPath().some(
|
|
4551
|
+
(node) => node instanceof HTMLElementConstructor && (() => {
|
|
4552
|
+
const element = node;
|
|
4553
|
+
return element.id === OVERLAY_ID || element.classList.contains("mesurer-ti-card") || element.classList.contains("mesurer-ti-box") || element.classList.contains("mesurer-ti-close") || element.classList.contains("mesurer-toolbar-surface");
|
|
4554
|
+
})()
|
|
4555
|
+
);
|
|
4556
|
+
const onClick = (event) => {
|
|
4557
|
+
if (isInspectorUIEvent(event) || pointerOverToolbar(event.clientX, event.clientY)) {
|
|
4558
|
+
return;
|
|
4559
|
+
}
|
|
4560
|
+
event.preventDefault();
|
|
4561
|
+
event.stopImmediatePropagation();
|
|
4562
|
+
if (event.button === 0) {
|
|
4563
|
+
const source = pickElementAt(event.clientX, event.clientY);
|
|
4564
|
+
if (source) createPin(source);
|
|
4565
|
+
}
|
|
4566
|
+
};
|
|
4567
|
+
const onAuxClick = (event) => {
|
|
4568
|
+
if (isInspectorUIEvent(event) || pointerOverToolbar(event.clientX, event.clientY)) {
|
|
4569
|
+
return;
|
|
4570
|
+
}
|
|
4571
|
+
event.preventDefault();
|
|
4572
|
+
event.stopImmediatePropagation();
|
|
4573
|
+
};
|
|
4574
|
+
const enable = () => {
|
|
4575
|
+
if (enabled || !availableDocument || !availableWindow) return;
|
|
4576
|
+
enabled = true;
|
|
4577
|
+
ensureStyles();
|
|
4578
|
+
ensureOverlay();
|
|
4579
|
+
document2.body.classList.add(BODY_MODE_CLASS);
|
|
4580
|
+
window2.addEventListener("mousemove", onMouseMove, true);
|
|
4581
|
+
window2.addEventListener("mouseout", onMouseOut, true);
|
|
4582
|
+
window2.addEventListener("click", onClick, true);
|
|
4583
|
+
window2.addEventListener("auxclick", onAuxClick, true);
|
|
4584
|
+
window2.addEventListener("scroll", onScrollOrResize, true);
|
|
4585
|
+
window2.addEventListener("resize", onScrollOrResize, true);
|
|
4586
|
+
};
|
|
4587
|
+
const disable = () => {
|
|
4588
|
+
if (!enabled) return;
|
|
4589
|
+
enabled = false;
|
|
4590
|
+
if (pendingIdleId !== -1) getIdleScheduler().cancel(pendingIdleId);
|
|
4591
|
+
pendingIdleId = -1;
|
|
4592
|
+
pendingElement = null;
|
|
4593
|
+
history.length = 0;
|
|
4594
|
+
future.length = 0;
|
|
4595
|
+
window2.removeEventListener("mousemove", onMouseMove, true);
|
|
4596
|
+
window2.removeEventListener("mouseout", onMouseOut, true);
|
|
4597
|
+
window2.removeEventListener("click", onClick, true);
|
|
4598
|
+
window2.removeEventListener("auxclick", onAuxClick, true);
|
|
4599
|
+
window2.removeEventListener("scroll", onScrollOrResize, true);
|
|
4600
|
+
window2.removeEventListener("resize", onScrollOrResize, true);
|
|
4601
|
+
hideHover();
|
|
4602
|
+
hoverBox?.remove();
|
|
4603
|
+
hoverCard?.remove();
|
|
4604
|
+
hoverBox = null;
|
|
4605
|
+
hoverCard = null;
|
|
4606
|
+
clearPins();
|
|
4607
|
+
document2.body.classList.remove(BODY_MODE_CLASS);
|
|
4608
|
+
};
|
|
4609
|
+
const cleanup = () => {
|
|
4610
|
+
disable();
|
|
4611
|
+
overlay?.remove();
|
|
4612
|
+
overlay = null;
|
|
4613
|
+
if (typeof document2 !== "undefined") {
|
|
4614
|
+
document2.getElementById(STYLE_ID)?.remove();
|
|
4615
|
+
if (portalIsShadowRoot) {
|
|
4616
|
+
options.portalTarget.querySelector(`#${STYLE_ID}`)?.remove();
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
};
|
|
4620
|
+
return {
|
|
4621
|
+
enable,
|
|
4622
|
+
disable,
|
|
4623
|
+
undo,
|
|
4624
|
+
redo,
|
|
4625
|
+
canUndo: () => history.length > 0,
|
|
4626
|
+
canRedo: () => future.length > 0,
|
|
4627
|
+
clear,
|
|
4628
|
+
inspect,
|
|
4629
|
+
isEnabled: () => enabled,
|
|
4630
|
+
cleanup,
|
|
4631
|
+
destroy: cleanup
|
|
4632
|
+
};
|
|
4633
|
+
};
|
|
4634
|
+
var TextInspector = createTextInspector({}, true);
|
|
4635
|
+
|
|
4636
|
+
// measurer.tsx
|
|
4637
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4638
|
+
var measurerInstanceCount = 0;
|
|
4639
|
+
var XRAY_STYLE_ID = "mesurer-xray-styles";
|
|
4640
|
+
var XRAY_STYLES = `
|
|
4641
|
+
.xray-mode * {
|
|
4642
|
+
outline: solid 1px blue !important;
|
|
4643
|
+
}
|
|
4644
|
+
.xray-mode #mesurer-extension-host,
|
|
4645
|
+
.xray-mode #mesurer-extension-host *,
|
|
4646
|
+
.xray-mode .mesurer-root,
|
|
4647
|
+
.xray-mode .mesurer-root *,
|
|
4648
|
+
.xray-mode .mesurer-toolbar-surface,
|
|
4649
|
+
.xray-mode .mesurer-toolbar-surface * {
|
|
4650
|
+
outline: none !important;
|
|
4651
|
+
}
|
|
4652
|
+
`;
|
|
4653
|
+
var subscribeHydration = () => () => {
|
|
4654
|
+
};
|
|
4655
|
+
var useHydrated = () => useSyncExternalStore(
|
|
4656
|
+
subscribeHydration,
|
|
4657
|
+
() => true,
|
|
4658
|
+
() => false
|
|
4659
|
+
);
|
|
4660
|
+
var stripMeasurement = (measurement) => ({
|
|
4661
|
+
...measurement,
|
|
4662
|
+
elementRef: void 0
|
|
4663
|
+
});
|
|
4664
|
+
var stripDistance = (distance) => ({
|
|
4665
|
+
...distance,
|
|
4666
|
+
elementRefA: void 0,
|
|
4667
|
+
elementRefB: void 0
|
|
4668
|
+
});
|
|
4669
|
+
function MeasurerClient({
|
|
4670
|
+
highlightColor,
|
|
4671
|
+
guideColor,
|
|
4672
|
+
hoverHighlightEnabled,
|
|
4673
|
+
persistOnReload,
|
|
4674
|
+
portalTarget,
|
|
4675
|
+
persistKey
|
|
4676
|
+
}) {
|
|
4677
|
+
const instanceIdRef = useRef9(null);
|
|
4678
|
+
if (instanceIdRef.current === null) {
|
|
4679
|
+
instanceIdRef.current = ++measurerInstanceCount;
|
|
4680
|
+
}
|
|
4681
|
+
const storageKey = persistKey ?? (instanceIdRef.current === 1 ? "mesurer-state" : `mesurer-state-${instanceIdRef.current}`);
|
|
4682
|
+
const ownerDocument = portalTarget.ownerDocument ?? document;
|
|
4683
|
+
const ownerWindow = ownerDocument.defaultView ?? window;
|
|
4684
|
+
const guideScrollRef = useRef9({
|
|
4685
|
+
x: ownerWindow.scrollX,
|
|
4686
|
+
y: ownerWindow.scrollY
|
|
4687
|
+
});
|
|
4688
|
+
const textInspectorRef = useRef9(null);
|
|
4689
|
+
if (!textInspectorRef.current) {
|
|
4690
|
+
textInspectorRef.current = createTextInspector({ portalTarget });
|
|
4691
|
+
}
|
|
4692
|
+
const textInspector = textInspectorRef.current;
|
|
4693
|
+
const selectionRectRef = useRef9(null);
|
|
4694
|
+
const toolbarRef = useRef9(null);
|
|
4695
|
+
const selectionAnimationCleanupTimeoutRef = useRef9(null);
|
|
4696
|
+
const guideDragRef = useRef9(null);
|
|
4697
|
+
const guideUserSelectRef = useRef9(null);
|
|
4698
|
+
const persistedState = useMemo2(() => {
|
|
4699
|
+
if (!persistOnReload) return null;
|
|
4700
|
+
try {
|
|
4701
|
+
const stored = window.localStorage.getItem(storageKey);
|
|
4702
|
+
if (!stored) return null;
|
|
4703
|
+
const parsed = JSON.parse(stored);
|
|
4704
|
+
if (!parsed || parsed.version !== 1) return null;
|
|
4705
|
+
return parsed;
|
|
4706
|
+
} catch {
|
|
4707
|
+
return null;
|
|
4708
|
+
}
|
|
4709
|
+
}, [persistOnReload, storageKey]);
|
|
4710
|
+
const enabledRef = useRef9(false);
|
|
4711
|
+
const toolModeRef = useRef9(
|
|
4712
|
+
persistedState?.toolMode === "rulers" ? "none" : persistedState?.toolMode ?? "none"
|
|
4713
|
+
);
|
|
4714
|
+
const rulersVisibleRef = useRef9(
|
|
4715
|
+
persistedState?.rulersVisible ?? persistedState?.toolMode === "rulers"
|
|
4716
|
+
);
|
|
4717
|
+
const guideOrientationRef = useRef9(
|
|
4718
|
+
persistedState?.guideOrientation ?? "vertical"
|
|
4719
|
+
);
|
|
4720
|
+
const measurementsRef = useRef9(
|
|
4721
|
+
persistedState?.measurements ?? []
|
|
4722
|
+
);
|
|
4723
|
+
const activeMeasurementRef = useRef9(
|
|
4724
|
+
persistedState?.activeMeasurement ?? null
|
|
4725
|
+
);
|
|
4726
|
+
const heldDistancesRef = useRef9(
|
|
4727
|
+
persistedState?.heldDistances ?? []
|
|
4728
|
+
);
|
|
4729
|
+
const guidesRef = useRef9(persistedState?.guides ?? []);
|
|
4730
|
+
const selectedGuideIdsRef = useRef9(
|
|
4731
|
+
persistedState?.selectedGuideIds ?? []
|
|
4732
|
+
);
|
|
4733
|
+
const { overlayRef, selectedElementRef, hoverElementRef } = useOverlayRefs();
|
|
4734
|
+
const {
|
|
4735
|
+
selectionOriginRect,
|
|
4736
|
+
setSelectionOriginRect,
|
|
4737
|
+
hoverPointer,
|
|
4738
|
+
setHoverPointer,
|
|
4739
|
+
hoverElement,
|
|
4740
|
+
setHoverElement,
|
|
4741
|
+
selectedElement,
|
|
4742
|
+
setSelectedElement,
|
|
4743
|
+
clearSelectionRect
|
|
4744
|
+
} = useMeasurerLocalState({
|
|
4745
|
+
selectedElementRef,
|
|
4746
|
+
hoverElementRef,
|
|
3308
4747
|
selectionRectRef
|
|
3309
4748
|
});
|
|
3310
4749
|
const {
|
|
@@ -3316,12 +4755,15 @@ function MeasurerClient({
|
|
|
3316
4755
|
setAltPressed,
|
|
3317
4756
|
toolMode,
|
|
3318
4757
|
setToolMode,
|
|
4758
|
+
rulersVisible,
|
|
4759
|
+
setRulersVisible,
|
|
3319
4760
|
guidesEnabled,
|
|
3320
4761
|
multiMeasureEnabled,
|
|
3321
4762
|
snapGuidesEnabled
|
|
3322
4763
|
} = useMeasureToggles({
|
|
3323
4764
|
initialEnabled: persistedState?.enabled,
|
|
3324
|
-
initialToolMode: persistedState?.toolMode
|
|
4765
|
+
initialToolMode: persistedState?.toolMode === "rulers" ? "none" : persistedState?.toolMode,
|
|
4766
|
+
initialRulersVisible: persistedState?.rulersVisible ?? persistedState?.toolMode === "rulers"
|
|
3325
4767
|
});
|
|
3326
4768
|
const { start, setStart, end, setEnd, isDragging, setIsDragging } = useDragState();
|
|
3327
4769
|
const {
|
|
@@ -3353,85 +4795,170 @@ function MeasurerClient({
|
|
|
3353
4795
|
initialGuides: persistedState?.guides ?? [],
|
|
3354
4796
|
initialSelectedGuideIds: persistedState?.selectedGuideIds ?? []
|
|
3355
4797
|
});
|
|
3356
|
-
const [toolbarActive, setToolbarActive] =
|
|
3357
|
-
const { clearGuideDragHold, scheduleGuideDragHold } = useGuideDragHold();
|
|
3358
|
-
const [guidePreview, setGuidePreview] =
|
|
3359
|
-
const [guideOrientation, setGuideOrientation] =
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
activeMeasurement: activeMeasurement ? stripMeasurement(activeMeasurement) : null,
|
|
3371
|
-
heldDistances: heldDistances.map(stripDistance)
|
|
3372
|
-
});
|
|
3373
|
-
}, [
|
|
3374
|
-
activeMeasurement,
|
|
3375
|
-
enabled,
|
|
3376
|
-
guideOrientation,
|
|
3377
|
-
guides,
|
|
3378
|
-
heldDistances,
|
|
3379
|
-
measurements,
|
|
3380
|
-
persistOnReload,
|
|
3381
|
-
selectedGuideIds,
|
|
3382
|
-
toolMode
|
|
3383
|
-
]);
|
|
3384
|
-
useEffect9(() => {
|
|
4798
|
+
const [toolbarActive, setToolbarActive] = useState8(true);
|
|
4799
|
+
const { clearGuideDragHold, scheduleGuideDragHold } = useGuideDragHold(ownerWindow);
|
|
4800
|
+
const [guidePreview, setGuidePreview] = useState8(null);
|
|
4801
|
+
const [guideOrientation, setGuideOrientation] = useState8(persistedState?.guideOrientation ?? "vertical");
|
|
4802
|
+
enabledRef.current = enabled;
|
|
4803
|
+
toolModeRef.current = toolMode;
|
|
4804
|
+
rulersVisibleRef.current = rulersVisible;
|
|
4805
|
+
guideOrientationRef.current = guideOrientation;
|
|
4806
|
+
measurementsRef.current = measurements;
|
|
4807
|
+
activeMeasurementRef.current = activeMeasurement;
|
|
4808
|
+
heldDistancesRef.current = heldDistances;
|
|
4809
|
+
guidesRef.current = guides;
|
|
4810
|
+
selectedGuideIdsRef.current = selectedGuideIds;
|
|
4811
|
+
const persistState = useCallback6(() => {
|
|
3385
4812
|
if (!persistOnReload) return;
|
|
3386
4813
|
if (typeof window === "undefined") return;
|
|
3387
|
-
if (!persistPayload) return;
|
|
3388
4814
|
try {
|
|
3389
|
-
window.localStorage.setItem(
|
|
4815
|
+
window.localStorage.setItem(
|
|
4816
|
+
storageKey,
|
|
4817
|
+
JSON.stringify({
|
|
4818
|
+
version: 1,
|
|
4819
|
+
enabled: enabledRef.current,
|
|
4820
|
+
toolMode: toolModeRef.current,
|
|
4821
|
+
rulersVisible: rulersVisibleRef.current,
|
|
4822
|
+
guideOrientation: guideOrientationRef.current,
|
|
4823
|
+
guides: guidesRef.current,
|
|
4824
|
+
selectedGuideIds: selectedGuideIdsRef.current,
|
|
4825
|
+
measurements: measurementsRef.current.map(stripMeasurement),
|
|
4826
|
+
activeMeasurement: activeMeasurementRef.current ? stripMeasurement(activeMeasurementRef.current) : null,
|
|
4827
|
+
heldDistances: heldDistancesRef.current.map(stripDistance)
|
|
4828
|
+
})
|
|
4829
|
+
);
|
|
3390
4830
|
} catch {
|
|
3391
4831
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
4832
|
+
}, [persistOnReload, storageKey]);
|
|
4833
|
+
const setEnabledPersisted = useCallback6(
|
|
4834
|
+
(value) => {
|
|
4835
|
+
const next = typeof value === "function" ? value(enabledRef.current) : value;
|
|
4836
|
+
if (Object.is(next, enabledRef.current)) return;
|
|
4837
|
+
enabledRef.current = next;
|
|
4838
|
+
setEnabled(next);
|
|
4839
|
+
persistState();
|
|
4840
|
+
},
|
|
4841
|
+
[persistState, setEnabled]
|
|
4842
|
+
);
|
|
4843
|
+
const setRulersVisiblePersisted = useCallback6(
|
|
4844
|
+
(value) => {
|
|
4845
|
+
const next = typeof value === "function" ? value(rulersVisibleRef.current) : value;
|
|
4846
|
+
if (Object.is(next, rulersVisibleRef.current)) return;
|
|
4847
|
+
rulersVisibleRef.current = next;
|
|
4848
|
+
setRulersVisible(next);
|
|
4849
|
+
persistState();
|
|
4850
|
+
},
|
|
4851
|
+
[persistState, setRulersVisible]
|
|
4852
|
+
);
|
|
4853
|
+
const setToolModePersisted = useCallback6(
|
|
4854
|
+
(value) => {
|
|
4855
|
+
const next = typeof value === "function" ? value(toolModeRef.current) : value;
|
|
4856
|
+
if (Object.is(next, toolModeRef.current)) return;
|
|
4857
|
+
toolModeRef.current = next;
|
|
4858
|
+
setToolMode(next);
|
|
4859
|
+
if (next === "text-inspector") {
|
|
4860
|
+
textInspector.enable();
|
|
4861
|
+
} else {
|
|
4862
|
+
textInspector.disable();
|
|
3396
4863
|
}
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
4864
|
+
persistState();
|
|
4865
|
+
},
|
|
4866
|
+
[persistState, setToolMode, textInspector]
|
|
4867
|
+
);
|
|
4868
|
+
const setGuideOrientationPersisted = useCallback6(
|
|
4869
|
+
(value) => {
|
|
4870
|
+
const next = typeof value === "function" ? value(guideOrientationRef.current) : value;
|
|
4871
|
+
if (Object.is(next, guideOrientationRef.current)) return;
|
|
4872
|
+
guideOrientationRef.current = next;
|
|
4873
|
+
setGuideOrientation(next);
|
|
4874
|
+
persistState();
|
|
4875
|
+
},
|
|
4876
|
+
[persistState, setGuideOrientation]
|
|
4877
|
+
);
|
|
4878
|
+
const setMeasurementsPersisted = useCallback6(
|
|
4879
|
+
(value) => {
|
|
4880
|
+
const next = typeof value === "function" ? value(measurementsRef.current) : value;
|
|
4881
|
+
if (Object.is(next, measurementsRef.current)) return;
|
|
4882
|
+
measurementsRef.current = next;
|
|
4883
|
+
setMeasurements(next);
|
|
4884
|
+
persistState();
|
|
4885
|
+
},
|
|
4886
|
+
[persistState, setMeasurements]
|
|
4887
|
+
);
|
|
4888
|
+
const setActiveMeasurementPersisted = useCallback6(
|
|
4889
|
+
(value) => {
|
|
4890
|
+
const next = typeof value === "function" ? value(activeMeasurementRef.current) : value;
|
|
4891
|
+
if (Object.is(next, activeMeasurementRef.current)) return;
|
|
4892
|
+
activeMeasurementRef.current = next;
|
|
4893
|
+
setActiveMeasurement(next);
|
|
4894
|
+
persistState();
|
|
4895
|
+
},
|
|
4896
|
+
[persistState, setActiveMeasurement]
|
|
4897
|
+
);
|
|
4898
|
+
const setHeldDistancesPersisted = useCallback6(
|
|
4899
|
+
(value) => {
|
|
4900
|
+
const next = typeof value === "function" ? value(heldDistancesRef.current) : value;
|
|
4901
|
+
if (Object.is(next, heldDistancesRef.current)) return;
|
|
4902
|
+
heldDistancesRef.current = next;
|
|
4903
|
+
setHeldDistances(next);
|
|
4904
|
+
persistState();
|
|
4905
|
+
},
|
|
4906
|
+
[persistState, setHeldDistances]
|
|
4907
|
+
);
|
|
4908
|
+
const setGuidesPersisted = useCallback6(
|
|
4909
|
+
(value) => {
|
|
4910
|
+
const next = typeof value === "function" ? value(guidesRef.current) : value;
|
|
4911
|
+
if (Object.is(next, guidesRef.current)) return;
|
|
4912
|
+
guidesRef.current = next;
|
|
4913
|
+
setGuides(next);
|
|
4914
|
+
persistState();
|
|
4915
|
+
},
|
|
4916
|
+
[persistState, setGuides]
|
|
4917
|
+
);
|
|
4918
|
+
const setSelectedGuideIdsPersisted = useCallback6(
|
|
4919
|
+
(value) => {
|
|
4920
|
+
const next = typeof value === "function" ? value(selectedGuideIdsRef.current) : value;
|
|
4921
|
+
if (Object.is(next, selectedGuideIdsRef.current)) return;
|
|
4922
|
+
selectedGuideIdsRef.current = next;
|
|
4923
|
+
setSelectedGuideIds(next);
|
|
4924
|
+
persistState();
|
|
4925
|
+
},
|
|
4926
|
+
[persistState, setSelectedGuideIds]
|
|
4927
|
+
);
|
|
3403
4928
|
const {
|
|
3404
4929
|
recordSnapshot,
|
|
3405
4930
|
createActionCommit,
|
|
3406
4931
|
setToolModeWithHistory,
|
|
3407
4932
|
setGuideOrientationWithHistory,
|
|
3408
|
-
setEnabledWithHistory
|
|
4933
|
+
setEnabledWithHistory,
|
|
4934
|
+
undo: undoHistory,
|
|
4935
|
+
redo: redoHistory
|
|
3409
4936
|
} = useMeasurerHistory({
|
|
3410
4937
|
toggles: {
|
|
3411
4938
|
enabled,
|
|
3412
|
-
setEnabled,
|
|
4939
|
+
setEnabled: setEnabledPersisted,
|
|
3413
4940
|
toolMode,
|
|
3414
|
-
setToolMode,
|
|
4941
|
+
setToolMode: setToolModePersisted,
|
|
3415
4942
|
guideOrientation,
|
|
3416
|
-
setGuideOrientation
|
|
4943
|
+
setGuideOrientation: setGuideOrientationPersisted
|
|
3417
4944
|
},
|
|
3418
4945
|
measurements: {
|
|
3419
4946
|
measurements,
|
|
3420
|
-
setMeasurements,
|
|
4947
|
+
setMeasurements: setMeasurementsPersisted,
|
|
3421
4948
|
activeMeasurement,
|
|
3422
|
-
setActiveMeasurement,
|
|
4949
|
+
setActiveMeasurement: setActiveMeasurementPersisted,
|
|
3423
4950
|
selectedMeasurements,
|
|
3424
4951
|
setSelectedMeasurements,
|
|
3425
4952
|
selectedMeasurement,
|
|
3426
4953
|
setSelectedMeasurement,
|
|
3427
4954
|
heldDistances,
|
|
3428
|
-
setHeldDistances
|
|
4955
|
+
setHeldDistances: setHeldDistancesPersisted
|
|
3429
4956
|
},
|
|
3430
4957
|
guides: {
|
|
3431
4958
|
guides,
|
|
3432
|
-
setGuides,
|
|
4959
|
+
setGuides: setGuidesPersisted,
|
|
3433
4960
|
selectedGuideIds,
|
|
3434
|
-
setSelectedGuideIds,
|
|
4961
|
+
setSelectedGuideIds: setSelectedGuideIdsPersisted,
|
|
3435
4962
|
draggingGuideId,
|
|
3436
4963
|
setDraggingGuideId
|
|
3437
4964
|
},
|
|
@@ -3446,96 +4973,254 @@ function MeasurerClient({
|
|
|
3446
4973
|
clearSelectionRect
|
|
3447
4974
|
}
|
|
3448
4975
|
});
|
|
4976
|
+
const undo = useCallback6(() => {
|
|
4977
|
+
if (toolMode === "text-inspector" && textInspector.undo()) return;
|
|
4978
|
+
undoHistory();
|
|
4979
|
+
}, [textInspector, toolMode, undoHistory]);
|
|
4980
|
+
const redo = useCallback6(() => {
|
|
4981
|
+
if (toolMode === "text-inspector" && textInspector.redo()) return;
|
|
4982
|
+
redoHistory();
|
|
4983
|
+
}, [redoHistory, textInspector, toolMode]);
|
|
3449
4984
|
const clearAll = useCallback6(() => {
|
|
4985
|
+
if (toolMode === "text-inspector") {
|
|
4986
|
+
textInspector.clear();
|
|
4987
|
+
}
|
|
3450
4988
|
recordSnapshot();
|
|
3451
4989
|
clearGuideDragHold();
|
|
3452
4990
|
setStart(null);
|
|
3453
4991
|
setEnd(null);
|
|
3454
4992
|
setIsDragging(false);
|
|
3455
|
-
|
|
3456
|
-
|
|
4993
|
+
setActiveMeasurementPersisted(null);
|
|
4994
|
+
setMeasurementsPersisted([]);
|
|
3457
4995
|
setSelectedMeasurement(null);
|
|
3458
4996
|
setSelectedMeasurements([]);
|
|
3459
4997
|
clearSelectionRect();
|
|
3460
4998
|
setSelectedElement(null);
|
|
3461
4999
|
setHoverRect(null);
|
|
3462
5000
|
setHoverElement(null);
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
5001
|
+
setGuidesPersisted([]);
|
|
5002
|
+
setSelectedGuideIdsPersisted([]);
|
|
5003
|
+
setHeldDistancesPersisted([]);
|
|
3466
5004
|
}, [
|
|
3467
5005
|
clearGuideDragHold,
|
|
3468
5006
|
clearSelectionRect,
|
|
3469
5007
|
recordSnapshot,
|
|
3470
|
-
|
|
5008
|
+
setActiveMeasurementPersisted,
|
|
3471
5009
|
setEnd,
|
|
3472
|
-
|
|
3473
|
-
|
|
5010
|
+
setGuidesPersisted,
|
|
5011
|
+
setHeldDistancesPersisted,
|
|
3474
5012
|
setHoverElement,
|
|
3475
5013
|
setHoverRect,
|
|
3476
5014
|
setIsDragging,
|
|
3477
|
-
|
|
5015
|
+
setMeasurementsPersisted,
|
|
3478
5016
|
setSelectedElement,
|
|
3479
|
-
|
|
5017
|
+
setSelectedGuideIdsPersisted,
|
|
3480
5018
|
setSelectedMeasurement,
|
|
3481
5019
|
setSelectedMeasurements,
|
|
3482
|
-
setStart
|
|
5020
|
+
setStart,
|
|
5021
|
+
textInspector,
|
|
5022
|
+
toolMode
|
|
3483
5023
|
]);
|
|
3484
5024
|
const removeSelectedGuides = useCallback6(() => {
|
|
3485
5025
|
if (selectedGuideIds.length === 0) return false;
|
|
3486
5026
|
recordSnapshot();
|
|
3487
|
-
|
|
5027
|
+
setGuidesPersisted(
|
|
3488
5028
|
(prev) => prev.filter((guide) => !selectedGuideIds.includes(guide.id))
|
|
3489
5029
|
);
|
|
3490
|
-
|
|
5030
|
+
setSelectedGuideIdsPersisted([]);
|
|
3491
5031
|
return true;
|
|
3492
|
-
}, [
|
|
5032
|
+
}, [
|
|
5033
|
+
recordSnapshot,
|
|
5034
|
+
selectedGuideIds,
|
|
5035
|
+
setGuidesPersisted,
|
|
5036
|
+
setSelectedGuideIdsPersisted
|
|
5037
|
+
]);
|
|
3493
5038
|
useHotkeys({
|
|
5039
|
+
eventTarget: ownerWindow,
|
|
3494
5040
|
clearAll,
|
|
5041
|
+
undo,
|
|
5042
|
+
redo,
|
|
3495
5043
|
removeSelectedGuides,
|
|
3496
5044
|
setEnabled: setEnabledWithHistory,
|
|
3497
5045
|
setToolMode: setToolModeWithHistory,
|
|
5046
|
+
setRulersVisible: setRulersVisiblePersisted,
|
|
3498
5047
|
setAltPressed,
|
|
3499
5048
|
isOverlayActive: () => enabled && (toolMode !== "none" || toolbarActive),
|
|
3500
5049
|
setGuideOrientation: setGuideOrientationWithHistory,
|
|
3501
5050
|
onInteract: () => setToolbarActive(true)
|
|
3502
5051
|
});
|
|
3503
5052
|
useResizeSync({
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
5053
|
+
document: ownerDocument,
|
|
5054
|
+
window: ownerWindow,
|
|
5055
|
+
setMeasurements: setMeasurementsPersisted,
|
|
5056
|
+
setActiveMeasurement: setActiveMeasurementPersisted,
|
|
5057
|
+
setHeldDistances: setHeldDistancesPersisted,
|
|
3507
5058
|
setSelectedMeasurement,
|
|
3508
|
-
setGuides,
|
|
5059
|
+
setGuides: setGuidesPersisted,
|
|
3509
5060
|
selectedElementRef
|
|
3510
5061
|
});
|
|
5062
|
+
useEffect5(() => {
|
|
5063
|
+
const handleScroll = () => {
|
|
5064
|
+
const next = {
|
|
5065
|
+
x: ownerWindow.scrollX,
|
|
5066
|
+
y: ownerWindow.scrollY
|
|
5067
|
+
};
|
|
5068
|
+
const deltaX = next.x - guideScrollRef.current.x;
|
|
5069
|
+
const deltaY = next.y - guideScrollRef.current.y;
|
|
5070
|
+
guideScrollRef.current = next;
|
|
5071
|
+
if (deltaX === 0 && deltaY === 0) return;
|
|
5072
|
+
setGuidesPersisted(
|
|
5073
|
+
(prev) => prev.map((guide) => ({
|
|
5074
|
+
...guide,
|
|
5075
|
+
position: guide.position - (guide.orientation === "vertical" ? deltaX : deltaY)
|
|
5076
|
+
}))
|
|
5077
|
+
);
|
|
5078
|
+
};
|
|
5079
|
+
ownerWindow.addEventListener("scroll", handleScroll, true);
|
|
5080
|
+
return () => ownerWindow.removeEventListener("scroll", handleScroll, true);
|
|
5081
|
+
}, [ownerWindow, setGuidesPersisted]);
|
|
3511
5082
|
useLiveElementTracking({
|
|
5083
|
+
document: ownerDocument,
|
|
5084
|
+
window: ownerWindow,
|
|
3512
5085
|
enabled,
|
|
3513
5086
|
selectedElementRef,
|
|
3514
5087
|
hoverElementRef,
|
|
3515
5088
|
setSelectedMeasurement,
|
|
3516
5089
|
setSelectedMeasurements,
|
|
3517
5090
|
setHoverRect,
|
|
3518
|
-
setMeasurements,
|
|
3519
|
-
setActiveMeasurement,
|
|
3520
|
-
setHeldDistances
|
|
5091
|
+
setMeasurements: setMeasurementsPersisted,
|
|
5092
|
+
setActiveMeasurement: setActiveMeasurementPersisted,
|
|
5093
|
+
setHeldDistances: setHeldDistancesPersisted
|
|
3521
5094
|
});
|
|
3522
|
-
|
|
5095
|
+
useEffect5(() => {
|
|
3523
5096
|
if (!toolbarActive || toolMode !== "none") return;
|
|
3524
5097
|
const handlePointerDown2 = (event) => {
|
|
3525
5098
|
const toolbarNode = toolbarRef.current;
|
|
3526
5099
|
if (toolbarNode && toolbarNode.contains(event.target)) return;
|
|
3527
5100
|
setToolbarActive(false);
|
|
3528
5101
|
};
|
|
3529
|
-
|
|
5102
|
+
ownerWindow.addEventListener("pointerdown", handlePointerDown2);
|
|
3530
5103
|
return () => {
|
|
3531
|
-
|
|
5104
|
+
ownerWindow.removeEventListener("pointerdown", handlePointerDown2);
|
|
3532
5105
|
};
|
|
3533
|
-
}, [toolbarActive, toolMode]);
|
|
3534
|
-
|
|
3535
|
-
if (
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
5106
|
+
}, [ownerWindow, toolbarActive, toolMode]);
|
|
5107
|
+
useEffect5(() => {
|
|
5108
|
+
if (!enabled) return;
|
|
5109
|
+
const handleGuidePointerDown2 = (event) => {
|
|
5110
|
+
if (toolbarRef.current?.contains(event.target)) return;
|
|
5111
|
+
const guideTarget = event.composedPath().some(
|
|
5112
|
+
(target) => target instanceof ownerWindow.Element && target.hasAttribute("data-mesurer-guide")
|
|
5113
|
+
);
|
|
5114
|
+
if (guideTarget && toolMode !== "none") return;
|
|
5115
|
+
const point = { x: event.clientX, y: event.clientY };
|
|
5116
|
+
const guide = guides.find((candidate) => {
|
|
5117
|
+
const distance = candidate.orientation === "vertical" ? Math.abs(candidate.position - point.x) : Math.abs(candidate.position - point.y);
|
|
5118
|
+
return distance <= GUIDE_HITBOX_SIZE / 2;
|
|
5119
|
+
});
|
|
5120
|
+
if (!guide) return;
|
|
5121
|
+
if (event.button === 0 && !event.shiftKey && toolMode === "none") {
|
|
5122
|
+
guideDragRef.current = {
|
|
5123
|
+
id: guide.id,
|
|
5124
|
+
orientation: guide.orientation,
|
|
5125
|
+
pointerId: event.pointerId,
|
|
5126
|
+
commit: createActionCommit(),
|
|
5127
|
+
committed: false
|
|
5128
|
+
};
|
|
5129
|
+
}
|
|
5130
|
+
setSelectedGuideIdsPersisted(
|
|
5131
|
+
(prev) => event.shiftKey ? prev.includes(guide.id) ? prev.filter((id) => id !== guide.id) : [...prev, guide.id] : [guide.id]
|
|
5132
|
+
);
|
|
5133
|
+
};
|
|
5134
|
+
const handleGuidePointerMove = (event) => {
|
|
5135
|
+
const drag = guideDragRef.current;
|
|
5136
|
+
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
5137
|
+
const position = drag.orientation === "vertical" ? event.clientX : event.clientY;
|
|
5138
|
+
if (!drag.committed) {
|
|
5139
|
+
event.preventDefault();
|
|
5140
|
+
if (guideUserSelectRef.current === null) {
|
|
5141
|
+
guideUserSelectRef.current = ownerDocument.documentElement.style.userSelect;
|
|
5142
|
+
ownerDocument.documentElement.style.userSelect = "none";
|
|
5143
|
+
}
|
|
5144
|
+
ownerWindow.getSelection()?.removeAllRanges();
|
|
5145
|
+
drag.commit();
|
|
5146
|
+
drag.committed = true;
|
|
5147
|
+
}
|
|
5148
|
+
setGuidesPersisted(
|
|
5149
|
+
(prev) => prev.map(
|
|
5150
|
+
(guide) => guide.id === drag.id ? { ...guide, position } : guide
|
|
5151
|
+
)
|
|
5152
|
+
);
|
|
5153
|
+
};
|
|
5154
|
+
const handleGuidePointerEnd = (event) => {
|
|
5155
|
+
if (guideDragRef.current?.pointerId === event.pointerId) {
|
|
5156
|
+
guideDragRef.current = null;
|
|
5157
|
+
if (guideUserSelectRef.current !== null) {
|
|
5158
|
+
ownerDocument.documentElement.style.userSelect = guideUserSelectRef.current;
|
|
5159
|
+
guideUserSelectRef.current = null;
|
|
5160
|
+
}
|
|
5161
|
+
}
|
|
5162
|
+
};
|
|
5163
|
+
ownerWindow.addEventListener("pointerdown", handleGuidePointerDown2, true);
|
|
5164
|
+
ownerWindow.addEventListener("pointermove", handleGuidePointerMove, true);
|
|
5165
|
+
ownerWindow.addEventListener("pointerup", handleGuidePointerEnd, true);
|
|
5166
|
+
ownerWindow.addEventListener("pointercancel", handleGuidePointerEnd, true);
|
|
5167
|
+
return () => {
|
|
5168
|
+
ownerWindow.removeEventListener(
|
|
5169
|
+
"pointerdown",
|
|
5170
|
+
handleGuidePointerDown2,
|
|
5171
|
+
true
|
|
5172
|
+
);
|
|
5173
|
+
ownerWindow.removeEventListener("pointermove", handleGuidePointerMove, true);
|
|
5174
|
+
ownerWindow.removeEventListener("pointerup", handleGuidePointerEnd, true);
|
|
5175
|
+
ownerWindow.removeEventListener(
|
|
5176
|
+
"pointercancel",
|
|
5177
|
+
handleGuidePointerEnd,
|
|
5178
|
+
true
|
|
5179
|
+
);
|
|
5180
|
+
if (guideUserSelectRef.current !== null) {
|
|
5181
|
+
ownerDocument.documentElement.style.userSelect = guideUserSelectRef.current;
|
|
5182
|
+
guideUserSelectRef.current = null;
|
|
5183
|
+
}
|
|
5184
|
+
};
|
|
5185
|
+
}, [
|
|
5186
|
+
createActionCommit,
|
|
5187
|
+
enabled,
|
|
5188
|
+
guides,
|
|
5189
|
+
ownerWindow,
|
|
5190
|
+
setGuidesPersisted,
|
|
5191
|
+
setSelectedGuideIdsPersisted,
|
|
5192
|
+
toolMode
|
|
5193
|
+
]);
|
|
5194
|
+
useEffect5(() => {
|
|
5195
|
+
if (toolMode === "text-inspector") {
|
|
5196
|
+
textInspector.enable();
|
|
5197
|
+
} else {
|
|
5198
|
+
textInspector.disable();
|
|
5199
|
+
}
|
|
5200
|
+
}, [textInspector, toolMode]);
|
|
5201
|
+
useEffect5(() => {
|
|
5202
|
+
let style = ownerDocument.getElementById(XRAY_STYLE_ID);
|
|
5203
|
+
if (!style) {
|
|
5204
|
+
style = ownerDocument.createElement("style");
|
|
5205
|
+
style.id = XRAY_STYLE_ID;
|
|
5206
|
+
style.textContent = XRAY_STYLES;
|
|
5207
|
+
ownerDocument.head.appendChild(style);
|
|
5208
|
+
}
|
|
5209
|
+
if (toolMode === "xray") {
|
|
5210
|
+
ownerDocument.body.classList.add("xray-mode");
|
|
5211
|
+
} else {
|
|
5212
|
+
ownerDocument.body.classList.remove("xray-mode");
|
|
5213
|
+
}
|
|
5214
|
+
return () => {
|
|
5215
|
+
ownerDocument.body.classList.remove("xray-mode");
|
|
5216
|
+
};
|
|
5217
|
+
}, [ownerDocument, toolMode]);
|
|
5218
|
+
useEffect5(() => {
|
|
5219
|
+
return () => {
|
|
5220
|
+
textInspector.destroy();
|
|
5221
|
+
};
|
|
5222
|
+
}, [textInspector]);
|
|
5223
|
+
useEffect5(() => {
|
|
3539
5224
|
const hasSelectionAnimationState = !!selectionOriginRect || !!selectedMeasurement?.originRect || selectedMeasurements.some((measurement) => !!measurement.originRect);
|
|
3540
5225
|
if (!hasSelectionAnimationState) {
|
|
3541
5226
|
if (selectionAnimationCleanupTimeoutRef.current !== null) {
|
|
@@ -3564,6 +5249,12 @@ function MeasurerClient({
|
|
|
3564
5249
|
return changed ? next : prev;
|
|
3565
5250
|
});
|
|
3566
5251
|
}, MEASURE_TRANSITION_MS);
|
|
5252
|
+
return () => {
|
|
5253
|
+
if (selectionAnimationCleanupTimeoutRef.current !== null) {
|
|
5254
|
+
window.clearTimeout(selectionAnimationCleanupTimeoutRef.current);
|
|
5255
|
+
selectionAnimationCleanupTimeoutRef.current = null;
|
|
5256
|
+
}
|
|
5257
|
+
};
|
|
3567
5258
|
}, [
|
|
3568
5259
|
selectionOriginRect,
|
|
3569
5260
|
selectedMeasurement,
|
|
@@ -3572,13 +5263,6 @@ function MeasurerClient({
|
|
|
3572
5263
|
setSelectedMeasurements,
|
|
3573
5264
|
setSelectionOriginRect
|
|
3574
5265
|
]);
|
|
3575
|
-
useEffect9(() => {
|
|
3576
|
-
return () => {
|
|
3577
|
-
if (selectionAnimationCleanupTimeoutRef.current !== null) {
|
|
3578
|
-
window.clearTimeout(selectionAnimationCleanupTimeoutRef.current);
|
|
3579
|
-
}
|
|
3580
|
-
};
|
|
3581
|
-
}, []);
|
|
3582
5266
|
const displayedMeasurements = holdEnabled ? measurements : multiMeasureEnabled && measurements.length > 0 ? measurements : activeMeasurement ? [activeMeasurement] : [];
|
|
3583
5267
|
const {
|
|
3584
5268
|
activeRect,
|
|
@@ -3600,6 +5284,8 @@ function MeasurerClient({
|
|
|
3600
5284
|
hoverEdgeVisibility,
|
|
3601
5285
|
measurementEdgeVisibility
|
|
3602
5286
|
} = useMeasurerDerived({
|
|
5287
|
+
document: ownerDocument,
|
|
5288
|
+
window: ownerWindow,
|
|
3603
5289
|
start,
|
|
3604
5290
|
end,
|
|
3605
5291
|
selectedMeasurements,
|
|
@@ -3625,6 +5311,8 @@ function MeasurerClient({
|
|
|
3625
5311
|
handlePointerUp,
|
|
3626
5312
|
handlePointerLeave
|
|
3627
5313
|
} = useMeasurerPointer({
|
|
5314
|
+
document: ownerDocument,
|
|
5315
|
+
window: ownerWindow,
|
|
3628
5316
|
toolbarRef,
|
|
3629
5317
|
overlayRef,
|
|
3630
5318
|
selectionRectRef,
|
|
@@ -3650,15 +5338,15 @@ function MeasurerClient({
|
|
|
3650
5338
|
optionPairOverlay,
|
|
3651
5339
|
setAltPressed,
|
|
3652
5340
|
setGuidePreview,
|
|
3653
|
-
setSelectedGuideIds,
|
|
3654
|
-
setGuides,
|
|
5341
|
+
setSelectedGuideIds: setSelectedGuideIdsPersisted,
|
|
5342
|
+
setGuides: setGuidesPersisted,
|
|
3655
5343
|
setStart,
|
|
3656
5344
|
setEnd,
|
|
3657
5345
|
setIsDragging,
|
|
3658
|
-
setHeldDistances,
|
|
5346
|
+
setHeldDistances: setHeldDistancesPersisted,
|
|
3659
5347
|
setDraggingGuideId,
|
|
3660
|
-
setActiveMeasurement,
|
|
3661
|
-
setMeasurements,
|
|
5348
|
+
setActiveMeasurement: setActiveMeasurementPersisted,
|
|
5349
|
+
setMeasurements: setMeasurementsPersisted,
|
|
3662
5350
|
setSelectedMeasurements,
|
|
3663
5351
|
setSelectedMeasurement,
|
|
3664
5352
|
setSelectionOriginRect,
|
|
@@ -3671,24 +5359,62 @@ function MeasurerClient({
|
|
|
3671
5359
|
const removeHeldDistance = useCallback6(
|
|
3672
5360
|
(id) => {
|
|
3673
5361
|
recordSnapshot();
|
|
3674
|
-
|
|
5362
|
+
setHeldDistancesPersisted(
|
|
5363
|
+
(prev) => prev.filter((distance) => distance.id !== id)
|
|
5364
|
+
);
|
|
5365
|
+
},
|
|
5366
|
+
[recordSnapshot, setHeldDistancesPersisted]
|
|
5367
|
+
);
|
|
5368
|
+
const startGuideFromRuler = useCallback6(
|
|
5369
|
+
(orientation, position) => {
|
|
5370
|
+
const id = createId();
|
|
5371
|
+
const commit = createActionCommit();
|
|
5372
|
+
commit();
|
|
5373
|
+
setSelectedGuideIdsPersisted([]);
|
|
5374
|
+
setGuidesPersisted((prev) => [...prev, { id, orientation, position }]);
|
|
5375
|
+
return id;
|
|
5376
|
+
},
|
|
5377
|
+
[
|
|
5378
|
+
createActionCommit,
|
|
5379
|
+
setGuidesPersisted,
|
|
5380
|
+
setSelectedGuideIdsPersisted
|
|
5381
|
+
]
|
|
5382
|
+
);
|
|
5383
|
+
const moveGuideFromRuler = useCallback6(
|
|
5384
|
+
(id, position) => {
|
|
5385
|
+
setGuidesPersisted(
|
|
5386
|
+
(prev) => prev.map((guide) => guide.id === id ? { ...guide, position } : guide)
|
|
5387
|
+
);
|
|
5388
|
+
},
|
|
5389
|
+
[setGuidesPersisted]
|
|
5390
|
+
);
|
|
5391
|
+
const finishGuideFromRuler = useCallback6(
|
|
5392
|
+
(id) => {
|
|
5393
|
+
setSelectedGuideIdsPersisted([id]);
|
|
5394
|
+
},
|
|
5395
|
+
[setSelectedGuideIdsPersisted]
|
|
5396
|
+
);
|
|
5397
|
+
const cancelGuideFromRuler = useCallback6(
|
|
5398
|
+
(id) => {
|
|
5399
|
+
setGuidesPersisted((prev) => prev.filter((guide) => guide.id !== id));
|
|
3675
5400
|
},
|
|
3676
|
-
[
|
|
5401
|
+
[setGuidesPersisted]
|
|
3677
5402
|
);
|
|
3678
5403
|
const handleGuidePointerDown = useCallback6(
|
|
3679
5404
|
(guide, event) => {
|
|
3680
5405
|
const commit = createActionCommit();
|
|
3681
5406
|
if (!enabled) return;
|
|
3682
5407
|
event.stopPropagation();
|
|
5408
|
+
event.preventDefault();
|
|
3683
5409
|
if (event.shiftKey) {
|
|
3684
5410
|
commit();
|
|
3685
|
-
|
|
5411
|
+
setSelectedGuideIdsPersisted(
|
|
3686
5412
|
(prev) => prev.includes(guide.id) ? prev.filter((id) => id !== guide.id) : [...prev, guide.id]
|
|
3687
5413
|
);
|
|
3688
5414
|
return;
|
|
3689
5415
|
}
|
|
3690
5416
|
commit();
|
|
3691
|
-
|
|
5417
|
+
setSelectedGuideIdsPersisted([guide.id]);
|
|
3692
5418
|
scheduleGuideDragHold(guide.id, setDraggingGuideId);
|
|
3693
5419
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
3694
5420
|
},
|
|
@@ -3697,7 +5423,7 @@ function MeasurerClient({
|
|
|
3697
5423
|
enabled,
|
|
3698
5424
|
scheduleGuideDragHold,
|
|
3699
5425
|
setDraggingGuideId,
|
|
3700
|
-
|
|
5426
|
+
setSelectedGuideIdsPersisted
|
|
3701
5427
|
]
|
|
3702
5428
|
);
|
|
3703
5429
|
const handleGuidePointerUp = useCallback6(
|
|
@@ -3712,17 +5438,29 @@ function MeasurerClient({
|
|
|
3712
5438
|
[clearGuideDragHold, setDraggingGuideId]
|
|
3713
5439
|
);
|
|
3714
5440
|
return createPortal(
|
|
3715
|
-
/* @__PURE__ */
|
|
5441
|
+
/* @__PURE__ */ jsxs7(
|
|
3716
5442
|
"div",
|
|
3717
5443
|
{
|
|
3718
5444
|
ref: overlayRef,
|
|
3719
5445
|
className: "mesurer-root msr:pointer-events-none msr:fixed msr:inset-0 msr:z-50",
|
|
3720
5446
|
children: [
|
|
3721
|
-
/* @__PURE__ */
|
|
5447
|
+
enabled && rulersVisible ? /* @__PURE__ */ jsx9(
|
|
5448
|
+
RulersOverlay,
|
|
5449
|
+
{
|
|
5450
|
+
onStartGuide: startGuideFromRuler,
|
|
5451
|
+
onMoveGuide: moveGuideFromRuler,
|
|
5452
|
+
onFinishGuide: finishGuideFromRuler,
|
|
5453
|
+
onCancelGuide: cancelGuideFromRuler,
|
|
5454
|
+
guides,
|
|
5455
|
+
selectedGuideIds
|
|
5456
|
+
}
|
|
5457
|
+
) : null,
|
|
5458
|
+
/* @__PURE__ */ jsx9(
|
|
3722
5459
|
MeasurerOverlay,
|
|
3723
5460
|
{
|
|
3724
5461
|
enabled,
|
|
3725
5462
|
toolMode,
|
|
5463
|
+
guidePointerEvents: enabled && (toolMode !== "none" || rulersVisible),
|
|
3726
5464
|
guidesEnabled,
|
|
3727
5465
|
altPressed,
|
|
3728
5466
|
isDragging,
|
|
@@ -3760,13 +5498,16 @@ function MeasurerClient({
|
|
|
3760
5498
|
onGuidePointerCancel: handleGuidePointerUp
|
|
3761
5499
|
}
|
|
3762
5500
|
),
|
|
3763
|
-
/* @__PURE__ */
|
|
5501
|
+
/* @__PURE__ */ jsx9(
|
|
3764
5502
|
Toolbar,
|
|
3765
5503
|
{
|
|
3766
5504
|
ref: toolbarRef,
|
|
5505
|
+
eventTarget: ownerWindow,
|
|
3767
5506
|
toolMode,
|
|
3768
5507
|
setEnabled: setEnabledWithHistory,
|
|
3769
5508
|
setToolMode: setToolModeWithHistory,
|
|
5509
|
+
rulersVisible,
|
|
5510
|
+
setRulersVisible: setRulersVisiblePersisted,
|
|
3770
5511
|
guideOrientation,
|
|
3771
5512
|
setGuideOrientation: setGuideOrientationWithHistory,
|
|
3772
5513
|
onInteract: () => setToolbarActive(true)
|
|
@@ -3783,24 +5524,28 @@ function Measurer({
|
|
|
3783
5524
|
guideColor = "oklch(0.63 0.26 29.23)",
|
|
3784
5525
|
hoverHighlightEnabled = true,
|
|
3785
5526
|
persistOnReload = false,
|
|
3786
|
-
portalTarget
|
|
5527
|
+
portalTarget,
|
|
5528
|
+
persistKey
|
|
3787
5529
|
}) {
|
|
3788
5530
|
if (typeof document !== "undefined") {
|
|
3789
5531
|
ensureMeasurerStyles(MESURER_STYLES, portalTarget);
|
|
3790
5532
|
}
|
|
3791
5533
|
const hydrated = useHydrated();
|
|
3792
5534
|
if (!hydrated) return null;
|
|
3793
|
-
return /* @__PURE__ */
|
|
5535
|
+
return /* @__PURE__ */ jsx9(
|
|
3794
5536
|
MeasurerClient,
|
|
3795
5537
|
{
|
|
3796
5538
|
highlightColor,
|
|
3797
5539
|
guideColor,
|
|
3798
5540
|
hoverHighlightEnabled,
|
|
3799
5541
|
persistOnReload,
|
|
5542
|
+
persistKey,
|
|
3800
5543
|
portalTarget: portalTarget ?? document.body
|
|
3801
5544
|
}
|
|
3802
5545
|
);
|
|
3803
5546
|
}
|
|
3804
5547
|
export {
|
|
3805
|
-
Measurer
|
|
5548
|
+
Measurer,
|
|
5549
|
+
TextInspector,
|
|
5550
|
+
createTextInspector
|
|
3806
5551
|
};
|