mtrl 0.3.3 → 0.3.6

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/components/menu/api.ts +143 -268
  3. package/src/components/menu/config.ts +84 -40
  4. package/src/components/menu/features/anchor.ts +159 -0
  5. package/src/components/menu/features/controller.ts +970 -0
  6. package/src/components/menu/features/index.ts +4 -0
  7. package/src/components/menu/index.ts +31 -63
  8. package/src/components/menu/menu.ts +107 -97
  9. package/src/components/menu/types.ts +263 -447
  10. package/src/components/segmented-button/config.ts +59 -20
  11. package/src/components/segmented-button/index.ts +1 -1
  12. package/src/components/segmented-button/segment.ts +51 -97
  13. package/src/components/segmented-button/segmented-button.ts +114 -2
  14. package/src/components/segmented-button/types.ts +52 -0
  15. package/src/core/compose/features/icon.ts +15 -13
  16. package/src/core/dom/classes.ts +81 -9
  17. package/src/core/dom/create.ts +30 -19
  18. package/src/core/layout/README.md +531 -166
  19. package/src/core/layout/array.ts +3 -4
  20. package/src/core/layout/config.ts +193 -0
  21. package/src/core/layout/create.ts +1 -2
  22. package/src/core/layout/index.ts +12 -2
  23. package/src/core/layout/object.ts +2 -3
  24. package/src/core/layout/processor.ts +60 -12
  25. package/src/core/layout/result.ts +1 -2
  26. package/src/core/layout/types.ts +105 -50
  27. package/src/core/layout/utils.ts +69 -61
  28. package/src/index.ts +2 -1
  29. package/src/styles/components/_button.scss +6 -0
  30. package/src/styles/components/_chip.scss +4 -5
  31. package/src/styles/components/_menu.scss +20 -8
  32. package/src/styles/components/_segmented-button.scss +173 -63
  33. package/src/styles/main.scss +23 -23
  34. package/src/styles/utilities/_layout.scss +665 -0
  35. package/src/components/menu/features/items-manager.ts +0 -457
  36. package/src/components/menu/features/keyboard-navigation.ts +0 -133
  37. package/src/components/menu/features/positioning.ts +0 -127
  38. package/src/components/menu/features/visibility.ts +0 -230
  39. package/src/components/menu/menu-item.ts +0 -86
  40. package/src/components/menu/utils.ts +0 -67
  41. /package/src/{core/build → styles/utilities}/_ripple.scss +0 -0
@@ -1,562 +1,378 @@
1
1
  // src/components/menu/types.ts
2
2
 
3
3
  /**
4
- * Menu horizontal alignment options
5
- *
6
- * Determines how the menu is horizontally aligned relative to its anchor element.
7
- *
8
- * @category Components
9
- * @example
10
- * ```typescript
11
- * // Position menu with right alignment
12
- * menu.position(buttonElement, { align: 'right' });
13
- * ```
14
- */
15
- export type MenuAlign = 'left' | 'right' | 'center';
16
-
17
- /**
18
- * Menu vertical alignment options
19
- *
20
- * Determines how the menu is vertically positioned relative to its anchor element.
21
- *
22
- * @category Components
23
- * @example
24
- * ```typescript
25
- * // Position menu above the anchor element
26
- * menu.position(buttonElement, { vAlign: 'top' });
27
- * ```
28
- */
29
- export type MenuVerticalAlign = 'top' | 'bottom' | 'middle';
30
-
31
- /**
32
- * Menu item types
33
- *
34
- * Defines the different types of items that can be added to a menu.
35
- * - 'item': Standard selectable menu item (default)
36
- * - 'divider': Horizontal line separating groups of menu items
4
+ * Menu placement options
5
+ * Controls where the menu will appear relative to its anchor element
37
6
  *
38
7
  * @category Components
39
- * @example
40
- * ```typescript
41
- * // Adding a divider between menu items
42
- * menu.addItem({ type: 'divider' });
43
- * ```
44
8
  */
45
- export type MenuItemType = 'item' | 'divider';
9
+ export const MENU_PLACEMENT = {
10
+ /** Places menu below the anchor, aligned to left edge */
11
+ BOTTOM_START: 'bottom-start',
12
+ /** Places menu below the anchor, centered */
13
+ BOTTOM: 'bottom',
14
+ /** Places menu below the anchor, aligned to right edge */
15
+ BOTTOM_END: 'bottom-end',
16
+ /** Places menu above the anchor, aligned to left edge */
17
+ TOP_START: 'top-start',
18
+ /** Places menu above the anchor, centered */
19
+ TOP: 'top',
20
+ /** Places menu above the anchor, aligned to right edge */
21
+ TOP_END: 'top-end',
22
+ /** Places menu to the right of the anchor, aligned to top edge */
23
+ RIGHT_START: 'right-start',
24
+ /** Places menu to the right of the anchor, centered */
25
+ RIGHT: 'right',
26
+ /** Places menu to the right of the anchor, aligned to bottom edge */
27
+ RIGHT_END: 'right-end',
28
+ /** Places menu to the left of the anchor, aligned to top edge */
29
+ LEFT_START: 'left-start',
30
+ /** Places menu to the left of the anchor, centered */
31
+ LEFT: 'left',
32
+ /** Places menu to the left of the anchor, aligned to bottom edge */
33
+ LEFT_END: 'left-end'
34
+ } as const;
46
35
 
47
36
  /**
48
- * Menu events
49
- *
50
- * Events that can be subscribed to for the Menu component.
51
- * - 'select': Fired when a menu item is selected
52
- * - 'open': Fired when the menu is shown
53
- * - 'close': Fired when the menu is hidden
54
- * - 'submenuOpen': Fired when a submenu is opened
55
- * - 'submenuClose': Fired when a submenu is closed
37
+ * Alignment options for the menu
56
38
  *
57
39
  * @category Components
58
- * @example
59
- * ```typescript
60
- * // Listen for menu open events
61
- * menu.on('open', () => {
62
- * console.log('Menu opened');
63
- * });
64
- *
65
- * // Listen for item selection
66
- * menu.on('select', (event) => {
67
- * console.log(`Selected item: ${event.name}`);
68
- * });
69
- * ```
70
40
  */
71
- export type MenuEvent = 'select' | 'open' | 'close' | 'submenuOpen' | 'submenuClose';
41
+ export type MenuPlacement = typeof MENU_PLACEMENT[keyof typeof MENU_PLACEMENT];
72
42
 
73
43
  /**
74
- * Menu item configuration
75
- *
76
- * Configuration object for individual menu items.
44
+ * Configuration interface for a menu item
77
45
  *
78
46
  * @category Components
79
- * @example
80
- * ```typescript
81
- * // Basic menu item
82
- * const basicItem: MenuItemConfig = {
83
- * name: 'edit',
84
- * text: 'Edit Document'
85
- * };
86
- *
87
- * // Disabled menu item
88
- * const disabledItem: MenuItemConfig = {
89
- * name: 'print',
90
- * text: 'Print',
91
- * disabled: true
92
- * };
93
- *
94
- * // Menu item with a submenu
95
- * const itemWithSubmenu: MenuItemConfig = {
96
- * name: 'share',
97
- * text: 'Share',
98
- * items: [
99
- * { name: 'email', text: 'Email' },
100
- * { name: 'link', text: 'Copy Link' }
101
- * ]
102
- * };
103
- *
104
- * // Divider item
105
- * const divider: MenuItemConfig = { type: 'divider' };
106
- * ```
107
47
  */
108
- export interface MenuItemConfig {
48
+ export interface MenuItem {
109
49
  /**
110
- * Unique identifier for the item
111
- * Used for identifying the item when handling selection events
50
+ * Unique ID for the menu item
51
+ * Required for accessibility and event handling
112
52
  */
113
- name: string;
53
+ id: string;
114
54
 
115
- /**
116
- * Text content displayed for the item
117
- * This is the visible label shown in the menu
55
+ /**
56
+ * Display text for the menu item
118
57
  */
119
58
  text: string;
120
59
 
121
- /**
122
- * Type of menu item
123
- * Defaults to 'item' if not specified
60
+ /**
61
+ * Optional icon to display before the text
62
+ * Accepts HTML string (typically SVG)
124
63
  */
125
- type?: MenuItemType | string;
126
-
127
- /**
128
- * Whether the item is disabled
129
- * Disabled items can't be selected and appear visually muted
130
- */
131
- disabled?: boolean;
64
+ icon?: string;
132
65
 
133
- /**
134
- * Additional CSS classes to apply to the item
135
- * Useful for custom styling or visual indicators
66
+ /**
67
+ * Optional keyboard shortcut hint to display
68
+ * Shown at the end of the menu item
136
69
  */
137
- class?: string;
70
+ shortcut?: string;
138
71
 
139
- /**
140
- * Submenu items
141
- * Creates a nested menu that appears when this item is hovered
142
- */
143
- items?: MenuItemConfig[];
144
- }
145
-
146
- /**
147
- * Menu position configuration
148
- *
149
- * Configures how a menu is positioned relative to an anchor element.
150
- * This allows for precise control over menu placement in the UI.
151
- *
152
- * @category Components
153
- * @example
154
- * ```typescript
155
- * // Position menu at the bottom-right of the anchor with additional offset
156
- * menu.position(buttonElement, {
157
- * align: 'right',
158
- * vAlign: 'bottom',
159
- * offsetX: 5,
160
- * offsetY: 10
161
- * });
162
- *
163
- * // Center align menu below the anchor
164
- * menu.position(buttonElement, {
165
- * align: 'center',
166
- * vAlign: 'bottom'
167
- * });
168
- * ```
169
- */
170
- export interface MenuPositionConfig {
171
- /**
172
- * Horizontal alignment
173
- * Controls how the menu aligns horizontally with the anchor element
174
- * @default 'left'
72
+ /**
73
+ * Whether the menu item is disabled
74
+ * Disabled items cannot be clicked but remain visible
175
75
  */
176
- align?: MenuAlign | string;
76
+ disabled?: boolean;
177
77
 
178
- /**
179
- * Vertical alignment
180
- * Controls how the menu aligns vertically with the anchor element
181
- * @default 'bottom'
78
+ /**
79
+ * Whether this item has a submenu
80
+ * If true, the item will show an indicator and can open a nested menu
182
81
  */
183
- vAlign?: MenuVerticalAlign | string;
82
+ hasSubmenu?: boolean;
184
83
 
185
- /**
186
- * Horizontal offset in pixels
187
- * Additional horizontal offset from the aligned position
188
- * Positive values move the menu to the right
189
- * @default 0
84
+ /**
85
+ * Optional array of submenu items
86
+ * Only used when hasSubmenu is true
190
87
  */
191
- offsetX?: number;
88
+ submenu?: MenuItem[];
192
89
 
193
- /**
194
- * Vertical offset in pixels
195
- * Additional vertical offset from the aligned position
196
- * Positive values move the menu downward
197
- * @default 0
90
+ /**
91
+ * Additional data to associate with the menu item
92
+ * This can be used for custom behavior in click handlers
198
93
  */
199
- offsetY?: number;
94
+ data?: any;
200
95
  }
201
96
 
202
97
  /**
203
- * Menu position result
204
- *
205
- * Contains the calculated position values for a menu.
206
- * Used internally by the positioning system.
98
+ * Menu item type for dividers
207
99
  *
208
100
  * @category Components
209
- * @internal
210
101
  */
211
- export interface MenuPosition {
212
- /**
213
- * Left position in pixels
214
- * Absolute position from the left edge of the viewport
102
+ export interface MenuDivider {
103
+ /**
104
+ * Type must be 'divider' to differentiate from regular menu items
215
105
  */
216
- left: number;
106
+ type: 'divider';
217
107
 
218
- /**
219
- * Top position in pixels
220
- * Absolute position from the top edge of the viewport
108
+ /**
109
+ * Optional ID for the divider (for accessibility)
221
110
  */
222
- top: number;
111
+ id?: string;
223
112
  }
224
113
 
225
114
  /**
226
- * Menu item internal data structure
227
- *
228
- * Used internally to track menu item DOM elements and their configurations.
229
- * This helps with item management and event handling.
115
+ * Combined type for menu content items (regular items or dividers)
230
116
  *
231
117
  * @category Components
232
- * @internal
233
118
  */
234
- export interface MenuItemData {
235
- /**
236
- * DOM element for the item
237
- * Reference to the rendered menu item element
238
- */
239
- element: HTMLElement;
240
-
241
- /**
242
- * Item configuration
243
- * The configuration that was used to create this item
244
- */
245
- config: MenuItemConfig;
246
- }
119
+ export type MenuContent = MenuItem | MenuDivider;
247
120
 
248
121
  /**
249
- * Menu selection event data
250
- *
251
- * Contains information about a selected menu item.
252
- * This is passed to event handlers when an item is selected.
122
+ * Configuration interface for the Menu component
253
123
  *
254
124
  * @category Components
255
- * @example
256
- * ```typescript
257
- * menu.on('select', (event: MenuSelectEvent) => {
258
- * console.log(`Selected: ${event.name}`);
259
- * console.log(`Text: ${event.text}`);
260
- *
261
- * // For submenu items, path contains the hierarchy
262
- * if (event.path) {
263
- * console.log(`From submenu path: ${event.path.join(' > ')}`);
264
- * }
265
- * });
266
- * ```
267
125
  */
268
- export interface MenuSelectEvent {
269
- /**
270
- * Name of the selected item
271
- * Matches the name property from MenuItemConfig
126
+ export interface MenuConfig {
127
+ /**
128
+ * Element to which the menu will be anchored
129
+ * Can be an HTML element or a CSS selector string
272
130
  */
273
- name: string;
131
+ anchor: HTMLElement | string;
274
132
 
275
- /**
276
- * Text content of the selected item
277
- * The visible text that was displayed in the menu
133
+ /**
134
+ * Array of menu items and dividers to display
278
135
  */
279
- text: string;
136
+ items: MenuContent[];
280
137
 
281
- /**
282
- * Path of parent item names (for submenus)
283
- * For nested menu selections, contains the names of all parent items
284
- * from top level to the selected item
138
+ /**
139
+ * Placement of the menu relative to the anchor
140
+ * @default 'bottom-start'
285
141
  */
286
- path?: string[];
287
- }
288
-
289
- /**
290
- * Configuration interface for the Menu component
291
- *
292
- * Provides options for creating and configuring a Menu component.
293
- *
294
- * @category Components
295
- * @example
296
- * ```typescript
297
- * // Create a basic menu with initial items
298
- * const menu = createMenu({
299
- * items: [
300
- * { name: 'copy', text: 'Copy' },
301
- * { name: 'paste', text: 'Paste' },
302
- * { type: 'divider' },
303
- * { name: 'delete', text: 'Delete' }
304
- * ],
305
- * stayOpenOnSelect: false,
306
- * class: 'custom-menu'
307
- * });
308
- *
309
- * // Create a submenu
310
- * const submenu = createMenu({
311
- * items: [
312
- * { name: 'option1', text: 'Option 1' },
313
- * { name: 'option2', text: 'Option 2' }
314
- * ],
315
- * parentItem: parentElement
316
- * });
317
- * ```
318
- */
319
- export interface MenuConfig {
320
- /**
321
- * Initial menu items
322
- * Array of item configurations to populate the menu with
142
+ placement?: MenuPlacement;
143
+
144
+ /**
145
+ * Whether the menu should close when an item is clicked
146
+ * @default true
323
147
  */
324
- items?: MenuItemConfig[];
148
+ closeOnSelect?: boolean;
325
149
 
326
- /**
327
- * Additional CSS classes
328
- * Custom classes to apply to the menu container element
150
+ /**
151
+ * Whether the menu should close when the user clicks outside
152
+ * @default true
329
153
  */
330
- class?: string;
154
+ closeOnClickOutside?: boolean;
331
155
 
332
- /**
333
- * Whether to keep menu open after selection
334
- * When true, selecting an item will not automatically close the menu
335
- * @default false
156
+ /**
157
+ * Whether the menu should close when the escape key is pressed
158
+ * @default true
336
159
  */
337
- stayOpenOnSelect?: boolean;
160
+ closeOnEscape?: boolean;
338
161
 
339
- /**
340
- * Origin element that opens the menu
341
- * Element used to trigger the menu appearance (like a button)
162
+ /**
163
+ * Whether submenus should open on hover
164
+ * @default true
342
165
  */
343
- origin?: HTMLElement | { element: HTMLElement };
166
+ openSubmenuOnHover?: boolean;
344
167
 
345
- /**
346
- * Parent item element (for submenus)
347
- * For submenus, references the parent menu item this menu belongs to
168
+ /**
169
+ * Optional width for the menu (in CSS units)
170
+ * If not provided, menu will size to its content
348
171
  */
349
- parentItem?: HTMLElement;
172
+ width?: string;
350
173
 
351
- /**
352
- * Prefix for class names
353
- * Custom prefix for all CSS class names generated by the component
174
+ /**
175
+ * Optional maximum height for the menu (in CSS units)
176
+ * If content exceeds this height, the menu will scroll
177
+ */
178
+ maxHeight?: string;
179
+
180
+ /**
181
+ * Optional offset from the anchor (in pixels)
182
+ * @default 8
183
+ */
184
+ offset?: number;
185
+
186
+ /**
187
+ * Whether the menu should automatically flip placement to stay in viewport
188
+ * @default true
189
+ */
190
+ autoFlip?: boolean;
191
+
192
+ /**
193
+ * Whether the menu is initially visible
194
+ * @default false
195
+ */
196
+ visible?: boolean;
197
+
198
+ /**
199
+ * Additional CSS classes to add to the menu
200
+ */
201
+ class?: string;
202
+
203
+ /**
204
+ * Component prefix for CSS class names
354
205
  * @default 'mtrl'
355
206
  */
356
207
  prefix?: string;
357
208
 
358
- /**
359
- * Component name
360
- * Name identifier used in CSS classes and debugging
209
+ /**
210
+ * Component name used in CSS class generation
361
211
  * @default 'menu'
362
212
  */
363
213
  componentName?: string;
214
+
215
+ /**
216
+ * Event handlers for the menu
217
+ */
218
+ on?: {
219
+ /**
220
+ * Called when the menu is opened
221
+ */
222
+ open?: (event: MenuEvent) => void;
223
+
224
+ /**
225
+ * Called when the menu is closed
226
+ */
227
+ close?: (event: MenuEvent) => void;
228
+
229
+ /**
230
+ * Called when a menu item is selected
231
+ */
232
+ select?: (event: MenuSelectEvent) => void;
233
+ };
364
234
  }
365
235
 
366
236
  /**
367
- * Menu component interface
368
- *
369
- * Represents a Material Design 3 menu component that provides a temporary
370
- * surface containing choices that users can interact with.
371
- *
372
- * The menu supports positioning, item management, keyboard navigation,
373
- * and event handling for user interactions.
374
- *
375
- * This interface is implemented by the object returned from the {@link ../menu!default | createMenu} function.
237
+ * Menu event interface
376
238
  *
377
239
  * @category Components
378
- * @example
379
- * ```typescript
380
- * // Create a menu with items
381
- * const menu = createMenu({
382
- * items: [
383
- * { name: 'edit', text: 'Edit' },
384
- * { name: 'duplicate', text: 'Duplicate' },
385
- * { type: 'divider' },
386
- * { name: 'delete', text: 'Delete' }
387
- * ]
388
- * });
389
- *
390
- * // Position and show the menu
391
- * const button = document.getElementById('menuButton');
392
- * button.addEventListener('click', () => {
393
- * menu.position(button).show();
394
- * });
240
+ */
241
+ export interface MenuEvent {
242
+ /** The menu component that triggered the event */
243
+ menu: MenuComponent;
244
+
245
+ /** Original DOM event if available */
246
+ originalEvent?: Event;
247
+
248
+ /** Function to prevent default behavior */
249
+ preventDefault: () => void;
250
+
251
+ /** Whether default behavior was prevented */
252
+ defaultPrevented: boolean;
253
+ }
254
+
255
+ /**
256
+ * Menu selection event interface
395
257
  *
396
- * // Handle selection
397
- * menu.on('select', (event) => {
398
- * console.log(`Selected: ${event.name}`);
399
- * if (event.name === 'delete') {
400
- * // Handle delete action
401
- * }
402
- * });
403
- * ```
258
+ * @category Components
259
+ */
260
+ export interface MenuSelectEvent extends MenuEvent {
261
+ /** The selected menu item */
262
+ item: MenuItem;
263
+
264
+ /** ID of the selected menu item */
265
+ itemId: string;
266
+
267
+ /** Data associated with the menu item (if any) */
268
+ itemData?: any;
269
+ }
270
+
271
+ /**
272
+ * Menu component interface
404
273
  *
405
- * @see {@link ../menu!default | createMenu} for creating menu instances
274
+ * @category Components
406
275
  */
407
276
  export interface MenuComponent {
408
- /**
409
- * The root element of the menu
410
- * Access to the underlying DOM element for direct manipulation if needed
411
- */
277
+ /** The menu's root DOM element */
412
278
  element: HTMLElement;
413
279
 
414
- /**
415
- * Shows the menu
416
- * Makes the menu visible in the DOM
417
- * @returns The menu component for method chaining
280
+ /**
281
+ * Opens the menu
282
+ * @param event - Optional event that triggered the open
283
+ * @returns The menu component for chaining
418
284
  */
419
- show: () => MenuComponent;
285
+ open: (event?: Event) => MenuComponent;
420
286
 
421
- /**
422
- * Hides the menu
423
- * Makes the menu invisible in the DOM
424
- * @returns The menu component for method chaining
287
+ /**
288
+ * Closes the menu
289
+ * @param event - Optional event that triggered the close
290
+ * @returns The menu component for chaining
425
291
  */
426
- hide: () => MenuComponent;
292
+ close: (event?: Event) => MenuComponent;
427
293
 
428
- /**
429
- * Checks if the menu is visible
430
- * @returns True if the menu is currently visible
294
+ /**
295
+ * Toggles the menu's open state
296
+ * @param event - Optional event that triggered the toggle
297
+ * @returns The menu component for chaining
431
298
  */
432
- isVisible: () => boolean;
299
+ toggle: (event?: Event) => MenuComponent;
433
300
 
434
- /**
435
- * Positions the menu relative to a target
436
- * Places the menu in relation to a target element with customizable alignment
437
- * @param target - The element to position the menu against
438
- * @param options - Configuration for how to align the menu
439
- * @returns The menu component for method chaining
301
+ /**
302
+ * Checks if the menu is currently open
303
+ * @returns True if the menu is open
440
304
  */
441
- position: (target: HTMLElement, options?: MenuPositionConfig) => MenuComponent;
305
+ isOpen: () => boolean;
442
306
 
443
- /**
444
- * Adds a menu item
445
- * Dynamically adds a new item to the menu
446
- * @param config - Configuration for the new menu item
447
- * @returns The menu component for method chaining
307
+ /**
308
+ * Updates the menu items
309
+ * @param items - New array of menu items and dividers
310
+ * @returns The menu component for chaining
448
311
  */
449
- addItem: (config: MenuItemConfig) => MenuComponent;
312
+ setItems: (items: MenuContent[]) => MenuComponent;
450
313
 
451
- /**
452
- * Removes a menu item by name
453
- * Dynamically removes an item from the menu
454
- * @param name - Name identifier of the item to remove
455
- * @returns The menu component for method chaining
314
+ /**
315
+ * Gets the current menu items
316
+ * @returns Array of current menu items and dividers
456
317
  */
457
- removeItem: (name: string) => MenuComponent;
318
+ getItems: () => MenuContent[];
458
319
 
459
- /**
460
- * Gets all menu items
461
- * @returns A Map of all items in the menu, indexed by item name
320
+ /**
321
+ * Updates the menu's anchor element
322
+ * @param anchor - New anchor element or selector
323
+ * @returns The menu component for chaining
462
324
  */
463
- getItems: () => Map<string, MenuItemData>;
325
+ setAnchor: (anchor: HTMLElement | string) => MenuComponent;
464
326
 
465
- /**
466
- * Adds event listener
467
- * Subscribes to menu events like 'select', 'open', etc.
468
- * @param event - The event name to listen for
469
- * @param handler - Callback function to execute when the event occurs
470
- * @returns The menu component for method chaining
327
+ /**
328
+ * Gets the current anchor element
329
+ * @returns Current anchor element
471
330
  */
472
- on: (event: string, handler: Function) => MenuComponent;
331
+ getAnchor: () => HTMLElement;
473
332
 
474
- /**
475
- * Removes event listener
476
- * Unsubscribes from menu events
477
- * @param event - The event name to stop listening for
478
- * @param handler - The handler function to remove
479
- * @returns The menu component for method chaining
333
+ /**
334
+ * Updates the menu's placement
335
+ * @param placement - New placement value
336
+ * @returns The menu component for chaining
480
337
  */
481
- off: (event: string, handler: Function) => MenuComponent;
338
+ setPlacement: (placement: MenuPlacement) => MenuComponent;
482
339
 
483
- /**
484
- * Destroys the menu component and cleans up resources
485
- * Removes event listeners and DOM elements to prevent memory leaks
486
- * @returns The menu component for method chaining
340
+ /**
341
+ * Gets the current menu placement
342
+ * @returns Current placement
487
343
  */
488
- destroy: () => MenuComponent;
489
- }
490
-
491
- /**
492
- * Base component interface
493
- *
494
- * Internal interface representing the base structure for menu components
495
- * before the public API is applied.
496
- *
497
- * @internal
498
- * @category Components
499
- */
500
- export interface BaseComponent {
501
- /** The root DOM element */
502
- element: HTMLElement;
503
-
504
- /** Method to emit events */
505
- emit?: (event: string, data: any) => void;
344
+ getPlacement: () => MenuPlacement;
506
345
 
507
- /** Method to subscribe to events */
508
- on?: (event: string, handler: Function) => any;
509
-
510
- /** Method to unsubscribe from events */
511
- off?: (event: string, handler: Function) => any;
512
-
513
- /** Method to show the component */
514
- show?: () => any;
515
-
516
- /** Method to hide the component */
517
- hide?: () => any;
518
-
519
- /** Method to check visibility */
520
- isVisible?: () => boolean;
521
-
522
- /** Method to position relative to target */
523
- position?: (target: HTMLElement, options?: MenuPositionConfig) => any;
524
-
525
- /** Method to add an item */
526
- addItem?: (config: MenuItemConfig) => any;
527
-
528
- /** Method to remove an item */
529
- removeItem?: (name: string) => any;
530
-
531
- /** Method to get all items */
532
- getItems?: () => Map<string, MenuItemData>;
533
-
534
- /** Method to close submenus */
535
- closeSubmenus?: () => any;
536
-
537
- /** Method to refresh hover handlers */
538
- refreshHoverHandlers?: () => any;
346
+ /**
347
+ * Adds an event listener to the menu
348
+ * @param event - Event name ('open', 'close', 'select')
349
+ * @param handler - Event handler function
350
+ * @returns The menu component for chaining
351
+ */
352
+ on: <T extends keyof MenuEvents>(event: T, handler: MenuEvents[T]) => MenuComponent;
539
353
 
540
- /** Lifecycle methods container */
541
- lifecycle?: {
542
- destroy: () => void;
543
- };
354
+ /**
355
+ * Removes an event listener from the menu
356
+ * @param event - Event name
357
+ * @param handler - Event handler function
358
+ * @returns The menu component for chaining
359
+ */
360
+ off: <T extends keyof MenuEvents>(event: T, handler: MenuEvents[T]) => MenuComponent;
544
361
 
545
- /** Allow for additional properties */
546
- [key: string]: any;
362
+ /**
363
+ * Destroys the menu component and cleans up resources
364
+ */
365
+ destroy: () => void;
547
366
  }
548
367
 
549
368
  /**
550
- * API options interface
369
+ * Menu events interface for type-checking
551
370
  *
552
- * Internal interface used when applying the API to a component.
553
- *
554
- * @internal
555
371
  * @category Components
372
+ * @internal
556
373
  */
557
- export interface ApiOptions {
558
- /** Lifecycle methods to include */
559
- lifecycle: {
560
- destroy: () => void;
561
- };
374
+ export interface MenuEvents {
375
+ 'open': (event: MenuEvent) => void;
376
+ 'close': (event: MenuEvent) => void;
377
+ 'select': (event: MenuSelectEvent) => void;
562
378
  }