@olenbetong/appframe-ds 0.5.0 → 0.7.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +11 -9
  3. package/scripts/copyAssets.mjs +10 -1
  4. package/src/AfLookup/Lookup.tsx +7 -8
  5. package/src/AfLookup/{Combobox.tsx → LookupCombobox.tsx} +8 -8
  6. package/src/AfLookup/LookupEdit.tsx +5 -6
  7. package/src/AfLookup/index.ts +1 -1
  8. package/src/autocomplete/Autocomplete.css +222 -0
  9. package/src/autocomplete/Autocomplete.tsx +316 -0
  10. package/src/autocomplete/AutocompleteFrame.tsx +149 -0
  11. package/src/autocomplete/Combobox.tsx +260 -0
  12. package/src/autocomplete/index.ts +4 -0
  13. package/src/autocomplete/types.ts +200 -0
  14. package/src/autocomplete/utils.ts +183 -0
  15. package/src/binding/CancelButton.tsx +4 -1
  16. package/src/binding/CancelIconButton.tsx +2 -2
  17. package/src/binding/DataEditToolbar.tsx +1 -2
  18. package/src/binding/DeleteButton.tsx +6 -2
  19. package/src/binding/DeleteIconButton.tsx +5 -4
  20. package/src/binding/RefreshButton.tsx +7 -3
  21. package/src/binding/RefreshIconButton.tsx +6 -5
  22. package/src/binding/RefreshRowIconButton.tsx +6 -5
  23. package/src/binding/SaveButton.tsx +14 -4
  24. package/src/binding/SaveIconButton.tsx +13 -6
  25. package/src/index.ts +4 -0
  26. package/src/input/InputAdornments.css +75 -0
  27. package/src/input/InputAdornments.tsx +97 -0
  28. package/src/input/index.ts +1 -0
  29. package/src/progress/LinearProgress.css +93 -0
  30. package/src/progress/LinearProgress.tsx +104 -0
  31. package/src/progress/index.ts +1 -0
  32. package/src/sortable/DropIndicator.css +51 -0
  33. package/src/sortable/DropIndicator.tsx +27 -0
  34. package/src/sortable/SortableItemList.css +21 -0
  35. package/src/sortable/SortableItemList.tsx +264 -0
  36. package/src/sortable/index.ts +8 -0
  37. package/src/sortable/reorderSortOrder.ts +126 -0
  38. package/src/sortable/sortOrder.ts +101 -0
  39. package/src/sortable/types.ts +9 -0
  40. package/src/sortable/useSortableContainer.ts +53 -0
  41. package/src/sortable/useSortableItem.ts +95 -0
  42. package/src/sortable/useSortableList.ts +117 -0
  43. /package/src/AfLookup/{Combobox.css → LookupCombobox.css} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @olenbetong/appframe-ds
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 52e2e10: Add `Autocomplete` and `Combobox`, built on the Base UI components of the same name and styled with Designsystemet tokens. Both expose an API close to MUI's `Autocomplete` (`options`, `value`/`onChange`, `inputValue`/`onInputChange`, `getOptionLabel`, `isOptionEqualToValue`, `filterOptions`, `renderOption`, `groupBy`, `multiple`), plus Designsystemet field props (`label`, `description`, `error`, `data-size`). Use `Combobox` when the user must pick one of the options and `Autocomplete` when free text is allowed (`freeSolo`). Multiple selection renders the selected options as chips above the input, like Designsystemet's `Suggestion`. `createFilterOptions` is exported for custom filtering.
8
+
9
+ **Breaking:** the data object bound `Combobox` used internally by `AfLookup` is renamed to `LookupCombobox` (`ComboboxProps` → `LookupComboboxProps`) to free up the `Combobox` name.
10
+
11
+ - 77e96aa: Add `SortableItemList`, an `ItemList` variant bound to a data object where items can be reordered by dragging or through a menu on the drag handle. The building blocks are exported as well (`useSortableList`, `useSortableItem`, `useSortableContainer`, `DropIndicator`, `reorderSortOrder`, `getNextSortOrder`, `ensureNonZeroSortOrder`) for lists that need custom item markup.
12
+
13
+ ## 0.6.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 0147e80: Add `LinearProgress` component: a designsystemet-styled linear progress bar equivalent to MUI `LinearProgress`, with indeterminate and determinate modes and an `overlay` prop for an absolutely positioned bar that does not affect the layout.
18
+ - 56080ed: Add `InputAdornments` and `InputSlot`: an input with adornments (MUI `TextField` start/end adornment equivalent) where the border, background, hover and focus styling lives on a wrapper around the input and its adornments. Adornments are passed as children, and `InputSlot` controls where the input is placed (defaults to the start).
19
+ - bc89c1e: Migrated all icons in appframe-ds from `@mui/icons-material` to `@navikt/aksel-icons`. Bound action buttons (`SaveButton`, `DeleteButton`, `CancelButton`, `RefreshButton` and their icon-only variants) now show a leading icon that is hidden while loading, so button width no longer changes when toggling the loading state. `SaveButton` and `SaveIconButton` also display a small warning badge on the save icon when the current record has unsaved changes, matching the existing appframe-mui behavior.
20
+
21
+ ### Patch Changes
22
+
23
+ - 0147e80: Make the indeterminate `LinearProgress` animation more visible by using a single travelling bar that stretches and shrinks, instead of the two subtle MUI-style bars.
24
+
3
25
  ## 0.5.0
4
26
 
5
27
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olenbetong/appframe-ds",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Components that bind Designsystemet components to Appframe data objects",
5
5
  "type": "module",
6
6
  "types": "./es/index.d.ts",
@@ -16,25 +16,28 @@
16
16
  "license": "MIT",
17
17
  "peerDependencies": {
18
18
  "@digdir/designsystemet-react": ">=1.18.0",
19
- "@mui/icons-material": ">=7.0.0",
19
+ "@navikt/aksel-icons": ">=8.16.1",
20
20
  "react": ">=19.2.8",
21
21
  "react-dom": ">=19.2.8",
22
22
  "react-error-boundary": ">=6.1.2",
23
23
  "react-router": ">=8.3.0"
24
24
  },
25
25
  "dependencies": {
26
+ "@atlaskit/pragmatic-drag-and-drop": "2.0.1",
27
+ "@atlaskit/pragmatic-drag-and-drop-hitbox": "2.0.0",
28
+ "@base-ui/react": "1.7.0",
26
29
  "@olenbetong/appframe-core": "2.11.10",
27
30
  "@olenbetong/appframe-data": "1.5.0",
28
- "@olenbetong/appframe-react": "1.23.0",
29
- "react-window": "^1.8.11",
31
+ "@olenbetong/appframe-react": "2.0.0",
32
+ "clsx": "^2.1.1",
30
33
  "react-virtualized-auto-sizer": "^1.0.26",
31
- "clsx": "^2.1.1"
34
+ "react-window": "^1.8.11"
32
35
  },
33
36
  "devDependencies": {
34
37
  "@digdir/designsystemet-react": "1.18.0",
35
- "@mui/icons-material": "9.2.0",
36
- "@types/react": "19.2.17",
37
- "@types/react-dom": "19.2.3",
38
+ "@navikt/aksel-icons": "8.16.1",
39
+ "@types/react": "19.2.18",
40
+ "@types/react-dom": "19.2.4",
38
41
  "@types/react-window": "^1.8.8",
39
42
  "react": "19.2.8",
40
43
  "react-dom": "19.2.8",
@@ -42,7 +45,6 @@
42
45
  "react-router": "8.3.0",
43
46
  "typescript": "7.0.2"
44
47
  },
45
- "optionalDependencies": {},
46
48
  "scripts": {
47
49
  "build": "pnpm run build:tsc && pnpm run build:css",
48
50
  "build:tsc": "node --no-warnings ../../scripts/clean.ts ./es tsconfig.build.tsbuildinfo && tsc -p tsconfig.build.json",
@@ -3,7 +3,7 @@ import { cpSync, mkdirSync } from "node:fs";
3
3
  const files = [
4
4
  ["src/AfLookup/Lookup.css", "es/AfLookup/Lookup.css"],
5
5
  ["src/AfLookup/LookupGrid.css", "es/AfLookup/LookupGrid.css"],
6
- ["src/AfLookup/Combobox.css", "es/AfLookup/Combobox.css"],
6
+ ["src/AfLookup/LookupCombobox.css", "es/AfLookup/LookupCombobox.css"],
7
7
  ["src/layout/AppMenu.css", "es/layout/AppMenu.css"],
8
8
  ["src/layout/AppMenuItem.css", "es/layout/AppMenuItem.css"],
9
9
  ["src/layout/AppMenuSubheader.css", "es/layout/AppMenuSubheader.css"],
@@ -16,13 +16,22 @@ const files = [
16
16
  ["src/page/PageBlock.css", "es/page/PageBlock.css"],
17
17
  ["src/page/PageHeader.css", "es/page/PageHeader.css"],
18
18
  ["src/list/ItemList.css", "es/list/ItemList.css"],
19
+ ["src/input/InputAdornments.css", "es/input/InputAdornments.css"],
19
20
  ["src/paper/Paper.css", "es/paper/Paper.css"],
21
+ ["src/progress/LinearProgress.css", "es/progress/LinearProgress.css"],
22
+ ["src/sortable/DropIndicator.css", "es/sortable/DropIndicator.css"],
23
+ ["src/sortable/SortableItemList.css", "es/sortable/SortableItemList.css"],
24
+ ["src/autocomplete/Autocomplete.css", "es/autocomplete/Autocomplete.css"],
20
25
  ];
21
26
 
22
27
  mkdirSync("es/layout", { recursive: true });
28
+ mkdirSync("es/input", { recursive: true });
23
29
  mkdirSync("es/list", { recursive: true });
24
30
  mkdirSync("es/page", { recursive: true });
25
31
  mkdirSync("es/paper", { recursive: true });
32
+ mkdirSync("es/progress", { recursive: true });
33
+ mkdirSync("es/sortable", { recursive: true });
34
+ mkdirSync("es/autocomplete", { recursive: true });
26
35
 
27
36
  for (let [src, dest] of files) {
28
37
  cpSync(src, dest);
@@ -1,8 +1,7 @@
1
1
  import "./Lookup.css";
2
2
 
3
3
  import { Button, Textfield, type TextfieldProps } from "@digdir/designsystemet-react";
4
- import ClearIcon from "@mui/icons-material/Close";
5
- import SearchIcon from "@mui/icons-material/Search";
4
+ import { MagnifyingGlassIcon, XMarkIcon } from "@navikt/aksel-icons";
6
5
  import { getLocalizedString } from "@olenbetong/appframe-core";
7
6
  import { type DistributiveOmit, useLookupState } from "@olenbetong/appframe-react";
8
7
 
@@ -10,9 +9,9 @@ import clsx from "clsx";
10
9
  import { useRef } from "react";
11
10
  import { createPortal } from "react-dom";
12
11
 
13
- import { Combobox, type ComboboxProps } from "./Combobox.js";
12
+ import { LookupCombobox, type LookupComboboxProps } from "./LookupCombobox.js";
14
13
 
15
- export type AfLookupProps<T extends Record<string, unknown>> = DistributiveOmit<ComboboxProps<T>, "value"> & {
14
+ export type AfLookupProps<T extends Record<string, unknown>> = DistributiveOmit<LookupComboboxProps<T>, "value"> & {
16
15
  /**
17
16
  * Allows the user to enter a value manually that might not be in the list.
18
17
  */
@@ -27,7 +26,7 @@ export type AfLookupProps<T extends Record<string, unknown>> = DistributiveOmit<
27
26
  };
28
27
  };
29
28
 
30
- export type LookupProps<T extends Record<string, unknown>> = DistributiveOmit<ComboboxProps<T>, "value"> & {
29
+ export type LookupProps<T extends Record<string, unknown>> = DistributiveOmit<LookupComboboxProps<T>, "value"> & {
31
30
  slotProps?: {
32
31
  dialog?: Partial<React.HTMLProps<HTMLDialogElement>>;
33
32
  };
@@ -71,7 +70,7 @@ export function useLookup<T extends Record<string, unknown>>({
71
70
  style={{ positionAnchor: anchorName, ...slotProps?.dialog?.style } as React.CSSProperties}
72
71
  >
73
72
  {open && (
74
- <Combobox
73
+ <LookupCombobox
75
74
  {...props}
76
75
  initialSearchValue={initialSearchValueRef.current}
77
76
  onClose={() => dialogRef.current?.close()}
@@ -143,7 +142,7 @@ export function AfLookup<T extends Record<string, unknown>>({
143
142
  document.getElementById(inputId)?.focus();
144
143
  }}
145
144
  >
146
- <ClearIcon />
145
+ <XMarkIcon />
147
146
  </Button>
148
147
  )}
149
148
  <Button
@@ -153,7 +152,7 @@ export function AfLookup<T extends Record<string, unknown>>({
153
152
  aria-label={getLocalizedString("Search")}
154
153
  onClick={() => openDialog()}
155
154
  >
156
- <SearchIcon />
155
+ <MagnifyingGlassIcon />
157
156
  </Button>
158
157
  </div>
159
158
  </div>
@@ -1,4 +1,4 @@
1
- import "./Combobox.css";
1
+ import "./LookupCombobox.css";
2
2
 
3
3
  import { Button, Textfield } from "@digdir/designsystemet-react";
4
4
  import { getLocalizedString } from "@olenbetong/appframe-core";
@@ -11,7 +11,7 @@ import { VariableSizeList as VirtualList } from "react-window";
11
11
 
12
12
  import { LookupGrid } from "./LookupGrid.js";
13
13
 
14
- export interface ComboboxBaseProps<T extends Record<string, unknown>> {
14
+ export interface LookupComboboxBaseProps<T extends Record<string, unknown>> {
15
15
  nullable?: boolean;
16
16
  dataObject: DataObject<T>;
17
17
  uniqueIdField?: string;
@@ -22,7 +22,7 @@ export interface ComboboxBaseProps<T extends Record<string, unknown>> {
22
22
  onClose?: () => void;
23
23
  }
24
24
 
25
- export interface ComboboxListProps<T extends Record<string, unknown>> extends ComboboxBaseProps<T> {
25
+ export interface LookupComboboxListProps<T extends Record<string, unknown>> extends LookupComboboxBaseProps<T> {
26
26
  /**
27
27
  * Renders the popup content as a list (default).
28
28
  */
@@ -30,7 +30,7 @@ export interface ComboboxListProps<T extends Record<string, unknown>> extends Co
30
30
  renderItem: (props: React.ComponentPropsWithRef<"li"> & { item: T }) => React.ReactNode;
31
31
  }
32
32
 
33
- export interface ComboboxGridProps<T extends Record<string, unknown>> extends ComboboxBaseProps<T> {
33
+ export interface LookupComboboxGridProps<T extends Record<string, unknown>> extends LookupComboboxBaseProps<T> {
34
34
  /**
35
35
  * Renders the popup content as a grid with a header row and one column per
36
36
  * entry in `columns`.
@@ -39,9 +39,9 @@ export interface ComboboxGridProps<T extends Record<string, unknown>> extends Co
39
39
  columns: LookupColumn<T>[];
40
40
  }
41
41
 
42
- export type ComboboxProps<T extends Record<string, unknown>> = ComboboxListProps<T> | ComboboxGridProps<T>;
42
+ export type LookupComboboxProps<T extends Record<string, unknown>> = LookupComboboxListProps<T> | LookupComboboxGridProps<T>;
43
43
 
44
- export function Combobox<T extends Record<string, unknown>>(props: ComboboxProps<T>) {
44
+ export function LookupCombobox<T extends Record<string, unknown>>(props: LookupComboboxProps<T>) {
45
45
  let {
46
46
  nullable,
47
47
  dataObject,
@@ -52,7 +52,7 @@ export function Combobox<T extends Record<string, unknown>>(props: ComboboxProps
52
52
  onClose,
53
53
  } = props;
54
54
  let isGrid = props.variant === "grid";
55
- let columns = isGrid ? (props as ComboboxGridProps<T>).columns : undefined;
55
+ let columns = isGrid ? (props as LookupComboboxGridProps<T>).columns : undefined;
56
56
  let listRef = useRef<VirtualList>(null);
57
57
 
58
58
  let [isDesktop, setIsDesktop] = useState(
@@ -121,7 +121,7 @@ export function Combobox<T extends Record<string, unknown>>(props: ComboboxProps
121
121
  let item = data[index];
122
122
  let itemId = getItemId(item);
123
123
  let active = index === currentIndex;
124
- let ItemComponent = (props as ComboboxListProps<T>).renderItem;
124
+ let ItemComponent = (props as LookupComboboxListProps<T>).renderItem;
125
125
 
126
126
  return (
127
127
  <ItemComponent
@@ -1,19 +1,18 @@
1
1
  import "./Lookup.css";
2
2
 
3
3
  import { Button, Textfield, type TextfieldProps } from "@digdir/designsystemet-react";
4
- import ClearIcon from "@mui/icons-material/Close";
5
- import SearchIcon from "@mui/icons-material/Search";
4
+ import { MagnifyingGlassIcon, XMarkIcon } from "@navikt/aksel-icons";
6
5
  import { getLocalizedString } from "@olenbetong/appframe-core";
7
6
  import type { DistributiveOmit } from "@olenbetong/appframe-react";
8
7
 
9
8
  import clsx from "clsx";
10
9
  import type React from "react";
11
10
 
12
- import type { ComboboxProps } from "./Combobox.js";
11
+ import type { LookupComboboxProps } from "./LookupCombobox.js";
13
12
  import { useLookup } from "./Lookup.js";
14
13
 
15
14
  export type AfLookupEditProps<T extends Record<string, unknown>> = DistributiveOmit<
16
- ComboboxProps<T>,
15
+ LookupComboboxProps<T>,
17
16
  "value" | "onChange"
18
17
  > & {
19
18
  /**
@@ -108,7 +107,7 @@ export function AfLookupEdit<T extends Record<string, unknown>>({
108
107
  document.getElementById(inputId)?.focus();
109
108
  }}
110
109
  >
111
- <ClearIcon />
110
+ <XMarkIcon />
112
111
  </Button>
113
112
  )}
114
113
  <Button
@@ -121,7 +120,7 @@ export function AfLookupEdit<T extends Record<string, unknown>>({
121
120
  openDialog();
122
121
  }}
123
122
  >
124
- <SearchIcon />
123
+ <MagnifyingGlassIcon />
125
124
  </Button>
126
125
  </div>
127
126
  </div>
@@ -1,5 +1,5 @@
1
1
  export * from "./BoundLookup.js";
2
- export * from "./Combobox.js";
2
+ export * from "./LookupCombobox.js";
3
3
  export * from "./Lookup.js";
4
4
  export * from "./LookupEdit.js";
5
5
  export * from "./LookupGrid.js";
@@ -0,0 +1,222 @@
1
+ .ObAutocomplete-root {
2
+ --obAutocomplete-padding: 0.25rem;
3
+ --obAutocomplete-gap: 0.25rem;
4
+ --obAutocomplete-fontSize: var(--ds-font-size-3, 1rem);
5
+
6
+ display: inline-grid;
7
+ }
8
+
9
+ .ObAutocomplete-root[data-full-width="true"] {
10
+ display: grid;
11
+ inline-size: 100%;
12
+ }
13
+
14
+ .ObAutocomplete-root[data-size="xs"] {
15
+ --obAutocomplete-padding: 0.125rem;
16
+ --obAutocomplete-fontSize: var(--ds-font-size-1, 0.75rem);
17
+ }
18
+
19
+ .ObAutocomplete-root[data-size="sm"] {
20
+ --obAutocomplete-padding: 0.25rem;
21
+ --obAutocomplete-fontSize: var(--ds-font-size-2, 0.875rem);
22
+ }
23
+
24
+ .ObAutocomplete-root[data-size="md"] {
25
+ --obAutocomplete-padding: 0.25rem;
26
+ --obAutocomplete-fontSize: var(--ds-font-size-3, 1rem);
27
+ }
28
+
29
+ .ObAutocomplete-root[data-size="lg"] {
30
+ --obAutocomplete-padding: 0.375rem;
31
+ --obAutocomplete-fontSize: var(--ds-font-size-4, 1.125rem);
32
+ }
33
+
34
+ /*
35
+ * The control is the visual input: it owns the border, background, hover and
36
+ * focus styling, so the chips, the bare input and the buttons read as a single
37
+ * control. Mirrors how Designsystemet's Suggestion renders selected chips
38
+ * above the input.
39
+ */
40
+ .ObAutocomplete-control {
41
+ display: flex;
42
+ flex-direction: column;
43
+ box-sizing: border-box;
44
+ gap: var(--obAutocomplete-gap);
45
+ padding: var(--obAutocomplete-padding);
46
+ inline-size: 100%;
47
+ font-size: var(--obAutocomplete-fontSize);
48
+ color: var(--ds-color-neutral-text-default, #1e2b3c);
49
+ background-color: var(--ds-color-neutral-surface-default, #fff);
50
+ border: var(--ds-border-width-default, 1px) solid var(--ds-color-neutral-border-default, #b3b3b3);
51
+ border-radius: var(--ds-border-radius-md, 0.375rem);
52
+ }
53
+
54
+ .ObAutocomplete-control:hover:not(:focus-within) {
55
+ border-color: var(--ds-color-neutral-border-strong, #767676);
56
+ }
57
+
58
+ .ObAutocomplete-control:has(.ObAutocomplete-input:focus-visible) {
59
+ box-shadow: var(--dsc-focus-boxShadow);
60
+ outline: var(--dsc-focus-outline);
61
+ outline-offset: var(--ds-border-width-focus, 3px);
62
+ }
63
+
64
+ .ObAutocomplete-control[data-invalid="true"] {
65
+ border-color: var(--ds-color-danger-border-default, #b3253a);
66
+ }
67
+
68
+ .ObAutocomplete-control[data-disabled="true"] {
69
+ cursor: not-allowed;
70
+ opacity: var(--ds-disabled-opacity, 0.3);
71
+ }
72
+
73
+ .ObAutocomplete-chips {
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ gap: var(--obAutocomplete-gap);
77
+ padding: var(--obAutocomplete-padding);
78
+ padding-block-end: 0;
79
+ }
80
+
81
+ .ObAutocomplete-inputGroup {
82
+ display: flex;
83
+ align-items: center;
84
+ gap: var(--obAutocomplete-gap);
85
+ min-inline-size: 0;
86
+ }
87
+
88
+ .ObAutocomplete-input {
89
+ flex: 1;
90
+ min-inline-size: 0;
91
+ padding: var(--ds-size-1, 0.25rem);
92
+ font: inherit;
93
+ color: inherit;
94
+ background: transparent;
95
+ border: none;
96
+ outline: none;
97
+ }
98
+
99
+ .ObAutocomplete-input:disabled {
100
+ cursor: not-allowed;
101
+ }
102
+
103
+ .ObAutocomplete-button {
104
+ display: inline-flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ flex: none;
108
+ padding: var(--ds-size-1, 0.25rem);
109
+ font-size: var(--obAutocomplete-fontSize);
110
+ color: inherit;
111
+ background: transparent;
112
+ border: none;
113
+ border-radius: var(--ds-border-radius-sm, 0.25rem);
114
+ cursor: pointer;
115
+ }
116
+
117
+ .ObAutocomplete-button:hover:not(:disabled) {
118
+ background-color: var(--ds-color-neutral-surface-hover, #e6e6e6);
119
+ }
120
+
121
+ .ObAutocomplete-button:disabled {
122
+ cursor: not-allowed;
123
+ }
124
+
125
+ .ObAutocomplete-button[data-visible="false"] {
126
+ display: none;
127
+ }
128
+
129
+ .ObAutocomplete-trigger[data-popup-open] svg {
130
+ rotate: 180deg;
131
+ }
132
+
133
+ .ObAutocomplete-spinner {
134
+ flex: none;
135
+ display: inline-flex;
136
+ align-items: center;
137
+ padding-inline: var(--ds-size-1, 0.25rem);
138
+ }
139
+
140
+ .ObAutocomplete-positioner {
141
+ z-index: 1500;
142
+ /* Base UI renders the positioner even while closed */
143
+ outline: none;
144
+ }
145
+
146
+ .ObAutocomplete-popup {
147
+ box-sizing: border-box;
148
+ inline-size: var(--anchor-width);
149
+ max-block-size: min(24rem, var(--available-height));
150
+ overflow-y: auto;
151
+ overscroll-behavior: contain;
152
+ padding: var(--ds-size-1, 0.25rem);
153
+ font-size: var(--obAutocomplete-fontSize, var(--ds-font-size-3, 1rem));
154
+ color: var(--ds-color-neutral-text-default, #1e2b3c);
155
+ background-color: var(--ds-color-neutral-background-default, #fff);
156
+ border: var(--ds-border-width-default, 1px) solid var(--ds-color-neutral-border-subtle, #e0e0e0);
157
+ border-radius: var(--ds-border-radius-md, 0.375rem);
158
+ box-shadow: var(--ds-shadow-md, 0 2px 8px 0 rgb(0 0 0 / 0.12));
159
+ transform-origin: var(--transform-origin);
160
+ transition:
161
+ opacity 0.12s ease-out,
162
+ scale 0.12s ease-out;
163
+ }
164
+
165
+ .ObAutocomplete-popup[data-starting-style],
166
+ .ObAutocomplete-popup[data-ending-style] {
167
+ opacity: 0;
168
+ scale: 0.98;
169
+ }
170
+
171
+ .ObAutocomplete-list {
172
+ display: flex;
173
+ flex-direction: column;
174
+ }
175
+
176
+ .ObAutocomplete-item {
177
+ display: flex;
178
+ align-items: center;
179
+ gap: var(--ds-size-2, 0.5rem);
180
+ padding: var(--ds-size-2, 0.5rem);
181
+ border-radius: var(--ds-border-radius-sm, 0.25rem);
182
+ cursor: default;
183
+ user-select: none;
184
+ scroll-margin-block: var(--ds-size-1, 0.25rem);
185
+ }
186
+
187
+ .ObAutocomplete-item[data-highlighted] {
188
+ background-color: var(--ds-color-accent-surface-hover, #d6e2f2);
189
+ }
190
+
191
+ .ObAutocomplete-item[data-selected] {
192
+ font-weight: var(--ds-font-weight-medium, 500);
193
+ background-color: var(--ds-color-accent-surface-default, #e6effa);
194
+ }
195
+
196
+ .ObAutocomplete-item[data-selected][data-highlighted] {
197
+ background-color: var(--ds-color-accent-surface-active, #c2d5ec);
198
+ }
199
+
200
+ .ObAutocomplete-item[data-disabled] {
201
+ cursor: not-allowed;
202
+ opacity: var(--ds-disabled-opacity, 0.3);
203
+ }
204
+
205
+ .ObAutocomplete-itemIndicator {
206
+ display: inline-flex;
207
+ flex: none;
208
+ inline-size: 1em;
209
+ }
210
+
211
+ .ObAutocomplete-groupLabel {
212
+ padding: var(--ds-size-2, 0.5rem);
213
+ font-size: var(--ds-font-size-1, 0.75rem);
214
+ font-weight: var(--ds-font-weight-semibold, 600);
215
+ color: var(--ds-color-neutral-text-subtle, #4c5866);
216
+ text-transform: uppercase;
217
+ }
218
+
219
+ .ObAutocomplete-empty:not(:empty) {
220
+ padding: var(--ds-size-2, 0.5rem);
221
+ color: var(--ds-color-neutral-text-subtle, #4c5866);
222
+ }