UNPKG

solid-command-palette

Version:

Add a command palette to your Solid.js App

1,551 lines (1,550 loc) 56.2 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); import { createRenderEffect, sharedConfig, createSignal, createRoot, onCleanup, batch, $PROXY, getListener, createContext, useContext, createMemo, createEffect, onMount, createComponent, children, mergeProps, createComputed, untrack, splitProps, For, Show, createUniqueId } from "solid-js"; import tinykeys, { parseKeybinding } from "tinykeys"; import Fuse from "fuse.js"; const booleans = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "controls", "default", "disabled", "formnovalidate", "hidden", "indeterminate", "ismap", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "readonly", "required", "reversed", "seamless", "selected"]; const Properties = new Set(["className", "value", "readOnly", "formNoValidate", "isMap", "noModule", "playsInline", ...booleans]); const ChildProperties = new Set(["innerHTML", "textContent", "innerText", "children"]); const Aliases = { className: "class", htmlFor: "for" }; const PropAliases = { class: "className", formnovalidate: "formNoValidate", ismap: "isMap", nomodule: "noModule", playsinline: "playsInline", readonly: "readOnly" }; const DelegatedEvents = new Set(["beforeinput", "click", "dblclick", "focusin", "focusout", "input", "keydown", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "pointerdown", "pointermove", "pointerout", "pointerover", "pointerup", "touchend", "touchmove", "touchstart"]); const SVGNamespace = { xlink: "http://www.w3.org/1999/xlink", xml: "http://www.w3.org/XML/1998/namespace" }; function reconcileArrays(parentNode, a, b) { let bLength = b.length, aEnd = a.length, bEnd = bLength, aStart = 0, bStart = 0, after = a[aEnd - 1].nextSibling, map = null; while (aStart < aEnd || bStart < bEnd) { if (a[aStart] === b[bStart]) { aStart++; bStart++; continue; } while (a[aEnd - 1] === b[bEnd - 1]) { aEnd--; bEnd--; } if (aEnd === aStart) { const node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] : after; while (bStart < bEnd) parentNode.insertBefore(b[bStart++], node); } else if (bEnd === bStart) { while (aStart < aEnd) { if (!map || !map.has(a[aStart])) a[aStart].remove(); aStart++; } } else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) { const node = a[--aEnd].nextSibling; parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling); parentNode.insertBefore(b[--bEnd], node); a[aEnd] = b[bEnd]; } else { if (!map) { map = new Map(); let i = bStart; while (i < bEnd) map.set(b[i], i++); } const index = map.get(a[aStart]); if (index != null) { if (bStart < index && index < bEnd) { let i = aStart, sequence = 1, t; while (++i < aEnd && i < bEnd) { if ((t = map.get(a[i])) == null || t !== index + sequence) break; sequence++; } if (sequence > index - bStart) { const node = a[aStart]; while (bStart < index) parentNode.insertBefore(b[bStart++], node); } else parentNode.replaceChild(b[bStart++], a[aStart++]); } else aStart++; } else a[aStart++].remove(); } } } const $$EVENTS = "_$DX_DELEGATE"; function template(html, check, isSVG) { const t = document.createElement("template"); t.innerHTML = html; let node = t.content.firstChild; if (isSVG) node = node.firstChild; return node; } function delegateEvents(eventNames, document2 = window.document) { const e = document2[$$EVENTS] || (document2[$$EVENTS] = new Set()); for (let i = 0, l = eventNames.length; i < l; i++) { const name = eventNames[i]; if (!e.has(name)) { e.add(name); document2.addEventListener(name, eventHandler); } } } function setAttribute(node, name, value) { if (value == null) node.removeAttribute(name); else node.setAttribute(name, value); } function setAttributeNS(node, namespace, name, value) { if (value == null) node.removeAttributeNS(namespace, name); else node.setAttributeNS(namespace, name, value); } function addEventListener(node, name, handler, delegate) { if (delegate) { if (Array.isArray(handler)) { node[`$$${name}`] = handler[0]; node[`$$${name}Data`] = handler[1]; } else node[`$$${name}`] = handler; } else if (Array.isArray(handler)) { node.addEventListener(name, (e) => handler[0](handler[1], e)); } else node.addEventListener(name, handler); } function classList(node, value, prev = {}) { const classKeys = Object.keys(value || {}), prevKeys = Object.keys(prev); let i, len; for (i = 0, len = prevKeys.length; i < len; i++) { const key = prevKeys[i]; if (!key || key === "undefined" || value[key]) continue; toggleClassKey(node, key, false); delete prev[key]; } for (i = 0, len = classKeys.length; i < len; i++) { const key = classKeys[i], classValue = !!value[key]; if (!key || key === "undefined" || prev[key] === classValue || !classValue) continue; toggleClassKey(node, key, true); prev[key] = classValue; } return prev; } function style(node, value, prev = {}) { const nodeStyle = node.style; if (value == null || typeof value === "string") return nodeStyle.cssText = value; typeof prev === "string" && (prev = {}); let v, s; for (s in prev) { value[s] == null && nodeStyle.removeProperty(s); delete prev[s]; } for (s in value) { v = value[s]; if (v !== prev[s]) { nodeStyle.setProperty(s, v); prev[s] = v; } } return prev; } function spread(node, accessor, isSVG, skipChildren) { if (typeof accessor === "function") { createRenderEffect((current) => spreadExpression(node, accessor(), current, isSVG, skipChildren)); } else spreadExpression(node, accessor, void 0, isSVG, skipChildren); } function insert(parent, accessor, marker, initial) { if (marker !== void 0 && !initial) initial = []; if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker); createRenderEffect((current) => insertExpression(parent, accessor(), current, marker), initial); } function assign(node, props, isSVG, skipChildren, prevProps = {}) { for (const prop in prevProps) { if (!(prop in props)) { if (prop === "children") continue; assignProp(node, prop, null, prevProps[prop], isSVG); } } for (const prop in props) { if (prop === "children") { if (!skipChildren) insertExpression(node, props.children); continue; } const value = props[prop]; prevProps[prop] = assignProp(node, prop, value, prevProps[prop], isSVG); } } function toPropertyName(name) { return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase()); } function toggleClassKey(node, key, value) { const classNames = key.trim().split(/\s+/); for (let i = 0, nameLen = classNames.length; i < nameLen; i++) node.classList.toggle(classNames[i], value); } function assignProp(node, prop, value, prev, isSVG) { let isCE, isProp, isChildProp; if (prop === "style") return style(node, value, prev); if (prop === "classList") return classList(node, value, prev); if (value === prev) return prev; if (prop === "ref") { value(node); } else if (prop.slice(0, 3) === "on:") { node.addEventListener(prop.slice(3), value); } else if (prop.slice(0, 10) === "oncapture:") { node.addEventListener(prop.slice(10), value, true); } else if (prop.slice(0, 2) === "on") { const name = prop.slice(2).toLowerCase(); const delegate = DelegatedEvents.has(name); addEventListener(node, name, value, delegate); delegate && delegateEvents([name]); } else if ((isChildProp = ChildProperties.has(prop)) || !isSVG && (PropAliases[prop] || (isProp = Properties.has(prop))) || (isCE = node.nodeName.includes("-"))) { if (isCE && !isProp && !isChildProp) node[toPropertyName(prop)] = value; else node[PropAliases[prop] || prop] = value; } else { const ns = isSVG && prop.indexOf(":") > -1 && SVGNamespace[prop.split(":")[0]]; if (ns) setAttributeNS(node, ns, prop, value); else setAttribute(node, Aliases[prop] || prop, value); } return value; } function eventHandler(e) { const key = `$$${e.type}`; let node = e.composedPath && e.composedPath()[0] || e.target; if (e.target !== node) { Object.defineProperty(e, "target", { configurable: true, value: node }); } Object.defineProperty(e, "currentTarget", { configurable: true, get() { return node || document; } }); while (node !== null) { const handler = node[key]; if (handler && !node.disabled) { const data = node[`${key}Data`]; data !== void 0 ? handler(data, e) : handler(e); if (e.cancelBubble) return; } node = node.host && node.host !== node && node.host instanceof Node ? node.host : node.parentNode; } } function spreadExpression(node, props, prevProps = {}, isSVG, skipChildren) { if (!skipChildren && "children" in props) { createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children)); } createRenderEffect(() => assign(node, props, isSVG, true, prevProps)); return prevProps; } function insertExpression(parent, value, current, marker, unwrapArray) { if (sharedConfig.context && !current) current = [...parent.childNodes]; while (typeof current === "function") current = current(); if (value === current) return current; const t = typeof value, multi = marker !== void 0; parent = multi && current[0] && current[0].parentNode || parent; if (t === "string" || t === "number") { if (t === "number") value = value.toString(); if (multi) { let node = current[0]; if (node && node.nodeType === 3) { node.data = value; } else node = document.createTextNode(value); current = cleanChildren(parent, current, marker, node); } else { if (current !== "" && typeof current === "string") { current = parent.firstChild.data = value; } else current = parent.textContent = value; } } else if (value == null || t === "boolean") { if (sharedConfig.context) return current; current = cleanChildren(parent, current, marker); } else if (t === "function") { createRenderEffect(() => { let v = value(); while (typeof v === "function") v = v(); current = insertExpression(parent, v, current, marker); }); return () => current; } else if (Array.isArray(value)) { const array = []; if (normalizeIncomingArray(array, value, unwrapArray)) { createRenderEffect(() => current = insertExpression(parent, array, current, marker, true)); return () => current; } if (sharedConfig.context && current && current.length) { for (let i = 0; i < array.length; i++) { if (array[i].parentNode) return current = array; } return current; } if (array.length === 0) { current = cleanChildren(parent, current, marker); if (multi) return current; } else { if (Array.isArray(current)) { if (current.length === 0) { appendNodes(parent, array, marker); } else reconcileArrays(parent, current, array); } else if (current == null || current === "") { appendNodes(parent, array); } else { reconcileArrays(parent, multi && current || [parent.firstChild], array); } } current = array; } else if (value instanceof Node) { if (sharedConfig.context) return current = value.parentNode ? multi ? [value] : value : current; if (Array.isArray(current)) { if (multi) return current = cleanChildren(parent, current, marker, value); cleanChildren(parent, current, null, value); } else if (current == null || current === "" || !parent.firstChild) { parent.appendChild(value); } else parent.replaceChild(value, parent.firstChild); current = value; } else ; return current; } function normalizeIncomingArray(normalized, array, unwrap2) { let dynamic = false; for (let i = 0, len = array.length; i < len; i++) { let item = array[i], t; if (item instanceof Node) { normalized.push(item); } else if (item == null || item === true || item === false) ; else if (Array.isArray(item)) { dynamic = normalizeIncomingArray(normalized, item) || dynamic; } else if ((t = typeof item) === "string") { normalized.push(document.createTextNode(item)); } else if (t === "function") { if (unwrap2) { while (typeof item === "function") item = item(); dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item]) || dynamic; } else { normalized.push(item); dynamic = true; } } else normalized.push(document.createTextNode(item.toString())); } return dynamic; } function appendNodes(parent, array, marker) { for (let i = 0, len = array.length; i < len; i++) parent.insertBefore(array[i], marker); } function cleanChildren(parent, current, marker, replacement) { if (marker === void 0) return parent.textContent = ""; const node = replacement || document.createTextNode(""); if (current.length) { let inserted = false; for (let i = current.length - 1; i >= 0; i--) { const el = current[i]; if (node !== el) { const isParent = el.parentNode === parent; if (!inserted && !i) isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker); else isParent && el.remove(); } else inserted = true; } } else parent.insertBefore(node, marker); return [node]; } const SVG_NAMESPACE = "http://www.w3.org/2000/svg"; function createElement(tagName, isSVG = false) { return isSVG ? document.createElementNS(SVG_NAMESPACE, tagName) : document.createElement(tagName); } function Portal(props) { const { useShadow } = props, marker = document.createTextNode(""), mount = props.mount || document.body; function renderPortal() { if (sharedConfig.context) { const [s, set] = createSignal(false); queueMicrotask(() => set(true)); return () => s() && props.children; } else return () => props.children; } if (mount instanceof HTMLHeadElement) { const [clean, setClean] = createSignal(false); const cleanup = () => setClean(true); createRoot((dispose) => insert(mount, () => !clean() ? renderPortal()() : dispose(), null)); onCleanup(() => { if (sharedConfig.context) queueMicrotask(cleanup); else cleanup(); }); } else { const container = createElement(props.isSVG ? "g" : "div", props.isSVG), renderRoot = useShadow && container.attachShadow ? container.attachShadow({ mode: "open" }) : container; Object.defineProperty(container, "host", { get() { return marker.parentNode; } }); insert(renderRoot, renderPortal()); mount.appendChild(container); props.ref && props.ref(container); onCleanup(() => mount.removeChild(container)); } return marker; } const $RAW = Symbol("store-raw"), $NODE = Symbol("store-node"), $NAME = Symbol("store-name"); function wrap$1(value, name) { let p = value[$PROXY]; if (!p) { Object.defineProperty(value, $PROXY, { value: p = new Proxy(value, proxyTraps$1) }); const keys = Object.keys(value), desc = Object.getOwnPropertyDescriptors(value); for (let i = 0, l = keys.length; i < l; i++) { const prop = keys[i]; if (desc[prop].get) { const get = desc[prop].get.bind(p); Object.defineProperty(value, prop, { get }); } } } return p; } function isWrappable(obj) { return obj != null && typeof obj === "object" && (obj[$PROXY] || !obj.__proto__ || obj.__proto__ === Object.prototype || Array.isArray(obj)); } function unwrap(item, set = new Set()) { let result, unwrapped, v, prop; if (result = item != null && item[$RAW]) return result; if (!isWrappable(item) || set.has(item)) return item; if (Array.isArray(item)) { if (Object.isFrozen(item)) item = item.slice(0); else set.add(item); for (let i = 0, l = item.length; i < l; i++) { v = item[i]; if ((unwrapped = unwrap(v, set)) !== v) item[i] = unwrapped; } } else { if (Object.isFrozen(item)) item = Object.assign({}, item); else set.add(item); const keys = Object.keys(item), desc = Object.getOwnPropertyDescriptors(item); for (let i = 0, l = keys.length; i < l; i++) { prop = keys[i]; if (desc[prop].get) continue; v = item[prop]; if ((unwrapped = unwrap(v, set)) !== v) item[prop] = unwrapped; } } return item; } function getDataNodes(target) { let nodes = target[$NODE]; if (!nodes) Object.defineProperty(target, $NODE, { value: nodes = {} }); return nodes; } function proxyDescriptor(target, property) { const desc = Reflect.getOwnPropertyDescriptor(target, property); if (!desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE || property === $NAME) return desc; delete desc.value; delete desc.writable; desc.get = () => target[$PROXY][property]; return desc; } function ownKeys(target) { if (getListener()) { const nodes = getDataNodes(target); (nodes._ || (nodes._ = createDataNode()))(); } return Reflect.ownKeys(target); } function createDataNode() { const [s, set] = createSignal(void 0, { equals: false, internal: true }); s.$ = set; return s; } const proxyTraps$1 = { get(target, property, receiver) { if (property === $RAW) return target; if (property === $PROXY) return receiver; const value = target[property]; if (property === $NODE || property === "__proto__") return value; const wrappable = isWrappable(value); if (getListener() && (typeof value !== "function" || target.hasOwnProperty(property))) { let nodes, node; if (wrappable && (nodes = getDataNodes(value))) { node = nodes._ || (nodes._ = createDataNode()); node(); } nodes = getDataNodes(target); node = nodes[property] || (nodes[property] = createDataNode()); node(); } return wrappable ? wrap$1(value) : value; }, set() { return true; }, deleteProperty() { return true; }, ownKeys, getOwnPropertyDescriptor: proxyDescriptor }; function setProperty(state, property, value) { if (state[property] === value) return; const array = Array.isArray(state); const len = state.length; const isUndefined = value === void 0; const notify = array || isUndefined === property in state; if (isUndefined) { delete state[property]; } else state[property] = value; let nodes = getDataNodes(state), node; (node = nodes[property]) && node.$(); if (array && state.length !== len) (node = nodes.length) && node.$(); notify && (node = nodes._) && node.$(); } function mergeStoreNode(state, value) { const keys = Object.keys(value); for (let i = 0; i < keys.length; i += 1) { const key = keys[i]; setProperty(state, key, value[key]); } } function updatePath(current, path, traversed = []) { let part, prev = current; if (path.length > 1) { part = path.shift(); const partType = typeof part, isArray = Array.isArray(current); if (Array.isArray(part)) { for (let i = 0; i < part.length; i++) { updatePath(current, [part[i]].concat(path), [part[i]].concat(traversed)); } return; } else if (isArray && partType === "function") { for (let i = 0; i < current.length; i++) { if (part(current[i], i)) updatePath(current, [i].concat(path), [i].concat(traversed)); } return; } else if (isArray && partType === "object") { const { from = 0, to = current.length - 1, by = 1 } = part; for (let i = from; i <= to; i += by) { updatePath(current, [i].concat(path), [i].concat(traversed)); } return; } else if (path.length > 1) { updatePath(current[part], path, [part].concat(traversed)); return; } prev = current[part]; traversed = [part].concat(traversed); } let value = path[0]; if (typeof value === "function") { value = value(prev, traversed); if (value === prev) return; } if (part === void 0 && value == void 0) return; value = unwrap(value); if (part === void 0 || isWrappable(prev) && isWrappable(value) && !Array.isArray(value)) { mergeStoreNode(prev, value); } else setProperty(current, part, value); } function createStore(store, options) { const unwrappedStore = unwrap(store || {}); const wrappedStore = wrap$1(unwrappedStore); function setStore(...args) { batch(() => updatePath(unwrappedStore, args)); } return [wrappedStore, setStore]; } const setterTraps = { get(target, property) { if (property === $RAW) return target; const value = target[property]; return isWrappable(value) ? new Proxy(value, setterTraps) : value; }, set(target, property, value) { setProperty(target, property, unwrap(value)); return true; }, deleteProperty(target, property) { setProperty(target, property, void 0); return true; } }; function produce(fn) { return (state) => { if (isWrappable(state)) fn(new Proxy(state, setterTraps)); return state; }; } const storeContext = createContext(); const Provider = storeContext.Provider; function useStore() { const store = useContext(storeContext); if (!store) { throw new Error("Please use it inside Root component"); } return store; } const rootParentActionId = "__ROOT__"; function getActionContext(action, actionsContext) { const rootContext = actionsContext.root; const dynamicContext = actionsContext.dynamic[action.id] || {}; return { rootContext, dynamicContext }; } function checkActionAllowed(action, actionsContext) { if (!action.cond) { return true; } const { rootContext, dynamicContext } = getActionContext(action, actionsContext); const isAllowed = action.cond({ actionId: action.id, rootContext, dynamicContext }); return isAllowed; } function runAction(action, actionsContext, storeMethods) { const { id, run } = action; if (!run) { storeMethods.selectParentAction(id); return; } const { rootContext, dynamicContext } = getActionContext(action, actionsContext); run({ actionId: id, rootContext, dynamicContext }); storeMethods.closePalette(); } function getShortcutHandlersMap(actionsList, actionsContext, storeMethods) { const shortcutMap = {}; actionsList.forEach((action) => { const actionHandler = (event) => { const targetElem = event.target; const shortcutsAttr = targetElem.dataset.cpKbdShortcuts; if (shortcutsAttr === "disabled") { return; } const isAllowed = checkActionAllowed(action, actionsContext); if (!isAllowed) { return; } event.preventDefault(); runAction(action, actionsContext, storeMethods); }; const shortcut2 = action.shortcut; if (shortcut2) { shortcutMap[shortcut2] = actionHandler; } }); return shortcutMap; } function getActiveParentAction(activeParentActionIdList) { const activeId = activeParentActionIdList.at(-1); const isRoot = activeId === rootParentActionId; return { activeId, isRoot }; } function createActionList() { const [state] = useStore(); const actionsList = createMemo(() => { return Object.values(state.actions); }); return actionsList; } function createNestedActionList() { const actionsList = createActionList(); const [state] = useStore(); function nestedActionFilter(action) { const { activeId, isRoot } = getActiveParentAction(state.activeParentActionIdList); const isAllowed = isRoot || action.parentActionId === activeId; return isAllowed; } const nestedActionsList = createMemo(() => { const nestedActionsList2 = actionsList().filter(nestedActionFilter); return nestedActionsList2; }); return nestedActionsList; } function createConditionalActionList() { const [state] = useStore(); const nestedActionsList = createNestedActionList(); function conditionalActionFilter(action) { const isAllowed = checkActionAllowed(action, state.actionsContext); return isAllowed; } const conditionalActionList = createMemo(() => { const conditionalActionList2 = nestedActionsList().filter(conditionalActionFilter); return conditionalActionList2; }); return conditionalActionList; } function createSearchResultList() { const [state] = useStore(); const conditionalActionList = createConditionalActionList(); const fuse = new Fuse(conditionalActionList(), { keys: [ { name: "title", weight: 1 }, { name: "subtitle", weight: 0.7 }, { name: "keywords", weight: 0.5 } ] }); const resultsList = createMemo(() => { if (state.searchText.length === 0) { return conditionalActionList(); } const searchResults = fuse.search(state.searchText); const resultsList2 = searchResults.map((result) => result.item); return resultsList2; }); createEffect(() => { fuse.setCollection(conditionalActionList()); }); return resultsList; } function createKbdShortcuts() { const [state, storeMethods] = useStore(); const { togglePalette } = storeMethods; const actionsList = createActionList(); let unsubscribe = null; onMount(() => { const shortcutMap = getShortcutHandlersMap(actionsList(), state.actionsContext, storeMethods); const commandPaletteHandler = (event) => { event.preventDefault(); togglePalette(); }; unsubscribe = tinykeys(window, __spreadProps(__spreadValues({}, shortcutMap), { "$mod+k": commandPaletteHandler })); }); onCleanup(() => { if (unsubscribe) { unsubscribe(); } }); } const _tmpl$$5 = template(`<div></div>`); const RootInternal = () => { createKbdShortcuts(); return null; }; const Root = (p) => { const initialActions = p.actions || {}; const initialActionsContext = p.actionsContext || {}; const [state, setState] = createStore({ visibility: "closed", searchText: "", activeParentActionIdList: [rootParentActionId], actions: initialActions, actionsContext: { root: initialActionsContext, dynamic: {} } }); const storeMethods = { setSearchText(newValue) { setState("searchText", newValue); }, setActionsContext(actionId, newData) { setState("actionsContext", "dynamic", actionId, newData); }, resetActionsContext(actionId) { setState("actionsContext", "dynamic", produce((dynamicContext) => { delete dynamicContext[actionId]; })); }, openPalette() { setState("visibility", "opened"); }, closePalette() { setState("visibility", "closed"); const hasActiveParent = state.activeParentActionIdList.length > 1; if (hasActiveParent) { storeMethods.setSearchText(""); storeMethods.resetParentAction(); } }, togglePalette() { setState("visibility", (prev) => prev === "opened" ? "closed" : "opened"); }, selectParentAction(parentActionId) { if (parentActionId === rootParentActionId) { return; } setState("activeParentActionIdList", (old) => { return [...old, parentActionId]; }); storeMethods.setSearchText(""); }, revertParentAction() { setState("activeParentActionIdList", (old) => { const { isRoot } = getActiveParentAction(old); if (isRoot) { return old; } const copiedList = [...old]; copiedList.pop(); return copiedList; }); }, resetParentAction() { setState("activeParentActionIdList", [rootParentActionId]); } }; const store = [state, storeMethods]; return createComponent(Provider, { value: store, get children() { const _el$ = _tmpl$$5.cloneNode(true); insert(_el$, createComponent(RootInternal, {}), null); insert(_el$, () => p.children, null); return _el$; } }); }; const Transition = (props) => { let el; let first = true; const [s1, set1] = createSignal(); const [s2, set2] = createSignal(); const resolved = children(() => props.children); const name = props.name || "s"; props = mergeProps({ name, enterActiveClass: name + "-enter-active", enterClass: name + "-enter", enterToClass: name + "-enter-to", exitActiveClass: name + "-exit-active", exitClass: name + "-exit", exitToClass: name + "-exit-to" }, props); const { onBeforeEnter, onEnter, onAfterEnter, onBeforeExit, onExit, onAfterExit } = props; function enterTransition(el2, prev) { if (!first || props.appear) { let endTransition = function() { if (el2) { el2.classList.remove(...enterActiveClasses); el2.classList.remove(...enterToClasses); batch(() => { s1() !== el2 && set1(el2); s2() === el2 && set2(void 0); }); onAfterEnter && onAfterEnter(el2); if (props.mode === "inout") exitTransition(el2, prev); } }; const enterClasses = props.enterClass.split(" "); const enterActiveClasses = props.enterActiveClass.split(" "); const enterToClasses = props.enterToClass.split(" "); onBeforeEnter && onBeforeEnter(el2); el2.classList.add(...enterClasses); el2.classList.add(...enterActiveClasses); requestAnimationFrame(() => { el2.classList.remove(...enterClasses); el2.classList.add(...enterToClasses); onEnter && onEnter(el2, endTransition); if (!onEnter || onEnter.length < 2) { el2.addEventListener("transitionend", endTransition, { once: true }); el2.addEventListener("animationend", endTransition, { once: true }); } }); } prev && !props.mode ? set2(el2) : set1(el2); } function exitTransition(el2, prev) { const exitClasses = props.exitClass.split(" "); const exitActiveClasses = props.exitActiveClass.split(" "); const exitToClasses = props.exitToClass.split(" "); if (!prev.parentNode) return endTransition(); onBeforeExit && onBeforeExit(prev); prev.classList.add(...exitClasses); prev.classList.add(...exitActiveClasses); requestAnimationFrame(() => { prev.classList.remove(...exitClasses); prev.classList.add(...exitToClasses); }); onExit && onExit(prev, endTransition); if (!onExit || onExit.length < 2) { prev.addEventListener("transitionend", endTransition, { once: true }); prev.addEventListener("animationend", endTransition, { once: true }); } function endTransition() { prev.classList.remove(...exitActiveClasses); prev.classList.remove(...exitToClasses); s1() === prev && set1(void 0); onAfterExit && onAfterExit(prev); if (props.mode === "outin") enterTransition(el2, prev); } } createComputed((prev) => { el = resolved(); while (typeof el === "function") el = el(); return untrack(() => { if (el && el !== prev) { if (props.mode !== "outin") enterTransition(el, prev); else if (first) set1(el); } if (prev && prev !== el && props.mode !== "inout") exitTransition(el, prev); first = false; return el; }); }); return [s1, s2]; }; const CommandPalettePortal = (p) => { let portalElem; createRenderEffect(() => { if (portalElem) { return; } const parent = document.body; const newPortalElem = document.createElement("div"); newPortalElem.classList.add("command-palette-portal"); parent.appendChild(newPortalElem); portalElem = newPortalElem; }); onCleanup(() => { if (portalElem) { portalElem.remove(); portalElem = void 0; } }); return createComponent(Portal, { mount: portalElem, get children() { return p.children; } }); }; function getFormattedKey(key) { if (key === "Meta") { return "\u2318"; } if (key === "Control") { return "Ctrl"; } if (key === "Escape") { return "Esc"; } return key; } const getFormattedShortcut = (shortcut2) => { const parsedShortcut = parseKeybinding(shortcut2); const formattedShortcut = parsedShortcut.map((group2) => { const flatGroup = group2.flat(); const formattedGroup = flatGroup.map(getFormattedKey); return formattedGroup; }); return formattedShortcut; }; const kbdShortcut = "_kbdShortcut_v1zud_1"; const kbdGroup = "_kbdGroup_v1zud_6"; const kbdKey = "_kbdKey_v1zud_11"; var styles$4 = { kbdShortcut, kbdGroup, kbdKey }; const _tmpl$$4 = template(`<kbd></kbd>`); const KbdShortcut = (p) => { const [l, others] = splitProps(p, ["shortcut", "class"]); const formattedShortcut = getFormattedShortcut(l.shortcut); const keyClasses = [styles$4.kbdKey, l.class].join(" "); return (() => { const _el$ = _tmpl$$4.cloneNode(true); spread(_el$, others, false, true); insert(_el$, createComponent(For, { each: formattedShortcut, children: (group2) => (() => { const _el$2 = _tmpl$$4.cloneNode(true); insert(_el$2, createComponent(For, { each: group2, children: (key) => (() => { const _el$3 = _tmpl$$4.cloneNode(true); _el$3.className = keyClasses; insert(_el$3, key); return _el$3; })() })); createRenderEffect(() => _el$2.className = styles$4.kbdGroup); return _el$2; })() })); createRenderEffect(() => _el$.className = styles$4.kbdShortcut); return _el$; })(); }; const scrollShape = "_scrollShape_1199m_1"; var styles$3 = { scrollShape }; const _tmpl$$3 = template(`<div></div>`); const ScrollAssist = (p) => { let intervalId = null; function triggerNavigation() { p.onNavigate(); } function startSelecting() { triggerNavigation(); intervalId = setInterval(() => { if (p.status === "running") { triggerNavigation(); } }, 500); } function stopSelecting() { if (intervalId) { clearInterval(intervalId); } intervalId = null; } function handleMouseEnter() { if (p.status === "available") { startSelecting(); } } function handleMouseMove(event) { if (p.status !== "running") { return; } let shouldStop = false; if (p.direction === "up" && event.movementY > 0) { shouldStop = true; } if (p.direction === "down" && event.movementY < 0) { shouldStop = true; } if (shouldStop) { p.onStop(); } } function handleMouseLeave() { p.onStop(); } createEffect(() => { if (p.status === "stopped") { stopSelecting(); } }); return (() => { const _el$ = _tmpl$$3.cloneNode(true); _el$.addEventListener("mouseleave", handleMouseLeave); _el$.$$mousemove = handleMouseMove; _el$.addEventListener("mouseenter", handleMouseEnter); createRenderEffect((_p$) => { const _v$ = styles$3.scrollShape, _v$2 = p.direction, _v$3 = p.status; _v$ !== _p$._v$ && (_el$.className = _p$._v$ = _v$); _v$2 !== _p$._v$2 && setAttribute(_el$, "data-direction", _p$._v$2 = _v$2); _v$3 !== _p$._v$3 && setAttribute(_el$, "data-status", _p$._v$3 = _v$3); return _p$; }, { _v$: void 0, _v$2: void 0, _v$3: void 0 }); return _el$; })(); }; delegateEvents(["mousemove"]); const visuallyHidden = "_visuallyHidden_1rdqz_1"; const stripSpace = "_stripSpace_1rdqz_14"; var utilStyles = { visuallyHidden, stripSpace }; const resultWrapper = "_resultWrapper_m81ar_1"; const resultList = "_resultList_m81ar_7"; const resultItem = "_resultItem_m81ar_11"; const activeItem = "_activeItem_m81ar_21"; const resultTitle = "_resultTitle_m81ar_25"; const resultSubtitle = "_resultSubtitle_m81ar_30"; const resultShortcut = "_resultShortcut_m81ar_37"; var styles$2 = { resultWrapper, resultList, resultItem, activeItem, resultTitle, resultSubtitle, resultShortcut }; const _tmpl$$2 = template(`<p></p>`), _tmpl$2$1 = template(`<li role="option"><div><h4></h4></div><div></div></li>`), _tmpl$3$1 = template(`<div><ul role="listbox"></ul></div>`), _tmpl$4 = template(`<div><h4>Couldn't find any matching actions</h4></div>`); const ResultItem = (p) => { let resultItemElem; let isMoving = false; function isActive() { return p.action.id === p.activeItemId; } function handleMouseMove(action) { if (isMoving) { return; } isMoving = true; p.onActionItemHover(action); } function handleMouseLeave() { isMoving = false; } function handleMouseDown(event) { event.preventDefault(); } createEffect(() => { if (isActive() && resultItemElem) { resultItemElem.scrollIntoView({ behavior: "smooth", block: "nearest" }); } }); return (() => { const _el$ = _tmpl$2$1.cloneNode(true), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$5 = _el$2.nextSibling; _el$.$$mousedown = handleMouseDown; _el$.addEventListener("mouseleave", handleMouseLeave); _el$.$$mousemove = handleMouseMove; _el$.$$mousemoveData = p.action; _el$.$$click = p.onActionItemSelect; _el$.$$clickData = p.action; const _ref$ = resultItemElem; typeof _ref$ === "function" ? _ref$(_el$) : resultItemElem = _el$; insert(_el$3, () => p.action.title); insert(_el$2, createComponent(Show, { get when() { return p.action.subtitle; }, get children() { const _el$4 = _tmpl$$2.cloneNode(true); insert(_el$4, () => p.action.subtitle); createRenderEffect(() => _el$4.className = `${styles$2.resultSubtitle} ${utilStyles.stripSpace}`); return _el$4; } }), null); insert(_el$5, createComponent(Show, { get when() { return p.action.shortcut; }, children: (shortcut2) => createComponent(KbdShortcut, { get ["class"]() { return styles$2.resultShortcut; }, shortcut: shortcut2 }) })); createRenderEffect((_p$) => { const _v$ = `scp-result-item-${p.action.id}`, _v$2 = styles$2.resultItem, _v$3 = { [styles$2.activeItem]: isActive() }, _v$4 = isActive(), _v$5 = `${styles$2.resultTitle} ${utilStyles.stripSpace}`; _v$ !== _p$._v$ && setAttribute(_el$, "id", _p$._v$ = _v$); _v$2 !== _p$._v$2 && (_el$.className = _p$._v$2 = _v$2); _p$._v$3 = classList(_el$, _v$3, _p$._v$3); _v$4 !== _p$._v$4 && setAttribute(_el$, "aria-selected", _p$._v$4 = _v$4); _v$5 !== _p$._v$5 && (_el$3.className = _p$._v$5 = _v$5); return _p$; }, { _v$: void 0, _v$2: void 0, _v$3: void 0, _v$4: void 0, _v$5: void 0 }); return _el$; })(); }; const PanelResult = (p) => { return (() => { const _el$6 = _tmpl$3$1.cloneNode(true), _el$7 = _el$6.firstChild; insert(_el$7, createComponent(For, { get each() { return p.resultsList; }, get fallback() { return (() => { const _el$8 = _tmpl$4.cloneNode(true), _el$9 = _el$8.firstChild; createRenderEffect((_p$) => { const _v$10 = styles$2.resultItem, _v$11 = `${styles$2.resultTitle} ${utilStyles.stripSpace}`; _v$10 !== _p$._v$10 && (_el$8.className = _p$._v$10 = _v$10); _v$11 !== _p$._v$11 && (_el$9.className = _p$._v$11 = _v$11); return _p$; }, { _v$10: void 0, _v$11: void 0 }); return _el$8; })(); }, children: (action) => createComponent(ResultItem, { action, get activeItemId() { return p.activeItemId; }, get onActionItemHover() { return p.onActionItemHover; }, get onActionItemSelect() { return p.onActionItemSelect; } }) })); createRenderEffect((_p$) => { const _v$6 = styles$2.resultWrapper, _v$7 = p.resultListId, _v$8 = p.searchLabelId, _v$9 = `${styles$2.resultList} ${utilStyles.stripSpace}`; _v$6 !== _p$._v$6 && (_el$6.className = _p$._v$6 = _v$6); _v$7 !== _p$._v$7 && setAttribute(_el$7, "id", _p$._v$7 = _v$7); _v$8 !== _p$._v$8 && setAttribute(_el$7, "aria-labelledby", _p$._v$8 = _v$8); _v$9 !== _p$._v$9 && (_el$7.className = _p$._v$9 = _v$9); return _p$; }, { _v$6: void 0, _v$7: void 0, _v$8: void 0, _v$9: void 0 }); return _el$6; })(); }; delegateEvents(["click", "mousemove", "mousedown"]); const footer = "_footer_14oge_1"; const group = "_group_14oge_11"; const shortcut = "_shortcut_14oge_17"; const runShortcut = "_runShortcut_14oge_27"; const icon = "_icon_14oge_31"; const iconArrow = "_iconArrow_14oge_36"; const iconReturn = "_iconReturn_14oge_40"; var styles$1 = { footer, group, shortcut, runShortcut, icon, iconArrow, iconReturn }; const _tmpl$$1 = template(`<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M8 7l4-4m0 0l4 4m-4-4v18"></path></svg>`), _tmpl$2 = template(`<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6"></path></svg>`), _tmpl$3 = template(`<div><div>Navigate with <kbd></kbd><kbd></kbd></div><div>Select using <kbd></kbd></div></div>`); const IconArrow = (p) => { return (() => { const _el$ = _tmpl$$1.cloneNode(true); createRenderEffect((_p$) => { const _v$ = `${styles$1.icon} ${styles$1.iconArrow}`, _v$2 = p.direction || "up"; _v$ !== _p$._v$ && setAttribute(_el$, "class", _p$._v$ = _v$); _v$2 !== _p$._v$2 && setAttribute(_el$, "data-arrow-direction", _p$._v$2 = _v$2); return _p$; }, { _v$: void 0, _v$2: void 0 }); return _el$; })(); }; const IconReturn = () => { return (() => { const _el$2 = _tmpl$2.cloneNode(true); createRenderEffect(() => setAttribute(_el$2, "class", `${styles$1.icon} ${styles$1.iconReturn}`)); return _el$2; })(); }; const PanelFooter = () => { return (() => { const _el$3 = _tmpl$3.cloneNode(true), _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild, _el$7 = _el$5.nextSibling, _el$8 = _el$7.nextSibling, _el$9 = _el$4.nextSibling, _el$10 = _el$9.firstChild, _el$12 = _el$10.nextSibling; insert(_el$7, createComponent(IconArrow, {})); insert(_el$8, createComponent(IconArrow, { direction: "down" })); insert(_el$12, createComponent(IconReturn, {})); createRenderEffect((_p$) => { const _v$3 = styles$1.footer, _v$4 = styles$1.group, _v$5 = styles$1.shortcut, _v$6 = styles$1.shortcut, _v$7 = styles$1.group, _v$8 = `${styles$1.shortcut} ${styles$1.runShortcut}`; _v$3 !== _p$._v$3 && (_el$3.className = _p$._v$3 = _v$3); _v$4 !== _p$._v$4 && (_el$4.className = _p$._v$4 = _v$4); _v$5 !== _p$._v$5 && (_el$7.className = _p$._v$5 = _v$5); _v$6 !== _p$._v$6 && (_el$8.className = _p$._v$6 = _v$6); _v$7 !== _p$._v$7 && (_el$9.className = _p$._v$7 = _v$7); _v$8 !== _p$._v$8 && (_el$12.className = _p$._v$8 = _v$8); return _p$; }, { _v$3: void 0, _v$4: void 0, _v$5: void 0, _v$6: void 0, _v$7: void 0, _v$8: void 0 }); return _el$3; })(); }; const wrapper = "_wrapper_1lhwr_1"; const palette = "_palette_1lhwr_12"; const panel = "_panel_1lhwr_18"; const animEnter = "_animEnter_1lhwr_36"; const animEnterActive = "_animEnterActive_1lhwr_47"; const animExit = "_animExit_1lhwr_52"; const animExitActive = "_animExitActive_1lhwr_56"; const searchForm = "_searchForm_1lhwr_68"; const searchInput = "_searchInput_1lhwr_75"; const closeBtn = "_closeBtn_1lhwr_96"; var styles = { wrapper, palette, panel, animEnter, animEnterActive, animExit, animExitActive, searchForm, searchInput, closeBtn }; const _tmpl$ = template(`<div><div><div role="combobox" aria-haspopup="listbox"><form role="search" novalidate><label>Search for an action and then select one of the option.</label><input type="search" aria-autocomplete="list" autocomplete="off" autocapitalize="off" placeholder="Type a command or search..." data-cp-kbd-shortcuts="disabled"><button type="button"><span>Close the Command Palette</span></button></form></div></div></div>`); const CommandPaletteInternal = () => { const [state, storeMethods] = useStore(); const { closePalette, setSearchText, revertParentAction } = storeMethods; const resultsList = createSearchResultList(); const [activeItemId, setActiveItemId] = createSignal(null); const [userInteraction, setUserInteraction] = createSignal("idle"); const searchLabelId = createUniqueId(); const searchInputId = createUniqueId(); const resultListId = createUniqueId(); let wrapperElem; let searchInputElem; let closeBtnElem; let lastFocusedElem; function triggerRun(action) { runAction(action, state.actionsContext, storeMethods); } function activatePrevItem() { const actionsList = resultsList(); const actionsCount = actionsList.length; const activeActionId = activeItemId(); const currentActionIndex = actionsList.findIndex((action) => action.id === activeActionId); if (currentActionIndex < 0) { return; } const prevActionIndex = (actionsCount + currentActionIndex - 1) % actionsCount; const prevActionId = actionsList[prevActionIndex].id; setActiveItemId(prevActionId); } function activateNextItem() { const actionsList = resultsList(); const actionsCount = actionsList.length; const activeActionId = activeItemId(); const currentActionIndex = actionsList.findIndex((action) => action.id === activeActionId); if (currentActionIndex < 0) { return; } const nextActionIndex = (currentActionIndex + 1) % actionsCount; const nextActionId = actionsList[nextActionIndex].id; setActiveItemId(nextActionId); } function handleWrapperClick() { closePalette(); } function handlePanelClick(event) { event.stopPropagation(); } const handleSearchInput = (event) => { const newValue = event.currentTarget.value; setUserInteraction("search"); setSearchText(newValue); }; function handleActionItemSelect(action) { triggerRun(action); } function handleActionItemHover(action) { setUserInteraction("navigate-mouse"); setActiveItemId(action.id); } function handleKbdEnter(event) { const targetElem = event.target; if (closeBtnElem && closeBtnElem.contains(targetElem)) { return; } event.preventDefault(); const activeActionId = activeItemId(); if (!activeActionId) { return null; } const action = state.actions[activeActionId]; triggerRun(action); } function handleKbdPrev(event) { event.preventDefault(); setUserInteraction("navigate-kbd"); activatePrevItem(); } function handleKbdNext(event) { event.preventDefault(); setUserInteraction("navigate-kbd"); activateNextItem(); } function handleKbdFirst(event) { event.preventDefault(); const actionsList = resultsList(); const firstAction = actionsList[0]; if (firstAction) { setUserInteraction("navigate-kbd"); setActiveItemId(firstAction.id); } } function handleKbdLast(event) { event.preventDefault(); const actionsList = resultsList(); const lastAction = actionsList.at(-1); if (lastAction) { setUserInteraction("navigate-kbd"); setActiveItemId(lastAction.id); } } function handleKbdDelete() { const isSearchEmpty = state.searchText.length <= 0; if (isSearchEmpty) { revertParentAction(); } } function handleScrollAssistPrev() { setUserInteraction("navigate-scroll-assist"); activatePrevItem(); } function handleScrollAssistNext() { setUserInteraction("navigate-scroll-assist"); activateNextItem(); } function handleScrollAssistStop() { setUserInteraction("idle"); } function getScrollAssistStatus() { if (userInteraction() === "navigate-mouse") { return "available";