Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions docs/examples/multiple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,37 @@ const sharedLocale = {
style: { width: 300 },
};

const maxTagPlaceholder = (value) => {
return (
<ul>
{value?.map((item, index) => {
return <li key={index}>{item?.format('YYYY-MM-DD')}</li>;
})}
</ul>
);
};

export default () => {
const singleRef = React.useRef<PickerRef>(null);

return (
<div>
<SinglePicker {...sharedLocale} multiple ref={singleRef} onOpenChange={console.error} />
<SinglePicker {...sharedLocale} multiple ref={singleRef} needConfirm />
<SinglePicker {...sharedLocale} multiple picker="week" defaultValue={[
dayjs('2021-01-01'),
dayjs('2021-01-08'),
]} />
<SinglePicker
{...sharedLocale}
multiple
picker="week"
defaultValue={[dayjs('2021-01-01'), dayjs('2021-01-08')]}
/>
<SinglePicker
maxTagCount={10}
{...sharedLocale}
multiple
ref={singleRef}
maxTagPlaceholder={maxTagPlaceholder}
defaultValue={[dayjs('2021-01-01'), dayjs('2021-01-08')]}
/>
</div>
);
};
9 changes: 6 additions & 3 deletions src/PickerInput/Selector/SingleSelector/MultipleDates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react';
import type { PickerProps } from '../../SinglePicker';

export interface MultipleDatesProps<DateType extends object = any>
extends Pick<PickerProps, 'maxTagCount'> {
extends Pick<PickerProps, 'maxTagCount' | 'maxTagPlaceholder'> {
prefixCls: string;
value: DateType[];
onRemove: (value: DateType) => void;
Expand All @@ -25,6 +25,7 @@ export default function MultipleDates<DateType extends object = any>(
formatDate,
disabled,
maxTagCount,
maxTagPlaceholder,
placeholder,
} = props;

Expand Down Expand Up @@ -68,8 +69,10 @@ export default function MultipleDates<DateType extends object = any>(

// ========================= Rest =========================
function renderRest(omittedValues: DateType[]) {
const content = `+ ${omittedValues.length} ...`;

const content =
typeof maxTagPlaceholder === 'function'
? maxTagPlaceholder(omittedValues)
: maxTagPlaceholder;
return renderSelector(content);
}

Expand Down
4 changes: 3 additions & 1 deletion src/PickerInput/Selector/SingleSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import MultipleDates from './MultipleDates';

export interface SingleSelectorProps<DateType extends object = any>
extends SelectorProps<DateType>,
Pick<PickerProps, 'multiple' | 'maxTagCount'> {
Pick<PickerProps, 'multiple' | 'maxTagCount' | 'maxTagPlaceholder'> {
id?: string;

value?: DateType[];
Expand Down Expand Up @@ -75,6 +75,7 @@ function SingleSelector<DateType extends object = any>(
onInputChange,
multiple,
maxTagCount,
maxTagPlaceholder = (omittedValues: DateType[]) => `+ ${omittedValues.length} ...`,

// Valid
format,
Expand Down Expand Up @@ -170,6 +171,7 @@ function SingleSelector<DateType extends object = any>(
onRemove={onMultipleRemove}
formatDate={getText}
maxTagCount={maxTagCount}
maxTagPlaceholder={maxTagPlaceholder}
disabled={disabled}
removeIcon={removeIcon}
placeholder={placeholder}
Expand Down
1 change: 1 addition & 0 deletions src/PickerInput/SinglePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface BasePickerProps<DateType extends object = any>
removeIcon?: React.ReactNode;
/** Only work when `multiple` is in used */
maxTagCount?: number | 'responsive';
maxTagPlaceholder?: React.ReactNode | ((omittedValues: DateType[]) => React.ReactNode);

// Value
value?: DateType | DateType[] | null;
Expand Down
109 changes: 109 additions & 0 deletions tests/multiple.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,115 @@ describe('Picker.Multiple', () => {
).toBeFalsy();
});
});
describe('maxTagPlaceholder', () => {
it('should not show maxTagPlaceholder when items count is within maxTagCount', () => {
const maxTagPlaceholder = (omittedValues: any[]) => (
<span className="custom-max-tag-placeholder">+{omittedValues.length} more</span>
);

const { container } = render(
<DayPicker
multiple
maxTagCount={3}
maxTagPlaceholder={maxTagPlaceholder}
defaultValue={[getDay('2000-01-01'), getDay('2000-01-02')]}
/>,
);

// Should show all items, no placeholder
expect(container.querySelectorAll('.rc-picker-selection-item')).toHaveLength(2);
expect(container.querySelector('.custom-max-tag-placeholder')).toBeFalsy();
});

it('should show maxTagPlaceholder when items count exceeds maxTagCount', () => {
const maxTagPlaceholder = (omittedValues: any[]) => (
<span className="custom-max-tag-placeholder">+{omittedValues.length} items</span>
);

const { container } = render(
<DayPicker
multiple
maxTagCount={2}
maxTagPlaceholder={maxTagPlaceholder}
defaultValue={[
getDay('2000-01-01'),
getDay('2000-01-02'),
getDay('2000-01-03'),
getDay('2000-01-04'),
]}
/>,
);

// Should show maxTagCount items + placeholder
expect(container.querySelectorAll('.rc-picker-selection-item')).toHaveLength(3);
expect(container.querySelector('.custom-max-tag-placeholder').textContent).toBe('+2 items');
});

it('should work with custom maxTagPlaceholder component', () => {
const CustomPlaceholder = ({ omittedValues }: { omittedValues: any[] }) => (
<div className="custom-placeholder-wrapper">
<span className="omitted-count">{omittedValues.length}</span>
<span className="omitted-text">hidden dates</span>
</div>
);

const { container } = render(
<DayPicker
multiple
maxTagCount={1}
maxTagPlaceholder={(omittedValues) => <CustomPlaceholder omittedValues={omittedValues} />}
defaultValue={[getDay('2000-01-01'), getDay('2000-01-02'), getDay('2000-01-03')]}
/>,
);

expect(container.querySelector('.custom-placeholder-wrapper')).toBeTruthy();
expect(container.querySelector('.omitted-count').textContent).toBe('2');
expect(container.querySelector('.omitted-text').textContent).toBe('hidden dates');
});

it('should handle maxTagCount edge cases1', () => {
const maxTagPlaceholder = (omittedValues: any[]) => (
<span className="edge-case-placeholder">+{omittedValues.length}</span>
);

// Test maxTagCount = 0
const { container } = render(
<DayPicker
multiple
maxTagCount={0}
maxTagPlaceholder={maxTagPlaceholder}
defaultValue={[getDay('2000-01-01')]}
/>,
);
expect(container.querySelectorAll('.rc-picker-selection-item')).toHaveLength(1);
expect(container.querySelector('.edge-case-placeholder')).toBeTruthy();
expect(container.querySelector('.edge-case-placeholder').textContent).toBe('+1');
});

it('should pass correct omittedValues to maxTagPlaceholder', () => {
const maxTagPlaceholder = jest.fn((omittedValues) => (
<span className="test-placeholder">+{omittedValues.length}</span>
));

const values = [
getDay('2000-01-01'),
getDay('2000-01-02'),
getDay('2000-01-03'),
getDay('2000-01-04'),
];

render(
<DayPicker
multiple
maxTagCount={2}
maxTagPlaceholder={maxTagPlaceholder}
defaultValue={values}
/>,
);

expect(maxTagPlaceholder).toHaveBeenCalledWith([values[2], values[3]]);
});
});

it('click year panel should not select', () => {
const onChange = jest.fn();
Expand Down