mtrl 0.2.5 → 0.2.7

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 (196) hide show
  1. package/index.ts +18 -0
  2. package/package.json +1 -1
  3. package/src/components/badge/_styles.scss +123 -115
  4. package/src/components/badge/api.ts +57 -59
  5. package/src/components/badge/badge.ts +16 -2
  6. package/src/components/badge/config.ts +65 -11
  7. package/src/components/badge/constants.ts +22 -12
  8. package/src/components/badge/features.ts +44 -40
  9. package/src/components/badge/types.ts +42 -30
  10. package/src/components/bottom-app-bar/_styles.scss +103 -0
  11. package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
  12. package/src/components/bottom-app-bar/config.ts +73 -0
  13. package/src/components/bottom-app-bar/index.ts +11 -0
  14. package/src/components/bottom-app-bar/types.ts +108 -0
  15. package/src/components/button/_styles.scss +0 -66
  16. package/src/components/button/api.ts +5 -0
  17. package/src/components/button/button.ts +0 -2
  18. package/src/components/button/config.ts +5 -0
  19. package/src/components/button/constants.ts +0 -6
  20. package/src/components/button/index.ts +2 -2
  21. package/src/components/button/types.ts +7 -7
  22. package/src/components/card/_styles.scss +67 -25
  23. package/src/components/card/api.ts +54 -3
  24. package/src/components/card/card.ts +25 -6
  25. package/src/components/card/config.ts +189 -22
  26. package/src/components/card/constants.ts +20 -19
  27. package/src/components/card/content.ts +299 -2
  28. package/src/components/card/features.ts +158 -4
  29. package/src/components/card/index.ts +31 -9
  30. package/src/components/card/types.ts +166 -15
  31. package/src/components/checkbox/_styles.scss +0 -2
  32. package/src/components/chip/chip.ts +1 -9
  33. package/src/components/chip/constants.ts +0 -10
  34. package/src/components/chip/index.ts +1 -1
  35. package/src/components/chip/types.ts +1 -4
  36. package/src/components/datepicker/_styles.scss +358 -0
  37. package/src/components/datepicker/api.ts +272 -0
  38. package/src/components/datepicker/config.ts +144 -0
  39. package/src/components/datepicker/constants.ts +98 -0
  40. package/src/components/datepicker/datepicker.ts +346 -0
  41. package/src/components/datepicker/index.ts +9 -0
  42. package/src/components/datepicker/render.ts +452 -0
  43. package/src/components/datepicker/types.ts +268 -0
  44. package/src/components/datepicker/utils.ts +290 -0
  45. package/src/components/dialog/_styles.scss +174 -128
  46. package/src/components/dialog/api.ts +48 -13
  47. package/src/components/dialog/config.ts +9 -5
  48. package/src/components/dialog/dialog.ts +6 -3
  49. package/src/components/dialog/features.ts +290 -130
  50. package/src/components/dialog/types.ts +7 -4
  51. package/src/components/divider/_styles.scss +57 -0
  52. package/src/components/divider/config.ts +81 -0
  53. package/src/components/divider/divider.ts +37 -0
  54. package/src/components/divider/features.ts +207 -0
  55. package/src/components/divider/index.ts +5 -0
  56. package/src/components/divider/types.ts +55 -0
  57. package/src/components/extended-fab/_styles.scss +267 -0
  58. package/src/components/extended-fab/api.ts +141 -0
  59. package/src/components/extended-fab/config.ts +108 -0
  60. package/src/components/extended-fab/constants.ts +36 -0
  61. package/src/components/extended-fab/extended-fab.ts +125 -0
  62. package/src/components/extended-fab/index.ts +4 -0
  63. package/src/components/extended-fab/types.ts +287 -0
  64. package/src/components/fab/_styles.scss +225 -0
  65. package/src/components/fab/api.ts +97 -0
  66. package/src/components/fab/config.ts +94 -0
  67. package/src/components/fab/constants.ts +41 -0
  68. package/src/components/fab/fab.ts +67 -0
  69. package/src/components/fab/index.ts +4 -0
  70. package/src/components/fab/types.ts +234 -0
  71. package/src/components/navigation/_styles.scss +1 -0
  72. package/src/components/navigation/api.ts +78 -50
  73. package/src/components/navigation/features/items.ts +280 -0
  74. package/src/components/navigation/nav-item.ts +72 -23
  75. package/src/components/navigation/navigation.ts +54 -2
  76. package/src/components/navigation/types.ts +210 -188
  77. package/src/components/progress/_styles.scss +0 -65
  78. package/src/components/progress/config.ts +1 -2
  79. package/src/components/progress/constants.ts +0 -14
  80. package/src/components/progress/index.ts +1 -1
  81. package/src/components/progress/progress.ts +1 -4
  82. package/src/components/progress/types.ts +1 -4
  83. package/src/components/radios/_styles.scss +0 -45
  84. package/src/components/radios/api.ts +85 -60
  85. package/src/components/radios/config.ts +1 -2
  86. package/src/components/radios/constants.ts +0 -9
  87. package/src/components/radios/index.ts +1 -1
  88. package/src/components/radios/radio.ts +34 -11
  89. package/src/components/radios/radios.ts +2 -1
  90. package/src/components/radios/types.ts +1 -7
  91. package/src/components/search/_styles.scss +306 -0
  92. package/src/components/search/api.ts +203 -0
  93. package/src/components/search/config.ts +87 -0
  94. package/src/components/search/constants.ts +21 -0
  95. package/src/components/search/features/index.ts +4 -0
  96. package/src/components/search/features/search.ts +718 -0
  97. package/src/components/search/features/states.ts +165 -0
  98. package/src/components/search/features/structure.ts +198 -0
  99. package/src/components/search/index.ts +10 -0
  100. package/src/components/search/search.ts +52 -0
  101. package/src/components/search/types.ts +163 -0
  102. package/src/components/segmented-button/_styles.scss +117 -0
  103. package/src/components/segmented-button/config.ts +67 -0
  104. package/src/components/segmented-button/constants.ts +42 -0
  105. package/src/components/segmented-button/index.ts +4 -0
  106. package/src/components/segmented-button/segment.ts +155 -0
  107. package/src/components/segmented-button/segmented-button.ts +250 -0
  108. package/src/components/segmented-button/types.ts +219 -0
  109. package/src/components/slider/_styles.scss +221 -168
  110. package/src/components/slider/accessibility.md +59 -0
  111. package/src/components/slider/api.ts +41 -120
  112. package/src/components/slider/config.ts +51 -49
  113. package/src/components/slider/features/handlers.ts +495 -0
  114. package/src/components/slider/features/index.ts +1 -2
  115. package/src/components/slider/features/slider.ts +66 -84
  116. package/src/components/slider/features/states.ts +195 -0
  117. package/src/components/slider/features/structure.ts +141 -184
  118. package/src/components/slider/features/ui.ts +150 -201
  119. package/src/components/slider/index.ts +2 -11
  120. package/src/components/slider/slider.ts +9 -12
  121. package/src/components/slider/types.ts +39 -24
  122. package/src/components/switch/_styles.scss +0 -2
  123. package/src/components/tabs/_styles.scss +346 -154
  124. package/src/components/tabs/api.ts +178 -400
  125. package/src/components/tabs/config.ts +46 -52
  126. package/src/components/tabs/constants.ts +85 -8
  127. package/src/components/tabs/features.ts +403 -0
  128. package/src/components/tabs/index.ts +60 -3
  129. package/src/components/tabs/indicator.ts +285 -0
  130. package/src/components/tabs/responsive.ts +144 -0
  131. package/src/components/tabs/scroll-indicators.ts +149 -0
  132. package/src/components/tabs/state.ts +186 -0
  133. package/src/components/tabs/tab-api.ts +258 -0
  134. package/src/components/tabs/tab.ts +255 -0
  135. package/src/components/tabs/tabs.ts +50 -31
  136. package/src/components/tabs/types.ts +332 -128
  137. package/src/components/tabs/utils.ts +107 -0
  138. package/src/components/textfield/_styles.scss +0 -98
  139. package/src/components/textfield/config.ts +2 -3
  140. package/src/components/textfield/constants.ts +0 -14
  141. package/src/components/textfield/index.ts +2 -2
  142. package/src/components/textfield/textfield.ts +0 -2
  143. package/src/components/textfield/types.ts +1 -4
  144. package/src/components/timepicker/README.md +277 -0
  145. package/src/components/timepicker/_styles.scss +451 -0
  146. package/src/components/timepicker/api.ts +632 -0
  147. package/src/components/timepicker/clockdial.ts +482 -0
  148. package/src/components/timepicker/config.ts +130 -0
  149. package/src/components/timepicker/constants.ts +138 -0
  150. package/src/components/timepicker/index.ts +8 -0
  151. package/src/components/timepicker/render.ts +613 -0
  152. package/src/components/timepicker/timepicker.ts +117 -0
  153. package/src/components/timepicker/types.ts +336 -0
  154. package/src/components/timepicker/utils.ts +241 -0
  155. package/src/components/top-app-bar/_styles.scss +225 -0
  156. package/src/components/top-app-bar/config.ts +83 -0
  157. package/src/components/top-app-bar/index.ts +11 -0
  158. package/src/components/top-app-bar/top-app-bar.ts +316 -0
  159. package/src/components/top-app-bar/types.ts +140 -0
  160. package/src/core/build/_ripple.scss +6 -6
  161. package/src/core/build/ripple.ts +72 -95
  162. package/src/core/compose/component.ts +1 -1
  163. package/src/core/compose/features/badge.ts +79 -0
  164. package/src/core/compose/features/icon.ts +3 -1
  165. package/src/core/compose/features/index.ts +3 -1
  166. package/src/core/compose/features/ripple.ts +4 -1
  167. package/src/core/compose/features/textlabel.ts +26 -2
  168. package/src/core/dom/create.ts +5 -0
  169. package/src/index.ts +9 -0
  170. package/src/styles/abstract/_theme.scss +115 -3
  171. package/src/styles/themes/_autumn.scss +21 -0
  172. package/src/styles/themes/_base-theme.scss +61 -0
  173. package/src/styles/themes/_baseline.scss +58 -0
  174. package/src/styles/themes/_bluekhaki.scss +125 -0
  175. package/src/styles/themes/_brownbeige.scss +125 -0
  176. package/src/styles/themes/_browngreen.scss +125 -0
  177. package/src/styles/themes/_forest.scss +6 -0
  178. package/src/styles/themes/_greenbeige.scss +125 -0
  179. package/src/styles/themes/_material.scss +125 -0
  180. package/src/styles/themes/_ocean.scss +6 -0
  181. package/src/styles/themes/_sageivory.scss +125 -0
  182. package/src/styles/themes/_spring.scss +6 -0
  183. package/src/styles/themes/_summer.scss +5 -0
  184. package/src/styles/themes/_sunset.scss +5 -0
  185. package/src/styles/themes/_tealcaramel.scss +125 -0
  186. package/src/styles/themes/_winter.scss +6 -0
  187. package/src/components/card/actions.ts +0 -48
  188. package/src/components/card/header.ts +0 -88
  189. package/src/components/card/media.ts +0 -52
  190. package/src/components/navigation/features/items.js +0 -192
  191. package/src/components/slider/features/appearance.ts +0 -94
  192. package/src/components/slider/features/disabled.ts +0 -43
  193. package/src/components/slider/features/events.ts +0 -164
  194. package/src/components/slider/features/interactions.ts +0 -261
  195. package/src/components/slider/features/keyboard.ts +0 -112
  196. package/src/core/collection/adapters/mongodb.js +0 -232
@@ -2,7 +2,7 @@
2
2
  import { SliderConfig } from '../types';
3
3
 
4
4
  /**
5
- * Create UI update helpers for slider component with MD3 enhancements
5
+ * Create optimized UI update helpers for slider component
6
6
  *
7
7
  * @param config Slider configuration
8
8
  * @param state Slider state object
@@ -12,19 +12,29 @@ export const createUiHelpers = (config: SliderConfig, state) => {
12
12
  // Return empty implementations if component structure is missing
13
13
  if (!state.component?.structure) {
14
14
  console.error('Cannot create UI helpers: component structure is missing');
15
- return Object.fromEntries(['getPercentage', 'getValueFromPosition', 'roundToStep',
16
- 'clamp', 'setThumbPosition', 'updateActiveTrack', 'updateStartTrack',
17
- 'updateRemainingTrack', 'updateThumbPositions', 'updateValueBubbles',
18
- 'showValueBubble', 'generateTicks', 'updateTicks', 'updateUi']
19
- .map(method => [method, method === 'clamp' ? (v, min, max) => Math.min(Math.max(v, min), max) :
20
- method === 'roundToStep' ? v => v :
21
- method === 'getPercentage' || method === 'getValueFromPosition' ? () => 0 :
22
- () => {}]));
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
+ };
23
25
  }
24
26
 
25
27
  const {
26
- track, activeTrack, startTrack, remainingTrack, thumb,
27
- valueBubble, secondThumb, secondValueBubble, ticksContainer
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
28
38
  } = state.component.structure;
29
39
 
30
40
  /**
@@ -39,21 +49,22 @@ export const createUiHelpers = (config: SliderConfig, state) => {
39
49
  * Gets track dimensions and constraints for positioning calculations
40
50
  */
41
51
  const getTrackDimensions = () => {
42
- if (!track || !thumb) return null;
52
+ if (!track || !handle || !container) return null;
43
53
 
44
- const thumbRect = thumb.getBoundingClientRect();
45
- const trackRect = track.getBoundingClientRect();
46
- const thumbSize = thumbRect.width || 20;
54
+ const handleRect = handle.getBoundingClientRect();
55
+ const trackRect = container.getBoundingClientRect();
56
+ const handleSize = handleRect.width || 20;
47
57
  const trackSize = trackRect.width;
48
58
 
49
- const edgeConstraint = (thumbSize / 2) / trackSize * 100;
50
- const paddingPercent = (8 / trackSize) * 100; // 8px padding
59
+ const edgeConstraint = (handleSize / 2) / trackSize * 100;
60
+ const paddingPixels = state.activeHandle ? 6 : 8;
61
+ const paddingPercent = (paddingPixels / trackSize) * 100;
51
62
 
52
- return { thumbSize, trackSize, edgeConstraint, paddingPercent };
63
+ return { handleSize, trackSize, edgeConstraint, paddingPercent };
53
64
  };
54
65
 
55
66
  /**
56
- * Map value percentage to visual position with edge constraints
67
+ * Maps value percentage to visual position with edge constraints
57
68
  */
58
69
  const mapValueToVisualPercent = (valuePercent, edgeConstraint) => {
59
70
  const minEdge = edgeConstraint;
@@ -69,17 +80,15 @@ export const createUiHelpers = (config: SliderConfig, state) => {
69
80
  * Gets slider value from a position on the track
70
81
  */
71
82
  const getValueFromPosition = (position) => {
72
- if (!track) return state.min;
83
+ if (!track || !container) return state.min;
73
84
 
74
85
  try {
75
- const trackRect = track.getBoundingClientRect();
86
+ const containerRect = container.getBoundingClientRect();
76
87
  const range = state.max - state.min;
88
+ const handleWidth = handle.getBoundingClientRect().width || 20;
77
89
 
78
- const thumbRect = thumb.getBoundingClientRect();
79
- const thumbWidth = thumbRect.width || 20;
80
-
81
- const leftEdge = trackRect.left + (thumbWidth / 2);
82
- const rightEdge = trackRect.right - (thumbWidth / 2);
90
+ const leftEdge = containerRect.left + (handleWidth / 2);
91
+ const rightEdge = containerRect.right - (handleWidth / 2);
83
92
  const effectiveWidth = rightEdge - leftEdge;
84
93
 
85
94
  const adjustedPosition = Math.max(leftEdge, Math.min(rightEdge, position));
@@ -109,147 +118,116 @@ export const createUiHelpers = (config: SliderConfig, state) => {
109
118
  const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
110
119
 
111
120
  /**
112
- * Sets thumb position based on a value percentage with proper edge mapping
121
+ * Updates handle and bubble positions and transforms
113
122
  */
114
- const setThumbPosition = (thumbElement, bubbleElement, valuePercent) => {
115
- if (!thumbElement || !track) return;
123
+ const updateHandlePositions = () => {
124
+ if (!handle || !container) return;
116
125
 
117
126
  const dims = getTrackDimensions();
118
127
  if (!dims) return;
119
128
 
120
- const { thumbSize, trackSize } = dims;
121
- const edgeConstraint = (thumbSize / 2) / trackSize * 100;
122
- const adjustedPercent = mapValueToVisualPercent(valuePercent, edgeConstraint);
129
+ const { edgeConstraint } = dims;
123
130
 
124
- thumbElement.style.left = `${adjustedPercent}%`;
125
- thumbElement.style.transform = 'translate(-50%, -50%)';
131
+ // Update main handle position
132
+ const percent = getPercentage(state.value);
133
+ const adjustedPercent = mapValueToVisualPercent(percent, edgeConstraint);
126
134
 
127
- if (bubbleElement) {
128
- bubbleElement.style.left = `${adjustedPercent}%`;
129
- bubbleElement.style.transform = 'translateX(-50%)';
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%)';
130
140
  }
131
- };
132
-
133
- /**
134
- * Updates start track styles
135
- */
136
- const updateStartTrack = () => {
137
- if (!startTrack || !track || !thumb) return;
138
-
139
- const dims = getTrackDimensions();
140
- if (!dims) return;
141
-
142
- const { thumbSize, trackSize, paddingPercent } = dims;
143
141
 
144
- if (config.range && state.secondValue !== null) {
145
- const lowerValue = Math.min(state.value, state.secondValue);
146
- const lowerPercent = getPercentage(lowerValue);
147
-
148
- const edgeConstraint = (thumbSize / 2) / trackSize * 100;
149
- const adjustedPercent = mapValueToVisualPercent(lowerPercent, edgeConstraint);
150
- const finalPercent = Math.max(0, adjustedPercent - paddingPercent);
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);
151
146
 
152
- startTrack.style.display = 'block';
153
- startTrack.style.width = `${finalPercent}%`;
154
- startTrack.style.left = '0';
155
- startTrack.style.height = '100%';
156
- } else {
157
- startTrack.style.display = 'none';
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));
158
159
  }
159
160
  };
160
-
161
+
161
162
  /**
162
- * Updates active track styles
163
+ * Updates all track segments at once with optimized positioning
163
164
  */
164
- const updateActiveTrack = () => {
165
- if (!activeTrack || !track || !thumb) return;
165
+ const updateTrackSegments = () => {
166
+ if (!track || !container || !handle) return;
166
167
 
167
168
  const dims = getTrackDimensions();
168
169
  if (!dims) return;
169
170
 
170
- const { thumbSize, trackSize, paddingPercent } = dims;
171
- const edgeConstraint = (thumbSize / 2) / trackSize * 100;
171
+ const { handleSize, trackSize, paddingPercent } = dims;
172
+ const edgeConstraint = (handleSize / 2) / trackSize * 100;
172
173
 
173
174
  if (config.range && state.secondValue !== null) {
174
- // Range slider (two thumbs)
175
+ // Range slider setup
175
176
  const lowerValue = Math.min(state.value, state.secondValue);
176
177
  const higherValue = Math.max(state.value, state.secondValue);
177
178
  const lowerPercent = getPercentage(lowerValue);
178
179
  const higherPercent = getPercentage(higherValue);
179
180
 
180
- const adjustedLower = mapValueToVisualPercent(lowerPercent, edgeConstraint) + paddingPercent;
181
- const adjustedHigher = mapValueToVisualPercent(higherPercent, edgeConstraint) - paddingPercent;
181
+ const adjustedLower = mapValueToVisualPercent(lowerPercent, edgeConstraint);
182
+ const adjustedHigher = mapValueToVisualPercent(higherPercent, edgeConstraint);
182
183
 
183
- let trackLength = Math.max(0, adjustedHigher - adjustedLower);
184
- if (higherPercent - lowerPercent < paddingPercent * 2) {
185
- trackLength = Math.max(0, higherPercent - lowerPercent);
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';
186
192
  }
187
193
 
188
- activeTrack.style.display = 'block';
189
- activeTrack.style.width = `${trackLength}%`;
190
- activeTrack.style.left = `${adjustedLower}%`;
191
- activeTrack.style.height = '100%';
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';
192
212
  } else {
193
- // Single thumb slider
213
+ // Single handle slider
194
214
  const valuePercent = getPercentage(state.value);
195
215
  const adjustedPercent = mapValueToVisualPercent(valuePercent, edgeConstraint);
196
- const adjustedWidth = Math.max(0, adjustedPercent - paddingPercent);
197
216
 
217
+ // Hide start track for single slider
218
+ startTrack.style.display = 'none';
219
+
220
+ // Active track (filled part)
198
221
  activeTrack.style.display = 'block';
199
- activeTrack.style.width = `${adjustedWidth}%`;
200
222
  activeTrack.style.left = '0';
201
- activeTrack.style.height = '100%';
202
- }
203
- };
204
-
205
- /**
206
- * Updates remaining track styles
207
- */
208
- const updateRemainingTrack = () => {
209
- if (!remainingTrack || !track || !thumb) return;
210
-
211
- const dims = getTrackDimensions();
212
- if (!dims) return;
213
-
214
- const { thumbSize, trackSize, paddingPercent } = dims;
215
- const edgeConstraint = (thumbSize / 2) / trackSize * 100;
216
-
217
- // Find the highest thumb value
218
- const highValue = config.range && state.secondValue !== null ?
219
- Math.max(state.value, state.secondValue) : state.value;
220
-
221
- const valuePercent = getPercentage(highValue);
222
-
223
- // Map percentage to visual range
224
- const adjustedPercent = mapValueToVisualPercent(valuePercent, edgeConstraint) + paddingPercent;
225
- const remainingSize = Math.max(0, 100 - adjustedPercent);
226
-
227
- remainingTrack.style.display = 'block';
228
- remainingTrack.style.width = `${remainingSize}%`;
229
- remainingTrack.style.left = `${adjustedPercent}%`;
230
- remainingTrack.style.height = '100%';
231
- };
232
-
233
- /**
234
- * Updates thumb positions
235
- */
236
- const updateThumbPositions = () => {
237
- if (!thumb) return;
238
-
239
- // Update main thumb
240
- const percent = getPercentage(state.value);
241
- setThumbPosition(thumb, valueBubble, percent);
242
-
243
- // Update second thumb if range slider
244
- if (config.range && secondThumb && secondValueBubble && state.secondValue !== null) {
245
- const secondPercent = getPercentage(state.secondValue);
246
- setThumbPosition(secondThumb, secondValueBubble, secondPercent);
247
- }
248
-
249
- // Update ARIA attributes
250
- thumb.setAttribute('aria-valuenow', String(state.value));
251
- if (config.range && secondThumb && state.secondValue !== null) {
252
- secondThumb.setAttribute('aria-valuenow', String(state.secondValue));
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';
253
231
  }
254
232
  };
255
233
 
@@ -259,11 +237,9 @@ export const createUiHelpers = (config: SliderConfig, state) => {
259
237
  const updateValueBubbles = () => {
260
238
  if (!valueBubble) return;
261
239
 
262
- // Format the values
263
240
  const formatter = config.valueFormatter || (value => value.toString());
264
-
265
- // Update main and second value bubble if needed
266
241
  valueBubble.textContent = formatter(state.value);
242
+
267
243
  if (config.range && secondValueBubble && state.secondValue !== null) {
268
244
  secondValueBubble.textContent = formatter(state.secondValue);
269
245
  }
@@ -275,42 +251,30 @@ export const createUiHelpers = (config: SliderConfig, state) => {
275
251
  const showValueBubble = (bubbleElement, show) => {
276
252
  if (!bubbleElement || !config.showValue) return;
277
253
 
278
- const visibleClass = `${state.component.getClass('slider-value')}--visible`;
279
- bubbleElement.classList[show ? 'add' : 'remove'](visibleClass);
254
+ bubbleElement.classList[show ? 'add' : 'remove'](`${state.component.getClass('slider-value')}--visible`);
280
255
  };
281
256
 
282
257
  /**
283
258
  * Generates tick marks
284
259
  */
285
260
  const generateTicks = () => {
286
- if (!ticksContainer) {
287
- console.warn('Ticks container not found in component structure');
288
- return;
289
- }
261
+ if (!ticksContainer || !container) return;
290
262
 
291
263
  // Clear existing ticks
292
- const sliderElement = state.component.element;
293
- sliderElement.querySelectorAll(`.${state.component.getClass('slider-tick')}`)
294
- .forEach(tick => tick.parentNode.removeChild(tick));
295
-
296
264
  while (ticksContainer.firstChild) {
297
265
  ticksContainer.removeChild(ticksContainer.firstChild);
298
266
  }
299
267
 
300
- // Reset ticks array
301
268
  state.ticks = [];
302
-
303
269
  if (!config.ticks) return;
304
270
 
305
- // Generate tick values
306
271
  const numSteps = Math.floor((state.max - state.min) / state.step);
307
272
  const tickValues = [];
308
273
 
274
+ // Generate tick values
309
275
  for (let i = 0; i <= numSteps; i++) {
310
276
  const value = state.min + (i * state.step);
311
- if (value <= state.max) {
312
- tickValues.push(value);
313
- }
277
+ if (value <= state.max) tickValues.push(value);
314
278
  }
315
279
 
316
280
  // Ensure max value is included
@@ -319,41 +283,35 @@ export const createUiHelpers = (config: SliderConfig, state) => {
319
283
  }
320
284
 
321
285
  // CSS classes
322
- const activeClass = `${state.component.getClass('slider-tick')}--active`;
323
- const inactiveClass = `${state.component.getClass('slider-tick')}--inactive`;
324
- const hiddenClass = `${state.component.getClass('slider-tick')}--hidden`;
325
286
  const tickClass = state.component.getClass('slider-tick');
287
+ const activeClass = `${tickClass}--active`;
288
+ const inactiveClass = `${tickClass}--inactive`;
289
+ const hiddenClass = `${tickClass}--hidden`;
326
290
 
327
- // Create ticks
291
+ // Create tick elements
328
292
  tickValues.forEach(value => {
329
293
  const percent = getPercentage(value);
294
+ const tick = document.createElement('div');
295
+ tick.classList.add(tickClass);
296
+ tick.style.left = `${percent}%`;
330
297
 
331
- // Create tick mark if enabled
332
- if (config.ticks) {
333
- const tick = document.createElement('div');
334
- tick.classList.add(tickClass);
335
-
336
- // Position tick
337
- tick.style.left = `${percent}%`;
338
-
339
- // Check if this tick should be hidden (matches exactly a selected value)
340
- const isExactlySelected = value === state.value ||
341
- (config.range && state.secondValue !== null && value === state.secondValue);
342
-
343
- if (isExactlySelected) {
344
- tick.classList.add(hiddenClass);
345
- } else if (config.range && state.secondValue !== null) {
346
- const lowerValue = Math.min(state.value, state.secondValue);
347
- const higherValue = Math.max(state.value, state.secondValue);
348
-
349
- tick.classList.add(value >= lowerValue && value <= higherValue ? activeClass : inactiveClass);
350
- } else {
351
- tick.classList.add(value <= state.value ? activeClass : inactiveClass);
352
- }
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);
353
307
 
354
- ticksContainer.appendChild(tick);
355
- state.ticks.push(tick);
308
+ tick.classList.add(value >= lowerValue && value <= higherValue ? activeClass : inactiveClass);
309
+ } else {
310
+ tick.classList.add(value <= state.value ? activeClass : inactiveClass);
356
311
  }
312
+
313
+ ticksContainer.appendChild(tick);
314
+ state.ticks.push(tick);
357
315
  });
358
316
  };
359
317
 
@@ -363,24 +321,23 @@ export const createUiHelpers = (config: SliderConfig, state) => {
363
321
  const updateTicks = () => {
364
322
  if (!state.ticks || state.ticks.length === 0) return;
365
323
 
366
- const activeClass = `${state.component.getClass('slider-tick')}--active`;
367
- const inactiveClass = `${state.component.getClass('slider-tick')}--inactive`;
368
- const hiddenClass = `${state.component.getClass('slider-tick')}--hidden`;
324
+ const tickClass = state.component.getClass('slider-tick');
325
+ const activeClass = `${tickClass}--active`;
326
+ const inactiveClass = `${tickClass}--inactive`;
327
+ const hiddenClass = `${tickClass}--hidden`;
369
328
 
370
- // Update active ticks based on current value
371
329
  state.ticks.forEach((tick, index) => {
372
- // Calculate the value for this tick based on its index
330
+ // Calculate the value for this tick
373
331
  const tickValue = state.min + (index * state.step);
374
332
 
375
- // First, reset visibility
333
+ // Reset visibility first
376
334
  tick.classList.remove(hiddenClass);
377
335
 
378
336
  // Check if this tick should be hidden (matches exactly a selected value)
379
- const isExactlySelected = tickValue === state.value ||
380
- (config.range && state.secondValue !== null && tickValue === state.secondValue);
337
+ const isExactlySelected = (tickValue === state.value ||
338
+ (config.range && state.secondValue !== null && tickValue === state.secondValue));
381
339
 
382
340
  if (isExactlySelected) {
383
- // Hide this tick as it exactly matches a selected value
384
341
  tick.classList.add(hiddenClass);
385
342
  } else if (config.range && state.secondValue !== null) {
386
343
  // Range slider - ticks between values should be active
@@ -411,29 +368,21 @@ export const createUiHelpers = (config: SliderConfig, state) => {
411
368
  * Updates all UI elements
412
369
  */
413
370
  const updateUi = () => {
414
- updateThumbPositions();
415
- updateStartTrack();
416
- updateActiveTrack();
417
- updateRemainingTrack();
371
+ updateHandlePositions();
372
+ updateTrackSegments();
418
373
  updateValueBubbles();
419
374
  updateTicks();
420
375
  };
421
376
 
422
- // Return helper methods
377
+ // Return consolidated helper methods
423
378
  return {
424
379
  getPercentage,
425
380
  getValueFromPosition,
426
381
  roundToStep,
427
382
  clamp,
428
- setThumbPosition,
429
- updateActiveTrack,
430
- updateStartTrack,
431
- updateRemainingTrack,
432
- updateThumbPositions,
433
- updateValueBubbles,
434
383
  showValueBubble,
435
384
  generateTicks,
436
385
  updateTicks,
437
386
  updateUi
438
387
  };
439
- };
388
+ }
@@ -4,16 +4,7 @@
4
4
  export { default } from './slider';
5
5
 
6
6
  // Export constants
7
- export {
8
- SLIDER_COLORS,
9
- SLIDER_SIZES,
10
- SLIDER_ORIENTATIONS,
11
- SLIDER_EVENTS
12
- } from './constants';
7
+ export { SLIDER_COLORS, SLIDER_SIZES, SLIDER_EVENTS } from './constants';
13
8
 
14
9
  // Export types for TypeScript users
15
- export type {
16
- SliderConfig,
17
- SliderComponent,
18
- SliderEvent
19
- } from './types';
10
+ export type { SliderConfig, SliderComponent, SliderEvent } from './types';
@@ -1,13 +1,9 @@
1
1
  // src/components/slider/slider.ts
2
2
  import { pipe } from '../../core/compose/pipe';
3
3
  import { createBase, withElement } from '../../core/compose/component';
4
- import { withEvents, withLifecycle } from '../../core/compose/features';
5
- import {
6
- withStructure,
7
- withDisabled,
8
- withAppearance,
9
- withSlider
10
- } from './features';
4
+ import { withEvents, withLifecycle, withTextLabel, withIcon } from '../../core/compose/features';
5
+ import { withStructure, withSlider } from './features';
6
+ import { withStates } from './features/states';
11
7
  import { withAPI } from './api';
12
8
  import { SliderConfig, SliderComponent } from './types';
13
9
  import { createBaseConfig, getElementConfig, getApiConfig } from './config';
@@ -21,22 +17,23 @@ const createSlider = (config: SliderConfig = {}): SliderComponent => {
21
17
  const baseConfig = createBaseConfig(config);
22
18
 
23
19
  try {
24
- // First create the component with all required features
20
+ // Create the component with all required features
25
21
  const component = pipe(
26
22
  createBase,
27
23
  withEvents(),
28
24
  withElement(getElementConfig(baseConfig)),
25
+ withIcon(baseConfig),
26
+ withTextLabel(baseConfig),
29
27
  withStructure(baseConfig),
30
- withDisabled(baseConfig),
31
- withAppearance(baseConfig),
28
+ withStates(baseConfig),
32
29
  withSlider(baseConfig),
33
30
  withLifecycle()
34
31
  )(baseConfig);
35
32
 
36
- // Then generate the API configuration using the component
33
+ // Generate the API configuration
37
34
  const apiOptions = getApiConfig(component);
38
35
 
39
- // Finally, apply the API layer with the generated options
36
+ // Apply the API layer
40
37
  const slider = withAPI(apiOptions)(component);
41
38
 
42
39
  // Register event handlers from config