@khanacademy/wonder-blocks-link
Advanced tools
Comparing version
# @khanacademy/wonder-blocks-link | ||
## 0.0.0-PR2464-20250206220047 | ||
## 0.0.0-PR2465-20250207172334 | ||
### Major Changes | ||
### Patch Changes | ||
- a0944f2: Remove `kind` prop as the `secondary` variant is now dropped. | ||
- Updated dependencies [22d94f9] | ||
- @khanacademy/wonder-blocks-core@0.0.0-PR2465-20250207172334 | ||
- @khanacademy/wonder-blocks-clickable@0.0.0-PR2465-20250207172334 | ||
- @khanacademy/wonder-blocks-icon@0.0.0-PR2465-20250207172334 | ||
## 7.1.0 | ||
### Minor Changes | ||
@@ -18,11 +23,11 @@ | ||
- 969864b: Update internal addStyle variable name to address aphrodite-add-style-variable-name linting rule | ||
- bb2a026: pnpm: Switch to workspace protocol to handle dependency versions with changesets on monorepo setup" | ||
- 257b91d: Update Link to use CSS pseudo-classes (:hover, :focus-visible, :active) instead of JS driven states (hovered, focused, pressed). | ||
- bbfd08a: Internal `Link` refactor to use `semanticColor` tokens intead of `color`. Also moved the link colors to an object to prepare this for an upcoming theme integration" | ||
- Updated dependencies [969864b] | ||
- Updated dependencies [bb2a026] | ||
- Updated dependencies [f03298f] | ||
- @khanacademy/wonder-blocks-clickable@0.0.0-PR2464-20250206220047 | ||
- @khanacademy/wonder-blocks-core@0.0.0-PR2464-20250206220047 | ||
- @khanacademy/wonder-blocks-icon@0.0.0-PR2464-20250206220047 | ||
- @khanacademy/wonder-blocks-tokens@0.0.0-PR2464-20250206220047 | ||
- @khanacademy/wonder-blocks-clickable@6.1.0 | ||
- @khanacademy/wonder-blocks-core@12.1.0 | ||
- @khanacademy/wonder-blocks-icon@5.1.0 | ||
- @khanacademy/wonder-blocks-tokens@4.2.0 | ||
@@ -29,0 +34,0 @@ ## 7.0.8 |
@@ -26,2 +26,6 @@ import * as React from "react"; | ||
/** | ||
* Kind of Link. Note: Secondary light Links are not supported. | ||
*/ | ||
kind?: "primary" | "secondary"; | ||
/** | ||
* Whether the button is on a dark/colored background. | ||
@@ -28,0 +32,0 @@ */ |
@@ -10,8 +10,8 @@ import _objectDestructuringEmpty from '@babel/runtime/helpers/objectDestructuringEmpty'; | ||
import { addStyle } from '@khanacademy/wonder-blocks-core'; | ||
import { spacing, semanticColor, color, mix, border } from '@khanacademy/wonder-blocks-tokens'; | ||
import { spacing, mix, fade, color } from '@khanacademy/wonder-blocks-tokens'; | ||
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon'; | ||
import externalLinkIcon from '@phosphor-icons/core/bold/arrow-square-out-bold.svg'; | ||
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"]; | ||
const StyledAnchor = addStyle("a"); | ||
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"]; | ||
const StyledA = addStyle("a"); | ||
const StyledLink = addStyle(Link$1); | ||
@@ -24,4 +24,6 @@ const LinkCore = React.forwardRef(function LinkCore(props, ref) { | ||
focused, | ||
hovered, | ||
href, | ||
inline = false, | ||
kind = "primary", | ||
light = false, | ||
@@ -37,4 +39,5 @@ visitable = false, | ||
restProps = _objectWithoutPropertiesLoose(props, _excluded$1); | ||
const linkStyles = _generateStyles(inline, light, visitable); | ||
const defaultStyles = [sharedStyles.shared, linkStyles.rest, inline && linkStyles.restInline, !pressed && focused && linkStyles.focus]; | ||
const linkStyles = _generateStyles(inline, kind, light, visitable); | ||
const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting; | ||
const defaultStyles = [sharedStyles.shared, restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus]; | ||
const commonProps = _extends({ | ||
@@ -73,3 +76,3 @@ "data-testid": testId, | ||
ref: ref | ||
}), linkContent) : React.createElement(StyledAnchor, _extends({}, commonProps, { | ||
}), linkContent) : React.createElement(StyledA, _extends({}, commonProps, { | ||
href: href, | ||
@@ -101,92 +104,66 @@ ref: ref | ||
}); | ||
const action = semanticColor.action.outlined.progressive; | ||
const pink = "#fa50ae"; | ||
const theme = { | ||
color: { | ||
default: { | ||
rest: { | ||
foreground: action.default.foreground | ||
}, | ||
hover: { | ||
foreground: action.hover.foreground | ||
}, | ||
focus: { | ||
border: semanticColor.border.focus, | ||
foreground: action.hover.foreground | ||
}, | ||
press: { | ||
foreground: action.press.foreground | ||
}, | ||
restVisited: { | ||
foreground: color.purple | ||
}, | ||
pressVisited: { | ||
foreground: mix(color.offBlack32, color.purple) | ||
} | ||
}, | ||
inverse: { | ||
rest: { | ||
foreground: semanticColor.text.inverse | ||
}, | ||
hover: { | ||
foreground: semanticColor.text.inverse | ||
}, | ||
focus: { | ||
border: semanticColor.border.inverse, | ||
foreground: semanticColor.text.inverse | ||
}, | ||
press: { | ||
foreground: color.fadedBlue | ||
}, | ||
restVisited: { | ||
foreground: pink | ||
}, | ||
pressVisited: { | ||
foreground: mix(color.white50, pink) | ||
} | ||
} | ||
} | ||
}; | ||
const _generateStyles = (inline, light, visitable) => { | ||
const buttonType = `${inline.toString()}-${light.toString()}-${visitable.toString()}`; | ||
const _generateStyles = (inline, kind, light, visitable) => { | ||
const buttonType = `${kind}-${inline.toString()}-${light.toString()}-${visitable.toString()}`; | ||
if (styles[buttonType]) { | ||
return styles[buttonType]; | ||
} | ||
const variant = light ? theme.color.inverse : theme.color.default; | ||
const restVisited = visitable ? { | ||
if (kind === "secondary" && light) { | ||
throw new Error("Secondary Light links are not supported"); | ||
} | ||
if (visitable && kind !== "primary") { | ||
throw new Error("Only primary link is visitable"); | ||
} | ||
const { | ||
blue, | ||
purple, | ||
white, | ||
offBlack, | ||
offBlack32, | ||
offBlack64 | ||
} = color; | ||
const pink = "#fa50ae"; | ||
const linkPurple = mix(fade(offBlack, 0.08), purple); | ||
const fadedBlue = color.fadedBlue; | ||
const activeLightVisited = mix(fade(white, 0.32), pink); | ||
const activeDefaultPrimary = color.activeBlue; | ||
const primaryDefaultTextColor = light ? white : blue; | ||
const secondaryDefaultTextColor = inline ? offBlack : offBlack64; | ||
const defaultTextColor = kind === "primary" ? primaryDefaultTextColor : secondaryDefaultTextColor; | ||
const primaryActiveColor = light ? fadedBlue : activeDefaultPrimary; | ||
const secondaryActiveColor = inline ? activeDefaultPrimary : offBlack; | ||
const activeColor = kind === "primary" ? primaryActiveColor : secondaryActiveColor; | ||
const defaultVisited = visitable ? { | ||
":visited": { | ||
color: variant.restVisited.foreground | ||
color: light ? pink : linkPurple | ||
} | ||
} : Object.freeze({}); | ||
const pressVisited = visitable ? { | ||
const activeVisited = visitable ? { | ||
":visited": { | ||
color: variant.pressVisited.foreground | ||
color: light ? activeLightVisited : mix(offBlack32, linkPurple) | ||
} | ||
} : Object.freeze({}); | ||
const focusStyling = _extends({ | ||
color: variant.focus.foreground, | ||
outline: `${border.width.hairline}px solid ${variant.focus.border}`, | ||
borderRadius: border.radius.small_3 | ||
}, restVisited); | ||
const pressStyling = _extends({ | ||
color: variant.press.foreground, | ||
textDecoration: "underline currentcolor solid" | ||
}, pressVisited); | ||
const newStyles = { | ||
rest: _extends({ | ||
color: variant.rest.foreground | ||
}, restVisited, { | ||
":hover": _extends({ | ||
textDecoration: "underline currentcolor solid", | ||
color: variant.hover.foreground | ||
}, restVisited), | ||
":focus-visible": focusStyling, | ||
":active": pressStyling | ||
}), | ||
restInline: { | ||
resting: _extends({ | ||
color: defaultTextColor | ||
}, defaultVisited), | ||
restingInline: _extends({ | ||
color: defaultTextColor, | ||
textDecoration: "underline currentcolor solid", | ||
textUnderlineOffset: 2 | ||
}, defaultVisited), | ||
hover: _extends({ | ||
textDecoration: "underline currentcolor solid", | ||
color: defaultTextColor | ||
}, defaultVisited), | ||
focus: { | ||
":focus-visible": _extends({ | ||
color: defaultTextColor, | ||
outline: `1px solid ${light ? white : blue}`, | ||
borderRadius: 3 | ||
}, defaultVisited) | ||
}, | ||
focus: focusStyling, | ||
press: pressStyling | ||
active: _extends({ | ||
color: activeColor, | ||
textDecoration: "underline currentcolor solid" | ||
}, activeVisited) | ||
}; | ||
@@ -197,3 +174,3 @@ styles[buttonType] = StyleSheet.create(newStyles); | ||
const _excluded = ["onClick", "beforeNav", "safeWithNav", "href", "skipClientNav", "children", "tabIndex", "onKeyDown", "onKeyUp", "target", "inline", "light", "visitable"]; | ||
const _excluded = ["onClick", "beforeNav", "safeWithNav", "href", "skipClientNav", "children", "tabIndex", "onKeyDown", "onKeyUp", "target", "inline", "kind", "light", "visitable"]; | ||
const Link = React.forwardRef(function Link(props, ref) { | ||
@@ -212,2 +189,3 @@ const { | ||
inline = false, | ||
kind = "primary", | ||
light = false, | ||
@@ -237,2 +215,3 @@ visitable = false | ||
inline: inline, | ||
kind: kind, | ||
light: light, | ||
@@ -261,2 +240,3 @@ visitable: visitable, | ||
inline: inline, | ||
kind: kind, | ||
light: light, | ||
@@ -263,0 +243,0 @@ visitable: visitable, |
@@ -35,4 +35,4 @@ 'use strict'; | ||
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"]; | ||
const StyledAnchor = wonderBlocksCore.addStyle("a"); | ||
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"]; | ||
const StyledA = wonderBlocksCore.addStyle("a"); | ||
const StyledLink = wonderBlocksCore.addStyle(reactRouterDom.Link); | ||
@@ -45,4 +45,6 @@ const LinkCore = React__namespace.forwardRef(function LinkCore(props, ref) { | ||
focused, | ||
hovered, | ||
href, | ||
inline = false, | ||
kind = "primary", | ||
light = false, | ||
@@ -58,4 +60,5 @@ visitable = false, | ||
restProps = _objectWithoutPropertiesLoose(props, _excluded$1); | ||
const linkStyles = _generateStyles(inline, light, visitable); | ||
const defaultStyles = [sharedStyles.shared, linkStyles.rest, inline && linkStyles.restInline, !pressed && focused && linkStyles.focus]; | ||
const linkStyles = _generateStyles(inline, kind, light, visitable); | ||
const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting; | ||
const defaultStyles = [sharedStyles.shared, restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus]; | ||
const commonProps = _extends({ | ||
@@ -94,3 +97,3 @@ "data-testid": testId, | ||
ref: ref | ||
}), linkContent) : React__namespace.createElement(StyledAnchor, _extends({}, commonProps, { | ||
}), linkContent) : React__namespace.createElement(StyledA, _extends({}, commonProps, { | ||
href: href, | ||
@@ -122,92 +125,66 @@ ref: ref | ||
}); | ||
const action = wonderBlocksTokens.semanticColor.action.outlined.progressive; | ||
const pink = "#fa50ae"; | ||
const theme = { | ||
color: { | ||
default: { | ||
rest: { | ||
foreground: action.default.foreground | ||
}, | ||
hover: { | ||
foreground: action.hover.foreground | ||
}, | ||
focus: { | ||
border: wonderBlocksTokens.semanticColor.border.focus, | ||
foreground: action.hover.foreground | ||
}, | ||
press: { | ||
foreground: action.press.foreground | ||
}, | ||
restVisited: { | ||
foreground: wonderBlocksTokens.color.purple | ||
}, | ||
pressVisited: { | ||
foreground: wonderBlocksTokens.mix(wonderBlocksTokens.color.offBlack32, wonderBlocksTokens.color.purple) | ||
} | ||
}, | ||
inverse: { | ||
rest: { | ||
foreground: wonderBlocksTokens.semanticColor.text.inverse | ||
}, | ||
hover: { | ||
foreground: wonderBlocksTokens.semanticColor.text.inverse | ||
}, | ||
focus: { | ||
border: wonderBlocksTokens.semanticColor.border.inverse, | ||
foreground: wonderBlocksTokens.semanticColor.text.inverse | ||
}, | ||
press: { | ||
foreground: wonderBlocksTokens.color.fadedBlue | ||
}, | ||
restVisited: { | ||
foreground: pink | ||
}, | ||
pressVisited: { | ||
foreground: wonderBlocksTokens.mix(wonderBlocksTokens.color.white50, pink) | ||
} | ||
} | ||
} | ||
}; | ||
const _generateStyles = (inline, light, visitable) => { | ||
const buttonType = `${inline.toString()}-${light.toString()}-${visitable.toString()}`; | ||
const _generateStyles = (inline, kind, light, visitable) => { | ||
const buttonType = `${kind}-${inline.toString()}-${light.toString()}-${visitable.toString()}`; | ||
if (styles[buttonType]) { | ||
return styles[buttonType]; | ||
} | ||
const variant = light ? theme.color.inverse : theme.color.default; | ||
const restVisited = visitable ? { | ||
if (kind === "secondary" && light) { | ||
throw new Error("Secondary Light links are not supported"); | ||
} | ||
if (visitable && kind !== "primary") { | ||
throw new Error("Only primary link is visitable"); | ||
} | ||
const { | ||
blue, | ||
purple, | ||
white, | ||
offBlack, | ||
offBlack32, | ||
offBlack64 | ||
} = wonderBlocksTokens.color; | ||
const pink = "#fa50ae"; | ||
const linkPurple = wonderBlocksTokens.mix(wonderBlocksTokens.fade(offBlack, 0.08), purple); | ||
const fadedBlue = wonderBlocksTokens.color.fadedBlue; | ||
const activeLightVisited = wonderBlocksTokens.mix(wonderBlocksTokens.fade(white, 0.32), pink); | ||
const activeDefaultPrimary = wonderBlocksTokens.color.activeBlue; | ||
const primaryDefaultTextColor = light ? white : blue; | ||
const secondaryDefaultTextColor = inline ? offBlack : offBlack64; | ||
const defaultTextColor = kind === "primary" ? primaryDefaultTextColor : secondaryDefaultTextColor; | ||
const primaryActiveColor = light ? fadedBlue : activeDefaultPrimary; | ||
const secondaryActiveColor = inline ? activeDefaultPrimary : offBlack; | ||
const activeColor = kind === "primary" ? primaryActiveColor : secondaryActiveColor; | ||
const defaultVisited = visitable ? { | ||
":visited": { | ||
color: variant.restVisited.foreground | ||
color: light ? pink : linkPurple | ||
} | ||
} : Object.freeze({}); | ||
const pressVisited = visitable ? { | ||
const activeVisited = visitable ? { | ||
":visited": { | ||
color: variant.pressVisited.foreground | ||
color: light ? activeLightVisited : wonderBlocksTokens.mix(offBlack32, linkPurple) | ||
} | ||
} : Object.freeze({}); | ||
const focusStyling = _extends({ | ||
color: variant.focus.foreground, | ||
outline: `${wonderBlocksTokens.border.width.hairline}px solid ${variant.focus.border}`, | ||
borderRadius: wonderBlocksTokens.border.radius.small_3 | ||
}, restVisited); | ||
const pressStyling = _extends({ | ||
color: variant.press.foreground, | ||
textDecoration: "underline currentcolor solid" | ||
}, pressVisited); | ||
const newStyles = { | ||
rest: _extends({ | ||
color: variant.rest.foreground | ||
}, restVisited, { | ||
":hover": _extends({ | ||
textDecoration: "underline currentcolor solid", | ||
color: variant.hover.foreground | ||
}, restVisited), | ||
":focus-visible": focusStyling, | ||
":active": pressStyling | ||
}), | ||
restInline: { | ||
resting: _extends({ | ||
color: defaultTextColor | ||
}, defaultVisited), | ||
restingInline: _extends({ | ||
color: defaultTextColor, | ||
textDecoration: "underline currentcolor solid", | ||
textUnderlineOffset: 2 | ||
}, defaultVisited), | ||
hover: _extends({ | ||
textDecoration: "underline currentcolor solid", | ||
color: defaultTextColor | ||
}, defaultVisited), | ||
focus: { | ||
":focus-visible": _extends({ | ||
color: defaultTextColor, | ||
outline: `1px solid ${light ? white : blue}`, | ||
borderRadius: 3 | ||
}, defaultVisited) | ||
}, | ||
focus: focusStyling, | ||
press: pressStyling | ||
active: _extends({ | ||
color: activeColor, | ||
textDecoration: "underline currentcolor solid" | ||
}, activeVisited) | ||
}; | ||
@@ -218,3 +195,3 @@ styles[buttonType] = aphrodite.StyleSheet.create(newStyles); | ||
const _excluded = ["onClick", "beforeNav", "safeWithNav", "href", "skipClientNav", "children", "tabIndex", "onKeyDown", "onKeyUp", "target", "inline", "light", "visitable"]; | ||
const _excluded = ["onClick", "beforeNav", "safeWithNav", "href", "skipClientNav", "children", "tabIndex", "onKeyDown", "onKeyUp", "target", "inline", "kind", "light", "visitable"]; | ||
const Link = React__namespace.forwardRef(function Link(props, ref) { | ||
@@ -233,2 +210,3 @@ const { | ||
inline = false, | ||
kind = "primary", | ||
light = false, | ||
@@ -258,2 +236,3 @@ visitable = false | ||
inline: inline, | ||
kind: kind, | ||
light: light, | ||
@@ -282,2 +261,3 @@ visitable: visitable, | ||
inline: inline, | ||
kind: kind, | ||
light: light, | ||
@@ -284,0 +264,0 @@ visitable: visitable, |
{ | ||
"name": "@khanacademy/wonder-blocks-link", | ||
"version": "0.0.0-PR2464-20250206220047", | ||
"version": "0.0.0-PR2465-20250207172334", | ||
"design": "v1", | ||
@@ -16,6 +16,6 @@ "publishConfig": { | ||
"@babel/runtime": "^7.24.5", | ||
"@khanacademy/wonder-blocks-clickable": "0.0.0-PR2464-20250206220047", | ||
"@khanacademy/wonder-blocks-core": "0.0.0-PR2464-20250206220047", | ||
"@khanacademy/wonder-blocks-icon": "0.0.0-PR2464-20250206220047", | ||
"@khanacademy/wonder-blocks-tokens": "0.0.0-PR2464-20250206220047" | ||
"@khanacademy/wonder-blocks-clickable": "0.0.0-PR2465-20250207172334", | ||
"@khanacademy/wonder-blocks-core": "0.0.0-PR2465-20250207172334", | ||
"@khanacademy/wonder-blocks-icon": "0.0.0-PR2465-20250207172334", | ||
"@khanacademy/wonder-blocks-tokens": "4.2.0" | ||
}, | ||
@@ -30,3 +30,3 @@ "peerDependencies": { | ||
"devDependencies": { | ||
"@khanacademy/wb-dev-build-settings": "0.0.0-PR2464-20250206220047" | ||
"@khanacademy/wb-dev-build-settings": "2.1.0" | ||
}, | ||
@@ -33,0 +33,0 @@ "scripts": { |
44586
-0.3%668
-5.11%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated