@bitrise/bitkit-v2 0.3.417 → 0.3.419
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/components/BitkitCombobox/BitkitCombobox.d.ts +17 -5
- package/dist/components/BitkitCombobox/BitkitCombobox.js +149 -54
- package/dist/components/BitkitCombobox/BitkitCombobox.js.map +1 -1
- package/dist/theme/slot-recipes/Combobox.recipe.d.ts +1 -1
- package/dist/theme/slot-recipes/Combobox.recipe.js +1 -10
- package/dist/theme/slot-recipes/Combobox.recipe.js.map +1 -1
- package/dist/theme/slot-recipes/PageHeader.recipe.js +1 -0
- package/dist/theme/slot-recipes/PageHeader.recipe.js.map +1 -1
- package/dist/theme/slot-recipes/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { ComboboxRootProps } from '@chakra-ui/react/combobox';
|
|
2
2
|
import { BitkitFieldProps } from '../BitkitField/BitkitField';
|
|
3
|
-
import { BitkitSelectMenuEmptyStateProps, BitkitSelectMenuItemProps, BitkitSelectMenuScrollProps
|
|
3
|
+
import { BitkitSelectMenuEmptyStateProps, BitkitSelectMenuItemProps, BitkitSelectMenuScrollProps } from '../BitkitSelectMenu/BitkitSelectMenu';
|
|
4
4
|
import { BitkitSelectMenuActionChild } from '../BitkitSelectMenu/BitkitSelectMenuAction';
|
|
5
5
|
export type BitkitComboboxProps = Omit<BitkitFieldProps, 'children' | 'onChange' | 'state'> & {
|
|
6
|
+
/**
|
|
7
|
+
* Accept text that matches no option. `onValueChange` then fires with the typed text when the
|
|
8
|
+
* user commits it (closing the menu or leaving the field), and with the option's `value` when
|
|
9
|
+
* they pick one from the list.
|
|
10
|
+
*/
|
|
11
|
+
allowCustomValue?: boolean;
|
|
6
12
|
children?: BitkitSelectMenuActionChild;
|
|
7
|
-
comboboxProps?: Omit<ComboboxRootProps, 'collection' | 'defaultValue' | 'onValueChange' | 'value'>;
|
|
13
|
+
comboboxProps?: Omit<ComboboxRootProps, 'allowCustomValue' | 'collection' | 'defaultInputValue' | 'defaultValue' | 'ids' | 'inputValue' | 'onInputValueChange' | 'onOpenChange' | 'onValueChange' | 'open' | 'openOnClick' | 'value'>;
|
|
8
14
|
defaultValue?: string;
|
|
9
15
|
disablePortal?: boolean;
|
|
10
16
|
isLoading?: boolean;
|
|
@@ -14,10 +20,16 @@ export type BitkitComboboxProps = Omit<BitkitFieldProps, 'children' | 'onChange'
|
|
|
14
20
|
size?: 'md' | 'lg';
|
|
15
21
|
state?: 'disabled' | 'error' | 'readOnly' | 'warning';
|
|
16
22
|
value?: string;
|
|
17
|
-
} &
|
|
23
|
+
} & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps;
|
|
18
24
|
declare const _default: import('react').ForwardRefExoticComponent<Omit<BitkitFieldProps, "children" | "onChange" | "state"> & {
|
|
25
|
+
/**
|
|
26
|
+
* Accept text that matches no option. `onValueChange` then fires with the typed text when the
|
|
27
|
+
* user commits it (closing the menu or leaving the field), and with the option's `value` when
|
|
28
|
+
* they pick one from the list.
|
|
29
|
+
*/
|
|
30
|
+
allowCustomValue?: boolean;
|
|
19
31
|
children?: BitkitSelectMenuActionChild;
|
|
20
|
-
comboboxProps?: Omit<ComboboxRootProps, "collection" | "defaultValue" | "onValueChange" | "value">;
|
|
32
|
+
comboboxProps?: Omit<ComboboxRootProps, "allowCustomValue" | "collection" | "defaultInputValue" | "defaultValue" | "ids" | "inputValue" | "onInputValueChange" | "onOpenChange" | "onValueChange" | "open" | "openOnClick" | "value">;
|
|
21
33
|
defaultValue?: string;
|
|
22
34
|
disablePortal?: boolean;
|
|
23
35
|
isLoading?: boolean;
|
|
@@ -27,7 +39,7 @@ declare const _default: import('react').ForwardRefExoticComponent<Omit<BitkitFie
|
|
|
27
39
|
size?: "md" | "lg";
|
|
28
40
|
state?: "disabled" | "error" | "readOnly" | "warning";
|
|
29
41
|
value?: string;
|
|
30
|
-
} &
|
|
42
|
+
} & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & import('react').RefAttributes<HTMLDivElement>> & {
|
|
31
43
|
Action: {
|
|
32
44
|
(props: import('..').BitkitSelectMenuActionProps): import("react").JSX.Element;
|
|
33
45
|
displayName: string;
|
|
@@ -7,21 +7,57 @@ import BitkitCloseButton from "../BitkitCloseButton/BitkitCloseButton.js";
|
|
|
7
7
|
import BitkitSelectMenuAction from "../BitkitSelectMenu/BitkitSelectMenuAction.js";
|
|
8
8
|
import BitkitSelectMenu from "../BitkitSelectMenu/BitkitSelectMenu.js";
|
|
9
9
|
import BitkitField from "../BitkitField/BitkitField.js";
|
|
10
|
-
import { forwardRef, useContext, useState } from "react";
|
|
10
|
+
import { forwardRef, useContext, useRef, useState } from "react";
|
|
11
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { Portal } from "@chakra-ui/react/portal";
|
|
13
13
|
import { createListCollection } from "@chakra-ui/react/collection";
|
|
14
14
|
import { Combobox } from "@chakra-ui/react/combobox";
|
|
15
|
+
import { useFieldContext } from "@chakra-ui/react/field";
|
|
15
16
|
import { useFilter } from "@chakra-ui/react/locale";
|
|
16
17
|
//#region lib/components/BitkitCombobox/BitkitCombobox.tsx
|
|
18
|
+
/**
|
|
19
|
+
* A text input that filters a list of options as you type. The menu opens on focus with every
|
|
20
|
+
* option, narrows to the ones matching the input, and shows an empty state when nothing matches.
|
|
21
|
+
* Unlike BitkitSelect's menu it has no separate search field — the input itself is the filter.
|
|
22
|
+
*/
|
|
17
23
|
var BitkitCombobox = forwardRef((props, ref) => {
|
|
18
|
-
const { children, comboboxProps, defaultValue, disablePortal, emptyHelperText, emptyLabel, isLoading, items, onScrolledToBottom,
|
|
24
|
+
const { allowCustomValue, children, comboboxProps, defaultValue, disablePortal, emptyHelperText, emptyLabel, isLoading, items, onScrolledToBottom, onValueChange, placeholder = "Enter value or select", size = "lg", state, value, ...fieldProps } = props;
|
|
25
|
+
return /* @__PURE__ */ jsx(BitkitField, {
|
|
26
|
+
ref,
|
|
27
|
+
state,
|
|
28
|
+
...fieldProps,
|
|
29
|
+
children: /* @__PURE__ */ jsx(ComboboxControl, {
|
|
30
|
+
allowCustomValue,
|
|
31
|
+
comboboxProps,
|
|
32
|
+
defaultValue,
|
|
33
|
+
disablePortal,
|
|
34
|
+
emptyHelperText: emptyHelperText ?? (allowCustomValue ? "Enter custom value." : void 0),
|
|
35
|
+
emptyLabel,
|
|
36
|
+
hasWarning: state === "warning" || !!fieldProps.warningText,
|
|
37
|
+
isInvalid: state === "error" || !!fieldProps.errorText,
|
|
38
|
+
isLoading,
|
|
39
|
+
items,
|
|
40
|
+
onScrolledToBottom,
|
|
41
|
+
onValueChange,
|
|
42
|
+
placeholder,
|
|
43
|
+
size,
|
|
44
|
+
state,
|
|
45
|
+
value,
|
|
46
|
+
children
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
BitkitCombobox.displayName = "BitkitCombobox";
|
|
51
|
+
/** Rendered inside BitkitField so it can read the field's ids and wire them to the input. */
|
|
52
|
+
var ComboboxControl = ({ allowCustomValue, children, comboboxProps, defaultValue, disablePortal, emptyHelperText, emptyLabel, hasWarning, isInvalid, isLoading, items, onScrolledToBottom, onValueChange, placeholder, size, state, value }) => {
|
|
19
53
|
const { disablePortal: disablePortalFromContext } = useContext(BitkitPortalContext);
|
|
54
|
+
const field = useFieldContext();
|
|
20
55
|
const { contains } = useFilter({ sensitivity: "base" });
|
|
21
56
|
const [filterText, setFilterText] = useState("");
|
|
22
57
|
const visibleItems = filterText ? items.filter((item) => contains(item.label, filterText)) : items;
|
|
23
58
|
const collection = createListCollection({
|
|
24
59
|
items: visibleItems,
|
|
60
|
+
groupBy: (item) => item.group || "",
|
|
25
61
|
isItemDisabled: (item) => !!item.disabled
|
|
26
62
|
});
|
|
27
63
|
const itemValues = items.map((item) => item.value);
|
|
@@ -33,8 +69,30 @@ var BitkitCombobox = forwardRef((props, ref) => {
|
|
|
33
69
|
setPrevItemsKey(itemsKey);
|
|
34
70
|
if (!isAppend) setFilterText("");
|
|
35
71
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
72
|
+
const [initialInputValue] = useState(() => {
|
|
73
|
+
const initialValue = value ?? defaultValue;
|
|
74
|
+
if (!initialValue) return "";
|
|
75
|
+
return items.find((item) => item.value === initialValue)?.label ?? (allowCustomValue ? initialValue : "");
|
|
76
|
+
});
|
|
77
|
+
const [inputValue, setInputValue] = useState(initialInputValue);
|
|
78
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
79
|
+
const [prevValue, setPrevValue] = useState(value);
|
|
80
|
+
if (value !== prevValue) {
|
|
81
|
+
setPrevValue(value);
|
|
82
|
+
if (allowCustomValue) setInputValue(value ? items.find((item) => item.value === value)?.label ?? value : "");
|
|
83
|
+
}
|
|
84
|
+
const lastEmittedValue = useRef(null);
|
|
85
|
+
const skipFocusOpen = useRef(false);
|
|
86
|
+
const isInteractive = state !== "disabled" && state !== "readOnly";
|
|
87
|
+
const commitCustomValue = () => {
|
|
88
|
+
const text = inputValue.trim();
|
|
89
|
+
if (!allowCustomValue || !text) return;
|
|
90
|
+
const match = items.find((item) => item.label.toLowerCase() === text.toLowerCase());
|
|
91
|
+
const committed = match ? match.value : text;
|
|
92
|
+
if (lastEmittedValue.current === committed) return;
|
|
93
|
+
lastEmittedValue.current = committed;
|
|
94
|
+
onValueChange?.(committed);
|
|
95
|
+
};
|
|
38
96
|
const iconSize = size === "md" ? "16" : "24";
|
|
39
97
|
let statusIcon;
|
|
40
98
|
if (isInvalid) statusIcon = /* @__PURE__ */ jsx(IconErrorCircleFilled, {
|
|
@@ -42,57 +100,94 @@ var BitkitCombobox = forwardRef((props, ref) => {
|
|
|
42
100
|
color: "icon/negative"
|
|
43
101
|
});
|
|
44
102
|
else if (hasWarning) statusIcon = /* @__PURE__ */ jsx(IconWarningYellow, { size: iconSize });
|
|
45
|
-
return /* @__PURE__ */
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
103
|
+
return /* @__PURE__ */ jsxs(Combobox.Root, {
|
|
104
|
+
...comboboxProps,
|
|
105
|
+
allowCustomValue,
|
|
106
|
+
collection,
|
|
107
|
+
defaultInputValue: initialInputValue,
|
|
108
|
+
defaultValue: defaultValue ? [defaultValue] : void 0,
|
|
109
|
+
disabled: state === "disabled",
|
|
110
|
+
hasStatusIcon: !!statusIcon,
|
|
111
|
+
ids: field ? {
|
|
112
|
+
input: field.ids.control,
|
|
113
|
+
label: field.ids.label
|
|
114
|
+
} : void 0,
|
|
115
|
+
invalid: isInvalid,
|
|
116
|
+
inputValue: allowCustomValue ? inputValue : void 0,
|
|
117
|
+
onInputValueChange: ({ inputValue: nextInputValue, reason }) => {
|
|
118
|
+
setInputValue(nextInputValue);
|
|
119
|
+
if (reason === "clear-trigger" && lastEmittedValue.current !== null) {
|
|
120
|
+
lastEmittedValue.current = null;
|
|
121
|
+
onValueChange?.(void 0);
|
|
122
|
+
}
|
|
123
|
+
setFilterText(reason === "input-change" ? nextInputValue : "");
|
|
124
|
+
},
|
|
125
|
+
onOpenChange: ({ open }) => {
|
|
126
|
+
setIsOpen(open);
|
|
127
|
+
if (!open) commitCustomValue();
|
|
128
|
+
},
|
|
129
|
+
onValueChange: (details) => {
|
|
130
|
+
const next = details.value[0];
|
|
131
|
+
if (allowCustomValue) setInputValue(next ? items.find((item) => item.value === next)?.label ?? next : "");
|
|
132
|
+
if (next === void 0 && lastEmittedValue.current === null) return;
|
|
133
|
+
lastEmittedValue.current = next ?? null;
|
|
134
|
+
onValueChange?.(next);
|
|
135
|
+
},
|
|
136
|
+
open: isOpen,
|
|
137
|
+
openOnClick: true,
|
|
138
|
+
readOnly: state === "readOnly",
|
|
139
|
+
scrollToIndexFn: ({ getElement }) => getElement()?.scrollIntoView({ block: "nearest" }),
|
|
140
|
+
selectionBehavior: allowCustomValue ? "preserve" : void 0,
|
|
141
|
+
size,
|
|
142
|
+
value: value === void 0 ? void 0 : value ? [value] : [],
|
|
143
|
+
children: [/* @__PURE__ */ jsxs(Combobox.Control, {
|
|
144
|
+
className: "group",
|
|
145
|
+
children: [/* @__PURE__ */ jsx(Combobox.Input, {
|
|
146
|
+
onBlur: commitCustomValue,
|
|
147
|
+
onKeyDown: (event) => {
|
|
148
|
+
if (!allowCustomValue || event.key !== "Enter") return;
|
|
149
|
+
if (event.currentTarget.getAttribute("aria-activedescendant")) return;
|
|
150
|
+
commitCustomValue();
|
|
151
|
+
setIsOpen(false);
|
|
152
|
+
},
|
|
153
|
+
onFocus: () => {
|
|
154
|
+
if (skipFocusOpen.current || !isInteractive) return;
|
|
155
|
+
setIsOpen(true);
|
|
156
|
+
},
|
|
157
|
+
placeholder
|
|
158
|
+
}), /* @__PURE__ */ jsxs(Combobox.IndicatorGroup, { children: [
|
|
159
|
+
/* @__PURE__ */ jsx(Combobox.ClearTrigger, {
|
|
160
|
+
asChild: true,
|
|
161
|
+
hidden: !isInteractive || !inputValue && !value,
|
|
162
|
+
children: /* @__PURE__ */ jsx(BitkitCloseButton, { size: "sm" })
|
|
163
|
+
}),
|
|
164
|
+
statusIcon,
|
|
165
|
+
/* @__PURE__ */ jsx(Combobox.Trigger, {
|
|
166
|
+
asChild: true,
|
|
167
|
+
onPointerDown: () => {
|
|
168
|
+
skipFocusOpen.current = true;
|
|
169
|
+
requestAnimationFrame(() => {
|
|
170
|
+
skipFocusOpen.current = false;
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
children: /* @__PURE__ */ jsx(AssetSelectChevron, {})
|
|
174
|
+
})
|
|
175
|
+
] })]
|
|
176
|
+
}), /* @__PURE__ */ jsx(Portal, {
|
|
177
|
+
disabled: disablePortal || disablePortalFromContext,
|
|
178
|
+
children: /* @__PURE__ */ jsx(Combobox.Positioner, { children: /* @__PURE__ */ jsx(BitkitSelectMenu, {
|
|
179
|
+
collection,
|
|
180
|
+
emptyHelperText,
|
|
181
|
+
emptyLabel,
|
|
182
|
+
isLoading,
|
|
183
|
+
onScrolledToBottom,
|
|
184
|
+
size,
|
|
185
|
+
variant: "combobox",
|
|
186
|
+
children
|
|
187
|
+
}) })
|
|
188
|
+
})]
|
|
93
189
|
});
|
|
94
|
-
}
|
|
95
|
-
BitkitCombobox.displayName = "BitkitCombobox";
|
|
190
|
+
};
|
|
96
191
|
var BitkitCombobox_default = withSubComponents(BitkitCombobox, { Action: BitkitSelectMenuAction });
|
|
97
192
|
//#endregion
|
|
98
193
|
export { BitkitCombobox_default as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitCombobox.js","names":[],"sources":["../../../lib/components/BitkitCombobox/BitkitCombobox.tsx"],"sourcesContent":["import { createListCollection } from '@chakra-ui/react/collection';\nimport { Combobox, type ComboboxRootProps } from '@chakra-ui/react/combobox';\nimport { useFilter } from '@chakra-ui/react/locale';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { forwardRef, useContext, useState } from 'react';\n\nimport IconErrorCircleFilled from '../../icons/IconErrorCircleFilled';\nimport IconWarningYellow from '../../icons/IconWarningYellow';\nimport AssetSelectChevron from '../../utilities/AssetSelectChevron';\nimport BitkitPortalContext from '../../utilities/BitkitPortalContext';\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\nimport BitkitField, { type BitkitFieldProps } from '../BitkitField/BitkitField';\nimport BitkitSelectMenu, {\n type BitkitSelectMenuEmptyStateProps,\n type BitkitSelectMenuItemProps,\n type BitkitSelectMenuScrollProps,\n type BitkitSelectMenuSearchProps,\n} from '../BitkitSelectMenu/BitkitSelectMenu';\nimport BitkitSelectMenuAction, { type BitkitSelectMenuActionChild } from '../BitkitSelectMenu/BitkitSelectMenuAction';\n\nexport type BitkitComboboxProps = Omit<BitkitFieldProps, 'children' | 'onChange' | 'state'> & {\n children?: BitkitSelectMenuActionChild;\n comboboxProps?: Omit<ComboboxRootProps, 'collection' | 'defaultValue' | 'onValueChange' | 'value'>;\n defaultValue?: string;\n disablePortal?: boolean;\n isLoading?: boolean;\n items: Array<BitkitSelectMenuItemProps>;\n onValueChange?: (newVal: string | undefined) => void;\n placeholder?: string;\n size?: 'md' | 'lg';\n state?: 'disabled' | 'error' | 'readOnly' | 'warning';\n value?: string;\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps;\n\nconst BitkitCombobox = forwardRef<HTMLDivElement, BitkitComboboxProps>((props: BitkitComboboxProps, ref) => {\n const {\n children,\n comboboxProps,\n defaultValue,\n disablePortal,\n emptyHelperText,\n emptyLabel,\n isLoading,\n items,\n onScrolledToBottom,\n onSearchChange,\n onValueChange,\n placeholder = 'Enter a value or select',\n searchValue,\n size = 'lg',\n state,\n value,\n ...fieldProps\n } = props;\n\n const { disablePortal: disablePortalFromContext } = useContext(BitkitPortalContext);\n\n const { contains } = useFilter({ sensitivity: 'base' });\n\n // Derive the collection on every render rather than using useListCollection, which snapshots\n // `items` into state as `initialItems` and never syncs it again, so changing `items` actually reaches the menu.\n // Deriving also keeps callers that pass an inline array literal safe, since nothing here is keyed on items identity.\n const [filterText, setFilterText] = useState('');\n const visibleItems = filterText ? items.filter((item) => contains(item.label, filterText)) : items;\n const collection = createListCollection<BitkitSelectMenuItemProps>({\n items: visibleItems,\n isItemDisabled: (item) => !!item.disabled,\n });\n\n // A new set of items invalidates whatever the old ones were filtered by — otherwise leftover\n // filter text (which Zag also sets from the selected item's label) can hide every new item and\n // leave the menu empty. Keyed on item values, not array identity, so an inline `items={[…]}`\n // literal doesn't wipe the filter on every keystroke. Matches what useListCollection's `set()`\n // used to do for us.\n const itemValues = items.map((item) => item.value);\n const itemsKey = JSON.stringify(itemValues);\n const [prevItemsKey, setPrevItemsKey] = useState(itemsKey);\n if (prevItemsKey !== itemsKey) {\n const prevValues = JSON.parse(prevItemsKey) as Array<string>;\n const isAppend = itemValues.length > prevValues.length && prevValues.every((v, i) => v === itemValues[i]);\n setPrevItemsKey(itemsKey);\n if (!isAppend) {\n setFilterText('');\n }\n }\n\n const hasWarning = state === 'warning' || !!fieldProps.warningText;\n const isInvalid = state === 'error' || !!fieldProps.errorText;\n const iconSize = size === 'md' ? '16' : '24';\n\n let statusIcon;\n if (isInvalid) {\n statusIcon = <IconErrorCircleFilled size={iconSize} color=\"icon/negative\" />;\n } else if (hasWarning) {\n statusIcon = <IconWarningYellow size={iconSize} />;\n }\n\n return (\n <BitkitField ref={ref} state={state} {...fieldProps}>\n <Combobox.Root\n {...comboboxProps}\n collection={collection}\n defaultValue={defaultValue ? [defaultValue] : undefined}\n disabled={state === 'disabled'}\n hasStatusIcon={!!statusIcon}\n invalid={isInvalid}\n onInputValueChange={(e) => {\n setFilterText(e.inputValue);\n }}\n onValueChange={(details) => onValueChange?.(details.value[0])}\n readOnly={state === 'readOnly'}\n // Bypass Zag's isScrollable(contentEl) gate — our Content is overflow:hidden flex\n // column, so the real scroll container is itemList. See BitkitMultiselect for why.\n scrollToIndexFn={({ getElement }) => getElement()?.scrollIntoView({ block: 'nearest' })}\n size={size}\n // Stay controlled whenever `value` is provided — including `''` (\"nothing selected\"). A\n // truthiness check (`value ? … : undefined`) passes `undefined` for `''`, which flips\n // Combobox.Root to uncontrolled: it then ignores `value`, so resets don't take and\n // onValueChange stops firing when the same option is re-selected.\n value={value === undefined ? undefined : value ? [value] : []}\n >\n <Combobox.Control className=\"group\">\n <Combobox.Input placeholder={placeholder} />\n <Combobox.IndicatorGroup>\n <Combobox.ClearTrigger asChild>\n <BitkitCloseButton size=\"sm\" />\n </Combobox.ClearTrigger>\n {statusIcon}\n <Combobox.Trigger asChild>\n <AssetSelectChevron />\n </Combobox.Trigger>\n </Combobox.IndicatorGroup>\n </Combobox.Control>\n <Portal disabled={disablePortal || disablePortalFromContext}>\n <Combobox.Positioner>\n <BitkitSelectMenu\n collection={collection}\n emptyHelperText={emptyHelperText}\n emptyLabel={emptyLabel}\n isLoading={isLoading}\n onScrolledToBottom={onScrolledToBottom}\n onSearchChange={onSearchChange}\n searchValue={searchValue}\n size={size}\n variant=\"combobox\"\n >\n {children}\n </BitkitSelectMenu>\n </Combobox.Positioner>\n </Portal>\n </Combobox.Root>\n </BitkitField>\n );\n});\n\nBitkitCombobox.displayName = 'BitkitCombobox';\n\nexport default withSubComponents(BitkitCombobox, { Action: BitkitSelectMenuAction });\n"],"mappings":";;;;;;;;;;;;;;;;AAqCA,IAAM,iBAAiB,YAAiD,OAA4B,QAAQ;CAC1G,MAAM,EACJ,UACA,eACA,cACA,eACA,iBACA,YACA,WACA,OACA,oBACA,gBACA,eACA,cAAc,2BACd,aACA,OAAO,MACP,OACA,OACA,GAAG,eACD;CAEJ,MAAM,EAAE,eAAe,6BAA6B,WAAW,mBAAmB;CAElF,MAAM,EAAE,aAAa,UAAU,EAAE,aAAa,OAAO,CAAC;CAKtD,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAC/C,MAAM,eAAe,aAAa,MAAM,QAAQ,SAAS,SAAS,KAAK,OAAO,UAAU,CAAC,IAAI;CAC7F,MAAM,aAAa,qBAAgD;EACjE,OAAO;EACP,iBAAiB,SAAS,CAAC,CAAC,KAAK;CACnC,CAAC;CAOD,MAAM,aAAa,MAAM,KAAK,SAAS,KAAK,KAAK;CACjD,MAAM,WAAW,KAAK,UAAU,UAAU;CAC1C,MAAM,CAAC,cAAc,mBAAmB,SAAS,QAAQ;CACzD,IAAI,iBAAiB,UAAU;EAC7B,MAAM,aAAa,KAAK,MAAM,YAAY;EAC1C,MAAM,WAAW,WAAW,SAAS,WAAW,UAAU,WAAW,OAAO,GAAG,MAAM,MAAM,WAAW,EAAE;EACxG,gBAAgB,QAAQ;EACxB,IAAI,CAAC,UACH,cAAc,EAAE;CAEpB;CAEA,MAAM,aAAa,UAAU,aAAa,CAAC,CAAC,WAAW;CACvD,MAAM,YAAY,UAAU,WAAW,CAAC,CAAC,WAAW;CACpD,MAAM,WAAW,SAAS,OAAO,OAAO;CAExC,IAAI;CACJ,IAAI,WACF,aAAa,oBAAC,uBAAD;EAAuB,MAAM;EAAU,OAAM;CAAiB,CAAA;MACtE,IAAI,YACT,aAAa,oBAAC,mBAAD,EAAmB,MAAM,SAAW,CAAA;CAGnD,OACE,oBAAC,aAAD;EAAkB;EAAY;EAAO,GAAI;EACvC,UAAA,qBAAC,SAAS,MAAV;GACE,GAAI;GACQ;GACZ,cAAc,eAAe,CAAC,YAAY,IAAI,KAAA;GAC9C,UAAU,UAAU;GACpB,eAAe,CAAC,CAAC;GACjB,SAAS;GACT,qBAAqB,MAAM;IACzB,cAAc,EAAE,UAAU;GAC5B;GACA,gBAAgB,YAAY,gBAAgB,QAAQ,MAAM,EAAE;GAC5D,UAAU,UAAU;GAGpB,kBAAkB,EAAE,iBAAiB,WAAW,CAAC,EAAE,eAAe,EAAE,OAAO,UAAU,CAAC;GAChF;GAKN,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,QAAQ,CAAC,KAAK,IAAI,CAAC;GApB9D,UAAA,CAsBE,qBAAC,SAAS,SAAV;IAAkB,WAAU;IAA5B,UAAA,CACE,oBAAC,SAAS,OAAV,EAA6B,YAAc,CAAA,GAC3C,qBAAC,SAAS,gBAAV,EAAA,UAAA;KACE,oBAAC,SAAS,cAAV;MAAuB,SAAA;MACrB,UAAA,oBAAC,mBAAD,EAAmB,MAAK,KAAM,CAAA;KACT,CAAA;KACtB;KACD,oBAAC,SAAS,SAAV;MAAkB,SAAA;MAChB,UAAA,oBAAC,oBAAD,CAAqB,CAAA;KACL,CAAA;IACK,EAAA,CAAA,CACT;GAClB,CAAA,GAAA,oBAAC,QAAD;IAAQ,UAAU,iBAAiB;IACjC,UAAA,oBAAC,SAAS,YAAV,EAAA,UACE,oBAAC,kBAAD;KACc;KACK;KACL;KACD;KACS;KACJ;KACH;KACP;KACN,SAAQ;KAEP;IACe,CAAA,EACC,CAAA;GACf,CAAA,CACK;;CACJ,CAAA;AAEjB,CAAC;AAED,eAAe,cAAc;AAE7B,IAAA,yBAAe,kBAAkB,gBAAgB,EAAE,QAAQ,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"BitkitCombobox.js","names":[],"sources":["../../../lib/components/BitkitCombobox/BitkitCombobox.tsx"],"sourcesContent":["import { createListCollection } from '@chakra-ui/react/collection';\nimport { Combobox, type ComboboxRootProps } from '@chakra-ui/react/combobox';\nimport { useFieldContext } from '@chakra-ui/react/field';\nimport { useFilter } from '@chakra-ui/react/locale';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { forwardRef, useContext, useRef, useState } from 'react';\n\nimport IconErrorCircleFilled from '../../icons/IconErrorCircleFilled';\nimport IconWarningYellow from '../../icons/IconWarningYellow';\nimport AssetSelectChevron from '../../utilities/AssetSelectChevron';\nimport BitkitPortalContext from '../../utilities/BitkitPortalContext';\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\nimport BitkitField, { type BitkitFieldProps } from '../BitkitField/BitkitField';\nimport BitkitSelectMenu, {\n type BitkitSelectMenuEmptyStateProps,\n type BitkitSelectMenuItemProps,\n type BitkitSelectMenuScrollProps,\n} from '../BitkitSelectMenu/BitkitSelectMenu';\nimport BitkitSelectMenuAction, { type BitkitSelectMenuActionChild } from '../BitkitSelectMenu/BitkitSelectMenuAction';\n\nexport type BitkitComboboxProps = Omit<BitkitFieldProps, 'children' | 'onChange' | 'state'> & {\n /**\n * Accept text that matches no option. `onValueChange` then fires with the typed text when the\n * user commits it (closing the menu or leaving the field), and with the option's `value` when\n * they pick one from the list.\n */\n allowCustomValue?: boolean;\n children?: BitkitSelectMenuActionChild;\n comboboxProps?: Omit<\n ComboboxRootProps,\n | 'allowCustomValue'\n | 'collection'\n | 'defaultInputValue'\n | 'defaultValue'\n | 'ids'\n | 'inputValue'\n | 'onInputValueChange'\n | 'onOpenChange'\n | 'onValueChange'\n | 'open'\n | 'openOnClick'\n | 'value'\n >;\n defaultValue?: string;\n disablePortal?: boolean;\n isLoading?: boolean;\n items: Array<BitkitSelectMenuItemProps>;\n onValueChange?: (newVal: string | undefined) => void;\n placeholder?: string;\n size?: 'md' | 'lg';\n state?: 'disabled' | 'error' | 'readOnly' | 'warning';\n value?: string;\n} & BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps;\n\n/**\n * A text input that filters a list of options as you type. The menu opens on focus with every\n * option, narrows to the ones matching the input, and shows an empty state when nothing matches.\n * Unlike BitkitSelect's menu it has no separate search field — the input itself is the filter.\n */\nconst BitkitCombobox = forwardRef<HTMLDivElement, BitkitComboboxProps>((props: BitkitComboboxProps, ref) => {\n const {\n allowCustomValue,\n children,\n comboboxProps,\n defaultValue,\n disablePortal,\n emptyHelperText,\n emptyLabel,\n isLoading,\n items,\n onScrolledToBottom,\n onValueChange,\n placeholder = 'Enter value or select',\n size = 'lg',\n state,\n value,\n ...fieldProps\n } = props;\n\n return (\n <BitkitField ref={ref} state={state} {...fieldProps}>\n <ComboboxControl\n allowCustomValue={allowCustomValue}\n comboboxProps={comboboxProps}\n defaultValue={defaultValue}\n disablePortal={disablePortal}\n emptyHelperText={emptyHelperText ?? (allowCustomValue ? 'Enter custom value.' : undefined)}\n emptyLabel={emptyLabel}\n hasWarning={state === 'warning' || !!fieldProps.warningText}\n isInvalid={state === 'error' || !!fieldProps.errorText}\n isLoading={isLoading}\n items={items}\n onScrolledToBottom={onScrolledToBottom}\n onValueChange={onValueChange}\n placeholder={placeholder}\n size={size}\n state={state}\n value={value}\n >\n {children}\n </ComboboxControl>\n </BitkitField>\n );\n});\n\nBitkitCombobox.displayName = 'BitkitCombobox';\n\ntype ComboboxControlProps = Pick<\n BitkitComboboxProps,\n | 'allowCustomValue'\n | 'children'\n | 'comboboxProps'\n | 'defaultValue'\n | 'disablePortal'\n | 'emptyHelperText'\n | 'emptyLabel'\n | 'isLoading'\n | 'items'\n | 'onScrolledToBottom'\n | 'onValueChange'\n | 'state'\n | 'value'\n> &\n Required<Pick<BitkitComboboxProps, 'placeholder' | 'size'>> & {\n hasWarning: boolean;\n isInvalid: boolean;\n };\n\n/** Rendered inside BitkitField so it can read the field's ids and wire them to the input. */\nconst ComboboxControl = ({\n allowCustomValue,\n children,\n comboboxProps,\n defaultValue,\n disablePortal,\n emptyHelperText,\n emptyLabel,\n hasWarning,\n isInvalid,\n isLoading,\n items,\n onScrolledToBottom,\n onValueChange,\n placeholder,\n size,\n state,\n value,\n}: ComboboxControlProps) => {\n const { disablePortal: disablePortalFromContext } = useContext(BitkitPortalContext);\n const field = useFieldContext();\n\n const { contains } = useFilter({ sensitivity: 'base' });\n\n // Derive the collection on every render rather than using useListCollection, which snapshots\n // `items` into state as `initialItems` and never syncs it again, so changing `items` actually reaches the menu.\n // Deriving also keeps callers that pass an inline array literal safe, since nothing here is keyed on items identity.\n const [filterText, setFilterText] = useState('');\n const visibleItems = filterText ? items.filter((item) => contains(item.label, filterText)) : items;\n const collection = createListCollection<BitkitSelectMenuItemProps>({\n items: visibleItems,\n groupBy: (item) => item.group || '',\n isItemDisabled: (item) => !!item.disabled,\n });\n\n // A new set of items invalidates whatever the old ones were filtered by — otherwise leftover\n // filter text can hide every new item and leave the menu empty. Keyed on item values, not array\n // identity, so an inline `items={[…]}` literal doesn't wipe the filter on every keystroke; an\n // append (the next page of results) keeps it, so paging doesn't drop what the user typed.\n const itemValues = items.map((item) => item.value);\n const itemsKey = JSON.stringify(itemValues);\n const [prevItemsKey, setPrevItemsKey] = useState(itemsKey);\n if (prevItemsKey !== itemsKey) {\n const prevValues = JSON.parse(prevItemsKey) as Array<string>;\n const isAppend = itemValues.length > prevValues.length && prevValues.every((v, i) => v === itemValues[i]);\n setPrevItemsKey(itemsKey);\n if (!isAppend) {\n setFilterText('');\n }\n }\n\n // Zag only reports the input text once it changes, so mirror what it starts with — otherwise the\n // clear button stays hidden next to a pre-selected value.\n const [initialInputValue] = useState(() => {\n const initialValue = value ?? defaultValue;\n if (!initialValue) return '';\n return items.find((item) => item.value === initialValue)?.label ?? (allowCustomValue ? initialValue : '');\n });\n const [inputValue, setInputValue] = useState(initialInputValue);\n const [isOpen, setIsOpen] = useState(false);\n // A controlled `value` that no option carries can only live in the input, so follow it there.\n const [prevValue, setPrevValue] = useState(value);\n if (value !== prevValue) {\n setPrevValue(value);\n if (allowCustomValue) {\n setInputValue(value ? (items.find((item) => item.value === value)?.label ?? value) : '');\n }\n }\n const lastEmittedValue = useRef<string | null>(null);\n // Clicking the chevron focuses the input first, so without this the focus handler would open the\n // menu just before the trigger's own click closes it again.\n const skipFocusOpen = useRef(false);\n\n const isInteractive = state !== 'disabled' && state !== 'readOnly';\n\n const commitCustomValue = () => {\n const text = inputValue.trim();\n if (!allowCustomValue || !text) return;\n // Match the filter's case-insensitivity: typing \"react\" means the React option, not a custom\n // value that happens to read the same.\n const match = items.find((item) => item.label.toLowerCase() === text.toLowerCase());\n const committed = match ? match.value : text;\n if (lastEmittedValue.current === committed) return;\n lastEmittedValue.current = committed;\n onValueChange?.(committed);\n };\n\n const iconSize = size === 'md' ? '16' : '24';\n\n let statusIcon;\n if (isInvalid) {\n statusIcon = <IconErrorCircleFilled size={iconSize} color=\"icon/negative\" />;\n } else if (hasWarning) {\n statusIcon = <IconWarningYellow size={iconSize} />;\n }\n\n return (\n <Combobox.Root\n {...comboboxProps}\n allowCustomValue={allowCustomValue}\n collection={collection}\n defaultInputValue={initialInputValue}\n defaultValue={defaultValue ? [defaultValue] : undefined}\n disabled={state === 'disabled'}\n hasStatusIcon={!!statusIcon}\n // Chakra's Combobox doesn't take its input id from the surrounding Field, so the field\n // label's `htmlFor` would point at an element that doesn't exist. Hand it the field's ids\n // instead, and the label both labels and focuses the input.\n ids={field ? { input: field.ids.control, label: field.ids.label } : undefined}\n invalid={isInvalid}\n // Custom values live only in the input: Zag rewrites it from the collection on every value\n // change, which would blank text no option carries, so we own it and keep Zag off it.\n inputValue={allowCustomValue ? inputValue : undefined}\n onInputValueChange={({ inputValue: nextInputValue, reason }) => {\n setInputValue(nextInputValue);\n // The clear button empties `value` too, but a custom value never reached it, so Zag has\n // nothing to report — tell the consumer the field is empty now.\n if (reason === 'clear-trigger' && lastEmittedValue.current !== null) {\n lastEmittedValue.current = null;\n onValueChange?.(undefined);\n }\n // Only what the user types filters the list. Zag also writes the selected item's label\n // into the input, which would otherwise narrow the menu to that one item.\n setFilterText(reason === 'input-change' ? nextInputValue : '');\n }}\n onOpenChange={({ open }) => {\n setIsOpen(open);\n if (!open) commitCustomValue();\n }}\n onValueChange={(details) => {\n const next = details.value[0];\n // `selectionBehavior=\"preserve\"` leaves the input alone, so put the option's label there.\n if (allowCustomValue) setInputValue(next ? (items.find((item) => item.value === next)?.label ?? next) : '');\n // The clear path above already reported the empty field.\n if (next === undefined && lastEmittedValue.current === null) return;\n lastEmittedValue.current = next ?? null;\n onValueChange?.(next);\n }}\n open={isOpen}\n openOnClick\n readOnly={state === 'readOnly'}\n // Bypass Zag's isScrollable(contentEl) gate — our Content is overflow:hidden flex\n // column, so the real scroll container is itemList. See BitkitMultiselect for why.\n scrollToIndexFn={({ getElement }) => getElement()?.scrollIntoView({ block: 'nearest' })}\n selectionBehavior={allowCustomValue ? 'preserve' : undefined}\n size={size}\n // Stay controlled whenever `value` is provided — including `''` (\"nothing selected\"). A\n // truthiness check (`value ? … : undefined`) passes `undefined` for `''`, which flips\n // Combobox.Root to uncontrolled: it then ignores `value`, so resets don't take and\n // onValueChange stops firing when the same option is re-selected.\n value={value === undefined ? undefined : value ? [value] : []}\n >\n <Combobox.Control className=\"group\">\n <Combobox.Input\n onBlur={commitCustomValue}\n onKeyDown={(event) => {\n // Zag's Enter selects the highlighted item and does nothing when there is none, so\n // free text would just sit in an open menu. Commit it and close.\n if (!allowCustomValue || event.key !== 'Enter') return;\n if (event.currentTarget.getAttribute('aria-activedescendant')) return;\n commitCustomValue();\n setIsOpen(false);\n }}\n onFocus={() => {\n if (skipFocusOpen.current || !isInteractive) return;\n setIsOpen(true);\n }}\n placeholder={placeholder}\n />\n <Combobox.IndicatorGroup>\n {/* Zag hides the clear button until an option is selected; the design shows it for\n anything the field holds, including text that matches nothing yet. */}\n <Combobox.ClearTrigger asChild hidden={!isInteractive || (!inputValue && !value)}>\n <BitkitCloseButton size=\"sm\" />\n </Combobox.ClearTrigger>\n {statusIcon}\n <Combobox.Trigger\n asChild\n onPointerDown={() => {\n skipFocusOpen.current = true;\n requestAnimationFrame(() => {\n skipFocusOpen.current = false;\n });\n }}\n >\n <AssetSelectChevron />\n </Combobox.Trigger>\n </Combobox.IndicatorGroup>\n </Combobox.Control>\n <Portal disabled={disablePortal || disablePortalFromContext}>\n <Combobox.Positioner>\n <BitkitSelectMenu\n collection={collection}\n emptyHelperText={emptyHelperText}\n emptyLabel={emptyLabel}\n isLoading={isLoading}\n onScrolledToBottom={onScrolledToBottom}\n size={size}\n variant=\"combobox\"\n >\n {children}\n </BitkitSelectMenu>\n </Combobox.Positioner>\n </Portal>\n </Combobox.Root>\n );\n};\n\nexport default withSubComponents(BitkitCombobox, { Action: BitkitSelectMenuAction });\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const comboboxSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "input" | "label" | "list" | "root" | "item" | "itemIndicator" | "trigger" | "positioner" | "itemGroup" | "itemGroupLabel" | "itemText" | "clearTrigger" | "control" | "
|
|
1
|
+
declare const comboboxSlotRecipe: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "input" | "label" | "list" | "root" | "item" | "itemIndicator" | "trigger" | "positioner" | "itemGroup" | "itemGroupLabel" | "itemText" | "clearTrigger" | "control" | "indicatorGroup" | "empty", {
|
|
2
2
|
size: {
|
|
3
3
|
md: {
|
|
4
4
|
item: {
|
|
@@ -5,7 +5,7 @@ import { comboboxAnatomy } from "@chakra-ui/react/anatomy";
|
|
|
5
5
|
//#region lib/theme/slot-recipes/Combobox.recipe.ts
|
|
6
6
|
var comboboxSlotRecipe = defineSlotRecipe({
|
|
7
7
|
className: "combobox",
|
|
8
|
-
slots:
|
|
8
|
+
slots: comboboxAnatomy.keys(),
|
|
9
9
|
base: {
|
|
10
10
|
control: {
|
|
11
11
|
display: "flex",
|
|
@@ -18,15 +18,6 @@ var comboboxSlotRecipe = defineSlotRecipe({
|
|
|
18
18
|
height: "var(--input-height)",
|
|
19
19
|
textOverflow: "ellipsis"
|
|
20
20
|
},
|
|
21
|
-
empty: {
|
|
22
|
-
paddingInline: "16",
|
|
23
|
-
paddingBlock: "8",
|
|
24
|
-
textStyle: "body/lg/regular"
|
|
25
|
-
},
|
|
26
|
-
emptyHelperText: {
|
|
27
|
-
color: "text/helper",
|
|
28
|
-
textStyle: "body/sm/regular"
|
|
29
|
-
},
|
|
30
21
|
...base$1,
|
|
31
22
|
indicatorGroup: {
|
|
32
23
|
display: "flex",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/Combobox.recipe.ts"],"sourcesContent":["import { comboboxAnatomy } from '@chakra-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { base, variants } from '../common/ComboboxAndSelect.common';\nimport * as inputStyle from '../common/InputAndTextarea.common';\n\nconst comboboxSlotRecipe = defineSlotRecipe({\n className: 'combobox',\n slots:
|
|
1
|
+
{"version":3,"file":"Combobox.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/Combobox.recipe.ts"],"sourcesContent":["import { comboboxAnatomy } from '@chakra-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { base, variants } from '../common/ComboboxAndSelect.common';\nimport * as inputStyle from '../common/InputAndTextarea.common';\n\nconst comboboxSlotRecipe = defineSlotRecipe({\n className: 'combobox',\n slots: comboboxAnatomy.keys(),\n base: {\n control: {\n display: 'flex',\n alignItems: 'center',\n position: 'relative',\n },\n input: {\n ...inputStyle.base,\n ...inputStyle.singleLineInputOverrides,\n height: 'var(--input-height)',\n textOverflow: 'ellipsis',\n },\n ...base,\n indicatorGroup: {\n display: 'flex',\n alignItems: 'center',\n gap: '8',\n position: 'absolute',\n right: '16',\n top: '50%',\n transform: 'translateY(-50%)',\n },\n },\n variants: {\n size: {\n md: {\n input: {\n ...inputStyle.variants.size.md,\n ...inputStyle.singleLineInputOverrides,\n paddingInlineEnd: '96',\n },\n ...variants.size.md,\n },\n lg: {\n input: {\n ...inputStyle.variants.size.lg,\n ...inputStyle.singleLineInputOverrides,\n paddingInlineEnd: '96',\n },\n ...variants.size.lg,\n },\n },\n hasStatusIcon: {\n true: {\n input: {\n paddingInlineEnd: '128',\n },\n },\n false: {},\n },\n },\n defaultVariants: {\n size: 'lg',\n },\n});\n\nexport default comboboxSlotRecipe;\n"],"mappings":";;;;;AAMA,IAAM,qBAAqB,iBAAiB;CAC1C,WAAW;CACX,OAAO,gBAAgB,KAAK;CAC5B,MAAM;EACJ,SAAS;GACP,SAAS;GACT,YAAY;GACZ,UAAU;EACZ;EACA,OAAO;GACL,GAAG;GACH,GAAG;GACH,QAAQ;GACR,cAAc;EAChB;EACA,GAAG;EACH,gBAAgB;GACd,SAAS;GACT,YAAY;GACZ,KAAK;GACL,UAAU;GACV,OAAO;GACP,KAAK;GACL,WAAW;EACb;CACF;CACA,UAAU;EACR,MAAM;GACJ,IAAI;IACF,OAAO;KACL,GAAA,SAAuB,KAAK;KAC5B,GAAG;KACH,kBAAkB;IACpB;IACA,GAAG,WAAS,KAAK;GACnB;GACA,IAAI;IACF,OAAO;KACL,GAAA,SAAuB,KAAK;KAC5B,GAAG;KACH,kBAAkB;IACpB;IACA,GAAG,WAAS,KAAK;GACnB;EACF;EACA,eAAe;GACb,MAAM,EACJ,OAAO,EACL,kBAAkB,MACpB,EACF;GACA,OAAO,CAAC;EACV;CACF;CACA,iBAAiB,EACf,MAAM,KACR;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageHeader.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/PageHeader.recipe.ts"],"sourcesContent":["import { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\n/**\n * The collapsed single-row layout, shared by `variant=\"minimal\"` and `isSticky`. Both apply the\n * exact same overrides, so the two variants are idempotent when combined. The expanded layout\n * lives in `base` — `variant=\"default\"` and `isSticky: false` deliberately define nothing, so\n * neither can undo the other's collapse.\n *\n * Every override is scoped to `tablet` and up, with no `base` key: below the breakpoint the `base`\n * styles win and the header stays expanded. The mobile Figma frame has no sticky or minimal\n * variant — it always shows the title as a heading — and a single 72px row cannot hold a\n * breadcrumb plus full-width actions at 375px.\n *\n * The slots the collapsed row drops are hidden here rather than omitted from the DOM, so the\n * component never has to know the viewport: no breakpoint hook, and no wrong-layout first paint.\n */\nconst collapsedSlots = {\n headerBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '24',\n // No 72 in the size scale — the design fixes the collapsed row height.\n minHeight: rem(72),\n paddingBlockEnd: '12',\n paddingBlockStart: '12',\n paddingInlineEnd: '32',\n paddingInlineStart: '24',\n },\n },\n breadcrumb: {\n tablet: {\n flex: '0 1 auto',\n minWidth: 0,\n },\n },\n contentBlock: {\n tablet: {\n alignItems: 'center',\n flex: '1 0 0',\n // 24 between the title and the actions, per `pageType=main, isSticky=true`. The 8 belongs to\n // `actionBlock`, between the buttons.\n gap: '24',\n justifyContent: 'flex-end',\n minWidth: 0,\n },\n },\n titleBlock: {\n tablet: {\n alignItems: 'center',\n },\n },\n title: {\n tablet: {\n textStyle: 'heading/h3',\n },\n },\n actionBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '8',\n width: 'auto',\n },\n },\n avatar: {\n tablet: { display: 'none' },\n },\n badge: {\n tablet: { display: 'none' },\n },\n secondaryText: {\n tablet: { display: 'none' },\n },\n tabs: {\n tablet: { display: 'none' },\n },\n} as const;\n\n/**\n * Collapsed *and* carrying a breadcrumb: the trail shows the title as its current item, so the\n * heading would duplicate it. `Breadcrumb.CurrentLink` is a link and not a heading, so the block is\n * made screen-reader-only instead of hidden — that keeps exactly one `h1` on the page at every\n * width without a second, conditionally rendered heading node.\n */\nconst titleInBreadcrumb = {\n titleBlock: { tablet: { srOnly: true } },\n // The row is trail + actions. The actions cannot shrink, so leaving `contentBlock` on a zero\n // basis let a long trail take the whole row and collapse it to width 0 — the buttons then\n // overflowed their own box and painted on top of the trail. Sizing the actions to their content\n // and letting the trail take what is left makes the trail yield, and its last crumb ellipsise.\n breadcrumb: { tablet: { flex: '1 1 auto' } },\n // `width: auto` matters as much as the flex here, for the same reason it does in `controlsRow`:\n // the base width is `100%`, which flex-basis `auto` resolves to, so without it this block claims\n // the whole row and squeezes the trail to nothing.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * `minimal` *with* inline controls: the row carries three groups — trail, controls, actions — spread\n * apart rather than the usual trail-left/actions-right pair. `contentBlock` gives up its `flex: 1`\n * so `space-between` has room to distribute; without that it would absorb the free space and pin\n * the controls against the actions.\n *\n * Paired with both collapse modes, since `minimal` and `isSticky` produce the same row through\n * `collapsedSlots` — pairing it with `minimal` alone left the sticky row dropping the middle group.\n * This is the row the design file calls `PageHeader-WFE`.\n */\nconst controlsRow = {\n headerBlock: { tablet: { justifyContent: 'space-between' } },\n // `width: auto` matters as much as the flex: the base width is `100%`, which flex-basis `auto`\n // resolves to, so the block would otherwise claim the whole row and shrink the trail until its\n // metadata truncated away. Sized to its actions instead, leaving the free space to distribute.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * Collapsed with inline controls but no trail: the title takes the left slot, so the three groups\n * are the title, the controls and the actions — all inside `contentBlock`, which already spans the\n * row. The title block gives up its `flex: 1` so `space-between` has free space to distribute; left\n * growing, it would absorb the row and shove the controls against the actions.\n */\nconst controlsWithoutTrail = {\n contentBlock: { tablet: { justifyContent: 'space-between' } },\n titleBlock: { tablet: { flex: '0 1 auto' } },\n} as const;\n\n/**\n * Shared by the `app` and `user` content shapes — a larger avatar centred against a smaller title\n * and 14px secondary text. The two differ only in the avatar-to-text gap.\n */\nconst entityContent = {\n titleBlock: {\n alignItems: 'center',\n },\n title: {\n textStyle: { base: 'heading/mobile/h2', tablet: 'heading/h2' },\n },\n secondaryText: {\n textStyle: 'body/md/regular',\n },\n} as const;\n\nconst pageHeaderSlotRecipe = defineSlotRecipe({\n className: 'page-header',\n slots: [\n 'root',\n 'headerBlock',\n 'breadcrumb',\n 'controls',\n 'contentBlock',\n 'titleBlock',\n 'avatar',\n 'textBlock',\n 'titleRow',\n 'title',\n 'badge',\n 'secondaryText',\n 'actionBlock',\n 'tabs',\n ] as const,\n base: {\n root: {\n background: 'background/primary',\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n headerBlock: {\n alignItems: 'flex-start',\n display: 'flex',\n flexDirection: 'column',\n gap: { base: '16', tablet: '24' },\n paddingBlockEnd: { base: '16', tablet: '24' },\n paddingBlockStart: { base: '16', tablet: '24' },\n paddingInlineEnd: { base: '16', tablet: '32' },\n paddingInlineStart: { base: '16', tablet: '24' },\n width: '100%',\n },\n breadcrumb: {\n display: 'flex',\n maxWidth: '100%',\n minWidth: 0,\n // The trail's list is `white-space: nowrap`, so without this a long one escapes the header's\n // right edge instead of being clipped by it. `BitkitBreadcrumb` ellipsises its last crumb on\n // its own, but only once it is allowed to shrink — see the `breadcrumb` prop docs.\n overflow: 'hidden',\n },\n controls: {\n alignItems: 'center',\n display: 'flex',\n flexShrink: 0,\n },\n contentBlock: {\n alignItems: { base: 'flex-start', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column', tablet: 'row' },\n gap: { base: '16', tablet: '32' },\n width: '100%',\n },\n titleBlock: {\n display: 'flex',\n flex: '1 0 0',\n minWidth: 0,\n },\n avatar: {\n display: 'flex',\n flexShrink: 0,\n },\n textBlock: {\n display: 'flex',\n flexDirection: 'column',\n minWidth: 0,\n },\n titleRow: {\n alignItems: 'center',\n display: 'flex',\n gap: '12',\n minWidth: 0,\n paddingInlineEnd: { base: '0', tablet: '24' },\n },\n title: {\n color: 'text/primary',\n minWidth: 0,\n textStyle: { base: 'heading/mobile/h1', tablet: 'heading/h1' },\n // One line with an ellipsis rather than wrapping. A wrapped title grew the header without\n // limit, and the collapsed row is a fixed 72px that a second line would break. The component\n // pairs this with `BitkitOverflowTooltip` so the full string stays readable.\n truncate: true,\n },\n badge: {\n display: 'flex',\n flexShrink: 0,\n // The design nudges the badge below the optical centre of the title line, wrapping it in\n // `flex-col h-full justify-center pt-8`. Reproduced with the same mechanism rather than a\n // fixed offset: the row centres the margin box, so this lands the badge `8 / 2` lower —\n // 12px down a 40px desktop line and 10px down a 36px mobile one, matching both frames.\n marginBlockStart: '8',\n },\n secondaryText: {\n color: 'text/secondary',\n textStyle: 'body/lg/regular',\n truncate: true,\n },\n actionBlock: {\n // The design puts the primary action on top once the actions stack, so `base` reverses them\n // visually while the DOM keeps its secondary-then-primary order for the row layout.\n //\n // That mismatch is deliberate and settled — please don't \"fix\" it. Actions arrive as an opaque\n // `children` list, so with one DOM order and two visual orders, no arrangement satisfies both\n // breakpoints; flipping the DOM only moves the mismatch to the row. The alternatives are a\n // design change or a structured actions API, and neither earns its cost: the surviving case is\n // a zoomed desktop window rendering `base`, where focus steps up rather than down between two\n // adjacent buttons and nothing becomes unreachable. Chasing visual order through the DOM is\n // also a pattern the design system avoids. v1 ships the same behaviour in `SubHeader.tsx:96`.\n alignItems: { base: 'stretch', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column-reverse', tablet: 'row' },\n flexShrink: 0,\n gap: '12',\n justifyContent: 'flex-end',\n width: { base: '100%', tablet: 'auto' },\n },\n tabs: {\n // The tab list draws its own bottom border, inset by this padding. Pulling the row up by 1px\n // lands it exactly on the root's border instead of stacking a second line above it, so the\n // header keeps one full-width bottom edge as designed.\n marginBlockEnd: rem(-1),\n paddingInlineEnd: { base: '0', tablet: '32' },\n paddingInlineStart: { base: '0', tablet: '16' },\n width: '100%',\n },\n },\n compoundVariants: [\n { hasBreadcrumb: true, variant: 'minimal', css: titleInBreadcrumb },\n { hasBreadcrumb: true, isSticky: true, css: titleInBreadcrumb },\n { hasBreadcrumb: true, hasControls: true, variant: 'minimal', css: controlsRow },\n { hasBreadcrumb: true, hasControls: true, isSticky: true, css: controlsRow },\n { hasBreadcrumb: false, hasControls: true, variant: 'minimal', css: controlsWithoutTrail },\n { hasBreadcrumb: false, hasControls: true, isSticky: true, css: controlsWithoutTrail },\n ],\n variants: {\n contentVariant: {\n title: {\n titleBlock: {\n // `center` rather than the design's `flex-end`. With no secondary text the two are\n // identical — a 40px avatar against a 40px title line — so the bare sub-page card is\n // unaffected. With secondary text present, `flex-end` dropped the avatar down beside it;\n // centring matches how the app card sits its avatar against a two-line block.\n alignItems: 'center',\n gap: '12',\n },\n textBlock: {\n gap: '4',\n },\n },\n // `app` and `user` differ only in the gap between the avatar and the text — 16 and 12\n // respectively — so they share everything else via `entityContent`.\n app: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '16',\n },\n },\n user: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '12',\n },\n },\n },\n // Mobile splits the trail into its own `breadcrumb-margin` block (`pt-24 px-16`) above a\n // `p-16` header block, so the breadcrumb sits 24 from the top rather than 16. Desktop is 24\n // either way, hence the flat value.\n hasBreadcrumb: {\n true: {\n headerBlock: {\n paddingBlockStart: '24',\n },\n },\n false: {},\n },\n hasControls: {\n true: {},\n false: {},\n },\n isSticky: {\n true: {\n root: {\n // Scoped to `tablet` like the layout overrides: below the breakpoint `isSticky` is\n // ignored entirely, so the expanded header must not pick up the stuck chrome either.\n tablet: {\n borderColor: 'border/minimal',\n boxShadow: 'elevation/sm',\n },\n },\n ...collapsedSlots,\n },\n false: {},\n },\n variant: {\n default: {},\n minimal: collapsedSlots,\n },\n },\n defaultVariants: {\n contentVariant: 'title',\n hasBreadcrumb: false,\n hasControls: false,\n isSticky: false,\n variant: 'default',\n },\n});\n\nexport default pageHeaderSlotRecipe;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PageHeader.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/PageHeader.recipe.ts"],"sourcesContent":["import { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\n/**\n * The collapsed single-row layout, shared by `variant=\"minimal\"` and `isSticky`. Both apply the\n * exact same overrides, so the two variants are idempotent when combined. The expanded layout\n * lives in `base` — `variant=\"default\"` and `isSticky: false` deliberately define nothing, so\n * neither can undo the other's collapse.\n *\n * Every override is scoped to `tablet` and up, with no `base` key: below the breakpoint the `base`\n * styles win and the header stays expanded. The mobile Figma frame has no sticky or minimal\n * variant — it always shows the title as a heading — and a single 72px row cannot hold a\n * breadcrumb plus full-width actions at 375px.\n *\n * The slots the collapsed row drops are hidden here rather than omitted from the DOM, so the\n * component never has to know the viewport: no breakpoint hook, and no wrong-layout first paint.\n */\nconst collapsedSlots = {\n headerBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '24',\n // No 72 in the size scale — the design fixes the collapsed row height.\n minHeight: rem(72),\n paddingBlockEnd: '12',\n paddingBlockStart: '12',\n paddingInlineEnd: '32',\n paddingInlineStart: '24',\n },\n },\n breadcrumb: {\n tablet: {\n flex: '0 1 auto',\n minWidth: 0,\n },\n },\n contentBlock: {\n tablet: {\n alignItems: 'center',\n flex: '1 0 0',\n // 24 between the title and the actions, per `pageType=main, isSticky=true`. The 8 belongs to\n // `actionBlock`, between the buttons.\n gap: '24',\n justifyContent: 'flex-end',\n minWidth: 0,\n },\n },\n titleBlock: {\n tablet: {\n alignItems: 'center',\n },\n },\n title: {\n tablet: {\n textStyle: 'heading/h3',\n },\n },\n actionBlock: {\n tablet: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: '8',\n width: 'auto',\n },\n },\n avatar: {\n tablet: { display: 'none' },\n },\n badge: {\n tablet: { display: 'none' },\n },\n secondaryText: {\n tablet: { display: 'none' },\n },\n tabs: {\n tablet: { display: 'none' },\n },\n} as const;\n\n/**\n * Collapsed *and* carrying a breadcrumb: the trail shows the title as its current item, so the\n * heading would duplicate it. `Breadcrumb.CurrentLink` is a link and not a heading, so the block is\n * made screen-reader-only instead of hidden — that keeps exactly one `h1` on the page at every\n * width without a second, conditionally rendered heading node.\n */\nconst titleInBreadcrumb = {\n titleBlock: { tablet: { srOnly: true } },\n // The row is trail + actions. The actions cannot shrink, so leaving `contentBlock` on a zero\n // basis let a long trail take the whole row and collapse it to width 0 — the buttons then\n // overflowed their own box and painted on top of the trail. Sizing the actions to their content\n // and letting the trail take what is left makes the trail yield, and its last crumb ellipsise.\n breadcrumb: { tablet: { flex: '1 1 auto' } },\n // `width: auto` matters as much as the flex here, for the same reason it does in `controlsRow`:\n // the base width is `100%`, which flex-basis `auto` resolves to, so without it this block claims\n // the whole row and squeezes the trail to nothing.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * `minimal` *with* inline controls: the row carries three groups — trail, controls, actions — spread\n * apart rather than the usual trail-left/actions-right pair. `contentBlock` gives up its `flex: 1`\n * so `space-between` has room to distribute; without that it would absorb the free space and pin\n * the controls against the actions.\n *\n * Paired with both collapse modes, since `minimal` and `isSticky` produce the same row through\n * `collapsedSlots` — pairing it with `minimal` alone left the sticky row dropping the middle group.\n * This is the row the design file calls `PageHeader-WFE`.\n */\nconst controlsRow = {\n headerBlock: { tablet: { justifyContent: 'space-between' } },\n // Undoes the `flex: 1 1 auto` that `titleInBreadcrumb` gives the trail. That growth is right for\n // the two-group row (trail + actions), but here a third group sits between them: a growing trail\n // swallows all the free space on its side and shoves the controls island against the actions.\n // Shrink-only keeps the trail ellipsising when the row is tight, while `space-between` gets free\n // space to distribute.\n breadcrumb: { tablet: { flex: '0 1 auto' } },\n // `width: auto` matters as much as the flex: the base width is `100%`, which flex-basis `auto`\n // resolves to, so the block would otherwise claim the whole row and shrink the trail until its\n // metadata truncated away. Sized to its actions instead, leaving the free space to distribute.\n contentBlock: { tablet: { flex: '0 0 auto', width: 'auto' } },\n} as const;\n\n/**\n * Collapsed with inline controls but no trail: the title takes the left slot, so the three groups\n * are the title, the controls and the actions — all inside `contentBlock`, which already spans the\n * row. The title block gives up its `flex: 1` so `space-between` has free space to distribute; left\n * growing, it would absorb the row and shove the controls against the actions.\n */\nconst controlsWithoutTrail = {\n contentBlock: { tablet: { justifyContent: 'space-between' } },\n titleBlock: { tablet: { flex: '0 1 auto' } },\n} as const;\n\n/**\n * Shared by the `app` and `user` content shapes — a larger avatar centred against a smaller title\n * and 14px secondary text. The two differ only in the avatar-to-text gap.\n */\nconst entityContent = {\n titleBlock: {\n alignItems: 'center',\n },\n title: {\n textStyle: { base: 'heading/mobile/h2', tablet: 'heading/h2' },\n },\n secondaryText: {\n textStyle: 'body/md/regular',\n },\n} as const;\n\nconst pageHeaderSlotRecipe = defineSlotRecipe({\n className: 'page-header',\n slots: [\n 'root',\n 'headerBlock',\n 'breadcrumb',\n 'controls',\n 'contentBlock',\n 'titleBlock',\n 'avatar',\n 'textBlock',\n 'titleRow',\n 'title',\n 'badge',\n 'secondaryText',\n 'actionBlock',\n 'tabs',\n ] as const,\n base: {\n root: {\n background: 'background/primary',\n borderBlockEnd: '1px solid',\n borderColor: 'border/regular',\n display: 'flex',\n flexDirection: 'column',\n width: '100%',\n },\n headerBlock: {\n alignItems: 'flex-start',\n display: 'flex',\n flexDirection: 'column',\n gap: { base: '16', tablet: '24' },\n paddingBlockEnd: { base: '16', tablet: '24' },\n paddingBlockStart: { base: '16', tablet: '24' },\n paddingInlineEnd: { base: '16', tablet: '32' },\n paddingInlineStart: { base: '16', tablet: '24' },\n width: '100%',\n },\n breadcrumb: {\n display: 'flex',\n maxWidth: '100%',\n minWidth: 0,\n // The trail's list is `white-space: nowrap`, so without this a long one escapes the header's\n // right edge instead of being clipped by it. `BitkitBreadcrumb` ellipsises its last crumb on\n // its own, but only once it is allowed to shrink — see the `breadcrumb` prop docs.\n overflow: 'hidden',\n },\n controls: {\n alignItems: 'center',\n display: 'flex',\n flexShrink: 0,\n },\n contentBlock: {\n alignItems: { base: 'flex-start', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column', tablet: 'row' },\n gap: { base: '16', tablet: '32' },\n width: '100%',\n },\n titleBlock: {\n display: 'flex',\n flex: '1 0 0',\n minWidth: 0,\n },\n avatar: {\n display: 'flex',\n flexShrink: 0,\n },\n textBlock: {\n display: 'flex',\n flexDirection: 'column',\n minWidth: 0,\n },\n titleRow: {\n alignItems: 'center',\n display: 'flex',\n gap: '12',\n minWidth: 0,\n paddingInlineEnd: { base: '0', tablet: '24' },\n },\n title: {\n color: 'text/primary',\n minWidth: 0,\n textStyle: { base: 'heading/mobile/h1', tablet: 'heading/h1' },\n // One line with an ellipsis rather than wrapping. A wrapped title grew the header without\n // limit, and the collapsed row is a fixed 72px that a second line would break. The component\n // pairs this with `BitkitOverflowTooltip` so the full string stays readable.\n truncate: true,\n },\n badge: {\n display: 'flex',\n flexShrink: 0,\n // The design nudges the badge below the optical centre of the title line, wrapping it in\n // `flex-col h-full justify-center pt-8`. Reproduced with the same mechanism rather than a\n // fixed offset: the row centres the margin box, so this lands the badge `8 / 2` lower —\n // 12px down a 40px desktop line and 10px down a 36px mobile one, matching both frames.\n marginBlockStart: '8',\n },\n secondaryText: {\n color: 'text/secondary',\n textStyle: 'body/lg/regular',\n truncate: true,\n },\n actionBlock: {\n // The design puts the primary action on top once the actions stack, so `base` reverses them\n // visually while the DOM keeps its secondary-then-primary order for the row layout.\n //\n // That mismatch is deliberate and settled — please don't \"fix\" it. Actions arrive as an opaque\n // `children` list, so with one DOM order and two visual orders, no arrangement satisfies both\n // breakpoints; flipping the DOM only moves the mismatch to the row. The alternatives are a\n // design change or a structured actions API, and neither earns its cost: the surviving case is\n // a zoomed desktop window rendering `base`, where focus steps up rather than down between two\n // adjacent buttons and nothing becomes unreachable. Chasing visual order through the DOM is\n // also a pattern the design system avoids. v1 ships the same behaviour in `SubHeader.tsx:96`.\n alignItems: { base: 'stretch', tablet: 'flex-end' },\n display: 'flex',\n flexDirection: { base: 'column-reverse', tablet: 'row' },\n flexShrink: 0,\n gap: '12',\n justifyContent: 'flex-end',\n width: { base: '100%', tablet: 'auto' },\n },\n tabs: {\n // The tab list draws its own bottom border, inset by this padding. Pulling the row up by 1px\n // lands it exactly on the root's border instead of stacking a second line above it, so the\n // header keeps one full-width bottom edge as designed.\n marginBlockEnd: rem(-1),\n paddingInlineEnd: { base: '0', tablet: '32' },\n paddingInlineStart: { base: '0', tablet: '16' },\n width: '100%',\n },\n },\n compoundVariants: [\n { hasBreadcrumb: true, variant: 'minimal', css: titleInBreadcrumb },\n { hasBreadcrumb: true, isSticky: true, css: titleInBreadcrumb },\n { hasBreadcrumb: true, hasControls: true, variant: 'minimal', css: controlsRow },\n { hasBreadcrumb: true, hasControls: true, isSticky: true, css: controlsRow },\n { hasBreadcrumb: false, hasControls: true, variant: 'minimal', css: controlsWithoutTrail },\n { hasBreadcrumb: false, hasControls: true, isSticky: true, css: controlsWithoutTrail },\n ],\n variants: {\n contentVariant: {\n title: {\n titleBlock: {\n // `center` rather than the design's `flex-end`. With no secondary text the two are\n // identical — a 40px avatar against a 40px title line — so the bare sub-page card is\n // unaffected. With secondary text present, `flex-end` dropped the avatar down beside it;\n // centring matches how the app card sits its avatar against a two-line block.\n alignItems: 'center',\n gap: '12',\n },\n textBlock: {\n gap: '4',\n },\n },\n // `app` and `user` differ only in the gap between the avatar and the text — 16 and 12\n // respectively — so they share everything else via `entityContent`.\n app: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '16',\n },\n },\n user: {\n ...entityContent,\n titleBlock: {\n ...entityContent.titleBlock,\n gap: '12',\n },\n },\n },\n // Mobile splits the trail into its own `breadcrumb-margin` block (`pt-24 px-16`) above a\n // `p-16` header block, so the breadcrumb sits 24 from the top rather than 16. Desktop is 24\n // either way, hence the flat value.\n hasBreadcrumb: {\n true: {\n headerBlock: {\n paddingBlockStart: '24',\n },\n },\n false: {},\n },\n hasControls: {\n true: {},\n false: {},\n },\n isSticky: {\n true: {\n root: {\n // Scoped to `tablet` like the layout overrides: below the breakpoint `isSticky` is\n // ignored entirely, so the expanded header must not pick up the stuck chrome either.\n tablet: {\n borderColor: 'border/minimal',\n boxShadow: 'elevation/sm',\n },\n },\n ...collapsedSlots,\n },\n false: {},\n },\n variant: {\n default: {},\n minimal: collapsedSlots,\n },\n },\n defaultVariants: {\n contentVariant: 'title',\n hasBreadcrumb: false,\n hasControls: false,\n isSticky: false,\n variant: 'default',\n },\n});\n\nexport default pageHeaderSlotRecipe;\n"],"mappings":"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"}
|
|
@@ -509,7 +509,7 @@ declare const slotRecipes: {
|
|
|
509
509
|
};
|
|
510
510
|
}>;
|
|
511
511
|
collapsible: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "root" | "trigger" | "indicator", import('@chakra-ui/react').SlotRecipeVariantRecord<"content" | "root" | "trigger" | "indicator">>;
|
|
512
|
-
combobox: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "input" | "label" | "list" | "root" | "item" | "itemIndicator" | "trigger" | "positioner" | "itemGroup" | "itemGroupLabel" | "itemText" | "clearTrigger" | "control" | "
|
|
512
|
+
combobox: import('@chakra-ui/react').SlotRecipeDefinition<"content" | "input" | "label" | "list" | "root" | "item" | "itemIndicator" | "trigger" | "positioner" | "itemGroup" | "itemGroupLabel" | "itemText" | "clearTrigger" | "control" | "indicatorGroup" | "empty", {
|
|
513
513
|
size: {
|
|
514
514
|
md: {
|
|
515
515
|
item: {
|