@tldraw/editor 5.1.0 → 5.2.0-canary.083e81484bc9
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 +1 -1
- package/dist-cjs/index.d.ts +10 -46
- package/dist-cjs/index.js +3 -4
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +4 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultLoadingScreen.js +2 -2
- package/dist-cjs/lib/components/default-components/DefaultLoadingScreen.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeErrorFallback.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultSvgDefs.js +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSvgDefs.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +51 -15
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js +2 -2
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +8 -58
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +1 -1
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +79 -0
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +7 -0
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/editor/types/event-types.js +0 -2
- package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +3 -1
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +2 -2
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +5 -3
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +10 -46
- package/dist-esm/index.mjs +2 -6
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +4 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultLoadingScreen.mjs +2 -2
- package/dist-esm/lib/components/default-components/DefaultLoadingScreen.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultShapeErrorFallback.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultSvgDefs.mjs +2 -2
- package/dist-esm/lib/components/default-components/DefaultSvgDefs.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +51 -15
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +2 -2
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +8 -58
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +59 -0
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +7 -0
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/editor/types/event-types.mjs +0 -2
- package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +3 -1
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +2 -2
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +5 -3
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +2 -0
- package/package.json +8 -8
- package/src/index.ts +1 -5
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +4 -1
- package/src/lib/components/default-components/DefaultLoadingScreen.tsx +1 -1
- package/src/lib/components/default-components/DefaultShapeErrorFallback.tsx +4 -3
- package/src/lib/components/default-components/DefaultSvgDefs.tsx +1 -1
- package/src/lib/editor/Editor.ts +83 -23
- package/src/lib/editor/derivations/bindingsIndex.ts +1 -1
- package/src/lib/editor/derivations/parentsToChildren.ts +1 -1
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +1 -1
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +54 -74
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +15 -65
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +14 -0
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +6 -3
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +4 -4
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +1 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +13 -9
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +16 -14
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +86 -0
- package/src/lib/editor/tools/StateNode.ts +0 -2
- package/src/lib/editor/types/event-types.ts +2 -6
- package/src/lib/license/LicenseProvider.tsx +3 -1
- package/src/lib/primitives/utils.ts +1 -1
- package/src/lib/utils/dom.ts +5 -3
- package/src/version.ts +3 -3
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +0 -7
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +0 -141
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +0 -7
- package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/editor/types/event-types.ts"],
|
|
4
|
-
"sourcesContent": ["import { TLHandle, TLShape, VecModel } from '@tldraw/tlschema'\nimport { VecLike } from '../../primitives/Vec'\nimport { TLOverlay } from '../overlays/OverlayUtil'\nimport { TLSelectionHandle } from './selection-types'\n\n/** @public */\nexport type UiEventType = 'pointer' | 'click' | 'keyboard' | 'wheel' | 'pinch' | 'zoom'\n\n/** @public */\nexport type TLPointerEventTarget =\n\t| { target: 'canvas'; shape?: undefined }\n\t| { target: 'selection'; handle?: TLSelectionHandle; shape?: undefined }\n\t| { target: 'shape'; shape: TLShape }\n\t| { target: 'handle'; shape: TLShape; handle: TLHandle }\n\t| { target: 'overlay'; overlay: TLOverlay; shape?: undefined }\n\n/** @public */\nexport type TLPointerEventName =\n\t| 'pointer_down'\n\t| 'pointer_move'\n\t| 'long_press'\n\t| 'pointer_up'\n\t| 'right_click'\n\t| 'middle_click'\n\n/** @public */\nexport type TLCLickEventName = 'double_click'
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { TLHandle, TLShape, VecModel } from '@tldraw/tlschema'\nimport { VecLike } from '../../primitives/Vec'\nimport { TLOverlay } from '../overlays/OverlayUtil'\nimport { TLSelectionHandle } from './selection-types'\n\n/** @public */\nexport type UiEventType = 'pointer' | 'click' | 'keyboard' | 'wheel' | 'pinch' | 'zoom'\n\n/** @public */\nexport type TLPointerEventTarget =\n\t| { target: 'canvas'; shape?: undefined }\n\t| { target: 'selection'; handle?: TLSelectionHandle; shape?: undefined }\n\t| { target: 'shape'; shape: TLShape }\n\t| { target: 'handle'; shape: TLShape; handle: TLHandle }\n\t| { target: 'overlay'; overlay: TLOverlay; shape?: undefined }\n\n/** @public */\nexport type TLPointerEventName =\n\t| 'pointer_down'\n\t| 'pointer_move'\n\t| 'long_press'\n\t| 'pointer_up'\n\t| 'right_click'\n\t| 'middle_click'\n\n/** @public */\nexport type TLCLickEventName = 'double_click'\n\n/** @public */\nexport type TLPinchEventName = 'pinch_start' | 'pinch' | 'pinch_end'\n\n/** @public */\nexport type TLKeyboardEventName = 'key_down' | 'key_up' | 'key_repeat'\n\n/** @public */\nexport type TLEventName =\n\t| TLPointerEventName\n\t| TLCLickEventName\n\t| TLPinchEventName\n\t| TLKeyboardEventName\n\t| 'wheel'\n\t| 'cancel'\n\t| 'complete'\n\t| 'interrupt'\n\t| 'tick'\n\n/** @public */\nexport interface TLBaseEventInfo {\n\ttype: UiEventType\n\tshiftKey: boolean\n\taltKey: boolean\n\tctrlKey: boolean\n\tmetaKey: boolean\n\taccelKey: boolean\n}\n\n/** @public */\nexport type TLPointerEventInfo = TLBaseEventInfo & {\n\ttype: 'pointer'\n\tname: TLPointerEventName\n\t// The pointer position in client space, i.e. clientX / clientY\n\tpoint: VecLike\n\tpointerId: number\n\tbutton: number\n\tisPen: boolean\n} & TLPointerEventTarget\n\n/** @public */\nexport type TLClickEventInfo = TLBaseEventInfo & {\n\ttype: 'click'\n\tname: TLCLickEventName\n\tpoint: VecLike\n\tpointerId: number\n\tbutton: number\n\tphase: 'down' | 'up' | 'settle-down' | 'settle-up'\n} & TLPointerEventTarget\n\n/** @public */\nexport type TLKeyboardEventInfo = TLBaseEventInfo & {\n\ttype: 'keyboard'\n\tname: TLKeyboardEventName\n\tkey: string\n\tcode: string\n}\n\n/** @public */\nexport type TLPinchEventInfo = TLBaseEventInfo & {\n\ttype: 'pinch'\n\tname: TLPinchEventName\n\tpoint: VecModel\n\tdelta: VecModel\n}\n\n/** @public */\nexport type TLWheelEventInfo = TLBaseEventInfo & {\n\ttype: 'wheel'\n\tname: 'wheel'\n\tdelta: VecModel\n\tpoint: VecModel\n}\n\n/** @public */\nexport interface TLCancelEventInfo {\n\ttype: 'misc'\n\tname: 'cancel'\n}\n/** @public */\nexport interface TLCompleteEventInfo {\n\ttype: 'misc'\n\tname: 'complete'\n}\n/** @public */\nexport interface TLInterruptEventInfo {\n\ttype: 'misc'\n\tname: 'interrupt'\n}\n/** @public */\nexport interface TLTickEventInfo {\n\ttype: 'misc'\n\tname: 'tick'\n\telapsed: number\n}\n\n/** @public */\nexport type TLEventInfo =\n\t| TLPointerEventInfo\n\t| TLClickEventInfo\n\t| TLKeyboardEventInfo\n\t| TLPinchEventInfo\n\t| TLWheelEventInfo\n\t| TLCancelEventInfo\n\t| TLCompleteEventInfo\n\t| TLInterruptEventInfo\n\t| TLTickEventInfo\n\n/** @public */\nexport type TLPointerEvent = (info: TLPointerEventInfo) => void\n/** @public */\nexport type TLClickEvent = (info: TLClickEventInfo) => void\n/** @public */\nexport type TLKeyboardEvent = (info: TLKeyboardEventInfo) => void\n/** @public */\nexport type TLPinchEvent = (info: TLPinchEventInfo) => void\n/** @public */\nexport type TLWheelEvent = (info: TLWheelEventInfo) => void\n/** @public */\nexport type TLCancelEvent = (info: TLCancelEventInfo) => void\n/** @public */\nexport type TLCompleteEvent = (info: TLCompleteEventInfo) => void\n/** @public */\nexport type TLInterruptEvent = (info: TLInterruptEventInfo) => void\n/** @public */\nexport type TLTickEvent = (info: TLTickEventInfo) => void\n\n/** @public */\nexport type UiEvent =\n\t| TLPointerEvent\n\t| TLClickEvent\n\t| TLKeyboardEvent\n\t| TLPinchEvent\n\t| TLCancelEvent\n\t| TLCompleteEvent\n\n/** @public */\nexport type TLEnterEventHandler = (info: any, from: string) => void\n/** @public */\nexport type TLExitEventHandler = (info: any, to: string) => void\n\n/** @public */\nexport interface TLEventHandlers {\n\tonPointerDown: TLPointerEvent\n\tonPointerMove: TLPointerEvent\n\tonLongPress: TLPointerEvent\n\tonRightClick: TLPointerEvent\n\tonDoubleClick: TLClickEvent\n\tonMiddleClick: TLPointerEvent\n\tonPointerUp: TLPointerEvent\n\tonKeyDown: TLKeyboardEvent\n\tonKeyUp: TLKeyboardEvent\n\tonKeyRepeat: TLKeyboardEvent\n\tonWheel: TLWheelEvent\n\tonCancel: TLCancelEvent\n\tonComplete: TLCompleteEvent\n\tonInterrupt: TLInterruptEvent\n\tonTick: TLTickEvent\n}\n\n/** @public */\nexport const EVENT_NAME_MAP: Record<\n\tExclude<TLEventName, TLPinchEventName>,\n\tkeyof TLEventHandlers\n> = {\n\twheel: 'onWheel',\n\tpointer_down: 'onPointerDown',\n\tpointer_move: 'onPointerMove',\n\tlong_press: 'onLongPress',\n\tpointer_up: 'onPointerUp',\n\tright_click: 'onRightClick',\n\tmiddle_click: 'onMiddleClick',\n\tkey_down: 'onKeyDown',\n\tkey_up: 'onKeyUp',\n\tkey_repeat: 'onKeyRepeat',\n\tcancel: 'onCancel',\n\tcomplete: 'onComplete',\n\tinterrupt: 'onInterrupt',\n\tdouble_click: 'onDoubleClick',\n\ttick: 'onTick',\n}\n"],
|
|
5
|
+
"mappings": "AA4LO,MAAM,iBAGT;AAAA,EACH,OAAO;AAAA,EACP,cAAc;AAAA,EACd,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,MAAM;AACP;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,7 +3,9 @@ import { useValue } from "@tldraw/state-react";
|
|
|
3
3
|
import { createContext, useContext, useEffect, useState } from "react";
|
|
4
4
|
import { LicenseManager } from "./LicenseManager.mjs";
|
|
5
5
|
const LicenseContext = createContext({});
|
|
6
|
-
|
|
6
|
+
function useLicenseContext() {
|
|
7
|
+
return useContext(LicenseContext);
|
|
8
|
+
}
|
|
7
9
|
function shouldHideEditorAfterDelay(licenseState) {
|
|
8
10
|
return licenseState === "expired" || licenseState === "unlicensed-production";
|
|
9
11
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/license/LicenseProvider.tsx"],
|
|
4
|
-
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { createContext, ReactNode, useContext, useEffect, useState } from 'react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport const LicenseContext = createContext({} as LicenseManager)\n\n/** @internal */\nexport
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { useValue } from '@tldraw/state-react'\nimport { createContext, ReactNode, useContext, useEffect, useState } from 'react'\nimport { LicenseManager } from './LicenseManager'\n\n/** @internal */\nexport const LicenseContext = createContext({} as LicenseManager)\n\n/** @internal */\nexport function useLicenseContext() {\n\treturn useContext(LicenseContext)\n}\n\nfunction shouldHideEditorAfterDelay(licenseState: string): boolean {\n\treturn licenseState === 'expired' || licenseState === 'unlicensed-production'\n}\n\n/** @internal */\nexport const LICENSE_TIMEOUT = 5000\n\n/** @internal */\nexport function LicenseProvider({\n\tlicenseKey = getLicenseKeyFromEnv() ?? undefined,\n\tchildren,\n}: {\n\tlicenseKey?: string\n\tchildren: ReactNode\n}) {\n\tconst [licenseManager] = useState(() => new LicenseManager(licenseKey))\n\tconst licenseState = useValue(licenseManager.state)\n\tconst [showEditor, setShowEditor] = useState(true)\n\n\t// When license expires or no license in production, show for 5 seconds then hide\n\tuseEffect(() => {\n\t\tif (shouldHideEditorAfterDelay(licenseState) && showEditor) {\n\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tsetShowEditor(false)\n\t\t\t}, LICENSE_TIMEOUT)\n\n\t\t\treturn () => clearTimeout(timer)\n\t\t}\n\t}, [licenseState, showEditor])\n\n\t// If license is expired or no license in production and 5 seconds have passed, don't render anything (blank screen)\n\tif (shouldHideEditorAfterDelay(licenseState) && !showEditor) {\n\t\treturn <LicenseGate />\n\t}\n\n\treturn <LicenseContext.Provider value={licenseManager}>{children}</LicenseContext.Provider>\n}\n\n// Renders as a hidden div that can be detected by tests\nfunction LicenseGate() {\n\treturn <div data-testid=\"tl-license-expired\" style={{ display: 'none' }} />\n}\n\nlet envLicenseKey: string | undefined | null = undefined\nfunction getLicenseKeyFromEnv() {\n\tif (envLicenseKey !== undefined) {\n\t\treturn envLicenseKey\n\t}\n\t// it's important here that we write out the full process.env.WHATEVER expression instead of\n\t// doing something like process.env[someVariable]. This is because most bundlers do something\n\t// like a find-replace inject environment variables, and so won't pick up on dynamic ones. It\n\t// also means we can't do checks like `process.env && process.env.WHATEVER`, which is why we use\n\t// the `getEnv` try/catch approach.\n\n\t// framework-specific prefixes borrowed from the ones vercel uses, but trimmed down to just the\n\t// react-y ones: https://vercel.com/docs/environment-variables/framework-environment-variables\n\tenvLicenseKey =\n\t\tgetEnv(() => process.env.TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.REACT_APP_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.GATSBY_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.VITE_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => process.env.PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.NEXT_PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.REACT_APP_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.GATSBY_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.VITE_TLDRAW_LICENSE_KEY) ||\n\t\tgetEnv(() => (import.meta as any).env.PUBLIC_TLDRAW_LICENSE_KEY) ||\n\t\tnull\n\n\treturn envLicenseKey\n}\n\nfunction getEnv(cb: () => string | undefined) {\n\ttry {\n\t\treturn cb()\n\t} catch {\n\t\treturn undefined\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AA6CS;AA7CT,SAAS,gBAAgB;AACzB,SAAS,eAA0B,YAAY,WAAW,gBAAgB;AAC1E,SAAS,sBAAsB;AAGxB,MAAM,iBAAiB,cAAc,CAAC,CAAmB;AAGzD,SAAS,oBAAoB;AACnC,SAAO,WAAW,cAAc;AACjC;AAEA,SAAS,2BAA2B,cAA+B;AAClE,SAAO,iBAAiB,aAAa,iBAAiB;AACvD;AAGO,MAAM,kBAAkB;AAGxB,SAAS,gBAAgB;AAAA,EAC/B,aAAa,qBAAqB,KAAK;AAAA,EACvC;AACD,GAGG;AACF,QAAM,CAAC,cAAc,IAAI,SAAS,MAAM,IAAI,eAAe,UAAU,CAAC;AACtE,QAAM,eAAe,SAAS,eAAe,KAAK;AAClD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,IAAI;AAGjD,YAAU,MAAM;AACf,QAAI,2BAA2B,YAAY,KAAK,YAAY;AAE3D,YAAM,QAAQ,WAAW,MAAM;AAC9B,sBAAc,KAAK;AAAA,MACpB,GAAG,eAAe;AAElB,aAAO,MAAM,aAAa,KAAK;AAAA,IAChC;AAAA,EACD,GAAG,CAAC,cAAc,UAAU,CAAC;AAG7B,MAAI,2BAA2B,YAAY,KAAK,CAAC,YAAY;AAC5D,WAAO,oBAAC,eAAY;AAAA,EACrB;AAEA,SAAO,oBAAC,eAAe,UAAf,EAAwB,OAAO,gBAAiB,UAAS;AAClE;AAGA,SAAS,cAAc;AACtB,SAAO,oBAAC,SAAI,eAAY,sBAAqB,OAAO,EAAE,SAAS,OAAO,GAAG;AAC1E;AAEA,IAAI,gBAA2C;AAC/C,SAAS,uBAAuB;AAC/B,MAAI,kBAAkB,QAAW;AAChC,WAAO;AAAA,EACR;AASA,kBACC,OAAO,MAAM,QAAQ,IAAI,kBAAkB,KAC3C,OAAO,MAAM,QAAQ,IAAI,8BAA8B,KACvD,OAAO,MAAM,QAAQ,IAAI,4BAA4B,KACrD,OAAO,MAAM,QAAQ,IAAI,yBAAyB,KAClD,OAAO,MAAM,QAAQ,IAAI,uBAAuB,KAChD,OAAO,MAAM,QAAQ,IAAI,yBAAyB,KAClD,OAAO,MAAO,YAAoB,IAAI,kBAAkB,KACxD,OAAO,MAAO,YAAoB,IAAI,8BAA8B,KACpE,OAAO,MAAO,YAAoB,IAAI,4BAA4B,KAClE,OAAO,MAAO,YAAoB,IAAI,yBAAyB,KAC/D,OAAO,MAAO,YAAoB,IAAI,uBAAuB,KAC7D,OAAO,MAAO,YAAoB,IAAI,yBAAyB,KAC/D;AAED,SAAO;AACR;AAEA,SAAS,OAAO,IAA8B;AAC7C,MAAI;AACH,WAAO,GAAG;AAAA,EACX,QAAQ;AACP,WAAO;AAAA,EACR;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -142,9 +142,9 @@ function toDomPrecision(v) {
|
|
|
142
142
|
function toFixed(v) {
|
|
143
143
|
return Math.round(v * 100) / 100;
|
|
144
144
|
}
|
|
145
|
-
|
|
145
|
+
function isSafeFloat(n) {
|
|
146
146
|
return Math.abs(n) < Number.MAX_SAFE_INTEGER;
|
|
147
|
-
}
|
|
147
|
+
}
|
|
148
148
|
function angleDistance(fromAngle, toAngle, direction) {
|
|
149
149
|
const dist = direction < 0 ? clockwiseAngleDist(fromAngle, toAngle) : counterClockwiseAngleDist(fromAngle, toAngle);
|
|
150
150
|
return dist;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/primitives/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { Vec, VecLike } from './Vec'\n\n/** @public */\nexport function precise(A: VecLike) {\n\treturn `${toDomPrecision(A.x)},${toDomPrecision(A.y)} `\n}\n\n/** @public */\nexport function average(A: VecLike, B: VecLike) {\n\treturn `${toDomPrecision((A.x + B.x) / 2)},${toDomPrecision((A.y + B.y) / 2)} `\n}\n\n/** @public */\nexport const PI = Math.PI\n/** @public */\nexport const HALF_PI = PI / 2\n/** @public */\nexport const PI2 = PI * 2\n/** @public */\nexport const SIN = Math.sin\n\n/**\n * Clamp a value into a range.\n *\n * @example\n *\n * ```ts\n * const A = clamp(0, 1) // 1\n * ```\n *\n * @param n - The number to clamp.\n * @param min - The minimum value.\n * @public\n */\nexport function clamp(n: number, min: number): number\n/**\n * Clamp a value into a range.\n *\n * @example\n *\n * ```ts\n * const A = clamp(0, 1, 10) // 1\n * const B = clamp(11, 1, 10) // 10\n * const C = clamp(5, 1, 10) // 5\n * ```\n *\n * @param n - The number to clamp.\n * @param min - The minimum value.\n * @param max - The maximum value.\n * @public\n */\nexport function clamp(n: number, min: number, max: number): number\nexport function clamp(n: number, min: number, max?: number): number {\n\treturn Math.max(min, typeof max !== 'undefined' ? Math.min(n, max) : n)\n}\n\n/**\n * Get a number to a precision.\n *\n * @param n - The number.\n * @param precision - The precision.\n * @public\n */\nexport function toPrecision(n: number, precision = 10000000000) {\n\tif (!n) return 0\n\treturn Math.round(n * precision) / precision\n}\n\n/**\n * Whether two numbers numbers a and b are approximately equal.\n *\n * @param a - The first point.\n * @param b - The second point.\n * @public\n */\nexport function approximately(a: number, b: number, precision = 0.000001) {\n\treturn Math.abs(a - b) <= precision\n}\n\n/**\n * Whether a number is approximately less than or equal to another number.\n *\n * @param a - The first number.\n * @param b - The second number.\n * @public\n */\nexport function approximatelyLte(a: number, b: number, precision = 0.000001) {\n\treturn a < b || approximately(a, b, precision)\n}\n\n/**\n * Find the approximate perimeter of an ellipse.\n *\n * @param rx - The ellipse's x radius.\n * @param ry - The ellipse's y radius.\n * @public\n */\nexport function perimeterOfEllipse(rx: number, ry: number): number {\n\tconst h = Math.pow(rx - ry, 2) / Math.pow(rx + ry, 2)\n\treturn PI * (rx + ry) * (1 + (3 * h) / (10 + Math.sqrt(4 - 3 * h)))\n}\n\n/**\n * @param a - Any angle in radians\n * @returns A number between 0 and 2 * PI\n * @public\n */\nexport function canonicalizeRotation(a: number) {\n\ta = a % PI2\n\tif (a < 0) {\n\t\ta = a + PI2\n\t} else if (a === 0) {\n\t\t// prevent negative zero\n\t\ta = 0\n\t}\n\treturn a\n}\n\n/**\n * Get the clockwise angle distance between two angles.\n *\n * @param a0 - The first angle.\n * @param a1 - The second angle.\n * @public\n */\nexport function clockwiseAngleDist(a0: number, a1: number): number {\n\ta0 = canonicalizeRotation(a0)\n\ta1 = canonicalizeRotation(a1)\n\tif (a0 > a1) {\n\t\ta1 += PI2\n\t}\n\treturn a1 - a0\n}\n\n/**\n * Get the counter-clockwise angle distance between two angles.\n *\n * @param a0 - The first angle.\n * @param a1 - The second angle.\n * @public\n */\nexport function counterClockwiseAngleDist(a0: number, a1: number): number {\n\treturn PI2 - clockwiseAngleDist(a0, a1)\n}\n\n/**\n * Get the short angle distance between two angles.\n *\n * @param a0 - The first angle.\n * @param a1 - The second angle.\n * @public\n */\nexport function shortAngleDist(a0: number, a1: number): number {\n\tconst da = (a1 - a0) % PI2\n\treturn ((2 * da) % PI2) - da\n}\n\n/**\n * Clamp radians within 0 and 2PI\n *\n * @param r - The radian value.\n * @public\n */\nexport function clampRadians(r: number): number {\n\treturn (PI2 + r) % PI2\n}\n\n/**\n * Clamp rotation to even segments.\n *\n * @param r - The rotation in radians.\n * @param segments - The number of segments.\n * @public\n */\nexport function snapAngle(r: number, segments: number): number {\n\tconst seg = PI2 / segments\n\tlet ang = (Math.floor((clampRadians(r) + seg / 2) / seg) * seg) % PI2\n\tif (ang < PI) ang += PI2\n\tif (ang > PI) ang -= PI2\n\treturn ang\n}\n\n/**\n * Checks whether two angles are approximately at right-angles or parallel to each other\n *\n * @param a - Angle a (radians)\n * @param b - Angle b (radians)\n * @returns True iff the angles are approximately at right-angles or parallel to each other\n * @public\n */\nexport function areAnglesCompatible(a: number, b: number) {\n\treturn a === b || approximately((a % (Math.PI / 2)) - (b % (Math.PI / 2)), 0)\n}\n\n/**\n * Convert degrees to radians.\n *\n * @param d - The degree in degrees.\n * @public\n */\nexport function degreesToRadians(d: number): number {\n\treturn (d * PI) / 180\n}\n\n/**\n * Convert radians to degrees.\n *\n * @param r - The degree in radians.\n * @public\n */\nexport function radiansToDegrees(r: number): number {\n\treturn (r * 180) / PI\n}\n\n/**\n * Get a point on the perimeter of a circle.\n *\n * @param center - The center of the circle.\n * @param r - The radius of the circle.\n * @param a - The angle in radians.\n * @public\n */\nexport function getPointOnCircle(center: VecLike, r: number, a: number) {\n\treturn new Vec(center.x, center.y).add(Vec.FromAngle(a, r))\n}\n\n/** @public */\nexport function getPolygonVertices(width: number, height: number, sides: number) {\n\tconst cx = width / 2\n\tconst cy = height / 2\n\tconst pointsOnPerimeter: Vec[] = []\n\n\tlet minX = Infinity\n\tlet maxX = -Infinity\n\tlet minY = Infinity\n\tlet maxY = -Infinity\n\tfor (let i = 0; i < sides; i++) {\n\t\tconst step = PI2 / sides\n\t\tconst t = -HALF_PI + i * step\n\t\tconst x = cx + cx * Math.cos(t)\n\t\tconst y = cy + cy * Math.sin(t)\n\t\tif (x < minX) minX = x\n\t\tif (y < minY) minY = y\n\t\tif (x > maxX) maxX = x\n\t\tif (y > maxY) maxY = y\n\t\tpointsOnPerimeter.push(new Vec(x, y))\n\t}\n\n\t// Bounds of calculated points\n\tconst w = maxX - minX\n\tconst h = maxY - minY\n\n\t// Difference between input bounds and calculated bounds\n\tconst dx = width - w\n\tconst dy = height - h\n\n\t// If there's a difference, scale the points to the input bounds\n\tif (dx !== 0 || dy !== 0) {\n\t\tfor (let i = 0; i < pointsOnPerimeter.length; i++) {\n\t\t\tconst pt = pointsOnPerimeter[i]\n\t\t\tpt.x = ((pt.x - minX) / w) * width\n\t\t\tpt.y = ((pt.y - minY) / h) * height\n\t\t}\n\t}\n\n\treturn pointsOnPerimeter\n}\n\n/**\n * @param a0 - The start point in the A range\n * @param a1 - The end point in the A range\n * @param b0 - The start point in the B range\n * @param b1 - The end point in the B range\n * @returns True if the ranges overlap\n * @public\n */\nexport function rangesOverlap(a0: number, a1: number, b0: number, b1: number): boolean {\n\treturn a0 < b1 && b0 < a1\n}\n\n/**\n * Finds the intersection of two ranges.\n *\n * @param a0 - The start point in the A range\n * @param a1 - The end point in the A range\n * @param b0 - The start point in the B range\n * @param b1 - The end point in the B range\n * @returns The intersection of the ranges, or null if no intersection\n * @public\n */\nexport function rangeIntersection(\n\ta0: number,\n\ta1: number,\n\tb0: number,\n\tb1: number\n): [number, number] | null {\n\tconst min = Math.max(a0, b0)\n\tconst max = Math.min(a1, b1)\n\tif (min <= max) {\n\t\treturn [min, max]\n\t}\n\treturn null\n}\n\n/** Helper for point in polygon */\nfunction cross(x: VecLike, y: VecLike, z: VecLike): number {\n\treturn (y.x - x.x) * (z.y - x.y) - (z.x - x.x) * (y.y - x.y)\n}\n\n/**\n * Get whether a point is inside of a polygon.\n *\n * ```ts\n * const result = pointInPolygon(myPoint, myPoints)\n * ```\n *\n * @public\n */\nexport function pointInPolygon(A: VecLike, points: VecLike[]): boolean {\n\t// Uses winding number algorithm. Previously also had a per-edge check:\n\t// if (Vec.Dist(A, a) + Vec.Dist(A, b) === Vec.Dist(a, b)) return true\n\t// which tested if A lies exactly on edge (a, b). Removed because it cost 3 sqrts per vertex\n\t// and exact float equality with sqrt results essentially never fires in practice.\n\tlet windingNumber = 0\n\tlet a: VecLike\n\tlet b: VecLike\n\n\tfor (let i = 0; i < points.length; i++) {\n\t\ta = points[i]\n\t\tif (a.x === A.x && a.y === A.y) return true\n\n\t\tb = points[(i + 1) % points.length]\n\n\t\tif (a.y <= A.y) {\n\t\t\tif (b.y > A.y && cross(a, b, A) > 0) {\n\t\t\t\twindingNumber += 1\n\t\t\t}\n\t\t} else if (b.y <= A.y && cross(a, b, A) < 0) {\n\t\t\twindingNumber -= 1\n\t\t}\n\t}\n\n\treturn windingNumber !== 0\n}\n\n/**\n * The DOM likes values to be fixed to 3 decimal places\n *\n * @public\n */\nexport function toDomPrecision(v: number) {\n\treturn Math.round(v * 1e4) / 1e4\n}\n\n/**\n * @public\n */\nexport function toFixed(v: number) {\n\treturn Math.round(v * 1e2) / 1e2\n}\n\n/**\n * Check if a float is safe to use. ie: Not too big or small.\n * @public\n */\nexport const isSafeFloat = (n: number) => {\n\treturn Math.abs(n) < Number.MAX_SAFE_INTEGER\n}\n\n/**\n * Get the angle of a point on an arc.\n * @param fromAngle - The angle from center to arc's start point (A) on the circle\n * @param toAngle - The angle from center to arc's end point (B) on the circle\n * @param direction - The direction of the arc (1 = counter-clockwise, -1 = clockwise)\n * @returns The distance in radians between the two angles according to the direction\n * @public\n */\nexport function angleDistance(fromAngle: number, toAngle: number, direction: number) {\n\tconst dist =\n\t\tdirection < 0\n\t\t\t? clockwiseAngleDist(fromAngle, toAngle)\n\t\t\t: counterClockwiseAngleDist(fromAngle, toAngle)\n\treturn dist\n}\n\n/**\n * Returns the t value of the point on the arc.\n *\n * @param mAB - The measure of the arc from A to B, negative if counter-clockwise\n * @param A - The angle from center to arc's start point (A) on the circle\n * @param B - The angle from center to arc's end point (B) on the circle\n * @param P - The angle on the circle (P) to find the t value for\n *\n * @returns The t value of the point on the arc, with 0 being the start and 1 being the end\n *\n * @public\n */\nexport function getPointInArcT(mAB: number, A: number, B: number, P: number): number {\n\tlet mAP: number\n\tif (Math.abs(mAB) > PI) {\n\t\tmAP = shortAngleDist(A, P)\n\t\tconst mPB = shortAngleDist(P, B)\n\t\tif (Math.abs(mAP) < Math.abs(mPB)) {\n\t\t\treturn mAP / mAB\n\t\t} else {\n\t\t\treturn (mAB - mPB) / mAB\n\t\t}\n\t} else {\n\t\tmAP = shortAngleDist(A, P)\n\t\tconst t = mAP / mAB\n\n\t\t// If the arc is something like -2.8 to 2.2, then we'll get a weird bug\n\t\t// where the measurement to the center is negative but measure to points\n\t\t// near the end are positive\n\t\tif (Math.sign(mAP) !== Math.sign(mAB)) {\n\t\t\treturn Math.abs(t) > 0.5 ? 1 : 0\n\t\t}\n\n\t\treturn t\n\t}\n}\n\n/**\n * Get the measure of an arc.\n *\n * @param A - The angle from center to arc's start point (A) on the circle\n * @param B - The angle from center to arc's end point (B) on the circle\n * @param sweepFlag - 1 if the arc is clockwise, 0 if counter-clockwise\n * @param largeArcFlag - 1 if the arc is greater than 180 degrees, 0 if less than 180 degrees\n *\n * @returns The measure of the arc, negative if counter-clockwise\n *\n * @public\n */\nexport function getArcMeasure(A: number, B: number, sweepFlag: number, largeArcFlag: number) {\n\tconst m = ((2 * ((B - A) % PI2)) % PI2) - ((B - A) % PI2)\n\tif (!largeArcFlag) return m\n\treturn (PI2 - Math.abs(m)) * (sweepFlag ? 1 : -1)\n}\n\n/**\n * Get the center of a circle from three points.\n *\n * @param a - The first point\n * @param b - The second point\n * @param c - The third point\n *\n * @returns The center of the circle or null if the points are collinear\n *\n * @public\n */\nexport function centerOfCircleFromThreePoints(a: VecLike, b: VecLike, c: VecLike) {\n\tconst u = -2 * (a.x * (b.y - c.y) - a.y * (b.x - c.x) + b.x * c.y - c.x * b.y)\n\tconst x =\n\t\t((a.x * a.x + a.y * a.y) * (c.y - b.y) +\n\t\t\t(b.x * b.x + b.y * b.y) * (a.y - c.y) +\n\t\t\t(c.x * c.x + c.y * c.y) * (b.y - a.y)) /\n\t\tu\n\tconst y =\n\t\t((a.x * a.x + a.y * a.y) * (b.x - c.x) +\n\t\t\t(b.x * b.x + b.y * b.y) * (c.x - a.x) +\n\t\t\t(c.x * c.x + c.y * c.y) * (a.x - b.x)) /\n\t\tu\n\tif (!Number.isFinite(x) || !Number.isFinite(y)) {\n\t\treturn null\n\t}\n\treturn new Vec(x, y)\n}\n\n/** @public */\nexport function getPointsOnArc(\n\tstartPoint: VecLike,\n\tendPoint: VecLike,\n\tcenter: VecLike | null,\n\tradius: number,\n\tnumPoints: number\n): Vec[] {\n\tif (center === null) {\n\t\treturn [Vec.From(startPoint), Vec.From(endPoint)]\n\t}\n\tconst results: Vec[] = []\n\tconst startAngle = Vec.Angle(center, startPoint)\n\tconst endAngle = Vec.Angle(center, endPoint)\n\tconst l = clockwiseAngleDist(startAngle, endAngle)\n\tfor (let i = 0; i < numPoints; i++) {\n\t\tconst t = i / (numPoints - 1)\n\t\tconst angle = startAngle + l * t\n\t\tconst point = getPointOnCircle(center, radius, angle)\n\t\tresults.push(point)\n\t}\n\treturn results\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { Vec, VecLike } from './Vec'\n\n/** @public */\nexport function precise(A: VecLike) {\n\treturn `${toDomPrecision(A.x)},${toDomPrecision(A.y)} `\n}\n\n/** @public */\nexport function average(A: VecLike, B: VecLike) {\n\treturn `${toDomPrecision((A.x + B.x) / 2)},${toDomPrecision((A.y + B.y) / 2)} `\n}\n\n/** @public */\nexport const PI = Math.PI\n/** @public */\nexport const HALF_PI = PI / 2\n/** @public */\nexport const PI2 = PI * 2\n/** @public */\nexport const SIN = Math.sin\n\n/**\n * Clamp a value into a range.\n *\n * @example\n *\n * ```ts\n * const A = clamp(0, 1) // 1\n * ```\n *\n * @param n - The number to clamp.\n * @param min - The minimum value.\n * @public\n */\nexport function clamp(n: number, min: number): number\n/**\n * Clamp a value into a range.\n *\n * @example\n *\n * ```ts\n * const A = clamp(0, 1, 10) // 1\n * const B = clamp(11, 1, 10) // 10\n * const C = clamp(5, 1, 10) // 5\n * ```\n *\n * @param n - The number to clamp.\n * @param min - The minimum value.\n * @param max - The maximum value.\n * @public\n */\nexport function clamp(n: number, min: number, max: number): number\nexport function clamp(n: number, min: number, max?: number): number {\n\treturn Math.max(min, typeof max !== 'undefined' ? Math.min(n, max) : n)\n}\n\n/**\n * Get a number to a precision.\n *\n * @param n - The number.\n * @param precision - The precision.\n * @public\n */\nexport function toPrecision(n: number, precision = 10000000000) {\n\tif (!n) return 0\n\treturn Math.round(n * precision) / precision\n}\n\n/**\n * Whether two numbers numbers a and b are approximately equal.\n *\n * @param a - The first point.\n * @param b - The second point.\n * @public\n */\nexport function approximately(a: number, b: number, precision = 0.000001) {\n\treturn Math.abs(a - b) <= precision\n}\n\n/**\n * Whether a number is approximately less than or equal to another number.\n *\n * @param a - The first number.\n * @param b - The second number.\n * @public\n */\nexport function approximatelyLte(a: number, b: number, precision = 0.000001) {\n\treturn a < b || approximately(a, b, precision)\n}\n\n/**\n * Find the approximate perimeter of an ellipse.\n *\n * @param rx - The ellipse's x radius.\n * @param ry - The ellipse's y radius.\n * @public\n */\nexport function perimeterOfEllipse(rx: number, ry: number): number {\n\tconst h = Math.pow(rx - ry, 2) / Math.pow(rx + ry, 2)\n\treturn PI * (rx + ry) * (1 + (3 * h) / (10 + Math.sqrt(4 - 3 * h)))\n}\n\n/**\n * @param a - Any angle in radians\n * @returns A number between 0 and 2 * PI\n * @public\n */\nexport function canonicalizeRotation(a: number) {\n\ta = a % PI2\n\tif (a < 0) {\n\t\ta = a + PI2\n\t} else if (a === 0) {\n\t\t// prevent negative zero\n\t\ta = 0\n\t}\n\treturn a\n}\n\n/**\n * Get the clockwise angle distance between two angles.\n *\n * @param a0 - The first angle.\n * @param a1 - The second angle.\n * @public\n */\nexport function clockwiseAngleDist(a0: number, a1: number): number {\n\ta0 = canonicalizeRotation(a0)\n\ta1 = canonicalizeRotation(a1)\n\tif (a0 > a1) {\n\t\ta1 += PI2\n\t}\n\treturn a1 - a0\n}\n\n/**\n * Get the counter-clockwise angle distance between two angles.\n *\n * @param a0 - The first angle.\n * @param a1 - The second angle.\n * @public\n */\nexport function counterClockwiseAngleDist(a0: number, a1: number): number {\n\treturn PI2 - clockwiseAngleDist(a0, a1)\n}\n\n/**\n * Get the short angle distance between two angles.\n *\n * @param a0 - The first angle.\n * @param a1 - The second angle.\n * @public\n */\nexport function shortAngleDist(a0: number, a1: number): number {\n\tconst da = (a1 - a0) % PI2\n\treturn ((2 * da) % PI2) - da\n}\n\n/**\n * Clamp radians within 0 and 2PI\n *\n * @param r - The radian value.\n * @public\n */\nexport function clampRadians(r: number): number {\n\treturn (PI2 + r) % PI2\n}\n\n/**\n * Clamp rotation to even segments.\n *\n * @param r - The rotation in radians.\n * @param segments - The number of segments.\n * @public\n */\nexport function snapAngle(r: number, segments: number): number {\n\tconst seg = PI2 / segments\n\tlet ang = (Math.floor((clampRadians(r) + seg / 2) / seg) * seg) % PI2\n\tif (ang < PI) ang += PI2\n\tif (ang > PI) ang -= PI2\n\treturn ang\n}\n\n/**\n * Checks whether two angles are approximately at right-angles or parallel to each other\n *\n * @param a - Angle a (radians)\n * @param b - Angle b (radians)\n * @returns True iff the angles are approximately at right-angles or parallel to each other\n * @public\n */\nexport function areAnglesCompatible(a: number, b: number) {\n\treturn a === b || approximately((a % (Math.PI / 2)) - (b % (Math.PI / 2)), 0)\n}\n\n/**\n * Convert degrees to radians.\n *\n * @param d - The degree in degrees.\n * @public\n */\nexport function degreesToRadians(d: number): number {\n\treturn (d * PI) / 180\n}\n\n/**\n * Convert radians to degrees.\n *\n * @param r - The degree in radians.\n * @public\n */\nexport function radiansToDegrees(r: number): number {\n\treturn (r * 180) / PI\n}\n\n/**\n * Get a point on the perimeter of a circle.\n *\n * @param center - The center of the circle.\n * @param r - The radius of the circle.\n * @param a - The angle in radians.\n * @public\n */\nexport function getPointOnCircle(center: VecLike, r: number, a: number) {\n\treturn new Vec(center.x, center.y).add(Vec.FromAngle(a, r))\n}\n\n/** @public */\nexport function getPolygonVertices(width: number, height: number, sides: number) {\n\tconst cx = width / 2\n\tconst cy = height / 2\n\tconst pointsOnPerimeter: Vec[] = []\n\n\tlet minX = Infinity\n\tlet maxX = -Infinity\n\tlet minY = Infinity\n\tlet maxY = -Infinity\n\tfor (let i = 0; i < sides; i++) {\n\t\tconst step = PI2 / sides\n\t\tconst t = -HALF_PI + i * step\n\t\tconst x = cx + cx * Math.cos(t)\n\t\tconst y = cy + cy * Math.sin(t)\n\t\tif (x < minX) minX = x\n\t\tif (y < minY) minY = y\n\t\tif (x > maxX) maxX = x\n\t\tif (y > maxY) maxY = y\n\t\tpointsOnPerimeter.push(new Vec(x, y))\n\t}\n\n\t// Bounds of calculated points\n\tconst w = maxX - minX\n\tconst h = maxY - minY\n\n\t// Difference between input bounds and calculated bounds\n\tconst dx = width - w\n\tconst dy = height - h\n\n\t// If there's a difference, scale the points to the input bounds\n\tif (dx !== 0 || dy !== 0) {\n\t\tfor (let i = 0; i < pointsOnPerimeter.length; i++) {\n\t\t\tconst pt = pointsOnPerimeter[i]\n\t\t\tpt.x = ((pt.x - minX) / w) * width\n\t\t\tpt.y = ((pt.y - minY) / h) * height\n\t\t}\n\t}\n\n\treturn pointsOnPerimeter\n}\n\n/**\n * @param a0 - The start point in the A range\n * @param a1 - The end point in the A range\n * @param b0 - The start point in the B range\n * @param b1 - The end point in the B range\n * @returns True if the ranges overlap\n * @public\n */\nexport function rangesOverlap(a0: number, a1: number, b0: number, b1: number): boolean {\n\treturn a0 < b1 && b0 < a1\n}\n\n/**\n * Finds the intersection of two ranges.\n *\n * @param a0 - The start point in the A range\n * @param a1 - The end point in the A range\n * @param b0 - The start point in the B range\n * @param b1 - The end point in the B range\n * @returns The intersection of the ranges, or null if no intersection\n * @public\n */\nexport function rangeIntersection(\n\ta0: number,\n\ta1: number,\n\tb0: number,\n\tb1: number\n): [number, number] | null {\n\tconst min = Math.max(a0, b0)\n\tconst max = Math.min(a1, b1)\n\tif (min <= max) {\n\t\treturn [min, max]\n\t}\n\treturn null\n}\n\n/** Helper for point in polygon */\nfunction cross(x: VecLike, y: VecLike, z: VecLike): number {\n\treturn (y.x - x.x) * (z.y - x.y) - (z.x - x.x) * (y.y - x.y)\n}\n\n/**\n * Get whether a point is inside of a polygon.\n *\n * ```ts\n * const result = pointInPolygon(myPoint, myPoints)\n * ```\n *\n * @public\n */\nexport function pointInPolygon(A: VecLike, points: VecLike[]): boolean {\n\t// Uses winding number algorithm. Previously also had a per-edge check:\n\t// if (Vec.Dist(A, a) + Vec.Dist(A, b) === Vec.Dist(a, b)) return true\n\t// which tested if A lies exactly on edge (a, b). Removed because it cost 3 sqrts per vertex\n\t// and exact float equality with sqrt results essentially never fires in practice.\n\tlet windingNumber = 0\n\tlet a: VecLike\n\tlet b: VecLike\n\n\tfor (let i = 0; i < points.length; i++) {\n\t\ta = points[i]\n\t\tif (a.x === A.x && a.y === A.y) return true\n\n\t\tb = points[(i + 1) % points.length]\n\n\t\tif (a.y <= A.y) {\n\t\t\tif (b.y > A.y && cross(a, b, A) > 0) {\n\t\t\t\twindingNumber += 1\n\t\t\t}\n\t\t} else if (b.y <= A.y && cross(a, b, A) < 0) {\n\t\t\twindingNumber -= 1\n\t\t}\n\t}\n\n\treturn windingNumber !== 0\n}\n\n/**\n * The DOM likes values to be fixed to 3 decimal places\n *\n * @public\n */\nexport function toDomPrecision(v: number) {\n\treturn Math.round(v * 1e4) / 1e4\n}\n\n/**\n * @public\n */\nexport function toFixed(v: number) {\n\treturn Math.round(v * 1e2) / 1e2\n}\n\n/**\n * Check if a float is safe to use. ie: Not too big or small.\n * @public\n */\nexport function isSafeFloat(n: number) {\n\treturn Math.abs(n) < Number.MAX_SAFE_INTEGER\n}\n\n/**\n * Get the angle of a point on an arc.\n * @param fromAngle - The angle from center to arc's start point (A) on the circle\n * @param toAngle - The angle from center to arc's end point (B) on the circle\n * @param direction - The direction of the arc (1 = counter-clockwise, -1 = clockwise)\n * @returns The distance in radians between the two angles according to the direction\n * @public\n */\nexport function angleDistance(fromAngle: number, toAngle: number, direction: number) {\n\tconst dist =\n\t\tdirection < 0\n\t\t\t? clockwiseAngleDist(fromAngle, toAngle)\n\t\t\t: counterClockwiseAngleDist(fromAngle, toAngle)\n\treturn dist\n}\n\n/**\n * Returns the t value of the point on the arc.\n *\n * @param mAB - The measure of the arc from A to B, negative if counter-clockwise\n * @param A - The angle from center to arc's start point (A) on the circle\n * @param B - The angle from center to arc's end point (B) on the circle\n * @param P - The angle on the circle (P) to find the t value for\n *\n * @returns The t value of the point on the arc, with 0 being the start and 1 being the end\n *\n * @public\n */\nexport function getPointInArcT(mAB: number, A: number, B: number, P: number): number {\n\tlet mAP: number\n\tif (Math.abs(mAB) > PI) {\n\t\tmAP = shortAngleDist(A, P)\n\t\tconst mPB = shortAngleDist(P, B)\n\t\tif (Math.abs(mAP) < Math.abs(mPB)) {\n\t\t\treturn mAP / mAB\n\t\t} else {\n\t\t\treturn (mAB - mPB) / mAB\n\t\t}\n\t} else {\n\t\tmAP = shortAngleDist(A, P)\n\t\tconst t = mAP / mAB\n\n\t\t// If the arc is something like -2.8 to 2.2, then we'll get a weird bug\n\t\t// where the measurement to the center is negative but measure to points\n\t\t// near the end are positive\n\t\tif (Math.sign(mAP) !== Math.sign(mAB)) {\n\t\t\treturn Math.abs(t) > 0.5 ? 1 : 0\n\t\t}\n\n\t\treturn t\n\t}\n}\n\n/**\n * Get the measure of an arc.\n *\n * @param A - The angle from center to arc's start point (A) on the circle\n * @param B - The angle from center to arc's end point (B) on the circle\n * @param sweepFlag - 1 if the arc is clockwise, 0 if counter-clockwise\n * @param largeArcFlag - 1 if the arc is greater than 180 degrees, 0 if less than 180 degrees\n *\n * @returns The measure of the arc, negative if counter-clockwise\n *\n * @public\n */\nexport function getArcMeasure(A: number, B: number, sweepFlag: number, largeArcFlag: number) {\n\tconst m = ((2 * ((B - A) % PI2)) % PI2) - ((B - A) % PI2)\n\tif (!largeArcFlag) return m\n\treturn (PI2 - Math.abs(m)) * (sweepFlag ? 1 : -1)\n}\n\n/**\n * Get the center of a circle from three points.\n *\n * @param a - The first point\n * @param b - The second point\n * @param c - The third point\n *\n * @returns The center of the circle or null if the points are collinear\n *\n * @public\n */\nexport function centerOfCircleFromThreePoints(a: VecLike, b: VecLike, c: VecLike) {\n\tconst u = -2 * (a.x * (b.y - c.y) - a.y * (b.x - c.x) + b.x * c.y - c.x * b.y)\n\tconst x =\n\t\t((a.x * a.x + a.y * a.y) * (c.y - b.y) +\n\t\t\t(b.x * b.x + b.y * b.y) * (a.y - c.y) +\n\t\t\t(c.x * c.x + c.y * c.y) * (b.y - a.y)) /\n\t\tu\n\tconst y =\n\t\t((a.x * a.x + a.y * a.y) * (b.x - c.x) +\n\t\t\t(b.x * b.x + b.y * b.y) * (c.x - a.x) +\n\t\t\t(c.x * c.x + c.y * c.y) * (a.x - b.x)) /\n\t\tu\n\tif (!Number.isFinite(x) || !Number.isFinite(y)) {\n\t\treturn null\n\t}\n\treturn new Vec(x, y)\n}\n\n/** @public */\nexport function getPointsOnArc(\n\tstartPoint: VecLike,\n\tendPoint: VecLike,\n\tcenter: VecLike | null,\n\tradius: number,\n\tnumPoints: number\n): Vec[] {\n\tif (center === null) {\n\t\treturn [Vec.From(startPoint), Vec.From(endPoint)]\n\t}\n\tconst results: Vec[] = []\n\tconst startAngle = Vec.Angle(center, startPoint)\n\tconst endAngle = Vec.Angle(center, endPoint)\n\tconst l = clockwiseAngleDist(startAngle, endAngle)\n\tfor (let i = 0; i < numPoints; i++) {\n\t\tconst t = i / (numPoints - 1)\n\t\tconst angle = startAngle + l * t\n\t\tconst point = getPointOnCircle(center, radius, angle)\n\t\tresults.push(point)\n\t}\n\treturn results\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -36,11 +36,13 @@ function releasePointerCapture(element, event) {
|
|
|
36
36
|
console.warn("releasePointerCapture called on element:", element, event);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
function stopEventPropagation(e) {
|
|
40
|
+
return e.stopPropagation();
|
|
41
|
+
}
|
|
42
|
+
function setStyleProperty(elm, property, value) {
|
|
41
43
|
if (!elm) return;
|
|
42
44
|
elm.style.setProperty(property, String(value));
|
|
43
|
-
}
|
|
45
|
+
}
|
|
44
46
|
function elementShouldCaptureKeys(el, includeButtonsAndMenus = true) {
|
|
45
47
|
if (!el) return false;
|
|
46
48
|
const tagName = el.tagName.toLowerCase();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/utils/dom.ts"],
|
|
4
|
-
"sourcesContent": ["/*\nThis is used to facilitate double clicking and pointer capture on elements.\n\nThe events in this file are possibly set on individual SVG elements, \nsuch as handles or corner handles, rather than on HTML elements or \nSVGSVGElements. Raw SVG elements do not support pointerCapture in\nmost cases, meaning that in order for pointer capture to work, we \nneed to crawl up the DOM tree to find the nearest HTML element. Then,\nin order for that element to also call the `onPointerUp` event from\nthis file, we need to manually set that event on that element and\nlater remove it when the pointerup occurs. This is a potential leak\nif the user clicks on a handle but the pointerup does not fire for\nwhatever reason.\n*/\n\nimport { debugFlags, pointerCaptureTrackingObject } from './debug-flags'\n\n/** @public */\nexport function loopToHtmlElement(elm: Element): HTMLElement {\n\tif (elm.nodeType === Node.ELEMENT_NODE) return elm as HTMLElement\n\tif (elm.parentElement) return loopToHtmlElement(elm.parentElement)\n\telse throw Error('Could not find a parent element of an HTML type!')\n}\n\n/**\n * This function calls `event.preventDefault()` for you. Why is that useful?\n *\n * Because if you enable `window.preventDefaultLogging = true` it'll log out a message when it\n * happens. Because we use console.warn rather than (log) you'll get a stack trace in the inspector\n * telling you exactly where it happened. This is important because `e.preventDefault()` is the\n * source of many bugs, but unfortunately it can't be avoided because it also stops a lot of default\n * behaviour which doesn't make sense in our UI\n *\n * @param event - To prevent default on\n * @public\n */\nexport function preventDefault(event: React.BaseSyntheticEvent | Event) {\n\tif ('cancelable' in event && !event.cancelable) return\n\tevent.preventDefault()\n\tif (debugFlags.logPreventDefaults.get()) {\n\t\tconsole.warn('preventDefault called on event:', event)\n\t}\n}\n\n/** @public */\nexport function setPointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\telement.setPointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\ttrackingObj.set(element, (trackingObj.get(element) ?? 0) + 1)\n\t\tconsole.warn('setPointerCapture called on element:', element, event)\n\t}\n}\n\n/** @public */\nexport function releasePointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\tif (!element.hasPointerCapture(event.pointerId)) {\n\t\treturn\n\t}\n\n\telement.releasePointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\tif (trackingObj.get(element) === 1) {\n\t\t\ttrackingObj.delete(element)\n\t\t} else if (trackingObj.has(element)) {\n\t\t\ttrackingObj.set(element, trackingObj.get(element)! - 1)\n\t\t} else {\n\t\t\tconsole.warn('Release without capture')\n\t\t}\n\t\tconsole.warn('releasePointerCapture called on element:', element, event)\n\t}\n}\n\n/**\n * Calls `event.stopPropagation()`.\n *\n * @deprecated Use {@link Editor.markEventAsHandled} instead, or manually call `event.stopPropagation()` if\n * that's what you really want.\n *\n * @public\n */\nexport
|
|
5
|
-
"mappings": "AAeA,SAAS,YAAY,oCAAoC;AAGlD,SAAS,kBAAkB,KAA2B;AAC5D,MAAI,IAAI,aAAa,KAAK,aAAc,QAAO;AAC/C,MAAI,IAAI,cAAe,QAAO,kBAAkB,IAAI,aAAa;AAAA,MAC5D,OAAM,MAAM,kDAAkD;AACpE;AAcO,SAAS,eAAe,OAAyC;AACvE,MAAI,gBAAgB,SAAS,CAAC,MAAM,WAAY;AAChD,QAAM,eAAe;AACrB,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,YAAQ,KAAK,mCAAmC,KAAK;AAAA,EACtD;AACD;AAGO,SAAS,kBACf,SACA,OACC;AACD,UAAQ,kBAAkB,MAAM,SAAS;AACzC,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,gBAAY,IAAI,UAAU,YAAY,IAAI,OAAO,KAAK,KAAK,CAAC;AAC5D,YAAQ,KAAK,wCAAwC,SAAS,KAAK;AAAA,EACpE;AACD;AAGO,SAAS,sBACf,SACA,OACC;AACD,MAAI,CAAC,QAAQ,kBAAkB,MAAM,SAAS,GAAG;AAChD;AAAA,EACD;AAEA,UAAQ,sBAAsB,MAAM,SAAS;AAC7C,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,QAAI,YAAY,IAAI,OAAO,MAAM,GAAG;AACnC,kBAAY,OAAO,OAAO;AAAA,IAC3B,WAAW,YAAY,IAAI,OAAO,GAAG;AACpC,kBAAY,IAAI,SAAS,YAAY,IAAI,OAAO,IAAK,CAAC;AAAA,IACvD,OAAO;AACN,cAAQ,KAAK,yBAAyB;AAAA,IACvC;AACA,YAAQ,KAAK,4CAA4C,SAAS,KAAK;AAAA,EACxE;AACD;AAUO,
|
|
4
|
+
"sourcesContent": ["/*\nThis is used to facilitate double clicking and pointer capture on elements.\n\nThe events in this file are possibly set on individual SVG elements, \nsuch as handles or corner handles, rather than on HTML elements or \nSVGSVGElements. Raw SVG elements do not support pointerCapture in\nmost cases, meaning that in order for pointer capture to work, we \nneed to crawl up the DOM tree to find the nearest HTML element. Then,\nin order for that element to also call the `onPointerUp` event from\nthis file, we need to manually set that event on that element and\nlater remove it when the pointerup occurs. This is a potential leak\nif the user clicks on a handle but the pointerup does not fire for\nwhatever reason.\n*/\n\nimport { debugFlags, pointerCaptureTrackingObject } from './debug-flags'\n\n/** @public */\nexport function loopToHtmlElement(elm: Element): HTMLElement {\n\tif (elm.nodeType === Node.ELEMENT_NODE) return elm as HTMLElement\n\tif (elm.parentElement) return loopToHtmlElement(elm.parentElement)\n\telse throw Error('Could not find a parent element of an HTML type!')\n}\n\n/**\n * This function calls `event.preventDefault()` for you. Why is that useful?\n *\n * Because if you enable `window.preventDefaultLogging = true` it'll log out a message when it\n * happens. Because we use console.warn rather than (log) you'll get a stack trace in the inspector\n * telling you exactly where it happened. This is important because `e.preventDefault()` is the\n * source of many bugs, but unfortunately it can't be avoided because it also stops a lot of default\n * behaviour which doesn't make sense in our UI\n *\n * @param event - To prevent default on\n * @public\n */\nexport function preventDefault(event: React.BaseSyntheticEvent | Event) {\n\tif ('cancelable' in event && !event.cancelable) return\n\tevent.preventDefault()\n\tif (debugFlags.logPreventDefaults.get()) {\n\t\tconsole.warn('preventDefault called on event:', event)\n\t}\n}\n\n/** @public */\nexport function setPointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\telement.setPointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\ttrackingObj.set(element, (trackingObj.get(element) ?? 0) + 1)\n\t\tconsole.warn('setPointerCapture called on element:', element, event)\n\t}\n}\n\n/** @public */\nexport function releasePointerCapture(\n\telement: Element,\n\tevent: React.PointerEvent<Element> | PointerEvent\n) {\n\tif (!element.hasPointerCapture(event.pointerId)) {\n\t\treturn\n\t}\n\n\telement.releasePointerCapture(event.pointerId)\n\tif (debugFlags.logPointerCaptures.get()) {\n\t\tconst trackingObj = pointerCaptureTrackingObject.get()\n\t\tif (trackingObj.get(element) === 1) {\n\t\t\ttrackingObj.delete(element)\n\t\t} else if (trackingObj.has(element)) {\n\t\t\ttrackingObj.set(element, trackingObj.get(element)! - 1)\n\t\t} else {\n\t\t\tconsole.warn('Release without capture')\n\t\t}\n\t\tconsole.warn('releasePointerCapture called on element:', element, event)\n\t}\n}\n\n/**\n * Calls `event.stopPropagation()`.\n *\n * @deprecated Use {@link Editor.markEventAsHandled} instead, or manually call `event.stopPropagation()` if\n * that's what you really want.\n *\n * @public\n */\nexport function stopEventPropagation(e: any) {\n\treturn e.stopPropagation()\n}\n\n/** @internal */\nexport function setStyleProperty(\n\telm: HTMLElement | null,\n\tproperty: string,\n\tvalue: string | number\n) {\n\tif (!elm) return\n\telm.style.setProperty(property, String(value))\n}\n\n/** @internal */\nexport function elementShouldCaptureKeys(el: Element | null, includeButtonsAndMenus = true) {\n\tif (!el) return false\n\n\tconst tagName = el.tagName.toLowerCase()\n\treturn (\n\t\t(el as HTMLElement).isContentEditable ||\n\t\ttagName === 'input' ||\n\t\ttagName === 'textarea' ||\n\t\t(includeButtonsAndMenus && tagName === 'select') ||\n\t\t(includeButtonsAndMenus && tagName === 'button') ||\n\t\tel.classList.contains('tlui-slider__thumb')\n\t)\n}\n\n/**\n * Returns the global `document`. Use this instead of bare `document` to satisfy lint rules.\n *\n * When you have a DOM node or editor instance, prefer the scoped versions instead:\n * - `getOwnerDocument(node)` \u2013 the document that owns a specific DOM node\n * - `editor.getContainerDocument()` \u2013 the document where the editor is mounted\n *\n * @internal\n */\nexport function getGlobalDocument(): Document {\n\t// eslint-disable-next-line no-restricted-globals\n\tif (typeof document !== 'undefined') return document\n\treturn globalThis.document\n}\n\n/**\n * Returns the global `window`. Use this instead of bare `window` to satisfy lint rules.\n *\n * When you have a DOM node or editor instance, prefer the scoped versions instead:\n * - `getOwnerWindow(node)` \u2013 the window that owns a specific DOM node\n * - `editor.getContainerWindow()` \u2013 the window where the editor is mounted\n *\n * @internal\n */\nexport function getGlobalWindow(): Window & typeof globalThis {\n\tif (typeof window !== 'undefined') return window as Window & typeof globalThis\n\treturn globalThis as Window & typeof globalThis\n}\n\n/** @internal */\nexport function activeElementShouldCaptureKeys(includeButtonsAndMenus = true, doc?: Document) {\n\treturn elementShouldCaptureKeys(\n\t\t(doc ?? getGlobalDocument()).activeElement,\n\t\tincludeButtonsAndMenus\n\t)\n}\n"],
|
|
5
|
+
"mappings": "AAeA,SAAS,YAAY,oCAAoC;AAGlD,SAAS,kBAAkB,KAA2B;AAC5D,MAAI,IAAI,aAAa,KAAK,aAAc,QAAO;AAC/C,MAAI,IAAI,cAAe,QAAO,kBAAkB,IAAI,aAAa;AAAA,MAC5D,OAAM,MAAM,kDAAkD;AACpE;AAcO,SAAS,eAAe,OAAyC;AACvE,MAAI,gBAAgB,SAAS,CAAC,MAAM,WAAY;AAChD,QAAM,eAAe;AACrB,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,YAAQ,KAAK,mCAAmC,KAAK;AAAA,EACtD;AACD;AAGO,SAAS,kBACf,SACA,OACC;AACD,UAAQ,kBAAkB,MAAM,SAAS;AACzC,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,gBAAY,IAAI,UAAU,YAAY,IAAI,OAAO,KAAK,KAAK,CAAC;AAC5D,YAAQ,KAAK,wCAAwC,SAAS,KAAK;AAAA,EACpE;AACD;AAGO,SAAS,sBACf,SACA,OACC;AACD,MAAI,CAAC,QAAQ,kBAAkB,MAAM,SAAS,GAAG;AAChD;AAAA,EACD;AAEA,UAAQ,sBAAsB,MAAM,SAAS;AAC7C,MAAI,WAAW,mBAAmB,IAAI,GAAG;AACxC,UAAM,cAAc,6BAA6B,IAAI;AACrD,QAAI,YAAY,IAAI,OAAO,MAAM,GAAG;AACnC,kBAAY,OAAO,OAAO;AAAA,IAC3B,WAAW,YAAY,IAAI,OAAO,GAAG;AACpC,kBAAY,IAAI,SAAS,YAAY,IAAI,OAAO,IAAK,CAAC;AAAA,IACvD,OAAO;AACN,cAAQ,KAAK,yBAAyB;AAAA,IACvC;AACA,YAAQ,KAAK,4CAA4C,SAAS,KAAK;AAAA,EACxE;AACD;AAUO,SAAS,qBAAqB,GAAQ;AAC5C,SAAO,EAAE,gBAAgB;AAC1B;AAGO,SAAS,iBACf,KACA,UACA,OACC;AACD,MAAI,CAAC,IAAK;AACV,MAAI,MAAM,YAAY,UAAU,OAAO,KAAK,CAAC;AAC9C;AAGO,SAAS,yBAAyB,IAAoB,yBAAyB,MAAM;AAC3F,MAAI,CAAC,GAAI,QAAO;AAEhB,QAAM,UAAU,GAAG,QAAQ,YAAY;AACvC,SACE,GAAmB,qBACpB,YAAY,WACZ,YAAY,cACX,0BAA0B,YAAY,YACtC,0BAA0B,YAAY,YACvC,GAAG,UAAU,SAAS,oBAAoB;AAE5C;AAWO,SAAS,oBAA8B;AAE7C,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,SAAO,WAAW;AACnB;AAWO,SAAS,kBAA8C;AAC7D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO;AACR;AAGO,SAAS,+BAA+B,yBAAyB,MAAM,KAAgB;AAC7F,SAAO;AAAA,KACL,OAAO,kBAAkB,GAAG;AAAA,IAC7B;AAAA,EACD;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "5.
|
|
1
|
+
const version = "5.2.0-canary.083e81484bc9";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2026-05-06T16:28:18.473Z",
|
|
4
|
-
minor: "2026-06-
|
|
5
|
-
patch: "2026-06-
|
|
4
|
+
minor: "2026-06-10T10:56:24.812Z",
|
|
5
|
+
patch: "2026-06-10T10:56:24.812Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.2.0-canary.083e81484bc9'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-06-10T10:56:24.812Z',\n\tpatch: '2026-06-10T10:56:24.812Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/editor.css
CHANGED
|
@@ -182,6 +182,7 @@
|
|
|
182
182
|
--tl-color-text-0: hsl(0, 0%, 11%);
|
|
183
183
|
--tl-color-text-1: hsl(0, 0%, 18%);
|
|
184
184
|
--tl-color-text-3: hsl(204, 4%, 45%);
|
|
185
|
+
--tl-color-text-disabled: hsl(204, 4%, 55%);
|
|
185
186
|
--tl-color-text-shadow: hsl(0, 0%, 100%);
|
|
186
187
|
--tl-color-text-highlight: hsl(52, 100%, 50%);
|
|
187
188
|
--tl-color-text-highlight-p3: color(display-p3 0.972 0.8205 0.05);
|
|
@@ -236,6 +237,7 @@
|
|
|
236
237
|
--tl-color-text-0: hsl(0, 9%, 94%);
|
|
237
238
|
--tl-color-text-1: hsl(0, 0%, 85%);
|
|
238
239
|
--tl-color-text-3: hsl(204, 4%, 75%);
|
|
240
|
+
--tl-color-text-disabled: hsl(204, 4%, 50%);
|
|
239
241
|
--tl-color-text-shadow: hsl(210, 13%, 18%);
|
|
240
242
|
--tl-color-text-highlight: hsl(52, 100%, 41%);
|
|
241
243
|
--tl-color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (editor).",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.2.0-canary.083e81484bc9",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@tiptap/core": "^3.12.1",
|
|
50
50
|
"@tiptap/pm": "^3.12.1",
|
|
51
51
|
"@tiptap/react": "^3.12.1",
|
|
52
|
-
"@tldraw/state": "5.
|
|
53
|
-
"@tldraw/state-react": "5.
|
|
54
|
-
"@tldraw/store": "5.
|
|
55
|
-
"@tldraw/tlschema": "5.
|
|
56
|
-
"@tldraw/utils": "5.
|
|
57
|
-
"@tldraw/validate": "5.
|
|
52
|
+
"@tldraw/state": "5.2.0-canary.083e81484bc9",
|
|
53
|
+
"@tldraw/state-react": "5.2.0-canary.083e81484bc9",
|
|
54
|
+
"@tldraw/store": "5.2.0-canary.083e81484bc9",
|
|
55
|
+
"@tldraw/tlschema": "5.2.0-canary.083e81484bc9",
|
|
56
|
+
"@tldraw/utils": "5.2.0-canary.083e81484bc9",
|
|
57
|
+
"@tldraw/validate": "5.2.0-canary.083e81484bc9",
|
|
58
58
|
"classnames": "^2.5.1",
|
|
59
59
|
"eventemitter3": "^4.0.7",
|
|
60
60
|
"idb": "^7.1.1",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"react": "^19.2.1",
|
|
81
81
|
"react-dom": "^19.2.1",
|
|
82
82
|
"resize-observer-polyfill": "^1.5.1",
|
|
83
|
-
"vitest": "^
|
|
83
|
+
"vitest": "^4.1.7"
|
|
84
84
|
},
|
|
85
85
|
"module": "dist-esm/index.mjs",
|
|
86
86
|
"source": "src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -185,11 +185,7 @@ export {
|
|
|
185
185
|
type TLOverlay,
|
|
186
186
|
type TLOverlayUtilConstructor,
|
|
187
187
|
} from './lib/editor/overlays/OverlayUtil'
|
|
188
|
-
export {
|
|
189
|
-
ShapeIndicatorOverlayUtil,
|
|
190
|
-
strokeShapeIndicators,
|
|
191
|
-
type TLShapeIndicatorOverlay,
|
|
192
|
-
} from './lib/editor/overlays/ShapeIndicatorOverlayUtil'
|
|
188
|
+
export { strokeShapeIndicators } from './lib/editor/overlays/strokeShapeIndicators'
|
|
193
189
|
export {
|
|
194
190
|
getPerfectDashProps,
|
|
195
191
|
type PerfectDashTerminal,
|
|
@@ -16,7 +16,10 @@ const BASE_ERROR_URL = 'https://github.com/tldraw/tldraw/issues/new'
|
|
|
16
16
|
export type TLErrorFallbackComponent = ComponentType<{ error: unknown; editor?: Editor }>
|
|
17
17
|
|
|
18
18
|
/** @public @react */
|
|
19
|
-
export const DefaultErrorFallback: TLErrorFallbackComponent = ({
|
|
19
|
+
export const DefaultErrorFallback: TLErrorFallbackComponent = function DefaultErrorFallback({
|
|
20
|
+
error,
|
|
21
|
+
editor,
|
|
22
|
+
}) {
|
|
20
23
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
21
24
|
const [shouldShowError, setShouldShowError] = useState(process.env.NODE_ENV === 'development')
|
|
22
25
|
const [didCopy, setDidCopy] = useState(false)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEditorComponents } from '../../hooks/EditorComponentsContext'
|
|
2
2
|
|
|
3
3
|
/** @public @react */
|
|
4
|
-
export
|
|
4
|
+
export function DefaultLoadingScreen() {
|
|
5
5
|
const { Spinner } = useEditorComponents()
|
|
6
6
|
return (
|
|
7
7
|
<div className="tl-loading" aria-busy="true" tabIndex={0}>
|
|
@@ -4,6 +4,7 @@ import { ComponentType } from 'react'
|
|
|
4
4
|
export type TLShapeErrorFallbackComponent = ComponentType<{ error: any }>
|
|
5
5
|
|
|
6
6
|
/** @internal */
|
|
7
|
-
export const DefaultShapeErrorFallback: TLShapeErrorFallbackComponent =
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export const DefaultShapeErrorFallback: TLShapeErrorFallbackComponent =
|
|
8
|
+
function DefaultShapeErrorFallback() {
|
|
9
|
+
return <div className="tl-shape-error-boundary" />
|
|
10
|
+
}
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -3336,6 +3336,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3336
3336
|
|
|
3337
3337
|
let { x, y, z = currentCamera.z } = point
|
|
3338
3338
|
|
|
3339
|
+
// `requested` kept the caller's focal point (e.g. the cursor) fixed at
|
|
3340
|
+
// zoom `rz`. When `rz` gets clamped, keep that same focal point fixed at
|
|
3341
|
+
// the clamped zoom `z` rather than snapping to the viewport center.
|
|
3342
|
+
const preserveFocalPoint = (current: number, requested: number, rz: number, z: number) => {
|
|
3343
|
+
const cz = currentCamera.z
|
|
3344
|
+
if (rz === cz) return current
|
|
3345
|
+
return current + ((requested - current) * (1 / z - 1 / cz)) / (1 / rz - 1 / cz)
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3339
3348
|
// If force is true, then we'll set the camera to the point regardless of
|
|
3340
3349
|
// the camera options, so that we can handle gestures that permit elasticity
|
|
3341
3350
|
// or decay, or animations that occur while the camera is locked.
|
|
@@ -3378,17 +3387,14 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3378
3387
|
}
|
|
3379
3388
|
|
|
3380
3389
|
if (z < minZ || z > maxZ) {
|
|
3381
|
-
// We're trying to zoom out past the minimum zoom level,
|
|
3382
|
-
//
|
|
3383
|
-
//
|
|
3384
|
-
|
|
3385
|
-
const
|
|
3386
|
-
const cyA = -cy + vsb.h / cz / 2
|
|
3390
|
+
// We're trying to zoom out past the minimum zoom level, or in
|
|
3391
|
+
// past the maximum zoom level, so clamp the zoom while keeping
|
|
3392
|
+
// the caller's focal point fixed. Axis constraints below still
|
|
3393
|
+
// apply on top of this.
|
|
3394
|
+
const rz = z
|
|
3387
3395
|
z = clamp(z, minZ, maxZ)
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
x = cx + cxB - cxA
|
|
3391
|
-
y = cy + cyB - cyA
|
|
3396
|
+
x = preserveFocalPoint(currentCamera.x, x, rz, z)
|
|
3397
|
+
y = preserveFocalPoint(currentCamera.y, y, rz, z)
|
|
3392
3398
|
}
|
|
3393
3399
|
|
|
3394
3400
|
// Calculate available space
|
|
@@ -3477,12 +3483,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3477
3483
|
}
|
|
3478
3484
|
}
|
|
3479
3485
|
} else {
|
|
3480
|
-
// constrain the zoom,
|
|
3486
|
+
// constrain the zoom, keeping the caller's focal point fixed
|
|
3481
3487
|
if (z > zoomMax || z < zoomMin) {
|
|
3482
|
-
const
|
|
3488
|
+
const rz = z
|
|
3483
3489
|
z = clamp(z, zoomMin, zoomMax)
|
|
3484
|
-
x =
|
|
3485
|
-
y =
|
|
3490
|
+
x = preserveFocalPoint(currentCamera.x, x, rz, z)
|
|
3491
|
+
y = preserveFocalPoint(currentCamera.y, y, rz, z)
|
|
3486
3492
|
}
|
|
3487
3493
|
}
|
|
3488
3494
|
}
|
|
@@ -4023,16 +4029,34 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4023
4029
|
|
|
4024
4030
|
this.once('stop-camera-animation', cancel)
|
|
4025
4031
|
|
|
4032
|
+
const dirZ = direction.z ?? 0
|
|
4033
|
+
|
|
4026
4034
|
const moveCamera = (elapsed: number) => {
|
|
4027
4035
|
const { x: cx, y: cy, z: cz } = this.getCamera()
|
|
4028
|
-
|
|
4036
|
+
|
|
4037
|
+
// Pan movement from x/y direction
|
|
4038
|
+
const dx = (direction.x * (currentSpeed * elapsed)) / cz
|
|
4039
|
+
const dy = (direction.y * (currentSpeed * elapsed)) / cz
|
|
4040
|
+
|
|
4041
|
+
let newCx = cx + dx
|
|
4042
|
+
let newCy = cy + dy
|
|
4043
|
+
let newCz = cz
|
|
4044
|
+
|
|
4045
|
+
// animate zoom if z direction is passed in
|
|
4046
|
+
if (dirZ !== 0) {
|
|
4047
|
+
newCz = cz * (1 + dirZ * currentSpeed * elapsed)
|
|
4048
|
+
// Adjust x/y to keep the viewport center fixed while zooming
|
|
4049
|
+
const center = this.getViewportScreenCenter()
|
|
4050
|
+
newCx += center.x / newCz - center.x / cz
|
|
4051
|
+
newCy += center.y / newCz - center.y / cz
|
|
4052
|
+
}
|
|
4029
4053
|
|
|
4030
4054
|
// Apply friction
|
|
4031
4055
|
currentSpeed *= 1 - friction
|
|
4032
4056
|
if (currentSpeed < speedThreshold) {
|
|
4033
4057
|
cancel()
|
|
4034
4058
|
} else {
|
|
4035
|
-
this._setCamera(new Vec(
|
|
4059
|
+
this._setCamera(new Vec(newCx, newCy, newCz))
|
|
4036
4060
|
}
|
|
4037
4061
|
}
|
|
4038
4062
|
|
|
@@ -10768,6 +10792,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10768
10792
|
/** @internal */
|
|
10769
10793
|
private _selectedShapeIdsAtPointerDown: TLShapeId[] = []
|
|
10770
10794
|
|
|
10795
|
+
/**
|
|
10796
|
+
* Whether `_selectedShapeIdsAtPointerDown` holds a pre-gesture selection
|
|
10797
|
+
* captured by a `pointer_down` (the touch path) that a following pinch
|
|
10798
|
+
* should restore. False when no pointer_down preceded the pinch (the
|
|
10799
|
+
* Safari trackpad path uses gesture events), in which case `pinch_start`
|
|
10800
|
+
* captures the live selection instead.
|
|
10801
|
+
* @internal
|
|
10802
|
+
*/
|
|
10803
|
+
private _didCaptureSelectionAtPointerDown = false
|
|
10804
|
+
|
|
10771
10805
|
/** @internal */
|
|
10772
10806
|
private _longPressTimeout = -1 as any
|
|
10773
10807
|
|
|
@@ -10933,16 +10967,28 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10933
10967
|
if (inputs.getIsPinching()) return
|
|
10934
10968
|
|
|
10935
10969
|
if (!inputs.getIsEditing()) {
|
|
10936
|
-
//
|
|
10937
|
-
//
|
|
10938
|
-
//
|
|
10939
|
-
|
|
10970
|
+
// If a pointer_down already captured the pre-gesture selection,
|
|
10971
|
+
// keep it: on touch, the first finger's pointer_down can change
|
|
10972
|
+
// the selection before the second finger starts the pinch, and we
|
|
10973
|
+
// want to restore the selection from before that change. When no
|
|
10974
|
+
// pointer_down preceded the pinch (Safari delivers trackpad pinches
|
|
10975
|
+
// as gesture events), capture the live selection now.
|
|
10976
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
10977
|
+
this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds]
|
|
10978
|
+
}
|
|
10940
10979
|
|
|
10941
10980
|
this._didPinch = true
|
|
10942
10981
|
|
|
10943
10982
|
inputs.setIsPinching(true)
|
|
10944
10983
|
|
|
10945
10984
|
this.interrupt()
|
|
10985
|
+
|
|
10986
|
+
// If the first finger changed the selection, roll it back now rather
|
|
10987
|
+
// than waiting for the pinch to end, so the pre-gesture selection is
|
|
10988
|
+
// what's shown during the pinch.
|
|
10989
|
+
if (this._didCaptureSelectionAtPointerDown) {
|
|
10990
|
+
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
10991
|
+
}
|
|
10946
10992
|
}
|
|
10947
10993
|
|
|
10948
10994
|
this.emit('event', info)
|
|
@@ -10994,6 +11040,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10994
11040
|
const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this
|
|
10995
11041
|
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
10996
11042
|
this._selectedShapeIdsAtPointerDown = []
|
|
11043
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
10997
11044
|
|
|
10998
11045
|
if (this._didPinch) {
|
|
10999
11046
|
this._didPinch = false
|
|
@@ -11122,8 +11169,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11122
11169
|
}, this.options.longPressDurationMs)
|
|
11123
11170
|
}
|
|
11124
11171
|
|
|
11125
|
-
// Save the selected ids at
|
|
11126
|
-
|
|
11172
|
+
// Save the selected ids at the start of an interaction so a pinch can
|
|
11173
|
+
// restore the pre-gesture selection. Only capture on the first pointer:
|
|
11174
|
+
// on touch, the second finger's pointer_down arrives after the first
|
|
11175
|
+
// has already changed the selection, and we want the earlier snapshot.
|
|
11176
|
+
// Cleared on pointer_up / pinch_end.
|
|
11177
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11178
|
+
this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds()
|
|
11179
|
+
this._didCaptureSelectionAtPointerDown = true
|
|
11180
|
+
}
|
|
11127
11181
|
|
|
11128
11182
|
// Firefox bug fix...
|
|
11129
11183
|
// If it's a left-mouse-click, we store the pointer id for later user
|
|
@@ -11243,6 +11297,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11243
11297
|
if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
|
|
11244
11298
|
this.inputs.setIsRightPointing(false)
|
|
11245
11299
|
this._selectedShapeIdsAtPointerDown = []
|
|
11300
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11246
11301
|
break // fall through to state chart dispatch as right_click
|
|
11247
11302
|
}
|
|
11248
11303
|
|
|
@@ -11289,12 +11344,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11289
11344
|
this.slideCamera({ speed: slideSpeed, direction: slideDirection })
|
|
11290
11345
|
}
|
|
11291
11346
|
this._selectedShapeIdsAtPointerDown = []
|
|
11347
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11292
11348
|
return this
|
|
11293
11349
|
}
|
|
11294
11350
|
}
|
|
11295
11351
|
|
|
11296
11352
|
if (slideSpeed > 0) {
|
|
11297
|
-
this.slideCamera({
|
|
11353
|
+
this.slideCamera({
|
|
11354
|
+
speed: slideSpeed,
|
|
11355
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11356
|
+
})
|
|
11298
11357
|
}
|
|
11299
11358
|
} else {
|
|
11300
11359
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11307,6 +11366,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11307
11366
|
// Clear the stashed selection so the next pinch captures fresh state.
|
|
11308
11367
|
// This fixes Safari pinch zoom restoring outdated selections.
|
|
11309
11368
|
this._selectedShapeIdsAtPointerDown = []
|
|
11369
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11310
11370
|
|
|
11311
11371
|
break
|
|
11312
11372
|
}
|
|
@@ -29,7 +29,7 @@ function fromScratch(bindingsQuery: Computed<TLBinding[], unknown>) {
|
|
|
29
29
|
return shapesToBindings
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export
|
|
32
|
+
export function bindingsIndex(editor: Editor): Computed<TLBindingsIndex> {
|
|
33
33
|
const { store } = editor
|
|
34
34
|
const bindingsHistory = store.query.filterHistory('binding')
|
|
35
35
|
const bindingsQuery = store.query.records('binding')
|
|
@@ -22,7 +22,7 @@ function fromScratch(
|
|
|
22
22
|
return result
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export
|
|
25
|
+
export function parentsToChildren(store: TLStore) {
|
|
26
26
|
const shapeIdsQuery = store.query.ids<'shape'>('shape')
|
|
27
27
|
const shapeHistory = store.query.filterHistory('shape')
|
|
28
28
|
|