@clickhouse/click-ui 0.10.0-rc1 → 0.10.0-rc2
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/dist/cjs/click-ui.css +6 -0
- package/dist/cjs/components/DatePicker/Common.cjs +1 -1
- package/dist/cjs/components/DatePicker/Common.cjs.map +1 -1
- package/dist/cjs/components/DatePicker/DateRangePicker.cjs +1 -1
- package/dist/cjs/components/DatePicker/DateRangePicker.cjs.map +1 -1
- package/dist/cjs/components/DatePicker/DateTimeRangePicker.cjs +12 -8
- package/dist/cjs/components/DatePicker/DateTimeRangePicker.cjs.map +1 -1
- package/dist/cjs/components/DatePicker/utils.cjs +22 -6
- package/dist/cjs/components/DatePicker/utils.cjs.map +1 -1
- package/dist/cjs/components/GenericMenu/GenericMenu.css +2 -0
- package/dist/cjs/components/Select/common/InternalSelect.cjs +147 -193
- package/dist/cjs/components/Select/common/InternalSelect.cjs.map +1 -1
- package/dist/cjs/components/Select/common/SelectComponents.css +4 -0
- package/dist/cjs/components/Select/common/SelectComponents.module.css.cjs +1 -0
- package/dist/cjs/components/Select/common/SelectComponents.module.css.cjs.map +1 -1
- package/dist/esm/click-ui.css +6 -0
- package/dist/esm/components/DatePicker/Common.js +2 -2
- package/dist/esm/components/DatePicker/Common.js.map +1 -1
- package/dist/esm/components/DatePicker/DateRangePicker.js +2 -2
- package/dist/esm/components/DatePicker/DateRangePicker.js.map +1 -1
- package/dist/esm/components/DatePicker/DateTimeRangePicker.js +13 -9
- package/dist/esm/components/DatePicker/DateTimeRangePicker.js.map +1 -1
- package/dist/esm/components/DatePicker/utils.js +20 -5
- package/dist/esm/components/DatePicker/utils.js.map +1 -1
- package/dist/esm/components/GenericMenu/GenericMenu.css +2 -0
- package/dist/esm/components/Select/common/InternalSelect.js +148 -194
- package/dist/esm/components/Select/common/InternalSelect.js.map +1 -1
- package/dist/esm/components/Select/common/SelectComponents.css +4 -0
- package/dist/esm/components/Select/common/SelectComponents.module.css.js +1 -0
- package/dist/esm/components/Select/common/SelectComponents.module.css.js.map +1 -1
- package/dist/types/components/DatePicker/utils.d.ts +3 -2
- package/dist/types/components/Select/common/index.d.ts +1 -1
- package/dist/types/components/Select/common/types.d.ts +0 -6
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../src/components/DatePicker/utils.ts"],"sourcesContent":["import { isSameDate } from '@h6s/calendar';\nimport { dayjs } from '@/utils/date';\n\nexport type Timezone = 'system' | 'UTC';\n\nexport interface DateRange {\n startDate: Date;\n endDate: Date;\n}\n\nconst locale = 'en-US';\n\nexport type Meridiem = 'am' | 'pm';\n\nexport interface Time {\n hour: number;\n minutes: number;\n}\n\nexport interface DateRangeListItem {\n dateRange: DateRange;\n label: string;\n}\n\nconst createFormatter = (options: Intl.DateTimeFormatOptions) => {\n const timezoneFormatters: Partial<Record<Timezone, Intl.DateTimeFormat>> = {};\n\n return (timezone: Timezone, date: Date): string => {\n if (!timezoneFormatters[timezone]) {\n const opts = timezone === 'UTC' ? { ...options, timeZone: 'UTC' } : options;\n timezoneFormatters[timezone] = new Intl.DateTimeFormat(locale, opts);\n }\n return timezoneFormatters[timezone].format(date);\n };\n};\n\nexport const formatSelectedDate = createFormatter({\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n});\n\nexport const formatWeekday = createFormatter({ weekday: 'short' });\n\nexport const formatSelectedDateTime = createFormatter({\n day: '2-digit',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n});\n\nexport const formatSelectedDateTimeWithSeconds = createFormatter({\n day: '2-digit',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n});\n\nexport const formatDateHeader = createFormatter({\n month: 'short',\n year: 'numeric',\n});\n\n// In UTC mode, shift by the host offset so local-time getters return UTC\n// values. shiftFromTimezone reverses it.\n//\n// Caveat: round-tripping across a DST boundary drifts by an hour — each\n// direction reads getTimezoneOffset on its own input. Call sites don't\n// round-trip the same Date, so this hasn't bitten us.\nexport const shiftToTimezone = (date: Date, timezone: Timezone): Date => {\n if (timezone !== 'UTC') {\n return date;\n }\n return new Date(date.getTime() + date.getTimezoneOffset() * 60_000);\n};\n\nexport const shiftFromTimezone = (date: Date, timezone: Timezone): Date => {\n if (timezone !== 'UTC') {\n return date;\n }\n return new Date(date.getTime() - date.getTimezoneOffset() * 60_000);\n};\n\nexport const getPredefinedMonthsForDateRangePicker = (\n numberOfMonths: number\n): DateRange[] => {\n const now = dayjs();\n\n if (numberOfMonths < 0) {\n const lastSixMonths: DateRange[] = [];\n for (let i = 0; i < Math.abs(numberOfMonths); i++) {\n const date = now.subtract(i, 'month');\n if (date.date() === 1 && date.month() === now.month()) {\n continue;\n }\n lastSixMonths.push({\n startDate: date.startOf('month').toDate(),\n endDate: i === 0 ? now.toDate() : date.endOf('month').toDate(),\n });\n }\n\n return lastSixMonths.reverse();\n }\n\n const nextSixMonths: DateRange[] = [];\n for (let i = 0; i < numberOfMonths; i++) {\n const date = now.add(i, 'month');\n nextSixMonths.push({\n startDate: date.startOf('month').toDate(),\n endDate: date.endOf('month').toDate(),\n });\n }\n\n return nextSixMonths;\n};\n\nexport const getPredefinedTimePeriodsForDateTimePicker = (): DateRangeListItem[] => {\n const now = dayjs();\n\n const fifteenMinutesAgo = now.subtract(15, 'minute');\n const thirtyMinutesAgo = now.subtract(30, 'minute');\n const oneHourAgo = now.subtract(1, 'hour');\n const sixHoursAgo = now.subtract(6, 'hour');\n const oneDayAgo = now.subtract(1, 'day');\n const oneMonthAgo = now.subtract(1, 'month');\n\n const dateRangeList: DateRangeListItem[] = [\n {\n dateRange: {\n startDate: fifteenMinutesAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past 15 minutes',\n },\n {\n dateRange: {\n startDate: thirtyMinutesAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past 30 minutes',\n },\n {\n dateRange: {\n startDate: oneHourAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past hour',\n },\n {\n dateRange: {\n startDate: sixHoursAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past 6 hours',\n },\n {\n dateRange: {\n startDate: oneDayAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past day',\n },\n {\n dateRange: {\n startDate: oneMonthAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past month',\n },\n ];\n\n return dateRangeList;\n};\n\nexport const getNextNDatesForDatePickerAllowOnlyList = (numberOfDays: number): Date[] => {\n const now = dayjs();\n\n return Array.from({ length: numberOfDays }, (_, i) =>\n now.add(i, 'day').startOf('day').toDate()\n );\n};\n\nexport const isDateNotInAllowList = (\n allowList: Array<Date> | undefined,\n date: Date\n): boolean =>\n Array.isArray(allowList) &&\n allowList.length > 0 &&\n !allowList.some(allowedDate => isSameDate(allowedDate, date));\n\nexport const datesAreWithinMaxRange = (\n startDate: Date,\n endDate: Date,\n maxRangeLength: number\n): boolean => {\n const daysDifference = Math.abs(dayjs(startDate).diff(dayjs(endDate), 'days'));\n\n return daysDifference <= maxRangeLength;\n};\n\nexport const isDateRangeTheWholeMonth = (\n { startDate, endDate }: DateRange,\n timezone: Timezone = 'system'\n): boolean => {\n const start = timezone === 'UTC' ? dayjs.utc(startDate) : dayjs(startDate);\n const end = timezone === 'UTC' ? dayjs.utc(endDate) : dayjs(endDate);\n\n if (start.month() !== end.month()) {\n return false;\n }\n\n const startDateIsFirstDay = start.isSame(start.startOf('month'), 'day');\n const endDateIsLastDay = end.isSame(end.endOf('month'), 'day');\n\n return startDateIsFirstDay && endDateIsLastDay;\n};\n\nexport const dateRangeIsValid = (dateRange: DateRange): boolean => {\n if (!dateRange?.startDate || !dateRange?.endDate) {\n return false;\n }\n\n if (!(dateRange.startDate instanceof Date) || !dayjs(dateRange.startDate).isValid()) {\n return false;\n }\n\n if (!(dateRange.endDate instanceof Date) || !dayjs(dateRange.endDate).isValid()) {\n return false;\n }\n\n if (dateRange.startDate.getTime() > dateRange.endDate.getTime()) {\n return false;\n }\n\n return true;\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../src/components/DatePicker/utils.ts"],"sourcesContent":["import { isSameDate } from '@h6s/calendar';\nimport { dayjs } from '@/utils/date';\n\nexport type Timezone = 'system' | 'UTC';\n\nexport interface DateRange {\n startDate: Date;\n endDate: Date;\n}\n\nconst locale = 'en-US';\n\nexport type Meridiem = 'am' | 'pm';\n\nexport interface Time {\n hour: number;\n minutes: number;\n}\n\nexport interface DateRangeListItem {\n dateRange: DateRange;\n label: string;\n}\n\nconst createFormatter = (options: Intl.DateTimeFormatOptions) => {\n const timezoneFormatters: Partial<Record<Timezone, Intl.DateTimeFormat>> = {};\n\n return (timezone: Timezone, date: Date): string => {\n if (!timezoneFormatters[timezone]) {\n const opts = timezone === 'UTC' ? { ...options, timeZone: 'UTC' } : options;\n timezoneFormatters[timezone] = new Intl.DateTimeFormat(locale, opts);\n }\n return timezoneFormatters[timezone].format(date);\n };\n};\n\nexport const formatSelectedDate = createFormatter({\n day: '2-digit',\n month: 'short',\n year: 'numeric',\n});\n\nexport const formatWeekday = createFormatter({ weekday: 'short' });\n\nexport const formatSelectedDateTime = createFormatter({\n day: '2-digit',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n});\n\nexport const formatSelectedDateTimeWithSeconds = createFormatter({\n day: '2-digit',\n month: 'short',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n});\n\nexport const formatDateHeader = createFormatter({\n month: 'short',\n year: 'numeric',\n});\n\n// In UTC mode, shift by the host offset so local-time getters return UTC\n// values. shiftFromTimezone reverses it.\n//\n// Caveat: round-tripping across a DST boundary drifts by an hour — each\n// direction reads getTimezoneOffset on its own input. Call sites don't\n// round-trip the same Date, so this hasn't bitten us.\nexport const shiftToTimezone = (date: Date, timezone: Timezone): Date => {\n if (timezone !== 'UTC') {\n return date;\n }\n return new Date(date.getTime() + date.getTimezoneOffset() * 60_000);\n};\n\nexport const shiftFromTimezone = (date: Date, timezone: Timezone): Date => {\n if (timezone !== 'UTC') {\n return date;\n }\n return new Date(date.getTime() - date.getTimezoneOffset() * 60_000);\n};\n\nexport const getPredefinedMonthsForDateRangePicker = (\n numberOfMonths: number\n): DateRange[] => {\n const now = dayjs();\n\n if (numberOfMonths < 0) {\n const lastSixMonths: DateRange[] = [];\n for (let i = 0; i < Math.abs(numberOfMonths); i++) {\n const date = now.subtract(i, 'month');\n if (date.date() === 1 && date.month() === now.month()) {\n continue;\n }\n lastSixMonths.push({\n startDate: date.startOf('month').toDate(),\n endDate: i === 0 ? now.toDate() : date.endOf('month').toDate(),\n });\n }\n\n return lastSixMonths.reverse();\n }\n\n const nextSixMonths: DateRange[] = [];\n for (let i = 0; i < numberOfMonths; i++) {\n const date = now.add(i, 'month');\n nextSixMonths.push({\n startDate: date.startOf('month').toDate(),\n endDate: date.endOf('month').toDate(),\n });\n }\n\n return nextSixMonths;\n};\n\nexport const getPredefinedTimePeriodsForDateTimePicker = (): DateRangeListItem[] => {\n const now = dayjs();\n\n const fifteenMinutesAgo = now.subtract(15, 'minute');\n const thirtyMinutesAgo = now.subtract(30, 'minute');\n const oneHourAgo = now.subtract(1, 'hour');\n const sixHoursAgo = now.subtract(6, 'hour');\n const oneDayAgo = now.subtract(1, 'day');\n const oneMonthAgo = now.subtract(1, 'month');\n\n const dateRangeList: DateRangeListItem[] = [\n {\n dateRange: {\n startDate: fifteenMinutesAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past 15 minutes',\n },\n {\n dateRange: {\n startDate: thirtyMinutesAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past 30 minutes',\n },\n {\n dateRange: {\n startDate: oneHourAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past hour',\n },\n {\n dateRange: {\n startDate: sixHoursAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past 6 hours',\n },\n {\n dateRange: {\n startDate: oneDayAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past day',\n },\n {\n dateRange: {\n startDate: oneMonthAgo.toDate(),\n endDate: now.toDate(),\n },\n label: 'Past month',\n },\n ];\n\n return dateRangeList;\n};\n\nexport const getNextNDatesForDatePickerAllowOnlyList = (numberOfDays: number): Date[] => {\n const now = dayjs();\n\n return Array.from({ length: numberOfDays }, (_, i) =>\n now.add(i, 'day').startOf('day').toDate()\n );\n};\n\nexport const isDateNotInAllowList = (\n allowList: Array<Date> | undefined,\n date: Date\n): boolean =>\n Array.isArray(allowList) &&\n allowList.length > 0 &&\n !allowList.some(allowedDate => isSameDate(allowedDate, date));\n\nexport const areDatesWithinMaxRange = (\n startDate: Date,\n endDate: Date,\n maxRangeLength: number\n): boolean => {\n // Compare calendar days; dayjs would otherwise drop a partial day from the diff.\n const daysDifference = Math.abs(\n dayjs(startDate).startOf('day').diff(dayjs(endDate).startOf('day'), 'days')\n );\n\n return daysDifference < maxRangeLength;\n};\n\nconst ONE_DAY_MS = 24 * 60 * 60 * 1000;\nconst toleranceMs = 60 * 1000;\n\nexport const isDateRangeWithinRange = (\n selectedRange: DateRange,\n predefinedRange: DateRange,\n timezone: Timezone = 'system'\n): boolean => {\n const { startDate, endDate } = predefinedRange;\n\n if (endDate.getTime() - startDate.getTime() < ONE_DAY_MS) {\n return (\n Math.abs(selectedRange.startDate.getTime() - startDate.getTime()) <= toleranceMs &&\n Math.abs(selectedRange.endDate.getTime() - endDate.getTime()) <= toleranceMs\n );\n }\n\n // Shifted the same way the calendar is, so the check agrees with the days it marks.\n const shiftedSelectedStart = shiftToTimezone(selectedRange.startDate, timezone);\n const shiftedSelectedEnd = shiftToTimezone(selectedRange.endDate, timezone);\n const shiftedStart = shiftToTimezone(startDate, timezone);\n const shiftedEnd = shiftToTimezone(endDate, timezone);\n\n return (\n isSameDate(shiftedSelectedStart, shiftedStart) &&\n isSameDate(shiftedSelectedEnd, shiftedEnd)\n );\n};\n\nexport const isDateRangeTheWholeMonth = (\n { startDate, endDate }: DateRange,\n timezone: Timezone = 'system'\n): boolean => {\n const start = timezone === 'UTC' ? dayjs.utc(startDate) : dayjs(startDate);\n const end = timezone === 'UTC' ? dayjs.utc(endDate) : dayjs(endDate);\n\n if (start.month() !== end.month()) {\n return false;\n }\n\n const startDateIsFirstDay = start.isSame(start.startOf('month'), 'day');\n const endDateIsLastDay = end.isSame(end.endOf('month'), 'day');\n\n return startDateIsFirstDay && endDateIsLastDay;\n};\n\nexport const isDateRangeValid = (dateRange: DateRange): boolean => {\n if (!dateRange?.startDate || !dateRange?.endDate) {\n return false;\n }\n\n if (!(dateRange.startDate instanceof Date) || !dayjs(dateRange.startDate).isValid()) {\n return false;\n }\n\n if (!(dateRange.endDate instanceof Date) || !dayjs(dateRange.endDate).isValid()) {\n return false;\n }\n\n if (dateRange.startDate.getTime() > dateRange.endDate.getTime()) {\n return false;\n }\n\n return true;\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
.generic-menu-panel_type_dropdown-menu__ezKZT {
|
|
21
21
|
max-width: var(--radix-dropdown-menu-content-available-width);
|
|
22
22
|
max-height: var(--radix-dropdown-menu-content-available-height);
|
|
23
|
+
/* Kept in this file (not Dropdown.module.css) so it can't lose to `overflow: hidden` above due to cross-file import order. */
|
|
24
|
+
overflow-y: auto;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
.generic-menu-panel_type_context-menu__nu-Kt {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { useId, useState, useRef, useCallback,
|
|
2
|
+
import { useId, useState, useRef, useCallback, useMemo, forwardRef, Children, isValidElement } from 'react';
|
|
3
3
|
import { Portal } from '@radix-ui/react-popover';
|
|
4
4
|
import { SelectPopoverRoot, StyledSelectTrigger, SelectValue, HiddenSelectElement, SelectPopoverContent, SelectList, SearchBarContainer, SearchBar, selectStyles, SelectListContent, SelectGroupContainer, SelectGroupName, SelectGroupContent, SelectNoDataContainer, SelectItemDescriptionText } from './SelectComponents.js';
|
|
5
5
|
import { OptionContext } from './OptionContext.js';
|
|
@@ -11,7 +11,6 @@ import { GenericMenuItem } from '../../GenericMenu/index.js';
|
|
|
11
11
|
import { IconWrapper } from '../../IconWrapper/index.js';
|
|
12
12
|
import { useInputModality } from '../../../hooks/internal/useInputModality.js';
|
|
13
13
|
import { cn } from '../../../lib/cva.js';
|
|
14
|
-
import { getTextFromNodes } from '../../../lib/getTextFromNodes.js';
|
|
15
14
|
import { useResolvedPortalContainer } from '../../../providers/PortalContext.js';
|
|
16
15
|
import { FormRoot } from '../../FormContainer/FormRoot.js';
|
|
17
16
|
import { FormElementContainer } from '../../FormContainer/FormElementContainer.js';
|
|
@@ -85,36 +84,18 @@ const NoOptionsDisplay = ({
|
|
|
85
84
|
}
|
|
86
85
|
);
|
|
87
86
|
};
|
|
88
|
-
const
|
|
87
|
+
const childrenToNormalizedOptions = (children, register) => {
|
|
89
88
|
return Children.toArray(children).flatMap((child) => {
|
|
90
89
|
if (isValidElement(child) && child && typeof child === "object") {
|
|
91
90
|
const type = child.type;
|
|
92
91
|
if (type.displayName === "Select.Group") {
|
|
93
|
-
|
|
94
|
-
return childrenToComboboxItemArray(
|
|
95
|
-
groupChildren,
|
|
96
|
-
callback,
|
|
97
|
-
getTextFromNodes(child.props.heading).toLowerCase()
|
|
98
|
-
);
|
|
92
|
+
return childrenToNormalizedOptions(child.props.children, register);
|
|
99
93
|
} else if (type.displayName === "Select.Item") {
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
callback({
|
|
104
|
-
disabled,
|
|
105
|
-
value,
|
|
106
|
-
title,
|
|
107
|
-
heading,
|
|
108
|
-
nodeProps: child.props
|
|
109
|
-
});
|
|
110
|
-
return {
|
|
111
|
-
disabled,
|
|
112
|
-
value,
|
|
113
|
-
title,
|
|
114
|
-
heading
|
|
115
|
-
};
|
|
94
|
+
const { value, disabled } = child.props;
|
|
95
|
+
register(value, child.props);
|
|
96
|
+
return { value, disabled };
|
|
116
97
|
} else if ("props" in child && child.props.children) {
|
|
117
|
-
return
|
|
98
|
+
return childrenToNormalizedOptions(child.props.children, register);
|
|
118
99
|
}
|
|
119
100
|
}
|
|
120
101
|
return [];
|
|
@@ -155,100 +136,70 @@ const InternalSelect = ({
|
|
|
155
136
|
const defaultId = useId();
|
|
156
137
|
const [search, setSearch] = useState("");
|
|
157
138
|
const [highlighted, setHighlighted] = useState();
|
|
158
|
-
const
|
|
159
|
-
const navigatable = useRef([]);
|
|
139
|
+
const [searchSource, setSearchSource] = useState(() => /* @__PURE__ */ new Map());
|
|
160
140
|
const valueNode = useRef(/* @__PURE__ */ new Map());
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
},
|
|
173
|
-
[search]
|
|
174
|
-
);
|
|
175
|
-
const onUpdateSearch = useCallback(
|
|
176
|
-
(search2) => {
|
|
177
|
-
setSearch(search2);
|
|
178
|
-
let hasHighlightedValue = false;
|
|
179
|
-
const visibleItemsList = [];
|
|
180
|
-
const navigatableList = [];
|
|
181
|
-
const searchLowerCase = search2.toLowerCase();
|
|
182
|
-
list.forEach((item) => {
|
|
183
|
-
if (item.title.includes(searchLowerCase) || item.heading?.includes(searchLowerCase)) {
|
|
184
|
-
if (item.value === highlighted) {
|
|
185
|
-
hasHighlightedValue = true;
|
|
186
|
-
}
|
|
187
|
-
visibleItemsList.push(item.value);
|
|
188
|
-
if (!item.disabled) {
|
|
189
|
-
navigatableList.push(item.value);
|
|
190
|
-
}
|
|
141
|
+
const registerValueNode = useCallback((value, nodeProps) => {
|
|
142
|
+
valueNode.current.set(value, nodeProps);
|
|
143
|
+
}, []);
|
|
144
|
+
const normalizedOptions = useMemo(() => {
|
|
145
|
+
if (options) {
|
|
146
|
+
return options.flatMap((option) => {
|
|
147
|
+
if ("options" in option) {
|
|
148
|
+
return (option.options ?? []).map((item) => {
|
|
149
|
+
registerValueNode(item.value, item);
|
|
150
|
+
return { value: item.value, disabled: item.disabled };
|
|
151
|
+
});
|
|
191
152
|
}
|
|
153
|
+
registerValueNode(option.value, option);
|
|
154
|
+
return { value: option.value, disabled: option.disabled };
|
|
192
155
|
});
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
156
|
+
} else if (children) {
|
|
157
|
+
return childrenToNormalizedOptions(children, registerValueNode);
|
|
158
|
+
}
|
|
159
|
+
return [];
|
|
160
|
+
}, [children, options, registerValueNode]);
|
|
161
|
+
const listNode = useRef(null);
|
|
162
|
+
const captureSearchSource = useCallback(() => {
|
|
163
|
+
const root = listNode.current;
|
|
164
|
+
if (!root) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const next = /* @__PURE__ */ new Map();
|
|
168
|
+
root.querySelectorAll("[cui-select-item][data-value]").forEach((el) => {
|
|
169
|
+
const value = el.getAttribute("data-value");
|
|
170
|
+
if (value === null) {
|
|
171
|
+
return;
|
|
197
172
|
}
|
|
198
|
-
|
|
199
|
-
|
|
173
|
+
const group = el.closest("[cui-select-group]");
|
|
174
|
+
const heading = group?.querySelector("[cui-select-group-name]")?.textContent ?? "";
|
|
175
|
+
next.set(value, `${el.textContent ?? ""} ${heading}`.toLowerCase());
|
|
176
|
+
});
|
|
177
|
+
setSearchSource(next);
|
|
178
|
+
}, []);
|
|
179
|
+
const onSearchChange = (next) => {
|
|
180
|
+
if (search === "" && next !== "") {
|
|
181
|
+
captureSearchSource();
|
|
182
|
+
}
|
|
183
|
+
setSearch(next);
|
|
184
|
+
};
|
|
185
|
+
const matchedOptions = useMemo(() => {
|
|
186
|
+
if (search === "") {
|
|
187
|
+
return normalizedOptions;
|
|
188
|
+
}
|
|
189
|
+
const searchLowerCase = search.toLowerCase();
|
|
190
|
+
return normalizedOptions.filter(
|
|
191
|
+
(item) => (searchSource.get(item.value) ?? "").includes(searchLowerCase)
|
|
192
|
+
);
|
|
193
|
+
}, [search, normalizedOptions, searchSource]);
|
|
194
|
+
const visibleValues = useMemo(
|
|
195
|
+
() => new Set(matchedOptions.map((o) => o.value)),
|
|
196
|
+
[matchedOptions]
|
|
200
197
|
);
|
|
201
|
-
const
|
|
202
|
-
(
|
|
203
|
-
|
|
204
|
-
if (options2) {
|
|
205
|
-
setList(
|
|
206
|
-
options2.flatMap((option) => {
|
|
207
|
-
if ("options" in option) {
|
|
208
|
-
const heading = getTextFromNodes(option.heading).toLowerCase();
|
|
209
|
-
return (option.options ?? []).map((item) => {
|
|
210
|
-
valueNode.current.set(item.value, item);
|
|
211
|
-
const title = getTextFromNodes(item.label).toLowerCase();
|
|
212
|
-
if (title.includes(lowerCasedSearch) || heading?.includes(lowerCasedSearch)) {
|
|
213
|
-
visibleList.current.push(item.value);
|
|
214
|
-
if (!disabled) {
|
|
215
|
-
navigatable.current.push(item.value);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return {
|
|
219
|
-
heading,
|
|
220
|
-
disabled: item.disabled,
|
|
221
|
-
value: item.value,
|
|
222
|
-
title
|
|
223
|
-
};
|
|
224
|
-
});
|
|
225
|
-
} else {
|
|
226
|
-
valueNode.current.set(option.value, option);
|
|
227
|
-
const title = getTextFromNodes(option.label).toLowerCase();
|
|
228
|
-
if (title.includes(lowerCasedSearch)) {
|
|
229
|
-
visibleList.current.push(option.value);
|
|
230
|
-
if (!disabled) {
|
|
231
|
-
navigatable.current.push(option.value);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
return {
|
|
235
|
-
disabled: option.disabled,
|
|
236
|
-
value: option.value,
|
|
237
|
-
title: getTextFromNodes(option.label)
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
})
|
|
241
|
-
);
|
|
242
|
-
} else if (children2) {
|
|
243
|
-
setList(childrenToComboboxItemArray(children2, updateElements));
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
[disabled, search, updateElements]
|
|
198
|
+
const navigableValues = useMemo(
|
|
199
|
+
() => matchedOptions.filter((o) => !o.disabled).map((o) => o.value),
|
|
200
|
+
[matchedOptions]
|
|
247
201
|
);
|
|
248
|
-
|
|
249
|
-
updateList(children, options);
|
|
250
|
-
setInitialized(true);
|
|
251
|
-
}, [children, options, updateList]);
|
|
202
|
+
const effectiveHighlight = highlighted && navigableValues.includes(highlighted) ? highlighted : navigableValues[0];
|
|
252
203
|
const inputRef = useRef(null);
|
|
253
204
|
const inputModalityProps = useInputModality();
|
|
254
205
|
const portalContainer = useResolvedPortalContainer(container);
|
|
@@ -256,41 +207,41 @@ const InternalSelect = ({
|
|
|
256
207
|
inputRef.current?.focus();
|
|
257
208
|
};
|
|
258
209
|
const clearSearch = () => {
|
|
259
|
-
|
|
210
|
+
setSearch("");
|
|
260
211
|
};
|
|
261
212
|
const onKeyDown = (e) => {
|
|
262
213
|
if (!e.defaultPrevented) {
|
|
263
214
|
if (e.key === "Enter") {
|
|
264
215
|
e.preventDefault();
|
|
265
|
-
if (
|
|
266
|
-
onSelect(
|
|
267
|
-
} else if (
|
|
216
|
+
if (effectiveHighlight) {
|
|
217
|
+
onSelect(effectiveHighlight, void 0, e);
|
|
218
|
+
} else if (matchedOptions.length === 0 && allowCreateOption) {
|
|
268
219
|
onSelect(search, "custom", e);
|
|
269
220
|
}
|
|
270
221
|
} else if (["ArrowUp", "ArrowDown", "Home", "End"].includes(e.key)) {
|
|
271
222
|
e.preventDefault();
|
|
272
|
-
let nextHighlightedValue =
|
|
273
|
-
const highlightedIndex =
|
|
274
|
-
(value) => value ===
|
|
223
|
+
let nextHighlightedValue = effectiveHighlight;
|
|
224
|
+
const highlightedIndex = navigableValues.findIndex(
|
|
225
|
+
(value) => value === effectiveHighlight
|
|
275
226
|
);
|
|
276
227
|
if (e.key === "ArrowUp") {
|
|
277
228
|
if (highlightedIndex === 0) {
|
|
278
|
-
nextHighlightedValue =
|
|
229
|
+
nextHighlightedValue = navigableValues[navigableValues.length - 1];
|
|
279
230
|
} else {
|
|
280
|
-
nextHighlightedValue =
|
|
231
|
+
nextHighlightedValue = navigableValues[highlightedIndex - 1];
|
|
281
232
|
}
|
|
282
233
|
} else if (e.key === "ArrowDown") {
|
|
283
234
|
e.preventDefault();
|
|
284
|
-
if (highlightedIndex ===
|
|
285
|
-
nextHighlightedValue =
|
|
235
|
+
if (highlightedIndex === navigableValues.length - 1) {
|
|
236
|
+
nextHighlightedValue = navigableValues[0];
|
|
286
237
|
} else {
|
|
287
|
-
nextHighlightedValue =
|
|
238
|
+
nextHighlightedValue = navigableValues[highlightedIndex + 1];
|
|
288
239
|
}
|
|
289
240
|
} else if (e.key === "End") {
|
|
290
241
|
e.preventDefault();
|
|
291
|
-
nextHighlightedValue =
|
|
242
|
+
nextHighlightedValue = navigableValues[navigableValues.length - 1];
|
|
292
243
|
} else if (e.key === "Home") {
|
|
293
|
-
nextHighlightedValue =
|
|
244
|
+
nextHighlightedValue = navigableValues[0];
|
|
294
245
|
e.preventDefault();
|
|
295
246
|
}
|
|
296
247
|
setHighlighted(nextHighlightedValue);
|
|
@@ -298,21 +249,19 @@ const InternalSelect = ({
|
|
|
298
249
|
}
|
|
299
250
|
};
|
|
300
251
|
const isHidden = useCallback(
|
|
301
|
-
(value) =>
|
|
302
|
-
|
|
303
|
-
},
|
|
304
|
-
[visibleList]
|
|
252
|
+
(value) => !visibleValues.has(value ?? ""),
|
|
253
|
+
[visibleValues]
|
|
305
254
|
);
|
|
306
255
|
const optionContextValue = useMemo(() => {
|
|
307
256
|
return {
|
|
308
257
|
search,
|
|
309
258
|
updateHighlighted: setHighlighted,
|
|
310
|
-
highlighted,
|
|
259
|
+
highlighted: effectiveHighlight,
|
|
311
260
|
isHidden,
|
|
312
261
|
onSelect,
|
|
313
262
|
selectedValues
|
|
314
263
|
};
|
|
315
|
-
}, [search,
|
|
264
|
+
}, [search, effectiveHighlight, isHidden, onSelect, selectedValues]);
|
|
316
265
|
const onCreateOption = (e) => {
|
|
317
266
|
e.preventDefault();
|
|
318
267
|
e.stopPropagation();
|
|
@@ -345,7 +294,7 @@ const InternalSelect = ({
|
|
|
345
294
|
"data-testid": "select-trigger",
|
|
346
295
|
...triggerProps,
|
|
347
296
|
children: [
|
|
348
|
-
|
|
297
|
+
/* @__PURE__ */ jsx(SelectValue, { children: selectedValues.length === 0 ? placeholder : multiple ? /* @__PURE__ */ jsx(
|
|
349
298
|
MultiSelectValue,
|
|
350
299
|
{
|
|
351
300
|
disabled: disabled ?? false,
|
|
@@ -380,7 +329,7 @@ const InternalSelect = ({
|
|
|
380
329
|
form,
|
|
381
330
|
value: selectedValues,
|
|
382
331
|
onChange: () => null,
|
|
383
|
-
children:
|
|
332
|
+
children: normalizedOptions.map((item) => /* @__PURE__ */ jsx(
|
|
384
333
|
"option",
|
|
385
334
|
{
|
|
386
335
|
value: item.value,
|
|
@@ -398,10 +347,7 @@ const InternalSelect = ({
|
|
|
398
347
|
sideOffset: 5,
|
|
399
348
|
onFocus,
|
|
400
349
|
onCloseAutoFocus: () => {
|
|
401
|
-
|
|
402
|
-
},
|
|
403
|
-
onOpenAutoFocus: () => {
|
|
404
|
-
setHighlighted(visibleList.current[0]);
|
|
350
|
+
setSearch("");
|
|
405
351
|
},
|
|
406
352
|
align: "start",
|
|
407
353
|
$useFullWidthItems: useFullWidthItems,
|
|
@@ -413,7 +359,7 @@ const InternalSelect = ({
|
|
|
413
359
|
{
|
|
414
360
|
ref: inputRef,
|
|
415
361
|
value: search,
|
|
416
|
-
onChange: (e) =>
|
|
362
|
+
onChange: (e) => onSearchChange(e.target.value),
|
|
417
363
|
"data-testid": "select-search-input",
|
|
418
364
|
onKeyDown,
|
|
419
365
|
$showSearch: showSearch
|
|
@@ -434,54 +380,61 @@ const InternalSelect = ({
|
|
|
434
380
|
}
|
|
435
381
|
)
|
|
436
382
|
] }),
|
|
437
|
-
/* @__PURE__ */ jsx(
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
383
|
+
/* @__PURE__ */ jsx(
|
|
384
|
+
SelectListContent,
|
|
385
|
+
{
|
|
386
|
+
ref: listNode,
|
|
387
|
+
$maxHeight: maxHeight,
|
|
388
|
+
children: /* @__PURE__ */ jsx(OptionContext.Provider, { value: optionContextValue, children: options && options.length > 0 ? options.map((props2, index) => {
|
|
389
|
+
if ("options" in props2) {
|
|
390
|
+
const { options: itemList = [], ...groupProps } = props2;
|
|
391
|
+
return /* @__PURE__ */ jsx(
|
|
392
|
+
SelectGroup,
|
|
393
|
+
{
|
|
394
|
+
...groupProps,
|
|
395
|
+
children: itemList.map((itemProps, itemIndex) => {
|
|
396
|
+
if (checkbox) {
|
|
397
|
+
return /* @__PURE__ */ jsx(
|
|
398
|
+
MultiSelectCheckboxItem,
|
|
399
|
+
{
|
|
400
|
+
...itemProps
|
|
401
|
+
},
|
|
402
|
+
`select-${id}-group-${index}-item-${itemIndex}`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
return /* @__PURE__ */ jsx(
|
|
406
|
+
SelectItem,
|
|
407
|
+
{
|
|
408
|
+
...itemProps
|
|
409
|
+
},
|
|
410
|
+
`select-${id}-group-${index}-item-${itemIndex}`
|
|
411
|
+
);
|
|
412
|
+
})
|
|
413
|
+
},
|
|
414
|
+
`select-${id}-group-${index}`
|
|
415
|
+
);
|
|
416
|
+
} else {
|
|
417
|
+
if (checkbox) {
|
|
454
418
|
return /* @__PURE__ */ jsx(
|
|
455
|
-
|
|
419
|
+
MultiSelectCheckboxItem,
|
|
456
420
|
{
|
|
457
|
-
...
|
|
421
|
+
...props2
|
|
458
422
|
},
|
|
459
|
-
`select-${id}-
|
|
423
|
+
`select-${id}-item-${index}`
|
|
460
424
|
);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
},
|
|
472
|
-
`select-${id}-item-${index}`
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
return /* @__PURE__ */ jsx(
|
|
476
|
-
SelectItem,
|
|
477
|
-
{
|
|
478
|
-
...props2
|
|
479
|
-
},
|
|
480
|
-
`select-${id}-item-${index}`
|
|
481
|
-
);
|
|
425
|
+
}
|
|
426
|
+
return /* @__PURE__ */ jsx(
|
|
427
|
+
SelectItem,
|
|
428
|
+
{
|
|
429
|
+
...props2
|
|
430
|
+
},
|
|
431
|
+
`select-${id}-item-${index}`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
}) : children })
|
|
482
435
|
}
|
|
483
|
-
|
|
484
|
-
|
|
436
|
+
),
|
|
437
|
+
matchedOptions.length === 0 && (allowCreateOption || !!noAvailableOptions) && /* @__PURE__ */ jsx(
|
|
485
438
|
NoOptionsDisplay,
|
|
486
439
|
{
|
|
487
440
|
allowCreateOption,
|
|
@@ -521,10 +474,11 @@ const SelectGroup = forwardRef(
|
|
|
521
474
|
SelectGroupContainer,
|
|
522
475
|
{
|
|
523
476
|
...props,
|
|
477
|
+
"cui-select-group": "",
|
|
524
478
|
ref: mergeRefs([
|
|
525
479
|
forwardedRef,
|
|
526
480
|
(node) => {
|
|
527
|
-
const hidden = node?.querySelectorAll("[cui-select-item]").length === 0;
|
|
481
|
+
const hidden = node?.querySelectorAll("[cui-select-item]:not([hidden])").length === 0;
|
|
528
482
|
if (hidden) {
|
|
529
483
|
node?.setAttribute("hidden", "");
|
|
530
484
|
} else {
|
|
@@ -534,7 +488,7 @@ const SelectGroup = forwardRef(
|
|
|
534
488
|
}
|
|
535
489
|
]),
|
|
536
490
|
children: [
|
|
537
|
-
/* @__PURE__ */ jsx(SelectGroupName, { children: heading }),
|
|
491
|
+
/* @__PURE__ */ jsx(SelectGroupName, { "cui-select-group-name": "", children: heading }),
|
|
538
492
|
/* @__PURE__ */ jsx(SelectGroupContent, { children })
|
|
539
493
|
]
|
|
540
494
|
}
|
|
@@ -573,15 +527,15 @@ const SelectItem = forwardRef(
|
|
|
573
527
|
updateHighlighted(value);
|
|
574
528
|
}
|
|
575
529
|
};
|
|
576
|
-
|
|
577
|
-
return null;
|
|
578
|
-
}
|
|
530
|
+
const hidden = isHidden(value);
|
|
579
531
|
const isChecked = selectedValues.includes(value);
|
|
580
532
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
581
533
|
/* @__PURE__ */ jsxs(
|
|
582
534
|
GenericMenuItem,
|
|
583
535
|
{
|
|
584
536
|
...props,
|
|
537
|
+
hidden,
|
|
538
|
+
className: cn(selectStyles["select-item"], props.className),
|
|
585
539
|
"data-value": value,
|
|
586
540
|
onClick: onSelectValue,
|
|
587
541
|
onMouseOver,
|
|
@@ -618,7 +572,7 @@ const SelectItem = forwardRef(
|
|
|
618
572
|
]
|
|
619
573
|
}
|
|
620
574
|
),
|
|
621
|
-
separator && /* @__PURE__ */ jsx(Separator, { size: "sm" })
|
|
575
|
+
separator && !hidden && /* @__PURE__ */ jsx(Separator, { size: "sm" })
|
|
622
576
|
] });
|
|
623
577
|
}
|
|
624
578
|
);
|
|
@@ -655,15 +609,15 @@ const MultiSelectCheckboxItem = forwardRef(
|
|
|
655
609
|
updateHighlighted(value);
|
|
656
610
|
}
|
|
657
611
|
};
|
|
658
|
-
|
|
659
|
-
return null;
|
|
660
|
-
}
|
|
612
|
+
const hidden = isHidden(value);
|
|
661
613
|
const isChecked = selectedValues.includes(value);
|
|
662
614
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
663
615
|
/* @__PURE__ */ jsx(
|
|
664
616
|
GenericMenuItem,
|
|
665
617
|
{
|
|
666
618
|
...props,
|
|
619
|
+
hidden,
|
|
620
|
+
className: cn(selectStyles["select-item"], props.className),
|
|
667
621
|
"data-value": value,
|
|
668
622
|
onClick: handleMenuItemClick,
|
|
669
623
|
onMouseOver: handleMenuItemMouseOver,
|
|
@@ -707,7 +661,7 @@ const MultiSelectCheckboxItem = forwardRef(
|
|
|
707
661
|
)
|
|
708
662
|
}
|
|
709
663
|
),
|
|
710
|
-
separator && /* @__PURE__ */ jsx(Separator, { size: "sm" })
|
|
664
|
+
separator && !hidden && /* @__PURE__ */ jsx(Separator, { size: "sm" })
|
|
711
665
|
] });
|
|
712
666
|
}
|
|
713
667
|
);
|