@12-apps/ui 1.23.0 → 2.0.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/package.json +3 -1
- package/src/components/data-display/Alert/Alert.types.ts +2 -1
- package/src/components/data-display/Avatar/Avatar.types.ts +10 -2
- package/src/components/data-display/Badge/Badge.types.ts +3 -2
- package/src/components/data-display/Carousel/Carousel.parts.tsx +12 -10
- package/src/components/data-display/Carousel/Carousel.styles.ts +4 -3
- package/src/components/data-display/Carousel/Carousel.tsx +2 -1
- package/src/components/data-display/Carousel/Carousel.types.ts +7 -6
- package/src/components/data-display/Chart/Chart.tsx +2 -1
- package/src/components/data-display/Chart/Chart.types.ts +3 -2
- package/src/components/data-display/Chart/ChartSpec.types.ts +6 -7
- package/src/components/data-display/Chart/SpecChart.tsx +2 -1
- package/src/components/data-display/Chart/chart-internals.ts +3 -2
- package/src/components/data-display/Chart/chart-spec.ts +11 -1
- package/src/components/data-display/Chip/Chip.tsx +23 -3
- package/src/components/data-display/Chip/Chip.types.ts +37 -3
- package/src/components/data-display/Chip/chip.md +7 -3
- package/src/components/data-display/Chip/index.ts +1 -1
- package/src/components/data-display/DataViews/DataViewsGrid.tsx +10 -0
- package/src/components/data-display/DataViews/DataViewsTableBase.tsx +3 -0
- package/src/components/data-display/DataViews/data-views-grid-bodies.tsx +113 -62
- package/src/components/data-display/DataViews/data-views-grid-parts.tsx +4 -0
- package/src/components/data-display/DataViews/data-views-overflow.ts +23 -51
- package/src/components/data-display/DataViews/index.ts +4 -0
- package/src/components/data-display/DataViews/list-card-rails.tsx +29 -0
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.tsx +8 -5
- package/src/components/data-display/DateTimeDisplay/DateTimeDisplay.types.ts +2 -1
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.types.ts +2 -1
- package/src/components/data-display/LoadingState/LoadingState.types.ts +2 -1
- package/src/components/data-display/Progress/Progress.types.ts +3 -2
- package/src/components/data-display/Sheet/Sheet.body.tsx +2 -1
- package/src/components/data-display/Sheet/Sheet.styles.ts +3 -2
- package/src/components/data-display/Sheet/Sheet.types.ts +7 -2
- package/src/components/data-display/Stepper/Stepper.types.ts +2 -1
- package/src/components/data-display/Table/Table.styles.ts +1 -1
- package/src/components/data-display/Table/Table.types.ts +3 -1
- package/src/components/data-display/Tooltip/Tooltip.types.ts +2 -1
- package/src/components/feedback/Dialog/Dialog.types.ts +2 -1
- package/src/components/feedback/Modal/Modal.types.ts +2 -1
- package/src/components/form/Button/Button.types.ts +3 -2
- package/src/components/form/Command/Command.styles.ts +8 -7
- package/src/components/form/Command/Command.types.ts +3 -2
- package/src/components/form/CreatableSelect/CreatableSelect.types.ts +2 -1
- package/src/components/form/Input/Input.types.ts +2 -1
- package/src/components/form/InputOTP/InputOTP.types.ts +3 -2
- package/src/components/form/Label/Label.styles.ts +8 -5
- package/src/components/form/Label/Label.tsx +1 -1
- package/src/components/form/Label/Label.types.ts +3 -2
- package/src/components/form/Menubar/Menubar.styles.ts +10 -8
- package/src/components/form/Menubar/Menubar.tsx +2 -1
- package/src/components/form/Menubar/Menubar.types.ts +7 -6
- package/src/components/form/RadioGroup/RadioGroup.types.ts +3 -2
- package/src/components/form/Select/Select.tsx +13 -1
- package/src/components/form/Select/Select.types.ts +5 -2
- package/src/components/form/Slider/Slider.types.ts +3 -2
- package/src/components/form/Switch/Switch.types.ts +3 -2
- package/src/components/form/Textarea/Textarea.types.ts +3 -2
- package/src/components/form/Toggle/Toggle.types.ts +3 -2
- package/src/components/form/ToggleGroup/ToggleGroup.types.ts +3 -2
- package/src/components/layout/Separator/Separator.types.ts +2 -1
- package/src/components/layout/Spacer/Spacer.types.ts +2 -1
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.types.ts +7 -2
- package/src/components/navigation/ContextMenu/ContextMenu.types.ts +3 -2
- package/src/components/navigation/DropdownMenu/DropdownMenu.tsx +1 -0
- package/src/components/navigation/DropdownMenu/DropdownMenu.types.ts +12 -2
- package/src/components/navigation/NavigationMenu/NavigationMenu.types.ts +7 -2
- package/src/components/navigation/Pagination/Pagination.tsx +3 -1
- package/src/components/navigation/Pagination/Pagination.types.ts +5 -3
- package/src/components/navigation/Tabs/Tabs.types.ts +3 -2
- package/src/components/typography/Blockquote/Blockquote.types.ts +2 -1
- package/src/components/typography/Code/Code.types.ts +2 -1
- package/src/components/typography/Heading/Heading.types.ts +2 -1
- package/src/components/typography/Paragraph/Paragraph.types.ts +3 -2
- package/src/components/typography/Text/Text.types.ts +3 -2
- package/src/components/utility/AnimatedIcon/AnimatedIcon.types.ts +2 -1
- package/src/components/utility/Overflow/index.ts +6 -0
- package/src/components/utility/Overflow/overflow.ts +125 -0
- package/src/components/utility/WorkflowStep/WorkflowStep.types.ts +3 -2
- package/src/components/utility/index.ts +1 -0
- package/src/tokens/scales.ts +153 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@12-apps/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"packageManager": "pnpm@9.0.0",
|
|
6
6
|
"type": "module",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"./social-login-button": "./src/social-login-button/index.ts",
|
|
21
21
|
"./user-avatar": "./src/user-avatar/index.ts",
|
|
22
22
|
"./utils": "./src/utils/index.ts",
|
|
23
|
+
"./tokens": "./src/tokens/scales.ts",
|
|
23
24
|
"./mui/Box": "./src/mui/Box.ts",
|
|
24
25
|
"./mui/Link": "./src/mui/Link.ts",
|
|
25
26
|
"./mui/Stack": "./src/mui/Stack.ts",
|
|
@@ -134,6 +135,7 @@
|
|
|
134
135
|
"./utility/AspectRatio": "./src/components/utility/AspectRatio/index.ts",
|
|
135
136
|
"./utility/InfiniteScroll": "./src/components/utility/InfiniteScroll/index.ts",
|
|
136
137
|
"./utility/InstallPrompt": "./src/components/utility/InstallPrompt/index.ts",
|
|
138
|
+
"./utility/Overflow": "./src/components/utility/Overflow/index.ts",
|
|
137
139
|
"./utility/Portal": "./src/components/utility/Portal/index.ts",
|
|
138
140
|
"./utility/Transition": "./src/components/utility/Transition/index.ts",
|
|
139
141
|
"./utility/VirtualList": "./src/components/utility/VirtualList/index.ts",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue } from '../../../tokens/scales';
|
|
1
2
|
import type { AlertProps as MuiAlertProps } from '@mui/material';
|
|
2
3
|
import type React from 'react';
|
|
3
4
|
|
|
@@ -10,7 +11,7 @@ export interface AlertProps extends Omit<MuiAlertProps, 'variant' | 'color' | 'r
|
|
|
10
11
|
/**
|
|
11
12
|
* The color of the alert (when not using variant-specific colors)
|
|
12
13
|
*/
|
|
13
|
-
color?:
|
|
14
|
+
color?: Exclude<ColorValue, 'info'>;
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Whether the alert should have a glow effect
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { AvatarProps as MuiAvatarProps } from '@mui/material';
|
|
2
3
|
import type React from 'react';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The house scale, EXTENDED by one stop rather than replacing it.
|
|
7
|
+
*
|
|
8
|
+
* `xxl` is real — an avatar is the one component with a portrait size above the
|
|
9
|
+
* scale's top — so it is added to `SizeValue` instead of the union being
|
|
10
|
+
* rewritten by hand. Spelling all six out again is how the copy drifts.
|
|
11
|
+
*/
|
|
12
|
+
export type AvatarSize = SizeValue | 'xxl';
|
|
5
13
|
export type AvatarVariant = 'circle' | 'square' | 'rounded' | 'status';
|
|
6
14
|
export type AvatarStatus = 'online' | 'offline' | 'away' | 'busy';
|
|
7
15
|
|
|
@@ -49,7 +57,7 @@ export interface AvatarProps extends Omit<MuiAvatarProps, 'variant'> {
|
|
|
49
57
|
/**
|
|
50
58
|
* Color of the avatar background when no image is provided
|
|
51
59
|
*/
|
|
52
|
-
color?:
|
|
60
|
+
color?: Exclude<ColorValue, 'info'>;
|
|
53
61
|
|
|
54
62
|
/**
|
|
55
63
|
* Whether the avatar is in a loading state
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { BadgeProps as MuiBadgeProps } from '@mui/material';
|
|
2
3
|
import type React from 'react';
|
|
3
4
|
|
|
@@ -13,7 +14,7 @@ export type BadgeVariant =
|
|
|
13
14
|
| 'success'
|
|
14
15
|
| 'warning';
|
|
15
16
|
|
|
16
|
-
export type BadgeSize = 'xs' | 'sm' | 'md' | 'lg'
|
|
17
|
+
export type BadgeSize = Extract<SizeValue, 'xs' | 'sm' | 'md' | 'lg'>;
|
|
17
18
|
|
|
18
19
|
export interface BadgeProps extends Omit<MuiBadgeProps, 'variant' | 'color' | 'content'> {
|
|
19
20
|
/**
|
|
@@ -29,7 +30,7 @@ export interface BadgeProps extends Omit<MuiBadgeProps, 'variant' | 'color' | 'c
|
|
|
29
30
|
/**
|
|
30
31
|
* The color of the badge
|
|
31
32
|
*/
|
|
32
|
-
color?:
|
|
33
|
+
color?: ColorValue;
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Whether the badge should have a glow effect
|
|
@@ -7,6 +7,8 @@ import React from 'react';
|
|
|
7
7
|
|
|
8
8
|
import { withDefaults } from '../../../utils/withDefaults';
|
|
9
9
|
|
|
10
|
+
import { accentFor, muiSize } from '../../../tokens/scales';
|
|
11
|
+
|
|
10
12
|
import type {
|
|
11
13
|
CarouselArrowsProps,
|
|
12
14
|
CarouselIndicatorsProps,
|
|
@@ -69,8 +71,8 @@ const LineIndicator: React.FC<IndicatorProps> = ({ index, isActive, color, onSel
|
|
|
69
71
|
width: isActive ? 30 : 20,
|
|
70
72
|
height: 3,
|
|
71
73
|
backgroundColor: isActive
|
|
72
|
-
? theme
|
|
73
|
-
: alpha(theme
|
|
74
|
+
? accentFor(theme, color).main
|
|
75
|
+
: alpha(accentFor(theme, color).main, 0.3),
|
|
74
76
|
borderRadius: 1.5,
|
|
75
77
|
transition: theme.transitions.create(['width', 'background-color']),
|
|
76
78
|
cursor: 'pointer',
|
|
@@ -96,9 +98,9 @@ const NumberIndicator: React.FC<IndicatorProps> = ({ index, isActive, color, onS
|
|
|
96
98
|
alignItems: 'center',
|
|
97
99
|
justifyContent: 'center',
|
|
98
100
|
borderRadius: '50%',
|
|
99
|
-
backgroundColor: isActive ? theme
|
|
100
|
-
color: isActive ? theme
|
|
101
|
-
border: `1px solid ${theme
|
|
101
|
+
backgroundColor: isActive ? accentFor(theme, color).main : 'transparent',
|
|
102
|
+
color: isActive ? accentFor(theme, color).contrastText : accentFor(theme, color).main,
|
|
103
|
+
border: `1px solid ${accentFor(theme, color).main}`,
|
|
102
104
|
fontSize: '0.75rem',
|
|
103
105
|
fontWeight: isActive ? 'bold' : 'normal',
|
|
104
106
|
cursor: 'pointer',
|
|
@@ -122,7 +124,7 @@ const DotIndicator: React.FC<IndicatorProps> = ({ index, isActive, color, onSele
|
|
|
122
124
|
onClick={onSelect}
|
|
123
125
|
sx={{
|
|
124
126
|
p: 0.5,
|
|
125
|
-
color: isActive ? theme
|
|
127
|
+
color: isActive ? accentFor(theme, color).main : alpha(accentFor(theme, color).main, 0.3),
|
|
126
128
|
transform: isActive ? 'scale(1.2)' : 'scale(1)',
|
|
127
129
|
transition: theme.transitions.create(['transform', 'color']),
|
|
128
130
|
}}
|
|
@@ -185,7 +187,7 @@ const ARROWS_DEFAULTS = {
|
|
|
185
187
|
disablePrev: false,
|
|
186
188
|
disableNext: false,
|
|
187
189
|
color: 'primary',
|
|
188
|
-
size: '
|
|
190
|
+
size: 'md',
|
|
189
191
|
} satisfies Partial<CarouselArrowsProps>;
|
|
190
192
|
|
|
191
193
|
/**
|
|
@@ -198,7 +200,7 @@ const arrowSx = (theme: Theme, color: Color, isOverlay: boolean): CSSObject => (
|
|
|
198
200
|
transform: 'translateY(-50%)',
|
|
199
201
|
zIndex: 3,
|
|
200
202
|
backgroundColor: alpha(theme.palette.background.paper, 0.8),
|
|
201
|
-
color: theme
|
|
203
|
+
color: accentFor(theme, color).main,
|
|
202
204
|
'&:disabled': { opacity: 0.3 },
|
|
203
205
|
...(isOverlay
|
|
204
206
|
? {
|
|
@@ -223,7 +225,7 @@ export const CarouselArrows: React.FC<CarouselArrowsProps> = (props) => {
|
|
|
223
225
|
<IconButton
|
|
224
226
|
onClick={onPrev}
|
|
225
227
|
disabled={disabled || disablePrev}
|
|
226
|
-
size={size}
|
|
228
|
+
size={muiSize(size)}
|
|
227
229
|
className={className}
|
|
228
230
|
aria-label="Previous slide"
|
|
229
231
|
data-testid="carousel-prev-button"
|
|
@@ -236,7 +238,7 @@ export const CarouselArrows: React.FC<CarouselArrowsProps> = (props) => {
|
|
|
236
238
|
onClick={onNext}
|
|
237
239
|
disabled={disabled || disableNext}
|
|
238
240
|
aria-label="Next slide"
|
|
239
|
-
size={size}
|
|
241
|
+
size={muiSize(size)}
|
|
240
242
|
className={className}
|
|
241
243
|
data-testid="carousel-next-button"
|
|
242
244
|
sx={{ ...sx, right: offset, ...style }}
|
|
@@ -2,6 +2,7 @@ import { alpha } from '@mui/material';
|
|
|
2
2
|
import type { CSSObject, Theme } from '@mui/material';
|
|
3
3
|
|
|
4
4
|
import type { CarouselProps } from './Carousel.types';
|
|
5
|
+
import { accentFor } from '../../../tokens/scales';
|
|
5
6
|
|
|
6
7
|
type Variant = NonNullable<CarouselProps['variant']>;
|
|
7
8
|
type Size = NonNullable<CarouselProps['size']>;
|
|
@@ -39,12 +40,12 @@ const SURFACES: Record<Variant, (input: ContainerStyleInput) => CSSObject> = {
|
|
|
39
40
|
glass: ({ theme, color, glass }) => ({
|
|
40
41
|
backgroundColor: alpha(theme.palette.background.paper, glass ? 0.1 : 0.9),
|
|
41
42
|
backdropFilter: 'blur(20px)',
|
|
42
|
-
border: `1px solid ${alpha(theme
|
|
43
|
+
border: `1px solid ${alpha(accentFor(theme, color).main, 0.2)}`,
|
|
43
44
|
}),
|
|
44
45
|
|
|
45
46
|
gradient: ({ theme, color, gradient }) => ({
|
|
46
47
|
background: gradient
|
|
47
|
-
? `linear-gradient(135deg, ${alpha(theme
|
|
48
|
+
? `linear-gradient(135deg, ${alpha(accentFor(theme, color).light, 0.1)}, ${alpha(accentFor(theme, color).dark, 0.1)})`
|
|
48
49
|
: 'transparent',
|
|
49
50
|
}),
|
|
50
51
|
|
|
@@ -59,7 +60,7 @@ const SURFACES: Record<Variant, (input: ContainerStyleInput) => CSSObject> = {
|
|
|
59
60
|
|
|
60
61
|
export const containerStyles = (input: ContainerStyleInput): CSSObject => {
|
|
61
62
|
const { theme, variant, size, color, height, width, glow, pulse } = input;
|
|
62
|
-
const accent = theme
|
|
63
|
+
const accent = accentFor(theme, color).main;
|
|
63
64
|
|
|
64
65
|
return {
|
|
65
66
|
position: 'relative' as const,
|
|
@@ -8,6 +8,7 @@ import { CarouselChrome } from './Carousel.chrome';
|
|
|
8
8
|
import { CarouselTrack } from './Carousel.slide';
|
|
9
9
|
import { containerStyles } from './Carousel.styles';
|
|
10
10
|
import type { CarouselItem, CarouselProps } from './Carousel.types';
|
|
11
|
+
import { muiColor } from '../../../tokens/scales';
|
|
11
12
|
|
|
12
13
|
export { CarouselArrows, CarouselIndicators, CarouselThumbnails } from './Carousel.parts';
|
|
13
14
|
|
|
@@ -80,7 +81,7 @@ export const Carousel: React.FC<CarouselProps> = (props) => {
|
|
|
80
81
|
if (loading) {
|
|
81
82
|
return (
|
|
82
83
|
<Box sx={{ ...frameSx, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
|
83
|
-
<CircularProgress color={color} />
|
|
84
|
+
<CircularProgress color={muiColor(color, 'inherit')} />
|
|
84
85
|
</Box>
|
|
85
86
|
);
|
|
86
87
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { CSSProperties, ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
export interface CarouselItem {
|
|
@@ -12,8 +13,8 @@ export interface CarouselItem {
|
|
|
12
13
|
export interface CarouselProps {
|
|
13
14
|
items: CarouselItem[];
|
|
14
15
|
variant?: 'default' | 'glass' | 'gradient' | 'elevated' | 'minimal' | 'cards';
|
|
15
|
-
size?:
|
|
16
|
-
color?:
|
|
16
|
+
size?: SizeValue;
|
|
17
|
+
color?: Exclude<ColorValue, 'neutral'>;
|
|
17
18
|
autoPlay?: boolean;
|
|
18
19
|
autoPlayInterval?: number;
|
|
19
20
|
loop?: boolean;
|
|
@@ -50,7 +51,7 @@ export interface CarouselIndicatorsProps {
|
|
|
50
51
|
activeIndex: number;
|
|
51
52
|
onSelect: (index: number) => void;
|
|
52
53
|
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
53
|
-
color?:
|
|
54
|
+
color?: Exclude<ColorValue, 'neutral'>;
|
|
54
55
|
variant?: 'dots' | 'lines' | 'numbers';
|
|
55
56
|
className?: string;
|
|
56
57
|
style?: CSSProperties;
|
|
@@ -63,8 +64,8 @@ export interface CarouselArrowsProps {
|
|
|
63
64
|
disabled?: boolean;
|
|
64
65
|
disablePrev?: boolean;
|
|
65
66
|
disableNext?: boolean;
|
|
66
|
-
color?:
|
|
67
|
-
size?: '
|
|
67
|
+
color?: Exclude<ColorValue, 'neutral'>;
|
|
68
|
+
size?: Extract<SizeValue, 'sm' | 'md' | 'lg'>;
|
|
68
69
|
className?: string;
|
|
69
70
|
style?: CSSProperties;
|
|
70
71
|
}
|
|
@@ -73,7 +74,7 @@ export interface CarouselThumbnailsProps {
|
|
|
73
74
|
items: CarouselItem[];
|
|
74
75
|
activeIndex: number;
|
|
75
76
|
onSelect: (index: number) => void;
|
|
76
|
-
size?:
|
|
77
|
+
size?: SizeValue;
|
|
77
78
|
className?: string;
|
|
78
79
|
style?: CSSProperties;
|
|
79
80
|
}
|
|
@@ -5,6 +5,7 @@ import type { ChartProps } from './Chart.types';
|
|
|
5
5
|
import { ChartContainer } from './ChartComposables';
|
|
6
6
|
import { getSizeStyles, getVariantStyles } from './chart-internals';
|
|
7
7
|
import { renderChartByType } from './chart-renderers';
|
|
8
|
+
import { muiColor } from '../../../tokens/scales';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Prop-driven Recharts wrapper (line/bar/area/pie/radar/scatter/composed)
|
|
@@ -70,7 +71,7 @@ export const Chart: React.FC<ChartProps> = (props) => {
|
|
|
70
71
|
data-testid={`${dataTestId}-loading`}
|
|
71
72
|
sx={{ ...styles, ...sizeStyles, display: 'flex', justifyContent: 'center', alignItems: 'center' }}
|
|
72
73
|
>
|
|
73
|
-
<CircularProgress color={props.color ?? 'primary'} data-testid={`${dataTestId}-loading-spinner`} />
|
|
74
|
+
<CircularProgress color={muiColor(props.color ?? 'primary', 'inherit')} data-testid={`${dataTestId}-loading-spinner`} />
|
|
74
75
|
</Paper>
|
|
75
76
|
);
|
|
76
77
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { CSSProperties } from 'react';
|
|
2
3
|
|
|
3
4
|
export type ChartType = 'line' | 'bar' | 'area' | 'pie' | 'radar' | 'scatter' | 'composed';
|
|
@@ -26,8 +27,8 @@ export interface ChartProps {
|
|
|
26
27
|
series?: ChartSeries[];
|
|
27
28
|
type?: ChartType;
|
|
28
29
|
variant?: 'default' | 'glass' | 'gradient' | 'elevated' | 'minimal' | 'neon';
|
|
29
|
-
size?:
|
|
30
|
-
color?:
|
|
30
|
+
size?: SizeValue;
|
|
31
|
+
color?: Exclude<ColorValue, 'neutral'>;
|
|
31
32
|
height?: number;
|
|
32
33
|
width?: number | string;
|
|
33
34
|
glow?: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorValue } from '../../../tokens/scales';
|
|
1
2
|
/**
|
|
2
3
|
* JSON-serializable chart specification — the declarative surface of the raw
|
|
3
4
|
* chart library. A `ChartSpec` plus plain data rows fully describes a rendered
|
|
@@ -13,13 +14,11 @@ export type ChartSpecType = 'line' | 'bar' | 'area' | 'pie' | 'donut';
|
|
|
13
14
|
* Semantic color token resolved against the MUI palette at render time.
|
|
14
15
|
* Specs must not carry raw color values.
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| 'error'
|
|
22
|
-
| 'info';
|
|
17
|
+
/**
|
|
18
|
+
* The house vocabulary minus `neutral`: a data series is always an accent, and
|
|
19
|
+
* an unaccented series would be indistinguishable from the grid it sits on.
|
|
20
|
+
*/
|
|
21
|
+
export type ChartSemanticColor = Exclude<ColorValue, 'neutral'>;
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* Number formatting applied to tooltip values and the y axis.
|
|
@@ -5,6 +5,7 @@ import { Chart } from './Chart';
|
|
|
5
5
|
import type { ChartDataPoint } from './Chart.types';
|
|
6
6
|
import type { ChartSemanticColor, ChartSpec } from './ChartSpec.types';
|
|
7
7
|
import { CHART_SEMANTIC_COLORS, specToChartProps } from './chart-spec';
|
|
8
|
+
import { accentFor } from '../../../tokens/scales';
|
|
8
9
|
|
|
9
10
|
export interface SpecChartProps {
|
|
10
11
|
/** Validated spec — parse untrusted JSON with `parseChartSpec` first. */
|
|
@@ -36,7 +37,7 @@ export const SpecChart: React.FC<SpecChartProps> = ({
|
|
|
36
37
|
const scheme: readonly ChartSemanticColor[] =
|
|
37
38
|
spec.colorScheme && spec.colorScheme.length > 0 ? spec.colorScheme : CHART_SEMANTIC_COLORS;
|
|
38
39
|
const resolveColor = (token: ChartSemanticColor | undefined, index: number): string =>
|
|
39
|
-
theme
|
|
40
|
+
accentFor(theme, token ?? scheme[index % scheme.length] ?? 'primary').main;
|
|
40
41
|
return specToChartProps(spec, data, { resolveColor });
|
|
41
42
|
}, [spec, data, theme]);
|
|
42
43
|
|
|
@@ -2,6 +2,7 @@ import { alpha, type Theme } from '@mui/material';
|
|
|
2
2
|
import type { CSSProperties } from 'react';
|
|
3
3
|
|
|
4
4
|
import type { ChartProps, ChartSeries } from './Chart.types';
|
|
5
|
+
import { accentFor} from '../../../tokens/scales';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Non-JSX internals of the prop-driven Chart: size/variant styling, palette
|
|
@@ -65,7 +66,7 @@ interface VariantOptions {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
function effectStyles(theme: Theme, options: VariantOptions): SxStyles {
|
|
68
|
-
const accent = theme
|
|
69
|
+
const accent = accentFor(theme, options.color).main;
|
|
69
70
|
const glow = options.glow ? { boxShadow: `0 0 30px ${alpha(accent, 0.4)}` } : {};
|
|
70
71
|
const pulse = options.pulse
|
|
71
72
|
? {
|
|
@@ -91,7 +92,7 @@ function variantSurface(theme: Theme, options: VariantOptions): SxStyles {
|
|
|
91
92
|
case 'gradient':
|
|
92
93
|
return {
|
|
93
94
|
background: options.gradient
|
|
94
|
-
? `linear-gradient(135deg, ${alpha(theme
|
|
95
|
+
? `linear-gradient(135deg, ${alpha(accentFor(theme, options.color).light, 0.05)}, ${alpha(accentFor(theme, options.color).dark, 0.05)})`
|
|
95
96
|
: theme.palette.background.paper,
|
|
96
97
|
};
|
|
97
98
|
case 'elevated':
|
|
@@ -7,12 +7,22 @@ import {
|
|
|
7
7
|
type ChartSpecRenderContext,
|
|
8
8
|
} from './chart-spec-registry';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* BREAKING FOR STORED SPECS, not just for types.
|
|
12
|
+
*
|
|
13
|
+
* A chart spec is DATA — it is authored as JSON and can be persisted — and this
|
|
14
|
+
* list is validated at runtime, so a saved spec carrying `"error"` now throws
|
|
15
|
+
* `ChartSpecError` instead of silently drawing. That is the right failure (the
|
|
16
|
+
* alternative is a series quietly losing its colour), but unlike the rest of
|
|
17
|
+
* this migration a type-check will not find the affected specs: anything stored
|
|
18
|
+
* outside the repo has to be rewritten `error` → `danger`.
|
|
19
|
+
*/
|
|
10
20
|
export const CHART_SEMANTIC_COLORS: readonly ChartSemanticColor[] = [
|
|
11
21
|
'primary',
|
|
12
22
|
'secondary',
|
|
13
23
|
'success',
|
|
14
24
|
'warning',
|
|
15
|
-
'
|
|
25
|
+
'danger',
|
|
16
26
|
'info',
|
|
17
27
|
];
|
|
18
28
|
|
|
@@ -13,6 +13,10 @@ import {
|
|
|
13
13
|
} from './Chip.helpers';
|
|
14
14
|
import type { ChipProps } from './Chip.types';
|
|
15
15
|
|
|
16
|
+
/** MUI draws two chip sizes; ours are the house abbreviations for them. */
|
|
17
|
+
const muiSizeFor = (size: NonNullable<ChipProps['size']>): 'small' | 'medium' =>
|
|
18
|
+
size === 'sm' ? 'small' : 'medium';
|
|
19
|
+
|
|
16
20
|
type MuiChipColor =
|
|
17
21
|
| 'primary'
|
|
18
22
|
| 'secondary'
|
|
@@ -22,10 +26,26 @@ type MuiChipColor =
|
|
|
22
26
|
| 'warning'
|
|
23
27
|
| 'default';
|
|
24
28
|
|
|
29
|
+
/**
|
|
30
|
+
* `danger` and `neutral` are ours; the rest are MUI's own names already.
|
|
31
|
+
*
|
|
32
|
+
* The same boundary translation `Button` performs, and it must stay a
|
|
33
|
+
* translation rather than a cast: a cast is what let `danger` through untouched
|
|
34
|
+
* and had MUI silently fall back to grey.
|
|
35
|
+
*
|
|
36
|
+
* `neutral` maps to `default`, not to `inherit` as it does on a button. A chip's
|
|
37
|
+
* unaccented state is a real palette entry with its own fill; `inherit` would
|
|
38
|
+
* take the surrounding text colour and paint a chip that reads as disabled.
|
|
39
|
+
*/
|
|
40
|
+
const muiColorFor = (color: NonNullable<ChipProps['color']>): MuiChipColor => {
|
|
41
|
+
if (color === 'danger') return 'error';
|
|
42
|
+
return color === 'neutral' ? 'default' : color;
|
|
43
|
+
};
|
|
44
|
+
|
|
25
45
|
export const Chip = forwardRef<HTMLDivElement, ChipProps>(({
|
|
26
46
|
label,
|
|
27
47
|
variant = 'filled',
|
|
28
|
-
size = '
|
|
48
|
+
size = 'md',
|
|
29
49
|
color = 'primary',
|
|
30
50
|
avatarSrc,
|
|
31
51
|
avatar,
|
|
@@ -48,8 +68,8 @@ export const Chip = forwardRef<HTMLDivElement, ChipProps>(({
|
|
|
48
68
|
ref={ref}
|
|
49
69
|
label={<span data-testid={testId('label')}>{label}</span>}
|
|
50
70
|
variant={variant}
|
|
51
|
-
size={size}
|
|
52
|
-
color={color
|
|
71
|
+
size={muiSizeFor(size)}
|
|
72
|
+
color={muiColorFor(color)}
|
|
53
73
|
avatar={avatarFor(avatar, avatarSrc)}
|
|
54
74
|
icon={iconWithTestId(icon, testId('icon'))}
|
|
55
75
|
onDelete={deletable ? onDelete : undefined}
|
|
@@ -1,7 +1,41 @@
|
|
|
1
|
+
import type { ColorValue, SizeValue } from '../../../tokens/scales';
|
|
1
2
|
import type { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
export type ChipVariant = 'filled' | 'outlined';
|
|
4
|
-
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The house size scale, abbreviated like every other component's.
|
|
8
|
+
*
|
|
9
|
+
* `Avatar`, `Badge`, `Progress`, `Input`, `Modal` and `Dialog` all use `sm`/`md`;
|
|
10
|
+
* this was `'small' | 'medium'`, MUI's spelling, and the sole outlier in the
|
|
11
|
+
* package. That was not merely inconsistent — callers wrote `size="sm"` because
|
|
12
|
+
* every neighbouring component taught them to, it type-checked against the old
|
|
13
|
+
* `ChipSize` nowhere and reached MUI as an unknown value, and the chip silently
|
|
14
|
+
* rendered at the default `medium`. Twelve of them are doing that today.
|
|
15
|
+
*
|
|
16
|
+
* Only two entries, because a MUI chip only draws two. Inventing `lg` here would
|
|
17
|
+
* put a size in the type that nothing can render.
|
|
18
|
+
*/
|
|
19
|
+
export type ChipSize = Extract<SizeValue, 'sm' | 'md'>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The colours a chip can draw — THE HOUSE VOCABULARY, identical to `ButtonProps`.
|
|
23
|
+
*
|
|
24
|
+
* `danger` and `neutral` are ours; the rest are MUI's own names already. That is
|
|
25
|
+
* the same sentence `Button.tsx` carries, and deliberately so: `Button`, `Alert`,
|
|
26
|
+
* `Text`, `Heading`, `Paragraph` and `Blockquote` all speak this vocabulary, so a
|
|
27
|
+
* chip is the odd one out if it does not.
|
|
28
|
+
*
|
|
29
|
+
* This prop was `string`, and the widening was not free. `danger` — the house
|
|
30
|
+
* word for the destructive meaning, and what every neighbouring component
|
|
31
|
+
* accepts — reached MUI as an unknown value and fell back to the default grey.
|
|
32
|
+
* The chip that most needed emphasis rendered without any, and nothing said so.
|
|
33
|
+
*
|
|
34
|
+
* The fix is NOT to reject `danger`. Rejecting it would punish a caller for
|
|
35
|
+
* using the vocabulary the rest of the system taught them. The fix is for the
|
|
36
|
+
* chip to speak it and translate at the MUI boundary, exactly as `Button` does.
|
|
37
|
+
*/
|
|
38
|
+
export type ChipColor = ColorValue;
|
|
5
39
|
|
|
6
40
|
export interface ChipProps {
|
|
7
41
|
/** Text content displayed in the chip */
|
|
@@ -13,8 +47,8 @@ export interface ChipProps {
|
|
|
13
47
|
/** Size of the chip */
|
|
14
48
|
size?: ChipSize;
|
|
15
49
|
|
|
16
|
-
/** Theme color token */
|
|
17
|
-
color?:
|
|
50
|
+
/** Theme color token. See {@link ChipColor} for why this is a closed set. */
|
|
51
|
+
color?: ChipColor;
|
|
18
52
|
|
|
19
53
|
/** Source URL for avatar image */
|
|
20
54
|
avatarSrc?: string;
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
interface ChipProps {
|
|
7
7
|
label: string;
|
|
8
8
|
variant?: 'filled' | 'outlined';
|
|
9
|
-
size?: 'sm' | 'md'
|
|
10
|
-
|
|
9
|
+
size?: SizeValue narrowed to 'sm' | 'md';
|
|
10
|
+
/**
|
|
11
|
+
* The house vocabulary, identical to Button's. `danger` and `neutral` are
|
|
12
|
+
* ours and are translated at the MUI boundary. See `ColorValue`.
|
|
13
|
+
*/
|
|
14
|
+
color?: ColorValue;
|
|
11
15
|
avatarSrc?: string; // or avatar node via `avatar`
|
|
12
16
|
avatar?: React.ReactNode;
|
|
13
17
|
icon?: React.ReactNode; // leading icon
|
|
@@ -296,7 +300,7 @@ test('tag removal in list', async () => {
|
|
|
296
300
|
test('status chip with color coding', () => {
|
|
297
301
|
const statuses = [
|
|
298
302
|
{ label: 'Success', color: 'success', testId: 'status-success' },
|
|
299
|
-
{ label: 'Error', color: '
|
|
303
|
+
{ label: 'Error', color: 'danger', testId: 'status-error' },
|
|
300
304
|
{ label: 'Warning', color: 'warning', testId: 'status-warning' },
|
|
301
305
|
];
|
|
302
306
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Chip } from './Chip';
|
|
2
|
-
export type { ChipProps, ChipSize, ChipVariant } from './Chip.types';
|
|
2
|
+
export type { ChipColor, ChipProps, ChipSize, ChipVariant } from './Chip.types';
|
|
@@ -5,6 +5,7 @@ import { useEffect, useRef } from "react";
|
|
|
5
5
|
import { type SortFieldDefinition } from "../../layout/ContentToolbar";
|
|
6
6
|
|
|
7
7
|
import { GridShell } from "./data-views-grid-parts";
|
|
8
|
+
import type { ListGroupConfig } from "./list-card-rails";
|
|
8
9
|
import type { DisplayPanelView } from "./data-views-display-panel";
|
|
9
10
|
import type { BoardConfig } from "./DataViewsBoard";
|
|
10
11
|
import type { DataViewExport } from "./data-views-export";
|
|
@@ -123,6 +124,15 @@ interface DataViewsGridProps<T extends Record<string, unknown>> {
|
|
|
123
124
|
* offered, exactly as `renderCard` gates the cards.
|
|
124
125
|
*/
|
|
125
126
|
renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;
|
|
127
|
+
/**
|
|
128
|
+
* The Lista's SHARED COLUMNS — declared once for the list, obeyed by every row.
|
|
129
|
+
*
|
|
130
|
+
* This is what makes a list line up by construction rather than by convention.
|
|
131
|
+
* Omit it and each row still resolves its own tracks from its own config,
|
|
132
|
+
* which agrees with its neighbours right up until one row carries an unusually
|
|
133
|
+
* wide value.
|
|
134
|
+
*/
|
|
135
|
+
listGroup?: ListGroupConfig<T>;
|
|
126
136
|
/**
|
|
127
137
|
* The page-level partition rendered as an exclusive tab strip above the
|
|
128
138
|
* toolbar, with server-supplied counts. Requires `server`: a scope is applied
|
|
@@ -4,6 +4,7 @@ import type { SortFieldDefinition } from "../../layout/ContentToolbar";
|
|
|
4
4
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
|
|
6
6
|
import { DataViewsGrid } from "./DataViewsGrid";
|
|
7
|
+
import type { ListGroupConfig } from "./list-card-rails";
|
|
7
8
|
import type { DisplayPanelView } from "./data-views-display-panel";
|
|
8
9
|
import { viewStateKey } from "./data-views-dirty";
|
|
9
10
|
import { DeleteViewDialog } from "./DeleteViewDialog";
|
|
@@ -83,6 +84,8 @@ export interface DataViewsTableBaseProps<T extends Record<string, unknown>> {
|
|
|
83
84
|
board?: BoardConfig<T>;
|
|
84
85
|
/** Opt-in "Lista" layout — one full-width, entity-rendered row per record (FUT-733). */
|
|
85
86
|
renderListRow?: (row: T, selection: DataViewCardSelection) => React.ReactNode;
|
|
87
|
+
/** The Lista's shared columns, so its rows line up by construction not convention. */
|
|
88
|
+
listGroup?: ListGroupConfig<T>;
|
|
86
89
|
/** The page-level partition rendered as tabs under the toolbar (server mode only). */
|
|
87
90
|
scopes?: ScopeConfig[];
|
|
88
91
|
/** The row field the scopes partition by — used only to reject a pill over the same field. */
|