@reliability-design/web 1.0.3 → 1.1.1

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 (126) hide show
  1. package/dist/components/rel-accordion/README.md +132 -0
  2. package/dist/components/rel-accordion/rel-accordion.ts +47 -16
  3. package/dist/components/rel-alert/README.md +141 -0
  4. package/dist/components/rel-alert/rel-alert.ts +101 -20
  5. package/dist/components/rel-avatar/README.md +119 -0
  6. package/dist/components/rel-avatar/rel-avatar.ts +3 -2
  7. package/dist/components/rel-badge/README.md +86 -0
  8. package/dist/components/rel-badge/rel-badge.ts +11 -7
  9. package/dist/components/rel-breadcrumb/README.md +102 -0
  10. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +12 -6
  11. package/dist/components/rel-button/README.md +130 -0
  12. package/dist/components/rel-button/rel-button.ts +64 -8
  13. package/dist/components/rel-calendar/README.md +109 -0
  14. package/dist/components/rel-calendar/index.ts +1 -0
  15. package/dist/components/rel-calendar/rel-calendar.ts +467 -0
  16. package/dist/components/rel-card/README.md +94 -0
  17. package/dist/components/rel-card/rel-card.ts +12 -3
  18. package/dist/components/rel-cardmedia/README.md +127 -0
  19. package/dist/components/rel-cardmedia/rel-cardmedia.ts +14 -4
  20. package/dist/components/rel-carousel/README.md +166 -0
  21. package/dist/components/rel-carousel/index.ts +1 -0
  22. package/dist/components/rel-carousel/rel-carousel.ts +468 -0
  23. package/dist/components/rel-chart/README.md +286 -0
  24. package/dist/components/rel-chart/index.ts +1 -0
  25. package/dist/components/rel-chart/rel-chart.ts +736 -0
  26. package/dist/components/rel-checkbox/README.md +77 -0
  27. package/dist/components/rel-checkbox/rel-checkbox.ts +51 -12
  28. package/dist/components/rel-chip/README.md +114 -0
  29. package/dist/components/rel-chip/rel-chip.ts +83 -9
  30. package/dist/components/rel-container/README.md +99 -0
  31. package/dist/components/rel-date-picker/README.md +253 -0
  32. package/dist/components/rel-date-picker/index.ts +1 -0
  33. package/dist/components/rel-date-picker/rel-date-picker.ts +916 -0
  34. package/dist/components/rel-divider/README.md +100 -0
  35. package/dist/components/rel-divider/rel-divider.ts +9 -0
  36. package/dist/components/rel-drawer/README.md +200 -0
  37. package/dist/components/rel-drawer/index.ts +1 -0
  38. package/dist/components/rel-drawer/rel-drawer-footer.ts +29 -0
  39. package/dist/components/rel-drawer/rel-drawer.ts +612 -0
  40. package/dist/components/rel-kbd/README.md +151 -0
  41. package/dist/components/rel-kbd/rel-kbd.ts +118 -0
  42. package/dist/components/rel-layout/README.md +88 -0
  43. package/dist/components/rel-menu/README.md +151 -0
  44. package/dist/components/rel-menu/rel-menu.ts +64 -24
  45. package/dist/components/rel-menubar/README.md +329 -0
  46. package/dist/components/rel-menubar/index.ts +2 -0
  47. package/dist/components/rel-menubar/rel-menubar-menu.ts +16 -0
  48. package/dist/components/rel-menubar/rel-menubar.ts +605 -0
  49. package/dist/components/rel-nav-menu/README.md +289 -0
  50. package/dist/components/rel-nav-menu/index.ts +3 -0
  51. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +240 -0
  52. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +53 -0
  53. package/dist/components/rel-nav-menu/rel-nav-menu.ts +227 -0
  54. package/dist/components/rel-navbar/README.md +126 -0
  55. package/dist/components/rel-navbar/rel-navbar.ts +104 -0
  56. package/dist/components/rel-otp/README.md +440 -0
  57. package/dist/components/rel-otp/index.ts +1 -0
  58. package/dist/components/rel-otp/rel-otp.ts +504 -0
  59. package/dist/components/rel-pagination/README.md +410 -0
  60. package/dist/components/rel-pagination/index.ts +1 -0
  61. package/dist/components/rel-pagination/rel-pagination.ts +381 -0
  62. package/dist/components/rel-popover/README.md +568 -0
  63. package/dist/components/rel-popover/index.ts +2 -0
  64. package/dist/components/rel-popover/rel-popover-content.ts +55 -0
  65. package/dist/components/rel-popover/rel-popover.ts +330 -0
  66. package/dist/components/rel-progress/README.md +110 -0
  67. package/dist/components/rel-progress/rel-progress.ts +32 -5
  68. package/dist/components/rel-radio/README.md +120 -0
  69. package/dist/components/rel-radio/rel-radio.ts +31 -6
  70. package/dist/components/rel-resizable/README.md +140 -0
  71. package/dist/components/rel-resizable/index.ts +3 -0
  72. package/dist/components/rel-resizable/rel-resizable-group.ts +374 -0
  73. package/dist/components/rel-resizable/rel-resizable-handle.ts +145 -0
  74. package/dist/components/rel-resizable/rel-resizable-panel.ts +47 -0
  75. package/dist/components/rel-segmented-button/README.md +141 -0
  76. package/dist/components/rel-segmented-button/rel-segmented-button.ts +18 -13
  77. package/dist/components/rel-select/README.md +107 -0
  78. package/dist/components/rel-select/rel-select.ts +28 -14
  79. package/dist/components/rel-sheet/README.md +224 -0
  80. package/dist/components/rel-sheet/rel-sheet.ts +684 -0
  81. package/dist/components/rel-sidebar/README.md +209 -0
  82. package/dist/components/rel-sidebar/rel-sidebar.ts +1166 -0
  83. package/dist/components/rel-slider/README.md +135 -0
  84. package/dist/components/rel-slider/rel-slider.ts +44 -9
  85. package/dist/components/rel-snackbar/README.md +134 -0
  86. package/dist/components/rel-snackbar/rel-snackbar.ts +109 -14
  87. package/dist/components/rel-stepper/README.md +160 -0
  88. package/dist/components/rel-stepper/rel-stepper.ts +38 -27
  89. package/dist/components/rel-switch/README.md +102 -0
  90. package/dist/components/rel-switch/rel-switch.ts +34 -12
  91. package/dist/components/rel-tab/README.md +163 -0
  92. package/dist/components/rel-tab/rel-tab.ts +79 -23
  93. package/dist/components/rel-table/README.md +178 -0
  94. package/dist/components/rel-table/rel-table-body.ts +21 -0
  95. package/dist/components/rel-table/rel-table-caption.ts +27 -0
  96. package/dist/components/rel-table/rel-table-cell.ts +42 -0
  97. package/dist/components/rel-table/rel-table-footer.ts +23 -0
  98. package/dist/components/rel-table/rel-table-head.ts +45 -0
  99. package/dist/components/rel-table/rel-table-header.ts +21 -0
  100. package/dist/components/rel-table/rel-table-row.ts +36 -0
  101. package/dist/components/rel-table/rel-table.ts +53 -0
  102. package/dist/components/rel-textfield/README.md +90 -0
  103. package/dist/components/rel-textfield/rel-textfield.ts +55 -39
  104. package/dist/components/rel-toast/README.md +148 -0
  105. package/dist/components/rel-toast/rel-toast.ts +63 -24
  106. package/dist/components/rel-tooltip/README.md +103 -0
  107. package/dist/components/rel-tooltip/rel-tooltip.ts +123 -80
  108. package/dist/components/rel-topbar/rel-topbar-actions.ts +23 -0
  109. package/dist/components/rel-topbar/rel-topbar-brand.ts +46 -0
  110. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +33 -0
  111. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +28 -0
  112. package/dist/components/rel-topbar/rel-topbar-item.ts +315 -0
  113. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +23 -0
  114. package/dist/components/rel-topbar/rel-topbar-profile.ts +248 -0
  115. package/dist/components/rel-topbar/rel-topbar-utilities.ts +23 -0
  116. package/dist/components/rel-topbar/rel-topbar.ts +329 -0
  117. package/dist/index.d.mts +831 -7
  118. package/dist/index.d.ts +831 -7
  119. package/dist/index.js +9500 -1564
  120. package/dist/index.js.map +1 -1
  121. package/dist/index.mjs +9240 -1344
  122. package/dist/index.mjs.map +1 -1
  123. package/dist/styles/vars.css +187 -25
  124. package/dist/vars-TBB4BMSD.css +346 -0
  125. package/package.json +2 -1
  126. package/dist/vars-6ZIUPIU4.css +0 -184
@@ -0,0 +1,145 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+
4
+ @customElement("rel-resizable-handle")
5
+ export class RelResizableHandle extends LitElement {
6
+ /* =======================
7
+ * PUBLIC API
8
+ * ======================= */
9
+
10
+ @property({ type: String, reflect: true }) orientation: "horizontal" | "vertical" = "horizontal";
11
+
12
+ /* =======================
13
+ * INTERNAL STATE
14
+ * ======================= */
15
+
16
+ /** Index of this handle in the parent group */
17
+ public handleIndex = -1;
18
+
19
+ /** Current split value (0-100) for aria-valuenow */
20
+ public splitValue = 50;
21
+
22
+ /* =======================
23
+ * STYLES
24
+ * ======================= */
25
+
26
+ static styles = css`
27
+ :host {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ flex-shrink: 0;
32
+ position: relative;
33
+ outline: none;
34
+ background: var(--rel-colors-gray-border);
35
+ transition: background 0.15s ease;
36
+ }
37
+
38
+ :host([orientation="horizontal"]) {
39
+ width: 8px;
40
+ min-width: 8px;
41
+ cursor: col-resize;
42
+ }
43
+
44
+ :host([orientation="vertical"]) {
45
+ height: 8px;
46
+ min-height: 8px;
47
+ cursor: row-resize;
48
+ }
49
+
50
+ :host(:hover),
51
+ :host(:focus-visible) {
52
+ background: var(--rel-colors-blue-primary);
53
+ }
54
+
55
+ :host(:focus-visible) {
56
+ outline: 2px solid var(--rel-colors-blue-primary);
57
+ outline-offset: 2px;
58
+ }
59
+
60
+ .grabber {
61
+ background: var(--rel-colors-gray-placeholder);
62
+ border-radius: var(--rel-borders-radius-border-radius-500);
63
+ transition: background 0.15s ease;
64
+ }
65
+
66
+ :host([orientation="horizontal"]) .grabber {
67
+ width: 4px;
68
+ height: 24px;
69
+ }
70
+
71
+ :host([orientation="vertical"]) .grabber {
72
+ width: 24px;
73
+ height: 4px;
74
+ }
75
+
76
+ :host(:hover) .grabber,
77
+ :host(:focus-visible) .grabber {
78
+ background: var(--rel-colors-white);
79
+ }
80
+
81
+ :host([data-dragging]) {
82
+ background: var(--rel-colors-blue-primary);
83
+ }
84
+
85
+ :host([data-dragging]) .grabber {
86
+ background: var(--rel-colors-white);
87
+ }
88
+
89
+ @media (prefers-reduced-motion: reduce) {
90
+ :host {
91
+ transition: none;
92
+ }
93
+
94
+ .grabber {
95
+ transition: none;
96
+ }
97
+ }
98
+ `;
99
+
100
+ /* =======================
101
+ * LIFECYCLE
102
+ * ======================= */
103
+
104
+ connectedCallback() {
105
+ super.connectedCallback();
106
+ this.setAttribute("tabindex", "0");
107
+ this.setAttribute("role", "separator");
108
+ this.updateAriaOrientation();
109
+ }
110
+
111
+ updated(changed: Map<string, unknown>) {
112
+ if (changed.has("orientation")) {
113
+ this.updateAriaOrientation();
114
+ }
115
+ }
116
+
117
+ /* =======================
118
+ * ARIA
119
+ * ======================= */
120
+
121
+ private updateAriaOrientation() {
122
+ this.setAttribute("aria-orientation", this.orientation);
123
+ }
124
+
125
+ public updateAriaValue(value: number) {
126
+ this.splitValue = value;
127
+ this.setAttribute("aria-valuenow", String(Math.round(value)));
128
+ this.setAttribute("aria-valuemin", "0");
129
+ this.setAttribute("aria-valuemax", "100");
130
+ }
131
+
132
+ /* =======================
133
+ * RENDER
134
+ * ======================= */
135
+
136
+ render() {
137
+ return html`<div class="grabber"></div>`;
138
+ }
139
+ }
140
+
141
+ declare global {
142
+ interface HTMLElementTagNameMap {
143
+ "rel-resizable-handle": RelResizableHandle;
144
+ }
145
+ }
@@ -0,0 +1,47 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+
4
+ @customElement("rel-resizable-panel")
5
+ export class RelResizablePanel extends LitElement {
6
+ /* =======================
7
+ * PUBLIC API
8
+ * ======================= */
9
+
10
+ @property({ type: Number, attribute: "defaultsize" }) defaultSize?: number;
11
+ @property({ type: Number, attribute: "minsize" }) minSize = 10;
12
+ @property({ type: Number, attribute: "maxsize" }) maxSize = 90;
13
+
14
+ /* =======================
15
+ * INTERNAL STATE
16
+ * ======================= */
17
+
18
+ /** Current computed size in percentage */
19
+ public currentSize = 0;
20
+
21
+ /* =======================
22
+ * STYLES
23
+ * ======================= */
24
+
25
+ static styles = css`
26
+ :host {
27
+ display: flex;
28
+ flex-direction: column;
29
+ overflow: auto;
30
+ box-sizing: border-box;
31
+ }
32
+ `;
33
+
34
+ /* =======================
35
+ * RENDER
36
+ * ======================= */
37
+
38
+ render() {
39
+ return html`<slot></slot>`;
40
+ }
41
+ }
42
+
43
+ declare global {
44
+ interface HTMLElementTagNameMap {
45
+ "rel-resizable-panel": RelResizablePanel;
46
+ }
47
+ }
@@ -0,0 +1,141 @@
1
+ # rel-segmented-button
2
+
3
+ ## Overview
4
+ A segmented button group for mutually exclusive selections. Displays multiple options as connected buttons with a single active selection. Supports size variants, alignment options, and individual option states (disabled).
5
+
6
+ ## Usage
7
+ ```html
8
+ <!-- Basic segmented button -->
9
+ <rel-segmented-button id="viewMode" active="grid"></rel-segmented-button>
10
+ <script>
11
+ const viewMode = document.getElementById('viewMode');
12
+ viewMode.options = [
13
+ { label: 'List', value: 'list' },
14
+ { label: 'Grid', value: 'grid' },
15
+ { label: 'Table', value: 'table' }
16
+ ];
17
+ </script>
18
+
19
+ <!-- Small size with alignment -->
20
+ <rel-segmented-button
21
+ id="textAlign"
22
+ size="small"
23
+ align="middle"
24
+ active="center">
25
+ </rel-segmented-button>
26
+ <script>
27
+ const textAlign = document.getElementById('textAlign');
28
+ textAlign.options = [
29
+ { label: 'Left', value: 'left' },
30
+ { label: 'Center', value: 'center' },
31
+ { label: 'Right', value: 'right' }
32
+ ];
33
+ </script>
34
+
35
+ <!-- With disabled option -->
36
+ <rel-segmented-button id="planSelector"></rel-segmented-button>
37
+ <script>
38
+ const planSelector = document.getElementById('planSelector');
39
+ planSelector.options = [
40
+ { label: 'Free', value: 'free' },
41
+ { label: 'Pro', value: 'pro' },
42
+ { label: 'Enterprise', value: 'enterprise', disabled: true }
43
+ ];
44
+ planSelector.active = 'free';
45
+ </script>
46
+
47
+ <!-- Listen for changes -->
48
+ <rel-segmented-button id="sortOrder"></rel-segmented-button>
49
+ <script>
50
+ const sortOrder = document.getElementById('sortOrder');
51
+ sortOrder.options = [
52
+ { label: 'Newest', value: 'newest' },
53
+ { label: 'Oldest', value: 'oldest' },
54
+ { label: 'Popular', value: 'popular' }
55
+ ];
56
+ sortOrder.addEventListener('changed', (e) => {
57
+ console.log('Selected:', e.detail.value);
58
+ });
59
+ </script>
60
+ ```
61
+
62
+ ## API
63
+
64
+ ### Attributes/Properties
65
+ | Name | Type | Default | Description |
66
+ |------|------|---------|-------------|
67
+ | `options` | `SegmentOption[]` | `[]` | Array of segment options (see SegmentOption interface below) |
68
+ | `active` | `string` | `""` | Value of the currently active segment |
69
+ | `size` | `"small" \| "medium"` | `"medium"` | Size variant |
70
+ | `align` | `"left" \| "middle" \| "right"` | `"left"` | Horizontal alignment of the button group |
71
+
72
+ ### SegmentOption Interface
73
+ ```typescript
74
+ interface SegmentOption {
75
+ label: string; // Display text for the button
76
+ value: string; // Unique value identifier
77
+ disabled?: boolean; // Optional: disable this specific segment
78
+ }
79
+ ```
80
+
81
+ ## Events
82
+ | Event | Detail | Description |
83
+ |-------|--------|-------------|
84
+ | `changed` | `{ value: string }` | Fired when a different segment is selected |
85
+
86
+ ## Slots
87
+ Default slot not used.
88
+
89
+ ## CSS Parts
90
+ None exposed.
91
+
92
+ ## Tokens / CSS Variables
93
+
94
+ ### Semantic Tokens
95
+ - `--rel-fontFamilies-primary` - Font family
96
+ - `--rel-fontSizes-xs`, `--rel-fontSizes-sm` - Font sizes for small and medium variants
97
+ - `--rel-fontWeights-medium` - Font weight for segment labels
98
+
99
+ ### Spacing Tokens
100
+ - `--rel-spacing-space-3xs`, `--rel-spacing-space-2xs` - Vertical padding for sizes
101
+ - `--rel-spacing-space-xs`, `--rel-spacing-space-sm` - Horizontal padding for sizes
102
+
103
+ ### Color Tokens
104
+ - `--rel-colors-white` - Default segment background
105
+ - `--rel-colors-gray-border` - Outer border and segment dividers
106
+ - `--rel-text-heading` - Active segment background and default text color
107
+ - `--rel-surface-surface` - Hover and disabled background
108
+ - `--rel-text-disabled` - Disabled text color
109
+ - `--rel-border-info` - Focus outline color
110
+
111
+ ### Border Tokens
112
+ - `--rel-borders-radius-border-radius-300` - Border radius for the group
113
+
114
+ ## Accessibility
115
+ - Uses native `<button>` elements for proper keyboard navigation
116
+ - Focus visible state with inner outline for keyboard users
117
+ - Disabled segments use `pointer-events: none` and reduced opacity
118
+ - Each segment can receive focus independently
119
+
120
+ ### Keyboard Interactions
121
+ - `Tab` - Move focus between segments
122
+ - `Space/Enter` - Activate focused segment
123
+ - `Arrow Left/Right` - Navigate between segments (browser default)
124
+
125
+ ### Focus Behavior
126
+ - Focus outline appears inside the button boundary with `-2px` offset
127
+ - Uses info border color for high contrast
128
+ - Active button has `z-index: 1` to ensure focus ring is visible over adjacent segments
129
+
130
+ ## Notes / Edge Cases
131
+ - The component is `display: inline-block` and sizes to fit content
132
+ - All segments are connected with shared borders (2px solid gray)
133
+ - The last segment has no right border to avoid doubling with the outer container border
134
+ - Active segment has inverted colors (dark background, white text)
135
+ - Hovering a non-active, non-disabled segment shows a light gray background
136
+ - Hovering the active segment does not change its appearance
137
+ - Disabled segments show reduced opacity (0.5), gray background, and are non-interactive
138
+ - The `align` property uses flexbox justify-content (left → flex-start, middle → center, right → flex-end)
139
+ - Size variants affect both font size and padding
140
+ - Smooth transitions (0.2s ease-in-out) apply to all visual changes
141
+ - Clicking a disabled option will not change the `active` value or dispatch events
@@ -48,15 +48,20 @@ export class RelSegmentedButton extends LitElement {
48
48
 
49
49
  /* Base segment styling */
50
50
  .segment {
51
- background: var(--rel-colors-white);
51
+ background: var(--rel-colors-white, #fff);
52
52
  border: none;
53
53
  cursor: pointer;
54
- font-weight: var(--rel-fontWeights-medium);
55
- border-right: 2px solid var(--rel-colors-gray-border);
54
+ font-weight: var(--rel-fontWeights-medium, 500);
55
+ border-right: 2px solid var(--rel-colors-gray-border, #ddd);
56
56
  transition: all 0.2s ease-in-out;
57
- color: var(--rel-colors-gray-heading);
58
- font-family: var(--rel-fontFamilies-primary);
59
- outline: none;
57
+ color: var(--rel-text-heading, #2b2b2b);
58
+ font-family: var(--rel-fontFamilies-primary, sans-serif);
59
+ }
60
+
61
+ .segment:focus-visible {
62
+ outline: 2px solid var(--rel-border-info, #0091ea);
63
+ outline-offset: -2px;
64
+ z-index: 1;
60
65
  }
61
66
 
62
67
  .segment:last-child {
@@ -65,18 +70,18 @@ export class RelSegmentedButton extends LitElement {
65
70
 
66
71
  /* Hover */
67
72
  .segment:hover:not(.disabled):not(.active) {
68
- background: var(--rel-colors-gray-bg);
73
+ background: var(--rel-surface-surface, #f5f5f5);
69
74
  }
70
75
 
71
76
  /* Active */
72
77
  .segment.active {
73
- background: var(--rel-colors-black);
74
- color: var(--rel-colors-white);
78
+ background: var(--rel-text-heading, #2b2b2b);
79
+ color: var(--rel-colors-white, #fff);
75
80
  }
76
81
 
77
82
  .segment.active:hover:not(.disabled) {
78
- background: var(--rel-colors-black);
79
- color: var(--rel-colors-white);
83
+ background: var(--rel-text-heading, #2b2b2b);
84
+ color: var(--rel-colors-white, #fff);
80
85
  }
81
86
 
82
87
  /* Disabled */
@@ -84,8 +89,8 @@ export class RelSegmentedButton extends LitElement {
84
89
  .segment:disabled {
85
90
  cursor: not-allowed;
86
91
  opacity: 0.5;
87
- background: var(--rel-colors-gray-bg);
88
- color: var(--rel-colors-gray-placeholder);
92
+ background: var(--rel-surface-surface, #f5f5f5);
93
+ color: var(--rel-text-disabled, #9e9e9e);
89
94
  pointer-events: none;
90
95
  }
91
96
 
@@ -0,0 +1,107 @@
1
+ # rel-select
2
+
3
+ ## Overview
4
+ A customizable dropdown select component with support for icons, multiple states, and sizes. Features built-in validation states, supporting text, and comprehensive styling options for form-based interfaces.
5
+
6
+ ## Usage
7
+ ```html
8
+ <!-- Basic example -->
9
+ <rel-select id="countrySelect" label="Country" selected="USA"></rel-select>
10
+ <script>
11
+ const select = document.getElementById('countrySelect');
12
+ select.options = ['USA', 'Canada', 'Mexico'];
13
+ </script>
14
+
15
+ <!-- Example with common options -->
16
+ <rel-select
17
+ id="emailPreference"
18
+ label="Email Preference"
19
+ selected="Weekly"
20
+ size="medium"
21
+ state="default"
22
+ supportingText="Choose how often you want to receive emails"
23
+ leftIcon="📧">
24
+ </rel-select>
25
+ <script>
26
+ const emailPref = document.getElementById('emailPreference');
27
+ emailPref.options = ['Daily', 'Weekly', 'Monthly', 'Never'];
28
+ </script>
29
+ ```
30
+
31
+ ## API
32
+
33
+ ### Attributes/Properties
34
+ | Name | Type | Default | Description |
35
+ |------|------|---------|-------------|
36
+ | `label` | `string` | `""` | Label text displayed above the select |
37
+ | `options` | `string[]` | `[]` | Array of option values to display in dropdown |
38
+ | `selected` | `string` | `""` | Currently selected option value |
39
+ | `state` | `"default" \| "error" \| "disabled"` | `"default"` | Visual and interaction state of the select |
40
+ | `supportingText` | `string` | `""` | Helper or error text displayed below the select |
41
+ | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Size variant affecting padding and font size |
42
+ | `border` | `"rounded" \| "sharp"` | `"rounded"` | Border radius style |
43
+ | `leftIcon` | `string` | `""` | Icon or text displayed on the left side |
44
+ | `rightIcon` | `string` | `""` | Icon or text displayed on the right side (before dropdown arrow) |
45
+
46
+ ## Events
47
+ | Event | Detail | Description |
48
+ |-------|--------|-------------|
49
+ | `changed` | `{ value: string }` | Fired when the selected value changes |
50
+
51
+ ## Slots
52
+ Default slot not used.
53
+
54
+ ## CSS Parts
55
+ None exposed.
56
+
57
+ ## Tokens / CSS Variables
58
+
59
+ ### Semantic Tokens
60
+ - `--rel-fontFamilies-primary` - Font family
61
+ - `--rel-fontSizes-xs`, `--rel-fontSizes-sm`, `--rel-fontSizes-md` - Font sizes for different size variants
62
+ - `--rel-fontWeights-medium` - Font weight for label
63
+
64
+ ### Spacing Tokens
65
+ - `--rel-spacing-space-3xs`, `--rel-spacing-space-2xs`, `--rel-spacing-space-xs` - Internal padding
66
+ - `--rel-spacing-space-sm`, `--rel-spacing-space-lg`, `--rel-spacing-space-xl`, `--rel-spacing-space-2xl`, `--rel-spacing-space-3xl` - Padding and icon positioning
67
+
68
+ ### Color Tokens
69
+ - `--rel-colors-gray-heading` - Label text color
70
+ - `--rel-colors-gray-primary` - Icon and border hover color
71
+ - `--rel-colors-gray-border` - Default border color
72
+ - `--rel-colors-gray-placeholder` - Supporting text color
73
+ - `--rel-colors-white` - Background color
74
+ - `--rel-colors-primary-500` - Focus border and shadow color
75
+ - `--rel-colors-red-secondary` - Error state border color
76
+ - `--rel-background-error-light` - Error state focus shadow
77
+ - `--rel-surface-surface` - Disabled background
78
+ - `--rel-text-heading` - Select text color
79
+ - `--rel-text-disabled` - Disabled text color
80
+
81
+ ### Border Tokens
82
+ - `--rel-borders-radius-border-radius-300` - Rounded border radius
83
+
84
+ ## Accessibility
85
+ - Native `<select>` element provides built-in keyboard navigation
86
+ - Focus visible states with clear visual indicators (border color and box shadow)
87
+ - Label properly associated with select for screen readers
88
+ - Disabled state prevents interaction and reduces opacity
89
+ - Error state communicated through color and supporting text
90
+
91
+ ### Keyboard Interactions
92
+ - `Space/Enter` - Open dropdown
93
+ - `Arrow Up/Down` - Navigate options
94
+ - `Escape` - Close dropdown
95
+ - `Tab` - Move focus to next element
96
+
97
+ ### Focus Behavior
98
+ - Clear focus ring with primary color on keyboard focus
99
+ - Focus state uses box-shadow for visibility
100
+
101
+ ## Notes / Edge Cases
102
+ - When `state="disabled"`, the select becomes non-interactive with reduced opacity and cursor indication
103
+ - Empty `selected` value shows placeholder text "Select Option" which is hidden from the dropdown list
104
+ - Icons (left/right) adjust internal padding automatically to accommodate icon space
105
+ - The native dropdown arrow is always visible on the right side, custom rightIcon appears before it
106
+ - In error state, supporting text is styled with error color for visual consistency
107
+ - Options array is rendered as-is; complex objects not supported (use string values only)
@@ -28,7 +28,7 @@ export class RelSelect extends LitElement {
28
28
  static styles = css`
29
29
  :host {
30
30
  display: block;
31
- font-family: var(--rel-fontFamilies-primary);
31
+ font-family: var(--rel-fontFamilies-primary, sans-serif);
32
32
  width: 100%;
33
33
  }
34
34
 
@@ -74,26 +74,26 @@ export class RelSelect extends LitElement {
74
74
  select {
75
75
  flex: 1;
76
76
  appearance: none;
77
- border: 1px solid var(--rel-colors-gray-border);
78
- background-color: var(--rel-colors-white);
79
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
77
+ border: 1px solid var(--rel-colors-gray-border, #ddd);
78
+ background-color: var(--rel-colors-white, #fff);
79
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='currentColor' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
80
80
  background-repeat: no-repeat;
81
81
  background-position: right 12px center;
82
- font-family: var(--rel-fontFamilies-primary);
82
+ font-family: var(--rel-fontFamilies-primary, sans-serif);
83
83
  cursor: pointer;
84
84
  transition: all 0.2s ease-in-out;
85
- color: var(--rel-colors-gray-heading);
85
+ color: var(--rel-text-heading, #2b2b2b);
86
86
  width: 100%;
87
87
  outline: none;
88
88
  }
89
89
 
90
90
  select:hover:not(:disabled) {
91
- border-color: var(--rel-colors-gray-primary);
91
+ border-color: var(--rel-colors-gray-primary, #333);
92
92
  }
93
93
 
94
- select:focus:not(:disabled) {
95
- border-color: var(--rel-colors-black);
96
- box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.1);
94
+ select:focus-visible:not(:disabled) {
95
+ border-color: var(--rel-colors-primary-500, #0091ea);
96
+ box-shadow: 0 0 0 2px var(--rel-colors-primary-500, #0091ea);
97
97
  }
98
98
 
99
99
  /* States */
@@ -102,13 +102,13 @@ export class RelSelect extends LitElement {
102
102
  }
103
103
 
104
104
  select.error:focus {
105
- box-shadow: 0 0 0 3px rgba(213, 0, 0, 0.1);
105
+ box-shadow: 0 0 0 3px var(--rel-background-error-light);
106
106
  }
107
107
 
108
108
  select:disabled {
109
- background-color: var(--rel-colors-gray-bg);
110
- border-color: var(--rel-colors-gray-border);
111
- color: var(--rel-colors-gray-placeholder);
109
+ background-color: var(--rel-surface-surface, #f5f5f5);
110
+ border-color: var(--rel-colors-gray-border, #ddd);
111
+ color: var(--rel-text-disabled, #9e9e9e);
112
112
  cursor: not-allowed;
113
113
  opacity: 0.6;
114
114
  }
@@ -176,6 +176,20 @@ export class RelSelect extends LitElement {
176
176
  .error-text {
177
177
  color: var(--rel-colors-red-secondary);
178
178
  }
179
+
180
+ /* Dark mode — flip select background, text, border, and chevron icon to white */
181
+ :host-context([data-theme="dark"]) select,
182
+ :host-context(.dark) select {
183
+ background-color: var(--rel-color-bg-secondary);
184
+ color: #ffffff;
185
+ border-color: var(--rel-color-border-default);
186
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
187
+ }
188
+
189
+ :host-context([data-theme="dark"]) .select-label,
190
+ :host-context(.dark) .select-label {
191
+ color: var(--rel-color-text-primary);
192
+ }
179
193
  `;
180
194
 
181
195
  private onChange(event: Event) {