mtrl 0.2.5 → 0.2.7
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/index.ts +18 -0
- package/package.json +1 -1
- package/src/components/badge/_styles.scss +123 -115
- package/src/components/badge/api.ts +57 -59
- package/src/components/badge/badge.ts +16 -2
- package/src/components/badge/config.ts +65 -11
- package/src/components/badge/constants.ts +22 -12
- package/src/components/badge/features.ts +44 -40
- package/src/components/badge/types.ts +42 -30
- package/src/components/bottom-app-bar/_styles.scss +103 -0
- package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
- package/src/components/bottom-app-bar/config.ts +73 -0
- package/src/components/bottom-app-bar/index.ts +11 -0
- package/src/components/bottom-app-bar/types.ts +108 -0
- package/src/components/button/_styles.scss +0 -66
- package/src/components/button/api.ts +5 -0
- package/src/components/button/button.ts +0 -2
- package/src/components/button/config.ts +5 -0
- package/src/components/button/constants.ts +0 -6
- package/src/components/button/index.ts +2 -2
- package/src/components/button/types.ts +7 -7
- package/src/components/card/_styles.scss +67 -25
- package/src/components/card/api.ts +54 -3
- package/src/components/card/card.ts +25 -6
- package/src/components/card/config.ts +189 -22
- package/src/components/card/constants.ts +20 -19
- package/src/components/card/content.ts +299 -2
- package/src/components/card/features.ts +158 -4
- package/src/components/card/index.ts +31 -9
- package/src/components/card/types.ts +166 -15
- package/src/components/checkbox/_styles.scss +0 -2
- package/src/components/chip/chip.ts +1 -9
- package/src/components/chip/constants.ts +0 -10
- package/src/components/chip/index.ts +1 -1
- package/src/components/chip/types.ts +1 -4
- package/src/components/datepicker/_styles.scss +358 -0
- package/src/components/datepicker/api.ts +272 -0
- package/src/components/datepicker/config.ts +144 -0
- package/src/components/datepicker/constants.ts +98 -0
- package/src/components/datepicker/datepicker.ts +346 -0
- package/src/components/datepicker/index.ts +9 -0
- package/src/components/datepicker/render.ts +452 -0
- package/src/components/datepicker/types.ts +268 -0
- package/src/components/datepicker/utils.ts +290 -0
- package/src/components/dialog/_styles.scss +174 -128
- package/src/components/dialog/api.ts +48 -13
- package/src/components/dialog/config.ts +9 -5
- package/src/components/dialog/dialog.ts +6 -3
- package/src/components/dialog/features.ts +290 -130
- package/src/components/dialog/types.ts +7 -4
- package/src/components/divider/_styles.scss +57 -0
- package/src/components/divider/config.ts +81 -0
- package/src/components/divider/divider.ts +37 -0
- package/src/components/divider/features.ts +207 -0
- package/src/components/divider/index.ts +5 -0
- package/src/components/divider/types.ts +55 -0
- package/src/components/extended-fab/_styles.scss +267 -0
- package/src/components/extended-fab/api.ts +141 -0
- package/src/components/extended-fab/config.ts +108 -0
- package/src/components/extended-fab/constants.ts +36 -0
- package/src/components/extended-fab/extended-fab.ts +125 -0
- package/src/components/extended-fab/index.ts +4 -0
- package/src/components/extended-fab/types.ts +287 -0
- package/src/components/fab/_styles.scss +225 -0
- package/src/components/fab/api.ts +97 -0
- package/src/components/fab/config.ts +94 -0
- package/src/components/fab/constants.ts +41 -0
- package/src/components/fab/fab.ts +67 -0
- package/src/components/fab/index.ts +4 -0
- package/src/components/fab/types.ts +234 -0
- package/src/components/navigation/_styles.scss +1 -0
- package/src/components/navigation/api.ts +78 -50
- package/src/components/navigation/features/items.ts +280 -0
- package/src/components/navigation/nav-item.ts +72 -23
- package/src/components/navigation/navigation.ts +54 -2
- package/src/components/navigation/types.ts +210 -188
- package/src/components/progress/_styles.scss +0 -65
- package/src/components/progress/config.ts +1 -2
- package/src/components/progress/constants.ts +0 -14
- package/src/components/progress/index.ts +1 -1
- package/src/components/progress/progress.ts +1 -4
- package/src/components/progress/types.ts +1 -4
- package/src/components/radios/_styles.scss +0 -45
- package/src/components/radios/api.ts +85 -60
- package/src/components/radios/config.ts +1 -2
- package/src/components/radios/constants.ts +0 -9
- package/src/components/radios/index.ts +1 -1
- package/src/components/radios/radio.ts +34 -11
- package/src/components/radios/radios.ts +2 -1
- package/src/components/radios/types.ts +1 -7
- package/src/components/search/_styles.scss +306 -0
- package/src/components/search/api.ts +203 -0
- package/src/components/search/config.ts +87 -0
- package/src/components/search/constants.ts +21 -0
- package/src/components/search/features/index.ts +4 -0
- package/src/components/search/features/search.ts +718 -0
- package/src/components/search/features/states.ts +165 -0
- package/src/components/search/features/structure.ts +198 -0
- package/src/components/search/index.ts +10 -0
- package/src/components/search/search.ts +52 -0
- package/src/components/search/types.ts +163 -0
- package/src/components/segmented-button/_styles.scss +117 -0
- package/src/components/segmented-button/config.ts +67 -0
- package/src/components/segmented-button/constants.ts +42 -0
- package/src/components/segmented-button/index.ts +4 -0
- package/src/components/segmented-button/segment.ts +155 -0
- package/src/components/segmented-button/segmented-button.ts +250 -0
- package/src/components/segmented-button/types.ts +219 -0
- package/src/components/slider/_styles.scss +221 -168
- package/src/components/slider/accessibility.md +59 -0
- package/src/components/slider/api.ts +41 -120
- package/src/components/slider/config.ts +51 -49
- package/src/components/slider/features/handlers.ts +495 -0
- package/src/components/slider/features/index.ts +1 -2
- package/src/components/slider/features/slider.ts +66 -84
- package/src/components/slider/features/states.ts +195 -0
- package/src/components/slider/features/structure.ts +141 -184
- package/src/components/slider/features/ui.ts +150 -201
- package/src/components/slider/index.ts +2 -11
- package/src/components/slider/slider.ts +9 -12
- package/src/components/slider/types.ts +39 -24
- package/src/components/switch/_styles.scss +0 -2
- package/src/components/tabs/_styles.scss +346 -154
- package/src/components/tabs/api.ts +178 -400
- package/src/components/tabs/config.ts +46 -52
- package/src/components/tabs/constants.ts +85 -8
- package/src/components/tabs/features.ts +403 -0
- package/src/components/tabs/index.ts +60 -3
- package/src/components/tabs/indicator.ts +285 -0
- package/src/components/tabs/responsive.ts +144 -0
- package/src/components/tabs/scroll-indicators.ts +149 -0
- package/src/components/tabs/state.ts +186 -0
- package/src/components/tabs/tab-api.ts +258 -0
- package/src/components/tabs/tab.ts +255 -0
- package/src/components/tabs/tabs.ts +50 -31
- package/src/components/tabs/types.ts +332 -128
- package/src/components/tabs/utils.ts +107 -0
- package/src/components/textfield/_styles.scss +0 -98
- package/src/components/textfield/config.ts +2 -3
- package/src/components/textfield/constants.ts +0 -14
- package/src/components/textfield/index.ts +2 -2
- package/src/components/textfield/textfield.ts +0 -2
- package/src/components/textfield/types.ts +1 -4
- package/src/components/timepicker/README.md +277 -0
- package/src/components/timepicker/_styles.scss +451 -0
- package/src/components/timepicker/api.ts +632 -0
- package/src/components/timepicker/clockdial.ts +482 -0
- package/src/components/timepicker/config.ts +130 -0
- package/src/components/timepicker/constants.ts +138 -0
- package/src/components/timepicker/index.ts +8 -0
- package/src/components/timepicker/render.ts +613 -0
- package/src/components/timepicker/timepicker.ts +117 -0
- package/src/components/timepicker/types.ts +336 -0
- package/src/components/timepicker/utils.ts +241 -0
- package/src/components/top-app-bar/_styles.scss +225 -0
- package/src/components/top-app-bar/config.ts +83 -0
- package/src/components/top-app-bar/index.ts +11 -0
- package/src/components/top-app-bar/top-app-bar.ts +316 -0
- package/src/components/top-app-bar/types.ts +140 -0
- package/src/core/build/_ripple.scss +6 -6
- package/src/core/build/ripple.ts +72 -95
- package/src/core/compose/component.ts +1 -1
- package/src/core/compose/features/badge.ts +79 -0
- package/src/core/compose/features/icon.ts +3 -1
- package/src/core/compose/features/index.ts +3 -1
- package/src/core/compose/features/ripple.ts +4 -1
- package/src/core/compose/features/textlabel.ts +26 -2
- package/src/core/dom/create.ts +5 -0
- package/src/index.ts +9 -0
- package/src/styles/abstract/_theme.scss +115 -3
- package/src/styles/themes/_autumn.scss +21 -0
- package/src/styles/themes/_base-theme.scss +61 -0
- package/src/styles/themes/_baseline.scss +58 -0
- package/src/styles/themes/_bluekhaki.scss +125 -0
- package/src/styles/themes/_brownbeige.scss +125 -0
- package/src/styles/themes/_browngreen.scss +125 -0
- package/src/styles/themes/_forest.scss +6 -0
- package/src/styles/themes/_greenbeige.scss +125 -0
- package/src/styles/themes/_material.scss +125 -0
- package/src/styles/themes/_ocean.scss +6 -0
- package/src/styles/themes/_sageivory.scss +125 -0
- package/src/styles/themes/_spring.scss +6 -0
- package/src/styles/themes/_summer.scss +5 -0
- package/src/styles/themes/_sunset.scss +5 -0
- package/src/styles/themes/_tealcaramel.scss +125 -0
- package/src/styles/themes/_winter.scss +6 -0
- package/src/components/card/actions.ts +0 -48
- package/src/components/card/header.ts +0 -88
- package/src/components/card/media.ts +0 -52
- package/src/components/navigation/features/items.js +0 -192
- package/src/components/slider/features/appearance.ts +0 -94
- package/src/components/slider/features/disabled.ts +0 -43
- package/src/components/slider/features/events.ts +0 -164
- package/src/components/slider/features/interactions.ts +0 -261
- package/src/components/slider/features/keyboard.ts +0 -112
- package/src/core/collection/adapters/mongodb.js +0 -232
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
// src/components/badge/config.ts
|
|
2
2
|
import {
|
|
3
3
|
createComponentConfig,
|
|
4
|
-
createElementConfig
|
|
5
|
-
BaseComponentConfig
|
|
4
|
+
createElementConfig
|
|
6
5
|
} from '../../core/config/component-config';
|
|
7
6
|
import { BadgeConfig } from './types';
|
|
8
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
BADGE_VARIANTS,
|
|
9
|
+
BADGE_COLORS,
|
|
10
|
+
BADGE_POSITIONS,
|
|
11
|
+
BADGE_MAX_CHARACTERS
|
|
12
|
+
} from './constants';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Default configuration for the Badge component
|
|
12
16
|
*/
|
|
13
17
|
export const defaultConfig: BadgeConfig = {
|
|
14
|
-
variant: BADGE_VARIANTS.
|
|
15
|
-
size: BADGE_SIZES.MEDIUM,
|
|
18
|
+
variant: BADGE_VARIANTS.LARGE,
|
|
16
19
|
color: BADGE_COLORS.ERROR,
|
|
17
20
|
position: BADGE_POSITIONS.TOP_RIGHT,
|
|
18
|
-
|
|
19
|
-
visible: true
|
|
20
|
-
standalone: false
|
|
21
|
+
label: '',
|
|
22
|
+
visible: true
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -37,14 +39,21 @@ export const getElementConfig = (config: BadgeConfig) => {
|
|
|
37
39
|
// Create the attributes object
|
|
38
40
|
const attrs: Record<string, any> = {};
|
|
39
41
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
+
// For large badges, set appropriate ARIA attributes
|
|
43
|
+
if (config.variant !== BADGE_VARIANTS.SMALL) {
|
|
44
|
+
attrs.role = 'status';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Format the label if needed
|
|
48
|
+
const formattedLabel = config.variant === BADGE_VARIANTS.SMALL
|
|
49
|
+
? ''
|
|
50
|
+
: formatBadgeLabel(config.label || '', config.max);
|
|
42
51
|
|
|
43
52
|
return createElementConfig(config, {
|
|
44
53
|
tag: 'span',
|
|
45
54
|
attrs,
|
|
46
55
|
className: config.class,
|
|
47
|
-
|
|
56
|
+
text: formattedLabel // Use the formatted label
|
|
48
57
|
});
|
|
49
58
|
};
|
|
50
59
|
|
|
@@ -65,4 +74,49 @@ export const getApiConfig = (comp) => ({
|
|
|
65
74
|
}
|
|
66
75
|
});
|
|
67
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Format a label
|
|
79
|
+
* - Max 4 characters including "+" for overflow
|
|
80
|
+
* - Add "+" for numeric values exceeding max
|
|
81
|
+
*
|
|
82
|
+
* @param {string|number} label - Original label
|
|
83
|
+
* @param {number} max - Maximum value before using "+"
|
|
84
|
+
* @returns {string} Formatted label
|
|
85
|
+
*/
|
|
86
|
+
export const formatBadgeLabel = (label: string | number, max?: number): string => {
|
|
87
|
+
// Handle empty or undefined labels
|
|
88
|
+
if (label === undefined || label === null || label === '') {
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let formattedLabel = String(label);
|
|
93
|
+
|
|
94
|
+
const numericLabel = Number(label);
|
|
95
|
+
|
|
96
|
+
// Apply max value formatting
|
|
97
|
+
if (max !== undefined && !isNaN(numericLabel) && numericLabel > max) {
|
|
98
|
+
formattedLabel = `${max}+`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Ensure label doesn't exceed max characters
|
|
102
|
+
if (formattedLabel.length > BADGE_MAX_CHARACTERS) {
|
|
103
|
+
// Try to preserve as much information as possible
|
|
104
|
+
// For large numbers, use abbreviated format with "+"
|
|
105
|
+
const numericValue = Number(label);
|
|
106
|
+
if (!isNaN(numericValue)) {
|
|
107
|
+
if (numericValue >= 1000) {
|
|
108
|
+
formattedLabel = '999+';
|
|
109
|
+
} else {
|
|
110
|
+
// For numbers under 1000 but still too long, truncate
|
|
111
|
+
formattedLabel = formattedLabel.substring(0, BADGE_MAX_CHARACTERS - 1) + '+';
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// For non-numeric values, simply truncate
|
|
115
|
+
formattedLabel = formattedLabel.substring(0, BADGE_MAX_CHARACTERS);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return formattedLabel;
|
|
120
|
+
};
|
|
121
|
+
|
|
68
122
|
export default defaultConfig;
|
|
@@ -1,30 +1,40 @@
|
|
|
1
1
|
// src/components/badge/constants.ts
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Badge variants
|
|
5
|
+
* - SMALL: Simple dot badge (6dp diameter)
|
|
6
|
+
* - LARGE: Numbered badge (16dp height)
|
|
7
|
+
*/
|
|
3
8
|
export const BADGE_VARIANTS = {
|
|
4
|
-
STANDARD: 'standard',
|
|
5
|
-
DOT: 'dot',
|
|
6
|
-
OUTLINED: 'outlined'
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const BADGE_SIZES = {
|
|
10
9
|
SMALL: 'small',
|
|
11
|
-
MEDIUM: 'medium',
|
|
12
10
|
LARGE: 'large'
|
|
13
|
-
}
|
|
11
|
+
} as const;
|
|
14
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Badge colors
|
|
15
|
+
* ERROR is the default
|
|
16
|
+
*/
|
|
15
17
|
export const BADGE_COLORS = {
|
|
18
|
+
ERROR: 'error', // Default
|
|
16
19
|
PRIMARY: 'primary',
|
|
17
20
|
SECONDARY: 'secondary',
|
|
18
21
|
TERTIARY: 'tertiary',
|
|
19
|
-
ERROR: 'error',
|
|
20
22
|
SUCCESS: 'success',
|
|
21
23
|
WARNING: 'warning',
|
|
22
24
|
INFO: 'info'
|
|
23
|
-
}
|
|
25
|
+
} as const;
|
|
24
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Badge positions relative to its container
|
|
29
|
+
*/
|
|
25
30
|
export const BADGE_POSITIONS = {
|
|
26
|
-
TOP_RIGHT: 'top-right',
|
|
31
|
+
TOP_RIGHT: 'top-right', // Default
|
|
27
32
|
TOP_LEFT: 'top-left',
|
|
28
33
|
BOTTOM_RIGHT: 'bottom-right',
|
|
29
34
|
BOTTOM_LEFT: 'bottom-left'
|
|
30
|
-
}
|
|
35
|
+
} as const;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Maximum character count for badge labels
|
|
39
|
+
*/
|
|
40
|
+
export const BADGE_MAX_CHARACTERS = 4;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// src/components/badge/features.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BADGE_VARIANTS,
|
|
4
|
+
BADGE_COLORS,
|
|
5
|
+
BADGE_POSITIONS
|
|
6
|
+
} from './constants';
|
|
3
7
|
import { BadgeConfig } from './types';
|
|
8
|
+
import { formatBadgeLabel } from './config';
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* Higher-order function that adds visibility control features to a component
|
|
@@ -64,15 +69,24 @@ export const withVisibility = () => component => {
|
|
|
64
69
|
*/
|
|
65
70
|
export const withVariant = (config: BadgeConfig) => component => {
|
|
66
71
|
// Get variant from config with fallback to default
|
|
67
|
-
const variant = config.variant || BADGE_VARIANTS.
|
|
68
|
-
|
|
69
|
-
// Apply variant class
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
const variant = config.variant || BADGE_VARIANTS.LARGE;
|
|
73
|
+
|
|
74
|
+
// Apply variant class
|
|
75
|
+
component.element.classList.add(`${component.getClass('badge')}--${variant}`);
|
|
76
|
+
|
|
77
|
+
// Small badges (dot variant) don't have text
|
|
78
|
+
if (variant === BADGE_VARIANTS.SMALL) {
|
|
79
|
+
component.element.textContent = '';
|
|
80
|
+
component.element.setAttribute('aria-hidden', 'true');
|
|
81
|
+
} else {
|
|
82
|
+
// Add accessibility for large badges
|
|
83
|
+
component.element.setAttribute('role', 'status');
|
|
72
84
|
|
|
73
|
-
//
|
|
74
|
-
if (
|
|
75
|
-
|
|
85
|
+
// Set the label if available and variant is large
|
|
86
|
+
if (config.label !== undefined && config.label !== '') {
|
|
87
|
+
// Format the label according to max value
|
|
88
|
+
const formattedLabel = formatBadgeLabel(config.label, config.max);
|
|
89
|
+
component.element.textContent = formattedLabel;
|
|
76
90
|
}
|
|
77
91
|
}
|
|
78
92
|
|
|
@@ -94,40 +108,22 @@ export const withColor = (config: BadgeConfig) => component => {
|
|
|
94
108
|
return component;
|
|
95
109
|
};
|
|
96
110
|
|
|
97
|
-
/**
|
|
98
|
-
* Higher-order function that adds size features to a badge component
|
|
99
|
-
* @param {BadgeConfig} config - Badge configuration
|
|
100
|
-
* @returns {Function} Component enhancer with size features
|
|
101
|
-
*/
|
|
102
|
-
export const withSize = (config: BadgeConfig) => component => {
|
|
103
|
-
// Get size from config with fallback to default
|
|
104
|
-
const size = config.size || BADGE_SIZES.MEDIUM;
|
|
105
|
-
|
|
106
|
-
// Apply size class if not medium (default)
|
|
107
|
-
if (size !== BADGE_SIZES.MEDIUM) {
|
|
108
|
-
component.element.classList.add(`${component.getClass('badge')}--${size}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return component;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
111
|
/**
|
|
115
112
|
* Higher-order function that adds positioning features to a badge component
|
|
116
113
|
* @param {BadgeConfig} config - Badge configuration
|
|
117
114
|
* @returns {Function} Component enhancer with positioning features
|
|
118
115
|
*/
|
|
119
116
|
export const withPosition = (config: BadgeConfig) => component => {
|
|
120
|
-
// Skip for standalone badges
|
|
121
|
-
if (config.standalone) {
|
|
122
|
-
return component;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
117
|
// Get position from config with fallback to default
|
|
126
118
|
const position = config.position || BADGE_POSITIONS.TOP_RIGHT;
|
|
127
119
|
|
|
128
|
-
// Apply position class
|
|
120
|
+
// Apply position class
|
|
129
121
|
component.element.classList.add(`${component.getClass('badge')}--${position}`);
|
|
130
|
-
|
|
122
|
+
|
|
123
|
+
// If there's a target, add positioned class
|
|
124
|
+
if (config.target) {
|
|
125
|
+
component.element.classList.add(`${component.getClass('badge')}--positioned`);
|
|
126
|
+
}
|
|
131
127
|
|
|
132
128
|
return component;
|
|
133
129
|
};
|
|
@@ -138,8 +134,8 @@ export const withPosition = (config: BadgeConfig) => component => {
|
|
|
138
134
|
* @returns {Function} Component enhancer with max value features
|
|
139
135
|
*/
|
|
140
136
|
export const withMax = (config: BadgeConfig) => component => {
|
|
141
|
-
// Skip if no max is defined
|
|
142
|
-
if (config.max === undefined) {
|
|
137
|
+
// Skip if no max is defined or for small badges
|
|
138
|
+
if (config.max === undefined || config.variant === BADGE_VARIANTS.SMALL) {
|
|
143
139
|
return component;
|
|
144
140
|
}
|
|
145
141
|
|
|
@@ -147,9 +143,14 @@ export const withMax = (config: BadgeConfig) => component => {
|
|
|
147
143
|
component.config.max = config.max;
|
|
148
144
|
|
|
149
145
|
// Apply max formatting if needed
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
component.element.
|
|
146
|
+
if (config.label !== undefined && config.label !== '') {
|
|
147
|
+
const formattedLabel = formatBadgeLabel(config.label, config.max);
|
|
148
|
+
component.element.textContent = formattedLabel;
|
|
149
|
+
|
|
150
|
+
// Add overflow class if label was truncated
|
|
151
|
+
if (typeof config.label === 'number' && config.label > config.max) {
|
|
152
|
+
component.element.classList.add(`${component.getClass('badge')}--overflow`);
|
|
153
|
+
}
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
return component;
|
|
@@ -161,8 +162,8 @@ export const withMax = (config: BadgeConfig) => component => {
|
|
|
161
162
|
* @returns {Function} Component enhancer with attachment features
|
|
162
163
|
*/
|
|
163
164
|
export const withAttachment = (config: BadgeConfig) => component => {
|
|
164
|
-
// Skip
|
|
165
|
-
if (
|
|
165
|
+
// Skip if no target is provided
|
|
166
|
+
if (!config.target) {
|
|
166
167
|
return component;
|
|
167
168
|
}
|
|
168
169
|
|
|
@@ -170,6 +171,9 @@ export const withAttachment = (config: BadgeConfig) => component => {
|
|
|
170
171
|
const wrapper = document.createElement('div');
|
|
171
172
|
wrapper.classList.add(component.getClass('badge-wrapper'));
|
|
172
173
|
|
|
174
|
+
// Make sure positioning context is correct
|
|
175
|
+
wrapper.style.position = 'relative';
|
|
176
|
+
|
|
173
177
|
// Replace the target with the wrapper
|
|
174
178
|
const parent = config.target.parentNode;
|
|
175
179
|
if (parent) {
|
|
@@ -1,43 +1,58 @@
|
|
|
1
1
|
// src/components/badge/types.ts
|
|
2
|
-
import { BADGE_VARIANTS,
|
|
2
|
+
import { BADGE_VARIANTS, BADGE_COLORS, BADGE_POSITIONS } from './constants';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Configuration interface for the Badge component
|
|
6
|
+
* Following Material Design 3 specifications
|
|
6
7
|
*/
|
|
7
8
|
export interface BadgeConfig {
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Badge variant (small dot or large numbered)
|
|
11
|
+
* Small badge (6dp) or Large badge (16dp height)
|
|
12
|
+
*/
|
|
13
|
+
variant?: keyof typeof BADGE_VARIANTS | (typeof BADGE_VARIANTS)[keyof typeof BADGE_VARIANTS];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Badge color (error is default)
|
|
17
|
+
*/
|
|
18
|
+
color?: keyof typeof BADGE_COLORS | (typeof BADGE_COLORS)[keyof typeof BADGE_COLORS];
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Badge position relative to its container
|
|
22
|
+
*/
|
|
23
|
+
position?: keyof typeof BADGE_POSITIONS | (typeof BADGE_POSITIONS)[keyof typeof BADGE_POSITIONS];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Text label inside the badge (for large badges)
|
|
27
|
+
* Up to 4 characters, with "+" for overflow
|
|
28
|
+
*/
|
|
29
|
+
label?: string | number;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Maximum value to display (shows "{max}+" if label exceeds max)
|
|
33
|
+
* Usually 999+ for large numbers
|
|
34
|
+
*/
|
|
24
35
|
max?: number;
|
|
25
36
|
|
|
26
37
|
/** Whether the badge should be visible */
|
|
27
38
|
visible?: boolean;
|
|
28
39
|
|
|
29
|
-
/** Whether the badge should be standalone (not attached to another element) */
|
|
30
|
-
standalone?: boolean;
|
|
31
|
-
|
|
32
40
|
/** Target element to which badge will be attached */
|
|
33
41
|
target?: HTMLElement;
|
|
34
42
|
|
|
35
43
|
/** Additional CSS classes */
|
|
36
44
|
class?: string;
|
|
45
|
+
|
|
46
|
+
/** CSS class prefix */
|
|
47
|
+
prefix?: string;
|
|
48
|
+
|
|
49
|
+
/** Component name */
|
|
50
|
+
componentName?: string;
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
/**
|
|
40
54
|
* Badge component interface
|
|
55
|
+
* Following Material Design 3 specifications
|
|
41
56
|
*/
|
|
42
57
|
export interface BadgeComponent {
|
|
43
58
|
/** Badge element */
|
|
@@ -46,11 +61,11 @@ export interface BadgeComponent {
|
|
|
46
61
|
/** Badge wrapper element (if badge is attached to target) */
|
|
47
62
|
wrapper?: HTMLElement;
|
|
48
63
|
|
|
49
|
-
/** Sets badge text
|
|
50
|
-
|
|
64
|
+
/** Sets badge text label */
|
|
65
|
+
setLabel: (label: string | number) => BadgeComponent;
|
|
51
66
|
|
|
52
|
-
/** Gets badge text
|
|
53
|
-
|
|
67
|
+
/** Gets badge text label */
|
|
68
|
+
getLabel: () => string;
|
|
54
69
|
|
|
55
70
|
/** Shows the badge */
|
|
56
71
|
show: () => BadgeComponent;
|
|
@@ -68,16 +83,13 @@ export interface BadgeComponent {
|
|
|
68
83
|
setMax: (max: number) => BadgeComponent;
|
|
69
84
|
|
|
70
85
|
/** Sets badge color */
|
|
71
|
-
setColor: (color: keyof typeof BADGE_COLORS | BADGE_COLORS) => BadgeComponent;
|
|
86
|
+
setColor: (color: keyof typeof BADGE_COLORS | (typeof BADGE_COLORS)[keyof typeof BADGE_COLORS]) => BadgeComponent;
|
|
72
87
|
|
|
73
88
|
/** Sets badge variant */
|
|
74
|
-
setVariant: (variant: keyof typeof BADGE_VARIANTS | BADGE_VARIANTS) => BadgeComponent;
|
|
75
|
-
|
|
76
|
-
/** Sets badge size */
|
|
77
|
-
setSize: (size: keyof typeof BADGE_SIZES | BADGE_SIZES) => BadgeComponent;
|
|
89
|
+
setVariant: (variant: keyof typeof BADGE_VARIANTS | (typeof BADGE_VARIANTS)[keyof typeof BADGE_VARIANTS]) => BadgeComponent;
|
|
78
90
|
|
|
79
91
|
/** Sets badge position */
|
|
80
|
-
setPosition: (position: keyof typeof BADGE_POSITIONS | BADGE_POSITIONS) => BadgeComponent;
|
|
92
|
+
setPosition: (position: keyof typeof BADGE_POSITIONS | (typeof BADGE_POSITIONS)[keyof typeof BADGE_POSITIONS]) => BadgeComponent;
|
|
81
93
|
|
|
82
94
|
/** Attaches badge to a target element */
|
|
83
95
|
attachTo: (target: HTMLElement) => BadgeComponent;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/components/bottom-app-bar/styles.scss
|
|
2
|
+
@use 'sass:map';
|
|
3
|
+
@use '../../styles/abstract/base' as base;
|
|
4
|
+
@use '../../styles/abstract/variables' as v;
|
|
5
|
+
@use '../../styles/abstract/functions' as f;
|
|
6
|
+
@use '../../styles/abstract/mixins' as m;
|
|
7
|
+
@use '../../styles/abstract/theme' as t;
|
|
8
|
+
|
|
9
|
+
$component: '#{base.$prefix}-bottom-app-bar';
|
|
10
|
+
|
|
11
|
+
.#{$component} {
|
|
12
|
+
// Core Properties
|
|
13
|
+
position: absolute;
|
|
14
|
+
bottom: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
right: 0;
|
|
17
|
+
z-index: f.get-z-index('fixed');
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
height: 80px; // Default height as per specs
|
|
22
|
+
padding: 12px 16px 12px 4px; // top/bottom 12px, right 16px, left 4px
|
|
23
|
+
background-color: t.color('surface-container');
|
|
24
|
+
|
|
25
|
+
// Apply material elevation
|
|
26
|
+
@include m.elevation(2);
|
|
27
|
+
|
|
28
|
+
// Apply border radius at the top
|
|
29
|
+
border-top-left-radius: t.shape('medium');
|
|
30
|
+
border-top-right-radius: t.shape('medium');
|
|
31
|
+
|
|
32
|
+
// Add transition for smooth animations
|
|
33
|
+
transition: transform 0.3s ease-in-out;
|
|
34
|
+
|
|
35
|
+
// Actions container on the left side
|
|
36
|
+
&-actions {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
gap: 4px; // Small gap between action buttons
|
|
40
|
+
height: 100%;
|
|
41
|
+
|
|
42
|
+
// Icon buttons should have consistent sizing
|
|
43
|
+
> * {
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// FAB container on the right side
|
|
49
|
+
&-fab-container {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
margin-left: auto;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Adjustment for when FAB is present - use the specified height
|
|
57
|
+
&--with-fab {
|
|
58
|
+
height: 72px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Adjustment for when FAB is centered
|
|
62
|
+
&--fab-center {
|
|
63
|
+
.#{$component}-fab-container {
|
|
64
|
+
position: absolute;
|
|
65
|
+
left: 50%;
|
|
66
|
+
transform: translateX(-50%);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Hidden state - moved off-screen
|
|
71
|
+
&--hidden {
|
|
72
|
+
transform: translateY(100%);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// RTL Support
|
|
76
|
+
[dir="rtl"] & {
|
|
77
|
+
padding: 12px 4px 12px 16px;
|
|
78
|
+
|
|
79
|
+
&-actions {
|
|
80
|
+
flex-direction: row-reverse;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&-fab-container {
|
|
84
|
+
margin-right: auto;
|
|
85
|
+
margin-left: initial;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// // Media query to hide on large screens
|
|
90
|
+
// @media (min-width: map.get(v.$breakpoints, 'lg')) {
|
|
91
|
+
// display: none;
|
|
92
|
+
// }
|
|
93
|
+
|
|
94
|
+
// Reduced motion support
|
|
95
|
+
@include m.reduced-motion {
|
|
96
|
+
transition-duration: 0.01ms;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// High contrast mode support
|
|
100
|
+
@include m.high-contrast {
|
|
101
|
+
border-top: 1px solid currentColor;
|
|
102
|
+
}
|
|
103
|
+
}
|