@rokkit/ui 1.0.0-next.127 → 1.0.0-next.129

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 (54) hide show
  1. package/package.json +6 -16
  2. package/src/components/BreadCrumbs.svelte +37 -17
  3. package/src/components/Button.svelte +11 -5
  4. package/src/components/Carousel.svelte +11 -6
  5. package/src/components/Code.svelte +6 -2
  6. package/src/components/FloatingAction.svelte +24 -21
  7. package/src/components/FloatingNavigation.svelte +36 -29
  8. package/src/components/Grid.svelte +128 -0
  9. package/src/components/ItemContent.svelte +21 -20
  10. package/src/components/LazyTree.svelte +165 -0
  11. package/src/components/List.svelte +146 -434
  12. package/src/components/Menu.svelte +195 -346
  13. package/src/components/MultiSelect.svelte +238 -390
  14. package/src/components/PaletteManager.svelte +15 -5
  15. package/src/components/Pill.svelte +19 -14
  16. package/src/components/Range.svelte +8 -3
  17. package/src/components/Rating.svelte +19 -9
  18. package/src/components/Reveal.svelte +1 -13
  19. package/src/components/SearchFilter.svelte +11 -3
  20. package/src/components/Select.svelte +265 -454
  21. package/src/components/Stepper.svelte +9 -6
  22. package/src/components/Switch.svelte +11 -11
  23. package/src/components/Table.svelte +0 -1
  24. package/src/components/Tabs.svelte +96 -172
  25. package/src/components/Timeline.svelte +5 -5
  26. package/src/components/Toggle.svelte +55 -119
  27. package/src/components/Toolbar.svelte +24 -23
  28. package/src/components/Tree.svelte +115 -584
  29. package/src/components/UploadFileStatus.svelte +83 -0
  30. package/src/components/UploadProgress.svelte +131 -0
  31. package/src/components/UploadTarget.svelte +124 -0
  32. package/src/components/index.ts +5 -0
  33. package/src/index.ts +6 -1
  34. package/src/types/button.ts +3 -0
  35. package/src/types/code.ts +4 -4
  36. package/src/types/floating-action.ts +13 -8
  37. package/src/types/floating-navigation.ts +14 -2
  38. package/src/types/index.ts +5 -3
  39. package/src/types/list.ts +10 -6
  40. package/src/types/menu.ts +38 -138
  41. package/src/types/palette.ts +17 -0
  42. package/src/types/select.ts +33 -63
  43. package/src/types/switch.ts +9 -5
  44. package/src/types/table.ts +6 -6
  45. package/src/types/tabs.ts +13 -34
  46. package/src/types/timeline.ts +5 -3
  47. package/src/types/toggle.ts +15 -56
  48. package/src/types/toolbar.ts +1 -1
  49. package/src/types/tree.ts +9 -18
  50. package/src/types/upload-file-status.ts +45 -0
  51. package/src/types/upload-progress.ts +111 -0
  52. package/src/types/upload-target.ts +68 -0
  53. package/src/utils/upload.js +128 -0
  54. package/src/types/item-proxy.ts +0 -358
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/ui",
3
- "version": "1.0.0-next.127",
3
+ "version": "1.0.0-next.129",
4
4
  "description": "Data driven UI components for Rokkit applications",
5
5
  "type": "module",
6
6
  "svelte": "./src/index.ts",
@@ -25,8 +25,6 @@
25
25
  ],
26
26
  "scripts": {
27
27
  "check": "svelte-check --tsconfig ./tsconfig.json",
28
- "test": "vitest run",
29
- "test:watch": "vitest",
30
28
  "build": "echo 'No build step needed for source-only package'"
31
29
  },
32
30
  "keywords": [
@@ -37,26 +35,18 @@
37
35
  "dropdown"
38
36
  ],
39
37
  "dependencies": {
40
- "@rokkit/core": "1.0.0-next.127",
41
- "@rokkit/data": "1.0.0-next.127",
42
- "@rokkit/states": "1.0.0-next.127",
43
- "@rokkit/actions": "1.0.0-next.127"
38
+ "@rokkit/core": "1.0.0-next.129",
39
+ "@rokkit/data": "1.0.0-next.129",
40
+ "@rokkit/states": "1.0.0-next.129",
41
+ "@rokkit/actions": "1.0.0-next.129"
44
42
  },
45
43
  "peerDependencies": {
46
44
  "shiki": "^3.23.0",
47
45
  "svelte": "^5.0.0"
48
46
  },
49
47
  "devDependencies": {
50
- "@sveltejs/vite-plugin-svelte": "^6.2.4",
51
- "@testing-library/jest-dom": "^6.9.1",
52
- "@testing-library/svelte": "^5.3.1",
53
- "@testing-library/user-event": "^14.6.1",
54
- "@vitest/browser": "^4.0.18",
55
- "playwright": "^1.58.2",
56
48
  "svelte": "^5.53.5",
57
49
  "svelte-check": "^4.4.3",
58
- "typescript": "^5.9.3",
59
- "vite": "^7.3.1",
60
- "vitest": "^4.0.18"
50
+ "typescript": "^5.9.3"
61
51
  }
62
52
  }
@@ -1,18 +1,23 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte'
3
- import { ItemProxy, type ItemFields } from '../types/item-proxy.js'
3
+ import { ProxyItem, messages } from '@rokkit/states'
4
+ import { DEFAULT_STATE_ICONS } from '@rokkit/core'
5
+
6
+ interface BreadCrumbsIcons {
7
+ separator?: string
8
+ }
4
9
 
5
10
  interface BreadCrumbsProps {
6
11
  /** Array of breadcrumb items */
7
12
  items?: unknown[]
8
13
  /** Custom field mappings */
9
- fields?: Partial<ItemFields>
10
- /** Separator icon class (default: 'i-lucide:chevron-right') */
11
- separator?: string
14
+ fields?: Record<string, string>
15
+ /** Custom icons */
16
+ icons?: BreadCrumbsIcons
12
17
  /** Callback when a breadcrumb is clicked */
13
18
  onclick?: (value: unknown, item: unknown) => void
14
19
  /** Custom snippet for rendering each crumb */
15
- crumb?: Snippet<[ItemProxy, boolean]>
20
+ crumb?: Snippet<[ProxyItem, boolean]>
16
21
  /** Additional CSS class */
17
22
  class?: string
18
23
  }
@@ -20,29 +25,32 @@
20
25
  const {
21
26
  items = [],
22
27
  fields,
23
- separator = 'i-lucide:chevron-right',
28
+ label = messages.current.breadcrumbs.label,
29
+ icons: userIcons = {} as BreadCrumbsIcons,
24
30
  onclick,
25
31
  crumb,
26
32
  class: className = ''
27
- }: BreadCrumbsProps = $props()
33
+ }: BreadCrumbsProps & { label?: string } = $props()
28
34
 
29
- function createProxy(item: unknown): ItemProxy {
30
- return new ItemProxy(item as Record<string, unknown>, fields)
35
+ const icons = $derived({ separator: DEFAULT_STATE_ICONS.navigate.right, ...userIcons })
36
+
37
+ function createProxy(item: unknown): ProxyItem {
38
+ return new ProxyItem(item, fields)
31
39
  }
32
40
 
33
- function handleClick(proxy: ItemProxy) {
34
- onclick?.(proxy.itemValue, proxy.original)
41
+ function handleClick(proxy: ProxyItem) {
42
+ onclick?.(proxy.value, proxy.original)
35
43
  }
36
44
  </script>
37
45
 
38
- {#snippet defaultCrumb(proxy: ItemProxy, _isLast: boolean)}
39
- {#if proxy.icon}
40
- <span data-breadcrumb-icon class={proxy.icon} aria-hidden="true"></span>
46
+ {#snippet defaultCrumb(proxy: ProxyItem, _isLast: boolean)}
47
+ {#if proxy.get('icon')}
48
+ <span data-breadcrumb-icon class={proxy.get('icon')} aria-hidden="true"></span>
41
49
  {/if}
42
- <span data-breadcrumb-label>{proxy.text}</span>
50
+ <span data-breadcrumb-label>{proxy.label}</span>
43
51
  {/snippet}
44
52
 
45
- <nav data-breadcrumbs class={className || undefined} aria-label="Breadcrumb">
53
+ <nav data-breadcrumbs class={className || undefined} aria-label={label}>
46
54
  <ol data-breadcrumb-list>
47
55
  {#each items as item, index (index)}
48
56
  {@const proxy = createProxy(item)}
@@ -50,7 +58,7 @@
50
58
 
51
59
  {#if index > 0}
52
60
  <li data-breadcrumb-separator aria-hidden="true">
53
- <span class={separator}></span>
61
+ <span class={icons.separator}></span>
54
62
  </li>
55
63
  {/if}
56
64
 
@@ -63,6 +71,18 @@
63
71
  {@render defaultCrumb(proxy, isLast)}
64
72
  {/if}
65
73
  </span>
74
+ {:else if proxy.get('href')}
75
+ <a
76
+ href={proxy.get('href')}
77
+ data-breadcrumb-link
78
+ onclick={() => handleClick(proxy)}
79
+ >
80
+ {#if crumb}
81
+ {@render crumb(proxy, isLast)}
82
+ {:else}
83
+ {@render defaultCrumb(proxy, isLast)}
84
+ {/if}
85
+ </a>
66
86
  {:else}
67
87
  <button
68
88
  type="button"
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { ButtonProps } from '../types/button.js'
3
- import { ItemProxy } from '../types/item-proxy.js'
3
+ import { ProxyItem } from '@rokkit/states'
4
4
  import ItemContent from './ItemContent.svelte'
5
5
 
6
6
  let {
@@ -12,23 +12,25 @@
12
12
  icon,
13
13
  iconRight,
14
14
  href,
15
- target,
15
+ target = '_self',
16
+ title,
16
17
  disabled = false,
17
18
  loading = false,
18
19
  onclick,
19
20
  class: className = '',
20
- children
21
+ children,
22
+ ...rest
21
23
  }: ButtonProps = $props()
22
24
 
23
25
  const isIconOnly = $derived(Boolean(icon) && !label && !children)
24
26
  const isDisabled = $derived(disabled || loading)
25
27
 
26
28
  /**
27
- * Create an ItemProxy for default content rendering.
29
+ * Create a ProxyItem for default content rendering.
28
30
  * Constructs a minimal item from button props.
29
31
  */
30
32
  const proxy = $derived(
31
- new ItemProxy({ text: label, icon, iconRight }, { text: 'text', icon: 'icon' })
33
+ new ProxyItem({ text: label, icon, iconRight })
32
34
  )
33
35
  </script>
34
36
 
@@ -46,6 +48,7 @@
46
48
  <a
47
49
  {href}
48
50
  {target}
51
+ {title}
49
52
  data-button
50
53
  data-variant={variant}
51
54
  data-style={style}
@@ -55,6 +58,7 @@
55
58
  class={className || undefined}
56
59
  aria-label={label}
57
60
  aria-busy={loading || undefined}
61
+ {...rest}
58
62
  >
59
63
  {#if children}
60
64
  {@render children()}
@@ -65,6 +69,7 @@
65
69
  {:else}
66
70
  <button
67
71
  {type}
72
+ {title}
68
73
  data-button
69
74
  data-variant={variant}
70
75
  data-style={style}
@@ -77,6 +82,7 @@
77
82
  aria-label={label}
78
83
  aria-busy={loading || undefined}
79
84
  {onclick}
85
+ {...rest}
80
86
  >
81
87
  {#if children}
82
88
  {@render children()}
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte'
3
3
  import { swipeable, keyboard } from '@rokkit/actions'
4
+ import { messages } from '@rokkit/states'
4
5
 
5
6
  interface CarouselProps {
6
7
  /** Number of slides (required when using children snippet) */
@@ -36,10 +37,13 @@
36
37
  showDots = true,
37
38
  showArrows = true,
38
39
  transition = 'slide',
40
+ labels: userLabels = {},
39
41
  class: className = '',
40
42
  slide,
41
43
  children
42
- }: CarouselProps = $props()
44
+ }: CarouselProps & { labels?: Record<string, string> } = $props()
45
+
46
+ const labels = $derived({ ...messages.current.carousel, ...userLabels })
43
47
 
44
48
  let hovered = $state(false)
45
49
 
@@ -85,13 +89,14 @@
85
89
  </script>
86
90
 
87
91
  <!-- svelte-ignore a11y_no_static_element_interactions -->
92
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
88
93
  <div
89
94
  data-carousel
90
95
  data-carousel-transition={transition}
91
96
  class={className || undefined}
92
- role="group"
97
+ role="application"
93
98
  aria-roledescription="carousel"
94
- aria-label="Carousel"
99
+ aria-label={labels.label}
95
100
  tabindex="0"
96
101
  use:swipeable={{ horizontal: true, vertical: false }}
97
102
  use:keyboard={keyMap}
@@ -133,7 +138,7 @@
133
138
  <button
134
139
  data-carousel-prev
135
140
  type="button"
136
- aria-label="Previous slide"
141
+ aria-label={labels.prev}
137
142
  onclick={prev}
138
143
  disabled={!loop && current === 0}
139
144
  >
@@ -143,7 +148,7 @@
143
148
  <button
144
149
  data-carousel-next
145
150
  type="button"
146
- aria-label="Next slide"
151
+ aria-label={labels.next}
147
152
  onclick={next}
148
153
  disabled={!loop && current === count - 1}
149
154
  >
@@ -152,7 +157,7 @@
152
157
  {/if}
153
158
 
154
159
  {#if showDots && count > 1}
155
- <div data-carousel-dots role="tablist" aria-label="Slide navigation">
160
+ <div data-carousel-dots role="tablist" aria-label={labels.slides}>
156
161
  {#each Array(count) as _, index (index)}
157
162
  <button
158
163
  data-carousel-dot
@@ -2,6 +2,7 @@
2
2
  import type { CodeProps, CodeStateIcons } from '../types/index.js'
3
3
  import { defaultCodeStateIcons } from '../types/code.js'
4
4
  import { highlightCode } from '../utils/shiki.js'
5
+ import { messages } from '@rokkit/states'
5
6
 
6
7
  const {
7
8
  code,
@@ -9,9 +10,12 @@
9
10
  theme = 'dark',
10
11
  showLineNumbers = false,
11
12
  showCopyButton = true,
13
+ labels: userLabels = {},
12
14
  icons: userIcons,
13
15
  class: className = ''
14
- }: CodeProps = $props()
16
+ }: CodeProps & { labels?: Record<string, string> } = $props()
17
+
18
+ const labels = $derived({ ...messages.current.code, ...userLabels })
15
19
 
16
20
  // Merge icons with defaults
17
21
  const icons = $derived<CodeStateIcons>({ ...defaultCodeStateIcons, ...userIcons })
@@ -55,7 +59,7 @@
55
59
  type="button"
56
60
  class="copy-button"
57
61
  onclick={copyToClipboard}
58
- aria-label={copied ? 'Copied!' : 'Copy code'}
62
+ aria-label={copied ? labels.copied : labels.copy}
59
63
  >
60
64
  {#if copied}
61
65
  <span class="copy-icon {icons.copysuccess}"></span>
@@ -3,16 +3,17 @@
3
3
  FloatingActionProps,
4
4
  FloatingActionItem,
5
5
  FloatingActionItemSnippet,
6
- FloatingActionItemHandlers
6
+ FloatingActionItemHandlers,
7
+ FloatingActionIcons
7
8
  } from '../types/floating-action.js'
8
9
  import { getSnippet } from '../types/floating-action.js'
9
- import { ItemProxy } from '../types/item-proxy.js'
10
+ import { ProxyItem } from '@rokkit/states'
11
+ import { DEFAULT_STATE_ICONS } from '@rokkit/core'
10
12
 
11
13
  let {
12
14
  items = [],
13
15
  fields: userFields,
14
- icon = 'i-lucide:plus',
15
- closeIcon = 'i-lucide:x',
16
+ icons: userIcons = {} as FloatingActionIcons,
16
17
  label = 'Actions',
17
18
  size = 'md',
18
19
  position = 'bottom-right',
@@ -30,11 +31,13 @@
30
31
  ...snippets
31
32
  }: FloatingActionProps & { [key: string]: FloatingActionItemSnippet | unknown } = $props()
32
33
 
34
+ const icons = $derived({ add: DEFAULT_STATE_ICONS.action.add, close: DEFAULT_STATE_ICONS.action.close, ...userIcons })
35
+
33
36
  /**
34
- * Create an ItemProxy for the given item
37
+ * Create a ProxyItem for the given item
35
38
  */
36
- function createProxy(item: FloatingActionItem): ItemProxy {
37
- return new ItemProxy(item, userFields)
39
+ function createProxy(item: FloatingActionItem): ProxyItem {
40
+ return new ProxyItem(item, userFields)
38
41
  }
39
42
 
40
43
  let fabRef = $state<HTMLDivElement | null>(null)
@@ -82,9 +85,9 @@
82
85
  /**
83
86
  * Handle item selection
84
87
  */
85
- function handleItemClick(item: { proxy: ItemProxy; original: FloatingActionItem }) {
88
+ function handleItemClick(item: { proxy: ProxyItem; original: FloatingActionItem }) {
86
89
  if (item.proxy.disabled) return
87
- onselect?.(item.proxy.itemValue, item.original)
90
+ onselect?.(item.proxy.value, item.original)
88
91
  close()
89
92
  // Return focus to trigger
90
93
  const trigger = fabRef?.querySelector('[data-fab-trigger]') as HTMLElement | undefined
@@ -162,7 +165,7 @@
162
165
  */
163
166
  function handleItemKeyDown(
164
167
  event: KeyboardEvent,
165
- item: { proxy: ItemProxy; original: FloatingActionItem }
168
+ item: { proxy: ProxyItem; original: FloatingActionItem }
166
169
  ) {
167
170
  if (event.key === 'Enter' || event.key === ' ') {
168
171
  event.preventDefault()
@@ -190,7 +193,7 @@
190
193
  * Create handlers object for custom snippets
191
194
  */
192
195
  function createHandlers(item: {
193
- proxy: ItemProxy
196
+ proxy: ProxyItem
194
197
  original: FloatingActionItem
195
198
  }): FloatingActionItemHandlers {
196
199
  return {
@@ -202,8 +205,8 @@
202
205
  /**
203
206
  * Resolve which snippet to use for an item
204
207
  */
205
- function resolveItemSnippet(proxy: ItemProxy): FloatingActionItemSnippet | null {
206
- const snippetName = proxy.snippetName
208
+ function resolveItemSnippet(proxy: ProxyItem): FloatingActionItemSnippet | null {
209
+ const snippetName = proxy.get('snippet')
207
210
  if (snippetName) {
208
211
  const namedSnippet = getSnippet(snippets, snippetName)
209
212
  if (namedSnippet) {
@@ -240,7 +243,7 @@
240
243
  </script>
241
244
 
242
245
  {#snippet defaultItem(
243
- proxy: ItemProxy,
246
+ proxy: ProxyItem,
244
247
  handlers: FloatingActionItemHandlers,
245
248
  index: number,
246
249
  total: number
@@ -251,22 +254,22 @@
251
254
  data-fab-index={index}
252
255
  data-disabled={proxy.disabled || undefined}
253
256
  disabled={proxy.disabled || disabled}
254
- aria-label={proxy.label || proxy.text}
257
+ aria-label={proxy.label}
255
258
  style="--fab-index: {index}; --fab-total: {total}; --fab-delay: {getItemDelay(index)}"
256
259
  onclick={handlers.onclick}
257
260
  onkeydown={handlers.onkeydown}
258
261
  >
259
- {#if proxy.icon}
260
- <span data-fab-item-icon class={proxy.icon} aria-hidden="true"></span>
262
+ {#if proxy.get('icon')}
263
+ <span data-fab-item-icon class={proxy.get('icon')} aria-hidden="true"></span>
261
264
  {/if}
262
- {#if proxy.text}
263
- <span data-fab-item-label>{proxy.text}</span>
265
+ {#if proxy.label}
266
+ <span data-fab-item-label>{proxy.label}</span>
264
267
  {/if}
265
268
  </button>
266
269
  {/snippet}
267
270
 
268
271
  {#snippet renderItem(
269
- item: { proxy: ItemProxy; original: FloatingActionItem },
272
+ item: { proxy: ProxyItem; original: FloatingActionItem },
270
273
  index: number,
271
274
  total: number
272
275
  )}
@@ -326,6 +329,6 @@
326
329
  onclick={toggle}
327
330
  onkeydown={handleTriggerKeyDown}
328
331
  >
329
- <span data-fab-icon class={open ? closeIcon : icon} aria-hidden="true"></span>
332
+ <span data-fab-icon class={open ? icons.close : icons.add} aria-hidden="true"></span>
330
333
  </button>
331
334
  </div>
@@ -1,22 +1,29 @@
1
1
  <script lang="ts">
2
- import type { FloatingNavigationProps } from '../types/floating-navigation.js'
3
- import { ItemProxy } from '../types/item-proxy.js'
2
+ import type { FloatingNavigationProps, FloatingNavigationIcons } from '../types/floating-navigation.js'
3
+ import { ProxyItem, messages } from '@rokkit/states'
4
+ import { DEFAULT_STATE_ICONS } from '@rokkit/core'
4
5
 
5
6
  let {
6
7
  items = [],
7
8
  fields: userFields,
9
+ icons: userIcons = {} as FloatingNavigationIcons,
8
10
  value = $bindable(),
9
11
  position = 'right',
10
12
  pinned = $bindable(false),
11
13
  observe = true,
12
14
  observerOptions = { rootMargin: '-20% 0px -70% 0px', threshold: 0 },
13
15
  size = 'md',
14
- label = 'Page navigation',
16
+ label = messages.current.floatingNav.label,
17
+ labels: userLabels = {},
15
18
  onselect,
16
19
  onpinchange,
17
20
  item: itemSnippet,
18
21
  class: className = ''
19
- }: FloatingNavigationProps = $props()
22
+ }: FloatingNavigationProps & { labels?: Record<string, string> } = $props()
23
+
24
+ const labels = $derived({ ...messages.current.floatingNav, ...userLabels })
25
+
26
+ const icons = $derived({ pin: DEFAULT_STATE_ICONS.action.pin, unpin: DEFAULT_STATE_ICONS.action.unpin, ...userIcons })
20
27
 
21
28
  let navRef = $state<HTMLElement | null>(null)
22
29
  let expanded = $state(false)
@@ -26,13 +33,13 @@
26
33
 
27
34
  const itemProxies = $derived(
28
35
  items.map((item) => ({
29
- proxy: new ItemProxy(item, userFields),
36
+ proxy: new ProxyItem(item, userFields),
30
37
  original: item
31
38
  }))
32
39
  )
33
40
 
34
41
  const activeIndex = $derived(
35
- itemProxies.findIndex((item) => item.proxy.itemValue === value)
42
+ itemProxies.findIndex((item) => item.proxy.value === value)
36
43
  )
37
44
 
38
45
  function togglePin() {
@@ -49,13 +56,13 @@
49
56
  if (!pinned) expanded = false
50
57
  }
51
58
 
52
- function handleItemClick(item: { proxy: ItemProxy; original: Record<string, unknown> }) {
53
- value = item.proxy.itemValue
54
- onselect?.(item.proxy.itemValue, item.original)
59
+ function handleItemClick(item: { proxy: ProxyItem; original: Record<string, unknown> }) {
60
+ value = item.proxy.value
61
+ onselect?.(item.proxy.value, item.original)
55
62
 
56
63
  // Smooth scroll to target section
57
- const href = item.proxy.has('href') ? String(item.original[userFields?.href ?? 'href'] ?? '') : ''
58
- const targetId = href.startsWith('#') ? href.slice(1) : String(item.proxy.itemValue)
64
+ const href = item.proxy.get('href') !== undefined ? String(item.original[userFields?.href ?? 'href'] ?? '') : ''
65
+ const targetId = href.startsWith('#') ? href.slice(1) : String(item.proxy.value)
59
66
  const el = document.getElementById(targetId)
60
67
  el?.scrollIntoView({ behavior: 'smooth' })
61
68
  }
@@ -116,24 +123,24 @@
116
123
  for (const entry of entries) {
117
124
  if (entry.isIntersecting) {
118
125
  const match = itemProxies.find((item) => {
119
- const href = item.proxy.has('href')
126
+ const href = item.proxy.get('href') !== undefined
120
127
  ? String(item.original[userFields?.href ?? 'href'] ?? '')
121
128
  : ''
122
- const targetId = href.startsWith('#') ? href.slice(1) : String(item.proxy.itemValue)
129
+ const targetId = href.startsWith('#') ? href.slice(1) : String(item.proxy.value)
123
130
  return targetId === entry.target.id
124
131
  })
125
132
  if (match) {
126
- value = match.proxy.itemValue
133
+ value = match.proxy.value
127
134
  }
128
135
  }
129
136
  }
130
137
  }, observerOptions)
131
138
 
132
139
  for (const item of itemProxies) {
133
- const href = item.proxy.has('href')
140
+ const href = item.proxy.get('href') !== undefined
134
141
  ? String(item.original[userFields?.href ?? 'href'] ?? '')
135
142
  : ''
136
- const targetId = href.startsWith('#') ? href.slice(1) : String(item.proxy.itemValue)
143
+ const targetId = href.startsWith('#') ? href.slice(1) : String(item.proxy.value)
137
144
  const el = document.getElementById(targetId)
138
145
  if (el) observer.observe(el)
139
146
  }
@@ -164,21 +171,21 @@
164
171
  type="button"
165
172
  data-floating-nav-pin
166
173
  aria-pressed={pinned}
167
- aria-label={pinned ? 'Unpin navigation' : 'Pin navigation'}
174
+ aria-label={pinned ? labels.unpin : labels.pin}
168
175
  onclick={togglePin}
169
176
  >
170
- <span class={pinned ? 'i-lucide:pin-off' : 'i-lucide:pin'} aria-hidden="true"></span>
177
+ <span data-floating-nav-pin-icon class={pinned ? icons.unpin : icons.pin} aria-hidden="true"></span>
171
178
  </button>
172
179
  </div>
173
180
 
174
181
  <div data-floating-nav-items>
175
- {#each itemProxies as item, index (item.proxy.itemValue ?? index)}
176
- {@const isActive = item.proxy.itemValue === value}
177
- {@const isLink = item.proxy.has('href')}
182
+ {#each itemProxies as item, index (item.proxy.value ?? index)}
183
+ {@const isActive = item.proxy.value === value}
184
+ {@const isLink = item.proxy.get('href') !== undefined}
178
185
  {#if itemSnippet}
179
186
  {@render itemSnippet(item.original, {
180
- text: item.proxy.text,
181
- icon: item.proxy.icon,
187
+ text: item.proxy.label,
188
+ icon: item.proxy.get('icon'),
182
189
  active: isActive
183
190
  })}
184
191
  {:else if isLink}
@@ -194,10 +201,10 @@
194
201
  handleItemClick(item)
195
202
  }}
196
203
  >
197
- {#if item.proxy.icon}
198
- <span data-floating-nav-icon class={item.proxy.icon} aria-hidden="true"></span>
204
+ {#if item.proxy.get('icon')}
205
+ <span data-floating-nav-icon class={item.proxy.get('icon')} aria-hidden="true"></span>
199
206
  {/if}
200
- <span data-floating-nav-label>{item.proxy.text}</span>
207
+ <span data-floating-nav-label>{item.proxy.label}</span>
201
208
  </a>
202
209
  {:else}
203
210
  <button
@@ -209,10 +216,10 @@
209
216
  style="--fn-index: {index}; --fn-total: {itemProxies.length}"
210
217
  onclick={() => handleItemClick(item)}
211
218
  >
212
- {#if item.proxy.icon}
213
- <span data-floating-nav-icon class={item.proxy.icon} aria-hidden="true"></span>
219
+ {#if item.proxy.get('icon')}
220
+ <span data-floating-nav-icon class={item.proxy.get('icon')} aria-hidden="true"></span>
214
221
  {/if}
215
- <span data-floating-nav-label>{item.proxy.text}</span>
222
+ <span data-floating-nav-label>{item.proxy.label}</span>
216
223
  </button>
217
224
  {/if}
218
225
  {/each}