@dryui/ui 0.1.2 → 0.1.3

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.
@@ -1,25 +1,72 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import { RichTextEditor as RichTextEditorPrimitive } from '@dryui/primitives/rich-text-editor';
3
+ import { getRichTextEditorCtx } from '@dryui/primitives/rich-text-editor';
4
4
 
5
5
  interface Props extends HTMLAttributes<HTMLDivElement> {}
6
6
 
7
7
  let { ...rest }: Props = $props();
8
8
 
9
+ const ctx = getRichTextEditorCtx();
10
+
11
+ let toolbarEl: HTMLDivElement;
12
+
9
13
  let showLinkInput = $state(false);
10
14
  let linkUrl = $state('');
11
15
  let linkInputEl = $state<HTMLInputElement>();
12
16
  let savedSelection = $state<Range | null>(null);
13
17
 
18
+ // Roving tabindex keyboard navigation
19
+ function getFocusableItems(toolbar: HTMLElement): HTMLElement[] {
20
+ return Array.from(
21
+ toolbar.querySelectorAll<HTMLElement>(
22
+ 'button:not([disabled]), [role="button"]:not([disabled])'
23
+ )
24
+ );
25
+ }
26
+
27
+ $effect(() => {
28
+ if (!toolbarEl) return;
29
+ const items = getFocusableItems(toolbarEl);
30
+ if (items.length > 0 && !items.some((el) => el.getAttribute('tabindex') === '0')) {
31
+ items[0]!.setAttribute('tabindex', '0');
32
+ }
33
+ });
34
+
35
+ function handleKeydown(event: KeyboardEvent) {
36
+ const toolbar = event.currentTarget as HTMLElement;
37
+ const items = getFocusableItems(toolbar);
38
+ if (items.length === 0) return;
39
+
40
+ const currentIndex = items.indexOf(event.target as HTMLElement);
41
+ if (currentIndex === -1) return;
42
+
43
+ let nextIndex: number | null = null;
44
+
45
+ if (event.key === 'ArrowLeft') {
46
+ nextIndex = currentIndex - 1 < 0 ? items.length - 1 : currentIndex - 1;
47
+ } else if (event.key === 'ArrowRight') {
48
+ nextIndex = currentIndex + 1 >= items.length ? 0 : currentIndex + 1;
49
+ } else if (event.key === 'Home') {
50
+ nextIndex = 0;
51
+ } else if (event.key === 'End') {
52
+ nextIndex = items.length - 1;
53
+ }
54
+
55
+ if (nextIndex !== null) {
56
+ event.preventDefault();
57
+ items[currentIndex]!.setAttribute('tabindex', '-1');
58
+ items[nextIndex]!.setAttribute('tabindex', '0');
59
+ items[nextIndex]!.focus();
60
+ }
61
+ }
62
+
14
63
  function openLinkInput(currentLink: string | null) {
15
- // Save the current selection so we can restore it when applying
16
64
  const sel = window.getSelection();
17
65
  if (sel && sel.rangeCount > 0) {
18
66
  savedSelection = sel.getRangeAt(0).cloneRange();
19
67
  }
20
68
  linkUrl = currentLink ?? 'https://';
21
69
  showLinkInput = true;
22
- // Focus input after render
23
70
  requestAnimationFrame(() => {
24
71
  linkInputEl?.focus();
25
72
  linkInputEl?.select();
@@ -43,210 +90,245 @@
43
90
  }
44
91
  </script>
45
92
 
46
- <RichTextEditorPrimitive.Toolbar data-part="toolbar" {...rest}>
47
- {#snippet children(ctx)}
48
- <div data-part="toolbarGroup">
49
- <button
50
- type="button"
51
- data-part="button"
52
- data-active={ctx.isBold}
53
- aria-pressed={ctx.isBold}
54
- aria-label="Bold"
55
- title="Bold (Ctrl+B)"
56
- tabindex={-1}
57
- onmousedown={(e) => e.preventDefault()}
58
- onclick={() => ctx.toggleBold()}><strong>B</strong></button
59
- >
60
-
61
- <button
62
- type="button"
63
- data-part="button"
64
- data-format="italic"
65
- data-active={ctx.isItalic}
66
- aria-pressed={ctx.isItalic}
67
- aria-label="Italic"
68
- title="Italic (Ctrl+I)"
69
- tabindex={-1}
70
- onmousedown={(e) => e.preventDefault()}
71
- onclick={() => ctx.toggleItalic()}>I</button
93
+ <div
94
+ bind:this={toolbarEl}
95
+ role="toolbar"
96
+ aria-orientation="horizontal"
97
+ aria-label="Text formatting"
98
+ data-part="toolbar"
99
+ data-rte-toolbar
100
+ onkeydown={handleKeydown}
101
+ {...rest}
102
+ >
103
+ <div data-part="toolbarGroup">
104
+ <button
105
+ type="button"
106
+ data-part="button"
107
+ data-active={ctx.isBold}
108
+ aria-pressed={ctx.isBold}
109
+ aria-label="Bold"
110
+ title="Bold (Ctrl+B)"
111
+ tabindex={-1}
112
+ onmousedown={(e) => e.preventDefault()}
113
+ onclick={() => ctx.toggleBold()}><strong>B</strong></button
114
+ >
115
+
116
+ <button
117
+ type="button"
118
+ data-part="button"
119
+ data-format="italic"
120
+ data-active={ctx.isItalic}
121
+ aria-pressed={ctx.isItalic}
122
+ aria-label="Italic"
123
+ title="Italic (Ctrl+I)"
124
+ tabindex={-1}
125
+ onmousedown={(e) => e.preventDefault()}
126
+ onclick={() => ctx.toggleItalic()}>I</button
127
+ >
128
+
129
+ <button
130
+ type="button"
131
+ data-part="button"
132
+ data-format="underline"
133
+ data-active={ctx.isUnderline}
134
+ aria-pressed={ctx.isUnderline}
135
+ aria-label="Underline"
136
+ title="Underline (Ctrl+U)"
137
+ tabindex={-1}
138
+ onmousedown={(e) => e.preventDefault()}
139
+ onclick={() => ctx.toggleUnderline()}>U</button
140
+ >
141
+
142
+ <button
143
+ type="button"
144
+ data-part="button"
145
+ data-format="strikethrough"
146
+ data-active={ctx.isStrikethrough}
147
+ aria-pressed={ctx.isStrikethrough}
148
+ aria-label="Strikethrough"
149
+ title="Strikethrough"
150
+ tabindex={-1}
151
+ onmousedown={(e) => e.preventDefault()}
152
+ onclick={() => ctx.toggleStrikethrough()}>S</button
153
+ >
154
+ </div>
155
+
156
+ <div data-part="separator" role="separator"></div>
157
+
158
+ <div data-part="toolbarGroup">
159
+ <button
160
+ type="button"
161
+ data-part="button"
162
+ data-active={ctx.currentHeading === 'h1'}
163
+ aria-pressed={ctx.currentHeading === 'h1'}
164
+ aria-label="Heading 1"
165
+ title="Heading 1"
166
+ tabindex={-1}
167
+ onmousedown={(e) => e.preventDefault()}
168
+ onclick={() => ctx.setHeading('h1')}>H1</button
169
+ >
170
+
171
+ <button
172
+ type="button"
173
+ data-part="button"
174
+ data-active={ctx.currentHeading === 'h2'}
175
+ aria-pressed={ctx.currentHeading === 'h2'}
176
+ aria-label="Heading 2"
177
+ title="Heading 2"
178
+ tabindex={-1}
179
+ onmousedown={(e) => e.preventDefault()}
180
+ onclick={() => ctx.setHeading('h2')}>H2</button
181
+ >
182
+
183
+ <button
184
+ type="button"
185
+ data-part="button"
186
+ data-active={ctx.currentHeading === 'h3'}
187
+ aria-pressed={ctx.currentHeading === 'h3'}
188
+ aria-label="Heading 3"
189
+ title="Heading 3"
190
+ tabindex={-1}
191
+ onmousedown={(e) => e.preventDefault()}
192
+ onclick={() => ctx.setHeading('h3')}>H3</button
193
+ >
194
+ </div>
195
+
196
+ <div data-part="separator" role="separator"></div>
197
+
198
+ <div data-part="toolbarGroup">
199
+ <button
200
+ type="button"
201
+ data-part="button"
202
+ data-active={ctx.isUnorderedList}
203
+ aria-pressed={ctx.isUnorderedList}
204
+ aria-label="Bullet list"
205
+ title="Bullet list"
206
+ tabindex={-1}
207
+ onmousedown={(e) => e.preventDefault()}
208
+ onclick={() => ctx.toggleUnorderedList()}
209
+ >
210
+ <svg
211
+ width="16"
212
+ height="16"
213
+ viewBox="0 0 16 16"
214
+ fill="none"
215
+ stroke="currentColor"
216
+ stroke-width="2"
217
+ stroke-linecap="round"
218
+ stroke-linejoin="round"
219
+ aria-hidden="true"
72
220
  >
73
-
74
- <button
75
- type="button"
76
- data-part="button"
77
- data-format="underline"
78
- data-active={ctx.isUnderline}
79
- aria-pressed={ctx.isUnderline}
80
- aria-label="Underline"
81
- title="Underline (Ctrl+U)"
82
- tabindex={-1}
83
- onmousedown={(e) => e.preventDefault()}
84
- onclick={() => ctx.toggleUnderline()}>U</button
221
+ <circle cx="3" cy="4" r="1" fill="currentColor" stroke="none" />
222
+ <circle cx="3" cy="8" r="1" fill="currentColor" stroke="none" />
223
+ <circle cx="3" cy="12" r="1" fill="currentColor" stroke="none" />
224
+ <line x1="6.5" y1="4" x2="14" y2="4" />
225
+ <line x1="6.5" y1="8" x2="14" y2="8" />
226
+ <line x1="6.5" y1="12" x2="14" y2="12" />
227
+ </svg>
228
+ </button>
229
+
230
+ <button
231
+ type="button"
232
+ data-part="button"
233
+ data-active={ctx.isOrderedList}
234
+ aria-pressed={ctx.isOrderedList}
235
+ aria-label="Numbered list"
236
+ title="Numbered list"
237
+ tabindex={-1}
238
+ onmousedown={(e) => e.preventDefault()}
239
+ onclick={() => ctx.toggleOrderedList()}
240
+ >
241
+ <svg
242
+ width="16"
243
+ height="16"
244
+ viewBox="0 0 16 16"
245
+ fill="none"
246
+ stroke="currentColor"
247
+ stroke-width="2"
248
+ stroke-linecap="round"
249
+ stroke-linejoin="round"
250
+ aria-hidden="true"
85
251
  >
86
-
87
- <button
88
- type="button"
89
- data-part="button"
90
- data-format="strikethrough"
91
- data-active={ctx.isStrikethrough}
92
- aria-pressed={ctx.isStrikethrough}
93
- aria-label="Strikethrough"
94
- title="Strikethrough"
95
- tabindex={-1}
96
- onmousedown={(e) => e.preventDefault()}
97
- onclick={() => ctx.toggleStrikethrough()}>S</button
98
- >
99
- </div>
100
-
101
- <div data-part="separator" role="separator"></div>
102
-
103
- <div data-part="toolbarGroup">
104
- <button
105
- type="button"
106
- data-part="button"
107
- data-active={ctx.currentHeading === 'h1'}
108
- aria-pressed={ctx.currentHeading === 'h1'}
109
- aria-label="Heading 1"
110
- title="Heading 1"
111
- tabindex={-1}
112
- onmousedown={(e) => e.preventDefault()}
113
- onclick={() => ctx.setHeading('h1')}>H1</button
114
- >
115
-
116
- <button
117
- type="button"
118
- data-part="button"
119
- data-active={ctx.currentHeading === 'h2'}
120
- aria-pressed={ctx.currentHeading === 'h2'}
121
- aria-label="Heading 2"
122
- title="Heading 2"
123
- tabindex={-1}
124
- onmousedown={(e) => e.preventDefault()}
125
- onclick={() => ctx.setHeading('h2')}>H2</button
126
- >
127
-
128
- <button
129
- type="button"
130
- data-part="button"
131
- data-active={ctx.currentHeading === 'h3'}
132
- aria-pressed={ctx.currentHeading === 'h3'}
133
- aria-label="Heading 3"
134
- title="Heading 3"
135
- tabindex={-1}
136
- onmousedown={(e) => e.preventDefault()}
137
- onclick={() => ctx.setHeading('h3')}>H3</button
138
- >
139
- </div>
140
-
141
- <div data-part="separator" role="separator"></div>
142
-
143
- <div data-part="toolbarGroup">
144
- <button
145
- type="button"
146
- data-part="button"
147
- data-active={ctx.isUnorderedList}
148
- aria-pressed={ctx.isUnorderedList}
149
- aria-label="Bullet list"
150
- title="Bullet list"
151
- tabindex={-1}
152
- onmousedown={(e) => e.preventDefault()}
153
- onclick={() => ctx.toggleUnorderedList()}
154
- >
155
- <svg
156
- width="16"
157
- height="16"
158
- viewBox="0 0 16 16"
159
- fill="none"
160
- stroke="currentColor"
161
- stroke-width="2"
162
- stroke-linecap="round"
163
- stroke-linejoin="round"
164
- aria-hidden="true"
252
+ <text
253
+ x="1"
254
+ y="5.5"
255
+ font-size="5"
256
+ fill="currentColor"
257
+ stroke="none"
258
+ font-family="sans-serif"
259
+ font-weight="bold">1</text
165
260
  >
166
- <circle cx="3" cy="4" r="1" fill="currentColor" stroke="none" />
167
- <circle cx="3" cy="8" r="1" fill="currentColor" stroke="none" />
168
- <circle cx="3" cy="12" r="1" fill="currentColor" stroke="none" />
169
- <line x1="6.5" y1="4" x2="14" y2="4" />
170
- <line x1="6.5" y1="8" x2="14" y2="8" />
171
- <line x1="6.5" y1="12" x2="14" y2="12" />
172
- </svg>
173
- </button>
174
-
175
- <button
176
- type="button"
177
- data-part="button"
178
- data-active={ctx.isOrderedList}
179
- aria-pressed={ctx.isOrderedList}
180
- aria-label="Numbered list"
181
- title="Numbered list"
182
- tabindex={-1}
183
- onmousedown={(e) => e.preventDefault()}
184
- onclick={() => ctx.toggleOrderedList()}
185
- >
186
- <svg
187
- width="16"
188
- height="16"
189
- viewBox="0 0 16 16"
190
- fill="none"
191
- stroke="currentColor"
192
- stroke-width="2"
193
- stroke-linecap="round"
194
- stroke-linejoin="round"
195
- aria-hidden="true"
261
+ <text
262
+ x="1"
263
+ y="9.5"
264
+ font-size="5"
265
+ fill="currentColor"
266
+ stroke="none"
267
+ font-family="sans-serif"
268
+ font-weight="bold">2</text
196
269
  >
197
- <text
198
- x="1"
199
- y="5.5"
200
- font-size="5"
201
- fill="currentColor"
202
- stroke="none"
203
- font-family="sans-serif"
204
- font-weight="bold">1</text
205
- >
206
- <text
207
- x="1"
208
- y="9.5"
209
- font-size="5"
210
- fill="currentColor"
211
- stroke="none"
212
- font-family="sans-serif"
213
- font-weight="bold">2</text
214
- >
215
- <text
216
- x="1"
217
- y="13.5"
218
- font-size="5"
219
- fill="currentColor"
220
- stroke="none"
221
- font-family="sans-serif"
222
- font-weight="bold">3</text
223
- >
224
- <line x1="6.5" y1="4" x2="14" y2="4" />
225
- <line x1="6.5" y1="8" x2="14" y2="8" />
226
- <line x1="6.5" y1="12" x2="14" y2="12" />
227
- </svg>
228
- </button>
229
- </div>
230
-
231
- <div data-part="separator" role="separator"></div>
270
+ <text
271
+ x="1"
272
+ y="13.5"
273
+ font-size="5"
274
+ fill="currentColor"
275
+ stroke="none"
276
+ font-family="sans-serif"
277
+ font-weight="bold">3</text
278
+ >
279
+ <line x1="6.5" y1="4" x2="14" y2="4" />
280
+ <line x1="6.5" y1="8" x2="14" y2="8" />
281
+ <line x1="6.5" y1="12" x2="14" y2="12" />
282
+ </svg>
283
+ </button>
284
+ </div>
285
+
286
+ <div data-part="separator" role="separator"></div>
287
+
288
+ <div data-part="toolbarGroup" class="toolbarGroupRelative">
289
+ <button
290
+ type="button"
291
+ data-part="button"
292
+ data-active={ctx.currentLink !== null}
293
+ aria-pressed={ctx.currentLink !== null}
294
+ aria-label={ctx.currentLink ? 'Edit link' : 'Insert link'}
295
+ title="Link (Ctrl+K)"
296
+ tabindex={-1}
297
+ onmousedown={(e) => e.preventDefault()}
298
+ onclick={() => {
299
+ if (ctx.currentLink) {
300
+ openLinkInput(ctx.currentLink);
301
+ } else {
302
+ openLinkInput(null);
303
+ }
304
+ }}
305
+ >
306
+ <svg
307
+ width="16"
308
+ height="16"
309
+ viewBox="0 0 16 16"
310
+ fill="none"
311
+ stroke="currentColor"
312
+ stroke-width="2"
313
+ stroke-linecap="round"
314
+ stroke-linejoin="round"
315
+ aria-hidden="true"
316
+ >
317
+ <path d="M6.5 9.5L9.5 6.5" />
318
+ <path d="M8.5 10.5L7 12C5.9 13.1 4.1 13.1 3 12C1.9 10.9 1.9 9.1 3 8L4.5 6.5" />
319
+ <path d="M7.5 5.5L9 4C10.1 2.9 11.9 2.9 13 4C14.1 5.1 14.1 6.9 13 8L11.5 9.5" />
320
+ </svg>
321
+ </button>
232
322
 
233
- <div data-part="toolbarGroup" class="toolbarGroupRelative">
323
+ {#if ctx.currentLink}
234
324
  <button
235
325
  type="button"
236
326
  data-part="button"
237
- data-active={ctx.currentLink !== null}
238
- aria-pressed={ctx.currentLink !== null}
239
- aria-label={ctx.currentLink ? 'Edit link' : 'Insert link'}
240
- title="Link (Ctrl+K)"
327
+ aria-label="Remove link"
328
+ title="Remove link"
241
329
  tabindex={-1}
242
330
  onmousedown={(e) => e.preventDefault()}
243
- onclick={() => {
244
- if (ctx.currentLink) {
245
- openLinkInput(ctx.currentLink);
246
- } else {
247
- openLinkInput(null);
248
- }
249
- }}
331
+ onclick={() => ctx.removeLink()}
250
332
  >
251
333
  <svg
252
334
  width="16"
@@ -262,83 +344,56 @@
262
344
  <path d="M6.5 9.5L9.5 6.5" />
263
345
  <path d="M8.5 10.5L7 12C5.9 13.1 4.1 13.1 3 12C1.9 10.9 1.9 9.1 3 8L4.5 6.5" />
264
346
  <path d="M7.5 5.5L9 4C10.1 2.9 11.9 2.9 13 4C14.1 5.1 14.1 6.9 13 8L11.5 9.5" />
347
+ <path d="M3 13L13 3" />
265
348
  </svg>
266
349
  </button>
267
-
268
- {#if ctx.currentLink}
269
- <button
270
- type="button"
271
- data-part="button"
272
- aria-label="Remove link"
273
- title="Remove link"
274
- tabindex={-1}
275
- onmousedown={(e) => e.preventDefault()}
276
- onclick={() => ctx.removeLink()}
277
- >
278
- <svg
279
- width="16"
280
- height="16"
281
- viewBox="0 0 16 16"
282
- fill="none"
283
- stroke="currentColor"
284
- stroke-width="2"
285
- stroke-linecap="round"
286
- stroke-linejoin="round"
287
- aria-hidden="true"
288
- >
289
- <path d="M6.5 9.5L9.5 6.5" />
290
- <path d="M8.5 10.5L7 12C5.9 13.1 4.1 13.1 3 12C1.9 10.9 1.9 9.1 3 8L4.5 6.5" />
291
- <path d="M7.5 5.5L9 4C10.1 2.9 11.9 2.9 13 4C14.1 5.1 14.1 6.9 13 8L11.5 9.5" />
292
- <path d="M3 13L13 3" />
293
- </svg>
294
- </button>
295
- {/if}
296
-
297
- {#if showLinkInput}
298
- <div data-part="linkPopover">
299
- <input
300
- bind:value={linkUrl}
301
- bind:this={linkInputEl}
302
- data-part="linkInput"
303
- type="url"
304
- placeholder="https://example.com"
305
- onkeydown={(e) => {
306
- if (e.key === 'Enter') {
307
- e.preventDefault();
308
- if (linkUrl) {
309
- restoreSelection();
310
- ctx.insertLink(linkUrl);
311
- }
312
- closeLinkInput();
313
- } else if (e.key === 'Escape') {
314
- closeLinkInput();
315
- }
316
- }}
317
- />
318
- <button
319
- type="button"
320
- data-part="linkApply"
321
- onclick={() => {
350
+ {/if}
351
+
352
+ {#if showLinkInput}
353
+ <div data-part="linkPopover">
354
+ <input
355
+ bind:value={linkUrl}
356
+ bind:this={linkInputEl}
357
+ data-part="linkInput"
358
+ type="url"
359
+ placeholder="https://example.com"
360
+ onkeydown={(e) => {
361
+ if (e.key === 'Enter') {
362
+ e.preventDefault();
322
363
  if (linkUrl) {
323
364
  restoreSelection();
324
365
  ctx.insertLink(linkUrl);
325
366
  }
326
367
  closeLinkInput();
327
- }}>Apply</button
328
- >
329
- <button type="button" data-part="linkCancel" onclick={() => closeLinkInput()}
330
- >Cancel</button
331
- >
332
- </div>
333
- {/if}
334
- </div>
335
- {/snippet}
336
- </RichTextEditorPrimitive.Toolbar>
368
+ } else if (e.key === 'Escape') {
369
+ closeLinkInput();
370
+ }
371
+ }}
372
+ />
373
+ <button
374
+ type="button"
375
+ data-part="linkApply"
376
+ onclick={() => {
377
+ if (linkUrl) {
378
+ restoreSelection();
379
+ ctx.insertLink(linkUrl);
380
+ }
381
+ closeLinkInput();
382
+ }}>Apply</button
383
+ >
384
+ <button type="button" data-part="linkCancel" onclick={() => closeLinkInput()}
385
+ >Cancel</button
386
+ >
387
+ </div>
388
+ {/if}
389
+ </div>
390
+ </div>
337
391
 
338
392
  <style>
339
393
  [data-part='toolbar'] {
340
394
  display: grid;
341
- grid-template-columns: repeat(auto-fill, minmax(min-content, max-content));
395
+ grid-auto-flow: column;
396
+ grid-auto-columns: max-content;
342
397
  align-items: center;
343
398
  gap: var(--dry-space-1);
344
399
  padding: var(--dry-space-1) var(--dry-space-2);
@@ -398,18 +453,6 @@
398
453
  background: var(--dry-color-fill-brand-hover);
399
454
  }
400
455
 
401
- [data-part='buttonItalic'] {
402
- font-style: italic;
403
- }
404
-
405
- [data-part='buttonUnderline'] {
406
- text-decoration: underline;
407
- }
408
-
409
- [data-part='buttonStrikethrough'] {
410
- text-decoration: line-through;
411
- }
412
-
413
456
  .toolbarGroupRelative {
414
457
  position: relative;
415
458
  }
@@ -118,7 +118,4 @@
118
118
  border-radius: inherit;
119
119
  }
120
120
 
121
- [data-shader-canvas] {
122
- height: 100%;
123
- }
124
121
  </style>
@@ -17,6 +17,7 @@
17
17
  aria-label="Toggle sidebar"
18
18
  aria-expanded={!ctx.collapsed}
19
19
  data-sidebar-trigger
20
+ data-side={ctx.side}
20
21
  class={className}
21
22
  onclick={() => ctx.toggle()}
22
23
  {...rest}
@@ -65,11 +66,11 @@
65
66
  transform: rotate(180deg);
66
67
  }
67
68
 
68
- [data-side='right'] [data-sidebar-trigger]::before {
69
+ [data-sidebar-trigger][data-side='right']::before {
69
70
  transform: rotate(180deg);
70
71
  }
71
72
 
72
- [data-side='right'] [data-sidebar-trigger][aria-expanded='true']::before {
73
+ [data-sidebar-trigger][data-side='right'][aria-expanded='true']::before {
73
74
  transform: none;
74
75
  }
75
76
  </style>