UNPKG

xdesign-vue-next

Version:

XDesign Component for vue-next

1 lines 8.35 kB
{"version":3,"file":"tnode.mjs","sources":["../../src/hooks/tnode.ts"],"sourcesContent":["import { h, getCurrentInstance, ComponentInternalInstance, VNode } from 'vue';\nimport isFunction from 'lodash/isFunction';\nimport camelCase from 'lodash/camelCase';\nimport kebabCase from 'lodash/kebabCase';\nimport { getDefaultNode, getParams, OptionsType, JSXRenderContext, getSlotFirst } from '../utils/render-tnode';\n\n// Compatibility handling for slot names, supporting both camelCase and kebab-case naming conventions. Example: value-display and valueDisplay\nfunction handleSlots(instance: ComponentInternalInstance, name: string, params: Record<string, any>) {\n // 2023-08 new Function triggers security issues in certain usage scenarios (Chrome extensions, Electron, etc.)\n // // Each slot needs its own h function to avoid injecting params from different slots\n // const finalParams = new Function('return ' + h.toString())();\n // if (params) {\n // Object.assign(finalParams, params);\n // }\n\n // Check if there is a camelCase-named slot (filter out comment nodes)\n let node = instance.slots[camelCase(name)]?.(params);\n if (node && node.filter((t) => t.type.toString() !== 'Symbol(v-cmt)').length) return node;\n // Check if there is a kebab-case-named slot\n node = instance.slots[kebabCase(name)]?.(params);\n if (node && node.filter((t) => t.type.toString() !== 'Symbol(v-cmt)').length) return node;\n return null;\n}\n\n/**\n * Check if a node is an empty node, filtering out comment nodes. Comment nodes are also considered empty nodes.\n */\nfunction isEmptyNode(node: any) {\n if ([undefined, null, ''].includes(node)) return true;\n const innerNodes = node instanceof Array ? node : [node];\n const r = innerNodes.filter((node) => node?.type?.toString() !== 'Symbol(Comment)');\n return !r.length;\n}\n\n/**\n * Render a TNode using JSX syntax, handling both props and slots. It can also handle the case where the default value is true, in which case the default node is rendered.\n * Priority: Props > Slots\n * If the prop value is true, the slot is rendered. If there is no slot available, the defaultNode is rendered.\n * @example const renderTNodeJSX = useTNodeJSX()\n * @return () => {}\n * @param name The name of the slot or prop\n * @param options The value can be either the default node to render or a collection of the default node and its parameters\n * @example renderTNodeJSX('closeBtn') // Priority: props function > slot\n * @example renderTNodeJSX('closeBtn', <close-icon />) // Renders <close-icon /> when the prop value is true\n * @example renderTNodeJSX('closeBtn', { defaultNode: <close-icon />, params }) // Renders the default node <close-icon /> with the specified parameters\n */\nexport const useTNodeJSX = () => {\n const instance = getCurrentInstance();\n return function (name: string, options?: OptionsType) {\n // Assemble params and defaultNode\n const params = getParams(options);\n const defaultNode = getDefaultNode(options);\n const slotFirst = getSlotFirst(options);\n\n // Handle props type of Node\n let propsNode;\n if (Object.keys(instance.props).includes(name)) {\n propsNode = instance.props[name];\n }\n\n // Uncomment the following lines to enable silent logging and warn users about using both slots and props for the same name\n // const isSilent = Boolean(isObject(options) && 'silent' in options && options.silent);\n // if (instance.slots[name] && propsNode && propsNode !== true && !isSilent) {\n // log.warn('', `Both slots.${name} and props.${name} exist, props.${name} is preferred`);\n // }\n\n // Do not render if propsNode is false\n if (propsNode === false) return;\n if (propsNode === true) {\n return handleSlots(instance, name, params) || defaultNode;\n }\n\n // Handle props and slots with the same name, prioritize props\n if (isFunction(propsNode)) return propsNode(h, params);\n const isPropsEmpty = [undefined, params, ''].includes(propsNode);\n if ((isPropsEmpty || slotFirst) && (instance.slots[camelCase(name)] || instance.slots[kebabCase(name)])) {\n return handleSlots(instance, name, params);\n }\n return propsNode;\n };\n};\n\n/**\n * In the setup function, handle TNode, props, and slots using JSX syntax. The difference from renderTNodeJSX is that it renders the default node when the prop value is undefined.\n * @example const renderTNodeJSXDefault = useTNodeDefault()\n * @return () => {}\n * @param name The name of the slot or prop\n * @example renderTNodeJSXDefault('closeBtn')\n * @example renderTNodeJSXDefault('closeBtn', <close-icon />) // Renders <close-icon /> when 'closeBtn' is empty\n * @example renderTNodeJSXDefault('closeBtn', { defaultNode: <close-icon />, params }) // Renders the default node <close-icon /> with the specified parameters when 'closeBtn' is empty\n */\nexport const useTNodeDefault = () => {\n const renderTNodeJSX = useTNodeJSX();\n return function (name: string, options?: VNode | JSXRenderContext) {\n const defaultNode = getDefaultNode(options);\n return renderTNodeJSX(name, options) || defaultNode;\n };\n};\n\n/**\n * In the setup function, used to handle TNode rendering for the same name.\n * @example const renderContent = useContent()\n * @return () => {}\n * @param name1 The first name, higher priority than name2\n * @param name2 The second name\n * @param defaultNode The default node to render: when both name1 and name2 are empty, the default content will be rendered\n * @example renderContent('default', 'content')\n * @example renderContent('default', 'content', 'I am the default content')\n * @example renderContent('default', 'content', { defaultNode: 'I am the default content', params })\n */\nexport const useContent = () => {\n const renderTNodeJSX = useTNodeJSX();\n return function (name1: string, name2: string, options?: VNode | JSXRenderContext) {\n // Assemble params and defaultNode\n const params = getParams(options);\n const defaultNode = getDefaultNode(options);\n\n const toParams = params ? { params } : undefined;\n\n const node1 = renderTNodeJSX(name1, toParams);\n const node2 = renderTNodeJSX(name2, toParams);\n\n const res = isEmptyNode(node1) ? node2 : node1;\n return isEmptyNode(res) ? defaultNode : res;\n };\n};"],"names":["propsNode","params"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,SAAA,WAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA;AAAqG,EAAA,IAAA,qBAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,gBAAA,CAAA;;AAU/F,EAAA,IAAA,IAAA,IAAA,IAAA,CAAA,MAAA,CAAA,UAAA,CAAA,EAAA;;AAAgE,GAAA,CAAA,CAAA,MAAA,EAAA,OAAA,IAAA,CAAA;;AAGhE,EAAA,IAAA,IAAA,IAAA,IAAA,CAAA,MAAA,CAAA,UAAA,CAAA,EAAA;;AAAgE,GAAA,CAAA,CAAA,MAAA,EAAA,OAAA,IAAA,CAAA;AAC7D,EAAA,OAAA,IAAA,CAAA;AACT,CAAA;AAKA,SAAA,WAAA,CAAA,IAAA,EAAA;AACE,EAAA,IAAA,CAAA,KAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,CAAA,QAAA,CAAA,IAAA,CAAA,EAAA,OAAA,IAAA,CAAA;;AAEM,EAAA,IAAA,CAAA,GAAA,UAAA,CAAA,MAAA,CAAA,UAAA,KAAA,EAAA;;;;;AAER,CAAA;AAcO,IAAA,WAAA,GAAA,SAAA,WAAA,GAAA;AACL,EAAA,IAAA,QAAA,GAAA,kBAAA,EAAA,CAAA;AACO,EAAA,OAAA,UAAA,IAAA,EAAA,OAAA,EAAA;AAEC,IAAA,IAAA,MAAA,GAAA,SAAA,CAAA,OAAA,CAAA,CAAA;AACA,IAAA,IAAA,WAAA,GAAA,cAAA,CAAA,OAAA,CAAA,CAAA;AACA,IAAA,IAAA,SAAA,GAAA,YAAA,CAAA,OAAA,CAAA,CAAA;AAGF,IAAA,IAAA,SAAA,CAAA;AACJ,IAAA,IAAA,MAAA,CAAA,IAAA,CAAA,QAAA,CAAA,KAAA,CAAA,CAAA,QAAA,CAAA,IAAA,CAAA,EAAA;AACEA,MAAAA,SAAAA,GAAAA,QAAAA,CAAAA,KAAAA,CAAAA,IAAAA,CAAAA,CAAAA;AACF,KAAA;;;;AAYA,KAAA;;AAIA,IAAA,IAAA,YAAA,GAAA,CAAA,KAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,CAAA,QAAA,CAAA,SAAA,CAAA,CAAA;;AAES,MAAA,OAAA,WAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,CAAA,CAAA;AACT,KAAA;AACO,IAAA,OAAA,SAAA,CAAA;;AAEX,EAAA;AAWO,IAAA,eAAA,GAAA,SAAA,eAAA,GAAA;AACL,EAAA,IAAA,cAAA,GAAA,WAAA,EAAA,CAAA;AACO,EAAA,OAAA,UAAA,IAAA,EAAA,OAAA,EAAA;AACC,IAAA,IAAA,WAAA,GAAA,cAAA,CAAA,OAAA,CAAA,CAAA;AACC,IAAA,OAAA,cAAA,CAAA,IAAA,EAAA,OAAA,CAAA,IAAA,WAAA,CAAA;;AAEX,EAAA;AAaO,IAAA,UAAA,GAAA,SAAA,UAAA,GAAA;AACL,EAAA,IAAA,cAAA,GAAA,WAAA,EAAA,CAAA;AACO,EAAA,OAAA,UAAA,KAAA,EAAA,KAAA,EAAA,OAAA,EAAA;AAEC,IAAA,IAAA,MAAA,GAAA,SAAA,CAAA,OAAA,CAAA,CAAA;AACA,IAAA,IAAA,WAAA,GAAA,cAAA,CAAA,OAAA,CAAA,CAAA;;AAEsBC,MAAAA,MAAAA,EAAAA,MAAAA;;AAEtB,IAAA,IAAA,KAAA,GAAA,cAAA,CAAA,KAAA,EAAA,QAAA,CAAA,CAAA;AACA,IAAA,IAAA,KAAA,GAAA,cAAA,CAAA,KAAA,EAAA,QAAA,CAAA,CAAA;;AAGC,IAAA,OAAA,WAAA,CAAA,GAAA,CAAA,GAAA,WAAA,GAAA,GAAA,CAAA;;AAEX;;;;"}