@veracity/vui 2.19.0 → 2.20.0-beta.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.
Files changed (210) hide show
  1. package/dist/cjs/checkbox/checkbox.d.ts.map +1 -1
  2. package/dist/cjs/checkbox/checkbox.js +7 -4
  3. package/dist/cjs/checkbox/checkbox.js.map +1 -1
  4. package/dist/cjs/checkbox/consts.d.ts +5 -4
  5. package/dist/cjs/checkbox/consts.d.ts.map +1 -1
  6. package/dist/cjs/checkbox/consts.js +5 -4
  7. package/dist/cjs/checkbox/consts.js.map +1 -1
  8. package/dist/cjs/checkbox/theme.d.ts +1 -1
  9. package/dist/cjs/checkbox/theme.js +1 -1
  10. package/dist/cjs/checkbox/theme.js.map +1 -1
  11. package/dist/cjs/index.d.ts +1 -0
  12. package/dist/cjs/index.d.ts.map +1 -1
  13. package/dist/cjs/index.js +1 -0
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/input/input.d.ts.map +1 -1
  16. package/dist/cjs/input/input.js +22 -19
  17. package/dist/cjs/input/input.js.map +1 -1
  18. package/dist/cjs/input/input.types.d.ts +2 -0
  19. package/dist/cjs/input/input.types.d.ts.map +1 -1
  20. package/dist/cjs/input/theme.d.ts +12 -0
  21. package/dist/cjs/input/theme.d.ts.map +1 -1
  22. package/dist/cjs/input/theme.js +13 -1
  23. package/dist/cjs/input/theme.js.map +1 -1
  24. package/dist/cjs/label/index.d.ts +4 -0
  25. package/dist/cjs/label/index.d.ts.map +1 -0
  26. package/dist/cjs/label/index.js +25 -0
  27. package/dist/cjs/label/index.js.map +1 -0
  28. package/dist/cjs/label/label.d.ts +6 -0
  29. package/dist/cjs/label/label.d.ts.map +1 -0
  30. package/dist/cjs/label/label.js +41 -0
  31. package/dist/cjs/label/label.js.map +1 -0
  32. package/dist/cjs/label/label.types.d.ts +7 -0
  33. package/dist/cjs/label/label.types.d.ts.map +1 -0
  34. package/dist/cjs/label/label.types.js +3 -0
  35. package/dist/cjs/label/label.types.js.map +1 -0
  36. package/dist/cjs/label/theme.d.ts +23 -0
  37. package/dist/cjs/label/theme.d.ts.map +1 -0
  38. package/dist/cjs/label/theme.js +28 -0
  39. package/dist/cjs/label/theme.js.map +1 -0
  40. package/dist/cjs/list/list.d.ts.map +1 -1
  41. package/dist/cjs/list/list.js +8 -7
  42. package/dist/cjs/list/list.js.map +1 -1
  43. package/dist/cjs/radio/consts.d.ts +5 -4
  44. package/dist/cjs/radio/consts.d.ts.map +1 -1
  45. package/dist/cjs/radio/consts.js +5 -4
  46. package/dist/cjs/radio/consts.js.map +1 -1
  47. package/dist/cjs/radio/radio.d.ts.map +1 -1
  48. package/dist/cjs/radio/radio.js +7 -3
  49. package/dist/cjs/radio/radio.js.map +1 -1
  50. package/dist/cjs/radio/theme.d.ts +1 -1
  51. package/dist/cjs/radio/theme.js +1 -1
  52. package/dist/cjs/radio/theme.js.map +1 -1
  53. package/dist/cjs/select/select.d.ts +11 -6
  54. package/dist/cjs/select/select.d.ts.map +1 -1
  55. package/dist/cjs/select/select.js +9 -2
  56. package/dist/cjs/select/select.js.map +1 -1
  57. package/dist/cjs/select/select.types.d.ts +8 -0
  58. package/dist/cjs/select/select.types.d.ts.map +1 -1
  59. package/dist/cjs/select/selectButton.d.ts.map +1 -1
  60. package/dist/cjs/select/selectButton.js +2 -0
  61. package/dist/cjs/select/selectButton.js.map +1 -1
  62. package/dist/cjs/select/selectGroup.js +1 -1
  63. package/dist/cjs/select/selectGroup.js.map +1 -1
  64. package/dist/cjs/select/selectOption.js +1 -1
  65. package/dist/cjs/select/selectOption.js.map +1 -1
  66. package/dist/cjs/select/theme.d.ts +32 -0
  67. package/dist/cjs/select/theme.d.ts.map +1 -1
  68. package/dist/cjs/select/theme.js +33 -1
  69. package/dist/cjs/select/theme.js.map +1 -1
  70. package/dist/cjs/switch/switchLabel.d.ts.map +1 -1
  71. package/dist/cjs/switch/switchLabel.js +4 -0
  72. package/dist/cjs/switch/switchLabel.js.map +1 -1
  73. package/dist/cjs/switch/theme.d.ts +17 -0
  74. package/dist/cjs/switch/theme.d.ts.map +1 -1
  75. package/dist/cjs/switch/theme.js +18 -0
  76. package/dist/cjs/switch/theme.js.map +1 -1
  77. package/dist/cjs/textarea/textarea.d.ts +1 -1
  78. package/dist/cjs/textarea/textarea.d.ts.map +1 -1
  79. package/dist/cjs/textarea/textarea.js +19 -16
  80. package/dist/cjs/textarea/textarea.js.map +1 -1
  81. package/dist/cjs/textarea/textarea.types.d.ts +2 -0
  82. package/dist/cjs/textarea/textarea.types.d.ts.map +1 -1
  83. package/dist/cjs/textarea/theme.js +1 -1
  84. package/dist/cjs/textarea/theme.js.map +1 -1
  85. package/dist/cjs/theme/components.d.ts +83 -2
  86. package/dist/cjs/theme/components.d.ts.map +1 -1
  87. package/dist/cjs/theme/components.js +56 -54
  88. package/dist/cjs/theme/components.js.map +1 -1
  89. package/dist/cjs/theme/defaultTheme.d.ts +83 -2
  90. package/dist/cjs/theme/defaultTheme.d.ts.map +1 -1
  91. package/dist/esm/checkbox/checkbox.d.ts.map +1 -1
  92. package/dist/esm/checkbox/checkbox.js +7 -4
  93. package/dist/esm/checkbox/checkbox.js.map +1 -1
  94. package/dist/esm/checkbox/consts.d.ts +5 -4
  95. package/dist/esm/checkbox/consts.d.ts.map +1 -1
  96. package/dist/esm/checkbox/consts.js +5 -4
  97. package/dist/esm/checkbox/consts.js.map +1 -1
  98. package/dist/esm/checkbox/theme.d.ts +1 -1
  99. package/dist/esm/checkbox/theme.js +1 -1
  100. package/dist/esm/checkbox/theme.js.map +1 -1
  101. package/dist/esm/index.d.ts +1 -0
  102. package/dist/esm/index.d.ts.map +1 -1
  103. package/dist/esm/index.js +1 -0
  104. package/dist/esm/index.js.map +1 -1
  105. package/dist/esm/input/input.d.ts.map +1 -1
  106. package/dist/esm/input/input.js +24 -21
  107. package/dist/esm/input/input.js.map +1 -1
  108. package/dist/esm/input/input.types.d.ts +2 -0
  109. package/dist/esm/input/input.types.d.ts.map +1 -1
  110. package/dist/esm/input/theme.d.ts +12 -0
  111. package/dist/esm/input/theme.d.ts.map +1 -1
  112. package/dist/esm/input/theme.js +13 -1
  113. package/dist/esm/input/theme.js.map +1 -1
  114. package/dist/esm/label/index.d.ts +4 -0
  115. package/dist/esm/label/index.d.ts.map +1 -0
  116. package/dist/esm/label/index.js +4 -0
  117. package/dist/esm/label/index.js.map +1 -0
  118. package/dist/esm/label/label.d.ts +6 -0
  119. package/dist/esm/label/label.d.ts.map +1 -0
  120. package/dist/esm/label/label.js +24 -0
  121. package/dist/esm/label/label.js.map +1 -0
  122. package/dist/esm/label/label.types.d.ts +7 -0
  123. package/dist/esm/label/label.types.d.ts.map +1 -0
  124. package/dist/esm/label/label.types.js +2 -0
  125. package/dist/esm/label/label.types.js.map +1 -0
  126. package/dist/esm/label/theme.d.ts +23 -0
  127. package/dist/esm/label/theme.d.ts.map +1 -0
  128. package/dist/esm/label/theme.js +26 -0
  129. package/dist/esm/label/theme.js.map +1 -0
  130. package/dist/esm/list/list.d.ts.map +1 -1
  131. package/dist/esm/list/list.js +7 -7
  132. package/dist/esm/list/list.js.map +1 -1
  133. package/dist/esm/radio/consts.d.ts +5 -4
  134. package/dist/esm/radio/consts.d.ts.map +1 -1
  135. package/dist/esm/radio/consts.js +5 -4
  136. package/dist/esm/radio/consts.js.map +1 -1
  137. package/dist/esm/radio/radio.d.ts.map +1 -1
  138. package/dist/esm/radio/radio.js +7 -3
  139. package/dist/esm/radio/radio.js.map +1 -1
  140. package/dist/esm/radio/theme.d.ts +1 -1
  141. package/dist/esm/radio/theme.js +1 -1
  142. package/dist/esm/radio/theme.js.map +1 -1
  143. package/dist/esm/select/select.d.ts +11 -6
  144. package/dist/esm/select/select.d.ts.map +1 -1
  145. package/dist/esm/select/select.js +13 -6
  146. package/dist/esm/select/select.js.map +1 -1
  147. package/dist/esm/select/select.types.d.ts +8 -0
  148. package/dist/esm/select/select.types.d.ts.map +1 -1
  149. package/dist/esm/select/selectButton.d.ts.map +1 -1
  150. package/dist/esm/select/selectButton.js +2 -0
  151. package/dist/esm/select/selectButton.js.map +1 -1
  152. package/dist/esm/select/selectGroup.js +1 -1
  153. package/dist/esm/select/selectGroup.js.map +1 -1
  154. package/dist/esm/select/selectOption.js +2 -2
  155. package/dist/esm/select/selectOption.js.map +1 -1
  156. package/dist/esm/select/theme.d.ts +32 -0
  157. package/dist/esm/select/theme.d.ts.map +1 -1
  158. package/dist/esm/select/theme.js +33 -1
  159. package/dist/esm/select/theme.js.map +1 -1
  160. package/dist/esm/switch/switchLabel.d.ts.map +1 -1
  161. package/dist/esm/switch/switchLabel.js +4 -0
  162. package/dist/esm/switch/switchLabel.js.map +1 -1
  163. package/dist/esm/switch/theme.d.ts +17 -0
  164. package/dist/esm/switch/theme.d.ts.map +1 -1
  165. package/dist/esm/switch/theme.js +18 -0
  166. package/dist/esm/switch/theme.js.map +1 -1
  167. package/dist/esm/textarea/textarea.d.ts +1 -1
  168. package/dist/esm/textarea/textarea.d.ts.map +1 -1
  169. package/dist/esm/textarea/textarea.js +22 -19
  170. package/dist/esm/textarea/textarea.js.map +1 -1
  171. package/dist/esm/textarea/textarea.types.d.ts +2 -0
  172. package/dist/esm/textarea/textarea.types.d.ts.map +1 -1
  173. package/dist/esm/textarea/theme.js +1 -1
  174. package/dist/esm/textarea/theme.js.map +1 -1
  175. package/dist/esm/theme/components.d.ts +83 -2
  176. package/dist/esm/theme/components.d.ts.map +1 -1
  177. package/dist/esm/theme/components.js +2 -0
  178. package/dist/esm/theme/components.js.map +1 -1
  179. package/dist/esm/theme/defaultTheme.d.ts +83 -2
  180. package/dist/esm/theme/defaultTheme.d.ts.map +1 -1
  181. package/dist/tsconfig.legacy.tsbuildinfo +1 -1
  182. package/dist/tsconfig.tsbuildinfo +1 -1
  183. package/package.json +1 -1
  184. package/src/checkbox/checkbox.tsx +7 -5
  185. package/src/checkbox/consts.ts +5 -4
  186. package/src/checkbox/theme.ts +1 -1
  187. package/src/index.ts +1 -0
  188. package/src/input/input.tsx +83 -66
  189. package/src/input/input.types.ts +2 -0
  190. package/src/input/theme.ts +13 -1
  191. package/src/label/index.ts +3 -0
  192. package/src/label/label.tsx +31 -0
  193. package/src/label/label.types.ts +8 -0
  194. package/src/label/theme.ts +29 -0
  195. package/src/list/list.tsx +6 -5
  196. package/src/radio/consts.ts +5 -4
  197. package/src/radio/radio.tsx +6 -4
  198. package/src/radio/theme.ts +1 -1
  199. package/src/select/select.tsx +30 -5
  200. package/src/select/select.types.ts +8 -0
  201. package/src/select/selectButton.tsx +2 -0
  202. package/src/select/selectGroup.tsx +1 -1
  203. package/src/select/selectOption.tsx +2 -2
  204. package/src/select/theme.ts +33 -1
  205. package/src/switch/switchLabel.tsx +5 -0
  206. package/src/switch/theme.ts +21 -0
  207. package/src/textarea/textarea.tsx +70 -49
  208. package/src/textarea/textarea.types.ts +2 -0
  209. package/src/textarea/theme.ts +1 -1
  210. package/src/theme/components.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veracity/vui",
3
- "version": "2.19.0",
3
+ "version": "2.20.0-beta.0",
4
4
  "description": "Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.",
5
5
  "module": "./dist/esm/index.js",
6
6
  "main": "./dist/cjs/index.js",
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react'
1
+ import { useEffect, useState } from 'react'
2
2
 
3
3
  import { omitThemingProps, styled, th, useStyleConfig, vui } from '../core'
4
4
  import Icon from '../icon'
@@ -38,12 +38,15 @@ export const CheckboxBase = styled.labelBox<CheckboxStyleProps>`
38
38
  color: ${p => th.color(p.controlHoverColor)};
39
39
  }
40
40
 
41
+ .vui-checkboxControl:focus-within {
42
+ color: ${checkboxColors.focus};
43
+ }
44
+
41
45
  &[aria-disabled='true'] {
42
- color: ${checkboxColors.disabledText};
43
46
  cursor: not-allowed;
44
47
 
45
48
  .vui-checkboxControl {
46
- color: ${checkboxColors.disabledText};
49
+ color: ${checkboxColors.disabled};
47
50
  }
48
51
  }
49
52
  `
@@ -82,7 +85,7 @@ export const Checkbox = vui<'span', CheckboxProps>((props, ref) => {
82
85
 
83
86
  const icon = isIndeterminate ? iconIndeterminate : isChecked ? iconChecked : iconProp
84
87
  const controlMr = children || label ? 1 : 0
85
- const color = controlColor ? controlColor : checkboxColors.main
88
+ const color = isChecked || isIndeterminate ? checkboxColors.checked : controlColor
86
89
  const controlHoverColor = hoverColor ? hoverColor : checkboxColors.hover
87
90
  const isLongLabel = label && label?.length >= 60
88
91
 
@@ -119,7 +122,6 @@ export const Checkbox = vui<'span', CheckboxProps>((props, ref) => {
119
122
  {...controlStyles}
120
123
  >
121
124
  <CheckboxInput
122
- aria-label={label ? label : 'input-checkbox'}
123
125
  className="vui-checkboxInput"
124
126
  onChange={handleOnChange}
125
127
  ref={inputRef}
@@ -1,6 +1,7 @@
1
1
  export const checkboxColors = {
2
- main: 'sandstone.60',
3
- hover: 'sandstone.60',
4
- disabled: 'sandstone.60',
5
- disabledText: 'sandstone.60',
2
+ unchecked: 'sandstone.60',
3
+ checked: 'seaBlue.28',
4
+ hover: 'seaBlue.20',
5
+ focus: 'seaBlue.35',
6
+ disabled: 'sandstone.90',
6
7
  } as const
@@ -2,7 +2,7 @@ import { checkboxColors } from './consts'
2
2
 
3
3
  const baseStyle = {
4
4
  control: {
5
- color: checkboxColors.main,
5
+ color: checkboxColors.unchecked,
6
6
  hoverColor: checkboxColors.hover,
7
7
  },
8
8
  }
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ export * from './icon'
25
25
  export * from './icons'
26
26
  export * from './image'
27
27
  export * from './input'
28
+ export * from './label'
28
29
  export * from './link'
29
30
  export * from './list'
30
31
  export * from './logo'
@@ -1,7 +1,8 @@
1
- import React, { useEffect, useMemo, useState } from 'react'
1
+ import { useEffect, useId, useMemo, useState } from 'react'
2
2
 
3
3
  import { IconButton } from '../button'
4
4
  import { styled, useStyleConfig, vui, VuiComponent } from '../core'
5
+ import Label from '../label'
5
6
  import { T } from '../t'
6
7
  import { ChangeEvent, cs, filterUndefined, isString } from '../utils'
7
8
  import AutoCompletePopover from './autoCompletePopover'
@@ -43,25 +44,27 @@ export const InputBase = styled.divBox`
43
44
  export const Input = vui<'div', InputProps>((props, ref) => {
44
45
  const {
45
46
  allowClear,
47
+ ariaLabel,
46
48
  autoComplete,
47
- autoCompleteOptions,
48
49
  autoCompleteMaxHeight,
50
+ autoCompleteOptions,
49
51
  autoFocus,
50
- ariaLabel,
51
52
  children,
52
53
  className,
53
54
  defaultValue,
54
55
  disabled,
56
+ displayValueOnly,
55
57
  errorText,
58
+ helpText,
56
59
  iconLeft,
57
60
  iconRight,
58
- id,
61
+ id: idProp,
59
62
  input,
60
63
  inputProps,
61
64
  inputRef,
62
65
  itemLeft,
63
66
  itemRight,
64
- helpText,
67
+ label,
65
68
  max,
66
69
  maxLength,
67
70
  min,
@@ -74,7 +77,6 @@ export const Input = vui<'div', InputProps>((props, ref) => {
74
77
  readOnly,
75
78
  required,
76
79
  showCount,
77
- displayValueOnly,
78
80
  size = 'lg',
79
81
  state = '',
80
82
  stateMapping,
@@ -85,10 +87,13 @@ export const Input = vui<'div', InputProps>((props, ref) => {
85
87
  ...rest
86
88
  } = props
87
89
 
90
+ const generatedId = useId()
88
91
  const [count, setCount] = useState(getInitialCount(props))
89
92
  const [valueInternal, setValueInternal] = useState(defaultValue || '')
90
93
  const states = { ...inputStateMapping, ...stateMapping }
91
94
 
95
+ const id = idProp || generatedId
96
+
92
97
  const styles = useStyleConfig('Input', props)
93
98
 
94
99
  const context = useMemo(() => filterUndefined({ disabled, size, variant }), [disabled, size, variant])
@@ -131,10 +136,7 @@ export const Input = vui<'div', InputProps>((props, ref) => {
131
136
  return (
132
137
  <InputProvider value={context}>
133
138
  {displayValueOnly ? (
134
- <T
135
- className={cs('vui-input-value', className)}
136
- size={displayValueOnlyTextSize[size] as 'xs' | 'md' | 'sm' | 'lg'}
137
- >
139
+ <T className={cs('vui-input-value', className)} size={displayValueOnlyTextSize[size]}>
138
140
  {value || defaultValue}
139
141
  </T>
140
142
  ) : (
@@ -144,63 +146,78 @@ export const Input = vui<'div', InputProps>((props, ref) => {
144
146
  filterAutoCompleteOptions={filterAutoCompleteOptions}
145
147
  onAutoCompleteSelect={onAutoCompleteSelect}
146
148
  >
147
- <InputBase className={cs('vui-input', className)} ref={ref} {...styles.container} {...aliasedProps} {...rest}>
148
- {itemLeft}
149
- {isString(iconLeft) ? <InputIcon ml={1} name={iconLeft} /> : iconLeft}
150
- {children ?? input ?? (
151
- <InputInput
152
- ref={inputRef}
153
- {...{
154
- autoFocus,
155
- ariaLabel,
156
- defaultValue,
157
- disabled,
158
- id,
159
- max,
160
- maxLength,
161
- min,
162
- name,
163
- onBlur,
164
- onChange,
165
- onFocus,
166
- pattern,
167
- placeholder,
168
- readOnly,
169
- required,
170
- step,
171
- type,
172
- }}
173
- autoComplete={autoCompleteOptions?.length ? 'off' : autoComplete}
174
- value={valueInternal}
175
- {...inputProps}
176
- />
177
- )}
178
- {isString(iconRight) ? <InputIcon mr={1} name={iconRight} /> : iconRight}
179
- {itemRight}
180
- {state && <InputIcon mr={1} {...states[state]?.iconProps} />}
181
- {allowClear && (
182
- <IconButton
183
- disabled={!valueInternal}
184
- icon="falTimes"
185
- mr={0.5}
186
- onClick={onClear}
187
- size={clearIconSize[size]}
188
- title="Clear"
189
- />
190
- )}
191
- {showCount && (
192
- <T
193
- className="vui-inputCount"
194
- color={maxLength && count > maxLength ? inputColors.error : inputColors.helpText}
195
- position="absolute"
196
- right={0}
197
- size="sm"
198
- top="calc(100% + 1px)"
199
- >
200
- {count} {maxLength ? `/ ${maxLength}` : null}
201
- </T>
149
+ <>
150
+ {isString(label) ? (
151
+ <Label aria-disabled={disabled} className="vui-input-label" htmlFor={id} mb={0.5} {...styles.label}>
152
+ {label}
153
+ </Label>
154
+ ) : (
155
+ label
202
156
  )}
203
- </InputBase>
157
+ <InputBase
158
+ className={cs('vui-input', className)}
159
+ ref={ref}
160
+ {...styles.container}
161
+ {...aliasedProps}
162
+ {...rest}
163
+ >
164
+ {itemLeft}
165
+ {isString(iconLeft) ? <InputIcon ml={1} name={iconLeft} /> : iconLeft}
166
+ {children ?? input ?? (
167
+ <InputInput
168
+ ref={inputRef}
169
+ {...{
170
+ autoFocus,
171
+ ariaLabel,
172
+ defaultValue,
173
+ disabled,
174
+ id,
175
+ max,
176
+ maxLength,
177
+ min,
178
+ name,
179
+ onBlur,
180
+ onChange,
181
+ onFocus,
182
+ pattern,
183
+ placeholder,
184
+ readOnly,
185
+ required,
186
+ step,
187
+ type,
188
+ }}
189
+ autoComplete={autoCompleteOptions?.length ? 'off' : autoComplete}
190
+ value={valueInternal}
191
+ {...inputProps}
192
+ />
193
+ )}
194
+ {isString(iconRight) ? <InputIcon mr={1} name={iconRight} /> : iconRight}
195
+ {itemRight}
196
+ {state && <InputIcon mr={1} {...states[state]?.iconProps} />}
197
+ {allowClear && (
198
+ <IconButton
199
+ disabled={!valueInternal}
200
+ icon="falTimes"
201
+ mr={0.5}
202
+ onClick={onClear}
203
+ size={clearIconSize[size]}
204
+ title="Clear"
205
+ />
206
+ )}
207
+ {showCount && (
208
+ <T
209
+ className="vui-inputCount"
210
+ color={maxLength && count > maxLength ? inputColors.error : inputColors.helpText}
211
+ position="absolute"
212
+ right={0}
213
+ size="sm"
214
+ top="calc(100% + 1px)"
215
+ >
216
+ {count} {maxLength ? `/ ${maxLength}` : null}
217
+ </T>
218
+ )}
219
+ </InputBase>
220
+ </>
204
221
  </AutoCompletePopover>
205
222
  )}
206
223
 
@@ -47,6 +47,8 @@ export type InputProps = SystemProps &
47
47
  itemLeft?: React.ReactNode
48
48
  /** Socket displaying a custom element on the right. */
49
49
  itemRight?: React.ReactNode
50
+ /** The label. */
51
+ label?: string | React.ReactNode
50
52
  /** Passed to the inner input. */
51
53
  max?: number | string
52
54
  /** Passed to the inner input. */
@@ -15,7 +15,7 @@ const defaultProps = {
15
15
  variant: 'grey',
16
16
  }
17
17
 
18
- const parts = ['container', 'icon', 'input']
18
+ const parts = ['container', 'icon', 'input', 'label']
19
19
 
20
20
  const sizes = {
21
21
  sm: {
@@ -27,6 +27,9 @@ const sizes = {
27
27
  size: 'xs',
28
28
  },
29
29
  input: {},
30
+ label: {
31
+ fontSize: 'sm',
32
+ },
30
33
  },
31
34
  md: {
32
35
  container: {
@@ -37,6 +40,9 @@ const sizes = {
37
40
  size: 'sm',
38
41
  },
39
42
  input: {},
43
+ label: {
44
+ fontSize: 'sm',
45
+ },
40
46
  },
41
47
  lg: {
42
48
  container: {
@@ -47,6 +53,9 @@ const sizes = {
47
53
  size: 'md',
48
54
  },
49
55
  input: {},
56
+ label: {
57
+ fontSize: 'md',
58
+ },
50
59
  },
51
60
  xl: {
52
61
  container: {
@@ -57,6 +66,9 @@ const sizes = {
57
66
  size: 'md',
58
67
  },
59
68
  input: {},
69
+ label: {
70
+ fontSize: 'lg',
71
+ },
60
72
  },
61
73
  }
62
74
 
@@ -0,0 +1,3 @@
1
+ export * from './label'
2
+ export { default } from './label'
3
+ export * from './label.types'
@@ -0,0 +1,31 @@
1
+ import { omitThemingProps, styled, useStyleConfig, vui } from '../core'
2
+ import T from '../t'
3
+ import { cs } from '../utils'
4
+ import { LabelProps } from './label.types'
5
+
6
+ export const LabelBase = styled.labelBox`
7
+ display: block;
8
+ font-weight: 600;
9
+ width: 100%;
10
+ color: darkBlue.main;
11
+
12
+ &[aria-disabled='true'] {
13
+ color: sandstone.75;
14
+ cursor: not-allowed;
15
+ }
16
+ `
17
+
18
+ /** Displays a paragraph of text. */
19
+ export const Label = vui<'label', LabelProps>((props, ref) => {
20
+ const { children, className, text, ...rest } = omitThemingProps(props)
21
+ const styles = useStyleConfig('Label', props)
22
+
23
+ return (
24
+ <T as={LabelBase} className={cs('vui-label', className)} ref={ref} {...styles} {...rest}>
25
+ {children ?? text}
26
+ </T>
27
+ )
28
+ })
29
+
30
+ Label.displayName = 'Label'
31
+ export default Label
@@ -0,0 +1,8 @@
1
+ import { SystemProps, TypographyProps } from '../system'
2
+ import { ThemingProps } from '../theme'
3
+
4
+ export type LabelProps = SystemProps &
5
+ ThemingProps<'P'> & {
6
+ /** Displays given text if no children are provided. */
7
+ text?: number | string
8
+ }
@@ -0,0 +1,29 @@
1
+ const baseStyle = {}
2
+
3
+ const defaultProps = {
4
+ size: 'md',
5
+ }
6
+
7
+ const sizes = {
8
+ xs: {
9
+ fontSize: 'xs',
10
+ },
11
+ sm: {
12
+ fontSize: 'sm',
13
+ },
14
+ md: {
15
+ fontSize: 'md',
16
+ },
17
+ lg: {
18
+ fontSize: 'lg',
19
+ },
20
+ }
21
+
22
+ const variants = {}
23
+
24
+ export default {
25
+ baseStyle,
26
+ defaultProps,
27
+ sizes,
28
+ variants,
29
+ }
package/src/list/list.tsx CHANGED
@@ -53,12 +53,13 @@ export const List = vui<'ul', ListProps>((props, ref) => {
53
53
  }
54
54
 
55
55
  useEffect(() => {
56
- if (isInteractive) document.addEventListener('keydown', onKeydown)
57
-
58
- return () => {
59
- if (isInteractive) document.removeEventListener('keydown', onKeydown)
56
+ if (listRef.current && isInteractive) {
57
+ listRef.current.addEventListener('keydown', onKeydown)
58
+ return () => {
59
+ listRef.current?.removeEventListener('keydown', onKeydown)
60
+ }
60
61
  }
61
- }, [])
62
+ }, [listRef.current, isInteractive])
62
63
 
63
64
  return (
64
65
  <ListProvider value={context}>
@@ -1,6 +1,7 @@
1
1
  export const radioColors = {
2
- main: 'sandstone.60',
3
- hover: 'sandstone.60',
4
- disabled: 'sandstone.60',
5
- disabledText: 'sandstone.60',
2
+ unchecked: 'sandstone.60',
3
+ checked: 'seaBlue.28',
4
+ hover: 'seaBlue.20',
5
+ focus: 'seaBlue.35',
6
+ disabled: 'sandstone.90',
6
7
  } as const
@@ -39,8 +39,12 @@ export const RadioBase = styled.labelBox<RadioStyleProps>`
39
39
  color: ${p => th.color(p.controlHoverColor)};
40
40
  }
41
41
 
42
+ .vui-radioControl:focus-within {
43
+ color: ${radioColors.focus};
44
+ }
45
+
42
46
  &[aria-disabled='true'] {
43
- color: ${radioColors.disabledText};
47
+ color: ${radioColors.disabled};
44
48
  cursor: not-allowed;
45
49
 
46
50
  .vui-radioControl {
@@ -89,7 +93,7 @@ export const Radio = vui<'span', RadioProps>((props, ref) => {
89
93
 
90
94
  const icon = isChecked ? iconChecked : iconProp
91
95
  const controlMr = children || label ? 1 : 0
92
- const color = controlColor ? controlColor : radioColors.main
96
+ const color = isChecked ? radioColors.checked : controlColor
93
97
  const controlHoverColor = hoverColor ? hoverColor : radioColors.hover
94
98
 
95
99
  useEffect(() => {
@@ -128,7 +132,6 @@ export const Radio = vui<'span', RadioProps>((props, ref) => {
128
132
  >
129
133
  {checked !== undefined && (
130
134
  <RadioInput
131
- aria-label="input-radio"
132
135
  className="vui-radioInput"
133
136
  onChange={handleOnChange}
134
137
  ref={inputRef}
@@ -140,7 +143,6 @@ export const Radio = vui<'span', RadioProps>((props, ref) => {
140
143
 
141
144
  {checked === undefined && (
142
145
  <RadioInput
143
- aria-label="input-radio"
144
146
  className="vui-radioInput"
145
147
  onChange={handleOnChange}
146
148
  ref={inputRef}
@@ -2,7 +2,7 @@ import { radioColors } from './consts'
2
2
 
3
3
  const baseStyle = {
4
4
  control: {
5
- color: radioColors.main,
5
+ color: radioColors.unchecked,
6
6
  hoverColor: radioColors.hover,
7
7
  },
8
8
  }
@@ -1,10 +1,14 @@
1
- import React, { useEffect, useState } from 'react'
1
+ import { useEffect, useId, useState } from 'react'
2
2
 
3
3
  import { Box } from '../box'
4
+ import { useStyleConfig } from '../core'
4
5
  import { Input } from '../input'
6
+ import { helpTextSize } from '../input/consts'
7
+ import HelpText from '../input/helpText'
8
+ import Label from '../label'
5
9
  import { Popover } from '../popover'
6
- import { __DEV__ } from '../utils'
7
- import { SelectProvider } from './context'
10
+ import { __DEV__, isString } from '../utils'
11
+ import { SelectProvider, useSelectContext } from './context'
8
12
  import { SelectOptionData, SelectProps } from './select.types'
9
13
  import SelectButton from './selectButton'
10
14
  import SelectContent from './selectContent'
@@ -22,8 +26,12 @@ export function Select(props: SelectProps) {
22
26
  children,
23
27
  defaultValue,
24
28
  disabled,
29
+ errorText,
30
+ helpText,
31
+ id: idProp,
25
32
  isInvalid,
26
33
  isMultiple,
34
+ label,
27
35
  maxHeight,
28
36
  name,
29
37
  onChange,
@@ -33,7 +41,7 @@ export function Select(props: SelectProps) {
33
41
  selectButton,
34
42
  selectButtonProps,
35
43
  showOptionsFilter,
36
- size,
44
+ size = 'lg',
37
45
  value,
38
46
  variant,
39
47
  ...rest
@@ -45,9 +53,13 @@ export function Select(props: SelectProps) {
45
53
  console.error('<Select /> is used with isMultiple but its value is not an array: ', value)
46
54
  }
47
55
 
56
+ const generatedId = useId()
57
+ const styles = useStyleConfig('Select', useSelectContext())
48
58
  const [query, setQuery] = useState<string>('')
49
59
  const [filteredOptions, setFilteredOptions] = useState(options)
50
60
 
61
+ const id = idProp || generatedId
62
+
51
63
  const context = {
52
64
  disabled,
53
65
  isInvalid,
@@ -73,6 +85,13 @@ export function Select(props: SelectProps) {
73
85
 
74
86
  return (
75
87
  <SelectProvider value={context}>
88
+ {isString(label) ? (
89
+ <Label aria-disabled={disabled} className="vui-input-label" htmlFor={id} mb={0.5} {...styles.label}>
90
+ {label}
91
+ </Label>
92
+ ) : (
93
+ label
94
+ )}
76
95
  <Popover matchWidth {...rest}>
77
96
  <>
78
97
  {selectButton ?? <SelectButton {...selectButtonProps} />}
@@ -85,7 +104,7 @@ export function Select(props: SelectProps) {
85
104
  mt={0}
86
105
  onChange={onQueryChange}
87
106
  placeholder="Filter…"
88
- size="sm"
107
+ size={size}
89
108
  value={query}
90
109
  />
91
110
  </Box>
@@ -97,6 +116,12 @@ export function Select(props: SelectProps) {
97
116
  </SelectContent>
98
117
  </>
99
118
  </Popover>
119
+ {!!helpText && <HelpText size={helpTextSize[size]}>{helpText}</HelpText>}
120
+ {!!errorText && (
121
+ <HelpText isError size={helpTextSize[size]}>
122
+ {errorText}
123
+ </HelpText>
124
+ )}
100
125
  </SelectProvider>
101
126
  )
102
127
  }
@@ -24,12 +24,20 @@ export type SelectProps = ThemingProps<'Select'> &
24
24
  UseSelectProps & {
25
25
  /** Select cannot be opened and is styled accordingly. */
26
26
  disabled?: boolean
27
+ /** Socket displaying error text below an input. */
28
+ errorText?: string | React.ReactNode
29
+ /** Socket displaying help text below an input. */
30
+ helpText?: React.ReactNode | string
31
+ /** Unique identifier */
32
+ id?: string
27
33
  /** Represents invalid form input and is styled accordingly. */
28
34
  isInvalid?: boolean
29
35
  /** Maximum container height in px. */
30
36
  maxHeight?: number
31
37
  /** Name of the input. Used in custom change event to support form library integration. */
32
38
  name?: string
39
+ /** The label. */
40
+ label?: string | React.ReactNode
33
41
  /** Data prop to display an array of options in the popover. */
34
42
  options?: SelectOptionData[]
35
43
  /** Displayed inside the trigger when no value is selected. */
@@ -26,6 +26,8 @@ export const SelectButton = vui<'button', SelectButtonProps>((props, ref) => {
26
26
  backgroundColor: 'sandstone.79',
27
27
  borderColor: 'sandstone.79',
28
28
  hoverBg: 'sandstone.79',
29
+ hoverBorderColor: 'sandstone.79',
30
+ activeBorderColor: 'sandstone.79',
29
31
  }
30
32
  : undefined
31
33
 
@@ -11,7 +11,7 @@ export const SelectGroup = vui<'ul', SelectGroupProps>((props, ref) => {
11
11
  const { className, ...rest } = props
12
12
  const styles = useStyleConfig('Select', useSelectContext())
13
13
 
14
- return <List className={cs('vui-selectGroup', className)} ref={ref} size="sm" {...styles.group} {...rest} />
14
+ return <List className={cs('vui-selectGroup', className)} ref={ref} {...styles.group} {...rest} />
15
15
  }) as VuiComponent<'ul', SelectGroupProps> & {
16
16
  Divider: typeof ListDivider
17
17
  Heading: typeof ListHeading
@@ -50,14 +50,14 @@ export const SelectOption = vui<'li', SelectOptionProps>((props, ref) => {
50
50
  selectedBg="skyBlue.selected"
51
51
  title={title}
52
52
  value={valueProp}
53
- {...styles.item}
53
+ {...styles.option}
54
54
  {...rest}
55
55
  {...ellipsisOverflow}
56
56
  >
57
57
  {children ??
58
58
  (isMultiple && (
59
59
  <>
60
- <Checkbox checked={isSelected} disabled={disabled} mr={1} />
60
+ <Checkbox checked={isSelected} disabled={disabled} mr={1} {...styles.option} />
61
61
  <List.Text>{props.text}</List.Text>
62
62
  </>
63
63
  ))}