@reliability-design/web 1.0.3 → 1.0.6

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 (114) hide show
  1. package/dist/components/rel-accordion/README.md +132 -0
  2. package/dist/components/rel-accordion/rel-accordion.ts +43 -16
  3. package/dist/components/rel-alert/README.md +141 -0
  4. package/dist/components/rel-alert/rel-alert.ts +18 -7
  5. package/dist/components/rel-avatar/README.md +119 -0
  6. package/dist/components/rel-badge/README.md +86 -0
  7. package/dist/components/rel-badge/rel-badge.ts +6 -6
  8. package/dist/components/rel-breadcrumb/README.md +102 -0
  9. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +12 -6
  10. package/dist/components/rel-button/README.md +130 -0
  11. package/dist/components/rel-calendar/README.md +109 -0
  12. package/dist/components/rel-calendar/index.ts +1 -0
  13. package/dist/components/rel-calendar/rel-calendar.ts +467 -0
  14. package/dist/components/rel-card/README.md +94 -0
  15. package/dist/components/rel-card/rel-card.ts +12 -3
  16. package/dist/components/rel-cardmedia/README.md +127 -0
  17. package/dist/components/rel-cardmedia/rel-cardmedia.ts +14 -4
  18. package/dist/components/rel-carousel/README.md +166 -0
  19. package/dist/components/rel-carousel/index.ts +1 -0
  20. package/dist/components/rel-carousel/rel-carousel.ts +469 -0
  21. package/dist/components/rel-chart/README.md +286 -0
  22. package/dist/components/rel-chart/index.ts +1 -0
  23. package/dist/components/rel-chart/rel-chart.ts +736 -0
  24. package/dist/components/rel-checkbox/README.md +77 -0
  25. package/dist/components/rel-checkbox/rel-checkbox.ts +18 -10
  26. package/dist/components/rel-chip/README.md +114 -0
  27. package/dist/components/rel-chip/rel-chip.ts +20 -4
  28. package/dist/components/rel-container/README.md +99 -0
  29. package/dist/components/rel-date-picker/README.md +253 -0
  30. package/dist/components/rel-date-picker/index.ts +1 -0
  31. package/dist/components/rel-date-picker/rel-date-picker.ts +916 -0
  32. package/dist/components/rel-divider/README.md +100 -0
  33. package/dist/components/rel-drawer/README.md +200 -0
  34. package/dist/components/rel-drawer/index.ts +1 -0
  35. package/dist/components/rel-drawer/rel-drawer.ts +621 -0
  36. package/dist/components/rel-kbd/README.md +151 -0
  37. package/dist/components/rel-kbd/rel-kbd.ts +118 -0
  38. package/dist/components/rel-layout/README.md +88 -0
  39. package/dist/components/rel-menu/README.md +151 -0
  40. package/dist/components/rel-menu/rel-menu.ts +18 -10
  41. package/dist/components/rel-menubar/README.md +329 -0
  42. package/dist/components/rel-menubar/index.ts +2 -0
  43. package/dist/components/rel-menubar/rel-menubar-menu.ts +16 -0
  44. package/dist/components/rel-menubar/rel-menubar.ts +576 -0
  45. package/dist/components/rel-nav-menu/README.md +289 -0
  46. package/dist/components/rel-nav-menu/index.ts +3 -0
  47. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +143 -0
  48. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +53 -0
  49. package/dist/components/rel-nav-menu/rel-nav-menu.ts +331 -0
  50. package/dist/components/rel-navbar/README.md +126 -0
  51. package/dist/components/rel-navbar/rel-navbar.ts +91 -0
  52. package/dist/components/rel-otp/README.md +440 -0
  53. package/dist/components/rel-otp/index.ts +1 -0
  54. package/dist/components/rel-otp/rel-otp.ts +504 -0
  55. package/dist/components/rel-pagination/README.md +410 -0
  56. package/dist/components/rel-pagination/index.ts +1 -0
  57. package/dist/components/rel-pagination/rel-pagination.ts +376 -0
  58. package/dist/components/rel-popover/README.md +568 -0
  59. package/dist/components/rel-popover/index.ts +2 -0
  60. package/dist/components/rel-popover/rel-popover-content.ts +55 -0
  61. package/dist/components/rel-popover/rel-popover.ts +327 -0
  62. package/dist/components/rel-progress/README.md +110 -0
  63. package/dist/components/rel-progress/rel-progress.ts +32 -5
  64. package/dist/components/rel-quote-page/README.md +166 -0
  65. package/dist/components/rel-quote-page/rel-quote-page.ts +816 -0
  66. package/dist/components/rel-radio/README.md +120 -0
  67. package/dist/components/rel-radio/rel-radio.ts +13 -5
  68. package/dist/components/rel-resizable/README.md +140 -0
  69. package/dist/components/rel-resizable/index.ts +3 -0
  70. package/dist/components/rel-resizable/rel-resizable-group.ts +374 -0
  71. package/dist/components/rel-resizable/rel-resizable-handle.ts +149 -0
  72. package/dist/components/rel-resizable/rel-resizable-panel.ts +47 -0
  73. package/dist/components/rel-segmented-button/README.md +141 -0
  74. package/dist/components/rel-segmented-button/rel-segmented-button.ts +18 -13
  75. package/dist/components/rel-select/README.md +107 -0
  76. package/dist/components/rel-select/rel-select.ts +14 -14
  77. package/dist/components/rel-sheet/README.md +224 -0
  78. package/dist/components/rel-sheet/rel-sheet.ts +683 -0
  79. package/dist/components/rel-sidebar/README.md +209 -0
  80. package/dist/components/rel-sidebar/rel-sidebar.ts +1158 -0
  81. package/dist/components/rel-slider/README.md +135 -0
  82. package/dist/components/rel-slider/rel-slider.ts +19 -7
  83. package/dist/components/rel-snackbar/README.md +134 -0
  84. package/dist/components/rel-snackbar/rel-snackbar.ts +67 -2
  85. package/dist/components/rel-stepper/README.md +160 -0
  86. package/dist/components/rel-stepper/rel-stepper.ts +6 -6
  87. package/dist/components/rel-switch/README.md +102 -0
  88. package/dist/components/rel-switch/rel-switch.ts +15 -6
  89. package/dist/components/rel-tab/README.md +163 -0
  90. package/dist/components/rel-tab/rel-tab.ts +36 -14
  91. package/dist/components/rel-table/README.md +178 -0
  92. package/dist/components/rel-table/rel-table-body.ts +16 -0
  93. package/dist/components/rel-table/rel-table-caption.ts +22 -0
  94. package/dist/components/rel-table/rel-table-cell.ts +49 -0
  95. package/dist/components/rel-table/rel-table-footer.ts +18 -0
  96. package/dist/components/rel-table/rel-table-head.ts +33 -0
  97. package/dist/components/rel-table/rel-table-header.ts +16 -0
  98. package/dist/components/rel-table/rel-table-row.ts +32 -0
  99. package/dist/components/rel-table/rel-table.ts +47 -0
  100. package/dist/components/rel-textfield/README.md +90 -0
  101. package/dist/components/rel-textfield/rel-textfield.ts +35 -19
  102. package/dist/components/rel-toast/README.md +148 -0
  103. package/dist/components/rel-toast/rel-toast.ts +32 -14
  104. package/dist/components/rel-tooltip/README.md +103 -0
  105. package/dist/components/rel-tooltip/rel-tooltip.ts +9 -9
  106. package/dist/index.d.mts +836 -1
  107. package/dist/index.d.ts +836 -1
  108. package/dist/index.js +10658 -1493
  109. package/dist/index.js.map +1 -1
  110. package/dist/index.mjs +10616 -1499
  111. package/dist/index.mjs.map +1 -1
  112. package/dist/styles/vars.css +293 -183
  113. package/dist/{vars-6ZIUPIU4.css → vars-ITL2K3KO.css} +293 -183
  114. package/package.json +1 -1
@@ -0,0 +1,102 @@
1
+ # rel-switch
2
+
3
+ ## Overview
4
+ A toggle switch component for binary on/off states. Features smooth animations, focus halo effects, pressed states, and respects user motion preferences. Built with custom visual styling while maintaining native checkbox accessibility.
5
+
6
+ ## Usage
7
+ ```html
8
+ <!-- Basic switch -->
9
+ <rel-switch></rel-switch>
10
+
11
+ <!-- Pre-checked switch -->
12
+ <rel-switch checked></rel-switch>
13
+
14
+ <!-- Disabled switch -->
15
+ <rel-switch disabled></rel-switch>
16
+ <rel-switch checked disabled></rel-switch>
17
+
18
+ <!-- With event listener -->
19
+ <rel-switch id="notifications"></rel-switch>
20
+ <script>
21
+ const toggle = document.getElementById('notifications');
22
+ toggle.addEventListener('changed', (e) => {
23
+ console.log('Switch state:', e.detail); // boolean: true/false
24
+ });
25
+ </script>
26
+
27
+ <!-- Programmatically control -->
28
+ <rel-switch id="darkMode"></rel-switch>
29
+ <script>
30
+ const darkModeSwitch = document.getElementById('darkMode');
31
+ darkModeSwitch.checked = true;
32
+ darkModeSwitch.disabled = false;
33
+ </script>
34
+ ```
35
+
36
+ ## API
37
+
38
+ ### Attributes/Properties
39
+ | Name | Type | Default | Description |
40
+ |------|------|---------|-------------|
41
+ | `checked` | `boolean` | `false` | Whether the switch is in the ON position |
42
+ | `disabled` | `boolean` | `false` | Disables the switch and reduces opacity |
43
+
44
+ ## Events
45
+ | Event | Detail | Description |
46
+ |-------|--------|-------------|
47
+ | `changed` | `boolean` (the new checked state) | Fired when the switch is toggled by user interaction |
48
+
49
+ ## Slots
50
+ Default slot not used.
51
+
52
+ ## CSS Parts
53
+ None exposed.
54
+
55
+ ## Tokens / CSS Variables
56
+
57
+ ### Component-Level Custom Properties
58
+ The component defines these CSS custom properties on `:host` which can be overridden:
59
+
60
+ - `--switch-track` - Track color when unchecked (default: `--rel-text-placeholder`)
61
+ - `--switch-knob-on` - Knob color when checked (default: `--rel-colors-black`)
62
+ - `--switch-knob-off` - Knob color when unchecked (default: `--rel-colors-white`)
63
+ - `--switch-halo` - Focus halo color (default: `--rel-border-default`)
64
+ - `--switch-disabled` - Color for disabled state (default: `--rel-text-disabled`)
65
+
66
+ ### Design Token References
67
+ - `--rel-text-placeholder` - Default track color
68
+ - `--rel-text-dark-placeholder` - Hover track color
69
+ - `--rel-colors-black` - ON knob color
70
+ - `--rel-colors-white` - OFF knob color
71
+ - `--rel-border-default` - Focus halo
72
+ - `--rel-text-disabled` - Disabled state color
73
+ - `--rel-surface-surface` - Used in disabled styling
74
+
75
+ ## Accessibility
76
+ - Uses native checkbox input with `role="switch"` and `aria-checked`
77
+ - Visually hidden checkbox maintains keyboard and screen reader support
78
+ - Focus visible state shows prominent halo around knob
79
+ - Disabled state prevents interaction and reduces opacity to 0.5
80
+ - Smooth transitions respect `prefers-reduced-motion` media query
81
+
82
+ ### Keyboard Interactions
83
+ - `Space` - Toggle switch on/off
84
+ - `Tab` - Move focus to/from switch
85
+
86
+ ### Focus Behavior
87
+ - Focus ring appears as a 6px halo around the knob using `--switch-halo` color
88
+ - Halo uses box-shadow for smooth visual feedback
89
+
90
+ ### Motion Support
91
+ - Animations disabled when `prefers-reduced-motion: reduce` is set
92
+ - Transitions apply to track color, knob position, knob color, and box-shadow
93
+
94
+ ## Notes / Edge Cases
95
+ - The switch is 42px wide × 22px tall with a 12px tall track and 18px diameter knob
96
+ - Visual knob animates 22px horizontally when toggling from OFF to ON
97
+ - Hover effect only applies when not disabled (track darkens slightly)
98
+ - Pressed state applies a `scale(0.9)` transform to the knob for tactile feedback
99
+ - The knob includes a subtle drop shadow (`0 1px 3px rgba(0,0,0,0.3)`) for depth
100
+ - When disabled, both track and knob use `--switch-disabled` color
101
+ - The component is `display: inline-block` by default
102
+ - Focus halo appears on keyboard focus only (`:focus-visible`), not on mouse click
@@ -11,11 +11,11 @@ export class RelSwitch extends LitElement {
11
11
 
12
12
  static styles = css`
13
13
  :host {
14
- --switch-track: #7e8186;
15
- --switch-knob-on: #000000;
16
- --switch-knob-off: #ffffff;
17
- --switch-halo: rgba(224, 224, 224, 0.8);
18
- --switch-disabled: #d1d5db;
14
+ --switch-track: var(--rel-text-placeholder);
15
+ --switch-knob-on: var(--rel-colors-black);
16
+ --switch-knob-off: var(--rel-colors-white);
17
+ --switch-halo: var(--rel-border-default);
18
+ --switch-disabled: var(--rel-text-disabled);
19
19
  display: inline-block;
20
20
  }
21
21
 
@@ -77,7 +77,7 @@ export class RelSwitch extends LitElement {
77
77
 
78
78
  /* Hover */
79
79
  .switch-wrapper:hover:not(.switch-disabled) .switch-slider {
80
- background-color: #666;
80
+ background-color: var(--rel-text-dark-placeholder);
81
81
  }
82
82
 
83
83
  /* Focus halo */
@@ -100,6 +100,13 @@ export class RelSwitch extends LitElement {
100
100
  .switch-disabled .switch-slider::before {
101
101
  background-color: var(--switch-disabled);
102
102
  }
103
+
104
+ @media (prefers-reduced-motion: reduce) {
105
+ .switch-slider,
106
+ .switch-slider::before {
107
+ transition: none;
108
+ }
109
+ }
103
110
  `;
104
111
 
105
112
  private toggle(ev: Event) {
@@ -148,6 +155,8 @@ export class RelSwitch extends LitElement {
148
155
  <label class="${wrapperClasses}">
149
156
  <input
150
157
  type="checkbox"
158
+ role="switch"
159
+ aria-checked="${this.checked}"
151
160
  ?disabled=${this.disabled}
152
161
  .checked=${this.checked}
153
162
  @change=${(e: Event) => this.toggle(e)}
@@ -0,0 +1,163 @@
1
+ # rel-tab
2
+
3
+ ## Overview
4
+ A tabbed interface component with automatic underline indicator, keyboard navigation, optional badge counts, and disabled states. Features ARIA-compliant navigation with roving tabindex and arrow key support.
5
+
6
+ ## Usage
7
+ ```html
8
+ <!-- Basic tabs -->
9
+ <rel-tab id="basicTabs"></rel-tab>
10
+ <script>
11
+ const tabs = document.getElementById('basicTabs');
12
+ tabs.tabs = [
13
+ { label: 'Overview' },
14
+ { label: 'Details' },
15
+ { label: 'Settings' }
16
+ ];
17
+ tabs.activeIndex = 0;
18
+ </script>
19
+
20
+ <!-- With badges (notification counts) -->
21
+ <rel-tab id="badgeTabs"></rel-tab>
22
+ <script>
23
+ const badgeTabs = document.getElementById('badgeTabs');
24
+ badgeTabs.tabs = [
25
+ { label: 'Inbox', badge: 5 },
26
+ { label: 'Drafts', badge: 2 },
27
+ { label: 'Sent' }
28
+ ];
29
+ </script>
30
+
31
+ <!-- With disabled tab -->
32
+ <rel-tab id="disabledTabs"></rel-tab>
33
+ <script>
34
+ const disabledTabs = document.getElementById('disabledTabs');
35
+ disabledTabs.tabs = [
36
+ { label: 'Available' },
37
+ { label: 'Coming Soon', disabled: true },
38
+ { label: 'Active' }
39
+ ];
40
+ </script>
41
+
42
+ <!-- Listen for tab changes -->
43
+ <rel-tab id="tabsWithListener"></rel-tab>
44
+ <script>
45
+ const listener = document.getElementById('tabsWithListener');
46
+ listener.tabs = [
47
+ { label: 'Tab 1' },
48
+ { label: 'Tab 2' },
49
+ { label: 'Tab 3' }
50
+ ];
51
+ listener.addEventListener('tab-change', (e) => {
52
+ console.log('Active tab index:', e.detail);
53
+ });
54
+ </script>
55
+
56
+ <!-- Tab content controlled externally -->
57
+ <rel-tab id="contentTabs" activeIndex="0"></rel-tab>
58
+ <div id="tabContent">
59
+ <div class="panel" data-index="0">Content for Tab 1</div>
60
+ <div class="panel" data-index="1" style="display:none;">Content for Tab 2</div>
61
+ <div class="panel" data-index="2" style="display:none;">Content for Tab 3</div>
62
+ </div>
63
+ <script>
64
+ const contentTabs = document.getElementById('contentTabs');
65
+ contentTabs.tabs = [
66
+ { label: 'Tab 1' },
67
+ { label: 'Tab 2' },
68
+ { label: 'Tab 3' }
69
+ ];
70
+ contentTabs.addEventListener('tab-change', (e) => {
71
+ document.querySelectorAll('#tabContent .panel').forEach((panel, i) => {
72
+ panel.style.display = i === e.detail ? 'block' : 'none';
73
+ });
74
+ });
75
+ </script>
76
+ ```
77
+
78
+ ## API
79
+
80
+ ### Attributes/Properties
81
+ | Name | Type | Default | Description |
82
+ |------|------|---------|-------------|
83
+ | `tabs` | `TabItem[]` | `[]` | Array of tab items (see TabItem interface below) |
84
+ | `activeIndex` (reflected) | `number` | `0` | Index of the currently active tab |
85
+
86
+ ### TabItem Interface
87
+ ```typescript
88
+ interface TabItem {
89
+ label: string; // Display text
90
+ badge?: number; // Optional notification count
91
+ disabled?: boolean; // Disables interaction
92
+ }
93
+ ```
94
+
95
+ ## Events
96
+ | Event | Detail | Description |
97
+ |-------|--------|-------------|
98
+ | `tab-change` | `number` (the new active index) | Fired when a different tab is selected |
99
+
100
+ ## Slots
101
+ | Slot | Description |
102
+ |------|-------------|
103
+ | (default) | Tab panel content (rendered in `.tab-content` wrapper below tabs) |
104
+
105
+ ## CSS Parts
106
+ None exposed.
107
+
108
+ ## Tokens / CSS Variables
109
+
110
+ ### Component-Level Custom Properties
111
+ The component defines CSS custom properties on `:host`:
112
+
113
+ - `--tab-active-color` - Active tab underline color (default: `--rel-colors-green-primary`)
114
+ - `--tab-text-default` - Default tab text color (default: `--rel-text-primary`)
115
+ - `--tab-text-disabled` - Disabled tab text color (default: `--rel-text-disabled`)
116
+ - `--tab-text-hover` - Hover tab text color (default: `--rel-text-heading`)
117
+ - `--tab-underline-height` - Height of active underline (default: `3px`)
118
+ - `--tab-hover-color` - Background color on hover (default: `--rel-surface-surface`)
119
+
120
+ ### Design Token References
121
+ - `--rel-fontFamilies-primary` - Font family
122
+ - `--rel-fontSizes-md` - Font size
123
+ - `--rel-fontWeights-medium` - Font weight
124
+ - `--rel-spacing-space-sm`, `--rel-spacing-space-md` - Tab padding
125
+ - `--rel-spacing-space-2xs` - Gap between label and badge
126
+ - `--rel-border-tab` - Bottom border color (default: `#c4c4c4`)
127
+ - `--rel-border-info` - Focus outline color
128
+ - `--rel-borders-radius-border-radius-100` - Focus outline border radius
129
+ - `--rel-colors-red-primary` - Badge background color
130
+ - `--rel-colors-white` - Badge text color
131
+
132
+ ## Accessibility
133
+ - Uses `role="tablist"` on container and `role="tab"` on each tab
134
+ - Tabs have `aria-selected` and `aria-disabled` attributes
135
+ - Implements roving tabindex (only active tab is focusable via Tab key)
136
+ - Arrow key navigation between tabs
137
+ - Focus visible states with blue outline
138
+
139
+ ### Keyboard Interactions
140
+ - `Tab` - Focus the active tab (or first non-disabled tab)
141
+ - `Arrow Right` - Navigate to next tab (wraps to first, skips disabled)
142
+ - `Arrow Left` - Navigate to previous tab (wraps to last, skips disabled)
143
+ - `Enter / Space` - Activate focused tab
144
+
145
+ ### Focus Behavior
146
+ - Focus outline: 2px blue with -2px offset (inside boundary)
147
+ - Border radius applied to focus outline
148
+ - Focus automatically moves when navigating with arrow keys
149
+
150
+ ## Notes / Edge Cases
151
+ - The **active tab** has a colored underline (3px high by default) at the bottom
152
+ - **Hover effect** (non-active, non-disabled): light gray background
153
+ - **Badges** are circular (16px height, min 16px width) with red background and white text
154
+ - Clicking a disabled tab does nothing (no event dispatched, no index change)
155
+ - Arrow key navigation wraps around (after last tab, goes to first, and vice versa)
156
+ - Arrow key navigation skips disabled tabs
157
+ - When a tab is activated via arrow keys, focus is programmatically moved to that tab
158
+ - The component includes a `.tab-content` wrapper (with 1rem vertical padding) that renders slotted content
159
+ - The `.tab-content` is always visible; consumers must manually show/hide panel content based on `activeIndex`
160
+ - Tabs have a bottom border (1px solid) via `border-bottom` on `.tabs-wrapper`
161
+ - Active tab underline (`position: absolute`, `bottom: 0`) overlays the border
162
+ - Transitions: color (0.2s), background-color (0.2s), transform (0.2s) for smooth interactions
163
+ - The `activeIndex` property is reflected in HTML as an attribute
@@ -14,34 +14,40 @@ export class RelTab extends LitElement {
14
14
 
15
15
  static styles = css`
16
16
  :host {
17
- --tab-active-color: #00f49c;
18
- --tab-text-default: #111;
19
- --tab-text-disabled: #a5a7aa;
20
- --tab-text-hover: #000;
17
+ --tab-active-color: var(--rel-colors-green-primary);
18
+ --tab-text-default: var(--rel-text-primary);
19
+ --tab-text-disabled: var(--rel-text-disabled);
20
+ --tab-text-hover: var(--rel-text-heading);
21
21
  --tab-underline-height: 3px;
22
- --tab-hover-color: #f3f3f3;
22
+ --tab-hover-color: var(--rel-surface-surface);
23
23
  display: block;
24
24
  font-family: var(--rel-fontFamilies-primary);
25
25
  }
26
26
 
27
27
  .tabs-wrapper {
28
28
  display: flex;
29
- border-bottom: 1px solid #e5e5e5;
30
- font-family: var(--rel-fontFamilies-primary);
29
+ border-bottom: 1px solid var(--rel-border-tab, #c4c4c4);
30
+ font-family: var(--rel-fontFamilies-primary, sans-serif);
31
31
  user-select: none;
32
32
  }
33
33
 
34
34
  .tab {
35
35
  position: relative;
36
- padding: 0.75rem 1rem;
36
+ padding: var(--rel-spacing-space-sm, 12px) var(--rel-spacing-space-md, 16px);
37
37
  cursor: pointer;
38
38
  color: var(--tab-text-default);
39
- font-size: 0.9rem;
40
- font-weight: 500;
39
+ font-size: var(--rel-fontSizes-md, 14px);
40
+ font-weight: var(--rel-fontWeights-medium, 500);
41
41
  transition: color 0.2s ease;
42
42
  display: flex;
43
43
  align-items: center;
44
- gap: 6px;
44
+ gap: var(--rel-spacing-space-2xs, 4px);
45
+ }
46
+
47
+ .tab:focus-visible {
48
+ outline: 2px solid var(--rel-border-info, #0091ea);
49
+ outline-offset: -2px;
50
+ border-radius: var(--rel-borders-radius-border-radius-100, 2px);
45
51
  }
46
52
 
47
53
  .tab:hover:not(.disabled) .tab-label {
@@ -77,8 +83,8 @@ export class RelTab extends LitElement {
77
83
  display: inline-flex;
78
84
  justify-content: center;
79
85
  align-items: center;
80
- background: #ff0400;
81
- color: #fff;
86
+ background: var(--rel-colors-red-primary);
87
+ color: var(--rel-colors-white);
82
88
  border-radius: 50%;
83
89
  font-size: 11px;
84
90
  font-weight: 600;
@@ -107,10 +113,26 @@ export class RelTab extends LitElement {
107
113
  }
108
114
 
109
115
  private onKeyDown(event: KeyboardEvent, index: number) {
110
- if (this.tabs[index]?.disabled) return;
111
116
  if (event.key === "Enter" || event.key === " ") {
117
+ if (this.tabs[index]?.disabled) return;
112
118
  event.preventDefault();
113
119
  this.selectTab(index);
120
+ return;
121
+ }
122
+
123
+ if (event.key === "ArrowRight" || event.key === "ArrowLeft") {
124
+ event.preventDefault();
125
+ const dir = event.key === "ArrowRight" ? 1 : -1;
126
+ let next = index;
127
+ for (let i = 0; i < this.tabs.length; i++) {
128
+ next = (next + dir + this.tabs.length) % this.tabs.length;
129
+ if (!this.tabs[next]?.disabled) break;
130
+ }
131
+ this.selectTab(next);
132
+ this.updateComplete.then(() => {
133
+ const tabEls = this.shadowRoot?.querySelectorAll("[role=tab]");
134
+ (tabEls?.[next] as HTMLElement)?.focus();
135
+ });
114
136
  }
115
137
  }
116
138
 
@@ -0,0 +1,178 @@
1
+ # rel-table
2
+
3
+ ## Overview
4
+ A simple table wrapper component providing optional border and compact mode styling. Uses slots to accept standard HTML table content (thead, tbody, tfoot). Features horizontal scrolling for overflow and semantic table structure.
5
+
6
+ ## Usage
7
+ ```html
8
+ <!-- Basic table -->
9
+ <rel-table>
10
+ <thead>
11
+ <tr>
12
+ <th>Name</th>
13
+ <th>Email</th>
14
+ <th>Role</th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <tr>
19
+ <td>John Doe</td>
20
+ <td>john@example.com</td>
21
+ <td>Admin</td>
22
+ </tr>
23
+ <tr>
24
+ <td>Jane Smith</td>
25
+ <td>jane@example.com</td>
26
+ <td>User</td>
27
+ </tr>
28
+ </tbody>
29
+ </rel-table>
30
+
31
+ <!-- Bordered table -->
32
+ <rel-table bordered>
33
+ <thead>
34
+ <tr>
35
+ <th>Product</th>
36
+ <th>Price</th>
37
+ <th>Quantity</th>
38
+ </tr>
39
+ </thead>
40
+ <tbody>
41
+ <tr>
42
+ <td>Widget</td>
43
+ <td>$10.00</td>
44
+ <td>5</td>
45
+ </tr>
46
+ <tr>
47
+ <td>Gadget</td>
48
+ <td>$25.00</td>
49
+ <td>2</td>
50
+ </tr>
51
+ </tbody>
52
+ </rel-table>
53
+
54
+ <!-- Compact table -->
55
+ <rel-table compact>
56
+ <thead>
57
+ <tr>
58
+ <th>ID</th>
59
+ <th>Status</th>
60
+ </tr>
61
+ </thead>
62
+ <tbody>
63
+ <tr>
64
+ <td>001</td>
65
+ <td>Active</td>
66
+ </tr>
67
+ <tr>
68
+ <td>002</td>
69
+ <td>Pending</td>
70
+ </tr>
71
+ </tbody>
72
+ </rel-table>
73
+
74
+ <!-- Bordered and compact -->
75
+ <rel-table bordered compact>
76
+ <thead>
77
+ <tr>
78
+ <th>Date</th>
79
+ <th>Event</th>
80
+ </tr>
81
+ </thead>
82
+ <tbody>
83
+ <tr>
84
+ <td>2024-01-15</td>
85
+ <td>Launch</td>
86
+ </tr>
87
+ <tr>
88
+ <td>2024-02-20</td>
89
+ <td>Update</td>
90
+ </tr>
91
+ </tbody>
92
+ </rel-table>
93
+
94
+ <!-- Responsive table with horizontal scroll -->
95
+ <rel-table bordered>
96
+ <thead>
97
+ <tr>
98
+ <th>Column 1</th>
99
+ <th>Column 2</th>
100
+ <th>Column 3</th>
101
+ <th>Column 4</th>
102
+ <th>Column 5</th>
103
+ <th>Column 6</th>
104
+ <th>Column 7</th>
105
+ <th>Column 8</th>
106
+ </tr>
107
+ </thead>
108
+ <tbody>
109
+ <tr>
110
+ <td>Data 1</td>
111
+ <td>Data 2</td>
112
+ <td>Data 3</td>
113
+ <td>Data 4</td>
114
+ <td>Data 5</td>
115
+ <td>Data 6</td>
116
+ <td>Data 7</td>
117
+ <td>Data 8</td>
118
+ </tr>
119
+ </tbody>
120
+ </rel-table>
121
+ ```
122
+
123
+ ## API
124
+
125
+ ### Attributes/Properties
126
+ | Name | Type | Default | Description |
127
+ |------|------|---------|-------------|
128
+ | `bordered` (reflected) | `boolean` | `false` | Adds border and border-radius to the table wrapper |
129
+ | `compact` (reflected) | `boolean` | `false` | Applies compact spacing (currently defined but not styled in component) |
130
+
131
+ ## Events
132
+ None.
133
+
134
+ ## Slots
135
+ | Slot | Description |
136
+ |------|-------------|
137
+ | (default) | Standard HTML table content (`<thead>`, `<tbody>`, `<tfoot>`, `<tr>`, `<th>`, `<td>`, etc.) |
138
+
139
+ ## CSS Parts
140
+ None exposed.
141
+
142
+ ## Tokens / CSS Variables
143
+
144
+ ### Semantic Tokens
145
+ - `--rel-fontFamilies-primary` - Font family
146
+ - `--rel-fontSizes-md` - Table font size
147
+
148
+ ### Color Tokens
149
+ - `--rel-colors-gray-primary` - Table text color
150
+ - `--rel-colors-gray-border` - Border color (when bordered is true)
151
+
152
+ ### Border Tokens
153
+ - `--rel-borders-width-stroke-100` - Border width
154
+ - `--rel-borders-radius-border-radius-200` - Table wrapper border radius
155
+
156
+ ## Accessibility
157
+ - Uses semantic native `<table>` element for proper screen reader support
158
+ - Ensure slotted table content includes proper `<thead>`, `<th>`, and `scope` attributes
159
+ - `caption-side: bottom` allows captions to be read after table content
160
+
161
+ ### Keyboard Interactions
162
+ - Standard browser table navigation
163
+ - Focusable elements within cells can be tabbed to
164
+
165
+ ### Focus Behavior
166
+ - No specific focus handling (standard table behavior)
167
+
168
+ ## Notes / Edge Cases
169
+ - The component wraps the table in a `.table-wrapper` div with `overflow-x: auto` for horizontal scrolling
170
+ - The inner `<table>` element uses `border-collapse: collapse` for standard table rendering
171
+ - **bordered mode**: Applies a border with `--rel-borders-width-stroke-100` and rounded corners to the wrapper
172
+ - The `bordered` and `compact` attributes are reflected in HTML (appear as actual attributes when set)
173
+ - **compact mode**: Currently reflected but no styling is applied in the component (may be intended for future use or external styling)
174
+ - The table is `width: 100%` by default
175
+ - The component is `display: block` and takes full width of its container
176
+ - The table uses `caption-side: bottom` for any `<caption>` elements
177
+ - You must provide your own cell padding, row styling, and hover effects via global CSS or inline styles
178
+ - The component provides minimal structural styling; most table appearance is controlled by the browser and your custom CSS
@@ -0,0 +1,16 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+
4
+ @customElement("rel-table-body")
5
+ export class RelTableBody extends LitElement {
6
+ static styles = css`
7
+ :host {
8
+ display: table-row-group;
9
+ font-family: var(--rel-fontFamilies-primary);
10
+ }
11
+ `;
12
+
13
+ render() {
14
+ return html`<slot></slot>`;
15
+ }
16
+ }
@@ -0,0 +1,22 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+
4
+ @customElement("rel-table-caption")
5
+ export class RelTableCaption extends LitElement {
6
+ static styles = css`
7
+ :host {
8
+ display: table-caption;
9
+ caption-side: bottom;
10
+ font-family: var(--rel-fontFamilies-primary);
11
+ margin-top: var(--rel-spacing-space-md);
12
+ padding-top: var(--rel-spacing-space-sm);
13
+ font-size: var(--rel-fontSizes-sm);
14
+ color: var(--rel-colors-gray-placeholder);
15
+ text-align: center;
16
+ }
17
+ `;
18
+
19
+ render() {
20
+ return html`<slot></slot>`;
21
+ }
22
+ }
@@ -0,0 +1,49 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+
4
+ @customElement("rel-table-cell")
5
+ export class RelTableCell extends LitElement {
6
+ @property({ type: String, reflect: true }) align: "left" | "center" | "right" = "left";
7
+ @property({ type: Number, reflect: true }) colspan?: number;
8
+
9
+ static styles = css`
10
+ :host {
11
+ display: table-cell;
12
+ font-family: var(--rel-fontFamilies-primary);
13
+ padding: var(--rel-spacing-space-sm) var(--rel-spacing-space-md);
14
+ font-size: var(--rel-fontSizes-md);
15
+ color: var(--rel-colors-gray-primary);
16
+ vertical-align: middle;
17
+ text-align: left;
18
+ }
19
+
20
+ :host([align="center"]) {
21
+ text-align: center;
22
+ }
23
+
24
+ :host([align="right"]) {
25
+ text-align: right;
26
+ }
27
+ `;
28
+
29
+ render() {
30
+ return html`<slot></slot>`;
31
+ }
32
+
33
+ updated(changedProperties: Map<string, any>) {
34
+ super.updated(changedProperties);
35
+ // Handle colspan attribute
36
+ if (changedProperties.has("colspan") && this.colspan) {
37
+ // Apply colspan to the host element since it's display: table-cell
38
+ this.style.setProperty("--colspan", this.colspan.toString());
39
+ }
40
+ }
41
+
42
+ connectedCallback() {
43
+ super.connectedCallback();
44
+ // Set colspan attribute on the host element for table layout
45
+ if (this.colspan) {
46
+ this.setAttribute("colspan", this.colspan.toString());
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,18 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+
4
+ @customElement("rel-table-footer")
5
+ export class RelTableFooter extends LitElement {
6
+ static styles = css`
7
+ :host {
8
+ display: table-footer-group;
9
+ font-family: var(--rel-fontFamilies-primary);
10
+ font-weight: var(--rel-fontWeights-medium, 500);
11
+ background-color: var(--rel-colors-gray-light);
12
+ }
13
+ `;
14
+
15
+ render() {
16
+ return html`<slot></slot>`;
17
+ }
18
+ }