mtrl 0.2.8 → 0.3.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/index.ts +4 -0
- package/package.json +1 -1
- package/src/components/button/button.ts +34 -5
- 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/core.ts +302 -0
- package/src/components/navigation/system/events.ts +240 -0
- package/src/components/navigation/system/index.ts +184 -0
- package/src/components/navigation/system/mobile.ts +278 -0
- package/src/components/navigation/system/state.ts +77 -0
- package/src/components/navigation/system/types.ts +364 -0
- package/src/components/slider/config.ts +20 -2
- package/src/components/slider/features/controller.ts +737 -0
- package/src/components/slider/features/handlers.ts +18 -16
- package/src/components/slider/features/index.ts +3 -2
- package/src/components/slider/features/range.ts +104 -0
- package/src/components/slider/schema.ts +141 -0
- package/src/components/slider/slider.ts +34 -13
- package/src/components/switch/api.ts +16 -0
- package/src/components/switch/config.ts +1 -18
- package/src/components/switch/features.ts +198 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/switch/switch.ts +3 -3
- package/src/components/switch/types.ts +14 -2
- 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 +45 -0
- package/src/core/composition/features/icon.ts +131 -0
- package/src/core/composition/features/index.ts +12 -0
- package/src/core/composition/features/label.ts +155 -0
- package/src/core/composition/features/layout.ts +47 -0
- package/src/core/composition/index.ts +26 -0
- package/src/core/index.ts +1 -1
- package/src/core/layout/README.md +350 -0
- package/src/core/layout/array.ts +181 -0
- package/src/core/layout/create.ts +55 -0
- package/src/core/layout/index.ts +26 -0
- package/src/core/layout/object.ts +124 -0
- package/src/core/layout/processor.ts +58 -0
- package/src/core/layout/result.ts +85 -0
- package/src/core/layout/types.ts +125 -0
- package/src/core/layout/utils.ts +136 -0
- package/src/index.ts +1 -0
- package/src/styles/abstract/_variables.scss +28 -0
- package/src/styles/components/_navigation-mobile.scss +244 -0
- package/src/styles/components/_navigation-system.scss +151 -0
- package/src/styles/components/_switch.scss +133 -69
- package/src/styles/components/_textfield.scss +259 -27
- 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/src/core/layout/index.js +0 -95
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
// src/components/slider/features/ui.ts
|
|
2
|
-
import { SliderConfig } from '../types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Create optimized UI update helpers for slider component
|
|
6
|
-
*
|
|
7
|
-
* @param config Slider configuration
|
|
8
|
-
* @param state Slider state object
|
|
9
|
-
* @returns UI update helper methods
|
|
10
|
-
*/
|
|
11
|
-
export const createUiHelpers = (config: SliderConfig, state) => {
|
|
12
|
-
// Return empty implementations if component structure is missing
|
|
13
|
-
if (!state.component?.structure) {
|
|
14
|
-
console.error('Cannot create UI helpers: component structure is missing');
|
|
15
|
-
return {
|
|
16
|
-
getPercentage: () => 0,
|
|
17
|
-
getValueFromPosition: () => 0,
|
|
18
|
-
roundToStep: v => v,
|
|
19
|
-
clamp: (v, min, max) => Math.min(Math.max(v, min), max),
|
|
20
|
-
updateUi: () => {},
|
|
21
|
-
showValueBubble: () => {},
|
|
22
|
-
generateTicks: () => {},
|
|
23
|
-
updateTicks: () => {}
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const {
|
|
28
|
-
container = null,
|
|
29
|
-
track = null,
|
|
30
|
-
activeTrack = null,
|
|
31
|
-
startTrack = null,
|
|
32
|
-
remainingTrack = null,
|
|
33
|
-
handle = null,
|
|
34
|
-
valueBubble = null,
|
|
35
|
-
secondHandle = null,
|
|
36
|
-
secondValueBubble = null,
|
|
37
|
-
ticksContainer = null
|
|
38
|
-
} = state.component.structure;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Calculates percentage position for a value
|
|
42
|
-
*/
|
|
43
|
-
const getPercentage = (value) => {
|
|
44
|
-
const range = state.max - state.min;
|
|
45
|
-
return range === 0 ? 0 : ((value - state.min) / range) * 100;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Gets track dimensions and constraints for positioning calculations
|
|
50
|
-
*/
|
|
51
|
-
const getTrackDimensions = () => {
|
|
52
|
-
if (!track || !handle || !container) return null;
|
|
53
|
-
|
|
54
|
-
const handleRect = handle.getBoundingClientRect();
|
|
55
|
-
const trackRect = container.getBoundingClientRect();
|
|
56
|
-
const handleSize = handleRect.width || 20;
|
|
57
|
-
const trackSize = trackRect.width;
|
|
58
|
-
|
|
59
|
-
const edgeConstraint = (handleSize / 2) / trackSize * 100;
|
|
60
|
-
const paddingPixels = state.activeHandle ? 6 : 8;
|
|
61
|
-
const paddingPercent = (paddingPixels / trackSize) * 100;
|
|
62
|
-
|
|
63
|
-
return { handleSize, trackSize, edgeConstraint, paddingPercent };
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Maps value percentage to visual position with edge constraints
|
|
68
|
-
*/
|
|
69
|
-
const mapValueToVisualPercent = (valuePercent, edgeConstraint) => {
|
|
70
|
-
const minEdge = edgeConstraint;
|
|
71
|
-
const maxEdge = 100 - edgeConstraint;
|
|
72
|
-
const visualRange = maxEdge - minEdge;
|
|
73
|
-
|
|
74
|
-
if (valuePercent <= 0) return minEdge;
|
|
75
|
-
if (valuePercent >= 100) return maxEdge;
|
|
76
|
-
return minEdge + (valuePercent / 100) * visualRange;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Gets slider value from a position on the track
|
|
81
|
-
*/
|
|
82
|
-
const getValueFromPosition = (position) => {
|
|
83
|
-
if (!track || !container) return state.min;
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
const containerRect = container.getBoundingClientRect();
|
|
87
|
-
const range = state.max - state.min;
|
|
88
|
-
const handleWidth = handle.getBoundingClientRect().width || 20;
|
|
89
|
-
|
|
90
|
-
const leftEdge = containerRect.left + (handleWidth / 2);
|
|
91
|
-
const rightEdge = containerRect.right - (handleWidth / 2);
|
|
92
|
-
const effectiveWidth = rightEdge - leftEdge;
|
|
93
|
-
|
|
94
|
-
const adjustedPosition = Math.max(leftEdge, Math.min(rightEdge, position));
|
|
95
|
-
const percentageFromLeft = (adjustedPosition - leftEdge) / effectiveWidth;
|
|
96
|
-
|
|
97
|
-
return state.min + percentageFromLeft * range;
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.warn('Error calculating value from position:', error);
|
|
100
|
-
return state.min;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Rounds a value to the nearest step
|
|
106
|
-
*/
|
|
107
|
-
const roundToStep = (value) => {
|
|
108
|
-
const step = state.step;
|
|
109
|
-
if (step <= 0) return value;
|
|
110
|
-
|
|
111
|
-
const steps = Math.round((value - state.min) / step);
|
|
112
|
-
return state.min + (steps * step);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Clamps a value between min and max
|
|
117
|
-
*/
|
|
118
|
-
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Updates handle and bubble positions and transforms
|
|
122
|
-
*/
|
|
123
|
-
const updateHandlePositions = () => {
|
|
124
|
-
if (!handle || !container) return;
|
|
125
|
-
|
|
126
|
-
const dims = getTrackDimensions();
|
|
127
|
-
if (!dims) return;
|
|
128
|
-
|
|
129
|
-
const { edgeConstraint } = dims;
|
|
130
|
-
|
|
131
|
-
// Update main handle position
|
|
132
|
-
const percent = getPercentage(state.value);
|
|
133
|
-
const adjustedPercent = mapValueToVisualPercent(percent, edgeConstraint);
|
|
134
|
-
|
|
135
|
-
handle.style.left = `${adjustedPercent}%`;
|
|
136
|
-
handle.style.transform = 'translate(-50%, -50%)';
|
|
137
|
-
if (valueBubble) {
|
|
138
|
-
valueBubble.style.left = `${adjustedPercent}%`;
|
|
139
|
-
valueBubble.style.transform = 'translateX(-50%)';
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Update second handle if range slider
|
|
143
|
-
if (config.range && secondHandle && state.secondValue !== null) {
|
|
144
|
-
const secondPercent = getPercentage(state.secondValue);
|
|
145
|
-
const adjustedSecondPercent = mapValueToVisualPercent(secondPercent, edgeConstraint);
|
|
146
|
-
|
|
147
|
-
secondHandle.style.left = `${adjustedSecondPercent}%`;
|
|
148
|
-
secondHandle.style.transform = 'translate(-50%, -50%)';
|
|
149
|
-
if (secondValueBubble) {
|
|
150
|
-
secondValueBubble.style.left = `${adjustedSecondPercent}%`;
|
|
151
|
-
secondValueBubble.style.transform = 'translateX(-50%)';
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Update ARIA attributes
|
|
156
|
-
handle.setAttribute('aria-valuenow', String(state.value));
|
|
157
|
-
if (config.range && secondHandle && state.secondValue !== null) {
|
|
158
|
-
secondHandle.setAttribute('aria-valuenow', String(state.secondValue));
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Updates all track segments at once with optimized positioning
|
|
164
|
-
*/
|
|
165
|
-
const updateTrackSegments = () => {
|
|
166
|
-
if (!track || !container || !handle) return;
|
|
167
|
-
|
|
168
|
-
const dims = getTrackDimensions();
|
|
169
|
-
if (!dims) return;
|
|
170
|
-
|
|
171
|
-
const { handleSize, trackSize, paddingPercent } = dims;
|
|
172
|
-
const edgeConstraint = (handleSize / 2) / trackSize * 100;
|
|
173
|
-
|
|
174
|
-
if (config.range && state.secondValue !== null) {
|
|
175
|
-
// Range slider setup
|
|
176
|
-
const lowerValue = Math.min(state.value, state.secondValue);
|
|
177
|
-
const higherValue = Math.max(state.value, state.secondValue);
|
|
178
|
-
const lowerPercent = getPercentage(lowerValue);
|
|
179
|
-
const higherPercent = getPercentage(higherValue);
|
|
180
|
-
|
|
181
|
-
const adjustedLower = mapValueToVisualPercent(lowerPercent, edgeConstraint);
|
|
182
|
-
const adjustedHigher = mapValueToVisualPercent(higherPercent, edgeConstraint);
|
|
183
|
-
|
|
184
|
-
// Start track (before first handle)
|
|
185
|
-
if (lowerPercent > 1) {
|
|
186
|
-
startTrack.style.display = 'block';
|
|
187
|
-
startTrack.style.left = '0';
|
|
188
|
-
startTrack.style.right = `${100 - (adjustedLower - paddingPercent)}%`;
|
|
189
|
-
startTrack.style.width = 'auto';
|
|
190
|
-
} else {
|
|
191
|
-
startTrack.style.display = 'none';
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Active track (between handles)
|
|
195
|
-
const valueDiffPercent = Math.abs(higherPercent - lowerPercent);
|
|
196
|
-
const hideThreshold = (handleSize / trackSize) * 100;
|
|
197
|
-
|
|
198
|
-
if (valueDiffPercent <= hideThreshold) {
|
|
199
|
-
activeTrack.style.display = 'none';
|
|
200
|
-
} else {
|
|
201
|
-
activeTrack.style.display = 'block';
|
|
202
|
-
activeTrack.style.left = `${adjustedLower + paddingPercent}%`;
|
|
203
|
-
activeTrack.style.right = `${100 - (adjustedHigher - paddingPercent)}%`;
|
|
204
|
-
activeTrack.style.width = 'auto';
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Remaining track (after second handle)
|
|
208
|
-
remainingTrack.style.display = 'block';
|
|
209
|
-
remainingTrack.style.left = `${adjustedHigher + paddingPercent}%`;
|
|
210
|
-
remainingTrack.style.right = '0';
|
|
211
|
-
remainingTrack.style.width = 'auto';
|
|
212
|
-
} else {
|
|
213
|
-
// Single handle slider
|
|
214
|
-
const valuePercent = getPercentage(state.value);
|
|
215
|
-
const adjustedPercent = mapValueToVisualPercent(valuePercent, edgeConstraint);
|
|
216
|
-
|
|
217
|
-
// Hide start track for single slider
|
|
218
|
-
startTrack.style.display = 'none';
|
|
219
|
-
|
|
220
|
-
// Active track (filled part)
|
|
221
|
-
activeTrack.style.display = 'block';
|
|
222
|
-
activeTrack.style.left = '0';
|
|
223
|
-
activeTrack.style.right = `${100 - (adjustedPercent - paddingPercent)}%`;
|
|
224
|
-
activeTrack.style.width = 'auto';
|
|
225
|
-
|
|
226
|
-
// Remaining track (unfilled part)
|
|
227
|
-
remainingTrack.style.display = 'block';
|
|
228
|
-
remainingTrack.style.left = `${adjustedPercent + paddingPercent}%`;
|
|
229
|
-
remainingTrack.style.right = '0';
|
|
230
|
-
remainingTrack.style.width = 'auto';
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Updates value bubble content
|
|
236
|
-
*/
|
|
237
|
-
const updateValueBubbles = () => {
|
|
238
|
-
if (!valueBubble) return;
|
|
239
|
-
|
|
240
|
-
const formatter = config.valueFormatter || (value => value.toString());
|
|
241
|
-
valueBubble.textContent = formatter(state.value);
|
|
242
|
-
|
|
243
|
-
if (config.range && secondValueBubble && state.secondValue !== null) {
|
|
244
|
-
secondValueBubble.textContent = formatter(state.secondValue);
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Shows or hides value bubble
|
|
250
|
-
*/
|
|
251
|
-
const showValueBubble = (bubbleElement, show) => {
|
|
252
|
-
if (!bubbleElement || !config.showValue) return;
|
|
253
|
-
|
|
254
|
-
bubbleElement.classList[show ? 'add' : 'remove'](`${state.component.getClass('slider-value')}--visible`);
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Generates tick marks
|
|
259
|
-
*/
|
|
260
|
-
const generateTicks = () => {
|
|
261
|
-
if (!ticksContainer || !container) return;
|
|
262
|
-
|
|
263
|
-
// Clear existing ticks
|
|
264
|
-
while (ticksContainer.firstChild) {
|
|
265
|
-
ticksContainer.removeChild(ticksContainer.firstChild);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
state.ticks = [];
|
|
269
|
-
if (!config.ticks) return;
|
|
270
|
-
|
|
271
|
-
const numSteps = Math.floor((state.max - state.min) / state.step);
|
|
272
|
-
const tickValues = [];
|
|
273
|
-
|
|
274
|
-
// Generate tick values
|
|
275
|
-
for (let i = 0; i <= numSteps; i++) {
|
|
276
|
-
const value = state.min + (i * state.step);
|
|
277
|
-
if (value <= state.max) tickValues.push(value);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Ensure max value is included
|
|
281
|
-
if (tickValues[tickValues.length - 1] !== state.max) {
|
|
282
|
-
tickValues.push(state.max);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// CSS classes
|
|
286
|
-
const tickClass = state.component.getClass('slider-tick');
|
|
287
|
-
const activeClass = `${tickClass}--active`;
|
|
288
|
-
const inactiveClass = `${tickClass}--inactive`;
|
|
289
|
-
const hiddenClass = `${tickClass}--hidden`;
|
|
290
|
-
|
|
291
|
-
// Create tick elements
|
|
292
|
-
tickValues.forEach(value => {
|
|
293
|
-
const percent = getPercentage(value);
|
|
294
|
-
const tick = document.createElement('div');
|
|
295
|
-
tick.classList.add(tickClass);
|
|
296
|
-
tick.style.left = `${percent}%`;
|
|
297
|
-
|
|
298
|
-
// Determine tick active state
|
|
299
|
-
const isExactlySelected = (value === state.value ||
|
|
300
|
-
(config.range && state.secondValue !== null && value === state.secondValue));
|
|
301
|
-
|
|
302
|
-
if (isExactlySelected) {
|
|
303
|
-
tick.classList.add(hiddenClass);
|
|
304
|
-
} else if (config.range && state.secondValue !== null) {
|
|
305
|
-
const lowerValue = Math.min(state.value, state.secondValue);
|
|
306
|
-
const higherValue = Math.max(state.value, state.secondValue);
|
|
307
|
-
|
|
308
|
-
tick.classList.add(value >= lowerValue && value <= higherValue ? activeClass : inactiveClass);
|
|
309
|
-
} else {
|
|
310
|
-
tick.classList.add(value <= state.value ? activeClass : inactiveClass);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
ticksContainer.appendChild(tick);
|
|
314
|
-
state.ticks.push(tick);
|
|
315
|
-
});
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Updates active state of tick marks
|
|
320
|
-
*/
|
|
321
|
-
const updateTicks = () => {
|
|
322
|
-
if (!state.ticks || state.ticks.length === 0) return;
|
|
323
|
-
|
|
324
|
-
const tickClass = state.component.getClass('slider-tick');
|
|
325
|
-
const activeClass = `${tickClass}--active`;
|
|
326
|
-
const inactiveClass = `${tickClass}--inactive`;
|
|
327
|
-
const hiddenClass = `${tickClass}--hidden`;
|
|
328
|
-
|
|
329
|
-
state.ticks.forEach((tick, index) => {
|
|
330
|
-
// Calculate the value for this tick
|
|
331
|
-
const tickValue = state.min + (index * state.step);
|
|
332
|
-
|
|
333
|
-
// Reset visibility first
|
|
334
|
-
tick.classList.remove(hiddenClass);
|
|
335
|
-
|
|
336
|
-
// Check if this tick should be hidden (matches exactly a selected value)
|
|
337
|
-
const isExactlySelected = (tickValue === state.value ||
|
|
338
|
-
(config.range && state.secondValue !== null && tickValue === state.secondValue));
|
|
339
|
-
|
|
340
|
-
if (isExactlySelected) {
|
|
341
|
-
tick.classList.add(hiddenClass);
|
|
342
|
-
} else if (config.range && state.secondValue !== null) {
|
|
343
|
-
// Range slider - ticks between values should be active
|
|
344
|
-
const lowerValue = Math.min(state.value, state.secondValue);
|
|
345
|
-
const higherValue = Math.max(state.value, state.secondValue);
|
|
346
|
-
|
|
347
|
-
if (tickValue >= lowerValue && tickValue <= higherValue) {
|
|
348
|
-
tick.classList.add(activeClass);
|
|
349
|
-
tick.classList.remove(inactiveClass);
|
|
350
|
-
} else {
|
|
351
|
-
tick.classList.remove(activeClass);
|
|
352
|
-
tick.classList.add(inactiveClass);
|
|
353
|
-
}
|
|
354
|
-
} else {
|
|
355
|
-
// Single slider - ticks below value should be active
|
|
356
|
-
if (tickValue <= state.value) {
|
|
357
|
-
tick.classList.add(activeClass);
|
|
358
|
-
tick.classList.remove(inactiveClass);
|
|
359
|
-
} else {
|
|
360
|
-
tick.classList.remove(activeClass);
|
|
361
|
-
tick.classList.add(inactiveClass);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Updates all UI elements
|
|
369
|
-
*/
|
|
370
|
-
const updateUi = () => {
|
|
371
|
-
updateHandlePositions();
|
|
372
|
-
updateTrackSegments();
|
|
373
|
-
updateValueBubbles();
|
|
374
|
-
updateTicks();
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
// Return consolidated helper methods
|
|
378
|
-
return {
|
|
379
|
-
getPercentage,
|
|
380
|
-
getValueFromPosition,
|
|
381
|
-
roundToStep,
|
|
382
|
-
clamp,
|
|
383
|
-
showValueBubble,
|
|
384
|
-
generateTicks,
|
|
385
|
-
updateTicks,
|
|
386
|
-
updateUi
|
|
387
|
-
};
|
|
388
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// src/components/textfield/constants.ts
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Textfield visual variants
|
|
5
|
-
*/
|
|
6
|
-
export const TEXTFIELD_VARIANTS = {
|
|
7
|
-
FILLED: 'filled',
|
|
8
|
-
OUTLINED: 'outlined'
|
|
9
|
-
} as const;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Textfield input types
|
|
13
|
-
*/
|
|
14
|
-
export const TEXTFIELD_TYPES = {
|
|
15
|
-
TEXT: 'text',
|
|
16
|
-
PASSWORD: 'password',
|
|
17
|
-
EMAIL: 'email',
|
|
18
|
-
NUMBER: 'number',
|
|
19
|
-
TEL: 'tel',
|
|
20
|
-
URL: 'url',
|
|
21
|
-
SEARCH: 'search',
|
|
22
|
-
MULTILINE: 'multiline'
|
|
23
|
-
} as const;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Validation schema for textfield configuration
|
|
27
|
-
*/
|
|
28
|
-
export const TEXTFIELD_SCHEMA = {
|
|
29
|
-
type: {
|
|
30
|
-
type: 'string',
|
|
31
|
-
enum: Object.values(TEXTFIELD_TYPES),
|
|
32
|
-
required: false
|
|
33
|
-
},
|
|
34
|
-
variant: {
|
|
35
|
-
type: 'string',
|
|
36
|
-
enum: Object.values(TEXTFIELD_VARIANTS),
|
|
37
|
-
required: false
|
|
38
|
-
},
|
|
39
|
-
name: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
required: false
|
|
42
|
-
},
|
|
43
|
-
label: {
|
|
44
|
-
type: 'string',
|
|
45
|
-
required: false
|
|
46
|
-
},
|
|
47
|
-
placeholder: {
|
|
48
|
-
type: 'string',
|
|
49
|
-
required: false
|
|
50
|
-
},
|
|
51
|
-
value: {
|
|
52
|
-
type: 'string',
|
|
53
|
-
required: false
|
|
54
|
-
},
|
|
55
|
-
required: {
|
|
56
|
-
type: 'boolean',
|
|
57
|
-
required: false
|
|
58
|
-
},
|
|
59
|
-
disabled: {
|
|
60
|
-
type: 'boolean',
|
|
61
|
-
required: false
|
|
62
|
-
},
|
|
63
|
-
maxLength: {
|
|
64
|
-
type: 'number',
|
|
65
|
-
required: false
|
|
66
|
-
},
|
|
67
|
-
pattern: {
|
|
68
|
-
type: 'string',
|
|
69
|
-
required: false
|
|
70
|
-
},
|
|
71
|
-
autocomplete: {
|
|
72
|
-
type: 'string',
|
|
73
|
-
required: false
|
|
74
|
-
},
|
|
75
|
-
class: {
|
|
76
|
-
type: 'string',
|
|
77
|
-
required: false
|
|
78
|
-
}
|
|
79
|
-
} as const;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Textfield state classes
|
|
83
|
-
*/
|
|
84
|
-
export const TEXTFIELD_STATES = {
|
|
85
|
-
FOCUSED: 'focused',
|
|
86
|
-
FILLED: 'filled',
|
|
87
|
-
DISABLED: 'disabled',
|
|
88
|
-
INVALID: 'invalid'
|
|
89
|
-
} as const;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Textfield element classes
|
|
93
|
-
*/
|
|
94
|
-
export const TEXTFIELD_CLASSES = {
|
|
95
|
-
ROOT: 'textfield',
|
|
96
|
-
INPUT: 'textfield-input',
|
|
97
|
-
LABEL: 'textfield-label',
|
|
98
|
-
HELPER: 'textfield-helper',
|
|
99
|
-
COUNTER: 'textfield-counter'
|
|
100
|
-
} as const;
|
package/src/core/layout/index.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { isObject } from '../utils'
|
|
2
|
-
|
|
3
|
-
const createComponent = (Component, options = {}) => {
|
|
4
|
-
// Check if Component is a class (has prototype) or function
|
|
5
|
-
const isClass = Component.prototype && Component.prototype.constructor === Component
|
|
6
|
-
|
|
7
|
-
if (isClass) {
|
|
8
|
-
return new Component(options)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return Component(options)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Recursively creates components based on a provided schema.
|
|
16
|
-
*
|
|
17
|
-
* @param {Array} schema - An array of components or sub-schemas.
|
|
18
|
-
* @param {HTMLElement} container - The container for the current level of components.
|
|
19
|
-
* @param {Object} [structure={}] - An accumulator object for components, keyed by name.
|
|
20
|
-
* @param {number} [level=0] - The current level of recursion.
|
|
21
|
-
* @returns {Object} The structure containing all created components.
|
|
22
|
-
*/
|
|
23
|
-
const createLayout = (schema, container, structure = {}, level = 0, components = []) => {
|
|
24
|
-
level++
|
|
25
|
-
let component
|
|
26
|
-
const object = {}
|
|
27
|
-
const fragment = document.createDocumentFragment()
|
|
28
|
-
|
|
29
|
-
if (!Array.isArray(schema)) {
|
|
30
|
-
console.error('Schema is not an array!', container, level, schema)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (let i = 0; i < schema.length; i++) {
|
|
34
|
-
let name
|
|
35
|
-
let options = {}
|
|
36
|
-
|
|
37
|
-
if (schema[i] instanceof Object && typeof schema[i] === 'function') {
|
|
38
|
-
if (isObject(schema[i + 1])) {
|
|
39
|
-
options = schema[i + 1]
|
|
40
|
-
} else if (isObject(schema[i + 2])) {
|
|
41
|
-
options = schema[i + 2]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (options.id) {
|
|
45
|
-
name = options.id
|
|
46
|
-
} else if (typeof schema[i + 1] === 'string') {
|
|
47
|
-
name = schema[i + 1]
|
|
48
|
-
if (!schema[i].isElement && !schema[i].isComponent) {
|
|
49
|
-
options.name = name
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
component = createComponent(schema[i], options)
|
|
54
|
-
|
|
55
|
-
const element = component.element || component
|
|
56
|
-
if (level === 1) structure.element = element
|
|
57
|
-
|
|
58
|
-
if (name) {
|
|
59
|
-
structure[name] = component
|
|
60
|
-
components.push([name, component])
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (component) {
|
|
64
|
-
if (component.insert) component.insert(fragment)
|
|
65
|
-
else fragment.appendChild(element)
|
|
66
|
-
|
|
67
|
-
if (container) {
|
|
68
|
-
// console.log('container', container)
|
|
69
|
-
component._container = container
|
|
70
|
-
if (component.onInserted) component.onInserted(container)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
} else if (Array.isArray(schema[i])) {
|
|
74
|
-
if (!component) component = container
|
|
75
|
-
createLayout(schema[i], component, structure, level, components)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (container && fragment.hasChildNodes()) {
|
|
80
|
-
const wrapper = container.element || container
|
|
81
|
-
wrapper.appendChild(fragment)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function get (name) {
|
|
85
|
-
return structure[name] || null
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
object.component = structure
|
|
89
|
-
object.components = components
|
|
90
|
-
object.get = get
|
|
91
|
-
|
|
92
|
-
return object
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export default createLayout
|