@m3e/segmented-button 1.0.0-rc.1 → 1.0.0-rc.2

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.
@@ -1,208 +0,0 @@
1
- import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
2
- import { customElement, property } from "lit/decorators.js";
3
-
4
- import {
5
- AttachInternals,
6
- DesignToken,
7
- Dirty,
8
- Disabled,
9
- FormAssociated,
10
- formValue,
11
- Labelled,
12
- Role,
13
- Touched,
14
- } from "@m3e/core";
15
-
16
- import { SelectionManager, selectionManager } from "@m3e/core/a11y";
17
-
18
- import { M3eButtonSegmentElement } from "./ButtonSegmentElement";
19
-
20
- /**
21
- * @summary
22
- * A button that allows a user to select from a limited set of options.
23
- *
24
- * @description
25
- * The `m3e-segmented-button` component allows users to select one or more options from a horizontal group.
26
- * Each segment behaves like a toggle-able button, supporting icon and label content, selection state, and
27
- * accessibility roles. Built with Material Design 3 principles, it adapts shape, color, and ripple feedback
28
- * based on interaction state and input modality. Segments are visually unified but independently interactive.
29
- *
30
- * @example
31
- * The following example illustrates a single-select segmented button with four segments.
32
- * ```html
33
- * <m3e-segmented-button>
34
- * <m3e-button-segment checked>8 oz</m3e-button-segment>
35
- * <m3e-button-segment>12 oz</m3e-button-segment>
36
- * <m3e-button-segment>16 oz</m3e-button-segment>
37
- * <m3e-button-segment>20 oz</m3e-button-segment>
38
- * </m3e-segmented-button>
39
- * ```
40
- * @example
41
- * The next example illustrates a multiselect segmented button designated using the `multi` attribute.
42
- * ```html
43
- * <m3e-segmented-button multi>
44
- * <m3e-button-segment checked>$</m3e-button-segment>
45
- * <m3e-button-segment checked>$$</m3e-button-segment>
46
- * <m3e-button-segment>$$$</m3e-button-segment>
47
- * <m3e-button-segment>$$$$</m3e-button-segment>
48
- * </m3e-segmented-button>
49
- * ```
50
- *
51
- * @tag m3e-segmented-button
52
- *
53
- * @slot - Renders the segments of the button.
54
- *
55
- * @attr disabled - Whether the element is disabled.
56
- * @attr hide-selection-indicator - Whether to hide the selection indicator.
57
- * @attr multi - Whether multiple options can be selected.
58
- * @attr name - The name that identifies the element when submitting the associated form.
59
- *
60
- * @fires input - Emitted when the checked state of a segment changes.
61
- * @fires change - Emitted when the checked state of a segment changes.
62
- *
63
- * @cssprop --m3e-segmented-button-start-shape - Border radius for the first segment in a segmented button.
64
- * @cssprop --m3e-segmented-button-end-shape - Border radius for the last segment in a segmented button.
65
- */
66
- @customElement("m3e-segmented-button")
67
- export class M3eSegmentedButtonElement extends Labelled(
68
- Dirty(Touched(FormAssociated(Disabled(AttachInternals(Role(LitElement, "radiogroup"))))))
69
- ) {
70
- /** The styles of the element. */
71
- static override styles: CSSResultGroup = css`
72
- :host {
73
- display: inline-flex;
74
- vertical-align: middle;
75
- align-items: center;
76
- }
77
- ::slotted(:first-child) {
78
- border-radius: var(
79
- --m3e-segmented-button-start-shape,
80
- ${DesignToken.shape.corner.full} ${DesignToken.shape.corner.none} ${DesignToken.shape.corner.none}
81
- ${DesignToken.shape.corner.full}
82
- );
83
- }
84
- ::slotted(:last-child) {
85
- border-radius: var(
86
- --m3e-segmented-button-end-shape,
87
- ${DesignToken.shape.corner.none} ${DesignToken.shape.corner.full} ${DesignToken.shape.corner.full}
88
- ${DesignToken.shape.corner.none}
89
- );
90
- }
91
- ::slotted(:not(:first-child)) {
92
- --_segmented-button-left-border: none;
93
- }
94
- `;
95
-
96
- /** @internal */
97
- readonly [selectionManager] = new SelectionManager<M3eButtonSegmentElement>()
98
- .withWrap()
99
- .onActiveItemChange(() => this[selectionManager].activeItem?.click());
100
-
101
- /**
102
- * Whether multiple options can be selected.
103
- * @default false
104
- */
105
- @property({ type: Boolean }) multi = false;
106
-
107
- /**
108
- * Whether to hide the selection indicator.
109
- * @default false
110
- */
111
- @property({ attribute: "hide-selection-indicator", type: Boolean }) hideSelectionIndicator = false;
112
-
113
- /** The segments of the button. */
114
- get segments(): readonly M3eButtonSegmentElement[] {
115
- return this[selectionManager]?.items ?? [];
116
- }
117
-
118
- /** The selected segment(s) of the button. */
119
- get selected(): readonly M3eButtonSegmentElement[] {
120
- return this[selectionManager]?.selectedItems ?? [];
121
- }
122
-
123
- /** The selected value(s) of the button. */
124
- get value(): string | readonly string[] | null {
125
- const values = this.selected.map((x) => x.value);
126
- switch (values.length) {
127
- case 0:
128
- return null;
129
- case 1:
130
- return values[0];
131
- default:
132
- return values;
133
- }
134
- }
135
-
136
- /** @inheritdoc @internal */
137
- override get [formValue]() {
138
- const values = this.value;
139
- if (Array.isArray(values)) {
140
- const data = new FormData();
141
- for (const value of values) {
142
- data.append(this.name, value);
143
- }
144
- return data;
145
- }
146
- return <string | null>values;
147
- }
148
-
149
- /** @inheritdoc */
150
- override connectedCallback(): void {
151
- super.connectedCallback();
152
- this[selectionManager].multi = this.multi;
153
- this[selectionManager].disableRovingTabIndex(this.multi);
154
- }
155
-
156
- /** @inheritdoc */
157
- protected override update(changedProperties: PropertyValues<this>): void {
158
- super.update(changedProperties);
159
-
160
- if (changedProperties.has("disabled") && (changedProperties.get("disabled") !== undefined || this.disabled)) {
161
- this[selectionManager].disabled = this.disabled;
162
- }
163
-
164
- if (changedProperties.has("multi")) {
165
- this.role = this.multi ? "group" : "radiogroup";
166
- this[selectionManager].multi = this.multi;
167
- this[selectionManager].disableRovingTabIndex(this.multi);
168
- }
169
-
170
- if (changedProperties.has("hideSelectionIndicator")) {
171
- this.segments.forEach((x) => x.classList.toggle("-hide-selection", this.hideSelectionIndicator));
172
- }
173
- }
174
-
175
- /** @inheritdoc */
176
- protected override render(): unknown {
177
- return html`<slot
178
- @slotchange="${this.#handleSlotChange}"
179
- @keydown="${this.#handleKeyDown}"
180
- @change="${this.#handleChange}"
181
- ></slot>`;
182
- }
183
-
184
- /** @private */
185
- #handleSlotChange() {
186
- const { added } = this[selectionManager].setItems([...this.querySelectorAll("m3e-button-segment")]);
187
- added.forEach((x) => x.classList.toggle("-hide-selection", this.hideSelectionIndicator));
188
- }
189
-
190
- /** @private */
191
- #handleKeyDown(e: KeyboardEvent): void {
192
- if (!this.multi) {
193
- this[selectionManager].onKeyDown(e);
194
- }
195
- }
196
-
197
- /** @private */
198
- #handleChange(e: Event): void {
199
- e.stopPropagation();
200
- this.dispatchEvent(new Event("change", { bubbles: true }));
201
- }
202
- }
203
-
204
- declare global {
205
- interface HTMLElementTagNameMap {
206
- "m3e-segmented-button": M3eSegmentedButtonElement;
207
- }
208
- }
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./ButtonSegmentElement";
2
- export * from "./SegmentedButtonElement";
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist/src"
6
- },
7
- "include": ["src/**/*.ts", "**/*.mjs", "**/*.js"],
8
- "exclude": []
9
- }