mtrl 0.2.6 → 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.
- package/index.ts +18 -0
- package/package.json +1 -1
- package/src/components/badge/_styles.scss +117 -109
- package/src/components/badge/api.ts +57 -59
- package/src/components/badge/badge.ts +16 -2
- package/src/components/badge/config.ts +65 -11
- package/src/components/badge/constants.ts +22 -12
- package/src/components/badge/features.ts +44 -40
- package/src/components/badge/types.ts +42 -30
- package/src/components/bottom-app-bar/_styles.scss +103 -0
- package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
- package/src/components/bottom-app-bar/config.ts +73 -0
- package/src/components/bottom-app-bar/index.ts +11 -0
- package/src/components/bottom-app-bar/types.ts +108 -0
- package/src/components/button/_styles.scss +0 -10
- package/src/components/button/api.ts +5 -0
- package/src/components/button/config.ts +5 -0
- package/src/components/button/types.ts +6 -0
- package/src/components/card/card.ts +13 -25
- package/src/components/card/config.ts +67 -22
- package/src/components/card/features.ts +3 -0
- package/src/components/card/types.ts +28 -0
- package/src/components/checkbox/_styles.scss +0 -2
- package/src/components/datepicker/_styles.scss +358 -0
- package/src/components/datepicker/api.ts +272 -0
- package/src/components/datepicker/config.ts +144 -0
- package/src/components/datepicker/constants.ts +98 -0
- package/src/components/datepicker/datepicker.ts +346 -0
- package/src/components/datepicker/index.ts +9 -0
- package/src/components/datepicker/render.ts +452 -0
- package/src/components/datepicker/types.ts +268 -0
- package/src/components/datepicker/utils.ts +290 -0
- package/src/components/dialog/_styles.scss +174 -128
- package/src/components/dialog/api.ts +48 -13
- package/src/components/dialog/config.ts +9 -5
- package/src/components/dialog/dialog.ts +6 -3
- package/src/components/dialog/features.ts +290 -130
- package/src/components/dialog/types.ts +7 -4
- package/src/components/divider/_styles.scss +57 -0
- package/src/components/divider/config.ts +81 -0
- package/src/components/divider/divider.ts +37 -0
- package/src/components/divider/features.ts +207 -0
- package/src/components/divider/index.ts +5 -0
- package/src/components/divider/types.ts +55 -0
- package/src/components/extended-fab/_styles.scss +267 -0
- package/src/components/extended-fab/api.ts +141 -0
- package/src/components/extended-fab/config.ts +108 -0
- package/src/components/extended-fab/constants.ts +36 -0
- package/src/components/extended-fab/extended-fab.ts +125 -0
- package/src/components/extended-fab/index.ts +4 -0
- package/src/components/extended-fab/types.ts +287 -0
- package/src/components/fab/_styles.scss +225 -0
- package/src/components/fab/api.ts +97 -0
- package/src/components/fab/config.ts +94 -0
- package/src/components/fab/constants.ts +41 -0
- package/src/components/fab/fab.ts +67 -0
- package/src/components/fab/index.ts +4 -0
- package/src/components/fab/types.ts +234 -0
- package/src/components/navigation/_styles.scss +1 -0
- package/src/components/navigation/api.ts +78 -50
- package/src/components/navigation/features/items.ts +280 -0
- package/src/components/navigation/nav-item.ts +72 -23
- package/src/components/navigation/navigation.ts +54 -2
- package/src/components/navigation/types.ts +210 -188
- package/src/components/search/_styles.scss +306 -0
- package/src/components/search/api.ts +203 -0
- package/src/components/search/config.ts +87 -0
- package/src/components/search/constants.ts +21 -0
- package/src/components/search/features/index.ts +4 -0
- package/src/components/search/features/search.ts +718 -0
- package/src/components/search/features/states.ts +165 -0
- package/src/components/search/features/structure.ts +198 -0
- package/src/components/search/index.ts +10 -0
- package/src/components/search/search.ts +52 -0
- package/src/components/search/types.ts +163 -0
- package/src/components/segmented-button/_styles.scss +117 -0
- package/src/components/segmented-button/config.ts +67 -0
- package/src/components/segmented-button/constants.ts +42 -0
- package/src/components/segmented-button/index.ts +4 -0
- package/src/components/segmented-button/segment.ts +155 -0
- package/src/components/segmented-button/segmented-button.ts +250 -0
- package/src/components/segmented-button/types.ts +219 -0
- package/src/components/slider/_styles.scss +83 -24
- package/src/components/slider/accessibility.md +5 -5
- package/src/components/slider/api.ts +41 -120
- package/src/components/slider/config.ts +51 -47
- package/src/components/slider/features/handlers.ts +495 -0
- package/src/components/slider/features/index.ts +1 -2
- package/src/components/slider/features/slider.ts +66 -84
- package/src/components/slider/features/states.ts +195 -0
- package/src/components/slider/features/structure.ts +136 -206
- package/src/components/slider/features/ui.ts +145 -206
- package/src/components/slider/index.ts +2 -11
- package/src/components/slider/slider.ts +9 -12
- package/src/components/slider/types.ts +39 -24
- package/src/components/switch/_styles.scss +0 -2
- package/src/components/tabs/_styles.scss +94 -32
- package/src/components/tabs/features.ts +4 -2
- package/src/components/tabs/indicator.ts +73 -13
- package/src/components/tabs/types.ts +10 -2
- package/src/components/timepicker/README.md +277 -0
- package/src/components/timepicker/_styles.scss +451 -0
- package/src/components/timepicker/api.ts +632 -0
- package/src/components/timepicker/clockdial.ts +482 -0
- package/src/components/timepicker/config.ts +130 -0
- package/src/components/timepicker/constants.ts +138 -0
- package/src/components/timepicker/index.ts +8 -0
- package/src/components/timepicker/render.ts +613 -0
- package/src/components/timepicker/timepicker.ts +117 -0
- package/src/components/timepicker/types.ts +336 -0
- package/src/components/timepicker/utils.ts +241 -0
- package/src/components/top-app-bar/_styles.scss +225 -0
- package/src/components/top-app-bar/config.ts +83 -0
- package/src/components/top-app-bar/index.ts +11 -0
- package/src/components/top-app-bar/top-app-bar.ts +316 -0
- package/src/components/top-app-bar/types.ts +140 -0
- package/src/core/build/_ripple.scss +6 -6
- package/src/core/build/ripple.ts +72 -95
- package/src/core/compose/features/icon.ts +3 -1
- package/src/core/compose/features/ripple.ts +4 -1
- package/src/core/compose/features/textlabel.ts +26 -2
- package/src/core/dom/create.ts +5 -0
- package/src/index.ts +9 -0
- package/src/styles/abstract/_theme.scss +9 -1
- package/src/styles/themes/_autumn.scss +21 -0
- package/src/styles/themes/_base-theme.scss +61 -0
- package/src/styles/themes/_baseline.scss +58 -0
- package/src/styles/themes/_bluekhaki.scss +125 -0
- package/src/styles/themes/_brownbeige.scss +125 -0
- package/src/styles/themes/_browngreen.scss +125 -0
- package/src/styles/themes/_forest.scss +6 -0
- package/src/styles/themes/_greenbeige.scss +125 -0
- package/src/styles/themes/_material.scss +125 -0
- package/src/styles/themes/_ocean.scss +6 -0
- package/src/styles/themes/_sageivory.scss +125 -0
- package/src/styles/themes/_spring.scss +6 -0
- package/src/styles/themes/_summer.scss +5 -0
- package/src/styles/themes/_sunset.scss +5 -0
- package/src/styles/themes/_tealcaramel.scss +125 -0
- package/src/styles/themes/_winter.scss +6 -0
- package/src/components/navigation/features/items.js +0 -192
- package/src/components/slider/features/appearance.ts +0 -94
- package/src/components/slider/features/disabled.ts +0 -68
- package/src/components/slider/features/events.ts +0 -164
- package/src/components/slider/features/interactions.ts +0 -396
- package/src/components/slider/features/keyboard.ts +0 -233
- package/src/core/collection/adapters/mongodb.js +0 -232
|
@@ -1,29 +1,34 @@
|
|
|
1
|
-
// src/components/dialog/features.ts
|
|
1
|
+
// src/components/dialog/features.ts (partial updated code)
|
|
2
|
+
|
|
2
3
|
import { getOverlayConfig } from './config';
|
|
3
4
|
import { DIALOG_SIZES, DIALOG_ANIMATIONS, DIALOG_FOOTER_ALIGNMENTS, DIALOG_EVENTS } from './constants';
|
|
4
5
|
import { DialogConfig, DialogButton, DialogEvent } from './types';
|
|
5
6
|
import createButton from '../button';
|
|
7
|
+
import { createDivider } from '../divider'; // Import the divider component
|
|
6
8
|
import { BUTTON_VARIANTS } from '../button/constants';
|
|
9
|
+
import { addClass, removeClass, hasClass } from '../../core/dom/classes';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
|
-
* Creates the dialog DOM structure
|
|
12
|
+
* Creates the dialog DOM structure with proper divider handling
|
|
10
13
|
* @param config Dialog configuration
|
|
11
14
|
* @returns Component enhancer with DOM structure
|
|
12
15
|
*/
|
|
13
16
|
export const withStructure = (config: DialogConfig) => component => {
|
|
14
17
|
// Create the overlay element
|
|
15
18
|
const overlayConfig = getOverlayConfig(config);
|
|
16
|
-
const overlay = document.createElement(overlayConfig.tag);
|
|
19
|
+
const overlay = document.createElement(overlayConfig.tag || 'div');
|
|
17
20
|
|
|
18
21
|
// Add overlay classes
|
|
19
22
|
overlay.classList.add(component.getClass('dialog-overlay'));
|
|
20
23
|
|
|
21
|
-
// Set overlay attributes
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// Set overlay attributes safely
|
|
25
|
+
if (overlayConfig.attrs && typeof overlayConfig.attrs === 'object') {
|
|
26
|
+
Object.entries(overlayConfig.attrs).forEach(([key, value]) => {
|
|
27
|
+
if (key && typeof key === 'string' && value !== undefined) {
|
|
28
|
+
overlay.setAttribute(key, String(value));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
27
32
|
|
|
28
33
|
// Set custom z-index if provided
|
|
29
34
|
if (config.zIndex) {
|
|
@@ -63,9 +68,18 @@ export const withStructure = (config: DialogConfig) => component => {
|
|
|
63
68
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
64
69
|
</svg>
|
|
65
70
|
`;
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
|
|
72
|
+
// Close button click handler with event-based communication
|
|
73
|
+
closeButton.addEventListener('click', (e) => {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
e.stopPropagation();
|
|
76
|
+
|
|
77
|
+
// Use the dialog:close custom event which will be listened for in withVisibility
|
|
78
|
+
if (component && component.emit) {
|
|
79
|
+
component.emit('dialog:close', { source: 'closeButton' });
|
|
80
|
+
}
|
|
68
81
|
});
|
|
82
|
+
|
|
69
83
|
header.appendChild(closeButton);
|
|
70
84
|
}
|
|
71
85
|
|
|
@@ -90,7 +104,7 @@ export const withStructure = (config: DialogConfig) => component => {
|
|
|
90
104
|
// Apply footer alignment
|
|
91
105
|
const alignment = config.footerAlignment || DIALOG_FOOTER_ALIGNMENTS.RIGHT;
|
|
92
106
|
if (alignment !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
|
|
93
|
-
footer
|
|
107
|
+
addClass(footer, `${component.getClass('dialog-footer')}--${alignment}`);
|
|
94
108
|
}
|
|
95
109
|
|
|
96
110
|
// Add buttons if provided
|
|
@@ -101,36 +115,70 @@ export const withStructure = (config: DialogConfig) => component => {
|
|
|
101
115
|
return footer;
|
|
102
116
|
};
|
|
103
117
|
|
|
118
|
+
const createDividerElement = () => {
|
|
119
|
+
const divider = createDivider({
|
|
120
|
+
variant: 'full-width',
|
|
121
|
+
class: component.getClass('dialog-divider')
|
|
122
|
+
});
|
|
123
|
+
return divider;
|
|
124
|
+
};
|
|
125
|
+
|
|
104
126
|
// Create the dialog structure
|
|
105
127
|
const header = createHeader();
|
|
106
128
|
const content = createContent();
|
|
107
129
|
const footer = Array.isArray(config.buttons) && config.buttons.length > 0 ? createFooter() : null;
|
|
108
130
|
|
|
109
|
-
// Add
|
|
110
|
-
component.element.
|
|
111
|
-
component.element.appendChild(content);
|
|
112
|
-
if (footer) {
|
|
113
|
-
component.element.appendChild(footer);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Add dialog to overlay
|
|
117
|
-
overlay.appendChild(component.element);
|
|
118
|
-
|
|
119
|
-
// Add dialog classes
|
|
120
|
-
component.element.classList.add(component.getClass('dialog'));
|
|
131
|
+
// Add dialog classes to the main component element
|
|
132
|
+
addClass(component.element, component.getClass('dialog'));
|
|
121
133
|
|
|
122
134
|
// Apply size class
|
|
123
135
|
const size = config.size || DIALOG_SIZES.MEDIUM;
|
|
124
136
|
if (size !== DIALOG_SIZES.MEDIUM) {
|
|
125
|
-
component.element
|
|
137
|
+
addClass(component.element, `${component.getClass('dialog')}--${size}`);
|
|
126
138
|
}
|
|
127
139
|
|
|
128
140
|
// Apply animation class
|
|
129
141
|
const animation = config.animation || DIALOG_ANIMATIONS.SCALE;
|
|
130
142
|
if (animation !== DIALOG_ANIMATIONS.SCALE) {
|
|
131
|
-
component.element
|
|
143
|
+
addClass(component.element, `${component.getClass('dialog')}--${animation}`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Add header to dialog
|
|
147
|
+
component.element.appendChild(header);
|
|
148
|
+
|
|
149
|
+
// Create divider elements if configured
|
|
150
|
+
let headerDivider = null;
|
|
151
|
+
let footerDivider = null;
|
|
152
|
+
|
|
153
|
+
if (config.divider) {
|
|
154
|
+
// Add header divider (between header and content)
|
|
155
|
+
headerDivider = createDividerElement();
|
|
156
|
+
headerDivider.element.classList.add(component.getClass('dialog-header-divider'));
|
|
157
|
+
component.element.appendChild(headerDivider.element);
|
|
158
|
+
|
|
159
|
+
// If footer exists, add footer divider (between content and footer)
|
|
160
|
+
if (footer) {
|
|
161
|
+
footerDivider = createDividerElement();
|
|
162
|
+
footerDivider.element.classList.add(component.getClass('dialog-footer-divider'));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Add content to dialog
|
|
167
|
+
component.element.appendChild(content);
|
|
168
|
+
|
|
169
|
+
// Add footer divider before footer if it exists
|
|
170
|
+
if (footerDivider) {
|
|
171
|
+
component.element.appendChild(footerDivider.element);
|
|
132
172
|
}
|
|
133
173
|
|
|
174
|
+
// Add footer to dialog if exists
|
|
175
|
+
if (footer) {
|
|
176
|
+
component.element.appendChild(footer);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Add the dialog element to the overlay
|
|
180
|
+
overlay.appendChild(component.element);
|
|
181
|
+
|
|
134
182
|
// Add overlay to container or document.body
|
|
135
183
|
const container = config.container || document.body;
|
|
136
184
|
container.appendChild(overlay);
|
|
@@ -143,11 +191,88 @@ export const withStructure = (config: DialogConfig) => component => {
|
|
|
143
191
|
header,
|
|
144
192
|
content,
|
|
145
193
|
footer,
|
|
194
|
+
headerDivider,
|
|
195
|
+
footerDivider,
|
|
146
196
|
container
|
|
147
197
|
}
|
|
148
198
|
};
|
|
149
199
|
};
|
|
150
200
|
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Add methods to manage dividers
|
|
204
|
+
* @returns Component enhancer with divider management features
|
|
205
|
+
*/
|
|
206
|
+
export const withDivider = () => component => {
|
|
207
|
+
return {
|
|
208
|
+
...component,
|
|
209
|
+
divider: {
|
|
210
|
+
/**
|
|
211
|
+
* Shows or hides the dividers
|
|
212
|
+
* @param show Whether to show the dividers
|
|
213
|
+
* @returns Component instance for chaining
|
|
214
|
+
*/
|
|
215
|
+
toggleDivider(show) {
|
|
216
|
+
// Handle header divider
|
|
217
|
+
if (show && !component.structure.headerDivider) {
|
|
218
|
+
// Create and add header divider
|
|
219
|
+
const headerDivider = createDivider({
|
|
220
|
+
variant: 'full-width',
|
|
221
|
+
class: `${component.getClass('dialog-divider')} ${component.getClass('dialog-header-divider')}`
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Insert after header, before content
|
|
225
|
+
component.element.insertBefore(
|
|
226
|
+
headerDivider.element,
|
|
227
|
+
component.structure.content
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
component.structure.headerDivider = headerDivider;
|
|
231
|
+
|
|
232
|
+
// If footer exists, add footer divider
|
|
233
|
+
if (component.structure.footer && !component.structure.footerDivider) {
|
|
234
|
+
const footerDivider = createDivider({
|
|
235
|
+
variant: 'full-width',
|
|
236
|
+
class: `${component.getClass('dialog-divider')} ${component.getClass('dialog-footer-divider')}`
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Insert before footer
|
|
240
|
+
component.element.insertBefore(
|
|
241
|
+
footerDivider.element,
|
|
242
|
+
component.structure.footer
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
component.structure.footerDivider = footerDivider;
|
|
246
|
+
}
|
|
247
|
+
} else if (!show) {
|
|
248
|
+
// Remove header divider if it exists
|
|
249
|
+
if (component.structure.headerDivider) {
|
|
250
|
+
component.structure.headerDivider.element.remove();
|
|
251
|
+
component.structure.headerDivider = null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Remove footer divider if it exists
|
|
255
|
+
if (component.structure.footerDivider) {
|
|
256
|
+
component.structure.footerDivider.element.remove();
|
|
257
|
+
component.structure.footerDivider = null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return component;
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Checks if the dialog has dividers
|
|
266
|
+
* @returns Whether the dialog has dividers
|
|
267
|
+
*/
|
|
268
|
+
hasDivider() {
|
|
269
|
+
return component.structure.headerDivider !== null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
|
|
151
276
|
/**
|
|
152
277
|
* Adds button to dialog footer
|
|
153
278
|
* @param footer Footer element
|
|
@@ -170,26 +295,32 @@ const addButton = (footer: HTMLElement, buttonConfig: DialogButton, component: a
|
|
|
170
295
|
...attrs
|
|
171
296
|
});
|
|
172
297
|
|
|
173
|
-
//
|
|
298
|
+
// Button click handler with event-based communication
|
|
174
299
|
button.on('click', event => {
|
|
300
|
+
console.log('button click');
|
|
175
301
|
let shouldClose = closeDialog;
|
|
176
302
|
|
|
177
303
|
// Call onClick handler if provided
|
|
178
304
|
if (typeof onClick === 'function') {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
305
|
+
try {
|
|
306
|
+
const result = onClick(event, component);
|
|
307
|
+
if (result === false) {
|
|
308
|
+
shouldClose = false;
|
|
309
|
+
}
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.error('Error in onClick handler:', err);
|
|
183
312
|
}
|
|
184
313
|
}
|
|
185
314
|
|
|
186
|
-
// Close dialog if needed
|
|
315
|
+
// Close dialog if needed - using event-based communication
|
|
187
316
|
if (shouldClose) {
|
|
188
|
-
component
|
|
317
|
+
if (component && component.emit) {
|
|
318
|
+
component.emit('dialog:close', { source: 'button', text });
|
|
319
|
+
}
|
|
189
320
|
}
|
|
190
321
|
});
|
|
191
322
|
|
|
192
|
-
// Set autofocus
|
|
323
|
+
// Set autofocus if needed
|
|
193
324
|
if (autofocus) {
|
|
194
325
|
button.element.setAttribute('autofocus', 'true');
|
|
195
326
|
}
|
|
@@ -300,125 +431,154 @@ export const withVisibility = () => component => {
|
|
|
300
431
|
function handleOverlayClick(e: MouseEvent) {
|
|
301
432
|
// Only close if the click was directly on the overlay
|
|
302
433
|
if (e.target === component.overlay) {
|
|
303
|
-
|
|
304
|
-
dialog: component,
|
|
305
|
-
originalEvent: e
|
|
306
|
-
});
|
|
434
|
+
visibility.close();
|
|
307
435
|
}
|
|
308
436
|
}
|
|
309
437
|
|
|
310
438
|
function handleEscKey(e: KeyboardEvent) {
|
|
311
|
-
if (e.key === 'Escape' &&
|
|
312
|
-
|
|
313
|
-
dialog: component,
|
|
314
|
-
originalEvent: e
|
|
315
|
-
});
|
|
439
|
+
if (e.key === 'Escape' && visibility.isOpen()) {
|
|
440
|
+
visibility.close();
|
|
316
441
|
}
|
|
317
442
|
}
|
|
318
443
|
|
|
319
444
|
// Setup initial state
|
|
320
445
|
if (isOpen) {
|
|
321
|
-
component.overlay
|
|
322
|
-
component.element
|
|
446
|
+
addClass(component.overlay, `${component.getClass('dialog-overlay')}--visible`);
|
|
447
|
+
addClass(component.element, `${component.getClass('dialog')}--visible`);
|
|
323
448
|
|
|
324
449
|
// Setup focus trap and events
|
|
325
450
|
trapFocus();
|
|
326
451
|
setupEvents();
|
|
327
452
|
}
|
|
328
453
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
open
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
454
|
+
// Create visibility object with clean methods
|
|
455
|
+
const visibility = {
|
|
456
|
+
open() {
|
|
457
|
+
// Don't do anything if already open
|
|
458
|
+
if (this.isOpen()) return;
|
|
459
|
+
|
|
460
|
+
// Store the currently focused element
|
|
461
|
+
previouslyFocusedElement = document.activeElement as HTMLElement;
|
|
462
|
+
|
|
463
|
+
// Trigger before open event
|
|
464
|
+
const beforeOpenEvent = {
|
|
465
|
+
dialog: component,
|
|
466
|
+
defaultPrevented: false,
|
|
467
|
+
preventDefault: () => { beforeOpenEvent.defaultPrevented = true; }
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
if (typeof component.emit === 'function') {
|
|
471
|
+
component.emit(DIALOG_EVENTS.BEFORE_OPEN, beforeOpenEvent);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// If event was prevented, don't open
|
|
475
|
+
if (beforeOpenEvent.defaultPrevented) return;
|
|
476
|
+
|
|
477
|
+
// Add to DOM if needed
|
|
478
|
+
if (component.overlay && !component.overlay.parentNode) {
|
|
479
|
+
const container = component.structure.container || document.body;
|
|
480
|
+
container.appendChild(component.overlay);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Show the overlay
|
|
484
|
+
addClass(component.overlay, `${component.getClass('dialog-overlay')}--visible`);
|
|
485
|
+
|
|
486
|
+
// Show the dialog
|
|
487
|
+
setTimeout(() => {
|
|
488
|
+
addClass(component.element, `${component.getClass('dialog')}--visible`);
|
|
345
489
|
|
|
346
|
-
//
|
|
347
|
-
|
|
490
|
+
// Setup focus trap and events
|
|
491
|
+
trapFocus();
|
|
492
|
+
setupEvents();
|
|
348
493
|
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
component.
|
|
352
|
-
|
|
353
|
-
// Setup focus trap and events
|
|
354
|
-
trapFocus();
|
|
355
|
-
setupEvents();
|
|
494
|
+
// Trigger open event
|
|
495
|
+
if (typeof component.emit === 'function') {
|
|
496
|
+
component.emit(DIALOG_EVENTS.OPEN, { dialog: component });
|
|
356
497
|
|
|
357
|
-
// Trigger after open event after animation completes
|
|
358
498
|
setTimeout(() => {
|
|
359
|
-
component.
|
|
499
|
+
component.emit(DIALOG_EVENTS.AFTER_OPEN, { dialog: component });
|
|
360
500
|
}, animationDuration);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
501
|
+
}
|
|
502
|
+
}, 10);
|
|
503
|
+
},
|
|
504
|
+
|
|
505
|
+
close() {
|
|
506
|
+
console.log('Dialog close method called');
|
|
366
507
|
|
|
367
|
-
close
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
},
|
|
508
|
+
// Trigger before close event
|
|
509
|
+
const beforeCloseEvent = {
|
|
510
|
+
dialog: component,
|
|
511
|
+
defaultPrevented: false,
|
|
512
|
+
preventDefault: () => { beforeCloseEvent.defaultPrevented = true; }
|
|
513
|
+
};
|
|
396
514
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
515
|
+
if (typeof component.emit === 'function') {
|
|
516
|
+
component.emit(DIALOG_EVENTS.BEFORE_CLOSE, beforeCloseEvent);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// If event was prevented, don't close
|
|
520
|
+
if (beforeCloseEvent.defaultPrevented) {
|
|
521
|
+
console.log('Dialog close prevented by event handler');
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Get class names
|
|
526
|
+
const dialogVisibleClass = `${component.getClass('dialog')}--visible`;
|
|
527
|
+
const overlayVisibleClass = `${component.getClass('dialog-overlay')}--visible`;
|
|
528
|
+
|
|
529
|
+
// Remove dialog visible class
|
|
530
|
+
removeClass(component.element, dialogVisibleClass);
|
|
531
|
+
|
|
532
|
+
// Remove overlay visible class
|
|
533
|
+
removeClass(component.overlay, overlayVisibleClass);
|
|
534
|
+
|
|
535
|
+
// Release focus and cleanup events
|
|
536
|
+
releaseFocus();
|
|
537
|
+
cleanupEvents();
|
|
411
538
|
|
|
412
|
-
|
|
413
|
-
|
|
539
|
+
// Trigger close events
|
|
540
|
+
if (typeof component.emit === 'function') {
|
|
541
|
+
component.emit(DIALOG_EVENTS.CLOSE, { dialog: component });
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Remove from DOM after animation completes
|
|
545
|
+
setTimeout(() => {
|
|
546
|
+
if (component.overlay && component.overlay.parentNode) {
|
|
547
|
+
component.overlay.parentNode.removeChild(component.overlay);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (typeof component.emit === 'function') {
|
|
551
|
+
component.emit(DIALOG_EVENTS.AFTER_CLOSE, { dialog: component });
|
|
552
|
+
}
|
|
553
|
+
}, animationDuration);
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
toggle(open?: boolean) {
|
|
557
|
+
if (open === undefined) {
|
|
558
|
+
this.isOpen() ? this.close() : this.open();
|
|
559
|
+
} else if (open) {
|
|
560
|
+
this.open();
|
|
561
|
+
} else {
|
|
562
|
+
this.close();
|
|
414
563
|
}
|
|
415
564
|
},
|
|
416
565
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
releaseFocus
|
|
566
|
+
isOpen() {
|
|
567
|
+
return component.element.classList.contains(`${component.getClass('dialog')}--visible`);
|
|
420
568
|
}
|
|
421
569
|
};
|
|
570
|
+
|
|
571
|
+
// Set up event listener for the dialog:close event
|
|
572
|
+
if (component && component.on) {
|
|
573
|
+
component.on('dialog:close', () => {
|
|
574
|
+
visibility.close();
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return {
|
|
579
|
+
...component,
|
|
580
|
+
visibility
|
|
581
|
+
};
|
|
422
582
|
};
|
|
423
583
|
|
|
424
584
|
/**
|
|
@@ -560,7 +720,7 @@ export const withButtons = () => component => {
|
|
|
560
720
|
// Apply footer alignment
|
|
561
721
|
const alignment = component.config.footerAlignment || DIALOG_FOOTER_ALIGNMENTS.RIGHT;
|
|
562
722
|
if (alignment !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
|
|
563
|
-
footer
|
|
723
|
+
addClass(footer, `${component.getClass('dialog-footer')}--${alignment}`);
|
|
564
724
|
}
|
|
565
725
|
|
|
566
726
|
component.element.appendChild(footer);
|
|
@@ -620,13 +780,13 @@ export const withButtons = () => component => {
|
|
|
620
780
|
// Remove existing alignment classes
|
|
621
781
|
Object.values(DIALOG_FOOTER_ALIGNMENTS).forEach(align => {
|
|
622
782
|
if (align !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
|
|
623
|
-
component.structure.footer
|
|
783
|
+
removeClass(component.structure.footer, `${component.getClass('dialog-footer')}--${align}`);
|
|
624
784
|
}
|
|
625
785
|
});
|
|
626
786
|
|
|
627
787
|
// Add new alignment class if not right (default)
|
|
628
788
|
if (alignment !== DIALOG_FOOTER_ALIGNMENTS.RIGHT) {
|
|
629
|
-
component.structure.footer
|
|
789
|
+
addClass(component.structure.footer, `${component.getClass('dialog-footer')}--${alignment}`);
|
|
630
790
|
}
|
|
631
791
|
}
|
|
632
792
|
}
|
|
@@ -648,12 +808,12 @@ export const withSize = () => component => {
|
|
|
648
808
|
setSize(size: keyof typeof DIALOG_SIZES | DIALOG_SIZES) {
|
|
649
809
|
// Remove existing size classes
|
|
650
810
|
Object.values(DIALOG_SIZES).forEach(sizeValue => {
|
|
651
|
-
component.element
|
|
811
|
+
removeClass(component.element, `${component.getClass('dialog')}--${sizeValue}`);
|
|
652
812
|
});
|
|
653
813
|
|
|
654
814
|
// Add new size class if not medium (default)
|
|
655
815
|
if (size !== DIALOG_SIZES.MEDIUM) {
|
|
656
|
-
component.element
|
|
816
|
+
addClass(component.element, `${component.getClass('dialog')}--${size}`);
|
|
657
817
|
}
|
|
658
818
|
}
|
|
659
819
|
}
|
|
@@ -54,10 +54,7 @@ export interface DialogConfig {
|
|
|
54
54
|
buttons?: DialogButton[];
|
|
55
55
|
|
|
56
56
|
/** Whether to show a divider between header and content */
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/** Whether to show a divider between content and footer */
|
|
60
|
-
footerDivider?: boolean;
|
|
57
|
+
divider?: boolean;
|
|
61
58
|
|
|
62
59
|
/** Dialog z-index (defaults to 1000) */
|
|
63
60
|
zIndex?: number;
|
|
@@ -187,6 +184,12 @@ export interface DialogComponent {
|
|
|
187
184
|
/** Gets dialog footer element */
|
|
188
185
|
getFooterElement: () => HTMLElement | null;
|
|
189
186
|
|
|
187
|
+
/** Shows or hides the divider */
|
|
188
|
+
toggleDivider: (show: boolean) => DialogComponent;
|
|
189
|
+
|
|
190
|
+
/** Checks if the dialog has a divider */
|
|
191
|
+
hasDivider: () => boolean;
|
|
192
|
+
|
|
190
193
|
/** Creates a confirmation dialog with Yes/No buttons */
|
|
191
194
|
confirm: (options?: DialogConfirmOptions) => Promise<boolean>;
|
|
192
195
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// src/components/divider/_styles.scss
|
|
2
|
+
|
|
3
|
+
@use '../../styles/abstract/base' as base;
|
|
4
|
+
@use '../../styles/abstract/variables' as v;
|
|
5
|
+
@use '../../styles/abstract/functions' as f;
|
|
6
|
+
@use '../../styles/abstract/mixins' as m;
|
|
7
|
+
@use '../../styles/abstract/theme' as t;
|
|
8
|
+
|
|
9
|
+
$component: '#{base.$prefix}-divider';
|
|
10
|
+
|
|
11
|
+
.#{$component} {
|
|
12
|
+
// Base styles
|
|
13
|
+
display: block;
|
|
14
|
+
border: none;
|
|
15
|
+
margin: 0;
|
|
16
|
+
padding: 0;
|
|
17
|
+
background-color: t.color('outline-variant');
|
|
18
|
+
|
|
19
|
+
// Orientation variants
|
|
20
|
+
&--horizontal {
|
|
21
|
+
width: 100%;
|
|
22
|
+
height: 1px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&--vertical {
|
|
26
|
+
height: 100%;
|
|
27
|
+
width: 1px;
|
|
28
|
+
display: inline-block;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Variant styles (these set the base for the variants, specific insets are handled via JS)
|
|
32
|
+
&--full-width {
|
|
33
|
+
width: 100%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&--inset {
|
|
37
|
+
// Base class for inset styles - specific margins are set via JS
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&--middle-inset {
|
|
41
|
+
// Base class for middle inset styles - specific margins are set via JS
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Parent-child relationship context
|
|
45
|
+
.#{base.$prefix}-list & {
|
|
46
|
+
margin: 8px 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.#{base.$prefix}-card & {
|
|
50
|
+
margin: 8px 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Dark theme support
|
|
54
|
+
:root[data-theme-mode="dark"] & {
|
|
55
|
+
// Dark theme color is handled through the CSS variable in theme
|
|
56
|
+
}
|
|
57
|
+
}
|