mtrl 0.2.8 → 0.2.9
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/index.ts +2 -0
- package/package.json +1 -1
- package/src/components/navigation/api.ts +131 -96
- package/src/components/navigation/features/controller.ts +273 -0
- package/src/components/navigation/features/items.ts +133 -64
- package/src/components/navigation/navigation.ts +17 -2
- package/src/components/navigation/system-types.ts +124 -0
- package/src/components/navigation/system.ts +776 -0
- package/src/components/slider/config.ts +20 -2
- package/src/components/slider/features/controller.ts +761 -0
- package/src/components/slider/features/handlers.ts +18 -15
- package/src/components/slider/features/index.ts +3 -2
- package/src/components/slider/features/range.ts +104 -0
- package/src/components/slider/slider.ts +34 -14
- package/src/components/slider/structure.ts +152 -0
- package/src/components/textfield/api.ts +53 -0
- package/src/components/textfield/features.ts +322 -0
- package/src/components/textfield/textfield.ts +8 -0
- package/src/components/textfield/types.ts +12 -3
- package/src/components/timepicker/clockdial.ts +1 -4
- package/src/core/compose/features/textinput.ts +15 -2
- package/src/core/composition/features/dom.ts +33 -0
- package/src/core/composition/features/icon.ts +131 -0
- package/src/core/composition/features/index.ts +11 -0
- package/src/core/composition/features/label.ts +156 -0
- package/src/core/composition/features/structure.ts +22 -0
- package/src/core/composition/index.ts +26 -0
- package/src/core/index.ts +1 -1
- package/src/core/structure.ts +288 -0
- package/src/index.ts +1 -0
- package/src/styles/components/_navigation-mobile.scss +244 -0
- package/src/styles/components/_navigation-system.scss +151 -0
- package/src/styles/components/_textfield.scss +250 -11
- package/demo/build.ts +0 -349
- package/demo/index.html +0 -110
- package/demo/main.js +0 -448
- package/demo/styles.css +0 -239
- package/server.ts +0 -86
- package/src/components/slider/features/slider.ts +0 -318
- package/src/components/slider/features/structure.ts +0 -181
- package/src/components/slider/features/ui.ts +0 -388
- package/src/components/textfield/constants.ts +0 -100
package/demo/styles.css
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
// demo/styles.scss
|
|
2
|
-
|
|
3
|
-
// Import the main styles from the source code
|
|
4
|
-
@use '../src/styles/main.scss';
|
|
5
|
-
|
|
6
|
-
/* Base styles */
|
|
7
|
-
:root {
|
|
8
|
-
--primary-color: #6750a4;
|
|
9
|
-
--on-primary-color: #ffffff;
|
|
10
|
-
--primary-container-color: #eaddff;
|
|
11
|
-
--on-primary-container-color: #21005d;
|
|
12
|
-
--secondary-color: #625b71;
|
|
13
|
-
--on-secondary-color: #ffffff;
|
|
14
|
-
--secondary-container-color: #e8def8;
|
|
15
|
-
--on-secondary-container-color: #1d192b;
|
|
16
|
-
--tertiary-color: #7d5260;
|
|
17
|
-
--surface-color: #fffbfe;
|
|
18
|
-
--on-surface-color: #1c1b1f;
|
|
19
|
-
--surface-variant-color: #e7e0ec;
|
|
20
|
-
--on-surface-variant-color: #49454f;
|
|
21
|
-
--outline-color: #79747e;
|
|
22
|
-
--background-color: #fffbfe;
|
|
23
|
-
--error-color: #b3261e;
|
|
24
|
-
|
|
25
|
-
--elevation-1: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);
|
|
26
|
-
--elevation-2: 0px 2px 6px 2px rgba(0, 0, 0, 0.15);
|
|
27
|
-
--elevation-3: 0px 4px 8px 3px rgba(0, 0, 0, 0.15);
|
|
28
|
-
|
|
29
|
-
--spacing-1: 4px;
|
|
30
|
-
--spacing-2: 8px;
|
|
31
|
-
--spacing-3: 12px;
|
|
32
|
-
--spacing-4: 16px;
|
|
33
|
-
--spacing-5: 24px;
|
|
34
|
-
--spacing-6: 32px;
|
|
35
|
-
|
|
36
|
-
--border-radius-small: 4px;
|
|
37
|
-
--border-radius-medium: 8px;
|
|
38
|
-
--border-radius-large: 16px;
|
|
39
|
-
--border-radius-full: 9999px;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/* Dark theme support */
|
|
43
|
-
@media (prefers-color-scheme: dark) {
|
|
44
|
-
:root {
|
|
45
|
-
--primary-color: #d0bcff;
|
|
46
|
-
--on-primary-color: #381e72;
|
|
47
|
-
--primary-container-color: #4f378b;
|
|
48
|
-
--on-primary-container-color: #eaddff;
|
|
49
|
-
--secondary-color: #ccc2dc;
|
|
50
|
-
--on-secondary-color: #332d41;
|
|
51
|
-
--secondary-container-color: #4a4458;
|
|
52
|
-
--on-secondary-container-color: #e8def8;
|
|
53
|
-
--tertiary-color: #efb8c8;
|
|
54
|
-
--surface-color: #1c1b1f;
|
|
55
|
-
--on-surface-color: #e6e1e5;
|
|
56
|
-
--surface-variant-color: #49454f;
|
|
57
|
-
--on-surface-variant-color: #cac4d0;
|
|
58
|
-
--outline-color: #938f99;
|
|
59
|
-
--background-color: #1c1b1f;
|
|
60
|
-
--error-color: #f2b8b5;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/* Core styles */
|
|
65
|
-
* {
|
|
66
|
-
box-sizing: border-box;
|
|
67
|
-
margin: 0;
|
|
68
|
-
padding: 0;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
body {
|
|
72
|
-
font-family: 'Roboto', sans-serif;
|
|
73
|
-
background-color: var(--background-color);
|
|
74
|
-
color: var(--on-surface-color);
|
|
75
|
-
line-height: 1.5;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/* Layout */
|
|
79
|
-
.content {
|
|
80
|
-
max-width: 1200px;
|
|
81
|
-
margin: 0 auto;
|
|
82
|
-
padding: var(--spacing-5);
|
|
83
|
-
margin-bottom: 120px; /* For bottom app bar */
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/* Component Sections */
|
|
87
|
-
.component-section {
|
|
88
|
-
margin-bottom: var(--spacing-6);
|
|
89
|
-
padding: var(--spacing-4);
|
|
90
|
-
border-radius: var(--border-radius-medium);
|
|
91
|
-
background-color: var(--surface-color);
|
|
92
|
-
box-shadow: var(--elevation-1);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.component-section h2 {
|
|
96
|
-
color: var(--primary-color);
|
|
97
|
-
margin-bottom: var(--spacing-4);
|
|
98
|
-
font-size: 1.5rem;
|
|
99
|
-
border-bottom: 1px solid var(--outline-color);
|
|
100
|
-
padding-bottom: var(--spacing-2);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.component-row {
|
|
104
|
-
display: flex;
|
|
105
|
-
flex-wrap: wrap;
|
|
106
|
-
gap: var(--spacing-5);
|
|
107
|
-
align-items: flex-start;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.align-top {
|
|
111
|
-
align-items: flex-start;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/* Demo Blocks */
|
|
115
|
-
.demo-block {
|
|
116
|
-
flex: 1;
|
|
117
|
-
min-width: 300px;
|
|
118
|
-
margin-bottom: var(--spacing-4);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.demo-block h3 {
|
|
122
|
-
font-size: 1rem;
|
|
123
|
-
color: var(--on-surface-variant-color);
|
|
124
|
-
margin-bottom: var(--spacing-3);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.demo-content {
|
|
128
|
-
display: flex;
|
|
129
|
-
flex-direction: column;
|
|
130
|
-
gap: var(--spacing-3);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/* Intro section */
|
|
134
|
-
#intro {
|
|
135
|
-
text-align: center;
|
|
136
|
-
margin-bottom: var(--spacing-6);
|
|
137
|
-
padding: var(--spacing-6) 0;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
#intro h1 {
|
|
141
|
-
color: var(--primary-color);
|
|
142
|
-
font-size: 2.5rem;
|
|
143
|
-
margin-bottom: var(--spacing-3);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
#intro p {
|
|
147
|
-
color: var(--on-surface-variant-color);
|
|
148
|
-
font-size: 1.2rem;
|
|
149
|
-
max-width: 600px;
|
|
150
|
-
margin: 0 auto;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/* App Bars */
|
|
154
|
-
.top-app-bar {
|
|
155
|
-
position: sticky;
|
|
156
|
-
top: 0;
|
|
157
|
-
z-index: 1000;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/* Carousel */
|
|
161
|
-
.carousel-item {
|
|
162
|
-
height: 200px;
|
|
163
|
-
display: flex;
|
|
164
|
-
align-items: center;
|
|
165
|
-
justify-content: center;
|
|
166
|
-
background-color: var(--primary-container-color);
|
|
167
|
-
color: var(--on-primary-container-color);
|
|
168
|
-
font-weight: bold;
|
|
169
|
-
border-radius: var(--border-radius-medium);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/* Card Demo */
|
|
173
|
-
.demo-card-media {
|
|
174
|
-
height: 140px;
|
|
175
|
-
background-color: var(--primary-container-color);
|
|
176
|
-
background-image: linear-gradient(45deg, var(--primary-color) 25%, transparent 25%, transparent 50%, var(--primary-color) 50%, var(--primary-color) 75%, transparent 75%, transparent);
|
|
177
|
-
background-size: 20px 20px;
|
|
178
|
-
border-radius: var(--border-radius-medium) var(--border-radius-medium) 0 0;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/* Hack to ensure components like dialog, sheet, tooltip are visible in the demo */
|
|
182
|
-
.mtrl-dialog, .mtrl-sheet, .mtrl-tooltip {
|
|
183
|
-
position: absolute; /* Override fixed positioning for demo */
|
|
184
|
-
z-index: 2; /* Lower z-index for demo */
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/* Display helpers */
|
|
188
|
-
.demo-text {
|
|
189
|
-
margin: var(--spacing-2) 0;
|
|
190
|
-
color: var(--on-surface-variant-color);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/* Responsive adjustments */
|
|
194
|
-
@media (max-width: 768px) {
|
|
195
|
-
.component-row {
|
|
196
|
-
flex-direction: column;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.demo-block {
|
|
200
|
-
width: 100%;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/* Component-specific styling overrides for demo purposes */
|
|
205
|
-
.mtrl-button {
|
|
206
|
-
margin-right: var(--spacing-2);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.mtrl-textfield {
|
|
210
|
-
width: 100%;
|
|
211
|
-
max-width: 300px;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.mtrl-card {
|
|
215
|
-
max-width: 320px;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.mtrl-list {
|
|
219
|
-
max-width: 400px;
|
|
220
|
-
border: 1px solid var(--outline-color);
|
|
221
|
-
border-radius: var(--border-radius-medium);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.mtrl-slider {
|
|
225
|
-
width: 100%;
|
|
226
|
-
max-width: 300px;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.mtrl-navigation {
|
|
230
|
-
width: 300px;
|
|
231
|
-
border: 1px solid var(--outline-color);
|
|
232
|
-
border-radius: var(--border-radius-medium);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.mtrl-tabs {
|
|
236
|
-
width: 100%;
|
|
237
|
-
max-width: 400px;
|
|
238
|
-
border-bottom: 1px solid var(--outline-color);
|
|
239
|
-
}
|
package/server.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// server.ts - TypeScript version of the Bun server for the component library demo
|
|
2
|
-
import { serve, type ServeOptions } from "bun";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { readFileSync, existsSync } from "fs";
|
|
5
|
-
|
|
6
|
-
// Content type mapping
|
|
7
|
-
const contentTypes: Record<string, string> = {
|
|
8
|
-
".html": "text/html",
|
|
9
|
-
".js": "text/javascript",
|
|
10
|
-
".mjs": "text/javascript", // Add this for ES modules
|
|
11
|
-
".css": "text/css",
|
|
12
|
-
".json": "application/json",
|
|
13
|
-
".png": "image/png",
|
|
14
|
-
".jpg": "image/jpeg",
|
|
15
|
-
".svg": "image/svg+xml"
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Define the port (hardcoded instead of using environment variable)
|
|
19
|
-
const PORT: number = 3301;
|
|
20
|
-
|
|
21
|
-
// Define demo directory path
|
|
22
|
-
const DEMO_DIR: string = "./demo";
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Serves a file from the demo directory
|
|
26
|
-
* @param path Path to the file relative to the demo directory
|
|
27
|
-
* @returns Response object with the file content or error message
|
|
28
|
-
*/
|
|
29
|
-
function serveFile(path: string): Response {
|
|
30
|
-
// Add demo directory to path
|
|
31
|
-
const filePath: string = join(DEMO_DIR, path);
|
|
32
|
-
|
|
33
|
-
// Handle index.html for directory request
|
|
34
|
-
let resolvedPath: string = filePath;
|
|
35
|
-
if (filePath.endsWith('/') || !filePath.includes('.')) {
|
|
36
|
-
resolvedPath = join(filePath, 'index.html');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Check if file exists
|
|
40
|
-
if (!existsSync(resolvedPath)) {
|
|
41
|
-
return new Response("File not found", { status: 404 });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Get file extension for content type
|
|
45
|
-
const ext: string = resolvedPath.substring(resolvedPath.lastIndexOf('.'));
|
|
46
|
-
const contentType: string = contentTypes[ext] || "application/octet-stream";
|
|
47
|
-
|
|
48
|
-
// Read and serve the file
|
|
49
|
-
try {
|
|
50
|
-
const content: Buffer = readFileSync(resolvedPath);
|
|
51
|
-
|
|
52
|
-
// For JavaScript files, ensure they're served with the correct MIME type
|
|
53
|
-
// and additionally add proper headers for modules
|
|
54
|
-
if (ext === '.js') {
|
|
55
|
-
return new Response(content, {
|
|
56
|
-
headers: {
|
|
57
|
-
"Content-Type": "text/javascript",
|
|
58
|
-
"Cache-Control": "no-cache"
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return new Response(content, {
|
|
64
|
-
headers: { "Content-Type": contentType }
|
|
65
|
-
});
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error(`Error serving ${resolvedPath}:`, error);
|
|
68
|
-
return new Response("Server error", { status: 500 });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Server options with typings
|
|
73
|
-
const serverOptions: ServeOptions = {
|
|
74
|
-
port: PORT,
|
|
75
|
-
fetch(req: Request): Response | Promise<Response> {
|
|
76
|
-
const url = new URL(req.url);
|
|
77
|
-
const path = url.pathname === '/' ? '/' : url.pathname;
|
|
78
|
-
|
|
79
|
-
return serveFile(path);
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// Create and start the server
|
|
84
|
-
const server = serve(serverOptions);
|
|
85
|
-
|
|
86
|
-
console.log(`Server running at http://localhost:${PORT}`);
|
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
// src/components/slider/features/slider.ts
|
|
2
|
-
import { SLIDER_EVENTS } from '../constants';
|
|
3
|
-
import { SliderConfig } from '../types';
|
|
4
|
-
import { createUiHelpers } from './ui';
|
|
5
|
-
import { createHandlers } from './handlers';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Add main slider functionality to component
|
|
9
|
-
* @param config Slider configuration
|
|
10
|
-
* @returns Component enhancer with slider functionality
|
|
11
|
-
*/
|
|
12
|
-
export const withSlider = (config: SliderConfig) => component => {
|
|
13
|
-
// Ensure component has events
|
|
14
|
-
if (!component.events) {
|
|
15
|
-
component.events = {
|
|
16
|
-
listeners: {},
|
|
17
|
-
on(event, handler) {
|
|
18
|
-
if (!this.listeners[event]) this.listeners[event] = [];
|
|
19
|
-
this.listeners[event].push(handler);
|
|
20
|
-
return this;
|
|
21
|
-
},
|
|
22
|
-
off(event, handler) {
|
|
23
|
-
if (this.listeners[event]) {
|
|
24
|
-
this.listeners[event] = this.listeners[event].filter(h => h !== handler);
|
|
25
|
-
}
|
|
26
|
-
return this;
|
|
27
|
-
},
|
|
28
|
-
trigger(event, data) {
|
|
29
|
-
if (this.listeners[event]) {
|
|
30
|
-
this.listeners[event].forEach(handler => handler(data));
|
|
31
|
-
}
|
|
32
|
-
return this;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Initialize state
|
|
38
|
-
const state = {
|
|
39
|
-
value: config.value !== undefined ? config.value : 0,
|
|
40
|
-
secondValue: config.secondValue !== undefined ? config.secondValue : null,
|
|
41
|
-
min: config.min !== undefined ? config.min : 0,
|
|
42
|
-
max: config.max !== undefined ? config.max : 100,
|
|
43
|
-
step: config.step !== undefined ? config.step : 1,
|
|
44
|
-
dragging: false,
|
|
45
|
-
activeBubble: null,
|
|
46
|
-
activeHandle: null,
|
|
47
|
-
ticks: [],
|
|
48
|
-
valueHideTimer: null,
|
|
49
|
-
component
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Create event helpers
|
|
53
|
-
const eventHelpers = {
|
|
54
|
-
triggerEvent(eventName, originalEvent = null) {
|
|
55
|
-
const eventData = {
|
|
56
|
-
slider: state.component,
|
|
57
|
-
value: state.value,
|
|
58
|
-
secondValue: state.secondValue,
|
|
59
|
-
originalEvent,
|
|
60
|
-
preventDefault: () => { eventData.defaultPrevented = true; },
|
|
61
|
-
defaultPrevented: false
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
state.component.events.trigger(eventName, eventData);
|
|
65
|
-
return eventData;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Create UI helpers and handlers
|
|
70
|
-
const uiHelpers = createUiHelpers(config, state);
|
|
71
|
-
const handlers = createHandlers(config, state, uiHelpers, eventHelpers);
|
|
72
|
-
|
|
73
|
-
// Initialize slider
|
|
74
|
-
const initSlider = () => {
|
|
75
|
-
// Set ARIA attributes
|
|
76
|
-
component.element.setAttribute('aria-valuemin', String(state.min));
|
|
77
|
-
component.element.setAttribute('aria-valuemax', String(state.max));
|
|
78
|
-
component.element.setAttribute('aria-valuenow', String(state.value));
|
|
79
|
-
|
|
80
|
-
if (!component.structure) {
|
|
81
|
-
console.warn('Cannot initialize slider: missing structure');
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const { handle, secondHandle } = component.structure;
|
|
86
|
-
|
|
87
|
-
if (handle) {
|
|
88
|
-
handle.setAttribute('aria-valuemin', String(state.min));
|
|
89
|
-
handle.setAttribute('aria-valuemax', String(state.max));
|
|
90
|
-
handle.setAttribute('aria-valuenow', String(state.value));
|
|
91
|
-
|
|
92
|
-
if (config.range && secondHandle && state.secondValue !== null) {
|
|
93
|
-
secondHandle.setAttribute('aria-valuemin', String(state.min));
|
|
94
|
-
secondHandle.setAttribute('aria-valuemax', String(state.max));
|
|
95
|
-
secondHandle.setAttribute('aria-valuenow', String(state.secondValue));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Initial UI update
|
|
100
|
-
uiHelpers.updateUi();
|
|
101
|
-
|
|
102
|
-
// Generate ticks if needed
|
|
103
|
-
if (config.ticks || config.tickLabels) {
|
|
104
|
-
uiHelpers.generateTicks();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Setup event listeners
|
|
108
|
-
handlers.setupEventListeners();
|
|
109
|
-
|
|
110
|
-
// Force one more UI update after a delay to ensure proper positioning
|
|
111
|
-
setTimeout(() => {
|
|
112
|
-
uiHelpers.updateUi();
|
|
113
|
-
}, 50);
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// Register with lifecycle if available
|
|
117
|
-
if (component.lifecycle) {
|
|
118
|
-
const originalDestroy = component.lifecycle.destroy || (() => {});
|
|
119
|
-
component.lifecycle.destroy = () => {
|
|
120
|
-
handlers.cleanupEventListeners();
|
|
121
|
-
originalDestroy();
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Initialize slider
|
|
126
|
-
initSlider();
|
|
127
|
-
|
|
128
|
-
// Return enhanced component
|
|
129
|
-
return {
|
|
130
|
-
...component,
|
|
131
|
-
slider: {
|
|
132
|
-
/**
|
|
133
|
-
* Sets slider value
|
|
134
|
-
* @param value New value
|
|
135
|
-
* @param triggerEvent Whether to trigger change event
|
|
136
|
-
* @returns Slider controller for chaining
|
|
137
|
-
*/
|
|
138
|
-
setValue(value, triggerEvent = true) {
|
|
139
|
-
const newValue = uiHelpers.clamp(value, state.min, state.max);
|
|
140
|
-
state.value = newValue;
|
|
141
|
-
uiHelpers.updateUi();
|
|
142
|
-
|
|
143
|
-
if (triggerEvent) {
|
|
144
|
-
eventHelpers.triggerEvent(SLIDER_EVENTS.CHANGE);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return this;
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Gets slider value
|
|
152
|
-
* @returns Current value
|
|
153
|
-
*/
|
|
154
|
-
getValue() {
|
|
155
|
-
return state.value;
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Sets secondary slider value (for range slider)
|
|
160
|
-
* @param value New secondary value
|
|
161
|
-
* @param triggerEvent Whether to trigger change event
|
|
162
|
-
* @returns Slider controller for chaining
|
|
163
|
-
*/
|
|
164
|
-
setSecondValue(value, triggerEvent = true) {
|
|
165
|
-
if (!config.range) return this;
|
|
166
|
-
|
|
167
|
-
const newValue = uiHelpers.clamp(value, state.min, state.max);
|
|
168
|
-
state.secondValue = newValue;
|
|
169
|
-
uiHelpers.updateUi();
|
|
170
|
-
|
|
171
|
-
if (triggerEvent) {
|
|
172
|
-
eventHelpers.triggerEvent(SLIDER_EVENTS.CHANGE);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return this;
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Gets secondary slider value
|
|
180
|
-
* @returns Current secondary value or null
|
|
181
|
-
*/
|
|
182
|
-
getSecondValue() {
|
|
183
|
-
return config.range ? state.secondValue : null;
|
|
184
|
-
},
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Sets slider minimum value
|
|
188
|
-
* @param min New minimum value
|
|
189
|
-
* @returns Slider controller for chaining
|
|
190
|
-
*/
|
|
191
|
-
setMin(min) {
|
|
192
|
-
state.min = min;
|
|
193
|
-
|
|
194
|
-
// Update ARIA attributes
|
|
195
|
-
component.element.setAttribute('aria-valuemin', String(min));
|
|
196
|
-
if (component.structure.handle) {
|
|
197
|
-
component.structure.handle.setAttribute('aria-valuemin', String(min));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (config.range && component.structure.secondHandle) {
|
|
201
|
-
component.structure.secondHandle.setAttribute('aria-valuemin', String(min));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Clamp values to new min
|
|
205
|
-
if (state.value < min) state.value = min;
|
|
206
|
-
if (config.range && state.secondValue !== null && state.secondValue < min) {
|
|
207
|
-
state.secondValue = min;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Regenerate ticks if needed
|
|
211
|
-
if (config.ticks || config.tickLabels) {
|
|
212
|
-
uiHelpers.generateTicks();
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
uiHelpers.updateUi();
|
|
216
|
-
return this;
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Gets slider minimum value
|
|
221
|
-
* @returns Current minimum value
|
|
222
|
-
*/
|
|
223
|
-
getMin() {
|
|
224
|
-
return state.min;
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Sets slider maximum value
|
|
229
|
-
* @param max New maximum value
|
|
230
|
-
* @returns Slider controller for chaining
|
|
231
|
-
*/
|
|
232
|
-
setMax(max) {
|
|
233
|
-
state.max = max;
|
|
234
|
-
|
|
235
|
-
// Update ARIA attributes
|
|
236
|
-
component.element.setAttribute('aria-valuemax', String(max));
|
|
237
|
-
if (component.structure.handle) {
|
|
238
|
-
component.structure.handle.setAttribute('aria-valuemax', String(max));
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (config.range && component.structure.secondHandle) {
|
|
242
|
-
component.structure.secondHandle.setAttribute('aria-valuemax', String(max));
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Clamp values to new max
|
|
246
|
-
if (state.value > max) state.value = max;
|
|
247
|
-
if (config.range && state.secondValue !== null && state.secondValue > max) {
|
|
248
|
-
state.secondValue = max;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Regenerate ticks if needed
|
|
252
|
-
if (config.ticks || config.tickLabels) {
|
|
253
|
-
uiHelpers.generateTicks();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
uiHelpers.updateUi();
|
|
257
|
-
return this;
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Gets slider maximum value
|
|
262
|
-
* @returns Current maximum value
|
|
263
|
-
*/
|
|
264
|
-
getMax() {
|
|
265
|
-
return state.max;
|
|
266
|
-
},
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Sets slider step size
|
|
270
|
-
* @param step New step size
|
|
271
|
-
* @returns Slider controller for chaining
|
|
272
|
-
*/
|
|
273
|
-
setStep(step) {
|
|
274
|
-
state.step = step;
|
|
275
|
-
|
|
276
|
-
// Add or remove discrete class
|
|
277
|
-
component.element.classList[step > 0 ? 'add' : 'remove'](
|
|
278
|
-
`${component.getClass('slider')}--discrete`
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
// Regenerate ticks if needed
|
|
282
|
-
if (config.ticks || config.tickLabels) {
|
|
283
|
-
uiHelpers.generateTicks();
|
|
284
|
-
uiHelpers.updateTicks();
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return this;
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Gets slider step size
|
|
292
|
-
* @returns Current step size
|
|
293
|
-
*/
|
|
294
|
-
getStep() {
|
|
295
|
-
return state.step;
|
|
296
|
-
},
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Regenerate tick marks and labels
|
|
300
|
-
* @returns Slider controller for chaining
|
|
301
|
-
*/
|
|
302
|
-
regenerateTicks() {
|
|
303
|
-
uiHelpers.generateTicks();
|
|
304
|
-
uiHelpers.updateTicks();
|
|
305
|
-
return this;
|
|
306
|
-
},
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Update all UI elements
|
|
310
|
-
* @returns Slider controller for chaining
|
|
311
|
-
*/
|
|
312
|
-
updateUi() {
|
|
313
|
-
uiHelpers.updateUi();
|
|
314
|
-
return this;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
};
|