@gradio/imageeditor 0.12.13 → 0.13.0

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.
Files changed (130) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/Example.svelte +1 -1
  3. package/IMAGE_EDITOR_OVERVIEW.md +224 -0
  4. package/ImageEditor.stories.svelte +4 -4
  5. package/Index.svelte +35 -46
  6. package/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +56 -103
  7. package/dist/Example.svelte.d.ts +1 -1
  8. package/dist/Index.svelte +29 -33
  9. package/dist/Index.svelte.d.ts +17 -16
  10. package/dist/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +47 -88
  11. package/dist/{shared/InteractiveImageEditor.svelte.d.ts → InteractiveImageEditor.svelte.d.ts} +13 -15
  12. package/dist/shared/Anchor.svelte +311 -0
  13. package/dist/shared/Anchor.svelte.d.ts +18 -0
  14. package/dist/shared/Controls.svelte +162 -23
  15. package/dist/shared/Controls.svelte.d.ts +7 -2
  16. package/dist/shared/{tools/IconButton.svelte → IconButton.svelte} +19 -3
  17. package/dist/shared/{tools/IconButton.svelte.d.ts → IconButton.svelte.d.ts} +4 -1
  18. package/dist/shared/ImageEditor.svelte +546 -289
  19. package/dist/shared/ImageEditor.svelte.d.ts +51 -56
  20. package/dist/shared/Layers.svelte +233 -0
  21. package/dist/shared/Layers.svelte.d.ts +35 -0
  22. package/dist/shared/Resize.svelte +218 -0
  23. package/dist/shared/Resize.svelte.d.ts +29 -0
  24. package/dist/shared/SecondaryToolbar.svelte +54 -0
  25. package/dist/shared/SecondaryToolbar.svelte.d.ts +35 -0
  26. package/dist/shared/Toolbar.svelte +337 -0
  27. package/dist/shared/Toolbar.svelte.d.ts +42 -0
  28. package/dist/shared/{tools → brush}/BrushOptions.svelte +68 -64
  29. package/dist/shared/{tools → brush}/BrushOptions.svelte.d.ts +9 -9
  30. package/dist/shared/{tools → brush}/BrushSize.svelte +2 -27
  31. package/dist/shared/{tools → brush}/ColorField.svelte +2 -1
  32. package/dist/shared/{tools → brush}/ColorField.svelte.d.ts +1 -0
  33. package/dist/shared/{tools → brush}/ColorPicker.svelte +81 -9
  34. package/dist/shared/{tools → brush}/ColorPicker.svelte.d.ts +1 -0
  35. package/dist/shared/{tools → brush}/ColorSwatch.svelte +78 -38
  36. package/dist/shared/{tools → brush}/ColorSwatch.svelte.d.ts +6 -2
  37. package/dist/shared/brush/brush-cursor.d.ts +101 -0
  38. package/dist/shared/brush/brush-cursor.js +327 -0
  39. package/dist/shared/brush/brush-textures.d.ts +71 -0
  40. package/dist/shared/brush/brush-textures.js +404 -0
  41. package/dist/shared/brush/brush-utils.d.ts +32 -0
  42. package/dist/shared/brush/brush-utils.js +59 -0
  43. package/dist/shared/brush/brush.d.ts +152 -0
  44. package/dist/shared/brush/brush.js +396 -0
  45. package/dist/shared/brush/types.d.ts +37 -0
  46. package/dist/shared/brush/types.js +1 -0
  47. package/dist/shared/core/editor.d.ts +252 -0
  48. package/dist/shared/core/editor.js +1221 -0
  49. package/dist/shared/crop/crop.d.ts +201 -0
  50. package/dist/shared/crop/crop.js +727 -0
  51. package/dist/shared/image/image.d.ts +89 -0
  52. package/dist/shared/image/image.js +185 -0
  53. package/dist/shared/resize/resize.d.ts +270 -0
  54. package/dist/shared/resize/resize.js +1413 -0
  55. package/dist/shared/types.d.ts +12 -0
  56. package/dist/shared/utils/pixi.d.ts +16 -57
  57. package/dist/shared/utils/pixi.js +15 -113
  58. package/dist/shared/zoom/zoom.d.ts +136 -0
  59. package/dist/shared/zoom/zoom.js +548 -0
  60. package/package.json +11 -10
  61. package/shared/Anchor.svelte +384 -0
  62. package/shared/Controls.svelte +194 -27
  63. package/shared/{tools/IconButton.svelte → IconButton.svelte} +21 -4
  64. package/shared/ImageEditor.svelte +682 -349
  65. package/shared/Layers.svelte +249 -0
  66. package/shared/Resize.svelte +239 -0
  67. package/shared/SecondaryToolbar.svelte +61 -0
  68. package/shared/Toolbar.svelte +386 -0
  69. package/shared/brush/BRUSH_TOOL.md +134 -0
  70. package/shared/brush/BrushOptions.svelte +200 -0
  71. package/shared/{tools → brush}/BrushSize.svelte +2 -30
  72. package/shared/{tools → brush}/ColorField.svelte +3 -1
  73. package/shared/{tools → brush}/ColorPicker.svelte +86 -9
  74. package/shared/{tools → brush}/ColorSwatch.svelte +95 -42
  75. package/shared/brush/brush-cursor.ts +408 -0
  76. package/shared/brush/brush-textures.ts +508 -0
  77. package/shared/brush/brush-utils.ts +76 -0
  78. package/shared/brush/brush.ts +506 -0
  79. package/shared/brush/types.ts +41 -0
  80. package/shared/core/EDITOR.md +182 -0
  81. package/shared/core/editor.ts +1730 -0
  82. package/shared/crop/CROP.md +139 -0
  83. package/shared/crop/crop.ts +1027 -0
  84. package/shared/image/IMAGE.md +135 -0
  85. package/shared/image/image.ts +300 -0
  86. package/shared/resize/resize.ts +1894 -0
  87. package/shared/types.ts +14 -0
  88. package/shared/utils/pixi.ts +19 -246
  89. package/shared/zoom/zoom.ts +729 -0
  90. package/dist/shared/layers/Layers.svelte +0 -231
  91. package/dist/shared/layers/Layers.svelte.d.ts +0 -18
  92. package/dist/shared/layers/utils.d.ts +0 -73
  93. package/dist/shared/layers/utils.js +0 -156
  94. package/dist/shared/tools/Brush.svelte +0 -215
  95. package/dist/shared/tools/Brush.svelte.d.ts +0 -29
  96. package/dist/shared/tools/Crop.svelte +0 -155
  97. package/dist/shared/tools/Crop.svelte.d.ts +0 -16
  98. package/dist/shared/tools/Cropper.svelte +0 -271
  99. package/dist/shared/tools/Cropper.svelte.d.ts +0 -41
  100. package/dist/shared/tools/Handle.svelte +0 -260
  101. package/dist/shared/tools/Handle.svelte.d.ts +0 -29
  102. package/dist/shared/tools/Sources.svelte +0 -257
  103. package/dist/shared/tools/Sources.svelte.d.ts +0 -34
  104. package/dist/shared/tools/Tools.svelte +0 -102
  105. package/dist/shared/tools/Tools.svelte.d.ts +0 -48
  106. package/dist/shared/tools/brush.d.ts +0 -62
  107. package/dist/shared/tools/brush.js +0 -133
  108. package/dist/shared/tools/crop.d.ts +0 -15
  109. package/dist/shared/tools/crop.js +0 -154
  110. package/dist/shared/tools/index.d.ts +0 -5
  111. package/dist/shared/tools/index.js +0 -5
  112. package/dist/shared/tools/sources.d.ts +0 -46
  113. package/dist/shared/tools/sources.js +0 -121
  114. package/dist/shared/tools/types.d.ts +0 -1
  115. package/shared/layers/Layers.svelte +0 -250
  116. package/shared/layers/utils.ts +0 -294
  117. package/shared/tools/Brush.svelte +0 -280
  118. package/shared/tools/BrushOptions.svelte +0 -180
  119. package/shared/tools/Crop.svelte +0 -189
  120. package/shared/tools/Cropper.svelte +0 -346
  121. package/shared/tools/Handle.svelte +0 -289
  122. package/shared/tools/Sources.svelte +0 -283
  123. package/shared/tools/Tools.svelte +0 -162
  124. package/shared/tools/brush.ts +0 -247
  125. package/shared/tools/crop.ts +0 -213
  126. package/shared/tools/index.ts +0 -5
  127. package/shared/tools/sources.ts +0 -195
  128. package/shared/tools/types.ts +0 -1
  129. /package/dist/shared/{tools → brush}/BrushSize.svelte.d.ts +0 -0
  130. /package/dist/shared/{tools/types.js → types.js} +0 -0
@@ -1,346 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from "svelte";
3
- import Handle from "./Handle.svelte";
4
- import { type EditorContext } from "../ImageEditor.svelte";
5
- import { clamp } from "../utils/pixi";
6
- import { resize_and_reposition } from "./crop";
7
-
8
- export let editor_box: EditorContext["editor_box"];
9
- export let crop_constraint: number | null;
10
-
11
- const dispatch = createEventDispatcher<{
12
- crop_start: {
13
- x: number;
14
- y: number;
15
- width: number;
16
- height: number;
17
- };
18
- crop_continue: {
19
- x: number;
20
- y: number;
21
- width: number;
22
- height: number;
23
- };
24
- crop_end: {
25
- x: number;
26
- y: number;
27
- width: number;
28
- height: number;
29
- };
30
- }>();
31
-
32
- let _height = $editor_box.child_height;
33
- let _width = $editor_box.child_width;
34
- let _top = $editor_box.child_top - $editor_box.parent_top;
35
- let _left = $editor_box.child_left - $editor_box.parent_left;
36
- let _right = $editor_box.child_right - $editor_box.parent_left;
37
- let _bottom = 0;
38
-
39
- let dragging = false;
40
-
41
- export let w_p: number;
42
- export let h_p: number;
43
- export let l_p: number;
44
- export let t_p: number;
45
-
46
- const positions = ["tl", "br", "tr", "bl", "t", "b", "l", "r"] as const;
47
-
48
- let finished: boolean;
49
-
50
- let timer: NodeJS.Timeout;
51
- let triggered = false;
52
-
53
- $: {
54
- if (dragging || position_drag) {
55
- clearTimeout(timer);
56
-
57
- finished = false;
58
- } else {
59
- set_finished_with_timeout_and_delay();
60
- }
61
- }
62
-
63
- function set_finished_with_timeout_and_delay(): void {
64
- if (timer) {
65
- clearTimeout(timer);
66
- }
67
- timer = setTimeout(() => {
68
- if (triggered) {
69
- dispatch("crop_end", {
70
- x: l_p,
71
- y: t_p,
72
- width: w_p,
73
- height: h_p
74
- });
75
- triggered = false;
76
- }
77
-
78
- finished = true;
79
- position_drag = false;
80
- }, 1000);
81
- }
82
-
83
- function handle_change(
84
- {
85
- top,
86
- bottom,
87
- left,
88
- right
89
- }: {
90
- top: number | undefined;
91
- bottom: number | undefined;
92
- left: number | undefined;
93
- right: number | undefined;
94
- },
95
- position: (typeof positions)[number]
96
- ): void {
97
- _top = clamp(
98
- top ? top - $editor_box.parent_top : _top,
99
- $editor_box.child_top - $editor_box.parent_top,
100
- $editor_box.child_bottom - $editor_box.parent_top
101
- );
102
-
103
- _left = clamp(
104
- left ? left - $editor_box.parent_left : _left,
105
- $editor_box.child_left - $editor_box.parent_left,
106
- $editor_box.child_right - $editor_box.parent_left
107
- );
108
- _right = clamp(
109
- right ? right - $editor_box.parent_left : _right,
110
- $editor_box.child_left - $editor_box.parent_left,
111
- $editor_box.child_right - $editor_box.parent_left
112
- );
113
- _bottom = clamp(
114
- bottom ? bottom - $editor_box.parent_top : _bottom,
115
- $editor_box.child_top - $editor_box.parent_top,
116
- $editor_box.child_bottom - $editor_box.parent_top
117
- );
118
- _width = clamp(
119
- right ? right - _left - $editor_box.parent_left : _width,
120
- 0,
121
- _right - _left
122
- );
123
- _width = clamp(
124
- left ? _right - left + $editor_box.parent_left : _width,
125
- 0,
126
- _right - _left
127
- );
128
- _height = clamp(
129
- bottom ? bottom - _top - $editor_box.parent_top : _height,
130
- 0,
131
- _bottom - _top
132
- );
133
- _height = clamp(
134
- top ? _bottom - top + $editor_box.parent_top : _height,
135
- 0,
136
- _bottom - _top
137
- );
138
-
139
- const anchors_for_position = {
140
- tl: "br",
141
- tr: "bl",
142
- bl: "tr",
143
- br: "tl",
144
- t: "b",
145
- b: "t",
146
- l: "r",
147
- r: "l",
148
- c: "c"
149
- } as const;
150
-
151
- if (crop_constraint) {
152
- const max_w = ["t", "b"].includes(position)
153
- ? $editor_box.child_width
154
- : _right - _left;
155
- const max_h = ["l", "r"].includes(position)
156
- ? $editor_box.child_height
157
- : _bottom - _top;
158
- let result = resize_and_reposition(
159
- _width,
160
- _height,
161
- anchors_for_position[position],
162
- crop_constraint,
163
- max_w,
164
- max_h
165
- );
166
-
167
- _width = result.new_width;
168
- _height = result.new_height;
169
- _left = _left + result.x_offset;
170
- _top = _top + result.y_offset;
171
- _right = _left + _width;
172
- _bottom = _top + _height;
173
- }
174
-
175
- w_p = _width / $editor_box.child_width;
176
- h_p = _height / $editor_box.child_height;
177
- l_p =
178
- (_left - $editor_box.child_left + $editor_box.parent_left) /
179
- $editor_box.child_width;
180
- t_p =
181
- (_top - $editor_box.child_top + $editor_box.parent_top) /
182
- $editor_box.child_height;
183
-
184
- dispatch(triggered ? "crop_continue" : "crop_start", {
185
- x: l_p,
186
- y: t_p,
187
- width: w_p,
188
- height: h_p
189
- });
190
-
191
- triggered = true;
192
- }
193
-
194
- function resize(): void {
195
- _width = w_p * $editor_box.child_width;
196
- _height = h_p * $editor_box.child_height;
197
- _left =
198
- l_p * $editor_box.child_width +
199
- ($editor_box.child_left - $editor_box.parent_left);
200
- _top =
201
- t_p * $editor_box.child_height +
202
- ($editor_box.child_top - $editor_box.parent_top);
203
- _right = _left + _width;
204
- _bottom = _top + _height;
205
- }
206
-
207
- $: $editor_box && resize();
208
-
209
- let start_x = 0;
210
- let start_y = 0;
211
- let position_drag = false;
212
- function handle_drag_start(e: MouseEvent): void {
213
- position_drag = true;
214
-
215
- start_x = e.clientX;
216
- start_y = e.clientY;
217
-
218
- if (!finished) return;
219
- finished = false;
220
- dispatch("crop_start", {
221
- x: l_p,
222
- y: t_p,
223
- width: w_p,
224
- height: h_p
225
- });
226
- }
227
-
228
- function handle_drag_end(e: MouseEvent): void {
229
- if (!position_drag) return;
230
-
231
- position_drag = false;
232
- }
233
-
234
- function handle_dragging(e: MouseEvent): void {
235
- if (!position_drag) return;
236
-
237
- const x_delta = e.clientX - start_x;
238
- const y_delta = e.clientY - start_y;
239
-
240
- _left = clamp(
241
- _left + x_delta,
242
- $editor_box.child_left - $editor_box.parent_left,
243
- $editor_box.child_right - $editor_box.parent_left - _width
244
- );
245
-
246
- _top = clamp(
247
- _top + y_delta,
248
- $editor_box.child_top - $editor_box.parent_top,
249
- $editor_box.child_bottom - $editor_box.parent_top - _height
250
- );
251
-
252
- _right = _left + _width;
253
- _bottom = _top + _height;
254
-
255
- l_p =
256
- (_left - $editor_box.child_left + $editor_box.parent_left) /
257
- $editor_box.child_width;
258
- t_p =
259
- (_top - $editor_box.child_top + $editor_box.parent_top) /
260
- $editor_box.child_height;
261
-
262
- start_x = e.clientX;
263
- start_y = e.clientY;
264
- dispatch("crop_continue", {
265
- x: l_p,
266
- y: t_p,
267
- width: w_p,
268
- height: h_p
269
- });
270
-
271
- triggered = true;
272
- }
273
- </script>
274
-
275
- <svelte:window on:mousemove={handle_dragging} on:mouseup={handle_drag_end} />
276
-
277
- <div class="wrap">
278
- <div
279
- class="box"
280
- style:width="{_width}px"
281
- style:height="{_height}px"
282
- style:top="{_top}px"
283
- style:left="{_left}px"
284
- >
285
- {#each positions as position}
286
- <Handle
287
- on:change={({ detail }) => handle_change(detail, position)}
288
- bind:dragging
289
- location={position}
290
- />
291
- {/each}
292
-
293
- <!-- svelte-ignore a11y-no-static-element-interactions -->
294
- <div class="grid" class:finished on:mousedown={handle_drag_start}>
295
- {#each { length: 25 } as _}
296
- <div></div>
297
- {/each}
298
- </div>
299
- </div>
300
- </div>
301
-
302
- <style>
303
- .grid {
304
- height: 100%;
305
- width: 100%;
306
- display: grid;
307
- grid-template-rows: 1fr 1px 1fr 1px 1fr;
308
- grid-template-columns: 1fr 1px 1fr 1px 1fr;
309
- overflow: hidden;
310
- transition: 0.2s;
311
- opacity: 1;
312
- /* pointer-events: none; */
313
- }
314
-
315
- .grid.finished {
316
- opacity: 0;
317
- }
318
-
319
- .grid > div {
320
- width: 100%;
321
- height: 100%;
322
- }
323
-
324
- .grid > div:nth-of-type(even) {
325
- background: black;
326
- opacity: 0.5;
327
- }
328
-
329
- .wrap {
330
- position: absolute;
331
- top: 0;
332
- left: 0;
333
- width: 100%;
334
- height: 100%;
335
-
336
- /* transform: translateY(-20px); */
337
- }
338
-
339
- .box {
340
- position: absolute;
341
- width: 100%;
342
- height: 100%;
343
- border: 1px solid black;
344
- z-index: var(--layer-top);
345
- }
346
- </style>
@@ -1,289 +0,0 @@
1
- <script lang="ts">
2
- import { tick, createEventDispatcher } from "svelte";
3
-
4
- export let type = "corner";
5
- export let location: "tl" | "tr" | "bl" | "br" | "t" | "b" | "l" | "r";
6
-
7
- export let x1 = 0;
8
- export let y1 = 0;
9
- export let x2 = 0;
10
- export let y2 = 0;
11
-
12
- let box: DOMRect;
13
- let y_offset = 0;
14
- let x_offset = 0;
15
- const min = 100;
16
-
17
- let active = false;
18
-
19
- const dispatch = createEventDispatcher<{
20
- change: {
21
- top: number | undefined;
22
- bottom: number | undefined;
23
- left: number | undefined;
24
- right: number | undefined;
25
- };
26
- }>();
27
- export let dragging = false;
28
-
29
- let el: HTMLDivElement;
30
-
31
- function handle_mousedown(e: MouseEvent): void {
32
- box = el.getBoundingClientRect();
33
- active = true;
34
- dragging = true;
35
-
36
- if (["tl", "bl", "l"].includes(location)) x_offset = e.clientX - box.right;
37
- if (["tl", "tr", "t"].includes(location)) y_offset = e.clientY - box.bottom;
38
- if (["tr", "r", "br"].includes(location)) x_offset = e.clientX - box.left;
39
- if (["br", "b", "bl"].includes(location)) y_offset = e.clientY - box.top;
40
- }
41
-
42
- function handle_mousemove(e: MouseEvent): void {
43
- if (!active) return;
44
- const top_pos = e.clientY - y_offset;
45
- const bottom_pos = e.clientY - y_offset;
46
- const left_pos = e.clientX - x_offset;
47
- const right_pos = e.clientX - x_offset;
48
-
49
- if (["tl", "bl", "l"].includes(location)) {
50
- x1 = left_pos;
51
- }
52
-
53
- if (["tl", "tr", "t"].includes(location)) {
54
- y1 = top_pos;
55
- }
56
-
57
- if (["tr", "r", "br"].includes(location)) {
58
- x2 = right_pos;
59
- }
60
-
61
- if (["br", "b", "bl"].includes(location)) {
62
- y2 = bottom_pos;
63
- }
64
- }
65
-
66
- async function handle_mouseup(e: MouseEvent): Promise<void> {
67
- await tick();
68
- active = false;
69
- dragging = false;
70
- }
71
-
72
- function make_transform(
73
- _location: typeof location,
74
- x1: number,
75
- x2: number,
76
- y1: number,
77
- y2: number
78
- ): string {
79
- let t = undefined;
80
- let l = undefined;
81
- let r = undefined;
82
- let b = undefined;
83
-
84
- if (box) {
85
- if (["tl", "l", "bl"].includes(_location)) {
86
- l = x1;
87
- }
88
-
89
- if (["tl", "t", "tr"].includes(_location)) {
90
- t = y1;
91
- }
92
-
93
- if (["tr", "r", "br"].includes(_location)) {
94
- r = x2;
95
- }
96
-
97
- if (["br", "b", "bl"].includes(_location)) {
98
- b = y2;
99
- }
100
- }
101
-
102
- dispatch("change", { top: t, bottom: b, left: l, right: r });
103
- return "";
104
- }
105
-
106
- $: transform = make_transform(location, x1, x2, y1, y2);
107
- </script>
108
-
109
- <svelte:window on:mousemove={handle_mousemove} on:mouseup={handle_mouseup} />
110
-
111
- <!-- svelte-ignore a11y-no-static-element-interactions -->
112
- <div class="hitbox {location}" on:mousedown={handle_mousedown} style:transform>
113
- <div class="handle {type} {location}" bind:this={el}></div>
114
- </div>
115
-
116
- <style>
117
- .hitbox {
118
- position: absolute;
119
- width: 50px;
120
- height: 50px;
121
- --hitbox-mid-offset: calc(50% - 25px);
122
- --hitbox-corner-offset: -25px;
123
- --handle-corner-offset: calc(50% - 5px);
124
- --handle-mid-offset: calc(50% - 2px);
125
- z-index: var(--layer-top);
126
- }
127
-
128
- /* hitbox positions */
129
- .hitbox.tl,
130
- .hitbox.bl,
131
- .hitbox.l {
132
- left: var(--hitbox-corner-offset);
133
- }
134
-
135
- .hitbox.tr,
136
- .hitbox.br,
137
- .hitbox.r {
138
- right: var(--hitbox-corner-offset);
139
- }
140
-
141
- .hitbox.t,
142
- .hitbox.tr,
143
- .hitbox.tl {
144
- top: var(--hitbox-corner-offset);
145
- }
146
-
147
- .hitbox.t,
148
- .hitbox.b {
149
- left: var(--hitbox-mid-offset);
150
- }
151
-
152
- .hitbox.l,
153
- .hitbox.r {
154
- top: var(--hitbox-mid-offset);
155
- }
156
-
157
- .hitbox.b,
158
- .hitbox.br,
159
- .hitbox.bl {
160
- bottom: var(--hitbox-corner-offset);
161
- }
162
-
163
- /* hitbox cursors */
164
-
165
- .hitbox.tl,
166
- .hitbox.br {
167
- cursor: nwse-resize;
168
- }
169
-
170
- .hitbox.bl,
171
- .hitbox.tr {
172
- cursor: nesw-resize;
173
- }
174
-
175
- .hitbox.l,
176
- .hitbox.r {
177
- cursor: ew-resize;
178
- }
179
-
180
- .hitbox.t,
181
- .hitbox.b {
182
- cursor: ns-resize;
183
- }
184
-
185
- /* Visual handles */
186
- .handle {
187
- position: absolute;
188
- }
189
-
190
- /* square to fill in corners */
191
- .corner {
192
- width: 4px;
193
- height: 4px;
194
- background: black;
195
- }
196
-
197
- /* handle segment positions */
198
- .handle.tl,
199
- .handle.bl,
200
- .handle.l {
201
- left: var(--handle-corner-offset);
202
- }
203
-
204
- .handle.tr,
205
- .handle.r,
206
- .handle.br {
207
- right: var(--handle-corner-offset);
208
- }
209
-
210
- .handle.tr,
211
- .handle.t,
212
- .handle.tl {
213
- top: var(--handle-corner-offset);
214
- }
215
-
216
- .handle.br,
217
- .handle.b,
218
- .handle.bl {
219
- bottom: var(--handle-corner-offset);
220
- }
221
-
222
- .handle.l,
223
- .handle.r {
224
- bottom: var(--handle-mid-offset);
225
- }
226
-
227
- .handle.t,
228
- .handle.b {
229
- left: var(--handle-mid-offset);
230
- }
231
-
232
- .handle::before {
233
- position: absolute;
234
- content: "";
235
- width: 20px;
236
- height: 4px;
237
- background: black;
238
- }
239
-
240
- .handle::after {
241
- position: absolute;
242
- content: "";
243
- width: 4px;
244
- height: 20px;
245
- background: black;
246
- }
247
-
248
- .handle.t::before,
249
- .handle.b::before {
250
- width: 30px;
251
- left: -14px;
252
- }
253
-
254
- .handle.r::after,
255
- .handle.l::after {
256
- height: 30px;
257
- top: -13px;
258
- }
259
-
260
- .handle.l::before,
261
- .handle.r::before {
262
- content: none;
263
- }
264
-
265
- .handle.t::after,
266
- .handle.b::after {
267
- content: none;
268
- }
269
-
270
- .handle.tr::before,
271
- .handle.br::before {
272
- right: 4px;
273
- }
274
-
275
- .handle.tl::before,
276
- .handle.bl::before {
277
- left: 4px;
278
- }
279
-
280
- .handle.tl::after,
281
- .handle.tr::after {
282
- top: 4px;
283
- }
284
-
285
- .handle.bl::after,
286
- .handle.br::after {
287
- bottom: 4px;
288
- }
289
- </style>