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,60 +1,132 @@
1
1
  // src/core/dom/classes.ts
2
2
  /**
3
3
  * @module core/dom
4
- * @description DOM manipulation utilities
4
+ * @description DOM manipulation utilities optimized for performance
5
5
  */
6
6
 
7
7
  import { normalizeClasses } from '../utils';
8
+ import { PREFIX } from '../config';
9
+
10
+ // Constant for prefix with dash for better performance
11
+ const PREFIX_WITH_DASH = `${PREFIX}-`;
8
12
 
9
13
  /**
10
14
  * Adds multiple classes to an element
15
+ * Automatically adds prefix to classes that don't already have it
16
+ * Optimized for minimal array operations and DOM interactions
17
+ *
11
18
  * @param {HTMLElement} element - Target element
12
19
  * @param {...(string | string[])} classes - Classes to add
13
20
  * @returns {HTMLElement} Modified element
14
21
  */
15
22
  export const addClass = (element: HTMLElement, ...classes: (string | string[])[]): HTMLElement => {
16
23
  const normalizedClasses = normalizeClasses(...classes);
17
- if (normalizedClasses.length) {
18
- element.classList.add(...normalizedClasses);
24
+
25
+ // Early return for empty classes
26
+ if (!normalizedClasses.length) return element;
27
+
28
+ // Using DOMTokenList's add() with multiple arguments is faster than multiple add() calls
29
+ // But we need to handle prefixing first
30
+ const prefixedClasses: string[] = [];
31
+
32
+ for (let i = 0; i < normalizedClasses.length; i++) {
33
+ const cls = normalizedClasses[i];
34
+ if (!cls) continue;
35
+
36
+ prefixedClasses.push(
37
+ cls.startsWith(PREFIX_WITH_DASH) ? cls : PREFIX_WITH_DASH + cls
38
+ );
39
+ }
40
+
41
+ // Add all classes in a single operation if possible
42
+ if (prefixedClasses.length) {
43
+ element.classList.add(...prefixedClasses);
19
44
  }
45
+
20
46
  return element;
21
47
  };
22
48
 
23
49
  /**
24
50
  * Removes multiple classes from an element
51
+ * Handles only exact class names as specified (no automatic prefixing)
52
+ * For better performance, clients should know exactly which classes to remove
53
+ *
25
54
  * @param {HTMLElement} element - Target element
26
55
  * @param {...(string | string[])} classes - Classes to remove
27
56
  * @returns {HTMLElement} Modified element
28
57
  */
29
58
  export const removeClass = (element: HTMLElement, ...classes: (string | string[])[]): HTMLElement => {
30
59
  const normalizedClasses = normalizeClasses(...classes);
31
- if (normalizedClasses.length) {
32
- element.classList.remove(...normalizedClasses);
60
+
61
+ // Early return for empty classes
62
+ if (!normalizedClasses.length) return element;
63
+
64
+ // Prepare prefixed class names
65
+ const prefixedClasses: string[] = [];
66
+
67
+ for (let i = 0; i < normalizedClasses.length; i++) {
68
+ const cls = normalizedClasses[i];
69
+ if (!cls) continue;
70
+
71
+ // Only add the prefixed version
72
+ prefixedClasses.push(
73
+ cls.startsWith(PREFIX_WITH_DASH) ? cls : PREFIX_WITH_DASH + cls
74
+ );
75
+ }
76
+
77
+ // Remove all classes in a single operation if possible
78
+ if (prefixedClasses.length) {
79
+ element.classList.remove(...prefixedClasses);
33
80
  }
81
+
34
82
  return element;
35
83
  };
36
84
 
37
85
  /**
38
86
  * Toggles multiple classes on an element
87
+ * Automatically adds prefix to classes that don't already have it
88
+ *
39
89
  * @param {HTMLElement} element - Target element
40
90
  * @param {...(string | string[])} classes - Classes to toggle
41
91
  * @returns {HTMLElement} Modified element
42
92
  */
43
93
  export const toggleClass = (element: HTMLElement, ...classes: (string | string[])[]): HTMLElement => {
44
94
  const normalizedClasses = normalizeClasses(...classes);
45
- normalizedClasses.forEach(cls => {
46
- element.classList.toggle(cls);
47
- });
95
+
96
+ for (let i = 0; i < normalizedClasses.length; i++) {
97
+ const cls = normalizedClasses[i];
98
+ if (!cls) continue;
99
+
100
+ const prefixedClass = cls.startsWith(PREFIX_WITH_DASH) ? cls : PREFIX_WITH_DASH + cls;
101
+ element.classList.toggle(prefixedClass);
102
+ }
103
+
48
104
  return element;
49
105
  };
50
106
 
51
107
  /**
52
108
  * Checks if an element has all specified classes
109
+ * Automatically adds prefix to classes that don't already have it
110
+ *
53
111
  * @param {HTMLElement} element - Target element
54
112
  * @param {...(string | string[])} classes - Classes to check
55
113
  * @returns {boolean} True if element has all specified classes
56
114
  */
57
115
  export const hasClass = (element: HTMLElement, ...classes: (string | string[])[]): boolean => {
58
116
  const normalizedClasses = normalizeClasses(...classes);
59
- return normalizedClasses.every(cls => element.classList.contains(cls));
117
+
118
+ // Early return for empty classes (technically all are present)
119
+ if (!normalizedClasses.length) return true;
120
+
121
+ for (let i = 0; i < normalizedClasses.length; i++) {
122
+ const cls = normalizedClasses[i];
123
+ if (!cls) continue;
124
+
125
+ const prefixedClass = cls.startsWith(PREFIX_WITH_DASH) ? cls : PREFIX_WITH_DASH + cls;
126
+ if (!element.classList.contains(prefixedClass)) {
127
+ return false;
128
+ }
129
+ }
130
+
131
+ return true;
60
132
  };
@@ -7,6 +7,7 @@
7
7
  import { setAttributes } from './attributes';
8
8
  import { normalizeClasses } from '../utils';
9
9
  import { PREFIX } from '../config';
10
+ import { addClass } from './classes'; // Import addClass
10
11
 
11
12
  /**
12
13
  * Event handler function type
@@ -58,9 +59,22 @@ export interface CreateElementOptions {
58
59
  data?: Record<string, string>;
59
60
 
60
61
  /**
61
- * CSS classes
62
+ * CSS classes (will be automatically prefixed with 'mtrl-')
63
+ * Alias for 'className'
62
64
  */
63
- className?: string | string[] | null;
65
+ class?: string | string[];
66
+
67
+ /**
68
+ * CSS classes (will be automatically prefixed with 'mtrl-')
69
+ * Alias for 'class'
70
+ */
71
+ className?: string | string[];
72
+
73
+ /**
74
+ * CSS classes that will NOT be prefixed
75
+ * Added as-is to the element
76
+ */
77
+ rawClass?: string | string[];
64
78
 
65
79
  /**
66
80
  * HTML attributes
@@ -95,9 +109,6 @@ export interface EventHandlerStorage {
95
109
  [eventName: string]: EventHandler;
96
110
  }
97
111
 
98
- // Constant for prefix with dash
99
- const PREFIX_WITH_DASH = `${PREFIX}-`;
100
-
101
112
  /**
102
113
  * Creates a DOM element with the specified options
103
114
  *
@@ -112,7 +123,9 @@ export const createElement = (options: CreateElementOptions = {}): HTMLElement =
112
123
  text = '',
113
124
  id = '',
114
125
  data = {},
126
+ class: classOption,
115
127
  className,
128
+ rawClass,
116
129
  attrs = {},
117
130
  forwardEvents = {},
118
131
  onCreate,
@@ -127,14 +140,17 @@ export const createElement = (options: CreateElementOptions = {}): HTMLElement =
127
140
  if (text) element.textContent = text;
128
141
  if (id) element.id = id;
129
142
 
130
- // Handle classes
131
- if (className) {
132
- const classes = normalizeClasses(className);
133
- if (classes.length) {
134
- // Apply prefix to classes in a single operation
135
- element.classList.add(...classes.map(cls =>
136
- cls && !cls.startsWith(PREFIX_WITH_DASH) ? PREFIX_WITH_DASH + cls : cls
137
- ).filter(Boolean));
143
+ // 1. Handle prefixed classes using addClass
144
+ const prefixedClassSource = classOption || className;
145
+ if (prefixedClassSource) {
146
+ addClass(element, prefixedClassSource);
147
+ }
148
+
149
+ // 2. Handle raw classes (no prefix)
150
+ if (rawClass) {
151
+ const rawClasses = normalizeClasses(rawClass);
152
+ if (rawClasses.length) {
153
+ element.classList.add(...rawClasses);
138
154
  }
139
155
  }
140
156
 
@@ -230,12 +246,7 @@ export const withAttributes = (attrs: Record<string, any>) =>
230
246
  */
231
247
  export const withClasses = (...classes: (string | string[])[]) =>
232
248
  (element: HTMLElement): HTMLElement => {
233
- const normalizedClasses = normalizeClasses(...classes);
234
- if (normalizedClasses.length) {
235
- element.classList.add(...normalizedClasses.map(cls =>
236
- cls && !cls.startsWith(PREFIX_WITH_DASH) ? PREFIX_WITH_DASH + cls : cls
237
- ).filter(Boolean));
238
- }
249
+ addClass(element, ...classes);
239
250
  return element;
240
251
  };
241
252