fluent-svelte-updated
Version:
Forked from https://github.com/vegardlarsen/fluent-svelte. A faithful implementation of Microsoft's Fluent Design System in Svelte.
97 lines (96 loc) • 3.84 kB
JavaScript
// Note: bubble and listen are no longer available in Svelte 4+
// These functions need to be replaced with modern alternatives
import { tabbable } from "tabbable";
import { createFocusTrap } from "focus-trap";
export { default as ComboBoxItem } from "./ComboBox/ComboBoxItem.svelte";
export { default as FlyoutSurface } from "./Flyout/FlyoutSurface.svelte";
export { default as TooltipSurface } from "./Tooltip/TooltipSurface.svelte";
export { default as MenuFlyoutSurface } from "./MenuFlyout/MenuFlyoutSurface.svelte";
export { default as CalendarViewItem } from "./CalendarView/CalendarViewItem.svelte";
export function externalMouseEvents(node, options = { type: "click", stopPropagation: false }) {
const { type, stopPropagation } = options;
const handleEvent = (event) => {
if (stopPropagation)
event.stopPropagation();
if (node && !node.contains(event.target) && !event.defaultPrevented) {
node.dispatchEvent(new CustomEvent(`outer${type}`, {
detail: event
}));
}
};
document.addEventListener(type, handleEvent, true);
return {
destroy() {
document.removeEventListener(type, handleEvent, true);
}
};
}
// Basic wrapper action around focus-trap
export function focusTrap(node, options) {
const trap = createFocusTrap(node, (options = { ...options, fallbackFocus: node }));
trap.activate();
return {
destroy() {
trap.deactivate();
}
};
}
// ID generator for handling WAI-ARIA related attributes
export function uid(prefix) {
return (prefix +
String.fromCharCode(Math.floor(Math.random() * 26) + 97) +
Math.random().toString(16).slice(2) +
Date.now().toString(16).split(".")[0]);
}
// Controls the focus of a list of elements by using the arrow keys
export function arrowNavigation(node, options = { preventTab: false, stopPropagation: false }) {
const handleKeyDown = (event) => {
const { key } = event;
const { activeElement } = document;
let tabOrder = tabbable(node);
// if (directChildren) tabOrder = tabOrder.filter(child => child.parentElement === node);
const activeIndex = tabOrder.indexOf(document.activeElement);
if (tabOrder.length < 0)
return;
if (key === "ArrowUp" ||
key === "ArrowDown" ||
key === "Home" ||
key === "End" ||
(key === "Tab" && options.preventTab)) {
event.preventDefault();
if (options.stopPropagation)
event.stopPropagation();
}
if (key === "ArrowUp") {
if (tabOrder[0] === activeElement) {
tabOrder[tabOrder.length - 1].focus();
}
else if (tabOrder.includes(activeElement)) {
tabOrder[activeIndex - 1].focus();
}
}
else if (key === "ArrowDown") {
if (tabOrder[tabOrder.length - 1] === activeElement) {
tabOrder[0].focus();
}
else if (tabOrder.includes(activeElement)) {
tabOrder[activeIndex + 1].focus();
}
}
else if (key === "Home") {
tabOrder[0].focus();
}
else if (key === "End") {
tabOrder[tabOrder.length - 1].focus();
}
};
node.addEventListener("keydown", handleKeyDown);
return {
destroy: () => node.removeEventListener("keydown", handleKeyDown)
};
}
// Returns a number representing the duration of a specified CSS custom property in ms
export function getCSSDuration(property) {
const duration = window.getComputedStyle(document.documentElement).getPropertyValue(property);
return parseFloat(duration) * (/\ds$/.test(duration) ? 1000 : 1) || 0;
}