-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
226 additions
and
269 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
"@salt-ds/lab": patch | ||
--- | ||
|
||
Updates to Lab `SkipLink` | ||
|
||
- Deprecated `targetRef` prop, added `target` prop to accept a string representing the ID of the target element. | ||
- Updated styling to adhere with the rest of the library styles for consistency. | ||
- Fixed an issue where the `SkipLink` would render when the ref to the target element was broken. Now, the skip link will not render at all if the target element is not found. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,44 @@ | ||
/* CSS Variables for the Skip Link */ | ||
.saltSkipLink { | ||
--skipLink-padding: var(--saltSkipLink-padding, var(--salt-size-unit)); | ||
--skipLink-margin: var(--saltSkipLink-margin, var(--salt-size-unit)); | ||
--skipLink-background: var(--saltSkipLink-background, var(--salt-actionable-primary-background)); | ||
--skipLink-color: var(--saltSkipLink-color, var(--salt-content-primary-foreground)); | ||
} | ||
|
||
/* Overrides */ | ||
.saltSkipLink { | ||
--saltLink-color-focus: var(--skipLink-color); | ||
} | ||
|
||
.saltSkipLink-target { | ||
--skipLink-target-focus: var(--salt-focused-outline); | ||
} | ||
|
||
/*Styles applied when the link is focused to hide the Skip Link when not in focus*/ | ||
.saltSkipLink { | ||
top: 0; | ||
left: 0; | ||
opacity: 0; | ||
width: 1px; | ||
height: 1px; | ||
display: block; | ||
opacity: 0; | ||
margin: 0; | ||
padding: 0; | ||
overflow: hidden; | ||
position: absolute; | ||
|
||
color: var(--salt-content-primary-foreground); | ||
letter-spacing: var(--salt-text-letterSpacing); | ||
text-decoration: var(--salt-navigable-textDecoration); | ||
font-family: var(--salt-text-fontFamily); | ||
white-space: nowrap; | ||
background: var(--saltSkipLink-background, var(--salt-container-primary-background)); | ||
} | ||
|
||
/* Styles applied when the link is focused to display the Skip Link only when in focus*/ | ||
.saltSkipLink:focus { | ||
opacity: 1; | ||
width: auto; | ||
height: auto; | ||
white-space: nowrap; | ||
margin: var(--skipLink-margin); | ||
padding: calc(var(--skipLink-padding) - 1px) var(--skipLink-padding) var(--skipLink-padding); | ||
background: var(--skipLink-background); | ||
color: var(--skipLink-color); | ||
box-shadow: var(--salt-overlayable-shadow-popout); | ||
height: max(var(--salt-size-base), auto); | ||
padding: var(--salt-spacing-100) var(--salt-spacing-300); | ||
outline: var(--salt-focused-outline); | ||
outline-offset: calc(-1 * var(--salt-focused-outlineWidth)); | ||
box-shadow: var(--salt-overlayable-shadow); | ||
} | ||
|
||
.saltSkipLink { | ||
font-size: var(--salt-text-fontSize); | ||
font-family: var(--saltSkipLink-fontFamily, var(--salt-text-fontFamily)); | ||
line-height: var(--saltSkipLink-lineHeight, var(--salt-text-lineHeight)); | ||
@keyframes fade-in-out-outline { | ||
0% { | ||
outline-color: var(--salt-focused-outlineColor); | ||
} | ||
100% { | ||
outline-color: transparent; | ||
} | ||
} | ||
|
||
/*Styles applied to the skip link focus target*/ | ||
.saltSkipLink-target { | ||
outline: var(--skipLink-target-focus); | ||
animation: fade-in-out-outline var(--salt-duration-notable) var(--salt-animation-timing-function) both; | ||
outline: var(--salt-focused-outline); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,60 @@ | ||
import { Link, type LinkProps, makePrefixer } from "@salt-ds/core"; | ||
import { makePrefixer } from "@salt-ds/core"; | ||
import { useComponentCssInjection } from "@salt-ds/styles"; | ||
import { useWindow } from "@salt-ds/window"; | ||
import { clsx } from "clsx"; | ||
import { type RefObject, forwardRef } from "react"; | ||
import { | ||
type ComponentPropsWithoutRef, | ||
forwardRef, | ||
useEffect, | ||
useRef, | ||
} from "react"; | ||
import { useManageFocusOnTarget } from "./internal/useManageFocusOnTarget"; | ||
|
||
import skipLinkCss from "./SkipLink.css"; | ||
|
||
interface SkipLinkProps extends LinkProps { | ||
interface SkipLinkProps extends ComponentPropsWithoutRef<"a"> { | ||
/** | ||
* This is a ref that has access to the target element. | ||
* | ||
* This will be used to apply focus to that element | ||
* | ||
* Refs are referentially stable so if this changes it won't be picked up | ||
* will need to find a better way of passing in the target element to apply the attributes | ||
* The ID of the target element to apply focus when the link is clicked. | ||
* If the element with this ID is not found, the SkipLink will not be rendered. | ||
*/ | ||
targetRef?: RefObject<HTMLElement>; | ||
target: string; | ||
} | ||
|
||
const withBaseName = makePrefixer("saltSkipLink"); | ||
|
||
export const SkipLink = forwardRef<HTMLAnchorElement, SkipLinkProps>( | ||
function SkipLink({ className, targetRef, ...rest }, ref) { | ||
function SkipLink({ className, target, children, ...rest }, ref) { | ||
const targetWindow = useWindow(); | ||
useComponentCssInjection({ | ||
testId: "salt-skip-link", | ||
css: skipLinkCss, | ||
window: targetWindow, | ||
}); | ||
|
||
const targetClass = clsx(withBaseName("target"), className); | ||
const targetRef = useRef<HTMLElement | null>(null); | ||
|
||
const eventHandlers = useManageFocusOnTarget({ targetRef, targetClass }); | ||
useEffect(() => { | ||
targetRef.current = document.getElementById(target); | ||
}, [target]); | ||
|
||
const eventHandlers = useManageFocusOnTarget({ | ||
targetRef, | ||
targetClass: withBaseName("target"), | ||
}); | ||
|
||
return ( | ||
<li> | ||
<Link | ||
{...eventHandlers} | ||
{...rest} | ||
targetRef.current && ( | ||
<a | ||
className={clsx(withBaseName(), className)} | ||
href={`#${target}`} | ||
ref={ref} | ||
/> | ||
</li> | ||
target="_self" | ||
{...eventHandlers} | ||
{...rest} | ||
> | ||
{children} | ||
</a> | ||
) | ||
); | ||
}, | ||
); |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
export * from "./SkipLink"; | ||
export * from "./SkipLinks"; |
Oops, something went wrong.