@sanity/ui 1.8.2 → 2.0.0-alpha.2

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 (49) hide show
  1. package/dist/index.d.ts +42 -11
  2. package/dist/index.esm.js +335 -116
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/index.js +334 -115
  5. package/dist/index.js.map +1 -1
  6. package/package.json +34 -16
  7. package/src/components/autocomplete/autocomplete.tsx +2 -1
  8. package/src/components/dialog/dialog.tsx +3 -3
  9. package/src/components/hotkeys/hotkeys.tsx +2 -1
  10. package/src/components/menu/menuButton.tsx +2 -2
  11. package/src/components/menu/menuGroup.tsx +2 -2
  12. package/src/components/tab/tab.tsx +2 -1
  13. package/src/primitives/avatar/styles.ts +1 -1
  14. package/src/primitives/button/button.tsx +6 -7
  15. package/src/primitives/button/styles.ts +20 -3
  16. package/src/primitives/card/styles.ts +1 -1
  17. package/src/primitives/checkbox/checkbox.tsx +1 -0
  18. package/src/primitives/checkbox/styles.ts +47 -17
  19. package/src/primitives/kbd/kbd.tsx +6 -6
  20. package/src/primitives/popover/popoverCard.tsx +2 -2
  21. package/src/primitives/radio/radio.tsx +1 -0
  22. package/src/primitives/radio/styles.ts +17 -4
  23. package/src/primitives/select/select.tsx +3 -2
  24. package/src/primitives/select/styles.ts +2 -1
  25. package/src/primitives/switch/__workshop__/props.tsx +4 -4
  26. package/src/primitives/switch/styles.ts +19 -12
  27. package/src/primitives/text/styles.ts +1 -0
  28. package/src/primitives/textInput/textInput.tsx +2 -1
  29. package/src/primitives/tooltip/tooltip.tsx +2 -2
  30. package/src/primitives/types.ts +3 -2
  31. package/src/styles/colorVars/colorVarsStyle.ts +2 -0
  32. package/src/styles/focusRing/index.ts +3 -1
  33. package/src/styles/input/textInputStyle.ts +2 -1
  34. package/src/styles/radius/radiusStyle.ts +14 -4
  35. package/src/styles/radius/types.ts +3 -1
  36. package/src/theme/lib/theme/avatar.ts +3 -0
  37. package/src/theme/lib/theme/color/_generic/types.ts +1 -0
  38. package/src/theme/lib/theme/color/color.test.ts +1 -0
  39. package/src/theme/lib/theme/color/defaults.ts +8 -0
  40. package/src/theme/lib/theme/color/input/types.ts +1 -0
  41. package/src/theme/lib/theme/input.ts +11 -0
  42. package/src/theme/lib/theme/theme.ts +7 -1
  43. package/src/theme/studioTheme/color.ts +82 -70
  44. package/src/theme/studioTheme/fonts.ts +3 -3
  45. package/src/theme/studioTheme/theme.ts +17 -3
  46. package/src/theme/studioTheme/tints.ts +152 -0
  47. package/src/theme/types.ts +8 -0
  48. package/src/types/index.ts +1 -0
  49. package/src/types/radius.ts +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/ui",
3
- "version": "1.8.2",
3
+ "version": "2.0.0-alpha.2",
4
4
  "sideEffects": false,
5
5
  "types": "./dist/index.d.ts",
6
6
  "source": "./src/index.ts",
@@ -46,53 +46,70 @@
46
46
  "watch": "pkg watch --strict",
47
47
  "workshop:build": "node -r esbuild-register -r tsconfig-paths/register scripts/build",
48
48
  "workshop:dev": "node -r esbuild-register -r tsconfig-paths/register scripts/dev",
49
- "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist"
49
+ "workshop:start": "http-server -a localhost -c-0 -p 1337 -s -P http://localhost:1337/index.html? dist",
50
+ "storybook": "storybook dev -p 6006",
51
+ "build-storybook": "storybook build"
50
52
  },
51
53
  "dependencies": {
52
54
  "@floating-ui/react-dom": "2.0.0",
53
55
  "@sanity/color": "^2.2.5",
54
56
  "@sanity/icons": "^2.4.1",
55
57
  "csstype": "^3.1.2",
56
- "framer-motion": "^10.16.1",
58
+ "framer-motion": "^10.16.2",
57
59
  "react-refractor": "^2.1.7"
58
60
  },
59
61
  "devDependencies": {
60
- "@babel/core": "^7.22.10",
61
- "@babel/preset-env": "^7.22.10",
62
+ "@babel/core": "^7.22.11",
63
+ "@babel/preset-env": "^7.22.14",
62
64
  "@babel/preset-react": "^7.22.5",
63
- "@babel/preset-typescript": "^7.22.5",
65
+ "@babel/preset-typescript": "^7.22.11",
64
66
  "@commitlint/cli": "^17.7.1",
65
67
  "@commitlint/config-conventional": "^17.7.0",
66
68
  "@juggle/resize-observer": "^3.4.0",
67
69
  "@sanity/pkg-utils": "^2.4.8",
68
- "@sanity/semantic-release-preset": "^4.1.3",
70
+ "@sanity/semantic-release-preset": "^4.1.4",
69
71
  "@sanity/ui-workshop": "^1.2.11",
72
+ "@storybook/addon-a11y": "^7.4.5",
73
+ "@storybook/addon-docs": "^7.4.5",
74
+ "@storybook/addon-essentials": "^7.4.5",
75
+ "@storybook/addon-interactions": "^7.4.5",
76
+ "@storybook/addon-links": "^7.4.5",
77
+ "@storybook/addon-storysource": "^7.4.5",
78
+ "@storybook/addon-themes": "^7.4.5",
79
+ "@storybook/blocks": "^7.4.5",
80
+ "@storybook/jest": "^0.2.2",
81
+ "@storybook/manager-api": "^7.4.5",
82
+ "@storybook/react": "^7.4.5",
83
+ "@storybook/react-vite": "^7.4.5",
84
+ "@storybook/testing-library": "^0.2.1",
85
+ "@storybook/theming": "^7.4.5",
70
86
  "@testing-library/dom": "^9.3.1",
71
87
  "@testing-library/jest-dom": "^5.17.0",
72
88
  "@testing-library/react": "^14.0.0",
73
89
  "@types/jest": "^29.5.4",
74
90
  "@types/jest-axe": "^3.5.5",
75
- "@types/node": "^20.5.4",
91
+ "@types/node": "^20.5.9",
76
92
  "@types/react": "^18.2.21",
77
93
  "@types/react-dom": "^18.2.7",
78
94
  "@types/react-is": "^18.2.1",
79
95
  "@types/refractor": "^3.0.2",
80
96
  "@types/testing-library__jest-dom": "^5.14.9",
81
- "@typescript-eslint/eslint-plugin": "^6.4.1",
82
- "@typescript-eslint/parser": "^6.4.1",
97
+ "@typescript-eslint/eslint-plugin": "^6.5.0",
98
+ "@typescript-eslint/parser": "^6.5.0",
83
99
  "commitizen": "^4.3.0",
84
- "cypress": "^12.17.4",
85
- "cypress-real-events": "^1.10.0",
100
+ "cypress": "^13.1.0",
101
+ "cypress-real-events": "^1.10.1",
86
102
  "cz-conventional-changelog": "^3.3.0",
87
103
  "esbuild": "^0.19.2",
88
104
  "esbuild-register": "^3.4.2",
89
- "eslint": "^8.47.0",
105
+ "eslint": "^8.48.0",
90
106
  "eslint-config-prettier": "^9.0.0",
91
107
  "eslint-plugin-import": "^2.28.1",
92
108
  "eslint-plugin-jsx-a11y": "^6.7.1",
93
109
  "eslint-plugin-prettier": "^5.0.0",
94
110
  "eslint-plugin-react": "^7.33.2",
95
111
  "eslint-plugin-react-hooks": "^4.6.0",
112
+ "eslint-plugin-storybook": "^0.6.14",
96
113
  "http-server": "^14.1.1",
97
114
  "husky": "^8.0.3",
98
115
  "jest": "^29.6.4",
@@ -101,17 +118,18 @@
101
118
  "lint-staged": "^14.0.1",
102
119
  "module-alias": "^2.2.3",
103
120
  "npm-run-all": "^4.1.5",
104
- "prettier": "^3.0.2",
121
+ "prettier": "^3.0.3",
105
122
  "react": "^18.2.0",
106
123
  "react-dom": "^18.2.0",
107
124
  "react-is": "^18.2.0",
108
125
  "refractor": "^4.8.1",
109
126
  "rimraf": "^5.0.1",
110
- "semantic-release": "^21.1.0",
127
+ "semantic-release": "^21.1.1",
111
128
  "start-server-and-test": "^2.0.0",
129
+ "storybook": "^7.4.5",
112
130
  "styled-components": "^6.0.7",
113
131
  "tsconfig-paths": "^4.2.0",
114
- "typescript": "^5.1.6"
132
+ "typescript": "^5.2.2"
115
133
  },
116
134
  "peerDependencies": {
117
135
  "react": "^18",
@@ -31,6 +31,7 @@ import {
31
31
  Text,
32
32
  TextInput,
33
33
  } from '../../primitives'
34
+ import {Radius} from '../../types'
34
35
  import {AnimatedSpinnerIcon, ListBox, Root} from './autocomplete.styles'
35
36
  import {AutocompleteOption} from './autocompleteOption'
36
37
  import {autocompleteReducer} from './autocompleteReducer'
@@ -64,7 +65,7 @@ export interface AutocompleteProps<Option extends BaseAutocompleteOption = BaseA
64
65
  popover?: Omit<PopoverProps, 'content' | 'onMouseEnter' | 'onMouseLeave' | 'open'> &
65
66
  Omit<HTMLProps<HTMLDivElement>, 'as' | 'children' | 'content' | 'ref' | 'width'>
66
67
  prefix?: ReactNode
67
- radius?: number | number[]
68
+ radius?: Radius | Radius[]
68
69
  /** @beta */
69
70
  relatedElements?: HTMLElement[]
70
71
  renderOption?: (option: Option) => ReactElement
@@ -12,7 +12,7 @@ import {Box, Button, Card, Container, Flex, Text} from '../../primitives'
12
12
  import {ResponsivePaddingProps, ResponsiveWidthProps} from '../../primitives/types'
13
13
  import {responsivePaddingStyle, ResponsivePaddingStyleProps} from '../../styles/internal'
14
14
  import {ThemeColorSchemeKey, useTheme} from '../../theme'
15
- import {DialogPosition} from '../../types'
15
+ import {DialogPosition, Radius} from '../../types'
16
16
  import {Layer, LayerProps, Portal, useBoundaryElement, useLayer, usePortal} from '../../utils'
17
17
  import {
18
18
  dialogStyle,
@@ -33,7 +33,7 @@ export interface DialogProps extends ResponsivePaddingProps, ResponsiveWidthProp
33
33
  * @beta
34
34
  */
35
35
  __unstable_hideCloseButton?: boolean
36
- cardRadius?: number | number[]
36
+ cardRadius?: Radius | Radius[]
37
37
  cardShadow?: number | number[]
38
38
  contentRef?: React.ForwardedRef<HTMLDivElement>
39
39
  footer?: React.ReactNode
@@ -66,7 +66,7 @@ interface DialogCardProps extends ResponsiveWidthProps {
66
66
  onClickOutside?: () => void
67
67
  onClose?: () => void
68
68
  portal?: string
69
- radius: number | number[]
69
+ radius: Radius | Radius[]
70
70
  scheme?: ThemeColorSchemeKey
71
71
  shadow: number | number[]
72
72
  }
@@ -2,6 +2,7 @@ import {forwardRef} from 'react'
2
2
  import styled from 'styled-components'
3
3
  import {useArrayProp} from '../../hooks'
4
4
  import {Inline, KBD} from '../../primitives'
5
+ import {Radius} from '../../types'
5
6
 
6
7
  /**
7
8
  * @public
@@ -9,7 +10,7 @@ import {Inline, KBD} from '../../primitives'
9
10
  export interface HotkeysProps {
10
11
  fontSize?: number | number[]
11
12
  padding?: number | number[]
12
- radius?: number | number[]
13
+ radius?: Radius | Radius[]
13
14
  space?: number | number[]
14
15
  keys?: string[]
15
16
  }
@@ -2,7 +2,7 @@ import {cloneElement, forwardRef, useCallback, useMemo, useState, useEffect, use
2
2
  import {isElement} from 'react-is'
3
3
  import {Popover, PopoverProps} from '../../primitives'
4
4
  import {ThemeColorSchemeKey} from '../../theme'
5
- import {Placement} from '../../types'
5
+ import {Placement, Radius} from '../../types'
6
6
  import {MenuProps} from './menu'
7
7
 
8
8
  /**
@@ -34,7 +34,7 @@ export interface MenuButtonProps {
34
34
  /**
35
35
  * @deprecated Use `popover={{radius: 2}}` instead.
36
36
  */
37
- popoverRadius?: number | number[]
37
+ popoverRadius?: Radius | Radius[]
38
38
  /**
39
39
  * @beta Do not use in production.
40
40
  * @deprecated Use `popover={{portal: true}}` instead.
@@ -4,7 +4,7 @@ import {isValidElementType} from 'react-is'
4
4
  import {useArrayProp} from '../../hooks'
5
5
  import {Box, Flex, Popover, PopoverProps, Text} from '../../primitives'
6
6
  import {Selectable} from '../../primitives/_selectable'
7
- import {SelectableTone} from '../../types/selectable'
7
+ import {Radius, SelectableTone} from '../../types'
8
8
  import {Menu} from './menu'
9
9
  import {useMenu} from './useMenu'
10
10
 
@@ -17,7 +17,7 @@ export interface MenuGroupProps {
17
17
  icon?: React.ElementType | React.ReactNode
18
18
  padding?: number | number[]
19
19
  popover?: Omit<PopoverProps, 'content' | 'open'>
20
- radius?: number | number[]
20
+ radius?: Radius | Radius[]
21
21
  space?: number | number[]
22
22
  text: React.ReactNode
23
23
  tone?: SelectableTone
@@ -38,7 +38,7 @@ export const Tab = forwardRef(function Tab(
38
38
  icon,
39
39
  id,
40
40
  focused,
41
- fontSize,
41
+ fontSize = 1,
42
42
  label,
43
43
  onClick,
44
44
  onFocus,
@@ -88,6 +88,7 @@ export const Tab = forwardRef(function Tab(
88
88
  onBlur={handleBlur}
89
89
  onFocus={handleFocus}
90
90
  padding={padding}
91
+ radius="full"
91
92
  ref={setRef}
92
93
  role="tab"
93
94
  selected={selected}
@@ -57,7 +57,7 @@ function avatarArrowStyle(): CSSObject {
57
57
 
58
58
  export function avatarRootStyle(props: AvatarRootStyleProps & ThemeProps): CSSObject {
59
59
  const {$color, theme} = props
60
- const {focusRing} = theme.sanity
60
+ const {focusRing} = theme.sanity.avatar
61
61
 
62
62
  return {
63
63
  backgroundColor: $color,
@@ -30,6 +30,7 @@ export interface ButtonProps extends ResponsivePaddingProps, ResponsiveRadiusPro
30
30
  selected?: boolean
31
31
  space?: number | number[]
32
32
  textAlign?: ButtonTextAlign
33
+ muted?: boolean
33
34
  text?: React.ReactNode
34
35
  tone?: ButtonTone
35
36
  type?: 'button' | 'reset' | 'submit'
@@ -64,7 +65,7 @@ export const Button = forwardRef(function Button(
64
65
  const {
65
66
  children,
66
67
  disabled,
67
- fontSize,
68
+ fontSize = 1,
68
69
  icon,
69
70
  iconRight,
70
71
  justify: justifyProp = 'center',
@@ -84,6 +85,7 @@ export const Button = forwardRef(function Button(
84
85
  textAlign,
85
86
  tone = 'default',
86
87
  type = 'button',
88
+ muted = false,
87
89
  ...restProps
88
90
  } = props
89
91
 
@@ -135,7 +137,7 @@ export const Button = forwardRef(function Button(
135
137
 
136
138
  {(icon || text || iconRight) && (
137
139
  <Box as="span" {...boxProps}>
138
- <Flex as="span" justify={justify}>
140
+ <Flex as="span" justify={justify} gap={space}>
139
141
  {icon && (
140
142
  <Text size={fontSize}>
141
143
  {isValidElement(icon) && icon}
@@ -144,12 +146,9 @@ export const Button = forwardRef(function Button(
144
146
  )}
145
147
 
146
148
  {text && (
147
- <Box
148
- flex={iconRight ? 1 : undefined}
149
- marginLeft={icon ? space : undefined}
150
- marginRight={iconRight ? space : undefined}
151
- >
149
+ <Box flex={iconRight ? 1 : undefined}>
152
150
  <Text
151
+ muted={muted}
153
152
  align={textAlign}
154
153
  size={fontSize}
155
154
  textOverflow="ellipsis"
@@ -42,6 +42,11 @@ export function buttonBaseStyles(): ReturnType<typeof css> {
42
42
  }
43
43
 
44
44
  const buttonTheme = {border: {width: 1}}
45
+ const defaultBoxShadow = '0px 2px 0px 0px rgba(112, 128, 155, 0.19);'
46
+
47
+ function combineBoxShadow(...boxShadows: (string | undefined)[]): string {
48
+ return boxShadows.filter(Boolean).join(',')
49
+ }
45
50
 
46
51
  /**
47
52
  * @internal
@@ -50,7 +55,8 @@ export function buttonColorStyles(
50
55
  props: {$mode: ButtonMode; $tone: ButtonTone} & ThemeProps,
51
56
  ): CSSObject[] {
52
57
  const {$mode, theme} = props
53
- const {focusRing} = theme.sanity
58
+ const {focusRing} = theme.sanity.button
59
+ const shadow = props.$mode !== 'bleed'
54
60
  const base = theme.sanity.color.base
55
61
  const mode = theme.sanity.color.button[$mode] || theme.sanity.color.button.default
56
62
  const color = mode[props.$tone] || mode.default
@@ -64,11 +70,22 @@ export function buttonColorStyles(
64
70
  boxShadow: focusRingBorderStyle(border),
65
71
  '&:disabled, &[data-disabled="true"]': _colorVarsStyle(base, color.disabled),
66
72
  "&:not([data-disabled='true'])": {
73
+ boxShadow: combineBoxShadow(
74
+ focusRingBorderStyle(border),
75
+ shadow ? defaultBoxShadow : undefined,
76
+ ),
67
77
  '&:focus': {
68
- boxShadow: focusRingStyle({base, border, focusRing}),
78
+ boxShadow: focusRingStyle({
79
+ base,
80
+ border: {width: 2, color: base.bg},
81
+ focusRing,
82
+ }),
69
83
  },
70
84
  '&:focus:not(:focus-visible)': {
71
- boxShadow: focusRingBorderStyle(border),
85
+ boxShadow: combineBoxShadow(
86
+ focusRingBorderStyle(border),
87
+ shadow ? defaultBoxShadow : undefined,
88
+ ),
72
89
  },
73
90
  '@media (hover: hover)': {
74
91
  '&:hover': _colorVarsStyle(base, color.hovered),
@@ -47,7 +47,7 @@ export function cardBaseStyle(props: CardStyleProps & ThemeProps): ReturnType<ty
47
47
 
48
48
  export function cardColorStyle(props: CardStyleProps & ThemeProps): ReturnType<typeof css> {
49
49
  const {$checkered, $focusRing, theme} = props
50
- const {focusRing} = theme.sanity
50
+ const {focusRing} = theme.sanity.card
51
51
  const {base, card, dark} = theme.sanity.color
52
52
  const border = {width: 0, color: 'var(--card-border-color)'}
53
53
 
@@ -47,6 +47,7 @@ export const Checkbox = forwardRef(function Checkbox(
47
47
  <Root className={className} data-ui="Checkbox" style={style}>
48
48
  <Input
49
49
  data-read-only={!disabled && readOnly ? '' : undefined}
50
+ data-error={customValidity ? '' : undefined}
50
51
  {...restProps}
51
52
  checked={checked}
52
53
  disabled={disabled || readOnly}
@@ -12,7 +12,8 @@ export function checkboxBaseStyles(): ReturnType<typeof css> {
12
12
  export function inputElementStyles(props: ThemeProps): ReturnType<typeof css> {
13
13
  const {theme} = props
14
14
  const color = theme.sanity.color.input
15
- const {focusRing, input, radius} = theme.sanity
15
+ const {input, radius} = theme.sanity
16
+ const {focusRing} = input.checkbox
16
17
 
17
18
  return css`
18
19
  position: absolute;
@@ -49,27 +50,58 @@ export function inputElementStyles(props: ThemeProps): ReturnType<typeof css> {
49
50
 
50
51
  & > path {
51
52
  vector-effect: non-scaling-stroke;
52
- stroke-width: 2 !important;
53
+ stroke-width: 1.2 !important;
53
54
  }
54
55
  }
55
56
  }
57
+ &:checked + span {
58
+ background: ${color.default.enabled.bg2};
59
+ box-shadow: ${focusRingBorderStyle({
60
+ color: color.default.enabled.bg2,
61
+ width: input.border.width,
62
+ })};
63
+ color: ${color.default.enabled.bg};
64
+ }
65
+
66
+ /* focus */
67
+ &:not(:disabled):focus:focus-visible + span {
68
+ box-shadow: ${focusRingStyle({focusRing})};
69
+ }
70
+
71
+ /* focus when checked - uses a different offset */
72
+ &:not(:disabled):focus:focus-visible&:checked + span {
73
+ box-shadow: ${focusRingStyle({focusRing: {width: 1, offset: 1}})};
74
+ }
56
75
 
57
- &:not(:disabled):focus + span {
76
+ &[data-error] + span {
77
+ background-color: ${color.invalid.enabled.border};
78
+ box-shadow: ${focusRingBorderStyle({
79
+ width: input.border.width,
80
+ color: color.invalid.enabled.bg2,
81
+ })};
82
+ color: ${color.default.disabled.fg};
83
+ }
84
+ &[data-error]&:checked + span {
85
+ background-color: ${color.invalid.enabled.bg2};
86
+ color: ${color.default.enabled.bg};
87
+ }
88
+ &[data-error]&:checked&:not(:disabled):focus:focus-visible + span {
58
89
  box-shadow: ${focusRingStyle({
59
- border: {width: input.border.width, color: color.default.enabled.border},
60
- focusRing,
90
+ border: {width: input.border.width, color: color.invalid.readOnly.bg2},
91
+ focusRing: {width: 1, offset: 1},
61
92
  })};
62
93
  }
63
94
 
64
- &:not(:disabled):focus:not(:focus-visible) + span {
95
+ &:disabled + span {
96
+ background-color: ${color.default.disabled.bg};
65
97
  box-shadow: ${focusRingBorderStyle({
66
- color: color.default.enabled.border,
67
98
  width: input.border.width,
99
+ color: color.default.disabled.border,
68
100
  })};
101
+ color: ${color.default.disabled.fg};
69
102
  }
70
-
71
- &:checked + span > svg:first-child {
72
- opacity: 1;
103
+ &:disabled&:checked + span {
104
+ background-color: ${color.default.disabled.bg2};
73
105
  }
74
106
 
75
107
  &[data-read-only] + span {
@@ -81,15 +113,13 @@ export function inputElementStyles(props: ThemeProps): ReturnType<typeof css> {
81
113
  color: ${color.default.readOnly.fg};
82
114
  }
83
115
 
84
- &:not([data-read-only]):disabled + span {
85
- background-color: ${color.default.disabled.bg};
86
- box-shadow: ${focusRingBorderStyle({
87
- width: input.border.width,
88
- color: color.default.disabled.border,
89
- })};
90
- color: ${color.default.disabled.fg};
116
+ &[data-read-only]&:checked + span {
117
+ background-color: ${color.default.readOnly.bg2};
91
118
  }
92
119
 
120
+ &:checked + span > svg:first-child {
121
+ opacity: 1;
122
+ }
93
123
  &:indeterminate + span > svg:last-child {
94
124
  opacity: 1;
95
125
  }
@@ -2,8 +2,9 @@ import {forwardRef} from 'react'
2
2
  import styled, {css} from 'styled-components'
3
3
  import {useArrayProp} from '../../hooks'
4
4
  import {responsiveRadiusStyle, ResponsiveRadiusStyleProps} from '../../styles/internal'
5
+ import {Radius} from '../../types'
5
6
  import {Box} from '../box'
6
- import {Code} from '../code'
7
+ import {Text} from '../text'
7
8
 
8
9
  /**
9
10
  * @public
@@ -12,14 +13,13 @@ export interface KBDProps {
12
13
  as?: React.ElementType | keyof JSX.IntrinsicElements
13
14
  fontSize?: number | number[]
14
15
  padding?: number | number[]
15
- radius?: number | number[]
16
+ radius?: Radius | Radius[]
16
17
  }
17
18
 
18
19
  function kbdStyle() {
19
20
  return css`
20
- background: var(--card-bg-color);
21
+ background: var(--card-bg2-color);
21
22
  font: inherit;
22
- box-shadow: inset 0 0 0 1px var(--card-hairline-hard-color);
23
23
 
24
24
  &:not([hidden]) {
25
25
  display: inline-block;
@@ -41,9 +41,9 @@ export const KBD = forwardRef(function KBD(
41
41
  return (
42
42
  <Root data-ui="KBD" {...restProps} $radius={useArrayProp(radius)} ref={ref}>
43
43
  <Box as="span" padding={padding}>
44
- <Code as="span" muted size={fontSize}>
44
+ <Text as="span" muted size={fontSize} weight="medium">
45
45
  {children}
46
- </Code>
46
+ </Text>
47
47
  </Box>
48
48
  </Root>
49
49
  )
@@ -3,7 +3,7 @@ import React, {CSSProperties, forwardRef, memo, useMemo} from 'react'
3
3
  import styled from 'styled-components'
4
4
  import {FLOATING_STATIC_SIDES} from '../../constants'
5
5
  import {ThemeColorSchemeKey} from '../../theme'
6
- import {BoxOverflow, CardTone, Placement, PopoverMargins} from '../../types'
6
+ import {BoxOverflow, CardTone, Placement, PopoverMargins, Radius} from '../../types'
7
7
  import {useLayer} from '../../utils'
8
8
  import {Card} from '../card'
9
9
  import {Flex} from '../flex'
@@ -34,7 +34,7 @@ export const PopoverCard = memo(
34
34
  overflow?: BoxOverflow
35
35
  padding?: number | number[]
36
36
  placement?: Placement
37
- radius?: number | number[]
37
+ radius?: Radius | Radius[]
38
38
  scheme?: ThemeColorSchemeKey
39
39
  shadow?: number | number[]
40
40
  strategy: Strategy
@@ -29,6 +29,7 @@ export const Radio = forwardRef(function Radio(
29
29
  <Root className={className} data-ui="Radio" style={style}>
30
30
  <Input
31
31
  data-read-only={!disabled && readOnly ? '' : undefined}
32
+ data-error={customValidity ? '' : undefined}
32
33
  {...restProps}
33
34
  disabled={disabled || readOnly}
34
35
  readOnly={readOnly}
@@ -18,7 +18,8 @@ export function radioBaseStyle(): ReturnType<typeof css> {
18
18
 
19
19
  export function inputElementStyle(props: ThemeProps): ReturnType<typeof css> {
20
20
  const {theme} = props
21
- const {focusRing, input} = theme.sanity
21
+ const {input} = theme.sanity
22
+ const {focusRing} = input.radio
22
23
  const color = theme.sanity.color.input
23
24
  const dist = (input.radio.size - input.radio.markSize) / 2
24
25
 
@@ -58,7 +59,7 @@ export function inputElementStyle(props: ThemeProps): ReturnType<typeof css> {
58
59
  height: ${rem(input.radio.markSize)};
59
60
  width: ${rem(input.radio.markSize)};
60
61
  border-radius: ${rem(input.radio.markSize / 2)};
61
- background: ${color.default.enabled.fg};
62
+ background: ${color.default.enabled.bg2};
62
63
  opacity: 0;
63
64
  }
64
65
  }
@@ -82,13 +83,25 @@ export function inputElementStyle(props: ThemeProps): ReturnType<typeof css> {
82
83
  opacity: 1;
83
84
  }
84
85
 
86
+ /* customValidity */
87
+ &[data-error] + span {
88
+ background-color: ${color.invalid.enabled.border};
89
+ box-shadow: ${focusRingBorderStyle({
90
+ width: input.border.width,
91
+ color: color.invalid.enabled.bg2,
92
+ })};
93
+ &::after {
94
+ background: ${color.invalid.enabled.bg2};
95
+ }
96
+ }
97
+
85
98
  /* read only */
86
99
  &[data-read-only] + span {
87
100
  box-shadow: 0 0 0 1px ${color.default.readOnly.border};
88
101
  background: ${color.default.readOnly.bg};
89
102
 
90
103
  &::after {
91
- background: ${color.default.readOnly.fg};
104
+ background: ${color.default.readOnly.border};
92
105
  }
93
106
  }
94
107
 
@@ -98,7 +111,7 @@ export function inputElementStyle(props: ThemeProps): ReturnType<typeof css> {
98
111
  background: ${color.default.disabled.bg};
99
112
 
100
113
  &::after {
101
- background: ${color.default.disabled.fg};
114
+ background: ${color.default.disabled.border};
102
115
  }
103
116
  }
104
117
  `
@@ -2,6 +2,7 @@ import {SelectIcon} from '@sanity/icons'
2
2
  import {forwardRef} from 'react'
3
3
  import styled from 'styled-components'
4
4
  import {useForwardedRef, useCustomValidity, useArrayProp} from '../../hooks'
5
+ import {Radius} from '../../types'
5
6
  import {Box} from '../box'
6
7
  import {Text} from '../text'
7
8
  import {selectStyle} from './styles'
@@ -12,7 +13,7 @@ import {selectStyle} from './styles'
12
13
  export interface SelectProps {
13
14
  fontSize?: number | number[]
14
15
  padding?: number | number[]
15
- radius?: number | number[]
16
+ radius?: Radius | Radius[]
16
17
  space?: number | number[]
17
18
  customValidity?: string
18
19
  }
@@ -22,7 +23,7 @@ const Root = styled.div(selectStyle.root)
22
23
  const Input = styled.select<{
23
24
  $fontSize: number[]
24
25
  $padding: number[]
25
- $radius: number[]
26
+ $radius: Radius[]
26
27
  $space: number[]
27
28
  }>(selectStyle.input)
28
29
 
@@ -43,7 +43,8 @@ function inputBaseStyle(props: ThemeProps): ReturnType<typeof css> {
43
43
 
44
44
  function inputColorStyle(props: ThemeProps) {
45
45
  const {theme} = props
46
- const {focusRing, input} = theme.sanity
46
+ const {input} = theme.sanity
47
+ const {focusRing} = input.select
47
48
  const color = theme.sanity.color.input
48
49
 
49
50
  return css`
@@ -8,8 +8,8 @@ export default function PropsStory() {
8
8
  const indeterminate = useBoolean('Indeterminate', false)
9
9
  const readOnly = useBoolean('Read only', false)
10
10
  const theme = useTheme()
11
- const focusRingOffset = useNumber('Focus ring offset', theme.sanity.focusRing.offset)
12
- const focusRingWidth = useNumber('Focus ring width', theme.sanity.focusRing.width)
11
+ const focusRingOffset = useNumber('Focus ring offset', theme.sanity.input.switch.focusRing.offset)
12
+ const focusRingWidth = useNumber('Focus ring width', theme.sanity.input.switch.focusRing.width)
13
13
  const handleChange = useCallback(() => undefined, [])
14
14
 
15
15
  const customTheme = useMemo(
@@ -18,8 +18,8 @@ export default function PropsStory() {
18
18
  sanity: {
19
19
  ...theme.sanity,
20
20
  focusRing: {
21
- offset: focusRingOffset || theme.sanity.focusRing.offset,
22
- width: focusRingWidth || theme.sanity.focusRing.width,
21
+ offset: focusRingOffset || theme.sanity.input.switch.focusRing.offset,
22
+ width: focusRingWidth || theme.sanity.input.switch.focusRing.width,
23
23
  },
24
24
  },
25
25
  }),