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.
- 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 → _styles.scss} +79 -7
- package/src/components/card/{actions.js → actions.ts} +15 -18
- package/src/components/card/{api.js → api.ts} +33 -33
- package/src/components/card/card.ts +41 -0
- package/src/components/card/config.ts +99 -0
- package/src/components/card/{constants.js → constants.ts} +11 -10
- package/src/components/card/{content.js → content.ts} +15 -18
- package/src/components/card/{features.js → features.ts} +104 -94
- package/src/components/card/{header.js → header.ts} +21 -25
- 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} +3 -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/card/card.js +0 -102
- package/src/components/card/config.js +0 -16
- package/src/components/card/index.js +0 -7
- package/src/components/card/media.js +0 -56
- 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,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.
|
|
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 {
|
|
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
|
+
};
|