@mittwald/flow-react-components 1.6.0-next.5 → 1.6.0-next.50
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/AGENTS.md +132 -88
- package/USAGE.md +7 -2
- package/dist/assets/component-index.json +1 -1
- package/dist/assets/doc-properties.json +1 -1
- package/dist/css/all-layered.css +1 -1
- package/dist/css/all.css +1 -1
- package/dist/js/_virtual/_18.locale.mjs +14 -0
- package/dist/js/default.mjs +4 -3
- package/dist/js/flr-universal.mjs +2 -1
- package/dist/js/node_modules/.pnpm/{@lezer_lr@1.4.10 → @lezer_lr@1.4.11}/node_modules/@lezer/lr/dist/index.mjs +40 -28
- package/dist/js/node_modules/.pnpm/@lezer_lr@1.4.11/node_modules/@lezer/lr/dist/index.mjs.map +1 -0
- package/dist/js/packages/components/src/components/AccentBox/AccentBox.mjs +3 -2
- package/dist/js/packages/components/src/components/AccentBox/AccentBox.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Accordion/Accordion.mjs +3 -2
- package/dist/js/packages/components/src/components/Accordion/Accordion.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Action/models/ActionState.mjs +2 -2
- package/dist/js/packages/components/src/components/ActionGroup/ActionGroup.mjs +3 -3
- package/dist/js/packages/components/src/components/ActionGroup/ActionGroup.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Activity/Activity.mjs +1 -1
- package/dist/js/packages/components/src/components/Activity/Activity.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Alert/Alert.mjs +3 -2
- package/dist/js/packages/components/src/components/Alert/Alert.mjs.map +1 -1
- package/dist/js/packages/components/src/components/AlertBadge/AlertBadge.mjs +1 -1
- package/dist/js/packages/components/src/components/AlertBadge/AlertBadge.mjs.map +1 -1
- package/dist/js/packages/components/src/components/AlertBadge/AlertBadge.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Badge/Badge.mjs +2 -2
- package/dist/js/packages/components/src/components/Badge/Badge.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Badge/Badge.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Calendar/components/RangeCalendar/helpers/useCalendarDateRangePresets.mjs +1 -1
- package/dist/js/packages/components/src/components/CartesianChart/CartesianChart.mjs +6 -8
- package/dist/js/packages/components/src/components/CartesianChart/CartesianChart.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CartesianChart/components/YAxis/YAxis.mjs +23 -5
- package/dist/js/packages/components/src/components/CartesianChart/components/YAxis/YAxis.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CartesianChart/hooks/useTickLabelWidth.mjs +67 -0
- package/dist/js/packages/components/src/components/CartesianChart/hooks/useTickLabelWidth.mjs.map +1 -0
- package/dist/js/packages/components/src/components/Checkbox/Checkbox.mjs +2 -2
- package/dist/js/packages/components/src/components/Checkbox/Checkbox.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CodeBlock/CodeBlock.mjs +3 -3
- package/dist/js/packages/components/src/components/CodeBlock/CodeBlock.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CodeEditor/CodeEditor.mjs +41 -12
- package/dist/js/packages/components/src/components/CodeEditor/CodeEditor.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CodeEditor/hooks/useCodeEditorExtensions.mjs +29 -16
- package/dist/js/packages/components/src/components/CodeEditor/hooks/useCodeEditorExtensions.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CodeEditor/languages/dotEnv/dotEnv.mjs +1 -1
- package/dist/js/packages/components/src/components/ComboBox/ComboBox.mjs +3 -2
- package/dist/js/packages/components/src/components/ComboBox/ComboBox.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CountryOptions/CountryOptions.mjs +5 -1
- package/dist/js/packages/components/src/components/CountryOptions/CountryOptions.mjs.map +1 -1
- package/dist/js/packages/components/src/components/DatePicker/DatePicker.mjs +2 -1
- package/dist/js/packages/components/src/components/DatePicker/DatePicker.mjs.map +1 -1
- package/dist/js/packages/components/src/components/DateRangePicker/DateRangePicker.mjs +2 -1
- package/dist/js/packages/components/src/components/DateRangePicker/DateRangePicker.mjs.map +1 -1
- package/dist/js/packages/components/src/components/DeprecationWarningProvider/DeprecationWarningProvider.mjs +40 -8
- package/dist/js/packages/components/src/components/DeprecationWarningProvider/DeprecationWarningProvider.mjs.map +1 -1
- package/dist/js/packages/components/src/components/DonutChart/DonutChart.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Heading/Heading.mjs +2 -0
- package/dist/js/packages/components/src/components/Heading/Heading.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Heading/Heading.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Icon/Icon.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/IllustratedMessage/IllustratedMessage.mjs +3 -2
- package/dist/js/packages/components/src/components/IllustratedMessage/IllustratedMessage.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Label/Label.mjs +0 -4
- package/dist/js/packages/components/src/components/Label/Label.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Link/Link.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/List.mjs +27 -23
- package/dist/js/packages/components/src/components/List/List.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Header/components/ActiveFilters/ActiveFilters.mjs +5 -2
- package/dist/js/packages/components/src/components/List/components/Header/components/ActiveFilters/ActiveFilters.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/AllFiltersModal.mjs +2 -2
- package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/AllFiltersModal.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/FilterAccordionDateRange.mjs +5 -3
- package/dist/js/packages/components/src/components/List/components/Header/components/AllFiltersModal/FilterAccordionDateRange.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Header/components/DateTimeRangeFields/DateTimeRangeFields.mjs +101 -0
- package/dist/js/packages/components/src/components/List/components/Header/components/DateTimeRangeFields/DateTimeRangeFields.mjs.map +1 -0
- package/dist/js/packages/components/src/components/List/components/Header/components/DateTimeRangeFields/DateTimeRangeFields.module.mjs +13 -0
- package/dist/js/packages/components/src/components/List/components/Header/components/DateTimeRangeFields/DateTimeRangeFields.module.mjs.map +1 -0
- package/dist/js/packages/components/src/components/List/components/Header/components/FilterContextMenu/DateRangeFilterPopover.mjs +16 -9
- package/dist/js/packages/components/src/components/List/components/Header/components/FilterContextMenu/DateRangeFilterPopover.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Header/components/FilterContextMenu/FilterContextMenus.module.mjs +6 -2
- package/dist/js/packages/components/src/components/List/components/Header/components/FilterContextMenu/FilterContextMenus.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Header/components/SearchField/SearchField.mjs +4 -2
- package/dist/js/packages/components/src/components/List/components/Header/components/SearchField/SearchField.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Items/Items.mjs +27 -1
- package/dist/js/packages/components/src/components/List/components/Items/Items.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Items/components/Item/Item.mjs +1 -1
- package/dist/js/packages/components/src/components/List/components/Items/components/Item/Item.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Items/components/Item/hooks/useGridItemProps.mjs +1 -2
- package/dist/js/packages/components/src/components/List/components/Items/components/Item/hooks/useGridItemProps.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Items/views/GridList/GridList.mjs +3 -0
- package/dist/js/packages/components/src/components/List/components/Items/views/GridList/GridList.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/ListItemView/ListItemView.mjs +46 -44
- package/dist/js/packages/components/src/components/List/components/ListItemView/ListItemView.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/ListItemView/components/ListItemViewContent/ListItemViewContent.mjs +25 -25
- package/dist/js/packages/components/src/components/List/components/ListItemView/components/ListItemViewContent/ListItemViewContent.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/ListSummary/ListSummary.mjs +5 -9
- package/dist/js/packages/components/src/components/List/components/ListSummary/ListSummary.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Table/Table.mjs +29 -13
- package/dist/js/packages/components/src/components/List/components/Table/Table.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/components/Table/components/Row.mjs +31 -0
- package/dist/js/packages/components/src/components/List/components/Table/components/Row.mjs.map +1 -0
- package/dist/js/packages/components/src/components/List/hooks/useLatestOnAction.mjs +21 -0
- package/dist/js/packages/components/src/components/List/hooks/useLatestOnAction.mjs.map +1 -0
- package/dist/js/packages/components/src/components/List/hooks/useListSelector.mjs +18 -0
- package/dist/js/packages/components/src/components/List/hooks/useListSelector.mjs.map +1 -0
- package/dist/js/packages/components/src/components/List/listContext.mjs +32 -2
- package/dist/js/packages/components/src/components/List/listContext.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/List.mjs +1 -0
- package/dist/js/packages/components/src/components/List/model/List.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/ListViewMode.mjs +2 -2
- package/dist/js/packages/components/src/components/List/model/ReactTable.mjs +2 -2
- package/dist/js/packages/components/src/components/List/model/filter/DateRangeFilter.mjs +15 -2
- package/dist/js/packages/components/src/components/List/model/filter/DateRangeFilter.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/filter/resolveDateRangeFilterValue.mjs +16 -0
- package/dist/js/packages/components/src/components/List/model/filter/resolveDateRangeFilterValue.mjs.map +1 -0
- package/dist/js/packages/components/src/components/List/model/item/ItemView.mjs +20 -7
- package/dist/js/packages/components/src/components/List/model/item/ItemView.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/loading/IncrementalLoaderState.mjs +2 -2
- package/dist/js/packages/components/src/components/List/model/table/Table.mjs +11 -1
- package/dist/js/packages/components/src/components/List/model/table/Table.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/table/TableBody.mjs +5 -1
- package/dist/js/packages/components/src/components/List/model/table/TableBody.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/table/TableCell.mjs +1 -1
- package/dist/js/packages/components/src/components/List/model/table/TableCell.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/table/TableColumn.mjs +4 -0
- package/dist/js/packages/components/src/components/List/model/table/TableColumn.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/table/TableHeader.mjs +8 -1
- package/dist/js/packages/components/src/components/List/model/table/TableHeader.mjs.map +1 -1
- package/dist/js/packages/components/src/components/List/model/table/TableRow.mjs +28 -1
- package/dist/js/packages/components/src/components/List/model/table/TableRow.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Markdown/Markdown.mjs +25 -7
- package/dist/js/packages/components/src/components/Markdown/Markdown.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Markdown/components/SkeletonBlocks.mjs +1 -1
- package/dist/js/packages/components/src/components/Markdown/components/SkeletonBlocks.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Markdown/lib/isExternalHref.mjs +8 -0
- package/dist/js/packages/components/src/components/Markdown/lib/isExternalHref.mjs.map +1 -0
- package/dist/js/packages/components/src/components/MenuItem/MenuItem.mjs +32 -3
- package/dist/js/packages/components/src/components/MenuItem/MenuItem.mjs.map +1 -1
- package/dist/js/packages/components/src/components/MenuItem/MenuItem.module.mjs +1 -3
- package/dist/js/packages/components/src/components/MessageThread/MessageThread.mjs +1 -1
- package/dist/js/packages/components/src/components/MessageThread/MessageThread.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Modal/Modal.mjs +9 -2
- package/dist/js/packages/components/src/components/Modal/Modal.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Navigation/Navigation.module.mjs +1 -3
- package/dist/js/packages/components/src/components/NumberField/NumberField.mjs +2 -3
- package/dist/js/packages/components/src/components/NumberField/NumberField.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Option/Option.module.mjs +1 -3
- package/dist/js/packages/components/src/components/Overlay/components/OverlayContent.mjs +2 -1
- package/dist/js/packages/components/src/components/Overlay/components/OverlayContent.mjs.map +1 -1
- package/dist/js/packages/components/src/components/PasswordCreationField/PasswordCreationField.mjs +3 -3
- package/dist/js/packages/components/src/components/PasswordCreationField/PasswordCreationField.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.mjs +1 -1
- package/dist/js/packages/components/src/components/Popover/components/NonModalPopoverContent/NonModalPopoverContent.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Popover/components/PopoverContent/PopoverContent.mjs +4 -2
- package/dist/js/packages/components/src/components/Popover/components/PopoverContent/PopoverContent.mjs.map +1 -1
- package/dist/js/packages/components/src/components/ProgressBar/ProgressBar.mjs.map +1 -1
- package/dist/js/packages/components/src/components/ProgressBar/components/ProgressBarLegend.mjs +5 -4
- package/dist/js/packages/components/src/components/ProgressBar/components/ProgressBarLegend.mjs.map +1 -1
- package/dist/js/packages/components/src/components/RadioGroup/RadioGroup.mjs +2 -3
- package/dist/js/packages/components/src/components/RadioGroup/RadioGroup.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Rating/Rating.mjs +12 -11
- package/dist/js/packages/components/src/components/Rating/Rating.mjs.map +1 -1
- package/dist/js/packages/components/src/components/SearchField/SearchField.mjs +2 -3
- package/dist/js/packages/components/src/components/SearchField/SearchField.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Section/Section.mjs +9 -5
- package/dist/js/packages/components/src/components/Section/Section.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Section/components/SectionHeader/SectionHeader.mjs +0 -4
- package/dist/js/packages/components/src/components/Section/components/SectionHeader/SectionHeader.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Section/context.mjs +47 -0
- package/dist/js/packages/components/src/components/Section/context.mjs.map +1 -0
- package/dist/js/packages/components/src/components/SegmentedControl/SegmentedControl.mjs +2 -3
- package/dist/js/packages/components/src/components/SegmentedControl/SegmentedControl.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Select/Select.mjs +2 -3
- package/dist/js/packages/components/src/components/Select/Select.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Slider/Slider.mjs +47 -41
- package/dist/js/packages/components/src/components/Slider/Slider.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Table/Table.mjs +3 -0
- package/dist/js/packages/components/src/components/Table/Table.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Table/Table.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Table/components/TableCell/TableCell.mjs +5 -12
- package/dist/js/packages/components/src/components/Table/components/TableCell/TableCell.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Table/components/TableColumn/TableColumn.mjs +4 -2
- package/dist/js/packages/components/src/components/Table/components/TableColumn/TableColumn.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Table/components/TableHeader/TableHeader.mjs +7 -1
- package/dist/js/packages/components/src/components/Table/components/TableHeader/TableHeader.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Table/components/TableHeader/context.mjs +14 -0
- package/dist/js/packages/components/src/components/Table/components/TableHeader/context.mjs.map +1 -0
- package/dist/js/packages/components/src/components/Tabs/Tabs.mjs +6 -8
- package/dist/js/packages/components/src/components/Tabs/Tabs.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Tabs/Tabs.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Tabs/components/TabTitle/TabTitle.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Text/Text.module.mjs.map +1 -1
- package/dist/js/packages/components/src/components/TextField/TextField.mjs +11 -8
- package/dist/js/packages/components/src/components/TextField/TextField.mjs.map +1 -1
- package/dist/js/packages/components/src/components/TranslationProvider/useLocalizedStringFormatter.mjs +15 -2
- package/dist/js/packages/components/src/components/TranslationProvider/useLocalizedStringFormatter.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Wrap/Wrap.mjs.map +1 -1
- package/dist/js/packages/components/src/integrations/react-hook-form/components/Field/Field.mjs +1 -1
- package/dist/js/packages/components/src/integrations/react-hook-form/components/Form/Form.mjs +4 -1
- package/dist/js/packages/components/src/integrations/react-hook-form/components/Form/Form.mjs.map +1 -1
- package/dist/js/packages/components/src/integrations/react-hook-form/components/FormRootError/FormRootError.mjs +1 -1
- package/dist/js/packages/components/src/integrations/react-hook-form/components/FormSettingsProvider/FormSettingsProvider.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs +10 -158
- package/dist/js/packages/components/src/lib/controller/overlay/OverlayController.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/controller/overlay/useCloseOverlayConfirmationController.mjs +1 -0
- package/dist/js/packages/components/src/lib/controller/overlay/useCloseOverlayConfirmationController.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/hooks/dom/useVirtualKeyboardVisible.mjs +8 -4
- package/dist/js/packages/components/src/lib/hooks/dom/useVirtualKeyboardVisible.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/object/isPlainObjectDeepEqual.mjs +29 -0
- package/dist/js/packages/components/src/lib/object/isPlainObjectDeepEqual.mjs.map +1 -0
- package/dist/js/packages/components/src/lib/propsContext/components/ClearPropsContext.mjs +2 -1
- package/dist/js/packages/components/src/lib/propsContext/components/ClearPropsContext.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/propsContext/components/PropsContextProvider.mjs +14 -3
- package/dist/js/packages/components/src/lib/propsContext/components/PropsContextProvider.mjs.map +1 -1
- package/dist/js/packages/components/src/lib/slotContext/SlotContextProvider.mjs +9 -4
- package/dist/js/packages/components/src/lib/slotContext/SlotContextProvider.mjs.map +1 -1
- package/dist/js/packages/components/src/views/DatePickerView.mjs +16 -0
- package/dist/js/packages/components/src/views/DatePickerView.mjs.map +1 -0
- package/dist/js/packages/components/src/views/LabelView.mjs +16 -0
- package/dist/js/packages/components/src/views/LabelView.mjs.map +1 -0
- package/dist/js/packages/components/src/views/TimeFieldView.mjs +16 -0
- package/dist/js/packages/components/src/views/TimeFieldView.mjs.map +1 -0
- package/dist/js/packages/components-base/src/index.mjs +5 -2
- package/dist/js/packages/components-base/src/list/filter/ListDateRangeFilter.mjs +1 -0
- package/dist/js/packages/components-base/src/list/filter/ListDateRangeFilter.mjs.map +1 -1
- package/dist/js/packages/components-base/src/list/filter/ListFilter.mjs +4 -1
- package/dist/js/packages/components-base/src/list/filter/ListFilter.mjs.map +1 -1
- package/dist/js/packages/components-base/src/list/filter/dateRange.mjs +37 -13
- package/dist/js/packages/components-base/src/list/filter/dateRange.mjs.map +1 -1
- package/dist/js/packages/components-base/src/list/filter/dateTimeRangeFields.mjs +55 -0
- package/dist/js/packages/components-base/src/list/filter/dateTimeRangeFields.mjs.map +1 -0
- package/dist/js/packages/components-base/src/list/filter/formatDateRange.mjs +27 -0
- package/dist/js/packages/components-base/src/list/filter/formatDateRange.mjs.map +1 -0
- package/dist/js/packages/components-base/src/list/loading/ListLoaderState.mjs +10 -5
- package/dist/js/packages/components-base/src/list/loading/ListLoaderState.mjs.map +1 -1
- package/dist/js/packages/components-base/src/overlay/OverlayState.mjs +196 -0
- package/dist/js/packages/components-base/src/overlay/OverlayState.mjs.map +1 -0
- package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs +1 -1
- package/dist/js/packages/design-tokens/dist/json-runtime/all-dark.mjs.map +1 -1
- package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs +1 -1
- package/dist/js/packages/design-tokens/dist/json-runtime/all-light.mjs.map +1 -1
- package/dist/types/_bundled/flow-components-base/index.d.ts +4 -1
- package/dist/types/_bundled/flow-components-base/list/filter/ListFilter.d.ts +2 -0
- package/dist/types/_bundled/flow-components-base/list/filter/dateRange.d.ts +24 -1
- package/dist/types/_bundled/flow-components-base/list/filter/dateTimeRangeFields.d.ts +34 -0
- package/dist/types/_bundled/flow-components-base/list/filter/formatDateRange.d.ts +7 -0
- package/dist/types/_bundled/flow-components-base/list/loading/ListLoaderState.d.ts +5 -0
- package/dist/types/_bundled/flow-components-base/overlay/OverlayState.d.ts +94 -0
- package/dist/types/components/AlertBadge/AlertBadge.d.ts +2 -2
- package/dist/types/components/Badge/Badge.d.ts +2 -2
- package/dist/types/components/CartesianChart/hooks/useTickLabelWidth.d.ts +1 -0
- package/dist/types/components/CodeBlock/CodeBlock.d.ts +1 -1
- package/dist/types/components/DonutChart/DonutChart.d.ts +1 -4
- package/dist/types/components/Link/Link.d.ts +1 -1
- package/dist/types/components/List/components/Header/components/DateTimeRangeFields/DateTimeRangeFields.d.ts +8 -0
- package/dist/types/components/List/components/Items/components/Item/Item.d.ts +2 -0
- package/dist/types/components/List/components/Items/components/Item/hooks/useGridItemProps.d.ts +1 -0
- package/dist/types/components/List/components/ListSummary/ListSummary.d.ts +3 -2
- package/dist/types/components/List/components/Table/components/Row.d.ts +13 -0
- package/dist/types/components/List/hooks/useLatestOnAction.d.ts +7 -0
- package/dist/types/components/List/hooks/useListSelector.d.ts +6 -0
- package/dist/types/components/List/index.d.ts +2 -0
- package/dist/types/components/List/listContext.d.ts +16 -0
- package/dist/types/components/List/model/filter/DateRangeFilter.d.ts +15 -8
- package/dist/types/components/List/model/filter/resolveDateRangeFilterValue.d.ts +11 -0
- package/dist/types/components/List/model/filter/types.d.ts +23 -1
- package/dist/types/components/List/model/item/ItemView.d.ts +34 -11
- package/dist/types/components/List/model/table/Table.d.ts +7 -0
- package/dist/types/components/List/model/table/TableBody.d.ts +1 -0
- package/dist/types/components/List/model/table/TableColumn.d.ts +1 -0
- package/dist/types/components/List/model/table/TableHeader.d.ts +1 -0
- package/dist/types/components/List/model/table/TableRow.d.ts +14 -0
- package/dist/types/components/List/model/table/types.d.ts +17 -1
- package/dist/types/components/List/typedList.d.ts +1 -0
- package/dist/types/components/Markdown/lib/isExternalHref.d.ts +1 -0
- package/dist/types/components/ProgressBar/ProgressBar.d.ts +1 -4
- package/dist/types/components/Rating/Rating.d.ts +5 -5
- package/dist/types/components/Section/context.d.ts +28 -0
- package/dist/types/components/Table/components/TableCell/TableCell.d.ts +4 -1
- package/dist/types/components/Table/components/TableHeader/context.d.ts +6 -0
- package/dist/types/components/Wrap/Wrap.d.ts +5 -0
- package/dist/types/index/flr-universal.d.ts +1 -1
- package/dist/types/integrations/react-hook-form/components/FormSettingsProvider/FormSettingsProvider.d.ts +7 -1
- package/dist/types/lib/controller/overlay/OverlayController.d.ts +8 -74
- package/dist/types/lib/dev/hydrateServerMarkup.d.ts +2 -0
- package/dist/types/lib/hooks/dom/useVirtualKeyboardVisible.d.ts +4 -1
- package/dist/types/lib/object/isPlainObjectDeepEqual.d.ts +8 -0
- package/package.json +12 -12
- package/dist/js/node_modules/.pnpm/@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.mjs.map +0 -1
- package/dist/js/packages/components/src/lib/date/transformDateValueToFormattedDate.mjs +0 -10
- package/dist/js/packages/components/src/lib/date/transformDateValueToFormattedDate.mjs.map +0 -1
- package/dist/types/lib/date/transformDateValueToDateTime.d.ts +0 -3
- package/dist/types/lib/date/transformDateValueToFormattedDate.d.ts +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListFilter.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/filter/ListFilter.ts"],"sourcesContent":["import { toArray } from \"../../lib/array\";\nimport { getListColumn, type ListModelContext } from \"../ListModelContext\";\nimport type { ListSettingsOperationOptions } from \"../settings/types\";\nimport { customPropertyPrefix } from \"../types\";\nimport type { PropertyName, PropertyValueRenderMethod } from \"../types\";\nimport { ListFilterValue } from \"./ListFilterValue\";\nimport type {\n FilterMatcher,\n FilterMode,\n FilterUpdatedCallback,\n ListFilterShape,\n} from \"./types\";\nimport type {\n Column,\n ColumnDef,\n ColumnFilter,\n InitialTableState,\n} from \"@tanstack/table-core\";\nimport { getProperty } from \"dot-prop\";\nimport { difference, unique } from \"remeda\";\n\nconst equalsPropertyMatcher: FilterMatcher<unknown, never, never> = (\n filterValue,\n propertyValue,\n) => filterValue === propertyValue;\n\n/** From how many values on a multiple-choice filter offers \"Select all\". */\nconst selectAllMinValueCount = 6;\n\nconst stringCastRenderMethod: PropertyValueRenderMethod<unknown, never> = (\n value,\n) => String(value) as never;\n\n/** What `storeFilters` needs of a filter, and nothing more. */\ninterface StorableFilter {\n readonly storageKey: string;\n getArrayValue(): { id: string }[];\n}\n\n/**\n * One filter of a list: its values, which of them are on, and how that is\n * persisted.\n *\n * Framework-free apart from one thing, which is why `TRendered` exists: a\n * filter value has to be _shown_, and what \"shown\" is belongs to the binding.\n * React's `Filter` fills it with `ReactNode`; the default is `unknown`, so the\n * core can be read without deciding.\n *\n * The selected values live in the TanStack table's column filter, not here.\n * This translates: ids to values, values to a predicate, a toggle to a new\n * column filter.\n */\nexport class ListFilter<\n T = never,\n TProp extends PropertyName<T> = never,\n TMatchValue = never,\n TRendered = unknown,\n> {\n private _values?: ListFilterValue<TRendered>[] | undefined;\n private valuesFromTableState?: {\n facets: Map<unknown, number>;\n values: ListFilterValue<TRendered>[];\n };\n public readonly context: ListModelContext<T>;\n public readonly property: TProp;\n public readonly mode: FilterMode;\n public readonly matcher: FilterMatcher<T, never, never>;\n public readonly renderItem: PropertyValueRenderMethod<TMatchValue, TRendered>;\n public readonly name?: string;\n public readonly autosave: boolean;\n public readonly manualSave: boolean;\n private readonly onFilterChangeCallbacks = new Set<FilterUpdatedCallback>();\n private readonly defaultSelectedValues?: ListFilterValue<TRendered>[];\n public readonly priority: \"primary\" | \"secondary\";\n public readonly storageKey: string;\n\n public constructor(\n context: ListModelContext<T>,\n shape: ListFilterShape<T, TProp, TMatchValue, TRendered>,\n ) {\n const {\n autosave = context.settingsDefaults?.filters?.autosave ?? false,\n manualSave = context.settingsDefaults?.filters?.manualSave ?? true,\n property,\n mode = \"some\",\n values,\n matcher = equalsPropertyMatcher,\n renderItem = stringCastRenderMethod as PropertyValueRenderMethod<\n TMatchValue,\n TRendered\n >,\n priority = \"primary\",\n name,\n defaultSelected,\n onChange,\n } = shape;\n\n this.context = context;\n this.autosave = autosave;\n this.manualSave = manualSave;\n this.property = property;\n this.storageKey = String(property);\n this.mode = mode;\n this._values = values?.map((v) => ListFilterValue.create(this, v));\n this.matcher = matcher;\n this.renderItem = renderItem;\n this.name = name;\n this.priority = priority;\n this.defaultSelectedValues = defaultSelected?.map((v) =>\n ListFilterValue.create(this, v),\n );\n if (onChange) {\n this.onFilterChangeCallbacks.add(onChange);\n }\n }\n\n public updateInitialState(initialState: InitialTableState): void {\n const initialIds = this.getInitialSelectedIds();\n\n if (initialIds?.length) {\n initialState.columnFilters = [\n ...(initialState.columnFilters ?? []),\n {\n id: this.property as string,\n value: initialIds,\n },\n ];\n }\n }\n\n private getInitialSelectedIds(): string[] | undefined {\n return (\n this.getStoredSelectedIds({\n autosave: this.autosave,\n manualSave: this.manualSave,\n }) ?? this.defaultSelectedValues?.map((v) => v.id)\n );\n }\n\n private getStoredSelectedIds(\n options: ListSettingsOperationOptions,\n ): string[] | undefined {\n return this.context.settings?.get(\"activeFilters\", options)?.[\n this.storageKey\n ];\n }\n\n private getStoredSelectedValues(\n options: ListSettingsOperationOptions,\n ): ListFilterValue<TRendered>[] | undefined {\n return this.getStoredSelectedIds(options)\n ?.map((id) => this.values.find((v) => v.id === id))\n .filter((v): v is ListFilterValue<TRendered> => v !== undefined);\n }\n\n /**\n * Writes every filter's selection in one go — they share a settings key.\n *\n * Takes the two members it reads rather than a `ListFilter<any, …>`: a\n * `Table<never>` is not assignable to a `Table<any>` (a row model sits in a\n * contravariant position deep inside), so a list of concrete filters would\n * not go in.\n */\n public static storeFilters<T>(\n context: ListModelContext<T>,\n filters: StorableFilter[],\n options: ListSettingsOperationOptions,\n ): void {\n const data = Object.fromEntries(\n filters.map((filter) => [\n filter.storageKey,\n filter.getArrayValue().map((v) => v.id),\n ]),\n );\n\n context.settings?.store(\"activeFilters\", data, options);\n }\n\n public updateTableColumnDef(def: ColumnDef<T>): void {\n def.enableColumnFilter = true;\n def.filterFn = this.getTableFilterFn();\n }\n\n private getTableFilterFn(): ColumnDef<T>[\"filterFn\"] {\n return (row, _, filterValue) => {\n const propertyAsString = this.property as string;\n\n /*\n * A custom property is not on the item, so the matcher gets the item\n * itself and decides.\n */\n const filterBy = propertyAsString.startsWith(customPropertyPrefix)\n ? row.original\n : getProperty(row.original as object, propertyAsString);\n\n return this.checkFilterMatches(filterBy, filterValue);\n };\n }\n\n private checkFilterMatches(\n property: unknown,\n filterValueInput: unknown,\n ): boolean {\n if (filterValueInput === null) {\n return true;\n }\n\n const predicate = (filterValue: ListFilterValue<TRendered>) =>\n this.matcher(filterValue.value as never, property as never);\n\n const toFilterValue = (something: unknown) =>\n ListFilterValue.create(this, something);\n\n if (this.mode === \"all\") {\n return toArray(filterValueInput).map(toFilterValue).every(predicate);\n } else if (this.mode === \"some\") {\n const filterArr = toArray(filterValueInput);\n return (\n filterArr.length === 0 || filterArr.map(toFilterValue).some(predicate)\n );\n } else if (this.mode === \"one\") {\n const oneValue = Array.isArray(filterValueInput)\n ? filterValueInput[0]\n : filterValueInput;\n return predicate(toFilterValue(oneValue));\n }\n\n throw new Error(`Unknown filter mode '${this.mode}'`);\n }\n\n protected getTableColumnFilter(): ColumnFilter | undefined {\n return this.context.dataTable\n .getState()\n .columnFilters.find((f) => f.id === this.property);\n }\n\n protected getTableColumn(): Column<T> {\n return getListColumn(this.context.dataTable, this.property);\n }\n\n public getValue(): unknown {\n return this.getTableColumnFilter()?.value ?? null;\n }\n\n /*\n * Rebuilt only when TanStack hands out a new map: it memoizes the faceted\n * values and replaces the map when the data changes. Without this, every\n * row the filter function checks re-hashes every value — `getArrayValue()`\n * resolves each stored id through `values`.\n */\n private getValuesFromTableState(): ListFilterValue<TRendered>[] {\n const facets = this.getTableColumn().getFacetedUniqueValues();\n\n if (this.valuesFromTableState?.facets !== facets) {\n this.valuesFromTableState = {\n facets,\n values: unique(\n Array.from(facets.keys())\n .flatMap((v) => v)\n .filter((v) => v !== undefined && v !== null),\n ).map((v) => ListFilterValue.create(this, v)),\n };\n }\n\n return this.valuesFromTableState.values;\n }\n\n private checkIfValueIsUnknown(value: ListFilterValue<TRendered>): boolean {\n return !this.values.some((v) => v.id === value.id);\n }\n\n /**\n * Drops a selection the data no longer offers — a stored filter value whose\n * item is gone would otherwise filter everything away with no way to undo\n * it.\n */\n public deleteUnknownFilterValues(): void {\n /* Values the data offers are by definition known. */\n if (this._values === undefined) {\n return;\n }\n\n for (const currentValues of this.getArrayValue()) {\n if (this.checkIfValueIsUnknown(currentValues)) {\n this.deactivateValue(currentValues);\n }\n }\n }\n\n /**\n * The values the filter offers — the ones it was given, or the ones the data\n * has.\n *\n * Follows the table, not a snapshot. A binding that keeps one filter instance\n * for the list's lifetime would otherwise hold the answer from before the\n * first batch arrived: an async loader gives the header an empty menu and\n * never fills it. The values are cached per faceted-values map, which\n * TanStack replaces when the data changes.\n */\n public get values(): ListFilterValue<TRendered>[] {\n return this._values ?? this.getValuesFromTableState();\n }\n\n public getArrayValue(): ListFilterValue<TRendered>[] {\n const value = this.getValue();\n return value === null\n ? []\n : toArray(value).map((v) => ListFilterValue.create(this, v));\n }\n\n public isValueActive(value: ListFilterValue<TRendered>): boolean {\n return this.getArrayValue().some((v) => v.equals(value));\n }\n\n public isActive(): boolean {\n return this.getArrayValue().length > 0;\n }\n\n public deactivateValue(value: ListFilterValue<TRendered>): void {\n const currentValueAsArray = this.getArrayValue();\n\n const updatedValue =\n this.mode === \"all\" || this.mode === \"some\"\n ? currentValueAsArray.filter((v) => !v.equals(value))\n : null;\n\n this.getTableColumn().setFilterValue(updatedValue);\n this.callOnChangedHandlers(updatedValue);\n }\n\n private callOnChangedHandlers(\n newValue: ListFilterValue<TRendered>[] | ListFilterValue<TRendered> | null,\n ): void {\n const values = toArray(newValue).map((v) => v?.value);\n this.onFilterChangeCallbacks.forEach((cb) => cb(values));\n }\n\n public hasChanges(): boolean {\n const currentIds = this.getArrayValue().map((v) => v.id);\n\n const defaultIds =\n this.getStoredSelectedIds({ autosave: false }) ??\n this.defaultSelectedValues?.map((v) => v.id) ??\n [];\n\n return (\n currentIds.length !== defaultIds.length ||\n difference(currentIds, defaultIds).length > 0\n );\n }\n\n public isStoringAvailable(): boolean {\n return !!this.context.settings && this.manualSave;\n }\n\n public resetValues(): void {\n const storedValues =\n this.getStoredSelectedValues({ autosave: false }) ??\n this.defaultSelectedValues;\n\n const resetTo =\n storedValues ?? (this.mode === \"all\" || this.mode === \"some\" ? [] : null);\n\n this.getTableColumn().setFilterValue(resetTo);\n this.callOnChangedHandlers(resetTo);\n }\n\n public clear(): void {\n this.getTableColumn().setFilterValue(null);\n this.callOnChangedHandlers(null);\n }\n\n public toggleValue(newValue: ListFilterValue<TRendered>): void {\n const currentValueAsArray = this.getArrayValue();\n\n let updatedValue:\n ListFilterValue<TRendered>[] | ListFilterValue<TRendered> | null;\n\n if (this.mode === \"all\" || this.mode === \"some\") {\n updatedValue = newValue.isActive\n ? currentValueAsArray.filter((v) => !v.equals(newValue))\n : [...currentValueAsArray, newValue];\n } else {\n updatedValue = newValue.isActive ? null : newValue;\n }\n\n this.getTableColumn().setFilterValue(updatedValue);\n this.callOnChangedHandlers(updatedValue);\n }\n\n /**\n * Whether the filter offers \"Select all\" — a `some` filter with enough\n * values.\n */\n public get isSelectAllAvailable(): boolean {\n return this.mode === \"some\" && this.values.length >= selectAllMinValueCount;\n }\n\n public isEveryValueActive(): boolean {\n return this.values.every((v) => v.isActive);\n }\n\n public selectAll(): void {\n this.setArrayValue(this.values);\n }\n\n /** Makes exactly these values active — what a multiple-selection menu reports. */\n public setActiveValueIds(ids: Iterable<unknown>): void {\n const idSet = new Set(ids);\n this.setArrayValue(this.values.filter((v) => idSet.has(v.id)));\n }\n\n public deselectAll(): void {\n this.setArrayValue([]);\n }\n\n private setArrayValue(value: ListFilterValue<TRendered>[]): void {\n this.getTableColumn().setFilterValue(value);\n this.callOnChangedHandlers(value);\n }\n\n public onFilterUpdated(cb: () => unknown): void {\n this.onFilterChangeCallbacks.add(cb);\n }\n}\n\nexport default ListFilter;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ListFilter.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/filter/ListFilter.ts"],"sourcesContent":["import { toArray } from \"../../lib/array\";\nimport { getListColumn, type ListModelContext } from \"../ListModelContext\";\nimport type { ListSettingsOperationOptions } from \"../settings/types\";\nimport { customPropertyPrefix } from \"../types\";\nimport type { PropertyName, PropertyValueRenderMethod } from \"../types\";\nimport { ListFilterValue } from \"./ListFilterValue\";\nimport type {\n FilterMatcher,\n FilterMode,\n FilterUpdatedCallback,\n ListFilterShape,\n} from \"./types\";\nimport type {\n Column,\n ColumnDef,\n ColumnFilter,\n InitialTableState,\n} from \"@tanstack/table-core\";\nimport { getProperty } from \"dot-prop\";\nimport { difference, unique } from \"remeda\";\n\nconst equalsPropertyMatcher: FilterMatcher<unknown, never, never> = (\n filterValue,\n propertyValue,\n) => filterValue === propertyValue;\n\n/** From how many values on a multiple-choice filter offers \"Select all\". */\nconst selectAllMinValueCount = 6;\n\nconst stringCastRenderMethod: PropertyValueRenderMethod<unknown, never> = (\n value,\n) => String(value) as never;\n\n/** What `storeFilters` needs of a filter, and nothing more. */\ninterface StorableFilter {\n readonly storageKey: string;\n getArrayValue(): { id: string }[];\n}\n\n/**\n * One filter of a list: its values, which of them are on, and how that is\n * persisted.\n *\n * Framework-free apart from one thing, which is why `TRendered` exists: a\n * filter value has to be _shown_, and what \"shown\" is belongs to the binding.\n * React's `Filter` fills it with `ReactNode`; the default is `unknown`, so the\n * core can be read without deciding.\n *\n * The selected values live in the TanStack table's column filter, not here.\n * This translates: ids to values, values to a predicate, a toggle to a new\n * column filter.\n */\nexport class ListFilter<\n T = never,\n TProp extends PropertyName<T> = never,\n TMatchValue = never,\n TRendered = unknown,\n> {\n private _values?: ListFilterValue<TRendered>[] | undefined;\n private valuesFromTableState?: {\n facets: Map<unknown, number>;\n values: ListFilterValue<TRendered>[];\n };\n public readonly context: ListModelContext<T>;\n public readonly property: TProp;\n public readonly mode: FilterMode;\n public readonly matcher: FilterMatcher<T, never, never>;\n public readonly renderItem: PropertyValueRenderMethod<TMatchValue, TRendered>;\n public readonly name?: string;\n public readonly autosave: boolean;\n public readonly manualSave: boolean;\n private readonly onFilterChangeCallbacks = new Set<FilterUpdatedCallback>();\n private readonly defaultSelectedValues?: ListFilterValue<TRendered>[];\n public readonly priority: \"primary\" | \"secondary\";\n public readonly storageKey: string;\n\n public constructor(\n context: ListModelContext<T>,\n shape: ListFilterShape<T, TProp, TMatchValue, TRendered>,\n ) {\n const {\n autosave = context.settingsDefaults?.filters?.autosave ?? false,\n manualSave = context.settingsDefaults?.filters?.manualSave ?? true,\n property,\n mode = \"some\",\n values,\n matcher = equalsPropertyMatcher,\n renderItem = stringCastRenderMethod as PropertyValueRenderMethod<\n TMatchValue,\n TRendered\n >,\n priority = \"primary\",\n name,\n defaultSelected,\n onChange,\n } = shape;\n\n this.context = context;\n this.autosave = autosave;\n this.manualSave = manualSave;\n this.property = property;\n this.storageKey = String(property);\n this.mode = mode;\n this._values = values?.map((v) => ListFilterValue.create(this, v));\n this.matcher = matcher;\n this.renderItem = renderItem;\n this.name = name;\n this.priority = priority;\n this.defaultSelectedValues = defaultSelected?.map((v) =>\n ListFilterValue.create(this, v),\n );\n if (onChange) {\n this.onFilterChangeCallbacks.add(onChange);\n }\n }\n\n public updateInitialState(initialState: InitialTableState): void {\n const initialIds = this.getInitialSelectedIds();\n\n if (initialIds?.length) {\n initialState.columnFilters = [\n ...(initialState.columnFilters ?? []),\n {\n id: this.property as string,\n value: initialIds,\n },\n ];\n }\n }\n\n private getInitialSelectedIds(): string[] | undefined {\n return (\n this.getStoredSelectedIds({\n autosave: this.autosave,\n manualSave: this.manualSave,\n }) ?? this.defaultSelectedValues?.map((v) => v.id)\n );\n }\n\n private getStoredSelectedIds(\n options: ListSettingsOperationOptions,\n ): string[] | undefined {\n return this.context.settings?.get(\"activeFilters\", options)?.[\n this.storageKey\n ];\n }\n\n private getStoredSelectedValues(\n options: ListSettingsOperationOptions,\n ): ListFilterValue<TRendered>[] | undefined {\n return this.getStoredSelectedIds(options)\n ?.map((id) => this.values.find((v) => v.id === id))\n .filter((v): v is ListFilterValue<TRendered> => v !== undefined);\n }\n\n /**\n * Writes every filter's selection in one go — they share a settings key.\n *\n * Takes the two members it reads rather than a `ListFilter<any, …>`: a\n * `Table<never>` is not assignable to a `Table<any>` (a row model sits in a\n * contravariant position deep inside), so a list of concrete filters would\n * not go in.\n */\n public static storeFilters<T>(\n context: ListModelContext<T>,\n filters: StorableFilter[],\n options: ListSettingsOperationOptions,\n ): void {\n const data = Object.fromEntries(\n filters.map((filter) => [\n filter.storageKey,\n filter.getArrayValue().map((v) => v.id),\n ]),\n );\n\n context.settings?.store(\"activeFilters\", data, options);\n }\n\n public updateTableColumnDef(def: ColumnDef<T>): void {\n def.enableColumnFilter = true;\n def.filterFn = this.getTableFilterFn();\n }\n\n private getTableFilterFn(): ColumnDef<T>[\"filterFn\"] {\n return (row, _, filterValue) => {\n const propertyAsString = this.property as string;\n\n /*\n * A custom property is not on the item, so the matcher gets the item\n * itself and decides.\n */\n const filterBy = propertyAsString.startsWith(customPropertyPrefix)\n ? row.original\n : getProperty(row.original as object, propertyAsString);\n\n return this.checkFilterMatches(filterBy, filterValue);\n };\n }\n\n private checkFilterMatches(\n property: unknown,\n filterValueInput: unknown,\n ): boolean {\n if (filterValueInput === null) {\n return true;\n }\n\n const predicate = (filterValue: ListFilterValue<TRendered>) =>\n this.matcher(filterValue.value as never, property as never);\n\n const toFilterValue = (something: unknown) =>\n ListFilterValue.create(this, something);\n\n if (this.mode === \"all\") {\n return toArray(filterValueInput).map(toFilterValue).every(predicate);\n } else if (this.mode === \"some\") {\n const filterArr = toArray(filterValueInput);\n return (\n filterArr.length === 0 || filterArr.map(toFilterValue).some(predicate)\n );\n } else if (this.mode === \"one\") {\n const oneValue = Array.isArray(filterValueInput)\n ? filterValueInput[0]\n : filterValueInput;\n return predicate(toFilterValue(oneValue));\n }\n\n throw new Error(`Unknown filter mode '${this.mode}'`);\n }\n\n protected getTableColumnFilter(): ColumnFilter | undefined {\n return this.context.dataTable\n .getState()\n .columnFilters.find((f) => f.id === this.property);\n }\n\n protected getTableColumn(): Column<T> {\n return getListColumn(this.context.dataTable, this.property);\n }\n\n public getValue(): unknown {\n return this.getTableColumnFilter()?.value ?? null;\n }\n\n /*\n * Rebuilt only when TanStack hands out a new map: it memoizes the faceted\n * values and replaces the map when the data changes. Without this, every\n * row the filter function checks re-hashes every value — `getArrayValue()`\n * resolves each stored id through `values`.\n */\n private getValuesFromTableState(): ListFilterValue<TRendered>[] {\n const facets = this.getTableColumn().getFacetedUniqueValues();\n\n if (this.valuesFromTableState?.facets !== facets) {\n this.valuesFromTableState = {\n facets,\n values: unique(\n Array.from(facets.keys())\n .flatMap((v) => v)\n .filter((v) => v !== undefined && v !== null),\n ).map((v) => ListFilterValue.create(this, v)),\n };\n }\n\n return this.valuesFromTableState.values;\n }\n\n private checkIfValueIsUnknown(value: ListFilterValue<TRendered>): boolean {\n return !this.values.some((v) => v.id === value.id);\n }\n\n /**\n * Drops a selection the data no longer offers — a stored filter value whose\n * item is gone would otherwise filter everything away with no way to undo\n * it.\n */\n public deleteUnknownFilterValues(): void {\n /* Values the data offers are by definition known. */\n if (this._values === undefined) {\n return;\n }\n\n for (const currentValues of this.getArrayValue()) {\n if (this.checkIfValueIsUnknown(currentValues)) {\n this.deactivateValue(currentValues);\n }\n }\n }\n\n /**\n * The values the filter offers — the ones it was given, or the ones the data\n * has.\n *\n * Follows the table, not a snapshot. A binding that keeps one filter instance\n * for the list's lifetime would otherwise hold the answer from before the\n * first batch arrived: an async loader gives the header an empty menu and\n * never fills it. The values are cached per faceted-values map, which\n * TanStack replaces when the data changes.\n */\n public get values(): ListFilterValue<TRendered>[] {\n return this._values ?? this.getValuesFromTableState();\n }\n\n public getArrayValue(): ListFilterValue<TRendered>[] {\n const value = this.getValue();\n return value === null\n ? []\n : toArray(value).map((v) => ListFilterValue.create(this, v));\n }\n\n public isValueActive(value: ListFilterValue<TRendered>): boolean {\n return this.getArrayValue().some((v) => v.equals(value));\n }\n\n public isActive(): boolean {\n return this.getArrayValue().length > 0;\n }\n\n public deactivateValue(value: ListFilterValue<TRendered>): void {\n const currentValueAsArray = this.getArrayValue();\n\n const updatedValue =\n this.mode === \"all\" || this.mode === \"some\"\n ? currentValueAsArray.filter((v) => !v.equals(value))\n : null;\n\n this.getTableColumn().setFilterValue(updatedValue);\n this.callOnChangedHandlers(updatedValue);\n }\n\n private callOnChangedHandlers(\n newValue: ListFilterValue<TRendered>[] | ListFilterValue<TRendered> | null,\n ): void {\n this.notifyFilterUpdated(toArray(newValue).map((v) => v?.value));\n }\n\n /** Tells the listeners — the list resetting its batches among them. */\n protected notifyFilterUpdated(values: unknown[]): void {\n this.onFilterChangeCallbacks.forEach((cb) => cb(values));\n }\n\n public hasChanges(): boolean {\n const currentIds = this.getArrayValue().map((v) => v.id);\n\n const defaultIds =\n this.getStoredSelectedIds({ autosave: false }) ??\n this.defaultSelectedValues?.map((v) => v.id) ??\n [];\n\n return (\n currentIds.length !== defaultIds.length ||\n difference(currentIds, defaultIds).length > 0\n );\n }\n\n public isStoringAvailable(): boolean {\n return !!this.context.settings && this.manualSave;\n }\n\n public resetValues(): void {\n const storedValues =\n this.getStoredSelectedValues({ autosave: false }) ??\n this.defaultSelectedValues;\n\n const resetTo =\n storedValues ?? (this.mode === \"all\" || this.mode === \"some\" ? [] : null);\n\n this.getTableColumn().setFilterValue(resetTo);\n this.callOnChangedHandlers(resetTo);\n }\n\n public clear(): void {\n this.getTableColumn().setFilterValue(null);\n this.callOnChangedHandlers(null);\n }\n\n public toggleValue(newValue: ListFilterValue<TRendered>): void {\n const currentValueAsArray = this.getArrayValue();\n\n let updatedValue:\n ListFilterValue<TRendered>[] | ListFilterValue<TRendered> | null;\n\n if (this.mode === \"all\" || this.mode === \"some\") {\n updatedValue = newValue.isActive\n ? currentValueAsArray.filter((v) => !v.equals(newValue))\n : [...currentValueAsArray, newValue];\n } else {\n updatedValue = newValue.isActive ? null : newValue;\n }\n\n this.getTableColumn().setFilterValue(updatedValue);\n this.callOnChangedHandlers(updatedValue);\n }\n\n /**\n * Whether the filter offers \"Select all\" — a `some` filter with enough\n * values.\n */\n public get isSelectAllAvailable(): boolean {\n return this.mode === \"some\" && this.values.length >= selectAllMinValueCount;\n }\n\n public isEveryValueActive(): boolean {\n return this.values.every((v) => v.isActive);\n }\n\n public selectAll(): void {\n this.setArrayValue(this.values);\n }\n\n /** Makes exactly these values active — what a multiple-selection menu reports. */\n public setActiveValueIds(ids: Iterable<unknown>): void {\n const idSet = new Set(ids);\n this.setArrayValue(this.values.filter((v) => idSet.has(v.id)));\n }\n\n public deselectAll(): void {\n this.setArrayValue([]);\n }\n\n private setArrayValue(value: ListFilterValue<TRendered>[]): void {\n this.getTableColumn().setFilterValue(value);\n this.callOnChangedHandlers(value);\n }\n\n public onFilterUpdated(cb: () => unknown): void {\n this.onFilterChangeCallbacks.add(cb);\n }\n}\n\nexport default ListFilter;\n"],"mappings":"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"}
|
|
@@ -1,27 +1,52 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
|
-
import { CalendarDate } from "@internationalized/date";
|
|
3
|
+
import { CalendarDate, CalendarDateTime, ZonedDateTime } from "@internationalized/date";
|
|
4
4
|
import { DateTime } from "luxon";
|
|
5
5
|
//#region ../components-base/src/list/filter/dateRange.ts
|
|
6
6
|
/** A range needs both ends present to be one, even if either may be unset. */
|
|
7
7
|
var isListDateRange = (value) => !!value && typeof value === "object" && "start" in value && "end" in value;
|
|
8
|
-
var
|
|
8
|
+
var hasTime = (date) => "hour" in date;
|
|
9
|
+
/**
|
|
10
|
+
* The date as a local point in time. A `ZonedDateTime` is the instant it names;
|
|
11
|
+
* anything else is read field by field, since after crossing the remote
|
|
12
|
+
* boundary a `CalendarDate` is a plain object.
|
|
13
|
+
*/
|
|
14
|
+
var listDateToDateTime = (date) => date instanceof ZonedDateTime ? DateTime.fromJSDate(date.toDate()) : DateTime.fromObject({
|
|
9
15
|
year: date.year,
|
|
10
16
|
month: date.month,
|
|
11
|
-
day: date.day
|
|
17
|
+
day: date.day,
|
|
18
|
+
...hasTime(date) ? {
|
|
19
|
+
hour: date.hour,
|
|
20
|
+
minute: date.minute,
|
|
21
|
+
second: date.second
|
|
22
|
+
} : {}
|
|
12
23
|
});
|
|
13
24
|
/**
|
|
25
|
+
* Resolves a range to the instants it spans, for filtering on the server side.
|
|
26
|
+
* Both bounds are inclusive: a date covers its whole day and a date with time
|
|
27
|
+
* its whole minute, in the user's local time zone. A missing side has no
|
|
28
|
+
* bound.
|
|
29
|
+
*/
|
|
30
|
+
var resolveListDateRange = (range) => {
|
|
31
|
+
const unit = (date) => hasTime(date) ? "minute" : "day";
|
|
32
|
+
return {
|
|
33
|
+
start: range.start ? listDateToDateTime(range.start).startOf(unit(range.start)).toJSDate() : void 0,
|
|
34
|
+
end: range.end ? listDateToDateTime(range.end).endOf(unit(range.end)).toJSDate() : void 0
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
14
38
|
* The cell's value as a point in time, or `undefined` when the filter does not
|
|
15
39
|
* treat it as a date.
|
|
16
40
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* start of its day
|
|
20
|
-
*
|
|
41
|
+
* A luxon `DateTime` and an ISO 8601 string are compared as the instant they
|
|
42
|
+
* name — a date-only string as the start of its day. A `CalendarDate` counts as
|
|
43
|
+
* the start of its day, a `CalendarDateTime` as its local time and a
|
|
44
|
+
* `ZonedDateTime` as its instant. Anything else, a plain `{ year, month, day }`
|
|
45
|
+
* object included, is not a date here.
|
|
21
46
|
*/
|
|
22
47
|
var toDateTime = (value) => {
|
|
23
48
|
if (value instanceof DateTime) return value;
|
|
24
|
-
if (value instanceof CalendarDate) return
|
|
49
|
+
if (value instanceof CalendarDate || value instanceof CalendarDateTime || value instanceof ZonedDateTime) return listDateToDateTime(value);
|
|
25
50
|
if (typeof value === "string") return DateTime.fromISO(value);
|
|
26
51
|
};
|
|
27
52
|
/**
|
|
@@ -35,10 +60,9 @@ var dateRangeFilterFn = (row, columnId, range) => {
|
|
|
35
60
|
if (!range) return true;
|
|
36
61
|
const dateValue = toDateTime(row.getValue(columnId));
|
|
37
62
|
if (!dateValue) return true;
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return !(endDate && dateValue > endDate);
|
|
63
|
+
const { start, end } = resolveListDateRange(range);
|
|
64
|
+
if (start && dateValue.toMillis() < start.getTime()) return false;
|
|
65
|
+
return !(end && dateValue.toMillis() > end.getTime());
|
|
42
66
|
};
|
|
43
67
|
/** Turns the column into one a date range filters. */
|
|
44
68
|
var applyDateRangeColumnDef = (def) => {
|
|
@@ -46,6 +70,6 @@ var applyDateRangeColumnDef = (def) => {
|
|
|
46
70
|
def.filterFn = dateRangeFilterFn;
|
|
47
71
|
};
|
|
48
72
|
//#endregion
|
|
49
|
-
export { applyDateRangeColumnDef, dateRangeFilterFn, isListDateRange };
|
|
73
|
+
export { applyDateRangeColumnDef, dateRangeFilterFn, isListDateRange, listDateToDateTime, resolveListDateRange };
|
|
50
74
|
|
|
51
75
|
//# sourceMappingURL=dateRange.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dateRange.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/filter/dateRange.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"dateRange.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/filter/dateRange.ts"],"sourcesContent":["import {\n CalendarDate,\n CalendarDateTime,\n ZonedDateTime,\n} from \"@internationalized/date\";\nimport type { ColumnDef, Row } from \"@tanstack/table-core\";\nimport { DateTime } from \"luxon\";\n\n/**\n * A calendar date, in whichever shape it reached the filter — with a time of\n * day when the filter narrows down by minute.\n */\nexport interface ListDateParts {\n readonly year: number;\n readonly month: number;\n readonly day: number;\n readonly hour?: number;\n readonly minute?: number;\n readonly second?: number;\n}\n\nexport interface ListDateRange {\n readonly start?: ListDateParts;\n readonly end?: ListDateParts;\n}\n\n/** A range needs both ends present to be one, even if either may be unset. */\nexport const isListDateRange = (value: unknown): value is ListDateRange =>\n !!value && typeof value === \"object\" && \"start\" in value && \"end\" in value;\n\nconst hasTime = (date: ListDateParts) => \"hour\" in date;\n\n/**\n * The date as a local point in time. A `ZonedDateTime` is the instant it names;\n * anything else is read field by field, since after crossing the remote\n * boundary a `CalendarDate` is a plain object.\n */\nexport const listDateToDateTime = (date: ListDateParts): DateTime =>\n date instanceof ZonedDateTime\n ? DateTime.fromJSDate(date.toDate())\n : DateTime.fromObject({\n year: date.year,\n month: date.month,\n day: date.day,\n ...(hasTime(date)\n ? { hour: date.hour, minute: date.minute, second: date.second }\n : {}),\n });\n\n/**\n * Resolves a range to the instants it spans, for filtering on the server side.\n * Both bounds are inclusive: a date covers its whole day and a date with time\n * its whole minute, in the user's local time zone. A missing side has no\n * bound.\n */\nexport const resolveListDateRange = (\n range: ListDateRange,\n): { start?: Date; end?: Date } => {\n const unit = (date: ListDateParts) => (hasTime(date) ? \"minute\" : \"day\");\n\n return {\n start: range.start\n ? listDateToDateTime(range.start).startOf(unit(range.start)).toJSDate()\n : undefined,\n end: range.end\n ? listDateToDateTime(range.end).endOf(unit(range.end)).toJSDate()\n : undefined,\n };\n};\n\n/**\n * The cell's value as a point in time, or `undefined` when the filter does not\n * treat it as a date.\n *\n * A luxon `DateTime` and an ISO 8601 string are compared as the instant they\n * name — a date-only string as the start of its day. A `CalendarDate` counts as\n * the start of its day, a `CalendarDateTime` as its local time and a\n * `ZonedDateTime` as its instant. Anything else, a plain `{ year, month, day }`\n * object included, is not a date here.\n */\nconst toDateTime = (value: unknown): DateTime | undefined => {\n if (value instanceof DateTime) {\n return value;\n }\n if (\n value instanceof CalendarDate ||\n value instanceof CalendarDateTime ||\n value instanceof ZonedDateTime\n ) {\n return listDateToDateTime(value);\n }\n if (typeof value === \"string\") {\n return DateTime.fromISO(value);\n }\n return undefined;\n};\n\n/**\n * Whether a row's date falls inside the selected range.\n *\n * A value that is not a date keeps its row: a filter the data cannot answer\n * should not empty the list. That includes a string luxon cannot parse — the\n * invalid `DateTime` compares as `NaN`, and neither end excludes it.\n */\nexport const dateRangeFilterFn = <T>(\n row: Row<T>,\n columnId: string,\n range?: ListDateRange,\n): boolean => {\n if (!range) {\n return true;\n }\n\n const dateValue = toDateTime(row.getValue(columnId));\n\n if (!dateValue) {\n return true;\n }\n\n const { start, end } = resolveListDateRange(range);\n\n if (start && dateValue.toMillis() < start.getTime()) {\n return false;\n }\n\n return !(end && dateValue.toMillis() > end.getTime());\n};\n\n/** Turns the column into one a date range filters. */\nexport const applyDateRangeColumnDef = <T>(def: ColumnDef<T>): void => {\n def.enableColumnFilter = true;\n def.filterFn = dateRangeFilterFn;\n};\n"],"mappings":";;;;;;AA2BA,IAAa,mBAAmB,UAC9B,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,WAAW,SAAS,SAAS;AAEvE,IAAM,WAAW,SAAwB,UAAU;;;;;;AAOnD,IAAa,sBAAsB,SACjC,gBAAgB,gBACZ,SAAS,WAAW,KAAK,OAAO,CAAC,IACjC,SAAS,WAAW;CAClB,MAAM,KAAK;CACX,OAAO,KAAK;CACZ,KAAK,KAAK;CACV,GAAI,QAAQ,IAAI,IACZ;EAAE,MAAM,KAAK;EAAM,QAAQ,KAAK;EAAQ,QAAQ,KAAK;CAAO,IAC5D,CAAC;AACP,CAAC;;;;;;;AAQP,IAAa,wBACX,UACiC;CACjC,MAAM,QAAQ,SAAyB,QAAQ,IAAI,IAAI,WAAW;CAElE,OAAO;EACL,OAAO,MAAM,QACT,mBAAmB,MAAM,KAAK,CAAC,CAAC,QAAQ,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,SAAS,IACpE,KAAA;EACJ,KAAK,MAAM,MACP,mBAAmB,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,IAC9D,KAAA;CACN;AACF;;;;;;;;;;;AAYA,IAAM,cAAc,UAAyC;CAC3D,IAAI,iBAAiB,UACnB,OAAO;CAET,IACE,iBAAiB,gBACjB,iBAAiB,oBACjB,iBAAiB,eAEjB,OAAO,mBAAmB,KAAK;CAEjC,IAAI,OAAO,UAAU,UACnB,OAAO,SAAS,QAAQ,KAAK;AAGjC;;;;;;;;AASA,IAAa,qBACX,KACA,UACA,UACY;CACZ,IAAI,CAAC,OACH,OAAO;CAGT,MAAM,YAAY,WAAW,IAAI,SAAS,QAAQ,CAAC;CAEnD,IAAI,CAAC,WACH,OAAO;CAGT,MAAM,EAAE,OAAO,QAAQ,qBAAqB,KAAK;CAEjD,IAAI,SAAS,UAAU,SAAS,IAAI,MAAM,QAAQ,GAChD,OAAO;CAGT,OAAO,EAAE,OAAO,UAAU,SAAS,IAAI,IAAI,QAAQ;AACrD;;AAGA,IAAa,2BAA8B,QAA4B;CACrE,IAAI,qBAAqB;CACzB,IAAI,WAAW;AACjB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
/* */
|
|
3
|
+
import { resolveListDateRange } from "./dateRange.mjs";
|
|
4
|
+
import { CalendarDate, Time, toCalendarDateTime } from "@internationalized/date";
|
|
5
|
+
//#region ../components-base/src/list/filter/dateTimeRangeFields.ts
|
|
6
|
+
var toListCalendarDate = (value) => value ? new CalendarDate(value.year, value.month, value.day) : null;
|
|
7
|
+
var toListTime = (value) => value && "hour" in value ? new Time(value.hour, value.minute) : null;
|
|
8
|
+
var listDateTimeRangeFieldsFromValue = (value) => ({
|
|
9
|
+
startDate: toListCalendarDate(value?.start),
|
|
10
|
+
startTime: toListTime(value?.start),
|
|
11
|
+
endDate: toListCalendarDate(value?.end),
|
|
12
|
+
endTime: toListTime(value?.end)
|
|
13
|
+
});
|
|
14
|
+
var toBound = (date, time) => date ? time ? toCalendarDateTime(date, time) : date : void 0;
|
|
15
|
+
var boundKey = (bound) => bound && [
|
|
16
|
+
bound.year,
|
|
17
|
+
bound.month,
|
|
18
|
+
bound.day,
|
|
19
|
+
bound.hour,
|
|
20
|
+
bound.minute
|
|
21
|
+
].join("-");
|
|
22
|
+
var isYearComplete = (date) => !!date && date.year >= 1e3;
|
|
23
|
+
/** Not while a year is still being typed: "2" would read as an early end. */
|
|
24
|
+
var isListDateTimeRangeEndBeforeStart = (fields) => {
|
|
25
|
+
if (!isYearComplete(fields.startDate) || !isYearComplete(fields.endDate)) return false;
|
|
26
|
+
const { start, end } = resolveListDateRange({
|
|
27
|
+
start: toBound(fields.startDate, fields.startTime),
|
|
28
|
+
end: toBound(fields.endDate, fields.endTime)
|
|
29
|
+
});
|
|
30
|
+
return !!start && !!end && end < start;
|
|
31
|
+
};
|
|
32
|
+
var isListDateValid = (date, limits = {}) => {
|
|
33
|
+
const minValue = toListCalendarDate(limits.minValue);
|
|
34
|
+
const maxValue = toListCalendarDate(limits.maxValue);
|
|
35
|
+
return !date || !(!isYearComplete(date) || minValue && date.compare(minValue) < 0 || maxValue && date.compare(maxValue) > 0 || limits.isDateUnavailable?.(date));
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The range the fields stand for, or `undefined` while it must not be applied:
|
|
39
|
+
* an invalid input keeps the last valid range, and an unchanged one needs no
|
|
40
|
+
* update. `null` clears the filter.
|
|
41
|
+
*/
|
|
42
|
+
var getListDateTimeRangeUpdate = (fields, applied, limits) => {
|
|
43
|
+
if (!isListDateValid(fields.startDate, limits) || !isListDateValid(fields.endDate, limits) || isListDateTimeRangeEndBeforeStart(fields)) return;
|
|
44
|
+
const start = toBound(fields.startDate, fields.startTime);
|
|
45
|
+
const end = toBound(fields.endDate, fields.endTime);
|
|
46
|
+
if (boundKey(start) === boundKey(applied?.start) && boundKey(end) === boundKey(applied?.end)) return;
|
|
47
|
+
return start || end ? {
|
|
48
|
+
start,
|
|
49
|
+
end
|
|
50
|
+
} : null;
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
export { getListDateTimeRangeUpdate, isListDateTimeRangeEndBeforeStart, isListDateValid, listDateTimeRangeFieldsFromValue, toListCalendarDate, toListTime };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=dateTimeRangeFields.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateTimeRangeFields.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/filter/dateTimeRangeFields.ts"],"sourcesContent":["import {\n CalendarDate,\n type CalendarDateTime,\n Time,\n toCalendarDateTime,\n} from \"@internationalized/date\";\nimport {\n resolveListDateRange,\n type ListDateParts,\n type ListDateRange,\n} from \"./dateRange\";\n\n/*\n * The rules of the date and time fields a range filter shows with\n * `granularity: \"minute\"`. Which input is valid and when it applies is the same\n * in every binding; the fields and the state holding their input are not.\n */\n\nexport interface ListDateTimeRangeFields {\n readonly startDate: CalendarDate | null;\n readonly startTime: Time | null;\n readonly endDate: CalendarDate | null;\n readonly endTime: Time | null;\n}\n\nexport interface ListDateTimeRangeLimits {\n readonly minValue?: ListDateParts | null;\n readonly maxValue?: ListDateParts | null;\n readonly isDateUnavailable?: (date: CalendarDate) => boolean;\n}\n\ntype Bound = CalendarDate | CalendarDateTime;\n\nexport interface ListDateTimeRange {\n readonly start?: Bound;\n readonly end?: Bound;\n}\n\n/* Field by field: a value from the host of a remote connection is a plain object. */\nexport const toListCalendarDate = (\n value?: ListDateParts | null,\n): CalendarDate | null =>\n value ? new CalendarDate(value.year, value.month, value.day) : null;\n\nexport const toListTime = (\n value?: { readonly hour?: number; readonly minute?: number } | null,\n): Time | null =>\n value && \"hour\" in value ? new Time(value.hour, value.minute) : null;\n\nexport const listDateTimeRangeFieldsFromValue = (\n value: ListDateRange | null,\n): ListDateTimeRangeFields => ({\n startDate: toListCalendarDate(value?.start),\n startTime: toListTime(value?.start),\n endDate: toListCalendarDate(value?.end),\n endTime: toListTime(value?.end),\n});\n\nconst toBound = (date: CalendarDate | null, time: Time | null) =>\n date ? (time ? toCalendarDateTime(date, time) : date) : undefined;\n\nconst boundKey = (bound?: ListDateParts) =>\n bound &&\n [bound.year, bound.month, bound.day, bound.hour, bound.minute].join(\"-\");\n\n// react-aria reports a typed year digit by digit (2, 20, 202, 2026)\nconst isYearComplete = (date: CalendarDate | null) =>\n !!date && date.year >= 1000;\n\n/** Not while a year is still being typed: \"2\" would read as an early end. */\nexport const isListDateTimeRangeEndBeforeStart = (\n fields: ListDateTimeRangeFields,\n): boolean => {\n if (!isYearComplete(fields.startDate) || !isYearComplete(fields.endDate)) {\n return false;\n }\n const { start, end } = resolveListDateRange({\n start: toBound(fields.startDate, fields.startTime),\n end: toBound(fields.endDate, fields.endTime),\n });\n return !!start && !!end && end < start;\n};\n\nexport const isListDateValid = (\n date: CalendarDate | null,\n limits: ListDateTimeRangeLimits = {},\n): boolean => {\n const minValue = toListCalendarDate(limits.minValue);\n const maxValue = toListCalendarDate(limits.maxValue);\n\n return (\n !date ||\n !(\n !isYearComplete(date) ||\n (minValue && date.compare(minValue) < 0) ||\n (maxValue && date.compare(maxValue) > 0) ||\n limits.isDateUnavailable?.(date)\n )\n );\n};\n\n/**\n * The range the fields stand for, or `undefined` while it must not be applied:\n * an invalid input keeps the last valid range, and an unchanged one needs no\n * update. `null` clears the filter.\n */\nexport const getListDateTimeRangeUpdate = (\n fields: ListDateTimeRangeFields,\n applied: ListDateRange | null,\n limits?: ListDateTimeRangeLimits,\n): ListDateTimeRange | null | undefined => {\n if (\n !isListDateValid(fields.startDate, limits) ||\n !isListDateValid(fields.endDate, limits) ||\n isListDateTimeRangeEndBeforeStart(fields)\n ) {\n return undefined;\n }\n\n const start = toBound(fields.startDate, fields.startTime);\n const end = toBound(fields.endDate, fields.endTime);\n\n if (\n boundKey(start) === boundKey(applied?.start) &&\n boundKey(end) === boundKey(applied?.end)\n ) {\n return undefined;\n }\n\n return start || end ? { start, end } : null;\n};\n"],"mappings":";;;;;AAuCA,IAAa,sBACX,UAEA,QAAQ,IAAI,aAAa,MAAM,MAAM,MAAM,OAAO,MAAM,GAAG,IAAI;AAEjE,IAAa,cACX,UAEA,SAAS,UAAU,QAAQ,IAAI,KAAK,MAAM,MAAM,MAAM,MAAM,IAAI;AAElE,IAAa,oCACX,WAC6B;CAC7B,WAAW,mBAAmB,OAAO,KAAK;CAC1C,WAAW,WAAW,OAAO,KAAK;CAClC,SAAS,mBAAmB,OAAO,GAAG;CACtC,SAAS,WAAW,OAAO,GAAG;AAChC;AAEA,IAAM,WAAW,MAA2B,SAC1C,OAAQ,OAAO,mBAAmB,MAAM,IAAI,IAAI,OAAQ,KAAA;AAE1D,IAAM,YAAY,UAChB,SACA;CAAC,MAAM;CAAM,MAAM;CAAO,MAAM;CAAK,MAAM;CAAM,MAAM;AAAM,CAAC,CAAC,KAAK,GAAG;AAGzE,IAAM,kBAAkB,SACtB,CAAC,CAAC,QAAQ,KAAK,QAAQ;;AAGzB,IAAa,qCACX,WACY;CACZ,IAAI,CAAC,eAAe,OAAO,SAAS,KAAK,CAAC,eAAe,OAAO,OAAO,GACrE,OAAO;CAET,MAAM,EAAE,OAAO,QAAQ,qBAAqB;EAC1C,OAAO,QAAQ,OAAO,WAAW,OAAO,SAAS;EACjD,KAAK,QAAQ,OAAO,SAAS,OAAO,OAAO;CAC7C,CAAC;CACD,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,MAAM;AACnC;AAEA,IAAa,mBACX,MACA,SAAkC,CAAC,MACvB;CACZ,MAAM,WAAW,mBAAmB,OAAO,QAAQ;CACnD,MAAM,WAAW,mBAAmB,OAAO,QAAQ;CAEnD,OACE,CAAC,QACD,EACE,CAAC,eAAe,IAAI,KACnB,YAAY,KAAK,QAAQ,QAAQ,IAAI,KACrC,YAAY,KAAK,QAAQ,QAAQ,IAAI,KACtC,OAAO,oBAAoB,IAAI;AAGrC;;;;;;AAOA,IAAa,8BACX,QACA,SACA,WACyC;CACzC,IACE,CAAC,gBAAgB,OAAO,WAAW,MAAM,KACzC,CAAC,gBAAgB,OAAO,SAAS,MAAM,KACvC,kCAAkC,MAAM,GAExC;CAGF,MAAM,QAAQ,QAAQ,OAAO,WAAW,OAAO,SAAS;CACxD,MAAM,MAAM,QAAQ,OAAO,SAAS,OAAO,OAAO;CAElD,IACE,SAAS,KAAK,MAAM,SAAS,SAAS,KAAK,KAC3C,SAAS,GAAG,MAAM,SAAS,SAAS,GAAG,GAEvC;CAGF,OAAO,SAAS,MAAM;EAAE;EAAO;CAAI,IAAI;AACzC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
/* */
|
|
3
|
+
import { listDateToDateTime } from "./dateRange.mjs";
|
|
4
|
+
import { DateFormatter } from "@internationalized/date";
|
|
5
|
+
//#region ../components-base/src/list/filter/formatDateRange.ts
|
|
6
|
+
/** The active filter chip's text: an end with time shows its time. */
|
|
7
|
+
var formatListDateRange = (value, locale, format) => {
|
|
8
|
+
const formatBound = (bound) => new DateFormatter(locale, {
|
|
9
|
+
year: "numeric",
|
|
10
|
+
month: "numeric",
|
|
11
|
+
day: "numeric",
|
|
12
|
+
..."hour" in bound ? {
|
|
13
|
+
hour: "2-digit",
|
|
14
|
+
minute: "2-digit",
|
|
15
|
+
hourCycle: "h23"
|
|
16
|
+
} : {}
|
|
17
|
+
}).format(listDateToDateTime(bound).toJSDate());
|
|
18
|
+
const { start, end } = value;
|
|
19
|
+
if (start && end) return `${formatBound(start)} – ${formatBound(end)}`;
|
|
20
|
+
if (start) return format("dateRange.from", { date: formatBound(start) });
|
|
21
|
+
if (end) return format("dateRange.until", { date: formatBound(end) });
|
|
22
|
+
return "";
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { formatListDateRange };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=formatDateRange.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatDateRange.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/filter/formatDateRange.ts"],"sourcesContent":["import { DateFormatter } from \"@internationalized/date\";\nimport {\n listDateToDateTime,\n type ListDateParts,\n type ListDateRange,\n} from \"./dateRange\";\n\n/** Formats the text of an open range (\"from {date}\", \"until {date}\"). */\nexport type ListDateRangeTextFormat = (\n key: \"dateRange.from\" | \"dateRange.until\",\n values: { date: string },\n) => string;\n\n/** The active filter chip's text: an end with time shows its time. */\nexport const formatListDateRange = (\n value: ListDateRange,\n locale: string,\n format: ListDateRangeTextFormat,\n): string => {\n const formatBound = (bound: ListDateParts) =>\n new DateFormatter(locale, {\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n // TimeField always shows 24 hours\n ...(\"hour\" in bound\n ? { hour: \"2-digit\", minute: \"2-digit\", hourCycle: \"h23\" }\n : {}),\n }).format(listDateToDateTime(bound).toJSDate());\n\n const { start, end } = value;\n\n if (start && end) {\n return `${formatBound(start)} – ${formatBound(end)}`;\n }\n if (start) {\n return format(\"dateRange.from\", { date: formatBound(start) });\n }\n if (end) {\n return format(\"dateRange.until\", { date: formatBound(end) });\n }\n return \"\";\n};\n"],"mappings":";;;;;;AAcA,IAAa,uBACX,OACA,QACA,WACW;CACX,MAAM,eAAe,UACnB,IAAI,cAAc,QAAQ;EACxB,MAAM;EACN,OAAO;EACP,KAAK;EAEL,GAAI,UAAU,QACV;GAAE,MAAM;GAAW,QAAQ;GAAW,WAAW;EAAM,IACvD,CAAC;CACP,CAAC,CAAC,CAAC,OAAO,mBAAmB,KAAK,CAAC,CAAC,SAAS,CAAC;CAEhD,MAAM,EAAE,OAAO,QAAQ;CAEvB,IAAI,SAAS,KACX,OAAO,GAAG,YAAY,KAAK,EAAE,KAAK,YAAY,GAAG;CAEnD,IAAI,OACF,OAAO,OAAO,kBAAkB,EAAE,MAAM,YAAY,KAAK,EAAE,CAAC;CAE9D,IAAI,KACF,OAAO,OAAO,mBAAmB,EAAE,MAAM,YAAY,GAAG,EAAE,CAAC;CAE7D,OAAO;AACT"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
|
-
import { uniqueBy } from "remeda";
|
|
3
|
+
import { isShallowEqual, uniqueBy } from "remeda";
|
|
4
4
|
import { action, computed, makeObservable, observable } from "mobx";
|
|
5
5
|
//#region ../components-base/src/list/loading/ListLoaderState.ts
|
|
6
6
|
/**
|
|
@@ -49,12 +49,17 @@ var ListLoaderState = class {
|
|
|
49
49
|
this.batchLoadingStates = [];
|
|
50
50
|
this.dataBatches = [];
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Keeps the current batch when `data` holds the same items in the same order.
|
|
54
|
+
* A loader that builds a new array on every fetch — a refetch whose items its
|
|
55
|
+
* data layer reuses — would otherwise re-render the whole list for nothing.
|
|
56
|
+
*/
|
|
52
57
|
setDataBatch(index, data) {
|
|
53
58
|
if (this.dataBatches.length === 0) this.prevDataBatches = [];
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
const current = this.dataBatches[index];
|
|
60
|
+
if (current !== void 0 && isShallowEqual(current, data)) return;
|
|
61
|
+
this.dataBatches[index] = data;
|
|
62
|
+
this.prevDataBatches[index] = data;
|
|
58
63
|
}
|
|
59
64
|
setBatchLoadingState(index, state) {
|
|
60
65
|
if (state === "error" || state === "loaded") this.setIsInitiallyLoading(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListLoaderState.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/loading/ListLoaderState.ts"],"sourcesContent":["import type { BatchLoadingState, ListData } from \"./types\";\nimport { action, computed, makeObservable, observable } from \"mobx\";\nimport { uniqueBy } from \"remeda\";\n\nexport interface ListLoaderStateOptions<T> {\n /**\n * Identifies an item, so the same one loaded in two batches appears once.\n * Without it the batches are concatenated as they arrive.\n */\n getItemId?: (item: T) => string;\n}\n\n/**\n * What a list has loaded so far, and how far each batch has got.\n *\n * MobX, and nothing else — no hook, no framework. A binding reads it through\n * its own reactivity: React with `useSelector`, Vue with `watchMobxValue`. That\n * split is the point: the batching, the deduplication and the \"still loading\"\n * rules are one implementation, and only the subscription is written twice.\n *\n * What is _not_ here is the loading itself. Fetching a batch is\n * `usePromise`/Suspense in React and something else in Vue, so it stays with\n * the binding, and only its outcome is reported here.\n */\nexport class ListLoaderState<T> {\n public dataBatches: ListData<T>[] = [];\n public batchLoadingStates: BatchLoadingState[] = [\"void\"];\n public metadata?: unknown = undefined;\n public isInitiallyLoading = true;\n\n /**\n * The last non-empty result, kept outside MobX on purpose: it exists so a\n * reset can keep rendering the previous data instead of flashing empty, and\n * observing it would make that very reset re-render.\n */\n public prevDataBatches: ListData<T>[] = [];\n\n private readonly getItemId?: (item: T) => string;\n\n public constructor(options: ListLoaderStateOptions<T> = {}) {\n this.getItemId = options.getItemId;\n\n makeObservable(this, {\n prevDataBatches: false,\n dataBatches: observable.shallow,\n batchLoadingStates: observable.shallow,\n metadata: observable,\n mergedData: computed,\n isLoading: computed,\n isLoadingMore: computed,\n isInitiallyLoading: observable,\n setIsInitiallyLoading: action.bound,\n reset: action.bound,\n setDataBatch: action.bound,\n setBatchLoadingState: action.bound,\n setMetadata: action.bound,\n });\n }\n\n public reset(): void {\n this.batchLoadingStates = [];\n this.dataBatches = [];\n }\n\n public setDataBatch(index: number, data: ListData<T>): void {\n if (this.dataBatches.length === 0) {\n this.prevDataBatches = [];\n }\n\n
|
|
1
|
+
{"version":3,"file":"ListLoaderState.mjs","names":[],"sources":["../../../../../../../../components-base/src/list/loading/ListLoaderState.ts"],"sourcesContent":["import type { BatchLoadingState, ListData } from \"./types\";\nimport { action, computed, makeObservable, observable } from \"mobx\";\nimport { isShallowEqual, uniqueBy } from \"remeda\";\n\nexport interface ListLoaderStateOptions<T> {\n /**\n * Identifies an item, so the same one loaded in two batches appears once.\n * Without it the batches are concatenated as they arrive.\n */\n getItemId?: (item: T) => string;\n}\n\n/**\n * What a list has loaded so far, and how far each batch has got.\n *\n * MobX, and nothing else — no hook, no framework. A binding reads it through\n * its own reactivity: React with `useSelector`, Vue with `watchMobxValue`. That\n * split is the point: the batching, the deduplication and the \"still loading\"\n * rules are one implementation, and only the subscription is written twice.\n *\n * What is _not_ here is the loading itself. Fetching a batch is\n * `usePromise`/Suspense in React and something else in Vue, so it stays with\n * the binding, and only its outcome is reported here.\n */\nexport class ListLoaderState<T> {\n public dataBatches: ListData<T>[] = [];\n public batchLoadingStates: BatchLoadingState[] = [\"void\"];\n public metadata?: unknown = undefined;\n public isInitiallyLoading = true;\n\n /**\n * The last non-empty result, kept outside MobX on purpose: it exists so a\n * reset can keep rendering the previous data instead of flashing empty, and\n * observing it would make that very reset re-render.\n */\n public prevDataBatches: ListData<T>[] = [];\n\n private readonly getItemId?: (item: T) => string;\n\n public constructor(options: ListLoaderStateOptions<T> = {}) {\n this.getItemId = options.getItemId;\n\n makeObservable(this, {\n prevDataBatches: false,\n dataBatches: observable.shallow,\n batchLoadingStates: observable.shallow,\n metadata: observable,\n mergedData: computed,\n isLoading: computed,\n isLoadingMore: computed,\n isInitiallyLoading: observable,\n setIsInitiallyLoading: action.bound,\n reset: action.bound,\n setDataBatch: action.bound,\n setBatchLoadingState: action.bound,\n setMetadata: action.bound,\n });\n }\n\n public reset(): void {\n this.batchLoadingStates = [];\n this.dataBatches = [];\n }\n\n /**\n * Keeps the current batch when `data` holds the same items in the same order.\n * A loader that builds a new array on every fetch — a refetch whose items its\n * data layer reuses — would otherwise re-render the whole list for nothing.\n */\n public setDataBatch(index: number, data: ListData<T>): void {\n if (this.dataBatches.length === 0) {\n this.prevDataBatches = [];\n }\n\n const current = this.dataBatches[index];\n if (current !== undefined && isShallowEqual(current, data)) {\n return;\n }\n\n this.dataBatches[index] = data;\n this.prevDataBatches[index] = data;\n }\n\n public setBatchLoadingState(index: number, state: BatchLoadingState): void {\n if (state === \"error\" || state === \"loaded\") {\n this.setIsInitiallyLoading(false);\n }\n if (this.batchLoadingStates[index] !== state) {\n this.batchLoadingStates[index] = state;\n }\n }\n\n public setMetadata(metadata?: unknown): void {\n this.metadata = metadata;\n }\n\n public setIsInitiallyLoading(isInitiallyLoading: boolean): void {\n this.isInitiallyLoading = isInitiallyLoading;\n }\n\n public get mergedData(): T[] {\n const dataBatches =\n this.dataBatches.length === 0 ? this.prevDataBatches : this.dataBatches;\n\n const merged = dataBatches.flatMap((d) => d);\n return this.getItemId ? uniqueBy(merged, this.getItemId) : merged;\n }\n\n public get isLoading(): boolean {\n return this.batchLoadingStates.some((s) => s === \"loading\" || s === \"void\");\n }\n\n public get isLoadingMore(): boolean {\n return this.isLoading && this.dataBatches.length > 0;\n }\n\n public isBatchLoaded(batchIndex: number): boolean {\n return batchIndex in this.dataBatches;\n }\n}\n\nexport default ListLoaderState;\n"],"mappings":";;;;;;;;;;;;;;;;;AAwBA,IAAa,kBAAb,MAAgC;CAC9B,cAAoC,CAAC;CACrC,qBAAiD,CAAC,MAAM;CACxD,WAA4B,KAAA;CAC5B,qBAA4B;;;;;;CAO5B,kBAAwC,CAAC;CAEzC;CAEA,YAAmB,UAAqC,CAAC,GAAG;EAC1D,KAAK,YAAY,QAAQ;EAEzB,eAAe,MAAM;GACnB,iBAAiB;GACjB,aAAa,WAAW;GACxB,oBAAoB,WAAW;GAC/B,UAAU;GACV,YAAY;GACZ,WAAW;GACX,eAAe;GACf,oBAAoB;GACpB,uBAAuB,OAAO;GAC9B,OAAO,OAAO;GACd,cAAc,OAAO;GACrB,sBAAsB,OAAO;GAC7B,aAAa,OAAO;EACtB,CAAC;CACH;CAEA,QAAqB;EACnB,KAAK,qBAAqB,CAAC;EAC3B,KAAK,cAAc,CAAC;CACtB;;;;;;CAOA,aAAoB,OAAe,MAAyB;EAC1D,IAAI,KAAK,YAAY,WAAW,GAC9B,KAAK,kBAAkB,CAAC;EAG1B,MAAM,UAAU,KAAK,YAAY;EACjC,IAAI,YAAY,KAAA,KAAa,eAAe,SAAS,IAAI,GACvD;EAGF,KAAK,YAAY,SAAS;EAC1B,KAAK,gBAAgB,SAAS;CAChC;CAEA,qBAA4B,OAAe,OAAgC;EACzE,IAAI,UAAU,WAAW,UAAU,UACjC,KAAK,sBAAsB,KAAK;EAElC,IAAI,KAAK,mBAAmB,WAAW,OACrC,KAAK,mBAAmB,SAAS;CAErC;CAEA,YAAmB,UAA0B;EAC3C,KAAK,WAAW;CAClB;CAEA,sBAA6B,oBAAmC;EAC9D,KAAK,qBAAqB;CAC5B;CAEA,IAAW,aAAkB;EAI3B,MAAM,UAFJ,KAAK,YAAY,WAAW,IAAI,KAAK,kBAAkB,KAAK,YAAA,CAEnC,SAAS,MAAM,CAAC;EAC3C,OAAO,KAAK,YAAY,SAAS,QAAQ,KAAK,SAAS,IAAI;CAC7D;CAEA,IAAW,YAAqB;EAC9B,OAAO,KAAK,mBAAmB,MAAM,MAAM,MAAM,aAAa,MAAM,MAAM;CAC5E;CAEA,IAAW,gBAAyB;EAClC,OAAO,KAAK,aAAa,KAAK,YAAY,SAAS;CACrD;CAEA,cAAqB,YAA6B;EAChD,OAAO,cAAc,KAAK;CAC5B;AACF"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
/* */
|
|
3
|
+
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
|
4
|
+
//#region ../components-base/src/overlay/OverlayState.ts
|
|
5
|
+
/**
|
|
6
|
+
* Whether an overlay is open, and whether closing it has to be confirmed first.
|
|
7
|
+
* Each binding adds its subscription and its lifecycle: React's
|
|
8
|
+
* `OverlayController` subclasses it, Vue's adapter wraps it in refs.
|
|
9
|
+
*
|
|
10
|
+
* `TCloseOptions` lets a binding pass more on a close than the state reads —
|
|
11
|
+
* React's `overlay`, resolved by `Action` before the close arrives here.
|
|
12
|
+
*/
|
|
13
|
+
var OverlayState = class {
|
|
14
|
+
isOpen = false;
|
|
15
|
+
isContentSuspended = false;
|
|
16
|
+
onOpenHandlers = /* @__PURE__ */ new Set();
|
|
17
|
+
onCloseHandlers = /* @__PURE__ */ new Set();
|
|
18
|
+
onOpenChangeHandlers = /* @__PURE__ */ new Set();
|
|
19
|
+
showConfirmationModal = false;
|
|
20
|
+
closeIsConfirmed = false;
|
|
21
|
+
confirmOnCloseFromOptions;
|
|
22
|
+
/**
|
|
23
|
+
* Every mounted component that has an opinion on close confirmation
|
|
24
|
+
* contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop
|
|
25
|
+
* and a `Form` tracking its dirty state. Combining them instead of assigning
|
|
26
|
+
* a single flag keeps them from overwriting each other.
|
|
27
|
+
*/
|
|
28
|
+
confirmOnCloseSources = observable.map();
|
|
29
|
+
/**
|
|
30
|
+
* Active grants that allow closing without a confirmation. Each entry is
|
|
31
|
+
* scoped to an ongoing operation that legitimately closes the overlay – e.g.
|
|
32
|
+
* a `Form` submit – and is dropped again when that operation has finished, so
|
|
33
|
+
* an operation that does _not_ close the overlay leaves the confirmation
|
|
34
|
+
* armed.
|
|
35
|
+
*/
|
|
36
|
+
closeWithoutConfirmationGrants = /* @__PURE__ */ new Set();
|
|
37
|
+
/**
|
|
38
|
+
* The open state a `setOpen` call is currently applying. Handlers run before
|
|
39
|
+
* `isOpen` is assigned, so a handler that calls `setOpen` again would not be
|
|
40
|
+
* caught by the equality check at the top and would recurse.
|
|
41
|
+
*/
|
|
42
|
+
openStateInFlight;
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
makeObservable(this, {
|
|
45
|
+
isOpen: observable,
|
|
46
|
+
isContentSuspended: observable,
|
|
47
|
+
showConfirmationModal: observable,
|
|
48
|
+
confirmOnCloseEnabled: computed,
|
|
49
|
+
open: action.bound,
|
|
50
|
+
close: action.bound,
|
|
51
|
+
toggle: action.bound,
|
|
52
|
+
setOpen: action.bound,
|
|
53
|
+
syncOpen: action.bound,
|
|
54
|
+
setIsContentSuspended: action.bound,
|
|
55
|
+
confirmClose: action.bound,
|
|
56
|
+
cancelConfirmation: action.bound
|
|
57
|
+
});
|
|
58
|
+
const { isDefaultOpen = false, confirmOnClose = false } = options;
|
|
59
|
+
this.isOpen = isDefaultOpen;
|
|
60
|
+
this.confirmOnCloseFromOptions = confirmOnClose;
|
|
61
|
+
}
|
|
62
|
+
/** Whether closing this overlay currently requires a confirmation. */
|
|
63
|
+
get confirmOnCloseEnabled() {
|
|
64
|
+
if (this.confirmOnCloseSources.size === 0) return this.confirmOnCloseFromOptions;
|
|
65
|
+
return Array.from(this.confirmOnCloseSources.values()).some(Boolean);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Sets the opinion of one source – any object the caller keeps – on close
|
|
69
|
+
* confirmation. Remove the source again when its owner goes away.
|
|
70
|
+
*
|
|
71
|
+
* @internal Bindings call it from their lifecycle.
|
|
72
|
+
*/
|
|
73
|
+
setConfirmOnCloseSource(source, confirmOnClose) {
|
|
74
|
+
runInAction(() => {
|
|
75
|
+
this.confirmOnCloseSources.set(source, confirmOnClose);
|
|
76
|
+
this.withdrawUnneededConfirmation();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** @internal Bindings call it from their lifecycle. */
|
|
80
|
+
removeConfirmOnCloseSource(source) {
|
|
81
|
+
runInAction(() => {
|
|
82
|
+
this.confirmOnCloseSources.delete(source);
|
|
83
|
+
this.withdrawUnneededConfirmation();
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
withdrawUnneededConfirmation() {
|
|
87
|
+
if (!this.confirmOnCloseEnabled) this.showConfirmationModal = false;
|
|
88
|
+
}
|
|
89
|
+
addOpenStateHandler(handler, handlersSet) {
|
|
90
|
+
handlersSet.add(handler);
|
|
91
|
+
return () => {
|
|
92
|
+
handlersSet.delete(handler);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
executeHandlers(isOpen, handlers) {
|
|
96
|
+
return Array.from(handlers).map((handler) => handler(isOpen)).some((result) => result === false);
|
|
97
|
+
}
|
|
98
|
+
executeOnClose() {
|
|
99
|
+
return this.executeHandlers(false, this.onCloseHandlers);
|
|
100
|
+
}
|
|
101
|
+
executeOnOpen() {
|
|
102
|
+
return this.executeHandlers(true, this.onOpenHandlers);
|
|
103
|
+
}
|
|
104
|
+
executeOnOpenChange(isOpen) {
|
|
105
|
+
return this.executeHandlers(isOpen, this.onOpenChangeHandlers);
|
|
106
|
+
}
|
|
107
|
+
addOnClose(handler) {
|
|
108
|
+
return this.addOpenStateHandler(handler, this.onCloseHandlers);
|
|
109
|
+
}
|
|
110
|
+
addOnOpen(handler) {
|
|
111
|
+
return this.addOpenStateHandler(handler, this.onOpenHandlers);
|
|
112
|
+
}
|
|
113
|
+
addOnOpenChange(handler) {
|
|
114
|
+
return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);
|
|
115
|
+
}
|
|
116
|
+
open() {
|
|
117
|
+
this.setOpen(true);
|
|
118
|
+
}
|
|
119
|
+
close(options) {
|
|
120
|
+
this.setOpen(false, options);
|
|
121
|
+
}
|
|
122
|
+
toggle() {
|
|
123
|
+
this.setOpen(!this.isOpen);
|
|
124
|
+
}
|
|
125
|
+
setOpen(toOpen, options) {
|
|
126
|
+
if (this.isOpen === toOpen || this.openStateInFlight === toOpen) return;
|
|
127
|
+
this.openStateInFlight = toOpen;
|
|
128
|
+
try {
|
|
129
|
+
this.applyOpenState(toOpen, options);
|
|
130
|
+
} finally {
|
|
131
|
+
this.openStateInFlight = void 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Sets the open state without running any handler. Use it to mirror a
|
|
136
|
+
* controlled `isOpen` prop, whose change comes from the consumer – notifying
|
|
137
|
+
* them of their own state would echo it back. Closing this way drops a
|
|
138
|
+
* pending close confirmation as well.
|
|
139
|
+
*/
|
|
140
|
+
syncOpen(toOpen) {
|
|
141
|
+
this.assignOpenState(toOpen);
|
|
142
|
+
}
|
|
143
|
+
/** A closed overlay has no close left to confirm. */
|
|
144
|
+
assignOpenState(toOpen) {
|
|
145
|
+
this.isOpen = toOpen;
|
|
146
|
+
if (!toOpen) {
|
|
147
|
+
this.showConfirmationModal = false;
|
|
148
|
+
this.closeIsConfirmed = false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
applyOpenState(toOpen, options) {
|
|
152
|
+
const { bypassConfirmation = false } = options ?? {};
|
|
153
|
+
if (toOpen === false) {
|
|
154
|
+
const closeIsConfirmed = this.closeIsConfirmed;
|
|
155
|
+
this.closeIsConfirmed = false;
|
|
156
|
+
if (this.confirmOnCloseEnabled && !closeIsConfirmed && this.closeWithoutConfirmationGrants.size === 0 && !bypassConfirmation) {
|
|
157
|
+
this.showConfirmationModal = true;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
let aborted;
|
|
162
|
+
if (toOpen) aborted = this.executeOnOpen();
|
|
163
|
+
else aborted = this.executeOnClose();
|
|
164
|
+
if (!aborted) aborted = this.executeOnOpenChange(toOpen);
|
|
165
|
+
if (!aborted) this.assignOpenState(toOpen);
|
|
166
|
+
}
|
|
167
|
+
setIsContentSuspended(to) {
|
|
168
|
+
this.isContentSuspended = to;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Allows closing this overlay without a confirmation until the returned
|
|
172
|
+
* disposer is called. Use it around an operation that may legitimately close
|
|
173
|
+
* the overlay – e.g. a `Form` submit, where a "discard unsaved changes?"
|
|
174
|
+
* prompt would be nonsense – and dispose it as soon as that operation has
|
|
175
|
+
* finished. An operation that ends without closing the overlay therefore
|
|
176
|
+
* leaves the confirmation armed (#2775).
|
|
177
|
+
*/
|
|
178
|
+
grantCloseWithoutConfirmation() {
|
|
179
|
+
const grant = {};
|
|
180
|
+
this.closeWithoutConfirmationGrants.add(grant);
|
|
181
|
+
return () => {
|
|
182
|
+
this.closeWithoutConfirmationGrants.delete(grant);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
confirmClose() {
|
|
186
|
+
this.closeIsConfirmed = true;
|
|
187
|
+
this.showConfirmationModal = false;
|
|
188
|
+
}
|
|
189
|
+
cancelConfirmation() {
|
|
190
|
+
this.showConfirmationModal = false;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
//#endregion
|
|
194
|
+
export { OverlayState };
|
|
195
|
+
|
|
196
|
+
//# sourceMappingURL=OverlayState.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OverlayState.mjs","names":[],"sources":["../../../../../../../components-base/src/overlay/OverlayState.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from \"mobx\";\n\nexport type OverlayOpenHandler = () => unknown;\nexport type OverlayCloseHandler = () => unknown;\nexport type OverlayOpenStateHandler = (isOpen: boolean) => unknown;\nexport type AnyOverlayOpenStateHandler =\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler;\n\nexport type DisposerFn = () => void;\n\nexport interface OverlayCloseOptions {\n /** Close without asking, even when the overlay requires confirmation. */\n bypassConfirmation?: boolean;\n}\n\nexport interface OverlayStateOptions {\n isDefaultOpen?: boolean;\n /**\n * Whether closing the overlay must be confirmed while no source has an\n * opinion (`setConfirmOnCloseSource`).\n */\n confirmOnClose?: boolean;\n}\n\n/**\n * Whether an overlay is open, and whether closing it has to be confirmed first.\n * Each binding adds its subscription and its lifecycle: React's\n * `OverlayController` subclasses it, Vue's adapter wraps it in refs.\n *\n * `TCloseOptions` lets a binding pass more on a close than the state reads —\n * React's `overlay`, resolved by `Action` before the close arrives here.\n */\nexport class OverlayState<\n TCloseOptions extends OverlayCloseOptions = OverlayCloseOptions,\n> {\n public isOpen = false;\n public isContentSuspended = false;\n private onOpenHandlers = new Set<OverlayOpenHandler>();\n private onCloseHandlers = new Set<OverlayCloseHandler>();\n private onOpenChangeHandlers = new Set<OverlayOpenStateHandler>();\n\n public showConfirmationModal = false;\n public closeIsConfirmed = false;\n private readonly confirmOnCloseFromOptions: boolean;\n /**\n * Every mounted component that has an opinion on close confirmation\n * contributes one entry here – e.g. a `Modal` with a `confirmOnClose` prop\n * and a `Form` tracking its dirty state. Combining them instead of assigning\n * a single flag keeps them from overwriting each other.\n */\n private confirmOnCloseSources = observable.map<object, boolean>();\n /**\n * Active grants that allow closing without a confirmation. Each entry is\n * scoped to an ongoing operation that legitimately closes the overlay – e.g.\n * a `Form` submit – and is dropped again when that operation has finished, so\n * an operation that does _not_ close the overlay leaves the confirmation\n * armed.\n */\n private closeWithoutConfirmationGrants = new Set<object>();\n /**\n * The open state a `setOpen` call is currently applying. Handlers run before\n * `isOpen` is assigned, so a handler that calls `setOpen` again would not be\n * caught by the equality check at the top and would recurse.\n */\n private openStateInFlight: boolean | undefined;\n\n public constructor(options: OverlayStateOptions = {}) {\n makeObservable(this, {\n isOpen: observable,\n isContentSuspended: observable,\n showConfirmationModal: observable,\n confirmOnCloseEnabled: computed,\n open: action.bound,\n close: action.bound,\n toggle: action.bound,\n setOpen: action.bound,\n syncOpen: action.bound,\n setIsContentSuspended: action.bound,\n confirmClose: action.bound,\n cancelConfirmation: action.bound,\n });\n const { isDefaultOpen = false, confirmOnClose = false } = options;\n this.isOpen = isDefaultOpen;\n this.confirmOnCloseFromOptions = confirmOnClose;\n }\n\n /** Whether closing this overlay currently requires a confirmation. */\n public get confirmOnCloseEnabled(): boolean {\n if (this.confirmOnCloseSources.size === 0) {\n return this.confirmOnCloseFromOptions;\n }\n return Array.from(this.confirmOnCloseSources.values()).some(Boolean);\n }\n\n /**\n * Sets the opinion of one source – any object the caller keeps – on close\n * confirmation. Remove the source again when its owner goes away.\n *\n * @internal Bindings call it from their lifecycle.\n */\n public setConfirmOnCloseSource(source: object, confirmOnClose: boolean) {\n runInAction(() => {\n this.confirmOnCloseSources.set(source, confirmOnClose);\n this.withdrawUnneededConfirmation();\n });\n }\n\n /** @internal Bindings call it from their lifecycle. */\n public removeConfirmOnCloseSource(source: object) {\n runInAction(() => {\n this.confirmOnCloseSources.delete(source);\n this.withdrawUnneededConfirmation();\n });\n }\n\n private withdrawUnneededConfirmation() {\n if (!this.confirmOnCloseEnabled) {\n this.showConfirmationModal = false;\n }\n }\n\n private addOpenStateHandler<T extends AnyOverlayOpenStateHandler>(\n handler: T,\n handlersSet: Set<T>,\n ): DisposerFn {\n handlersSet.add(handler);\n return () => {\n handlersSet.delete(handler);\n };\n }\n\n private executeHandlers(\n isOpen: boolean,\n handlers: Set<\n OverlayOpenHandler | OverlayCloseHandler | OverlayOpenStateHandler\n >,\n ): boolean {\n const handlerResult = Array.from(handlers).map((handler) =>\n handler(isOpen),\n );\n return handlerResult.some((result) => result === false);\n }\n\n private executeOnClose(): boolean {\n return this.executeHandlers(false, this.onCloseHandlers);\n }\n\n private executeOnOpen(): boolean {\n return this.executeHandlers(true, this.onOpenHandlers);\n }\n\n private executeOnOpenChange(isOpen: boolean): boolean {\n return this.executeHandlers(isOpen, this.onOpenChangeHandlers);\n }\n\n public addOnClose(handler: OverlayCloseHandler) {\n return this.addOpenStateHandler(handler, this.onCloseHandlers);\n }\n\n public addOnOpen(handler: OverlayOpenHandler) {\n return this.addOpenStateHandler(handler, this.onOpenHandlers);\n }\n\n public addOnOpenChange(handler: OverlayOpenStateHandler) {\n return this.addOpenStateHandler(handler, this.onOpenChangeHandlers);\n }\n\n public open(): void {\n this.setOpen(true);\n }\n\n public close(options?: TCloseOptions): void {\n this.setOpen(false, options);\n }\n\n public toggle(): void {\n this.setOpen(!this.isOpen);\n }\n\n public setOpen(toOpen: boolean, options?: TCloseOptions): void {\n if (this.isOpen === toOpen || this.openStateInFlight === toOpen) {\n return;\n }\n\n this.openStateInFlight = toOpen;\n try {\n this.applyOpenState(toOpen, options);\n } finally {\n this.openStateInFlight = undefined;\n }\n }\n\n /**\n * Sets the open state without running any handler. Use it to mirror a\n * controlled `isOpen` prop, whose change comes from the consumer – notifying\n * them of their own state would echo it back. Closing this way drops a\n * pending close confirmation as well.\n */\n public syncOpen(toOpen: boolean): void {\n this.assignOpenState(toOpen);\n }\n\n /** A closed overlay has no close left to confirm. */\n private assignOpenState(toOpen: boolean): void {\n this.isOpen = toOpen;\n if (!toOpen) {\n this.showConfirmationModal = false;\n this.closeIsConfirmed = false;\n }\n }\n\n private applyOpenState(toOpen: boolean, options?: TCloseOptions): void {\n const { bypassConfirmation = false } = options ?? {};\n\n if (toOpen === false) {\n // The confirmation is a one-shot permission for exactly this close\n // attempt – consume it here instead of only when a close succeeds, so it\n // cannot survive an aborted close and disarm later attempts.\n const closeIsConfirmed = this.closeIsConfirmed;\n this.closeIsConfirmed = false;\n\n if (\n this.confirmOnCloseEnabled &&\n !closeIsConfirmed &&\n this.closeWithoutConfirmationGrants.size === 0 &&\n !bypassConfirmation\n ) {\n this.showConfirmationModal = true;\n return;\n }\n }\n\n let aborted: boolean;\n if (toOpen) {\n aborted = this.executeOnOpen();\n } else {\n aborted = this.executeOnClose();\n }\n if (!aborted) {\n aborted = this.executeOnOpenChange(toOpen);\n }\n\n if (!aborted) {\n this.assignOpenState(toOpen);\n }\n }\n\n public setIsContentSuspended(to: boolean): void {\n this.isContentSuspended = to;\n }\n\n /**\n * Allows closing this overlay without a confirmation until the returned\n * disposer is called. Use it around an operation that may legitimately close\n * the overlay – e.g. a `Form` submit, where a \"discard unsaved changes?\"\n * prompt would be nonsense – and dispose it as soon as that operation has\n * finished. An operation that ends without closing the overlay therefore\n * leaves the confirmation armed (#2775).\n */\n public grantCloseWithoutConfirmation(): DisposerFn {\n const grant = {};\n this.closeWithoutConfirmationGrants.add(grant);\n return () => {\n this.closeWithoutConfirmationGrants.delete(grant);\n };\n }\n\n public confirmClose(): void {\n this.closeIsConfirmed = true;\n this.showConfirmationModal = false;\n }\n\n public cancelConfirmation(): void {\n this.showConfirmationModal = false;\n }\n}\n"],"mappings":"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"}
|
|
@@ -2811,7 +2811,7 @@ var table = {
|
|
|
2811
2811
|
}
|
|
2812
2812
|
};
|
|
2813
2813
|
var texture = { "grain": {
|
|
2814
|
-
"value": "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.
|
|
2814
|
+
"value": "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.21' intercept='0.3950'/%3E%3CfeFuncG type='linear' slope='0.21' intercept='0.3950'/%3E%3CfeFuncB type='linear' slope='0.21' intercept='0.3950'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")",
|
|
2815
2815
|
"path": ["texture", "grain"]
|
|
2816
2816
|
} };
|
|
2817
2817
|
var all_dark_default = {
|