mtrl 0.2.6 → 0.2.8

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 (226) hide show
  1. package/demo/build.ts +349 -0
  2. package/demo/index.html +110 -0
  3. package/demo/main.js +448 -0
  4. package/demo/styles.css +239 -0
  5. package/index.ts +18 -0
  6. package/package.json +14 -3
  7. package/server.ts +86 -0
  8. package/src/components/badge/api.ts +70 -63
  9. package/src/components/badge/badge.ts +16 -2
  10. package/src/components/badge/config.ts +66 -13
  11. package/src/components/badge/features.ts +51 -42
  12. package/src/components/badge/index.ts +27 -2
  13. package/src/components/badge/types.ts +62 -30
  14. package/src/components/bottom-app-bar/bottom-app-bar.ts +154 -0
  15. package/src/components/bottom-app-bar/config.ts +29 -0
  16. package/src/components/bottom-app-bar/index.ts +17 -0
  17. package/src/components/bottom-app-bar/types.ts +114 -0
  18. package/src/components/button/api.ts +5 -0
  19. package/src/components/button/button.ts +0 -1
  20. package/src/components/button/config.ts +6 -2
  21. package/src/components/button/index.ts +10 -2
  22. package/src/components/button/types.ts +20 -2
  23. package/src/components/card/card.ts +13 -25
  24. package/src/components/card/config.ts +83 -30
  25. package/src/components/card/content.ts +8 -10
  26. package/src/components/card/features.ts +4 -3
  27. package/src/components/card/index.ts +29 -2
  28. package/src/components/card/types.ts +33 -22
  29. package/src/components/checkbox/config.ts +3 -4
  30. package/src/components/checkbox/index.ts +1 -2
  31. package/src/components/checkbox/types.ts +12 -3
  32. package/src/components/chip/api.ts +170 -221
  33. package/src/components/chip/chip.ts +34 -302
  34. package/src/components/chip/config.ts +1 -2
  35. package/src/components/chip/index.ts +10 -2
  36. package/src/components/chip/types.ts +224 -35
  37. package/src/components/datepicker/api.ts +265 -0
  38. package/src/components/datepicker/config.ts +141 -0
  39. package/src/components/datepicker/datepicker.ts +341 -0
  40. package/src/components/datepicker/index.ts +12 -0
  41. package/src/components/datepicker/render.ts +450 -0
  42. package/src/components/datepicker/types.ts +397 -0
  43. package/src/components/datepicker/utils.ts +289 -0
  44. package/src/components/dialog/api.ts +55 -21
  45. package/src/components/dialog/config.ts +12 -9
  46. package/src/components/dialog/dialog.ts +6 -3
  47. package/src/components/dialog/features.ts +345 -151
  48. package/src/components/dialog/index.ts +38 -8
  49. package/src/components/dialog/types.ts +40 -14
  50. package/src/components/divider/config.ts +81 -0
  51. package/src/components/divider/divider.ts +37 -0
  52. package/src/components/divider/features.ts +207 -0
  53. package/src/components/divider/index.ts +9 -0
  54. package/src/components/divider/types.ts +55 -0
  55. package/src/components/extended-fab/api.ts +141 -0
  56. package/src/components/extended-fab/config.ts +112 -0
  57. package/src/components/extended-fab/extended-fab.ts +125 -0
  58. package/src/components/extended-fab/index.ts +9 -0
  59. package/src/components/extended-fab/types.ts +304 -0
  60. package/src/components/fab/api.ts +97 -0
  61. package/src/components/fab/config.ts +93 -0
  62. package/src/components/fab/fab.ts +67 -0
  63. package/src/components/fab/index.ts +9 -0
  64. package/src/components/fab/types.ts +251 -0
  65. package/src/components/list/config.ts +4 -5
  66. package/src/components/list/features.ts +6 -7
  67. package/src/components/list/index.ts +7 -9
  68. package/src/components/list/list-item.ts +12 -13
  69. package/src/components/list/types.ts +50 -5
  70. package/src/components/list/utils.ts +30 -3
  71. package/src/components/menu/features/items-manager.ts +9 -9
  72. package/src/components/menu/features/positioning.ts +7 -7
  73. package/src/components/menu/features/visibility.ts +7 -7
  74. package/src/components/menu/index.ts +7 -9
  75. package/src/components/menu/menu-item.ts +6 -6
  76. package/src/components/menu/menu.ts +22 -0
  77. package/src/components/menu/types.ts +29 -10
  78. package/src/components/menu/utils.ts +67 -0
  79. package/src/components/navigation/api.ts +78 -50
  80. package/src/components/navigation/config.ts +22 -10
  81. package/src/components/navigation/features/items.ts +284 -0
  82. package/src/components/navigation/index.ts +0 -6
  83. package/src/components/navigation/nav-item.ts +70 -33
  84. package/src/components/navigation/navigation.ts +53 -3
  85. package/src/components/navigation/types.ts +117 -70
  86. package/src/components/progress/api.ts +2 -3
  87. package/src/components/progress/config.ts +2 -3
  88. package/src/components/progress/index.ts +0 -1
  89. package/src/components/progress/progress.ts +1 -2
  90. package/src/components/progress/types.ts +186 -33
  91. package/src/components/radios/config.ts +1 -1
  92. package/src/components/radios/index.ts +0 -1
  93. package/src/components/radios/types.ts +0 -7
  94. package/src/components/search/api.ts +203 -0
  95. package/src/components/search/config.ts +86 -0
  96. package/src/components/search/features/index.ts +4 -0
  97. package/src/components/search/features/search.ts +717 -0
  98. package/src/components/search/features/states.ts +169 -0
  99. package/src/components/search/features/structure.ts +197 -0
  100. package/src/components/search/index.ts +7 -0
  101. package/src/components/search/search.ts +52 -0
  102. package/src/components/search/types.ts +175 -0
  103. package/src/components/segmented-button/config.ts +80 -0
  104. package/src/components/segmented-button/index.ts +4 -0
  105. package/src/components/segmented-button/segment.ts +154 -0
  106. package/src/components/segmented-button/segmented-button.ts +249 -0
  107. package/src/components/segmented-button/types.ts +254 -0
  108. package/src/components/slider/accessibility.md +5 -5
  109. package/src/components/slider/api.ts +41 -120
  110. package/src/components/slider/config.ts +51 -47
  111. package/src/components/slider/features/handlers.ts +495 -0
  112. package/src/components/slider/features/index.ts +1 -2
  113. package/src/components/slider/features/slider.ts +66 -84
  114. package/src/components/slider/features/states.ts +195 -0
  115. package/src/components/slider/features/structure.ts +136 -206
  116. package/src/components/slider/features/ui.ts +145 -206
  117. package/src/components/slider/index.ts +2 -11
  118. package/src/components/slider/slider.ts +9 -12
  119. package/src/components/slider/types.ts +67 -26
  120. package/src/components/snackbar/config.ts +2 -3
  121. package/src/components/snackbar/constants.ts +0 -32
  122. package/src/components/snackbar/index.ts +0 -1
  123. package/src/components/snackbar/position.ts +9 -1
  124. package/src/components/snackbar/types.ts +122 -46
  125. package/src/components/switch/config.ts +2 -3
  126. package/src/components/switch/index.ts +0 -1
  127. package/src/components/switch/types.ts +3 -2
  128. package/src/components/tabs/config.ts +3 -4
  129. package/src/components/tabs/features.ts +4 -2
  130. package/src/components/tabs/index.ts +0 -15
  131. package/src/components/tabs/indicator.ts +73 -13
  132. package/src/components/tabs/tab-api.ts +12 -4
  133. package/src/components/tabs/tab.ts +18 -6
  134. package/src/components/tabs/types.ts +23 -5
  135. package/src/components/textfield/config.ts +2 -3
  136. package/src/components/textfield/index.ts +0 -1
  137. package/src/components/textfield/types.ts +17 -3
  138. package/src/components/timepicker/README.md +277 -0
  139. package/src/components/timepicker/api.ts +632 -0
  140. package/src/components/timepicker/clockdial.ts +482 -0
  141. package/src/components/timepicker/config.ts +228 -0
  142. package/src/components/timepicker/index.ts +3 -0
  143. package/src/components/timepicker/render.ts +613 -0
  144. package/src/components/timepicker/timepicker.ts +117 -0
  145. package/src/components/timepicker/types.ts +336 -0
  146. package/src/components/timepicker/utils.ts +241 -0
  147. package/src/components/tooltip/api.ts +1 -1
  148. package/src/components/tooltip/config.ts +27 -6
  149. package/src/components/tooltip/index.ts +0 -1
  150. package/src/components/tooltip/types.ts +13 -3
  151. package/src/components/top-app-bar/config.ts +83 -0
  152. package/src/components/top-app-bar/index.ts +11 -0
  153. package/src/components/top-app-bar/top-app-bar.ts +316 -0
  154. package/src/components/top-app-bar/types.ts +140 -0
  155. package/src/core/build/_ripple.scss +6 -6
  156. package/src/core/build/ripple.ts +72 -95
  157. package/src/core/compose/features/icon.ts +3 -1
  158. package/src/core/compose/features/ripple.ts +4 -1
  159. package/src/core/compose/features/textlabel.ts +23 -2
  160. package/src/core/dom/create.ts +5 -0
  161. package/src/index.ts +9 -0
  162. package/src/styles/abstract/_theme.scss +9 -1
  163. package/src/styles/components/_badge.scss +182 -0
  164. package/src/styles/components/_bottom-app-bar.scss +103 -0
  165. package/src/{components/button/_styles.scss → styles/components/_button.scss} +0 -10
  166. package/src/{components/checkbox/_styles.scss → styles/components/_checkbox.scss} +0 -2
  167. package/src/styles/components/_datepicker.scss +358 -0
  168. package/src/styles/components/_dialog.scss +259 -0
  169. package/src/styles/components/_divider.scss +57 -0
  170. package/src/styles/components/_extended-fab.scss +267 -0
  171. package/src/styles/components/_fab.scss +225 -0
  172. package/src/{components/navigation/_styles.scss → styles/components/_navigation.scss} +1 -0
  173. package/src/styles/components/_search.scss +306 -0
  174. package/src/styles/components/_segmented-button.scss +117 -0
  175. package/src/{components/slider/_styles.scss → styles/components/_slider.scss} +83 -24
  176. package/src/{components/switch/_styles.scss → styles/components/_switch.scss} +0 -2
  177. package/src/{components/tabs/_styles.scss → styles/components/_tabs.scss} +95 -33
  178. package/src/{components/textfield/_styles.scss → styles/components/_textfield.scss} +70 -67
  179. package/src/styles/components/_timepicker.scss +451 -0
  180. package/src/styles/components/_top-app-bar.scss +225 -0
  181. package/src/styles/main.scss +98 -49
  182. package/src/styles/themes/_autumn.scss +21 -0
  183. package/src/styles/themes/_base-theme.scss +61 -0
  184. package/src/styles/themes/_baseline.scss +58 -0
  185. package/src/styles/themes/_bluekhaki.scss +125 -0
  186. package/src/styles/themes/_brownbeige.scss +125 -0
  187. package/src/styles/themes/_browngreen.scss +125 -0
  188. package/src/styles/themes/_forest.scss +6 -0
  189. package/src/styles/themes/_greenbeige.scss +125 -0
  190. package/src/styles/themes/_material.scss +125 -0
  191. package/src/styles/themes/_ocean.scss +6 -0
  192. package/src/styles/themes/_sageivory.scss +125 -0
  193. package/src/styles/themes/_spring.scss +6 -0
  194. package/src/styles/themes/_summer.scss +5 -0
  195. package/src/styles/themes/_sunset.scss +5 -0
  196. package/src/styles/themes/_tealcaramel.scss +125 -0
  197. package/src/styles/themes/_winter.scss +6 -0
  198. package/src/components/badge/_styles.scss +0 -174
  199. package/src/components/badge/constants.ts +0 -30
  200. package/src/components/button/constants.ts +0 -11
  201. package/src/components/card/constants.ts +0 -84
  202. package/src/components/dialog/_styles.scss +0 -213
  203. package/src/components/dialog/constants.ts +0 -32
  204. package/src/components/menu/constants.ts +0 -154
  205. package/src/components/navigation/constants.ts +0 -200
  206. package/src/components/navigation/features/items.js +0 -192
  207. package/src/components/progress/constants.ts +0 -29
  208. package/src/components/slider/features/appearance.ts +0 -94
  209. package/src/components/slider/features/disabled.ts +0 -68
  210. package/src/components/slider/features/events.ts +0 -164
  211. package/src/components/slider/features/interactions.ts +0 -396
  212. package/src/components/slider/features/keyboard.ts +0 -233
  213. package/src/components/switch/constants.ts +0 -80
  214. package/src/components/tabs/constants.ts +0 -89
  215. package/src/core/collection/adapters/mongodb.js +0 -232
  216. /package/src/{components/card/_styles.scss → styles/components/_card.scss} +0 -0
  217. /package/src/{components/carousel/_styles.scss → styles/components/_carousel.scss} +0 -0
  218. /package/src/{components/chip/_styles.scss → styles/components/_chip.scss} +0 -0
  219. /package/src/{components/list/_styles.scss → styles/components/_list.scss} +0 -0
  220. /package/src/{components/menu/_styles.scss → styles/components/_menu.scss} +0 -0
  221. /package/src/{components/progress/_styles.scss → styles/components/_progress.scss} +0 -0
  222. /package/src/{components/radios/_styles.scss → styles/components/_radios.scss} +0 -0
  223. /package/src/{components/sheet/_styles.scss → styles/components/_sheet.scss} +0 -0
  224. /package/src/{components/snackbar/_styles.scss → styles/components/_snackbar.scss} +0 -0
  225. /package/src/{components/tooltip/_styles.scss → styles/components/_tooltip.scss} +0 -0
  226. /package/src/styles/utilities/{_color.scss → _colors.scss} +0 -0
@@ -1,73 +1,13 @@
1
1
  // src/core/build/ripple.ts
2
-
3
2
  import { RIPPLE_CONFIG, RIPPLE_TIMING } from './constants';
3
+ import { PREFIX } from '../config';
4
+
5
+ // ... existing interfaces ...
4
6
 
5
- /**
6
- * Ripple animation configuration
7
- */
8
- export interface RippleConfig {
9
- /**
10
- * Animation duration in milliseconds
11
- */
12
- duration?: number;
13
-
14
- /**
15
- * Animation timing function
16
- */
17
- timing?: string;
18
-
19
- /**
20
- * Opacity start and end values
21
- */
22
- opacity?: [string, string];
23
- }
24
-
25
- /**
26
- * End coordinates for ripple animation
27
- */
28
- interface EndCoordinates {
29
- size: string;
30
- top: string;
31
- left: string;
32
- }
33
-
34
- /**
35
- * Document event listener
36
- */
37
- interface DocumentListener {
38
- event: string;
39
- handler: EventListener;
40
- }
41
-
42
- /**
43
- * Ripple controller interface
44
- */
45
- export interface RippleController {
46
- /**
47
- * Attaches ripple effect to an element
48
- * @param element - Target element
49
- */
50
- mount: (element: HTMLElement) => void;
51
-
52
- /**
53
- * Removes ripple effect from an element
54
- * @param element - Target element
55
- */
56
- unmount: (element: HTMLElement) => void;
57
- }
58
-
59
- /**
60
- * Creates a ripple effect instance
61
- *
62
- * @param config - Ripple configuration
63
- * @returns Ripple controller instance
64
- */
65
7
  export const createRipple = (config: RippleConfig = {}): RippleController => {
66
- // Make sure we fully merge the config options
67
8
  const options = {
68
9
  ...RIPPLE_CONFIG,
69
10
  ...config,
70
- // Handle nested objects like opacity array
71
11
  opacity: config.opacity || RIPPLE_CONFIG.opacity
72
12
  };
73
13
 
@@ -84,18 +24,18 @@ export const createRipple = (config: RippleConfig = {}): RippleController => {
84
24
  };
85
25
  };
86
26
 
27
+ // Track active ripples for proper cleanup
28
+ const activeRipples = new WeakMap<HTMLElement, Set<HTMLElement>>();
29
+
87
30
  const createRippleElement = (): HTMLDivElement => {
88
31
  const ripple = document.createElement('div');
89
- ripple.className = 'ripple';
90
- // Initial styles already set in CSS
91
- ripple.style.transition = `all ${options.duration}ms ${options.timing}`;
32
+ ripple.className = `${PREFIX}-ripple-wave`;
33
+ // No inline transition style - let CSS handle it
92
34
  return ripple;
93
35
  };
94
36
 
95
- // Store document event listeners for cleanup
96
37
  let documentListeners: DocumentListener[] = [];
97
38
 
98
- // Safe document event handling
99
39
  const addDocumentListener = (event: string, handler: EventListener): void => {
100
40
  if (typeof document.addEventListener === 'function') {
101
41
  document.addEventListener(event, handler);
@@ -113,45 +53,56 @@ export const createRipple = (config: RippleConfig = {}): RippleController => {
113
53
  };
114
54
 
115
55
  const animate = (event: MouseEvent, container: HTMLElement): void => {
116
- if (!container) return;
56
+ if (!container || !container.__rippleContainer) return;
117
57
 
58
+ const rippleContainer = container.__rippleContainer;
118
59
  const bounds = container.getBoundingClientRect();
119
60
  const ripple = createRippleElement();
120
61
 
121
- // Set initial position and state
62
+ // Calculate ripple size - should be larger than the container
63
+ // Use the maximum dimension of the container multiplied by 2
64
+ const size = Math.max(bounds.width, bounds.height) * 2;
65
+
66
+ // Calculate position to center the ripple on the click point
67
+ const x = event.clientX - bounds.left - (size / 2);
68
+ const y = event.clientY - bounds.top - (size / 2);
69
+
70
+ // Set explicit size and position
122
71
  Object.assign(ripple.style, {
123
- left: `${event.offsetX || bounds.width / 2}px`,
124
- top: `${event.offsetY || bounds.height / 2}px`,
125
- transform: 'scale(0)',
126
- opacity: options.opacity[0]
72
+ width: `${size}px`,
73
+ height: `${size}px`,
74
+ left: `${x}px`,
75
+ top: `${y}px`
127
76
  });
128
77
 
129
- container.appendChild(ripple);
78
+ // Append to container
79
+ rippleContainer.appendChild(ripple);
130
80
 
131
81
  // Force reflow
132
- // eslint-disable-next-line no-unused-expressions
133
82
  ripple.offsetHeight;
134
83
 
135
- // Animate to end position
136
- const end = getEndCoordinates(bounds);
137
- Object.assign(ripple.style, {
138
- ...end,
139
- transform: 'scale(1)',
140
- opacity: options.opacity[1]
84
+ // Add active class to trigger animation
85
+ requestAnimationFrame(() => {
86
+ ripple.classList.add('active');
141
87
  });
142
88
 
143
89
  const cleanup = () => {
144
- ripple.style.opacity = '0';
90
+ // Remove document listeners
91
+ removeDocumentListener('mouseup', cleanup);
92
+ removeDocumentListener('mouseleave', cleanup);
145
93
 
146
- // Use setTimeout to remove element after animation
94
+ // Remove active class and add fade-out class
95
+ ripple.classList.remove('active');
96
+ ripple.classList.add('fade-out');
97
+
98
+ // Remove after animation
147
99
  setTimeout(() => {
148
100
  if (ripple.parentNode) {
149
101
  ripple.parentNode.removeChild(ripple);
150
102
  }
103
+ // Remove from tracking
104
+ activeRipples.get(container)?.delete(ripple);
151
105
  }, options.duration);
152
-
153
- removeDocumentListener('mouseup', cleanup);
154
- removeDocumentListener('mouseleave', cleanup);
155
106
  };
156
107
 
157
108
  addDocumentListener('mouseup', cleanup);
@@ -167,8 +118,21 @@ export const createRipple = (config: RippleConfig = {}): RippleController => {
167
118
  if (currentPosition === 'static') {
168
119
  element.style.position = 'relative';
169
120
  }
170
- element.style.overflow = 'hidden';
121
+
122
+ // Create ripple container if it doesn't exist
123
+ let rippleContainer = element.querySelector(`.${PREFIX}-ripple`);
124
+ if (!rippleContainer) {
125
+ rippleContainer = document.createElement('div');
126
+ rippleContainer.className = `${PREFIX}-ripple`;
127
+ element.appendChild(rippleContainer);
128
+ }
171
129
 
130
+ // Store reference to container
131
+ element.__rippleContainer = rippleContainer as HTMLElement;
132
+
133
+ // Initialize ripple tracking
134
+ activeRipples.set(element, new Set());
135
+
172
136
  // Store the mousedown handler to be able to remove it later
173
137
  const mousedownHandler = (e: MouseEvent) => animate(e, element);
174
138
 
@@ -198,19 +162,32 @@ export const createRipple = (config: RippleConfig = {}): RippleController => {
198
162
  element.__rippleHandlers = [];
199
163
  }
200
164
 
201
- // Remove all ripple elements
202
- const ripples = element.querySelectorAll('.ripple');
203
- ripples.forEach(ripple => {
204
- // Call remove directly to match the test expectation
205
- ripple.remove();
206
- });
165
+ // Remove all active ripples immediately
166
+ if (activeRipples.has(element)) {
167
+ const ripples = activeRipples.get(element);
168
+ if (ripples) {
169
+ ripples.forEach(ripple => {
170
+ if (ripple.parentNode) {
171
+ ripple.parentNode.removeChild(ripple);
172
+ }
173
+ });
174
+ }
175
+ activeRipples.delete(element);
176
+ }
177
+
178
+ // Remove ripple container
179
+ if (element.__rippleContainer && element.__rippleContainer.parentNode) {
180
+ element.__rippleContainer.parentNode.removeChild(element.__rippleContainer);
181
+ delete element.__rippleContainer;
182
+ }
207
183
  }
208
184
  };
209
185
  };
210
186
 
211
- // Extend the HTMLElement interface to add rippleHandlers property
187
+ // Extend the HTMLElement interface
212
188
  declare global {
213
189
  interface HTMLElement {
214
190
  __rippleHandlers?: Array<(e: MouseEvent) => void>;
191
+ __rippleContainer?: HTMLElement;
215
192
  }
216
193
  }
@@ -58,7 +58,9 @@ export const withIcon = <T extends IconConfig>(config: T) =>
58
58
  icon.setIcon(config.icon);
59
59
  }
60
60
 
61
- updateCircularStyle(component, config);
61
+ if (component.componentName === 'button') {
62
+ updateCircularStyle(component, config);
63
+ }
62
64
 
63
65
  return {
64
66
  ...component,
@@ -31,6 +31,9 @@ export const withRipple = <T extends RippleFeatureConfig>(config: T) =>
31
31
  if (!config.ripple) return component as C & RippleComponent;
32
32
 
33
33
  const rippleInstance = createRipple(config.rippleConfig);
34
+
35
+ // Immediately mount ripple to ensure it's available right away
36
+ rippleInstance.mount(component.element);
34
37
 
35
38
  // If component has lifecycle methods, integrate ripple with them
36
39
  if (component.lifecycle) {
@@ -39,7 +42,7 @@ export const withRipple = <T extends RippleFeatureConfig>(config: T) =>
39
42
 
40
43
  component.lifecycle.mount = () => {
41
44
  originalMount.call(component.lifecycle);
42
- rippleInstance.mount(component.element);
45
+ // We don't need to mount again here since we already did it above
43
46
  };
44
47
 
45
48
  component.lifecycle.destroy = () => {
@@ -11,6 +11,11 @@ export interface TextLabelConfig {
11
11
  */
12
12
  label?: string;
13
13
 
14
+ /**
15
+ * Label position ('start' or 'end')
16
+ */
17
+ labelPosition?: 'start' | 'end';
18
+
14
19
  /**
15
20
  * CSS class prefix
16
21
  */
@@ -69,8 +74,24 @@ export const withTextLabel = <T extends TextLabelConfig>(config: T = {} as T) =>
69
74
  labelElement.className = `${config.prefix}-${config.componentName}-label`;
70
75
  labelElement.textContent = config.label;
71
76
 
72
- // Insert label after input for proper z-index stacking
73
- component.element.appendChild(labelElement);
77
+ // Position the label based on labelPosition (default to 'start')
78
+ const position = config.labelPosition || 'start';
79
+
80
+ if (position === 'start') {
81
+ // Insert label as the first child
82
+ if (component.element.firstChild) {
83
+ component.element.insertBefore(labelElement, component.element.firstChild);
84
+ } else {
85
+ component.element.appendChild(labelElement);
86
+ }
87
+ } else {
88
+ // Insert label at the end (default behavior)
89
+ component.element.appendChild(labelElement);
90
+ }
91
+
92
+ if (position && component.componentName !== 'slider') {
93
+ component.element.classList.add(`${config.prefix}-${config.componentName}--label-${position}`);
94
+ }
74
95
 
75
96
  const label: LabelManager = {
76
97
  setText(text: string) {
@@ -35,6 +35,11 @@ export interface CreateElementOptions {
35
35
  * Element ID
36
36
  */
37
37
  id?: string;
38
+
39
+ /**
40
+ * Element ariaLabel
41
+ */
42
+ ariaLabel?: string;
38
43
 
39
44
  /**
40
45
  * Dataset attributes
package/src/index.ts CHANGED
@@ -2,21 +2,30 @@
2
2
  export { createElement } from './core/dom/create'
3
3
  export { default as createLayout } from './core/layout'
4
4
  export { default as createButton } from './components/button'
5
+ export { default as createFab } from './components/fab'
6
+ export { default as createExtendedFab } from './components/extended-fab'
7
+ export { default as createSegmentedButton } from './components/segmented-button'
8
+ export { default as createBottomAppBar } from './components/bottom-app-bar'
5
9
  export { default as createBadge } from './components/badge'
6
10
  export { default as createCard } from './components/card'
7
11
  export { default as createCarousel } from './components/carousel'
8
12
  export { default as createCheckbox } from './components/checkbox'
9
13
  export { default as createChip } from './components/chip'
14
+ export { default as createDatePicker } from './components/datepicker'
10
15
  export { default as createDialog } from './components/dialog'
16
+ export { default as createDivider } from './components/divider'
11
17
  export { default as createMenu } from './components/menu'
12
18
  export { default as createNavigation } from './components/navigation'
13
19
  export { default as createProgress } from './components/progress'
14
20
  export { default as createRadios } from './components/radios'
21
+ export { default as createSearch } from './components/search'
15
22
  export { default as createSheet } from './components/sheet'
16
23
  export { default as createSlider } from './components/slider'
17
24
  export { default as createSnackbar } from './components/snackbar'
18
25
  export { default as createSwitch } from './components/switch'
19
26
  export { default as createTabs } from './components/tabs'
20
27
  export { default as createTextfield } from './components/textfield'
28
+ export { default as createTimePicker } from './components/timepicker'
29
+ export { default as createTopAppBar } from './components/top-app-bar'
21
30
  export { default as createTooltip } from './components/tooltip'
22
31
  export { default as createList } from './components/list'
@@ -48,8 +48,16 @@ $mtrl-sys-shape: (
48
48
  @return var(--#{$prefix}-sys-color-#{$key}-rgb);
49
49
  }
50
50
 
51
+ /**
52
+ * Creates a color with alpha transparency using RGB values
53
+ * This version uses string.unquote to preserve the rgba function correctly
54
+ * @param {String} $key - Color token name
55
+ * @param {Number} $opacity - Opacity value (0-1)
56
+ * @return {String} rgba CSS function with variable
57
+ */
51
58
  @function alpha($key, $opacity) {
52
- @return rgba(var(--#{$prefix}-sys-color-#{$key}-rgb), $opacity);
59
+ // #{'...'} prevents SASS from interpreting rgba as a SASS function
60
+ @return #{'rgba(var(--#{$prefix}-sys-color-#{$key}-rgb), #{$opacity})'};
53
61
  }
54
62
 
55
63
  @function state($key) {
@@ -0,0 +1,182 @@
1
+ // src/components/badge/_badge.scss
2
+ @use '../../styles/abstract/base' as base;
3
+ @use '../../styles/abstract/variables' as v;
4
+ @use '../../styles/abstract/functions' as f;
5
+ @use '../../styles/abstract/mixins' as m;
6
+ @use '../../styles/abstract/theme' as t;
7
+
8
+ /**
9
+ * Badge component styles
10
+ *
11
+ * Badge specifications:
12
+ * - Small badge size: 6dp
13
+ * - Large badge height: 16dp
14
+ * - Small badge corner radius: 3dp
15
+ * - Large badge corner radius: 8dp
16
+ * - Small badge: positioned 6dp from container edge
17
+ * - Large badge: positioned 14dp (height) x 12dp (width) from container edge
18
+ */
19
+ $component: '#{base.$prefix}-badge';
20
+ $wrapper: '#{base.$prefix}-badge-wrapper';
21
+
22
+ // Wrapper styles to establish positioning context
23
+ .#{$wrapper} {
24
+ position: relative;
25
+ display: inline-flex;
26
+ flex-shrink: 0;
27
+ }
28
+
29
+ .#{$component} {
30
+ // Base badge styles
31
+ position: absolute;
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ font-weight: 500;
36
+ box-sizing: border-box;
37
+ overflow: hidden;
38
+ transition: all 200ms ease;
39
+ text-overflow: ellipsis;
40
+
41
+ // Hide for visibility: false
42
+ &--invisible {
43
+ display: none;
44
+ }
45
+
46
+ // Small badge (dot)
47
+ &--small {
48
+ width: 6px;
49
+ height: 6px;
50
+ min-width: 6px;
51
+ border-radius: 3px; // 3dp corner radius
52
+ font-size: 0;
53
+ padding: 0;
54
+ }
55
+
56
+ // Large badge
57
+ &--large {
58
+ height: 16px;
59
+ min-width: 16px;
60
+ border-radius: 8px; // 8dp corner radius
61
+ padding: 0 4px;
62
+ font-size: 11px;
63
+ line-height: 16px;
64
+
65
+ // Handle max character count container (16dp x 34dp)
66
+ &.#{$component}--overflow {
67
+ min-width: auto;
68
+ max-width: 34px; // max width is 34dp for overflow badges
69
+ padding: 0 4px;
70
+ }
71
+ }
72
+
73
+ // Position specs
74
+ &--positioned {
75
+ // Small badge placement (6dp from container edge)
76
+ &.#{$component}--small {
77
+ &.#{$component}--top-right {
78
+ top: -3px;
79
+ right: -3px;
80
+ }
81
+
82
+ &.#{$component}--top-left {
83
+ top: -3px;
84
+ left: -3px;
85
+ }
86
+
87
+ &.#{$component}--bottom-right {
88
+ bottom: -3px;
89
+ right: -3px;
90
+ }
91
+
92
+ &.#{$component}--bottom-left {
93
+ bottom: -3px;
94
+ left: -3px;
95
+ }
96
+ }
97
+
98
+ // Large badge placement (14dp x 12dp from container edge)
99
+ &.#{$component}--large {
100
+ &.#{$component}--top-right {
101
+ top: -8px;
102
+ right: -8px;
103
+ }
104
+
105
+ &.#{$component}--top-left {
106
+ top: -8px;
107
+ left: -8px;
108
+ }
109
+
110
+ &.#{$component}--bottom-right {
111
+ bottom: -8px;
112
+ right: -8px;
113
+ }
114
+
115
+ &.#{$component}--bottom-left {
116
+ bottom: -8px;
117
+ left: -8px;
118
+ }
119
+ }
120
+ }
121
+
122
+ // badge color system
123
+ &--error {
124
+ background-color: t.color('error');
125
+ color: t.color('on-error');
126
+ }
127
+
128
+ &--primary {
129
+ background-color: t.color('primary');
130
+ color: t.color('on-primary');
131
+ }
132
+
133
+ &--secondary {
134
+ background-color: t.color('secondary');
135
+ color: t.color('on-secondary');
136
+ }
137
+
138
+ &--tertiary {
139
+ background-color: t.color('tertiary');
140
+ color: t.color('on-tertiary');
141
+ }
142
+
143
+ &--success {
144
+ background-color: t.color('success');
145
+ color: t.color('on-success');
146
+ }
147
+
148
+ &--warning {
149
+ background-color: t.color('warning');
150
+ color: t.color('on-warning');
151
+ }
152
+
153
+ &--info {
154
+ background-color: t.color('info');
155
+ color: t.color('on-info');
156
+ }
157
+ }
158
+
159
+ // RTL support
160
+ [dir="rtl"] {
161
+ .#{$component}--positioned {
162
+ &.#{$component}--top-right {
163
+ right: auto;
164
+ left: -8px;
165
+ }
166
+
167
+ &.#{$component}--top-left {
168
+ left: auto;
169
+ right: -8px;
170
+ }
171
+
172
+ &.#{$component}--bottom-right {
173
+ right: auto;
174
+ left: -8px;
175
+ }
176
+
177
+ &.#{$component}--bottom-left {
178
+ left: auto;
179
+ right: -8px;
180
+ }
181
+ }
182
+ }
@@ -0,0 +1,103 @@
1
+ // src/components/bottom-app-bar/styles.scss
2
+ @use 'sass:map';
3
+ @use '../../styles/abstract/base' as base;
4
+ @use '../../styles/abstract/variables' as v;
5
+ @use '../../styles/abstract/functions' as f;
6
+ @use '../../styles/abstract/mixins' as m;
7
+ @use '../../styles/abstract/theme' as t;
8
+
9
+ $component: '#{base.$prefix}-bottom-app-bar';
10
+
11
+ .#{$component} {
12
+ // Core Properties
13
+ position: absolute;
14
+ bottom: 0;
15
+ left: 0;
16
+ right: 0;
17
+ z-index: f.get-z-index('fixed');
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: space-between;
21
+ height: 80px; // Default height as per specs
22
+ padding: 12px 16px 12px 4px; // top/bottom 12px, right 16px, left 4px
23
+ background-color: t.color('surface-container');
24
+
25
+ // Apply material elevation
26
+ @include m.elevation(2);
27
+
28
+ // Apply border radius at the top
29
+ border-top-left-radius: t.shape('medium');
30
+ border-top-right-radius: t.shape('medium');
31
+
32
+ // Add transition for smooth animations
33
+ transition: transform 0.3s ease-in-out;
34
+
35
+ // Actions container on the left side
36
+ &-actions {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 4px; // Small gap between action buttons
40
+ height: 100%;
41
+
42
+ // Icon buttons should have consistent sizing
43
+ > * {
44
+ flex-shrink: 0;
45
+ }
46
+ }
47
+
48
+ // FAB container on the right side
49
+ &-fab-container {
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ margin-left: auto;
54
+ }
55
+
56
+ // Adjustment for when FAB is present - use the specified height
57
+ &--with-fab {
58
+ height: 72px;
59
+ }
60
+
61
+ // Adjustment for when FAB is centered
62
+ &--fab-center {
63
+ .#{$component}-fab-container {
64
+ position: absolute;
65
+ left: 50%;
66
+ transform: translateX(-50%);
67
+ }
68
+ }
69
+
70
+ // Hidden state - moved off-screen
71
+ &--hidden {
72
+ transform: translateY(100%);
73
+ }
74
+
75
+ // RTL Support
76
+ [dir="rtl"] & {
77
+ padding: 12px 4px 12px 16px;
78
+
79
+ &-actions {
80
+ flex-direction: row-reverse;
81
+ }
82
+
83
+ &-fab-container {
84
+ margin-right: auto;
85
+ margin-left: initial;
86
+ }
87
+ }
88
+
89
+ // // Media query to hide on large screens
90
+ // @media (min-width: map.get(v.$breakpoints, 'lg')) {
91
+ // display: none;
92
+ // }
93
+
94
+ // Reduced motion support
95
+ @include m.reduced-motion {
96
+ transition-duration: 0.01ms;
97
+ }
98
+
99
+ // High contrast mode support
100
+ @include m.high-contrast {
101
+ border-top: 1px solid currentColor;
102
+ }
103
+ }
@@ -96,16 +96,6 @@ $component: '#{base.$prefix}-button';
96
96
  }
97
97
  }
98
98
 
99
- // Ripple container
100
- .ripple {
101
- position: absolute;
102
- border-radius: 50%;
103
- transform: scale(0);
104
- pointer-events: none;
105
- background-color: currentColor;
106
- opacity: 0.12;
107
- }
108
-
109
99
  &--disabled {
110
100
  opacity: 0.38
111
101
  }
@@ -70,8 +70,6 @@ $component: '#{base.$prefix}-checkbox';
70
70
 
71
71
  // Label position variants
72
72
  &--label-start {
73
- flex-direction: row-reverse;
74
-
75
73
  .#{$component}-label {
76
74
  margin-left: 0;
77
75
  margin-right: 12px;