huibo-ui 0.5.0 → 0.6.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 (69) hide show
  1. package/dist/cjs/hb-form-item.cjs.entry.js +59 -9
  2. package/dist/cjs/hb-form-item.cjs.entry.js.map +1 -1
  3. package/dist/cjs/hb-form.cjs.entry.js +105 -2
  4. package/dist/cjs/hb-form.cjs.entry.js.map +1 -1
  5. package/dist/cjs/hb-select.cjs.entry.js +82 -10
  6. package/dist/cjs/hb-select.cjs.entry.js.map +1 -1
  7. package/dist/cjs/hb-steps.cjs.entry.js +1 -1
  8. package/dist/cjs/hb-steps.cjs.entry.js.map +1 -1
  9. package/dist/cjs/hb-table.cjs.entry.js +195 -27
  10. package/dist/cjs/hb-table.cjs.entry.js.map +1 -1
  11. package/dist/cjs/huibo-ui.cjs.js +1 -1
  12. package/dist/cjs/loader.cjs.js +1 -1
  13. package/dist/collection/components/Form/Form.js +205 -2
  14. package/dist/collection/components/Form/Form.js.map +1 -1
  15. package/dist/collection/components/Form/FormItem.js +117 -10
  16. package/dist/collection/components/Form/FormItem.js.map +1 -1
  17. package/dist/collection/components/Select/Select.js +105 -10
  18. package/dist/collection/components/Select/Select.js.map +1 -1
  19. package/dist/collection/components/Table/Table.js +273 -27
  20. package/dist/collection/components/Table/Table.js.map +1 -1
  21. package/dist/collection/utils/virtual-scroll.js +39 -0
  22. package/dist/collection/utils/virtual-scroll.js.map +1 -0
  23. package/dist/components/hb-form-item.js +62 -9
  24. package/dist/components/hb-form-item.js.map +1 -1
  25. package/dist/components/hb-form.js +110 -2
  26. package/dist/components/hb-form.js.map +1 -1
  27. package/dist/components/hb-select.js +87 -11
  28. package/dist/components/hb-select.js.map +1 -1
  29. package/dist/components/hb-steps.js +1 -1
  30. package/dist/components/hb-steps.js.map +1 -1
  31. package/dist/components/hb-table.js +203 -29
  32. package/dist/components/hb-table.js.map +1 -1
  33. package/dist/esm/hb-form-item.entry.js +59 -9
  34. package/dist/esm/hb-form-item.entry.js.map +1 -1
  35. package/dist/esm/hb-form.entry.js +105 -2
  36. package/dist/esm/hb-form.entry.js.map +1 -1
  37. package/dist/esm/hb-select.entry.js +82 -10
  38. package/dist/esm/hb-select.entry.js.map +1 -1
  39. package/dist/esm/hb-steps.entry.js +1 -1
  40. package/dist/esm/hb-steps.entry.js.map +1 -1
  41. package/dist/esm/hb-table.entry.js +195 -27
  42. package/dist/esm/hb-table.entry.js.map +1 -1
  43. package/dist/esm/huibo-ui.js +1 -1
  44. package/dist/esm/loader.js +1 -1
  45. package/dist/huibo-ui/huibo-ui.esm.js +1 -1
  46. package/dist/huibo-ui/huibo-ui.esm.js.map +1 -1
  47. package/dist/huibo-ui/{p-79b24b83.entry.js → p-2cf5bf20.entry.js} +2 -2
  48. package/dist/huibo-ui/{p-79b24b83.entry.js.map → p-2cf5bf20.entry.js.map} +1 -1
  49. package/dist/huibo-ui/p-4148d875.entry.js +2 -0
  50. package/dist/huibo-ui/p-4148d875.entry.js.map +1 -0
  51. package/dist/huibo-ui/{p-54a28052.entry.js → p-6bfe1954.entry.js} +2 -2
  52. package/dist/huibo-ui/p-6bfe1954.entry.js.map +1 -0
  53. package/dist/huibo-ui/{p-ac18c68b.entry.js → p-e8824b2c.entry.js} +2 -2
  54. package/dist/huibo-ui/p-e8824b2c.entry.js.map +1 -0
  55. package/dist/huibo-ui/p-f69599fa.entry.js +2 -0
  56. package/dist/huibo-ui/p-f69599fa.entry.js.map +1 -0
  57. package/dist/types/components/Form/Form.d.ts +57 -0
  58. package/dist/types/components/Form/FormItem.d.ts +23 -0
  59. package/dist/types/components/Select/Select.d.ts +19 -0
  60. package/dist/types/components/Table/Table.d.ts +103 -8
  61. package/dist/types/components.d.ts +148 -2
  62. package/dist/types/utils/virtual-scroll.d.ts +38 -0
  63. package/package.json +1 -1
  64. package/dist/huibo-ui/p-29092b85.entry.js +0 -2
  65. package/dist/huibo-ui/p-29092b85.entry.js.map +0 -1
  66. package/dist/huibo-ui/p-2bc30b1b.entry.js +0 -2
  67. package/dist/huibo-ui/p-2bc30b1b.entry.js.map +0 -1
  68. package/dist/huibo-ui/p-54a28052.entry.js.map +0 -1
  69. package/dist/huibo-ui/p-ac18c68b.entry.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{r as e,g as t,h as i}from"./p-e42dfa95.js";const o='/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:host,:root{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,::backdrop,:after,:before{border:0 solid;box-sizing:border-box;margin:0;padding:0}::file-selector-button{appearance:button;background-color:#0000;border:0 solid;border-radius:0;box-sizing:border-box;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;margin:0;margin-inline-end:4px;opacity:1;padding:0}:host,html{-webkit-text-size-adjust:100%;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);line-height:1.5;tab-size:4;-webkit-tap-highlight-color:transparent}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-size:1em;font-variation-settings:var(--default-mono-font-variation-settings,normal)}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}button,input,optgroup,select,textarea{background-color:#0000;border-radius:0;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex;padding-block:0}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.inline{display:inline}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}} /*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components;:host{display:block}.hb-form{display:flex;flex-direction:column;gap:var(--hb-spacing-md)}.hb-form--inline{align-items:flex-start;flex-flow:wrap;gap:var(--hb-spacing-sm)var(--hb-spacing-lg)}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}';const a=o;const n=class{constructor(t){e(this,t)}get el(){return t(this)}model={};rules={};labelPosition="right";labelWidth="80px";inline=false;size="default";disabled=false;fields=[];fieldRegistry=new Map;handleFieldRegister=e=>{const{prop:t,validate:i,resetValue:o,getValue:a}=e.detail;this.fieldRegistry.set(t,{prop:t,validate:i,resetValue:o,getValue:a})};componentWillLoad(){this.el.addEventListener("hbFormFieldRegister",this.handleFieldRegister)}disconnectedCallback(){this.el.removeEventListener("hbFormFieldRegister",this.handleFieldRegister)}validate=async()=>{const e=await Promise.all(Array.from(this.fieldRegistry.values()).map((async e=>{const t=await e.validate();return t.length===0})));return e.every(Boolean)};resetFields=()=>{this.fieldRegistry.forEach((e=>e.resetValue()))};render(){return i("form",{key:"4e5a8f5d54c6760936fa8735e9a41d7956d631b1",class:{"hb-form":true,[`hb-form--label-${this.labelPosition}`]:true,"hb-form--inline":this.inline},onSubmit:e=>e.preventDefault(),novalidate:true},i("slot",{key:"d2e9a364e36387770dc8deb4c42c0e66542cd6a0"}))}};n.style=a;export{n as hb_form};
2
- //# sourceMappingURL=p-ac18c68b.entry.js.map
1
+ import{r as e,g as t,h as i}from"./p-e42dfa95.js";const o='/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:host,:root{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,::backdrop,:after,:before{border:0 solid;box-sizing:border-box;margin:0;padding:0}::file-selector-button{appearance:button;background-color:#0000;border:0 solid;border-radius:0;box-sizing:border-box;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;margin:0;margin-inline-end:4px;opacity:1;padding:0}:host,html{-webkit-text-size-adjust:100%;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);line-height:1.5;tab-size:4;-webkit-tap-highlight-color:transparent}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-size:1em;font-variation-settings:var(--default-mono-font-variation-settings,normal)}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}button,input,optgroup,select,textarea{background-color:#0000;border-radius:0;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex;padding-block:0}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.inline{display:inline}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}} /*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components;:host{display:block}.hb-form{display:flex;flex-direction:column;gap:var(--hb-spacing-md)}.hb-form--inline{align-items:flex-start;flex-flow:wrap;gap:var(--hb-spacing-sm)var(--hb-spacing-lg)}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}';const n=o;const a=class{constructor(t){e(this,t)}get el(){return t(this)}model={};rules={};labelPosition="right";labelWidth="80px";inline=false;size="default";disabled=false;initialValues;validateMessages;onFinish;onFinishFailed;onValuesChange;fields=[];fieldRegistry=new Map;handleFieldRegister=e=>{const{prop:t,validate:i,resetValue:o,getValue:n}=e.detail;this.fieldRegistry.set(t,{prop:t,validate:i,resetValue:o,getValue:n})};handleFieldChange=e=>{if(!this.onValuesChange)return;const t=e.target;const i=t.closest?.("hb-form-item");if(!i)return;const o=i.prop;if(!o)return;const n=this.fieldRegistry.get(o);const a=n?n.getValue():undefined;this.onValuesChange({prop:o,value:a,values:this.getFieldsValue()})};componentWillLoad(){this.el.addEventListener("hbFormFieldRegister",this.handleFieldRegister);this.el.addEventListener("hbChange",this.handleFieldChange)}componentDidLoad(){if(this.initialValues){this.fieldRegistry.forEach(((e,t)=>{if(this.initialValues&&t in this.initialValues){this.setFieldValue(t,this.initialValues[t])}}))}}disconnectedCallback(){this.el.removeEventListener("hbFormFieldRegister",this.handleFieldRegister);this.el.removeEventListener("hbChange",this.handleFieldChange)}getFieldsValue(){const e={};this.fieldRegistry.forEach(((t,i)=>{e[i]=t.getValue()}));return e}setFieldValue(e,t){const i=this.el.querySelector(`hb-form-item[prop="${e}"]`);if(!i)return;const o=i.querySelector("hb-input, hb-select, hb-cascader, hb-date-picker, hb-date-time-picker, hb-date-range-picker, "+"hb-input-number, hb-textarea, hb-checkbox, hb-checkbox-group, hb-radio-group, hb-switch, "+"hb-slider, hb-color-picker, hb-rate, hb-time-picker, hb-time-select");if(o){o.modelValue=t}}validate=async()=>{const e=await Promise.all(Array.from(this.fieldRegistry.values()).map((async e=>{const t=await e.validate();return t.length===0})));return e.every(Boolean)};handleSubmit=async e=>{e.preventDefault();const t=[];let i=true;for(const e of this.fieldRegistry.values()){const o=await e.validate();if(o.length>0){i=false;t.push({prop:e.prop,errors:o})}}if(i){this.onFinish?.(this.getFieldsValue())}else{this.onFinishFailed?.(t)}};resetFields=()=>{this.fieldRegistry.forEach((e=>e.resetValue()))};render(){return i("form",{key:"876ec07f044efed1a9aa92dbb76642b95013e9a5",class:{"hb-form":true,[`hb-form--label-${this.labelPosition}`]:true,"hb-form--inline":this.inline},onSubmit:this.handleSubmit,novalidate:true},i("slot",{key:"16efaff38a6f97ff1f339eef37f55b7e4aff0f4c"}))}};a.style=n;export{a as hb_form};
2
+ //# sourceMappingURL=p-e8824b2c.entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["formCss","HbFormStyle0","Form","model","rules","labelPosition","labelWidth","inline","size","disabled","initialValues","validateMessages","onFinish","onFinishFailed","onValuesChange","fields","fieldRegistry","Map","handleFieldRegister","e","prop","validate","resetValue","getValue","detail","this","set","handleFieldChange","target","item","closest","reg","get","value","undefined","values","getFieldsValue","componentWillLoad","el","addEventListener","componentDidLoad","forEach","_reg","setFieldValue","disconnectedCallback","removeEventListener","formItem","querySelector","control","modelValue","async","results","Promise","all","Array","from","map","field","errors","length","every","Boolean","handleSubmit","preventDefault","errorList","allOk","push","resetFields","render","h","key","class","onSubmit","novalidate"],"sources":["src/components/Form/form.css?tag=hb-form&encapsulation=shadow","src/components/Form/Form.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.hb-form {\n display: flex;\n flex-direction: column;\n gap: var(--hb-spacing-md);\n}\n\n.hb-form--inline {\n flex-direction: row;\n flex-wrap: wrap;\n gap: var(--hb-spacing-sm) var(--hb-spacing-lg);\n align-items: flex-start;\n}\n","import { Component, h, Prop, State, Element } from '@stencil/core';\n\ninterface FormFieldRegistration {\n prop: string;\n validate: () => Promise<string[]>;\n resetValue: () => void;\n getValue: () => any;\n}\n\n/**\n * Form 表单组件\n * 由输入框、选择器、单选框、多选框等控件组成,配合表单校验\n */\n@Component({\n tag: 'hb-form',\n styleUrl: 'form.css',\n shadow: true,\n})\nexport class Form {\n @Element() el: HTMLElement;\n\n /** 表单数据对象 */\n @Prop() model: Record<string, any> = {};\n\n /** 表单验证规则 */\n @Prop() rules: Record<string, any[]> = {};\n\n /** 标签位置 */\n @Prop() labelPosition: 'left' | 'right' | 'top' = 'right';\n\n /** 标签宽度 */\n @Prop() labelWidth: string = '80px';\n\n /** 是否行内表单 */\n @Prop() inline: boolean = false;\n\n /** 表单尺寸 */\n @Prop() size: 'large' | 'default' | 'small' = 'default';\n\n /** 是否禁用 */\n @Prop() disabled: boolean = false;\n\n /**\n * F1:初始值(非受控)。挂载后把这些值写到对应字段的子控件 modelValue。\n * key = FormItem 的 prop。\n */\n @Prop() initialValues?: Record<string, any>;\n\n /**\n * F4:校验提示模板。覆盖默认的「{label}不能为空」「{label}格式不正确」等文案。\n * 支持 {label} 占位符。仅对未在 rule.message 显式指定消息的规则生效。\n */\n @Prop() validateMessages?: { required?: string; pattern?: string; email?: string; min?: string; max?: string };\n\n /**\n * F2:提交且校验通过后的回调。参数为各字段当前值组成的对象。\n * 由表单 submit(form onSubmit)触发——表单内放 type=\"submit\" 的按钮即可。\n */\n @Prop() onFinish?: (values: Record<string, any>) => void;\n\n /**\n * F2:提交且校验失败后的回调。\n */\n @Prop() onFinishFailed?: (errors: { prop: string; errors: string[] }[]) => void;\n\n /**\n * F3:任意字段值变化时的回调。参数为 { prop, value, values }。\n * 由子控件冒泡的 hbChange 触发。\n */\n @Prop() onValuesChange?: (info: { prop: string; value: any; values: Record<string, any> }) => void;\n\n @State() fields: FormFieldRegistration[] = [];\n\n private fieldRegistry = new Map<string, FormFieldRegistration>();\n\n // 用 componentWillLoad 而非 componentDidLoad 注册监听器:\n // Stencil 生命周期里子组件(FormItem)的 componentDidLoad 先于父组件(Form)触发,\n // 若在 componentDidLoad 才挂监听,会错过子项派发的 hbFormFieldRegister,\n // 导致 fieldRegistry 为空、validate() 永远返回 true(真实浏览器里复现,mock-doc 被 waitForChanges 掩盖)。\n // L1:抽命名 handler 以便 disconnectedCallback 正确 remove(修复前匿名箭头无法 remove)。\n private handleFieldRegister = ((e: CustomEvent) => {\n const { prop, validate, resetValue, getValue } = e.detail;\n this.fieldRegistry.set(prop, { prop, validate, resetValue, getValue });\n }) as EventListener;\n\n /**\n * F3:监听子控件冒泡的 hbChange,识别来源 FormItem 并触发 onValuesChange。\n * 注:hbChange 由 hb-input/hb-select 等控件发出(composed 冒泡穿过 shadow),\n * 这里在 host 上捕获,通过 closest('hb-form-item') 定位字段 prop。\n */\n private handleFieldChange = ((e: Event) => {\n if (!this.onValuesChange) return;\n const target = e.target as HTMLElement;\n const item = target.closest?.('hb-form-item') as any;\n if (!item) return;\n const prop = item.prop;\n if (!prop) return;\n // 取该字段最新值\n const reg = this.fieldRegistry.get(prop);\n const value = reg ? reg.getValue() : undefined;\n this.onValuesChange({ prop, value, values: this.getFieldsValue() });\n }) as EventListener;\n\n componentWillLoad() {\n this.el.addEventListener('hbFormFieldRegister', this.handleFieldRegister);\n // F3:捕获子控件值变化\n this.el.addEventListener('hbChange', this.handleFieldChange);\n }\n\n componentDidLoad() {\n // F1:把 initialValues 写到对应字段的子控件\n if (this.initialValues) {\n this.fieldRegistry.forEach((_reg, prop) => {\n if (this.initialValues && prop in this.initialValues) {\n this.setFieldValue(prop, this.initialValues[prop]);\n }\n });\n }\n }\n\n disconnectedCallback() {\n this.el.removeEventListener('hbFormFieldRegister', this.handleFieldRegister);\n this.el.removeEventListener('hbChange', this.handleFieldChange);\n }\n\n /**\n * 收集所有字段的当前值(getFieldsValue)。\n */\n private getFieldsValue(): Record<string, any> {\n const values: Record<string, any> = {};\n this.fieldRegistry.forEach((reg, prop) => {\n values[prop] = reg.getValue();\n });\n return values;\n }\n\n /**\n * 设置某字段子控件的值(setFieldValue)。\n * 子控件统一用 modelValue 受控。\n */\n private setFieldValue(prop: string, value: any) {\n const formItem = this.el.querySelector(`hb-form-item[prop=\"${prop}\"]`) as HTMLElement | null;\n if (!formItem) return;\n const control = formItem.querySelector(\n 'hb-input, hb-select, hb-cascader, hb-date-picker, hb-date-time-picker, hb-date-range-picker, ' +\n 'hb-input-number, hb-textarea, hb-checkbox, hb-checkbox-group, hb-radio-group, hb-switch, ' +\n 'hb-slider, hb-color-picker, hb-rate, hb-time-picker, hb-time-select',\n ) as any;\n if (control) {\n control.modelValue = value;\n }\n }\n\n /**\n * 验证整个表单\n * @returns 是否验证通过\n */\n @Prop() validate = async (): Promise<boolean> => {\n const results = await Promise.all(\n Array.from(this.fieldRegistry.values()).map(async field => {\n const errors = await field.validate();\n return errors.length === 0;\n }),\n );\n return results.every(Boolean);\n };\n\n /**\n * F2:提交表单——校验全部字段,通过则 onFinish(values),失败则 onFinishFailed(errors)。\n */\n private handleSubmit = async (e: Event) => {\n e.preventDefault();\n const errorList: { prop: string; errors: string[] }[] = [];\n let allOk = true;\n for (const field of this.fieldRegistry.values()) {\n const errors = await field.validate();\n if (errors.length > 0) {\n allOk = false;\n errorList.push({ prop: field.prop, errors });\n }\n }\n if (allOk) {\n this.onFinish?.(this.getFieldsValue());\n } else {\n this.onFinishFailed?.(errorList);\n }\n };\n\n /**\n * 重置表单\n */\n @Prop() resetFields = (): void => {\n this.fieldRegistry.forEach(field => field.resetValue());\n };\n\n render() {\n return (\n <form\n class={{\n 'hb-form': true,\n [`hb-form--label-${this.labelPosition}`]: true,\n 'hb-form--inline': this.inline,\n }}\n onSubmit={this.handleSubmit}\n novalidate\n >\n <slot />\n </form>\n );\n }\n}\n"],"mappings":"kDAAA,MAAMA,EAAU,8wLAChB,MAAAC,EAAeD,E,MCiBFE,EAAI,M,iDAIPC,MAA6B,GAG7BC,MAA+B,GAG/BC,cAA0C,QAG1CC,WAAqB,OAGrBC,OAAkB,MAGlBC,KAAsC,UAGtCC,SAAoB,MAMpBC,cAMAC,iBAMAC,SAKAC,eAMAC,eAECC,OAAkC,GAEnCC,cAAgB,IAAIC,IAOpBC,oBAAwBC,IAC9B,MAAMC,KAAEA,EAAIC,SAAEA,EAAQC,WAAEA,EAAUC,SAAEA,GAAaJ,EAAEK,OACnDC,KAAKT,cAAcU,IAAIN,EAAM,CAAEA,OAAMC,WAAUC,aAAYC,YAC5D,EAOOI,kBAAsBR,IAC5B,IAAKM,KAAKX,eAAgB,OAC1B,MAAMc,EAAST,EAAES,OACjB,MAAMC,EAAOD,EAAOE,UAAU,gBAC9B,IAAKD,EAAM,OACX,MAAMT,EAAOS,EAAKT,KAClB,IAAKA,EAAM,OAEX,MAAMW,EAAMN,KAAKT,cAAcgB,IAAIZ,GACnC,MAAMa,EAAQF,EAAMA,EAAIR,WAAaW,UACrCT,KAAKX,eAAe,CAAEM,OAAMa,QAAOE,OAAQV,KAAKW,kBACjD,EAED,iBAAAC,GACEZ,KAAKa,GAAGC,iBAAiB,sBAAuBd,KAAKP,qBAErDO,KAAKa,GAAGC,iBAAiB,WAAYd,KAAKE,kB,CAG5C,gBAAAa,GAEE,GAAIf,KAAKf,cAAe,CACtBe,KAAKT,cAAcyB,SAAQ,CAACC,EAAMtB,KAChC,GAAIK,KAAKf,eAAiBU,KAAQK,KAAKf,cAAe,CACpDe,KAAKkB,cAAcvB,EAAMK,KAAKf,cAAcU,G,MAMpD,oBAAAwB,GACEnB,KAAKa,GAAGO,oBAAoB,sBAAuBpB,KAAKP,qBACxDO,KAAKa,GAAGO,oBAAoB,WAAYpB,KAAKE,kB,CAMvC,cAAAS,GACN,MAAMD,EAA8B,GACpCV,KAAKT,cAAcyB,SAAQ,CAACV,EAAKX,KAC/Be,EAAOf,GAAQW,EAAIR,UAAU,IAE/B,OAAOY,C,CAOD,aAAAQ,CAAcvB,EAAca,GAClC,MAAMa,EAAWrB,KAAKa,GAAGS,cAAc,sBAAsB3B,OAC7D,IAAK0B,EAAU,OACf,MAAME,EAAUF,EAASC,cACvB,gGACE,4FACA,uEAEJ,GAAIC,EAAS,CACXA,EAAQC,WAAahB,C,EAQjBZ,SAAW6B,UACjB,MAAMC,QAAgBC,QAAQC,IAC5BC,MAAMC,KAAK9B,KAAKT,cAAcmB,UAAUqB,KAAIN,MAAMO,IAChD,MAAMC,QAAeD,EAAMpC,WAC3B,OAAOqC,EAAOC,SAAW,CAAC,KAG9B,OAAOR,EAAQS,MAAMC,QAAQ,EAMvBC,aAAeZ,MAAO/B,IAC5BA,EAAE4C,iBACF,MAAMC,EAAkD,GACxD,IAAIC,EAAQ,KACZ,IAAK,MAAMR,KAAShC,KAAKT,cAAcmB,SAAU,CAC/C,MAAMuB,QAAeD,EAAMpC,WAC3B,GAAIqC,EAAOC,OAAS,EAAG,CACrBM,EAAQ,MACRD,EAAUE,KAAK,CAAE9C,KAAMqC,EAAMrC,KAAMsC,U,EAGvC,GAAIO,EAAO,CACTxC,KAAKb,WAAWa,KAAKW,iB,KAChB,CACLX,KAAKZ,iBAAiBmD,E,GAOlBG,YAAc,KACpB1C,KAAKT,cAAcyB,SAAQgB,GAASA,EAAMnC,cAAa,EAGzD,MAAA8C,GACE,OACEC,EAAA,QAAAC,IAAA,2CACEC,MAAO,CACL,UAAW,KACX,CAAC,kBAAkB9C,KAAKpB,iBAAkB,KAC1C,kBAAmBoB,KAAKlB,QAE1BiE,SAAU/C,KAAKqC,aACfW,WAAU,MAEVJ,EAAA,QAAAC,IAAA,6C","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ import{r as e,c as t,g as i,h as s}from"./p-e42dfa95.js";import{c as o}from"./p-4ef5a884.js";import{a as r,h as a}from"./p-00aa34c8.js";function l(e){const{total:t,viewportHeight:i,scrollTop:s,buffer:o=5}=e;if(t<=0)return{startIndex:0,endIndex:0};const r=e.itemHeight>0?e.itemHeight:1;let a=Math.floor(s/r)-o;if(a<0)a=0;let l=Math.ceil((s+i)/r)+o;if(l>t)l=t;return{startIndex:a,endIndex:l}}function n(e,t){const i=t>0?t:1;return e*i}function h(e,t){const i=t>0?t:1;return e*i}const c='/*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:host,:root{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,::backdrop,:after,:before{border:0 solid;box-sizing:border-box;margin:0;padding:0}::file-selector-button{appearance:button;background-color:#0000;border:0 solid;border-radius:0;box-sizing:border-box;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;margin:0;margin-inline-end:4px;opacity:1;padding:0}:host,html{-webkit-text-size-adjust:100%;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);line-height:1.5;tab-size:4;-webkit-tap-highlight-color:transparent}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-size:1em;font-variation-settings:var(--default-mono-font-variation-settings,normal)}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}button,input,optgroup,select,textarea{background-color:#0000;border-radius:0;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex;padding-block:0}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.relative{position:relative}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}} /*! tailwindcss v4.1.16 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components;:host{--hb-select-font-size:14px;--hb-select-height:32px;--hb-select-border-color:var(--hb-border-color,#dcdfe6);--hb-select-border-color-hover:var(--hb-color-primary);--hb-select-bg-color:var(--hb-color-white,#fff);--hb-select-text-color:var(--hb-color-text-regular,#606266);--hb-select-placeholder-color:var(--hb-color-text-placeholder,#c0c4cc);display:inline-block;position:relative}.hb-select{display:inline-block;position:relative;width:240px}.hb-select__input-wrapper{position:relative}.hb-select__input,.hb-select__input-wrapper{cursor:pointer;display:inline-block;width:100%}.hb-select__input{background-color:var(--hb-select-bg-color);border:1px solid var(--hb-select-border-color);border-radius:4px;box-sizing:border-box;color:var(--hb-select-text-color);font-size:var(--hb-select-font-size);height:var(--hb-select-height);line-height:var(--hb-select-height);outline:none;padding:0 30px 0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.hb-select__input::placeholder{color:var(--hb-select-placeholder-color)}.hb-select__input:focus,.hb-select__input:hover:not(:disabled){border-color:var(--hb-select-border-color-hover)}.hb-select__tags{align-items:center;background-color:var(--hb-select-bg-color);border:1px solid var(--hb-select-border-color);border-radius:4px;display:flex;flex-wrap:wrap;min-height:var(--hb-select-height);padding:0 30px 0 5px}.hb-select__tag{align-items:center;background-color:var(--hb-fill-color-light,#f0f2f5);border:1px solid var(--hb-border-color-lighter,#e4e7ed);border-radius:4px;color:var(--hb-color-text-regular,#606266);display:inline-flex;font-size:12px;height:24px;margin:2px 0 2px 6px;padding:0 8px}.hb-select__tag-text{margin-right:4px}.hb-select__tag-close{align-items:center;color:var(--hb-color-text-placeholder,#c0c4cc);cursor:pointer;display:inline-flex;height:12px;justify-content:center;transition:color .2s;width:12px}.hb-select__tag-close svg{height:100%;width:100%}.hb-select__tag-close:hover{color:var(--hb-color-text-regular,#606266)}.hb-select__suffix{align-items:center;color:var(--hb-select-text-color);display:flex;position:absolute;right:8px;top:50%;transform:translateY(-50%)}.hb-select__clear{align-items:center;color:var(--hb-select-placeholder-color);cursor:pointer;display:inline-flex;height:14px;justify-content:center;margin-right:8px;transition:color .2s;width:14px}.hb-select__clear svg{height:100%;width:100%}.hb-select__clear:hover{color:var(--hb-select-text-color)}.hb-select__arrow{align-items:center;color:var(--hb-select-placeholder-color);display:inline-flex;height:12px;justify-content:center;transition:transform .3s;width:12px}.hb-select__arrow svg{height:100%;width:100%}.hb-select--open .hb-select__arrow{transform:rotate(180deg)}.hb-select__dropdown{background-color:var(--hb-select-bg-color);border:1px solid var(--hb-select-border-color);border-radius:4px;box-shadow:0 2px 12px #0000001a;left:0;margin-top:4px;max-height:300px;min-width:100%;overflow-y:auto;position:absolute;top:100%;z-index:1000}.hb-select__menu{list-style:none;margin:0;padding:6px 0}.hb-select__menu-item{align-items:center;color:var(--hb-select-text-color);cursor:pointer;display:flex;font-size:var(--hb-select-font-size);padding:8px 20px;transition:background-color .2s}.hb-select__menu-item:hover:not(.hb-select__menu-item--disabled):not(.hb-select__menu-item--divided){background-color:var(--hb-fill-color-light,#f5f7fa)}.hb-select__menu-item--selected{color:var(--hb-color-primary);font-weight:600}.hb-select__menu-item--disabled{color:var(--hb-color-text-disabled,#c0c4cc);cursor:not-allowed}.hb-select__menu-item--divided{border-top:1px solid var(--hb-border-color-lighter,#e4e7ed);margin-top:6px;padding-top:6px}.hb-select__menu-item--empty{color:var(--hb-select-placeholder-color);cursor:default}.hb-select__menu-item-checkbox{align-items:center;color:var(--hb-color-primary,#1677ff);display:inline-flex;height:14px;justify-content:center;margin-right:8px;width:14px}.hb-select__menu-item-checkbox svg{height:100%;width:100%}.hb-select__menu-item--create{color:var(--hb-color-primary,#1677ff);font-weight:500}.hb-select__menu-item--create:hover{background-color:var(--hb-color-primary-bg,#e6f4ff)}.hb-select__menu-item-label{flex:1}.hb-select--small{font-size:12px}.hb-select--small .hb-select__input{font-size:12px;height:24px;line-height:24px;padding:0 25px 0 12px}.hb-select--large{font-size:16px}.hb-select--large .hb-select__input{font-size:16px;height:40px;line-height:40px;padding:0 35px 0 18px}.hb-select--disabled{cursor:not-allowed}.hb-select--disabled .hb-select__input{background-color:var(--hb-fill-color-light,#f5f7fa);border-color:var(--hb-select-border-color);color:var(--hb-color-text-disabled,#c0c4cc);cursor:not-allowed}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}';const d=c;const p=class{constructor(i){e(this,i);this.hbChange=t(this,"hbChange",7);this.hbVisibleChange=t(this,"hbVisibleChange",7)}get el(){return i(this)}modelValue;options=[];placeholder="请选择";disabled=false;size="default";clearable=false;multiple=false;filterable=false;filterMethod;defaultFirstOption=false;allowCreate=false;collapseTags=false;maxCollapseTags;virtual=false;dropdownMaxHeight=256;virtualItemHeight=34;isOpen=false;inputValue="";searchValue="";filteredOptions=[];activeOptionIndex=-1;dropdownScrollTop=0;handleDropdownScroll=e=>{const t=e.target;this.dropdownScrollTop=t.scrollTop};listboxId=`hb-select-listbox-${Math.random().toString(36).slice(2,11)}`;hbChange;hbVisibleChange;clickOutside=o({host:null,isOpen:()=>this.isOpen,onClose:()=>{this.isOpen=false;this.hbVisibleChange.emit(false)}});componentDidLoad(){this.clickOutside=o({host:this.el,isOpen:()=>this.isOpen,onClose:()=>{this.isOpen=false;this.hbVisibleChange.emit(false)}});this.clickOutside.connect();this.updateInputValue();if(this.filterable){this.filteredOptions=this.options}}disconnectedCallback(){this.clickOutside.disconnect()}handleValueChange(){this.updateInputValue()}handleOptionsChange(){if(this.filterable){this.filteredOptions=this.options}}updateInputValue(){if(!this.modelValue){this.inputValue="";return}if(this.multiple&&Array.isArray(this.modelValue)){const e=this.modelValue.map((e=>{const t=this.options.find((t=>t.value===e));return t?t.label:String(e)}));this.inputValue=e.join(", ")}else{const e=this.options.find((e=>e.value===this.modelValue));this.inputValue=e?e.label:String(this.modelValue)}}handleInputClick=()=>{if(this.disabled)return;this.isOpen=!this.isOpen;if(this.isOpen){this.activeOptionIndex=this.defaultFirstOption?Math.max(-1,this.options.findIndex((e=>!e.disabled))):-1}this.hbVisibleChange.emit(this.isOpen)};handleWrapperKeydown=e=>{if(this.disabled)return;const t=this.filterable?this.filteredOptions:this.options;if(!this.isOpen){if(e.key==="Enter"||e.key===" "||e.key==="Spacebar"||e.key==="ArrowDown"||e.key==="ArrowUp"){e.preventDefault();this.isOpen=true;this.activeOptionIndex=-1;this.hbVisibleChange.emit(true)}return}const i=a(e,{activeIndex:this.activeOptionIndex,itemCount:t.length,loop:true});switch(i.type){case"navigate":e.preventDefault();this.activeOptionIndex=i.index;break;case"select":{e.preventDefault();const s=t[i.index];if(s&&!s.disabled)this.handleSelect(s);break}case"close":e.preventDefault();this.isOpen=false;this.hbVisibleChange.emit(false);break}};handleSelect=e=>{if(e.disabled)return;if(this.multiple){const t=this.modelValue||[];const i=t.indexOf(e.value);if(i>-1){t.splice(i,1)}else{t.push(e.value)}this.modelValue=[...t]}else{this.modelValue=e.value;this.isOpen=false;this.hbVisibleChange.emit(false)}this.updateInputValue();this.hbChange.emit(this.modelValue)};handleClear=e=>{e.stopPropagation();this.modelValue=this.multiple?[]:undefined;this.inputValue="";this.isOpen=false;this.hbChange.emit(this.modelValue);this.hbVisibleChange.emit(false)};handleSearch=e=>{const t=e.target;this.searchValue=t.value;if(this.filterMethod){this.filterMethod(t.value)}else{this.filteredOptions=this.options.filter((e=>e.label.toLowerCase().includes(t.value.toLowerCase())))}};isSelected(e){if(this.multiple&&Array.isArray(this.modelValue)){return this.modelValue.includes(e.value)}return this.modelValue===e.value}get createOption(){if(!this.allowCreate||!this.filterable||!this.isOpen)return null;const e=this.searchValue.trim();if(!e)return null;const t=this.options.some((t=>String(t.label).toLowerCase()===e.toLowerCase()||String(t.value).toLowerCase()===e.toLowerCase()));if(t)return null;return{value:e,label:e}}handleCreate=()=>{const e=this.createOption;if(!e)return;if(this.multiple){const t=(this.modelValue||[]).slice();if(!t.includes(e.value))t.push(e.value);this.modelValue=t}else{this.modelValue=e.value;this.isOpen=false;this.hbVisibleChange.emit(false)}this.searchValue="";this.filteredOptions=this.options;this.updateInputValue();this.hbChange.emit(this.modelValue)};renderOption(e,t){return s("li",{id:`${this.listboxId}-opt-${t}`,class:{"hb-select__menu-item":true,"hb-select__menu-item--selected":this.isSelected(e),"hb-select__menu-item--disabled":e.disabled,"hb-select__menu-item--divided":e.divided,"hb-select__menu-item--active":t===this.activeOptionIndex},style:this.virtual?{height:`${this.virtualItemHeight}px`}:undefined,role:"option","aria-selected":this.isSelected(e)?"true":"false","aria-disabled":e.disabled?"true":undefined,onClick:()=>this.handleSelect(e)},this.multiple&&s("span",{class:"hb-select__menu-item-checkbox","aria-hidden":"true"},this.isSelected(e)?s("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":3,"stroke-linecap":"round","stroke-linejoin":"round"},s("path",{d:"M5 12l5 5L20 7"})):null),s("span",{class:"hb-select__menu-item-label"},e.label))}render(){const e=this.filterable?this.filteredOptions:this.options;const t=this.clearable&&this.modelValue!==undefined&&(this.multiple?this.modelValue.length>0:true);return s("div",{key:"711a2660ec0ff788a027b7097a64f74ee535ae58",class:{"hb-select":true,"hb-select--open":this.isOpen,"hb-select--disabled":this.disabled,[`hb-select--${this.size}`]:true},role:"combobox","aria-haspopup":"listbox","aria-expanded":this.isOpen?"true":"false","aria-controls":this.isOpen?this.listboxId:undefined,"aria-activedescendant":this.isOpen&&this.activeOptionIndex>=0?`${this.listboxId}-opt-${this.activeOptionIndex}`:undefined},s("div",{key:"7719c10931fd36306a7bc302b167c43a782158bd",class:"hb-select__input-wrapper",onClick:this.handleInputClick,onKeyDown:this.handleWrapperKeydown},this.multiple&&Array.isArray(this.modelValue)&&this.modelValue.length>0?s("div",{class:"hb-select__tags"},this.modelValue.slice(0,this.collapseTags&&this.maxCollapseTags?this.maxCollapseTags:undefined).map((e=>{const t=this.options.find((t=>t.value===e));return s("span",{class:"hb-select__tag"},s("span",{class:"hb-select__tag-text"},t?t.label:e),s("span",{class:"hb-select__tag-close",role:"button","aria-label":"移除标签",tabIndex:0,onClick:i=>{i.stopPropagation();this.handleSelect(t||{value:e,label:String(e)})},onKeyDown:r},s("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round","aria-hidden":"true"},s("path",{d:"M6 6l12 12M18 6L6 18"}))))})),this.collapseTags&&this.maxCollapseTags&&this.modelValue.length>this.maxCollapseTags&&s("span",{class:"hb-select__tag"},s("span",{class:"hb-select__tag-text"},"+",this.modelValue.length-this.maxCollapseTags))):s("input",{type:"text",class:"hb-select__input",placeholder:this.placeholder,value:this.filterable&&this.isOpen?this.searchValue:this.inputValue,disabled:this.disabled,readonly:!this.filterable||!this.isOpen,onInput:this.handleSearch,"aria-haspopup":"listbox","aria-expanded":this.isOpen?"true":"false",role:"combobox"}),s("span",{key:"a9dc4ecd508bb6828296cf2a9465ab5c24595573",class:"hb-select__suffix"},t&&s("span",{key:"cde7a95063f12c03844303681a3a95da1f5aaa66",class:"hb-select__clear",role:"button","aria-label":"清空",tabIndex:0,onClick:this.handleClear,onKeyDown:r},s("svg",{key:"a9abef626a4a3da495afffe7e562fb557a26f8e7",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round","aria-hidden":"true"},s("path",{key:"a95c9113f3c7ef741dc9a8111576827571668ecf",d:"M6 6l12 12M18 6L6 18"}))),s("span",{key:"184023640706c01ed18854cb5b1975f9def18dc4",class:"hb-select__arrow","aria-hidden":"true"},s("svg",{key:"14fec9c7d46ad1d22ddf07de502aedabe8b19b18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"},s("path",{key:"d280de7e1545be150238126b65f6c37e499bb83a",d:"M6 9l6 6 6-6"}))))),this.isOpen&&s("div",{key:"e9a10e24e49095535c232ec39be458780789fde4",class:"hb-select__dropdown"},s("ul",{key:"874854750698dcb2346cbd3a965ba0e500b5bafc",class:"hb-select__menu",role:"listbox",id:this.listboxId,style:this.virtual?{maxHeight:`${this.dropdownMaxHeight}px`,overflowY:"auto"}:undefined,onScroll:this.virtual?this.handleDropdownScroll:undefined},this.createOption&&s("li",{key:"5ca5a633a0d69ddb1ba065bb08d947d663b774ac",class:{"hb-select__menu-item":true,"hb-select__menu-item--create":true},role:"option","aria-selected":"false",onClick:this.handleCreate},s("span",{key:"f986194f0456c910bba2447603505edce6cb6e60",class:"hb-select__menu-item-label"},"创建「",this.createOption.label,"」")),e.length===0&&!this.createOption?s("li",{class:"hb-select__menu-item hb-select__menu-item--empty","aria-disabled":"true"},"无数据"):this.virtual?s("div",{style:{height:`${h(e.length,this.virtualItemHeight)}px`,position:"relative"}},s("div",{style:{transform:`translateY(${n(l({total:e.length,itemHeight:this.virtualItemHeight,viewportHeight:this.dropdownMaxHeight,scrollTop:this.dropdownScrollTop}).startIndex,this.virtualItemHeight)}px)`}},e.slice(l({total:e.length,itemHeight:this.virtualItemHeight,viewportHeight:this.dropdownMaxHeight,scrollTop:this.dropdownScrollTop}).startIndex,l({total:e.length,itemHeight:this.virtualItemHeight,viewportHeight:this.dropdownMaxHeight,scrollTop:this.dropdownScrollTop}).endIndex).map(((t,i)=>{const s=l({total:e.length,itemHeight:this.virtualItemHeight,viewportHeight:this.dropdownMaxHeight,scrollTop:this.dropdownScrollTop}).startIndex+i;return this.renderOption(t,s)})))):e.map(((e,t)=>this.renderOption(e,t))))))}static get watchers(){return{modelValue:["handleValueChange"],options:["handleOptionsChange"]}}};p.style=d;export{p as hb_select};
2
+ //# sourceMappingURL=p-f69599fa.entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getVirtualRange","opts","total","viewportHeight","scrollTop","buffer","startIndex","endIndex","itemHeight","Math","floor","ceil","getOffsetTop","h","getTotalHeight","selectCss","HbSelectStyle0","Select","modelValue","options","placeholder","disabled","size","clearable","multiple","filterable","filterMethod","defaultFirstOption","allowCreate","collapseTags","maxCollapseTags","virtual","dropdownMaxHeight","virtualItemHeight","isOpen","inputValue","searchValue","filteredOptions","activeOptionIndex","dropdownScrollTop","handleDropdownScroll","e","target","this","listboxId","random","toString","slice","hbChange","hbVisibleChange","clickOutside","createClickOutsideHandler","host","onClose","emit","componentDidLoad","el","connect","updateInputValue","disconnectedCallback","disconnect","handleValueChange","handleOptionsChange","Array","isArray","labels","map","val","option","find","opt","value","label","String","join","handleInputClick","max","findIndex","o","handleWrapperKeydown","displayOptions","key","preventDefault","action","handleListKeyboard","activeIndex","itemCount","length","loop","type","index","handleSelect","currentValue","indexOf","splice","push","handleClear","stopPropagation","undefined","handleSearch","filter","toLowerCase","includes","isSelected","createOption","q","trim","exists","some","handleCreate","arr","renderOption","id","class","divided","style","height","role","onClick","viewBox","fill","stroke","d","render","showClear","onKeyDown","tabIndex","activationClickHandler","readonly","onInput","maxHeight","overflowY","onScroll","position","transform","i","absIndex"],"sources":["src/utils/virtual-scroll.ts","src/components/Select/select.css?tag=hb-select&encapsulation=shadow","src/components/Select/Select.tsx"],"sourcesContent":["/**\n * 通用虚拟滚动工具(V1,包2)。\n *\n * 从 Table 的虚拟滚动逻辑提取,供 Select/Cascader/Tree/TreeSelect/Menu 复用。\n * 仅渲染「可见窗口 + 上下缓冲」范围的项,而非全量列表——1000+ 选项时 DOM 节点数恒定。\n *\n * 用法(组件内):\n * 1. 维护 scrollTop state(onScroll 回调更新)\n * 2. 调 getVirtualRange({ total, itemHeight, viewportHeight, scrollTop, buffer }) 得 [start, end)\n * 3. 仅渲染 list.slice(start, end),用 getOffsetTop(start, itemHeight) 撑出顶部空白\n */\n\nexport interface VirtualRangeOptions {\n /** 列表总项数 */\n total: number;\n /** 每项高度(px),>0 */\n itemHeight: number;\n /** 视口高度(px) */\n viewportHeight: number;\n /** 当前滚动位置(px) */\n scrollTop: number;\n /** 上下缓冲行数(默认 5) */\n buffer?: number;\n}\n\nexport interface VirtualRange {\n /** 起始索引(含) */\n startIndex: number;\n /** 结束索引(不含) */\n endIndex: number;\n}\n\n/**\n * 计算可见窗口 [startIndex, endIndex)。\n * startIndex 夹到 [0, total),endIndex 夹到 [0, total]。\n */\nexport function getVirtualRange(opts: VirtualRangeOptions): VirtualRange {\n const { total, viewportHeight, scrollTop, buffer = 5 } = opts;\n if (total <= 0) return { startIndex: 0, endIndex: 0 };\n const itemHeight = opts.itemHeight > 0 ? opts.itemHeight : 1;\n\n let startIndex = Math.floor(scrollTop / itemHeight) - buffer;\n if (startIndex < 0) startIndex = 0;\n\n let endIndex = Math.ceil((scrollTop + viewportHeight) / itemHeight) + buffer;\n if (endIndex > total) endIndex = total;\n\n return { startIndex, endIndex };\n}\n\n/** 撑出顶部空白高度(px),用于偏移可见窗口到正确滚动位置。 */\nexport function getOffsetTop(startIndex: number, itemHeight: number): number {\n const h = itemHeight > 0 ? itemHeight : 1;\n return startIndex * h;\n}\n\n/** 容器总高度(px),用于撑出滚动条。 */\nexport function getTotalHeight(total: number, itemHeight: number): number {\n const h = itemHeight > 0 ? itemHeight : 1;\n return total * h;\n}\n",":host {\n display: inline-block;\n position: relative;\n --hb-select-font-size: 14px;\n --hb-select-height: 32px;\n --hb-select-border-color: var(--hb-border-color, #dcdfe6);\n --hb-select-border-color-hover: var(--hb-color-primary);\n --hb-select-bg-color: var(--hb-color-white, #ffffff);\n --hb-select-text-color: var(--hb-color-text-regular, #606266);\n --hb-select-placeholder-color: var(--hb-color-text-placeholder, #c0c4cc);\n}\n\n.hb-select {\n display: inline-block;\n position: relative;\n width: 240px;\n}\n\n.hb-select__input-wrapper {\n position: relative;\n display: inline-block;\n width: 100%;\n cursor: pointer;\n}\n\n.hb-select__input {\n display: inline-block;\n width: 100%;\n height: var(--hb-select-height);\n line-height: var(--hb-select-height);\n padding: 0 30px 0 15px;\n font-size: var(--hb-select-font-size);\n color: var(--hb-select-text-color);\n background-color: var(--hb-select-bg-color);\n border: 1px solid var(--hb-select-border-color);\n border-radius: 4px;\n box-sizing: border-box;\n cursor: pointer;\n outline: none;\n transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\n}\n\n.hb-select__input::placeholder {\n color: var(--hb-select-placeholder-color);\n}\n\n.hb-select__input:hover:not(:disabled) {\n border-color: var(--hb-select-border-color-hover);\n}\n\n.hb-select__input:focus {\n border-color: var(--hb-select-border-color-hover);\n}\n\n.hb-select__tags {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n padding: 0 30px 0 5px;\n min-height: var(--hb-select-height);\n border: 1px solid var(--hb-select-border-color);\n border-radius: 4px;\n background-color: var(--hb-select-bg-color);\n}\n\n.hb-select__tag {\n display: inline-flex;\n align-items: center;\n height: 24px;\n padding: 0 8px;\n margin: 2px 0 2px 6px;\n background-color: var(--hb-fill-color-light, #f0f2f5);\n border: 1px solid var(--hb-border-color-lighter, #e4e7ed);\n border-radius: 4px;\n font-size: 12px;\n color: var(--hb-color-text-regular, #606266);\n}\n\n.hb-select__tag-text {\n margin-right: 4px;\n}\n\n.hb-select__tag-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n cursor: pointer;\n color: var(--hb-color-text-placeholder, #c0c4cc);\n transition: color 0.2s;\n}\n\n.hb-select__tag-close svg {\n width: 100%;\n height: 100%;\n}\n\n.hb-select__tag-close:hover {\n color: var(--hb-color-text-regular, #606266);\n}\n\n.hb-select__suffix {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n color: var(--hb-select-text-color);\n}\n\n.hb-select__clear {\n margin-right: 8px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n cursor: pointer;\n color: var(--hb-select-placeholder-color);\n transition: color 0.2s;\n}\n\n.hb-select__clear svg {\n width: 100%;\n height: 100%;\n}\n\n.hb-select__clear:hover {\n color: var(--hb-select-text-color);\n}\n\n.hb-select__arrow {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n color: var(--hb-select-placeholder-color);\n transition: transform 0.3s;\n}\n\n.hb-select__arrow svg {\n width: 100%;\n height: 100%;\n}\n\n.hb-select--open .hb-select__arrow {\n transform: rotate(180deg);\n}\n\n.hb-select__dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n margin-top: 4px;\n background-color: var(--hb-select-bg-color);\n border: 1px solid var(--hb-select-border-color);\n border-radius: 4px;\n box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);\n z-index: 1000;\n min-width: 100%;\n max-height: 300px;\n overflow-y: auto;\n}\n\n.hb-select__menu {\n margin: 0;\n padding: 6px 0;\n list-style: none;\n}\n\n.hb-select__menu-item {\n display: flex;\n align-items: center;\n padding: 8px 20px;\n font-size: var(--hb-select-font-size);\n color: var(--hb-select-text-color);\n cursor: pointer;\n transition: background-color 0.2s;\n}\n\n.hb-select__menu-item:hover:not(.hb-select__menu-item--disabled):not(.hb-select__menu-item--divided) {\n background-color: var(--hb-fill-color-light, #f5f7fa);\n}\n\n.hb-select__menu-item--selected {\n color: var(--hb-color-primary);\n font-weight: 600;\n}\n\n.hb-select__menu-item--disabled {\n color: var(--hb-color-text-disabled, #c0c4cc);\n cursor: not-allowed;\n}\n\n.hb-select__menu-item--divided {\n border-top: 1px solid var(--hb-border-color-lighter, #e4e7ed);\n margin-top: 6px;\n padding-top: 6px;\n}\n\n.hb-select__menu-item--empty {\n color: var(--hb-select-placeholder-color);\n cursor: default;\n}\n\n.hb-select__menu-item-checkbox {\n margin-right: 8px;\n width: 14px;\n height: 14px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--hb-color-primary, #1677ff);\n}\n\n.hb-select__menu-item-checkbox svg {\n width: 100%;\n height: 100%;\n}\n\n.hb-select__menu-item--create {\n color: var(--hb-color-primary, #1677ff);\n font-weight: 500;\n}\n\n.hb-select__menu-item--create:hover {\n background-color: var(--hb-color-primary-bg, #e6f4ff);\n}\n\n.hb-select__menu-item-label {\n flex: 1;\n}\n\n.hb-select--small {\n font-size: 12px;\n}\n\n.hb-select--small .hb-select__input {\n height: 24px;\n line-height: 24px;\n font-size: 12px;\n padding: 0 25px 0 12px;\n}\n\n.hb-select--large {\n font-size: 16px;\n}\n\n.hb-select--large .hb-select__input {\n height: 40px;\n line-height: 40px;\n font-size: 16px;\n padding: 0 35px 0 18px;\n}\n\n.hb-select--disabled {\n cursor: not-allowed;\n}\n\n.hb-select--disabled .hb-select__input {\n background-color: var(--hb-fill-color-light, #f5f7fa);\n border-color: var(--hb-select-border-color);\n color: var(--hb-color-text-disabled, #c0c4cc);\n cursor: not-allowed;\n}\n","import { Component, h, Prop, Event, EventEmitter, State, Element, Watch } from '@stencil/core';\nimport { createClickOutsideHandler } from '../../utils/click-outside';\nimport { handleListKeyboard, activationClickHandler } from '../../utils/a11y';\nimport { getVirtualRange, getOffsetTop, getTotalHeight } from '../../utils/virtual-scroll';\n\nexport interface SelectOption {\n value: string | number;\n label: string;\n disabled?: boolean;\n divided?: boolean;\n}\n\n/**\n * Select 选择器组件\n * 当选项过多时,使用下拉菜单展示并选择内容\n */\n@Component({\n tag: 'hb-select',\n styleUrl: 'select.css',\n shadow: true,\n})\nexport class Select {\n @Element() el: HTMLElement;\n\n /**\n * 绑定值\n */\n @Prop({ mutable: true }) modelValue?: string | number | (string | number)[];\n\n /**\n * 可选项数据源\n */\n @Prop() options: SelectOption[] = [];\n\n /**\n * 输入框占位文本\n */\n @Prop() placeholder: string = '请选择';\n\n /**\n * 是否禁用\n * @default false\n */\n @Prop() disabled: boolean = false;\n\n /**\n * 输入框尺寸\n */\n @Prop() size: 'large' | 'default' | 'small' = 'default';\n\n /**\n * 是否可清空\n * @default false\n */\n @Prop() clearable: boolean = false;\n\n /**\n * 是否多选\n * @default false\n */\n @Prop() multiple: boolean = false;\n\n /**\n * 是否可搜索\n * @default false\n */\n @Prop() filterable: boolean = false;\n\n /**\n * 自定义过滤方法\n */\n @Prop() filterMethod?: (query: string) => void;\n\n /**\n * 是否默认展开\n * @default false\n */\n @Prop() defaultFirstOption: boolean = false;\n\n /**\n * 是否允许创建新条目\n * @default false\n */\n @Prop() allowCreate: boolean = false;\n\n /**\n * 多选时是否将选中值按文字的形式展示\n * @default false\n */\n @Prop() collapseTags: boolean = false;\n\n /**\n * 多选时最多显示多少个tag\n */\n @Prop() maxCollapseTags?: number;\n\n /**\n * V1:是否开启虚拟滚动(1000+ 选项时推荐)。默认 false。\n * 开启后下拉仅渲染可见窗口内的选项,DOM 节点数恒定。\n */\n @Prop() virtual: boolean = false;\n\n /**\n * V1:下拉最大高度(px)。virtual=true 时必填(定义视口高度)。默认 256。\n */\n @Prop() dropdownMaxHeight: number = 256;\n\n /**\n * V1:虚拟滚动每项预估高度(px)。默认 34。\n */\n @Prop() virtualItemHeight: number = 34;\n\n @State() isOpen: boolean = false;\n @State() inputValue: string = '';\n @State() searchValue: string = '';\n @State() filteredOptions: SelectOption[] = [];\n /** 键盘高亮的选项索引(-1 表示无) */\n @State() activeOptionIndex: number = -1;\n /** V1:下拉滚动位置(px),驱动虚拟滚动可见窗口重算 */\n @State() dropdownScrollTop: number = 0;\n\n /** V1:下拉滚动回调 */\n private handleDropdownScroll = (e: Event) => {\n const target = e.target as HTMLElement;\n this.dropdownScrollTop = target.scrollTop;\n };\n\n /**\n * O4:实例级稳定 id,用于 combobox 的 aria-controls / aria-activedescendant 关联,\n * 让读屏在键盘导航时播报当前高亮项。\n */\n private listboxId = `hb-select-listbox-${Math.random().toString(36).slice(2, 11)}`;\n\n /**\n * 值改变事件\n */\n @Event() hbChange: EventEmitter<string | number | (string | number)[]>;\n\n /**\n * 下拉框出现/隐藏时触发\n */\n @Event() hbVisibleChange: EventEmitter<boolean>;\n\n private clickOutside = createClickOutsideHandler({\n host: null as any,\n isOpen: () => this.isOpen,\n onClose: () => {\n this.isOpen = false;\n this.hbVisibleChange.emit(false);\n },\n });\n\n componentDidLoad() {\n this.clickOutside = createClickOutsideHandler({\n host: this.el,\n isOpen: () => this.isOpen,\n onClose: () => {\n this.isOpen = false;\n this.hbVisibleChange.emit(false);\n },\n });\n this.clickOutside.connect();\n this.updateInputValue();\n if (this.filterable) {\n this.filteredOptions = this.options;\n }\n }\n\n disconnectedCallback() {\n this.clickOutside.disconnect();\n }\n\n @Watch('modelValue')\n handleValueChange() {\n this.updateInputValue();\n }\n\n @Watch('options')\n handleOptionsChange() {\n if (this.filterable) {\n this.filteredOptions = this.options;\n }\n }\n\n private updateInputValue() {\n if (!this.modelValue) {\n this.inputValue = '';\n return;\n }\n\n if (this.multiple && Array.isArray(this.modelValue)) {\n const labels = this.modelValue.map(val => {\n const option = this.options.find(opt => opt.value === val);\n return option ? option.label : String(val);\n });\n this.inputValue = labels.join(', ');\n } else {\n const option = this.options.find(opt => opt.value === this.modelValue);\n this.inputValue = option ? option.label : String(this.modelValue);\n }\n }\n\n private handleInputClick = () => {\n if (this.disabled) return;\n this.isOpen = !this.isOpen;\n if (this.isOpen) {\n // defaultFirstOption=true:打开时自动高亮第一个可选(非禁用)项\n this.activeOptionIndex = this.defaultFirstOption\n ? Math.max(\n -1,\n this.options.findIndex(o => !o.disabled),\n )\n : -1;\n }\n this.hbVisibleChange.emit(this.isOpen);\n };\n\n private handleWrapperKeydown = (e: KeyboardEvent) => {\n if (this.disabled) return;\n const displayOptions = this.filterable ? this.filteredOptions : this.options;\n\n if (!this.isOpen) {\n // 关闭态:Enter / Space / 方向键 展开\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar' || e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n this.isOpen = true;\n this.activeOptionIndex = -1;\n this.hbVisibleChange.emit(true);\n }\n return;\n }\n\n const action = handleListKeyboard(e, {\n activeIndex: this.activeOptionIndex,\n itemCount: displayOptions.length,\n loop: true,\n });\n switch (action.type) {\n case 'navigate':\n e.preventDefault();\n this.activeOptionIndex = action.index;\n break;\n case 'select': {\n e.preventDefault();\n const opt = displayOptions[action.index];\n if (opt && !opt.disabled) this.handleSelect(opt);\n break;\n }\n case 'close':\n e.preventDefault();\n this.isOpen = false;\n this.hbVisibleChange.emit(false);\n break;\n default:\n break;\n }\n };\n\n private handleSelect = (option: SelectOption) => {\n if (option.disabled) return;\n\n if (this.multiple) {\n const currentValue = (this.modelValue as (string | number)[]) || [];\n const index = currentValue.indexOf(option.value);\n\n if (index > -1) {\n currentValue.splice(index, 1);\n } else {\n currentValue.push(option.value);\n }\n\n this.modelValue = [...currentValue];\n } else {\n this.modelValue = option.value;\n this.isOpen = false;\n this.hbVisibleChange.emit(false);\n }\n\n this.updateInputValue();\n this.hbChange.emit(this.modelValue);\n };\n\n private handleClear = (e: Event) => {\n e.stopPropagation();\n this.modelValue = this.multiple ? [] : undefined;\n this.inputValue = '';\n this.isOpen = false;\n this.hbChange.emit(this.modelValue);\n this.hbVisibleChange.emit(false);\n };\n\n private handleSearch = (e: Event) => {\n const target = e.target as HTMLInputElement;\n this.searchValue = target.value;\n\n if (this.filterMethod) {\n this.filterMethod(target.value);\n } else {\n this.filteredOptions = this.options.filter(opt => opt.label.toLowerCase().includes(target.value.toLowerCase()));\n }\n };\n\n private isSelected(option: SelectOption): boolean {\n if (this.multiple && Array.isArray(this.modelValue)) {\n return this.modelValue.includes(option.value);\n }\n return this.modelValue === option.value;\n }\n\n /**\n * allowCreate + filterable:当用户输入的文本在已有选项中不存在时,\n * 渲染一个\"创建 xxx\"项。返回待创建的文本(已 trim);无需创建返回 null。\n */\n private get createOption(): SelectOption | null {\n if (!this.allowCreate || !this.filterable || !this.isOpen) return null;\n const q = this.searchValue.trim();\n if (!q) return null;\n const exists = this.options.some(o => String(o.label).toLowerCase() === q.toLowerCase() || String(o.value).toLowerCase() === q.toLowerCase());\n if (exists) return null;\n return { value: q, label: q };\n }\n\n private handleCreate = () => {\n const opt = this.createOption;\n if (!opt) return;\n if (this.multiple) {\n const arr = ((this.modelValue as (string | number)[]) || []).slice();\n if (!arr.includes(opt.value)) arr.push(opt.value);\n this.modelValue = arr;\n } else {\n this.modelValue = opt.value;\n this.isOpen = false;\n this.hbVisibleChange.emit(false);\n }\n this.searchValue = '';\n this.filteredOptions = this.options;\n this.updateInputValue();\n this.hbChange.emit(this.modelValue);\n };\n\n /** 渲染单个选项 <li>(普通 + 虚拟滚动共用,V1 提取) */\n private renderOption(option: SelectOption, index: number) {\n return (\n <li\n id={`${this.listboxId}-opt-${index}`}\n class={{\n 'hb-select__menu-item': true,\n 'hb-select__menu-item--selected': this.isSelected(option),\n 'hb-select__menu-item--disabled': option.disabled,\n 'hb-select__menu-item--divided': option.divided,\n 'hb-select__menu-item--active': index === this.activeOptionIndex,\n }}\n style={this.virtual ? { height: `${this.virtualItemHeight}px` } : undefined}\n role=\"option\"\n aria-selected={this.isSelected(option) ? 'true' : 'false'}\n aria-disabled={option.disabled ? 'true' : undefined}\n onClick={() => this.handleSelect(option)}\n >\n {this.multiple && (\n <span class=\"hb-select__menu-item-checkbox\" aria-hidden=\"true\">\n {this.isSelected(option) ? (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width={3} stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M5 12l5 5L20 7\" />\n </svg>\n ) : null}\n </span>\n )}\n <span class=\"hb-select__menu-item-label\">{option.label}</span>\n </li>\n );\n }\n\n render() {\n const displayOptions = this.filterable ? this.filteredOptions : this.options;\n const showClear = this.clearable && this.modelValue !== undefined && (this.multiple ? (this.modelValue as any[]).length > 0 : true);\n\n return (\n <div\n class={{\n 'hb-select': true,\n 'hb-select--open': this.isOpen,\n 'hb-select--disabled': this.disabled,\n [`hb-select--${this.size}`]: true,\n }}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={this.isOpen ? 'true' : 'false'}\n aria-controls={this.isOpen ? this.listboxId : undefined}\n aria-activedescendant={this.isOpen && this.activeOptionIndex >= 0 ? `${this.listboxId}-opt-${this.activeOptionIndex}` : undefined}\n >\n <div class=\"hb-select__input-wrapper\" onClick={this.handleInputClick} onKeyDown={this.handleWrapperKeydown}>\n {this.multiple && Array.isArray(this.modelValue) && this.modelValue.length > 0 ? (\n <div class=\"hb-select__tags\">\n {this.modelValue.slice(0, this.collapseTags && this.maxCollapseTags ? this.maxCollapseTags : undefined).map(val => {\n const option = this.options.find(opt => opt.value === val);\n return (\n <span class=\"hb-select__tag\">\n <span class=\"hb-select__tag-text\">{option ? option.label : val}</span>\n <span\n class=\"hb-select__tag-close\"\n role=\"button\"\n aria-label=\"移除标签\"\n tabIndex={0}\n onClick={e => {\n e.stopPropagation();\n this.handleSelect(option || { value: val, label: String(val) });\n }}\n onKeyDown={activationClickHandler}\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width={2} stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 6l12 12M18 6L6 18\" />\n </svg>\n </span>\n </span>\n );\n })}\n {this.collapseTags && this.maxCollapseTags && this.modelValue.length > this.maxCollapseTags && (\n <span class=\"hb-select__tag\">\n <span class=\"hb-select__tag-text\">+{this.modelValue.length - this.maxCollapseTags}</span>\n </span>\n )}\n </div>\n ) : (\n <input\n type=\"text\"\n class=\"hb-select__input\"\n placeholder={this.placeholder}\n value={this.filterable && this.isOpen ? this.searchValue : this.inputValue}\n disabled={this.disabled}\n readonly={!this.filterable || !this.isOpen}\n onInput={this.handleSearch}\n aria-haspopup=\"listbox\"\n aria-expanded={this.isOpen ? 'true' : 'false'}\n role=\"combobox\"\n />\n )}\n <span class=\"hb-select__suffix\">\n {showClear && (\n <span class=\"hb-select__clear\" role=\"button\" aria-label=\"清空\" tabIndex={0} onClick={this.handleClear} onKeyDown={activationClickHandler}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width={2} stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 6l12 12M18 6L6 18\" />\n </svg>\n </span>\n )}\n <span class=\"hb-select__arrow\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width={2} stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </span>\n </span>\n </div>\n {this.isOpen && (\n <div class=\"hb-select__dropdown\">\n <ul\n class=\"hb-select__menu\"\n role=\"listbox\"\n id={this.listboxId}\n // V1:虚拟滚动时滚动容器限高 + onScroll 更新可见窗口\n style={this.virtual ? { maxHeight: `${this.dropdownMaxHeight}px`, overflowY: 'auto' } : undefined}\n onScroll={this.virtual ? this.handleDropdownScroll : undefined}\n >\n {/* allowCreate:用户输入文本不存在时,渲染创建项(置顶) */}\n {this.createOption && (\n <li class={{ 'hb-select__menu-item': true, 'hb-select__menu-item--create': true }} role=\"option\" aria-selected=\"false\" onClick={this.handleCreate}>\n <span class=\"hb-select__menu-item-label\">创建「{this.createOption.label}」</span>\n </li>\n )}\n {displayOptions.length === 0 && !this.createOption ? (\n <li class=\"hb-select__menu-item hb-select__menu-item--empty\" aria-disabled=\"true\">\n 无数据\n </li>\n ) : this.virtual ? (\n // V1:虚拟滚动——仅渲染可见窗口 + 顶部撑高 spacer\n <div style={{ height: `${getTotalHeight(displayOptions.length, this.virtualItemHeight)}px`, position: 'relative' }}>\n <div style={{ transform: `translateY(${getOffsetTop(getVirtualRange({ total: displayOptions.length, itemHeight: this.virtualItemHeight, viewportHeight: this.dropdownMaxHeight, scrollTop: this.dropdownScrollTop }).startIndex, this.virtualItemHeight)}px)` }}>\n {displayOptions\n .slice(\n getVirtualRange({ total: displayOptions.length, itemHeight: this.virtualItemHeight, viewportHeight: this.dropdownMaxHeight, scrollTop: this.dropdownScrollTop }).startIndex,\n getVirtualRange({ total: displayOptions.length, itemHeight: this.virtualItemHeight, viewportHeight: this.dropdownMaxHeight, scrollTop: this.dropdownScrollTop }).endIndex,\n )\n .map((option, i) => {\n const absIndex = getVirtualRange({ total: displayOptions.length, itemHeight: this.virtualItemHeight, viewportHeight: this.dropdownMaxHeight, scrollTop: this.dropdownScrollTop }).startIndex + i;\n return this.renderOption(option, absIndex);\n })}\n </div>\n </div>\n ) : (\n displayOptions.map((option, index) => this.renderOption(option, index))\n )}\n </ul>\n </div>\n )}\n </div>\n );\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -24,16 +24,73 @@ export declare class Form {
24
24
  size: 'large' | 'default' | 'small';
25
25
  /** 是否禁用 */
26
26
  disabled: boolean;
27
+ /**
28
+ * F1:初始值(非受控)。挂载后把这些值写到对应字段的子控件 modelValue。
29
+ * key = FormItem 的 prop。
30
+ */
31
+ initialValues?: Record<string, any>;
32
+ /**
33
+ * F4:校验提示模板。覆盖默认的「{label}不能为空」「{label}格式不正确」等文案。
34
+ * 支持 {label} 占位符。仅对未在 rule.message 显式指定消息的规则生效。
35
+ */
36
+ validateMessages?: {
37
+ required?: string;
38
+ pattern?: string;
39
+ email?: string;
40
+ min?: string;
41
+ max?: string;
42
+ };
43
+ /**
44
+ * F2:提交且校验通过后的回调。参数为各字段当前值组成的对象。
45
+ * 由表单 submit(form onSubmit)触发——表单内放 type="submit" 的按钮即可。
46
+ */
47
+ onFinish?: (values: Record<string, any>) => void;
48
+ /**
49
+ * F2:提交且校验失败后的回调。
50
+ */
51
+ onFinishFailed?: (errors: {
52
+ prop: string;
53
+ errors: string[];
54
+ }[]) => void;
55
+ /**
56
+ * F3:任意字段值变化时的回调。参数为 { prop, value, values }。
57
+ * 由子控件冒泡的 hbChange 触发。
58
+ */
59
+ onValuesChange?: (info: {
60
+ prop: string;
61
+ value: any;
62
+ values: Record<string, any>;
63
+ }) => void;
27
64
  fields: FormFieldRegistration[];
28
65
  private fieldRegistry;
29
66
  private handleFieldRegister;
67
+ /**
68
+ * F3:监听子控件冒泡的 hbChange,识别来源 FormItem 并触发 onValuesChange。
69
+ * 注:hbChange 由 hb-input/hb-select 等控件发出(composed 冒泡穿过 shadow),
70
+ * 这里在 host 上捕获,通过 closest('hb-form-item') 定位字段 prop。
71
+ */
72
+ private handleFieldChange;
30
73
  componentWillLoad(): void;
74
+ componentDidLoad(): void;
31
75
  disconnectedCallback(): void;
76
+ /**
77
+ * 收集所有字段的当前值(getFieldsValue)。
78
+ */
79
+ private getFieldsValue;
80
+ /**
81
+ * 设置某字段子控件的值(setFieldValue)。
82
+ * 子控件统一用 modelValue 受控。
83
+ */
84
+ private setFieldValue;
32
85
  /**
33
86
  * 验证整个表单
34
87
  * @returns 是否验证通过
35
88
  */
36
89
  validate: () => Promise<boolean>;
90
+ /**
91
+ * F2:提交表单——校验全部字段,通过则 onFinish(values),失败则 onFinishFailed(errors)。
92
+ */
93
+ private handleSubmit;
37
94
  /**
38
95
  * 重置表单
39
96
  */
@@ -16,6 +16,18 @@ export declare class FormItem {
16
16
  rules: any[];
17
17
  /** 表单尺寸 */
18
18
  size: 'large' | 'default' | 'small';
19
+ /**
20
+ * F6:手动校验态('success' | 'warning' | 'error' | 'validating' | '')。
21
+ * 设置后覆盖内部校验结果驱动的错误显示(对齐 antd validateStatus)。
22
+ */
23
+ validateStatus?: '' | 'success' | 'warning' | 'error' | 'validating';
24
+ /** F6:手动错误/帮助文案(配合 validateStatus='error' 显示自定义提示) */
25
+ help?: string;
26
+ /**
27
+ * F7:标签栅格占比(1-24)。未设置时用 labelWidth。
28
+ * 对齐 antd labelCol(简化为纯数字栅格,labelCol.span)。
29
+ */
30
+ labelCol?: number;
19
31
  errors: string[];
20
32
  isvalidating: boolean;
21
33
  /** hb-form 在 componentWillLoad 注册的事件监听;FormItem 在 componentDidLoad 派发,
@@ -30,11 +42,22 @@ export declare class FormItem {
30
42
  private get isRequired();
31
43
  /** 继承父 hb-form 的 labelPosition(FormItem 自身无此 prop,避免与 Form 冲突时以 Form 为准) */
32
44
  private get resolvedLabelPosition();
45
+ /**
46
+ * F4:继承父 hb-form 的 validateMessages(校验提示模板)。
47
+ * 支持占位符 {label}。仅对 rule 未显式指定 message 的规则生效。
48
+ */
49
+ private get resolvedValidateMessages();
50
+ /** 用模板生成错误文案({label} 替换为字段标签),优先级:rule.message > 模板 > 内置默认 */
51
+ private msg;
33
52
  /**
34
53
  * 验证此字段
35
54
  */
36
55
  validate: () => Promise<string[]>;
37
56
  resetValue: () => void;
38
57
  getValue: () => any;
58
+ /** F6:实际显示的错误文案。手动 help 优先;否则取内部 errors[0] */
59
+ private get displayError();
60
+ /** F6:实际是否显示错误(手动 validateStatus='error' 或内部有错) */
61
+ private get showError();
39
62
  render(): any;
40
63
  }
@@ -70,12 +70,29 @@ export declare class Select {
70
70
  * 多选时最多显示多少个tag
71
71
  */
72
72
  maxCollapseTags?: number;
73
+ /**
74
+ * V1:是否开启虚拟滚动(1000+ 选项时推荐)。默认 false。
75
+ * 开启后下拉仅渲染可见窗口内的选项,DOM 节点数恒定。
76
+ */
77
+ virtual: boolean;
78
+ /**
79
+ * V1:下拉最大高度(px)。virtual=true 时必填(定义视口高度)。默认 256。
80
+ */
81
+ dropdownMaxHeight: number;
82
+ /**
83
+ * V1:虚拟滚动每项预估高度(px)。默认 34。
84
+ */
85
+ virtualItemHeight: number;
73
86
  isOpen: boolean;
74
87
  inputValue: string;
75
88
  searchValue: string;
76
89
  filteredOptions: SelectOption[];
77
90
  /** 键盘高亮的选项索引(-1 表示无) */
78
91
  activeOptionIndex: number;
92
+ /** V1:下拉滚动位置(px),驱动虚拟滚动可见窗口重算 */
93
+ dropdownScrollTop: number;
94
+ /** V1:下拉滚动回调 */
95
+ private handleDropdownScroll;
79
96
  /**
80
97
  * O4:实例级稳定 id,用于 combobox 的 aria-controls / aria-activedescendant 关联,
81
98
  * 让读屏在键盘导航时播报当前高亮项。
@@ -107,5 +124,7 @@ export declare class Select {
107
124
  */
108
125
  private get createOption();
109
126
  private handleCreate;
127
+ /** 渲染单个选项 <li>(普通 + 虚拟滚动共用,V1 提取) */
128
+ private renderOption;
110
129
  render(): any;
111
130
  }
@@ -8,16 +8,33 @@ export interface TableColumn {
8
8
  width?: string;
9
9
  /** 最小列宽 */
10
10
  minWidth?: string;
11
- /** 是否可排序 */
11
+ /** 是否可排序(true=按字段值排序) */
12
12
  sortable?: boolean;
13
+ /** 排序函数(接收两行,返回数字)。优先级高于 sortable,启用自定义排序(T2) */
14
+ sorter?: (a: Record<string, any>, b: Record<string, any>) => number;
15
+ /** 受控排序方向(设置后 Table 不再内部切换该列,由外部控制,T2) */
16
+ sortOrder?: SortDirection;
13
17
  /** 对齐方式 */
14
18
  align?: 'left' | 'center' | 'right';
15
19
  /** 固定列:left / right / true(等同 left) */
16
20
  fixed?: 'left' | 'right' | boolean;
17
21
  /** 单元格文本格式化(框架无关,返回纯文本字符串) */
18
22
  formatter?: (row: Record<string, any>, index: number) => string;
23
+ /** 自定义单元格渲染(返回字符串或内联 JSX,T7)。优先级高于 formatter */
24
+ render?: (row: Record<string, any>, index: number) => any;
19
25
  /** 该列是否可(行内)编辑;需同时开启 Table.editable 才生效 */
20
26
  editable?: boolean;
27
+ /** 筛选项(非空时表头显示筛选下拉;与 onFilter 配合,T3) */
28
+ filters?: {
29
+ label: string;
30
+ value: string | number;
31
+ }[];
32
+ /** 受控筛选值(设置后由外部控制,T3) */
33
+ filteredValue?: (string | number)[];
34
+ /** 筛选函数 (row, filterValue) => boolean(T3) */
35
+ onFilter?: (row: Record<string, any>, filterValue: string | number) => boolean;
36
+ /** 超出省略号 */
37
+ ellipsis?: boolean;
21
38
  }
22
39
  /**
23
40
  * 行操作按钮配置(框架无关)。
@@ -35,6 +52,24 @@ export interface TableAction {
35
52
  disabled?: (row: Record<string, any>, index: number) => boolean;
36
53
  }
37
54
  export type SortDirection = 'ascending' | 'descending' | null;
55
+ /**
56
+ * 内置分页配置(T1)。传入 pagination 对象即启用内置分页,
57
+ * Table 自动切片 data 并在底部渲染 <hb-pagination>。
58
+ */
59
+ export interface TablePagination {
60
+ /** 当前页(从 1 开始,受控) */
61
+ current?: number;
62
+ /** 默认当前页(非受控) */
63
+ defaultCurrent?: number;
64
+ /** 每页条数(受控) */
65
+ pageSize?: number;
66
+ /** 默认每页条数(非受控,默认 10) */
67
+ defaultPageSize?: number;
68
+ /** 可选每页条数 */
69
+ pageSizes?: number[];
70
+ /** 是否显示总数 */
71
+ showTotal?: boolean;
72
+ }
38
73
  /**
39
74
  * 树形数据配置。
40
75
  * `children` 指定子节点在每行数据中的字段名(默认 'children'),
@@ -86,6 +121,13 @@ export declare class Table {
86
121
  treeProps?: TableTreeProps;
87
122
  /** 是否开启行内编辑模式(默认关闭)。需列配置 column.editable=true 才对该列生效 */
88
123
  editable: boolean;
124
+ /**
125
+ * 内置分页配置(T1)。传入后 Table 自动对 data 切片并在底部渲染 <hb-pagination>。
126
+ * 不传则不分页(向后兼容)。
127
+ */
128
+ pagination?: TablePagination;
129
+ /** 行 className(函数,按行返回附加 class,T8) */
130
+ rowClassName?: (row: Record<string, any>, index: number) => string;
89
131
  sortProp: string;
90
132
  sortDirection: SortDirection;
91
133
  currentRow: number;
@@ -99,6 +141,12 @@ export declare class Table {
99
141
  rowKey: string | number;
100
142
  prop: string;
101
143
  } | null;
144
+ /** T1 分页:内部当前页(非受控时用) */
145
+ internalPage: number;
146
+ /** T1 分页:内部每页条数(非受控时用) */
147
+ internalPageSize: number;
148
+ /** T3 筛选:内部筛选状态 { prop: 选中的 value 列表 }(非受控时用) */
149
+ internalFilters: Record<string, (string | number)[]>;
102
150
  /** 排序变化事件 */
103
151
  hbSortChange: EventEmitter<{
104
152
  prop: string;
@@ -128,16 +176,24 @@ export declare class Table {
128
176
  prop: string;
129
177
  value: any;
130
178
  }>;
179
+ /** T1 分页变化事件 { current, pageSize } */
180
+ hbPageChange: EventEmitter<{
181
+ current: number;
182
+ pageSize: number;
183
+ }>;
184
+ /** T3 筛选变化事件 { prop, values } */
185
+ hbFilterChange: EventEmitter<{
186
+ prop: string;
187
+ values: (string | number)[];
188
+ }>;
131
189
  handleDataChange(): void;
190
+ handlePaginationChange(): void;
132
191
  /** 树形模式是否启用(显式传入 treeProps 即启用) */
133
192
  private get isTreeMode();
134
193
  /** 子节点字段名(treeProps.children 缺省回退 'children') */
135
194
  private get childrenField();
136
195
  /**
137
196
  * 把树拍平成可见行列表:仅保留「祖先链路全部已展开」的后代。
138
- * @param list 当前层级的数组
139
- * @param level 当前层级(根 = 0)
140
- * @param parentKeyPath 父级 key 路径,用于构造深层稳定 key(避免不同分支同 index 撞 key)
141
197
  */
142
198
  private flattenTree;
143
199
  /** 树形展开/收起切换 */
@@ -158,8 +214,39 @@ export declare class Table {
158
214
  private get visibleRange();
159
215
  /** 虚拟滚动:撑高容器总高度 */
160
216
  private get virtualTotalHeight();
217
+ /**
218
+ * T2:解析某列的有效排序方向。
219
+ * 受控(col.sortOrder 设置)→ 用该值;否则用内部 state(sortProp/sortDirection)。
220
+ */
221
+ private effectiveSortOrder;
161
222
  private handleSort;
223
+ /**
224
+ * T2 增强的排序数据:支持 col.sorter 自定义排序函数 + 受控 sortOrder。
225
+ * 多列排序不支持(与 antd 行为一致,取首个有效排序列)。
226
+ */
162
227
  private get sortedData();
228
+ /**
229
+ * T3 筛选:应用所有列的 onFilter。
230
+ * 受控(col.filteredValue 已定义)→ 用该值;否则用内部 internalFilters[prop]。
231
+ */
232
+ private get filteredData();
233
+ /**
234
+ * T1 分页:取当前页数据切片(仅当 pagination 配置时)。
235
+ * 在 sorted+filtered 之后切片。
236
+ */
237
+ private get pagedData();
238
+ /** T1:当前页(受控优先) */
239
+ private get currentPage();
240
+ /** T1:当前每页条数(受控优先) */
241
+ private get currentPageSize();
242
+ /** T1:分页切换 */
243
+ private handlePageChange;
244
+ /** T1:每页条数切换 */
245
+ private handlePageSizeChange;
246
+ /** T3:筛选下拉切换某项 */
247
+ private handleFilterToggle;
248
+ /** T3:清空某列筛选 */
249
+ private handleFilterReset;
163
250
  private get isAllSelected();
164
251
  private get isIndeterminate();
165
252
  private toggleRow;
@@ -168,23 +255,31 @@ export declare class Table {
168
255
  private handleRowClick;
169
256
  private handleAction;
170
257
  private get hasActions();
258
+ /** T3:某列是否有激活筛选 */
259
+ private isColumnFiltered;
171
260
  /**
172
261
  * 计算固定列的 sticky 偏移(左侧/右侧累计宽度)。
173
262
  * P1 优化:缓存结果,仅当 columns 引用变化时重算。
174
- * 修复前是 getter,被每个 <td>/<th> 反复调用,复杂度 O(rows×cols²)。
175
263
  */
176
264
  private _fixedOffsetsCache;
177
265
  private _fixedOffsetsColumnsRef;
178
266
  private getFixedOffsets;
179
267
  private cellStyle;
268
+ /**
269
+ * 渲染单元格内容(T7:优先 col.render,其次 formatter,最后原值)。
270
+ */
271
+ private renderCell;
180
272
  /**
181
273
  * 渲染单行(普通 + 虚拟滚动 + 树形 共用)。
182
- * - 普通模式:rowIndex 为在 sortedData 中的全局索引。
183
- * - 树形模式:fr.level 决定缩进,第一列渲染展开箭头,key 取 fr.key。
184
- * fr 为可选;未传时按普通模式渲染。
185
274
  */
186
275
  private renderRow;
276
+ /**
277
+ * T3:渲染表头某列的筛选下拉。
278
+ */
279
+ private renderColumnFilter;
187
280
  /** 渲染表头(普通 + 虚拟滚动共用,表头始终固定不随滚) */
188
281
  private renderHeader;
282
+ /** T1:渲染内置分页底部栏 */
283
+ private renderPagination;
189
284
  render(): any;
190
285
  }