@formkit/themes
Version:
FormKit base themes
1 lines • 20.5 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts"],"names":["sectionKey","themePlugin"],"mappings":"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","sourcesContent":["/**\n * This package contains the official themes for FormKit. Read the\n * {@link https://formkit.com/getting-started/installation |\n * installation documentation} for more information.\n *\n * @packageDocumentation\n */\n\nimport {\n FORMKIT_VERSION,\n FormKitNode,\n FormKitClasses,\n FormKitEvent,\n} from '@formkit/core'\n\n/**\n * A function that returns a class list string\n * @internal\n */\ntype ClassFunction = (node: FormKitNode, sectionKey: string) => string\n\n/**\n * A function that returns an icon SVG string.\n * @public\n */\nexport interface FormKitIconLoader {\n (iconName: string): string | undefined | Promise<string | undefined>\n}\n\n/**\n * A function that returns a remote URL for retrieving an SVG icon by name.\n * @public\n */\nexport interface FormKitIconLoaderUrl {\n (iconName: string): string | undefined\n}\n\n/**\n * A function to generate FormKit class functions from a JavaScript object.\n * @param classes - An object of input types with nested objects of sectionKeys and class lists.\n * @returns An object of sectionKeys with class functions.\n * @public\n */\nexport function generateClasses(\n classes: Record<string, Record<string, string>>\n): Record<string, string | FormKitClasses | Record<string, boolean>> {\n const classesBySectionKey: Record<string, Record<string, any>> = {}\n Object.keys(classes).forEach((type) => {\n Object.keys(classes[type]).forEach((sectionKey) => {\n if (!classesBySectionKey[sectionKey]) {\n classesBySectionKey[sectionKey] = {\n [type]: classes[type][sectionKey],\n }\n } else {\n classesBySectionKey[sectionKey][type] = classes[type][sectionKey]\n }\n })\n })\n\n Object.keys(classesBySectionKey).forEach((sectionKey) => {\n const classesObject = classesBySectionKey[sectionKey]\n classesBySectionKey[sectionKey] = function (node, sectionKey) {\n return addClassesBySection(node, sectionKey, classesObject)\n } as ClassFunction\n })\n\n return classesBySectionKey\n}\n\n/**\n * Updates a class list for a given sectionKey\n * @param node - the FormKit node being operated on\n * @param sectionKey - The section key to which the class list will be applied\n * @param classByType - Object containing mappings of class lists to section keys\n * @returns\n * @public\n */\nfunction addClassesBySection(\n node: FormKitNode,\n _sectionKey: string,\n classesByType: Record<string, () => string>\n): string {\n const type = node.props.type\n const family = node.props.family\n let classList = ''\n if (classesByType.global) {\n classList += classesByType.global + ' '\n }\n if (classesByType[`family:${family}`]) {\n classList += classesByType[`family:${family}`] + ' '\n }\n if (classesByType[type]) {\n classList += classesByType[type]\n }\n const listParts = classList.split('$reset')\n if (listParts.length > 1) {\n return `$reset ${listParts[listParts.length - 1].trim()}`\n }\n return listParts[0].trim()\n}\n\n/**\n * The document's computed CSS styles\n */\nlet documentStyles: Record<any, any> | undefined = undefined\nlet documentThemeLinkTag: HTMLElement | null = null\n\n/**\n * Stores the state of theme loading\n */\nlet themeDidLoad: (value?: unknown) => void\nlet themeHasLoaded = false\nlet themeWasRequested = false\n\nconst themeLoaded = /* #__PURE__ */ new Promise<void>((res) => {\n themeDidLoad = () => {\n themeHasLoaded = true\n res()\n }\n})\n\n/**\n * Check if we are client-side\n */\nconst isClient = typeof window !== 'undefined' && typeof fetch !== 'undefined'\ndocumentStyles = isClient\n ? /* #__PURE__ */ getComputedStyle(document.documentElement)\n : undefined\n\n/**\n * The FormKit icon Registry - a global record of loaded icons.\n * @public\n */\nexport const iconRegistry: Record<string, string | undefined> = {}\n\n/**\n * A collection of existing icon requests to avoid duplicate fetching\n */\nconst iconRequests: Record<string, any> = {}\n\n/**\n * Creates the theme plugin based on a given theme name.\n * @param theme - The name or id of the theme to apply.\n * @param icons - Icons you want to add to the global icon registry.\n * @param iconLoaderUrl - A function that returns a remote url for retrieving an\n * SVG icon by name.\n * @param iconLoader - A function that handles loading an icon when it is not\n * found in the registry.\n * @public\n */\nexport function createThemePlugin(\n theme?: string,\n icons?: Record<string, string | undefined>,\n iconLoaderUrl?: FormKitIconLoaderUrl,\n iconLoader?: FormKitIconLoader\n): (node: FormKitNode) => any {\n if (icons) {\n // add any user-provided icons to the registry\n Object.assign(iconRegistry, icons)\n }\n\n // if we have a theme declared, request it\n if (\n isClient &&\n !themeWasRequested &&\n documentStyles?.getPropertyValue('--formkit-theme')\n ) {\n // we have the theme loaded locally\n themeDidLoad()\n themeWasRequested = true\n } else if (theme && !themeWasRequested && isClient) {\n // we have the theme name but need to request it remotely\n loadTheme(theme)\n } else if (!themeWasRequested && isClient) {\n // we don't have a discoverable theme, so don't wait for it\n themeDidLoad()\n }\n\n const themePlugin = function themePlugin(node: FormKitNode) {\n // register the icon handler, and override with local prop value if it exists\n node.addProps(['iconLoader', 'iconLoaderUrl'])\n node.props.iconHandler = createIconHandler(\n node.props?.iconLoader ? node.props.iconLoader : iconLoader,\n node.props?.iconLoaderUrl ? node.props.iconLoaderUrl : iconLoaderUrl\n )\n loadIconPropIcons(node, node.props.iconHandler)\n\n node.on('created', () => {\n // set up the `-icon` click handlers\n if (node?.context?.handlers) {\n node.context.handlers.iconClick = (\n sectionKey: string\n ): ((e: MouseEvent) => void) | void => {\n const clickHandlerProp = `on${sectionKey\n .charAt(0)\n .toUpperCase()}${sectionKey.slice(1)}IconClick`\n const handlerFunction = node.props[clickHandlerProp]\n if (handlerFunction && typeof handlerFunction === 'function') {\n return (e: MouseEvent) => {\n return handlerFunction(node, e)\n }\n }\n return undefined\n }\n }\n if (node?.context?.fns) {\n node.context.fns.iconRole = (sectionKey: string): string | null => {\n const clickHandlerProp = `on${sectionKey\n .charAt(0)\n .toUpperCase()}${sectionKey.slice(1)}IconClick`\n return typeof node.props[clickHandlerProp] === 'function'\n ? 'button'\n : null\n }\n }\n })\n }\n\n themePlugin.iconHandler = createIconHandler(iconLoader, iconLoaderUrl)\n return themePlugin\n}\n\n/**\n * Loads a FormKit theme\n */\nfunction loadTheme(theme: string) {\n if (!theme || !isClient || typeof getComputedStyle !== 'function') {\n // if we're not client-side then bail\n return\n }\n\n // since we're client-side, flag that we've requested the theme\n themeWasRequested = true\n\n documentThemeLinkTag = document.getElementById('formkit-theme')\n\n // retrieve document styles on plugin creation when the window object exists\n\n if (\n theme &&\n // if we have a window object\n isClient &&\n // we don't have an existing theme OR the theme being set up is different\n ((!documentStyles?.getPropertyValue('--formkit-theme') &&\n !documentThemeLinkTag) ||\n (documentThemeLinkTag?.getAttribute('data-theme') &&\n documentThemeLinkTag?.getAttribute('data-theme') !== theme))\n ) {\n // if for some reason we didn't overwrite the __FKV__ token during publish\n // then use the `latest` tag for CDN fetching. (this applies to local dev as well)\n const formkitVersion = FORMKIT_VERSION.startsWith('__')\n ? 'latest'\n : FORMKIT_VERSION\n const themeUrl = `https://cdn.jsdelivr.net/npm/@formkit/themes@${formkitVersion}/dist/${theme}/theme.css`\n const link = document.createElement('link')\n link.type = 'text/css'\n link.rel = 'stylesheet'\n link.id = 'formkit-theme'\n link.setAttribute('data-theme', theme)\n link.onload = () => {\n documentStyles = getComputedStyle(document.documentElement) // grab new variables from theme\n themeDidLoad()\n }\n document.head.appendChild(link)\n link.href = themeUrl\n // if we had an existing theme being loaded, remove it.\n if (documentThemeLinkTag) {\n documentThemeLinkTag.remove()\n }\n }\n}\n\n/**\n * Returns a function responsible for loading an icon by name.\n * @param iconLoader - a function for loading an icon when it's not found in the\n * iconRegistry.\n * @param iconLoaderUrl - a function that returns a remote URL for retrieving an\n * SVG icon by name.\n * @public\n */\nexport function createIconHandler(\n iconLoader?: FormKitIconLoader,\n iconLoaderUrl?: FormKitIconLoaderUrl\n): FormKitIconLoader {\n return (\n iconName: string | boolean\n ): string | undefined | Promise<string | undefined> => {\n // bail if we got something that wasn't string\n if (typeof iconName !== 'string') return\n // if we're dealing with an inline SVG, just use it as-is\n if (iconName.startsWith('<svg')) {\n return iconName\n }\n\n // is this a default icon that should only load from a stylesheet?\n const isDefault = iconName.startsWith('default:')\n iconName = isDefault ? iconName.split(':')[1] : iconName\n\n // check if we've already loaded the icon before\n const iconWasAlreadyLoaded = iconName in iconRegistry\n\n let loadedIcon: string | undefined | Promise<string | undefined> = undefined\n\n if (iconWasAlreadyLoaded) {\n return iconRegistry[iconName]\n } else if (!iconRequests[iconName]) {\n loadedIcon = getIconFromStylesheet(iconName)\n loadedIcon =\n isClient && typeof loadedIcon === 'undefined'\n ? Promise.resolve(loadedIcon)\n : loadedIcon\n if (loadedIcon instanceof Promise) {\n iconRequests[iconName] = loadedIcon\n .then((iconValue) => {\n if (!iconValue && typeof iconName === 'string' && !isDefault) {\n return (loadedIcon =\n typeof iconLoader === 'function'\n ? iconLoader(iconName)\n : getRemoteIcon(iconName, iconLoaderUrl))\n }\n return iconValue\n })\n .then((finalIcon) => {\n if (typeof iconName === 'string') {\n iconRegistry[isDefault ? `default:${iconName}` : iconName] =\n finalIcon\n }\n return finalIcon\n })\n } else if (typeof loadedIcon === 'string') {\n iconRegistry[isDefault ? `default:${iconName}` : iconName] = loadedIcon\n return loadedIcon\n }\n }\n return iconRequests[iconName]\n }\n}\n\nfunction getIconFromStylesheet(\n iconName: string\n): string | undefined | Promise<string | undefined> {\n if (!isClient) return\n if (themeHasLoaded) {\n return loadStylesheetIcon(iconName)\n } else {\n return themeLoaded.then(() => {\n return loadStylesheetIcon(iconName)\n })\n }\n}\n\nfunction loadStylesheetIcon(iconName: string) {\n const cssVarIcon = documentStyles?.getPropertyValue(`--fk-icon-${iconName}`)\n if (cssVarIcon) {\n // if we have a matching icon in the CSS properties, then decode it\n const icon: string = atob(cssVarIcon)\n if (icon.startsWith('<svg')) {\n iconRegistry[iconName] = icon\n return icon\n }\n }\n return undefined\n}\n\n/**\n * Attempts to fetch a remote icon from the FormKit CDN\n * @param iconName - The string name of the icon\n * @public\n */\nfunction getRemoteIcon(\n iconName: string,\n iconLoaderUrl?: FormKitIconLoaderUrl\n): Promise<string | undefined> | undefined {\n const formkitVersion = FORMKIT_VERSION.startsWith('__')\n ? 'latest'\n : FORMKIT_VERSION\n const fetchUrl =\n typeof iconLoaderUrl === 'function'\n ? iconLoaderUrl(iconName)\n : `https://cdn.jsdelivr.net/npm/@formkit/icons@${formkitVersion}/dist/icons/${iconName}.svg`\n if (!isClient) return undefined\n return fetch(`${fetchUrl}`)\n .then(async (r) => {\n const icon = await r.text()\n if (icon.startsWith('<svg')) {\n return icon\n }\n return undefined\n })\n .catch((e) => {\n console.error(e)\n return undefined\n })\n}\n\n/**\n * Loads icons for the matching `-icon` props on a given node\n */\nfunction loadIconPropIcons(\n node: FormKitNode,\n iconHandler: FormKitIconLoader\n): void {\n const iconRegex = /^[a-zA-Z-]+(?:-icon|Icon)$/\n const iconProps = Object.keys(node.props).filter((prop) => {\n return iconRegex.test(prop)\n })\n iconProps.forEach((sectionKey) => {\n return loadPropIcon(node, iconHandler, sectionKey)\n })\n}\n\n/**\n * Loads an icon from an icon-prop declaration eg. suffix-icon=\"settings\"\n */\nfunction loadPropIcon(\n node: FormKitNode,\n iconHandler: FormKitIconLoader,\n sectionKey: string\n): Promise<void> | void {\n const iconName = node.props[sectionKey]\n const loadedIcon = iconHandler(iconName)\n const rawIconProp = `_raw${sectionKey\n .charAt(0)\n .toUpperCase()}${sectionKey.slice(1)}`\n const clickHandlerProp = `on${sectionKey\n .charAt(0)\n .toUpperCase()}${sectionKey.slice(1)}Click`\n node.addProps([rawIconProp, clickHandlerProp])\n // listen for changes to the icon prop\n node.on(`prop:${sectionKey}`, reloadIcon)\n if (loadedIcon instanceof Promise) {\n return loadedIcon.then((svg) => {\n node.props[rawIconProp] = svg\n })\n } else {\n node.props[rawIconProp] = loadedIcon\n }\n return\n}\n\n/**\n * reloads an icon when the prop value changes\n */\nfunction reloadIcon(event: FormKitEvent): void | Promise<void> {\n const node = event.origin\n const iconName = event.payload\n const iconHandler = node?.props?.iconHandler\n const sectionKey = event.name.split(':')[1]\n const rawIconProp = `_raw${sectionKey\n .charAt(0)\n .toUpperCase()}${sectionKey.slice(1)}`\n\n if (iconHandler && typeof iconHandler === 'function') {\n const loadedIcon = iconHandler(iconName)\n\n if (loadedIcon instanceof Promise) {\n return loadedIcon.then((svg) => {\n node.props[rawIconProp] = svg\n })\n } else {\n node.props[rawIconProp] = loadedIcon\n }\n }\n}\n"]}