tldraw 3.16.0-canary.ed8bd30c0f28 → 3.16.0-canary.efdec30fc411
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/dist-cjs/index.d.ts +89 -4
- package/dist-cjs/index.js +11 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +1 -1
- package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
- package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js +10 -1
- package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
- package/dist-cjs/lib/ui/components/AccessibilityMenu.js +35 -0
- package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +7 -0
- package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +2 -1
- package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
- package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +3 -3
- package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +1 -1
- package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +2 -1
- package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
- package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
- package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +2 -0
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +171 -140
- package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js +3 -3
- package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +2 -2
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js +26 -25
- package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +3 -3
- package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +6 -5
- package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +9 -10
- package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +5 -4
- package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js +6 -0
- package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +4 -15
- package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +3 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +1 -1
- package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +18 -7
- package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +284 -0
- package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
- package/dist-cjs/lib/ui/components/primitives/layout.js +51 -0
- package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +152 -2
- package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
- package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js +3 -2
- package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js.map +2 -2
- package/dist-cjs/lib/ui/context/actions.js +15 -0
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/context/events.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTools.js +76 -9
- package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +3 -0
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +89 -4
- package/dist-esm/index.mjs +19 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +1 -1
- package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
- package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +10 -1
- package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
- package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +19 -0
- package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +7 -0
- package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
- package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +3 -5
- package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
- package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -1
- package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
- package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
- package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +3 -1
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +171 -140
- package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs +3 -3
- package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs +26 -25
- package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +6 -5
- package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +9 -10
- package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +5 -4
- package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs +6 -0
- package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +4 -5
- package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +1 -1
- package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +18 -7
- package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +254 -0
- package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
- package/dist-esm/lib/ui/components/primitives/layout.mjs +21 -0
- package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +160 -4
- package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
- package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs +3 -2
- package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs.map +2 -2
- package/dist-esm/lib/ui/context/actions.mjs +15 -0
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/context/events.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTools.mjs +83 -10
- package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +3 -0
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +15 -0
- package/src/lib/shapes/arrow/arrowTargetState.ts +2 -1
- package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
- package/src/lib/tools/SelectTool/childStates/Translating.ts +0 -1
- package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
- package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +2 -1
- package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
- package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
- package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
- package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +3 -2
- package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
- package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
- package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +3 -1
- package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +146 -107
- package/src/lib/ui/components/StylePanel/DoubleDropdownPicker.tsx +3 -3
- package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +7 -6
- package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +7 -6
- package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +10 -11
- package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +14 -11
- package/src/lib/ui/components/menu-items.tsx +8 -0
- package/src/lib/ui/components/primitives/TldrawUiButtonPicker.tsx +38 -36
- package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +1 -1
- package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
- package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +34 -12
- package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +332 -0
- package/src/lib/ui/components/primitives/layout.tsx +33 -0
- package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +218 -3
- package/src/lib/ui/context/TldrawUiContextProvider.tsx +23 -20
- package/src/lib/ui/context/actions.tsx +15 -0
- package/src/lib/ui/context/events.tsx +2 -0
- package/src/lib/ui/hooks/useTools.tsx +118 -10
- package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +3 -0
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +3 -0
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/ui.css +80 -69
- package/src/test/arrows-megabus.test.tsx +12 -6
- package/src/test/inner-outer-margin.test.ts +315 -0
- package/tldraw.css +82 -69
package/src/lib/ui.css
CHANGED
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
opacity: 1;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
.tlui-button[aria-expanded='true'][data-direction='left']
|
|
100
|
+
.tlui-button[aria-expanded='true'][data-direction='left'] {
|
|
101
101
|
background: linear-gradient(270deg, rgba(144, 144, 144, 0) 0%, var(--color-muted-2) 100%);
|
|
102
102
|
opacity: 1;
|
|
103
103
|
}
|
|
@@ -161,12 +161,6 @@
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
/* Panel button */
|
|
165
|
-
|
|
166
|
-
.tlui-button__panel {
|
|
167
|
-
position: relative;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
164
|
/* Menu button */
|
|
171
165
|
|
|
172
166
|
.tlui-button__menu {
|
|
@@ -207,7 +201,7 @@
|
|
|
207
201
|
|
|
208
202
|
/* Tool lock button */
|
|
209
203
|
|
|
210
|
-
.tlui-toolbar__lock-button {
|
|
204
|
+
.tlui-main-toolbar__lock-button {
|
|
211
205
|
position: absolute;
|
|
212
206
|
top: 4px;
|
|
213
207
|
right: 0px;
|
|
@@ -218,7 +212,7 @@
|
|
|
218
212
|
border-radius: var(--radius-2);
|
|
219
213
|
}
|
|
220
214
|
|
|
221
|
-
.tlui-toolbar__lock-button::after {
|
|
215
|
+
.tlui-main-toolbar__lock-button::after {
|
|
222
216
|
top: 4px;
|
|
223
217
|
left: 8px;
|
|
224
218
|
inset: 4px;
|
|
@@ -230,16 +224,6 @@
|
|
|
230
224
|
position: relative;
|
|
231
225
|
height: 48px;
|
|
232
226
|
width: 48px;
|
|
233
|
-
margin-left: -2px;
|
|
234
|
-
margin-right: -2px;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
.tlui-button__tool:nth-of-type(1) {
|
|
238
|
-
margin-left: 0px;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
.tlui-button__tool:nth-last-of-type(1) {
|
|
242
|
-
margin-right: 0px;
|
|
243
227
|
}
|
|
244
228
|
|
|
245
229
|
.tlui-button__tool::after {
|
|
@@ -270,47 +254,30 @@
|
|
|
270
254
|
width: 16px;
|
|
271
255
|
}
|
|
272
256
|
|
|
273
|
-
/*
|
|
257
|
+
/* Row layout */
|
|
274
258
|
|
|
275
|
-
.tlui-
|
|
259
|
+
.tlui-row {
|
|
276
260
|
display: flex;
|
|
277
261
|
flex-direction: row;
|
|
262
|
+
padding: 0 2px;
|
|
278
263
|
}
|
|
279
|
-
.tlui-
|
|
264
|
+
.tlui-row > * {
|
|
280
265
|
margin-left: -2px;
|
|
281
266
|
margin-right: -2px;
|
|
282
267
|
}
|
|
283
|
-
.tlui-buttons__horizontal > *:nth-child(1) {
|
|
284
|
-
margin-left: 0px;
|
|
285
|
-
}
|
|
286
|
-
.tlui-buttons__horizontal > *:nth-last-child(1) {
|
|
287
|
-
margin-right: 0px;
|
|
288
|
-
}
|
|
289
268
|
|
|
290
|
-
/*
|
|
269
|
+
/* Grid layout */
|
|
291
270
|
|
|
292
|
-
.tlui-
|
|
271
|
+
.tlui-grid {
|
|
293
272
|
display: grid;
|
|
294
|
-
grid-template-columns: repeat(4,
|
|
273
|
+
grid-template-columns: repeat(4, 1fr);
|
|
295
274
|
grid-auto-flow: row;
|
|
296
275
|
overflow: hidden;
|
|
276
|
+
padding: 2px;
|
|
297
277
|
}
|
|
298
|
-
.tlui-
|
|
278
|
+
.tlui-grid > * {
|
|
299
279
|
margin: -2px;
|
|
300
280
|
}
|
|
301
|
-
.tlui-buttons__grid > .tlui-button:nth-of-type(4n),
|
|
302
|
-
.tlui-buttons__vertical-align > .tlui-button:nth-of-type(3n) {
|
|
303
|
-
margin-right: 0px;
|
|
304
|
-
}
|
|
305
|
-
.tlui-buttons__grid > .tlui-button:nth-of-type(4n - 3) {
|
|
306
|
-
margin-left: 0px;
|
|
307
|
-
}
|
|
308
|
-
.tlui-buttons__grid > .tlui-button:nth-of-type(-n + 4) {
|
|
309
|
-
margin-top: 0px;
|
|
310
|
-
}
|
|
311
|
-
.tlui-buttons__grid > .tlui-button:nth-last-of-type(-n + 4) {
|
|
312
|
-
margin-bottom: 0px;
|
|
313
|
-
}
|
|
314
281
|
|
|
315
282
|
/* Zoom button */
|
|
316
283
|
|
|
@@ -1000,6 +967,12 @@
|
|
|
1000
967
|
max-width: 148px;
|
|
1001
968
|
}
|
|
1002
969
|
|
|
970
|
+
.tlui-style-panel[data-show-ui-labels='true'] .tlui-button[data-isactive='true'] {
|
|
971
|
+
border-radius: 10px;
|
|
972
|
+
outline: 2px solid var(--color-text);
|
|
973
|
+
outline-offset: -5px;
|
|
974
|
+
}
|
|
975
|
+
|
|
1003
976
|
.tlui-style-panel::-webkit-scrollbar {
|
|
1004
977
|
display: none;
|
|
1005
978
|
}
|
|
@@ -1027,12 +1000,8 @@
|
|
|
1027
1000
|
border-bottom: 1px solid var(--color-divider);
|
|
1028
1001
|
}
|
|
1029
1002
|
|
|
1030
|
-
.tlui-style-
|
|
1031
|
-
|
|
1032
|
-
}
|
|
1033
|
-
/* Only really used for the alignment picker */
|
|
1034
|
-
.tlui-style-panel__row__extra-button {
|
|
1035
|
-
margin-left: -2px;
|
|
1003
|
+
.tlui-style-panel__dropdown-picker:only-child {
|
|
1004
|
+
width: 100%;
|
|
1036
1005
|
}
|
|
1037
1006
|
|
|
1038
1007
|
.tlui-style-panel__double-select-picker {
|
|
@@ -1064,6 +1033,26 @@
|
|
|
1064
1033
|
}
|
|
1065
1034
|
}
|
|
1066
1035
|
|
|
1036
|
+
/* Accessibility subheadings */
|
|
1037
|
+
|
|
1038
|
+
.tlui-style-panel__section .tlui-style-panel__subheading,
|
|
1039
|
+
.tlui-style-panel__section__common .tlui-style-panel__subheading,
|
|
1040
|
+
.tlui-style-panel__subheading + .tlui-slider__container {
|
|
1041
|
+
margin: 0;
|
|
1042
|
+
padding: var(--space-2) var(--space-3) 0px var(--space-4);
|
|
1043
|
+
font-size: 12px;
|
|
1044
|
+
font-weight: inherit;
|
|
1045
|
+
line-height: inherit;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.tlui-style-panel .tlui-style-panel__subheading:nth-of-type(1) {
|
|
1049
|
+
padding-top: var(--space-3);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
.tlui-style-panel__subheading + .tlui-slider__container {
|
|
1053
|
+
padding-top: 0px;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1067
1056
|
/* --------------------- Bottom --------------------- */
|
|
1068
1057
|
|
|
1069
1058
|
.tlui-layout__bottom {
|
|
@@ -1128,7 +1117,7 @@
|
|
|
1128
1117
|
/* --------------------- Toolbar -------------------- */
|
|
1129
1118
|
|
|
1130
1119
|
/* Wide container */
|
|
1131
|
-
.tlui-toolbar {
|
|
1120
|
+
.tlui-main-toolbar {
|
|
1132
1121
|
grid-column: 1 / span 3;
|
|
1133
1122
|
grid-row: 1;
|
|
1134
1123
|
display: flex;
|
|
@@ -1139,7 +1128,7 @@
|
|
|
1139
1128
|
}
|
|
1140
1129
|
|
|
1141
1130
|
/* Centered Content */
|
|
1142
|
-
.tlui-toolbar__inner {
|
|
1131
|
+
.tlui-main-toolbar__inner {
|
|
1143
1132
|
position: relative;
|
|
1144
1133
|
width: fit-content;
|
|
1145
1134
|
display: flex;
|
|
@@ -1147,12 +1136,12 @@
|
|
|
1147
1136
|
align-items: flex-end;
|
|
1148
1137
|
}
|
|
1149
1138
|
|
|
1150
|
-
.tlui-toolbar__left {
|
|
1139
|
+
.tlui-main-toolbar__left {
|
|
1151
1140
|
width: fit-content;
|
|
1152
1141
|
}
|
|
1153
1142
|
|
|
1154
1143
|
/* Row of controls + lock button */
|
|
1155
|
-
.tlui-toolbar__extras {
|
|
1144
|
+
.tlui-main-toolbar__extras {
|
|
1156
1145
|
position: relative;
|
|
1157
1146
|
z-index: var(--layer-above);
|
|
1158
1147
|
width: 100%;
|
|
@@ -1161,11 +1150,11 @@
|
|
|
1161
1150
|
height: 48px;
|
|
1162
1151
|
}
|
|
1163
1152
|
|
|
1164
|
-
.tlui-toolbar__extras:empty {
|
|
1153
|
+
.tlui-main-toolbar__extras:empty {
|
|
1165
1154
|
display: none;
|
|
1166
1155
|
}
|
|
1167
1156
|
|
|
1168
|
-
.tlui-toolbar__extras__controls {
|
|
1157
|
+
.tlui-main-toolbar__extras__controls {
|
|
1169
1158
|
display: flex;
|
|
1170
1159
|
position: relative;
|
|
1171
1160
|
flex-direction: row;
|
|
@@ -1180,7 +1169,7 @@
|
|
|
1180
1169
|
width: fit-content;
|
|
1181
1170
|
}
|
|
1182
1171
|
|
|
1183
|
-
.tlui-toolbar__tools {
|
|
1172
|
+
.tlui-main-toolbar__tools {
|
|
1184
1173
|
display: flex;
|
|
1185
1174
|
flex-direction: row;
|
|
1186
1175
|
align-items: center;
|
|
@@ -1191,35 +1180,57 @@
|
|
|
1191
1180
|
background: var(--color-panel);
|
|
1192
1181
|
box-shadow: var(--shadow-2);
|
|
1193
1182
|
}
|
|
1194
|
-
.tlui-toolbar__tools__list {
|
|
1195
|
-
display: flex;
|
|
1196
|
-
flex-direction: row;
|
|
1197
|
-
align-items: center;
|
|
1198
|
-
}
|
|
1199
1183
|
|
|
1200
|
-
.tlui-toolbar__overflow {
|
|
1184
|
+
.tlui-main-toolbar__overflow {
|
|
1201
1185
|
width: 40px;
|
|
1186
|
+
margin-left: 2px;
|
|
1202
1187
|
}
|
|
1203
1188
|
|
|
1204
|
-
.tlui-layout__mobile .tlui-toolbar__overflow {
|
|
1189
|
+
.tlui-layout__mobile .tlui-main-toolbar__overflow {
|
|
1205
1190
|
width: 32px;
|
|
1206
1191
|
padding: 0px;
|
|
1207
1192
|
}
|
|
1208
1193
|
|
|
1209
|
-
.tlui-toolbar *[data-state='open']::after {
|
|
1194
|
+
.tlui-main-toolbar *[data-state='open']::after {
|
|
1210
1195
|
background: linear-gradient(0deg, rgba(144, 144, 144, 0) 0%, var(--color-muted-2) 100%);
|
|
1211
1196
|
opacity: 1;
|
|
1212
1197
|
}
|
|
1213
1198
|
|
|
1214
1199
|
@media (hover: hover) {
|
|
1215
|
-
.tlui-toolbar *[data-state='open']:not(:hover)::after {
|
|
1200
|
+
.tlui-main-toolbar *[data-state='open']:not(:hover)::after {
|
|
1216
1201
|
background: linear-gradient(0deg, rgba(144, 144, 144, 0) 0%, var(--color-muted-2) 100%);
|
|
1217
1202
|
opacity: 1;
|
|
1218
1203
|
}
|
|
1219
1204
|
}
|
|
1220
1205
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1206
|
+
/* ------------------- Tooltip -------------------- */
|
|
1207
|
+
|
|
1208
|
+
.tlui-tooltip {
|
|
1209
|
+
font-size: 12px;
|
|
1210
|
+
padding: 2px 8px;
|
|
1211
|
+
border-radius: 4px;
|
|
1212
|
+
background-color: var(--color-tooltip);
|
|
1213
|
+
box-shadow: none;
|
|
1214
|
+
color: var(--color-text-shadow);
|
|
1215
|
+
max-width: 400px;
|
|
1216
|
+
width: fit-content;
|
|
1217
|
+
text-align: center;
|
|
1218
|
+
pointer-events: none;
|
|
1219
|
+
will-change: transform, opacity;
|
|
1220
|
+
z-index: 2;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.tlui-tooltip__arrow {
|
|
1224
|
+
fill: var(--color-tooltip);
|
|
1225
|
+
will-change: opacity;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
[data-radix-popper-content-wrapper]:has(.tlui-tooltip) {
|
|
1229
|
+
z-index: var(--layer-toasts) !important;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
[data-radix-popper-content-wrapper]:has(.tlui-tooltip[data-should-animate='true']) {
|
|
1233
|
+
transition: all 0.1s ease-out;
|
|
1223
1234
|
}
|
|
1224
1235
|
|
|
1225
1236
|
/* ------------------- Debug panel ------------------ */
|
|
@@ -288,11 +288,13 @@ describe('When shapes are overlapping', () => {
|
|
|
288
288
|
editor.pointerDown(0, 50) // over nothing
|
|
289
289
|
editor.pointerMove(125, 50) // over box1 only
|
|
290
290
|
expect(bindings().end).toMatchObject({ toId: ids.box1 })
|
|
291
|
-
editor.pointerMove(175, 50) // box2 is higher but box1 is filled
|
|
291
|
+
editor.pointerMove(175, 50) // box2 is higher but box1 is filled, but we're on the edge ofd box 2
|
|
292
|
+
expect(bindings().end).toMatchObject({ toId: ids.box2 })
|
|
293
|
+
editor.pointerMove(175, 70) // box2 is higher but box1 is filled, and we're inside of box2
|
|
292
294
|
expect(bindings().end).toMatchObject({ toId: ids.box1 })
|
|
293
|
-
editor.pointerMove(225,
|
|
295
|
+
editor.pointerMove(225, 70) // box3 is higher
|
|
294
296
|
expect(bindings().end).toMatchObject({ toId: ids.box3 })
|
|
295
|
-
editor.pointerMove(275,
|
|
297
|
+
editor.pointerMove(275, 70) // box4 is higher but box 3 is filled
|
|
296
298
|
expect(bindings().end).toMatchObject({ toId: ids.box3 })
|
|
297
299
|
})
|
|
298
300
|
|
|
@@ -304,14 +306,18 @@ describe('When shapes are overlapping', () => {
|
|
|
304
306
|
])
|
|
305
307
|
editor.setCurrentTool('arrow')
|
|
306
308
|
editor.pointerDown(0, 50)
|
|
307
|
-
editor.pointerMove(175, 50) // box1 is smaller even though it's behind box2
|
|
309
|
+
editor.pointerMove(175, 50) // box1 is smaller even though it's behind box2, but we're on the edge of box 2
|
|
310
|
+
expect(bindings().end).toMatchObject({ toId: ids.box2 })
|
|
311
|
+
editor.pointerMove(175, 70) // box1 is smaller even though it's behind box2
|
|
308
312
|
expect(bindings().end).toMatchObject({ toId: ids.box1 })
|
|
309
|
-
editor.pointerMove(150, 90) // box3 is smaller and at the front
|
|
313
|
+
editor.pointerMove(150, 90) // box3 is smaller and at the front but we're on the edge of box 2
|
|
314
|
+
expect(bindings().end).toMatchObject({ toId: ids.box2 })
|
|
315
|
+
editor.pointerMove(160, 90) // box3 is smaller and at the front and we're in box1 and box 3 and box 2
|
|
310
316
|
expect(bindings().end).toMatchObject({ toId: ids.box3 })
|
|
311
317
|
editor.sendToBack([ids.box3])
|
|
312
318
|
editor.pointerMove(149, 90) // box3 is smaller, even when at the back
|
|
313
319
|
expect(bindings().end).toMatchObject({ toId: ids.box3 })
|
|
314
|
-
editor.pointerMove(175,
|
|
320
|
+
editor.pointerMove(175, 60) // inside of box1 and box 2, but box 1 is smaller
|
|
315
321
|
expect(bindings().end).toMatchObject({ toId: ids.box1 })
|
|
316
322
|
})
|
|
317
323
|
})
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { TLArrowShape, createShapeId } from '@tldraw/editor'
|
|
2
|
+
import { getArrowBindings } from '../lib/shapes/arrow/shared'
|
|
3
|
+
import { TestEditor } from './TestEditor'
|
|
4
|
+
|
|
5
|
+
let editor: TestEditor
|
|
6
|
+
|
|
7
|
+
const ids = {
|
|
8
|
+
solidShape: createShapeId('solidShape'),
|
|
9
|
+
hollowShape: createShapeId('hollowShape'),
|
|
10
|
+
arrow: createShapeId('arrow'),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const _arrow = () => editor.getOnlySelectedShape() as TLArrowShape
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
editor = new TestEditor()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('Inner/Outer Margin Shape Detection', () => {
|
|
20
|
+
describe('getShapeAtPoint with inner/outer margins', () => {
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
// Create a solid filled shape
|
|
23
|
+
editor.createShape({
|
|
24
|
+
id: ids.solidShape,
|
|
25
|
+
type: 'geo',
|
|
26
|
+
x: 100,
|
|
27
|
+
y: 100,
|
|
28
|
+
props: {
|
|
29
|
+
w: 100,
|
|
30
|
+
h: 100,
|
|
31
|
+
fill: 'solid',
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Create a hollow shape on top (same position, smaller size)
|
|
36
|
+
editor.createShape({
|
|
37
|
+
id: ids.hollowShape,
|
|
38
|
+
type: 'geo',
|
|
39
|
+
x: 125,
|
|
40
|
+
y: 125,
|
|
41
|
+
props: {
|
|
42
|
+
w: 50,
|
|
43
|
+
h: 50,
|
|
44
|
+
// No fill property - defaults to 'none' (hollow)
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should support inner/outer margin options', () => {
|
|
50
|
+
// Test that the new margin options are accepted
|
|
51
|
+
const point = { x: 150, y: 150 }
|
|
52
|
+
|
|
53
|
+
// Test with array margin [innerMargin, outerMargin]
|
|
54
|
+
const arrayMarginHit = editor.getShapeAtPoint(point, {
|
|
55
|
+
hitInside: true,
|
|
56
|
+
margin: [8, 4],
|
|
57
|
+
})
|
|
58
|
+
expect(arrayMarginHit).toBeDefined()
|
|
59
|
+
|
|
60
|
+
// Test with insideMargin option
|
|
61
|
+
const insideMarginHit = editor.getShapeAtPoint(point, {
|
|
62
|
+
hitInside: true,
|
|
63
|
+
})
|
|
64
|
+
expect(insideMarginHit).toBeDefined()
|
|
65
|
+
|
|
66
|
+
// Test with single number margin (should use same for both)
|
|
67
|
+
const singleMarginHit = editor.getShapeAtPoint(point, {
|
|
68
|
+
hitInside: true,
|
|
69
|
+
margin: 8,
|
|
70
|
+
})
|
|
71
|
+
expect(singleMarginHit).toBeDefined()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('should respect hitInside option for hollow shapes', () => {
|
|
75
|
+
const point = { x: 150, y: 150 }
|
|
76
|
+
|
|
77
|
+
// Without hitInside, should not hit hollow shape
|
|
78
|
+
const noHitInsideHit = editor.getShapeAtPoint(point, {
|
|
79
|
+
margin: [8, 0],
|
|
80
|
+
})
|
|
81
|
+
expect(noHitInsideHit?.id).toBe(ids.solidShape)
|
|
82
|
+
|
|
83
|
+
// With hitInside, should be able to hit hollow shape
|
|
84
|
+
const withHitInsideHit = editor.getShapeAtPoint(point, {
|
|
85
|
+
hitInside: true,
|
|
86
|
+
margin: [8, 0],
|
|
87
|
+
})
|
|
88
|
+
expect(withHitInsideHit).toBeDefined()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should handle edge cases correctly', () => {
|
|
92
|
+
// Test point exactly on the edge of hollow shape
|
|
93
|
+
const edgePoint = { x: 125, y: 150 }
|
|
94
|
+
|
|
95
|
+
const edgeHit = editor.getShapeAtPoint(edgePoint, {
|
|
96
|
+
hitInside: true,
|
|
97
|
+
margin: [8, 8],
|
|
98
|
+
})
|
|
99
|
+
expect(edgeHit).toBeDefined()
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe('Arrow binding with inner/outer margins', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
// Create a solid filled shape
|
|
106
|
+
editor.createShape({
|
|
107
|
+
id: ids.solidShape,
|
|
108
|
+
type: 'geo',
|
|
109
|
+
x: 100,
|
|
110
|
+
y: 100,
|
|
111
|
+
props: {
|
|
112
|
+
w: 100,
|
|
113
|
+
h: 100,
|
|
114
|
+
fill: 'solid',
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// Create a hollow shape on top (same position, smaller size)
|
|
119
|
+
editor.createShape({
|
|
120
|
+
id: ids.hollowShape,
|
|
121
|
+
type: 'geo',
|
|
122
|
+
x: 125,
|
|
123
|
+
y: 125,
|
|
124
|
+
props: {
|
|
125
|
+
w: 50,
|
|
126
|
+
h: 50,
|
|
127
|
+
// No fill property - defaults to 'none' (hollow)
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('should create arrow bindings with inner/outer margin support', () => {
|
|
133
|
+
editor.setCurrentTool('arrow')
|
|
134
|
+
|
|
135
|
+
// Start arrow outside both shapes
|
|
136
|
+
editor.pointerDown(50, 150)
|
|
137
|
+
|
|
138
|
+
// Move to center of hollow shape (which overlaps solid shape)
|
|
139
|
+
editor.pointerMove(150, 150)
|
|
140
|
+
editor.pointerUp()
|
|
141
|
+
|
|
142
|
+
const createdArrow = editor
|
|
143
|
+
.getCurrentPageShapes()
|
|
144
|
+
.find((s) => s.type === 'arrow') as TLArrowShape
|
|
145
|
+
expect(createdArrow).toBeDefined()
|
|
146
|
+
|
|
147
|
+
const arrowBindings = getArrowBindings(editor, createdArrow)
|
|
148
|
+
expect(arrowBindings.end).toBeDefined()
|
|
149
|
+
// The binding should be to one of the shapes
|
|
150
|
+
expect([ids.solidShape, ids.hollowShape]).toContain(arrowBindings.end?.toId)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('should bind to solid shape when no hollow shape is present', () => {
|
|
154
|
+
// Remove the hollow shape
|
|
155
|
+
editor.deleteShape(ids.hollowShape)
|
|
156
|
+
|
|
157
|
+
editor.setCurrentTool('arrow')
|
|
158
|
+
|
|
159
|
+
// Start arrow outside shape
|
|
160
|
+
editor.pointerDown(50, 150)
|
|
161
|
+
|
|
162
|
+
// Move to center of solid shape
|
|
163
|
+
editor.pointerMove(150, 150)
|
|
164
|
+
editor.pointerUp()
|
|
165
|
+
|
|
166
|
+
const createdArrow = editor
|
|
167
|
+
.getCurrentPageShapes()
|
|
168
|
+
.find((s) => s.type === 'arrow') as TLArrowShape
|
|
169
|
+
expect(createdArrow).toBeDefined()
|
|
170
|
+
|
|
171
|
+
const arrowBindings = getArrowBindings(editor, createdArrow)
|
|
172
|
+
expect(arrowBindings.end).toBeDefined()
|
|
173
|
+
expect(arrowBindings.end?.toId).toBe(ids.solidShape)
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
describe('Complex overlapping scenarios', () => {
|
|
178
|
+
it('should handle multiple overlapping shapes correctly', () => {
|
|
179
|
+
// Create multiple shapes with different fill states
|
|
180
|
+
editor.createShape({
|
|
181
|
+
id: ids.solidShape,
|
|
182
|
+
type: 'geo',
|
|
183
|
+
x: 100,
|
|
184
|
+
y: 100,
|
|
185
|
+
props: {
|
|
186
|
+
w: 100,
|
|
187
|
+
h: 100,
|
|
188
|
+
fill: 'solid',
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
editor.createShape({
|
|
193
|
+
id: ids.hollowShape,
|
|
194
|
+
type: 'geo',
|
|
195
|
+
x: 125,
|
|
196
|
+
y: 125,
|
|
197
|
+
props: {
|
|
198
|
+
w: 50,
|
|
199
|
+
h: 50,
|
|
200
|
+
// No fill property - defaults to 'none' (hollow)
|
|
201
|
+
},
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
// Create another hollow shape
|
|
205
|
+
const hollowShape2 = createShapeId('hollowShape2')
|
|
206
|
+
editor.createShape({
|
|
207
|
+
id: hollowShape2,
|
|
208
|
+
type: 'geo',
|
|
209
|
+
x: 140,
|
|
210
|
+
y: 140,
|
|
211
|
+
props: {
|
|
212
|
+
w: 30,
|
|
213
|
+
h: 30,
|
|
214
|
+
// No fill property - defaults to 'none' (hollow)
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
// Test point in the innermost hollow shape
|
|
219
|
+
const point = { x: 155, y: 155 }
|
|
220
|
+
|
|
221
|
+
const hit = editor.getShapeAtPoint(point, {
|
|
222
|
+
hitInside: true,
|
|
223
|
+
margin: [8, 8],
|
|
224
|
+
})
|
|
225
|
+
expect(hit).toBeDefined()
|
|
226
|
+
// Should hit one of the shapes
|
|
227
|
+
expect([ids.solidShape, ids.hollowShape, hollowShape2]).toContain(hit?.id)
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('should handle shapes with different geometries', () => {
|
|
231
|
+
// Create a solid rectangle
|
|
232
|
+
editor.createShape({
|
|
233
|
+
id: ids.solidShape,
|
|
234
|
+
type: 'geo',
|
|
235
|
+
x: 100,
|
|
236
|
+
y: 100,
|
|
237
|
+
props: {
|
|
238
|
+
w: 100,
|
|
239
|
+
h: 100,
|
|
240
|
+
fill: 'solid',
|
|
241
|
+
},
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
// Create a hollow circle on top
|
|
245
|
+
editor.createShape({
|
|
246
|
+
id: ids.hollowShape,
|
|
247
|
+
type: 'geo',
|
|
248
|
+
x: 125,
|
|
249
|
+
y: 125,
|
|
250
|
+
props: {
|
|
251
|
+
w: 50,
|
|
252
|
+
h: 50,
|
|
253
|
+
geo: 'ellipse',
|
|
254
|
+
// No fill property - defaults to 'none' (hollow)
|
|
255
|
+
},
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
// Test point inside the circle
|
|
259
|
+
const point = { x: 150, y: 150 }
|
|
260
|
+
|
|
261
|
+
const hit = editor.getShapeAtPoint(point, {
|
|
262
|
+
hitInside: true,
|
|
263
|
+
margin: [8, 8],
|
|
264
|
+
})
|
|
265
|
+
expect(hit).toBeDefined()
|
|
266
|
+
// Should hit one of the shapes
|
|
267
|
+
expect([ids.solidShape, ids.hollowShape]).toContain(hit?.id)
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe('Regression tests for the original bug', () => {
|
|
272
|
+
it('should support binding to hollow shapes when overlapping solid shapes', () => {
|
|
273
|
+
// This test verifies that the infrastructure exists for the bug fix
|
|
274
|
+
// Create a solid shape
|
|
275
|
+
editor.createShape({
|
|
276
|
+
id: ids.solidShape,
|
|
277
|
+
type: 'geo',
|
|
278
|
+
x: 100,
|
|
279
|
+
y: 100,
|
|
280
|
+
props: {
|
|
281
|
+
w: 100,
|
|
282
|
+
h: 100,
|
|
283
|
+
fill: 'solid',
|
|
284
|
+
},
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
// Create a hollow shape on top
|
|
288
|
+
editor.createShape({
|
|
289
|
+
id: ids.hollowShape,
|
|
290
|
+
type: 'geo',
|
|
291
|
+
x: 125,
|
|
292
|
+
y: 125,
|
|
293
|
+
props: {
|
|
294
|
+
w: 50,
|
|
295
|
+
h: 50,
|
|
296
|
+
// No fill property - defaults to 'none' (hollow)
|
|
297
|
+
},
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
// Test that we can detect both shapes
|
|
301
|
+
const point = { x: 150, y: 150 }
|
|
302
|
+
|
|
303
|
+
// Should be able to hit the solid shape without hitInside
|
|
304
|
+
const solidHit = editor.getShapeAtPoint(point)
|
|
305
|
+
expect(solidHit?.id).toBe(ids.solidShape)
|
|
306
|
+
|
|
307
|
+
// Should be able to hit the hollow shape with hitInside and inner margin
|
|
308
|
+
const hollowHit = editor.getShapeAtPoint(point, {
|
|
309
|
+
hitInside: true,
|
|
310
|
+
margin: [8, 0],
|
|
311
|
+
})
|
|
312
|
+
expect(hollowHit).toBeDefined()
|
|
313
|
+
})
|
|
314
|
+
})
|
|
315
|
+
})
|