@rcarls/rc-segmented-button 0.4.2 → 0.5.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.
- package/CHANGELOG.md +20 -0
- package/dist/custom-elements.json +8 -2
- package/dist/{rc-segmented-button-ixogzL_a.js → rc-segmented-button-COV7INIU.js} +48 -30
- package/dist/rc-segmented-button-COV7INIU.js.map +1 -0
- package/dist/rc-segmented-button-define.js +1 -1
- package/dist/rc-segmented-button.js +1 -1
- package/dist/types/packages/rc-segmented-button/src/rc-segmented-button.d.ts +4 -2
- package/package.json +1 -1
- package/dist/rc-segmented-button-ixogzL_a.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @rcarls/rc-segmented-button
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7c68235: Fix two spacing bugs in the optional selected-icon (checkmark) pattern:
|
|
8
|
+
`--rc-segmented-button-segment-gap` had no fallback value, so there was no
|
|
9
|
+
gap at all between the checkmark and the label text; and the checkmark
|
|
10
|
+
slot was `display: none` when unchecked (zero width, zero gap consumed),
|
|
11
|
+
so a segment's width visibly grew when it became selected.
|
|
12
|
+
|
|
13
|
+
The selected-icon slot now always reserves its width (new
|
|
14
|
+
`--rc-segmented-button-selected-icon-size`, default `1.25em`), toggling
|
|
15
|
+
only `visibility` between checked/unchecked states, with a matching
|
|
16
|
+
pure-CSS mirror spacer on the opposite side (RTL-safe via logical
|
|
17
|
+
`inline-size`) so the label text stays centered instead of leaning toward
|
|
18
|
+
the now-always-reserved leading icon slot. Segment width is now constant
|
|
19
|
+
regardless of selection state. `--rc-segmented-button-segment-gap`
|
|
20
|
+
defaults to `0.5em`. Both changes are backward compatible for consumers
|
|
21
|
+
not using the selected-icon slot at all.
|
|
22
|
+
|
|
3
23
|
## 0.4.2
|
|
4
24
|
|
|
5
25
|
## 0.4.1
|
|
@@ -50,8 +50,14 @@
|
|
|
50
50
|
"name": "RCSegmentedButton",
|
|
51
51
|
"cssProperties": [
|
|
52
52
|
{
|
|
53
|
-
"description": "Gap between segment icon and label content
|
|
54
|
-
"name": "--rc-segmented-button-segment-gap"
|
|
53
|
+
"description": "Gap between segment icon and label content.",
|
|
54
|
+
"name": "--rc-segmented-button-segment-gap",
|
|
55
|
+
"default": "0.5em"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Reserved inline-size of the selected-icon slot (and its opposite-side mirror spacer) — constant regardless of checked state, so segment width doesn't change on selection.",
|
|
59
|
+
"name": "--rc-segmented-button-selected-icon-size",
|
|
60
|
+
"default": "1.25em"
|
|
55
61
|
},
|
|
56
62
|
{
|
|
57
63
|
"description": "Minimum segment block size (defers to native label layout when unset).",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { css as b, LitElement as v, html as
|
|
1
|
+
import { css as b, LitElement as v, html as h } from "lit";
|
|
2
2
|
import { property as o } from "lit/decorators.js";
|
|
3
|
-
const
|
|
3
|
+
const g = b`
|
|
4
4
|
:host {
|
|
5
5
|
display: inline-block;
|
|
6
6
|
color-scheme: inherit;
|
|
@@ -10,12 +10,12 @@ const h = b`
|
|
|
10
10
|
display: none;
|
|
11
11
|
}
|
|
12
12
|
`;
|
|
13
|
-
var f = Object.defineProperty,
|
|
14
|
-
for (var s =
|
|
15
|
-
(d =
|
|
16
|
-
return
|
|
13
|
+
var f = Object.defineProperty, m = Object.getOwnPropertyDescriptor, c = (u, e, t, i) => {
|
|
14
|
+
for (var s = i > 1 ? void 0 : i ? m(e, t) : e, r = u.length - 1, d; r >= 0; r--)
|
|
15
|
+
(d = u[r]) && (s = (i ? d(e, t, s) : d(s)) || s);
|
|
16
|
+
return i && s && f(e, t, s), s;
|
|
17
17
|
};
|
|
18
|
-
const
|
|
18
|
+
const p = `
|
|
19
19
|
@layer rc-base {
|
|
20
20
|
rc-segmented-button > fieldset {
|
|
21
21
|
display: var(--_rc-segmented-button-fieldset-display, revert);
|
|
@@ -46,7 +46,7 @@ const m = `
|
|
|
46
46
|
display: var(--_rc-segmented-button-segment-display, revert);
|
|
47
47
|
align-items: center;
|
|
48
48
|
justify-content: center;
|
|
49
|
-
gap: var(--rc-segmented-button-segment-gap);
|
|
49
|
+
gap: var(--rc-segmented-button-segment-gap, 0.5em);
|
|
50
50
|
min-block-size: var(--rc-segmented-button-segment-min-block-size);
|
|
51
51
|
padding-block: var(--rc-segmented-button-segment-padding-block, revert);
|
|
52
52
|
padding-inline: var(--rc-segmented-button-segment-padding-inline, revert);
|
|
@@ -113,25 +113,43 @@ const m = `
|
|
|
113
113
|
pointer-events: var(--_rc-segmented-button-radio-pointer-events, revert);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/* Always reserved (never display:none) so a segment's width doesn't
|
|
117
|
+
change between checked/unchecked — only visibility toggles. A fixed
|
|
118
|
+
inline-size keeps the reserved width deterministic regardless of the
|
|
119
|
+
icon's own intrinsic size. */
|
|
116
120
|
rc-segmented-button > fieldset > label > [data-rc-segmented-button-selected-icon] {
|
|
117
|
-
display:
|
|
121
|
+
display: var(--_rc-segmented-button-selected-icon-display, inline-grid);
|
|
122
|
+
inline-size: var(--rc-segmented-button-selected-icon-size, 1.25em);
|
|
123
|
+
place-items: center;
|
|
124
|
+
visibility: hidden;
|
|
118
125
|
}
|
|
119
126
|
|
|
120
127
|
rc-segmented-button > fieldset > label:has(input[type='radio']:checked) > [data-rc-segmented-button-selected-icon] {
|
|
121
|
-
|
|
122
|
-
|
|
128
|
+
visibility: visible;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Mirrors the selected-icon slot's reserved width on the opposite side,
|
|
132
|
+
so the label text stays centered instead of leaning toward the
|
|
133
|
+
always-reserved leading icon slot. Logical inline-size + scoping via
|
|
134
|
+
:has() (only labels that opt into the checkmark pattern get a mirror)
|
|
135
|
+
keeps this RTL-correct and backward compatible for consumers not
|
|
136
|
+
using the selected-icon slot at all. */
|
|
137
|
+
rc-segmented-button > fieldset > label:has([data-rc-segmented-button-selected-icon])::after {
|
|
138
|
+
content: '';
|
|
139
|
+
inline-size: var(--rc-segmented-button-selected-icon-size, 1.25em);
|
|
140
|
+
visibility: hidden;
|
|
123
141
|
}
|
|
124
142
|
}
|
|
125
143
|
`;
|
|
126
|
-
var
|
|
127
|
-
const l = (
|
|
144
|
+
var n;
|
|
145
|
+
const l = (n = class extends v {
|
|
128
146
|
constructor() {
|
|
129
147
|
super(...arguments), this._value = "", this._defaultValue = "", this._valueInitialized = !1, this._$fieldset = null, this._disabledOwned = !1, this._slotMicrotaskQueued = !1, this.disabled = !1, this.orientation = "horizontal", this._handleChange = (e) => {
|
|
130
148
|
const t = e.target;
|
|
131
149
|
if (!(t instanceof HTMLInputElement) || t.type !== "radio" || !t.checked)
|
|
132
150
|
return;
|
|
133
|
-
const
|
|
134
|
-
this._value = t.value, this._valueInitialized = !0, this.requestUpdate("value",
|
|
151
|
+
const i = this.value;
|
|
152
|
+
this._value = t.value, this._valueInitialized = !0, this.requestUpdate("value", i), this.dispatchEvent(
|
|
135
153
|
new CustomEvent("rc-segmented-button-change", {
|
|
136
154
|
bubbles: !0,
|
|
137
155
|
composed: !0,
|
|
@@ -142,19 +160,19 @@ const l = (i = class extends v {
|
|
|
142
160
|
const t = e.target;
|
|
143
161
|
if (!(t instanceof HTMLInputElement) || t.type !== "radio" || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)
|
|
144
162
|
return;
|
|
145
|
-
const
|
|
163
|
+
const i = this.orientation === "vertical" ? ["ArrowDown"] : ["ArrowRight", "ArrowDown"], s = this.orientation === "vertical" ? ["ArrowUp"] : ["ArrowLeft", "ArrowUp"], r = this._$enabledRadios(), d = r.indexOf(t);
|
|
146
164
|
if (d === -1)
|
|
147
165
|
return;
|
|
148
166
|
let a;
|
|
149
|
-
|
|
167
|
+
i.includes(e.key) ? a = r[(d + 1) % r.length] : s.includes(e.key) ? a = r[(d - 1 + r.length) % r.length] : e.key === "Home" ? a = r[0] : e.key === "End" && (a = r[r.length - 1]), a && (e.preventDefault(), a.focus(), a.checked = !0, a.dispatchEvent(new Event("change", { bubbles: !0 })));
|
|
150
168
|
};
|
|
151
169
|
}
|
|
152
170
|
static _ensureBaseStyles(e) {
|
|
153
|
-
if (
|
|
171
|
+
if (n._styledRoots.has(e))
|
|
154
172
|
return;
|
|
155
|
-
|
|
173
|
+
n._styledRoots.add(e);
|
|
156
174
|
const t = document.createElement("style");
|
|
157
|
-
t.setAttribute("data-rc-light-dom-base", "rc-segmented-button"), t.textContent =
|
|
175
|
+
t.setAttribute("data-rc-light-dom-base", "rc-segmented-button"), t.textContent = p, e instanceof Document ? e.head.append(t) : e.append(t);
|
|
158
176
|
}
|
|
159
177
|
get value() {
|
|
160
178
|
return this._value || this._defaultValue;
|
|
@@ -171,7 +189,7 @@ const l = (i = class extends v {
|
|
|
171
189
|
this._defaultValue = e, !this._valueInitialized && !this._value && (this._applyValue(!1), this.requestUpdate("value", t)), this.requestUpdate("defaultValue", t);
|
|
172
190
|
}
|
|
173
191
|
connectedCallback() {
|
|
174
|
-
super.connectedCallback(),
|
|
192
|
+
super.connectedCallback(), n._ensureBaseStyles(this.getRootNode());
|
|
175
193
|
}
|
|
176
194
|
disconnectedCallback() {
|
|
177
195
|
this._$fieldset?.removeEventListener("change", this._handleChange), this._$fieldset?.removeEventListener("keydown", this._handleKeyDown), super.disconnectedCallback();
|
|
@@ -183,7 +201,7 @@ const l = (i = class extends v {
|
|
|
183
201
|
e.has("disabled") && this._applyDisabled();
|
|
184
202
|
}
|
|
185
203
|
render() {
|
|
186
|
-
return
|
|
204
|
+
return h`<slot @slotchange=${this._handleSlotChange}></slot>`;
|
|
187
205
|
}
|
|
188
206
|
_handleSlotChange() {
|
|
189
207
|
this._slotMicrotaskQueued || (this._slotMicrotaskQueued = !0, queueMicrotask(() => {
|
|
@@ -213,29 +231,29 @@ const l = (i = class extends v {
|
|
|
213
231
|
return this._$radios.filter((e) => !e.disabled && !this.disabled);
|
|
214
232
|
}
|
|
215
233
|
_applyValue(e) {
|
|
216
|
-
const t = this._$radios,
|
|
234
|
+
const t = this._$radios, i = this.value;
|
|
217
235
|
for (const s of t)
|
|
218
|
-
s.checked = s.value ===
|
|
236
|
+
s.checked = s.value === i;
|
|
219
237
|
}
|
|
220
238
|
_applyDisabled() {
|
|
221
239
|
const e = this._$fieldset;
|
|
222
240
|
e && (this.disabled ? (e.disabled || (this._disabledOwned = !0), e.disabled = !0) : this._disabledOwned && (e.disabled = !1, this._disabledOwned = !1));
|
|
223
241
|
}
|
|
224
|
-
},
|
|
225
|
-
|
|
242
|
+
}, n.styles = g, n._styledRoots = /* @__PURE__ */ new Set(), n);
|
|
243
|
+
c([
|
|
226
244
|
o({ type: String, reflect: !0 })
|
|
227
245
|
], l.prototype, "value", 1);
|
|
228
|
-
|
|
246
|
+
c([
|
|
229
247
|
o({ type: String, attribute: "default-value" })
|
|
230
248
|
], l.prototype, "defaultValue", 1);
|
|
231
|
-
|
|
249
|
+
c([
|
|
232
250
|
o({ type: Boolean, reflect: !0 })
|
|
233
251
|
], l.prototype, "disabled", 2);
|
|
234
|
-
|
|
252
|
+
c([
|
|
235
253
|
o({ type: String, reflect: !0 })
|
|
236
254
|
], l.prototype, "orientation", 2);
|
|
237
255
|
let w = l;
|
|
238
256
|
export {
|
|
239
257
|
w as R
|
|
240
258
|
};
|
|
241
|
-
//# sourceMappingURL=rc-segmented-button-
|
|
259
|
+
//# sourceMappingURL=rc-segmented-button-COV7INIU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rc-segmented-button-COV7INIU.js","sources":["../src/rc-segmented-button.styles.ts","../src/rc-segmented-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const segmentedButtonStyles = css`\n :host {\n display: inline-block;\n color-scheme: inherit;\n }\n\n :host([hidden]) {\n display: none;\n }\n`;\n\nexport default segmentedButtonStyles;\n","import { LitElement, html } from 'lit';\nimport type { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport segmentedButtonStyles from './rc-segmented-button.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-segmented-button': RCSegmentedButton;\n }\n\n interface HTMLElementEventMap {\n 'rc-segmented-button-change': CustomEvent<RCSegmentedButtonChangeDetail>;\n }\n}\n\nconst LIGHT_DOM_CSS = `\n@layer rc-base {\n rc-segmented-button > fieldset {\n display: var(--_rc-segmented-button-fieldset-display, revert);\n margin: var(--_rc-segmented-button-fieldset-margin, revert);\n padding: var(--_rc-segmented-button-fieldset-padding, revert);\n border: var(--_rc-segmented-button-fieldset-border, revert);\n border-radius: var(--_rc-segmented-button-fieldset-radius, revert);\n overflow: var(--_rc-segmented-button-fieldset-overflow, revert);\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset {\n flex-direction: column;\n }\n\n rc-segmented-button > fieldset > legend {\n position: var(--_rc-segmented-button-legend-position, revert);\n inline-size: var(--_rc-segmented-button-legend-inline-size, revert);\n block-size: var(--_rc-segmented-button-legend-block-size, revert);\n margin: var(--_rc-segmented-button-legend-margin, revert);\n padding: var(--_rc-segmented-button-legend-padding, revert);\n border: var(--_rc-segmented-button-legend-border, revert);\n overflow: var(--_rc-segmented-button-legend-overflow, revert);\n clip: var(--_rc-segmented-button-legend-clip, revert);\n white-space: var(--_rc-segmented-button-legend-white-space, revert);\n }\n\n rc-segmented-button > fieldset > label {\n display: var(--_rc-segmented-button-segment-display, revert);\n align-items: center;\n justify-content: center;\n gap: var(--rc-segmented-button-segment-gap, 0.5em);\n min-block-size: var(--rc-segmented-button-segment-min-block-size);\n padding-block: var(--rc-segmented-button-segment-padding-block, revert);\n padding-inline: var(--rc-segmented-button-segment-padding-inline, revert);\n border: var(--rc-segmented-button-border, revert);\n color: var(--rc-segmented-button-color, revert);\n background: var(--rc-segmented-button-bg, revert);\n cursor: var(--_rc-segmented-button-segment-cursor, revert);\n user-select: var(--_rc-segmented-button-segment-user-select, revert);\n }\n\n rc-segmented-button > fieldset > label:first-of-type {\n border-start-start-radius: var(--rc-segmented-button-radius, revert);\n border-end-start-radius: var(--rc-segmented-button-radius, revert);\n }\n\n rc-segmented-button > fieldset > label:last-of-type {\n border-start-end-radius: var(--rc-segmented-button-radius, revert);\n border-end-end-radius: var(--rc-segmented-button-radius, revert);\n }\n\n rc-segmented-button > fieldset > label + label {\n border-inline-start: var(--rc-segmented-button-divider, revert);\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset > label + label {\n border-inline-start: var(--_rc-segmented-button-vertical-border-inline-start, revert);\n border-block-start: var(--rc-segmented-button-divider, revert);\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset > label:first-of-type {\n border-start-start-radius: var(--rc-segmented-button-radius, revert);\n border-start-end-radius: var(--rc-segmented-button-radius, revert);\n border-end-start-radius: 0;\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset > label:last-of-type {\n border-start-end-radius: 0;\n border-end-start-radius: var(--rc-segmented-button-radius, revert);\n border-end-end-radius: var(--rc-segmented-button-radius, revert);\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:checked) {\n color: var(--rc-segmented-button-selected-color, revert);\n background: var(--rc-segmented-button-selected-bg, revert);\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:focus-visible) {\n outline: var(--rc-segmented-button-focus-ring, revert);\n outline-offset: var(--rc-segmented-button-focus-ring-offset, revert);\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:disabled),\n rc-segmented-button[disabled] > fieldset > label {\n opacity: var(--rc-segmented-button-disabled-opacity, revert);\n cursor: var(--_rc-segmented-button-disabled-cursor, revert);\n }\n\n rc-segmented-button > fieldset > label > input[type='radio'] {\n position: var(--_rc-segmented-button-radio-position, revert);\n inline-size: var(--_rc-segmented-button-radio-inline-size, revert);\n block-size: var(--_rc-segmented-button-radio-block-size, revert);\n margin: var(--_rc-segmented-button-radio-margin, revert);\n opacity: var(--_rc-segmented-button-radio-opacity, revert);\n pointer-events: var(--_rc-segmented-button-radio-pointer-events, revert);\n }\n\n /* Always reserved (never display:none) so a segment's width doesn't\n change between checked/unchecked — only visibility toggles. A fixed\n inline-size keeps the reserved width deterministic regardless of the\n icon's own intrinsic size. */\n rc-segmented-button > fieldset > label > [data-rc-segmented-button-selected-icon] {\n display: var(--_rc-segmented-button-selected-icon-display, inline-grid);\n inline-size: var(--rc-segmented-button-selected-icon-size, 1.25em);\n place-items: center;\n visibility: hidden;\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:checked) > [data-rc-segmented-button-selected-icon] {\n visibility: visible;\n }\n\n /* Mirrors the selected-icon slot's reserved width on the opposite side,\n so the label text stays centered instead of leaning toward the\n always-reserved leading icon slot. Logical inline-size + scoping via\n :has() (only labels that opt into the checkmark pattern get a mirror)\n keeps this RTL-correct and backward compatible for consumers not\n using the selected-icon slot at all. */\n rc-segmented-button > fieldset > label:has([data-rc-segmented-button-selected-icon])::after {\n content: '';\n inline-size: var(--rc-segmented-button-selected-icon-size, 1.25em);\n visibility: hidden;\n }\n}\n`;\n\n/** Detail payload for `rc-segmented-button-change`. */\nexport interface RCSegmentedButtonChangeDetail {\n /** Current selected radio value after user interaction. */\n value: string;\n}\n\n/**\n * Segmented button group that enhances a direct native `<fieldset>` of radio inputs.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-segmented-button rc-segmented-button docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/radio/ WAI-ARIA radio group pattern}\n *\n * @slot - A direct `<fieldset>` containing native radio inputs and labels.\n *\n * @fires rc-segmented-button-change - Fired after user interaction changes the selected value.\n *\n * @attr value - Current selected radio value. Host writes are silent.\n * @attr default-value - Initial selected value for uncontrolled usage.\n * @attr disabled - Mirrors disabled state to the native fieldset.\n * @attr orientation - Keyboard orientation: `horizontal` or `vertical`.\n *\n * @cssprop [--rc-segmented-button-segment-gap=0.5em] - Gap between segment icon and label content.\n * @cssprop [--rc-segmented-button-selected-icon-size=1.25em] - Reserved inline-size of the\n * selected-icon slot (and its opposite-side mirror spacer) — constant regardless of checked\n * state, so segment width doesn't change on selection.\n * @cssprop [--rc-segmented-button-segment-min-block-size] - Minimum segment block size (defers\n * to native label layout when unset).\n * @cssprop [--rc-segmented-button-segment-padding-block=revert] - Segment block-axis padding\n * (defers to native label padding when unset).\n * @cssprop [--rc-segmented-button-segment-padding-inline=revert] - Segment inline-axis padding\n * (defers to native label padding when unset).\n * @cssprop [--rc-segmented-button-border=revert] - Segment border (defers to native label border\n * when unset).\n * @cssprop [--rc-segmented-button-color=revert] - Segment text color (defers to native label\n * color when unset).\n * @cssprop [--rc-segmented-button-bg=revert] - Segment background (defers to native label\n * background when unset).\n * @cssprop [--rc-segmented-button-radius=revert] - Rounded corner radius on the first and last\n * segments (defers to native label styling when unset).\n * @cssprop [--rc-segmented-button-divider=revert] - Border between adjacent segments (defers to\n * native label styling when unset).\n * @cssprop [--rc-segmented-button-selected-color=revert] - Segment text color when its radio is\n * checked (defers to native label color when unset).\n * @cssprop [--rc-segmented-button-selected-bg=revert] - Segment background when its radio is\n * checked (defers to native label background when unset).\n * @cssprop [--rc-segmented-button-focus-ring=revert] - Segment outline when its radio is\n * focus-visible (defers to native focus styling when unset).\n * @cssprop [--rc-segmented-button-focus-ring-offset=revert] - Segment outline offset when its\n * radio is focus-visible (defers to native focus styling when unset).\n * @cssprop [--rc-segmented-button-disabled-opacity=revert] - Segment opacity when its radio is\n * disabled, or when the host is `disabled` (defers to native disabled styling when unset).\n */\nexport class RCSegmentedButton extends LitElement {\n static override styles = segmentedButtonStyles;\n\n private static readonly _styledRoots = new Set<Document | ShadowRoot>();\n\n private static _ensureBaseStyles(root: Document | ShadowRoot): void {\n if (RCSegmentedButton._styledRoots.has(root)) {\n return;\n }\n\n RCSegmentedButton._styledRoots.add(root);\n\n const style = document.createElement('style');\n\n style.setAttribute('data-rc-light-dom-base', 'rc-segmented-button');\n style.textContent = LIGHT_DOM_CSS;\n\n if (root instanceof Document) {\n root.head.append(style);\n } else {\n root.append(style);\n }\n }\n\n private _value = '';\n private _defaultValue = '';\n private _valueInitialized = false;\n private _$fieldset: HTMLFieldSetElement | null = null;\n private _disabledOwned = false;\n private _slotMicrotaskQueued = false;\n\n /** Current selected radio value. Host writes are silent. */\n @property({ type: String, reflect: true })\n get value(): string {\n return this._value || this._defaultValue;\n }\n\n set value(value: string | undefined) {\n const oldValue = this.value;\n\n this._value = value ?? '';\n this._valueInitialized = true;\n this._applyValue(false);\n this.requestUpdate('value', oldValue);\n }\n\n /** Initial selected value for uncontrolled usage. */\n @property({ type: String, attribute: 'default-value' })\n get defaultValue(): string {\n return this._defaultValue;\n }\n\n set defaultValue(value: string) {\n const oldValue = this._defaultValue;\n\n this._defaultValue = value;\n\n if (!this._valueInitialized && !this._value) {\n this._applyValue(false);\n this.requestUpdate('value', oldValue);\n }\n\n this.requestUpdate('defaultValue', oldValue);\n }\n\n /** Mirror disabled state to the native fieldset. */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Keyboard orientation. */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n override connectedCallback(): void {\n super.connectedCallback();\n RCSegmentedButton._ensureBaseStyles(this.getRootNode() as Document | ShadowRoot);\n }\n\n override disconnectedCallback(): void {\n this._$fieldset?.removeEventListener('change', this._handleChange);\n this._$fieldset?.removeEventListener('keydown', this._handleKeyDown);\n super.disconnectedCallback();\n }\n\n protected override firstUpdated(): void {\n this._syncFieldset();\n }\n\n protected override updated(changed: PropertyValues<this>): void {\n if (changed.has('disabled')) {\n this._applyDisabled();\n }\n }\n\n protected override render() {\n return html`<slot @slotchange=${this._handleSlotChange}></slot>`;\n }\n\n private _handleSlotChange(): void {\n if (this._slotMicrotaskQueued) {\n return;\n }\n\n this._slotMicrotaskQueued = true;\n\n queueMicrotask(() => {\n this._slotMicrotaskQueued = false;\n\n if (this.isConnected) {\n this._syncFieldset();\n }\n });\n }\n\n private _syncFieldset(): void {\n const $nextFieldset = this.querySelector<HTMLFieldSetElement>(':scope > fieldset');\n\n if (!$nextFieldset && import.meta.env.DEV) {\n console.warn(\n '[rc-segmented-button] No direct child <fieldset> found. Place native radio inputs inside a fieldset.',\n this,\n );\n }\n\n if ($nextFieldset === this._$fieldset) {\n this._syncInitialValue();\n this._applyValue(false);\n this._applyDisabled();\n\n return;\n }\n\n this._$fieldset?.removeEventListener('change', this._handleChange);\n this._$fieldset?.removeEventListener('keydown', this._handleKeyDown);\n this._$fieldset = $nextFieldset;\n this._disabledOwned = false;\n\n if ($nextFieldset) {\n $nextFieldset.addEventListener('change', this._handleChange);\n $nextFieldset.addEventListener('keydown', this._handleKeyDown);\n }\n\n this._syncInitialValue();\n this._applyValue(false);\n this._applyDisabled();\n }\n\n private _syncInitialValue(): void {\n if (this._valueInitialized || this._value) {\n return;\n }\n\n const $checked = this._$radios.find(($radio) => $radio.checked);\n\n if ($checked) {\n this._value = $checked.value;\n this._defaultValue = $checked.defaultChecked ? $checked.value : this._defaultValue;\n }\n }\n\n private get _$radios(): HTMLInputElement[] {\n if (!this._$fieldset) {\n return [];\n }\n\n return Array.from(\n this._$fieldset.querySelectorAll<HTMLInputElement>(':scope input[type=\"radio\"]'),\n );\n }\n\n private _$enabledRadios(): HTMLInputElement[] {\n return this._$radios.filter(($radio) => !$radio.disabled && !this.disabled);\n }\n\n private readonly _handleChange = (event: Event): void => {\n const $target = event.target;\n\n if (!($target instanceof HTMLInputElement) || $target.type !== 'radio' || !$target.checked) {\n return;\n }\n\n const oldValue = this.value;\n\n this._value = $target.value;\n this._valueInitialized = true;\n this.requestUpdate('value', oldValue);\n\n this.dispatchEvent(\n new CustomEvent<RCSegmentedButtonChangeDetail>('rc-segmented-button-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n };\n\n private readonly _handleKeyDown = (event: KeyboardEvent): void => {\n const $target = event.target;\n\n if (!($target instanceof HTMLInputElement) || $target.type !== 'radio') {\n return;\n }\n\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return;\n }\n\n const forwardKeys =\n this.orientation === 'vertical' ? ['ArrowDown'] : ['ArrowRight', 'ArrowDown'];\n const backwardKeys = this.orientation === 'vertical' ? ['ArrowUp'] : ['ArrowLeft', 'ArrowUp'];\n const $radios = this._$enabledRadios();\n const currentIndex = $radios.indexOf($target);\n\n if (currentIndex === -1) {\n return;\n }\n\n let $next: HTMLInputElement | undefined;\n\n if (forwardKeys.includes(event.key)) {\n $next = $radios[(currentIndex + 1) % $radios.length];\n } else if (backwardKeys.includes(event.key)) {\n $next = $radios[(currentIndex - 1 + $radios.length) % $radios.length];\n } else if (event.key === 'Home') {\n $next = $radios[0];\n } else if (event.key === 'End') {\n $next = $radios[$radios.length - 1];\n }\n\n if (!$next) {\n return;\n }\n\n event.preventDefault();\n $next.focus();\n $next.checked = true;\n $next.dispatchEvent(new Event('change', { bubbles: true }));\n };\n\n private _applyValue(_writeDefault: boolean): void {\n const $radios = this._$radios;\n const value = this.value;\n\n for (const $radio of $radios) {\n $radio.checked = $radio.value === value;\n }\n }\n\n private _applyDisabled(): void {\n const $fieldset = this._$fieldset;\n\n if (!$fieldset) {\n return;\n }\n\n if (this.disabled) {\n if (!$fieldset.disabled) {\n this._disabledOwned = true;\n }\n\n $fieldset.disabled = true;\n } else if (this._disabledOwned) {\n $fieldset.disabled = false;\n this._disabledOwned = false;\n }\n }\n}\n\nexport default RCSegmentedButton;\n"],"names":["segmentedButtonStyles","css","LIGHT_DOM_CSS","_RCSegmentedButton","_a","LitElement","event","$target","oldValue","forwardKeys","backwardKeys","$radios","currentIndex","$next","root","style","value","changed","html","$nextFieldset","$checked","$radio","_writeDefault","$fieldset","__decorateClass","property","RCSegmentedButton"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { R as e } from "./rc-segmented-button-
|
|
1
|
+
import { R as e } from "./rc-segmented-button-COV7INIU.js";
|
|
2
2
|
customElements.get("rc-segmented-button") || customElements.define("rc-segmented-button", e);
|
|
3
3
|
//# sourceMappingURL=rc-segmented-button-define.js.map
|
|
@@ -27,8 +27,10 @@ export interface RCSegmentedButtonChangeDetail {
|
|
|
27
27
|
* @attr disabled - Mirrors disabled state to the native fieldset.
|
|
28
28
|
* @attr orientation - Keyboard orientation: `horizontal` or `vertical`.
|
|
29
29
|
*
|
|
30
|
-
* @cssprop [--rc-segmented-button-segment-gap] - Gap between segment icon and label content
|
|
31
|
-
*
|
|
30
|
+
* @cssprop [--rc-segmented-button-segment-gap=0.5em] - Gap between segment icon and label content.
|
|
31
|
+
* @cssprop [--rc-segmented-button-selected-icon-size=1.25em] - Reserved inline-size of the
|
|
32
|
+
* selected-icon slot (and its opposite-side mirror spacer) — constant regardless of checked
|
|
33
|
+
* state, so segment width doesn't change on selection.
|
|
32
34
|
* @cssprop [--rc-segmented-button-segment-min-block-size] - Minimum segment block size (defers
|
|
33
35
|
* to native label layout when unset).
|
|
34
36
|
* @cssprop [--rc-segmented-button-segment-padding-block=revert] - Segment block-axis padding
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rc-segmented-button-ixogzL_a.js","sources":["../src/rc-segmented-button.styles.ts","../src/rc-segmented-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const segmentedButtonStyles = css`\n :host {\n display: inline-block;\n color-scheme: inherit;\n }\n\n :host([hidden]) {\n display: none;\n }\n`;\n\nexport default segmentedButtonStyles;\n","import { LitElement, html } from 'lit';\nimport type { PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport segmentedButtonStyles from './rc-segmented-button.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-segmented-button': RCSegmentedButton;\n }\n\n interface HTMLElementEventMap {\n 'rc-segmented-button-change': CustomEvent<RCSegmentedButtonChangeDetail>;\n }\n}\n\nconst LIGHT_DOM_CSS = `\n@layer rc-base {\n rc-segmented-button > fieldset {\n display: var(--_rc-segmented-button-fieldset-display, revert);\n margin: var(--_rc-segmented-button-fieldset-margin, revert);\n padding: var(--_rc-segmented-button-fieldset-padding, revert);\n border: var(--_rc-segmented-button-fieldset-border, revert);\n border-radius: var(--_rc-segmented-button-fieldset-radius, revert);\n overflow: var(--_rc-segmented-button-fieldset-overflow, revert);\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset {\n flex-direction: column;\n }\n\n rc-segmented-button > fieldset > legend {\n position: var(--_rc-segmented-button-legend-position, revert);\n inline-size: var(--_rc-segmented-button-legend-inline-size, revert);\n block-size: var(--_rc-segmented-button-legend-block-size, revert);\n margin: var(--_rc-segmented-button-legend-margin, revert);\n padding: var(--_rc-segmented-button-legend-padding, revert);\n border: var(--_rc-segmented-button-legend-border, revert);\n overflow: var(--_rc-segmented-button-legend-overflow, revert);\n clip: var(--_rc-segmented-button-legend-clip, revert);\n white-space: var(--_rc-segmented-button-legend-white-space, revert);\n }\n\n rc-segmented-button > fieldset > label {\n display: var(--_rc-segmented-button-segment-display, revert);\n align-items: center;\n justify-content: center;\n gap: var(--rc-segmented-button-segment-gap);\n min-block-size: var(--rc-segmented-button-segment-min-block-size);\n padding-block: var(--rc-segmented-button-segment-padding-block, revert);\n padding-inline: var(--rc-segmented-button-segment-padding-inline, revert);\n border: var(--rc-segmented-button-border, revert);\n color: var(--rc-segmented-button-color, revert);\n background: var(--rc-segmented-button-bg, revert);\n cursor: var(--_rc-segmented-button-segment-cursor, revert);\n user-select: var(--_rc-segmented-button-segment-user-select, revert);\n }\n\n rc-segmented-button > fieldset > label:first-of-type {\n border-start-start-radius: var(--rc-segmented-button-radius, revert);\n border-end-start-radius: var(--rc-segmented-button-radius, revert);\n }\n\n rc-segmented-button > fieldset > label:last-of-type {\n border-start-end-radius: var(--rc-segmented-button-radius, revert);\n border-end-end-radius: var(--rc-segmented-button-radius, revert);\n }\n\n rc-segmented-button > fieldset > label + label {\n border-inline-start: var(--rc-segmented-button-divider, revert);\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset > label + label {\n border-inline-start: var(--_rc-segmented-button-vertical-border-inline-start, revert);\n border-block-start: var(--rc-segmented-button-divider, revert);\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset > label:first-of-type {\n border-start-start-radius: var(--rc-segmented-button-radius, revert);\n border-start-end-radius: var(--rc-segmented-button-radius, revert);\n border-end-start-radius: 0;\n }\n\n rc-segmented-button[orientation='vertical'] > fieldset > label:last-of-type {\n border-start-end-radius: 0;\n border-end-start-radius: var(--rc-segmented-button-radius, revert);\n border-end-end-radius: var(--rc-segmented-button-radius, revert);\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:checked) {\n color: var(--rc-segmented-button-selected-color, revert);\n background: var(--rc-segmented-button-selected-bg, revert);\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:focus-visible) {\n outline: var(--rc-segmented-button-focus-ring, revert);\n outline-offset: var(--rc-segmented-button-focus-ring-offset, revert);\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:disabled),\n rc-segmented-button[disabled] > fieldset > label {\n opacity: var(--rc-segmented-button-disabled-opacity, revert);\n cursor: var(--_rc-segmented-button-disabled-cursor, revert);\n }\n\n rc-segmented-button > fieldset > label > input[type='radio'] {\n position: var(--_rc-segmented-button-radio-position, revert);\n inline-size: var(--_rc-segmented-button-radio-inline-size, revert);\n block-size: var(--_rc-segmented-button-radio-block-size, revert);\n margin: var(--_rc-segmented-button-radio-margin, revert);\n opacity: var(--_rc-segmented-button-radio-opacity, revert);\n pointer-events: var(--_rc-segmented-button-radio-pointer-events, revert);\n }\n\n rc-segmented-button > fieldset > label > [data-rc-segmented-button-selected-icon] {\n display: none;\n }\n\n rc-segmented-button > fieldset > label:has(input[type='radio']:checked) > [data-rc-segmented-button-selected-icon] {\n display: var(--_rc-segmented-button-selected-icon-display, none);\n place-items: center;\n }\n}\n`;\n\n/** Detail payload for `rc-segmented-button-change`. */\nexport interface RCSegmentedButtonChangeDetail {\n /** Current selected radio value after user interaction. */\n value: string;\n}\n\n/**\n * Segmented button group that enhances a direct native `<fieldset>` of radio inputs.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-segmented-button rc-segmented-button docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/radio/ WAI-ARIA radio group pattern}\n *\n * @slot - A direct `<fieldset>` containing native radio inputs and labels.\n *\n * @fires rc-segmented-button-change - Fired after user interaction changes the selected value.\n *\n * @attr value - Current selected radio value. Host writes are silent.\n * @attr default-value - Initial selected value for uncontrolled usage.\n * @attr disabled - Mirrors disabled state to the native fieldset.\n * @attr orientation - Keyboard orientation: `horizontal` or `vertical`.\n *\n * @cssprop [--rc-segmented-button-segment-gap] - Gap between segment icon and label content\n * (defers to native label layout when unset).\n * @cssprop [--rc-segmented-button-segment-min-block-size] - Minimum segment block size (defers\n * to native label layout when unset).\n * @cssprop [--rc-segmented-button-segment-padding-block=revert] - Segment block-axis padding\n * (defers to native label padding when unset).\n * @cssprop [--rc-segmented-button-segment-padding-inline=revert] - Segment inline-axis padding\n * (defers to native label padding when unset).\n * @cssprop [--rc-segmented-button-border=revert] - Segment border (defers to native label border\n * when unset).\n * @cssprop [--rc-segmented-button-color=revert] - Segment text color (defers to native label\n * color when unset).\n * @cssprop [--rc-segmented-button-bg=revert] - Segment background (defers to native label\n * background when unset).\n * @cssprop [--rc-segmented-button-radius=revert] - Rounded corner radius on the first and last\n * segments (defers to native label styling when unset).\n * @cssprop [--rc-segmented-button-divider=revert] - Border between adjacent segments (defers to\n * native label styling when unset).\n * @cssprop [--rc-segmented-button-selected-color=revert] - Segment text color when its radio is\n * checked (defers to native label color when unset).\n * @cssprop [--rc-segmented-button-selected-bg=revert] - Segment background when its radio is\n * checked (defers to native label background when unset).\n * @cssprop [--rc-segmented-button-focus-ring=revert] - Segment outline when its radio is\n * focus-visible (defers to native focus styling when unset).\n * @cssprop [--rc-segmented-button-focus-ring-offset=revert] - Segment outline offset when its\n * radio is focus-visible (defers to native focus styling when unset).\n * @cssprop [--rc-segmented-button-disabled-opacity=revert] - Segment opacity when its radio is\n * disabled, or when the host is `disabled` (defers to native disabled styling when unset).\n */\nexport class RCSegmentedButton extends LitElement {\n static override styles = segmentedButtonStyles;\n\n private static readonly _styledRoots = new Set<Document | ShadowRoot>();\n\n private static _ensureBaseStyles(root: Document | ShadowRoot): void {\n if (RCSegmentedButton._styledRoots.has(root)) {\n return;\n }\n\n RCSegmentedButton._styledRoots.add(root);\n\n const style = document.createElement('style');\n\n style.setAttribute('data-rc-light-dom-base', 'rc-segmented-button');\n style.textContent = LIGHT_DOM_CSS;\n\n if (root instanceof Document) {\n root.head.append(style);\n } else {\n root.append(style);\n }\n }\n\n private _value = '';\n private _defaultValue = '';\n private _valueInitialized = false;\n private _$fieldset: HTMLFieldSetElement | null = null;\n private _disabledOwned = false;\n private _slotMicrotaskQueued = false;\n\n /** Current selected radio value. Host writes are silent. */\n @property({ type: String, reflect: true })\n get value(): string {\n return this._value || this._defaultValue;\n }\n\n set value(value: string | undefined) {\n const oldValue = this.value;\n\n this._value = value ?? '';\n this._valueInitialized = true;\n this._applyValue(false);\n this.requestUpdate('value', oldValue);\n }\n\n /** Initial selected value for uncontrolled usage. */\n @property({ type: String, attribute: 'default-value' })\n get defaultValue(): string {\n return this._defaultValue;\n }\n\n set defaultValue(value: string) {\n const oldValue = this._defaultValue;\n\n this._defaultValue = value;\n\n if (!this._valueInitialized && !this._value) {\n this._applyValue(false);\n this.requestUpdate('value', oldValue);\n }\n\n this.requestUpdate('defaultValue', oldValue);\n }\n\n /** Mirror disabled state to the native fieldset. */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /** Keyboard orientation. */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n override connectedCallback(): void {\n super.connectedCallback();\n RCSegmentedButton._ensureBaseStyles(this.getRootNode() as Document | ShadowRoot);\n }\n\n override disconnectedCallback(): void {\n this._$fieldset?.removeEventListener('change', this._handleChange);\n this._$fieldset?.removeEventListener('keydown', this._handleKeyDown);\n super.disconnectedCallback();\n }\n\n protected override firstUpdated(): void {\n this._syncFieldset();\n }\n\n protected override updated(changed: PropertyValues<this>): void {\n if (changed.has('disabled')) {\n this._applyDisabled();\n }\n }\n\n protected override render() {\n return html`<slot @slotchange=${this._handleSlotChange}></slot>`;\n }\n\n private _handleSlotChange(): void {\n if (this._slotMicrotaskQueued) {\n return;\n }\n\n this._slotMicrotaskQueued = true;\n\n queueMicrotask(() => {\n this._slotMicrotaskQueued = false;\n\n if (this.isConnected) {\n this._syncFieldset();\n }\n });\n }\n\n private _syncFieldset(): void {\n const $nextFieldset = this.querySelector<HTMLFieldSetElement>(':scope > fieldset');\n\n if (!$nextFieldset && import.meta.env.DEV) {\n console.warn(\n '[rc-segmented-button] No direct child <fieldset> found. Place native radio inputs inside a fieldset.',\n this,\n );\n }\n\n if ($nextFieldset === this._$fieldset) {\n this._syncInitialValue();\n this._applyValue(false);\n this._applyDisabled();\n\n return;\n }\n\n this._$fieldset?.removeEventListener('change', this._handleChange);\n this._$fieldset?.removeEventListener('keydown', this._handleKeyDown);\n this._$fieldset = $nextFieldset;\n this._disabledOwned = false;\n\n if ($nextFieldset) {\n $nextFieldset.addEventListener('change', this._handleChange);\n $nextFieldset.addEventListener('keydown', this._handleKeyDown);\n }\n\n this._syncInitialValue();\n this._applyValue(false);\n this._applyDisabled();\n }\n\n private _syncInitialValue(): void {\n if (this._valueInitialized || this._value) {\n return;\n }\n\n const $checked = this._$radios.find(($radio) => $radio.checked);\n\n if ($checked) {\n this._value = $checked.value;\n this._defaultValue = $checked.defaultChecked ? $checked.value : this._defaultValue;\n }\n }\n\n private get _$radios(): HTMLInputElement[] {\n if (!this._$fieldset) {\n return [];\n }\n\n return Array.from(\n this._$fieldset.querySelectorAll<HTMLInputElement>(':scope input[type=\"radio\"]'),\n );\n }\n\n private _$enabledRadios(): HTMLInputElement[] {\n return this._$radios.filter(($radio) => !$radio.disabled && !this.disabled);\n }\n\n private readonly _handleChange = (event: Event): void => {\n const $target = event.target;\n\n if (!($target instanceof HTMLInputElement) || $target.type !== 'radio' || !$target.checked) {\n return;\n }\n\n const oldValue = this.value;\n\n this._value = $target.value;\n this._valueInitialized = true;\n this.requestUpdate('value', oldValue);\n\n this.dispatchEvent(\n new CustomEvent<RCSegmentedButtonChangeDetail>('rc-segmented-button-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n };\n\n private readonly _handleKeyDown = (event: KeyboardEvent): void => {\n const $target = event.target;\n\n if (!($target instanceof HTMLInputElement) || $target.type !== 'radio') {\n return;\n }\n\n if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n return;\n }\n\n const forwardKeys =\n this.orientation === 'vertical' ? ['ArrowDown'] : ['ArrowRight', 'ArrowDown'];\n const backwardKeys = this.orientation === 'vertical' ? ['ArrowUp'] : ['ArrowLeft', 'ArrowUp'];\n const $radios = this._$enabledRadios();\n const currentIndex = $radios.indexOf($target);\n\n if (currentIndex === -1) {\n return;\n }\n\n let $next: HTMLInputElement | undefined;\n\n if (forwardKeys.includes(event.key)) {\n $next = $radios[(currentIndex + 1) % $radios.length];\n } else if (backwardKeys.includes(event.key)) {\n $next = $radios[(currentIndex - 1 + $radios.length) % $radios.length];\n } else if (event.key === 'Home') {\n $next = $radios[0];\n } else if (event.key === 'End') {\n $next = $radios[$radios.length - 1];\n }\n\n if (!$next) {\n return;\n }\n\n event.preventDefault();\n $next.focus();\n $next.checked = true;\n $next.dispatchEvent(new Event('change', { bubbles: true }));\n };\n\n private _applyValue(_writeDefault: boolean): void {\n const $radios = this._$radios;\n const value = this.value;\n\n for (const $radio of $radios) {\n $radio.checked = $radio.value === value;\n }\n }\n\n private _applyDisabled(): void {\n const $fieldset = this._$fieldset;\n\n if (!$fieldset) {\n return;\n }\n\n if (this.disabled) {\n if (!$fieldset.disabled) {\n this._disabledOwned = true;\n }\n\n $fieldset.disabled = true;\n } else if (this._disabledOwned) {\n $fieldset.disabled = false;\n this._disabledOwned = false;\n }\n }\n}\n\nexport default RCSegmentedButton;\n"],"names":["segmentedButtonStyles","css","LIGHT_DOM_CSS","_RCSegmentedButton","_a","LitElement","event","$target","oldValue","forwardKeys","backwardKeys","$radios","currentIndex","$next","root","style","value","changed","html","$nextFieldset","$checked","$radio","_writeDefault","$fieldset","__decorateClass","property","RCSegmentedButton"],"mappings":"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"}
|