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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/components/navigation/constants.
|
|
1
|
+
// src/components/navigation/constants.ts
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Navigation variants following Material Design 3
|
|
@@ -9,7 +9,7 @@ export const NAV_VARIANTS = {
|
|
|
9
9
|
BAR: 'bar', // Bottom or top navigation bar
|
|
10
10
|
DRAWER_MODAL: 'modal', // Modal drawer overlay
|
|
11
11
|
DRAWER_STANDARD: 'standard' // Standard permanent drawer
|
|
12
|
-
}
|
|
12
|
+
} as const;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Navigation positions
|
|
@@ -19,7 +19,7 @@ export const NAV_POSITIONS = {
|
|
|
19
19
|
RIGHT: 'right',
|
|
20
20
|
TOP: 'top',
|
|
21
21
|
BOTTOM: 'bottom'
|
|
22
|
-
}
|
|
22
|
+
} as const;
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Navigation behaviors
|
|
@@ -28,7 +28,7 @@ export const NAV_BEHAVIORS = {
|
|
|
28
28
|
FIXED: 'fixed', // Always visible
|
|
29
29
|
DISMISSIBLE: 'dismissible', // Can be dismissed/hidden
|
|
30
30
|
MODAL: 'modal' // Overlays content with scrim
|
|
31
|
-
}
|
|
31
|
+
} as const;
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Navigation state classes
|
|
@@ -41,7 +41,7 @@ export const NAV_STATES = {
|
|
|
41
41
|
HOVERED: 'hovered', // Hover state
|
|
42
42
|
FOCUSED: 'focused', // Keyboard focus state
|
|
43
43
|
PRESSED: 'pressed' // Press/click state
|
|
44
|
-
}
|
|
44
|
+
} as const;
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Navigation element classes
|
|
@@ -61,7 +61,7 @@ export const NAV_CLASSES = {
|
|
|
61
61
|
NESTED_CONTAINER: 'nav-nested-container',
|
|
62
62
|
NESTED_ITEM: 'nav-nested-item',
|
|
63
63
|
EXPAND_ICON: 'nav-expand-icon'
|
|
64
|
-
}
|
|
64
|
+
} as const;
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Validation schema for navigation configuration
|
|
@@ -119,7 +119,7 @@ export const NAV_SCHEMA = {
|
|
|
119
119
|
optional: true
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
}
|
|
122
|
+
} as const;
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* Navigation item states
|
|
@@ -127,7 +127,7 @@ export const NAV_SCHEMA = {
|
|
|
127
127
|
export const NAV_ITEM_STATES = {
|
|
128
128
|
EXPANDED: 'expanded',
|
|
129
129
|
COLLAPSED: 'collapsed'
|
|
130
|
-
}
|
|
130
|
+
} as const;
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* Navigation item schema
|
|
@@ -175,7 +175,7 @@ export const NAV_ITEM_SCHEMA = {
|
|
|
175
175
|
default: false
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
|
-
}
|
|
178
|
+
} as const;
|
|
179
179
|
|
|
180
180
|
/**
|
|
181
181
|
* Navigation group schema
|
|
@@ -197,4 +197,4 @@ export const NAV_GROUP_SCHEMA = {
|
|
|
197
197
|
default: true
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
}
|
|
200
|
+
} as const;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/components/navigation/index.ts
|
|
2
|
+
export { default } from './navigation'
|
|
3
|
+
export {
|
|
4
|
+
NAV_VARIANTS,
|
|
5
|
+
NAV_POSITIONS,
|
|
6
|
+
NAV_BEHAVIORS,
|
|
7
|
+
NAV_STATES
|
|
8
|
+
} from './constants'
|
|
9
|
+
export {
|
|
10
|
+
NavigationConfig,
|
|
11
|
+
NavigationComponent,
|
|
12
|
+
NavItemConfig,
|
|
13
|
+
NavGroupConfig
|
|
14
|
+
} from './types'
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// src/components/navigation/nav-item.ts
|
|
2
|
+
import { NavItemConfig } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates an expand/collapse icon element
|
|
6
|
+
* @param {string} prefix - CSS class prefix
|
|
7
|
+
* @returns {HTMLElement} Expand icon element
|
|
8
|
+
*/
|
|
9
|
+
export const createExpandIcon = (prefix: string): HTMLElement => {
|
|
10
|
+
const icon = document.createElement('span');
|
|
11
|
+
icon.className = `${prefix}-nav-expand-icon`;
|
|
12
|
+
icon.innerHTML = `
|
|
13
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
14
|
+
<polyline points="9 18 15 12 9 6"></polyline>
|
|
15
|
+
</svg>
|
|
16
|
+
`;
|
|
17
|
+
return icon;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a nested items container
|
|
22
|
+
* @param {NavItemConfig[]} items - Nested items configuration
|
|
23
|
+
* @param {string} prefix - CSS class prefix
|
|
24
|
+
* @param {Function} createItem - Item creation function
|
|
25
|
+
* @returns {HTMLElement} Nested items container
|
|
26
|
+
*/
|
|
27
|
+
export const createNestedContainer = (
|
|
28
|
+
items: NavItemConfig[],
|
|
29
|
+
prefix: string,
|
|
30
|
+
createItem: (config: NavItemConfig, container: HTMLElement, prefix: string) => HTMLElement
|
|
31
|
+
): HTMLElement => {
|
|
32
|
+
const container = document.createElement('div');
|
|
33
|
+
container.className = `${prefix}-nav-nested-container`;
|
|
34
|
+
container.setAttribute('role', 'group');
|
|
35
|
+
container.hidden = true;
|
|
36
|
+
|
|
37
|
+
items.forEach(itemConfig => {
|
|
38
|
+
createItem(itemConfig, container, prefix);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return container;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a navigation item element
|
|
46
|
+
* @param {NavItemConfig} config - Item configuration
|
|
47
|
+
* @param {HTMLElement} container - Container element
|
|
48
|
+
* @param {string} prefix - CSS class prefix
|
|
49
|
+
* @returns {HTMLElement} Created navigation item
|
|
50
|
+
*/
|
|
51
|
+
export const createNavItem = (
|
|
52
|
+
config: NavItemConfig,
|
|
53
|
+
container: HTMLElement,
|
|
54
|
+
prefix: string
|
|
55
|
+
): HTMLElement => {
|
|
56
|
+
const itemContainer = document.createElement('div');
|
|
57
|
+
itemContainer.className = `${prefix}-nav-item-container`;
|
|
58
|
+
|
|
59
|
+
const item = document.createElement('button');
|
|
60
|
+
item.className = `${prefix}-nav-item`;
|
|
61
|
+
item.setAttribute('role', config.items?.length ? 'button' : 'menuitem');
|
|
62
|
+
item.setAttribute('aria-selected', 'false');
|
|
63
|
+
|
|
64
|
+
if (config.id) {
|
|
65
|
+
item.dataset.id = config.id;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (config.disabled) {
|
|
69
|
+
item.disabled = true;
|
|
70
|
+
item.setAttribute('aria-disabled', 'true');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Add icon if provided
|
|
74
|
+
if (config.icon) {
|
|
75
|
+
const icon = document.createElement('span');
|
|
76
|
+
icon.className = `${prefix}-nav-item-icon`;
|
|
77
|
+
icon.innerHTML = config.icon;
|
|
78
|
+
item.appendChild(icon);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Add label if provided
|
|
82
|
+
if (config.label) {
|
|
83
|
+
const label = document.createElement('span');
|
|
84
|
+
label.className = `${prefix}-nav-item-label`;
|
|
85
|
+
label.textContent = config.label;
|
|
86
|
+
item.appendChild(label);
|
|
87
|
+
item.setAttribute('aria-label', config.label);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add badge if provided
|
|
91
|
+
if (config.badge) {
|
|
92
|
+
const badge = document.createElement('span');
|
|
93
|
+
badge.className = `${prefix}-nav-item-badge`;
|
|
94
|
+
badge.textContent = config.badge;
|
|
95
|
+
badge.setAttribute('aria-label', `${config.badge} notifications`);
|
|
96
|
+
item.appendChild(badge);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
itemContainer.appendChild(item);
|
|
100
|
+
|
|
101
|
+
// Handle nested items - only for drawer variant
|
|
102
|
+
if (config.items?.length && container.closest('.mtrl-nav--drawer, .mtrl-nav--drawer-modal, .mtrl-nav--drawer-standard')) {
|
|
103
|
+
const expandIcon = createExpandIcon(prefix);
|
|
104
|
+
item.appendChild(expandIcon);
|
|
105
|
+
|
|
106
|
+
item.setAttribute('aria-expanded', config.expanded ? 'true' : 'false');
|
|
107
|
+
item.setAttribute('aria-haspopup', 'true');
|
|
108
|
+
|
|
109
|
+
const nestedContainer = createNestedContainer(config.items, prefix, createNavItem);
|
|
110
|
+
nestedContainer.hidden = !config.expanded;
|
|
111
|
+
itemContainer.appendChild(nestedContainer);
|
|
112
|
+
|
|
113
|
+
// Handle expand/collapse
|
|
114
|
+
item.addEventListener('click', (event) => {
|
|
115
|
+
event.stopPropagation();
|
|
116
|
+
const isExpanded = item.getAttribute('aria-expanded') === 'true';
|
|
117
|
+
item.setAttribute('aria-expanded', (!isExpanded).toString());
|
|
118
|
+
nestedContainer.hidden = isExpanded;
|
|
119
|
+
|
|
120
|
+
// Toggle expand icon rotation
|
|
121
|
+
if (expandIcon.style) {
|
|
122
|
+
expandIcon.style.transform = isExpanded ? '' : 'rotate(90deg)';
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
container.appendChild(itemContainer);
|
|
128
|
+
return item;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Recursively gets all nested items from a navigation item
|
|
133
|
+
* @param {HTMLElement} item - Navigation item element
|
|
134
|
+
* @param {string} prefix - CSS class prefix
|
|
135
|
+
* @returns {Array<HTMLElement>} Array of all nested items
|
|
136
|
+
*/
|
|
137
|
+
export const getAllNestedItems = (item: HTMLElement, prefix: string): HTMLElement[] => {
|
|
138
|
+
const container = item.closest(`.${prefix}-nav-item-container`);
|
|
139
|
+
if (!container) return [];
|
|
140
|
+
|
|
141
|
+
const nestedContainer = container.querySelector(`.${prefix}-nav-nested-container`);
|
|
142
|
+
if (!nestedContainer) return [];
|
|
143
|
+
|
|
144
|
+
const items = Array.from(nestedContainer.querySelectorAll(`.${prefix}-nav-item`)) as HTMLElement[];
|
|
145
|
+
return items.reduce((acc: HTMLElement[], nestedItem: HTMLElement) => {
|
|
146
|
+
return [...acc, nestedItem, ...getAllNestedItems(nestedItem, prefix)];
|
|
147
|
+
}, []);
|
|
148
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/components/navigation/navigation.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
|
+
withPosition // Import core position feature
|
|
10
|
+
} from '../../core/compose/features';
|
|
11
|
+
import { withAPI } from './api';
|
|
12
|
+
import { withNavItems } from './features/items';
|
|
13
|
+
import { NavigationConfig, NavigationComponent } from './types';
|
|
14
|
+
import {
|
|
15
|
+
createBaseConfig,
|
|
16
|
+
getElementConfig,
|
|
17
|
+
getApiConfig
|
|
18
|
+
} from './config';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new Navigation component
|
|
22
|
+
* @param {NavigationConfig} config - Navigation configuration
|
|
23
|
+
* @returns {NavigationComponent} Navigation component instance
|
|
24
|
+
*/
|
|
25
|
+
const createNavigation = (config: NavigationConfig = {}): NavigationComponent => {
|
|
26
|
+
const baseConfig = createBaseConfig(config);
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const navigation = pipe(
|
|
30
|
+
createBase,
|
|
31
|
+
// First add events system
|
|
32
|
+
withEvents(),
|
|
33
|
+
// Then add the element and other features
|
|
34
|
+
withElement(getElementConfig(baseConfig)),
|
|
35
|
+
withVariant(baseConfig),
|
|
36
|
+
withPosition(baseConfig),
|
|
37
|
+
withNavItems(baseConfig),
|
|
38
|
+
withDisabled(baseConfig),
|
|
39
|
+
withLifecycle(),
|
|
40
|
+
comp => withAPI(getApiConfig(comp))(comp)
|
|
41
|
+
)(baseConfig);
|
|
42
|
+
|
|
43
|
+
return navigation as NavigationComponent;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Navigation creation error:', error instanceof Error ? error.message : String(error));
|
|
46
|
+
throw new Error(`Failed to create navigation: ${error instanceof Error ? error.message : String(error)}`);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default createNavigation;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// src/components/navigation/types.ts
|
|
2
|
+
import {
|
|
3
|
+
NAV_VARIANTS,
|
|
4
|
+
NAV_POSITIONS,
|
|
5
|
+
NAV_BEHAVIORS
|
|
6
|
+
} from './constants';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Navigation item configuration
|
|
10
|
+
*/
|
|
11
|
+
export interface NavItemConfig {
|
|
12
|
+
/** Unique identifier for the item */
|
|
13
|
+
id: string;
|
|
14
|
+
|
|
15
|
+
/** HTML content for the icon */
|
|
16
|
+
icon: string;
|
|
17
|
+
|
|
18
|
+
/** Text label for the item */
|
|
19
|
+
label: string;
|
|
20
|
+
|
|
21
|
+
/** Optional badge text (notifications, etc.) */
|
|
22
|
+
badge?: string;
|
|
23
|
+
|
|
24
|
+
/** Whether the item is disabled */
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
|
|
27
|
+
/** Whether the item is active */
|
|
28
|
+
active?: boolean;
|
|
29
|
+
|
|
30
|
+
/** Optional subtitle (for drawer variant) */
|
|
31
|
+
subtitle?: string;
|
|
32
|
+
|
|
33
|
+
/** ID of the group this item belongs to */
|
|
34
|
+
groupId?: string;
|
|
35
|
+
|
|
36
|
+
/** Nested navigation items */
|
|
37
|
+
items?: NavItemConfig[];
|
|
38
|
+
|
|
39
|
+
/** Whether nested items are expanded */
|
|
40
|
+
expanded?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Navigation group configuration
|
|
45
|
+
*/
|
|
46
|
+
export interface NavGroupConfig {
|
|
47
|
+
/** Unique identifier for the group */
|
|
48
|
+
id: string;
|
|
49
|
+
|
|
50
|
+
/** Group title text */
|
|
51
|
+
title: string;
|
|
52
|
+
|
|
53
|
+
/** Whether the group is expanded */
|
|
54
|
+
expanded?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Stored item data
|
|
59
|
+
*/
|
|
60
|
+
export interface NavItemData {
|
|
61
|
+
/** DOM element for the item */
|
|
62
|
+
element: HTMLElement;
|
|
63
|
+
|
|
64
|
+
/** Item configuration */
|
|
65
|
+
config: NavItemConfig;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Navigation change event data
|
|
70
|
+
*/
|
|
71
|
+
export interface NavChangeEvent {
|
|
72
|
+
/** ID of the active item */
|
|
73
|
+
id: string;
|
|
74
|
+
|
|
75
|
+
/** Item data */
|
|
76
|
+
item: NavItemData;
|
|
77
|
+
|
|
78
|
+
/** Previously active item */
|
|
79
|
+
previousItem: NavItemData | null;
|
|
80
|
+
|
|
81
|
+
/** Path of parent item IDs */
|
|
82
|
+
path: string[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Configuration interface for the Navigation component
|
|
87
|
+
*/
|
|
88
|
+
export interface NavigationConfig {
|
|
89
|
+
/** Navigation variant */
|
|
90
|
+
variant?: keyof typeof NAV_VARIANTS | string;
|
|
91
|
+
|
|
92
|
+
/** Navigation position */
|
|
93
|
+
position?: keyof typeof NAV_POSITIONS | string;
|
|
94
|
+
|
|
95
|
+
/** Navigation behavior */
|
|
96
|
+
behavior?: keyof typeof NAV_BEHAVIORS | string;
|
|
97
|
+
|
|
98
|
+
/** Initial navigation items */
|
|
99
|
+
items?: NavItemConfig[];
|
|
100
|
+
|
|
101
|
+
/** Navigation groups */
|
|
102
|
+
groups?: NavGroupConfig[];
|
|
103
|
+
|
|
104
|
+
/** Whether the navigation is disabled */
|
|
105
|
+
disabled?: boolean;
|
|
106
|
+
|
|
107
|
+
/** Whether drawer is initially expanded */
|
|
108
|
+
expanded?: boolean;
|
|
109
|
+
|
|
110
|
+
/** Whether to show labels */
|
|
111
|
+
showLabels?: boolean;
|
|
112
|
+
|
|
113
|
+
/** Whether backdrop scrim is enabled */
|
|
114
|
+
scrimEnabled?: boolean;
|
|
115
|
+
|
|
116
|
+
/** ARIA label for accessibility */
|
|
117
|
+
ariaLabel?: string;
|
|
118
|
+
|
|
119
|
+
/** Additional CSS classes */
|
|
120
|
+
class?: string;
|
|
121
|
+
|
|
122
|
+
/** Prefix for class names */
|
|
123
|
+
prefix?: string;
|
|
124
|
+
|
|
125
|
+
/** Component name */
|
|
126
|
+
componentName?: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Navigation component interface
|
|
131
|
+
*/
|
|
132
|
+
export interface NavigationComponent {
|
|
133
|
+
/** The root element of the navigation */
|
|
134
|
+
element: HTMLElement;
|
|
135
|
+
|
|
136
|
+
/** Map of all navigation items */
|
|
137
|
+
items: Map<string, NavItemData>;
|
|
138
|
+
|
|
139
|
+
/** Adds a new navigation item */
|
|
140
|
+
addItem: (itemConfig: NavItemConfig) => NavigationComponent;
|
|
141
|
+
|
|
142
|
+
/** Removes a navigation item by ID */
|
|
143
|
+
removeItem: (id: string) => NavigationComponent;
|
|
144
|
+
|
|
145
|
+
/** Retrieves a navigation item by ID */
|
|
146
|
+
getItem: (id: string) => NavItemData | undefined;
|
|
147
|
+
|
|
148
|
+
/** Retrieves all navigation items */
|
|
149
|
+
getAllItems: () => NavItemData[];
|
|
150
|
+
|
|
151
|
+
/** Gets the currently active item */
|
|
152
|
+
getActive: () => NavItemData | null;
|
|
153
|
+
|
|
154
|
+
/** Gets the path to an item (parent IDs) */
|
|
155
|
+
getItemPath: (id: string) => string[];
|
|
156
|
+
|
|
157
|
+
/** Sets an item as active by ID */
|
|
158
|
+
setActive: (id: string) => NavigationComponent;
|
|
159
|
+
|
|
160
|
+
/** Adds event listener */
|
|
161
|
+
on: (event: string, handler: Function) => NavigationComponent;
|
|
162
|
+
|
|
163
|
+
/** Removes event listener */
|
|
164
|
+
off: (event: string, handler: Function) => NavigationComponent;
|
|
165
|
+
|
|
166
|
+
/** Enables the navigation */
|
|
167
|
+
enable: () => NavigationComponent;
|
|
168
|
+
|
|
169
|
+
/** Disables the navigation */
|
|
170
|
+
disable: () => NavigationComponent;
|
|
171
|
+
|
|
172
|
+
/** Destroys the navigation component and cleans up resources */
|
|
173
|
+
destroy: () => void;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* API options interface
|
|
178
|
+
*/
|
|
179
|
+
export interface ApiOptions {
|
|
180
|
+
disabled: {
|
|
181
|
+
enable: () => any;
|
|
182
|
+
disable: () => any;
|
|
183
|
+
};
|
|
184
|
+
lifecycle: {
|
|
185
|
+
destroy: () => void;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Base component interface
|
|
191
|
+
*/
|
|
192
|
+
export interface BaseComponent {
|
|
193
|
+
element: HTMLElement;
|
|
194
|
+
emit?: (event: string, data: any) => void;
|
|
195
|
+
on?: (event: string, handler: Function) => any;
|
|
196
|
+
off?: (event: string, handler: Function) => any;
|
|
197
|
+
addItem?: (itemConfig: NavItemConfig) => any;
|
|
198
|
+
removeItem?: (id: string) => any;
|
|
199
|
+
getItem?: (id: string) => NavItemData | undefined;
|
|
200
|
+
getAllItems?: () => NavItemData[];
|
|
201
|
+
getActive?: () => NavItemData | null;
|
|
202
|
+
getItemPath?: (id: string) => string[];
|
|
203
|
+
setActive?: (id: string) => any;
|
|
204
|
+
disabled?: {
|
|
205
|
+
enable: () => any;
|
|
206
|
+
disable: () => any;
|
|
207
|
+
};
|
|
208
|
+
lifecycle?: {
|
|
209
|
+
destroy: () => void;
|
|
210
|
+
};
|
|
211
|
+
[key: string]: any;
|
|
212
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// src/components/progress/_styles.scss
|
|
2
|
+
@use '../../styles/abstract/base' as base;
|
|
3
|
+
@use '../../styles/abstract/variables' as v;
|
|
4
|
+
@use '../../styles/abstract/functions' as f;
|
|
5
|
+
@use '../../styles/abstract/mixins' as m;
|
|
6
|
+
@use '../../styles/abstract/theme' as t;
|
|
7
|
+
|
|
8
|
+
$component: '#{base.$prefix}-progress';
|
|
9
|
+
|
|
10
|
+
.#{$component} {
|
|
11
|
+
// Base styles
|
|
12
|
+
position: relative;
|
|
13
|
+
display: block;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
|
|
16
|
+
// Common accessibility attributes
|
|
17
|
+
&[aria-disabled="true"] {
|
|
18
|
+
opacity: 0.38;
|
|
19
|
+
pointer-events: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Linear progress variant
|
|
23
|
+
&--linear {
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 4px; // Default height
|
|
26
|
+
|
|
27
|
+
.#{$component}-track {
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 0;
|
|
30
|
+
left: 0;
|
|
31
|
+
width: 100%;
|
|
32
|
+
height: 100%;
|
|
33
|
+
background-color: t.color('surface-container-highest');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.#{$component}-buffer {
|
|
37
|
+
position: absolute;
|
|
38
|
+
top: 0;
|
|
39
|
+
left: 0;
|
|
40
|
+
height: 100%;
|
|
41
|
+
width: 0;
|
|
42
|
+
background-color: t.alpha('primary', 0.4);
|
|
43
|
+
transition: width 0.3s ease;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.#{$component}-indicator {
|
|
47
|
+
position: absolute;
|
|
48
|
+
top: 0;
|
|
49
|
+
left: 0;
|
|
50
|
+
height: 100%;
|
|
51
|
+
width: 0;
|
|
52
|
+
background-color: t.color('primary');
|
|
53
|
+
transition: width 0.3s ease;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Indeterminate animation for linear progress
|
|
57
|
+
&.#{$component}--indeterminate {
|
|
58
|
+
.#{$component}-buffer {
|
|
59
|
+
display: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.#{$component}-indicator {
|
|
63
|
+
width: 30%;
|
|
64
|
+
animation: linear-indeterminate 2s infinite;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.#{$component}-label {
|
|
69
|
+
position: absolute;
|
|
70
|
+
right: 0;
|
|
71
|
+
top: 8px;
|
|
72
|
+
font-size: 12px;
|
|
73
|
+
color: t.color('on-surface-variant');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Circular progress variant
|
|
78
|
+
&--circular {
|
|
79
|
+
display: inline-flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
justify-content: center;
|
|
82
|
+
width: 48px;
|
|
83
|
+
height: 48px;
|
|
84
|
+
|
|
85
|
+
svg {
|
|
86
|
+
width: 100%;
|
|
87
|
+
height: 100%;
|
|
88
|
+
transform: rotate(-90deg);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.#{$component}-track {
|
|
92
|
+
stroke: t.color('surface-container-highest');
|
|
93
|
+
fill: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.#{$component}-indicator {
|
|
97
|
+
stroke: t.color('primary');
|
|
98
|
+
fill: none;
|
|
99
|
+
stroke-dasharray: 283; // 2*PI*45
|
|
100
|
+
stroke-dashoffset: 283;
|
|
101
|
+
transition: stroke-dashoffset 0.3s ease;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Indeterminate animation for circular progress
|
|
105
|
+
&.#{$component}--indeterminate {
|
|
106
|
+
.#{$component}-indicator {
|
|
107
|
+
animation: circular-indeterminate 1.5s linear infinite;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.#{$component}-label {
|
|
112
|
+
position: absolute;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
color: t.color('on-surface-variant');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Size variants
|
|
119
|
+
&--small {
|
|
120
|
+
&.#{$component}--linear {
|
|
121
|
+
height: 2px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&.#{$component}--circular {
|
|
125
|
+
width: 24px;
|
|
126
|
+
height: 24px;
|
|
127
|
+
|
|
128
|
+
.#{$component}-track,
|
|
129
|
+
.#{$component}-indicator {
|
|
130
|
+
stroke-width: 3;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&--medium {
|
|
136
|
+
&.#{$component}--linear {
|
|
137
|
+
height: 4px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&.#{$component}--circular {
|
|
141
|
+
width: 48px;
|
|
142
|
+
height: 48px;
|
|
143
|
+
|
|
144
|
+
.#{$component}-track,
|
|
145
|
+
.#{$component}-indicator {
|
|
146
|
+
stroke-width: 4;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
&--large {
|
|
152
|
+
&.#{$component}--linear {
|
|
153
|
+
height: 8px;
|
|
154
|
+
|
|
155
|
+
.#{$component}-label {
|
|
156
|
+
font-size: 14px;
|
|
157
|
+
top: 12px;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
&.#{$component}--circular {
|
|
162
|
+
width: 64px;
|
|
163
|
+
height: 64px;
|
|
164
|
+
|
|
165
|
+
.#{$component}-track,
|
|
166
|
+
.#{$component}-indicator {
|
|
167
|
+
stroke-width: 6;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.#{$component}-label {
|
|
171
|
+
font-size: 14px;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Disabled state
|
|
177
|
+
&--disabled {
|
|
178
|
+
opacity: 0.38;
|
|
179
|
+
pointer-events: none;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Keyframes for indeterminate animations
|
|
184
|
+
@keyframes linear-indeterminate {
|
|
185
|
+
0% {
|
|
186
|
+
left: -30%;
|
|
187
|
+
}
|
|
188
|
+
100% {
|
|
189
|
+
left: 100%;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@keyframes circular-indeterminate {
|
|
194
|
+
0% {
|
|
195
|
+
stroke-dashoffset: 283;
|
|
196
|
+
}
|
|
197
|
+
50% {
|
|
198
|
+
stroke-dashoffset: 70;
|
|
199
|
+
}
|
|
200
|
+
100% {
|
|
201
|
+
stroke-dashoffset: 283;
|
|
202
|
+
transform: rotate(360deg);
|
|
203
|
+
}
|
|
204
|
+
}
|