dinocollab-core 2.2.41 → 2.2.43

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.create.js","sources":["../../../src/filter-bar/index.create.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { useState, useEffect, useRef } from 'react'\r\nimport { Box, BoxProps, styled, useMediaQuery, useTheme } from '@mui/material'\r\nimport { createFilterMenu } from './menu/create'\r\nimport { createFilterBarContext } from './index.context'\r\nimport { createFilterSort } from './components/filter-sort'\r\nimport { createFilterInput } from './components/filter-input'\r\nimport { createFilterSummary } from './components/filter-summary'\r\n// types\r\nimport type { ComponentType, FC } from 'react'\r\nimport type { TFilterState } from './types'\r\nimport type { IFilterMenuConfig, IFilterMenuProps } from './menu/types'\r\nimport type { IFilterBarContext, IFilterBarContextState } from './index.context'\r\nimport type { IFilterSortConfig, IFilterSortProps } from './components/filter-sort.types'\r\nimport type { IFilterInputConfig, IFilterInputProps } from './components/filter-input.types'\r\nimport type { IFilterSummaryConfig, IFilterSummaryProps } from './components/filter-summary.types'\r\n\r\nexport interface IFilterBarConfigs<T> {\r\n /** Debounce delay for filter input changes in milliseconds @default 300 */\r\n debounceDelay?: number\r\n defaultFilterState?: TFilterState<T>\r\n /** Default filter logic, can be overridden by individual filters @default \"and\" */\r\n defaultFilterLogic?: 'and' | 'or'\r\n InputComponent?: ComponentType<IFilterInputProps<T>>\r\n inputConfig?: IFilterInputConfig<T>\r\n MenuComponent?: ComponentType<IFilterMenuProps<T>>\r\n menuConfig?: IFilterMenuConfig<T>\r\n sortConfig?: IFilterSortConfig<T>\r\n SortComponent?: ComponentType<IFilterSortProps<T>>\r\n /** Enable or disable the summary component. Default is true. */\r\n enableSummary?: boolean\r\n SummaryComponent?: ComponentType<IFilterSummaryProps<T>>\r\n summaryConfig?: IFilterSummaryConfig<T>\r\n}\r\n\r\nexport interface IFilterBarSlots {\r\n summaryWrapProps?: BoxProps\r\n summaryBefore?: React.ReactNode\r\n summaryAfter?: React.ReactNode\r\n before?: React.ReactNode\r\n after?: React.ReactNode\r\n}\r\n\r\nexport interface IFilterBarProps<T> {\r\n sx?: BoxProps['sx']\r\n value?: TFilterState<T>\r\n defaultValue?: TFilterState<T>\r\n onChange?: (state: TFilterState<T>, signal?: AbortSignal) => Promise<void> | void\r\n slots?: IFilterBarSlots\r\n loading?: boolean\r\n}\r\n\r\ninterface IFilterBarState<T> extends IFilterBarContextState<T> {}\r\n\r\nexport function createFilterBar<T>(configs: IFilterBarConfigs<T>) {\r\n const debounceDelay = configs.debounceDelay ?? 300\r\n\r\n if (!configs.InputComponent) {\r\n const configInput = configs.inputConfig || { fields: {} }\r\n configs.inputConfig = configInput\r\n configs.InputComponent = createFilterInput<T>(configInput)\r\n }\r\n if (!configs.MenuComponent) {\r\n const configMenu = configs.menuConfig || { fields: {} }\r\n configs.menuConfig = configMenu\r\n configs.MenuComponent = createFilterMenu<T>(configMenu)\r\n }\r\n if (!configs.SummaryComponent && configs.enableSummary !== false) {\r\n const configSummary: IFilterSummaryConfig<T> = configs.summaryConfig || { fields: {} }\r\n configs.summaryConfig = configSummary\r\n configs.SummaryComponent = createFilterSummary<T>(configSummary)\r\n }\r\n if (!configs.SortComponent) {\r\n const configSort: IFilterSortConfig<T> = configs.sortConfig || { fields: {} }\r\n configs.sortConfig = configSort\r\n configs.SortComponent = createFilterSort<T>(configSort)\r\n }\r\n\r\n const defaultFilterLogic = configs.defaultFilterLogic || 'and'\r\n const Context = createFilterBarContext<T>()\r\n\r\n const FilterBar: FC<IFilterBarProps<T>> = (props) => {\r\n const { slots } = props\r\n const InputComponent = configs.InputComponent as ComponentType<IFilterInputProps<T>>\r\n const MenuComponent = configs.MenuComponent as ComponentType<IFilterMenuProps<T>>\r\n const SummaryComponent = configs.SummaryComponent as ComponentType<IFilterSummaryProps<T>>\r\n const SortComponent = configs.SortComponent as ComponentType<IFilterSortProps<T>>\r\n\r\n const getDefaultFilterState = (): TFilterState<T> => {\r\n return Object.assign({ filterLogic: defaultFilterLogic }, configs.defaultFilterState, props.defaultValue)\r\n }\r\n\r\n const computeInitial = (): IFilterBarState<T> => {\r\n if (props.value) return { filterState: props.value }\r\n return { filterState: getDefaultFilterState() }\r\n }\r\n\r\n const [localState, setLocalState] = useState<IFilterBarState<T>>(computeInitial)\r\n const [isLoading, setIsLoading] = useState<boolean>(false)\r\n const debounceTimer = useRef<number | null>(null)\r\n const pendingStateRef = useRef<TFilterState<T> | null>(null)\r\n const abortControllerRef = useRef<AbortController | null>(null)\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current)\r\n debounceTimer.current = null\r\n }\r\n abortControllerRef.current?.abort()\r\n abortControllerRef.current = null\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n // keep local state in sync if controlled\r\n if (props.value) setLocalState({ filterState: props.value })\r\n }, [props.value])\r\n\r\n const handleChange = async (filterState: TFilterState<T>, signal: AbortSignal, state?: Partial<IFilterBarState<T>>) => {\r\n try {\r\n setLocalState((prev) => ({ filterState: state?.filterState ?? prev.filterState }))\r\n setIsLoading(true)\r\n await props.onChange?.(filterState, signal)\r\n if (signal.aborted) return\r\n setIsLoading(false)\r\n } catch (error) {\r\n if (signal.aborted) return\r\n setIsLoading(false)\r\n throw error\r\n }\r\n }\r\n\r\n // Action handlers to manipulate filter state\r\n // Debounce or throttle can be added to these handlers if needed to optimize performance for rapid changes\r\n const setFilterState = (state: TFilterState<T>) => {\r\n // preserve filterLogic from current state, fallback to defaultFilterLogic if not set\r\n const currentFilterLogic = (props.value || localState.filterState).filterLogic ?? defaultFilterLogic\r\n const mergedState: TFilterState<T> = { filterLogic: currentFilterLogic, ...state }\r\n // store latest requested state\r\n pendingStateRef.current = mergedState\r\n\r\n // If uncontrolled, update UI immediately for responsiveness\r\n if (!props.value) setLocalState({ filterState: mergedState })\r\n\r\n // debounce actual handler calls so only the last one within delay fires\r\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\r\n debounceTimer.current = window.setTimeout(() => {\r\n // abort previous in-flight request before starting a new one\r\n abortControllerRef.current?.abort()\r\n const controller = new AbortController()\r\n abortControllerRef.current = controller\r\n\r\n const s = pendingStateRef.current as TFilterState<T>\r\n if (props.value) {\r\n handleChange(s, controller.signal)\r\n } else {\r\n handleChange(s, controller.signal, { filterState: s })\r\n }\r\n debounceTimer.current = null\r\n pendingStateRef.current = null\r\n }, debounceDelay)\r\n }\r\n\r\n const contextValue: IFilterBarContext<T> = {\r\n filterState: props.value || localState.filterState,\r\n defaultFilterState: getDefaultFilterState(),\r\n isLoading: props.loading || isLoading,\r\n setFilterState\r\n }\r\n\r\n const theme = useTheme()\r\n const isSmall = useMediaQuery(theme.breakpoints.down('md'))\r\n\r\n return (\r\n <Context.Provider value={contextValue}>\r\n <FilterBarStyled className={filterbarClasses.root} sx={props.sx}>\r\n <Box className={filterbarClasses.inner}>\r\n {slots?.before || null}\r\n <div className={filterbarClasses.action}>\r\n <MenuComponent slots={{ popperProps: { placement: 'bottom-start' } }} />\r\n <SortComponent slots={{ popperProps: { placement: 'bottom-start' } }} />\r\n </div>\r\n <InputComponent slots={{ minimalInput: isSmall, popperProps: { placement: 'bottom-start' } }} />\r\n {slots?.after || null}\r\n </Box>\r\n <Box {...slots?.summaryWrapProps} sx={{ display: 'flex', alignItems: 'center', ...slots?.summaryWrapProps?.sx }}>\r\n {slots?.summaryBefore || null}\r\n <Box sx={{ flex: 1, minWidth: 0 }}>{configs.enableSummary !== false && <SummaryComponent />}</Box>\r\n {slots?.summaryAfter || null}\r\n </Box>\r\n </FilterBarStyled>\r\n </Context.Provider>\r\n )\r\n }\r\n\r\n return FilterBar\r\n}\r\n\r\nconst filterbarClasses = {\r\n root: 'DinoFilterBar-root',\r\n inner: 'DinoFilterBar-inner',\r\n action: 'DinoFilterBar-action'\r\n}\r\n\r\nconst FilterBarStyled = styled(Box)(({ theme }) => ({\r\n [`&.${filterbarClasses.root}`]: {\r\n backgroundColor: theme.palette.background.paper,\r\n boxSizing: 'border-box'\r\n },\r\n [`.${filterbarClasses.inner}`]: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: theme.spacing(1)\r\n },\r\n [`.${filterbarClasses.action}`]: {\r\n display: 'flex',\r\n alignItems: 'center'\r\n }\r\n}))\r\n"],"names":["createFilterBar","configs","_configs$debounceDela","debounceDelay","InputComponent","configInput","inputConfig","fields","createFilterInput","MenuComponent","configMenu","menuConfig","createFilterMenu","SummaryComponent","enableSummary","configSummary","summaryConfig","createFilterSummary","SortComponent","configSort","sortConfig","createFilterSort","defaultFilterLogic","Context","createFilterBarContext","props","_slots$summaryWrapPro","slots","getDefaultFilterState","Object","assign","filterLogic","defaultFilterState","defaultValue","_useState","useState","value","filterState","_useState2","_slicedToArray","localState","setLocalState","_useState3","_useState4","isLoading","setIsLoading","debounceTimer","useRef","pendingStateRef","abortControllerRef","useEffect","_abortControllerRef$c","current","clearTimeout","abort","handleChange","_ref","_asyncToGenerator","_regenerator","m","_callee","signal","state","_props$onChange","_t","w","_context","p","n","prev","_state$filterState","onChange","call","aborted","a","v","_x","_x2","_x3","apply","this","arguments","contextValue","loading","setFilterState","_filterLogic","currentFilterLogic","mergedState","_objectSpread","window","setTimeout","_abortControllerRef$c2","controller","AbortController","s","theme","useTheme","isSmall","useMediaQuery","breakpoints","down","_jsx","Provider","children","_jsxs","FilterBarStyled","className","filterbarClasses","root","sx","Box","inner","before","action","popperProps","placement","minimalInput","after","summaryWrapProps","display","alignItems","summaryBefore","flex","minWidth","summaryAfter","styled","_ref2","_defineProperty","concat","backgroundColor","palette","background","paper","boxSizing","gap","spacing"],"mappings":"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"}
1
+ {"version":3,"file":"index.create.js","sources":["../../../src/filter-bar/index.create.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { useState, useEffect, useRef } from 'react'\r\nimport { Box, BoxProps, styled, useMediaQuery, useTheme } from '@mui/material'\r\nimport { createFilterMenu } from './menu/create'\r\nimport { createFilterBarContext } from './index.context'\r\nimport { DEFAULT_LOGIC_ROOT } from './helpers'\r\nimport { createFilterSort } from './components/filter-sort'\r\nimport { createFilterInput } from './components/filter-input'\r\nimport { createFilterSummary } from './components/filter-summary'\r\n// types\r\nimport type { ComponentType, FC } from 'react'\r\nimport type { TFilterState } from './types'\r\nimport type { IFilterMenuConfig, IFilterMenuProps } from './menu/types'\r\nimport type { IFilterBarContext, IFilterBarContextState } from './index.context'\r\nimport type { IFilterSortConfig, IFilterSortProps } from './components/filter-sort.types'\r\nimport type { IFilterInputConfig, IFilterInputProps } from './components/filter-input.types'\r\nimport type { IFilterSummaryConfig, IFilterSummaryProps } from './components/filter-summary.types'\r\n\r\nexport interface IFilterBarConfigs<T> {\r\n /** Debounce delay for filter input changes in milliseconds @default 300 */\r\n debounceDelay?: number\r\n defaultFilterState?: TFilterState<T>\r\n /** Default filter logic, can be overridden by individual filters @default \"and\" */\r\n defaultFilterLogic?: 'and' | 'or'\r\n InputComponent?: ComponentType<IFilterInputProps<T>>\r\n inputConfig?: IFilterInputConfig<T>\r\n MenuComponent?: ComponentType<IFilterMenuProps<T>>\r\n menuConfig?: IFilterMenuConfig<T>\r\n sortConfig?: IFilterSortConfig<T>\r\n SortComponent?: ComponentType<IFilterSortProps<T>>\r\n /** Enable or disable the summary component. Default is true. */\r\n enableSummary?: boolean\r\n SummaryComponent?: ComponentType<IFilterSummaryProps<T>>\r\n summaryConfig?: IFilterSummaryConfig<T>\r\n}\r\n\r\nexport interface IFilterBarSlots {\r\n summaryWrapProps?: BoxProps\r\n summaryBefore?: React.ReactNode\r\n summaryAfter?: React.ReactNode\r\n before?: React.ReactNode\r\n after?: React.ReactNode\r\n}\r\n\r\nexport interface IFilterBarProps<T> {\r\n sx?: BoxProps['sx']\r\n value?: TFilterState<T>\r\n defaultValue?: TFilterState<T>\r\n onChange?: (state: TFilterState<T>, signal?: AbortSignal) => Promise<void> | void\r\n slots?: IFilterBarSlots\r\n loading?: boolean\r\n}\r\n\r\ninterface IFilterBarState<T> extends IFilterBarContextState<T> {}\r\n\r\nexport function createFilterBar<T>(configs: IFilterBarConfigs<T>) {\r\n const debounceDelay = configs.debounceDelay ?? 300\r\n\r\n if (!configs.InputComponent) {\r\n const configInput = configs.inputConfig || { fields: {} }\r\n configs.inputConfig = configInput\r\n configs.InputComponent = createFilterInput<T>(configInput)\r\n }\r\n if (!configs.MenuComponent) {\r\n const configMenu = configs.menuConfig || { fields: {} }\r\n configs.menuConfig = configMenu\r\n configs.MenuComponent = createFilterMenu<T>(configMenu)\r\n }\r\n if (!configs.SummaryComponent && configs.enableSummary !== false) {\r\n const configSummary: IFilterSummaryConfig<T> = configs.summaryConfig || { fields: {} }\r\n configs.summaryConfig = configSummary\r\n configs.SummaryComponent = createFilterSummary<T>(configSummary)\r\n }\r\n if (!configs.SortComponent) {\r\n const configSort: IFilterSortConfig<T> = configs.sortConfig || { fields: {} }\r\n configs.sortConfig = configSort\r\n configs.SortComponent = createFilterSort<T>(configSort)\r\n }\r\n\r\n const defaultFilterLogic = configs.defaultFilterLogic || DEFAULT_LOGIC_ROOT\r\n const Context = createFilterBarContext<T>()\r\n\r\n const FilterBar: FC<IFilterBarProps<T>> = (props) => {\r\n const { slots } = props\r\n const InputComponent = configs.InputComponent as ComponentType<IFilterInputProps<T>>\r\n const MenuComponent = configs.MenuComponent as ComponentType<IFilterMenuProps<T>>\r\n const SummaryComponent = configs.SummaryComponent as ComponentType<IFilterSummaryProps<T>>\r\n const SortComponent = configs.SortComponent as ComponentType<IFilterSortProps<T>>\r\n\r\n const getDefaultFilterState = (): TFilterState<T> => {\r\n return Object.assign({ filterLogic: defaultFilterLogic }, configs.defaultFilterState, props.defaultValue)\r\n }\r\n\r\n const computeInitial = (): IFilterBarState<T> => {\r\n if (props.value) return { filterState: props.value }\r\n return { filterState: getDefaultFilterState() }\r\n }\r\n\r\n const [localState, setLocalState] = useState<IFilterBarState<T>>(computeInitial)\r\n const [isLoading, setIsLoading] = useState<boolean>(false)\r\n const debounceTimer = useRef<number | null>(null)\r\n const pendingStateRef = useRef<TFilterState<T> | null>(null)\r\n const abortControllerRef = useRef<AbortController | null>(null)\r\n\r\n useEffect(() => {\r\n return () => {\r\n if (debounceTimer.current) {\r\n clearTimeout(debounceTimer.current)\r\n debounceTimer.current = null\r\n }\r\n abortControllerRef.current?.abort()\r\n abortControllerRef.current = null\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n // keep local state in sync if controlled\r\n if (props.value) setLocalState({ filterState: props.value })\r\n }, [props.value])\r\n\r\n const handleChange = async (filterState: TFilterState<T>, signal: AbortSignal, state?: Partial<IFilterBarState<T>>) => {\r\n try {\r\n setLocalState((prev) => ({ filterState: state?.filterState ?? prev.filterState }))\r\n setIsLoading(true)\r\n await props.onChange?.(filterState, signal)\r\n if (signal.aborted) return\r\n setIsLoading(false)\r\n } catch (error) {\r\n if (signal.aborted) return\r\n setIsLoading(false)\r\n throw error\r\n }\r\n }\r\n\r\n // Action handlers to manipulate filter state\r\n // Debounce or throttle can be added to these handlers if needed to optimize performance for rapid changes\r\n const setFilterState = (state: TFilterState<T>) => {\r\n // preserve filterLogic from current state, fallback to defaultFilterLogic if not set\r\n const currentFilterLogic = (props.value || localState.filterState).filterLogic ?? defaultFilterLogic\r\n const rawFilterLogic = state.filterLogic ?? currentFilterLogic\r\n const mergedState: TFilterState<T> = { ...state }\r\n if (rawFilterLogic !== defaultFilterLogic) mergedState.filterLogic = rawFilterLogic\r\n else delete mergedState.filterLogic\r\n // store latest requested state\r\n pendingStateRef.current = mergedState\r\n\r\n // If uncontrolled, update UI immediately for responsiveness\r\n if (!props.value) setLocalState({ filterState: mergedState })\r\n\r\n // debounce actual handler calls so only the last one within delay fires\r\n if (debounceTimer.current) clearTimeout(debounceTimer.current)\r\n debounceTimer.current = window.setTimeout(() => {\r\n // abort previous in-flight request before starting a new one\r\n abortControllerRef.current?.abort()\r\n const controller = new AbortController()\r\n abortControllerRef.current = controller\r\n\r\n const s = pendingStateRef.current as TFilterState<T>\r\n if (props.value) {\r\n handleChange(s, controller.signal)\r\n } else {\r\n handleChange(s, controller.signal, { filterState: s })\r\n }\r\n debounceTimer.current = null\r\n pendingStateRef.current = null\r\n }, debounceDelay)\r\n }\r\n\r\n const contextValue: IFilterBarContext<T> = {\r\n filterState: props.value || localState.filterState,\r\n defaultFilterState: getDefaultFilterState(),\r\n isLoading: props.loading || isLoading,\r\n setFilterState\r\n }\r\n\r\n const theme = useTheme()\r\n const isSmall = useMediaQuery(theme.breakpoints.down('md'))\r\n\r\n return (\r\n <Context.Provider value={contextValue}>\r\n <FilterBarStyled className={filterbarClasses.root} sx={props.sx}>\r\n <Box className={filterbarClasses.inner}>\r\n {slots?.before || null}\r\n <div className={filterbarClasses.action}>\r\n <MenuComponent slots={{ popperProps: { placement: 'bottom-start' } }} />\r\n <SortComponent slots={{ popperProps: { placement: 'bottom-start' } }} />\r\n </div>\r\n <InputComponent slots={{ minimalInput: isSmall, popperProps: { placement: 'bottom-start' } }} />\r\n {slots?.after || null}\r\n </Box>\r\n <Box {...slots?.summaryWrapProps} sx={{ display: 'flex', alignItems: 'center', ...slots?.summaryWrapProps?.sx }}>\r\n {slots?.summaryBefore || null}\r\n <Box sx={{ flex: 1, minWidth: 0 }}>{configs.enableSummary !== false && <SummaryComponent />}</Box>\r\n {slots?.summaryAfter || null}\r\n </Box>\r\n </FilterBarStyled>\r\n </Context.Provider>\r\n )\r\n }\r\n\r\n return FilterBar\r\n}\r\n\r\nconst filterbarClasses = {\r\n root: 'DinoFilterBar-root',\r\n inner: 'DinoFilterBar-inner',\r\n action: 'DinoFilterBar-action'\r\n}\r\n\r\nconst FilterBarStyled = styled(Box)(({ theme }) => ({\r\n [`&.${filterbarClasses.root}`]: {\r\n backgroundColor: theme.palette.background.paper,\r\n boxSizing: 'border-box'\r\n },\r\n [`.${filterbarClasses.inner}`]: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: theme.spacing(1)\r\n },\r\n [`.${filterbarClasses.action}`]: {\r\n display: 'flex',\r\n alignItems: 'center'\r\n }\r\n}))\r\n"],"names":["createFilterBar","configs","_configs$debounceDela","debounceDelay","InputComponent","configInput","inputConfig","fields","createFilterInput","MenuComponent","configMenu","menuConfig","createFilterMenu","SummaryComponent","enableSummary","configSummary","summaryConfig","createFilterSummary","SortComponent","configSort","sortConfig","createFilterSort","defaultFilterLogic","DEFAULT_LOGIC_ROOT","Context","createFilterBarContext","props","_slots$summaryWrapPro","slots","getDefaultFilterState","Object","assign","filterLogic","defaultFilterState","defaultValue","_useState","useState","value","filterState","_useState2","_slicedToArray","localState","setLocalState","_useState3","_useState4","isLoading","setIsLoading","debounceTimer","useRef","pendingStateRef","abortControllerRef","useEffect","_abortControllerRef$c","current","clearTimeout","abort","handleChange","_ref","_asyncToGenerator","_regenerator","m","_callee","signal","state","_props$onChange","_t","w","_context","p","n","prev","_state$filterState","onChange","call","aborted","a","v","_x","_x2","_x3","apply","this","arguments","contextValue","loading","setFilterState","_filterLogic","_state$filterLogic","currentFilterLogic","rawFilterLogic","mergedState","_objectSpread","window","setTimeout","_abortControllerRef$c2","controller","AbortController","s","theme","useTheme","isSmall","useMediaQuery","breakpoints","down","_jsx","Provider","children","_jsxs","FilterBarStyled","className","filterbarClasses","root","sx","Box","inner","before","action","popperProps","placement","minimalInput","after","summaryWrapProps","display","alignItems","summaryBefore","flex","minWidth","summaryAfter","styled","_ref2","_defineProperty","concat","backgroundColor","palette","background","paper","boxSizing","gap","spacing"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{defineProperty as l,slicedToArray as e}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as i,jsxs as n}from"react/jsx-runtime";import{useMemo as o,useState as t}from"react";import{styled as r,radioGroupClasses as a,Box as u,Typography as s,RadioGroup as c,FormControlLabel as d,Radio as v,Button as p}from"@mui/material";import{createChipViewers as m}from"../components/chip-viewer.js";import{ButtonBack as f,ChipDark as b}from"../components/ui.units.js";import{PopperContent as g,PopperBody as h,PopperFooter as y}from"../components/popper-custom.js";function x(l){var r,a,x=m(),C=null!==(r=null==l?void 0:l.trueLabel)&&void 0!==r?r:"Yes",z=null!==(a=null==l?void 0:l.falseLabel)&&void 0!==a?a:"No",j=[{value:!0,label:C},{value:!1,label:z}];return function(r){var a,m=o(function(){return Object.assign({},{singleValue:!0},r.currentConfig,null==l?void 0:l.config)},[null==l?void 0:l.config,r.currentConfig]),k=r.value,A=void 0===k?{values:[],logic:"or"}:k,L=A.values.length>0?String(A.values[0]):"",B=t(L),N=e(B,2),P=N[0],R=N[1],T=null!==(a=null==m?void 0:m.label)&&void 0!==a?a:m.field.toString(),V=""!==P,w=!V,F=o(function(){var l=Array.isArray(A.values)?A.values:[A.values];return{field:m.field,items:l.map(function(l){return{value:l,label:!0===l?C:!1===l?z:String(l)}})}},[m.field,A]),I=o(function(){var e=(null==l?void 0:l.top)||r.top;return e?i(u,{sx:{mb:1},children:e}):null},[null==l?void 0:l.top,r.top]),Y=[];return r.isLoading&&Y.push("disabled"),i(S,{className:Y.join(" "),noValidate:!0,onSubmit:function(l){(l.preventDefault(),l.stopPropagation(),V)&&(!function(l){r.onSubmit(m.field,l,m)}({values:["true"===P],logic:"or"}),R(""))},children:n(g,{title:"Filter by ".concat(T),onClose:r.onClose,slots:{beforeTitle:i(f,{size:"small",onClick:r.onBack}),afterTitle:i(b,{sx:{ml:1.5},size:"small",label:"Single value"})},children:[n(h,{children:[I,m.description&&i(s,{variant:"caption",color:"text.secondary",sx:{mb:1,display:"block"},children:m.description}),i(x,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:F,onRemove:r.onRemove}),i(c,{name:m.field.toString(),value:P,onChange:function(l){return R(l.target.value)},children:j.map(function(l){return i(d,{value:String(l.value),control:i(v,{size:"small"}),label:i(s,{variant:"body2",children:l.label})},String(l.value))})})]}),n(y,{children:[i(p,{size:"small",color:"error",variant:"text",disabled:!A.values||0===A.values.length,onClick:function(){var l;null===(l=r.onRemoveField)||void 0===l||l.call(r,m.field,m)},children:"Clear All"}),i(u,{sx:{flex:1}}),i(p,{size:"small",color:"inherit",variant:"text",onClick:r.onClose,children:"Cancel"}),i(p,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:w,children:"Apply"})]})]})})}}function C(l){var e,i,n=null!==(e=null==l?void 0:l.trueLabel)&&void 0!==e?e:"Yes",o=null!==(i=null==l?void 0:l.falseLabel)&&void 0!==i?i:"No";return function(l){return!0===l||"true"===l?n:!1===l||"false"===l?o:String(l)}}var S=r("form")(l({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.12)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}},".".concat(a.root),{gap:0}));export{x as default,C as formatterBoolean};
1
+ import{defineProperty as l,slicedToArray as e}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as i,jsxs as n}from"react/jsx-runtime";import{useMemo as o,useState as t}from"react";import{styled as r,radioGroupClasses as a,Box as s,Typography as u,RadioGroup as c,FormControlLabel as d,Radio as v,Button as p}from"@mui/material";import{createChipViewers as m}from"../components/chip-viewer.js";import{ButtonBack as f,ChipDark as b}from"../components/ui.units.js";import{PopperContent as g,PopperBody as h,PopperFooter as y}from"../components/popper-custom.js";import{DEFAULT_LOGIC as x}from"../helpers.js";function C(l){var r,a,C=m(),S=null!==(r=null==l?void 0:l.trueLabel)&&void 0!==r?r:"Yes",j=null!==(a=null==l?void 0:l.falseLabel)&&void 0!==a?a:"No",k=[{value:!0,label:S},{value:!1,label:j}];return function(r){var a,m=o(function(){return Object.assign({},{singleValue:!0},r.currentConfig,null==l?void 0:l.config)},[null==l?void 0:l.config,r.currentConfig]),A=r.value,L=void 0===A?{values:[],logic:x}:A,B=L.values.length>0?String(L.values[0]):"",N=t(B),P=e(N,2),R=P[0],T=P[1],V=null!==(a=null==m?void 0:m.label)&&void 0!==a?a:m.field.toString(),w=""!==R,F=!w,I=o(function(){var l=Array.isArray(L.values)?L.values:[L.values];return{field:m.field,items:l.map(function(l){return{value:l,label:!0===l?S:!1===l?j:String(l)}})}},[m.field,L]),Y=o(function(){var e=(null==l?void 0:l.top)||r.top;return e?i(s,{sx:{mb:1},children:e}):null},[null==l?void 0:l.top,r.top]),_=[];return r.isLoading&&_.push("disabled"),i(z,{className:_.join(" "),noValidate:!0,onSubmit:function(l){(l.preventDefault(),l.stopPropagation(),w)&&(!function(l){r.onSubmit(m.field,l,m)}({values:["true"===R],logic:x}),T(""))},children:n(g,{title:"Filter by ".concat(V),onClose:r.onClose,slots:{beforeTitle:i(f,{size:"small",onClick:r.onBack}),afterTitle:i(b,{sx:{ml:1.5},size:"small",label:"Single value"})},children:[n(h,{children:[Y,m.description&&i(u,{variant:"caption",color:"text.secondary",sx:{mb:1,display:"block"},children:m.description}),i(C,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:I,onRemove:r.onRemove}),i(c,{name:m.field.toString(),value:R,onChange:function(l){return T(l.target.value)},children:k.map(function(l){return i(d,{value:String(l.value),control:i(v,{size:"small"}),label:i(u,{variant:"body2",children:l.label})},String(l.value))})})]}),n(y,{children:[i(p,{size:"small",color:"error",variant:"text",disabled:!L.values||0===L.values.length,onClick:function(){var l;null===(l=r.onRemoveField)||void 0===l||l.call(r,m.field,m)},children:"Clear All"}),i(s,{sx:{flex:1}}),i(p,{size:"small",color:"inherit",variant:"text",onClick:r.onClose,children:"Cancel"}),i(p,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:F,children:"Apply"})]})]})})}}function S(l){var e,i,n=null!==(e=null==l?void 0:l.trueLabel)&&void 0!==e?e:"Yes",o=null!==(i=null==l?void 0:l.falseLabel)&&void 0!==i?i:"No";return function(l){return!0===l||"true"===l?n:!1===l||"false"===l?o:String(l)}}var z=r("form")(l({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.12)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}},".".concat(a.root),{gap:0}));export{C as default,S as formatterBoolean};
2
2
  //# sourceMappingURL=create-form-field-boolean.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-form-field-boolean.js","sources":["../../../../src/filter-bar/menu/create-form-field-boolean.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { useMemo, useState } from 'react'\r\nimport { Box, Button, FormControlLabel, Radio, RadioGroup, radioGroupClasses, styled, Typography } from '@mui/material'\r\nimport { createChipViewers, TChipViewerGroup } from '../components/chip-viewer'\r\nimport { ButtonBack, ChipDark } from '../components/ui.units'\r\nimport { PopperBody, PopperContent, PopperFooter } from '../components/popper-custom'\r\n// types\r\nimport type { FC, ReactNode } from 'react'\r\nimport type { TFieldValid, TFieldValue } from '../types'\r\nimport type { IFieldMenuConfig, IFilterMenuFormProps } from './types'\r\n\r\n/** Props for the `FormFieldBoolean` component returned by `createFormFieldBoolean`. Extends the base filter-menu form props. */\r\nexport interface IFormFieldBooleanProps<T> extends IFilterMenuFormProps<T> {\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/** Parameters passed to `createFormFieldBoolean` to configure the generated component. */\r\nexport interface IFormFieldBooleanParam<T> {\r\n /** Optional configuration for the form field */\r\n config?: IFieldMenuConfig<T>\r\n /** Label for the `true` option. @default \"Yes\" */\r\n trueLabel?: string\r\n /** Label for the `false` option. @default \"No\" */\r\n falseLabel?: string\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/**\r\n * Factory function that creates a `FormFieldBoolean` filter-menu component.\r\n *\r\n * The generated component renders two radio buttons (true / false) inside a\r\n * popper/menu panel. It is designed for boolean fields such as `is_active`,\r\n * `is_deleted`, `is_verified`, etc. It supports:\r\n * - Configurable labels for the true/false options (e.g. \"Yes / No\", \"Active / Inactive\")\r\n * - Chip viewers showing the currently applied value\r\n * - Single-value mode by default (only one boolean can be applied at a time)\r\n * - A loading overlay that disables interaction while `isLoading` is true\r\n *\r\n * @param params - Static configuration (optional label overrides, optional field config override)\r\n * @returns A React FC ready to be used as a boolean filter-menu field component\r\n */\r\nfunction createFormFieldBoolean<T>(params?: IFormFieldBooleanParam<T>) {\r\n const ChipViewers = createChipViewers<T>()\r\n\r\n const trueLabel = params?.trueLabel ?? 'Yes'\r\n const falseLabel = params?.falseLabel ?? 'No'\r\n\r\n const BOOLEAN_OPTIONS: { value: TFieldValid; label: string }[] = [\r\n { value: true, label: trueLabel },\r\n { value: false, label: falseLabel }\r\n ]\r\n\r\n const FormFieldBoolean: FC<IFormFieldBooleanProps<T>> = (props) => {\r\n /** Merge `props.currentConfig` with `params.config` (if provided).\r\n * Fields from `params.config` override the corresponding keys in `props.currentConfig`.\r\n * Any keys not present in `params.config` are preserved from `props.currentConfig`.\r\n */\r\n // singleValue:true is the boolean default — ensures replaceFilter is used instead of upsertManyFilter\r\n const mergedConfig = useMemo(\r\n () => Object.assign({}, { singleValue: true }, props.currentConfig, params?.config),\r\n [params?.config, props.currentConfig]\r\n )\r\n\r\n const { value = { values: [], logic: 'or' } } = props\r\n // Initialize from existing applied value so the radio reflects current state when reopening\r\n const initialSelected = value.values.length > 0 ? String(value.values[0]) : ''\r\n // Radio value is stored as string in DOM; convert back to boolean on submit\r\n const [selectedValue, setSelectedValue] = useState<string>(initialSelected)\r\n\r\n const label = mergedConfig?.label ?? mergedConfig.field.toString()\r\n\r\n const hasDataChange = selectedValue !== ''\r\n const isApplyDisabled = !hasDataChange\r\n\r\n const handleSubmit = (newValue: TFieldValue) => {\r\n props.onSubmit(mergedConfig.field, newValue, mergedConfig)\r\n }\r\n\r\n const handleSubmitForm = (event: React.FormEvent<HTMLFormElement>) => {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n\r\n if (!hasDataChange) return\r\n\r\n // Convert string back to actual boolean\r\n const boolValue = selectedValue === 'true'\r\n const newValue: TFieldValue = { values: [boolValue as TFieldValid], logic: 'or' }\r\n handleSubmit(newValue)\r\n setSelectedValue('')\r\n }\r\n\r\n const filterViewerValue = useMemo<TChipViewerGroup<T>>(() => {\r\n const items = Array.isArray(value.values) ? value.values : [value.values]\r\n return {\r\n field: mergedConfig.field,\r\n items: items.map((v) => ({\r\n value: v,\r\n label: v === true ? trueLabel : v === false ? falseLabel : String(v)\r\n }))\r\n }\r\n }, [mergedConfig.field, value])\r\n\r\n const handleClearAll = () => {\r\n props.onRemoveField?.(mergedConfig.field, mergedConfig)\r\n }\r\n\r\n const renderTop = useMemo(() => {\r\n const topContent = params?.top || props.top\r\n if (topContent) return <Box sx={{ mb: 1 }}>{topContent}</Box>\r\n return null\r\n }, [params?.top, props.top])\r\n\r\n // Boolean is always single-value — show badge instead of logic toggle\r\n const renderAfterTitle = () => <ChipDark sx={{ ml: 1.5 }} size='small' label='Single value' />\r\n\r\n const rootClasses: string[] = []\r\n if (props.isLoading) rootClasses.push('disabled')\r\n\r\n return (\r\n <RootStyled className={rootClasses.join(' ')} noValidate onSubmit={handleSubmitForm}>\r\n <PopperContent\r\n title={`Filter by ${label}`}\r\n onClose={props.onClose}\r\n slots={{\r\n beforeTitle: <ButtonBack size='small' onClick={props.onBack} />,\r\n afterTitle: renderAfterTitle()\r\n }}\r\n >\r\n <PopperBody>\r\n {renderTop}\r\n {mergedConfig.description && (\r\n <Typography variant='caption' color='text.secondary' sx={{ mb: 1, display: 'block' }}>\r\n {mergedConfig.description}\r\n </Typography>\r\n )}\r\n <ChipViewers\r\n sx={{ mb: 1, borderBottom: 'none!important' }}\r\n label='Applied'\r\n placement='horizontal'\r\n enableMinimalesticView\r\n value={filterViewerValue}\r\n onRemove={props.onRemove}\r\n />\r\n <RadioGroup name={mergedConfig.field.toString()} value={selectedValue} onChange={(e) => setSelectedValue(e.target.value)}>\r\n {BOOLEAN_OPTIONS.map((option) => (\r\n <FormControlLabel\r\n key={String(option.value)}\r\n value={String(option.value)}\r\n control={<Radio size='small' />}\r\n label={<Typography variant='body2'>{option.label}</Typography>}\r\n />\r\n ))}\r\n </RadioGroup>\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button size='small' color='error' variant='text' disabled={!value.values || value.values.length === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n <Box sx={{ flex: 1 }} />\r\n <Button size='small' color='inherit' variant='text' onClick={props.onClose}>\r\n Cancel\r\n </Button>\r\n <Button size='small' type='submit' color='primary' variant='contained' disabled={isApplyDisabled}>\r\n Apply\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n </RootStyled>\r\n )\r\n }\r\n\r\n return FormFieldBoolean\r\n}\r\n\r\nexport default createFormFieldBoolean\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utilities\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Creates a `labelFormatter` for use in `summaryConfig`.\r\n * Converts boolean values (`true` / `false`) to human-readable labels in the filter summary chips.\r\n *\r\n * @param trueLabel - Label shown for `true`. @default \"Yes\"\r\n * @param falseLabel - Label shown for `false`. @default \"No\"\r\n *\r\n * @example\r\n * ```ts\r\n * createFilterSummary({\r\n * fields: {\r\n * active: { label: 'Active', labelFormatter: formatterBoolean({ trueLabel: 'Active', falseLabel: 'Inactive' }) }\r\n * }\r\n * })\r\n * ```\r\n */\r\nexport function formatterBoolean(param?: { trueLabel?: string; falseLabel?: string }) {\r\n const trueLabel = param?.trueLabel ?? 'Yes'\r\n const falseLabel = param?.falseLabel ?? 'No'\r\n return (value: TFieldValid): string | undefined => {\r\n if (value === true || value === 'true') return trueLabel\r\n if (value === false || value === 'false') return falseLabel\r\n return String(value)\r\n }\r\n}\r\n\r\nconst RootStyled = styled('form')({\r\n position: 'relative',\r\n '&::after': {\r\n content: '\"\"',\r\n display: 'block',\r\n position: 'absolute',\r\n inset: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.12)',\r\n filter: 'blur(2px)',\r\n zIndex: -1,\r\n opacity: 0,\r\n transition: 'opacity 0.3s',\r\n visibility: 'hidden'\r\n },\r\n '&.disabled': {\r\n pointerEvents: 'none',\r\n '&::after': { zIndex: 1, opacity: 1, visibility: 'visible' }\r\n },\r\n [`.${radioGroupClasses.root}`]: { gap: 0 }\r\n})\r\n"],"names":["createFormFieldBoolean","params","_params$trueLabel","_params$falseLabel","ChipViewers","createChipViewers","trueLabel","falseLabel","BOOLEAN_OPTIONS","value","label","props","_mergedConfig$label","mergedConfig","useMemo","Object","assign","singleValue","currentConfig","config","_props$value","values","logic","initialSelected","length","String","_useState","useState","_useState2","_slicedToArray","selectedValue","setSelectedValue","field","toString","hasDataChange","isApplyDisabled","filterViewerValue","items","Array","isArray","map","v","renderTop","topContent","top","_jsx","Box","sx","mb","children","rootClasses","isLoading","push","RootStyled","className","join","noValidate","onSubmit","event","preventDefault","stopPropagation","newValue","handleSubmit","_jsxs","PopperContent","title","concat","onClose","slots","beforeTitle","ButtonBack","size","onClick","onBack","afterTitle","ChipDark","ml","PopperBody","description","Typography","variant","color","display","borderBottom","placement","enableMinimalesticView","onRemove","RadioGroup","name","onChange","e","target","option","FormControlLabel","control","Radio","PopperFooter","Button","disabled","_props$onRemoveField","onRemoveField","call","flex","type","formatterBoolean","param","_param$trueLabel","_param$falseLabel","styled","_defineProperty","position","content","inset","backgroundColor","filter","zIndex","opacity","transition","visibility","pointerEvents","radioGroupClasses","root","gap"],"mappings":"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"}
1
+ {"version":3,"file":"create-form-field-boolean.js","sources":["../../../../src/filter-bar/menu/create-form-field-boolean.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { useMemo, useState } from 'react'\r\nimport { Box, Button, FormControlLabel, Radio, RadioGroup, radioGroupClasses, styled, Typography } from '@mui/material'\r\nimport { createChipViewers, TChipViewerGroup } from '../components/chip-viewer'\r\nimport { ButtonBack, ChipDark } from '../components/ui.units'\r\nimport { PopperBody, PopperContent, PopperFooter } from '../components/popper-custom'\r\nimport { DEFAULT_LOGIC } from '../helpers'\r\n// types\r\nimport type { FC, ReactNode } from 'react'\r\nimport type { TFieldValid, TFieldValue } from '../types'\r\nimport type { IFieldMenuConfig, IFilterMenuFormProps } from './types'\r\n\r\n/** Props for the `FormFieldBoolean` component returned by `createFormFieldBoolean`. Extends the base filter-menu form props. */\r\nexport interface IFormFieldBooleanProps<T> extends IFilterMenuFormProps<T> {\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/** Parameters passed to `createFormFieldBoolean` to configure the generated component. */\r\nexport interface IFormFieldBooleanParam<T> {\r\n /** Optional configuration for the form field */\r\n config?: IFieldMenuConfig<T>\r\n /** Label for the `true` option. @default \"Yes\" */\r\n trueLabel?: string\r\n /** Label for the `false` option. @default \"No\" */\r\n falseLabel?: string\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/**\r\n * Factory function that creates a `FormFieldBoolean` filter-menu component.\r\n *\r\n * The generated component renders two radio buttons (true / false) inside a\r\n * popper/menu panel. It is designed for boolean fields such as `is_active`,\r\n * `is_deleted`, `is_verified`, etc. It supports:\r\n * - Configurable labels for the true/false options (e.g. \"Yes / No\", \"Active / Inactive\")\r\n * - Chip viewers showing the currently applied value\r\n * - Single-value mode by default (only one boolean can be applied at a time)\r\n * - A loading overlay that disables interaction while `isLoading` is true\r\n *\r\n * @param params - Static configuration (optional label overrides, optional field config override)\r\n * @returns A React FC ready to be used as a boolean filter-menu field component\r\n */\r\nfunction createFormFieldBoolean<T>(params?: IFormFieldBooleanParam<T>) {\r\n const ChipViewers = createChipViewers<T>()\r\n\r\n const trueLabel = params?.trueLabel ?? 'Yes'\r\n const falseLabel = params?.falseLabel ?? 'No'\r\n\r\n const BOOLEAN_OPTIONS: { value: TFieldValid; label: string }[] = [\r\n { value: true, label: trueLabel },\r\n { value: false, label: falseLabel }\r\n ]\r\n\r\n const FormFieldBoolean: FC<IFormFieldBooleanProps<T>> = (props) => {\r\n /** Merge `props.currentConfig` with `params.config` (if provided).\r\n * Fields from `params.config` override the corresponding keys in `props.currentConfig`.\r\n * Any keys not present in `params.config` are preserved from `props.currentConfig`.\r\n */\r\n // singleValue:true is the boolean default — ensures replaceFilter is used instead of upsertManyFilter\r\n const mergedConfig = useMemo(\r\n () => Object.assign({}, { singleValue: true }, props.currentConfig, params?.config),\r\n [params?.config, props.currentConfig]\r\n )\r\n\r\n const { value = { values: [], logic: DEFAULT_LOGIC } } = props\r\n // Initialize from existing applied value so the radio reflects current state when reopening\r\n const initialSelected = value.values.length > 0 ? String(value.values[0]) : ''\r\n // Radio value is stored as string in DOM; convert back to boolean on submit\r\n const [selectedValue, setSelectedValue] = useState<string>(initialSelected)\r\n\r\n const label = mergedConfig?.label ?? mergedConfig.field.toString()\r\n\r\n const hasDataChange = selectedValue !== ''\r\n const isApplyDisabled = !hasDataChange\r\n\r\n const handleSubmit = (newValue: TFieldValue) => {\r\n props.onSubmit(mergedConfig.field, newValue, mergedConfig)\r\n }\r\n\r\n const handleSubmitForm = (event: React.FormEvent<HTMLFormElement>) => {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n\r\n if (!hasDataChange) return\r\n\r\n // Convert string back to actual boolean\r\n const boolValue = selectedValue === 'true'\r\n const newValue: TFieldValue = { values: [boolValue as TFieldValid], logic: DEFAULT_LOGIC }\r\n handleSubmit(newValue)\r\n setSelectedValue('')\r\n }\r\n\r\n const filterViewerValue = useMemo<TChipViewerGroup<T>>(() => {\r\n const items = Array.isArray(value.values) ? value.values : [value.values]\r\n return {\r\n field: mergedConfig.field,\r\n items: items.map((v) => ({\r\n value: v,\r\n label: v === true ? trueLabel : v === false ? falseLabel : String(v)\r\n }))\r\n }\r\n }, [mergedConfig.field, value])\r\n\r\n const handleClearAll = () => {\r\n props.onRemoveField?.(mergedConfig.field, mergedConfig)\r\n }\r\n\r\n const renderTop = useMemo(() => {\r\n const topContent = params?.top || props.top\r\n if (topContent) return <Box sx={{ mb: 1 }}>{topContent}</Box>\r\n return null\r\n }, [params?.top, props.top])\r\n\r\n // Boolean is always single-value — show badge instead of logic toggle\r\n const renderAfterTitle = () => <ChipDark sx={{ ml: 1.5 }} size='small' label='Single value' />\r\n\r\n const rootClasses: string[] = []\r\n if (props.isLoading) rootClasses.push('disabled')\r\n\r\n return (\r\n <RootStyled className={rootClasses.join(' ')} noValidate onSubmit={handleSubmitForm}>\r\n <PopperContent\r\n title={`Filter by ${label}`}\r\n onClose={props.onClose}\r\n slots={{\r\n beforeTitle: <ButtonBack size='small' onClick={props.onBack} />,\r\n afterTitle: renderAfterTitle()\r\n }}\r\n >\r\n <PopperBody>\r\n {renderTop}\r\n {mergedConfig.description && (\r\n <Typography variant='caption' color='text.secondary' sx={{ mb: 1, display: 'block' }}>\r\n {mergedConfig.description}\r\n </Typography>\r\n )}\r\n <ChipViewers\r\n sx={{ mb: 1, borderBottom: 'none!important' }}\r\n label='Applied'\r\n placement='horizontal'\r\n enableMinimalesticView\r\n value={filterViewerValue}\r\n onRemove={props.onRemove}\r\n />\r\n <RadioGroup name={mergedConfig.field.toString()} value={selectedValue} onChange={(e) => setSelectedValue(e.target.value)}>\r\n {BOOLEAN_OPTIONS.map((option) => (\r\n <FormControlLabel\r\n key={String(option.value)}\r\n value={String(option.value)}\r\n control={<Radio size='small' />}\r\n label={<Typography variant='body2'>{option.label}</Typography>}\r\n />\r\n ))}\r\n </RadioGroup>\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button size='small' color='error' variant='text' disabled={!value.values || value.values.length === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n <Box sx={{ flex: 1 }} />\r\n <Button size='small' color='inherit' variant='text' onClick={props.onClose}>\r\n Cancel\r\n </Button>\r\n <Button size='small' type='submit' color='primary' variant='contained' disabled={isApplyDisabled}>\r\n Apply\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n </RootStyled>\r\n )\r\n }\r\n\r\n return FormFieldBoolean\r\n}\r\n\r\nexport default createFormFieldBoolean\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utilities\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Creates a `labelFormatter` for use in `summaryConfig`.\r\n * Converts boolean values (`true` / `false`) to human-readable labels in the filter summary chips.\r\n *\r\n * @param trueLabel - Label shown for `true`. @default \"Yes\"\r\n * @param falseLabel - Label shown for `false`. @default \"No\"\r\n *\r\n * @example\r\n * ```ts\r\n * createFilterSummary({\r\n * fields: {\r\n * active: { label: 'Active', labelFormatter: formatterBoolean({ trueLabel: 'Active', falseLabel: 'Inactive' }) }\r\n * }\r\n * })\r\n * ```\r\n */\r\nexport function formatterBoolean(param?: { trueLabel?: string; falseLabel?: string }) {\r\n const trueLabel = param?.trueLabel ?? 'Yes'\r\n const falseLabel = param?.falseLabel ?? 'No'\r\n return (value: TFieldValid): string | undefined => {\r\n if (value === true || value === 'true') return trueLabel\r\n if (value === false || value === 'false') return falseLabel\r\n return String(value)\r\n }\r\n}\r\n\r\nconst RootStyled = styled('form')({\r\n position: 'relative',\r\n '&::after': {\r\n content: '\"\"',\r\n display: 'block',\r\n position: 'absolute',\r\n inset: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.12)',\r\n filter: 'blur(2px)',\r\n zIndex: -1,\r\n opacity: 0,\r\n transition: 'opacity 0.3s',\r\n visibility: 'hidden'\r\n },\r\n '&.disabled': {\r\n pointerEvents: 'none',\r\n '&::after': { zIndex: 1, opacity: 1, visibility: 'visible' }\r\n },\r\n [`.${radioGroupClasses.root}`]: { gap: 0 }\r\n})\r\n"],"names":["createFormFieldBoolean","params","_params$trueLabel","_params$falseLabel","ChipViewers","createChipViewers","trueLabel","falseLabel","BOOLEAN_OPTIONS","value","label","props","_mergedConfig$label","mergedConfig","useMemo","Object","assign","singleValue","currentConfig","config","_props$value","values","logic","DEFAULT_LOGIC","initialSelected","length","String","_useState","useState","_useState2","_slicedToArray","selectedValue","setSelectedValue","field","toString","hasDataChange","isApplyDisabled","filterViewerValue","items","Array","isArray","map","v","renderTop","topContent","top","_jsx","Box","sx","mb","children","rootClasses","isLoading","push","RootStyled","className","join","noValidate","onSubmit","event","preventDefault","stopPropagation","newValue","handleSubmit","_jsxs","PopperContent","title","concat","onClose","slots","beforeTitle","ButtonBack","size","onClick","onBack","afterTitle","ChipDark","ml","PopperBody","description","Typography","variant","color","display","borderBottom","placement","enableMinimalesticView","onRemove","RadioGroup","name","onChange","e","target","option","FormControlLabel","control","Radio","PopperFooter","Button","disabled","_props$onRemoveField","onRemoveField","call","flex","type","formatterBoolean","param","_param$trueLabel","_param$falseLabel","styled","_defineProperty","position","content","inset","backgroundColor","filter","zIndex","opacity","transition","visibility","pointerEvents","radioGroupClasses","root","gap"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{slicedToArray as e,defineProperty as i}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as l,jsxs as n}from"react/jsx-runtime";import{useMemo as o,useState as r,createRef as t}from"react";import{styled as a,Typography as u,ToggleButtonGroup as s,ToggleButton as c,TextField as d,Button as v,Box as p}from"@mui/material";import{createChipViewers as m}from"../components/chip-viewer.js";import{getErrorMessage as f}from"../../form/helpers.js";import{ButtonBack as g,FilterLogicToggle as b}from"../components/ui.units.js";import{PopperContent as h,PopperBody as x,PopperFooter as y}from"../components/popper-custom.js";var C={eq:"=",lt:"<",lte:"≤",gt:">",gte:"≥"},z=["eq","lt","lte","gt","gte"];function j(e,i){return"".concat(e,":").concat(i)}function k(e){if("string"!=typeof e)return null;var i=e.indexOf(":");if(-1===i)return null;var l=e.slice(0,i),n=parseFloat(e.slice(i+1));return!z.includes(l)||isNaN(n)?null:{operator:l,num:n}}function N(e){var i=k(e);return i?"".concat(C[i.operator]," ").concat(i.num):String(e)}function A(a){var k=m();return function(m){var A,S,B,T,O=o(function(){return Object.assign({},m.currentConfig,null==a?void 0:a.config)},[null==a?void 0:a.config,m.currentConfig]),P=t(),R=m.value,q=void 0===R?{values:[],logic:null!==(A=null==O?void 0:O.defaultLogic)&&void 0!==A?A:"or"}:R,w=r(q.logic),I=e(w,2),M=I[0],V=I[1],E=r(null!==(S=null==a?void 0:a.defaultOperator)&&void 0!==S?S:"eq"),H=e(E,2),L=H[0],_=H[1],D=r(""),W=e(D,2),G=W[0],J=W[1],K=null!==(B=null==O?void 0:O.label)&&void 0!==B?B:O.field.toString(),Q=r({}),U=e(Q,2),X=U[0],Y=U[1],Z=function(e){m.onSubmit(O.field,e,O)},$=M!==q.logic,ee=f(X,O.field),ie=o(function(){var e=Array.isArray(q.values)?q.values:[q.values];return{field:O.field,items:e.map(function(e){return{value:e,label:N(e)}})}},[O.field,q]),le=!(""!==G.trim()&&!isNaN(parseFloat(G)))&&!$,ne=[];return m.isLoading&&ne.push("disabled"),l(F,{className:ne.join(" "),noValidate:!0,onSubmit:function(e){var l,n,o;e.preventDefault(),e.stopPropagation();var r=parseFloat(null!==(l=null===(n=P.current)||void 0===n?void 0:n.value)&&void 0!==l?l:"");if(isNaN(r))$&&Z({values:q.values,logic:M});else{var t=i({},O.field,r),a=null===(o=m.validator)||void 0===o?void 0:o.run(t);if(Y(a||{}),!a||0===Object.keys(a).length){var u=j(L,r);Z({values:[u],logic:M}),P.current&&(P.current.blur(),P.current.value=""),J("")}}},children:n(h,{title:"Filter by ".concat(K),onClose:m.onClose,slots:{beforeTitle:l(g,{size:"small",onClick:m.onBack}),afterTitle:O.singleValue?null:l(b,{sx:{ml:1},value:M,onChange:function(e,i){V(i)}})},children:[n(x,{children:[O.description&&l(u,{variant:"caption",color:"text.secondary",sx:{display:"block",mb:1},children:O.description}),l(k,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:ie,onRemove:m.onRemove}),l(s,{exclusive:!0,size:"small",value:L,onChange:function(e,i){i&&_(i)},sx:{mb:1,width:"100%",".MuiToggleButton-root":{flex:1,py:.25,fontSize:"0.8rem"}},children:z.map(function(e){return l(c,{value:e,children:C[e]},e)})}),l(d,{inputRef:P,autoFocus:!0,type:"number",name:O.field.toString(),size:"small",fullWidth:!0,placeholder:"Enter number",error:ee.error,helperText:ee.message,inputProps:{step:null!==(T=null==a?void 0:a.step)&&void 0!==T?T:1,min:null==a?void 0:a.min,max:null==a?void 0:a.max},onChange:function(e){return J(e.target.value)},sx:{".MuiInputBase-root":{minHeight:"42px"}}})]}),n(y,{children:[l(v,{size:"small",color:"error",variant:"text",disabled:!q.values||0===q.values.length,onClick:function(){var e;null===(e=m.onRemoveField)||void 0===e||e.call(m,O.field,O)},children:"Clear All"}),l(p,{sx:{flex:1}}),l(v,{size:"small",color:"inherit",variant:"text",onClick:m.onClose,children:"Cancel"}),l(v,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:le,children:"Apply"})]})]})})}}var F=a("form")({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.2)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}});function S(){return function(e){return N(e)}}export{k as decodeNumberValue,A as default,j as encodeNumberValue,N as formatNumberChipLabel,S as formatterNumber};
1
+ import{slicedToArray as e,defineProperty as i}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as l,jsxs as n}from"react/jsx-runtime";import{useMemo as o,useState as r,createRef as t}from"react";import{styled as a,Typography as u,ToggleButtonGroup as s,ToggleButton as c,TextField as d,Button as v,Box as p}from"@mui/material";import{createChipViewers as m}from"../components/chip-viewer.js";import{getErrorMessage as f}from"../../form/helpers.js";import{ButtonBack as g,FilterLogicToggle as b}from"../components/ui.units.js";import{PopperContent as h,PopperBody as x,PopperFooter as y}from"../components/popper-custom.js";import{DEFAULT_LOGIC as C}from"../helpers.js";var j={eq:"=",lt:"<",lte:"≤",gt:">",gte:"≥"},z=["eq","lt","lte","gt","gte"];function k(e,i){return"".concat(e,":").concat(i)}function N(e){if("string"!=typeof e)return null;var i=e.indexOf(":");if(-1===i)return null;var l=e.slice(0,i),n=parseFloat(e.slice(i+1));return!z.includes(l)||isNaN(n)?null:{operator:l,num:n}}function A(e){var i=N(e);return i?"".concat(j[i.operator]," ").concat(i.num):String(e)}function F(a){var N=m();return function(m){var F,B,T,O,P,R,q=o(function(){return Object.assign({},m.currentConfig,null==a?void 0:a.config)},[null==a?void 0:a.config,m.currentConfig]),w=t(),I=null!==(F=null==q?void 0:q.defaultLogic)&&void 0!==F?F:C,M=m.value,V=void 0===M?{values:[]}:M,E=r(null!==(B=V.logic)&&void 0!==B?B:I),H=e(E,2),L=H[0],_=H[1],D=r(null!==(T=null==a?void 0:a.defaultOperator)&&void 0!==T?T:"eq"),W=e(D,2),G=W[0],J=W[1],K=r(""),Q=e(K,2),U=Q[0],X=Q[1],Y=null!==(O=null==q?void 0:q.label)&&void 0!==O?O:q.field.toString(),Z=r({}),$=e(Z,2),ee=$[0],ie=$[1],le=function(e){m.onSubmit(q.field,e,q)},ne=L!==(null!==(P=V.logic)&&void 0!==P?P:I),oe=f(ee,q.field),re=o(function(){var e=Array.isArray(V.values)?V.values:[V.values];return{field:q.field,items:e.map(function(e){return{value:e,label:A(e)}})}},[q.field,V]),te=!(""!==U.trim()&&!isNaN(parseFloat(U)))&&!ne,ae=[];return m.isLoading&&ae.push("disabled"),l(S,{className:ae.join(" "),noValidate:!0,onSubmit:function(e){var l,n,o;e.preventDefault(),e.stopPropagation();var r=parseFloat(null!==(l=null===(n=w.current)||void 0===n?void 0:n.value)&&void 0!==l?l:"");if(isNaN(r))ne&&le({values:V.values,logic:L});else{var t=i({},q.field,r),a=null===(o=m.validator)||void 0===o?void 0:o.run(t);if(ie(a||{}),!a||0===Object.keys(a).length){var u=k(G,r);le({values:[u],logic:L}),w.current&&(w.current.blur(),w.current.value=""),X("")}}},children:n(h,{title:"Filter by ".concat(Y),onClose:m.onClose,slots:{beforeTitle:l(g,{size:"small",onClick:m.onBack}),afterTitle:q.singleValue?null:l(b,{sx:{ml:1},value:L,onChange:function(e,i){_(i)}})},children:[n(x,{children:[q.description&&l(u,{variant:"caption",color:"text.secondary",sx:{display:"block",mb:1},children:q.description}),l(N,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:re,onRemove:m.onRemove}),l(s,{exclusive:!0,size:"small",value:G,onChange:function(e,i){i&&J(i)},sx:{mb:1,width:"100%",".MuiToggleButton-root":{flex:1,py:.25,fontSize:"0.8rem"}},children:z.map(function(e){return l(c,{value:e,children:j[e]},e)})}),l(d,{inputRef:w,autoFocus:!0,type:"number",name:q.field.toString(),size:"small",fullWidth:!0,placeholder:"Enter number",error:oe.error,helperText:oe.message,inputProps:{step:null!==(R=null==a?void 0:a.step)&&void 0!==R?R:1,min:null==a?void 0:a.min,max:null==a?void 0:a.max},onChange:function(e){return X(e.target.value)},sx:{".MuiInputBase-root":{minHeight:"42px"}}})]}),n(y,{children:[l(v,{size:"small",color:"error",variant:"text",disabled:!V.values||0===V.values.length,onClick:function(){var e;null===(e=m.onRemoveField)||void 0===e||e.call(m,q.field,q)},children:"Clear All"}),l(p,{sx:{flex:1}}),l(v,{size:"small",color:"inherit",variant:"text",onClick:m.onClose,children:"Cancel"}),l(v,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:te,children:"Apply"})]})]})})}}var S=a("form")({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.2)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}});function B(){return function(e){return A(e)}}export{N as decodeNumberValue,F as default,k as encodeNumberValue,A as formatNumberChipLabel,B as formatterNumber};
2
2
  //# sourceMappingURL=create-form-field-number.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-form-field-number.js","sources":["../../../../src/filter-bar/menu/create-form-field-number.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { createRef, useMemo, useState } from 'react'\r\nimport { Box, Button, styled, TextField, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material'\r\nimport { createChipViewers } from '../components/chip-viewer'\r\nimport { getErrorMessage } from '../../form/helpers'\r\nimport { ButtonBack, FilterLogicToggle } from '../components/ui.units'\r\nimport { PopperBody, PopperContent, PopperFooter } from '../components/popper-custom'\r\n// types\r\nimport type { FC } from 'react'\r\nimport type { IPartialError } from '../../form/validator'\r\nimport type { TChipViewerGroup } from '../components/chip-viewer'\r\nimport type { IFieldMenuConfig, IFilterMenuFormProps } from './types'\r\nimport type { TFieldModelValid, TFieldValid, TFieldValue, TLogic, TNumberOperator } from '../types'\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\nconst OPERATOR_SYMBOLS: Record<TNumberOperator, string> = {\r\n eq: '=',\r\n lt: '<',\r\n lte: '≤',\r\n gt: '>',\r\n gte: '≥'\r\n}\r\n\r\nconst OPERATORS: TNumberOperator[] = ['eq', 'lt', 'lte', 'gt', 'gte']\r\n\r\n// ---------------------------------------------------------------------------\r\n// Encode / decode helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encodes operator + number into a single string stored in `values[]`. e.g. `\"gt:18\"` */\r\nexport function encodeNumberValue(operator: TNumberOperator, num: number): string {\r\n return `${operator}:${num}`\r\n}\r\n\r\n/** Decodes an encoded number value back into its parts. Returns `null` if invalid. */\r\nexport function decodeNumberValue(encoded: TFieldValid): { operator: TNumberOperator; num: number } | null {\r\n if (typeof encoded !== 'string') return null\r\n const colonIdx = encoded.indexOf(':')\r\n if (colonIdx === -1) return null\r\n const op = encoded.slice(0, colonIdx) as TNumberOperator\r\n const num = parseFloat(encoded.slice(colonIdx + 1))\r\n if (!OPERATORS.includes(op) || isNaN(num)) return null\r\n return { operator: op, num }\r\n}\r\n\r\n/** Returns a human-readable chip label for an encoded number value, e.g. `\"> 18\"`. */\r\nexport function formatNumberChipLabel(encoded: TFieldValid): string {\r\n const decoded = decodeNumberValue(encoded)\r\n if (!decoded) return String(encoded)\r\n return `${OPERATOR_SYMBOLS[decoded.operator]} ${decoded.num}`\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public interfaces\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Props for the `FormFieldNumber` component returned by `createFormFieldNumber`. Extends the base filter-menu form props. */\r\nexport interface IFormFieldNumberProps<T> extends IFilterMenuFormProps<T> {}\r\n\r\n/** Parameters passed to `createFormFieldNumber` to configure the generated component. */\r\nexport interface IFormFieldNumberParam<T> {\r\n /** Optional configuration for the form field */\r\n config?: IFieldMenuConfig<T>\r\n /** Default operator shown when the menu first opens. @default 'eq' */\r\n defaultOperator?: TNumberOperator\r\n /** Step for the number input. @default 1 */\r\n step?: number\r\n /** Min allowed value */\r\n min?: number\r\n /** Max allowed value */\r\n max?: number\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Factory function that creates a `FormFieldNumber` filter-menu component.\r\n *\r\n * The generated component renders a number input with a comparison-operator\r\n * toggle (`=`, `<`, `≤`, `>`, `≥`) inside a popper/menu panel. It supports:\r\n * - OR / AND logic toggle when more than one value is applied\r\n * - Chip viewers showing the currently applied values with operator labels\r\n * - Auto-focus and input reset after each successful submission\r\n * - Built-in validation via an optional `validator` prop\r\n * - A loading overlay that disables interaction while `isLoading` is true\r\n *\r\n * Each submitted value is encoded as `\"<operator>:<number>\"` (e.g. `\"gt:18\"`)\r\n * and stored in `TFieldValue.values[]`. Use `decodeNumberValue` / `formatNumberChipLabel`\r\n * to decode them when building query logic.\r\n *\r\n * @param params - Static configuration (optional field config override, default operator, step, min, max)\r\n * @returns A React FC ready to be used as a number filter-menu field component\r\n */\r\nfunction createFormFieldNumber<T>(params?: IFormFieldNumberParam<T>) {\r\n const ChipViewers = createChipViewers<T>()\r\n\r\n const FormFieldNumber: FC<IFormFieldNumberProps<T>> = (props) => {\r\n const mergedConfig = useMemo(() => Object.assign({}, props.currentConfig, params?.config), [params?.config, props.currentConfig])\r\n\r\n const refInput = createRef<HTMLInputElement>()\r\n const { value = { values: [], logic: mergedConfig?.defaultLogic ?? 'or' } } = props\r\n const [filterLogic, setFilterLogic] = useState<TLogic>(value.logic!)\r\n const [operator, setOperator] = useState<TNumberOperator>(params?.defaultOperator ?? 'eq')\r\n const [inputValue, setInputValue] = useState('')\r\n\r\n const label = mergedConfig?.label ?? mergedConfig.field.toString()\r\n\r\n const [errorData, setErrorData] = useState<IPartialError<TFieldModelValid<T>>>({})\r\n\r\n const handleSubmit = (newValue: TFieldValue) => {\r\n props.onSubmit(mergedConfig.field, newValue, mergedConfig)\r\n }\r\n\r\n const hasLogicChange = filterLogic !== value.logic\r\n\r\n const handleSubmitForm = (event: React.FormEvent<HTMLFormElement>) => {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n\r\n const rawNum = parseFloat(refInput.current?.value ?? '')\r\n\r\n // Submit logic change only (no new value)\r\n if (isNaN(rawNum)) {\r\n if (hasLogicChange) {\r\n handleSubmit({ values: value.values, logic: filterLogic })\r\n }\r\n return\r\n }\r\n\r\n const obj = { [mergedConfig.field]: rawNum } as Partial<TFieldModelValid<T>>\r\n const validationError = props.validator?.run(obj) as IPartialError<TFieldModelValid<T>>\r\n\r\n setErrorData(validationError || {})\r\n\r\n if (!validationError || Object.keys(validationError).length === 0) {\r\n const encoded = encodeNumberValue(operator, rawNum)\r\n const newValue: TFieldValue = { values: [encoded], logic: filterLogic }\r\n handleSubmit(newValue)\r\n\r\n if (refInput.current) {\r\n refInput.current.blur()\r\n refInput.current.value = ''\r\n }\r\n setInputValue('')\r\n }\r\n }\r\n\r\n const error = getErrorMessage(errorData, mergedConfig.field)\r\n\r\n const filterViewerValue = useMemo<TChipViewerGroup<T>>(() => {\r\n const items = Array.isArray(value.values) ? value.values : [value.values]\r\n return {\r\n field: mergedConfig.field,\r\n items: items.map((v) => ({ value: v, label: formatNumberChipLabel(v) }))\r\n }\r\n }, [mergedConfig.field, value])\r\n\r\n const handleChangeLogic = (newLogic: TLogic) => {\r\n setFilterLogic(newLogic)\r\n }\r\n\r\n const hasValidInput = inputValue.trim() !== '' && !isNaN(parseFloat(inputValue))\r\n const isApplyDisabled = !hasValidInput && !hasLogicChange\r\n\r\n const handleClearAll = () => {\r\n props.onRemoveField?.(mergedConfig.field, mergedConfig)\r\n }\r\n\r\n const renderAfterTitle = () => {\r\n if (mergedConfig.singleValue) return null\r\n return <FilterLogicToggle sx={{ ml: 1 }} value={filterLogic} onChange={(_, nVal) => handleChangeLogic(nVal)} />\r\n }\r\n\r\n const rootClasses: string[] = []\r\n if (props.isLoading) rootClasses.push('disabled')\r\n\r\n return (\r\n <RootStyled className={rootClasses.join(' ')} noValidate onSubmit={handleSubmitForm}>\r\n <PopperContent\r\n title={`Filter by ${label}`}\r\n onClose={props.onClose}\r\n slots={{\r\n beforeTitle: <ButtonBack size='small' onClick={props.onBack} />,\r\n afterTitle: renderAfterTitle()\r\n }}\r\n >\r\n <PopperBody>\r\n {mergedConfig.description && (\r\n <Typography variant='caption' color='text.secondary' sx={{ display: 'block', mb: 1 }}>\r\n {mergedConfig.description}\r\n </Typography>\r\n )}\r\n <ChipViewers\r\n sx={{ mb: 1, borderBottom: 'none!important' }}\r\n label='Applied'\r\n placement='horizontal'\r\n enableMinimalesticView\r\n value={filterViewerValue}\r\n onRemove={props.onRemove}\r\n />\r\n <ToggleButtonGroup\r\n exclusive\r\n size='small'\r\n value={operator}\r\n onChange={(_, val) => {\r\n if (val) setOperator(val)\r\n }}\r\n sx={{ mb: 1, width: '100%', '.MuiToggleButton-root': { flex: 1, py: 0.25, fontSize: '0.8rem' } }}\r\n >\r\n {OPERATORS.map((op) => (\r\n <ToggleButton key={op} value={op}>\r\n {OPERATOR_SYMBOLS[op]}\r\n </ToggleButton>\r\n ))}\r\n </ToggleButtonGroup>\r\n <TextField\r\n inputRef={refInput}\r\n autoFocus\r\n type='number'\r\n name={mergedConfig.field.toString()}\r\n size='small'\r\n fullWidth\r\n placeholder='Enter number'\r\n error={error.error}\r\n helperText={error.message}\r\n inputProps={{ step: params?.step ?? 1, min: params?.min, max: params?.max }}\r\n onChange={(e) => setInputValue(e.target.value)}\r\n sx={{ '.MuiInputBase-root': { minHeight: '42px' } }}\r\n />\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button size='small' color='error' variant='text' disabled={!value.values || value.values.length === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n <Box sx={{ flex: 1 }} />\r\n <Button size='small' color='inherit' variant='text' onClick={props.onClose}>\r\n Cancel\r\n </Button>\r\n <Button size='small' type='submit' color='primary' variant='contained' disabled={isApplyDisabled}>\r\n Apply\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n </RootStyled>\r\n )\r\n }\r\n\r\n return FormFieldNumber\r\n}\r\n\r\nexport default createFormFieldNumber\r\n\r\nconst RootStyled = styled('form')({\r\n position: 'relative',\r\n '&::after': {\r\n content: '\"\"',\r\n display: 'block',\r\n position: 'absolute',\r\n inset: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.2)',\r\n filter: 'blur(2px)',\r\n zIndex: -1,\r\n opacity: 0,\r\n transition: 'opacity 0.3s',\r\n visibility: 'hidden'\r\n },\r\n '&.disabled': {\r\n pointerEvents: 'none',\r\n '&::after': {\r\n zIndex: 1,\r\n opacity: 1,\r\n visibility: 'visible'\r\n }\r\n }\r\n})\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utilities\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Creates a labelFormatter for use in summaryConfig.\r\n * Formats encoded number values (e.g. `\"gt:18\"`) to a human-readable label (e.g. `\"> 18\"`).\r\n *\r\n * @example\r\n * summaryConfig: {\r\n * labelFormatter: { age: formatterNumber() }\r\n * }\r\n */\r\nexport function formatterNumber() {\r\n return (value: TFieldValid): string | undefined => {\r\n return formatNumberChipLabel(value)\r\n }\r\n}\r\n"],"names":["OPERATOR_SYMBOLS","eq","lt","lte","gt","gte","OPERATORS","encodeNumberValue","operator","num","concat","decodeNumberValue","encoded","colonIdx","indexOf","op","slice","parseFloat","includes","isNaN","formatNumberChipLabel","decoded","String","createFormFieldNumber","params","ChipViewers","createChipViewers","props","_mergedConfig$default","_params$defaultOperat","_mergedConfig$label","_params$step","mergedConfig","useMemo","Object","assign","currentConfig","config","refInput","createRef","_props$value","value","values","logic","defaultLogic","_useState","useState","_useState2","_slicedToArray","filterLogic","setFilterLogic","_useState3","defaultOperator","_useState4","setOperator","_useState5","_useState6","inputValue","setInputValue","label","field","toString","_useState7","_useState8","errorData","setErrorData","handleSubmit","newValue","onSubmit","hasLogicChange","error","getErrorMessage","filterViewerValue","items","Array","isArray","map","v","isApplyDisabled","trim","rootClasses","isLoading","push","_jsx","RootStyled","className","join","noValidate","event","_refInput$current$val","_refInput$current","_props$validator","preventDefault","stopPropagation","rawNum","current","obj","_defineProperty","validationError","validator","run","keys","length","blur","children","_jsxs","PopperContent","title","onClose","slots","beforeTitle","ButtonBack","size","onClick","onBack","afterTitle","singleValue","FilterLogicToggle","sx","ml","onChange","_","nVal","PopperBody","description","Typography","variant","color","display","mb","borderBottom","placement","enableMinimalesticView","onRemove","ToggleButtonGroup","exclusive","val","width","flex","py","fontSize","ToggleButton","TextField","inputRef","autoFocus","type","name","fullWidth","placeholder","helperText","message","inputProps","step","min","max","e","target","minHeight","PopperFooter","Button","disabled","_props$onRemoveField","onRemoveField","call","Box","styled","position","content","inset","backgroundColor","filter","zIndex","opacity","transition","visibility","pointerEvents","formatterNumber"],"mappings":"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"}
1
+ {"version":3,"file":"create-form-field-number.js","sources":["../../../../src/filter-bar/menu/create-form-field-number.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { createRef, useMemo, useState } from 'react'\r\nimport { Box, Button, styled, TextField, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material'\r\nimport { createChipViewers } from '../components/chip-viewer'\r\nimport { getErrorMessage } from '../../form/helpers'\r\nimport { ButtonBack, FilterLogicToggle } from '../components/ui.units'\r\nimport { PopperBody, PopperContent, PopperFooter } from '../components/popper-custom'\r\nimport { DEFAULT_LOGIC } from '../helpers'\r\n// types\r\nimport type { FC } from 'react'\r\nimport type { IPartialError } from '../../form/validator'\r\nimport type { TChipViewerGroup } from '../components/chip-viewer'\r\nimport type { IFieldMenuConfig, IFilterMenuFormProps } from './types'\r\nimport type { TFieldModelValid, TFieldValid, TFieldValue, TLogic, TNumberOperator } from '../types'\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\nconst OPERATOR_SYMBOLS: Record<TNumberOperator, string> = {\r\n eq: '=',\r\n lt: '<',\r\n lte: '≤',\r\n gt: '>',\r\n gte: '≥'\r\n}\r\n\r\nconst OPERATORS: TNumberOperator[] = ['eq', 'lt', 'lte', 'gt', 'gte']\r\n\r\n// ---------------------------------------------------------------------------\r\n// Encode / decode helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Encodes operator + number into a single string stored in `values[]`. e.g. `\"gt:18\"` */\r\nexport function encodeNumberValue(operator: TNumberOperator, num: number): string {\r\n return `${operator}:${num}`\r\n}\r\n\r\n/** Decodes an encoded number value back into its parts. Returns `null` if invalid. */\r\nexport function decodeNumberValue(encoded: TFieldValid): { operator: TNumberOperator; num: number } | null {\r\n if (typeof encoded !== 'string') return null\r\n const colonIdx = encoded.indexOf(':')\r\n if (colonIdx === -1) return null\r\n const op = encoded.slice(0, colonIdx) as TNumberOperator\r\n const num = parseFloat(encoded.slice(colonIdx + 1))\r\n if (!OPERATORS.includes(op) || isNaN(num)) return null\r\n return { operator: op, num }\r\n}\r\n\r\n/** Returns a human-readable chip label for an encoded number value, e.g. `\"> 18\"`. */\r\nexport function formatNumberChipLabel(encoded: TFieldValid): string {\r\n const decoded = decodeNumberValue(encoded)\r\n if (!decoded) return String(encoded)\r\n return `${OPERATOR_SYMBOLS[decoded.operator]} ${decoded.num}`\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public interfaces\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Props for the `FormFieldNumber` component returned by `createFormFieldNumber`. Extends the base filter-menu form props. */\r\nexport interface IFormFieldNumberProps<T> extends IFilterMenuFormProps<T> {}\r\n\r\n/** Parameters passed to `createFormFieldNumber` to configure the generated component. */\r\nexport interface IFormFieldNumberParam<T> {\r\n /** Optional configuration for the form field */\r\n config?: IFieldMenuConfig<T>\r\n /** Default operator shown when the menu first opens. @default 'eq' */\r\n defaultOperator?: TNumberOperator\r\n /** Step for the number input. @default 1 */\r\n step?: number\r\n /** Min allowed value */\r\n min?: number\r\n /** Max allowed value */\r\n max?: number\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Factory function that creates a `FormFieldNumber` filter-menu component.\r\n *\r\n * The generated component renders a number input with a comparison-operator\r\n * toggle (`=`, `<`, `≤`, `>`, `≥`) inside a popper/menu panel. It supports:\r\n * - OR / AND logic toggle when more than one value is applied\r\n * - Chip viewers showing the currently applied values with operator labels\r\n * - Auto-focus and input reset after each successful submission\r\n * - Built-in validation via an optional `validator` prop\r\n * - A loading overlay that disables interaction while `isLoading` is true\r\n *\r\n * Each submitted value is encoded as `\"<operator>:<number>\"` (e.g. `\"gt:18\"`)\r\n * and stored in `TFieldValue.values[]`. Use `decodeNumberValue` / `formatNumberChipLabel`\r\n * to decode them when building query logic.\r\n *\r\n * @param params - Static configuration (optional field config override, default operator, step, min, max)\r\n * @returns A React FC ready to be used as a number filter-menu field component\r\n */\r\nfunction createFormFieldNumber<T>(params?: IFormFieldNumberParam<T>) {\r\n const ChipViewers = createChipViewers<T>()\r\n\r\n const FormFieldNumber: FC<IFormFieldNumberProps<T>> = (props) => {\r\n const mergedConfig = useMemo(() => Object.assign({}, props.currentConfig, params?.config), [params?.config, props.currentConfig])\r\n\r\n const refInput = createRef<HTMLInputElement>()\r\n const defaultLogic: TLogic = mergedConfig?.defaultLogic ?? DEFAULT_LOGIC\r\n const { value = { values: [] } } = props\r\n const [filterLogic, setFilterLogic] = useState<TLogic>(value.logic ?? defaultLogic)\r\n const [operator, setOperator] = useState<TNumberOperator>(params?.defaultOperator ?? 'eq')\r\n const [inputValue, setInputValue] = useState('')\r\n\r\n const label = mergedConfig?.label ?? mergedConfig.field.toString()\r\n\r\n const [errorData, setErrorData] = useState<IPartialError<TFieldModelValid<T>>>({})\r\n\r\n const handleSubmit = (newValue: TFieldValue) => {\r\n props.onSubmit(mergedConfig.field, newValue, mergedConfig)\r\n }\r\n\r\n const hasLogicChange = filterLogic !== (value.logic ?? defaultLogic)\r\n\r\n const handleSubmitForm = (event: React.FormEvent<HTMLFormElement>) => {\r\n event.preventDefault()\r\n event.stopPropagation()\r\n\r\n const rawNum = parseFloat(refInput.current?.value ?? '')\r\n\r\n // Submit logic change only (no new value)\r\n if (isNaN(rawNum)) {\r\n if (hasLogicChange) {\r\n handleSubmit({ values: value.values, logic: filterLogic })\r\n }\r\n return\r\n }\r\n\r\n const obj = { [mergedConfig.field]: rawNum } as Partial<TFieldModelValid<T>>\r\n const validationError = props.validator?.run(obj) as IPartialError<TFieldModelValid<T>>\r\n\r\n setErrorData(validationError || {})\r\n\r\n if (!validationError || Object.keys(validationError).length === 0) {\r\n const encoded = encodeNumberValue(operator, rawNum)\r\n const newValue: TFieldValue = { values: [encoded], logic: filterLogic }\r\n handleSubmit(newValue)\r\n\r\n if (refInput.current) {\r\n refInput.current.blur()\r\n refInput.current.value = ''\r\n }\r\n setInputValue('')\r\n }\r\n }\r\n\r\n const error = getErrorMessage(errorData, mergedConfig.field)\r\n\r\n const filterViewerValue = useMemo<TChipViewerGroup<T>>(() => {\r\n const items = Array.isArray(value.values) ? value.values : [value.values]\r\n return {\r\n field: mergedConfig.field,\r\n items: items.map((v) => ({ value: v, label: formatNumberChipLabel(v) }))\r\n }\r\n }, [mergedConfig.field, value])\r\n\r\n const handleChangeLogic = (newLogic: TLogic) => {\r\n setFilterLogic(newLogic)\r\n }\r\n\r\n const hasValidInput = inputValue.trim() !== '' && !isNaN(parseFloat(inputValue))\r\n const isApplyDisabled = !hasValidInput && !hasLogicChange\r\n\r\n const handleClearAll = () => {\r\n props.onRemoveField?.(mergedConfig.field, mergedConfig)\r\n }\r\n\r\n const renderAfterTitle = () => {\r\n if (mergedConfig.singleValue) return null\r\n return <FilterLogicToggle sx={{ ml: 1 }} value={filterLogic} onChange={(_, nVal) => handleChangeLogic(nVal)} />\r\n }\r\n\r\n const rootClasses: string[] = []\r\n if (props.isLoading) rootClasses.push('disabled')\r\n\r\n return (\r\n <RootStyled className={rootClasses.join(' ')} noValidate onSubmit={handleSubmitForm}>\r\n <PopperContent\r\n title={`Filter by ${label}`}\r\n onClose={props.onClose}\r\n slots={{\r\n beforeTitle: <ButtonBack size='small' onClick={props.onBack} />,\r\n afterTitle: renderAfterTitle()\r\n }}\r\n >\r\n <PopperBody>\r\n {mergedConfig.description && (\r\n <Typography variant='caption' color='text.secondary' sx={{ display: 'block', mb: 1 }}>\r\n {mergedConfig.description}\r\n </Typography>\r\n )}\r\n <ChipViewers\r\n sx={{ mb: 1, borderBottom: 'none!important' }}\r\n label='Applied'\r\n placement='horizontal'\r\n enableMinimalesticView\r\n value={filterViewerValue}\r\n onRemove={props.onRemove}\r\n />\r\n <ToggleButtonGroup\r\n exclusive\r\n size='small'\r\n value={operator}\r\n onChange={(_, val) => {\r\n if (val) setOperator(val)\r\n }}\r\n sx={{ mb: 1, width: '100%', '.MuiToggleButton-root': { flex: 1, py: 0.25, fontSize: '0.8rem' } }}\r\n >\r\n {OPERATORS.map((op) => (\r\n <ToggleButton key={op} value={op}>\r\n {OPERATOR_SYMBOLS[op]}\r\n </ToggleButton>\r\n ))}\r\n </ToggleButtonGroup>\r\n <TextField\r\n inputRef={refInput}\r\n autoFocus\r\n type='number'\r\n name={mergedConfig.field.toString()}\r\n size='small'\r\n fullWidth\r\n placeholder='Enter number'\r\n error={error.error}\r\n helperText={error.message}\r\n inputProps={{ step: params?.step ?? 1, min: params?.min, max: params?.max }}\r\n onChange={(e) => setInputValue(e.target.value)}\r\n sx={{ '.MuiInputBase-root': { minHeight: '42px' } }}\r\n />\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button size='small' color='error' variant='text' disabled={!value.values || value.values.length === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n <Box sx={{ flex: 1 }} />\r\n <Button size='small' color='inherit' variant='text' onClick={props.onClose}>\r\n Cancel\r\n </Button>\r\n <Button size='small' type='submit' color='primary' variant='contained' disabled={isApplyDisabled}>\r\n Apply\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n </RootStyled>\r\n )\r\n }\r\n\r\n return FormFieldNumber\r\n}\r\n\r\nexport default createFormFieldNumber\r\n\r\nconst RootStyled = styled('form')({\r\n position: 'relative',\r\n '&::after': {\r\n content: '\"\"',\r\n display: 'block',\r\n position: 'absolute',\r\n inset: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.2)',\r\n filter: 'blur(2px)',\r\n zIndex: -1,\r\n opacity: 0,\r\n transition: 'opacity 0.3s',\r\n visibility: 'hidden'\r\n },\r\n '&.disabled': {\r\n pointerEvents: 'none',\r\n '&::after': {\r\n zIndex: 1,\r\n opacity: 1,\r\n visibility: 'visible'\r\n }\r\n }\r\n})\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utilities\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Creates a labelFormatter for use in summaryConfig.\r\n * Formats encoded number values (e.g. `\"gt:18\"`) to a human-readable label (e.g. `\"> 18\"`).\r\n *\r\n * @example\r\n * summaryConfig: {\r\n * labelFormatter: { age: formatterNumber() }\r\n * }\r\n */\r\nexport function formatterNumber() {\r\n return (value: TFieldValid): string | undefined => {\r\n return formatNumberChipLabel(value)\r\n }\r\n}\r\n"],"names":["OPERATOR_SYMBOLS","eq","lt","lte","gt","gte","OPERATORS","encodeNumberValue","operator","num","concat","decodeNumberValue","encoded","colonIdx","indexOf","op","slice","parseFloat","includes","isNaN","formatNumberChipLabel","decoded","String","createFormFieldNumber","params","ChipViewers","createChipViewers","props","_mergedConfig$default","_value$logic","_params$defaultOperat","_mergedConfig$label","_value$logic2","_params$step","mergedConfig","useMemo","Object","assign","currentConfig","config","refInput","createRef","defaultLogic","DEFAULT_LOGIC","_props$value","value","values","_useState","useState","logic","_useState2","_slicedToArray","filterLogic","setFilterLogic","_useState3","defaultOperator","_useState4","setOperator","_useState5","_useState6","inputValue","setInputValue","label","field","toString","_useState7","_useState8","errorData","setErrorData","handleSubmit","newValue","onSubmit","hasLogicChange","error","getErrorMessage","filterViewerValue","items","Array","isArray","map","v","isApplyDisabled","trim","rootClasses","isLoading","push","_jsx","RootStyled","className","join","noValidate","event","_refInput$current$val","_refInput$current","_props$validator","preventDefault","stopPropagation","rawNum","current","obj","_defineProperty","validationError","validator","run","keys","length","blur","children","_jsxs","PopperContent","title","onClose","slots","beforeTitle","ButtonBack","size","onClick","onBack","afterTitle","singleValue","FilterLogicToggle","sx","ml","onChange","_","nVal","PopperBody","description","Typography","variant","color","display","mb","borderBottom","placement","enableMinimalesticView","onRemove","ToggleButtonGroup","exclusive","val","width","flex","py","fontSize","ToggleButton","TextField","inputRef","autoFocus","type","name","fullWidth","placeholder","helperText","message","inputProps","step","min","max","e","target","minHeight","PopperFooter","Button","disabled","_props$onRemoveField","onRemoveField","call","Box","styled","position","content","inset","backgroundColor","filter","zIndex","opacity","transition","visibility","pointerEvents","formatterNumber"],"mappings":"4qBAqBA,IAAMA,EAAoD,CACxDC,GAAI,IACJC,GAAI,IACJC,IAAK,IACLC,GAAI,IACJC,IAAK,KAGDC,EAA+B,CAAC,KAAM,KAAM,MAAO,KAAM,OAO/C,SAAAC,EAAkBC,EAA2BC,GAC3D,MAAA,GAAAC,OAAUF,EAAQE,KAAAA,OAAID,EACxB,CAGM,SAAUE,EAAkBC,GAChC,GAAuB,iBAAZA,EAAsB,OAAO,KACxC,IAAMC,EAAWD,EAAQE,QAAQ,KACjC,IAAmB,IAAfD,EAAiB,OAAO,KAC5B,IAAME,EAAKH,EAAQI,MAAM,EAAGH,GACtBJ,EAAMQ,WAAWL,EAAQI,MAAMH,EAAW,IAChD,OAAKP,EAAUY,SAASH,IAAOI,MAAMV,GAAa,KAC3C,CAAED,SAAUO,EAAIN,IAAAA,EACzB,CAGM,SAAUW,EAAsBR,GACpC,IAAMS,EAAUV,EAAkBC,GAClC,OAAKS,EACL,GAAAX,OAAUV,EAAiBqB,EAAQb,UAASE,KAAAA,OAAIW,EAAQZ,KADnCa,OAAOV,EAE9B,CA6CA,SAASW,EAAyBC,GAChC,IAAMC,EAAcC,IA0JpB,OAxJsD,SAACC,GAAS,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EACxDC,EAAeC,EAAQ,WAAA,OAAMC,OAAOC,OAAO,GAAIV,EAAMW,cAAed,eAAAA,EAAQe,OAAO,EAAE,CAACf,aAAAA,EAAAA,EAAQe,OAAQZ,EAAMW,gBAE5GE,EAAWC,IACXC,EAAiDd,QAArCA,EAAWM,aAAY,EAAZA,EAAcQ,oBAAYd,IAAAA,EAAAA,EAAIe,EAC3DC,EAAmCjB,EAA3BkB,MAAAA,OAAQ,IAAHD,EAAG,CAAEE,OAAQ,IAAIF,EAC9BG,EAAsCC,UAAQnB,EAASgB,EAAMI,aAAK,IAAApB,EAAAA,EAAIa,GAAaQ,EAAAC,EAAAJ,EAAA,GAA5EK,EAAWF,EAAA,GAAEG,EAAcH,EAAA,GAClCI,EAAgCN,EAAiDlB,QAAzCA,EAAkBN,eAAAA,EAAQ+B,2BAAezB,EAAAA,EAAI,MAAK0B,EAAAL,EAAAG,EAAA,GAAnF9C,EAAQgD,EAAA,GAAEC,EAAWD,EAAA,GAC5BE,EAAoCV,EAAS,IAAGW,EAAAR,EAAAO,EAAA,GAAzCE,EAAUD,EAAA,GAAEE,EAAaF,EAAA,GAE1BG,UAAK/B,EAAGG,aAAAA,EAAAA,EAAc4B,aAAK,IAAA/B,EAAAA,EAAIG,EAAa6B,MAAMC,WAExDC,EAAkCjB,EAA6C,IAAGkB,EAAAf,EAAAc,EAAA,GAA3EE,GAASD,EAAA,GAAEE,GAAYF,EAAA,GAExBG,GAAe,SAACC,GACpB3C,EAAM4C,SAASrC,EAAa6B,MAAOO,EAAUpC,EAC9C,EAEKsC,GAAiBpB,aAAWpB,EAAMa,EAAMI,aAAK,IAAAjB,EAAAA,EAAIU,GAkCjD+B,GAAQC,EAAgBP,GAAWjC,EAAa6B,OAEhDY,GAAoBxC,EAA6B,WACrD,IAAMyC,EAAQC,MAAMC,QAAQjC,EAAMC,QAAUD,EAAMC,OAAS,CAACD,EAAMC,QAClE,MAAO,CACLiB,MAAO7B,EAAa6B,MACpBa,MAAOA,EAAMG,IAAI,SAACC,GAAC,MAAM,CAAEnC,MAAOmC,EAAGlB,MAAO1C,EAAsB4D,GAAK,GAE1E,EAAE,CAAC9C,EAAa6B,MAAOlB,IAOlBoC,KADsC,KAAtBrB,EAAWsB,SAAkB/D,MAAMF,WAAW2C,OACzBY,GAWrCW,GAAwB,GAG9B,OAFIxD,EAAMyD,WAAWD,GAAYE,KAAK,YAGpCC,EAACC,EAAU,CAACC,UAAWL,GAAYM,KAAK,KAAMC,cAAWnB,SA9DlC,SAACoB,GAA2C,IAAAC,EAAAC,EAAAC,EACnEH,EAAMI,iBACNJ,EAAMK,kBAEN,IAAMC,EAAShF,WAAkC,QAAxB2E,UAAAC,EAACrD,EAAS0D,eAAO,IAAAL,OAAA,EAAhBA,EAAkBhD,aAAK+C,IAAAA,EAAAA,EAAI,IAGrD,GAAIzE,MAAM8E,GACJzB,IACFH,GAAa,CAAEvB,OAAQD,EAAMC,OAAQG,MAAOG,QAFhD,CAOA,IAAM+C,EAAGC,EAAA,CAAA,EAAMlE,EAAa6B,MAAQkC,GAC9BI,EAAiCP,QAAlBA,EAAGnE,EAAM2E,qBAASR,SAAfA,EAAiBS,IAAIJ,GAI7C,GAFA/B,GAAaiC,GAAmB,KAE3BA,GAA2D,IAAxCjE,OAAOoE,KAAKH,GAAiBI,OAAc,CACjE,IAAM7F,EAAUL,EAAkBC,EAAUyF,GAE5C5B,GAD8B,CAAEvB,OAAQ,CAAClC,GAAUqC,MAAOG,IAGtDZ,EAAS0D,UACX1D,EAAS0D,QAAQQ,OACjBlE,EAAS0D,QAAQrD,MAAQ,IAE3BgB,EAAc,GACf,CAjBA,CAkBF,EAgCoF8C,SACjFC,EAACC,EAAa,CACZC,MAAKpG,aAAAA,OAAeoD,GACpBiD,QAASpF,EAAMoF,QACfC,MAAO,CACLC,YAAa3B,EAAC4B,EAAU,CAACC,KAAK,QAAQC,QAASzF,EAAM0F,SACrDC,WAdFpF,EAAaqF,YAAoB,KAC9BjC,EAACkC,EAAkB,CAAAC,GAAI,CAAEC,GAAI,GAAK7E,MAAOO,EAAauE,SAAU,SAACC,EAAGC,GAZ3ExE,EAYsGwE,EAAK,KAgBvGlB,SAAA,CAAAC,EAACkB,EACE,CAAAnB,SAAA,CAAAzE,EAAa6F,aACZzC,EAAC0C,GAAWC,QAAQ,UAAUC,MAAM,iBAAiBT,GAAI,CAAEU,QAAS,QAASC,GAAI,GAAGzB,SACjFzE,EAAa6F,cAGlBzC,EAAC7D,EAAW,CACVgG,GAAI,CAAEW,GAAI,EAAGC,aAAc,kBAC3BvE,MAAM,UACNwE,UAAU,aACVC,0BACA1F,MAAO8B,GACP6D,SAAU7G,EAAM6G,WAElBlD,EAACmD,EAAiB,CAChBC,WACA,EAAAvB,KAAK,QACLtE,MAAOrC,EACPmH,SAAU,SAACC,EAAGe,GACRA,GAAKlF,EAAYkF,EACtB,EACDlB,GAAI,CAAEW,GAAI,EAAGQ,MAAO,OAAQ,wBAAyB,CAAEC,KAAM,EAAGC,GAAI,IAAMC,SAAU,WAEnFpC,SAAArG,EAAUyE,IAAI,SAAChE,GAAE,OAChBuE,EAAC0D,EAAY,CAAUnG,MAAO9B,EAAE4F,SAC7B3G,EAAiBe,IADDA,EAGpB,KAEHuE,EAAC2D,EAAS,CACRC,SAAU1G,EACV2G,WAAS,EACTC,KAAK,SACLC,KAAMnH,EAAa6B,MAAMC,WACzBmD,KAAK,QACLmC,WACA,EAAAC,YAAY,eACZ9E,MAAOA,GAAMA,MACb+E,WAAY/E,GAAMgF,QAClBC,WAAY,CAAEC,KAAkB1H,QAAdA,EAAET,aAAM,EAANA,EAAQmI,YAAI1H,IAAAA,EAAAA,EAAI,EAAG2H,IAAKpI,aAAAA,EAAAA,EAAQoI,IAAKC,IAAKrI,aAAM,EAANA,EAAQqI,KACtElC,SAAU,SAACmC,GAAC,OAAKjG,EAAciG,EAAEC,OAAOlH,MAAM,EAC9C4E,GAAI,CAAE,qBAAsB,CAAEuC,UAAW,cAG7CpD,EAACqD,EACC,CAAAtD,SAAA,CAAArB,EAAC4E,EAAM,CAAC/C,KAAK,QAAQe,MAAM,QAAQD,QAAQ,OAAOkC,UAAWtH,EAAMC,QAAkC,IAAxBD,EAAMC,OAAO2D,OAAcW,QAnEzF,WAAK,IAAAgD,EACP,QAAnBA,EAAAzI,EAAM0I,qBAAND,IAAmBA,GAAnBA,EAAAE,KAAA3I,EAAsBO,EAAa6B,MAAO7B,EAC3C,EAmEgByE,SAAA,cACTrB,EAACiF,EAAI,CAAA9C,GAAI,CAAEoB,KAAM,KACjBvD,EAAC4E,EAAO,CAAA/C,KAAK,QAAQe,MAAM,UAAUD,QAAQ,OAAOb,QAASzF,EAAMoF,QAE1DJ,SAAA,WACTrB,EAAC4E,EAAO,CAAA/C,KAAK,QAAQiC,KAAK,SAASlB,MAAM,UAAUD,QAAQ,YAAYkC,SAAUlF,GAExE0B,SAAA,iBAKlB,CAGH,CAIA,IAAMpB,EAAaiF,EAAO,OAAPA,CAAe,CAChCC,SAAU,WACV,WAAY,CACVC,QAAS,KACTvC,QAAS,QACTsC,SAAU,WACVE,MAAO,EACPC,gBAAiB,qBACjBC,OAAQ,YACRC,QAAU,EACVC,QAAS,EACTC,WAAY,eACZC,WAAY,UAEd,aAAc,CACZC,cAAe,OACf,WAAY,CACVJ,OAAQ,EACRC,QAAS,EACTE,WAAY,uBAkBFE,IACd,OAAO,SAACtI,GACN,OAAOzB,EAAsByB,EAC9B,CACH"}
@@ -1,2 +1,2 @@
1
- import{slicedToArray as l,toConsumableArray as e,defineProperty as o}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as n,jsxs as i}from"react/jsx-runtime";import{useMemo as r,useState as t,useRef as a,useEffect as u}from"react";import{styled as c,Box as s,Typography as d,CircularProgress as m,Button as v,FormGroup as f,FormControlLabel as p,Checkbox as b}from"@mui/material";import g from"@mui/icons-material/Info";import"../../form/validator.js";import"../../form/dino-form.js";import{getErrorMessage as h}from"../../form/helpers.js";import"../../../_virtual/Reflect.js";import"../../form/decorator.form.js";import"../../form/create.form-grid-layout.units.js";import{createChipViewers as x}from"../components/chip-viewer.js";import{PopperContent as y,PopperBody as C,PopperFooter as j}from"../components/popper-custom.js";import{ButtonBack as A,ChipDark as V,FilterLogicToggle as k}from"../components/ui.units.js";function z(c){var z=x(),O=(c||{}).options,L=void 0===O?[]:O;return function(x){var O,R,w,I=r(function(){return Object.assign({},x.currentConfig,null==c?void 0:c.config)},[null==c?void 0:c.config,x.currentConfig]),B=x.value,E=void 0===B?{values:[],logic:null!==(O=null==I?void 0:I.defaultLogic)&&void 0!==O?O:"or"}:B,F=t(E.logic),N=l(F,2),T=N[0],_=N[1],D=null!==(R=null==c?void 0:c.forceLogic)&&void 0!==R?R:T,M=null!==(w=null==I?void 0:I.label)&&void 0!==w?w:I.field.toString(),P=t([]),H=l(P,2),U=H[0],q=H[1],G=t(null!=c&&c.fetchOptions?"loading":"loaded"),J=l(G,2),K=J[0],Q=J[1],W=a(null),X=function(){var l;if(null!=c&&c.fetchOptions){null===(l=W.current)||void 0===l||l.abort();var e=new AbortController;W.current=e,Q("loading"),c.fetchOptions(e.signal).then(function(l){q(l),Q("loaded")}).catch(function(l){var e;null===(e=x.onError)||void 0===e||e.call(x),"AbortError"!==(null==l?void 0:l.name)&&Q("error")})}};u(function(){return X(),function(){var l;return null===(l=W.current)||void 0===l?void 0:l.abort()}},[]);var Y=null!=c&&c.fetchOptions?U:L,Z=t(function(){return Array.isArray(E.values)?e(E.values):[]}),$=l(Z,2),ll=$[0],el=$[1],ol=Array.isArray(E.values)?E.values:[],nl=T!==E.logic,il=ll.length!==ol.length||ll.some(function(l){return!ol.includes(l)}),rl=!il&&!nl,tl=t({}),al=l(tl,2),ul=al[0],cl=al[1],sl=function(l){x.onSubmit(I.field,l,I)},dl=h(ul,I.field),ml=r(function(){var l=Array.isArray(E.values)?E.values:[E.values];return{field:I.field,items:l.map(function(l){var e;return{value:l,label:null===(e=Y.find(function(e){return e.value===l}))||void 0===e?void 0:e.label}})}},[I.field,E]),vl=null!=(null==c?void 0:c.maxValueCount)&&ll.length>c.maxValueCount,fl=null!=(null==c?void 0:c.maxValueCount)&&ll.length>=c.maxValueCount,pl=r(function(){var l=(null==c?void 0:c.top)||x.top;return l?n(s,{sx:{mb:1},children:l}):null},[null==c?void 0:c.top,x.top]),bl=[];return(x.isLoading||"loading"===K)&&bl.push("disabled"),n(S,{className:bl.join(" "),noValidate:!0,onSubmit:function(l){var e;if(l.preventDefault(),il){if(!vl){var n=o({},I.field,ll),i=null===(e=x.validator)||void 0===e?void 0:e.run(n);if(cl(i||{}),!i||0===Object.keys(i).length)sl({values:ll,logic:D})}}else nl&&sl({values:E.values,logic:D})},children:i(y,{title:"Filter by ".concat(M),onClose:x.onClose,slots:{beforeTitle:n(A,{size:"small",onClick:x.onBack}),afterTitle:null!=c&&c.forceLogic?null:I.singleValue?n(V,{sx:{ml:1.5},size:"small",label:"Last value only"}):n(k,{sx:{ml:1},value:D,onChange:function(l,e){_(e)}})},children:[i(C,{children:[pl,I.description&&n(d,{variant:"caption",color:"text.secondary",sx:{mb:1,display:"block"},children:I.description}),null!=(null==c?void 0:c.maxValueCount)&&n(d,{variant:"caption",color:vl?"warning.main":"text.secondary",sx:{mb:.5,display:"block"},children:null!=c&&c.maxValueCount?vl?"Maximum ".concat(c.maxValueCount," value").concat(c.maxValueCount>1?"s":""," selected (limit reached)"):"Up to ".concat(c.maxValueCount," value").concat(c.maxValueCount>1?"s":""," can be selected"):""}),n(z,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:ml,onRemove:x.onRemove}),"loading"===K&&n(s,{sx:{display:"flex",justifyContent:"center",mt:2},children:n(m,{size:20})}),"error"===K&&i(s,{sx:{display:"flex",flexDirection:"column",alignItems:"center",mt:2,mb:3,gap:1},children:[n(g,{color:"error",fontSize:"large"}),n(d,{variant:"body2",color:"error",children:"Failed to load options"}),n(v,{size:"small",variant:"outlined",color:"error",onClick:X,children:"Retry"})]}),0===Y.length&&"loaded"===K&&n(d,{variant:"body2",color:"text.secondary",sx:{mt:2},children:"No options available"}),n(f,{className:dl.error?"error":"",children:Y.map(function(l,o){var i,r=ll.includes(l.value),t=ml.items.some(function(e){return e.value===l.value})&&!0===(null==c?void 0:c.disabledAfterSubmit),a=!r&&fl;return n(p,{value:l.value,disabled:t||a,label:null!==(i=l.label)&&void 0!==i?i:l.value,control:n(b,{name:I.field.toString(),checked:r,onChange:function(o){return n=l.value,i=o.target.checked,void el(function(l){return i?[].concat(e(l),[n]):l.filter(function(l){return l!==n})});var n,i}})},l.value.toString()+o)})})]}),i(j,{children:[n(v,{size:"small",color:"error",variant:"text",disabled:!E.values||0===E.values.length,onClick:function(){var l;null===(l=x.onRemoveField)||void 0===l||l.call(x,I.field,I)},children:"Clear All"}),n(s,{sx:{flex:1}}),n(v,{size:"small",color:"inherit",variant:"text",onClick:x.onClose,children:"Cancel"}),n(v,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:rl,children:"Apply"})]})]})})}}var S=c("form")({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.12)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}});export{z as default};
1
+ import{slicedToArray as l,toConsumableArray as e,defineProperty as o}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as n,jsxs as i}from"react/jsx-runtime";import{useMemo as r,useState as t,useRef as a,useEffect as u}from"react";import{styled as c,Box as s,Typography as d,CircularProgress as m,Button as v,FormGroup as f,FormControlLabel as p,Checkbox as b}from"@mui/material";import h from"@mui/icons-material/Info";import"../../form/validator.js";import"../../form/dino-form.js";import{getErrorMessage as g}from"../../form/helpers.js";import"../../../_virtual/Reflect.js";import"../../form/decorator.form.js";import"../../form/create.form-grid-layout.units.js";import{DEFAULT_LOGIC as x}from"../helpers.js";import{createChipViewers as y}from"../components/chip-viewer.js";import{PopperContent as C,PopperBody as j,PopperFooter as A}from"../components/popper-custom.js";import{ButtonBack as V,ChipDark as k,FilterLogicToggle as z}from"../components/ui.units.js";function S(c){var S=y(),L=(c||{}).options,R=void 0===L?[]:L;return function(y){var L,w,I,B,E,F=r(function(){return Object.assign({},y.currentConfig,null==c?void 0:c.config)},[null==c?void 0:c.config,y.currentConfig]),N=null!==(L=null==F?void 0:F.defaultLogic)&&void 0!==L?L:x,T=y.value,_=void 0===T?{values:[]}:T,D=t(null!==(w=_.logic)&&void 0!==w?w:N),M=l(D,2),P=M[0],H=M[1],U=null!==(I=null==c?void 0:c.forceLogic)&&void 0!==I?I:P,q=null!==(B=null==F?void 0:F.label)&&void 0!==B?B:F.field.toString(),G=t([]),J=l(G,2),K=J[0],Q=J[1],W=t(null!=c&&c.fetchOptions?"loading":"loaded"),X=l(W,2),Y=X[0],Z=X[1],$=a(null),ll=function(){var l;if(null!=c&&c.fetchOptions){null===(l=$.current)||void 0===l||l.abort();var e=new AbortController;$.current=e,Z("loading"),c.fetchOptions(e.signal).then(function(l){Q(l),Z("loaded")}).catch(function(l){var e;null===(e=y.onError)||void 0===e||e.call(y),"AbortError"!==(null==l?void 0:l.name)&&Z("error")})}};u(function(){return ll(),function(){var l;return null===(l=$.current)||void 0===l?void 0:l.abort()}},[]);var el=null!=c&&c.fetchOptions?K:R,ol=t(function(){return Array.isArray(_.values)?e(_.values):[]}),nl=l(ol,2),il=nl[0],rl=nl[1],tl=Array.isArray(_.values)?_.values:[],al=P!==(null!==(E=_.logic)&&void 0!==E?E:N),ul=il.length!==tl.length||il.some(function(l){return!tl.includes(l)}),cl=!ul&&!al,sl=t({}),dl=l(sl,2),ml=dl[0],vl=dl[1],fl=function(l){y.onSubmit(F.field,l,F)},pl=g(ml,F.field),bl=r(function(){var l=Array.isArray(_.values)?_.values:[_.values];return{field:F.field,items:l.map(function(l){var e;return{value:l,label:null===(e=el.find(function(e){return e.value===l}))||void 0===e?void 0:e.label}})}},[F.field,_]),hl=null!=(null==c?void 0:c.maxValueCount)&&il.length>c.maxValueCount,gl=null!=(null==c?void 0:c.maxValueCount)&&il.length>=c.maxValueCount,xl=r(function(){var l=(null==c?void 0:c.top)||y.top;return l?n(s,{sx:{mb:1},children:l}):null},[null==c?void 0:c.top,y.top]),yl=[];return(y.isLoading||"loading"===Y)&&yl.push("disabled"),n(O,{className:yl.join(" "),noValidate:!0,onSubmit:function(l){var e;if(l.preventDefault(),ul){if(!hl){var n=o({},F.field,il),i=null===(e=y.validator)||void 0===e?void 0:e.run(n);if(vl(i||{}),!i||0===Object.keys(i).length)fl({values:il,logic:U})}}else al&&fl({values:_.values,logic:U})},children:i(C,{title:"Filter by ".concat(q),onClose:y.onClose,slots:{beforeTitle:n(V,{size:"small",onClick:y.onBack}),afterTitle:null!=c&&c.forceLogic?null:F.singleValue?n(k,{sx:{ml:1.5},size:"small",label:"Last value only"}):n(z,{sx:{ml:1},value:U,onChange:function(l,e){H(e)}})},children:[i(j,{children:[xl,F.description&&n(d,{variant:"caption",color:"text.secondary",sx:{mb:1,display:"block"},children:F.description}),null!=(null==c?void 0:c.maxValueCount)&&n(d,{variant:"caption",color:hl?"warning.main":"text.secondary",sx:{mb:.5,display:"block"},children:null!=c&&c.maxValueCount?hl?"Maximum ".concat(c.maxValueCount," value").concat(c.maxValueCount>1?"s":""," selected (limit reached)"):"Up to ".concat(c.maxValueCount," value").concat(c.maxValueCount>1?"s":""," can be selected"):""}),n(S,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:bl,onRemove:y.onRemove}),"loading"===Y&&n(s,{sx:{display:"flex",justifyContent:"center",mt:2},children:n(m,{size:20})}),"error"===Y&&i(s,{sx:{display:"flex",flexDirection:"column",alignItems:"center",mt:2,mb:3,gap:1},children:[n(h,{color:"error",fontSize:"large"}),n(d,{variant:"body2",color:"error",children:"Failed to load options"}),n(v,{size:"small",variant:"outlined",color:"error",onClick:ll,children:"Retry"})]}),0===el.length&&"loaded"===Y&&n(d,{variant:"body2",color:"text.secondary",sx:{mt:2},children:"No options available"}),n(f,{className:pl.error?"error":"",children:el.map(function(l,o){var i,r=il.includes(l.value),t=bl.items.some(function(e){return e.value===l.value})&&!0===(null==c?void 0:c.disabledAfterSubmit),a=!r&&gl;return n(p,{value:l.value,disabled:t||a,label:null!==(i=l.label)&&void 0!==i?i:l.value,control:n(b,{name:F.field.toString(),checked:r,onChange:function(o){return n=l.value,i=o.target.checked,void rl(function(l){return i?[].concat(e(l),[n]):l.filter(function(l){return l!==n})});var n,i}})},l.value.toString()+o)})})]}),i(A,{children:[n(v,{size:"small",color:"error",variant:"text",disabled:!_.values||0===_.values.length,onClick:function(){var l;null===(l=y.onRemoveField)||void 0===l||l.call(y,F.field,F)},children:"Clear All"}),n(s,{sx:{flex:1}}),n(v,{size:"small",color:"inherit",variant:"text",onClick:y.onClose,children:"Cancel"}),n(v,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:cl,children:"Apply"})]})]})})}}var O=c("form")({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.12)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}});export{S as default};
2
2
  //# sourceMappingURL=create-form-field-select-multiple.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-form-field-select-multiple.js","sources":["../../../../src/filter-bar/menu/create-form-field-select-multiple.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { useEffect, useMemo, useRef, useState } from 'react'\r\nimport { Box, Button, Checkbox, CircularProgress, FormControlLabel, FormGroup, formGroupClasses, styled, Typography } from '@mui/material'\r\nimport InfoIcon from '@mui/icons-material/Info'\r\nimport { getErrorMessage } from '../../form'\r\nimport { createChipViewers, TChipViewerGroup } from '../components/chip-viewer'\r\nimport { PopperBody, PopperContent, PopperFooter } from '../components/popper-custom'\r\nimport { ButtonBack, ChipDark, FilterLogicToggle } from '../components/ui.units'\r\n// types\r\nimport type { FC, ReactNode } from 'react'\r\nimport type { IPartialError } from '../../form/validator'\r\nimport type { IFieldSelectOption } from './create-form-field-select'\r\nimport type { TFieldModelValid, TFieldValid, TFieldValue, TLogic } from '../types'\r\nimport type { IFieldMenuConfig, IFilterMenuFormProps, TFetchStatus } from './types'\r\n\r\n/** Props for the `FormFieldSelectMultiple` component returned by `createFormFieldSelectMultiple`. Extends the base filter-menu form props. */\r\nexport interface IFormFieldSelectMultipleProps<T> extends IFilterMenuFormProps<T> {\r\n /** Callback function to handle errors */\r\n onError?: () => void\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/** Parameters passed to `createFormFieldSelectMultiple` to configure the generated component. */\r\nexport interface IFormFieldSelectMultipleParam<T> {\r\n /** Optional configuration for the form field */\r\n config?: IFieldMenuConfig<T>\r\n /** List of options for the select field */\r\n options?: IFieldSelectOption[]\r\n /** Function to fetch options asynchronously */\r\n fetchOptions?: (signal?: AbortSignal) => Promise<IFieldSelectOption[]>\r\n /** If true, disables the field after submission. @default false */\r\n disabledAfterSubmit?: boolean\r\n /** Force a fixed logic value, hiding the logic toggle */\r\n forceLogic?: TLogic\r\n /** Maximum number of values that can be selected */\r\n maxValueCount?: number\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/**\r\n * Factory function that creates a `FormFieldSelectMultiple` filter-menu component.\r\n *\r\n * The generated component renders a checkbox list of options inside a\r\n * popper/menu panel, allowing the user to select **multiple values** at once.\r\n * It supports:\r\n * - Controlled checkbox state to prevent uncontrolled→controlled React warnings\r\n * - OR / AND logic toggle when more than one value is applied\r\n * - Chip viewers showing the currently applied values\r\n * - Built-in validation via an optional `validator` prop\r\n * - A loading overlay that disables interaction while `isLoading` is true\r\n *\r\n * @param params - Static configuration (option list, optional field config override)\r\n * @returns A React FC ready to be used as a multi-select filter-menu field component\r\n */\r\nfunction createFormFieldSelectMultiple<T>(params?: IFormFieldSelectMultipleParam<T>) {\r\n const ChipViewers = createChipViewers<T>()\r\n const { options: staticOptions = [] } = params || {}\r\n\r\n const FormFieldSelectMultiple: FC<IFormFieldSelectMultipleProps<T>> = (props) => {\r\n /** Merge `props.currentConfig` with `params.config` (if provided).\r\n * Fields from `params.config` override the corresponding keys in `props.currentConfig`.\r\n * Any keys not present in `params.config` are preserved from `props.currentConfig`.\r\n */\r\n const mergedConfig = useMemo(() => Object.assign({}, props.currentConfig, params?.config), [params?.config, props.currentConfig])\r\n\r\n const { value = { values: [], logic: mergedConfig?.defaultLogic ?? 'or' } } = props\r\n const [filterLogic, setFilterLogic] = useState<TLogic>(value.logic!)\r\n const effectiveLogic = params?.forceLogic ?? filterLogic\r\n\r\n const label = mergedConfig?.label ?? mergedConfig.field.toString()\r\n\r\n const [fetchedOptions, setFetchedOptions] = useState<IFieldSelectOption[]>([])\r\n const [fetchStatus, setFetchStatus] = useState<TFetchStatus>(params?.fetchOptions ? 'loading' : 'loaded')\r\n const abortRef = useRef<AbortController | null>(null)\r\n\r\n const runFetch = () => {\r\n if (!params?.fetchOptions) return\r\n abortRef.current?.abort()\r\n const controller = new AbortController()\r\n abortRef.current = controller\r\n setFetchStatus('loading')\r\n params\r\n .fetchOptions(controller.signal)\r\n .then((data) => {\r\n setFetchedOptions(data)\r\n setFetchStatus('loaded')\r\n })\r\n .catch((err) => {\r\n props.onError?.()\r\n if (err?.name !== 'AbortError') setFetchStatus('error')\r\n })\r\n }\r\n\r\n useEffect(() => {\r\n runFetch()\r\n return () => abortRef.current?.abort()\r\n }, [])\r\n\r\n const options = params?.fetchOptions ? fetchedOptions : staticOptions\r\n\r\n // Track checked values as controlled state to avoid the uncontrolled→controlled MUI warning\r\n // Initialize directly from value.values so pre-selected values are visible even before fetchOptions resolves\r\n const [checkedValues, setCheckedValues] = useState<TFieldValid[]>(() => {\r\n return Array.isArray(value.values) ? [...value.values] : []\r\n })\r\n\r\n const appliedValues = Array.isArray(value.values) ? value.values : []\r\n const hasLogicChange = filterLogic !== value.logic\r\n const hasDataChange = checkedValues.length !== appliedValues.length || checkedValues.some((v) => !appliedValues.includes(v))\r\n const isApplyDisabled = !hasDataChange && !hasLogicChange\r\n\r\n const [errorData, setErrorData] = useState<IPartialError<TFieldModelValid<T>>>({})\r\n\r\n const handleCheckboxChange = (optionValue: TFieldValid, checked: boolean) => {\r\n setCheckedValues((prev) => (checked ? [...prev, optionValue] : prev.filter((v) => v !== optionValue)))\r\n }\r\n\r\n const handleSubmit = (newValue: TFieldValue) => {\r\n props.onSubmit(mergedConfig.field, newValue, mergedConfig)\r\n }\r\n\r\n const handleSubmitForm = (event: React.FormEvent<HTMLFormElement>) => {\r\n event.preventDefault()\r\n\r\n if (!hasDataChange) {\r\n if (hasLogicChange) handleSubmit({ values: value.values, logic: effectiveLogic })\r\n return\r\n }\r\n\r\n if (isMaxReached) return\r\n\r\n const obj = { [mergedConfig.field]: checkedValues } as Partial<TFieldModelValid<T>>\r\n let errorData = props.validator?.run(obj) as IPartialError<TFieldModelValid<T>>\r\n\r\n setErrorData(errorData || {})\r\n\r\n if (!errorData || Object.keys(errorData).length === 0) {\r\n const newValue: TFieldValue = { values: checkedValues, logic: effectiveLogic }\r\n handleSubmit(newValue)\r\n }\r\n }\r\n\r\n const errorResult = getErrorMessage(errorData, mergedConfig.field)\r\n const filterViewerValue = useMemo<TChipViewerGroup<T>>(() => {\r\n const items = Array.isArray(value.values) ? value.values : [value.values]\r\n return {\r\n field: mergedConfig.field,\r\n items: items.map((v) => ({ value: v, label: options.find((o) => o.value === v)?.label }))\r\n }\r\n }, [mergedConfig.field, value])\r\n\r\n const isMaxReached = params?.maxValueCount != null && checkedValues.length > params.maxValueCount\r\n const isMaxReachedValid = params?.maxValueCount != null && checkedValues.length >= params.maxValueCount\r\n\r\n const handleChangeLogic = (newLogic: TLogic) => {\r\n setFilterLogic(newLogic)\r\n }\r\n\r\n const handleClearAll = () => {\r\n props.onRemoveField?.(mergedConfig.field, mergedConfig)\r\n }\r\n\r\n const getMaxReachedText = () => {\r\n if (!params?.maxValueCount) return ''\r\n if (isMaxReached) {\r\n return `Maximum ${params.maxValueCount} value${params.maxValueCount > 1 ? 's' : ''} selected (limit reached)`\r\n } else {\r\n return `Up to ${params.maxValueCount} value${params.maxValueCount > 1 ? 's' : ''} can be selected`\r\n }\r\n }\r\n\r\n const renderAfterTitle = () => {\r\n if (params?.forceLogic) return null\r\n if (mergedConfig.singleValue) return <ChipDark sx={{ ml: 1.5 }} size='small' label='Last value only' />\r\n return <FilterLogicToggle sx={{ ml: 1 }} value={effectiveLogic} onChange={(_, nVal) => handleChangeLogic(nVal)} />\r\n }\r\n\r\n const renderTop = useMemo(() => {\r\n const topContent = params?.top || props.top\r\n if (topContent) return <Box sx={{ mb: 1 }}>{topContent}</Box>\r\n return null\r\n }, [params?.top, props.top])\r\n\r\n const rootClasses: string[] = []\r\n if (props.isLoading || fetchStatus === 'loading') rootClasses.push('disabled')\r\n\r\n return (\r\n <RootStyled className={rootClasses.join(' ')} noValidate onSubmit={handleSubmitForm}>\r\n <PopperContent\r\n title={`Filter by ${label}`}\r\n onClose={props.onClose}\r\n slots={{\r\n beforeTitle: <ButtonBack size='small' onClick={props.onBack} />,\r\n afterTitle: renderAfterTitle()\r\n }}\r\n >\r\n <PopperBody>\r\n {renderTop}\r\n {mergedConfig.description && (\r\n <Typography variant='caption' color='text.secondary' sx={{ mb: 1, display: 'block' }}>\r\n {mergedConfig.description}\r\n </Typography>\r\n )}\r\n {params?.maxValueCount != null && (\r\n <Typography variant='caption' color={isMaxReached ? 'warning.main' : 'text.secondary'} sx={{ mb: 0.5, display: 'block' }}>\r\n {getMaxReachedText()}\r\n </Typography>\r\n )}\r\n <ChipViewers\r\n sx={{ mb: 1, borderBottom: 'none!important' }}\r\n label='Applied'\r\n placement='horizontal'\r\n enableMinimalesticView\r\n value={filterViewerValue}\r\n onRemove={props.onRemove}\r\n />\r\n {fetchStatus === 'loading' && (\r\n <Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>\r\n <CircularProgress size={20} />\r\n </Box>\r\n )}\r\n {fetchStatus === 'error' && (\r\n <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', mt: 2, mb: 3, gap: 1 }}>\r\n <InfoIcon color='error' fontSize='large' />\r\n <Typography variant='body2' color='error'>\r\n Failed to load options\r\n </Typography>\r\n <Button size='small' variant='outlined' color='error' onClick={runFetch}>\r\n Retry\r\n </Button>\r\n </Box>\r\n )}\r\n {options.length === 0 && fetchStatus === 'loaded' && (\r\n <Typography variant='body2' color='text.secondary' sx={{ mt: 2 }}>\r\n No options available\r\n </Typography>\r\n )}\r\n <FormGroup className={errorResult.error ? 'error' : ''}>\r\n {options.map((x, i) => {\r\n const isChecked = checkedValues.includes(x.value as TFieldValid)\r\n const isSelected = filterViewerValue.items.some((item) => item.value === x.value)\r\n const disabled = isSelected && params?.disabledAfterSubmit === true\r\n const disableDueToMax = !isChecked && isMaxReachedValid\r\n return (\r\n <FormControlLabel\r\n key={x.value.toString() + i}\r\n value={x.value}\r\n disabled={disabled || disableDueToMax}\r\n label={x.label ?? x.value}\r\n control={\r\n <Checkbox\r\n name={mergedConfig.field.toString()}\r\n checked={isChecked}\r\n onChange={(e) => handleCheckboxChange(x.value as TFieldValid, e.target.checked)}\r\n />\r\n }\r\n />\r\n )\r\n })}\r\n </FormGroup>\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button size='small' color='error' variant='text' disabled={!value.values || value.values.length === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n <Box sx={{ flex: 1 }} />\r\n <Button size='small' color='inherit' variant='text' onClick={props.onClose}>\r\n Cancel\r\n </Button>\r\n <Button size='small' type='submit' color='primary' variant='contained' disabled={isApplyDisabled}>\r\n Apply\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n </RootStyled>\r\n )\r\n }\r\n\r\n return FormFieldSelectMultiple\r\n}\r\n\r\nexport default createFormFieldSelectMultiple\r\n\r\nconst RootStyled = styled('form')({\r\n position: 'relative',\r\n '&::after': {\r\n content: '\"\"',\r\n display: 'block',\r\n position: 'absolute',\r\n inset: 0, // top: 0, left: 0, right: 0, bottom: 0\r\n backgroundColor: 'rgba(0, 0, 0, 0.12)',\r\n filter: 'blur(2px)',\r\n zIndex: -1,\r\n opacity: 0,\r\n transition: 'opacity 0.3s',\r\n visibility: 'hidden'\r\n },\r\n '&.disabled': {\r\n pointerEvents: 'none',\r\n '&::after': {\r\n zIndex: 1,\r\n opacity: 1,\r\n visibility: 'visible'\r\n }\r\n }\r\n // [`.${formGroupClasses.root}`]: {}\r\n})\r\n"],"names":["createFormFieldSelectMultiple","params","ChipViewers","createChipViewers","_ref$options","options","staticOptions","props","_mergedConfig$default","_params$forceLogic","_mergedConfig$label","mergedConfig","useMemo","Object","assign","currentConfig","config","_props$value","value","values","logic","defaultLogic","_useState","useState","_useState2","_slicedToArray","filterLogic","setFilterLogic","effectiveLogic","forceLogic","label","field","toString","_useState3","_useState4","fetchedOptions","setFetchedOptions","_useState5","fetchOptions","_useState6","fetchStatus","setFetchStatus","abortRef","useRef","runFetch","_abortRef$current","current","abort","controller","AbortController","signal","then","data","err","_props$onError","onError","call","name","useEffect","_abortRef$current2","_useState7","Array","isArray","_toConsumableArray","_useState8","checkedValues","setCheckedValues","appliedValues","hasLogicChange","hasDataChange","length","some","v","includes","isApplyDisabled","_useState9","_useState0","errorData","setErrorData","handleSubmit","newValue","onSubmit","errorResult","getErrorMessage","filterViewerValue","items","map","_options$find","find","o","isMaxReached","maxValueCount","isMaxReachedValid","renderTop","topContent","top","_jsx","Box","sx","mb","children","rootClasses","isLoading","push","RootStyled","className","join","noValidate","event","_props$validator","preventDefault","obj","_defineProperty","validator","run","keys","_jsxs","PopperContent","title","concat","onClose","slots","beforeTitle","ButtonBack","size","onClick","onBack","afterTitle","singleValue","ChipDark","ml","FilterLogicToggle","onChange","_","nVal","PopperBody","description","Typography","variant","color","display","borderBottom","placement","enableMinimalesticView","onRemove","justifyContent","mt","CircularProgress","flexDirection","alignItems","gap","InfoIcon","fontSize","Button","FormGroup","error","x","i","_x$label","isChecked","disabled","item","disabledAfterSubmit","disableDueToMax","FormControlLabel","control","Checkbox","checked","e","optionValue","target","prev","filter","PopperFooter","_props$onRemoveField","onRemoveField","flex","type","styled","position","content","inset","backgroundColor","zIndex","opacity","transition","visibility","pointerEvents"],"mappings":"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"}
1
+ {"version":3,"file":"create-form-field-select-multiple.js","sources":["../../../../src/filter-bar/menu/create-form-field-select-multiple.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { useEffect, useMemo, useRef, useState } from 'react'\r\nimport { Box, Button, Checkbox, CircularProgress, FormControlLabel, FormGroup, formGroupClasses, styled, Typography } from '@mui/material'\r\nimport InfoIcon from '@mui/icons-material/Info'\r\nimport { getErrorMessage } from '../../form'\r\nimport { DEFAULT_LOGIC } from '../helpers'\r\nimport { createChipViewers, TChipViewerGroup } from '../components/chip-viewer'\r\nimport { PopperBody, PopperContent, PopperFooter } from '../components/popper-custom'\r\nimport { ButtonBack, ChipDark, FilterLogicToggle } from '../components/ui.units'\r\n// types\r\nimport type { FC, ReactNode } from 'react'\r\nimport type { IPartialError } from '../../form/validator'\r\nimport type { IFieldSelectOption } from './create-form-field-select'\r\nimport type { TFieldModelValid, TFieldValid, TFieldValue, TLogic } from '../types'\r\nimport type { IFieldMenuConfig, IFilterMenuFormProps, TFetchStatus } from './types'\r\n\r\n/** Props for the `FormFieldSelectMultiple` component returned by `createFormFieldSelectMultiple`. Extends the base filter-menu form props. */\r\nexport interface IFormFieldSelectMultipleProps<T> extends IFilterMenuFormProps<T> {\r\n /** Callback function to handle errors */\r\n onError?: () => void\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/** Parameters passed to `createFormFieldSelectMultiple` to configure the generated component. */\r\nexport interface IFormFieldSelectMultipleParam<T> {\r\n /** Optional configuration for the form field */\r\n config?: IFieldMenuConfig<T>\r\n /** List of options for the select field */\r\n options?: IFieldSelectOption[]\r\n /** Function to fetch options asynchronously */\r\n fetchOptions?: (signal?: AbortSignal) => Promise<IFieldSelectOption[]>\r\n /** If true, disables the field after submission. @default false */\r\n disabledAfterSubmit?: boolean\r\n /** Force a fixed logic value, hiding the logic toggle */\r\n forceLogic?: TLogic\r\n /** Maximum number of values that can be selected */\r\n maxValueCount?: number\r\n /** Optional content to render at the top of the form */\r\n top?: ReactNode\r\n}\r\n\r\n/**\r\n * Factory function that creates a `FormFieldSelectMultiple` filter-menu component.\r\n *\r\n * The generated component renders a checkbox list of options inside a\r\n * popper/menu panel, allowing the user to select **multiple values** at once.\r\n * It supports:\r\n * - Controlled checkbox state to prevent uncontrolled→controlled React warnings\r\n * - OR / AND logic toggle when more than one value is applied\r\n * - Chip viewers showing the currently applied values\r\n * - Built-in validation via an optional `validator` prop\r\n * - A loading overlay that disables interaction while `isLoading` is true\r\n *\r\n * @param params - Static configuration (option list, optional field config override)\r\n * @returns A React FC ready to be used as a multi-select filter-menu field component\r\n */\r\nfunction createFormFieldSelectMultiple<T>(params?: IFormFieldSelectMultipleParam<T>) {\r\n const ChipViewers = createChipViewers<T>()\r\n const { options: staticOptions = [] } = params || {}\r\n\r\n const FormFieldSelectMultiple: FC<IFormFieldSelectMultipleProps<T>> = (props) => {\r\n /** Merge `props.currentConfig` with `params.config` (if provided).\r\n * Fields from `params.config` override the corresponding keys in `props.currentConfig`.\r\n * Any keys not present in `params.config` are preserved from `props.currentConfig`.\r\n */\r\n const mergedConfig = useMemo(() => Object.assign({}, props.currentConfig, params?.config), [params?.config, props.currentConfig])\r\n\r\n const defaultLogic: TLogic = mergedConfig?.defaultLogic ?? DEFAULT_LOGIC\r\n const { value = { values: [] } } = props\r\n const [filterLogic, setFilterLogic] = useState<TLogic>(value.logic ?? defaultLogic)\r\n const effectiveLogic = params?.forceLogic ?? filterLogic\r\n\r\n const label = mergedConfig?.label ?? mergedConfig.field.toString()\r\n\r\n const [fetchedOptions, setFetchedOptions] = useState<IFieldSelectOption[]>([])\r\n const [fetchStatus, setFetchStatus] = useState<TFetchStatus>(params?.fetchOptions ? 'loading' : 'loaded')\r\n const abortRef = useRef<AbortController | null>(null)\r\n\r\n const runFetch = () => {\r\n if (!params?.fetchOptions) return\r\n abortRef.current?.abort()\r\n const controller = new AbortController()\r\n abortRef.current = controller\r\n setFetchStatus('loading')\r\n params\r\n .fetchOptions(controller.signal)\r\n .then((data) => {\r\n setFetchedOptions(data)\r\n setFetchStatus('loaded')\r\n })\r\n .catch((err) => {\r\n props.onError?.()\r\n if (err?.name !== 'AbortError') setFetchStatus('error')\r\n })\r\n }\r\n\r\n useEffect(() => {\r\n runFetch()\r\n return () => abortRef.current?.abort()\r\n }, [])\r\n\r\n const options = params?.fetchOptions ? fetchedOptions : staticOptions\r\n\r\n // Track checked values as controlled state to avoid the uncontrolled→controlled MUI warning\r\n // Initialize directly from value.values so pre-selected values are visible even before fetchOptions resolves\r\n const [checkedValues, setCheckedValues] = useState<TFieldValid[]>(() => {\r\n return Array.isArray(value.values) ? [...value.values] : []\r\n })\r\n\r\n const appliedValues = Array.isArray(value.values) ? value.values : []\r\n const hasLogicChange = filterLogic !== (value.logic ?? defaultLogic)\r\n const hasDataChange = checkedValues.length !== appliedValues.length || checkedValues.some((v) => !appliedValues.includes(v))\r\n const isApplyDisabled = !hasDataChange && !hasLogicChange\r\n\r\n const [errorData, setErrorData] = useState<IPartialError<TFieldModelValid<T>>>({})\r\n\r\n const handleCheckboxChange = (optionValue: TFieldValid, checked: boolean) => {\r\n setCheckedValues((prev) => (checked ? [...prev, optionValue] : prev.filter((v) => v !== optionValue)))\r\n }\r\n\r\n const handleSubmit = (newValue: TFieldValue) => {\r\n props.onSubmit(mergedConfig.field, newValue, mergedConfig)\r\n }\r\n\r\n const handleSubmitForm = (event: React.FormEvent<HTMLFormElement>) => {\r\n event.preventDefault()\r\n\r\n if (!hasDataChange) {\r\n if (hasLogicChange) handleSubmit({ values: value.values, logic: effectiveLogic })\r\n return\r\n }\r\n\r\n if (isMaxReached) return\r\n\r\n const obj = { [mergedConfig.field]: checkedValues } as Partial<TFieldModelValid<T>>\r\n let errorData = props.validator?.run(obj) as IPartialError<TFieldModelValid<T>>\r\n\r\n setErrorData(errorData || {})\r\n\r\n if (!errorData || Object.keys(errorData).length === 0) {\r\n const newValue: TFieldValue = { values: checkedValues, logic: effectiveLogic }\r\n handleSubmit(newValue)\r\n }\r\n }\r\n\r\n const errorResult = getErrorMessage(errorData, mergedConfig.field)\r\n const filterViewerValue = useMemo<TChipViewerGroup<T>>(() => {\r\n const items = Array.isArray(value.values) ? value.values : [value.values]\r\n return {\r\n field: mergedConfig.field,\r\n items: items.map((v) => ({ value: v, label: options.find((o) => o.value === v)?.label }))\r\n }\r\n }, [mergedConfig.field, value])\r\n\r\n const isMaxReached = params?.maxValueCount != null && checkedValues.length > params.maxValueCount\r\n const isMaxReachedValid = params?.maxValueCount != null && checkedValues.length >= params.maxValueCount\r\n\r\n const handleChangeLogic = (newLogic: TLogic) => {\r\n setFilterLogic(newLogic)\r\n }\r\n\r\n const handleClearAll = () => {\r\n props.onRemoveField?.(mergedConfig.field, mergedConfig)\r\n }\r\n\r\n const getMaxReachedText = () => {\r\n if (!params?.maxValueCount) return ''\r\n if (isMaxReached) {\r\n return `Maximum ${params.maxValueCount} value${params.maxValueCount > 1 ? 's' : ''} selected (limit reached)`\r\n } else {\r\n return `Up to ${params.maxValueCount} value${params.maxValueCount > 1 ? 's' : ''} can be selected`\r\n }\r\n }\r\n\r\n const renderAfterTitle = () => {\r\n if (params?.forceLogic) return null\r\n if (mergedConfig.singleValue) return <ChipDark sx={{ ml: 1.5 }} size='small' label='Last value only' />\r\n return <FilterLogicToggle sx={{ ml: 1 }} value={effectiveLogic} onChange={(_, nVal) => handleChangeLogic(nVal)} />\r\n }\r\n\r\n const renderTop = useMemo(() => {\r\n const topContent = params?.top || props.top\r\n if (topContent) return <Box sx={{ mb: 1 }}>{topContent}</Box>\r\n return null\r\n }, [params?.top, props.top])\r\n\r\n const rootClasses: string[] = []\r\n if (props.isLoading || fetchStatus === 'loading') rootClasses.push('disabled')\r\n\r\n return (\r\n <RootStyled className={rootClasses.join(' ')} noValidate onSubmit={handleSubmitForm}>\r\n <PopperContent\r\n title={`Filter by ${label}`}\r\n onClose={props.onClose}\r\n slots={{\r\n beforeTitle: <ButtonBack size='small' onClick={props.onBack} />,\r\n afterTitle: renderAfterTitle()\r\n }}\r\n >\r\n <PopperBody>\r\n {renderTop}\r\n {mergedConfig.description && (\r\n <Typography variant='caption' color='text.secondary' sx={{ mb: 1, display: 'block' }}>\r\n {mergedConfig.description}\r\n </Typography>\r\n )}\r\n {params?.maxValueCount != null && (\r\n <Typography variant='caption' color={isMaxReached ? 'warning.main' : 'text.secondary'} sx={{ mb: 0.5, display: 'block' }}>\r\n {getMaxReachedText()}\r\n </Typography>\r\n )}\r\n <ChipViewers\r\n sx={{ mb: 1, borderBottom: 'none!important' }}\r\n label='Applied'\r\n placement='horizontal'\r\n enableMinimalesticView\r\n value={filterViewerValue}\r\n onRemove={props.onRemove}\r\n />\r\n {fetchStatus === 'loading' && (\r\n <Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>\r\n <CircularProgress size={20} />\r\n </Box>\r\n )}\r\n {fetchStatus === 'error' && (\r\n <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', mt: 2, mb: 3, gap: 1 }}>\r\n <InfoIcon color='error' fontSize='large' />\r\n <Typography variant='body2' color='error'>\r\n Failed to load options\r\n </Typography>\r\n <Button size='small' variant='outlined' color='error' onClick={runFetch}>\r\n Retry\r\n </Button>\r\n </Box>\r\n )}\r\n {options.length === 0 && fetchStatus === 'loaded' && (\r\n <Typography variant='body2' color='text.secondary' sx={{ mt: 2 }}>\r\n No options available\r\n </Typography>\r\n )}\r\n <FormGroup className={errorResult.error ? 'error' : ''}>\r\n {options.map((x, i) => {\r\n const isChecked = checkedValues.includes(x.value as TFieldValid)\r\n const isSelected = filterViewerValue.items.some((item) => item.value === x.value)\r\n const disabled = isSelected && params?.disabledAfterSubmit === true\r\n const disableDueToMax = !isChecked && isMaxReachedValid\r\n return (\r\n <FormControlLabel\r\n key={x.value.toString() + i}\r\n value={x.value}\r\n disabled={disabled || disableDueToMax}\r\n label={x.label ?? x.value}\r\n control={\r\n <Checkbox\r\n name={mergedConfig.field.toString()}\r\n checked={isChecked}\r\n onChange={(e) => handleCheckboxChange(x.value as TFieldValid, e.target.checked)}\r\n />\r\n }\r\n />\r\n )\r\n })}\r\n </FormGroup>\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button size='small' color='error' variant='text' disabled={!value.values || value.values.length === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n <Box sx={{ flex: 1 }} />\r\n <Button size='small' color='inherit' variant='text' onClick={props.onClose}>\r\n Cancel\r\n </Button>\r\n <Button size='small' type='submit' color='primary' variant='contained' disabled={isApplyDisabled}>\r\n Apply\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n </RootStyled>\r\n )\r\n }\r\n\r\n return FormFieldSelectMultiple\r\n}\r\n\r\nexport default createFormFieldSelectMultiple\r\n\r\nconst RootStyled = styled('form')({\r\n position: 'relative',\r\n '&::after': {\r\n content: '\"\"',\r\n display: 'block',\r\n position: 'absolute',\r\n inset: 0, // top: 0, left: 0, right: 0, bottom: 0\r\n backgroundColor: 'rgba(0, 0, 0, 0.12)',\r\n filter: 'blur(2px)',\r\n zIndex: -1,\r\n opacity: 0,\r\n transition: 'opacity 0.3s',\r\n visibility: 'hidden'\r\n },\r\n '&.disabled': {\r\n pointerEvents: 'none',\r\n '&::after': {\r\n zIndex: 1,\r\n opacity: 1,\r\n visibility: 'visible'\r\n }\r\n }\r\n // [`.${formGroupClasses.root}`]: {}\r\n})\r\n"],"names":["createFormFieldSelectMultiple","params","ChipViewers","createChipViewers","_ref$options","options","staticOptions","props","_mergedConfig$default","_value$logic","_params$forceLogic","_mergedConfig$label","_value$logic2","mergedConfig","useMemo","Object","assign","currentConfig","config","defaultLogic","DEFAULT_LOGIC","_props$value","value","values","_useState","useState","logic","_useState2","_slicedToArray","filterLogic","setFilterLogic","effectiveLogic","forceLogic","label","field","toString","_useState3","_useState4","fetchedOptions","setFetchedOptions","_useState5","fetchOptions","_useState6","fetchStatus","setFetchStatus","abortRef","useRef","runFetch","_abortRef$current","current","abort","controller","AbortController","signal","then","data","err","_props$onError","onError","call","name","useEffect","_abortRef$current2","_useState7","Array","isArray","_toConsumableArray","_useState8","checkedValues","setCheckedValues","appliedValues","hasLogicChange","hasDataChange","length","some","v","includes","isApplyDisabled","_useState9","_useState0","errorData","setErrorData","handleSubmit","newValue","onSubmit","errorResult","getErrorMessage","filterViewerValue","items","map","_options$find","find","o","isMaxReached","maxValueCount","isMaxReachedValid","renderTop","topContent","top","_jsx","Box","sx","mb","children","rootClasses","isLoading","push","RootStyled","className","join","noValidate","event","_props$validator","preventDefault","obj","_defineProperty","validator","run","keys","_jsxs","PopperContent","title","concat","onClose","slots","beforeTitle","ButtonBack","size","onClick","onBack","afterTitle","singleValue","ChipDark","ml","FilterLogicToggle","onChange","_","nVal","PopperBody","description","Typography","variant","color","display","borderBottom","placement","enableMinimalesticView","onRemove","justifyContent","mt","CircularProgress","flexDirection","alignItems","gap","InfoIcon","fontSize","Button","FormGroup","error","x","i","_x$label","isChecked","disabled","item","disabledAfterSubmit","disableDueToMax","FormControlLabel","control","Checkbox","checked","e","optionValue","target","prev","filter","PopperFooter","_props$onRemoveField","onRemoveField","flex","type","styled","position","content","inset","backgroundColor","zIndex","opacity","transition","visibility","pointerEvents"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{defineProperty as o,slicedToArray as l}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as e,jsxs as n}from"react/jsx-runtime";import{useMemo as i,useState as r,useRef as t,useEffect as a}from"react";import{styled as c,radioGroupClasses as u,Box as s,Typography as d,CircularProgress as m,Button as v,RadioGroup as f,FormControlLabel as p,Radio as b}from"@mui/material";import g from"@mui/icons-material/Info";import{getErrorMessage as h}from"../../form/helpers.js";import{createChipViewers as x}from"../components/chip-viewer.js";import{ButtonBack as y,ChipDark as C,FilterLogicToggle as z}from"../components/ui.units.js";import{PopperContent as k,PopperBody as V,PopperFooter as j}from"../components/popper-custom.js";function A(c){var u=x(),A=c.options;return function(x){var O,S,F,M=i(function(){return Object.assign({},x.currentConfig,null==c?void 0:c.config)},[null==c?void 0:c.config,x.currentConfig]),R=x.value,w=void 0===R?{values:[],logic:null!==(O=null==M?void 0:M.defaultLogic)&&void 0!==O?O:"or"}:R,I=r(w.logic),B=l(I,2),E=B[0],N=B[1],T=null!==(S=c.forceLogic)&&void 0!==S?S:E,D=r(null),P=l(D,2),_=P[0],H=P[1],U=r([]),q=l(U,2),G=q[0],J=q[1],K=r(c.fetchOptions?"loading":"loaded"),Q=l(K,2),W=Q[0],X=Q[1],Y=t(null),Z=function(){var o;if(c.fetchOptions){null===(o=Y.current)||void 0===o||o.abort();var l=new AbortController;Y.current=l,X("loading"),c.fetchOptions(l.signal).then(function(o){J(o),X("loaded")}).catch(function(o){var l;null===(l=x.onError)||void 0===l||l.call(x),"AbortError"!==(null==o?void 0:o.name)&&X("error")})}};a(function(){return Z(),function(){var o;return null===(o=Y.current)||void 0===o?void 0:o.abort()}},[]);var $=c.fetchOptions?G:null!=A?A:[],oo=E!==w.logic,lo=null!==_,eo=!lo&&!oo,no=null!==(F=null==M?void 0:M.label)&&void 0!==F?F:M.field.toString(),io=r({}),ro=l(io,2),to=ro[0],ao=ro[1],co=function(o){x.onSubmit(M.field,o,M)},uo=h(to,M.field),so=i(function(){var o=Array.isArray(w.values)?w.values:[w.values];return{field:M.field,items:o.map(function(o){var l;return{value:o,label:null===(l=$.find(function(l){return l.value===o}))||void 0===l?void 0:l.label}})}},[M.field,w,$]),mo=null!=c.maxValueCount&&so.items.length>=c.maxValueCount,vo=i(function(){var o=(null==c?void 0:c.top)||x.top;return o?e(s,{sx:{mb:1},children:o}):null},[null==c?void 0:c.top,x.top]),fo=[];return(x.isLoading||"loading"===W)&&fo.push("disabled"),e(L,{className:fo.join(" "),noValidate:!0,onSubmit:function(l){var e;if(l.preventDefault(),lo){if(!mo){var n=o({},M.field,_),i=null===(e=x.validator)||void 0===e?void 0:e.run(n);if(ao(i||{}),!i||0===Object.keys(i).length)co({values:[_],logic:T}),H(null)}}else oo&&co({values:w.values,logic:T})},children:n(k,{title:"Filter by ".concat(no),onClose:x.onClose,slots:{beforeTitle:e(y,{size:"small",onClick:x.onBack}),afterTitle:c.forceLogic?null:M.singleValue?e(C,{sx:{ml:1.5},size:"small",label:"Last value only"}):e(z,{sx:{ml:1},value:T,onChange:function(o,l){N(l)}})},children:[n(V,{children:[vo,M.description&&e(d,{variant:"caption",color:"text.secondary",sx:{mb:1,display:"block"},children:M.description}),null!=c.maxValueCount&&e(d,{variant:"caption",color:mo?"warning.main":"text.secondary",sx:{mb:.5,display:"block"},children:c.maxValueCount?mo?"Maximum ".concat(c.maxValueCount," value").concat(c.maxValueCount>1?"s":""," selected (limit reached)"):"Up to ".concat(c.maxValueCount," value").concat(c.maxValueCount>1?"s":""," can be selected"):""}),e(u,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:so,onRemove:x.onRemove}),"loading"===W&&e(s,{sx:{display:"flex",justifyContent:"center",mt:2},children:e(m,{size:20})}),"error"===W&&n(s,{sx:{display:"flex",flexDirection:"column",alignItems:"center",mt:2,mb:3,gap:1},children:[e(g,{color:"error",fontSize:"large"}),e(d,{variant:"body2",color:"error",children:"Failed to load options"}),e(v,{size:"small",variant:"outlined",color:"error",onClick:Z,children:"Retry"})]}),0===$.length&&"loaded"===W&&e(d,{variant:"body2",color:"text.secondary",sx:{mt:2},children:"No options available"}),e(f,{sx:{mx:-1},name:M.field.toString(),value:null!=_?_:"",onChange:function(o){return H(o.target.value)},className:uo.error?"error":"",children:$.map(function(o,l){var n,i=so.items.some(function(l){return l.value===o.value});return e(p,{disabled:i||mo,value:o.value,control:e(b,{size:"small"}),label:e(d,{variant:"body2",children:null!==(n=o.label)&&void 0!==n?n:o.value})},o.value.toString()+l)})}),uo.error&&e(d,{variant:"caption",color:"error",sx:{mt:.5},children:uo.message})]}),n(j,{children:[e(v,{size:"small",color:"error",variant:"text",disabled:!w.values||0===w.values.length,onClick:function(){var o;null===(o=x.onRemoveField)||void 0===o||o.call(x,M.field,M)},children:"Clear All"}),e(s,{sx:{flex:1}}),e(v,{size:"small",color:"inherit",variant:"text",onClick:x.onClose,children:"Cancel"}),e(v,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:eo,children:"Apply"})]})]})})}}var L=c("form")(o({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.12)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}},".".concat(u.root),{"&.error .MuiRadio-root":{color:"#d32f2f"},".MuiFormControlLabel-root":{margin:0},".MuiFormControlLabel-root:hover":{backgroundColor:"rgba(25, 118, 210, 0.04)"}}));export{A as default};
1
+ import{defineProperty as l,slicedToArray as o}from"../../../_virtual/_rollupPluginBabelHelpers.js";import{jsx as e,jsxs as n}from"react/jsx-runtime";import{useMemo as i,useState as r,useRef as t,useEffect as a}from"react";import{styled as u,radioGroupClasses as c,Box as s,Typography as d,CircularProgress as m,Button as v,RadioGroup as f,FormControlLabel as p,Radio as b}from"@mui/material";import g from"@mui/icons-material/Info";import{getErrorMessage as h}from"../../form/helpers.js";import{DEFAULT_LOGIC as x}from"../helpers.js";import{createChipViewers as y}from"../components/chip-viewer.js";import{ButtonBack as C,ChipDark as z,FilterLogicToggle as j}from"../components/ui.units.js";import{PopperContent as k,PopperBody as V,PopperFooter as A}from"../components/popper-custom.js";function L(u){var c=y(),L=u.options;return function(y){var S,F,M,R,w,I=i(function(){return Object.assign({},y.currentConfig,null==u?void 0:u.config)},[null==u?void 0:u.config,y.currentConfig]),B=null!==(S=null==I?void 0:I.defaultLogic)&&void 0!==S?S:x,E=y.value,N=void 0===E?{values:[]}:E,T=r(null!==(F=N.logic)&&void 0!==F?F:B),D=o(T,2),P=D[0],_=D[1],H=null!==(M=u.forceLogic)&&void 0!==M?M:P,U=r(null),q=o(U,2),G=q[0],J=q[1],K=r([]),Q=o(K,2),W=Q[0],X=Q[1],Y=r(u.fetchOptions?"loading":"loaded"),Z=o(Y,2),$=Z[0],ll=Z[1],ol=t(null),el=function(){var l;if(u.fetchOptions){null===(l=ol.current)||void 0===l||l.abort();var o=new AbortController;ol.current=o,ll("loading"),u.fetchOptions(o.signal).then(function(l){X(l),ll("loaded")}).catch(function(l){var o;null===(o=y.onError)||void 0===o||o.call(y),"AbortError"!==(null==l?void 0:l.name)&&ll("error")})}};a(function(){return el(),function(){var l;return null===(l=ol.current)||void 0===l?void 0:l.abort()}},[]);var nl=u.fetchOptions?W:null!=L?L:[],il=P!==(null!==(R=N.logic)&&void 0!==R?R:B),rl=null!==G,tl=!rl&&!il,al=null!==(w=null==I?void 0:I.label)&&void 0!==w?w:I.field.toString(),ul=r({}),cl=o(ul,2),sl=cl[0],dl=cl[1],ml=function(l){y.onSubmit(I.field,l,I)},vl=h(sl,I.field),fl=i(function(){var l=Array.isArray(N.values)?N.values:[N.values];return{field:I.field,items:l.map(function(l){var o;return{value:l,label:null===(o=nl.find(function(o){return o.value===l}))||void 0===o?void 0:o.label}})}},[I.field,N,nl]),pl=null!=u.maxValueCount&&fl.items.length>=u.maxValueCount,bl=i(function(){var l=(null==u?void 0:u.top)||y.top;return l?e(s,{sx:{mb:1},children:l}):null},[null==u?void 0:u.top,y.top]),gl=[];return(y.isLoading||"loading"===$)&&gl.push("disabled"),e(O,{className:gl.join(" "),noValidate:!0,onSubmit:function(o){var e;if(o.preventDefault(),rl){if(!pl){var n=l({},I.field,G),i=null===(e=y.validator)||void 0===e?void 0:e.run(n);if(dl(i||{}),!i||0===Object.keys(i).length)ml({values:[G],logic:H}),J(null)}}else il&&ml({values:N.values,logic:H})},children:n(k,{title:"Filter by ".concat(al),onClose:y.onClose,slots:{beforeTitle:e(C,{size:"small",onClick:y.onBack}),afterTitle:u.forceLogic?null:I.singleValue?e(z,{sx:{ml:1.5},size:"small",label:"Last value only"}):e(j,{sx:{ml:1},value:H,onChange:function(l,o){_(o)}})},children:[n(V,{children:[bl,I.description&&e(d,{variant:"caption",color:"text.secondary",sx:{mb:1,display:"block"},children:I.description}),null!=u.maxValueCount&&e(d,{variant:"caption",color:pl?"warning.main":"text.secondary",sx:{mb:.5,display:"block"},children:u.maxValueCount?pl?"Maximum ".concat(u.maxValueCount," value").concat(u.maxValueCount>1?"s":""," selected (limit reached)"):"Up to ".concat(u.maxValueCount," value").concat(u.maxValueCount>1?"s":""," can be selected"):""}),e(c,{sx:{mb:1,borderBottom:"none!important"},label:"Applied",placement:"horizontal",enableMinimalesticView:!0,value:fl,onRemove:y.onRemove}),"loading"===$&&e(s,{sx:{display:"flex",justifyContent:"center",mt:2},children:e(m,{size:20})}),"error"===$&&n(s,{sx:{display:"flex",flexDirection:"column",alignItems:"center",mt:2,mb:3,gap:1},children:[e(g,{color:"error",fontSize:"large"}),e(d,{variant:"body2",color:"error",children:"Failed to load options"}),e(v,{size:"small",variant:"outlined",color:"error",onClick:el,children:"Retry"})]}),0===nl.length&&"loaded"===$&&e(d,{variant:"body2",color:"text.secondary",sx:{mt:2},children:"No options available"}),e(f,{sx:{mx:-1},name:I.field.toString(),value:null!=G?G:"",onChange:function(l){return J(l.target.value)},className:vl.error?"error":"",children:nl.map(function(l,o){var n,i=fl.items.some(function(o){return o.value===l.value});return e(p,{disabled:i||pl,value:l.value,control:e(b,{size:"small"}),label:e(d,{variant:"body2",children:null!==(n=l.label)&&void 0!==n?n:l.value})},l.value.toString()+o)})}),vl.error&&e(d,{variant:"caption",color:"error",sx:{mt:.5},children:vl.message})]}),n(A,{children:[e(v,{size:"small",color:"error",variant:"text",disabled:!N.values||0===N.values.length,onClick:function(){var l;null===(l=y.onRemoveField)||void 0===l||l.call(y,I.field,I)},children:"Clear All"}),e(s,{sx:{flex:1}}),e(v,{size:"small",color:"inherit",variant:"text",onClick:y.onClose,children:"Cancel"}),e(v,{size:"small",type:"submit",color:"primary",variant:"contained",disabled:tl,children:"Apply"})]})]})})}}var O=u("form")(l({position:"relative","&::after":{content:'""',display:"block",position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.12)",filter:"blur(2px)",zIndex:-1,opacity:0,transition:"opacity 0.3s",visibility:"hidden"},"&.disabled":{pointerEvents:"none","&::after":{zIndex:1,opacity:1,visibility:"visible"}}},".".concat(c.root),{"&.error .MuiRadio-root":{color:"#d32f2f"},".MuiFormControlLabel-root":{margin:0},".MuiFormControlLabel-root:hover":{backgroundColor:"rgba(25, 118, 210, 0.04)"}}));export{L as default};
2
2
  //# sourceMappingURL=create-form-field-select.js.map