mtrl 0.1.2 → 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 (220) 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 +359 -0
  12. package/src/components/card/actions.ts +48 -0
  13. package/src/components/card/api.ts +102 -0
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/constants.ts +69 -0
  17. package/src/components/card/content.ts +48 -0
  18. package/src/components/card/features.ts +228 -0
  19. package/src/components/card/header.ts +88 -0
  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} +4 -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/checkbox/api.js +0 -45
  138. package/src/components/checkbox/checkbox.js +0 -96
  139. package/src/components/checkbox/index.js +0 -2
  140. package/src/components/container/api.js +0 -42
  141. package/src/components/container/container.js +0 -45
  142. package/src/components/container/index.js +0 -2
  143. package/src/components/container/styles.scss +0 -66
  144. package/src/components/list/index.js +0 -2
  145. package/src/components/list/list-item.js +0 -147
  146. package/src/components/list/list.js +0 -267
  147. package/src/components/menu/api.js +0 -117
  148. package/src/components/menu/constants.js +0 -42
  149. package/src/components/menu/features/items-manager.js +0 -375
  150. package/src/components/menu/features/keyboard-navigation.js +0 -129
  151. package/src/components/menu/features/positioning.js +0 -125
  152. package/src/components/menu/index.js +0 -2
  153. package/src/components/menu/menu-item.js +0 -41
  154. package/src/components/menu/menu.js +0 -54
  155. package/src/components/navigation/api.js +0 -43
  156. package/src/components/navigation/index.js +0 -2
  157. package/src/components/navigation/nav-item.js +0 -137
  158. package/src/components/navigation/navigation.js +0 -55
  159. package/src/components/snackbar/api.js +0 -125
  160. package/src/components/snackbar/features.js +0 -69
  161. package/src/components/snackbar/index.js +0 -2
  162. package/src/components/snackbar/position.js +0 -63
  163. package/src/components/snackbar/queue.js +0 -74
  164. package/src/components/snackbar/snackbar.js +0 -70
  165. package/src/components/switch/api.js +0 -44
  166. package/src/components/switch/index.js +0 -2
  167. package/src/components/switch/switch.js +0 -71
  168. package/src/components/textfield/api.js +0 -49
  169. package/src/components/textfield/index.js +0 -2
  170. package/src/components/textfield/textfield.js +0 -68
  171. package/src/core/build/_ripple.scss +0 -79
  172. package/src/core/build/constants.js +0 -51
  173. package/src/core/build/icon.js +0 -78
  174. package/src/core/build/ripple.js +0 -159
  175. package/src/core/build/text.js +0 -54
  176. package/src/core/compose/base.js +0 -8
  177. package/src/core/compose/component.js +0 -225
  178. package/src/core/compose/features/checkable.js +0 -114
  179. package/src/core/compose/features/disabled.js +0 -64
  180. package/src/core/compose/features/events.js +0 -48
  181. package/src/core/compose/features/icon.js +0 -33
  182. package/src/core/compose/features/index.js +0 -20
  183. package/src/core/compose/features/input.js +0 -100
  184. package/src/core/compose/features/lifecycle.js +0 -69
  185. package/src/core/compose/features/position.js +0 -60
  186. package/src/core/compose/features/ripple.js +0 -32
  187. package/src/core/compose/features/size.js +0 -9
  188. package/src/core/compose/features/style.js +0 -12
  189. package/src/core/compose/features/text.js +0 -17
  190. package/src/core/compose/features/textinput.js +0 -114
  191. package/src/core/compose/features/textlabel.js +0 -28
  192. package/src/core/compose/features/track.js +0 -49
  193. package/src/core/compose/features/variant.js +0 -9
  194. package/src/core/compose/features/withEvents.js +0 -67
  195. package/src/core/compose/index.js +0 -16
  196. package/src/core/config.js +0 -140
  197. package/src/core/dom/classes.js +0 -70
  198. package/src/core/dom/create.js +0 -132
  199. package/src/core/dom/events.js +0 -175
  200. package/src/core/dom/index.js +0 -5
  201. package/src/core/dom/utils.js +0 -22
  202. package/src/core/index.js +0 -23
  203. package/src/core/state/disabled.js +0 -51
  204. package/src/core/state/emitter.js +0 -63
  205. package/src/core/state/events.js +0 -29
  206. package/src/core/state/index.js +0 -6
  207. package/src/core/state/lifecycle.js +0 -64
  208. package/src/core/state/store.js +0 -112
  209. package/src/core/utils/index.js +0 -39
  210. package/src/core/utils/object.js +0 -22
  211. package/src/core/utils/validate.js +0 -37
  212. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  213. /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
  214. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  215. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  216. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  217. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  218. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  219. /package/src/components/switch/{constants.js → constants.ts} +0 -0
  220. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -0,0 +1,74 @@
1
+ // src/components/switch/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig,
5
+ BaseComponentConfig
6
+ } from '../../core/config/component-config';
7
+ import { SwitchConfig, BaseComponent, ApiOptions } from './types';
8
+ import { SWITCH_LABEL_POSITION } from './constants';
9
+
10
+ /**
11
+ * Default configuration for the Switch component
12
+ */
13
+ export const defaultConfig: SwitchConfig = {
14
+ labelPosition: SWITCH_LABEL_POSITION.END
15
+ };
16
+
17
+ /**
18
+ * Creates the base configuration for Switch component
19
+ * @param {SwitchConfig} config - User provided configuration
20
+ * @returns {SwitchConfig} Complete configuration with defaults applied
21
+ */
22
+ export const createBaseConfig = (config: SwitchConfig = {}): SwitchConfig =>
23
+ createComponentConfig(defaultConfig, config, 'switch') as SwitchConfig;
24
+
25
+ /**
26
+ * Generates element configuration for the Switch component
27
+ * @param {SwitchConfig} config - Switch configuration
28
+ * @returns {Object} Element configuration object for withElement
29
+ */
30
+ export const getElementConfig = (config: SwitchConfig) =>
31
+ createElementConfig(config, {
32
+ tag: 'div',
33
+ componentName: 'switch',
34
+ className: config.class,
35
+ interactive: true
36
+ });
37
+
38
+ /**
39
+ * Applies label position class to the component
40
+ * @param {SwitchConfig} config - Component configuration
41
+ */
42
+ export const withLabelPosition = (config: SwitchConfig) => (component: BaseComponent): BaseComponent => {
43
+ if (!config.label) return component;
44
+
45
+ const position = config.labelPosition || SWITCH_LABEL_POSITION.END;
46
+ const positionClass = `${config.prefix}-switch--label-${position}`;
47
+
48
+ component.element.classList.add(positionClass);
49
+
50
+ return component;
51
+ };
52
+
53
+ /**
54
+ * Creates API configuration for the Switch component
55
+ * @param {BaseComponent} comp - Component with disabled, lifecycle, and checkable features
56
+ * @returns {ApiOptions} API configuration object
57
+ */
58
+ export const getApiConfig = (comp: BaseComponent): ApiOptions => ({
59
+ disabled: {
60
+ enable: comp.disabled?.enable,
61
+ disable: comp.disabled?.disable
62
+ },
63
+ lifecycle: {
64
+ destroy: comp.lifecycle?.destroy
65
+ },
66
+ checkable: {
67
+ check: comp.checkable?.check,
68
+ uncheck: comp.checkable?.uncheck,
69
+ toggle: comp.checkable?.toggle,
70
+ isChecked: comp.checkable?.isChecked
71
+ }
72
+ });
73
+
74
+ export default defaultConfig;
@@ -0,0 +1,4 @@
1
+ // src/components/switch/index.ts
2
+ export { default } from './switch'
3
+ export { SWITCH_LABEL_POSITION } from './constants'
4
+ export { SwitchConfig, SwitchComponent } from './types'
@@ -0,0 +1,52 @@
1
+ // src/components/switch/switch.ts
2
+ import { pipe } from '../../core/compose';
3
+ import { createBase, withElement } from '../../core/compose/component';
4
+ import {
5
+ withEvents,
6
+ withTextLabel,
7
+ withDisabled,
8
+ withLifecycle,
9
+ withInput,
10
+ withTrack,
11
+ withCheckable
12
+ } from '../../core/compose/features';
13
+ import { withAPI } from './api';
14
+ import { SwitchConfig, SwitchComponent, BaseComponent } from './types';
15
+ import {
16
+ createBaseConfig,
17
+ getElementConfig,
18
+ withLabelPosition,
19
+ getApiConfig
20
+ } from './config';
21
+
22
+ /**
23
+ * Creates a new Switch component
24
+ * @param {SwitchConfig} config - Switch configuration
25
+ * @returns {SwitchComponent} Switch component instance
26
+ */
27
+ const createSwitch = (config: SwitchConfig = {}): SwitchComponent => {
28
+ const baseConfig = createBaseConfig(config);
29
+
30
+ try {
31
+ const switchComponent = pipe(
32
+ createBase,
33
+ withEvents(), // Move events first to ensure system is available
34
+ withElement(getElementConfig(baseConfig)),
35
+ withInput(baseConfig),
36
+ withTrack(baseConfig),
37
+ withTextLabel(baseConfig),
38
+ withLabelPosition(baseConfig),
39
+ withCheckable(baseConfig),
40
+ withDisabled(baseConfig),
41
+ withLifecycle(),
42
+ comp => withAPI(getApiConfig(comp))(comp)
43
+ )(baseConfig);
44
+
45
+ return switchComponent as SwitchComponent;
46
+ } catch (error) {
47
+ console.error('Switch creation error:', error instanceof Error ? error.message : String(error));
48
+ throw new Error(`Failed to create switch: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ };
51
+
52
+ export default createSwitch;
@@ -0,0 +1,142 @@
1
+ // src/components/switch/types.ts
2
+ import { SWITCH_LABEL_POSITION } from './constants';
3
+
4
+ /**
5
+ * Configuration interface for the Switch component
6
+ */
7
+ export interface SwitchConfig {
8
+ /** Input name attribute */
9
+ name?: string;
10
+
11
+ /** Initial checked state */
12
+ checked?: boolean;
13
+
14
+ /** Whether input is required */
15
+ required?: boolean;
16
+
17
+ /** Whether switch is disabled */
18
+ disabled?: boolean;
19
+
20
+ /** Input value attribute */
21
+ value?: string;
22
+
23
+ /** Label text */
24
+ label?: string;
25
+
26
+ /** Label position (start/end) */
27
+ labelPosition?: keyof typeof SWITCH_LABEL_POSITION | string;
28
+
29
+ /** Additional CSS classes */
30
+ class?: string;
31
+
32
+ /** ARIA label for accessibility */
33
+ ariaLabel?: string;
34
+
35
+ /** Prefix for class names */
36
+ prefix?: string;
37
+
38
+ /** Component name */
39
+ componentName?: string;
40
+
41
+ /** Icon HTML content */
42
+ icon?: string;
43
+ }
44
+
45
+ /**
46
+ * Switch component interface
47
+ */
48
+ export interface SwitchComponent {
49
+ /** The root element of the switch */
50
+ element: HTMLElement;
51
+
52
+ /** The input element */
53
+ input: HTMLInputElement;
54
+
55
+ /** Gets the switch's value */
56
+ getValue: () => string;
57
+
58
+ /** Sets the switch's value */
59
+ setValue: (value: string) => SwitchComponent;
60
+
61
+ /** Checks/activates the switch */
62
+ check: () => SwitchComponent;
63
+
64
+ /** Unchecks/deactivates the switch */
65
+ uncheck: () => SwitchComponent;
66
+
67
+ /** Toggles the switch's checked state */
68
+ toggle: () => SwitchComponent;
69
+
70
+ /** Returns whether the switch is checked */
71
+ isChecked: () => boolean;
72
+
73
+ /** Sets the switch's label text */
74
+ setLabel: (text: string) => SwitchComponent;
75
+
76
+ /** Gets the switch's label text */
77
+ getLabel: () => string;
78
+
79
+ /** Adds event listener */
80
+ on: (event: string, handler: Function) => SwitchComponent;
81
+
82
+ /** Removes event listener */
83
+ off: (event: string, handler: Function) => SwitchComponent;
84
+
85
+ /** Enables the switch */
86
+ enable: () => SwitchComponent;
87
+
88
+ /** Disables the switch */
89
+ disable: () => SwitchComponent;
90
+
91
+ /** Destroys the switch component and cleans up resources */
92
+ destroy: () => void;
93
+ }
94
+
95
+ /**
96
+ * API options interface
97
+ */
98
+ export interface ApiOptions {
99
+ disabled: {
100
+ enable: () => any;
101
+ disable: () => any;
102
+ };
103
+ lifecycle: {
104
+ destroy: () => void;
105
+ };
106
+ checkable: {
107
+ check: () => any;
108
+ uncheck: () => any;
109
+ toggle: () => any;
110
+ isChecked: () => boolean;
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Base component interface
116
+ */
117
+ export interface BaseComponent {
118
+ element: HTMLElement;
119
+ input?: HTMLInputElement;
120
+ getValue?: () => string;
121
+ setValue?: (value: string) => any;
122
+ text?: {
123
+ setText: (content: string) => any;
124
+ getText: () => string;
125
+ };
126
+ on?: (event: string, handler: Function) => any;
127
+ off?: (event: string, handler: Function) => any;
128
+ disabled?: {
129
+ enable: () => any;
130
+ disable: () => any;
131
+ };
132
+ lifecycle?: {
133
+ destroy: () => void;
134
+ };
135
+ checkable?: {
136
+ check: () => any;
137
+ uncheck: () => any;
138
+ toggle: () => any;
139
+ isChecked: () => boolean;
140
+ };
141
+ [key: string]: any;
142
+ }
@@ -0,0 +1,72 @@
1
+ // src/components/textfield/api.ts
2
+ import { BaseComponent, TextfieldComponent, ApiOptions } from './types';
3
+
4
+ /**
5
+ * Enhances textfield component with API methods
6
+ * @param {ApiOptions} options - API configuration
7
+ * @returns {Function} Higher-order function that adds API methods to component
8
+ */
9
+ export const withAPI = ({ disabled, lifecycle }: ApiOptions) =>
10
+ (component: BaseComponent): TextfieldComponent => ({
11
+ ...component as any,
12
+ element: component.element,
13
+ input: component.input as HTMLInputElement | HTMLTextAreaElement,
14
+
15
+ // Value management
16
+ getValue: component.getValue || (() => ''),
17
+ setValue(value: string): TextfieldComponent {
18
+ component.setValue?.(value);
19
+ return this;
20
+ },
21
+
22
+ // Attributes API
23
+ setAttribute(name: string, value: string): TextfieldComponent {
24
+ component.setAttribute?.(name, value);
25
+ return this;
26
+ },
27
+
28
+ getAttribute(name: string): string | null {
29
+ return component.getAttribute?.(name) || null;
30
+ },
31
+
32
+ removeAttribute(name: string): TextfieldComponent {
33
+ component.removeAttribute?.(name);
34
+ return this;
35
+ },
36
+
37
+ // Label management
38
+ setLabel(text: string): TextfieldComponent {
39
+ component.label?.setText(text);
40
+ return this;
41
+ },
42
+
43
+ getLabel(): string {
44
+ return component.label?.getText() || '';
45
+ },
46
+
47
+ // Event handling
48
+ on(event: string, handler: Function): TextfieldComponent {
49
+ component.on?.(event, handler);
50
+ return this;
51
+ },
52
+
53
+ off(event: string, handler: Function): TextfieldComponent {
54
+ component.off?.(event, handler);
55
+ return this;
56
+ },
57
+
58
+ // State management
59
+ enable(): TextfieldComponent {
60
+ disabled.enable();
61
+ return this;
62
+ },
63
+
64
+ disable(): TextfieldComponent {
65
+ disabled.disable();
66
+ return this;
67
+ },
68
+
69
+ destroy(): void {
70
+ lifecycle.destroy();
71
+ }
72
+ });
@@ -0,0 +1,54 @@
1
+ // src/components/textfield/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig,
5
+ BaseComponentConfig
6
+ } from '../../core/config/component-config';
7
+ import { TextfieldConfig, BaseComponent, ApiOptions } from './types';
8
+ import { TEXTFIELD_VARIANTS, TEXTFIELD_TYPES, TEXTFIELD_SIZES } from './constants';
9
+
10
+ /**
11
+ * Default configuration for the Textfield component
12
+ */
13
+ export const defaultConfig: TextfieldConfig = {
14
+ type: TEXTFIELD_TYPES.TEXT,
15
+ variant: TEXTFIELD_VARIANTS.FILLED,
16
+ size: TEXTFIELD_SIZES.MEDIUM
17
+ };
18
+
19
+ /**
20
+ * Creates the base configuration for Textfield component
21
+ * @param {TextfieldConfig} config - User provided configuration
22
+ * @returns {TextfieldConfig} Complete configuration with defaults applied
23
+ */
24
+ export const createBaseConfig = (config: TextfieldConfig = {}): TextfieldConfig =>
25
+ createComponentConfig(defaultConfig, config, 'textfield') as TextfieldConfig;
26
+
27
+ /**
28
+ * Generates element configuration for the Textfield component
29
+ * @param {TextfieldConfig} config - Textfield configuration
30
+ * @returns {Object} Element configuration object for withElement
31
+ */
32
+ export const getElementConfig = (config: TextfieldConfig) =>
33
+ createElementConfig(config, {
34
+ tag: 'div',
35
+ componentName: 'textfield',
36
+ className: config.class
37
+ });
38
+
39
+ /**
40
+ * Creates API configuration for the Textfield component
41
+ * @param {BaseComponent} comp - Component with disabled and lifecycle features
42
+ * @returns {ApiOptions} API configuration object
43
+ */
44
+ export const getApiConfig = (comp: BaseComponent): ApiOptions => ({
45
+ disabled: {
46
+ enable: comp.disabled?.enable,
47
+ disable: comp.disabled?.disable
48
+ },
49
+ lifecycle: {
50
+ destroy: comp.lifecycle?.destroy
51
+ }
52
+ });
53
+
54
+ export default defaultConfig;
@@ -1,16 +1,25 @@
1
- // src/components/textfield/constants.js
1
+ // src/components/textfield/constants.ts
2
2
 
3
+ /**
4
+ * Textfield visual variants
5
+ */
3
6
  export const TEXTFIELD_VARIANTS = {
4
7
  FILLED: 'filled',
5
8
  OUTLINED: 'outlined'
6
- }
9
+ } as const;
7
10
 
11
+ /**
12
+ * Textfield size variants
13
+ */
8
14
  export const TEXTFIELD_SIZES = {
9
15
  SMALL: 'small',
10
16
  MEDIUM: 'medium',
11
17
  LARGE: 'large'
12
- }
18
+ } as const;
13
19
 
20
+ /**
21
+ * Textfield input types
22
+ */
14
23
  export const TEXTFIELD_TYPES = {
15
24
  TEXT: 'text',
16
25
  PASSWORD: 'password',
@@ -20,8 +29,11 @@ export const TEXTFIELD_TYPES = {
20
29
  URL: 'url',
21
30
  SEARCH: 'search',
22
31
  MULTILINE: 'multiline'
23
- }
32
+ } as const;
24
33
 
34
+ /**
35
+ * Validation schema for textfield configuration
36
+ */
25
37
  export const TEXTFIELD_SCHEMA = {
26
38
  type: {
27
39
  type: 'string',
@@ -78,4 +90,25 @@ export const TEXTFIELD_SCHEMA = {
78
90
  type: 'string',
79
91
  required: false
80
92
  }
81
- }
93
+ } as const;
94
+
95
+ /**
96
+ * Textfield state classes
97
+ */
98
+ export const TEXTFIELD_STATES = {
99
+ FOCUSED: 'focused',
100
+ FILLED: 'filled',
101
+ DISABLED: 'disabled',
102
+ INVALID: 'invalid'
103
+ } as const;
104
+
105
+ /**
106
+ * Textfield element classes
107
+ */
108
+ export const TEXTFIELD_CLASSES = {
109
+ ROOT: 'textfield',
110
+ INPUT: 'textfield-input',
111
+ LABEL: 'textfield-label',
112
+ HELPER: 'textfield-helper',
113
+ COUNTER: 'textfield-counter'
114
+ } as const;
@@ -0,0 +1,4 @@
1
+ // src/components/textfield/index.ts
2
+ export { default } from './textfield'
3
+ export { TEXTFIELD_VARIANTS, TEXTFIELD_SIZES, TEXTFIELD_TYPES } from './constants'
4
+ export { TextfieldConfig, TextfieldComponent } from './types'
@@ -0,0 +1,50 @@
1
+ // src/components/textfield/textfield.ts
2
+ import { pipe } from '../../core/compose';
3
+ import { createBase, withElement } from '../../core/compose/component';
4
+ import {
5
+ withEvents,
6
+ withDisabled,
7
+ withLifecycle,
8
+ withVariant,
9
+ withSize,
10
+ withTextInput,
11
+ withTextLabel
12
+ } from '../../core/compose/features';
13
+ import { withAPI } from './api';
14
+ import { TextfieldConfig, TextfieldComponent } from './types';
15
+ import {
16
+ createBaseConfig,
17
+ getElementConfig,
18
+ getApiConfig
19
+ } from './config';
20
+
21
+ /**
22
+ * Creates a new Textfield component
23
+ * @param {TextfieldConfig} config - Textfield configuration
24
+ * @returns {TextfieldComponent} Textfield component instance
25
+ */
26
+ const createTextfield = (config: TextfieldConfig = {}): TextfieldComponent => {
27
+ const baseConfig = createBaseConfig(config);
28
+
29
+ try {
30
+ const textfield = pipe(
31
+ createBase,
32
+ withEvents(),
33
+ withElement(getElementConfig(baseConfig)),
34
+ withVariant(baseConfig),
35
+ withSize(baseConfig),
36
+ withTextInput(baseConfig),
37
+ withTextLabel(baseConfig),
38
+ withDisabled(baseConfig),
39
+ withLifecycle(),
40
+ comp => withAPI(getApiConfig(comp))(comp)
41
+ )(baseConfig);
42
+
43
+ return textfield as TextfieldComponent;
44
+ } catch (error) {
45
+ console.error('Textfield creation error:', error instanceof Error ? error.message : String(error));
46
+ throw new Error(`Failed to create textfield: ${error instanceof Error ? error.message : String(error)}`);
47
+ }
48
+ };
49
+
50
+ export default createTextfield;
@@ -0,0 +1,139 @@
1
+ // src/components/textfield/types.ts
2
+ import { TEXTFIELD_VARIANTS, TEXTFIELD_SIZES, TEXTFIELD_TYPES } from './constants';
3
+
4
+ /**
5
+ * Configuration interface for the Textfield component
6
+ */
7
+ export interface TextfieldConfig {
8
+ /** Input type (text, password, email, etc.) */
9
+ type?: keyof typeof TEXTFIELD_TYPES | string;
10
+
11
+ /** Visual variant (filled, outlined) */
12
+ variant?: keyof typeof TEXTFIELD_VARIANTS | string;
13
+
14
+ /** Size variant (small, medium, large) */
15
+ size?: keyof typeof TEXTFIELD_SIZES | string;
16
+
17
+ /** Input name attribute */
18
+ name?: string;
19
+
20
+ /** Label text */
21
+ label?: string;
22
+
23
+ /** Placeholder text */
24
+ placeholder?: string;
25
+
26
+ /** Initial value */
27
+ value?: string;
28
+
29
+ /** Whether input is required */
30
+ required?: boolean;
31
+
32
+ /** Whether textfield is disabled */
33
+ disabled?: boolean;
34
+
35
+ /** Maximum input length */
36
+ maxLength?: number;
37
+
38
+ /** Input pattern for validation */
39
+ pattern?: string;
40
+
41
+ /** Autocomplete attribute */
42
+ autocomplete?: string;
43
+
44
+ /** Additional CSS classes */
45
+ class?: string;
46
+
47
+ /** Prefix for class names */
48
+ prefix?: string;
49
+
50
+ /** Component name */
51
+ componentName?: string;
52
+ }
53
+
54
+ /**
55
+ * Textfield component interface
56
+ */
57
+ export interface TextfieldComponent {
58
+ /** The root element of the textfield */
59
+ element: HTMLElement;
60
+
61
+ /** The input element */
62
+ input: HTMLInputElement | HTMLTextAreaElement;
63
+
64
+ /** Gets the textfield's value */
65
+ getValue: () => string;
66
+
67
+ /** Sets the textfield's value */
68
+ setValue: (value: string) => TextfieldComponent;
69
+
70
+ /** Sets an attribute on the input element */
71
+ setAttribute: (name: string, value: string) => TextfieldComponent;
72
+
73
+ /** Gets an attribute from the input element */
74
+ getAttribute: (name: string) => string | null;
75
+
76
+ /** Removes an attribute from the input element */
77
+ removeAttribute: (name: string) => TextfieldComponent;
78
+
79
+ /** Sets the textfield's label text */
80
+ setLabel: (text: string) => TextfieldComponent;
81
+
82
+ /** Gets the textfield's label text */
83
+ getLabel: () => string;
84
+
85
+ /** Adds event listener */
86
+ on: (event: string, handler: Function) => TextfieldComponent;
87
+
88
+ /** Removes event listener */
89
+ off: (event: string, handler: Function) => TextfieldComponent;
90
+
91
+ /** Enables the textfield */
92
+ enable: () => TextfieldComponent;
93
+
94
+ /** Disables the textfield */
95
+ disable: () => TextfieldComponent;
96
+
97
+ /** Destroys the textfield component and cleans up resources */
98
+ destroy: () => void;
99
+ }
100
+
101
+ /**
102
+ * API options interface
103
+ */
104
+ export interface ApiOptions {
105
+ disabled: {
106
+ enable: () => any;
107
+ disable: () => any;
108
+ };
109
+ lifecycle: {
110
+ destroy: () => void;
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Base component interface
116
+ */
117
+ export interface BaseComponent {
118
+ element: HTMLElement;
119
+ input?: HTMLInputElement | HTMLTextAreaElement;
120
+ getValue?: () => string;
121
+ setValue?: (value: string) => any;
122
+ setAttribute?: (name: string, value: string) => any;
123
+ getAttribute?: (name: string) => string | null;
124
+ removeAttribute?: (name: string) => any;
125
+ label?: {
126
+ setText: (content: string) => any;
127
+ getText: () => string;
128
+ };
129
+ on?: (event: string, handler: Function) => any;
130
+ off?: (event: string, handler: Function) => any;
131
+ disabled?: {
132
+ enable: () => any;
133
+ disable: () => any;
134
+ };
135
+ lifecycle?: {
136
+ destroy: () => void;
137
+ };
138
+ [key: string]: any;
139
+ }
@@ -0,0 +1,43 @@
1
+ // src/core/compose/base.ts
2
+
3
+ /**
4
+ * Configuration for component creation
5
+ */
6
+ export interface ComponentConfig {
7
+ [key: string]: any;
8
+ }
9
+
10
+ /**
11
+ * Basic component interface
12
+ */
13
+ export interface Component {
14
+ /**
15
+ * Component element
16
+ */
17
+ element: HTMLElement | null;
18
+
19
+ /**
20
+ * Component configuration
21
+ */
22
+ config: ComponentConfig;
23
+
24
+ /**
25
+ * Setup method
26
+ * @returns Component for chaining
27
+ */
28
+ setup: () => Component;
29
+ }
30
+
31
+ /**
32
+ * Creates a basic component with minimal structure
33
+ *
34
+ * @param config - Component configuration
35
+ * @returns Basic component structure
36
+ */
37
+ export const createComponent = (config: ComponentConfig = {}): Component => ({
38
+ element: null,
39
+ config,
40
+ setup() {
41
+ return this;
42
+ }
43
+ });