@basic-ui/material 1.0.0-alpha.32 → 1.0.0-alpha.33

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.
Files changed (35) hide show
  1. package/build/cjs/index.js +9 -7
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/esm/Chip/ButtonChip.d.ts +1 -1
  4. package/build/esm/Combobox/Combobox.d.ts +7 -7
  5. package/build/esm/Select/CustomContainerExample.d.ts +3 -0
  6. package/build/esm/Select/CustomContainerExample.js +59 -0
  7. package/build/esm/Select/CustomContainerExample.js.map +1 -0
  8. package/build/esm/Select/Select.d.ts +4 -2
  9. package/build/esm/Select/Select.js +4 -3
  10. package/build/esm/Select/Select.js.map +1 -1
  11. package/build/esm/Table/TableHead.d.ts +1 -1
  12. package/build/esm/TextField/FilledContainer.d.ts +4 -1
  13. package/build/esm/TextField/FilledContainer.js +5 -5
  14. package/build/esm/TextField/FilledContainer.js.map +1 -1
  15. package/build/esm/TextField/TextField.d.ts +1 -1
  16. package/build/esm/ThemeExplorer/ThemeBuilder.js +13 -2
  17. package/build/esm/ThemeExplorer/ThemeBuilder.js.map +1 -1
  18. package/build/esm/ThemeExplorer/ThemeColors.js +33 -15
  19. package/build/esm/ThemeExplorer/ThemeColors.js.map +1 -1
  20. package/build/esm/ThemeExplorer/components.d.ts +1 -1
  21. package/build/esm/ThemeExplorer/components.js +11 -13
  22. package/build/esm/ThemeExplorer/components.js.map +1 -1
  23. package/build/esm/ThemeExplorer/makeColorScheme.d.ts +32 -4
  24. package/build/esm/ThemeExplorer/makeColorScheme.js +41 -8
  25. package/build/esm/ThemeExplorer/makeColorScheme.js.map +1 -1
  26. package/build/tsconfig-build.tsbuildinfo +1 -1
  27. package/package.json +2 -2
  28. package/src/Select/CustomContainerExample.tsx +59 -0
  29. package/src/Select/Select.story.tsx +22 -1
  30. package/src/Select/Select.tsx +6 -2
  31. package/src/TextField/FilledContainer.tsx +6 -5
  32. package/src/ThemeExplorer/ThemeBuilder.tsx +16 -5
  33. package/src/ThemeExplorer/ThemeColors.tsx +39 -15
  34. package/src/ThemeExplorer/components.tsx +12 -20
  35. package/src/ThemeExplorer/makeColorScheme.tsx +39 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basic-ui/material",
3
- "version": "1.0.0-alpha.32",
3
+ "version": "1.0.0-alpha.33",
4
4
  "description": "Accessible React Components used as building blocks for UI patterns",
5
5
  "author": "Lucas Terra <lucasterra7@gmail.com>",
6
6
  "license": "MIT",
@@ -52,5 +52,5 @@
52
52
  "react": "^16.14.0 || ^17.0.0 || ^18.0.0",
53
53
  "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0"
54
54
  },
55
- "gitHead": "42c1e44b1429227fe589e0f7a4bfeeb15b5e395a"
55
+ "gitHead": "475bece40050a72ea07ed47cf3f34eecd51d4484"
56
56
  }
@@ -0,0 +1,59 @@
1
+ import { forwardRef } from 'react';
2
+
3
+ import { alpha } from '../color';
4
+ import { Box } from '../Box';
5
+ import type { FilledContainerProps } from '../';
6
+ import { FilledContainerOverlay } from '../';
7
+
8
+ export const CustomContainer = forwardRef<HTMLDivElement, FilledContainerProps>(
9
+ function CustomContainer(props, forwardedRef) {
10
+ const {
11
+ label,
12
+ labelIsFloating,
13
+ inputId,
14
+ hasFocus,
15
+ color: colorProp,
16
+ children,
17
+ error = false,
18
+ disabled = false,
19
+ forceActive = false,
20
+ leadingIcon,
21
+ ...otherProps
22
+ } = props;
23
+
24
+ const active = hasFocus || forceActive;
25
+
26
+ return (
27
+ <Box
28
+ ref={forwardedRef}
29
+ disabled={disabled}
30
+ active={active || error}
31
+ __css={{
32
+ variant: 'text.label-small',
33
+ position: 'relative',
34
+ lineHeight: 0,
35
+ width: '100%',
36
+ height: 32,
37
+ overflow: 'hidden',
38
+ boxSizing: 'border-box',
39
+ borderRadius: 'full',
40
+ color: alpha('on.surface-variant', 0.87),
41
+ ...(disabled && {
42
+ backgroundColor: alpha('on.surface-variant', 0.08),
43
+ color: alpha('on.surface-variant', 0.38),
44
+ }),
45
+ ...(active && { color: 'primary' }),
46
+ '& > [role="button"]': {
47
+ variant: 'text.label-medium',
48
+ minHeight: 32,
49
+ py: 0,
50
+ },
51
+ }}
52
+ {...otherProps}
53
+ >
54
+ {children}
55
+ <FilledContainerOverlay forceActive={active} />
56
+ </Box>
57
+ );
58
+ }
59
+ );
@@ -1,9 +1,11 @@
1
1
  import { useState } from 'react';
2
2
 
3
+ import type { SelectProps } from './';
3
4
  import { Select } from './';
4
5
  import { SelectItem } from '../SelectItem';
5
6
  import { Box } from '../Box';
6
7
  import { CheckBox } from '../CheckBox';
8
+ import { CustomContainer as CustomContainerExample } from './CustomContainerExample';
7
9
  // import './styles.css';
8
10
 
9
11
  export default {
@@ -23,7 +25,15 @@ const SearchIcon = (props) => (
23
25
  </svg>
24
26
  );
25
27
 
26
- const Example = ({ variant, native = false }) => {
28
+ const Example = ({
29
+ variant,
30
+ native = false,
31
+ CustomContainer: Container = undefined,
32
+ }: {
33
+ variant?: 'outlined' | 'filled';
34
+ native?: boolean;
35
+ CustomContainer?: SelectProps['CustomContainer'];
36
+ }) => {
27
37
  const [error, setError] = useState<boolean | string>(false);
28
38
  const [color, setColor] = useState<'primary' | 'secondary'>('primary');
29
39
 
@@ -86,6 +96,7 @@ const Example = ({ variant, native = false }) => {
86
96
  value={color}
87
97
  onChange={(e, value) => setColor(value as 'primary' | 'secondary')}
88
98
  label="Color"
99
+ CustomContainer={Container}
89
100
  >
90
101
  <SelectItem value="primary">Primary</SelectItem>
91
102
  <SelectItem value="secondary">Secondary</SelectItem>
@@ -144,6 +155,7 @@ const Example = ({ variant, native = false }) => {
144
155
  helperText="Helper text"
145
156
  children={children}
146
157
  placeholder="Empty"
158
+ CustomContainer={Container}
147
159
  />
148
160
  </Box>
149
161
  <Box mb={3} width={230}>
@@ -156,6 +168,7 @@ const Example = ({ variant, native = false }) => {
156
168
  defaultValue="20"
157
169
  helperText="Helper text"
158
170
  children={children}
171
+ CustomContainer={Container}
159
172
  />
160
173
  </Box>
161
174
  <Box mb={3} width={230}>
@@ -166,6 +179,7 @@ const Example = ({ variant, native = false }) => {
166
179
  variant={variant}
167
180
  label="Standard"
168
181
  children={children}
182
+ CustomContainer={Container}
169
183
  />
170
184
  </Box>
171
185
  <Box mb={3} width={230}>
@@ -178,6 +192,7 @@ const Example = ({ variant, native = false }) => {
178
192
  helperText="Helper text"
179
193
  disabled
180
194
  children={children}
195
+ CustomContainer={Container}
181
196
  />
182
197
  </Box>
183
198
  <Box mb={3} width={230}>
@@ -189,6 +204,7 @@ const Example = ({ variant, native = false }) => {
189
204
  label=""
190
205
  helperText="Helper text"
191
206
  children={children}
207
+ CustomContainer={Container}
192
208
  />
193
209
  </Box>
194
210
  <Box mb={3} width={230}>
@@ -201,6 +217,7 @@ const Example = ({ variant, native = false }) => {
201
217
  helperText="Helper text"
202
218
  children={children}
203
219
  leadingIcon={<SearchIcon />}
220
+ CustomContainer={Container}
204
221
  />
205
222
  </Box>
206
223
  <Box mb={3} width={230}>
@@ -213,6 +230,7 @@ const Example = ({ variant, native = false }) => {
213
230
  helperText="Helper text"
214
231
  children={children}
215
232
  leadingIcon={<SearchIcon />}
233
+ CustomContainer={Container}
216
234
  />
217
235
  </Box>
218
236
  </Box>
@@ -221,6 +239,9 @@ const Example = ({ variant, native = false }) => {
221
239
  };
222
240
 
223
241
  export const Filled = () => <Example variant="filled" />;
242
+ export const CustomContainer = () => (
243
+ <Example CustomContainer={CustomContainerExample} />
244
+ );
224
245
  export const Outlined = () => <Example variant="outlined" />;
225
246
  export const FilledNative = () => <Example variant="filled" native />;
226
247
  export const OutlinedNative = () => <Example variant="outlined" native />;
@@ -14,6 +14,7 @@ import {
14
14
  import type { Theme } from '../theme';
15
15
  import { useTheme } from '../theme';
16
16
  import { Select as SelectComp, SelectButton } from './styledComponents';
17
+ import type { FilledContainerProps } from '../TextField/FilledContainer';
17
18
  import { FilledContainer } from '../TextField/FilledContainer';
18
19
  import { HelperText } from '../TextField/HelperText';
19
20
  import { OutlinedContainer } from '../TextField/OutlinedContainer';
@@ -48,6 +49,7 @@ export interface SelectProps
48
49
  onChange?: (e: ChangeEvent<HTMLSelectElement>, value: string) => void;
49
50
  renderValue?: (value?: string) => string | undefined;
50
51
  leadingIcon?: ReactNode;
52
+ CustomContainer?: ComponentType<FilledContainerProps>;
51
53
  }
52
54
 
53
55
  export const Select = forwardRef<
@@ -73,6 +75,7 @@ export const Select = forwardRef<
73
75
  children,
74
76
  renderValue: renderValueProp,
75
77
  leadingIcon = null,
78
+ CustomContainer: overwrittenContainer,
76
79
  ...otherProps
77
80
  } = props;
78
81
  const [value, onChange] = useControlledState(
@@ -89,7 +92,8 @@ export const Select = forwardRef<
89
92
  const fallbackId = useId();
90
93
  const theme = useTheme();
91
94
 
92
- const Container = componentMap[variant] || OutlinedContainer;
95
+ const Container =
96
+ overwrittenContainer || componentMap[variant] || OutlinedContainer;
93
97
 
94
98
  const handleFocus = () => {
95
99
  setHasFocus(true);
@@ -147,7 +151,7 @@ export const Select = forwardRef<
147
151
  labelIsFloating={labelIsFloating}
148
152
  inputId={inputId}
149
153
  hasFocus={hasFocus}
150
- disabled={disabled}
154
+ disabled={disabled ?? false}
151
155
  forceActive={open}
152
156
  error={hasError}
153
157
  leadingIcon={Boolean(leadingIcon)}
@@ -24,9 +24,10 @@ const makeSelector = (
24
24
  `input:${state} ~ &,` +
25
25
  `select:${state} ~ &,` +
26
26
  `button:${state} ~ &,` +
27
- `textarea:${state} ~ &`;
27
+ `textarea:${state} ~ &,` +
28
+ `[role="button"]:${state} ~ &`;
28
29
 
29
- const Overlay = (props: { forceActive?: boolean }) => {
30
+ export const FilledContainerOverlay = (props: { forceActive?: boolean }) => {
30
31
  const { forceActive } = props;
31
32
  const theme = useTheme();
32
33
 
@@ -60,7 +61,7 @@ const Overlay = (props: { forceActive?: boolean }) => {
60
61
  );
61
62
  };
62
63
 
63
- const BorderBottom = () => (
64
+ const FilledContainerBorderBottom = () => (
64
65
  <Box
65
66
  __css={{
66
67
  position: 'absolute',
@@ -163,8 +164,8 @@ export const FilledContainer = forwardRef<HTMLDivElement, FilledContainerProps>(
163
164
 
164
165
  {children}
165
166
 
166
- <Overlay forceActive={active} />
167
- <BorderBottom />
167
+ <FilledContainerOverlay forceActive={active} />
168
+ <FilledContainerBorderBottom />
168
169
  <LineRipple active={active || error} color={color} />
169
170
  </Box>
170
171
  );
@@ -1,9 +1,10 @@
1
1
  import type { ComponentType } from 'react';
2
2
  import { useState, useMemo, useEffect } from 'react';
3
3
  import {
4
- CorePalette,
5
4
  argbFromHex,
6
5
  hexFromArgb,
6
+ TonalPalette,
7
+ HCT,
7
8
  } from '@material/material-color-utilities';
8
9
  import type { Color } from '@basic-ui/color-picker';
9
10
  import { toColor } from '@basic-ui/color-picker';
@@ -98,10 +99,20 @@ const ThemeBuilderImpl = (props: ThemeBuilderProps) => {
98
99
  'primary'
99
100
  );
100
101
 
101
- const { a1, a2, a3, error, n1, n2 } = useMemo(
102
- () => CorePalette.of(argbFromHex(primaryColor.hex)),
103
- [primaryColor.hex]
104
- );
102
+ const { a1, a2, a3, error, n1, n2 } = useMemo(() => {
103
+ /* This is from CorePalette.of(...) */
104
+ const argb = argbFromHex(primaryColor.hex);
105
+ const hct = HCT.fromInt(argb);
106
+ const hue = hct.hue;
107
+ return {
108
+ a1: TonalPalette.fromHueAndChroma(hue, Math.max(48, hct.chroma)),
109
+ a2: TonalPalette.fromHueAndChroma(hue, 16),
110
+ a3: TonalPalette.fromHueAndChroma(hue + 60, 24),
111
+ n1: TonalPalette.fromHueAndChroma(hue, 6),
112
+ n2: TonalPalette.fromHueAndChroma(hue, 8),
113
+ error: TonalPalette.fromHueAndChroma(25, 84),
114
+ };
115
+ }, [primaryColor.hex]);
105
116
 
106
117
  const [secondaryColor, secondaryColorTonal, setSecondaryColor] =
107
118
  useDeferredColor('secondary', a2);
@@ -43,33 +43,57 @@ export const ThemeColors = memo(
43
43
  <ColorRow
44
44
  colors={[
45
45
  {
46
- token: `background`,
47
- bg: scheme.background,
48
- color: scheme.on.background,
46
+ token: `surface-dim`,
47
+ bg: scheme['surface-dim'],
48
+ color: scheme.on['surface'],
49
49
  },
50
50
  {
51
- token: `on.background`,
52
- bg: scheme.on.background,
53
- color: scheme.background,
51
+ token: `surface`,
52
+ bg: scheme['surface'],
53
+ color: scheme.on['surface'],
54
54
  },
55
55
  {
56
- token: `surface`,
57
- bg: scheme.surface,
58
- color: scheme.on.surface,
56
+ token: `surface-bright`,
57
+ bg: scheme['surface-bright'],
58
+ color: scheme.on['surface'],
59
59
  },
60
+ ]}
61
+ />
62
+ <ColorRow
63
+ colors={[
60
64
  {
61
- token: `on.surface`,
62
- bg: scheme.on.surface,
63
- color: scheme.surface,
65
+ token: `surface-container-lowest`,
66
+ bg: scheme['surface-container-lowest'],
67
+ color: scheme.on['surface'],
68
+ },
69
+ {
70
+ token: `surface-container-low`,
71
+ bg: scheme['surface-container-low'],
72
+ color: scheme.on['surface'],
73
+ },
74
+ {
75
+ token: `surface-container`,
76
+ bg: scheme['surface-container'],
77
+ color: scheme.on['surface'],
78
+ },
79
+ {
80
+ token: `surface-container-high`,
81
+ bg: scheme['surface-container-high'],
82
+ color: scheme.on['surface'],
83
+ },
84
+ {
85
+ token: `surface-container-highest`,
86
+ bg: scheme['surface-container-highest'],
87
+ color: scheme.on['surface'],
64
88
  },
65
89
  ]}
66
90
  />
67
91
  <ColorRow
68
92
  colors={[
69
93
  {
70
- token: `surface-variant`,
71
- bg: scheme['surface-variant'],
72
- color: scheme.on['surface-variant'],
94
+ token: `on.surface`,
95
+ bg: scheme.on['surface'],
96
+ color: scheme['surface'],
73
97
  },
74
98
  {
75
99
  token: `on.surface-variant`,
@@ -10,9 +10,9 @@ export const ColorItem = memo(
10
10
  token: string;
11
11
  style: CSSProperties;
12
12
  height?: number;
13
- width: string;
13
+ flex: number;
14
14
  }) => {
15
- const { token, style, width, height = '100%' } = props;
15
+ const { token, style, flex, height = '100%' } = props;
16
16
  const [computedColor, setComputedColor] = useState<string>();
17
17
  const hslColor = computedColor
18
18
  ? parseToHsl(computedColor)
@@ -43,7 +43,7 @@ export const ColorItem = memo(
43
43
  >
44
44
  <Text
45
45
  as="div"
46
- variant="body-small"
46
+ variant="body-medium"
47
47
  style={style}
48
48
  ref={(ref: HTMLDivElement | null) => {
49
49
  if (ref) {
@@ -51,12 +51,10 @@ export const ColorItem = memo(
51
51
  }
52
52
  }}
53
53
  sx={{
54
- width,
54
+ flex,
55
55
  height,
56
- px: '10px',
57
- py: '10px',
58
- fontSize: '11px',
59
- lineHeight: '11px',
56
+ px: '12px',
57
+ py: '12px',
60
58
  textOverflow: 'ellipsis',
61
59
  overflow: 'hidden',
62
60
  }}
@@ -80,27 +78,21 @@ export const ColorRow = memo(
80
78
  display="flex"
81
79
  sx={{
82
80
  ':first-of-type': {
83
- borderTopLeftRadius: 'extra-large',
84
- borderTopRightRadius: 'extra-large',
81
+ borderTopLeftRadius: 'large',
82
+ borderTopRightRadius: 'large',
85
83
  overflow: 'hidden',
86
84
  },
87
85
  ':last-of-type': {
88
- borderBottomLeftRadius: 'extra-large',
89
- borderBottomRightRadius: 'extra-large',
86
+ borderBottomLeftRadius: 'large',
87
+ borderBottomRightRadius: 'large',
90
88
  overflow: 'hidden',
91
89
  },
92
90
  height,
93
91
  }}
94
92
  >
95
- {colors.map(({ token, bg, color }, idx) => (
93
+ {colors.map(({ token, bg, color }) => (
96
94
  <ColorItem
97
- width={
98
- colors.length % 2 === 1
99
- ? idx === colors.length - 1
100
- ? '50%'
101
- : '25%'
102
- : '33.33%'
103
- }
95
+ flex={1}
104
96
  key={token}
105
97
  token={token}
106
98
  style={{ backgroundColor: bg, color: color }}
@@ -22,11 +22,19 @@ export function makeColorScheme(opts: {
22
22
  'secondary-container': c(opts.secondary, 90),
23
23
  'tertiary-container': c(opts.tertiary, 90),
24
24
  'error-container': c(opts.error, 90),
25
- background: c(opts.neutral, 99),
26
- surface: c(opts.neutral, 99),
25
+ background: c(opts.neutral, 98),
27
26
  'surface-variant': c(opts.neutralVariant, 90),
28
27
  outline: c(opts.neutralVariant, 50),
29
28
  'outline-variant': c(opts.neutralVariant, 80),
29
+ // https://material.io/blog/tone-based-surface-color-m3
30
+ 'surface-dim': c(opts.neutral, 87),
31
+ surface: c(opts.neutral, 98),
32
+ 'surface-bright': c(opts.neutral, 98),
33
+ 'surface-container-lowest': c(opts.neutral, 100),
34
+ 'surface-container-low': c(opts.neutral, 96),
35
+ 'surface-container': c(opts.neutral, 94),
36
+ 'surface-container-high': c(opts.neutral, 92),
37
+ 'surface-container-highest': c(opts.neutral, 90),
30
38
  on: {
31
39
  primary: c(opts.primary, 100),
32
40
  secondary: c(opts.secondary, 100),
@@ -37,10 +45,18 @@ export function makeColorScheme(opts: {
37
45
  'tertiary-container': c(opts.tertiary, 10),
38
46
  'error-container': c(opts.error, 10),
39
47
  background: c(opts.neutral, 10),
40
- surface: c(opts.neutral, 10),
41
48
  'surface-variant': c(opts.neutralVariant, 30),
42
49
  outline: c(opts.neutralVariant, 95),
43
50
  'outline-variant': c(opts.neutralVariant, 10),
51
+ // https://material.io/blog/tone-based-surface-color-m3
52
+ 'surface-dim': c(opts.neutral, 10),
53
+ surface: c(opts.neutral, 10),
54
+ 'surface-bright': c(opts.neutral, 10),
55
+ 'surface-container-lowest': c(opts.neutral, 10),
56
+ 'surface-container-low': c(opts.neutral, 10),
57
+ 'surface-container': c(opts.neutral, 10),
58
+ 'surface-container-high': c(opts.neutral, 10),
59
+ 'surface-container-highest': c(opts.neutral, 10),
44
60
  },
45
61
  modes: {
46
62
  dark: {
@@ -52,11 +68,20 @@ export function makeColorScheme(opts: {
52
68
  'secondary-container': c(opts.secondary, 30),
53
69
  'tertiary-container': c(opts.tertiary, 30),
54
70
  'error-container': c(opts.error, 30),
55
- background: c(opts.neutral, 10),
56
- surface: c(opts.neutral, 10),
71
+ background: c(opts.neutral, 6),
57
72
  'surface-variant': c(opts.neutralVariant, 30),
58
73
  outline: c(opts.neutralVariant, 60),
59
74
  'outline-variant': c(opts.neutralVariant, 30),
75
+ // https://material.io/blog/tone-based-surface-color-m3
76
+ // TODO: get the actual values from here once updated: https://github.com/material-foundation/material-color-utilities/blob/main/dart/lib/scheme/scheme.dart#L126-L156
77
+ 'surface-dim': c(opts.neutral, 6),
78
+ surface: c(opts.neutral, 6),
79
+ 'surface-bright': c(opts.neutral, 24),
80
+ 'surface-container-lowest': c(opts.neutral, 4),
81
+ 'surface-container-low': c(opts.neutral, 10),
82
+ 'surface-container': c(opts.neutral, 12),
83
+ 'surface-container-high': c(opts.neutral, 17),
84
+ 'surface-container-highest': c(opts.neutral, 22),
60
85
  on: {
61
86
  primary: c(opts.primary, 20),
62
87
  secondary: c(opts.secondary, 20),
@@ -67,10 +92,18 @@ export function makeColorScheme(opts: {
67
92
  'tertiary-container': c(opts.tertiary, 90),
68
93
  'error-container': c(opts.error, 90),
69
94
  background: c(opts.neutral, 90),
70
- surface: c(opts.neutral, 90),
71
95
  'surface-variant': c(opts.neutralVariant, 80),
72
96
  outline: c(opts.neutralVariant, 10),
73
97
  'outline-variant': c(opts.neutralVariant, 90),
98
+ // https://material.io/blog/tone-based-surface-color-m3
99
+ 'surface-dim': c(opts.neutral, 90),
100
+ surface: c(opts.neutral, 90),
101
+ 'surface-bright': c(opts.neutral, 90),
102
+ 'surface-container-lowest': c(opts.neutral, 90),
103
+ 'surface-container-low': c(opts.neutral, 90),
104
+ 'surface-container': c(opts.neutral, 90),
105
+ 'surface-container-high': c(opts.neutral, 90),
106
+ 'surface-container-highest': c(opts.neutral, 90),
74
107
  },
75
108
  },
76
109
  },