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,29 +1,61 @@
1
- // src/components/dialog/features.ts
1
+ // src/components/dialog/features.ts (partial updated code)
2
+
2
3
  import { getOverlayConfig } from './config';
3
- import { DIALOG_SIZES, DIALOG_ANIMATIONS, DIALOG_FOOTER_ALIGNMENTS, DIALOG_EVENTS } from './constants';
4
- import { DialogConfig, DialogButton, DialogEvent } from './types';
4
+ import { DialogConfig, DialogButton } from './types';
5
5
  import createButton from '../button';
6
- import { BUTTON_VARIANTS } from '../button/constants';
6
+ import { createDivider } from '../divider'; // Import the divider component
7
+ import { addClass, removeClass, hasClass } from '../../core/dom/classes';
8
+
9
+ // Common constants for internal use
10
+ const SIZE_MEDIUM = 'medium';
11
+ const ANIMATION_SCALE = 'scale';
12
+ const FOOTER_ALIGNMENT_RIGHT = 'right';
13
+ const EVENT_BEFORE_OPEN = 'beforeopen';
14
+ const EVENT_OPEN = 'open';
15
+ const EVENT_AFTER_OPEN = 'afteropen';
16
+ const EVENT_BEFORE_CLOSE = 'beforeclose';
17
+ const EVENT_CLOSE = 'close';
18
+ const EVENT_AFTER_CLOSE = 'afterclose';
19
+
20
+ // Common button variants for internal use
21
+ const BUTTON_VARIANT_TEXT = 'text';
22
+ const BUTTON_VARIANT_FILLED = 'filled';
23
+
24
+ // Arrays for class management
25
+ const ALL_SIZES = ['small', 'medium', 'large', 'fullwidth', 'fullscreen'];
26
+ const ALL_ANIMATIONS = ['scale', 'slide-up', 'slide-down', 'fade'];
27
+ const ALL_FOOTER_ALIGNMENTS = ['right', 'left', 'center', 'space-between'];
28
+
29
+ const DIALOG_EVENTS = {
30
+ OPEN: 'open',
31
+ CLOSE: 'close',
32
+ BEFORE_OPEN: 'beforeopen',
33
+ BEFORE_CLOSE: 'beforeclose',
34
+ AFTER_OPEN: 'afteropen',
35
+ AFTER_CLOSE: 'afterclose'
36
+ };
7
37
 
8
38
  /**
9
- * Creates the dialog DOM structure
39
+ * Creates the dialog DOM structure with proper divider handling
10
40
  * @param config Dialog configuration
11
41
  * @returns Component enhancer with DOM structure
12
42
  */
13
43
  export const withStructure = (config: DialogConfig) => component => {
14
44
  // Create the overlay element
15
45
  const overlayConfig = getOverlayConfig(config);
16
- const overlay = document.createElement(overlayConfig.tag);
46
+ const overlay = document.createElement(overlayConfig.tag || 'div');
17
47
 
18
48
  // Add overlay classes
19
49
  overlay.classList.add(component.getClass('dialog-overlay'));
20
50
 
21
- // Set overlay attributes
22
- Object.entries(overlayConfig.attrs || {}).forEach(([key, value]) => {
23
- if (value !== undefined) {
24
- overlay.setAttribute(key, String(value));
25
- }
26
- });
51
+ // Set overlay attributes safely
52
+ if (overlayConfig.attrs && typeof overlayConfig.attrs === 'object') {
53
+ Object.entries(overlayConfig.attrs).forEach(([key, value]) => {
54
+ if (key && typeof key === 'string' && value !== undefined) {
55
+ overlay.setAttribute(key, String(value));
56
+ }
57
+ });
58
+ }
27
59
 
28
60
  // Set custom z-index if provided
29
61
  if (config.zIndex) {
@@ -63,9 +95,18 @@ export const withStructure = (config: DialogConfig) => component => {
63
95
  <line x1="6" y1="6" x2="18" y2="18"></line>
64
96
  </svg>
65
97
  `;
66
- closeButton.addEventListener('click', () => {
67
- component.events.trigger(DIALOG_EVENTS.CLOSE, { dialog: component });
98
+
99
+ // Close button click handler with event-based communication
100
+ closeButton.addEventListener('click', (e) => {
101
+ e.preventDefault();
102
+ e.stopPropagation();
103
+
104
+ // Use the dialog:close custom event which will be listened for in withVisibility
105
+ if (component && component.emit) {
106
+ component.emit('dialog:close', { source: 'closeButton' });
107
+ }
68
108
  });
109
+
69
110
  header.appendChild(closeButton);
70
111
  }
71
112
 
@@ -88,9 +129,9 @@ export const withStructure = (config: DialogConfig) => component => {
88
129
  footer.classList.add(component.getClass('dialog-footer'));
89
130
 
90
131
  // Apply footer alignment
91
- const alignment = config.footerAlignment || DIALOG_FOOTER_ALIGNMENTS.RIGHT;
92
- if (alignment !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
93
- footer.classList.add(`${component.getClass('dialog-footer')}--${alignment}`);
132
+ const alignment = config.footerAlignment || 'right';
133
+ if (alignment !== 'right') {
134
+ addClass(footer, `${component.getClass('dialog-footer')}--${alignment}`);
94
135
  }
95
136
 
96
137
  // Add buttons if provided
@@ -101,36 +142,70 @@ export const withStructure = (config: DialogConfig) => component => {
101
142
  return footer;
102
143
  };
103
144
 
145
+ const createDividerElement = () => {
146
+ const divider = createDivider({
147
+ variant: 'full-width',
148
+ class: component.getClass('dialog-divider')
149
+ });
150
+ return divider;
151
+ };
152
+
104
153
  // Create the dialog structure
105
154
  const header = createHeader();
106
155
  const content = createContent();
107
156
  const footer = Array.isArray(config.buttons) && config.buttons.length > 0 ? createFooter() : null;
108
157
 
109
- // Add header, content, and footer to dialog
110
- component.element.appendChild(header);
111
- component.element.appendChild(content);
112
- if (footer) {
113
- component.element.appendChild(footer);
158
+ // Add dialog classes to the main component element
159
+ addClass(component.element, component.getClass('dialog'));
160
+
161
+ // Apply size class
162
+ const size = config.size || 'medium';
163
+ if (size !== 'medium') {
164
+ addClass(component.element, `${component.getClass('dialog')}--${size}`);
114
165
  }
115
166
 
116
- // Add dialog to overlay
117
- overlay.appendChild(component.element);
167
+ // Apply animation class
168
+ const animation = config.animation || 'scale';
169
+ if (animation !== 'scale') {
170
+ addClass(component.element, `${component.getClass('dialog')}--${animation}`);
171
+ }
172
+
173
+ // Add header to dialog
174
+ component.element.appendChild(header);
118
175
 
119
- // Add dialog classes
120
- component.element.classList.add(component.getClass('dialog'));
176
+ // Create divider elements if configured
177
+ let headerDivider = null;
178
+ let footerDivider = null;
121
179
 
122
- // Apply size class
123
- const size = config.size || DIALOG_SIZES.MEDIUM;
124
- if (size !== DIALOG_SIZES.MEDIUM) {
125
- component.element.classList.add(`${component.getClass('dialog')}--${size}`);
180
+ if (config.divider) {
181
+ // Add header divider (between header and content)
182
+ headerDivider = createDividerElement();
183
+ headerDivider.element.classList.add(component.getClass('dialog-header-divider'));
184
+ component.element.appendChild(headerDivider.element);
185
+
186
+ // If footer exists, add footer divider (between content and footer)
187
+ if (footer) {
188
+ footerDivider = createDividerElement();
189
+ footerDivider.element.classList.add(component.getClass('dialog-footer-divider'));
190
+ }
126
191
  }
127
192
 
128
- // Apply animation class
129
- const animation = config.animation || DIALOG_ANIMATIONS.SCALE;
130
- if (animation !== DIALOG_ANIMATIONS.SCALE) {
131
- component.element.classList.add(`${component.getClass('dialog')}--${animation}`);
193
+ // Add content to dialog
194
+ component.element.appendChild(content);
195
+
196
+ // Add footer divider before footer if it exists
197
+ if (footerDivider) {
198
+ component.element.appendChild(footerDivider.element);
199
+ }
200
+
201
+ // Add footer to dialog if exists
202
+ if (footer) {
203
+ component.element.appendChild(footer);
132
204
  }
133
205
 
206
+ // Add the dialog element to the overlay
207
+ overlay.appendChild(component.element);
208
+
134
209
  // Add overlay to container or document.body
135
210
  const container = config.container || document.body;
136
211
  container.appendChild(overlay);
@@ -143,11 +218,88 @@ export const withStructure = (config: DialogConfig) => component => {
143
218
  header,
144
219
  content,
145
220
  footer,
221
+ headerDivider,
222
+ footerDivider,
146
223
  container
147
224
  }
148
225
  };
149
226
  };
150
227
 
228
+
229
+ /**
230
+ * Add methods to manage dividers
231
+ * @returns Component enhancer with divider management features
232
+ */
233
+ export const withDivider = () => component => {
234
+ return {
235
+ ...component,
236
+ divider: {
237
+ /**
238
+ * Shows or hides the dividers
239
+ * @param show Whether to show the dividers
240
+ * @returns Component instance for chaining
241
+ */
242
+ toggleDivider(show) {
243
+ // Handle header divider
244
+ if (show && !component.structure.headerDivider) {
245
+ // Create and add header divider
246
+ const headerDivider = createDivider({
247
+ variant: 'full-width',
248
+ class: `${component.getClass('dialog-divider')} ${component.getClass('dialog-header-divider')}`
249
+ });
250
+
251
+ // Insert after header, before content
252
+ component.element.insertBefore(
253
+ headerDivider.element,
254
+ component.structure.content
255
+ );
256
+
257
+ component.structure.headerDivider = headerDivider;
258
+
259
+ // If footer exists, add footer divider
260
+ if (component.structure.footer && !component.structure.footerDivider) {
261
+ const footerDivider = createDivider({
262
+ variant: 'full-width',
263
+ class: `${component.getClass('dialog-divider')} ${component.getClass('dialog-footer-divider')}`
264
+ });
265
+
266
+ // Insert before footer
267
+ component.element.insertBefore(
268
+ footerDivider.element,
269
+ component.structure.footer
270
+ );
271
+
272
+ component.structure.footerDivider = footerDivider;
273
+ }
274
+ } else if (!show) {
275
+ // Remove header divider if it exists
276
+ if (component.structure.headerDivider) {
277
+ component.structure.headerDivider.element.remove();
278
+ component.structure.headerDivider = null;
279
+ }
280
+
281
+ // Remove footer divider if it exists
282
+ if (component.structure.footerDivider) {
283
+ component.structure.footerDivider.element.remove();
284
+ component.structure.footerDivider = null;
285
+ }
286
+ }
287
+
288
+ return component;
289
+ },
290
+
291
+ /**
292
+ * Checks if the dialog has dividers
293
+ * @returns Whether the dialog has dividers
294
+ */
295
+ hasDivider() {
296
+ return component.structure.headerDivider !== null;
297
+ }
298
+ }
299
+ };
300
+ };
301
+
302
+
151
303
  /**
152
304
  * Adds button to dialog footer
153
305
  * @param footer Footer element
@@ -157,7 +309,7 @@ export const withStructure = (config: DialogConfig) => component => {
157
309
  const addButton = (footer: HTMLElement, buttonConfig: DialogButton, component: any) => {
158
310
  const {
159
311
  text,
160
- variant = BUTTON_VARIANTS.TEXT,
312
+ variant = 'text', // Using string literal directly instead of BUTTON_VARIANTS.TEXT
161
313
  onClick,
162
314
  closeDialog = true,
163
315
  autofocus = false,
@@ -170,26 +322,32 @@ const addButton = (footer: HTMLElement, buttonConfig: DialogButton, component: a
170
322
  ...attrs
171
323
  });
172
324
 
173
- // Add click handler
325
+ // Button click handler with event-based communication
174
326
  button.on('click', event => {
327
+ console.log('button click');
175
328
  let shouldClose = closeDialog;
176
329
 
177
330
  // Call onClick handler if provided
178
331
  if (typeof onClick === 'function') {
179
- const result = onClick(event, component);
180
- // If onClick returns false, don't close the dialog
181
- if (result === false) {
182
- shouldClose = false;
332
+ try {
333
+ const result = onClick(event, component);
334
+ if (result === false) {
335
+ shouldClose = false;
336
+ }
337
+ } catch (err) {
338
+ console.error('Error in onClick handler:', err);
183
339
  }
184
340
  }
185
341
 
186
- // Close dialog if needed
342
+ // Close dialog if needed - using event-based communication
187
343
  if (shouldClose) {
188
- component.events.trigger(DIALOG_EVENTS.CLOSE, { dialog: component });
344
+ if (component && component.emit) {
345
+ component.emit('dialog:close', { source: 'button', text });
346
+ }
189
347
  }
190
348
  });
191
349
 
192
- // Set autofocus attribute if needed
350
+ // Set autofocus if needed
193
351
  if (autofocus) {
194
352
  button.element.setAttribute('autofocus', 'true');
195
353
  }
@@ -300,125 +458,154 @@ export const withVisibility = () => component => {
300
458
  function handleOverlayClick(e: MouseEvent) {
301
459
  // Only close if the click was directly on the overlay
302
460
  if (e.target === component.overlay) {
303
- component.events.trigger(DIALOG_EVENTS.CLOSE, {
304
- dialog: component,
305
- originalEvent: e
306
- });
461
+ visibility.close();
307
462
  }
308
463
  }
309
464
 
310
465
  function handleEscKey(e: KeyboardEvent) {
311
- if (e.key === 'Escape' && component.visibility.isOpen()) {
312
- component.events.trigger(DIALOG_EVENTS.CLOSE, {
313
- dialog: component,
314
- originalEvent: e
315
- });
466
+ if (e.key === 'Escape' && visibility.isOpen()) {
467
+ visibility.close();
316
468
  }
317
469
  }
318
470
 
319
471
  // Setup initial state
320
472
  if (isOpen) {
321
- component.overlay.classList.add(`${component.getClass('dialog-overlay')}--visible`);
322
- component.element.classList.add(`${component.getClass('dialog')}--visible`);
473
+ addClass(component.overlay, `${component.getClass('dialog-overlay')}--visible`);
474
+ addClass(component.element, `${component.getClass('dialog')}--visible`);
323
475
 
324
476
  // Setup focus trap and events
325
477
  trapFocus();
326
478
  setupEvents();
327
479
  }
328
480
 
329
- return {
330
- ...component,
331
- visibility: {
332
- open() {
333
- // Don't do anything if already open
334
- if (this.isOpen()) return;
335
-
336
- // Store the currently focused element
337
- previouslyFocusedElement = document.activeElement as HTMLElement;
338
-
339
- // Trigger before open event
340
- const beforeOpenEvent = { dialog: component, defaultPrevented: false, preventDefault: () => { beforeOpenEvent.defaultPrevented = true; } };
341
- component.events.trigger(DIALOG_EVENTS.BEFORE_OPEN, beforeOpenEvent);
342
-
343
- // If event was prevented, don't open
344
- if (beforeOpenEvent.defaultPrevented) return;
481
+ // Create visibility object with clean methods
482
+ const visibility = {
483
+ open() {
484
+ // Don't do anything if already open
485
+ if (this.isOpen()) return;
486
+
487
+ // Store the currently focused element
488
+ previouslyFocusedElement = document.activeElement as HTMLElement;
489
+
490
+ // Trigger before open event
491
+ const beforeOpenEvent = {
492
+ dialog: component,
493
+ defaultPrevented: false,
494
+ preventDefault: () => { beforeOpenEvent.defaultPrevented = true; }
495
+ };
496
+
497
+ if (typeof component.emit === 'function') {
498
+ component.emit(DIALOG_EVENTS.BEFORE_OPEN, beforeOpenEvent);
499
+ }
500
+
501
+ // If event was prevented, don't open
502
+ if (beforeOpenEvent.defaultPrevented) return;
503
+
504
+ // Add to DOM if needed
505
+ if (component.overlay && !component.overlay.parentNode) {
506
+ const container = component.structure.container || document.body;
507
+ container.appendChild(component.overlay);
508
+ }
509
+
510
+ // Show the overlay
511
+ addClass(component.overlay, `${component.getClass('dialog-overlay')}--visible`);
512
+
513
+ // Show the dialog
514
+ setTimeout(() => {
515
+ addClass(component.element, `${component.getClass('dialog')}--visible`);
345
516
 
346
- // Show the overlay
347
- component.overlay.classList.add(`${component.getClass('dialog-overlay')}--visible`);
517
+ // Setup focus trap and events
518
+ trapFocus();
519
+ setupEvents();
348
520
 
349
- // Show the dialog after a small delay to allow the overlay animation to start
350
- setTimeout(() => {
351
- component.element.classList.add(`${component.getClass('dialog')}--visible`);
352
-
353
- // Setup focus trap and events
354
- trapFocus();
355
- setupEvents();
521
+ // Trigger open event
522
+ if (typeof component.emit === 'function') {
523
+ component.emit(DIALOG_EVENTS.OPEN, { dialog: component });
356
524
 
357
- // Trigger after open event after animation completes
358
525
  setTimeout(() => {
359
- component.events.trigger(DIALOG_EVENTS.AFTER_OPEN, { dialog: component });
526
+ component.emit(DIALOG_EVENTS.AFTER_OPEN, { dialog: component });
360
527
  }, animationDuration);
361
-
362
- // Trigger open event
363
- component.events.trigger(DIALOG_EVENTS.OPEN, { dialog: component });
364
- }, 10);
365
- },
528
+ }
529
+ }, 10);
530
+ },
531
+
532
+ close() {
533
+ console.log('Dialog close method called');
366
534
 
367
- close() {
368
- // Don't do anything if already closed
369
- if (!this.isOpen()) return;
370
-
371
- // Trigger before close event
372
- const beforeCloseEvent = { dialog: component, defaultPrevented: false, preventDefault: () => { beforeCloseEvent.defaultPrevented = true; } };
373
- component.events.trigger(DIALOG_EVENTS.BEFORE_CLOSE, beforeCloseEvent);
374
-
375
- // If event was prevented, don't close
376
- if (beforeCloseEvent.defaultPrevented) return;
377
-
378
- // Hide the dialog
379
- component.element.classList.remove(`${component.getClass('dialog')}--visible`);
380
-
381
- // Release focus trap and cleanup events
382
- releaseFocus();
383
- cleanupEvents();
384
-
385
- // Trigger close event
386
- component.events.trigger(DIALOG_EVENTS.CLOSE, { dialog: component });
387
-
388
- // Hide the overlay after animation completes
389
- setTimeout(() => {
390
- component.overlay.classList.remove(`${component.getClass('dialog-overlay')}--visible`);
391
-
392
- // Trigger after close event
393
- component.events.trigger(DIALOG_EVENTS.AFTER_CLOSE, { dialog: component });
394
- }, animationDuration);
395
- },
535
+ // Trigger before close event
536
+ const beforeCloseEvent = {
537
+ dialog: component,
538
+ defaultPrevented: false,
539
+ preventDefault: () => { beforeCloseEvent.defaultPrevented = true; }
540
+ };
396
541
 
397
- toggle(open?: boolean) {
398
- if (open === undefined) {
399
- // Toggle based on current state
400
- if (this.isOpen()) {
401
- this.close();
402
- } else {
403
- this.open();
404
- }
405
- } else if (open) {
406
- this.open();
407
- } else {
408
- this.close();
409
- }
410
- },
542
+ if (typeof component.emit === 'function') {
543
+ component.emit(DIALOG_EVENTS.BEFORE_CLOSE, beforeCloseEvent);
544
+ }
545
+
546
+ // If event was prevented, don't close
547
+ if (beforeCloseEvent.defaultPrevented) {
548
+ console.log('Dialog close prevented by event handler');
549
+ return;
550
+ }
551
+
552
+ // Get class names
553
+ const dialogVisibleClass = `${component.getClass('dialog')}--visible`;
554
+ const overlayVisibleClass = `${component.getClass('dialog-overlay')}--visible`;
411
555
 
412
- isOpen() {
413
- return component.element.classList.contains(`${component.getClass('dialog')}--visible`);
556
+ // Remove dialog visible class
557
+ removeClass(component.element, dialogVisibleClass);
558
+
559
+ // Remove overlay visible class
560
+ removeClass(component.overlay, overlayVisibleClass);
561
+
562
+ // Release focus and cleanup events
563
+ releaseFocus();
564
+ cleanupEvents();
565
+
566
+ // Trigger close events
567
+ if (typeof component.emit === 'function') {
568
+ component.emit(DIALOG_EVENTS.CLOSE, { dialog: component });
569
+ }
570
+
571
+ // Remove from DOM after animation completes
572
+ setTimeout(() => {
573
+ if (component.overlay && component.overlay.parentNode) {
574
+ component.overlay.parentNode.removeChild(component.overlay);
575
+ }
576
+
577
+ if (typeof component.emit === 'function') {
578
+ component.emit(DIALOG_EVENTS.AFTER_CLOSE, { dialog: component });
579
+ }
580
+ }, animationDuration);
581
+ },
582
+
583
+ toggle(open?: boolean) {
584
+ if (open === undefined) {
585
+ this.isOpen() ? this.close() : this.open();
586
+ } else if (open) {
587
+ this.open();
588
+ } else {
589
+ this.close();
414
590
  }
415
591
  },
416
592
 
417
- focus: {
418
- trapFocus,
419
- releaseFocus
593
+ isOpen() {
594
+ return component.element.classList.contains(`${component.getClass('dialog')}--visible`);
420
595
  }
421
596
  };
597
+
598
+ // Set up event listener for the dialog:close event
599
+ if (component && component.on) {
600
+ component.on('dialog:close', () => {
601
+ visibility.close();
602
+ });
603
+ }
604
+
605
+ return {
606
+ ...component,
607
+ visibility
608
+ };
422
609
  };
423
610
 
424
611
  /**
@@ -558,9 +745,9 @@ export const withButtons = () => component => {
558
745
  footer.classList.add(component.getClass('dialog-footer'));
559
746
 
560
747
  // Apply footer alignment
561
- const alignment = component.config.footerAlignment || DIALOG_FOOTER_ALIGNMENTS.RIGHT;
562
- if (alignment !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
563
- footer.classList.add(`${component.getClass('dialog-footer')}--${alignment}`);
748
+ const alignment = component.config.footerAlignment || 'right';
749
+ if (alignment !== 'right') {
750
+ addClass(footer, `${component.getClass('dialog-footer')}--${alignment}`);
564
751
  }
565
752
 
566
753
  component.element.appendChild(footer);
@@ -614,19 +801,22 @@ export const withButtons = () => component => {
614
801
  * Sets footer alignment
615
802
  * @param alignment Footer alignment
616
803
  */
617
- setFooterAlignment(alignment: keyof typeof DIALOG_FOOTER_ALIGNMENTS | DIALOG_FOOTER_ALIGNMENTS) {
804
+ setFooterAlignment(alignment: string) {
618
805
  if (!component.structure.footer) return;
619
806
 
807
+ // Define all possible alignments
808
+ const ALL_ALIGNMENTS = ['right', 'left', 'center', 'space-between'];
809
+
620
810
  // Remove existing alignment classes
621
- Object.values(DIALOG_FOOTER_ALIGNMENTS).forEach(align => {
622
- if (align !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
623
- component.structure.footer.classList.remove(`${component.getClass('dialog-footer')}--${align}`);
811
+ ALL_ALIGNMENTS.forEach(align => {
812
+ if (align !== 'right') {
813
+ removeClass(component.structure.footer, `${component.getClass('dialog-footer')}--${align}`);
624
814
  }
625
815
  });
626
816
 
627
817
  // Add new alignment class if not right (default)
628
- if (alignment !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
629
- component.structure.footer.classList.add(`${component.getClass('dialog-footer')}--${alignment}`);
818
+ if (alignment !== 'right') {
819
+ addClass(component.structure.footer, `${component.getClass('dialog-footer')}--${alignment}`);
630
820
  }
631
821
  }
632
822
  }
@@ -645,15 +835,18 @@ export const withSize = () => component => {
645
835
  * Sets dialog size
646
836
  * @param size Size variant
647
837
  */
648
- setSize(size: keyof typeof DIALOG_SIZES | DIALOG_SIZES) {
838
+ setSize(size: string) {
839
+ // Define all possible sizes
840
+ const ALL_SIZES = ['small', 'medium', 'large', 'fullwidth', 'fullscreen'];
841
+
649
842
  // Remove existing size classes
650
- Object.values(DIALOG_SIZES).forEach(sizeValue => {
651
- component.element.classList.remove(`${component.getClass('dialog')}--${sizeValue}`);
843
+ ALL_SIZES.forEach(sizeValue => {
844
+ removeClass(component.element, `${component.getClass('dialog')}--${sizeValue}`);
652
845
  });
653
846
 
654
847
  // Add new size class if not medium (default)
655
- if (size !== DIALOG_SIZES.MEDIUM) {
656
- component.element.classList.add(`${component.getClass('dialog')}--${size}`);
848
+ if (size !== 'medium') {
849
+ addClass(component.element, `${component.getClass('dialog')}--${size}`);
657
850
  }
658
851
  }
659
852
  }
@@ -674,9 +867,10 @@ export const withConfirm = () => component => {
674
867
  message,
675
868
  confirmText = 'Yes',
676
869
  cancelText = 'No',
677
- confirmVariant = BUTTON_VARIANTS.FILLED,
678
- cancelVariant = BUTTON_VARIANTS.TEXT,
679
- size = DIALOG_SIZES.SMALL
870
+ // Use string literals directly
871
+ confirmVariant = 'filled',
872
+ cancelVariant = 'text',
873
+ size = 'small'
680
874
  } = options;
681
875
 
682
876
  // Set dialog properties