@vuu-ui/vuu-filters 0.13.16 → 0.13.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ExpandoCombobox.js","sources":["../../../../packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx"],"sourcesContent":["import cx from \"clsx\";\nimport { ComboBox, ComboBoxProps } from \"@salt-ds/core\";\nimport {\n ChangeEvent,\n ForwardedRef,\n ReactElement,\n Ref,\n SyntheticEvent,\n forwardRef,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\n\nimport expandoComboboxCss from \"./ExpandoCombobox.css\";\n\nconst classBase = \"vuuExpandoCombobox\";\n\nexport interface ExpandoComboboxProps<Item = string>\n extends ComboBoxProps<Item> {\n itemToString?: (item: Item) => string;\n}\n\nexport type ComboBoxOpenChangeHandler = Exclude<\n ComboBoxProps[\"onOpenChange\"],\n undefined\n>;\n\nconst defaultItemToString = (item: unknown) => {\n if (typeof item === \"string\") {\n return item;\n } else {\n return item?.toString() ?? \"\";\n }\n};\nexport const ExpandoCombobox = forwardRef(function ExpandoCombobox<\n Item = string,\n>(\n {\n children,\n className,\n inputProps: inputPropsProp,\n itemToString = defaultItemToString,\n multiselect,\n onChange,\n onSelectionChange,\n onOpenChange,\n value: valueProp,\n ...props\n }: ExpandoComboboxProps<Item>,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-expando-combobox\",\n css: expandoComboboxCss,\n window: targetWindow,\n });\n\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState(\n valueProp === undefined ? \"\" : valueProp.toString(),\n );\n\n const handleChange = useCallback(\n (evt: ChangeEvent<HTMLInputElement>) => {\n const value = evt.target.value;\n onChange?.(evt);\n setValue(value);\n },\n [onChange],\n );\n\n const handleSelectionChange = useCallback(\n (evt: SyntheticEvent, newSelected: Item[]) => {\n if (multiselect) {\n onSelectionChange?.(evt, newSelected);\n } else {\n const [selectedValue] = newSelected;\n setTimeout(() => {\n onSelectionChange?.(evt, newSelected);\n setValue(itemToString(selectedValue));\n }, 100);\n }\n },\n [onSelectionChange, itemToString, multiselect],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, reason) => {\n onOpenChange?.(open, reason);\n setOpen(open);\n },\n [onOpenChange],\n );\n\n const inputProps = useMemo<ComboBoxProps<Item>[\"inputProps\"]>(() => {\n return {\n autoComplete: \"off\",\n ...inputPropsProp,\n onFocus: (evt) => {\n inputPropsProp?.onFocus?.(evt);\n setTimeout(() => {\n setOpen(true);\n }, 100);\n },\n };\n }, [inputPropsProp]);\n\n // const matchingValues = values.filter((val) =>\n // val.toLowerCase().startsWith(value.trim().toLowerCase())\n // );\n\n return (\n <div\n className={cx(classBase, className)}\n data-text={value}\n ref={forwardedRef}\n >\n <ComboBox<Item>\n {...props}\n inputProps={inputProps}\n multiselect={multiselect}\n onChange={handleChange}\n onOpenChange={handleOpenChange}\n onSelectionChange={handleSelectionChange}\n open={open}\n value={value}\n >\n {children}\n </ComboBox>\n </div>\n );\n}) as <Item = string>(\n props: ExpandoComboboxProps<Item> & { ref?: Ref<HTMLDivElement> },\n) => ReactElement;\n"],"names":["forwardRef","ExpandoCombobox","useWindow","useComponentCssInjection","expandoComboboxCss","useState","useCallback","value","open","useMemo","jsx","ComboBox"],"mappings":"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"}
1
+ {"version":3,"file":"ExpandoCombobox.js","sources":["../../../../packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx"],"sourcesContent":["import cx from \"clsx\";\nimport { ComboBox, ComboBoxProps } from \"@salt-ds/core\";\nimport {\n ChangeEvent,\n ForwardedRef,\n ReactElement,\n Ref,\n SyntheticEvent,\n forwardRef,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\n\nimport expandoComboboxCss from \"./ExpandoCombobox.css\";\n\nconst classBase = \"vuuExpandoCombobox\";\n\nexport interface ExpandoComboboxProps<Item = string>\n extends ComboBoxProps<Item> {\n itemToString?: (item: Item) => string;\n}\n\nexport type ComboBoxOpenChangeHandler = Exclude<\n ComboBoxProps[\"onOpenChange\"],\n undefined\n>;\n\nconst defaultItemToString = (item: unknown) => {\n if (typeof item === \"string\") {\n return item;\n } else {\n return item?.toString() ?? \"\";\n }\n};\nexport const ExpandoCombobox = forwardRef(function ExpandoCombobox<\n Item = string,\n>(\n {\n children,\n className,\n inputProps: inputPropsProp,\n itemToString = defaultItemToString,\n multiselect,\n onChange,\n onSelectionChange,\n onOpenChange,\n value: valueProp,\n ...props\n }: ExpandoComboboxProps<Item>,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-expando-combobox\",\n css: expandoComboboxCss,\n window: targetWindow,\n });\n\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState(\n valueProp === undefined ? \"\" : valueProp.toString(),\n );\n\n const handleChange = useCallback(\n (evt: ChangeEvent<HTMLInputElement>) => {\n const value = evt.target.value;\n onChange?.(evt);\n setValue(value);\n },\n [onChange],\n );\n\n const handleSelectionChange = useCallback(\n (evt: SyntheticEvent, newSelected: Item[]) => {\n if (multiselect) {\n onSelectionChange?.(evt, newSelected);\n } else {\n const [selectedValue] = newSelected;\n setTimeout(() => {\n onSelectionChange?.(evt, newSelected);\n setValue(itemToString(selectedValue));\n }, 100);\n }\n },\n [onSelectionChange, itemToString, multiselect],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, reason) => {\n onOpenChange?.(open, reason);\n setOpen(open);\n },\n [onOpenChange],\n );\n\n const inputProps = useMemo<ComboBoxProps<Item>[\"inputProps\"]>(() => {\n return {\n autoComplete: \"off\",\n ...inputPropsProp,\n onFocus: (evt) => {\n inputPropsProp?.onFocus?.(evt);\n\n setTimeout(() => {\n setOpen(true);\n }, 100);\n },\n };\n }, [inputPropsProp]);\n\n return (\n <div\n className={cx(classBase, className)}\n data-text={value}\n ref={forwardedRef}\n >\n <ComboBox<Item>\n {...props}\n inputProps={inputProps}\n multiselect={multiselect}\n onChange={handleChange}\n onOpenChange={handleOpenChange}\n onSelectionChange={handleSelectionChange}\n open={open}\n value={value}\n >\n {children}\n </ComboBox>\n </div>\n );\n}) as <Item = string>(\n props: ExpandoComboboxProps<Item> & { ref?: Ref<HTMLDivElement> },\n) => ReactElement;\n"],"names":["forwardRef","ExpandoCombobox","useWindow","useComponentCssInjection","expandoComboboxCss","useState","useCallback","value","open","useMemo","jsx","ComboBox"],"mappings":"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"}
@@ -20,6 +20,7 @@ const FilterClause = ({
20
20
  onFocusSave,
21
21
  filterClauseModel,
22
22
  vuuTable,
23
+ openDropdownOnFocus = true,
23
24
  ...htmlAttributes
24
25
  }) => {
25
26
  const {
@@ -38,7 +39,8 @@ const FilterClause = ({
38
39
  filterClauseModel,
39
40
  onCancel,
40
41
  onFocusSave,
41
- columnsByName
42
+ columnsByName,
43
+ openDropdownOnFocus
42
44
  });
43
45
  const targetWindow = window.useWindow();
44
46
  styles.useComponentCssInjection({
@@ -1 +1 @@
1
- {"version":3,"file":"FilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/FilterClause.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { ColumnPicker } from \"./ColumnPicker\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\n\nimport { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport filterClauseCss from \"./FilterClause.css\";\nimport { OperatorPicker } from \"./OperatorPicker\";\n\nexport type FilterClauseCancelType = \"Backspace\" | \"Escape\";\nexport type FilterClauseCancelHandler = (\n filterClause: FilterClauseModel,\n reason: FilterClauseCancelType,\n) => void;\n\nexport interface FilterClauseProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n columnsByName: ColumnDescriptorsByName;\n filterClauseModel: FilterClauseModel;\n onCancel?: FilterClauseCancelHandler;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n vuuTable: VuuTable;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n vuuTable,\n ...htmlAttributes\n}: FilterClauseProps) => {\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n onSelectColumn,\n onSelectOperator,\n onDeselectValue,\n onOpenChange,\n operatorRef,\n selectedColumn,\n valueRef,\n } = useFilterClause({\n filterClauseModel,\n onCancel,\n onFocusSave,\n columnsByName,\n });\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-filter-clause\",\n css: filterClauseCss,\n window: targetWindow,\n });\n\n const columns = useMemo(() => Object.values(columnsByName), [columnsByName]);\n\n return (\n <div className={cx(classBase, className)} {...htmlAttributes} tabIndex={0}>\n <ColumnPicker\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Column`)}\n columns={columns}\n key=\"column-field\"\n onSelect={onSelectColumn}\n ref={columnRef}\n value={filterClauseModel.column ?? \"\"}\n />\n {selectedColumn?.name ? (\n <OperatorPicker\n column={selectedColumn}\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Operator`, {\n [`${classBase}Operator-hidden`]: selectedColumn === null,\n })}\n key=\"operator-field\"\n onSelect={onSelectOperator}\n ref={operatorRef}\n value={filterClauseModel.op ?? \"\"}\n />\n ) : null}\n {filterClauseModel.op ? (\n <FilterClauseValueEditor\n inputProps={inputProps}\n key=\"value-field\"\n onChangeValue={onChangeValue}\n onOpenChange={onOpenChange}\n onDeselectValue={onDeselectValue}\n operator={filterClauseModel.op}\n ref={valueRef}\n selectedColumn={selectedColumn}\n table={vuuTable}\n value={\n (filterClause as MultiValueFilterClause)?.values ??\n (filterClause as SingleValueFilterClause)?.value\n }\n />\n ) : null}\n </div>\n );\n};\n"],"names":["useFilterClause","useWindow","useComponentCssInjection","filterClauseCss","useMemo","jsxs","jsx","ColumnPicker","OperatorPicker","FilterClauseValueEditor"],"mappings":";;;;;;;;;;;;;AAkCA,MAAM,SAAY,GAAA,iBAAA;AAEX,MAAM,eAAe,CAAC;AAAA,EAC3B,SAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAyB,KAAA;AACvB,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,MACEA,+BAAgB,CAAA;AAAA,IAClB,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAeC,gBAAU,EAAA;AAC/B,EAAyBC,+BAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,mBAAA;AAAA,IACR,GAAK,EAAAC,cAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAM,MAAA,OAAA,GAAUC,cAAQ,MAAM,MAAA,CAAO,OAAO,aAAa,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AAE3E,EACE,uBAAAC,eAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,EAAG,CAAA,SAAA,EAAW,SAAS,CAAI,EAAA,GAAG,cAAgB,EAAA,QAAA,EAAU,CACtE,EAAA,QAAA,EAAA;AAAA,oBAAAC,cAAA;AAAA,MAACC,yBAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAQ,MAAA,CAAA,CAAA;AAAA,QACvD,OAAA;AAAA,QAEA,QAAU,EAAA,cAAA;AAAA,QACV,GAAK,EAAA,SAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,MAAU,IAAA;AAAA,OAAA;AAAA,MAH/B;AAAA,KAIN;AAAA,IACC,gBAAgB,IACf,mBAAAD,cAAA;AAAA,MAACE,6BAAA;AAAA,MAAA;AAAA,QACC,MAAQ,EAAA,cAAA;AAAA,QACR,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAY,QAAA,CAAA,EAAA;AAAA,UACzD,CAAC,CAAA,EAAG,SAAS,CAAA,eAAA,CAAiB,GAAG,cAAmB,KAAA;AAAA,SACrD,CAAA;AAAA,QAED,QAAU,EAAA,gBAAA;AAAA,QACV,GAAK,EAAA,WAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,EAAM,IAAA;AAAA,OAAA;AAAA,MAH3B;AAAA,KAKJ,GAAA,IAAA;AAAA,IACH,kBAAkB,EACjB,mBAAAF,cAAA;AAAA,MAACG,+CAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QAEA,aAAA;AAAA,QACA,YAAA;AAAA,QACA,eAAA;AAAA,QACA,UAAU,iBAAkB,CAAA,EAAA;AAAA,QAC5B,GAAK,EAAA,QAAA;AAAA,QACL,cAAA;AAAA,QACA,KAAO,EAAA,QAAA;AAAA,QACP,KAAA,EACG,YAAyC,EAAA,MAAA,IACzC,YAA0C,EAAA;AAAA,OAAA;AAAA,MAVzC;AAAA,KAaJ,GAAA;AAAA,GACN,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"FilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/FilterClause.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { ColumnPicker } from \"./ColumnPicker\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\n\nimport { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport filterClauseCss from \"./FilterClause.css\";\nimport { OperatorPicker } from \"./OperatorPicker\";\n\nexport type FilterClauseCancelType = \"Backspace\" | \"Escape\";\nexport type FilterClauseCancelHandler = (\n filterClause: FilterClauseModel,\n reason: FilterClauseCancelType,\n) => void;\n\nexport interface FilterClauseProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n columnsByName: ColumnDescriptorsByName;\n filterClauseModel: FilterClauseModel;\n onCancel?: FilterClauseCancelHandler;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n openDropdownOnFocus?: boolean;\n vuuTable: VuuTable;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n vuuTable,\n openDropdownOnFocus = true,\n ...htmlAttributes\n}: FilterClauseProps) => {\n\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n onSelectColumn,\n onSelectOperator,\n onDeselectValue,\n onOpenChange,\n operatorRef,\n selectedColumn,\n valueRef,\n } = useFilterClause({\n filterClauseModel,\n onCancel,\n onFocusSave,\n columnsByName,\n openDropdownOnFocus,\n });\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-filter-clause\",\n css: filterClauseCss,\n window: targetWindow,\n });\n\n const columns = useMemo(() => Object.values(columnsByName), [columnsByName]);\n\n return (\n <div className={cx(classBase, className)} {...htmlAttributes} tabIndex={0}>\n <ColumnPicker\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Column`)}\n columns={columns}\n key=\"column-field\"\n onSelect={onSelectColumn}\n ref={columnRef}\n value={filterClauseModel.column ?? \"\"}\n />\n {selectedColumn?.name ? (\n <OperatorPicker\n column={selectedColumn}\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Operator`, {\n [`${classBase}Operator-hidden`]: selectedColumn === null,\n })}\n key=\"operator-field\"\n onSelect={onSelectOperator}\n ref={operatorRef}\n value={filterClauseModel.op ?? \"\"}\n />\n ) : null}\n {filterClauseModel.op ? (\n <FilterClauseValueEditor\n inputProps={inputProps}\n key=\"value-field\"\n onChangeValue={onChangeValue}\n onOpenChange={onOpenChange}\n onDeselectValue={onDeselectValue}\n operator={filterClauseModel.op}\n ref={valueRef}\n selectedColumn={selectedColumn}\n table={vuuTable}\n value={\n (filterClause as MultiValueFilterClause)?.values ??\n (filterClause as SingleValueFilterClause)?.value\n }\n />\n ) : null}\n </div>\n );\n};\n"],"names":["useFilterClause","useWindow","useComponentCssInjection","filterClauseCss","useMemo","jsxs","jsx","ColumnPicker","OperatorPicker","FilterClauseValueEditor"],"mappings":";;;;;;;;;;;;;AAmCA,MAAM,SAAY,GAAA,iBAAA;AAEX,MAAM,eAAe,CAAC;AAAA,EAC3B,SAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,mBAAsB,GAAA,IAAA;AAAA,EACtB,GAAG;AACL,CAAyB,KAAA;AAEvB,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,MACEA,+BAAgB,CAAA;AAAA,IAClB,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAeC,gBAAU,EAAA;AAC/B,EAAyBC,+BAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,mBAAA;AAAA,IACR,GAAK,EAAAC,cAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAM,MAAA,OAAA,GAAUC,cAAQ,MAAM,MAAA,CAAO,OAAO,aAAa,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AAE3E,EACE,uBAAAC,eAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,EAAG,CAAA,SAAA,EAAW,SAAS,CAAI,EAAA,GAAG,cAAgB,EAAA,QAAA,EAAU,CACtE,EAAA,QAAA,EAAA;AAAA,oBAAAC,cAAA;AAAA,MAACC,yBAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAQ,MAAA,CAAA,CAAA;AAAA,QACvD,OAAA;AAAA,QAEA,QAAU,EAAA,cAAA;AAAA,QACV,GAAK,EAAA,SAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,MAAU,IAAA;AAAA,OAAA;AAAA,MAH/B;AAAA,KAIN;AAAA,IACC,gBAAgB,IACf,mBAAAD,cAAA;AAAA,MAACE,6BAAA;AAAA,MAAA;AAAA,QACC,MAAQ,EAAA,cAAA;AAAA,QACR,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAY,QAAA,CAAA,EAAA;AAAA,UACzD,CAAC,CAAA,EAAG,SAAS,CAAA,eAAA,CAAiB,GAAG,cAAmB,KAAA;AAAA,SACrD,CAAA;AAAA,QAED,QAAU,EAAA,gBAAA;AAAA,QACV,GAAK,EAAA,WAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,EAAM,IAAA;AAAA,OAAA;AAAA,MAH3B;AAAA,KAKJ,GAAA,IAAA;AAAA,IACH,kBAAkB,EACjB,mBAAAF,cAAA;AAAA,MAACG,+CAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QAEA,aAAA;AAAA,QACA,YAAA;AAAA,QACA,eAAA;AAAA,QACA,UAAU,iBAAkB,CAAA,EAAA;AAAA,QAC5B,GAAK,EAAA,QAAA;AAAA,QACL,cAAA;AAAA,QACA,KAAO,EAAA,QAAA;AAAA,QACP,KAAA,EACG,YAAyC,EAAA,MAAA,IACzC,YAA0C,EAAA;AAAA,OAAA;AAAA,MAVzC;AAAA,KAaJ,GAAA;AAAA,GACN,EAAA,CAAA;AAEJ;;;;"}
@@ -7,7 +7,13 @@ var react = require('react');
7
7
  var ExpandoCombobox = require('./ExpandoCombobox.js');
8
8
  var operatorUtils = require('./operator-utils.js');
9
9
 
10
- const OperatorPicker = react.forwardRef(function ColumnPicker({ className, column, inputProps, onSelect, value }, forwardedRef) {
10
+ const OperatorPicker = react.forwardRef(function ColumnPicker({
11
+ className,
12
+ column,
13
+ inputProps,
14
+ onSelect,
15
+ value
16
+ }, forwardedRef) {
11
17
  const handleSelectionChange = (evt, newSelected) => {
12
18
  const [selectedValue] = newSelected;
13
19
  if (vuuUtils.isValidFilterClauseOp(selectedValue)) {
@@ -1 +1 @@
1
- {"version":3,"file":"OperatorPicker.js","sources":["../../../../packages/vuu-filters/src/filter-clause/OperatorPicker.tsx"],"sourcesContent":["import type { FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport type { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { isValidFilterClauseOp } from \"@vuu-ui/vuu-utils\";\nimport { ComboBoxProps, Option } from \"@salt-ds/core\";\nimport { ForwardedRef, SyntheticEvent, forwardRef } from \"react\";\nimport { ExpandoCombobox } from \"./ExpandoCombobox\";\nimport { getOperators } from \"./operator-utils\";\n\nexport type OperatorPickerProps = Pick<\n ComboBoxProps,\n \"className\" | \"inputProps\" | \"value\"\n> & {\n column: ColumnDescriptor;\n onSelect: (evt: SyntheticEvent, operator: FilterClauseOp) => void;\n};\n\nexport const OperatorPicker = forwardRef(function ColumnPicker(\n { className, column, inputProps, onSelect, value }: OperatorPickerProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const handleSelectionChange = (\n evt: SyntheticEvent,\n newSelected: string[],\n ) => {\n const [selectedValue] = newSelected;\n if (isValidFilterClauseOp(selectedValue)) {\n onSelect(evt, selectedValue);\n }\n };\n\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"operator\"\n onSelectionChange={handleSelectionChange}\n ref={forwardedRef}\n title=\"operator\"\n value={value}\n >\n {getOperators(column).map((op) => (\n <Option value={op} key={op} />\n ))}\n </ExpandoCombobox>\n );\n});\n"],"names":["forwardRef","isValidFilterClauseOp","jsx","ExpandoCombobox","getOperators","Option"],"mappings":";;;;;;;;;AAgBa,MAAA,cAAA,GAAiBA,gBAAW,CAAA,SAAS,YAChD,CAAA,EAAE,SAAW,EAAA,MAAA,EAAQ,UAAY,EAAA,QAAA,EAAU,KAAM,EAAA,EACjD,YACA,EAAA;AACA,EAAM,MAAA,qBAAA,GAAwB,CAC5B,GAAA,EACA,WACG,KAAA;AACH,IAAM,MAAA,CAAC,aAAa,CAAI,GAAA,WAAA;AACxB,IAAI,IAAAC,8BAAA,CAAsB,aAAa,CAAG,EAAA;AACxC,MAAA,QAAA,CAAS,KAAK,aAAa,CAAA;AAAA;AAC7B,GACF;AAEA,EACE,uBAAAC,cAAA;AAAA,IAACC,+BAAA;AAAA,IAAA;AAAA,MACC,UAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAW,EAAA,UAAA;AAAA,MACX,iBAAmB,EAAA,qBAAA;AAAA,MACnB,GAAK,EAAA,YAAA;AAAA,MACL,KAAM,EAAA,UAAA;AAAA,MACN,KAAA;AAAA,MAEC,QAAA,EAAAC,0BAAA,CAAa,MAAM,CAAA,CAAE,GAAI,CAAA,CAAC,EACzB,qBAAAF,cAAA,CAACG,WAAO,EAAA,EAAA,KAAA,EAAO,EAAS,EAAA,EAAA,EAAI,CAC7B;AAAA;AAAA,GACH;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"OperatorPicker.js","sources":["../../../../packages/vuu-filters/src/filter-clause/OperatorPicker.tsx"],"sourcesContent":["import type { FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport type { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { isValidFilterClauseOp } from \"@vuu-ui/vuu-utils\";\nimport { ComboBoxProps, Option } from \"@salt-ds/core\";\nimport { ForwardedRef, SyntheticEvent, forwardRef } from \"react\";\nimport { ExpandoCombobox } from \"./ExpandoCombobox\";\nimport { getOperators } from \"./operator-utils\";\n\nexport type OperatorPickerProps = Pick<\n ComboBoxProps,\n \"className\" | \"inputProps\" | \"value\"\n> & {\n column: ColumnDescriptor;\n onSelect: (evt: SyntheticEvent, operator: FilterClauseOp) => void;\n};\n\nexport const OperatorPicker = forwardRef(function ColumnPicker(\n {\n className,\n column,\n inputProps,\n onSelect,\n value,\n }: OperatorPickerProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const handleSelectionChange = (\n evt: SyntheticEvent,\n newSelected: string[],\n ) => {\n const [selectedValue] = newSelected;\n if (isValidFilterClauseOp(selectedValue)) {\n onSelect(evt, selectedValue);\n }\n };\n\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"operator\"\n onSelectionChange={handleSelectionChange}\n ref={forwardedRef}\n title=\"operator\"\n value={value}\n >\n {getOperators(column).map((op) => (\n <Option value={op} key={op} />\n ))}\n </ExpandoCombobox>\n );\n});\n"],"names":["forwardRef","isValidFilterClauseOp","jsx","ExpandoCombobox","getOperators","Option"],"mappings":";;;;;;;;;AAgBa,MAAA,cAAA,GAAiBA,gBAAW,CAAA,SAAS,YAChD,CAAA;AAAA,EACE,SAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EACA,YACA,EAAA;AACA,EAAM,MAAA,qBAAA,GAAwB,CAC5B,GAAA,EACA,WACG,KAAA;AACH,IAAM,MAAA,CAAC,aAAa,CAAI,GAAA,WAAA;AACxB,IAAI,IAAAC,8BAAA,CAAsB,aAAa,CAAG,EAAA;AACxC,MAAA,QAAA,CAAS,KAAK,aAAa,CAAA;AAAA;AAC7B,GACF;AAEA,EACE,uBAAAC,cAAA;AAAA,IAACC,+BAAA;AAAA,IAAA;AAAA,MACC,UAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAW,EAAA,UAAA;AAAA,MACX,iBAAmB,EAAA,qBAAA;AAAA,MACnB,GAAK,EAAA,YAAA;AAAA,MACL,KAAM,EAAA,UAAA;AAAA,MACN,KAAA;AAAA,MAEC,QAAA,EAAAC,0BAAA,CAAa,MAAM,CAAA,CAAE,GAAI,CAAA,CAAC,EACzB,qBAAAF,cAAA,CAACG,WAAO,EAAA,EAAA,KAAA,EAAO,EAAS,EAAA,EAAA,EAAI,CAC7B;AAAA;AAAA,GACH;AAEJ,CAAC;;;;"}
@@ -9,7 +9,8 @@ const useFilterClause = ({
9
9
  onCancel,
10
10
  columnsByName,
11
11
  onFocusSave,
12
- onOpenChange
12
+ onOpenChange,
13
+ openDropdownOnFocus = true
13
14
  }) => {
14
15
  const [filterClause, setFilterClause] = react.useState(
15
16
  filterClauseModel.isValid ? filterClauseModel.asFilter() : {}
@@ -22,14 +23,24 @@ const useFilterClause = ({
22
23
  const columnRef = react.useRef(null);
23
24
  const operatorRef = react.useRef(null);
24
25
  const valueRef = react.useRef(null);
26
+ const filterTouched = react.useRef(false);
27
+ const filterClauseTouched = react.useCallback(() => {
28
+ const unTouched = !openDropdownOnFocus && !filterTouched.current;
29
+ const setTouched = (state) => filterTouched.current = state;
30
+ if (unTouched) {
31
+ setTouched(true);
32
+ return false;
33
+ }
34
+ return true;
35
+ }, [openDropdownOnFocus]);
25
36
  const setValueRef = react.useCallback(
26
37
  (el) => {
27
38
  valueRef.current = el;
28
- if (!filterClauseModel.isValid) {
39
+ if (!filterClauseModel.isValid && filterClauseTouched()) {
29
40
  el?.querySelector("input")?.focus();
30
41
  }
31
42
  },
32
- [filterClauseModel.isValid]
43
+ [filterClauseModel.isValid, filterClauseTouched]
33
44
  );
34
45
  const removeAndNavigateToNextInputIfAtBoundary = react.useCallback(
35
46
  (evt) => {
@@ -106,6 +117,7 @@ const useFilterClause = ({
106
117
  filterClauseFocusManagement.tabToPreviousFilterCombinator(evt.target);
107
118
  } else if (evt.key === "Tab") {
108
119
  if (filterClauseModel.isValid) {
120
+ evt.preventDefault();
109
121
  evt.stopPropagation();
110
122
  onFocusSave?.();
111
123
  }
@@ -121,7 +133,8 @@ const useFilterClause = ({
121
133
  const handleOpenChange = react.useCallback(
122
134
  (open, closeReason) => {
123
135
  const isMultiSelect = filterClauseModel.op === "in";
124
- if (!open && isMultiSelect && filterClauseModel.isValid) {
136
+ const filterHasNoValue = !filterClauseModel.isValid && filterClauseModel.op !== void 0 && filterClauseModel.column !== void 0;
137
+ if (!open && isMultiSelect && (filterClauseModel.isValid || filterHasNoValue)) {
125
138
  filterClauseModel.commit();
126
139
  }
127
140
  onOpenChange?.(open, closeReason);
@@ -136,13 +149,15 @@ const useFilterClause = ({
136
149
  [handleKeyDownCaptureNavigation]
137
150
  );
138
151
  react.useEffect(() => {
139
- if (!filterClauseModel.isValid) {
140
- const inputRef = filterClauseModel.column === void 0 ? columnRef : filterClauseModel.op === void 0 ? operatorRef : null;
141
- requestAnimationFrame(() => {
142
- inputRef?.current?.querySelector("input")?.focus();
143
- });
152
+ const inputRef = filterClauseModel.column === void 0 ? columnRef : filterClauseModel.op === void 0 ? operatorRef : null;
153
+ if (!filterClauseModel.isValid && inputRef) {
154
+ if (filterClauseTouched()) {
155
+ requestAnimationFrame(() => {
156
+ inputRef.current?.querySelector("input")?.focus();
157
+ });
158
+ }
144
159
  }
145
- }, [filterClauseModel]);
160
+ }, [filterClauseModel, filterClauseTouched]);
146
161
  return {
147
162
  inputProps,
148
163
  columnRef,
@@ -1 +1 @@
1
- {"version":3,"file":"useFilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/useFilterClause.ts"],"sourcesContent":["import { FilterClause, FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport { hasOpenOptionList } from \"@vuu-ui/vuu-utils\";\nimport {\n KeyboardEvent,\n RefCallback,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { FilterClauseProps } from \"./FilterClause\";\nimport {\n clauseIsNotFirst,\n focusNextElement,\n focusNextFocusableElement,\n navigateToNextItemIfAtBoundary,\n tabToPreviousFilterCombinator,\n} from \"./filterClauseFocusManagement\";\nimport { ComboBoxOpenChangeHandler } from \"./ExpandoCombobox\";\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n> & { onOpenChange?: ComboBoxOpenChangeHandler };\n\nexport type FilterClauseValueChangeHandler = (\n value: string | string[] | number | number[],\n isFinal?: boolean,\n) => void;\n\nexport const useFilterClause = ({\n filterClauseModel,\n onCancel,\n columnsByName,\n onFocusSave,\n onOpenChange,\n}: FilterClauseEditorHookProps) => {\n const [filterClause, setFilterClause] = useState<Partial<FilterClause>>(\n filterClauseModel.isValid ? filterClauseModel.asFilter() : {},\n );\n\n useMemo(() => {\n filterClauseModel.on(\"filterClause\", (filterClause) => {\n setFilterClause(filterClause);\n });\n }, [filterClauseModel]);\n\n const columnRef = useRef<HTMLDivElement>(null);\n const operatorRef = useRef<HTMLDivElement>(null);\n const valueRef = useRef<HTMLDivElement | null>(null);\n\n const setValueRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n valueRef.current = el;\n if (!filterClauseModel.isValid) {\n el?.querySelector(\"input\")?.focus();\n }\n },\n [filterClauseModel.isValid],\n );\n\n const removeAndNavigateToNextInputIfAtBoundary = useCallback(\n (evt: KeyboardEvent) => {\n const input = evt.target as HTMLInputElement;\n if (input.value === \"\") {\n const field = input.closest(\"[data-field]\") as HTMLElement;\n switch (field?.dataset?.field) {\n case \"operator\": {\n filterClauseModel.column = undefined;\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"value\": {\n filterClauseModel.setOp(undefined);\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"column\": {\n if (clauseIsNotFirst(input)) {\n // When we backspace from an empty clause, the clause will be removed.filterClause\n // In this case, we will reposition focus on previous clause, but we\n // don't want the backspace to be effect an edit on that clause.\n evt.preventDefault();\n onCancel?.(filterClauseModel, \"Backspace\");\n }\n }\n }\n }\n },\n [filterClauseModel, onCancel],\n );\n\n const onSelectColumn = (evt: SyntheticEvent, selectedColumn: string) => {\n if (selectedColumn) {\n if (evt?.type === \"keydown\") {\n const { key } = evt as KeyboardEvent;\n if (key === \"Tab\") {\n if (filterClauseModel.column === selectedColumn) {\n // No selection change, allow normal Tab navigation (to Save button)\n return;\n } else {\n // Tab is being used to change selection, keep focus within the clause\n evt.preventDefault();\n }\n }\n }\n }\n filterClauseModel.column = selectedColumn;\n setTimeout(() => {\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_: SyntheticEvent, selectedOp: FilterClauseOp) => {\n filterClauseModel.setOp(selectedOp);\n focusNextElement();\n },\n [filterClauseModel],\n );\n\n const handleChangeValue = useCallback<FilterClauseValueChangeHandler>(\n (value, isFinal) => filterClauseModel.setValue(value, isFinal),\n [filterClauseModel],\n );\n\n const handleDeselectValue = useCallback(\n () => filterClauseModel.setValue(undefined),\n [filterClauseModel],\n );\n\n const handleKeyDownCaptureNavigation = useCallback(\n (evt: KeyboardEvent<HTMLInputElement>) => {\n if ([\"ArrowLeft\", \"ArrowRight\"].includes(evt.key)) {\n navigateToNextItemIfAtBoundary(evt);\n } else if (evt.key === \"Backspace\") {\n removeAndNavigateToNextInputIfAtBoundary(evt);\n } else if (evt.key === \"Escape\") {\n // ignore when optionlist is open, the optionList will be collapsed\n if (!hasOpenOptionList(evt.target)) {\n onCancel?.(filterClauseModel, \"Escape\");\n }\n } else if (evt.key === \"Tab\" && evt.shiftKey) {\n evt.preventDefault();\n tabToPreviousFilterCombinator(evt.target as HTMLElement);\n } else if (evt.key === \"Tab\") {\n // if the clause is valid, skip to save\n if (filterClauseModel.isValid) {\n //evt.preventDefault();\n evt.stopPropagation();\n // TODO focus cancel if not changed\n onFocusSave?.();\n }\n }\n },\n [\n filterClauseModel,\n onCancel,\n onFocusSave,\n removeAndNavigateToNextInputIfAtBoundary,\n ],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, closeReason) => {\n const isMultiSelect = filterClauseModel.op === \"in\";\n if (!open && isMultiSelect && filterClauseModel.isValid) {\n filterClauseModel.commit();\n }\n onOpenChange?.(open, closeReason);\n },\n [filterClauseModel, onOpenChange],\n );\n\n const inputProps = useMemo(\n () => ({\n onKeyDownCapture: handleKeyDownCaptureNavigation,\n tabIndex: -1,\n }),\n [handleKeyDownCaptureNavigation],\n );\n\n // Do we need this or can we leave it to the filterEditor\n useEffect(() => {\n // leave the valueInput to callbackRef handler above, may\n // fire after the requestAnimationFrame\n if (!filterClauseModel.isValid) {\n const inputRef =\n filterClauseModel.column === undefined\n ? columnRef\n : filterClauseModel.op === undefined\n ? operatorRef\n : null;\n\n requestAnimationFrame(() => {\n inputRef?.current?.querySelector(\"input\")?.focus();\n });\n }\n }, [filterClauseModel]);\n\n return {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue: handleChangeValue,\n onDeselectValue: handleDeselectValue,\n onSelectColumn,\n onSelectOperator,\n onOpenChange: handleOpenChange,\n operatorRef,\n selectedColumn: columnsByName[filterClauseModel.column ?? \"\"],\n valueRef: setValueRef,\n };\n};\n"],"names":["useState","useMemo","filterClause","useRef","useCallback","focusNextFocusableElement","clauseIsNotFirst","focusNextElement","navigateToNextItemIfAtBoundary","hasOpenOptionList","tabToPreviousFilterCombinator","useEffect"],"mappings":";;;;;;AA+BO,MAAM,kBAAkB,CAAC;AAAA,EAC9B,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAmC,KAAA;AACjC,EAAM,MAAA,CAAC,YAAc,EAAA,eAAe,CAAI,GAAAA,cAAA;AAAA,IACtC,iBAAkB,CAAA,OAAA,GAAU,iBAAkB,CAAA,QAAA,KAAa;AAAC,GAC9D;AAEA,EAAAC,aAAA,CAAQ,MAAM;AACZ,IAAkB,iBAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAACC,aAAiB,KAAA;AACrD,MAAA,eAAA,CAAgBA,aAAY,CAAA;AAAA,KAC7B,CAAA;AAAA,GACH,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAM,MAAA,SAAA,GAAYC,aAAuB,IAAI,CAAA;AAC7C,EAAM,MAAA,WAAA,GAAcA,aAAuB,IAAI,CAAA;AAC/C,EAAM,MAAA,QAAA,GAAWA,aAA8B,IAAI,CAAA;AAEnD,EAAA,MAAM,WAAc,GAAAC,iBAAA;AAAA,IAClB,CAAC,EAAO,KAAA;AACN,MAAA,QAAA,CAAS,OAAU,GAAA,EAAA;AACnB,MAAI,IAAA,CAAC,kBAAkB,OAAS,EAAA;AAC9B,QAAI,EAAA,EAAA,aAAA,CAAc,OAAO,CAAA,EAAG,KAAM,EAAA;AAAA;AACpC,KACF;AAAA,IACA,CAAC,kBAAkB,OAAO;AAAA,GAC5B;AAEA,EAAA,MAAM,wCAA2C,GAAAA,iBAAA;AAAA,IAC/C,CAAC,GAAuB,KAAA;AACtB,MAAA,MAAM,QAAQ,GAAI,CAAA,MAAA;AAClB,MAAI,IAAA,KAAA,CAAM,UAAU,EAAI,EAAA;AACtB,QAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,OAAA,CAAQ,cAAc,CAAA;AAC1C,QAAQ,QAAA,KAAA,EAAO,SAAS,KAAO;AAAA,UAC7B,KAAK,UAAY,EAAA;AACf,YAAA,iBAAA,CAAkB,MAAS,GAAA,KAAA,CAAA;AAC3B,YAAAC,qDAAA,CAA0B,KAAK,CAAA;AAC/B,YAAA;AAAA;AACF,UACA,KAAK,OAAS,EAAA;AACZ,YAAA,iBAAA,CAAkB,MAAM,KAAS,CAAA,CAAA;AACjC,YAAAA,qDAAA,CAA0B,KAAK,CAAA;AAC/B,YAAA;AAAA;AACF,UACA,KAAK,QAAU,EAAA;AACb,YAAI,IAAAC,4CAAA,CAAiB,KAAK,CAAG,EAAA;AAI3B,cAAA,GAAA,CAAI,cAAe,EAAA;AACnB,cAAA,QAAA,GAAW,mBAAmB,WAAW,CAAA;AAAA;AAC3C;AACF;AACF;AACF,KACF;AAAA,IACA,CAAC,mBAAmB,QAAQ;AAAA,GAC9B;AAEA,EAAM,MAAA,cAAA,GAAiB,CAAC,GAAA,EAAqB,cAA2B,KAAA;AACtE,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAI,IAAA,GAAA,EAAK,SAAS,SAAW,EAAA;AAC3B,QAAM,MAAA,EAAE,KAAQ,GAAA,GAAA;AAChB,QAAA,IAAI,QAAQ,KAAO,EAAA;AACjB,UAAI,IAAA,iBAAA,CAAkB,WAAW,cAAgB,EAAA;AAE/C,YAAA;AAAA,WACK,MAAA;AAEL,YAAA,GAAA,CAAI,cAAe,EAAA;AAAA;AACrB;AACF;AACF;AAEF,IAAA,iBAAA,CAAkB,MAAS,GAAA,cAAA;AAC3B,IAAA,UAAA,CAAW,MAAM;AACf,MAAiBC,4CAAA,EAAA;AAAA,OAChB,GAAG,CAAA;AAAA,GACR;AAEA,EAAA,MAAM,gBAAmB,GAAAH,iBAAA;AAAA,IACvB,CAAC,GAAmB,UAA+B,KAAA;AACjD,MAAA,iBAAA,CAAkB,MAAM,UAAU,CAAA;AAClC,MAAiBG,4CAAA,EAAA;AAAA,KACnB;AAAA,IACA,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,iBAAoB,GAAAH,iBAAA;AAAA,IACxB,CAAC,KAAO,EAAA,OAAA,KAAY,iBAAkB,CAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AAAA,IAC7D,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,mBAAsB,GAAAA,iBAAA;AAAA,IAC1B,MAAM,iBAAkB,CAAA,QAAA,CAAS,KAAS,CAAA,CAAA;AAAA,IAC1C,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,8BAAiC,GAAAA,iBAAA;AAAA,IACrC,CAAC,GAAyC,KAAA;AACxC,MAAA,IAAI,CAAC,WAAa,EAAA,YAAY,EAAE,QAAS,CAAA,GAAA,CAAI,GAAG,CAAG,EAAA;AACjD,QAAAI,0DAAA,CAA+B,GAAG,CAAA;AAAA,OACpC,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,WAAa,EAAA;AAClC,QAAA,wCAAA,CAAyC,GAAG,CAAA;AAAA,OAC9C,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,QAAU,EAAA;AAE/B,QAAA,IAAI,CAACC,0BAAA,CAAkB,GAAI,CAAA,MAAM,CAAG,EAAA;AAClC,UAAA,QAAA,GAAW,mBAAmB,QAAQ,CAAA;AAAA;AACxC,OACS,MAAA,IAAA,GAAA,CAAI,GAAQ,KAAA,KAAA,IAAS,IAAI,QAAU,EAAA;AAC5C,QAAA,GAAA,CAAI,cAAe,EAAA;AACnB,QAAAC,yDAAA,CAA8B,IAAI,MAAqB,CAAA;AAAA,OACzD,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,KAAO,EAAA;AAE5B,QAAA,IAAI,kBAAkB,OAAS,EAAA;AAE7B,UAAA,GAAA,CAAI,eAAgB,EAAA;AAEpB,UAAc,WAAA,IAAA;AAAA;AAChB;AACF,KACF;AAAA,IACA;AAAA,MACE,iBAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,gBAAmB,GAAAN,iBAAA;AAAA,IACvB,CAAC,MAAM,WAAgB,KAAA;AACrB,MAAM,MAAA,aAAA,GAAgB,kBAAkB,EAAO,KAAA,IAAA;AAC/C,MAAA,IAAI,CAAC,IAAA,IAAQ,aAAiB,IAAA,iBAAA,CAAkB,OAAS,EAAA;AACvD,QAAA,iBAAA,CAAkB,MAAO,EAAA;AAAA;AAE3B,MAAA,YAAA,GAAe,MAAM,WAAW,CAAA;AAAA,KAClC;AAAA,IACA,CAAC,mBAAmB,YAAY;AAAA,GAClC;AAEA,EAAA,MAAM,UAAa,GAAAH,aAAA;AAAA,IACjB,OAAO;AAAA,MACL,gBAAkB,EAAA,8BAAA;AAAA,MAClB,QAAU,EAAA,CAAA;AAAA,KACZ,CAAA;AAAA,IACA,CAAC,8BAA8B;AAAA,GACjC;AAGA,EAAAU,eAAA,CAAU,MAAM;AAGd,IAAI,IAAA,CAAC,kBAAkB,OAAS,EAAA;AAC9B,MAAM,MAAA,QAAA,GACJ,kBAAkB,MAAW,KAAA,KAAA,CAAA,GACzB,YACA,iBAAkB,CAAA,EAAA,KAAO,SACvB,WACA,GAAA,IAAA;AAER,MAAA,qBAAA,CAAsB,MAAM;AAC1B,QAAA,QAAA,EAAU,OAAS,EAAA,aAAA,CAAc,OAAO,CAAA,EAAG,KAAM,EAAA;AAAA,OAClD,CAAA;AAAA;AACH,GACF,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAO,OAAA;AAAA,IACL,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAe,EAAA,iBAAA;AAAA,IACf,eAAiB,EAAA,mBAAA;AAAA,IACjB,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAc,EAAA,gBAAA;AAAA,IACd,WAAA;AAAA,IACA,cAAgB,EAAA,aAAA,CAAc,iBAAkB,CAAA,MAAA,IAAU,EAAE,CAAA;AAAA,IAC5D,QAAU,EAAA;AAAA,GACZ;AACF;;;;"}
1
+ {"version":3,"file":"useFilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/useFilterClause.ts"],"sourcesContent":["import { FilterClause, FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport { hasOpenOptionList } from \"@vuu-ui/vuu-utils\";\nimport {\n KeyboardEvent,\n RefCallback,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { FilterClauseProps } from \"./FilterClause\";\nimport {\n clauseIsNotFirst,\n focusNextElement,\n focusNextFocusableElement,\n navigateToNextItemIfAtBoundary,\n tabToPreviousFilterCombinator,\n} from \"./filterClauseFocusManagement\";\nimport { ComboBoxOpenChangeHandler } from \"./ExpandoCombobox\";\n\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n> & { onOpenChange?: ComboBoxOpenChangeHandler; openDropdownOnFocus?: boolean };\n\nexport type FilterClauseValueChangeHandler = (\n value: string | string[] | number | number[],\n isFinal?: boolean,\n) => void;\n\nexport const useFilterClause = ({\n filterClauseModel,\n onCancel,\n columnsByName,\n onFocusSave,\n onOpenChange,\n openDropdownOnFocus = true,\n}: FilterClauseEditorHookProps) => {\n const [filterClause, setFilterClause] = useState<Partial<FilterClause>>(\n filterClauseModel.isValid ? filterClauseModel.asFilter() : {},\n );\n\n useMemo(() => {\n filterClauseModel.on(\"filterClause\", (filterClause) => {\n setFilterClause(filterClause);\n });\n }, [filterClauseModel]);\n\n const columnRef = useRef<HTMLDivElement>(null);\n const operatorRef = useRef<HTMLDivElement>(null);\n const valueRef = useRef<HTMLDivElement | null>(null);\n const filterTouched = useRef(false);\n\n const filterClauseTouched = useCallback(() => {\n const unTouched = !openDropdownOnFocus && !filterTouched.current;\n const setTouched = (state: boolean) => filterTouched.current = state;\n if (unTouched) {\n setTouched(true);\n return false;\n }\n return true;\n }, [openDropdownOnFocus]);\n\n const setValueRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n valueRef.current = el;\n if (!filterClauseModel.isValid && filterClauseTouched()) { \n el?.querySelector(\"input\")?.focus();\n }\n },\n [filterClauseModel.isValid, filterClauseTouched],\n );\n\n const removeAndNavigateToNextInputIfAtBoundary = useCallback(\n (evt: KeyboardEvent) => {\n const input = evt.target as HTMLInputElement;\n if (input.value === \"\") {\n const field = input.closest(\"[data-field]\") as HTMLElement;\n switch (field?.dataset?.field) {\n case \"operator\": {\n filterClauseModel.column = undefined;\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"value\": {\n filterClauseModel.setOp(undefined);\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"column\": {\n if (clauseIsNotFirst(input)) {\n // When we backspace from an empty clause, the clause will be removed.filterClause\n // In this case, we will reposition focus on previous clause, but we\n // don't want the backspace to be effect an edit on that clause.\n evt.preventDefault();\n onCancel?.(filterClauseModel, \"Backspace\");\n }\n }\n }\n }\n },\n [filterClauseModel, onCancel],\n );\n\n const onSelectColumn = (evt: SyntheticEvent, selectedColumn: string) => {\n if (selectedColumn) {\n if (evt?.type === \"keydown\") {\n const { key } = evt as KeyboardEvent;\n if (key === \"Tab\") {\n if (filterClauseModel.column === selectedColumn) {\n // No selection change, allow normal Tab navigation (to Save button)\n return;\n } else {\n // Tab is being used to change selection, keep focus within the clause\n evt.preventDefault();\n }\n }\n }\n }\n filterClauseModel.column = selectedColumn;\n setTimeout(() => {\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_: SyntheticEvent, selectedOp: FilterClauseOp) => {\n filterClauseModel.setOp(selectedOp);\n focusNextElement();\n },\n [filterClauseModel],\n );\n\n const handleChangeValue = useCallback<FilterClauseValueChangeHandler>(\n (value, isFinal) => filterClauseModel.setValue(value, isFinal),\n [filterClauseModel],\n );\n\n const handleDeselectValue = useCallback(\n () => filterClauseModel.setValue(undefined),\n [filterClauseModel],\n );\n\n const handleKeyDownCaptureNavigation = useCallback(\n (evt: KeyboardEvent<HTMLInputElement>) => {\n if ([\"ArrowLeft\", \"ArrowRight\"].includes(evt.key)) {\n navigateToNextItemIfAtBoundary(evt);\n } else if (evt.key === \"Backspace\") {\n removeAndNavigateToNextInputIfAtBoundary(evt);\n } else if (evt.key === \"Escape\") {\n // ignore when optionlist is open, the optionList will be collapsed\n if (!hasOpenOptionList(evt.target)) {\n onCancel?.(filterClauseModel, \"Escape\");\n }\n } else if (evt.key === \"Tab\" && evt.shiftKey) {\n evt.preventDefault();\n tabToPreviousFilterCombinator(evt.target as HTMLElement);\n } else if (evt.key === \"Tab\") {\n // if the clause is valid, skip to save\n if (filterClauseModel.isValid) {\n evt.preventDefault();\n evt.stopPropagation();\n // TODO focus cancel if not changed\n onFocusSave?.();\n }\n }\n },\n [\n filterClauseModel,\n onCancel,\n onFocusSave,\n removeAndNavigateToNextInputIfAtBoundary,\n ],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, closeReason) => {\n const isMultiSelect = filterClauseModel.op === \"in\";\n const filterHasNoValue =\n !filterClauseModel.isValid &&\n filterClauseModel.op !== undefined &&\n filterClauseModel.column !== undefined;\n\n if (\n !open &&\n isMultiSelect &&\n (filterClauseModel.isValid || filterHasNoValue)\n ) {\n filterClauseModel.commit();\n }\n onOpenChange?.(open, closeReason);\n },\n [filterClauseModel, onOpenChange],\n );\n\n const inputProps = useMemo(\n () => ({\n onKeyDownCapture: handleKeyDownCaptureNavigation,\n tabIndex: -1,\n }),\n [handleKeyDownCaptureNavigation],\n );\n\n // Do we need this or can we leave it to the filterEditor\n useEffect(() => {\n // leave the valueInput to callbackRef handler above, may\n // fire after the requestAnimationFrame\n const inputRef =\n filterClauseModel.column === undefined\n ? columnRef\n : filterClauseModel.op === undefined\n ? operatorRef\n : null;\n\n if (!filterClauseModel.isValid && inputRef) {\n if (filterClauseTouched()) {\n requestAnimationFrame(() => {\n inputRef.current?.querySelector(\"input\")?.focus();\n });\n }\n }\n }, [filterClauseModel, filterClauseTouched]);\n\n return {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue: handleChangeValue,\n onDeselectValue: handleDeselectValue,\n onSelectColumn,\n onSelectOperator,\n onOpenChange: handleOpenChange,\n operatorRef,\n selectedColumn: columnsByName[filterClauseModel.column ?? \"\"],\n valueRef: setValueRef,\n };\n};\n"],"names":["useState","useMemo","filterClause","useRef","useCallback","focusNextFocusableElement","clauseIsNotFirst","focusNextElement","navigateToNextItemIfAtBoundary","hasOpenOptionList","tabToPreviousFilterCombinator","useEffect"],"mappings":";;;;;;AAgCO,MAAM,kBAAkB,CAAC;AAAA,EAC9B,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,mBAAsB,GAAA;AACxB,CAAmC,KAAA;AACjC,EAAM,MAAA,CAAC,YAAc,EAAA,eAAe,CAAI,GAAAA,cAAA;AAAA,IACtC,iBAAkB,CAAA,OAAA,GAAU,iBAAkB,CAAA,QAAA,KAAa;AAAC,GAC9D;AAEA,EAAAC,aAAA,CAAQ,MAAM;AACZ,IAAkB,iBAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAACC,aAAiB,KAAA;AACrD,MAAA,eAAA,CAAgBA,aAAY,CAAA;AAAA,KAC7B,CAAA;AAAA,GACH,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAM,MAAA,SAAA,GAAYC,aAAuB,IAAI,CAAA;AAC7C,EAAM,MAAA,WAAA,GAAcA,aAAuB,IAAI,CAAA;AAC/C,EAAM,MAAA,QAAA,GAAWA,aAA8B,IAAI,CAAA;AACnD,EAAM,MAAA,aAAA,GAAgBA,aAAO,KAAK,CAAA;AAElC,EAAM,MAAA,mBAAA,GAAsBC,kBAAY,MAAM;AAC5C,IAAA,MAAM,SAAY,GAAA,CAAC,mBAAuB,IAAA,CAAC,aAAc,CAAA,OAAA;AACzD,IAAA,MAAM,UAAa,GAAA,CAAC,KAAmB,KAAA,aAAA,CAAc,OAAU,GAAA,KAAA;AAC/D,IAAA,IAAI,SAAW,EAAA;AACb,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAO,OAAA,KAAA;AAAA;AAET,IAAO,OAAA,IAAA;AAAA,GACT,EAAG,CAAC,mBAAmB,CAAC,CAAA;AAExB,EAAA,MAAM,WAAc,GAAAA,iBAAA;AAAA,IAClB,CAAC,EAAO,KAAA;AACN,MAAA,QAAA,CAAS,OAAU,GAAA,EAAA;AACnB,MAAA,IAAI,CAAC,iBAAA,CAAkB,OAAW,IAAA,mBAAA,EAAuB,EAAA;AACvD,QAAI,EAAA,EAAA,aAAA,CAAc,OAAO,CAAA,EAAG,KAAM,EAAA;AAAA;AACpC,KACF;AAAA,IACA,CAAC,iBAAkB,CAAA,OAAA,EAAS,mBAAmB;AAAA,GACjD;AAEA,EAAA,MAAM,wCAA2C,GAAAA,iBAAA;AAAA,IAC/C,CAAC,GAAuB,KAAA;AACtB,MAAA,MAAM,QAAQ,GAAI,CAAA,MAAA;AAClB,MAAI,IAAA,KAAA,CAAM,UAAU,EAAI,EAAA;AACtB,QAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,OAAA,CAAQ,cAAc,CAAA;AAC1C,QAAQ,QAAA,KAAA,EAAO,SAAS,KAAO;AAAA,UAC7B,KAAK,UAAY,EAAA;AACf,YAAA,iBAAA,CAAkB,MAAS,GAAA,KAAA,CAAA;AAC3B,YAAAC,qDAAA,CAA0B,KAAK,CAAA;AAC/B,YAAA;AAAA;AACF,UACA,KAAK,OAAS,EAAA;AACZ,YAAA,iBAAA,CAAkB,MAAM,KAAS,CAAA,CAAA;AACjC,YAAAA,qDAAA,CAA0B,KAAK,CAAA;AAC/B,YAAA;AAAA;AACF,UACA,KAAK,QAAU,EAAA;AACb,YAAI,IAAAC,4CAAA,CAAiB,KAAK,CAAG,EAAA;AAI3B,cAAA,GAAA,CAAI,cAAe,EAAA;AACnB,cAAA,QAAA,GAAW,mBAAmB,WAAW,CAAA;AAAA;AAC3C;AACF;AACF;AACF,KACF;AAAA,IACA,CAAC,mBAAmB,QAAQ;AAAA,GAC9B;AAEA,EAAM,MAAA,cAAA,GAAiB,CAAC,GAAA,EAAqB,cAA2B,KAAA;AACtE,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAI,IAAA,GAAA,EAAK,SAAS,SAAW,EAAA;AAC3B,QAAM,MAAA,EAAE,KAAQ,GAAA,GAAA;AAChB,QAAA,IAAI,QAAQ,KAAO,EAAA;AACjB,UAAI,IAAA,iBAAA,CAAkB,WAAW,cAAgB,EAAA;AAE/C,YAAA;AAAA,WACK,MAAA;AAEL,YAAA,GAAA,CAAI,cAAe,EAAA;AAAA;AACrB;AACF;AACF;AAEF,IAAA,iBAAA,CAAkB,MAAS,GAAA,cAAA;AAC3B,IAAA,UAAA,CAAW,MAAM;AACf,MAAiBC,4CAAA,EAAA;AAAA,OAChB,GAAG,CAAA;AAAA,GACR;AAEA,EAAA,MAAM,gBAAmB,GAAAH,iBAAA;AAAA,IACvB,CAAC,GAAmB,UAA+B,KAAA;AACjD,MAAA,iBAAA,CAAkB,MAAM,UAAU,CAAA;AAClC,MAAiBG,4CAAA,EAAA;AAAA,KACnB;AAAA,IACA,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,iBAAoB,GAAAH,iBAAA;AAAA,IACxB,CAAC,KAAO,EAAA,OAAA,KAAY,iBAAkB,CAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AAAA,IAC7D,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,mBAAsB,GAAAA,iBAAA;AAAA,IAC1B,MAAM,iBAAkB,CAAA,QAAA,CAAS,KAAS,CAAA,CAAA;AAAA,IAC1C,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,8BAAiC,GAAAA,iBAAA;AAAA,IACrC,CAAC,GAAyC,KAAA;AACxC,MAAA,IAAI,CAAC,WAAa,EAAA,YAAY,EAAE,QAAS,CAAA,GAAA,CAAI,GAAG,CAAG,EAAA;AACjD,QAAAI,0DAAA,CAA+B,GAAG,CAAA;AAAA,OACpC,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,WAAa,EAAA;AAClC,QAAA,wCAAA,CAAyC,GAAG,CAAA;AAAA,OAC9C,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,QAAU,EAAA;AAE/B,QAAA,IAAI,CAACC,0BAAA,CAAkB,GAAI,CAAA,MAAM,CAAG,EAAA;AAClC,UAAA,QAAA,GAAW,mBAAmB,QAAQ,CAAA;AAAA;AACxC,OACS,MAAA,IAAA,GAAA,CAAI,GAAQ,KAAA,KAAA,IAAS,IAAI,QAAU,EAAA;AAC5C,QAAA,GAAA,CAAI,cAAe,EAAA;AACnB,QAAAC,yDAAA,CAA8B,IAAI,MAAqB,CAAA;AAAA,OACzD,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,KAAO,EAAA;AAE5B,QAAA,IAAI,kBAAkB,OAAS,EAAA;AAC7B,UAAA,GAAA,CAAI,cAAe,EAAA;AACnB,UAAA,GAAA,CAAI,eAAgB,EAAA;AAEpB,UAAc,WAAA,IAAA;AAAA;AAChB;AACF,KACF;AAAA,IACA;AAAA,MACE,iBAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,gBAAmB,GAAAN,iBAAA;AAAA,IACvB,CAAC,MAAM,WAAgB,KAAA;AACrB,MAAM,MAAA,aAAA,GAAgB,kBAAkB,EAAO,KAAA,IAAA;AAC/C,MAAM,MAAA,gBAAA,GACJ,CAAC,iBAAkB,CAAA,OAAA,IACnB,kBAAkB,EAAO,KAAA,KAAA,CAAA,IACzB,kBAAkB,MAAW,KAAA,KAAA,CAAA;AAE/B,MAAA,IACE,CAAC,IAAA,IACD,aACC,KAAA,iBAAA,CAAkB,WAAW,gBAC9B,CAAA,EAAA;AACA,QAAA,iBAAA,CAAkB,MAAO,EAAA;AAAA;AAE3B,MAAA,YAAA,GAAe,MAAM,WAAW,CAAA;AAAA,KAClC;AAAA,IACA,CAAC,mBAAmB,YAAY;AAAA,GAClC;AAEA,EAAA,MAAM,UAAa,GAAAH,aAAA;AAAA,IACjB,OAAO;AAAA,MACL,gBAAkB,EAAA,8BAAA;AAAA,MAClB,QAAU,EAAA,CAAA;AAAA,KACZ,CAAA;AAAA,IACA,CAAC,8BAA8B;AAAA,GACjC;AAGA,EAAAU,eAAA,CAAU,MAAM;AAGd,IAAM,MAAA,QAAA,GACJ,kBAAkB,MAAW,KAAA,KAAA,CAAA,GACzB,YACA,iBAAkB,CAAA,EAAA,KAAO,SACvB,WACA,GAAA,IAAA;AAER,IAAI,IAAA,CAAC,iBAAkB,CAAA,OAAA,IAAW,QAAU,EAAA;AAC1C,MAAA,IAAI,qBAAuB,EAAA;AACzB,QAAA,qBAAA,CAAsB,MAAM;AAC1B,UAAA,QAAA,CAAS,OAAS,EAAA,aAAA,CAAc,OAAO,CAAA,EAAG,KAAM,EAAA;AAAA,SACjD,CAAA;AAAA;AACH;AACF,GACC,EAAA,CAAC,iBAAmB,EAAA,mBAAmB,CAAC,CAAA;AAE3C,EAAO,OAAA;AAAA,IACL,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAe,EAAA,iBAAA;AAAA,IACf,eAAiB,EAAA,mBAAA;AAAA,IACjB,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAc,EAAA,gBAAA;AAAA,IACd,WAAA;AAAA,IACA,cAAgB,EAAA,aAAA,CAAc,iBAAkB,CAAA,MAAA,IAAU,EAAE,CAAA;AAAA,IAC5D,QAAU,EAAA;AAAA,GACZ;AACF;;;;"}
@@ -181,7 +181,8 @@ const FilterClauseValueEditorText = react.forwardRef(
181
181
  handleInputCommit,
182
182
  handleMultiValueSelectionChange,
183
183
  value,
184
- handleSingleValueSelectionChange
184
+ handleSingleValueSelectionChange,
185
+ onOpenChange
185
186
  ]);
186
187
  return getValueInputField();
187
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FilterClauseValueEditorText.js","sources":["../../../../../packages/vuu-filters/src/filter-clause/value-editors/FilterClauseValueEditorText.tsx"],"sourcesContent":["import { useTypeaheadSuggestions } from \"@vuu-ui/vuu-data-react\";\nimport type { TypeaheadParams } from \"@vuu-ui/vuu-protocol-types\";\nimport { ExpandoInput, MultiSelectionHandler } from \"@vuu-ui/vuu-ui-controls\";\nimport { CommitHandler, getVuuTable, NO_DATA_MATCH } from \"@vuu-ui/vuu-utils\";\nimport { Option } from \"@salt-ds/core\";\nimport {\n FormEvent,\n ForwardedRef,\n forwardRef,\n HTMLAttributes,\n KeyboardEventHandler,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { ExpandoCombobox } from \"../ExpandoCombobox\";\nimport { FilterClauseValueEditor } from \"../filterClauseTypes\";\n\nexport interface FilterClauseTextValueEditorProps\n extends FilterClauseValueEditor,\n HTMLAttributes<HTMLDivElement> {\n \"data-field\"?: string;\n // ref: RefObject<HTMLDivElement>;\n operator: string;\n value: string | string[];\n}\n\nexport const FilterClauseValueEditorText = forwardRef(\n function FilterClauseTextValueEditor(\n {\n inputProps: inputPropsProp,\n className,\n column,\n onChangeValue,\n onOpenChange,\n operator,\n table,\n value,\n }: FilterClauseTextValueEditorProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n ) {\n const isMultiValue = operator === \"in\";\n\n // If we have a multiselect text value which we are editing, this will render\n // a comma delimited list of the selected values. That is not what we display\n // by default when using a multiselect combo. Its not a huge problem - as soon\n // as user focuses this component and we display dropdown, input text is cleared\n // (so user can type to filter list) until dropdown closes again. <ight need to\n // revisit.\n const [valueInputValue, setValueInputValue] = useState(\n value?.toString() ?? \"\",\n );\n const [typeaheadValues, setTypeaheadValues] = useState<string[] | false>(\n [],\n );\n\n const getSuggestions = useTypeaheadSuggestions();\n\n const handleSingleValueSelectionChange = useCallback(\n (_: SyntheticEvent, [value]: string[]) => onChangeValue(value),\n [onChangeValue],\n );\n\n const handleMultiValueSelectionChange = useCallback<MultiSelectionHandler>(\n // TODO when will this ever be final ?\n (_, values) => onChangeValue(values, false),\n [onChangeValue],\n );\n\n useEffect(() => {\n if (table) {\n const vuuTable = getVuuTable(table);\n const params: TypeaheadParams =\n valueInputValue && !isMultiValue\n ? [vuuTable, column.name, valueInputValue]\n : [vuuTable, column.name];\n getSuggestions(params)\n .then((suggestions) => {\n if (suggestions === false) {\n setTypeaheadValues(false);\n } else if (suggestions.length === 0 && valueInputValue) {\n setTypeaheadValues(NO_DATA_MATCH);\n } else {\n setTypeaheadValues(suggestions);\n }\n })\n .catch((err) => {\n console.error(\"Error getting suggestions\", err);\n });\n }\n }, [table, column, valueInputValue, getSuggestions, isMultiValue]);\n\n const handleInputChange = useCallback(\n (evt: FormEvent<HTMLInputElement>) => {\n const { value } = evt.target as HTMLInputElement;\n setValueInputValue(value);\n // we want to set the filterclause status to valid, but not trigger focus change\n if (\n operator === \"starts\" ||\n operator === \"ends\" ||\n operator === \"contains\"\n ) {\n onChangeValue(value, false);\n }\n },\n [onChangeValue, operator],\n );\n\n const handleInputCommit = useCallback<CommitHandler>(\n (_, value = \"\") => {\n if (typeof value === \"string\") {\n onChangeValue(value);\n }\n },\n [onChangeValue],\n );\n\n const handleKeyDownFreeTextInput = useCallback<\n KeyboardEventHandler<HTMLInputElement>\n >(\n (evt) => {\n if (\n (evt.key === \"Enter\" || evt.key === \"Tab\") &&\n valueInputValue !== \"\"\n ) {\n evt.stopPropagation();\n evt.preventDefault();\n onChangeValue(valueInputValue);\n } else {\n inputPropsProp?.onKeyDown?.(evt);\n }\n },\n [inputPropsProp, onChangeValue, valueInputValue],\n );\n\n const inputProps = useMemo(() => {\n if (operator === \"starts\" || operator === \"ends\") {\n return {\n ...inputPropsProp,\n onKeyDown: handleKeyDownFreeTextInput,\n };\n } else {\n return inputPropsProp;\n }\n }, [inputPropsProp, handleKeyDownFreeTextInput, operator]);\n\n const getValueInputField = useCallback(() => {\n if (typeaheadValues === false) {\n // No typeahead service available\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n onCommit={handleInputCommit}\n />\n );\n }\n switch (operator) {\n case \"in\":\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onOpenChange={onOpenChange}\n onSelectionChange={handleMultiValueSelectionChange}\n ref={forwardedRef}\n multiselect\n truncate\n value={value}\n >\n {typeaheadValues\n // .filter((typeaheadValue) =>\n // typeaheadValue\n // .toLowerCase()\n // .includes(value.trim().toLowerCase())\n // )\n .map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n );\n case \"starts\": {\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} disabled />\n ))}\n </ExpandoCombobox>\n );\n }\n\n case \"ends\":\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n />\n );\n\n default: {\n return typeaheadValues.length > 0 ? (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n title=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n ) : null;\n }\n }\n }, [\n typeaheadValues,\n operator,\n inputProps,\n className,\n valueInputValue,\n forwardedRef,\n handleInputChange,\n handleInputCommit,\n handleMultiValueSelectionChange,\n value,\n handleSingleValueSelectionChange,\n ]);\n\n return getValueInputField();\n },\n);\n"],"names":["forwardRef","useState","useTypeaheadSuggestions","useCallback","value","useEffect","getVuuTable","NO_DATA_MATCH","useMemo","jsx","ExpandoInput","ExpandoCombobox","Option"],"mappings":"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"}
1
+ {"version":3,"file":"FilterClauseValueEditorText.js","sources":["../../../../../packages/vuu-filters/src/filter-clause/value-editors/FilterClauseValueEditorText.tsx"],"sourcesContent":["import { useTypeaheadSuggestions } from \"@vuu-ui/vuu-data-react\";\nimport type { TypeaheadParams } from \"@vuu-ui/vuu-protocol-types\";\nimport { ExpandoInput, MultiSelectionHandler } from \"@vuu-ui/vuu-ui-controls\";\nimport { CommitHandler, getVuuTable, NO_DATA_MATCH } from \"@vuu-ui/vuu-utils\";\nimport { Option } from \"@salt-ds/core\";\nimport {\n FormEvent,\n ForwardedRef,\n forwardRef,\n HTMLAttributes,\n KeyboardEventHandler,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { ExpandoCombobox } from \"../ExpandoCombobox\";\nimport { FilterClauseValueEditor } from \"../filterClauseTypes\";\n\nexport interface FilterClauseTextValueEditorProps\n extends FilterClauseValueEditor,\n HTMLAttributes<HTMLDivElement> {\n \"data-field\"?: string;\n // ref: RefObject<HTMLDivElement>;\n operator: string;\n value: string | string[];\n}\n\nexport const FilterClauseValueEditorText = forwardRef(\n function FilterClauseTextValueEditor(\n {\n inputProps: inputPropsProp,\n className,\n column,\n onChangeValue,\n onOpenChange,\n operator,\n table,\n value,\n }: FilterClauseTextValueEditorProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n ) {\n const isMultiValue = operator === \"in\";\n\n // If we have a multiselect text value which we are editing, this will render\n // a comma delimited list of the selected values. That is not what we display\n // by default when using a multiselect combo. Its not a huge problem - as soon\n // as user focuses this component and we display dropdown, input text is cleared\n // (so user can type to filter list) until dropdown closes again. <ight need to\n // revisit.\n const [valueInputValue, setValueInputValue] = useState(\n value?.toString() ?? \"\",\n );\n const [typeaheadValues, setTypeaheadValues] = useState<string[] | false>(\n [],\n );\n\n const getSuggestions = useTypeaheadSuggestions();\n\n const handleSingleValueSelectionChange = useCallback(\n (_: SyntheticEvent, [value]: string[]) => onChangeValue(value),\n [onChangeValue],\n );\n\n const handleMultiValueSelectionChange = useCallback<MultiSelectionHandler>(\n // TODO when will this ever be final ?\n (_, values) => onChangeValue(values, false),\n [onChangeValue],\n );\n\n useEffect(() => {\n if (table) {\n const vuuTable = getVuuTable(table);\n const params: TypeaheadParams =\n valueInputValue && !isMultiValue\n ? [vuuTable, column.name, valueInputValue]\n : [vuuTable, column.name];\n getSuggestions(params)\n .then((suggestions) => {\n if (suggestions === false) {\n setTypeaheadValues(false);\n } else if (suggestions.length === 0 && valueInputValue) {\n setTypeaheadValues(NO_DATA_MATCH);\n } else {\n setTypeaheadValues(suggestions);\n }\n })\n .catch((err) => {\n console.error(\"Error getting suggestions\", err);\n });\n }\n }, [table, column, valueInputValue, getSuggestions, isMultiValue]);\n\n const handleInputChange = useCallback(\n (evt: FormEvent<HTMLInputElement>) => {\n const { value } = evt.target as HTMLInputElement;\n setValueInputValue(value);\n // we want to set the filterclause status to valid, but not trigger focus change\n if (\n operator === \"starts\" ||\n operator === \"ends\" ||\n operator === \"contains\"\n ) {\n onChangeValue(value, false);\n }\n },\n [onChangeValue, operator],\n );\n\n const handleInputCommit = useCallback<CommitHandler>(\n (_, value = \"\") => {\n if (typeof value === \"string\") {\n onChangeValue(value);\n }\n },\n [onChangeValue],\n );\n\n const handleKeyDownFreeTextInput = useCallback<\n KeyboardEventHandler<HTMLInputElement>\n >(\n (evt) => {\n if (\n (evt.key === \"Enter\" || evt.key === \"Tab\") &&\n valueInputValue !== \"\"\n ) {\n evt.stopPropagation();\n evt.preventDefault();\n onChangeValue(valueInputValue);\n } else {\n inputPropsProp?.onKeyDown?.(evt);\n }\n },\n [inputPropsProp, onChangeValue, valueInputValue],\n );\n\n const inputProps = useMemo(() => {\n if (operator === \"starts\" || operator === \"ends\") {\n return {\n ...inputPropsProp,\n onKeyDown: handleKeyDownFreeTextInput,\n };\n } else {\n return inputPropsProp;\n }\n }, [inputPropsProp, handleKeyDownFreeTextInput, operator]);\n\n const getValueInputField = useCallback(() => {\n if (typeaheadValues === false) {\n // No typeahead service available\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n onCommit={handleInputCommit}\n />\n );\n }\n switch (operator) {\n case \"in\":\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onOpenChange={onOpenChange}\n onSelectionChange={handleMultiValueSelectionChange}\n ref={forwardedRef}\n multiselect\n truncate\n value={value}\n >\n {typeaheadValues\n // .filter((typeaheadValue) =>\n // typeaheadValue\n // .toLowerCase()\n // .includes(value.trim().toLowerCase())\n // )\n .map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n );\n case \"starts\": {\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} disabled />\n ))}\n </ExpandoCombobox>\n );\n }\n\n case \"ends\":\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n />\n );\n\n default: {\n return typeaheadValues.length > 0 ? (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n title=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n ) : null;\n }\n }\n }, [\n typeaheadValues,\n operator,\n inputProps,\n className,\n valueInputValue,\n forwardedRef,\n handleInputChange,\n handleInputCommit,\n handleMultiValueSelectionChange,\n value,\n handleSingleValueSelectionChange,\n onOpenChange,\n ]);\n\n return getValueInputField();\n },\n);\n"],"names":["forwardRef","useState","useTypeaheadSuggestions","useCallback","value","useEffect","getVuuTable","NO_DATA_MATCH","useMemo","jsx","ExpandoInput","ExpandoCombobox","Option"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpandoCombobox.js","sources":["../../../../packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx"],"sourcesContent":["import cx from \"clsx\";\nimport { ComboBox, ComboBoxProps } from \"@salt-ds/core\";\nimport {\n ChangeEvent,\n ForwardedRef,\n ReactElement,\n Ref,\n SyntheticEvent,\n forwardRef,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\n\nimport expandoComboboxCss from \"./ExpandoCombobox.css\";\n\nconst classBase = \"vuuExpandoCombobox\";\n\nexport interface ExpandoComboboxProps<Item = string>\n extends ComboBoxProps<Item> {\n itemToString?: (item: Item) => string;\n}\n\nexport type ComboBoxOpenChangeHandler = Exclude<\n ComboBoxProps[\"onOpenChange\"],\n undefined\n>;\n\nconst defaultItemToString = (item: unknown) => {\n if (typeof item === \"string\") {\n return item;\n } else {\n return item?.toString() ?? \"\";\n }\n};\nexport const ExpandoCombobox = forwardRef(function ExpandoCombobox<\n Item = string,\n>(\n {\n children,\n className,\n inputProps: inputPropsProp,\n itemToString = defaultItemToString,\n multiselect,\n onChange,\n onSelectionChange,\n onOpenChange,\n value: valueProp,\n ...props\n }: ExpandoComboboxProps<Item>,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-expando-combobox\",\n css: expandoComboboxCss,\n window: targetWindow,\n });\n\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState(\n valueProp === undefined ? \"\" : valueProp.toString(),\n );\n\n const handleChange = useCallback(\n (evt: ChangeEvent<HTMLInputElement>) => {\n const value = evt.target.value;\n onChange?.(evt);\n setValue(value);\n },\n [onChange],\n );\n\n const handleSelectionChange = useCallback(\n (evt: SyntheticEvent, newSelected: Item[]) => {\n if (multiselect) {\n onSelectionChange?.(evt, newSelected);\n } else {\n const [selectedValue] = newSelected;\n setTimeout(() => {\n onSelectionChange?.(evt, newSelected);\n setValue(itemToString(selectedValue));\n }, 100);\n }\n },\n [onSelectionChange, itemToString, multiselect],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, reason) => {\n onOpenChange?.(open, reason);\n setOpen(open);\n },\n [onOpenChange],\n );\n\n const inputProps = useMemo<ComboBoxProps<Item>[\"inputProps\"]>(() => {\n return {\n autoComplete: \"off\",\n ...inputPropsProp,\n onFocus: (evt) => {\n inputPropsProp?.onFocus?.(evt);\n setTimeout(() => {\n setOpen(true);\n }, 100);\n },\n };\n }, [inputPropsProp]);\n\n // const matchingValues = values.filter((val) =>\n // val.toLowerCase().startsWith(value.trim().toLowerCase())\n // );\n\n return (\n <div\n className={cx(classBase, className)}\n data-text={value}\n ref={forwardedRef}\n >\n <ComboBox<Item>\n {...props}\n inputProps={inputProps}\n multiselect={multiselect}\n onChange={handleChange}\n onOpenChange={handleOpenChange}\n onSelectionChange={handleSelectionChange}\n open={open}\n value={value}\n >\n {children}\n </ComboBox>\n </div>\n );\n}) as <Item = string>(\n props: ExpandoComboboxProps<Item> & { ref?: Ref<HTMLDivElement> },\n) => ReactElement;\n"],"names":["ExpandoCombobox","value","open"],"mappings":"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"}
1
+ {"version":3,"file":"ExpandoCombobox.js","sources":["../../../../packages/vuu-filters/src/filter-clause/ExpandoCombobox.tsx"],"sourcesContent":["import cx from \"clsx\";\nimport { ComboBox, ComboBoxProps } from \"@salt-ds/core\";\nimport {\n ChangeEvent,\n ForwardedRef,\n ReactElement,\n Ref,\n SyntheticEvent,\n forwardRef,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\n\nimport expandoComboboxCss from \"./ExpandoCombobox.css\";\n\nconst classBase = \"vuuExpandoCombobox\";\n\nexport interface ExpandoComboboxProps<Item = string>\n extends ComboBoxProps<Item> {\n itemToString?: (item: Item) => string;\n}\n\nexport type ComboBoxOpenChangeHandler = Exclude<\n ComboBoxProps[\"onOpenChange\"],\n undefined\n>;\n\nconst defaultItemToString = (item: unknown) => {\n if (typeof item === \"string\") {\n return item;\n } else {\n return item?.toString() ?? \"\";\n }\n};\nexport const ExpandoCombobox = forwardRef(function ExpandoCombobox<\n Item = string,\n>(\n {\n children,\n className,\n inputProps: inputPropsProp,\n itemToString = defaultItemToString,\n multiselect,\n onChange,\n onSelectionChange,\n onOpenChange,\n value: valueProp,\n ...props\n }: ExpandoComboboxProps<Item>,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-expando-combobox\",\n css: expandoComboboxCss,\n window: targetWindow,\n });\n\n const [open, setOpen] = useState(false);\n const [value, setValue] = useState(\n valueProp === undefined ? \"\" : valueProp.toString(),\n );\n\n const handleChange = useCallback(\n (evt: ChangeEvent<HTMLInputElement>) => {\n const value = evt.target.value;\n onChange?.(evt);\n setValue(value);\n },\n [onChange],\n );\n\n const handleSelectionChange = useCallback(\n (evt: SyntheticEvent, newSelected: Item[]) => {\n if (multiselect) {\n onSelectionChange?.(evt, newSelected);\n } else {\n const [selectedValue] = newSelected;\n setTimeout(() => {\n onSelectionChange?.(evt, newSelected);\n setValue(itemToString(selectedValue));\n }, 100);\n }\n },\n [onSelectionChange, itemToString, multiselect],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, reason) => {\n onOpenChange?.(open, reason);\n setOpen(open);\n },\n [onOpenChange],\n );\n\n const inputProps = useMemo<ComboBoxProps<Item>[\"inputProps\"]>(() => {\n return {\n autoComplete: \"off\",\n ...inputPropsProp,\n onFocus: (evt) => {\n inputPropsProp?.onFocus?.(evt);\n\n setTimeout(() => {\n setOpen(true);\n }, 100);\n },\n };\n }, [inputPropsProp]);\n\n return (\n <div\n className={cx(classBase, className)}\n data-text={value}\n ref={forwardedRef}\n >\n <ComboBox<Item>\n {...props}\n inputProps={inputProps}\n multiselect={multiselect}\n onChange={handleChange}\n onOpenChange={handleOpenChange}\n onSelectionChange={handleSelectionChange}\n open={open}\n value={value}\n >\n {children}\n </ComboBox>\n </div>\n );\n}) as <Item = string>(\n props: ExpandoComboboxProps<Item> & { ref?: Ref<HTMLDivElement> },\n) => ReactElement;\n"],"names":["ExpandoCombobox","value","open"],"mappings":"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"}
@@ -18,6 +18,7 @@ const FilterClause = ({
18
18
  onFocusSave,
19
19
  filterClauseModel,
20
20
  vuuTable,
21
+ openDropdownOnFocus = true,
21
22
  ...htmlAttributes
22
23
  }) => {
23
24
  const {
@@ -36,7 +37,8 @@ const FilterClause = ({
36
37
  filterClauseModel,
37
38
  onCancel,
38
39
  onFocusSave,
39
- columnsByName
40
+ columnsByName,
41
+ openDropdownOnFocus
40
42
  });
41
43
  const targetWindow = useWindow();
42
44
  useComponentCssInjection({
@@ -1 +1 @@
1
- {"version":3,"file":"FilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/FilterClause.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { ColumnPicker } from \"./ColumnPicker\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\n\nimport { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport filterClauseCss from \"./FilterClause.css\";\nimport { OperatorPicker } from \"./OperatorPicker\";\n\nexport type FilterClauseCancelType = \"Backspace\" | \"Escape\";\nexport type FilterClauseCancelHandler = (\n filterClause: FilterClauseModel,\n reason: FilterClauseCancelType,\n) => void;\n\nexport interface FilterClauseProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n columnsByName: ColumnDescriptorsByName;\n filterClauseModel: FilterClauseModel;\n onCancel?: FilterClauseCancelHandler;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n vuuTable: VuuTable;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n vuuTable,\n ...htmlAttributes\n}: FilterClauseProps) => {\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n onSelectColumn,\n onSelectOperator,\n onDeselectValue,\n onOpenChange,\n operatorRef,\n selectedColumn,\n valueRef,\n } = useFilterClause({\n filterClauseModel,\n onCancel,\n onFocusSave,\n columnsByName,\n });\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-filter-clause\",\n css: filterClauseCss,\n window: targetWindow,\n });\n\n const columns = useMemo(() => Object.values(columnsByName), [columnsByName]);\n\n return (\n <div className={cx(classBase, className)} {...htmlAttributes} tabIndex={0}>\n <ColumnPicker\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Column`)}\n columns={columns}\n key=\"column-field\"\n onSelect={onSelectColumn}\n ref={columnRef}\n value={filterClauseModel.column ?? \"\"}\n />\n {selectedColumn?.name ? (\n <OperatorPicker\n column={selectedColumn}\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Operator`, {\n [`${classBase}Operator-hidden`]: selectedColumn === null,\n })}\n key=\"operator-field\"\n onSelect={onSelectOperator}\n ref={operatorRef}\n value={filterClauseModel.op ?? \"\"}\n />\n ) : null}\n {filterClauseModel.op ? (\n <FilterClauseValueEditor\n inputProps={inputProps}\n key=\"value-field\"\n onChangeValue={onChangeValue}\n onOpenChange={onOpenChange}\n onDeselectValue={onDeselectValue}\n operator={filterClauseModel.op}\n ref={valueRef}\n selectedColumn={selectedColumn}\n table={vuuTable}\n value={\n (filterClause as MultiValueFilterClause)?.values ??\n (filterClause as SingleValueFilterClause)?.value\n }\n />\n ) : null}\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAkCA,MAAM,SAAY,GAAA,iBAAA;AAEX,MAAM,eAAe,CAAC;AAAA,EAC3B,SAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACL,CAAyB,KAAA;AACvB,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,MACE,eAAgB,CAAA;AAAA,IAClB,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAe,SAAU,EAAA;AAC/B,EAAyB,wBAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,mBAAA;AAAA,IACR,GAAK,EAAA,eAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM,MAAA,CAAO,OAAO,aAAa,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AAE3E,EACE,uBAAA,IAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,EAAG,CAAA,SAAA,EAAW,SAAS,CAAI,EAAA,GAAG,cAAgB,EAAA,QAAA,EAAU,CACtE,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAQ,MAAA,CAAA,CAAA;AAAA,QACvD,OAAA;AAAA,QAEA,QAAU,EAAA,cAAA;AAAA,QACV,GAAK,EAAA,SAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,MAAU,IAAA;AAAA,OAAA;AAAA,MAH/B;AAAA,KAIN;AAAA,IACC,gBAAgB,IACf,mBAAA,GAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,MAAQ,EAAA,cAAA;AAAA,QACR,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAY,QAAA,CAAA,EAAA;AAAA,UACzD,CAAC,CAAA,EAAG,SAAS,CAAA,eAAA,CAAiB,GAAG,cAAmB,KAAA;AAAA,SACrD,CAAA;AAAA,QAED,QAAU,EAAA,gBAAA;AAAA,QACV,GAAK,EAAA,WAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,EAAM,IAAA;AAAA,OAAA;AAAA,MAH3B;AAAA,KAKJ,GAAA,IAAA;AAAA,IACH,kBAAkB,EACjB,mBAAA,GAAA;AAAA,MAAC,uBAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QAEA,aAAA;AAAA,QACA,YAAA;AAAA,QACA,eAAA;AAAA,QACA,UAAU,iBAAkB,CAAA,EAAA;AAAA,QAC5B,GAAK,EAAA,QAAA;AAAA,QACL,cAAA;AAAA,QACA,KAAO,EAAA,QAAA;AAAA,QACP,KAAA,EACG,YAAyC,EAAA,MAAA,IACzC,YAA0C,EAAA;AAAA,OAAA;AAAA,MAVzC;AAAA,KAaJ,GAAA;AAAA,GACN,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"FilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/FilterClause.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { ColumnPicker } from \"./ColumnPicker\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\n\nimport { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport filterClauseCss from \"./FilterClause.css\";\nimport { OperatorPicker } from \"./OperatorPicker\";\n\nexport type FilterClauseCancelType = \"Backspace\" | \"Escape\";\nexport type FilterClauseCancelHandler = (\n filterClause: FilterClauseModel,\n reason: FilterClauseCancelType,\n) => void;\n\nexport interface FilterClauseProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n columnsByName: ColumnDescriptorsByName;\n filterClauseModel: FilterClauseModel;\n onCancel?: FilterClauseCancelHandler;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n openDropdownOnFocus?: boolean;\n vuuTable: VuuTable;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n vuuTable,\n openDropdownOnFocus = true,\n ...htmlAttributes\n}: FilterClauseProps) => {\n\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n onSelectColumn,\n onSelectOperator,\n onDeselectValue,\n onOpenChange,\n operatorRef,\n selectedColumn,\n valueRef,\n } = useFilterClause({\n filterClauseModel,\n onCancel,\n onFocusSave,\n columnsByName,\n openDropdownOnFocus,\n });\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-filter-clause\",\n css: filterClauseCss,\n window: targetWindow,\n });\n\n const columns = useMemo(() => Object.values(columnsByName), [columnsByName]);\n\n return (\n <div className={cx(classBase, className)} {...htmlAttributes} tabIndex={0}>\n <ColumnPicker\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Column`)}\n columns={columns}\n key=\"column-field\"\n onSelect={onSelectColumn}\n ref={columnRef}\n value={filterClauseModel.column ?? \"\"}\n />\n {selectedColumn?.name ? (\n <OperatorPicker\n column={selectedColumn}\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Operator`, {\n [`${classBase}Operator-hidden`]: selectedColumn === null,\n })}\n key=\"operator-field\"\n onSelect={onSelectOperator}\n ref={operatorRef}\n value={filterClauseModel.op ?? \"\"}\n />\n ) : null}\n {filterClauseModel.op ? (\n <FilterClauseValueEditor\n inputProps={inputProps}\n key=\"value-field\"\n onChangeValue={onChangeValue}\n onOpenChange={onOpenChange}\n onDeselectValue={onDeselectValue}\n operator={filterClauseModel.op}\n ref={valueRef}\n selectedColumn={selectedColumn}\n table={vuuTable}\n value={\n (filterClause as MultiValueFilterClause)?.values ??\n (filterClause as SingleValueFilterClause)?.value\n }\n />\n ) : null}\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAmCA,MAAM,SAAY,GAAA,iBAAA;AAEX,MAAM,eAAe,CAAC;AAAA,EAC3B,SAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,mBAAsB,GAAA,IAAA;AAAA,EACtB,GAAG;AACL,CAAyB,KAAA;AAEvB,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,MACE,eAAgB,CAAA;AAAA,IAClB,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAe,SAAU,EAAA;AAC/B,EAAyB,wBAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,mBAAA;AAAA,IACR,GAAK,EAAA,eAAA;AAAA,IACL,MAAQ,EAAA;AAAA,GACT,CAAA;AAED,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM,MAAA,CAAO,OAAO,aAAa,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA;AAE3E,EACE,uBAAA,IAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,EAAG,CAAA,SAAA,EAAW,SAAS,CAAI,EAAA,GAAG,cAAgB,EAAA,QAAA,EAAU,CACtE,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAQ,MAAA,CAAA,CAAA;AAAA,QACvD,OAAA;AAAA,QAEA,QAAU,EAAA,cAAA;AAAA,QACV,GAAK,EAAA,SAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,MAAU,IAAA;AAAA,OAAA;AAAA,MAH/B;AAAA,KAIN;AAAA,IACC,gBAAgB,IACf,mBAAA,GAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,MAAQ,EAAA,cAAA;AAAA,QACR,UAAA;AAAA,QACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAY,QAAA,CAAA,EAAA;AAAA,UACzD,CAAC,CAAA,EAAG,SAAS,CAAA,eAAA,CAAiB,GAAG,cAAmB,KAAA;AAAA,SACrD,CAAA;AAAA,QAED,QAAU,EAAA,gBAAA;AAAA,QACV,GAAK,EAAA,WAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,EAAM,IAAA;AAAA,OAAA;AAAA,MAH3B;AAAA,KAKJ,GAAA,IAAA;AAAA,IACH,kBAAkB,EACjB,mBAAA,GAAA;AAAA,MAAC,uBAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QAEA,aAAA;AAAA,QACA,YAAA;AAAA,QACA,eAAA;AAAA,QACA,UAAU,iBAAkB,CAAA,EAAA;AAAA,QAC5B,GAAK,EAAA,QAAA;AAAA,QACL,cAAA;AAAA,QACA,KAAO,EAAA,QAAA;AAAA,QACP,KAAA,EACG,YAAyC,EAAA,MAAA,IACzC,YAA0C,EAAA;AAAA,OAAA;AAAA,MAVzC;AAAA,KAaJ,GAAA;AAAA,GACN,EAAA,CAAA;AAEJ;;;;"}
@@ -5,7 +5,13 @@ import { forwardRef } from 'react';
5
5
  import { ExpandoCombobox } from './ExpandoCombobox.js';
6
6
  import { getOperators } from './operator-utils.js';
7
7
 
8
- const OperatorPicker = forwardRef(function ColumnPicker({ className, column, inputProps, onSelect, value }, forwardedRef) {
8
+ const OperatorPicker = forwardRef(function ColumnPicker({
9
+ className,
10
+ column,
11
+ inputProps,
12
+ onSelect,
13
+ value
14
+ }, forwardedRef) {
9
15
  const handleSelectionChange = (evt, newSelected) => {
10
16
  const [selectedValue] = newSelected;
11
17
  if (isValidFilterClauseOp(selectedValue)) {
@@ -1 +1 @@
1
- {"version":3,"file":"OperatorPicker.js","sources":["../../../../packages/vuu-filters/src/filter-clause/OperatorPicker.tsx"],"sourcesContent":["import type { FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport type { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { isValidFilterClauseOp } from \"@vuu-ui/vuu-utils\";\nimport { ComboBoxProps, Option } from \"@salt-ds/core\";\nimport { ForwardedRef, SyntheticEvent, forwardRef } from \"react\";\nimport { ExpandoCombobox } from \"./ExpandoCombobox\";\nimport { getOperators } from \"./operator-utils\";\n\nexport type OperatorPickerProps = Pick<\n ComboBoxProps,\n \"className\" | \"inputProps\" | \"value\"\n> & {\n column: ColumnDescriptor;\n onSelect: (evt: SyntheticEvent, operator: FilterClauseOp) => void;\n};\n\nexport const OperatorPicker = forwardRef(function ColumnPicker(\n { className, column, inputProps, onSelect, value }: OperatorPickerProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const handleSelectionChange = (\n evt: SyntheticEvent,\n newSelected: string[],\n ) => {\n const [selectedValue] = newSelected;\n if (isValidFilterClauseOp(selectedValue)) {\n onSelect(evt, selectedValue);\n }\n };\n\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"operator\"\n onSelectionChange={handleSelectionChange}\n ref={forwardedRef}\n title=\"operator\"\n value={value}\n >\n {getOperators(column).map((op) => (\n <Option value={op} key={op} />\n ))}\n </ExpandoCombobox>\n );\n});\n"],"names":[],"mappings":";;;;;;;AAgBa,MAAA,cAAA,GAAiB,UAAW,CAAA,SAAS,YAChD,CAAA,EAAE,SAAW,EAAA,MAAA,EAAQ,UAAY,EAAA,QAAA,EAAU,KAAM,EAAA,EACjD,YACA,EAAA;AACA,EAAM,MAAA,qBAAA,GAAwB,CAC5B,GAAA,EACA,WACG,KAAA;AACH,IAAM,MAAA,CAAC,aAAa,CAAI,GAAA,WAAA;AACxB,IAAI,IAAA,qBAAA,CAAsB,aAAa,CAAG,EAAA;AACxC,MAAA,QAAA,CAAS,KAAK,aAAa,CAAA;AAAA;AAC7B,GACF;AAEA,EACE,uBAAA,GAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,UAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAW,EAAA,UAAA;AAAA,MACX,iBAAmB,EAAA,qBAAA;AAAA,MACnB,GAAK,EAAA,YAAA;AAAA,MACL,KAAM,EAAA,UAAA;AAAA,MACN,KAAA;AAAA,MAEC,QAAA,EAAA,YAAA,CAAa,MAAM,CAAA,CAAE,GAAI,CAAA,CAAC,EACzB,qBAAA,GAAA,CAAC,MAAO,EAAA,EAAA,KAAA,EAAO,EAAS,EAAA,EAAA,EAAI,CAC7B;AAAA;AAAA,GACH;AAEJ,CAAC;;;;"}
1
+ {"version":3,"file":"OperatorPicker.js","sources":["../../../../packages/vuu-filters/src/filter-clause/OperatorPicker.tsx"],"sourcesContent":["import type { FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport type { ColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { isValidFilterClauseOp } from \"@vuu-ui/vuu-utils\";\nimport { ComboBoxProps, Option } from \"@salt-ds/core\";\nimport { ForwardedRef, SyntheticEvent, forwardRef } from \"react\";\nimport { ExpandoCombobox } from \"./ExpandoCombobox\";\nimport { getOperators } from \"./operator-utils\";\n\nexport type OperatorPickerProps = Pick<\n ComboBoxProps,\n \"className\" | \"inputProps\" | \"value\"\n> & {\n column: ColumnDescriptor;\n onSelect: (evt: SyntheticEvent, operator: FilterClauseOp) => void;\n};\n\nexport const OperatorPicker = forwardRef(function ColumnPicker(\n {\n className,\n column,\n inputProps,\n onSelect,\n value,\n }: OperatorPickerProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n) {\n const handleSelectionChange = (\n evt: SyntheticEvent,\n newSelected: string[],\n ) => {\n const [selectedValue] = newSelected;\n if (isValidFilterClauseOp(selectedValue)) {\n onSelect(evt, selectedValue);\n }\n };\n\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"operator\"\n onSelectionChange={handleSelectionChange}\n ref={forwardedRef}\n title=\"operator\"\n value={value}\n >\n {getOperators(column).map((op) => (\n <Option value={op} key={op} />\n ))}\n </ExpandoCombobox>\n );\n});\n"],"names":[],"mappings":";;;;;;;AAgBa,MAAA,cAAA,GAAiB,UAAW,CAAA,SAAS,YAChD,CAAA;AAAA,EACE,SAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EACA,YACA,EAAA;AACA,EAAM,MAAA,qBAAA,GAAwB,CAC5B,GAAA,EACA,WACG,KAAA;AACH,IAAM,MAAA,CAAC,aAAa,CAAI,GAAA,WAAA;AACxB,IAAI,IAAA,qBAAA,CAAsB,aAAa,CAAG,EAAA;AACxC,MAAA,QAAA,CAAS,KAAK,aAAa,CAAA;AAAA;AAC7B,GACF;AAEA,EACE,uBAAA,GAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,UAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAW,EAAA,UAAA;AAAA,MACX,iBAAmB,EAAA,qBAAA;AAAA,MACnB,GAAK,EAAA,YAAA;AAAA,MACL,KAAM,EAAA,UAAA;AAAA,MACN,KAAA;AAAA,MAEC,QAAA,EAAA,YAAA,CAAa,MAAM,CAAA,CAAE,GAAI,CAAA,CAAC,EACzB,qBAAA,GAAA,CAAC,MAAO,EAAA,EAAA,KAAA,EAAO,EAAS,EAAA,EAAA,EAAI,CAC7B;AAAA;AAAA,GACH;AAEJ,CAAC;;;;"}
@@ -7,7 +7,8 @@ const useFilterClause = ({
7
7
  onCancel,
8
8
  columnsByName,
9
9
  onFocusSave,
10
- onOpenChange
10
+ onOpenChange,
11
+ openDropdownOnFocus = true
11
12
  }) => {
12
13
  const [filterClause, setFilterClause] = useState(
13
14
  filterClauseModel.isValid ? filterClauseModel.asFilter() : {}
@@ -20,14 +21,24 @@ const useFilterClause = ({
20
21
  const columnRef = useRef(null);
21
22
  const operatorRef = useRef(null);
22
23
  const valueRef = useRef(null);
24
+ const filterTouched = useRef(false);
25
+ const filterClauseTouched = useCallback(() => {
26
+ const unTouched = !openDropdownOnFocus && !filterTouched.current;
27
+ const setTouched = (state) => filterTouched.current = state;
28
+ if (unTouched) {
29
+ setTouched(true);
30
+ return false;
31
+ }
32
+ return true;
33
+ }, [openDropdownOnFocus]);
23
34
  const setValueRef = useCallback(
24
35
  (el) => {
25
36
  valueRef.current = el;
26
- if (!filterClauseModel.isValid) {
37
+ if (!filterClauseModel.isValid && filterClauseTouched()) {
27
38
  el?.querySelector("input")?.focus();
28
39
  }
29
40
  },
30
- [filterClauseModel.isValid]
41
+ [filterClauseModel.isValid, filterClauseTouched]
31
42
  );
32
43
  const removeAndNavigateToNextInputIfAtBoundary = useCallback(
33
44
  (evt) => {
@@ -104,6 +115,7 @@ const useFilterClause = ({
104
115
  tabToPreviousFilterCombinator(evt.target);
105
116
  } else if (evt.key === "Tab") {
106
117
  if (filterClauseModel.isValid) {
118
+ evt.preventDefault();
107
119
  evt.stopPropagation();
108
120
  onFocusSave?.();
109
121
  }
@@ -119,7 +131,8 @@ const useFilterClause = ({
119
131
  const handleOpenChange = useCallback(
120
132
  (open, closeReason) => {
121
133
  const isMultiSelect = filterClauseModel.op === "in";
122
- if (!open && isMultiSelect && filterClauseModel.isValid) {
134
+ const filterHasNoValue = !filterClauseModel.isValid && filterClauseModel.op !== void 0 && filterClauseModel.column !== void 0;
135
+ if (!open && isMultiSelect && (filterClauseModel.isValid || filterHasNoValue)) {
123
136
  filterClauseModel.commit();
124
137
  }
125
138
  onOpenChange?.(open, closeReason);
@@ -134,13 +147,15 @@ const useFilterClause = ({
134
147
  [handleKeyDownCaptureNavigation]
135
148
  );
136
149
  useEffect(() => {
137
- if (!filterClauseModel.isValid) {
138
- const inputRef = filterClauseModel.column === void 0 ? columnRef : filterClauseModel.op === void 0 ? operatorRef : null;
139
- requestAnimationFrame(() => {
140
- inputRef?.current?.querySelector("input")?.focus();
141
- });
150
+ const inputRef = filterClauseModel.column === void 0 ? columnRef : filterClauseModel.op === void 0 ? operatorRef : null;
151
+ if (!filterClauseModel.isValid && inputRef) {
152
+ if (filterClauseTouched()) {
153
+ requestAnimationFrame(() => {
154
+ inputRef.current?.querySelector("input")?.focus();
155
+ });
156
+ }
142
157
  }
143
- }, [filterClauseModel]);
158
+ }, [filterClauseModel, filterClauseTouched]);
144
159
  return {
145
160
  inputProps,
146
161
  columnRef,
@@ -1 +1 @@
1
- {"version":3,"file":"useFilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/useFilterClause.ts"],"sourcesContent":["import { FilterClause, FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport { hasOpenOptionList } from \"@vuu-ui/vuu-utils\";\nimport {\n KeyboardEvent,\n RefCallback,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { FilterClauseProps } from \"./FilterClause\";\nimport {\n clauseIsNotFirst,\n focusNextElement,\n focusNextFocusableElement,\n navigateToNextItemIfAtBoundary,\n tabToPreviousFilterCombinator,\n} from \"./filterClauseFocusManagement\";\nimport { ComboBoxOpenChangeHandler } from \"./ExpandoCombobox\";\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n> & { onOpenChange?: ComboBoxOpenChangeHandler };\n\nexport type FilterClauseValueChangeHandler = (\n value: string | string[] | number | number[],\n isFinal?: boolean,\n) => void;\n\nexport const useFilterClause = ({\n filterClauseModel,\n onCancel,\n columnsByName,\n onFocusSave,\n onOpenChange,\n}: FilterClauseEditorHookProps) => {\n const [filterClause, setFilterClause] = useState<Partial<FilterClause>>(\n filterClauseModel.isValid ? filterClauseModel.asFilter() : {},\n );\n\n useMemo(() => {\n filterClauseModel.on(\"filterClause\", (filterClause) => {\n setFilterClause(filterClause);\n });\n }, [filterClauseModel]);\n\n const columnRef = useRef<HTMLDivElement>(null);\n const operatorRef = useRef<HTMLDivElement>(null);\n const valueRef = useRef<HTMLDivElement | null>(null);\n\n const setValueRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n valueRef.current = el;\n if (!filterClauseModel.isValid) {\n el?.querySelector(\"input\")?.focus();\n }\n },\n [filterClauseModel.isValid],\n );\n\n const removeAndNavigateToNextInputIfAtBoundary = useCallback(\n (evt: KeyboardEvent) => {\n const input = evt.target as HTMLInputElement;\n if (input.value === \"\") {\n const field = input.closest(\"[data-field]\") as HTMLElement;\n switch (field?.dataset?.field) {\n case \"operator\": {\n filterClauseModel.column = undefined;\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"value\": {\n filterClauseModel.setOp(undefined);\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"column\": {\n if (clauseIsNotFirst(input)) {\n // When we backspace from an empty clause, the clause will be removed.filterClause\n // In this case, we will reposition focus on previous clause, but we\n // don't want the backspace to be effect an edit on that clause.\n evt.preventDefault();\n onCancel?.(filterClauseModel, \"Backspace\");\n }\n }\n }\n }\n },\n [filterClauseModel, onCancel],\n );\n\n const onSelectColumn = (evt: SyntheticEvent, selectedColumn: string) => {\n if (selectedColumn) {\n if (evt?.type === \"keydown\") {\n const { key } = evt as KeyboardEvent;\n if (key === \"Tab\") {\n if (filterClauseModel.column === selectedColumn) {\n // No selection change, allow normal Tab navigation (to Save button)\n return;\n } else {\n // Tab is being used to change selection, keep focus within the clause\n evt.preventDefault();\n }\n }\n }\n }\n filterClauseModel.column = selectedColumn;\n setTimeout(() => {\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_: SyntheticEvent, selectedOp: FilterClauseOp) => {\n filterClauseModel.setOp(selectedOp);\n focusNextElement();\n },\n [filterClauseModel],\n );\n\n const handleChangeValue = useCallback<FilterClauseValueChangeHandler>(\n (value, isFinal) => filterClauseModel.setValue(value, isFinal),\n [filterClauseModel],\n );\n\n const handleDeselectValue = useCallback(\n () => filterClauseModel.setValue(undefined),\n [filterClauseModel],\n );\n\n const handleKeyDownCaptureNavigation = useCallback(\n (evt: KeyboardEvent<HTMLInputElement>) => {\n if ([\"ArrowLeft\", \"ArrowRight\"].includes(evt.key)) {\n navigateToNextItemIfAtBoundary(evt);\n } else if (evt.key === \"Backspace\") {\n removeAndNavigateToNextInputIfAtBoundary(evt);\n } else if (evt.key === \"Escape\") {\n // ignore when optionlist is open, the optionList will be collapsed\n if (!hasOpenOptionList(evt.target)) {\n onCancel?.(filterClauseModel, \"Escape\");\n }\n } else if (evt.key === \"Tab\" && evt.shiftKey) {\n evt.preventDefault();\n tabToPreviousFilterCombinator(evt.target as HTMLElement);\n } else if (evt.key === \"Tab\") {\n // if the clause is valid, skip to save\n if (filterClauseModel.isValid) {\n //evt.preventDefault();\n evt.stopPropagation();\n // TODO focus cancel if not changed\n onFocusSave?.();\n }\n }\n },\n [\n filterClauseModel,\n onCancel,\n onFocusSave,\n removeAndNavigateToNextInputIfAtBoundary,\n ],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, closeReason) => {\n const isMultiSelect = filterClauseModel.op === \"in\";\n if (!open && isMultiSelect && filterClauseModel.isValid) {\n filterClauseModel.commit();\n }\n onOpenChange?.(open, closeReason);\n },\n [filterClauseModel, onOpenChange],\n );\n\n const inputProps = useMemo(\n () => ({\n onKeyDownCapture: handleKeyDownCaptureNavigation,\n tabIndex: -1,\n }),\n [handleKeyDownCaptureNavigation],\n );\n\n // Do we need this or can we leave it to the filterEditor\n useEffect(() => {\n // leave the valueInput to callbackRef handler above, may\n // fire after the requestAnimationFrame\n if (!filterClauseModel.isValid) {\n const inputRef =\n filterClauseModel.column === undefined\n ? columnRef\n : filterClauseModel.op === undefined\n ? operatorRef\n : null;\n\n requestAnimationFrame(() => {\n inputRef?.current?.querySelector(\"input\")?.focus();\n });\n }\n }, [filterClauseModel]);\n\n return {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue: handleChangeValue,\n onDeselectValue: handleDeselectValue,\n onSelectColumn,\n onSelectOperator,\n onOpenChange: handleOpenChange,\n operatorRef,\n selectedColumn: columnsByName[filterClauseModel.column ?? \"\"],\n valueRef: setValueRef,\n };\n};\n"],"names":["filterClause"],"mappings":";;;;AA+BO,MAAM,kBAAkB,CAAC;AAAA,EAC9B,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAmC,KAAA;AACjC,EAAM,MAAA,CAAC,YAAc,EAAA,eAAe,CAAI,GAAA,QAAA;AAAA,IACtC,iBAAkB,CAAA,OAAA,GAAU,iBAAkB,CAAA,QAAA,KAAa;AAAC,GAC9D;AAEA,EAAA,OAAA,CAAQ,MAAM;AACZ,IAAkB,iBAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAACA,aAAiB,KAAA;AACrD,MAAA,eAAA,CAAgBA,aAAY,CAAA;AAAA,KAC7B,CAAA;AAAA,GACH,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAM,MAAA,SAAA,GAAY,OAAuB,IAAI,CAAA;AAC7C,EAAM,MAAA,WAAA,GAAc,OAAuB,IAAI,CAAA;AAC/C,EAAM,MAAA,QAAA,GAAW,OAA8B,IAAI,CAAA;AAEnD,EAAA,MAAM,WAAc,GAAA,WAAA;AAAA,IAClB,CAAC,EAAO,KAAA;AACN,MAAA,QAAA,CAAS,OAAU,GAAA,EAAA;AACnB,MAAI,IAAA,CAAC,kBAAkB,OAAS,EAAA;AAC9B,QAAI,EAAA,EAAA,aAAA,CAAc,OAAO,CAAA,EAAG,KAAM,EAAA;AAAA;AACpC,KACF;AAAA,IACA,CAAC,kBAAkB,OAAO;AAAA,GAC5B;AAEA,EAAA,MAAM,wCAA2C,GAAA,WAAA;AAAA,IAC/C,CAAC,GAAuB,KAAA;AACtB,MAAA,MAAM,QAAQ,GAAI,CAAA,MAAA;AAClB,MAAI,IAAA,KAAA,CAAM,UAAU,EAAI,EAAA;AACtB,QAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,OAAA,CAAQ,cAAc,CAAA;AAC1C,QAAQ,QAAA,KAAA,EAAO,SAAS,KAAO;AAAA,UAC7B,KAAK,UAAY,EAAA;AACf,YAAA,iBAAA,CAAkB,MAAS,GAAA,KAAA,CAAA;AAC3B,YAAA,yBAAA,CAA0B,KAAK,CAAA;AAC/B,YAAA;AAAA;AACF,UACA,KAAK,OAAS,EAAA;AACZ,YAAA,iBAAA,CAAkB,MAAM,KAAS,CAAA,CAAA;AACjC,YAAA,yBAAA,CAA0B,KAAK,CAAA;AAC/B,YAAA;AAAA;AACF,UACA,KAAK,QAAU,EAAA;AACb,YAAI,IAAA,gBAAA,CAAiB,KAAK,CAAG,EAAA;AAI3B,cAAA,GAAA,CAAI,cAAe,EAAA;AACnB,cAAA,QAAA,GAAW,mBAAmB,WAAW,CAAA;AAAA;AAC3C;AACF;AACF;AACF,KACF;AAAA,IACA,CAAC,mBAAmB,QAAQ;AAAA,GAC9B;AAEA,EAAM,MAAA,cAAA,GAAiB,CAAC,GAAA,EAAqB,cAA2B,KAAA;AACtE,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAI,IAAA,GAAA,EAAK,SAAS,SAAW,EAAA;AAC3B,QAAM,MAAA,EAAE,KAAQ,GAAA,GAAA;AAChB,QAAA,IAAI,QAAQ,KAAO,EAAA;AACjB,UAAI,IAAA,iBAAA,CAAkB,WAAW,cAAgB,EAAA;AAE/C,YAAA;AAAA,WACK,MAAA;AAEL,YAAA,GAAA,CAAI,cAAe,EAAA;AAAA;AACrB;AACF;AACF;AAEF,IAAA,iBAAA,CAAkB,MAAS,GAAA,cAAA;AAC3B,IAAA,UAAA,CAAW,MAAM;AACf,MAAiB,gBAAA,EAAA;AAAA,OAChB,GAAG,CAAA;AAAA,GACR;AAEA,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,GAAmB,UAA+B,KAAA;AACjD,MAAA,iBAAA,CAAkB,MAAM,UAAU,CAAA;AAClC,MAAiB,gBAAA,EAAA;AAAA,KACnB;AAAA,IACA,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,iBAAoB,GAAA,WAAA;AAAA,IACxB,CAAC,KAAO,EAAA,OAAA,KAAY,iBAAkB,CAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AAAA,IAC7D,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,mBAAsB,GAAA,WAAA;AAAA,IAC1B,MAAM,iBAAkB,CAAA,QAAA,CAAS,KAAS,CAAA,CAAA;AAAA,IAC1C,CAAC,iBAAiB;AAAA,GACpB;AAEA,EAAA,MAAM,8BAAiC,GAAA,WAAA;AAAA,IACrC,CAAC,GAAyC,KAAA;AACxC,MAAA,IAAI,CAAC,WAAa,EAAA,YAAY,EAAE,QAAS,CAAA,GAAA,CAAI,GAAG,CAAG,EAAA;AACjD,QAAA,8BAAA,CAA+B,GAAG,CAAA;AAAA,OACpC,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,WAAa,EAAA;AAClC,QAAA,wCAAA,CAAyC,GAAG,CAAA;AAAA,OAC9C,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,QAAU,EAAA;AAE/B,QAAA,IAAI,CAAC,iBAAA,CAAkB,GAAI,CAAA,MAAM,CAAG,EAAA;AAClC,UAAA,QAAA,GAAW,mBAAmB,QAAQ,CAAA;AAAA;AACxC,OACS,MAAA,IAAA,GAAA,CAAI,GAAQ,KAAA,KAAA,IAAS,IAAI,QAAU,EAAA;AAC5C,QAAA,GAAA,CAAI,cAAe,EAAA;AACnB,QAAA,6BAAA,CAA8B,IAAI,MAAqB,CAAA;AAAA,OACzD,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,KAAO,EAAA;AAE5B,QAAA,IAAI,kBAAkB,OAAS,EAAA;AAE7B,UAAA,GAAA,CAAI,eAAgB,EAAA;AAEpB,UAAc,WAAA,IAAA;AAAA;AAChB;AACF,KACF;AAAA,IACA;AAAA,MACE,iBAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,MAAM,WAAgB,KAAA;AACrB,MAAM,MAAA,aAAA,GAAgB,kBAAkB,EAAO,KAAA,IAAA;AAC/C,MAAA,IAAI,CAAC,IAAA,IAAQ,aAAiB,IAAA,iBAAA,CAAkB,OAAS,EAAA;AACvD,QAAA,iBAAA,CAAkB,MAAO,EAAA;AAAA;AAE3B,MAAA,YAAA,GAAe,MAAM,WAAW,CAAA;AAAA,KAClC;AAAA,IACA,CAAC,mBAAmB,YAAY;AAAA,GAClC;AAEA,EAAA,MAAM,UAAa,GAAA,OAAA;AAAA,IACjB,OAAO;AAAA,MACL,gBAAkB,EAAA,8BAAA;AAAA,MAClB,QAAU,EAAA,CAAA;AAAA,KACZ,CAAA;AAAA,IACA,CAAC,8BAA8B;AAAA,GACjC;AAGA,EAAA,SAAA,CAAU,MAAM;AAGd,IAAI,IAAA,CAAC,kBAAkB,OAAS,EAAA;AAC9B,MAAM,MAAA,QAAA,GACJ,kBAAkB,MAAW,KAAA,KAAA,CAAA,GACzB,YACA,iBAAkB,CAAA,EAAA,KAAO,SACvB,WACA,GAAA,IAAA;AAER,MAAA,qBAAA,CAAsB,MAAM;AAC1B,QAAA,QAAA,EAAU,OAAS,EAAA,aAAA,CAAc,OAAO,CAAA,EAAG,KAAM,EAAA;AAAA,OAClD,CAAA;AAAA;AACH,GACF,EAAG,CAAC,iBAAiB,CAAC,CAAA;AAEtB,EAAO,OAAA;AAAA,IACL,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAe,EAAA,iBAAA;AAAA,IACf,eAAiB,EAAA,mBAAA;AAAA,IACjB,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,YAAc,EAAA,gBAAA;AAAA,IACd,WAAA;AAAA,IACA,cAAgB,EAAA,aAAA,CAAc,iBAAkB,CAAA,MAAA,IAAU,EAAE,CAAA;AAAA,IAC5D,QAAU,EAAA;AAAA,GACZ;AACF;;;;"}
1
+ {"version":3,"file":"useFilterClause.js","sources":["../../../../packages/vuu-filters/src/filter-clause/useFilterClause.ts"],"sourcesContent":["import { FilterClause, FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport { hasOpenOptionList } from \"@vuu-ui/vuu-utils\";\nimport {\n KeyboardEvent,\n RefCallback,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { FilterClauseProps } from \"./FilterClause\";\nimport {\n clauseIsNotFirst,\n focusNextElement,\n focusNextFocusableElement,\n navigateToNextItemIfAtBoundary,\n tabToPreviousFilterCombinator,\n} from \"./filterClauseFocusManagement\";\nimport { ComboBoxOpenChangeHandler } from \"./ExpandoCombobox\";\n\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n> & { onOpenChange?: ComboBoxOpenChangeHandler; openDropdownOnFocus?: boolean };\n\nexport type FilterClauseValueChangeHandler = (\n value: string | string[] | number | number[],\n isFinal?: boolean,\n) => void;\n\nexport const useFilterClause = ({\n filterClauseModel,\n onCancel,\n columnsByName,\n onFocusSave,\n onOpenChange,\n openDropdownOnFocus = true,\n}: FilterClauseEditorHookProps) => {\n const [filterClause, setFilterClause] = useState<Partial<FilterClause>>(\n filterClauseModel.isValid ? filterClauseModel.asFilter() : {},\n );\n\n useMemo(() => {\n filterClauseModel.on(\"filterClause\", (filterClause) => {\n setFilterClause(filterClause);\n });\n }, [filterClauseModel]);\n\n const columnRef = useRef<HTMLDivElement>(null);\n const operatorRef = useRef<HTMLDivElement>(null);\n const valueRef = useRef<HTMLDivElement | null>(null);\n const filterTouched = useRef(false);\n\n const filterClauseTouched = useCallback(() => {\n const unTouched = !openDropdownOnFocus && !filterTouched.current;\n const setTouched = (state: boolean) => filterTouched.current = state;\n if (unTouched) {\n setTouched(true);\n return false;\n }\n return true;\n }, [openDropdownOnFocus]);\n\n const setValueRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n valueRef.current = el;\n if (!filterClauseModel.isValid && filterClauseTouched()) { \n el?.querySelector(\"input\")?.focus();\n }\n },\n [filterClauseModel.isValid, filterClauseTouched],\n );\n\n const removeAndNavigateToNextInputIfAtBoundary = useCallback(\n (evt: KeyboardEvent) => {\n const input = evt.target as HTMLInputElement;\n if (input.value === \"\") {\n const field = input.closest(\"[data-field]\") as HTMLElement;\n switch (field?.dataset?.field) {\n case \"operator\": {\n filterClauseModel.column = undefined;\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"value\": {\n filterClauseModel.setOp(undefined);\n focusNextFocusableElement(\"bwd\");\n break;\n }\n case \"column\": {\n if (clauseIsNotFirst(input)) {\n // When we backspace from an empty clause, the clause will be removed.filterClause\n // In this case, we will reposition focus on previous clause, but we\n // don't want the backspace to be effect an edit on that clause.\n evt.preventDefault();\n onCancel?.(filterClauseModel, \"Backspace\");\n }\n }\n }\n }\n },\n [filterClauseModel, onCancel],\n );\n\n const onSelectColumn = (evt: SyntheticEvent, selectedColumn: string) => {\n if (selectedColumn) {\n if (evt?.type === \"keydown\") {\n const { key } = evt as KeyboardEvent;\n if (key === \"Tab\") {\n if (filterClauseModel.column === selectedColumn) {\n // No selection change, allow normal Tab navigation (to Save button)\n return;\n } else {\n // Tab is being used to change selection, keep focus within the clause\n evt.preventDefault();\n }\n }\n }\n }\n filterClauseModel.column = selectedColumn;\n setTimeout(() => {\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_: SyntheticEvent, selectedOp: FilterClauseOp) => {\n filterClauseModel.setOp(selectedOp);\n focusNextElement();\n },\n [filterClauseModel],\n );\n\n const handleChangeValue = useCallback<FilterClauseValueChangeHandler>(\n (value, isFinal) => filterClauseModel.setValue(value, isFinal),\n [filterClauseModel],\n );\n\n const handleDeselectValue = useCallback(\n () => filterClauseModel.setValue(undefined),\n [filterClauseModel],\n );\n\n const handleKeyDownCaptureNavigation = useCallback(\n (evt: KeyboardEvent<HTMLInputElement>) => {\n if ([\"ArrowLeft\", \"ArrowRight\"].includes(evt.key)) {\n navigateToNextItemIfAtBoundary(evt);\n } else if (evt.key === \"Backspace\") {\n removeAndNavigateToNextInputIfAtBoundary(evt);\n } else if (evt.key === \"Escape\") {\n // ignore when optionlist is open, the optionList will be collapsed\n if (!hasOpenOptionList(evt.target)) {\n onCancel?.(filterClauseModel, \"Escape\");\n }\n } else if (evt.key === \"Tab\" && evt.shiftKey) {\n evt.preventDefault();\n tabToPreviousFilterCombinator(evt.target as HTMLElement);\n } else if (evt.key === \"Tab\") {\n // if the clause is valid, skip to save\n if (filterClauseModel.isValid) {\n evt.preventDefault();\n evt.stopPropagation();\n // TODO focus cancel if not changed\n onFocusSave?.();\n }\n }\n },\n [\n filterClauseModel,\n onCancel,\n onFocusSave,\n removeAndNavigateToNextInputIfAtBoundary,\n ],\n );\n\n const handleOpenChange = useCallback<ComboBoxOpenChangeHandler>(\n (open, closeReason) => {\n const isMultiSelect = filterClauseModel.op === \"in\";\n const filterHasNoValue =\n !filterClauseModel.isValid &&\n filterClauseModel.op !== undefined &&\n filterClauseModel.column !== undefined;\n\n if (\n !open &&\n isMultiSelect &&\n (filterClauseModel.isValid || filterHasNoValue)\n ) {\n filterClauseModel.commit();\n }\n onOpenChange?.(open, closeReason);\n },\n [filterClauseModel, onOpenChange],\n );\n\n const inputProps = useMemo(\n () => ({\n onKeyDownCapture: handleKeyDownCaptureNavigation,\n tabIndex: -1,\n }),\n [handleKeyDownCaptureNavigation],\n );\n\n // Do we need this or can we leave it to the filterEditor\n useEffect(() => {\n // leave the valueInput to callbackRef handler above, may\n // fire after the requestAnimationFrame\n const inputRef =\n filterClauseModel.column === undefined\n ? columnRef\n : filterClauseModel.op === undefined\n ? operatorRef\n : null;\n\n if (!filterClauseModel.isValid && inputRef) {\n if (filterClauseTouched()) {\n requestAnimationFrame(() => {\n inputRef.current?.querySelector(\"input\")?.focus();\n });\n }\n }\n }, [filterClauseModel, filterClauseTouched]);\n\n return {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue: handleChangeValue,\n onDeselectValue: handleDeselectValue,\n onSelectColumn,\n onSelectOperator,\n onOpenChange: handleOpenChange,\n operatorRef,\n selectedColumn: columnsByName[filterClauseModel.column ?? \"\"],\n valueRef: setValueRef,\n };\n};\n"],"names":["filterClause"],"mappings":"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"}
@@ -179,7 +179,8 @@ const FilterClauseValueEditorText = forwardRef(
179
179
  handleInputCommit,
180
180
  handleMultiValueSelectionChange,
181
181
  value,
182
- handleSingleValueSelectionChange
182
+ handleSingleValueSelectionChange,
183
+ onOpenChange
183
184
  ]);
184
185
  return getValueInputField();
185
186
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FilterClauseValueEditorText.js","sources":["../../../../../packages/vuu-filters/src/filter-clause/value-editors/FilterClauseValueEditorText.tsx"],"sourcesContent":["import { useTypeaheadSuggestions } from \"@vuu-ui/vuu-data-react\";\nimport type { TypeaheadParams } from \"@vuu-ui/vuu-protocol-types\";\nimport { ExpandoInput, MultiSelectionHandler } from \"@vuu-ui/vuu-ui-controls\";\nimport { CommitHandler, getVuuTable, NO_DATA_MATCH } from \"@vuu-ui/vuu-utils\";\nimport { Option } from \"@salt-ds/core\";\nimport {\n FormEvent,\n ForwardedRef,\n forwardRef,\n HTMLAttributes,\n KeyboardEventHandler,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { ExpandoCombobox } from \"../ExpandoCombobox\";\nimport { FilterClauseValueEditor } from \"../filterClauseTypes\";\n\nexport interface FilterClauseTextValueEditorProps\n extends FilterClauseValueEditor,\n HTMLAttributes<HTMLDivElement> {\n \"data-field\"?: string;\n // ref: RefObject<HTMLDivElement>;\n operator: string;\n value: string | string[];\n}\n\nexport const FilterClauseValueEditorText = forwardRef(\n function FilterClauseTextValueEditor(\n {\n inputProps: inputPropsProp,\n className,\n column,\n onChangeValue,\n onOpenChange,\n operator,\n table,\n value,\n }: FilterClauseTextValueEditorProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n ) {\n const isMultiValue = operator === \"in\";\n\n // If we have a multiselect text value which we are editing, this will render\n // a comma delimited list of the selected values. That is not what we display\n // by default when using a multiselect combo. Its not a huge problem - as soon\n // as user focuses this component and we display dropdown, input text is cleared\n // (so user can type to filter list) until dropdown closes again. <ight need to\n // revisit.\n const [valueInputValue, setValueInputValue] = useState(\n value?.toString() ?? \"\",\n );\n const [typeaheadValues, setTypeaheadValues] = useState<string[] | false>(\n [],\n );\n\n const getSuggestions = useTypeaheadSuggestions();\n\n const handleSingleValueSelectionChange = useCallback(\n (_: SyntheticEvent, [value]: string[]) => onChangeValue(value),\n [onChangeValue],\n );\n\n const handleMultiValueSelectionChange = useCallback<MultiSelectionHandler>(\n // TODO when will this ever be final ?\n (_, values) => onChangeValue(values, false),\n [onChangeValue],\n );\n\n useEffect(() => {\n if (table) {\n const vuuTable = getVuuTable(table);\n const params: TypeaheadParams =\n valueInputValue && !isMultiValue\n ? [vuuTable, column.name, valueInputValue]\n : [vuuTable, column.name];\n getSuggestions(params)\n .then((suggestions) => {\n if (suggestions === false) {\n setTypeaheadValues(false);\n } else if (suggestions.length === 0 && valueInputValue) {\n setTypeaheadValues(NO_DATA_MATCH);\n } else {\n setTypeaheadValues(suggestions);\n }\n })\n .catch((err) => {\n console.error(\"Error getting suggestions\", err);\n });\n }\n }, [table, column, valueInputValue, getSuggestions, isMultiValue]);\n\n const handleInputChange = useCallback(\n (evt: FormEvent<HTMLInputElement>) => {\n const { value } = evt.target as HTMLInputElement;\n setValueInputValue(value);\n // we want to set the filterclause status to valid, but not trigger focus change\n if (\n operator === \"starts\" ||\n operator === \"ends\" ||\n operator === \"contains\"\n ) {\n onChangeValue(value, false);\n }\n },\n [onChangeValue, operator],\n );\n\n const handleInputCommit = useCallback<CommitHandler>(\n (_, value = \"\") => {\n if (typeof value === \"string\") {\n onChangeValue(value);\n }\n },\n [onChangeValue],\n );\n\n const handleKeyDownFreeTextInput = useCallback<\n KeyboardEventHandler<HTMLInputElement>\n >(\n (evt) => {\n if (\n (evt.key === \"Enter\" || evt.key === \"Tab\") &&\n valueInputValue !== \"\"\n ) {\n evt.stopPropagation();\n evt.preventDefault();\n onChangeValue(valueInputValue);\n } else {\n inputPropsProp?.onKeyDown?.(evt);\n }\n },\n [inputPropsProp, onChangeValue, valueInputValue],\n );\n\n const inputProps = useMemo(() => {\n if (operator === \"starts\" || operator === \"ends\") {\n return {\n ...inputPropsProp,\n onKeyDown: handleKeyDownFreeTextInput,\n };\n } else {\n return inputPropsProp;\n }\n }, [inputPropsProp, handleKeyDownFreeTextInput, operator]);\n\n const getValueInputField = useCallback(() => {\n if (typeaheadValues === false) {\n // No typeahead service available\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n onCommit={handleInputCommit}\n />\n );\n }\n switch (operator) {\n case \"in\":\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onOpenChange={onOpenChange}\n onSelectionChange={handleMultiValueSelectionChange}\n ref={forwardedRef}\n multiselect\n truncate\n value={value}\n >\n {typeaheadValues\n // .filter((typeaheadValue) =>\n // typeaheadValue\n // .toLowerCase()\n // .includes(value.trim().toLowerCase())\n // )\n .map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n );\n case \"starts\": {\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} disabled />\n ))}\n </ExpandoCombobox>\n );\n }\n\n case \"ends\":\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n />\n );\n\n default: {\n return typeaheadValues.length > 0 ? (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n title=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n ) : null;\n }\n }\n }, [\n typeaheadValues,\n operator,\n inputProps,\n className,\n valueInputValue,\n forwardedRef,\n handleInputChange,\n handleInputCommit,\n handleMultiValueSelectionChange,\n value,\n handleSingleValueSelectionChange,\n ]);\n\n return getValueInputField();\n },\n);\n"],"names":["value"],"mappings":"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"}
1
+ {"version":3,"file":"FilterClauseValueEditorText.js","sources":["../../../../../packages/vuu-filters/src/filter-clause/value-editors/FilterClauseValueEditorText.tsx"],"sourcesContent":["import { useTypeaheadSuggestions } from \"@vuu-ui/vuu-data-react\";\nimport type { TypeaheadParams } from \"@vuu-ui/vuu-protocol-types\";\nimport { ExpandoInput, MultiSelectionHandler } from \"@vuu-ui/vuu-ui-controls\";\nimport { CommitHandler, getVuuTable, NO_DATA_MATCH } from \"@vuu-ui/vuu-utils\";\nimport { Option } from \"@salt-ds/core\";\nimport {\n FormEvent,\n ForwardedRef,\n forwardRef,\n HTMLAttributes,\n KeyboardEventHandler,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { ExpandoCombobox } from \"../ExpandoCombobox\";\nimport { FilterClauseValueEditor } from \"../filterClauseTypes\";\n\nexport interface FilterClauseTextValueEditorProps\n extends FilterClauseValueEditor,\n HTMLAttributes<HTMLDivElement> {\n \"data-field\"?: string;\n // ref: RefObject<HTMLDivElement>;\n operator: string;\n value: string | string[];\n}\n\nexport const FilterClauseValueEditorText = forwardRef(\n function FilterClauseTextValueEditor(\n {\n inputProps: inputPropsProp,\n className,\n column,\n onChangeValue,\n onOpenChange,\n operator,\n table,\n value,\n }: FilterClauseTextValueEditorProps,\n forwardedRef: ForwardedRef<HTMLDivElement>,\n ) {\n const isMultiValue = operator === \"in\";\n\n // If we have a multiselect text value which we are editing, this will render\n // a comma delimited list of the selected values. That is not what we display\n // by default when using a multiselect combo. Its not a huge problem - as soon\n // as user focuses this component and we display dropdown, input text is cleared\n // (so user can type to filter list) until dropdown closes again. <ight need to\n // revisit.\n const [valueInputValue, setValueInputValue] = useState(\n value?.toString() ?? \"\",\n );\n const [typeaheadValues, setTypeaheadValues] = useState<string[] | false>(\n [],\n );\n\n const getSuggestions = useTypeaheadSuggestions();\n\n const handleSingleValueSelectionChange = useCallback(\n (_: SyntheticEvent, [value]: string[]) => onChangeValue(value),\n [onChangeValue],\n );\n\n const handleMultiValueSelectionChange = useCallback<MultiSelectionHandler>(\n // TODO when will this ever be final ?\n (_, values) => onChangeValue(values, false),\n [onChangeValue],\n );\n\n useEffect(() => {\n if (table) {\n const vuuTable = getVuuTable(table);\n const params: TypeaheadParams =\n valueInputValue && !isMultiValue\n ? [vuuTable, column.name, valueInputValue]\n : [vuuTable, column.name];\n getSuggestions(params)\n .then((suggestions) => {\n if (suggestions === false) {\n setTypeaheadValues(false);\n } else if (suggestions.length === 0 && valueInputValue) {\n setTypeaheadValues(NO_DATA_MATCH);\n } else {\n setTypeaheadValues(suggestions);\n }\n })\n .catch((err) => {\n console.error(\"Error getting suggestions\", err);\n });\n }\n }, [table, column, valueInputValue, getSuggestions, isMultiValue]);\n\n const handleInputChange = useCallback(\n (evt: FormEvent<HTMLInputElement>) => {\n const { value } = evt.target as HTMLInputElement;\n setValueInputValue(value);\n // we want to set the filterclause status to valid, but not trigger focus change\n if (\n operator === \"starts\" ||\n operator === \"ends\" ||\n operator === \"contains\"\n ) {\n onChangeValue(value, false);\n }\n },\n [onChangeValue, operator],\n );\n\n const handleInputCommit = useCallback<CommitHandler>(\n (_, value = \"\") => {\n if (typeof value === \"string\") {\n onChangeValue(value);\n }\n },\n [onChangeValue],\n );\n\n const handleKeyDownFreeTextInput = useCallback<\n KeyboardEventHandler<HTMLInputElement>\n >(\n (evt) => {\n if (\n (evt.key === \"Enter\" || evt.key === \"Tab\") &&\n valueInputValue !== \"\"\n ) {\n evt.stopPropagation();\n evt.preventDefault();\n onChangeValue(valueInputValue);\n } else {\n inputPropsProp?.onKeyDown?.(evt);\n }\n },\n [inputPropsProp, onChangeValue, valueInputValue],\n );\n\n const inputProps = useMemo(() => {\n if (operator === \"starts\" || operator === \"ends\") {\n return {\n ...inputPropsProp,\n onKeyDown: handleKeyDownFreeTextInput,\n };\n } else {\n return inputPropsProp;\n }\n }, [inputPropsProp, handleKeyDownFreeTextInput, operator]);\n\n const getValueInputField = useCallback(() => {\n if (typeaheadValues === false) {\n // No typeahead service available\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n onCommit={handleInputCommit}\n />\n );\n }\n switch (operator) {\n case \"in\":\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onOpenChange={onOpenChange}\n onSelectionChange={handleMultiValueSelectionChange}\n ref={forwardedRef}\n multiselect\n truncate\n value={value}\n >\n {typeaheadValues\n // .filter((typeaheadValue) =>\n // typeaheadValue\n // .toLowerCase()\n // .includes(value.trim().toLowerCase())\n // )\n .map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n );\n case \"starts\": {\n return (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} disabled />\n ))}\n </ExpandoCombobox>\n );\n }\n\n case \"ends\":\n return (\n <ExpandoInput\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n value={valueInputValue}\n ref={forwardedRef}\n onChange={handleInputChange}\n />\n );\n\n default: {\n return typeaheadValues.length > 0 ? (\n <ExpandoCombobox\n inputProps={inputProps}\n className={className}\n data-field=\"value\"\n title=\"value\"\n onChange={handleInputChange}\n onSelectionChange={handleSingleValueSelectionChange}\n ref={forwardedRef}\n value={value}\n >\n {typeaheadValues.map((state) => (\n <Option value={state} key={state} />\n ))}\n </ExpandoCombobox>\n ) : null;\n }\n }\n }, [\n typeaheadValues,\n operator,\n inputProps,\n className,\n valueInputValue,\n forwardedRef,\n handleInputChange,\n handleInputCommit,\n handleMultiValueSelectionChange,\n value,\n handleSingleValueSelectionChange,\n onOpenChange,\n ]);\n\n return getValueInputField();\n },\n);\n"],"names":["value"],"mappings":"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"}
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
- "version": "0.13.16",
2
+ "version": "0.13.18",
3
3
  "author": "heswell",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "devDependencies": {
7
- "@vuu-ui/vuu-data-types": "0.13.16",
8
- "@vuu-ui/vuu-protocol-types": "0.13.16",
9
- "@vuu-ui/vuu-table-types": "0.13.16",
10
- "@vuu-ui/vuu-filter-types": "0.13.16"
7
+ "@vuu-ui/vuu-data-types": "0.13.18",
8
+ "@vuu-ui/vuu-protocol-types": "0.13.18",
9
+ "@vuu-ui/vuu-table-types": "0.13.18",
10
+ "@vuu-ui/vuu-filter-types": "0.13.18"
11
11
  },
12
12
  "dependencies": {
13
- "@vuu-ui/vuu-data-react": "0.13.16",
14
- "@vuu-ui/vuu-filter-parser": "0.13.16",
15
- "@vuu-ui/vuu-popups": "0.13.16",
16
- "@vuu-ui/vuu-ui-controls": "0.13.16",
17
- "@vuu-ui/vuu-table": "0.13.16",
18
- "@vuu-ui/vuu-utils": "0.13.16",
13
+ "@vuu-ui/vuu-data-react": "0.13.18",
14
+ "@vuu-ui/vuu-filter-parser": "0.13.18",
15
+ "@vuu-ui/vuu-popups": "0.13.18",
16
+ "@vuu-ui/vuu-ui-controls": "0.13.18",
17
+ "@vuu-ui/vuu-table": "0.13.18",
18
+ "@vuu-ui/vuu-utils": "0.13.18",
19
19
  "@salt-ds/core": "1.43.0",
20
20
  "@salt-ds/styles": "0.2.1",
21
21
  "@salt-ds/window": "0.1.1"
@@ -10,6 +10,7 @@ export interface FilterClauseProps extends Omit<HTMLAttributes<HTMLDivElement>,
10
10
  onCancel?: FilterClauseCancelHandler;
11
11
  onDropdownOpen?: () => void;
12
12
  onFocusSave?: () => void;
13
+ openDropdownOnFocus?: boolean;
13
14
  vuuTable: VuuTable;
14
15
  }
15
- export declare const FilterClause: ({ className, columnsByName, onCancel, onDropdownOpen, onFocusSave, filterClauseModel, vuuTable, ...htmlAttributes }: FilterClauseProps) => import("react/jsx-runtime").JSX.Element;
16
+ export declare const FilterClause: ({ className, columnsByName, onCancel, onDropdownOpen, onFocusSave, filterClauseModel, vuuTable, openDropdownOnFocus, ...htmlAttributes }: FilterClauseProps) => import("react/jsx-runtime").JSX.Element;
@@ -4,9 +4,10 @@ import { FilterClauseProps } from "./FilterClause";
4
4
  import { ComboBoxOpenChangeHandler } from "./ExpandoCombobox";
5
5
  export type FilterClauseEditorHookProps = Pick<FilterClauseProps, "columnsByName" | "filterClauseModel" | "onCancel" | "onFocusSave"> & {
6
6
  onOpenChange?: ComboBoxOpenChangeHandler;
7
+ openDropdownOnFocus?: boolean;
7
8
  };
8
9
  export type FilterClauseValueChangeHandler = (value: string | string[] | number | number[], isFinal?: boolean) => void;
9
- export declare const useFilterClause: ({ filterClauseModel, onCancel, columnsByName, onFocusSave, onOpenChange, }: FilterClauseEditorHookProps) => {
10
+ export declare const useFilterClause: ({ filterClauseModel, onCancel, columnsByName, onFocusSave, onOpenChange, openDropdownOnFocus, }: FilterClauseEditorHookProps) => {
10
11
  inputProps: {
11
12
  onKeyDownCapture: (evt: KeyboardEvent<HTMLInputElement>) => void;
12
13
  tabIndex: number;