@blokkli/editor 1.0.3 → 1.1.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 (78) hide show
  1. package/README.md +0 -6
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +344 -11
  4. package/dist/runtime/adapter/drupal/graphql/base.graphql +2 -1
  5. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +4 -1
  6. package/dist/runtime/adapter/index.d.ts +12 -1
  7. package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue +41 -39
  8. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +10 -16
  9. package/dist/runtime/blokkliPlugins/ViewOption/index.vue +2 -0
  10. package/dist/runtime/components/BlokkliField.vue +76 -18
  11. package/dist/runtime/components/BlokkliItem.vue +34 -6
  12. package/dist/runtime/components/BlokkliProvider.vue +18 -1
  13. package/dist/runtime/components/Edit/BlockProxy/index.vue +102 -0
  14. package/dist/runtime/components/Edit/DragInteractions/index.vue +49 -25
  15. package/dist/runtime/components/Edit/DraggableList.vue +139 -29
  16. package/dist/runtime/components/Edit/EditProvider.vue +4 -0
  17. package/dist/runtime/components/Edit/Features/AddList/index.vue +3 -0
  18. package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue +111 -0
  19. package/dist/runtime/components/Edit/Features/Artboard/Scrollbar/index.vue +47 -0
  20. package/dist/runtime/components/Edit/Features/Artboard/index.vue +301 -9
  21. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +3 -4
  22. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +27 -0
  23. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +24 -3
  24. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/fragment.glsl +56 -24
  25. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +184 -29
  26. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/vertex.glsl +36 -16
  27. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +4 -0
  28. package/dist/runtime/components/Edit/Features/Duplicate/index.vue +1 -13
  29. package/dist/runtime/components/Edit/Features/EditableMask/index.vue +2 -2
  30. package/dist/runtime/components/Edit/Features/History/index.vue +1 -1
  31. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue +2 -2
  32. package/dist/runtime/components/Edit/Features/Options/Form/Checkboxes/index.vue +28 -25
  33. package/dist/runtime/components/Edit/Features/Options/Form/Color/index.vue +1 -1
  34. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +67 -39
  35. package/dist/runtime/components/Edit/Features/Options/Form/Number/index.vue +6 -2
  36. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue +1 -1
  37. package/dist/runtime/components/Edit/Features/Options/Form/Range/index.vue +2 -2
  38. package/dist/runtime/components/Edit/Features/Options/Form/Text/index.vue +2 -1
  39. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +84 -33
  40. package/dist/runtime/components/Edit/Features/ProxyView/index.vue +38 -0
  41. package/dist/runtime/components/Edit/Features/Publish/index.vue +53 -6
  42. package/dist/runtime/components/Edit/Features/Search/Overlay/index.vue +3 -13
  43. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +1 -1
  44. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +2 -0
  45. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +3 -3
  46. package/dist/runtime/components/Edit/Features/Structure/index.vue +3 -3
  47. package/dist/runtime/components/Edit/ScrollBoundary/index.vue +24 -0
  48. package/dist/runtime/components/Edit/index.d.ts +2 -1
  49. package/dist/runtime/components/Edit/index.js +3 -1
  50. package/dist/runtime/composables/defineBlokkli.js +10 -5
  51. package/dist/runtime/constants/index.d.ts +1 -1
  52. package/dist/runtime/constants/index.js +6 -1
  53. package/dist/runtime/css/output.css +1 -1
  54. package/dist/runtime/helpers/animationProvider.js +10 -4
  55. package/dist/runtime/helpers/domProvider.d.ts +4 -2
  56. package/dist/runtime/helpers/domProvider.js +42 -19
  57. package/dist/runtime/helpers/featuresProvider.d.ts +1 -1
  58. package/dist/runtime/helpers/runtimeHelpers/index.d.ts +6 -0
  59. package/dist/runtime/helpers/runtimeHelpers/index.js +25 -0
  60. package/dist/runtime/helpers/selectionProvider.d.ts +2 -1
  61. package/dist/runtime/helpers/selectionProvider.js +7 -8
  62. package/dist/runtime/helpers/symbols.d.ts +7 -0
  63. package/dist/runtime/helpers/symbols.js +7 -0
  64. package/dist/runtime/helpers/typesProvider.d.ts +1 -1
  65. package/dist/runtime/helpers/uiProvider.d.ts +1 -0
  66. package/dist/runtime/helpers/uiProvider.js +16 -3
  67. package/dist/runtime/helpers/webgl/index.d.ts +6 -1
  68. package/dist/runtime/helpers/webgl/index.js +38 -5
  69. package/dist/runtime/icons/eye.svg +1 -0
  70. package/dist/runtime/types/generatedModuleTypes.d.ts +12 -4
  71. package/dist/runtime/types/index.d.ts +39 -3
  72. package/package.json +7 -5
  73. package/dist/runtime/components/Edit/Features/Artboard/Manager/Artboard.d.ts +0 -204
  74. package/dist/runtime/components/Edit/Features/Artboard/Manager/Artboard.js +0 -748
  75. package/dist/runtime/components/Edit/Features/Artboard/Manager/Scrollbar/index.vue +0 -176
  76. package/dist/runtime/components/Edit/Features/Artboard/Manager/index.vue +0 -317
  77. package/dist/runtime/helpers/Artboard/index.d.ts +0 -16
  78. package/dist/runtime/helpers/Artboard/index.js +0 -20
@@ -1,14 +1,76 @@
1
1
  <template>
2
- <ArtboardManager
3
- :persist="settings.persist"
4
- :scroll-speed="settings.scrollSpeed"
5
- />
2
+ <PluginToolbarButton
3
+ id="artboard_reset_zoom"
4
+ :title="$t('artboardResetZoom', 'Reset zoom')"
5
+ :shortcut-group="$t('artboard', 'Artboard')"
6
+ :tour-text="
7
+ $t(
8
+ 'artboardToolbarButtonTourText',
9
+ 'Shows the current zoom factor. Click on it to reset the zoom back to 100%.',
10
+ )
11
+ "
12
+ icon="magnifier"
13
+ meta
14
+ key-code="0"
15
+ region="view-options"
16
+ weight="100"
17
+ @click="resetZoom"
18
+ >
19
+ <div class="bk-feature-canvas-button">
20
+ <span>{{ zoomLevel }}</span>
21
+ </div>
22
+ </PluginToolbarButton>
23
+
24
+ <PluginViewOption
25
+ id="artboardOverview"
26
+ v-slot="{ isActive }"
27
+ :label="$t('artboardOverviewToggle', 'Toggle overview')"
28
+ :title-on="$t('artboardOverviewShow', 'Show overview')"
29
+ :title-off="$t('artboardOverviewHide', 'Hide overview')"
30
+ :tour-text="
31
+ $t(
32
+ 'artboardOverviewTourText',
33
+ `Displays a top level overview of your content.`,
34
+ )
35
+ "
36
+ icon="eye"
37
+ key-code="O"
38
+ weight="90"
39
+ >
40
+ <Teleport v-if="isActive" to="body">
41
+ <Overview :artboard="artboard" />
42
+ </Teleport>
43
+ </PluginViewOption>
44
+
45
+ <Scrollbar :artboard="artboard" orientation="y" />
6
46
  </template>
7
47
 
8
48
  <script lang="ts" setup>
9
- import ArtboardManager from './Manager/index.vue'
10
- import { defineBlokkliFeature } from '#imports'
11
-
49
+ import {
50
+ watch,
51
+ computed,
52
+ useBlokkli,
53
+ onMounted,
54
+ onBeforeUnmount,
55
+ defineBlokkliFeature,
56
+ } from '#imports'
57
+ import type { Coord } from '#blokkli/types'
58
+ import { PluginToolbarButton, PluginViewOption } from '#blokkli/plugins'
59
+ import Overview from './Overview/index.vue'
60
+ import Scrollbar from './Scrollbar/index.vue'
61
+ import onBlokkliEvent from '#blokkli/helpers/composables/onBlokkliEvent'
62
+ import defineShortcut from '#blokkli/helpers/composables/defineShortcut'
63
+ import {
64
+ createArtboard,
65
+ type ArtboardOptions,
66
+ type Artboard,
67
+ type PluginWheelOptions,
68
+ touch,
69
+ wheel,
70
+ mouse,
71
+ dom as domPlugin,
72
+ type PluginWheel,
73
+ } from 'artboard-deluxe'
12
74
  const { settings } = defineBlokkliFeature({
13
75
  id: 'artboard',
14
76
  label: 'Artboard',
@@ -20,14 +82,21 @@ const { settings } = defineBlokkliFeature({
20
82
  type: 'checkbox',
21
83
  default: true,
22
84
  label: 'Persist position and zoom',
23
- group: 'behavior',
85
+ group: 'artboard',
86
+ viewports: ['desktop'],
87
+ },
88
+ momentum: {
89
+ type: 'checkbox',
90
+ default: true,
91
+ label: 'Use smooth scrolling',
92
+ group: 'artboard',
24
93
  viewports: ['desktop'],
25
94
  },
26
95
  scrollSpeed: {
27
96
  type: 'slider',
28
97
  default: 1,
29
98
  label: 'Artboard scroll speed',
30
- group: 'behavior',
99
+ group: 'artboard',
31
100
  viewports: ['desktop'],
32
101
  min: 0.5,
33
102
  max: 1.5,
@@ -36,6 +105,229 @@ const { settings } = defineBlokkliFeature({
36
105
  },
37
106
  screenshot: 'feature-artboard.jpg',
38
107
  })
108
+
109
+ const { context, storage, ui, animation, $t, dom } = useBlokkli()
110
+
111
+ const zoomLevel = computed(() => Math.round(ui.artboardScale.value * 100) + '%')
112
+
113
+ const PADDING = 50
114
+
115
+ const options = computed<ArtboardOptions>(() => {
116
+ return {
117
+ maxScale: ui.isMobile.value ? 1 : 3,
118
+ direction: ui.isMobile.value ? 'vertical' : 'both',
119
+ minScale: 0.1,
120
+ overscrollBounds: {
121
+ top: ui.visibleViewport.value.y + PADDING,
122
+ left: ui.visibleViewport.value.x + PADDING,
123
+ right:
124
+ ui.viewport.value.width -
125
+ ui.visibleViewport.value.width -
126
+ ui.visibleViewport.value.x +
127
+ PADDING,
128
+ bottom: PADDING,
129
+ },
130
+ }
131
+ })
132
+
133
+ watch(options, function (newOptions) {
134
+ artboard.setOptions(newOptions)
135
+ })
136
+
137
+ type SavedState = {
138
+ offset: Coord
139
+ scale: number
140
+ }
141
+ const storageKey = computed(() => 'artboard:' + context.value.entityUuid)
142
+ const savedState = storage.use<SavedState | null>(storageKey, null)
143
+
144
+ const saveState = () => {
145
+ if (!settings.value.persist) {
146
+ return
147
+ }
148
+ savedState.value = {
149
+ offset: artboard.getOffset(),
150
+ scale: artboard.getScale(),
151
+ }
152
+ }
153
+
154
+ let pluginWheel: PluginWheel | null = null
155
+
156
+ const wheelOptions = computed<PluginWheelOptions>(() => {
157
+ return {
158
+ useMomentumZoom: settings.value.momentum,
159
+ useMomentumScroll: settings.value.momentum,
160
+ interceptWheel: true,
161
+ scrollSpeed: settings.value.scrollSpeed,
162
+ wheelZoomFactor: settings.value.scrollSpeed,
163
+ }
164
+ })
165
+
166
+ watch(wheelOptions, function (newOptions) {
167
+ if (pluginWheel) {
168
+ pluginWheel.options.setAll(newOptions)
169
+ }
170
+ })
171
+
172
+ function getArtboard(): Artboard {
173
+ pluginWheel = wheel(wheelOptions.value)
174
+ return createArtboard(
175
+ ui.rootElement(),
176
+ [
177
+ mouse(),
178
+ touch(),
179
+ pluginWheel,
180
+ domPlugin({
181
+ element: ui.artboardElement(),
182
+ setInitTransformFromRect: !savedState.value || !settings.value.persist,
183
+ precision: 0.1,
184
+ restoreStyles: true,
185
+ }),
186
+ ],
187
+ {
188
+ initTransform:
189
+ savedState.value && settings.value.persist
190
+ ? {
191
+ x: savedState.value.offset.x,
192
+ y: savedState.value.offset.y,
193
+ scale: savedState.value?.scale || 1,
194
+ }
195
+ : undefined,
196
+ ...options.value,
197
+ },
198
+ )
199
+ }
200
+
201
+ const artboard = getArtboard()
202
+
203
+ watch(options, function (newOptions) {
204
+ artboard.setOptions(newOptions)
205
+ })
206
+
207
+ onBlokkliEvent('animationFrame:before', (time) => {
208
+ artboard.loop(time)
209
+ const artboardSize = artboard.getArtboardSize()
210
+ if (artboardSize) {
211
+ ui.artboardSize.value.height = artboardSize.height
212
+ ui.artboardSize.value.width = artboardSize.width
213
+ }
214
+
215
+ const offset = artboard.getOffset()
216
+
217
+ // We don't need much precision here, so we can round it.
218
+ // This also prevents updating rects in WebGL buffers for small changes.
219
+ ui.artboardOffset.value.x = Math.ceil(offset.x)
220
+ ui.artboardOffset.value.y = Math.ceil(offset.y)
221
+ ui.artboardScale.value = artboard.getScale()
222
+ animation.requestDraw()
223
+ })
224
+
225
+ onMounted(() => {
226
+ window.addEventListener('beforeunload', saveState)
227
+ })
228
+
229
+ onBeforeUnmount(() => {
230
+ saveState()
231
+ artboard.destroy()
232
+ window.removeEventListener('beforeunload', saveState)
233
+ })
234
+
235
+ const resetZoom = () => {
236
+ artboard.resetZoom({
237
+ duration: 500,
238
+ })
239
+ animation.requestDraw()
240
+ }
241
+
242
+ onBlokkliEvent('keyPressed', (e) => {
243
+ if (e.code === 'Home') {
244
+ e.originalEvent.preventDefault()
245
+ artboard.scrollToTop()
246
+ animation.requestDraw()
247
+ } else if (e.code === 'End') {
248
+ e.originalEvent.preventDefault()
249
+ artboard.scrollToEnd()
250
+ animation.requestDraw()
251
+ } else if (e.code === 'PageUp') {
252
+ e.originalEvent.preventDefault()
253
+ artboard.scrollPageUp()
254
+ animation.requestDraw()
255
+ } else if (e.code === 'PageDown') {
256
+ e.originalEvent.preventDefault()
257
+ artboard.scrollPageDown()
258
+ animation.requestDraw()
259
+ } else if (e.code === 'ArrowUp') {
260
+ e.originalEvent.preventDefault()
261
+ artboard.scrollUp()
262
+ animation.requestDraw()
263
+ } else if (e.code === 'ArrowDown') {
264
+ e.originalEvent.preventDefault()
265
+ artboard.scrollDown()
266
+ animation.requestDraw()
267
+ } else if (e.code === '0' && e.meta) {
268
+ e.originalEvent.preventDefault()
269
+ resetZoom()
270
+ } else if (e.code === '1' && e.meta) {
271
+ e.originalEvent.preventDefault()
272
+ artboard.scaleToFit()
273
+ animation.requestDraw()
274
+ }
275
+ })
276
+
277
+ defineShortcut(
278
+ [
279
+ {
280
+ code: 'Home',
281
+ label: $t('artboardScrollToTop', 'Scroll to top'),
282
+ },
283
+ {
284
+ code: 'End',
285
+ label: $t('artboardScrollToEnd', 'Scroll to end'),
286
+ },
287
+ {
288
+ code: 'PageUp',
289
+ label: $t('artboardScrollOnePageUp', 'Scroll one page up'),
290
+ },
291
+ {
292
+ code: 'PageDown',
293
+ label: $t('artboardScrollOnePageDown', 'Scroll one page down'),
294
+ },
295
+ {
296
+ code: 'ArrowUp',
297
+ label: $t('artboardScrollUp', 'Scroll up'),
298
+ },
299
+ {
300
+ code: 'ArrowDown',
301
+ label: $t('artboardScrollDown', 'Scroll down'),
302
+ },
303
+ {
304
+ code: '1',
305
+ label: $t('artboardScaleToFit', 'Scale to fit'),
306
+ meta: true,
307
+ },
308
+ ].map((v) => {
309
+ return { ...v, group: $t('artboard', 'Artboard') }
310
+ }),
311
+ )
312
+
313
+ onBlokkliEvent('scrollIntoView', (e) => {
314
+ const rect = dom.getBlockRect(e.uuid)
315
+ if (!rect) {
316
+ return
317
+ }
318
+
319
+ if (dom.isBlockVisible(e.uuid)) {
320
+ return
321
+ }
322
+
323
+ // @TODO: Prevent scrolling into view when already
324
+
325
+ artboard.scrollIntoView(rect, {
326
+ scale: 'none',
327
+ axis: 'y',
328
+ behavior: e.immediate ? 'instant' : 'auto',
329
+ })
330
+ })
39
331
  </script>
40
332
 
41
333
  <script lang="ts">
@@ -1,7 +1,6 @@
1
1
  <template>
2
- <div
2
+ <ScrollBoundary
3
3
  class="bk-command-palette bk-control"
4
- @wheel.passive.stop
5
4
  @keydown.stop="onKeyDown"
6
5
  @keyup.stop
7
6
  @click.stop
@@ -30,7 +29,7 @@
30
29
  @select="onSelect($event)"
31
30
  />
32
31
  </div>
33
- </div>
32
+ </ScrollBoundary>
34
33
  </template>
35
34
 
36
35
  <script lang="ts" setup>
@@ -43,7 +42,7 @@ import {
43
42
  nextTick,
44
43
  onBeforeUnmount,
45
44
  } from '#imports'
46
- import { Icon } from '#blokkli/components'
45
+ import { Icon, ScrollBoundary } from '#blokkli/components'
47
46
  import type { Command, CommandGroup } from '#blokkli/types'
48
47
  import Group from './Group/index.vue'
49
48
  import { falsy } from '#blokkli/helpers'
@@ -32,6 +32,7 @@ onBlokkliEvent('canvas:draw', (e) => {
32
32
  return
33
33
  }
34
34
  ctx.clearRect(0, 0, ui.viewport.value.width, ui.viewport.value.height)
35
+ ctx.strokeStyle = 'blue'
35
36
  const blockRects = dom.getBlockRects()
36
37
  const viewport = ui.visibleViewport.value
37
38
 
@@ -47,6 +48,32 @@ onBlokkliEvent('canvas:draw', (e) => {
47
48
  height: rect.height * e.artboardScale,
48
49
  }
49
50
  if (intersects(drawnRect, viewport)) {
51
+ ctx.beginPath()
52
+ ctx.rect(drawnRect.x, drawnRect.y, drawnRect.width, drawnRect.height)
53
+ ctx.stroke()
54
+ }
55
+ }
56
+
57
+ ctx.strokeStyle = 'red'
58
+
59
+ const visibleFieldRects = dom.getVisibleFields()
60
+ for (let i = 0; i < visibleFieldRects.length; i++) {
61
+ const key = visibleFieldRects[i]
62
+
63
+ const rect = dom.getFieldRect(key)
64
+
65
+ if (!rect) {
66
+ continue
67
+ }
68
+
69
+ const drawnRect = {
70
+ x: rect.x * e.artboardScale + e.artboardOffset.x,
71
+ y: rect.y * e.artboardScale + e.artboardOffset.y,
72
+ width: rect.width * e.artboardScale,
73
+ height: rect.height * e.artboardScale,
74
+ }
75
+ if (intersects(drawnRect, viewport)) {
76
+ ctx.beginPath()
50
77
  ctx.rect(drawnRect.x, drawnRect.y, drawnRect.width, drawnRect.height)
51
78
  ctx.stroke()
52
79
  }
@@ -11,7 +11,7 @@
11
11
  :style="{ backgroundColor: activeColor }"
12
12
  >
13
13
  <Icon name="cursor-move" />
14
- <p v-html="activeLabel" />
14
+ <p v-html="prevActiveLabel" />
15
15
  </div>
16
16
  </Transition>
17
17
  <div
@@ -52,7 +52,14 @@
52
52
  </template>
53
53
 
54
54
  <script setup lang="ts">
55
- import { ref, computed, useBlokkli, onMounted, onBeforeUnmount } from '#imports'
55
+ import {
56
+ ref,
57
+ watch,
58
+ computed,
59
+ useBlokkli,
60
+ onMounted,
61
+ onBeforeUnmount,
62
+ } from '#imports'
56
63
  import type { Coord, DraggableItem, Rectangle } from '#blokkli/types'
57
64
  import {
58
65
  isInsideRect,
@@ -93,6 +100,17 @@ const props = defineProps<{
93
100
  activeLabel?: string
94
101
  }>()
95
102
 
103
+ const prevActiveLabel = ref('')
104
+
105
+ watch(
106
+ () => props.activeLabel,
107
+ function (label) {
108
+ if (label) {
109
+ prevActiveLabel.value = label
110
+ }
111
+ },
112
+ )
113
+
96
114
  const width = ref(10)
97
115
  const height = ref(10)
98
116
 
@@ -122,7 +140,10 @@ const style = computed(() => {
122
140
  width: width.value + 'px',
123
141
  height: height.value + 'px',
124
142
  transform: `translate(${translateX.value}px, ${translateY.value}px)`,
125
- '--bk-active-color': props.activeColor || 'rgba(255,255,255,0)',
143
+ '--bk-active-color':
144
+ props.activeColor && props.activeLabel
145
+ ? props.activeColor
146
+ : 'rgba(255,255,255,0)',
126
147
  }
127
148
  })
128
149
 
@@ -1,9 +1,9 @@
1
1
  precision mediump float;
2
2
 
3
3
  varying float v_intersecting;
4
+ varying float v_is_hover_area;
4
5
  varying vec4 v_quad;
5
- varying vec3 v_color_default;
6
- varying vec3 v_color_active;
6
+ varying vec3 v_color;
7
7
 
8
8
  uniform float u_scale;
9
9
  uniform float u_dpi;
@@ -14,10 +14,16 @@ float roundedBoxSDF(vec2 CenterPosition, vec2 Size, float Radius) {
14
14
  }
15
15
 
16
16
  void main() {
17
- float radius_base = 2.0 * u_scale;
17
+ bool isHoverArea = v_is_hover_area >= 1.0;
18
+ float stroke = isHoverArea ? 0.75 : 2.0;
19
+ float radiusBase = stroke * u_scale;
20
+
18
21
  float thickness = max(min(1.0 * u_scale, 3.0), 0.5);
19
- float inset = max(min(2.0 * u_scale, 1.0), 2.0) * thickness;
20
22
 
23
+ // Calculate the resulting inset so that we draw the rounded box and border *inside* the quad (vs. that it would bleed outside the quad).
24
+ float inset = max(min(2.0 * u_scale, 1.0), 3.0) * thickness + stroke;
25
+
26
+ // Rectangle dimensions with inset.
21
27
  float u_rect_x = v_quad.x + inset;
22
28
  float u_rect_y = v_quad.y + inset;
23
29
  float u_rectWidth = v_quad.z - 2.0 * inset;
@@ -25,34 +31,60 @@ void main() {
25
31
 
26
32
  vec2 size = vec2(u_rectWidth, u_rectHeight);
27
33
 
28
- float x = u_rect_x;
29
- float y = u_rect_y;
30
- vec2 offsetPosition = vec2(x + size.x / 2.0, y + size.y / 2.0);
34
+ // Center position of the rectangle.
35
+ vec2 offsetPosition = vec2(u_rect_x + size.x / 2.0, u_rect_y + size.y / 2.0);
36
+ vec2 location = offsetPosition;
37
+
38
+ // Make sure the edges of the border are not too harsh.
39
+ float edgeSoftness = 0.5 * u_dpi;
31
40
 
32
- vec2 location = vec2(offsetPosition);
41
+ float borderWidth = stroke * u_scale * u_dpi;
33
42
 
34
- float edgeSoftness = 1.0 * u_dpi;
35
- float radius =
36
- min(radius_base * u_dpi, min(size.x, size.y) / 2.0) + thickness * 2.0;
43
+ // Different radius for inner and outer.
44
+ float radiusOutside =
45
+ min(radiusBase * u_dpi, min(size.x, size.y)) + thickness;
46
+ float radiusInside = radiusOutside - borderWidth;
37
47
 
38
- float distance = roundedBoxSDF(
48
+ vec2 sizeInner = size - 2.0 * borderWidth;
49
+
50
+ // Compute different distance for inside and outside.
51
+ float distanceOuter = roundedBoxSDF(
39
52
  location - gl_FragCoord.xy,
40
53
  size / 2.0,
41
- radius
54
+ radiusOutside
55
+ );
56
+ float distanceInner = roundedBoxSDF(
57
+ location - gl_FragCoord.xy,
58
+ sizeInner / 2.0,
59
+ radiusInside
42
60
  );
43
61
 
44
- bool is_intersecting = v_intersecting >= 0.5;
62
+ float alphaOuter =
63
+ 1.0 - smoothstep(-edgeSoftness, edgeSoftness, distanceOuter - thickness);
64
+ float alphaInner =
65
+ 1.0 - smoothstep(-edgeSoftness, edgeSoftness, distanceInner - thickness);
45
66
 
46
- vec3 color = is_intersecting ? v_color_active : v_color_default;
47
- float mixedDistance = is_intersecting ? distance : abs(distance);
67
+ // Alpha value for the border.
68
+ float alphaBorder = clamp(alphaOuter - alphaInner, 0.0, 1.0);
48
69
 
49
- float smoothedAlpha =
50
- 1.0 - smoothstep(-edgeSoftness, edgeSoftness, mixedDistance - thickness);
70
+ // Adjust alphas based on intersection.
71
+ float adjustedAlphaFill =
72
+ v_intersecting >= 0.5
73
+ ? alphaInner * 0.95
74
+ : alphaInner * 0.2;
51
75
 
52
- gl_FragColor = vec4(
53
- color,
54
- is_intersecting
55
- ? smoothedAlpha - 0.4
56
- : smoothedAlpha
57
- );
76
+ if (v_is_hover_area >= 1.0) {
77
+ adjustedAlphaFill *= 0.12;
78
+ }
79
+
80
+ if (alphaBorder > 0.0) {
81
+ float a = isHoverArea ? 0.6 : 1.0;
82
+ gl_FragColor = vec4(v_color, a);
83
+ return;
84
+ } else if (adjustedAlphaFill > 0.0) {
85
+ gl_FragColor = vec4(v_color, adjustedAlphaFill);
86
+ return;
87
+ }
88
+
89
+ discard;
58
90
  }