@fluid-topics/ft-switch 0.1.8

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/README.md ADDED
@@ -0,0 +1,22 @@
1
+ two-state
2
+
3
+ ## Install
4
+
5
+ ```shell
6
+ npm install @fluid-topics/ft-switch
7
+ yarn add @fluid-topics/ft-switch
8
+ ```
9
+
10
+ ## Usage
11
+
12
+ ```typescript
13
+ import { html } from "lit"
14
+ import "@fluid-topics/ft-switch"
15
+
16
+ function render() {
17
+ return html` <ft-switch>
18
+ <ft-switch-option value="on">on</ft-switch-option>
19
+ <ft-switch-option value="off">off</ft-switch-option>
20
+ </ft-switch>`
21
+ }
22
+ ```
@@ -0,0 +1,47 @@
1
+ import { ElementDefinitionsMap, FtCssVariable, FtLitElement } from "@fluid-topics/ft-wc-utils";
2
+ import { Position } from "@fluid-topics/ft-tooltip";
3
+ export interface FtSwitchOptionProperties {
4
+ value: string;
5
+ icon?: string;
6
+ selected: boolean;
7
+ trailingIcon: boolean;
8
+ }
9
+ export declare const FtSwitchOptionCssVariables: {
10
+ borderRadiusLeft: FtCssVariable;
11
+ borderRadiusRight: FtCssVariable;
12
+ borderWidthLeft: FtCssVariable;
13
+ borderWidthRight: FtCssVariable;
14
+ borderWidthVertical: FtCssVariable;
15
+ };
16
+ export declare class SwitchOptionSelected extends CustomEvent<void> {
17
+ constructor();
18
+ }
19
+ export declare class FtSwitchOption extends FtLitElement implements FtSwitchOptionProperties {
20
+ static elementDefinitions: ElementDefinitionsMap;
21
+ static shadowRootOptions: {
22
+ delegatesFocus: boolean;
23
+ mode: ShadowRootMode;
24
+ slotAssignment?: SlotAssignmentMode | undefined;
25
+ customElements?: CustomElementRegistry | undefined;
26
+ };
27
+ protected getStyles(): import("lit").CSSResult;
28
+ value: string;
29
+ icon?: string;
30
+ label: string;
31
+ tooltipPosition: Position;
32
+ selected: boolean;
33
+ trailingIcon: boolean;
34
+ name: string;
35
+ private slottedContent?;
36
+ private input;
37
+ focus(): void;
38
+ protected getTemplate(): import("lit-html").TemplateResult<1>;
39
+ private addTooltip;
40
+ private onChange;
41
+ private getLabel;
42
+ private resolveIcon;
43
+ get textContent(): string;
44
+ private hasTextContent;
45
+ private onSlotchange;
46
+ }
47
+ //# sourceMappingURL=ft-switch-option.d.ts.map
@@ -0,0 +1,231 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { css, html, LitElement, nothing } from "lit";
8
+ import { property, query } from "lit/decorators.js";
9
+ import { customElement, designSystemVariables, FtCssVariable, FtLitElement, setVariable } from "@fluid-topics/ft-wc-utils";
10
+ import { FtRipple, FtRippleCssVariables } from "@fluid-topics/ft-ripple";
11
+ import { FtTypography, FtTypographyButtonCssVariables } from "@fluid-topics/ft-typography";
12
+ import { Icon } from "@material/mwc-icon";
13
+ import { classMap } from "lit/directives/class-map.js";
14
+ import { FtSwitchCssVariables } from "./ft-switch";
15
+ import { FtTooltip } from "@fluid-topics/ft-tooltip";
16
+ export const FtSwitchOptionCssVariables = {
17
+ borderRadiusLeft: FtCssVariable.extend("--ft-switch-option-border-radius-left", designSystemVariables.borderRadiusL),
18
+ borderRadiusRight: FtCssVariable.extend("--ft-switch-option-border-radius-right", designSystemVariables.borderRadiusL),
19
+ borderWidthLeft: FtCssVariable.create("--ft-switch-option-border-width-left", "SIZE", "1px"),
20
+ borderWidthRight: FtCssVariable.create("--ft-switch-option-border-width-right", "SIZE", "1px"),
21
+ borderWidthVertical: FtCssVariable.create("--ft-switch-option-border-width-vertical", "SIZE", "1px"),
22
+ };
23
+ export class SwitchOptionSelected extends CustomEvent {
24
+ constructor() {
25
+ super("selected");
26
+ }
27
+ }
28
+ let FtSwitchOption = class FtSwitchOption extends FtLitElement {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.value = "";
32
+ this.label = "";
33
+ this.tooltipPosition = "bottom";
34
+ this.selected = false;
35
+ this.trailingIcon = false;
36
+ this.name = "";
37
+ }
38
+ getStyles() {
39
+ // language=CSS
40
+ return css `
41
+ .ft-switch-option {
42
+ position: relative;
43
+ display: inline-block;
44
+ }
45
+
46
+ .ft-switch-option--input {
47
+ position: absolute;
48
+ opacity: 0;
49
+ width: 0;
50
+ height: 0;
51
+ }
52
+
53
+ .ft-switch-option--content {
54
+ --ft-switch-option-internal-line-height: calc(${FtSwitchCssVariables.fontSize} + 2px);
55
+ --ft-switch-option-internal-content-height: max(var(--ft-switch-option-internal-line-height), ${FtSwitchCssVariables.iconSize});
56
+
57
+ border-style: solid;
58
+ border-color: ${FtSwitchCssVariables.borderColor};
59
+ border-width: ${FtSwitchOptionCssVariables.borderWidthVertical} ${FtSwitchOptionCssVariables.borderWidthRight} ${FtSwitchOptionCssVariables.borderWidthVertical} ${FtSwitchOptionCssVariables.borderWidthLeft};
60
+ border-radius: ${FtSwitchOptionCssVariables.borderRadiusLeft} ${FtSwitchOptionCssVariables.borderRadiusRight} ${FtSwitchOptionCssVariables.borderRadiusRight} ${FtSwitchOptionCssVariables.borderRadiusLeft};
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ overflow: hidden;
65
+
66
+ --mdc-icon-size: ${FtSwitchCssVariables.iconSize};
67
+ padding: 6px 8px;
68
+ background-color: ${FtSwitchCssVariables.backgroundColor};
69
+ -webkit-mask-image: radial-gradient(white, black);
70
+ }
71
+
72
+ .ft-switch-option--input:checked + .ft-switch-option--content:before {
73
+ background-color: ${FtSwitchCssVariables.selectedBackgroundColor};
74
+ border-radius: ${FtSwitchOptionCssVariables.borderRadiusLeft} ${FtSwitchOptionCssVariables.borderRadiusRight} ${FtSwitchOptionCssVariables.borderRadiusRight} ${FtSwitchOptionCssVariables.borderRadiusLeft};
75
+ position: absolute;
76
+ inset: 0;
77
+ content: "";
78
+ z-index: 1;
79
+ opacity: ${designSystemVariables.opacityPrimaryOnSurfaceSelected};
80
+ }
81
+
82
+ .ft-switch-option--input:focus + .ft-switch-option--content:before {
83
+ background-color: ${FtSwitchCssVariables.selectedBackgroundColor};
84
+ border-radius: ${FtSwitchOptionCssVariables.borderRadiusLeft} ${FtSwitchOptionCssVariables.borderRadiusRight} ${FtSwitchOptionCssVariables.borderRadiusRight} ${FtSwitchOptionCssVariables.borderRadiusLeft};
85
+ position: absolute;
86
+ inset: 0;
87
+ content: "";
88
+ z-index: 1;
89
+ opacity: ${designSystemVariables.opacityPrimaryOnSurfaceFocused};
90
+ }
91
+
92
+ .ft-switch-option--label {
93
+ color: ${FtSwitchCssVariables.textColor};
94
+ overflow: hidden;
95
+ white-space: nowrap;
96
+ text-overflow: ellipsis;
97
+ display: block;
98
+ margin: 0 8px;
99
+ ${setVariable(FtTypographyButtonCssVariables.fontSize, FtSwitchCssVariables.fontSize)};
100
+ ${setVariable(FtTypographyButtonCssVariables.lineHeight, "var(--ft-switch-option-internal-content-height)")}
101
+ }
102
+
103
+ .ft-switch-option--input:checked + .ft-switch-option--content .ft-switch-option--label {
104
+ color: ${FtSwitchCssVariables.selectedTextColor};
105
+ }
106
+
107
+ .ft-switch-option--label[hidden] {
108
+ display: none;
109
+ }
110
+
111
+ .ft-switch-option--ripple {
112
+ ${setVariable(FtRippleCssVariables.color, FtSwitchCssVariables.rippleColor)};
113
+ }
114
+
115
+ mwc-icon, ft-ripple, ft-typography {
116
+ z-index: 2;
117
+ }
118
+
119
+ .ft-switch-option:not(.ft-switch-option--trailing-icon) mwc-icon {
120
+ order: -1;
121
+ }
122
+
123
+ mwc-icon {
124
+ flex-shrink: 0;
125
+ width: var(--mdc-icon-size);
126
+ color: ${FtSwitchCssVariables.iconColor};
127
+ }
128
+
129
+ .ft-switch-option--input:checked + .ft-switch-option--content mwc-icon {
130
+ color: ${FtSwitchCssVariables.selectedTextColor};
131
+ }
132
+ `;
133
+ }
134
+ focus() {
135
+ this.input.focus();
136
+ }
137
+ getTemplate() {
138
+ const classes = {
139
+ "ft-switch-option": true,
140
+ "ft-switch-option--trailing-icon": this.trailingIcon,
141
+ };
142
+ return this.addTooltip(html `
143
+ <label for="input" class=${classMap(classes)}>
144
+ <input id="input" type="radio" class="ft-switch-option--input"
145
+ .checked=${this.selected}
146
+ .value=${this.value}
147
+ .name=${this.name}
148
+ @change=${this.onChange}>
149
+ <div class="ft-switch-option--content">
150
+ <ft-ripple part="ripple" class="ft-switch-option--ripple"></ft-ripple>
151
+ <ft-typography variant="button" ?hidden=${!this.hasTextContent()}
152
+ class="ft-switch-option--label">
153
+ <slot @slotchange=${this.onSlotchange}></slot>
154
+ </ft-typography>
155
+ ${this.resolveIcon()}
156
+ </div>
157
+ </label>
158
+ `);
159
+ }
160
+ addTooltip(label) {
161
+ return this.hasTextContent() || this.getLabel().trim().length === 0 ? label : html `
162
+ <ft-tooltip part="tooltip"
163
+ text="${this.getLabel()}"
164
+ position="${this.tooltipPosition}">
165
+ ${label}
166
+ </ft-tooltip>
167
+ `;
168
+ }
169
+ onChange() {
170
+ this.selected = true;
171
+ this.dispatchEvent(new SwitchOptionSelected());
172
+ }
173
+ getLabel() {
174
+ return this.label || this.textContent;
175
+ }
176
+ resolveIcon() {
177
+ return this.icon
178
+ ? html `
179
+ <mwc-icon>${this.icon}</mwc-icon> `
180
+ : nothing;
181
+ }
182
+ get textContent() {
183
+ var _a, _b;
184
+ return (_b = (_a = this.slottedContent) === null || _a === void 0 ? void 0 : _a.assignedNodes().map(n => n.textContent).join("").trim()) !== null && _b !== void 0 ? _b : "";
185
+ }
186
+ hasTextContent() {
187
+ return this.textContent.length > 0;
188
+ }
189
+ onSlotchange() {
190
+ this.requestUpdate();
191
+ }
192
+ };
193
+ FtSwitchOption.elementDefinitions = {
194
+ "ft-ripple": FtRipple,
195
+ "ft-typography": FtTypography,
196
+ "ft-tooltip": FtTooltip,
197
+ "mwc-icon": Icon
198
+ };
199
+ FtSwitchOption.shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true };
200
+ __decorate([
201
+ property({ type: String })
202
+ ], FtSwitchOption.prototype, "value", void 0);
203
+ __decorate([
204
+ property({ type: String })
205
+ ], FtSwitchOption.prototype, "icon", void 0);
206
+ __decorate([
207
+ property({ type: String })
208
+ ], FtSwitchOption.prototype, "label", void 0);
209
+ __decorate([
210
+ property({ type: String })
211
+ ], FtSwitchOption.prototype, "tooltipPosition", void 0);
212
+ __decorate([
213
+ property({ type: Boolean, reflect: true })
214
+ ], FtSwitchOption.prototype, "selected", void 0);
215
+ __decorate([
216
+ property({ type: Boolean })
217
+ ], FtSwitchOption.prototype, "trailingIcon", void 0);
218
+ __decorate([
219
+ property({ attribute: false })
220
+ ], FtSwitchOption.prototype, "name", void 0);
221
+ __decorate([
222
+ query(".ft-switch-option--content slot")
223
+ ], FtSwitchOption.prototype, "slottedContent", void 0);
224
+ __decorate([
225
+ query(".ft-switch-option--input")
226
+ ], FtSwitchOption.prototype, "input", void 0);
227
+ FtSwitchOption = __decorate([
228
+ customElement("ft-switch-option")
229
+ ], FtSwitchOption);
230
+ export { FtSwitchOption };
231
+ //# sourceMappingURL=ft-switch-option.js.map
@@ -0,0 +1,38 @@
1
+ import { ElementDefinitionsMap, FtCssVariable, FtLitElement } from "@fluid-topics/ft-wc-utils";
2
+ export * from "./ft-switch-option";
3
+ export interface FtSwitchProperties {
4
+ value?: string;
5
+ }
6
+ export declare const FtSwitchCssVariables: {
7
+ textColor: FtCssVariable;
8
+ backgroundColor: FtCssVariable;
9
+ selectedTextColor: FtCssVariable;
10
+ selectedBackgroundColor: FtCssVariable;
11
+ borderColor: FtCssVariable;
12
+ borderRadius: FtCssVariable;
13
+ fontSize: FtCssVariable;
14
+ iconSize: FtCssVariable;
15
+ iconColor: FtCssVariable;
16
+ rippleColor: FtCssVariable;
17
+ };
18
+ export declare class FtSwitchChange extends CustomEvent<string> {
19
+ constructor(value: string);
20
+ }
21
+ export declare class FtSwitch extends FtLitElement implements FtSwitchProperties {
22
+ static elementDefinitions: ElementDefinitionsMap;
23
+ constructor();
24
+ get value(): string | undefined;
25
+ private slottedContent?;
26
+ private selectedOption?;
27
+ private options;
28
+ private groupName;
29
+ protected getStyles(): import("lit").CSSResult;
30
+ protected getTemplate(): import("lit-html").TemplateResult<1>;
31
+ private onKeyDown;
32
+ private onFocus;
33
+ private onSlotchange;
34
+ private registerOption;
35
+ private selectOption;
36
+ private updateOptions;
37
+ }
38
+ //# sourceMappingURL=ft-switch.d.ts.map
@@ -0,0 +1,142 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { css, html } from "lit";
8
+ import { query } from "lit/decorators.js";
9
+ import { v4 as uuidv4 } from "uuid";
10
+ import { customElement, designSystemVariables, FtCssVariable, FtLitElement, setVariable } from "@fluid-topics/ft-wc-utils";
11
+ import { FtSwitchOption, FtSwitchOptionCssVariables } from "./ft-switch-option";
12
+ import { FtTypographyButtonCssVariables } from "@fluid-topics/ft-typography";
13
+ export * from "./ft-switch-option";
14
+ export const FtSwitchCssVariables = {
15
+ textColor: FtCssVariable.extend("--ft-switch-text-color", designSystemVariables.colorOnSurfaceHigh),
16
+ backgroundColor: FtCssVariable.extend("--ft-switch-background-color", designSystemVariables.colorSurface),
17
+ selectedTextColor: FtCssVariable.extend("--ft-switch-selected-text-color", designSystemVariables.colorPrimary),
18
+ selectedBackgroundColor: FtCssVariable.extend("--ft-switch-selected-background-color", designSystemVariables.colorPrimary),
19
+ borderColor: FtCssVariable.extend("--ft-switch-border-color", designSystemVariables.colorOutline),
20
+ borderRadius: FtCssVariable.extend("--ft-switch-border-radius", designSystemVariables.borderRadiusL),
21
+ fontSize: FtCssVariable.extend("--ft-switch-font-size", FtTypographyButtonCssVariables.fontSize),
22
+ iconSize: FtCssVariable.create("--ft-switch-icon-size", "SIZE", "24px"),
23
+ iconColor: FtCssVariable.extend("--ft-switch-text-color", designSystemVariables.colorOnSurfaceMedium),
24
+ rippleColor: FtCssVariable.extend("--ft-switch-ripple-color", designSystemVariables.colorPrimary),
25
+ };
26
+ export class FtSwitchChange extends CustomEvent {
27
+ constructor(value) {
28
+ super("change", { detail: value });
29
+ }
30
+ }
31
+ let FtSwitch = class FtSwitch extends FtLitElement {
32
+ constructor() {
33
+ super();
34
+ this.options = [];
35
+ this.groupName = uuidv4();
36
+ this.addEventListener("keydown", (e) => this.onKeyDown(e));
37
+ }
38
+ get value() {
39
+ var _a;
40
+ return (_a = this.selectedOption) === null || _a === void 0 ? void 0 : _a.value;
41
+ }
42
+ getStyles() {
43
+ // language=CSS
44
+ return css `
45
+ :host {
46
+ display: inline-block;
47
+ }
48
+
49
+ .ft-switch slot {
50
+ display: flex;
51
+ align-items: center;
52
+ }
53
+
54
+ .ft-switch slot::slotted(ft-switch-option) {
55
+ ${setVariable(FtSwitchOptionCssVariables.borderRadiusLeft, "0")};
56
+ ${setVariable(FtSwitchOptionCssVariables.borderRadiusRight, "0")};
57
+ ${setVariable(FtSwitchOptionCssVariables.borderWidthLeft, "0")};
58
+ }
59
+
60
+ .ft-switch slot::slotted(ft-switch-option:first-child) {
61
+ ${setVariable(FtSwitchOptionCssVariables.borderRadiusLeft, FtSwitchCssVariables.borderRadius)};
62
+ ${setVariable(FtSwitchOptionCssVariables.borderWidthLeft, "1px")};
63
+ }
64
+
65
+ .ft-switch slot::slotted(ft-switch-option:last-child) {
66
+ ${setVariable(FtSwitchOptionCssVariables.borderRadiusRight, FtSwitchCssVariables.borderRadius)};
67
+ }
68
+ `;
69
+ }
70
+ getTemplate() {
71
+ return html `
72
+ <div class="ft-switch">
73
+ <slot @slotchange=${this.onSlotchange}></slot>
74
+ </div>
75
+ `;
76
+ }
77
+ onKeyDown(e) {
78
+ let focusedOption = this.options.find(option => option.ownerDocument.activeElement == option);
79
+ if (focusedOption) {
80
+ if (e.key == "ArrowDown" || e.key == "ArrowRight") {
81
+ let optionIndex = this.options.indexOf(focusedOption);
82
+ if (optionIndex < this.options.length - 1) {
83
+ optionIndex++;
84
+ }
85
+ e.preventDefault();
86
+ this.selectOption(this.options[optionIndex]);
87
+ }
88
+ if (e.key == "ArrowUp" || e.key == "ArrowLeft") {
89
+ let optionIndex = this.options.indexOf(focusedOption);
90
+ if (optionIndex > 0) {
91
+ optionIndex--;
92
+ }
93
+ e.preventDefault();
94
+ this.selectOption(this.options[optionIndex]);
95
+ }
96
+ }
97
+ }
98
+ onFocus(option) {
99
+ if (this.selectedOption && this.selectedOption != option) {
100
+ this.selectedOption.focus();
101
+ }
102
+ }
103
+ onSlotchange() {
104
+ var _a;
105
+ this.options = [];
106
+ return (_a = this.slottedContent) === null || _a === void 0 ? void 0 : _a.assignedElements().forEach(element => {
107
+ if (element instanceof FtSwitchOption) {
108
+ this.registerOption(element);
109
+ }
110
+ this.updateOptions();
111
+ });
112
+ }
113
+ registerOption(option) {
114
+ option.name = this.groupName;
115
+ option.addEventListener("selected", () => this.selectOption(option));
116
+ option.addEventListener("focus", () => this.onFocus(option));
117
+ if (option.selected) {
118
+ this.selectedOption = option;
119
+ }
120
+ this.options.push(option);
121
+ }
122
+ selectOption(option) {
123
+ this.selectedOption = option;
124
+ option.focus();
125
+ this.dispatchEvent(new FtSwitchChange(this.selectedOption.value));
126
+ this.updateOptions();
127
+ }
128
+ updateOptions() {
129
+ this.options.forEach(option => {
130
+ option.selected = option == this.selectedOption;
131
+ });
132
+ }
133
+ };
134
+ FtSwitch.elementDefinitions = {};
135
+ __decorate([
136
+ query(".ft-switch slot")
137
+ ], FtSwitch.prototype, "slottedContent", void 0);
138
+ FtSwitch = __decorate([
139
+ customElement("ft-switch")
140
+ ], FtSwitch);
141
+ export { FtSwitch };
142
+ //# sourceMappingURL=ft-switch.js.map