@lobehub/ui 5.62.1 → 5.63.1

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 (56) hide show
  1. package/es/ThemeProvider/GlobalStyle/essential.mjs +12 -0
  2. package/es/ThemeProvider/GlobalStyle/essential.mjs.map +1 -1
  3. package/es/base-ui/Input/style.d.mts +1 -1
  4. package/es/base-ui/Pagination/Pagination.mjs +20 -3
  5. package/es/base-ui/Pagination/Pagination.mjs.map +1 -1
  6. package/es/base-ui/Pagination/style.mjs +47 -3
  7. package/es/base-ui/Pagination/style.mjs.map +1 -1
  8. package/es/base-ui/ProTable/FieldControl.mjs +10 -3
  9. package/es/base-ui/ProTable/FieldControl.mjs.map +1 -1
  10. package/es/base-ui/ProTable/LightFilter.mjs +6 -3
  11. package/es/base-ui/ProTable/LightFilter.mjs.map +1 -1
  12. package/es/base-ui/ProTable/ProTable.d.mts +4 -5
  13. package/es/base-ui/ProTable/ProTable.mjs +38 -31
  14. package/es/base-ui/ProTable/ProTable.mjs.map +1 -1
  15. package/es/base-ui/ProTable/SearchForm.mjs +59 -6
  16. package/es/base-ui/ProTable/SearchForm.mjs.map +1 -1
  17. package/es/base-ui/ProTable/index.d.mts +3 -2
  18. package/es/base-ui/ProTable/index.mjs +3 -1
  19. package/es/base-ui/ProTable/locale.d.mts +18 -0
  20. package/es/base-ui/ProTable/locale.mjs +68 -0
  21. package/es/base-ui/ProTable/locale.mjs.map +1 -0
  22. package/es/base-ui/ProTable/style.mjs +38 -0
  23. package/es/base-ui/ProTable/style.mjs.map +1 -1
  24. package/es/base-ui/ProTable/type.d.mts +66 -10
  25. package/es/base-ui/ProTable/useColumnRequest.mjs +61 -0
  26. package/es/base-ui/ProTable/useColumnRequest.mjs.map +1 -0
  27. package/es/base-ui/ProTable/useFetchData.mjs.map +1 -1
  28. package/es/base-ui/Select/Select.mjs +3 -1
  29. package/es/base-ui/Select/Select.mjs.map +1 -1
  30. package/es/base-ui/Select/hooks.mjs +8 -4
  31. package/es/base-ui/Select/hooks.mjs.map +1 -1
  32. package/es/base-ui/Select/type.d.mts +7 -0
  33. package/es/base-ui/Table/Table.mjs +3 -1
  34. package/es/base-ui/Table/Table.mjs.map +1 -1
  35. package/es/base-ui/Table/style.mjs +173 -28
  36. package/es/base-ui/Table/style.mjs.map +1 -1
  37. package/es/base-ui/Text/style.d.mts +1 -1
  38. package/es/dashboard/ConsoleNav/style.mjs +2 -2
  39. package/es/dashboard/ConsoleNav/style.mjs.map +1 -1
  40. package/es/dashboard/FilterSidebar/style.mjs +2 -2
  41. package/es/dashboard/FilterSidebar/style.mjs.map +1 -1
  42. package/es/dashboard/FilterStrip/style.mjs +1 -1
  43. package/es/dashboard/FilterStrip/style.mjs.map +1 -1
  44. package/es/dashboard/MetricStrip/style.mjs +1 -1
  45. package/es/dashboard/MetricStrip/style.mjs.map +1 -1
  46. package/es/dashboard/PageSkeleton/style.mjs +2 -1
  47. package/es/dashboard/PageSkeleton/style.mjs.map +1 -1
  48. package/es/dashboard/Surface/Surface.mjs +1 -2
  49. package/es/dashboard/Surface/Surface.mjs.map +1 -1
  50. package/es/dashboard/Surface/link.d.mts +1 -1
  51. package/es/dashboard/Surface/link.mjs +1 -1
  52. package/es/dashboard/Surface/link.mjs.map +1 -1
  53. package/es/dashboard/Surface/style.d.mts +14 -8
  54. package/es/dashboard/Surface/style.mjs +25 -20
  55. package/es/dashboard/Surface/style.mjs.map +1 -1
  56. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/base-ui/ProTable/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const PRO_PREFIX_CLS = 'lobe-pro-table';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n alert: css`\n display: flex;\n gap: 12px;\n align-items: center;\n justify-content: space-between;\n\n min-height: 40px;\n margin-block-end: 12px;\n padding-block: 6px;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadius};\n\n font-size: ${cssVar.fontSize};\n color: ${cssVar.colorText};\n\n background: color-mix(in srgb, ${cssVar.colorPrimary} 8%, transparent);\n `,\n alertInfo: css`\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 12px;\n align-items: center;\n\n min-width: 0;\n `,\n alertOption: css`\n display: flex;\n flex: none;\n gap: 8px;\n align-items: center;\n `,\n part: css`\n min-width: 0;\n `,\n partBordered: css`\n padding: 16px;\n border: 1px solid ${cssVar.colorBorderSecondary};\n border-radius: ${cssVar.borderRadiusLG};\n `,\n code: css`\n padding-block: 1px;\n padding-inline: 6px;\n border-radius: ${cssVar.borderRadiusSM};\n\n font-family: ${cssVar.fontFamilyCode};\n font-size: 0.9em;\n\n background: ${cssVar.colorFillTertiary};\n `,\n copyable: css`\n display: inline-flex;\n gap: 4px;\n align-items: center;\n max-width: 100%;\n `,\n copyableText: css`\n overflow: hidden;\n min-width: 0;\n text-overflow: ellipsis;\n `,\n density: css`\n display: flex;\n flex-direction: column;\n min-width: 140px;\n padding: 4px;\n `,\n densityItem: css`\n cursor: pointer;\n\n display: flex;\n gap: 8px;\n align-items: center;\n justify-content: space-between;\n\n height: 32px;\n padding-inline: 8px;\n border: none;\n border-radius: ${cssVar.borderRadiusSM};\n\n font: inherit;\n color: ${cssVar.colorText};\n text-align: start;\n\n background: transparent;\n\n &:hover,\n &:focus-visible {\n background: ${cssVar.colorFillTertiary};\n outline: none;\n }\n\n &[aria-checked='true'] {\n font-weight: 500;\n }\n `,\n enumList: css`\n display: inline-flex;\n flex-wrap: wrap;\n gap: 8px;\n `,\n indexBorder: css`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n min-width: 18px;\n height: 18px;\n padding-inline: 4px;\n border-radius: 9px;\n\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n color: ${cssVar.colorText};\n\n background: ${cssVar.colorFillSecondary};\n\n &[data-top] {\n color: ${cssVar.colorTextLightSolid};\n background: ${cssVar.colorPrimary};\n }\n `,\n lightFilter: css`\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n `,\n lightFilterItem: css`\n display: inline-flex;\n flex: none;\n align-items: center;\n width: 160px;\n\n & > * {\n width: 100%;\n }\n `,\n lightFilterLabel: css`\n font-size: ${cssVar.fontSizeSM};\n color: ${cssVar.colorTextSecondary};\n white-space: nowrap;\n `,\n optionCell: css`\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n justify-content: flex-end;\n `,\n root: css`\n --lobe-pro-table-status-default: ${cssVar.colorTextQuaternary};\n --lobe-pro-table-status-error: ${cssVar.colorError};\n --lobe-pro-table-status-processing: ${cssVar.colorPrimary};\n --lobe-pro-table-status-success: ${cssVar.colorSuccess};\n --lobe-pro-table-status-warning: ${cssVar.colorWarning};\n\n display: flex;\n flex-direction: column;\n gap: 16px;\n min-width: 0;\n\n &[data-fullscreen] {\n overflow: auto;\n padding: 16px;\n background: ${cssVar.colorBgLayout};\n }\n `,\n search: css`\n display: grid;\n gap: 16px 24px;\n align-items: center;\n `,\n searchActions: css`\n display: flex;\n grid-column-end: -1;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n justify-content: flex-end;\n `,\n searchField: css`\n min-width: 0;\n\n /* The base-ui Form.Field row: no list padding, fixed-width label column, full-width control. */\n & > div {\n gap: 8px;\n padding-block: 0;\n }\n\n & > div > label {\n overflow: hidden;\n flex: none;\n\n width: var(--lobe-pro-table-label-width, auto);\n\n color: ${cssVar.colorTextSecondary};\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &[data-layout='horizontal'] > div > label {\n text-align: end;\n }\n\n & > div > div {\n flex: 1;\n align-items: stretch;\n min-width: 0;\n }\n `,\n searchFieldControl: css`\n flex: 1;\n min-width: 0;\n `,\n searchLabel: css`\n overflow: hidden;\n flex: none;\n\n color: ${cssVar.colorTextSecondary};\n text-align: end;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &[data-layout='vertical'] {\n text-align: start;\n }\n `,\n setting: css`\n display: flex;\n flex-direction: column;\n\n width: 260px;\n max-height: 420px;\n padding-block: 4px;\n `,\n settingGroupTitle: css`\n padding-block: 6px 2px;\n padding-inline: 12px;\n font-size: ${cssVar.fontSizeSM};\n color: ${cssVar.colorTextDescription};\n `,\n settingHeader: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding-block: 4px 8px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorSplit};\n `,\n settingItem: css`\n display: flex;\n gap: 4px;\n align-items: center;\n\n min-height: 32px;\n padding-inline: 12px 8px;\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n\n &:hover [data-setting-actions] {\n opacity: 1;\n }\n `,\n settingItemActions: css`\n display: flex;\n flex: none;\n gap: 2px;\n opacity: 0;\n\n &:focus-within {\n opacity: 1;\n }\n `,\n settingItemTitle: css`\n overflow: hidden;\n flex: 1;\n\n min-width: 0;\n\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n settingList: css`\n overflow: auto;\n flex: 1;\n padding-block: 4px;\n `,\n status: css`\n display: inline-flex;\n gap: 8px;\n align-items: center;\n `,\n statusDot: css`\n flex: none;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n `,\n statusProcessing: css`\n @keyframes lobe-pro-table-status-pulse {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, currentcolor 40%, transparent);\n }\n\n 100% {\n box-shadow: 0 0 0 4px transparent;\n }\n }\n\n color: ${cssVar.colorPrimary};\n animation: lobe-pro-table-status-pulse 1.2s ease-out infinite;\n `,\n title: css`\n display: flex;\n flex: none;\n gap: 4px;\n align-items: center;\n\n min-width: 0;\n\n font-size: ${cssVar.fontSizeLG};\n font-weight: 600;\n color: ${cssVar.colorText};\n `,\n titleSub: css`\n font-size: ${cssVar.fontSize};\n font-weight: normal;\n color: ${cssVar.colorTextDescription};\n `,\n titleTooltip: css`\n display: inline-flex;\n gap: 4px;\n align-items: center;\n `,\n toolbar: css`\n display: flex;\n flex-wrap: nowrap;\n gap: 12px;\n align-items: center;\n justify-content: space-between;\n\n margin-block-end: 16px;\n `,\n toolbarActions: css`\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n justify-content: flex-end;\n\n min-width: 0;\n margin-inline-start: auto;\n `,\n toolbarOptions: css`\n display: flex;\n flex: none;\n gap: 2px;\n align-items: center;\n `,\n}));\n"],"mappings":";;AAEA,MAAa,iBAAiB;AAE9B,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,OAAO,GAAG;;;;;;;;;;qBAUS,OAAO,aAAa;;iBAExB,OAAO,SAAS;aACpB,OAAO,UAAU;;qCAEO,OAAO,aAAa;;CAEvD,WAAW,GAAG;;;;;;;;;CASd,aAAa,GAAG;;;;;;CAMhB,MAAM,GAAG;;;CAGT,cAAc,GAAG;;wBAEK,OAAO,qBAAqB;qBAC/B,OAAO,eAAe;;CAEzC,MAAM,GAAG;;;qBAGU,OAAO,eAAe;;mBAExB,OAAO,eAAe;;;kBAGvB,OAAO,kBAAkB;;CAEzC,UAAU,GAAG;;;;;;CAMb,cAAc,GAAG;;;;;CAKjB,SAAS,GAAG;;;;;;CAMZ,aAAa,GAAG;;;;;;;;;;;qBAWG,OAAO,eAAe;;;aAG9B,OAAO,UAAU;;;;;;;oBAOV,OAAO,kBAAkB;;;;;;;;CAQ3C,UAAU,GAAG;;;;;CAKb,aAAa,GAAG;;;;;;;;;;;;aAYL,OAAO,UAAU;;kBAEZ,OAAO,mBAAmB;;;eAG7B,OAAO,oBAAoB;oBACtB,OAAO,aAAa;;;CAGtC,aAAa,GAAG;;;;;;CAMhB,iBAAiB,GAAG;;;;;;;;;;CAUpB,kBAAkB,GAAG;iBACN,OAAO,WAAW;aACtB,OAAO,mBAAmB;;;CAGrC,YAAY,GAAG;;;;;;;CAOf,MAAM,GAAG;uCAC4B,OAAO,oBAAoB;qCAC7B,OAAO,WAAW;0CACb,OAAO,aAAa;uCACvB,OAAO,aAAa;uCACpB,OAAO,aAAa;;;;;;;;;;oBAUvC,OAAO,cAAc;;;CAGvC,QAAQ,GAAG;;;;;CAKX,eAAe,GAAG;;;;;;;;CAQlB,aAAa,GAAG;;;;;;;;;;;;;;;eAeH,OAAO,mBAAmB;;;;;;;;;;;;;;;CAevC,oBAAoB,GAAG;;;;CAIvB,aAAa,GAAG;;;;aAIL,OAAO,mBAAmB;;;;;;;;;CASrC,SAAS,GAAG;;;;;;;;CAQZ,mBAAmB,GAAG;;;iBAGP,OAAO,WAAW;aACtB,OAAO,qBAAqB;;CAEvC,eAAe,GAAG;;;;;;;kCAOc,OAAO,WAAW;;CAElD,aAAa,GAAG;;;;;;;;;oBASE,OAAO,kBAAkB;;;;;;;CAO3C,oBAAoB,GAAG;;;;;;;;;;CAUvB,kBAAkB,GAAG;;;;;;;;;CASrB,aAAa,GAAG;;;;;CAKhB,QAAQ,GAAG;;;;;CAKX,WAAW,GAAG;;;;;;CAMd,kBAAkB,GAAG;;;;;;;;;;;aAWV,OAAO,aAAa;;;CAG/B,OAAO,GAAG;;;;;;;;iBAQK,OAAO,WAAW;;aAEtB,OAAO,UAAU;;CAE5B,UAAU,GAAG;iBACE,OAAO,SAAS;;aAEpB,OAAO,qBAAqB;;CAEvC,cAAc,GAAG;;;;;CAKjB,SAAS,GAAG;;;;;;;;;CASZ,gBAAgB,GAAG;;;;;;;;;;;CAWnB,gBAAgB,GAAG;;;;;;AAMrB,EAAE"}
1
+ {"version":3,"file":"style.mjs","names":[],"sources":["../../../src/base-ui/ProTable/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nexport const PRO_PREFIX_CLS = 'lobe-pro-table';\n\nexport const styles = createStaticStyles(({ css, cssVar }) => ({\n alert: css`\n display: flex;\n gap: 12px;\n align-items: center;\n justify-content: space-between;\n\n min-height: 40px;\n margin-block-end: 12px;\n padding-block: 6px;\n padding-inline: 12px;\n border-radius: ${cssVar.borderRadius};\n\n font-size: ${cssVar.fontSize};\n color: ${cssVar.colorText};\n\n background: color-mix(in srgb, ${cssVar.colorPrimary} 8%, transparent);\n `,\n alertInfo: css`\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 12px;\n align-items: center;\n\n min-width: 0;\n `,\n alertOption: css`\n display: flex;\n flex: none;\n gap: 8px;\n align-items: center;\n `,\n part: css`\n min-width: 0;\n `,\n partBordered: css`\n padding: 16px;\n border: 1px solid ${cssVar.colorBorderSecondary};\n border-radius: ${cssVar.borderRadiusLG};\n `,\n code: css`\n padding-block: 1px;\n padding-inline: 6px;\n border-radius: ${cssVar.borderRadiusSM};\n\n font-family: ${cssVar.fontFamilyCode};\n font-size: 0.9em;\n\n background: ${cssVar.colorFillTertiary};\n `,\n copyable: css`\n display: inline-flex;\n gap: 4px;\n align-items: center;\n max-width: 100%;\n `,\n copyableText: css`\n overflow: hidden;\n min-width: 0;\n text-overflow: ellipsis;\n `,\n density: css`\n display: flex;\n flex-direction: column;\n min-width: 140px;\n padding: 4px;\n `,\n densityItem: css`\n cursor: pointer;\n\n display: flex;\n gap: 8px;\n align-items: center;\n justify-content: space-between;\n\n height: 32px;\n padding-inline: 8px;\n border: none;\n border-radius: ${cssVar.borderRadiusSM};\n\n font: inherit;\n color: ${cssVar.colorText};\n text-align: start;\n\n background: transparent;\n\n &:hover,\n &:focus-visible {\n background: ${cssVar.colorFillTertiary};\n outline: none;\n }\n\n &[aria-checked='true'] {\n font-weight: 500;\n }\n `,\n enumList: css`\n display: inline-flex;\n flex-wrap: wrap;\n gap: 8px;\n `,\n indexBorder: css`\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n min-width: 18px;\n height: 18px;\n padding-inline: 4px;\n border-radius: 9px;\n\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n color: ${cssVar.colorText};\n\n background: ${cssVar.colorFillSecondary};\n\n &[data-top] {\n color: ${cssVar.colorTextLightSolid};\n background: ${cssVar.colorPrimary};\n }\n `,\n lightFilter: css`\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n `,\n lightFilterItem: css`\n display: inline-flex;\n flex: none;\n align-items: center;\n width: 160px;\n\n & > * {\n width: 100%;\n }\n `,\n lightFilterLabel: css`\n font-size: ${cssVar.fontSizeSM};\n color: ${cssVar.colorTextSecondary};\n white-space: nowrap;\n `,\n optionCell: css`\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n align-items: center;\n justify-content: flex-end;\n `,\n root: css`\n --lobe-pro-table-status-default: ${cssVar.colorTextQuaternary};\n --lobe-pro-table-status-error: ${cssVar.colorError};\n --lobe-pro-table-status-processing: ${cssVar.colorPrimary};\n --lobe-pro-table-status-success: ${cssVar.colorSuccess};\n --lobe-pro-table-status-warning: ${cssVar.colorWarning};\n\n display: flex;\n flex-direction: column;\n gap: 16px;\n min-width: 0;\n\n /* Query form → toolbar / table: 24px (16px gap + 8px), parts below keep 16px. */\n & > :has(> [data-pro-table-search]) {\n margin-block-end: 8px;\n }\n\n &[data-fullscreen] {\n overflow: auto;\n padding: 16px;\n background: ${cssVar.colorBgLayout};\n }\n `,\n search: css`\n display: grid;\n gap: 16px 24px;\n align-items: center;\n `,\n searchActions: css`\n display: flex;\n grid-column-end: -1;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n justify-content: flex-end;\n\n /* Vertical: buttons sit on the control line of the last row (Pro adds a blank label). */\n &[data-layout='vertical'] {\n align-self: end;\n }\n `,\n /* Ellipsis lives on the element that holds the text (Form wraps labels in flex boxes). */\n searchLabelText: css`\n overflow: hidden;\n display: block;\n\n min-width: 0;\n max-width: 100%;\n\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n searchField: css`\n min-width: 0;\n\n /* The base-ui Form.Field row: no list padding, fixed-width label column, full-width control. */\n & > div {\n gap: 8px;\n padding-block: 0;\n }\n\n & > div > label {\n overflow: hidden;\n flex: none;\n\n width: var(--lobe-pro-table-label-width, auto);\n\n color: ${cssVar.colorTextSecondary};\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &[data-layout='horizontal'] > div > label {\n text-align: end;\n }\n\n /* A long label never leaves the form: a block label clips and ellipsizes at the END of\n the text (text-align only moves short labels; it never shifts overflow to the start). */\n && > div > label {\n min-width: 0;\n max-width: 100%;\n }\n\n && > div > label * {\n min-width: 0;\n max-width: 100%;\n }\n\n /* Vertical (Pro QueryFilter vertical): label on its own line, full-width control. */\n &[data-layout='vertical'] > div > label {\n width: 100%;\n text-align: start;\n }\n\n & > div > div {\n flex: 1;\n align-items: stretch;\n min-width: 0;\n }\n `,\n searchFieldControl: css`\n flex: 1;\n min-width: 0;\n `,\n searchLabel: css`\n overflow: hidden;\n flex: none;\n\n color: ${cssVar.colorTextSecondary};\n text-align: end;\n text-overflow: ellipsis;\n white-space: nowrap;\n\n &[data-layout='vertical'] {\n text-align: start;\n }\n `,\n setting: css`\n display: flex;\n flex-direction: column;\n\n width: 260px;\n max-height: 420px;\n padding-block: 4px;\n `,\n settingGroupTitle: css`\n padding-block: 6px 2px;\n padding-inline: 12px;\n font-size: ${cssVar.fontSizeSM};\n color: ${cssVar.colorTextDescription};\n `,\n settingHeader: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n\n padding-block: 4px 8px;\n padding-inline: 12px;\n border-block-end: 1px solid ${cssVar.colorSplit};\n `,\n settingItem: css`\n display: flex;\n gap: 4px;\n align-items: center;\n\n min-height: 32px;\n padding-inline: 12px 8px;\n\n &:hover {\n background: ${cssVar.colorFillTertiary};\n }\n\n &:hover [data-setting-actions] {\n opacity: 1;\n }\n `,\n settingItemActions: css`\n display: flex;\n flex: none;\n gap: 2px;\n opacity: 0;\n\n &:focus-within {\n opacity: 1;\n }\n `,\n settingItemTitle: css`\n overflow: hidden;\n flex: 1;\n\n min-width: 0;\n\n text-overflow: ellipsis;\n white-space: nowrap;\n `,\n settingList: css`\n overflow: auto;\n flex: 1;\n padding-block: 4px;\n `,\n status: css`\n display: inline-flex;\n gap: 8px;\n align-items: center;\n `,\n statusDot: css`\n flex: none;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n `,\n statusProcessing: css`\n @keyframes lobe-pro-table-status-pulse {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, currentcolor 40%, transparent);\n }\n\n 100% {\n box-shadow: 0 0 0 4px transparent;\n }\n }\n\n color: ${cssVar.colorPrimary};\n animation: lobe-pro-table-status-pulse 1.2s ease-out infinite;\n `,\n title: css`\n display: flex;\n flex: none;\n gap: 4px;\n align-items: center;\n\n min-width: 0;\n\n font-size: ${cssVar.fontSizeLG};\n font-weight: 600;\n color: ${cssVar.colorText};\n `,\n titleSub: css`\n font-size: ${cssVar.fontSize};\n font-weight: normal;\n color: ${cssVar.colorTextDescription};\n `,\n titleTooltip: css`\n display: inline-flex;\n gap: 4px;\n align-items: center;\n `,\n toolbar: css`\n display: flex;\n flex-wrap: nowrap;\n gap: 12px;\n align-items: center;\n justify-content: space-between;\n\n margin-block-end: 16px;\n `,\n toolbarActions: css`\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 8px;\n align-items: center;\n justify-content: flex-end;\n\n min-width: 0;\n margin-inline-start: auto;\n `,\n toolbarOptions: css`\n display: flex;\n flex: none;\n gap: 2px;\n align-items: center;\n `,\n}));\n"],"mappings":";;AAEA,MAAa,iBAAiB;AAE9B,MAAa,SAAS,oBAAoB,EAAE,KAAK,cAAc;CAC7D,OAAO,GAAG;;;;;;;;;;qBAUS,OAAO,aAAa;;iBAExB,OAAO,SAAS;aACpB,OAAO,UAAU;;qCAEO,OAAO,aAAa;;CAEvD,WAAW,GAAG;;;;;;;;;CASd,aAAa,GAAG;;;;;;CAMhB,MAAM,GAAG;;;CAGT,cAAc,GAAG;;wBAEK,OAAO,qBAAqB;qBAC/B,OAAO,eAAe;;CAEzC,MAAM,GAAG;;;qBAGU,OAAO,eAAe;;mBAExB,OAAO,eAAe;;;kBAGvB,OAAO,kBAAkB;;CAEzC,UAAU,GAAG;;;;;;CAMb,cAAc,GAAG;;;;;CAKjB,SAAS,GAAG;;;;;;CAMZ,aAAa,GAAG;;;;;;;;;;;qBAWG,OAAO,eAAe;;;aAG9B,OAAO,UAAU;;;;;;;oBAOV,OAAO,kBAAkB;;;;;;;;CAQ3C,UAAU,GAAG;;;;;CAKb,aAAa,GAAG;;;;;;;;;;;;aAYL,OAAO,UAAU;;kBAEZ,OAAO,mBAAmB;;;eAG7B,OAAO,oBAAoB;oBACtB,OAAO,aAAa;;;CAGtC,aAAa,GAAG;;;;;;CAMhB,iBAAiB,GAAG;;;;;;;;;;CAUpB,kBAAkB,GAAG;iBACN,OAAO,WAAW;aACtB,OAAO,mBAAmB;;;CAGrC,YAAY,GAAG;;;;;;;CAOf,MAAM,GAAG;uCAC4B,OAAO,oBAAoB;qCAC7B,OAAO,WAAW;0CACb,OAAO,aAAa;uCACvB,OAAO,aAAa;uCACpB,OAAO,aAAa;;;;;;;;;;;;;;;oBAevC,OAAO,cAAc;;;CAGvC,QAAQ,GAAG;;;;;CAKX,eAAe,GAAG;;;;;;;;;;;;;CAclB,iBAAiB,GAAG;;;;;;;;;;CAUpB,aAAa,GAAG;;;;;;;;;;;;;;;eAeH,OAAO,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCvC,oBAAoB,GAAG;;;;CAIvB,aAAa,GAAG;;;;aAIL,OAAO,mBAAmB;;;;;;;;;CASrC,SAAS,GAAG;;;;;;;;CAQZ,mBAAmB,GAAG;;;iBAGP,OAAO,WAAW;aACtB,OAAO,qBAAqB;;CAEvC,eAAe,GAAG;;;;;;;kCAOc,OAAO,WAAW;;CAElD,aAAa,GAAG;;;;;;;;;oBASE,OAAO,kBAAkB;;;;;;;CAO3C,oBAAoB,GAAG;;;;;;;;;;CAUvB,kBAAkB,GAAG;;;;;;;;;CASrB,aAAa,GAAG;;;;;CAKhB,QAAQ,GAAG;;;;;CAKX,WAAW,GAAG;;;;;;CAMd,kBAAkB,GAAG;;;;;;;;;;;aAWV,OAAO,aAAa;;;CAG/B,OAAO,GAAG;;;;;;;;iBAQK,OAAO,WAAW;;aAEtB,OAAO,UAAU;;CAE5B,UAAU,GAAG;iBACE,OAAO,SAAS;;aAEpB,OAAO,qBAAqB;;CAEvC,cAAc,GAAG;;;;;CAKjB,SAAS,GAAG;;;;;;;;;CASZ,gBAAgB,GAAG;;;;;;;;;;;CAWnB,gBAAgB,GAAG;;;;;;AAMrB,EAAE"}
@@ -1,5 +1,5 @@
1
1
  import { FormInstance, FormValues, UseFormOptions } from "../FormKit/type.mjs";
2
- import { SortOrder, TableColumnFilterItem, TableColumnType, TablePaginationConfig, TableProps, TableRowSelection, TableSize, TableVariant } from "../Table/type.mjs";
2
+ import { SortOrder, TableColumnFilterItem, TableColumnType, TableLoadingConfig, TablePaginationConfig, TableProps, TableRowSelection, TableSize, TableVariant } from "../Table/type.mjs";
3
3
  import "../FormKit/index.mjs";
4
4
  import { CSSProperties, Key, MutableRefObject, ReactNode, Ref } from "react";
5
5
  //#region src/base-ui/ProTable/type.d.ts
@@ -70,6 +70,21 @@ interface ProTableActionType {
70
70
  reset: () => void;
71
71
  setPageInfo: (pageInfo: Partial<ProTablePageInfo>) => void;
72
72
  }
73
+ /** An option returned by a column `request`. */
74
+ interface ProTableRequestOption {
75
+ [key: string]: any;
76
+ disabled?: boolean;
77
+ label: ReactNode;
78
+ value: string | number | boolean;
79
+ }
80
+ /**
81
+ * Column `request`: loads the options of a select-like search field. Receives the column
82
+ * `params` and, during remote search, the typed `keyWords`.
83
+ */
84
+ type ProColumnRequest = (params: {
85
+ [key: string]: any;
86
+ keyWords?: string;
87
+ }) => Promise<ProTableRequestOption[]>;
73
88
  interface ProTableSchemaConfig<T> {
74
89
  /** Current form handle; lets `renderFormItem` read sibling fields. */
75
90
  form: ProTableFormInstance;
@@ -85,6 +100,8 @@ interface ProColumnType<T = any> extends Omit<TableColumnType<T>, 'filters' | 'o
85
100
  colSize?: number;
86
101
  /** Show a copy button after the cell text. */
87
102
  copyable?: boolean;
103
+ /** Debounce of the column `request` (on `params` change and remote search) in ms. @default 10 */
104
+ debounceTime?: number;
88
105
  /** Column-setting checkbox disabled (the column can't be hidden). */
89
106
  disable?: boolean | {
90
107
  checkbox: boolean;
@@ -113,6 +130,8 @@ interface ProColumnType<T = any> extends Omit<TableColumnType<T>, 'filters' | 'o
113
130
  onFilter?: boolean | TableColumnType<T>['onFilter'];
114
131
  /** Order in the search form (larger first). */
115
132
  order?: number;
133
+ /** Extra params of the column `request`; a change (deep compare) re-requests. */
134
+ params?: Record<string, any>;
116
135
  /**
117
136
  * `render(dom, record, index, action, schema)`; `dom` is the value-type rendering. With
118
137
  * `valueType: 'option'` return an array of action nodes.
@@ -122,6 +141,12 @@ interface ProColumnType<T = any> extends Omit<TableColumnType<T>, 'filters' | 'o
122
141
  renderFormItem?: (schema: ProColumnType<T>, config: ProTableSchemaConfig<T>, form: ProTableFormInstance) => ReactNode;
123
142
  /** Transform the raw cell value before the value-type rendering. */
124
143
  renderText?: (text: any, record: T, index: number, action: ProTableActionType | undefined) => any;
144
+ /**
145
+ * Load the search field's options asynchronously (select-like field, replaces `valueEnum` /
146
+ * `fieldProps.options` once loaded). With `fieldProps: { showSearch: true, filterOption: false }`
147
+ * typing re-requests with `keyWords`.
148
+ */
149
+ request?: ProColumnRequest;
125
150
  /** `false` hides the column in the search form; `{ transform }` reshapes the submitted value. */
126
151
  search?: boolean | {
127
152
  transform: ProTableSearchTransform;
@@ -156,11 +181,28 @@ interface ProTableRequestData<T> {
156
181
  success?: boolean;
157
182
  total?: number;
158
183
  }
159
- type ProTableRequest<T, Params> = (params: Params & {
184
+ /** `sort` argument of `request`: column key → order (ProComponents shape). */
185
+ type ProTableRequestSort = Record<string, SortOrder>;
186
+ /** `filter` argument of `request`: column key → selected filter values (ProComponents shape). */
187
+ type ProTableRequestFilter = Record<string, (string | number)[] | null>;
188
+ /** `request(params, sort, filter)`; resolves `{ data, total, success }` (all optional). */
189
+ type ProTableRequest<T, Params = Record<string, any>> = (params: Params & {
190
+ [key: string]: any;
160
191
  current?: number;
161
192
  keyword?: string;
162
193
  pageSize?: number;
163
- }, sort: Record<string, SortOrder>, filter: Record<string, (string | number | boolean)[] | null>) => Promise<Partial<ProTableRequestData<T>>>;
194
+ }, sort: ProTableRequestSort, filter: ProTableRequestFilter) => Promise<Partial<ProTableRequestData<T>>>;
195
+ /**
196
+ * `loading` as an object: Spin options of the table overlay (`tip`, `variant`, …) plus `delay`
197
+ * (ms before the overlay shows). Without `spinning` the overlay follows the `request` state.
198
+ */
199
+ type ProTableLoadingConfig = TableLoadingConfig & {
200
+ delay?: number;
201
+ };
202
+ /** Breakpoints of a responsive `search.span`, measured on the query form width. */
203
+ type ProTableSpanBreakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
204
+ /** `search.span` per form width: `xs` < 576 ≤ `sm` < 768 ≤ `md` < 992 ≤ `lg` < 1200 ≤ `xl` < 1600 ≤ `xxl`. */
205
+ type ProTableSpanConfig = Partial<Record<ProTableSpanBreakpoint, number>>;
164
206
  type ProTableDensity = 'large' | 'medium' | 'small';
165
207
  interface ProTableOptionConfig {
166
208
  density?: boolean;
@@ -203,8 +245,11 @@ interface ProTableSearchConfig {
203
245
  }, dom: ReactNode[]) => ReactNode[]);
204
246
  resetText?: ReactNode;
205
247
  searchText?: ReactNode;
206
- /** Span of each field in a 24-column grid (`8` = 3 per row). Responsive to the width by default. */
207
- span?: number;
248
+ /**
249
+ * Span of each field in a 24-column grid (`8` = 3 per row), or one per form-width breakpoint
250
+ * (`{ xs: 24, md: 12, xl: 8 }`). Responsive to the width by default.
251
+ */
252
+ span?: number | ProTableSpanConfig;
208
253
  submitText?: ReactNode;
209
254
  }
210
255
  interface ProTableAlertRenderProps<T> {
@@ -249,7 +294,7 @@ interface ProTableLocale {
249
294
  selectPlaceholder?: string;
250
295
  unfixedTitle?: ReactNode;
251
296
  }
252
- interface ProTableProps<T = any, Params = Record<string, any>> extends Omit<TableProps<T>, 'columns' | 'dataSource' | 'pagination' | 'rowSelection' | 'size' | 'title' | 'loading' | 'ref'> {
297
+ interface ProTableProps<T = any, Params = Record<string, any>> extends Omit<TableProps<T>, 'columns' | 'dataSource' | 'pagination' | 'rowSelection' | 'size' | 'title' | 'loading' | 'locale' | 'ref'> {
253
298
  actionRef?: MutableRefObject<ProTableActionType | undefined> | Ref<ProTableActionType>;
254
299
  /** Hook to reshape the form values before they become `params`. */
255
300
  beforeSearchSubmit?: (params: Record<string, any>) => Record<string, any>;
@@ -271,9 +316,14 @@ interface ProTableProps<T = any, Params = Record<string, any>> extends Omit<Tabl
271
316
  defaultData?: T[];
272
317
  /** @default 'medium' */
273
318
  defaultSize?: ProTableDensity;
274
- /** Initial values of the search form. */
319
+ /** Search form config (ProComponents `form`, base-ui Form underneath). */
275
320
  form?: {
321
+ /** Skip every column validation rule (`formItemProps.rules` / `required`). */
322
+ ignoreRules?: boolean;
323
+ /** Initial values of the search form. */
276
324
  initialValues?: Record<string, any>;
325
+ /** Field layout of the query form; `search.layout` wins. */
326
+ layout?: 'horizontal' | 'vertical';
277
327
  onValuesChange?: (changed: any, all: any) => void;
278
328
  /** base-ui Form `validateOn`. @default 'auto' */
279
329
  validateOn?: ValidateOn;
@@ -282,8 +332,14 @@ interface ProTableProps<T = any, Params = Record<string, any>> extends Omit<Tabl
282
332
  /** Kept for ProComponents compatibility; the parts have no card background to remove. */
283
333
  ghost?: boolean;
284
334
  headerTitle?: ReactNode;
285
- loading?: boolean;
286
- locale?: TableProps<T>['locale'] & ProTableLocale;
335
+ /** Controlled loading; an object configures the overlay (`delay`, `tip`, …), see `ProTableLoadingConfig`. */
336
+ loading?: boolean | ProTableLoadingConfig;
337
+ /**
338
+ * ProTable texts plus the base-ui Table locale. Table's `collapse` / `expand` (row expand
339
+ * labels) are replaced by ProTable's search-form toggle texts, so the keys never conflict.
340
+ * Defaults to the preset of ConfigProvider `locale` (zh* → zh-CN, otherwise en-US).
341
+ */
342
+ locale?: Omit<NonNullable<TableProps<T>['locale']>, keyof ProTableLocale> & ProTableLocale;
287
343
  /** Don't fetch on mount; call `actionRef.current.reload()` (or submit the form). */
288
344
  manualRequest?: boolean;
289
345
  onDataSourceChange?: (dataSource: T[]) => void;
@@ -339,5 +395,5 @@ interface ProTableProps<T = any, Params = Record<string, any>> extends Omit<Tabl
339
395
  variant?: TableVariant;
340
396
  }
341
397
  //#endregion
342
- export { ProColumnType, ProColumns, ProTableActionType, ProTableAlertRender, ProTableAlertRenderProps, ProTableColumnsState, ProTableColumnsStateItem, ProTableColumnsStateMap, ProTableDensity, ProTableFormInstance, ProTableFormRule, ProTableLocale, ProTableOptionConfig, ProTablePageInfo, ProTableProps, ProTableRequest, ProTableRequestData, ProTableSchemaConfig, ProTableSearchConfig, ProTableSearchTransform, ProTableStatus, ProTableToolbarConfig, ProTableValueEnum, ProTableValueEnumItem, ProTableValueType, type SortOrder };
398
+ export { ProColumnRequest, ProColumnType, ProColumns, ProTableActionType, ProTableAlertRender, ProTableAlertRenderProps, ProTableColumnsState, ProTableColumnsStateItem, ProTableColumnsStateMap, ProTableDensity, ProTableFormInstance, ProTableFormRule, ProTableLoadingConfig, ProTableLocale, ProTableOptionConfig, ProTablePageInfo, ProTableProps, ProTableRequest, ProTableRequestData, ProTableRequestFilter, ProTableRequestOption, ProTableRequestSort, ProTableSchemaConfig, ProTableSearchConfig, ProTableSearchTransform, ProTableSpanBreakpoint, ProTableSpanConfig, ProTableStatus, ProTableToolbarConfig, ProTableValueEnum, ProTableValueEnumItem, ProTableValueType, type SortOrder };
343
399
  //# sourceMappingURL=type.d.mts.map
@@ -0,0 +1,61 @@
1
+ import { useEffect, useMemo, useRef, useState } from "react";
2
+ //#region src/base-ui/ProTable/useColumnRequest.ts
3
+ const stable = (value) => {
4
+ try {
5
+ return JSON.stringify(value) ?? "";
6
+ } catch {
7
+ return "";
8
+ }
9
+ };
10
+ /**
11
+ * Column-level `request` (ProComponents semantics): loads the options of a select-like search
12
+ * field. `request({ keyWords, ...params })` runs on mount, whenever `params` changes and, while
13
+ * remote search is on (`fieldProps.showSearch` with `fieldProps.filterOption === false`), on
14
+ * typing, debounced by `debounceTime` (default 10ms). Stale responses are dropped.
15
+ */
16
+ const useColumnRequest = (column) => {
17
+ const { debounceTime = 10, params, request } = column;
18
+ const [options, setOptions] = useState(void 0);
19
+ const [loading, setLoading] = useState(false);
20
+ const [keyWords, setKeyWords] = useState(void 0);
21
+ const requestRef = useRef(request);
22
+ requestRef.current = request;
23
+ const idRef = useRef(0);
24
+ const paramsKey = useMemo(() => stable(params), [params]);
25
+ const enabled = !!request;
26
+ useEffect(() => {
27
+ if (!enabled) return;
28
+ const id = ++idRef.current;
29
+ const timer = setTimeout(() => {
30
+ const run = requestRef.current;
31
+ if (!run) return;
32
+ setLoading(true);
33
+ Promise.resolve(run({
34
+ ...params,
35
+ keyWords
36
+ })).then((list) => {
37
+ if (id === idRef.current) setOptions(Array.isArray(list) ? list : []);
38
+ }).catch(() => {
39
+ if (id === idRef.current) setOptions([]);
40
+ }).finally(() => {
41
+ if (id === idRef.current) setLoading(false);
42
+ });
43
+ }, Math.max(0, debounceTime));
44
+ return () => clearTimeout(timer);
45
+ }, [
46
+ enabled,
47
+ paramsKey,
48
+ keyWords,
49
+ debounceTime
50
+ ]);
51
+ return {
52
+ enabled,
53
+ loading,
54
+ onSearch: enabled && !!column.fieldProps?.showSearch && column.fieldProps?.filterOption === false ? (value) => setKeyWords(value || void 0) : void 0,
55
+ options
56
+ };
57
+ };
58
+ //#endregion
59
+ export { useColumnRequest };
60
+
61
+ //# sourceMappingURL=useColumnRequest.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useColumnRequest.mjs","names":[],"sources":["../../../src/base-ui/ProTable/useColumnRequest.ts"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { ProColumnType, ProTableRequestOption } from './type';\n\nconst stable = (value: unknown) => {\n try {\n return JSON.stringify(value) ?? '';\n } catch {\n return '';\n }\n};\n\n/**\n * Column-level `request` (ProComponents semantics): loads the options of a select-like search\n * field. `request({ keyWords, ...params })` runs on mount, whenever `params` changes and, while\n * remote search is on (`fieldProps.showSearch` with `fieldProps.filterOption === false`), on\n * typing, debounced by `debounceTime` (default 10ms). Stale responses are dropped.\n */\nexport const useColumnRequest = (column: ProColumnType<any>) => {\n const { debounceTime = 10, params, request } = column;\n const [options, setOptions] = useState<ProTableRequestOption[] | undefined>(undefined);\n const [loading, setLoading] = useState(false);\n const [keyWords, setKeyWords] = useState<string | undefined>(undefined);\n const requestRef = useRef(request);\n requestRef.current = request;\n const idRef = useRef(0);\n const paramsKey = useMemo(() => stable(params), [params]);\n const enabled = !!request;\n\n useEffect(() => {\n if (!enabled) return;\n const id = ++idRef.current;\n const timer = setTimeout(\n () => {\n const run = requestRef.current;\n if (!run) return;\n setLoading(true);\n Promise.resolve(run({ ...params, keyWords }))\n .then((list) => {\n if (id === idRef.current) setOptions(Array.isArray(list) ? list : []);\n })\n .catch(() => {\n if (id === idRef.current) setOptions([]);\n })\n .finally(() => {\n if (id === idRef.current) setLoading(false);\n });\n },\n // The first load is not debounced beyond the configured time; typing reuses it.\n Math.max(0, debounceTime),\n );\n return () => clearTimeout(timer);\n // `params` is tracked through its serialized key.\n }, [enabled, paramsKey, keyWords, debounceTime]);\n\n const remoteSearch =\n enabled && !!column.fieldProps?.showSearch && column.fieldProps?.filterOption === false;\n\n return {\n enabled,\n loading,\n onSearch: remoteSearch ? (value: string) => setKeyWords(value || undefined) : undefined,\n options,\n };\n};\n"],"mappings":";;AAIA,MAAM,UAAU,UAAmB;CACjC,IAAI;EACF,OAAO,KAAK,UAAU,KAAK,KAAK;CAClC,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;AAQA,MAAa,oBAAoB,WAA+B;CAC9D,MAAM,EAAE,eAAe,IAAI,QAAQ,YAAY;CAC/C,MAAM,CAAC,SAAS,cAAc,SAA8C,KAAA,CAAS;CACrF,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,UAAU,eAAe,SAA6B,KAAA,CAAS;CACtE,MAAM,aAAa,OAAO,OAAO;CACjC,WAAW,UAAU;CACrB,MAAM,QAAQ,OAAO,CAAC;CACtB,MAAM,YAAY,cAAc,OAAO,MAAM,GAAG,CAAC,MAAM,CAAC;CACxD,MAAM,UAAU,CAAC,CAAC;CAElB,gBAAgB;EACd,IAAI,CAAC,SAAS;EACd,MAAM,KAAK,EAAE,MAAM;EACnB,MAAM,QAAQ,iBACN;GACJ,MAAM,MAAM,WAAW;GACvB,IAAI,CAAC,KAAK;GACV,WAAW,IAAI;GACf,QAAQ,QAAQ,IAAI;IAAE,GAAG;IAAQ;GAAS,CAAC,CAAC,CAAC,CAC1C,MAAM,SAAS;IACd,IAAI,OAAO,MAAM,SAAS,WAAW,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC;GACtE,CAAC,CAAC,CACD,YAAY;IACX,IAAI,OAAO,MAAM,SAAS,WAAW,CAAC,CAAC;GACzC,CAAC,CAAC,CACD,cAAc;IACb,IAAI,OAAO,MAAM,SAAS,WAAW,KAAK;GAC5C,CAAC;EACL,GAEA,KAAK,IAAI,GAAG,YAAY,CAC1B;EACA,aAAa,aAAa,KAAK;CAEjC,GAAG;EAAC;EAAS;EAAW;EAAU;CAAY,CAAC;CAK/C,OAAO;EACL;EACA;EACA,UALA,WAAW,CAAC,CAAC,OAAO,YAAY,cAAc,OAAO,YAAY,iBAAiB,SAKxD,UAAkB,YAAY,SAAS,KAAA,CAAS,IAAI,KAAA;EAC9E;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"useFetchData.mjs","names":[],"sources":["../../../src/base-ui/ProTable/useFetchData.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { SortOrder } from '@/base-ui/Table/type';\n\nimport type { ProTablePageInfo, ProTableRequest } from './type';\n\ntype Filter = Record<string, (string | number | boolean)[] | null>;\n\nexport interface UseFetchDataOptions<T> {\n debounceTime: number;\n defaultData?: T[];\n /** Everything except the page that a fetch depends on, as a stable string. */\n depsKey: string;\n filter: Filter;\n getParams: () => Record<string, any>;\n manual: boolean;\n onDataSourceChange?: (data: T[]) => void;\n onLoad?: (data: T[]) => void;\n onLoadingChange?: (loading: boolean) => void;\n onRequestError?: (error: Error) => void;\n pageInfo: ProTablePageInfo;\n paginated: boolean;\n polling?: number | ((data: T[]) => number);\n postData?: (data: T[]) => T[];\n request?: ProTableRequest<T, any>;\n setTotal: (total: number) => void;\n sort: Record<string, SortOrder>;\n}\n\n/** `request` driving: debounced fetch on deps / page change, stale-response guard, polling. */\nexport const useFetchData = <T>(options: UseFetchDataOptions<T>) => {\n const [data, setData] = useState<T[]>(options.defaultData ?? []);\n const [loading, setLoading] = useState(false);\n const latest = useRef(options);\n latest.current = options;\n const requestId = useRef(0);\n const [enabled, setEnabled] = useState(!options.manual);\n const [token, setToken] = useState(0);\n const pending = useRef<(() => void)[]>([]);\n\n const updateLoading = (next: boolean) => {\n setLoading(next);\n latest.current.onLoadingChange?.(next);\n };\n\n const run = useCallback(async () => {\n const opts = latest.current;\n if (!opts.request) return;\n const id = ++requestId.current;\n updateLoading(true);\n try {\n const params: Record<string, any> = { ...opts.getParams() };\n if (opts.paginated) {\n params.current = opts.pageInfo.current;\n params.pageSize = opts.pageInfo.pageSize;\n }\n const response = await opts.request(params as any, opts.sort, opts.filter);\n if (id !== requestId.current) return;\n if (response.success === false) {\n // Pro keeps the previous data when the request reports failure.\n return;\n }\n const raw = response.data ?? [];\n const next = opts.postData ? opts.postData(raw) : raw;\n setData(next);\n opts.setTotal(response.total ?? next.length);\n opts.onLoad?.(next);\n opts.onDataSourceChange?.(next);\n } catch (error) {\n if (id !== requestId.current) return;\n if (opts.onRequestError) opts.onRequestError(error as Error);\n else console.error(error);\n } finally {\n if (id === requestId.current) updateLoading(false);\n const resolvers = pending.current;\n pending.current = [];\n resolvers.forEach((resolve) => resolve());\n }\n }, []);\n\n const { current, pageSize } = options.pageInfo;\n useEffect(() => {\n if (!enabled || !latest.current.request) return;\n const delay = latest.current.debounceTime;\n if (delay <= 0) {\n void run();\n return;\n }\n const timer = setTimeout(() => void run(), delay);\n return () => clearTimeout(timer);\n }, [enabled, token, options.depsKey, current, pageSize, run]);\n\n // Polling: schedule the next round once the current one is done.\n useEffect(() => {\n const { polling } = latest.current;\n if (!polling || loading || !enabled) return;\n const interval = typeof polling === 'function' ? polling(data) : polling;\n if (!interval) return;\n const timer = setTimeout(() => void run(), Math.max(interval, 2000));\n return () => clearTimeout(timer);\n }, [data, loading, enabled, options.polling, run]);\n\n /** Force a fetch (also enables a `manualRequest` table); resolves when it settles. */\n const reload = useCallback(\n () =>\n new Promise<void>((resolve) => {\n if (!latest.current.request) {\n resolve();\n return;\n }\n pending.current.push(resolve);\n setEnabled(true);\n setToken((value) => value + 1);\n }),\n [],\n );\n\n return { data, loading, reload, setData };\n};\n"],"mappings":";;;AA8BA,MAAa,gBAAmB,YAAoC;CAClE,MAAM,CAAC,MAAM,WAAW,SAAc,QAAQ,eAAe,CAAC,CAAC;CAC/D,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,SAAS,OAAO,OAAO;CAC7B,OAAO,UAAU;CACjB,MAAM,YAAY,OAAO,CAAC;CAC1B,MAAM,CAAC,SAAS,cAAc,SAAS,CAAC,QAAQ,MAAM;CACtD,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CACpC,MAAM,UAAU,OAAuB,CAAC,CAAC;CAEzC,MAAM,iBAAiB,SAAkB;EACvC,WAAW,IAAI;EACf,OAAO,QAAQ,kBAAkB,IAAI;CACvC;CAEA,MAAM,MAAM,YAAY,YAAY;EAClC,MAAM,OAAO,OAAO;EACpB,IAAI,CAAC,KAAK,SAAS;EACnB,MAAM,KAAK,EAAE,UAAU;EACvB,cAAc,IAAI;EAClB,IAAI;GACF,MAAM,SAA8B,EAAE,GAAG,KAAK,UAAU,EAAE;GAC1D,IAAI,KAAK,WAAW;IAClB,OAAO,UAAU,KAAK,SAAS;IAC/B,OAAO,WAAW,KAAK,SAAS;GAClC;GACA,MAAM,WAAW,MAAM,KAAK,QAAQ,QAAe,KAAK,MAAM,KAAK,MAAM;GACzE,IAAI,OAAO,UAAU,SAAS;GAC9B,IAAI,SAAS,YAAY,OAEvB;GAEF,MAAM,MAAM,SAAS,QAAQ,CAAC;GAC9B,MAAM,OAAO,KAAK,WAAW,KAAK,SAAS,GAAG,IAAI;GAClD,QAAQ,IAAI;GACZ,KAAK,SAAS,SAAS,SAAS,KAAK,MAAM;GAC3C,KAAK,SAAS,IAAI;GAClB,KAAK,qBAAqB,IAAI;EAChC,SAAS,OAAO;GACd,IAAI,OAAO,UAAU,SAAS;GAC9B,IAAI,KAAK,gBAAgB,KAAK,eAAe,KAAc;QACtD,QAAQ,MAAM,KAAK;EAC1B,UAAU;GACR,IAAI,OAAO,UAAU,SAAS,cAAc,KAAK;GACjD,MAAM,YAAY,QAAQ;GAC1B,QAAQ,UAAU,CAAC;GACnB,UAAU,SAAS,YAAY,QAAQ,CAAC;EAC1C;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,EAAE,SAAS,aAAa,QAAQ;CACtC,gBAAgB;EACd,IAAI,CAAC,WAAW,CAAC,OAAO,QAAQ,SAAS;EACzC,MAAM,QAAQ,OAAO,QAAQ;EAC7B,IAAI,SAAS,GAAG;GACd,IAAS;GACT;EACF;EACA,MAAM,QAAQ,iBAAiB,KAAK,IAAI,GAAG,KAAK;EAChD,aAAa,aAAa,KAAK;CACjC,GAAG;EAAC;EAAS;EAAO,QAAQ;EAAS;EAAS;EAAU;CAAG,CAAC;CAG5D,gBAAgB;EACd,MAAM,EAAE,YAAY,OAAO;EAC3B,IAAI,CAAC,WAAW,WAAW,CAAC,SAAS;EACrC,MAAM,WAAW,OAAO,YAAY,aAAa,QAAQ,IAAI,IAAI;EACjE,IAAI,CAAC,UAAU;EACf,MAAM,QAAQ,iBAAiB,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,GAAI,CAAC;EACnE,aAAa,aAAa,KAAK;CACjC,GAAG;EAAC;EAAM;EAAS;EAAS,QAAQ;EAAS;CAAG,CAAC;CAiBjD,OAAO;EAAE;EAAM;EAAS,QAdT,kBAEX,IAAI,SAAe,YAAY;GAC7B,IAAI,CAAC,OAAO,QAAQ,SAAS;IAC3B,QAAQ;IACR;GACF;GACA,QAAQ,QAAQ,KAAK,OAAO;GAC5B,WAAW,IAAI;GACf,UAAU,UAAU,QAAQ,CAAC;EAC/B,CAAC,GACH,CAAC,CAG0B;EAAG;CAAQ;AAC1C"}
1
+ {"version":3,"file":"useFetchData.mjs","names":[],"sources":["../../../src/base-ui/ProTable/useFetchData.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { SortOrder } from '@/base-ui/Table/type';\n\nimport type { ProTablePageInfo, ProTableRequest, ProTableRequestFilter } from './type';\n\ntype Filter = Record<string, (string | number | boolean)[] | null>;\n\nexport interface UseFetchDataOptions<T> {\n debounceTime: number;\n defaultData?: T[];\n /** Everything except the page that a fetch depends on, as a stable string. */\n depsKey: string;\n filter: Filter;\n getParams: () => Record<string, any>;\n manual: boolean;\n onDataSourceChange?: (data: T[]) => void;\n onLoad?: (data: T[]) => void;\n onLoadingChange?: (loading: boolean) => void;\n onRequestError?: (error: Error) => void;\n pageInfo: ProTablePageInfo;\n paginated: boolean;\n polling?: number | ((data: T[]) => number);\n postData?: (data: T[]) => T[];\n request?: ProTableRequest<T, any>;\n setTotal: (total: number) => void;\n sort: Record<string, SortOrder>;\n}\n\n/** `request` driving: debounced fetch on deps / page change, stale-response guard, polling. */\nexport const useFetchData = <T>(options: UseFetchDataOptions<T>) => {\n const [data, setData] = useState<T[]>(options.defaultData ?? []);\n const [loading, setLoading] = useState(false);\n const latest = useRef(options);\n latest.current = options;\n const requestId = useRef(0);\n const [enabled, setEnabled] = useState(!options.manual);\n const [token, setToken] = useState(0);\n const pending = useRef<(() => void)[]>([]);\n\n const updateLoading = (next: boolean) => {\n setLoading(next);\n latest.current.onLoadingChange?.(next);\n };\n\n const run = useCallback(async () => {\n const opts = latest.current;\n if (!opts.request) return;\n const id = ++requestId.current;\n updateLoading(true);\n try {\n const params: Record<string, any> = { ...opts.getParams() };\n if (opts.paginated) {\n params.current = opts.pageInfo.current;\n params.pageSize = opts.pageInfo.pageSize;\n }\n const response = await opts.request(\n params as any,\n opts.sort,\n opts.filter as ProTableRequestFilter,\n );\n if (id !== requestId.current) return;\n if (response.success === false) {\n // Pro keeps the previous data when the request reports failure.\n return;\n }\n const raw = response.data ?? [];\n const next = opts.postData ? opts.postData(raw) : raw;\n setData(next);\n opts.setTotal(response.total ?? next.length);\n opts.onLoad?.(next);\n opts.onDataSourceChange?.(next);\n } catch (error) {\n if (id !== requestId.current) return;\n if (opts.onRequestError) opts.onRequestError(error as Error);\n else console.error(error);\n } finally {\n if (id === requestId.current) updateLoading(false);\n const resolvers = pending.current;\n pending.current = [];\n resolvers.forEach((resolve) => resolve());\n }\n }, []);\n\n const { current, pageSize } = options.pageInfo;\n useEffect(() => {\n if (!enabled || !latest.current.request) return;\n const delay = latest.current.debounceTime;\n if (delay <= 0) {\n void run();\n return;\n }\n const timer = setTimeout(() => void run(), delay);\n return () => clearTimeout(timer);\n }, [enabled, token, options.depsKey, current, pageSize, run]);\n\n // Polling: schedule the next round once the current one is done.\n useEffect(() => {\n const { polling } = latest.current;\n if (!polling || loading || !enabled) return;\n const interval = typeof polling === 'function' ? polling(data) : polling;\n if (!interval) return;\n const timer = setTimeout(() => void run(), Math.max(interval, 2000));\n return () => clearTimeout(timer);\n }, [data, loading, enabled, options.polling, run]);\n\n /** Force a fetch (also enables a `manualRequest` table); resolves when it settles. */\n const reload = useCallback(\n () =>\n new Promise<void>((resolve) => {\n if (!latest.current.request) {\n resolve();\n return;\n }\n pending.current.push(resolve);\n setEnabled(true);\n setToken((value) => value + 1);\n }),\n [],\n );\n\n return { data, loading, reload, setData };\n};\n"],"mappings":";;;AA8BA,MAAa,gBAAmB,YAAoC;CAClE,MAAM,CAAC,MAAM,WAAW,SAAc,QAAQ,eAAe,CAAC,CAAC;CAC/D,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,SAAS,OAAO,OAAO;CAC7B,OAAO,UAAU;CACjB,MAAM,YAAY,OAAO,CAAC;CAC1B,MAAM,CAAC,SAAS,cAAc,SAAS,CAAC,QAAQ,MAAM;CACtD,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CACpC,MAAM,UAAU,OAAuB,CAAC,CAAC;CAEzC,MAAM,iBAAiB,SAAkB;EACvC,WAAW,IAAI;EACf,OAAO,QAAQ,kBAAkB,IAAI;CACvC;CAEA,MAAM,MAAM,YAAY,YAAY;EAClC,MAAM,OAAO,OAAO;EACpB,IAAI,CAAC,KAAK,SAAS;EACnB,MAAM,KAAK,EAAE,UAAU;EACvB,cAAc,IAAI;EAClB,IAAI;GACF,MAAM,SAA8B,EAAE,GAAG,KAAK,UAAU,EAAE;GAC1D,IAAI,KAAK,WAAW;IAClB,OAAO,UAAU,KAAK,SAAS;IAC/B,OAAO,WAAW,KAAK,SAAS;GAClC;GACA,MAAM,WAAW,MAAM,KAAK,QAC1B,QACA,KAAK,MACL,KAAK,MACP;GACA,IAAI,OAAO,UAAU,SAAS;GAC9B,IAAI,SAAS,YAAY,OAEvB;GAEF,MAAM,MAAM,SAAS,QAAQ,CAAC;GAC9B,MAAM,OAAO,KAAK,WAAW,KAAK,SAAS,GAAG,IAAI;GAClD,QAAQ,IAAI;GACZ,KAAK,SAAS,SAAS,SAAS,KAAK,MAAM;GAC3C,KAAK,SAAS,IAAI;GAClB,KAAK,qBAAqB,IAAI;EAChC,SAAS,OAAO;GACd,IAAI,OAAO,UAAU,SAAS;GAC9B,IAAI,KAAK,gBAAgB,KAAK,eAAe,KAAc;QACtD,QAAQ,MAAM,KAAK;EAC1B,UAAU;GACR,IAAI,OAAO,UAAU,SAAS,cAAc,KAAK;GACjD,MAAM,YAAY,QAAQ;GAC1B,QAAQ,UAAU,CAAC;GACnB,UAAU,SAAS,YAAY,QAAQ,CAAC;EAC1C;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,EAAE,SAAS,aAAa,QAAQ;CACtC,gBAAgB;EACd,IAAI,CAAC,WAAW,CAAC,OAAO,QAAQ,SAAS;EACzC,MAAM,QAAQ,OAAO,QAAQ;EAC7B,IAAI,SAAS,GAAG;GACd,IAAS;GACT;EACF;EACA,MAAM,QAAQ,iBAAiB,KAAK,IAAI,GAAG,KAAK;EAChD,aAAa,aAAa,KAAK;CACjC,GAAG;EAAC;EAAS;EAAO,QAAQ;EAAS;EAAS;EAAU;CAAG,CAAC;CAG5D,gBAAgB;EACd,MAAM,EAAE,YAAY,OAAO;EAC3B,IAAI,CAAC,WAAW,WAAW,CAAC,SAAS;EACrC,MAAM,WAAW,OAAO,YAAY,aAAa,QAAQ,IAAI,IAAI;EACjE,IAAI,CAAC,UAAU;EACf,MAAM,QAAQ,iBAAiB,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,GAAI,CAAC;EACnE,aAAa,aAAa,KAAK;CACjC,GAAG;EAAC;EAAM;EAAS;EAAS,QAAQ;EAAS;CAAG,CAAC;CAiBjD,OAAO;EAAE;EAAM;EAAS,QAdT,kBAEX,IAAI,SAAe,YAAY;GAC7B,IAAI,CAAC,OAAO,QAAQ,SAAS;IAC3B,QAAQ;IACR;GACF;GACA,QAAQ,QAAQ,KAAK,OAAO;GAC5B,WAAW,IAAI;GACf,UAAU,UAAU,QAAQ,CAAC;EAC/B,CAAC,GACH,CAAC,CAG0B;EAAG;CAAQ;AAC1C"}
@@ -11,7 +11,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import { cx, useThemeMode } from "antd-style";
12
12
  import { Select } from "@base-ui/react/select";
13
13
  //#region src/base-ui/Select/Select.tsx
14
- const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOpen, defaultValue, disabled, id, labelRender, listHeight = 512, listItemHeight, loading, mode, name, onChange, onOpenChange, onSelect, open, optionRender, options, placeholder, popupClassName, popupMatchSelectWidth, prefix, readOnly, required, behaviorVariant = "default", selectedIndicatorVariant = "check", shadow, showSearch, size = "middle", style, suffixIcon, suffixIconProps, tokenSeparators, value, variant, virtual }) => {
14
+ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOpen, defaultValue, disabled, id, labelRender, listHeight = 512, listItemHeight, loading, mode, name, onChange, onOpenChange, onSelect, open, optionRender, options, placeholder, popupClassName, popupMatchSelectWidth, prefix, readOnly, required, behaviorVariant = "default", selectedIndicatorVariant = "check", shadow, showSearch, filterOption, onSearch, size = "middle", style, suffixIcon, suffixIconProps, tokenSeparators, value, variant, virtual }) => {
15
15
  const { isDarkMode } = useThemeMode();
16
16
  const resolvedVariant = variant ?? (isDarkMode ? "filled" : "outlined");
17
17
  const isTags = mode === "tags";
@@ -38,6 +38,8 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
38
38
  });
39
39
  const handleRemoveTag = useCallback((index) => handleValueChange(valueArray.filter((_, itemIndex) => itemIndex !== index)), [handleValueChange, valueArray]);
40
40
  const { filteredOptions, handleSearchChange, handleSearchKeyDown, searchValue, shouldShowSearch, stopSearchPropagation } = useSelectSearch({
41
+ filterOption,
42
+ onSearch,
41
43
  appendTagValues,
42
44
  handleOpenChange,
43
45
  mergedOpen,
@@ -1 +1 @@
1
- {"version":3,"file":"Select.mjs","names":["Select","menuStyles","styles","BaseSelect"],"sources":["../../../src/base-ui/Select/Select.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx, useThemeMode } from 'antd-style';\nimport { type MouseEvent } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\n\nimport { SelectPositioner } from './atoms';\nimport { isValueEmpty, shouldIgnoreRootValueChange } from './helpers';\nimport {\n usePortalContainer,\n useSelectOpen,\n useSelectSearch,\n useSelectValue,\n useSelectVirtual,\n} from './hooks';\nimport {\n createTriggerValueRenderer,\n EmptyContent,\n resolveIconNode,\n resolveSuffixIcon,\n SelectListSection,\n SelectSearchInput,\n SelectTriggerSuffix,\n} from './parts';\nimport { renderOptions } from './renderOptions';\nimport { styles, triggerVariants } from './style';\nimport { type SelectOption, type SelectProps } from './type';\n\nconst Select = memo<SelectProps<any>>(\n ({\n allowClear,\n autoFocus,\n className,\n classNames,\n defaultOpen,\n defaultValue,\n disabled,\n id,\n labelRender,\n listHeight = 512,\n listItemHeight,\n loading,\n mode,\n name,\n onChange,\n onOpenChange,\n onSelect,\n open,\n optionRender,\n options,\n placeholder,\n popupClassName,\n popupMatchSelectWidth,\n prefix,\n readOnly,\n required,\n behaviorVariant = 'default',\n selectedIndicatorVariant = 'check',\n shadow,\n showSearch,\n size = 'middle',\n style,\n suffixIcon,\n suffixIconProps,\n tokenSeparators,\n value,\n variant,\n virtual,\n }) => {\n const { isDarkMode } = useThemeMode();\n const resolvedVariant = variant ?? (isDarkMode ? 'filled' : 'outlined');\n const isTags = mode === 'tags';\n const isMultiple = mode === 'multiple' || mode === 'tags';\n const isItemAligned = behaviorVariant === 'item-aligned';\n\n const [extraOptions, setExtraOptions] = useState<SelectOption<any>[]>([]);\n\n useEffect(() => {\n if (mode !== 'tags' && extraOptions.length > 0) {\n setExtraOptions([]);\n }\n }, [mode, extraOptions.length]);\n\n const {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n removeLastTagValue,\n resolvedOptions,\n valueArray,\n } = useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n });\n\n const { handleOpenChange, mergedOpen } = useSelectOpen({ defaultOpen, onOpenChange, open });\n\n const handleRemoveTag = useCallback(\n (index: number) =>\n handleValueChange(valueArray.filter((_, itemIndex) => itemIndex !== index)),\n [handleValueChange, valueArray],\n );\n\n const {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n } = useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n });\n\n // Base UI prunes selected values that are missing from the registered (filtered) options\n // and reports it with reason 'none'. Ignore it while open or while closing with a stale\n // search term, so searching never mutates the value. Closed typeahead stays valid.\n const handleRootValueChange = useCallback(\n (nextValue: any, eventDetails?: { reason?: string }) => {\n if (isTags && !mergedOpen) return;\n if (shouldIgnoreRootValueChange({ mergedOpen, reason: eventDetails?.reason, searchValue }))\n return;\n handleValueChange(nextValue);\n },\n [handleValueChange, isTags, mergedOpen, searchValue],\n );\n\n const virtualState = useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n });\n\n const portalContainer = usePortalContainer();\n\n const renderValue = useMemo(\n () =>\n createTriggerValueRenderer({\n getOption,\n isMultiple,\n isTags,\n labelRender,\n normalizeValue,\n onRemoveValue: handleRemoveTag,\n placeholder: isTags ? undefined : placeholder,\n }),\n [getOption, handleRemoveTag, isMultiple, isTags, labelRender, normalizeValue, placeholder],\n );\n\n const hasValue = isMultiple ? valueArray.length > 0 : !isValueEmpty(normalizedValue);\n const showClear = Boolean(allowClear && hasValue && !disabled && !readOnly);\n\n const handleClear = useCallback(\n (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n handleValueChange(isMultiple ? [] : null);\n },\n [handleValueChange, isMultiple],\n );\n\n const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);\n const suffixIconNode = useMemo(\n () => resolveSuffixIcon(suffixIcon, suffixIconProps, loading),\n [loading, suffixIcon, suffixIconProps],\n );\n\n const popupStyle = useMemo(() => {\n const maxHeight = isItemAligned ? '80vh' : `${listHeight}px`;\n const baseStyle: React.CSSProperties = {\n maxWidth: 'var(--available-width)',\n minWidth: 'var(--anchor-width)',\n ['--lobe-select-popup-max-height' as any]: maxHeight,\n };\n\n if (popupMatchSelectWidth === undefined || popupMatchSelectWidth === true) {\n return baseStyle;\n }\n if (typeof popupMatchSelectWidth === 'number') {\n return {\n ...baseStyle,\n minWidth: popupMatchSelectWidth,\n width: popupMatchSelectWidth,\n };\n }\n return { ...baseStyle, minWidth: 'max-content' };\n }, [isItemAligned, listHeight, popupMatchSelectWidth]);\n\n const triggerClassName = cx(\n triggerVariants({ shadow, size, variant: resolvedVariant }),\n className,\n classNames?.root,\n classNames?.trigger,\n );\n\n const isBoldIndicator = selectedIndicatorVariant === 'bold';\n const itemTextClassName = cx(\n optionRender ? menuStyles.itemContent : menuStyles.label,\n styles.itemText,\n classNames?.itemText,\n );\n\n const isEmpty = filteredOptions.length === 0;\n const listContent = isEmpty ? (\n <EmptyContent classNames={classNames} />\n ) : (\n renderOptions({\n classNames,\n isBoldIndicator,\n items: filteredOptions,\n itemTextClassName,\n listItemHeight,\n optionRender,\n })\n );\n\n return (\n <BaseSelect.Root\n disabled={disabled}\n id={id}\n modal={isItemAligned}\n multiple={isMultiple}\n name={name}\n open={mergedOpen}\n readOnly={readOnly}\n required={required}\n value={normalizedValue}\n onOpenChange={handleOpenChange}\n onValueChange={handleRootValueChange}\n >\n <BaseSelect.Trigger\n autoFocus={!isTags && autoFocus}\n className={triggerClassName}\n disabled={disabled}\n nativeButton={!isTags}\n render={isTags ? <div /> : undefined}\n style={style}\n >\n {prefixNode !== null && prefixNode !== undefined && (\n <span className={cx(styles.prefix, classNames?.prefix)}>{prefixNode}</span>\n )}\n <BaseSelect.Value\n className={cx(styles.value, isTags && styles.tagsValue, classNames?.value)}\n >\n {renderValue}\n </BaseSelect.Value>\n {isTags && (\n <SelectSearchInput\n inline\n autoFocus={autoFocus}\n classNames={classNames}\n disabled={disabled}\n placeholder={valueArray.length === 0 ? placeholder : undefined}\n readOnly={readOnly}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectTriggerSuffix\n classNames={classNames}\n showClear={showClear}\n suffixIconNode={suffixIconNode}\n onClear={handleClear}\n />\n </BaseSelect.Trigger>\n\n <BaseSelect.Portal container={portalContainer}>\n <SelectPositioner\n align=\"start\"\n alignItemWithTrigger={isItemAligned}\n className={styles.positioner}\n side=\"bottom\"\n sideOffset={6}\n >\n <BaseSelect.Popup\n style={popupStyle}\n className={cx(\n menuStyles.popup,\n styles.popup,\n popupClassName,\n classNames?.popup,\n classNames?.dropdown,\n )}\n >\n {shouldShowSearch && !isTags && (\n <SelectSearchInput\n classNames={classNames}\n placeholder={placeholder}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectListSection\n classNames={classNames}\n hasSearch={shouldShowSearch && !isTags}\n isEmpty={isEmpty}\n listContent={listContent}\n listItemHeight={listItemHeight}\n virtual={virtual}\n virtualState={virtualState}\n />\n </BaseSelect.Popup>\n </SelectPositioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n );\n },\n);\n\nSelect.displayName = 'Select';\n\nexport default Select;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Select.mjs","names":["Select","menuStyles","styles","BaseSelect"],"sources":["../../../src/base-ui/Select/Select.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx, useThemeMode } from 'antd-style';\nimport { type MouseEvent } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\n\nimport { SelectPositioner } from './atoms';\nimport { isValueEmpty, shouldIgnoreRootValueChange } from './helpers';\nimport {\n usePortalContainer,\n useSelectOpen,\n useSelectSearch,\n useSelectValue,\n useSelectVirtual,\n} from './hooks';\nimport {\n createTriggerValueRenderer,\n EmptyContent,\n resolveIconNode,\n resolveSuffixIcon,\n SelectListSection,\n SelectSearchInput,\n SelectTriggerSuffix,\n} from './parts';\nimport { renderOptions } from './renderOptions';\nimport { styles, triggerVariants } from './style';\nimport { type SelectOption, type SelectProps } from './type';\n\nconst Select = memo<SelectProps<any>>(\n ({\n allowClear,\n autoFocus,\n className,\n classNames,\n defaultOpen,\n defaultValue,\n disabled,\n id,\n labelRender,\n listHeight = 512,\n listItemHeight,\n loading,\n mode,\n name,\n onChange,\n onOpenChange,\n onSelect,\n open,\n optionRender,\n options,\n placeholder,\n popupClassName,\n popupMatchSelectWidth,\n prefix,\n readOnly,\n required,\n behaviorVariant = 'default',\n selectedIndicatorVariant = 'check',\n shadow,\n showSearch,\n filterOption,\n onSearch,\n size = 'middle',\n style,\n suffixIcon,\n suffixIconProps,\n tokenSeparators,\n value,\n variant,\n virtual,\n }) => {\n const { isDarkMode } = useThemeMode();\n const resolvedVariant = variant ?? (isDarkMode ? 'filled' : 'outlined');\n const isTags = mode === 'tags';\n const isMultiple = mode === 'multiple' || mode === 'tags';\n const isItemAligned = behaviorVariant === 'item-aligned';\n\n const [extraOptions, setExtraOptions] = useState<SelectOption<any>[]>([]);\n\n useEffect(() => {\n if (mode !== 'tags' && extraOptions.length > 0) {\n setExtraOptions([]);\n }\n }, [mode, extraOptions.length]);\n\n const {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n removeLastTagValue,\n resolvedOptions,\n valueArray,\n } = useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n });\n\n const { handleOpenChange, mergedOpen } = useSelectOpen({ defaultOpen, onOpenChange, open });\n\n const handleRemoveTag = useCallback(\n (index: number) =>\n handleValueChange(valueArray.filter((_, itemIndex) => itemIndex !== index)),\n [handleValueChange, valueArray],\n );\n\n const {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n } = useSelectSearch({\n filterOption,\n onSearch,\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n });\n\n // Base UI prunes selected values that are missing from the registered (filtered) options\n // and reports it with reason 'none'. Ignore it while open or while closing with a stale\n // search term, so searching never mutates the value. Closed typeahead stays valid.\n const handleRootValueChange = useCallback(\n (nextValue: any, eventDetails?: { reason?: string }) => {\n if (isTags && !mergedOpen) return;\n if (shouldIgnoreRootValueChange({ mergedOpen, reason: eventDetails?.reason, searchValue }))\n return;\n handleValueChange(nextValue);\n },\n [handleValueChange, isTags, mergedOpen, searchValue],\n );\n\n const virtualState = useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n });\n\n const portalContainer = usePortalContainer();\n\n const renderValue = useMemo(\n () =>\n createTriggerValueRenderer({\n getOption,\n isMultiple,\n isTags,\n labelRender,\n normalizeValue,\n onRemoveValue: handleRemoveTag,\n placeholder: isTags ? undefined : placeholder,\n }),\n [getOption, handleRemoveTag, isMultiple, isTags, labelRender, normalizeValue, placeholder],\n );\n\n const hasValue = isMultiple ? valueArray.length > 0 : !isValueEmpty(normalizedValue);\n const showClear = Boolean(allowClear && hasValue && !disabled && !readOnly);\n\n const handleClear = useCallback(\n (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n handleValueChange(isMultiple ? [] : null);\n },\n [handleValueChange, isMultiple],\n );\n\n const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);\n const suffixIconNode = useMemo(\n () => resolveSuffixIcon(suffixIcon, suffixIconProps, loading),\n [loading, suffixIcon, suffixIconProps],\n );\n\n const popupStyle = useMemo(() => {\n const maxHeight = isItemAligned ? '80vh' : `${listHeight}px`;\n const baseStyle: React.CSSProperties = {\n maxWidth: 'var(--available-width)',\n minWidth: 'var(--anchor-width)',\n ['--lobe-select-popup-max-height' as any]: maxHeight,\n };\n\n if (popupMatchSelectWidth === undefined || popupMatchSelectWidth === true) {\n return baseStyle;\n }\n if (typeof popupMatchSelectWidth === 'number') {\n return {\n ...baseStyle,\n minWidth: popupMatchSelectWidth,\n width: popupMatchSelectWidth,\n };\n }\n return { ...baseStyle, minWidth: 'max-content' };\n }, [isItemAligned, listHeight, popupMatchSelectWidth]);\n\n const triggerClassName = cx(\n triggerVariants({ shadow, size, variant: resolvedVariant }),\n className,\n classNames?.root,\n classNames?.trigger,\n );\n\n const isBoldIndicator = selectedIndicatorVariant === 'bold';\n const itemTextClassName = cx(\n optionRender ? menuStyles.itemContent : menuStyles.label,\n styles.itemText,\n classNames?.itemText,\n );\n\n const isEmpty = filteredOptions.length === 0;\n const listContent = isEmpty ? (\n <EmptyContent classNames={classNames} />\n ) : (\n renderOptions({\n classNames,\n isBoldIndicator,\n items: filteredOptions,\n itemTextClassName,\n listItemHeight,\n optionRender,\n })\n );\n\n return (\n <BaseSelect.Root\n disabled={disabled}\n id={id}\n modal={isItemAligned}\n multiple={isMultiple}\n name={name}\n open={mergedOpen}\n readOnly={readOnly}\n required={required}\n value={normalizedValue}\n onOpenChange={handleOpenChange}\n onValueChange={handleRootValueChange}\n >\n <BaseSelect.Trigger\n autoFocus={!isTags && autoFocus}\n className={triggerClassName}\n disabled={disabled}\n nativeButton={!isTags}\n render={isTags ? <div /> : undefined}\n style={style}\n >\n {prefixNode !== null && prefixNode !== undefined && (\n <span className={cx(styles.prefix, classNames?.prefix)}>{prefixNode}</span>\n )}\n <BaseSelect.Value\n className={cx(styles.value, isTags && styles.tagsValue, classNames?.value)}\n >\n {renderValue}\n </BaseSelect.Value>\n {isTags && (\n <SelectSearchInput\n inline\n autoFocus={autoFocus}\n classNames={classNames}\n disabled={disabled}\n placeholder={valueArray.length === 0 ? placeholder : undefined}\n readOnly={readOnly}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectTriggerSuffix\n classNames={classNames}\n showClear={showClear}\n suffixIconNode={suffixIconNode}\n onClear={handleClear}\n />\n </BaseSelect.Trigger>\n\n <BaseSelect.Portal container={portalContainer}>\n <SelectPositioner\n align=\"start\"\n alignItemWithTrigger={isItemAligned}\n className={styles.positioner}\n side=\"bottom\"\n sideOffset={6}\n >\n <BaseSelect.Popup\n style={popupStyle}\n className={cx(\n menuStyles.popup,\n styles.popup,\n popupClassName,\n classNames?.popup,\n classNames?.dropdown,\n )}\n >\n {shouldShowSearch && !isTags && (\n <SelectSearchInput\n classNames={classNames}\n placeholder={placeholder}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectListSection\n classNames={classNames}\n hasSearch={shouldShowSearch && !isTags}\n isEmpty={isEmpty}\n listContent={listContent}\n listItemHeight={listItemHeight}\n virtual={virtual}\n virtualState={virtualState}\n />\n </BaseSelect.Popup>\n </SelectPositioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n );\n },\n);\n\nSelect.displayName = 'Select';\n\nexport default Select;\n"],"mappings":"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"}
@@ -135,7 +135,7 @@ function useSelectOpen({ defaultOpen, onOpenChange, open }) {
135
135
  mergedOpen
136
136
  };
137
137
  }
138
- function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode, removeLastTagValue, resolvedOptions, showSearch, tokenSeparators }) {
138
+ function useSelectSearch({ filterOption, onSearch, appendTagValues, handleOpenChange, mergedOpen, mode, removeLastTagValue, resolvedOptions, showSearch, tokenSeparators }) {
139
139
  const [searchValue, setSearchValue] = useState("");
140
140
  const shouldShowSearch = Boolean(showSearch || mode === "tags");
141
141
  useEffect(() => {
@@ -153,9 +153,11 @@ function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode,
153
153
  }
154
154
  }
155
155
  setSearchValue(nextValue);
156
+ onSearch?.(nextValue);
156
157
  }, [
157
158
  appendTagValues,
158
159
  mode,
160
+ onSearch,
159
161
  tokenSeparators
160
162
  ]);
161
163
  const handleSearchKeyDown = useCallback((event) => {
@@ -190,20 +192,22 @@ function useSelectSearch({ appendTagValues, handleOpenChange, mergedOpen, mode,
190
192
  }, []);
191
193
  return {
192
194
  filteredOptions: useMemo(() => {
193
- if (!shouldShowSearch || !searchValue.trim()) return resolvedOptions;
195
+ if (!shouldShowSearch || !searchValue.trim() || filterOption === false) return resolvedOptions;
194
196
  const query = searchValue.trim().toLowerCase();
197
+ const matches = (option) => typeof filterOption === "function" ? filterOption(searchValue, option) : getOptionSearchText(option).toLowerCase().includes(query);
195
198
  return resolvedOptions.map((item) => {
196
199
  if (isGroupOption(item)) {
197
- const groupItems = item.options.filter((option) => getOptionSearchText(option).toLowerCase().includes(query));
200
+ const groupItems = item.options.filter((option) => matches(option));
198
201
  if (!groupItems.length) return null;
199
202
  return {
200
203
  ...item,
201
204
  options: groupItems
202
205
  };
203
206
  }
204
- return getOptionSearchText(item).toLowerCase().includes(query) ? item : null;
207
+ return matches(item) ? item : null;
205
208
  }).filter(Boolean);
206
209
  }, [
210
+ filterOption,
207
211
  resolvedOptions,
208
212
  searchValue,
209
213
  shouldShowSearch
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.mjs","names":[],"sources":["../../../src/base-ui/Select/hooks.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useAppElement } from '@/ThemeProvider/AppElementContext';\n\nimport {\n countVirtualItems,\n getOptionSearchText,\n isGroupOption,\n isValueEmpty,\n normalizeValueFor,\n splitBySeparators,\n} from './helpers';\nimport {\n type SelectOption,\n type SelectOptions,\n type SelectProps,\n type SelectRootChangeEventDetails,\n type SelectSize,\n} from './type';\n\ninterface UseSelectValueParams {\n defaultValue: SelectProps['defaultValue'];\n extraOptions: SelectOption<any>[];\n isMultiple: boolean;\n onChange: SelectProps['onChange'];\n onSelect: SelectProps['onSelect'];\n options: SelectOptions<any> | undefined;\n setExtraOptions: React.Dispatch<React.SetStateAction<SelectOption<any>[]>>;\n value: SelectProps['value'];\n}\n\nexport function useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n}: UseSelectValueParams) {\n const [uncontrolledValue, setUncontrolledValue] = useState<any>(() => {\n if (defaultValue !== undefined) return defaultValue;\n return isMultiple ? [] : null;\n });\n\n const normalizeValue = useMemo(() => normalizeValueFor(isMultiple), [isMultiple]);\n\n const mergedValue = value !== undefined ? value : uncontrolledValue;\n const normalizedValue = useMemo(() => normalizeValue(mergedValue), [mergedValue, normalizeValue]);\n\n const valueArray = useMemo(() => {\n if (isMultiple) return normalizedValue as any[];\n return isValueEmpty(normalizedValue) ? [] : [normalizedValue];\n }, [isMultiple, normalizedValue]);\n\n const { optionMap, resolvedOptions } = useMemo(() => {\n const baseOptions = options ?? [];\n const optionValueMap = new Map<any, SelectOption<any>>();\n\n const addOption = (item: SelectOption<any>) => {\n if (!optionValueMap.has(item.value)) {\n optionValueMap.set(item.value, item);\n }\n };\n\n baseOptions.forEach((item) => {\n if (isGroupOption(item)) {\n item.options.forEach(addOption);\n } else {\n addOption(item);\n }\n });\n\n const filteredExtraOptions = extraOptions.filter((item) => !optionValueMap.has(item.value));\n filteredExtraOptions.forEach(addOption);\n const mergedOptions: SelectOptions<any> = [...baseOptions, ...filteredExtraOptions];\n\n const missingValueOptions: SelectOption<any>[] = valueArray\n .filter((val) => !optionValueMap.has(val))\n .map((val) => ({ label: String(val), value: val }));\n missingValueOptions.forEach(addOption);\n\n return {\n optionMap: optionValueMap,\n resolvedOptions: missingValueOptions.length\n ? [...mergedOptions, ...missingValueOptions]\n : mergedOptions,\n };\n }, [extraOptions, options, valueArray]);\n\n const getOption = useCallback(\n (optionValue: any): SelectOption<any> => {\n const matched = optionMap.get(optionValue);\n if (matched) return matched;\n if (optionValue && typeof optionValue === 'object' && 'label' in optionValue) {\n return { label: (optionValue as any).label, value: optionValue };\n }\n return { label: String(optionValue), value: optionValue };\n },\n [optionMap],\n );\n\n const previousValueRef = useRef<any>(normalizedValue);\n useEffect(() => {\n previousValueRef.current = normalizedValue;\n }, [normalizedValue]);\n\n const handleValueChange = useCallback(\n (nextValue: any) => {\n const normalizedNextValue = normalizeValue(nextValue);\n const previousValue = previousValueRef.current;\n\n if (isMultiple) {\n const prevValues = Array.isArray(previousValue) ? previousValue : [];\n const nextValues = Array.isArray(normalizedNextValue) ? normalizedNextValue : [];\n const addedValues = nextValues.filter(\n (val) => !prevValues.some((prev) => Object.is(prev, val)),\n );\n addedValues.forEach((val) => onSelect?.(val, getOption(val)));\n\n if (value === undefined) setUncontrolledValue(nextValues);\n onChange?.(\n nextValues,\n nextValues.map((val) => getOption(val)),\n );\n } else {\n if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) {\n onSelect?.(normalizedNextValue, getOption(normalizedNextValue));\n }\n if (value === undefined) setUncontrolledValue(normalizedNextValue);\n onChange?.(\n isValueEmpty(normalizedNextValue) ? undefined : normalizedNextValue,\n isValueEmpty(normalizedNextValue) ? undefined : getOption(normalizedNextValue),\n );\n }\n\n previousValueRef.current = normalizedNextValue;\n },\n [getOption, isMultiple, normalizeValue, onChange, onSelect, value],\n );\n\n const appendTagValues = useCallback(\n (rawValues: string[]) => {\n const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);\n if (!valuesToAdd.length) return;\n\n const currentValues = Array.isArray(previousValueRef.current)\n ? previousValueRef.current\n : valueArray;\n const nextValues = [...currentValues];\n const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));\n\n if (newOptionValues.length > 0) {\n setExtraOptions((prev) => {\n const existingValues = new Set(prev.map((item) => item.value));\n const merged = [...prev];\n newOptionValues.forEach((val) => {\n if (!existingValues.has(val)) {\n merged.push({ label: val, value: val });\n }\n });\n return merged;\n });\n }\n\n valuesToAdd.forEach((val) => {\n if (!nextValues.some((item) => Object.is(item, val))) {\n nextValues.push(val);\n }\n });\n\n if (nextValues.length !== valueArray.length) {\n handleValueChange(nextValues);\n }\n },\n [handleValueChange, optionMap, setExtraOptions, valueArray],\n );\n\n const removeLastTagValue = useCallback(() => {\n const currentValues = Array.isArray(previousValueRef.current)\n ? previousValueRef.current\n : valueArray;\n if (currentValues.length > 0) handleValueChange(currentValues.slice(0, -1));\n }, [handleValueChange, valueArray]);\n\n return {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n optionMap,\n resolvedOptions,\n removeLastTagValue,\n valueArray,\n };\n}\n\ninterface UseSelectOpenParams {\n defaultOpen: boolean | undefined;\n onOpenChange: SelectProps['onOpenChange'];\n open: boolean | undefined;\n}\n\nexport function useSelectOpen({ defaultOpen, onOpenChange, open }: UseSelectOpenParams) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));\n\n useEffect(() => {\n if (open !== undefined) setUncontrolledOpen(open);\n }, [open]);\n\n const mergedOpen = open ?? uncontrolledOpen;\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean, eventDetails?: SelectRootChangeEventDetails) => {\n onOpenChange?.(nextOpen, eventDetails);\n if (open === undefined) setUncontrolledOpen(nextOpen);\n },\n [onOpenChange, open],\n );\n\n return { handleOpenChange, mergedOpen };\n}\n\ninterface UseSelectSearchParams {\n appendTagValues: (values: string[]) => void;\n handleOpenChange: (nextOpen: boolean) => void;\n mergedOpen: boolean;\n mode: SelectProps['mode'];\n removeLastTagValue: () => void;\n resolvedOptions: SelectOptions;\n showSearch: boolean | undefined;\n tokenSeparators: string[] | undefined;\n}\n\nexport function useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n}: UseSelectSearchParams) {\n const [searchValue, setSearchValue] = useState('');\n const shouldShowSearch = Boolean(showSearch || mode === 'tags');\n\n useEffect(() => {\n if (!mergedOpen) setSearchValue('');\n }, [mergedOpen]);\n\n const handleSearchChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.target.value;\n if (mode === 'tags') {\n const parts = splitBySeparators(nextValue, tokenSeparators);\n if (parts.length > 1) {\n const pending = parts.pop() ?? '';\n appendTagValues(parts.filter(Boolean));\n setSearchValue(pending);\n return;\n }\n }\n setSearchValue(nextValue);\n },\n [appendTagValues, mode, tokenSeparators],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n handleOpenChange(false);\n return;\n }\n if (mode !== 'tags') return;\n\n if (event.key === 'Backspace' && !searchValue) {\n event.preventDefault();\n removeLastTagValue();\n return;\n }\n\n const isSeparator = tokenSeparators?.includes(event.key);\n if (event.key === 'Enter' || isSeparator) {\n event.preventDefault();\n event.stopPropagation();\n appendTagValues([searchValue]);\n setSearchValue('');\n }\n },\n [appendTagValues, handleOpenChange, mode, removeLastTagValue, searchValue, tokenSeparators],\n );\n\n // Stop propagation in capture phase + on keyup to block base-ui Popup-level\n // `useTypeahead` (and any ancestor typeahead) from hijacking the search\n // input's first-letter focus behavior. Do not remove.\n const stopSearchPropagation = useCallback((event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n }, []);\n\n const filteredOptions = useMemo(() => {\n if (!shouldShowSearch || !searchValue.trim()) return resolvedOptions;\n const query = searchValue.trim().toLowerCase();\n\n return resolvedOptions\n .map((item) => {\n if (isGroupOption(item)) {\n const groupItems = item.options.filter((option) =>\n getOptionSearchText(option).toLowerCase().includes(query),\n );\n if (!groupItems.length) return null;\n return { ...item, options: groupItems };\n }\n return getOptionSearchText(item).toLowerCase().includes(query) ? item : null;\n })\n .filter(Boolean) as SelectOptions;\n }, [resolvedOptions, searchValue, shouldShowSearch]);\n\n return {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n };\n}\n\ninterface UseSelectVirtualParams {\n filteredOptions: SelectOptions;\n listItemHeight: number | undefined;\n size: SelectSize;\n valueArray: any[];\n virtual: boolean | undefined;\n}\n\nexport function useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n}: UseSelectVirtualParams) {\n const virtualListStyle = useMemo(() => {\n if (!virtual) return undefined;\n const rowCount = countVirtualItems(filteredOptions);\n const maxVisibleRows = 6;\n const estimatedRowHeight =\n listItemHeight ?? (size === 'large' ? 40 : size === 'small' ? 28 : 32);\n const visibleRows = Math.min(Math.max(rowCount, 1), maxVisibleRows);\n const estimatedHeight = visibleRows * estimatedRowHeight + 8;\n\n return {\n height: `min(${estimatedHeight}px, var(--lobe-select-available-height, var(--available-height)))`,\n };\n }, [filteredOptions, listItemHeight, size, virtual]);\n\n const selectedIndices = useMemo(() => {\n if (!virtual || valueArray.length === 0) return undefined;\n const selectedSet = new Set(valueArray);\n const indices: number[] = [];\n let index = 0;\n\n filteredOptions.forEach((item) => {\n if (isGroupOption(item)) {\n if (item.options.some((option) => selectedSet.has(option.value))) {\n indices.push(index);\n }\n index += 1;\n return;\n }\n if (selectedSet.has(item.value)) indices.push(index);\n index += 1;\n });\n\n return indices.length ? indices : undefined;\n }, [filteredOptions, valueArray, virtual]);\n\n return { selectedIndices, virtualListStyle };\n}\n\nexport function usePortalContainer() {\n const appElement = useAppElement();\n // `appElement` is the ThemeProvider wrapper div, which uses `display: contents`\n // so it has no layout box. `@base-ui/react/select` fails to mount its Popup\n // into a `display: contents` container in certain hosts (editor/chat inputs\n // with focus traps). Fall back to `document.body` in that case; keep the\n // original behavior when the wrapper has a real layout (older themes, SSR\n // snapshot, etc.).\n return useMemo(() => {\n if (typeof window === 'undefined') return appElement;\n if (!(appElement instanceof HTMLElement)) return undefined;\n const display = window.getComputedStyle(appElement).display;\n return display === 'contents' ? document.body : appElement;\n }, [appElement]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hooks.mjs","names":[],"sources":["../../../src/base-ui/Select/hooks.tsx"],"sourcesContent":["'use client';\n\nimport {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useAppElement } from '@/ThemeProvider/AppElementContext';\n\nimport {\n countVirtualItems,\n getOptionSearchText,\n isGroupOption,\n isValueEmpty,\n normalizeValueFor,\n splitBySeparators,\n} from './helpers';\nimport {\n type SelectOption,\n type SelectOptions,\n type SelectProps,\n type SelectRootChangeEventDetails,\n type SelectSize,\n} from './type';\n\ninterface UseSelectValueParams {\n defaultValue: SelectProps['defaultValue'];\n extraOptions: SelectOption<any>[];\n isMultiple: boolean;\n onChange: SelectProps['onChange'];\n onSelect: SelectProps['onSelect'];\n options: SelectOptions<any> | undefined;\n setExtraOptions: React.Dispatch<React.SetStateAction<SelectOption<any>[]>>;\n value: SelectProps['value'];\n}\n\nexport function useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n}: UseSelectValueParams) {\n const [uncontrolledValue, setUncontrolledValue] = useState<any>(() => {\n if (defaultValue !== undefined) return defaultValue;\n return isMultiple ? [] : null;\n });\n\n const normalizeValue = useMemo(() => normalizeValueFor(isMultiple), [isMultiple]);\n\n const mergedValue = value !== undefined ? value : uncontrolledValue;\n const normalizedValue = useMemo(() => normalizeValue(mergedValue), [mergedValue, normalizeValue]);\n\n const valueArray = useMemo(() => {\n if (isMultiple) return normalizedValue as any[];\n return isValueEmpty(normalizedValue) ? [] : [normalizedValue];\n }, [isMultiple, normalizedValue]);\n\n const { optionMap, resolvedOptions } = useMemo(() => {\n const baseOptions = options ?? [];\n const optionValueMap = new Map<any, SelectOption<any>>();\n\n const addOption = (item: SelectOption<any>) => {\n if (!optionValueMap.has(item.value)) {\n optionValueMap.set(item.value, item);\n }\n };\n\n baseOptions.forEach((item) => {\n if (isGroupOption(item)) {\n item.options.forEach(addOption);\n } else {\n addOption(item);\n }\n });\n\n const filteredExtraOptions = extraOptions.filter((item) => !optionValueMap.has(item.value));\n filteredExtraOptions.forEach(addOption);\n const mergedOptions: SelectOptions<any> = [...baseOptions, ...filteredExtraOptions];\n\n const missingValueOptions: SelectOption<any>[] = valueArray\n .filter((val) => !optionValueMap.has(val))\n .map((val) => ({ label: String(val), value: val }));\n missingValueOptions.forEach(addOption);\n\n return {\n optionMap: optionValueMap,\n resolvedOptions: missingValueOptions.length\n ? [...mergedOptions, ...missingValueOptions]\n : mergedOptions,\n };\n }, [extraOptions, options, valueArray]);\n\n const getOption = useCallback(\n (optionValue: any): SelectOption<any> => {\n const matched = optionMap.get(optionValue);\n if (matched) return matched;\n if (optionValue && typeof optionValue === 'object' && 'label' in optionValue) {\n return { label: (optionValue as any).label, value: optionValue };\n }\n return { label: String(optionValue), value: optionValue };\n },\n [optionMap],\n );\n\n const previousValueRef = useRef<any>(normalizedValue);\n useEffect(() => {\n previousValueRef.current = normalizedValue;\n }, [normalizedValue]);\n\n const handleValueChange = useCallback(\n (nextValue: any) => {\n const normalizedNextValue = normalizeValue(nextValue);\n const previousValue = previousValueRef.current;\n\n if (isMultiple) {\n const prevValues = Array.isArray(previousValue) ? previousValue : [];\n const nextValues = Array.isArray(normalizedNextValue) ? normalizedNextValue : [];\n const addedValues = nextValues.filter(\n (val) => !prevValues.some((prev) => Object.is(prev, val)),\n );\n addedValues.forEach((val) => onSelect?.(val, getOption(val)));\n\n if (value === undefined) setUncontrolledValue(nextValues);\n onChange?.(\n nextValues,\n nextValues.map((val) => getOption(val)),\n );\n } else {\n if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) {\n onSelect?.(normalizedNextValue, getOption(normalizedNextValue));\n }\n if (value === undefined) setUncontrolledValue(normalizedNextValue);\n onChange?.(\n isValueEmpty(normalizedNextValue) ? undefined : normalizedNextValue,\n isValueEmpty(normalizedNextValue) ? undefined : getOption(normalizedNextValue),\n );\n }\n\n previousValueRef.current = normalizedNextValue;\n },\n [getOption, isMultiple, normalizeValue, onChange, onSelect, value],\n );\n\n const appendTagValues = useCallback(\n (rawValues: string[]) => {\n const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);\n if (!valuesToAdd.length) return;\n\n const currentValues = Array.isArray(previousValueRef.current)\n ? previousValueRef.current\n : valueArray;\n const nextValues = [...currentValues];\n const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));\n\n if (newOptionValues.length > 0) {\n setExtraOptions((prev) => {\n const existingValues = new Set(prev.map((item) => item.value));\n const merged = [...prev];\n newOptionValues.forEach((val) => {\n if (!existingValues.has(val)) {\n merged.push({ label: val, value: val });\n }\n });\n return merged;\n });\n }\n\n valuesToAdd.forEach((val) => {\n if (!nextValues.some((item) => Object.is(item, val))) {\n nextValues.push(val);\n }\n });\n\n if (nextValues.length !== valueArray.length) {\n handleValueChange(nextValues);\n }\n },\n [handleValueChange, optionMap, setExtraOptions, valueArray],\n );\n\n const removeLastTagValue = useCallback(() => {\n const currentValues = Array.isArray(previousValueRef.current)\n ? previousValueRef.current\n : valueArray;\n if (currentValues.length > 0) handleValueChange(currentValues.slice(0, -1));\n }, [handleValueChange, valueArray]);\n\n return {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n optionMap,\n resolvedOptions,\n removeLastTagValue,\n valueArray,\n };\n}\n\ninterface UseSelectOpenParams {\n defaultOpen: boolean | undefined;\n onOpenChange: SelectProps['onOpenChange'];\n open: boolean | undefined;\n}\n\nexport function useSelectOpen({ defaultOpen, onOpenChange, open }: UseSelectOpenParams) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));\n\n useEffect(() => {\n if (open !== undefined) setUncontrolledOpen(open);\n }, [open]);\n\n const mergedOpen = open ?? uncontrolledOpen;\n\n const handleOpenChange = useCallback(\n (nextOpen: boolean, eventDetails?: SelectRootChangeEventDetails) => {\n onOpenChange?.(nextOpen, eventDetails);\n if (open === undefined) setUncontrolledOpen(nextOpen);\n },\n [onOpenChange, open],\n );\n\n return { handleOpenChange, mergedOpen };\n}\n\ninterface UseSelectSearchParams {\n appendTagValues: (values: string[]) => void;\n filterOption?: SelectProps<any>['filterOption'];\n handleOpenChange: (nextOpen: boolean) => void;\n mergedOpen: boolean;\n mode: SelectProps['mode'];\n onSearch?: (value: string) => void;\n removeLastTagValue: () => void;\n resolvedOptions: SelectOptions;\n showSearch: boolean | undefined;\n tokenSeparators: string[] | undefined;\n}\n\nexport function useSelectSearch({\n filterOption,\n onSearch,\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n}: UseSelectSearchParams) {\n const [searchValue, setSearchValue] = useState('');\n const shouldShowSearch = Boolean(showSearch || mode === 'tags');\n\n useEffect(() => {\n if (!mergedOpen) setSearchValue('');\n }, [mergedOpen]);\n\n const handleSearchChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.target.value;\n if (mode === 'tags') {\n const parts = splitBySeparators(nextValue, tokenSeparators);\n if (parts.length > 1) {\n const pending = parts.pop() ?? '';\n appendTagValues(parts.filter(Boolean));\n setSearchValue(pending);\n return;\n }\n }\n setSearchValue(nextValue);\n onSearch?.(nextValue);\n },\n [appendTagValues, mode, onSearch, tokenSeparators],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n\n if (event.key === 'Escape') {\n handleOpenChange(false);\n return;\n }\n if (mode !== 'tags') return;\n\n if (event.key === 'Backspace' && !searchValue) {\n event.preventDefault();\n removeLastTagValue();\n return;\n }\n\n const isSeparator = tokenSeparators?.includes(event.key);\n if (event.key === 'Enter' || isSeparator) {\n event.preventDefault();\n event.stopPropagation();\n appendTagValues([searchValue]);\n setSearchValue('');\n }\n },\n [appendTagValues, handleOpenChange, mode, removeLastTagValue, searchValue, tokenSeparators],\n );\n\n // Stop propagation in capture phase + on keyup to block base-ui Popup-level\n // `useTypeahead` (and any ancestor typeahead) from hijacking the search\n // input's first-letter focus behavior. Do not remove.\n const stopSearchPropagation = useCallback((event: KeyboardEvent<HTMLInputElement>) => {\n event.stopPropagation();\n }, []);\n\n const filteredOptions = useMemo(() => {\n if (!shouldShowSearch || !searchValue.trim() || filterOption === false) return resolvedOptions;\n const query = searchValue.trim().toLowerCase();\n const matches = (option: any) =>\n typeof filterOption === 'function'\n ? filterOption(searchValue, option)\n : getOptionSearchText(option).toLowerCase().includes(query);\n\n return resolvedOptions\n .map((item) => {\n if (isGroupOption(item)) {\n const groupItems = item.options.filter((option) => matches(option));\n if (!groupItems.length) return null;\n return { ...item, options: groupItems };\n }\n return matches(item) ? item : null;\n })\n .filter(Boolean) as SelectOptions;\n }, [filterOption, resolvedOptions, searchValue, shouldShowSearch]);\n\n return {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n };\n}\n\ninterface UseSelectVirtualParams {\n filteredOptions: SelectOptions;\n listItemHeight: number | undefined;\n size: SelectSize;\n valueArray: any[];\n virtual: boolean | undefined;\n}\n\nexport function useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n}: UseSelectVirtualParams) {\n const virtualListStyle = useMemo(() => {\n if (!virtual) return undefined;\n const rowCount = countVirtualItems(filteredOptions);\n const maxVisibleRows = 6;\n const estimatedRowHeight =\n listItemHeight ?? (size === 'large' ? 40 : size === 'small' ? 28 : 32);\n const visibleRows = Math.min(Math.max(rowCount, 1), maxVisibleRows);\n const estimatedHeight = visibleRows * estimatedRowHeight + 8;\n\n return {\n height: `min(${estimatedHeight}px, var(--lobe-select-available-height, var(--available-height)))`,\n };\n }, [filteredOptions, listItemHeight, size, virtual]);\n\n const selectedIndices = useMemo(() => {\n if (!virtual || valueArray.length === 0) return undefined;\n const selectedSet = new Set(valueArray);\n const indices: number[] = [];\n let index = 0;\n\n filteredOptions.forEach((item) => {\n if (isGroupOption(item)) {\n if (item.options.some((option) => selectedSet.has(option.value))) {\n indices.push(index);\n }\n index += 1;\n return;\n }\n if (selectedSet.has(item.value)) indices.push(index);\n index += 1;\n });\n\n return indices.length ? indices : undefined;\n }, [filteredOptions, valueArray, virtual]);\n\n return { selectedIndices, virtualListStyle };\n}\n\nexport function usePortalContainer() {\n const appElement = useAppElement();\n // `appElement` is the ThemeProvider wrapper div, which uses `display: contents`\n // so it has no layout box. `@base-ui/react/select` fails to mount its Popup\n // into a `display: contents` container in certain hosts (editor/chat inputs\n // with focus traps). Fall back to `document.body` in that case; keep the\n // original behavior when the wrapper has a real layout (older themes, SSR\n // snapshot, etc.).\n return useMemo(() => {\n if (typeof window === 'undefined') return appElement;\n if (!(appElement instanceof HTMLElement)) return undefined;\n const display = window.getComputedStyle(appElement).display;\n return display === 'contents' ? document.body : appElement;\n }, [appElement]);\n}\n"],"mappings":"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"}
@@ -64,6 +64,11 @@ interface SelectProps<Value = string> extends Pick<VirtualListProps, 'virtual' |
64
64
  defaultOpen?: boolean;
65
65
  defaultValue?: Value | Value[] | null;
66
66
  disabled?: boolean;
67
+ /**
68
+ * Local filtering of the options while searching: `false` keeps every option (filter on the
69
+ * server through `onSearch`), a function decides per option. @default true
70
+ */
71
+ filterOption?: boolean | ((input: string, option: SelectOption<Value>) => boolean);
67
72
  id?: string;
68
73
  labelRender?: (option: SelectOption<Value>) => ReactNode;
69
74
  /**
@@ -76,6 +81,8 @@ interface SelectProps<Value = string> extends Pick<VirtualListProps, 'virtual' |
76
81
  name?: string;
77
82
  onChange?: (value: Value | Value[] | null | undefined, option?: SelectOption<Value> | SelectOption<Value>[]) => void;
78
83
  onOpenChange?: (open: boolean, eventDetails?: SelectRootChangeEventDetails) => void;
84
+ /** Called with the search text as it is typed (`showSearch`). */
85
+ onSearch?: (value: string) => void;
79
86
  onSelect?: (value: Value, option?: SelectOption<Value>) => void;
80
87
  open?: boolean;
81
88
  optionRender?: (option: SelectOption<Value>, info: {
@@ -114,6 +114,8 @@ const TableInner = (props) => {
114
114
  const rawColumns = useMemo(() => columnsProp ?? convertChildrenToColumns(children), [columnsProp, children]);
115
115
  const columns = useMemo(() => fillColumns(rawColumns, columnDefaults), [rawColumns, columnDefaults]);
116
116
  assertColumnKeys(columns);
117
+ /** Multi-level headers get column dividers; plain tables never do. */
118
+ const grouped = useMemo(() => columns.some((column) => Array.isArray(column.children) && column.children.length > 0), [columns]);
117
119
  const needResponsive = useMemo(() => flattenColumns(columns).some(({ column }) => column.responsive), [columns]);
118
120
  const screens = useBreakpoint(needResponsive);
119
121
  const hasRowSelection = Boolean(rowSelection);
@@ -448,7 +450,7 @@ const TableInner = (props) => {
448
450
  tableLayout: mergedTableLayout,
449
451
  title,
450
452
  transformColumns: transformSelectionColumns,
451
- className: cx(styles.table, sizeClassName[size], `${PREFIX_CLS}-${size === "middle" ? "medium" : size}`, variant === "outlined" && styles.outlined, variant === "filled" && styles.filled, `${PREFIX_CLS}-${variant}`, rowHoverable && styles.hoverable),
453
+ className: cx(styles.table, sizeClassName[size], `${PREFIX_CLS}-${size === "middle" ? "medium" : size}`, variant === "borderless" && styles.borderless, variant === "outlined" && styles.outlined, grouped && styles.grouped, variant === "filled" && styles.filled, `${PREFIX_CLS}-${variant}`, rowHoverable && styles.hoverable),
452
454
  classNames: {
453
455
  body: mergedClassNames.body,
454
456
  content: mergedClassNames.content,