torch-glare 1.2.8 → 1.3.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 (41) hide show
  1. package/apps/lib/components/TableDnDWrapper.ts +495 -0
  2. package/apps/lib/components/TextEditor.tsx +53 -1
  3. package/dist/bin/index.js +5 -0
  4. package/dist/bin/index.js.map +1 -1
  5. package/dist/src/commands/mcp.d.ts +2 -0
  6. package/dist/src/commands/mcp.d.ts.map +1 -0
  7. package/dist/src/commands/mcp.js +91 -0
  8. package/dist/src/commands/mcp.js.map +1 -0
  9. package/dist/src/shared/configureFonts.d.ts +6 -0
  10. package/dist/src/shared/configureFonts.d.ts.map +1 -0
  11. package/dist/src/shared/configureFonts.js +106 -0
  12. package/dist/src/shared/configureFonts.js.map +1 -0
  13. package/dist/src/shared/configureGlobalCss.d.ts +6 -0
  14. package/dist/src/shared/configureGlobalCss.d.ts.map +1 -0
  15. package/dist/src/shared/configureGlobalCss.js +154 -0
  16. package/dist/src/shared/configureGlobalCss.js.map +1 -0
  17. package/dist/src/shared/configureTailwind.d.ts +7 -0
  18. package/dist/src/shared/configureTailwind.d.ts.map +1 -0
  19. package/dist/src/shared/configureTailwind.js +163 -0
  20. package/dist/src/shared/configureTailwind.js.map +1 -0
  21. package/dist/src/shared/detectFramework.d.ts +23 -0
  22. package/dist/src/shared/detectFramework.d.ts.map +1 -0
  23. package/dist/src/shared/detectFramework.js +119 -0
  24. package/dist/src/shared/detectFramework.js.map +1 -0
  25. package/dist/src/shared/getDependenciesAndInstallNestedComponents.d.ts.map +1 -1
  26. package/dist/src/shared/getDependenciesAndInstallNestedComponents.js +18 -2
  27. package/dist/src/shared/getDependenciesAndInstallNestedComponents.js.map +1 -1
  28. package/dist/src/shared/installBaseUtils.d.ts +5 -0
  29. package/dist/src/shared/installBaseUtils.d.ts.map +1 -0
  30. package/dist/src/shared/installBaseUtils.js +79 -0
  31. package/dist/src/shared/installBaseUtils.js.map +1 -0
  32. package/dist/src/shared/resolveAliases.d.ts +24 -0
  33. package/dist/src/shared/resolveAliases.d.ts.map +1 -0
  34. package/dist/src/shared/resolveAliases.js +98 -0
  35. package/dist/src/shared/resolveAliases.js.map +1 -0
  36. package/docs/components/breadcrumb.md +955 -0
  37. package/docs/components/button-group.md +647 -0
  38. package/docs/components/text-editor.md +711 -0
  39. package/docs/components/toggle-button.md +640 -0
  40. package/docs/tutorials/getting-started.md +123 -431
  41. package/package.json +1 -1
@@ -0,0 +1,955 @@
1
+ ---
2
+ name: Breadcrumb
3
+ version: 1.1.15
4
+ status: stable
5
+ category: components/navigation
6
+ tags: [navigation, breadcrumb, wayfinding, compound, accessible, rtl]
7
+ last-reviewed: 2024-11-05
8
+ bundle-size: 2.2kb
9
+ dependencies:
10
+ - "@radix-ui/react-slot": "^1.0.0"
11
+ - "class-variance-authority": "^0.7.0"
12
+ ---
13
+
14
+ # Breadcrumb
15
+
16
+ > A compound breadcrumb navigation component with seven sub-components for building flexible, accessible breadcrumb trails. Supports multiple sizes, two style variants, the asChild pattern for custom link components, and collapsible ellipsis for long paths.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install torch-glare
22
+ ```
23
+
24
+ ## Import
25
+
26
+ ```typescript
27
+ import {
28
+ Breadcrumb,
29
+ BreadcrumbList,
30
+ BreadcrumbItem,
31
+ BreadcrumbLink,
32
+ BreadcrumbPage,
33
+ BreadcrumbSeparator,
34
+ BreadcrumbEllipsis,
35
+ } from 'torch-glare/lib/components/Breadcrumb'
36
+ // or
37
+ import {
38
+ Breadcrumb,
39
+ BreadcrumbList,
40
+ BreadcrumbItem,
41
+ BreadcrumbLink,
42
+ BreadcrumbPage,
43
+ BreadcrumbSeparator,
44
+ BreadcrumbEllipsis,
45
+ } from 'torch-glare/lib/components'
46
+ ```
47
+
48
+ ## Quick Examples
49
+
50
+ ### Basic Usage
51
+
52
+ ```typescript
53
+ import {
54
+ Breadcrumb,
55
+ BreadcrumbList,
56
+ BreadcrumbItem,
57
+ BreadcrumbLink,
58
+ BreadcrumbPage,
59
+ BreadcrumbSeparator,
60
+ } from 'torch-glare/lib/components/Breadcrumb'
61
+
62
+ function Example() {
63
+ return (
64
+ <Breadcrumb>
65
+ <BreadcrumbList>
66
+ <BreadcrumbItem>
67
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
68
+ </BreadcrumbItem>
69
+ <BreadcrumbSeparator />
70
+ <BreadcrumbItem>
71
+ <BreadcrumbLink href="/products">Products</BreadcrumbLink>
72
+ </BreadcrumbItem>
73
+ <BreadcrumbSeparator />
74
+ <BreadcrumbItem>
75
+ <BreadcrumbPage>Current Product</BreadcrumbPage>
76
+ </BreadcrumbItem>
77
+ </BreadcrumbList>
78
+ </Breadcrumb>
79
+ )
80
+ }
81
+ ```
82
+
83
+ ### With Different Sizes
84
+
85
+ ```typescript
86
+ // Small
87
+ <Breadcrumb>
88
+ <BreadcrumbList size="S">
89
+ <BreadcrumbItem>
90
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
91
+ </BreadcrumbItem>
92
+ <BreadcrumbSeparator />
93
+ <BreadcrumbItem>
94
+ <BreadcrumbPage>Page</BreadcrumbPage>
95
+ </BreadcrumbItem>
96
+ </BreadcrumbList>
97
+ </Breadcrumb>
98
+
99
+ // Medium (default)
100
+ <Breadcrumb>
101
+ <BreadcrumbList size="M">
102
+ <BreadcrumbItem>
103
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
104
+ </BreadcrumbItem>
105
+ <BreadcrumbSeparator />
106
+ <BreadcrumbItem>
107
+ <BreadcrumbPage>Page</BreadcrumbPage>
108
+ </BreadcrumbItem>
109
+ </BreadcrumbList>
110
+ </Breadcrumb>
111
+
112
+ // Large
113
+ <Breadcrumb>
114
+ <BreadcrumbList size="L">
115
+ <BreadcrumbItem>
116
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
117
+ </BreadcrumbItem>
118
+ <BreadcrumbSeparator />
119
+ <BreadcrumbItem>
120
+ <BreadcrumbPage>Page</BreadcrumbPage>
121
+ </BreadcrumbItem>
122
+ </BreadcrumbList>
123
+ </Breadcrumb>
124
+ ```
125
+
126
+ ### With SystemStyle Variant
127
+
128
+ ```typescript
129
+ <Breadcrumb>
130
+ <BreadcrumbList>
131
+ <BreadcrumbItem>
132
+ <BreadcrumbLink variant="SystemStyle" href="/">Home</BreadcrumbLink>
133
+ </BreadcrumbItem>
134
+ <BreadcrumbSeparator variant="SystemStyle" />
135
+ <BreadcrumbItem>
136
+ <BreadcrumbLink variant="SystemStyle" href="/docs">Docs</BreadcrumbLink>
137
+ </BreadcrumbItem>
138
+ <BreadcrumbSeparator variant="SystemStyle" />
139
+ <BreadcrumbItem>
140
+ <BreadcrumbPage variant="SystemStyle">API</BreadcrumbPage>
141
+ </BreadcrumbItem>
142
+ </BreadcrumbList>
143
+ </Breadcrumb>
144
+ ```
145
+
146
+ ### With Ellipsis (Collapsed Items)
147
+
148
+ ```typescript
149
+ <Breadcrumb>
150
+ <BreadcrumbList>
151
+ <BreadcrumbItem>
152
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
153
+ </BreadcrumbItem>
154
+ <BreadcrumbSeparator />
155
+ <BreadcrumbItem>
156
+ <BreadcrumbEllipsis />
157
+ </BreadcrumbItem>
158
+ <BreadcrumbSeparator />
159
+ <BreadcrumbItem>
160
+ <BreadcrumbLink href="/category/subcategory">Subcategory</BreadcrumbLink>
161
+ </BreadcrumbItem>
162
+ <BreadcrumbSeparator />
163
+ <BreadcrumbItem>
164
+ <BreadcrumbPage>Current Page</BreadcrumbPage>
165
+ </BreadcrumbItem>
166
+ </BreadcrumbList>
167
+ </Breadcrumb>
168
+ ```
169
+
170
+ ### With Custom Separator
171
+
172
+ ```typescript
173
+ <Breadcrumb>
174
+ <BreadcrumbList>
175
+ <BreadcrumbItem>
176
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
177
+ </BreadcrumbItem>
178
+ <BreadcrumbSeparator>
179
+ <i className="ri-arrow-right-s-line" />
180
+ </BreadcrumbSeparator>
181
+ <BreadcrumbItem>
182
+ <BreadcrumbLink href="/docs">Docs</BreadcrumbLink>
183
+ </BreadcrumbItem>
184
+ <BreadcrumbSeparator>
185
+ /
186
+ </BreadcrumbSeparator>
187
+ <BreadcrumbItem>
188
+ <BreadcrumbPage>Guide</BreadcrumbPage>
189
+ </BreadcrumbItem>
190
+ </BreadcrumbList>
191
+ </Breadcrumb>
192
+ ```
193
+
194
+ ### With asChild (Custom Link Component)
195
+
196
+ ```typescript
197
+ import Link from 'next/link'
198
+
199
+ <Breadcrumb>
200
+ <BreadcrumbList>
201
+ <BreadcrumbItem>
202
+ <BreadcrumbLink asChild>
203
+ <Link href="/">Home</Link>
204
+ </BreadcrumbLink>
205
+ </BreadcrumbItem>
206
+ <BreadcrumbSeparator />
207
+ <BreadcrumbItem>
208
+ <BreadcrumbLink asChild>
209
+ <Link href="/products">Products</Link>
210
+ </BreadcrumbLink>
211
+ </BreadcrumbItem>
212
+ <BreadcrumbSeparator />
213
+ <BreadcrumbItem>
214
+ <BreadcrumbPage>Details</BreadcrumbPage>
215
+ </BreadcrumbItem>
216
+ </BreadcrumbList>
217
+ </Breadcrumb>
218
+ ```
219
+
220
+ ### With Theme Override
221
+
222
+ ```typescript
223
+ <Breadcrumb theme="dark">
224
+ <BreadcrumbList>
225
+ <BreadcrumbItem>
226
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
227
+ </BreadcrumbItem>
228
+ <BreadcrumbSeparator />
229
+ <BreadcrumbItem>
230
+ <BreadcrumbPage>Dark Page</BreadcrumbPage>
231
+ </BreadcrumbItem>
232
+ </BreadcrumbList>
233
+ </Breadcrumb>
234
+ ```
235
+
236
+ ### With Icons
237
+
238
+ ```typescript
239
+ <Breadcrumb>
240
+ <BreadcrumbList>
241
+ <BreadcrumbItem>
242
+ <BreadcrumbLink href="/">
243
+ <i className="ri-home-line mr-1" />
244
+ Home
245
+ </BreadcrumbLink>
246
+ </BreadcrumbItem>
247
+ <BreadcrumbSeparator />
248
+ <BreadcrumbItem>
249
+ <BreadcrumbLink href="/settings">
250
+ <i className="ri-settings-line mr-1" />
251
+ Settings
252
+ </BreadcrumbLink>
253
+ </BreadcrumbItem>
254
+ <BreadcrumbSeparator />
255
+ <BreadcrumbItem>
256
+ <BreadcrumbPage>
257
+ <i className="ri-user-line mr-1" />
258
+ Profile
259
+ </BreadcrumbPage>
260
+ </BreadcrumbItem>
261
+ </BreadcrumbList>
262
+ </Breadcrumb>
263
+ ```
264
+
265
+ ## API Reference
266
+
267
+ ### Breadcrumb (Root)
268
+
269
+ | Prop | Type | Default | Description |
270
+ |------|------|---------|-------------|
271
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme for the breadcrumb |
272
+ | `className` | `string` | - | Additional CSS classes |
273
+
274
+ Renders a `<nav>` element with `aria-label="breadcrumb"`.
275
+
276
+ ### BreadcrumbList
277
+
278
+ | Prop | Type | Default | Description |
279
+ |------|------|---------|-------------|
280
+ | `size` | `'S' \| 'M' \| 'L'` | `'M'` | Text size and gap spacing |
281
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme |
282
+ | `className` | `string` | - | Additional CSS classes |
283
+
284
+ Renders an `<ol>` element with flex-wrap layout.
285
+
286
+ ### BreadcrumbItem
287
+
288
+ | Prop | Type | Default | Description |
289
+ |------|------|---------|-------------|
290
+ | `className` | `string` | - | Additional CSS classes |
291
+
292
+ Renders an `<li>` element with inline-flex alignment.
293
+
294
+ ### BreadcrumbLink
295
+
296
+ | Prop | Type | Default | Description |
297
+ |------|------|---------|-------------|
298
+ | `variant` | `'PresentationStyle' \| 'SystemStyle'` | `'PresentationStyle'` | Visual style variant |
299
+ | `asChild` | `boolean` | `false` | Merge props onto child element (Slot pattern) |
300
+ | `href` | `string` | - | Link destination URL |
301
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme |
302
+ | `className` | `string` | - | Additional CSS classes |
303
+
304
+ Renders an `<a>` element (or child via Slot when `asChild` is true).
305
+
306
+ ### BreadcrumbPage
307
+
308
+ | Prop | Type | Default | Description |
309
+ |------|------|---------|-------------|
310
+ | `variant` | `'PresentationStyle' \| 'SystemStyle'` | `'PresentationStyle'` | Visual style variant |
311
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme |
312
+ | `className` | `string` | - | Additional CSS classes |
313
+
314
+ Renders a `<span>` with `aria-current="page"` and `aria-disabled="true"`.
315
+
316
+ ### BreadcrumbSeparator
317
+
318
+ | Prop | Type | Default | Description |
319
+ |------|------|---------|-------------|
320
+ | `variant` | `'PresentationStyle' \| 'SystemStyle'` | `'PresentationStyle'` | Visual style variant |
321
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme |
322
+ | `children` | `React.ReactNode` | `<i className="ri-arrow-right-s-line" />` | Custom separator content |
323
+ | `className` | `string` | - | Additional CSS classes |
324
+
325
+ Renders an `<li>` with `role="presentation"` and `aria-hidden="true"`. Defaults to a right-arrow icon.
326
+
327
+ ### BreadcrumbEllipsis
328
+
329
+ | Prop | Type | Default | Description |
330
+ |------|------|---------|-------------|
331
+ | `variant` | `'PresentationStyle' \| 'SystemStyle'` | `'PresentationStyle'` | Visual style variant |
332
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme |
333
+ | `className` | `string` | - | Additional CSS classes |
334
+
335
+ Renders a `<span>` with `role="presentation"`, `aria-hidden="true"`, and a "More" screen-reader label. Displays a `ri-more-line` icon.
336
+
337
+ ### Size Variants (BreadcrumbList)
338
+
339
+ | Size | Text Size | Gap |
340
+ |------|-----------|-----|
341
+ | S | 12px | 4px (gap-1) |
342
+ | M | 14px | 6px (gap-1.5) |
343
+ | L | 16px | 8px (gap-2) |
344
+
345
+ ### TypeScript
346
+
347
+ ```typescript
348
+ import { ComponentPropsWithoutRef } from 'react'
349
+ import { VariantProps } from 'class-variance-authority'
350
+
351
+ type Themes = 'light' | 'dark' | 'default'
352
+
353
+ interface BreadcrumbProps extends ComponentPropsWithoutRef<'nav'> {
354
+ theme?: Themes
355
+ separator?: React.ReactNode
356
+ }
357
+
358
+ interface BreadcrumbListProps
359
+ extends ComponentPropsWithoutRef<'ol'>,
360
+ VariantProps<typeof breadcrumbListStyles> {
361
+ theme?: Themes
362
+ }
363
+
364
+ interface BreadcrumbLinkProps
365
+ extends ComponentPropsWithoutRef<'a'>,
366
+ VariantProps<typeof breadcrumbLinkStyles> {
367
+ asChild?: boolean
368
+ theme?: Themes
369
+ }
370
+
371
+ interface BreadcrumbPageProps
372
+ extends ComponentPropsWithoutRef<'span'>,
373
+ VariantProps<typeof breadcrumbPageStyles> {
374
+ theme?: Themes
375
+ }
376
+
377
+ interface BreadcrumbSeparatorProps
378
+ extends ComponentPropsWithoutRef<'li'>,
379
+ VariantProps<typeof breadcrumbSeparatorStyles> {
380
+ theme?: Themes
381
+ }
382
+
383
+ interface BreadcrumbEllipsisProps
384
+ extends ComponentPropsWithoutRef<'span'>,
385
+ VariantProps<typeof breadcrumbEllipsisStyles> {
386
+ theme?: Themes
387
+ }
388
+
389
+ export const Breadcrumb: React.ForwardRefExoticComponent<
390
+ BreadcrumbProps & React.RefAttributes<HTMLElement>
391
+ >
392
+ export const BreadcrumbList: React.ForwardRefExoticComponent<
393
+ BreadcrumbListProps & React.RefAttributes<HTMLOListElement>
394
+ >
395
+ export const BreadcrumbItem: React.ForwardRefExoticComponent<
396
+ ComponentPropsWithoutRef<'li'> & React.RefAttributes<HTMLLIElement>
397
+ >
398
+ export const BreadcrumbLink: React.ForwardRefExoticComponent<
399
+ BreadcrumbLinkProps & React.RefAttributes<HTMLAnchorElement>
400
+ >
401
+ export const BreadcrumbPage: React.ForwardRefExoticComponent<
402
+ BreadcrumbPageProps & React.RefAttributes<HTMLSpanElement>
403
+ >
404
+ export const BreadcrumbSeparator: React.ForwardRefExoticComponent<
405
+ BreadcrumbSeparatorProps & React.RefAttributes<HTMLLIElement>
406
+ >
407
+ export const BreadcrumbEllipsis: React.ForwardRefExoticComponent<
408
+ BreadcrumbEllipsisProps & React.RefAttributes<HTMLSpanElement>
409
+ >
410
+
411
+ export {
412
+ breadcrumbListStyles,
413
+ breadcrumbLinkStyles,
414
+ breadcrumbPageStyles,
415
+ breadcrumbSeparatorStyles,
416
+ breadcrumbEllipsisStyles,
417
+ }
418
+ ```
419
+
420
+ ## Common Patterns
421
+
422
+ ### Dynamic Breadcrumb from Route
423
+
424
+ ```typescript
425
+ function DynamicBreadcrumb({ segments }: { segments: { label: string; href: string }[] }) {
426
+ return (
427
+ <Breadcrumb>
428
+ <BreadcrumbList>
429
+ {segments.map((segment, index) => {
430
+ const isLast = index === segments.length - 1
431
+
432
+ return (
433
+ <React.Fragment key={segment.href}>
434
+ <BreadcrumbItem>
435
+ {isLast ? (
436
+ <BreadcrumbPage>{segment.label}</BreadcrumbPage>
437
+ ) : (
438
+ <BreadcrumbLink href={segment.href}>
439
+ {segment.label}
440
+ </BreadcrumbLink>
441
+ )}
442
+ </BreadcrumbItem>
443
+ {!isLast && <BreadcrumbSeparator />}
444
+ </React.Fragment>
445
+ )
446
+ })}
447
+ </BreadcrumbList>
448
+ </Breadcrumb>
449
+ )
450
+ }
451
+
452
+ // Usage
453
+ <DynamicBreadcrumb
454
+ segments={[
455
+ { label: 'Home', href: '/' },
456
+ { label: 'Products', href: '/products' },
457
+ { label: 'Electronics', href: '/products/electronics' },
458
+ { label: 'Laptops', href: '/products/electronics/laptops' },
459
+ ]}
460
+ />
461
+ ```
462
+
463
+ ### Collapsible Breadcrumb with Dropdown
464
+
465
+ ```typescript
466
+ import { DropdownMenu } from 'torch-glare/lib/components/DropdownMenu'
467
+
468
+ function CollapsibleBreadcrumb({
469
+ items,
470
+ maxVisible = 3
471
+ }: {
472
+ items: { label: string; href: string }[]
473
+ maxVisible?: number
474
+ }) {
475
+ const shouldCollapse = items.length > maxVisible
476
+ const visibleStart = items.slice(0, 1)
477
+ const collapsed = shouldCollapse ? items.slice(1, items.length - (maxVisible - 1)) : []
478
+ const visibleEnd = shouldCollapse ? items.slice(items.length - (maxVisible - 1)) : items.slice(1)
479
+
480
+ return (
481
+ <Breadcrumb>
482
+ <BreadcrumbList>
483
+ {/* First item always visible */}
484
+ {visibleStart.map((item) => (
485
+ <React.Fragment key={item.href}>
486
+ <BreadcrumbItem>
487
+ <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>
488
+ </BreadcrumbItem>
489
+ <BreadcrumbSeparator />
490
+ </React.Fragment>
491
+ ))}
492
+
493
+ {/* Collapsed items shown as ellipsis */}
494
+ {collapsed.length > 0 && (
495
+ <>
496
+ <BreadcrumbItem>
497
+ <DropdownMenu>
498
+ <DropdownMenu.Trigger asChild>
499
+ <BreadcrumbEllipsis />
500
+ </DropdownMenu.Trigger>
501
+ <DropdownMenu.Content>
502
+ {collapsed.map((item) => (
503
+ <DropdownMenu.Item key={item.href} asChild>
504
+ <a href={item.href}>{item.label}</a>
505
+ </DropdownMenu.Item>
506
+ ))}
507
+ </DropdownMenu.Content>
508
+ </DropdownMenu>
509
+ </BreadcrumbItem>
510
+ <BreadcrumbSeparator />
511
+ </>
512
+ )}
513
+
514
+ {/* Remaining visible items */}
515
+ {visibleEnd.map((item, index) => {
516
+ const isLast = index === visibleEnd.length - 1
517
+ return (
518
+ <React.Fragment key={item.href}>
519
+ <BreadcrumbItem>
520
+ {isLast ? (
521
+ <BreadcrumbPage>{item.label}</BreadcrumbPage>
522
+ ) : (
523
+ <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>
524
+ )}
525
+ </BreadcrumbItem>
526
+ {!isLast && <BreadcrumbSeparator />}
527
+ </React.Fragment>
528
+ )
529
+ })}
530
+ </BreadcrumbList>
531
+ </Breadcrumb>
532
+ )
533
+ }
534
+ ```
535
+
536
+ ### Next.js App Router Integration
537
+
538
+ ```typescript
539
+ 'use client'
540
+
541
+ import { usePathname } from 'next/navigation'
542
+ import Link from 'next/link'
543
+
544
+ function AppBreadcrumb() {
545
+ const pathname = usePathname()
546
+ const segments = pathname.split('/').filter(Boolean)
547
+
548
+ return (
549
+ <Breadcrumb>
550
+ <BreadcrumbList>
551
+ <BreadcrumbItem>
552
+ <BreadcrumbLink asChild>
553
+ <Link href="/">Home</Link>
554
+ </BreadcrumbLink>
555
+ </BreadcrumbItem>
556
+
557
+ {segments.map((segment, index) => {
558
+ const href = '/' + segments.slice(0, index + 1).join('/')
559
+ const isLast = index === segments.length - 1
560
+ const label = segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' ')
561
+
562
+ return (
563
+ <React.Fragment key={href}>
564
+ <BreadcrumbSeparator />
565
+ <BreadcrumbItem>
566
+ {isLast ? (
567
+ <BreadcrumbPage>{label}</BreadcrumbPage>
568
+ ) : (
569
+ <BreadcrumbLink asChild>
570
+ <Link href={href}>{label}</Link>
571
+ </BreadcrumbLink>
572
+ )}
573
+ </BreadcrumbItem>
574
+ </React.Fragment>
575
+ )
576
+ })}
577
+ </BreadcrumbList>
578
+ </Breadcrumb>
579
+ )
580
+ }
581
+ ```
582
+
583
+ ### File Explorer Breadcrumb
584
+
585
+ ```typescript
586
+ function FileExplorerBreadcrumb({
587
+ path,
588
+ onNavigate
589
+ }: {
590
+ path: string[]
591
+ onNavigate: (index: number) => void
592
+ }) {
593
+ return (
594
+ <Breadcrumb>
595
+ <BreadcrumbList size="S">
596
+ <BreadcrumbItem>
597
+ <BreadcrumbLink
598
+ href="#"
599
+ onClick={(e) => { e.preventDefault(); onNavigate(-1) }}
600
+ >
601
+ <i className="ri-folder-line mr-1" />
602
+ Root
603
+ </BreadcrumbLink>
604
+ </BreadcrumbItem>
605
+
606
+ {path.map((folder, index) => {
607
+ const isLast = index === path.length - 1
608
+ return (
609
+ <React.Fragment key={index}>
610
+ <BreadcrumbSeparator />
611
+ <BreadcrumbItem>
612
+ {isLast ? (
613
+ <BreadcrumbPage>
614
+ <i className="ri-folder-open-line mr-1" />
615
+ {folder}
616
+ </BreadcrumbPage>
617
+ ) : (
618
+ <BreadcrumbLink
619
+ href="#"
620
+ onClick={(e) => { e.preventDefault(); onNavigate(index) }}
621
+ >
622
+ <i className="ri-folder-line mr-1" />
623
+ {folder}
624
+ </BreadcrumbLink>
625
+ )}
626
+ </BreadcrumbItem>
627
+ </React.Fragment>
628
+ )
629
+ })}
630
+ </BreadcrumbList>
631
+ </Breadcrumb>
632
+ )
633
+ }
634
+ ```
635
+
636
+ ## Testing
637
+
638
+ ### Unit Test Example
639
+
640
+ ```typescript
641
+ import { render, screen } from '@testing-library/react'
642
+ import {
643
+ Breadcrumb,
644
+ BreadcrumbList,
645
+ BreadcrumbItem,
646
+ BreadcrumbLink,
647
+ BreadcrumbPage,
648
+ BreadcrumbSeparator,
649
+ BreadcrumbEllipsis,
650
+ } from 'torch-glare/lib/components/Breadcrumb'
651
+
652
+ describe('Breadcrumb', () => {
653
+ it('renders navigation landmark', () => {
654
+ render(
655
+ <Breadcrumb>
656
+ <BreadcrumbList>
657
+ <BreadcrumbItem>
658
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
659
+ </BreadcrumbItem>
660
+ </BreadcrumbList>
661
+ </Breadcrumb>
662
+ )
663
+
664
+ expect(screen.getByRole('navigation')).toHaveAttribute('aria-label', 'breadcrumb')
665
+ })
666
+
667
+ it('renders links as anchors', () => {
668
+ render(
669
+ <Breadcrumb>
670
+ <BreadcrumbList>
671
+ <BreadcrumbItem>
672
+ <BreadcrumbLink href="/test">Test</BreadcrumbLink>
673
+ </BreadcrumbItem>
674
+ </BreadcrumbList>
675
+ </Breadcrumb>
676
+ )
677
+
678
+ const link = screen.getByText('Test')
679
+ expect(link.tagName).toBe('A')
680
+ expect(link).toHaveAttribute('href', '/test')
681
+ })
682
+
683
+ it('marks current page with aria-current', () => {
684
+ render(
685
+ <Breadcrumb>
686
+ <BreadcrumbList>
687
+ <BreadcrumbItem>
688
+ <BreadcrumbPage>Current</BreadcrumbPage>
689
+ </BreadcrumbItem>
690
+ </BreadcrumbList>
691
+ </Breadcrumb>
692
+ )
693
+
694
+ const page = screen.getByText('Current')
695
+ expect(page).toHaveAttribute('aria-current', 'page')
696
+ expect(page).toHaveAttribute('aria-disabled', 'true')
697
+ })
698
+
699
+ it('hides separators from accessibility tree', () => {
700
+ const { container } = render(
701
+ <Breadcrumb>
702
+ <BreadcrumbList>
703
+ <BreadcrumbItem>
704
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
705
+ </BreadcrumbItem>
706
+ <BreadcrumbSeparator />
707
+ <BreadcrumbItem>
708
+ <BreadcrumbPage>Page</BreadcrumbPage>
709
+ </BreadcrumbItem>
710
+ </BreadcrumbList>
711
+ </Breadcrumb>
712
+ )
713
+
714
+ const separator = container.querySelector('[role="presentation"]')
715
+ expect(separator).toHaveAttribute('aria-hidden', 'true')
716
+ })
717
+
718
+ it('renders ellipsis with screen reader text', () => {
719
+ render(
720
+ <Breadcrumb>
721
+ <BreadcrumbList>
722
+ <BreadcrumbItem>
723
+ <BreadcrumbEllipsis />
724
+ </BreadcrumbItem>
725
+ </BreadcrumbList>
726
+ </Breadcrumb>
727
+ )
728
+
729
+ expect(screen.getByText('More')).toHaveClass('sr-only')
730
+ })
731
+
732
+ it('applies size variant to list', () => {
733
+ const { container } = render(
734
+ <Breadcrumb>
735
+ <BreadcrumbList size="L">
736
+ <BreadcrumbItem>
737
+ <BreadcrumbPage>Page</BreadcrumbPage>
738
+ </BreadcrumbItem>
739
+ </BreadcrumbList>
740
+ </Breadcrumb>
741
+ )
742
+
743
+ const list = container.querySelector('ol')
744
+ expect(list).toHaveClass('text-[16px]', 'gap-2')
745
+ })
746
+ })
747
+ ```
748
+
749
+ ### Accessibility Test
750
+
751
+ ```typescript
752
+ import { axe } from '@axe-core/react'
753
+
754
+ test('Breadcrumb meets WCAG standards', async () => {
755
+ const { container } = render(
756
+ <Breadcrumb>
757
+ <BreadcrumbList>
758
+ <BreadcrumbItem>
759
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
760
+ </BreadcrumbItem>
761
+ <BreadcrumbSeparator />
762
+ <BreadcrumbItem>
763
+ <BreadcrumbPage>Current Page</BreadcrumbPage>
764
+ </BreadcrumbItem>
765
+ </BreadcrumbList>
766
+ </Breadcrumb>
767
+ )
768
+
769
+ const results = await axe(container)
770
+ expect(results).toHaveNoViolations()
771
+ })
772
+ ```
773
+
774
+ ## Accessibility
775
+
776
+ ### Semantic HTML
777
+
778
+ The Breadcrumb component renders proper semantic structure:
779
+
780
+ ```html
781
+ <nav aria-label="breadcrumb">
782
+ <ol>
783
+ <li>
784
+ <a href="/">Home</a>
785
+ </li>
786
+ <li role="presentation" aria-hidden="true">
787
+ <!-- separator icon -->
788
+ </li>
789
+ <li>
790
+ <span role="link" aria-disabled="true" aria-current="page">
791
+ Current Page
792
+ </span>
793
+ </li>
794
+ </ol>
795
+ </nav>
796
+ ```
797
+
798
+ ### ARIA Attributes
799
+
800
+ - `<nav aria-label="breadcrumb">`: Identifies the navigation landmark
801
+ - `<span aria-current="page">`: Marks the current page in the trail
802
+ - `<span aria-disabled="true">`: Indicates the current page is not interactive
803
+ - `<li role="presentation" aria-hidden="true">`: Hides decorative separators
804
+ - `<span role="presentation" aria-hidden="true">`: Hides decorative ellipsis
805
+
806
+ ### Keyboard Support
807
+
808
+ - **Tab**: Navigate between breadcrumb links
809
+ - **Enter**: Activate focused link
810
+ - **Space**: Activate focused link
811
+
812
+ ### Screen Reader Support
813
+
814
+ - Navigation landmark announced as "breadcrumb"
815
+ - Links are announced with their text content
816
+ - Current page announced with "current page" semantics
817
+ - Separators and ellipsis hidden from screen readers
818
+ - "More" label provided for ellipsis via `sr-only` text
819
+
820
+ ### Best Practices
821
+
822
+ ```typescript
823
+ // Use BreadcrumbPage for the current/last item (not a link)
824
+ <BreadcrumbPage>Current Page</BreadcrumbPage>
825
+
826
+ // Use BreadcrumbLink for navigable items
827
+ <BreadcrumbLink href="/path">Navigable</BreadcrumbLink>
828
+
829
+ // Use asChild with framework routing components
830
+ <BreadcrumbLink asChild>
831
+ <Link href="/path">Next.js Link</Link>
832
+ </BreadcrumbLink>
833
+ ```
834
+
835
+ ## Styling
836
+
837
+ ### Variant Styles
838
+
839
+ #### PresentationStyle (Default)
840
+
841
+ - **Links**: `text-content-presentation-global-secondary`, hover to `text-content-presentation-global-primary`
842
+ - **Current Page**: `text-content-presentation-global-primary`
843
+ - **Separator**: `text-content-presentation-global-secondary`
844
+ - **Ellipsis**: hover `bg-background-presentation-action-hover`
845
+
846
+ #### SystemStyle
847
+
848
+ - **Links**: `text-content-system-global-secondary`, hover to `text-content-system-global-primary`
849
+ - **Current Page**: `text-content-system-global-primary`
850
+ - **Separator**: `text-content-system-global-secondary`
851
+ - **Ellipsis**: hover `bg-background-system-action-secondary-hover`
852
+
853
+ ### Link Interactions
854
+
855
+ ```css
856
+ /* Links have hover underline and focus ring */
857
+ hover:underline
858
+ focus-visible:ring-2
859
+ focus-visible:ring-border-presentation-state-focus
860
+ focus-visible:rounded-[2px]
861
+ ```
862
+
863
+ ### Ellipsis Dimensions
864
+
865
+ ```css
866
+ /* Fixed 24x24px clickable area with rounded corners */
867
+ w-6 h-6
868
+ rounded-[4px]
869
+ cursor-pointer
870
+ ```
871
+
872
+ ### Custom Styles
873
+
874
+ ```typescript
875
+ <Breadcrumb className="bg-gray-50 px-4 py-2 rounded-lg">
876
+ <BreadcrumbList>
877
+ <BreadcrumbItem>
878
+ <BreadcrumbLink href="/" className="text-blue-600">Home</BreadcrumbLink>
879
+ </BreadcrumbItem>
880
+ <BreadcrumbSeparator className="text-gray-400" />
881
+ <BreadcrumbItem>
882
+ <BreadcrumbPage className="font-bold">Page</BreadcrumbPage>
883
+ </BreadcrumbItem>
884
+ </BreadcrumbList>
885
+ </Breadcrumb>
886
+ ```
887
+
888
+ ## Performance
889
+
890
+ | Metric | Value |
891
+ |--------|-------|
892
+ | Bundle size (gzip) | 2.2kb |
893
+ | First render | <5ms |
894
+ | Re-render | <2ms |
895
+ | Tree-shakeable | Yes |
896
+
897
+ ### Optimization Tips
898
+
899
+ 1. Use `React.Fragment` with keys for dynamic breadcrumb generation
900
+ 2. Memoize breadcrumb segments if derived from expensive computations
901
+ 3. Use `asChild` pattern to avoid extra DOM nodes when integrating with routers
902
+
903
+ ## Troubleshooting
904
+
905
+ ### Links not navigating with Next.js
906
+
907
+ **Solution:** Use the `asChild` prop to pass props to your framework's Link component:
908
+
909
+ ```typescript
910
+ <BreadcrumbLink asChild>
911
+ <Link href="/path">Page</Link>
912
+ </BreadcrumbLink>
913
+ ```
914
+
915
+ ### Separator icon not showing
916
+
917
+ **Solution:** Ensure Remix Icon CSS is loaded. The default separator uses `ri-arrow-right-s-line`. Alternatively, provide custom separator content:
918
+
919
+ ```typescript
920
+ <BreadcrumbSeparator>/</BreadcrumbSeparator>
921
+ ```
922
+
923
+ ### Breadcrumb wrapping on small screens
924
+
925
+ **Solution:** The BreadcrumbList uses `flex-wrap` by default. To prevent wrapping, add `flex-nowrap` and `overflow-hidden`:
926
+
927
+ ```typescript
928
+ <BreadcrumbList className="flex-nowrap overflow-hidden">
929
+ {/* items */}
930
+ </BreadcrumbList>
931
+ ```
932
+
933
+ ## Related Components
934
+
935
+ - [DropdownMenu](/docs/components/dropdown-menu.md) - Combine with BreadcrumbEllipsis for collapsed items
936
+ - [LinkButton](/docs/components/link-button.md) - Styled link actions
937
+ - [Button](/docs/components/button.md) - Action buttons
938
+
939
+ ## Browser Support
940
+
941
+ - Chrome 90+
942
+ - Firefox 88+
943
+ - Safari 14+
944
+ - Edge 90+
945
+ - Mobile browsers
946
+
947
+ ## Changelog
948
+
949
+ ### v1.1.15
950
+ - Initial stable release
951
+ - 7 sub-components (Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis)
952
+ - 2 style variants (PresentationStyle, SystemStyle)
953
+ - 3 list size variants (S, M, L)
954
+ - asChild pattern for custom link components
955
+ - Full accessibility with ARIA attributes and semantic HTML