@reliability-design/web 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/components/rel-accordion/rel-accordion.ts +289 -150
  2. package/dist/components/rel-alert/rel-alert.ts +34 -34
  3. package/dist/components/rel-avatar/README.md +15 -4
  4. package/dist/components/rel-avatar/rel-avatar.ts +138 -94
  5. package/dist/components/rel-badge/README.md +7 -0
  6. package/dist/components/rel-badge/rel-badge.ts +39 -2
  7. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +6 -6
  8. package/dist/components/rel-button/rel-button.ts +96 -28
  9. package/dist/components/rel-calendar/rel-calendar.ts +15 -8
  10. package/dist/components/rel-card/rel-card.ts +9 -17
  11. package/dist/components/rel-cardmedia/rel-cardmedia.ts +20 -23
  12. package/dist/components/rel-carousel/rel-carousel.ts +596 -468
  13. package/dist/components/rel-checkbox/rel-checkbox.ts +68 -16
  14. package/dist/components/rel-chip/README.md +7 -0
  15. package/dist/components/rel-chip/rel-chip.ts +411 -244
  16. package/dist/components/rel-container/rel-container.ts +2 -2
  17. package/dist/components/rel-date-picker/rel-date-picker.ts +23 -19
  18. package/dist/components/rel-divider/rel-divider.ts +3 -3
  19. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -2
  20. package/dist/components/rel-drawer/rel-drawer.ts +46 -90
  21. package/dist/components/rel-kbd/rel-kbd.ts +94 -118
  22. package/dist/components/rel-layout/rel-layout.ts +49 -58
  23. package/dist/components/rel-menu/rel-menu.ts +359 -359
  24. package/dist/components/rel-menubar/rel-menubar-menu.css +3 -0
  25. package/dist/components/rel-menubar/rel-menubar-menu.ts +2 -1
  26. package/dist/components/rel-menubar/rel-menubar.ts +603 -605
  27. package/dist/components/rel-otp/rel-otp.ts +22 -25
  28. package/dist/components/rel-pagination/rel-pagination.ts +442 -381
  29. package/dist/components/rel-popover/rel-popover-content.ts +6 -5
  30. package/dist/components/rel-popover/rel-popover.ts +26 -7
  31. package/dist/components/rel-progress/rel-progress.ts +10 -9
  32. package/dist/components/rel-radio/rel-radio.ts +228 -172
  33. package/dist/components/rel-range-picker/rel-range-picker.css +349 -0
  34. package/dist/components/rel-range-picker/rel-range-picker.ts +1080 -0
  35. package/dist/components/rel-resizable/rel-resizable-handle.ts +8 -7
  36. package/dist/components/rel-segmented-button/rel-segmented-button.ts +41 -20
  37. package/dist/components/rel-select/README.md +34 -28
  38. package/dist/components/rel-select/rel-select.ts +1015 -275
  39. package/dist/components/rel-sheet/rel-sheet.ts +365 -684
  40. package/dist/components/rel-skeleton/rel-skeleton.ts +139 -0
  41. package/dist/components/rel-slider/rel-slider.ts +49 -27
  42. package/dist/components/rel-snackbar/rel-snackbar.ts +28 -28
  43. package/dist/components/rel-stepper/rel-stepper.ts +11 -10
  44. package/dist/components/rel-switch/rel-switch.ts +7 -6
  45. package/dist/components/rel-tab/rel-tab.ts +15 -29
  46. package/dist/components/rel-textfield/rel-textfield.ts +192 -35
  47. package/dist/components/rel-toast/rel-toast.ts +21 -13
  48. package/dist/components/rel-tooltip/rel-tooltip.ts +123 -123
  49. package/dist/components/rel-topbar/rel-topbar-actions.ts +1 -0
  50. package/dist/components/rel-topbar/rel-topbar-brand.ts +1 -0
  51. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +32 -2
  52. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +1 -1
  53. package/dist/components/rel-topbar/rel-topbar-item.ts +15 -10
  54. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +1 -0
  55. package/dist/components/rel-topbar/rel-topbar-profile.ts +30 -56
  56. package/dist/components/rel-topbar/rel-topbar-utilities.ts +1 -0
  57. package/dist/components/rel-topbar/rel-topbar.ts +137 -28
  58. package/dist/index.d.mts +310 -193
  59. package/dist/index.d.ts +310 -193
  60. package/dist/index.js +5562 -3526
  61. package/dist/index.js.map +1 -1
  62. package/dist/index.mjs +5328 -3284
  63. package/dist/index.mjs.map +1 -1
  64. package/dist/rel-menubar-menu-BEEQDAXW.css +3 -0
  65. package/dist/styles/vars-v2.css +525 -0
  66. package/dist/styles/vars.css +346 -346
  67. package/dist/{vars-TBB4BMSD.css → vars-I2PC74XD.css} +346 -346
  68. package/dist/vars-v2-VMGWTFJZ.css +525 -0
  69. package/package.json +2 -1
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement, property } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
3
4
 
4
5
  @customElement("rel-popover-content")
5
6
  export class RelPopoverContent extends LitElement {
@@ -13,14 +14,14 @@ export class RelPopoverContent extends LitElement {
13
14
  }
14
15
 
15
16
  .popover-content {
16
- background: var(--rel-colors-white);
17
- border: var(--rel-borders-width-stroke-100) solid var(--rel-colors-gray-border);
17
+ background: var(--rel-color-bg-primary);
18
+ border: var(--rel-borders-width-stroke-100) solid var(--rel-color-border-default);
18
19
  border-radius: var(--rel-borders-radius-border-radius-200);
19
20
  box-shadow: var(--rel-shadows-shadow-300);
20
21
  padding: var(--rel-spacing-space-md);
21
22
  font-family: var(--rel-fontFamilies-primary);
22
23
  font-size: var(--rel-fontSizes-sm);
23
- color: var(--rel-colors-gray-heading);
24
+ color: var(--rel-color-text-heading);
24
25
  }
25
26
 
26
27
  .popover-content ::slotted(h1),
@@ -31,12 +32,12 @@ export class RelPopoverContent extends LitElement {
31
32
  .popover-content ::slotted(h6) {
32
33
  margin: 0 0 var(--rel-spacing-space-xs);
33
34
  font-weight: var(--rel-fontWeights-semibold);
34
- color: var(--rel-colors-gray-heading);
35
+ color: var(--rel-color-text-heading);
35
36
  }
36
37
 
37
38
  .popover-content ::slotted(p) {
38
39
  margin: 0 0 var(--rel-spacing-space-sm);
39
- color: var(--rel-colors-gray-placeholder);
40
+ color: var(--rel-color-text-placeholder);
40
41
  line-height: var(--rel-lineHeights-md);
41
42
  }
42
43
 
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement, property, state, query } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
3
4
 
4
5
  type SideType = "top" | "right" | "bottom" | "left";
5
6
  type AlignType = "start" | "center" | "end";
@@ -48,8 +49,12 @@ export class RelPopover extends LitElement {
48
49
  }
49
50
 
50
51
  :host([disabled]) {
51
- pointer-events: none;
52
52
  opacity: 0.6;
53
+ cursor: not-allowed;
54
+ }
55
+
56
+ :host([disabled]) * {
57
+ pointer-events: none;
53
58
  }
54
59
 
55
60
  .content-wrapper {
@@ -233,7 +238,8 @@ export class RelPopover extends LitElement {
233
238
  }
234
239
 
235
240
  private restoreFocus() {
236
- this.triggerEl?.focus();
241
+ (this.returnFocusEl ?? this.triggerEl)?.focus();
242
+ this.returnFocusEl = null;
237
243
  }
238
244
 
239
245
  private trapFocusLoop(e: KeyboardEvent) {
@@ -272,12 +278,25 @@ export class RelPopover extends LitElement {
272
278
  const t = this.triggerEl.getBoundingClientRect();
273
279
  const c = this.contentWrapper.getBoundingClientRect();
274
280
 
275
- let top = t.bottom + this.sideOffset;
276
- let left = t.left + t.width / 2 - c.width / 2;
281
+ let top = 0;
282
+ let left = 0;
277
283
 
278
- if (this.side === "top") top = t.top - c.height - this.sideOffset;
279
- if (this.side === "left") left = t.left - c.width - this.sideOffset;
280
- if (this.side === "right") left = t.right + this.sideOffset;
284
+ if (this.side === "top") {
285
+ top = t.top - c.height - this.sideOffset;
286
+ left = t.left + t.width / 2 - c.width / 2;
287
+ }
288
+ if (this.side === "bottom") {
289
+ top = t.bottom + this.sideOffset;
290
+ left = t.left + t.width / 2 - c.width / 2;
291
+ }
292
+ if (this.side === "left") {
293
+ top = t.top + t.height / 2 - c.height / 2;
294
+ left = t.left - c.width - this.sideOffset;
295
+ }
296
+ if (this.side === "right") {
297
+ top = t.top + t.height / 2 - c.height / 2;
298
+ left = t.right + this.sideOffset;
299
+ }
281
300
 
282
301
  top = Math.max(8, Math.min(top, window.innerHeight - c.height - 8));
283
302
  left = Math.max(8, Math.min(left, window.innerWidth - c.width - 8));
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement, property } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
3
4
 
4
5
  export type ProgressMode =
5
6
  | "linear-determinate"
@@ -21,7 +22,7 @@ export class RelProgress extends LitElement {
21
22
  static styles = css`
22
23
  :host {
23
24
  display: block;
24
- font-family: var(--rel-fontFamilies-primary, sans-serif);
25
+ font-family: var(--rel-fontFamilies-primary);
25
26
  }
26
27
 
27
28
  :host([mode*="circular"]) {
@@ -30,15 +31,15 @@ export class RelProgress extends LitElement {
30
31
 
31
32
  /* Linear */
32
33
  .linear-track {
33
- background: var(--rel-colors-gray-border, #ddd);
34
- border-radius: var(--rel-borders-radius-border-radius-200, 8px);
34
+ background: var(--rel-color-border-default);
35
+ border-radius: var(--rel-borders-radius-border-radius-0);
35
36
  height: 6px;
36
37
  overflow: hidden;
37
38
  width: 100%;
38
39
  }
39
40
 
40
41
  .linear-bar {
41
- background: var(--rel-colors-black);
42
+ background: var(--rel-color-text-primary);
42
43
  height: 100%;
43
44
  transition: width 0.3s ease;
44
45
  }
@@ -75,15 +76,15 @@ export class RelProgress extends LitElement {
75
76
 
76
77
  .circular-bg {
77
78
  fill: none;
78
- stroke: var(--rel-colors-gray-border);
79
+ stroke: var(--rel-color-border-default);
79
80
  stroke-width: 3;
80
81
  }
81
82
 
82
83
  .circular-progress {
83
84
  fill: none;
84
- stroke: var(--rel-colors-black);
85
+ stroke: var(--rel-color-text-primary);
85
86
  stroke-width: 3;
86
- stroke-linecap: round;
87
+ stroke-linecap: butt;
87
88
  transition: stroke-dashoffset 0.35s;
88
89
  }
89
90
 
@@ -93,8 +94,8 @@ export class RelProgress extends LitElement {
93
94
  }
94
95
 
95
96
  .spinner-path {
96
- stroke: var(--rel-colors-black);
97
- stroke-linecap: round;
97
+ stroke: var(--rel-color-text-primary);
98
+ stroke-linecap: butt;
98
99
  animation: dash 1.5s ease-in-out infinite;
99
100
  }
100
101
 
@@ -1,172 +1,228 @@
1
- import { LitElement, html, css } from "lit";
2
- import { customElement, property } from "lit/decorators.js";
3
-
4
- export interface RadioOption {
5
- value: string;
6
- label: string;
7
- supportingText?: string;
8
- disabled?: boolean;
9
- error?: boolean;
10
- }
11
-
12
- @customElement("rel-radio")
13
- export class RelRadio extends LitElement {
14
- @property({ type: Array }) options: RadioOption[] = [];
15
-
16
- @property({ type: String }) name = "radio-group";
17
-
18
- @property({ type: String, reflect: true })
19
- selectedValue: string | null = null;
20
-
21
- @property({ type: Boolean })
22
- disabled = false;
23
-
24
- @property({ type: String }) value = "";
25
-
26
- checked = false;
27
-
28
- private _onChange: (value: string) => void = () => {};
29
- private _onTouched: () => void = () => {};
30
-
31
- static styles = css`
32
- :host {
33
- display: block;
34
- font-family: var(--rel-fontFamilies-primary);
35
- }
36
-
37
- .rel-radio-group {
38
- display: flex;
39
- flex-direction: column;
40
- gap: var(--rel-spacing-space-xs);
41
- }
42
-
43
- .rel-radio-option {
44
- display: flex;
45
- flex-direction: column;
46
- gap: var(--rel-spacing-space-3xs);
47
- cursor: pointer;
48
- }
49
-
50
- .rel-radio-option.disabled {
51
- opacity: 0.6;
52
- cursor: not-allowed !important;
53
- }
54
-
55
- .radio-main {
56
- display: flex;
57
- align-items: center;
58
- gap: var(--rel-spacing-space-2xs);
59
- }
60
-
61
- input {
62
- position: absolute;
63
- opacity: 0;
64
- pointer-events: none;
65
- }
66
-
67
- .radio-custom {
68
- width: 20px;
69
- height: 20px;
70
- border: 2px solid var(--rel-text-heading, #2b2b2b);
71
- border-radius: 50%;
72
- position: relative;
73
- flex-shrink: 0;
74
- }
75
-
76
- input:focus-visible + .radio-custom {
77
- outline: 2px solid var(--rel-border-info, #0091ea);
78
- outline-offset: 2px;
79
- }
80
-
81
- input:checked + .radio-custom::after {
82
- content: "";
83
- position: absolute;
84
- inset: 4px;
85
- background: var(--rel-text-heading, #2b2b2b);
86
- border-radius: 50%;
87
- }
88
-
89
- .radio-label {
90
- font-size: var(--rel-fontSizes-sm, 12px);
91
- font-weight: var(--rel-fontWeights-medium, 500);
92
- color: var(--rel-text-primary, #333);
93
- }
94
-
95
- .radio-supporting {
96
- font-size: var(--rel-fontSizes-xs, 10px);
97
- margin-left: 28px;
98
- color: var(--rel-text-placeholder, #a9a9a9);
99
- }
100
-
101
- .error .radio-custom {
102
- border-color: var(--rel-colors-red-secondary);
103
- }
104
-
105
- .error input:checked + .radio-custom::after {
106
- background: var(--rel-colors-red-secondary);
107
- }
108
- `;
109
-
110
- private onChange(value: string) {
111
- if (this.disabled) return;
112
-
113
- this.selectedValue = value;
114
- this.dispatchEvent(
115
- new CustomEvent("rel-change", {
116
- detail: {
117
- checked: this.selectedValue === value,
118
- value,
119
- },
120
- bubbles: true,
121
- composed: true,
122
- })
123
- );
124
- this._onChange(this.value);
125
- }
126
-
127
- registerOnChange(fn: (value: string) => void): void { this._onChange = fn; }
128
- registerOnTouched(fn: () => void): void { this._onTouched = fn; }
129
- writeValue(value: string): void { this.checked = value === this.value; }
130
-
131
- private renderOption(option: RadioOption) {
132
- const isChecked = this.selectedValue === option.value;
133
- const isDisabled = this.disabled || option.disabled;
134
-
135
- const classes = [
136
- "rel-radio-option",
137
- isDisabled ? "disabled" : "",
138
- option.error ? "error" : "",
139
- ]
140
- .filter(Boolean)
141
- .join(" ");
142
-
143
- return html`
144
- <label class="${classes}">
145
- <div class="radio-main">
146
- <input
147
- type="radio"
148
- name="${this.name}"
149
- .checked="${isChecked}"
150
- ?disabled="${isDisabled}"
151
- @change="${() => this.onChange(option.value)}"
152
- @blur="${() => this._onTouched()}"
153
- />
154
- <span class="radio-custom"></span>
155
- <span class="radio-label">${option.label}</span>
156
- </div>
157
-
158
- ${option.supportingText
159
- ? html`<div class="radio-supporting">${option.supportingText}</div>`
160
- : ""}
161
- </label>
162
- `;
163
- }
164
-
165
- render() {
166
- return html`
167
- <div class="rel-radio-group">
168
- ${this.options.map((o) => this.renderOption(o))}
169
- </div>
170
- `;
171
- }
172
- }
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
4
+
5
+ export interface RadioOption {
6
+ value: string;
7
+ label: string;
8
+ supportingText?: string;
9
+ disabled?: boolean;
10
+ }
11
+
12
+ @customElement("rel-radio")
13
+ export class RelRadio extends LitElement {
14
+ @property({ type: Array }) options: RadioOption[] = [];
15
+
16
+ @property({ type: String }) name = "radio-group";
17
+
18
+ @property({ type: String, reflect: true })
19
+ selectedValue: string | null = null;
20
+
21
+ @property({ type: Boolean })
22
+ disabled = false;
23
+
24
+ @property({ type: Boolean }) error = false;
25
+
26
+ @property({ type: String }) errorMessage = "";
27
+
28
+ @property({ type: String }) value = "";
29
+
30
+ checked = false;
31
+
32
+ private _onChange: (value: string) => void = () => {};
33
+ private _onTouched: () => void = () => {};
34
+
35
+ static styles = css`
36
+ :host {
37
+ display: block;
38
+ font-family: var(--rel-fontFamilies-primary);
39
+ }
40
+
41
+ .rel-radio-group {
42
+ display: flex;
43
+ flex-direction: column;
44
+ align-items: flex-start;
45
+ gap: var(--rel-spacing-space-xs);
46
+ }
47
+
48
+ .rel-radio-option {
49
+ display: inline-flex;
50
+ flex-direction: column;
51
+ gap: var(--rel-spacing-space-3xs);
52
+ cursor: pointer;
53
+ }
54
+
55
+ .rel-radio-option.disabled {
56
+ opacity: 0.6;
57
+ cursor: not-allowed !important;
58
+ }
59
+
60
+ .rel-radio-option:not(.disabled):hover .radio-custom {
61
+ border-color: #525252;
62
+ }
63
+
64
+ .rel-radio-option:not(.disabled):hover .radio-label {
65
+ color: #525252;
66
+ }
67
+
68
+ .rel-radio-option:not(.disabled):hover .radio-supporting {
69
+ color: #7D7D7D;
70
+ }
71
+
72
+ .rel-radio-option:focus-within:has(input:focus-visible) {
73
+ outline: 1.5px solid #000000;
74
+ outline-offset: 1px;
75
+ }
76
+
77
+ .radio-main {
78
+ display: flex;
79
+ align-items: center;
80
+ gap: var(--rel-spacing-space-2xs);
81
+ }
82
+
83
+ input {
84
+ position: absolute;
85
+ opacity: 0;
86
+ pointer-events: none;
87
+ }
88
+
89
+ .radio-custom {
90
+ width: 20px;
91
+ height: 20px;
92
+ border: 2px solid var(--rel-color-text-heading);
93
+ border-radius: 50%;
94
+ position: relative;
95
+ flex-shrink: 0;
96
+ }
97
+
98
+ input:checked + .radio-custom::after {
99
+ content: "";
100
+ position: absolute;
101
+ inset: 4px;
102
+ background: var(--rel-color-text-heading);
103
+ border-radius: 50%;
104
+ }
105
+
106
+ .radio-label {
107
+ font-size: var(--rel-fontSizes-md, 16px);
108
+ font-weight: var(--rel-fontWeights-medium);
109
+ color: var(--rel-color-text-primary);
110
+ }
111
+
112
+ .radio-supporting {
113
+ font-size: var(--rel-fontSizes-sm, 12px);
114
+ margin-left: 28px;
115
+ color: #7D7D7D;
116
+ }
117
+
118
+ /* Error state — unchecked only */
119
+ .rel-radio-option.error-unchecked .radio-custom {
120
+ border-color: #CE3131;
121
+ }
122
+
123
+ .rel-radio-option.error-unchecked .radio-label {
124
+ color: #CE3131;
125
+ }
126
+
127
+ .rel-radio-option.error-unchecked .radio-supporting {
128
+ color: #CE3131;
129
+ }
130
+
131
+ /* Error message below group */
132
+ .error-message {
133
+ font-size: var(--rel-fontSizes-sm, 12px);
134
+ color: #CE3131;
135
+ margin-top: var(--rel-spacing-space-2xs, 4px);
136
+ }
137
+
138
+ /* Dark mode hover overrides */
139
+ :host-context([data-theme="dark"]) .rel-radio-option:not(.disabled):hover .radio-custom,
140
+ :host-context(.dark) .rel-radio-option:not(.disabled):hover .radio-custom {
141
+ border-color: var(--rel-color-text-secondary, #D4D4D4);
142
+ }
143
+
144
+ :host-context([data-theme="dark"]) .rel-radio-option:not(.disabled):hover .radio-label,
145
+ :host-context(.dark) .rel-radio-option:not(.disabled):hover .radio-label {
146
+ color: var(--rel-color-text-secondary, #D4D4D4);
147
+ }
148
+
149
+ :host-context([data-theme="dark"]) .rel-radio-option:not(.disabled):hover .radio-supporting,
150
+ :host-context(.dark) .rel-radio-option:not(.disabled):hover .radio-supporting {
151
+ color: var(--rel-color-text-placeholder, #A3A3A3);
152
+ }
153
+
154
+ :host-context([data-theme="dark"]) .rel-radio-option:focus-within:has(input:focus-visible),
155
+ :host-context(.dark) .rel-radio-option:focus-within:has(input:focus-visible) {
156
+ outline: 1.5px solid var(--rel-color-text-primary, #F5F5F5);
157
+ outline-offset: 1px;
158
+ }
159
+ `;
160
+
161
+ private onChange(value: string) {
162
+ if (this.disabled) return;
163
+
164
+ this.selectedValue = value;
165
+ this.dispatchEvent(
166
+ new CustomEvent("rel-change", {
167
+ detail: { value, checked: true },
168
+ bubbles: true,
169
+ composed: true,
170
+ })
171
+ );
172
+ this._onChange(this.value);
173
+ }
174
+
175
+ registerOnChange(fn: (value: string) => void): void { this._onChange = fn; }
176
+ registerOnTouched(fn: () => void): void { this._onTouched = fn; }
177
+ writeValue(value: string): void { this.checked = value === this.value; }
178
+
179
+ private get hasSelection(): boolean {
180
+ return this.selectedValue !== null && this.selectedValue !== "";
181
+ }
182
+
183
+ private renderOption(option: RadioOption) {
184
+ const isChecked = this.selectedValue === option.value;
185
+ const isDisabled = this.disabled || option.disabled;
186
+ const isErrorActive = this.error && !this.hasSelection;
187
+
188
+ const classes = [
189
+ "rel-radio-option",
190
+ isDisabled ? "disabled" : "",
191
+ isErrorActive ? "error-unchecked" : "",
192
+ ]
193
+ .filter(Boolean)
194
+ .join(" ");
195
+
196
+ return html`
197
+ <label class="${classes}">
198
+ <div class="radio-main">
199
+ <input
200
+ type="radio"
201
+ name="${this.name}"
202
+ .checked="${isChecked}"
203
+ ?disabled="${isDisabled}"
204
+ @change="${() => this.onChange(option.value)}"
205
+ @blur="${() => this._onTouched()}"
206
+ />
207
+ <span class="radio-custom"></span>
208
+ <span class="radio-label">${option.label}</span>
209
+ </div>
210
+
211
+ ${option.supportingText
212
+ ? html`<div class="radio-supporting">${option.supportingText}</div>`
213
+ : ""}
214
+ </label>
215
+ `;
216
+ }
217
+
218
+ render() {
219
+ return html`
220
+ <div class="rel-radio-group">
221
+ ${this.options.map((o) => this.renderOption(o))}
222
+ </div>
223
+ ${this.error && this.errorMessage && !this.hasSelection
224
+ ? html`<div class="error-message">${this.errorMessage}</div>`
225
+ : ""}
226
+ `;
227
+ }
228
+ }