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.
Files changed (42) hide show
  1. package/index.ts +2 -0
  2. package/package.json +1 -1
  3. package/src/components/navigation/api.ts +131 -96
  4. package/src/components/navigation/features/controller.ts +273 -0
  5. package/src/components/navigation/features/items.ts +133 -64
  6. package/src/components/navigation/navigation.ts +17 -2
  7. package/src/components/navigation/system-types.ts +124 -0
  8. package/src/components/navigation/system.ts +776 -0
  9. package/src/components/slider/config.ts +20 -2
  10. package/src/components/slider/features/controller.ts +761 -0
  11. package/src/components/slider/features/handlers.ts +18 -15
  12. package/src/components/slider/features/index.ts +3 -2
  13. package/src/components/slider/features/range.ts +104 -0
  14. package/src/components/slider/slider.ts +34 -14
  15. package/src/components/slider/structure.ts +152 -0
  16. package/src/components/textfield/api.ts +53 -0
  17. package/src/components/textfield/features.ts +322 -0
  18. package/src/components/textfield/textfield.ts +8 -0
  19. package/src/components/textfield/types.ts +12 -3
  20. package/src/components/timepicker/clockdial.ts +1 -4
  21. package/src/core/compose/features/textinput.ts +15 -2
  22. package/src/core/composition/features/dom.ts +33 -0
  23. package/src/core/composition/features/icon.ts +131 -0
  24. package/src/core/composition/features/index.ts +11 -0
  25. package/src/core/composition/features/label.ts +156 -0
  26. package/src/core/composition/features/structure.ts +22 -0
  27. package/src/core/composition/index.ts +26 -0
  28. package/src/core/index.ts +1 -1
  29. package/src/core/structure.ts +288 -0
  30. package/src/index.ts +1 -0
  31. package/src/styles/components/_navigation-mobile.scss +244 -0
  32. package/src/styles/components/_navigation-system.scss +151 -0
  33. package/src/styles/components/_textfield.scss +250 -11
  34. package/demo/build.ts +0 -349
  35. package/demo/index.html +0 -110
  36. package/demo/main.js +0 -448
  37. package/demo/styles.css +0 -239
  38. package/server.ts +0 -86
  39. package/src/components/slider/features/slider.ts +0 -318
  40. package/src/components/slider/features/structure.ts +0 -181
  41. package/src/components/slider/features/ui.ts +0 -388
  42. package/src/components/textfield/constants.ts +0 -100
@@ -1,181 +0,0 @@
1
- // src/components/slider/features/structure.ts
2
- import { SLIDER_COLORS, SLIDER_SIZES } from '../constants';
3
- import { SliderConfig } from '../types';
4
- import createLayout from '../../../core/layout';
5
- import { createElement } from '../../../core/dom/create';
6
-
7
- /**
8
- * Creates the slider DOM structure using layout system
9
- * @param config Slider configuration
10
- * @returns Component enhancer with DOM structure
11
- */
12
- export const withStructure = (config: SliderConfig) => component => {
13
- // Set default values
14
- const min = config.min || 0;
15
- const max = config.max || 100;
16
- const value = config.value !== undefined ? config.value : min;
17
- const secondValue = config.secondValue !== undefined ? config.secondValue : null;
18
- const isRangeSlider = config.range && secondValue !== null;
19
- const isDisabled = config.disabled === true;
20
-
21
- // Format the values
22
- const formatter = config.valueFormatter || (val => val.toString());
23
-
24
- // Get prefixed class names
25
- const getClass = (className) => component.getClass(className);
26
-
27
- // Define slider structure
28
- const structure = [
29
- [createElement, 'container', {
30
- className: getClass('slider-container')
31
- }, [
32
- // Track with segments
33
- [createElement, 'track', {
34
- className: getClass('slider-track')
35
- }, [
36
- [createElement, 'startTrack', {
37
- className: getClass('slider-start-track')
38
- }],
39
- [createElement, 'activeTrack', {
40
- className: getClass('slider-active-track')
41
- }],
42
- [createElement, 'remainingTrack', {
43
- className: getClass('slider-remaining-track')
44
- }]
45
- ]],
46
-
47
- // Ticks container
48
- [createElement, 'ticksContainer', {
49
- className: getClass('slider-ticks-container')
50
- }],
51
-
52
- // Dots for ends
53
- [createElement, 'startDot', {
54
- className: [
55
- getClass('slider-dot'),
56
- getClass('slider-dot--start')
57
- ]
58
- }],
59
- [createElement, 'endDot', {
60
- className: [
61
- getClass('slider-dot'),
62
- getClass('slider-dot--end')
63
- ]
64
- }],
65
-
66
- // Main handle
67
- [createElement, 'handle', {
68
- className: getClass('slider-handle'),
69
- attrs: {
70
- 'role': 'slider',
71
- 'aria-valuemin': String(min),
72
- 'aria-valuemax': String(max),
73
- 'aria-valuenow': String(value),
74
- 'aria-orientation': 'horizontal',
75
- 'tabindex': isDisabled ? '-1' : '0',
76
- 'aria-disabled': isDisabled ? 'true' : 'false'
77
- },
78
- style: {
79
- left: `${((value - min) / (max - min)) * 100}%`
80
- }
81
- }],
82
-
83
- // Main value bubble
84
- [createElement, 'valueBubble', {
85
- className: getClass('slider-value'),
86
- text: formatter(value)
87
- }]
88
- ]]
89
- ];
90
-
91
- // Add second handle and bubble for range slider
92
- if (isRangeSlider) {
93
- const secondHandlePos = ((secondValue - min) / (max - min)) * 100;
94
-
95
- // Add second handle to structure
96
- structure[0][3].push(
97
- [createElement, 'secondHandle', {
98
- className: getClass('slider-handle'),
99
- attrs: {
100
- 'role': 'slider',
101
- 'aria-valuemin': String(min),
102
- 'aria-valuemax': String(max),
103
- 'aria-valuenow': String(secondValue),
104
- 'aria-orientation': 'horizontal',
105
- 'tabindex': isDisabled ? '-1' : '0',
106
- 'aria-disabled': isDisabled ? 'true' : 'false'
107
- },
108
- style: {
109
- left: `${secondHandlePos}%`
110
- }
111
- }]
112
- );
113
-
114
- // Add second bubble to structure
115
- structure[0][3].push(
116
- [createElement, 'secondValueBubble', {
117
- className: getClass('slider-value'),
118
- text: formatter(secondValue)
119
- }]
120
- );
121
- }
122
-
123
- // Create layout and get structure elements
124
- const components = createLayout(structure, component.element).component;
125
-
126
- // Add component base class and accessibility attributes
127
- component.element.classList.add(component.getClass('slider'));
128
- component.element.setAttribute('tabindex', '-1');
129
- component.element.setAttribute('role', 'none');
130
- component.element.setAttribute('aria-disabled', isDisabled ? 'true' : 'false');
131
-
132
- // Position any icon properly
133
- const iconElement = component.element.querySelector(`.${component.getClass('icon')}`);
134
- if (iconElement && config.label) {
135
- iconElement.classList.add(component.getClass('slider-icon'));
136
- component.element.classList.add(component.getClass('slider--icon'));
137
- }
138
-
139
- // Apply style classes
140
- applyStyleClasses(component, config, isRangeSlider, isDisabled);
141
-
142
- // Return enhanced component with structure
143
- return {
144
- ...component,
145
- structure: components
146
- };
147
- };
148
-
149
- /**
150
- * Applies style classes based on configuration
151
- */
152
- function applyStyleClasses(component, config, isRangeSlider, isDisabled) {
153
- const baseClass = component.getClass('slider');
154
-
155
- // Apply size class
156
- const size = config.size || SLIDER_SIZES.MEDIUM;
157
- if (size !== SLIDER_SIZES.MEDIUM) {
158
- component.element.classList.add(`${baseClass}--${size}`);
159
- }
160
-
161
- // Apply color class
162
- const color = config.color || SLIDER_COLORS.PRIMARY;
163
- if (color !== SLIDER_COLORS.PRIMARY) {
164
- component.element.classList.add(`${baseClass}--${color}`);
165
- }
166
-
167
- // Apply discrete class if step is specified
168
- if (config.step !== undefined && config.step > 0) {
169
- component.element.classList.add(`${baseClass}--discrete`);
170
- }
171
-
172
- // Apply disabled class if needed
173
- if (isDisabled) {
174
- component.element.classList.add(`${baseClass}--disabled`);
175
- }
176
-
177
- // Apply range class if needed
178
- if (isRangeSlider) {
179
- component.element.classList.add(`${baseClass}--range`);
180
- }
181
- }
@@ -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;