@khanacademy/wonder-blocks-clickable 7.0.3 → 7.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @khanacademy/wonder-blocks-clickable
2
2
 
3
+ ## 7.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 38042e2: Add `viewTransition` prop to support ReactRouter's v6 `Link.viewTransition` prop which supports the View Transitions API. See https://reactrouter.com/6.30.0/components/link#viewtransition
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [28fa0c0]
12
+ - Updated dependencies [28fa0c0]
13
+ - @khanacademy/wonder-blocks-core@12.3.0
14
+
15
+ ## 7.0.4
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [b9e4946]
20
+ - @khanacademy/wonder-blocks-tokens@10.0.0
21
+ - @khanacademy/wonder-blocks-core@12.2.1
22
+
3
23
  ## 7.0.3
4
24
 
5
25
  ### Patch Changes
@@ -87,6 +87,15 @@ type CommonProps = Readonly<{
87
87
  * Respond to a raw "mouseup" event.
88
88
  */
89
89
  onMouseUp?: (e: React.MouseEvent) => unknown;
90
+ /**
91
+ * An optional prop that enables a
92
+ * [https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API](View
93
+ * Transition) for this navigation by wrapping the final state update in
94
+ * `document.startViewTransition()`.
95
+ *
96
+ * @see https://reactrouter.com/6.30.0/components/link#viewtransition
97
+ */
98
+ viewTransition?: boolean;
90
99
  }>;
91
100
  type Props = (CommonProps & Readonly<{
92
101
  /**
package/dist/es/index.js CHANGED
@@ -1,497 +1,16 @@
1
- import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
2
- import _extends from '@babel/runtime/helpers/extends';
1
+ import { jsx } from 'react/jsx-runtime';
3
2
  import * as React from 'react';
4
3
  import { StyleSheet } from 'aphrodite';
5
4
  import { useNavigate, Link, useInRouterContext } from 'react-router-dom-v5-compat';
6
5
  import { keys, addStyle } from '@khanacademy/wonder-blocks-core';
7
6
  import { border, semanticColor } from '@khanacademy/wonder-blocks-tokens';
8
7
 
9
- const getAppropriateTriggersForRole = role => {
10
- switch (role) {
11
- case "link":
12
- return {
13
- triggerOnEnter: true,
14
- triggerOnSpace: false
15
- };
16
- case "checkbox":
17
- case "radio":
18
- case "listbox":
19
- return {
20
- triggerOnEnter: false,
21
- triggerOnSpace: true
22
- };
23
- case "button":
24
- case "menuitem":
25
- case "menu":
26
- case "option":
27
- default:
28
- return {
29
- triggerOnEnter: true,
30
- triggerOnSpace: true
31
- };
32
- }
33
- };
34
- const disabledHandlers = {
35
- onClick: () => void 0,
36
- onMouseEnter: () => void 0,
37
- onMouseLeave: () => void 0,
38
- onMouseDown: () => void 0,
39
- onMouseUp: () => void 0,
40
- onTouchStart: () => void 0,
41
- onTouchEnd: () => void 0,
42
- onTouchCancel: () => void 0,
43
- onKeyDown: () => void 0,
44
- onKeyUp: () => void 0
45
- };
46
- const startState = {
47
- hovered: false,
48
- focused: false,
49
- pressed: false,
50
- waiting: false
51
- };
52
- class ClickableBehavior extends React.Component {
53
- static getDerivedStateFromProps(props, state) {
54
- if (props.disabled) {
55
- return _extends({}, startState, {
56
- focused: state.focused
57
- });
58
- } else {
59
- return null;
60
- }
61
- }
62
- constructor(props) {
63
- super(props);
64
- this.waitingForClick = void 0;
65
- this.enterClick = void 0;
66
- this.handleClick = e => {
67
- const {
68
- onClick = undefined,
69
- beforeNav = undefined,
70
- safeWithNav = undefined
71
- } = this.props;
72
- if (this.enterClick) {
73
- return;
74
- }
75
- if (onClick || beforeNav || safeWithNav) {
76
- this.waitingForClick = false;
77
- }
78
- this.runCallbackAndMaybeNavigate(e);
79
- };
80
- this.handleMouseEnter = e => {
81
- if (!this.waitingForClick) {
82
- this.setState({
83
- hovered: true
84
- });
85
- }
86
- };
87
- this.handleMouseLeave = () => {
88
- if (!this.waitingForClick) {
89
- this.setState({
90
- hovered: false,
91
- pressed: false,
92
- focused: false
93
- });
94
- }
95
- };
96
- this.handleMouseDown = e => {
97
- if (this.props.onMouseDown) {
98
- this.props.onMouseDown(e);
99
- }
100
- this.setState({
101
- pressed: true
102
- });
103
- };
104
- this.handleMouseUp = e => {
105
- if (this.props.onMouseUp) {
106
- this.props.onMouseUp(e);
107
- }
108
- this.setState({
109
- pressed: false,
110
- focused: false
111
- });
112
- };
113
- this.handleTouchStart = () => {
114
- this.setState({
115
- pressed: true
116
- });
117
- };
118
- this.handleTouchEnd = () => {
119
- this.setState({
120
- pressed: false
121
- });
122
- this.waitingForClick = true;
123
- };
124
- this.handleTouchCancel = () => {
125
- this.setState({
126
- pressed: false
127
- });
128
- this.waitingForClick = true;
129
- };
130
- this.handleKeyDown = e => {
131
- const {
132
- onKeyDown,
133
- role
134
- } = this.props;
135
- if (onKeyDown) {
136
- onKeyDown(e);
137
- }
138
- const keyName = e.key;
139
- const {
140
- triggerOnEnter,
141
- triggerOnSpace
142
- } = getAppropriateTriggersForRole(role);
143
- if (triggerOnEnter && keyName === keys.enter || triggerOnSpace && keyName === keys.space) {
144
- e.preventDefault();
145
- this.setState({
146
- pressed: true
147
- });
148
- } else if (!triggerOnEnter && keyName === keys.enter) {
149
- this.enterClick = true;
150
- }
151
- };
152
- this.handleKeyUp = e => {
153
- const {
154
- onKeyUp,
155
- role
156
- } = this.props;
157
- if (onKeyUp) {
158
- onKeyUp(e);
159
- }
160
- const keyName = e.key;
161
- const {
162
- triggerOnEnter,
163
- triggerOnSpace
164
- } = getAppropriateTriggersForRole(role);
165
- if (triggerOnEnter && keyName === keys.enter || triggerOnSpace && keyName === keys.space) {
166
- this.setState({
167
- pressed: false,
168
- focused: true
169
- });
170
- this.runCallbackAndMaybeNavigate(e);
171
- } else if (!triggerOnEnter && keyName === keys.enter) {
172
- this.enterClick = false;
173
- }
174
- };
175
- this.handleFocus = e => {
176
- const {
177
- onFocus
178
- } = this.props;
179
- this.setState({
180
- focused: true
181
- }, () => {
182
- if (onFocus) {
183
- onFocus(e);
184
- }
185
- });
186
- };
187
- this.handleBlur = e => {
188
- this.setState({
189
- focused: false,
190
- pressed: false
191
- });
192
- };
193
- this.state = startState;
194
- this.waitingForClick = false;
195
- this.enterClick = false;
196
- }
197
- navigateOrReset(shouldNavigate) {
198
- if (shouldNavigate) {
199
- const {
200
- navigate,
201
- href,
202
- skipClientNav,
203
- target = undefined
204
- } = this.props;
205
- if (href) {
206
- if (target === "_blank") {
207
- window.open(href, "_blank");
208
- this.setState({
209
- waiting: false
210
- });
211
- } else if (navigate && !skipClientNav) {
212
- navigate(href);
213
- this.setState({
214
- waiting: false
215
- });
216
- } else {
217
- window.location.assign(href);
218
- }
219
- }
220
- } else {
221
- this.setState({
222
- waiting: false
223
- });
224
- }
225
- }
226
- handleSafeWithNav(safeWithNav, shouldNavigate) {
227
- const {
228
- skipClientNav,
229
- navigate
230
- } = this.props;
231
- if (navigate && !skipClientNav || this.props.target === "_blank") {
232
- safeWithNav();
233
- this.navigateOrReset(shouldNavigate);
234
- return Promise.resolve();
235
- } else {
236
- if (!this.state.waiting) {
237
- this.setState({
238
- waiting: true
239
- });
240
- }
241
- return safeWithNav().then(() => {
242
- if (!this.state.waiting) {
243
- this.setState({
244
- waiting: true
245
- });
246
- }
247
- return;
248
- }).catch(error => {}).finally(() => {
249
- this.navigateOrReset(shouldNavigate);
250
- });
251
- }
252
- }
253
- runCallbackAndMaybeNavigate(e) {
254
- const {
255
- onClick = undefined,
256
- beforeNav = undefined,
257
- safeWithNav = undefined,
258
- href,
259
- type
260
- } = this.props;
261
- let shouldNavigate = true;
262
- let canSubmit = true;
263
- if (onClick) {
264
- onClick(e);
265
- }
266
- if (e.defaultPrevented) {
267
- shouldNavigate = false;
268
- canSubmit = false;
269
- }
270
- e.preventDefault();
271
- if (!href && type === "submit" && canSubmit) {
272
- let target = e.currentTarget;
273
- while (target) {
274
- if (target instanceof window.HTMLFormElement) {
275
- const event = new window.Event("submit", {
276
- bubbles: true,
277
- cancelable: true
278
- });
279
- target.dispatchEvent(event);
280
- break;
281
- }
282
- target = target.parentElement;
283
- }
284
- }
285
- if (beforeNav) {
286
- this.setState({
287
- waiting: true
288
- });
289
- beforeNav().then(() => {
290
- if (safeWithNav) {
291
- return this.handleSafeWithNav(safeWithNav, shouldNavigate);
292
- } else {
293
- return this.navigateOrReset(shouldNavigate);
294
- }
295
- }).catch(() => {});
296
- } else if (safeWithNav) {
297
- return this.handleSafeWithNav(safeWithNav, shouldNavigate);
298
- } else {
299
- this.navigateOrReset(shouldNavigate);
300
- }
301
- }
302
- render() {
303
- const rel = this.props.rel || (this.props.target === "_blank" ? "noopener noreferrer" : undefined);
304
- const childrenProps = this.props.disabled ? _extends({}, disabledHandlers, {
305
- onFocus: this.handleFocus,
306
- onBlur: this.handleBlur,
307
- tabIndex: this.props.tabIndex,
308
- rel
309
- }) : {
310
- onClick: this.handleClick,
311
- onMouseEnter: this.handleMouseEnter,
312
- onMouseLeave: this.handleMouseLeave,
313
- onMouseDown: this.handleMouseDown,
314
- onMouseUp: this.handleMouseUp,
315
- onTouchStart: this.handleTouchStart,
316
- onTouchEnd: this.handleTouchEnd,
317
- onTouchCancel: this.handleTouchCancel,
318
- onKeyDown: this.handleKeyDown,
319
- onKeyUp: this.handleKeyUp,
320
- onFocus: this.handleFocus,
321
- onBlur: this.handleBlur,
322
- tabIndex: this.props.tabIndex,
323
- rel
324
- };
325
- const {
326
- children
327
- } = this.props;
328
- return children && children(this.state, childrenProps);
329
- }
330
- }
331
- ClickableBehavior.defaultProps = {
332
- disabled: false
333
- };
8
+ const getAppropriateTriggersForRole=role=>{switch(role){case"link":return {triggerOnEnter:true,triggerOnSpace:false};case"checkbox":case"radio":case"listbox":return {triggerOnEnter:false,triggerOnSpace:true};case"button":case"menuitem":case"menu":case"option":default:return {triggerOnEnter:true,triggerOnSpace:true}}};const disabledHandlers={onClick:()=>void 0,onMouseEnter:()=>void 0,onMouseLeave:()=>void 0,onMouseDown:()=>void 0,onMouseUp:()=>void 0,onTouchStart:()=>void 0,onTouchEnd:()=>void 0,onTouchCancel:()=>void 0,onKeyDown:()=>void 0,onKeyUp:()=>void 0};const startState={hovered:false,focused:false,pressed:false,waiting:false};class ClickableBehavior extends React.Component{static getDerivedStateFromProps(props,state){if(props.disabled){return {...startState,focused:state.focused}}else {return null}}navigateOrReset(shouldNavigate){if(shouldNavigate){const{navigate,href,skipClientNav,target=undefined}=this.props;if(href){if(target==="_blank"){window.open(href,"_blank");this.setState({waiting:false});}else if(navigate&&!skipClientNav){navigate(href,{viewTransition:this.props.viewTransition});this.setState({waiting:false});}else {window.location.assign(href);}}}else {this.setState({waiting:false});}}handleSafeWithNav(safeWithNav,shouldNavigate){const{skipClientNav,navigate}=this.props;if(navigate&&!skipClientNav||this.props.target==="_blank"){safeWithNav();this.navigateOrReset(shouldNavigate);return Promise.resolve()}else {if(!this.state.waiting){this.setState({waiting:true});}return safeWithNav().then(()=>{if(!this.state.waiting){this.setState({waiting:true});}return}).catch(error=>{}).finally(()=>{this.navigateOrReset(shouldNavigate);})}}runCallbackAndMaybeNavigate(e){const{onClick=undefined,beforeNav=undefined,safeWithNav=undefined,href,type}=this.props;let shouldNavigate=true;let canSubmit=true;if(onClick){onClick(e);}if(e.defaultPrevented){shouldNavigate=false;canSubmit=false;}e.preventDefault();if(!href&&type==="submit"&&canSubmit){let target=e.currentTarget;while(target){if(target instanceof window.HTMLFormElement){const event=new window.Event("submit",{bubbles:true,cancelable:true});target.dispatchEvent(event);break}target=target.parentElement;}}if(beforeNav){this.setState({waiting:true});beforeNav().then(()=>{if(safeWithNav){return this.handleSafeWithNav(safeWithNav,shouldNavigate)}else {return this.navigateOrReset(shouldNavigate)}}).catch(()=>{});}else if(safeWithNav){return this.handleSafeWithNav(safeWithNav,shouldNavigate)}else {this.navigateOrReset(shouldNavigate);}}render(){const rel=this.props.rel||(this.props.target==="_blank"?"noopener noreferrer":undefined);const childrenProps=this.props.disabled?{...disabledHandlers,onFocus:this.handleFocus,onBlur:this.handleBlur,tabIndex:this.props.tabIndex,rel}:{onClick:this.handleClick,onMouseEnter:this.handleMouseEnter,onMouseLeave:this.handleMouseLeave,onMouseDown:this.handleMouseDown,onMouseUp:this.handleMouseUp,onTouchStart:this.handleTouchStart,onTouchEnd:this.handleTouchEnd,onTouchCancel:this.handleTouchCancel,onKeyDown:this.handleKeyDown,onKeyUp:this.handleKeyUp,onFocus:this.handleFocus,onBlur:this.handleBlur,tabIndex:this.props.tabIndex,rel};const{children}=this.props;return children&&children(this.state,childrenProps)}constructor(props){super(props),this.handleClick=e=>{const{onClick=undefined,beforeNav=undefined,safeWithNav=undefined}=this.props;if(this.enterClick){return}if(onClick||beforeNav||safeWithNav){this.waitingForClick=false;}this.runCallbackAndMaybeNavigate(e);},this.handleMouseEnter=e=>{if(!this.waitingForClick){this.setState({hovered:true});}},this.handleMouseLeave=()=>{if(!this.waitingForClick){this.setState({hovered:false,pressed:false,focused:false});}},this.handleMouseDown=e=>{if(this.props.onMouseDown){this.props.onMouseDown(e);}this.setState({pressed:true});},this.handleMouseUp=e=>{if(this.props.onMouseUp){this.props.onMouseUp(e);}this.setState({pressed:false,focused:false});},this.handleTouchStart=()=>{this.setState({pressed:true});},this.handleTouchEnd=()=>{this.setState({pressed:false});this.waitingForClick=true;},this.handleTouchCancel=()=>{this.setState({pressed:false});this.waitingForClick=true;},this.handleKeyDown=e=>{const{onKeyDown,role}=this.props;if(onKeyDown){onKeyDown(e);}const keyName=e.key;const{triggerOnEnter,triggerOnSpace}=getAppropriateTriggersForRole(role);if(triggerOnEnter&&keyName===keys.enter||triggerOnSpace&&keyName===keys.space){e.preventDefault();this.setState({pressed:true});}else if(!triggerOnEnter&&keyName===keys.enter){this.enterClick=true;}},this.handleKeyUp=e=>{const{onKeyUp,role}=this.props;if(onKeyUp){onKeyUp(e);}const keyName=e.key;const{triggerOnEnter,triggerOnSpace}=getAppropriateTriggersForRole(role);if(triggerOnEnter&&keyName===keys.enter||triggerOnSpace&&keyName===keys.space){this.setState({pressed:false,focused:true});this.runCallbackAndMaybeNavigate(e);}else if(!triggerOnEnter&&keyName===keys.enter){this.enterClick=false;}},this.handleFocus=e=>{const{onFocus}=this.props;this.setState({focused:true},()=>{if(onFocus){onFocus(e);}});},this.handleBlur=e=>{this.setState({focused:false,pressed:false});};this.state=startState;this.waitingForClick=false;this.enterClick=false;}}ClickableBehavior.defaultProps={disabled:false};
334
9
 
335
- const isClientSideUrl = href => {
336
- if (typeof href !== "string") {
337
- return false;
338
- }
339
- return !/^(https?:)?\/\//i.test(href) && !/^([^#]*#[\w-]*|[\w\-.]+:)/.test(href);
340
- };
10
+ const isClientSideUrl=href=>{if(typeof href!=="string"){return false}return !/^(https?:)?\/\//i.test(href)&&!/^([^#]*#[\w-]*|[\w\-.]+:)/.test(href)};
341
11
 
342
- function withRouter(Component) {
343
- function WithRouterWrapper(props) {
344
- const navigate = useNavigate();
345
- return React.createElement(Component, _extends({}, props, {
346
- navigate: navigate
347
- }));
348
- }
349
- WithRouterWrapper.displayName = "withRouter(ClickableBehavior)";
350
- return WithRouterWrapper;
351
- }
352
- const ClickableBehaviorWithRouter = withRouter(ClickableBehavior);
353
- function getClickableBehavior(href, skipClientNav, inRouterContext) {
354
- if (inRouterContext && skipClientNav !== true && href && isClientSideUrl(href)) {
355
- return ClickableBehaviorWithRouter;
356
- }
357
- return ClickableBehavior;
358
- }
12
+ function withRouter(Component){function WithRouterWrapper(props){const navigate=useNavigate();return jsx(Component,{...props,navigate:navigate})}WithRouterWrapper.displayName="withRouter(ClickableBehavior)";return WithRouterWrapper}const ClickableBehaviorWithRouter=withRouter(ClickableBehavior);function getClickableBehavior(href,skipClientNav,inRouterContext){if(inRouterContext&&skipClientNav!==true&&href&&isClientSideUrl(href)){return ClickableBehaviorWithRouter}return ClickableBehavior}
359
13
 
360
- const _excluded = ["href", "onClick", "skipClientNav", "beforeNav", "safeWithNav", "style", "target", "testId", "onFocus", "onKeyDown", "onKeyUp", "onMouseDown", "onMouseUp", "hideDefaultFocusRing", "light", "disabled", "tabIndex"];
361
- const StyledA = addStyle("a");
362
- const StyledButton = addStyle("button");
363
- const StyledLink = addStyle(Link);
364
- const Clickable = React.forwardRef(function Clickable(props, ref) {
365
- const getCorrectTag = (clickableState, inRouterContext, commonProps) => {
366
- const activeHref = props.href && !props.disabled;
367
- const useClient = inRouterContext && !props.skipClientNav && isClientSideUrl(props.href || "");
368
- if (activeHref && useClient && props.href) {
369
- return React.createElement(StyledLink, _extends({}, commonProps, {
370
- to: props.href,
371
- role: props.role,
372
- target: props.target || undefined,
373
- "aria-disabled": props.disabled ? "true" : "false",
374
- ref: ref
375
- }), props.children(clickableState));
376
- } else if (activeHref && !useClient) {
377
- return React.createElement(StyledA, _extends({}, commonProps, {
378
- href: props.href,
379
- role: props.role,
380
- target: props.target || undefined,
381
- "aria-disabled": props.disabled ? "true" : "false",
382
- ref: ref
383
- }), props.children(clickableState));
384
- } else {
385
- return React.createElement(StyledButton, _extends({}, commonProps, {
386
- type: "button",
387
- "aria-disabled": props.disabled,
388
- ref: ref
389
- }), props.children(clickableState));
390
- }
391
- };
392
- const inRouterContext = useInRouterContext();
393
- const {
394
- href,
395
- onClick,
396
- skipClientNav,
397
- beforeNav = undefined,
398
- safeWithNav = undefined,
399
- style,
400
- target = undefined,
401
- testId,
402
- onFocus,
403
- onKeyDown,
404
- onKeyUp,
405
- onMouseDown,
406
- onMouseUp,
407
- hideDefaultFocusRing,
408
- light,
409
- disabled,
410
- tabIndex
411
- } = props,
412
- restProps = _objectWithoutPropertiesLoose(props, _excluded);
413
- const ClickableBehavior = getClickableBehavior(href, skipClientNav, inRouterContext);
414
- const getStyle = state => [styles.reset, styles.link, !hideDefaultFocusRing && state.focused && (light ? styles.focusedLight : styles.focused), disabled && styles.disabled, style];
415
- if (beforeNav) {
416
- return React.createElement(ClickableBehavior, {
417
- href: href,
418
- onClick: onClick,
419
- beforeNav: beforeNav,
420
- safeWithNav: safeWithNav,
421
- onFocus: onFocus,
422
- onKeyDown: onKeyDown,
423
- onKeyUp: onKeyUp,
424
- onMouseDown: onMouseDown,
425
- onMouseUp: onMouseUp,
426
- disabled: disabled,
427
- tabIndex: tabIndex
428
- }, (state, childrenProps) => getCorrectTag(state, inRouterContext, _extends({}, restProps, {
429
- "data-testid": testId,
430
- style: getStyle(state)
431
- }, childrenProps)));
432
- } else {
433
- return React.createElement(ClickableBehavior, {
434
- href: href,
435
- onClick: onClick,
436
- safeWithNav: safeWithNav,
437
- onFocus: onFocus,
438
- onKeyDown: onKeyDown,
439
- onKeyUp: onKeyUp,
440
- onMouseDown: onMouseDown,
441
- onMouseUp: onMouseUp,
442
- target: target,
443
- disabled: disabled,
444
- tabIndex: tabIndex
445
- }, (state, childrenProps) => getCorrectTag(state, inRouterContext, _extends({}, restProps, {
446
- "data-testid": testId,
447
- style: getStyle(state)
448
- }, childrenProps)));
449
- }
450
- });
451
- Clickable.defaultProps = {
452
- light: false,
453
- disabled: false
454
- };
455
- const styles = StyleSheet.create({
456
- reset: {
457
- border: "none",
458
- margin: 0,
459
- padding: 0,
460
- width: "auto",
461
- overflow: "visible",
462
- background: "transparent",
463
- textDecoration: "none",
464
- color: "inherit",
465
- font: "inherit",
466
- boxSizing: "border-box",
467
- touchAction: "manipulation",
468
- userSelect: "none",
469
- outline: "none",
470
- lineHeight: "normal",
471
- WebkitFontSmoothing: "inherit",
472
- MozOsxFontSmoothing: "inherit"
473
- },
474
- link: {
475
- cursor: "pointer"
476
- },
477
- focused: {
478
- ":focus": {
479
- outline: `solid ${border.width.medium} ${semanticColor.focus.outer}`
480
- }
481
- },
482
- focusedLight: {
483
- outline: `solid ${border.width.medium} ${semanticColor.border.inverse}`
484
- },
485
- disabled: {
486
- color: semanticColor.action.secondary.disabled.foreground,
487
- cursor: "not-allowed",
488
- ":focus": {
489
- outline: "none"
490
- },
491
- ":focus-visible": {
492
- outline: `solid ${border.width.medium} ${semanticColor.focus.outer}`
493
- }
494
- }
495
- });
14
+ const StyledA=addStyle("a");const StyledButton=addStyle("button");const StyledLink=addStyle(Link);const Clickable=React.forwardRef(function Clickable(props,ref){const getCorrectTag=(clickableState,inRouterContext,commonProps)=>{const activeHref=props.href&&!props.disabled;const useClient=inRouterContext&&!props.skipClientNav&&isClientSideUrl(props.href||"");if(activeHref&&useClient&&props.href){return jsx(StyledLink,{...commonProps,to:props.href,role:props.role,target:props.target||undefined,"aria-disabled":props.disabled?"true":"false",ref:ref,children:props.children(clickableState)})}else if(activeHref&&!useClient){return jsx(StyledA,{...commonProps,href:props.href,role:props.role,target:props.target||undefined,"aria-disabled":props.disabled?"true":"false",ref:ref,children:props.children(clickableState)})}else {return jsx(StyledButton,{...commonProps,type:"button","aria-disabled":props.disabled,ref:ref,children:props.children(clickableState)})}};const inRouterContext=useInRouterContext();const{href,onClick,skipClientNav,beforeNav=undefined,safeWithNav=undefined,style,target=undefined,testId,onFocus,onKeyDown,onKeyUp,onMouseDown,onMouseUp,hideDefaultFocusRing,light,disabled,tabIndex,...restProps}=props;const ClickableBehavior=getClickableBehavior(href,skipClientNav,inRouterContext);const getStyle=state=>[styles.reset,styles.link,!hideDefaultFocusRing&&state.focused&&(light?styles.focusedLight:styles.focused),disabled&&styles.disabled,style];if(beforeNav){return jsx(ClickableBehavior,{href:href,onClick:onClick,beforeNav:beforeNav,safeWithNav:safeWithNav,onFocus:onFocus,onKeyDown:onKeyDown,onKeyUp:onKeyUp,onMouseDown:onMouseDown,onMouseUp:onMouseUp,disabled:disabled,tabIndex:tabIndex,children:(state,childrenProps)=>getCorrectTag(state,inRouterContext,{...restProps,"data-testid":testId,style:getStyle(state),...childrenProps})})}else {return jsx(ClickableBehavior,{href:href,onClick:onClick,safeWithNav:safeWithNav,onFocus:onFocus,onKeyDown:onKeyDown,onKeyUp:onKeyUp,onMouseDown:onMouseDown,onMouseUp:onMouseUp,target:target,disabled:disabled,tabIndex:tabIndex,children:(state,childrenProps)=>getCorrectTag(state,inRouterContext,{...restProps,"data-testid":testId,style:getStyle(state),...childrenProps})})}});Clickable.defaultProps={light:false,disabled:false};const styles=StyleSheet.create({reset:{border:"none",margin:0,padding:0,width:"auto",overflow:"visible",background:"transparent",textDecoration:"none",color:"inherit",font:"inherit",boxSizing:"border-box",touchAction:"manipulation",userSelect:"none",outline:"none",lineHeight:"normal",WebkitFontSmoothing:"inherit",MozOsxFontSmoothing:"inherit"},link:{cursor:"pointer"},focused:{":focus":{outline:`solid ${border.width.medium} ${semanticColor.focus.outer}`}},focusedLight:{outline:`solid ${border.width.medium} ${semanticColor.border.inverse}`},disabled:{color:semanticColor.action.secondary.disabled.foreground,cursor:"not-allowed",":focus":{outline:"none"},":focus-visible":{outline:`solid ${border.width.medium} ${semanticColor.focus.outer}`}}});
496
15
 
497
16
  export { ClickableBehavior, Clickable as default, getClickableBehavior, isClientSideUrl };
package/dist/index.js CHANGED
@@ -2,16 +2,13 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var _objectWithoutPropertiesLoose = require('@babel/runtime/helpers/objectWithoutPropertiesLoose');
6
- var _extends = require('@babel/runtime/helpers/extends');
5
+ var jsxRuntime = require('react/jsx-runtime');
7
6
  var React = require('react');
8
7
  var aphrodite = require('aphrodite');
9
8
  var reactRouterDomV5Compat = require('react-router-dom-v5-compat');
10
9
  var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
11
10
  var wonderBlocksTokens = require('@khanacademy/wonder-blocks-tokens');
12
11
 
13
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
-
15
12
  function _interopNamespace(e) {
16
13
  if (e && e.__esModule) return e;
17
14
  var n = Object.create(null);
@@ -30,497 +27,15 @@ function _interopNamespace(e) {
30
27
  return Object.freeze(n);
31
28
  }
32
29
 
33
- var _objectWithoutPropertiesLoose__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutPropertiesLoose);
34
- var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
35
30
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
36
31
 
37
- const getAppropriateTriggersForRole = role => {
38
- switch (role) {
39
- case "link":
40
- return {
41
- triggerOnEnter: true,
42
- triggerOnSpace: false
43
- };
44
- case "checkbox":
45
- case "radio":
46
- case "listbox":
47
- return {
48
- triggerOnEnter: false,
49
- triggerOnSpace: true
50
- };
51
- case "button":
52
- case "menuitem":
53
- case "menu":
54
- case "option":
55
- default:
56
- return {
57
- triggerOnEnter: true,
58
- triggerOnSpace: true
59
- };
60
- }
61
- };
62
- const disabledHandlers = {
63
- onClick: () => void 0,
64
- onMouseEnter: () => void 0,
65
- onMouseLeave: () => void 0,
66
- onMouseDown: () => void 0,
67
- onMouseUp: () => void 0,
68
- onTouchStart: () => void 0,
69
- onTouchEnd: () => void 0,
70
- onTouchCancel: () => void 0,
71
- onKeyDown: () => void 0,
72
- onKeyUp: () => void 0
73
- };
74
- const startState = {
75
- hovered: false,
76
- focused: false,
77
- pressed: false,
78
- waiting: false
79
- };
80
- class ClickableBehavior extends React__namespace.Component {
81
- static getDerivedStateFromProps(props, state) {
82
- if (props.disabled) {
83
- return _extends__default["default"]({}, startState, {
84
- focused: state.focused
85
- });
86
- } else {
87
- return null;
88
- }
89
- }
90
- constructor(props) {
91
- super(props);
92
- this.waitingForClick = void 0;
93
- this.enterClick = void 0;
94
- this.handleClick = e => {
95
- const {
96
- onClick = undefined,
97
- beforeNav = undefined,
98
- safeWithNav = undefined
99
- } = this.props;
100
- if (this.enterClick) {
101
- return;
102
- }
103
- if (onClick || beforeNav || safeWithNav) {
104
- this.waitingForClick = false;
105
- }
106
- this.runCallbackAndMaybeNavigate(e);
107
- };
108
- this.handleMouseEnter = e => {
109
- if (!this.waitingForClick) {
110
- this.setState({
111
- hovered: true
112
- });
113
- }
114
- };
115
- this.handleMouseLeave = () => {
116
- if (!this.waitingForClick) {
117
- this.setState({
118
- hovered: false,
119
- pressed: false,
120
- focused: false
121
- });
122
- }
123
- };
124
- this.handleMouseDown = e => {
125
- if (this.props.onMouseDown) {
126
- this.props.onMouseDown(e);
127
- }
128
- this.setState({
129
- pressed: true
130
- });
131
- };
132
- this.handleMouseUp = e => {
133
- if (this.props.onMouseUp) {
134
- this.props.onMouseUp(e);
135
- }
136
- this.setState({
137
- pressed: false,
138
- focused: false
139
- });
140
- };
141
- this.handleTouchStart = () => {
142
- this.setState({
143
- pressed: true
144
- });
145
- };
146
- this.handleTouchEnd = () => {
147
- this.setState({
148
- pressed: false
149
- });
150
- this.waitingForClick = true;
151
- };
152
- this.handleTouchCancel = () => {
153
- this.setState({
154
- pressed: false
155
- });
156
- this.waitingForClick = true;
157
- };
158
- this.handleKeyDown = e => {
159
- const {
160
- onKeyDown,
161
- role
162
- } = this.props;
163
- if (onKeyDown) {
164
- onKeyDown(e);
165
- }
166
- const keyName = e.key;
167
- const {
168
- triggerOnEnter,
169
- triggerOnSpace
170
- } = getAppropriateTriggersForRole(role);
171
- if (triggerOnEnter && keyName === wonderBlocksCore.keys.enter || triggerOnSpace && keyName === wonderBlocksCore.keys.space) {
172
- e.preventDefault();
173
- this.setState({
174
- pressed: true
175
- });
176
- } else if (!triggerOnEnter && keyName === wonderBlocksCore.keys.enter) {
177
- this.enterClick = true;
178
- }
179
- };
180
- this.handleKeyUp = e => {
181
- const {
182
- onKeyUp,
183
- role
184
- } = this.props;
185
- if (onKeyUp) {
186
- onKeyUp(e);
187
- }
188
- const keyName = e.key;
189
- const {
190
- triggerOnEnter,
191
- triggerOnSpace
192
- } = getAppropriateTriggersForRole(role);
193
- if (triggerOnEnter && keyName === wonderBlocksCore.keys.enter || triggerOnSpace && keyName === wonderBlocksCore.keys.space) {
194
- this.setState({
195
- pressed: false,
196
- focused: true
197
- });
198
- this.runCallbackAndMaybeNavigate(e);
199
- } else if (!triggerOnEnter && keyName === wonderBlocksCore.keys.enter) {
200
- this.enterClick = false;
201
- }
202
- };
203
- this.handleFocus = e => {
204
- const {
205
- onFocus
206
- } = this.props;
207
- this.setState({
208
- focused: true
209
- }, () => {
210
- if (onFocus) {
211
- onFocus(e);
212
- }
213
- });
214
- };
215
- this.handleBlur = e => {
216
- this.setState({
217
- focused: false,
218
- pressed: false
219
- });
220
- };
221
- this.state = startState;
222
- this.waitingForClick = false;
223
- this.enterClick = false;
224
- }
225
- navigateOrReset(shouldNavigate) {
226
- if (shouldNavigate) {
227
- const {
228
- navigate,
229
- href,
230
- skipClientNav,
231
- target = undefined
232
- } = this.props;
233
- if (href) {
234
- if (target === "_blank") {
235
- window.open(href, "_blank");
236
- this.setState({
237
- waiting: false
238
- });
239
- } else if (navigate && !skipClientNav) {
240
- navigate(href);
241
- this.setState({
242
- waiting: false
243
- });
244
- } else {
245
- window.location.assign(href);
246
- }
247
- }
248
- } else {
249
- this.setState({
250
- waiting: false
251
- });
252
- }
253
- }
254
- handleSafeWithNav(safeWithNav, shouldNavigate) {
255
- const {
256
- skipClientNav,
257
- navigate
258
- } = this.props;
259
- if (navigate && !skipClientNav || this.props.target === "_blank") {
260
- safeWithNav();
261
- this.navigateOrReset(shouldNavigate);
262
- return Promise.resolve();
263
- } else {
264
- if (!this.state.waiting) {
265
- this.setState({
266
- waiting: true
267
- });
268
- }
269
- return safeWithNav().then(() => {
270
- if (!this.state.waiting) {
271
- this.setState({
272
- waiting: true
273
- });
274
- }
275
- return;
276
- }).catch(error => {}).finally(() => {
277
- this.navigateOrReset(shouldNavigate);
278
- });
279
- }
280
- }
281
- runCallbackAndMaybeNavigate(e) {
282
- const {
283
- onClick = undefined,
284
- beforeNav = undefined,
285
- safeWithNav = undefined,
286
- href,
287
- type
288
- } = this.props;
289
- let shouldNavigate = true;
290
- let canSubmit = true;
291
- if (onClick) {
292
- onClick(e);
293
- }
294
- if (e.defaultPrevented) {
295
- shouldNavigate = false;
296
- canSubmit = false;
297
- }
298
- e.preventDefault();
299
- if (!href && type === "submit" && canSubmit) {
300
- let target = e.currentTarget;
301
- while (target) {
302
- if (target instanceof window.HTMLFormElement) {
303
- const event = new window.Event("submit", {
304
- bubbles: true,
305
- cancelable: true
306
- });
307
- target.dispatchEvent(event);
308
- break;
309
- }
310
- target = target.parentElement;
311
- }
312
- }
313
- if (beforeNav) {
314
- this.setState({
315
- waiting: true
316
- });
317
- beforeNav().then(() => {
318
- if (safeWithNav) {
319
- return this.handleSafeWithNav(safeWithNav, shouldNavigate);
320
- } else {
321
- return this.navigateOrReset(shouldNavigate);
322
- }
323
- }).catch(() => {});
324
- } else if (safeWithNav) {
325
- return this.handleSafeWithNav(safeWithNav, shouldNavigate);
326
- } else {
327
- this.navigateOrReset(shouldNavigate);
328
- }
329
- }
330
- render() {
331
- const rel = this.props.rel || (this.props.target === "_blank" ? "noopener noreferrer" : undefined);
332
- const childrenProps = this.props.disabled ? _extends__default["default"]({}, disabledHandlers, {
333
- onFocus: this.handleFocus,
334
- onBlur: this.handleBlur,
335
- tabIndex: this.props.tabIndex,
336
- rel
337
- }) : {
338
- onClick: this.handleClick,
339
- onMouseEnter: this.handleMouseEnter,
340
- onMouseLeave: this.handleMouseLeave,
341
- onMouseDown: this.handleMouseDown,
342
- onMouseUp: this.handleMouseUp,
343
- onTouchStart: this.handleTouchStart,
344
- onTouchEnd: this.handleTouchEnd,
345
- onTouchCancel: this.handleTouchCancel,
346
- onKeyDown: this.handleKeyDown,
347
- onKeyUp: this.handleKeyUp,
348
- onFocus: this.handleFocus,
349
- onBlur: this.handleBlur,
350
- tabIndex: this.props.tabIndex,
351
- rel
352
- };
353
- const {
354
- children
355
- } = this.props;
356
- return children && children(this.state, childrenProps);
357
- }
358
- }
359
- ClickableBehavior.defaultProps = {
360
- disabled: false
361
- };
32
+ const getAppropriateTriggersForRole=role=>{switch(role){case"link":return {triggerOnEnter:true,triggerOnSpace:false};case"checkbox":case"radio":case"listbox":return {triggerOnEnter:false,triggerOnSpace:true};case"button":case"menuitem":case"menu":case"option":default:return {triggerOnEnter:true,triggerOnSpace:true}}};const disabledHandlers={onClick:()=>void 0,onMouseEnter:()=>void 0,onMouseLeave:()=>void 0,onMouseDown:()=>void 0,onMouseUp:()=>void 0,onTouchStart:()=>void 0,onTouchEnd:()=>void 0,onTouchCancel:()=>void 0,onKeyDown:()=>void 0,onKeyUp:()=>void 0};const startState={hovered:false,focused:false,pressed:false,waiting:false};class ClickableBehavior extends React__namespace.Component{static getDerivedStateFromProps(props,state){if(props.disabled){return {...startState,focused:state.focused}}else {return null}}navigateOrReset(shouldNavigate){if(shouldNavigate){const{navigate,href,skipClientNav,target=undefined}=this.props;if(href){if(target==="_blank"){window.open(href,"_blank");this.setState({waiting:false});}else if(navigate&&!skipClientNav){navigate(href,{viewTransition:this.props.viewTransition});this.setState({waiting:false});}else {window.location.assign(href);}}}else {this.setState({waiting:false});}}handleSafeWithNav(safeWithNav,shouldNavigate){const{skipClientNav,navigate}=this.props;if(navigate&&!skipClientNav||this.props.target==="_blank"){safeWithNav();this.navigateOrReset(shouldNavigate);return Promise.resolve()}else {if(!this.state.waiting){this.setState({waiting:true});}return safeWithNav().then(()=>{if(!this.state.waiting){this.setState({waiting:true});}return}).catch(error=>{}).finally(()=>{this.navigateOrReset(shouldNavigate);})}}runCallbackAndMaybeNavigate(e){const{onClick=undefined,beforeNav=undefined,safeWithNav=undefined,href,type}=this.props;let shouldNavigate=true;let canSubmit=true;if(onClick){onClick(e);}if(e.defaultPrevented){shouldNavigate=false;canSubmit=false;}e.preventDefault();if(!href&&type==="submit"&&canSubmit){let target=e.currentTarget;while(target){if(target instanceof window.HTMLFormElement){const event=new window.Event("submit",{bubbles:true,cancelable:true});target.dispatchEvent(event);break}target=target.parentElement;}}if(beforeNav){this.setState({waiting:true});beforeNav().then(()=>{if(safeWithNav){return this.handleSafeWithNav(safeWithNav,shouldNavigate)}else {return this.navigateOrReset(shouldNavigate)}}).catch(()=>{});}else if(safeWithNav){return this.handleSafeWithNav(safeWithNav,shouldNavigate)}else {this.navigateOrReset(shouldNavigate);}}render(){const rel=this.props.rel||(this.props.target==="_blank"?"noopener noreferrer":undefined);const childrenProps=this.props.disabled?{...disabledHandlers,onFocus:this.handleFocus,onBlur:this.handleBlur,tabIndex:this.props.tabIndex,rel}:{onClick:this.handleClick,onMouseEnter:this.handleMouseEnter,onMouseLeave:this.handleMouseLeave,onMouseDown:this.handleMouseDown,onMouseUp:this.handleMouseUp,onTouchStart:this.handleTouchStart,onTouchEnd:this.handleTouchEnd,onTouchCancel:this.handleTouchCancel,onKeyDown:this.handleKeyDown,onKeyUp:this.handleKeyUp,onFocus:this.handleFocus,onBlur:this.handleBlur,tabIndex:this.props.tabIndex,rel};const{children}=this.props;return children&&children(this.state,childrenProps)}constructor(props){super(props),this.handleClick=e=>{const{onClick=undefined,beforeNav=undefined,safeWithNav=undefined}=this.props;if(this.enterClick){return}if(onClick||beforeNav||safeWithNav){this.waitingForClick=false;}this.runCallbackAndMaybeNavigate(e);},this.handleMouseEnter=e=>{if(!this.waitingForClick){this.setState({hovered:true});}},this.handleMouseLeave=()=>{if(!this.waitingForClick){this.setState({hovered:false,pressed:false,focused:false});}},this.handleMouseDown=e=>{if(this.props.onMouseDown){this.props.onMouseDown(e);}this.setState({pressed:true});},this.handleMouseUp=e=>{if(this.props.onMouseUp){this.props.onMouseUp(e);}this.setState({pressed:false,focused:false});},this.handleTouchStart=()=>{this.setState({pressed:true});},this.handleTouchEnd=()=>{this.setState({pressed:false});this.waitingForClick=true;},this.handleTouchCancel=()=>{this.setState({pressed:false});this.waitingForClick=true;},this.handleKeyDown=e=>{const{onKeyDown,role}=this.props;if(onKeyDown){onKeyDown(e);}const keyName=e.key;const{triggerOnEnter,triggerOnSpace}=getAppropriateTriggersForRole(role);if(triggerOnEnter&&keyName===wonderBlocksCore.keys.enter||triggerOnSpace&&keyName===wonderBlocksCore.keys.space){e.preventDefault();this.setState({pressed:true});}else if(!triggerOnEnter&&keyName===wonderBlocksCore.keys.enter){this.enterClick=true;}},this.handleKeyUp=e=>{const{onKeyUp,role}=this.props;if(onKeyUp){onKeyUp(e);}const keyName=e.key;const{triggerOnEnter,triggerOnSpace}=getAppropriateTriggersForRole(role);if(triggerOnEnter&&keyName===wonderBlocksCore.keys.enter||triggerOnSpace&&keyName===wonderBlocksCore.keys.space){this.setState({pressed:false,focused:true});this.runCallbackAndMaybeNavigate(e);}else if(!triggerOnEnter&&keyName===wonderBlocksCore.keys.enter){this.enterClick=false;}},this.handleFocus=e=>{const{onFocus}=this.props;this.setState({focused:true},()=>{if(onFocus){onFocus(e);}});},this.handleBlur=e=>{this.setState({focused:false,pressed:false});};this.state=startState;this.waitingForClick=false;this.enterClick=false;}}ClickableBehavior.defaultProps={disabled:false};
362
33
 
363
- const isClientSideUrl = href => {
364
- if (typeof href !== "string") {
365
- return false;
366
- }
367
- return !/^(https?:)?\/\//i.test(href) && !/^([^#]*#[\w-]*|[\w\-.]+:)/.test(href);
368
- };
34
+ const isClientSideUrl=href=>{if(typeof href!=="string"){return false}return !/^(https?:)?\/\//i.test(href)&&!/^([^#]*#[\w-]*|[\w\-.]+:)/.test(href)};
369
35
 
370
- function withRouter(Component) {
371
- function WithRouterWrapper(props) {
372
- const navigate = reactRouterDomV5Compat.useNavigate();
373
- return React__namespace.createElement(Component, _extends__default["default"]({}, props, {
374
- navigate: navigate
375
- }));
376
- }
377
- WithRouterWrapper.displayName = "withRouter(ClickableBehavior)";
378
- return WithRouterWrapper;
379
- }
380
- const ClickableBehaviorWithRouter = withRouter(ClickableBehavior);
381
- function getClickableBehavior(href, skipClientNav, inRouterContext) {
382
- if (inRouterContext && skipClientNav !== true && href && isClientSideUrl(href)) {
383
- return ClickableBehaviorWithRouter;
384
- }
385
- return ClickableBehavior;
386
- }
36
+ function withRouter(Component){function WithRouterWrapper(props){const navigate=reactRouterDomV5Compat.useNavigate();return jsxRuntime.jsx(Component,{...props,navigate:navigate})}WithRouterWrapper.displayName="withRouter(ClickableBehavior)";return WithRouterWrapper}const ClickableBehaviorWithRouter=withRouter(ClickableBehavior);function getClickableBehavior(href,skipClientNav,inRouterContext){if(inRouterContext&&skipClientNav!==true&&href&&isClientSideUrl(href)){return ClickableBehaviorWithRouter}return ClickableBehavior}
387
37
 
388
- const _excluded = ["href", "onClick", "skipClientNav", "beforeNav", "safeWithNav", "style", "target", "testId", "onFocus", "onKeyDown", "onKeyUp", "onMouseDown", "onMouseUp", "hideDefaultFocusRing", "light", "disabled", "tabIndex"];
389
- const StyledA = wonderBlocksCore.addStyle("a");
390
- const StyledButton = wonderBlocksCore.addStyle("button");
391
- const StyledLink = wonderBlocksCore.addStyle(reactRouterDomV5Compat.Link);
392
- const Clickable = React__namespace.forwardRef(function Clickable(props, ref) {
393
- const getCorrectTag = (clickableState, inRouterContext, commonProps) => {
394
- const activeHref = props.href && !props.disabled;
395
- const useClient = inRouterContext && !props.skipClientNav && isClientSideUrl(props.href || "");
396
- if (activeHref && useClient && props.href) {
397
- return React__namespace.createElement(StyledLink, _extends__default["default"]({}, commonProps, {
398
- to: props.href,
399
- role: props.role,
400
- target: props.target || undefined,
401
- "aria-disabled": props.disabled ? "true" : "false",
402
- ref: ref
403
- }), props.children(clickableState));
404
- } else if (activeHref && !useClient) {
405
- return React__namespace.createElement(StyledA, _extends__default["default"]({}, commonProps, {
406
- href: props.href,
407
- role: props.role,
408
- target: props.target || undefined,
409
- "aria-disabled": props.disabled ? "true" : "false",
410
- ref: ref
411
- }), props.children(clickableState));
412
- } else {
413
- return React__namespace.createElement(StyledButton, _extends__default["default"]({}, commonProps, {
414
- type: "button",
415
- "aria-disabled": props.disabled,
416
- ref: ref
417
- }), props.children(clickableState));
418
- }
419
- };
420
- const inRouterContext = reactRouterDomV5Compat.useInRouterContext();
421
- const {
422
- href,
423
- onClick,
424
- skipClientNav,
425
- beforeNav = undefined,
426
- safeWithNav = undefined,
427
- style,
428
- target = undefined,
429
- testId,
430
- onFocus,
431
- onKeyDown,
432
- onKeyUp,
433
- onMouseDown,
434
- onMouseUp,
435
- hideDefaultFocusRing,
436
- light,
437
- disabled,
438
- tabIndex
439
- } = props,
440
- restProps = _objectWithoutPropertiesLoose__default["default"](props, _excluded);
441
- const ClickableBehavior = getClickableBehavior(href, skipClientNav, inRouterContext);
442
- const getStyle = state => [styles.reset, styles.link, !hideDefaultFocusRing && state.focused && (light ? styles.focusedLight : styles.focused), disabled && styles.disabled, style];
443
- if (beforeNav) {
444
- return React__namespace.createElement(ClickableBehavior, {
445
- href: href,
446
- onClick: onClick,
447
- beforeNav: beforeNav,
448
- safeWithNav: safeWithNav,
449
- onFocus: onFocus,
450
- onKeyDown: onKeyDown,
451
- onKeyUp: onKeyUp,
452
- onMouseDown: onMouseDown,
453
- onMouseUp: onMouseUp,
454
- disabled: disabled,
455
- tabIndex: tabIndex
456
- }, (state, childrenProps) => getCorrectTag(state, inRouterContext, _extends__default["default"]({}, restProps, {
457
- "data-testid": testId,
458
- style: getStyle(state)
459
- }, childrenProps)));
460
- } else {
461
- return React__namespace.createElement(ClickableBehavior, {
462
- href: href,
463
- onClick: onClick,
464
- safeWithNav: safeWithNav,
465
- onFocus: onFocus,
466
- onKeyDown: onKeyDown,
467
- onKeyUp: onKeyUp,
468
- onMouseDown: onMouseDown,
469
- onMouseUp: onMouseUp,
470
- target: target,
471
- disabled: disabled,
472
- tabIndex: tabIndex
473
- }, (state, childrenProps) => getCorrectTag(state, inRouterContext, _extends__default["default"]({}, restProps, {
474
- "data-testid": testId,
475
- style: getStyle(state)
476
- }, childrenProps)));
477
- }
478
- });
479
- Clickable.defaultProps = {
480
- light: false,
481
- disabled: false
482
- };
483
- const styles = aphrodite.StyleSheet.create({
484
- reset: {
485
- border: "none",
486
- margin: 0,
487
- padding: 0,
488
- width: "auto",
489
- overflow: "visible",
490
- background: "transparent",
491
- textDecoration: "none",
492
- color: "inherit",
493
- font: "inherit",
494
- boxSizing: "border-box",
495
- touchAction: "manipulation",
496
- userSelect: "none",
497
- outline: "none",
498
- lineHeight: "normal",
499
- WebkitFontSmoothing: "inherit",
500
- MozOsxFontSmoothing: "inherit"
501
- },
502
- link: {
503
- cursor: "pointer"
504
- },
505
- focused: {
506
- ":focus": {
507
- outline: `solid ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.focus.outer}`
508
- }
509
- },
510
- focusedLight: {
511
- outline: `solid ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.border.inverse}`
512
- },
513
- disabled: {
514
- color: wonderBlocksTokens.semanticColor.action.secondary.disabled.foreground,
515
- cursor: "not-allowed",
516
- ":focus": {
517
- outline: "none"
518
- },
519
- ":focus-visible": {
520
- outline: `solid ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.focus.outer}`
521
- }
522
- }
523
- });
38
+ const StyledA=wonderBlocksCore.addStyle("a");const StyledButton=wonderBlocksCore.addStyle("button");const StyledLink=wonderBlocksCore.addStyle(reactRouterDomV5Compat.Link);const Clickable=React__namespace.forwardRef(function Clickable(props,ref){const getCorrectTag=(clickableState,inRouterContext,commonProps)=>{const activeHref=props.href&&!props.disabled;const useClient=inRouterContext&&!props.skipClientNav&&isClientSideUrl(props.href||"");if(activeHref&&useClient&&props.href){return jsxRuntime.jsx(StyledLink,{...commonProps,to:props.href,role:props.role,target:props.target||undefined,"aria-disabled":props.disabled?"true":"false",ref:ref,children:props.children(clickableState)})}else if(activeHref&&!useClient){return jsxRuntime.jsx(StyledA,{...commonProps,href:props.href,role:props.role,target:props.target||undefined,"aria-disabled":props.disabled?"true":"false",ref:ref,children:props.children(clickableState)})}else {return jsxRuntime.jsx(StyledButton,{...commonProps,type:"button","aria-disabled":props.disabled,ref:ref,children:props.children(clickableState)})}};const inRouterContext=reactRouterDomV5Compat.useInRouterContext();const{href,onClick,skipClientNav,beforeNav=undefined,safeWithNav=undefined,style,target=undefined,testId,onFocus,onKeyDown,onKeyUp,onMouseDown,onMouseUp,hideDefaultFocusRing,light,disabled,tabIndex,...restProps}=props;const ClickableBehavior=getClickableBehavior(href,skipClientNav,inRouterContext);const getStyle=state=>[styles.reset,styles.link,!hideDefaultFocusRing&&state.focused&&(light?styles.focusedLight:styles.focused),disabled&&styles.disabled,style];if(beforeNav){return jsxRuntime.jsx(ClickableBehavior,{href:href,onClick:onClick,beforeNav:beforeNav,safeWithNav:safeWithNav,onFocus:onFocus,onKeyDown:onKeyDown,onKeyUp:onKeyUp,onMouseDown:onMouseDown,onMouseUp:onMouseUp,disabled:disabled,tabIndex:tabIndex,children:(state,childrenProps)=>getCorrectTag(state,inRouterContext,{...restProps,"data-testid":testId,style:getStyle(state),...childrenProps})})}else {return jsxRuntime.jsx(ClickableBehavior,{href:href,onClick:onClick,safeWithNav:safeWithNav,onFocus:onFocus,onKeyDown:onKeyDown,onKeyUp:onKeyUp,onMouseDown:onMouseDown,onMouseUp:onMouseUp,target:target,disabled:disabled,tabIndex:tabIndex,children:(state,childrenProps)=>getCorrectTag(state,inRouterContext,{...restProps,"data-testid":testId,style:getStyle(state),...childrenProps})})}});Clickable.defaultProps={light:false,disabled:false};const styles=aphrodite.StyleSheet.create({reset:{border:"none",margin:0,padding:0,width:"auto",overflow:"visible",background:"transparent",textDecoration:"none",color:"inherit",font:"inherit",boxSizing:"border-box",touchAction:"manipulation",userSelect:"none",outline:"none",lineHeight:"normal",WebkitFontSmoothing:"inherit",MozOsxFontSmoothing:"inherit"},link:{cursor:"pointer"},focused:{":focus":{outline:`solid ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.focus.outer}`}},focusedLight:{outline:`solid ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.border.inverse}`},disabled:{color:wonderBlocksTokens.semanticColor.action.secondary.disabled.foreground,cursor:"not-allowed",":focus":{outline:"none"},":focus-visible":{outline:`solid ${wonderBlocksTokens.border.width.medium} ${wonderBlocksTokens.semanticColor.focus.outer}`}}});
524
39
 
525
40
  exports.ClickableBehavior = ClickableBehavior;
526
41
  exports["default"] = Clickable;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-clickable",
3
- "version": "7.0.3",
3
+ "version": "7.1.0",
4
4
  "design": "v1",
5
5
  "description": "Clickable component for Wonder-Blocks.",
6
6
  "main": "dist/index.js",
@@ -12,9 +12,8 @@
12
12
  "access": "public"
13
13
  },
14
14
  "dependencies": {
15
- "@babel/runtime": "^7.24.5",
16
- "@khanacademy/wonder-blocks-core": "12.2.1",
17
- "@khanacademy/wonder-blocks-tokens": "9.0.0"
15
+ "@khanacademy/wonder-blocks-core": "12.3.0",
16
+ "@khanacademy/wonder-blocks-tokens": "10.0.0"
18
17
  },
19
18
  "peerDependencies": {
20
19
  "aphrodite": "^1.2.5",
@@ -25,7 +24,7 @@
25
24
  "react-router-dom-v5-compat": "^6.30.0"
26
25
  },
27
26
  "devDependencies": {
28
- "@khanacademy/wb-dev-build-settings": "2.1.1"
27
+ "@khanacademy/wb-dev-build-settings": "3.0.0"
29
28
  },
30
29
  "scripts": {
31
30
  "test": "echo \"Error: no test specified\" && exit 1"