[3/3] Highlighter styling (#1490)
This PR finalises the highlighter shape with new colors, sizing, and perfect freehand options. The colors are based on our existing colour palette, but take advantage of wide-gamut displays to make the highlighter highlightier. I used my [oklch color palette tool to pick the palette](https://alex.dytry.ch/toys/palette/?palette=%7B%22families%22:%5B%22black%22,%22grey%22,%22white%22,%22green%22,%22light-green%22,%22blue%22,%22light-blue%22,%22violet%22,%22light-violet%22,%22red%22,%22light-red%22,%22orange%22,%22yellow%22%5D,%22shades%22:%5B%22light-mode%22,%22dark-mode%22,%22hl-light%22,%22hl-dark%22%5D,%22colors%22:%5B%5B%5B0.2308,0,null%5D,%5B0.9097,0,null%5D,%5B0.2308,0,null%5D,%5B0.2308,0,null%5D%5D,%5B%5B0.7692,0.0145,248.02%5D,%5B0.6778,0.0118,256.72%5D,%5B0.7692,0.0145,248.02%5D,%5B0.7692,0.0145,248.02%5D%5D,%5B%5B1,0,null%5D,%5B0.2308,0,null%5D,%5B1,0,null%5D,%5B1,0,null%5D%5D,%5B%5B0.5851,0.1227,164.1%5D,%5B0.5319,0.0811,162.23%5D,%5B0.8729,0.2083,173.3%5D,%5B0.5851,0.152,173.3%5D%5D,%5B%5B0.7146,0.1835,146.44%5D,%5B0.6384,0.1262,143.36%5D,%5B0.8603,0.2438,140.11%5D,%5B0.6082,0.2286,140.11%5D%5D,%5B%5B0.5566,0.2082,268.35%5D,%5B0.4961,0.1644,270.65%5D,%5B0.7158,0.173,243.85%5D,%5B0.5573,0.178,243.85%5D%5D,%5B%5B0.718,0.1422,246.06%5D,%5B0.6366,0.1055,250.98%5D,%5B0.8615,0.1896,200.03%5D,%5B0.707,0.161,200.03%5D%5D,%5B%5B0.5783,0.2186,319.15%5D,%5B0.5043,0.1647,315.37%5D,%5B0.728,0.2001,307.45%5D,%5B0.5433,0.2927,307.45%5D%5D,%5B%5B0.7904,0.1516,319.77%5D,%5B0.6841,0.1139,315.99%5D,%5B0.812,0.21,327.8%5D,%5B0.5668,0.281,327.8%5D%5D,%5B%5B0.5928,0.2106,26.53%5D,%5B0.5112,0.1455,26.18%5D,%5B0.7326,0.21,20.59%5D,%5B0.554,0.2461,20.59%5D%5D,%5B%5B0.7563,0.146,21.1%5D,%5B0.6561,0.0982,20.86%5D,%5B0.7749,0.178,6.8%5D,%5B0.5565,0.2454,6.8%5D%5D,%5B%5B0.6851,0.1954,44.57%5D,%5B0.5958,0.1366,46.6%5D,%5B0.8207,0.175,68.62%5D,%5B0.6567,0.164,68.61%5D%5D,%5B%5B0.8503,0.1149,68.95%5D,%5B0.7404,0.0813,72.25%5D,%5B0.8939,0.2137,100.36%5D,%5B0.7776,0.186,100.36%5D%5D%5D%7D&selected=3). I'm not sure happy about these colors as they are right now - in particular, i think dark mode looks a bit rubbish and there are a few colors where the highlight and original version are much too similar (light-violet & light-red). Black uses yellow (like note shape) and grey uses light-blue. Exports are forced into srgb color space rather than P3 for maximum compatibility. ![image](https://github.com/tldraw/tldraw/assets/1489520/e3de762b-6ef7-4d17-87db-3e2b71dd8de1) ![image](https://github.com/tldraw/tldraw/assets/1489520/3bd90aa9-bdbc-4a2b-9e56-e3a83a2a877b) The size of a highlighter stroke is now based on the text size which works nicely for making the highlighter play well with text: ![image](https://github.com/tldraw/tldraw/assets/1489520/dd3184fc-decd-4db5-90ce-e9cc75edd3d6) Perfect freehands settings are very similar to the draw tool, but with the thinning turned way down. There is still some, but it's pretty minimal. ### The plan 1. initial highlighter shape/tool #1401 2. sandwich rendering for highlighter shapes #1418 3. shape styling - new colours and sizes, lightweight perfect freehand changes #1490 **>you are here<** ### Change Type - [x] `minor` — New Feature ### Test Plan 1. You can find the highlighter tool in the extended toolbar 2. You can activate the highlighter tool by pressing shift-D 3. Highlighter draws nice and vibrantly when over the page background or frame background 4. Highlighter is less vibrant but still visible when drawn over images / other fills 5. Highlighter size should nicely match the corresponding unscaled text size 6. Exports with highlighter look as expected ### Release Notes Highlighter pen is here! 🎉🎉🎉 --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This commit is contained in:
parent
a11a741de4
commit
d6085e4ea6
23 changed files with 211 additions and 107 deletions
|
@ -1,4 +1,4 @@
|
||||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M7.5 24.5C8 24 9.3 23 10.5 23C11.3229 23 12.1927 23.1567 12.8195 23.309C13.2406 23.4113 13.6936 23.3064 14 23V23M7.5 24.5L6.5 23.5L5.5 22.5M7.5 24.5L6.5 25.5L3.5 24.5L5.5 22.5M7.5 24.5L5.5 22.5M5.5 22.5C6 22 7 20.7 7 19.5C7 18.6771 6.84326 17.8073 6.69101 17.1805C6.5887 16.7594 6.69357 16.3064 7 16V16M7 16L18.5858 4.41421C19.3668 3.63317 20.6332 3.63317 21.4142 4.41421L25.5858 8.58579C26.3668 9.36684 26.3668 10.6332 25.5858 11.4142L14 23M7 16L14 23" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M13.1024 25.123L26.6953 10.412C27.424 9.62334 27.3999 8.39987 26.6405 7.64054L23.3649 4.36488C22.6034 3.60337 21.3756 3.58158 20.5875 4.31559L5.98401 17.9175M13.1024 25.123L5.98401 17.9175M13.1024 25.123C12.6024 24.9563 11.3025 24.5374 10.1025 24.5374C8.90254 24.5374 7.60254 25.5374 7.10254 26.0374M5.98401 17.9175C6.15068 18.4175 6.60254 19.8374 6.60254 21.0374C6.60254 22.2374 5.60254 23.5374 5.10254 24.0374M7.10254 26.0374L6.10254 25.0374L5.10254 24.0374M7.10254 26.0374L6.10254 27.0374L2 27.1399L5.10254 24.0374" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M3.5 24.5L5.5 22.5L7.5 24.5L6.5 25.5L3.5 24.5Z" fill="black"/>
|
<path d="M2 26L4 24L6 26L5 27L2 26Z" fill="black"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
Before Width: | Height: | Size: 719 B After Width: | Height: | Size: 764 B |
|
@ -1,3 +0,0 @@
|
||||||
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M11.6041 25.123L27.1506 9.55414L20.0322 2.34865L4.48573 17.9175M11.6041 25.123L7.78596 26.7594L2.84937 21.7357L4.48573 17.9175M11.6041 25.123L4.48573 17.9175" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 352 B |
1
packages/assets/imports.d.ts
vendored
1
packages/assets/imports.d.ts
vendored
|
@ -151,7 +151,6 @@ export function getAssetUrlsByImport(opts?: AssetUrlOptions): {
|
||||||
'tool-frame': string
|
'tool-frame': string
|
||||||
'tool-hand': string
|
'tool-hand': string
|
||||||
'tool-highlight': string
|
'tool-highlight': string
|
||||||
'tool-highlighter': string
|
|
||||||
'tool-laser': string
|
'tool-laser': string
|
||||||
'tool-line': string
|
'tool-line': string
|
||||||
'tool-media': string
|
'tool-media': string
|
||||||
|
|
|
@ -162,7 +162,6 @@ import iconsToolEraser from './icons/icon/tool-eraser.svg'
|
||||||
import iconsToolFrame from './icons/icon/tool-frame.svg'
|
import iconsToolFrame from './icons/icon/tool-frame.svg'
|
||||||
import iconsToolHand from './icons/icon/tool-hand.svg'
|
import iconsToolHand from './icons/icon/tool-hand.svg'
|
||||||
import iconsToolHighlight from './icons/icon/tool-highlight.svg'
|
import iconsToolHighlight from './icons/icon/tool-highlight.svg'
|
||||||
import iconsToolHighlighter from './icons/icon/tool-highlighter.svg'
|
|
||||||
import iconsToolLaser from './icons/icon/tool-laser.svg'
|
import iconsToolLaser from './icons/icon/tool-laser.svg'
|
||||||
import iconsToolLine from './icons/icon/tool-line.svg'
|
import iconsToolLine from './icons/icon/tool-line.svg'
|
||||||
import iconsToolMedia from './icons/icon/tool-media.svg'
|
import iconsToolMedia from './icons/icon/tool-media.svg'
|
||||||
|
@ -394,7 +393,6 @@ export function getAssetUrlsByImport(opts) {
|
||||||
'tool-frame': formatAssetUrl(iconsToolFrame, opts),
|
'tool-frame': formatAssetUrl(iconsToolFrame, opts),
|
||||||
'tool-hand': formatAssetUrl(iconsToolHand, opts),
|
'tool-hand': formatAssetUrl(iconsToolHand, opts),
|
||||||
'tool-highlight': formatAssetUrl(iconsToolHighlight, opts),
|
'tool-highlight': formatAssetUrl(iconsToolHighlight, opts),
|
||||||
'tool-highlighter': formatAssetUrl(iconsToolHighlighter, opts),
|
|
||||||
'tool-laser': formatAssetUrl(iconsToolLaser, opts),
|
'tool-laser': formatAssetUrl(iconsToolLaser, opts),
|
||||||
'tool-line': formatAssetUrl(iconsToolLine, opts),
|
'tool-line': formatAssetUrl(iconsToolLine, opts),
|
||||||
'tool-media': formatAssetUrl(iconsToolMedia, opts),
|
'tool-media': formatAssetUrl(iconsToolMedia, opts),
|
||||||
|
|
1
packages/assets/urls.d.ts
vendored
1
packages/assets/urls.d.ts
vendored
|
@ -151,7 +151,6 @@ export function getAssetUrlsByMetaUrl(opts?: AssetUrlOptions): {
|
||||||
'tool-frame': string
|
'tool-frame': string
|
||||||
'tool-hand': string
|
'tool-hand': string
|
||||||
'tool-highlight': string
|
'tool-highlight': string
|
||||||
'tool-highlighter': string
|
|
||||||
'tool-laser': string
|
'tool-laser': string
|
||||||
'tool-line': string
|
'tool-line': string
|
||||||
'tool-media': string
|
'tool-media': string
|
||||||
|
|
|
@ -498,10 +498,6 @@ export function getAssetUrlsByMetaUrl(opts) {
|
||||||
new URL('./icons/icon/tool-highlight.svg', import.meta.url).href,
|
new URL('./icons/icon/tool-highlight.svg', import.meta.url).href,
|
||||||
opts
|
opts
|
||||||
),
|
),
|
||||||
'tool-highlighter': formatAssetUrl(
|
|
||||||
new URL('./icons/icon/tool-highlighter.svg', import.meta.url).href,
|
|
||||||
opts
|
|
||||||
),
|
|
||||||
'tool-laser': formatAssetUrl(
|
'tool-laser': formatAssetUrl(
|
||||||
new URL('./icons/icon/tool-laser.svg', import.meta.url).href,
|
new URL('./icons/icon/tool-laser.svg', import.meta.url).href,
|
||||||
opts
|
opts
|
||||||
|
|
|
@ -634,6 +634,7 @@ export const debugFlags: {
|
||||||
logMessages: DebugFlag<never[]>;
|
logMessages: DebugFlag<never[]>;
|
||||||
resetConnectionEveryPing: DebugFlag<boolean>;
|
resetConnectionEveryPing: DebugFlag<boolean>;
|
||||||
debugCursors: DebugFlag<boolean>;
|
debugCursors: DebugFlag<boolean>;
|
||||||
|
forceSrgb: DebugFlag<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// @internal (undocumented)
|
// @internal (undocumented)
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
/*
|
||||||
|
https://alex.dytry.ch/toys/palette/?palette=%7B%22families%22:%5B%22black%22,%22grey%22,%22white%22,%22green%22,%22light-green%22,%22blue%22,%22light-blue%22,%22violet%22,%22light-violet%22,%22red%22,%22light-red%22,%22orange%22,%22yellow%22%5D,%22shades%22:%5B%22light-mode%22,%22dark-mode%22,%22hl-light%22,%22hl-dark%22%5D,%22colors%22:%5B%5B%5B0.2308,0,null%5D,%5B0.9097,0,null%5D,%5B0.2308,0,null%5D,%5B0.2308,0,null%5D%5D,%5B%5B0.7692,0.0145,248.02%5D,%5B0.6778,0.0118,256.72%5D,%5B0.7692,0.0145,248.02%5D,%5B0.7692,0.0145,248.02%5D%5D,%5B%5B1,0,null%5D,%5B0.2308,0,null%5D,%5B1,0,null%5D,%5B1,0,null%5D%5D,%5B%5B0.5851,0.1227,164.1%5D,%5B0.5319,0.0811,162.23%5D,%5B0.8729,0.2083,173.3%5D,%5B0.5851,0.152,173.3%5D%5D,%5B%5B0.7146,0.1835,146.44%5D,%5B0.6384,0.1262,143.36%5D,%5B0.8603,0.2438,140.11%5D,%5B0.6082,0.2286,140.11%5D%5D,%5B%5B0.5566,0.2082,268.35%5D,%5B0.4961,0.1644,270.65%5D,%5B0.7158,0.173,243.85%5D,%5B0.5573,0.178,243.85%5D%5D,%5B%5B0.718,0.1422,246.06%5D,%5B0.6366,0.1055,250.98%5D,%5B0.8615,0.1896,200.03%5D,%5B0.707,0.161,200.03%5D%5D,%5B%5B0.5783,0.2186,319.15%5D,%5B0.5043,0.1647,315.37%5D,%5B0.728,0.2001,307.45%5D,%5B0.5433,0.2927,307.45%5D%5D,%5B%5B0.7904,0.1516,319.77%5D,%5B0.6841,0.1139,315.99%5D,%5B0.812,0.21,327.8%5D,%5B0.5668,0.281,327.8%5D%5D,%5B%5B0.5928,0.2106,26.53%5D,%5B0.5112,0.1455,26.18%5D,%5B0.7326,0.21,20.59%5D,%5B0.554,0.2461,20.59%5D%5D,%5B%5B0.7563,0.146,21.1%5D,%5B0.6561,0.0982,20.86%5D,%5B0.7749,0.178,6.8%5D,%5B0.5565,0.2454,6.8%5D%5D,%5B%5B0.6851,0.1954,44.57%5D,%5B0.5958,0.1366,46.6%5D,%5B0.8207,0.175,68.62%5D,%5B0.6567,0.164,68.61%5D%5D,%5B%5B0.8503,0.1149,68.95%5D,%5B0.7404,0.0813,72.25%5D,%5B0.8939,0.2137,100.36%5D,%5B0.7776,0.186,100.36%5D%5D%5D%7D&selected=3
|
||||||
|
*/
|
||||||
|
|
||||||
.tl-container {
|
.tl-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -142,6 +146,21 @@
|
||||||
--palette-violet-pattern: #bd63d3;
|
--palette-violet-pattern: #bd63d3;
|
||||||
--palette-white-pattern: #ffffff;
|
--palette-white-pattern: #ffffff;
|
||||||
--palette-yellow-pattern: #fecb92;
|
--palette-yellow-pattern: #fecb92;
|
||||||
|
|
||||||
|
/* for highlighter pen */
|
||||||
|
--palette-black-highlight: #fddd00;
|
||||||
|
--palette-grey-highlight: #cbe7f1;
|
||||||
|
--palette-green-highlight: #00ffc8;
|
||||||
|
--palette-light-green-highlight: #65f641;
|
||||||
|
--palette-blue-highlight: #10acff;
|
||||||
|
--palette-light-blue-highlight: #00f4ff;
|
||||||
|
--palette-violet-highlight: #c77cff;
|
||||||
|
--palette-light-violet-highlight: #ff88ff;
|
||||||
|
--palette-red-highlight: #ff636e;
|
||||||
|
--palette-light-red-highlight: #ff7fa3;
|
||||||
|
--palette-orange-highlight: #ffa500;
|
||||||
|
--palette-yellow-highlight: #fddd00;
|
||||||
|
|
||||||
--shadow-1: 0px 1px 2px rgba(0, 0, 0, 0.22), 0px 1px 3px rgba(0, 0, 0, 0.09);
|
--shadow-1: 0px 1px 2px rgba(0, 0, 0, 0.22), 0px 1px 3px rgba(0, 0, 0, 0.09);
|
||||||
--shadow-2: 0px 0px 2px rgba(0, 0, 0, 0.12), 0px 2px 3px rgba(0, 0, 0, 0.24),
|
--shadow-2: 0px 0px 2px rgba(0, 0, 0, 0.12), 0px 2px 3px rgba(0, 0, 0, 0.24),
|
||||||
0px 2px 6px rgba(0, 0, 0, 0.1), inset 0px 0px 0px 1px var(--color-panel-contrast);
|
0px 2px 6px rgba(0, 0, 0, 0.1), inset 0px 0px 0px 1px var(--color-panel-contrast);
|
||||||
|
@ -210,6 +229,7 @@
|
||||||
--palette-violet-semi: #31293c;
|
--palette-violet-semi: #31293c;
|
||||||
--palette-white-semi: #ffffff;
|
--palette-white-semi: #ffffff;
|
||||||
--palette-yellow-semi: #3c3934;
|
--palette-yellow-semi: #3c3934;
|
||||||
|
|
||||||
/* for fill style 'pattern' */
|
/* for fill style 'pattern' */
|
||||||
--palette-black-pattern: #989898;
|
--palette-black-pattern: #989898;
|
||||||
--palette-blue-pattern: #3a4b9e;
|
--palette-blue-pattern: #3a4b9e;
|
||||||
|
@ -224,6 +244,21 @@
|
||||||
--palette-violet-pattern: #763a8b;
|
--palette-violet-pattern: #763a8b;
|
||||||
--palette-white-pattern: #ffffff;
|
--palette-white-pattern: #ffffff;
|
||||||
--palette-yellow-pattern: #fecb92;
|
--palette-yellow-pattern: #fecb92;
|
||||||
|
|
||||||
|
/* for highlighter pen */
|
||||||
|
--palette-black-highlight: #d2b700;
|
||||||
|
--palette-grey-highlight: #9cb4cb;
|
||||||
|
--palette-green-highlight: #009774;
|
||||||
|
--palette-light-green-highlight: #00a000;
|
||||||
|
--palette-blue-highlight: #0079d2;
|
||||||
|
--palette-light-blue-highlight: #00bdc8;
|
||||||
|
--palette-violet-highlight: #9e00ee;
|
||||||
|
--palette-light-violet-highlight: #c400c7;
|
||||||
|
--palette-red-highlight: #de002c;
|
||||||
|
--palette-light-red-highlight: #db005b;
|
||||||
|
--palette-orange-highlight: #d07a00;
|
||||||
|
--palette-yellow-highlight: #d2b700;
|
||||||
|
|
||||||
--shadow-1: 0px 1px 2px #00000029, 0px 1px 3px #00000038,
|
--shadow-1: 0px 1px 2px #00000029, 0px 1px 3px #00000038,
|
||||||
inset 0px 0px 0px 1px var(--color-panel-contrast);
|
inset 0px 0px 0px 1px var(--color-panel-contrast);
|
||||||
--shadow-2: 0px 1px 3px #00000077, 0px 2px 6px #00000055,
|
--shadow-2: 0px 1px 3px #00000077, 0px 2px 6px #00000055,
|
||||||
|
@ -232,6 +267,41 @@
|
||||||
inset 0px 0px 0px 1px var(--color-panel-contrast);
|
inset 0px 0px 0px 1px var(--color-panel-contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** p3 colors */
|
||||||
|
@media (color-gamut: p3) {
|
||||||
|
.tl-theme__light:not(.tl-theme__force-sRGB) {
|
||||||
|
/* for highlighter pen */
|
||||||
|
--palette-black-highlight: color(display-p3 0.972 0.8705 0.05);
|
||||||
|
--palette-grey-highlight: color(display-p3 0.8163 0.9023 0.9416);
|
||||||
|
--palette-green-highlight: color(display-p3 0.2536 0.984 0.7981);
|
||||||
|
--palette-light-green-highlight: color(display-p3 0.563 0.9495 0.3857);
|
||||||
|
--palette-blue-highlight: color(display-p3 0.308 0.6632 0.9996);
|
||||||
|
--palette-light-blue-highlight: color(display-p3 0.1512 0.9414 0.9996);
|
||||||
|
--palette-violet-highlight: color(display-p3 0.7469 0.5089 0.9995);
|
||||||
|
--palette-light-violet-highlight: color(display-p3 0.9676 0.5652 0.9999);
|
||||||
|
--palette-red-highlight: color(display-p3 0.9992 0.4376 0.45);
|
||||||
|
--palette-light-red-highlight: color(display-p3 0.9988 0.5301 0.6397);
|
||||||
|
--palette-orange-highlight: color(display-p3 0.9988 0.6905 0.266);
|
||||||
|
--palette-yellow-highlight: color(display-p3 0.972 0.8705 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tl-theme__dark:not(.tl-theme__force-sRGB) {
|
||||||
|
/* for highlighter pen */
|
||||||
|
--palette-black-highlight: color(display-p3 0.8078 0.7225 0.0312);
|
||||||
|
--palette-grey-highlight: color(display-p3 0.6299 0.7012 0.7856);
|
||||||
|
--palette-green-highlight: color(display-p3 0.0085 0.582 0.4604);
|
||||||
|
--palette-light-green-highlight: color(display-p3 0.2711 0.6172 0.0195);
|
||||||
|
--palette-blue-highlight: color(display-p3 0.0032 0.4655 0.7991);
|
||||||
|
--palette-light-blue-highlight: color(display-p3 0.0023 0.7259 0.7735);
|
||||||
|
--palette-violet-highlight: color(display-p3 0.5651 0.0079 0.8986);
|
||||||
|
--palette-light-violet-highlight: color(display-p3 0.7024 0.0403 0.753);
|
||||||
|
--palette-red-highlight: color(display-p3 0.7978 0.0509 0.2035);
|
||||||
|
--palette-light-red-highlight: color(display-p3 0.7849 0.0585 0.3589);
|
||||||
|
--palette-orange-highlight: color(display-p3 0.7699 0.4937 0.0085);
|
||||||
|
--palette-yellow-highlight: color(display-p3 0.8078 0.7225 0.0312);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tl-counter-scaled {
|
.tl-counter-scaled {
|
||||||
transform: scale(var(--tl-scale));
|
transform: scale(var(--tl-scale));
|
||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
|
|
|
@ -5617,7 +5617,9 @@ export class App extends EventEmitter<TLEventMap> {
|
||||||
// Get the styles from the container. We'll use these to pull out colors etc.
|
// Get the styles from the container. We'll use these to pull out colors etc.
|
||||||
// NOTE: We can force force a light theme here becasue we don't want export
|
// NOTE: We can force force a light theme here becasue we don't want export
|
||||||
const fakeContainerEl = document.createElement('div')
|
const fakeContainerEl = document.createElement('div')
|
||||||
fakeContainerEl.className = `tl-container tl-theme__${darkMode ? 'dark' : 'light'}`
|
fakeContainerEl.className = `tl-container tl-theme__${
|
||||||
|
darkMode ? 'dark' : 'light'
|
||||||
|
} tl-theme__force-sRGB`
|
||||||
document.body.appendChild(fakeContainerEl)
|
document.body.appendChild(fakeContainerEl)
|
||||||
|
|
||||||
const containerStyle = getComputedStyle(fakeContainerEl)
|
const containerStyle = getComputedStyle(fakeContainerEl)
|
||||||
|
@ -5642,6 +5644,12 @@ export class App extends EventEmitter<TLEventMap> {
|
||||||
containerStyle.getPropertyValue(`--palette-${color.id}-semi`),
|
containerStyle.getPropertyValue(`--palette-${color.id}-semi`),
|
||||||
])
|
])
|
||||||
) as Record<TLColorType, string>,
|
) as Record<TLColorType, string>,
|
||||||
|
highlight: Object.fromEntries(
|
||||||
|
STYLES.color.map((color) => [
|
||||||
|
color.id,
|
||||||
|
containerStyle.getPropertyValue(`--palette-${color.id}-highlight`),
|
||||||
|
])
|
||||||
|
) as Record<TLColorType, string>,
|
||||||
text: containerStyle.getPropertyValue(`--color-text`),
|
text: containerStyle.getPropertyValue(`--color-text`),
|
||||||
background: containerStyle.getPropertyValue(`--color-background`),
|
background: containerStyle.getPropertyValue(`--color-background`),
|
||||||
solid: containerStyle.getPropertyValue(`--palette-solid`),
|
solid: containerStyle.getPropertyValue(`--palette-solid`),
|
||||||
|
|
|
@ -23,10 +23,10 @@ import { getDrawShapeStrokeDashArray, getFreehandOptions, getPointsFromSegments
|
||||||
export class TLDrawUtil extends TLShapeUtil<TLDrawShape> {
|
export class TLDrawUtil extends TLShapeUtil<TLDrawShape> {
|
||||||
static override type = 'draw'
|
static override type = 'draw'
|
||||||
|
|
||||||
hideResizeHandles = (shape: TLDrawShape) => this.getIsDot(shape)
|
hideResizeHandles = (shape: TLDrawShape) => getIsDot(shape)
|
||||||
hideRotateHandle = (shape: TLDrawShape) => this.getIsDot(shape)
|
hideRotateHandle = (shape: TLDrawShape) => getIsDot(shape)
|
||||||
hideSelectionBoundsBg = (shape: TLDrawShape) => this.getIsDot(shape)
|
hideSelectionBoundsBg = (shape: TLDrawShape) => getIsDot(shape)
|
||||||
hideSelectionBoundsFg = (shape: TLDrawShape) => this.getIsDot(shape)
|
hideSelectionBoundsFg = (shape: TLDrawShape) => getIsDot(shape)
|
||||||
|
|
||||||
override defaultProps(): TLDrawShape['props'] {
|
override defaultProps(): TLDrawShape['props'] {
|
||||||
return {
|
return {
|
||||||
|
@ -44,10 +44,6 @@ export class TLDrawUtil extends TLShapeUtil<TLDrawShape> {
|
||||||
|
|
||||||
isClosed = (shape: TLDrawShape) => shape.props.isClosed
|
isClosed = (shape: TLDrawShape) => shape.props.isClosed
|
||||||
|
|
||||||
private getIsDot(shape: TLDrawShape) {
|
|
||||||
return shape.props.segments.length === 1 && shape.props.segments[0].points.length < 2
|
|
||||||
}
|
|
||||||
|
|
||||||
getBounds(shape: TLDrawShape) {
|
getBounds(shape: TLDrawShape) {
|
||||||
return Box2d.FromPoints(this.outline(shape))
|
return Box2d.FromPoints(this.outline(shape))
|
||||||
}
|
}
|
||||||
|
@ -310,3 +306,7 @@ function getDot(point: VecLike, sw: number) {
|
||||||
r * 2
|
r * 2
|
||||||
},0`
|
},0`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getIsDot(shape: TLDrawShape) {
|
||||||
|
return shape.props.segments.length === 1 && shape.props.segments[0].points.length < 2
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,21 @@ const solidSettings = (strokeWidth: number): StrokeOptions => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getHighlightFreehandSettings(
|
||||||
|
strokeWidth: number,
|
||||||
|
showAsComplete: boolean
|
||||||
|
): StrokeOptions {
|
||||||
|
return {
|
||||||
|
size: 1 + strokeWidth,
|
||||||
|
thinning: 0.1,
|
||||||
|
streamline: 0.1, // 0.62 + ((1 + strokeWidth) / 8) * 0.06,
|
||||||
|
smoothing: 0.5,
|
||||||
|
simulatePressure: true,
|
||||||
|
easing: EASINGS.easeOutSine,
|
||||||
|
last: showAsComplete,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getFreehandOptions(
|
export function getFreehandOptions(
|
||||||
shapeProps: { dash: TLDashType; isPen: boolean; isComplete: boolean },
|
shapeProps: { dash: TLDashType; isPen: boolean; isComplete: boolean },
|
||||||
strokeWidth: number,
|
strokeWidth: number,
|
||||||
|
|
|
@ -11,24 +11,25 @@ import {
|
||||||
import { TLDrawShapeSegment, TLHighlightShape } from '@tldraw/tlschema'
|
import { TLDrawShapeSegment, TLHighlightShape } from '@tldraw/tlschema'
|
||||||
import { last, rng } from '@tldraw/utils'
|
import { last, rng } from '@tldraw/utils'
|
||||||
import { SVGContainer } from '../../../components/SVGContainer'
|
import { SVGContainer } from '../../../components/SVGContainer'
|
||||||
|
import { FONT_SIZES } from '../../../constants'
|
||||||
import { getSvgPathFromStroke, getSvgPathFromStrokePoints } from '../../../utils/svg'
|
import { getSvgPathFromStroke, getSvgPathFromStrokePoints } from '../../../utils/svg'
|
||||||
import { App } from '../../App'
|
|
||||||
import { ShapeFill } from '../shared/ShapeFill'
|
import { ShapeFill } from '../shared/ShapeFill'
|
||||||
import { TLExportColors } from '../shared/TLExportColors'
|
import { TLExportColors } from '../shared/TLExportColors'
|
||||||
import { useForceSolid } from '../shared/useForceSolid'
|
import { useForceSolid } from '../shared/useForceSolid'
|
||||||
import { getFreehandOptions, getPointsFromSegments } from '../TLDrawUtil/getPath'
|
import { getHighlightFreehandSettings, getPointsFromSegments } from '../TLDrawUtil/getPath'
|
||||||
import { OnResizeHandler, TLShapeUtil } from '../TLShapeUtil'
|
import { OnResizeHandler, TLShapeUtil } from '../TLShapeUtil'
|
||||||
|
|
||||||
const OVERLAY_OPACITY = 0.4
|
const OVERLAY_OPACITY = 0.35
|
||||||
|
const UNDERLAY_OPACITY = 0.82
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
static type = 'highlight'
|
static type = 'highlight'
|
||||||
|
|
||||||
hideResizeHandles = (shape: TLHighlightShape) => this.getIsDot(shape)
|
hideResizeHandles = (shape: TLHighlightShape) => getIsDot(shape)
|
||||||
hideRotateHandle = (shape: TLHighlightShape) => this.getIsDot(shape)
|
hideRotateHandle = (shape: TLHighlightShape) => getIsDot(shape)
|
||||||
hideSelectionBoundsBg = (shape: TLHighlightShape) => this.getIsDot(shape)
|
hideSelectionBoundsBg = (shape: TLHighlightShape) => getIsDot(shape)
|
||||||
hideSelectionBoundsFg = (shape: TLHighlightShape) => this.getIsDot(shape)
|
hideSelectionBoundsFg = (shape: TLHighlightShape) => getIsDot(shape)
|
||||||
|
|
||||||
override defaultProps(): TLHighlightShape['props'] {
|
override defaultProps(): TLHighlightShape['props'] {
|
||||||
return {
|
return {
|
||||||
|
@ -41,10 +42,6 @@ export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getIsDot(shape: TLHighlightShape) {
|
|
||||||
return shape.props.segments.length === 1 && shape.props.segments[0].points.length < 2
|
|
||||||
}
|
|
||||||
|
|
||||||
getBounds(shape: TLHighlightShape) {
|
getBounds(shape: TLHighlightShape) {
|
||||||
return Box2d.FromPoints(this.outline(shape))
|
return Box2d.FromPoints(this.outline(shape))
|
||||||
}
|
}
|
||||||
|
@ -60,7 +57,7 @@ export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
hitTestPoint(shape: TLHighlightShape, point: VecLike): boolean {
|
hitTestPoint(shape: TLHighlightShape, point: VecLike): boolean {
|
||||||
const outline = this.outline(shape)
|
const outline = this.outline(shape)
|
||||||
const zoomLevel = this.app.zoomLevel
|
const zoomLevel = this.app.zoomLevel
|
||||||
const offsetDist = this.app.getStrokeWidth(shape.props.size) / zoomLevel
|
const offsetDist = getStrokeWidth(shape) / zoomLevel
|
||||||
|
|
||||||
if (shape.props.segments.length === 1 && shape.props.segments[0].points.length < 4) {
|
if (shape.props.segments.length === 1 && shape.props.segments[0].points.length < 4) {
|
||||||
if (shape.props.segments[0].points.some((pt) => Vec2d.Dist(point, pt) < offsetDist * 1.5)) {
|
if (shape.props.segments[0].points.some((pt) => Vec2d.Dist(point, pt) < offsetDist * 1.5)) {
|
||||||
|
@ -85,7 +82,7 @@ export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
|
|
||||||
if (shape.props.segments.length === 1 && shape.props.segments[0].points.length < 4) {
|
if (shape.props.segments.length === 1 && shape.props.segments[0].points.length < 4) {
|
||||||
const zoomLevel = this.app.zoomLevel
|
const zoomLevel = this.app.zoomLevel
|
||||||
const offsetDist = this.app.getStrokeWidth(shape.props.size) / zoomLevel
|
const offsetDist = getStrokeWidth(shape) / zoomLevel
|
||||||
|
|
||||||
if (
|
if (
|
||||||
shape.props.segments[0].points.some(
|
shape.props.segments[0].points.some(
|
||||||
|
@ -106,16 +103,28 @@ export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render(shape: TLHighlightShape) {
|
render(shape: TLHighlightShape) {
|
||||||
return <HighlightRenderer app={this.app} shape={shape} opacity={OVERLAY_OPACITY} />
|
return (
|
||||||
|
<HighlightRenderer
|
||||||
|
strokeWidth={getStrokeWidth(shape)}
|
||||||
|
shape={shape}
|
||||||
|
opacity={OVERLAY_OPACITY}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBackground(shape: TLHighlightShape) {
|
renderBackground(shape: TLHighlightShape) {
|
||||||
return <HighlightRenderer app={this.app} shape={shape} />
|
return (
|
||||||
|
<HighlightRenderer
|
||||||
|
strokeWidth={getStrokeWidth(shape)}
|
||||||
|
shape={shape}
|
||||||
|
opacity={UNDERLAY_OPACITY}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
indicator(shape: TLHighlightShape) {
|
indicator(shape: TLHighlightShape) {
|
||||||
const forceSolid = useForceSolid()
|
const forceSolid = useForceSolid()
|
||||||
const strokeWidth = this.app.getStrokeWidth(shape.props.size)
|
const strokeWidth = getStrokeWidth(shape)
|
||||||
const allPointsFromSegments = getPointsFromSegments(shape.props.segments)
|
const allPointsFromSegments = getPointsFromSegments(shape.props.segments)
|
||||||
|
|
||||||
let sw = strokeWidth
|
let sw = strokeWidth
|
||||||
|
@ -124,27 +133,33 @@ export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
||||||
const options = getFreehandOptions(
|
const options = getHighlightFreehandSettings(strokeWidth, showAsComplete)
|
||||||
{ dash: 'draw', isComplete: shape.props.isComplete, isPen: shape.props.isPen },
|
|
||||||
sw,
|
|
||||||
showAsComplete,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
const strokePoints = getStrokePoints(allPointsFromSegments, options)
|
const strokePoints = getStrokePoints(allPointsFromSegments, options)
|
||||||
const solidStrokePath =
|
|
||||||
strokePoints.length > 1
|
|
||||||
? getSvgPathFromStrokePoints(strokePoints, false)
|
|
||||||
: getDot(allPointsFromSegments[0], sw)
|
|
||||||
|
|
||||||
return <path d={solidStrokePath} />
|
let strokePath
|
||||||
|
if (strokePoints.length < 2) {
|
||||||
|
strokePath = getIndicatorDot(allPointsFromSegments[0], sw)
|
||||||
|
} else {
|
||||||
|
strokePath = getSvgPathFromStrokePoints(strokePoints, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return <path d={strokePath} />
|
||||||
}
|
}
|
||||||
|
|
||||||
toSvg(shape: TLHighlightShape, _font: string | undefined, colors: TLExportColors) {
|
override expandSelectionOutlinePx(shape: TLHighlightShape): number {
|
||||||
return highlighterToSvg(this.app, shape, OVERLAY_OPACITY, colors)
|
return getStrokeWidth(shape) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
toBackgroundSvg(shape: TLHighlightShape, font: string | undefined, colors: TLExportColors) {
|
override toSvg(shape: TLHighlightShape, _font: string | undefined, colors: TLExportColors) {
|
||||||
return highlighterToSvg(this.app, shape, 1, colors)
|
return highlighterToSvg(getStrokeWidth(shape), shape, OVERLAY_OPACITY, colors)
|
||||||
|
}
|
||||||
|
|
||||||
|
override toBackgroundSvg(
|
||||||
|
shape: TLHighlightShape,
|
||||||
|
font: string | undefined,
|
||||||
|
colors: TLExportColors
|
||||||
|
) {
|
||||||
|
return highlighterToSvg(getStrokeWidth(shape), shape, UNDERLAY_OPACITY, colors)
|
||||||
}
|
}
|
||||||
|
|
||||||
override onResize: OnResizeHandler<TLHighlightShape> = (shape, info) => {
|
override onResize: OnResizeHandler<TLHighlightShape> = (shape, info) => {
|
||||||
|
@ -171,30 +186,32 @@ export class TLHighlightUtil extends TLShapeUtil<TLHighlightShape> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expandSelectionOutlinePx(shape: TLHighlightShape): number {
|
|
||||||
return (this.app.getStrokeWidth(shape.props.size) * 1.6) / 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDot(point: VecLike, sw: number) {
|
function getShapeDot(point: VecLike) {
|
||||||
const r = (sw + 1) * 0.5
|
const r = 0.1
|
||||||
|
return `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${
|
||||||
|
r * 2
|
||||||
|
},0`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIndicatorDot(point: VecLike, sw: number) {
|
||||||
|
const r = sw / 2
|
||||||
return `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${
|
return `M ${point.x} ${point.y} m -${r}, 0 a ${r},${r} 0 1,0 ${r * 2},0 a ${r},${r} 0 1,0 -${
|
||||||
r * 2
|
r * 2
|
||||||
},0`
|
},0`
|
||||||
}
|
}
|
||||||
|
|
||||||
function HighlightRenderer({
|
function HighlightRenderer({
|
||||||
app,
|
strokeWidth,
|
||||||
shape,
|
shape,
|
||||||
opacity,
|
opacity,
|
||||||
}: {
|
}: {
|
||||||
app: App
|
strokeWidth: number
|
||||||
shape: TLHighlightShape
|
shape: TLHighlightShape
|
||||||
opacity?: number
|
opacity?: number
|
||||||
}) {
|
}) {
|
||||||
const forceSolid = useForceSolid()
|
const forceSolid = useForceSolid()
|
||||||
const strokeWidth = app.getStrokeWidth(shape.props.size)
|
|
||||||
const allPointsFromSegments = getPointsFromSegments(shape.props.segments)
|
const allPointsFromSegments = getPointsFromSegments(shape.props.segments)
|
||||||
|
|
||||||
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
||||||
|
@ -204,30 +221,27 @@ function HighlightRenderer({
|
||||||
sw += rng(shape.id)() * (strokeWidth / 6)
|
sw += rng(shape.id)() * (strokeWidth / 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = getFreehandOptions(
|
const options = getHighlightFreehandSettings(sw, showAsComplete)
|
||||||
{ isComplete: shape.props.isComplete, isPen: shape.props.isPen, dash: 'draw' },
|
|
||||||
sw,
|
|
||||||
showAsComplete,
|
|
||||||
forceSolid
|
|
||||||
)
|
|
||||||
const strokePoints = getStrokePoints(allPointsFromSegments, options)
|
const strokePoints = getStrokePoints(allPointsFromSegments, options)
|
||||||
|
|
||||||
const solidStrokePath =
|
const solidStrokePath =
|
||||||
strokePoints.length > 1
|
strokePoints.length > 1
|
||||||
? getSvgPathFromStrokePoints(strokePoints, false)
|
? getSvgPathFromStrokePoints(strokePoints, false)
|
||||||
: getDot(allPointsFromSegments[0], sw)
|
: getShapeDot(allPointsFromSegments[0])
|
||||||
|
|
||||||
if (!forceSolid || strokePoints.length < 2) {
|
if (!forceSolid || strokePoints.length < 2) {
|
||||||
setStrokePointRadii(strokePoints, options)
|
setStrokePointRadii(strokePoints, options)
|
||||||
const strokeOutlinePoints = getStrokeOutlinePoints(strokePoints, options)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SVGContainer id={shape.id} style={{ opacity }}>
|
<SVGContainer id={shape.id} style={{ opacity }}>
|
||||||
<ShapeFill fill="none" color={shape.props.color} d={solidStrokePath} />
|
|
||||||
<path
|
<path
|
||||||
d={getSvgPathFromStroke(strokeOutlinePoints, true)}
|
d={solidStrokePath}
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
fill="currentColor"
|
fill="none"
|
||||||
|
pointerEvents="all"
|
||||||
|
stroke={`var(--palette-${shape.props.color}-highlight)`}
|
||||||
|
strokeWidth={sw}
|
||||||
/>
|
/>
|
||||||
</SVGContainer>
|
</SVGContainer>
|
||||||
)
|
)
|
||||||
|
@ -240,7 +254,7 @@ function HighlightRenderer({
|
||||||
d={solidStrokePath}
|
d={solidStrokePath}
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke={`var(--palette-${shape.props.color}-highlight)`}
|
||||||
strokeWidth={strokeWidth}
|
strokeWidth={strokeWidth}
|
||||||
strokeDashoffset="0"
|
strokeDashoffset="0"
|
||||||
/>
|
/>
|
||||||
|
@ -249,14 +263,13 @@ function HighlightRenderer({
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlighterToSvg(
|
function highlighterToSvg(
|
||||||
app: App,
|
strokeWidth: number,
|
||||||
shape: TLHighlightShape,
|
shape: TLHighlightShape,
|
||||||
opacity: number,
|
opacity: number,
|
||||||
colors: TLExportColors
|
colors: TLExportColors
|
||||||
) {
|
) {
|
||||||
const { color } = shape.props
|
const { color } = shape.props
|
||||||
|
|
||||||
const strokeWidth = app.getStrokeWidth(shape.props.size)
|
|
||||||
const allPointsFromSegments = getPointsFromSegments(shape.props.segments)
|
const allPointsFromSegments = getPointsFromSegments(shape.props.segments)
|
||||||
|
|
||||||
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
const showAsComplete = shape.props.isComplete || last(shape.props.segments)?.type === 'straight'
|
||||||
|
@ -266,12 +279,7 @@ function highlighterToSvg(
|
||||||
sw += rng(shape.id)() * (strokeWidth / 6)
|
sw += rng(shape.id)() * (strokeWidth / 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = getFreehandOptions(
|
const options = getHighlightFreehandSettings(sw, showAsComplete)
|
||||||
{ dash: 'draw', isComplete: shape.props.isComplete, isPen: shape.props.isPen },
|
|
||||||
sw,
|
|
||||||
showAsComplete,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
const strokePoints = getStrokePoints(allPointsFromSegments, options)
|
const strokePoints = getStrokePoints(allPointsFromSegments, options)
|
||||||
|
|
||||||
setStrokePointRadii(strokePoints, options)
|
setStrokePointRadii(strokePoints, options)
|
||||||
|
@ -279,9 +287,17 @@ function highlighterToSvg(
|
||||||
|
|
||||||
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
||||||
path.setAttribute('d', getSvgPathFromStroke(strokeOutlinePoints, true))
|
path.setAttribute('d', getSvgPathFromStroke(strokeOutlinePoints, true))
|
||||||
path.setAttribute('fill', colors.fill[color])
|
path.setAttribute('fill', colors.highlight[color])
|
||||||
path.setAttribute('stroke-linecap', 'round')
|
path.setAttribute('stroke-linecap', 'round')
|
||||||
path.setAttribute('opacity', opacity.toString())
|
path.setAttribute('opacity', opacity.toString())
|
||||||
|
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStrokeWidth(shape: TLHighlightShape) {
|
||||||
|
return FONT_SIZES[shape.props.size] * 1.12
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIsDot(shape: TLHighlightShape) {
|
||||||
|
return shape.props.segments.length === 1 && shape.props.segments[0].points.length < 2
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ export type TLExportColors = {
|
||||||
fill: Record<TLColorType, string>
|
fill: Record<TLColorType, string>
|
||||||
pattern: Record<TLColorType, string>
|
pattern: Record<TLColorType, string>
|
||||||
semi: Record<TLColorType, string>
|
semi: Record<TLColorType, string>
|
||||||
|
highlight: Record<TLColorType, string>
|
||||||
solid: string
|
solid: string
|
||||||
text: string
|
text: string
|
||||||
background: string
|
background: string
|
||||||
|
|
|
@ -2,11 +2,11 @@ import { TLEventHandlers } from '../types/event-types'
|
||||||
import { StateNode } from './StateNode'
|
import { StateNode } from './StateNode'
|
||||||
import { TLArrowTool } from './TLArrowTool/TLArrowTool'
|
import { TLArrowTool } from './TLArrowTool/TLArrowTool'
|
||||||
import { TLDrawTool } from './TLDrawTool/TLDrawTool'
|
import { TLDrawTool } from './TLDrawTool/TLDrawTool'
|
||||||
import { TLHighlightTool } from './TLDrawTool/TLHighlightTool'
|
|
||||||
import { TLEraserTool } from './TLEraserTool/TLEraserTool'
|
import { TLEraserTool } from './TLEraserTool/TLEraserTool'
|
||||||
import { TLFrameTool } from './TLFrameTool/TLFrameTool'
|
import { TLFrameTool } from './TLFrameTool/TLFrameTool'
|
||||||
import { TLGeoTool } from './TLGeoTool/TLGeoTool'
|
import { TLGeoTool } from './TLGeoTool/TLGeoTool'
|
||||||
import { TLHandTool } from './TLHandTool/TLHandTool'
|
import { TLHandTool } from './TLHandTool/TLHandTool'
|
||||||
|
import { TLHighlightTool } from './TLHighlightTool/TLHighlightTool'
|
||||||
import { TLLaserTool } from './TLLaserTool/TLLaserTool'
|
import { TLLaserTool } from './TLLaserTool/TLLaserTool'
|
||||||
import { TLLineTool } from './TLLineTool/TLLineTool'
|
import { TLLineTool } from './TLLineTool/TLLineTool'
|
||||||
import { TLNoteTool } from './TLNoteTool/TLNoteTool'
|
import { TLNoteTool } from './TLNoteTool/TLNoteTool'
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { TLStyleType } from '@tldraw/tlschema'
|
import { TLStyleType } from '@tldraw/tlschema'
|
||||||
import { StateNode } from '../StateNode'
|
import { StateNode } from '../StateNode'
|
||||||
|
|
||||||
import { Drawing } from './children/Drawing'
|
// shared custody
|
||||||
import { Idle } from './children/Idle'
|
import { Drawing } from '../TLDrawTool/children/Drawing'
|
||||||
|
import { Idle } from '../TLDrawTool/children/Idle'
|
||||||
|
|
||||||
export class TLHighlightTool extends StateNode {
|
export class TLHighlightTool extends StateNode {
|
||||||
static override id = 'highlight'
|
static override id = 'highlight'
|
|
@ -116,9 +116,7 @@ export const Shape = track(function Shape({
|
||||||
data-shape-type={shape.type}
|
data-shape-type={shape.type}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
>
|
>
|
||||||
{isCulled ? (
|
{!isCulled && (
|
||||||
<CulledShape shape={shape} util={util} />
|
|
||||||
) : (
|
|
||||||
<OptionalErrorBoundary
|
<OptionalErrorBoundary
|
||||||
fallback={ShapeErrorFallback ? (error) => <ShapeErrorFallback error={error} /> : null}
|
fallback={ShapeErrorFallback ? (error) => <ShapeErrorFallback error={error} /> : null}
|
||||||
onError={(error) =>
|
onError={(error) =>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useValue } from 'signia-react'
|
import { useValue } from 'signia-react'
|
||||||
|
import { debugFlags } from '../utils/debug-flags'
|
||||||
import { useApp } from './useApp'
|
import { useApp } from './useApp'
|
||||||
import { useContainer } from './useContainer'
|
import { useContainer } from './useContainer'
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ export function useDarkMode() {
|
||||||
const app = useApp()
|
const app = useApp()
|
||||||
const container = useContainer()
|
const container = useContainer()
|
||||||
const isDarkMode = useValue('isDarkMode', () => app.isDarkMode, [app])
|
const isDarkMode = useValue('isDarkMode', () => app.isDarkMode, [app])
|
||||||
|
const forceSrgb = useValue(debugFlags.forceSrgb)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (isDarkMode) {
|
if (isDarkMode) {
|
||||||
|
@ -24,5 +26,10 @@ export function useDarkMode() {
|
||||||
color: 'black',
|
color: 'black',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [app, container, isDarkMode])
|
if (forceSrgb) {
|
||||||
|
container.classList.add('tl-theme__force-sRGB')
|
||||||
|
} else {
|
||||||
|
container.classList.remove('tl-theme__force-sRGB')
|
||||||
|
}
|
||||||
|
}, [app, container, forceSrgb, isDarkMode])
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const featureFlags = {
|
||||||
// todo: remove this. it's not used, but we only have one feature flag and i
|
// todo: remove this. it's not used, but we only have one feature flag and i
|
||||||
// wanted an example :(
|
// wanted an example :(
|
||||||
peopleMenu: createFeatureFlag('peopleMenu'),
|
peopleMenu: createFeatureFlag('peopleMenu'),
|
||||||
highlighterTool: createFeatureFlag('highlighterTool'),
|
highlighterTool: createFeatureFlag('highlighterTool', { all: true }),
|
||||||
} satisfies Record<string, DebugFlag<boolean>>
|
} satisfies Record<string, DebugFlag<boolean>>
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
@ -51,6 +51,7 @@ export const debugFlags = {
|
||||||
debugCursors: createDebugValue('debugCursors', {
|
debugCursors: createDebugValue('debugCursors', {
|
||||||
defaults: { all: false },
|
defaults: { all: false },
|
||||||
}),
|
}),
|
||||||
|
forceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
@ -732,10 +732,10 @@ export type TLUiEventHandler<T extends keyof TLUiEventMap = keyof TLUiEventMap>
|
||||||
export type TLUiEventSource = 'actions-menu' | 'context-menu' | 'debug-panel' | 'dialog' | 'export-menu' | 'help-menu' | 'helper-buttons' | 'kbd' | 'menu' | 'navigation-zone' | 'page-menu' | 'people-menu' | 'quick-actions' | 'share-menu' | 'toolbar' | 'unknown' | 'zoom-menu';
|
export type TLUiEventSource = 'actions-menu' | 'context-menu' | 'debug-panel' | 'dialog' | 'export-menu' | 'help-menu' | 'helper-buttons' | 'kbd' | 'menu' | 'navigation-zone' | 'page-menu' | 'people-menu' | 'quick-actions' | 'share-menu' | 'toolbar' | 'unknown' | 'zoom-menu';
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type TLUiIconType = 'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlight' | 'tool-highlighter' | 'tool-laser' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'vertical-align-center' | 'vertical-align-end' | 'vertical-align-start' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out';
|
export type TLUiIconType = 'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlight' | 'tool-laser' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'vertical-align-center' | 'vertical-align-end' | 'vertical-align-start' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out';
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const TLUiIconTypes: readonly ["align-bottom-center", "align-bottom-left", "align-bottom-right", "align-bottom", "align-center-center", "align-center-horizontal", "align-center-left", "align-center-right", "align-center-vertical", "align-left", "align-right", "align-top-center", "align-top-left", "align-top-right", "align-top", "arrow-left", "arrowhead-arrow", "arrowhead-bar", "arrowhead-diamond", "arrowhead-dot", "arrowhead-none", "arrowhead-square", "arrowhead-triangle-inverted", "arrowhead-triangle", "aspect-ratio", "avatar", "blob", "bring-forward", "bring-to-front", "check", "checkbox-checked", "checkbox-empty", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-ne", "chevrons-sw", "clipboard-copied", "clipboard-copy", "code", "collab", "color", "comment", "cross-2", "cross", "dash-dashed", "dash-dotted", "dash-draw", "dash-solid", "discord", "distribute-horizontal", "distribute-vertical", "dot", "dots-horizontal", "dots-vertical", "drag-handle-dots", "duplicate", "edit", "external-link", "file", "fill-none", "fill-pattern", "fill-semi", "fill-solid", "follow", "following", "font-draw", "font-mono", "font-sans", "font-serif", "geo-arrow-down", "geo-arrow-left", "geo-arrow-right", "geo-arrow-up", "geo-check-box", "geo-diamond", "geo-ellipse", "geo-hexagon", "geo-octagon", "geo-oval", "geo-pentagon", "geo-rectangle", "geo-rhombus-2", "geo-rhombus", "geo-star", "geo-trapezoid", "geo-triangle", "geo-x-box", "github", "group", "hidden", "image", "info-circle", "leading", "link", "lock-small", "lock", "menu", "minus", "mixed", "pack", "page", "plus", "question-mark-circle", "question-mark", "redo", "reset-zoom", "rotate-ccw", "rotate-cw", "ruler", "search", "send-backward", "send-to-back", "settings-horizontal", "settings-vertical-1", "settings-vertical", "share-1", "share-2", "size-extra-large", "size-large", "size-medium", "size-small", "spline-cubic", "spline-line", "stack-horizontal", "stack-vertical", "stretch-horizontal", "stretch-vertical", "text-align-center", "text-align-justify", "text-align-left", "text-align-right", "tool-arrow", "tool-embed", "tool-eraser", "tool-frame", "tool-hand", "tool-highlight", "tool-highlighter", "tool-laser", "tool-line", "tool-media", "tool-note", "tool-pencil", "tool-pointer", "tool-text", "trash", "triangle-down", "triangle-up", "twitter", "undo", "ungroup", "unlock-small", "unlock", "vertical-align-center", "vertical-align-end", "vertical-align-start", "visible", "warning-triangle", "zoom-in", "zoom-out"];
|
export const TLUiIconTypes: readonly ["align-bottom-center", "align-bottom-left", "align-bottom-right", "align-bottom", "align-center-center", "align-center-horizontal", "align-center-left", "align-center-right", "align-center-vertical", "align-left", "align-right", "align-top-center", "align-top-left", "align-top-right", "align-top", "arrow-left", "arrowhead-arrow", "arrowhead-bar", "arrowhead-diamond", "arrowhead-dot", "arrowhead-none", "arrowhead-square", "arrowhead-triangle-inverted", "arrowhead-triangle", "aspect-ratio", "avatar", "blob", "bring-forward", "bring-to-front", "check", "checkbox-checked", "checkbox-empty", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-ne", "chevrons-sw", "clipboard-copied", "clipboard-copy", "code", "collab", "color", "comment", "cross-2", "cross", "dash-dashed", "dash-dotted", "dash-draw", "dash-solid", "discord", "distribute-horizontal", "distribute-vertical", "dot", "dots-horizontal", "dots-vertical", "drag-handle-dots", "duplicate", "edit", "external-link", "file", "fill-none", "fill-pattern", "fill-semi", "fill-solid", "follow", "following", "font-draw", "font-mono", "font-sans", "font-serif", "geo-arrow-down", "geo-arrow-left", "geo-arrow-right", "geo-arrow-up", "geo-check-box", "geo-diamond", "geo-ellipse", "geo-hexagon", "geo-octagon", "geo-oval", "geo-pentagon", "geo-rectangle", "geo-rhombus-2", "geo-rhombus", "geo-star", "geo-trapezoid", "geo-triangle", "geo-x-box", "github", "group", "hidden", "image", "info-circle", "leading", "link", "lock-small", "lock", "menu", "minus", "mixed", "pack", "page", "plus", "question-mark-circle", "question-mark", "redo", "reset-zoom", "rotate-ccw", "rotate-cw", "ruler", "search", "send-backward", "send-to-back", "settings-horizontal", "settings-vertical-1", "settings-vertical", "share-1", "share-2", "size-extra-large", "size-large", "size-medium", "size-small", "spline-cubic", "spline-line", "stack-horizontal", "stack-vertical", "stretch-horizontal", "stretch-vertical", "text-align-center", "text-align-justify", "text-align-left", "text-align-right", "tool-arrow", "tool-embed", "tool-eraser", "tool-frame", "tool-hand", "tool-highlight", "tool-laser", "tool-line", "tool-media", "tool-note", "tool-pencil", "tool-pointer", "tool-text", "trash", "triangle-down", "triangle-up", "twitter", "undo", "ungroup", "unlock-small", "unlock", "vertical-align-center", "vertical-align-end", "vertical-align-start", "visible", "warning-triangle", "zoom-in", "zoom-out"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const ToastsContext: Context<ToastsContextType>;
|
export const ToastsContext: Context<ToastsContextType>;
|
||||||
|
|
|
@ -181,6 +181,7 @@ const DebugMenuContent = track(function DebugMenuContent({
|
||||||
<DropdownMenu.Group>
|
<DropdownMenu.Group>
|
||||||
<Toggle label="Read-only" value={app.isReadOnly} onChange={(r) => app.setReadOnly(r)} />
|
<Toggle label="Read-only" value={app.isReadOnly} onChange={(r) => app.setReadOnly(r)} />
|
||||||
<DebugFlagToggle flag={debugFlags.debugSvg} />
|
<DebugFlagToggle flag={debugFlags.debugSvg} />
|
||||||
|
<DebugFlagToggle flag={debugFlags.forceSrgb} />
|
||||||
<DebugFlagToggle
|
<DebugFlagToggle
|
||||||
flag={debugFlags.debugCursors}
|
flag={debugFlags.debugCursors}
|
||||||
onChange={(enabled) => {
|
onChange={(enabled) => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { App, featureFlags, useApp } from '@tldraw/editor'
|
import { App, featureFlags, useApp } from '@tldraw/editor'
|
||||||
|
import { compact } from '@tldraw/utils'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useValue } from 'signia-react'
|
import { useValue } from 'signia-react'
|
||||||
import { ToolItem, ToolsContextType, useTools } from './useTools'
|
import { ToolItem, ToolsContextType, useTools } from './useTools'
|
||||||
|
@ -45,7 +46,7 @@ export function ToolbarSchemaProvider({ overrides, children }: ToolbarSchemaProv
|
||||||
const highlighterEnabled = useValue(featureFlags.highlighterTool)
|
const highlighterEnabled = useValue(featureFlags.highlighterTool)
|
||||||
|
|
||||||
const toolbarSchema = React.useMemo<ToolbarSchemaContextType>(() => {
|
const toolbarSchema = React.useMemo<ToolbarSchemaContextType>(() => {
|
||||||
const schema: ToolbarSchemaContextType = [
|
const schema: ToolbarSchemaContextType = compact([
|
||||||
toolbarItem(tools.select),
|
toolbarItem(tools.select),
|
||||||
toolbarItem(tools.hand),
|
toolbarItem(tools.hand),
|
||||||
toolbarItem(tools.draw),
|
toolbarItem(tools.draw),
|
||||||
|
@ -62,23 +63,20 @@ export function ToolbarSchemaProvider({ overrides, children }: ToolbarSchemaProv
|
||||||
toolbarItem(tools['rhombus']),
|
toolbarItem(tools['rhombus']),
|
||||||
toolbarItem(tools['pentagon']),
|
toolbarItem(tools['pentagon']),
|
||||||
toolbarItem(tools['hexagon']),
|
toolbarItem(tools['hexagon']),
|
||||||
toolbarItem(tools['octagon']),
|
// toolbarItem(tools['octagon']),
|
||||||
toolbarItem(tools['star']),
|
toolbarItem(tools['star']),
|
||||||
toolbarItem(tools['oval']),
|
toolbarItem(tools['oval']),
|
||||||
toolbarItem(tools.line),
|
toolbarItem(tools['x-box']),
|
||||||
toolbarItem(tools['arrow-right']),
|
toolbarItem(tools['check-box']),
|
||||||
toolbarItem(tools['arrow-left']),
|
toolbarItem(tools['arrow-left']),
|
||||||
toolbarItem(tools['arrow-up']),
|
toolbarItem(tools['arrow-up']),
|
||||||
toolbarItem(tools['arrow-down']),
|
toolbarItem(tools['arrow-down']),
|
||||||
toolbarItem(tools['x-box']),
|
toolbarItem(tools['arrow-right']),
|
||||||
toolbarItem(tools['check-box']),
|
|
||||||
toolbarItem(tools.frame),
|
toolbarItem(tools.frame),
|
||||||
|
toolbarItem(tools.line),
|
||||||
|
highlighterEnabled ? toolbarItem(tools.highlight) : null,
|
||||||
toolbarItem(tools.laser),
|
toolbarItem(tools.laser),
|
||||||
]
|
])
|
||||||
|
|
||||||
if (highlighterEnabled) {
|
|
||||||
schema.push(toolbarItem(tools.highlight))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overrides) {
|
if (overrides) {
|
||||||
return overrides(app, schema, { tools })
|
return overrides(app, schema, { tools })
|
||||||
|
|
|
@ -210,7 +210,7 @@ export function ToolsProvider({ overrides, children }: ToolsProviderProps) {
|
||||||
readonlyOk: true,
|
readonlyOk: true,
|
||||||
icon: 'tool-highlight',
|
icon: 'tool-highlight',
|
||||||
// TODO: pick a better shortcut
|
// TODO: pick a better shortcut
|
||||||
kbd: 'i',
|
kbd: '!d',
|
||||||
onSelect(source) {
|
onSelect(source) {
|
||||||
app.setSelectedTool('highlight')
|
app.setSelectedTool('highlight')
|
||||||
trackEvent('select-tool', { source, id: 'highlight' })
|
trackEvent('select-tool', { source, id: 'highlight' })
|
||||||
|
|
|
@ -142,7 +142,6 @@ export type TLUiIconType =
|
||||||
| 'tool-frame'
|
| 'tool-frame'
|
||||||
| 'tool-hand'
|
| 'tool-hand'
|
||||||
| 'tool-highlight'
|
| 'tool-highlight'
|
||||||
| 'tool-highlighter'
|
|
||||||
| 'tool-laser'
|
| 'tool-laser'
|
||||||
| 'tool-line'
|
| 'tool-line'
|
||||||
| 'tool-media'
|
| 'tool-media'
|
||||||
|
@ -307,7 +306,6 @@ export const TLUiIconTypes = [
|
||||||
'tool-frame',
|
'tool-frame',
|
||||||
'tool-hand',
|
'tool-hand',
|
||||||
'tool-highlight',
|
'tool-highlight',
|
||||||
'tool-highlighter',
|
|
||||||
'tool-laser',
|
'tool-laser',
|
||||||
'tool-line',
|
'tool-line',
|
||||||
'tool-media',
|
'tool-media',
|
||||||
|
|
Loading…
Reference in a new issue