@reliability-design/web 1.4.6 → 1.4.7

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 (146) hide show
  1. package/CHANGELOG.md +211 -49
  2. package/dist/components/rel-accordion/README.md +132 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +156 -61
  5. package/dist/components/rel-avatar/README.md +116 -130
  6. package/dist/components/rel-badge/README.md +98 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +160 -130
  9. package/dist/components/rel-calendar/README.md +109 -109
  10. package/dist/components/rel-card/README.md +75 -94
  11. package/dist/components/rel-cardmedia/README.md +100 -127
  12. package/dist/components/rel-carousel/README.md +184 -166
  13. package/dist/components/rel-checkbox/README.md +93 -75
  14. package/dist/components/rel-chip/README.md +132 -121
  15. package/dist/components/rel-container/README.md +107 -99
  16. package/dist/components/rel-date-picker/README.md +200 -289
  17. package/dist/components/rel-divider/README.md +78 -100
  18. package/dist/components/rel-drawer/README.md +187 -200
  19. package/dist/components/rel-kbd/README.md +141 -151
  20. package/dist/components/rel-menu/README.md +178 -151
  21. package/dist/components/rel-menubar/README.md +218 -329
  22. package/dist/components/rel-otp/README.md +170 -440
  23. package/dist/components/rel-pagination/README.md +100 -424
  24. package/dist/components/rel-popover/README.md +203 -568
  25. package/dist/components/rel-progress/README.md +88 -110
  26. package/dist/components/rel-radio/README.md +131 -138
  27. package/dist/components/rel-range-picker/README.md +162 -0
  28. package/dist/components/rel-resizable/README.md +199 -140
  29. package/dist/components/rel-segmented-button/README.md +155 -141
  30. package/dist/components/rel-select/README.md +154 -93
  31. package/dist/components/rel-sheet/README.md +168 -224
  32. package/dist/components/rel-skeleton/README.md +103 -0
  33. package/dist/components/rel-slider/README.md +130 -135
  34. package/dist/components/rel-snackbar/README.md +162 -134
  35. package/dist/components/rel-stepper/README.md +158 -160
  36. package/dist/components/rel-switch/README.md +108 -102
  37. package/dist/components/rel-tab/README.md +171 -163
  38. package/dist/components/rel-textfield/README.md +159 -69
  39. package/dist/components/rel-time-picker/README.md +122 -157
  40. package/dist/components/rel-toast/README.md +157 -148
  41. package/dist/components/rel-tooltip/README.md +108 -111
  42. package/dist/components/rel-upload/README.md +220 -0
  43. package/dist/index.d.mts +1147 -340
  44. package/dist/index.d.ts +1147 -340
  45. package/dist/index.js +3451 -3163
  46. package/dist/index.js.map +1 -1
  47. package/dist/index.mjs +3416 -3118
  48. package/dist/index.mjs.map +1 -1
  49. package/dist/styles/vars.css +877 -866
  50. package/dist/{vars-XNMTSRVN.css → vars-JHTUGNRG.css} +877 -866
  51. package/package.json +3 -2
  52. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  53. package/dist/components/rel-alert/rel-alert.ts +0 -305
  54. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -720
  55. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  56. package/dist/components/rel-badge/rel-badge.ts +0 -175
  57. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  58. package/dist/components/rel-button/rel-button.ts +0 -560
  59. package/dist/components/rel-calendar/index.ts +0 -1
  60. package/dist/components/rel-calendar/rel-calendar.ts +0 -565
  61. package/dist/components/rel-card/rel-card.ts +0 -88
  62. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  63. package/dist/components/rel-carousel/index.ts +0 -1
  64. package/dist/components/rel-carousel/rel-carousel.ts +0 -723
  65. package/dist/components/rel-chart/README.md +0 -286
  66. package/dist/components/rel-chart/index.ts +0 -1
  67. package/dist/components/rel-chart/rel-chart.ts +0 -754
  68. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  69. package/dist/components/rel-chip/rel-chip.ts +0 -483
  70. package/dist/components/rel-container/rel-container.ts +0 -95
  71. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  72. package/dist/components/rel-date-picker/date-format.ts +0 -47
  73. package/dist/components/rel-date-picker/date-parse.test.ts +0 -116
  74. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  75. package/dist/components/rel-date-picker/index.ts +0 -1
  76. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  77. package/dist/components/rel-divider/rel-divider.ts +0 -54
  78. package/dist/components/rel-drawer/index.ts +0 -1
  79. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  80. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  81. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  82. package/dist/components/rel-layout/rel-layout.ts +0 -49
  83. package/dist/components/rel-menu/rel-menu.ts +0 -541
  84. package/dist/components/rel-menubar/index.ts +0 -2
  85. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  86. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  87. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  88. package/dist/components/rel-nav-menu/README.md +0 -289
  89. package/dist/components/rel-nav-menu/index.ts +0 -3
  90. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  91. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  92. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  93. package/dist/components/rel-navbar/README.md +0 -126
  94. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  95. package/dist/components/rel-otp/index.ts +0 -1
  96. package/dist/components/rel-otp/rel-otp.ts +0 -527
  97. package/dist/components/rel-pagination/index.ts +0 -1
  98. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  99. package/dist/components/rel-popover/index.ts +0 -2
  100. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  101. package/dist/components/rel-popover/rel-popover.ts +0 -475
  102. package/dist/components/rel-progress/rel-progress.ts +0 -234
  103. package/dist/components/rel-radio/rel-radio.ts +0 -481
  104. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  105. package/dist/components/rel-resizable/index.ts +0 -3
  106. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  107. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  108. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  109. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  110. package/dist/components/rel-select/rel-select.ts +0 -1416
  111. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  112. package/dist/components/rel-sidebar/README.md +0 -209
  113. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  114. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  115. package/dist/components/rel-slider/rel-slider.ts +0 -673
  116. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  117. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  118. package/dist/components/rel-switch/rel-switch.ts +0 -199
  119. package/dist/components/rel-tab/rel-tab.ts +0 -264
  120. package/dist/components/rel-table/README.md +0 -178
  121. package/dist/components/rel-table/rel-table-body.ts +0 -22
  122. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  123. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  124. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  125. package/dist/components/rel-table/rel-table-head.ts +0 -47
  126. package/dist/components/rel-table/rel-table-header.ts +0 -22
  127. package/dist/components/rel-table/rel-table-row.ts +0 -37
  128. package/dist/components/rel-table/rel-table.ts +0 -62
  129. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  130. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  131. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  132. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  133. package/dist/components/rel-toast/rel-toast.ts +0 -206
  134. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  135. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  136. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  137. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  138. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  139. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  140. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  141. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  142. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  144. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  145. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  146. package/dist/components/rel-upload/rel-upload.ts +0 -968
@@ -1,102 +1,96 @@
1
- #rel-breadcrumbs
2
-
3
- ## Overview
4
- A breadcrumb navigation component that displays a hierarchical path of pages. Features accessible markup, automatic last-item detection, built-in chevron separators, and proper ARIA attributes. Automatically styles the last item as the current page.
5
-
6
- ## Usage
7
- ```html
8
- <!-- Basic breadcrumb -->
9
- <rel-breadcrumbs id="breadcrumb1"></rel-breadcrumbs>
10
- <script>
11
- const breadcrumb = document.getElementById('breadcrumb1');
12
- breadcrumb.items = [
13
- { label: 'Home', url: '/' },
14
- { label: 'Products', url: '/products' },
15
- { label: 'Electronics', url: '/products/electronics' },
16
- { label: 'Laptops' } // Last item has no URL
17
- ];
18
- </script>
19
-
20
- <!-- Simple path -->
21
- <rel-breadcrumbs id="breadcrumb2"></rel-breadcrumbs>
22
- <script>
23
- document.getElementById('breadcrumb2').items = [
24
- { label: 'Dashboard', url: '/dashboard' },
25
- { label: 'Settings' }
26
- ];
27
- </script>
28
-
29
- <!-- Deep nested path -->
30
- <rel-breadcrumbs id="breadcrumb3"></rel-breadcrumbs>
31
- <script>
32
- document.getElementById('breadcrumb3').items = [
33
- { label: 'Docs', url: '/docs' },
34
- { label: 'Components', url: '/docs/components' },
35
- { label: 'Navigation', url: '/docs/components/navigation' },
36
- { label: 'Breadcrumbs' }
37
- ];
38
- </script>
39
- ```
40
-
41
- ## API
42
-
43
- ### Attributes/Properties
44
- | Name | Type | Default | Description |
45
- |------|------|---------|-------------|
46
- | `items` | `BreadcrumbItem[]` | `[]` | Array of breadcrumb items (see BreadcrumbItem interface below) |
47
-
48
- ### BreadcrumbItem Interface
49
- ```typescript
50
- interface BreadcrumbItem {
51
- label: string; // Display text
52
- url?: string; // Optional link URL (omit for current/last page)
53
- }
54
- ```
55
-
56
- ## Events
57
- None.
58
-
59
- ## Slots
60
- Default slot not used.
61
-
62
- ## CSS Parts
63
- None exposed.
64
-
65
- ## Tokens / CSS Variables
66
-
67
- ### Semantic Tokens
68
- - `--rel-fonts-font-family` - Font family
69
- - `--rel-body-md-regular-font-size` - Font size
70
- - `--rel-fonts-weight-body-medium` - Font weight for links
71
- - `--rel-fonts-weight-body-semibold` - Font weight for current page
72
-
73
- ### Color Tokens
74
- - `--rel-text-default` - Base text color
75
- - `--rel-text-label` - Link and current page text color
76
- - `--rel-bg-info` - Link hover color and focus outline
77
-
78
- ## Accessibility
79
- - Uses semantic `<nav>` with `aria-label="Breadcrumb"`
80
- - Uses `<ol>` ordered list for proper structure
81
- - Last item has `aria-current="page"` to indicate current page
82
- - Links have focus visible states with blue outline
83
- - Chevron separator has `aria-hidden="true"` to hide from screen readers
84
-
85
- ### Keyboard Interactions
86
- - `Tab` - Navigate through breadcrumb links
87
- - `Enter` - Follow focused link
88
-
89
- ### Focus Behavior
90
- - Links show 2px blue outline with 2px offset when focused
91
- - Border radius applied to focus outline for visual consistency
92
-
93
- ## Notes / Edge Cases
94
- - The last item in `items` array is automatically treated as the current page
95
- - Last item renders as a `<span class="current">` instead of `<a>`, even if it has a `url`
96
- - Chevron separators (SVG chevron-right arrows) appear between all items except after the last one
97
- - Chevrons are 16px × 16px with 10px horizontal margins
98
- - Chevron color inherits `currentColor` from parent
99
- - Links have `text-decoration: none` by default, `underline` on hover
100
- - The current page label is bold and not clickable (`cursor: default`)
101
- - The component is `display: block` and takes full width
102
- - The ordered list uses `flex-wrap: wrap` to handle overflow gracefully
1
+ # rel-breadcrumbs
2
+
3
+ Breadcrumb trail (element `<rel-breadcrumbs>`, folder `rel-breadcrumb`): a `<nav aria-label="Breadcrumb">` ordered list built from an `items` array, with chevron separators and the last entry rendered as the non-link current page. Use it to show where the current page sits in a hierarchy and to jump back up it; do not use it as primary navigation or for a single-level site.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Basic trail: every item but the last is a link -->
9
+ <rel-breadcrumbs id="trail"></rel-breadcrumbs>
10
+ <script>
11
+ document.getElementById('trail').items = [
12
+ { label: 'Home', url: '/' },
13
+ { label: 'Products', url: '/products' },
14
+ { label: 'Electronics', url: '/products/electronics' },
15
+ { label: 'Laptops' } // current page — no url needed
16
+ ];
17
+ </script>
18
+
19
+ <!-- Two levels -->
20
+ <rel-breadcrumbs id="short"></rel-breadcrumbs>
21
+ <script>
22
+ document.getElementById('short').items = [
23
+ { label: 'Dashboard', url: '/dashboard' },
24
+ { label: 'Settings' }
25
+ ];
26
+ </script>
27
+
28
+ <!-- Restyle the current-page text through its part -->
29
+ <style>
30
+ .muted::part(label) {
31
+ color: gray;
32
+ }
33
+ </style>
34
+ <rel-breadcrumbs class="muted" id="muted"></rel-breadcrumbs>
35
+ <script>
36
+ document.getElementById('muted').items = [
37
+ { label: 'Docs', url: '/docs' },
38
+ { label: 'Components', url: '/docs/components' },
39
+ { label: 'Breadcrumbs' }
40
+ ];
41
+ </script>
42
+ ```
43
+
44
+ The `BreadcrumbItem` shape is `{ label: string; url?: string }`; the type is exported from the package.
45
+
46
+ <!-- readme-gen:start -->
47
+
48
+ <!-- Generated from rel-breadcrumb.ts — do not edit; run readme-generate.mjs -->
49
+
50
+ ## API
51
+
52
+ ### Attributes / Properties
53
+
54
+ | Property | Attribute | Type | Default | Description |
55
+ | --- | --- | --- | --- | --- |
56
+ | `items` | `items` | `BreadcrumbItem[]` | `[]` | Ordered trail, root first: `{ label: string; url?: string }[]`. Items with a `url` render as links except the last one, which is always the current page (and never a link). Set as a property — arrays do not survive attribute serialisation. |
57
+
58
+ ## Events
59
+
60
+ | Event | Detail | Bubbles / composed | Description |
61
+ | --- | --- | --- | --- |
62
+ | — | — | — | This element emits no custom events. |
63
+
64
+ ## Slots
65
+
66
+ | Slot | Description |
67
+ | --- | --- |
68
+ | — | This element has no slots. |
69
+
70
+ ## CSS Parts
71
+
72
+ | Part | Description |
73
+ | --- | --- |
74
+ | `base` | The `<nav>` landmark wrapping the ordered list. |
75
+ | `label` | The non-link current-page text (`aria-current="page"`), also used for any item without a `url`. |
76
+
77
+ <!-- readme-gen:end -->
78
+
79
+ ## Accessibility
80
+
81
+ - Semantic `<nav aria-label="Breadcrumb">` landmark (the `base` part) containing an `<ol>`, so the trail is announced as an ordered list within a named navigation region.
82
+ - The last item is a `<span aria-current="page">` (the `label` part), never a link, so the current page is identified without being actionable.
83
+ - Chevron separators are inline SVGs with `aria-hidden="true"`.
84
+ - Links show a 2px focus outline with 2px offset on `:focus-visible`.
85
+
86
+ | Key | Action |
87
+ | --- | --- |
88
+ | `Tab` / `Shift+Tab` | Move between the breadcrumb links |
89
+ | `Enter` | Follow the focused link (native anchor behaviour) |
90
+
91
+ ## Notes / Edge Cases
92
+
93
+ - **The last item is always the current page**, even if it has a `url` — it renders as text, not a link. Any earlier item *without* a `url` also renders as text (and reuses the `label` part and `aria-current="page"`, so give every ancestor a `url`).
94
+ - `items` must be assigned as a property (it is an array); setting an `items` attribute in HTML does not work.
95
+ - Separators are 16px chevrons with 10px horizontal margins inheriting `currentColor`; the list wraps onto new lines when it runs out of width.
96
+ - Links are plain anchors: navigation happens natively and no custom event is emitted. Intercept `click` on the host if you route client-side.
@@ -1,130 +1,160 @@
1
- # rel-button
2
-
3
- ## Overview
4
- A versatile button component with six variants (default, primary, secondary, text, link, icon), three tone options, three sizes, and configurable border radius. Features hover, active, and focus states with smooth transitions. Slots support custom content including text, icons, or combinations.
5
-
6
- ## Usage
7
- ```html
8
- <!-- Basic variants -->
9
- <rel-button variant="default">Default Button</rel-button>
10
- <rel-button variant="primary">Primary Button</rel-button>
11
- <rel-button variant="secondary">Secondary Button</rel-button>
12
- <rel-button variant="text">Text Button</rel-button>
13
- <rel-button variant="link">Link Style</rel-button>
14
-
15
- <!-- Icon button -->
16
- <rel-button variant="icon">⚙️</rel-button>
17
-
18
- <!-- Tones (affect color scheme) -->
19
- <rel-button variant="primary" tone="default">Default Tone</rel-button>
20
- <rel-button variant="primary" tone="critical">Critical Action</rel-button>
21
- <rel-button variant="primary" tone="success">Success Action</rel-button>
22
-
23
- <!-- Sizes -->
24
- <rel-button size="small">Small</rel-button>
25
- <rel-button size="medium">Medium</rel-button>
26
- <rel-button size="large">Large</rel-button>
27
-
28
- <!-- Border radius options -->
29
- <rel-button border="corner-radius">Rounded</rel-button>
30
- <rel-button border="small-corner-radius">Small Rounded</rel-button>
31
- <rel-button border="no-corner-radius">Sharp</rel-button>
32
-
33
- <!-- Disabled -->
34
- <rel-button disabled>Disabled Button</rel-button>
35
-
36
- <!-- With icon and text (using slot) -->
37
- <rel-button variant="primary">
38
- <svg width="16" height="16" viewBox="0 0 16 16"><path d="M8 0l3 6h6l-5 4 2 6-6-4-6 4 2-6-5-4h6z"/></svg>
39
- Save
40
- </rel-button>
41
-
42
- <!-- Listen for click -->
43
- <rel-button id="actionBtn" variant="primary">Click Me</rel-button>
44
- <script>
45
- document.getElementById('actionBtn').addEventListener('click', () => {
46
- console.log('Button clicked');
47
- });
48
- </script>
49
- ```
50
-
51
- ## API
52
-
53
- ### Attributes/Properties
54
- | Name | Type | Default | Description |
55
- |------|------|---------|-------------|
56
- | `variant` | `"default" \| "primary" \| "secondary" \| "text" \| "link" \| "icon"` | `"default"` | Visual style variant |
57
- | `tone` | `"default" \| "critical" \| "success"` | `"default"` | Color tone (affects default/primary variants) |
58
- | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Button size |
59
- | `border` | `"corner-radius" \| "small-corner-radius" \| "no-corner-radius"` | `"corner-radius"` | Border radius style |
60
- | `disabled` | `boolean` (reflected) | `false` | Disables interaction and applies disabled styling |
61
-
62
- ## Events
63
- | Event | Detail | Description |
64
- |-------|--------|-------------|
65
- | `click` | `MouseEvent` | Re-dispatched from the internal button (for framework compatibility) |
66
-
67
- ## Slots
68
- | Slot | Description |
69
- |------|-------------|
70
- | (default) | Button content (text, icons, or combination) |
71
-
72
- ## CSS Parts
73
- None exposed.
74
-
75
- ## Tokens / CSS Variables
76
-
77
- ### Semantic Tokens
78
- - `--rel-fonts-font-family` - Font family
79
- - `--rel-fonts-weight-body-semibold` - Font weight
80
- - `--rel-body-sm-regular-font-size`, `--rel-body-md-regular-font-size`, `--rel-body-xl-regular-font-size` - Font sizes for sizes
81
-
82
- ### Spacing Tokens
83
- - `--rel-spacing-2xs` - Internal gap between elements
84
- - `--rel-spacing-md`, `--rel-spacing-lg`, `--rel-spacing-xl` - Horizontal padding by size
85
-
86
- ### Color Tokens (by variant/tone)
87
- - **default + default tone**: `--rel-text-default` (bg), `--rel-bg-surface` (text)
88
- - **default + critical tone**: `--rel-bg-danger` (bg), `--rel-bg-surface` (text)
89
- - **default + success tone**: `--rel-text-success` (bg), `--rel-bg-surface` (text)
90
- - **primary + default tone**: `--rel-bg-brand` (bg), `--rel-text-default` (text)
91
- - **primary + critical tone**: `--rel-bg-danger` (bg), `--rel-bg-surface` (text)
92
- - **primary + success tone**: `--rel-text-success` (bg), `--rel-bg-surface` (text)
93
- - **secondary**: `--rel-bg-surface` (bg), `--rel-text-default` (text + border)
94
- - **text**: transparent (bg), `--rel-text-default` (text)
95
- - **link**: transparent (bg), `--rel-bg-info` (text), underlined
96
- - **icon**: `--rel-bg-surface-elevated` (bg), `--rel-text-default` (text), circular (40px × 40px)
97
- - **disabled**: `--rel-border-default` (bg), `--rel-text-disabled` (text)
98
-
99
- ### Border Tokens
100
- - `--rel-border-radius-full-rounded` - Large corner radius
101
- - `--rel-border-radius-sm` - Small corner radius
102
- - `--rel-border-radius-square` - No corner radius
103
-
104
- ## Accessibility
105
- - Uses native `<button>` element for proper semantics
106
- - `aria-disabled` attribute set on disabled buttons
107
- - Focus visible state with blue outline
108
- - Keyboard accessible (Space/Enter activation)
109
-
110
- ### Keyboard Interactions
111
- - `Tab` - Focus the button
112
- - `Space/Enter` - Activate the button
113
-
114
- ### Focus Behavior
115
- - Blue 2px outline with 2px offset on focus-visible
116
- - Focus outline works across all variants
117
-
118
- ## Notes / Edge Cases
119
- - **Icon variant** is always circular (40px × 40px), ignores size property, and has no padding
120
- - **Link variant** has `text-decoration: underline`
121
- - **Secondary variant** includes a 1px border matching the text color
122
- - Hover effect applies `filter: brightness(0.92)` to darken
123
- - Active (pressed) effect applies `transform: scale(0.97)` for tactile feedback
124
- - Disabled buttons have `pointer-events: none` and use `!important` to override theming
125
- - The component re-dispatches click events to ensure framework compatibility (e.g., Angular)
126
- - Clicking a disabled button prevents default and stops propagation
127
- - Size variants affect height (32px/40px/48px) and horizontal padding
128
- - The button has `display: inline-flex` with `align-items: center` and `justify-content: center`
129
- - Internal gap of `var(--rel-spacing-2xs)` allows icons + text combinations
130
- - Transitions are `0.15s ease` for all visual changes
1
+ # rel-button
2
+
3
+ Action button implementing the Figma "Button" component: a native `<button>` with the Figma **Style** (`variant`), **Tone** (`tone`) and **Size** axes, an independent **Icon Only** mode, a **Loading** state and an optional corner badge. Use it for every clickable action (submit, confirm, open, delete). Do not use it for navigation to another page — use a link instead.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Styles (Figma "Style") -->
9
+ <rel-button variant="primary">Primary</rel-button>
10
+ <rel-button variant="secondary">Secondary</rel-button>
11
+ <rel-button variant="ghost">Ghost</rel-button>
12
+ <rel-button variant="link">Link style</rel-button>
13
+ <rel-button variant="default">Neutral fill</rel-button>
14
+ <div style="background: #1f2937; padding: 8px;">
15
+ <rel-button variant="static">Static (on dark surfaces)</rel-button>
16
+ </div>
17
+
18
+ <!-- Tones (Figma "Tone") -->
19
+ <rel-button variant="primary" tone="brand">Save</rel-button>
20
+ <rel-button variant="primary" tone="neutral">Cancel</rel-button>
21
+ <rel-button variant="primary" tone="destructive">Delete</rel-button>
22
+ <rel-button variant="secondary" tone="destructive">Remove</rel-button>
23
+ <rel-button variant="ghost" tone="destructive">Discard</rel-button>
24
+
25
+ <!-- Sizes: 32 / 40 / 48px -->
26
+ <rel-button size="small">Small</rel-button>
27
+ <rel-button size="medium">Medium</rel-button>
28
+ <rel-button size="large">Large</rel-button>
29
+
30
+ <!-- Corner radius -->
31
+ <rel-button border="corner-radius">Pill</rel-button>
32
+ <rel-button border="small-corner-radius">Small radius</rel-button>
33
+ <rel-button border="no-corner-radius">Square</rel-button>
34
+
35
+ <!-- Icon + label, and icon-only (needs an accessible name) -->
36
+ <rel-button variant="primary">
37
+ <rel-icon name="plus"></rel-icon>
38
+ Add item
39
+ </rel-button>
40
+ <rel-button variant="secondary" icon-only aria-label="Settings">
41
+ <rel-icon name="settings"></rel-icon>
42
+ </rel-button>
43
+ <rel-button variant="ghost" icon-only size="small" aria-label="Close">
44
+ <rel-icon name="x"></rel-icon>
45
+ </rel-button>
46
+
47
+ <!-- States -->
48
+ <rel-button variant="primary" loading>Saving</rel-button>
49
+ <rel-button variant="primary" disabled>Unavailable</rel-button>
50
+
51
+ <!-- Corner badges -->
52
+ <rel-button variant="secondary" badge="3">Inbox</rel-button>
53
+ <rel-button variant="ghost" icon-only badge-dot aria-label="Notifications">
54
+ <rel-icon name="bell"></rel-icon>
55
+ </rel-button>
56
+
57
+ <!-- Listen for clicks (native click bubbles through the shadow root) -->
58
+ <rel-button id="save" variant="primary">Save</rel-button>
59
+ <script>
60
+ document.getElementById('save').addEventListener('click', () => {
61
+ console.log('saved');
62
+ });
63
+ </script>
64
+
65
+ <!-- Per-instance minimum width -->
66
+ <rel-button variant="primary" style="--rel-button-min-width: 160px;">Wide</rel-button>
67
+ ```
68
+
69
+ ### Deprecated aliases
70
+
71
+ ```html
72
+ <!-- Legacy Style spellings — still rendered identically, prefer the canonical names -->
73
+ <rel-button variant="outline">Outline</rel-button> <!-- → variant="secondary" -->
74
+ <rel-button variant="text">Text</rel-button> <!-- → variant="ghost" -->
75
+ <rel-button variant="icon" aria-label="Settings"> <!-- → icon-only + a variant -->
76
+ <rel-icon name="settings"></rel-icon>
77
+ </rel-button>
78
+
79
+ <!-- Legacy Tone spellings — each logs once per page:
80
+ [rel-button] "tone="critical"" is deprecated and will be removed in 3.0 — use "tone="destructive"" instead. -->
81
+ <rel-button variant="primary" tone="critical">Delete</rel-button> <!-- → tone="destructive" -->
82
+ <rel-button variant="primary" tone="danger">Delete</rel-button> <!-- → tone="destructive" -->
83
+ ```
84
+
85
+ <!-- readme-gen:start -->
86
+
87
+ <!-- Generated from rel-button.ts — do not edit; run readme-generate.mjs -->
88
+
89
+ ## API
90
+
91
+ ### Attributes / Properties
92
+
93
+ | Property | Attribute | Type | Default | Description |
94
+ | --- | --- | --- | --- | --- |
95
+ | `variant` | `variant` | `"default" \| "primary" \| "secondary" \| "text" \| "link" \| "icon" \| "static" \| "outline" \| "ghost"` | `"default"` | Style axis (Figma "Style"). Canonical: `default` (legacy neutral fill), `primary`, `secondary` (outlined), `ghost` (text-only), `link` (underlined inline text), `static` (transparent, static-light label for dark/colored surfaces). Deprecated aliases still accepted: `outline` = secondary, `text` = ghost, and `icon` (pre-2.0 40px circular icon button — use `icon-only` with a style instead). |
96
+ | `tone` | `tone` | `"default" \| "primary" \| "secondary" \| "critical" \| "success" \| "neutral" \| "brand" \| "danger" \| "destructive"` | `"default"` | Tone axis (Figma "Tone"). Canonical: `neutral` (= `default`), `brand` (= `primary`), `destructive`. Deprecated aliases `critical` and `danger` map to destructive and log a one-time console notice. `secondary` and `success` are legacy extras with no Figma counterpart (secondary only affects the legacy `icon` variant). |
97
+ | `iconOnly` | `icon-only` | `boolean` | `false` | Figma "Type=Icon Only": renders a square button (32/40/48px per `size`) of the current style and tone with no padding or min-width. Composes with every `variant`; slot a single `rel-icon` and set `aria-label`. Reflected. |
98
+ | `loading` | `loading` | `boolean` | `false` | Figma "State=Loading": replaces the label with a spinner (`indicator` part), sets `aria-busy`, and blocks pointer and programmatic clicks. The button keeps its width. Reflected. |
99
+ | `size` | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Figma "Size": `small` = 32px, `medium` = 40px, `large` = 48px height, with matching padding, typography and minimum width. |
100
+ | `border` | `border` | `"corner-radius" \| "small-corner-radius" \| "no-corner-radius"` | `"corner-radius"` | Corner treatment: `corner-radius` = fully rounded pill, `small-corner-radius` = small radius token, `no-corner-radius` = square corners. |
101
+ | `disabled` | `disabled` | `boolean` | `false` | Figma "State=Disabled": dims the button to 50% opacity, flattens filled styles to the disabled fill, shows a `not-allowed` cursor and swallows every click (including programmatic `.click()`). Reflected. |
102
+ | `ariaLabel` | `aria-label` | `string \| null` | `null` | Accessible name forwarded to the inner native `<button>`. Required for `icon-only` buttons, whose slotted icon has no visible text. |
103
+ | `badge` | `badge` | `string` | `""` | Text for a small `rel-badge` anchored to the top-right corner (e.g. "3", "999+"). Empty string renders no badge. Ignored when `badge-dot` is set. |
104
+ | `badgeDot` | `badge-dot` | `boolean` | `false` | Renders a small dot badge in the top-right corner instead of a numbered badge; takes precedence over `badge`. The dot is inset 2px from the corner so it lands on a circular icon button's edge. |
105
+
106
+ ## Events
107
+
108
+ | Event | Detail | Bubbles / composed | Description |
109
+ | --- | --- | --- | --- |
110
+ | — | — | — | This element emits no custom events. |
111
+
112
+ ## Slots
113
+
114
+ | Slot | Description |
115
+ | --- | --- |
116
+ | (default) | Button content: label text, a `rel-icon`, or icon + text (kept on one line with the size's gap). |
117
+
118
+ ## CSS Parts
119
+
120
+ | Part | Description |
121
+ | --- | --- |
122
+ | `base` | The inner native `<button>` element (padding, min-width, fill, border, focus ring). |
123
+ | `indicator` | The loading spinner, rendered only while `loading` is set. |
124
+
125
+ ## Tokens / CSS Variables
126
+
127
+ ### Component hooks
128
+
129
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
130
+
131
+ | Custom property | Default | Description |
132
+ | --- | --- | --- |
133
+ | `--rel-button-min-width` | `80px` | Overrides the per-size minimum width (Figma small/medium/large = 80/100/120px, ghost small = 56px). Ignored by `icon-only` and `link`. |
134
+
135
+ <!-- readme-gen:end -->
136
+
137
+ ## Accessibility
138
+
139
+ - Renders a native `<button>` (the `base` part), so it is focusable, announced as a button and activated with the keyboard without extra work.
140
+ - `aria-disabled` mirrors `disabled`; `aria-busy` mirrors `loading`. The spinner is `aria-hidden`, and the label stays in the DOM (visually hidden) while loading, so the accessible name does not change.
141
+ - `aria-label` is forwarded to the inner button. Always set it on `icon-only` buttons and on the legacy `icon` variant — a slotted icon has no text.
142
+ - Disabled and loading buttons swallow clicks in the capture phase on the host, so `el.click()` and delegated listeners never fire.
143
+
144
+ | Key | Action |
145
+ | --- | --- |
146
+ | `Tab` / `Shift+Tab` | Move focus to / from the button |
147
+ | `Enter` / `Space` | Activate (native button behaviour) |
148
+
149
+ Focus: `:focus-visible` shows the shared 2px focus outline plus inner/outer halo on every style except `link`, which shows a 2px focus-coloured underline bar and the hover label colour instead (still a visible indicator per WCAG 2.4.7). Pressing scales the button to 97%; the spinner slows to 2s under `prefers-reduced-motion: reduce`.
150
+
151
+ ## Notes / Edge Cases
152
+
153
+ - **Events.** The element dispatches no custom events. The native `click` is `composed`, so a listener on `<rel-button>` (or an ancestor) receives exactly one event per activation — do not re-dispatch it.
154
+ - **Minimum widths** come from the Figma master: small/medium/large = 80/100/120px, ghost small = 56px. `link` has no minimum, `icon-only` is a fixed square (32/40/48px) and the legacy `icon` variant is always a 40px circle regardless of `size`. Override per instance with `--rel-button-min-width`.
155
+ - **Legacy `icon` variant vs `icon-only`.** `variant="icon"` keeps its pre-2.0 look (40px circle, tone-driven fill, `tone="secondary"` gives it an outline) and ignores `size` and `border`. `icon-only` is an axis that composes with any style and size — prefer it.
156
+ - **`tone` on `secondary` / `ghost` / `link`** changes the label, border or text colour only; the fill stays on the surface. The destructive outline border is deliberately subtle at rest and only goes solid on hover/pressed, matching Figma.
157
+ - **`static`** is a neutral-only style meant for coloured or dark backgrounds; other tones have no static treatment.
158
+ - **`success`** is a legacy tone without a Figma counterpart; it renders a green fill/outline/ghost tint but is not part of the current spec.
159
+ - **Badges** render a small `rel-badge` positioned outside the button's box (numbered) or 2px inside the corner (dot); give the button room in tight layouts. `badge-dot` wins when both are set.
160
+ - **Disabled styling**: only filled styles (`default`, `primary`, `icon`) flatten to the neutral disabled fill; `secondary`, `ghost`, `link` and `static` keep their shape at 50% opacity so they still read as their own style.