UNPKG

@zag-js/tree-view

Version:

Core logic for the tree-view widget implemented as a state machine

823 lines (816 loc) 29.3 kB
'use strict'; var anatomy$1 = require('@zag-js/anatomy'); var collection$1 = require('@zag-js/collection'); var domQuery = require('@zag-js/dom-query'); var utils = require('@zag-js/utils'); var core = require('@zag-js/core'); var types = require('@zag-js/types'); // src/tree-view.anatomy.ts var anatomy = anatomy$1.createAnatomy("tree-view").parts( "root", "label", "tree", "item", "itemIndicator", "itemText", "branch", "branchControl", "branchTrigger", "branchContent", "branchText", "branchIndicator", "branchIndentGuide" ); var parts = anatomy.build(); var collection = (options) => { return new collection$1.TreeCollection(options); }; collection.empty = () => { return new collection$1.TreeCollection({ rootNode: { children: [] } }); }; function filePathCollection(paths) { return collection$1.filePathToTree(paths); } // src/tree-view.dom.ts var getRootId = (ctx) => ctx.ids?.root ?? `tree:${ctx.id}:root`; var getLabelId = (ctx) => ctx.ids?.label ?? `tree:${ctx.id}:label`; var getNodeId = (ctx, value) => ctx.ids?.node?.(value) ?? `tree:${ctx.id}:node:${value}`; var getTreeId = (ctx) => ctx.ids?.tree ?? `tree:${ctx.id}:tree`; var focusNode = (ctx, value) => { if (value == null) return; const nodeId = getNodeId(ctx, value); ctx.getById(nodeId)?.focus({ preventScroll: true }); }; // src/tree-view.utils.ts function skipFn(params) { const { prop, context } = params; return function skip({ indexPath }) { const paths = prop("collection").getValuePath(indexPath).slice(0, -1); return paths.some((value) => !context.get("expandedValue").includes(value)); }; } function getVisibleNodes(params) { const { prop } = params; const nodes = []; prop("collection").visit({ skip: skipFn(params), onEnter: (node, indexPath) => { nodes.push({ node, indexPath }); } }); return nodes; } // src/tree-view.connect.ts function connect(service, normalize) { const { context, scope, computed, prop, send } = service; const collection2 = prop("collection"); const expandedValue = Array.from(context.get("expandedValue")); const selectedValue = Array.from(context.get("selectedValue")); const isTypingAhead = computed("isTypingAhead"); const focusedValue = context.get("focusedValue"); function getNodeState(props2) { const { node, indexPath } = props2; const value = collection2.getNodeValue(node); return { value, valuePath: collection2.getValuePath(indexPath), disabled: Boolean(node.disabled), focused: focusedValue == null ? utils.isEqual(indexPath, [0]) : focusedValue === value, selected: selectedValue.includes(value), expanded: expandedValue.includes(value), depth: indexPath.length, isBranch: collection2.isBranchNode(node) }; } return { collection: collection2, expandedValue, selectedValue, expand(value) { if (!value) return send({ type: "EXPANDED.ALL" }); const _expandedValue = utils.uniq(expandedValue.concat(...value)); send({ type: "EXPANDED.SET", value: _expandedValue, src: "expand" }); }, collapse(value) { if (!value) return send({ type: "EXPANDED.SET", value: [], src: "collapseAll" }); const _expandedValue = utils.uniq(utils.remove(expandedValue, ...value)); send({ type: "EXPANDED.SET", value: _expandedValue, src: "collapse" }); }, deselect(value) { if (!value) return send({ type: "SELECTED.SET", value: [], src: "deselectAll" }); const _selectedValue = utils.uniq(utils.remove(selectedValue, ...value)); send({ type: "SELECTED.SET", value: _selectedValue, src: "deselect" }); }, select(value) { if (!value) return send({ type: "SELECTED.ALL" }); const nextValue = []; if (prop("selectionMode") === "single") { if (value.length > 0) nextValue.push(value[value.length - 1]); } else { nextValue.push(...selectedValue, ...value); } send({ type: "SELECTED.SET", value: nextValue, src: "select" }); }, getVisibleNodes() { return getVisibleNodes(service); }, focus(value) { focusNode(scope, value); }, selectParent(value) { const parentNode = collection2.getParentNode(value); if (!parentNode) return; const _selectedValue = utils.add(selectedValue, collection2.getNodeValue(parentNode)); send({ type: "SELECTED.SET", value: _selectedValue, src: "select.parent" }); }, expandParent(value) { const parentNode = collection2.getParentNode(value); if (!parentNode) return; const _expandedValue = utils.add(expandedValue, collection2.getNodeValue(parentNode)); send({ type: "EXPANDED.SET", value: _expandedValue, src: "expand.parent" }); }, setExpandedValue(value) { const _expandedValue = utils.uniq(value); send({ type: "EXPANDED.SET", value: _expandedValue }); }, setSelectedValue(value) { const _selectedValue = utils.uniq(value); send({ type: "SELECTED.SET", value: _selectedValue }); }, getRootProps() { return normalize.element({ ...parts.root.attrs, id: getRootId(scope), dir: prop("dir") }); }, getLabelProps() { return normalize.element({ ...parts.label.attrs, id: getLabelId(scope), dir: prop("dir") }); }, getTreeProps() { return normalize.element({ ...parts.tree.attrs, id: getTreeId(scope), dir: prop("dir"), role: "tree", "aria-label": "Tree View", "aria-labelledby": getLabelId(scope), "aria-multiselectable": prop("selectionMode") === "multiple" || void 0, tabIndex: -1, onKeyDown(event) { if (event.defaultPrevented) return; if (domQuery.isComposingEvent(event)) return; const target = domQuery.getEventTarget(event); if (domQuery.isEditableElement(target)) return; const node = target?.closest("[data-part=branch-control], [data-part=item]"); if (!node) return; const nodeId = node.dataset.value; if (nodeId == null) { console.warn(`[zag-js/tree-view] Node id not found for node`, node); return; } const isBranchNode = node.matches("[data-part=branch-control]"); const keyMap = { ArrowDown(event2) { if (domQuery.isModifierKey(event2)) return; event2.preventDefault(); send({ type: "NODE.ARROW_DOWN", id: nodeId, shiftKey: event2.shiftKey }); }, ArrowUp(event2) { if (domQuery.isModifierKey(event2)) return; event2.preventDefault(); send({ type: "NODE.ARROW_UP", id: nodeId, shiftKey: event2.shiftKey }); }, ArrowLeft(event2) { if (domQuery.isModifierKey(event2) || node.dataset.disabled) return; event2.preventDefault(); send({ type: isBranchNode ? "BRANCH_NODE.ARROW_LEFT" : "NODE.ARROW_LEFT", id: nodeId }); }, ArrowRight(event2) { if (!isBranchNode || node.dataset.disabled) return; event2.preventDefault(); send({ type: "BRANCH_NODE.ARROW_RIGHT", id: nodeId }); }, Home(event2) { if (domQuery.isModifierKey(event2)) return; event2.preventDefault(); send({ type: "NODE.HOME", id: nodeId, shiftKey: event2.shiftKey }); }, End(event2) { if (domQuery.isModifierKey(event2)) return; event2.preventDefault(); send({ type: "NODE.END", id: nodeId, shiftKey: event2.shiftKey }); }, Space(event2) { if (node.dataset.disabled) return; if (isTypingAhead) { send({ type: "TREE.TYPEAHEAD", key: event2.key }); } else { keyMap.Enter?.(event2); } }, Enter(event2) { if (node.dataset.disabled) return; const isLink = target?.closest("a[href]"); if (!isLink) event2.preventDefault(); send({ type: isBranchNode ? "BRANCH_NODE.CLICK" : "NODE.CLICK", id: nodeId, src: "keyboard" }); }, "*"(event2) { if (node.dataset.disabled) return; event2.preventDefault(); send({ type: "SIBLINGS.EXPAND", id: nodeId }); }, a(event2) { if (!event2.metaKey || node.dataset.disabled) return; event2.preventDefault(); send({ type: "SELECTED.ALL", moveFocus: true }); } }; const key = domQuery.getEventKey(event, { dir: prop("dir") }); const exec = keyMap[key]; if (exec) { exec(event); return; } if (!isTypingAhead) return; const isValidTypeahead = event.key.length === 1 && !domQuery.isModifierKey(event); if (!isValidTypeahead) return; send({ type: "TREE.TYPEAHEAD", key: event.key, id: nodeId }); event.preventDefault(); } }); }, getNodeState, getItemProps(props2) { const itemState = getNodeState(props2); return normalize.element({ ...parts.item.attrs, id: getNodeId(scope, itemState.value), dir: prop("dir"), "data-ownedby": getTreeId(scope), "data-path": props2.indexPath.join("/"), "data-value": itemState.value, tabIndex: itemState.focused ? 0 : -1, "data-focus": domQuery.dataAttr(itemState.focused), role: "treeitem", "aria-current": itemState.selected ? "true" : void 0, "aria-selected": itemState.disabled ? void 0 : itemState.selected, "data-selected": domQuery.dataAttr(itemState.selected), "aria-disabled": itemState.disabled, "data-disabled": domQuery.dataAttr(itemState.disabled), "aria-level": itemState.depth, "data-depth": itemState.depth, style: { "--depth": itemState.depth }, onFocus(event) { event.stopPropagation(); send({ type: "NODE.FOCUS", id: itemState.value }); }, onClick(event) { if (itemState.disabled) return; const isMetaKey = event.metaKey || event.ctrlKey; send({ type: "NODE.CLICK", id: itemState.value, shiftKey: event.shiftKey, ctrlKey: isMetaKey }); event.stopPropagation(); const isLink = event.currentTarget.matches("a[href]"); if (!isLink) event.preventDefault(); } }); }, getItemTextProps(props2) { const itemState = getNodeState(props2); return normalize.element({ ...parts.itemText.attrs, "data-disabled": domQuery.dataAttr(itemState.disabled), "data-selected": domQuery.dataAttr(itemState.selected), "data-focus": domQuery.dataAttr(itemState.focused) }); }, getItemIndicatorProps(props2) { const itemState = getNodeState(props2); return normalize.element({ ...parts.itemIndicator.attrs, "aria-hidden": true, "data-disabled": domQuery.dataAttr(itemState.disabled), "data-selected": domQuery.dataAttr(itemState.selected), "data-focus": domQuery.dataAttr(itemState.focused), hidden: !itemState.selected }); }, getBranchProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branch.attrs, "data-depth": nodeState.depth, dir: prop("dir"), "data-branch": nodeState.value, role: "treeitem", "data-ownedby": getTreeId(scope), "data-value": nodeState.value, "aria-level": nodeState.depth, "aria-selected": nodeState.disabled ? void 0 : nodeState.selected, "data-path": props2.indexPath.join("/"), "data-selected": domQuery.dataAttr(nodeState.selected), "aria-expanded": nodeState.expanded, "data-state": nodeState.expanded ? "open" : "closed", "aria-disabled": nodeState.disabled, "data-disabled": domQuery.dataAttr(nodeState.disabled), style: { "--depth": nodeState.depth } }); }, getBranchIndicatorProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branchIndicator.attrs, "aria-hidden": true, "data-state": nodeState.expanded ? "open" : "closed", "data-disabled": domQuery.dataAttr(nodeState.disabled), "data-selected": domQuery.dataAttr(nodeState.selected), "data-focus": domQuery.dataAttr(nodeState.focused) }); }, getBranchTriggerProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branchTrigger.attrs, role: "button", dir: prop("dir"), "data-disabled": domQuery.dataAttr(nodeState.disabled), "data-state": nodeState.expanded ? "open" : "closed", "data-value": nodeState.value, onClick(event) { if (nodeState.disabled) return; send({ type: "BRANCH_TOGGLE.CLICK", id: nodeState.value }); event.stopPropagation(); } }); }, getBranchControlProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branchControl.attrs, role: "button", id: getNodeId(scope, nodeState.value), dir: prop("dir"), tabIndex: nodeState.focused ? 0 : -1, "data-path": props2.indexPath.join("/"), "data-state": nodeState.expanded ? "open" : "closed", "data-disabled": domQuery.dataAttr(nodeState.disabled), "data-selected": domQuery.dataAttr(nodeState.selected), "data-focus": domQuery.dataAttr(nodeState.focused), "data-value": nodeState.value, "data-depth": nodeState.depth, onFocus(event) { send({ type: "NODE.FOCUS", id: nodeState.value }); event.stopPropagation(); }, onClick(event) { if (nodeState.disabled) return; const isMetaKey = event.metaKey || event.ctrlKey; send({ type: "BRANCH_NODE.CLICK", id: nodeState.value, shiftKey: event.shiftKey, ctrlKey: isMetaKey }); event.stopPropagation(); } }); }, getBranchTextProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branchText.attrs, dir: prop("dir"), "data-disabled": domQuery.dataAttr(nodeState.disabled), "data-state": nodeState.expanded ? "open" : "closed" }); }, getBranchContentProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branchContent.attrs, role: "group", dir: prop("dir"), "data-state": nodeState.expanded ? "open" : "closed", "data-depth": nodeState.depth, "data-path": props2.indexPath.join("/"), "data-value": nodeState.value, hidden: !nodeState.expanded }); }, getBranchIndentGuideProps(props2) { const nodeState = getNodeState(props2); return normalize.element({ ...parts.branchIndentGuide.attrs, "data-depth": nodeState.depth }); } }; } var { and } = core.createGuards(); var machine = core.createMachine({ props({ props: props2 }) { return { selectionMode: "single", collection: collection.empty(), typeahead: true, expandOnClick: true, defaultExpandedValue: [], defaultSelectedValue: [], ...props2 }; }, initialState() { return "idle"; }, context({ prop, bindable, getContext }) { return { expandedValue: bindable(() => ({ defaultValue: prop("defaultExpandedValue"), value: prop("expandedValue"), isEqual: utils.isEqual, onChange(value) { const ctx = getContext(); const focusedValue = ctx.get("focusedValue"); prop("onExpandedChange")?.({ expandedValue: value, focusedValue }); } })), selectedValue: bindable(() => ({ defaultValue: prop("defaultSelectedValue"), value: prop("selectedValue"), isEqual: utils.isEqual, onChange(value) { const ctx = getContext(); const focusedValue = ctx.get("focusedValue"); prop("onSelectionChange")?.({ selectedValue: value, focusedValue }); } })), focusedValue: bindable(() => ({ defaultValue: prop("focusedValue"), onChange(value) { prop("onFocusChange")?.({ focusedValue: value }); } })) }; }, refs() { return { typeaheadState: { ...domQuery.getByTypeahead.defaultOptions } }; }, computed: { isMultipleSelection: ({ prop }) => prop("selectionMode") === "multiple", isTypingAhead: ({ refs }) => refs.get("typeaheadState").keysSoFar.length > 0 }, on: { "EXPANDED.SET": { actions: ["setExpanded"] }, "SELECTED.SET": { actions: ["setSelected"] }, "SELECTED.ALL": [ { guard: and("isMultipleSelection", "moveFocus"), actions: ["selectAllNodes", "focusTreeLastNode"] }, { guard: "isMultipleSelection", actions: ["selectAllNodes"] } ], "EXPANDED.ALL": { actions: ["expandAllBranches"] } }, states: { idle: { on: { "NODE.FOCUS": { actions: ["setFocusedNode"] }, "NODE.ARROW_DOWN": [ { guard: and("isShiftKey", "isMultipleSelection"), actions: ["focusTreeNextNode", "extendSelectionToNextNode"] }, { actions: ["focusTreeNextNode"] } ], "NODE.ARROW_UP": [ { guard: and("isShiftKey", "isMultipleSelection"), actions: ["focusTreePrevNode", "extendSelectionToPrevNode"] }, { actions: ["focusTreePrevNode"] } ], "NODE.ARROW_LEFT": { actions: ["focusBranchNode"] }, "BRANCH_NODE.ARROW_LEFT": [ { guard: "isBranchExpanded", actions: ["collapseBranch"] }, { actions: ["focusBranchNode"] } ], "BRANCH_NODE.ARROW_RIGHT": [ { guard: and("isBranchFocused", "isBranchExpanded"), actions: ["focusBranchFirstNode"] }, { actions: ["expandBranch"] } ], "SIBLINGS.EXPAND": { actions: ["expandSiblingBranches"] }, "NODE.HOME": [ { guard: and("isShiftKey", "isMultipleSelection"), actions: ["extendSelectionToFirstNode", "focusTreeFirstNode"] }, { actions: ["focusTreeFirstNode"] } ], "NODE.END": [ { guard: and("isShiftKey", "isMultipleSelection"), actions: ["extendSelectionToLastNode", "focusTreeLastNode"] }, { actions: ["focusTreeLastNode"] } ], "NODE.CLICK": [ { guard: and("isCtrlKey", "isMultipleSelection"), actions: ["toggleNodeSelection"] }, { guard: and("isShiftKey", "isMultipleSelection"), actions: ["extendSelectionToNode"] }, { actions: ["selectNode"] } ], "BRANCH_NODE.CLICK": [ { guard: and("isCtrlKey", "isMultipleSelection"), actions: ["toggleNodeSelection"] }, { guard: and("isShiftKey", "isMultipleSelection"), actions: ["extendSelectionToNode"] }, { guard: "openOnClick", actions: ["selectNode", "toggleBranchNode"] }, { actions: ["selectNode"] } ], "BRANCH_TOGGLE.CLICK": { actions: ["toggleBranchNode"] }, "TREE.TYPEAHEAD": { actions: ["focusMatchedNode"] } } } }, implementations: { guards: { isBranchFocused: ({ context, event }) => context.get("focusedValue") === event.id, isBranchExpanded: ({ context, event }) => context.get("expandedValue").includes(event.id), isShiftKey: ({ event }) => event.shiftKey, isCtrlKey: ({ event }) => event.ctrlKey, hasSelectedItems: ({ context }) => context.get("selectedValue").length > 0, isMultipleSelection: ({ prop }) => prop("selectionMode") === "multiple", moveFocus: ({ event }) => !!event.moveFocus, openOnClick: ({ prop }) => !!prop("expandOnClick") }, actions: { selectNode({ context, event }) { context.set("selectedValue", [event.id]); }, setFocusedNode({ context, event }) { context.set("focusedValue", event.id); }, clearFocusedNode({ context }) { context.set("focusedValue", null); }, clearSelectedItem({ context }) { context.set("selectedValue", []); }, toggleBranchNode({ context, event }) { context.set("expandedValue", (prev) => utils.addOrRemove(prev, event.id)); }, expandBranch({ context, event }) { context.set("expandedValue", (prev) => utils.add(prev, event.id)); }, collapseBranch({ context, event }) { context.set("expandedValue", (prev) => utils.remove(prev, event.id)); }, setExpanded({ context, event }) { context.set("expandedValue", event.value); }, setSelected({ context, event }) { context.set("selectedValue", event.value); }, focusTreeFirstNode({ prop, scope }) { const collection2 = prop("collection"); const firstNode = collection2.getFirstNode(); const firstValue = collection2.getNodeValue(firstNode); focusNode(scope, firstValue); }, focusTreeLastNode({ prop, scope }) { const collection2 = prop("collection"); const lastNode = collection2.getLastNode(); const lastValue = collection2.getNodeValue(lastNode); focusNode(scope, lastValue); }, focusBranchFirstNode({ event, prop, scope }) { const collection2 = prop("collection"); const branchNode = collection2.findNode(event.id); const firstNode = collection2.getFirstNode(branchNode); const firstValue = collection2.getNodeValue(firstNode); focusNode(scope, firstValue); }, focusTreeNextNode(params) { const { event, prop, scope } = params; const collection2 = prop("collection"); const nextNode = collection2.getNextNode(event.id, { skip: skipFn(params) }); if (!nextNode) return; const nextValue = collection2.getNodeValue(nextNode); focusNode(scope, nextValue); }, focusTreePrevNode(params) { const { event, prop, scope } = params; const collection2 = prop("collection"); const prevNode = collection2.getPreviousNode(event.id, { skip: skipFn(params) }); if (!prevNode) return; const prevValue = collection2.getNodeValue(prevNode); focusNode(scope, prevValue); }, focusBranchNode({ event, prop, scope }) { const collection2 = prop("collection"); const parentNode = collection2.getParentNode(event.id); const parentValue = parentNode ? collection2.getNodeValue(parentNode) : void 0; focusNode(scope, parentValue); }, selectAllNodes({ context, prop }) { context.set("selectedValue", prop("collection").getValues()); }, focusMatchedNode(params) { const { context, prop, refs, event, scope } = params; const nodes = getVisibleNodes(params); const elements = nodes.map(({ node: node2 }) => ({ textContent: prop("collection").stringifyNode(node2), id: prop("collection").getNodeValue(node2) })); const node = domQuery.getByTypeahead(elements, { state: refs.get("typeaheadState"), activeId: context.get("focusedValue"), key: event.key }); focusNode(scope, node?.id); }, toggleNodeSelection({ context, event }) { const selectedValue = utils.addOrRemove(context.get("selectedValue"), event.id); context.set("selectedValue", selectedValue); }, expandAllBranches({ context, prop }) { const nextValue = prop("collection").getBranchValues(); context.set("expandedValue", nextValue); }, expandSiblingBranches({ context, event, prop }) { const collection2 = prop("collection"); const indexPath = collection2.getIndexPath(event.id); if (!indexPath) return; const nodes = collection2.getSiblingNodes(indexPath); const values = nodes.map((node) => collection2.getNodeValue(node)); context.set("expandedValue", utils.uniq(values)); }, extendSelectionToNode(params) { const { context, event, prop } = params; const collection2 = prop("collection"); const anchorValue = utils.first(context.get("selectedValue")) || collection2.getNodeValue(collection2.getFirstNode()); const targetValue = event.id; let values = [anchorValue, targetValue]; let hits = 0; const visibleNodes = getVisibleNodes(params); visibleNodes.forEach(({ node }) => { const nodeValue = collection2.getNodeValue(node); if (hits === 1) values.push(nodeValue); if (nodeValue === anchorValue || nodeValue === targetValue) hits++; }); context.set("selectedValue", utils.uniq(values)); }, extendSelectionToNextNode(params) { const { context, event, prop } = params; const collection2 = prop("collection"); const nextNode = collection2.getNextNode(event.id, { skip: skipFn(params) }); if (!nextNode) return; const values = new Set(context.get("selectedValue")); const nextValue = collection2.getNodeValue(nextNode); if (nextValue == null) return; if (values.has(event.id) && values.has(nextValue)) { values.delete(event.id); } else if (!values.has(nextValue)) { values.add(nextValue); } context.set("selectedValue", Array.from(values)); }, extendSelectionToPrevNode(params) { const { context, event, prop } = params; const collection2 = prop("collection"); const prevNode = collection2.getPreviousNode(event.id, { skip: skipFn(params) }); if (!prevNode) return; const values = new Set(context.get("selectedValue")); const prevValue = collection2.getNodeValue(prevNode); if (prevValue == null) return; if (values.has(event.id) && values.has(prevValue)) { values.delete(event.id); } else if (!values.has(prevValue)) { values.add(prevValue); } context.set("selectedValue", Array.from(values)); }, extendSelectionToFirstNode(params) { const { context, prop } = params; const collection2 = prop("collection"); const currentSelection = utils.first(context.get("selectedValue")); const values = []; collection2.visit({ skip: skipFn(params), onEnter: (node) => { const nodeValue = collection2.getNodeValue(node); values.push(nodeValue); if (nodeValue === currentSelection) { return "stop"; } } }); context.set("selectedValue", values); }, extendSelectionToLastNode(params) { const { context, prop } = params; const collection2 = prop("collection"); const currentSelection = utils.first(context.get("selectedValue")); const values = []; let current = false; collection2.visit({ skip: skipFn(params), onEnter: (node) => { const nodeValue = collection2.getNodeValue(node); if (nodeValue === currentSelection) current = true; if (current) values.push(nodeValue); } }); context.set("selectedValue", values); } } } }); var props = types.createProps()([ "ids", "collection", "dir", "expandedValue", "expandOnClick", "focusedValue", "getRootNode", "id", "onExpandedChange", "onFocusChange", "onSelectionChange", "selectedValue", "selectionMode", "typeahead", "defaultExpandedValue", "defaultSelectedValue" ]); var splitProps = utils.createSplitProps(props); var itemProps = types.createProps()(["node", "indexPath"]); var splitItemProps = utils.createSplitProps(itemProps); exports.anatomy = anatomy; exports.collection = collection; exports.connect = connect; exports.filePathCollection = filePathCollection; exports.itemProps = itemProps; exports.machine = machine; exports.props = props; exports.splitItemProps = splitItemProps; exports.splitProps = splitProps;