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,640 @@
1
+ ---
2
+ name: ToggleButton
3
+ version: 1.1.15
4
+ status: stable
5
+ category: components/buttons
6
+ tags: [toggle, button, pressed, radix-ui, accessible, variants]
7
+ last-reviewed: 2024-11-05
8
+ bundle-size: 2.6kb
9
+ dependencies:
10
+ - "@radix-ui/react-toggle": "^1.0.0"
11
+ - "class-variance-authority": "^0.7.0"
12
+ ---
13
+
14
+ # ToggleButton
15
+
16
+ > A standalone toggle button component built on Radix UI Toggle with five visual variants, four sizes, and an icon-only mode. Renders as a two-state button with `data-[state=on]` active styling. Ideal for toolbar actions, feature toggles, and any on/off interaction.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install torch-glare
22
+ ```
23
+
24
+ ## Import
25
+
26
+ ```typescript
27
+ import { ToggleButton } from 'torch-glare/lib/components/ToggleButton'
28
+ // or
29
+ import { ToggleButton } from 'torch-glare/lib/components'
30
+
31
+ // Also available via ButtonGroup re-export
32
+ import { ToggleButton } from 'torch-glare/lib/components/ButtonGroup'
33
+ ```
34
+
35
+ ## Quick Examples
36
+
37
+ ### Basic Usage
38
+
39
+ ```typescript
40
+ import { ToggleButton } from 'torch-glare/lib/components/ToggleButton'
41
+
42
+ function Example() {
43
+ const [pressed, setPressed] = useState(false)
44
+
45
+ return (
46
+ <ToggleButton
47
+ pressed={pressed}
48
+ onPressedChange={setPressed}
49
+ >
50
+ <i className="ri-bold" />
51
+ </ToggleButton>
52
+ )
53
+ }
54
+ ```
55
+
56
+ ### All Variants
57
+
58
+ ```typescript
59
+ <ToggleButton variant="PrimeStyle">Prime</ToggleButton>
60
+ <ToggleButton variant="BlueSecStyle">Blue Secondary</ToggleButton>
61
+ <ToggleButton variant="BorderStyle">Border</ToggleButton>
62
+ <ToggleButton variant="PrimeContStyle">Prime Container</ToggleButton>
63
+ <ToggleButton variant="SystemStyle">System</ToggleButton>
64
+ ```
65
+
66
+ ### With Sizes
67
+
68
+ ```typescript
69
+ <ToggleButton size="S">Small</ToggleButton>
70
+ <ToggleButton size="M">Medium (Default)</ToggleButton>
71
+ <ToggleButton size="L">Large</ToggleButton>
72
+ <ToggleButton size="XL">Extra Large</ToggleButton>
73
+ ```
74
+
75
+ ### Icon-Only Mode
76
+
77
+ ```typescript
78
+ // Icon mode makes the button square (equal width and height)
79
+ <ToggleButton buttonType="icon" size="S" aria-label="Favorite">
80
+ <i className="ri-heart-line" />
81
+ </ToggleButton>
82
+
83
+ <ToggleButton buttonType="icon" size="M" aria-label="Bookmark">
84
+ <i className="ri-bookmark-line" />
85
+ </ToggleButton>
86
+
87
+ <ToggleButton buttonType="icon" size="L" aria-label="Star">
88
+ <i className="ri-star-line" />
89
+ </ToggleButton>
90
+
91
+ <ToggleButton buttonType="icon" size="XL" aria-label="Pin">
92
+ <i className="ri-pushpin-line" />
93
+ </ToggleButton>
94
+ ```
95
+
96
+ ### With Text and Icon
97
+
98
+ ```typescript
99
+ <ToggleButton variant="PrimeStyle" size="M">
100
+ <i className="ri-heart-line" />
101
+ Favorite
102
+ </ToggleButton>
103
+ ```
104
+
105
+ ### Controlled Toggle
106
+
107
+ ```typescript
108
+ function BookmarkButton() {
109
+ const [bookmarked, setBookmarked] = useState(false)
110
+
111
+ return (
112
+ <ToggleButton
113
+ variant={bookmarked ? 'BlueSecStyle' : 'BorderStyle'}
114
+ pressed={bookmarked}
115
+ onPressedChange={setBookmarked}
116
+ buttonType="icon"
117
+ size="M"
118
+ aria-label={bookmarked ? 'Remove bookmark' : 'Add bookmark'}
119
+ >
120
+ <i className={bookmarked ? 'ri-bookmark-fill' : 'ri-bookmark-line'} />
121
+ </ToggleButton>
122
+ )
123
+ }
124
+ ```
125
+
126
+ ### Uncontrolled Toggle
127
+
128
+ ```typescript
129
+ <ToggleButton defaultPressed aria-label="Notifications enabled">
130
+ <i className="ri-notification-line" />
131
+ </ToggleButton>
132
+ ```
133
+
134
+ ### Disabled State
135
+
136
+ ```typescript
137
+ <ToggleButton disabled>Disabled Off</ToggleButton>
138
+ <ToggleButton disabled pressed>Disabled On</ToggleButton>
139
+ ```
140
+
141
+ ### With Theme Override
142
+
143
+ ```typescript
144
+ <ToggleButton theme="dark" variant="PrimeStyle">
145
+ Dark Theme
146
+ </ToggleButton>
147
+
148
+ <ToggleButton theme="light" variant="BlueSecStyle">
149
+ Light Theme
150
+ </ToggleButton>
151
+ ```
152
+
153
+ ## API Reference
154
+
155
+ ### Props
156
+
157
+ | Prop | Type | Default | Description |
158
+ |------|------|---------|-------------|
159
+ | `pressed` | `boolean` | - | Controlled pressed state |
160
+ | `defaultPressed` | `boolean` | `false` | Uncontrolled default state |
161
+ | `onPressedChange` | `(pressed: boolean) => void` | - | Called when pressed state changes |
162
+ | `variant` | `VariantType` | `'PrimeStyle'` | Visual style variant |
163
+ | `size` | `'S' \| 'M' \| 'L' \| 'XL'` | `'M'` | Size of the toggle button |
164
+ | `buttonType` | `'default' \| 'icon'` | `'default'` | Set to `'icon'` for square dimensions |
165
+ | `disabled` | `boolean` | `false` | Disables the toggle button |
166
+ | `theme` | `'light' \| 'dark' \| 'default'` | - | Override theme for this component |
167
+ | `className` | `string` | - | Additional CSS classes |
168
+ | `children` | `React.ReactNode` | - | Toggle button content |
169
+
170
+ ### Variant Types
171
+
172
+ | Variant | Background | Active State | Description |
173
+ |---------|-----------|-------------|-------------|
174
+ | `PrimeStyle` | Secondary | Hover highlight | Default primary toggle style |
175
+ | `BlueSecStyle` | Secondary | Information blue | Blue secondary accent |
176
+ | `BorderStyle` | Border-style bg | Hover highlight | Bordered toggle style |
177
+ | `PrimeContStyle` | Transparent | Container hover | Minimal container style |
178
+ | `SystemStyle` | Black alpha 20 | White alpha 20 | Dark/system UI style |
179
+
180
+ ### Size Variants
181
+
182
+ | Size | Height | Width (default) | Width (icon) | Border Radius | Typography | Icon Size |
183
+ |------|--------|----------------|--------------|---------------|------------|-----------|
184
+ | S | 22px | auto (px: 8px) | 22px | 4px | Small Medium | 12px |
185
+ | M | 28px | auto (px: 12px) | 28px | 4px | Large Medium | 18px |
186
+ | L | 34px | auto (px: 16px) | 34px | 6px | Large Medium | 20px |
187
+ | XL | 40px | auto (px: 20px) | 40px | 6px | Headers Medium | 22px |
188
+
189
+ ### TypeScript
190
+
191
+ ```typescript
192
+ import { ComponentPropsWithoutRef, ElementRef } from 'react'
193
+ import * as TogglePrimitive from '@radix-ui/react-toggle'
194
+ import { VariantProps } from 'class-variance-authority'
195
+
196
+ type Themes = 'light' | 'dark' | 'default'
197
+
198
+ type ToggleButtonProps = ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
199
+ VariantProps<typeof toggleButtonStyles> & {
200
+ theme?: Themes
201
+ }
202
+
203
+ export const ToggleButton: React.ForwardRefExoticComponent<
204
+ ToggleButtonProps & React.RefAttributes<ElementRef<typeof TogglePrimitive.Root>>
205
+ >
206
+
207
+ export { toggleButtonStyles }
208
+ export type { ToggleButtonProps }
209
+ ```
210
+
211
+ ## Common Patterns
212
+
213
+ ### Favorite Button with API
214
+
215
+ ```typescript
216
+ function FavoriteButton({ itemId }: { itemId: string }) {
217
+ const [isFavorite, setIsFavorite] = useState(false)
218
+ const [isLoading, setIsLoading] = useState(false)
219
+
220
+ const toggleFavorite = async (pressed: boolean) => {
221
+ setIsLoading(true)
222
+ try {
223
+ await toggleFavoriteAPI(itemId, pressed)
224
+ setIsFavorite(pressed)
225
+ } finally {
226
+ setIsLoading(false)
227
+ }
228
+ }
229
+
230
+ return (
231
+ <ToggleButton
232
+ variant={isFavorite ? 'BlueSecStyle' : 'BorderStyle'}
233
+ buttonType="icon"
234
+ size="M"
235
+ pressed={isFavorite}
236
+ onPressedChange={toggleFavorite}
237
+ disabled={isLoading}
238
+ aria-label={isFavorite ? 'Remove from favorites' : 'Add to favorites'}
239
+ >
240
+ <i className={isFavorite ? 'ri-heart-fill' : 'ri-heart-line'} />
241
+ </ToggleButton>
242
+ )
243
+ }
244
+ ```
245
+
246
+ ### Sidebar Toggle
247
+
248
+ ```typescript
249
+ function SidebarToggle() {
250
+ const [collapsed, setCollapsed] = useState(false)
251
+
252
+ return (
253
+ <ToggleButton
254
+ variant="PrimeContStyle"
255
+ buttonType="icon"
256
+ size="L"
257
+ pressed={collapsed}
258
+ onPressedChange={setCollapsed}
259
+ aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
260
+ >
261
+ <i className={collapsed ? 'ri-menu-unfold-line' : 'ri-menu-fold-line'} />
262
+ </ToggleButton>
263
+ )
264
+ }
265
+ ```
266
+
267
+ ### Toolbar Actions Row
268
+
269
+ ```typescript
270
+ function EditorToolbar() {
271
+ const [styles, setStyles] = useState({
272
+ bold: false,
273
+ italic: false,
274
+ underline: false,
275
+ code: false
276
+ })
277
+
278
+ const toggle = (key: keyof typeof styles) => {
279
+ setStyles(prev => ({ ...prev, [key]: !prev[key] }))
280
+ }
281
+
282
+ const toolbarItems = [
283
+ { key: 'bold', icon: 'ri-bold', label: 'Bold' },
284
+ { key: 'italic', icon: 'ri-italic', label: 'Italic' },
285
+ { key: 'underline', icon: 'ri-underline', label: 'Underline' },
286
+ { key: 'code', icon: 'ri-code-s-slash-line', label: 'Code' }
287
+ ] as const
288
+
289
+ return (
290
+ <div className="flex gap-1 p-2 border rounded">
291
+ {toolbarItems.map(({ key, icon, label }) => (
292
+ <ToggleButton
293
+ key={key}
294
+ buttonType="icon"
295
+ size="S"
296
+ variant="PrimeContStyle"
297
+ pressed={styles[key]}
298
+ onPressedChange={() => toggle(key)}
299
+ aria-label={label}
300
+ >
301
+ <i className={icon} />
302
+ </ToggleButton>
303
+ ))}
304
+ </div>
305
+ )
306
+ }
307
+ ```
308
+
309
+ ### Dark UI Panel
310
+
311
+ ```typescript
312
+ function DarkPanel() {
313
+ const [muted, setMuted] = useState(false)
314
+ const [recording, setRecording] = useState(false)
315
+
316
+ return (
317
+ <div className="bg-gray-900 p-4 rounded flex gap-2">
318
+ <ToggleButton
319
+ variant="SystemStyle"
320
+ buttonType="icon"
321
+ size="L"
322
+ pressed={muted}
323
+ onPressedChange={setMuted}
324
+ aria-label={muted ? 'Unmute' : 'Mute'}
325
+ >
326
+ <i className={muted ? 'ri-mic-off-fill' : 'ri-mic-fill'} />
327
+ </ToggleButton>
328
+
329
+ <ToggleButton
330
+ variant="SystemStyle"
331
+ buttonType="icon"
332
+ size="L"
333
+ pressed={recording}
334
+ onPressedChange={setRecording}
335
+ aria-label={recording ? 'Stop recording' : 'Start recording'}
336
+ >
337
+ <i className={recording ? 'ri-stop-circle-fill' : 'ri-record-circle-fill'} />
338
+ </ToggleButton>
339
+ </div>
340
+ )
341
+ }
342
+ ```
343
+
344
+ ### Theme Switcher
345
+
346
+ ```typescript
347
+ function ThemeSwitcher() {
348
+ const [isDark, setIsDark] = useState(false)
349
+
350
+ return (
351
+ <ToggleButton
352
+ variant="BorderStyle"
353
+ size="M"
354
+ pressed={isDark}
355
+ onPressedChange={setIsDark}
356
+ aria-label={`Switch to ${isDark ? 'light' : 'dark'} theme`}
357
+ >
358
+ <i className={isDark ? 'ri-moon-fill' : 'ri-sun-line'} />
359
+ {isDark ? 'Dark' : 'Light'}
360
+ </ToggleButton>
361
+ )
362
+ }
363
+ ```
364
+
365
+ ## Testing
366
+
367
+ ### Unit Test Example
368
+
369
+ ```typescript
370
+ import { render, screen, fireEvent } from '@testing-library/react'
371
+ import { ToggleButton } from 'torch-glare/lib/components/ToggleButton'
372
+
373
+ describe('ToggleButton', () => {
374
+ it('toggles pressed state on click', () => {
375
+ const handleChange = jest.fn()
376
+ render(
377
+ <ToggleButton onPressedChange={handleChange}>
378
+ Toggle
379
+ </ToggleButton>
380
+ )
381
+
382
+ fireEvent.click(screen.getByRole('button'))
383
+ expect(handleChange).toHaveBeenCalledWith(true)
384
+ })
385
+
386
+ it('renders with pressed state', () => {
387
+ render(<ToggleButton pressed>Active</ToggleButton>)
388
+
389
+ const button = screen.getByRole('button')
390
+ expect(button).toHaveAttribute('data-state', 'on')
391
+ })
392
+
393
+ it('applies icon mode dimensions', () => {
394
+ const { container } = render(
395
+ <ToggleButton buttonType="icon" size="M">
396
+ <i className="ri-star-line" />
397
+ </ToggleButton>
398
+ )
399
+
400
+ const button = container.querySelector('button')
401
+ expect(button).toHaveClass('w-[28px]', 'px-0')
402
+ })
403
+
404
+ it('applies variant styles', () => {
405
+ const { container } = render(
406
+ <ToggleButton variant="BlueSecStyle">Blue</ToggleButton>
407
+ )
408
+
409
+ const button = container.querySelector('button')
410
+ expect(button).toHaveClass('bg-background-presentation-action-secondary')
411
+ })
412
+
413
+ it('handles disabled state', () => {
414
+ const handleChange = jest.fn()
415
+ render(
416
+ <ToggleButton disabled onPressedChange={handleChange}>
417
+ Disabled
418
+ </ToggleButton>
419
+ )
420
+
421
+ const button = screen.getByRole('button')
422
+ fireEvent.click(button)
423
+
424
+ expect(handleChange).not.toHaveBeenCalled()
425
+ expect(button).toHaveClass('cursor-not-allowed')
426
+ })
427
+ })
428
+ ```
429
+
430
+ ### Accessibility Test
431
+
432
+ ```typescript
433
+ import { axe } from '@axe-core/react'
434
+
435
+ test('ToggleButton meets WCAG standards', async () => {
436
+ const { container } = render(
437
+ <ToggleButton aria-label="Toggle feature">
438
+ <i className="ri-star-line" />
439
+ </ToggleButton>
440
+ )
441
+
442
+ const results = await axe(container)
443
+ expect(results).toHaveNoViolations()
444
+ })
445
+ ```
446
+
447
+ ## Accessibility
448
+
449
+ ### Keyboard Support
450
+
451
+ - **Space**: Toggle pressed state when focused
452
+ - **Enter**: Toggle pressed state
453
+ - **Tab**: Move focus to/from the toggle button
454
+
455
+ ### ARIA Attributes
456
+
457
+ Radix UI Toggle automatically provides:
458
+
459
+ ```html
460
+ <!-- Unpressed -->
461
+ <button
462
+ role="button"
463
+ aria-pressed="false"
464
+ data-state="off"
465
+ />
466
+
467
+ <!-- Pressed -->
468
+ <button
469
+ role="button"
470
+ aria-pressed="true"
471
+ data-state="on"
472
+ />
473
+
474
+ <!-- Disabled -->
475
+ <button
476
+ role="button"
477
+ aria-pressed="false"
478
+ data-state="off"
479
+ disabled
480
+ />
481
+ ```
482
+
483
+ ### Screen Reader Support
484
+
485
+ - Announces toggle button role
486
+ - Communicates pressed/unpressed state
487
+ - Reads aria-label or text content
488
+ - Announces state changes on interaction
489
+
490
+ ### Best Practices
491
+
492
+ ```typescript
493
+ // Always provide aria-label for icon-only toggle buttons
494
+ <ToggleButton buttonType="icon" aria-label="Bold text">
495
+ <i className="ri-bold" />
496
+ </ToggleButton>
497
+
498
+ // Or include screen-reader text
499
+ <ToggleButton buttonType="icon">
500
+ <i className="ri-bold" />
501
+ <span className="sr-only">Bold</span>
502
+ </ToggleButton>
503
+ ```
504
+
505
+ ## Styling
506
+
507
+ ### Variant Details
508
+
509
+ - **PrimeStyle**: `bg-background-presentation-action-secondary` with hover/active highlight
510
+ - **BlueSecStyle**: Same base as PrimeStyle but active state uses information blue (`bg-background-presentation-state-information-primary`)
511
+ - **BorderStyle**: `bg-background-presentation-action-borderstyle` with visible border (`border-border-presentation-action-disabled`)
512
+ - **PrimeContStyle**: Transparent background, minimal with container-style hover
513
+ - **SystemStyle**: `bg-black-alpha-20` with white text and `border-[#2C2D2E]`, white alpha hover/active
514
+
515
+ ### Active State Styling
516
+
517
+ All variants use `data-[state=on]` for the active/pressed visual:
518
+
519
+ ```css
520
+ /* PrimeStyle / BorderStyle active */
521
+ data-[state=on]:bg-background-presentation-action-hover
522
+ data-[state=on]:text-content-presentation-action-hover
523
+
524
+ /* BlueSecStyle active */
525
+ data-[state=on]:bg-background-presentation-state-information-primary
526
+ data-[state=on]:text-content-presentation-action-hover
527
+
528
+ /* PrimeContStyle active */
529
+ data-[state=on]:bg-background-presentation-action-contstyle-hover
530
+
531
+ /* SystemStyle active */
532
+ data-[state=on]:bg-white/20
533
+ data-[state=on]:text-white
534
+ ```
535
+
536
+ ### Focus Ring
537
+
538
+ All variants include focus-visible ring styling:
539
+
540
+ ```css
541
+ /* Standard variants */
542
+ focus-visible:ring-2 focus-visible:ring-border-presentation-state-focus
543
+
544
+ /* SystemStyle */
545
+ focus-visible:ring-2 focus-visible:ring-white/50
546
+ ```
547
+
548
+ ### Custom Styles
549
+
550
+ ```typescript
551
+ <ToggleButton
552
+ className="rounded-full shadow-sm"
553
+ variant="BorderStyle"
554
+ size="L"
555
+ >
556
+ Custom Shape
557
+ </ToggleButton>
558
+ ```
559
+
560
+ ## Performance
561
+
562
+ | Metric | Value |
563
+ |--------|-------|
564
+ | Bundle size (gzip) | 2.6kb |
565
+ | First render | <5ms |
566
+ | Re-render | <2ms |
567
+ | Interaction | <1ms |
568
+ | Tree-shakeable | Yes |
569
+
570
+ ### Optimization Tips
571
+
572
+ 1. Use `defaultPressed` for uncontrolled mode when you do not need external state
573
+ 2. Memoize `onPressedChange` handlers with `useCallback`
574
+ 3. For groups of toggle buttons, consider using `ButtonGroup` instead for better semantics
575
+
576
+ ## Migration
577
+
578
+ ### From Toggle Component
579
+
580
+ ```diff
581
+ // Toggle and ToggleButton share a similar API
582
+ // ToggleButton adds buttonType="icon" mode and slightly different variants
583
+ - import { Toggle } from 'torch-glare/lib/components/Toggle'
584
+ + import { ToggleButton } from 'torch-glare/lib/components/ToggleButton'
585
+
586
+ - <Toggle pressed={value} onPressedChange={setValue}>
587
+ + <ToggleButton pressed={value} onPressedChange={setValue}>
588
+ Content
589
+ - </Toggle>
590
+ + </ToggleButton>
591
+ ```
592
+
593
+ ## Troubleshooting
594
+
595
+ ### Icon not sizing correctly
596
+
597
+ **Solution:** Icons are automatically sized via `[&_i]:text-[Xpx]` selectors per size variant. Use Remix Icon `<i>` tags for automatic sizing:
598
+
599
+ ```typescript
600
+ <ToggleButton size="L">
601
+ <i className="ri-heart-line" />
602
+ {/* Icon automatically sized to 20px */}
603
+ </ToggleButton>
604
+ ```
605
+
606
+ ### Toggle not changing state
607
+
608
+ **Solution:** Use controlled or uncontrolled mode properly:
609
+
610
+ ```typescript
611
+ // Controlled - you manage state
612
+ <ToggleButton pressed={value} onPressedChange={setValue} />
613
+
614
+ // Uncontrolled - internal state
615
+ <ToggleButton defaultPressed />
616
+ ```
617
+
618
+ ## Related Components
619
+
620
+ - [ButtonGroup](/docs/components/button-group.md) - Group of toggle buttons with single/multiple selection
621
+ - [Toggle](/docs/components/toggle.md) - Similar toggle with additional variant options
622
+ - [Button](/docs/components/button.md) - Standard action buttons
623
+ - [Switch](/docs/components/switch.md) - For on/off states with slider visual
624
+
625
+ ## Browser Support
626
+
627
+ - Chrome 90+
628
+ - Firefox 88+
629
+ - Safari 14+
630
+ - Edge 90+
631
+ - Mobile browsers
632
+
633
+ ## Changelog
634
+
635
+ ### v1.1.15
636
+ - Initial stable release
637
+ - 5 visual variants (PrimeStyle, BlueSecStyle, BorderStyle, PrimeContStyle, SystemStyle)
638
+ - 4 size variants (S, M, L, XL)
639
+ - Icon-only mode via buttonType="icon" with compound variants
640
+ - Re-exported from ButtonGroup module