@servicetitan/dte-unlayer 0.95.0 → 0.97.0
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/dist/display-conditions/DisplayConditionModal.d.ts.map +1 -1
- package/dist/display-conditions/DisplayConditionModal.js +42 -36
- package/dist/display-conditions/DisplayConditionModal.js.map +1 -1
- package/dist/editor-core-source.d.ts +1 -1
- package/dist/editor-core-source.d.ts.map +1 -1
- package/dist/editor-core-source.js +1 -1
- package/dist/editor-core-source.js.map +1 -1
- package/package.json +1 -1
- package/src/display-conditions/DisplayConditionModal.tsx +30 -31
- package/src/editor-core-source.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DisplayConditionModal.d.ts","sourceRoot":"","sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DisplayConditionModal.d.ts","sourceRoot":"","sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"names":[],"mappings":"AAiBA,MAAM,WAAW,0BAA0B;IACvC,MAAM,CAAC,EAAE,OAAO,kBAAkB,EAAE,YAAY,CAAC;CACpD;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAO,0BAA0B,uCAgNtE,CAAC"}
|
|
@@ -41,15 +41,9 @@ export const DisplayConditionModal = (props)=>{
|
|
|
41
41
|
});
|
|
42
42
|
}, []);
|
|
43
43
|
const handleClose = useCallback(()=>{
|
|
44
|
-
|
|
45
|
-
var _request_data;
|
|
46
|
-
request.done((_request_data = request.data) !== null && _request_data !== void 0 ? _request_data : null);
|
|
47
|
-
setRequest(null);
|
|
48
|
-
}
|
|
44
|
+
setRequest(null);
|
|
49
45
|
setIsOpen(false);
|
|
50
|
-
}, [
|
|
51
|
-
request
|
|
52
|
-
]);
|
|
46
|
+
}, []);
|
|
53
47
|
const handleSave = useCallback(()=>{
|
|
54
48
|
if (!request) {
|
|
55
49
|
return;
|
|
@@ -169,6 +163,7 @@ export const DisplayConditionModal = (props)=>{
|
|
|
169
163
|
style: {
|
|
170
164
|
maxHeight: MODAL_CONTENT_MAX_HEIGHT,
|
|
171
165
|
overflowY: 'auto',
|
|
166
|
+
paddingRight: 8,
|
|
172
167
|
width: '100%'
|
|
173
168
|
},
|
|
174
169
|
children: [
|
|
@@ -190,7 +185,7 @@ export const DisplayConditionModal = (props)=>{
|
|
|
190
185
|
}),
|
|
191
186
|
/*#__PURE__*/ _jsxs(Flex, {
|
|
192
187
|
direction: "row",
|
|
193
|
-
alignItems: "
|
|
188
|
+
alignItems: "flex-end",
|
|
194
189
|
gap: "3",
|
|
195
190
|
style: {
|
|
196
191
|
flexWrap: 'wrap'
|
|
@@ -200,13 +195,16 @@ export const DisplayConditionModal = (props)=>{
|
|
|
200
195
|
size: "small",
|
|
201
196
|
subdued: true,
|
|
202
197
|
variant: "body",
|
|
198
|
+
style: {
|
|
199
|
+
paddingBottom: 10
|
|
200
|
+
},
|
|
203
201
|
children: "Select to show or hide selected component."
|
|
204
202
|
}),
|
|
205
203
|
/*#__PURE__*/ _jsx("div", {
|
|
206
204
|
style: {
|
|
207
205
|
width: 160
|
|
208
206
|
},
|
|
209
|
-
children: /*#__PURE__*/ _jsxs(Combobox, {
|
|
207
|
+
children: /*#__PURE__*/ _jsxs(Combobox.Select, {
|
|
210
208
|
...{
|
|
211
209
|
disableClearSelection: true
|
|
212
210
|
},
|
|
@@ -225,7 +223,7 @@ export const DisplayConditionModal = (props)=>{
|
|
|
225
223
|
onChange: handleBehaviorChange,
|
|
226
224
|
children: [
|
|
227
225
|
/*#__PURE__*/ _jsx(Combobox.SelectTrigger, {
|
|
228
|
-
label: "
|
|
226
|
+
label: "",
|
|
229
227
|
placeholder: "Select..."
|
|
230
228
|
}),
|
|
231
229
|
/*#__PURE__*/ _jsx(Combobox.Content, {
|
|
@@ -244,36 +242,44 @@ export const DisplayConditionModal = (props)=>{
|
|
|
244
242
|
})
|
|
245
243
|
]
|
|
246
244
|
}),
|
|
247
|
-
/*#__PURE__*/ _jsx(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
children: "Complete each condition before saving. Data point and value are required, and numeric fields must contain a valid number."
|
|
245
|
+
/*#__PURE__*/ _jsx("div", {
|
|
246
|
+
style: {
|
|
247
|
+
padding: 8
|
|
248
|
+
},
|
|
249
|
+
children: /*#__PURE__*/ _jsx(ConditionGroupsSection, {
|
|
250
|
+
dataPointOptions: dataPointOptions,
|
|
251
|
+
groups: state.groups,
|
|
252
|
+
onAddGroup: addGroup,
|
|
253
|
+
onRemoveGroup: removeGroup,
|
|
254
|
+
onUpdateGroup: updateGroup
|
|
255
|
+
})
|
|
259
256
|
})
|
|
260
257
|
]
|
|
261
258
|
})
|
|
262
259
|
}),
|
|
263
|
-
/*#__PURE__*/
|
|
260
|
+
/*#__PURE__*/ _jsx(Dialog.Footer, {
|
|
264
261
|
sticky: true,
|
|
265
|
-
children:
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
262
|
+
children: /*#__PURE__*/ _jsxs(Flex, {
|
|
263
|
+
justifyContent: "flex-end",
|
|
264
|
+
alignItems: "center",
|
|
265
|
+
gap: "3",
|
|
266
|
+
style: {
|
|
267
|
+
width: '100%'
|
|
268
|
+
},
|
|
269
|
+
children: [
|
|
270
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
271
|
+
appearance: "secondary",
|
|
272
|
+
onClick: handleClose,
|
|
273
|
+
children: "Cancel"
|
|
274
|
+
}),
|
|
275
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
276
|
+
appearance: "primary",
|
|
277
|
+
disabled: !canSave,
|
|
278
|
+
onClick: handleSave,
|
|
279
|
+
children: "Save Changes"
|
|
280
|
+
})
|
|
281
|
+
]
|
|
282
|
+
})
|
|
277
283
|
})
|
|
278
284
|
]
|
|
279
285
|
}), portalTarget);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"sourcesContent":["import { Button, Combobox, Dialog, Flex, Text } from '@servicetitan/anvil2';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ConditionGroupsSection } from './ConditionGroupsSection';\nimport { defaultGroup, defaultState, MODAL_CONTENT_MAX_HEIGHT } from './constants';\nimport { DisplayConditionRequest, onDisplayCondition } from './displayConditionController';\nimport { buildUnlayerDisplayCondition, parseUnlayerDisplayCondition } from './nunjucks';\nimport { getSchemaDataPointOptions } from './schemaDataPoints';\nimport { ConditionGroup as ConditionGroupType, DisplayBehavior } from './types';\n\nconst BEHAVIOR_OPTIONS = [\n { label: 'Show', value: 'show' },\n { label: 'Hide', value: 'hide' },\n] as const;\nconst NUMERIC_VALUE_RE = /^-?(?:\\d+\\.?\\d*|\\.\\d+)$/;\n\ntype BehaviorOption = (typeof BEHAVIOR_OPTIONS)[number];\n\nexport interface DisplayConditionModalProps {\n schema?: import('../shared/schema').SchemaObject;\n}\n\nexport const DisplayConditionModal = (props: DisplayConditionModalProps) => {\n const [request, setRequest] = useState<DisplayConditionRequest | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [state, setState] = useState(defaultState);\n\n const dataPointOptions = useMemo(() => getSchemaDataPointOptions(props.schema), [props.schema]);\n\n const portalTarget = useMemo(() => {\n if (typeof document === 'undefined') {\n return null;\n }\n return document.body;\n }, []);\n\n useEffect(() => {\n return onDisplayCondition(nextRequest => {\n setRequest(nextRequest);\n const existing = nextRequest.data;\n const parsed = parseUnlayerDisplayCondition(existing);\n setState(parsed ?? defaultState());\n setIsOpen(true);\n });\n }, []);\n\n const handleClose = useCallback(() => {\n if (request) {\n request.done(request.data ?? null);\n setRequest(null);\n }\n setIsOpen(false);\n }, [request]);\n\n const handleSave = useCallback(() => {\n if (!request) {\n return;\n }\n const condition = buildUnlayerDisplayCondition(state);\n if (condition) {\n request.done(condition);\n } else {\n request.done(null);\n }\n setRequest(null);\n setIsOpen(false);\n }, [request, state]);\n\n const updateGroup = useCallback((index: number, group: ConditionGroupType) => {\n setState(prev => {\n const next = [...prev.groups];\n next[index] = group;\n return { ...prev, groups: next };\n });\n }, []);\n\n const removeGroup = useCallback((index: number) => {\n setState(prev => ({\n ...prev,\n groups: (() => {\n const nextGroups = prev.groups.filter((_, i) => i !== index);\n if (nextGroups.length === 0) {\n return [defaultGroup()];\n }\n if (index === 0) {\n const { logicalOperator: unusedOp, ...firstGroup } = nextGroups[0];\n return [firstGroup, ...nextGroups.slice(1)];\n }\n return nextGroups;\n })(),\n }));\n }, []);\n\n const addGroup = useCallback(() => {\n setState(prev => ({\n ...prev,\n groups: [...prev.groups, { ...defaultGroup(), logicalOperator: 'and' }],\n }));\n }, []);\n\n const selectedBehavior = useMemo(\n () => BEHAVIOR_OPTIONS.find(opt => opt.value === state.behavior) ?? BEHAVIOR_OPTIONS[0],\n [state.behavior],\n );\n\n const handleBehaviorChange = useCallback((item: BehaviorOption | null) => {\n if (item) {\n setState(prev => ({ ...prev, behavior: item.value as DisplayBehavior }));\n }\n }, []);\n\n const canSave = useMemo(() => {\n for (const group of state.groups) {\n for (const condition of group.conditions) {\n if (!condition.dataPointKey) {\n return false;\n }\n if (condition.operator === 'is_empty' || condition.operator === 'is_not_empty') {\n continue;\n }\n const trimmedValue = condition.value.trim();\n if (!trimmedValue) {\n return false;\n }\n const fieldType =\n dataPointOptions.find(opt => opt.fullKey === condition.dataPointKey)\n ?.fieldType ?? 'string';\n if (fieldType === 'number' && !NUMERIC_VALUE_RE.test(trimmedValue)) {\n return false;\n }\n }\n }\n return state.groups.length > 0;\n }, [dataPointOptions, state.groups]);\n\n if (!portalTarget || !isOpen) {\n return null;\n }\n\n return createPortal(\n <Dialog open={isOpen} onClose={handleClose} size=\"xlarge\">\n <Dialog.Header>Rules and Conditions</Dialog.Header>\n <Dialog.Content>\n <Flex\n direction=\"column\"\n gap=\"6\"\n style={{\n maxHeight: MODAL_CONTENT_MAX_HEIGHT,\n overflowY: 'auto',\n width: '100%',\n }}\n >\n <Flex\n direction=\"column\"\n gap=\"3\"\n style={{\n borderBottom: '1px solid #e0e0e0',\n paddingBottom: 16,\n }}\n >\n <Text size=\"medium\" variant=\"body\" style={{ fontWeight: 'bold' }}>\n When conditions are met:\n </Text>\n <Flex\n direction=\"row\"\n alignItems=\"center\"\n gap=\"3\"\n style={{ flexWrap: 'wrap' }}\n >\n <Text size=\"small\" subdued variant=\"body\">\n Select to show or hide selected component.\n </Text>\n <div style={{ width: 160 }}>\n <Combobox\n {...({ disableClearSelection: true } as object)}\n itemToKey={(item: BehaviorOption | null) => item?.value ?? ''}\n itemToString={(item: BehaviorOption | null) =>\n item?.label ?? ''\n }\n items={[...BEHAVIOR_OPTIONS]}\n selectedItem={selectedBehavior}\n onChange={handleBehaviorChange}\n >\n <Combobox.SelectTrigger\n label=\"Behavior\"\n placeholder=\"Select...\"\n />\n <Combobox.Content>\n {({ items }: { items: BehaviorOption[] }) => (\n <Combobox.List>\n {items.map((item, i) => (\n <Combobox.Item\n index={i}\n item={item}\n key={item.value}\n >\n {item.label}\n </Combobox.Item>\n ))}\n </Combobox.List>\n )}\n </Combobox.Content>\n </Combobox>\n </div>\n </Flex>\n </Flex>\n <ConditionGroupsSection\n dataPointOptions={dataPointOptions}\n groups={state.groups}\n onAddGroup={addGroup}\n onRemoveGroup={removeGroup}\n onUpdateGroup={updateGroup}\n />\n {!canSave && (\n <Text size=\"small\" subdued variant=\"body\">\n Complete each condition before saving. Data point and value are\n required, and numeric fields must contain a valid number.\n </Text>\n )}\n </Flex>\n </Dialog.Content>\n <Dialog.Footer sticky>\n <Dialog.CancelButton onClick={handleClose}>Cancel</Dialog.CancelButton>\n <Button appearance=\"primary\" disabled={!canSave} onClick={handleSave}>\n Save Changes\n </Button>\n </Dialog.Footer>\n </Dialog>,\n portalTarget,\n );\n};\n"],"names":["Button","Combobox","Dialog","Flex","Text","useCallback","useEffect","useMemo","useState","createPortal","ConditionGroupsSection","defaultGroup","defaultState","MODAL_CONTENT_MAX_HEIGHT","onDisplayCondition","buildUnlayerDisplayCondition","parseUnlayerDisplayCondition","getSchemaDataPointOptions","BEHAVIOR_OPTIONS","label","value","NUMERIC_VALUE_RE","DisplayConditionModal","props","request","setRequest","isOpen","setIsOpen","state","setState","dataPointOptions","schema","portalTarget","document","body","nextRequest","existing","data","parsed","handleClose","done","handleSave","condition","updateGroup","index","group","prev","next","groups","removeGroup","nextGroups","filter","_","i","length","logicalOperator","unusedOp","firstGroup","slice","addGroup","selectedBehavior","find","opt","behavior","handleBehaviorChange","item","canSave","conditions","dataPointKey","operator","trimmedValue","trim","fieldType","fullKey","test","open","onClose","size","Header","Content","direction","gap","style","maxHeight","overflowY","width","borderBottom","paddingBottom","variant","fontWeight","alignItems","flexWrap","subdued","div","disableClearSelection","itemToKey","itemToString","items","selectedItem","onChange","SelectTrigger","placeholder","List","map","Item","onAddGroup","onRemoveGroup","onUpdateGroup","Footer","sticky","CancelButton","onClick","appearance","disabled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/display-conditions/DisplayConditionModal.tsx"],"sourcesContent":["import { Button, Combobox, Dialog, Flex, Text } from '@servicetitan/anvil2';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ConditionGroupsSection } from './ConditionGroupsSection';\nimport { defaultGroup, defaultState, MODAL_CONTENT_MAX_HEIGHT } from './constants';\nimport { DisplayConditionRequest, onDisplayCondition } from './displayConditionController';\nimport { buildUnlayerDisplayCondition, parseUnlayerDisplayCondition } from './nunjucks';\nimport { getSchemaDataPointOptions } from './schemaDataPoints';\nimport { ConditionGroup as ConditionGroupType, DisplayBehavior } from './types';\n\nconst BEHAVIOR_OPTIONS = [\n { label: 'Show', value: 'show' },\n { label: 'Hide', value: 'hide' },\n] as const;\nconst NUMERIC_VALUE_RE = /^-?(?:\\d+\\.?\\d*|\\.\\d+)$/;\ntype BehaviorOption = (typeof BEHAVIOR_OPTIONS)[number];\n\nexport interface DisplayConditionModalProps {\n schema?: import('../shared/schema').SchemaObject;\n}\n\nexport const DisplayConditionModal = (props: DisplayConditionModalProps) => {\n const [request, setRequest] = useState<DisplayConditionRequest | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [state, setState] = useState(defaultState);\n\n const dataPointOptions = useMemo(() => getSchemaDataPointOptions(props.schema), [props.schema]);\n\n const portalTarget = useMemo(() => {\n if (typeof document === 'undefined') {\n return null;\n }\n return document.body;\n }, []);\n\n useEffect(() => {\n return onDisplayCondition(nextRequest => {\n setRequest(nextRequest);\n const existing = nextRequest.data;\n const parsed = parseUnlayerDisplayCondition(existing);\n setState(parsed ?? defaultState());\n setIsOpen(true);\n });\n }, []);\n\n const handleClose = useCallback(() => {\n setRequest(null);\n setIsOpen(false);\n }, []);\n\n const handleSave = useCallback(() => {\n if (!request) {\n return;\n }\n const condition = buildUnlayerDisplayCondition(state);\n if (condition) {\n request.done(condition);\n } else {\n request.done(null);\n }\n setRequest(null);\n setIsOpen(false);\n }, [request, state]);\n\n const updateGroup = useCallback((index: number, group: ConditionGroupType) => {\n setState(prev => {\n const next = [...prev.groups];\n next[index] = group;\n return { ...prev, groups: next };\n });\n }, []);\n\n const removeGroup = useCallback((index: number) => {\n setState(prev => ({\n ...prev,\n groups: (() => {\n const nextGroups = prev.groups.filter((_, i) => i !== index);\n if (nextGroups.length === 0) {\n return [defaultGroup()];\n }\n if (index === 0) {\n const { logicalOperator: unusedOp, ...firstGroup } = nextGroups[0];\n return [firstGroup, ...nextGroups.slice(1)];\n }\n return nextGroups;\n })(),\n }));\n }, []);\n\n const addGroup = useCallback(() => {\n setState(prev => ({\n ...prev,\n groups: [...prev.groups, { ...defaultGroup(), logicalOperator: 'and' }],\n }));\n }, []);\n\n const selectedBehavior = useMemo(\n () => BEHAVIOR_OPTIONS.find(opt => opt.value === state.behavior) ?? BEHAVIOR_OPTIONS[0],\n [state.behavior],\n );\n\n const handleBehaviorChange = useCallback((item: BehaviorOption | null) => {\n if (item) {\n setState(prev => ({ ...prev, behavior: item.value as DisplayBehavior }));\n }\n }, []);\n\n const canSave = useMemo(() => {\n for (const group of state.groups) {\n for (const condition of group.conditions) {\n if (!condition.dataPointKey) {\n return false;\n }\n if (condition.operator === 'is_empty' || condition.operator === 'is_not_empty') {\n continue;\n }\n const trimmedValue = condition.value.trim();\n if (!trimmedValue) {\n return false;\n }\n const fieldType =\n dataPointOptions.find(opt => opt.fullKey === condition.dataPointKey)\n ?.fieldType ?? 'string';\n if (fieldType === 'number' && !NUMERIC_VALUE_RE.test(trimmedValue)) {\n return false;\n }\n }\n }\n return state.groups.length > 0;\n }, [dataPointOptions, state.groups]);\n\n if (!portalTarget || !isOpen) {\n return null;\n }\n\n return createPortal(\n <Dialog open={isOpen} onClose={handleClose} size=\"xlarge\">\n <Dialog.Header>Rules and Conditions</Dialog.Header>\n <Dialog.Content>\n <Flex\n direction=\"column\"\n gap=\"6\"\n style={{\n maxHeight: MODAL_CONTENT_MAX_HEIGHT,\n overflowY: 'auto',\n paddingRight: 8,\n width: '100%',\n }}\n >\n <Flex\n direction=\"column\"\n gap=\"3\"\n style={{\n borderBottom: '1px solid #e0e0e0',\n paddingBottom: 16,\n }}\n >\n <Text size=\"medium\" variant=\"body\" style={{ fontWeight: 'bold' }}>\n When conditions are met:\n </Text>\n <Flex\n direction=\"row\"\n alignItems=\"flex-end\"\n gap=\"3\"\n style={{ flexWrap: 'wrap' }}\n >\n <Text size=\"small\" subdued variant=\"body\" style={{ paddingBottom: 10 }}>\n Select to show or hide selected component.\n </Text>\n <div style={{ width: 160 }}>\n <Combobox.Select\n {...({ disableClearSelection: true } as object)}\n itemToKey={(item: BehaviorOption | null) => item?.value ?? ''}\n itemToString={(item: BehaviorOption | null) =>\n item?.label ?? ''\n }\n items={[...BEHAVIOR_OPTIONS]}\n selectedItem={selectedBehavior}\n onChange={handleBehaviorChange}\n >\n <Combobox.SelectTrigger label=\"\" placeholder=\"Select...\" />\n <Combobox.Content>\n {({ items }: { items: BehaviorOption[] }) => (\n <Combobox.List>\n {items.map((item, i) => (\n <Combobox.Item\n index={i}\n item={item}\n key={item.value}\n >\n {item.label}\n </Combobox.Item>\n ))}\n </Combobox.List>\n )}\n </Combobox.Content>\n </Combobox.Select>\n </div>\n </Flex>\n </Flex>\n <div style={{ padding: 8 }}>\n <ConditionGroupsSection\n dataPointOptions={dataPointOptions}\n groups={state.groups}\n onAddGroup={addGroup}\n onRemoveGroup={removeGroup}\n onUpdateGroup={updateGroup}\n />\n </div>\n </Flex>\n </Dialog.Content>\n <Dialog.Footer sticky>\n <Flex\n justifyContent=\"flex-end\"\n alignItems=\"center\"\n gap=\"3\"\n style={{ width: '100%' }}\n >\n <Button appearance=\"secondary\" onClick={handleClose}>\n Cancel\n </Button>\n <Button appearance=\"primary\" disabled={!canSave} onClick={handleSave}>\n Save Changes\n </Button>\n </Flex>\n </Dialog.Footer>\n </Dialog>,\n portalTarget,\n );\n};\n"],"names":["Button","Combobox","Dialog","Flex","Text","useCallback","useEffect","useMemo","useState","createPortal","ConditionGroupsSection","defaultGroup","defaultState","MODAL_CONTENT_MAX_HEIGHT","onDisplayCondition","buildUnlayerDisplayCondition","parseUnlayerDisplayCondition","getSchemaDataPointOptions","BEHAVIOR_OPTIONS","label","value","NUMERIC_VALUE_RE","DisplayConditionModal","props","request","setRequest","isOpen","setIsOpen","state","setState","dataPointOptions","schema","portalTarget","document","body","nextRequest","existing","data","parsed","handleClose","handleSave","condition","done","updateGroup","index","group","prev","next","groups","removeGroup","nextGroups","filter","_","i","length","logicalOperator","unusedOp","firstGroup","slice","addGroup","selectedBehavior","find","opt","behavior","handleBehaviorChange","item","canSave","conditions","dataPointKey","operator","trimmedValue","trim","fieldType","fullKey","test","open","onClose","size","Header","Content","direction","gap","style","maxHeight","overflowY","paddingRight","width","borderBottom","paddingBottom","variant","fontWeight","alignItems","flexWrap","subdued","div","Select","disableClearSelection","itemToKey","itemToString","items","selectedItem","onChange","SelectTrigger","placeholder","List","map","Item","padding","onAddGroup","onRemoveGroup","onUpdateGroup","Footer","sticky","justifyContent","appearance","onClick","disabled"],"mappings":"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"}
|