@lobehub/ui 5.60.0 → 5.61.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/EmojiPicker/AvatarUploader.mjs +1 -1
- package/es/Form/components/FormSubmitFooter.mjs +1 -1
- package/es/base-ui/Pagination/Pagination.mjs +158 -41
- package/es/base-ui/Pagination/Pagination.mjs.map +1 -1
- package/es/base-ui/Pagination/helpers.mjs +3 -3
- package/es/base-ui/Pagination/helpers.mjs.map +1 -1
- package/es/base-ui/Pagination/index.d.mts +2 -2
- package/es/base-ui/Pagination/style.mjs +39 -0
- package/es/base-ui/Pagination/style.mjs.map +1 -1
- package/es/base-ui/Pagination/type.d.mts +42 -4
- package/es/base-ui/QRCode/QRCode.mjs +1 -1
- package/es/base-ui/Select/Select.mjs +15 -8
- package/es/base-ui/Select/Select.mjs.map +1 -1
- package/es/base-ui/Select/helpers.mjs +8 -1
- package/es/base-ui/Select/helpers.mjs.map +1 -1
- package/es/base-ui/Table/Column.d.mts +9 -0
- package/es/base-ui/Table/Column.mjs +7 -0
- package/es/base-ui/Table/Column.mjs.map +1 -0
- package/es/base-ui/Table/ColumnGroup.d.mts +12 -0
- package/es/base-ui/Table/ColumnGroup.mjs +7 -0
- package/es/base-ui/Table/ColumnGroup.mjs.map +1 -0
- package/es/base-ui/Table/ExpandIcon.mjs +33 -0
- package/es/base-ui/Table/ExpandIcon.mjs.map +1 -0
- package/es/base-ui/Table/FilterDropdown.mjs +284 -0
- package/es/base-ui/Table/FilterDropdown.mjs.map +1 -0
- package/es/base-ui/Table/LoadingSkeleton.mjs +83 -0
- package/es/base-ui/Table/LoadingSkeleton.mjs.map +1 -0
- package/es/base-ui/Table/Table.d.mts +21 -3
- package/es/base-ui/Table/Table.mjs +444 -97
- package/es/base-ui/Table/Table.mjs.map +1 -1
- package/es/base-ui/Table/columnUtils.mjs +56 -0
- package/es/base-ui/Table/columnUtils.mjs.map +1 -0
- package/es/base-ui/Table/index.d.mts +4 -2
- package/es/base-ui/Table/selectionUtils.d.mts +9 -0
- package/es/base-ui/Table/selectionUtils.mjs +128 -0
- package/es/base-ui/Table/selectionUtils.mjs.map +1 -0
- package/es/base-ui/Table/semantic.mjs +55 -0
- package/es/base-ui/Table/semantic.mjs.map +1 -0
- package/es/base-ui/Table/style.mjs +801 -161
- package/es/base-ui/Table/style.mjs.map +1 -1
- package/es/base-ui/Table/type.d.mts +471 -37
- package/es/base-ui/Table/useBreakpoint.mjs +41 -0
- package/es/base-ui/Table/useBreakpoint.mjs.map +1 -0
- package/es/base-ui/Table/useFilter.mjs +64 -0
- package/es/base-ui/Table/useFilter.mjs.map +1 -0
- package/es/base-ui/Table/useSelection.mjs +421 -0
- package/es/base-ui/Table/useSelection.mjs.map +1 -0
- package/es/base-ui/Table/useSorter.mjs +152 -0
- package/es/base-ui/Table/useSorter.mjs.map +1 -0
- package/es/base-ui/Table/useTableState.mjs +82 -55
- package/es/base-ui/Table/useTableState.mjs.map +1 -1
- package/es/base-ui/index.d.mts +6 -4
- package/es/base-ui/index.mjs +9 -9
- package/es/chat/EditableMessageList/EditableMessageList.mjs +1 -1
- package/es/chat/MessageInput/MessageInput.mjs +1 -1
- package/es/chat/MessageModal/MessageModal.mjs +1 -1
- package/es/chat/TokenTag/TokenTag.mjs +1 -1
- package/es/i18n/resources/en/index.d.mts +3 -2
- package/es/i18n/resources/en/index.mjs +4 -2
- package/es/i18n/resources/en/index.mjs.map +1 -1
- package/es/i18n/resources/en/table.d.mts +23 -0
- package/es/i18n/resources/en/table.mjs +24 -0
- package/es/i18n/resources/en/table.mjs.map +1 -0
- package/es/i18n/resources/zhCn/index.d.mts +3 -2
- package/es/i18n/resources/zhCn/index.mjs +4 -2
- package/es/i18n/resources/zhCn/index.mjs.map +1 -1
- package/es/i18n/resources/zhCn/table.d.mts +23 -0
- package/es/i18n/resources/zhCn/table.mjs +24 -0
- package/es/i18n/resources/zhCn/table.mjs.map +1 -0
- package/es/i18n/types.d.mts +2 -1
- package/es/index.mjs +2 -2
- package/package.json +2 -2
- package/es/base-ui/Table/FilterMenu.mjs +0 -45
- package/es/base-ui/Table/FilterMenu.mjs.map +0 -1
- package/es/base-ui/Table/TableBody.mjs +0 -59
- package/es/base-ui/Table/TableBody.mjs.map +0 -1
- package/es/base-ui/Table/TableHead.mjs +0 -50
- package/es/base-ui/Table/TableHead.mjs.map +0 -1
- package/es/base-ui/Table/features.mjs +0 -12
- package/es/base-ui/Table/features.mjs.map +0 -1
- package/es/base-ui/Table/fixedOffsets.mjs +0 -29
- package/es/base-ui/Table/fixedOffsets.mjs.map +0 -1
- package/es/base-ui/Table/toColumnDefs.mjs +0 -26
- package/es/base-ui/Table/toColumnDefs.mjs.map +0 -1
|
@@ -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 } 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 handleRootValueChange = useCallback(\n (nextValue: any) => {\n if (!(isTags && !mergedOpen)) handleValueChange(nextValue);\n },\n [handleValueChange, isTags, mergedOpen],\n );\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 const virtualState = useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n });\n\n const portalContainer = usePortalContainer();\n\n const renderValue = useMemo(\n () =>\n createTriggerValueRenderer({\n getOption,\n isMultiple,\n isTags,\n labelRender,\n normalizeValue,\n onRemoveValue: handleRemoveTag,\n placeholder: isTags ? undefined : placeholder,\n }),\n [getOption, handleRemoveTag, isMultiple, isTags, labelRender, normalizeValue, placeholder],\n );\n\n const hasValue = isMultiple ? valueArray.length > 0 : !isValueEmpty(normalizedValue);\n const showClear = Boolean(allowClear && hasValue && !disabled && !readOnly);\n\n const handleClear = useCallback(\n (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n handleValueChange(isMultiple ? [] : null);\n },\n [handleValueChange, isMultiple],\n );\n\n const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);\n const suffixIconNode = useMemo(\n () => resolveSuffixIcon(suffixIcon, suffixIconProps, loading),\n [loading, suffixIcon, suffixIconProps],\n );\n\n const popupStyle = useMemo(() => {\n const maxHeight = isItemAligned ? '80vh' : `${listHeight}px`;\n const baseStyle: React.CSSProperties = {\n maxWidth: 'var(--available-width)',\n minWidth: 'var(--anchor-width)',\n ['--lobe-select-popup-max-height' as any]: maxHeight,\n };\n\n if (popupMatchSelectWidth === undefined || popupMatchSelectWidth === true) {\n return baseStyle;\n }\n if (typeof popupMatchSelectWidth === 'number') {\n return {\n ...baseStyle,\n minWidth: popupMatchSelectWidth,\n width: popupMatchSelectWidth,\n };\n }\n return { ...baseStyle, minWidth: 'max-content' };\n }, [isItemAligned, listHeight, popupMatchSelectWidth]);\n\n const triggerClassName = cx(\n triggerVariants({ shadow, size, variant: resolvedVariant }),\n className,\n classNames?.root,\n classNames?.trigger,\n );\n\n const isBoldIndicator = selectedIndicatorVariant === 'bold';\n const itemTextClassName = cx(\n optionRender ? menuStyles.itemContent : menuStyles.label,\n styles.itemText,\n classNames?.itemText,\n );\n\n const isEmpty = filteredOptions.length === 0;\n const listContent = isEmpty ? (\n <EmptyContent classNames={classNames} />\n ) : (\n renderOptions({\n classNames,\n isBoldIndicator,\n items: filteredOptions,\n itemTextClassName,\n listItemHeight,\n optionRender,\n })\n );\n\n return (\n <BaseSelect.Root\n disabled={disabled}\n id={id}\n modal={isItemAligned}\n multiple={isMultiple}\n name={name}\n open={mergedOpen}\n readOnly={readOnly}\n required={required}\n value={normalizedValue}\n onOpenChange={handleOpenChange}\n onValueChange={handleRootValueChange}\n >\n <BaseSelect.Trigger\n autoFocus={!isTags && autoFocus}\n className={triggerClassName}\n disabled={disabled}\n nativeButton={!isTags}\n render={isTags ? <div /> : undefined}\n style={style}\n >\n {prefixNode !== null && prefixNode !== undefined && (\n <span className={cx(styles.prefix, classNames?.prefix)}>{prefixNode}</span>\n )}\n <BaseSelect.Value\n className={cx(styles.value, isTags && styles.tagsValue, classNames?.value)}\n >\n {renderValue}\n </BaseSelect.Value>\n {isTags && (\n <SelectSearchInput\n inline\n autoFocus={autoFocus}\n classNames={classNames}\n disabled={disabled}\n placeholder={valueArray.length === 0 ? placeholder : undefined}\n readOnly={readOnly}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectTriggerSuffix\n classNames={classNames}\n showClear={showClear}\n suffixIconNode={suffixIconNode}\n onClear={handleClear}\n />\n </BaseSelect.Trigger>\n\n <BaseSelect.Portal container={portalContainer}>\n <SelectPositioner\n align=\"start\"\n alignItemWithTrigger={isItemAligned}\n className={styles.positioner}\n side=\"bottom\"\n sideOffset={6}\n >\n <BaseSelect.Popup\n style={popupStyle}\n className={cx(\n menuStyles.popup,\n styles.popup,\n popupClassName,\n classNames?.popup,\n classNames?.dropdown,\n )}\n >\n {shouldShowSearch && !isTags && (\n <SelectSearchInput\n classNames={classNames}\n placeholder={placeholder}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectListSection\n classNames={classNames}\n hasSearch={shouldShowSearch && !isTags}\n isEmpty={isEmpty}\n listContent={listContent}\n listItemHeight={listItemHeight}\n virtual={virtual}\n virtualState={virtualState}\n />\n </BaseSelect.Popup>\n </SelectPositioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n );\n },\n);\n\nSelect.displayName = 'Select';\n\nexport default Select;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Select.mjs","names":["Select","menuStyles","styles","BaseSelect"],"sources":["../../../src/base-ui/Select/Select.tsx"],"sourcesContent":["'use client';\n\nimport { Select as BaseSelect } from '@base-ui/react/select';\nimport { cx, useThemeMode } from 'antd-style';\nimport { type MouseEvent } from 'react';\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { styles as menuStyles } from '@/base-ui/DropdownMenu/sharedStyle';\n\nimport { SelectPositioner } from './atoms';\nimport { isValueEmpty, shouldIgnoreRootValueChange } from './helpers';\nimport {\n usePortalContainer,\n useSelectOpen,\n useSelectSearch,\n useSelectValue,\n useSelectVirtual,\n} from './hooks';\nimport {\n createTriggerValueRenderer,\n EmptyContent,\n resolveIconNode,\n resolveSuffixIcon,\n SelectListSection,\n SelectSearchInput,\n SelectTriggerSuffix,\n} from './parts';\nimport { renderOptions } from './renderOptions';\nimport { styles, triggerVariants } from './style';\nimport { type SelectOption, type SelectProps } from './type';\n\nconst Select = memo<SelectProps<any>>(\n ({\n allowClear,\n autoFocus,\n className,\n classNames,\n defaultOpen,\n defaultValue,\n disabled,\n id,\n labelRender,\n listHeight = 512,\n listItemHeight,\n loading,\n mode,\n name,\n onChange,\n onOpenChange,\n onSelect,\n open,\n optionRender,\n options,\n placeholder,\n popupClassName,\n popupMatchSelectWidth,\n prefix,\n readOnly,\n required,\n behaviorVariant = 'default',\n selectedIndicatorVariant = 'check',\n shadow,\n showSearch,\n size = 'middle',\n style,\n suffixIcon,\n suffixIconProps,\n tokenSeparators,\n value,\n variant,\n virtual,\n }) => {\n const { isDarkMode } = useThemeMode();\n const resolvedVariant = variant ?? (isDarkMode ? 'filled' : 'outlined');\n const isTags = mode === 'tags';\n const isMultiple = mode === 'multiple' || mode === 'tags';\n const isItemAligned = behaviorVariant === 'item-aligned';\n\n const [extraOptions, setExtraOptions] = useState<SelectOption<any>[]>([]);\n\n useEffect(() => {\n if (mode !== 'tags' && extraOptions.length > 0) {\n setExtraOptions([]);\n }\n }, [mode, extraOptions.length]);\n\n const {\n appendTagValues,\n getOption,\n handleValueChange,\n normalizedValue,\n normalizeValue,\n removeLastTagValue,\n resolvedOptions,\n valueArray,\n } = useSelectValue({\n defaultValue,\n extraOptions,\n isMultiple,\n onChange,\n onSelect,\n options,\n setExtraOptions,\n value,\n });\n\n const { handleOpenChange, mergedOpen } = useSelectOpen({ defaultOpen, onOpenChange, open });\n\n const handleRemoveTag = useCallback(\n (index: number) =>\n handleValueChange(valueArray.filter((_, itemIndex) => itemIndex !== index)),\n [handleValueChange, valueArray],\n );\n\n const {\n filteredOptions,\n handleSearchChange,\n handleSearchKeyDown,\n searchValue,\n shouldShowSearch,\n stopSearchPropagation,\n } = useSelectSearch({\n appendTagValues,\n handleOpenChange,\n mergedOpen,\n mode,\n removeLastTagValue,\n resolvedOptions,\n showSearch,\n tokenSeparators,\n });\n\n // Base UI prunes selected values that are missing from the registered (filtered) options\n // and reports it with reason 'none'. Ignore it while open or while closing with a stale\n // search term, so searching never mutates the value. Closed typeahead stays valid.\n const handleRootValueChange = useCallback(\n (nextValue: any, eventDetails?: { reason?: string }) => {\n if (isTags && !mergedOpen) return;\n if (shouldIgnoreRootValueChange({ mergedOpen, reason: eventDetails?.reason, searchValue }))\n return;\n handleValueChange(nextValue);\n },\n [handleValueChange, isTags, mergedOpen, searchValue],\n );\n\n const virtualState = useSelectVirtual({\n filteredOptions,\n listItemHeight,\n size,\n valueArray,\n virtual,\n });\n\n const portalContainer = usePortalContainer();\n\n const renderValue = useMemo(\n () =>\n createTriggerValueRenderer({\n getOption,\n isMultiple,\n isTags,\n labelRender,\n normalizeValue,\n onRemoveValue: handleRemoveTag,\n placeholder: isTags ? undefined : placeholder,\n }),\n [getOption, handleRemoveTag, isMultiple, isTags, labelRender, normalizeValue, placeholder],\n );\n\n const hasValue = isMultiple ? valueArray.length > 0 : !isValueEmpty(normalizedValue);\n const showClear = Boolean(allowClear && hasValue && !disabled && !readOnly);\n\n const handleClear = useCallback(\n (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n handleValueChange(isMultiple ? [] : null);\n },\n [handleValueChange, isMultiple],\n );\n\n const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);\n const suffixIconNode = useMemo(\n () => resolveSuffixIcon(suffixIcon, suffixIconProps, loading),\n [loading, suffixIcon, suffixIconProps],\n );\n\n const popupStyle = useMemo(() => {\n const maxHeight = isItemAligned ? '80vh' : `${listHeight}px`;\n const baseStyle: React.CSSProperties = {\n maxWidth: 'var(--available-width)',\n minWidth: 'var(--anchor-width)',\n ['--lobe-select-popup-max-height' as any]: maxHeight,\n };\n\n if (popupMatchSelectWidth === undefined || popupMatchSelectWidth === true) {\n return baseStyle;\n }\n if (typeof popupMatchSelectWidth === 'number') {\n return {\n ...baseStyle,\n minWidth: popupMatchSelectWidth,\n width: popupMatchSelectWidth,\n };\n }\n return { ...baseStyle, minWidth: 'max-content' };\n }, [isItemAligned, listHeight, popupMatchSelectWidth]);\n\n const triggerClassName = cx(\n triggerVariants({ shadow, size, variant: resolvedVariant }),\n className,\n classNames?.root,\n classNames?.trigger,\n );\n\n const isBoldIndicator = selectedIndicatorVariant === 'bold';\n const itemTextClassName = cx(\n optionRender ? menuStyles.itemContent : menuStyles.label,\n styles.itemText,\n classNames?.itemText,\n );\n\n const isEmpty = filteredOptions.length === 0;\n const listContent = isEmpty ? (\n <EmptyContent classNames={classNames} />\n ) : (\n renderOptions({\n classNames,\n isBoldIndicator,\n items: filteredOptions,\n itemTextClassName,\n listItemHeight,\n optionRender,\n })\n );\n\n return (\n <BaseSelect.Root\n disabled={disabled}\n id={id}\n modal={isItemAligned}\n multiple={isMultiple}\n name={name}\n open={mergedOpen}\n readOnly={readOnly}\n required={required}\n value={normalizedValue}\n onOpenChange={handleOpenChange}\n onValueChange={handleRootValueChange}\n >\n <BaseSelect.Trigger\n autoFocus={!isTags && autoFocus}\n className={triggerClassName}\n disabled={disabled}\n nativeButton={!isTags}\n render={isTags ? <div /> : undefined}\n style={style}\n >\n {prefixNode !== null && prefixNode !== undefined && (\n <span className={cx(styles.prefix, classNames?.prefix)}>{prefixNode}</span>\n )}\n <BaseSelect.Value\n className={cx(styles.value, isTags && styles.tagsValue, classNames?.value)}\n >\n {renderValue}\n </BaseSelect.Value>\n {isTags && (\n <SelectSearchInput\n inline\n autoFocus={autoFocus}\n classNames={classNames}\n disabled={disabled}\n placeholder={valueArray.length === 0 ? placeholder : undefined}\n readOnly={readOnly}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectTriggerSuffix\n classNames={classNames}\n showClear={showClear}\n suffixIconNode={suffixIconNode}\n onClear={handleClear}\n />\n </BaseSelect.Trigger>\n\n <BaseSelect.Portal container={portalContainer}>\n <SelectPositioner\n align=\"start\"\n alignItemWithTrigger={isItemAligned}\n className={styles.positioner}\n side=\"bottom\"\n sideOffset={6}\n >\n <BaseSelect.Popup\n style={popupStyle}\n className={cx(\n menuStyles.popup,\n styles.popup,\n popupClassName,\n classNames?.popup,\n classNames?.dropdown,\n )}\n >\n {shouldShowSearch && !isTags && (\n <SelectSearchInput\n classNames={classNames}\n placeholder={placeholder}\n stopPropagation={stopSearchPropagation}\n value={searchValue}\n onChange={handleSearchChange}\n onKeyDown={handleSearchKeyDown}\n />\n )}\n <SelectListSection\n classNames={classNames}\n hasSearch={shouldShowSearch && !isTags}\n isEmpty={isEmpty}\n listContent={listContent}\n listItemHeight={listItemHeight}\n virtual={virtual}\n virtualState={virtualState}\n />\n </BaseSelect.Popup>\n </SelectPositioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n );\n },\n);\n\nSelect.displayName = 'Select';\n\nexport default Select;\n"],"mappings":"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"}
|
|
@@ -26,7 +26,14 @@ const normalizeValueFor = (isMultiple) => (nextValue) => {
|
|
|
26
26
|
if (Array.isArray(nextValue)) return nextValue[0] ?? null;
|
|
27
27
|
return nextValue === void 0 ? null : nextValue;
|
|
28
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Base UI reports value changes it derives itself (e.g. pruning selected values that are
|
|
31
|
+
* missing from the filtered options) with reason 'none'. While the popup is open, or while
|
|
32
|
+
* it is closing and the search term has not been reset yet, those are not user selections.
|
|
33
|
+
* A 'none' change on a fully closed select is a typeahead selection and stays valid.
|
|
34
|
+
*/
|
|
35
|
+
const shouldIgnoreRootValueChange = ({ mergedOpen, reason, searchValue }) => reason === "none" && (mergedOpen || searchValue !== "");
|
|
29
36
|
//#endregion
|
|
30
|
-
export { countVirtualItems, getOptionSearchText, isGroupOption, isValueEmpty, normalizeValueFor, splitBySeparators };
|
|
37
|
+
export { countVirtualItems, getOptionSearchText, isGroupOption, isValueEmpty, normalizeValueFor, shouldIgnoreRootValueChange, splitBySeparators };
|
|
31
38
|
|
|
32
39
|
//# sourceMappingURL=helpers.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.mjs","names":[],"sources":["../../../src/base-ui/Select/helpers.ts"],"sourcesContent":["import { type SelectOption, type SelectOptionGroup, type SelectOptions } from './type';\n\nexport const isGroupOption = <Value>(\n option: SelectOption<Value> | SelectOptionGroup<Value>,\n): option is SelectOptionGroup<Value> => Boolean((option as SelectOptionGroup<Value>).options);\n\nexport const getOptionSearchText = <Value>(option: SelectOption<Value>) => {\n if (typeof option.label === 'string' || typeof option.label === 'number') {\n return String(option.label);\n }\n if (option.title) return option.title;\n if (typeof option.value === 'string' || typeof option.value === 'number') {\n return String(option.value);\n }\n return '';\n};\n\nconst escapeRegExp = (value: string) => value.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&');\n\nexport const splitBySeparators = (value: string, separators?: string[]) => {\n if (!separators || separators.length === 0) return [value];\n const pattern = separators.map(escapeRegExp).join('|');\n return value.split(new RegExp(pattern, 'g'));\n};\n\nexport const countVirtualItems = (items: SelectOptions) =>\n items.reduce((count, item) => {\n if (isGroupOption(item)) {\n return count + item.options.length + 1;\n }\n return count + 1;\n }, 0);\n\nexport const isValueEmpty = (value: unknown) =>\n value === null || value === undefined || value === '';\n\nexport const normalizeValueFor = (isMultiple: boolean) => (nextValue: any) => {\n if (isMultiple) {\n if (Array.isArray(nextValue)) return nextValue;\n if (nextValue === null || nextValue === undefined) return [];\n return [nextValue];\n }\n if (Array.isArray(nextValue)) return nextValue[0] ?? null;\n return nextValue === undefined ? null : nextValue;\n};\n"],"mappings":";AAEA,MAAa,iBACX,WACuC,QAAS,OAAoC,OAAO;AAE7F,MAAa,uBAA8B,WAAgC;CACzE,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,UAC9D,OAAO,OAAO,OAAO,KAAK;CAE5B,IAAI,OAAO,OAAO,OAAO,OAAO;CAChC,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,UAC9D,OAAO,OAAO,OAAO,KAAK;CAE5B,OAAO;AACT;AAEA,MAAM,gBAAgB,UAAkB,MAAM,WAAW,uBAAuB,MAAM;AAEtF,MAAa,qBAAqB,OAAe,eAA0B;CACzE,IAAI,CAAC,cAAc,WAAW,WAAW,GAAG,OAAO,CAAC,KAAK;CACzD,MAAM,UAAU,WAAW,IAAI,YAAY,CAAC,CAAC,KAAK,GAAG;CACrD,OAAO,MAAM,MAAM,IAAI,OAAO,SAAS,GAAG,CAAC;AAC7C;AAEA,MAAa,qBAAqB,UAChC,MAAM,QAAQ,OAAO,SAAS;CAC5B,IAAI,cAAc,IAAI,GACpB,OAAO,QAAQ,KAAK,QAAQ,SAAS;CAEvC,OAAO,QAAQ;AACjB,GAAG,CAAC;AAEN,MAAa,gBAAgB,UAC3B,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU;AAErD,MAAa,qBAAqB,gBAAyB,cAAmB;CAC5E,IAAI,YAAY;EACd,IAAI,MAAM,QAAQ,SAAS,GAAG,OAAO;EACrC,IAAI,cAAc,QAAQ,cAAc,KAAA,GAAW,OAAO,CAAC;EAC3D,OAAO,CAAC,SAAS;CACnB;CACA,IAAI,MAAM,QAAQ,SAAS,GAAG,OAAO,UAAU,MAAM;CACrD,OAAO,cAAc,KAAA,IAAY,OAAO;AAC1C"}
|
|
1
|
+
{"version":3,"file":"helpers.mjs","names":[],"sources":["../../../src/base-ui/Select/helpers.ts"],"sourcesContent":["import { type SelectOption, type SelectOptionGroup, type SelectOptions } from './type';\n\nexport const isGroupOption = <Value>(\n option: SelectOption<Value> | SelectOptionGroup<Value>,\n): option is SelectOptionGroup<Value> => Boolean((option as SelectOptionGroup<Value>).options);\n\nexport const getOptionSearchText = <Value>(option: SelectOption<Value>) => {\n if (typeof option.label === 'string' || typeof option.label === 'number') {\n return String(option.label);\n }\n if (option.title) return option.title;\n if (typeof option.value === 'string' || typeof option.value === 'number') {\n return String(option.value);\n }\n return '';\n};\n\nconst escapeRegExp = (value: string) => value.replaceAll(/[$()*+.?[\\\\\\]^{|}]/g, '\\\\$&');\n\nexport const splitBySeparators = (value: string, separators?: string[]) => {\n if (!separators || separators.length === 0) return [value];\n const pattern = separators.map(escapeRegExp).join('|');\n return value.split(new RegExp(pattern, 'g'));\n};\n\nexport const countVirtualItems = (items: SelectOptions) =>\n items.reduce((count, item) => {\n if (isGroupOption(item)) {\n return count + item.options.length + 1;\n }\n return count + 1;\n }, 0);\n\nexport const isValueEmpty = (value: unknown) =>\n value === null || value === undefined || value === '';\n\nexport const normalizeValueFor = (isMultiple: boolean) => (nextValue: any) => {\n if (isMultiple) {\n if (Array.isArray(nextValue)) return nextValue;\n if (nextValue === null || nextValue === undefined) return [];\n return [nextValue];\n }\n if (Array.isArray(nextValue)) return nextValue[0] ?? null;\n return nextValue === undefined ? null : nextValue;\n};\n\n/**\n * Base UI reports value changes it derives itself (e.g. pruning selected values that are\n * missing from the filtered options) with reason 'none'. While the popup is open, or while\n * it is closing and the search term has not been reset yet, those are not user selections.\n * A 'none' change on a fully closed select is a typeahead selection and stays valid.\n */\nexport const shouldIgnoreRootValueChange = ({\n mergedOpen,\n reason,\n searchValue,\n}: {\n mergedOpen: boolean;\n reason?: string;\n searchValue: string;\n}) => reason === 'none' && (mergedOpen || searchValue !== '');\n"],"mappings":";AAEA,MAAa,iBACX,WACuC,QAAS,OAAoC,OAAO;AAE7F,MAAa,uBAA8B,WAAgC;CACzE,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,UAC9D,OAAO,OAAO,OAAO,KAAK;CAE5B,IAAI,OAAO,OAAO,OAAO,OAAO;CAChC,IAAI,OAAO,OAAO,UAAU,YAAY,OAAO,OAAO,UAAU,UAC9D,OAAO,OAAO,OAAO,KAAK;CAE5B,OAAO;AACT;AAEA,MAAM,gBAAgB,UAAkB,MAAM,WAAW,uBAAuB,MAAM;AAEtF,MAAa,qBAAqB,OAAe,eAA0B;CACzE,IAAI,CAAC,cAAc,WAAW,WAAW,GAAG,OAAO,CAAC,KAAK;CACzD,MAAM,UAAU,WAAW,IAAI,YAAY,CAAC,CAAC,KAAK,GAAG;CACrD,OAAO,MAAM,MAAM,IAAI,OAAO,SAAS,GAAG,CAAC;AAC7C;AAEA,MAAa,qBAAqB,UAChC,MAAM,QAAQ,OAAO,SAAS;CAC5B,IAAI,cAAc,IAAI,GACpB,OAAO,QAAQ,KAAK,QAAQ,SAAS;CAEvC,OAAO,QAAQ;AACjB,GAAG,CAAC;AAEN,MAAa,gBAAgB,UAC3B,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU;AAErD,MAAa,qBAAqB,gBAAyB,cAAmB;CAC5E,IAAI,YAAY;EACd,IAAI,MAAM,QAAQ,SAAS,GAAG,OAAO;EACrC,IAAI,cAAc,QAAQ,cAAc,KAAA,GAAW,OAAO,CAAC;EAC3D,OAAO,CAAC,SAAS;CACnB;CACA,IAAI,MAAM,QAAQ,SAAS,GAAG,OAAO,UAAU,MAAM;CACrD,OAAO,cAAc,KAAA,IAAY,OAAO;AAC1C;;;;;;;AAQA,MAAa,+BAA+B,EAC1C,YACA,QACA,kBAKI,WAAW,WAAW,cAAc,gBAAgB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TableColumnType } from "./type.mjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/base-ui/Table/Column.d.ts
|
|
4
|
+
type TableColumnProps<T> = TableColumnType<T>;
|
|
5
|
+
/** JSX sugar for one `columns` entry; `Table` reads its props and it renders nothing itself. */
|
|
6
|
+
declare const Column: <T>(_props: TableColumnProps<T>) => ReactNode;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { TableColumnProps, Column as default };
|
|
9
|
+
//# sourceMappingURL=Column.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Column.mjs","names":[],"sources":["../../../src/base-ui/Table/Column.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport type { TableColumnType } from './type';\n\nexport type TableColumnProps<T> = TableColumnType<T>;\n\n/** JSX sugar for one `columns` entry; `Table` reads its props and it renders nothing itself. */\nconst Column = <T,>(_props: TableColumnProps<T>): ReactNode => null;\n\nexport default Column;\n"],"mappings":";;AAOA,MAAM,UAAc,WAA2C"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TableColumnType } from "./type.mjs";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/base-ui/Table/ColumnGroup.d.ts
|
|
4
|
+
interface TableColumnGroupProps<T> extends Omit<TableColumnType<T>, 'dataIndex'> {
|
|
5
|
+
/** `Table.Column` / `Table.ColumnGroup` elements rendered under this header. */
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** JSX sugar for a grouped header; `Table` reads its props and it renders nothing itself. */
|
|
9
|
+
declare const ColumnGroup: <T>(_props: TableColumnGroupProps<T>) => ReactNode;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { TableColumnGroupProps, ColumnGroup as default };
|
|
12
|
+
//# sourceMappingURL=ColumnGroup.d.mts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/base-ui/Table/ColumnGroup.tsx
|
|
2
|
+
/** JSX sugar for a grouped header; `Table` reads its props and it renders nothing itself. */
|
|
3
|
+
const ColumnGroup = (_props) => null;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { ColumnGroup as default };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=ColumnGroup.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColumnGroup.mjs","names":[],"sources":["../../../src/base-ui/Table/ColumnGroup.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport type { TableColumnType } from './type';\n\nexport interface TableColumnGroupProps<T> extends Omit<TableColumnType<T>, 'dataIndex'> {\n /** `Table.Column` / `Table.ColumnGroup` elements rendered under this header. */\n children: ReactNode;\n}\n\n/** JSX sugar for a grouped header; `Table` reads its props and it renders nothing itself. */\nconst ColumnGroup = <T,>(_props: TableColumnGroupProps<T>): ReactNode => null;\n\nexport default ColumnGroup;\n"],"mappings":";;AAUA,MAAM,eAAmB,WAAgD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import ActionIcon from "../ActionIcon/ActionIcon.mjs";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { cx } from "antd-style";
|
|
5
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
6
|
+
//#region src/base-ui/Table/ExpandIcon.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Default expand toggle: a small borderless `ActionIcon` (chevron right / down, swapped without a
|
|
9
|
+
* transition). Rows that cannot expand keep an invisible spacer of the same size so tree rows line
|
|
10
|
+
* up. Mirrors antd `ExpandIcon`.
|
|
11
|
+
*/
|
|
12
|
+
const renderExpandIcon = ({ expandable, expanded, onExpand, prefixCls, record }, locale) => {
|
|
13
|
+
const iconCls = `${prefixCls}-row-expand-icon`;
|
|
14
|
+
if (!expandable) return /* @__PURE__ */ jsx("span", {
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
className: cx(iconCls, `${iconCls}-spaced`)
|
|
17
|
+
});
|
|
18
|
+
return /* @__PURE__ */ jsx(ActionIcon, {
|
|
19
|
+
"aria-expanded": expanded,
|
|
20
|
+
"aria-label": expanded ? locale.collapse : locale.expand,
|
|
21
|
+
className: cx(iconCls, expanded ? `${iconCls}-expanded` : `${iconCls}-collapsed`),
|
|
22
|
+
icon: expanded ? ChevronDown : ChevronRight,
|
|
23
|
+
size: "small",
|
|
24
|
+
onClick: (event) => {
|
|
25
|
+
onExpand(record, event);
|
|
26
|
+
event.stopPropagation();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { renderExpandIcon as default };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=ExpandIcon.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpandIcon.mjs","names":[],"sources":["../../../src/base-ui/Table/ExpandIcon.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { ChevronDown, ChevronRight } from 'lucide-react';\nimport type { MouseEvent, ReactNode } from 'react';\n\nimport ActionIcon from '@/base-ui/ActionIcon';\n\nimport type { TableExpandIconProps, TableLocale } from './type';\n\n/**\n * Default expand toggle: a small borderless `ActionIcon` (chevron right / down, swapped without a\n * transition). Rows that cannot expand keep an invisible spacer of the same size so tree rows line\n * up. Mirrors antd `ExpandIcon`.\n */\nconst renderExpandIcon = <T,>(\n { expandable, expanded, onExpand, prefixCls, record }: TableExpandIconProps<T>,\n locale: Pick<TableLocale, 'collapse' | 'expand'>,\n): ReactNode => {\n const iconCls = `${prefixCls}-row-expand-icon`;\n if (!expandable) {\n return <span aria-hidden=\"true\" className={cx(iconCls, `${iconCls}-spaced`)} />;\n }\n return (\n <ActionIcon\n aria-expanded={expanded}\n aria-label={expanded ? locale.collapse : locale.expand}\n className={cx(iconCls, expanded ? `${iconCls}-expanded` : `${iconCls}-collapsed`)}\n icon={expanded ? ChevronDown : ChevronRight}\n size=\"small\"\n onClick={(event) => {\n onExpand(record, event as unknown as MouseEvent<HTMLElement>);\n event.stopPropagation();\n }}\n />\n );\n};\n\nexport default renderExpandIcon;\n"],"mappings":";;;;;;;;;;;AAeA,MAAM,oBACJ,EAAE,YAAY,UAAU,UAAU,WAAW,UAC7C,WACc;CACd,MAAM,UAAU,GAAG,UAAU;CAC7B,IAAI,CAAC,YACH,OAAO,oBAAC,QAAD;EAAM,eAAY;EAAO,WAAW,GAAG,SAAS,GAAG,QAAQ,QAAQ;CAAI,CAAA;CAEhF,OACE,oBAAC,YAAD;EACE,iBAAe;EACf,cAAY,WAAW,OAAO,WAAW,OAAO;EAChD,WAAW,GAAG,SAAS,WAAW,GAAG,QAAQ,aAAa,GAAG,QAAQ,WAAW;EAChF,MAAM,WAAW,cAAc;EAC/B,MAAK;EACL,UAAU,UAAU;GAClB,SAAS,QAAQ,KAA2C;GAC5D,MAAM,gBAAgB;EACxB;CACD,CAAA;AAEL"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import Icon from "../../Icon/Icon.mjs";
|
|
3
|
+
import Button from "../Button/Button.mjs";
|
|
4
|
+
import ActionIcon from "../ActionIcon/ActionIcon.mjs";
|
|
5
|
+
import Input_default from "../Input/Input.mjs";
|
|
6
|
+
import { PopoverPopup, PopoverPortal, PopoverPositioner, PopoverRoot, PopoverTriggerElement } from "../Popover/atoms.mjs";
|
|
7
|
+
import Empty from "../../Empty/Empty.mjs";
|
|
8
|
+
import Checkbox_default from "../Checkbox/Checkbox.mjs";
|
|
9
|
+
import Radio from "../Radio/Radio.mjs";
|
|
10
|
+
import { conductCheck, getAllKeys } from "../Tree/utils.mjs";
|
|
11
|
+
import Tree from "../Tree/Tree.mjs";
|
|
12
|
+
import { PREFIX_CLS, styles } from "./style.mjs";
|
|
13
|
+
import { flattenFilterKeys } from "./useFilter.mjs";
|
|
14
|
+
import { createContext, use, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
15
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
import { cx } from "antd-style";
|
|
17
|
+
import { ListFilter, Search } from "lucide-react";
|
|
18
|
+
import { RadioGroup } from "@base-ui/react/radio-group";
|
|
19
|
+
//#region src/base-ui/Table/FilterDropdown.tsx
|
|
20
|
+
const FILTER_CLS = `${PREFIX_CLS}-filter`;
|
|
21
|
+
/** True inside rc-table's hidden measure row, where only a static trigger is rendered. */
|
|
22
|
+
const TableMeasureRowContext = createContext(false);
|
|
23
|
+
const sameKeys = (a, b) => (a ?? null) === (b ?? null) || Boolean(a) && Boolean(b) && a.length === b.length && a.every((key, i) => key === b[i]);
|
|
24
|
+
const textMatches = (search, text) => (typeof text === "string" || typeof text === "number") && String(text).toLowerCase().includes(search);
|
|
25
|
+
const DEPRECATED_PROPS = [["filterDropdownOpen", "filterDropdownProps.open"], ["onFilterDropdownOpenChange", "filterDropdownProps.onOpenChange"]];
|
|
26
|
+
const warnedProps = /* @__PURE__ */ new Set();
|
|
27
|
+
/** Warns once per deprecated column prop, in development (antd `warning.deprecated`). */
|
|
28
|
+
const warnDeprecated = (column) => {
|
|
29
|
+
if (process.env.NODE_ENV === "production") return;
|
|
30
|
+
for (const [name, replacement] of DEPRECATED_PROPS) if (name in column && !warnedProps.has(name)) {
|
|
31
|
+
warnedProps.add(name);
|
|
32
|
+
console.warn(`[Table] \`${name}\` is deprecated. Please use \`${replacement}\` instead.`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/** Keys of `key` and its descendants, plus the keys of its ancestors. */
|
|
36
|
+
const findLineage = (nodes, key, ancestors = []) => {
|
|
37
|
+
for (const node of nodes) {
|
|
38
|
+
if (node.key === key) return {
|
|
39
|
+
ancestors,
|
|
40
|
+
subtree: getAllKeys([node])
|
|
41
|
+
};
|
|
42
|
+
const found = node.children && findLineage(node.children, key, [...ancestors, node.key]);
|
|
43
|
+
if (found) return found;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
/** Draft keys that re-render on write and can be read synchronously (antd `useSyncState`). */
|
|
47
|
+
const useSyncKeys = (initial) => {
|
|
48
|
+
const ref = useRef(initial);
|
|
49
|
+
const [, rerender] = useReducer((count) => count + 1, 0);
|
|
50
|
+
return [() => ref.current, (next) => {
|
|
51
|
+
ref.current = next;
|
|
52
|
+
rerender();
|
|
53
|
+
}];
|
|
54
|
+
};
|
|
55
|
+
const FilterDropdown = ({ column, columnKey, filterState, getPopupContainer, label, locale, triggerFilter }) => {
|
|
56
|
+
const { defaultFilteredValue, filterDropdown, filterDropdownOpen, filterDropdownProps = {}, filterIcon, filterMode = "menu", filterMultiple = true, filterOnClose = true, filterResetToDefaultFilteredValue, filters, filterSearch = false, onFilterDropdownOpenChange } = column;
|
|
57
|
+
const inMeasureRow = use(TableMeasureRowContext);
|
|
58
|
+
warnDeprecated(column);
|
|
59
|
+
const triggerRef = useRef(null);
|
|
60
|
+
const [visible, setVisible] = useState(false);
|
|
61
|
+
const [searchValue, setSearchValue] = useState("");
|
|
62
|
+
const normalizedSearch = searchValue.trim().toLowerCase();
|
|
63
|
+
const mergedVisible = filterDropdownProps.open ?? filterDropdownOpen ?? visible;
|
|
64
|
+
const filtered = Boolean(filterState?.filteredKeys?.length || filterState?.forceFiltered);
|
|
65
|
+
const triggerOpen = (next) => {
|
|
66
|
+
setVisible(next);
|
|
67
|
+
setSearchValue("");
|
|
68
|
+
filterDropdownProps.onOpenChange?.(next);
|
|
69
|
+
onFilterDropdownOpenChange?.(next);
|
|
70
|
+
};
|
|
71
|
+
const propFilteredKeys = filterState?.filteredKeys;
|
|
72
|
+
const [getSelectedKeys, setSelectedKeys] = useSyncKeys(propFilteredKeys ?? []);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (mergedVisible) setSelectedKeys(propFilteredKeys ?? []);
|
|
75
|
+
}, [propFilteredKeys, mergedVisible]);
|
|
76
|
+
const internalTriggerFilter = (keys) => {
|
|
77
|
+
const mergedKeys = keys?.length ? keys : null;
|
|
78
|
+
if (mergedKeys === null && !propFilteredKeys) return;
|
|
79
|
+
if (sameKeys(mergedKeys, propFilteredKeys)) return;
|
|
80
|
+
triggerFilter(columnKey, mergedKeys);
|
|
81
|
+
};
|
|
82
|
+
const onConfirm = () => {
|
|
83
|
+
triggerOpen(false);
|
|
84
|
+
internalTriggerFilter(getSelectedKeys());
|
|
85
|
+
};
|
|
86
|
+
const onReset = ({ closeDropdown = false, confirm = false } = {}) => {
|
|
87
|
+
if (confirm) internalTriggerFilter([]);
|
|
88
|
+
if (closeDropdown) triggerOpen(false);
|
|
89
|
+
setSearchValue("");
|
|
90
|
+
setSelectedKeys(filterResetToDefaultFilteredValue ? (defaultFilteredValue ?? []).map(String) : []);
|
|
91
|
+
};
|
|
92
|
+
const doFilter = ({ closeDropdown = true } = {}) => {
|
|
93
|
+
if (closeDropdown) triggerOpen(false);
|
|
94
|
+
internalTriggerFilter(getSelectedKeys());
|
|
95
|
+
};
|
|
96
|
+
/** Opening / closing from the trigger, an outside press or Escape. */
|
|
97
|
+
const onPopoverOpenChange = (next) => {
|
|
98
|
+
if (next && propFilteredKeys !== void 0) setSelectedKeys(propFilteredKeys ?? []);
|
|
99
|
+
if (!next && !filterDropdown && filterOnClose) onConfirm();
|
|
100
|
+
else triggerOpen(next);
|
|
101
|
+
};
|
|
102
|
+
const selectedKeys = getSelectedKeys();
|
|
103
|
+
const selectedSet = new Set(selectedKeys.map(String));
|
|
104
|
+
const allKeys = useMemo(() => flattenFilterKeys(filters).map(String), [filters]);
|
|
105
|
+
const matches = (item) => typeof filterSearch === "function" ? filterSearch(normalizedSearch, item) : textMatches(normalizedSearch, item.text);
|
|
106
|
+
const toggleKey = (key, checked) => {
|
|
107
|
+
if (!filterMultiple) return setSelectedKeys(checked ? [key] : []);
|
|
108
|
+
const rest = selectedKeys.filter((item) => String(item) !== key);
|
|
109
|
+
setSelectedKeys(checked ? [...rest, key] : rest);
|
|
110
|
+
};
|
|
111
|
+
const renderMenuItems = (items) => items.flatMap((item, index) => {
|
|
112
|
+
const key = String(item.value);
|
|
113
|
+
if (item.children) {
|
|
114
|
+
const children = renderMenuItems(item.children);
|
|
115
|
+
if (children.length === 0) return [];
|
|
116
|
+
return [/* @__PURE__ */ jsxs("div", {
|
|
117
|
+
className: styles.filterGroup,
|
|
118
|
+
role: "group",
|
|
119
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
120
|
+
className: cx(styles.filterGroupTitle, `${FILTER_CLS}-dropdown-submenu-title`),
|
|
121
|
+
children: item.text
|
|
122
|
+
}), children]
|
|
123
|
+
}, key || index)];
|
|
124
|
+
}
|
|
125
|
+
if (normalizedSearch && !matches(item)) return [];
|
|
126
|
+
return [/* @__PURE__ */ jsx("div", {
|
|
127
|
+
className: cx(styles.filterItem, `${FILTER_CLS}-dropdown-item`),
|
|
128
|
+
children: filterMultiple ? /* @__PURE__ */ jsx(Checkbox_default, {
|
|
129
|
+
checked: selectedSet.has(key),
|
|
130
|
+
onChange: (checked) => toggleKey(key, checked),
|
|
131
|
+
children: item.text
|
|
132
|
+
}) : /* @__PURE__ */ jsx(Radio, {
|
|
133
|
+
value: key,
|
|
134
|
+
children: item.text
|
|
135
|
+
})
|
|
136
|
+
}, key)];
|
|
137
|
+
});
|
|
138
|
+
const toTreeData = (items, ancestorMatched = false) => (items ?? []).flatMap((item, index) => {
|
|
139
|
+
const selfMatched = ancestorMatched || !normalizedSearch || matches(item);
|
|
140
|
+
const children = item.children ? toTreeData(item.children, selfMatched) : void 0;
|
|
141
|
+
if (!selfMatched && !children?.length) return [];
|
|
142
|
+
return [{
|
|
143
|
+
children,
|
|
144
|
+
key: item.value !== void 0 ? String(item.value) : String(index),
|
|
145
|
+
title: item.text
|
|
146
|
+
}];
|
|
147
|
+
});
|
|
148
|
+
const renderSearch = () => filterSearch ? /* @__PURE__ */ jsx("div", {
|
|
149
|
+
className: cx(styles.filterSearch, `${PREFIX_CLS}-filter-dropdown-search`),
|
|
150
|
+
children: /* @__PURE__ */ jsx(Input_default, {
|
|
151
|
+
allowClear: true,
|
|
152
|
+
placeholder: locale.filterSearchPlaceholder,
|
|
153
|
+
prefix: /* @__PURE__ */ jsx(Icon, {
|
|
154
|
+
icon: Search,
|
|
155
|
+
size: 14
|
|
156
|
+
}),
|
|
157
|
+
size: "small",
|
|
158
|
+
value: searchValue,
|
|
159
|
+
onChange: (event) => setSearchValue(event.target.value)
|
|
160
|
+
})
|
|
161
|
+
}) : null;
|
|
162
|
+
const empty = /* @__PURE__ */ jsx(Empty, {
|
|
163
|
+
className: styles.filterEmpty,
|
|
164
|
+
description: locale.filterEmptyText,
|
|
165
|
+
imageSize: 24
|
|
166
|
+
});
|
|
167
|
+
let content;
|
|
168
|
+
if (typeof filterDropdown === "function") content = filterDropdown({
|
|
169
|
+
clearFilters: onReset,
|
|
170
|
+
close: () => triggerOpen(false),
|
|
171
|
+
confirm: doFilter,
|
|
172
|
+
filters,
|
|
173
|
+
prefixCls: `${FILTER_CLS}-dropdown-custom`,
|
|
174
|
+
selectedKeys,
|
|
175
|
+
setSelectedKeys,
|
|
176
|
+
visible: mergedVisible
|
|
177
|
+
});
|
|
178
|
+
else if (filterDropdown !== void 0) content = filterDropdown;
|
|
179
|
+
else {
|
|
180
|
+
let body;
|
|
181
|
+
if (!filters?.length) body = empty;
|
|
182
|
+
else if (filterMode === "tree") {
|
|
183
|
+
const treeData = toTreeData(filters);
|
|
184
|
+
const fullTreeData = normalizedSearch ? toTreeData(filters, true) : treeData;
|
|
185
|
+
const onTreeCheck = (checked, node) => {
|
|
186
|
+
if (!filterMultiple) return setSelectedKeys(checked ? [node.key] : []);
|
|
187
|
+
const lineage = findLineage(fullTreeData, node.key);
|
|
188
|
+
const base = conductCheck(fullTreeData, selectedKeys.map(String)).checked;
|
|
189
|
+
if (checked) lineage?.subtree.forEach((key) => base.add(key));
|
|
190
|
+
else [...lineage?.subtree ?? [], ...lineage?.ancestors ?? []].forEach((key) => base.delete(key));
|
|
191
|
+
setSelectedKeys([...conductCheck(fullTreeData, base).checked]);
|
|
192
|
+
};
|
|
193
|
+
body = /* @__PURE__ */ jsxs(Fragment$1, { children: [renderSearch(), /* @__PURE__ */ jsxs("div", {
|
|
194
|
+
className: cx(styles.filterTree, `${PREFIX_CLS}-filter-dropdown-tree`),
|
|
195
|
+
children: [filterMultiple && /* @__PURE__ */ jsx(Checkbox_default, {
|
|
196
|
+
checked: selectedKeys.length > 0 && selectedKeys.length === allKeys.length,
|
|
197
|
+
className: cx(styles.filterCheckAll, `lobe-table-filter-dropdown-checkall`),
|
|
198
|
+
indeterminate: selectedKeys.length > 0 && selectedKeys.length < allKeys.length,
|
|
199
|
+
onChange: (checked) => setSelectedKeys(checked ? allKeys : []),
|
|
200
|
+
children: locale.filterCheckAll
|
|
201
|
+
}), treeData.length > 0 ? /* @__PURE__ */ jsx(Tree, {
|
|
202
|
+
checkable: true,
|
|
203
|
+
defaultExpandAll: true,
|
|
204
|
+
checkStrictly: !filterMultiple || Boolean(normalizedSearch),
|
|
205
|
+
checkedKeys: selectedKeys.map(String),
|
|
206
|
+
multiple: filterMultiple,
|
|
207
|
+
selectedKeys: [],
|
|
208
|
+
size: "small",
|
|
209
|
+
treeData,
|
|
210
|
+
onCheck: (_, { checked, node }) => onTreeCheck(checked, node)
|
|
211
|
+
}) : empty]
|
|
212
|
+
})] });
|
|
213
|
+
} else {
|
|
214
|
+
const items = renderMenuItems(filters);
|
|
215
|
+
const list = /* @__PURE__ */ jsx("div", {
|
|
216
|
+
className: cx(styles.filterMenu, `${FILTER_CLS}-dropdown-menu`),
|
|
217
|
+
children: items
|
|
218
|
+
});
|
|
219
|
+
body = /* @__PURE__ */ jsxs(Fragment$1, { children: [renderSearch(), items.length === 0 ? empty : filterMultiple ? list : /* @__PURE__ */ jsx(RadioGroup, {
|
|
220
|
+
value: selectedKeys.length ? String(selectedKeys[0]) : null,
|
|
221
|
+
onValueChange: (value) => setSelectedKeys(value == null ? [] : [String(value)]),
|
|
222
|
+
children: list
|
|
223
|
+
})] });
|
|
224
|
+
}
|
|
225
|
+
const resetDisabled = filterResetToDefaultFilteredValue ? sameKeys((defaultFilteredValue ?? []).map(String), selectedKeys.map(String)) : selectedKeys.length === 0;
|
|
226
|
+
content = /* @__PURE__ */ jsxs(Fragment$1, { children: [body, /* @__PURE__ */ jsxs("div", {
|
|
227
|
+
className: cx(styles.filterButtons, `${FILTER_CLS}-dropdown-btns`),
|
|
228
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
229
|
+
disabled: resetDisabled,
|
|
230
|
+
size: "small",
|
|
231
|
+
type: "link",
|
|
232
|
+
onClick: () => onReset(),
|
|
233
|
+
children: locale.filterReset
|
|
234
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
235
|
+
size: "small",
|
|
236
|
+
type: "primary",
|
|
237
|
+
onClick: onConfirm,
|
|
238
|
+
children: locale.filterConfirm
|
|
239
|
+
})]
|
|
240
|
+
})] });
|
|
241
|
+
}
|
|
242
|
+
const popupRender = filterDropdownProps.popupRender ?? filterDropdownProps.dropdownRender;
|
|
243
|
+
const panel = /* @__PURE__ */ jsx("div", {
|
|
244
|
+
className: cx(styles.filterDropdown, `${FILTER_CLS}-dropdown`),
|
|
245
|
+
children: popupRender ? popupRender(content) : content
|
|
246
|
+
});
|
|
247
|
+
const icon = typeof filterIcon === "function" ? filterIcon(filtered) : filterIcon ?? ListFilter;
|
|
248
|
+
const trigger = /* @__PURE__ */ jsx(ActionIcon, {
|
|
249
|
+
active: filtered,
|
|
250
|
+
"aria-description": locale.filterTitle,
|
|
251
|
+
"aria-label": `Filter ${label}`,
|
|
252
|
+
className: cx(styles.filterButton, `${FILTER_CLS}-trigger`, filtered && styles.filterActive),
|
|
253
|
+
"data-active": filtered || void 0,
|
|
254
|
+
icon,
|
|
255
|
+
ref: triggerRef,
|
|
256
|
+
size: "small",
|
|
257
|
+
onClick: (event) => event.stopPropagation()
|
|
258
|
+
});
|
|
259
|
+
if (inMeasureRow) return trigger;
|
|
260
|
+
const resolveContainer = filterDropdownProps.getPopupContainer ?? getPopupContainer;
|
|
261
|
+
const container = mergedVisible && resolveContainer && triggerRef.current ? resolveContainer(triggerRef.current) : void 0;
|
|
262
|
+
return /* @__PURE__ */ jsxs(PopoverRoot, {
|
|
263
|
+
open: mergedVisible,
|
|
264
|
+
onOpenChange: onPopoverOpenChange,
|
|
265
|
+
children: [/* @__PURE__ */ jsx(PopoverTriggerElement, { children: trigger }), /* @__PURE__ */ jsx(PopoverPortal, {
|
|
266
|
+
container,
|
|
267
|
+
children: /* @__PURE__ */ jsx(PopoverPositioner, {
|
|
268
|
+
className: filterDropdownProps.rootClassName,
|
|
269
|
+
placement: filterDropdownProps.placement ?? "bottomRight",
|
|
270
|
+
sideOffset: 4,
|
|
271
|
+
style: filterDropdownProps.zIndex === void 0 ? void 0 : { zIndex: filterDropdownProps.zIndex },
|
|
272
|
+
children: /* @__PURE__ */ jsx(PopoverPopup, {
|
|
273
|
+
className: cx(styles.filterPopup, filterDropdownProps.className),
|
|
274
|
+
style: filterDropdownProps.style,
|
|
275
|
+
children: panel
|
|
276
|
+
})
|
|
277
|
+
})
|
|
278
|
+
})]
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
//#endregion
|
|
282
|
+
export { TableMeasureRowContext, FilterDropdown as default };
|
|
283
|
+
|
|
284
|
+
//# sourceMappingURL=FilterDropdown.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterDropdown.mjs","names":["Checkbox","Input","BaseRadioGroup"],"sources":["../../../src/base-ui/Table/FilterDropdown.tsx"],"sourcesContent":["'use client';\n\nimport { RadioGroup as BaseRadioGroup } from '@base-ui/react/radio-group';\nimport { cx } from 'antd-style';\nimport { ListFilter, Search } from 'lucide-react';\nimport {\n createContext,\n type Key,\n type ReactNode,\n use,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\n\nimport ActionIcon from '@/base-ui/ActionIcon';\nimport Button from '@/base-ui/Button';\nimport { Checkbox } from '@/base-ui/Checkbox';\nimport { Input } from '@/base-ui/Input';\nimport {\n PopoverPopup,\n PopoverPortal,\n PopoverPositioner,\n PopoverRoot,\n PopoverTriggerElement,\n} from '@/base-ui/Popover';\nimport { Radio } from '@/base-ui/Radio';\nimport Tree, { conductCheck, getAllKeys, type TreeDataNode } from '@/base-ui/Tree';\nimport Empty from '@/Empty';\nimport Icon from '@/Icon';\n\nimport { PREFIX_CLS, styles } from './style';\nimport type {\n TableColumnFilterItem,\n TableColumnType,\n TableFilterDropdownProps,\n TableLocale,\n} from './type';\nimport { type FilterKeys, type FilterState, flattenFilterKeys } from './useFilter';\n\nconst FILTER_CLS = `${PREFIX_CLS}-filter`;\n\n/** True inside rc-table's hidden measure row, where only a static trigger is rendered. */\nexport const TableMeasureRowContext = createContext(false);\n\nconst sameKeys = (a: readonly Key[] | null | undefined, b: readonly Key[] | null | undefined) =>\n (a ?? null) === (b ?? null) ||\n (Boolean(a) && Boolean(b) && a!.length === b!.length && a!.every((key, i) => key === b![i]));\n\nconst textMatches = (search: string, text: ReactNode) =>\n (typeof text === 'string' || typeof text === 'number') &&\n String(text).toLowerCase().includes(search);\n\nconst DEPRECATED_PROPS = [\n ['filterDropdownOpen', 'filterDropdownProps.open'],\n ['onFilterDropdownOpenChange', 'filterDropdownProps.onOpenChange'],\n] as const;\nconst warnedProps = new Set<string>();\n\n/** Warns once per deprecated column prop, in development (antd `warning.deprecated`). */\nconst warnDeprecated = (column: object) => {\n if (process.env.NODE_ENV === 'production') return;\n for (const [name, replacement] of DEPRECATED_PROPS) {\n if (name in column && !warnedProps.has(name)) {\n warnedProps.add(name);\n console.warn(`[Table] \\`${name}\\` is deprecated. Please use \\`${replacement}\\` instead.`);\n }\n }\n};\n\n/** Keys of `key` and its descendants, plus the keys of its ancestors. */\nconst findLineage = (\n nodes: readonly TreeDataNode[],\n key: string,\n ancestors: string[] = [],\n): { ancestors: string[]; subtree: string[] } | undefined => {\n for (const node of nodes) {\n if (node.key === key) return { ancestors, subtree: getAllKeys([node]) };\n const found = node.children && findLineage(node.children, key, [...ancestors, node.key]);\n if (found) return found;\n }\n};\n\n/** Draft keys that re-render on write and can be read synchronously (antd `useSyncState`). */\nconst useSyncKeys = (initial: Key[]) => {\n const ref = useRef(initial);\n const [, rerender] = useReducer((count: number) => count + 1, 0);\n return [\n () => ref.current,\n (next: Key[]) => {\n ref.current = next;\n rerender();\n },\n ] as const;\n};\n\ninterface FilterDropdownProps<T> {\n column: TableColumnType<T>;\n columnKey: string;\n filterState?: FilterState<T>;\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n label: string;\n locale: Pick<\n TableLocale,\n | 'filterCheckAll'\n | 'filterConfirm'\n | 'filterEmptyText'\n | 'filterReset'\n | 'filterSearchPlaceholder'\n | 'filterTitle'\n >;\n triggerFilter: (columnKey: string, filteredKeys: FilterKeys) => void;\n}\n\nconst FilterDropdown = <T,>({\n column,\n columnKey,\n filterState,\n getPopupContainer,\n label,\n locale,\n triggerFilter,\n}: FilterDropdownProps<T>) => {\n const {\n defaultFilteredValue,\n filterDropdown,\n filterDropdownOpen,\n filterDropdownProps = {},\n filterIcon,\n filterMode = 'menu',\n filterMultiple = true,\n filterOnClose = true,\n filterResetToDefaultFilteredValue,\n filters,\n filterSearch = false,\n onFilterDropdownOpenChange,\n } = column;\n\n const inMeasureRow = use(TableMeasureRowContext);\n warnDeprecated(column);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const [visible, setVisible] = useState(false);\n const [searchValue, setSearchValue] = useState('');\n const normalizedSearch = searchValue.trim().toLowerCase();\n const mergedVisible = filterDropdownProps.open ?? filterDropdownOpen ?? visible;\n const filtered = Boolean(filterState?.filteredKeys?.length || filterState?.forceFiltered);\n\n const triggerOpen = (next: boolean) => {\n setVisible(next);\n // The search box starts empty every time the panel opens.\n setSearchValue('');\n filterDropdownProps.onOpenChange?.(next);\n onFilterDropdownOpenChange?.(next);\n };\n\n // ============================ Draft keys ============================\n // Booleans only come from `filteredValue`; the panel works with keys, like antd.\n const propFilteredKeys = filterState?.filteredKeys as Key[] | null | undefined;\n const [getSelectedKeys, setSelectedKeys] = useSyncKeys(propFilteredKeys ?? []);\n\n useEffect(() => {\n if (mergedVisible) setSelectedKeys(propFilteredKeys ?? []);\n // `setSelectedKeys` is stable in behavior; re-sync only on open / applied-keys change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [propFilteredKeys, mergedVisible]);\n\n // ============================== Submit ==============================\n const internalTriggerFilter = (keys: Key[] | null) => {\n const mergedKeys = keys?.length ? keys : null;\n if (mergedKeys === null && !propFilteredKeys) return;\n if (sameKeys(mergedKeys, propFilteredKeys)) return;\n triggerFilter(columnKey, mergedKeys);\n };\n\n const onConfirm = () => {\n triggerOpen(false);\n internalTriggerFilter(getSelectedKeys());\n };\n\n const onReset: NonNullable<TableFilterDropdownProps['clearFilters']> = ({\n closeDropdown = false,\n confirm = false,\n } = {}) => {\n if (confirm) internalTriggerFilter([]);\n if (closeDropdown) triggerOpen(false);\n setSearchValue('');\n setSelectedKeys(\n filterResetToDefaultFilteredValue ? (defaultFilteredValue ?? []).map(String) : [],\n );\n };\n\n const doFilter: TableFilterDropdownProps['confirm'] = ({ closeDropdown = true } = {}) => {\n if (closeDropdown) triggerOpen(false);\n internalTriggerFilter(getSelectedKeys());\n };\n\n /** Opening / closing from the trigger, an outside press or Escape. */\n const onPopoverOpenChange = (next: boolean) => {\n if (next && propFilteredKeys !== undefined) setSelectedKeys(propFilteredKeys ?? []);\n if (!next && !filterDropdown && filterOnClose) onConfirm();\n else triggerOpen(next);\n };\n\n // ============================== Content =============================\n const selectedKeys = getSelectedKeys();\n const selectedSet = new Set(selectedKeys.map(String));\n const allKeys = useMemo(() => flattenFilterKeys(filters).map(String), [filters]);\n\n const matches = (item: TableColumnFilterItem) =>\n typeof filterSearch === 'function'\n ? filterSearch(normalizedSearch, item)\n : textMatches(normalizedSearch, item.text);\n\n const toggleKey = (key: string, checked: boolean) => {\n if (!filterMultiple) return setSelectedKeys(checked ? [key] : []);\n const rest = selectedKeys.filter((item) => String(item) !== key);\n setSelectedKeys(checked ? [...rest, key] : rest);\n };\n\n const renderMenuItems = (items: readonly TableColumnFilterItem[]): ReactNode[] =>\n items.flatMap((item, index) => {\n const key = String(item.value);\n if (item.children) {\n const children = renderMenuItems(item.children);\n if (children.length === 0) return [];\n return [\n <div className={styles.filterGroup} key={key || index} role=\"group\">\n <div className={cx(styles.filterGroupTitle, `${FILTER_CLS}-dropdown-submenu-title`)}>\n {item.text}\n </div>\n {children}\n </div>,\n ];\n }\n if (normalizedSearch && !matches(item)) return [];\n return [\n <div className={cx(styles.filterItem, `${FILTER_CLS}-dropdown-item`)} key={key}>\n {filterMultiple ? (\n <Checkbox\n checked={selectedSet.has(key)}\n onChange={(checked) => toggleKey(key, checked)}\n >\n {item.text}\n </Checkbox>\n ) : (\n <Radio value={key}>{item.text}</Radio>\n )}\n </div>,\n ];\n });\n\n const toTreeData = (\n items: readonly TableColumnFilterItem[] | undefined,\n ancestorMatched = false,\n ): TreeDataNode[] =>\n (items ?? []).flatMap((item, index) => {\n const selfMatched = ancestorMatched || !normalizedSearch || matches(item);\n const children = item.children ? toTreeData(item.children, selfMatched) : undefined;\n if (!selfMatched && !children?.length) return [];\n return [\n {\n children,\n key: item.value !== undefined ? String(item.value) : String(index),\n title: item.text,\n },\n ];\n });\n\n const renderSearch = () =>\n filterSearch ? (\n <div className={cx(styles.filterSearch, `${PREFIX_CLS}-filter-dropdown-search`)}>\n <Input\n allowClear\n placeholder={locale.filterSearchPlaceholder}\n prefix={<Icon icon={Search} size={14} />}\n size=\"small\"\n value={searchValue}\n onChange={(event) => setSearchValue(event.target.value)}\n />\n </div>\n ) : null;\n\n const empty = (\n <Empty className={styles.filterEmpty} description={locale.filterEmptyText} imageSize={24} />\n );\n\n let content: ReactNode;\n if (typeof filterDropdown === 'function') {\n content = filterDropdown({\n clearFilters: onReset,\n close: () => triggerOpen(false),\n confirm: doFilter,\n filters,\n prefixCls: `${FILTER_CLS}-dropdown-custom`,\n selectedKeys,\n setSelectedKeys,\n visible: mergedVisible,\n });\n } else if (filterDropdown !== undefined) {\n content = filterDropdown;\n } else {\n let body: ReactNode;\n if (!filters?.length) {\n body = empty;\n } else if (filterMode === 'tree') {\n const treeData = toTreeData(filters);\n // Searching prunes the tree, so cascade checks on the full tree and show the keys as is.\n const fullTreeData = normalizedSearch ? toTreeData(filters, true) : treeData;\n const onTreeCheck = (checked: boolean, node: TreeDataNode) => {\n if (!filterMultiple) return setSelectedKeys(checked ? [node.key] : []);\n const lineage = findLineage(fullTreeData, node.key);\n const base = conductCheck(fullTreeData, selectedKeys.map(String)).checked;\n if (checked) lineage?.subtree.forEach((key) => base.add(key));\n else\n [...(lineage?.subtree ?? []), ...(lineage?.ancestors ?? [])].forEach((key) =>\n base.delete(key),\n );\n setSelectedKeys([...conductCheck(fullTreeData, base).checked]);\n };\n body = (\n <>\n {renderSearch()}\n <div className={cx(styles.filterTree, `${PREFIX_CLS}-filter-dropdown-tree`)}>\n {filterMultiple && (\n <Checkbox\n checked={selectedKeys.length > 0 && selectedKeys.length === allKeys.length}\n className={cx(styles.filterCheckAll, `${PREFIX_CLS}-filter-dropdown-checkall`)}\n indeterminate={selectedKeys.length > 0 && selectedKeys.length < allKeys.length}\n onChange={(checked) => setSelectedKeys(checked ? allKeys : [])}\n >\n {locale.filterCheckAll}\n </Checkbox>\n )}\n {treeData.length > 0 ? (\n <Tree\n checkable\n defaultExpandAll\n checkStrictly={!filterMultiple || Boolean(normalizedSearch)}\n checkedKeys={selectedKeys.map(String)}\n multiple={filterMultiple}\n selectedKeys={[]}\n size=\"small\"\n treeData={treeData}\n onCheck={(_, { checked, node }) => onTreeCheck(checked, node)}\n />\n ) : (\n empty\n )}\n </div>\n </>\n );\n } else {\n const items = renderMenuItems(filters);\n const list = (\n <div className={cx(styles.filterMenu, `${FILTER_CLS}-dropdown-menu`)}>{items}</div>\n );\n body = (\n <>\n {renderSearch()}\n {items.length === 0 ? (\n empty\n ) : filterMultiple ? (\n list\n ) : (\n <BaseRadioGroup\n value={selectedKeys.length ? String(selectedKeys[0]) : null}\n onValueChange={(value) => setSelectedKeys(value == null ? [] : [String(value)])}\n >\n {list}\n </BaseRadioGroup>\n )}\n </>\n );\n }\n\n const resetDisabled = filterResetToDefaultFilteredValue\n ? sameKeys((defaultFilteredValue ?? []).map(String), selectedKeys.map(String))\n : selectedKeys.length === 0;\n\n content = (\n <>\n {body}\n <div className={cx(styles.filterButtons, `${FILTER_CLS}-dropdown-btns`)}>\n <Button disabled={resetDisabled} size=\"small\" type=\"link\" onClick={() => onReset()}>\n {locale.filterReset}\n </Button>\n <Button size=\"small\" type=\"primary\" onClick={onConfirm}>\n {locale.filterConfirm}\n </Button>\n </div>\n </>\n );\n }\n\n const popupRender = filterDropdownProps.popupRender ?? filterDropdownProps.dropdownRender;\n const panel = (\n <div className={cx(styles.filterDropdown, `${FILTER_CLS}-dropdown`)}>\n {popupRender ? popupRender(content) : content}\n </div>\n );\n\n // ============================== Trigger =============================\n const icon = typeof filterIcon === 'function' ? filterIcon(filtered) : (filterIcon ?? ListFilter);\n\n // Native `title` would need ActionIcon's tooltip, which can't sit inside the popover trigger;\n // the localized hint rides on `aria-description` instead.\n const trigger = (\n <ActionIcon\n active={filtered}\n aria-description={locale.filterTitle}\n aria-label={`Filter ${label}`}\n className={cx(styles.filterButton, `${FILTER_CLS}-trigger`, filtered && styles.filterActive)}\n data-active={filtered || undefined}\n icon={icon}\n ref={triggerRef}\n size=\"small\"\n onClick={(event) => event.stopPropagation()}\n />\n );\n\n if (inMeasureRow) return trigger;\n\n const resolveContainer = filterDropdownProps.getPopupContainer ?? getPopupContainer;\n const container =\n mergedVisible && resolveContainer && triggerRef.current\n ? resolveContainer(triggerRef.current)\n : undefined;\n\n return (\n <PopoverRoot open={mergedVisible} onOpenChange={onPopoverOpenChange}>\n <PopoverTriggerElement>{trigger}</PopoverTriggerElement>\n <PopoverPortal container={container}>\n <PopoverPositioner\n className={filterDropdownProps.rootClassName}\n placement={filterDropdownProps.placement ?? 'bottomRight'}\n sideOffset={4}\n style={\n filterDropdownProps.zIndex === undefined\n ? undefined\n : { zIndex: filterDropdownProps.zIndex }\n }\n >\n <PopoverPopup\n className={cx(styles.filterPopup, filterDropdownProps.className)}\n style={filterDropdownProps.style}\n >\n {panel}\n </PopoverPopup>\n </PopoverPositioner>\n </PopoverPortal>\n </PopoverRoot>\n );\n};\n\nexport default FilterDropdown;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import Skeleton from "../Skeleton/index.mjs";
|
|
3
|
+
import { isColumnGroup, isColumnVisibleAt } from "./columnUtils.mjs";
|
|
4
|
+
import { styles } from "./style.mjs";
|
|
5
|
+
import { memo, useMemo } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
//#region src/base-ui/Table/LoadingSkeleton.tsx
|
|
8
|
+
const DEFAULT_ROWS = 5;
|
|
9
|
+
/** Varying bar widths so consecutive rows do not look identical. */
|
|
10
|
+
const CELL_WIDTHS = [
|
|
11
|
+
72,
|
|
12
|
+
56,
|
|
13
|
+
64,
|
|
14
|
+
48,
|
|
15
|
+
80,
|
|
16
|
+
40,
|
|
17
|
+
60,
|
|
18
|
+
52
|
|
19
|
+
];
|
|
20
|
+
const resolveTrack = (width) => {
|
|
21
|
+
if (typeof width === "number") return `${width}px`;
|
|
22
|
+
if (typeof width === "string" && width) return width;
|
|
23
|
+
return "minmax(0, 1fr)";
|
|
24
|
+
};
|
|
25
|
+
const leafColumns = (columns, screens) => columns.flatMap((column) => {
|
|
26
|
+
if (!isColumnVisibleAt(column, screens)) return [];
|
|
27
|
+
if (isColumnGroup(column)) return leafColumns(column.children, screens);
|
|
28
|
+
return [column];
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Body placeholder while `loading` and there are no rows. Uses the real leaf column
|
|
32
|
+
* widths (plus selection / expand tracks when those columns are on) so the skeleton
|
|
33
|
+
* lines up under the live header; row padding follows the table size CSS vars.
|
|
34
|
+
*/
|
|
35
|
+
function TableLoadingSkeletonInner({ columns, expandColumn = false, rows = DEFAULT_ROWS, screens, selectionColumn = false, size }) {
|
|
36
|
+
const tracks = useMemo(() => {
|
|
37
|
+
const list = [];
|
|
38
|
+
if (selectionColumn) list.push(`32px`);
|
|
39
|
+
if (expandColumn) list.push(`48px`);
|
|
40
|
+
const leaves = leafColumns(columns, screens);
|
|
41
|
+
if (leaves.length === 0) list.push("minmax(0, 1.4fr)", "minmax(0, 1fr)", "minmax(0, 0.8fr)", "minmax(0, 1fr)");
|
|
42
|
+
else leaves.forEach((column) => list.push(resolveTrack(column.width)));
|
|
43
|
+
return list;
|
|
44
|
+
}, [
|
|
45
|
+
columns,
|
|
46
|
+
expandColumn,
|
|
47
|
+
screens,
|
|
48
|
+
selectionColumn
|
|
49
|
+
]);
|
|
50
|
+
const gridTemplateColumns = tracks.join(" ");
|
|
51
|
+
const rowCount = Math.max(1, rows);
|
|
52
|
+
return /* @__PURE__ */ jsx("div", {
|
|
53
|
+
"aria-hidden": true,
|
|
54
|
+
className: styles.skeleton,
|
|
55
|
+
"data-table-skeleton": "",
|
|
56
|
+
"data-table-skeleton-size": size === "middle" ? "medium" : size,
|
|
57
|
+
children: Array.from({ length: rowCount }, (_, rowIndex) => /* @__PURE__ */ jsx("div", {
|
|
58
|
+
className: styles.skeletonRow,
|
|
59
|
+
style: { gridTemplateColumns },
|
|
60
|
+
children: tracks.map((_, colIndex) => {
|
|
61
|
+
const isLeading = selectionColumn && colIndex === 0 || expandColumn && colIndex === (selectionColumn ? 1 : 0);
|
|
62
|
+
const widthPct = isLeading ? 100 : CELL_WIDTHS[(rowIndex * 3 + colIndex) % CELL_WIDTHS.length];
|
|
63
|
+
return /* @__PURE__ */ jsx("div", {
|
|
64
|
+
className: styles.skeletonCell,
|
|
65
|
+
children: isLeading ? /* @__PURE__ */ jsx(Skeleton, {
|
|
66
|
+
height: 14,
|
|
67
|
+
radius: 4,
|
|
68
|
+
width: 14
|
|
69
|
+
}) : /* @__PURE__ */ jsx(Skeleton, {
|
|
70
|
+
height: 14,
|
|
71
|
+
radius: 4,
|
|
72
|
+
width: `${widthPct}%`
|
|
73
|
+
})
|
|
74
|
+
}, colIndex);
|
|
75
|
+
})
|
|
76
|
+
}, rowIndex))
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const TableLoadingSkeleton = memo(TableLoadingSkeletonInner);
|
|
80
|
+
//#endregion
|
|
81
|
+
export { TableLoadingSkeleton as default };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=LoadingSkeleton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingSkeleton.mjs","names":[],"sources":["../../../src/base-ui/Table/LoadingSkeleton.tsx"],"sourcesContent":["'use client';\n\nimport { memo, useMemo } from 'react';\n\nimport Skeleton from '@/base-ui/Skeleton';\n\nimport { isColumnGroup, isColumnVisibleAt } from './columnUtils';\nimport { EXPAND_COLUMN_WIDTH, SELECTION_COLUMN_WIDTH, styles } from './style';\nimport type { TableBreakpoint, TableColumn, TableSize } from './type';\n\nconst DEFAULT_ROWS = 5;\n\n/** Varying bar widths so consecutive rows do not look identical. */\nconst CELL_WIDTHS = [72, 56, 64, 48, 80, 40, 60, 52] as const;\n\nexport interface TableLoadingSkeletonProps<T = any> {\n columns: readonly TableColumn<T>[];\n expandColumn?: boolean;\n rows?: number;\n screens: ReadonlySet<TableBreakpoint> | null;\n selectionColumn?: boolean;\n size: TableSize;\n}\n\nconst resolveTrack = (width: TableColumn<any>['width']) => {\n if (typeof width === 'number') return `${width}px`;\n if (typeof width === 'string' && width) return width;\n return 'minmax(0, 1fr)';\n};\n\nconst leafColumns = <T,>(\n columns: readonly TableColumn<T>[],\n screens: ReadonlySet<TableBreakpoint> | null,\n): TableColumn<T>[] =>\n columns.flatMap((column) => {\n if (!isColumnVisibleAt(column, screens)) return [];\n if (isColumnGroup(column)) return leafColumns(column.children, screens);\n return [column];\n });\n\n/**\n * Body placeholder while `loading` and there are no rows. Uses the real leaf column\n * widths (plus selection / expand tracks when those columns are on) so the skeleton\n * lines up under the live header; row padding follows the table size CSS vars.\n */\nfunction TableLoadingSkeletonInner<T>({\n columns,\n expandColumn = false,\n rows = DEFAULT_ROWS,\n screens,\n selectionColumn = false,\n size,\n}: TableLoadingSkeletonProps<T>) {\n const tracks = useMemo(() => {\n const list: string[] = [];\n if (selectionColumn) list.push(`${SELECTION_COLUMN_WIDTH}px`);\n if (expandColumn) list.push(`${EXPAND_COLUMN_WIDTH}px`);\n const leaves = leafColumns(columns, screens);\n if (leaves.length === 0) {\n list.push('minmax(0, 1.4fr)', 'minmax(0, 1fr)', 'minmax(0, 0.8fr)', 'minmax(0, 1fr)');\n } else {\n leaves.forEach((column) => list.push(resolveTrack(column.width)));\n }\n return list;\n }, [columns, expandColumn, screens, selectionColumn]);\n\n const gridTemplateColumns = tracks.join(' ');\n const rowCount = Math.max(1, rows);\n\n return (\n <div\n aria-hidden\n className={styles.skeleton}\n data-table-skeleton=\"\"\n data-table-skeleton-size={size === 'middle' ? 'medium' : size}\n >\n {Array.from({ length: rowCount }, (_, rowIndex) => (\n <div className={styles.skeletonRow} key={rowIndex} style={{ gridTemplateColumns }}>\n {tracks.map((_, colIndex) => {\n const leadingSelection = selectionColumn && colIndex === 0;\n const leadingExpand = expandColumn && colIndex === (selectionColumn ? 1 : 0);\n const isLeading = leadingSelection || leadingExpand;\n const widthPct = isLeading\n ? 100\n : CELL_WIDTHS[(rowIndex * 3 + colIndex) % CELL_WIDTHS.length];\n return (\n <div className={styles.skeletonCell} key={colIndex}>\n {isLeading ? (\n <Skeleton height={14} radius={4} width={14} />\n ) : (\n <Skeleton height={14} radius={4} width={`${widthPct}%`} />\n )}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n );\n}\n\nconst TableLoadingSkeleton = memo(TableLoadingSkeletonInner) as typeof TableLoadingSkeletonInner;\n\nexport default TableLoadingSkeleton;\n"],"mappings":";;;;;;;AAUA,MAAM,eAAe;;AAGrB,MAAM,cAAc;CAAC;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;AAAE;AAWnD,MAAM,gBAAgB,UAAqC;CACzD,IAAI,OAAO,UAAU,UAAU,OAAO,GAAG,MAAM;CAC/C,IAAI,OAAO,UAAU,YAAY,OAAO,OAAO;CAC/C,OAAO;AACT;AAEA,MAAM,eACJ,SACA,YAEA,QAAQ,SAAS,WAAW;CAC1B,IAAI,CAAC,kBAAkB,QAAQ,OAAO,GAAG,OAAO,CAAC;CACjD,IAAI,cAAc,MAAM,GAAG,OAAO,YAAY,OAAO,UAAU,OAAO;CACtE,OAAO,CAAC,MAAM;AAChB,CAAC;;;;;;AAOH,SAAS,0BAA6B,EACpC,SACA,eAAe,OACf,OAAO,cACP,SACA,kBAAkB,OAClB,QAC+B;CAC/B,MAAM,SAAS,cAAc;EAC3B,MAAM,OAAiB,CAAC;EACxB,IAAI,iBAAiB,KAAK,KAAK,MAA6B;EAC5D,IAAI,cAAc,KAAK,KAAK,MAA0B;EACtD,MAAM,SAAS,YAAY,SAAS,OAAO;EAC3C,IAAI,OAAO,WAAW,GACpB,KAAK,KAAK,oBAAoB,kBAAkB,oBAAoB,gBAAgB;OAEpF,OAAO,SAAS,WAAW,KAAK,KAAK,aAAa,OAAO,KAAK,CAAC,CAAC;EAElE,OAAO;CACT,GAAG;EAAC;EAAS;EAAc;EAAS;CAAe,CAAC;CAEpD,MAAM,sBAAsB,OAAO,KAAK,GAAG;CAC3C,MAAM,WAAW,KAAK,IAAI,GAAG,IAAI;CAEjC,OACE,oBAAC,OAAD;EACE,eAAA;EACA,WAAW,OAAO;EAClB,uBAAoB;EACpB,4BAA0B,SAAS,WAAW,WAAW;EAExD,UAAA,MAAM,KAAK,EAAE,QAAQ,SAAS,IAAI,GAAG,aACpC,oBAAC,OAAD;GAAK,WAAW,OAAO;GAA4B,OAAO,EAAE,oBAAoB;GAC7E,UAAA,OAAO,KAAK,GAAG,aAAa;IAG3B,MAAM,YAFmB,mBAAmB,aAAa,KACnC,gBAAgB,cAAc,kBAAkB,IAAI;IAE1E,MAAM,WAAW,YACb,MACA,aAAa,WAAW,IAAI,YAAY,YAAY;IACxD,OACE,oBAAC,OAAD;KAAK,WAAW,OAAO;KACpB,UAAA,YACC,oBAAC,UAAD;MAAU,QAAQ;MAAI,QAAQ;MAAG,OAAO;KAAK,CAAA,IAE7C,oBAAC,UAAD;MAAU,QAAQ;MAAI,QAAQ;MAAG,OAAO,GAAG,SAAS;KAAK,CAAA;IAExD,GANqC,QAMrC;GAET,CAAC;EACE,GAlBoC,QAkBpC,CACN;CACE,CAAA;AAET;AAEA,MAAM,uBAAuB,KAAK,yBAAyB"}
|