braid-design-system 30.4.3 → 30.7.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 (40) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/lib/components/Actions/Actions.docs.tsx +1 -1
  3. package/lib/components/Autosuggest/Autosuggest.screenshots.tsx +43 -1
  4. package/lib/components/Autosuggest/Autosuggest.tsx +2 -1
  5. package/lib/components/Badge/Badge.docs.tsx +1 -1
  6. package/lib/components/Button/Button.docs.tsx +1 -1
  7. package/lib/components/ButtonLink/ButtonLink.docs.tsx +1 -1
  8. package/lib/components/Card/Card.docs.tsx +1 -1
  9. package/lib/components/Checkbox/Checkbox.docs.tsx +17 -9
  10. package/lib/components/Checkbox/CheckboxStandalone.screenshots.tsx +17 -9
  11. package/lib/components/Divider/Divider.docs.tsx +1 -1
  12. package/lib/components/Dropdown/Dropdown.docs.tsx +16 -7
  13. package/lib/components/Dropdown/Dropdown.screenshots.tsx +51 -1
  14. package/lib/components/Dropdown/Dropdown.tsx +1 -1
  15. package/lib/components/FieldLabel/FieldLabel.docs.tsx +150 -12
  16. package/lib/components/FieldLabel/FieldLabel.screenshots.tsx +13 -0
  17. package/lib/components/FieldLabel/FieldLabel.tsx +3 -1
  18. package/lib/components/FieldMessage/FieldMessage.docs.tsx +4 -21
  19. package/lib/components/MonthPicker/MonthPicker.screenshots.tsx +23 -1
  20. package/lib/components/Notice/Notice.docs.tsx +1 -1
  21. package/lib/components/PasswordField/PasswordField.screenshots.tsx +32 -10
  22. package/lib/components/PasswordField/PasswordField.tsx +2 -1
  23. package/lib/components/Radio/Radio.screenshots.tsx +17 -9
  24. package/lib/components/RadioGroup/RadioGroup.screenshots.tsx +14 -17
  25. package/lib/components/Tabs/Tabs.docs.tsx +1 -1
  26. package/lib/components/Tag/Tag.docs.tsx +1 -1
  27. package/lib/components/TextField/TextField.docs.tsx +3 -3
  28. package/lib/components/TextField/TextField.screenshots.tsx +70 -32
  29. package/lib/components/TextField/TextField.tsx +2 -1
  30. package/lib/components/TextLinkButton/TextLinkButton.docs.tsx +2 -2
  31. package/lib/components/TextLinkButton/TextLinkButton.tsx +3 -1
  32. package/lib/components/Textarea/Textarea.docs.tsx +2 -2
  33. package/lib/components/Textarea/Textarea.screenshots.tsx +61 -28
  34. package/lib/components/Textarea/Textarea.tsx +1 -1
  35. package/lib/components/Toggle/Toggle.tsx +95 -92
  36. package/lib/components/private/Field/ClearField.tsx +1 -0
  37. package/lib/components/private/Field/Field.tsx +9 -3
  38. package/lib/components/private/FieldGroup/FieldGroup.tsx +1 -0
  39. package/lib/css/reset/reset.css.ts +3 -0
  40. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  import React, { ReactNode, useState } from 'react';
2
2
  import { ComponentScreenshot } from '../../../site/src/types';
3
- import { Textarea, TextLink } from '../';
3
+ import { Stack, Textarea, TextLink } from '../';
4
4
 
5
5
  const Container = ({ children }: { children: ReactNode }) => (
6
6
  <div style={{ maxWidth: '300px' }}>{children}</div>
@@ -13,24 +13,19 @@ export const screenshots: ComponentScreenshot = {
13
13
  label: 'Textarea',
14
14
  Container,
15
15
  Example: ({ id, handler }) => (
16
- <Textarea
17
- id={id}
18
- value="Senior Developer"
19
- onChange={handler}
20
- label="Job Title"
21
- />
16
+ <Textarea id={id} value="Text value" onChange={handler} label="Label" />
22
17
  ),
23
18
  },
24
19
  {
25
- label: 'Textarea with message',
20
+ label: 'Textarea with neutral message',
26
21
  Container,
27
22
  Example: ({ id, handler }) => (
28
23
  <Textarea
29
24
  id={id}
30
25
  value=""
31
26
  onChange={handler}
32
- label="Job Title"
33
- message="e.g. Senior Developer"
27
+ label="Label"
28
+ message="Neutral message"
34
29
  />
35
30
  ),
36
31
  },
@@ -42,8 +37,8 @@ export const screenshots: ComponentScreenshot = {
42
37
  id={id}
43
38
  value=""
44
39
  onChange={handler}
45
- label="Title"
46
- secondaryLabel="Optional"
40
+ label="Label"
41
+ secondaryLabel="Secondary"
47
42
  />
48
43
  ),
49
44
  },
@@ -55,8 +50,8 @@ export const screenshots: ComponentScreenshot = {
55
50
  id={id}
56
51
  value=""
57
52
  onChange={handler}
58
- label="Title"
59
- secondaryLabel="Optional"
53
+ label="Label"
54
+ secondaryLabel="Secondary"
60
55
  tertiaryLabel={<TextLink href="#">Help?</TextLink>}
61
56
  />
62
57
  ),
@@ -65,7 +60,7 @@ export const screenshots: ComponentScreenshot = {
65
60
  label: 'Textarea with no visual label',
66
61
  Container,
67
62
  Example: ({ id, handler }) => (
68
- <Textarea id={id} value="" onChange={handler} aria-label="Title" />
63
+ <Textarea id={id} value="" onChange={handler} aria-label="Label" />
69
64
  ),
70
65
  },
71
66
  {
@@ -74,10 +69,10 @@ export const screenshots: ComponentScreenshot = {
74
69
  Example: ({ id, handler }) => (
75
70
  <Textarea
76
71
  id={id}
77
- value="No"
72
+ value=""
78
73
  onChange={handler}
79
- label="Do you like Braid?"
80
- message="Answer is incorrect"
74
+ label="Label"
75
+ message="Critical message"
81
76
  tone="critical"
82
77
  />
83
78
  ),
@@ -88,14 +83,52 @@ export const screenshots: ComponentScreenshot = {
88
83
  Example: ({ id, handler }) => (
89
84
  <Textarea
90
85
  id={id}
91
- value="Yes"
86
+ value=""
92
87
  onChange={handler}
93
- label="Do you like Braid?"
94
- message="Nice one!"
88
+ label="Label"
89
+ message="Positive message"
95
90
  tone="positive"
96
91
  />
97
92
  ),
98
93
  },
94
+ {
95
+ label: 'Textarea disabled',
96
+ Container,
97
+ Example: ({ id, handler }) => (
98
+ <Stack space="gutter">
99
+ <Textarea
100
+ label="With no value or placeholder"
101
+ id={`${id}_1`}
102
+ value=""
103
+ disabled={true}
104
+ onChange={handler}
105
+ />
106
+ <Textarea
107
+ label="With value and no placeholder"
108
+ id={`${id}_2`}
109
+ value="Text value"
110
+ disabled={true}
111
+ onChange={handler}
112
+ />
113
+ <Textarea
114
+ label="With no value and a placeholder"
115
+ id={`${id}_3`}
116
+ value=""
117
+ disabled={true}
118
+ placeholder="Placeholder text"
119
+ onChange={handler}
120
+ />
121
+ <Textarea
122
+ label="With value and a placeholder"
123
+ id={`${id}_4`}
124
+ value="Text value"
125
+ disabled={true}
126
+ placeholder="Placeholder text"
127
+ onChange={handler}
128
+ />
129
+ </Stack>
130
+ ),
131
+ },
99
132
  {
100
133
  label: 'Textarea grow field with typing, limited to 6 lines',
101
134
  Container,
@@ -107,7 +140,7 @@ export const screenshots: ComponentScreenshot = {
107
140
  id={id}
108
141
  value={value}
109
142
  onChange={(e) => setValue(e.currentTarget.value)}
110
- label="Do you like Braid?"
143
+ label="Label"
111
144
  lineLimit={6}
112
145
  />
113
146
  );
@@ -124,7 +157,7 @@ export const screenshots: ComponentScreenshot = {
124
157
  id={id}
125
158
  value={value}
126
159
  onChange={(e) => setValue(e.currentTarget.value)}
127
- label="Do you like Braid?"
160
+ label="Label"
128
161
  characterLimit={50}
129
162
  />
130
163
  );
@@ -143,7 +176,7 @@ export const screenshots: ComponentScreenshot = {
143
176
  id={id}
144
177
  value={value}
145
178
  onChange={(e) => setValue(e.currentTarget.value)}
146
- label="Do you like Braid?"
179
+ label="Label"
147
180
  characterLimit={50}
148
181
  />
149
182
  );
@@ -162,7 +195,7 @@ export const screenshots: ComponentScreenshot = {
162
195
  id={id}
163
196
  value={value}
164
197
  onChange={(e) => setValue(e.currentTarget.value)}
165
- label="Do you like Braid?"
198
+ label="Label"
166
199
  characterLimit={9}
167
200
  />
168
201
  );
@@ -181,7 +214,7 @@ export const screenshots: ComponentScreenshot = {
181
214
  id={id}
182
215
  value={value}
183
216
  onChange={(e) => setValue(e.currentTarget.value)}
184
- label="Do you like Braid?"
217
+ label="Label"
185
218
  description="Characters 9-22 are invalid"
186
219
  highlightRanges={[{ start: 9, end: 22 }]}
187
220
  />
@@ -201,7 +234,7 @@ export const screenshots: ComponentScreenshot = {
201
234
  id={id}
202
235
  value={value}
203
236
  onChange={(e) => setValue(e.currentTarget.value)}
204
- label="Do you like Braid?"
237
+ label="Label"
205
238
  description="Characters 9-22 are invalid"
206
239
  characterLimit={50}
207
240
  highlightRanges={[{ start: 9, end: 22 }]}
@@ -218,7 +251,7 @@ export const screenshots: ComponentScreenshot = {
218
251
 
219
252
  return (
220
253
  <Textarea
221
- label="Do you like Braid?"
254
+ label="Label"
222
255
  id={id}
223
256
  onChange={(e) => setValue(e.currentTarget.value)}
224
257
  value={value}
@@ -176,7 +176,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
176
176
  updateScroll(event.currentTarget.scrollTop)
177
177
  : undefined
178
178
  }
179
- placeholder={placeholder}
179
+ placeholder={!restProps.disabled ? placeholder : undefined}
180
180
  className={[styles.field, className]}
181
181
  {...fieldProps}
182
182
  ref={ref}
@@ -1,4 +1,9 @@
1
- import React, { AllHTMLAttributes, ChangeEvent, ReactNode } from 'react';
1
+ import React, {
2
+ AllHTMLAttributes,
3
+ forwardRef,
4
+ ChangeEvent,
5
+ ReactNode,
6
+ } from 'react';
2
7
  import { Box } from '../Box/Box';
3
8
  import { FieldOverlay } from '../private/FieldOverlay/FieldOverlay';
4
9
  import { Text } from '../Text/Text';
@@ -30,111 +35,109 @@ const handleChange =
30
35
  }
31
36
  };
32
37
 
33
- export const Toggle = ({
34
- id,
35
- on,
36
- onChange,
37
- label,
38
- align = 'left',
39
- size = 'standard',
40
- data,
41
- }: ToggleProps) => {
42
- const showBorder = useBackgroundLightness() === 'light';
38
+ export const Toggle = forwardRef<HTMLInputElement, ToggleProps>(
39
+ (
40
+ { id, on, onChange, label, align = 'left', size = 'standard', data },
41
+ forwardedRef,
42
+ ) => {
43
+ const showBorder = useBackgroundLightness() === 'light';
43
44
 
44
- return (
45
- <Box
46
- position="relative"
47
- zIndex={0}
48
- display="flex"
49
- flexDirection={align === 'left' ? undefined : 'rowReverse'}
50
- className={styles.root}
51
- {...(data ? buildDataAttributes(data) : undefined)}
52
- >
53
- <Box
54
- component="input"
55
- type="checkbox"
56
- id={id}
57
- checked={on}
58
- onChange={handleChange(onChange)}
59
- position="absolute"
60
- zIndex={1}
61
- cursor="pointer"
62
- opacity={0}
63
- className={[
64
- styles.realField,
65
- styles.realFieldPosition[size],
66
- styles.fieldSize[size],
67
- ]}
68
- />
45
+ return (
69
46
  <Box
70
47
  position="relative"
48
+ zIndex={0}
71
49
  display="flex"
72
- alignItems="center"
73
- flexShrink={0}
74
- className={[
75
- styles.slideContainer,
76
- styles.slideContainerSize[size],
77
- styles.fieldSize[size],
78
- ]}
50
+ flexDirection={align === 'left' ? undefined : 'rowReverse'}
51
+ className={styles.root}
52
+ {...(data ? buildDataAttributes(data) : undefined)}
79
53
  >
80
54
  <Box
55
+ component="input"
56
+ type="checkbox"
57
+ id={id}
58
+ checked={on}
59
+ onChange={handleChange(onChange)}
81
60
  position="absolute"
82
- width="full"
83
- overflow="hidden"
84
- borderRadius="full"
85
- className={[styles.slideTrack[size], styles.slideTrackBackground]}
61
+ zIndex={1}
62
+ cursor="pointer"
63
+ opacity={0}
64
+ className={[
65
+ styles.realField,
66
+ styles.realFieldPosition[size],
67
+ styles.fieldSize[size],
68
+ ]}
69
+ ref={forwardedRef}
70
+ />
71
+ <Box
72
+ position="relative"
73
+ display="flex"
74
+ alignItems="center"
75
+ flexShrink={0}
76
+ className={[
77
+ styles.slideContainer,
78
+ styles.slideContainerSize[size],
79
+ styles.fieldSize[size],
80
+ ]}
86
81
  >
87
82
  <Box
88
83
  position="absolute"
89
84
  width="full"
90
- height="full"
91
- background="formAccent"
85
+ overflow="hidden"
86
+ borderRadius="full"
87
+ className={[styles.slideTrack[size], styles.slideTrackBackground]}
88
+ >
89
+ <Box
90
+ position="absolute"
91
+ width="full"
92
+ height="full"
93
+ background="formAccent"
94
+ transition="fast"
95
+ className={styles.slideTrackSelected}
96
+ />
97
+ </Box>
98
+ <Box
99
+ position="absolute"
100
+ background="input"
101
+ boxShadow={showBorder ? 'borderField' : undefined}
92
102
  transition="fast"
93
- className={styles.slideTrackSelected}
94
- />
103
+ display="flex"
104
+ alignItems="center"
105
+ justifyContent="center"
106
+ borderRadius="full"
107
+ className={styles.slider[size]}
108
+ >
109
+ <FieldOverlay className={styles.icon}>
110
+ <IconTick tone="formAccent" size="fill" />
111
+ </FieldOverlay>
112
+ <FieldOverlay
113
+ variant="focus"
114
+ borderRadius="full"
115
+ className={styles.focusOverlay}
116
+ />
117
+ <FieldOverlay
118
+ variant="hover"
119
+ borderRadius="full"
120
+ className={styles.hoverOverlay}
121
+ />
122
+ </Box>
95
123
  </Box>
96
124
  <Box
97
- position="absolute"
98
- background="input"
99
- boxShadow={showBorder ? 'borderField' : undefined}
100
- transition="fast"
101
- display="flex"
102
- alignItems="center"
103
- justifyContent="center"
104
- borderRadius="full"
105
- className={styles.slider[size]}
125
+ component="label"
126
+ htmlFor={id}
127
+ paddingLeft={align === 'left' ? 'xsmall' : undefined}
128
+ paddingRight={
129
+ align === 'right' || align === 'justify' ? 'xsmall' : undefined
130
+ }
131
+ flexGrow={align === 'justify' ? 1 : undefined}
132
+ userSelect="none"
133
+ cursor="pointer"
134
+ className={[styles.label[size], virtualTouchable()]}
106
135
  >
107
- <FieldOverlay className={styles.icon}>
108
- <IconTick tone="formAccent" size="fill" />
109
- </FieldOverlay>
110
- <FieldOverlay
111
- variant="focus"
112
- borderRadius="full"
113
- className={styles.focusOverlay}
114
- />
115
- <FieldOverlay
116
- variant="hover"
117
- borderRadius="full"
118
- className={styles.hoverOverlay}
119
- />
136
+ <Text baseline={false} weight={on ? 'strong' : undefined} size={size}>
137
+ {label}
138
+ </Text>
120
139
  </Box>
121
140
  </Box>
122
- <Box
123
- component="label"
124
- htmlFor={id}
125
- paddingLeft={align === 'left' ? 'xsmall' : undefined}
126
- paddingRight={
127
- align === 'right' || align === 'justify' ? 'xsmall' : undefined
128
- }
129
- flexGrow={align === 'justify' ? 1 : undefined}
130
- userSelect="none"
131
- cursor="pointer"
132
- className={[styles.label[size], virtualTouchable()]}
133
- >
134
- <Text baseline={false} weight={on ? 'strong' : undefined} size={size}>
135
- {label}
136
- </Text>
137
- </Box>
138
- </Box>
139
- );
140
- };
141
+ );
142
+ },
143
+ );
@@ -25,6 +25,7 @@ export const ClearField = ({ hide = false, onClear, inputRef }: Props) => {
25
25
 
26
26
  return (
27
27
  <Box
28
+ component="span"
28
29
  height="touchable"
29
30
  width="touchable"
30
31
  display="flex"
@@ -80,6 +80,7 @@ interface FieldRenderProps extends Pick<FieldBaseProps, PassthroughProps> {
80
80
  type InternalFieldProps = FieldBaseProps &
81
81
  FieldLabelVariant & {
82
82
  secondaryIcon?: ReactNode;
83
+ alwaysShowSecondaryIcon?: boolean;
83
84
  children(
84
85
  overlays: ReactNode,
85
86
  props: FieldRenderProps,
@@ -104,6 +105,7 @@ export const Field = ({
104
105
  'aria-describedby': ariaDescribedBy,
105
106
  data,
106
107
  secondaryIcon,
108
+ alwaysShowSecondaryIcon = false,
107
109
  autoFocus,
108
110
  icon,
109
111
  prefix,
@@ -126,6 +128,8 @@ export const Field = ({
126
128
 
127
129
  const hasValue = typeof value === 'string' ? value.length > 0 : value != null;
128
130
  const hasVisualLabel = 'label' in restProps;
131
+ const showSecondaryIcon =
132
+ alwaysShowSecondaryIcon || (secondaryIcon && hasValue);
129
133
 
130
134
  const overlays = (
131
135
  <Fragment>
@@ -151,6 +155,7 @@ export const Field = ({
151
155
  id={labelId}
152
156
  htmlFor={id}
153
157
  label={'label' in restProps ? restProps.label : undefined}
158
+ disabled={disabled}
154
159
  secondaryLabel={
155
160
  'secondaryLabel' in restProps ? restProps.secondaryLabel : undefined
156
161
  }
@@ -169,7 +174,7 @@ export const Field = ({
169
174
  background={fieldBackground}
170
175
  borderRadius="standard"
171
176
  display="flex"
172
- className={secondaryIcon ? styles.secondaryIconSpace : undefined}
177
+ className={showSecondaryIcon ? styles.secondaryIconSpace : undefined}
173
178
  >
174
179
  {children(
175
180
  overlays,
@@ -179,7 +184,7 @@ export const Field = ({
179
184
  background: fieldBackground,
180
185
  width: 'full',
181
186
  paddingLeft: fieldPadding,
182
- paddingRight: secondaryIcon ? undefined : fieldPadding,
187
+ paddingRight: showSecondaryIcon ? undefined : fieldPadding,
183
188
  borderRadius: 'standard',
184
189
  outline: 'none',
185
190
  'aria-describedby': mergeIds(
@@ -203,7 +208,7 @@ export const Field = ({
203
208
  styles.placeholderColor,
204
209
  useText({
205
210
  backgroundContext: fieldBackground,
206
- tone: hasValue ? 'neutral' : 'secondary',
211
+ tone: hasValue && !disabled ? 'neutral' : 'secondary',
207
212
  size: 'standard',
208
213
  baseline: false,
209
214
  }),
@@ -230,6 +235,7 @@ export const Field = ({
230
235
  ) : null,
231
236
  secondaryIcon ? (
232
237
  <Box
238
+ component="span"
233
239
  position="absolute"
234
240
  width="touchable"
235
241
  height="touchable"
@@ -103,6 +103,7 @@ export const FieldGroup = ({
103
103
  label={restProps.label}
104
104
  secondaryLabel={secondaryLabel}
105
105
  tertiaryLabel={tertiaryLabel}
106
+ disabled={disabled}
106
107
  description={description}
107
108
  descriptionId={descriptionId}
108
109
  />
@@ -59,6 +59,9 @@ const mark = style({
59
59
  const select = style([
60
60
  field,
61
61
  style({
62
+ ':disabled': {
63
+ opacity: 1,
64
+ },
62
65
  selectors: {
63
66
  '&::-ms-expand': {
64
67
  display: 'none',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-design-system",
3
- "version": "30.4.3",
3
+ "version": "30.7.0",
4
4
  "description": "Themeable design system for the SEEK Group",
5
5
  "main": "lib/components/index.ts",
6
6
  "sideEffects": [
@@ -54,7 +54,6 @@
54
54
  "@types/classnames": "^2.2.11",
55
55
  "@types/dedent": "^0.7.0",
56
56
  "@types/lodash": "^4.14.168",
57
- "@types/react": "^16.8.8",
58
57
  "@types/uuid": "^8.3.0",
59
58
  "@vanilla-extract/css": "^1.6.1",
60
59
  "@vanilla-extract/css-utils": "^0.1.1",
@@ -97,7 +96,8 @@
97
96
  "@types/babel-plugin-macros": "^2.8.4",
98
97
  "@types/fs-extra": "^9.0.6",
99
98
  "@types/prettier": "^2.1.6",
100
- "@types/react-dom": "^16.8.2",
99
+ "@types/react": "^17.0.0",
100
+ "@types/react-dom": "^17.0.0",
101
101
  "@types/react-router-dom": "^5.1.7",
102
102
  "@types/sanitize-html": "^1.27.1",
103
103
  "@types/webpack-env": "^1.16.0",