@mustib/web-components 0.0.0-alpha.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.
@@ -0,0 +1,305 @@
1
+ import { M as MUElement, _ as __decorate, g as getElementBoundaries } from '../mu-element-CZDI_RCY.js';
2
+ import { css, html } from 'lit';
3
+ import { state, property, query } from 'lit/decorators.js';
4
+ import { MuRangeThumbValue } from './mu-range-thumb-value.js';
5
+ import { MuTransparent } from './mu-transparent.js';
6
+ import '../decorators.js';
7
+
8
+ class MuRangeThumb extends MUElement {
9
+ get range() {
10
+ return this._range;
11
+ }
12
+ set range(value) {
13
+ if (this._isRangeReady.resolved && (value[0] > this.minValue || value[1] < this.maxValue)) {
14
+ console.warn(`range must not be less than max value (${this.maxValue}) or greater than min value (${this.minValue}), but got (${value})`, this);
15
+ return;
16
+ }
17
+ if (!this._isRangeReady.resolved)
18
+ this._isRangeReady.resolve();
19
+ this._range = value;
20
+ }
21
+ constructor() {
22
+ super();
23
+ this.eventActionData = undefined;
24
+ this._addEventActionAttributes = undefined;
25
+ /**
26
+ * A set of related mu-range-thumb-value elements
27
+ */
28
+ this._valueElements = new Set();
29
+ this._isRangeReady = this.generateIsReadyPromise({
30
+ onTimeout: () => {
31
+ console.warn('range not set for mu-range-thumb, switching to default value [0, 100]', this);
32
+ this.range = [0, 100];
33
+ },
34
+ });
35
+ this.axis = 'x';
36
+ /**
37
+ * The current value of the thumb.
38
+ */
39
+ this.value = 0;
40
+ this.step = 1;
41
+ /**
42
+ * A boolean indicates if the thumb is focused.
43
+ *
44
+ * for internal use only by mu-range
45
+ */
46
+ this.focused = false;
47
+ /**
48
+ * A string indicates how range handles other thumbs intersecting with with thumb.
49
+ *
50
+ * `prevent` is the default behavior, and it means do not allow other thumbs intersecting this thumb to pass.
51
+ *
52
+ * `pass-over` means allow other thumbs to pass over this thumb so they can have a free movement.
53
+ */
54
+ this.intersectBehavior = 'prevent';
55
+ /**
56
+ * A boolean indicates if the thumb should be completely ignored when interacting with the range.
57
+ *
58
+ * When `true`, the thumb will not be active when the user interacts with the range, and other non-transparent thumbs will be active instead.
59
+ *
60
+ * It's like setting `readonly` or `disabled` on the thumb, but instead of nothing being active, other thumbs will be active.
61
+ */
62
+ this.transparent = false;
63
+ /**
64
+ * A boolean indicates if the thumb should force the step when interacting with the range.
65
+ */
66
+ this.forceStep = false;
67
+ this._slotChangeHandler = () => {
68
+ this._valueElements.clear();
69
+ const addElement = (el) => {
70
+ if (el instanceof MuRangeThumbValue) {
71
+ this._valueElements.add(el);
72
+ }
73
+ };
74
+ this.renderRoot.querySelector('slot')?.assignedElements({ flatten: true }).forEach(el => {
75
+ if (el instanceof MuTransparent) {
76
+ el.contents.forEach(addElement);
77
+ }
78
+ else {
79
+ addElement(el);
80
+ }
81
+ });
82
+ this._updateValueElements();
83
+ this.updateValueElementsAxis();
84
+ };
85
+ this.updateComplete.then(() => {
86
+ this.setAttribute('role', 'slider');
87
+ this.addEventListener('mu-transparent-slotchange', this._slotChangeHandler);
88
+ });
89
+ }
90
+ /**
91
+ * returns an object containing the width and height of the thumb
92
+ */
93
+ get size() {
94
+ const { container } = this;
95
+ let width = 0;
96
+ let height = 0;
97
+ if (container) {
98
+ const boundaries = getElementBoundaries(container);
99
+ width = boundaries.width;
100
+ height = boundaries.height;
101
+ }
102
+ return { width, height };
103
+ }
104
+ connectedCallback() {
105
+ super.connectedCallback();
106
+ this._isRangeReady.promise.then(() => {
107
+ if (this.minValue === undefined) {
108
+ this.minValue = this.range[0];
109
+ }
110
+ if (this.maxValue === undefined) {
111
+ this.maxValue = this.range[1];
112
+ }
113
+ if (this.value === undefined) {
114
+ this.setValueFromPercentage(50);
115
+ }
116
+ });
117
+ }
118
+ /**
119
+ * Updates the value of related mu-range-thumb-value elements
120
+ */
121
+ _updateValueElements() {
122
+ if (this._valueElements.size === 0)
123
+ return;
124
+ this._valueElements.forEach(el => {
125
+ el.setValue({
126
+ value: this.value,
127
+ percentage: this.getPercentageFromValue(this.value)
128
+ });
129
+ });
130
+ }
131
+ async getUpdateComplete() {
132
+ const result = await super.getUpdateComplete();
133
+ await this._isRangeReady.promise;
134
+ return result;
135
+ }
136
+ /**
137
+ * Returns a boolean indicating if the value is valid to be set.
138
+ */
139
+ isValidValue(value) {
140
+ const isValid = value <= this.maxValue && value >= this.minValue;
141
+ return isValid;
142
+ }
143
+ /**
144
+ * Sets the value of the thumb and returns a boolean indicating if the value was changed.
145
+ * @param value The value to set
146
+ * @returns A boolean indicating if the value was changed
147
+ */
148
+ setValue(value) {
149
+ if (this.isValidValue(value)) {
150
+ this.value = value;
151
+ return true;
152
+ }
153
+ return false;
154
+ }
155
+ /**
156
+ * Sets the value of the thumb from a percentage and returns a boolean indicating if the value was changed.
157
+ * @param percentage The percentage to set
158
+ * @returns A boolean indicating if the value was changed
159
+ */
160
+ setValueFromPercentage(percentage) {
161
+ const value = ((percentage / 100) * (this.range[1] - this.range[0])) + this.range[0];
162
+ return this.setValue(value);
163
+ }
164
+ /**
165
+ * Converts a given value to a percentage based on the current range and returns it.
166
+ */
167
+ getPercentageFromValue(value) {
168
+ return ((value) / (this.range[1] - this.range[0])) * 100;
169
+ }
170
+ /**
171
+ * Updates the axis of related mu-range-thumb-value elements
172
+ */
173
+ updateValueElementsAxis() {
174
+ this._valueElements.forEach(el => el.setAxis(this.axis === 'x' || this.axis === '-x' ? 'x' : 'y'));
175
+ }
176
+ async updated(_changedProperties) {
177
+ await this.updateComplete;
178
+ if (_changedProperties.has('axis')) {
179
+ this.updateValueElementsAxis();
180
+ this.ariaOrientation = this.axis === '-y' || this.axis === 'y' ? 'vertical' : 'horizontal';
181
+ }
182
+ if (_changedProperties.has('value')) {
183
+ if (!this.isValidValue(this.value)) {
184
+ console.warn(`value attribute must not be greater than max value (${this.maxValue}) or less than min value (${this.minValue}), but got (${this.value})`, this);
185
+ }
186
+ this.style.setProperty('--mu-range-thumb-percentage', `${this.getPercentageFromValue(this.value)}%`);
187
+ this.setAttribute('aria-valuenow', `${this.value}`);
188
+ this._updateValueElements();
189
+ }
190
+ if (_changedProperties.has('minValue') || _changedProperties.has('maxValue')) {
191
+ this.setAttribute('aria-valuemin', `${this.minValue}`);
192
+ this.setAttribute('aria-valuemax', `${this.maxValue}`);
193
+ if (this.minValue > this.maxValue) {
194
+ console.warn(`minValue attribute must not be greater than maxValue attribute, but got (${this.minValue}, ${this.maxValue})`, this);
195
+ }
196
+ else if (this.minValue < this.range[0] || this.maxValue > this.range[1]) {
197
+ console.warn(`minValue (${this.minValue}) and maxValue (${this.maxValue}) attributes must be equal to or in the range of range property (${this.range})`, this);
198
+ }
199
+ }
200
+ }
201
+ render() {
202
+ return html `
203
+ <div id='container' part='container' axis='${this.axis}'>
204
+ <slot @slotchange=${this._slotChangeHandler}></slot>
205
+ </div>
206
+ `;
207
+ }
208
+ }
209
+ MuRangeThumb.styles = [MUElement.cssBase, css `
210
+ #container {
211
+ --thumb-size: var(--mu-range-thumb-size, calc(var(--range-thickness) * 3));
212
+ --range-thumb-background-color: var(--mu-range-thumb-background-color, var(--mu-color-500));
213
+ --range-thumb-shadow: var(--mu-range-thumb-shadow, 0 0 calc(var(--thumb-size) * .2) hsl(from var(--range-thumb-background-color) h s calc(l * .25)));
214
+ --position: clamp(0px, calc(var(--mu-range-thumb-percentage) - (var(--thumb-size) / 2)) , calc(100% - var(--thumb-size))) !important;
215
+ position: absolute;
216
+ border-radius: 9999px;
217
+ transition: all 50ms ease-in;
218
+ width: var(--thumb-size);
219
+ aspect-ratio: 1;
220
+ background-color: var(--range-thumb-background-color);
221
+ user-select: none;
222
+ box-shadow: var(--range-thumb-shadow);
223
+ z-index: 1;
224
+ }
225
+
226
+
227
+ :host([focused]) #container {
228
+ ${MUElement.css.focus};
229
+ }
230
+
231
+ #container[axis='x'] {
232
+ left: var(--position);
233
+ top: 50%;
234
+ transform: translateY(-50%);
235
+ }
236
+
237
+ #container[axis='-x'] {
238
+ left: unset;
239
+ top: 50%;
240
+ right: var(--position);
241
+ transform: translateY(-50%);
242
+ }
243
+
244
+ #container[axis='y'] {
245
+ top: unset;
246
+ bottom: var(--position);
247
+ left: 50%;
248
+ transform: translateX(-50%);
249
+ }
250
+
251
+ #container[axis='-y'] {
252
+ bottom: unset;
253
+ top: var(--position);
254
+ left: 50%;
255
+ transform: translateX(-50%);
256
+ }
257
+ `];
258
+ __decorate([
259
+ state()
260
+ ], MuRangeThumb.prototype, "axis", void 0);
261
+ __decorate([
262
+ property({
263
+ reflect: true,
264
+ type: Number,
265
+ attribute: 'min-value'
266
+ })
267
+ ], MuRangeThumb.prototype, "minValue", void 0);
268
+ __decorate([
269
+ property({
270
+ reflect: true,
271
+ type: Number,
272
+ attribute: 'max-value'
273
+ })
274
+ ], MuRangeThumb.prototype, "maxValue", void 0);
275
+ __decorate([
276
+ property({
277
+ reflect: true,
278
+ type: Number,
279
+ attribute: 'value'
280
+ })
281
+ ], MuRangeThumb.prototype, "value", void 0);
282
+ __decorate([
283
+ property({ reflect: true, type: Number, })
284
+ ], MuRangeThumb.prototype, "step", void 0);
285
+ __decorate([
286
+ property()
287
+ ], MuRangeThumb.prototype, "name", void 0);
288
+ __decorate([
289
+ property({ type: Boolean, reflect: true })
290
+ ], MuRangeThumb.prototype, "focused", void 0);
291
+ __decorate([
292
+ property({ attribute: 'intersect-behavior' })
293
+ ], MuRangeThumb.prototype, "intersectBehavior", void 0);
294
+ __decorate([
295
+ property()
296
+ ], MuRangeThumb.prototype, "transparent", void 0);
297
+ __decorate([
298
+ property({ attribute: 'force-step', type: Boolean })
299
+ ], MuRangeThumb.prototype, "forceStep", void 0);
300
+ __decorate([
301
+ query('#container', true)
302
+ ], MuRangeThumb.prototype, "container", void 0);
303
+ MuRangeThumb.register('mu-range-thumb');
304
+
305
+ export { MuRangeThumb };
@@ -0,0 +1,206 @@
1
+ import { CSSResultGroup, PropertyValues } from 'lit';
2
+ import { MUElement } from './mu-element.js';
3
+ import { MuRangeThumb } from './mu-range-thumb.js';
4
+ import { MuRangeFill } from './mu-range-fill.js';
5
+ import '@mustib/utils/browser';
6
+ import './mu-range-thumb-value.js';
7
+
8
+ type RangeThumb = {
9
+ element: MuRangeThumb;
10
+ linkedFillElements: RangeFill[] | undefined;
11
+ value: number;
12
+ index: number;
13
+ name: string;
14
+ };
15
+ type RangeFill = {
16
+ element: MuRangeFill;
17
+ linkedThumbs: RangeThumb[];
18
+ };
19
+ type Events = {
20
+ /**
21
+ * Emitted when pointerdown on a non-thumb element and empty-area attribute has a value of "dispatch".
22
+ *
23
+ * This can be used to dynamically add thumbs.
24
+ */
25
+ 'mu-range-empty-area': CustomEvent<{
26
+ values: ReturnType<MuRange['_getValuesFromEvent']>;
27
+ }>;
28
+ /**
29
+ * Emitted when the value of the range changes.
30
+ */
31
+ 'mu-range-change': CustomEvent<{
32
+ data: {
33
+ name: string;
34
+ value: number;
35
+ }[];
36
+ }>;
37
+ /**
38
+ * Emitted when new thumbs are added after the initial render.
39
+ */
40
+ 'mu-range-added-thumbs': CustomEvent<{
41
+ data: {
42
+ name: string;
43
+ value: number;
44
+ }[];
45
+ }>;
46
+ /**
47
+ * Emitted when thumbs are removed after the initial render.
48
+ */
49
+ 'mu-range-removed-thumbs': CustomEvent<{
50
+ data: {
51
+ name: string;
52
+ value: number;
53
+ }[];
54
+ }>;
55
+ };
56
+ declare class MuRange extends MUElement {
57
+ static styles?: CSSResultGroup | undefined;
58
+ eventActionData: undefined;
59
+ _addEventActionAttributes: undefined;
60
+ /**
61
+ * The axis of the range.
62
+ *
63
+ * `x` - horizontal axis auto matching the direction
64
+ *
65
+ * `-x` - horizontal axis reversed
66
+ *
67
+ * `y` - vertical axis
68
+ *
69
+ * `-y` - vertical axis reversed
70
+ */
71
+ axis: 'x' | 'y' | '-x' | '-y';
72
+ /**
73
+ * The minimum value of the range.
74
+ */
75
+ min: number;
76
+ /**
77
+ * The maximum value of the range.
78
+ */
79
+ max: number;
80
+ /**
81
+ * The value of the range for the controlled mode.
82
+ *
83
+ * @see {@link MuRange.setValueFromString}
84
+ *
85
+ * @default undefined
86
+ */
87
+ value?: string;
88
+ /**
89
+ * The initial render value of the range for the uncontrolled mode.
90
+ *
91
+ * @see {@link MuRange.setValueFromString}
92
+ *
93
+ * @default undefined
94
+ */
95
+ defaultValue?: string;
96
+ /**
97
+ * Thumb behavior when pointerdown on a non-thumb element.
98
+ *
99
+ * - `prevent` - don't do anything
100
+ *
101
+ * - `dispatch` - dispatch the {@link Events['mu-range-empty-area']} event
102
+ *
103
+ * - `nearest` - move the nearest thumb to the pointer position
104
+ *
105
+ * @default `nearest`
106
+ */
107
+ emptyArea: 'prevent' | 'dispatch' | 'nearest';
108
+ protected _isReadyPromise: Readonly<{
109
+ status: "success" | "fail" | "pending";
110
+ resolved: boolean;
111
+ promise: Promise<boolean>;
112
+ resolve: () => void;
113
+ }>;
114
+ get isControlled(): boolean;
115
+ _thumbs: RangeThumb[];
116
+ _thumbsElementsMap: Map<MuRangeThumb, RangeThumb>;
117
+ _thumbsNamesMap: Map<string, RangeThumb>;
118
+ _activeThumb: RangeThumb | undefined;
119
+ /**
120
+ * this is used to prevent focus listener from running when the pointer is down otherwise active thumb will gain focus when the pointer is down
121
+ */
122
+ protected _isPointerDown: boolean;
123
+ set activeThumb(thumb: RangeThumb | undefined);
124
+ get activeThumb(): RangeThumb | undefined;
125
+ constructor();
126
+ disconnectedCallback(): void;
127
+ /**
128
+ *
129
+ * @returns an array of objects containing the name and value of each thumb
130
+ */
131
+ getValue(): {
132
+ name: string;
133
+ value: number;
134
+ }[];
135
+ /**
136
+ * Programmatically insert a thumb element
137
+ */
138
+ insertThumbElement(thumbEl: MuRangeThumb): Promise<void>;
139
+ /**
140
+ * Switches the active thumb for keyboard navigation
141
+ */
142
+ switchNavigationActiveItem(direction: 'next' | 'prev'): boolean;
143
+ dispatchChangeEvent(thumbs?: {
144
+ name: string;
145
+ value: number;
146
+ }[]): void;
147
+ _setThumbValue(thumb: RangeThumb, value: number): void;
148
+ /**
149
+ * Updates the range fill element
150
+ */
151
+ updateRangeFill(range: RangeFill): Promise<void>;
152
+ /**
153
+ * Takes a thumb and a value and returns the step value to be set
154
+ */
155
+ _getThumbStepValue(thumb: RangeThumb, value: number): number;
156
+ /**
157
+ * gets the value and percentage from pointer event
158
+ */
159
+ _getValuesFromEvent(e: {
160
+ clientX: number;
161
+ clientY: number;
162
+ }): {
163
+ roundedPercentage: number;
164
+ value: number;
165
+ percentage: number;
166
+ rawPercentage: number;
167
+ };
168
+ /**
169
+ * sorts the thumbs
170
+ */
171
+ sortThumbs(): void;
172
+ _slotChangeHandler: () => Promise<void>;
173
+ /**
174
+ * @param valueString
175
+ *
176
+ * a comma separated string without spaces of (thumb values) or (an optional thumb name followed by a colon then the value) or a mix of both
177
+ *
178
+ * make sure to only use one format where all has names or no names, because if there is no names, the order of the values will be the same as the order of the thumbs.
179
+ * so you might end up with a thumb with a different value (named and not named).
180
+ *
181
+ * @example "0,50,100"
182
+ * @example "thumb1:0,thumb2:50,thumb3:100"
183
+ * @example "0,thumb2:50,100"
184
+ *
185
+ */
186
+ setValueFromString(valueString: string): Promise<void>;
187
+ _keydownHandler: (e: KeyboardEvent) => void;
188
+ _pointerdownHandler: (e: PointerEvent) => void;
189
+ _documentPointerupHandler: (e: PointerEvent) => void;
190
+ _pointermoveHandler: (e: PointerEvent) => void;
191
+ _documentPointermoveHandler: (e: PointerEvent) => void;
192
+ _debouncedPointermoveHandler: (e: PointerEvent) => void;
193
+ protected getUpdateComplete(): Promise<boolean>;
194
+ protected firstUpdated(_changedProperties: PropertyValues<this>): Promise<void>;
195
+ protected updated(_changedProperties: PropertyValues<this>): Promise<void>;
196
+ render(): unknown;
197
+ }
198
+ declare global {
199
+ interface HTMLElementTagNameMap {
200
+ 'mu-range': MuRange;
201
+ }
202
+ interface GlobalEventHandlersEventMap extends Events {
203
+ }
204
+ }
205
+
206
+ export { MuRange };