@lobehub/ui 5.62.1 → 5.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/base-ui/Input/style.d.mts +1 -1
- package/es/base-ui/Pagination/Pagination.mjs +20 -3
- package/es/base-ui/Pagination/Pagination.mjs.map +1 -1
- package/es/base-ui/Pagination/style.mjs +47 -3
- package/es/base-ui/Pagination/style.mjs.map +1 -1
- package/es/base-ui/ProTable/FieldControl.mjs +10 -3
- package/es/base-ui/ProTable/FieldControl.mjs.map +1 -1
- package/es/base-ui/ProTable/LightFilter.mjs +6 -3
- package/es/base-ui/ProTable/LightFilter.mjs.map +1 -1
- package/es/base-ui/ProTable/ProTable.d.mts +4 -5
- package/es/base-ui/ProTable/ProTable.mjs +38 -31
- package/es/base-ui/ProTable/ProTable.mjs.map +1 -1
- package/es/base-ui/ProTable/SearchForm.mjs +59 -6
- package/es/base-ui/ProTable/SearchForm.mjs.map +1 -1
- package/es/base-ui/ProTable/index.d.mts +3 -2
- package/es/base-ui/ProTable/index.mjs +3 -1
- package/es/base-ui/ProTable/locale.d.mts +18 -0
- package/es/base-ui/ProTable/locale.mjs +68 -0
- package/es/base-ui/ProTable/locale.mjs.map +1 -0
- package/es/base-ui/ProTable/style.mjs +38 -0
- package/es/base-ui/ProTable/style.mjs.map +1 -1
- package/es/base-ui/ProTable/type.d.mts +66 -10
- package/es/base-ui/ProTable/useColumnRequest.mjs +61 -0
- package/es/base-ui/ProTable/useColumnRequest.mjs.map +1 -0
- package/es/base-ui/ProTable/useFetchData.mjs.map +1 -1
- package/es/base-ui/Select/Select.mjs +3 -1
- package/es/base-ui/Select/Select.mjs.map +1 -1
- package/es/base-ui/Select/hooks.mjs +8 -4
- package/es/base-ui/Select/hooks.mjs.map +1 -1
- package/es/base-ui/Select/type.d.mts +7 -0
- package/es/base-ui/Table/Table.mjs +3 -1
- package/es/base-ui/Table/Table.mjs.map +1 -1
- package/es/base-ui/Table/style.mjs +109 -18
- package/es/base-ui/Table/style.mjs.map +1 -1
- package/es/base-ui/Text/style.d.mts +1 -1
- package/es/dashboard/FilterStrip/style.mjs +1 -1
- package/es/dashboard/FilterStrip/style.mjs.map +1 -1
- package/es/dashboard/MetricStrip/style.mjs +1 -1
- package/es/dashboard/MetricStrip/style.mjs.map +1 -1
- package/es/dashboard/PageSkeleton/style.mjs +2 -1
- package/es/dashboard/PageSkeleton/style.mjs.map +1 -1
- package/es/dashboard/Surface/Surface.mjs +1 -2
- package/es/dashboard/Surface/Surface.mjs.map +1 -1
- package/es/dashboard/Surface/style.d.mts +10 -5
- package/es/dashboard/Surface/style.mjs +17 -13
- package/es/dashboard/Surface/style.mjs.map +1 -1
- 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
|
-
|
|
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:
|
|
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
|
-
/**
|
|
207
|
-
|
|
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
|
-
/**
|
|
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
|
|
286
|
-
|
|
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
|
|
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":";;;;;;;;;;;;;AA+BA,MAAMA,WAAS,MACZ,EACC,YACA,WACA,WACA,YACA,aACA,cACA,UACA,IACA,aACA,aAAa,KACb,gBACA,SACA,MACA,MACA,UACA,cACA,UACA,MACA,cACA,SACA,aACA,gBACA,uBACA,QACA,UACA,UACA,kBAAkB,WAClB,2BAA2B,SAC3B,QACA,YACA,OAAO,UACP,OACA,YACA,iBACA,iBACA,OACA,SACA,cACI;CACJ,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,kBAAkB,YAAY,aAAa,WAAW;CAC5D,MAAM,SAAS,SAAS;CACxB,MAAM,aAAa,SAAS,cAAc,SAAS;CACnD,MAAM,gBAAgB,oBAAoB;CAE1C,MAAM,CAAC,cAAc,mBAAmB,SAA8B,CAAC,CAAC;CAExE,gBAAgB;EACd,IAAI,SAAS,UAAU,aAAa,SAAS,GAC3C,gBAAgB,CAAC,CAAC;CAEtB,GAAG,CAAC,MAAM,aAAa,MAAM,CAAC;CAE9B,MAAM,EACJ,iBACA,WACA,mBACA,iBACA,gBACA,oBACA,iBACA,eACE,eAAe;EACjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,kBAAkB,eAAe,cAAc;EAAE;EAAa;EAAc;CAAK,CAAC;CAE1F,MAAM,kBAAkB,aACrB,UACC,kBAAkB,WAAW,QAAQ,GAAG,cAAc,cAAc,KAAK,CAAC,GAC5E,CAAC,mBAAmB,UAAU,CAChC;CAEA,MAAM,EACJ,iBACA,oBACA,qBACA,aACA,kBACA,0BACE,gBAAgB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAKD,MAAM,wBAAwB,aAC3B,WAAgB,iBAAuC;EACtD,IAAI,UAAU,CAAC,YAAY;EAC3B,IAAI,4BAA4B;GAAE;GAAY,QAAQ,cAAc;GAAQ;EAAY,CAAC,GACvF;EACF,kBAAkB,SAAS;CAC7B,GACA;EAAC;EAAmB;EAAQ;EAAY;CAAW,CACrD;CAEA,MAAM,eAAe,iBAAiB;EACpC;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,kBAAkB,mBAAmB;CAE3C,MAAM,cAAc,cAEhB,2BAA2B;EACzB;EACA;EACA;EACA;EACA;EACA,eAAe;EACf,aAAa,SAAS,KAAA,IAAY;CACpC,CAAC,GACH;EAAC;EAAW;EAAiB;EAAY;EAAQ;EAAa;EAAgB;CAAW,CAC3F;CAEA,MAAM,WAAW,aAAa,WAAW,SAAS,IAAI,CAAC,aAAa,eAAe;CACnF,MAAM,YAAY,QAAQ,cAAc,YAAY,CAAC,YAAY,CAAC,QAAQ;CAE1E,MAAM,cAAc,aACjB,UAAsB;EACrB,MAAM,eAAe;EACrB,MAAM,gBAAgB;EACtB,kBAAkB,aAAa,CAAC,IAAI,IAAI;CAC1C,GACA,CAAC,mBAAmB,UAAU,CAChC;CAEA,MAAM,aAAa,cAAc,gBAAgB,MAAM,GAAG,CAAC,MAAM,CAAC;CAClE,MAAM,iBAAiB,cACf,kBAAkB,YAAY,iBAAiB,OAAO,GAC5D;EAAC;EAAS;EAAY;CAAe,CACvC;CAEA,MAAM,aAAa,cAAc;EAC/B,MAAM,YAAY,gBAAgB,SAAS,GAAG,WAAW;EACzD,MAAM,YAAiC;GACrC,UAAU;GACV,UAAU;IACT,mCAA0C;EAC7C;EAEA,IAAI,0BAA0B,KAAA,KAAa,0BAA0B,MACnE,OAAO;EAET,IAAI,OAAO,0BAA0B,UACnC,OAAO;GACL,GAAG;GACH,UAAU;GACV,OAAO;EACT;EAEF,OAAO;GAAE,GAAG;GAAW,UAAU;EAAc;CACjD,GAAG;EAAC;EAAe;EAAY;CAAqB,CAAC;CAErD,MAAM,mBAAmB,GACvB,gBAAgB;EAAE;EAAQ;EAAM,SAAS;CAAgB,CAAC,GAC1D,WACA,YAAY,MACZ,YAAY,OACd;CAEA,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,oBAAoB,GACxB,eAAeC,OAAW,cAAcA,OAAW,OACnDC,SAAO,UACP,YAAY,QACd;CAEA,MAAM,UAAU,gBAAgB,WAAW;CAC3C,MAAM,cAAc,UAClB,oBAAC,cAAD,EAA0B,WAAa,CAAA,IAEvC,cAAc;EACZ;EACA;EACA,OAAO;EACP;EACA;EACA;CACF,CAAC;CAGH,OACE,qBAACC,OAAW,MAAZ;EACY;EACN;EACJ,OAAO;EACP,UAAU;EACJ;EACN,MAAM;EACI;EACA;EACV,OAAO;EACP,cAAc;EACd,eAAe;EAXjB,UAAA,CAaE,qBAACA,OAAW,SAAZ;GACE,WAAW,CAAC,UAAU;GACtB,WAAW;GACD;GACV,cAAc,CAAC;GACf,QAAQ,SAAS,oBAAC,OAAD,CAAM,CAAA,IAAI,KAAA;GACpB;GANT,UAAA;IAQG,eAAe,QAAQ,eAAe,KAAA,KACrC,oBAAC,QAAD;KAAM,WAAW,GAAGD,SAAO,QAAQ,YAAY,MAAM;KAAI,UAAA;IAAiB,CAAA;IAE5E,oBAACC,OAAW,OAAZ;KACE,WAAW,GAAGD,SAAO,OAAO,UAAUA,SAAO,WAAW,YAAY,KAAK;KAExE,UAAA;IACe,CAAA;IACjB,UACC,oBAAC,mBAAD;KACE,QAAA;KACW;KACC;KACF;KACV,aAAa,WAAW,WAAW,IAAI,cAAc,KAAA;KAC3C;KACV,iBAAiB;KACjB,OAAO;KACP,UAAU;KACV,WAAW;IACZ,CAAA;IAEH,oBAAC,qBAAD;KACc;KACD;KACK;KAChB,SAAS;IACV,CAAA;GACiB;EAEpB,CAAA,GAAA,oBAACC,OAAW,QAAZ;GAAmB,WAAW;GAC5B,UAAA,oBAAC,kBAAD;IACE,OAAM;IACN,sBAAsB;IACtB,WAAWD,SAAO;IAClB,MAAK;IACL,YAAY;IAEZ,UAAA,qBAACC,OAAW,OAAZ;KACE,OAAO;KACP,WAAW,GACTF,OAAW,OACXC,SAAO,OACP,gBACA,YAAY,OACZ,YAAY,QACd;KARF,UAAA,CAUG,oBAAoB,CAAC,UACpB,oBAAC,mBAAD;MACc;MACC;MACb,iBAAiB;MACjB,OAAO;MACP,UAAU;MACV,WAAW;KACZ,CAAA,GAEH,oBAAC,mBAAD;MACc;MACZ,WAAW,oBAAoB,CAAC;MACvB;MACI;MACG;MACP;MACK;KACf,CAAA,CACe;;GACF,CAAA;EACD,CAAA,CACJ;;AAErB,CACF;AAEA,SAAO,cAAc"}
|
|
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) =>
|
|
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
|
|
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,
|