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.
- package/README.md +70 -22
- package/index.ts +33 -0
- package/package.json +14 -5
- package/src/components/button/{styles.scss → _styles.scss} +2 -2
- package/src/components/button/api.ts +89 -0
- package/src/components/button/button.ts +50 -0
- package/src/components/button/config.ts +75 -0
- package/src/components/button/constants.ts +17 -0
- package/src/components/button/index.ts +4 -0
- package/src/components/button/types.ts +118 -0
- package/src/components/card/_styles.scss +359 -0
- package/src/components/card/actions.ts +48 -0
- package/src/components/card/api.ts +102 -0
- package/src/components/card/card.ts +41 -0
- package/src/components/card/config.ts +99 -0
- package/src/components/card/constants.ts +69 -0
- package/src/components/card/content.ts +48 -0
- package/src/components/card/features.ts +228 -0
- package/src/components/card/header.ts +88 -0
- package/src/components/card/index.ts +19 -0
- package/src/components/card/media.ts +52 -0
- package/src/components/card/types.ts +174 -0
- package/src/components/checkbox/api.ts +82 -0
- package/src/components/checkbox/checkbox.ts +75 -0
- package/src/components/checkbox/config.ts +90 -0
- package/src/components/checkbox/index.ts +4 -0
- package/src/components/checkbox/types.ts +146 -0
- package/src/components/chip/_styles.scss +372 -0
- package/src/components/chip/api.ts +115 -0
- package/src/components/chip/chip-set.ts +225 -0
- package/src/components/chip/chip.ts +82 -0
- package/src/components/chip/config.ts +92 -0
- package/src/components/chip/constants.ts +38 -0
- package/src/components/chip/index.ts +4 -0
- package/src/components/chip/types.ts +172 -0
- package/src/components/list/api.ts +72 -0
- package/src/components/list/config.ts +43 -0
- package/src/components/list/{constants.js → constants.ts} +34 -7
- package/src/components/list/features.ts +224 -0
- package/src/components/list/index.ts +14 -0
- package/src/components/list/list-item.ts +120 -0
- package/src/components/list/list.ts +37 -0
- package/src/components/list/types.ts +179 -0
- package/src/components/list/utils.ts +47 -0
- package/src/components/menu/api.ts +119 -0
- package/src/components/menu/config.ts +54 -0
- package/src/components/menu/constants.ts +154 -0
- package/src/components/menu/features/items-manager.ts +457 -0
- package/src/components/menu/features/keyboard-navigation.ts +133 -0
- package/src/components/menu/features/positioning.ts +127 -0
- package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
- package/src/components/menu/index.ts +14 -0
- package/src/components/menu/menu-item.ts +43 -0
- package/src/components/menu/menu.ts +53 -0
- package/src/components/menu/types.ts +178 -0
- package/src/components/navigation/api.ts +79 -0
- package/src/components/navigation/config.ts +61 -0
- package/src/components/navigation/{constants.js → constants.ts} +10 -10
- package/src/components/navigation/index.ts +14 -0
- package/src/components/navigation/nav-item.ts +148 -0
- package/src/components/navigation/navigation.ts +50 -0
- package/src/components/navigation/types.ts +212 -0
- package/src/components/progress/_styles.scss +204 -0
- package/src/components/progress/api.ts +179 -0
- package/src/components/progress/config.ts +124 -0
- package/src/components/progress/constants.ts +43 -0
- package/src/components/progress/index.ts +5 -0
- package/src/components/progress/progress.ts +163 -0
- package/src/components/progress/types.ts +102 -0
- package/src/components/snackbar/api.ts +162 -0
- package/src/components/snackbar/config.ts +62 -0
- package/src/components/snackbar/{constants.js → constants.ts} +21 -4
- package/src/components/snackbar/features.ts +76 -0
- package/src/components/snackbar/index.ts +4 -0
- package/src/components/snackbar/position.ts +71 -0
- package/src/components/snackbar/queue.ts +76 -0
- package/src/components/snackbar/snackbar.ts +60 -0
- package/src/components/snackbar/types.ts +58 -0
- package/src/components/switch/api.ts +77 -0
- package/src/components/switch/config.ts +74 -0
- package/src/components/switch/index.ts +4 -0
- package/src/components/switch/switch.ts +52 -0
- package/src/components/switch/types.ts +142 -0
- package/src/components/textfield/api.ts +72 -0
- package/src/components/textfield/config.ts +54 -0
- package/src/components/textfield/{constants.js → constants.ts} +38 -5
- package/src/components/textfield/index.ts +4 -0
- package/src/components/textfield/textfield.ts +50 -0
- package/src/components/textfield/types.ts +139 -0
- package/src/core/compose/base.ts +43 -0
- package/src/core/compose/component.ts +247 -0
- package/src/core/compose/features/checkable.ts +155 -0
- package/src/core/compose/features/disabled.ts +116 -0
- package/src/core/compose/features/events.ts +65 -0
- package/src/core/compose/features/icon.ts +67 -0
- package/src/core/compose/features/index.ts +35 -0
- package/src/core/compose/features/input.ts +174 -0
- package/src/core/compose/features/lifecycle.ts +139 -0
- package/src/core/compose/features/position.ts +94 -0
- package/src/core/compose/features/ripple.ts +55 -0
- package/src/core/compose/features/size.ts +29 -0
- package/src/core/compose/features/style.ts +31 -0
- package/src/core/compose/features/text.ts +44 -0
- package/src/core/compose/features/textinput.ts +225 -0
- package/src/core/compose/features/textlabel.ts +92 -0
- package/src/core/compose/features/track.ts +84 -0
- package/src/core/compose/features/variant.ts +29 -0
- package/src/core/compose/features/withEvents.ts +137 -0
- package/src/core/compose/index.ts +54 -0
- package/src/core/compose/{pipe.js → pipe.ts} +16 -11
- package/src/core/config/component-config.ts +136 -0
- package/src/core/config.ts +211 -0
- package/src/core/dom/{attributes.js → attributes.ts} +11 -11
- package/src/core/dom/classes.ts +60 -0
- package/src/core/dom/create.ts +188 -0
- package/src/core/dom/events.ts +209 -0
- package/src/core/dom/index.ts +10 -0
- package/src/core/dom/utils.ts +97 -0
- package/src/core/index.ts +111 -0
- package/src/core/state/disabled.ts +81 -0
- package/src/core/state/emitter.ts +94 -0
- package/src/core/state/events.ts +88 -0
- package/src/core/state/index.ts +16 -0
- package/src/core/state/lifecycle.ts +131 -0
- package/src/core/state/store.ts +197 -0
- package/src/core/utils/index.ts +45 -0
- package/src/core/utils/{mobile.js → mobile.ts} +48 -24
- package/src/core/utils/object.ts +41 -0
- package/src/core/utils/validate.ts +234 -0
- package/src/{index.js → index.ts} +4 -2
- package/index.js +0 -11
- package/src/components/button/api.js +0 -54
- package/src/components/button/button.js +0 -81
- package/src/components/button/config.js +0 -10
- package/src/components/button/constants.js +0 -63
- package/src/components/button/index.js +0 -2
- package/src/components/checkbox/api.js +0 -45
- package/src/components/checkbox/checkbox.js +0 -96
- package/src/components/checkbox/index.js +0 -2
- package/src/components/container/api.js +0 -42
- package/src/components/container/container.js +0 -45
- package/src/components/container/index.js +0 -2
- package/src/components/container/styles.scss +0 -66
- package/src/components/list/index.js +0 -2
- package/src/components/list/list-item.js +0 -147
- package/src/components/list/list.js +0 -267
- package/src/components/menu/api.js +0 -117
- package/src/components/menu/constants.js +0 -42
- package/src/components/menu/features/items-manager.js +0 -375
- package/src/components/menu/features/keyboard-navigation.js +0 -129
- package/src/components/menu/features/positioning.js +0 -125
- package/src/components/menu/index.js +0 -2
- package/src/components/menu/menu-item.js +0 -41
- package/src/components/menu/menu.js +0 -54
- package/src/components/navigation/api.js +0 -43
- package/src/components/navigation/index.js +0 -2
- package/src/components/navigation/nav-item.js +0 -137
- package/src/components/navigation/navigation.js +0 -55
- package/src/components/snackbar/api.js +0 -125
- package/src/components/snackbar/features.js +0 -69
- package/src/components/snackbar/index.js +0 -2
- package/src/components/snackbar/position.js +0 -63
- package/src/components/snackbar/queue.js +0 -74
- package/src/components/snackbar/snackbar.js +0 -70
- package/src/components/switch/api.js +0 -44
- package/src/components/switch/index.js +0 -2
- package/src/components/switch/switch.js +0 -71
- package/src/components/textfield/api.js +0 -49
- package/src/components/textfield/index.js +0 -2
- package/src/components/textfield/textfield.js +0 -68
- package/src/core/build/_ripple.scss +0 -79
- package/src/core/build/constants.js +0 -51
- package/src/core/build/icon.js +0 -78
- package/src/core/build/ripple.js +0 -159
- package/src/core/build/text.js +0 -54
- package/src/core/compose/base.js +0 -8
- package/src/core/compose/component.js +0 -225
- package/src/core/compose/features/checkable.js +0 -114
- package/src/core/compose/features/disabled.js +0 -64
- package/src/core/compose/features/events.js +0 -48
- package/src/core/compose/features/icon.js +0 -33
- package/src/core/compose/features/index.js +0 -20
- package/src/core/compose/features/input.js +0 -100
- package/src/core/compose/features/lifecycle.js +0 -69
- package/src/core/compose/features/position.js +0 -60
- package/src/core/compose/features/ripple.js +0 -32
- package/src/core/compose/features/size.js +0 -9
- package/src/core/compose/features/style.js +0 -12
- package/src/core/compose/features/text.js +0 -17
- package/src/core/compose/features/textinput.js +0 -114
- package/src/core/compose/features/textlabel.js +0 -28
- package/src/core/compose/features/track.js +0 -49
- package/src/core/compose/features/variant.js +0 -9
- package/src/core/compose/features/withEvents.js +0 -67
- package/src/core/compose/index.js +0 -16
- package/src/core/config.js +0 -140
- package/src/core/dom/classes.js +0 -70
- package/src/core/dom/create.js +0 -132
- package/src/core/dom/events.js +0 -175
- package/src/core/dom/index.js +0 -5
- package/src/core/dom/utils.js +0 -22
- package/src/core/index.js +0 -23
- package/src/core/state/disabled.js +0 -51
- package/src/core/state/emitter.js +0 -63
- package/src/core/state/events.js +0 -29
- package/src/core/state/index.js +0 -6
- package/src/core/state/lifecycle.js +0 -64
- package/src/core/state/store.js +0 -112
- package/src/core/utils/index.js +0 -39
- package/src/core/utils/object.js +0 -22
- package/src/core/utils/validate.js +0 -37
- /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
- /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
- /package/src/components/list/{styles.scss → _styles.scss} +0 -0
- /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
- /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
- /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
- /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
- /package/src/components/switch/{constants.js → constants.ts} +0 -0
- /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,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.
|
|
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,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
|
+
});
|