@vuu-ui/vuu-filters 0.8.72 → 0.8.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/filter-clause/FilterClause.css.js +1 -1
- package/cjs/filter-clause/FilterClause.js +45 -53
- package/cjs/filter-clause/FilterClause.js.map +1 -1
- package/cjs/filter-clause/filterClauseFocusManagement.js +0 -1
- package/cjs/filter-clause/filterClauseFocusManagement.js.map +1 -1
- package/cjs/filter-clause/useFilterClause.js +15 -10
- package/cjs/filter-clause/useFilterClause.js.map +1 -1
- package/cjs/filter-clause/value-editors/FilterClauseValueEditor.js +60 -55
- package/cjs/filter-clause/value-editors/FilterClauseValueEditor.js.map +1 -1
- package/esm/filter-clause/FilterClause.css.js +1 -1
- package/esm/filter-clause/FilterClause.js +45 -53
- package/esm/filter-clause/FilterClause.js.map +1 -1
- package/esm/filter-clause/filterClauseFocusManagement.js +1 -1
- package/esm/filter-clause/filterClauseFocusManagement.js.map +1 -1
- package/esm/filter-clause/useFilterClause.js +16 -11
- package/esm/filter-clause/useFilterClause.js.map +1 -1
- package/esm/filter-clause/value-editors/FilterClauseValueEditor.js +60 -55
- package/esm/filter-clause/value-editors/FilterClauseValueEditor.js.map +1 -1
- package/package.json +11 -11
- package/types/filter-clause/filterClauseFocusManagement.d.ts +0 -1
- package/types/filter-clause/useFilterClause.d.ts +2 -2
- package/types/filter-clause/value-editors/FilterClauseValueEditor.d.ts +19 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var filterClauseCss = ".vuuFilterClause {\n --vuuExpandoInput-top: 0;\n --content-height: calc(var(--salt-size-base) - var(--salt-spacing-150));\n --vuuExpandoInput-height: var(--content-height);\n --vuuExpandoCombobox-height: var(--content-height);\n --saltButton-height: 16px;\n --saltButton-width: 16px;\n --salt-focused-outlineStyle: dotted;\n\n align-items: center;\n background: var(--salt-container-primary-background);\n border-color: var(--vuu-color-gray-45);\n border-radius: var(--saltButton-borderRadius);\n border-width: 1px;\n border-style: solid;\n display: flex;\n flex-direction: row;\n gap: var(--salt-spacing-50);\n height: var(--salt-size-base);\n min-width: calc(var(--salt-size-base) * 4);\n padding: 0 var(--salt-spacing-100);\n width: fit-content;\n\n\n .
|
|
3
|
+
var filterClauseCss = ".vuuFilterClause {\n --vuuExpandoInput-top: 0;\n --content-height: calc(var(--salt-size-base) - var(--salt-spacing-150));\n --vuuExpandoInput-height: var(--content-height);\n --vuuExpandoCombobox-height: var(--content-height);\n --saltButton-height: 16px;\n --saltButton-width: 16px;\n --salt-focused-outlineStyle: dotted;\n\n align-items: center;\n background: var(--salt-container-primary-background);\n border-color: var(--vuu-color-gray-45);\n border-radius: var(--saltButton-borderRadius);\n border-width: 1px;\n border-style: solid;\n display: flex;\n flex-direction: row;\n gap: var(--salt-spacing-50);\n height: var(--salt-size-base);\n min-width: calc(var(--salt-size-base) * 4);\n padding: 0 var(--salt-spacing-100);\n width: fit-content;\n\n .vuuFilterClauseField {\n flex: 0 0 auto;\n }\n .vuuFilterClauseField:last-child {\n flex: 1 0 auto;\n }\n\n .vuuExpandoCombobox {\n flex-basis: auto;\n flex-shrink: 0;\n flex-grow: 0;\n }\n\n &:focus-within {\n border-color: var(--vuu-color-purple-10);\n }\n\n .saltComboBox-focused {\n outline: none;\n }\n\n .saltTokenizedInput {\n height: 16px;\n min-height: 16px;\n }\n\n .saltTokenizedInput .saltInputPill {\n --pill-fontSize: 12px;\n --saltButton-borderStyle: none;\n --pill-background: none;\n height: 16px;\n margin: 0;\n }\n\n .saltTokenizedInput-pillGroup {\n padding: 0;\n height: 16px;\n }\n}\n\n.salt-density-high .vuuFilterClause {\n padding: 4px 8px;\n gap: 4px;\n --salt-text-lineHeight: 12px;\n --saltInputLegacy-fontSize: 12px;\n --saltInputLegacy-minWidth: 12px;\n}\n\n.salt-density-high .vuuFilterClause .saltInput {\n padding: 0;\n min-height: 16px;\n height: 16px;\n}\n\n.vuuFilterClauseOperator-hidden {\n display: none;\n}\n\n.vuuFilterClause .saltInput-focused,\n.vuuFilterClause .saltTokenizedInput-focused {\n outline: none;\n color: var(--salt-content-primary-foreground);\n}\n\n.vuuFilterClause-DatePicker {\n border: none;\n}\n";
|
|
4
4
|
|
|
5
5
|
module.exports = filterClauseCss;
|
|
6
6
|
//# sourceMappingURL=FilterClause.css.js.map
|
|
@@ -32,10 +32,10 @@ const FilterClause = ({
|
|
|
32
32
|
// onChangeColumn,
|
|
33
33
|
onSelectColumn,
|
|
34
34
|
onSelectOperator,
|
|
35
|
-
onFocus,
|
|
36
35
|
onDeselectValue,
|
|
37
36
|
operatorRef,
|
|
38
|
-
selectedColumn
|
|
37
|
+
selectedColumn,
|
|
38
|
+
valueRef
|
|
39
39
|
} = useFilterClause.useFilterClause({
|
|
40
40
|
filterClauseModel,
|
|
41
41
|
onCancel,
|
|
@@ -49,57 +49,49 @@ const FilterClause = ({
|
|
|
49
49
|
window: targetWindow
|
|
50
50
|
});
|
|
51
51
|
const columns = react.useMemo(() => Object.values(columnsByName), [columnsByName]);
|
|
52
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
table: tableSchema.table,
|
|
96
|
-
value: filterClause?.values ?? filterClause?.value
|
|
97
|
-
},
|
|
98
|
-
"value-field"
|
|
99
|
-
)
|
|
100
|
-
]
|
|
101
|
-
}
|
|
102
|
-
);
|
|
52
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx(classBase, className), ...htmlAttributes, tabIndex: 0, children: [
|
|
53
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
54
|
+
ColumnPicker.ColumnPicker,
|
|
55
|
+
{
|
|
56
|
+
inputProps,
|
|
57
|
+
className: cx(`${classBase}Field`, `${classBase}Column`),
|
|
58
|
+
columns,
|
|
59
|
+
onSelect: onSelectColumn,
|
|
60
|
+
ref: columnRef,
|
|
61
|
+
value: filterClauseModel.column ?? ""
|
|
62
|
+
},
|
|
63
|
+
"column-field"
|
|
64
|
+
),
|
|
65
|
+
selectedColumn?.name ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
66
|
+
OperatorPicker.OperatorPicker,
|
|
67
|
+
{
|
|
68
|
+
column: selectedColumn,
|
|
69
|
+
inputProps,
|
|
70
|
+
className: cx(`${classBase}Field`, `${classBase}Operator`, {
|
|
71
|
+
[`${classBase}Operator-hidden`]: selectedColumn === null
|
|
72
|
+
}),
|
|
73
|
+
onSelect: onSelectOperator,
|
|
74
|
+
ref: operatorRef,
|
|
75
|
+
value: filterClauseModel.op ?? ""
|
|
76
|
+
},
|
|
77
|
+
"operator-field"
|
|
78
|
+
) : null,
|
|
79
|
+
filterClauseModel.op ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
80
|
+
FilterClauseValueEditor.FilterClauseValueEditor,
|
|
81
|
+
{
|
|
82
|
+
inputProps,
|
|
83
|
+
onChangeValue,
|
|
84
|
+
onDeselectValue,
|
|
85
|
+
operator: filterClauseModel.op,
|
|
86
|
+
ref: valueRef,
|
|
87
|
+
selectedColumn,
|
|
88
|
+
suggestionProvider,
|
|
89
|
+
table: tableSchema.table,
|
|
90
|
+
value: filterClause?.values ?? filterClause?.value
|
|
91
|
+
},
|
|
92
|
+
"value-field"
|
|
93
|
+
) : null
|
|
94
|
+
] });
|
|
103
95
|
};
|
|
104
96
|
|
|
105
97
|
exports.FilterClause = FilterClause;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterClause.js","sources":["../../src/filter-clause/FilterClause.tsx"],"sourcesContent":["import type { SuggestionProvider, TableSchema } from \"@vuu-ui/vuu-data-types\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport { CloseReason } from \"@vuu-ui/vuu-ui-controls\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\nimport { ColumnPicker } from \"./ColumnPicker\";\n\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 onDropdownClose?: (closeReason: CloseReason) => void;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n suggestionProvider?: SuggestionProvider;\n tableSchema: TableSchema;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownClose,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n suggestionProvider,\n tableSchema,\n ...htmlAttributes\n}: FilterClauseProps) => {\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n // onChangeColumn,\n onSelectColumn,\n onSelectOperator,\n
|
|
1
|
+
{"version":3,"file":"FilterClause.js","sources":["../../src/filter-clause/FilterClause.tsx"],"sourcesContent":["import type { SuggestionProvider, TableSchema } from \"@vuu-ui/vuu-data-types\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport { CloseReason } from \"@vuu-ui/vuu-ui-controls\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\nimport { ColumnPicker } from \"./ColumnPicker\";\n\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 onDropdownClose?: (closeReason: CloseReason) => void;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n suggestionProvider?: SuggestionProvider;\n tableSchema: TableSchema;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownClose,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n suggestionProvider,\n tableSchema,\n ...htmlAttributes\n}: FilterClauseProps) => {\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n // onChangeColumn,\n onSelectColumn,\n onSelectOperator,\n onDeselectValue,\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 onDeselectValue={onDeselectValue}\n operator={filterClauseModel.op}\n ref={valueRef}\n selectedColumn={selectedColumn}\n suggestionProvider={suggestionProvider}\n table={tableSchema.table}\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":";;;;;;;;;;;;;AAqCA,MAAM,SAAY,GAAA,iBAAA,CAAA;AAEX,MAAM,eAAe,CAAC;AAAA,EAC3B,SAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,kBAAA;AAAA,EACA,WAAA;AAAA,EACA,GAAG,cAAA;AACL,CAAyB,KAAA;AACvB,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA;AAAA,IAEA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA,QAAA;AAAA,MACEA,+BAAgB,CAAA;AAAA,IAClB,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,MAAM,eAAeC,gBAAU,EAAA,CAAA;AAC/B,EAAyBC,+BAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,mBAAA;AAAA,IACR,GAAK,EAAAC,cAAA;AAAA,IACL,MAAQ,EAAA,YAAA;AAAA,GACT,CAAA,CAAA;AAED,EAAM,MAAA,OAAA,GAAUC,cAAQ,MAAM,MAAA,CAAO,OAAO,aAAa,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA,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,EAAA;AAAA,OAAA;AAAA,MAH/B,cAAA;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,IAAA;AAAA,SACrD,CAAA;AAAA,QAED,QAAU,EAAA,gBAAA;AAAA,QACV,GAAK,EAAA,WAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,EAAM,IAAA,EAAA;AAAA,OAAA;AAAA,MAH3B,gBAAA;AAAA,KAKJ,GAAA,IAAA;AAAA,IACH,kBAAkB,EACjB,mBAAAF,cAAA;AAAA,MAACG,+CAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QAEA,aAAA;AAAA,QACA,eAAA;AAAA,QACA,UAAU,iBAAkB,CAAA,EAAA;AAAA,QAC5B,GAAK,EAAA,QAAA;AAAA,QACL,cAAA;AAAA,QACA,kBAAA;AAAA,QACA,OAAO,WAAY,CAAA,KAAA;AAAA,QACnB,KAAA,EACG,YAAyC,EAAA,MAAA,IACzC,YAA0C,EAAA,KAAA;AAAA,OAAA;AAAA,MAVzC,aAAA;AAAA,KAaJ,GAAA,IAAA;AAAA,GACN,EAAA,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -190,7 +190,6 @@ const focusFirstClauseIfAllClausesValid = (filterEditor) => {
|
|
|
190
190
|
exports.clauseIsNotFirst = clauseIsNotFirst;
|
|
191
191
|
exports.elementIsFilterClause = elementIsFilterClause;
|
|
192
192
|
exports.elementIsFilterCombinator = elementIsFilterCombinator;
|
|
193
|
-
exports.focusField = focusField;
|
|
194
193
|
exports.focusFilterClauseField = focusFilterClauseField;
|
|
195
194
|
exports.focusFirstClauseIfAllClausesValid = focusFirstClauseIfAllClausesValid;
|
|
196
195
|
exports.focusLastClauseValue = focusLastClauseValue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterClauseFocusManagement.js","sources":["../../src/filter-clause/filterClauseFocusManagement.ts"],"sourcesContent":["import { getElementDataIndex, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEvent } from \"react\";\n\nconst getFilterClauseElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClause\") as HTMLElement;\n\nconst getFilterClauseFieldElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClauseField\") as HTMLElement;\n\ntype FilterClauseFieldName = \"column\" | \"operator\" | \"value\";\nconst mapFilterFieldToClassName: Record<FilterClauseFieldName, string> = {\n column: \"vuuFilterClauseColumn\",\n operator: \"vuuFilterClauseOperator\",\n value: \"vuuFilterClauseValue\",\n};\n\nconst getFilterClauseDetails = ({ classList }: HTMLElement) => {\n if (classList.contains(\"vuuFilterClauseColumn\")) {\n return \"column\";\n } else if (classList.contains(\"vuuFilterClauseOperator\")) {\n return \"operator\";\n } else if (classList.contains(\"vuuFilterClauseValue\")) {\n return \"value\";\n } else {\n throw Error(\n \"getFilterClauseField, filterClauseElemnent is missing required class name\"\n );\n }\n};\n\nexport const getFocusedFieldDetails = (): [number, string] | [] => {\n const el = document.activeElement as HTMLElement;\n const field = queryClosest(el, \".vuuFilterClauseField\");\n const filterClause = queryClosest(field, \".vuuFilterClause\");\n if (filterClause && field) {\n return [getElementDataIndex(filterClause), getFilterClauseDetails(field)];\n } else {\n return [];\n }\n};\n\n// Focus the input control within field. If clause passed, will\n// focus first field within clause\nexport const focusField = (fieldOrClause: HTMLElement | null) => {\n const input = fieldOrClause?.querySelector(\"input\");\n if (input) {\n input.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n }\n};\n\nexport const elementIsFilterCombinator = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClauseCombinator\");\n\nexport const elementIsFilterClause = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClause\");\n\nexport const focusFilterClauseField = (\n filterEditor: HTMLElement,\n filterClauseIndex: number,\n fieldName: FilterClauseFieldName = \"value\"\n) => {\n if (filterEditor) {\n const fieldClassName = mapFilterFieldToClassName[fieldName];\n const field = filterEditor.querySelector(\n `.vuuFilterClause[data-index=\"${filterClauseIndex}\"] .${fieldClassName}`\n ) as HTMLElement;\n focusField(field);\n }\n};\n\nexport const focusLastClauseValue = (filterEditor: HTMLElement) => {\n console.log(\"focusLastClauseValue\");\n const field = Array.from(\n filterEditor?.querySelectorAll(\".vuuFilterClauseField\")\n ).at(-1) as HTMLElement;\n focusField(field);\n};\n\nexport const focusNextFocusableElement = (direction: \"fwd\" | \"bwd\" = \"fwd\") => {\n const activeField = getFocusedField() as HTMLElement;\n const filterClause = getFilterClauseElement(activeField);\n if (direction === \"fwd\" && filterClause?.lastChild === activeField) {\n requestAnimationFrame(() => {\n focusNextFocusableElement();\n });\n } else {\n const nextField =\n direction === \"fwd\"\n ? (activeField?.nextElementSibling as HTMLElement)\n : (activeField?.previousElementSibling as HTMLElement);\n\n nextField?.querySelector(\"input\")?.focus();\n }\n};\n\nconst getFocusedField = () => {\n const activeElement = document.activeElement as HTMLElement;\n if (activeElement?.classList.contains(\"vuuFilterClause-clearButton\")) {\n return activeElement as HTMLElement;\n } else {\n return getFilterClauseFieldElement(activeElement);\n }\n};\n\nexport const focusNextElement = () => {\n const filterClauseField = getFocusedField();\n const filterClause = getFilterClauseElement(filterClauseField);\n if (filterClause && filterClauseField) {\n if (filterClauseField.classList.contains(\"vuuFilterClauseValue\")) {\n const clearButton = filterClause.querySelector(\n \".vuuFilterClause-clearButton\"\n ) as HTMLButtonElement;\n clearButton?.focus();\n } else {\n focusNextFocusableElement();\n }\n }\n};\n\nconst cursorAtTextStart = (input: HTMLInputElement) =>\n input.selectionStart === 0;\n\nconst cursorAtTextEnd = (input: HTMLInputElement) =>\n input.selectionStart === input.value.length;\n\nconst getFieldName = (field: HTMLElement) =>\n field?.classList.contains(\"vuuFilterClauseColumn\")\n ? \"column\"\n : field?.classList.contains(\"vuuFilterClauseOperator\")\n ? \"operator\"\n : \"value\";\n\nexport const clauseIsNotFirst = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n if (clause) {\n const index = getElementDataIndex(clause);\n return index > 0;\n }\n};\n\nconst clauseIsNotLast = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n const nextClause = clause?.nextElementSibling as HTMLElement;\n return nextClause?.classList.contains(\"vuuFilterClauseCombinator\");\n};\n\nexport const tabToPreviousFilterCombinator = (currentElement: HTMLElement) => {\n const filterClause = getFilterClauseElement(currentElement);\n const nextItem = filterClause.previousSibling as HTMLElement;\n console.log(`tab to previous combinator`);\n nextItem?.focus();\n};\n\nexport const navigateToNextFilterClause = (\n currentElement: HTMLElement,\n direction: \"bwd\" | \"fwd\" = \"fwd\"\n) => {\n if (direction === \"bwd\") {\n if (elementIsFilterCombinator(currentElement)) {\n const nextClause = currentElement.previousElementSibling;\n if (elementIsFilterClause(nextClause)) {\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n console.log(`focus field Value ${nextField?.classList}`);\n focusField(nextField);\n }\n } else {\n const filterClause = getFilterClauseElement(currentElement);\n const nextClause = filterClause.previousSibling as HTMLElement;\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n focusField(nextField);\n }\n } else {\n const nextClause = currentElement.nextSibling as HTMLElement;\n focusField(nextClause);\n }\n};\n\n// The logic around preventDefault/stopPropagation is important\n// in this function\nexport const navigateToNextItemIfAtBoundary = (\n evt: KeyboardEvent<HTMLInputElement>\n) => {\n const input = evt.target as HTMLInputElement;\n const field = getFilterClauseFieldElement(input);\n if (evt.key === \"ArrowLeft\") {\n if (cursorAtTextStart(input)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"column\") {\n if (clauseIsNotFirst(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.previousElementSibling as HTMLElement;\n combinator?.focus();\n }\n } else {\n evt.preventDefault();\n focusField(field.previousSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at start. We want the arrowLeft to move the cursor\n evt.stopPropagation();\n } else if (evt.key === \"ArrowRight\") {\n if (cursorAtTextEnd(input as HTMLInputElement)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"value\") {\n if (clauseIsNotLast(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.nextElementSibling as HTMLElement;\n combinator?.focus();\n }\n // Do not preventDefault, stopPropagation\n return;\n } else {\n evt.preventDefault();\n focusField(field.nextSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at end. We want the arrowRight to move the cursor\n evt.stopPropagation();\n }\n};\n\nexport const focusFirstClauseIfAllClausesValid = (\n filterEditor: HTMLElement\n) => {\n const columInput = Array.from(\n filterEditor.querySelectorAll(\".vuuFilterClauseColumn input\")\n ) as HTMLInputElement[];\n if (columInput.every((input) => input.value.length > 0)) {\n setTimeout(() => {\n const input = columInput.at(0);\n input?.select();\n input?.focus();\n }, 100);\n }\n};\n"],"names":["queryClosest","getElementDataIndex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filterClauseFocusManagement.js","sources":["../../src/filter-clause/filterClauseFocusManagement.ts"],"sourcesContent":["import { getElementDataIndex, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEvent } from \"react\";\n\nconst getFilterClauseElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClause\") as HTMLElement;\n\nconst getFilterClauseFieldElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClauseField\") as HTMLElement;\n\ntype FilterClauseFieldName = \"column\" | \"operator\" | \"value\";\nconst mapFilterFieldToClassName: Record<FilterClauseFieldName, string> = {\n column: \"vuuFilterClauseColumn\",\n operator: \"vuuFilterClauseOperator\",\n value: \"vuuFilterClauseValue\",\n};\n\nconst getFilterClauseDetails = ({ classList }: HTMLElement) => {\n if (classList.contains(\"vuuFilterClauseColumn\")) {\n return \"column\";\n } else if (classList.contains(\"vuuFilterClauseOperator\")) {\n return \"operator\";\n } else if (classList.contains(\"vuuFilterClauseValue\")) {\n return \"value\";\n } else {\n throw Error(\n \"getFilterClauseField, filterClauseElemnent is missing required class name\"\n );\n }\n};\n\nexport const getFocusedFieldDetails = (): [number, string] | [] => {\n const el = document.activeElement as HTMLElement;\n const field = queryClosest(el, \".vuuFilterClauseField\");\n const filterClause = queryClosest(field, \".vuuFilterClause\");\n if (filterClause && field) {\n return [getElementDataIndex(filterClause), getFilterClauseDetails(field)];\n } else {\n return [];\n }\n};\n\n// Focus the input control within field. If clause passed, will\n// focus first field within clause\nconst focusField = (fieldOrClause: HTMLElement | null) => {\n const input = fieldOrClause?.querySelector(\"input\");\n if (input) {\n input.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n }\n};\n\nexport const elementIsFilterCombinator = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClauseCombinator\");\n\nexport const elementIsFilterClause = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClause\");\n\nexport const focusFilterClauseField = (\n filterEditor: HTMLElement,\n filterClauseIndex: number,\n fieldName: FilterClauseFieldName = \"value\"\n) => {\n if (filterEditor) {\n const fieldClassName = mapFilterFieldToClassName[fieldName];\n const field = filterEditor.querySelector(\n `.vuuFilterClause[data-index=\"${filterClauseIndex}\"] .${fieldClassName}`\n ) as HTMLElement;\n focusField(field);\n }\n};\n\nexport const focusLastClauseValue = (filterEditor: HTMLElement) => {\n console.log(\"focusLastClauseValue\");\n const field = Array.from(\n filterEditor?.querySelectorAll(\".vuuFilterClauseField\")\n ).at(-1) as HTMLElement;\n focusField(field);\n};\n\nexport const focusNextFocusableElement = (direction: \"fwd\" | \"bwd\" = \"fwd\") => {\n const activeField = getFocusedField() as HTMLElement;\n const filterClause = getFilterClauseElement(activeField);\n if (direction === \"fwd\" && filterClause?.lastChild === activeField) {\n requestAnimationFrame(() => {\n focusNextFocusableElement();\n });\n } else {\n const nextField =\n direction === \"fwd\"\n ? (activeField?.nextElementSibling as HTMLElement)\n : (activeField?.previousElementSibling as HTMLElement);\n\n nextField?.querySelector(\"input\")?.focus();\n }\n};\n\nconst getFocusedField = () => {\n const activeElement = document.activeElement as HTMLElement;\n if (activeElement?.classList.contains(\"vuuFilterClause-clearButton\")) {\n return activeElement as HTMLElement;\n } else {\n return getFilterClauseFieldElement(activeElement);\n }\n};\n\nexport const focusNextElement = () => {\n const filterClauseField = getFocusedField();\n const filterClause = getFilterClauseElement(filterClauseField);\n if (filterClause && filterClauseField) {\n if (filterClauseField.classList.contains(\"vuuFilterClauseValue\")) {\n const clearButton = filterClause.querySelector(\n \".vuuFilterClause-clearButton\"\n ) as HTMLButtonElement;\n clearButton?.focus();\n } else {\n focusNextFocusableElement();\n }\n }\n};\n\nconst cursorAtTextStart = (input: HTMLInputElement) =>\n input.selectionStart === 0;\n\nconst cursorAtTextEnd = (input: HTMLInputElement) =>\n input.selectionStart === input.value.length;\n\nconst getFieldName = (field: HTMLElement) =>\n field?.classList.contains(\"vuuFilterClauseColumn\")\n ? \"column\"\n : field?.classList.contains(\"vuuFilterClauseOperator\")\n ? \"operator\"\n : \"value\";\n\nexport const clauseIsNotFirst = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n if (clause) {\n const index = getElementDataIndex(clause);\n return index > 0;\n }\n};\n\nconst clauseIsNotLast = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n const nextClause = clause?.nextElementSibling as HTMLElement;\n return nextClause?.classList.contains(\"vuuFilterClauseCombinator\");\n};\n\nexport const tabToPreviousFilterCombinator = (currentElement: HTMLElement) => {\n const filterClause = getFilterClauseElement(currentElement);\n const nextItem = filterClause.previousSibling as HTMLElement;\n console.log(`tab to previous combinator`);\n nextItem?.focus();\n};\n\nexport const navigateToNextFilterClause = (\n currentElement: HTMLElement,\n direction: \"bwd\" | \"fwd\" = \"fwd\"\n) => {\n if (direction === \"bwd\") {\n if (elementIsFilterCombinator(currentElement)) {\n const nextClause = currentElement.previousElementSibling;\n if (elementIsFilterClause(nextClause)) {\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n console.log(`focus field Value ${nextField?.classList}`);\n focusField(nextField);\n }\n } else {\n const filterClause = getFilterClauseElement(currentElement);\n const nextClause = filterClause.previousSibling as HTMLElement;\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n focusField(nextField);\n }\n } else {\n const nextClause = currentElement.nextSibling as HTMLElement;\n focusField(nextClause);\n }\n};\n\n// The logic around preventDefault/stopPropagation is important\n// in this function\nexport const navigateToNextItemIfAtBoundary = (\n evt: KeyboardEvent<HTMLInputElement>\n) => {\n const input = evt.target as HTMLInputElement;\n const field = getFilterClauseFieldElement(input);\n if (evt.key === \"ArrowLeft\") {\n if (cursorAtTextStart(input)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"column\") {\n if (clauseIsNotFirst(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.previousElementSibling as HTMLElement;\n combinator?.focus();\n }\n } else {\n evt.preventDefault();\n focusField(field.previousSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at start. We want the arrowLeft to move the cursor\n evt.stopPropagation();\n } else if (evt.key === \"ArrowRight\") {\n if (cursorAtTextEnd(input as HTMLInputElement)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"value\") {\n if (clauseIsNotLast(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.nextElementSibling as HTMLElement;\n combinator?.focus();\n }\n // Do not preventDefault, stopPropagation\n return;\n } else {\n evt.preventDefault();\n focusField(field.nextSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at end. We want the arrowRight to move the cursor\n evt.stopPropagation();\n }\n};\n\nexport const focusFirstClauseIfAllClausesValid = (\n filterEditor: HTMLElement\n) => {\n const columInput = Array.from(\n filterEditor.querySelectorAll(\".vuuFilterClauseColumn input\")\n ) as HTMLInputElement[];\n if (columInput.every((input) => input.value.length > 0)) {\n setTimeout(() => {\n const input = columInput.at(0);\n input?.select();\n input?.focus();\n }, 100);\n }\n};\n"],"names":["queryClosest","getElementDataIndex"],"mappings":"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"}
|
|
@@ -20,6 +20,16 @@ const useFilterClause = ({
|
|
|
20
20
|
}, [filterClauseModel]);
|
|
21
21
|
const columnRef = react.useRef(null);
|
|
22
22
|
const operatorRef = react.useRef(null);
|
|
23
|
+
const valueRef = react.useRef(null);
|
|
24
|
+
const setValueRef = react.useCallback(
|
|
25
|
+
(el) => {
|
|
26
|
+
valueRef.current = el;
|
|
27
|
+
if (!filterClauseModel.isValid) {
|
|
28
|
+
el?.querySelector("input")?.focus();
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
[filterClauseModel.isValid]
|
|
32
|
+
);
|
|
23
33
|
const removeAndNavigateToNextInputIfAtBoundary = react.useCallback(
|
|
24
34
|
(evt) => {
|
|
25
35
|
const input = evt.target;
|
|
@@ -109,11 +119,6 @@ const useFilterClause = ({
|
|
|
109
119
|
removeAndNavigateToNextInputIfAtBoundary
|
|
110
120
|
]
|
|
111
121
|
);
|
|
112
|
-
const handleFocus = react.useCallback((evt) => {
|
|
113
|
-
if (filterClauseFocusManagement.elementIsFilterClause(evt.target)) {
|
|
114
|
-
filterClauseFocusManagement.focusField(evt.target);
|
|
115
|
-
}
|
|
116
|
-
}, []);
|
|
117
122
|
const inputProps = react.useMemo(
|
|
118
123
|
() => ({
|
|
119
124
|
onKeyDownCapture: handleKeyDownCaptureNavigation,
|
|
@@ -122,10 +127,10 @@ const useFilterClause = ({
|
|
|
122
127
|
[handleKeyDownCaptureNavigation]
|
|
123
128
|
);
|
|
124
129
|
react.useEffect(() => {
|
|
125
|
-
if (filterClauseModel.
|
|
130
|
+
if (!filterClauseModel.isValid) {
|
|
131
|
+
const inputRef = filterClauseModel.column === void 0 ? columnRef : filterClauseModel.op === void 0 ? operatorRef : null;
|
|
126
132
|
requestAnimationFrame(() => {
|
|
127
|
-
|
|
128
|
-
columnInput?.focus();
|
|
133
|
+
inputRef?.current?.querySelector("input")?.focus();
|
|
129
134
|
});
|
|
130
135
|
}
|
|
131
136
|
}, [filterClauseModel]);
|
|
@@ -136,10 +141,10 @@ const useFilterClause = ({
|
|
|
136
141
|
onChangeValue: handleChangeValue,
|
|
137
142
|
onDeselectValue: handleDeselectValue,
|
|
138
143
|
onSelectColumn,
|
|
139
|
-
onFocus: handleFocus,
|
|
140
144
|
onSelectOperator,
|
|
141
145
|
operatorRef,
|
|
142
|
-
selectedColumn: columnsByName[
|
|
146
|
+
selectedColumn: columnsByName[filterClauseModel.column ?? ""],
|
|
147
|
+
valueRef: setValueRef
|
|
143
148
|
};
|
|
144
149
|
};
|
|
145
150
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFilterClause.js","sources":["../../src/filter-clause/useFilterClause.ts"],"sourcesContent":["import { FilterClause, FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport { hasOpenOptionList } from \"@vuu-ui/vuu-utils\";\nimport {\n FocusEventHandler,\n KeyboardEvent,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { FilterClauseProps } from \"./FilterClause\";\nimport {\n clauseIsNotFirst,\n elementIsFilterClause,\n focusField,\n focusNextElement,\n focusNextFocusableElement,\n navigateToNextItemIfAtBoundary,\n tabToPreviousFilterCombinator,\n} from \"./filterClauseFocusManagement\";\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n>;\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}: 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\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 console.log(`focus next element`);\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_, 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 handleFocus = useCallback<FocusEventHandler>((evt) => {\n if (elementIsFilterClause(evt.target)) {\n focusField(evt.target);\n }\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 if (filterClauseModel.column === undefined) {\n requestAnimationFrame(() => {\n const columnInput = columnRef?.current?.querySelector(\"input\");\n columnInput?.focus();\n });\n }\n }, [filterClauseModel]);\n\n return {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue: handleChangeValue,\n onDeselectValue: handleDeselectValue,\n onSelectColumn,\n onFocus: handleFocus,\n onSelectOperator,\n operatorRef,\n selectedColumn: columnsByName[filterClause.column ?? \"\"],\n };\n};\n"],"names":["useState","useMemo","filterClause","useRef","useCallback","focusNextFocusableElement","clauseIsNotFirst","focusNextElement","navigateToNextItemIfAtBoundary","hasOpenOptionList","tabToPreviousFilterCombinator","elementIsFilterClause","focusField","useEffect"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useFilterClause.js","sources":["../../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\";\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n>;\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}: 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 console.log(`focus next element`);\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_, 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 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 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":"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"}
|
|
@@ -5,72 +5,77 @@ var cx = require('clsx');
|
|
|
5
5
|
var FilterClauseValueEditorNumber = require('./FilterClauseValueEditorNumber.js');
|
|
6
6
|
var FilterClauseValueEditorText = require('./FilterClauseValueEditorText.js');
|
|
7
7
|
var vuuUtils = require('@vuu-ui/vuu-utils');
|
|
8
|
+
var react = require('react');
|
|
8
9
|
var FilterClauseValueEditorDate = require('./FilterClauseValueEditorDate.js');
|
|
9
10
|
|
|
10
11
|
const classBase = "vuuFilterClause";
|
|
11
|
-
const FilterClauseValueEditor = (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
FilterClauseValueEditorDate.FilterClauseValueEditorDate,
|
|
28
|
-
{
|
|
29
|
-
inputProps,
|
|
30
|
-
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
31
|
-
"data-field": "value",
|
|
32
|
-
value,
|
|
33
|
-
operator,
|
|
34
|
-
onChangeValue
|
|
35
|
-
}
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
switch (selectedColumn.serverDataType) {
|
|
39
|
-
case "string":
|
|
40
|
-
case "char":
|
|
41
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42
|
-
FilterClauseValueEditorText.FilterClauseValueEditorText,
|
|
43
|
-
{
|
|
44
|
-
inputProps,
|
|
45
|
-
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
46
|
-
column: selectedColumn,
|
|
47
|
-
onDeselect: onDeselectValue,
|
|
48
|
-
onChangeValue,
|
|
49
|
-
operator,
|
|
50
|
-
suggestionProvider,
|
|
51
|
-
table,
|
|
52
|
-
value: value === void 0 ? "" : Array.isArray(value) ? value.map((val) => val.toString()) : value.toString()
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
case "int":
|
|
56
|
-
case "long":
|
|
57
|
-
case "double":
|
|
12
|
+
const FilterClauseValueEditor = react.forwardRef(
|
|
13
|
+
function FilterClauseValueEditor2({
|
|
14
|
+
selectedColumn,
|
|
15
|
+
operator,
|
|
16
|
+
inputProps,
|
|
17
|
+
onChangeValue,
|
|
18
|
+
onDeselectValue,
|
|
19
|
+
suggestionProvider,
|
|
20
|
+
table,
|
|
21
|
+
value
|
|
22
|
+
}, forwardedRef) {
|
|
23
|
+
if (selectedColumn === void 0 || operator === void 0) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (vuuUtils.isDateTimeColumn(selectedColumn)) {
|
|
27
|
+
console.log(`return DateInput`);
|
|
58
28
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
59
|
-
|
|
29
|
+
FilterClauseValueEditorDate.FilterClauseValueEditorDate,
|
|
60
30
|
{
|
|
61
31
|
inputProps,
|
|
62
32
|
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
63
|
-
column: selectedColumn,
|
|
64
33
|
"data-field": "value",
|
|
65
|
-
|
|
66
|
-
operator
|
|
34
|
+
value,
|
|
35
|
+
operator,
|
|
36
|
+
onChangeValue
|
|
67
37
|
}
|
|
68
38
|
);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
39
|
+
}
|
|
40
|
+
switch (selectedColumn.serverDataType) {
|
|
41
|
+
case "string":
|
|
42
|
+
case "char":
|
|
43
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44
|
+
FilterClauseValueEditorText.FilterClauseValueEditorText,
|
|
45
|
+
{
|
|
46
|
+
inputProps,
|
|
47
|
+
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
48
|
+
column: selectedColumn,
|
|
49
|
+
onDeselect: onDeselectValue,
|
|
50
|
+
onChangeValue,
|
|
51
|
+
operator,
|
|
52
|
+
ref: forwardedRef,
|
|
53
|
+
suggestionProvider,
|
|
54
|
+
table,
|
|
55
|
+
value: value === void 0 ? "" : Array.isArray(value) ? value.map((val) => val.toString()) : value.toString()
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
case "int":
|
|
59
|
+
case "long":
|
|
60
|
+
case "double":
|
|
61
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
62
|
+
FilterClauseValueEditorNumber.FilterClauseValueEditorNumber,
|
|
63
|
+
{
|
|
64
|
+
inputProps,
|
|
65
|
+
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
66
|
+
column: selectedColumn,
|
|
67
|
+
"data-field": "value",
|
|
68
|
+
onChangeValue,
|
|
69
|
+
operator,
|
|
70
|
+
ref: forwardedRef
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
default:
|
|
74
|
+
console.log("returning null");
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
72
77
|
}
|
|
73
|
-
|
|
78
|
+
);
|
|
74
79
|
|
|
75
80
|
exports.FilterClauseValueEditor = FilterClauseValueEditor;
|
|
76
81
|
//# sourceMappingURL=FilterClauseValueEditor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterClauseValueEditor.js","sources":["../../../src/filter-clause/value-editors/FilterClauseValueEditor.tsx"],"sourcesContent":["import { TableSchemaTable } from \"@vuu-ui/vuu-data-types\";\nimport cx from \"clsx\";\nimport {
|
|
1
|
+
{"version":3,"file":"FilterClauseValueEditor.js","sources":["../../../src/filter-clause/value-editors/FilterClauseValueEditor.tsx"],"sourcesContent":["import { TableSchemaTable } from \"@vuu-ui/vuu-data-types\";\nimport cx from \"clsx\";\nimport { useFilterClause } from \"../useFilterClause\";\nimport { FilterClauseValueEditorNumber } from \"./FilterClauseValueEditorNumber\";\nimport { FilterClauseValueEditorText } from \"./FilterClauseValueEditorText\";\n\nimport {\n NumericFilterClauseOp,\n SingleValueFilterClauseOp,\n} from \"@vuu-ui/vuu-filter-types\";\nimport { isDateTimeColumn } from \"@vuu-ui/vuu-utils\";\nimport { ForwardedRef, forwardRef } from \"react\";\nimport { FilterClauseProps } from \"../FilterClause\";\nimport { FilterClauseValueEditorDate } from \"./FilterClauseValueEditorDate\";\n\nconst classBase = \"vuuFilterClause\";\n\ntype FilterClauseValueEditorProps = Pick<\n ReturnType<typeof useFilterClause>,\n \"selectedColumn\" | \"inputProps\" | \"onChangeValue\" | \"onDeselectValue\"\n> &\n Pick<FilterClauseProps, \"suggestionProvider\"> & {\n table?: TableSchemaTable;\n } & {\n operator?: SingleValueFilterClauseOp | \"in\";\n value?: string | string[] | number | number[] | boolean | boolean[];\n };\n\nexport const FilterClauseValueEditor = forwardRef(\n function FilterClauseValueEditor(\n {\n selectedColumn,\n operator,\n inputProps,\n onChangeValue,\n onDeselectValue,\n suggestionProvider,\n table,\n value,\n }: FilterClauseValueEditorProps,\n forwardedRef: ForwardedRef<HTMLDivElement>\n ) {\n if (selectedColumn === undefined || operator === undefined) {\n return null;\n }\n\n if (isDateTimeColumn(selectedColumn)) {\n console.log(`return DateInput`);\n return (\n <FilterClauseValueEditorDate\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Value`)}\n data-field=\"value\"\n // ref={forwardedRef}\n value={value as number}\n operator={operator as NumericFilterClauseOp}\n onChangeValue={onChangeValue}\n />\n );\n }\n\n switch (selectedColumn.serverDataType) {\n case \"string\":\n case \"char\":\n return (\n <FilterClauseValueEditorText\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Value`)}\n column={selectedColumn}\n onDeselect={onDeselectValue}\n onChangeValue={onChangeValue}\n operator={operator}\n ref={forwardedRef}\n suggestionProvider={suggestionProvider}\n table={table}\n value={\n value === undefined\n ? \"\"\n : Array.isArray(value)\n ? value.map((val) => val.toString())\n : (value.toString() as string | string[])\n }\n />\n );\n case \"int\":\n case \"long\":\n case \"double\":\n return (\n <FilterClauseValueEditorNumber\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Value`)}\n column={selectedColumn}\n data-field=\"value\"\n onChangeValue={onChangeValue}\n operator={operator}\n ref={forwardedRef}\n />\n );\n default:\n console.log(\"returning null\");\n return null;\n }\n }\n);\n"],"names":["forwardRef","FilterClauseValueEditor","isDateTimeColumn","jsx","FilterClauseValueEditorDate","FilterClauseValueEditorText","FilterClauseValueEditorNumber"],"mappings":";;;;;;;;;;AAeA,MAAM,SAAY,GAAA,iBAAA,CAAA;AAaX,MAAM,uBAA0B,GAAAA,gBAAA;AAAA,EACrC,SAASC,wBACP,CAAA;AAAA,IACE,cAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,KAEF,YACA,EAAA;AACA,IAAI,IAAA,cAAA,KAAmB,KAAa,CAAA,IAAA,QAAA,KAAa,KAAW,CAAA,EAAA;AAC1D,MAAO,OAAA,IAAA,CAAA;AAAA,KACT;AAEA,IAAI,IAAAC,yBAAA,CAAiB,cAAc,CAAG,EAAA;AACpC,MAAA,OAAA,CAAQ,IAAI,CAAkB,gBAAA,CAAA,CAAA,CAAA;AAC9B,MACE,uBAAAC,cAAA;AAAA,QAACC,uDAAA;AAAA,QAAA;AAAA,UACC,UAAA;AAAA,UACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAO,KAAA,CAAA,CAAA;AAAA,UACtD,YAAW,EAAA,OAAA;AAAA,UAEX,KAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA;AAAA,SAAA;AAAA,OACF,CAAA;AAAA,KAEJ;AAEA,IAAA,QAAQ,eAAe,cAAgB;AAAA,MACrC,KAAK,QAAA,CAAA;AAAA,MACL,KAAK,MAAA;AACH,QACE,uBAAAD,cAAA;AAAA,UAACE,uDAAA;AAAA,UAAA;AAAA,YACC,UAAA;AAAA,YACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAO,KAAA,CAAA,CAAA;AAAA,YACtD,MAAQ,EAAA,cAAA;AAAA,YACR,UAAY,EAAA,eAAA;AAAA,YACZ,aAAA;AAAA,YACA,QAAA;AAAA,YACA,GAAK,EAAA,YAAA;AAAA,YACL,kBAAA;AAAA,YACA,KAAA;AAAA,YACA,OACE,KAAU,KAAA,KAAA,CAAA,GACN,EACA,GAAA,KAAA,CAAM,QAAQ,KAAK,CAAA,GACnB,KAAM,CAAA,GAAA,CAAI,CAAC,GAAQ,KAAA,GAAA,CAAI,UAAU,CAAA,GAChC,MAAM,QAAS,EAAA;AAAA,WAAA;AAAA,SAExB,CAAA;AAAA,MAEJ,KAAK,KAAA,CAAA;AAAA,MACL,KAAK,MAAA,CAAA;AAAA,MACL,KAAK,QAAA;AACH,QACE,uBAAAF,cAAA;AAAA,UAACG,2DAAA;AAAA,UAAA;AAAA,YACC,UAAA;AAAA,YACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAO,KAAA,CAAA,CAAA;AAAA,YACtD,MAAQ,EAAA,cAAA;AAAA,YACR,YAAW,EAAA,OAAA;AAAA,YACX,aAAA;AAAA,YACA,QAAA;AAAA,YACA,GAAK,EAAA,YAAA;AAAA,WAAA;AAAA,SACP,CAAA;AAAA,MAEJ;AACE,QAAA,OAAA,CAAQ,IAAI,gBAAgB,CAAA,CAAA;AAC5B,QAAO,OAAA,IAAA,CAAA;AAAA,KACX;AAAA,GACF;AACF;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var filterClauseCss = ".vuuFilterClause {\n --vuuExpandoInput-top: 0;\n --content-height: calc(var(--salt-size-base) - var(--salt-spacing-150));\n --vuuExpandoInput-height: var(--content-height);\n --vuuExpandoCombobox-height: var(--content-height);\n --saltButton-height: 16px;\n --saltButton-width: 16px;\n --salt-focused-outlineStyle: dotted;\n\n align-items: center;\n background: var(--salt-container-primary-background);\n border-color: var(--vuu-color-gray-45);\n border-radius: var(--saltButton-borderRadius);\n border-width: 1px;\n border-style: solid;\n display: flex;\n flex-direction: row;\n gap: var(--salt-spacing-50);\n height: var(--salt-size-base);\n min-width: calc(var(--salt-size-base) * 4);\n padding: 0 var(--salt-spacing-100);\n width: fit-content;\n\n\n .
|
|
1
|
+
var filterClauseCss = ".vuuFilterClause {\n --vuuExpandoInput-top: 0;\n --content-height: calc(var(--salt-size-base) - var(--salt-spacing-150));\n --vuuExpandoInput-height: var(--content-height);\n --vuuExpandoCombobox-height: var(--content-height);\n --saltButton-height: 16px;\n --saltButton-width: 16px;\n --salt-focused-outlineStyle: dotted;\n\n align-items: center;\n background: var(--salt-container-primary-background);\n border-color: var(--vuu-color-gray-45);\n border-radius: var(--saltButton-borderRadius);\n border-width: 1px;\n border-style: solid;\n display: flex;\n flex-direction: row;\n gap: var(--salt-spacing-50);\n height: var(--salt-size-base);\n min-width: calc(var(--salt-size-base) * 4);\n padding: 0 var(--salt-spacing-100);\n width: fit-content;\n\n .vuuFilterClauseField {\n flex: 0 0 auto;\n }\n .vuuFilterClauseField:last-child {\n flex: 1 0 auto;\n }\n\n .vuuExpandoCombobox {\n flex-basis: auto;\n flex-shrink: 0;\n flex-grow: 0;\n }\n\n &:focus-within {\n border-color: var(--vuu-color-purple-10);\n }\n\n .saltComboBox-focused {\n outline: none;\n }\n\n .saltTokenizedInput {\n height: 16px;\n min-height: 16px;\n }\n\n .saltTokenizedInput .saltInputPill {\n --pill-fontSize: 12px;\n --saltButton-borderStyle: none;\n --pill-background: none;\n height: 16px;\n margin: 0;\n }\n\n .saltTokenizedInput-pillGroup {\n padding: 0;\n height: 16px;\n }\n}\n\n.salt-density-high .vuuFilterClause {\n padding: 4px 8px;\n gap: 4px;\n --salt-text-lineHeight: 12px;\n --saltInputLegacy-fontSize: 12px;\n --saltInputLegacy-minWidth: 12px;\n}\n\n.salt-density-high .vuuFilterClause .saltInput {\n padding: 0;\n min-height: 16px;\n height: 16px;\n}\n\n.vuuFilterClauseOperator-hidden {\n display: none;\n}\n\n.vuuFilterClause .saltInput-focused,\n.vuuFilterClause .saltTokenizedInput-focused {\n outline: none;\n color: var(--salt-content-primary-foreground);\n}\n\n.vuuFilterClause-DatePicker {\n border: none;\n}\n";
|
|
2
2
|
|
|
3
3
|
export { filterClauseCss as default };
|
|
4
4
|
//# sourceMappingURL=FilterClause.css.js.map
|
|
@@ -30,10 +30,10 @@ const FilterClause = ({
|
|
|
30
30
|
// onChangeColumn,
|
|
31
31
|
onSelectColumn,
|
|
32
32
|
onSelectOperator,
|
|
33
|
-
onFocus,
|
|
34
33
|
onDeselectValue,
|
|
35
34
|
operatorRef,
|
|
36
|
-
selectedColumn
|
|
35
|
+
selectedColumn,
|
|
36
|
+
valueRef
|
|
37
37
|
} = useFilterClause({
|
|
38
38
|
filterClauseModel,
|
|
39
39
|
onCancel,
|
|
@@ -47,57 +47,49 @@ const FilterClause = ({
|
|
|
47
47
|
window: targetWindow
|
|
48
48
|
});
|
|
49
49
|
const columns = useMemo(() => Object.values(columnsByName), [columnsByName]);
|
|
50
|
-
return /* @__PURE__ */ jsxs(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
table: tableSchema.table,
|
|
94
|
-
value: filterClause?.values ?? filterClause?.value
|
|
95
|
-
},
|
|
96
|
-
"value-field"
|
|
97
|
-
)
|
|
98
|
-
]
|
|
99
|
-
}
|
|
100
|
-
);
|
|
50
|
+
return /* @__PURE__ */ jsxs("div", { className: cx(classBase, className), ...htmlAttributes, tabIndex: 0, children: [
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
ColumnPicker,
|
|
53
|
+
{
|
|
54
|
+
inputProps,
|
|
55
|
+
className: cx(`${classBase}Field`, `${classBase}Column`),
|
|
56
|
+
columns,
|
|
57
|
+
onSelect: onSelectColumn,
|
|
58
|
+
ref: columnRef,
|
|
59
|
+
value: filterClauseModel.column ?? ""
|
|
60
|
+
},
|
|
61
|
+
"column-field"
|
|
62
|
+
),
|
|
63
|
+
selectedColumn?.name ? /* @__PURE__ */ jsx(
|
|
64
|
+
OperatorPicker,
|
|
65
|
+
{
|
|
66
|
+
column: selectedColumn,
|
|
67
|
+
inputProps,
|
|
68
|
+
className: cx(`${classBase}Field`, `${classBase}Operator`, {
|
|
69
|
+
[`${classBase}Operator-hidden`]: selectedColumn === null
|
|
70
|
+
}),
|
|
71
|
+
onSelect: onSelectOperator,
|
|
72
|
+
ref: operatorRef,
|
|
73
|
+
value: filterClauseModel.op ?? ""
|
|
74
|
+
},
|
|
75
|
+
"operator-field"
|
|
76
|
+
) : null,
|
|
77
|
+
filterClauseModel.op ? /* @__PURE__ */ jsx(
|
|
78
|
+
FilterClauseValueEditor,
|
|
79
|
+
{
|
|
80
|
+
inputProps,
|
|
81
|
+
onChangeValue,
|
|
82
|
+
onDeselectValue,
|
|
83
|
+
operator: filterClauseModel.op,
|
|
84
|
+
ref: valueRef,
|
|
85
|
+
selectedColumn,
|
|
86
|
+
suggestionProvider,
|
|
87
|
+
table: tableSchema.table,
|
|
88
|
+
value: filterClause?.values ?? filterClause?.value
|
|
89
|
+
},
|
|
90
|
+
"value-field"
|
|
91
|
+
) : null
|
|
92
|
+
] });
|
|
101
93
|
};
|
|
102
94
|
|
|
103
95
|
export { FilterClause };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterClause.js","sources":["../../src/filter-clause/FilterClause.tsx"],"sourcesContent":["import type { SuggestionProvider, TableSchema } from \"@vuu-ui/vuu-data-types\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport { CloseReason } from \"@vuu-ui/vuu-ui-controls\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\nimport { ColumnPicker } from \"./ColumnPicker\";\n\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 onDropdownClose?: (closeReason: CloseReason) => void;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n suggestionProvider?: SuggestionProvider;\n tableSchema: TableSchema;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownClose,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n suggestionProvider,\n tableSchema,\n ...htmlAttributes\n}: FilterClauseProps) => {\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n // onChangeColumn,\n onSelectColumn,\n onSelectOperator,\n
|
|
1
|
+
{"version":3,"file":"FilterClause.js","sources":["../../src/filter-clause/FilterClause.tsx"],"sourcesContent":["import type { SuggestionProvider, TableSchema } from \"@vuu-ui/vuu-data-types\";\nimport {\n ColumnDescriptorsByName,\n MultiValueFilterClause,\n SingleValueFilterClause,\n} from \"@vuu-ui/vuu-filter-types\";\nimport { CloseReason } from \"@vuu-ui/vuu-ui-controls\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport cx from \"clsx\";\nimport { HTMLAttributes, useMemo } from \"react\";\nimport { FilterClauseModel } from \"../FilterModel\";\nimport { useFilterClause } from \"./useFilterClause\";\nimport { FilterClauseValueEditor } from \"./value-editors/FilterClauseValueEditor\";\nimport { ColumnPicker } from \"./ColumnPicker\";\n\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 onDropdownClose?: (closeReason: CloseReason) => void;\n onDropdownOpen?: () => void;\n onFocusSave?: () => void;\n suggestionProvider?: SuggestionProvider;\n tableSchema: TableSchema;\n}\n\nconst classBase = \"vuuFilterClause\";\n\nexport const FilterClause = ({\n className,\n columnsByName,\n onCancel,\n onDropdownClose,\n onDropdownOpen,\n onFocusSave,\n filterClauseModel,\n suggestionProvider,\n tableSchema,\n ...htmlAttributes\n}: FilterClauseProps) => {\n const {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue,\n // onChangeColumn,\n onSelectColumn,\n onSelectOperator,\n onDeselectValue,\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 onDeselectValue={onDeselectValue}\n operator={filterClauseModel.op}\n ref={valueRef}\n selectedColumn={selectedColumn}\n suggestionProvider={suggestionProvider}\n table={tableSchema.table}\n value={\n (filterClause as MultiValueFilterClause)?.values ??\n (filterClause as SingleValueFilterClause)?.value\n }\n />\n ) : null}\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAqCA,MAAM,SAAY,GAAA,iBAAA,CAAA;AAEX,MAAM,eAAe,CAAC;AAAA,EAC3B,SAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,WAAA;AAAA,EACA,iBAAA;AAAA,EACA,kBAAA;AAAA,EACA,WAAA;AAAA,EACA,GAAG,cAAA;AACL,CAAyB,KAAA;AACvB,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA;AAAA,IAEA,cAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA,QAAA;AAAA,MACE,eAAgB,CAAA;AAAA,IAClB,iBAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,MAAM,eAAe,SAAU,EAAA,CAAA;AAC/B,EAAyB,wBAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,mBAAA;AAAA,IACR,GAAK,EAAA,eAAA;AAAA,IACL,MAAQ,EAAA,YAAA;AAAA,GACT,CAAA,CAAA;AAED,EAAM,MAAA,OAAA,GAAU,QAAQ,MAAM,MAAA,CAAO,OAAO,aAAa,CAAA,EAAG,CAAC,aAAa,CAAC,CAAA,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,EAAA;AAAA,OAAA;AAAA,MAH/B,cAAA;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,IAAA;AAAA,SACrD,CAAA;AAAA,QAED,QAAU,EAAA,gBAAA;AAAA,QACV,GAAK,EAAA,WAAA;AAAA,QACL,KAAA,EAAO,kBAAkB,EAAM,IAAA,EAAA;AAAA,OAAA;AAAA,MAH3B,gBAAA;AAAA,KAKJ,GAAA,IAAA;AAAA,IACH,kBAAkB,EACjB,mBAAA,GAAA;AAAA,MAAC,uBAAA;AAAA,MAAA;AAAA,QACC,UAAA;AAAA,QAEA,aAAA;AAAA,QACA,eAAA;AAAA,QACA,UAAU,iBAAkB,CAAA,EAAA;AAAA,QAC5B,GAAK,EAAA,QAAA;AAAA,QACL,cAAA;AAAA,QACA,kBAAA;AAAA,QACA,OAAO,WAAY,CAAA,KAAA;AAAA,QACnB,KAAA,EACG,YAAyC,EAAA,MAAA,IACzC,YAA0C,EAAA,KAAA;AAAA,OAAA;AAAA,MAVzC,aAAA;AAAA,KAaJ,GAAA,IAAA;AAAA,GACN,EAAA,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -185,5 +185,5 @@ const focusFirstClauseIfAllClausesValid = (filterEditor) => {
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
|
|
188
|
-
export { clauseIsNotFirst, elementIsFilterClause, elementIsFilterCombinator,
|
|
188
|
+
export { clauseIsNotFirst, elementIsFilterClause, elementIsFilterCombinator, focusFilterClauseField, focusFirstClauseIfAllClausesValid, focusLastClauseValue, focusNextElement, focusNextFocusableElement, getFocusedFieldDetails, navigateToNextFilterClause, navigateToNextItemIfAtBoundary, tabToPreviousFilterCombinator };
|
|
189
189
|
//# sourceMappingURL=filterClauseFocusManagement.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterClauseFocusManagement.js","sources":["../../src/filter-clause/filterClauseFocusManagement.ts"],"sourcesContent":["import { getElementDataIndex, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEvent } from \"react\";\n\nconst getFilterClauseElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClause\") as HTMLElement;\n\nconst getFilterClauseFieldElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClauseField\") as HTMLElement;\n\ntype FilterClauseFieldName = \"column\" | \"operator\" | \"value\";\nconst mapFilterFieldToClassName: Record<FilterClauseFieldName, string> = {\n column: \"vuuFilterClauseColumn\",\n operator: \"vuuFilterClauseOperator\",\n value: \"vuuFilterClauseValue\",\n};\n\nconst getFilterClauseDetails = ({ classList }: HTMLElement) => {\n if (classList.contains(\"vuuFilterClauseColumn\")) {\n return \"column\";\n } else if (classList.contains(\"vuuFilterClauseOperator\")) {\n return \"operator\";\n } else if (classList.contains(\"vuuFilterClauseValue\")) {\n return \"value\";\n } else {\n throw Error(\n \"getFilterClauseField, filterClauseElemnent is missing required class name\"\n );\n }\n};\n\nexport const getFocusedFieldDetails = (): [number, string] | [] => {\n const el = document.activeElement as HTMLElement;\n const field = queryClosest(el, \".vuuFilterClauseField\");\n const filterClause = queryClosest(field, \".vuuFilterClause\");\n if (filterClause && field) {\n return [getElementDataIndex(filterClause), getFilterClauseDetails(field)];\n } else {\n return [];\n }\n};\n\n// Focus the input control within field. If clause passed, will\n// focus first field within clause\nexport const focusField = (fieldOrClause: HTMLElement | null) => {\n const input = fieldOrClause?.querySelector(\"input\");\n if (input) {\n input.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n }\n};\n\nexport const elementIsFilterCombinator = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClauseCombinator\");\n\nexport const elementIsFilterClause = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClause\");\n\nexport const focusFilterClauseField = (\n filterEditor: HTMLElement,\n filterClauseIndex: number,\n fieldName: FilterClauseFieldName = \"value\"\n) => {\n if (filterEditor) {\n const fieldClassName = mapFilterFieldToClassName[fieldName];\n const field = filterEditor.querySelector(\n `.vuuFilterClause[data-index=\"${filterClauseIndex}\"] .${fieldClassName}`\n ) as HTMLElement;\n focusField(field);\n }\n};\n\nexport const focusLastClauseValue = (filterEditor: HTMLElement) => {\n console.log(\"focusLastClauseValue\");\n const field = Array.from(\n filterEditor?.querySelectorAll(\".vuuFilterClauseField\")\n ).at(-1) as HTMLElement;\n focusField(field);\n};\n\nexport const focusNextFocusableElement = (direction: \"fwd\" | \"bwd\" = \"fwd\") => {\n const activeField = getFocusedField() as HTMLElement;\n const filterClause = getFilterClauseElement(activeField);\n if (direction === \"fwd\" && filterClause?.lastChild === activeField) {\n requestAnimationFrame(() => {\n focusNextFocusableElement();\n });\n } else {\n const nextField =\n direction === \"fwd\"\n ? (activeField?.nextElementSibling as HTMLElement)\n : (activeField?.previousElementSibling as HTMLElement);\n\n nextField?.querySelector(\"input\")?.focus();\n }\n};\n\nconst getFocusedField = () => {\n const activeElement = document.activeElement as HTMLElement;\n if (activeElement?.classList.contains(\"vuuFilterClause-clearButton\")) {\n return activeElement as HTMLElement;\n } else {\n return getFilterClauseFieldElement(activeElement);\n }\n};\n\nexport const focusNextElement = () => {\n const filterClauseField = getFocusedField();\n const filterClause = getFilterClauseElement(filterClauseField);\n if (filterClause && filterClauseField) {\n if (filterClauseField.classList.contains(\"vuuFilterClauseValue\")) {\n const clearButton = filterClause.querySelector(\n \".vuuFilterClause-clearButton\"\n ) as HTMLButtonElement;\n clearButton?.focus();\n } else {\n focusNextFocusableElement();\n }\n }\n};\n\nconst cursorAtTextStart = (input: HTMLInputElement) =>\n input.selectionStart === 0;\n\nconst cursorAtTextEnd = (input: HTMLInputElement) =>\n input.selectionStart === input.value.length;\n\nconst getFieldName = (field: HTMLElement) =>\n field?.classList.contains(\"vuuFilterClauseColumn\")\n ? \"column\"\n : field?.classList.contains(\"vuuFilterClauseOperator\")\n ? \"operator\"\n : \"value\";\n\nexport const clauseIsNotFirst = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n if (clause) {\n const index = getElementDataIndex(clause);\n return index > 0;\n }\n};\n\nconst clauseIsNotLast = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n const nextClause = clause?.nextElementSibling as HTMLElement;\n return nextClause?.classList.contains(\"vuuFilterClauseCombinator\");\n};\n\nexport const tabToPreviousFilterCombinator = (currentElement: HTMLElement) => {\n const filterClause = getFilterClauseElement(currentElement);\n const nextItem = filterClause.previousSibling as HTMLElement;\n console.log(`tab to previous combinator`);\n nextItem?.focus();\n};\n\nexport const navigateToNextFilterClause = (\n currentElement: HTMLElement,\n direction: \"bwd\" | \"fwd\" = \"fwd\"\n) => {\n if (direction === \"bwd\") {\n if (elementIsFilterCombinator(currentElement)) {\n const nextClause = currentElement.previousElementSibling;\n if (elementIsFilterClause(nextClause)) {\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n console.log(`focus field Value ${nextField?.classList}`);\n focusField(nextField);\n }\n } else {\n const filterClause = getFilterClauseElement(currentElement);\n const nextClause = filterClause.previousSibling as HTMLElement;\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n focusField(nextField);\n }\n } else {\n const nextClause = currentElement.nextSibling as HTMLElement;\n focusField(nextClause);\n }\n};\n\n// The logic around preventDefault/stopPropagation is important\n// in this function\nexport const navigateToNextItemIfAtBoundary = (\n evt: KeyboardEvent<HTMLInputElement>\n) => {\n const input = evt.target as HTMLInputElement;\n const field = getFilterClauseFieldElement(input);\n if (evt.key === \"ArrowLeft\") {\n if (cursorAtTextStart(input)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"column\") {\n if (clauseIsNotFirst(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.previousElementSibling as HTMLElement;\n combinator?.focus();\n }\n } else {\n evt.preventDefault();\n focusField(field.previousSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at start. We want the arrowLeft to move the cursor\n evt.stopPropagation();\n } else if (evt.key === \"ArrowRight\") {\n if (cursorAtTextEnd(input as HTMLInputElement)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"value\") {\n if (clauseIsNotLast(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.nextElementSibling as HTMLElement;\n combinator?.focus();\n }\n // Do not preventDefault, stopPropagation\n return;\n } else {\n evt.preventDefault();\n focusField(field.nextSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at end. We want the arrowRight to move the cursor\n evt.stopPropagation();\n }\n};\n\nexport const focusFirstClauseIfAllClausesValid = (\n filterEditor: HTMLElement\n) => {\n const columInput = Array.from(\n filterEditor.querySelectorAll(\".vuuFilterClauseColumn input\")\n ) as HTMLInputElement[];\n if (columInput.every((input) => input.value.length > 0)) {\n setTimeout(() => {\n const input = columInput.at(0);\n input?.select();\n input?.focus();\n }, 100);\n }\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filterClauseFocusManagement.js","sources":["../../src/filter-clause/filterClauseFocusManagement.ts"],"sourcesContent":["import { getElementDataIndex, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEvent } from \"react\";\n\nconst getFilterClauseElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClause\") as HTMLElement;\n\nconst getFilterClauseFieldElement = (possiblyDescendant?: HTMLElement) =>\n possiblyDescendant?.closest(\".vuuFilterClauseField\") as HTMLElement;\n\ntype FilterClauseFieldName = \"column\" | \"operator\" | \"value\";\nconst mapFilterFieldToClassName: Record<FilterClauseFieldName, string> = {\n column: \"vuuFilterClauseColumn\",\n operator: \"vuuFilterClauseOperator\",\n value: \"vuuFilterClauseValue\",\n};\n\nconst getFilterClauseDetails = ({ classList }: HTMLElement) => {\n if (classList.contains(\"vuuFilterClauseColumn\")) {\n return \"column\";\n } else if (classList.contains(\"vuuFilterClauseOperator\")) {\n return \"operator\";\n } else if (classList.contains(\"vuuFilterClauseValue\")) {\n return \"value\";\n } else {\n throw Error(\n \"getFilterClauseField, filterClauseElemnent is missing required class name\"\n );\n }\n};\n\nexport const getFocusedFieldDetails = (): [number, string] | [] => {\n const el = document.activeElement as HTMLElement;\n const field = queryClosest(el, \".vuuFilterClauseField\");\n const filterClause = queryClosest(field, \".vuuFilterClause\");\n if (filterClause && field) {\n return [getElementDataIndex(filterClause), getFilterClauseDetails(field)];\n } else {\n return [];\n }\n};\n\n// Focus the input control within field. If clause passed, will\n// focus first field within clause\nconst focusField = (fieldOrClause: HTMLElement | null) => {\n const input = fieldOrClause?.querySelector(\"input\");\n if (input) {\n input.focus();\n requestAnimationFrame(() => {\n input?.select();\n });\n }\n};\n\nexport const elementIsFilterCombinator = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClauseCombinator\");\n\nexport const elementIsFilterClause = (\n element: Element | null\n): element is HTMLElement =>\n element !== null && element.classList.contains(\"vuuFilterClause\");\n\nexport const focusFilterClauseField = (\n filterEditor: HTMLElement,\n filterClauseIndex: number,\n fieldName: FilterClauseFieldName = \"value\"\n) => {\n if (filterEditor) {\n const fieldClassName = mapFilterFieldToClassName[fieldName];\n const field = filterEditor.querySelector(\n `.vuuFilterClause[data-index=\"${filterClauseIndex}\"] .${fieldClassName}`\n ) as HTMLElement;\n focusField(field);\n }\n};\n\nexport const focusLastClauseValue = (filterEditor: HTMLElement) => {\n console.log(\"focusLastClauseValue\");\n const field = Array.from(\n filterEditor?.querySelectorAll(\".vuuFilterClauseField\")\n ).at(-1) as HTMLElement;\n focusField(field);\n};\n\nexport const focusNextFocusableElement = (direction: \"fwd\" | \"bwd\" = \"fwd\") => {\n const activeField = getFocusedField() as HTMLElement;\n const filterClause = getFilterClauseElement(activeField);\n if (direction === \"fwd\" && filterClause?.lastChild === activeField) {\n requestAnimationFrame(() => {\n focusNextFocusableElement();\n });\n } else {\n const nextField =\n direction === \"fwd\"\n ? (activeField?.nextElementSibling as HTMLElement)\n : (activeField?.previousElementSibling as HTMLElement);\n\n nextField?.querySelector(\"input\")?.focus();\n }\n};\n\nconst getFocusedField = () => {\n const activeElement = document.activeElement as HTMLElement;\n if (activeElement?.classList.contains(\"vuuFilterClause-clearButton\")) {\n return activeElement as HTMLElement;\n } else {\n return getFilterClauseFieldElement(activeElement);\n }\n};\n\nexport const focusNextElement = () => {\n const filterClauseField = getFocusedField();\n const filterClause = getFilterClauseElement(filterClauseField);\n if (filterClause && filterClauseField) {\n if (filterClauseField.classList.contains(\"vuuFilterClauseValue\")) {\n const clearButton = filterClause.querySelector(\n \".vuuFilterClause-clearButton\"\n ) as HTMLButtonElement;\n clearButton?.focus();\n } else {\n focusNextFocusableElement();\n }\n }\n};\n\nconst cursorAtTextStart = (input: HTMLInputElement) =>\n input.selectionStart === 0;\n\nconst cursorAtTextEnd = (input: HTMLInputElement) =>\n input.selectionStart === input.value.length;\n\nconst getFieldName = (field: HTMLElement) =>\n field?.classList.contains(\"vuuFilterClauseColumn\")\n ? \"column\"\n : field?.classList.contains(\"vuuFilterClauseOperator\")\n ? \"operator\"\n : \"value\";\n\nexport const clauseIsNotFirst = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n if (clause) {\n const index = getElementDataIndex(clause);\n return index > 0;\n }\n};\n\nconst clauseIsNotLast = (el: HTMLElement) => {\n const clause = getFilterClauseElement(el);\n const nextClause = clause?.nextElementSibling as HTMLElement;\n return nextClause?.classList.contains(\"vuuFilterClauseCombinator\");\n};\n\nexport const tabToPreviousFilterCombinator = (currentElement: HTMLElement) => {\n const filterClause = getFilterClauseElement(currentElement);\n const nextItem = filterClause.previousSibling as HTMLElement;\n console.log(`tab to previous combinator`);\n nextItem?.focus();\n};\n\nexport const navigateToNextFilterClause = (\n currentElement: HTMLElement,\n direction: \"bwd\" | \"fwd\" = \"fwd\"\n) => {\n if (direction === \"bwd\") {\n if (elementIsFilterCombinator(currentElement)) {\n const nextClause = currentElement.previousElementSibling;\n if (elementIsFilterClause(nextClause)) {\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n console.log(`focus field Value ${nextField?.classList}`);\n focusField(nextField);\n }\n } else {\n const filterClause = getFilterClauseElement(currentElement);\n const nextClause = filterClause.previousSibling as HTMLElement;\n const nextField = nextClause.querySelector(\n \".vuuFilterClauseValue\"\n ) as HTMLElement;\n focusField(nextField);\n }\n } else {\n const nextClause = currentElement.nextSibling as HTMLElement;\n focusField(nextClause);\n }\n};\n\n// The logic around preventDefault/stopPropagation is important\n// in this function\nexport const navigateToNextItemIfAtBoundary = (\n evt: KeyboardEvent<HTMLInputElement>\n) => {\n const input = evt.target as HTMLInputElement;\n const field = getFilterClauseFieldElement(input);\n if (evt.key === \"ArrowLeft\") {\n if (cursorAtTextStart(input)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"column\") {\n if (clauseIsNotFirst(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.previousElementSibling as HTMLElement;\n combinator?.focus();\n }\n } else {\n evt.preventDefault();\n focusField(field.previousSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at start. We want the arrowLeft to move the cursor\n evt.stopPropagation();\n } else if (evt.key === \"ArrowRight\") {\n if (cursorAtTextEnd(input as HTMLInputElement)) {\n const fieldName = getFieldName(field);\n if (fieldName === \"value\") {\n if (clauseIsNotLast(input)) {\n const filterClause = getFilterClauseElement(field);\n const combinator = filterClause.nextElementSibling as HTMLElement;\n combinator?.focus();\n }\n // Do not preventDefault, stopPropagation\n return;\n } else {\n evt.preventDefault();\n focusField(field.nextSibling as HTMLElement);\n }\n }\n // stopPropagation, even if cursor is not at end. We want the arrowRight to move the cursor\n evt.stopPropagation();\n }\n};\n\nexport const focusFirstClauseIfAllClausesValid = (\n filterEditor: HTMLElement\n) => {\n const columInput = Array.from(\n filterEditor.querySelectorAll(\".vuuFilterClauseColumn input\")\n ) as HTMLInputElement[];\n if (columInput.every((input) => input.value.length > 0)) {\n setTimeout(() => {\n const input = columInput.at(0);\n input?.select();\n input?.focus();\n }, 100);\n }\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { hasOpenOptionList } from '@vuu-ui/vuu-utils';
|
|
2
2
|
import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
|
|
3
|
-
import { clauseIsNotFirst, focusNextFocusableElement, focusNextElement, navigateToNextItemIfAtBoundary, tabToPreviousFilterCombinator
|
|
3
|
+
import { clauseIsNotFirst, focusNextFocusableElement, focusNextElement, navigateToNextItemIfAtBoundary, tabToPreviousFilterCombinator } from './filterClauseFocusManagement.js';
|
|
4
4
|
|
|
5
5
|
const useFilterClause = ({
|
|
6
6
|
filterClauseModel,
|
|
@@ -18,6 +18,16 @@ const useFilterClause = ({
|
|
|
18
18
|
}, [filterClauseModel]);
|
|
19
19
|
const columnRef = useRef(null);
|
|
20
20
|
const operatorRef = useRef(null);
|
|
21
|
+
const valueRef = useRef(null);
|
|
22
|
+
const setValueRef = useCallback(
|
|
23
|
+
(el) => {
|
|
24
|
+
valueRef.current = el;
|
|
25
|
+
if (!filterClauseModel.isValid) {
|
|
26
|
+
el?.querySelector("input")?.focus();
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
[filterClauseModel.isValid]
|
|
30
|
+
);
|
|
21
31
|
const removeAndNavigateToNextInputIfAtBoundary = useCallback(
|
|
22
32
|
(evt) => {
|
|
23
33
|
const input = evt.target;
|
|
@@ -107,11 +117,6 @@ const useFilterClause = ({
|
|
|
107
117
|
removeAndNavigateToNextInputIfAtBoundary
|
|
108
118
|
]
|
|
109
119
|
);
|
|
110
|
-
const handleFocus = useCallback((evt) => {
|
|
111
|
-
if (elementIsFilterClause(evt.target)) {
|
|
112
|
-
focusField(evt.target);
|
|
113
|
-
}
|
|
114
|
-
}, []);
|
|
115
120
|
const inputProps = useMemo(
|
|
116
121
|
() => ({
|
|
117
122
|
onKeyDownCapture: handleKeyDownCaptureNavigation,
|
|
@@ -120,10 +125,10 @@ const useFilterClause = ({
|
|
|
120
125
|
[handleKeyDownCaptureNavigation]
|
|
121
126
|
);
|
|
122
127
|
useEffect(() => {
|
|
123
|
-
if (filterClauseModel.
|
|
128
|
+
if (!filterClauseModel.isValid) {
|
|
129
|
+
const inputRef = filterClauseModel.column === void 0 ? columnRef : filterClauseModel.op === void 0 ? operatorRef : null;
|
|
124
130
|
requestAnimationFrame(() => {
|
|
125
|
-
|
|
126
|
-
columnInput?.focus();
|
|
131
|
+
inputRef?.current?.querySelector("input")?.focus();
|
|
127
132
|
});
|
|
128
133
|
}
|
|
129
134
|
}, [filterClauseModel]);
|
|
@@ -134,10 +139,10 @@ const useFilterClause = ({
|
|
|
134
139
|
onChangeValue: handleChangeValue,
|
|
135
140
|
onDeselectValue: handleDeselectValue,
|
|
136
141
|
onSelectColumn,
|
|
137
|
-
onFocus: handleFocus,
|
|
138
142
|
onSelectOperator,
|
|
139
143
|
operatorRef,
|
|
140
|
-
selectedColumn: columnsByName[
|
|
144
|
+
selectedColumn: columnsByName[filterClauseModel.column ?? ""],
|
|
145
|
+
valueRef: setValueRef
|
|
141
146
|
};
|
|
142
147
|
};
|
|
143
148
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFilterClause.js","sources":["../../src/filter-clause/useFilterClause.ts"],"sourcesContent":["import { FilterClause, FilterClauseOp } from \"@vuu-ui/vuu-filter-types\";\nimport { hasOpenOptionList } from \"@vuu-ui/vuu-utils\";\nimport {\n FocusEventHandler,\n KeyboardEvent,\n SyntheticEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { FilterClauseProps } from \"./FilterClause\";\nimport {\n clauseIsNotFirst,\n elementIsFilterClause,\n focusField,\n focusNextElement,\n focusNextFocusableElement,\n navigateToNextItemIfAtBoundary,\n tabToPreviousFilterCombinator,\n} from \"./filterClauseFocusManagement\";\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n>;\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}: 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\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 console.log(`focus next element`);\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_, 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 handleFocus = useCallback<FocusEventHandler>((evt) => {\n if (elementIsFilterClause(evt.target)) {\n focusField(evt.target);\n }\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 if (filterClauseModel.column === undefined) {\n requestAnimationFrame(() => {\n const columnInput = columnRef?.current?.querySelector(\"input\");\n columnInput?.focus();\n });\n }\n }, [filterClauseModel]);\n\n return {\n inputProps,\n columnRef,\n filterClause,\n onChangeValue: handleChangeValue,\n onDeselectValue: handleDeselectValue,\n onSelectColumn,\n onFocus: handleFocus,\n onSelectOperator,\n operatorRef,\n selectedColumn: columnsByName[filterClause.column ?? \"\"],\n };\n};\n"],"names":["filterClause"],"mappings":";;;;AAgCO,MAAM,kBAAkB,CAAC;AAAA,EAC9B,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AACF,CAAmC,KAAA;AACjC,EAAM,MAAA,CAAC,YAAc,EAAA,eAAe,CAAI,GAAA,QAAA;AAAA,IACtC,iBAAkB,CAAA,OAAA,GAAU,iBAAkB,CAAA,QAAA,KAAa,EAAC;AAAA,GAC9D,CAAA;AAEA,EAAA,OAAA,CAAQ,MAAM;AACZ,IAAkB,iBAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAACA,aAAiB,KAAA;AACrD,MAAA,eAAA,CAAgBA,aAAY,CAAA,CAAA;AAAA,KAC7B,CAAA,CAAA;AAAA,GACH,EAAG,CAAC,iBAAiB,CAAC,CAAA,CAAA;AAEtB,EAAM,MAAA,SAAA,GAAY,OAAuB,IAAI,CAAA,CAAA;AAC7C,EAAM,MAAA,WAAA,GAAc,OAAuB,IAAI,CAAA,CAAA;AAE/C,EAAA,MAAM,wCAA2C,GAAA,WAAA;AAAA,IAC/C,CAAC,GAAuB,KAAA;AACtB,MAAA,MAAM,QAAQ,GAAI,CAAA,MAAA,CAAA;AAClB,MAAI,IAAA,KAAA,CAAM,UAAU,EAAI,EAAA;AACtB,QAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,OAAA,CAAQ,cAAc,CAAA,CAAA;AAC1C,QAAQ,QAAA,KAAA,EAAO,SAAS,KAAO;AAAA,UAC7B,KAAK,UAAY,EAAA;AACf,YAAA,iBAAA,CAAkB,MAAS,GAAA,KAAA,CAAA,CAAA;AAC3B,YAAA,yBAAA,CAA0B,KAAK,CAAA,CAAA;AAC/B,YAAA,MAAA;AAAA,WACF;AAAA,UACA,KAAK,OAAS,EAAA;AACZ,YAAA,iBAAA,CAAkB,MAAM,KAAS,CAAA,CAAA,CAAA;AACjC,YAAA,yBAAA,CAA0B,KAAK,CAAA,CAAA;AAC/B,YAAA,MAAA;AAAA,WACF;AAAA,UACA,KAAK,QAAU,EAAA;AACb,YAAI,IAAA,gBAAA,CAAiB,KAAK,CAAG,EAAA;AAI3B,cAAA,GAAA,CAAI,cAAe,EAAA,CAAA;AACnB,cAAA,QAAA,GAAW,mBAAmB,WAAW,CAAA,CAAA;AAAA,aAC3C;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,mBAAmB,QAAQ,CAAA;AAAA,GAC9B,CAAA;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,CAAA;AAChB,QAAA,IAAI,QAAQ,KAAO,EAAA;AACjB,UAAI,IAAA,iBAAA,CAAkB,WAAW,cAAgB,EAAA;AAE/C,YAAA,OAAA;AAAA,WACK,MAAA;AAEL,YAAA,GAAA,CAAI,cAAe,EAAA,CAAA;AAAA,WACrB;AAAA,SACF;AAAA,OACF;AAAA,KACF;AACA,IAAA,iBAAA,CAAkB,MAAS,GAAA,cAAA,CAAA;AAC3B,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,OAAA,CAAQ,IAAI,CAAoB,kBAAA,CAAA,CAAA,CAAA;AAChC,MAAiB,gBAAA,EAAA,CAAA;AAAA,OAChB,GAAG,CAAA,CAAA;AAAA,GACR,CAAA;AAEA,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,GAAG,UAA+B,KAAA;AACjC,MAAA,iBAAA,CAAkB,MAAM,UAAU,CAAA,CAAA;AAClC,MAAiB,gBAAA,EAAA,CAAA;AAAA,KACnB;AAAA,IACA,CAAC,iBAAiB,CAAA;AAAA,GACpB,CAAA;AAEA,EAAA,MAAM,iBAAoB,GAAA,WAAA;AAAA,IACxB,CAAC,KAAO,EAAA,OAAA,KAAY,iBAAkB,CAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AAAA,IAC7D,CAAC,iBAAiB,CAAA;AAAA,GACpB,CAAA;AAEA,EAAA,MAAM,mBAAsB,GAAA,WAAA;AAAA,IAC1B,MAAM,iBAAkB,CAAA,QAAA,CAAS,KAAS,CAAA,CAAA;AAAA,IAC1C,CAAC,iBAAiB,CAAA;AAAA,GACpB,CAAA;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,CAAA;AAAA,OACpC,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,WAAa,EAAA;AAClC,QAAA,wCAAA,CAAyC,GAAG,CAAA,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,CAAA;AAAA,SACxC;AAAA,OACS,MAAA,IAAA,GAAA,CAAI,GAAQ,KAAA,KAAA,IAAS,IAAI,QAAU,EAAA;AAC5C,QAAA,GAAA,CAAI,cAAe,EAAA,CAAA;AACnB,QAAA,6BAAA,CAA8B,IAAI,MAAqB,CAAA,CAAA;AAAA,OACzD,MAAA,IAAW,GAAI,CAAA,GAAA,KAAQ,KAAO,EAAA;AAE5B,QAAA,IAAI,kBAAkB,OAAS,EAAA;AAC7B,UAAA,GAAA,CAAI,cAAe,EAAA,CAAA;AACnB,UAAA,GAAA,CAAI,eAAgB,EAAA,CAAA;AAEpB,UAAc,WAAA,IAAA,CAAA;AAAA,SAChB;AAAA,OACF;AAAA,KACF;AAAA,IACA;AAAA,MACE,iBAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA,wCAAA;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,WAAA,GAAc,WAA+B,CAAA,CAAC,GAAQ,KAAA;AAC1D,IAAI,IAAA,qBAAA,CAAsB,GAAI,CAAA,MAAM,CAAG,EAAA;AACrC,MAAA,UAAA,CAAW,IAAI,MAAM,CAAA,CAAA;AAAA,KACvB;AAAA,GACF,EAAG,EAAE,CAAA,CAAA;AAEL,EAAA,MAAM,UAAa,GAAA,OAAA;AAAA,IACjB,OAAO;AAAA,MACL,gBAAkB,EAAA,8BAAA;AAAA,MAClB,QAAU,EAAA,CAAA,CAAA;AAAA,KACZ,CAAA;AAAA,IACA,CAAC,8BAA8B,CAAA;AAAA,GACjC,CAAA;AAGA,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,iBAAA,CAAkB,WAAW,KAAW,CAAA,EAAA;AAC1C,MAAA,qBAAA,CAAsB,MAAM;AAC1B,QAAA,MAAM,WAAc,GAAA,SAAA,EAAW,OAAS,EAAA,aAAA,CAAc,OAAO,CAAA,CAAA;AAC7D,QAAA,WAAA,EAAa,KAAM,EAAA,CAAA;AAAA,OACpB,CAAA,CAAA;AAAA,KACH;AAAA,GACF,EAAG,CAAC,iBAAiB,CAAC,CAAA,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,OAAS,EAAA,WAAA;AAAA,IACT,gBAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAgB,EAAA,aAAA,CAAc,YAAa,CAAA,MAAA,IAAU,EAAE,CAAA;AAAA,GACzD,CAAA;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"useFilterClause.js","sources":["../../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\";\nexport type FilterClauseEditorHookProps = Pick<\n FilterClauseProps,\n \"columnsByName\" | \"filterClauseModel\" | \"onCancel\" | \"onFocusSave\"\n>;\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}: 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 console.log(`focus next element`);\n focusNextElement();\n }, 100);\n };\n\n const onSelectOperator = useCallback(\n (_, 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 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 operatorRef,\n selectedColumn: columnsByName[filterClauseModel.column ?? \"\"],\n valueRef: setValueRef,\n };\n};\n"],"names":["filterClause"],"mappings":"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"}
|
|
@@ -3,72 +3,77 @@ import cx from 'clsx';
|
|
|
3
3
|
import { FilterClauseValueEditorNumber } from './FilterClauseValueEditorNumber.js';
|
|
4
4
|
import { FilterClauseValueEditorText } from './FilterClauseValueEditorText.js';
|
|
5
5
|
import { isDateTimeColumn } from '@vuu-ui/vuu-utils';
|
|
6
|
+
import { forwardRef } from 'react';
|
|
6
7
|
import { FilterClauseValueEditorDate } from './FilterClauseValueEditorDate.js';
|
|
7
8
|
|
|
8
9
|
const classBase = "vuuFilterClause";
|
|
9
|
-
const FilterClauseValueEditor = (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
FilterClauseValueEditorDate,
|
|
26
|
-
{
|
|
27
|
-
inputProps,
|
|
28
|
-
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
29
|
-
"data-field": "value",
|
|
30
|
-
value,
|
|
31
|
-
operator,
|
|
32
|
-
onChangeValue
|
|
33
|
-
}
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
switch (selectedColumn.serverDataType) {
|
|
37
|
-
case "string":
|
|
38
|
-
case "char":
|
|
39
|
-
return /* @__PURE__ */ jsx(
|
|
40
|
-
FilterClauseValueEditorText,
|
|
41
|
-
{
|
|
42
|
-
inputProps,
|
|
43
|
-
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
44
|
-
column: selectedColumn,
|
|
45
|
-
onDeselect: onDeselectValue,
|
|
46
|
-
onChangeValue,
|
|
47
|
-
operator,
|
|
48
|
-
suggestionProvider,
|
|
49
|
-
table,
|
|
50
|
-
value: value === void 0 ? "" : Array.isArray(value) ? value.map((val) => val.toString()) : value.toString()
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
case "int":
|
|
54
|
-
case "long":
|
|
55
|
-
case "double":
|
|
10
|
+
const FilterClauseValueEditor = forwardRef(
|
|
11
|
+
function FilterClauseValueEditor2({
|
|
12
|
+
selectedColumn,
|
|
13
|
+
operator,
|
|
14
|
+
inputProps,
|
|
15
|
+
onChangeValue,
|
|
16
|
+
onDeselectValue,
|
|
17
|
+
suggestionProvider,
|
|
18
|
+
table,
|
|
19
|
+
value
|
|
20
|
+
}, forwardedRef) {
|
|
21
|
+
if (selectedColumn === void 0 || operator === void 0) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (isDateTimeColumn(selectedColumn)) {
|
|
25
|
+
console.log(`return DateInput`);
|
|
56
26
|
return /* @__PURE__ */ jsx(
|
|
57
|
-
|
|
27
|
+
FilterClauseValueEditorDate,
|
|
58
28
|
{
|
|
59
29
|
inputProps,
|
|
60
30
|
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
61
|
-
column: selectedColumn,
|
|
62
31
|
"data-field": "value",
|
|
63
|
-
|
|
64
|
-
operator
|
|
32
|
+
value,
|
|
33
|
+
operator,
|
|
34
|
+
onChangeValue
|
|
65
35
|
}
|
|
66
36
|
);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
37
|
+
}
|
|
38
|
+
switch (selectedColumn.serverDataType) {
|
|
39
|
+
case "string":
|
|
40
|
+
case "char":
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
FilterClauseValueEditorText,
|
|
43
|
+
{
|
|
44
|
+
inputProps,
|
|
45
|
+
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
46
|
+
column: selectedColumn,
|
|
47
|
+
onDeselect: onDeselectValue,
|
|
48
|
+
onChangeValue,
|
|
49
|
+
operator,
|
|
50
|
+
ref: forwardedRef,
|
|
51
|
+
suggestionProvider,
|
|
52
|
+
table,
|
|
53
|
+
value: value === void 0 ? "" : Array.isArray(value) ? value.map((val) => val.toString()) : value.toString()
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
case "int":
|
|
57
|
+
case "long":
|
|
58
|
+
case "double":
|
|
59
|
+
return /* @__PURE__ */ jsx(
|
|
60
|
+
FilterClauseValueEditorNumber,
|
|
61
|
+
{
|
|
62
|
+
inputProps,
|
|
63
|
+
className: cx(`${classBase}Field`, `${classBase}Value`),
|
|
64
|
+
column: selectedColumn,
|
|
65
|
+
"data-field": "value",
|
|
66
|
+
onChangeValue,
|
|
67
|
+
operator,
|
|
68
|
+
ref: forwardedRef
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
default:
|
|
72
|
+
console.log("returning null");
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
70
75
|
}
|
|
71
|
-
|
|
76
|
+
);
|
|
72
77
|
|
|
73
78
|
export { FilterClauseValueEditor };
|
|
74
79
|
//# sourceMappingURL=FilterClauseValueEditor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterClauseValueEditor.js","sources":["../../../src/filter-clause/value-editors/FilterClauseValueEditor.tsx"],"sourcesContent":["import { TableSchemaTable } from \"@vuu-ui/vuu-data-types\";\nimport cx from \"clsx\";\nimport {
|
|
1
|
+
{"version":3,"file":"FilterClauseValueEditor.js","sources":["../../../src/filter-clause/value-editors/FilterClauseValueEditor.tsx"],"sourcesContent":["import { TableSchemaTable } from \"@vuu-ui/vuu-data-types\";\nimport cx from \"clsx\";\nimport { useFilterClause } from \"../useFilterClause\";\nimport { FilterClauseValueEditorNumber } from \"./FilterClauseValueEditorNumber\";\nimport { FilterClauseValueEditorText } from \"./FilterClauseValueEditorText\";\n\nimport {\n NumericFilterClauseOp,\n SingleValueFilterClauseOp,\n} from \"@vuu-ui/vuu-filter-types\";\nimport { isDateTimeColumn } from \"@vuu-ui/vuu-utils\";\nimport { ForwardedRef, forwardRef } from \"react\";\nimport { FilterClauseProps } from \"../FilterClause\";\nimport { FilterClauseValueEditorDate } from \"./FilterClauseValueEditorDate\";\n\nconst classBase = \"vuuFilterClause\";\n\ntype FilterClauseValueEditorProps = Pick<\n ReturnType<typeof useFilterClause>,\n \"selectedColumn\" | \"inputProps\" | \"onChangeValue\" | \"onDeselectValue\"\n> &\n Pick<FilterClauseProps, \"suggestionProvider\"> & {\n table?: TableSchemaTable;\n } & {\n operator?: SingleValueFilterClauseOp | \"in\";\n value?: string | string[] | number | number[] | boolean | boolean[];\n };\n\nexport const FilterClauseValueEditor = forwardRef(\n function FilterClauseValueEditor(\n {\n selectedColumn,\n operator,\n inputProps,\n onChangeValue,\n onDeselectValue,\n suggestionProvider,\n table,\n value,\n }: FilterClauseValueEditorProps,\n forwardedRef: ForwardedRef<HTMLDivElement>\n ) {\n if (selectedColumn === undefined || operator === undefined) {\n return null;\n }\n\n if (isDateTimeColumn(selectedColumn)) {\n console.log(`return DateInput`);\n return (\n <FilterClauseValueEditorDate\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Value`)}\n data-field=\"value\"\n // ref={forwardedRef}\n value={value as number}\n operator={operator as NumericFilterClauseOp}\n onChangeValue={onChangeValue}\n />\n );\n }\n\n switch (selectedColumn.serverDataType) {\n case \"string\":\n case \"char\":\n return (\n <FilterClauseValueEditorText\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Value`)}\n column={selectedColumn}\n onDeselect={onDeselectValue}\n onChangeValue={onChangeValue}\n operator={operator}\n ref={forwardedRef}\n suggestionProvider={suggestionProvider}\n table={table}\n value={\n value === undefined\n ? \"\"\n : Array.isArray(value)\n ? value.map((val) => val.toString())\n : (value.toString() as string | string[])\n }\n />\n );\n case \"int\":\n case \"long\":\n case \"double\":\n return (\n <FilterClauseValueEditorNumber\n inputProps={inputProps}\n className={cx(`${classBase}Field`, `${classBase}Value`)}\n column={selectedColumn}\n data-field=\"value\"\n onChangeValue={onChangeValue}\n operator={operator}\n ref={forwardedRef}\n />\n );\n default:\n console.log(\"returning null\");\n return null;\n }\n }\n);\n"],"names":["FilterClauseValueEditor"],"mappings":";;;;;;;;AAeA,MAAM,SAAY,GAAA,iBAAA,CAAA;AAaX,MAAM,uBAA0B,GAAA,UAAA;AAAA,EACrC,SAASA,wBACP,CAAA;AAAA,IACE,cAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,KAEF,YACA,EAAA;AACA,IAAI,IAAA,cAAA,KAAmB,KAAa,CAAA,IAAA,QAAA,KAAa,KAAW,CAAA,EAAA;AAC1D,MAAO,OAAA,IAAA,CAAA;AAAA,KACT;AAEA,IAAI,IAAA,gBAAA,CAAiB,cAAc,CAAG,EAAA;AACpC,MAAA,OAAA,CAAQ,IAAI,CAAkB,gBAAA,CAAA,CAAA,CAAA;AAC9B,MACE,uBAAA,GAAA;AAAA,QAAC,2BAAA;AAAA,QAAA;AAAA,UACC,UAAA;AAAA,UACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAO,KAAA,CAAA,CAAA;AAAA,UACtD,YAAW,EAAA,OAAA;AAAA,UAEX,KAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAA;AAAA,SAAA;AAAA,OACF,CAAA;AAAA,KAEJ;AAEA,IAAA,QAAQ,eAAe,cAAgB;AAAA,MACrC,KAAK,QAAA,CAAA;AAAA,MACL,KAAK,MAAA;AACH,QACE,uBAAA,GAAA;AAAA,UAAC,2BAAA;AAAA,UAAA;AAAA,YACC,UAAA;AAAA,YACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAO,KAAA,CAAA,CAAA;AAAA,YACtD,MAAQ,EAAA,cAAA;AAAA,YACR,UAAY,EAAA,eAAA;AAAA,YACZ,aAAA;AAAA,YACA,QAAA;AAAA,YACA,GAAK,EAAA,YAAA;AAAA,YACL,kBAAA;AAAA,YACA,KAAA;AAAA,YACA,OACE,KAAU,KAAA,KAAA,CAAA,GACN,EACA,GAAA,KAAA,CAAM,QAAQ,KAAK,CAAA,GACnB,KAAM,CAAA,GAAA,CAAI,CAAC,GAAQ,KAAA,GAAA,CAAI,UAAU,CAAA,GAChC,MAAM,QAAS,EAAA;AAAA,WAAA;AAAA,SAExB,CAAA;AAAA,MAEJ,KAAK,KAAA,CAAA;AAAA,MACL,KAAK,MAAA,CAAA;AAAA,MACL,KAAK,QAAA;AACH,QACE,uBAAA,GAAA;AAAA,UAAC,6BAAA;AAAA,UAAA;AAAA,YACC,UAAA;AAAA,YACA,WAAW,EAAG,CAAA,CAAA,EAAG,SAAS,CAAS,KAAA,CAAA,EAAA,CAAA,EAAG,SAAS,CAAO,KAAA,CAAA,CAAA;AAAA,YACtD,MAAQ,EAAA,cAAA;AAAA,YACR,YAAW,EAAA,OAAA;AAAA,YACX,aAAA;AAAA,YACA,QAAA;AAAA,YACA,GAAK,EAAA,YAAA;AAAA,WAAA;AAAA,SACP,CAAA;AAAA,MAEJ;AACE,QAAA,OAAA,CAAQ,IAAI,gBAAgB,CAAA,CAAA;AAC5B,QAAO,OAAA,IAAA,CAAA;AAAA,KACX;AAAA,GACF;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.8.
|
|
2
|
+
"version": "0.8.73",
|
|
3
3
|
"author": "heswell",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"@vuu-ui/vuu-data-types": "0.8.
|
|
8
|
-
"@vuu-ui/vuu-protocol-types": "0.8.
|
|
9
|
-
"@vuu-ui/vuu-table-types": "0.8.
|
|
10
|
-
"@vuu-ui/vuu-filter-types": "0.8.
|
|
7
|
+
"@vuu-ui/vuu-data-types": "0.8.73",
|
|
8
|
+
"@vuu-ui/vuu-protocol-types": "0.8.73",
|
|
9
|
+
"@vuu-ui/vuu-table-types": "0.8.73",
|
|
10
|
+
"@vuu-ui/vuu-filter-types": "0.8.73",
|
|
11
11
|
"@types/uuid": "^9.0.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@vuu-ui/vuu-data-react": "0.8.
|
|
15
|
-
"@vuu-ui/vuu-filter-parser": "0.8.
|
|
16
|
-
"@vuu-ui/vuu-popups": "0.8.
|
|
17
|
-
"@vuu-ui/vuu-ui-controls": "0.8.
|
|
18
|
-
"@vuu-ui/vuu-table": "0.8.
|
|
19
|
-
"@vuu-ui/vuu-utils": "0.8.
|
|
14
|
+
"@vuu-ui/vuu-data-react": "0.8.73",
|
|
15
|
+
"@vuu-ui/vuu-filter-parser": "0.8.73",
|
|
16
|
+
"@vuu-ui/vuu-popups": "0.8.73",
|
|
17
|
+
"@vuu-ui/vuu-ui-controls": "0.8.73",
|
|
18
|
+
"@vuu-ui/vuu-table": "0.8.73",
|
|
19
|
+
"@vuu-ui/vuu-utils": "0.8.73",
|
|
20
20
|
"@salt-ds/core": "1.27.1",
|
|
21
21
|
"@salt-ds/styles": "0.2.1",
|
|
22
22
|
"@salt-ds/window": "0.1.1",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { KeyboardEvent } from "react";
|
|
2
2
|
type FilterClauseFieldName = "column" | "operator" | "value";
|
|
3
3
|
export declare const getFocusedFieldDetails: () => [number, string] | [];
|
|
4
|
-
export declare const focusField: (fieldOrClause: HTMLElement | null) => void;
|
|
5
4
|
export declare const elementIsFilterCombinator: (element: Element | null) => element is HTMLElement;
|
|
6
5
|
export declare const elementIsFilterClause: (element: Element | null) => element is HTMLElement;
|
|
7
6
|
export declare const focusFilterClauseField: (filterEditor: HTMLElement, filterClauseIndex: number, fieldName?: FilterClauseFieldName) => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FilterClause, FilterClauseOp } from "@vuu-ui/vuu-filter-types";
|
|
2
|
-
import {
|
|
2
|
+
import { KeyboardEvent, RefCallback, SyntheticEvent } from "react";
|
|
3
3
|
import { FilterClauseProps } from "./FilterClause";
|
|
4
4
|
export type FilterClauseEditorHookProps = Pick<FilterClauseProps, "columnsByName" | "filterClauseModel" | "onCancel" | "onFocusSave">;
|
|
5
5
|
export type FilterClauseValueChangeHandler = (value: string | string[] | number | number[], isFinal?: boolean) => void;
|
|
@@ -13,8 +13,8 @@ export declare const useFilterClause: ({ filterClauseModel, onCancel, columnsByN
|
|
|
13
13
|
onChangeValue: FilterClauseValueChangeHandler;
|
|
14
14
|
onDeselectValue: () => void;
|
|
15
15
|
onSelectColumn: (evt: SyntheticEvent, selectedColumn: string) => void;
|
|
16
|
-
onFocus: FocusEventHandler;
|
|
17
16
|
onSelectOperator: (_: any, selectedOp: FilterClauseOp) => void;
|
|
18
17
|
operatorRef: import("react").RefObject<HTMLDivElement>;
|
|
19
18
|
selectedColumn: import("packages/vuu-table-types").ColumnDescriptor;
|
|
19
|
+
valueRef: RefCallback<HTMLDivElement>;
|
|
20
20
|
};
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { TableSchemaTable } from "@vuu-ui/vuu-data-types";
|
|
3
|
-
import { useFilterClause } from "../useFilterClause";
|
|
4
3
|
import { SingleValueFilterClauseOp } from "@vuu-ui/vuu-filter-types";
|
|
5
4
|
import { FilterClauseProps } from "../FilterClause";
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export declare const FilterClauseValueEditor: import("react").ForwardRefExoticComponent<Pick<{
|
|
6
|
+
inputProps: {
|
|
7
|
+
onKeyDownCapture: (evt: import("react").KeyboardEvent<HTMLInputElement>) => void;
|
|
8
|
+
tabIndex: number;
|
|
9
|
+
};
|
|
10
|
+
columnRef: import("react").RefObject<HTMLDivElement>;
|
|
11
|
+
filterClause: Partial<import("@vuu-ui/vuu-filter-types").FilterClause>;
|
|
12
|
+
onChangeValue: import("../useFilterClause").FilterClauseValueChangeHandler;
|
|
13
|
+
onDeselectValue: () => void;
|
|
14
|
+
onSelectColumn: (evt: import("react").SyntheticEvent<Element, Event>, selectedColumn: string) => void;
|
|
15
|
+
onSelectOperator: (_: any, selectedOp: import("@vuu-ui/vuu-filter-types").FilterClauseOp) => void;
|
|
16
|
+
operatorRef: import("react").RefObject<HTMLDivElement>;
|
|
17
|
+
selectedColumn: import("packages/vuu-table-types").ColumnDescriptor;
|
|
18
|
+
valueRef: import("react").RefCallback<HTMLDivElement>;
|
|
19
|
+
}, "inputProps" | "onChangeValue" | "selectedColumn" | "onDeselectValue"> & Pick<FilterClauseProps, "suggestionProvider"> & {
|
|
20
|
+
table?: TableSchemaTable | undefined;
|
|
8
21
|
} & {
|
|
9
|
-
operator?: SingleValueFilterClauseOp |
|
|
10
|
-
value?: string |
|
|
11
|
-
}
|
|
12
|
-
export declare const FilterClauseValueEditor: React.FC<FilterClauseValueEditorProps>;
|
|
13
|
-
export {};
|
|
22
|
+
operator?: "in" | SingleValueFilterClauseOp | undefined;
|
|
23
|
+
value?: string | number | boolean | string[] | number[] | boolean[] | undefined;
|
|
24
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|