@schemx/element-plus 0.0.1-beta.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 (184) hide show
  1. package/README.md +151 -0
  2. package/dist/__tests__/exports.test.d.ts +2 -0
  3. package/dist/__tests__/exports.test.d.ts.map +1 -0
  4. package/dist/__tests__/layout.test.d.ts +2 -0
  5. package/dist/__tests__/layout.test.d.ts.map +1 -0
  6. package/dist/__tests__/renderer-components.test.d.ts +2 -0
  7. package/dist/__tests__/renderer-components.test.d.ts.map +1 -0
  8. package/dist/__tests__/sensitive-input.test.d.ts +2 -0
  9. package/dist/__tests__/sensitive-input.test.d.ts.map +1 -0
  10. package/dist/__tests__/types/layout.types.d.ts +2 -0
  11. package/dist/__tests__/types/layout.types.d.ts.map +1 -0
  12. package/dist/__tests__/types/rendererProps.types.d.ts +2 -0
  13. package/dist/__tests__/types/rendererProps.types.d.ts.map +1 -0
  14. package/dist/analyze.html +4949 -0
  15. package/dist/config/defaultConfig.d.ts +6 -0
  16. package/dist/config/defaultConfig.d.ts.map +1 -0
  17. package/dist/index.cjs +2 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.ts +20 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.mjs +3 -0
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/layout/defaultCol.d.ts +59 -0
  24. package/dist/layout/defaultCol.d.ts.map +1 -0
  25. package/dist/layout/defaultRow.d.ts +11 -0
  26. package/dist/layout/defaultRow.d.ts.map +1 -0
  27. package/dist/renderers/AutocompleteRenderer/index.d.ts +5 -0
  28. package/dist/renderers/AutocompleteRenderer/index.d.ts.map +1 -0
  29. package/dist/renderers/AutocompleteRenderer/index.vue.d.ts +48 -0
  30. package/dist/renderers/AutocompleteRenderer/index.vue.d.ts.map +1 -0
  31. package/dist/renderers/AutocompleteRenderer/types.d.ts +41 -0
  32. package/dist/renderers/AutocompleteRenderer/types.d.ts.map +1 -0
  33. package/dist/renderers/CascaderRenderer/index.d.ts +5 -0
  34. package/dist/renderers/CascaderRenderer/index.d.ts.map +1 -0
  35. package/dist/renderers/CascaderRenderer/index.vue.d.ts +29 -0
  36. package/dist/renderers/CascaderRenderer/index.vue.d.ts.map +1 -0
  37. package/dist/renderers/CascaderRenderer/types.d.ts +24 -0
  38. package/dist/renderers/CascaderRenderer/types.d.ts.map +1 -0
  39. package/dist/renderers/CheckboxRenderer/index.d.ts +5 -0
  40. package/dist/renderers/CheckboxRenderer/index.d.ts.map +1 -0
  41. package/dist/renderers/CheckboxRenderer/index.vue.d.ts +21 -0
  42. package/dist/renderers/CheckboxRenderer/index.vue.d.ts.map +1 -0
  43. package/dist/renderers/CheckboxRenderer/types.d.ts +24 -0
  44. package/dist/renderers/CheckboxRenderer/types.d.ts.map +1 -0
  45. package/dist/renderers/ColorPickerRenderer/index.d.ts +4 -0
  46. package/dist/renderers/ColorPickerRenderer/index.d.ts.map +1 -0
  47. package/dist/renderers/ColorPickerRenderer/index.vue.d.ts +25 -0
  48. package/dist/renderers/ColorPickerRenderer/index.vue.d.ts.map +1 -0
  49. package/dist/renderers/ColorPickerRenderer/types.d.ts +24 -0
  50. package/dist/renderers/ColorPickerRenderer/types.d.ts.map +1 -0
  51. package/dist/renderers/DatePickerRenderer/index.d.ts +4 -0
  52. package/dist/renderers/DatePickerRenderer/index.d.ts.map +1 -0
  53. package/dist/renderers/DatePickerRenderer/index.vue.d.ts +26 -0
  54. package/dist/renderers/DatePickerRenderer/index.vue.d.ts.map +1 -0
  55. package/dist/renderers/DatePickerRenderer/types.d.ts +20 -0
  56. package/dist/renderers/DatePickerRenderer/types.d.ts.map +1 -0
  57. package/dist/renderers/DateTimePickerRenderer/index.d.ts +4 -0
  58. package/dist/renderers/DateTimePickerRenderer/index.d.ts.map +1 -0
  59. package/dist/renderers/DateTimePickerRenderer/index.vue.d.ts +26 -0
  60. package/dist/renderers/DateTimePickerRenderer/index.vue.d.ts.map +1 -0
  61. package/dist/renderers/DateTimePickerRenderer/types.d.ts +25 -0
  62. package/dist/renderers/DateTimePickerRenderer/types.d.ts.map +1 -0
  63. package/dist/renderers/InputNumberRenderer/index.d.ts +4 -0
  64. package/dist/renderers/InputNumberRenderer/index.d.ts.map +1 -0
  65. package/dist/renderers/InputNumberRenderer/index.vue.d.ts +25 -0
  66. package/dist/renderers/InputNumberRenderer/index.vue.d.ts.map +1 -0
  67. package/dist/renderers/InputNumberRenderer/types.d.ts +20 -0
  68. package/dist/renderers/InputNumberRenderer/types.d.ts.map +1 -0
  69. package/dist/renderers/InputOtpRenderer/index.d.ts +4 -0
  70. package/dist/renderers/InputOtpRenderer/index.d.ts.map +1 -0
  71. package/dist/renderers/InputOtpRenderer/index.vue.d.ts +32 -0
  72. package/dist/renderers/InputOtpRenderer/index.vue.d.ts.map +1 -0
  73. package/dist/renderers/InputOtpRenderer/types.d.ts +22 -0
  74. package/dist/renderers/InputOtpRenderer/types.d.ts.map +1 -0
  75. package/dist/renderers/InputRenderer/index.d.ts +4 -0
  76. package/dist/renderers/InputRenderer/index.d.ts.map +1 -0
  77. package/dist/renderers/InputRenderer/index.vue.d.ts +46 -0
  78. package/dist/renderers/InputRenderer/index.vue.d.ts.map +1 -0
  79. package/dist/renderers/InputRenderer/types.d.ts +26 -0
  80. package/dist/renderers/InputRenderer/types.d.ts.map +1 -0
  81. package/dist/renderers/InputTagRenderer/index.d.ts +4 -0
  82. package/dist/renderers/InputTagRenderer/index.d.ts.map +1 -0
  83. package/dist/renderers/InputTagRenderer/index.vue.d.ts +42 -0
  84. package/dist/renderers/InputTagRenderer/index.vue.d.ts.map +1 -0
  85. package/dist/renderers/InputTagRenderer/types.d.ts +26 -0
  86. package/dist/renderers/InputTagRenderer/types.d.ts.map +1 -0
  87. package/dist/renderers/MentionRenderer/index.d.ts +5 -0
  88. package/dist/renderers/MentionRenderer/index.d.ts.map +1 -0
  89. package/dist/renderers/MentionRenderer/index.vue.d.ts +57 -0
  90. package/dist/renderers/MentionRenderer/index.vue.d.ts.map +1 -0
  91. package/dist/renderers/MentionRenderer/types.d.ts +34 -0
  92. package/dist/renderers/MentionRenderer/types.d.ts.map +1 -0
  93. package/dist/renderers/RadioRenderer/index.d.ts +5 -0
  94. package/dist/renderers/RadioRenderer/index.d.ts.map +1 -0
  95. package/dist/renderers/RadioRenderer/index.vue.d.ts +21 -0
  96. package/dist/renderers/RadioRenderer/index.vue.d.ts.map +1 -0
  97. package/dist/renderers/RadioRenderer/types.d.ts +22 -0
  98. package/dist/renderers/RadioRenderer/types.d.ts.map +1 -0
  99. package/dist/renderers/RateRenderer/index.d.ts +4 -0
  100. package/dist/renderers/RateRenderer/index.d.ts.map +1 -0
  101. package/dist/renderers/RateRenderer/index.vue.d.ts +20 -0
  102. package/dist/renderers/RateRenderer/index.vue.d.ts.map +1 -0
  103. package/dist/renderers/RateRenderer/types.d.ts +16 -0
  104. package/dist/renderers/RateRenderer/types.d.ts.map +1 -0
  105. package/dist/renderers/SelectRenderer/index.d.ts +5 -0
  106. package/dist/renderers/SelectRenderer/index.d.ts.map +1 -0
  107. package/dist/renderers/SelectRenderer/index.vue.d.ts +45 -0
  108. package/dist/renderers/SelectRenderer/index.vue.d.ts.map +1 -0
  109. package/dist/renderers/SelectRenderer/types.d.ts +36 -0
  110. package/dist/renderers/SelectRenderer/types.d.ts.map +1 -0
  111. package/dist/renderers/SensitiveInputRenderer/helper.d.ts +13 -0
  112. package/dist/renderers/SensitiveInputRenderer/helper.d.ts.map +1 -0
  113. package/dist/renderers/SensitiveInputRenderer/index.d.ts +5 -0
  114. package/dist/renderers/SensitiveInputRenderer/index.d.ts.map +1 -0
  115. package/dist/renderers/SensitiveInputRenderer/index.vue.d.ts +47 -0
  116. package/dist/renderers/SensitiveInputRenderer/index.vue.d.ts.map +1 -0
  117. package/dist/renderers/SensitiveInputRenderer/types.d.ts +51 -0
  118. package/dist/renderers/SensitiveInputRenderer/types.d.ts.map +1 -0
  119. package/dist/renderers/SliderRenderer/index.d.ts +4 -0
  120. package/dist/renderers/SliderRenderer/index.d.ts.map +1 -0
  121. package/dist/renderers/SliderRenderer/index.vue.d.ts +20 -0
  122. package/dist/renderers/SliderRenderer/index.vue.d.ts.map +1 -0
  123. package/dist/renderers/SliderRenderer/types.d.ts +16 -0
  124. package/dist/renderers/SliderRenderer/types.d.ts.map +1 -0
  125. package/dist/renderers/SwitchRenderer/index.d.ts +4 -0
  126. package/dist/renderers/SwitchRenderer/index.d.ts.map +1 -0
  127. package/dist/renderers/SwitchRenderer/index.vue.d.ts +22 -0
  128. package/dist/renderers/SwitchRenderer/index.vue.d.ts.map +1 -0
  129. package/dist/renderers/SwitchRenderer/types.d.ts +16 -0
  130. package/dist/renderers/SwitchRenderer/types.d.ts.map +1 -0
  131. package/dist/renderers/TimePickerRenderer/index.d.ts +4 -0
  132. package/dist/renderers/TimePickerRenderer/index.d.ts.map +1 -0
  133. package/dist/renderers/TimePickerRenderer/index.vue.d.ts +25 -0
  134. package/dist/renderers/TimePickerRenderer/index.vue.d.ts.map +1 -0
  135. package/dist/renderers/TimePickerRenderer/types.d.ts +23 -0
  136. package/dist/renderers/TimePickerRenderer/types.d.ts.map +1 -0
  137. package/dist/renderers/TimeSelectRenderer/index.d.ts +4 -0
  138. package/dist/renderers/TimeSelectRenderer/index.d.ts.map +1 -0
  139. package/dist/renderers/TimeSelectRenderer/index.vue.d.ts +25 -0
  140. package/dist/renderers/TimeSelectRenderer/index.vue.d.ts.map +1 -0
  141. package/dist/renderers/TimeSelectRenderer/types.d.ts +22 -0
  142. package/dist/renderers/TimeSelectRenderer/types.d.ts.map +1 -0
  143. package/dist/renderers/TreeSelectRenderer/index.d.ts +5 -0
  144. package/dist/renderers/TreeSelectRenderer/index.d.ts.map +1 -0
  145. package/dist/renderers/TreeSelectRenderer/index.vue.d.ts +44 -0
  146. package/dist/renderers/TreeSelectRenderer/index.vue.d.ts.map +1 -0
  147. package/dist/renderers/TreeSelectRenderer/types.d.ts +48 -0
  148. package/dist/renderers/TreeSelectRenderer/types.d.ts.map +1 -0
  149. package/dist/renderers/UploadRenderer/__tests__/preview.test.d.ts +2 -0
  150. package/dist/renderers/UploadRenderer/__tests__/preview.test.d.ts.map +1 -0
  151. package/dist/renderers/UploadRenderer/file-actions.vue.d.ts +29 -0
  152. package/dist/renderers/UploadRenderer/file-actions.vue.d.ts.map +1 -0
  153. package/dist/renderers/UploadRenderer/file-display.vue.d.ts +36 -0
  154. package/dist/renderers/UploadRenderer/file-display.vue.d.ts.map +1 -0
  155. package/dist/renderers/UploadRenderer/index.d.ts +4 -0
  156. package/dist/renderers/UploadRenderer/index.d.ts.map +1 -0
  157. package/dist/renderers/UploadRenderer/index.vue.d.ts +44 -0
  158. package/dist/renderers/UploadRenderer/index.vue.d.ts.map +1 -0
  159. package/dist/renderers/UploadRenderer/preview.vue.d.ts +76 -0
  160. package/dist/renderers/UploadRenderer/preview.vue.d.ts.map +1 -0
  161. package/dist/renderers/UploadRenderer/types.d.ts +67 -0
  162. package/dist/renderers/UploadRenderer/types.d.ts.map +1 -0
  163. package/dist/renderers/VirtualizedSelectRenderer/index.d.ts +5 -0
  164. package/dist/renderers/VirtualizedSelectRenderer/index.d.ts.map +1 -0
  165. package/dist/renderers/VirtualizedSelectRenderer/index.vue.d.ts +45 -0
  166. package/dist/renderers/VirtualizedSelectRenderer/index.vue.d.ts.map +1 -0
  167. package/dist/renderers/VirtualizedSelectRenderer/types.d.ts +36 -0
  168. package/dist/renderers/VirtualizedSelectRenderer/types.d.ts.map +1 -0
  169. package/dist/renderers/defaultRenderers.d.ts +499 -0
  170. package/dist/renderers/defaultRenderers.d.ts.map +1 -0
  171. package/dist/renderers/index.d.ts +48 -0
  172. package/dist/renderers/index.d.ts.map +1 -0
  173. package/dist/renderers/shared/date.d.ts +11 -0
  174. package/dist/renderers/shared/date.d.ts.map +1 -0
  175. package/dist/renderers/shared/options.d.ts +65 -0
  176. package/dist/renderers/shared/options.d.ts.map +1 -0
  177. package/dist/renderers/shared/props.d.ts +23 -0
  178. package/dist/renderers/shared/props.d.ts.map +1 -0
  179. package/dist/style.css +2 -0
  180. package/dist/types/schemx.d.ts +37 -0
  181. package/dist/types/schemx.d.ts.map +1 -0
  182. package/dist/utils/index.d.ts +140 -0
  183. package/dist/utils/index.d.ts.map +1 -0
  184. package/package.json +79 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["$slots","useAttrs","_useModel","computed","ref","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElInput","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElInputNumber","_mergeProps","_sfc_main","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElSwitch","_mergeProps","_sfc_main","useAttrs","_useModel","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElRadioGroup","_mergeProps","_createElementBlock","_Fragment","_renderList","ElRadio","_sfc_main","WithRemoteOptions","RadioRendererComponent","useAttrs","_useModel","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElCheckboxGroup","_mergeProps","_createElementBlock","_Fragment","_renderList","ElCheckbox","_sfc_main","WithRemoteOptions","CheckboxRendererComponent","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElDatePicker","_mergeProps","_sfc_main","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElCascader","_mergeProps","_sfc_main","WithRemoteOptions","CascaderRendererComponent","_hoisted_1","_hoisted_2","View","Hide","useAttrs","ref","_useModel","computed","nextTick","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createElementBlock","_withModifiers","ElIcon","_resolveDynamicComponent","_createCommentVNode","_createElementVNode","_createVNode","ElInput","_mergeProps","_sfc_main","useAttrs","_useModel","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createVNode","ElRate","_mergeProps","_sfc_main","useAttrs","_useModel","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElSlider","_mergeProps","_sfc_main","_openBlock","_createElementBlock","_normalizeClass","_createBlock","_unref","ElTooltip","_withCtx","_createVNode","ElButton","View","_withModifiers","_createCommentVNode","Download","Delete","_sfc_main","_hoisted_1","_hoisted_2","computed","_resolveComponent","_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createVNode","_withCtx","_unref","Document","_toDisplayString","_createCommentVNode","FileActions","_createBlock","_sfc_main","_hoisted_1","_hoisted_2","ref","computed","_openBlock","_createBlock","_unref","ElImageViewer","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","_createElementBlock","_Fragment","_createVNode","ElIcon","Back","Right","DArrowLeft","DArrowRight","_createCommentVNode","ZoomOut","ZoomIn","RefreshRight","RefreshLeft","Download","_createElementVNode","Document","_toDisplayString","ElButton","_createTextVNode","_sfc_main","$slots","useAttrs","_useModel","ref","computed","beforeUpload","useFieldContext","_openBlock","_createElementBlock","_Fragment","_createVNode","_unref","Wrapper","_normalizeClass","_withCtx","_renderList","_createBlock","ElImage","_toDisplayString","ElUpload","_mergeProps","FileDisplay","_renderSlot","ElIcon","Plus","ElButton","_createTextVNode","_createCommentVNode","FilePreview","_createSlots","_normalizeProps","_guardReactiveProps","_sfc_main","$slots","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElAutocomplete","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","WithRemoteOptions","AutocompleteRendererComponent","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElColorPicker","_mergeProps","_sfc_main","ColorPickerRendererComponent","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElDatePicker","_mergeProps","_sfc_main","DateTimePickerRendererComponent","$slots","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElInputTag","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","InputTagRendererComponent","$slots","useAttrs","_useModel","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElInputOtp","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","InputOtpRendererComponent","$slots","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElMention","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","WithRemoteOptions","MentionRendererComponent","$slots","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElSelect","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","WithRemoteOptions","SelectRendererComponent","$slots","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElSelectV2","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","WithRemoteOptions","VirtualizedSelectRendererComponent","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElTimePicker","_mergeProps","_sfc_main","TimePickerRendererComponent","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElTimeSelect","_mergeProps","_sfc_main","TimeSelectRendererComponent","$slots","useAttrs","_useModel","ref","computed","_openBlock","_createBlock","_unref","Wrapper","_normalizeClass","_withCtx","_createTextVNode","_toDisplayString","_createVNode","ElTreeSelect","_mergeProps","_createSlots","_renderSlot","_normalizeProps","_guardReactiveProps","_sfc_main","WithRemoteOptions","TreeSelectRendererComponent","ElCol","defineComponent","normalizeSchemxGutter","h","ElRow","InputRenderer","InputNumberRenderer","SwitchRenderer","RadioRenderer","CheckboxRenderer","DatePickerRenderer","CascaderRenderer","SensitiveInputRenderer","RateRenderer","SliderRenderer","UploadRenderer","AutocompleteRenderer","ColorPickerRenderer","DateTimePickerRenderer","InputTagRenderer","InputOtpRenderer","MentionRenderer","SelectRenderer","VirtualizedSelectRenderer","TimePickerRenderer","TimeSelectRenderer","TreeSelectRenderer","createRendererRegistry","createPresetRuleRegistry","configureSchemx","Object","defineProperties","exports","__esModule","value","Symbol","toStringTag","__create","create","__defProp","defineProperty","__getOwnPropDesc","getOwnPropertyDescriptor","__getOwnPropNames","getOwnPropertyNames","__getProtoOf","getPrototypeOf","__hasOwnProp","prototype","hasOwnProperty","__toESM","mod","isNodeMode","target","to","from","except","desc","key","keys","i","n","length","call","get","k","bind","enumerable","__copyProps","vue","require","_schemx_vue","element_plus","dayjs","_element_plus_icons_vue","_schemx_core","INTERNAL_RENDERER_PROPS","Set","getElementProps","props","attrs","extraKeys","excluded","result","entries","has","isEmptyDisplayValue","Array","isArray","getReadonlyDisplayValue","readonlyPlaceholder","findTreeItem","tree","targetValue","options","labelKey","valueKey","childrenKey","node","labels","values","search","nodes","currentLabels","String","currentValues","children","found","InputRenderer_default","defineComponent","name","inheritAttrs","__name","mergeModels","default","onChange","onBlur","onFocus","disabled","type","Boolean","readonly","placeholder","className","align","formItemProps","formInstance","valueModifiers","emits","setup","__props","expose","__expose","useAttrs","valueModel","useModel","currentValue","computed","inputRef","ref","inputProps","handleUpdate","nextValue","handleBlur","event","handleFocus","handleClear","focus","blur","_ctx","_cache","openBlock","createBlock","unref","Wrapper","class","normalizeClass","withCtx","createTextVNode","toDisplayString","createVNode","ElInput","mergeProps","ref_key","onClear","createSlots","_","$slots","prefix","fn","renderSlot","suffix","prepend","append","slotProps","normalizeProps","guardReactiveProps","InputNumberRenderer_default","_event","ElInputNumber","SwitchRenderer_default","Number","switchLoading","switchProps","loading","async","ElSwitch","RadioRenderer_default$1","label","disabledKey","radioProps","selectedValue","selectedLabel","option","find","item","getOptionValue","getOptionLabel","getOptionDisabled","ElRadioGroup","createElementBlock","Fragment","renderList","ElRadio","ref_for","getOptionProps","RadioRenderer_default","WithRemoteOptions","CheckboxRenderer_default$1","checkboxProps","selectedValues","groupValues","map","encodeValue","selectedLabels","decodeValue","ElCheckboxGroup","ElCheckbox","CheckboxRenderer_default","DatePickerRenderer_default","datePickerRef","datePickerProps","displayValue","formatValue","join","Date","format","ElDatePicker","CascaderRenderer_default$1","cascaderRef","cascaderProps","multiple","path","showAllLevels","separator","at","getDisplayPath","getDisplayValue","ElCascader","CascaderRenderer_default","_hoisted_1$3","_hoisted_2$3","SensitiveInputRenderer_default","Function","formatter","maskFormatter","chars","repeat","slice","defaultRevealed","revealed","onRevealChange","revealable","revealText","hideText","revealIcon","View","hideIcon","Hide","focusOnReveal","hideOnBlur","revealWhenReadonly","emit","__emit","revealedState","rawValue","isEmpty","isRevealed","canReveal","formattedValue","normalizeValue","maskedValue","isInputMasked","inputValue","trim","replace","watch","setRevealed","next","toggleReveal","nextTick","handleInputChange","handleInputBlur","handleInputFocus","onClick","withModifiers","ElIcon","resolveDynamicComponent","createCommentVNode","createElementVNode","RateRenderer_default","rateProps","ElRate","SliderRenderer_default","sliderProps","ElSlider","_plugin_vue_export_helper_default","sfc","__vccOpts","val","file_actions_default","canPreview","canDownload","canRemove","layout","showPreview","showDownload","showRemove","ElTooltip","content","ElButton","link","icon","title","$event","Download","Delete","_hoisted_1$2","_hoisted_2$2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","file_display_default","file","index","listType","fileType","crossorigin","loadText","imageExtensions","normalizedListType","isImageFile","configuredType","toLowerCase","includes","mime","raw","split","startsWith","url","previewUrl","downloadUrl","some","cleanName","pop","extensionIndex","lastIndexOf","getExtension","openPreview","handleDownload","handleRemove","_component_el_icon","resolveComponent","status","Document","Math","round","percentage","onPreview","onDownload","onRemove","src","alt","_hoisted_1$1","_hoisted_2$1","preview_vue_vue_type_script_setup_true_lang_default","modelValue","files","previewFullImage","beforePreview","downloadHandler","urlList","zIndex","initialIndex","infinite","hideOnClickModal","teleported","closeOnPressEscape","zoomRate","scale","minScale","maxScale","showProgress","activeIndex","internalVisible","imageViewerRef","activeFileKey","previewRequestId","objectUrls","Map","getFileName","genericMimeTypes","getObjectUrlKey","uid","isBlobFile","Blob","hasPreviewSource","getFileUrl","cached","URL","revokeObjectURL","createObjectURL","set","getFileKey","previewEntries","sourceFile","sourceIndex","filter","entry","previewFiles","activeFile","activeFileIsImage","activeFileCanRenderImage","viewerUrls","isVisible","previewVisible","setActiveIndex","min","max","isFinite","floor","resolveFileIndex","findIndex","targetKey","handleClose","handleViewerSwitch","handleError","handleRotate","degree","triggerDownload","document","createElement","href","download","rel","body","appendChild","click","remove","previewIndex","resolvedSourceIndex","getSourceIndex","isInteger","error","downloadError","Error","test","response","fetch","credentials","ok","blobUrl","blob","window","setTimeout","handleViewerDownload","viewerIndex","handleToolbarKeydown","action","preventDefault","immediate","setActiveItem","flush","availableObjectUrls","delete","currentIndex","onBeforeUnmount","forEach","clear","open","requestId","show","handled","done","then","catch","close","ElImageViewer","onClose","onSwitch","onError","onRotate","toolbar","role","tabindex","prev","onKeydown","Back","Right","DArrowLeft","DArrowRight","actions","ZoomOut","enableTransition","ZoomIn","rotateDeg","RefreshRight","RefreshLeft","preview_default","_hoisted_1","_hoisted_2","UploadRenderer_default","uploader","showUpload","disableUpload","propsHttp","data","onSuccess","fileList","normalizeFiles","previewRef","uploadRef","field","useFieldContext","resolveFieldContext","deep","imageFiles","nonImageFiles","imageUrls","acceptRules","accept","rule","handleBeforeUpload","rawFile","fileName","mimeType","normalizedRule","endsWith","isAcceptedFile","ElMessage","warning","configuredBeforeUpload","beforeUpload","uploadProps","httpRequest","setPending","message","uploadError","syncFiles","nextFiles","size","handleChange","_file","handleDisplayRemove","handlePreview","handleSuccess","responseData","getResponseValue","responseUrl","responseName","reduce","current","ElImage","fit","ElUpload","Plus","viewer","viewerProps","getElementOptionValue","fieldNames","getElementOptionLabel","getElementOptionDisplayValue","candidate","isElementOptionValue","normalizeElementSelection","AutocompleteRenderer_default$1","onSelect","autocompleteRef","normalizedOptions","normalizeElementOptions","localFetchSuggestions","query","callback","keyword","fetchSuggestions","autocompleteProps","handleSelect","ElAutocomplete","AutocompleteRenderer_default","ColorPickerRenderer_default","onActiveChange","colorPickerRef","colorPickerProps","handleActiveChange","ElColorPicker","formatElementDateValue","rangeSeparator","parsed","isValid","DateTimePickerRenderer_default","dateTimePickerRef","dateTimePickerProps","InputTagRenderer_default","onAddTag","onRemoveTag","inputTagRef","inputTagProps","handleAddTag","handleRemoveTag","ElInputTag","tag","InputOtpRenderer_default","onFinish","inputOtpProps","handleFinish","ElInputOtp","MentionRenderer_default$1","onSearch","onWholeRemove","mentionRef","mentionProps","handleSearch","pattern","handleWholeRemove","input","ElMention","header","footer","MentionRenderer_default","SelectRenderer_default$1","onVisibleChange","onEndReached","selectRef","selectProps","handleVisibleChange","visible","handleEndReached","direction","ElSelect","SelectRenderer_default","VirtualizedSelectRenderer_default$1","ElSelectV2","VirtualizedSelectRenderer_default","TimePickerRenderer_default","showNow","showConfirm","showFooter","showWeekNumber","ariaLabel","emptyValues","valueOnClear","disabledDate","cellClassName","shortcuts","arrowControl","validateEvent","unlinkPanels","singlePanel","placement","fallbackPlacements","disabledHours","disabledMinutes","disabledSeconds","automaticDropdown","id","popperClass","popperStyle","valueFormat","dateFormat","timeFormat","clearable","clearIcon","editable","saveOnBlur","prefixIcon","popperOptions","startPlaceholder","endPlaceholder","defaultValue","defaultTime","isRange","timePickerRef","timePickerProps","ElTimePicker","TimeSelectRenderer_default","timeSelectRef","timeSelectProps","ElTimeSelect","TreeSelectRenderer_default$1","nodeKey","onCheck","onNodeClick","onNodeExpand","treeSelectRef","treeData","treeSelectProps","getTreeDisplayValue","handleCheck","info","handleNodeClick","handleNodeExpand","instance","ElTreeSelect","TreeSelectRenderer_default","ElementPlusCol","ElCol","ElementPlusRow","slots","gutter","attrsClass","style","attrsStyle","restAttrs","top","right","bottom","left","normalizeSchemxGutter","halfTop","halfRight","halfBottom","halfLeft","h","ElRow","margin","defaultRenderers","inputNumber","switch","radio","checkbox","datePicker","cascader","sensitiveInput","rate","slider","upload","autocomplete","colorPicker","datetimePicker","inputTag","inputOtp","mention","select","virtualizedSelect","timePicker","timeSelect","treeSelect","rendererRegistry","registry","createRendererRegistry","registerAll","createElementPlusRendererRegistry","presetRuleRegistry","createPresetRuleRegistry","configureSchemx","colComponent","rowComponent","schemaConfig","col","span","row","labelAlign","labelWidth","labelPosition","contentAlign","bordered","AutocompleteRenderer","CascaderRenderer","CheckboxRenderer","ColorPickerRenderer","DEFAULT_RENDERER_TYPES","DatePickerRenderer","DateTimePickerRenderer","InputNumberRenderer","InputOtpRenderer","InputRenderer","InputTagRenderer","MentionRenderer","RadioRenderer","RateRenderer","SelectRenderer","SensitiveInputRenderer","SliderRenderer","SwitchRenderer","TimePickerRenderer","TimeSelectRenderer","TreeSelectRenderer","UploadRenderer","VirtualizedSelectRenderer","getFieldProps","now","parts","isRendererInteractive","mode","resolveRendererMode","useForm"],"sources":["../src/renderers/shared/props.ts","../src/utils/index.ts","../src/renderers/InputRenderer/index.vue","../src/renderers/InputRenderer/index.vue","../src/renderers/InputNumberRenderer/index.vue","../src/renderers/InputNumberRenderer/index.vue","../src/renderers/SwitchRenderer/index.vue","../src/renderers/SwitchRenderer/index.vue","../src/renderers/RadioRenderer/index.vue","../src/renderers/RadioRenderer/index.vue","../src/renderers/RadioRenderer/index.ts","../src/renderers/CheckboxRenderer/index.vue","../src/renderers/CheckboxRenderer/index.vue","../src/renderers/CheckboxRenderer/index.ts","../src/renderers/DatePickerRenderer/index.vue","../src/renderers/DatePickerRenderer/index.vue","../src/renderers/CascaderRenderer/index.vue","../src/renderers/CascaderRenderer/index.vue","../src/renderers/CascaderRenderer/index.ts","../src/renderers/SensitiveInputRenderer/helper.ts","../src/renderers/SensitiveInputRenderer/index.vue","../src/renderers/SensitiveInputRenderer/index.vue","../src/renderers/RateRenderer/index.vue","../src/renderers/RateRenderer/index.vue","../src/renderers/SliderRenderer/index.vue","../src/renderers/SliderRenderer/index.vue","../src/renderers/UploadRenderer/file-actions.vue","../src/renderers/UploadRenderer/file-actions.vue","../src/renderers/UploadRenderer/file-display.vue","../src/renderers/UploadRenderer/file-display.vue","../src/renderers/UploadRenderer/preview.vue","../src/renderers/UploadRenderer/preview.vue","../src/renderers/UploadRenderer/index.vue","../src/renderers/UploadRenderer/index.vue","../src/renderers/shared/options.ts","../src/renderers/AutocompleteRenderer/index.vue","../src/renderers/AutocompleteRenderer/index.vue","../src/renderers/AutocompleteRenderer/index.ts","../src/renderers/ColorPickerRenderer/index.vue","../src/renderers/ColorPickerRenderer/index.vue","../src/renderers/ColorPickerRenderer/index.ts","../src/renderers/shared/date.ts","../src/renderers/DateTimePickerRenderer/index.vue","../src/renderers/DateTimePickerRenderer/index.vue","../src/renderers/DateTimePickerRenderer/index.ts","../src/renderers/InputTagRenderer/index.vue","../src/renderers/InputTagRenderer/index.vue","../src/renderers/InputTagRenderer/index.ts","../src/renderers/InputOtpRenderer/index.vue","../src/renderers/InputOtpRenderer/index.vue","../src/renderers/InputOtpRenderer/index.ts","../src/renderers/MentionRenderer/index.vue","../src/renderers/MentionRenderer/index.vue","../src/renderers/MentionRenderer/index.ts","../src/renderers/SelectRenderer/index.vue","../src/renderers/SelectRenderer/index.vue","../src/renderers/SelectRenderer/index.ts","../src/renderers/VirtualizedSelectRenderer/index.vue","../src/renderers/VirtualizedSelectRenderer/index.vue","../src/renderers/VirtualizedSelectRenderer/index.ts","../src/renderers/TimePickerRenderer/index.vue","../src/renderers/TimePickerRenderer/index.vue","../src/renderers/TimePickerRenderer/index.ts","../src/renderers/TimeSelectRenderer/index.vue","../src/renderers/TimeSelectRenderer/index.vue","../src/renderers/TimeSelectRenderer/index.ts","../src/renderers/TreeSelectRenderer/index.vue","../src/renderers/TreeSelectRenderer/index.vue","../src/renderers/TreeSelectRenderer/index.ts","../src/renderers/index.ts","../src/layout/defaultCol.ts","../src/layout/defaultRow.ts","../src/renderers/defaultRenderers.ts","../src/config/defaultConfig.ts"],"sourcesContent":["/**\n * Element Plus Renderer 属性处理工具。\n *\n * 将 Schemx 的运行时控制属性从 Element Plus 原生属性中剔除,避免字段上下文\n * 和表单内部数据被错误透传给控件。\n */\n\n/** Schemx 内部使用、不能透传给 UI 控件的属性名。 */\nconst INTERNAL_RENDERER_PROPS = new Set([\n \"value\",\n \"onChange\",\n \"onBlur\",\n \"onFocus\",\n \"onUpdate:value\",\n \"formInstance\",\n \"formItemProps\",\n \"className\",\n \"readonlyPlaceholder\",\n \"dict\",\n \"fieldName\",\n \"contentAlign\",\n])\n\n/**\n * 合并并过滤 Renderer 的原生控件属性。\n *\n * @param props - Renderer 已声明的属性。\n * @param attrs - Renderer 未声明的透传属性。\n * @param extraKeys - 当前 Renderer 额外需要过滤的属性名。\n * @returns 可传给 Element Plus 控件的属性对象。\n */\nexport function getElementProps<TProps extends object>(\n props: TProps,\n attrs: Record<string, unknown>,\n extraKeys: readonly string[] = []\n): Record<string, unknown> {\n const excluded = new Set([...INTERNAL_RENDERER_PROPS, ...extraKeys])\n\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(attrs)) {\n if (!excluded.has(key)) result[key] = value\n }\n\n for (const [key, value] of Object.entries(props)) {\n if (!excluded.has(key)) result[key] = value\n }\n\n return result\n}\n\n/**\n * 从 Renderer Props 中提取表单项之外的 CSS 类名。\n *\n * @param className - Renderer 自定义类名。\n * @returns 可用于根节点的类名值。\n */\nexport function getRendererClassName(className = \"\"): string[] {\n return [\"schemx-renderer\", className].filter(Boolean)\n}\n","/**\n * Element Plus Renderer 工具函数\n *\n * 提供渲染器组件中常用的属性提取、树形数据查找、文件名解析等工具。\n *\n * @module utils\n */\n\n/**\n * 从 attrs 对象中获取指定属性值,不存在时返回默认值。\n *\n * 用于从 Vue 组件的 `attrs` 中安全地提取透传属性,\n * 常见场景包括读取 Renderer 的透传属性。\n *\n * @param attrs - Vue 组件的 attrs 对象\n * @param key - 属性名\n * @param defaultValue - 默认值\n * @typeParam TProps - attrs 对象类型\n *\n * @returns 属性值或默认值\n *\n * @example\n * getFieldProps(attrs, \"align\", \"right\")\n * getFieldProps(attrs, \"rightIcon\", \"arrow\")\n */\nexport function getFieldProps<TProps extends Record<string, unknown>>(\n attrs: TProps,\n key: keyof TProps,\n defaultValue: TProps[typeof key] = undefined as TProps[typeof key]\n): TProps[typeof key] {\n return attrs?.[key] ?? defaultValue\n}\n\n/**\n * 判断值是否应按空值展示。\n *\n * @example\n * ```ts\n * isEmptyDisplayValue([]) // => true\n * isEmptyDisplayValue(0) // => false\n * ```\n */\nexport function isEmptyDisplayValue(value: unknown): boolean {\n return (\n value === undefined ||\n value === null ||\n value === \"\" ||\n (Array.isArray(value) && value.length === 0)\n )\n}\n\n/**\n * 获取只读态展示值。\n *\n * 只在值为空时回退到 readonlyPlaceholder,保留 0、false 等有效值。\n *\n * @typeParam TValue - 待展示的值类型。\n *\n * @example\n * ```ts\n * getReadonlyDisplayValue(undefined, \"未填写\") // => \"未填写\"\n * getReadonlyDisplayValue(0, \"未填写\") // => 0\n * ```\n */\nexport function getReadonlyDisplayValue<TValue>(\n value: TValue,\n readonlyPlaceholder = \"-\"\n): TValue | string {\n return isEmptyDisplayValue(value) ? readonlyPlaceholder : value\n}\n\nexport type RendererMode = \"editable\" | \"disabled\" | \"readonly\"\n\n/**\n * 解析渲染器当前呈现模式。\n *\n * disabled/readonly 仍会阻止交互。\n *\n * @example\n * ```ts\n * resolveRendererMode({ readonly: true }) // => \"readonly\"\n * resolveRendererMode({ disabled: true, readonly: true }) // => \"disabled\"\n * ```\n */\nexport function resolveRendererMode(options: {\n disabled?: boolean\n readonly?: boolean\n}): RendererMode {\n if (options.disabled) return \"disabled\"\n if (options.readonly) return \"readonly\"\n\n return \"editable\"\n}\n\n/**\n * 判断当前状态是否允许用户交互。\n *\n * @example\n * ```ts\n * isRendererInteractive(\"editable\") // => true\n * isRendererInteractive(\"disabled\") // => false\n * ```\n */\nexport function isRendererInteractive(mode: RendererMode): boolean {\n return mode === \"editable\"\n}\n\n/**\n * 树形查找结果\n *\n * @typeParam TNode - 树节点类型。\n * @typeParam TValue - 节点值类型。\n */\nexport interface FindTreeItemResult<\n TNode extends Record<string, unknown> = Record<string, unknown>,\n TValue = unknown,\n> {\n /** 匹配节点 */\n node: TNode | null\n /** 从根到匹配节点的 label 路径 */\n labels: string[]\n /** 从根到匹配节点的 value 路径 */\n values: TValue[]\n}\n\n/**\n * 在树形数据中查找指定值的节点,返回匹配节点及其路径信息。\n *\n * 支持自定义字段名映射,适用于 Cascader 等树形选择组件。\n *\n * @typeParam TNode - 树节点类型。\n * @typeParam TValue - 待查找的节点值类型。\n * @param tree - 树形数据数组\n * @param targetValue - 要查找的目标值\n * @param options - 字段名配置\n * @param options.labelKey - label 字段名,默认 `\"label\"`\n * @param options.valueKey - value 字段名,默认 `\"value\"`\n * @param options.childrenKey - children 字段名,默认 `\"children\"`\n *\n * @returns `{ node, labels, values }`:匹配节点、label 路径和 value 路径\n *\n * @example\n * const result = findTreeItem(tree, \"guangzhou\", {\n * labelKey: \"text\",\n * valueKey: \"value\",\n * childrenKey: \"children\",\n * })\n * const { node, labels, values } = result\n * // node => { text: \"广州\", value: \"guangzhou\" }\n * // labels => [\"广东\", \"广州\"]\n * // values => [\"guangdong\", \"guangzhou\"]\n */\nexport function findTreeItem<TNode extends Record<string, unknown>, TValue>(\n tree: TNode[],\n targetValue: TValue,\n options: {\n labelKey?: string\n valueKey?: string\n childrenKey?: string\n } = {}\n): FindTreeItemResult<TNode, TValue> {\n const { labelKey = \"label\", valueKey = \"value\", childrenKey = \"children\" } = options\n\n const result: FindTreeItemResult<TNode, TValue> = { node: null, labels: [], values: [] }\n\n if (!Array.isArray(tree) || targetValue === undefined || targetValue === null) {\n return result\n }\n\n const search = (\n nodes: TNode[],\n labels: string[],\n values: TValue[]\n ): FindTreeItemResult<TNode, TValue> | null => {\n for (const node of nodes) {\n const currentLabels = [...labels, String(node[labelKey])]\n\n const currentValues = [...values, node[valueKey] as TValue]\n\n if (node[valueKey] === targetValue) {\n return { node, labels: currentLabels, values: currentValues }\n }\n\n const children = node[childrenKey]\n\n if (Array.isArray(children) && children.length > 0) {\n const found = search(children as TNode[], currentLabels, currentValues)\n\n if (found) return found\n }\n }\n\n return null\n }\n\n return search(tree, [], []) || result\n}\n\n/**\n * 从 URL 或文件路径中提取文件名。\n *\n * 去除查询参数和 hash 后,取最后一段路径作为文件名。\n * 用于上传组件中生成文件的唯一标识。\n *\n * @param url - 文件 URL 或路径\n *\n * @returns 文件名字符串,无法解析时返回原始输入或时间戳\n *\n * @example\n * getFileName(\"https://cdn.example.com/uploads/photo.jpg?t=123\")\n * // => \"photo.jpg\"\n *\n * getFileName(\"blob:http://localhost:3000/abc-def\")\n * // => \"abc-def\"\n */\nexport function getFileName(url: string | undefined | null): string {\n if (!url) return String(Date.now())\n\n try {\n const cleanUrl = url.split(\"?\")[0].split(\"#\")[0]\n\n const parts = cleanUrl.split(\"/\")\n\n const fileName = parts[parts.length - 1]\n\n return fileName || String(Date.now())\n } catch {\n return String(Date.now())\n }\n}\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElInput\n ref=\"inputRef\"\n v-bind=\"inputProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n @clear=\"handleClear\"\n >\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend>\n <slot name=\"prepend\" />\n </template>\n <template v-if=\"$slots.append\" #append>\n <slot name=\"append\" />\n </template>\n <template v-if=\"$slots['password-icon']\" #password-icon=\"slotProps\">\n <slot name=\"password-icon\" v-bind=\"slotProps\" />\n </template>\n </ElInput>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInput 渲染输入字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInput } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputRendererProps, InputValue } from \"./types\"\n import type { InputInstance } from \"element-plus\"\n\n defineOptions({\n name: \"InputRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n placeholder: \"\",\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputValue>(\"value\")\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const inputRef = ref<InputInstance>()\n\n const inputProps = computed(() =>\n getElementProps(props, attrs, [\"onBlur\", \"onFocus\", \"onClear\"])\n )\n\n /** 同步输入值。 */\n const handleUpdate = (value: string | number | null | undefined): void => {\n const nextValue = String(value ?? \"\")\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 转发输入框失焦事件。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 转发输入框聚焦事件。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n /** 处理清空操作并同步空字符串。 */\n const handleClear = (): void => {\n valueModel.value = \"\"\n props.onChange?.(\"\")\n }\n\n defineExpose({\n /** 聚焦内部输入框。 */\n focus: () => inputRef.value?.focus(),\n /** 使内部输入框失焦。 */\n blur: () => inputRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElInput\n ref=\"inputRef\"\n v-bind=\"inputProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n @clear=\"handleClear\"\n >\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend>\n <slot name=\"prepend\" />\n </template>\n <template v-if=\"$slots.append\" #append>\n <slot name=\"append\" />\n </template>\n <template v-if=\"$slots['password-icon']\" #password-icon=\"slotProps\">\n <slot name=\"password-icon\" v-bind=\"slotProps\" />\n </template>\n </ElInput>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInput 渲染输入字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInput } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputRendererProps, InputValue } from \"./types\"\n import type { InputInstance } from \"element-plus\"\n\n defineOptions({\n name: \"InputRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n placeholder: \"\",\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputValue>(\"value\")\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const inputRef = ref<InputInstance>()\n\n const inputProps = computed(() =>\n getElementProps(props, attrs, [\"onBlur\", \"onFocus\", \"onClear\"])\n )\n\n /** 同步输入值。 */\n const handleUpdate = (value: string | number | null | undefined): void => {\n const nextValue = String(value ?? \"\")\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 转发输入框失焦事件。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 转发输入框聚焦事件。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n /** 处理清空操作并同步空字符串。 */\n const handleClear = (): void => {\n valueModel.value = \"\"\n props.onChange?.(\"\")\n }\n\n defineExpose({\n /** 聚焦内部输入框。 */\n focus: () => inputRef.value?.focus(),\n /** 使内部输入框失焦。 */\n blur: () => inputRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-number-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(valueModel, props.readonlyPlaceholder) }}\n </template>\n <ElInputNumber\n ref=\"inputRef\"\n v-bind=\"inputProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInputNumber 渲染数值字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInputNumber } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputNumberRendererProps, InputNumberValue } from \"./types\"\n import type { InputNumberInstance } from \"element-plus\"\n\n defineOptions({\n name: \"InputNumberRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputNumberRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputNumberValue>(\"value\")\n\n const inputRef = ref<InputNumberInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? null)\n\n const inputProps = computed(() => getElementProps(props, attrs))\n\n /**\n * 同步 Element Plus 数字值。\n *\n * @param value - Element Plus 产生的数字或空值。\n */\n const handleUpdate = (value: number | undefined): void => {\n const nextValue = value ?? null\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /**\n * 处理数字输入失焦。\n *\n * @param event - 原生失焦事件。\n */\n const handleBlur = (_event: FocusEvent): void => {\n props.onBlur?.(currentValue.value)\n }\n\n /**\n * 处理数字输入聚焦。\n *\n * @param event - 原生聚焦事件。\n */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部数字输入框。 */\n focus: () => inputRef.value?.focus(),\n /** 使内部数字输入框失焦。 */\n blur: () => inputRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-number-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(valueModel, props.readonlyPlaceholder) }}\n </template>\n <ElInputNumber\n ref=\"inputRef\"\n v-bind=\"inputProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInputNumber 渲染数值字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInputNumber } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputNumberRendererProps, InputNumberValue } from \"./types\"\n import type { InputNumberInstance } from \"element-plus\"\n\n defineOptions({\n name: \"InputNumberRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputNumberRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputNumberValue>(\"value\")\n\n const inputRef = ref<InputNumberInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? null)\n\n const inputProps = computed(() => getElementProps(props, attrs))\n\n /**\n * 同步 Element Plus 数字值。\n *\n * @param value - Element Plus 产生的数字或空值。\n */\n const handleUpdate = (value: number | undefined): void => {\n const nextValue = value ?? null\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /**\n * 处理数字输入失焦。\n *\n * @param event - 原生失焦事件。\n */\n const handleBlur = (_event: FocusEvent): void => {\n props.onBlur?.(currentValue.value)\n }\n\n /**\n * 处理数字输入聚焦。\n *\n * @param event - 原生聚焦事件。\n */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部数字输入框。 */\n focus: () => inputRef.value?.focus(),\n /** 使内部数字输入框失焦。 */\n blur: () => inputRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-switch-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(valueModel, props.readonlyPlaceholder) }}\n </template>\n <ElSwitch\n v-bind=\"switchProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSwitch 渲染开关字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSwitch } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { SwitchRendererProps, SwitchValue } from \"./types\"\n\n defineOptions({\n name: \"SwitchRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SwitchRendererProps>(), {\n value: false,\n activeValue: true,\n inactiveValue: false,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<SwitchValue>(\"value\")\n\n const switchLoading = ref(false)\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? false)\n\n const switchProps = computed(() => ({\n ...getElementProps(props, attrs, [\"readonlyPlaceholder\"]),\n loading: Boolean(props.loading || switchLoading.value),\n }))\n\n /**\n * 处理开关状态变化,并等待异步业务回调完成。\n *\n * @param value - Element Plus 产生的开关值。\n */\n const handleUpdate = async (value: SwitchValue): Promise<void> => {\n if (props.readonly || props.disabled || switchLoading.value) return\n\n switchLoading.value = true\n\n try {\n const nextValue = await props.onChange?.(value)\n\n valueModel.value = nextValue ?? value\n } finally {\n switchLoading.value = false\n }\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-switch-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(valueModel, props.readonlyPlaceholder) }}\n </template>\n <ElSwitch\n v-bind=\"switchProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSwitch 渲染开关字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSwitch } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { SwitchRendererProps, SwitchValue } from \"./types\"\n\n defineOptions({\n name: \"SwitchRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SwitchRendererProps>(), {\n value: false,\n activeValue: true,\n inactiveValue: false,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<SwitchValue>(\"value\")\n\n const switchLoading = ref(false)\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? false)\n\n const switchProps = computed(() => ({\n ...getElementProps(props, attrs, [\"readonlyPlaceholder\"]),\n loading: Boolean(props.loading || switchLoading.value),\n }))\n\n /**\n * 处理开关状态变化,并等待异步业务回调完成。\n *\n * @param value - Element Plus 产生的开关值。\n */\n const handleUpdate = async (value: SwitchValue): Promise<void> => {\n if (props.readonly || props.disabled || switchLoading.value) return\n\n switchLoading.value = true\n\n try {\n const nextValue = await props.onChange?.(value)\n\n valueModel.value = nextValue ?? value\n } finally {\n switchLoading.value = false\n }\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-radio-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(selectedLabel, props.readonlyPlaceholder) }}\n </template>\n <ElRadioGroup\n v-bind=\"radioProps\"\n :model-value=\"selectedValue\"\n @update:model-value=\"handleUpdate\"\n >\n <ElRadio\n v-for=\"option in props.options\"\n :key=\"String(getOptionValue(option))\"\n v-bind=\"getOptionProps(option)\"\n >\n {{ getOptionLabel(option) }}\n </ElRadio>\n </ElRadioGroup>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElRadioGroup 渲染单选字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElRadio, ElRadioGroup } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { RadioOption, RadioRendererProps, RadioValue } from \"./types\"\n\n defineOptions({\n name: \"RadioRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<RadioRendererProps>(), {\n value: undefined,\n options: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<RadioValue>(\"value\")\n\n const labelKey = computed(() => props.props?.label ?? \"label\")\n\n const valueKey = computed(() => props.props?.value ?? \"value\")\n\n const disabledKey = computed(() => props.props?.disabled ?? \"disabled\")\n\n const radioProps = computed(() => getElementProps(props, attrs))\n\n const selectedValue = computed(() => valueModel.value ?? props.value)\n\n const selectedLabel = computed(() => {\n const option = props.options.find(\n (item) => getOptionValue(item) === selectedValue.value\n )\n\n return option ? getOptionLabel(option) : selectedValue.value\n })\n\n /**\n * 获取选项值。\n *\n * @param option - 当前单选选项。\n * @returns 选项值。\n */\n const getOptionValue = (option: RadioOption): RadioValue =>\n option[valueKey.value] as RadioValue\n\n /** 获取传给单个 Element Plus Radio 的完整配置。 */\n const getOptionProps = (option: RadioOption): Record<string, unknown> => ({\n ...option,\n label: getOptionLabel(option),\n value: getOptionValue(option),\n disabled: props.disabled || getOptionDisabled(option),\n })\n\n /**\n * 获取选项显示文本。\n *\n * @param option - 当前单选选项。\n * @returns 选项显示文本。\n */\n const getOptionLabel = (option: RadioOption): string =>\n String(option[labelKey.value] ?? getOptionValue(option))\n\n /**\n * 获取选项禁用状态。\n *\n * @param option - 当前单选选项。\n * @returns 是否禁用。\n */\n const getOptionDisabled = (option: RadioOption): boolean =>\n Boolean(option[disabledKey.value])\n\n /**\n * 同步 Element Plus 单选值。\n *\n * @param value - Element Plus 产生的新值。\n */\n const handleUpdate = (value: RadioValue | undefined): void => {\n if (value === undefined || props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-radio-renderer > .el-radio-group {\n display: flex;\n flex-wrap: wrap;\n gap: 10px 20px;\n }\n .schemx-radio-renderer > .el-radio-group .el-radio {\n margin-right: 0px;\n }\n\n .schemx-radio-renderer > .el-radio-group {\n justify-content: var(--schemx-content-align);\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-radio-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(selectedLabel, props.readonlyPlaceholder) }}\n </template>\n <ElRadioGroup\n v-bind=\"radioProps\"\n :model-value=\"selectedValue\"\n @update:model-value=\"handleUpdate\"\n >\n <ElRadio\n v-for=\"option in props.options\"\n :key=\"String(getOptionValue(option))\"\n v-bind=\"getOptionProps(option)\"\n >\n {{ getOptionLabel(option) }}\n </ElRadio>\n </ElRadioGroup>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElRadioGroup 渲染单选字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElRadio, ElRadioGroup } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { RadioOption, RadioRendererProps, RadioValue } from \"./types\"\n\n defineOptions({\n name: \"RadioRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<RadioRendererProps>(), {\n value: undefined,\n options: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<RadioValue>(\"value\")\n\n const labelKey = computed(() => props.props?.label ?? \"label\")\n\n const valueKey = computed(() => props.props?.value ?? \"value\")\n\n const disabledKey = computed(() => props.props?.disabled ?? \"disabled\")\n\n const radioProps = computed(() => getElementProps(props, attrs))\n\n const selectedValue = computed(() => valueModel.value ?? props.value)\n\n const selectedLabel = computed(() => {\n const option = props.options.find(\n (item) => getOptionValue(item) === selectedValue.value\n )\n\n return option ? getOptionLabel(option) : selectedValue.value\n })\n\n /**\n * 获取选项值。\n *\n * @param option - 当前单选选项。\n * @returns 选项值。\n */\n const getOptionValue = (option: RadioOption): RadioValue =>\n option[valueKey.value] as RadioValue\n\n /** 获取传给单个 Element Plus Radio 的完整配置。 */\n const getOptionProps = (option: RadioOption): Record<string, unknown> => ({\n ...option,\n label: getOptionLabel(option),\n value: getOptionValue(option),\n disabled: props.disabled || getOptionDisabled(option),\n })\n\n /**\n * 获取选项显示文本。\n *\n * @param option - 当前单选选项。\n * @returns 选项显示文本。\n */\n const getOptionLabel = (option: RadioOption): string =>\n String(option[labelKey.value] ?? getOptionValue(option))\n\n /**\n * 获取选项禁用状态。\n *\n * @param option - 当前单选选项。\n * @returns 是否禁用。\n */\n const getOptionDisabled = (option: RadioOption): boolean =>\n Boolean(option[disabledKey.value])\n\n /**\n * 同步 Element Plus 单选值。\n *\n * @param value - Element Plus 产生的新值。\n */\n const handleUpdate = (value: RadioValue | undefined): void => {\n if (value === undefined || props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-radio-renderer > .el-radio-group {\n display: flex;\n flex-wrap: wrap;\n gap: 10px 20px;\n }\n .schemx-radio-renderer > .el-radio-group .el-radio {\n margin-right: 0px;\n }\n\n .schemx-radio-renderer > .el-radio-group {\n justify-content: var(--schemx-content-align);\n }\n</style>\n","/** Radio Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport RadioRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(RadioRendererComponent)\nexport type { RadioOption, RadioRendererProps, RadioValue } from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-checkbox-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(selectedLabels, props.readonlyPlaceholder) }}\n </template>\n <ElCheckboxGroup\n v-bind=\"checkboxProps\"\n :model-value=\"groupValues\"\n @update:model-value=\"handleUpdate\"\n >\n <ElCheckbox\n v-for=\"option in props.options\"\n :key=\"String(getOptionValue(option))\"\n v-bind=\"getOptionProps(option)\"\n >\n {{ getOptionLabel(option) }}\n </ElCheckbox>\n </ElCheckboxGroup>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElCheckboxGroup 渲染复选字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElCheckbox, ElCheckboxGroup } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type {\n CheckboxOption,\n CheckboxOptionValue,\n CheckboxRendererProps,\n CheckboxValue,\n } from \"./types\"\n\n defineOptions({\n name: \"CheckboxRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<CheckboxRendererProps>(), {\n value: () => [],\n options: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<CheckboxValue>(\"value\")\n\n const labelKey = computed(() => props.props?.label ?? \"label\")\n\n const valueKey = computed(() => props.props?.value ?? \"value\")\n\n const disabledKey = computed(() => props.props?.disabled ?? \"disabled\")\n\n const checkboxProps = computed(() => getElementProps(props, attrs))\n\n const selectedValues = computed(() => valueModel.value ?? props.value ?? [])\n\n const groupValues = computed(() => selectedValues.value.map(encodeValue))\n\n const selectedLabels = computed(() =>\n selectedValues.value.map((value) => {\n const option = props.options.find((item) => getOptionValue(item) === value)\n\n return option ? getOptionLabel(option) : String(value)\n })\n )\n\n /**\n * 获取选项值。\n *\n * @param option - 当前复选选项。\n * @returns 选项值。\n */\n const getOptionValue = (option: CheckboxOption): CheckboxOptionValue | undefined =>\n option[valueKey.value] as CheckboxOptionValue | undefined\n\n /** 获取传给单个 Element Plus Checkbox 的完整配置。 */\n const getOptionProps = (option: CheckboxOption): Record<string, unknown> => ({\n ...option,\n label: getOptionLabel(option),\n value: encodeValue(getOptionValue(option)),\n disabled: props.disabled || getOptionDisabled(option),\n })\n\n /**\n * 将 boolean 选项值编码为 Element Plus CheckboxGroup 支持的值。\n *\n * @param value - Schemx 对外选项值。\n * @returns CheckboxGroup 可接受的字符串或数字值。\n */\n const encodeValue = (value: CheckboxOptionValue | undefined): string | number => {\n if (typeof value === \"boolean\") return value ? \"__schemx_true__\" : \"__schemx_false__\"\n\n return value ?? \"\"\n }\n\n /**\n * 将 Element Plus CheckboxGroup 值还原为 Schemx 选项值。\n *\n * @param value - CheckboxGroup 产生的字符串或数字值。\n * @returns Schemx 对外选项值。\n */\n const decodeValue = (value: string | number): CheckboxOptionValue => {\n if (value === \"__schemx_true__\") return true\n if (value === \"__schemx_false__\") return false\n\n return value\n }\n\n /**\n * 获取选项显示文本。\n *\n * @param option - 当前复选选项。\n * @returns 选项显示文本。\n */\n const getOptionLabel = (option: CheckboxOption): string =>\n String(option[labelKey.value] ?? getOptionValue(option))\n\n /**\n * 获取选项禁用状态。\n *\n * @param option - 当前复选选项。\n * @returns 是否禁用。\n */\n const getOptionDisabled = (option: CheckboxOption): boolean =>\n Boolean(option[disabledKey.value])\n\n /**\n * 同步 Element Plus 复选值。\n *\n * @param value - Element Plus 产生的新值列表。\n */\n const handleUpdate = (value: Array<string | number>): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = value.map(decodeValue) as CheckboxValue\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-checkbox-renderer > .el-checkbox-group {\n display: flex;\n flex-wrap: wrap;\n gap: 10px 20px;\n }\n\n .schemx-checkbox-renderer > .el-checkbox-group .el-checkbox {\n margin-right: 0px;\n }\n\n .schemx-checkbox-renderer > .el-checkbox-group {\n justify-content: var(--schemx-content-align);\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-checkbox-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(selectedLabels, props.readonlyPlaceholder) }}\n </template>\n <ElCheckboxGroup\n v-bind=\"checkboxProps\"\n :model-value=\"groupValues\"\n @update:model-value=\"handleUpdate\"\n >\n <ElCheckbox\n v-for=\"option in props.options\"\n :key=\"String(getOptionValue(option))\"\n v-bind=\"getOptionProps(option)\"\n >\n {{ getOptionLabel(option) }}\n </ElCheckbox>\n </ElCheckboxGroup>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElCheckboxGroup 渲染复选字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElCheckbox, ElCheckboxGroup } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type {\n CheckboxOption,\n CheckboxOptionValue,\n CheckboxRendererProps,\n CheckboxValue,\n } from \"./types\"\n\n defineOptions({\n name: \"CheckboxRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<CheckboxRendererProps>(), {\n value: () => [],\n options: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<CheckboxValue>(\"value\")\n\n const labelKey = computed(() => props.props?.label ?? \"label\")\n\n const valueKey = computed(() => props.props?.value ?? \"value\")\n\n const disabledKey = computed(() => props.props?.disabled ?? \"disabled\")\n\n const checkboxProps = computed(() => getElementProps(props, attrs))\n\n const selectedValues = computed(() => valueModel.value ?? props.value ?? [])\n\n const groupValues = computed(() => selectedValues.value.map(encodeValue))\n\n const selectedLabels = computed(() =>\n selectedValues.value.map((value) => {\n const option = props.options.find((item) => getOptionValue(item) === value)\n\n return option ? getOptionLabel(option) : String(value)\n })\n )\n\n /**\n * 获取选项值。\n *\n * @param option - 当前复选选项。\n * @returns 选项值。\n */\n const getOptionValue = (option: CheckboxOption): CheckboxOptionValue | undefined =>\n option[valueKey.value] as CheckboxOptionValue | undefined\n\n /** 获取传给单个 Element Plus Checkbox 的完整配置。 */\n const getOptionProps = (option: CheckboxOption): Record<string, unknown> => ({\n ...option,\n label: getOptionLabel(option),\n value: encodeValue(getOptionValue(option)),\n disabled: props.disabled || getOptionDisabled(option),\n })\n\n /**\n * 将 boolean 选项值编码为 Element Plus CheckboxGroup 支持的值。\n *\n * @param value - Schemx 对外选项值。\n * @returns CheckboxGroup 可接受的字符串或数字值。\n */\n const encodeValue = (value: CheckboxOptionValue | undefined): string | number => {\n if (typeof value === \"boolean\") return value ? \"__schemx_true__\" : \"__schemx_false__\"\n\n return value ?? \"\"\n }\n\n /**\n * 将 Element Plus CheckboxGroup 值还原为 Schemx 选项值。\n *\n * @param value - CheckboxGroup 产生的字符串或数字值。\n * @returns Schemx 对外选项值。\n */\n const decodeValue = (value: string | number): CheckboxOptionValue => {\n if (value === \"__schemx_true__\") return true\n if (value === \"__schemx_false__\") return false\n\n return value\n }\n\n /**\n * 获取选项显示文本。\n *\n * @param option - 当前复选选项。\n * @returns 选项显示文本。\n */\n const getOptionLabel = (option: CheckboxOption): string =>\n String(option[labelKey.value] ?? getOptionValue(option))\n\n /**\n * 获取选项禁用状态。\n *\n * @param option - 当前复选选项。\n * @returns 是否禁用。\n */\n const getOptionDisabled = (option: CheckboxOption): boolean =>\n Boolean(option[disabledKey.value])\n\n /**\n * 同步 Element Plus 复选值。\n *\n * @param value - Element Plus 产生的新值列表。\n */\n const handleUpdate = (value: Array<string | number>): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = value.map(decodeValue) as CheckboxValue\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-checkbox-renderer > .el-checkbox-group {\n display: flex;\n flex-wrap: wrap;\n gap: 10px 20px;\n }\n\n .schemx-checkbox-renderer > .el-checkbox-group .el-checkbox {\n margin-right: 0px;\n }\n\n .schemx-checkbox-renderer > .el-checkbox-group {\n justify-content: var(--schemx-content-align);\n }\n</style>\n","/** Checkbox Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport CheckboxRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(CheckboxRendererComponent)\nexport type { CheckboxOption, CheckboxRendererProps, CheckboxValue } from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-date-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElDatePicker\n ref=\"datePickerRef\"\n v-bind=\"datePickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElDatePicker 渲染日期字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import dayjs from \"dayjs\"\n import { ElDatePicker } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { DatePickerRendererProps, DatePickerValue } from \"./types\"\n import type { DatePickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"DatePickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<DatePickerRendererProps>(), {\n value: undefined,\n type: \"date\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<DatePickerValue>(\"value\")\n\n const datePickerRef = ref<DatePickerInstance>()\n\n const datePickerProps = computed(() => getElementProps(props, attrs))\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? null)\n\n const displayValue = computed(() => formatValue(currentValue.value))\n\n /**\n * 格式化日期值用于只读展示。\n *\n * @param value - Element Plus 日期值。\n * @returns 面向用户的日期文本。\n */\n function formatValue(value: DatePickerValue): string {\n if (Array.isArray(value)) {\n return value.map((item) => formatValue(item)).join(\" - \")\n }\n\n if (value instanceof Date || typeof value === \"number\") {\n return dayjs(value).format(props.format || \"YYYY-MM-DD\")\n }\n\n return value ? String(value) : \"\"\n }\n\n /**\n * 同步 Element Plus 日期值。\n *\n * @param value - Element Plus 产生的新日期值。\n */\n const handleUpdate = (value: DatePickerValue): void => {\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /**\n * 处理日期控件失焦。\n *\n * @param _event - Element Plus 产生的原生失焦事件。\n */\n const handleBlur = (_event: FocusEvent): void => {\n props.onBlur?.(currentValue.value)\n }\n\n /**\n * 处理日期控件聚焦。\n *\n * @param event - Element Plus 产生的原生聚焦事件。\n */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部日期输入控件。 */\n focus: () => datePickerRef.value?.focus(),\n /** 使内部日期输入控件失焦。 */\n blur: () => datePickerRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-date-picker-renderer > .el-date-editor {\n --el-date-editor-width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-date-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElDatePicker\n ref=\"datePickerRef\"\n v-bind=\"datePickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElDatePicker 渲染日期字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import dayjs from \"dayjs\"\n import { ElDatePicker } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { DatePickerRendererProps, DatePickerValue } from \"./types\"\n import type { DatePickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"DatePickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<DatePickerRendererProps>(), {\n value: undefined,\n type: \"date\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<DatePickerValue>(\"value\")\n\n const datePickerRef = ref<DatePickerInstance>()\n\n const datePickerProps = computed(() => getElementProps(props, attrs))\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? null)\n\n const displayValue = computed(() => formatValue(currentValue.value))\n\n /**\n * 格式化日期值用于只读展示。\n *\n * @param value - Element Plus 日期值。\n * @returns 面向用户的日期文本。\n */\n function formatValue(value: DatePickerValue): string {\n if (Array.isArray(value)) {\n return value.map((item) => formatValue(item)).join(\" - \")\n }\n\n if (value instanceof Date || typeof value === \"number\") {\n return dayjs(value).format(props.format || \"YYYY-MM-DD\")\n }\n\n return value ? String(value) : \"\"\n }\n\n /**\n * 同步 Element Plus 日期值。\n *\n * @param value - Element Plus 产生的新日期值。\n */\n const handleUpdate = (value: DatePickerValue): void => {\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /**\n * 处理日期控件失焦。\n *\n * @param _event - Element Plus 产生的原生失焦事件。\n */\n const handleBlur = (_event: FocusEvent): void => {\n props.onBlur?.(currentValue.value)\n }\n\n /**\n * 处理日期控件聚焦。\n *\n * @param event - Element Plus 产生的原生聚焦事件。\n */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部日期输入控件。 */\n focus: () => datePickerRef.value?.focus(),\n /** 使内部日期输入控件失焦。 */\n blur: () => datePickerRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-date-picker-renderer > .el-date-editor {\n --el-date-editor-width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-cascader-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElCascader\n ref=\"cascaderRef\"\n v-bind=\"cascaderProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElCascader 渲染级联字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElCascader } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { findTreeItem, getReadonlyDisplayValue } from \"@/utils\"\n\n import type { CascaderRendererProps, CascaderValueType } from \"./types\"\n import type { CascaderInstance, CascaderOption, CascaderValue } from \"element-plus\"\n\n defineOptions({\n name: \"CascaderRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<CascaderRendererProps>(), {\n value: null,\n options: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n showAllLevels: true,\n separator: \" / \",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<CascaderValueType>(\"value\")\n\n const cascaderRef = ref<CascaderInstance>()\n\n const valueKey = computed(() => props.props?.value ?? \"value\")\n\n const labelKey = computed(() => props.props?.label ?? \"label\")\n\n const childrenKey = computed(() => props.props?.children ?? \"children\")\n\n const cascaderProps = computed(() => getElementProps(props, attrs))\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? null)\n\n const displayValue = computed(() => getDisplayValue(currentValue.value))\n\n /**\n * 获取级联值的只读文本。\n *\n * @param value - 当前级联值。\n * @returns 级联路径显示文本。\n */\n function getDisplayValue(value: CascaderValueType): string {\n if (value === null || value === undefined) return \"\"\n\n if (props.props?.multiple && Array.isArray(value) && Array.isArray(value[0])) {\n return (value as unknown[][]).map((path) => getDisplayPath(path)).join(\"、\")\n }\n\n const targetValue = Array.isArray(value) ? value[value.length - 1] : value\n\n const result = findTreeItem(props.options as CascaderOption[], targetValue, {\n labelKey: labelKey.value,\n valueKey: valueKey.value,\n childrenKey: childrenKey.value,\n })\n\n if (result.labels.length === 0) return String(targetValue)\n\n return props.showAllLevels\n ? result.labels.join(props.separator)\n : (result.labels.at(-1) ?? \"\")\n }\n\n /**\n * 获取单条级联路径的只读文本。\n *\n * @param path - 当前级联路径的值列表。\n * @returns 级联路径显示文本。\n */\n function getDisplayPath(path: unknown[]): string {\n const targetValue = path[path.length - 1]\n\n const result = findTreeItem(props.options as CascaderOption[], targetValue, {\n labelKey: labelKey.value,\n valueKey: valueKey.value,\n childrenKey: childrenKey.value,\n })\n\n if (result.labels.length === 0) return String(targetValue)\n\n return props.showAllLevels\n ? result.labels.join(props.separator)\n : (result.labels.at(-1) ?? \"\")\n }\n\n /**\n * 同步 Element Plus 级联值。\n *\n * @param value - Element Plus 产生的新级联值。\n */\n const handleUpdate = (value: CascaderValue | null | undefined): void => {\n const nextValue = value ?? null\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /**\n * 处理级联控件失焦。\n *\n * @param _event - Element Plus 产生的原生失焦事件。\n */\n const handleBlur = (_event: FocusEvent): void => {\n props.onBlur?.(currentValue.value)\n }\n\n /**\n * 处理级联控件聚焦。\n *\n * @param event - Element Plus 产生的原生聚焦事件。\n */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部级联输入控件。 */\n focus: () => cascaderRef.value?.focus(),\n /** 使内部级联输入控件失焦。 */\n blur: () => cascaderRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-cascader-renderer > .el-cascader {\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-cascader-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElCascader\n ref=\"cascaderRef\"\n v-bind=\"cascaderProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElCascader 渲染级联字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElCascader } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { findTreeItem, getReadonlyDisplayValue } from \"@/utils\"\n\n import type { CascaderRendererProps, CascaderValueType } from \"./types\"\n import type { CascaderInstance, CascaderOption, CascaderValue } from \"element-plus\"\n\n defineOptions({\n name: \"CascaderRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<CascaderRendererProps>(), {\n value: null,\n options: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n showAllLevels: true,\n separator: \" / \",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<CascaderValueType>(\"value\")\n\n const cascaderRef = ref<CascaderInstance>()\n\n const valueKey = computed(() => props.props?.value ?? \"value\")\n\n const labelKey = computed(() => props.props?.label ?? \"label\")\n\n const childrenKey = computed(() => props.props?.children ?? \"children\")\n\n const cascaderProps = computed(() => getElementProps(props, attrs))\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? null)\n\n const displayValue = computed(() => getDisplayValue(currentValue.value))\n\n /**\n * 获取级联值的只读文本。\n *\n * @param value - 当前级联值。\n * @returns 级联路径显示文本。\n */\n function getDisplayValue(value: CascaderValueType): string {\n if (value === null || value === undefined) return \"\"\n\n if (props.props?.multiple && Array.isArray(value) && Array.isArray(value[0])) {\n return (value as unknown[][]).map((path) => getDisplayPath(path)).join(\"、\")\n }\n\n const targetValue = Array.isArray(value) ? value[value.length - 1] : value\n\n const result = findTreeItem(props.options as CascaderOption[], targetValue, {\n labelKey: labelKey.value,\n valueKey: valueKey.value,\n childrenKey: childrenKey.value,\n })\n\n if (result.labels.length === 0) return String(targetValue)\n\n return props.showAllLevels\n ? result.labels.join(props.separator)\n : (result.labels.at(-1) ?? \"\")\n }\n\n /**\n * 获取单条级联路径的只读文本。\n *\n * @param path - 当前级联路径的值列表。\n * @returns 级联路径显示文本。\n */\n function getDisplayPath(path: unknown[]): string {\n const targetValue = path[path.length - 1]\n\n const result = findTreeItem(props.options as CascaderOption[], targetValue, {\n labelKey: labelKey.value,\n valueKey: valueKey.value,\n childrenKey: childrenKey.value,\n })\n\n if (result.labels.length === 0) return String(targetValue)\n\n return props.showAllLevels\n ? result.labels.join(props.separator)\n : (result.labels.at(-1) ?? \"\")\n }\n\n /**\n * 同步 Element Plus 级联值。\n *\n * @param value - Element Plus 产生的新级联值。\n */\n const handleUpdate = (value: CascaderValue | null | undefined): void => {\n const nextValue = value ?? null\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /**\n * 处理级联控件失焦。\n *\n * @param _event - Element Plus 产生的原生失焦事件。\n */\n const handleBlur = (_event: FocusEvent): void => {\n props.onBlur?.(currentValue.value)\n }\n\n /**\n * 处理级联控件聚焦。\n *\n * @param event - Element Plus 产生的原生聚焦事件。\n */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部级联输入控件。 */\n focus: () => cascaderRef.value?.focus(),\n /** 使内部级联输入控件失焦。 */\n blur: () => cascaderRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-cascader-renderer > .el-cascader {\n width: 100%;\n }\n</style>\n","/** Cascader Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport CascaderRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(CascaderRendererComponent)\nexport type { CascaderRendererProps, CascaderValueType } from \"./types\"\n","/**\n * 将敏感值显示为首尾保留、中间掩码的文本。\n *\n * @param value - 待脱敏的文本。\n * @returns 脱敏后的文本。\n *\n * @example\n * ```ts\n * defaultMaskFormatter(\"13800138000\") // => \"138****8000\"\n * ```\n */\nexport function defaultMaskFormatter(value: string): string {\n const chars = [...value]\n\n const length = chars.length\n\n if (length <= 0) return \"\"\n if (length <= 2) return \"*\".repeat(length)\n if (length <= 6) return `${chars[0]}****${chars[length - 1]}`\n\n return `${chars.slice(0, 3).join(\"\")}****${chars.slice(-4).join(\"\")}`\n}\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-sensitive-input', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ displayValue }}\n <button\n v-if=\"canReveal\"\n type=\"button\"\n class=\"schemx-sensitive-input__toggle\"\n data-testid=\"sensitive-toggle\"\n :aria-label=\"props.revealText\"\n @click.stop=\"toggleReveal\"\n >\n <ElIcon v-if=\"props.revealIcon\">\n <component :is=\"props.revealIcon\" />\n </ElIcon>\n <span>{{ props.revealText }}</span>\n </button>\n </template>\n\n <ElInput\n ref=\"inputRef\"\n v-bind=\"inputProps\"\n :model-value=\"inputValue\"\n :readonly=\"isInputMasked\"\n @update:model-value=\"handleInputChange\"\n @blur=\"handleInputBlur\"\n @focus=\"handleInputFocus\"\n >\n <template #suffix>\n <button\n v-if=\"canReveal\"\n type=\"button\"\n class=\"schemx-sensitive-input__toggle\"\n data-testid=\"sensitive-toggle\"\n :aria-label=\"isRevealed ? props.hideText : props.revealText\"\n @click.stop=\"toggleReveal\"\n >\n <ElIcon v-if=\"isRevealed ? props.hideIcon : props.revealIcon\">\n <component :is=\"isRevealed ? props.hideIcon : props.revealIcon\" />\n </ElIcon>\n <span>{{ isRevealed ? props.hideText : props.revealText }}</span>\n </button>\n </template>\n </ElInput>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInput 实现与 Vant 一致的脱敏输入状态流。 */\n import { computed, nextTick, ref, useAttrs, watch } from \"vue\"\n\n import { Hide, View } from \"@element-plus/icons-vue\"\n import { Wrapper } from \"@schemx/vue\"\n import { ElIcon, ElInput } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { isEmptyDisplayValue } from \"@/utils\"\n\n import { defaultMaskFormatter } from \"./helper\"\n\n import type { SensitiveInputRendererProps, SensitiveInputValue } from \"./types\"\n import type { InputInstance } from \"element-plus\"\n\n defineOptions({\n name: \"SensitiveInput\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SensitiveInputRendererProps>(), {\n value: \"\",\n onChange: undefined,\n onBlur: undefined,\n onFocus: undefined,\n formatter: undefined,\n maskFormatter: defaultMaskFormatter,\n defaultRevealed: false,\n revealed: undefined,\n revealable: true,\n revealText: \"\",\n hideText: \"\",\n revealIcon: View,\n hideIcon: Hide,\n focusOnReveal: true,\n hideOnBlur: false,\n revealWhenReadonly: true,\n placeholder: \"\",\n readonlyPlaceholder: \"-\",\n disabled: false,\n readonly: false,\n className: \"\",\n })\n\n const emit = defineEmits<{\n \"reveal-change\": [revealed: boolean]\n change: [value: SensitiveInputValue]\n blur: [event: FocusEvent]\n }>()\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const inputRef = ref<InputInstance>()\n\n const valueModel = defineModel<SensitiveInputValue>(\"value\")\n\n const revealedState = ref(props.revealed ?? props.defaultRevealed)\n\n const rawValue = computed(() => String(valueModel.value ?? props.value ?? \"\"))\n\n const isEmpty = computed(() => isEmptyDisplayValue(rawValue.value))\n\n const isRevealed = computed(() => props.revealed ?? revealedState.value)\n\n const canReveal = computed(() => {\n if (isEmpty.value || !props.revealable || props.disabled) return false\n if (props.readonly && !props.revealWhenReadonly) return false\n\n return true\n })\n\n const formattedValue = computed(\n () => props.formatter?.(normalizeValue(rawValue.value)) ?? rawValue.value\n )\n\n const maskedValue = computed(() =>\n props.maskFormatter(normalizeValue(rawValue.value), {\n placeholder: props.placeholder ?? \"\",\n readonlyPlaceholder: props.readonlyPlaceholder ?? \"-\",\n })\n )\n\n const displayValue = computed(() => {\n if (props.readonly && isRevealed.value) return formattedValue.value\n\n return maskedValue.value\n })\n\n const isInputMasked = computed(\n () => props.revealable && !isEmpty.value && !isRevealed.value\n )\n\n const inputValue = computed(() =>\n isInputMasked.value ? maskedValue.value : formattedValue.value\n )\n\n const inputProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"type\",\n \"formatter\",\n \"onChange\",\n \"onBlur\",\n \"onFocus\",\n \"value\",\n \"revealed\",\n \"onRevealChange\",\n \"defaultRevealed\",\n \"revealable\",\n \"revealText\",\n \"hideText\",\n \"revealIcon\",\n \"hideIcon\",\n \"focusOnReveal\",\n \"hideOnBlur\",\n \"revealWhenReadonly\",\n \"maskFormatter\",\n ]),\n type: \"text\" as const,\n }))\n\n watch(\n () => props.revealed,\n (value) => {\n if (value !== undefined) revealedState.value = value\n }\n )\n\n /**\n * 规范化真实值,保持与 Vant 适配包一致的格式化输入。\n *\n * @param value - 原始真实值。\n * @returns 去除首尾空格和内部空格的值。\n */\n function normalizeValue(value: string): string {\n return value.trim().replace(/\\s/g, \"\")\n }\n\n /**\n * 设置显示状态并发送状态变化事件。\n *\n * @param next - 目标显示状态。\n */\n const setRevealed = (next: boolean): void => {\n if (isRevealed.value === next) return\n\n if (props.revealed === undefined) revealedState.value = next\n\n props.onRevealChange?.(next)\n emit(\"reveal-change\", next)\n }\n\n /** 切换脱敏状态并在展开输入框后按配置聚焦。 */\n const toggleReveal = (): void => {\n if (!canReveal.value) return\n\n const next = !isRevealed.value\n\n setRevealed(next)\n\n if (next && props.focusOnReveal && !props.readonly) {\n void nextTick(() => inputRef.value?.focus?.())\n }\n }\n\n /**\n * 处理输入框值变化。\n *\n * @param value - 输入框产生的新真实值。\n */\n const handleInputChange = (value: string): void => {\n if (props.revealable && !isEmptyDisplayValue(value)) setRevealed(true)\n\n valueModel.value = value\n props.onChange?.(value)\n emit(\"change\", value)\n }\n\n /**\n * 处理输入框失焦。\n *\n * @param event - 原生失焦事件。\n */\n const handleInputBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n emit(\"blur\", event)\n\n if (props.hideOnBlur) setRevealed(false)\n }\n\n /** 转发输入框聚焦事件。 */\n const handleInputFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部输入框。 */\n focus: () => inputRef.value?.focus?.(),\n /** 使内部输入框失焦。 */\n blur: () => inputRef.value?.blur?.(),\n })\n</script>\n\n<style lang=\"scss\">\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-sensitive-input {\n display: flex;\n align-items: center;\n justify-content: var(--schemx-content-align);\n gap: 6px;\n width: 100%;\n }\n\n .schemx-sensitive-input__toggle {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n border: 0;\n padding: 0;\n color: var(--schemx-sensitive-input-action-color, var(--el-color-primary));\n font: inherit;\n line-height: inherit;\n background: transparent;\n cursor: pointer;\n }\n\n .schemx-sensitive-input__toggle:focus-visible {\n border-radius: 4px;\n outline: 2px solid var(--el-color-primary);\n outline-offset: 2px;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-sensitive-input', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ displayValue }}\n <button\n v-if=\"canReveal\"\n type=\"button\"\n class=\"schemx-sensitive-input__toggle\"\n data-testid=\"sensitive-toggle\"\n :aria-label=\"props.revealText\"\n @click.stop=\"toggleReveal\"\n >\n <ElIcon v-if=\"props.revealIcon\">\n <component :is=\"props.revealIcon\" />\n </ElIcon>\n <span>{{ props.revealText }}</span>\n </button>\n </template>\n\n <ElInput\n ref=\"inputRef\"\n v-bind=\"inputProps\"\n :model-value=\"inputValue\"\n :readonly=\"isInputMasked\"\n @update:model-value=\"handleInputChange\"\n @blur=\"handleInputBlur\"\n @focus=\"handleInputFocus\"\n >\n <template #suffix>\n <button\n v-if=\"canReveal\"\n type=\"button\"\n class=\"schemx-sensitive-input__toggle\"\n data-testid=\"sensitive-toggle\"\n :aria-label=\"isRevealed ? props.hideText : props.revealText\"\n @click.stop=\"toggleReveal\"\n >\n <ElIcon v-if=\"isRevealed ? props.hideIcon : props.revealIcon\">\n <component :is=\"isRevealed ? props.hideIcon : props.revealIcon\" />\n </ElIcon>\n <span>{{ isRevealed ? props.hideText : props.revealText }}</span>\n </button>\n </template>\n </ElInput>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInput 实现与 Vant 一致的脱敏输入状态流。 */\n import { computed, nextTick, ref, useAttrs, watch } from \"vue\"\n\n import { Hide, View } from \"@element-plus/icons-vue\"\n import { Wrapper } from \"@schemx/vue\"\n import { ElIcon, ElInput } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { isEmptyDisplayValue } from \"@/utils\"\n\n import { defaultMaskFormatter } from \"./helper\"\n\n import type { SensitiveInputRendererProps, SensitiveInputValue } from \"./types\"\n import type { InputInstance } from \"element-plus\"\n\n defineOptions({\n name: \"SensitiveInput\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SensitiveInputRendererProps>(), {\n value: \"\",\n onChange: undefined,\n onBlur: undefined,\n onFocus: undefined,\n formatter: undefined,\n maskFormatter: defaultMaskFormatter,\n defaultRevealed: false,\n revealed: undefined,\n revealable: true,\n revealText: \"\",\n hideText: \"\",\n revealIcon: View,\n hideIcon: Hide,\n focusOnReveal: true,\n hideOnBlur: false,\n revealWhenReadonly: true,\n placeholder: \"\",\n readonlyPlaceholder: \"-\",\n disabled: false,\n readonly: false,\n className: \"\",\n })\n\n const emit = defineEmits<{\n \"reveal-change\": [revealed: boolean]\n change: [value: SensitiveInputValue]\n blur: [event: FocusEvent]\n }>()\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const inputRef = ref<InputInstance>()\n\n const valueModel = defineModel<SensitiveInputValue>(\"value\")\n\n const revealedState = ref(props.revealed ?? props.defaultRevealed)\n\n const rawValue = computed(() => String(valueModel.value ?? props.value ?? \"\"))\n\n const isEmpty = computed(() => isEmptyDisplayValue(rawValue.value))\n\n const isRevealed = computed(() => props.revealed ?? revealedState.value)\n\n const canReveal = computed(() => {\n if (isEmpty.value || !props.revealable || props.disabled) return false\n if (props.readonly && !props.revealWhenReadonly) return false\n\n return true\n })\n\n const formattedValue = computed(\n () => props.formatter?.(normalizeValue(rawValue.value)) ?? rawValue.value\n )\n\n const maskedValue = computed(() =>\n props.maskFormatter(normalizeValue(rawValue.value), {\n placeholder: props.placeholder ?? \"\",\n readonlyPlaceholder: props.readonlyPlaceholder ?? \"-\",\n })\n )\n\n const displayValue = computed(() => {\n if (props.readonly && isRevealed.value) return formattedValue.value\n\n return maskedValue.value\n })\n\n const isInputMasked = computed(\n () => props.revealable && !isEmpty.value && !isRevealed.value\n )\n\n const inputValue = computed(() =>\n isInputMasked.value ? maskedValue.value : formattedValue.value\n )\n\n const inputProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"type\",\n \"formatter\",\n \"onChange\",\n \"onBlur\",\n \"onFocus\",\n \"value\",\n \"revealed\",\n \"onRevealChange\",\n \"defaultRevealed\",\n \"revealable\",\n \"revealText\",\n \"hideText\",\n \"revealIcon\",\n \"hideIcon\",\n \"focusOnReveal\",\n \"hideOnBlur\",\n \"revealWhenReadonly\",\n \"maskFormatter\",\n ]),\n type: \"text\" as const,\n }))\n\n watch(\n () => props.revealed,\n (value) => {\n if (value !== undefined) revealedState.value = value\n }\n )\n\n /**\n * 规范化真实值,保持与 Vant 适配包一致的格式化输入。\n *\n * @param value - 原始真实值。\n * @returns 去除首尾空格和内部空格的值。\n */\n function normalizeValue(value: string): string {\n return value.trim().replace(/\\s/g, \"\")\n }\n\n /**\n * 设置显示状态并发送状态变化事件。\n *\n * @param next - 目标显示状态。\n */\n const setRevealed = (next: boolean): void => {\n if (isRevealed.value === next) return\n\n if (props.revealed === undefined) revealedState.value = next\n\n props.onRevealChange?.(next)\n emit(\"reveal-change\", next)\n }\n\n /** 切换脱敏状态并在展开输入框后按配置聚焦。 */\n const toggleReveal = (): void => {\n if (!canReveal.value) return\n\n const next = !isRevealed.value\n\n setRevealed(next)\n\n if (next && props.focusOnReveal && !props.readonly) {\n void nextTick(() => inputRef.value?.focus?.())\n }\n }\n\n /**\n * 处理输入框值变化。\n *\n * @param value - 输入框产生的新真实值。\n */\n const handleInputChange = (value: string): void => {\n if (props.revealable && !isEmptyDisplayValue(value)) setRevealed(true)\n\n valueModel.value = value\n props.onChange?.(value)\n emit(\"change\", value)\n }\n\n /**\n * 处理输入框失焦。\n *\n * @param event - 原生失焦事件。\n */\n const handleInputBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n emit(\"blur\", event)\n\n if (props.hideOnBlur) setRevealed(false)\n }\n\n /** 转发输入框聚焦事件。 */\n const handleInputFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部输入框。 */\n focus: () => inputRef.value?.focus?.(),\n /** 使内部输入框失焦。 */\n blur: () => inputRef.value?.blur?.(),\n })\n</script>\n\n<style lang=\"scss\">\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-sensitive-input {\n display: flex;\n align-items: center;\n justify-content: var(--schemx-content-align);\n gap: 6px;\n width: 100%;\n }\n\n .schemx-sensitive-input__toggle {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n border: 0;\n padding: 0;\n color: var(--schemx-sensitive-input-action-color, var(--el-color-primary));\n font: inherit;\n line-height: inherit;\n background: transparent;\n cursor: pointer;\n }\n\n .schemx-sensitive-input__toggle:focus-visible {\n border-radius: 4px;\n outline: 2px solid var(--el-color-primary);\n outline-offset: 2px;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-rate-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n <ElRate v-bind=\"rateProps\" :model-value=\"currentValue\" disabled />\n </template>\n <ElRate\n v-bind=\"rateProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElRate 渲染评分字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElRate } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n\n import type { RateRendererProps, RateValue } from \"./types\"\n\n defineOptions({\n name: \"RateRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<RateRendererProps>(), {\n value: 0,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<RateValue>(\"value\")\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? 0)\n\n const rateProps = computed(() => getElementProps(props, attrs))\n\n /**\n * 同步 Element Plus 评分值。\n *\n * @param value - Element Plus 产生的新评分。\n */\n const handleUpdate = (value: number): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-rate-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n <ElRate v-bind=\"rateProps\" :model-value=\"currentValue\" disabled />\n </template>\n <ElRate\n v-bind=\"rateProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElRate 渲染评分字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElRate } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n\n import type { RateRendererProps, RateValue } from \"./types\"\n\n defineOptions({\n name: \"RateRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<RateRendererProps>(), {\n value: 0,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<RateValue>(\"value\")\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? 0)\n\n const rateProps = computed(() => getElementProps(props, attrs))\n\n /**\n * 同步 Element Plus 评分值。\n *\n * @param value - Element Plus 产生的新评分。\n */\n const handleUpdate = (value: number): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-slider-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElSlider\n v-bind=\"sliderProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSlider 渲染滑块字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSlider } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { SliderRendererProps, SliderValue } from \"./types\"\n\n defineOptions({\n name: \"SliderRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SliderRendererProps>(), {\n value: 0,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<SliderValue>(\"value\")\n\n const sliderProps = computed(() => getElementProps(props, attrs))\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? 0)\n\n const displayValue = computed(() =>\n Array.isArray(currentValue.value)\n ? currentValue.value.join(\" - \")\n : currentValue.value\n )\n\n /**\n * 同步 Element Plus 滑块值。\n *\n * @param value - Element Plus 产生的新滑块值。\n */\n const handleUpdate = (value: number | number[]): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue: SliderValue = Array.isArray(value)\n ? [value[0] ?? 0, value[1] ?? value[0] ?? 0]\n : value\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-slider-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElSlider\n v-bind=\"sliderProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSlider 渲染滑块字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSlider } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { SliderRendererProps, SliderValue } from \"./types\"\n\n defineOptions({\n name: \"SliderRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SliderRendererProps>(), {\n value: 0,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<SliderValue>(\"value\")\n\n const sliderProps = computed(() => getElementProps(props, attrs))\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? 0)\n\n const displayValue = computed(() =>\n Array.isArray(currentValue.value)\n ? currentValue.value.join(\" - \")\n : currentValue.value\n )\n\n /**\n * 同步 Element Plus 滑块值。\n *\n * @param value - Element Plus 产生的新滑块值。\n */\n const handleUpdate = (value: number | number[]): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue: SliderValue = Array.isArray(value)\n ? [value[0] ?? 0, value[1] ?? value[0] ?? 0]\n : value\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<script setup lang=\"ts\">\n import { Delete, Download, View } from \"@element-plus/icons-vue\"\n import { ElButton, ElTooltip } from \"element-plus\"\n\n interface FileActionsProps {\n canPreview?: boolean\n canDownload?: boolean\n canRemove?: boolean\n layout?: \"inline\" | \"overlay\" | \"footer\"\n showPreview?: boolean\n showDownload?: boolean\n showRemove?: boolean\n }\n\n const props = withDefaults(defineProps<FileActionsProps>(), {\n canPreview: false,\n canDownload: false,\n canRemove: false,\n layout: \"inline\",\n showPreview: true,\n showDownload: true,\n showRemove: true,\n })\n\n const emit = defineEmits<{\n preview: []\n download: []\n remove: []\n }>()\n</script>\n\n<template>\n <div class=\"file-actions\" :class=\"`file-actions--${props.layout}`\">\n <ElTooltip\n v-if=\"props.showPreview && props.canPreview\"\n content=\"预览\"\n :disabled=\"props.layout !== 'inline'\"\n >\n <ElButton\n link\n :icon=\"View\"\n title=\"预览\"\n aria-label=\"预览\"\n @click.stop=\"emit('preview')\"\n />\n </ElTooltip>\n <ElTooltip\n v-if=\"props.showDownload && props.canDownload\"\n content=\"下载\"\n :disabled=\"props.layout !== 'inline'\"\n >\n <ElButton\n link\n :icon=\"Download\"\n title=\"下载\"\n aria-label=\"下载\"\n @click.stop=\"emit('download')\"\n />\n </ElTooltip>\n <ElTooltip\n v-if=\"props.showRemove && props.canRemove\"\n content=\"删除\"\n :disabled=\"props.layout !== 'inline'\"\n >\n <ElButton\n link\n type=\"danger\"\n :icon=\"Delete\"\n title=\"删除\"\n aria-label=\"删除\"\n @click.stop=\"emit('remove')\"\n />\n </ElTooltip>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n .file-actions {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n gap: 11px;\n\n &--inline {\n margin-left: 12px;\n }\n\n &--overlay {\n position: absolute;\n inset: 0;\n justify-content: center;\n gap: 10px;\n background: rgb(0 0 0 / 45%);\n opacity: 0;\n transition: opacity 0.2s;\n\n :deep(.el-button:not(.el-button--danger)) {\n color: #fff;\n }\n }\n\n :deep(.el-button) {\n margin-left: 0px;\n\n --el-font-size-base: 16px;\n }\n }\n\n :global(\n .file-display--picture-card .file-display__card-body:hover .file-actions--overlay\n ),\n :global(\n .file-display--picture-card\n .file-display__card-body:focus-within\n .file-actions--overlay\n ) {\n opacity: 1;\n }\n</style>\n","<script setup lang=\"ts\">\n import { Delete, Download, View } from \"@element-plus/icons-vue\"\n import { ElButton, ElTooltip } from \"element-plus\"\n\n interface FileActionsProps {\n canPreview?: boolean\n canDownload?: boolean\n canRemove?: boolean\n layout?: \"inline\" | \"overlay\" | \"footer\"\n showPreview?: boolean\n showDownload?: boolean\n showRemove?: boolean\n }\n\n const props = withDefaults(defineProps<FileActionsProps>(), {\n canPreview: false,\n canDownload: false,\n canRemove: false,\n layout: \"inline\",\n showPreview: true,\n showDownload: true,\n showRemove: true,\n })\n\n const emit = defineEmits<{\n preview: []\n download: []\n remove: []\n }>()\n</script>\n\n<template>\n <div class=\"file-actions\" :class=\"`file-actions--${props.layout}`\">\n <ElTooltip\n v-if=\"props.showPreview && props.canPreview\"\n content=\"预览\"\n :disabled=\"props.layout !== 'inline'\"\n >\n <ElButton\n link\n :icon=\"View\"\n title=\"预览\"\n aria-label=\"预览\"\n @click.stop=\"emit('preview')\"\n />\n </ElTooltip>\n <ElTooltip\n v-if=\"props.showDownload && props.canDownload\"\n content=\"下载\"\n :disabled=\"props.layout !== 'inline'\"\n >\n <ElButton\n link\n :icon=\"Download\"\n title=\"下载\"\n aria-label=\"下载\"\n @click.stop=\"emit('download')\"\n />\n </ElTooltip>\n <ElTooltip\n v-if=\"props.showRemove && props.canRemove\"\n content=\"删除\"\n :disabled=\"props.layout !== 'inline'\"\n >\n <ElButton\n link\n type=\"danger\"\n :icon=\"Delete\"\n title=\"删除\"\n aria-label=\"删除\"\n @click.stop=\"emit('remove')\"\n />\n </ElTooltip>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n .file-actions {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n gap: 11px;\n\n &--inline {\n margin-left: 12px;\n }\n\n &--overlay {\n position: absolute;\n inset: 0;\n justify-content: center;\n gap: 10px;\n background: rgb(0 0 0 / 45%);\n opacity: 0;\n transition: opacity 0.2s;\n\n :deep(.el-button:not(.el-button--danger)) {\n color: #fff;\n }\n }\n\n :deep(.el-button) {\n margin-left: 0px;\n\n --el-font-size-base: 16px;\n }\n }\n\n :global(\n .file-display--picture-card .file-display__card-body:hover .file-actions--overlay\n ),\n :global(\n .file-display--picture-card\n .file-display__card-body:focus-within\n .file-actions--overlay\n ) {\n opacity: 1;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from \"vue\"\n\n import { Document } from \"@element-plus/icons-vue\"\n\n import FileActions from \"./file-actions.vue\"\n\n import type { UploadListType } from \"./types\"\n import type { UploadFile as ElementUploadFile, UploadProps } from \"element-plus\"\n\n defineOptions({\n inheritAttrs: false,\n })\n\n interface UploadDisplayFile extends ElementUploadFile {\n type?: string\n previewUrl?: string\n downloadUrl?: string\n }\n\n interface FileDisplayProps {\n file: UploadDisplayFile\n index: number\n listType?: UploadListType | \"picture-img\"\n disabled?: boolean\n readonly?: boolean\n fileType?: string\n crossorigin?: UploadProps[\"crossorigin\"]\n loadText?: string\n }\n\n const props = withDefaults(defineProps<FileDisplayProps>(), {\n listType: \"text\",\n disabled: false,\n readonly: false,\n fileType: \"\",\n crossorigin: \"\",\n loadText: \"\",\n })\n\n const emit = defineEmits<{\n preview: [file: UploadDisplayFile]\n download: [file: UploadDisplayFile, index: number]\n remove: [file: UploadDisplayFile]\n }>()\n\n const imageExtensions = new Set([\n \"avif\",\n \"bmp\",\n \"gif\",\n \"heic\",\n \"heif\",\n \"ico\",\n \"jpeg\",\n \"jpg\",\n \"png\",\n \"svg\",\n \"webp\",\n ])\n\n const normalizedListType = computed<UploadListType>(() => {\n if (props.listType === \"picture\" || props.listType === \"picture-card\") {\n return props.listType\n }\n\n if (props.listType === \"picture-img\") {\n return \"picture-card\"\n }\n\n return \"text\"\n })\n\n const getExtension = (name?: string): string => {\n const cleanName = String(name).split(/[?#]/)[0].split(\"/\").pop() || \"\"\n\n const extensionIndex = cleanName.lastIndexOf(\".\")\n\n return extensionIndex > 0 ? cleanName.slice(extensionIndex + 1).toLowerCase() : \"\"\n }\n\n const isImageFile = (file: UploadDisplayFile): boolean => {\n const configuredType = String(props.fileType || \"\").toLowerCase()\n\n if ([\"image\", \"img\", \"picture\"].includes(configuredType)) {\n return true\n }\n\n if ([\"pdf\", \"video\", \"audio\"].includes(configuredType)) {\n return false\n }\n\n const mime = String(file?.raw?.type || file?.type || \"\")\n .toLowerCase()\n .split(\";\")[0]\n .trim()\n\n if (mime === \"image\" || mime.startsWith(\"image/\")) {\n return true\n }\n\n if (\n mime === \"application/pdf\" ||\n mime.startsWith(\"video/\") ||\n mime.startsWith(\"audio/\")\n ) {\n return false\n }\n\n return [file?.name, file?.url, file?.previewUrl, file?.downloadUrl].some((name) =>\n imageExtensions.has(getExtension(name))\n )\n }\n\n const canPreview = computed(() => Boolean(props.file))\n\n const canDownload = computed(() =>\n Boolean(\n props.file.previewUrl || props.file.url || props.file.downloadUrl || props.file.raw\n )\n )\n\n const canRemove = computed(() => !props.disabled && !props.readonly)\n\n const openPreview = () => {\n if (canPreview.value) {\n emit(\"preview\", props.file)\n }\n }\n\n const handleDownload = () => {\n if (canDownload.value) {\n emit(\"download\", props.file, props.index)\n }\n }\n\n const handleRemove = () => {\n if (canRemove.value) {\n emit(\"remove\", props.file)\n }\n }\n</script>\n\n<template>\n <div class=\"file-display\" :class=\"`file-display--${normalizedListType}`\">\n <div\n v-if=\"normalizedListType === 'text'\"\n class=\"file-display__text-item\"\n :class=\"{ 'file-display__text-item--error': file.status === 'fail' }\"\n >\n <div\n class=\"file-display__text-info\"\n :class=\"{ 'file-display__text-info--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <el-icon class=\"file-display__text-icon\"><Document /></el-icon>\n <span class=\"file-display__text-name\" :title=\"file.name\">\n {{ file.name || \"未命名文件\" }}\n </span>\n <span v-if=\"file.status === 'uploading'\" class=\"file-display__text-status\">\n {{ loadText || `${Math.round(file.percentage || 0)}%` }}\n </span>\n <span v-else-if=\"file.status === 'fail'\" class=\"file-display__text-status\">\n 上传失败\n </span>\n </div>\n\n <FileActions\n :can-preview=\"canPreview\"\n :can-download=\"canDownload\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n </div>\n\n <div\n v-else-if=\"normalizedListType === 'picture'\"\n class=\"file-display__picture-item\"\n :class=\"{ 'file-display__picture-item--error': file.status === 'fail' }\"\n >\n <div\n class=\"file-display__picture-thumb\"\n :class=\"{ 'file-display__picture-thumb--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <img\n v-if=\"isImageFile(file) && (file.previewUrl || file.url)\"\n class=\"file-display__picture-image\"\n :src=\"file.previewUrl || file.url\"\n :crossorigin=\"crossorigin || undefined\"\n :alt=\"file.name\"\n />\n <el-icon v-else class=\"file-display__picture-file-icon\"><Document /></el-icon>\n </div>\n\n <div\n class=\"file-display__picture-info\"\n :class=\"{ 'file-display__picture-info--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <span class=\"file-display__picture-name\" :title=\"file.name\">\n {{ file.name || \"未命名文件\" }}\n </span>\n <span v-if=\"file.status === 'uploading'\" class=\"file-display__picture-status\">\n {{ loadText || `${Math.round(file.percentage || 0)}%` }}\n </span>\n <span v-else-if=\"file.status === 'fail'\" class=\"file-display__picture-status\">\n 上传失败\n </span>\n </div>\n\n <FileActions\n :can-preview=\"canPreview\"\n :can-download=\"canDownload\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n </div>\n\n <div\n v-else\n class=\"file-display__card\"\n :class=\"{ 'file-display__card--error': file.status === 'fail' }\"\n >\n <div\n class=\"file-display__card-body\"\n :class=\"{ 'file-display__card-body--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <img\n v-if=\"isImageFile(file) && (file.previewUrl || file.url)\"\n class=\"file-display__card-image\"\n :src=\"file.previewUrl || file.url\"\n :crossorigin=\"crossorigin || undefined\"\n :alt=\"file.name\"\n />\n <el-icon v-else class=\"file-display__card-file-icon\"><Document /></el-icon>\n <FileActions\n layout=\"overlay\"\n :can-preview=\"canPreview\"\n :can-download=\"canDownload\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n <span v-if=\"file.status === 'uploading'\" class=\"file-display__card-status\">\n {{ loadText || `${Math.round(file.percentage || 0)}%` }}\n </span>\n <span v-else-if=\"file.status === 'fail'\" class=\"file-display__card-status\">\n 上传失败\n </span>\n </div>\n\n <!-- <div class=\"file-display__card-footer\">\n <span class=\"file-display__card-name\" :title=\"file.name\">\n {{ file.name || \"未命名文件\" }}\n </span>\n <FileActions\n layout=\"footer\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n </div> -->\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n .file-display {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n\n &--text {\n .file-display__text-item {\n display: flex;\n align-items: center;\n min-height: 36px;\n padding: 0 10px;\n border-radius: 4px;\n background: var(--el-fill-color-lighter);\n transition: background-color 0.2s;\n\n &:hover {\n background: var(--el-fill-color-light);\n }\n\n &--error {\n color: var(--el-color-danger);\n }\n }\n\n .file-display__text-info {\n display: flex;\n flex: 1;\n align-items: center;\n min-width: 0;\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n .file-display__text-icon {\n flex-shrink: 0;\n margin-right: 8px;\n color: var(--el-text-color-secondary);\n }\n\n .file-display__text-name {\n overflow: hidden;\n color: var(--el-text-color-regular);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .file-display__text-status {\n flex-shrink: 0;\n margin-left: 8px;\n color: var(--el-text-color-secondary);\n font-size: 12px;\n }\n }\n\n &--picture {\n .file-display__picture-item {\n display: flex;\n align-items: center;\n min-height: 36px;\n border-radius: 4px;\n transition: background-color 0.2s;\n\n &--error {\n color: var(--el-color-danger);\n }\n }\n\n .file-display__picture-thumb {\n display: flex;\n flex: 0 0 48px;\n align-items: center;\n justify-content: center;\n width: 45px;\n height: 45px;\n margin-right: 10px;\n overflow: hidden;\n border-radius: 4px;\n background: var(--el-fill-color);\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n .file-display__picture-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .file-display__picture-file-icon {\n color: var(--el-text-color-secondary);\n font-size: 24px;\n }\n\n .file-display__picture-info {\n display: flex;\n flex: 1;\n align-items: center;\n min-width: 0;\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n .file-display__picture-name {\n overflow: hidden;\n color: var(--el-text-color-regular);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .file-display__picture-status {\n flex-shrink: 0;\n margin-left: 8px;\n color: var(--el-text-color-secondary);\n font-size: 12px;\n }\n }\n\n &--picture-card {\n height: 100%;\n .file-display__card {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--el-bg-color);\n\n &--error {\n color: var(--el-color-danger);\n }\n\n &-body {\n position: relative;\n display: flex;\n flex: 1;\n align-items: center;\n justify-content: center;\n min-height: 0;\n overflow: hidden;\n background: var(--el-fill-color-lighter);\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n &-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &-file-icon {\n color: var(--el-text-color-secondary);\n font-size: 36px;\n }\n\n &-status {\n position: absolute;\n right: 6px;\n bottom: 4px;\n padding: 1px 4px;\n border-radius: 3px;\n background: rgb(0 0 0 / 55%);\n color: #fff;\n font-size: 12px;\n }\n\n &-footer {\n display: flex;\n flex: 0 0 32px;\n align-items: center;\n gap: 4px;\n min-width: 0;\n padding: 0 6px;\n }\n\n &-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n color: var(--el-text-color-regular);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from \"vue\"\n\n import { Document } from \"@element-plus/icons-vue\"\n\n import FileActions from \"./file-actions.vue\"\n\n import type { UploadListType } from \"./types\"\n import type { UploadFile as ElementUploadFile, UploadProps } from \"element-plus\"\n\n defineOptions({\n inheritAttrs: false,\n })\n\n interface UploadDisplayFile extends ElementUploadFile {\n type?: string\n previewUrl?: string\n downloadUrl?: string\n }\n\n interface FileDisplayProps {\n file: UploadDisplayFile\n index: number\n listType?: UploadListType | \"picture-img\"\n disabled?: boolean\n readonly?: boolean\n fileType?: string\n crossorigin?: UploadProps[\"crossorigin\"]\n loadText?: string\n }\n\n const props = withDefaults(defineProps<FileDisplayProps>(), {\n listType: \"text\",\n disabled: false,\n readonly: false,\n fileType: \"\",\n crossorigin: \"\",\n loadText: \"\",\n })\n\n const emit = defineEmits<{\n preview: [file: UploadDisplayFile]\n download: [file: UploadDisplayFile, index: number]\n remove: [file: UploadDisplayFile]\n }>()\n\n const imageExtensions = new Set([\n \"avif\",\n \"bmp\",\n \"gif\",\n \"heic\",\n \"heif\",\n \"ico\",\n \"jpeg\",\n \"jpg\",\n \"png\",\n \"svg\",\n \"webp\",\n ])\n\n const normalizedListType = computed<UploadListType>(() => {\n if (props.listType === \"picture\" || props.listType === \"picture-card\") {\n return props.listType\n }\n\n if (props.listType === \"picture-img\") {\n return \"picture-card\"\n }\n\n return \"text\"\n })\n\n const getExtension = (name?: string): string => {\n const cleanName = String(name).split(/[?#]/)[0].split(\"/\").pop() || \"\"\n\n const extensionIndex = cleanName.lastIndexOf(\".\")\n\n return extensionIndex > 0 ? cleanName.slice(extensionIndex + 1).toLowerCase() : \"\"\n }\n\n const isImageFile = (file: UploadDisplayFile): boolean => {\n const configuredType = String(props.fileType || \"\").toLowerCase()\n\n if ([\"image\", \"img\", \"picture\"].includes(configuredType)) {\n return true\n }\n\n if ([\"pdf\", \"video\", \"audio\"].includes(configuredType)) {\n return false\n }\n\n const mime = String(file?.raw?.type || file?.type || \"\")\n .toLowerCase()\n .split(\";\")[0]\n .trim()\n\n if (mime === \"image\" || mime.startsWith(\"image/\")) {\n return true\n }\n\n if (\n mime === \"application/pdf\" ||\n mime.startsWith(\"video/\") ||\n mime.startsWith(\"audio/\")\n ) {\n return false\n }\n\n return [file?.name, file?.url, file?.previewUrl, file?.downloadUrl].some((name) =>\n imageExtensions.has(getExtension(name))\n )\n }\n\n const canPreview = computed(() => Boolean(props.file))\n\n const canDownload = computed(() =>\n Boolean(\n props.file.previewUrl || props.file.url || props.file.downloadUrl || props.file.raw\n )\n )\n\n const canRemove = computed(() => !props.disabled && !props.readonly)\n\n const openPreview = () => {\n if (canPreview.value) {\n emit(\"preview\", props.file)\n }\n }\n\n const handleDownload = () => {\n if (canDownload.value) {\n emit(\"download\", props.file, props.index)\n }\n }\n\n const handleRemove = () => {\n if (canRemove.value) {\n emit(\"remove\", props.file)\n }\n }\n</script>\n\n<template>\n <div class=\"file-display\" :class=\"`file-display--${normalizedListType}`\">\n <div\n v-if=\"normalizedListType === 'text'\"\n class=\"file-display__text-item\"\n :class=\"{ 'file-display__text-item--error': file.status === 'fail' }\"\n >\n <div\n class=\"file-display__text-info\"\n :class=\"{ 'file-display__text-info--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <el-icon class=\"file-display__text-icon\"><Document /></el-icon>\n <span class=\"file-display__text-name\" :title=\"file.name\">\n {{ file.name || \"未命名文件\" }}\n </span>\n <span v-if=\"file.status === 'uploading'\" class=\"file-display__text-status\">\n {{ loadText || `${Math.round(file.percentage || 0)}%` }}\n </span>\n <span v-else-if=\"file.status === 'fail'\" class=\"file-display__text-status\">\n 上传失败\n </span>\n </div>\n\n <FileActions\n :can-preview=\"canPreview\"\n :can-download=\"canDownload\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n </div>\n\n <div\n v-else-if=\"normalizedListType === 'picture'\"\n class=\"file-display__picture-item\"\n :class=\"{ 'file-display__picture-item--error': file.status === 'fail' }\"\n >\n <div\n class=\"file-display__picture-thumb\"\n :class=\"{ 'file-display__picture-thumb--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <img\n v-if=\"isImageFile(file) && (file.previewUrl || file.url)\"\n class=\"file-display__picture-image\"\n :src=\"file.previewUrl || file.url\"\n :crossorigin=\"crossorigin || undefined\"\n :alt=\"file.name\"\n />\n <el-icon v-else class=\"file-display__picture-file-icon\"><Document /></el-icon>\n </div>\n\n <div\n class=\"file-display__picture-info\"\n :class=\"{ 'file-display__picture-info--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <span class=\"file-display__picture-name\" :title=\"file.name\">\n {{ file.name || \"未命名文件\" }}\n </span>\n <span v-if=\"file.status === 'uploading'\" class=\"file-display__picture-status\">\n {{ loadText || `${Math.round(file.percentage || 0)}%` }}\n </span>\n <span v-else-if=\"file.status === 'fail'\" class=\"file-display__picture-status\">\n 上传失败\n </span>\n </div>\n\n <FileActions\n :can-preview=\"canPreview\"\n :can-download=\"canDownload\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n </div>\n\n <div\n v-else\n class=\"file-display__card\"\n :class=\"{ 'file-display__card--error': file.status === 'fail' }\"\n >\n <div\n class=\"file-display__card-body\"\n :class=\"{ 'file-display__card-body--clickable': canPreview }\"\n @click=\"openPreview\"\n >\n <img\n v-if=\"isImageFile(file) && (file.previewUrl || file.url)\"\n class=\"file-display__card-image\"\n :src=\"file.previewUrl || file.url\"\n :crossorigin=\"crossorigin || undefined\"\n :alt=\"file.name\"\n />\n <el-icon v-else class=\"file-display__card-file-icon\"><Document /></el-icon>\n <FileActions\n layout=\"overlay\"\n :can-preview=\"canPreview\"\n :can-download=\"canDownload\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n <span v-if=\"file.status === 'uploading'\" class=\"file-display__card-status\">\n {{ loadText || `${Math.round(file.percentage || 0)}%` }}\n </span>\n <span v-else-if=\"file.status === 'fail'\" class=\"file-display__card-status\">\n 上传失败\n </span>\n </div>\n\n <!-- <div class=\"file-display__card-footer\">\n <span class=\"file-display__card-name\" :title=\"file.name\">\n {{ file.name || \"未命名文件\" }}\n </span>\n <FileActions\n layout=\"footer\"\n :can-remove=\"canRemove\"\n @preview=\"openPreview\"\n @download=\"handleDownload\"\n @remove=\"handleRemove\"\n />\n </div> -->\n </div>\n </div>\n</template>\n\n<style scoped lang=\"scss\">\n .file-display {\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n\n &--text {\n .file-display__text-item {\n display: flex;\n align-items: center;\n min-height: 36px;\n padding: 0 10px;\n border-radius: 4px;\n background: var(--el-fill-color-lighter);\n transition: background-color 0.2s;\n\n &:hover {\n background: var(--el-fill-color-light);\n }\n\n &--error {\n color: var(--el-color-danger);\n }\n }\n\n .file-display__text-info {\n display: flex;\n flex: 1;\n align-items: center;\n min-width: 0;\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n .file-display__text-icon {\n flex-shrink: 0;\n margin-right: 8px;\n color: var(--el-text-color-secondary);\n }\n\n .file-display__text-name {\n overflow: hidden;\n color: var(--el-text-color-regular);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .file-display__text-status {\n flex-shrink: 0;\n margin-left: 8px;\n color: var(--el-text-color-secondary);\n font-size: 12px;\n }\n }\n\n &--picture {\n .file-display__picture-item {\n display: flex;\n align-items: center;\n min-height: 36px;\n border-radius: 4px;\n transition: background-color 0.2s;\n\n &--error {\n color: var(--el-color-danger);\n }\n }\n\n .file-display__picture-thumb {\n display: flex;\n flex: 0 0 48px;\n align-items: center;\n justify-content: center;\n width: 45px;\n height: 45px;\n margin-right: 10px;\n overflow: hidden;\n border-radius: 4px;\n background: var(--el-fill-color);\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n .file-display__picture-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .file-display__picture-file-icon {\n color: var(--el-text-color-secondary);\n font-size: 24px;\n }\n\n .file-display__picture-info {\n display: flex;\n flex: 1;\n align-items: center;\n min-width: 0;\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n .file-display__picture-name {\n overflow: hidden;\n color: var(--el-text-color-regular);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .file-display__picture-status {\n flex-shrink: 0;\n margin-left: 8px;\n color: var(--el-text-color-secondary);\n font-size: 12px;\n }\n }\n\n &--picture-card {\n height: 100%;\n .file-display__card {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--el-bg-color);\n\n &--error {\n color: var(--el-color-danger);\n }\n\n &-body {\n position: relative;\n display: flex;\n flex: 1;\n align-items: center;\n justify-content: center;\n min-height: 0;\n overflow: hidden;\n background: var(--el-fill-color-lighter);\n\n &--clickable {\n cursor: pointer;\n }\n }\n\n &-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n &-file-icon {\n color: var(--el-text-color-secondary);\n font-size: 36px;\n }\n\n &-status {\n position: absolute;\n right: 6px;\n bottom: 4px;\n padding: 1px 4px;\n border-radius: 3px;\n background: rgb(0 0 0 / 55%);\n color: #fff;\n font-size: 12px;\n }\n\n &-footer {\n display: flex;\n flex: 0 0 32px;\n align-items: center;\n gap: 4px;\n min-width: 0;\n padding: 0 6px;\n }\n\n &-name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n color: var(--el-text-color-regular);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n // 所有文件共用 Element Plus 查看器;非图片通过默认插槽展示提示。\n import { computed, onBeforeUnmount, ref, watch } from \"vue\"\n\n import {\n Back,\n DArrowLeft,\n DArrowRight,\n Document,\n Download,\n RefreshLeft,\n RefreshRight,\n Right,\n ZoomIn,\n ZoomOut,\n } from \"@element-plus/icons-vue\"\n import { ElButton, ElIcon, ElImageViewer } from \"element-plus\"\n\n import type { PreviewFile, UploadBeforePreview, UploadDownloadHandler } from \"./types\"\n import type { ImageViewerInstance, ImageViewerProps, UploadRawFile } from \"element-plus\"\n\n interface PreviewFileWithRaw extends PreviewFile {\n raw: UploadRawFile\n }\n\n interface PreviewEntry {\n file: PreviewFile\n sourceIndex: number\n }\n\n interface CachedObjectUrl {\n raw: UploadRawFile\n url: string\n }\n\n type PreviewSource = PreviewFile | string | null | undefined\n\n interface PreviewProps extends ImageViewerProps {\n modelValue?: boolean\n files?: PreviewSource[]\n fileType?: string\n previewFullImage?: boolean\n beforePreview?: UploadBeforePreview\n downloadHandler?: UploadDownloadHandler\n }\n\n const props = withDefaults(defineProps<PreviewProps>(), {\n modelValue: false,\n urlList: () => [],\n files: () => [],\n initialIndex: 0,\n infinite: true,\n hideOnClickModal: false,\n teleported: true,\n closeOnPressEscape: true,\n showProgress: true,\n zoomRate: 1.2,\n minScale: 0.2,\n maxScale: 7,\n crossorigin: \"\",\n fileType: \"\",\n previewFullImage: true,\n })\n\n const emit = defineEmits<{\n \"update:modelValue\": [value: boolean]\n close: []\n switch: [index: number]\n error: [event: Event]\n rotate: [degree: number]\n download: [file: PreviewFile, index: number]\n \"download-error\": [error: Error, file: PreviewFile]\n preview: [file: PreviewFile]\n }>()\n\n // internalVisible 支持 open() 命令式调用,同时保留 modelValue 控制方式。\n const activeIndex = ref(0)\n\n const internalVisible = ref(false)\n\n const imageViewerRef = ref<ImageViewerInstance>()\n\n let activeFileKey: unknown\n\n // Ignore stale results when asynchronous beforePreview hooks overlap.\n let previewRequestId = 0\n\n // Blob URL 由当前组件创建,并在组件卸载时统一释放。\n const objectUrls = new Map<unknown, CachedObjectUrl>()\n\n /**\n * 从 URL 中提取用户可见的文件名。\n *\n * @param {string} url 文件 URL。\n * @returns {string} URL 最后的路径片段,无法提取时返回默认文件名。\n */\n const getFileName = (url: string): string => {\n const cleanUrl = url.split(/[?#]/)[0]\n\n return cleanUrl.split(\"/\").pop() || \"文件\"\n }\n\n /**\n * 将字符串 URL 转换为统一的预览文件结构。\n *\n * @param {PreviewSource} file 文件 URL 或文件元数据。\n * @returns {PreviewFile|null|undefined} 统一后的文件元数据。\n */\n const normalizeFile = (file: PreviewSource): PreviewFile | null | undefined => {\n if (typeof file === \"string\") {\n return {\n url: file,\n name: getFileName(file),\n type: props.fileType || \"\",\n status: \"success\",\n }\n }\n\n return file\n }\n\n /**\n * 提取不含查询参数和片段标识的文件扩展名,并转换为小写。\n *\n * @param {string} name 文件名或文件 URL。\n * @returns {string} 小写文件扩展名。\n */\n const getExtension = (name?: string): string => {\n const cleanName = String(name).split(/[?#]/)[0].split(\"/\").pop() || \"\"\n\n const extensionIndex = cleanName.lastIndexOf(\".\")\n\n return extensionIndex > 0 ? cleanName.slice(extensionIndex + 1).toLowerCase() : \"\"\n }\n\n const imageExtensions = new Set([\n \"avif\",\n \"bmp\",\n \"gif\",\n \"heic\",\n \"heif\",\n \"ico\",\n \"jpeg\",\n \"jpg\",\n \"png\",\n \"svg\",\n \"webp\",\n ])\n\n const transparentImageUrl = \"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=\"\n\n // Generic MIME values fall back to the filename extension.\n const genericMimeTypes = new Set([\n \"application/octet-stream\",\n \"application/x-unknown\",\n \"binary/octet-stream\",\n ])\n\n /**\n * 判断文件是否为图片;其他类型使用查看器默认插槽显示提示。\n *\n * @param {PreviewFile} file 文件元数据或浏览器原始文件。\n * @returns {boolean} 是否为图片。\n */\n const isImageFile = (file?: PreviewFile): boolean => {\n const configuredType = String(props.fileType || \"\").toLowerCase()\n\n if (\n [\"image\", \"img\", \"picture\"].includes(configuredType) ||\n configuredType.startsWith(\"image/\") ||\n imageExtensions.has(configuredType)\n ) {\n return true\n }\n\n if (configuredType && !genericMimeTypes.has(configuredType)) {\n return false\n }\n\n const mime = String(file?.raw?.type || file?.type || \"\")\n .toLowerCase()\n .split(\";\")[0]\n .trim()\n\n if (mime === \"image\" || mime.startsWith(\"image/\")) {\n return true\n }\n\n if (mime && !genericMimeTypes.has(mime)) {\n return false\n }\n\n return [file?.name, file?.url, file?.previewUrl, file?.downloadUrl].some((name) =>\n imageExtensions.has(getExtension(name))\n )\n }\n\n /**\n * 为 Blob URL 缓存和图片切换生成稳定的文件标识。\n *\n * @param {PreviewFile} file 文件元数据或浏览器原始文件。\n * @returns {unknown} 稳定的文件标识。\n */\n const getObjectUrlKey = (file?: PreviewFile): unknown => file?.uid ?? file?.raw ?? file\n\n const isBlobFile = (file?: PreviewFile): file is PreviewFileWithRaw =>\n typeof Blob !== \"undefined\" && file?.raw instanceof Blob\n\n const hasPreviewSource = (file?: PreviewFile): boolean =>\n Boolean(file?.previewUrl || file?.url || file?.downloadUrl || isBlobFile(file))\n\n /**\n * 解析预览 URL,必要时创建并缓存 Blob URL。\n *\n * @param {PreviewFile} file 文件元数据或浏览器原始文件。\n * @returns {string} 可供预览渲染器使用的 URL。\n */\n const getFileUrl = (file?: PreviewFile): string => {\n if (file?.previewUrl) {\n return file.previewUrl\n }\n\n if (file?.url) {\n return file.url\n }\n\n if (file?.downloadUrl) {\n return file.downloadUrl\n }\n\n if (isBlobFile(file)) {\n const key = getObjectUrlKey(file)\n\n let cached = objectUrls.get(key)\n\n if (cached?.raw !== file.raw) {\n if (cached) URL.revokeObjectURL(cached.url)\n cached = { raw: file.raw, url: URL.createObjectURL(file.raw) }\n objectUrls.set(key, cached)\n }\n\n return cached.url\n }\n\n return \"\"\n }\n\n /**\n * 生成稳定标识,用于比较过滤前后的预览文件。\n *\n * @param {PreviewFile} file 文件元数据。\n * @returns {unknown} 稳定的文件标识。\n */\n const getFileKey = (file?: PreviewFile): unknown =>\n file?.uid ?? file?.raw ?? file?.url ?? file?.previewUrl ?? file?.downloadUrl ?? file\n\n // 保留原始文件索引,下载回调需要与 Upload fileList 的索引一致。\n const previewEntries = computed<PreviewEntry[]>(() => {\n const source: PreviewSource[] = props.files.length ? props.files : props.urlList\n\n return source\n .map((sourceFile, sourceIndex) => ({\n file: normalizeFile(sourceFile),\n sourceIndex,\n }))\n .filter((entry): entry is PreviewEntry => Boolean(entry.file))\n })\n\n const previewFiles = computed(() => previewEntries.value.map(({ file }) => file))\n\n /**\n * 将预览条目映射回输入列表索引,供下载回调使用。\n *\n * @param {PreviewFile} target 预览文件。\n * @returns {number} 输入列表索引;找不到时返回 -1。\n */\n const getSourceIndex = (target: PreviewFile): number => {\n const targetKey = getFileKey(target)\n\n return (\n previewEntries.value.find(\n ({ file }) => file === target || getFileKey(file) === targetKey\n )?.sourceIndex ?? -1\n )\n }\n\n const activeFile = computed(() => previewFiles.value[activeIndex.value])\n\n const activeFileIsImage = computed(() => isImageFile(activeFile.value))\n\n const activeFileCanRenderImage = computed(\n () => activeFileIsImage.value && hasPreviewSource(activeFile.value)\n )\n\n const viewerUrls = computed(() =>\n previewFiles.value.map((file) =>\n isImageFile(file) && hasPreviewSource(file) ? getFileUrl(file) : transparentImageUrl\n )\n )\n\n const isVisible = computed(() => props.modelValue || internalVisible.value)\n\n const previewVisible = computed(() => isVisible.value && Boolean(activeFile.value))\n\n /**\n * 将当前索引限制在可用预览文件范围内。\n *\n * @param {number} index 请求打开的文件索引。\n */\n const setActiveIndex = (index: number): void => {\n if (!previewFiles.value.length) {\n activeIndex.value = 0\n activeFileKey = undefined\n\n return\n }\n\n const safeIndex = Number.isFinite(index) ? Math.floor(index) : 0\n\n activeIndex.value = Math.min(Math.max(safeIndex, 0), previewFiles.value.length - 1)\n activeFileKey = getFileKey(previewFiles.value[activeIndex.value])\n }\n\n /**\n * 将数字索引或文件对象解析为预览列表索引。\n *\n * @param {number|PreviewFile|null|undefined} target 文件索引或文件标识。\n * @returns {number} 匹配的索引,不存在时返回 -1。\n */\n const resolveFileIndex = (target: number | PreviewFile | null | undefined): number => {\n if (typeof target === \"number\") {\n return previewEntries.value.findIndex((entry) => entry.sourceIndex === target)\n }\n\n if (!target) {\n return -1\n }\n\n const targetKey = getFileKey(target)\n\n return previewFiles.value.findIndex(\n (file) => file === target || getFileKey(file) === targetKey\n )\n }\n\n /**\n * 打开对应的预览界面,必要时等待自定义预览拦截器放行。\n *\n * @param {number|PreviewFile} target 文件索引或文件标识。\n */\n const openPreview = (target: number | PreviewFile): void => {\n const index = resolveFileIndex(target)\n\n const file = previewFiles.value[index]\n\n if (index < 0 || !file) {\n return\n }\n\n if (!props.previewFullImage && isImageFile(file) && hasPreviewSource(file)) {\n return\n }\n\n const requestId = ++previewRequestId\n\n const show = () => {\n if (requestId !== previewRequestId) return\n\n const currentIndex = resolveFileIndex(file)\n\n if (currentIndex < 0) {\n return\n }\n\n setActiveIndex(currentIndex)\n internalVisible.value = true\n emit(\"preview\", file)\n }\n\n if (typeof props.beforePreview !== \"function\") {\n show()\n\n return\n }\n\n let handled = false\n\n const done = () => {\n if (handled) {\n return\n }\n\n handled = true\n show()\n }\n\n try {\n const result = props.beforePreview(file, done)\n\n if (result && typeof result === \"object\" && typeof result.then === \"function\") {\n result\n .then((value) => {\n if (value !== false) {\n done()\n }\n })\n .catch(() => undefined)\n } else if (result !== undefined && result !== false) {\n done()\n }\n } catch {\n return\n }\n }\n\n // 关闭当前预览,并同步 v-model 状态。\n const handleClose = (): void => {\n previewRequestId += 1\n internalVisible.value = false\n emit(\"update:modelValue\", false)\n emit(\"close\")\n }\n\n /**\n * 同步 Element Plus 查看器当前文件索引。\n *\n * @param {number} index 完整预览文件列表中的索引。\n */\n const handleViewerSwitch = (index: number): void => {\n const currentFile = previewFiles.value[index]\n\n if (!currentFile) return\n\n setActiveIndex(index)\n emit(\"switch\", activeIndex.value)\n }\n\n /**\n * 将图片查看器错误转发给父组件。\n *\n * @param {Event} event 查看器错误事件。\n */\n const handleError = (event: Event): void => {\n emit(\"error\", event)\n }\n\n /**\n * 将图片旋转事件转发给父组件。\n *\n * @param {number} degree 查看器报告的旋转角度。\n */\n const handleRotate = (degree: number): void => {\n emit(\"rotate\", degree)\n }\n\n /**\n * 根据解析后的 URL 触发浏览器下载。\n *\n * @param {string} url 解析后的文件 URL。\n * @param {string} name 下载时使用的文件名。\n */\n const triggerDownload = (url: string, name: string): void => {\n const link = document.createElement(\"a\")\n\n link.href = url\n link.download = name\n link.target = \"_blank\"\n link.rel = \"noopener noreferrer\"\n document.body.appendChild(link)\n link.click()\n link.remove()\n }\n\n /**\n * 优先使用自定义处理器下载,否则通过带认证的 fetch 兜底下载。\n *\n * @param {number|PreviewFile} target 文件索引或文件标识。\n * @param {number} [sourceIndex] 输入文件列表索引。\n * @returns {Promise<void>} 下载触发后结束。\n */\n const handleDownload = async (\n target: number | PreviewFile,\n sourceIndex?: number\n ): Promise<void> => {\n const previewIndex = resolveFileIndex(target)\n\n const file = previewFiles.value[previewIndex]\n\n const url = file?.downloadUrl || getFileUrl(file)\n\n if (!file || !url) {\n return\n }\n\n const resolvedSourceIndex = getSourceIndex(file)\n\n const index =\n typeof sourceIndex === \"number\" && Number.isInteger(sourceIndex) && sourceIndex >= 0\n ? sourceIndex\n : resolvedSourceIndex >= 0\n ? resolvedSourceIndex\n : previewIndex\n\n emit(\"download\", file, index)\n\n if (props.downloadHandler) {\n try {\n await props.downloadHandler(file, index)\n } catch (error) {\n const downloadError = error instanceof Error ? error : new Error(\"文件下载失败\")\n\n emit(\"download-error\", downloadError, file)\n }\n\n return\n }\n\n if (/^(?:blob:|data:)/i.test(url)) {\n triggerDownload(url, file.name || getFileName(url))\n\n return\n }\n\n try {\n const response = await fetch(url, { credentials: \"include\" })\n\n if (!response.ok) {\n throw new Error(`文件下载失败:${response.status}`)\n }\n\n const blobUrl = URL.createObjectURL(await response.blob())\n\n triggerDownload(blobUrl, file.name || getFileName(url))\n window.setTimeout(() => URL.revokeObjectURL(blobUrl), 1000)\n } catch {\n triggerDownload(url, file.name || getFileName(url))\n }\n }\n\n /**\n * 下载查看器当前选中的文件。\n *\n * @param {number} viewerIndex 查看器列表中的索引。\n * @returns {Promise<void>|undefined} 文件存在且可下载时返回下载 Promise。\n */\n const handleViewerDownload = (viewerIndex: number): Promise<void> | undefined => {\n const file = previewFiles.value[viewerIndex]\n\n if (file && hasPreviewSource(file)) {\n return handleDownload(file)\n }\n }\n\n /**\n * 为自定义工具栏图标补充键盘操作,同时保持点击行为不变。\n *\n * @param {KeyboardEvent} event 键盘事件。\n * @param {() => void} action 待执行的工具栏操作。\n */\n const handleToolbarKeydown = (event: KeyboardEvent, action: () => void): void => {\n if (event.key !== \"Enter\" && event.key !== \" \") {\n return\n }\n\n event.preventDefault()\n action()\n }\n\n // 外部控制显隐时使用 initialIndex;命令式打开则保留当前选中的文件。\n watch(\n () => props.modelValue,\n (value) => {\n if (!value) {\n previewRequestId += 1\n internalVisible.value = false\n\n return\n }\n\n if (!previewFiles.value.length) {\n emit(\"update:modelValue\", false)\n\n return\n }\n\n setActiveIndex(resolveFileIndex(props.initialIndex))\n },\n { immediate: true }\n )\n\n watch(\n () => props.initialIndex,\n (index) => {\n if (props.modelValue) setActiveIndex(resolveFileIndex(index))\n }\n )\n\n watch(\n activeIndex,\n (index) => {\n imageViewerRef.value?.setActiveItem(index)\n },\n { flush: \"post\" }\n )\n\n watch(previewFiles, (files) => {\n const availableObjectUrls = new Map(\n files\n .filter(\n (file) => isBlobFile(file) && !file.previewUrl && !file.url && !file.downloadUrl\n )\n .map((file) => [getObjectUrlKey(file), file.raw])\n )\n\n for (const [key, cached] of objectUrls) {\n if (availableObjectUrls.get(key) !== cached.raw) {\n URL.revokeObjectURL(cached.url)\n objectUrls.delete(key)\n }\n }\n\n if (!isVisible.value) return\n if (!files.length) {\n handleClose()\n\n return\n }\n\n const currentIndex = files.findIndex((file) => getFileKey(file) === activeFileKey)\n\n if (currentIndex >= 0) {\n activeIndex.value = currentIndex\n } else {\n setActiveIndex(activeIndex.value)\n }\n })\n\n // 释放当前组件创建的所有 Blob URL,避免浏览器资源持续占用。\n onBeforeUnmount(() => {\n objectUrls.forEach(({ url }) => URL.revokeObjectURL(url))\n objectUrls.clear()\n })\n\n // FileDisplay 只通过这些方法控制预览,无需了解内部实现。\n defineExpose({\n open: openPreview,\n close: handleClose,\n download: handleDownload,\n })\n</script>\n\n<template>\n <!-- 图片使用内置画布,其他文件通过查看器默认插槽显示提示。 -->\n <ElImageViewer\n v-if=\"previewVisible\"\n ref=\"imageViewerRef\"\n class=\"upload-renderer-viewer\"\n :url-list=\"viewerUrls\"\n :initial-index=\"activeIndex\"\n :infinite=\"infinite\"\n :hide-on-click-modal=\"hideOnClickModal\"\n :teleported=\"teleported\"\n :close-on-press-escape=\"closeOnPressEscape\"\n :show-progress=\"showProgress\"\n :zoom-rate=\"zoomRate\"\n :min-scale=\"minScale\"\n :max-scale=\"maxScale\"\n :crossorigin=\"crossorigin\"\n @close=\"handleClose\"\n @switch=\"handleViewerSwitch\"\n @error=\"handleError\"\n @rotate=\"handleRotate\"\n >\n <template #toolbar=\"toolbar\">\n <slot name=\"toolbar\" v-bind=\"toolbar\">\n <template v-if=\"previewFiles.length > 1\">\n <ElIcon\n class=\"file-preview__action\"\n title=\"上一张\"\n aria-label=\"上一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.prev\"\n @keydown=\"handleToolbarKeydown($event, toolbar.prev)\"\n >\n <Back />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"下一张\"\n aria-label=\"下一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.next\"\n @keydown=\"handleToolbarKeydown($event, toolbar.next)\"\n >\n <Right />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"第一张\"\n aria-label=\"第一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.setActiveItem(0)\"\n @keydown=\"handleToolbarKeydown($event, () => toolbar.setActiveItem(0))\"\n >\n <DArrowLeft />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"最后一张\"\n aria-label=\"最后一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.setActiveItem(previewFiles.length - 1)\"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.setActiveItem(previewFiles.length - 1)\n )\n \"\n >\n <DArrowRight />\n </ElIcon>\n </template>\n <template v-if=\"activeFileCanRenderImage\">\n <ElIcon\n class=\"file-preview__action\"\n title=\"缩小\"\n aria-label=\"缩小\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.actions('zoomOut')\"\n @keydown=\"handleToolbarKeydown($event, () => toolbar.actions('zoomOut'))\"\n >\n <ZoomOut />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"放大\"\n aria-label=\"放大\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.actions('zoomIn', { enableTransition: false, zoomRate })\"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.actions('zoomIn', { enableTransition: false, zoomRate })\n )\n \"\n >\n <ZoomIn />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"顺时针旋转\"\n aria-label=\"顺时针旋转\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"\n toolbar.actions('clockwise', { rotateDeg: 180, enableTransition: false })\n \"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.actions('clockwise', { rotateDeg: 180, enableTransition: false })\n )\n \"\n >\n <RefreshRight />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"逆时针旋转\"\n aria-label=\"逆时针旋转\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"\n toolbar.actions('anticlockwise', {\n rotateDeg: 180,\n enableTransition: false,\n })\n \"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.actions('anticlockwise', {\n rotateDeg: 180,\n enableTransition: false,\n })\n )\n \"\n >\n <RefreshLeft />\n </ElIcon>\n </template>\n <ElIcon\n v-if=\"activeFileCanRenderImage\"\n class=\"file-preview__action\"\n title=\"下载\"\n aria-label=\"下载\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"handleViewerDownload(toolbar.activeIndex)\"\n @keydown=\"\n handleToolbarKeydown($event, () => handleViewerDownload(toolbar.activeIndex))\n \"\n >\n <Download />\n </ElIcon>\n </slot>\n </template>\n\n <div v-if=\"!activeFileCanRenderImage\" class=\"file-preview__content\">\n <slot\n name=\"viewer\"\n :file=\"activeFile\"\n :download=\"() => handleDownload(activeFile)\"\n :close=\"handleClose\"\n >\n <div class=\"file-preview__unsupported\">\n <el-icon class=\"file-preview__unsupported-icon\"><Document /></el-icon>\n <p>\n {{\n hasPreviewSource(activeFile)\n ? \"该文件不支持预览,请下载后查看。\"\n : \"该文件暂无可预览内容。\"\n }}\n </p>\n <ElButton\n v-if=\"hasPreviewSource(activeFile)\"\n type=\"primary\"\n link\n @click=\"handleDownload(activeFile)\"\n >\n 下载文件\n </ElButton>\n </div>\n </slot>\n </div>\n </ElImageViewer>\n</template>\n\n<style lang=\"scss\">\n .file-preview {\n &__action {\n cursor: pointer;\n outline: none;\n\n &:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n border-radius: 2px;\n }\n }\n\n &__content {\n position: absolute;\n inset: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n\n > * {\n pointer-events: auto;\n }\n }\n\n &__unsupported {\n display: flex;\n align-items: center;\n flex-direction: column;\n gap: 24px;\n color: var(--el-fill-color-light);\n\n &-icon {\n flex-shrink: 0;\n font-size: 48px;\n }\n\n p {\n margin: 0;\n font-size: 15px;\n }\n }\n }\n\n .el-image-viewer__mask {\n backdrop-filter: blur(2px);\n opacity: 1;\n background-color: rgb(0 0 0 / 35%);\n }\n</style>\n","<script setup lang=\"ts\">\n // 所有文件共用 Element Plus 查看器;非图片通过默认插槽展示提示。\n import { computed, onBeforeUnmount, ref, watch } from \"vue\"\n\n import {\n Back,\n DArrowLeft,\n DArrowRight,\n Document,\n Download,\n RefreshLeft,\n RefreshRight,\n Right,\n ZoomIn,\n ZoomOut,\n } from \"@element-plus/icons-vue\"\n import { ElButton, ElIcon, ElImageViewer } from \"element-plus\"\n\n import type { PreviewFile, UploadBeforePreview, UploadDownloadHandler } from \"./types\"\n import type { ImageViewerInstance, ImageViewerProps, UploadRawFile } from \"element-plus\"\n\n interface PreviewFileWithRaw extends PreviewFile {\n raw: UploadRawFile\n }\n\n interface PreviewEntry {\n file: PreviewFile\n sourceIndex: number\n }\n\n interface CachedObjectUrl {\n raw: UploadRawFile\n url: string\n }\n\n type PreviewSource = PreviewFile | string | null | undefined\n\n interface PreviewProps extends ImageViewerProps {\n modelValue?: boolean\n files?: PreviewSource[]\n fileType?: string\n previewFullImage?: boolean\n beforePreview?: UploadBeforePreview\n downloadHandler?: UploadDownloadHandler\n }\n\n const props = withDefaults(defineProps<PreviewProps>(), {\n modelValue: false,\n urlList: () => [],\n files: () => [],\n initialIndex: 0,\n infinite: true,\n hideOnClickModal: false,\n teleported: true,\n closeOnPressEscape: true,\n showProgress: true,\n zoomRate: 1.2,\n minScale: 0.2,\n maxScale: 7,\n crossorigin: \"\",\n fileType: \"\",\n previewFullImage: true,\n })\n\n const emit = defineEmits<{\n \"update:modelValue\": [value: boolean]\n close: []\n switch: [index: number]\n error: [event: Event]\n rotate: [degree: number]\n download: [file: PreviewFile, index: number]\n \"download-error\": [error: Error, file: PreviewFile]\n preview: [file: PreviewFile]\n }>()\n\n // internalVisible 支持 open() 命令式调用,同时保留 modelValue 控制方式。\n const activeIndex = ref(0)\n\n const internalVisible = ref(false)\n\n const imageViewerRef = ref<ImageViewerInstance>()\n\n let activeFileKey: unknown\n\n // Ignore stale results when asynchronous beforePreview hooks overlap.\n let previewRequestId = 0\n\n // Blob URL 由当前组件创建,并在组件卸载时统一释放。\n const objectUrls = new Map<unknown, CachedObjectUrl>()\n\n /**\n * 从 URL 中提取用户可见的文件名。\n *\n * @param {string} url 文件 URL。\n * @returns {string} URL 最后的路径片段,无法提取时返回默认文件名。\n */\n const getFileName = (url: string): string => {\n const cleanUrl = url.split(/[?#]/)[0]\n\n return cleanUrl.split(\"/\").pop() || \"文件\"\n }\n\n /**\n * 将字符串 URL 转换为统一的预览文件结构。\n *\n * @param {PreviewSource} file 文件 URL 或文件元数据。\n * @returns {PreviewFile|null|undefined} 统一后的文件元数据。\n */\n const normalizeFile = (file: PreviewSource): PreviewFile | null | undefined => {\n if (typeof file === \"string\") {\n return {\n url: file,\n name: getFileName(file),\n type: props.fileType || \"\",\n status: \"success\",\n }\n }\n\n return file\n }\n\n /**\n * 提取不含查询参数和片段标识的文件扩展名,并转换为小写。\n *\n * @param {string} name 文件名或文件 URL。\n * @returns {string} 小写文件扩展名。\n */\n const getExtension = (name?: string): string => {\n const cleanName = String(name).split(/[?#]/)[0].split(\"/\").pop() || \"\"\n\n const extensionIndex = cleanName.lastIndexOf(\".\")\n\n return extensionIndex > 0 ? cleanName.slice(extensionIndex + 1).toLowerCase() : \"\"\n }\n\n const imageExtensions = new Set([\n \"avif\",\n \"bmp\",\n \"gif\",\n \"heic\",\n \"heif\",\n \"ico\",\n \"jpeg\",\n \"jpg\",\n \"png\",\n \"svg\",\n \"webp\",\n ])\n\n const transparentImageUrl = \"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=\"\n\n // Generic MIME values fall back to the filename extension.\n const genericMimeTypes = new Set([\n \"application/octet-stream\",\n \"application/x-unknown\",\n \"binary/octet-stream\",\n ])\n\n /**\n * 判断文件是否为图片;其他类型使用查看器默认插槽显示提示。\n *\n * @param {PreviewFile} file 文件元数据或浏览器原始文件。\n * @returns {boolean} 是否为图片。\n */\n const isImageFile = (file?: PreviewFile): boolean => {\n const configuredType = String(props.fileType || \"\").toLowerCase()\n\n if (\n [\"image\", \"img\", \"picture\"].includes(configuredType) ||\n configuredType.startsWith(\"image/\") ||\n imageExtensions.has(configuredType)\n ) {\n return true\n }\n\n if (configuredType && !genericMimeTypes.has(configuredType)) {\n return false\n }\n\n const mime = String(file?.raw?.type || file?.type || \"\")\n .toLowerCase()\n .split(\";\")[0]\n .trim()\n\n if (mime === \"image\" || mime.startsWith(\"image/\")) {\n return true\n }\n\n if (mime && !genericMimeTypes.has(mime)) {\n return false\n }\n\n return [file?.name, file?.url, file?.previewUrl, file?.downloadUrl].some((name) =>\n imageExtensions.has(getExtension(name))\n )\n }\n\n /**\n * 为 Blob URL 缓存和图片切换生成稳定的文件标识。\n *\n * @param {PreviewFile} file 文件元数据或浏览器原始文件。\n * @returns {unknown} 稳定的文件标识。\n */\n const getObjectUrlKey = (file?: PreviewFile): unknown => file?.uid ?? file?.raw ?? file\n\n const isBlobFile = (file?: PreviewFile): file is PreviewFileWithRaw =>\n typeof Blob !== \"undefined\" && file?.raw instanceof Blob\n\n const hasPreviewSource = (file?: PreviewFile): boolean =>\n Boolean(file?.previewUrl || file?.url || file?.downloadUrl || isBlobFile(file))\n\n /**\n * 解析预览 URL,必要时创建并缓存 Blob URL。\n *\n * @param {PreviewFile} file 文件元数据或浏览器原始文件。\n * @returns {string} 可供预览渲染器使用的 URL。\n */\n const getFileUrl = (file?: PreviewFile): string => {\n if (file?.previewUrl) {\n return file.previewUrl\n }\n\n if (file?.url) {\n return file.url\n }\n\n if (file?.downloadUrl) {\n return file.downloadUrl\n }\n\n if (isBlobFile(file)) {\n const key = getObjectUrlKey(file)\n\n let cached = objectUrls.get(key)\n\n if (cached?.raw !== file.raw) {\n if (cached) URL.revokeObjectURL(cached.url)\n cached = { raw: file.raw, url: URL.createObjectURL(file.raw) }\n objectUrls.set(key, cached)\n }\n\n return cached.url\n }\n\n return \"\"\n }\n\n /**\n * 生成稳定标识,用于比较过滤前后的预览文件。\n *\n * @param {PreviewFile} file 文件元数据。\n * @returns {unknown} 稳定的文件标识。\n */\n const getFileKey = (file?: PreviewFile): unknown =>\n file?.uid ?? file?.raw ?? file?.url ?? file?.previewUrl ?? file?.downloadUrl ?? file\n\n // 保留原始文件索引,下载回调需要与 Upload fileList 的索引一致。\n const previewEntries = computed<PreviewEntry[]>(() => {\n const source: PreviewSource[] = props.files.length ? props.files : props.urlList\n\n return source\n .map((sourceFile, sourceIndex) => ({\n file: normalizeFile(sourceFile),\n sourceIndex,\n }))\n .filter((entry): entry is PreviewEntry => Boolean(entry.file))\n })\n\n const previewFiles = computed(() => previewEntries.value.map(({ file }) => file))\n\n /**\n * 将预览条目映射回输入列表索引,供下载回调使用。\n *\n * @param {PreviewFile} target 预览文件。\n * @returns {number} 输入列表索引;找不到时返回 -1。\n */\n const getSourceIndex = (target: PreviewFile): number => {\n const targetKey = getFileKey(target)\n\n return (\n previewEntries.value.find(\n ({ file }) => file === target || getFileKey(file) === targetKey\n )?.sourceIndex ?? -1\n )\n }\n\n const activeFile = computed(() => previewFiles.value[activeIndex.value])\n\n const activeFileIsImage = computed(() => isImageFile(activeFile.value))\n\n const activeFileCanRenderImage = computed(\n () => activeFileIsImage.value && hasPreviewSource(activeFile.value)\n )\n\n const viewerUrls = computed(() =>\n previewFiles.value.map((file) =>\n isImageFile(file) && hasPreviewSource(file) ? getFileUrl(file) : transparentImageUrl\n )\n )\n\n const isVisible = computed(() => props.modelValue || internalVisible.value)\n\n const previewVisible = computed(() => isVisible.value && Boolean(activeFile.value))\n\n /**\n * 将当前索引限制在可用预览文件范围内。\n *\n * @param {number} index 请求打开的文件索引。\n */\n const setActiveIndex = (index: number): void => {\n if (!previewFiles.value.length) {\n activeIndex.value = 0\n activeFileKey = undefined\n\n return\n }\n\n const safeIndex = Number.isFinite(index) ? Math.floor(index) : 0\n\n activeIndex.value = Math.min(Math.max(safeIndex, 0), previewFiles.value.length - 1)\n activeFileKey = getFileKey(previewFiles.value[activeIndex.value])\n }\n\n /**\n * 将数字索引或文件对象解析为预览列表索引。\n *\n * @param {number|PreviewFile|null|undefined} target 文件索引或文件标识。\n * @returns {number} 匹配的索引,不存在时返回 -1。\n */\n const resolveFileIndex = (target: number | PreviewFile | null | undefined): number => {\n if (typeof target === \"number\") {\n return previewEntries.value.findIndex((entry) => entry.sourceIndex === target)\n }\n\n if (!target) {\n return -1\n }\n\n const targetKey = getFileKey(target)\n\n return previewFiles.value.findIndex(\n (file) => file === target || getFileKey(file) === targetKey\n )\n }\n\n /**\n * 打开对应的预览界面,必要时等待自定义预览拦截器放行。\n *\n * @param {number|PreviewFile} target 文件索引或文件标识。\n */\n const openPreview = (target: number | PreviewFile): void => {\n const index = resolveFileIndex(target)\n\n const file = previewFiles.value[index]\n\n if (index < 0 || !file) {\n return\n }\n\n if (!props.previewFullImage && isImageFile(file) && hasPreviewSource(file)) {\n return\n }\n\n const requestId = ++previewRequestId\n\n const show = () => {\n if (requestId !== previewRequestId) return\n\n const currentIndex = resolveFileIndex(file)\n\n if (currentIndex < 0) {\n return\n }\n\n setActiveIndex(currentIndex)\n internalVisible.value = true\n emit(\"preview\", file)\n }\n\n if (typeof props.beforePreview !== \"function\") {\n show()\n\n return\n }\n\n let handled = false\n\n const done = () => {\n if (handled) {\n return\n }\n\n handled = true\n show()\n }\n\n try {\n const result = props.beforePreview(file, done)\n\n if (result && typeof result === \"object\" && typeof result.then === \"function\") {\n result\n .then((value) => {\n if (value !== false) {\n done()\n }\n })\n .catch(() => undefined)\n } else if (result !== undefined && result !== false) {\n done()\n }\n } catch {\n return\n }\n }\n\n // 关闭当前预览,并同步 v-model 状态。\n const handleClose = (): void => {\n previewRequestId += 1\n internalVisible.value = false\n emit(\"update:modelValue\", false)\n emit(\"close\")\n }\n\n /**\n * 同步 Element Plus 查看器当前文件索引。\n *\n * @param {number} index 完整预览文件列表中的索引。\n */\n const handleViewerSwitch = (index: number): void => {\n const currentFile = previewFiles.value[index]\n\n if (!currentFile) return\n\n setActiveIndex(index)\n emit(\"switch\", activeIndex.value)\n }\n\n /**\n * 将图片查看器错误转发给父组件。\n *\n * @param {Event} event 查看器错误事件。\n */\n const handleError = (event: Event): void => {\n emit(\"error\", event)\n }\n\n /**\n * 将图片旋转事件转发给父组件。\n *\n * @param {number} degree 查看器报告的旋转角度。\n */\n const handleRotate = (degree: number): void => {\n emit(\"rotate\", degree)\n }\n\n /**\n * 根据解析后的 URL 触发浏览器下载。\n *\n * @param {string} url 解析后的文件 URL。\n * @param {string} name 下载时使用的文件名。\n */\n const triggerDownload = (url: string, name: string): void => {\n const link = document.createElement(\"a\")\n\n link.href = url\n link.download = name\n link.target = \"_blank\"\n link.rel = \"noopener noreferrer\"\n document.body.appendChild(link)\n link.click()\n link.remove()\n }\n\n /**\n * 优先使用自定义处理器下载,否则通过带认证的 fetch 兜底下载。\n *\n * @param {number|PreviewFile} target 文件索引或文件标识。\n * @param {number} [sourceIndex] 输入文件列表索引。\n * @returns {Promise<void>} 下载触发后结束。\n */\n const handleDownload = async (\n target: number | PreviewFile,\n sourceIndex?: number\n ): Promise<void> => {\n const previewIndex = resolveFileIndex(target)\n\n const file = previewFiles.value[previewIndex]\n\n const url = file?.downloadUrl || getFileUrl(file)\n\n if (!file || !url) {\n return\n }\n\n const resolvedSourceIndex = getSourceIndex(file)\n\n const index =\n typeof sourceIndex === \"number\" && Number.isInteger(sourceIndex) && sourceIndex >= 0\n ? sourceIndex\n : resolvedSourceIndex >= 0\n ? resolvedSourceIndex\n : previewIndex\n\n emit(\"download\", file, index)\n\n if (props.downloadHandler) {\n try {\n await props.downloadHandler(file, index)\n } catch (error) {\n const downloadError = error instanceof Error ? error : new Error(\"文件下载失败\")\n\n emit(\"download-error\", downloadError, file)\n }\n\n return\n }\n\n if (/^(?:blob:|data:)/i.test(url)) {\n triggerDownload(url, file.name || getFileName(url))\n\n return\n }\n\n try {\n const response = await fetch(url, { credentials: \"include\" })\n\n if (!response.ok) {\n throw new Error(`文件下载失败:${response.status}`)\n }\n\n const blobUrl = URL.createObjectURL(await response.blob())\n\n triggerDownload(blobUrl, file.name || getFileName(url))\n window.setTimeout(() => URL.revokeObjectURL(blobUrl), 1000)\n } catch {\n triggerDownload(url, file.name || getFileName(url))\n }\n }\n\n /**\n * 下载查看器当前选中的文件。\n *\n * @param {number} viewerIndex 查看器列表中的索引。\n * @returns {Promise<void>|undefined} 文件存在且可下载时返回下载 Promise。\n */\n const handleViewerDownload = (viewerIndex: number): Promise<void> | undefined => {\n const file = previewFiles.value[viewerIndex]\n\n if (file && hasPreviewSource(file)) {\n return handleDownload(file)\n }\n }\n\n /**\n * 为自定义工具栏图标补充键盘操作,同时保持点击行为不变。\n *\n * @param {KeyboardEvent} event 键盘事件。\n * @param {() => void} action 待执行的工具栏操作。\n */\n const handleToolbarKeydown = (event: KeyboardEvent, action: () => void): void => {\n if (event.key !== \"Enter\" && event.key !== \" \") {\n return\n }\n\n event.preventDefault()\n action()\n }\n\n // 外部控制显隐时使用 initialIndex;命令式打开则保留当前选中的文件。\n watch(\n () => props.modelValue,\n (value) => {\n if (!value) {\n previewRequestId += 1\n internalVisible.value = false\n\n return\n }\n\n if (!previewFiles.value.length) {\n emit(\"update:modelValue\", false)\n\n return\n }\n\n setActiveIndex(resolveFileIndex(props.initialIndex))\n },\n { immediate: true }\n )\n\n watch(\n () => props.initialIndex,\n (index) => {\n if (props.modelValue) setActiveIndex(resolveFileIndex(index))\n }\n )\n\n watch(\n activeIndex,\n (index) => {\n imageViewerRef.value?.setActiveItem(index)\n },\n { flush: \"post\" }\n )\n\n watch(previewFiles, (files) => {\n const availableObjectUrls = new Map(\n files\n .filter(\n (file) => isBlobFile(file) && !file.previewUrl && !file.url && !file.downloadUrl\n )\n .map((file) => [getObjectUrlKey(file), file.raw])\n )\n\n for (const [key, cached] of objectUrls) {\n if (availableObjectUrls.get(key) !== cached.raw) {\n URL.revokeObjectURL(cached.url)\n objectUrls.delete(key)\n }\n }\n\n if (!isVisible.value) return\n if (!files.length) {\n handleClose()\n\n return\n }\n\n const currentIndex = files.findIndex((file) => getFileKey(file) === activeFileKey)\n\n if (currentIndex >= 0) {\n activeIndex.value = currentIndex\n } else {\n setActiveIndex(activeIndex.value)\n }\n })\n\n // 释放当前组件创建的所有 Blob URL,避免浏览器资源持续占用。\n onBeforeUnmount(() => {\n objectUrls.forEach(({ url }) => URL.revokeObjectURL(url))\n objectUrls.clear()\n })\n\n // FileDisplay 只通过这些方法控制预览,无需了解内部实现。\n defineExpose({\n open: openPreview,\n close: handleClose,\n download: handleDownload,\n })\n</script>\n\n<template>\n <!-- 图片使用内置画布,其他文件通过查看器默认插槽显示提示。 -->\n <ElImageViewer\n v-if=\"previewVisible\"\n ref=\"imageViewerRef\"\n class=\"upload-renderer-viewer\"\n :url-list=\"viewerUrls\"\n :initial-index=\"activeIndex\"\n :infinite=\"infinite\"\n :hide-on-click-modal=\"hideOnClickModal\"\n :teleported=\"teleported\"\n :close-on-press-escape=\"closeOnPressEscape\"\n :show-progress=\"showProgress\"\n :zoom-rate=\"zoomRate\"\n :min-scale=\"minScale\"\n :max-scale=\"maxScale\"\n :crossorigin=\"crossorigin\"\n @close=\"handleClose\"\n @switch=\"handleViewerSwitch\"\n @error=\"handleError\"\n @rotate=\"handleRotate\"\n >\n <template #toolbar=\"toolbar\">\n <slot name=\"toolbar\" v-bind=\"toolbar\">\n <template v-if=\"previewFiles.length > 1\">\n <ElIcon\n class=\"file-preview__action\"\n title=\"上一张\"\n aria-label=\"上一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.prev\"\n @keydown=\"handleToolbarKeydown($event, toolbar.prev)\"\n >\n <Back />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"下一张\"\n aria-label=\"下一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.next\"\n @keydown=\"handleToolbarKeydown($event, toolbar.next)\"\n >\n <Right />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"第一张\"\n aria-label=\"第一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.setActiveItem(0)\"\n @keydown=\"handleToolbarKeydown($event, () => toolbar.setActiveItem(0))\"\n >\n <DArrowLeft />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"最后一张\"\n aria-label=\"最后一张\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.setActiveItem(previewFiles.length - 1)\"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.setActiveItem(previewFiles.length - 1)\n )\n \"\n >\n <DArrowRight />\n </ElIcon>\n </template>\n <template v-if=\"activeFileCanRenderImage\">\n <ElIcon\n class=\"file-preview__action\"\n title=\"缩小\"\n aria-label=\"缩小\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.actions('zoomOut')\"\n @keydown=\"handleToolbarKeydown($event, () => toolbar.actions('zoomOut'))\"\n >\n <ZoomOut />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"放大\"\n aria-label=\"放大\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"toolbar.actions('zoomIn', { enableTransition: false, zoomRate })\"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.actions('zoomIn', { enableTransition: false, zoomRate })\n )\n \"\n >\n <ZoomIn />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"顺时针旋转\"\n aria-label=\"顺时针旋转\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"\n toolbar.actions('clockwise', { rotateDeg: 180, enableTransition: false })\n \"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.actions('clockwise', { rotateDeg: 180, enableTransition: false })\n )\n \"\n >\n <RefreshRight />\n </ElIcon>\n <ElIcon\n class=\"file-preview__action\"\n title=\"逆时针旋转\"\n aria-label=\"逆时针旋转\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"\n toolbar.actions('anticlockwise', {\n rotateDeg: 180,\n enableTransition: false,\n })\n \"\n @keydown=\"\n handleToolbarKeydown($event, () =>\n toolbar.actions('anticlockwise', {\n rotateDeg: 180,\n enableTransition: false,\n })\n )\n \"\n >\n <RefreshLeft />\n </ElIcon>\n </template>\n <ElIcon\n v-if=\"activeFileCanRenderImage\"\n class=\"file-preview__action\"\n title=\"下载\"\n aria-label=\"下载\"\n role=\"button\"\n tabindex=\"0\"\n @click=\"handleViewerDownload(toolbar.activeIndex)\"\n @keydown=\"\n handleToolbarKeydown($event, () => handleViewerDownload(toolbar.activeIndex))\n \"\n >\n <Download />\n </ElIcon>\n </slot>\n </template>\n\n <div v-if=\"!activeFileCanRenderImage\" class=\"file-preview__content\">\n <slot\n name=\"viewer\"\n :file=\"activeFile\"\n :download=\"() => handleDownload(activeFile)\"\n :close=\"handleClose\"\n >\n <div class=\"file-preview__unsupported\">\n <el-icon class=\"file-preview__unsupported-icon\"><Document /></el-icon>\n <p>\n {{\n hasPreviewSource(activeFile)\n ? \"该文件不支持预览,请下载后查看。\"\n : \"该文件暂无可预览内容。\"\n }}\n </p>\n <ElButton\n v-if=\"hasPreviewSource(activeFile)\"\n type=\"primary\"\n link\n @click=\"handleDownload(activeFile)\"\n >\n 下载文件\n </ElButton>\n </div>\n </slot>\n </div>\n </ElImageViewer>\n</template>\n\n<style lang=\"scss\">\n .file-preview {\n &__action {\n cursor: pointer;\n outline: none;\n\n &:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n border-radius: 2px;\n }\n }\n\n &__content {\n position: absolute;\n inset: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n\n > * {\n pointer-events: auto;\n }\n }\n\n &__unsupported {\n display: flex;\n align-items: center;\n flex-direction: column;\n gap: 24px;\n color: var(--el-fill-color-light);\n\n &-icon {\n flex-shrink: 0;\n font-size: 48px;\n }\n\n p {\n margin: 0;\n font-size: 15px;\n }\n }\n }\n\n .el-image-viewer__mask {\n backdrop-filter: blur(2px);\n opacity: 1;\n background-color: rgb(0 0 0 / 35%);\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-upload-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n <div v-if=\"fileList.length\" class=\"schemx-upload-renderer__readonly-list\">\n <ElImage\n v-for=\"(file, index) in imageFiles\"\n :key=\"file.uid ?? file.name\"\n :src=\"file.url\"\n :preview-src-list=\"imageUrls\"\n :initial-index=\"index\"\n :preview-teleported=\"true\"\n fit=\"cover\"\n />\n <span\n v-for=\"file in nonImageFiles\"\n :key=\"file.uid ?? file.name\"\n class=\"schemx-upload-renderer__readonly-file\"\n >\n {{ file.name }}\n </span>\n </div>\n <span v-else>{{ props.readonlyPlaceholder }}</span>\n </template>\n <ElUpload\n ref=\"uploadRef\"\n v-bind=\"uploadProps\"\n v-model:file-list=\"fileList\"\n @change=\"handleChange\"\n @remove=\"handleRemove\"\n @preview=\"handlePreview\"\n @success=\"handleSuccess\"\n @error=\"handleError\"\n >\n <template v-if=\"props.showUpload !== false\">\n <slot>\n <ElIcon v-if=\"props.listType === 'picture-card'\"><Plus /></ElIcon>\n <ElButton v-else type=\"primary\">选择文件</ElButton>\n </slot>\n </template>\n <template #file=\"{ file, index }\">\n <FileDisplay\n :file=\"file\"\n :index=\"index\"\n :list-type=\"props.listType\"\n :file-type=\"props.fileType\"\n :crossorigin=\"props.crossorigin\"\n :disabled=\"props.disabled || props.disableUpload\"\n @preview=\"handlePreview\"\n @download=\"handleDownload\"\n @remove=\"handleDisplayRemove\"\n />\n </template>\n </ElUpload>\n </Wrapper>\n\n <FilePreview\n ref=\"previewRef\"\n :files=\"fileList\"\n :file-type=\"props.fileType\"\n :preview-full-image=\"props.previewFullImage\"\n :crossorigin=\"props.crossorigin\"\n :before-preview=\"props.beforePreview\"\n :download-handler=\"props.downloadHandler\"\n >\n <template v-if=\"$slots.viewer\" #viewer=\"viewerProps\">\n <slot name=\"viewer\" v-bind=\"viewerProps\" />\n </template>\n </FilePreview>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElUpload 管理文件选择、上传和预览。 */\n import { computed, ref, useAttrs, watch } from \"vue\"\n\n import { Plus } from \"@element-plus/icons-vue\"\n import { useFieldContext, Wrapper } from \"@schemx/vue\"\n import { ElButton, ElIcon, ElImage, ElMessage, ElUpload } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n\n import FileDisplay from \"./file-display.vue\"\n import FilePreview from \"./preview.vue\"\n\n import type { UploadRendererProps, UploadValue } from \"./types\"\n import type {\n UploadFile as ElementUploadFile,\n UploadFiles,\n UploadInstance,\n UploadProps,\n UploadRawFile,\n UploadRequestHandler,\n UploadUserFile,\n } from \"element-plus\"\n\n defineOptions({\n name: \"UploadRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<UploadRendererProps>(), {\n value: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n showUpload: true,\n disableUpload: false,\n previewFullImage: true,\n listType: \"picture-card\",\n multiple: true,\n showFileList: true,\n propsHttp: () => ({\n data: \"data\",\n url: \"url\",\n name: \"name\",\n }),\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<UploadValue>(\"value\")\n\n const fileList = ref<UploadUserFile[]>(normalizeFiles(props.value))\n\n const previewRef = ref<{\n open: (file: ElementUploadFile) => void\n download: (file: ElementUploadFile, index?: number) => Promise<void>\n }>()\n\n const uploadRef = ref<UploadInstance>()\n\n const field = resolveFieldContext()\n\n watch(\n () => props.value,\n (value) => {\n fileList.value = normalizeFiles(value)\n },\n { deep: true }\n )\n\n const imageFiles = computed(() =>\n fileList.value.filter((file) => Boolean(file.url && isImageFile(file)))\n )\n\n const nonImageFiles = computed(() =>\n fileList.value.filter((file) => !file.url || !isImageFile(file))\n )\n\n const imageUrls = computed(() =>\n imageFiles.value.map((file) => file.url).filter((url): url is string => Boolean(url))\n )\n\n /** 将 accept 字符串拆分为可逐项比对的文件类型规则。 */\n const acceptRules = computed(() =>\n String(props.accept ?? attrs.accept ?? \"\")\n .split(\",\")\n .map((rule) => rule.trim())\n .filter(Boolean)\n )\n\n /** 判断文件是否符合扩展名、精确 MIME 或 MIME 通配规则。 */\n const isAcceptedFile = (file: File): boolean => {\n if (!acceptRules.value.length) return true\n\n const fileName = file.name.toLowerCase()\n\n const mimeType = file.type.toLowerCase()\n\n return acceptRules.value.some((rule) => {\n const normalizedRule = rule.toLowerCase()\n\n if (normalizedRule === \"*\" || normalizedRule === \"*/*\") return true\n if (normalizedRule.startsWith(\".\")) return fileName.endsWith(normalizedRule)\n\n if (normalizedRule.endsWith(\"/*\")) {\n return mimeType.startsWith(normalizedRule.slice(0, -1))\n }\n\n if (normalizedRule.includes(\"/\")) return mimeType === normalizedRule\n\n return fileName.endsWith(`.${normalizedRule}`)\n })\n }\n\n /** 提示文件类型不符合 accept 配置。 */\n const showInvalidTypeWarning = (fileName: string): void => {\n ElMessage.warning(\n `${fileName} 类型不符合要求,仅支持:${acceptRules.value.join(\"、\")}`\n )\n }\n\n /** 强制校验文件类型,通过后再执行调用方的 beforeUpload。 */\n const handleBeforeUpload: NonNullable<UploadProps[\"beforeUpload\"]> = (\n rawFile: UploadRawFile\n ) => {\n if (!isAcceptedFile(rawFile)) {\n showInvalidTypeWarning(rawFile.name)\n\n return false\n }\n\n const configuredBeforeUpload = props.beforeUpload ?? attrs.beforeUpload\n\n if (typeof configuredBeforeUpload !== \"function\") return true\n\n const beforeUpload = configuredBeforeUpload as NonNullable<\n UploadProps[\"beforeUpload\"]\n >\n\n return beforeUpload(rawFile)\n }\n\n const uploadProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"value\",\n \"showUpload\",\n \"disableUpload\",\n \"previewFullImage\",\n \"fileType\",\n \"beforePreview\",\n \"downloadHandler\",\n \"propsHttp\",\n \"uploader\",\n \"fileList\",\n \"onChange\",\n \"onRemove\",\n \"onPreview\",\n \"onSuccess\",\n \"onError\",\n \"beforeUpload\",\n ]),\n disabled: props.disabled || props.disableUpload,\n beforeUpload: handleBeforeUpload,\n httpRequest: httpRequest.value,\n }))\n\n const httpRequest = computed<UploadRequestHandler | undefined>(() => {\n if (!props.uploader) return undefined\n\n return async (options) => {\n field?.setPending(true)\n\n try {\n const response = await props.uploader?.(options.file)\n\n options.onSuccess(response)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n const uploadError = new Error(message) as Parameters<typeof options.onError>[0]\n\n options.onError(uploadError)\n } finally {\n field?.setPending(false)\n }\n }\n })\n\n /**\n * 规范化外部文件列表。\n *\n * @param files - 外部传入的 Element Plus 文件列表。\n * @returns 可直接绑定到 ElUpload 的文件列表。\n */\n function normalizeFiles(files: UploadValue | undefined): UploadUserFile[] {\n return (files ?? []).map((file, index) => ({\n ...file,\n name: file.name || `file-${index + 1}`,\n uid: file.uid ?? index + 1,\n status: file.status ?? \"success\",\n }))\n }\n\n /**\n * 根据文件名或 MIME 类型判断是否为图片。\n *\n * @param file - Element Plus 文件项。\n * @returns 是否按图片展示。\n */\n function isImageFile(file: UploadUserFile): boolean {\n const rawFile = file.raw\n\n if (rawFile?.type) return rawFile.type.startsWith(\"image/\")\n\n return /\\.(avif|bmp|gif|jpe?g|png|svg|webp)$/i.test(file.name)\n }\n\n /**\n * 将 Element Plus 文件列表同步到 Schemx 字段。\n *\n * @param files - Element Plus 当前文件列表。\n */\n const syncFiles = (files: UploadFiles): void => {\n const nextFiles = files.map((file) => ({\n name: file.name,\n uid: file.uid,\n status: file.status,\n percentage: file.percentage,\n size: file.size,\n response: file.response,\n url: file.url,\n raw: file.raw,\n }))\n\n fileList.value = nextFiles\n valueModel.value = nextFiles\n props.onChange?.(nextFiles)\n }\n\n /**\n * 处理文件列表变化。\n *\n * @param _file - 本次发生变化的文件。\n * @param files - Element Plus 当前文件列表。\n */\n const handleChange: NonNullable<UploadProps[\"onChange\"]> = (\n _file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n syncFiles(files)\n }\n\n /**\n * 处理文件删除。\n *\n * @param file - 被删除的文件。\n * @param files - 删除后的文件列表。\n */\n const handleRemove: NonNullable<UploadProps[\"onRemove\"]> = (\n file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n syncFiles(files)\n props.onRemove?.(file, files)\n }\n\n const handleDisplayRemove = (file: ElementUploadFile): void => {\n uploadRef.value?.handleRemove(file)\n }\n\n const handleDownload = (file: ElementUploadFile, index: number): void => {\n void previewRef.value?.download(file, index)\n }\n\n /**\n * 处理文件预览。\n *\n * @param file - 被预览的文件。\n */\n const handlePreview: NonNullable<UploadProps[\"onPreview\"]> = (\n file: ElementUploadFile\n ): void => {\n previewRef.value?.open(file)\n props.onPreview?.(file)\n }\n\n /**\n * 处理上传成功并补充服务端文件信息。\n *\n * @param response - 服务端响应。\n * @param file - 上传完成的文件。\n * @param files - Element Plus 当前文件列表。\n */\n const handleSuccess: NonNullable<UploadProps[\"onSuccess\"]> = (\n response: unknown,\n file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n const responseData = getResponseValue(response, props.propsHttp?.data)\n\n const responseUrl = getResponseValue(responseData, props.propsHttp?.url)\n\n const responseName = getResponseValue(responseData, props.propsHttp?.name)\n\n if (typeof responseUrl === \"string\") file.url = responseUrl\n if (typeof responseName === \"string\") file.name = responseName\n\n syncFiles(files)\n props.onSuccess?.(response, file, files)\n }\n\n /**\n * 处理上传失败。\n *\n * @param error - Element Plus 上传错误。\n * @param file - 上传失败的文件。\n * @param files - Element Plus 当前文件列表。\n */\n const handleError: NonNullable<UploadProps[\"onError\"]> = (\n error: Error,\n file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n syncFiles(files)\n props.onError?.(error, file, files)\n }\n\n /**\n * 读取响应对象的指定字段。\n *\n * @param value - 待读取的响应值。\n * @param path - 点号分隔的字段路径。\n * @returns 字段值;路径不存在时返回 undefined。\n */\n function getResponseValue(value: unknown, path: string | undefined): unknown {\n if (!path) return value\n\n return path.split(\".\").reduce<unknown>((current, key) => {\n if (!current || typeof current !== \"object\") return undefined\n\n return (current as Record<string, unknown>)[key]\n }, value)\n }\n\n /** 尝试获取字段上下文,允许 Upload 作为独立组件测试。 */\n function resolveFieldContext() {\n try {\n return useFieldContext()\n } catch {\n return null\n }\n }\n</script>\n\n<style lang=\"scss\">\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n\n .el-upload-list,\n .el-upload {\n --el-upload-list-picture-card-size: 125px;\n --el-upload-picture-card-size: 125px;\n }\n }\n\n .schemx-upload-renderer__readonly-list {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n }\n\n .schemx-upload-renderer__readonly-list .el-image {\n width: 80px;\n height: 80px;\n }\n\n .schemx-upload-renderer__readonly-file {\n color: var(--el-text-color-regular);\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-upload-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n <div v-if=\"fileList.length\" class=\"schemx-upload-renderer__readonly-list\">\n <ElImage\n v-for=\"(file, index) in imageFiles\"\n :key=\"file.uid ?? file.name\"\n :src=\"file.url\"\n :preview-src-list=\"imageUrls\"\n :initial-index=\"index\"\n :preview-teleported=\"true\"\n fit=\"cover\"\n />\n <span\n v-for=\"file in nonImageFiles\"\n :key=\"file.uid ?? file.name\"\n class=\"schemx-upload-renderer__readonly-file\"\n >\n {{ file.name }}\n </span>\n </div>\n <span v-else>{{ props.readonlyPlaceholder }}</span>\n </template>\n <ElUpload\n ref=\"uploadRef\"\n v-bind=\"uploadProps\"\n v-model:file-list=\"fileList\"\n @change=\"handleChange\"\n @remove=\"handleRemove\"\n @preview=\"handlePreview\"\n @success=\"handleSuccess\"\n @error=\"handleError\"\n >\n <template v-if=\"props.showUpload !== false\">\n <slot>\n <ElIcon v-if=\"props.listType === 'picture-card'\"><Plus /></ElIcon>\n <ElButton v-else type=\"primary\">选择文件</ElButton>\n </slot>\n </template>\n <template #file=\"{ file, index }\">\n <FileDisplay\n :file=\"file\"\n :index=\"index\"\n :list-type=\"props.listType\"\n :file-type=\"props.fileType\"\n :crossorigin=\"props.crossorigin\"\n :disabled=\"props.disabled || props.disableUpload\"\n @preview=\"handlePreview\"\n @download=\"handleDownload\"\n @remove=\"handleDisplayRemove\"\n />\n </template>\n </ElUpload>\n </Wrapper>\n\n <FilePreview\n ref=\"previewRef\"\n :files=\"fileList\"\n :file-type=\"props.fileType\"\n :preview-full-image=\"props.previewFullImage\"\n :crossorigin=\"props.crossorigin\"\n :before-preview=\"props.beforePreview\"\n :download-handler=\"props.downloadHandler\"\n >\n <template v-if=\"$slots.viewer\" #viewer=\"viewerProps\">\n <slot name=\"viewer\" v-bind=\"viewerProps\" />\n </template>\n </FilePreview>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElUpload 管理文件选择、上传和预览。 */\n import { computed, ref, useAttrs, watch } from \"vue\"\n\n import { Plus } from \"@element-plus/icons-vue\"\n import { useFieldContext, Wrapper } from \"@schemx/vue\"\n import { ElButton, ElIcon, ElImage, ElMessage, ElUpload } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n\n import FileDisplay from \"./file-display.vue\"\n import FilePreview from \"./preview.vue\"\n\n import type { UploadRendererProps, UploadValue } from \"./types\"\n import type {\n UploadFile as ElementUploadFile,\n UploadFiles,\n UploadInstance,\n UploadProps,\n UploadRawFile,\n UploadRequestHandler,\n UploadUserFile,\n } from \"element-plus\"\n\n defineOptions({\n name: \"UploadRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<UploadRendererProps>(), {\n value: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n showUpload: true,\n disableUpload: false,\n previewFullImage: true,\n listType: \"picture-card\",\n multiple: true,\n showFileList: true,\n propsHttp: () => ({\n data: \"data\",\n url: \"url\",\n name: \"name\",\n }),\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<UploadValue>(\"value\")\n\n const fileList = ref<UploadUserFile[]>(normalizeFiles(props.value))\n\n const previewRef = ref<{\n open: (file: ElementUploadFile) => void\n download: (file: ElementUploadFile, index?: number) => Promise<void>\n }>()\n\n const uploadRef = ref<UploadInstance>()\n\n const field = resolveFieldContext()\n\n watch(\n () => props.value,\n (value) => {\n fileList.value = normalizeFiles(value)\n },\n { deep: true }\n )\n\n const imageFiles = computed(() =>\n fileList.value.filter((file) => Boolean(file.url && isImageFile(file)))\n )\n\n const nonImageFiles = computed(() =>\n fileList.value.filter((file) => !file.url || !isImageFile(file))\n )\n\n const imageUrls = computed(() =>\n imageFiles.value.map((file) => file.url).filter((url): url is string => Boolean(url))\n )\n\n /** 将 accept 字符串拆分为可逐项比对的文件类型规则。 */\n const acceptRules = computed(() =>\n String(props.accept ?? attrs.accept ?? \"\")\n .split(\",\")\n .map((rule) => rule.trim())\n .filter(Boolean)\n )\n\n /** 判断文件是否符合扩展名、精确 MIME 或 MIME 通配规则。 */\n const isAcceptedFile = (file: File): boolean => {\n if (!acceptRules.value.length) return true\n\n const fileName = file.name.toLowerCase()\n\n const mimeType = file.type.toLowerCase()\n\n return acceptRules.value.some((rule) => {\n const normalizedRule = rule.toLowerCase()\n\n if (normalizedRule === \"*\" || normalizedRule === \"*/*\") return true\n if (normalizedRule.startsWith(\".\")) return fileName.endsWith(normalizedRule)\n\n if (normalizedRule.endsWith(\"/*\")) {\n return mimeType.startsWith(normalizedRule.slice(0, -1))\n }\n\n if (normalizedRule.includes(\"/\")) return mimeType === normalizedRule\n\n return fileName.endsWith(`.${normalizedRule}`)\n })\n }\n\n /** 提示文件类型不符合 accept 配置。 */\n const showInvalidTypeWarning = (fileName: string): void => {\n ElMessage.warning(\n `${fileName} 类型不符合要求,仅支持:${acceptRules.value.join(\"、\")}`\n )\n }\n\n /** 强制校验文件类型,通过后再执行调用方的 beforeUpload。 */\n const handleBeforeUpload: NonNullable<UploadProps[\"beforeUpload\"]> = (\n rawFile: UploadRawFile\n ) => {\n if (!isAcceptedFile(rawFile)) {\n showInvalidTypeWarning(rawFile.name)\n\n return false\n }\n\n const configuredBeforeUpload = props.beforeUpload ?? attrs.beforeUpload\n\n if (typeof configuredBeforeUpload !== \"function\") return true\n\n const beforeUpload = configuredBeforeUpload as NonNullable<\n UploadProps[\"beforeUpload\"]\n >\n\n return beforeUpload(rawFile)\n }\n\n const uploadProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"value\",\n \"showUpload\",\n \"disableUpload\",\n \"previewFullImage\",\n \"fileType\",\n \"beforePreview\",\n \"downloadHandler\",\n \"propsHttp\",\n \"uploader\",\n \"fileList\",\n \"onChange\",\n \"onRemove\",\n \"onPreview\",\n \"onSuccess\",\n \"onError\",\n \"beforeUpload\",\n ]),\n disabled: props.disabled || props.disableUpload,\n beforeUpload: handleBeforeUpload,\n httpRequest: httpRequest.value,\n }))\n\n const httpRequest = computed<UploadRequestHandler | undefined>(() => {\n if (!props.uploader) return undefined\n\n return async (options) => {\n field?.setPending(true)\n\n try {\n const response = await props.uploader?.(options.file)\n\n options.onSuccess(response)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n const uploadError = new Error(message) as Parameters<typeof options.onError>[0]\n\n options.onError(uploadError)\n } finally {\n field?.setPending(false)\n }\n }\n })\n\n /**\n * 规范化外部文件列表。\n *\n * @param files - 外部传入的 Element Plus 文件列表。\n * @returns 可直接绑定到 ElUpload 的文件列表。\n */\n function normalizeFiles(files: UploadValue | undefined): UploadUserFile[] {\n return (files ?? []).map((file, index) => ({\n ...file,\n name: file.name || `file-${index + 1}`,\n uid: file.uid ?? index + 1,\n status: file.status ?? \"success\",\n }))\n }\n\n /**\n * 根据文件名或 MIME 类型判断是否为图片。\n *\n * @param file - Element Plus 文件项。\n * @returns 是否按图片展示。\n */\n function isImageFile(file: UploadUserFile): boolean {\n const rawFile = file.raw\n\n if (rawFile?.type) return rawFile.type.startsWith(\"image/\")\n\n return /\\.(avif|bmp|gif|jpe?g|png|svg|webp)$/i.test(file.name)\n }\n\n /**\n * 将 Element Plus 文件列表同步到 Schemx 字段。\n *\n * @param files - Element Plus 当前文件列表。\n */\n const syncFiles = (files: UploadFiles): void => {\n const nextFiles = files.map((file) => ({\n name: file.name,\n uid: file.uid,\n status: file.status,\n percentage: file.percentage,\n size: file.size,\n response: file.response,\n url: file.url,\n raw: file.raw,\n }))\n\n fileList.value = nextFiles\n valueModel.value = nextFiles\n props.onChange?.(nextFiles)\n }\n\n /**\n * 处理文件列表变化。\n *\n * @param _file - 本次发生变化的文件。\n * @param files - Element Plus 当前文件列表。\n */\n const handleChange: NonNullable<UploadProps[\"onChange\"]> = (\n _file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n syncFiles(files)\n }\n\n /**\n * 处理文件删除。\n *\n * @param file - 被删除的文件。\n * @param files - 删除后的文件列表。\n */\n const handleRemove: NonNullable<UploadProps[\"onRemove\"]> = (\n file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n syncFiles(files)\n props.onRemove?.(file, files)\n }\n\n const handleDisplayRemove = (file: ElementUploadFile): void => {\n uploadRef.value?.handleRemove(file)\n }\n\n const handleDownload = (file: ElementUploadFile, index: number): void => {\n void previewRef.value?.download(file, index)\n }\n\n /**\n * 处理文件预览。\n *\n * @param file - 被预览的文件。\n */\n const handlePreview: NonNullable<UploadProps[\"onPreview\"]> = (\n file: ElementUploadFile\n ): void => {\n previewRef.value?.open(file)\n props.onPreview?.(file)\n }\n\n /**\n * 处理上传成功并补充服务端文件信息。\n *\n * @param response - 服务端响应。\n * @param file - 上传完成的文件。\n * @param files - Element Plus 当前文件列表。\n */\n const handleSuccess: NonNullable<UploadProps[\"onSuccess\"]> = (\n response: unknown,\n file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n const responseData = getResponseValue(response, props.propsHttp?.data)\n\n const responseUrl = getResponseValue(responseData, props.propsHttp?.url)\n\n const responseName = getResponseValue(responseData, props.propsHttp?.name)\n\n if (typeof responseUrl === \"string\") file.url = responseUrl\n if (typeof responseName === \"string\") file.name = responseName\n\n syncFiles(files)\n props.onSuccess?.(response, file, files)\n }\n\n /**\n * 处理上传失败。\n *\n * @param error - Element Plus 上传错误。\n * @param file - 上传失败的文件。\n * @param files - Element Plus 当前文件列表。\n */\n const handleError: NonNullable<UploadProps[\"onError\"]> = (\n error: Error,\n file: ElementUploadFile,\n files: UploadFiles\n ): void => {\n syncFiles(files)\n props.onError?.(error, file, files)\n }\n\n /**\n * 读取响应对象的指定字段。\n *\n * @param value - 待读取的响应值。\n * @param path - 点号分隔的字段路径。\n * @returns 字段值;路径不存在时返回 undefined。\n */\n function getResponseValue(value: unknown, path: string | undefined): unknown {\n if (!path) return value\n\n return path.split(\".\").reduce<unknown>((current, key) => {\n if (!current || typeof current !== \"object\") return undefined\n\n return (current as Record<string, unknown>)[key]\n }, value)\n }\n\n /** 尝试获取字段上下文,允许 Upload 作为独立组件测试。 */\n function resolveFieldContext() {\n try {\n return useFieldContext()\n } catch {\n return null\n }\n }\n</script>\n\n<style lang=\"scss\">\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n\n .el-upload-list,\n .el-upload {\n --el-upload-list-picture-card-size: 125px;\n --el-upload-picture-card-size: 125px;\n }\n }\n\n .schemx-upload-renderer__readonly-list {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n }\n\n .schemx-upload-renderer__readonly-list .el-image {\n width: 80px;\n height: 80px;\n }\n\n .schemx-upload-renderer__readonly-file {\n color: var(--el-text-color-regular);\n }\n</style>\n","/** Element Plus 选项标准化与只读展示工具。 */\n\ntype ElementOptionValue = string | number | boolean\n\ninterface ElementFieldNames {\n label?: string\n value?: string\n disabled?: string\n children?: string\n}\n\ninterface ElementOption {\n label?: string\n value?: ElementOptionValue\n disabled?: boolean\n [key: string]: unknown\n}\n\n/**\n * 将 Schemx 选项映射为 Element Plus 默认的 label/value/disabled 结构。\n *\n * @param options - 待映射的选项列表。\n * @param fieldNames - 选项字段名映射。\n * @returns 可传给 Element Plus 的规范化选项列表。\n */\nexport function normalizeElementOptions(\n options: readonly ElementOption[] | undefined,\n fieldNames: ElementFieldNames = {}\n): ElementOption[] {\n const labelKey = fieldNames.label ?? \"label\"\n\n const valueKey = fieldNames.value ?? \"value\"\n\n const disabledKey = fieldNames.disabled ?? \"disabled\"\n\n return (options ?? []).map((option) => ({\n ...option,\n label: String(option[labelKey] ?? option[valueKey] ?? \"\"),\n value: option[valueKey] as ElementOptionValue | undefined,\n disabled: Boolean(option[disabledKey]),\n }))\n}\n\n/**\n * 根据字段映射读取选项值。\n *\n * @param option - 当前选项。\n * @param fieldNames - 选项字段名映射。\n * @returns 选项的基础值。\n */\nexport function getElementOptionValue(\n option: ElementOption,\n fieldNames: ElementFieldNames = {}\n): ElementOptionValue | undefined {\n return option[fieldNames.value ?? \"value\"] as ElementOptionValue | undefined\n}\n\n/**\n * 根据字段映射读取选项标签。\n *\n * @param option - 当前选项。\n * @param fieldNames - 选项字段名映射。\n * @returns 选项的显示文本。\n */\nexport function getElementOptionLabel(\n option: ElementOption,\n fieldNames: ElementFieldNames = {}\n): string {\n const label = option[fieldNames.label ?? \"label\"]\n\n const value = getElementOptionValue(option, fieldNames)\n\n return String(label ?? value ?? \"\")\n}\n\n/**\n * 将一个或多个选项值转换为只读展示文本。\n *\n * @param value - 当前字段值。\n * @param options - 可用于反查标签的选项列表。\n * @param fieldNames - 选项字段名映射。\n * @param separator - 多选值之间的分隔符。\n * @returns 选项标签拼接后的文本。\n */\nexport function getElementOptionDisplayValue(\n value: ElementOptionValue | ElementOptionValue[] | null | undefined,\n options: readonly ElementOption[],\n fieldNames: ElementFieldNames = {},\n separator = \"、\"\n): string {\n const values = Array.isArray(value) ? value : [value]\n\n return values\n .filter((item): item is ElementOptionValue => item !== null && item !== undefined)\n .map((item) => {\n const option = options.find(\n (candidate) => getElementOptionValue(candidate, fieldNames) === item\n )\n\n return option ? getElementOptionLabel(option, fieldNames) : String(item)\n })\n .join(separator)\n}\n\n/**\n * 判断值是否属于选择类 Renderer 支持的基础值。\n *\n * @param value - 待判断的运行时值。\n * @returns 是否为 string、number 或 boolean。\n */\nexport function isElementOptionValue(value: unknown): value is ElementOptionValue {\n return (\n typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\"\n )\n}\n\n/**\n * 规范化选择类 Renderer 的单选或多选值。\n *\n * @param value - Element Plus 产生的运行时值。\n * @param multiple - 是否处于多选模式。\n * @returns Schemx 选择类 Renderer 的基础值契约。\n */\nexport function normalizeElementSelection(\n value: unknown,\n multiple = false\n): ElementOptionValue | ElementOptionValue[] | null {\n if (multiple) {\n if (!Array.isArray(value)) return []\n\n return value.filter(isElementOptionValue)\n }\n\n return isElementOptionValue(value) ? value : null\n}\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-autocomplete-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElAutocomplete\n ref=\"autocompleteRef\"\n v-bind=\"autocompleteProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @select=\"handleSelect\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend>\n <slot name=\"prepend\" />\n </template>\n <template v-if=\"$slots.append\" #append>\n <slot name=\"append\" />\n </template>\n </ElAutocomplete>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElAutocomplete 渲染自动补全字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElAutocomplete } from \"element-plus\"\n\n import {\n getElementOptionLabel,\n normalizeElementOptions,\n } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type {\n AutocompleteOption,\n AutocompleteRendererProps,\n AutocompleteSuggestions,\n AutocompleteValue,\n } from \"./types\"\n import type { AutocompleteInstance } from \"element-plus\"\n\n defineOptions({\n name: \"AutocompleteRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<AutocompleteRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n placeholder: \"\",\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n props: () => ({}),\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<AutocompleteValue>(\"value\")\n\n const autocompleteRef = ref<AutocompleteInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const normalizedOptions = computed(() =>\n normalizeElementOptions(props.options, props.props)\n )\n\n const displayValue = computed(() => currentValue.value)\n\n const localFetchSuggestions: AutocompleteSuggestions = (query, callback) => {\n const keyword = String(query).toLowerCase()\n\n const options = normalizedOptions.value.filter((option) =>\n getElementOptionLabel(option, props.props).toLowerCase().includes(keyword)\n )\n\n callback(options)\n }\n\n const fetchSuggestions = computed<AutocompleteSuggestions>(\n () => props.fetchSuggestions ?? localFetchSuggestions\n )\n\n const autocompleteProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"options\",\n \"props\",\n \"onSelect\",\n \"onBlur\",\n \"onFocus\",\n ]),\n fetchSuggestions: fetchSuggestions.value,\n valueKey: props.valueKey ?? props.props?.label ?? \"label\",\n }))\n\n /** 同步自动补全输入值。 */\n const handleUpdate = (value: string | number): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理建议项选择。 */\n const handleSelect = (item: AutocompleteOption): void => {\n props.onSelect?.(item)\n }\n\n /** 处理自动补全输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理自动补全输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部自动补全输入框。 */\n focus: () => autocompleteRef.value?.focus(),\n /** 使内部自动补全输入框失焦。 */\n blur: () => autocompleteRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-autocomplete-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElAutocomplete\n ref=\"autocompleteRef\"\n v-bind=\"autocompleteProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @select=\"handleSelect\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n <template v-if=\"$slots.prepend\" #prepend>\n <slot name=\"prepend\" />\n </template>\n <template v-if=\"$slots.append\" #append>\n <slot name=\"append\" />\n </template>\n </ElAutocomplete>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElAutocomplete 渲染自动补全字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElAutocomplete } from \"element-plus\"\n\n import {\n getElementOptionLabel,\n normalizeElementOptions,\n } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type {\n AutocompleteOption,\n AutocompleteRendererProps,\n AutocompleteSuggestions,\n AutocompleteValue,\n } from \"./types\"\n import type { AutocompleteInstance } from \"element-plus\"\n\n defineOptions({\n name: \"AutocompleteRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<AutocompleteRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n placeholder: \"\",\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n props: () => ({}),\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<AutocompleteValue>(\"value\")\n\n const autocompleteRef = ref<AutocompleteInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const normalizedOptions = computed(() =>\n normalizeElementOptions(props.options, props.props)\n )\n\n const displayValue = computed(() => currentValue.value)\n\n const localFetchSuggestions: AutocompleteSuggestions = (query, callback) => {\n const keyword = String(query).toLowerCase()\n\n const options = normalizedOptions.value.filter((option) =>\n getElementOptionLabel(option, props.props).toLowerCase().includes(keyword)\n )\n\n callback(options)\n }\n\n const fetchSuggestions = computed<AutocompleteSuggestions>(\n () => props.fetchSuggestions ?? localFetchSuggestions\n )\n\n const autocompleteProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"options\",\n \"props\",\n \"onSelect\",\n \"onBlur\",\n \"onFocus\",\n ]),\n fetchSuggestions: fetchSuggestions.value,\n valueKey: props.valueKey ?? props.props?.label ?? \"label\",\n }))\n\n /** 同步自动补全输入值。 */\n const handleUpdate = (value: string | number): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理建议项选择。 */\n const handleSelect = (item: AutocompleteOption): void => {\n props.onSelect?.(item)\n }\n\n /** 处理自动补全输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理自动补全输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部自动补全输入框。 */\n focus: () => autocompleteRef.value?.focus(),\n /** 使内部自动补全输入框失焦。 */\n blur: () => autocompleteRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** Autocomplete Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport AutocompleteRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(AutocompleteRendererComponent)\nexport type {\n AutocompleteOption,\n AutocompleteOptionProps,\n AutocompleteRendererInstance,\n AutocompleteRendererProps,\n AutocompleteSuggestions,\n AutocompleteValue,\n} from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-color-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElColorPicker\n ref=\"colorPickerRef\"\n v-bind=\"colorPickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @active-change=\"handleActiveChange\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElColorPicker 渲染颜色字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElColorPicker } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { ColorPickerRendererProps, ColorPickerValue } from \"./types\"\n import type { ColorPickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"ColorPickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<ColorPickerRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<ColorPickerValue>(\"value\")\n\n const colorPickerRef = ref<ColorPickerInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const colorPickerProps = computed(() =>\n getElementProps(props, attrs, [\"onActiveChange\", \"onClear\", \"onBlur\", \"onFocus\"])\n )\n\n /** 同步颜色值。 */\n const handleUpdate = (value: ColorPickerValue): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理激活颜色变化。 */\n const handleActiveChange = (value: ColorPickerValue): void => {\n props.onActiveChange?.(value)\n }\n\n /** 处理颜色清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理颜色选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理颜色选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部颜色选择器。 */\n focus: () => colorPickerRef.value?.focus(),\n /** 使内部颜色选择器失焦。 */\n blur: () => colorPickerRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-color-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElColorPicker\n ref=\"colorPickerRef\"\n v-bind=\"colorPickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @active-change=\"handleActiveChange\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElColorPicker 渲染颜色字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElColorPicker } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { ColorPickerRendererProps, ColorPickerValue } from \"./types\"\n import type { ColorPickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"ColorPickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<ColorPickerRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<ColorPickerValue>(\"value\")\n\n const colorPickerRef = ref<ColorPickerInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const colorPickerProps = computed(() =>\n getElementProps(props, attrs, [\"onActiveChange\", \"onClear\", \"onBlur\", \"onFocus\"])\n )\n\n /** 同步颜色值。 */\n const handleUpdate = (value: ColorPickerValue): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理激活颜色变化。 */\n const handleActiveChange = (value: ColorPickerValue): void => {\n props.onActiveChange?.(value)\n }\n\n /** 处理颜色清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理颜色选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理颜色选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部颜色选择器。 */\n focus: () => colorPickerRef.value?.focus(),\n /** 使内部颜色选择器失焦。 */\n blur: () => colorPickerRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** ColorPicker Renderer 统一导出。 */\n\nimport ColorPickerRendererComponent from \"./index.vue\"\n\nexport default ColorPickerRendererComponent\nexport type { ColorPickerRendererProps, ColorPickerValue } from \"./types\"\n","/** Element Plus 日期与时间值的只读格式化工具。 */\n\nimport dayjs from \"dayjs\"\n\n/**\n * 格式化日期、时间或范围值。\n *\n * @param value - Element Plus 产生的单值或范围值。\n * @param format - Day.js 格式;字符串值会直接展示。\n * @param rangeSeparator - 范围值之间的分隔符。\n * @returns 面向用户的日期或时间文本。\n */\nexport function formatElementDateValue(\n value: unknown,\n format: string,\n rangeSeparator = \" - \"\n): string {\n if (Array.isArray(value)) {\n return value\n .map((item) => formatElementDateValue(item, format, rangeSeparator))\n .join(rangeSeparator)\n }\n\n if (value instanceof Date || typeof value === \"number\") {\n const parsed = dayjs(value)\n\n return parsed.isValid() ? parsed.format(format) : String(value)\n }\n\n return value === null || value === undefined || value === \"\" ? \"\" : String(value)\n}\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-date-time-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElDatePicker\n ref=\"dateTimePickerRef\"\n v-bind=\"dateTimePickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElDatePicker 的 datetime 类型渲染日期时间字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElDatePicker } from \"element-plus\"\n\n import { formatElementDateValue } from \"@/renderers/shared/date\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { DateTimePickerRendererProps, DateTimePickerValue } from \"./types\"\n import type { DatePickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"DateTimePickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<DateTimePickerRendererProps>(), {\n value: undefined,\n type: \"datetime\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<DateTimePickerValue>(\"value\")\n\n const dateTimePickerRef = ref<DatePickerInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const dateTimePickerProps = computed(() => ({\n ...getElementProps(props, attrs, [\"type\", \"onBlur\", \"onFocus\"]),\n type: props.type,\n }))\n\n const displayValue = computed(() =>\n formatElementDateValue(\n currentValue.value,\n props.format ?? \"YYYY-MM-DD HH:mm:ss\",\n props.rangeSeparator ?? \" - \"\n )\n )\n\n /** 同步日期时间值。 */\n const handleUpdate = (value: DateTimePickerValue): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理日期时间选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理日期时间选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部日期时间选择器。 */\n focus: () => dateTimePickerRef.value?.focus(),\n /** 使内部日期时间选择器失焦。 */\n blur: () => dateTimePickerRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-date-time-picker-renderer > .el-date-editor {\n --el-date-editor-width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-date-time-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElDatePicker\n ref=\"dateTimePickerRef\"\n v-bind=\"dateTimePickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElDatePicker 的 datetime 类型渲染日期时间字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElDatePicker } from \"element-plus\"\n\n import { formatElementDateValue } from \"@/renderers/shared/date\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { DateTimePickerRendererProps, DateTimePickerValue } from \"./types\"\n import type { DatePickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"DateTimePickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<DateTimePickerRendererProps>(), {\n value: undefined,\n type: \"datetime\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<DateTimePickerValue>(\"value\")\n\n const dateTimePickerRef = ref<DatePickerInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const dateTimePickerProps = computed(() => ({\n ...getElementProps(props, attrs, [\"type\", \"onBlur\", \"onFocus\"]),\n type: props.type,\n }))\n\n const displayValue = computed(() =>\n formatElementDateValue(\n currentValue.value,\n props.format ?? \"YYYY-MM-DD HH:mm:ss\",\n props.rangeSeparator ?? \" - \"\n )\n )\n\n /** 同步日期时间值。 */\n const handleUpdate = (value: DateTimePickerValue): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理日期时间选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理日期时间选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部日期时间选择器。 */\n focus: () => dateTimePickerRef.value?.focus(),\n /** 使内部日期时间选择器失焦。 */\n blur: () => dateTimePickerRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-date-time-picker-renderer > .el-date-editor {\n --el-date-editor-width: 100%;\n }\n</style>\n","/** DateTimePicker Renderer 统一导出。 */\n\nimport DateTimePickerRendererComponent from \"./index.vue\"\n\nexport default DateTimePickerRendererComponent\nexport type {\n DateTimePickerRendererProps,\n DateTimePickerType,\n DateTimePickerValue,\n} from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-tag-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElInputTag\n ref=\"inputTagRef\"\n v-bind=\"inputTagProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @add-tag=\"handleAddTag\"\n @remove-tag=\"handleRemoveTag\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n </ElInputTag>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInputTag 渲染标签输入字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInputTag } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputTagRendererProps, InputTagValue } from \"./types\"\n import type { InputTagInstance } from \"element-plus\"\n\n defineOptions({\n name: \"InputTagRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputTagRendererProps>(), {\n value: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputTagValue>(\"value\")\n\n const inputTagRef = ref<InputTagInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? [])\n\n const displayValue = computed(() => currentValue.value.join(\"、\"))\n\n const inputTagProps = computed(() =>\n getElementProps(props, attrs, [\n \"onAddTag\",\n \"onRemoveTag\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ])\n )\n\n /** 同步标签列表。 */\n const handleUpdate = (value: string[] | undefined): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = value ?? []\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理新增标签。 */\n const handleAddTag = (value: string | string[]): void => {\n props.onAddTag?.(value)\n }\n\n /** 处理删除标签。 */\n const handleRemoveTag = (value: string, index: number): void => {\n props.onRemoveTag?.(value, index)\n }\n\n /** 处理标签清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理标签输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理标签输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部标签输入框。 */\n focus: () => inputTagRef.value?.focus(),\n /** 使内部标签输入框失焦。 */\n blur: () => inputTagRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-tag-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElInputTag\n ref=\"inputTagRef\"\n v-bind=\"inputTagProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @add-tag=\"handleAddTag\"\n @remove-tag=\"handleRemoveTag\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n </ElInputTag>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInputTag 渲染标签输入字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInputTag } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputTagRendererProps, InputTagValue } from \"./types\"\n import type { InputTagInstance } from \"element-plus\"\n\n defineOptions({\n name: \"InputTagRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputTagRendererProps>(), {\n value: () => [],\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputTagValue>(\"value\")\n\n const inputTagRef = ref<InputTagInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? [])\n\n const displayValue = computed(() => currentValue.value.join(\"、\"))\n\n const inputTagProps = computed(() =>\n getElementProps(props, attrs, [\n \"onAddTag\",\n \"onRemoveTag\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ])\n )\n\n /** 同步标签列表。 */\n const handleUpdate = (value: string[] | undefined): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = value ?? []\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理新增标签。 */\n const handleAddTag = (value: string | string[]): void => {\n props.onAddTag?.(value)\n }\n\n /** 处理删除标签。 */\n const handleRemoveTag = (value: string, index: number): void => {\n props.onRemoveTag?.(value, index)\n }\n\n /** 处理标签清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理标签输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理标签输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部标签输入框。 */\n focus: () => inputTagRef.value?.focus(),\n /** 使内部标签输入框失焦。 */\n blur: () => inputTagRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** InputTag Renderer 统一导出。 */\n\nimport InputTagRendererComponent from \"./index.vue\"\n\nexport default InputTagRendererComponent\nexport type { InputTagRendererProps, InputTagValue } from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-otp-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElInputOtp\n v-bind=\"inputOtpProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @finish=\"handleFinish\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.separator\" #separator=\"slotProps\">\n <slot name=\"separator\" v-bind=\"slotProps\" />\n </template>\n </ElInputOtp>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInputOtp 渲染一次性密码字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInputOtp } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputOtpRendererProps, InputOtpValue } from \"./types\"\n\n defineOptions({\n name: \"InputOtpRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputOtpRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputOtpValue>(\"value\")\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const inputOtpProps = computed(() =>\n getElementProps(props, attrs, [\"onFinish\", \"onBlur\", \"onFocus\"])\n )\n\n /** 同步一次性密码值。 */\n const handleUpdate = (value: string): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理一次性密码输入完成。 */\n const handleFinish = (value: string): void => {\n props.onFinish?.(value)\n }\n\n /** 处理一次性密码输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理一次性密码输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-input-otp-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElInputOtp\n v-bind=\"inputOtpProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @finish=\"handleFinish\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.separator\" #separator=\"slotProps\">\n <slot name=\"separator\" v-bind=\"slotProps\" />\n </template>\n </ElInputOtp>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElInputOtp 渲染一次性密码字段。 */\n import { computed, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElInputOtp } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { InputOtpRendererProps, InputOtpValue } from \"./types\"\n\n defineOptions({\n name: \"InputOtpRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<InputOtpRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<InputOtpValue>(\"value\")\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const inputOtpProps = computed(() =>\n getElementProps(props, attrs, [\"onFinish\", \"onBlur\", \"onFocus\"])\n )\n\n /** 同步一次性密码值。 */\n const handleUpdate = (value: string): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理一次性密码输入完成。 */\n const handleFinish = (value: string): void => {\n props.onFinish?.(value)\n }\n\n /** 处理一次性密码输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理一次性密码输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** InputOtp Renderer 统一导出。 */\n\nimport InputOtpRendererComponent from \"./index.vue\"\n\nexport default InputOtpRendererComponent\nexport type { InputOtpRendererProps, InputOtpValue } from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-mention-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElMention\n ref=\"mentionRef\"\n v-bind=\"mentionProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @search=\"handleSearch\"\n @select=\"handleSelect\"\n @whole-remove=\"handleWholeRemove\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.prepend\" #prepend>\n <slot name=\"prepend\" />\n </template>\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n <template v-if=\"$slots.append\" #append>\n <slot name=\"append\" />\n </template>\n <template v-if=\"$slots['password-icon']\" #password-icon=\"slotProps\">\n <slot name=\"password-icon\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.label\" #label=\"slotProps\">\n <slot name=\"label\" v-bind=\"slotProps\" />\n </template>\n </ElMention>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElMention 渲染提及字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElMention } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { MentionOptionItem, MentionRendererProps, MentionValue } from \"./types\"\n import type { MentionInstance } from \"element-plus\"\n\n defineOptions({\n name: \"MentionRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<MentionRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<MentionValue>(\"value\")\n\n const mentionRef = ref<MentionInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const mentionProps = computed(() =>\n getElementProps(props, attrs, [\n \"onSearch\",\n \"onSelect\",\n \"onWholeRemove\",\n \"onBlur\",\n \"onFocus\",\n ])\n )\n\n /** 同步提及文本。 */\n const handleUpdate = (value: string): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理提及搜索。 */\n const handleSearch = (pattern: string, prefix: string): void => {\n props.onSearch?.(pattern, prefix)\n }\n\n /** 处理提及选项选择。 */\n const handleSelect = (option: MentionOptionItem, prefix: string): void => {\n props.onSelect?.(option, prefix)\n }\n\n /** 处理整体删除提及文本。 */\n const handleWholeRemove = (pattern: string, prefix: string): void => {\n props.onWholeRemove?.(pattern, prefix)\n }\n\n /** 处理提及输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理提及输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部提及输入框。 */\n focus: () => mentionRef.value?.input?.focus(),\n /** 使内部提及输入框失焦。 */\n blur: () => mentionRef.value?.input?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-mention-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(currentValue, props.readonlyPlaceholder) }}\n </template>\n <ElMention\n ref=\"mentionRef\"\n v-bind=\"mentionProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @search=\"handleSearch\"\n @select=\"handleSelect\"\n @whole-remove=\"handleWholeRemove\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.prepend\" #prepend>\n <slot name=\"prepend\" />\n </template>\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\" />\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\" />\n </template>\n <template v-if=\"$slots.append\" #append>\n <slot name=\"append\" />\n </template>\n <template v-if=\"$slots['password-icon']\" #password-icon=\"slotProps\">\n <slot name=\"password-icon\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.label\" #label=\"slotProps\">\n <slot name=\"label\" v-bind=\"slotProps\" />\n </template>\n </ElMention>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElMention 渲染提及字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElMention } from \"element-plus\"\n\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { MentionOptionItem, MentionRendererProps, MentionValue } from \"./types\"\n import type { MentionInstance } from \"element-plus\"\n\n defineOptions({\n name: \"MentionRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<MentionRendererProps>(), {\n value: \"\",\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<MentionValue>(\"value\")\n\n const mentionRef = ref<MentionInstance>()\n\n const currentValue = computed(() => valueModel.value ?? props.value ?? \"\")\n\n const mentionProps = computed(() =>\n getElementProps(props, attrs, [\n \"onSearch\",\n \"onSelect\",\n \"onWholeRemove\",\n \"onBlur\",\n \"onFocus\",\n ])\n )\n\n /** 同步提及文本。 */\n const handleUpdate = (value: string): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理提及搜索。 */\n const handleSearch = (pattern: string, prefix: string): void => {\n props.onSearch?.(pattern, prefix)\n }\n\n /** 处理提及选项选择。 */\n const handleSelect = (option: MentionOptionItem, prefix: string): void => {\n props.onSelect?.(option, prefix)\n }\n\n /** 处理整体删除提及文本。 */\n const handleWholeRemove = (pattern: string, prefix: string): void => {\n props.onWholeRemove?.(pattern, prefix)\n }\n\n /** 处理提及输入框失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理提及输入框聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部提及输入框。 */\n focus: () => mentionRef.value?.input?.focus(),\n /** 使内部提及输入框失焦。 */\n blur: () => mentionRef.value?.input?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** Mention Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport MentionRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(MentionRendererComponent)\nexport type {\n MentionOptionItem,\n MentionRendererInstance,\n MentionRendererProps,\n MentionValue,\n} from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElSelect\n ref=\"selectRef\"\n v-bind=\"selectProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @remove-tag=\"handleRemoveTag\"\n @visible-change=\"handleVisibleChange\"\n @end-reached=\"handleEndReached\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n </ElSelect>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSelect 渲染选项字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSelect } from \"element-plus\"\n\n import {\n getElementOptionDisplayValue,\n normalizeElementSelection,\n } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { SelectRendererProps, SelectValue } from \"./types\"\n import type { ScrollbarDirection, SelectInstance } from \"element-plus\"\n\n defineOptions({\n name: \"SelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n multiple: false,\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<SelectValue>(\"value\")\n\n const selectRef = ref<SelectInstance>()\n\n const currentValue = computed(() =>\n normalizeElementSelection(\n valueModel.value === undefined ? props.value : valueModel.value,\n props.multiple\n )\n )\n\n const displayValue = computed(() =>\n getElementOptionDisplayValue(currentValue.value, props.options ?? [], props.props)\n )\n\n const selectProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"onRemoveTag\",\n \"onVisibleChange\",\n \"onEndReached\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ]),\n }))\n\n /** 同步选择值。 */\n const handleUpdate = (value: unknown): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = normalizeElementSelection(value, props.multiple)\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理删除多选标签。 */\n const handleRemoveTag = (value: unknown): void => {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n props.onRemoveTag?.(value)\n }\n }\n\n /** 处理下拉面板显示状态变化。 */\n const handleVisibleChange = (visible: boolean): void => {\n props.onVisibleChange?.(visible)\n }\n\n /** 处理下拉列表滚动到底部。 */\n const handleEndReached = (direction: ScrollbarDirection): void => {\n props.onEndReached?.(direction)\n }\n\n /** 处理选择清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部选择器。 */\n focus: () => selectRef.value?.focus(),\n /** 使内部选择器失焦。 */\n blur: () => selectRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElSelect\n ref=\"selectRef\"\n v-bind=\"selectProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @remove-tag=\"handleRemoveTag\"\n @visible-change=\"handleVisibleChange\"\n @end-reached=\"handleEndReached\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n </ElSelect>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSelect 渲染选项字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSelect } from \"element-plus\"\n\n import {\n getElementOptionDisplayValue,\n normalizeElementSelection,\n } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { SelectRendererProps, SelectValue } from \"./types\"\n import type { ScrollbarDirection, SelectInstance } from \"element-plus\"\n\n defineOptions({\n name: \"SelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<SelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n multiple: false,\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<SelectValue>(\"value\")\n\n const selectRef = ref<SelectInstance>()\n\n const currentValue = computed(() =>\n normalizeElementSelection(\n valueModel.value === undefined ? props.value : valueModel.value,\n props.multiple\n )\n )\n\n const displayValue = computed(() =>\n getElementOptionDisplayValue(currentValue.value, props.options ?? [], props.props)\n )\n\n const selectProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"onRemoveTag\",\n \"onVisibleChange\",\n \"onEndReached\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ]),\n }))\n\n /** 同步选择值。 */\n const handleUpdate = (value: unknown): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = normalizeElementSelection(value, props.multiple)\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理删除多选标签。 */\n const handleRemoveTag = (value: unknown): void => {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n props.onRemoveTag?.(value)\n }\n }\n\n /** 处理下拉面板显示状态变化。 */\n const handleVisibleChange = (visible: boolean): void => {\n props.onVisibleChange?.(visible)\n }\n\n /** 处理下拉列表滚动到底部。 */\n const handleEndReached = (direction: ScrollbarDirection): void => {\n props.onEndReached?.(direction)\n }\n\n /** 处理选择清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部选择器。 */\n focus: () => selectRef.value?.focus(),\n /** 使内部选择器失焦。 */\n blur: () => selectRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** Select Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport SelectRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(SelectRendererComponent)\nexport type {\n SelectOption,\n SelectRendererInstance,\n SelectRendererProps,\n SelectValue,\n} from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-virtualized-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElSelectV2\n ref=\"selectRef\"\n v-bind=\"selectProps\"\n :model-value=\"currentValue\"\n :options=\"props.options ?? []\"\n @update:model-value=\"handleUpdate\"\n @remove-tag=\"handleRemoveTag\"\n @visible-change=\"handleVisibleChange\"\n @end-reached=\"handleEndReached\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n </ElSelectV2>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSelectV2 渲染虚拟化选项字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSelectV2 } from \"element-plus\"\n\n import {\n getElementOptionDisplayValue,\n normalizeElementSelection,\n } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { VirtualizedSelectRendererProps, VirtualizedSelectValue } from \"./types\"\n import type { ScrollbarDirection, SelectV2Instance } from \"element-plus\"\n\n defineOptions({\n name: \"VirtualizedSelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<VirtualizedSelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n multiple: false,\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<VirtualizedSelectValue>(\"value\")\n\n const selectRef = ref<SelectV2Instance>()\n\n const currentValue = computed(() =>\n normalizeElementSelection(\n valueModel.value === undefined ? props.value : valueModel.value,\n props.multiple\n )\n )\n\n const displayValue = computed(() =>\n getElementOptionDisplayValue(currentValue.value, props.options ?? [], props.props)\n )\n\n const selectProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"onRemoveTag\",\n \"onVisibleChange\",\n \"onEndReached\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ]),\n }))\n\n /** 同步虚拟化选择值。 */\n const handleUpdate = (value: unknown): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = normalizeElementSelection(value, props.multiple)\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理删除多选标签。 */\n const handleRemoveTag = (value: unknown): void => {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n props.onRemoveTag?.(value)\n }\n }\n\n /** 处理下拉面板显示状态变化。 */\n const handleVisibleChange = (visible: boolean): void => {\n props.onVisibleChange?.(visible)\n }\n\n /** 处理虚拟列表滚动到底部。 */\n const handleEndReached = (direction: ScrollbarDirection): void => {\n props.onEndReached?.(direction)\n }\n\n /** 处理选择清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理虚拟化选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理虚拟化选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部虚拟化选择器。 */\n focus: () => selectRef.value?.focus(),\n /** 使内部虚拟化选择器失焦。 */\n blur: () => selectRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-virtualized-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElSelectV2\n ref=\"selectRef\"\n v-bind=\"selectProps\"\n :model-value=\"currentValue\"\n :options=\"props.options ?? []\"\n @update:model-value=\"handleUpdate\"\n @remove-tag=\"handleRemoveTag\"\n @visible-change=\"handleVisibleChange\"\n @end-reached=\"handleEndReached\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n </ElSelectV2>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElSelectV2 渲染虚拟化选项字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElSelectV2 } from \"element-plus\"\n\n import {\n getElementOptionDisplayValue,\n normalizeElementSelection,\n } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { VirtualizedSelectRendererProps, VirtualizedSelectValue } from \"./types\"\n import type { ScrollbarDirection, SelectV2Instance } from \"element-plus\"\n\n defineOptions({\n name: \"VirtualizedSelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<VirtualizedSelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n options: () => [],\n multiple: false,\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<VirtualizedSelectValue>(\"value\")\n\n const selectRef = ref<SelectV2Instance>()\n\n const currentValue = computed(() =>\n normalizeElementSelection(\n valueModel.value === undefined ? props.value : valueModel.value,\n props.multiple\n )\n )\n\n const displayValue = computed(() =>\n getElementOptionDisplayValue(currentValue.value, props.options ?? [], props.props)\n )\n\n const selectProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"onRemoveTag\",\n \"onVisibleChange\",\n \"onEndReached\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ]),\n }))\n\n /** 同步虚拟化选择值。 */\n const handleUpdate = (value: unknown): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = normalizeElementSelection(value, props.multiple)\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理删除多选标签。 */\n const handleRemoveTag = (value: unknown): void => {\n if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n props.onRemoveTag?.(value)\n }\n }\n\n /** 处理下拉面板显示状态变化。 */\n const handleVisibleChange = (visible: boolean): void => {\n props.onVisibleChange?.(visible)\n }\n\n /** 处理虚拟列表滚动到底部。 */\n const handleEndReached = (direction: ScrollbarDirection): void => {\n props.onEndReached?.(direction)\n }\n\n /** 处理选择清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理虚拟化选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理虚拟化选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部虚拟化选择器。 */\n focus: () => selectRef.value?.focus(),\n /** 使内部虚拟化选择器失焦。 */\n blur: () => selectRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** VirtualizedSelect Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport VirtualizedSelectRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(VirtualizedSelectRendererComponent)\nexport type {\n VirtualizedSelectOption,\n VirtualizedSelectRendererInstance,\n VirtualizedSelectRendererProps,\n VirtualizedSelectValue,\n} from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-time-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElTimePicker\n ref=\"timePickerRef\"\n v-bind=\"timePickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElTimePicker 渲染时间字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElTimePicker } from \"element-plus\"\n\n import { formatElementDateValue } from \"@/renderers/shared/date\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { TimePickerRendererProps, TimePickerValue } from \"./types\"\n import type { TimePickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"TimePickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<TimePickerRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<TimePickerValue>(\"value\")\n\n const timePickerRef = ref<TimePickerInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const timePickerProps = computed(() =>\n getElementProps(props, attrs, [\"onBlur\", \"onFocus\"])\n )\n\n const displayValue = computed(() =>\n formatElementDateValue(\n currentValue.value,\n props.format ?? \"HH:mm:ss\",\n props.rangeSeparator ?? \" - \"\n )\n )\n\n /** 同步时间值。 */\n const handleUpdate = (value: TimePickerValue): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理时间选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理时间选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部时间选择器。 */\n focus: () => timePickerRef.value?.focus(),\n /** 使内部时间选择器失焦。 */\n blur: () => timePickerRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-time-picker-renderer > .el-date-editor {\n --el-date-editor-width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-time-picker-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElTimePicker\n ref=\"timePickerRef\"\n v-bind=\"timePickerProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElTimePicker 渲染时间字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElTimePicker } from \"element-plus\"\n\n import { formatElementDateValue } from \"@/renderers/shared/date\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { TimePickerRendererProps, TimePickerValue } from \"./types\"\n import type { TimePickerInstance } from \"element-plus\"\n\n defineOptions({\n name: \"TimePickerRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<TimePickerRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<TimePickerValue>(\"value\")\n\n const timePickerRef = ref<TimePickerInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const timePickerProps = computed(() =>\n getElementProps(props, attrs, [\"onBlur\", \"onFocus\"])\n )\n\n const displayValue = computed(() =>\n formatElementDateValue(\n currentValue.value,\n props.format ?? \"HH:mm:ss\",\n props.rangeSeparator ?? \" - \"\n )\n )\n\n /** 同步时间值。 */\n const handleUpdate = (value: TimePickerValue): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理时间选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理时间选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部时间选择器。 */\n focus: () => timePickerRef.value?.focus(),\n /** 使内部时间选择器失焦。 */\n blur: () => timePickerRef.value?.blur(),\n })\n</script>\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n\n .schemx-time-picker-renderer > .el-date-editor {\n --el-date-editor-width: 100%;\n }\n</style>\n","/** TimePicker Renderer 统一导出。 */\n\nimport TimePickerRendererComponent from \"./index.vue\"\n\nexport default TimePickerRendererComponent\nexport type { TimePickerRendererProps, TimePickerValue } from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-time-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElTimeSelect\n ref=\"timeSelectRef\"\n v-bind=\"timeSelectProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElTimeSelect 渲染固定时间字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElTimeSelect } from \"element-plus\"\n\n import { formatElementDateValue } from \"@/renderers/shared/date\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { TimeSelectRendererProps, TimeSelectValue } from \"./types\"\n import type { TimeSelectInstance } from \"element-plus\"\n\n defineOptions({\n name: \"TimeSelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<TimeSelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<TimeSelectValue>(\"value\")\n\n const timeSelectRef = ref<TimeSelectInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const timeSelectProps = computed(() =>\n getElementProps(props, attrs, [\"onClear\", \"onBlur\", \"onFocus\"])\n )\n\n const displayValue = computed(() =>\n formatElementDateValue(currentValue.value, props.format ?? \"HH:mm\")\n )\n\n /** 同步固定时间值。 */\n const handleUpdate = (value: string | null): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理固定时间清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理固定时间选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理固定时间选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部固定时间选择器。 */\n focus: () => timeSelectRef.value?.focus(),\n /** 使内部固定时间选择器失焦。 */\n blur: () => timeSelectRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-time-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElTimeSelect\n ref=\"timeSelectRef\"\n v-bind=\"timeSelectProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n />\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElTimeSelect 渲染固定时间字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElTimeSelect } from \"element-plus\"\n\n import { formatElementDateValue } from \"@/renderers/shared/date\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { getReadonlyDisplayValue } from \"@/utils\"\n\n import type { TimeSelectRendererProps, TimeSelectValue } from \"./types\"\n import type { TimeSelectInstance } from \"element-plus\"\n\n defineOptions({\n name: \"TimeSelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<TimeSelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<TimeSelectValue>(\"value\")\n\n const timeSelectRef = ref<TimeSelectInstance>()\n\n const currentValue = computed(() =>\n valueModel.value === undefined ? (props.value ?? null) : valueModel.value\n )\n\n const timeSelectProps = computed(() =>\n getElementProps(props, attrs, [\"onClear\", \"onBlur\", \"onFocus\"])\n )\n\n const displayValue = computed(() =>\n formatElementDateValue(currentValue.value, props.format ?? \"HH:mm\")\n )\n\n /** 同步固定时间值。 */\n const handleUpdate = (value: string | null): void => {\n if (props.readonly || props.disabled) return\n\n valueModel.value = value\n props.onChange?.(value)\n }\n\n /** 处理固定时间清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理固定时间选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理固定时间选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部固定时间选择器。 */\n focus: () => timeSelectRef.value?.focus(),\n /** 使内部固定时间选择器失焦。 */\n blur: () => timeSelectRef.value?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** TimeSelect Renderer 统一导出。 */\n\nimport TimeSelectRendererComponent from \"./index.vue\"\n\nexport default TimeSelectRendererComponent\nexport type { TimeSelectRendererProps, TimeSelectValue } from \"./types\"\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-tree-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElTreeSelect\n ref=\"treeSelectRef\"\n v-bind=\"treeSelectProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @check=\"handleCheck\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @visible-change=\"handleVisibleChange\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n </ElTreeSelect>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElTreeSelect 渲染树形选择字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElTreeSelect } from \"element-plus\"\n\n import { normalizeElementSelection } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { findTreeItem, getReadonlyDisplayValue } from \"@/utils\"\n\n import type { TreeSelectRendererProps, TreeSelectValue } from \"./types\"\n import type { CheckedInfo, TreeNodeData, TreeSelectInstance } from \"element-plus\"\n\n defineOptions({\n name: \"TreeSelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<TreeSelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n multiple: false,\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<TreeSelectValue>(\"value\")\n\n const treeSelectRef = ref<TreeSelectInstance>()\n\n const currentValue = computed(() =>\n normalizeElementSelection(\n valueModel.value === undefined ? props.value : valueModel.value,\n props.multiple\n )\n )\n\n const treeData = computed<TreeNodeData[]>(() => props.options ?? props.data ?? [])\n\n const treeSelectProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"options\",\n \"onCheck\",\n \"onNodeClick\",\n \"onNodeExpand\",\n \"onVisibleChange\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ]),\n data: treeData.value,\n nodeKey: props.nodeKey ?? \"value\",\n valueKey: props.valueKey ?? \"value\",\n }))\n\n const displayValue = computed(() => getTreeDisplayValue(currentValue.value))\n\n /** 将树节点值反查为路径文本。 */\n function getTreeDisplayValue(value: TreeSelectValue): string {\n const values = Array.isArray(value) ? value : [value]\n\n const valueKey = props.valueKey ?? \"value\"\n\n const labelKey = typeof props.props?.label === \"string\" ? props.props.label : \"label\"\n\n const childrenKey = props.props?.children ?? \"children\"\n\n return values\n .filter((item): item is string | number | boolean => item !== null)\n .map((item) => {\n const result = findTreeItem(treeData.value, item, {\n labelKey,\n valueKey,\n childrenKey,\n })\n\n return result.labels.length ? result.labels.join(\" / \") : String(item)\n })\n .join(\"、\")\n }\n\n /** 同步树形选择值。 */\n const handleUpdate = (value: unknown): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = normalizeElementSelection(value, props.multiple)\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理树节点勾选。 */\n const handleCheck = (data: TreeNodeData, info: CheckedInfo): void => {\n props.onCheck?.(data, info)\n }\n\n /** 处理树节点点击。 */\n const handleNodeClick = (\n data: TreeNodeData,\n node: unknown,\n event: MouseEvent\n ): void => {\n props.onNodeClick?.(data, node, event)\n }\n\n /** 处理树节点展开。 */\n const handleNodeExpand = (\n data: TreeNodeData,\n node: unknown,\n instance: unknown\n ): void => {\n props.onNodeExpand?.(data, node, instance)\n }\n\n /** 处理树形选择下拉面板显示状态变化。 */\n const handleVisibleChange = (visible: boolean): void => {\n props.onVisibleChange?.(visible)\n }\n\n /** 处理树形选择清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理树形选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理树形选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部树形选择器。 */\n focus: () => treeSelectRef.value?.selectRef?.focus(),\n /** 使内部树形选择器失焦。 */\n blur: () => treeSelectRef.value?.selectRef?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","<template>\n <Wrapper\n :class=\"['schemx-renderer', 'schemx-tree-select-renderer', props.className]\"\n :readonly=\"props.readonly\"\n :disabled=\"props.disabled\"\n >\n <template #readonly>\n {{ getReadonlyDisplayValue(displayValue, props.readonlyPlaceholder) }}\n </template>\n <ElTreeSelect\n ref=\"treeSelectRef\"\n v-bind=\"treeSelectProps\"\n :model-value=\"currentValue\"\n @update:model-value=\"handleUpdate\"\n @check=\"handleCheck\"\n @node-click=\"handleNodeClick\"\n @node-expand=\"handleNodeExpand\"\n @visible-change=\"handleVisibleChange\"\n @clear=\"handleClear\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n >\n <template v-if=\"$slots.default\" #default=\"slotProps\">\n <slot name=\"default\" v-bind=\"slotProps\" />\n </template>\n <template v-if=\"$slots.header\" #header>\n <slot name=\"header\" />\n </template>\n <template v-if=\"$slots.footer\" #footer>\n <slot name=\"footer\" />\n </template>\n <template v-if=\"$slots.loading\" #loading>\n <slot name=\"loading\" />\n </template>\n <template v-if=\"$slots.tag\" #tag=\"slotProps\">\n <slot name=\"tag\" v-bind=\"slotProps\" />\n </template>\n </ElTreeSelect>\n </Wrapper>\n</template>\n\n<script setup lang=\"ts\">\n /** 使用 Element Plus ElTreeSelect 渲染树形选择字段。 */\n import { computed, ref, useAttrs } from \"vue\"\n\n import { Wrapper } from \"@schemx/vue\"\n import { ElTreeSelect } from \"element-plus\"\n\n import { normalizeElementSelection } from \"@/renderers/shared/options\"\n import { getElementProps } from \"@/renderers/shared/props\"\n import { findTreeItem, getReadonlyDisplayValue } from \"@/utils\"\n\n import type { TreeSelectRendererProps, TreeSelectValue } from \"./types\"\n import type { CheckedInfo, TreeNodeData, TreeSelectInstance } from \"element-plus\"\n\n defineOptions({\n name: \"TreeSelectRendererComponent\",\n inheritAttrs: false,\n })\n\n const props = withDefaults(defineProps<TreeSelectRendererProps>(), {\n value: null,\n readonly: false,\n disabled: false,\n readonlyPlaceholder: \"-\",\n className: \"\",\n multiple: false,\n })\n\n const attrs = useAttrs() as Record<string, unknown>\n\n const valueModel = defineModel<TreeSelectValue>(\"value\")\n\n const treeSelectRef = ref<TreeSelectInstance>()\n\n const currentValue = computed(() =>\n normalizeElementSelection(\n valueModel.value === undefined ? props.value : valueModel.value,\n props.multiple\n )\n )\n\n const treeData = computed<TreeNodeData[]>(() => props.options ?? props.data ?? [])\n\n const treeSelectProps = computed(() => ({\n ...getElementProps(props, attrs, [\n \"options\",\n \"onCheck\",\n \"onNodeClick\",\n \"onNodeExpand\",\n \"onVisibleChange\",\n \"onClear\",\n \"onBlur\",\n \"onFocus\",\n ]),\n data: treeData.value,\n nodeKey: props.nodeKey ?? \"value\",\n valueKey: props.valueKey ?? \"value\",\n }))\n\n const displayValue = computed(() => getTreeDisplayValue(currentValue.value))\n\n /** 将树节点值反查为路径文本。 */\n function getTreeDisplayValue(value: TreeSelectValue): string {\n const values = Array.isArray(value) ? value : [value]\n\n const valueKey = props.valueKey ?? \"value\"\n\n const labelKey = typeof props.props?.label === \"string\" ? props.props.label : \"label\"\n\n const childrenKey = props.props?.children ?? \"children\"\n\n return values\n .filter((item): item is string | number | boolean => item !== null)\n .map((item) => {\n const result = findTreeItem(treeData.value, item, {\n labelKey,\n valueKey,\n childrenKey,\n })\n\n return result.labels.length ? result.labels.join(\" / \") : String(item)\n })\n .join(\"、\")\n }\n\n /** 同步树形选择值。 */\n const handleUpdate = (value: unknown): void => {\n if (props.readonly || props.disabled) return\n\n const nextValue = normalizeElementSelection(value, props.multiple)\n\n valueModel.value = nextValue\n props.onChange?.(nextValue)\n }\n\n /** 处理树节点勾选。 */\n const handleCheck = (data: TreeNodeData, info: CheckedInfo): void => {\n props.onCheck?.(data, info)\n }\n\n /** 处理树节点点击。 */\n const handleNodeClick = (\n data: TreeNodeData,\n node: unknown,\n event: MouseEvent\n ): void => {\n props.onNodeClick?.(data, node, event)\n }\n\n /** 处理树节点展开。 */\n const handleNodeExpand = (\n data: TreeNodeData,\n node: unknown,\n instance: unknown\n ): void => {\n props.onNodeExpand?.(data, node, instance)\n }\n\n /** 处理树形选择下拉面板显示状态变化。 */\n const handleVisibleChange = (visible: boolean): void => {\n props.onVisibleChange?.(visible)\n }\n\n /** 处理树形选择清空。 */\n const handleClear = (): void => {\n props.onClear?.()\n }\n\n /** 处理树形选择器失焦。 */\n const handleBlur = (event: FocusEvent): void => {\n props.onBlur?.(event)\n }\n\n /** 处理树形选择器聚焦。 */\n const handleFocus = (event: FocusEvent): void => {\n props.onFocus?.(event)\n }\n\n defineExpose({\n /** 聚焦内部树形选择器。 */\n focus: () => treeSelectRef.value?.selectRef?.focus(),\n /** 使内部树形选择器失焦。 */\n blur: () => treeSelectRef.value?.selectRef?.blur(),\n })\n</script>\n\n<style>\n .schemx-renderer {\n box-sizing: border-box;\n width: 100%;\n }\n</style>\n","/** TreeSelect Renderer 统一导出。 */\n\nimport { WithRemoteOptions } from \"@schemx/vue\"\n\nimport TreeSelectRendererComponent from \"./index.vue\"\n\nexport default WithRemoteOptions(TreeSelectRendererComponent)\nexport type { TreeSelectOption, TreeSelectRendererProps, TreeSelectValue } from \"./types\"\n","/** Element Plus Renderer 公共导出。 */\n\nexport { default as InputRenderer } from \"./InputRenderer\"\nexport { default as InputNumberRenderer } from \"./InputNumberRenderer\"\nexport { default as SwitchRenderer } from \"./SwitchRenderer\"\nexport { default as RadioRenderer } from \"./RadioRenderer\"\nexport { default as CheckboxRenderer } from \"./CheckboxRenderer\"\nexport { default as DatePickerRenderer } from \"./DatePickerRenderer\"\nexport { default as CascaderRenderer } from \"./CascaderRenderer\"\nexport { default as SensitiveInputRenderer } from \"./SensitiveInputRenderer\"\nexport { default as RateRenderer } from \"./RateRenderer\"\nexport { default as SliderRenderer } from \"./SliderRenderer\"\nexport { default as UploadRenderer } from \"./UploadRenderer\"\nexport { default as AutocompleteRenderer } from \"./AutocompleteRenderer\"\nexport { default as ColorPickerRenderer } from \"./ColorPickerRenderer\"\nexport { default as DateTimePickerRenderer } from \"./DateTimePickerRenderer\"\nexport { default as InputTagRenderer } from \"./InputTagRenderer\"\nexport { default as InputOtpRenderer } from \"./InputOtpRenderer\"\nexport { default as MentionRenderer } from \"./MentionRenderer\"\nexport { default as SelectRenderer } from \"./SelectRenderer\"\nexport { default as VirtualizedSelectRenderer } from \"./VirtualizedSelectRenderer\"\nexport { default as TimePickerRenderer } from \"./TimePickerRenderer\"\nexport { default as TimeSelectRenderer } from \"./TimeSelectRenderer\"\nexport { default as TreeSelectRenderer } from \"./TreeSelectRenderer\"\n\nexport type { InputRendererProps, InputValue } from \"./InputRenderer\"\nexport type { InputNumberRendererProps, InputNumberValue } from \"./InputNumberRenderer\"\nexport type { SwitchRendererProps, SwitchValue } from \"./SwitchRenderer\"\nexport type { RadioOption, RadioRendererProps, RadioValue } from \"./RadioRenderer\"\nexport type {\n CheckboxOption,\n CheckboxRendererProps,\n CheckboxValue,\n} from \"./CheckboxRenderer\"\nexport type { DatePickerRendererProps, DatePickerValue } from \"./DatePickerRenderer\"\nexport type { CascaderRendererProps, CascaderValueType } from \"./CascaderRenderer\"\nexport type {\n SensitiveInputRendererProps,\n SensitiveInputValue,\n} from \"./SensitiveInputRenderer\"\nexport type { RateRendererProps, RateValue } from \"./RateRenderer\"\nexport type { SliderRendererProps, SliderValue } from \"./SliderRenderer\"\nexport type {\n UploadBeforePreview,\n UploadDownloadHandler,\n UploadFile,\n UploadListType,\n UploadRendererProps,\n UploadRuntimeFile,\n UploadValue,\n} from \"./UploadRenderer\"\nexport type {\n AutocompleteOption,\n AutocompleteOptionProps,\n AutocompleteRendererInstance,\n AutocompleteRendererProps,\n AutocompleteSuggestions,\n AutocompleteValue,\n} from \"./AutocompleteRenderer\"\nexport type { ColorPickerRendererProps, ColorPickerValue } from \"./ColorPickerRenderer\"\nexport type {\n DateTimePickerRendererProps,\n DateTimePickerType,\n DateTimePickerValue,\n} from \"./DateTimePickerRenderer\"\nexport type { InputTagRendererProps, InputTagValue } from \"./InputTagRenderer\"\nexport type { InputOtpRendererProps, InputOtpValue } from \"./InputOtpRenderer\"\nexport type {\n MentionOptionItem,\n MentionRendererInstance,\n MentionRendererProps,\n MentionValue,\n} from \"./MentionRenderer\"\nexport type {\n SelectOption,\n SelectRendererInstance,\n SelectRendererProps,\n SelectValue,\n} from \"./SelectRenderer\"\nexport type {\n VirtualizedSelectOption,\n VirtualizedSelectRendererInstance,\n VirtualizedSelectRendererProps,\n VirtualizedSelectValue,\n} from \"./VirtualizedSelectRenderer\"\nexport type { TimePickerRendererProps, TimePickerValue } from \"./TimePickerRenderer\"\nexport type { TimeSelectRendererProps, TimeSelectValue } from \"./TimeSelectRenderer\"\nexport type {\n TreeSelectOption,\n TreeSelectRendererProps,\n TreeSelectValue,\n} from \"./TreeSelectRenderer\"\n\n/** Element Plus 适配包注册的默认 Renderer 类型。 */\nexport const DEFAULT_RENDERER_TYPES = [\n \"input\",\n \"inputNumber\",\n \"switch\",\n \"radio\",\n \"checkbox\",\n \"datePicker\",\n \"cascader\",\n \"sensitiveInput\",\n \"rate\",\n \"slider\",\n \"upload\",\n \"autocomplete\",\n \"colorPicker\",\n \"datetimePicker\",\n \"inputTag\",\n \"inputOtp\",\n \"mention\",\n \"select\",\n \"virtualizedSelect\",\n \"timePicker\",\n \"timeSelect\",\n \"treeSelect\",\n] as const\n","/**\n * Element Plus 默认 Col 定义。\n *\n * 由 Element Plus 适配包 Runtime 作为默认布局列组件使用;Vue 层提供通用 flex 行容器。\n *\n * @module layout/defaultCol\n */\n\nimport { ElCol } from \"element-plus\"\n\n/** Element Plus 适配包默认 Col。 */\nexport const ElementPlusCol = ElCol\n","/**\n * Element Plus 默认 Row 定义。\n *\n * 由 Element Plus 适配包 Runtime 作为默认布局行组件使用。\n *\n * @module layout/defaultRow\n */\n\nimport { defineComponent, h } from \"vue\"\n\nimport { normalizeSchemxGutter } from \"@schemx/vue\"\nimport { ElRow } from \"element-plus\"\n\nimport type { SchemxGutter } from \"@schemx/vue\"\n\nexport const ElementPlusRow = defineComponent({\n name: \"SchemxElementPlusRow\",\n inheritAttrs: false,\n setup(_, { attrs, slots }) {\n return () => {\n const { gutter, class: attrsClass, style: attrsStyle, ...restAttrs } = attrs\n\n const [top, right, bottom, left] = normalizeSchemxGutter(\n gutter as SchemxGutter | undefined\n )\n\n const halfTop = top / 2\n\n const halfRight = right / 2\n\n const halfBottom = bottom / 2\n\n const halfLeft = left / 2\n\n return h(\n ElRow,\n {\n ...restAttrs,\n class: attrsClass,\n gutter: 0,\n style: [\n attrsStyle,\n {\n \"--schemx-gutter-top\": `${halfTop}px`,\n \"--schemx-gutter-right\": `${halfRight}px`,\n \"--schemx-gutter-bottom\": `${halfBottom}px`,\n \"--schemx-gutter-left\": `${halfLeft}px`,\n margin: `-${halfTop}px -${halfRight}px -${halfBottom}px -${halfLeft}px`,\n },\n ],\n },\n slots\n )\n }\n },\n})\n","/**\n * Element Plus 默认 Renderer 定义。\n *\n * 该模块只导出 Renderer Map,由适配包 Runtime 注册到自己的 Registry,\n * 不在导入时修改 @schemx/vue 的模块级 Registry。\n */\n\nimport {\n AutocompleteRenderer,\n CascaderRenderer,\n CheckboxRenderer,\n ColorPickerRenderer,\n DatePickerRenderer,\n DateTimePickerRenderer,\n InputNumberRenderer,\n InputOtpRenderer,\n InputRenderer,\n InputTagRenderer,\n MentionRenderer,\n RadioRenderer,\n RateRenderer,\n SelectRenderer,\n SensitiveInputRenderer,\n SliderRenderer,\n SwitchRenderer,\n TimePickerRenderer,\n TimeSelectRenderer,\n TreeSelectRenderer,\n UploadRenderer,\n VirtualizedSelectRenderer,\n} from \"../renderers\"\n\nexport const defaultRenderers = {\n input: InputRenderer,\n inputNumber: InputNumberRenderer,\n switch: SwitchRenderer,\n radio: RadioRenderer,\n checkbox: CheckboxRenderer,\n datePicker: DatePickerRenderer,\n cascader: CascaderRenderer,\n sensitiveInput: SensitiveInputRenderer,\n rate: RateRenderer,\n slider: SliderRenderer,\n upload: UploadRenderer,\n autocomplete: AutocompleteRenderer,\n colorPicker: ColorPickerRenderer,\n datetimePicker: DateTimePickerRenderer,\n inputTag: InputTagRenderer,\n inputOtp: InputOtpRenderer,\n mention: MentionRenderer,\n select: SelectRenderer,\n virtualizedSelect: VirtualizedSelectRenderer,\n timePicker: TimePickerRenderer,\n timeSelect: TimeSelectRenderer,\n treeSelect: TreeSelectRenderer,\n}\n","/**\n * Element Plus 适配包的默认 Registry 与全局配置。\n *\n * 根入口通过导出本模块的 Registry 触发默认配置初始化。\n *\n * @module config/defaultConfig\n */\n\nimport {\n configureSchemx,\n createPresetRuleRegistry,\n createRendererRegistry,\n} from \"@schemx/core\"\n\nimport { ElementPlusCol } from \"../layout/defaultCol\"\nimport { ElementPlusRow } from \"../layout/defaultRow\"\nimport { defaultRenderers } from \"../renderers/defaultRenderers\"\n\nimport type { PresetRuleRegistry } from \"@schemx/core\"\n\n/** 创建 Element Plus 适配包默认使用的 Renderer Registry。 */\nfunction createElementPlusRendererRegistry() {\n const registry = createRendererRegistry(\"input\")\n\n registry.registerAll(defaultRenderers)\n\n return registry\n}\n\n/** Element Plus 适配包默认 Renderer Registry。 */\nexport const rendererRegistry = createElementPlusRendererRegistry()\n\n/** Element Plus 适配包默认校验规则 Registry。 */\nexport const presetRuleRegistry: PresetRuleRegistry = createPresetRuleRegistry()\n\n/**\n * 将 Element Plus 默认能力写入 Schemx 模块级全局配置。\n *\n * 业务可通过 Form Props 或 ConfigProvider 覆盖当前 Form;多个 UI 适配包同时导入时,\n * 最后执行的适配包配置会成为模块级全局默认值。\n */\nconfigureSchemx({\n rendererRegistry,\n presetRuleRegistry,\n colComponent: ElementPlusCol,\n rowComponent: ElementPlusRow,\n schemaConfig: {\n col: { span: 12 },\n row: { gutter: [14, 0] },\n labelAlign: \"right\",\n labelWidth: 120,\n labelPosition: \"left\",\n contentAlign: \"left\",\n bordered: false,\n },\n})\n"],"mappings":"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"}