mtrl 0.1.3 → 0.2.0

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 (224) hide show
  1. package/README.md +70 -22
  2. package/index.ts +33 -0
  3. package/package.json +14 -5
  4. package/src/components/button/{styles.scss → _styles.scss} +2 -2
  5. package/src/components/button/api.ts +89 -0
  6. package/src/components/button/button.ts +50 -0
  7. package/src/components/button/config.ts +75 -0
  8. package/src/components/button/constants.ts +17 -0
  9. package/src/components/button/index.ts +4 -0
  10. package/src/components/button/types.ts +118 -0
  11. package/src/components/card/{styles.scss → _styles.scss} +79 -7
  12. package/src/components/card/{actions.js → actions.ts} +15 -18
  13. package/src/components/card/{api.js → api.ts} +33 -33
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/{constants.js → constants.ts} +11 -10
  17. package/src/components/card/{content.js → content.ts} +15 -18
  18. package/src/components/card/{features.js → features.ts} +104 -94
  19. package/src/components/card/{header.js → header.ts} +21 -25
  20. package/src/components/card/index.ts +19 -0
  21. package/src/components/card/media.ts +52 -0
  22. package/src/components/card/types.ts +174 -0
  23. package/src/components/checkbox/api.ts +82 -0
  24. package/src/components/checkbox/checkbox.ts +75 -0
  25. package/src/components/checkbox/config.ts +90 -0
  26. package/src/components/checkbox/index.ts +4 -0
  27. package/src/components/checkbox/types.ts +146 -0
  28. package/src/components/chip/_styles.scss +372 -0
  29. package/src/components/chip/api.ts +115 -0
  30. package/src/components/chip/chip-set.ts +225 -0
  31. package/src/components/chip/chip.ts +82 -0
  32. package/src/components/chip/config.ts +92 -0
  33. package/src/components/chip/constants.ts +38 -0
  34. package/src/components/chip/index.ts +4 -0
  35. package/src/components/chip/types.ts +172 -0
  36. package/src/components/list/api.ts +72 -0
  37. package/src/components/list/config.ts +43 -0
  38. package/src/components/list/{constants.js → constants.ts} +34 -7
  39. package/src/components/list/features.ts +224 -0
  40. package/src/components/list/index.ts +14 -0
  41. package/src/components/list/list-item.ts +120 -0
  42. package/src/components/list/list.ts +37 -0
  43. package/src/components/list/types.ts +179 -0
  44. package/src/components/list/utils.ts +47 -0
  45. package/src/components/menu/api.ts +119 -0
  46. package/src/components/menu/config.ts +54 -0
  47. package/src/components/menu/constants.ts +154 -0
  48. package/src/components/menu/features/items-manager.ts +457 -0
  49. package/src/components/menu/features/keyboard-navigation.ts +133 -0
  50. package/src/components/menu/features/positioning.ts +127 -0
  51. package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
  52. package/src/components/menu/index.ts +14 -0
  53. package/src/components/menu/menu-item.ts +43 -0
  54. package/src/components/menu/menu.ts +53 -0
  55. package/src/components/menu/types.ts +178 -0
  56. package/src/components/navigation/api.ts +79 -0
  57. package/src/components/navigation/config.ts +61 -0
  58. package/src/components/navigation/{constants.js → constants.ts} +10 -10
  59. package/src/components/navigation/index.ts +14 -0
  60. package/src/components/navigation/nav-item.ts +148 -0
  61. package/src/components/navigation/navigation.ts +50 -0
  62. package/src/components/navigation/types.ts +212 -0
  63. package/src/components/progress/_styles.scss +204 -0
  64. package/src/components/progress/api.ts +179 -0
  65. package/src/components/progress/config.ts +124 -0
  66. package/src/components/progress/constants.ts +43 -0
  67. package/src/components/progress/index.ts +5 -0
  68. package/src/components/progress/progress.ts +163 -0
  69. package/src/components/progress/types.ts +102 -0
  70. package/src/components/snackbar/api.ts +162 -0
  71. package/src/components/snackbar/config.ts +62 -0
  72. package/src/components/snackbar/{constants.js → constants.ts} +21 -4
  73. package/src/components/snackbar/features.ts +76 -0
  74. package/src/components/snackbar/index.ts +4 -0
  75. package/src/components/snackbar/position.ts +71 -0
  76. package/src/components/snackbar/queue.ts +76 -0
  77. package/src/components/snackbar/snackbar.ts +60 -0
  78. package/src/components/snackbar/types.ts +58 -0
  79. package/src/components/switch/api.ts +77 -0
  80. package/src/components/switch/config.ts +74 -0
  81. package/src/components/switch/index.ts +4 -0
  82. package/src/components/switch/switch.ts +52 -0
  83. package/src/components/switch/types.ts +142 -0
  84. package/src/components/textfield/api.ts +72 -0
  85. package/src/components/textfield/config.ts +54 -0
  86. package/src/components/textfield/{constants.js → constants.ts} +38 -5
  87. package/src/components/textfield/index.ts +4 -0
  88. package/src/components/textfield/textfield.ts +50 -0
  89. package/src/components/textfield/types.ts +139 -0
  90. package/src/core/compose/base.ts +43 -0
  91. package/src/core/compose/component.ts +247 -0
  92. package/src/core/compose/features/checkable.ts +155 -0
  93. package/src/core/compose/features/disabled.ts +116 -0
  94. package/src/core/compose/features/events.ts +65 -0
  95. package/src/core/compose/features/icon.ts +67 -0
  96. package/src/core/compose/features/index.ts +35 -0
  97. package/src/core/compose/features/input.ts +174 -0
  98. package/src/core/compose/features/lifecycle.ts +139 -0
  99. package/src/core/compose/features/position.ts +94 -0
  100. package/src/core/compose/features/ripple.ts +55 -0
  101. package/src/core/compose/features/size.ts +29 -0
  102. package/src/core/compose/features/style.ts +31 -0
  103. package/src/core/compose/features/text.ts +44 -0
  104. package/src/core/compose/features/textinput.ts +225 -0
  105. package/src/core/compose/features/textlabel.ts +92 -0
  106. package/src/core/compose/features/track.ts +84 -0
  107. package/src/core/compose/features/variant.ts +29 -0
  108. package/src/core/compose/features/withEvents.ts +137 -0
  109. package/src/core/compose/index.ts +54 -0
  110. package/src/core/compose/{pipe.js → pipe.ts} +16 -11
  111. package/src/core/config/component-config.ts +136 -0
  112. package/src/core/config.ts +211 -0
  113. package/src/core/dom/{attributes.js → attributes.ts} +11 -11
  114. package/src/core/dom/classes.ts +60 -0
  115. package/src/core/dom/create.ts +188 -0
  116. package/src/core/dom/events.ts +209 -0
  117. package/src/core/dom/index.ts +10 -0
  118. package/src/core/dom/utils.ts +97 -0
  119. package/src/core/index.ts +111 -0
  120. package/src/core/state/disabled.ts +81 -0
  121. package/src/core/state/emitter.ts +94 -0
  122. package/src/core/state/events.ts +88 -0
  123. package/src/core/state/index.ts +16 -0
  124. package/src/core/state/lifecycle.ts +131 -0
  125. package/src/core/state/store.ts +197 -0
  126. package/src/core/utils/index.ts +45 -0
  127. package/src/core/utils/{mobile.js → mobile.ts} +48 -24
  128. package/src/core/utils/object.ts +41 -0
  129. package/src/core/utils/validate.ts +234 -0
  130. package/src/{index.js → index.ts} +3 -2
  131. package/index.js +0 -11
  132. package/src/components/button/api.js +0 -54
  133. package/src/components/button/button.js +0 -81
  134. package/src/components/button/config.js +0 -10
  135. package/src/components/button/constants.js +0 -63
  136. package/src/components/button/index.js +0 -2
  137. package/src/components/card/card.js +0 -102
  138. package/src/components/card/config.js +0 -16
  139. package/src/components/card/index.js +0 -7
  140. package/src/components/card/media.js +0 -56
  141. package/src/components/checkbox/api.js +0 -45
  142. package/src/components/checkbox/checkbox.js +0 -96
  143. package/src/components/checkbox/index.js +0 -2
  144. package/src/components/container/api.js +0 -42
  145. package/src/components/container/container.js +0 -45
  146. package/src/components/container/index.js +0 -2
  147. package/src/components/container/styles.scss +0 -66
  148. package/src/components/list/index.js +0 -2
  149. package/src/components/list/list-item.js +0 -147
  150. package/src/components/list/list.js +0 -267
  151. package/src/components/menu/api.js +0 -117
  152. package/src/components/menu/constants.js +0 -42
  153. package/src/components/menu/features/items-manager.js +0 -375
  154. package/src/components/menu/features/keyboard-navigation.js +0 -129
  155. package/src/components/menu/features/positioning.js +0 -125
  156. package/src/components/menu/index.js +0 -2
  157. package/src/components/menu/menu-item.js +0 -41
  158. package/src/components/menu/menu.js +0 -54
  159. package/src/components/navigation/api.js +0 -43
  160. package/src/components/navigation/index.js +0 -2
  161. package/src/components/navigation/nav-item.js +0 -137
  162. package/src/components/navigation/navigation.js +0 -55
  163. package/src/components/snackbar/api.js +0 -125
  164. package/src/components/snackbar/features.js +0 -69
  165. package/src/components/snackbar/index.js +0 -2
  166. package/src/components/snackbar/position.js +0 -63
  167. package/src/components/snackbar/queue.js +0 -74
  168. package/src/components/snackbar/snackbar.js +0 -70
  169. package/src/components/switch/api.js +0 -44
  170. package/src/components/switch/index.js +0 -2
  171. package/src/components/switch/switch.js +0 -71
  172. package/src/components/textfield/api.js +0 -49
  173. package/src/components/textfield/index.js +0 -2
  174. package/src/components/textfield/textfield.js +0 -68
  175. package/src/core/build/_ripple.scss +0 -79
  176. package/src/core/build/constants.js +0 -51
  177. package/src/core/build/icon.js +0 -78
  178. package/src/core/build/ripple.js +0 -159
  179. package/src/core/build/text.js +0 -54
  180. package/src/core/compose/base.js +0 -8
  181. package/src/core/compose/component.js +0 -225
  182. package/src/core/compose/features/checkable.js +0 -114
  183. package/src/core/compose/features/disabled.js +0 -64
  184. package/src/core/compose/features/events.js +0 -48
  185. package/src/core/compose/features/icon.js +0 -33
  186. package/src/core/compose/features/index.js +0 -20
  187. package/src/core/compose/features/input.js +0 -100
  188. package/src/core/compose/features/lifecycle.js +0 -69
  189. package/src/core/compose/features/position.js +0 -60
  190. package/src/core/compose/features/ripple.js +0 -32
  191. package/src/core/compose/features/size.js +0 -9
  192. package/src/core/compose/features/style.js +0 -12
  193. package/src/core/compose/features/text.js +0 -17
  194. package/src/core/compose/features/textinput.js +0 -114
  195. package/src/core/compose/features/textlabel.js +0 -28
  196. package/src/core/compose/features/track.js +0 -49
  197. package/src/core/compose/features/variant.js +0 -9
  198. package/src/core/compose/features/withEvents.js +0 -67
  199. package/src/core/compose/index.js +0 -16
  200. package/src/core/config.js +0 -140
  201. package/src/core/dom/classes.js +0 -70
  202. package/src/core/dom/create.js +0 -132
  203. package/src/core/dom/events.js +0 -175
  204. package/src/core/dom/index.js +0 -5
  205. package/src/core/dom/utils.js +0 -22
  206. package/src/core/index.js +0 -23
  207. package/src/core/state/disabled.js +0 -51
  208. package/src/core/state/emitter.js +0 -63
  209. package/src/core/state/events.js +0 -29
  210. package/src/core/state/index.js +0 -6
  211. package/src/core/state/lifecycle.js +0 -64
  212. package/src/core/state/store.js +0 -112
  213. package/src/core/utils/index.js +0 -39
  214. package/src/core/utils/object.js +0 -22
  215. package/src/core/utils/validate.js +0 -37
  216. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  217. /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
  218. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  219. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  220. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  221. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  222. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  223. /package/src/components/switch/{constants.js → constants.ts} +0 -0
  224. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -0,0 +1,136 @@
1
+ // src/core/config/component-config.ts
2
+ import { PREFIX } from '../config';
3
+
4
+ /**
5
+ * Base component configuration interface
6
+ * Common configuration properties shared by all components
7
+ */
8
+ export interface BaseComponentConfig {
9
+ componentName?: string;
10
+ prefix?: string;
11
+ class?: string;
12
+ [key: string]: any;
13
+ }
14
+
15
+ /**
16
+ * Creates a base configuration for any component
17
+ *
18
+ * @param {BaseComponentConfig} defaults - Default configuration for the component
19
+ * @param {BaseComponentConfig} userConfig - User provided configuration
20
+ * @param {string} componentName - The name of the component
21
+ * @returns {BaseComponentConfig} Complete configuration with defaults applied
22
+ *
23
+ * @example
24
+ * // In button/config.ts
25
+ * export const createBaseConfig = (config: ButtonConfig = {}) =>
26
+ * createComponentConfig(defaultConfig, config, 'button');
27
+ */
28
+ export const createComponentConfig = (
29
+ defaults: BaseComponentConfig,
30
+ userConfig: BaseComponentConfig = {},
31
+ componentName: string
32
+ ): BaseComponentConfig => {
33
+ // Create a new object with defaults and user config
34
+ const config = {
35
+ ...defaults,
36
+ ...userConfig,
37
+ // Force these values to ensure consistency
38
+ componentName,
39
+ prefix: PREFIX
40
+ };
41
+
42
+ return config;
43
+ };
44
+
45
+ /**
46
+ * Creates a class name with proper prefixing
47
+ *
48
+ * @param {string} componentName - The name of the component
49
+ * @param {string} [element] - Optional element name for BEM notation
50
+ * @param {string} [modifier] - Optional modifier name for BEM notation
51
+ * @returns {string} Properly formatted class name
52
+ *
53
+ * @example
54
+ * // Returns 'mtrl-button'
55
+ * createClassName('button');
56
+ *
57
+ * // Returns 'mtrl-button__icon'
58
+ * createClassName('button', 'icon');
59
+ *
60
+ * // Returns 'mtrl-button--primary'
61
+ * createClassName('button', null, 'primary');
62
+ *
63
+ * // Returns 'mtrl-button__icon--small'
64
+ * createClassName('button', 'icon', 'small');
65
+ */
66
+ export const createClassName = (
67
+ componentName: string,
68
+ element?: string | null,
69
+ modifier?: string | null
70
+ ): string => {
71
+ let className = `${PREFIX}-${componentName}`;
72
+
73
+ if (element) {
74
+ className += `__${element}`;
75
+ }
76
+
77
+ if (modifier) {
78
+ className += `--${modifier}`;
79
+ }
80
+
81
+ return className;
82
+ };
83
+
84
+ /**
85
+ * Processes class names for an element, handling arrays, nulls and conditional classes
86
+ *
87
+ * @param {string | string[] | null} classNames - Class names to process
88
+ * @returns {string} Space-separated class names as a string
89
+ *
90
+ * @example
91
+ * // Returns 'mtrl-card mtrl-card--elevated custom-class'
92
+ * processClassNames(['mtrl-card', 'mtrl-card--elevated', 'custom-class']);
93
+ *
94
+ * // Returns 'mtrl-card'
95
+ * processClassNames(['mtrl-card', null, undefined]);
96
+ */
97
+ export const processClassNames = (classNames: string | string[] | null): string => {
98
+ if (!classNames) return '';
99
+
100
+ if (typeof classNames === 'string') return classNames;
101
+
102
+ return classNames
103
+ .filter(Boolean) // Remove null, undefined, empty strings
104
+ .join(' ');
105
+ };
106
+
107
+ /**
108
+ * Creates a configuration object for withElement HOC
109
+ *
110
+ * @param {BaseComponentConfig} config - Component configuration
111
+ * @param {Object} options - Element options
112
+ * @returns {Object} Configuration object for withElement
113
+ */
114
+ export const createElementConfig = (
115
+ config: BaseComponentConfig,
116
+ options: {
117
+ tag: string;
118
+ attrs?: Record<string, any>;
119
+ className?: string | string[] | null;
120
+ html?: string;
121
+ text?: string;
122
+ forwardEvents?: Record<string, boolean | Function>;
123
+ interactive?: boolean;
124
+ }
125
+ ) => {
126
+ return {
127
+ tag: options.tag,
128
+ componentName: config.componentName,
129
+ attrs: options.attrs || {},
130
+ className: options.className,
131
+ html: options.html,
132
+ text: options.text,
133
+ forwardEvents: options.forwardEvents || {},
134
+ interactive: options.interactive
135
+ };
136
+ };
@@ -0,0 +1,211 @@
1
+ // src/core/config.ts
2
+
3
+ /**
4
+ * Library prefix used for all components
5
+ */
6
+ export const PREFIX = 'mtrl';
7
+
8
+ /**
9
+ * Gets a prefixed component class name
10
+ * @param type - Component type
11
+ * @returns Prefixed class name
12
+ */
13
+ export const getComponentClass = (type: string): string => `${PREFIX}-${type}`;
14
+
15
+ /**
16
+ * Gets a BEM modifier class name
17
+ * @param baseClass - Base class name
18
+ * @param modifier - Modifier name
19
+ * @returns Modifier class name
20
+ */
21
+ export const getModifierClass = (baseClass: string, modifier: string): string => `${baseClass}--${modifier}`;
22
+
23
+ /**
24
+ * Gets a BEM element class name
25
+ * @param baseClass - Base class name
26
+ * @param element - Element name
27
+ * @returns Element class name
28
+ */
29
+ export const getElementClass = (baseClass: string, element: string): string => `${baseClass}-${element}`;
30
+
31
+ /**
32
+ * Component type identifiers
33
+ */
34
+ export enum COMPONENTS {
35
+ BUTTON = 'button',
36
+ TEXTFIELD = 'textfield',
37
+ CONTAINER = 'container',
38
+ SNACKBAR = 'snackbar',
39
+ SWITCH = 'switch'
40
+ }
41
+
42
+ /**
43
+ * Theme configuration interface
44
+ */
45
+ export interface ThemeConfig {
46
+ /**
47
+ * Theme name
48
+ */
49
+ name: string;
50
+
51
+ /**
52
+ * Theme CSS variables
53
+ */
54
+ variables: Record<string, string>;
55
+
56
+ /**
57
+ * Theme variants
58
+ */
59
+ variants: Record<string, any>;
60
+ }
61
+
62
+ /**
63
+ * Component configuration interface
64
+ */
65
+ export interface ComponentConfig {
66
+ prefix: string;
67
+ type: string;
68
+ baseClass: string;
69
+ getClass: () => string;
70
+ getModifierClass: (modifier: string) => string;
71
+ getElementClass: (element: string) => string;
72
+ withTheme: (theme: string) => ThemedComponentConfig;
73
+ withVariants: (...variants: string[]) => VariantComponentConfig;
74
+ withStates: (...states: string[]) => StateComponentConfig;
75
+ }
76
+
77
+ /**
78
+ * Themed component configuration interface
79
+ */
80
+ export interface ThemedComponentConfig extends ComponentConfig {
81
+ theme: string;
82
+ getThemeClass: (variant: string) => string;
83
+ }
84
+
85
+ /**
86
+ * Variant component configuration interface
87
+ */
88
+ export interface VariantComponentConfig extends ComponentConfig {
89
+ variants: string[];
90
+ hasVariant: (variant: string) => boolean;
91
+ getVariantClass: (variant: string) => string | null;
92
+ }
93
+
94
+ /**
95
+ * State component configuration interface
96
+ */
97
+ export interface StateComponentConfig extends ComponentConfig {
98
+ states: string[];
99
+ getStateClass: (state: string) => string | null;
100
+ }
101
+
102
+ /**
103
+ * Creates a component configuration object
104
+ * @param type - Component type
105
+ * @returns Component configuration interface
106
+ */
107
+ export const createComponentConfig = (type: string): ComponentConfig => {
108
+ const baseClass = `${PREFIX}-${type}`;
109
+
110
+ // Create the base config object
111
+ const config: ComponentConfig = {
112
+ prefix: PREFIX,
113
+ type,
114
+ baseClass,
115
+
116
+ // Class name generators
117
+ getClass: () => baseClass,
118
+ getModifierClass: (modifier) => `${baseClass}--${modifier}`,
119
+ getElementClass: (element) => `${baseClass}-${element}`,
120
+
121
+ // Theme support
122
+ withTheme: (theme) => ({
123
+ ...config,
124
+ theme,
125
+ getThemeClass: (variant) => `${baseClass}--theme-${theme}-${variant}`
126
+ }),
127
+
128
+ // Variant support
129
+ withVariants: (...variants) => ({
130
+ ...config,
131
+ variants,
132
+ hasVariant: (variant) => variants.includes(variant),
133
+ getVariantClass: (variant) =>
134
+ variants.includes(variant) ? `${baseClass}--${variant}` : null
135
+ }),
136
+
137
+ // State support
138
+ withStates: (...states) => ({
139
+ ...config,
140
+ states,
141
+ getStateClass: (state) =>
142
+ states.includes(state) ? `${baseClass}--state-${state}` : null
143
+ })
144
+ };
145
+
146
+ return config;
147
+ };
148
+
149
+ /**
150
+ * Common component states
151
+ */
152
+ export enum STATES {
153
+ DISABLED = 'disabled',
154
+ FOCUSED = 'focused',
155
+ ACTIVE = 'active',
156
+ LOADING = 'loading',
157
+ ERROR = 'error'
158
+ }
159
+
160
+ /**
161
+ * CSS class generation utilities
162
+ */
163
+ export const classNames = {
164
+ /**
165
+ * Creates a BEM-style class name
166
+ * @param block - Block name
167
+ * @param element - Element name
168
+ * @param modifier - Modifier name
169
+ * @returns BEM class name
170
+ */
171
+ bem: (block: string, element?: string, modifier?: string): string => {
172
+ let className = block;
173
+ if (element) className += `-${element}`;
174
+ if (modifier) className += `--${modifier}`;
175
+ return className;
176
+ },
177
+
178
+ /**
179
+ * Joins class names, filtering out falsy values
180
+ * @param classes - Class names to join
181
+ * @returns Joined class names
182
+ */
183
+ join: (...classes: (string | undefined | null | false)[]): string =>
184
+ classes.filter(Boolean).join(' ')
185
+ };
186
+
187
+ /**
188
+ * Creates a themed component configuration
189
+ * @param type - Component type
190
+ * @param theme - Theme configuration
191
+ * @returns Themed component configuration
192
+ */
193
+ export const createThemedComponent = (type: string, theme: ThemeConfig): ThemedComponentConfig => {
194
+ const config = createComponentConfig(type);
195
+
196
+ return {
197
+ ...config,
198
+ theme: theme.name,
199
+
200
+ // Theme-specific class generators
201
+ getThemeClass: (variant) =>
202
+ `${config.getClass()}--theme-${theme.name}${variant ? `-${variant}` : ''}`,
203
+
204
+ // Theme CSS variables
205
+ getCssVariables: () =>
206
+ Object.entries(theme.variables).reduce((acc, [key, value]) => ({
207
+ ...acc,
208
+ [`--${PREFIX}-${type}-${key}`]: value
209
+ }), {} as Record<string, string>)
210
+ };
211
+ };
@@ -1,4 +1,4 @@
1
- // src/core/dom/attributes.js
1
+ // src/core/dom/attributes.ts
2
2
  /**
3
3
  * @module core/dom
4
4
  * @description DOM manipulation utilities
@@ -9,15 +9,15 @@
9
9
  * @memberof module:core/dom
10
10
  * @function setAttributes
11
11
  * @param {HTMLElement} element - Target element
12
- * @param {Object} attrs - Attributes to set
12
+ * @param {Record<string, any>} attrs - Attributes to set
13
13
  * @returns {HTMLElement} Modified element
14
14
  */
15
- export const setAttributes = (element, attrs = {}) => {
15
+ export const setAttributes = (element: HTMLElement, attrs: Record<string, any> = {}): HTMLElement => {
16
16
  Object.entries(attrs).forEach(([key, value]) => {
17
- if (value != null) element.setAttribute(key, value)
18
- })
19
- return element
20
- }
17
+ if (value != null) element.setAttribute(key, value.toString());
18
+ });
19
+ return element;
20
+ };
21
21
 
22
22
  /**
23
23
  * Removes multiple attributes from an element
@@ -27,7 +27,7 @@ export const setAttributes = (element, attrs = {}) => {
27
27
  * @param {string[]} attrs - Attributes to remove
28
28
  * @returns {HTMLElement} Modified element
29
29
  */
30
- export const removeAttributes = (element, attrs = []) => {
31
- attrs.forEach(attr => element.removeAttribute(attr))
32
- return element
33
- }
30
+ export const removeAttributes = (element: HTMLElement, attrs: string[] = []): HTMLElement => {
31
+ attrs.forEach(attr => element.removeAttribute(attr));
32
+ return element;
33
+ };
@@ -0,0 +1,60 @@
1
+ // src/core/dom/classes.ts
2
+ /**
3
+ * @module core/dom
4
+ * @description DOM manipulation utilities
5
+ */
6
+
7
+ import { normalizeClasses } from '../utils';
8
+
9
+ /**
10
+ * Adds multiple classes to an element
11
+ * @param {HTMLElement} element - Target element
12
+ * @param {...(string | string[])} classes - Classes to add
13
+ * @returns {HTMLElement} Modified element
14
+ */
15
+ export const addClass = (element: HTMLElement, ...classes: (string | string[])[]): HTMLElement => {
16
+ const normalizedClasses = normalizeClasses(...classes);
17
+ if (normalizedClasses.length) {
18
+ element.classList.add(...normalizedClasses);
19
+ }
20
+ return element;
21
+ };
22
+
23
+ /**
24
+ * Removes multiple classes from an element
25
+ * @param {HTMLElement} element - Target element
26
+ * @param {...(string | string[])} classes - Classes to remove
27
+ * @returns {HTMLElement} Modified element
28
+ */
29
+ export const removeClass = (element: HTMLElement, ...classes: (string | string[])[]): HTMLElement => {
30
+ const normalizedClasses = normalizeClasses(...classes);
31
+ if (normalizedClasses.length) {
32
+ element.classList.remove(...normalizedClasses);
33
+ }
34
+ return element;
35
+ };
36
+
37
+ /**
38
+ * Toggles multiple classes on an element
39
+ * @param {HTMLElement} element - Target element
40
+ * @param {...(string | string[])} classes - Classes to toggle
41
+ * @returns {HTMLElement} Modified element
42
+ */
43
+ export const toggleClass = (element: HTMLElement, ...classes: (string | string[])[]): HTMLElement => {
44
+ const normalizedClasses = normalizeClasses(...classes);
45
+ normalizedClasses.forEach(cls => {
46
+ element.classList.toggle(cls);
47
+ });
48
+ return element;
49
+ };
50
+
51
+ /**
52
+ * Checks if an element has all specified classes
53
+ * @param {HTMLElement} element - Target element
54
+ * @param {...(string | string[])} classes - Classes to check
55
+ * @returns {boolean} True if element has all specified classes
56
+ */
57
+ export const hasClass = (element: HTMLElement, ...classes: (string | string[])[]): boolean => {
58
+ const normalizedClasses = normalizeClasses(...classes);
59
+ return normalizedClasses.every(cls => element.classList.contains(cls));
60
+ };
@@ -0,0 +1,188 @@
1
+ // src/core/dom/create.ts
2
+ /**
3
+ * @module core/dom
4
+ * @description DOM manipulation utilities
5
+ */
6
+
7
+ import { setAttributes } from './attributes';
8
+ import { normalizeClasses } from '../utils';
9
+
10
+ /**
11
+ * Options for element creation
12
+ */
13
+ export interface CreateElementOptions {
14
+ /**
15
+ * HTML tag name
16
+ */
17
+ tag?: string;
18
+
19
+ /**
20
+ * Container to append element to
21
+ */
22
+ container?: HTMLElement | null;
23
+
24
+ /**
25
+ * Inner HTML content
26
+ */
27
+ html?: string;
28
+
29
+ /**
30
+ * Text content
31
+ */
32
+ text?: string;
33
+
34
+ /**
35
+ * Element ID
36
+ */
37
+ id?: string;
38
+
39
+ /**
40
+ * Dataset attributes
41
+ */
42
+ data?: Record<string, string>;
43
+
44
+ /**
45
+ * CSS classes
46
+ */
47
+ className?: string | string[] | null;
48
+
49
+ /**
50
+ * HTML attributes
51
+ */
52
+ attrs?: Record<string, any>;
53
+
54
+ /**
55
+ * Events to forward when component has emit method
56
+ */
57
+ forwardEvents?: Record<string, boolean | ((context: any, event: Event) => boolean)>;
58
+
59
+ /**
60
+ * Callback after element creation
61
+ */
62
+ onCreate?: (element: HTMLElement, context?: any) => void;
63
+
64
+ /**
65
+ * Component context
66
+ */
67
+ context?: any;
68
+
69
+ /**
70
+ * Additional attributes
71
+ */
72
+ [key: string]: any;
73
+ }
74
+
75
+ /**
76
+ * Creates a DOM element with the specified options
77
+ *
78
+ * @param {CreateElementOptions} options - Element creation options
79
+ * @returns {HTMLElement} Created element
80
+ */
81
+ export const createElement = (options: CreateElementOptions = {}): HTMLElement => {
82
+ const {
83
+ tag = 'div',
84
+ container = null,
85
+ html = '',
86
+ text = '',
87
+ id = '',
88
+ data = {},
89
+ className,
90
+ attrs = {},
91
+ forwardEvents = {},
92
+ onCreate,
93
+ context,
94
+ ...rest
95
+ } = options;
96
+
97
+ const element = document.createElement(tag);
98
+
99
+ // Handle content
100
+ if (html) element.innerHTML = html;
101
+ if (text) element.textContent = text;
102
+ if (id) element.id = id;
103
+
104
+ // Handle classes
105
+ if (className) {
106
+ const normalizedClasses = normalizeClasses(className);
107
+ if (normalizedClasses.length) {
108
+ element.classList.add(...normalizedClasses);
109
+ }
110
+ }
111
+
112
+ // Handle data attributes
113
+ Object.entries(data).forEach(([key, value]) => {
114
+ element.dataset[key] = value;
115
+ });
116
+
117
+ // Handle all other attributes
118
+ const allAttrs = { ...attrs, ...rest };
119
+ Object.entries(allAttrs).forEach(([key, value]) => {
120
+ if (value != null) element.setAttribute(key, value);
121
+ });
122
+
123
+ // Handle event forwarding if context has emit method
124
+ if (context?.emit && forwardEvents) {
125
+ Object.entries(forwardEvents).forEach(([nativeEvent, eventConfig]) => {
126
+ const shouldForward = typeof eventConfig === 'function'
127
+ ? eventConfig
128
+ : () => true;
129
+
130
+ element.addEventListener(nativeEvent, (event) => {
131
+ if (shouldForward({ ...context, element }, event)) {
132
+ context.emit(nativeEvent, { event });
133
+ }
134
+ });
135
+ });
136
+ }
137
+
138
+ // Append to container if provided
139
+ if (container) {
140
+ container.appendChild(element);
141
+ }
142
+
143
+ if (typeof onCreate === 'function') {
144
+ onCreate(element, context);
145
+ }
146
+
147
+ return element;
148
+ };
149
+
150
+ /**
151
+ * Higher-order function to add attributes to an element
152
+ * @param {Record<string, any>} attrs - Attributes to add
153
+ * @returns {(element: HTMLElement) => HTMLElement} Element transformer
154
+ */
155
+ export const withAttributes = (attrs: Record<string, any>) =>
156
+ (element: HTMLElement): HTMLElement => {
157
+ setAttributes(element, attrs);
158
+ return element;
159
+ };
160
+
161
+ /**
162
+ * Higher-order function to add classes to an element
163
+ * @param {...(string | string[])} classes - Classes to add
164
+ * @returns {(element: HTMLElement) => HTMLElement} Element transformer
165
+ */
166
+ export const withClasses = (...classes: (string | string[])[]) =>
167
+ (element: HTMLElement): HTMLElement => {
168
+ const normalizedClasses = normalizeClasses(...classes);
169
+ if (normalizedClasses.length) {
170
+ element.classList.add(...normalizedClasses);
171
+ }
172
+ return element;
173
+ };
174
+
175
+ /**
176
+ * Higher-order function to add content to an element
177
+ * @param {Node|string} content - Content to add
178
+ * @returns {(element: HTMLElement) => HTMLElement} Element transformer
179
+ */
180
+ export const withContent = (content: Node | string) =>
181
+ (element: HTMLElement): HTMLElement => {
182
+ if (content instanceof Node) {
183
+ element.appendChild(content);
184
+ } else {
185
+ element.textContent = content;
186
+ }
187
+ return element;
188
+ };