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,233 +0,0 @@
1
- // src/components/slider/features/keyboard.ts
2
- import { SLIDER_EVENTS } from '../constants';
3
-
4
- /**
5
- * Add keyboard interaction handlers to slider component
6
- *
7
- * @param state Slider state object
8
- * @param handlers Object containing handler methods
9
- * @returns Event handlers for keyboard interactions
10
- */
11
- export const createKeyboardHandlers = (state, handlers) => {
12
- const {
13
- secondThumb,
14
- secondValueBubble,
15
- valueBubble
16
- } = state.component.structure;
17
-
18
- const {
19
- showValueBubble,
20
- updateUi,
21
- triggerEvent
22
- } = handlers;
23
-
24
- // Last focused thumb tracker to handle tab sequences properly
25
- let lastFocusedThumb = null;
26
-
27
- /**
28
- * Clear any existing bubble hide timers
29
- */
30
- const clearBubbleHideTimer = () => {
31
- if (state.valueHideTimer) {
32
- clearTimeout(state.valueHideTimer);
33
- state.valueHideTimer = null;
34
- }
35
- };
36
-
37
- /**
38
- * Hide all bubbles immediately
39
- */
40
- const hideAllBubbles = () => {
41
- // Clear any pending hide timers
42
- clearBubbleHideTimer();
43
-
44
- // Hide both bubbles immediately
45
- if (valueBubble) {
46
- showValueBubble(valueBubble, false);
47
- }
48
- if (secondValueBubble) {
49
- showValueBubble(secondValueBubble, false);
50
- }
51
- };
52
-
53
- /**
54
- * Shows a bubble element with consistent behavior
55
- */
56
- const showBubble = (bubble) => {
57
- // First hide all bubbles
58
- hideAllBubbles();
59
-
60
- // Then show the active bubble
61
- if (bubble) {
62
- showValueBubble(bubble, true);
63
- }
64
- };
65
-
66
- /**
67
- * Hides a bubble element with optional delay
68
- */
69
- const hideBubble = (bubble, delay = 0) => {
70
- // Clear any existing timers
71
- clearBubbleHideTimer();
72
-
73
- if (!bubble) return;
74
-
75
- if (delay > 0) {
76
- state.valueHideTimer = setTimeout(() => {
77
- showValueBubble(bubble, false);
78
- }, delay);
79
- } else {
80
- showValueBubble(bubble, false);
81
- }
82
- };
83
-
84
- // Event handlers
85
- const handleKeyDown = (e, isSecondThumb = false) => {
86
- if (state.component.disabled && state.component.disabled.isDisabled()) return;
87
-
88
- const step = state.step || 1;
89
- let newValue;
90
- let stepSize = step;
91
-
92
- // Determine which value to modify
93
- if (isSecondThumb) {
94
- newValue = state.secondValue;
95
- } else {
96
- newValue = state.value;
97
- }
98
-
99
- // Handle tab key specifically for range sliders
100
- if (e.key === 'Tab') {
101
- // Let the browser handle the tab navigation
102
- // We'll deal with showing/hiding bubbles in the focus/blur handlers
103
- return;
104
- }
105
-
106
- // Determine step size based on modifier keys
107
- if (e.shiftKey) {
108
- stepSize = step * 10; // Large step when Shift is pressed
109
- }
110
-
111
- let valueChanged = false;
112
-
113
- switch (e.key) {
114
- case 'ArrowRight':
115
- case 'ArrowUp':
116
- e.preventDefault();
117
- newValue = Math.min(newValue + stepSize, state.max);
118
- valueChanged = true;
119
- break;
120
-
121
- case 'ArrowLeft':
122
- case 'ArrowDown':
123
- e.preventDefault();
124
- newValue = Math.max(newValue - stepSize, state.min);
125
- valueChanged = true;
126
- break;
127
-
128
- case 'Home':
129
- e.preventDefault();
130
- newValue = state.min;
131
- valueChanged = true;
132
- break;
133
-
134
- case 'End':
135
- e.preventDefault();
136
- newValue = state.max;
137
- valueChanged = true;
138
- break;
139
-
140
- case 'PageUp':
141
- e.preventDefault();
142
- newValue = Math.min(newValue + (step * 10), state.max);
143
- valueChanged = true;
144
- break;
145
-
146
- case 'PageDown':
147
- e.preventDefault();
148
- newValue = Math.max(newValue - (step * 10), state.min);
149
- valueChanged = true;
150
- break;
151
-
152
- default:
153
- return; // Exit if not a handled key
154
- }
155
-
156
- if (!valueChanged) return;
157
-
158
- // Update active bubble reference
159
- state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
160
-
161
- // Show value bubble during keyboard interaction
162
- showBubble(state.activeBubble);
163
-
164
- // Update the value
165
- if (isSecondThumb) {
166
- state.secondValue = newValue;
167
- } else {
168
- state.value = newValue;
169
- }
170
-
171
- // Update UI
172
- updateUi();
173
-
174
- // Trigger events
175
- triggerEvent(SLIDER_EVENTS.INPUT, e);
176
- triggerEvent(SLIDER_EVENTS.CHANGE, e);
177
- };
178
-
179
- const handleFocus = (e, isSecondThumb = false) => {
180
- if (state.component.disabled && state.component.disabled.isDisabled()) return;
181
-
182
- // Track the currently focused thumb for tab sequence handling
183
- const currentThumb = isSecondThumb ? secondThumb : state.component.structure.thumb;
184
-
185
- // If we're tabbing between thumbs, hide the previous bubble immediately
186
- if (lastFocusedThumb && lastFocusedThumb !== currentThumb) {
187
- hideAllBubbles();
188
- }
189
-
190
- // Update the last focused thumb
191
- lastFocusedThumb = currentThumb;
192
-
193
- // Add a class to indicate keyboard focus
194
- currentThumb.classList.add(`${state.component.getClass('slider-thumb')}--focused`);
195
-
196
- // Show value bubble on focus
197
- const bubble = isSecondThumb ? secondValueBubble : valueBubble;
198
- showBubble(bubble);
199
-
200
- // Update active bubble reference
201
- state.activeBubble = bubble;
202
-
203
- // Trigger focus event
204
- triggerEvent(SLIDER_EVENTS.FOCUS, e);
205
- };
206
-
207
- const handleBlur = (e, isSecondThumb = false) => {
208
- // Remove keyboard focus class
209
- const thumb = isSecondThumb ? secondThumb : state.component.structure.thumb;
210
- thumb.classList.remove(`${state.component.getClass('slider-thumb')}--focused`);
211
-
212
- // Only hide the bubble if we're not tabbing to another thumb
213
- // This check prevents the bubble from flickering when tabbing between thumbs
214
- const relatedTarget = e.relatedTarget;
215
- const otherThumb = isSecondThumb ? state.component.structure.thumb : secondThumb;
216
-
217
- if (!relatedTarget || relatedTarget !== otherThumb) {
218
- // We're not tabbing to the other thumb, so we can hide the bubble
219
- const bubble = isSecondThumb ? secondValueBubble : valueBubble;
220
- hideBubble(bubble, 200);
221
- }
222
-
223
- // Trigger blur event
224
- triggerEvent(SLIDER_EVENTS.BLUR, e);
225
- };
226
-
227
- // Return handlers
228
- return {
229
- handleKeyDown,
230
- handleFocus,
231
- handleBlur
232
- };
233
- };
@@ -1,80 +0,0 @@
1
- // src/components/switch/constants.ts
2
-
3
- /**
4
- * Label position options
5
- */
6
- export const SWITCH_LABEL_POSITION = {
7
- START: 'start',
8
- END: 'end'
9
- } as const;
10
-
11
- /**
12
- * Validation schema for switch configuration
13
- */
14
- export const SWITCH_SCHEMA = {
15
- type: 'object',
16
- properties: {
17
- name: {
18
- type: 'string',
19
- optional: true
20
- },
21
- checked: {
22
- type: 'boolean',
23
- optional: true
24
- },
25
- required: {
26
- type: 'boolean',
27
- optional: true
28
- },
29
- disabled: {
30
- type: 'boolean',
31
- optional: true
32
- },
33
- value: {
34
- type: 'string',
35
- optional: true
36
- },
37
- label: {
38
- type: 'string',
39
- optional: true
40
- },
41
- labelPosition: {
42
- type: 'string',
43
- enum: Object.values(SWITCH_LABEL_POSITION),
44
- optional: true
45
- },
46
- icon: {
47
- type: 'string',
48
- optional: true
49
- },
50
- ariaLabel: {
51
- type: 'string',
52
- optional: true
53
- },
54
- class: {
55
- type: 'string',
56
- optional: true
57
- }
58
- }
59
- } as const;
60
-
61
- /**
62
- * Switch state classes
63
- */
64
- export const SWITCH_STATES = {
65
- CHECKED: 'checked',
66
- DISABLED: 'disabled',
67
- FOCUSED: 'focused'
68
- } as const;
69
-
70
- /**
71
- * Switch element classes
72
- */
73
- export const SWITCH_CLASSES = {
74
- ROOT: 'switch',
75
- INPUT: 'switch-input',
76
- TRACK: 'switch-track',
77
- THUMB: 'thumb',
78
- THUMB_ICON: 'thumb-icon',
79
- LABEL: 'switch-label'
80
- } as const;
@@ -1,89 +0,0 @@
1
- // src/components/tabs/constants.ts
2
-
3
- /**
4
- * Tab variants
5
- */
6
- export const TABS_VARIANTS = {
7
- /** Primary tabs (standard MD3 style) */
8
- PRIMARY: 'primary',
9
- /** Secondary tabs (less prominent variant) */
10
- SECONDARY: 'secondary'
11
- };
12
-
13
- /**
14
- * Tab states
15
- */
16
- export const TAB_STATES = {
17
- /** Active (selected) tab state */
18
- ACTIVE: 'active',
19
- /** Inactive (unselected) tab state */
20
- INACTIVE: 'inactive',
21
- /** Disabled tab state */
22
- DISABLED: 'disabled'
23
- };
24
-
25
- /**
26
- * Tab layout types
27
- */
28
- export const TAB_LAYOUT = {
29
- /** Icon-only tab layout */
30
- ICON_ONLY: 'icon-only',
31
- /** Text-only tab layout */
32
- TEXT_ONLY: 'text-only',
33
- /** Icon and text layout */
34
- ICON_AND_TEXT: 'icon-and-text'
35
- };
36
-
37
- /**
38
- * Tab interaction states (for styling)
39
- */
40
- export const TAB_INTERACTION_STATES = {
41
- /** Default enabled state */
42
- ENABLED: 'enabled',
43
- /** Hover state */
44
- HOVER: 'hover',
45
- /** Focus state */
46
- FOCUS: 'focus',
47
- /** Pressed/active state */
48
- PRESSED: 'pressed'
49
- };
50
-
51
- /**
52
- * Tab animation constants
53
- */
54
- export const TAB_ANIMATION = {
55
- /** Standard transition duration in ms */
56
- TRANSITION_DURATION: 200,
57
- /** Standard transition timing function */
58
- TRANSITION_TIMING: 'cubic-bezier(0.4, 0, 0.2, 1)',
59
- /** Ripple animation duration in ms */
60
- RIPPLE_DURATION: 400
61
- };
62
-
63
- /**
64
- * Tab accessibility roles
65
- */
66
- export const TAB_A11Y = {
67
- /** Tab role */
68
- TAB_ROLE: 'tab',
69
- /** Tablist role */
70
- TABLIST_ROLE: 'tablist',
71
- /** Tabpanel role */
72
- TABPANEL_ROLE: 'tabpanel'
73
- };
74
-
75
- /**
76
- * MD3 tokens for tab colors
77
- */
78
- export const TAB_COLORS = {
79
- /** Surface color for container */
80
- SURFACE: 'surface',
81
- /** Primary color for active tab and indicator */
82
- PRIMARY: 'primary',
83
- /** On-surface color for active secondary tabs */
84
- ON_SURFACE: 'on-surface',
85
- /** On-surface-variant for inactive tabs */
86
- ON_SURFACE_VARIANT: 'on-surface-variant',
87
- /** Outline variant for divider */
88
- OUTLINE_VARIANT: 'outline-variant'
89
- };
@@ -1,232 +0,0 @@
1
- // src/core/collection/adapters/mongodb.js
2
-
3
- import { MongoClient, ObjectId } from 'mongodb'
4
- import { OPERATORS, createBaseAdapter } from './base'
5
-
6
- const MONGODB_OPERATORS = {
7
- [OPERATORS.EQ]: '$eq',
8
- [OPERATORS.NE]: '$ne',
9
- [OPERATORS.GT]: '$gt',
10
- [OPERATORS.GTE]: '$gte',
11
- [OPERATORS.LT]: '$lt',
12
- [OPERATORS.LTE]: '$lte',
13
- [OPERATORS.IN]: '$in',
14
- [OPERATORS.NIN]: '$nin',
15
- [OPERATORS.CONTAINS]: '$regex',
16
- [OPERATORS.STARTS_WITH]: '$regex',
17
- [OPERATORS.ENDS_WITH]: '$regex'
18
- }
19
-
20
- export const createMongoAdapter = (config = {}) => {
21
- const base = createBaseAdapter(config)
22
- let client = null
23
- let db = null
24
- let collection = null
25
-
26
- const transformDocument = (doc) => {
27
- if (!doc) return null
28
- const { _id, ...rest } = doc
29
- return { id: _id.toString(), ...rest }
30
- }
31
-
32
- const transformForMongo = (doc) => {
33
- if (!doc) return null
34
- const { id, ...rest } = doc
35
- return { _id: id ? new ObjectId(id) : new ObjectId(), ...rest }
36
- }
37
-
38
- const transformQuery = (query) => {
39
- const transformed = {}
40
-
41
- Object.entries(query).forEach(([field, conditions]) => {
42
- if (typeof conditions === 'object') {
43
- transformed[field] = Object.entries(conditions).reduce((acc, [op, value]) => {
44
- const mongoOp = MONGODB_OPERATORS[op]
45
- if (!mongoOp) return acc
46
-
47
- if (op === OPERATORS.CONTAINS) {
48
- acc[mongoOp] = new RegExp(value, 'i')
49
- } else if (op === OPERATORS.STARTS_WITH) {
50
- acc[mongoOp] = new RegExp(`^${value}`, 'i')
51
- } else if (op === OPERATORS.ENDS_WITH) {
52
- acc[mongoOp] = new RegExp(`${value}$`, 'i')
53
- } else {
54
- acc[mongoOp] = value
55
- }
56
-
57
- return acc
58
- }, {})
59
- } else {
60
- transformed[field] = conditions
61
- }
62
- })
63
-
64
- return transformed
65
- }
66
-
67
- return {
68
- ...base,
69
-
70
- connect: async () => {
71
- try {
72
- client = new MongoClient(config.uri, {
73
- useUnifiedTopology: true,
74
- maxPoolSize: 10,
75
- ...config.options
76
- })
77
-
78
- await client.connect()
79
- db = client.db(config.dbName)
80
- collection = db.collection(config.collection)
81
-
82
- // Optional: Create indexes
83
- // await collection.createIndex({ field: 1 })
84
- } catch (error) {
85
- return base.handleError(new Error(`MongoDB connection failed: ${error.message}`))
86
- }
87
- },
88
-
89
- disconnect: async () => {
90
- if (client) {
91
- await client.close()
92
- client = null
93
- db = null
94
- collection = null
95
- }
96
- },
97
-
98
- create: async (items) => {
99
- if (!collection) {
100
- return base.handleError(new Error('Not connected to MongoDB'))
101
- }
102
-
103
- const docs = items.map(item => transformForMongo(item))
104
- const result = await collection.insertMany(docs)
105
-
106
- return items.map((item, index) => ({
107
- ...item,
108
- id: result.insertedIds[index].toString()
109
- }))
110
- },
111
-
112
- read: async (query = {}, options = {}) => {
113
- if (!collection) {
114
- return base.handleError(new Error('Not connected to MongoDB'))
115
- }
116
-
117
- const {
118
- skip = 0,
119
- limit = 0,
120
- sort = {},
121
- projection = {}
122
- } = options
123
-
124
- const mongoQuery = transformQuery(query)
125
-
126
- const cursor = collection
127
- .find(mongoQuery)
128
- .skip(skip)
129
- .limit(limit)
130
- .project(projection)
131
- .sort(sort)
132
-
133
- const docs = await cursor.toArray()
134
- return docs.map(doc => transformDocument(doc))
135
- },
136
-
137
- update: async (items) => {
138
- if (!collection) {
139
- return base.handleError(new Error('Not connected to MongoDB'))
140
- }
141
-
142
- const operations = items.map(item => ({
143
- updateOne: {
144
- filter: { _id: new ObjectId(item.id) },
145
- update: { $set: transformForMongo(item) },
146
- upsert: false
147
- }
148
- }))
149
-
150
- await collection.bulkWrite(operations)
151
- return items
152
- },
153
-
154
- delete: async (ids) => {
155
- if (!collection) {
156
- return base.handleError(new Error('Not connected to MongoDB'))
157
- }
158
-
159
- const mongoIds = ids.map(id => new ObjectId(id))
160
- await collection.deleteMany({ _id: { $in: mongoIds } })
161
- return ids
162
- },
163
-
164
- query: async (query = {}, options = {}) => {
165
- if (!collection) {
166
- return base.handleError(new Error('Not connected to MongoDB'))
167
- }
168
-
169
- const {
170
- pipeline = [],
171
- skip = 0,
172
- limit = 0
173
- } = options
174
-
175
- const mongoQuery = transformQuery(query)
176
-
177
- const aggregation = [
178
- { $match: mongoQuery },
179
- ...pipeline
180
- ]
181
-
182
- if (skip > 0) {
183
- aggregation.push({ $skip: skip })
184
- }
185
-
186
- if (limit > 0) {
187
- aggregation.push({ $limit: limit })
188
- }
189
-
190
- const docs = await collection.aggregate(aggregation).toArray()
191
-
192
- return {
193
- results: docs.map(doc => transformDocument(doc)),
194
- total: await collection.countDocuments(mongoQuery)
195
- }
196
- },
197
-
198
- watch: (callback, pipeline = []) => {
199
- if (!collection) {
200
- return base.handleError(new Error('Not connected to MongoDB'))
201
- }
202
-
203
- const changeStream = collection.watch(pipeline, {
204
- fullDocument: 'updateLookup'
205
- })
206
-
207
- changeStream.on('change', async (change) => {
208
- const { operationType, documentKey, fullDocument } = change
209
-
210
- switch (operationType) {
211
- case 'insert':
212
- case 'update':
213
- case 'replace':
214
- callback({
215
- type: operationType,
216
- document: transformDocument(fullDocument)
217
- })
218
- break
219
-
220
- case 'delete':
221
- callback({
222
- type: operationType,
223
- documentId: documentKey._id.toString()
224
- })
225
- break
226
- }
227
- })
228
-
229
- return () => changeStream.close()
230
- }
231
- }
232
- }