@olenbetong/appframe-ds 0.8.0 → 0.9.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/CHANGELOG.md +70 -0
- package/package.json +50 -6
- package/scripts/copyAssets.mjs +13 -0
- package/src/AfLookup/LookupCombobox.tsx +3 -1
- package/src/filter/ChipListInput.tsx +79 -0
- package/src/filter/FieldFilterPanel.css +127 -0
- package/src/filter/FieldFilterPanel.tsx +309 -0
- package/src/filter/FilterBuilder.css +152 -0
- package/src/filter/FilterBuilder.test.tsx +153 -0
- package/src/filter/FilterBuilder.tsx +435 -0
- package/src/filter/FilterEditor.css +231 -0
- package/src/filter/FilterEditor.test.tsx +259 -0
- package/src/filter/FilterEditor.tsx +74 -0
- package/src/filter/FilterGroupEditor.tsx +160 -0
- package/src/filter/FilterNameDialog.css +22 -0
- package/src/filter/FilterNameDialog.tsx +81 -0
- package/src/filter/FilterRow.tsx +117 -0
- package/src/filter/FilterShareDialog.css +28 -0
- package/src/filter/FilterShareDialog.tsx +201 -0
- package/src/filter/FilterStringField.tsx +77 -0
- package/src/filter/FilterValueEditor.tsx +220 -0
- package/src/filter/SavedFilterTree.css +107 -0
- package/src/filter/SavedFilterTree.test.tsx +94 -0
- package/src/filter/SavedFilterTree.tsx +222 -0
- package/src/filter/fieldFilter.test.ts +158 -0
- package/src/filter/fieldFilter.ts +139 -0
- package/src/filter/index.ts +27 -0
- package/src/filter/types.ts +38 -0
- package/src/filter/useDistinctValues.test.ts +102 -0
- package/src/filter/useDistinctValues.ts +230 -0
- package/src/global.d.ts +11 -0
- package/src/grid/AfGridColumnsPanel.tsx +118 -0
- package/src/grid/AfGridContext.tsx +51 -0
- package/src/grid/AfGridError.tsx +46 -0
- package/src/grid/AfHeaderFilterCell.tsx +151 -0
- package/src/grid/AfHeaderFilterPanel.tsx +111 -0
- package/src/grid/Toolbar.tsx +233 -0
- package/src/grid/editing.ts +90 -0
- package/src/grid/filter.ts +78 -0
- package/src/grid/formatters.ts +48 -0
- package/src/grid/index.css +187 -0
- package/src/grid/index.tsx +376 -0
- package/src/grid/license.ts +48 -0
- package/src/grid/localization.ts +369 -0
- package/src/grid/slots/index.tsx +275 -0
- package/src/grid/slots/slots.css +53 -0
- package/src/grid/theme.tsx +185 -0
- package/src/grid/useAfColumns.tsx +313 -0
- package/src/grid/useAfCurrentIndex.ts +55 -0
- package/src/grid/useAfData.ts +20 -0
- package/src/grid/useAfFilter.ts +160 -0
- package/src/grid/useAfFilterFields.ts +55 -0
- package/src/grid/useAfGridApi.ts +66 -0
- package/src/grid/useAfKeyBindings.ts +36 -0
- package/src/grid/useAfPagination.ts +53 -0
- package/src/grid/useAfPersistedState.ts +222 -0
- package/src/grid/useAfRowEditModel.ts +137 -0
- package/src/grid/useAfSortModel.ts +72 -0
- package/src/index.ts +1 -0
- package/src/input/InputAdornments.tsx +6 -1
- package/src/report-downloader/ReportDownloader.css +67 -0
- package/src/report-downloader/components/StatusItem.tsx +86 -0
- package/src/report-downloader/components/StatusList.tsx +28 -0
- package/src/report-downloader/index.ts +41 -0
- package/src/report-downloader/status.tsx +92 -0
- package/src/test/setup.ts +8 -0
- package/vitest.config.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,75 @@
|
|
|
1
1
|
# @olenbetong/appframe-ds
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- cfc94c7: Rework the `AfGrid` header filter, and stop the toolbar refresh button from shifting while loading.
|
|
8
|
+
|
|
9
|
+
The header filters and the toolbar's filter builder now edit **one** filter tree in a single named
|
|
10
|
+
filter slot keyed on the grid `id`, instead of writing two slots that could not see each other. MUI's
|
|
11
|
+
`GridFilterModel` is no longer used as a transport — it cannot represent nested groups or the full
|
|
12
|
+
Appframe operator set. `useAfFilterModel` is replaced by `useAfFilter`, which exposes the tree plus
|
|
13
|
+
per-field helpers.
|
|
14
|
+
|
|
15
|
+
Each header filter cell is now an unlabelled input with a funnel button:
|
|
16
|
+
- one criterion taking a single value is edited straight from the input, debounced,
|
|
17
|
+
- anything else shows a read-only summary such as `In list (3)`, with a clear button,
|
|
18
|
+
- the funnel opens a per-column panel with a row per criterion, a `+ Criteria` button, and — for
|
|
19
|
+
string, number and uniqueidentifier columns — a searchable list of the column's distinct values
|
|
20
|
+
with row counts, checked to build an `in list` criterion.
|
|
21
|
+
|
|
22
|
+
The distinct list respects every other active filter but ignores the column's own criteria, so
|
|
23
|
+
unchecking a value does not make the remaining values disappear. Counts are best effort: views that
|
|
24
|
+
cannot be grouped fall back to a plain distinct list. Panel edits are staged and only applied on
|
|
25
|
+
`Apply`, so a half-built criterion never reaches the server.
|
|
26
|
+
|
|
27
|
+
`GridToolbarRefreshButton` now hides its icon while loading so the spinner replaces it instead of
|
|
28
|
+
being added next to it, and the columns panel has spacing between its search field and the column
|
|
29
|
+
list. `InputAdornments` accepts a `ref`, which is forwarded to the input element.
|
|
30
|
+
|
|
31
|
+
The panel body is exported on its own as **`FieldFilterPanel`**, a controlled component with no
|
|
32
|
+
dependency on the grid, so a single field can be filtered anywhere — a report parameter, a sidebar
|
|
33
|
+
facet, a mobile filter sheet. Its distinct value query is exported too, as `useDistinctValues`.
|
|
34
|
+
|
|
35
|
+
The header filter input no longer drives MUI's header filter edit mode from `onFocus`/`onBlur`. The
|
|
36
|
+
header filter cell refocuses itself whenever that state changes, so any mousedown leaving the input
|
|
37
|
+
pulled focus straight back in — inputs in the filter panel could not be focused, and starting a
|
|
38
|
+
column drag from a header cancelled the drag. Nothing is lost: MUI focuses the cell's focusable
|
|
39
|
+
element anyway, so typing and keyboard navigation still work.
|
|
40
|
+
|
|
41
|
+
- cfc94c7: Add `@olenbetong/appframe-ds/grid`, a Designsystemet flavoured `AfGrid`.
|
|
42
|
+
|
|
43
|
+
The grid keeps MUI X Data Grid Pro as its engine — Designsystemet has no data grid — but replaces
|
|
44
|
+
the chrome:
|
|
45
|
+
- the base slots (checkbox, button, icon button, text field, select, switch, tooltip, chip, badge,
|
|
46
|
+
progress, skeleton, divider) render Designsystemet components,
|
|
47
|
+
- the toolbar and the column panel are rebuilt with Designsystemet components and Aksel icons,
|
|
48
|
+
- the filter panel is replaced by `FilterBuilder` in dialog mode,
|
|
49
|
+
- the MUI theme is derived from the `--ds-color-*` tokens and follows `data-color-scheme`, so the
|
|
50
|
+
grid works in light and dark mode without an app-level `ThemeProvider`,
|
|
51
|
+
- the MUI X license is registered by the grid itself, from a build-time injected
|
|
52
|
+
`__MUI_X_LICENSE_KEY__` (supplied by the `appframe()` Vite plugin) or
|
|
53
|
+
`import.meta.env.VITE_MUI_X_LICENSE_KEY`.
|
|
54
|
+
|
|
55
|
+
The API matches the `@olenbetong/appframe-mui` `AfGrid`, so migrating is an import path change plus
|
|
56
|
+
an optional `filterViewName` for saved filters. Layout persistence uses the same store, so users
|
|
57
|
+
keep their saved column layouts.
|
|
58
|
+
|
|
59
|
+
The filter builder (`FilterBuilder`, `FilterEditor`, `SavedFilterTree`, …) moved here from
|
|
60
|
+
`@olenbetong/synergi-react` and is exported from the package root.
|
|
61
|
+
|
|
62
|
+
`ReportDownloader` (`openDataObjectReportWithProgress`) is available from
|
|
63
|
+
`@olenbetong/appframe-ds/report-downloader`, built with Designsystemet components.
|
|
64
|
+
|
|
65
|
+
### Patch Changes
|
|
66
|
+
|
|
67
|
+
- Updated dependencies [62a0ad5]
|
|
68
|
+
- Updated dependencies [5155cdb]
|
|
69
|
+
- @olenbetong/appframe-data@1.6.1
|
|
70
|
+
- @olenbetong/appframe-core@2.13.0
|
|
71
|
+
- @olenbetong/appframe-react@2.1.1
|
|
72
|
+
|
|
3
73
|
## 0.8.0
|
|
4
74
|
|
|
5
75
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-ds",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Components that bind Designsystemet components to Appframe data objects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./es/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
+
"types": "./es/index.d.ts",
|
|
9
10
|
"import": "./es/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./grid": {
|
|
13
|
+
"types": "./es/grid/index.d.ts",
|
|
14
|
+
"import": "./es/grid/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./report-downloader": {
|
|
17
|
+
"types": "./es/report-downloader/index.d.ts",
|
|
18
|
+
"import": "./es/report-downloader/index.js"
|
|
10
19
|
}
|
|
11
20
|
},
|
|
12
21
|
"sideEffects": [
|
|
@@ -16,29 +25,63 @@
|
|
|
16
25
|
"license": "MIT",
|
|
17
26
|
"peerDependencies": {
|
|
18
27
|
"@digdir/designsystemet-react": ">=1.18.0",
|
|
28
|
+
"@emotion/react": ">=11.14.0",
|
|
29
|
+
"@emotion/styled": ">=11.14.1",
|
|
30
|
+
"@mui/material": ">=9.0.0",
|
|
31
|
+
"@mui/x-data-grid-pro": ">=8.0.0 <9.0.0",
|
|
32
|
+
"@mui/x-license": ">=8.0.0 <9.0.0",
|
|
19
33
|
"@navikt/aksel-icons": ">=8.16.1",
|
|
20
34
|
"react": ">=19.2.8",
|
|
21
35
|
"react-dom": ">=19.2.8",
|
|
22
36
|
"react-error-boundary": ">=6.1.2",
|
|
23
37
|
"react-router": ">=8.3.0"
|
|
24
38
|
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"@emotion/react": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"@emotion/styled": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"@mui/material": {
|
|
47
|
+
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"@mui/x-data-grid-pro": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"@mui/x-license": {
|
|
53
|
+
"optional": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
25
56
|
"dependencies": {
|
|
26
57
|
"@atlaskit/pragmatic-drag-and-drop": "2.0.2",
|
|
27
58
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "2.0.0",
|
|
28
59
|
"@base-ui/react": "1.7.0",
|
|
29
60
|
"clsx": "^2.1.1",
|
|
61
|
+
"localforage": "^1.10.0",
|
|
62
|
+
"mitt": "^3.0.1",
|
|
30
63
|
"react-virtualized-auto-sizer": "^1.0.26",
|
|
31
64
|
"react-window": "^1.8.11",
|
|
32
|
-
"@olenbetong/appframe-
|
|
33
|
-
"@olenbetong/appframe-
|
|
34
|
-
"@olenbetong/appframe-
|
|
65
|
+
"@olenbetong/appframe-core": "2.13.0",
|
|
66
|
+
"@olenbetong/appframe-react": "2.1.1",
|
|
67
|
+
"@olenbetong/appframe-data": "1.6.1"
|
|
35
68
|
},
|
|
36
69
|
"devDependencies": {
|
|
37
70
|
"@digdir/designsystemet-react": "1.18.0",
|
|
71
|
+
"@emotion/react": "^11.14.0",
|
|
72
|
+
"@emotion/styled": "^11.14.1",
|
|
73
|
+
"@mui/material": "9.3.1",
|
|
74
|
+
"@mui/x-data-grid-pro": "8.29.2",
|
|
75
|
+
"@mui/x-license": "8.29.2",
|
|
38
76
|
"@navikt/aksel-icons": "8.16.1",
|
|
77
|
+
"@testing-library/dom": "^10.4.1",
|
|
78
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
79
|
+
"@testing-library/react": "16.3.2",
|
|
80
|
+
"@testing-library/user-event": "^14.6.3",
|
|
39
81
|
"@types/react": "19.2.18",
|
|
40
82
|
"@types/react-dom": "19.2.4",
|
|
41
83
|
"@types/react-window": "^1.8.8",
|
|
84
|
+
"happy-dom": "^20.11.1",
|
|
42
85
|
"react": "19.2.8",
|
|
43
86
|
"react-dom": "19.2.8",
|
|
44
87
|
"react-error-boundary": "6.1.2",
|
|
@@ -46,8 +89,9 @@
|
|
|
46
89
|
"typescript": "7.0.2"
|
|
47
90
|
},
|
|
48
91
|
"scripts": {
|
|
49
|
-
"build": "pnpm run build:tsc && pnpm run build:css",
|
|
92
|
+
"build": "pnpm run build:tsc && pnpm test && pnpm run build:css",
|
|
50
93
|
"build:tsc": "node --no-warnings ../../scripts/clean.ts ./es tsconfig.build.tsbuildinfo && tsc -p tsconfig.build.json",
|
|
51
|
-
"build:css": "node scripts/copyAssets.mjs"
|
|
94
|
+
"build:css": "node scripts/copyAssets.mjs",
|
|
95
|
+
"test": "vitest run"
|
|
52
96
|
}
|
|
53
97
|
}
|
package/scripts/copyAssets.mjs
CHANGED
|
@@ -22,6 +22,15 @@ const files = [
|
|
|
22
22
|
["src/sortable/DropIndicator.css", "es/sortable/DropIndicator.css"],
|
|
23
23
|
["src/sortable/SortableItemList.css", "es/sortable/SortableItemList.css"],
|
|
24
24
|
["src/autocomplete/Autocomplete.css", "es/autocomplete/Autocomplete.css"],
|
|
25
|
+
["src/filter/FilterBuilder.css", "es/filter/FilterBuilder.css"],
|
|
26
|
+
["src/filter/FieldFilterPanel.css", "es/filter/FieldFilterPanel.css"],
|
|
27
|
+
["src/filter/FilterEditor.css", "es/filter/FilterEditor.css"],
|
|
28
|
+
["src/filter/FilterNameDialog.css", "es/filter/FilterNameDialog.css"],
|
|
29
|
+
["src/filter/FilterShareDialog.css", "es/filter/FilterShareDialog.css"],
|
|
30
|
+
["src/filter/SavedFilterTree.css", "es/filter/SavedFilterTree.css"],
|
|
31
|
+
["src/grid/index.css", "es/grid/index.css"],
|
|
32
|
+
["src/grid/slots/slots.css", "es/grid/slots/slots.css"],
|
|
33
|
+
["src/report-downloader/ReportDownloader.css", "es/report-downloader/ReportDownloader.css"],
|
|
25
34
|
];
|
|
26
35
|
|
|
27
36
|
mkdirSync("es/layout", { recursive: true });
|
|
@@ -32,6 +41,10 @@ mkdirSync("es/paper", { recursive: true });
|
|
|
32
41
|
mkdirSync("es/progress", { recursive: true });
|
|
33
42
|
mkdirSync("es/sortable", { recursive: true });
|
|
34
43
|
mkdirSync("es/autocomplete", { recursive: true });
|
|
44
|
+
mkdirSync("es/filter", { recursive: true });
|
|
45
|
+
mkdirSync("es/grid", { recursive: true });
|
|
46
|
+
mkdirSync("es/grid/slots", { recursive: true });
|
|
47
|
+
mkdirSync("es/report-downloader", { recursive: true });
|
|
35
48
|
|
|
36
49
|
for (let [src, dest] of files) {
|
|
37
50
|
cpSync(src, dest);
|
|
@@ -39,7 +39,9 @@ export interface LookupComboboxGridProps<T extends Record<string, unknown>> exte
|
|
|
39
39
|
columns: LookupColumn<T>[];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
export type LookupComboboxProps<T extends Record<string, unknown>> =
|
|
42
|
+
export type LookupComboboxProps<T extends Record<string, unknown>> =
|
|
43
|
+
| LookupComboboxListProps<T>
|
|
44
|
+
| LookupComboboxGridProps<T>;
|
|
43
45
|
|
|
44
46
|
export function LookupCombobox<T extends Record<string, unknown>>(props: LookupComboboxProps<T>) {
|
|
45
47
|
let {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ChipRemovable, Textfield } from "@digdir/designsystemet-react";
|
|
2
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
|
|
5
|
+
export type ChipListInputProps = {
|
|
6
|
+
value: string[];
|
|
7
|
+
onChange: (value: string[]) => void;
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
"aria-label": string;
|
|
10
|
+
"data-size"?: "sm" | "md" | "lg";
|
|
11
|
+
type?: "text" | "number" | "date" | "datetime-local";
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Free text editor for the list operators. Values are added with Enter and
|
|
16
|
+
* rendered as removable chips.
|
|
17
|
+
*/
|
|
18
|
+
export function ChipListInput({
|
|
19
|
+
value,
|
|
20
|
+
onChange,
|
|
21
|
+
readOnly,
|
|
22
|
+
type = "text",
|
|
23
|
+
"aria-label": ariaLabel,
|
|
24
|
+
"data-size": size,
|
|
25
|
+
}: ChipListInputProps) {
|
|
26
|
+
let [draft, setDraft] = useState("");
|
|
27
|
+
|
|
28
|
+
function commit() {
|
|
29
|
+
let trimmed = draft.trim();
|
|
30
|
+
if (!trimmed || value.includes(trimmed)) {
|
|
31
|
+
setDraft("");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onChange([...value, trimmed]);
|
|
36
|
+
setDraft("");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
|
|
40
|
+
if (event.key === "Enter") {
|
|
41
|
+
// The editor is often rendered inside a dialog; committing a value
|
|
42
|
+
// must not submit or close it.
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
commit();
|
|
45
|
+
} else if (event.key === "Backspace" && draft === "" && value.length > 0) {
|
|
46
|
+
onChange(value.slice(0, -1));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="ObFilterEditor-chipList">
|
|
52
|
+
{value.map((item, index) => (
|
|
53
|
+
<ChipRemovable
|
|
54
|
+
// Values are deduplicated on add, so the value is a stable key.
|
|
55
|
+
key={item}
|
|
56
|
+
data-size={size}
|
|
57
|
+
disabled={readOnly}
|
|
58
|
+
aria-label={`${getLocalizedString("Remove")} ${item}`}
|
|
59
|
+
onClick={() => onChange(value.filter((_, i) => i !== index))}
|
|
60
|
+
>
|
|
61
|
+
{item}
|
|
62
|
+
</ChipRemovable>
|
|
63
|
+
))}
|
|
64
|
+
{!readOnly && (
|
|
65
|
+
<Textfield
|
|
66
|
+
className="ObFilterEditor-chipListInput"
|
|
67
|
+
aria-label={ariaLabel}
|
|
68
|
+
data-size={size}
|
|
69
|
+
type={type}
|
|
70
|
+
value={draft}
|
|
71
|
+
placeholder={getLocalizedString("Add value")}
|
|
72
|
+
onChange={(event) => setDraft(event.target.value)}
|
|
73
|
+
onKeyDown={handleKeyDown}
|
|
74
|
+
onBlur={commit}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
.ObFieldFilterPanel-root {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: var(--ds-size-3, 0.75rem);
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* The panel is sized by whatever it is put in — a popover, a dialog, a
|
|
8
|
+
* sidebar. It fills that container and lets the distinct list take up the
|
|
9
|
+
* slack, so the list grows and shrinks with the container instead of
|
|
10
|
+
* carrying a height of its own.
|
|
11
|
+
*/
|
|
12
|
+
block-size: 100%;
|
|
13
|
+
min-block-size: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.ObFieldFilterPanel-heading {
|
|
17
|
+
font-weight: var(--ds-font-weight-medium, 500);
|
|
18
|
+
color: var(--ds-color-neutral-text-default);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ObFieldFilterPanel-criteria {
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
flex: 0 0 auto;
|
|
25
|
+
gap: var(--ds-size-2, 0.5rem);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ObFieldFilterPanel-criterion {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
gap: var(--ds-size-1, 0.25rem);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* The filter editor's value cell is written for the filter builder's horizontal
|
|
36
|
+
* rows, where growing is what makes it fill the row. Stacked vertically that
|
|
37
|
+
* same `flex-grow` makes it stretch to fill the whole panel instead.
|
|
38
|
+
*/
|
|
39
|
+
.ObFieldFilterPanel-criterion > .ObFilterEditor-valueCell {
|
|
40
|
+
flex: 0 0 auto;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ObFieldFilterPanel-distinct {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
flex: 1 1 auto;
|
|
47
|
+
gap: var(--ds-size-2, 0.5rem);
|
|
48
|
+
min-block-size: 0;
|
|
49
|
+
padding-block-start: var(--ds-size-2, 0.5rem);
|
|
50
|
+
border-block-start: var(--ds-border-width-default, 1px) solid var(--ds-color-neutral-border-subtle, #e7e7e7);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ObFieldFilterPanel-distinctToolbar {
|
|
54
|
+
display: flex;
|
|
55
|
+
flex: 0 0 auto;
|
|
56
|
+
gap: var(--ds-size-1, 0.25rem);
|
|
57
|
+
align-items: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.ObFieldFilterPanel-distinctToolbar .ds-search {
|
|
61
|
+
flex: 1;
|
|
62
|
+
min-inline-size: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* The active sort is held down, so it is clear which of the two is in effect.
|
|
67
|
+
* Neutral tokens rather than accent ones: the accent scale is only defined
|
|
68
|
+
* inside a `data-color` scope, and the panel can be dropped anywhere.
|
|
69
|
+
*/
|
|
70
|
+
.ObFieldFilterPanel-distinctToolbar .ds-button[aria-pressed="true"] {
|
|
71
|
+
color: var(--ds-color-neutral-text-default, #292c30);
|
|
72
|
+
background: var(--ds-color-neutral-surface-active, #c9cacb);
|
|
73
|
+
box-shadow: inset 0 0 0 var(--ds-border-width-default, 1px) var(--ds-color-neutral-border-subtle, #e7e7e7);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* Both the list and the spinner that replaces it while loading use this box, so
|
|
78
|
+
* the panel does not jump when the values arrive. It is the part that takes up
|
|
79
|
+
* whatever room the container has left, and it never collapses to nothing.
|
|
80
|
+
*/
|
|
81
|
+
.ObFieldFilterPanel-valuesBox {
|
|
82
|
+
flex: 1 1 auto;
|
|
83
|
+
min-block-size: 8rem;
|
|
84
|
+
border: var(--ds-border-width-default, 1px) solid var(--ds-color-neutral-border-subtle, #e7e7e7);
|
|
85
|
+
border-radius: var(--ds-border-radius-md, 0.25rem);
|
|
86
|
+
background: var(--ds-color-neutral-surface-tinted, rgb(0 0 0 / 2%));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ObFieldFilterPanel-values {
|
|
90
|
+
display: flex;
|
|
91
|
+
flex-direction: column;
|
|
92
|
+
gap: var(--ds-size-1, 0.25rem);
|
|
93
|
+
margin: 0;
|
|
94
|
+
padding: var(--ds-size-1, 0.25rem);
|
|
95
|
+
overflow-y: auto;
|
|
96
|
+
list-style: none;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.ObFieldFilterPanel-value {
|
|
100
|
+
padding-inline: var(--ds-size-1, 0.25rem);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.ObFieldFilterPanel-loading {
|
|
104
|
+
display: flex;
|
|
105
|
+
align-items: center;
|
|
106
|
+
justify-content: center;
|
|
107
|
+
padding: var(--ds-size-4, 1rem);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.ObFieldFilterPanel-error {
|
|
111
|
+
margin: 0;
|
|
112
|
+
color: var(--ds-color-danger-text-default);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.ObFieldFilterPanel-hint {
|
|
116
|
+
margin: 0;
|
|
117
|
+
flex: 0 0 auto;
|
|
118
|
+
font-size: var(--ds-font-size-1, 0.75rem);
|
|
119
|
+
color: var(--ds-color-neutral-text-subtle, #68707c);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.ObFieldFilterPanel-actions {
|
|
123
|
+
display: flex;
|
|
124
|
+
flex: 0 0 auto;
|
|
125
|
+
gap: var(--ds-size-2, 0.5rem);
|
|
126
|
+
justify-content: flex-end;
|
|
127
|
+
}
|