@rokkit/ui 1.0.0-next.133 → 1.0.0-next.136

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.
@@ -49,13 +49,15 @@
49
49
 
50
50
  const icons = $derived({ ...DEFAULT_STATE_ICONS.folder, ...userIcons })
51
51
 
52
-
53
52
  const proxyTree = $derived(
54
53
  new ProxyTree(items, fields, {
55
54
  createProxy: (raw, f, key, level) =>
56
- new LazyProxyItem(raw, f, key, level, onlazyload
57
- ? async (_value, rawItem) => onlazyload(rawItem)
58
- : null
55
+ new LazyProxyItem(
56
+ raw,
57
+ f,
58
+ key,
59
+ level,
60
+ onlazyload ? async (_value, rawItem) => onlazyload(rawItem) : null
59
61
  )
60
62
  })
61
63
  )
@@ -93,73 +95,78 @@
93
95
  {@const content = resolveSnippet(snippets, proxy, ITEM_SNIPPET)}
94
96
 
95
97
  <div
96
- data-tree-node
97
- data-tree-path={node.key}
98
- data-tree-level={node.level - 1}
99
- data-tree-has-children={node.isExpandable || undefined}
100
- data-tree-loading={isLoading || undefined}
101
- data-active={isActive || undefined}
102
- role="treeitem"
103
- aria-expanded={node.isExpandable ? proxy.expanded : undefined}
104
- aria-selected={isActive}
105
- aria-busy={isLoading || undefined}
106
- aria-level={node.level}
107
- >
108
- <div data-tree-node-row>
109
- {#each node.lineTypes as lineType, lineIndex (lineIndex)}
110
- {#if lineType === 'icon'}
111
- <button
112
- type="button"
113
- data-tree-toggle-btn
114
- onclick={() => wrapper.toggle(node.key)}
115
- aria-label={isLoading ? labels.loading : proxy.expanded ? labels.collapse : labels.expand}
116
- tabindex={-1}
117
- >
118
- {#if isLoading}
119
- <span data-tree-spinner aria-hidden="true"></span>
120
- {:else}
121
- <span class={proxy.expanded ? icons.opened : icons.closed} aria-hidden="true"></span>
122
- {/if}
123
- </button>
124
- {:else}
125
- <Connector type={lineType} />
126
- {/if}
127
- {/each}
128
-
129
- {#if proxy.get('href')}
130
- <a
131
- href={proxy.get('href')}
132
- data-tree-item-content
133
- data-path={node.key}
134
- data-active={isActive || undefined}
135
- aria-label={proxy.label}
136
- aria-current={isActive ? 'page' : undefined}
137
- >
138
- {#if content}
139
- {@render content(proxy)}
140
- {:else}
141
- <ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
142
- {/if}
143
- </a>
144
- {:else}
98
+ data-tree-node
99
+ data-tree-path={node.key}
100
+ data-tree-level={node.level - 1}
101
+ data-tree-has-children={node.isExpandable || undefined}
102
+ data-tree-loading={isLoading || undefined}
103
+ data-active={isActive || undefined}
104
+ role="treeitem"
105
+ aria-expanded={node.isExpandable ? proxy.expanded : undefined}
106
+ aria-selected={isActive}
107
+ aria-busy={isLoading || undefined}
108
+ aria-level={node.level}
109
+ >
110
+ <div data-tree-node-row>
111
+ {#each node.lineTypes as lineType, lineIndex (lineIndex)}
112
+ {#if lineType === 'icon'}
145
113
  <button
146
114
  type="button"
147
- data-tree-item-content
148
- data-path={node.key}
149
- data-active={isActive || undefined}
150
- aria-label={proxy.label}
115
+ data-tree-toggle-btn
116
+ onclick={() => wrapper.toggle(node.key)}
117
+ aria-label={isLoading
118
+ ? labels.loading
119
+ : proxy.expanded
120
+ ? labels.collapse
121
+ : labels.expand}
122
+ tabindex={-1}
151
123
  >
152
- {#if content}
153
- {@render content(proxy)}
124
+ {#if isLoading}
125
+ <span data-tree-spinner aria-hidden="true"></span>
154
126
  {:else}
155
- <ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
127
+ <span class={proxy.expanded ? icons.opened : icons.closed} aria-hidden="true"
128
+ ></span>
156
129
  {/if}
157
130
  </button>
131
+ {:else}
132
+ <Connector type={lineType} />
158
133
  {/if}
159
- </div>
134
+ {/each}
135
+
136
+ {#if proxy.get('href')}
137
+ <a
138
+ href={proxy.get('href')}
139
+ data-tree-item-content
140
+ data-path={node.key}
141
+ data-active={isActive || undefined}
142
+ aria-label={proxy.label}
143
+ aria-current={isActive ? 'page' : undefined}
144
+ >
145
+ {#if content}
146
+ {@render content(proxy)}
147
+ {:else}
148
+ <ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
149
+ {/if}
150
+ </a>
151
+ {:else}
152
+ <button
153
+ type="button"
154
+ data-tree-item-content
155
+ data-path={node.key}
156
+ data-active={isActive || undefined}
157
+ aria-label={proxy.label}
158
+ >
159
+ {#if content}
160
+ {@render content(proxy)}
161
+ {:else}
162
+ <ItemContent {proxy} showIcon={!node.isExpandable} showSubtext={false} />
163
+ {/if}
164
+ </button>
165
+ {/if}
160
166
  </div>
167
+ </div>
161
168
  {/each}
162
169
  {#if hasMore}
163
- <Button label={labels.loadMore} style="ghost" size={size} onclick={() => wrapper.loadMore()} />
170
+ <Button label={labels.loadMore} style="ghost" {size} onclick={() => wrapper.loadMore()} />
164
171
  {/if}
165
172
  </div>
@@ -87,11 +87,10 @@
87
87
  $effect(() => {
88
88
  wrapper.moveToValue(value)
89
89
  })
90
-
91
90
  </script>
92
91
 
93
92
  {#snippet collapsibleIcon(proxy: ProxyItem)}
94
- {#if collapsible && proxy.hasChildren}
93
+ {#if collapsible && proxy.hasChildren}
95
94
  <span
96
95
  data-list-expand-icon
97
96
  class={proxy.expanded ? icons.opened : icons.closed}
@@ -113,7 +112,11 @@
113
112
  {#each wrapper.flatView as node (node.key)}
114
113
  {@const proxy = node.proxy}
115
114
  {@const isActive = proxy.value === value}
116
- {@const content = resolveSnippet(snippets as Record<string, unknown>, proxy, node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET)}
115
+ {@const content = resolveSnippet(
116
+ snippets as Record<string, unknown>,
117
+ proxy,
118
+ node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
119
+ )}
117
120
 
118
121
  {#if node.type === 'separator'}
119
122
  <hr data-list-separator />
@@ -137,10 +140,10 @@
137
140
  {#if content}
138
141
  {@render content(proxy)}
139
142
  {:else}
140
- <ItemContent {proxy} />
143
+ <ItemContent {proxy} />
141
144
  {/if}
142
145
 
143
- {@render collapsibleIcon(proxy)}
146
+ {@render collapsibleIcon(proxy)}
144
147
  </button>
145
148
  {:else if proxy.get('href')}
146
149
  <!--
@@ -159,7 +162,7 @@
159
162
  {#if content}
160
163
  {@render content(proxy)}
161
164
  {:else}
162
- <ItemContent {proxy} />
165
+ <ItemContent {proxy} />
163
166
  {/if}
164
167
  </a>
165
168
  {:else}
@@ -180,7 +183,7 @@
180
183
  {#if content}
181
184
  {@render content(proxy)}
182
185
  {:else}
183
- <ItemContent {proxy} />
186
+ <ItemContent {proxy} />
184
187
  {/if}
185
188
  </button>
186
189
  {/if}
@@ -137,7 +137,9 @@
137
137
  isOpen = true
138
138
  requestAnimationFrame(() => wrapper.first(null))
139
139
  },
140
- onclose: () => { isOpen = false },
140
+ onclose: () => {
141
+ isOpen = false
142
+ },
141
143
  onlast: () => requestAnimationFrame(() => wrapper.last(null))
142
144
  })
143
145
  return () => t.destroy()
@@ -213,16 +215,15 @@
213
215
 
214
216
  {#if isOpen}
215
217
  <!-- svelte-ignore a11y_no_static_element_interactions -->
216
- <div
217
- bind:this={dropdownRef}
218
- data-menu-dropdown
219
- role="menu"
220
- aria-orientation="vertical"
221
- >
218
+ <div bind:this={dropdownRef} data-menu-dropdown role="menu" aria-orientation="vertical">
222
219
  {#each wrapper.flatView as node (node.key)}
223
220
  {@const proxy = node.proxy}
224
221
  {@const isActive = proxy.value === value}
225
- {@const content = resolveSnippet(snippets as Record<string, unknown>, proxy, node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET)}
222
+ {@const content = resolveSnippet(
223
+ snippets as Record<string, unknown>,
224
+ proxy,
225
+ node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
226
+ )}
226
227
 
227
228
  {#if node.type === 'separator'}
228
229
  <hr data-menu-separator />
@@ -70,7 +70,12 @@
70
70
  [key: string]: unknown
71
71
  } = $props()
72
72
 
73
- const icons = $derived({ ...DEFAULT_STATE_ICONS.selector, ...DEFAULT_STATE_ICONS.checkbox, ...DEFAULT_STATE_ICONS.action, ...userIcons })
73
+ const icons = $derived({
74
+ ...DEFAULT_STATE_ICONS.selector,
75
+ ...DEFAULT_STATE_ICONS.checkbox,
76
+ ...DEFAULT_STATE_ICONS.action,
77
+ ...userIcons
78
+ })
74
79
 
75
80
  // ─── Dropdown state ───────────────────────────────────────────────────────
76
81
 
@@ -198,7 +203,9 @@
198
203
  isOpen = true
199
204
  requestAnimationFrame(() => wrapper.first(null))
200
205
  },
201
- onclose: () => { isOpen = false },
206
+ onclose: () => {
207
+ isOpen = false
208
+ },
202
209
  onlast: () => requestAnimationFrame(() => wrapper.last(null))
203
210
  })
204
211
  return () => t.destroy()
@@ -322,7 +329,11 @@
322
329
  {#each wrapper.flatView as node (node.key)}
323
330
  {@const proxy = node.proxy}
324
331
  {@const sel = !node.hasChildren && isItemSelected(proxy.value)}
325
- {@const content = resolveSnippet(snippets as Record<string, unknown>, proxy, node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET)}
332
+ {@const content = resolveSnippet(
333
+ snippets as Record<string, unknown>,
334
+ proxy,
335
+ node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
336
+ )}
326
337
 
327
338
  {#if node.type === 'separator'}
328
339
  <hr data-select-separator />
@@ -117,7 +117,7 @@
117
117
 
118
118
  // Add # if missing
119
119
  if (hex && !hex.startsWith('#')) {
120
- hex = `#${ hex}`
120
+ hex = `#${hex}`
121
121
  }
122
122
 
123
123
  hexInputs[role] = hex
@@ -278,11 +278,7 @@
278
278
  </div>
279
279
  {/snippet}
280
280
 
281
- <div
282
- data-palette-manager
283
- data-compact={compact || undefined}
284
- class={className || undefined}
285
- >
281
+ <div data-palette-manager data-compact={compact || undefined} class={className || undefined}>
286
282
  {#if showPresets && presets.length > 0}
287
283
  <div data-palette-presets>
288
284
  <span data-palette-presets-label>Presets</span>
@@ -8,14 +8,14 @@
8
8
  class?: string
9
9
  }
10
10
 
11
- const {
12
- value = null,
13
- max = 100,
14
- class: className = ''
15
- }: ProgressBarProps = $props()
11
+ const { value = null, max = 100, class: className = '' }: ProgressBarProps = $props()
16
12
 
17
- const indeterminate = $derived(value === null || value === undefined || max === null || max === undefined)
18
- const percentage = $derived(indeterminate ? 100 : Math.min(100, Math.max(0, (value! / max!) * 100)))
13
+ const indeterminate = $derived(
14
+ value === null || value === undefined || max === null || max === undefined
15
+ )
16
+ const percentage = $derived(
17
+ indeterminate ? 100 : Math.min(100, Math.max(0, (value! / max!) * 100))
18
+ )
19
19
  </script>
20
20
 
21
21
  <div
@@ -62,9 +62,7 @@
62
62
 
63
63
  let selectedLeft = $derived(rangeMode ? valueToPercent(lower) : 0)
64
64
  let selectedWidth = $derived(
65
- rangeMode
66
- ? valueToPercent(upper) - valueToPercent(lower)
67
- : valueToPercent(value)
65
+ rangeMode ? valueToPercent(upper) - valueToPercent(lower) : valueToPercent(value)
68
66
  )
69
67
 
70
68
  // ─── Ticks ──────────────────────────────────────────────────────
@@ -87,7 +85,11 @@
87
85
  if (disabled || trackWidth === 0) return
88
86
  const dx = event.detail.dx as number
89
87
  const currentPx = inverseLerp(rangeMode ? upper : value, min, max) * trackWidth
90
- const newPx = clamp(currentPx + dx, rangeMode ? inverseLerp(lower, min, max) * trackWidth : 0, trackWidth)
88
+ const newPx = clamp(
89
+ currentPx + dx,
90
+ rangeMode ? inverseLerp(lower, min, max) * trackWidth : 0,
91
+ trackWidth
92
+ )
91
93
  const raw = pixelToValue(newPx)
92
94
  const snapped = snapToStep(clamp(raw, rangeMode ? lower : min, max))
93
95
  if (rangeMode) {
@@ -243,19 +245,11 @@
243
245
  </script>
244
246
 
245
247
  <!-- svelte-ignore a11y_no_static_element_interactions -->
246
- <div
247
- data-range
248
- data-disabled={disabled || undefined}
249
- class={className || undefined}
250
- >
248
+ <div data-range data-disabled={disabled || undefined} class={className || undefined}>
251
249
  <!-- svelte-ignore a11y_click_events_have_key_events -->
252
250
  <div data-range-track onclick={handleTrackClick}>
253
251
  <div data-range-bar bind:clientWidth={trackWidth}></div>
254
- <div
255
- data-range-selected
256
- style:left="{selectedLeft}%"
257
- style:width="{selectedWidth}%"
258
- ></div>
252
+ <div data-range-selected style:left="{selectedLeft}%" style:width="{selectedWidth}%"></div>
259
253
 
260
254
  {#if rangeMode}
261
255
  <!-- Lower thumb -->
@@ -270,8 +264,12 @@
270
264
  onpanmove={handleLowerPanMove}
271
265
  onpanend={handleLowerPanEnd}
272
266
  onkeydown={handleLowerKeyDown}
273
- onfocus={() => { if (!disabled) slidingLower = true }}
274
- onblur={() => { slidingLower = false }}
267
+ onfocus={() => {
268
+ if (!disabled) slidingLower = true
269
+ }}
270
+ onblur={() => {
271
+ slidingLower = false
272
+ }}
275
273
  role="slider"
276
274
  aria-valuenow={lower}
277
275
  aria-valuemin={min}
@@ -293,8 +291,12 @@
293
291
  onpanmove={handleUpperPanMove}
294
292
  onpanend={handleUpperPanEnd}
295
293
  onkeydown={handleUpperKeyDown}
296
- onfocus={() => { if (!disabled) slidingUpper = true }}
297
- onblur={() => { slidingUpper = false }}
294
+ onfocus={() => {
295
+ if (!disabled) slidingUpper = true
296
+ }}
297
+ onblur={() => {
298
+ slidingUpper = false
299
+ }}
298
300
  role="slider"
299
301
  aria-valuenow={rangeMode ? upper : value}
300
302
  aria-valuemin={rangeMode ? lower : min}
@@ -92,8 +92,12 @@
92
92
  aria-checked={filled}
93
93
  aria-label="Rate {index + 1} of {max}"
94
94
  onclick={() => handleClick(index)}
95
- onmouseenter={() => { if (!disabled) hoverIndex = index }}
96
- onmouseleave={() => { hoverIndex = -1 }}
95
+ onmouseenter={() => {
96
+ if (!disabled) hoverIndex = index
97
+ }}
98
+ onmouseleave={() => {
99
+ hoverIndex = -1
100
+ }}
97
101
  >
98
102
  <span data-rating-icon class={filled ? icons.filled : icons.empty} aria-hidden="true"></span>
99
103
  </span>
@@ -78,8 +78,8 @@
78
78
  data-search-tag-remove
79
79
  onclick={() => removeFilter(i)}
80
80
  aria-label={labels.remove}
81
- type="button"
82
- >&times;</button>
81
+ type="button">&times;</button
82
+ >
83
83
  </span>
84
84
  {/if}
85
85
  {/each}
@@ -84,7 +84,11 @@
84
84
  [key: string]: unknown
85
85
  } = $props()
86
86
 
87
- const icons = $derived({ ...DEFAULT_STATE_ICONS.selector, ...DEFAULT_STATE_ICONS.checkbox, ...userIcons })
87
+ const icons = $derived({
88
+ ...DEFAULT_STATE_ICONS.selector,
89
+ ...DEFAULT_STATE_ICONS.checkbox,
90
+ ...userIcons
91
+ })
88
92
 
89
93
  // ─── Dropdown state ───────────────────────────────────────────────────────
90
94
 
@@ -109,11 +113,17 @@
109
113
  const children = item[childrenField]
110
114
  if (Array.isArray(children) && children.length > 0) {
111
115
  const matching = children.filter((child) =>
112
- String(child[textField] ?? '').toLowerCase().includes(query)
116
+ String(child[textField] ?? '')
117
+ .toLowerCase()
118
+ .includes(query)
113
119
  )
114
120
  return matching.length > 0 ? { ...item, [childrenField]: matching } : null
115
121
  }
116
- return String(item[textField] ?? '').toLowerCase().includes(query) ? item : null
122
+ return String(item[textField] ?? '')
123
+ .toLowerCase()
124
+ .includes(query)
125
+ ? item
126
+ : null
117
127
  })
118
128
  .filter(Boolean)
119
129
  })
@@ -325,12 +335,7 @@
325
335
 
326
336
  {#if isOpen}
327
337
  <!-- svelte-ignore a11y_no_static_element_interactions -->
328
- <div
329
- bind:this={dropdownRef}
330
- data-select-dropdown
331
- role="listbox"
332
- aria-orientation="vertical"
333
- >
338
+ <div bind:this={dropdownRef} data-select-dropdown role="listbox" aria-orientation="vertical">
334
339
  {#if filterable}
335
340
  <div data-select-filter>
336
341
  <!-- svelte-ignore a11y_autofocus -->
@@ -347,7 +352,11 @@
347
352
  {#each wrapper.flatView as node (node.key)}
348
353
  {@const proxy = node.proxy}
349
354
  {@const sel = !node.hasChildren && proxy.value === value}
350
- {@const content = resolveSnippet(snippets as Record<string, unknown>, proxy, node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET)}
355
+ {@const content = resolveSnippet(
356
+ snippets as Record<string, unknown>,
357
+ proxy,
358
+ node.hasChildren ? GROUP_SNIPPET : ITEM_SNIPPET
359
+ )}
351
360
 
352
361
  {#if node.type === 'separator'}
353
362
  <hr data-select-separator />
@@ -151,8 +151,10 @@
151
151
  <button
152
152
  type="button"
153
153
  data-stepper-dot
154
- data-active={index === current && stageIndex === currentStage || undefined}
155
- data-completed={step.completed || (index === current && stageIndex < currentStage) || undefined}
154
+ data-active={(index === current && stageIndex === currentStage) || undefined}
155
+ data-completed={step.completed ||
156
+ (index === current && stageIndex < currentStage) ||
157
+ undefined}
156
158
  disabled={!isClickable(index)}
157
159
  aria-label="Stage {stageIndex + 1}"
158
160
  onclick={() => handleDotClick(index, stageIndex)}
@@ -28,11 +28,14 @@
28
28
 
29
29
  // ─── Controller ─────────────────────────────────────────────────
30
30
 
31
- let controller = untrack(() => new TableController(data, {
32
- columns: userColumns,
33
- fields: userFields,
34
- value
35
- }))
31
+ let controller = untrack(
32
+ () =>
33
+ new TableController(data, {
34
+ columns: userColumns,
35
+ fields: userFields,
36
+ value
37
+ })
38
+ )
36
39
  let tableRef = $state<HTMLElement | null>(null)
37
40
 
38
41
  // Sync data changes to controller
@@ -141,11 +144,7 @@
141
144
  onfocusin={handleFocusIn}
142
145
  use:navigator={{ wrapper: controller, orientation: 'vertical' }}
143
146
  >
144
- <table
145
- role="grid"
146
- aria-label={caption}
147
- data-striped={striped || undefined}
148
- >
147
+ <table role="grid" aria-label={caption} data-striped={striped || undefined}>
149
148
  {#if caption}
150
149
  <caption data-table-caption>{caption}</caption>
151
150
  {/if}
@@ -162,7 +161,11 @@
162
161
  data-sortable={column.sortable !== false || undefined}
163
162
  data-sort-order={column.sorted ?? 'none'}
164
163
  scope="col"
165
- aria-sort={column.sorted === 'ascending' ? 'ascending' : column.sorted === 'descending' ? 'descending' : 'none'}
164
+ aria-sort={column.sorted === 'ascending'
165
+ ? 'ascending'
166
+ : column.sorted === 'descending'
167
+ ? 'descending'
168
+ : 'none'}
166
169
  style:width={column.width}
167
170
  style:text-align={column.align}
168
171
  onclick={(e) => handleSort(e, column)}
@@ -188,9 +191,7 @@
188
191
  </tr>
189
192
  {:else}
190
193
  <tr data-table-empty-row>
191
- <td data-table-empty colspan={controller.columns.length}>
192
- No data
193
- </td>
194
+ <td data-table-empty colspan={controller.columns.length}> No data </td>
194
195
  </tr>
195
196
  {/if}
196
197
  {:else}
@@ -212,20 +213,12 @@
212
213
  >
213
214
  {#each controller.columns as column (column.name)}
214
215
  {#if cellSnippet}
215
- <td
216
- data-table-cell
217
- data-column={column.name}
218
- style:text-align={column.align}
219
- >
216
+ <td data-table-cell data-column={column.name} style:text-align={column.align}>
220
217
  {@render cellSnippet(getCellValue(row, column), column, row)}
221
218
  </td>
222
219
  {:else}
223
220
  {@const cellIcon = getCellIcon(row, column)}
224
- <td
225
- data-table-cell
226
- data-column={column.name}
227
- style:text-align={column.align}
228
- >
221
+ <td data-table-cell data-column={column.name} style:text-align={column.align}>
229
222
  {#if cellIcon}
230
223
  <span data-cell-icon class={cellIcon} aria-hidden="true"></span>
231
224
  {/if}
@@ -49,7 +49,15 @@
49
49
  // ─── Wrapper ──────────────────────────────────────────────────────────────
50
50
 
51
51
  const proxyTree = $derived(new ProxyTree(options, userFields))
52
- const wrapper = $derived(new Wrapper(proxyTree, { onchange, onselect }))
52
+ const wrapper = $derived(
53
+ new Wrapper(proxyTree, {
54
+ onchange,
55
+ onselect: (v, proxy) => {
56
+ value = v
57
+ onselect?.(v, proxy)
58
+ }
59
+ })
60
+ )
53
61
 
54
62
  // ─── Navigator ────────────────────────────────────────────────────────────
55
63
 
@@ -90,8 +98,17 @@
90
98
  role="button"
91
99
  tabindex="-1"
92
100
  aria-label={labels.remove}
93
- onclick={(e) => { e.stopPropagation(); handleRemove(proxy) }}
94
- onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation(); e.preventDefault(); handleRemove(proxy) } }}
101
+ onclick={(e) => {
102
+ e.stopPropagation()
103
+ handleRemove(proxy)
104
+ }}
105
+ onkeydown={(e) => {
106
+ if (e.key === 'Enter' || e.key === ' ') {
107
+ e.stopPropagation()
108
+ e.preventDefault()
109
+ handleRemove(proxy)
110
+ }
111
+ }}
95
112
  >
96
113
  <span class={DEFAULT_STATE_ICONS.action.close} aria-hidden="true"></span>
97
114
  </span>
@@ -153,12 +170,7 @@
153
170
  </button>
154
171
  {/each}
155
172
  {#if editable}
156
- <button
157
- type="button"
158
- data-tabs-add
159
- aria-label={labels.add}
160
- onclick={handleAdd}
161
- >
173
+ <button type="button" data-tabs-add aria-label={labels.add} onclick={handleAdd}>
162
174
  <span class="i-lucide:plus" aria-hidden="true"></span>
163
175
  </button>
164
176
  {/if}