@khanacademy/wonder-blocks-switch 1.0.6 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @khanacademy/wonder-blocks-switch
2
2
 
3
+ ## 1.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 1f263385: Use `aria-disabled` instead of `disabled` for enabling focus on Screen Readers.
8
+
9
+ ## 1.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - fc6cec0b: Add theming to Switch and new color tokens for theming
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [5725703a]
18
+ - Updated dependencies [fc6cec0b]
19
+ - @khanacademy/wonder-blocks-theming@1.1.0
20
+
3
21
  ## 1.0.6
4
22
 
5
23
  ### Patch Changes
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import { AriaProps } from "@khanacademy/wonder-blocks-core";
3
3
  declare const Switch: React.ForwardRefExoticComponent<Pick<AriaProps, "aria-describedby" | "aria-label" | "aria-labelledby"> & {
4
4
  /**
5
- * Whether this compoonent is checked.
5
+ * Whether this component is checked.
6
6
  */
7
7
  checked: boolean;
8
8
  /**
package/dist/es/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { StyleSheet } from 'aphrodite';
3
- import { addStyle, UniqueIDProvider, View } from '@khanacademy/wonder-blocks-core';
4
- import Color, { mix } from '@khanacademy/wonder-blocks-color';
5
- import Spacing from '@khanacademy/wonder-blocks-spacing';
3
+ import { addStyle, useUniqueIdWithMock, View } from '@khanacademy/wonder-blocks-core';
4
+ import { tokens, mergeTheme, createThemeContext, ThemeSwitcherContext, useScopedTheme, useStyles } from '@khanacademy/wonder-blocks-theming';
6
5
 
7
6
  function _extends() {
8
7
  _extends = Object.assign ? Object.assign.bind() : function (target) {
@@ -19,9 +18,105 @@ function _extends() {
19
18
  return _extends.apply(this, arguments);
20
19
  }
21
20
 
21
+ const theme$1 = {
22
+ color: {
23
+ bg: {
24
+ switch: {
25
+ off: tokens.color.offBlack50,
26
+ disabledOff: tokens.color.offBlack32,
27
+ activeOff: tokens.color.offBlack64,
28
+ on: tokens.color.blue,
29
+ disabledOn: tokens.color.fadedBlue,
30
+ activeOn: tokens.color.activeBlue
31
+ },
32
+ slider: {
33
+ on: tokens.color.white,
34
+ off: tokens.color.white
35
+ },
36
+ icon: {
37
+ on: tokens.color.blue,
38
+ disabledOn: tokens.color.fadedBlue,
39
+ off: tokens.color.offBlack50,
40
+ disabledOff: tokens.color.offBlack32
41
+ }
42
+ },
43
+ outline: {
44
+ default: tokens.color.blue
45
+ }
46
+ },
47
+ border: {
48
+ radius: {
49
+ small: tokens.spacing.small_12,
50
+ full: tokens.border.radius.full
51
+ }
52
+ },
53
+ size: {
54
+ height: {
55
+ none: 0,
56
+ medium: 20,
57
+ large: tokens.spacing.large_24
58
+ },
59
+ width: {
60
+ none: 0,
61
+ small: tokens.spacing.xxxxSmall_2,
62
+ medium: 20,
63
+ large: 40
64
+ },
65
+ offset: {
66
+ default: 1
67
+ }
68
+ },
69
+ spacing: {
70
+ slider: {
71
+ position: tokens.spacing.xxxxSmall_2
72
+ },
73
+ icon: {
74
+ position: tokens.spacing.xxxSmall_4
75
+ },
76
+ transform: {
77
+ default: `translateX(${tokens.spacing.medium_16}px)`,
78
+ transition: "transform 0.15s ease-in-out"
79
+ }
80
+ }
81
+ };
82
+
83
+ const theme = mergeTheme(theme$1, {
84
+ color: {
85
+ bg: {
86
+ switch: {
87
+ off: tokens.color.white50,
88
+ disabledOff: tokens.color.white32,
89
+ activeOff: tokens.color.white50,
90
+ disabledOn: tokens.color.activeBlue
91
+ },
92
+ slider: {
93
+ off: tokens.color.eggplant
94
+ },
95
+ icon: {
96
+ off: tokens.color.white,
97
+ disabledOff: tokens.color.white50,
98
+ disabledOn: tokens.color.activeBlue
99
+ }
100
+ }
101
+ }
102
+ });
103
+
104
+ const themes = {
105
+ default: theme$1,
106
+ khanmigo: theme
107
+ };
108
+ const SwitchThemeContext = createThemeContext(theme$1);
109
+ function ThemedSwitch(props) {
110
+ const currentTheme = React.useContext(ThemeSwitcherContext);
111
+ const theme = themes[currentTheme] || theme$1;
112
+ return React.createElement(SwitchThemeContext.Provider, {
113
+ value: theme
114
+ }, props.children);
115
+ }
116
+
22
117
  const StyledSpan = addStyle("span");
23
118
  const StyledInput = addStyle("input");
24
- const Switch = React.forwardRef(function Switch(props, ref) {
119
+ const SwitchCore = React.forwardRef(function SwitchCore(props, ref) {
25
120
  const {
26
121
  "aria-label": ariaLabel,
27
122
  "aria-labelledby": ariaLabelledBy,
@@ -33,64 +128,67 @@ const Switch = React.forwardRef(function Switch(props, ref) {
33
128
  onChange,
34
129
  testId
35
130
  } = props;
131
+ const ids = useUniqueIdWithMock("labeled-field");
132
+ const uniqueId = id != null ? id : ids.get("labeled-field-id");
133
+ const {
134
+ theme,
135
+ themeName
136
+ } = useScopedTheme(SwitchThemeContext);
137
+ const sharedStyles = useStyles(themedSharedStyles, theme);
36
138
  const handleClick = () => {
37
139
  if (!disabled && onChange) {
38
140
  onChange(!checked);
39
141
  }
40
142
  };
41
143
  const handleChange = () => {};
42
- const stateStyles = _generateStyles(checked, disabled, onChange !== undefined);
144
+ const stateStyles = _generateStyles(checked, onChange !== undefined, disabled, theme, themeName);
43
145
  let styledIcon;
44
146
  if (icon) {
45
- styledIcon = React.cloneElement(icon, _extends({
147
+ styledIcon = React.cloneElement(icon, {
46
148
  size: "small",
47
149
  style: [sharedStyles.icon, stateStyles.icon],
48
150
  "aria-hidden": true
49
- }, icon.props));
151
+ });
50
152
  }
51
- return React.createElement(UniqueIDProvider, {
52
- mockOnFirstRender: true,
53
- scope: "switch"
54
- }, ids => {
55
- const uniqueId = id || ids.get("switch");
56
- return React.createElement(View, {
57
- onClick: handleClick,
58
- style: [sharedStyles.switch, stateStyles.switch, disabled && sharedStyles.disabled],
59
- testId: testId
60
- }, React.createElement(StyledInput, {
61
- "aria-describedby": ariaDescribedBy,
62
- "aria-label": ariaLabel,
63
- "aria-labelledby": ariaLabelledBy,
64
- checked: checked,
65
- disabled: disabled,
66
- id: uniqueId,
67
- onChange: handleChange,
68
- ref: ref,
69
- role: "switch",
70
- style: sharedStyles.hidden,
71
- type: "checkbox"
72
- }), icon && styledIcon, React.createElement(StyledSpan, {
73
- style: [sharedStyles.slider, stateStyles.slider]
74
- }));
75
- });
153
+ return React.createElement(View, {
154
+ onClick: handleClick,
155
+ style: [sharedStyles.switch, stateStyles.switch, disabled && sharedStyles.disabled],
156
+ testId: testId
157
+ }, React.createElement(StyledInput, {
158
+ "aria-describedby": ariaDescribedBy,
159
+ "aria-label": ariaLabel,
160
+ "aria-labelledby": ariaLabelledBy,
161
+ checked: checked,
162
+ "aria-disabled": disabled,
163
+ id: uniqueId,
164
+ onChange: handleChange,
165
+ ref: ref,
166
+ role: "switch",
167
+ style: sharedStyles.hidden,
168
+ type: "checkbox"
169
+ }), icon && styledIcon, React.createElement(StyledSpan, {
170
+ style: [sharedStyles.slider, stateStyles.slider]
171
+ }));
76
172
  });
77
- const sharedStyles = StyleSheet.create({
173
+ const themedSharedStyles = theme => ({
78
174
  hidden: {
79
175
  opacity: 0,
80
- height: 0,
81
- width: 0
176
+ height: theme.size.height.none,
177
+ width: theme.size.width.none
82
178
  },
83
179
  switch: {
84
180
  display: "inline-flex",
85
- height: Spacing.large_24,
86
- width: `calc(${Spacing.xLarge_32}px + ${Spacing.xSmall_8}px)`,
87
- borderRadius: Spacing.small_12,
181
+ height: theme.size.height.large,
182
+ width: theme.size.width.large,
183
+ borderRadius: theme.border.radius.small,
88
184
  flexShrink: 0,
89
- cursor: "pointer",
90
185
  ":hover": {
91
- outlineOffset: 1
186
+ outlineOffset: theme.size.offset.default
92
187
  },
93
- transition: "background-color 0.15s ease-in-out"
188
+ ":focus-within": {
189
+ outline: `solid ${theme.size.width.small}px ${theme.color.outline.default}`,
190
+ outlineOffset: theme.size.offset.default
191
+ }
94
192
  },
95
193
  disabled: {
96
194
  cursor: "auto",
@@ -100,78 +198,75 @@ const sharedStyles = StyleSheet.create({
100
198
  },
101
199
  slider: {
102
200
  position: "absolute",
103
- top: Spacing.xxxxSmall_2,
104
- left: Spacing.xxxxSmall_2,
105
- height: `calc(${Spacing.medium_16}px + ${Spacing.xxxSmall_4}px)`,
106
- width: `calc(${Spacing.medium_16}px + ${Spacing.xxxSmall_4}px)`,
107
- borderRadius: "50%",
108
- backgroundColor: Color.white,
109
- transition: "transform 0.15s ease-in-out"
201
+ top: theme.spacing.slider.position,
202
+ left: theme.spacing.slider.position,
203
+ height: theme.size.height.medium,
204
+ width: theme.size.width.medium,
205
+ borderRadius: theme.border.radius.full,
206
+ backgroundColor: theme.color.bg.slider.on,
207
+ transition: theme.spacing.transform.transition
110
208
  },
111
209
  icon: {
112
210
  position: "absolute",
113
- top: Spacing.xxxSmall_4,
114
- left: Spacing.xxxSmall_4,
211
+ top: theme.spacing.icon.position,
212
+ left: theme.spacing.icon.position,
115
213
  zIndex: 1,
116
- transition: "0.15s ease-in-out",
117
- transitionProperty: "transform, color"
214
+ transition: theme.spacing.transform.transition
118
215
  }
119
216
  });
120
217
  const styles = {};
121
- const _generateStyles = (checked, disabled, clickable) => {
122
- const checkedStyle = `${checked}-${disabled}-${clickable}`;
218
+ const _generateStyles = (checked, clickable, disabled, theme, themeName) => {
219
+ const checkedStyle = `${checked}-${clickable}-${disabled}-${themeName}`;
123
220
  if (styles[checkedStyle]) {
124
221
  return styles[checkedStyle];
125
222
  }
126
223
  let newStyles = {};
127
- const disabledBlue = mix(Color.blue, Color.offBlack50);
128
- const activeBlue = mix(Color.offBlack32, Color.blue);
224
+ const sharedSwitchStyles = {
225
+ cursor: clickable ? "pointer" : "auto",
226
+ ":hover": {
227
+ outline: clickable ? `solid ${theme.size.width.small}px ${theme.color.outline.default}` : "none"
228
+ }
229
+ };
129
230
  if (checked) {
130
231
  newStyles = {
131
- switch: {
132
- backgroundColor: disabled ? disabledBlue : Color.blue,
232
+ switch: _extends({
233
+ backgroundColor: disabled ? theme.color.bg.switch.disabledOn : theme.color.bg.switch.on,
133
234
  ":active": {
134
- backgroundColor: !disabled && clickable && activeBlue
135
- },
136
- ":focus-within": {
137
- outline: `solid ${Spacing.xxxxSmall_2}px ${Color.blue}`,
138
- outlineOffset: 1
139
- },
140
- ":hover": {
141
- outline: clickable ? `solid ${Spacing.xxxxSmall_2}px ${Color.blue}` : "none"
235
+ backgroundColor: !disabled && clickable ? theme.color.bg.switch.activeOn : undefined
142
236
  }
143
- },
237
+ }, sharedSwitchStyles),
144
238
  slider: {
145
- transform: `translateX(${Spacing.medium_16}px)`
239
+ transform: theme.spacing.transform.default
146
240
  },
147
241
  icon: {
148
- color: disabled ? disabledBlue : Color.blue,
149
- transform: `translateX(${Spacing.medium_16}px)`
242
+ color: disabled ? theme.color.bg.icon.disabledOn : theme.color.bg.icon.on,
243
+ transform: theme.spacing.transform.default
150
244
  }
151
245
  };
152
246
  } else {
153
247
  newStyles = {
154
- switch: {
155
- backgroundColor: disabled ? Color.offBlack32 : Color.offBlack50,
248
+ switch: _extends({
249
+ backgroundColor: disabled ? theme.color.bg.switch.disabledOff : theme.color.bg.switch.off,
156
250
  ":active": {
157
- backgroundColor: !disabled && clickable && Color.offBlack64
158
- },
159
- ":focus-within": {
160
- outline: `solid ${Spacing.xxxxSmall_2}px ${Color.blue}`,
161
- outlineOffset: 1
162
- },
163
- ":hover": {
164
- outline: clickable ? `solid ${Spacing.xxxxSmall_2}px ${Color.blue}` : "none"
251
+ backgroundColor: !disabled && clickable ? theme.color.bg.switch.activeOff : undefined
165
252
  }
253
+ }, sharedSwitchStyles),
254
+ slider: {
255
+ backgroundColor: theme.color.bg.slider.off
166
256
  },
167
257
  icon: {
168
- color: disabled ? Color.offBlack32 : Color.offBlack50
258
+ color: disabled ? theme.color.bg.icon.disabledOff : theme.color.bg.icon.off
169
259
  }
170
260
  };
171
261
  }
172
262
  styles[checkedStyle] = StyleSheet.create(newStyles);
173
263
  return styles[checkedStyle];
174
264
  };
265
+ const Switch = React.forwardRef(function Switch(props, ref) {
266
+ return React.createElement(ThemedSwitch, null, React.createElement(SwitchCore, _extends({}, props, {
267
+ ref: ref
268
+ })));
269
+ });
175
270
  Switch.displayName = "Switch";
176
271
 
177
272
  export { Switch as default };