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
@@ -0,0 +1,140 @@
1
+ // src/components/top-app-bar/types.ts
2
+ /**
3
+ * @module components/top-app-bar
4
+ * @description Type definitions for Top App Bar component
5
+ */
6
+
7
+ import { ElementComponent } from '../../core/compose';
8
+
9
+ /**
10
+ * Top App Bar types
11
+ * @category Components
12
+ */
13
+ export type TopAppBarType = 'small' | 'medium' | 'large' | 'center';
14
+
15
+ /**
16
+ * Configuration options for Top App Bar component
17
+ * @category Components
18
+ */
19
+ export interface TopAppBarConfig {
20
+ /**
21
+ * Element to use for the container
22
+ * @default 'header'
23
+ */
24
+ tag?: string;
25
+
26
+ /**
27
+ * Type of top app bar to display
28
+ * @default 'small'
29
+ */
30
+ type?: TopAppBarType;
31
+
32
+ /**
33
+ * Title text to display in the app bar
34
+ */
35
+ title?: string;
36
+
37
+ /**
38
+ * Whether to enable scrolling behavior
39
+ * @default true
40
+ */
41
+ scrollable?: boolean;
42
+
43
+ /**
44
+ * Whether to compress medium/large variants to small on scroll
45
+ * @default true
46
+ */
47
+ compressible?: boolean;
48
+
49
+ /**
50
+ * Scroll threshold in pixels to trigger the scrolled state
51
+ * @default 4
52
+ */
53
+ scrollThreshold?: number;
54
+
55
+ /**
56
+ * Additional CSS classes to apply
57
+ */
58
+ class?: string;
59
+
60
+ /**
61
+ * Optional callback when scrolling changes the bar appearance
62
+ */
63
+ onScroll?: (scrolled: boolean) => void;
64
+
65
+ /**
66
+ * Component prefix for class names
67
+ * @default 'mtrl'
68
+ */
69
+ prefix?: string;
70
+
71
+ /**
72
+ * Component name for class generation
73
+ */
74
+ componentName?: string;
75
+ }
76
+
77
+ /**
78
+ * Top App Bar component interface
79
+ * @category Components
80
+ */
81
+ export interface TopAppBar extends ElementComponent {
82
+ /**
83
+ * Sets the title of the top app bar
84
+ * @param {string} title - Title text
85
+ * @returns {TopAppBar} TopAppBar instance for chaining
86
+ */
87
+ setTitle: (title: string) => TopAppBar;
88
+
89
+ /**
90
+ * Gets the current title
91
+ * @returns {string} Current title text
92
+ */
93
+ getTitle: () => string;
94
+
95
+ /**
96
+ * Adds a leading navigation icon or element
97
+ * @param {HTMLElement} element - Element to add to the leading section
98
+ * @returns {TopAppBar} TopAppBar instance for chaining
99
+ */
100
+ addLeadingElement: (element: HTMLElement) => TopAppBar;
101
+
102
+ /**
103
+ * Adds a trailing action icon or element
104
+ * @param {HTMLElement} element - Element to add to the trailing section
105
+ * @returns {TopAppBar} TopAppBar instance for chaining
106
+ */
107
+ addTrailingElement: (element: HTMLElement) => TopAppBar;
108
+
109
+ /**
110
+ * Changes the top app bar type
111
+ * @param {TopAppBarType} type - New app bar type
112
+ * @returns {TopAppBar} TopAppBar instance for chaining
113
+ */
114
+ setType: (type: TopAppBarType) => TopAppBar;
115
+
116
+ /**
117
+ * Manually sets the scrolled state
118
+ * @param {boolean} scrolled - Whether to show the scrolled state
119
+ * @returns {TopAppBar} TopAppBar instance for chaining
120
+ */
121
+ setScrollState: (scrolled: boolean) => TopAppBar;
122
+
123
+ /**
124
+ * Gets the headline element
125
+ * @returns {HTMLElement} Headline element
126
+ */
127
+ getHeadlineElement: () => HTMLElement;
128
+
129
+ /**
130
+ * Gets the leading container element
131
+ * @returns {HTMLElement} Leading container element
132
+ */
133
+ getLeadingContainer: () => HTMLElement;
134
+
135
+ /**
136
+ * Gets the trailing container element
137
+ * @returns {HTMLElement} Trailing container element
138
+ */
139
+ getTrailingContainer: () => HTMLElement;
140
+ }
@@ -19,20 +19,20 @@ $component: '#{base.$prefix}-ripple';
19
19
  pointer-events: none;
20
20
  z-index: 0;
21
21
 
22
- // Ripple element
23
22
  &-wave {
24
23
  position: absolute;
25
24
  border-radius: 50%;
25
+
26
+ // Make the ripple more visible with these changes:
26
27
  background-color: currentColor;
27
- transform: scale(0);
28
- opacity: 0;
28
+ opacity: 0; // Start with 0 opacity
29
+ transform: scale(0); // Start slightly larger for better visibility
29
30
  pointer-events: none;
30
31
  will-change: transform, opacity;
31
32
 
32
33
  // Animation
33
- transition-property: transform, opacity;
34
- transition-duration: v.motion('duration-short4');
35
- transition-timing-function: v.motion('easing-standard');
34
+ transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
35
+ opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
36
36
 
37
37
  // Active ripple
38
38
  &.active {
@@ -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
  }
@@ -204,7 +204,7 @@ export const withElement = (options: WithElementOptions = {}) =>
204
204
  className: [
205
205
  base.getClass(options.componentName || base.componentName || 'component'),
206
206
  hasTouchSupport() && options.interactive ? base.getClass('interactive') : null,
207
- options.className
207
+ ...(Array.isArray(options.className) ? options.className : [options.className])
208
208
  ].filter(Boolean),
209
209
  attrs: options.attrs || {},
210
210
  forwardEvents: options.forwardEvents || {},
@@ -0,0 +1,79 @@
1
+ // src/core/compose/features/badge.ts
2
+
3
+ import { BaseComponent, ElementComponent } from '../component';
4
+ import createBadge from '../../../components/badge';
5
+ import { PREFIX } from '../../config';
6
+
7
+ /**
8
+ * Configuration for badge feature
9
+ */
10
+ export interface BadgeConfig {
11
+ /**
12
+ * Badge content to display
13
+ */
14
+ badge?: string | number;
15
+
16
+ /**
17
+ * Custom badge configuration
18
+ */
19
+ badgeConfig?: {
20
+ variant?: string;
21
+ color?: string;
22
+ size?: string;
23
+ position?: string;
24
+ max?: number;
25
+ [key: string]: any;
26
+ };
27
+
28
+ /**
29
+ * CSS class prefix
30
+ */
31
+ prefix?: string;
32
+
33
+ [key: string]: any;
34
+ }
35
+
36
+ /**
37
+ * Component with badge capabilities
38
+ */
39
+ export interface BadgeComponent extends BaseComponent {
40
+ /**
41
+ * Badge component instance
42
+ */
43
+ badge?: any;
44
+ }
45
+
46
+ /**
47
+ * Adds badge functionality to a component
48
+ * Creates and configures a badge component attached to the main component
49
+ *
50
+ * @param {BadgeConfig} config - Badge configuration
51
+ * @returns {Function} Component enhancer with badge functionality
52
+ */
53
+ export const withBadge = <T extends BadgeConfig>(config: T) =>
54
+ <C extends ElementComponent>(component: C): C & BadgeComponent => {
55
+ // Only create badge if content is provided
56
+ if (config.badge === undefined) {
57
+ return component as C & BadgeComponent;
58
+ }
59
+
60
+ // Create badge configuration
61
+ const badgeConfig = {
62
+ content: config.badge,
63
+ standalone: false,
64
+ target: component.element,
65
+ ...config.badgeConfig || {},
66
+ // Default to top-right position if not specified
67
+ position: config.badgeConfig?.position || 'top-right',
68
+ // Set prefix to match parent component
69
+ prefix: config.prefix || PREFIX
70
+ };
71
+
72
+ // Create badge component
73
+ const badge = createBadge(badgeConfig);
74
+
75
+ return {
76
+ ...component,
77
+ badge
78
+ };
79
+ };
@@ -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,
@@ -15,6 +15,7 @@ export { withTextInput } from './textinput';
15
15
  export { withTextLabel } from './textlabel';
16
16
  export { withTrack } from './track';
17
17
  export { withEvents as withEnhancedEvents } from './withEvents';
18
+ export { withBadge } from './badge';
18
19
 
19
20
  // State management features
20
21
  export { withDisabled } from './disabled';
@@ -32,4 +33,5 @@ export type { CheckableComponent, CheckableManager } from './checkable';
32
33
  export type { TextInputComponent } from './textinput';
33
34
  export type { LabelComponent, LabelManager } from './textlabel';
34
35
  export type { TrackComponent } from './track';
35
- export type { EnhancedEventComponent } from './withEvents';
36
+ export type { EnhancedEventComponent } from './withEvents';
37
+ export type { BadgeComponent, BadgeConfig } from './badge';
@@ -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,27 @@ 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
+ console.log('componentName', component.componentName)
93
+ console.log('position', position)
94
+
95
+ if (position && component.componentName !== 'slider') {
96
+ component.element.classList.add(`${config.prefix}-${config.componentName}--label-${position}`);
97
+ }
74
98
 
75
99
  const label: LabelManager = {
76
100
  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'