dinocollab-core 2.2.16 → 2.2.18

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.
Files changed (30) hide show
  1. package/dist/filter-bar/index.js +1 -1
  2. package/dist/src/filter-bar/components/chip-viewer.js +1 -1
  3. package/dist/src/filter-bar/components/chip-viewer.js.map +1 -1
  4. package/dist/src/filter-bar/components/filter-input.js +1 -1
  5. package/dist/src/filter-bar/components/filter-input.js.map +1 -1
  6. package/dist/src/filter-bar/components/filter-summary.js +1 -1
  7. package/dist/src/filter-bar/components/filter-summary.js.map +1 -1
  8. package/dist/src/filter-bar/components/popper-custom.js +1 -1
  9. package/dist/src/filter-bar/components/popper-custom.js.map +1 -1
  10. package/dist/src/filter-bar/index.create.js.map +1 -1
  11. package/dist/src/filter-bar/index.dino.js +1 -1
  12. package/dist/src/filter-bar/index.dino.js.map +1 -1
  13. package/dist/src/filter-bar/menu/create-form-field-datetime.js +1 -1
  14. package/dist/src/filter-bar/menu/create-form-field-datetime.js.map +1 -1
  15. package/dist/src/filter-bar/menu/create-form-field-select-multiple.js +1 -1
  16. package/dist/src/filter-bar/menu/create-form-field-select-multiple.js.map +1 -1
  17. package/dist/src/filter-bar/menu/create-form-field-select.js +1 -1
  18. package/dist/src/filter-bar/menu/create-form-field-select.js.map +1 -1
  19. package/dist/src/filter-bar/menu/create-form-field-string.js +1 -1
  20. package/dist/src/filter-bar/menu/create-form-field-string.js.map +1 -1
  21. package/dist/src/filter-bar/menu/create.js +1 -1
  22. package/dist/src/filter-bar/menu/create.js.map +1 -1
  23. package/dist/types/filter-bar/components/chip-viewer.d.ts +2 -0
  24. package/dist/types/filter-bar/components/filter-summary.types.d.ts +8 -2
  25. package/dist/types/filter-bar/components/popper-custom.d.ts +4 -1
  26. package/dist/types/filter-bar/index.d.ts +1 -0
  27. package/dist/types/filter-bar/index.dino.d.ts +2 -1
  28. package/dist/types/filter-bar/menu/create-form-field-datetime.d.ts +10 -2
  29. package/dist/types/filter-bar/menu/types.d.ts +4 -0
  30. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sources":["../../../../src/filter-bar/menu/create.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { createRef, useContext, useMemo, useState } from 'react'\r\nimport { Badge, Box, Button, IconButton, MenuItem, MenuList, styled, Tooltip, Typography } from '@mui/material'\r\nimport FilterListIcon from '@mui/icons-material/FilterList'\r\nimport ClickAwayListener from '@mui/material/ClickAwayListener'\r\nimport { KeySpecial } from '../types'\r\nimport { useFilterActions } from '../hooks'\r\nimport { FilterBarContext } from '../index.context'\r\nimport { FilterMenuNoField } from '../components/ui.units'\r\nimport { mapSpecialLabel, mapSpecialTexts } from '../helpers'\r\nimport { FormValidator, SingleRuleValidate } from '../../form/validator'\r\nimport { PopperContent, PopperCustom, PopperFooter } from '../components/popper-custom'\r\nimport createFormFieldString from './create-form-field-string'\r\n// types\r\nimport type { FC } from 'react'\r\nimport type { IFilterBarContext } from '../index.context'\r\nimport type { TFieldModelValid, TFieldType, TFieldValue } from '../types'\r\nimport type { IConfigValue, IFormValidatorConfig } from '../../form/validator'\r\nimport type { IFilterMenuConfigInternal, TFieldMenuConfigsInternal } from './types'\r\nimport type { IFilterMenuProps, IFilterMenuSlots, TFieldMenuConfigs } from './types'\r\nimport type { IFieldMenuConfig, IFilterMenuConfig, IFilterMenuFormProps } from './types'\r\n\r\n// #region utils\r\n/**\r\n * Builds a map of `FormValidator` instances keyed by field name.\r\n * Each validator is constructed from the validation rules defined in `config.validation`.\r\n * Fields with no validation config are skipped.\r\n *\r\n * @internal\r\n */\r\nfunction generateValidatorMap<T>(config: IFilterMenuConfig<T>) {\r\n const keys = Object.keys(config.fields) as TFieldType<T>[]\r\n const validateMaps = keys.reduce(\r\n (acc, key) => {\r\n const fieldKey = key as TFieldType<T>\r\n const fieldConfig = config.validation?.[fieldKey]\r\n if (fieldConfig) {\r\n acc[fieldKey] = new FormValidator({ [fieldKey]: fieldConfig } as IFormValidatorConfig<Partial<TFieldModelValid<T>>>)\r\n }\r\n return acc\r\n },\r\n {} as Record<TFieldType<T>, FormValidator<Partial<TFieldModelValid<T>>>>\r\n )\r\n return validateMaps\r\n}\r\n\r\n/**\r\n * Builds a map of form input components keyed by field name.\r\n * If a field defines a custom `FormComponent`, that is used; otherwise falls back to\r\n * the default `createFormFieldString()` free-text component.\r\n *\r\n * @internal\r\n */\r\nfunction generateFormInputMap<T>(config: IFilterMenuConfig<T>) {\r\n const { fields } = config\r\n const keys = Object.keys(fields) as TFieldType<T>[]\r\n const formInputMaps = keys.reduce(\r\n (acc, key) => {\r\n const fieldKey = key as TFieldType<T>\r\n const fieldConfig = fields[fieldKey] as IFieldMenuConfig<T>\r\n if (fieldConfig) {\r\n acc[fieldKey] = fieldConfig.FormComponent ?? createFormFieldString()\r\n }\r\n return acc\r\n },\r\n {} as Record<TFieldType<T>, React.ComponentType<IFilterMenuFormProps<T>>>\r\n )\r\n return formInputMaps\r\n}\r\n\r\n/**\r\n * Normalises a raw `IFilterMenuConfig` into the internal format used by the menu:\r\n * - Injects the quick-search pseudo-field when `enableQuickSearch` is `true` (default)\r\n * - Stamps each field entry with its own `field` key\r\n * - Ensures every field has at least a `Required` validation rule\r\n *\r\n * @internal\r\n */\r\nfunction generateConfigs<T>(config: IFilterMenuConfig<T>): IFilterMenuConfigInternal<T> {\r\n const { fields, validation, enableQuickSearch = true, ...rest } = config\r\n const qsKey = KeySpecial.quickSearch\r\n\r\n // Merge quick search field if enabled\r\n const mergedFields: TFieldMenuConfigs<T> = { ...fields }\r\n if (enableQuickSearch) {\r\n const item = mergedFields[qsKey]\r\n const label = item?.label ? item.label : mapSpecialLabel[qsKey]\r\n const temp = Object.assign({}, mergedFields[qsKey], { field: qsKey, label, singleValue: true })\r\n mergedFields[qsKey] = temp\r\n } else {\r\n delete mergedFields[qsKey]\r\n }\r\n\r\n const keys = Object.keys(mergedFields) as TFieldType<T>[]\r\n const finalFields = keys.reduce<TFieldMenuConfigsInternal<T>>((acc, key) => {\r\n const fieldConfig = mergedFields[key]\r\n if (!fieldConfig) return acc\r\n acc[key] = { ...fieldConfig, field: key }\r\n return acc\r\n }, {} as TFieldMenuConfigsInternal<T>)\r\n\r\n // Merge validation config with default required rule\r\n const mergedValidation: IFormValidatorConfig<Partial<TFieldModelValid<T>>> = { ...validation }\r\n keys.forEach((key) => {\r\n const item: IConfigValue<Partial<TFieldModelValid<T>>> | undefined = mergedValidation[key]\r\n const label = item?.label ?? mergedFields[key]?.label ?? key.toString()\r\n if (!item) {\r\n mergedValidation[key] = { Rules: [{ rule: SingleRuleValidate.Required }], label }\r\n } else if (!item.Rules.some((r) => r.rule === SingleRuleValidate.Required)) {\r\n item.label = label\r\n item.Rules.push({ rule: SingleRuleValidate.Required })\r\n }\r\n })\r\n\r\n return { ...rest, fields: finalFields, validation: mergedValidation, enableQuickSearch }\r\n}\r\n// #endregion\r\n\r\n// #region main\r\n/**\r\n * Factory function that creates a `FilterMenu` component from a static field configuration.\r\n *\r\n * The generated component renders a badge icon button that opens a popper panel with:\r\n * - A **field list** view — lists all configured filter fields with applied-value counts\r\n * - A **field form** view — renders the appropriate input component for the selected field\r\n * - A **quick-search** field (opt-out via `enableQuickSearch: false`)\r\n * - OR / AND logic toggle support per field\r\n * - \"Clear All\" action to reset all active filters at once\r\n *\r\n * All state (open/close, selected field) is local; filter values are read/written through\r\n * `FilterBarContext` via `useFilterActions`.\r\n *\r\n * @param config - Static filter-menu configuration (fields, validation, slots, etc.)\r\n * @returns A React FC ready to be dropped anywhere inside a `FilterBarProvider`\r\n */\r\nexport function createFilterMenu<T>(config: IFilterMenuConfig<T>) {\r\n const classes = filterMenuClasses\r\n const mergedConfigs = generateConfigs(config)\r\n const validateMaps = generateValidatorMap(mergedConfigs)\r\n const formInputMaps = generateFormInputMap(mergedConfigs)\r\n const quickSearchHint = config.quickSearchHint\r\n\r\n // Component\r\n const FilterMenu: FC<IFilterMenuProps<T>> = (props) => {\r\n const refButton = createRef<HTMLButtonElement>()\r\n\r\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)\r\n const isOpen = Boolean(anchorEl)\r\n\r\n const context = useContext(FilterBarContext) as IFilterBarContext<T>\r\n const filterActions = useFilterActions<T>(context)\r\n\r\n const [fieldSelected, setFieldSelected] = useState<TFieldType<T> | null>(null)\r\n\r\n const mergedSlots = useMemo<IFilterMenuSlots>(() => {\r\n const { popperProps, rootProps } = config\r\n return Object.assign({}, { popperProps, rootProps }, props.slots)\r\n }, [config, props.slots])\r\n\r\n const handleClose = () => {\r\n setAnchorEl(null)\r\n setTimeout(() => {\r\n setFieldSelected(null)\r\n }, 300)\r\n }\r\n\r\n const handleOpen = () => {\r\n setFieldSelected(null)\r\n setAnchorEl(refButton.current)\r\n }\r\n\r\n const handleMenuItemClick = (field: TFieldType<T>) => {\r\n setFieldSelected(field)\r\n }\r\n\r\n const handleClearAll = () => {\r\n filterActions.clearAllFilters()\r\n handleClose()\r\n }\r\n\r\n const handleSubmit = async (key: TFieldType<T>, value?: TFieldValue, fieldConfig?: IFieldMenuConfig<T>) => {\r\n if (!value) return\r\n if (fieldConfig?.singleValue || fieldConfig?.replaceValue) {\r\n filterActions.replaceFilter(key, value, { logic: value.logic })\r\n } else {\r\n filterActions.upsertManyFilter(key, value, { logic: value.logic })\r\n }\r\n if (config?.closeAfterSubmit !== false && fieldConfig?.closeAfterSubmit !== false) {\r\n handleClose()\r\n }\r\n }\r\n\r\n const data = useMemo(() => {\r\n const keys = Object.values(mergedConfigs.fields)\r\n return Array.from(keys) as IFieldMenuConfig<T>[]\r\n }, [mergedConfigs.fields])\r\n\r\n const renderContent = () => {\r\n if (data.length === 0) {\r\n return <FilterMenuNoField onClose={handleClose} />\r\n }\r\n const currentConfig = fieldSelected ? mergedConfigs.fields[fieldSelected] : undefined\r\n\r\n if (fieldSelected && currentConfig) {\r\n const FormComponent = formInputMaps[fieldSelected] as React.ComponentType<IFilterMenuFormProps<T>>\r\n if (!FormComponent) return null\r\n\r\n const config: IFieldMenuConfig<T> = { ...currentConfig }\r\n // Remove FormComponent from config before passing to form, as it's not needed there and can cause unnecessary re-renders\r\n if (config?.FormComponent) delete config.FormComponent\r\n\r\n const value = context.filterState.storeFilter?.[fieldSelected]\r\n return (\r\n <FormComponent\r\n currentConfig={config}\r\n value={value}\r\n isLoading={context.isLoading}\r\n onRemove={filterActions.removeFilterByFieldValue}\r\n validator={validateMaps[fieldSelected]}\r\n onSubmit={handleSubmit}\r\n onClose={handleClose}\r\n onRemoveField={(f) => filterActions.removeFilter(f)}\r\n onBack={() => setFieldSelected(null)}\r\n />\r\n )\r\n }\r\n\r\n return (\r\n <PopperContent title='Filter by' onClose={handleClose}>\r\n <MenuListCustom className={classes.menu}>\r\n {data.map((item) => {\r\n const key = item.field.toString()\r\n if (!key) return null\r\n const info = filterActions.getFieldInfo(item.field)\r\n const note = info?.values.join(', ') ?? ''\r\n const fieldCount = info ? info.values.length : 0\r\n const suffix = fieldCount > 0 ? ` (${fieldCount})` : ''\r\n const label = item.label ?? key.toString()\r\n let tooltipTitle = fieldCount > 0 ? `Filter by ${label}: ${note}` : undefined\r\n if (item.field === KeySpecial.quickSearch) {\r\n const txt = mapSpecialTexts.qsTooltip\r\n tooltipTitle = typeof quickSearchHint === 'function' ? quickSearchHint(txt) : (quickSearchHint ?? txt)\r\n } else if (item.tooltip) {\r\n const tooltip = typeof item.tooltip === 'function' ? item.tooltip(info?.values) : item.tooltip\r\n tooltipTitle = (info?.values.length ?? 0) > 0 ? tooltip : undefined\r\n }\r\n return (\r\n <MenuItem\r\n key={key}\r\n className={classes.menuItem}\r\n sx={{ justifyContent: 'space-between' }}\r\n onClick={() => handleMenuItemClick(item.field)}\r\n >\r\n <Tooltip title={tooltipTitle} placement='right' arrow>\r\n <div className={classes.menuItemInner}>\r\n <Typography variant='body2'>{label}</Typography>\r\n <Typography variant='caption' sx={{ ml: 1, color: 'text.secondary' }}>\r\n {suffix}\r\n </Typography>\r\n </div>\r\n </Tooltip>\r\n </MenuItem>\r\n )\r\n })}\r\n </MenuListCustom>\r\n <PopperFooter>\r\n <Button color='error' disabled={filterCount === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n )\r\n }\r\n\r\n const filterCount = filterActions.getTotalCount()\r\n const iconTitle = `${filterCount} Filter${filterCount !== 1 ? 's' : ''}`\r\n return (\r\n <ClickAwayListener onClickAway={handleClose}>\r\n <FilterInputStyled className={classes.root} {...mergedSlots.rootProps}>\r\n <Tooltip title={iconTitle} arrow placement='top'>\r\n <IconButton size='small' ref={refButton} onClick={handleOpen}>\r\n <Badge badgeContent={filterCount} color='primary' invisible={filterCount === 0}>\r\n <FilterListIcon fontSize='small' />\r\n </Badge>\r\n </IconButton>\r\n </Tooltip>\r\n <PopperCustom open={isOpen} anchorEl={anchorEl} placement='bottom' transition disablePortal {...mergedSlots.popperProps}>\r\n {renderContent()}\r\n </PopperCustom>\r\n </FilterInputStyled>\r\n </ClickAwayListener>\r\n )\r\n }\r\n return FilterMenu\r\n}\r\n// #endregion\r\n\r\n// #region styles\r\n/** CSS class names used by the `FilterMenu` component for external style overrides. */\r\nexport const filterMenuClasses = {\r\n root: 'DinoFilterMenu-root',\r\n input: 'DinoFilterMenu-input',\r\n beforeInput: 'DinoFilterMenu-beforeInput',\r\n menu: 'DinoFilterMenu-menu',\r\n menuItem: 'DinoFilterMenu-menuItem',\r\n menuItemInner: 'DinoFilterMenu-menuItemInner'\r\n}\r\n\r\nconst FilterInputStyled = styled(Box)({\r\n [`&.${filterMenuClasses.root}`]: {\r\n display: 'inline-flex',\r\n justifyContent: 'center',\r\n alignItems: 'center',\r\n flex: '0 0 auto'\r\n }\r\n})\r\n\r\nconst MenuListCustom = styled(MenuList)({\r\n [`.${filterMenuClasses.menuItem}`]: { paddingTop: 0, paddingBottom: 0 },\r\n [`.${filterMenuClasses.menuItemInner}`]: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'center',\r\n width: '100%',\r\n gap: '4px',\r\n paddingTop: '6px',\r\n paddingBottom: '6px'\r\n }\r\n})\r\n// #endregion\r\n"],"names":["createFilterMenu","config","classes","filterMenuClasses","mergedConfigs","fields","validation","_config$enableQuickSe","enableQuickSearch","rest","_objectWithoutProperties","_excluded","qsKey","KeySpecial","quickSearch","mergedFields","_objectSpread","item","label","mapSpecialLabel","temp","Object","assign","field","singleValue","keys","finalFields","reduce","acc","key","fieldConfig","mergedValidation","forEach","_ref","_item$label","_mergedFields$key","toString","Rules","some","r","rule","SingleRuleValidate","Required","push","generateConfigs","validateMaps","_config$validation","fieldKey","FormValidator","_defineProperty","generateValidatorMap","formInputMaps","_fieldConfig$FormComp","FormComponent","createFormFieldString","generateFormInputMap","quickSearchHint","props","refButton","createRef","_useState","useState","_useState2","_slicedToArray","anchorEl","setAnchorEl","isOpen","Boolean","context","useContext","FilterBarContext","filterActions","useFilterActions","_useState3","_useState4","fieldSelected","setFieldSelected","mergedSlots","useMemo","popperProps","rootProps","slots","handleClose","setTimeout","handleClearAll","clearAllFilters","handleSubmit","_ref2","_asyncToGenerator","_regenerator","m","_callee","value","w","_context","n","a","replaceValue","replaceFilter","logic","upsertManyFilter","closeAfterSubmit","_x","_x2","_x3","apply","this","arguments","data","values","Array","from","filterCount","getTotalCount","iconTitle","concat","_jsx","ClickAwayListener","onClickAway","children","_jsxs","FilterInputStyled","className","root","Tooltip","title","arrow","placement","IconButton","size","ref","onClick","current","Badge","badgeContent","color","invisible","FilterListIcon","fontSize","PopperCustom","open","transition","disablePortal","length","FilterMenuNoField","onClose","currentConfig","undefined","_context$filterState$","filterState","storeFilter","isLoading","onRemove","removeFilterByFieldValue","validator","onSubmit","onRemoveField","f","removeFilter","onBack","PopperContent","MenuListCustom","menu","map","_info$values$join","_item$label2","info","getFieldInfo","note","join","fieldCount","suffix","tooltipTitle","txt","mapSpecialTexts","qsTooltip","tooltip","_info$values$length","MenuItem","menuItem","sx","justifyContent","menuItemInner","Typography","variant","ml","PopperFooter","Button","disabled","renderContent","styled","Box","display","alignItems","flex","MenuList","paddingTop","paddingBottom","width","gap"],"mappings":"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"}
1
+ {"version":3,"file":"create.js","sources":["../../../../src/filter-bar/menu/create.tsx"],"sourcesContent":["// Copyright (c) 2024-present, Dinocollab Technologies, Inc. and its affiliates. All rights reserved.\r\n\r\n// imports\r\nimport { createRef, useContext, useMemo, useState } from 'react'\r\nimport { Badge, Box, Button, IconButton, MenuItem, MenuList, styled, Tooltip, Typography } from '@mui/material'\r\nimport FilterListIcon from '@mui/icons-material/FilterList'\r\nimport ClickAwayListener from '@mui/material/ClickAwayListener'\r\nimport { KeySpecial } from '../types'\r\nimport { useFilterActions } from '../hooks'\r\nimport { FilterBarContext } from '../index.context'\r\nimport { FilterMenuNoField } from '../components/ui.units'\r\nimport { mapSpecialLabel, mapSpecialTexts } from '../helpers'\r\nimport { FormValidator, SingleRuleValidate } from '../../form/validator'\r\nimport { PopperBody, PopperContent, PopperCustom, PopperFooter } from '../components/popper-custom'\r\nimport createFormFieldString from './create-form-field-string'\r\n// types\r\nimport type { FC } from 'react'\r\nimport type { IFilterBarContext } from '../index.context'\r\nimport type { TFieldModelValid, TFieldType, TFieldValue } from '../types'\r\nimport type { IConfigValue, IFormValidatorConfig } from '../../form/validator'\r\nimport type { IFilterMenuConfigInternal, TFieldMenuConfigsInternal } from './types'\r\nimport type { IFilterMenuProps, IFilterMenuSlots, TFieldMenuConfigs } from './types'\r\nimport type { IFieldMenuConfig, IFilterMenuConfig, IFilterMenuFormProps } from './types'\r\n\r\n// #region utils\r\n/**\r\n * Builds a map of `FormValidator` instances keyed by field name.\r\n * Each validator is constructed from the validation rules defined in `config.validation`.\r\n * Fields with no validation config are skipped.\r\n *\r\n * @internal\r\n */\r\nfunction generateValidatorMap<T>(config: IFilterMenuConfig<T>) {\r\n const keys = Object.keys(config.fields) as TFieldType<T>[]\r\n const validateMaps = keys.reduce(\r\n (acc, key) => {\r\n const fieldKey = key as TFieldType<T>\r\n const fieldConfig = config.validation?.[fieldKey]\r\n if (fieldConfig) {\r\n acc[fieldKey] = new FormValidator({ [fieldKey]: fieldConfig } as IFormValidatorConfig<Partial<TFieldModelValid<T>>>)\r\n }\r\n return acc\r\n },\r\n {} as Record<TFieldType<T>, FormValidator<Partial<TFieldModelValid<T>>>>\r\n )\r\n return validateMaps\r\n}\r\n\r\n/**\r\n * Builds a map of form input components keyed by field name.\r\n * If a field defines a custom `FormComponent`, that is used; otherwise falls back to\r\n * the default `createFormFieldString()` free-text component.\r\n *\r\n * @internal\r\n */\r\nfunction generateFormInputMap<T>(config: IFilterMenuConfig<T>) {\r\n const { fields } = config\r\n const keys = Object.keys(fields) as TFieldType<T>[]\r\n const formInputMaps = keys.reduce(\r\n (acc, key) => {\r\n const fieldKey = key as TFieldType<T>\r\n const fieldConfig = fields[fieldKey] as IFieldMenuConfig<T>\r\n if (fieldConfig) {\r\n acc[fieldKey] = fieldConfig.FormComponent ?? createFormFieldString()\r\n }\r\n return acc\r\n },\r\n {} as Record<TFieldType<T>, React.ComponentType<IFilterMenuFormProps<T>>>\r\n )\r\n return formInputMaps\r\n}\r\n\r\n/**\r\n * Normalises a raw `IFilterMenuConfig` into the internal format used by the menu:\r\n * - Injects the quick-search pseudo-field when `enableQuickSearch` is `true` (default)\r\n * - Stamps each field entry with its own `field` key\r\n * - Ensures every field has at least a `Required` validation rule\r\n *\r\n * @internal\r\n */\r\nfunction generateConfigs<T>(config: IFilterMenuConfig<T>): IFilterMenuConfigInternal<T> {\r\n const { fields, validation, enableQuickSearch = true, ...rest } = config\r\n const qsKey = KeySpecial.quickSearch\r\n\r\n // Merge quick search field if enabled\r\n const mergedFields: TFieldMenuConfigs<T> = { ...fields }\r\n if (enableQuickSearch) {\r\n const item = mergedFields[qsKey]\r\n const label = item?.label ? item.label : mapSpecialLabel[qsKey]\r\n const temp = Object.assign({}, mergedFields[qsKey], { field: qsKey, label, singleValue: true })\r\n mergedFields[qsKey] = temp\r\n } else {\r\n delete mergedFields[qsKey]\r\n }\r\n\r\n const keys = Object.keys(mergedFields) as TFieldType<T>[]\r\n const finalFields = keys.reduce<TFieldMenuConfigsInternal<T>>((acc, key) => {\r\n const fieldConfig = mergedFields[key]\r\n if (!fieldConfig) return acc\r\n acc[key] = { ...fieldConfig, field: key }\r\n return acc\r\n }, {} as TFieldMenuConfigsInternal<T>)\r\n\r\n // Merge validation config with default required rule\r\n const mergedValidation: IFormValidatorConfig<Partial<TFieldModelValid<T>>> = { ...validation }\r\n keys.forEach((key) => {\r\n const item: IConfigValue<Partial<TFieldModelValid<T>>> | undefined = mergedValidation[key]\r\n const label = item?.label ?? mergedFields[key]?.label ?? key.toString()\r\n if (!item) {\r\n mergedValidation[key] = { Rules: [{ rule: SingleRuleValidate.Required }], label }\r\n } else if (!item.Rules.some((r) => r.rule === SingleRuleValidate.Required)) {\r\n item.label = label\r\n item.Rules.push({ rule: SingleRuleValidate.Required })\r\n }\r\n })\r\n\r\n return { ...rest, fields: finalFields, validation: mergedValidation, enableQuickSearch }\r\n}\r\n// #endregion\r\n\r\n// #region main\r\n/**\r\n * Factory function that creates a `FilterMenu` component from a static field configuration.\r\n *\r\n * The generated component renders a badge icon button that opens a popper panel with:\r\n * - A **field list** view — lists all configured filter fields with applied-value counts\r\n * - A **field form** view — renders the appropriate input component for the selected field\r\n * - A **quick-search** field (opt-out via `enableQuickSearch: false`)\r\n * - OR / AND logic toggle support per field\r\n * - \"Clear All\" action to reset all active filters at once\r\n *\r\n * All state (open/close, selected field) is local; filter values are read/written through\r\n * `FilterBarContext` via `useFilterActions`.\r\n *\r\n * @param config - Static filter-menu configuration (fields, validation, slots, etc.)\r\n * @returns A React FC ready to be dropped anywhere inside a `FilterBarProvider`\r\n */\r\nexport function createFilterMenu<T>(config: IFilterMenuConfig<T>) {\r\n const classes = filterMenuClasses\r\n const mergedConfigs = generateConfigs(config)\r\n const validateMaps = generateValidatorMap(mergedConfigs)\r\n const formInputMaps = generateFormInputMap(mergedConfigs)\r\n const quickSearchHint = config.quickSearchHint\r\n\r\n // Component\r\n const FilterMenu: FC<IFilterMenuProps<T>> = (props) => {\r\n const refButton = createRef<HTMLButtonElement>()\r\n\r\n const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)\r\n const isOpen = Boolean(anchorEl)\r\n\r\n const context = useContext(FilterBarContext) as IFilterBarContext<T>\r\n const filterActions = useFilterActions<T>(context)\r\n\r\n const [fieldSelected, setFieldSelected] = useState<TFieldType<T> | null>(null)\r\n\r\n const mergedSlots = useMemo<IFilterMenuSlots>(() => {\r\n const { popperProps, rootProps } = config\r\n return Object.assign({}, { popperProps, rootProps }, props.slots)\r\n }, [config, props.slots])\r\n\r\n const handleClose = () => {\r\n setAnchorEl(null)\r\n setTimeout(() => {\r\n setFieldSelected(null)\r\n }, 300)\r\n }\r\n\r\n const handleOpen = () => {\r\n setFieldSelected(null)\r\n setAnchorEl(refButton.current)\r\n }\r\n\r\n const handleMenuItemClick = (field: TFieldType<T>) => {\r\n setFieldSelected(field)\r\n }\r\n\r\n const handleClearAll = () => {\r\n filterActions.clearAllFilters()\r\n handleClose()\r\n }\r\n\r\n const handleSubmit = async (key: TFieldType<T>, value?: TFieldValue, fieldConfig?: IFieldMenuConfig<T>) => {\r\n if (!value) return\r\n if (fieldConfig?.singleValue || fieldConfig?.replaceValue) {\r\n filterActions.replaceFilter(key, value, { logic: value.logic })\r\n } else {\r\n filterActions.upsertManyFilter(key, value, { logic: value.logic })\r\n }\r\n if (config?.closeAfterSubmit !== false && fieldConfig?.closeAfterSubmit !== false) {\r\n handleClose()\r\n }\r\n }\r\n\r\n const data = useMemo(() => {\r\n const keys = Object.values(mergedConfigs.fields)\r\n return Array.from(keys) as IFieldMenuConfig<T>[]\r\n }, [mergedConfigs.fields])\r\n\r\n const renderContent = () => {\r\n if (data.length === 0) {\r\n return <FilterMenuNoField onClose={handleClose} />\r\n }\r\n const currentConfig = fieldSelected ? mergedConfigs.fields[fieldSelected] : undefined\r\n\r\n if (fieldSelected && currentConfig) {\r\n const FormComponent = formInputMaps[fieldSelected] as React.ComponentType<IFilterMenuFormProps<T>>\r\n if (!FormComponent) return null\r\n\r\n const config: IFieldMenuConfig<T> = { ...currentConfig }\r\n // Remove FormComponent from config before passing to form, as it's not needed there and can cause unnecessary re-renders\r\n if (config?.FormComponent) delete config.FormComponent\r\n\r\n const value = context.filterState.storeFilter?.[fieldSelected]\r\n return (\r\n <FormComponent\r\n currentConfig={config}\r\n value={value}\r\n isLoading={context.isLoading}\r\n onRemove={filterActions.removeFilterByFieldValue}\r\n validator={validateMaps[fieldSelected]}\r\n onSubmit={handleSubmit}\r\n onClose={handleClose}\r\n onRemoveField={(f) => filterActions.removeFilter(f)}\r\n onBack={() => setFieldSelected(null)}\r\n />\r\n )\r\n }\r\n\r\n return (\r\n <PopperContent title='Filter by' onClose={handleClose}>\r\n <PopperBody disableGutter>\r\n <MenuListCustom className={classes.menu}>\r\n {data.map((item) => {\r\n const key = item.field.toString()\r\n if (!key) return null\r\n const info = filterActions.getFieldInfo(item.field)\r\n const note = info?.values.join(', ') ?? ''\r\n const fieldCount = info ? info.values.length : 0\r\n const suffix = fieldCount > 0 ? ` (${fieldCount})` : ''\r\n const label = item.label ?? key.toString()\r\n let tooltipTitle = fieldCount > 0 ? `Filter by ${label}: ${note}` : undefined\r\n if (item.field === KeySpecial.quickSearch) {\r\n const txt = mapSpecialTexts.qsTooltip\r\n tooltipTitle = typeof quickSearchHint === 'function' ? quickSearchHint(txt) : (quickSearchHint ?? txt)\r\n } else if (item.tooltip) {\r\n const tooltip = typeof item.tooltip === 'function' ? item.tooltip(info?.values) : item.tooltip\r\n tooltipTitle = (info?.values.length ?? 0) > 0 ? tooltip : undefined\r\n }\r\n return (\r\n <MenuItem\r\n key={key}\r\n className={classes.menuItem}\r\n sx={{ justifyContent: 'space-between' }}\r\n onClick={() => handleMenuItemClick(item.field)}\r\n >\r\n <Tooltip title={tooltipTitle} placement='right' arrow>\r\n <div className={classes.menuItemInner}>\r\n <Typography variant='body2'>{label}</Typography>\r\n <Typography variant='caption' sx={{ ml: 1, color: 'text.secondary' }}>\r\n {suffix}\r\n </Typography>\r\n </div>\r\n </Tooltip>\r\n </MenuItem>\r\n )\r\n })}\r\n </MenuListCustom>\r\n </PopperBody>\r\n <PopperFooter>\r\n <Button color='error' disabled={filterCount === 0} onClick={handleClearAll}>\r\n Clear All\r\n </Button>\r\n </PopperFooter>\r\n </PopperContent>\r\n )\r\n }\r\n\r\n const filterCount = filterActions.getTotalCount()\r\n const iconTitle = `${filterCount} Filter${filterCount !== 1 ? 's' : ''}`\r\n return (\r\n <ClickAwayListener onClickAway={handleClose}>\r\n <FilterInputStyled className={classes.root} {...mergedSlots.rootProps}>\r\n <Tooltip title={iconTitle} arrow placement='top'>\r\n <IconButton size='small' ref={refButton} onClick={handleOpen}>\r\n <Badge badgeContent={filterCount} color='primary' invisible={filterCount === 0}>\r\n <FilterListIcon fontSize='small' />\r\n </Badge>\r\n </IconButton>\r\n </Tooltip>\r\n <PopperCustom open={isOpen} anchorEl={anchorEl} placement='bottom' transition disablePortal {...mergedSlots.popperProps}>\r\n {renderContent()}\r\n </PopperCustom>\r\n </FilterInputStyled>\r\n </ClickAwayListener>\r\n )\r\n }\r\n return FilterMenu\r\n}\r\n// #endregion\r\n\r\n// #region styles\r\n/** CSS class names used by the `FilterMenu` component for external style overrides. */\r\nexport const filterMenuClasses = {\r\n root: 'DinoFilterMenu-root',\r\n input: 'DinoFilterMenu-input',\r\n beforeInput: 'DinoFilterMenu-beforeInput',\r\n menu: 'DinoFilterMenu-menu',\r\n menuItem: 'DinoFilterMenu-menuItem',\r\n menuItemInner: 'DinoFilterMenu-menuItemInner'\r\n}\r\n\r\nconst FilterInputStyled = styled(Box)({\r\n [`&.${filterMenuClasses.root}`]: {\r\n display: 'inline-flex',\r\n justifyContent: 'center',\r\n alignItems: 'center',\r\n flex: '0 0 auto'\r\n }\r\n})\r\n\r\nconst MenuListCustom = styled(MenuList)({\r\n [`.${filterMenuClasses.menuItem}`]: { paddingTop: 0, paddingBottom: 0 },\r\n [`.${filterMenuClasses.menuItemInner}`]: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'center',\r\n width: '100%',\r\n gap: '4px',\r\n paddingTop: '6px',\r\n paddingBottom: '6px'\r\n }\r\n})\r\n// #endregion\r\n"],"names":["createFilterMenu","config","classes","filterMenuClasses","mergedConfigs","fields","validation","_config$enableQuickSe","enableQuickSearch","rest","_objectWithoutProperties","_excluded","qsKey","KeySpecial","quickSearch","mergedFields","_objectSpread","item","label","mapSpecialLabel","temp","Object","assign","field","singleValue","keys","finalFields","reduce","acc","key","fieldConfig","mergedValidation","forEach","_ref","_item$label","_mergedFields$key","toString","Rules","some","r","rule","SingleRuleValidate","Required","push","generateConfigs","validateMaps","_config$validation","fieldKey","FormValidator","_defineProperty","generateValidatorMap","formInputMaps","_fieldConfig$FormComp","FormComponent","createFormFieldString","generateFormInputMap","quickSearchHint","props","refButton","createRef","_useState","useState","_useState2","_slicedToArray","anchorEl","setAnchorEl","isOpen","Boolean","context","useContext","FilterBarContext","filterActions","useFilterActions","_useState3","_useState4","fieldSelected","setFieldSelected","mergedSlots","useMemo","popperProps","rootProps","slots","handleClose","setTimeout","handleClearAll","clearAllFilters","handleSubmit","_ref2","_asyncToGenerator","_regenerator","m","_callee","value","w","_context","n","a","replaceValue","replaceFilter","logic","upsertManyFilter","closeAfterSubmit","_x","_x2","_x3","apply","this","arguments","data","values","Array","from","filterCount","getTotalCount","iconTitle","concat","_jsx","ClickAwayListener","onClickAway","children","_jsxs","FilterInputStyled","className","root","Tooltip","title","arrow","placement","IconButton","size","ref","onClick","current","Badge","badgeContent","color","invisible","FilterListIcon","fontSize","PopperCustom","open","transition","disablePortal","length","FilterMenuNoField","onClose","currentConfig","undefined","_context$filterState$","filterState","storeFilter","isLoading","onRemove","removeFilterByFieldValue","validator","onSubmit","onRemoveField","f","removeFilter","onBack","PopperContent","PopperBody","disableGutter","MenuListCustom","menu","map","_info$values$join","_item$label2","info","getFieldInfo","note","join","fieldCount","suffix","tooltipTitle","txt","mapSpecialTexts","qsTooltip","tooltip","_info$values$length","MenuItem","menuItem","sx","justifyContent","menuItemInner","Typography","variant","ml","PopperFooter","Button","disabled","renderContent","styled","Box","display","alignItems","flex","MenuList","paddingTop","paddingBottom","width","gap"],"mappings":"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"}
@@ -10,6 +10,7 @@ export interface TChipViewerGroup<T, O = any> {
10
10
  field: TFieldType<T>;
11
11
  label?: string;
12
12
  items: IChipViewerItem<O>[];
13
+ chipMinWidth?: number | string;
13
14
  }
14
15
  export type TOnRemoveFilterFunc<T> = (field: TFieldType<T>, value: TFieldValid) => void;
15
16
  interface IChipViewerProps<T> {
@@ -21,6 +22,7 @@ interface IChipViewerProps<T> {
21
22
  /** Enable minimalistic view: only show the last item, hide the rest as an icon at the start */
22
23
  enableMinimalesticView?: boolean;
23
24
  sx?: SxProps<Theme>;
25
+ forceShowAll?: boolean;
24
26
  }
25
27
  export declare function createChipViewers<T>(): FC<IChipViewerProps<T>>;
26
28
  export {};
@@ -1,9 +1,15 @@
1
1
  import { BoxProps } from '@mui/material';
2
- import type { TFieldType, TFieldValid } from '../types';
2
+ import type { TFieldType, TFieldValid, TFieldValue } from '../types';
3
3
  export interface IFieldSummaryConfig<T> {
4
4
  field: TFieldType<T>;
5
5
  label?: string;
6
- labelFormatter?: (value: TFieldValid) => string | undefined;
6
+ labelFormatter?: (value: TFieldValid, index: number, fieldValue: TFieldValue) => string | undefined;
7
+ /** When true, all values are collapsed into a single chip. Clicking X removes the entire field. */
8
+ singleChip?: boolean;
9
+ /** Separator used to join labels in singleChip mode. @default ', ' */
10
+ singleChipSeparator?: string;
11
+ /** Minimum width of the chip(s) for this field. */
12
+ chipMinWidth?: number | string;
7
13
  }
8
14
  export type TFieldSummaryConfigs<T> = Partial<Record<TFieldType<T>, Omit<IFieldSummaryConfig<T>, 'field'>>>;
9
15
  export interface IFilterSummaryConfig<T> {
@@ -24,5 +24,8 @@ export interface PopperContentProps extends BoxProps {
24
24
  }
25
25
  export declare const PopperContent: FC<PopperContentProps>;
26
26
  export declare const PopperFooter: FC<BoxProps & Required<PropsWithChildren>>;
27
- export declare const PopperBody: FC<BoxProps & Required<PropsWithChildren>>;
27
+ interface IPopperBodyProps extends BoxProps, PropsWithChildren {
28
+ disableGutter?: boolean;
29
+ }
30
+ export declare const PopperBody: FC<IPopperBodyProps>;
28
31
  export {};
@@ -6,3 +6,4 @@ export * from './local-filter-builder';
6
6
  export * from './index.dino';
7
7
  export type { IFieldSelectOption } from './menu/create-form-field-select';
8
8
  export type { IFormFieldDateTimeParam, TDateTimePickerType, TDateTimeMode } from './menu/create-form-field-datetime';
9
+ export * from './menu/create-form-field-datetime';
@@ -3,7 +3,7 @@ import { getFilterFromURL, isEmptyFilterState, isFilterStateEqual, removeNullVal
3
3
  import createFormFieldString from './menu/create-form-field-string';
4
4
  import createFormFieldSelect from './menu/create-form-field-select';
5
5
  import createFormFieldSelectMultiple from './menu/create-form-field-select-multiple';
6
- import createFormFieldDateTime from './menu/create-form-field-datetime';
6
+ import createFormFieldDateTime, { formatterDateTime } from './menu/create-form-field-datetime';
7
7
  export declare class DinoFilterBar {
8
8
  createFilterBar: typeof createFilterBar;
9
9
  createConvertToGraphQL: <TSource extends Record<string, any>, TTarget extends object>(state: import("./types").TFilterState<TSource>) => import("./convert-to-graphql").TableFileterConverter<TSource, TTarget>;
@@ -14,6 +14,7 @@ export declare class DinoFilterBar {
14
14
  createFormFieldDateTime: typeof createFormFieldDateTime;
15
15
  mapLogic: (logic?: import("./types").TLogic | undefined) => "Or" | "And";
16
16
  mapDirection: (direction?: import("./types").TDirection | undefined) => "ASC" | "DESC";
17
+ formatterDateTime: typeof formatterDateTime;
17
18
  isEmptyFilterState: typeof isEmptyFilterState;
18
19
  removeNullValues: typeof removeNullValues;
19
20
  isFilterStateEqual: typeof isFilterStateEqual;
@@ -1,5 +1,5 @@
1
1
  import type { FC } from 'react';
2
- import type { TDateLogic } from '../types';
2
+ import type { TDateLogic, TFieldValid } from '../types';
3
3
  import type { IFieldMenuConfig, IFilterMenuFormProps } from './types';
4
4
  /** Date logic options available in `single` mode. */
5
5
  export type TDateSingleLogic = Exclude<TDateLogic, 'range'>;
@@ -49,5 +49,13 @@ export interface IFormFieldDateTimeParam<T> {
49
49
  * @param params - Static configuration (picker type, mode, optional field config override)
50
50
  * @returns A React FC ready to be used as a date/time filter-menu field component
51
51
  */
52
- declare function createFormFieldDateTime<T>(params?: IFormFieldDateTimeParam<T>): FC<IFormFieldDateTimeProps<T>>;
52
+ export declare function createFormFieldDateTime<T>(params?: IFormFieldDateTimeParam<T>): FC<IFormFieldDateTimeProps<T>>;
53
53
  export default createFormFieldDateTime;
54
+ /**
55
+ * Creates a labelFormatter for use in summaryConfig.
56
+ * Formats ISO date strings to a human-readable format.
57
+ * For range fields, values are displayed as-is (no From/To prefix since index is unavailable).
58
+ */
59
+ export declare function formatterDateTime(pickerType?: TDateTimePickerType): (value: TFieldValid, index: number, fieldValue: {
60
+ dateLogic?: TDateLogic;
61
+ }) => string | undefined;
@@ -11,6 +11,8 @@ export interface IFieldMenuConfig<T> {
11
11
  replaceValue?: boolean;
12
12
  /** If true, the menu will close after submitting a value @default true */
13
13
  closeAfterSubmit?: boolean;
14
+ /** If true, the menu will close after clearing a value @default true */
15
+ closeAfterClear?: boolean;
14
16
  /** Default logic for combining multiple values for the field */
15
17
  defaultLogic?: TLogic;
16
18
  /** Tooltip for the field */
@@ -44,6 +46,8 @@ export interface IFilterMenuConfig<T> extends IFilterMenuSlots {
44
46
  enableQuickSearch?: boolean;
45
47
  /** Option to close the menu after submitting a value @default true */
46
48
  closeAfterSubmit?: boolean;
49
+ /** Option to close the menu after clearing a value @default true */
50
+ closeAfterClear?: boolean;
47
51
  }
48
52
  export interface IFilterMenuConfigInternal<T> extends Omit<IFilterMenuConfig<T>, 'fields'> {
49
53
  fields: TFieldMenuConfigsInternal<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dinocollab-core",
3
- "version": "2.2.16",
3
+ "version": "2.2.18",
4
4
  "description": "Dinocollab core - libraries for building collaborative applications with React 18",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",