@xihan-ui/vue 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/dist/components/carousel/carousel.d.ts +7 -1
  3. package/dist/components/carousel/carousel.d.ts.map +1 -1
  4. package/dist/components/carousel/carousel.js +1 -0
  5. package/dist/components/carousel/carousel.js.map +1 -1
  6. package/dist/components/cartesian-chart/cartesian-chart.d.ts.map +1 -1
  7. package/dist/components/cartesian-chart/cartesian-chart.js +2 -2
  8. package/dist/components/cartesian-chart/cartesian-chart.js.map +1 -1
  9. package/dist/components/cascader/cascader.js +2 -1
  10. package/dist/components/cascader/cascader.js.map +1 -1
  11. package/dist/components/citation/citation.d.ts.map +1 -1
  12. package/dist/components/citation/citation.js +8 -6
  13. package/dist/components/citation/citation.js.map +1 -1
  14. package/dist/components/color-picker/color-picker.js +2 -1
  15. package/dist/components/color-picker/color-picker.js.map +1 -1
  16. package/dist/components/combobox/combobox.js +3 -3
  17. package/dist/components/combobox/combobox.js.map +1 -1
  18. package/dist/components/context-menu/context-menu.js +2 -1
  19. package/dist/components/context-menu/context-menu.js.map +1 -1
  20. package/dist/components/date-picker/date-picker.d.ts.map +1 -1
  21. package/dist/components/date-picker/date-picker.js +1 -0
  22. package/dist/components/date-picker/date-picker.js.map +1 -1
  23. package/dist/components/date-range-picker/date-range-picker.d.ts.map +1 -1
  24. package/dist/components/date-range-picker/date-range-picker.js +1 -0
  25. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  26. package/dist/components/dialog/dialog.d.ts +11 -0
  27. package/dist/components/dialog/dialog.d.ts.map +1 -1
  28. package/dist/components/dialog/dialog.js +14 -4
  29. package/dist/components/dialog/dialog.js.map +1 -1
  30. package/dist/components/drawer/drawer.d.ts +11 -0
  31. package/dist/components/drawer/drawer.d.ts.map +1 -1
  32. package/dist/components/drawer/drawer.js +14 -4
  33. package/dist/components/drawer/drawer.js.map +1 -1
  34. package/dist/components/floating-panel/floating-panel.d.ts +2 -2
  35. package/dist/components/floating-panel/floating-panel.js +4 -1
  36. package/dist/components/floating-panel/floating-panel.js.map +1 -1
  37. package/dist/components/form/form.d.ts +8 -0
  38. package/dist/components/form/form.d.ts.map +1 -1
  39. package/dist/components/form/form.js +4 -1
  40. package/dist/components/form/form.js.map +1 -1
  41. package/dist/components/funnel-chart/funnel-chart.d.ts.map +1 -1
  42. package/dist/components/funnel-chart/funnel-chart.js +2 -2
  43. package/dist/components/funnel-chart/funnel-chart.js.map +1 -1
  44. package/dist/components/graph-chart/graph-chart.d.ts.map +1 -1
  45. package/dist/components/graph-chart/graph-chart.js +2 -2
  46. package/dist/components/graph-chart/graph-chart.js.map +1 -1
  47. package/dist/components/hierarchy-chart/hierarchy-chart.d.ts.map +1 -1
  48. package/dist/components/hierarchy-chart/hierarchy-chart.js +2 -2
  49. package/dist/components/hierarchy-chart/hierarchy-chart.js.map +1 -1
  50. package/dist/components/hover-card/hover-card.js +2 -1
  51. package/dist/components/hover-card/hover-card.js.map +1 -1
  52. package/dist/components/image-viewer/image-viewer.d.ts +7 -1
  53. package/dist/components/image-viewer/image-viewer.d.ts.map +1 -1
  54. package/dist/components/image-viewer/image-viewer.js +1 -0
  55. package/dist/components/image-viewer/image-viewer.js.map +1 -1
  56. package/dist/components/markdown-stream/markdown-stream.d.ts +1 -1
  57. package/dist/components/mention/mention.d.ts +1 -1
  58. package/dist/components/mention/mention.js +5 -4
  59. package/dist/components/mention/mention.js.map +1 -1
  60. package/dist/components/menu/menu.js +2 -1
  61. package/dist/components/menu/menu.js.map +1 -1
  62. package/dist/components/menubar/context.d.ts.map +1 -1
  63. package/dist/components/menubar/context.js.map +1 -1
  64. package/dist/components/menubar/menubar.d.ts.map +1 -1
  65. package/dist/components/menubar/menubar.js +16 -2
  66. package/dist/components/menubar/menubar.js.map +1 -1
  67. package/dist/components/pagination/pagination.js +4 -2
  68. package/dist/components/pagination/pagination.js.map +1 -1
  69. package/dist/components/pie-chart/pie-chart.d.ts.map +1 -1
  70. package/dist/components/pie-chart/pie-chart.js +2 -2
  71. package/dist/components/pie-chart/pie-chart.js.map +1 -1
  72. package/dist/components/popconfirm/popconfirm.js +2 -1
  73. package/dist/components/popconfirm/popconfirm.js.map +1 -1
  74. package/dist/components/popover/popover.js +2 -1
  75. package/dist/components/popover/popover.js.map +1 -1
  76. package/dist/components/radar-chart/radar-chart.d.ts.map +1 -1
  77. package/dist/components/radar-chart/radar-chart.js +2 -2
  78. package/dist/components/radar-chart/radar-chart.js.map +1 -1
  79. package/dist/components/reasoning/reasoning.d.ts +1 -1
  80. package/dist/components/sankey-chart/sankey-chart.d.ts.map +1 -1
  81. package/dist/components/sankey-chart/sankey-chart.js +2 -2
  82. package/dist/components/sankey-chart/sankey-chart.js.map +1 -1
  83. package/dist/components/select/select.d.ts +11 -0
  84. package/dist/components/select/select.d.ts.map +1 -1
  85. package/dist/components/select/select.js +12 -3
  86. package/dist/components/select/select.js.map +1 -1
  87. package/dist/components/side-nav/side-nav.d.ts.map +1 -1
  88. package/dist/components/side-nav/side-nav.js +8 -2
  89. package/dist/components/side-nav/side-nav.js.map +1 -1
  90. package/dist/components/sortable/sortable.d.ts +1 -1
  91. package/dist/components/table/table.d.ts +2 -2
  92. package/dist/components/table/table.d.ts.map +1 -1
  93. package/dist/components/time-picker/time-picker.js +2 -1
  94. package/dist/components/time-picker/time-picker.js.map +1 -1
  95. package/dist/components/time-range-picker/time-range-picker.js +2 -1
  96. package/dist/components/time-range-picker/time-range-picker.js.map +1 -1
  97. package/dist/components/tooltip/tooltip.js +2 -1
  98. package/dist/components/tooltip/tooltip.js.map +1 -1
  99. package/dist/components/tour/tour.d.ts +1 -1
  100. package/dist/components/tour/tour.js +12 -3
  101. package/dist/components/tour/tour.js.map +1 -1
  102. package/dist/components/tree-select/tree-select.js +3 -3
  103. package/dist/components/tree-select/tree-select.js.map +1 -1
  104. package/dist/locale.d.ts +2 -0
  105. package/dist/locale.js +2 -0
  106. package/dist/package.js +1 -1
  107. package/dist/runtime/as-child.js +7 -2
  108. package/dist/runtime/as-child.js.map +1 -1
  109. package/dist/runtime/portal.js +11 -1
  110. package/dist/runtime/portal.js.map +1 -1
  111. package/dist/runtime/use-overlay-exit.js +6 -1
  112. package/dist/runtime/use-overlay-exit.js.map +1 -1
  113. package/dist/services/dialog-service.d.ts +3 -3
  114. package/dist/services/dialog-service.d.ts.map +1 -1
  115. package/dist/services/dialog-service.js +8 -6
  116. package/dist/services/dialog-service.js.map +1 -1
  117. package/dist/services/service-config.js +2 -1
  118. package/dist/services/service-config.js.map +1 -1
  119. package/package.json +19 -15
@@ -1 +1 @@
1
- {"version":3,"file":"tour.js","names":[],"sources":["../../../src/components/tour/tour.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 tour 相关实现。\n\nimport type { Direction, Placement } from '@xihan-ui/core'\nimport type { TourApi, TourSchema, TourStep } from '@xihan-ui/headless'\nimport type { PropType, SlotsType, VNode } from 'vue'\nimport type { PayloadOf } from '../../runtime/payload'\nimport { defineComponent, h, mergeProps } from 'vue'\nimport { withXhConfig } from '../../config/config'\nimport { XhPortal } from '../../runtime/portal'\nimport { provideTour, useTourContext } from './context'\nimport { useTour } from './use-tour'\n\ntype TourProps = TourSchema['props']\n\n/** 默认插槽的载荷:引导的开合与步序状态,以及开关、切换步骤、放弃与校准位置的动作。 */\nexport type TourRootSlotProps = Pick<\n TourApi,\n | 'open'\n | 'value'\n | 'count'\n | 'currentStep'\n | 'firstStep'\n | 'lastStep'\n | 'progressText'\n | 'setOpen'\n | 'setValue'\n | 'goToNextStep'\n | 'goToPrevStep'\n | 'skip'\n | 'remeasure'\n>\n\nexport const XhTourRoot = defineComponent({\n name: 'XhTourRoot',\n // 全部 default: undefined —— 缺省值的唯一事实源在 machine 与 connect\n props: {\n steps: { type: Array as PropType<TourStep[]> },\n value: { type: Number },\n defaultValue: { type: Number },\n open: { type: Boolean, default: undefined },\n defaultOpen: { type: Boolean, default: undefined },\n placement: { type: String as PropType<Placement> },\n offset: { type: Number },\n /** 文字方向;浮层迁移到落点后无法继承作者子树上的方向,需要 RTL 时显式提供。 */\n dir: { type: String as PropType<Direction> },\n closeOnEscape: { type: Boolean, default: undefined },\n closeOnInteractOutside: { type: Boolean, default: undefined },\n showBackdrop: { type: Boolean, default: undefined },\n spotlightPadding: { type: Number },\n autoScroll: { type: Boolean, default: undefined },\n /** 目标缺席时等它出现的时长(ms),默认 3000;0 即不等。 */\n targetTimeout: { type: Number },\n translations: { type: Object as PropType<TourProps['translations']> },\n /** 本实例三张 Tour 浮层的 Portal 容器;优先于应用级配置。 */\n container: { type: Object as PropType<Element> },\n },\n // open-change / value-change 携带对象;update:* 携带裸值,支持 v-model:open 与 v-model:value\n emits: {\n 'open-change': (_details: PayloadOf<TourProps, 'onOpenChange'>) => true,\n 'update:open': (_open: PayloadOf<TourProps, 'onOpenChange'>['open']) => true,\n 'value-change': (_details: PayloadOf<TourProps, 'onValueChange'>) => true,\n 'update:value': (_value: PayloadOf<TourProps, 'onValueChange'>['value']) => true,\n 'complete': (_details: PayloadOf<TourProps, 'onComplete'>) => true,\n 'skip': (_details: PayloadOf<TourProps, 'onSkip'>) => true,\n },\n slots: Object as SlotsType<{\n default?: (props: TourRootSlotProps) => VNode[]\n }>,\n setup(props, { slots, emit }) {\n const ctx = useTour(withXhConfig('tour', props) as TourProps, {\n onOpenChange: (details) => {\n emit('open-change', details)\n emit('update:open', details.open)\n },\n onValueChange: (details) => {\n emit('value-change', details)\n emit('update:value', details.value)\n },\n onComplete: details => emit('complete', details),\n onSkip: details => emit('skip', details),\n }, () => props.container)\n provideTour(ctx)\n // 经插槽暴露状态与走步、放弃等命令,供浮层外的按钮使用\n return () => h('div', ctx.api.value.getRootProps() as Record<string, unknown>, slots.default?.({\n open: ctx.api.value.open,\n value: ctx.api.value.value,\n count: ctx.api.value.count,\n currentStep: ctx.api.value.currentStep,\n firstStep: ctx.api.value.firstStep,\n lastStep: ctx.api.value.lastStep,\n progressText: ctx.api.value.progressText,\n setOpen: ctx.api.value.setOpen,\n setValue: ctx.api.value.setValue,\n goToNextStep: ctx.api.value.goToNextStep,\n goToPrevStep: ctx.api.value.goToPrevStep,\n skip: ctx.api.value.skip,\n remeasure: ctx.api.value.remeasure,\n }))\n },\n})\n\nexport const XhTourBackdrop = defineComponent({\n name: 'XhTourBackdrop',\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到遮罩上\n inheritAttrs: false,\n setup(_, { slots, attrs }) {\n const ctx = useTourContext()\n // 与浮层同去一个落点:遮罩留在原地就会被面板甩下,两层不再叠在一起\n return () => h(XhPortal, { to: ctx.portalTarget.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getBackdropProps() as Record<string, unknown>, attrs),\n // 收起跟着退场闸门走:遮罩的淡出与气泡的退场并行播\n hidden: (!ctx.visible.value || !ctx.showBackdrop()) || undefined,\n ref: (el: unknown) => { ctx.backdropRef.value = el as HTMLElement },\n }, slots.default?.()),\n ])\n },\n})\n\nexport const XhTourSpotlight = defineComponent({\n name: 'XhTourSpotlight',\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到高亮框上\n inheritAttrs: false,\n setup(_, { attrs }) {\n const ctx = useTourContext()\n // 高亮框与遮罩是同一层暗幕的两半,必须一起搬\n return () => h(XhPortal, { to: ctx.portalTarget.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getSpotlightProps() as Record<string, unknown>, attrs),\n // 收起跟着退场闸门走:高亮框的退场与气泡并行播;居中步照常不画\n hidden: (!ctx.visible.value || !ctx.api.value.anchored) || undefined,\n ref: (el: unknown) => { ctx.spotlightRef.value = el as HTMLElement },\n }),\n ])\n },\n})\n\nexport const XhTourPositioner = defineComponent({\n name: 'XhTourPositioner',\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到 positioner 上\n inheritAttrs: false,\n setup(_, { slots, attrs }) {\n const ctx = useTourContext()\n // 搬到 portal 落点:留在原地的话,宿主祖先只要建了层叠上下文就能盖住浮层\n return () => h(XhPortal, { to: ctx.portalTarget.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getPositionerProps() as Record<string, unknown>, attrs),\n // 定位层收起跟着退场闸门走:它先 display:none 的话,里面气泡的退场一帧都播不出来\n hidden: !ctx.visible.value || undefined,\n ref: (el: unknown) => { ctx.positionerRef.value = el as HTMLElement },\n }, slots.default?.()),\n ])\n },\n})\n\nexport const XhTourContent = defineComponent({\n name: 'XhTourContent',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('div', {\n ...ctx.api.value.getContentProps() as Record<string, unknown>,\n // 收起跟着退场闸门走:皮肤刻意没给 content 补 [hidden]{display:none}(补了退场\n // 就一帧都播不出来),所以真正的收起落成内联 display——节点始终留在原地\n style: ctx.visible.value ? undefined : { display: 'none' },\n ref: (el: unknown) => { ctx.contentRef.value = el as HTMLElement },\n }, slots.default?.())\n },\n})\n\n// 标题与描述的文字取自步骤声明,有插槽则用插槽\nexport const XhTourTitle = defineComponent({\n name: 'XhTourTitle',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h(\n 'h2',\n ctx.api.value.getTitleProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.currentStep?.title,\n )\n },\n})\n\nexport const XhTourDescription = defineComponent({\n name: 'XhTourDescription',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h(\n 'p',\n ctx.api.value.getDescriptionProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.currentStep?.description,\n )\n },\n})\n\nexport const XhTourProgressText = defineComponent({\n name: 'XhTourProgressText',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h(\n 'span',\n ctx.api.value.getProgressTextProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.progressText,\n )\n },\n})\n\n/** 圆点组:未提供默认插槽时按步数铺设圆点,作者提供后按作者的内容。 */\nexport const XhTourProgressIndicator = defineComponent({\n name: 'XhTourProgressIndicator',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => {\n const api = ctx.api.value\n const dots = Array.from({ length: api.count }, (_, index) =>\n h('div', api.getProgressDotProps({ index }) as Record<string, unknown>))\n return h(\n 'div',\n api.getProgressIndicatorProps() as Record<string, unknown>,\n slots.default?.() ?? dots,\n )\n }\n },\n})\n\nexport const XhTourProgressDot = defineComponent({\n name: 'XhTourProgressDot',\n props: {\n // 圆点对应的步序,0 基;兼收字符串\n index: { type: [Number, String] as PropType<number | string>, required: true },\n },\n setup(props) {\n const ctx = useTourContext()\n return () => h('div', ctx.api.value.getProgressDotProps({ index: Number(props.index) }) as Record<string, unknown>)\n },\n})\n\nexport const XhTourPrevTrigger = defineComponent({\n name: 'XhTourPrevTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getPrevTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourNextTrigger = defineComponent({\n name: 'XhTourNextTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getNextTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourSkipTrigger = defineComponent({\n name: 'XhTourSkipTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getSkipTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourCloseTrigger = defineComponent({\n name: 'XhTourCloseTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getCloseTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourArrow = defineComponent({\n name: 'XhTourArrow',\n setup() {\n const ctx = useTourContext()\n return () => h('div', ctx.api.value.getArrowProps() as Record<string, unknown>)\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"tour.js","names":[],"sources":["../../../src/components/tour/tour.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 tour 相关实现。\n\nimport type { Direction, Placement } from '@xihan-ui/core'\nimport type { TourApi, TourSchema, TourStep } from '@xihan-ui/headless'\nimport type { PropType, SlotsType, VNode } from 'vue'\nimport type { PayloadOf } from '../../runtime/payload'\nimport { defineComponent, h, mergeProps } from 'vue'\nimport { withXhConfig } from '../../config/config'\nimport { XhPortal } from '../../runtime/portal'\nimport { provideTour, useTourContext } from './context'\nimport { useTour } from './use-tour'\n\ntype TourProps = TourSchema['props']\n\n/** 默认插槽的载荷:引导的开合与步序状态,以及开关、切换步骤、放弃与校准位置的动作。 */\nexport type TourRootSlotProps = Pick<\n TourApi,\n | 'open'\n | 'value'\n | 'count'\n | 'currentStep'\n | 'firstStep'\n | 'lastStep'\n | 'progressText'\n | 'setOpen'\n | 'setValue'\n | 'goToNextStep'\n | 'goToPrevStep'\n | 'skip'\n | 'remeasure'\n>\n\nexport const XhTourRoot = defineComponent({\n name: 'XhTourRoot',\n // 全部 default: undefined —— 缺省值的唯一事实源在 machine 与 connect\n props: {\n steps: { type: Array as PropType<TourStep[]> },\n value: { type: Number },\n defaultValue: { type: Number },\n open: { type: Boolean, default: undefined },\n defaultOpen: { type: Boolean, default: undefined },\n placement: { type: String as PropType<Placement> },\n offset: { type: Number },\n /** 文字方向;浮层迁移到落点后无法继承作者子树上的方向,需要 RTL 时显式提供。 */\n dir: { type: String as PropType<Direction> },\n closeOnEscape: { type: Boolean, default: undefined },\n closeOnInteractOutside: { type: Boolean, default: undefined },\n showBackdrop: { type: Boolean, default: undefined },\n spotlightPadding: { type: Number },\n autoScroll: { type: Boolean, default: undefined },\n /** 目标缺席时等它出现的时长(ms),默认 3000;0 即不等。 */\n targetTimeout: { type: Number },\n translations: { type: Object as PropType<TourProps['translations']> },\n /** 本实例三张 Tour 浮层的 Portal 容器;优先于应用级配置。 */\n container: { type: Object as PropType<Element> },\n },\n // open-change / value-change 携带对象;update:* 携带裸值,支持 v-model:open 与 v-model:value\n emits: {\n 'open-change': (_details: PayloadOf<TourProps, 'onOpenChange'>) => true,\n 'update:open': (_open: PayloadOf<TourProps, 'onOpenChange'>['open']) => true,\n 'value-change': (_details: PayloadOf<TourProps, 'onValueChange'>) => true,\n 'update:value': (_value: PayloadOf<TourProps, 'onValueChange'>['value']) => true,\n 'complete': (_details: PayloadOf<TourProps, 'onComplete'>) => true,\n 'skip': (_details: PayloadOf<TourProps, 'onSkip'>) => true,\n },\n slots: Object as SlotsType<{\n default?: (props: TourRootSlotProps) => VNode[]\n }>,\n setup(props, { slots, emit }) {\n const ctx = useTour(withXhConfig('tour', props) as TourProps, {\n onOpenChange: (details) => {\n emit('open-change', details)\n emit('update:open', details.open)\n },\n onValueChange: (details) => {\n emit('value-change', details)\n emit('update:value', details.value)\n },\n onComplete: details => emit('complete', details),\n onSkip: details => emit('skip', details),\n }, () => props.container)\n provideTour(ctx)\n // 经插槽暴露状态与走步、放弃等命令,供浮层外的按钮使用\n return () => h('div', ctx.api.value.getRootProps() as Record<string, unknown>, slots.default?.({\n open: ctx.api.value.open,\n value: ctx.api.value.value,\n count: ctx.api.value.count,\n currentStep: ctx.api.value.currentStep,\n firstStep: ctx.api.value.firstStep,\n lastStep: ctx.api.value.lastStep,\n progressText: ctx.api.value.progressText,\n setOpen: ctx.api.value.setOpen,\n setValue: ctx.api.value.setValue,\n goToNextStep: ctx.api.value.goToNextStep,\n goToPrevStep: ctx.api.value.goToPrevStep,\n skip: ctx.api.value.skip,\n remeasure: ctx.api.value.remeasure,\n }))\n },\n})\n\nexport const XhTourBackdrop = defineComponent({\n name: 'XhTourBackdrop',\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到遮罩上\n inheritAttrs: false,\n setup(_, { slots, attrs }) {\n const ctx = useTourContext()\n // 与浮层同去一个落点:遮罩留在原地就会被面板甩下,两层不再叠在一起\n return () => h(XhPortal, { to: ctx.portalTarget.value, present: ctx.visible.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getBackdropProps() as Record<string, unknown>, attrs),\n // 收起跟着退场闸门走:遮罩的淡出与气泡的退场并行播\n hidden: (!ctx.visible.value || !ctx.showBackdrop()) || undefined,\n ref: (el: unknown) => { ctx.backdropRef.value = el as HTMLElement },\n }, slots.default?.()),\n ])\n },\n})\n\nexport const XhTourSpotlight = defineComponent({\n name: 'XhTourSpotlight',\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到高亮框上\n inheritAttrs: false,\n setup(_, { attrs }) {\n const ctx = useTourContext()\n // 高亮框与遮罩是同一层暗幕的两半,必须一起搬\n return () => h(XhPortal, { to: ctx.portalTarget.value, present: ctx.visible.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getSpotlightProps() as Record<string, unknown>, attrs),\n // 收起跟着退场闸门走:高亮框的退场与气泡并行播;居中步照常不画\n hidden: (!ctx.visible.value || !ctx.api.value.anchored) || undefined,\n ref: (el: unknown) => { ctx.spotlightRef.value = el as HTMLElement },\n }),\n ])\n },\n})\n\nexport const XhTourPositioner = defineComponent({\n name: 'XhTourPositioner',\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到 positioner 上\n inheritAttrs: false,\n setup(_, { slots, attrs }) {\n const ctx = useTourContext()\n // 搬到 portal 落点:留在原地的话,宿主祖先只要建了层叠上下文就能盖住浮层\n return () => h(XhPortal, { to: ctx.portalTarget.value, present: ctx.visible.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getPositionerProps() as Record<string, unknown>, attrs),\n // 定位层收起跟着退场闸门走:它先 display:none 的话,里面气泡的退场一帧都播不出来\n hidden: !ctx.visible.value || undefined,\n ref: (el: unknown) => { ctx.positionerRef.value = el as HTMLElement },\n }, slots.default?.()),\n ])\n },\n})\n\nexport const XhTourContent = defineComponent({\n name: 'XhTourContent',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('div', {\n ...ctx.api.value.getContentProps() as Record<string, unknown>,\n // 收起跟着退场闸门走:皮肤刻意没给 content 补 [hidden]{display:none}(补了退场\n // 就一帧都播不出来),所以真正的收起落成内联 display——节点始终留在原地\n style: ctx.visible.value ? undefined : { display: 'none' },\n ref: (el: unknown) => { ctx.contentRef.value = el as HTMLElement },\n }, slots.default?.())\n },\n})\n\n// 标题与描述的文字取自步骤声明,有插槽则用插槽\nexport const XhTourTitle = defineComponent({\n name: 'XhTourTitle',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h(\n 'h2',\n ctx.api.value.getTitleProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.currentStep?.title,\n )\n },\n})\n\nexport const XhTourDescription = defineComponent({\n name: 'XhTourDescription',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h(\n 'p',\n ctx.api.value.getDescriptionProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.currentStep?.description,\n )\n },\n})\n\nexport const XhTourProgressText = defineComponent({\n name: 'XhTourProgressText',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h(\n 'span',\n ctx.api.value.getProgressTextProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.progressText,\n )\n },\n})\n\n/** 圆点组:未提供默认插槽时按步数铺设圆点,作者提供后按作者的内容。 */\nexport const XhTourProgressIndicator = defineComponent({\n name: 'XhTourProgressIndicator',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => {\n const api = ctx.api.value\n const dots = Array.from({ length: api.count }, (_, index) =>\n h('div', api.getProgressDotProps({ index }) as Record<string, unknown>))\n return h(\n 'div',\n api.getProgressIndicatorProps() as Record<string, unknown>,\n slots.default?.() ?? dots,\n )\n }\n },\n})\n\nexport const XhTourProgressDot = defineComponent({\n name: 'XhTourProgressDot',\n props: {\n // 圆点对应的步序,0 基;兼收字符串\n index: { type: [Number, String] as PropType<number | string>, required: true },\n },\n setup(props) {\n const ctx = useTourContext()\n return () => h('div', ctx.api.value.getProgressDotProps({ index: Number(props.index) }) as Record<string, unknown>)\n },\n})\n\nexport const XhTourPrevTrigger = defineComponent({\n name: 'XhTourPrevTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getPrevTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourNextTrigger = defineComponent({\n name: 'XhTourNextTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getNextTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourSkipTrigger = defineComponent({\n name: 'XhTourSkipTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getSkipTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourCloseTrigger = defineComponent({\n name: 'XhTourCloseTrigger',\n setup(_, { slots }) {\n const ctx = useTourContext()\n return () => h('button', ctx.api.value.getCloseTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTourArrow = defineComponent({\n name: 'XhTourArrow',\n setup() {\n const ctx = useTourContext()\n return () => h('div', ctx.api.value.getArrowProps() as Record<string, unknown>)\n },\n})\n"],"mappings":"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"}
@@ -306,7 +306,8 @@ container: { type: Object } },
306
306
  });
307
307
  return () => h(XhPortal, {
308
308
  to: props.container ?? ctx.portalTarget.value,
309
- source: ctx.triggerRef
309
+ source: ctx.triggerRef,
310
+ present: ctx.visible.value
310
311
  }, () => [h("div", {
311
312
  ...mergeProps(ctx.api.value.getPositionerProps(), attrs),
312
313
  ref: (el) => {
@@ -571,8 +572,7 @@ const XhTreeSelectHiddenInput = defineComponent({
571
572
  setup(_, { attrs }) {
572
573
  const ctx = useTreeSelectContext();
573
574
  return () => ctx.api.value.value.map((value) => h("input", {
574
- ...ctx.api.value.getHiddenInputProps({ value }),
575
- ...attrs,
575
+ ...mergeProps(ctx.api.value.getHiddenInputProps({ value }), attrs),
576
576
  key: value
577
577
  }));
578
578
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tree-select.js","names":[],"sources":["../../../src/components/tree-select/tree-select.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 tree select 相关实现。\n\nimport type { ControlVariant, Direction, Placement, Size, Tone } from '@xihan-ui/core'\nimport type { CollectionVirtualizer, TreeSelectApi, TreeSelectNode, TreeSelectNodeProps, TreeSelectSchema, TreeSelectTagMeta } from '@xihan-ui/headless'\nimport type { PropType, Ref, SlotsType, VNode } from 'vue'\nimport type { PayloadOf } from '../../runtime/payload'\nimport type { TreeSelectContext } from './use-tree-select'\nimport { computed, defineComponent, h, mergeProps, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { withXhConfig } from '../../config/config'\nimport { XhPortal } from '../../runtime/portal'\nimport { slotIsPlainText } from '../../runtime/slot-content'\nimport { useScrollbars } from '../../runtime/use-scrollbars'\nimport { withHandlers } from '../../runtime/with-handlers'\nimport { useFieldLabelWiring, useFieldStateWiring } from '../field/use-field-control'\nimport { useFormControlProps } from '../form/use-form-control'\nimport { provideTreeSelect, provideTreeSelectContent, provideTreeSelectNode, provideTreeSelectTag, useTreeSelectContentContext, useTreeSelectContext, useTreeSelectNodeContext, useTreeSelectTagContext } from './context'\nimport { useTreeSelect } from './use-tree-select'\n\ntype TreeSelectProps = TreeSelectSchema['props']\n\n/** 默认插槽的载荷:展开与选中状态、可见行序列、搜索视图、多选的可见标签与折起的个数、节点状态判定与写值方法。 */\nexport type TreeSelectRootSlotProps = Pick<\n TreeSelectApi,\n | 'open'\n | 'searching'\n | 'inputValue'\n | 'value'\n | 'expandedValue'\n | 'visibleNodes'\n | 'focusedValue'\n | 'empty'\n | 'loading'\n | 'displayText'\n | 'canClear'\n | 'tags'\n | 'overflowCount'\n | 'overflowText'\n | 'isSelected'\n | 'isIndeterminate'\n | 'isExpanded'\n | 'branchLoadState'\n | 'setOpen'\n | 'setValue'\n | 'setExpandedValue'\n | 'setInputValue'\n | 'expand'\n | 'collapse'\n | 'retryBranch'\n | 'select'\n | 'clear'\n | 'deselect'\n>\n\n/** 本节点持有焦点时,value 变更重新报告焦点节点,卸载时上报焦点丢失 */\nfunction reportNodeFocus(ctx: TreeSelectContext, el: Ref<HTMLElement | null>, value: () => string): void {\n let registered: string | null = null\n watch(value, (next, prev) => {\n if (next === prev)\n return\n const { service } = ctx\n if (service.getStatus() !== 'Started')\n return\n if (el.value && service.scope.getActiveElement() === el.value)\n service.send({ type: 'NODE.FOCUS', value: next })\n if (registered !== null) {\n service.send({ type: 'NODE.UNMOUNT', value: prev })\n service.send({ type: 'NODE.MOUNT', value: next })\n registered = next\n }\n })\n onMounted(() => queueMicrotask(() => {\n if (ctx.service.getStatus() !== 'Started')\n return\n registered = value()\n ctx.service.send({ type: 'NODE.MOUNT', value: registered })\n }))\n onBeforeUnmount(() => {\n const { service } = ctx\n // 整组一起卸载时根部件先停机,此刻送事件会在 dev 下抛\n if (service.getStatus() !== 'Started')\n return\n if (registered !== null)\n service.send({ type: 'NODE.UNMOUNT', value: registered })\n // 按「本节点当下正持有焦点」判定,不按 value 比对\n if (el.value && service.scope.getActiveElement() === el.value)\n service.send({ type: 'NODE.LOST' })\n })\n}\n\nexport const XhTreeSelectRoot = defineComponent({\n name: 'XhTreeSelectRoot',\n // 有 connect 兜底的 prop:普通类型省略 default,Boolean 显式保留 undefined\n props: {\n collection: { type: Array as PropType<TreeSelectNode[]> },\n /** 完整 collection 与 Virtualizer 的焦点桥;count 必须等于当前 visibleNodes.length。 */\n virtualizer: { type: Object as PropType<CollectionVirtualizer> },\n loadChildren: { type: Function as PropType<TreeSelectProps['loadChildren']> },\n /** 标题文字。提供后不必再写 label 部件;需要放置其他内容时改用 label 插槽。 */\n label: { type: String },\n /** 自动渲染树中是否带清空按钮;手写部件不使用它,写了节点即可清空。 */\n clearable: Boolean,\n value: { type: [String, Array] as PropType<string | string[]> },\n defaultValue: { type: [String, Array] as PropType<string | string[]> },\n expandedValue: { type: Array as PropType<string[]> },\n defaultExpandedValue: { type: Array as PropType<string[]> },\n open: { type: Boolean, default: undefined },\n defaultOpen: Boolean,\n multiple: Boolean,\n /** 多选标签最多显示的数量,其余折进 +N;默认 3。 */\n maxTagCount: { type: Number },\n /** 浮层内搜索:展开时焦点先落在搜索框上,输入即把树裁到只剩命中的那几枝。 */\n searchable: Boolean,\n /** 自定义匹配规则;缺省为标签大小写不敏感包含。 */\n filter: { type: Function as PropType<TreeSelectProps['filter']> },\n cascade: Boolean,\n checkedStrategy: { type: String as PropType<TreeSelectProps['checkedStrategy']> },\n disabled: { type: Boolean, default: undefined },\n readOnly: { type: Boolean, default: undefined },\n invalid: { type: Boolean, default: undefined },\n loading: Boolean,\n variant: { type: String as PropType<ControlVariant> },\n tone: { type: String as PropType<Tone> },\n size: { type: String as PropType<Size> },\n placeholder: { type: String },\n translations: { type: Object as PropType<TreeSelectProps['translations']> },\n placement: { type: String as PropType<Placement> },\n offset: { type: Number },\n loop: { type: Boolean, default: undefined },\n dir: { type: String as PropType<Direction> },\n name: { type: String },\n form: { type: String },\n },\n // *-change 携带 details 对象,update:* 携带裸值;选中值恒为数组,单选时长度 ≤ 1\n emits: {\n 'clear': () => true,\n 'value-change': (_details: PayloadOf<TreeSelectProps, 'onValueChange'>) => true,\n 'expanded-value-change': (_details: PayloadOf<TreeSelectProps, 'onExpandedValueChange'>) => true,\n 'open-change': (_details: PayloadOf<TreeSelectProps, 'onOpenChange'>) => true,\n 'branch-load-start': (_details: PayloadOf<TreeSelectProps, 'onBranchLoadStart'>) => true,\n 'branch-load': (_details: PayloadOf<TreeSelectProps, 'onBranchLoad'>) => true,\n 'branch-load-error': (_details: PayloadOf<TreeSelectProps, 'onBranchLoadError'>) => true,\n 'update:value': (_value: PayloadOf<TreeSelectProps, 'onValueChange'>['value']) => true,\n 'update:expandedValue': (_value: PayloadOf<TreeSelectProps, 'onExpandedValueChange'>['value']) => true,\n 'update:open': (_open: PayloadOf<TreeSelectProps, 'onOpenChange'>['open']) => true,\n },\n slots: Object as SlotsType<{\n default?: (props: TreeSelectRootSlotProps) => VNode[]\n label?: () => VNode[]\n }>,\n setup(props, { slots, emit }) {\n const notifyValue: TreeSelectProps['onValueChange'] = (details) => {\n emit('value-change', details)\n emit('update:value', details.value)\n }\n const notifyExpanded: TreeSelectProps['onExpandedValueChange'] = (details) => {\n emit('expanded-value-change', details)\n emit('update:expandedValue', details.value)\n }\n const notifyOpen: TreeSelectProps['onOpenChange'] = (details) => {\n emit('open-change', details)\n emit('update:open', details.open)\n }\n const notifyBranchLoadStart: TreeSelectProps['onBranchLoadStart'] = details => emit('branch-load-start', details)\n const notifyBranchLoad: TreeSelectProps['onBranchLoad'] = details => emit('branch-load', details)\n const notifyBranchLoadError: TreeSelectProps['onBranchLoadError'] = details => emit('branch-load-error', details)\n const ctx = useTreeSelect(withHandlers(withXhConfig('tree-select', useFormControlProps(props)), { onClear: () => emit('clear') }) as TreeSelectProps, {\n onValueChange: notifyValue,\n onExpandedValueChange: notifyExpanded,\n onOpenChange: notifyOpen,\n onBranchLoadStart: notifyBranchLoadStart,\n onBranchLoad: notifyBranchLoad,\n onBranchLoadError: notifyBranchLoadError,\n })\n provideTreeSelect(ctx)\n\n return () => h('div', ctx.api.value.getRootProps() as Record<string, unknown>, slots.default\n ? slots.default({\n open: ctx.api.value.open,\n searching: ctx.api.value.searching,\n inputValue: ctx.api.value.inputValue,\n value: ctx.api.value.value,\n expandedValue: ctx.api.value.expandedValue,\n visibleNodes: ctx.api.value.visibleNodes,\n focusedValue: ctx.api.value.focusedValue,\n empty: ctx.api.value.empty,\n loading: ctx.api.value.loading,\n displayText: ctx.api.value.displayText,\n canClear: ctx.api.value.canClear,\n tags: ctx.api.value.tags,\n overflowCount: ctx.api.value.overflowCount,\n overflowText: ctx.api.value.overflowText,\n isSelected: ctx.api.value.isSelected,\n isIndeterminate: ctx.api.value.isIndeterminate,\n isExpanded: ctx.api.value.isExpanded,\n branchLoadState: ctx.api.value.branchLoadState,\n setOpen: ctx.api.value.setOpen,\n setValue: ctx.api.value.setValue,\n setExpandedValue: ctx.api.value.setExpandedValue,\n setInputValue: ctx.api.value.setInputValue,\n expand: ctx.api.value.expand,\n collapse: ctx.api.value.collapse,\n retryBranch: ctx.api.value.retryBranch,\n select: ctx.api.value.select,\n clear: ctx.api.value.clear,\n deselect: ctx.api.value.deselect,\n })\n : props.collection\n ? renderDefaultTree(\n ctx.api.value.collection,\n props.multiple ? ctx.api.value.tags : null,\n props.searchable,\n slots.label?.() ?? (props.label != null ? [props.label] : null),\n props.clearable,\n )\n : [])\n },\n})\n\nexport const XhTreeSelectLabel = defineComponent({\n name: 'XhTreeSelectLabel',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('span', ctx.api.value.getLabelProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectControl = defineComponent({\n name: 'XhTreeSelectControl',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 描边、底色与聚焦环所在的那一层,触发按钮与尾部动作钮在里面并排\n return () => h('div', {\n ...ctx.api.value.getControlProps() as Record<string, unknown>,\n ref: (el: unknown) => { ctx.controlRef.value = el as HTMLElement },\n }, slots.default?.())\n },\n})\n\nexport const XhTreeSelectTrigger = defineComponent({\n name: 'XhTreeSelectTrigger',\n setup(_, { slots }) {\n // 字段的说明与校验状态要落在真控件上,不能停在封装根的 div 上\n const fieldWiring = useFieldStateWiring()\n // 字段的标签也得并进名字链:控件自带的那条指的是它自己那个没渲染的 label 部件\n const fieldLabel = useFieldLabelWiring()\n const ctx = useTreeSelectContext()\n return () => h('button', fieldLabel.value({\n ...fieldWiring.value,\n ...ctx.api.value.getTriggerProps() as Record<string, unknown>,\n ref: (el: unknown) => { ctx.triggerRef.value = el as HTMLElement },\n }), slots.default?.())\n },\n})\n\nexport const XhTreeSelectValueText = defineComponent({\n name: 'XhTreeSelectValueText',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 有插槽用插槽,否则显示选中项文本或 placeholder\n return () => h(\n 'span',\n ctx.api.value.getValueTextProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.displayText,\n )\n },\n})\n\nexport const XhTreeSelectTagList = defineComponent({\n name: 'XhTreeSelectTagList',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 标签行:可见标签与 +N 那一枚在里面并排;无选中时连接层给 hidden,value-text 回来显示占位文字\n return () => h('span', ctx.api.value.getTagListProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\n/** 标签文字所在的块(tag 的 label):截断规则挂在这一层。 */\nexport const XhTreeSelectTagLabel = defineComponent({\n name: 'XhTreeSelectTagLabel',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('span', ctx.api.value.getTagLabelProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\n/**\n * 标签内容:只有文字时替它包一层 label:截断规则挂在 label 上,直接展开在 root 上的文字过长会把\n * 删除按钮挤出;作者自己写了节点则原样放行。与 XhTagRoot 同一规则。\n * 库自身填入的文字(+N,没有折叠时是空串)恒包 label,三个适配器渲染出同一棵树。\n */\nfunction tagChildren(content: VNode[] | string | undefined): VNode[] | string | undefined {\n if (typeof content === 'string')\n return [h(XhTreeSelectTagLabel, null, () => content)]\n return slotIsPlainText(content) ? [h(XhTreeSelectTagLabel, null, () => content)] : content\n}\n\n/** 一个选中值一个标签,即库内 tag 的 root(data-scope=\"tag\"):语气、尺寸与禁用从树选择传下,形态按控件的面派生;触发器内纯展示,触发器外配合 XhTreeSelectItemDeleteTrigger 可删除。 */\nexport const XhTreeSelectTag = defineComponent({\n name: 'XhTreeSelectTag',\n props: {\n /** 它代表哪个选中值。 */\n value: { type: String, required: true },\n },\n setup(props, { slots }) {\n const ctx = useTreeSelectContext()\n provideTreeSelectTag({ value: () => props.value })\n return () => h('span', ctx.api.value.getTagProps({ value: props.value }) as Record<string, unknown>, tagChildren(slots.default?.()))\n },\n})\n\n/** 折叠的标签合成的一个标签:同样是 tag 的 root;有插槽时使用插槽,否则显示 +N。没有折叠的标签时连接层写 hidden。 */\nexport const XhTreeSelectOverflowTag = defineComponent({\n name: 'XhTreeSelectOverflowTag',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h(\n 'span',\n ctx.api.value.getOverflowTagProps() as Record<string, unknown>,\n tagChildren(slots.default?.() ?? ctx.api.value.overflowText),\n )\n },\n})\n\n/** 标签中的删除按钮:即所在标签那份 tag 的 close-trigger(data-scope=\"tag\"),可及名使用 translations.deleteItem;点按移除所在标签的选中值。 */\nexport const XhTreeSelectItemDeleteTrigger = defineComponent({\n name: 'XhTreeSelectItemDeleteTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const tag = useTreeSelectTagContext()\n return () => h('button', ctx.api.value.getItemDeleteTriggerProps({ value: tag.value() }) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectIndicator = defineComponent({\n name: 'XhTreeSelectIndicator',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('span', ctx.api.value.getIndicatorProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectClearTrigger = defineComponent({\n name: 'XhTreeSelectClearTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('button', ctx.api.value.getClearTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectPositioner = defineComponent({\n name: 'XhTreeSelectPositioner',\n props: {\n /** 本实例的 Portal 容器;优先于应用级配置。 */\n container: { type: Object as PropType<Element> },\n },\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到 positioner 上\n inheritAttrs: false,\n setup(props, { slots, attrs }) {\n const ctx = useTreeSelectContext()\n // 树的自绘条:与 content 同级、绝对定位不占布局,壳是这层已经 fixed 的 positioner。\n // 两条轴都摆:深层节点靠缩进往行末推,横向溢出与纵向一样是常态。\n // 横条的正负按排版方向算,而组件不读计算样式,把 positioner 上那份显式交过去\n const bars = useScrollbars({\n // 虚拟窗口的滚动层是 Virtualizer 的视口,条子跟着它走\n scrollable: () => ctx.service.prop('virtualizer')?.getViewportElement() ?? ctx.treeRef.value,\n axes: ['vertical', 'horizontal'],\n // 条子走浮层 4px 档\n props: () => ({ dir: (ctx.api.value.getPositionerProps() as { dir?: Direction }).dir, size: 'sm' }),\n })\n // 搬到 portal 落点:留在原地的话,宿主祖先只要建了层叠上下文就能盖住浮层\n return () => h(XhPortal, { to: props.container ?? ctx.portalTarget.value, source: ctx.triggerRef }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getPositionerProps() as Record<string, unknown>, attrs),\n ref: (el: unknown) => { ctx.positionerRef.value = el as HTMLElement },\n }, [...(slots.default?.() ?? []), ...bars.render()]),\n ])\n },\n})\n\nconst XhTreeSelectAutoEmpty = defineComponent({\n name: 'XhTreeSelectAutoEmpty',\n setup() {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n // 搜索视图里的空是「没有匹配」,与整棵树没有节点分开说\n return () => content.authoredEmptyCount.value > 0\n ? null\n : h('div', {\n ...ctx.api.value.getEmptyProps() as Record<string, unknown>,\n 'data-xh-tree-select-auto-empty': '',\n }, ctx.api.value.searching ? ctx.api.value.translations.noMatch : ctx.api.value.translations.empty)\n },\n})\n\nconst XhTreeSelectAutoLoading = defineComponent({\n name: 'XhTreeSelectAutoLoading',\n setup() {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n return () => content.authoredLoadingCount.value > 0\n ? null\n : h('div', {\n ...ctx.api.value.getLoadingProps() as Record<string, unknown>,\n 'data-xh-tree-select-auto-loading': '',\n }, ctx.api.value.translations.loading)\n },\n})\n\nexport const XhTreeSelectContent = defineComponent({\n name: 'XhTreeSelectContent',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const authoredEmptyCount = ref(0)\n const authoredLoadingCount = ref(0)\n const register = (count: Ref<number>): (() => void) => {\n count.value += 1\n let active = true\n return () => {\n if (!active)\n return\n active = false\n count.value -= 1\n }\n }\n provideTreeSelectContent({\n authoredEmptyCount,\n authoredLoadingCount,\n registerEmpty: () => register(authoredEmptyCount),\n registerLoading: () => register(authoredLoadingCount),\n })\n // 收起时只隐藏不卸载\n return () => h('div', {\n ...ctx.api.value.getContentProps() as Record<string, unknown>,\n // 收起跟着退场闸门走:皮肤刻意没给 content 补 [hidden]{display:none}(补了退场\n // 就一帧都播不出来),所以真正的收起落成内联 display——节点始终留在原地\n style: ctx.visible.value ? undefined : { display: 'none' },\n ref: (el: unknown) => { ctx.contentRef.value = el as HTMLElement },\n }, [slots.default?.(), h(XhTreeSelectAutoEmpty), h(XhTreeSelectAutoLoading)])\n },\n})\n\n/** 浮层内搜索框:放在 content 中、tree 之前;没开 searchable 时带 hidden。 */\nexport const XhTreeSelectInput = defineComponent({\n name: 'XhTreeSelectInput',\n setup() {\n const ctx = useTreeSelectContext()\n return () => h('input', ctx.api.value.getInputProps() as Record<string, unknown>)\n },\n})\n\nexport const XhTreeSelectTree = defineComponent({\n name: 'XhTreeSelectTree',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('div', {\n ...ctx.api.value.getTreeProps() as Record<string, unknown>,\n ref: (el: unknown) => { ctx.treeRef.value = el as HTMLElement | null },\n }, slots.default?.())\n },\n})\n\nexport const XhTreeSelectItem = defineComponent({\n name: 'XhTreeSelectItem',\n props: {\n value: { type: String, required: true },\n },\n setup(props, { slots }) {\n const ctx = useTreeSelectContext()\n const node = computed<TreeSelectNodeProps>(() => ({ value: props.value }))\n provideTreeSelectNode({ node })\n const el = ref<HTMLElement | null>(null)\n reportNodeFocus(ctx, el, () => props.value)\n return () => h(\n 'div',\n { ...ctx.api.value.getItemProps(node.value) as Record<string, unknown>, ref: el },\n slots.default?.(),\n )\n },\n})\n\nexport const XhTreeSelectItemText = defineComponent({\n name: 'XhTreeSelectItemText',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemTextProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\n/** 条目的第 2 行副文本,跨文字槽、走 muted 档 */\nexport const XhTreeSelectItemDescription = defineComponent({\n name: 'XhTreeSelectItemDescription',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemDescriptionProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\n/** 条目行尾的作者内容(计数、徽标) */\nexport const XhTreeSelectItemSuffix = defineComponent({\n name: 'XhTreeSelectItemSuffix',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemSuffixProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectItemIndicator = defineComponent({\n name: 'XhTreeSelectItemIndicator',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemIndicatorProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nfunction renderBranchFeedback(ctx: TreeSelectContext, node: TreeSelectNodeProps): VNode[] {\n if (ctx.api.value.branchLoadState(node.value) == null)\n return []\n return [\n h('div', ctx.api.value.getBranchLoadingProps(node) as Record<string, unknown>, ctx.api.value.translations.loading),\n h('div', ctx.api.value.getBranchErrorProps(node) as Record<string, unknown>, ctx.api.value.translations.branchError),\n h('button', ctx.api.value.getBranchRetryTriggerProps(node) as Record<string, unknown>, ctx.api.value.translations.retry),\n h('div', ctx.api.value.getBranchEmptyProps(node) as Record<string, unknown>, ctx.api.value.translations.branchEmpty),\n ]\n}\n\nexport const XhTreeSelectBranch = defineComponent({\n name: 'XhTreeSelectBranch',\n props: {\n value: { type: String, required: true },\n },\n setup(props, { slots }) {\n const ctx = useTreeSelectContext()\n const node = computed<TreeSelectNodeProps>(() => ({ value: props.value }))\n // 分支自身也是 treeitem,供其子部件读取;子节点各自再 provide 一层\n provideTreeSelectNode({ node })\n const el = ref<HTMLElement | null>(null)\n reportNodeFocus(ctx, el, () => props.value)\n return () => h(\n 'div',\n { ...ctx.api.value.getBranchProps(node.value) as Record<string, unknown>, ref: el },\n [slots.default?.(), ...renderBranchFeedback(ctx, node.value)],\n )\n },\n})\n\nexport const XhTreeSelectBranchControl = defineComponent({\n name: 'XhTreeSelectBranchControl',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchControlProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchTrigger = defineComponent({\n name: 'XhTreeSelectBranchTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getBranchTriggerProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchIndicator = defineComponent({\n name: 'XhTreeSelectBranchIndicator',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getBranchIndicatorProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchText = defineComponent({\n name: 'XhTreeSelectBranchText',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getBranchTextProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchContent = defineComponent({\n name: 'XhTreeSelectBranchContent',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n // 收起只加 hidden,不卸载子树节点\n return () => h('div', ctx.api.value.getBranchContentProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchLoading = defineComponent({\n name: 'XhTreeSelectBranchLoading',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchLoadingProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.loading)\n },\n})\n\nexport const XhTreeSelectBranchError = defineComponent({\n name: 'XhTreeSelectBranchError',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchErrorProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.branchError)\n },\n})\n\nexport const XhTreeSelectBranchRetryTrigger = defineComponent({\n name: 'XhTreeSelectBranchRetryTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('button', ctx.api.value.getBranchRetryTriggerProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.retry)\n },\n})\n\nexport const XhTreeSelectBranchEmpty = defineComponent({\n name: 'XhTreeSelectBranchEmpty',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchEmptyProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.branchEmpty)\n },\n})\n\nexport const XhTreeSelectEmpty = defineComponent({\n name: 'XhTreeSelectEmpty',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n const unregister = content.registerEmpty()\n onBeforeUnmount(unregister)\n return () => h('div', ctx.api.value.getEmptyProps() as Record<string, unknown>, slots.default?.() ?? (ctx.api.value.searching ? ctx.api.value.translations.noMatch : ctx.api.value.translations.empty))\n },\n})\n\nexport const XhTreeSelectLoading = defineComponent({\n name: 'XhTreeSelectLoading',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n const unregister = content.registerLoading()\n onBeforeUnmount(unregister)\n return () => h('div', ctx.api.value.getLoadingProps() as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.loading)\n },\n})\n\nexport const XhTreeSelectFooter = defineComponent({\n name: 'XhTreeSelectFooter',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 浮层底部的操作区:写在 content 里、tree 的兄弟,\n // 放在这里的按钮既不进 role=tree 的拥有关系,也走不到方向键与连打检索\n return () => h('div', ctx.api.value.getFooterProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectHiddenInput = defineComponent({\n name: 'XhTreeSelectHiddenInput',\n inheritAttrs: false,\n setup(_, { attrs }) {\n const ctx = useTreeSelectContext()\n // 表单出口,不写这个部件即不参与表单提交\n return () => ctx.api.value.value.map(value => h('input', {\n ...ctx.api.value.getHiddenInputProps({ value }) as Record<string, unknown>,\n ...attrs,\n key: value,\n }))\n },\n})\n\n/** 按 collection 递归铺设节点:带 children 的渲染为 branch,其余渲染为 item。 */\nfunction renderNodes(nodes: readonly TreeSelectNode[]): VNode[] {\n return nodes.map(node => (node.children || node.hasChildren)\n ? h(XhTreeSelectBranch, { key: node.value, value: node.value }, () => [\n h(XhTreeSelectBranchControl, null, () => [\n h(XhTreeSelectBranchTrigger),\n h(XhTreeSelectBranchText, null, () => node.label ?? node.value),\n h(XhTreeSelectItemIndicator),\n ]),\n h(XhTreeSelectBranchContent, null, () => renderNodes(node.children ?? [])),\n ])\n : h(XhTreeSelectItem, { key: node.value, value: node.value }, () => [\n h(XhTreeSelectItemIndicator),\n h(XhTreeSelectItemText, null, () => node.label ?? node.value),\n ]))\n}\n\n/**\n * 未写默认插槽时按 collection 铺开的整套结构,作者只提供数据。\n * 与手写部件产出的 DOM 完全一致,需要修改结构时写默认插槽,行为不变。\n */\nfunction renderDefaultTree(\n collection: readonly TreeSelectNode[],\n tags: readonly TreeSelectTagMeta[] | null,\n searchable: boolean,\n label: (VNode | string)[] | null,\n clearable: boolean,\n): VNode[] {\n return [\n ...(label ? [h(XhTreeSelectLabel, null, () => label)] : []),\n // 盒里放触发器;清空钮是触发器的兄弟(按钮不能套按钮)\n h(XhTreeSelectControl, null, () => [\n // 多选的已选项在触发器里排成标签:占位文字与标签行同时写着,有选中时标签露面、占位让位;\n // 触发器里的标签只作展示(按钮不能套按钮),摆不下的折进 +N\n h(XhTreeSelectTrigger, null, () => [\n h(XhTreeSelectValueText),\n ...(tags\n ? [h(XhTreeSelectTagList, null, () => [\n ...tags.map(tag => h(XhTreeSelectTag, { key: tag.value, value: tag.value }, () => tag.label)),\n h(XhTreeSelectOverflowTag),\n ])]\n : []),\n h(XhTreeSelectIndicator),\n ]),\n ...(clearable ? [h(XhTreeSelectClearTrigger)] : []),\n ]),\n h(XhTreeSelectPositioner, null, () => [\n // 开了搜索时搜索框排在树之前;collection 此刻已是裁剪后的树\n h(XhTreeSelectContent, null, () => [\n ...(searchable ? [h(XhTreeSelectInput)] : []),\n h(XhTreeSelectTree, null, () => renderNodes(collection)),\n ]),\n ]),\n ]\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tree-select.js","names":[],"sources":["../../../src/components/tree-select/tree-select.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 tree select 相关实现。\n\nimport type { ControlVariant, Direction, Placement, Size, Tone } from '@xihan-ui/core'\nimport type { CollectionVirtualizer, TreeSelectApi, TreeSelectNode, TreeSelectNodeProps, TreeSelectSchema, TreeSelectTagMeta } from '@xihan-ui/headless'\nimport type { PropType, Ref, SlotsType, VNode } from 'vue'\nimport type { PayloadOf } from '../../runtime/payload'\nimport type { TreeSelectContext } from './use-tree-select'\nimport { computed, defineComponent, h, mergeProps, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { withXhConfig } from '../../config/config'\nimport { XhPortal } from '../../runtime/portal'\nimport { slotIsPlainText } from '../../runtime/slot-content'\nimport { useScrollbars } from '../../runtime/use-scrollbars'\nimport { withHandlers } from '../../runtime/with-handlers'\nimport { useFieldLabelWiring, useFieldStateWiring } from '../field/use-field-control'\nimport { useFormControlProps } from '../form/use-form-control'\nimport { provideTreeSelect, provideTreeSelectContent, provideTreeSelectNode, provideTreeSelectTag, useTreeSelectContentContext, useTreeSelectContext, useTreeSelectNodeContext, useTreeSelectTagContext } from './context'\nimport { useTreeSelect } from './use-tree-select'\n\ntype TreeSelectProps = TreeSelectSchema['props']\n\n/** 默认插槽的载荷:展开与选中状态、可见行序列、搜索视图、多选的可见标签与折起的个数、节点状态判定与写值方法。 */\nexport type TreeSelectRootSlotProps = Pick<\n TreeSelectApi,\n | 'open'\n | 'searching'\n | 'inputValue'\n | 'value'\n | 'expandedValue'\n | 'visibleNodes'\n | 'focusedValue'\n | 'empty'\n | 'loading'\n | 'displayText'\n | 'canClear'\n | 'tags'\n | 'overflowCount'\n | 'overflowText'\n | 'isSelected'\n | 'isIndeterminate'\n | 'isExpanded'\n | 'branchLoadState'\n | 'setOpen'\n | 'setValue'\n | 'setExpandedValue'\n | 'setInputValue'\n | 'expand'\n | 'collapse'\n | 'retryBranch'\n | 'select'\n | 'clear'\n | 'deselect'\n>\n\n/** 本节点持有焦点时,value 变更重新报告焦点节点,卸载时上报焦点丢失 */\nfunction reportNodeFocus(ctx: TreeSelectContext, el: Ref<HTMLElement | null>, value: () => string): void {\n let registered: string | null = null\n watch(value, (next, prev) => {\n if (next === prev)\n return\n const { service } = ctx\n if (service.getStatus() !== 'Started')\n return\n if (el.value && service.scope.getActiveElement() === el.value)\n service.send({ type: 'NODE.FOCUS', value: next })\n if (registered !== null) {\n service.send({ type: 'NODE.UNMOUNT', value: prev })\n service.send({ type: 'NODE.MOUNT', value: next })\n registered = next\n }\n })\n onMounted(() => queueMicrotask(() => {\n if (ctx.service.getStatus() !== 'Started')\n return\n registered = value()\n ctx.service.send({ type: 'NODE.MOUNT', value: registered })\n }))\n onBeforeUnmount(() => {\n const { service } = ctx\n // 整组一起卸载时根部件先停机,此刻送事件会在 dev 下抛\n if (service.getStatus() !== 'Started')\n return\n if (registered !== null)\n service.send({ type: 'NODE.UNMOUNT', value: registered })\n // 按「本节点当下正持有焦点」判定,不按 value 比对\n if (el.value && service.scope.getActiveElement() === el.value)\n service.send({ type: 'NODE.LOST' })\n })\n}\n\nexport const XhTreeSelectRoot = defineComponent({\n name: 'XhTreeSelectRoot',\n // 有 connect 兜底的 prop:普通类型省略 default,Boolean 显式保留 undefined\n props: {\n collection: { type: Array as PropType<TreeSelectNode[]> },\n /** 完整 collection 与 Virtualizer 的焦点桥;count 必须等于当前 visibleNodes.length。 */\n virtualizer: { type: Object as PropType<CollectionVirtualizer> },\n loadChildren: { type: Function as PropType<TreeSelectProps['loadChildren']> },\n /** 标题文字。提供后不必再写 label 部件;需要放置其他内容时改用 label 插槽。 */\n label: { type: String },\n /** 自动渲染树中是否带清空按钮;手写部件不使用它,写了节点即可清空。 */\n clearable: Boolean,\n value: { type: [String, Array] as PropType<string | string[]> },\n defaultValue: { type: [String, Array] as PropType<string | string[]> },\n expandedValue: { type: Array as PropType<string[]> },\n defaultExpandedValue: { type: Array as PropType<string[]> },\n open: { type: Boolean, default: undefined },\n defaultOpen: Boolean,\n multiple: Boolean,\n /** 多选标签最多显示的数量,其余折进 +N;默认 3。 */\n maxTagCount: { type: Number },\n /** 浮层内搜索:展开时焦点先落在搜索框上,输入即把树裁到只剩命中的那几枝。 */\n searchable: Boolean,\n /** 自定义匹配规则;缺省为标签大小写不敏感包含。 */\n filter: { type: Function as PropType<TreeSelectProps['filter']> },\n cascade: Boolean,\n checkedStrategy: { type: String as PropType<TreeSelectProps['checkedStrategy']> },\n disabled: { type: Boolean, default: undefined },\n readOnly: { type: Boolean, default: undefined },\n invalid: { type: Boolean, default: undefined },\n loading: Boolean,\n variant: { type: String as PropType<ControlVariant> },\n tone: { type: String as PropType<Tone> },\n size: { type: String as PropType<Size> },\n placeholder: { type: String },\n translations: { type: Object as PropType<TreeSelectProps['translations']> },\n placement: { type: String as PropType<Placement> },\n offset: { type: Number },\n loop: { type: Boolean, default: undefined },\n dir: { type: String as PropType<Direction> },\n name: { type: String },\n form: { type: String },\n },\n // *-change 携带 details 对象,update:* 携带裸值;选中值恒为数组,单选时长度 ≤ 1\n emits: {\n 'clear': () => true,\n 'value-change': (_details: PayloadOf<TreeSelectProps, 'onValueChange'>) => true,\n 'expanded-value-change': (_details: PayloadOf<TreeSelectProps, 'onExpandedValueChange'>) => true,\n 'open-change': (_details: PayloadOf<TreeSelectProps, 'onOpenChange'>) => true,\n 'branch-load-start': (_details: PayloadOf<TreeSelectProps, 'onBranchLoadStart'>) => true,\n 'branch-load': (_details: PayloadOf<TreeSelectProps, 'onBranchLoad'>) => true,\n 'branch-load-error': (_details: PayloadOf<TreeSelectProps, 'onBranchLoadError'>) => true,\n 'update:value': (_value: PayloadOf<TreeSelectProps, 'onValueChange'>['value']) => true,\n 'update:expandedValue': (_value: PayloadOf<TreeSelectProps, 'onExpandedValueChange'>['value']) => true,\n 'update:open': (_open: PayloadOf<TreeSelectProps, 'onOpenChange'>['open']) => true,\n },\n slots: Object as SlotsType<{\n default?: (props: TreeSelectRootSlotProps) => VNode[]\n label?: () => VNode[]\n }>,\n setup(props, { slots, emit }) {\n const notifyValue: TreeSelectProps['onValueChange'] = (details) => {\n emit('value-change', details)\n emit('update:value', details.value)\n }\n const notifyExpanded: TreeSelectProps['onExpandedValueChange'] = (details) => {\n emit('expanded-value-change', details)\n emit('update:expandedValue', details.value)\n }\n const notifyOpen: TreeSelectProps['onOpenChange'] = (details) => {\n emit('open-change', details)\n emit('update:open', details.open)\n }\n const notifyBranchLoadStart: TreeSelectProps['onBranchLoadStart'] = details => emit('branch-load-start', details)\n const notifyBranchLoad: TreeSelectProps['onBranchLoad'] = details => emit('branch-load', details)\n const notifyBranchLoadError: TreeSelectProps['onBranchLoadError'] = details => emit('branch-load-error', details)\n const ctx = useTreeSelect(withHandlers(withXhConfig('tree-select', useFormControlProps(props)), { onClear: () => emit('clear') }) as TreeSelectProps, {\n onValueChange: notifyValue,\n onExpandedValueChange: notifyExpanded,\n onOpenChange: notifyOpen,\n onBranchLoadStart: notifyBranchLoadStart,\n onBranchLoad: notifyBranchLoad,\n onBranchLoadError: notifyBranchLoadError,\n })\n provideTreeSelect(ctx)\n\n return () => h('div', ctx.api.value.getRootProps() as Record<string, unknown>, slots.default\n ? slots.default({\n open: ctx.api.value.open,\n searching: ctx.api.value.searching,\n inputValue: ctx.api.value.inputValue,\n value: ctx.api.value.value,\n expandedValue: ctx.api.value.expandedValue,\n visibleNodes: ctx.api.value.visibleNodes,\n focusedValue: ctx.api.value.focusedValue,\n empty: ctx.api.value.empty,\n loading: ctx.api.value.loading,\n displayText: ctx.api.value.displayText,\n canClear: ctx.api.value.canClear,\n tags: ctx.api.value.tags,\n overflowCount: ctx.api.value.overflowCount,\n overflowText: ctx.api.value.overflowText,\n isSelected: ctx.api.value.isSelected,\n isIndeterminate: ctx.api.value.isIndeterminate,\n isExpanded: ctx.api.value.isExpanded,\n branchLoadState: ctx.api.value.branchLoadState,\n setOpen: ctx.api.value.setOpen,\n setValue: ctx.api.value.setValue,\n setExpandedValue: ctx.api.value.setExpandedValue,\n setInputValue: ctx.api.value.setInputValue,\n expand: ctx.api.value.expand,\n collapse: ctx.api.value.collapse,\n retryBranch: ctx.api.value.retryBranch,\n select: ctx.api.value.select,\n clear: ctx.api.value.clear,\n deselect: ctx.api.value.deselect,\n })\n : props.collection\n ? renderDefaultTree(\n ctx.api.value.collection,\n props.multiple ? ctx.api.value.tags : null,\n props.searchable,\n slots.label?.() ?? (props.label != null ? [props.label] : null),\n props.clearable,\n )\n : [])\n },\n})\n\nexport const XhTreeSelectLabel = defineComponent({\n name: 'XhTreeSelectLabel',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('span', ctx.api.value.getLabelProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectControl = defineComponent({\n name: 'XhTreeSelectControl',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 描边、底色与聚焦环所在的那一层,触发按钮与尾部动作钮在里面并排\n return () => h('div', {\n ...ctx.api.value.getControlProps() as Record<string, unknown>,\n ref: (el: unknown) => { ctx.controlRef.value = el as HTMLElement },\n }, slots.default?.())\n },\n})\n\nexport const XhTreeSelectTrigger = defineComponent({\n name: 'XhTreeSelectTrigger',\n setup(_, { slots }) {\n // 字段的说明与校验状态要落在真控件上,不能停在封装根的 div 上\n const fieldWiring = useFieldStateWiring()\n // 字段的标签也得并进名字链:控件自带的那条指的是它自己那个没渲染的 label 部件\n const fieldLabel = useFieldLabelWiring()\n const ctx = useTreeSelectContext()\n return () => h('button', fieldLabel.value({\n ...fieldWiring.value,\n ...ctx.api.value.getTriggerProps() as Record<string, unknown>,\n ref: (el: unknown) => { ctx.triggerRef.value = el as HTMLElement },\n }), slots.default?.())\n },\n})\n\nexport const XhTreeSelectValueText = defineComponent({\n name: 'XhTreeSelectValueText',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 有插槽用插槽,否则显示选中项文本或 placeholder\n return () => h(\n 'span',\n ctx.api.value.getValueTextProps() as Record<string, unknown>,\n slots.default?.() ?? ctx.api.value.displayText,\n )\n },\n})\n\nexport const XhTreeSelectTagList = defineComponent({\n name: 'XhTreeSelectTagList',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 标签行:可见标签与 +N 那一枚在里面并排;无选中时连接层给 hidden,value-text 回来显示占位文字\n return () => h('span', ctx.api.value.getTagListProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\n/** 标签文字所在的块(tag 的 label):截断规则挂在这一层。 */\nexport const XhTreeSelectTagLabel = defineComponent({\n name: 'XhTreeSelectTagLabel',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('span', ctx.api.value.getTagLabelProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\n/**\n * 标签内容:只有文字时替它包一层 label:截断规则挂在 label 上,直接展开在 root 上的文字过长会把\n * 删除按钮挤出;作者自己写了节点则原样放行。与 XhTagRoot 同一规则。\n * 库自身填入的文字(+N,没有折叠时是空串)恒包 label,三个适配器渲染出同一棵树。\n */\nfunction tagChildren(content: VNode[] | string | undefined): VNode[] | string | undefined {\n if (typeof content === 'string')\n return [h(XhTreeSelectTagLabel, null, () => content)]\n return slotIsPlainText(content) ? [h(XhTreeSelectTagLabel, null, () => content)] : content\n}\n\n/** 一个选中值一个标签,即库内 tag 的 root(data-scope=\"tag\"):语气、尺寸与禁用从树选择传下,形态按控件的面派生;触发器内纯展示,触发器外配合 XhTreeSelectItemDeleteTrigger 可删除。 */\nexport const XhTreeSelectTag = defineComponent({\n name: 'XhTreeSelectTag',\n props: {\n /** 它代表哪个选中值。 */\n value: { type: String, required: true },\n },\n setup(props, { slots }) {\n const ctx = useTreeSelectContext()\n provideTreeSelectTag({ value: () => props.value })\n return () => h('span', ctx.api.value.getTagProps({ value: props.value }) as Record<string, unknown>, tagChildren(slots.default?.()))\n },\n})\n\n/** 折叠的标签合成的一个标签:同样是 tag 的 root;有插槽时使用插槽,否则显示 +N。没有折叠的标签时连接层写 hidden。 */\nexport const XhTreeSelectOverflowTag = defineComponent({\n name: 'XhTreeSelectOverflowTag',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h(\n 'span',\n ctx.api.value.getOverflowTagProps() as Record<string, unknown>,\n tagChildren(slots.default?.() ?? ctx.api.value.overflowText),\n )\n },\n})\n\n/** 标签中的删除按钮:即所在标签那份 tag 的 close-trigger(data-scope=\"tag\"),可及名使用 translations.deleteItem;点按移除所在标签的选中值。 */\nexport const XhTreeSelectItemDeleteTrigger = defineComponent({\n name: 'XhTreeSelectItemDeleteTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const tag = useTreeSelectTagContext()\n return () => h('button', ctx.api.value.getItemDeleteTriggerProps({ value: tag.value() }) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectIndicator = defineComponent({\n name: 'XhTreeSelectIndicator',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('span', ctx.api.value.getIndicatorProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectClearTrigger = defineComponent({\n name: 'XhTreeSelectClearTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('button', ctx.api.value.getClearTriggerProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectPositioner = defineComponent({\n name: 'XhTreeSelectPositioner',\n props: {\n /** 本实例的 Portal 容器;优先于应用级配置。 */\n container: { type: Object as PropType<Element> },\n },\n // 根是 Teleport,Vue 不会把直通属性合上去,作者写的 class 与 style 得自己接住落到 positioner 上\n inheritAttrs: false,\n setup(props, { slots, attrs }) {\n const ctx = useTreeSelectContext()\n // 树的自绘条:与 content 同级、绝对定位不占布局,壳是这层已经 fixed 的 positioner。\n // 两条轴都摆:深层节点靠缩进往行末推,横向溢出与纵向一样是常态。\n // 横条的正负按排版方向算,而组件不读计算样式,把 positioner 上那份显式交过去\n const bars = useScrollbars({\n // 虚拟窗口的滚动层是 Virtualizer 的视口,条子跟着它走\n scrollable: () => ctx.service.prop('virtualizer')?.getViewportElement() ?? ctx.treeRef.value,\n axes: ['vertical', 'horizontal'],\n // 条子走浮层 4px 档\n props: () => ({ dir: (ctx.api.value.getPositionerProps() as { dir?: Direction }).dir, size: 'sm' }),\n })\n // 搬到 portal 落点:留在原地的话,宿主祖先只要建了层叠上下文就能盖住浮层\n return () => h(XhPortal, { to: props.container ?? ctx.portalTarget.value, source: ctx.triggerRef, present: ctx.visible.value }, () => [\n h('div', {\n ...mergeProps(ctx.api.value.getPositionerProps() as Record<string, unknown>, attrs),\n ref: (el: unknown) => { ctx.positionerRef.value = el as HTMLElement },\n }, [...(slots.default?.() ?? []), ...bars.render()]),\n ])\n },\n})\n\nconst XhTreeSelectAutoEmpty = defineComponent({\n name: 'XhTreeSelectAutoEmpty',\n setup() {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n // 搜索视图里的空是「没有匹配」,与整棵树没有节点分开说\n return () => content.authoredEmptyCount.value > 0\n ? null\n : h('div', {\n ...ctx.api.value.getEmptyProps() as Record<string, unknown>,\n 'data-xh-tree-select-auto-empty': '',\n }, ctx.api.value.searching ? ctx.api.value.translations.noMatch : ctx.api.value.translations.empty)\n },\n})\n\nconst XhTreeSelectAutoLoading = defineComponent({\n name: 'XhTreeSelectAutoLoading',\n setup() {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n return () => content.authoredLoadingCount.value > 0\n ? null\n : h('div', {\n ...ctx.api.value.getLoadingProps() as Record<string, unknown>,\n 'data-xh-tree-select-auto-loading': '',\n }, ctx.api.value.translations.loading)\n },\n})\n\nexport const XhTreeSelectContent = defineComponent({\n name: 'XhTreeSelectContent',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const authoredEmptyCount = ref(0)\n const authoredLoadingCount = ref(0)\n const register = (count: Ref<number>): (() => void) => {\n count.value += 1\n let active = true\n return () => {\n if (!active)\n return\n active = false\n count.value -= 1\n }\n }\n provideTreeSelectContent({\n authoredEmptyCount,\n authoredLoadingCount,\n registerEmpty: () => register(authoredEmptyCount),\n registerLoading: () => register(authoredLoadingCount),\n })\n // 收起时只隐藏不卸载\n return () => h('div', {\n ...ctx.api.value.getContentProps() as Record<string, unknown>,\n // 收起跟着退场闸门走:皮肤刻意没给 content 补 [hidden]{display:none}(补了退场\n // 就一帧都播不出来),所以真正的收起落成内联 display——节点始终留在原地\n style: ctx.visible.value ? undefined : { display: 'none' },\n ref: (el: unknown) => { ctx.contentRef.value = el as HTMLElement },\n }, [slots.default?.(), h(XhTreeSelectAutoEmpty), h(XhTreeSelectAutoLoading)])\n },\n})\n\n/** 浮层内搜索框:放在 content 中、tree 之前;没开 searchable 时带 hidden。 */\nexport const XhTreeSelectInput = defineComponent({\n name: 'XhTreeSelectInput',\n setup() {\n const ctx = useTreeSelectContext()\n return () => h('input', ctx.api.value.getInputProps() as Record<string, unknown>)\n },\n})\n\nexport const XhTreeSelectTree = defineComponent({\n name: 'XhTreeSelectTree',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n return () => h('div', {\n ...ctx.api.value.getTreeProps() as Record<string, unknown>,\n ref: (el: unknown) => { ctx.treeRef.value = el as HTMLElement | null },\n }, slots.default?.())\n },\n})\n\nexport const XhTreeSelectItem = defineComponent({\n name: 'XhTreeSelectItem',\n props: {\n value: { type: String, required: true },\n },\n setup(props, { slots }) {\n const ctx = useTreeSelectContext()\n const node = computed<TreeSelectNodeProps>(() => ({ value: props.value }))\n provideTreeSelectNode({ node })\n const el = ref<HTMLElement | null>(null)\n reportNodeFocus(ctx, el, () => props.value)\n return () => h(\n 'div',\n { ...ctx.api.value.getItemProps(node.value) as Record<string, unknown>, ref: el },\n slots.default?.(),\n )\n },\n})\n\nexport const XhTreeSelectItemText = defineComponent({\n name: 'XhTreeSelectItemText',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemTextProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\n/** 条目的第 2 行副文本,跨文字槽、走 muted 档 */\nexport const XhTreeSelectItemDescription = defineComponent({\n name: 'XhTreeSelectItemDescription',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemDescriptionProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\n/** 条目行尾的作者内容(计数、徽标) */\nexport const XhTreeSelectItemSuffix = defineComponent({\n name: 'XhTreeSelectItemSuffix',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemSuffixProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectItemIndicator = defineComponent({\n name: 'XhTreeSelectItemIndicator',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getItemIndicatorProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nfunction renderBranchFeedback(ctx: TreeSelectContext, node: TreeSelectNodeProps): VNode[] {\n if (ctx.api.value.branchLoadState(node.value) == null)\n return []\n return [\n h('div', ctx.api.value.getBranchLoadingProps(node) as Record<string, unknown>, ctx.api.value.translations.loading),\n h('div', ctx.api.value.getBranchErrorProps(node) as Record<string, unknown>, ctx.api.value.translations.branchError),\n h('button', ctx.api.value.getBranchRetryTriggerProps(node) as Record<string, unknown>, ctx.api.value.translations.retry),\n h('div', ctx.api.value.getBranchEmptyProps(node) as Record<string, unknown>, ctx.api.value.translations.branchEmpty),\n ]\n}\n\nexport const XhTreeSelectBranch = defineComponent({\n name: 'XhTreeSelectBranch',\n props: {\n value: { type: String, required: true },\n },\n setup(props, { slots }) {\n const ctx = useTreeSelectContext()\n const node = computed<TreeSelectNodeProps>(() => ({ value: props.value }))\n // 分支自身也是 treeitem,供其子部件读取;子节点各自再 provide 一层\n provideTreeSelectNode({ node })\n const el = ref<HTMLElement | null>(null)\n reportNodeFocus(ctx, el, () => props.value)\n return () => h(\n 'div',\n { ...ctx.api.value.getBranchProps(node.value) as Record<string, unknown>, ref: el },\n [slots.default?.(), ...renderBranchFeedback(ctx, node.value)],\n )\n },\n})\n\nexport const XhTreeSelectBranchControl = defineComponent({\n name: 'XhTreeSelectBranchControl',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchControlProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchTrigger = defineComponent({\n name: 'XhTreeSelectBranchTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getBranchTriggerProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchIndicator = defineComponent({\n name: 'XhTreeSelectBranchIndicator',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getBranchIndicatorProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchText = defineComponent({\n name: 'XhTreeSelectBranchText',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('span', ctx.api.value.getBranchTextProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchContent = defineComponent({\n name: 'XhTreeSelectBranchContent',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n // 收起只加 hidden,不卸载子树节点\n return () => h('div', ctx.api.value.getBranchContentProps(node.value) as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectBranchLoading = defineComponent({\n name: 'XhTreeSelectBranchLoading',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchLoadingProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.loading)\n },\n})\n\nexport const XhTreeSelectBranchError = defineComponent({\n name: 'XhTreeSelectBranchError',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchErrorProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.branchError)\n },\n})\n\nexport const XhTreeSelectBranchRetryTrigger = defineComponent({\n name: 'XhTreeSelectBranchRetryTrigger',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('button', ctx.api.value.getBranchRetryTriggerProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.retry)\n },\n})\n\nexport const XhTreeSelectBranchEmpty = defineComponent({\n name: 'XhTreeSelectBranchEmpty',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const { node } = useTreeSelectNodeContext()\n return () => h('div', ctx.api.value.getBranchEmptyProps(node.value) as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.branchEmpty)\n },\n})\n\nexport const XhTreeSelectEmpty = defineComponent({\n name: 'XhTreeSelectEmpty',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n const unregister = content.registerEmpty()\n onBeforeUnmount(unregister)\n return () => h('div', ctx.api.value.getEmptyProps() as Record<string, unknown>, slots.default?.() ?? (ctx.api.value.searching ? ctx.api.value.translations.noMatch : ctx.api.value.translations.empty))\n },\n})\n\nexport const XhTreeSelectLoading = defineComponent({\n name: 'XhTreeSelectLoading',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n const content = useTreeSelectContentContext()\n const unregister = content.registerLoading()\n onBeforeUnmount(unregister)\n return () => h('div', ctx.api.value.getLoadingProps() as Record<string, unknown>, slots.default?.() ?? ctx.api.value.translations.loading)\n },\n})\n\nexport const XhTreeSelectFooter = defineComponent({\n name: 'XhTreeSelectFooter',\n setup(_, { slots }) {\n const ctx = useTreeSelectContext()\n // 浮层底部的操作区:写在 content 里、tree 的兄弟,\n // 放在这里的按钮既不进 role=tree 的拥有关系,也走不到方向键与连打检索\n return () => h('div', ctx.api.value.getFooterProps() as Record<string, unknown>, slots.default?.())\n },\n})\n\nexport const XhTreeSelectHiddenInput = defineComponent({\n name: 'XhTreeSelectHiddenInput',\n inheritAttrs: false,\n setup(_, { attrs }) {\n const ctx = useTreeSelectContext()\n // 表单出口,不写这个部件即不参与表单提交\n // 合并而不是展开:作者的 class 与部件的挂载类拼起来,不互相覆盖\n return () => ctx.api.value.value.map(value => h('input', {\n ...mergeProps(ctx.api.value.getHiddenInputProps({ value }) as Record<string, unknown>, attrs),\n key: value,\n }))\n },\n})\n\n/** 按 collection 递归铺设节点:带 children 的渲染为 branch,其余渲染为 item。 */\nfunction renderNodes(nodes: readonly TreeSelectNode[]): VNode[] {\n return nodes.map(node => (node.children || node.hasChildren)\n ? h(XhTreeSelectBranch, { key: node.value, value: node.value }, () => [\n h(XhTreeSelectBranchControl, null, () => [\n h(XhTreeSelectBranchTrigger),\n h(XhTreeSelectBranchText, null, () => node.label ?? node.value),\n h(XhTreeSelectItemIndicator),\n ]),\n h(XhTreeSelectBranchContent, null, () => renderNodes(node.children ?? [])),\n ])\n : h(XhTreeSelectItem, { key: node.value, value: node.value }, () => [\n h(XhTreeSelectItemIndicator),\n h(XhTreeSelectItemText, null, () => node.label ?? node.value),\n ]))\n}\n\n/**\n * 未写默认插槽时按 collection 铺开的整套结构,作者只提供数据。\n * 与手写部件产出的 DOM 完全一致,需要修改结构时写默认插槽,行为不变。\n */\nfunction renderDefaultTree(\n collection: readonly TreeSelectNode[],\n tags: readonly TreeSelectTagMeta[] | null,\n searchable: boolean,\n label: (VNode | string)[] | null,\n clearable: boolean,\n): VNode[] {\n return [\n ...(label ? [h(XhTreeSelectLabel, null, () => label)] : []),\n // 盒里放触发器;清空钮是触发器的兄弟(按钮不能套按钮)\n h(XhTreeSelectControl, null, () => [\n // 多选的已选项在触发器里排成标签:占位文字与标签行同时写着,有选中时标签露面、占位让位;\n // 触发器里的标签只作展示(按钮不能套按钮),摆不下的折进 +N\n h(XhTreeSelectTrigger, null, () => [\n h(XhTreeSelectValueText),\n ...(tags\n ? [h(XhTreeSelectTagList, null, () => [\n ...tags.map(tag => h(XhTreeSelectTag, { key: tag.value, value: tag.value }, () => tag.label)),\n h(XhTreeSelectOverflowTag),\n ])]\n : []),\n h(XhTreeSelectIndicator),\n ]),\n ...(clearable ? [h(XhTreeSelectClearTrigger)] : []),\n ]),\n h(XhTreeSelectPositioner, null, () => [\n // 开了搜索时搜索框排在树之前;collection 此刻已是裁剪后的树\n h(XhTreeSelectContent, null, () => [\n ...(searchable ? [h(XhTreeSelectInput)] : []),\n h(XhTreeSelectTree, null, () => renderNodes(collection)),\n ]),\n ]),\n ]\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { XhLocale, deDE, enUS, esES, frFR, jaJP, koKR, ptBR, ruRU, zhCN, zhTW } from "@xihan-ui/headless/locale";
2
+ export { type XhLocale, deDE, enUS, esES, frFR, jaJP, koKR, ptBR, ruRU, zhCN, zhTW };
package/dist/locale.js ADDED
@@ -0,0 +1,2 @@
1
+ import { deDE, enUS, esES, frFR, jaJP, koKR, ptBR, ruRU, zhCN, zhTW } from "@xihan-ui/headless/locale";
2
+ export { deDE, enUS, esES, frFR, jaJP, koKR, ptBR, ruRU, zhCN, zhTW };
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "3.1.0";
2
+ var version = "3.2.0";
3
3
  //#endregion
4
4
  export { version };
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { mergePartProps } from "./merge-props.js";
2
- import { Comment, Fragment, Text, cloneVNode } from "vue";
3
- import { isEventHandlerKey } from "@xihan-ui/core";
2
+ import { Comment, Fragment, Text, cloneVNode, normalizeClass } from "vue";
3
+ import { isEventHandlerKey, stripScopeClass } from "@xihan-ui/core";
4
4
  //#region src/runtime/as-child.ts
5
5
  /**
6
6
  * asChild:部件不再渲染自己的包裹元素,把应挂载的属性合并到作者提供的子节点上。
@@ -67,6 +67,11 @@ function mergeIntoChild(nodes, props, scope, options = {}) {
67
67
  const keepAnatomy = !!options.applyAnatomy || !carriesOwnAnatomy(child);
68
68
  for (const [key, value] of Object.entries(props)) {
69
69
  if (!keepAnatomy && isRoleMarker(key)) continue;
70
+ if (!keepAnatomy && key === "class") {
71
+ const extra = stripScopeClass(normalizeClass(value));
72
+ if (extra) merged.class = extra;
73
+ continue;
74
+ }
70
75
  merged[key] = value;
71
76
  }
72
77
  if (typeof merged.ref === "function") {
@@ -1 +1 @@
1
- {"version":3,"file":"as-child.js","names":[],"sources":["../../src/runtime/as-child.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 as child 相关实现。\n\nimport type { VNode, VNodeChild } from 'vue'\nimport { isEventHandlerKey } from '@xihan-ui/core'\nimport { cloneVNode, Comment, Fragment, Text } from 'vue'\nimport { mergePartProps } from './merge-props'\n\n/**\n * asChild:部件不再渲染自己的包裹元素,把应挂载的属性合并到作者提供的子节点上。\n *\n * 触发器类部件默认渲染 <button>,作者需要用自己的按钮作为触发器时,只能在 <button> 中再嵌套一个\n * <button>:那是非法嵌套,浏览器会拆开它,事件与焦点都不正确。asChild 是唯一的正确方式。\n */\n\n/** 只忽略注释、空白与空占位;片段内的可见文本同样必须明确拒绝。 */\nfunction attributable(nodes: readonly VNodeChild[], scope: string): VNode[] {\n const out: VNode[] = []\n for (const node of nodes) {\n if (node == null || typeof node === 'boolean')\n continue\n if (Array.isArray(node)) {\n out.push(...attributable(node, scope))\n continue\n }\n if (typeof node === 'string' || typeof node === 'number') {\n if (typeof node === 'string' && node.trim() === '')\n continue\n throw new Error(`[xh] ${scope} asChild 需要恰好一个可挂载子节点,不能包含非空文本`)\n }\n if (node.type === Comment)\n continue\n if (node.type === Text) {\n if (String(node.children ?? '').trim() === '')\n continue\n throw new Error(`[xh] ${scope} asChild 需要恰好一个可挂载子节点,不能包含非空文本`)\n }\n if (node.type === Fragment && Array.isArray(node.children))\n out.push(...attributable(node.children as VNodeChild[], scope))\n else\n out.push(node)\n }\n return out\n}\n\n/** 子节点已带角色标记:组件节点的根由它自己渲染,元素节点检查是否写了 data-scope。 */\nexport function carriesOwnAnatomy(node: VNode): boolean {\n return typeof node.type !== 'string' || node.props?.['data-scope'] != null\n}\n\n/**\n * 角色标记:解剖两位、家族标记(data-xh-*)与随视觉盒走的形态轴(data-variant)。\n * 子节点自带解剖时这些都不该落到它身上:家族标记会在封装自己的视觉盒外再画一层壳,\n * 形态轴会盖掉封装根上作者写的那一档。\n */\nexport function isRoleMarker(key: string): boolean {\n return key === 'data-scope' || key === 'data-part' || key === 'data-variant' || key.startsWith('data-xh-')\n}\n\n/**\n * 元素 ref 解包:子节点是组件时 ref 得到的是组件实例,触发器需要的是它的根元素。\n * 组件多根时 $el 是占位注释,该类子节点本就不适合作为触发器,原样交出由定位层报错。\n */\nfunction unwrapElement(value: unknown): unknown {\n if (value && typeof value === 'object' && '$el' in value)\n return (value as { $el: unknown }).$el\n return value\n}\n\nexport interface MergeIntoChildOptions {\n /**\n * 子节点是组件时缺省视作自带解剖,只落接线属性。路由链接这类只把属性转交给自己渲出元素的封装没有自己的解剖,\n * 置 true 让部件的解剖与家族标记照样落上去。\n */\n applyAnatomy?: boolean\n}\n\n/**\n * 把部件属性合并到作者的子节点上。\n * @param nodes 默认插槽产出\n * @param props 部件该挂的属性(含 ref)\n * @param scope 部件所属组件名,只用于诊断文案\n * @param options 解剖标记的落法\n * @returns 合并后的节点;子节点不合规时抛错\n */\nexport function mergeIntoChild(\n nodes: readonly VNode[] | undefined,\n props: Record<string, unknown>,\n scope: string,\n options: MergeIntoChildOptions = {},\n): VNode {\n const candidates = attributable(nodes ?? [], scope)\n if (candidates.length !== 1)\n throw new Error(`[xh] ${scope} asChild 需要恰好一个可挂载子节点,实际是 ${candidates.length} 个`)\n const child = candidates[0]!\n\n // 子节点自带解剖标记时不覆盖它,只落接线属性;否则整套属性都给它\n const merged: Record<string, unknown> = {}\n const keepAnatomy = !!options.applyAnatomy || !carriesOwnAnatomy(child)\n for (const [key, value] of Object.entries(props)) {\n if (!keepAnatomy && isRoleMarker(key))\n continue\n merged[key] = value\n }\n if (typeof merged.ref === 'function') {\n const inner = merged.ref as (el: unknown) => void\n merged.ref = (value: unknown) => inner(unwrapElement(value))\n }\n // 第三个参数让两边的 ref 都保留:作者自己的 ref 与部件的 ref 各拿各的。\n // cloneVNode 把子节点自己的同名处理器排在传进来这一份的前面,也就是作者先跑、部件后跑;\n // 传进来的 props 已经把写在部件上的那一份按同一个先后合过(mergePartProps),\n // 所以写在子节点上还是写在部件上,作者的处理器都在部件之前。\n const cloned = cloneVNode(child, merged, true)\n // cloneVNode 默认无条件串接事件;改用作者可取消的部件合并,其他属性和双方 ref 保留。\n const events = mergePartProps(merged, child.props ?? {})\n for (const key of Object.keys(events)) {\n if (isEventHandlerKey(key))\n cloned.props![key] = events[key]\n }\n return cloned\n}\n"],"mappings":";;;;;;;;;;;AAoBA,SAAS,aAAa,OAA8B,OAAwB;CAC1E,MAAM,MAAe,CAAC;CACtB,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAClC;EACF,IAAI,MAAM,QAAQ,IAAI,GAAG;GACvB,IAAI,KAAK,GAAG,aAAa,MAAM,KAAK,CAAC;GACrC;EACF;EACA,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;GACxD,IAAI,OAAO,SAAS,YAAY,KAAK,KAAK,MAAM,IAC9C;GACF,MAAM,IAAI,MAAM,QAAQ,MAAM,+BAA+B;EAC/D;EACA,IAAI,KAAK,SAAS,SAChB;EACF,IAAI,KAAK,SAAS,MAAM;GACtB,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC,CAAC,KAAK,MAAM,IACzC;GACF,MAAM,IAAI,MAAM,QAAQ,MAAM,+BAA+B;EAC/D;EACA,IAAI,KAAK,SAAS,YAAY,MAAM,QAAQ,KAAK,QAAQ,GACvD,IAAI,KAAK,GAAG,aAAa,KAAK,UAA0B,KAAK,CAAC;OAE9D,IAAI,KAAK,IAAI;CACjB;CACA,OAAO;AACT;;AAGA,SAAgB,kBAAkB,MAAsB;CACtD,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,QAAQ,iBAAiB;AACxE;;;;;;AAOA,SAAgB,aAAa,KAAsB;CACjD,OAAO,QAAQ,gBAAgB,QAAQ,eAAe,QAAQ,kBAAkB,IAAI,WAAW,UAAU;AAC3G;;;;;AAMA,SAAS,cAAc,OAAyB;CAC9C,IAAI,SAAS,OAAO,UAAU,YAAY,SAAS,OACjD,OAAQ,MAA2B;CACrC,OAAO;AACT;;;;;;;;;AAkBA,SAAgB,eACd,OACA,OACA,OACA,UAAiC,CAAC,GAC3B;CACP,MAAM,aAAa,aAAa,SAAS,CAAC,GAAG,KAAK;CAClD,IAAI,WAAW,WAAW,GACxB,MAAM,IAAI,MAAM,QAAQ,MAAM,4BAA4B,WAAW,OAAO,GAAG;CACjF,MAAM,QAAQ,WAAW;CAGzB,MAAM,SAAkC,CAAC;CACzC,MAAM,cAAc,CAAC,CAAC,QAAQ,gBAAgB,CAAC,kBAAkB,KAAK;CACtE,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;EAChD,IAAI,CAAC,eAAe,aAAa,GAAG,GAClC;EACF,OAAO,OAAO;CAChB;CACA,IAAI,OAAO,OAAO,QAAQ,YAAY;EACpC,MAAM,QAAQ,OAAO;EACrB,OAAO,OAAO,UAAmB,MAAM,cAAc,KAAK,CAAC;CAC7D;CAKA,MAAM,SAAS,WAAW,OAAO,QAAQ,IAAI;CAE7C,MAAM,SAAS,eAAe,QAAQ,MAAM,SAAS,CAAC,CAAC;CACvD,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAClC,IAAI,kBAAkB,GAAG,GACvB,OAAO,MAAO,OAAO,OAAO;CAEhC,OAAO;AACT"}
1
+ {"version":3,"file":"as-child.js","names":[],"sources":["../../src/runtime/as-child.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 as child 相关实现。\n\nimport type { VNode, VNodeChild } from 'vue'\nimport { isEventHandlerKey, stripScopeClass } from '@xihan-ui/core'\nimport { cloneVNode, Comment, Fragment, normalizeClass, Text } from 'vue'\nimport { mergePartProps } from './merge-props'\n\n/**\n * asChild:部件不再渲染自己的包裹元素,把应挂载的属性合并到作者提供的子节点上。\n *\n * 触发器类部件默认渲染 <button>,作者需要用自己的按钮作为触发器时,只能在 <button> 中再嵌套一个\n * <button>:那是非法嵌套,浏览器会拆开它,事件与焦点都不正确。asChild 是唯一的正确方式。\n */\n\n/** 只忽略注释、空白与空占位;片段内的可见文本同样必须明确拒绝。 */\nfunction attributable(nodes: readonly VNodeChild[], scope: string): VNode[] {\n const out: VNode[] = []\n for (const node of nodes) {\n if (node == null || typeof node === 'boolean')\n continue\n if (Array.isArray(node)) {\n out.push(...attributable(node, scope))\n continue\n }\n if (typeof node === 'string' || typeof node === 'number') {\n if (typeof node === 'string' && node.trim() === '')\n continue\n throw new Error(`[xh] ${scope} asChild 需要恰好一个可挂载子节点,不能包含非空文本`)\n }\n if (node.type === Comment)\n continue\n if (node.type === Text) {\n if (String(node.children ?? '').trim() === '')\n continue\n throw new Error(`[xh] ${scope} asChild 需要恰好一个可挂载子节点,不能包含非空文本`)\n }\n if (node.type === Fragment && Array.isArray(node.children))\n out.push(...attributable(node.children as VNodeChild[], scope))\n else\n out.push(node)\n }\n return out\n}\n\n/** 子节点已带角色标记:组件节点的根由它自己渲染,元素节点检查是否写了 data-scope。 */\nexport function carriesOwnAnatomy(node: VNode): boolean {\n return typeof node.type !== 'string' || node.props?.['data-scope'] != null\n}\n\n/**\n * 角色标记:解剖两位、家族标记(data-xh-*)与随视觉盒走的形态轴(data-variant)。\n * 子节点自带解剖时这些都不该落到它身上:家族标记会在封装自己的视觉盒外再画一层壳,\n * 形态轴会盖掉封装根上作者写的那一档。\n */\nexport function isRoleMarker(key: string): boolean {\n return key === 'data-scope' || key === 'data-part' || key === 'data-variant' || key.startsWith('data-xh-')\n}\n\n/**\n * 元素 ref 解包:子节点是组件时 ref 得到的是组件实例,触发器需要的是它的根元素。\n * 组件多根时 $el 是占位注释,该类子节点本就不适合作为触发器,原样交出由定位层报错。\n */\nfunction unwrapElement(value: unknown): unknown {\n if (value && typeof value === 'object' && '$el' in value)\n return (value as { $el: unknown }).$el\n return value\n}\n\nexport interface MergeIntoChildOptions {\n /**\n * 子节点是组件时缺省视作自带解剖,只落接线属性。路由链接这类只把属性转交给自己渲出元素的封装没有自己的解剖,\n * 置 true 让部件的解剖与家族标记照样落上去。\n */\n applyAnatomy?: boolean\n}\n\n/**\n * 把部件属性合并到作者的子节点上。\n * @param nodes 默认插槽产出\n * @param props 部件该挂的属性(含 ref)\n * @param scope 部件所属组件名,只用于诊断文案\n * @param options 解剖标记的落法\n * @returns 合并后的节点;子节点不合规时抛错\n */\nexport function mergeIntoChild(\n nodes: readonly VNode[] | undefined,\n props: Record<string, unknown>,\n scope: string,\n options: MergeIntoChildOptions = {},\n): VNode {\n const candidates = attributable(nodes ?? [], scope)\n if (candidates.length !== 1)\n throw new Error(`[xh] ${scope} asChild 需要恰好一个可挂载子节点,实际是 ${candidates.length} 个`)\n const child = candidates[0]!\n\n // 子节点自带解剖标记时不覆盖它,只落接线属性;否则整套属性都给它\n const merged: Record<string, unknown> = {}\n const keepAnatomy = !!options.applyAnatomy || !carriesOwnAnatomy(child)\n for (const [key, value] of Object.entries(props)) {\n if (!keepAnatomy && isRoleMarker(key))\n continue\n // 挂载类随 data-scope 一起让位:作者写的类照合,部件那份的 xh-scope-* 不落到别人的根上\n if (!keepAnatomy && key === 'class') {\n const extra = stripScopeClass(normalizeClass(value))\n if (extra)\n merged.class = extra\n continue\n }\n merged[key] = value\n }\n if (typeof merged.ref === 'function') {\n const inner = merged.ref as (el: unknown) => void\n merged.ref = (value: unknown) => inner(unwrapElement(value))\n }\n // 第三个参数让两边的 ref 都保留:作者自己的 ref 与部件的 ref 各拿各的。\n // cloneVNode 把子节点自己的同名处理器排在传进来这一份的前面,也就是作者先跑、部件后跑;\n // 传进来的 props 已经把写在部件上的那一份按同一个先后合过(mergePartProps),\n // 所以写在子节点上还是写在部件上,作者的处理器都在部件之前。\n const cloned = cloneVNode(child, merged, true)\n // cloneVNode 默认无条件串接事件;改用作者可取消的部件合并,其他属性和双方 ref 保留。\n const events = mergePartProps(merged, child.props ?? {})\n for (const key of Object.keys(events)) {\n if (isEventHandlerKey(key))\n cloned.props![key] = events[key]\n }\n return cloned\n}\n"],"mappings":";;;;;;;;;;;AAoBA,SAAS,aAAa,OAA8B,OAAwB;CAC1E,MAAM,MAAe,CAAC;CACtB,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAClC;EACF,IAAI,MAAM,QAAQ,IAAI,GAAG;GACvB,IAAI,KAAK,GAAG,aAAa,MAAM,KAAK,CAAC;GACrC;EACF;EACA,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;GACxD,IAAI,OAAO,SAAS,YAAY,KAAK,KAAK,MAAM,IAC9C;GACF,MAAM,IAAI,MAAM,QAAQ,MAAM,+BAA+B;EAC/D;EACA,IAAI,KAAK,SAAS,SAChB;EACF,IAAI,KAAK,SAAS,MAAM;GACtB,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC,CAAC,KAAK,MAAM,IACzC;GACF,MAAM,IAAI,MAAM,QAAQ,MAAM,+BAA+B;EAC/D;EACA,IAAI,KAAK,SAAS,YAAY,MAAM,QAAQ,KAAK,QAAQ,GACvD,IAAI,KAAK,GAAG,aAAa,KAAK,UAA0B,KAAK,CAAC;OAE9D,IAAI,KAAK,IAAI;CACjB;CACA,OAAO;AACT;;AAGA,SAAgB,kBAAkB,MAAsB;CACtD,OAAO,OAAO,KAAK,SAAS,YAAY,KAAK,QAAQ,iBAAiB;AACxE;;;;;;AAOA,SAAgB,aAAa,KAAsB;CACjD,OAAO,QAAQ,gBAAgB,QAAQ,eAAe,QAAQ,kBAAkB,IAAI,WAAW,UAAU;AAC3G;;;;;AAMA,SAAS,cAAc,OAAyB;CAC9C,IAAI,SAAS,OAAO,UAAU,YAAY,SAAS,OACjD,OAAQ,MAA2B;CACrC,OAAO;AACT;;;;;;;;;AAkBA,SAAgB,eACd,OACA,OACA,OACA,UAAiC,CAAC,GAC3B;CACP,MAAM,aAAa,aAAa,SAAS,CAAC,GAAG,KAAK;CAClD,IAAI,WAAW,WAAW,GACxB,MAAM,IAAI,MAAM,QAAQ,MAAM,4BAA4B,WAAW,OAAO,GAAG;CACjF,MAAM,QAAQ,WAAW;CAGzB,MAAM,SAAkC,CAAC;CACzC,MAAM,cAAc,CAAC,CAAC,QAAQ,gBAAgB,CAAC,kBAAkB,KAAK;CACtE,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;EAChD,IAAI,CAAC,eAAe,aAAa,GAAG,GAClC;EAEF,IAAI,CAAC,eAAe,QAAQ,SAAS;GACnC,MAAM,QAAQ,gBAAgB,eAAe,KAAK,CAAC;GACnD,IAAI,OACF,OAAO,QAAQ;GACjB;EACF;EACA,OAAO,OAAO;CAChB;CACA,IAAI,OAAO,OAAO,QAAQ,YAAY;EACpC,MAAM,QAAQ,OAAO;EACrB,OAAO,OAAO,UAAmB,MAAM,cAAc,KAAK,CAAC;CAC7D;CAKA,MAAM,SAAS,WAAW,OAAO,QAAQ,IAAI;CAE7C,MAAM,SAAS,eAAe,QAAQ,MAAM,SAAS,CAAC,CAAC;CACvD,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAClC,IAAI,kBAAkB,GAAG,GACvB,OAAO,MAAO,OAAO,OAAO;CAEhC,OAAO;AACT"}
@@ -19,6 +19,15 @@ const XhPortal = defineComponent({
19
19
  source: {
20
20
  type: Object,
21
21
  default: void 0
22
+ },
23
+ /**
24
+ * 浮层此刻是否呈现(展开中,或退场动画还没播完)。为假时不建视觉桥:关着的浮层壳里只有藏起来的
25
+ * 内容,而每台桥都要在来源整条祖先链上挂观察、建时读一遍计算样式,页面上几十个关着的提示与下拉
26
+ * 白付这笔账,缓存页一进一出还要各重算一遍。缺省为真:常显、或展开才渲染的落点照旧随挂载建桥。
27
+ */
28
+ present: {
29
+ type: Boolean,
30
+ default: true
22
31
  }
23
32
  },
24
33
  setup(props, { slots }) {
@@ -31,7 +40,7 @@ const XhPortal = defineComponent({
31
40
  bridge = null;
32
41
  const source = props.source?.value ?? sourceRef.value;
33
42
  const shell = shellRef.value;
34
- if (!source || !shell) return;
43
+ if (!source || !shell || !props.present) return;
35
44
  bridge = createPortalVisualBridge({
36
45
  source,
37
46
  shell
@@ -44,6 +53,7 @@ const XhPortal = defineComponent({
44
53
  () => props.to,
45
54
  () => props.disabled
46
55
  ], connect, { flush: "post" });
56
+ watch(() => props.present, connect, { flush: "pre" });
47
57
  onBeforeUnmount(() => {
48
58
  bridge?.dispose();
49
59
  bridge = null;
@@ -1 +1 @@
1
- {"version":3,"file":"portal.js","names":[],"sources":["../../src/runtime/portal.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 portal 相关实现。\n\nimport type { PortalVisualBridge } from '@xihan-ui/core'\nimport type { PropType, Ref, VNode } from 'vue'\nimport { createPortalVisualBridge } from '@xihan-ui/core'\nimport { defineComponent, h, onBeforeUnmount, ref, Teleport, watch } from 'vue'\nimport { clearFieldContext } from '../components/field/context'\n\n/**\n * Vue 内部 Portal:Teleport 只负责物理搬运,本层为每个实例增加无盒壳并桥接逻辑来源的视觉轴。\n * 不公开成组件家族;所有浮层部件统一经这里走。\n */\nexport const XhPortal = defineComponent({\n name: 'XhPortal',\n props: {\n to: { type: [String, Object] as PropType<string | Element>, required: true },\n /** 客户端来源节点尚未落定时先原地渲染,绑定所属 Document 后再迁移到正式目标。 */\n disabled: Boolean,\n /** 已有锚点时直接作为逻辑来源,避免在结构敏感的 ButtonGroup/Toolbar 里增加元素标记。 */\n source: { type: Object as PropType<Readonly<Ref<HTMLElement | null>>>, default: undefined },\n },\n setup(props, { slots }) {\n // 浮层内容搬到落点后不再是外层字段的控件:放在里面的输入框不被外层字段命名、描述,也不拿同一个 id。\n // 与 Web Components 一致:那边的 Portal 把节点物理搬走,字段按 DOM 祖先链找控件,本来就够不着\n clearFieldContext()\n const sourceRef = ref<HTMLTemplateElement | null>(null)\n const shellRef = ref<HTMLElement | null>(null)\n let bridge: PortalVisualBridge | null = null\n\n const connect = (): void => {\n bridge?.dispose()\n bridge = null\n const source = props.source?.value ?? sourceRef.value\n const shell = shellRef.value\n if (!source || !shell)\n return\n bridge = createPortalVisualBridge({ source, shell })\n }\n\n watch([sourceRef, shellRef, () => props.source?.value, () => props.to, () => props.disabled], connect, { flush: 'post' })\n onBeforeUnmount(() => {\n bridge?.dispose()\n bridge = null\n })\n\n return (): VNode | VNode[] => [\n ...(props.source ? [] : [h('template', { 'ref': sourceRef, 'data-xh-portal-source': '' })]),\n h(Teleport, { to: props.to, disabled: props.disabled }, [\n h('div', {\n 'ref': shellRef,\n 'data-xh-portal-shell': '',\n 'style': { display: 'contents' },\n }, slots.default?.()),\n ]),\n ]\n },\n})\n"],"mappings":";;;;;;;;AAiBA,MAAa,WAAW,gBAAgB;CACtC,MAAM;CACN,OAAO;EACL,IAAI;GAAE,MAAM,CAAC,QAAQ,MAAM;GAAiC,UAAU;EAAK;;EAE3E,UAAU;;EAEV,QAAQ;GAAE,MAAM;GAAuD,SAAS,KAAA;EAAU;CAC5F;CACA,MAAM,OAAO,EAAE,SAAS;EAGtB,kBAAkB;EAClB,MAAM,YAAY,IAAgC,IAAI;EACtD,MAAM,WAAW,IAAwB,IAAI;EAC7C,IAAI,SAAoC;EAExC,MAAM,gBAAsB;GAC1B,QAAQ,QAAQ;GAChB,SAAS;GACT,MAAM,SAAS,MAAM,QAAQ,SAAS,UAAU;GAChD,MAAM,QAAQ,SAAS;GACvB,IAAI,CAAC,UAAU,CAAC,OACd;GACF,SAAS,yBAAyB;IAAE;IAAQ;GAAM,CAAC;EACrD;EAEA,MAAM;GAAC;GAAW;SAAgB,MAAM,QAAQ;SAAa,MAAM;SAAU,MAAM;EAAQ,GAAG,SAAS,EAAE,OAAO,OAAO,CAAC;EACxH,sBAAsB;GACpB,QAAQ,QAAQ;GAChB,SAAS;EACX,CAAC;EAED,aAA8B,CAC5B,GAAI,MAAM,SAAS,CAAC,IAAI,CAAC,EAAE,YAAY;GAAE,OAAO;GAAW,yBAAyB;EAAG,CAAC,CAAC,GACzF,EAAE,UAAU;GAAE,IAAI,MAAM;GAAI,UAAU,MAAM;EAAS,GAAG,CACtD,EAAE,OAAO;GACP,OAAO;GACP,wBAAwB;GACxB,SAAS,EAAE,SAAS,WAAW;EACjC,GAAG,MAAM,UAAU,CAAC,CACtB,CAAC,CACH;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"portal.js","names":[],"sources":["../../src/runtime/portal.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 portal 相关实现。\n\nimport type { PortalVisualBridge } from '@xihan-ui/core'\nimport type { PropType, Ref, VNode } from 'vue'\nimport { createPortalVisualBridge } from '@xihan-ui/core'\nimport { defineComponent, h, onBeforeUnmount, ref, Teleport, watch } from 'vue'\nimport { clearFieldContext } from '../components/field/context'\n\n/**\n * Vue 内部 Portal:Teleport 只负责物理搬运,本层为每个实例增加无盒壳并桥接逻辑来源的视觉轴。\n * 不公开成组件家族;所有浮层部件统一经这里走。\n */\nexport const XhPortal = defineComponent({\n name: 'XhPortal',\n props: {\n to: { type: [String, Object] as PropType<string | Element>, required: true },\n /** 客户端来源节点尚未落定时先原地渲染,绑定所属 Document 后再迁移到正式目标。 */\n disabled: Boolean,\n /** 已有锚点时直接作为逻辑来源,避免在结构敏感的 ButtonGroup/Toolbar 里增加元素标记。 */\n source: { type: Object as PropType<Readonly<Ref<HTMLElement | null>>>, default: undefined },\n /**\n * 浮层此刻是否呈现(展开中,或退场动画还没播完)。为假时不建视觉桥:关着的浮层壳里只有藏起来的\n * 内容,而每台桥都要在来源整条祖先链上挂观察、建时读一遍计算样式,页面上几十个关着的提示与下拉\n * 白付这笔账,缓存页一进一出还要各重算一遍。缺省为真:常显、或展开才渲染的落点照旧随挂载建桥。\n */\n present: { type: Boolean, default: true },\n },\n setup(props, { slots }) {\n // 浮层内容搬到落点后不再是外层字段的控件:放在里面的输入框不被外层字段命名、描述,也不拿同一个 id。\n // 与 Web Components 一致:那边的 Portal 把节点物理搬走,字段按 DOM 祖先链找控件,本来就够不着\n clearFieldContext()\n const sourceRef = ref<HTMLTemplateElement | null>(null)\n const shellRef = ref<HTMLElement | null>(null)\n let bridge: PortalVisualBridge | null = null\n\n const connect = (): void => {\n bridge?.dispose()\n bridge = null\n const source = props.source?.value ?? sourceRef.value\n const shell = shellRef.value\n if (!source || !shell || !props.present)\n return\n bridge = createPortalVisualBridge({ source, shell })\n }\n\n watch([sourceRef, shellRef, () => props.source?.value, () => props.to, () => props.disabled], connect, { flush: 'post' })\n // 来源与壳在挂载时就已就位,转为呈现时赶在本轮渲染之前建桥:内容第一次排版、定位引擎第一次\n // 量尺寸时,壳上已经是来源的环境(密度、方向、主题),不会先按落点的环境量一遍再跳\n watch(() => props.present, connect, { flush: 'pre' })\n onBeforeUnmount(() => {\n bridge?.dispose()\n bridge = null\n })\n\n return (): VNode | VNode[] => [\n ...(props.source ? [] : [h('template', { 'ref': sourceRef, 'data-xh-portal-source': '' })]),\n h(Teleport, { to: props.to, disabled: props.disabled }, [\n h('div', {\n 'ref': shellRef,\n 'data-xh-portal-shell': '',\n 'style': { display: 'contents' },\n }, slots.default?.()),\n ]),\n ]\n },\n})\n"],"mappings":";;;;;;;;AAiBA,MAAa,WAAW,gBAAgB;CACtC,MAAM;CACN,OAAO;EACL,IAAI;GAAE,MAAM,CAAC,QAAQ,MAAM;GAAiC,UAAU;EAAK;;EAE3E,UAAU;;EAEV,QAAQ;GAAE,MAAM;GAAuD,SAAS,KAAA;EAAU;;;;;;EAM1F,SAAS;GAAE,MAAM;GAAS,SAAS;EAAK;CAC1C;CACA,MAAM,OAAO,EAAE,SAAS;EAGtB,kBAAkB;EAClB,MAAM,YAAY,IAAgC,IAAI;EACtD,MAAM,WAAW,IAAwB,IAAI;EAC7C,IAAI,SAAoC;EAExC,MAAM,gBAAsB;GAC1B,QAAQ,QAAQ;GAChB,SAAS;GACT,MAAM,SAAS,MAAM,QAAQ,SAAS,UAAU;GAChD,MAAM,QAAQ,SAAS;GACvB,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,SAC9B;GACF,SAAS,yBAAyB;IAAE;IAAQ;GAAM,CAAC;EACrD;EAEA,MAAM;GAAC;GAAW;SAAgB,MAAM,QAAQ;SAAa,MAAM;SAAU,MAAM;EAAQ,GAAG,SAAS,EAAE,OAAO,OAAO,CAAC;EAGxH,YAAY,MAAM,SAAS,SAAS,EAAE,OAAO,MAAM,CAAC;EACpD,sBAAsB;GACpB,QAAQ,QAAQ;GAChB,SAAS;EACX,CAAC;EAED,aAA8B,CAC5B,GAAI,MAAM,SAAS,CAAC,IAAI,CAAC,EAAE,YAAY;GAAE,OAAO;GAAW,yBAAyB;EAAG,CAAC,CAAC,GACzF,EAAE,UAAU;GAAE,IAAI,MAAM;GAAI,UAAU,MAAM;EAAS,GAAG,CACtD,EAAE,OAAO;GACP,OAAO;GACP,wBAAwB;GACxB,SAAS,EAAE,SAAS,WAAW;EACjC,GAAG,MAAM,UAAU,CAAC,CACtB,CAAC,CACH;CACF;AACF,CAAC"}
@@ -2,6 +2,11 @@ import { getCurrentInstance, isRef, onBeforeUnmount, onMounted, ref, toValue, wa
2
2
  import { attachCssExit, createPresence } from "@xihan-ui/core/presence";
3
3
  //#region src/runtime/use-overlay-exit.ts
4
4
  /**
5
+ * 退场播完却不卸载的浮层(unmountOnExit 为 false)收起定位层用的属性。
6
+ * 皮肤给定位层声明过 display,UA 的 [hidden]{display:none} 压不住,只能写内联。
7
+ */
8
+ const OVERLAY_STOWED_PROPS = { style: { display: "none" } };
9
+ /**
5
10
  * 返回当前是否应当可见。作者把它覆盖到 content 的 `hidden` 上:
6
11
  * `{ ...api.getContentProps(), hidden: !visible.value || undefined }`。
7
12
  */
@@ -60,6 +65,6 @@ function useOverlayExit(options) {
60
65
  return visible;
61
66
  }
62
67
  //#endregion
63
- export { useOverlayExit };
68
+ export { OVERLAY_STOWED_PROPS, useOverlayExit };
64
69
 
65
70
  //# sourceMappingURL=use-overlay-exit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-overlay-exit.js","names":[],"sources":["../../src/runtime/use-overlay-exit.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 use overlay exit 相关实现。\n\nimport type { RuntimeConfig } from '@xihan-ui/core'\nimport type { PresenceHandle } from '@xihan-ui/core/presence'\nimport type { MaybeRefOrGetter, Ref } from 'vue'\nimport { attachCssExit, createPresence } from '@xihan-ui/core/presence'\nimport { getCurrentInstance, isRef, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\n// 退场闸门:把「几时真的收起浮层」从展开态挪到 presence 上。\n//\n// 连接层给 content 打的 `hidden` 是跟着 open 走的——收起那一帧节点就不生成盒子了,\n// 退场动画一帧都播不出来。这里把它改成跟着 presence 走:展开时可见、退场动画播完之前\n// 也可见,播完才真收。作者节点始终留在原地,被拉长的是「可见的时间」而不是「存在的时间」。\n//\n// 所有带退场的部件共用这一件:dialog / drawer / command / image-viewer 的遮罩经 additionalExitRefs\n// 一并计入,轻提示与通知卡片也经它把 Presence 交给机器。\n\nexport interface OverlayExitOptions {\n /**\n * 运行时配置,只用来区分有没有 DOM:服务端没有退场可言,传 null 即退化为可见与否跟随展开态。\n * 客户端必须等真实根节点才能确定 realm 时传 ref/getter;挂载后仍为空会明确失败。\n */\n config: MaybeRefOrGetter<RuntimeConfig | null>\n /** 当前逻辑上是否展开。 */\n isOpen: () => boolean\n /** content 节点,退场动画从它上面探测。 */\n contentRef: Ref<HTMLElement | null>\n /** 与 content 共同决定退出完成的其他真实视觉节点。 */\n additionalExitRefs?: Array<Ref<HTMLElement | null>>\n /** Presence 建立后交给需要共用退出生命周期的 Headless 状态机;卸载时回传 null。 */\n onPresence?: (presence: PresenceHandle | null) => void\n}\n\n/**\n * 返回当前是否应当可见。作者把它覆盖到 content 的 `hidden` 上:\n * `{ ...api.getContentProps(), hidden: !visible.value || undefined }`。\n */\nexport function useOverlayExit(options: OverlayExitOptions): Ref<boolean> {\n const { isOpen, contentRef } = options\n const visible = ref(isOpen())\n let presence: PresenceHandle | null = null\n const tracked = new Map<HTMLElement, () => void>()\n let stopOpen: (() => void) | undefined\n let stopContent: (() => void) | undefined\n\n const start = (config: RuntimeConfig | null): void => {\n if (!config) {\n stopOpen = watch(isOpen, (open) => {\n visible.value = open\n })\n return\n }\n\n presence = createPresence({\n open: isOpen(),\n onRenderedChange: (rendered) => {\n visible.value = rendered\n },\n })\n options.onPresence?.(presence)\n visible.value = presence.rendered\n\n // data-state 提交到 DOM 之后再驱动 presence,让退场探测读到正确的 animationName\n stopOpen = watch(isOpen, open => presence?.update(open), { flush: 'post' })\n\n // 延迟配置到挂载期才就绪时 content 已经存在,immediate 负责补上首次 attach。\n stopContent = watch([contentRef, ...(options.additionalExitRefs ?? [])], (nodes) => {\n const next = new Set(nodes.filter((node): node is HTMLElement => node !== null))\n for (const node of next) {\n if (!tracked.has(node))\n tracked.set(node, attachCssExit(node, presence!))\n }\n for (const [node, detach] of tracked) {\n if (!next.has(node)) {\n tracked.delete(node)\n detach()\n }\n }\n }, { flush: 'post', immediate: true })\n }\n\n const initial = toValue(options.config)\n const delayed = isRef(options.config) || typeof options.config === 'function'\n if (initial || !delayed) {\n start(initial)\n }\n else if (getCurrentInstance()) {\n onMounted(() => {\n const config = toValue(options.config)\n if (!config)\n throw new Error('[xh] useOverlayExit 的延迟 RuntimeConfig 在挂载后仍未就绪')\n start(config)\n })\n }\n else {\n throw new Error('[xh] useOverlayExit 的延迟 RuntimeConfig 只能在 Vue setup 生命周期内使用')\n }\n\n onBeforeUnmount(() => {\n stopOpen?.()\n stopContent?.()\n for (const detach of tracked.values()) detach()\n tracked.clear()\n presence?.dispose()\n options.onPresence?.(null)\n })\n\n return visible\n}\n"],"mappings":";;;;;;;AA0CA,SAAgB,eAAe,SAA2C;CACxE,MAAM,EAAE,QAAQ,eAAe;CAC/B,MAAM,UAAU,IAAI,OAAO,CAAC;CAC5B,IAAI,WAAkC;CACtC,MAAM,0BAAU,IAAI,IAA6B;CACjD,IAAI;CACJ,IAAI;CAEJ,MAAM,SAAS,WAAuC;EACpD,IAAI,CAAC,QAAQ;GACX,WAAW,MAAM,SAAS,SAAS;IACjC,QAAQ,QAAQ;GAClB,CAAC;GACD;EACF;EAEA,WAAW,eAAe;GACxB,MAAM,OAAO;GACb,mBAAmB,aAAa;IAC9B,QAAQ,QAAQ;GAClB;EACF,CAAC;EACD,QAAQ,aAAa,QAAQ;EAC7B,QAAQ,QAAQ,SAAS;EAGzB,WAAW,MAAM,SAAQ,SAAQ,UAAU,OAAO,IAAI,GAAG,EAAE,OAAO,OAAO,CAAC;EAG1E,cAAc,MAAM,CAAC,YAAY,GAAI,QAAQ,sBAAsB,CAAC,CAAE,IAAI,UAAU;GAClF,MAAM,OAAO,IAAI,IAAI,MAAM,QAAQ,SAA8B,SAAS,IAAI,CAAC;GAC/E,KAAK,MAAM,QAAQ,MACjB,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,QAAQ,IAAI,MAAM,cAAc,MAAM,QAAS,CAAC;GAEpD,KAAK,MAAM,CAAC,MAAM,WAAW,SAC3B,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG;IACnB,QAAQ,OAAO,IAAI;IACnB,OAAO;GACT;EAEJ,GAAG;GAAE,OAAO;GAAQ,WAAW;EAAK,CAAC;CACvC;CAEA,MAAM,UAAU,QAAQ,QAAQ,MAAM;CACtC,MAAM,UAAU,MAAM,QAAQ,MAAM,KAAK,OAAO,QAAQ,WAAW;CACnE,IAAI,WAAW,CAAC,SACd,MAAM,OAAO;MAEV,IAAI,mBAAmB,GAC1B,gBAAgB;EACd,MAAM,SAAS,QAAQ,QAAQ,MAAM;EACrC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,gDAAgD;EAClE,MAAM,MAAM;CACd,CAAC;MAGD,MAAM,IAAI,MAAM,6DAA6D;CAG/E,sBAAsB;EACpB,WAAW;EACX,cAAc;EACd,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,OAAO;EAC9C,QAAQ,MAAM;EACd,UAAU,QAAQ;EAClB,QAAQ,aAAa,IAAI;CAC3B,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"use-overlay-exit.js","names":[],"sources":["../../src/runtime/use-overlay-exit.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-Present XiHanFun and contributors.\n * Licensed under the MIT License. See LICENSE in the project root for license information.\n */\n\n// 提供 use overlay exit 相关实现。\n\nimport type { RuntimeConfig } from '@xihan-ui/core'\nimport type { PresenceHandle } from '@xihan-ui/core/presence'\nimport type { MaybeRefOrGetter, Ref } from 'vue'\nimport { attachCssExit, createPresence } from '@xihan-ui/core/presence'\nimport { getCurrentInstance, isRef, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\n// 退场闸门:把「几时真的收起浮层」从展开态挪到 presence 上。\n//\n// 连接层给 content 打的 `hidden` 是跟着 open 走的——收起那一帧节点就不生成盒子了,\n// 退场动画一帧都播不出来。这里把它改成跟着 presence 走:展开时可见、退场动画播完之前\n// 也可见,播完才真收。作者节点始终留在原地,被拉长的是「可见的时间」而不是「存在的时间」。\n//\n// 所有带退场的部件共用这一件:dialog / drawer / command / image-viewer 的遮罩经 additionalExitRefs\n// 一并计入,轻提示与通知卡片也经它把 Presence 交给机器。\n\n/**\n * 退场播完却不卸载的浮层(unmountOnExit 为 false)收起定位层用的属性。\n * 皮肤给定位层声明过 display,UA 的 [hidden]{display:none} 压不住,只能写内联。\n */\nexport const OVERLAY_STOWED_PROPS = { style: { display: 'none' } } as const\n\nexport interface OverlayExitOptions {\n /**\n * 运行时配置,只用来区分有没有 DOM:服务端没有退场可言,传 null 即退化为可见与否跟随展开态。\n * 客户端必须等真实根节点才能确定 realm 时传 ref/getter;挂载后仍为空会明确失败。\n */\n config: MaybeRefOrGetter<RuntimeConfig | null>\n /** 当前逻辑上是否展开。 */\n isOpen: () => boolean\n /** content 节点,退场动画从它上面探测。 */\n contentRef: Ref<HTMLElement | null>\n /** 与 content 共同决定退出完成的其他真实视觉节点。 */\n additionalExitRefs?: Array<Ref<HTMLElement | null>>\n /** Presence 建立后交给需要共用退出生命周期的 Headless 状态机;卸载时回传 null。 */\n onPresence?: (presence: PresenceHandle | null) => void\n}\n\n/**\n * 返回当前是否应当可见。作者把它覆盖到 content 的 `hidden` 上:\n * `{ ...api.getContentProps(), hidden: !visible.value || undefined }`。\n */\nexport function useOverlayExit(options: OverlayExitOptions): Ref<boolean> {\n const { isOpen, contentRef } = options\n const visible = ref(isOpen())\n let presence: PresenceHandle | null = null\n const tracked = new Map<HTMLElement, () => void>()\n let stopOpen: (() => void) | undefined\n let stopContent: (() => void) | undefined\n\n const start = (config: RuntimeConfig | null): void => {\n if (!config) {\n stopOpen = watch(isOpen, (open) => {\n visible.value = open\n })\n return\n }\n\n presence = createPresence({\n open: isOpen(),\n onRenderedChange: (rendered) => {\n visible.value = rendered\n },\n })\n options.onPresence?.(presence)\n visible.value = presence.rendered\n\n // data-state 提交到 DOM 之后再驱动 presence,让退场探测读到正确的 animationName\n stopOpen = watch(isOpen, open => presence?.update(open), { flush: 'post' })\n\n // 延迟配置到挂载期才就绪时 content 已经存在,immediate 负责补上首次 attach。\n stopContent = watch([contentRef, ...(options.additionalExitRefs ?? [])], (nodes) => {\n const next = new Set(nodes.filter((node): node is HTMLElement => node !== null))\n for (const node of next) {\n if (!tracked.has(node))\n tracked.set(node, attachCssExit(node, presence!))\n }\n for (const [node, detach] of tracked) {\n if (!next.has(node)) {\n tracked.delete(node)\n detach()\n }\n }\n }, { flush: 'post', immediate: true })\n }\n\n const initial = toValue(options.config)\n const delayed = isRef(options.config) || typeof options.config === 'function'\n if (initial || !delayed) {\n start(initial)\n }\n else if (getCurrentInstance()) {\n onMounted(() => {\n const config = toValue(options.config)\n if (!config)\n throw new Error('[xh] useOverlayExit 的延迟 RuntimeConfig 在挂载后仍未就绪')\n start(config)\n })\n }\n else {\n throw new Error('[xh] useOverlayExit 的延迟 RuntimeConfig 只能在 Vue setup 生命周期内使用')\n }\n\n onBeforeUnmount(() => {\n stopOpen?.()\n stopContent?.()\n for (const detach of tracked.values()) detach()\n tracked.clear()\n presence?.dispose()\n options.onPresence?.(null)\n })\n\n return visible\n}\n"],"mappings":";;;;;;;AA0BA,MAAa,uBAAuB,EAAE,OAAO,EAAE,SAAS,OAAO,EAAE;;;;;AAsBjE,SAAgB,eAAe,SAA2C;CACxE,MAAM,EAAE,QAAQ,eAAe;CAC/B,MAAM,UAAU,IAAI,OAAO,CAAC;CAC5B,IAAI,WAAkC;CACtC,MAAM,0BAAU,IAAI,IAA6B;CACjD,IAAI;CACJ,IAAI;CAEJ,MAAM,SAAS,WAAuC;EACpD,IAAI,CAAC,QAAQ;GACX,WAAW,MAAM,SAAS,SAAS;IACjC,QAAQ,QAAQ;GAClB,CAAC;GACD;EACF;EAEA,WAAW,eAAe;GACxB,MAAM,OAAO;GACb,mBAAmB,aAAa;IAC9B,QAAQ,QAAQ;GAClB;EACF,CAAC;EACD,QAAQ,aAAa,QAAQ;EAC7B,QAAQ,QAAQ,SAAS;EAGzB,WAAW,MAAM,SAAQ,SAAQ,UAAU,OAAO,IAAI,GAAG,EAAE,OAAO,OAAO,CAAC;EAG1E,cAAc,MAAM,CAAC,YAAY,GAAI,QAAQ,sBAAsB,CAAC,CAAE,IAAI,UAAU;GAClF,MAAM,OAAO,IAAI,IAAI,MAAM,QAAQ,SAA8B,SAAS,IAAI,CAAC;GAC/E,KAAK,MAAM,QAAQ,MACjB,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,QAAQ,IAAI,MAAM,cAAc,MAAM,QAAS,CAAC;GAEpD,KAAK,MAAM,CAAC,MAAM,WAAW,SAC3B,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG;IACnB,QAAQ,OAAO,IAAI;IACnB,OAAO;GACT;EAEJ,GAAG;GAAE,OAAO;GAAQ,WAAW;EAAK,CAAC;CACvC;CAEA,MAAM,UAAU,QAAQ,QAAQ,MAAM;CACtC,MAAM,UAAU,MAAM,QAAQ,MAAM,KAAK,OAAO,QAAQ,WAAW;CACnE,IAAI,WAAW,CAAC,SACd,MAAM,OAAO;MAEV,IAAI,mBAAmB,GAC1B,gBAAgB;EACd,MAAM,SAAS,QAAQ,QAAQ,MAAM;EACrC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,gDAAgD;EAClE,MAAM,MAAM;CACd,CAAC;MAGD,MAAM,IAAI,MAAM,6DAA6D;CAG/E,sBAAsB;EACpB,WAAW;EACX,cAAc;EACd,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG,OAAO;EAC9C,QAAQ,MAAM;EACd,UAAU,QAAQ;EAClB,QAAQ,aAAa,IAAI;CAC3B,CAAC;CAED,OAAO;AACT"}
@@ -43,11 +43,11 @@ interface PromptOptions<T extends object> extends Omit<ConfirmOptions, 'onOk' |
43
43
  onOk?: (value: T) => boolean | void | Promise<boolean | void>;
44
44
  }
45
45
  interface DialogServiceOptions {
46
- /** 确认按钮文案,默认 OK。 */
46
+ /** 确认按钮文案;未提供时取 config 里 translations.dialog.ok,再退英文语言包(OK)。 */
47
47
  okText?: MaybeRefOrGetter<string>;
48
- /** 取消按钮文案,默认 Cancel。 */
48
+ /** 取消按钮文案;未提供时取 translations.dialog.cancel,再退英文语言包(Cancel)。 */
49
49
  cancelText?: MaybeRefOrGetter<string>;
50
- /** 动作失败时的安全提示,支持与按钮文案相同的响应式来源。 */
50
+ /** 动作失败时的安全提示,支持与按钮文案相同的响应式来源;未提供时取 translations.dialog.actionError。 */
51
51
  actionErrorText?: MaybeRefOrGetter<string>;
52
52
  /**
53
53
  * 提供给对话框子树的全局配置(locale / translations / size / portalContainer)。
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-service.d.ts","names":[],"sources":["../../src/services/dialog-service.ts"],"mappings":";;;;;;;;;;;;KA4BY,6BAA6B;;UAGxB;EACf;;UAGe;EACf;EACA,UAAU;;EAEV,OAAO;;EAEP,QAAQ;EACR,SAAS;EACT,aAAa;;EAEb,8BAA8B;;EAE9B,iBAAiB,OAAO,6BAA6B;;;KAI3C,eAAe,KAAK;;UAGf,cAAc,0BAA0B,KAAK;;EAE5D,cAAc;;EAEd,OAAO,OAAO,MAAM;;EAEpB;;EAEA,QAAQ,OAAO,uBAAuB;;UAGvB;;EAEf,SAAS;;EAET,aAAa;;EAEb,kBAAkB;;;;;;EAMlB,SAAS,iBAAiB;;EAE1B,SAAS;;UAGM;;WAEN,aAAa;;EAEtB,UAAU,SAAS,mBAAmB;EACtC,OAAO,SAAS,iBAAiB;EACjC,UAAU,SAAS,iBAAiB;EACpC,UAAU,SAAS,iBAAiB;EACpC,QAAQ,SAAS,iBAAiB;;EAElC,SAAS,kBAAkB,SAAS,cAAc,OAAO,QAAQ;;EAEjE,YAAY,MAAM,iBAAiB;;EAEnC;;iBAqBc,oBAAoB,UAAS,uBAA4B"}
1
+ {"version":3,"file":"dialog-service.d.ts","names":[],"sources":["../../src/services/dialog-service.ts"],"mappings":";;;;;;;;;;;;KA4BY,6BAA6B;;UAGxB;EACf;;UAGe;EACf;EACA,UAAU;;EAEV,OAAO;;EAEP,QAAQ;EACR,SAAS;EACT,aAAa;;EAEb,8BAA8B;;EAE9B,iBAAiB,OAAO,6BAA6B;;;KAI3C,eAAe,KAAK;;UAGf,cAAc,0BAA0B,KAAK;;EAE5D,cAAc;;EAEd,OAAO,OAAO,MAAM;;EAEpB;;EAEA,QAAQ,OAAO,uBAAuB;;UAGvB;;EAEf,SAAS;;EAET,aAAa;;EAEb,kBAAkB;;;;;;EAMlB,SAAS,iBAAiB;;EAE1B,SAAS;;UAGM;;WAEN,aAAa;;EAEtB,UAAU,SAAS,mBAAmB;EACtC,OAAO,SAAS,iBAAiB;EACjC,UAAU,SAAS,iBAAiB;EACpC,UAAU,SAAS,iBAAiB;EACpC,QAAQ,SAAS,iBAAiB;;EAElC,SAAS,kBAAkB,SAAS,cAAc,OAAO,QAAQ;;EAEjE,YAAY,MAAM,iBAAiB;;EAEnC;;iBAsBc,oBAAoB,UAAS,uBAA4B"}
@@ -4,13 +4,13 @@ import { spinArc } from "./glyph.js";
4
4
  import { createServiceConfig } from "./service-config.js";
5
5
  import { createApp, defineComponent, h, reactive, shallowRef, toRaw, toValue } from "vue";
6
6
  import { ensurePortalRoot } from "@xihan-ui/core";
7
- import { createDialogServiceController, dialogServiceBadgeTone } from "@xihan-ui/headless";
7
+ import { createDialogServiceController, dialogServiceBadgeTone, dialogServiceTranslations } from "@xihan-ui/headless";
8
8
  //#region src/services/dialog-service.ts
9
9
  function createDialogService(options = {}) {
10
10
  if (typeof document === "undefined") throw new Error("createDialogService 需要 document;SSR 里请等到客户端再创建");
11
11
  const defaults = {
12
- okText: options.okText ?? "OK",
13
- cancelText: options.cancelText ?? "Cancel"
12
+ okText: options.okText,
13
+ cancelText: options.cancelText
14
14
  };
15
15
  const configSource = createServiceConfig(options.config);
16
16
  const holder = options.target ?? document.createElement("div");
@@ -39,6 +39,8 @@ function createDialogService(options = {}) {
39
39
  if (serviceState.failure) return null;
40
40
  const request = serviceState.current;
41
41
  const spec = request?.spec;
42
+ const text = dialogServiceTranslations(configSource.read()?.translations?.dialog);
43
+ const okText = toValue(spec?.okText) ?? text.ok;
42
44
  return h(XhDialogRoot, {
43
45
  "open": serviceState.open,
44
46
  "onUpdate:open": onOpenChange,
@@ -56,18 +58,18 @@ function createDialogService(options = {}) {
56
58
  serviceState.actionError ? h("p", {
57
59
  role: "alert",
58
60
  style: { color: "var(--xh-fg-danger)" }
59
- }, toValue(options.actionErrorText) ?? "Action failed. Please try again.") : null
61
+ }, toValue(options.actionErrorText) ?? text.actionError) : null
60
62
  ]),
61
63
  h(XhDialogFooter, null, () => [spec.showCancel ? h(XhButton, {
62
64
  variant: "ghost",
63
65
  disabled: serviceState.busy,
64
66
  onClick: () => controller.close(false)
65
- }, () => toValue(spec.cancelText)) : null, h(XhButton, {
67
+ }, () => toValue(spec.cancelText) ?? text.cancel) : null, h(XhButton, {
66
68
  variant: "solid",
67
69
  tone: spec.tone,
68
70
  loading: serviceState.busy,
69
71
  onClick: controller.confirmCurrent
70
- }, () => [serviceState.busy ? h(XhButtonIndicator, () => spinArc()) : null, h(XhButtonLabel, () => serviceState.busy ? `${toValue(spec.okText)}…` : toValue(spec.okText))])])
72
+ }, () => [serviceState.busy ? h(XhButtonIndicator, () => spinArc()) : null, h(XhButtonLabel, () => serviceState.busy ? `${okText}…` : okText)])])
71
73
  ]) : null);
72
74
  };
73
75
  }