@basic-ui/material 1.0.0-alpha.5 → 1.0.0-alpha.8
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/build/cjs/index.js +155 -13
- package/build/cjs/index.js.map +1 -1
- package/build/esm/Alert/Alert.d.ts +1 -1
- package/build/esm/AppBar/AppBarButton.d.ts +1 -1
- package/build/esm/BottomSheet/BottomSheet.d.ts +1 -1
- package/build/esm/Button/Button.d.ts +1 -1
- package/build/esm/Button/ButtonGroup.d.ts +1 -1
- package/build/esm/Button/FilledButton.d.ts +1 -1
- package/build/esm/Button/FilledButton.js +6 -8
- package/build/esm/Button/FilledButton.js.map +1 -1
- package/build/esm/Button/OutlinedButton.d.ts +1 -1
- package/build/esm/Button/TransparentButton.d.ts +1 -1
- package/build/esm/CheckBox/CheckBox.d.ts +1 -1
- package/build/esm/Chip/ButtonChip.d.ts +1 -1
- package/build/esm/Chip/ChipBase.d.ts +1 -1
- package/build/esm/Chip/ChoiceChip.d.ts +1 -1
- package/build/esm/Combobox/Combobox.d.ts +7 -7
- package/build/esm/Dialog/Dialog.d.ts +1 -1
- package/build/esm/Dialog/Scrim.d.ts +1 -1
- package/build/esm/Divider/Divider.d.ts +1 -1
- package/build/esm/Link/Link.d.ts +1 -1
- package/build/esm/ListItem/ListItem.d.ts +1 -1
- package/build/esm/Menu/Menu.d.ts +4 -4
- package/build/esm/NavRail/NavRailItem.d.ts +15 -0
- package/build/esm/NavRail/NavRailItem.js +146 -0
- package/build/esm/NavRail/NavRailItem.js.map +1 -0
- package/build/esm/NavRail/index.d.ts +1 -0
- package/build/esm/NavRail/index.js +2 -0
- package/build/esm/NavRail/index.js.map +1 -0
- package/build/esm/Paper/Paper.d.ts +1 -1
- package/build/esm/Ripple/useRippleSurface.d.ts +2 -2
- package/build/esm/Ripple/useRippleSurface.js +61 -58
- package/build/esm/Ripple/useRippleSurface.js.map +1 -1
- package/build/esm/Select/Select.d.ts +1 -1
- package/build/esm/Select/SelectIcon.d.ts +1 -1
- package/build/esm/SelectItem/SelectItem.d.ts +1 -1
- package/build/esm/SelectionControl/SelectionControlText.d.ts +1 -1
- package/build/esm/Skeleton/Skeleton.d.ts +1 -1
- package/build/esm/Switch/Switch.d.ts +1 -1
- package/build/esm/Tab/Tab.d.ts +1 -1
- package/build/esm/Table/TableHead.d.ts +1 -1
- package/build/esm/Table/TableRow.d.ts +1 -1
- package/build/esm/TextField/FilledContainer.d.ts +1 -1
- package/build/esm/TextField/HelperText.d.ts +1 -1
- package/build/esm/TextField/Input.d.ts +1 -1
- package/build/esm/TextField/TextField.d.ts +1 -1
- package/build/esm/Tooltip/Tooltip.d.ts +1 -1
- package/build/esm/color.d.ts +2 -0
- package/build/esm/color.js +8 -3
- package/build/esm/color.js.map +1 -1
- package/build/esm/index.d.ts +1 -0
- package/build/esm/index.js +1 -0
- package/build/esm/index.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/Button/Button.story.tsx +6 -1
- package/src/Button/FilledButton.tsx +4 -9
- package/src/NavRail/NavRail.story.tsx +189 -0
- package/src/NavRail/NavRailItem.tsx +174 -0
- package/src/NavRail/index.ts +1 -0
- package/src/Ripple/useRippleSurface.ts +70 -58
- package/src/ThemeExplorer/ThemeBuilder.story.tsx +27 -23
- package/src/color.ts +25 -4
- package/src/index.ts +1 -0
- package/src/ThemeExplorer/ThemeExplorer.story.tsx +0 -43
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { rem } from 'polished';
|
|
2
|
+
import React, { forwardRef, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { Box } from '../Box';
|
|
5
|
+
import { NavRailItem, NavRailIndicator, NavRailLabel } from './';
|
|
6
|
+
import type { NavRailLabelProps } from './';
|
|
7
|
+
// import './styles.css';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
title: 'components/NavRail',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const ListIcon = (props) => (
|
|
14
|
+
<svg
|
|
15
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
16
|
+
height={16}
|
|
17
|
+
width={16}
|
|
18
|
+
viewBox="0 0 24 24"
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<path
|
|
22
|
+
fill="currentColor"
|
|
23
|
+
d="M8 17q.425 0 .713-.288Q9 16.425 9 16t-.287-.713Q8.425 15 8 15t-.713.287Q7 15.575 7 16t.287.712Q7.575 17 8 17Zm0-4q.425 0 .713-.288Q9 12.425 9 12t-.287-.713Q8.425 11 8 11t-.713.287Q7 11.575 7 12t.287.712Q7.575 13 8 13Zm0-4q.425 0 .713-.288Q9 8.425 9 8t-.287-.713Q8.425 7 8 7t-.713.287Q7 7.575 7 8t.287.712Q7.575 9 8 9Zm3 8h6v-2h-6Zm0-4h6v-2h-6Zm0-4h6V7h-6ZM5 21q-.825 0-1.413-.587Q3 19.825 3 19V5q0-.825.587-1.413Q4.175 3 5 3h14q.825 0 1.413.587Q21 4.175 21 5v14q0 .825-.587 1.413Q19.825 21 19 21Zm0-2h14V5H5v14ZM5 5v14V5Z"
|
|
24
|
+
/>
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const KitchenIcon = (props) => (
|
|
29
|
+
<svg
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
height={16}
|
|
32
|
+
width={16}
|
|
33
|
+
viewBox="0 0 24 24"
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
<path
|
|
37
|
+
fill="currentColor"
|
|
38
|
+
d="M8 8V5h2v3Zm0 9v-5h2v5Zm-2 5q-.825 0-1.412-.587Q4 20.825 4 20V4q0-.825.588-1.413Q5.175 2 6 2h12q.825 0 1.413.587Q20 3.175 20 4v16q0 .825-.587 1.413Q18.825 22 18 22Zm0-2h12v-9H6v9ZM6 9h12V4H6Z"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const MenuIcon = (props) => (
|
|
44
|
+
<svg
|
|
45
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
46
|
+
height={16}
|
|
47
|
+
width={16}
|
|
48
|
+
viewBox="0 0 24 24"
|
|
49
|
+
{...props}
|
|
50
|
+
>
|
|
51
|
+
<path
|
|
52
|
+
fill="currentColor"
|
|
53
|
+
d="M17 22v-8h-3V7q0-2.075 1.463-3.537Q16.925 2 19 2v20ZM7 22v-9.15q-1.275-.35-2.137-1.4Q4 10.4 4 9V2h2v7h1V2h2v7h1V2h2v7q0 1.4-.863 2.45-.862 1.05-2.137 1.4V22Z"
|
|
54
|
+
/>
|
|
55
|
+
</svg>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export const Default = () => {
|
|
59
|
+
const [selectedItem, setSelectedItem] = useState('0');
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Box
|
|
63
|
+
bg="surface"
|
|
64
|
+
width="80px"
|
|
65
|
+
position="fixed"
|
|
66
|
+
top="0"
|
|
67
|
+
bottom="0"
|
|
68
|
+
left="0"
|
|
69
|
+
py={rem(80)}
|
|
70
|
+
display="flex"
|
|
71
|
+
flexDirection="column"
|
|
72
|
+
>
|
|
73
|
+
<NavRailItem
|
|
74
|
+
selected={selectedItem === '0'}
|
|
75
|
+
onClick={() => setSelectedItem('0')}
|
|
76
|
+
>
|
|
77
|
+
<NavRailIndicator>
|
|
78
|
+
<MenuIcon />
|
|
79
|
+
</NavRailIndicator>
|
|
80
|
+
<NavRailLabel>Menu</NavRailLabel>
|
|
81
|
+
</NavRailItem>
|
|
82
|
+
<NavRailItem
|
|
83
|
+
selected={selectedItem === '1'}
|
|
84
|
+
onClick={() => setSelectedItem('1')}
|
|
85
|
+
>
|
|
86
|
+
<NavRailIndicator>
|
|
87
|
+
<KitchenIcon />
|
|
88
|
+
</NavRailIndicator>
|
|
89
|
+
<NavRailLabel>Kitchen</NavRailLabel>
|
|
90
|
+
</NavRailItem>
|
|
91
|
+
<NavRailItem
|
|
92
|
+
selected={selectedItem === '2'}
|
|
93
|
+
onClick={() => setSelectedItem('2')}
|
|
94
|
+
>
|
|
95
|
+
<NavRailIndicator>
|
|
96
|
+
<ListIcon />
|
|
97
|
+
</NavRailIndicator>
|
|
98
|
+
<NavRailLabel>Orders</NavRailLabel>
|
|
99
|
+
</NavRailItem>
|
|
100
|
+
</Box>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const DisappearingNavRailLabel = forwardRef<
|
|
105
|
+
HTMLDivElement,
|
|
106
|
+
NavRailLabelProps & { selected: boolean }
|
|
107
|
+
>(function AnimatedNavRailLabel({ selected, height = '28px', ...props }, ref) {
|
|
108
|
+
const transitionDuration = '0.2s';
|
|
109
|
+
const transitionTimingFunction = 'cubic-bezier(0.4, 0, 0.2, 1)';
|
|
110
|
+
return (
|
|
111
|
+
<Box
|
|
112
|
+
ref={ref}
|
|
113
|
+
style={{
|
|
114
|
+
height: selected ? height : '0px',
|
|
115
|
+
}}
|
|
116
|
+
sx={{
|
|
117
|
+
transition: `height ${transitionDuration} ${transitionTimingFunction}`,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<NavRailLabel
|
|
121
|
+
style={{
|
|
122
|
+
transform: selected
|
|
123
|
+
? 'scale(1) translateY(0)'
|
|
124
|
+
: `scale(0.8, 0.64) translateY(calc(${height} * -0.5 * 0.64))`,
|
|
125
|
+
opacity: selected ? '1' : '0',
|
|
126
|
+
}}
|
|
127
|
+
sx={{
|
|
128
|
+
transformOrigin: 'center top',
|
|
129
|
+
transition:
|
|
130
|
+
`transform ${transitionDuration} ${transitionTimingFunction}, ` +
|
|
131
|
+
`opacity ${transitionDuration} ${transitionTimingFunction}`,
|
|
132
|
+
}}
|
|
133
|
+
{...props}
|
|
134
|
+
/>
|
|
135
|
+
</Box>
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export const WithHiddenLabels = () => {
|
|
140
|
+
const [selectedItem, setSelectedItem] = useState('0');
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<Box
|
|
144
|
+
bg="surface"
|
|
145
|
+
width="80px"
|
|
146
|
+
position="fixed"
|
|
147
|
+
top="0"
|
|
148
|
+
bottom="0"
|
|
149
|
+
left="0"
|
|
150
|
+
py={rem(80)}
|
|
151
|
+
display="flex"
|
|
152
|
+
flexDirection="column"
|
|
153
|
+
>
|
|
154
|
+
<NavRailItem
|
|
155
|
+
selected={selectedItem === '0'}
|
|
156
|
+
onClick={() => setSelectedItem('0')}
|
|
157
|
+
>
|
|
158
|
+
<NavRailIndicator>
|
|
159
|
+
<MenuIcon />
|
|
160
|
+
</NavRailIndicator>
|
|
161
|
+
<DisappearingNavRailLabel selected={selectedItem === '0'}>
|
|
162
|
+
Menu
|
|
163
|
+
</DisappearingNavRailLabel>
|
|
164
|
+
</NavRailItem>
|
|
165
|
+
<NavRailItem
|
|
166
|
+
selected={selectedItem === '1'}
|
|
167
|
+
onClick={() => setSelectedItem('1')}
|
|
168
|
+
>
|
|
169
|
+
<NavRailIndicator>
|
|
170
|
+
<KitchenIcon />
|
|
171
|
+
</NavRailIndicator>
|
|
172
|
+
<DisappearingNavRailLabel selected={selectedItem === '1'}>
|
|
173
|
+
Kitchen
|
|
174
|
+
</DisappearingNavRailLabel>
|
|
175
|
+
</NavRailItem>
|
|
176
|
+
<NavRailItem
|
|
177
|
+
selected={selectedItem === '2'}
|
|
178
|
+
onClick={() => setSelectedItem('2')}
|
|
179
|
+
>
|
|
180
|
+
<NavRailIndicator>
|
|
181
|
+
<ListIcon />
|
|
182
|
+
</NavRailIndicator>
|
|
183
|
+
<DisappearingNavRailLabel selected={selectedItem === '2'}>
|
|
184
|
+
Orders
|
|
185
|
+
</DisappearingNavRailLabel>
|
|
186
|
+
</NavRailItem>
|
|
187
|
+
</Box>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
2
|
+
import { rem } from 'polished';
|
|
3
|
+
import { get } from 'styled-system';
|
|
4
|
+
|
|
5
|
+
import type { BoxProps, SxStyleProp } from '../Box';
|
|
6
|
+
import { Box } from '../Box';
|
|
7
|
+
import { useTheme } from '../theme';
|
|
8
|
+
import { Text } from '../Text';
|
|
9
|
+
import type { TextProps } from '../Text';
|
|
10
|
+
import { useRippleSurface } from '../Ripple';
|
|
11
|
+
|
|
12
|
+
export interface NavRailItemProps extends Omit<BoxProps, 'color'> {
|
|
13
|
+
as?: React.ElementType<any>;
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
selected?: boolean;
|
|
17
|
+
color?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type NavRailIndicatorProps = BoxProps;
|
|
21
|
+
|
|
22
|
+
export const NavRailIndicator = forwardRef<
|
|
23
|
+
HTMLDivElement,
|
|
24
|
+
NavRailIndicatorProps
|
|
25
|
+
>(function NavRailIndicator(props, forwardedRef) {
|
|
26
|
+
const { as = 'div', children, __css, ...otherProps } = props;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Box
|
|
30
|
+
color="currentColor"
|
|
31
|
+
ref={forwardedRef}
|
|
32
|
+
as={as}
|
|
33
|
+
data-nav-rail-item-indicator=""
|
|
34
|
+
{...otherProps}
|
|
35
|
+
__css={{
|
|
36
|
+
width: '100%',
|
|
37
|
+
height: '100%',
|
|
38
|
+
maxWidth: rem(56),
|
|
39
|
+
maxHeight: rem(56),
|
|
40
|
+
borderRadius: 'full',
|
|
41
|
+
bg: 'var(--indicator-background-color)',
|
|
42
|
+
display: 'flex',
|
|
43
|
+
alignItems: 'center',
|
|
44
|
+
justifyContent: 'center',
|
|
45
|
+
minHeight: rem(32),
|
|
46
|
+
transition: 'background-color .2s cubic-bezier(.4,0,.2,1)',
|
|
47
|
+
pointerEvents: 'none',
|
|
48
|
+
...__css,
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
</Box>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export type NavRailLabelProps = TextProps;
|
|
57
|
+
|
|
58
|
+
export const NavRailLabel = forwardRef<HTMLDivElement, NavRailLabelProps>(
|
|
59
|
+
function NavRailLabel(props, forwardedRef) {
|
|
60
|
+
const { as = 'div', children, __css, ...otherProps } = props;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Text
|
|
64
|
+
ref={forwardedRef}
|
|
65
|
+
as={as}
|
|
66
|
+
variant="caption"
|
|
67
|
+
lineHeight={1}
|
|
68
|
+
{...otherProps}
|
|
69
|
+
__css={{
|
|
70
|
+
pt: rem(4),
|
|
71
|
+
pb: rem(12),
|
|
72
|
+
color: 'inherit',
|
|
73
|
+
pointerEvents: 'none',
|
|
74
|
+
...__css,
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{children}
|
|
78
|
+
</Text>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
export const NavRailItem = forwardRef<HTMLDivElement, NavRailItemProps>(
|
|
84
|
+
function NavRailItem(props, forwardedRef) {
|
|
85
|
+
const {
|
|
86
|
+
as = 'button',
|
|
87
|
+
children,
|
|
88
|
+
color = 'primary-container',
|
|
89
|
+
selected = false,
|
|
90
|
+
disabled = false,
|
|
91
|
+
style,
|
|
92
|
+
onKeyDown,
|
|
93
|
+
onPointerDown,
|
|
94
|
+
__css,
|
|
95
|
+
...otherProps
|
|
96
|
+
} = props;
|
|
97
|
+
const theme = useTheme();
|
|
98
|
+
const baseOpacity = 0,
|
|
99
|
+
hoverOpacity = 0.04,
|
|
100
|
+
focusOpacity = 0.12,
|
|
101
|
+
pressedOpacity = 0.12;
|
|
102
|
+
const ripple = useRippleSurface({
|
|
103
|
+
rippleColor: 'currentColor',
|
|
104
|
+
onKeyDown,
|
|
105
|
+
onPointerDown,
|
|
106
|
+
baseOpacity,
|
|
107
|
+
hoverOpacity,
|
|
108
|
+
focusOpacity,
|
|
109
|
+
pressedOpacity,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Apply ripple from nav item to nav indicator
|
|
113
|
+
const rippleCss = useMemo(() => {
|
|
114
|
+
const ret: SxStyleProp = {};
|
|
115
|
+
const keys = Object.keys(ripple.__css);
|
|
116
|
+
for (const key of keys) {
|
|
117
|
+
if (!key.startsWith('&')) {
|
|
118
|
+
ret['& [data-nav-rail-item-indicator]'] =
|
|
119
|
+
ret['& [data-nav-rail-item-indicator]'] || {};
|
|
120
|
+
ret['& [data-nav-rail-item-indicator]'][key] = ripple.__css[key];
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const newKey = key.replace(
|
|
125
|
+
/(.+?)::(before|after)/g,
|
|
126
|
+
'$1 [data-nav-rail-item-indicator]::$2'
|
|
127
|
+
);
|
|
128
|
+
ret[newKey] = ripple.__css[key];
|
|
129
|
+
}
|
|
130
|
+
return ret;
|
|
131
|
+
}, [ripple.__css]);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<Box
|
|
135
|
+
ref={forwardedRef}
|
|
136
|
+
as={as}
|
|
137
|
+
{...otherProps}
|
|
138
|
+
onPointerDown={ripple.onPointerDown}
|
|
139
|
+
onKeyDown={ripple.onKeyDown}
|
|
140
|
+
aria-pressed={selected}
|
|
141
|
+
type="button"
|
|
142
|
+
style={{ ...ripple.style, ...style }}
|
|
143
|
+
disabled={disabled}
|
|
144
|
+
__css={{
|
|
145
|
+
display: 'flex',
|
|
146
|
+
flexDirection: 'column',
|
|
147
|
+
alignItems: 'center',
|
|
148
|
+
transition: 'color .2s cubic-bezier(.4,0,.2,1)',
|
|
149
|
+
color: selected ? `on.${color}` : 'on.surface-variant',
|
|
150
|
+
'--indicator-background-color': selected
|
|
151
|
+
? get(theme, `colors.${color}`)
|
|
152
|
+
: 'transparent',
|
|
153
|
+
border: 'none',
|
|
154
|
+
':focus': {
|
|
155
|
+
outline: 'none',
|
|
156
|
+
},
|
|
157
|
+
backgroundColor: 'transparent',
|
|
158
|
+
margin: 0,
|
|
159
|
+
padding: 0,
|
|
160
|
+
px: rem(12),
|
|
161
|
+
minHeight: rem(60),
|
|
162
|
+
height: rem(60),
|
|
163
|
+
cursor: 'pointer',
|
|
164
|
+
textDecoration: 'none',
|
|
165
|
+
WebkitTapHighlightColor: 'transparent',
|
|
166
|
+
...rippleCss,
|
|
167
|
+
...__css,
|
|
168
|
+
}}
|
|
169
|
+
>
|
|
170
|
+
{children}
|
|
171
|
+
</Box>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './NavRailItem';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
|
+
import { useMemo } from 'react';
|
|
2
3
|
import { get } from '@styled-system/css';
|
|
3
4
|
import { wrapEvent } from '@basic-ui/core';
|
|
4
5
|
|
|
@@ -22,7 +23,7 @@ export interface UseRippleSurfaceOptions<T extends HTMLElement> {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function useRippleSurface<T extends HTMLElement>(
|
|
25
|
-
opts: UseRippleSurfaceOptions<T>
|
|
26
|
+
opts: UseRippleSurfaceOptions<T> = {}
|
|
26
27
|
) {
|
|
27
28
|
let {
|
|
28
29
|
// eslint-disable-next-line prefer-const
|
|
@@ -62,67 +63,78 @@ export function useRippleSurface<T extends HTMLElement>(
|
|
|
62
63
|
...rippleProps,
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
const css: SxStyleProp =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
'&:hover::before': {
|
|
88
|
-
opacity: hoverOpacity,
|
|
89
|
-
},
|
|
90
|
-
'&:focus-visible::before': {
|
|
91
|
-
opacity: focusOpacity,
|
|
92
|
-
},
|
|
93
|
-
...(!rippleEnabled && {
|
|
94
|
-
'&:active::before': {
|
|
95
|
-
opacity: pressedOpacity,
|
|
66
|
+
const css: SxStyleProp = useMemo(
|
|
67
|
+
() => ({
|
|
68
|
+
overflow: 'hidden',
|
|
69
|
+
position: 'relative',
|
|
70
|
+
cursor: 'pointer',
|
|
71
|
+
// fix overflow: hidden + borderRadius in Safari
|
|
72
|
+
// https://gist.github.com/ayamflow/b602ab436ac9f05660d9c15190f4fd7b#gistcomment-2359479
|
|
73
|
+
willChange: 'transform,opacity',
|
|
74
|
+
WebkitTapHighlightColor: 'transparent',
|
|
75
|
+
// ripple overlay
|
|
76
|
+
'&::before': {
|
|
77
|
+
backgroundColor: rippleColor,
|
|
78
|
+
boxSizing: 'content-box',
|
|
79
|
+
position: 'absolute',
|
|
80
|
+
content: '""',
|
|
81
|
+
opacity: baseOpacity,
|
|
82
|
+
pointerEvents: 'none',
|
|
83
|
+
top: '0',
|
|
84
|
+
left: '0',
|
|
85
|
+
width: '100%',
|
|
86
|
+
height: '100%',
|
|
87
|
+
transition: 'opacity 75ms linear',
|
|
96
88
|
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
opacity: baseOpacity + pressedOpacity,
|
|
100
|
-
},
|
|
101
|
-
'&[aria-pressed="true"]:hover::before': {
|
|
102
|
-
opacity: pressedOpacity + hoverOpacity,
|
|
103
|
-
},
|
|
104
|
-
'&[aria-pressed="true"]:focus-visible::before': {
|
|
105
|
-
opacity: pressedOpacity + focusOpacity,
|
|
106
|
-
},
|
|
107
|
-
...(!rippleEnabled && {
|
|
108
|
-
'&[aria-pressed="true"]:active::before': {
|
|
109
|
-
opacity: pressedOpacity + pressedOpacity,
|
|
89
|
+
'&:hover::before': {
|
|
90
|
+
opacity: hoverOpacity,
|
|
110
91
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
92
|
+
'&:focus-visible::before': {
|
|
93
|
+
opacity: focusOpacity,
|
|
94
|
+
},
|
|
95
|
+
...(!rippleEnabled && {
|
|
96
|
+
'&:active::before': {
|
|
97
|
+
opacity: pressedOpacity,
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
'&[aria-pressed="true"]::before': {
|
|
101
|
+
opacity: baseOpacity + pressedOpacity,
|
|
102
|
+
},
|
|
103
|
+
'&[aria-pressed="true"]:hover::before': {
|
|
104
|
+
opacity: pressedOpacity + hoverOpacity,
|
|
117
105
|
},
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
106
|
+
'&[aria-pressed="true"]:focus-visible::before': {
|
|
107
|
+
opacity: pressedOpacity + focusOpacity,
|
|
108
|
+
},
|
|
109
|
+
...(!rippleEnabled && {
|
|
110
|
+
'&[aria-pressed="true"]:active::before': {
|
|
111
|
+
opacity: pressedOpacity + pressedOpacity,
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
['&:disabled::before,&:disabled:hover::before,&:disabled:focus::before,&:disabled:active::before,' +
|
|
115
|
+
'&[data-disabled]::before,&[data-disabled]:hover::before,&[data-disabled]:focus::before,' +
|
|
116
|
+
'&[data-disabled]:active::before,&:disabled[aria-pressed="true"]::before']:
|
|
117
|
+
{
|
|
118
|
+
opacity: 0,
|
|
119
|
+
},
|
|
120
|
+
'&:disabled,&[data-disabled]': {
|
|
121
|
+
cursor: 'default',
|
|
122
|
+
},
|
|
123
|
+
// ripple
|
|
124
|
+
...(rippleEnabled && {
|
|
125
|
+
'&::after': { ...rippleStyle({ animation }) },
|
|
126
|
+
}),
|
|
124
127
|
}),
|
|
125
|
-
|
|
128
|
+
[
|
|
129
|
+
animation,
|
|
130
|
+
baseOpacity,
|
|
131
|
+
focusOpacity,
|
|
132
|
+
hoverOpacity,
|
|
133
|
+
pressedOpacity,
|
|
134
|
+
rippleColor,
|
|
135
|
+
rippleEnabled,
|
|
136
|
+
]
|
|
137
|
+
);
|
|
126
138
|
|
|
127
139
|
return {
|
|
128
140
|
style: { ...animationStyle, ...style },
|
|
@@ -68,6 +68,8 @@ const ThemeBuilder = () => {
|
|
|
68
68
|
sx={{ gap: 3 }}
|
|
69
69
|
flexDirection="column"
|
|
70
70
|
width="300px"
|
|
71
|
+
position="fixed"
|
|
72
|
+
top="0"
|
|
71
73
|
>
|
|
72
74
|
<Box display="flex">
|
|
73
75
|
<TextFieldColorPicker
|
|
@@ -131,31 +133,33 @@ const ThemeBuilder = () => {
|
|
|
131
133
|
</Button>
|
|
132
134
|
</Box>
|
|
133
135
|
</Box>
|
|
134
|
-
<Box width="
|
|
135
|
-
<Box
|
|
136
|
-
<Box flex="
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
<Box width="100%" pl="300px">
|
|
137
|
+
<Box width="600px" mx="auto">
|
|
138
|
+
<Box display="flex" flexDirection="column" sx={{ gap: 4 }}>
|
|
139
|
+
<Box flex="1">
|
|
140
|
+
<Text variant="h5" as="h1" pb={'0.3em'}>
|
|
141
|
+
Light theme
|
|
142
|
+
</Text>
|
|
143
|
+
<ThemeColors scheme={scheme} />
|
|
144
|
+
</Box>
|
|
145
|
+
<Box flex="1">
|
|
146
|
+
<Text variant="h5" as="h1" pb={'0.3em'}>
|
|
147
|
+
Dark theme
|
|
148
|
+
</Text>
|
|
149
|
+
<ThemeColors scheme={scheme.modes.dark} />
|
|
150
|
+
</Box>
|
|
141
151
|
</Box>
|
|
142
|
-
<Box flex="
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
<
|
|
152
|
+
<Box my={4} display="flex" sx={{ gap: 3 }} flexDirection="column">
|
|
153
|
+
<TonalColors palette={a1} />
|
|
154
|
+
<TonalColors palette={secondaryColorTonal} />
|
|
155
|
+
<TonalColors palette={tertiaryColorTonal} />
|
|
156
|
+
<TonalColors palette={error} />
|
|
157
|
+
<TonalColors palette={neutralColorTonal} />
|
|
158
|
+
<TonalColors palette={n2} />
|
|
159
|
+
</Box>
|
|
160
|
+
<Box as="pre" fontFamily="monospace" fontSize="12px">
|
|
161
|
+
{JSON.stringify({ colors: scheme }, null, 2)}
|
|
147
162
|
</Box>
|
|
148
|
-
</Box>
|
|
149
|
-
<Box my={4} display="flex" sx={{ gap: 3 }} flexDirection="column">
|
|
150
|
-
<TonalColors palette={a1} />
|
|
151
|
-
<TonalColors palette={secondaryColorTonal} />
|
|
152
|
-
<TonalColors palette={tertiaryColorTonal} />
|
|
153
|
-
<TonalColors palette={error} />
|
|
154
|
-
<TonalColors palette={neutralColorTonal} />
|
|
155
|
-
<TonalColors palette={n2} />
|
|
156
|
-
</Box>
|
|
157
|
-
<Box as="pre" fontFamily="monospace" fontSize="12px">
|
|
158
|
-
{JSON.stringify({ colors: scheme }, null, 2)}
|
|
159
163
|
</Box>
|
|
160
164
|
</Box>
|
|
161
165
|
</Box>
|
package/src/color.ts
CHANGED
|
@@ -17,17 +17,38 @@ export const alpha =
|
|
|
17
17
|
return `rgba(${rgb.red},${rgb.green},${rgb.blue},${alphaValue})`;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
export function mixColor(
|
|
21
|
+
baseColor: string,
|
|
22
|
+
overlayColor: string
|
|
23
|
+
): (theme: any) => string;
|
|
24
|
+
export function mixColor(
|
|
25
|
+
baseColor: string,
|
|
26
|
+
overlayColor: string,
|
|
27
|
+
overlayOpacity: number
|
|
28
|
+
): (theme: any) => string;
|
|
29
|
+
export function mixColor(
|
|
30
|
+
baseColor: string,
|
|
31
|
+
overlayColor: string,
|
|
32
|
+
overlayOpacity?: number
|
|
33
|
+
): (theme: any) => string {
|
|
34
|
+
return (theme) => {
|
|
35
|
+
baseColor = get(theme, `colors.${baseColor}`, baseColor);
|
|
36
|
+
overlayColor = overlayOpacity
|
|
37
|
+
? alpha(overlayColor, overlayOpacity)(theme)
|
|
38
|
+
: get(theme, `colors.${overlayColor}`, overlayColor);
|
|
39
|
+
|
|
40
|
+
return `linear-gradient(${overlayColor}, ${overlayColor}), ${baseColor}`;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
20
44
|
export function getColorOverlay(
|
|
21
45
|
theme: Theme,
|
|
22
46
|
baseColor: string,
|
|
23
47
|
overlayColor: string,
|
|
24
48
|
overlayOpacity: number
|
|
25
49
|
): SystemStyleObject {
|
|
26
|
-
baseColor = get(theme, `colors.${baseColor}`) || baseColor;
|
|
27
|
-
overlayColor = alpha(overlayColor, overlayOpacity)(theme);
|
|
28
|
-
|
|
29
50
|
return {
|
|
30
|
-
background:
|
|
51
|
+
background: mixColor(baseColor, overlayColor, overlayOpacity)(theme),
|
|
31
52
|
};
|
|
32
53
|
}
|
|
33
54
|
|
package/src/index.ts
CHANGED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { useTheme } from '@emotion/react';
|
|
3
|
-
|
|
4
|
-
import { ThemeColors } from './ThemeColors';
|
|
5
|
-
import { DARK_THEME_CLASS, DEFAULT_THEME_CLASS, Box } from '../';
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
title: 'components/ThemeExplorer',
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const ThemeExplorer = () => {
|
|
12
|
-
const theme = useTheme();
|
|
13
|
-
return (
|
|
14
|
-
<>
|
|
15
|
-
<Box
|
|
16
|
-
flex="1"
|
|
17
|
-
p={3}
|
|
18
|
-
borderRadius="extra-large"
|
|
19
|
-
overflow="hidden"
|
|
20
|
-
border="1px solid #fff"
|
|
21
|
-
borderColor="outline"
|
|
22
|
-
bg="surface"
|
|
23
|
-
className={DEFAULT_THEME_CLASS}
|
|
24
|
-
>
|
|
25
|
-
<ThemeColors scheme={theme.colors as any} />
|
|
26
|
-
</Box>
|
|
27
|
-
<Box
|
|
28
|
-
flex="1"
|
|
29
|
-
p={3}
|
|
30
|
-
borderRadius="extra-large"
|
|
31
|
-
overflow="hidden"
|
|
32
|
-
border="1px solid #fff"
|
|
33
|
-
borderColor="outline"
|
|
34
|
-
bg="surface"
|
|
35
|
-
className={DARK_THEME_CLASS}
|
|
36
|
-
>
|
|
37
|
-
<ThemeColors scheme={theme.colors.modes.dark as any} />
|
|
38
|
-
</Box>
|
|
39
|
-
</>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const Explorer = () => <ThemeExplorer />;
|