@khanacademy/wonder-blocks-button 9.0.2 → 10.0.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 +39 -0
- package/dist/components/button-core.d.ts +4 -4
- package/dist/components/button-unstyled.d.ts +11 -0
- package/dist/components/button.d.ts +24 -149
- package/dist/es/index.js +8 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -6
- package/dist/themes/default.d.ts +231 -176
- package/dist/themes/khanmigo.d.ts +231 -160
- package/dist/themes/themed-button.d.ts +231 -160
- package/dist/util/button.types.d.ts +154 -0
- package/package.json +8 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-button
|
|
2
2
|
|
|
3
|
+
## 10.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [c7d95bf]
|
|
8
|
+
- Updated dependencies [668093b]
|
|
9
|
+
- @khanacademy/wonder-blocks-theming@3.4.0
|
|
10
|
+
- @khanacademy/wonder-blocks-tokens@10.2.0
|
|
11
|
+
- @khanacademy/wonder-blocks-clickable@7.1.2
|
|
12
|
+
- @khanacademy/wonder-blocks-core@12.3.0
|
|
13
|
+
- @khanacademy/wonder-blocks-icon@5.1.4
|
|
14
|
+
- @khanacademy/wonder-blocks-progress-spinner@3.1.13
|
|
15
|
+
- @khanacademy/wonder-blocks-styles@0.2.9
|
|
16
|
+
- @khanacademy/wonder-blocks-typography@3.2.3
|
|
17
|
+
|
|
18
|
+
## 10.0.0
|
|
19
|
+
|
|
20
|
+
### Major Changes
|
|
21
|
+
|
|
22
|
+
- a55481a: Renames `color` prop to `actionType` and changes `default` to `progressive`.
|
|
23
|
+
|
|
24
|
+
### Minor Changes
|
|
25
|
+
|
|
26
|
+
- 812c167: Add `neutral` value to the `actionType` prop.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- a1be4c5: Updates Button default theme to simplify its use and have more consistency with the `IconButton` styles. Also makes some changes to get this button closer to the design specs.
|
|
31
|
+
- 176a3bd: Splits ButtonCore to keep styles there and creates a new ButtonUnstyled to handle the semantics of the Button HTML elements"
|
|
32
|
+
- Updated dependencies [a1be4c5]
|
|
33
|
+
- Updated dependencies [d00a6f1]
|
|
34
|
+
- Updated dependencies [abf5496]
|
|
35
|
+
- Updated dependencies [812c167]
|
|
36
|
+
- @khanacademy/wonder-blocks-tokens@10.1.0
|
|
37
|
+
- @khanacademy/wonder-blocks-clickable@7.1.1
|
|
38
|
+
- @khanacademy/wonder-blocks-progress-spinner@3.1.12
|
|
39
|
+
- @khanacademy/wonder-blocks-styles@0.2.8
|
|
40
|
+
- @khanacademy/wonder-blocks-typography@3.2.2
|
|
41
|
+
|
|
3
42
|
## 9.0.2
|
|
4
43
|
|
|
5
44
|
### Patch Changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Link } from "react-router-dom-v5-compat";
|
|
3
2
|
import type { ChildrenProps, ClickableState } from "@khanacademy/wonder-blocks-clickable";
|
|
4
|
-
import
|
|
3
|
+
import { Link } from "react-router-dom-v5-compat";
|
|
4
|
+
import type { ButtonActionType, ButtonKind, ButtonSize, ButtonProps } from "../util/button.types";
|
|
5
5
|
import { ButtonThemeContract } from "../themes/themed-button";
|
|
6
|
-
type Props =
|
|
6
|
+
type Props = ButtonProps & ChildrenProps & ClickableState;
|
|
7
7
|
declare const ButtonCore: React.ForwardRefExoticComponent<Props & React.RefAttributes<typeof Link | HTMLButtonElement | HTMLAnchorElement>>;
|
|
8
8
|
export default ButtonCore;
|
|
9
|
-
export declare const _generateStyles: (
|
|
9
|
+
export declare const _generateStyles: (actionType: ButtonActionType | undefined, kind: ButtonKind, size: ButtonSize, theme: ButtonThemeContract, themeName: string) => any;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Link } from "react-router-dom-v5-compat";
|
|
3
|
+
import { ButtonProps } from "../util/button.types";
|
|
4
|
+
type Props = Omit<ButtonProps, "children"> & {
|
|
5
|
+
/**
|
|
6
|
+
* The button content.
|
|
7
|
+
*/
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
};
|
|
10
|
+
declare const ButtonUnstyled: React.ForwardRefExoticComponent<Props & React.RefAttributes<typeof Link | HTMLButtonElement | HTMLAnchorElement>>;
|
|
11
|
+
export { ButtonUnstyled };
|
|
@@ -1,168 +1,43 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import type { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
|
-
import type { PhosphorIconAsset } from "@khanacademy/wonder-blocks-icon";
|
|
4
|
-
import { Link } from "react-router-dom-v5-compat";
|
|
5
|
-
export type SharedProps =
|
|
6
2
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
3
|
+
* The `Button` component is a reusable button that can be used in various
|
|
4
|
+
* contexts. It can be used as a link or a button, and it supports various
|
|
5
|
+
* props to customize its behavior and appearance.
|
|
6
|
+
*
|
|
7
|
+
* ### Usage
|
|
8
|
+
*
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import Button from "@khanacademy/wonder-blocks-button";
|
|
11
|
+
*
|
|
12
|
+
* <Button
|
|
13
|
+
* onClick={(e) => console.log("Hello, world!")}
|
|
14
|
+
* >
|
|
15
|
+
* Hello, world!
|
|
16
|
+
* </Button>
|
|
17
|
+
* ```
|
|
10
18
|
*/
|
|
11
|
-
Partial<Omit<AriaProps, "aria-disabled">> & {
|
|
12
|
-
/**
|
|
13
|
-
* Text to appear on the button.
|
|
14
|
-
*/
|
|
19
|
+
declare const Button: React.ForwardRefExoticComponent<Partial<Omit<import("@khanacademy/wonder-blocks-core").AriaProps, "aria-disabled">> & {
|
|
15
20
|
children: string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* will appear at the start of the button (left for LTR, right for RTL).
|
|
19
|
-
*/
|
|
20
|
-
startIcon?: PhosphorIconAsset;
|
|
21
|
-
/**
|
|
22
|
-
* A Phosphor icon asset (imported as a static SVG file) that
|
|
23
|
-
* will appear at the end of the button (right for LTR, left for RTL).
|
|
24
|
-
*/
|
|
25
|
-
endIcon?: PhosphorIconAsset;
|
|
26
|
-
/**
|
|
27
|
-
* If true, replaces the contents with a spinner.
|
|
28
|
-
*
|
|
29
|
-
* Note: setting this prop to `true` will disable the button.
|
|
30
|
-
*/
|
|
21
|
+
startIcon?: import("@khanacademy/wonder-blocks-icon").PhosphorIconAsset;
|
|
22
|
+
endIcon?: import("@khanacademy/wonder-blocks-icon").PhosphorIconAsset;
|
|
31
23
|
spinner?: boolean;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
color?: "default" | "destructive";
|
|
36
|
-
/**
|
|
37
|
-
* The kind of the button, either primary, secondary, or tertiary.
|
|
38
|
-
*
|
|
39
|
-
* In default state:
|
|
40
|
-
*
|
|
41
|
-
* - Primary buttons have background colors
|
|
42
|
-
* - Secondary buttons have a border and no background color
|
|
43
|
-
* - Tertiary buttons have no background or border
|
|
44
|
-
*/
|
|
45
|
-
kind?: "primary" | "secondary" | "tertiary";
|
|
46
|
-
/**
|
|
47
|
-
* The size of the button. "medium" = height: 40; "small" = height: 32;
|
|
48
|
-
* "large" = height: 56;
|
|
49
|
-
*/
|
|
50
|
-
size?: "medium" | "small" | "large";
|
|
51
|
-
/**
|
|
52
|
-
* Whether the button is disabled.
|
|
53
|
-
*/
|
|
24
|
+
actionType?: import("../util/button.types").ButtonActionType;
|
|
25
|
+
kind?: import("../util/button.types").ButtonKind;
|
|
26
|
+
size?: import("../util/button.types").ButtonSize;
|
|
54
27
|
disabled?: boolean;
|
|
55
|
-
/**
|
|
56
|
-
* An optional id attribute.
|
|
57
|
-
*/
|
|
58
28
|
id?: string;
|
|
59
|
-
/**
|
|
60
|
-
* Test ID used for e2e testing.
|
|
61
|
-
*/
|
|
62
29
|
testId?: string;
|
|
63
|
-
/**
|
|
64
|
-
* Specifies the type of relationship between the current document and the
|
|
65
|
-
* linked document. Should only be used when `href` is specified. This
|
|
66
|
-
* defaults to "noopener noreferrer" when `target="_blank"`, but can be
|
|
67
|
-
* overridden by setting this prop to something else.
|
|
68
|
-
*/
|
|
69
30
|
rel?: string;
|
|
70
|
-
/**
|
|
71
|
-
* A target destination window for a link to open in. Should only be used
|
|
72
|
-
* when `href` is specified.
|
|
73
|
-
*
|
|
74
|
-
* TODO(WB-1262): only allow this prop when `href` is also set.t
|
|
75
|
-
*/
|
|
76
31
|
target?: "_blank";
|
|
77
|
-
/**
|
|
78
|
-
* Set the tabindex attribute on the rendered element.
|
|
79
|
-
*/
|
|
80
32
|
tabIndex?: number;
|
|
81
|
-
/**
|
|
82
|
-
* Whether to avoid using client-side navigation.
|
|
83
|
-
*
|
|
84
|
-
* If the URL passed to href is local to the client-side, e.g.
|
|
85
|
-
* /math/algebra/eval-exprs, then it tries to use react-router-dom's Link
|
|
86
|
-
* component which handles the client-side navigation. You can set
|
|
87
|
-
* `skipClientNav` to true avoid using client-side nav entirely.
|
|
88
|
-
*
|
|
89
|
-
* NOTE: All URLs containing a protocol are considered external, e.g.
|
|
90
|
-
* https://khanacademy.org/math/algebra/eval-exprs will trigger a full
|
|
91
|
-
* page reload.
|
|
92
|
-
*/
|
|
93
33
|
skipClientNav?: boolean;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
*/
|
|
97
|
-
labelStyle?: StyleType;
|
|
98
|
-
/**
|
|
99
|
-
* Optional custom styles.
|
|
100
|
-
*/
|
|
101
|
-
style?: StyleType;
|
|
102
|
-
/**
|
|
103
|
-
* URL to navigate to.
|
|
104
|
-
*/
|
|
34
|
+
labelStyle?: import("@khanacademy/wonder-blocks-core").StyleType;
|
|
35
|
+
style?: import("@khanacademy/wonder-blocks-core").StyleType;
|
|
105
36
|
href?: string;
|
|
106
|
-
/**
|
|
107
|
-
* Used for buttons within <form>s.
|
|
108
|
-
*/
|
|
109
37
|
type?: "submit";
|
|
110
|
-
/**
|
|
111
|
-
* Adds CSS classes to the Button.
|
|
112
|
-
*/
|
|
113
38
|
className?: string;
|
|
114
|
-
/**
|
|
115
|
-
* Function to call when button is clicked.
|
|
116
|
-
*
|
|
117
|
-
* This callback should be used for running synchronous code, like
|
|
118
|
-
* dispatching a Redux action. For asynchronous code see the
|
|
119
|
-
* beforeNav and safeWithNav props. It should NOT be used to redirect
|
|
120
|
-
* to a different URL.
|
|
121
|
-
*
|
|
122
|
-
* Note: onClick is optional if href is present, but must be defined if
|
|
123
|
-
* href is not
|
|
124
|
-
*/
|
|
125
39
|
onClick?: (e: React.SyntheticEvent) => unknown;
|
|
126
|
-
/**
|
|
127
|
-
* Run async code before navigating. If the promise returned rejects then
|
|
128
|
-
* navigation will not occur.
|
|
129
|
-
*
|
|
130
|
-
* If both safeWithNav and beforeNav are provided, beforeNav will be run
|
|
131
|
-
* first and safeWithNav will only be run if beforeNav does not reject.
|
|
132
|
-
*
|
|
133
|
-
* WARNING: Do not use with `type="submit"`.
|
|
134
|
-
*/
|
|
135
40
|
beforeNav?: () => Promise<unknown>;
|
|
136
|
-
/**
|
|
137
|
-
* Run async code in the background while client-side navigating. If the
|
|
138
|
-
* browser does a full page load navigation, the callback promise must be
|
|
139
|
-
* settled before the navigation will occur. Errors are ignored so that
|
|
140
|
-
* navigation is guaranteed to succeed.
|
|
141
|
-
*
|
|
142
|
-
* WARNING: Do not use with `type="submit"`.
|
|
143
|
-
*/
|
|
144
41
|
safeWithNav?: () => Promise<unknown>;
|
|
145
|
-
}
|
|
146
|
-
type Props = SharedProps;
|
|
147
|
-
/**
|
|
148
|
-
* Reusable button component.
|
|
149
|
-
*
|
|
150
|
-
* Consisting of a [`ClickableBehavior`](#clickablebehavior) surrounding a
|
|
151
|
-
* `ButtonCore`. `ClickableBehavior` handles interactions and state changes.
|
|
152
|
-
* `ButtonCore` is a stateless component which displays the different states
|
|
153
|
-
* the `Button` can take.
|
|
154
|
-
*
|
|
155
|
-
* ### Usage
|
|
156
|
-
*
|
|
157
|
-
* ```jsx
|
|
158
|
-
* import Button from "@khanacademy/wonder-blocks-button";
|
|
159
|
-
*
|
|
160
|
-
* <Button
|
|
161
|
-
* onClick={(e) => console.log("Hello, world!")}
|
|
162
|
-
* >
|
|
163
|
-
* Hello, world!
|
|
164
|
-
* </Button>
|
|
165
|
-
* ```
|
|
166
|
-
*/
|
|
167
|
-
declare const Button: React.ForwardRefExoticComponent<Props & React.RefAttributes<typeof Link | HTMLButtonElement | HTMLAnchorElement>>;
|
|
42
|
+
} & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement | React.ForwardRefExoticComponent<import("react-router-dom-v5-compat").LinkProps & React.RefAttributes<HTMLAnchorElement>>>>;
|
|
168
43
|
export default Button;
|
package/dist/es/index.js
CHANGED
|
@@ -7,19 +7,22 @@ import { LabelSmall, LabelLarge } from '@khanacademy/wonder-blocks-typography';
|
|
|
7
7
|
import { addStyle, View } from '@khanacademy/wonder-blocks-core';
|
|
8
8
|
import { CircularSpinner } from '@khanacademy/wonder-blocks-progress-spinner';
|
|
9
9
|
import { mergeTheme, createThemeContext, ThemeSwitcherContext, useScopedTheme, useStyles } from '@khanacademy/wonder-blocks-theming';
|
|
10
|
-
import
|
|
10
|
+
import { focusStyles } from '@khanacademy/wonder-blocks-styles';
|
|
11
|
+
import { sizing, semanticColor, border, font, color } from '@khanacademy/wonder-blocks-tokens';
|
|
11
12
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
12
13
|
|
|
13
|
-
const
|
|
14
|
+
const textUnderlineOffset=sizing.size_040;const theme$1={root:{color:semanticColor.action,border:{width:{primary:{default:border.width.none,hover:border.width.medium,press:border.width.medium},secondary:{default:border.width.thin,hover:border.width.thin,press:border.width.thin},tertiary:{default:border.width.none,hover:border.width.medium,press:border.width.medium}},offset:{primary:border.width.medium,secondary:0,tertiary:0},radius:{small:border.radius.radius_040,medium:border.radius.radius_040,large:border.radius.radius_040}},sizing:{height:{small:sizing.size_320,medium:sizing.size_400,large:sizing.size_560},underline:{hover:sizing.size_020,press:sizing.size_010}},padding:{medium:sizing.size_160,large:sizing.size_320},font:{size:{large:"1.8rem"},lineHeight:{small:font.lineHeight.xMedium,default:font.lineHeight.large,large:"2.6rem"},weight:{default:font.weight.bold},offset:{default:textUnderlineOffset}}},icon:{color:{secondary:{progressive:{hover:{background:"transparent",foreground:semanticColor.action.secondary.progressive.hover.foreground}},destructive:{hover:{background:"transparent",foreground:semanticColor.action.secondary.destructive.hover.foreground}},neutral:{hover:{background:"transparent",foreground:semanticColor.action.secondary.neutral.hover.foreground}}}},border:{radius:border.radius.radius_full},margin:{inline:{inner:sizing.size_060,outer:`calc(-1 * ${border.width.medium})`}},padding:sizing.size_020}};
|
|
14
15
|
|
|
15
|
-
const secondaryBgColor=
|
|
16
|
+
const secondaryBgColor=color.offWhite;const theme=mergeTheme(theme$1,{root:{color:{secondary:{progressive:{default:{border:color.fadedBlue,background:secondaryBgColor},hover:{background:secondaryBgColor,foreground:semanticColor.action.secondary.progressive.default.foreground},press:{background:color.fadedBlue8}},destructive:{default:{border:color.fadedRed,background:secondaryBgColor},hover:{background:secondaryBgColor,foreground:semanticColor.action.secondary.destructive.default.foreground},press:{background:color.fadedRed8}}}},border:{radius:{medium:border.radius.radius_120,small:border.radius.radius_080,large:border.radius.radius_120}},font:{weight:{default:font.weight.regular}}},icon:{color:{secondary:{progressive:{hover:{background:color.fadedBlue16,foreground:semanticColor.action.secondary.progressive.default.foreground}},destructive:{hover:{background:color.fadedRed16,foreground:semanticColor.action.secondary.destructive.default.foreground}}}},border:{radius:border.radius.radius_full},margin:{inline:{outer:`calc(-1 * ${sizing.size_080})`}},padding:sizing.size_020}});
|
|
16
17
|
|
|
17
18
|
const themes={default:theme$1,khanmigo:theme};const ButtonThemeContext=createThemeContext(theme$1);function ThemedButton(props){const currentTheme=React.useContext(ThemeSwitcherContext);const theme=themes[currentTheme]||theme$1;return jsx(ButtonThemeContext.Provider,{value:theme,children:props.children})}
|
|
18
19
|
|
|
19
20
|
function ButtonIcon({icon,size,style,testId}){const commonProps={"aria-hidden":true,color:"currentColor",style:style,testId};switch(size){case"small":return jsx(PhosphorIcon,{...commonProps,size:"small",icon:icon});case"medium":default:return jsx(PhosphorIcon,{...commonProps,size:"medium",icon:icon})}}
|
|
20
21
|
|
|
21
|
-
const StyledA=addStyle("a");const StyledButton=addStyle("button");const StyledLink=addStyle(Link);const
|
|
22
|
+
const StyledA=addStyle("a");const StyledButton=addStyle("button");const StyledLink=addStyle(Link);const ButtonUnstyled=React.forwardRef(function ButtonUnstyled(props,ref){const{children,disabled,href,id,skipClientNav,style,testId,type,...restProps}=props;const commonProps={"data-testid":testId,id:id,role:"button",style:[styles$1.reset,style],...restProps};const inRouterContext=useInRouterContext();if(href&&!disabled){return inRouterContext&&!skipClientNav&&isClientSideUrl(href)?jsx(StyledLink,{...commonProps,to:href,ref:ref,children:children}):jsx(StyledA,{...commonProps,href:href,ref:ref,children:children})}else {return jsx(StyledButton,{type:type||"button",...commonProps,"aria-disabled":disabled,ref:ref,children:children})}});const styles$1=StyleSheet.create({reset:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"center",margin:0,padding:0,border:"none",cursor:"pointer",outline:"none",textDecoration:"none",boxSizing:"border-box",touchAction:"manipulation",userSelect:"none",":focus":{WebkitTapHighlightColor:"rgba(0,0,0,0)"}}});
|
|
22
23
|
|
|
23
|
-
const
|
|
24
|
+
const ButtonCore=React.forwardRef(function ButtonCore(props,ref){const{theme,themeName}=useScopedTheme(ButtonThemeContext);const sharedStyles=useStyles(themedSharedStyles,theme);const{children,skipClientNav,actionType,disabled:disabledProp,focused,hovered,href=undefined,kind="primary",labelStyle,pressed,size="medium",style,testId,type=undefined,spinner,startIcon,endIcon,id,waiting:_,...restProps}=props;const buttonStyles=_generateStyles(actionType,kind,size,theme,themeName);const disabled=spinner||disabledProp;const defaultStyle=[sharedStyles.shared,startIcon&&sharedStyles.withStartIcon,endIcon&&sharedStyles.withEndIcon,buttonStyles.default,disabled&&buttonStyles.disabled,!disabled&&(pressed?buttonStyles.pressed:focused&&buttonStyles.focused),size==="small"&&sharedStyles.small,size==="large"&&sharedStyles.large];const Label=size==="small"?LabelSmall:LabelLarge;const label=jsx(Label,{style:[sharedStyles.text,size==="small"&&sharedStyles.smallText,size==="large"&&sharedStyles.largeText,labelStyle,spinner&&sharedStyles.hiddenText,kind==="tertiary"&&!disabled&&(pressed?[buttonStyles.hover,buttonStyles.active]:hovered&&buttonStyles.hover)],testId:testId?`${testId}-inner-label`:undefined,children:children});const sizeMapping={medium:"small",small:"xsmall",large:"medium"};const iconSize=size==="small"?"small":"medium";const contents=jsxs(React.Fragment,{children:[startIcon&&jsx(View,{style:sharedStyles.iconWrapper,children:jsx(ButtonIcon,{size:iconSize,icon:startIcon,style:[sharedStyles.startIcon,kind==="tertiary"&&sharedStyles.tertiaryStartIcon],testId:testId?`${testId}-start-icon`:undefined})}),label,spinner&&jsx(CircularSpinner,{style:sharedStyles.spinner,size:sizeMapping[size],light:kind==="primary",testId:`${testId||"button"}-spinner`}),endIcon&&jsx(View,{testId:testId?`${testId}-end-icon-wrapper`:undefined,style:[styles.endIcon,sharedStyles.iconWrapper,sharedStyles.endIconWrapper,kind==="tertiary"&&sharedStyles.endIconWrapperTertiary,!disabled&&(focused||hovered)&&kind!=="primary"&&buttonStyles.iconWrapperHovered],children:jsx(ButtonIcon,{size:iconSize,icon:endIcon,testId:testId?`${testId}-end-icon`:undefined})})]});return jsx(ButtonUnstyled,{...restProps,disabled:disabled,href:href,id:id,ref:ref,skipClientNav:skipClientNav,style:[defaultStyle,style],testId:testId,tabIndex:props.tabIndex,type:type,children:contents})});const themedSharedStyles=theme=>({shared:{height:theme.root.sizing.height.medium,paddingBlock:0,paddingInline:theme.root.padding.medium},small:{borderRadius:theme.root.border.radius.small,height:theme.root.sizing.height.small},large:{borderRadius:theme.root.border.radius.large,height:theme.root.sizing.height.large},text:{alignItems:"center",fontWeight:theme.root.font.weight.default,whiteSpace:"nowrap",overflow:"hidden",lineHeight:theme.root.font.lineHeight.default,textOverflow:"ellipsis",display:"inline-block",pointerEvents:"none"},smallText:{lineHeight:theme.root.font.lineHeight.small},largeText:{fontSize:theme.root.font.size.large,lineHeight:theme.root.font.lineHeight.large},hiddenText:{visibility:"hidden"},spinner:{position:"absolute"},startIcon:{marginInlineStart:theme.icon.margin.inline.outer,marginInlineEnd:theme.icon.margin.inline.inner},tertiaryStartIcon:{marginInlineStart:0},endIcon:{marginInlineStart:theme.icon.margin.inline.inner},iconWrapper:{borderRadius:theme.icon.border.radius,padding:theme.icon.padding,minWidth:"auto"},endIconWrapper:{marginInlineStart:theme.icon.margin.inline.inner,marginInlineEnd:theme.icon.margin.inline.outer},endIconWrapperTertiary:{marginInlineEnd:0}});const styles={};const _generateStyles=(actionType="progressive",kind,size,theme,themeName)=>{const buttonType=`${actionType}-${kind}-${size}-${themeName}`;if(styles[buttonType]){return styles[buttonType]}const padding=size==="large"?theme.root.padding.large:theme.root.padding.medium;const borderWidthKind=theme.root.border.width[kind];const outlineOffsetKind=theme.root.border.offset[kind];const themeVariant=theme.root.color[kind][actionType];const disabledState=theme.root.color[kind].disabled;const disabledStatesStyles={borderColor:disabledState.border,borderWidth:borderWidthKind.default,background:disabledState.background,color:disabledState.foreground};const disabledStatesOverrides={...disabledStatesStyles,outline:"none",boxShadow:"none",textDecoration:"none",textDecorationThickness:"unset",textUnderlineOffset:"unset"};const newStyles={default:{borderRadius:theme.root.border.radius[size],paddingInline:kind==="tertiary"?0:padding,borderStyle:"solid",borderWidth:borderWidthKind.default,borderColor:themeVariant.default.border,background:themeVariant.default.background,color:themeVariant.default.foreground,":hover":{background:themeVariant.hover.background,color:themeVariant.hover.foreground,...kind==="primary"?{outline:`${borderWidthKind.hover} solid ${themeVariant.hover.border}`,outlineOffset:outlineOffsetKind}:undefined,...kind==="secondary"?{borderColor:themeVariant.hover.border,boxShadow:`inset 0 0 0 ${borderWidthKind.hover} ${themeVariant.hover.border}`}:undefined,...kind==="tertiary"?{textDecoration:"underline",textUnderlineOffset:theme.root.font.offset.default,textDecorationThickness:theme.root.sizing.underline.hover}:undefined},["@media not (hover: hover)"]:{":hover":{backgroundColor:"transparent"}},":active":{background:themeVariant.press.background,color:themeVariant.press.foreground,...kind==="primary"?{outline:`${borderWidthKind.press} solid ${themeVariant.press.border}`,outlineOffset:outlineOffsetKind}:undefined,...kind==="secondary"?{borderColor:themeVariant.press.border,boxShadow:`inset 0 0 0 ${borderWidthKind.press} ${themeVariant.press.border}`}:undefined,...kind==="tertiary"?{textDecoration:"underline",textUnderlineOffset:theme.root.font.offset.default,textDecorationThickness:theme.root.sizing.underline.press}:undefined},...focusStyles.focus,...kind==="secondary"?{":focus-visible:hover":{...focusStyles.focus[":focus-visible"],boxShadow:`inset 0 0 0 ${borderWidthKind.hover} ${themeVariant.hover.border}, ${focusStyles.focus[":focus-visible"].boxShadow}`},":focus-visible:active":{...focusStyles.focus[":focus-visible"],boxShadow:`inset 0 0 0 ${borderWidthKind.press} ${themeVariant.press.border}, ${focusStyles.focus[":focus-visible"].boxShadow}`}}:{}},disabled:{cursor:"not-allowed",...disabledStatesStyles,":hover":disabledStatesOverrides,":active":disabledStatesOverrides,":focus-visible":disabledStatesStyles},iconWrapperHovered:{...kind==="secondary"?{backgroundColor:theme.icon.color[kind][actionType].hover.background,color:theme.icon.color[kind][actionType].hover.foreground}:undefined}};styles[buttonType]=StyleSheet.create(newStyles);return styles[buttonType]};
|
|
25
|
+
|
|
26
|
+
const Button=React.forwardRef(function Button(props,ref){const{href=undefined,type=undefined,children,skipClientNav,onClick,beforeNav=undefined,safeWithNav=undefined,tabIndex,target,rel,actionType="progressive",kind="primary",size="medium",disabled=false,spinner=false,...sharedButtonCoreProps}=props;const inRouterContext=useInRouterContext();const ClickableBehavior=getClickableBehavior(href,skipClientNav,inRouterContext);const extraClickableProps=beforeNav?{beforeNav}:{target};return jsx(ClickableBehavior,{disabled:spinner||disabled,href:href,role:"button",type:type,onClick:onClick,safeWithNav:safeWithNav,rel:rel,...extraClickableProps,children:(state,restChildProps)=>jsx(ThemedButton,{children:jsx(ButtonCore,{...sharedButtonCoreProps,...state,...restChildProps,disabled:disabled,spinner:spinner||state.waiting,actionType:actionType,kind:kind,size:size,skipClientNav:skipClientNav,href:href,target:target,type:type,tabIndex:tabIndex,ref:ref,children:children})})})});
|
|
24
27
|
|
|
25
28
|
export { Button as default };
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -9,7 +9,8 @@ var wonderBlocksTypography = require('@khanacademy/wonder-blocks-typography');
|
|
|
9
9
|
var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
10
10
|
var wonderBlocksProgressSpinner = require('@khanacademy/wonder-blocks-progress-spinner');
|
|
11
11
|
var wonderBlocksTheming = require('@khanacademy/wonder-blocks-theming');
|
|
12
|
-
var
|
|
12
|
+
var wonderBlocksStyles = require('@khanacademy/wonder-blocks-styles');
|
|
13
|
+
var wonderBlocksTokens = require('@khanacademy/wonder-blocks-tokens');
|
|
13
14
|
var wonderBlocksIcon = require('@khanacademy/wonder-blocks-icon');
|
|
14
15
|
|
|
15
16
|
function _interopNamespace(e) {
|
|
@@ -31,18 +32,19 @@ function _interopNamespace(e) {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
|
-
var tokens__namespace = /*#__PURE__*/_interopNamespace(tokens);
|
|
35
35
|
|
|
36
|
-
const
|
|
36
|
+
const textUnderlineOffset=wonderBlocksTokens.sizing.size_040;const theme$1={root:{color:wonderBlocksTokens.semanticColor.action,border:{width:{primary:{default:wonderBlocksTokens.border.width.none,hover:wonderBlocksTokens.border.width.medium,press:wonderBlocksTokens.border.width.medium},secondary:{default:wonderBlocksTokens.border.width.thin,hover:wonderBlocksTokens.border.width.thin,press:wonderBlocksTokens.border.width.thin},tertiary:{default:wonderBlocksTokens.border.width.none,hover:wonderBlocksTokens.border.width.medium,press:wonderBlocksTokens.border.width.medium}},offset:{primary:wonderBlocksTokens.border.width.medium,secondary:0,tertiary:0},radius:{small:wonderBlocksTokens.border.radius.radius_040,medium:wonderBlocksTokens.border.radius.radius_040,large:wonderBlocksTokens.border.radius.radius_040}},sizing:{height:{small:wonderBlocksTokens.sizing.size_320,medium:wonderBlocksTokens.sizing.size_400,large:wonderBlocksTokens.sizing.size_560},underline:{hover:wonderBlocksTokens.sizing.size_020,press:wonderBlocksTokens.sizing.size_010}},padding:{medium:wonderBlocksTokens.sizing.size_160,large:wonderBlocksTokens.sizing.size_320},font:{size:{large:"1.8rem"},lineHeight:{small:wonderBlocksTokens.font.lineHeight.xMedium,default:wonderBlocksTokens.font.lineHeight.large,large:"2.6rem"},weight:{default:wonderBlocksTokens.font.weight.bold},offset:{default:textUnderlineOffset}}},icon:{color:{secondary:{progressive:{hover:{background:"transparent",foreground:wonderBlocksTokens.semanticColor.action.secondary.progressive.hover.foreground}},destructive:{hover:{background:"transparent",foreground:wonderBlocksTokens.semanticColor.action.secondary.destructive.hover.foreground}},neutral:{hover:{background:"transparent",foreground:wonderBlocksTokens.semanticColor.action.secondary.neutral.hover.foreground}}}},border:{radius:wonderBlocksTokens.border.radius.radius_full},margin:{inline:{inner:wonderBlocksTokens.sizing.size_060,outer:`calc(-1 * ${wonderBlocksTokens.border.width.medium})`}},padding:wonderBlocksTokens.sizing.size_020}};
|
|
37
37
|
|
|
38
|
-
const secondaryBgColor=
|
|
38
|
+
const secondaryBgColor=wonderBlocksTokens.color.offWhite;const theme=wonderBlocksTheming.mergeTheme(theme$1,{root:{color:{secondary:{progressive:{default:{border:wonderBlocksTokens.color.fadedBlue,background:secondaryBgColor},hover:{background:secondaryBgColor,foreground:wonderBlocksTokens.semanticColor.action.secondary.progressive.default.foreground},press:{background:wonderBlocksTokens.color.fadedBlue8}},destructive:{default:{border:wonderBlocksTokens.color.fadedRed,background:secondaryBgColor},hover:{background:secondaryBgColor,foreground:wonderBlocksTokens.semanticColor.action.secondary.destructive.default.foreground},press:{background:wonderBlocksTokens.color.fadedRed8}}}},border:{radius:{medium:wonderBlocksTokens.border.radius.radius_120,small:wonderBlocksTokens.border.radius.radius_080,large:wonderBlocksTokens.border.radius.radius_120}},font:{weight:{default:wonderBlocksTokens.font.weight.regular}}},icon:{color:{secondary:{progressive:{hover:{background:wonderBlocksTokens.color.fadedBlue16,foreground:wonderBlocksTokens.semanticColor.action.secondary.progressive.default.foreground}},destructive:{hover:{background:wonderBlocksTokens.color.fadedRed16,foreground:wonderBlocksTokens.semanticColor.action.secondary.destructive.default.foreground}}}},border:{radius:wonderBlocksTokens.border.radius.radius_full},margin:{inline:{outer:`calc(-1 * ${wonderBlocksTokens.sizing.size_080})`}},padding:wonderBlocksTokens.sizing.size_020}});
|
|
39
39
|
|
|
40
40
|
const themes={default:theme$1,khanmigo:theme};const ButtonThemeContext=wonderBlocksTheming.createThemeContext(theme$1);function ThemedButton(props){const currentTheme=React__namespace.useContext(wonderBlocksTheming.ThemeSwitcherContext);const theme=themes[currentTheme]||theme$1;return jsxRuntime.jsx(ButtonThemeContext.Provider,{value:theme,children:props.children})}
|
|
41
41
|
|
|
42
42
|
function ButtonIcon({icon,size,style,testId}){const commonProps={"aria-hidden":true,color:"currentColor",style:style,testId};switch(size){case"small":return jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{...commonProps,size:"small",icon:icon});case"medium":default:return jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{...commonProps,size:"medium",icon:icon})}}
|
|
43
43
|
|
|
44
|
-
const StyledA=wonderBlocksCore.addStyle("a");const StyledButton=wonderBlocksCore.addStyle("button");const StyledLink=wonderBlocksCore.addStyle(reactRouterDomV5Compat.Link);const
|
|
44
|
+
const StyledA=wonderBlocksCore.addStyle("a");const StyledButton=wonderBlocksCore.addStyle("button");const StyledLink=wonderBlocksCore.addStyle(reactRouterDomV5Compat.Link);const ButtonUnstyled=React__namespace.forwardRef(function ButtonUnstyled(props,ref){const{children,disabled,href,id,skipClientNav,style,testId,type,...restProps}=props;const commonProps={"data-testid":testId,id:id,role:"button",style:[styles$1.reset,style],...restProps};const inRouterContext=reactRouterDomV5Compat.useInRouterContext();if(href&&!disabled){return inRouterContext&&!skipClientNav&&wonderBlocksClickable.isClientSideUrl(href)?jsxRuntime.jsx(StyledLink,{...commonProps,to:href,ref:ref,children:children}):jsxRuntime.jsx(StyledA,{...commonProps,href:href,ref:ref,children:children})}else {return jsxRuntime.jsx(StyledButton,{type:type||"button",...commonProps,"aria-disabled":disabled,ref:ref,children:children})}});const styles$1=aphrodite.StyleSheet.create({reset:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"center",margin:0,padding:0,border:"none",cursor:"pointer",outline:"none",textDecoration:"none",boxSizing:"border-box",touchAction:"manipulation",userSelect:"none",":focus":{WebkitTapHighlightColor:"rgba(0,0,0,0)"}}});
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const ButtonCore=React__namespace.forwardRef(function ButtonCore(props,ref){const{theme,themeName}=wonderBlocksTheming.useScopedTheme(ButtonThemeContext);const sharedStyles=wonderBlocksTheming.useStyles(themedSharedStyles,theme);const{children,skipClientNav,actionType,disabled:disabledProp,focused,hovered,href=undefined,kind="primary",labelStyle,pressed,size="medium",style,testId,type=undefined,spinner,startIcon,endIcon,id,waiting:_,...restProps}=props;const buttonStyles=_generateStyles(actionType,kind,size,theme,themeName);const disabled=spinner||disabledProp;const defaultStyle=[sharedStyles.shared,startIcon&&sharedStyles.withStartIcon,endIcon&&sharedStyles.withEndIcon,buttonStyles.default,disabled&&buttonStyles.disabled,!disabled&&(pressed?buttonStyles.pressed:focused&&buttonStyles.focused),size==="small"&&sharedStyles.small,size==="large"&&sharedStyles.large];const Label=size==="small"?wonderBlocksTypography.LabelSmall:wonderBlocksTypography.LabelLarge;const label=jsxRuntime.jsx(Label,{style:[sharedStyles.text,size==="small"&&sharedStyles.smallText,size==="large"&&sharedStyles.largeText,labelStyle,spinner&&sharedStyles.hiddenText,kind==="tertiary"&&!disabled&&(pressed?[buttonStyles.hover,buttonStyles.active]:hovered&&buttonStyles.hover)],testId:testId?`${testId}-inner-label`:undefined,children:children});const sizeMapping={medium:"small",small:"xsmall",large:"medium"};const iconSize=size==="small"?"small":"medium";const contents=jsxRuntime.jsxs(React__namespace.Fragment,{children:[startIcon&&jsxRuntime.jsx(wonderBlocksCore.View,{style:sharedStyles.iconWrapper,children:jsxRuntime.jsx(ButtonIcon,{size:iconSize,icon:startIcon,style:[sharedStyles.startIcon,kind==="tertiary"&&sharedStyles.tertiaryStartIcon],testId:testId?`${testId}-start-icon`:undefined})}),label,spinner&&jsxRuntime.jsx(wonderBlocksProgressSpinner.CircularSpinner,{style:sharedStyles.spinner,size:sizeMapping[size],light:kind==="primary",testId:`${testId||"button"}-spinner`}),endIcon&&jsxRuntime.jsx(wonderBlocksCore.View,{testId:testId?`${testId}-end-icon-wrapper`:undefined,style:[styles.endIcon,sharedStyles.iconWrapper,sharedStyles.endIconWrapper,kind==="tertiary"&&sharedStyles.endIconWrapperTertiary,!disabled&&(focused||hovered)&&kind!=="primary"&&buttonStyles.iconWrapperHovered],children:jsxRuntime.jsx(ButtonIcon,{size:iconSize,icon:endIcon,testId:testId?`${testId}-end-icon`:undefined})})]});return jsxRuntime.jsx(ButtonUnstyled,{...restProps,disabled:disabled,href:href,id:id,ref:ref,skipClientNav:skipClientNav,style:[defaultStyle,style],testId:testId,tabIndex:props.tabIndex,type:type,children:contents})});const themedSharedStyles=theme=>({shared:{height:theme.root.sizing.height.medium,paddingBlock:0,paddingInline:theme.root.padding.medium},small:{borderRadius:theme.root.border.radius.small,height:theme.root.sizing.height.small},large:{borderRadius:theme.root.border.radius.large,height:theme.root.sizing.height.large},text:{alignItems:"center",fontWeight:theme.root.font.weight.default,whiteSpace:"nowrap",overflow:"hidden",lineHeight:theme.root.font.lineHeight.default,textOverflow:"ellipsis",display:"inline-block",pointerEvents:"none"},smallText:{lineHeight:theme.root.font.lineHeight.small},largeText:{fontSize:theme.root.font.size.large,lineHeight:theme.root.font.lineHeight.large},hiddenText:{visibility:"hidden"},spinner:{position:"absolute"},startIcon:{marginInlineStart:theme.icon.margin.inline.outer,marginInlineEnd:theme.icon.margin.inline.inner},tertiaryStartIcon:{marginInlineStart:0},endIcon:{marginInlineStart:theme.icon.margin.inline.inner},iconWrapper:{borderRadius:theme.icon.border.radius,padding:theme.icon.padding,minWidth:"auto"},endIconWrapper:{marginInlineStart:theme.icon.margin.inline.inner,marginInlineEnd:theme.icon.margin.inline.outer},endIconWrapperTertiary:{marginInlineEnd:0}});const styles={};const _generateStyles=(actionType="progressive",kind,size,theme,themeName)=>{const buttonType=`${actionType}-${kind}-${size}-${themeName}`;if(styles[buttonType]){return styles[buttonType]}const padding=size==="large"?theme.root.padding.large:theme.root.padding.medium;const borderWidthKind=theme.root.border.width[kind];const outlineOffsetKind=theme.root.border.offset[kind];const themeVariant=theme.root.color[kind][actionType];const disabledState=theme.root.color[kind].disabled;const disabledStatesStyles={borderColor:disabledState.border,borderWidth:borderWidthKind.default,background:disabledState.background,color:disabledState.foreground};const disabledStatesOverrides={...disabledStatesStyles,outline:"none",boxShadow:"none",textDecoration:"none",textDecorationThickness:"unset",textUnderlineOffset:"unset"};const newStyles={default:{borderRadius:theme.root.border.radius[size],paddingInline:kind==="tertiary"?0:padding,borderStyle:"solid",borderWidth:borderWidthKind.default,borderColor:themeVariant.default.border,background:themeVariant.default.background,color:themeVariant.default.foreground,":hover":{background:themeVariant.hover.background,color:themeVariant.hover.foreground,...kind==="primary"?{outline:`${borderWidthKind.hover} solid ${themeVariant.hover.border}`,outlineOffset:outlineOffsetKind}:undefined,...kind==="secondary"?{borderColor:themeVariant.hover.border,boxShadow:`inset 0 0 0 ${borderWidthKind.hover} ${themeVariant.hover.border}`}:undefined,...kind==="tertiary"?{textDecoration:"underline",textUnderlineOffset:theme.root.font.offset.default,textDecorationThickness:theme.root.sizing.underline.hover}:undefined},["@media not (hover: hover)"]:{":hover":{backgroundColor:"transparent"}},":active":{background:themeVariant.press.background,color:themeVariant.press.foreground,...kind==="primary"?{outline:`${borderWidthKind.press} solid ${themeVariant.press.border}`,outlineOffset:outlineOffsetKind}:undefined,...kind==="secondary"?{borderColor:themeVariant.press.border,boxShadow:`inset 0 0 0 ${borderWidthKind.press} ${themeVariant.press.border}`}:undefined,...kind==="tertiary"?{textDecoration:"underline",textUnderlineOffset:theme.root.font.offset.default,textDecorationThickness:theme.root.sizing.underline.press}:undefined},...wonderBlocksStyles.focusStyles.focus,...kind==="secondary"?{":focus-visible:hover":{...wonderBlocksStyles.focusStyles.focus[":focus-visible"],boxShadow:`inset 0 0 0 ${borderWidthKind.hover} ${themeVariant.hover.border}, ${wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}`},":focus-visible:active":{...wonderBlocksStyles.focusStyles.focus[":focus-visible"],boxShadow:`inset 0 0 0 ${borderWidthKind.press} ${themeVariant.press.border}, ${wonderBlocksStyles.focusStyles.focus[":focus-visible"].boxShadow}`}}:{}},disabled:{cursor:"not-allowed",...disabledStatesStyles,":hover":disabledStatesOverrides,":active":disabledStatesOverrides,":focus-visible":disabledStatesStyles},iconWrapperHovered:{...kind==="secondary"?{backgroundColor:theme.icon.color[kind][actionType].hover.background,color:theme.icon.color[kind][actionType].hover.foreground}:undefined}};styles[buttonType]=aphrodite.StyleSheet.create(newStyles);return styles[buttonType]};
|
|
47
|
+
|
|
48
|
+
const Button=React__namespace.forwardRef(function Button(props,ref){const{href=undefined,type=undefined,children,skipClientNav,onClick,beforeNav=undefined,safeWithNav=undefined,tabIndex,target,rel,actionType="progressive",kind="primary",size="medium",disabled=false,spinner=false,...sharedButtonCoreProps}=props;const inRouterContext=reactRouterDomV5Compat.useInRouterContext();const ClickableBehavior=wonderBlocksClickable.getClickableBehavior(href,skipClientNav,inRouterContext);const extraClickableProps=beforeNav?{beforeNav}:{target};return jsxRuntime.jsx(ClickableBehavior,{disabled:spinner||disabled,href:href,role:"button",type:type,onClick:onClick,safeWithNav:safeWithNav,rel:rel,...extraClickableProps,children:(state,restChildProps)=>jsxRuntime.jsx(ThemedButton,{children:jsxRuntime.jsx(ButtonCore,{...sharedButtonCoreProps,...state,...restChildProps,disabled:disabled,spinner:spinner||state.waiting,actionType:actionType,kind:kind,size:size,skipClientNav:skipClientNav,href:href,target:target,type:type,tabIndex:tabIndex,ref:ref,children:children})})})});
|
|
47
49
|
|
|
48
50
|
module.exports = Button;
|