@weasel-js/labkit 1.7.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/_dts/{CanvasStackContext-D2jnIwfk.d.ts → CanvasStackContext-Cjy6I-Iv.d.ts} +4 -1
- package/dist/_dts/{Stage-CCWfQQWM.d.ts → Stage-D6t7o0pF.d.ts} +3 -2
- package/dist/_dts/{index-CsYqUHD3.d.ts → index-BTmaRy6a.d.ts} +10 -6
- package/dist/_dts/{types-CSm9jgol.d.ts → index-DCMA4Fy1.d.ts} +59 -113
- package/dist/_dts/{types-CRPSGFAp.d.ts → types-BUBSIZuV.d.ts} +8 -7
- package/dist/_dts/{useTrialState-CTZPgeZ7.d.ts → useTrialState-Bh8bzFgE.d.ts} +1 -1
- package/dist/canvas/index.d.ts +8 -6
- package/dist/canvas/index.js +6 -6
- package/dist/chrome/index.d.ts +7 -5
- package/dist/chrome/index.js +10 -9
- package/dist/chunk-2ES4W47N.js +8 -0
- package/dist/chunk-2ES4W47N.js.map +1 -0
- package/dist/{chunk-WPLAANH4.js → chunk-2N7UBSS2.js} +12 -12
- package/dist/chunk-2N7UBSS2.js.map +1 -0
- package/dist/chunk-4KSC7NXL.js +15491 -0
- package/dist/chunk-4KSC7NXL.js.map +1 -0
- package/dist/{chunk-7BO7HNGF.js → chunk-CEGFXTBD.js} +8 -61
- package/dist/chunk-CEGFXTBD.js.map +1 -0
- package/dist/{chunk-275JRRVD.js → chunk-E23Q6A3Y.js} +232 -37
- package/dist/chunk-E23Q6A3Y.js.map +1 -0
- package/dist/{chunk-GOZLNM4L.js → chunk-E6NARGU7.js} +5 -5
- package/dist/{chunk-GOZLNM4L.js.map → chunk-E6NARGU7.js.map} +1 -1
- package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
- package/dist/chunk-EESJUSYR.js.map +1 -0
- package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
- package/dist/chunk-EFXRM6XQ.js.map +1 -0
- package/dist/chunk-F4ACIK7Z.js +210 -0
- package/dist/chunk-F4ACIK7Z.js.map +1 -0
- package/dist/{chunk-FMK7UQ6V.js → chunk-FB4MIZOO.js} +61 -44
- package/dist/chunk-FB4MIZOO.js.map +1 -0
- package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
- package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
- package/dist/{chunk-I5DUQ5HM.js → chunk-GAHELLJT.js} +75 -72
- package/dist/chunk-GAHELLJT.js.map +1 -0
- package/dist/{chunk-YT75VYRD.js → chunk-IBVRMHW5.js} +5 -5
- package/dist/{chunk-YT75VYRD.js.map → chunk-IBVRMHW5.js.map} +1 -1
- package/dist/{chunk-T5IBSPAM.js → chunk-JFOJESJF.js} +33 -23
- package/dist/chunk-JFOJESJF.js.map +1 -0
- package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
- package/dist/chunk-PMLZP7RT.js.map +1 -0
- package/dist/{chunk-Y23G2VZL.js → chunk-READTDQX.js} +2 -2
- package/dist/chunk-READTDQX.js.map +1 -0
- package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
- package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
- package/dist/{chunk-ZIFPHIWZ.js → chunk-T6DLGEJB.js} +12 -14
- package/dist/chunk-T6DLGEJB.js.map +1 -0
- package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
- package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
- package/dist/{chunk-UNAZSLWE.js → chunk-VYVGVBGY.js} +17 -20
- package/dist/chunk-VYVGVBGY.js.map +1 -0
- package/dist/{chunk-KMJ7RWD3.js → chunk-WLMDTI2Q.js} +3 -3
- package/dist/{chunk-KMJ7RWD3.js.map → chunk-WLMDTI2Q.js.map} +1 -1
- package/dist/{chunk-J7OWWTCW.js → chunk-XE5HJOPL.js} +5 -6
- package/dist/chunk-XE5HJOPL.js.map +1 -0
- package/dist/chunk-XVUKDSYV.js +38 -0
- package/dist/chunk-XVUKDSYV.js.map +1 -0
- package/dist/{chunk-FZ7YFQN7.js → chunk-YCFKW5RX.js} +3 -3
- package/dist/chunk-YCFKW5RX.js.map +1 -0
- package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
- package/dist/chunk-ZQIHJXP4.js.map +1 -0
- package/dist/config/index.d.ts +18 -10
- package/dist/config/index.js +4 -4
- package/dist/controls/index.d.ts +4 -7
- package/dist/controls/index.js +6 -5
- package/dist/dragdrop/index.d.ts +23 -3
- package/dist/dragdrop/index.js +4 -3
- package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
- package/dist/index.d.ts +60 -714
- package/dist/index.js +357 -334
- package/dist/index.js.map +1 -1
- package/dist/job/index.d.ts +8 -0
- package/dist/job/index.js +1 -1
- package/dist/layers/index.d.ts +6 -5
- package/dist/layers/index.js +3 -2
- package/dist/loupe/index.d.ts +100 -30
- package/dist/loupe/index.js +585 -6
- package/dist/loupe/index.js.map +1 -1
- package/dist/overview/index.d.ts +4 -2
- package/dist/overview/index.js +15 -14
- package/dist/overview/index.js.map +1 -1
- package/dist/passthrough/weasel-canvas.d.ts +2 -0
- package/dist/passthrough/weasel-ui.d.ts +2 -2871
- package/dist/passthrough/weasel-ui.js +3 -2
- package/dist/primitives/index.d.ts +213 -3
- package/dist/primitives/index.js +8 -7
- package/dist/state/index.d.ts +7 -5
- package/dist/state/index.js +6 -6
- package/dist/styles.css +60 -44
- package/dist/surface/index.d.ts +10 -2
- package/dist/surface/index.js +1 -1
- package/dist/undo/index.d.ts +5 -3
- package/package.json +11 -11
- package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
- package/src/annotations/AnnotationOverlay.tsx +50 -31
- package/src/annotations/Annotations.overlay.test.tsx +31 -0
- package/src/annotations/capture.browser.test.ts +41 -0
- package/src/annotations/capture.ts +14 -7
- package/src/annotations/drawOne.ts +2 -2
- package/src/annotations/frac.test.ts +44 -1
- package/src/annotations/frac.ts +46 -18
- package/src/annotations/index.ts +1 -0
- package/src/annotations/paint.test.ts +74 -33
- package/src/annotations/paint.ts +70 -32
- package/src/annotations/store.test.ts +212 -2
- package/src/annotations/store.ts +130 -27
- package/src/annotations/svgNodes.test.ts +22 -10
- package/src/annotations/svgNodes.ts +3 -3
- package/src/annotations/types.ts +29 -10
- package/src/canvas/CameraInput.test.tsx +30 -0
- package/src/canvas/CameraInput.tsx +16 -15
- package/src/canvas/CanvasStack.tsx +5 -5
- package/src/canvas/CanvasStackContext.ts +4 -1
- package/src/canvas/Stage.tsx +3 -3
- package/src/canvas/cameraRegistry.ts +1 -0
- package/src/canvas/worldSpec.ts +3 -1
- package/src/chrome/builtins.test.ts +7 -6
- package/src/chrome/builtins.tsx +5 -1
- package/src/chrome/index.ts +1 -1
- package/src/chrome/merge.test.ts +5 -0
- package/src/chrome/merge.ts +4 -2
- package/src/chrome/regions/PaletteRegion.test.tsx +2 -3
- package/src/chrome/regions/PaletteRegion.tsx +3 -4
- package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
- package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
- package/src/chrome/regions/ViewportRegion.less +6 -0
- package/src/chrome/regions/ViewportRegion.tsx +10 -4
- package/src/chrome/types.ts +4 -2
- package/src/config/auto.ts +1 -0
- package/src/config/builder.ts +6 -0
- package/src/config/types.ts +2 -1
- package/src/controls/ControlPanel.test.tsx +37 -3
- package/src/controls/ControlPanel.tsx +12 -3
- package/src/dragdrop/DragDropRuntime.tsx +22 -13
- package/src/dragdrop/DragGhost.tsx +3 -0
- package/src/dragdrop/Palette.tsx +2 -0
- package/src/index.test.ts +5 -0
- package/src/index.ts +1 -1
- package/src/instrument/types.ts +0 -6
- package/src/job/useJob.ts +14 -9
- package/src/lab/Lab.tsx +5 -1
- package/src/lab/LabShell.less +1 -0
- package/src/lab/LabSwitcher.browser.test.tsx +27 -0
- package/src/lab/LabSwitcher.less +2 -0
- package/src/lab/LabZoom.tsx +4 -4
- package/src/lab/Workspace.tsx +48 -52
- package/src/loupe/AGENTS.md +28 -15
- package/src/loupe/CanvasLoupe.tsx +2 -3
- package/src/loupe/DomLoupe.tsx +1 -7
- package/src/loupe/Loupe.less +16 -0
- package/src/loupe/TrialLoupe.tsx +120 -57
- package/src/loupe/index.ts +1 -6
- package/src/loupe/types.test.ts +3 -3
- package/src/loupe/types.ts +24 -27
- package/src/loupe/useLoupe.test.tsx +29 -4
- package/src/loupe/useLoupe.ts +20 -17
- package/src/overview/OverviewMarks.tsx +12 -4
- package/src/overview/TrialOverview.tsx +3 -3
- package/src/passthrough/weasel-ui.test.ts +1 -1
- package/src/passthrough/weasel-ui.ts +1 -1
- package/src/primitives/FloatingPanel.tsx +7 -3
- package/src/primitives/JobProgress.less +1 -0
- package/src/primitives/Readout.test.tsx +2 -2
- package/src/primitives/Split.tsx +69 -41
- package/src/primitives/Toolbar.tsx +3 -3
- package/src/primitives/ZoomControl.less +1 -2
- package/src/specimen/Specimen.tsx +0 -1
- package/src/state/undock.ts +3 -0
- package/src/state/useOpenOnce.ts +20 -16
- package/src/state/view.ts +1 -0
- package/src/surface/index.ts +1 -1
- package/src/surface/useTiledSurface.test.tsx +14 -0
- package/src/surface/useTiledSurface.ts +11 -3
- package/src/trial/Trial.annotations.test.tsx +73 -0
- package/src/trial/Trial.less +0 -16
- package/src/trial/Trial.loupe.test.tsx +28 -11
- package/src/trial/Trial.tsx +74 -62
- package/src/trial/TrialChrome.tsx +6 -3
- package/src/trial/index.ts +2 -0
- package/src/trial/loupeSwitch.ts +15 -0
- package/dist/_dts/LayerList.d-DiuEArKq.d.ts +0 -83
- package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +0 -79
- package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +0 -141
- package/dist/_dts/Select.d-Bensr_MT.d.ts +0 -579
- package/dist/_dts/index-B2Yj5aA0.d.ts +0 -274
- package/dist/chunk-275JRRVD.js.map +0 -1
- package/dist/chunk-4LJSC7MB.js +0 -143
- package/dist/chunk-4LJSC7MB.js.map +0 -1
- package/dist/chunk-7BO7HNGF.js.map +0 -1
- package/dist/chunk-CQLQPQ4P.js.map +0 -1
- package/dist/chunk-FMK7UQ6V.js.map +0 -1
- package/dist/chunk-FZ7YFQN7.js.map +0 -1
- package/dist/chunk-HXXTULDN.js.map +0 -1
- package/dist/chunk-I5DUQ5HM.js.map +0 -1
- package/dist/chunk-IJJUK4FU.js.map +0 -1
- package/dist/chunk-J7OWWTCW.js.map +0 -1
- package/dist/chunk-M7HP3FTK.js +0 -549
- package/dist/chunk-M7HP3FTK.js.map +0 -1
- package/dist/chunk-MIM5R4ZT.js +0 -14972
- package/dist/chunk-MIM5R4ZT.js.map +0 -1
- package/dist/chunk-RWNDDKOH.js.map +0 -1
- package/dist/chunk-T5IBSPAM.js.map +0 -1
- package/dist/chunk-UNAZSLWE.js.map +0 -1
- package/dist/chunk-WPLAANH4.js.map +0 -1
- package/dist/chunk-Y23G2VZL.js.map +0 -1
- package/dist/chunk-ZIFPHIWZ.js.map +0 -1
- package/src/primitives/useRovingTabIndex.test.ts +0 -48
- package/src/primitives/useRovingTabIndex.ts +0 -88
|
@@ -1,68 +1,15 @@
|
|
|
1
|
-
import { CanvasStackContext } from './chunk-
|
|
2
|
-
import { S, y } from './chunk-
|
|
3
|
-
import { useRef, useCallback, useEffect, useState, useContext } from 'react';
|
|
1
|
+
import { CanvasStackContext } from './chunk-ZQIHJXP4.js';
|
|
2
|
+
import { c2, S, y } from './chunk-4KSC7NXL.js';
|
|
4
3
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
4
|
import { useVisibleRaf, normalizeZoom } from '@weasel-js/core';
|
|
5
|
+
import { useState, useRef, useEffect, useContext } from 'react';
|
|
6
6
|
|
|
7
|
-
function nextIndex(current, key, count, orientation = "horizontal") {
|
|
8
|
-
if (count === 0) return null;
|
|
9
|
-
const forward = orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
|
10
|
-
const back = orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
|
11
|
-
if (key === forward) return (current + 1) % count;
|
|
12
|
-
if (key === back) return (current - 1 + count) % count;
|
|
13
|
-
if (key === "Home") return 0;
|
|
14
|
-
if (key === "End") return count - 1;
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
function useRovingTabIndex(orientation = "horizontal") {
|
|
18
|
-
const ref = useRef(null);
|
|
19
|
-
const stop = useRef(0);
|
|
20
|
-
const items = useCallback(
|
|
21
|
-
() => ref.current ? Array.from(
|
|
22
|
-
ref.current.querySelectorAll('button:not([disabled]), [role="button"]')
|
|
23
|
-
) : [],
|
|
24
|
-
[]
|
|
25
|
-
);
|
|
26
|
-
const setTabStop = useCallback(
|
|
27
|
-
(index) => {
|
|
28
|
-
const found = items();
|
|
29
|
-
const at = Math.min(Math.max(index, 0), Math.max(found.length - 1, 0));
|
|
30
|
-
stop.current = at;
|
|
31
|
-
for (const [i, el] of found.entries()) el.tabIndex = i === at ? 0 : -1;
|
|
32
|
-
},
|
|
33
|
-
[items]
|
|
34
|
-
);
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
const resync = () => {
|
|
37
|
-
const focused = items().indexOf(document.activeElement);
|
|
38
|
-
setTabStop(focused === -1 ? stop.current : focused);
|
|
39
|
-
};
|
|
40
|
-
resync();
|
|
41
|
-
if (!ref.current) return;
|
|
42
|
-
const mo = new MutationObserver(resync);
|
|
43
|
-
mo.observe(ref.current, { childList: true, subtree: true, attributeFilter: ["disabled"] });
|
|
44
|
-
return () => mo.disconnect();
|
|
45
|
-
}, [items, setTabStop]);
|
|
46
|
-
const onKeyDown = useCallback(
|
|
47
|
-
(e) => {
|
|
48
|
-
const found = items();
|
|
49
|
-
const current = found.indexOf(document.activeElement);
|
|
50
|
-
const next = nextIndex(current === -1 ? 0 : current, e.key, found.length, orientation);
|
|
51
|
-
if (next === null) return;
|
|
52
|
-
e.preventDefault();
|
|
53
|
-
found[next]?.focus();
|
|
54
|
-
setTabStop(next);
|
|
55
|
-
},
|
|
56
|
-
[items, setTabStop, orientation]
|
|
57
|
-
);
|
|
58
|
-
return { ref, onKeyDown };
|
|
59
|
-
}
|
|
60
7
|
function Toolbar({ children, "aria-label": ariaLabel }) {
|
|
61
|
-
const {
|
|
8
|
+
const { rootRef, onKeyDown } = c2({ orientation: "horizontal" });
|
|
62
9
|
return /* @__PURE__ */ jsx(
|
|
63
10
|
"div",
|
|
64
11
|
{
|
|
65
|
-
ref,
|
|
12
|
+
ref: rootRef,
|
|
66
13
|
className: "lk-toolbar",
|
|
67
14
|
role: "toolbar",
|
|
68
15
|
"aria-label": ariaLabel,
|
|
@@ -265,6 +212,6 @@ function Section({ children, end }) {
|
|
|
265
212
|
}
|
|
266
213
|
StatusBar.Section = Section;
|
|
267
214
|
|
|
268
|
-
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl
|
|
269
|
-
//# sourceMappingURL=chunk-
|
|
270
|
-
//# sourceMappingURL=chunk-
|
|
215
|
+
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl };
|
|
216
|
+
//# sourceMappingURL=chunk-CEGFXTBD.js.map
|
|
217
|
+
//# sourceMappingURL=chunk-CEGFXTBD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/primitives/Toolbar.tsx","../src/primitives/fpsAverage.ts","../src/primitives/FpsMeter.tsx","../src/primitives/ScaleIndicator.tsx","../src/primitives/ZoomControl.tsx","../src/primitives/StatusBar.tsx"],"names":["c","jsx","jsxs"],"mappings":"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","file":"chunk-CEGFXTBD.js","sourcesContent":["import type { MouseEventHandler, ReactNode } from 'react';\nimport { useRovingTabIndex } from '../passthrough/weasel-ui';\n\n/** Props for `<Toolbar>`. */\nexport interface ToolbarProps {\n children: ReactNode;\n /** Names the toolbar for assistive tech. Required by the APG pattern when a\n * view holds more than one. */\n 'aria-label'?: string;\n}\n\n/** A horizontal bar of controls. Fill it with `<Toolbar.Title>`,\n * `<Toolbar.Group>`, `<Toolbar.Button>` and `<Toolbar.Spacer>`. */\nexport function Toolbar({ children, 'aria-label': ariaLabel }: ToolbarProps) {\n const { rootRef, onKeyDown } = useRovingTabIndex<HTMLDivElement>({ orientation: 'horizontal' });\n return (\n <div\n ref={rootRef}\n className=\"lk-toolbar\"\n role=\"toolbar\"\n aria-label={ariaLabel}\n onKeyDown={onKeyDown}\n >\n {children}\n </div>\n );\n}\n\ninterface TitleProps {\n children: ReactNode;\n}\nfunction Title({ children }: TitleProps) {\n return <span className=\"lk-toolbar-title\">{children}</span>;\n}\n\n/** Props for `<Toolbar.Group>`. */\nexport interface ToolbarGroupProps {\n children: ReactNode;\n /** Pushes this group, and everything after it, to the far end. */\n end?: boolean;\n 'aria-label'?: string;\n}\n\n/** Related controls, kept tight and ruled off from their neighbors. Group\n * rather than separate with repeated `<Toolbar.Spacer>`: consecutive spacers\n * share the free space, so every gap collapses to the same slack and the bar\n * reads as one undifferentiated run. */\nfunction Group({ children, end, 'aria-label': ariaLabel }: ToolbarGroupProps) {\n return (\n // biome-ignore lint/a11y/useSemanticElements: a group inside role=\"toolbar\" is the APG pattern; the rule is local and cannot see the parent. <fieldset> means form controls, needs a <legend> to be named, and its UA min-width breaks flex children.\n <div\n className={`lk-toolbar-group${end ? ' lk-toolbar-group--end' : ''}`}\n role=\"group\"\n aria-label={ariaLabel}\n >\n {children}\n </div>\n );\n}\n\n/** Props for `<Toolbar.Button>`. */\nexport interface ToolbarButtonProps {\n children: ReactNode;\n onClick: MouseEventHandler<HTMLButtonElement>;\n disabled?: boolean;\n title?: string;\n /** Required when `children` is an icon with no text of its own. */\n 'aria-label'?: string;\n /** `danger` reddens on hover — for actions that discard work. */\n variant?: 'default' | 'danger';\n /** Square, for a button whose whole content is one glyph. */\n iconOnly?: boolean;\n /** Makes this a toggle: `aria-pressed`, and held down while true. */\n pressed?: boolean;\n}\n\nfunction Button({\n children,\n onClick,\n disabled,\n title,\n 'aria-label': ariaLabel,\n variant = 'default',\n iconOnly,\n pressed,\n}: ToolbarButtonProps) {\n const cls = [\n 'lk-toolbar-button',\n variant === 'danger' && 'lk-toolbar-button--danger',\n iconOnly && 'lk-toolbar-button--icon',\n pressed && 'lk-toolbar-button--pressed',\n ]\n .filter(Boolean)\n .join(' ');\n return (\n <button\n type=\"button\"\n className={cls}\n onClick={onClick}\n disabled={disabled}\n title={title}\n aria-label={ariaLabel ?? title}\n aria-pressed={pressed}\n >\n {children}\n </button>\n );\n}\n\nfunction Spacer() {\n return <span className=\"lk-toolbar-spacer\" aria-hidden=\"true\" />;\n}\n\n/** A label within a toolbar. */\nToolbar.Title = Title;\n/** A ruled-off run of related controls. */\nToolbar.Group = Group;\n/** A button within a toolbar. */\nToolbar.Button = Button;\n/** Flexible space that pushes what follows to the far end of the toolbar. */\nToolbar.Spacer = Spacer;\n","export function rollingAverage(samples: readonly number[]): number {\n if (samples.length === 0) return 0;\n const sum = samples.reduce((acc, n) => acc + n, 0);\n return Math.round(sum / samples.length);\n}\n","import { useVisibleRaf } from '@weasel-js/core';\nimport { useEffect, useRef, useState } from 'react';\nimport { rollingAverage } from './fpsAverage';\n\nconst SAMPLE_WINDOW = 30;\n\n/** A live frame-rate readout, averaged over the last 30 frames. */\nexport function FpsMeter() {\n const [fps, setFps] = useState(0);\n const samplesRef = useRef<number[]>([]);\n const lastTimeRef = useRef<number | null>(null);\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const loop = useVisibleRaf(\n (time) => {\n const last = lastTimeRef.current;\n if (last !== null) {\n const delta = time - last;\n if (delta > 0) {\n const samples = samplesRef.current;\n samples.push(1000 / delta);\n if (samples.length > SAMPLE_WINDOW) samples.shift();\n setFps(rollingAverage(samples));\n }\n }\n lastTimeRef.current = time;\n loop.request();\n },\n {\n target: rootRef,\n // The gap spent suspended is not a frame that took an hour to draw.\n onResume: () => {\n lastTimeRef.current = null;\n },\n },\n );\n\n useEffect(() => {\n loop.request();\n return () => loop.cancel();\n }, [loop]);\n\n return (\n <div className=\"lk-fps-meter\" ref={rootRef}>\n <span className=\"lk-fps-meter-label\">FPS</span>\n {/* The number is its own cell because it is the only part that changes:\n in one box with the label, every digit it gains or loses resizes the\n readout, and the status bar it sits in wraps to a second line and\n back — which in a small trial resizes the window. */}\n <span className=\"lk-fps-meter-value\">{fps}</span>\n </div>\n );\n}\n","import { useContext } from 'react';\nimport { CanvasStackContext } from '../canvas/CanvasStackContext';\n\n/** Props for `<ScaleIndicator>`. */\nexport interface ScaleIndicatorProps {\n /** Current view zoom factor. If omitted, reads from CanvasStackContext. Defaults to 1. */\n zoom?: number;\n /** World pixels per unit at zoom=1. Default: 1. */\n pixelsPerUnit?: number;\n /** Unit label. Default: 'px'. */\n unit?: string;\n /** Target bar width in display pixels. Default: 100. */\n targetWidth?: number;\n}\n\n// Rounds n to a \"nice\" number — 1, 2, 5, 10, 20, 50, ...\nfunction niceNumber(n: number): number {\n if (n <= 0) return 1;\n const exp = Math.floor(Math.log10(n));\n const fraction = n / 10 ** exp;\n let nice: number;\n if (fraction < 1.5) nice = 1;\n else if (fraction < 3.5) nice = 2;\n else if (fraction < 7.5) nice = 5;\n else nice = 10;\n return nice * 10 ** exp;\n}\n\n/** A scale bar: a labeled rule showing how far a round number of world units\n * is at the current zoom. Reads the zoom from the surrounding canvas stack\n * unless one is passed. */\nexport function ScaleIndicator({\n zoom,\n pixelsPerUnit = 1,\n unit = 'px',\n targetWidth = 100,\n}: ScaleIndicatorProps) {\n const ctxValue = useContext(CanvasStackContext);\n const effectiveZoom = zoom ?? ctxValue?.view.zoom ?? 1;\n const effectivePxPerUnit = pixelsPerUnit * effectiveZoom;\n const targetUnits = targetWidth / effectivePxPerUnit;\n const niceUnits = niceNumber(targetUnits);\n const barWidth = niceUnits * effectivePxPerUnit;\n return (\n <div className=\"lk-scale-indicator\" role=\"img\" aria-label={`Scale: ${niceUnits} ${unit}`}>\n <div className=\"lk-scale-indicator-bar\" style={{ width: `${barWidth}px` }} />\n <span className=\"lk-scale-indicator-label\">\n {niceUnits} {unit}\n </span>\n </div>\n );\n}\n","import { normalizeZoom } from '@weasel-js/core';\nimport { NumberField, Slider } from '../passthrough/weasel-ui';\n\n/** Props for `<ZoomControl>`. */\nexport interface ZoomControlProps {\n /** Current zoom as a scale factor: 1 is actual size. */\n zoom: number;\n /** Fired continuously while the slider drags. */\n onZoomChange: (zoom: number) => void;\n /** Fired when a drag settles or the field is committed. Defaults to\n * `onZoomChange`. */\n onZoomCommit?: (zoom: number) => void;\n /** Smallest selectable zoom. Defaults to 0.1 (10%). */\n min?: number;\n /** Largest selectable zoom. Defaults to 8 (800%). */\n max?: number;\n className?: string;\n}\n\n// Zoom is perceptually geometric — halving is as big a step as doubling — so\n// the slider runs on log2 and 100% lands mid-track for a symmetric range.\nconst toTrack = (zoom: number): number => Math.log2(zoom);\nconst fromTrack = (v: number): number => 2 ** v;\n\nconst clamp = (v: number, lo: number, hi: number): number => Math.max(lo, Math.min(hi, v));\n\n/** Zoom as a log-scaled slider with an editable percentage beside it. Pair it\n * with zoom-in / zoom-out buttons in a `<Toolbar.Group>`; this component owns\n * only the continuous part. */\nexport function ZoomControl({\n zoom,\n onZoomChange,\n onZoomCommit,\n min: minProp = 0.1,\n max: maxProp = 8,\n className,\n}: ZoomControlProps) {\n const min = normalizeZoom(minProp);\n const max = normalizeZoom(maxProp);\n const commit = onZoomCommit ?? onZoomChange;\n const emit = (track: number, done: boolean): void => {\n const next = clamp(fromTrack(track), min, max);\n (done ? commit : onZoomChange)(next);\n };\n\n return (\n <div className={`lk-zoom${className ? ` ${className}` : ''}`}>\n <Slider\n className=\"lk-zoom__slider\"\n ariaLabel=\"Zoom\"\n density=\"slim\"\n min={toTrack(min)}\n max={toTrack(max)}\n // Detents at the octaves plus actual size, so 25/50/100/200/400% are\n // reachable by drag rather than only by typing.\n stops={[-2, -1, 0, 1, 2]}\n thumbs={[{ value: clamp(toTrack(zoom), toTrack(min), toTrack(max)) }]}\n onInput={(next) => emit(next[0].value, false)}\n onChange={(next) => emit(next[0].value, true)}\n readoutPlacement=\"none\"\n />\n {/* `style: 'percent'` formats a fraction, so the field carries the scale\n factor itself and renders 0.5 as \"50%\". */}\n <NumberField\n className=\"lk-zoom__field\"\n width=\"fit\"\n aria-label=\"Zoom\"\n value={zoom}\n minValue={min}\n maxValue={max}\n step={0.01}\n hideSteppers\n ghost\n formatOptions={{ style: 'percent', maximumFractionDigits: 0 }}\n onChange={(next) => {\n if (!Number.isFinite(next)) return;\n commit(clamp(next, min, max));\n }}\n />\n </div>\n );\n}\n","import type { ReactNode } from 'react';\n\n/** Props for `<StatusBar>`. */\nexport interface StatusBarProps {\n children: ReactNode;\n}\n\n/** A footer strip for readouts. Fill it with `<StatusBar.Section>`. */\nexport function StatusBar({ children }: StatusBarProps) {\n return <div className=\"lk-status-bar\">{children}</div>;\n}\n\n/** Props for `<StatusBar.Section>`. */\nexport interface StatusBarSectionProps {\n children: ReactNode;\n /** Pushes this section, and everything after it, to the far end. */\n end?: boolean;\n}\nfunction Section({ children, end }: StatusBarSectionProps) {\n return (\n <span className={`lk-status-bar-section${end ? ' lk-status-bar-section--end' : ''}`}>\n {children}\n </span>\n );\n}\n\n/** One readout within a status bar. */\nStatusBar.Section = Section;\n"]}
|
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { identity, multiply } from './chunk-XVUKDSYV.js';
|
|
2
|
+
import { resolveScreenLength, scriptMetricsFor, boundsOfPath, getMarker, PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, resolveAlign, resolveRunFace, resolveTextStyle, parseColor, rgbaToHex, getPaintKind, resolveMarkerSize } from '@weasel-js/core';
|
|
2
3
|
import { tileGeometry } from '@weasel-js/core/patterns-builtin';
|
|
3
4
|
|
|
4
|
-
// ../svg/dist/index.js
|
|
5
|
-
|
|
6
|
-
// ../geom/dist/index.js
|
|
7
|
-
function identity() {
|
|
8
|
-
return [1, 0, 0, 1, 0, 0];
|
|
9
|
-
}
|
|
10
|
-
function multiply(m, n) {
|
|
11
|
-
return [
|
|
12
|
-
m[0] * n[0] + m[2] * n[1],
|
|
13
|
-
m[1] * n[0] + m[3] * n[1],
|
|
14
|
-
m[0] * n[2] + m[2] * n[3],
|
|
15
|
-
m[1] * n[2] + m[3] * n[3],
|
|
16
|
-
m[0] * n[4] + m[2] * n[5] + m[4],
|
|
17
|
-
m[1] * n[4] + m[3] * n[5] + m[5]
|
|
18
|
-
];
|
|
19
|
-
}
|
|
20
5
|
var IDENTITY_MATRIX = identity();
|
|
21
6
|
function isIdentity(m, eps = 1e-9) {
|
|
22
7
|
return Math.abs(m[0] - 1) < eps && Math.abs(m[1]) < eps && Math.abs(m[2]) < eps && Math.abs(m[3] - 1) < eps && Math.abs(m[4]) < eps && Math.abs(m[5]) < eps;
|
|
@@ -31,10 +16,201 @@ function trimNumber(n) {
|
|
|
31
16
|
if (Number.isInteger(r)) return String(r);
|
|
32
17
|
return String(r);
|
|
33
18
|
}
|
|
34
|
-
function anchorOffset(style,
|
|
19
|
+
function anchorOffset(style, width2) {
|
|
35
20
|
const edge = resolveAlign(style?.align ?? "left", style?.direction ?? "ltr");
|
|
36
|
-
return edge === "center" ?
|
|
21
|
+
return edge === "center" ? width2 / 2 : edge === "right" ? width2 : 0;
|
|
22
|
+
}
|
|
23
|
+
function parsePaintAttr(raw) {
|
|
24
|
+
if (raw == null) return null;
|
|
25
|
+
const s = raw.trim();
|
|
26
|
+
if (s === "") return null;
|
|
27
|
+
if (s === "none") return { kind: "none" };
|
|
28
|
+
if (s.toLowerCase() === "currentcolor") {
|
|
29
|
+
return { kind: "solid", color: "#000000", alpha: 1 };
|
|
30
|
+
}
|
|
31
|
+
const urlMatch = /^url\(\s*#([^)\s]+)\s*\)(.*)$/.exec(s);
|
|
32
|
+
if (urlMatch) {
|
|
33
|
+
const out = { kind: "ref", id: urlMatch[1] };
|
|
34
|
+
const rest = urlMatch[2].trim();
|
|
35
|
+
if (rest !== "" && rest !== "none") {
|
|
36
|
+
const fallback = parsePaintAttr(rest);
|
|
37
|
+
if (fallback?.kind === "solid") {
|
|
38
|
+
out.fallback = { color: fallback.color, alpha: fallback.alpha };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const [r, g, b, a] = parseColor(s);
|
|
45
|
+
return { kind: "solid", color: rgbaToHex([r, g, b]), alpha: a };
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var TEXT_TRANSFORMS = /* @__PURE__ */ new Set(["none", "uppercase", "lowercase", "capitalize"]);
|
|
51
|
+
var DIMENSION = /^([+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)([a-z%]*)$/i;
|
|
52
|
+
function dimension(v) {
|
|
53
|
+
const m = DIMENSION.exec(v);
|
|
54
|
+
return m ? { n: Number(m[1]), unit: m[2].toLowerCase() } : void 0;
|
|
55
|
+
}
|
|
56
|
+
var clamp01 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
|
|
57
|
+
var length = (native, coercedAs) => (v, warn, prop) => {
|
|
58
|
+
const d = dimension(v);
|
|
59
|
+
if (!d) return void 0;
|
|
60
|
+
if (d.unit && !native.includes(d.unit)) {
|
|
61
|
+
warn(`${prop} "${v}" uses unit "${d.unit}", which is not converted; treated as ${d.n} ${coercedAs}`);
|
|
62
|
+
}
|
|
63
|
+
return d.n;
|
|
64
|
+
};
|
|
65
|
+
var worldLength = length(["px"], "world units");
|
|
66
|
+
var keyword2 = (...words) => (v) => words.includes(v) ? v : void 0;
|
|
67
|
+
var isCurrentColor = (v) => v.toLowerCase() === "currentcolor";
|
|
68
|
+
function readPaint(v) {
|
|
69
|
+
if (v === "context-fill") return { kind: "context", of: "fill" };
|
|
70
|
+
if (v === "context-stroke") return { kind: "context", of: "stroke" };
|
|
71
|
+
return parsePaintAttr(v) ?? void 0;
|
|
72
|
+
}
|
|
73
|
+
function readRatio(v) {
|
|
74
|
+
const d = dimension(v);
|
|
75
|
+
if (!d || d.unit !== "" && d.unit !== "%") return void 0;
|
|
76
|
+
return clamp01(d.unit === "%" ? d.n / 100 : d.n);
|
|
77
|
+
}
|
|
78
|
+
function readSolidColor(v, warn, prop) {
|
|
79
|
+
const parsed = parsePaintAttr(v);
|
|
80
|
+
if (parsed?.kind !== "solid") return void 0;
|
|
81
|
+
if (isCurrentColor(v)) warn(`${prop}="${v}" is read as black; it is not resolved against color`);
|
|
82
|
+
return parsed;
|
|
83
|
+
}
|
|
84
|
+
function readMarkerRef(v) {
|
|
85
|
+
if (v === "none") return null;
|
|
86
|
+
return /^url\(\s*#([^)\s]+)\s*\)$/.exec(v)?.[1];
|
|
87
|
+
}
|
|
88
|
+
function readLinecap(v, warn) {
|
|
89
|
+
const cap = keyword2("butt", "round", "square")(v);
|
|
90
|
+
if (!cap) warn(`unsupported stroke-linecap: ${v}`);
|
|
91
|
+
return cap;
|
|
92
|
+
}
|
|
93
|
+
function readLinejoin(v, warn) {
|
|
94
|
+
const join = keyword2("miter", "round", "bevel")(v);
|
|
95
|
+
if (join) return join;
|
|
96
|
+
if (v === "arcs" || v === "miter-clip") {
|
|
97
|
+
warn(`stroke-linejoin "${v}" not supported; falling back to miter`);
|
|
98
|
+
return "miter";
|
|
99
|
+
}
|
|
100
|
+
warn(`unsupported stroke-linejoin: ${v}`);
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
function readDashArray(v, warn) {
|
|
104
|
+
if (v === "none" || v === "") return null;
|
|
105
|
+
const nums = [];
|
|
106
|
+
for (const t of v.split(/[\s,]+/).filter(Boolean)) {
|
|
107
|
+
const d = dimension(t);
|
|
108
|
+
if (!d || d.unit !== "" && d.unit !== "px" || d.n < 0) {
|
|
109
|
+
warn(`unrecognized stroke-dasharray: ${v}`);
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
nums.push(d.n);
|
|
113
|
+
}
|
|
114
|
+
return nums.length % 2 === 1 ? [...nums, ...nums] : nums;
|
|
115
|
+
}
|
|
116
|
+
function readMiterLimit(v, warn) {
|
|
117
|
+
const d = dimension(v);
|
|
118
|
+
if (d && d.unit === "" && d.n >= 1) return d.n;
|
|
119
|
+
warn(`unrecognized stroke-miterlimit: ${v}`);
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
function readColor(v) {
|
|
123
|
+
return isCurrentColor(v) || parsePaintAttr(v)?.kind === "solid" ? v : void 0;
|
|
37
124
|
}
|
|
125
|
+
function readFontSize(v, warn, prop) {
|
|
126
|
+
const d = dimension(v);
|
|
127
|
+
if (d?.unit === "%") return { fontScale: d.n / 100 };
|
|
128
|
+
const n = worldLength(v, warn, prop);
|
|
129
|
+
return n == null ? void 0 : { fontSize: n };
|
|
130
|
+
}
|
|
131
|
+
function readFontWeight(v) {
|
|
132
|
+
if (v === "normal" || v === "bold" || v === "bolder") return v;
|
|
133
|
+
const d = dimension(v);
|
|
134
|
+
return d && d.unit === "" && d.n >= 1 && d.n <= 1e3 ? d.n : void 0;
|
|
135
|
+
}
|
|
136
|
+
function readFontStyle(v, warn) {
|
|
137
|
+
if (v === "normal" || v === "italic") return v;
|
|
138
|
+
if (v === "oblique") {
|
|
139
|
+
warn('font-style "oblique" is read as italic');
|
|
140
|
+
return "italic";
|
|
141
|
+
}
|
|
142
|
+
return void 0;
|
|
143
|
+
}
|
|
144
|
+
function readLetterSpacing(v, warn, prop) {
|
|
145
|
+
return v === "normal" ? null : worldLength(v, warn, prop);
|
|
146
|
+
}
|
|
147
|
+
function readDecoration(v, warn) {
|
|
148
|
+
const out = {};
|
|
149
|
+
for (const t of v.toLowerCase().split(/\s+/)) {
|
|
150
|
+
if (t === "underline") out.underline = true;
|
|
151
|
+
else if (t === "line-through") out.strikethrough = true;
|
|
152
|
+
else if (t === "overline") out.overline = true;
|
|
153
|
+
else if (t !== "none" && t !== "blink") warn(`text-decoration "${v}": "${t}" is not modeled; dropped`);
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
function readFontVariant(v, warn) {
|
|
158
|
+
let out;
|
|
159
|
+
for (const t of v.toLowerCase().split(/\s+/)) {
|
|
160
|
+
if (t === "small-caps" || t === "normal") out = t;
|
|
161
|
+
else if (t) warn(`font-variant "${v}": "${t}" is not modeled; dropped`);
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
function readTextTransform(v) {
|
|
166
|
+
const t = v.toLowerCase();
|
|
167
|
+
return TEXT_TRANSFORMS.has(t) ? t : void 0;
|
|
168
|
+
}
|
|
169
|
+
var emLength = length(["em"], "em");
|
|
170
|
+
function readBaselineShift(v, warn, prop) {
|
|
171
|
+
const k = v.toLowerCase();
|
|
172
|
+
if (k === "super" || k === "sub") return { script: k };
|
|
173
|
+
if (k === "baseline") return {};
|
|
174
|
+
const d = dimension(v);
|
|
175
|
+
if (d?.unit === "%") return d.n === 0 ? {} : { baselineShift: d.n / 100 };
|
|
176
|
+
const n = emLength(v, warn, prop);
|
|
177
|
+
if (n == null) return void 0;
|
|
178
|
+
return n === 0 ? {} : { baselineShift: n };
|
|
179
|
+
}
|
|
180
|
+
var inherited = (read) => ({ inherits: true, read });
|
|
181
|
+
var own = (read) => ({ inherits: false, read });
|
|
182
|
+
var PROPERTIES = {
|
|
183
|
+
"fill": inherited(readPaint),
|
|
184
|
+
"fill-opacity": inherited(readRatio),
|
|
185
|
+
"fill-rule": inherited(keyword2("nonzero", "evenodd")),
|
|
186
|
+
"stroke": inherited(readPaint),
|
|
187
|
+
"stroke-width": inherited(worldLength),
|
|
188
|
+
"stroke-opacity": inherited(readRatio),
|
|
189
|
+
"stroke-linecap": inherited(readLinecap),
|
|
190
|
+
"stroke-linejoin": inherited(readLinejoin),
|
|
191
|
+
"stroke-dasharray": inherited(readDashArray),
|
|
192
|
+
"stroke-miterlimit": inherited(readMiterLimit),
|
|
193
|
+
"marker-start": inherited(readMarkerRef),
|
|
194
|
+
"marker-mid": inherited(readMarkerRef),
|
|
195
|
+
"marker-end": inherited(readMarkerRef),
|
|
196
|
+
"color": inherited(readColor),
|
|
197
|
+
"font-size": inherited(readFontSize),
|
|
198
|
+
"font-family": inherited((v) => v.length > 0 ? v : void 0),
|
|
199
|
+
"font-weight": inherited(readFontWeight),
|
|
200
|
+
"font-style": inherited(readFontStyle),
|
|
201
|
+
"text-anchor": inherited(keyword2("start", "middle", "end")),
|
|
202
|
+
"letter-spacing": inherited(readLetterSpacing),
|
|
203
|
+
"text-decoration": inherited(readDecoration),
|
|
204
|
+
"direction": inherited(keyword2("ltr", "rtl")),
|
|
205
|
+
"text-transform": inherited(readTextTransform),
|
|
206
|
+
"font-variant": inherited(readFontVariant),
|
|
207
|
+
"opacity": own(readRatio),
|
|
208
|
+
"stop-color": own(readSolidColor),
|
|
209
|
+
"stop-opacity": own(readRatio),
|
|
210
|
+
"baseline-shift": own(readBaselineShift),
|
|
211
|
+
"vector-effect": own(keyword2("none", "non-scaling-stroke"))
|
|
212
|
+
};
|
|
213
|
+
Object.keys(PROPERTIES).filter((p) => PROPERTIES[p].inherits);
|
|
38
214
|
function patternSpecOf(paint) {
|
|
39
215
|
return "tile" in paint.pattern ? paint.pattern : null;
|
|
40
216
|
}
|
|
@@ -53,7 +229,11 @@ function patternXml(id, paint, onWarn) {
|
|
|
53
229
|
`width="${trimNumber(geometry.size)}"`,
|
|
54
230
|
`height="${trimNumber(geometry.size)}"`
|
|
55
231
|
];
|
|
56
|
-
|
|
232
|
+
const [a, b, c, d] = paint.transform ?? [1, 0, 0, 1];
|
|
233
|
+
const placement = formatMatrix([a, b, c, d, origin.x, origin.y]);
|
|
234
|
+
if (paint.transform && !isIdentity([a, b, c, d, 0, 0]) && placement) {
|
|
235
|
+
attrs.push(`patternTransform="${placement}"`);
|
|
236
|
+
} else if (origin.x !== 0 || origin.y !== 0) {
|
|
57
237
|
attrs.push(`x="${trimNumber(origin.x)}"`, `y="${trimNumber(origin.y)}"`);
|
|
58
238
|
}
|
|
59
239
|
attrs.push(`data-weasel-tile="${escapeAttr(JSON.stringify(spec))}"`);
|
|
@@ -90,8 +270,8 @@ function escapeAttr(s) {
|
|
|
90
270
|
}
|
|
91
271
|
function serializePathD(path) {
|
|
92
272
|
if (path.kind === "rect") {
|
|
93
|
-
const { x, y, width, height } = path;
|
|
94
|
-
return `M${trimNumber(x)} ${trimNumber(y)}h${trimNumber(
|
|
273
|
+
const { x, y, width: width2, height: height2 } = path;
|
|
274
|
+
return `M${trimNumber(x)} ${trimNumber(y)}h${trimNumber(width2)}v${trimNumber(height2)}h${trimNumber(-width2)}Z`;
|
|
95
275
|
}
|
|
96
276
|
const cmds = path.commands;
|
|
97
277
|
const xs = path.coords;
|
|
@@ -176,6 +356,10 @@ var PaintServerRegistry = class {
|
|
|
176
356
|
if (hasNativeSvgForm(paint)) return `url(#${id})`;
|
|
177
357
|
return `url(#${id}) ${paintFallback(paint)}`;
|
|
178
358
|
}
|
|
359
|
+
/** The paint kind of each registered paint, once, in first-use order. */
|
|
360
|
+
paintKinds() {
|
|
361
|
+
return [...new Set(this.order.map((paint) => paint.fill ?? "solid"))];
|
|
362
|
+
}
|
|
179
363
|
/** Whether any registered paint serializes outside SVG's own vocabulary, so
|
|
180
364
|
* the root has to declare {@link WEASEL_NS}. */
|
|
181
365
|
usesPrivateNamespace() {
|
|
@@ -258,9 +442,10 @@ function paintServerXml(id, paint, onWarn) {
|
|
|
258
442
|
if (paint.fill === "pattern") return patternXml(id, paint, onWarn);
|
|
259
443
|
const builtin = gradientXml(id, paint);
|
|
260
444
|
if (builtin) return builtin;
|
|
261
|
-
const
|
|
445
|
+
const kind = getPaintKind(paint.fill);
|
|
446
|
+
const custom = kind?.toSvg?.(id, paint);
|
|
262
447
|
if (custom) return custom;
|
|
263
|
-
onWarn?.(`${paint.fill} fill has no vector form \u2014 omitted from <defs>`);
|
|
448
|
+
onWarn?.(kind ? `${paint.fill} fill has no vector form \u2014 omitted from <defs>` : `${paint.fill} fill is not registered \u2014 omitted from <defs>; a kind loaded on demand needs \`await warmSvg(nodes)\` before a synchronous export`);
|
|
264
449
|
return "";
|
|
265
450
|
}
|
|
266
451
|
function gradientUnitsAttr(units) {
|
|
@@ -508,19 +693,19 @@ function svgPaintOpacity(paint) {
|
|
|
508
693
|
function opacityAttr(name, v) {
|
|
509
694
|
return v != null && v !== 1 ? [`${name}="${trimNumber(v)}"`] : [];
|
|
510
695
|
}
|
|
511
|
-
function strokeWidthAttrs(
|
|
512
|
-
if (typeof
|
|
513
|
-
return [`stroke-width="${trimNumber(
|
|
696
|
+
function strokeWidthAttrs(width2) {
|
|
697
|
+
if (typeof width2 === "number") return [`stroke-width="${trimNumber(width2)}"`];
|
|
698
|
+
return [`stroke-width="${trimNumber(width2.px)}"`, 'vector-effect="non-scaling-stroke"'];
|
|
514
699
|
}
|
|
515
700
|
function coreStrokeAttrs(stroke, registry, warn) {
|
|
516
701
|
const paint = stroke?.paint;
|
|
517
702
|
if (!stroke || !paint) return [];
|
|
518
|
-
const
|
|
519
|
-
if (!((typeof
|
|
703
|
+
const width2 = stroke.width ?? 1;
|
|
704
|
+
if (!((typeof width2 === "object" ? width2.px : width2) > 0)) return [];
|
|
520
705
|
warnStrokeAlign(stroke.align, warn);
|
|
521
706
|
const attrs = [`stroke="${"color" in paint ? paint.color : registry.ref(paint)}"`];
|
|
522
707
|
attrs.push(...opacityAttr("stroke-opacity", paint.opacity));
|
|
523
|
-
attrs.push(...strokeWidthAttrs(
|
|
708
|
+
attrs.push(...strokeWidthAttrs(width2));
|
|
524
709
|
if (stroke.cap) attrs.push(`stroke-linecap="${stroke.cap}"`);
|
|
525
710
|
if (stroke.join) attrs.push(`stroke-linejoin="${stroke.join}"`);
|
|
526
711
|
if (stroke.dash && stroke.dash.length > 0) {
|
|
@@ -621,12 +806,14 @@ function textXml(node, registry, namespaces, warn) {
|
|
|
621
806
|
if (style?.fontFamily) attrs.push(`font-family="${escapeAttr2(style.fontFamily)}"`);
|
|
622
807
|
if (style?.fontWeight != null) attrs.push(`font-weight="${String(style.fontWeight)}"`);
|
|
623
808
|
if (style?.fontStyle && style.fontStyle !== "normal") attrs.push(`font-style="${style.fontStyle}"`);
|
|
809
|
+
if (style?.fontVariantCaps === "small-caps") attrs.push('font-variant="small-caps"');
|
|
624
810
|
const direction = style?.direction ?? "ltr";
|
|
625
811
|
if (direction === "rtl") attrs.push('direction="rtl"');
|
|
626
812
|
if (style?.align != null || direction === "rtl") {
|
|
627
813
|
const align = style?.align ?? "left";
|
|
628
|
-
const anchor = align === "center" ? "middle" : align === "start" ? "start" : align === "end" ? "end" : align === "left" === (direction === "ltr") ? "start" : "end";
|
|
814
|
+
const anchor = align === "center" ? "middle" : align === "start" || align === "justify" ? "start" : align === "end" ? "end" : align === "left" === (direction === "ltr") ? "start" : "end";
|
|
629
815
|
if (anchor !== "start") attrs.push(`text-anchor="${anchor}"`);
|
|
816
|
+
if (align === "justify") attrs.push('data-weasel-align="justify"');
|
|
630
817
|
}
|
|
631
818
|
if (style?.letterSpacing != null && style.letterSpacing !== 0) {
|
|
632
819
|
attrs.push(`letter-spacing="${trimNumber(resolveScreenLength(style.letterSpacing, 1))}"`);
|
|
@@ -661,17 +848,25 @@ function textXml(node, registry, namespaces, warn) {
|
|
|
661
848
|
const deg = node.rotation * 180 / Math.PI;
|
|
662
849
|
attrs.push(`transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`);
|
|
663
850
|
}
|
|
664
|
-
const body = node.runs && node.runs.length > 0 ? node.runs.map((r) => runXml(r, registry, warn)).join("") : escapeText(node.text);
|
|
851
|
+
const body = node.runs && node.runs.length > 0 ? node.runs.map((r) => runXml(r, style, registry, warn)).join("") : escapeText(node.text);
|
|
665
852
|
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
666
853
|
const metaEls = metaElementsXml(node.meta, namespaces);
|
|
667
854
|
return `<text ${attrs.join(" ")}${metaAttrs}>${body}${metaEls}</text>`;
|
|
668
855
|
}
|
|
669
|
-
function
|
|
856
|
+
function scriptSizeFace(run, style) {
|
|
857
|
+
if (run.script == null || run.baselineShift == null) return void 0;
|
|
858
|
+
const face = resolveRunFace(run, resolveTextStyle(style));
|
|
859
|
+
return { family: face.fontFamily, weight: face.fontWeight, style: face.fontStyle };
|
|
860
|
+
}
|
|
861
|
+
function runXml(run, style, registry, warn) {
|
|
670
862
|
const attrs = [];
|
|
671
|
-
if (run.
|
|
863
|
+
if (run.fontWeight != null) attrs.push(`font-weight="${run.fontWeight}"`);
|
|
864
|
+
else if (run.bold) attrs.push(`font-weight="700"`);
|
|
672
865
|
if (run.italic) attrs.push(`font-style="italic"`);
|
|
866
|
+
if (run.fontVariantCaps) attrs.push(`font-variant="${run.fontVariantCaps}"`);
|
|
673
867
|
if (run.fontFamily) attrs.push(`font-family="${escapeAttr2(run.fontFamily)}"`);
|
|
674
|
-
const
|
|
868
|
+
const face = scriptSizeFace(run, style);
|
|
869
|
+
const presetScale = face && run.script ? scriptMetricsFor(face.family, face.weight, face.style)[run.script].size : void 0;
|
|
675
870
|
const scale = run.fontScale ?? presetScale;
|
|
676
871
|
if (run.fontSize != null) attrs.push(`font-size="${trimNumber(resolveScreenLength(run.fontSize, 1))}"`);
|
|
677
872
|
else if (scale != null) attrs.push(`font-size="${trimNumber(scale * 100)}%"`);
|
|
@@ -724,5 +919,5 @@ function pathBounds(path) {
|
|
|
724
919
|
}
|
|
725
920
|
|
|
726
921
|
export { nativeSvgKind, nativeSvgSpace, serializeSvg, tilePreviewCssUrl };
|
|
727
|
-
//# sourceMappingURL=chunk-
|
|
728
|
-
//# sourceMappingURL=chunk-
|
|
922
|
+
//# sourceMappingURL=chunk-E23Q6A3Y.js.map
|
|
923
|
+
//# sourceMappingURL=chunk-E23Q6A3Y.js.map
|