@bitrise/bitkit-v2 0.3.459 → 0.3.460-beta.2893

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 (48) hide show
  1. package/dist/components/BitkitMultiselectMenu/BitkitMultiselectMenu.d.ts +3 -3
  2. package/dist/components/BitkitMultiselectMenu/BitkitMultiselectMenu.js.map +1 -1
  3. package/dist/components/BitkitSelectMenu/BitkitSelectMenu.d.ts +7 -2
  4. package/dist/components/BitkitSelectMenu/BitkitSelectMenu.js.map +1 -1
  5. package/dist/components/BitkitSelectMenu/SelectMenuShell.d.ts +3 -3
  6. package/dist/components/BitkitSelectMenu/SelectMenuShell.js +23 -4
  7. package/dist/components/BitkitSelectMenu/SelectMenuShell.js.map +1 -1
  8. package/dist/components/BitkitUISideNav/BitkitUISideNav.d.ts +37 -0
  9. package/dist/components/BitkitUISideNav/BitkitUISideNav.js +126 -0
  10. package/dist/components/BitkitUISideNav/BitkitUISideNav.js.map +1 -0
  11. package/dist/components/BitkitUISideNav/UISideNavBody.d.ts +7 -0
  12. package/dist/components/BitkitUISideNav/UISideNavBody.js +20 -0
  13. package/dist/components/BitkitUISideNav/UISideNavBody.js.map +1 -0
  14. package/dist/components/BitkitUISideNav/UISideNavContext.d.ts +32 -0
  15. package/dist/components/BitkitUISideNav/UISideNavContext.js +28 -0
  16. package/dist/components/BitkitUISideNav/UISideNavContext.js.map +1 -0
  17. package/dist/components/BitkitUISideNav/UISideNavFooter.d.ts +16 -0
  18. package/dist/components/BitkitUISideNav/UISideNavFooter.js +28 -0
  19. package/dist/components/BitkitUISideNav/UISideNavFooter.js.map +1 -0
  20. package/dist/components/BitkitUISideNav/UISideNavFooterHeading.d.ts +12 -0
  21. package/dist/components/BitkitUISideNav/UISideNavFooterHeading.js +26 -0
  22. package/dist/components/BitkitUISideNav/UISideNavFooterHeading.js.map +1 -0
  23. package/dist/components/BitkitUISideNav/UISideNavItem.d.ts +26 -0
  24. package/dist/components/BitkitUISideNav/UISideNavItem.js +33 -0
  25. package/dist/components/BitkitUISideNav/UISideNavItem.js.map +1 -0
  26. package/dist/components/BitkitUISideNav/UISideNavLink.d.ts +30 -0
  27. package/dist/components/BitkitUISideNav/UISideNavLink.js +60 -0
  28. package/dist/components/BitkitUISideNav/UISideNavLink.js.map +1 -0
  29. package/dist/components/BitkitUISideNav/UISideNavWorkspaceSelector.d.ts +45 -0
  30. package/dist/components/BitkitUISideNav/UISideNavWorkspaceSelector.js +105 -0
  31. package/dist/components/BitkitUISideNav/UISideNavWorkspaceSelector.js.map +1 -0
  32. package/dist/components/index.d.ts +2 -0
  33. package/dist/main.js +4 -1
  34. package/dist/theme/semantic-tokens/index.d.ts +17 -2
  35. package/dist/theme/semantic-tokens/semanticColors.d.ts +17 -2
  36. package/dist/theme/semantic-tokens/semanticColors.js +5 -2
  37. package/dist/theme/semantic-tokens/semanticColors.js.map +1 -1
  38. package/dist/theme/slot-recipes/DatePickerSelect.recipe.d.ts +12 -0
  39. package/dist/theme/slot-recipes/Select.recipe.d.ts +19 -1
  40. package/dist/theme/slot-recipes/Select.recipe.js +36 -1
  41. package/dist/theme/slot-recipes/Select.recipe.js.map +1 -1
  42. package/dist/theme/slot-recipes/UISideNav.recipe.d.ts +117 -0
  43. package/dist/theme/slot-recipes/UISideNav.recipe.js +448 -0
  44. package/dist/theme/slot-recipes/UISideNav.recipe.js.map +1 -0
  45. package/dist/theme/slot-recipes/index.d.ts +141 -1
  46. package/dist/theme/slot-recipes/index.js +3 -1
  47. package/dist/theme/slot-recipes/index.js.map +1 -1
  48. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { ListCollection } from '@chakra-ui/react/collection';
2
2
  import { ReactNode } from 'react';
3
- import { BitkitSelectMenuEmptyStateProps, BitkitSelectMenuScrollProps, BitkitSelectMenuSearchProps } from '../BitkitSelectMenu/BitkitSelectMenu';
3
+ import { BitkitSelectMenuEmptyStateProps, BitkitSelectMenuErrorStateProps, BitkitSelectMenuScrollProps, BitkitSelectMenuSearchProps } from '../BitkitSelectMenu/BitkitSelectMenu';
4
4
  import { BitkitSelectMenuActionChild } from '../BitkitSelectMenu/BitkitSelectMenuAction';
5
5
  export type BitkitMultiselectMenuItemProps = {
6
6
  value: string;
@@ -15,11 +15,11 @@ export type BitkitMultiselectMenuProps = {
15
15
  collection: ListCollection<BitkitMultiselectMenuItemProps>;
16
16
  isLoading?: boolean;
17
17
  size?: 'md' | 'lg';
18
- } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps;
18
+ } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & BitkitSelectMenuErrorStateProps;
19
19
  declare const BitkitMultiselectMenu: import('react').ForwardRefExoticComponent<{
20
20
  children?: BitkitSelectMenuActionChild;
21
21
  collection: ListCollection<BitkitMultiselectMenuItemProps>;
22
22
  isLoading?: boolean;
23
23
  size?: "md" | "lg";
24
- } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & import('react').RefAttributes<HTMLDivElement>>;
24
+ } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & BitkitSelectMenuErrorStateProps & import('react').RefAttributes<HTMLDivElement>>;
25
25
  export default BitkitMultiselectMenu;
@@ -1 +1 @@
1
- {"version":3,"file":"BitkitMultiselectMenu.js","names":[],"sources":["../../../lib/components/BitkitMultiselectMenu/BitkitMultiselectMenu.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { type ListCollection } from '@chakra-ui/react/collection';\nimport { Select } from '@chakra-ui/react/select';\nimport { Spinner } from '@chakra-ui/react/spinner';\nimport { type SystemStyleObject, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { forwardRef, type ReactNode } from 'react';\n\nimport { IconCheck } from '../../icons';\nimport {\n type BitkitSelectMenuEmptyStateProps,\n type BitkitSelectMenuScrollProps,\n type BitkitSelectMenuSearchProps,\n} from '../BitkitSelectMenu/BitkitSelectMenu';\nimport { type BitkitSelectMenuActionChild } from '../BitkitSelectMenu/BitkitSelectMenuAction';\nimport { SelectMenuShell, selectSizeMap, type SelectSizes } from '../BitkitSelectMenu/SelectMenuShell';\n\nexport type BitkitMultiselectMenuItemProps = {\n value: string;\n label: string;\n group?: string;\n helperText?: ReactNode;\n disabled?: boolean;\n loading?: boolean;\n};\n\nexport type BitkitMultiselectMenuProps = {\n children?: BitkitSelectMenuActionChild;\n collection: ListCollection<BitkitMultiselectMenuItemProps>;\n isLoading?: boolean;\n size?: 'md' | 'lg';\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps;\n\nconst BitkitMultiselectMenu = forwardRef<HTMLDivElement, BitkitMultiselectMenuProps>((props, ref) => {\n const { children, collection, size, ...shellProps } = props;\n const recipe = useSlotRecipe({ key: 'select' });\n const styles = recipe({ size });\n const { iconSize, spinnerSize } = selectSizeMap[size ?? 'lg'];\n\n return (\n <SelectMenuShell\n NS={Select}\n collection={collection}\n contentRef={ref}\n iconSize={iconSize}\n renderItem={(item) => (\n <MultiselectMenuItem\n key={item.value}\n item={item}\n iconSize={iconSize}\n spinnerSize={spinnerSize}\n styles={styles}\n />\n )}\n spinnerSize={spinnerSize}\n styles={styles}\n {...shellProps}\n >\n {children}\n </SelectMenuShell>\n );\n});\n\nBitkitMultiselectMenu.displayName = 'BitkitMultiselectMenu';\n\ntype MultiselectMenuItemRenderProps = {\n item: BitkitMultiselectMenuItemProps;\n iconSize: SelectSizes['iconSize'];\n spinnerSize: SelectSizes['spinnerSize'];\n styles: Record<string, SystemStyleObject>;\n};\n\nconst MultiselectMenuItem = ({ item, iconSize, spinnerSize, styles }: MultiselectMenuItemRenderProps) => {\n if (item.loading) {\n // Rendered as a plain Box, not Select.Item — Zag's state machine won't track it\n // as an option, so keyboard nav skips it and it can't be selected.\n return (\n <Box css={styles.item}>\n <Spinner variant=\"purple\" size={spinnerSize} css={styles.itemLoading} />\n <Text css={styles.itemLoadingLabel}>Loading...</Text>\n </Box>\n );\n }\n\n return (\n <Select.Item css={styles.item} item={item}>\n <Box css={styles.checkbox} data-slot=\"checkbox\">\n <IconCheck size={iconSize} css={styles.checkmark} data-slot=\"checkmark\" />\n </Box>\n <Box css={styles.itemContent}>\n <Text css={styles.itemLabel}>{item.label}</Text>\n {item.helperText && <Text css={styles.itemHelperText}>{item.helperText}</Text>}\n </Box>\n </Select.Item>\n );\n};\n\nexport default BitkitMultiselectMenu;\n"],"mappings":";;;;;;;;;;AAmCA,IAAM,wBAAwB,YAAwD,OAAO,QAAQ;CACnG,MAAM,EAAE,UAAU,YAAY,MAAM,GAAG,eAAe;CAEtD,MAAM,SADS,cAAc,EAAE,KAAK,SAAS,CAC9B,CAAA,CAAO,EAAE,KAAK,CAAC;CAC9B,MAAM,EAAE,UAAU,gBAAgB,cAAc,QAAQ;CAExD,OACE,oBAAC,iBAAD;EACE,IAAI;EACQ;EACZ,YAAY;EACF;EACV,aAAa,SACX,oBAAC,qBAAD;GAEQ;GACI;GACG;GACL;EACT,GALM,KAAK,KAKX;EAEU;EACL;EACR,GAAI;EAEH;CACc,CAAA;AAErB,CAAC;AAED,sBAAsB,cAAc;AASpC,IAAM,uBAAuB,EAAE,MAAM,UAAU,aAAa,aAA6C;CACvG,IAAI,KAAK,SAGP,OACE,qBAAC,KAAD;EAAK,KAAK,OAAO;EAAjB,UAAA,CACE,oBAAC,SAAD;GAAS,SAAQ;GAAS,MAAM;GAAa,KAAK,OAAO;EAAc,CAAA,GACvE,oBAAC,MAAD;GAAM,KAAK,OAAO;GAAkB,UAAA;EAAgB,CAAA,CACjD;;CAIT,OACE,qBAAC,OAAO,MAAR;EAAa,KAAK,OAAO;EAAY;EAArC,UAAA,CACE,oBAAC,KAAD;GAAK,KAAK,OAAO;GAAU,aAAU;GACnC,UAAA,oBAAC,WAAD;IAAW,MAAM;IAAU,KAAK,OAAO;IAAW,aAAU;GAAa,CAAA;EACtE,CAAA,GACL,qBAAC,KAAD;GAAK,KAAK,OAAO;GAAjB,UAAA,CACE,oBAAC,MAAD;IAAM,KAAK,OAAO;IAAY,UAAA,KAAK;GAAY,CAAA,GAC9C,KAAK,cAAc,oBAAC,MAAD;IAAM,KAAK,OAAO;IAAiB,UAAA,KAAK;GAAiB,CAAA,CAC1E;EACM,CAAA,CAAA;;AAEjB"}
1
+ {"version":3,"file":"BitkitMultiselectMenu.js","names":[],"sources":["../../../lib/components/BitkitMultiselectMenu/BitkitMultiselectMenu.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { type ListCollection } from '@chakra-ui/react/collection';\nimport { Select } from '@chakra-ui/react/select';\nimport { Spinner } from '@chakra-ui/react/spinner';\nimport { type SystemStyleObject, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { forwardRef, type ReactNode } from 'react';\n\nimport { IconCheck } from '../../icons';\nimport {\n type BitkitSelectMenuEmptyStateProps,\n type BitkitSelectMenuErrorStateProps,\n type BitkitSelectMenuScrollProps,\n type BitkitSelectMenuSearchProps,\n} from '../BitkitSelectMenu/BitkitSelectMenu';\nimport { type BitkitSelectMenuActionChild } from '../BitkitSelectMenu/BitkitSelectMenuAction';\nimport { SelectMenuShell, selectSizeMap, type SelectSizes } from '../BitkitSelectMenu/SelectMenuShell';\n\nexport type BitkitMultiselectMenuItemProps = {\n value: string;\n label: string;\n group?: string;\n helperText?: ReactNode;\n disabled?: boolean;\n loading?: boolean;\n};\n\nexport type BitkitMultiselectMenuProps = {\n children?: BitkitSelectMenuActionChild;\n collection: ListCollection<BitkitMultiselectMenuItemProps>;\n isLoading?: boolean;\n size?: 'md' | 'lg';\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps &\n BitkitSelectMenuErrorStateProps;\n\nconst BitkitMultiselectMenu = forwardRef<HTMLDivElement, BitkitMultiselectMenuProps>((props, ref) => {\n const { children, collection, size, ...shellProps } = props;\n const recipe = useSlotRecipe({ key: 'select' });\n const styles = recipe({ size });\n const { iconSize, spinnerSize } = selectSizeMap[size ?? 'lg'];\n\n return (\n <SelectMenuShell\n NS={Select}\n collection={collection}\n contentRef={ref}\n iconSize={iconSize}\n renderItem={(item) => (\n <MultiselectMenuItem\n key={item.value}\n item={item}\n iconSize={iconSize}\n spinnerSize={spinnerSize}\n styles={styles}\n />\n )}\n spinnerSize={spinnerSize}\n styles={styles}\n {...shellProps}\n >\n {children}\n </SelectMenuShell>\n );\n});\n\nBitkitMultiselectMenu.displayName = 'BitkitMultiselectMenu';\n\ntype MultiselectMenuItemRenderProps = {\n item: BitkitMultiselectMenuItemProps;\n iconSize: SelectSizes['iconSize'];\n spinnerSize: SelectSizes['spinnerSize'];\n styles: Record<string, SystemStyleObject>;\n};\n\nconst MultiselectMenuItem = ({ item, iconSize, spinnerSize, styles }: MultiselectMenuItemRenderProps) => {\n if (item.loading) {\n // Rendered as a plain Box, not Select.Item — Zag's state machine won't track it\n // as an option, so keyboard nav skips it and it can't be selected.\n return (\n <Box css={styles.item}>\n <Spinner variant=\"purple\" size={spinnerSize} css={styles.itemLoading} />\n <Text css={styles.itemLoadingLabel}>Loading...</Text>\n </Box>\n );\n }\n\n return (\n <Select.Item css={styles.item} item={item}>\n <Box css={styles.checkbox} data-slot=\"checkbox\">\n <IconCheck size={iconSize} css={styles.checkmark} data-slot=\"checkmark\" />\n </Box>\n <Box css={styles.itemContent}>\n <Text css={styles.itemLabel}>{item.label}</Text>\n {item.helperText && <Text css={styles.itemHelperText}>{item.helperText}</Text>}\n </Box>\n </Select.Item>\n );\n};\n\nexport default BitkitMultiselectMenu;\n"],"mappings":";;;;;;;;;;AAqCA,IAAM,wBAAwB,YAAwD,OAAO,QAAQ;CACnG,MAAM,EAAE,UAAU,YAAY,MAAM,GAAG,eAAe;CAEtD,MAAM,SADS,cAAc,EAAE,KAAK,SAAS,CAC9B,CAAA,CAAO,EAAE,KAAK,CAAC;CAC9B,MAAM,EAAE,UAAU,gBAAgB,cAAc,QAAQ;CAExD,OACE,oBAAC,iBAAD;EACE,IAAI;EACQ;EACZ,YAAY;EACF;EACV,aAAa,SACX,oBAAC,qBAAD;GAEQ;GACI;GACG;GACL;EACT,GALM,KAAK,KAKX;EAEU;EACL;EACR,GAAI;EAEH;CACc,CAAA;AAErB,CAAC;AAED,sBAAsB,cAAc;AASpC,IAAM,uBAAuB,EAAE,MAAM,UAAU,aAAa,aAA6C;CACvG,IAAI,KAAK,SAGP,OACE,qBAAC,KAAD;EAAK,KAAK,OAAO;EAAjB,UAAA,CACE,oBAAC,SAAD;GAAS,SAAQ;GAAS,MAAM;GAAa,KAAK,OAAO;EAAc,CAAA,GACvE,oBAAC,MAAD;GAAM,KAAK,OAAO;GAAkB,UAAA;EAAgB,CAAA,CACjD;;CAIT,OACE,qBAAC,OAAO,MAAR;EAAa,KAAK,OAAO;EAAY;EAArC,UAAA,CACE,oBAAC,KAAD;GAAK,KAAK,OAAO;GAAU,aAAU;GACnC,UAAA,oBAAC,WAAD;IAAW,MAAM;IAAU,KAAK,OAAO;IAAW,aAAU;GAAa,CAAA;EACtE,CAAA,GACL,qBAAC,KAAD;GAAK,KAAK,OAAO;GAAjB,UAAA,CACE,oBAAC,MAAD;IAAM,KAAK,OAAO;IAAY,UAAA,KAAK;GAAY,CAAA,GAC9C,KAAK,cAAc,oBAAC,MAAD;IAAM,KAAK,OAAO;IAAiB,UAAA,KAAK;GAAiB,CAAA,CAC1E;EACM,CAAA,CAAA;;AAEjB"}
@@ -8,6 +8,7 @@ export { type BitkitSelectMenuActionProps } from './BitkitSelectMenuAction';
8
8
  export type BitkitSelectMenuSearchProps = {
9
9
  /** When provided, a search input is rendered above the menu items. `searchValue` is required alongside. */
10
10
  onSearchChange?: (searchText: string) => void;
11
+ searchPlaceholder?: string;
11
12
  searchValue?: string;
12
13
  };
13
14
  export type BitkitSelectMenuScrollProps = {
@@ -33,6 +34,10 @@ export type BitkitSelectMenuEmptyStateProps = {
33
34
  emptyLabel?: string;
34
35
  emptyHelperText?: string;
35
36
  };
37
+ export type BitkitSelectMenuErrorStateProps = {
38
+ errorLabel?: string;
39
+ errorHelperText?: string;
40
+ };
36
41
  export type BitkitSelectMenuProps = {
37
42
  children?: BitkitSelectMenuActionChild;
38
43
  collection: ListCollection<BitkitSelectMenuItemProps>;
@@ -43,7 +48,7 @@ export type BitkitSelectMenuProps = {
43
48
  isLoading?: boolean;
44
49
  size?: 'md' | 'lg';
45
50
  variant?: 'select' | 'combobox';
46
- } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps;
51
+ } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & BitkitSelectMenuErrorStateProps;
47
52
  declare const BitkitSelectMenu: import('react').ForwardRefExoticComponent<{
48
53
  children?: BitkitSelectMenuActionChild;
49
54
  collection: ListCollection<BitkitSelectMenuItemProps>;
@@ -54,5 +59,5 @@ declare const BitkitSelectMenu: import('react').ForwardRefExoticComponent<{
54
59
  isLoading?: boolean;
55
60
  size?: "md" | "lg";
56
61
  variant?: "select" | "combobox";
57
- } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & import('react').RefAttributes<HTMLDivElement>>;
62
+ } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & BitkitSelectMenuErrorStateProps & import('react').RefAttributes<HTMLDivElement>>;
58
63
  export default BitkitSelectMenu;
@@ -1 +1 @@
1
- {"version":3,"file":"BitkitSelectMenu.js","names":[],"sources":["../../../lib/components/BitkitSelectMenu/BitkitSelectMenu.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { type ListCollection } from '@chakra-ui/react/collection';\nimport { Combobox } from '@chakra-ui/react/combobox';\nimport { Select, type SelectContentProps } from '@chakra-ui/react/select';\nimport { Spinner } from '@chakra-ui/react/spinner';\nimport { type SystemStyleObject, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { cloneElement, forwardRef, type ReactElement, type ReactNode } from 'react';\n\nimport { type BitkitIconComponent, IconCheck } from '../../icons';\nimport BitkitAvatar from '../BitkitAvatar/BitkitAvatar';\nimport { type BitkitBadgeProps } from '../BitkitBadge/BitkitBadge';\nimport { type BitkitSelectMenuActionChild } from './BitkitSelectMenuAction';\nimport { SelectMenuShell, selectSizeMap, type SelectSizes } from './SelectMenuShell';\n\nexport { type BitkitSelectMenuActionProps } from './BitkitSelectMenuAction';\n\nexport type BitkitSelectMenuSearchProps = {\n /** When provided, a search input is rendered above the menu items. `searchValue` is required alongside. */\n onSearchChange?: (searchText: string) => void;\n searchValue?: string;\n};\n\nexport type BitkitSelectMenuScrollProps = {\n /** Fires when the item list reaches its end. Position only: keep your own loading and end-of-list guards. */\n onScrolledToBottom?: () => void;\n};\n\nexport type BitkitSelectMenuItemProps = {\n value: string;\n label: string;\n group?: string;\n icon?: BitkitIconComponent;\n /** The item's avatar. A URL renders that image; `null` renders the avatar with the initials\n * of `label`; omitting the prop renders no avatar and leaves the row's leading slot to\n * `icon`. */\n avatar?: string | null;\n helperText?: ReactNode;\n /** A `BitkitBadge` after the label. Forced to `colorVariant=\"neutral\"` on a disabled item. */\n badge?: ReactElement<BitkitBadgeProps>;\n disabled?: boolean;\n loading?: boolean;\n};\n\nexport type BitkitSelectMenuEmptyStateProps = {\n emptyLabel?: string;\n emptyHelperText?: string;\n};\n\nexport type BitkitSelectMenuProps = {\n children?: BitkitSelectMenuActionChild;\n collection: ListCollection<BitkitSelectMenuItemProps>;\n /** Forwarded to the underlying Select/Combobox.Content. Kept for internal callers\n * (e.g. BitkitCalendar's in-grid selects that need to tweak max-height / width). The\n * public components (BitkitSelect, BitkitCombobox) do not expose this escape hatch. */\n contentProps?: SelectContentProps;\n isLoading?: boolean;\n size?: 'md' | 'lg';\n variant?: 'select' | 'combobox';\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps;\n\nconst BitkitSelectMenu = forwardRef<HTMLDivElement, BitkitSelectMenuProps>((props, ref) => {\n const { children, collection, variant = 'select', size, ...shellProps } = props;\n const NS = variant === 'combobox' ? Combobox : Select;\n const recipe = useSlotRecipe({ key: 'select' });\n const styles = recipe({ size });\n const { avatarSize, iconSize, spinnerSize } = selectSizeMap[size ?? 'lg'];\n\n return (\n <SelectMenuShell\n NS={NS}\n collection={collection}\n contentRef={ref}\n iconSize={iconSize}\n renderItem={(item) => (\n <SelectMenuItem\n key={item.value}\n NS={NS}\n avatarSize={avatarSize}\n item={item}\n iconSize={iconSize}\n spinnerSize={spinnerSize}\n styles={styles}\n />\n )}\n spinnerSize={spinnerSize}\n styles={styles}\n {...shellProps}\n >\n {children}\n </SelectMenuShell>\n );\n});\n\nBitkitSelectMenu.displayName = 'BitkitSelectMenu';\n\ntype SelectMenuItemRenderProps = {\n NS: typeof Select | typeof Combobox;\n avatarSize: SelectSizes['avatarSize'];\n item: BitkitSelectMenuItemProps;\n iconSize: SelectSizes['iconSize'];\n spinnerSize: SelectSizes['spinnerSize'];\n styles: Record<string, SystemStyleObject>;\n};\n\nconst SelectMenuItem = ({ NS, avatarSize, item, iconSize, spinnerSize, styles }: SelectMenuItemRenderProps) => {\n const Icon = item.icon;\n const showAvatar = item.avatar !== undefined;\n\n if (item.loading) {\n // Rendered as a plain Box, not NS.Item — Zag's state machine won't track it as\n // an option, so keyboard nav skips it and it can't be selected.\n return (\n <Box css={styles.item}>\n <Spinner variant=\"purple\" size={spinnerSize} css={styles.itemLoading} />\n <Text css={styles.itemLoadingLabel}>Loading...</Text>\n </Box>\n );\n }\n\n return (\n <NS.Item css={styles.item} item={item}>\n {showAvatar && (\n <Box data-slot=\"avatar\" css={styles.avatar}>\n <BitkitAvatar variant=\"image\" src={item.avatar ?? ''} name={item.label} size={avatarSize} />\n </Box>\n )}\n <Box css={styles.itemContent}>\n <Box display=\"flex\" alignItems=\"center\" gap=\"8\">\n {Icon && !showAvatar && <Icon css={styles.itemIcon} size={iconSize} />}\n <Text css={styles.itemLabel}>{item.label}</Text>\n </Box>\n {item.helperText && <Text css={styles.itemHelperText}>{item.helperText}</Text>}\n </Box>\n {item.badge && (\n <Box css={styles.itemBadge}>\n {item.disabled ? cloneElement(item.badge, { colorVariant: 'neutral' }) : item.badge}\n </Box>\n )}\n <NS.ItemIndicator asChild>\n <IconCheck size={iconSize} css={styles.itemIndicator} />\n </NS.ItemIndicator>\n </NS.Item>\n );\n};\n\nexport default BitkitSelectMenu;\n"],"mappings":";;;;;;;;;;;;AA+DA,IAAM,mBAAmB,YAAmD,OAAO,QAAQ;CACzF,MAAM,EAAE,UAAU,YAAY,UAAU,UAAU,MAAM,GAAG,eAAe;CAC1E,MAAM,KAAK,YAAY,aAAa,WAAW;CAE/C,MAAM,SADS,cAAc,EAAE,KAAK,SAAS,CAC9B,CAAA,CAAO,EAAE,KAAK,CAAC;CAC9B,MAAM,EAAE,YAAY,UAAU,gBAAgB,cAAc,QAAQ;CAEpE,OACE,oBAAC,iBAAD;EACM;EACQ;EACZ,YAAY;EACF;EACV,aAAa,SACX,oBAAC,gBAAD;GAEM;GACQ;GACN;GACI;GACG;GACL;EACT,GAPM,KAAK,KAOX;EAEU;EACL;EACR,GAAI;EAEH;CACc,CAAA;AAErB,CAAC;AAED,iBAAiB,cAAc;AAW/B,IAAM,kBAAkB,EAAE,IAAI,YAAY,MAAM,UAAU,aAAa,aAAwC;CAC7G,MAAM,OAAO,KAAK;CAClB,MAAM,aAAa,KAAK,WAAW,KAAA;CAEnC,IAAI,KAAK,SAGP,OACE,qBAAC,KAAD;EAAK,KAAK,OAAO;EAAjB,UAAA,CACE,oBAAC,SAAD;GAAS,SAAQ;GAAS,MAAM;GAAa,KAAK,OAAO;EAAc,CAAA,GACvE,oBAAC,MAAD;GAAM,KAAK,OAAO;GAAkB,UAAA;EAAgB,CAAA,CACjD;;CAIT,OACE,qBAAC,GAAG,MAAJ;EAAS,KAAK,OAAO;EAAY;EAAjC,UAAA;GACG,cACC,oBAAC,KAAD;IAAK,aAAU;IAAS,KAAK,OAAO;IAClC,UAAA,oBAAC,cAAD;KAAc,SAAQ;KAAQ,KAAK,KAAK,UAAU;KAAI,MAAM,KAAK;KAAO,MAAM;IAAa,CAAA;GACxF,CAAA;GAEP,qBAAC,KAAD;IAAK,KAAK,OAAO;IAAjB,UAAA,CACE,qBAAC,KAAD;KAAK,SAAQ;KAAO,YAAW;KAAS,KAAI;KAA5C,UAAA,CACG,QAAQ,CAAC,cAAc,oBAAC,MAAD;MAAM,KAAK,OAAO;MAAU,MAAM;KAAW,CAAA,GACrE,oBAAC,MAAD;MAAM,KAAK,OAAO;MAAY,UAAA,KAAK;KAAY,CAAA,CAC5C;IACJ,CAAA,GAAA,KAAK,cAAc,oBAAC,MAAD;KAAM,KAAK,OAAO;KAAiB,UAAA,KAAK;IAAiB,CAAA,CAC1E;;GACJ,KAAK,SACJ,oBAAC,KAAD;IAAK,KAAK,OAAO;IACd,UAAA,KAAK,WAAW,aAAa,KAAK,OAAO,EAAE,cAAc,UAAU,CAAC,IAAI,KAAK;GAC3E,CAAA;GAEP,oBAAC,GAAG,eAAJ;IAAkB,SAAA;IAChB,UAAA,oBAAC,WAAD;KAAW,MAAM;KAAU,KAAK,OAAO;IAAgB,CAAA;GACvC,CAAA;EACX;;AAEb"}
1
+ {"version":3,"file":"BitkitSelectMenu.js","names":[],"sources":["../../../lib/components/BitkitSelectMenu/BitkitSelectMenu.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { type ListCollection } from '@chakra-ui/react/collection';\nimport { Combobox } from '@chakra-ui/react/combobox';\nimport { Select, type SelectContentProps } from '@chakra-ui/react/select';\nimport { Spinner } from '@chakra-ui/react/spinner';\nimport { type SystemStyleObject, useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { cloneElement, forwardRef, type ReactElement, type ReactNode } from 'react';\n\nimport { type BitkitIconComponent, IconCheck } from '../../icons';\nimport BitkitAvatar from '../BitkitAvatar/BitkitAvatar';\nimport { type BitkitBadgeProps } from '../BitkitBadge/BitkitBadge';\nimport { type BitkitSelectMenuActionChild } from './BitkitSelectMenuAction';\nimport { SelectMenuShell, selectSizeMap, type SelectSizes } from './SelectMenuShell';\n\nexport { type BitkitSelectMenuActionProps } from './BitkitSelectMenuAction';\n\nexport type BitkitSelectMenuSearchProps = {\n /** When provided, a search input is rendered above the menu items. `searchValue` is required alongside. */\n onSearchChange?: (searchText: string) => void;\n searchPlaceholder?: string;\n searchValue?: string;\n};\n\nexport type BitkitSelectMenuScrollProps = {\n /** Fires when the item list reaches its end. Position only: keep your own loading and end-of-list guards. */\n onScrolledToBottom?: () => void;\n};\n\nexport type BitkitSelectMenuItemProps = {\n value: string;\n label: string;\n group?: string;\n icon?: BitkitIconComponent;\n /** The item's avatar. A URL renders that image; `null` renders the avatar with the initials\n * of `label`; omitting the prop renders no avatar and leaves the row's leading slot to\n * `icon`. */\n avatar?: string | null;\n helperText?: ReactNode;\n /** A `BitkitBadge` after the label. Forced to `colorVariant=\"neutral\"` on a disabled item. */\n badge?: ReactElement<BitkitBadgeProps>;\n disabled?: boolean;\n loading?: boolean;\n};\n\nexport type BitkitSelectMenuEmptyStateProps = {\n emptyLabel?: string;\n emptyHelperText?: string;\n};\n\nexport type BitkitSelectMenuErrorStateProps = {\n errorLabel?: string;\n errorHelperText?: string;\n};\n\nexport type BitkitSelectMenuProps = {\n children?: BitkitSelectMenuActionChild;\n collection: ListCollection<BitkitSelectMenuItemProps>;\n /** Forwarded to the underlying Select/Combobox.Content. Kept for internal callers\n * (e.g. BitkitCalendar's in-grid selects that need to tweak max-height / width). The\n * public components (BitkitSelect, BitkitCombobox) do not expose this escape hatch. */\n contentProps?: SelectContentProps;\n isLoading?: boolean;\n size?: 'md' | 'lg';\n variant?: 'select' | 'combobox';\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps &\n BitkitSelectMenuErrorStateProps;\n\nconst BitkitSelectMenu = forwardRef<HTMLDivElement, BitkitSelectMenuProps>((props, ref) => {\n const { children, collection, variant = 'select', size, ...shellProps } = props;\n const NS = variant === 'combobox' ? Combobox : Select;\n const recipe = useSlotRecipe({ key: 'select' });\n const styles = recipe({ size });\n const { avatarSize, iconSize, spinnerSize } = selectSizeMap[size ?? 'lg'];\n\n return (\n <SelectMenuShell\n NS={NS}\n collection={collection}\n contentRef={ref}\n iconSize={iconSize}\n renderItem={(item) => (\n <SelectMenuItem\n key={item.value}\n NS={NS}\n avatarSize={avatarSize}\n item={item}\n iconSize={iconSize}\n spinnerSize={spinnerSize}\n styles={styles}\n />\n )}\n spinnerSize={spinnerSize}\n styles={styles}\n {...shellProps}\n >\n {children}\n </SelectMenuShell>\n );\n});\n\nBitkitSelectMenu.displayName = 'BitkitSelectMenu';\n\ntype SelectMenuItemRenderProps = {\n NS: typeof Select | typeof Combobox;\n avatarSize: SelectSizes['avatarSize'];\n item: BitkitSelectMenuItemProps;\n iconSize: SelectSizes['iconSize'];\n spinnerSize: SelectSizes['spinnerSize'];\n styles: Record<string, SystemStyleObject>;\n};\n\nconst SelectMenuItem = ({ NS, avatarSize, item, iconSize, spinnerSize, styles }: SelectMenuItemRenderProps) => {\n const Icon = item.icon;\n const showAvatar = item.avatar !== undefined;\n\n if (item.loading) {\n // Rendered as a plain Box, not NS.Item — Zag's state machine won't track it as\n // an option, so keyboard nav skips it and it can't be selected.\n return (\n <Box css={styles.item}>\n <Spinner variant=\"purple\" size={spinnerSize} css={styles.itemLoading} />\n <Text css={styles.itemLoadingLabel}>Loading...</Text>\n </Box>\n );\n }\n\n return (\n <NS.Item css={styles.item} item={item}>\n {showAvatar && (\n <Box data-slot=\"avatar\" css={styles.avatar}>\n <BitkitAvatar variant=\"image\" src={item.avatar ?? ''} name={item.label} size={avatarSize} />\n </Box>\n )}\n <Box css={styles.itemContent}>\n <Box display=\"flex\" alignItems=\"center\" gap=\"8\">\n {Icon && !showAvatar && <Icon css={styles.itemIcon} size={iconSize} />}\n <Text css={styles.itemLabel}>{item.label}</Text>\n </Box>\n {item.helperText && <Text css={styles.itemHelperText}>{item.helperText}</Text>}\n </Box>\n {item.badge && (\n <Box css={styles.itemBadge}>\n {item.disabled ? cloneElement(item.badge, { colorVariant: 'neutral' }) : item.badge}\n </Box>\n )}\n <NS.ItemIndicator asChild>\n <IconCheck size={iconSize} css={styles.itemIndicator} />\n </NS.ItemIndicator>\n </NS.Item>\n );\n};\n\nexport default BitkitSelectMenu;\n"],"mappings":";;;;;;;;;;;;AAsEA,IAAM,mBAAmB,YAAmD,OAAO,QAAQ;CACzF,MAAM,EAAE,UAAU,YAAY,UAAU,UAAU,MAAM,GAAG,eAAe;CAC1E,MAAM,KAAK,YAAY,aAAa,WAAW;CAE/C,MAAM,SADS,cAAc,EAAE,KAAK,SAAS,CAC9B,CAAA,CAAO,EAAE,KAAK,CAAC;CAC9B,MAAM,EAAE,YAAY,UAAU,gBAAgB,cAAc,QAAQ;CAEpE,OACE,oBAAC,iBAAD;EACM;EACQ;EACZ,YAAY;EACF;EACV,aAAa,SACX,oBAAC,gBAAD;GAEM;GACQ;GACN;GACI;GACG;GACL;EACT,GAPM,KAAK,KAOX;EAEU;EACL;EACR,GAAI;EAEH;CACc,CAAA;AAErB,CAAC;AAED,iBAAiB,cAAc;AAW/B,IAAM,kBAAkB,EAAE,IAAI,YAAY,MAAM,UAAU,aAAa,aAAwC;CAC7G,MAAM,OAAO,KAAK;CAClB,MAAM,aAAa,KAAK,WAAW,KAAA;CAEnC,IAAI,KAAK,SAGP,OACE,qBAAC,KAAD;EAAK,KAAK,OAAO;EAAjB,UAAA,CACE,oBAAC,SAAD;GAAS,SAAQ;GAAS,MAAM;GAAa,KAAK,OAAO;EAAc,CAAA,GACvE,oBAAC,MAAD;GAAM,KAAK,OAAO;GAAkB,UAAA;EAAgB,CAAA,CACjD;;CAIT,OACE,qBAAC,GAAG,MAAJ;EAAS,KAAK,OAAO;EAAY;EAAjC,UAAA;GACG,cACC,oBAAC,KAAD;IAAK,aAAU;IAAS,KAAK,OAAO;IAClC,UAAA,oBAAC,cAAD;KAAc,SAAQ;KAAQ,KAAK,KAAK,UAAU;KAAI,MAAM,KAAK;KAAO,MAAM;IAAa,CAAA;GACxF,CAAA;GAEP,qBAAC,KAAD;IAAK,KAAK,OAAO;IAAjB,UAAA,CACE,qBAAC,KAAD;KAAK,SAAQ;KAAO,YAAW;KAAS,KAAI;KAA5C,UAAA,CACG,QAAQ,CAAC,cAAc,oBAAC,MAAD;MAAM,KAAK,OAAO;MAAU,MAAM;KAAW,CAAA,GACrE,oBAAC,MAAD;MAAM,KAAK,OAAO;MAAY,UAAA,KAAK;KAAY,CAAA,CAC5C;IACJ,CAAA,GAAA,KAAK,cAAc,oBAAC,MAAD;KAAM,KAAK,OAAO;KAAiB,UAAA,KAAK;IAAiB,CAAA,CAC1E;;GACJ,KAAK,SACJ,oBAAC,KAAD;IAAK,KAAK,OAAO;IACd,UAAA,KAAK,WAAW,aAAa,KAAK,OAAO,EAAE,cAAc,UAAU,CAAC,IAAI,KAAK;GAC3E,CAAA;GAEP,oBAAC,GAAG,eAAJ;IAAkB,SAAA;IAChB,UAAA,oBAAC,WAAD;KAAW,MAAM;KAAU,KAAK,OAAO;IAAgB,CAAA;GACvC,CAAA;EACX;;AAEb"}
@@ -3,7 +3,7 @@ import { Combobox } from '@chakra-ui/react/combobox';
3
3
  import { Select, SelectContentProps } from '@chakra-ui/react/select';
4
4
  import { SystemStyleObject } from '@chakra-ui/react/styled-system';
5
5
  import { ReactNode, Ref } from 'react';
6
- import { BitkitSelectMenuEmptyStateProps, BitkitSelectMenuScrollProps, BitkitSelectMenuSearchProps } from './BitkitSelectMenu';
6
+ import { BitkitSelectMenuEmptyStateProps, BitkitSelectMenuErrorStateProps, BitkitSelectMenuScrollProps, BitkitSelectMenuSearchProps } from './BitkitSelectMenu';
7
7
  import { BitkitSelectMenuActionChild } from './BitkitSelectMenuAction';
8
8
  export declare const selectSizeMap: {
9
9
  readonly lg: {
@@ -38,8 +38,8 @@ export type SelectMenuShellProps<T extends {
38
38
  renderItem: (item: T) => ReactNode;
39
39
  spinnerSize: SelectSizes['spinnerSize'];
40
40
  styles: Record<string, SystemStyleObject>;
41
- } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps;
41
+ } & BitkitSelectMenuSearchProps & BitkitSelectMenuScrollProps & BitkitSelectMenuEmptyStateProps & BitkitSelectMenuErrorStateProps;
42
42
  export declare const SelectMenuShell: <T extends {
43
43
  value: string;
44
44
  group?: string;
45
- }>({ NS, children, collection, contentProps, contentRef, emptyHelperText, emptyLabel, iconSize, isLoading, onScrolledToBottom, onSearchChange, renderItem, searchValue, spinnerSize, styles, }: SelectMenuShellProps<T>) => import('react').JSX.Element;
45
+ }>({ NS, children, collection, contentProps, contentRef, emptyHelperText, emptyLabel, errorHelperText, errorLabel, iconSize, isLoading, onScrolledToBottom, onSearchChange, renderItem, searchPlaceholder, searchValue, spinnerSize, styles, }: SelectMenuShellProps<T>) => import('react').JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import IconCross from "../../icons/IconCross.js";
2
+ import IconCrossCircle from "../../icons/IconCrossCircle.js";
2
3
  import IconMagnifier from "../../icons/IconMagnifier.js";
3
4
  import BitkitGroupHeading from "../BitkitGroupHeading/BitkitGroupHeading.js";
4
5
  import { SelectMenuShellContextProvider } from "./BitkitSelectMenuAction.js";
@@ -21,9 +22,10 @@ var selectSizeMap = {
21
22
  spinnerSize: "md"
22
23
  }
23
24
  };
24
- var SelectMenuShell = ({ NS, children, collection, contentProps, contentRef, emptyHelperText, emptyLabel = "No matching options", iconSize, isLoading = false, onScrolledToBottom, onSearchChange, renderItem, searchValue, spinnerSize, styles }) => {
25
+ var SelectMenuShell = ({ NS, children, collection, contentProps, contentRef, emptyHelperText, emptyLabel = "No matching options", errorHelperText, errorLabel, iconSize, isLoading = false, onScrolledToBottom, onSearchChange, renderItem, searchPlaceholder, searchValue, spinnerSize, styles }) => {
25
26
  const { css: contentCss, ...restContentProps } = contentProps ?? {};
26
27
  const isEmpty = collection.size === 0;
28
+ const hasError = errorLabel !== void 0;
27
29
  const hasAction = isValidElement(children);
28
30
  const wasAtBottom = useRef(false);
29
31
  const handleItemListScroll = (event) => {
@@ -49,12 +51,29 @@ var SelectMenuShell = ({ NS, children, collection, contentProps, contentRef, emp
49
51
  }),
50
52
  onSearchChange && /* @__PURE__ */ jsx(SelectMenuSearch, {
51
53
  iconSize,
54
+ placeholder: searchPlaceholder,
52
55
  styles,
53
56
  value: searchValue ?? "",
54
57
  onSearchChange
55
58
  }),
56
- /* @__PURE__ */ jsxs(Box, {
59
+ hasError ? /* @__PURE__ */ jsxs(Box, {
60
+ css: styles.errorState,
61
+ children: [/* @__PURE__ */ jsx(IconCrossCircle, {
62
+ css: styles.errorIcon,
63
+ size: iconSize
64
+ }), /* @__PURE__ */ jsxs(Box, {
65
+ css: styles.errorTextBlock,
66
+ children: [/* @__PURE__ */ jsx(Text, {
67
+ css: styles.errorLabel,
68
+ children: errorLabel
69
+ }), errorHelperText && /* @__PURE__ */ jsx(Text, {
70
+ css: styles.itemHelperText,
71
+ children: errorHelperText
72
+ })]
73
+ })]
74
+ }) : /* @__PURE__ */ jsxs(Box, {
57
75
  css: styles.itemList,
76
+ "data-slot": "item-list",
58
77
  onScroll: handleItemListScroll,
59
78
  children: [
60
79
  isLoading && /* @__PURE__ */ jsxs(Box, {
@@ -93,7 +112,7 @@ var SelectMenuShell = ({ NS, children, collection, contentProps, contentRef, emp
93
112
  })
94
113
  });
95
114
  };
96
- var SelectMenuSearch = ({ iconSize, onSearchChange, styles, value }) => /* @__PURE__ */ jsxs(Box, {
115
+ var SelectMenuSearch = ({ iconSize, onSearchChange, placeholder = "Search...", styles, value }) => /* @__PURE__ */ jsxs(Box, {
97
116
  css: styles.searchInputGroup,
98
117
  children: [
99
118
  /* @__PURE__ */ jsx(IconMagnifier, {
@@ -103,7 +122,7 @@ var SelectMenuSearch = ({ iconSize, onSearchChange, styles, value }) => /* @__PU
103
122
  /* @__PURE__ */ jsx(chakra.input, {
104
123
  "aria-label": "Search",
105
124
  css: styles.searchInput,
106
- placeholder: "Search...",
125
+ placeholder,
107
126
  value,
108
127
  onChange: (event) => onSearchChange(event.target.value),
109
128
  onKeyDown: (event) => {
@@ -1 +1 @@
1
- {"version":3,"file":"SelectMenuShell.js","names":[],"sources":["../../../lib/components/BitkitSelectMenu/SelectMenuShell.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { type ListCollection } from '@chakra-ui/react/collection';\nimport { type Combobox } from '@chakra-ui/react/combobox';\nimport { type Select, type SelectContentProps } from '@chakra-ui/react/select';\nimport { Spinner } from '@chakra-ui/react/spinner';\nimport { chakra, type SystemStyleObject } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { type ChangeEvent, isValidElement, type ReactNode, type Ref, type UIEvent, useRef } from 'react';\n\nimport { IconCross, IconMagnifier } from '../../icons';\nimport BitkitGroupHeading from '../BitkitGroupHeading/BitkitGroupHeading';\nimport {\n type BitkitSelectMenuEmptyStateProps,\n type BitkitSelectMenuScrollProps,\n type BitkitSelectMenuSearchProps,\n} from './BitkitSelectMenu';\nimport { type BitkitSelectMenuActionChild, SelectMenuShellContextProvider } from './BitkitSelectMenuAction';\n\nexport const selectSizeMap = {\n lg: { avatarSize: '32', iconSize: '24', spinnerSize: 'lg' },\n md: { avatarSize: '24', iconSize: '16', spinnerSize: 'md' },\n} as const;\n\nexport type SelectSizes = (typeof selectSizeMap)[keyof typeof selectSizeMap];\n\n/**\n * Internal shared shell for BitkitSelectMenu and BitkitMultiselectMenu.\n * Handles Content wrapper, search, loading, empty state, groups, and the action slot —\n * the caller only provides per-item rendering via renderItem and any sub-components\n * (e.g. <BitkitSelectMenu.Action />) via children.\n */\nexport type SelectMenuShellProps<T extends { value: string; group?: string }> = {\n NS: typeof Select | typeof Combobox;\n children?: BitkitSelectMenuActionChild;\n collection: ListCollection<T>;\n contentProps?: SelectContentProps;\n contentRef?: Ref<HTMLDivElement>;\n iconSize: SelectSizes['iconSize'];\n isLoading?: boolean;\n renderItem: (item: T) => ReactNode;\n spinnerSize: SelectSizes['spinnerSize'];\n styles: Record<string, SystemStyleObject>;\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps;\n\nexport const SelectMenuShell = <T extends { value: string; group?: string }>({\n NS,\n children,\n collection,\n contentProps,\n contentRef,\n emptyHelperText,\n emptyLabel = 'No matching options',\n iconSize,\n isLoading = false,\n onScrolledToBottom,\n onSearchChange,\n renderItem,\n searchValue,\n spinnerSize,\n styles,\n}: SelectMenuShellProps<T>) => {\n const { css: contentCss, ...restContentProps } = contentProps ?? {};\n const isEmpty = collection.size === 0;\n const hasAction = isValidElement(children);\n\n const wasAtBottom = useRef(false);\n const handleItemListScroll = (event: UIEvent<HTMLDivElement>) => {\n const list = event.currentTarget;\n const atBottom = list.scrollTop >= list.scrollHeight - list.offsetHeight - 1;\n // Only the transition into \"at the end\", so resting at the bottom doesn't keep asking.\n if (atBottom && !wasAtBottom.current) onScrolledToBottom?.();\n wasAtBottom.current = atBottom;\n };\n\n return (\n <SelectMenuShellContextProvider value={{ iconSize, styles }}>\n <NS.Content css={[styles.content, contentCss]} ref={contentRef} {...restContentProps}>\n {/*\n Without a search input, Zag's getInitialFocus (see @zag-js/dom-query) picks the first\n tabbable descendant as the menu's initial focus target — which would be the action\n slot, visually confusing. A hidden [data-autofocus] span wins over tabbables in\n getInitialFocus's querySelector, so we focus an invisible element instead and Zag's\n aria-activedescendant drives the highlight like a normal Select would.\n */}\n {!onSearchChange && hasAction && <span data-autofocus=\"\" tabIndex={-1} aria-hidden=\"true\" />}\n {onSearchChange && (\n <SelectMenuSearch\n iconSize={iconSize}\n styles={styles}\n value={searchValue ?? ''}\n onSearchChange={onSearchChange}\n />\n )}\n <Box css={styles.itemList} onScroll={handleItemListScroll}>\n {isLoading && (\n <Box css={styles.item}>\n <Spinner variant=\"purple\" size={spinnerSize} css={styles.itemLoading} />\n <Text css={styles.itemLoadingLabel}>Loading...</Text>\n </Box>\n )}\n {!isLoading && isEmpty && (\n <Box css={styles.emptyState}>\n <Text css={styles.itemLabel}>{emptyLabel}</Text>\n {emptyHelperText && <Text css={styles.itemHelperText}>{emptyHelperText}</Text>}\n </Box>\n )}\n {!isLoading &&\n !isEmpty &&\n collection.group().map(([type, group]) => (\n <NS.ItemGroup key={type}>\n {type && (\n <NS.ItemGroupLabel asChild>\n <BitkitGroupHeading label={type} paddingBlock=\"12\" paddingInline=\"16\" />\n </NS.ItemGroupLabel>\n )}\n {group.map(renderItem)}\n </NS.ItemGroup>\n ))}\n </Box>\n {children}\n </NS.Content>\n </SelectMenuShellContextProvider>\n );\n};\n\ntype SelectMenuSearchProps = {\n iconSize: '16' | '24';\n onSearchChange: (searchText: string) => void;\n styles: Record<string, SystemStyleObject>;\n value: string;\n};\n\nconst SelectMenuSearch = ({ iconSize, onSearchChange, styles, value }: SelectMenuSearchProps) => (\n <Box css={styles.searchInputGroup}>\n <IconMagnifier size={iconSize} color=\"icon/tertiary\" />\n <chakra.input\n aria-label=\"Search\"\n css={styles.searchInput}\n placeholder=\"Search...\"\n value={value}\n onChange={(event: ChangeEvent<HTMLInputElement>) => onSearchChange(event.target.value)}\n onKeyDown={(event) => {\n // Zag's Select.Content keyDown listener fires ITEM.CLICK + preventDefault on Space\n // regardless of which descendant is focused. That would eat the space before the\n // input can type it. Enter is left alone so \"type-then-Enter-to-select\" still works.\n if (event.key === ' ') event.stopPropagation();\n }}\n />\n {value && (\n <chakra.button\n type=\"button\"\n css={styles.searchClear}\n aria-label=\"Clear search\"\n onClick={() => onSearchChange('')}\n >\n <IconCross size={iconSize} />\n </chakra.button>\n )}\n </Box>\n);\n"],"mappings":";;;;;;;;;;;AAkBA,IAAa,gBAAgB;CAC3B,IAAI;EAAE,YAAY;EAAM,UAAU;EAAM,aAAa;CAAK;CAC1D,IAAI;EAAE,YAAY;EAAM,UAAU;EAAM,aAAa;CAAK;AAC5D;AAyBA,IAAa,mBAAgE,EAC3E,IACA,UACA,YACA,cACA,YACA,iBACA,aAAa,uBACb,UACA,YAAY,OACZ,oBACA,gBACA,YACA,aACA,aACA,aAC6B;CAC7B,MAAM,EAAE,KAAK,YAAY,GAAG,qBAAqB,gBAAgB,CAAC;CAClE,MAAM,UAAU,WAAW,SAAS;CACpC,MAAM,YAAY,eAAe,QAAQ;CAEzC,MAAM,cAAc,OAAO,KAAK;CAChC,MAAM,wBAAwB,UAAmC;EAC/D,MAAM,OAAO,MAAM;EACnB,MAAM,WAAW,KAAK,aAAa,KAAK,eAAe,KAAK,eAAe;EAE3E,IAAI,YAAY,CAAC,YAAY,SAAS,qBAAqB;EAC3D,YAAY,UAAU;CACxB;CAEA,OACE,oBAAC,gCAAD;EAAgC,OAAO;GAAE;GAAU;EAAO;EACxD,UAAA,qBAAC,GAAG,SAAJ;GAAY,KAAK,CAAC,OAAO,SAAS,UAAU;GAAG,KAAK;GAAY,GAAI;GAApE,UAAA;IAQG,CAAC,kBAAkB,aAAa,oBAAC,QAAD;KAAM,kBAAe;KAAG,UAAU;KAAI,eAAY;IAAQ,CAAA;IAC1F,kBACC,oBAAC,kBAAD;KACY;KACF;KACR,OAAO,eAAe;KACN;IACjB,CAAA;IAEH,qBAAC,KAAD;KAAK,KAAK,OAAO;KAAU,UAAU;KAArC,UAAA;MACG,aACC,qBAAC,KAAD;OAAK,KAAK,OAAO;OAAjB,UAAA,CACE,oBAAC,SAAD;QAAS,SAAQ;QAAS,MAAM;QAAa,KAAK,OAAO;OAAc,CAAA,GACvE,oBAAC,MAAD;QAAM,KAAK,OAAO;QAAkB,UAAA;OAAgB,CAAA,CACjD;;MAEN,CAAC,aAAa,WACb,qBAAC,KAAD;OAAK,KAAK,OAAO;OAAjB,UAAA,CACE,oBAAC,MAAD;QAAM,KAAK,OAAO;QAAY,UAAA;OAAiB,CAAA,GAC9C,mBAAmB,oBAAC,MAAD;QAAM,KAAK,OAAO;QAAiB,UAAA;OAAsB,CAAA,CAC1E;;MAEN,CAAC,aACA,CAAC,WACD,WAAW,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,WAC7B,qBAAC,GAAG,WAAJ,EAAA,UAAA,CACG,QACC,oBAAC,GAAG,gBAAJ;OAAmB,SAAA;OACjB,UAAA,oBAAC,oBAAD;QAAoB,OAAO;QAAM,cAAa;QAAK,eAAc;OAAM,CAAA;MACtD,CAAA,GAEpB,MAAM,IAAI,UAAU,CACT,EAAA,GAPK,IAOL,CACf;KACA;;IACJ;GACS;;CACkB,CAAA;AAEpC;AASA,IAAM,oBAAoB,EAAE,UAAU,gBAAgB,QAAQ,YAC5D,qBAAC,KAAD;CAAK,KAAK,OAAO;CAAjB,UAAA;EACE,oBAAC,eAAD;GAAe,MAAM;GAAU,OAAM;EAAiB,CAAA;EACtD,oBAAC,OAAO,OAAR;GACE,cAAW;GACX,KAAK,OAAO;GACZ,aAAY;GACL;GACP,WAAW,UAAyC,eAAe,MAAM,OAAO,KAAK;GACrF,YAAY,UAAU;IAIpB,IAAI,MAAM,QAAQ,KAAK,MAAM,gBAAgB;GAC/C;EACD,CAAA;EACA,SACC,oBAAC,OAAO,QAAR;GACE,MAAK;GACL,KAAK,OAAO;GACZ,cAAW;GACX,eAAe,eAAe,EAAE;GAEhC,UAAA,oBAAC,WAAD,EAAW,MAAM,SAAW,CAAA;EACf,CAAA;CAEd"}
1
+ {"version":3,"file":"SelectMenuShell.js","names":[],"sources":["../../../lib/components/BitkitSelectMenu/SelectMenuShell.tsx"],"sourcesContent":["import { Box } from '@chakra-ui/react/box';\nimport { type ListCollection } from '@chakra-ui/react/collection';\nimport { type Combobox } from '@chakra-ui/react/combobox';\nimport { type Select, type SelectContentProps } from '@chakra-ui/react/select';\nimport { Spinner } from '@chakra-ui/react/spinner';\nimport { chakra, type SystemStyleObject } from '@chakra-ui/react/styled-system';\nimport { Text } from '@chakra-ui/react/text';\nimport { type ChangeEvent, isValidElement, type ReactNode, type Ref, type UIEvent, useRef } from 'react';\n\nimport { IconCross, IconCrossCircle, IconMagnifier } from '../../icons';\nimport BitkitGroupHeading from '../BitkitGroupHeading/BitkitGroupHeading';\nimport {\n type BitkitSelectMenuEmptyStateProps,\n type BitkitSelectMenuErrorStateProps,\n type BitkitSelectMenuScrollProps,\n type BitkitSelectMenuSearchProps,\n} from './BitkitSelectMenu';\nimport { type BitkitSelectMenuActionChild, SelectMenuShellContextProvider } from './BitkitSelectMenuAction';\n\nexport const selectSizeMap = {\n lg: { avatarSize: '32', iconSize: '24', spinnerSize: 'lg' },\n md: { avatarSize: '24', iconSize: '16', spinnerSize: 'md' },\n} as const;\n\nexport type SelectSizes = (typeof selectSizeMap)[keyof typeof selectSizeMap];\n\n/**\n * Internal shared shell for BitkitSelectMenu and BitkitMultiselectMenu.\n * Handles Content wrapper, search, loading, empty state, groups, and the action slot —\n * the caller only provides per-item rendering via renderItem and any sub-components\n * (e.g. <BitkitSelectMenu.Action />) via children.\n */\nexport type SelectMenuShellProps<T extends { value: string; group?: string }> = {\n NS: typeof Select | typeof Combobox;\n children?: BitkitSelectMenuActionChild;\n collection: ListCollection<T>;\n contentProps?: SelectContentProps;\n contentRef?: Ref<HTMLDivElement>;\n iconSize: SelectSizes['iconSize'];\n isLoading?: boolean;\n renderItem: (item: T) => ReactNode;\n spinnerSize: SelectSizes['spinnerSize'];\n styles: Record<string, SystemStyleObject>;\n} & BitkitSelectMenuSearchProps &\n BitkitSelectMenuScrollProps &\n BitkitSelectMenuEmptyStateProps &\n BitkitSelectMenuErrorStateProps;\n\nexport const SelectMenuShell = <T extends { value: string; group?: string }>({\n NS,\n children,\n collection,\n contentProps,\n contentRef,\n emptyHelperText,\n emptyLabel = 'No matching options',\n errorHelperText,\n errorLabel,\n iconSize,\n isLoading = false,\n onScrolledToBottom,\n onSearchChange,\n renderItem,\n searchPlaceholder,\n searchValue,\n spinnerSize,\n styles,\n}: SelectMenuShellProps<T>) => {\n const { css: contentCss, ...restContentProps } = contentProps ?? {};\n const isEmpty = collection.size === 0;\n const hasError = errorLabel !== undefined;\n const hasAction = isValidElement(children);\n\n const wasAtBottom = useRef(false);\n const handleItemListScroll = (event: UIEvent<HTMLDivElement>) => {\n const list = event.currentTarget;\n const atBottom = list.scrollTop >= list.scrollHeight - list.offsetHeight - 1;\n // Only the transition into \"at the end\", so resting at the bottom doesn't keep asking.\n if (atBottom && !wasAtBottom.current) onScrolledToBottom?.();\n wasAtBottom.current = atBottom;\n };\n\n return (\n <SelectMenuShellContextProvider value={{ iconSize, styles }}>\n <NS.Content css={[styles.content, contentCss]} ref={contentRef} {...restContentProps}>\n {/*\n Without a search input, Zag's getInitialFocus (see @zag-js/dom-query) picks the first\n tabbable descendant as the menu's initial focus target — which would be the action\n slot, visually confusing. A hidden [data-autofocus] span wins over tabbables in\n getInitialFocus's querySelector, so we focus an invisible element instead and Zag's\n aria-activedescendant drives the highlight like a normal Select would.\n */}\n {!onSearchChange && hasAction && <span data-autofocus=\"\" tabIndex={-1} aria-hidden=\"true\" />}\n {onSearchChange && (\n <SelectMenuSearch\n iconSize={iconSize}\n placeholder={searchPlaceholder}\n styles={styles}\n value={searchValue ?? ''}\n onSearchChange={onSearchChange}\n />\n )}\n {hasError ? (\n <Box css={styles.errorState}>\n <IconCrossCircle css={styles.errorIcon} size={iconSize} />\n <Box css={styles.errorTextBlock}>\n <Text css={styles.errorLabel}>{errorLabel}</Text>\n {errorHelperText && <Text css={styles.itemHelperText}>{errorHelperText}</Text>}\n </Box>\n </Box>\n ) : (\n <Box css={styles.itemList} data-slot=\"item-list\" onScroll={handleItemListScroll}>\n {isLoading && (\n <Box css={styles.item}>\n <Spinner variant=\"purple\" size={spinnerSize} css={styles.itemLoading} />\n <Text css={styles.itemLoadingLabel}>Loading...</Text>\n </Box>\n )}\n {!isLoading && isEmpty && (\n <Box css={styles.emptyState}>\n <Text css={styles.itemLabel}>{emptyLabel}</Text>\n {emptyHelperText && <Text css={styles.itemHelperText}>{emptyHelperText}</Text>}\n </Box>\n )}\n {!isLoading &&\n !isEmpty &&\n collection.group().map(([type, group]) => (\n <NS.ItemGroup key={type}>\n {type && (\n <NS.ItemGroupLabel asChild>\n <BitkitGroupHeading label={type} paddingBlock=\"12\" paddingInline=\"16\" />\n </NS.ItemGroupLabel>\n )}\n {group.map(renderItem)}\n </NS.ItemGroup>\n ))}\n </Box>\n )}\n {children}\n </NS.Content>\n </SelectMenuShellContextProvider>\n );\n};\n\ntype SelectMenuSearchProps = {\n iconSize: '16' | '24';\n onSearchChange: (searchText: string) => void;\n placeholder?: string;\n styles: Record<string, SystemStyleObject>;\n value: string;\n};\n\nconst SelectMenuSearch = ({\n iconSize,\n onSearchChange,\n placeholder = 'Search...',\n styles,\n value,\n}: SelectMenuSearchProps) => (\n <Box css={styles.searchInputGroup}>\n <IconMagnifier size={iconSize} color=\"icon/tertiary\" />\n <chakra.input\n aria-label=\"Search\"\n css={styles.searchInput}\n placeholder={placeholder}\n value={value}\n onChange={(event: ChangeEvent<HTMLInputElement>) => onSearchChange(event.target.value)}\n onKeyDown={(event) => {\n // Zag's Select.Content keyDown listener fires ITEM.CLICK + preventDefault on Space\n // regardless of which descendant is focused. That would eat the space before the\n // input can type it. Enter is left alone so \"type-then-Enter-to-select\" still works.\n if (event.key === ' ') event.stopPropagation();\n }}\n />\n {value && (\n <chakra.button\n type=\"button\"\n css={styles.searchClear}\n aria-label=\"Clear search\"\n onClick={() => onSearchChange('')}\n >\n <IconCross size={iconSize} />\n </chakra.button>\n )}\n </Box>\n);\n"],"mappings":";;;;;;;;;;;;AAmBA,IAAa,gBAAgB;CAC3B,IAAI;EAAE,YAAY;EAAM,UAAU;EAAM,aAAa;CAAK;CAC1D,IAAI;EAAE,YAAY;EAAM,UAAU;EAAM,aAAa;CAAK;AAC5D;AA0BA,IAAa,mBAAgE,EAC3E,IACA,UACA,YACA,cACA,YACA,iBACA,aAAa,uBACb,iBACA,YACA,UACA,YAAY,OACZ,oBACA,gBACA,YACA,mBACA,aACA,aACA,aAC6B;CAC7B,MAAM,EAAE,KAAK,YAAY,GAAG,qBAAqB,gBAAgB,CAAC;CAClE,MAAM,UAAU,WAAW,SAAS;CACpC,MAAM,WAAW,eAAe,KAAA;CAChC,MAAM,YAAY,eAAe,QAAQ;CAEzC,MAAM,cAAc,OAAO,KAAK;CAChC,MAAM,wBAAwB,UAAmC;EAC/D,MAAM,OAAO,MAAM;EACnB,MAAM,WAAW,KAAK,aAAa,KAAK,eAAe,KAAK,eAAe;EAE3E,IAAI,YAAY,CAAC,YAAY,SAAS,qBAAqB;EAC3D,YAAY,UAAU;CACxB;CAEA,OACE,oBAAC,gCAAD;EAAgC,OAAO;GAAE;GAAU;EAAO;EACxD,UAAA,qBAAC,GAAG,SAAJ;GAAY,KAAK,CAAC,OAAO,SAAS,UAAU;GAAG,KAAK;GAAY,GAAI;GAApE,UAAA;IAQG,CAAC,kBAAkB,aAAa,oBAAC,QAAD;KAAM,kBAAe;KAAG,UAAU;KAAI,eAAY;IAAQ,CAAA;IAC1F,kBACC,oBAAC,kBAAD;KACY;KACV,aAAa;KACL;KACR,OAAO,eAAe;KACN;IACjB,CAAA;IAEF,WACC,qBAAC,KAAD;KAAK,KAAK,OAAO;KAAjB,UAAA,CACE,oBAAC,iBAAD;MAAiB,KAAK,OAAO;MAAW,MAAM;KAAW,CAAA,GACzD,qBAAC,KAAD;MAAK,KAAK,OAAO;MAAjB,UAAA,CACE,oBAAC,MAAD;OAAM,KAAK,OAAO;OAAa,UAAA;MAAiB,CAAA,GAC/C,mBAAmB,oBAAC,MAAD;OAAM,KAAK,OAAO;OAAiB,UAAA;MAAsB,CAAA,CAC1E;KACF,CAAA,CAAA;IAEL,CAAA,IAAA,qBAAC,KAAD;KAAK,KAAK,OAAO;KAAU,aAAU;KAAY,UAAU;KAA3D,UAAA;MACG,aACC,qBAAC,KAAD;OAAK,KAAK,OAAO;OAAjB,UAAA,CACE,oBAAC,SAAD;QAAS,SAAQ;QAAS,MAAM;QAAa,KAAK,OAAO;OAAc,CAAA,GACvE,oBAAC,MAAD;QAAM,KAAK,OAAO;QAAkB,UAAA;OAAgB,CAAA,CACjD;;MAEN,CAAC,aAAa,WACb,qBAAC,KAAD;OAAK,KAAK,OAAO;OAAjB,UAAA,CACE,oBAAC,MAAD;QAAM,KAAK,OAAO;QAAY,UAAA;OAAiB,CAAA,GAC9C,mBAAmB,oBAAC,MAAD;QAAM,KAAK,OAAO;QAAiB,UAAA;OAAsB,CAAA,CAC1E;;MAEN,CAAC,aACA,CAAC,WACD,WAAW,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,WAC7B,qBAAC,GAAG,WAAJ,EAAA,UAAA,CACG,QACC,oBAAC,GAAG,gBAAJ;OAAmB,SAAA;OACjB,UAAA,oBAAC,oBAAD;QAAoB,OAAO;QAAM,cAAa;QAAK,eAAc;OAAM,CAAA;MACtD,CAAA,GAEpB,MAAM,IAAI,UAAU,CACT,EAAA,GAPK,IAOL,CACf;KACA;;IAEN;GACS;;CACkB,CAAA;AAEpC;AAUA,IAAM,oBAAoB,EACxB,UACA,gBACA,cAAc,aACd,QACA,YAEA,qBAAC,KAAD;CAAK,KAAK,OAAO;CAAjB,UAAA;EACE,oBAAC,eAAD;GAAe,MAAM;GAAU,OAAM;EAAiB,CAAA;EACtD,oBAAC,OAAO,OAAR;GACE,cAAW;GACX,KAAK,OAAO;GACC;GACN;GACP,WAAW,UAAyC,eAAe,MAAM,OAAO,KAAK;GACrF,YAAY,UAAU;IAIpB,IAAI,MAAM,QAAQ,KAAK,MAAM,gBAAgB;GAC/C;EACD,CAAA;EACA,SACC,oBAAC,OAAO,QAAR;GACE,MAAK;GACL,KAAK,OAAO;GACZ,cAAW;GACX,eAAe,eAAe,EAAE;GAEhC,UAAA,oBAAC,WAAD,EAAW,MAAM,SAAW,CAAA;EACf,CAAA;CAEd"}
@@ -0,0 +1,37 @@
1
+ import { BoxProps } from '@chakra-ui/react/box';
2
+ import { ReactNode } from 'react';
3
+ export interface BitkitUISideNavProps extends Omit<BoxProps, 'children'> {
4
+ children: ReactNode;
5
+ /**
6
+ * Forces the desktop rail open or shut, overriding the pointer and focus behaviour. Leave it
7
+ * unset for the normal rail. Set it to `true` while something the rail does not know about is
8
+ * anchored to it, such as a popover opened from the footer.
9
+ */
10
+ expanded?: boolean;
11
+ /** Mobile drawer visibility. Controlled, because the header's menu button is what opens it. */
12
+ open?: boolean;
13
+ onOpenChange?: (open: boolean) => void;
14
+ }
15
+ export { uiSideNavRailWidth } from '../../theme/slot-recipes/UISideNav.recipe';
16
+ export { type BitkitUISideNavBodyProps } from './UISideNavBody';
17
+ export { type BitkitUISideNavFooterProps } from './UISideNavFooter';
18
+ export { type BitkitUISideNavFooterHeadingProps } from './UISideNavFooterHeading';
19
+ export { type BitkitUISideNavItemProps } from './UISideNavItem';
20
+ export { type BitkitUISideNavLinkAsAnchorProps, type BitkitUISideNavLinkAsButtonProps, type BitkitUISideNavLinkProps, } from './UISideNavLink';
21
+ export { type BitkitUISideNavWorkspaceProps, type BitkitUISideNavWorkspaceSelectorProps, } from './UISideNavWorkspaceSelector';
22
+ declare const _default: import('react').ForwardRefExoticComponent<BitkitUISideNavProps & import('react').RefAttributes<HTMLElement>> & {
23
+ Body: import('react').ForwardRefExoticComponent<import('./UISideNavBody').BitkitUISideNavBodyProps & import('react').RefAttributes<HTMLDivElement>>;
24
+ Footer: import('react').ForwardRefExoticComponent<import('./UISideNavFooter').BitkitUISideNavFooterProps & import('react').RefAttributes<HTMLDivElement>>;
25
+ FooterHeading: import('react').ForwardRefExoticComponent<import('./UISideNavFooterHeading').BitkitUISideNavFooterHeadingProps & import('react').RefAttributes<HTMLParagraphElement>>;
26
+ Item: import('react').ForwardRefExoticComponent<import('./UISideNavItem').BitkitUISideNavItemProps & import('react').RefAttributes<HTMLAnchorElement>>;
27
+ Link: import('react').ForwardRefExoticComponent<import('./UISideNavLink').BitkitUISideNavLinkProps & import('react').RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
28
+ WorkspaceSelector: import('react').ForwardRefExoticComponent<Omit<import('@chakra-ui/react').SelectTriggerProps, "children" | "onChange"> & {
29
+ children?: import('../BitkitSelectMenu/BitkitSelectMenuAction').BitkitSelectMenuActionChild;
30
+ isLoading?: boolean;
31
+ label?: string;
32
+ onValueChange?: (value: string) => void;
33
+ value?: string;
34
+ workspaces: Array<import('./UISideNavWorkspaceSelector').BitkitUISideNavWorkspaceProps>;
35
+ } & Omit<import('../BitkitSelectMenu/BitkitSelectMenu').BitkitSelectMenuSearchProps, "searchPlaceholder"> & import('../BitkitSelectMenu/BitkitSelectMenu').BitkitSelectMenuScrollProps & import('../BitkitSelectMenu/BitkitSelectMenu').BitkitSelectMenuEmptyStateProps & import('../BitkitSelectMenu/BitkitSelectMenu').BitkitSelectMenuErrorStateProps & import('react').RefAttributes<HTMLButtonElement>>;
36
+ };
37
+ export default _default;
@@ -0,0 +1,126 @@
1
+ import { withSubComponents } from "../../utilities/withSubComponents.js";
2
+ import BitkitCloseButton from "../BitkitCloseButton/BitkitCloseButton.js";
3
+ import useResponsive from "../../hooks/useResponsive.js";
4
+ import { UISideNavContextProvider } from "./UISideNavContext.js";
5
+ import UISideNavBody from "./UISideNavBody.js";
6
+ import UISideNavFooter from "./UISideNavFooter.js";
7
+ import UISideNavFooterHeading from "./UISideNavFooterHeading.js";
8
+ import UISideNavItem from "./UISideNavItem.js";
9
+ import UISideNavLink from "./UISideNavLink.js";
10
+ import UISideNavWorkspaceSelector from "./UISideNavWorkspaceSelector.js";
11
+ import { uiSideNavRailWidth } from "../../theme/slot-recipes/UISideNav.recipe.js";
12
+ import { Box } from "@chakra-ui/react/box";
13
+ import { useSlotRecipe } from "@chakra-ui/react/styled-system";
14
+ import { forwardRef, useRef, useState } from "react";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ import { Portal } from "@chakra-ui/react/portal";
17
+ import { Drawer } from "@chakra-ui/react/drawer";
18
+ //#region lib/components/BitkitUISideNav/BitkitUISideNav.tsx
19
+ /**
20
+ * The platform's primary navigation. It expects a workspace selector, a body of navigation
21
+ * items, and an optional footer:
22
+ *
23
+ * ```tsx
24
+ * <BitkitUISideNav open={open} onOpenChange={setOpen}>
25
+ * <BitkitUISideNav.WorkspaceSelector
26
+ * workspaces={workspaces}
27
+ * value={workspace}
28
+ * onValueChange={setWorkspace}
29
+ * />
30
+ * <BitkitUISideNav.Body>
31
+ * <BitkitUISideNav.Item href="/dashboard" icon={IconDashboard} selectedIcon={IconDashboardFilled} selected>
32
+ * Dashboard
33
+ * </BitkitUISideNav.Item>
34
+ * </BitkitUISideNav.Body>
35
+ * <BitkitUISideNav.Footer>…</BitkitUISideNav.Footer>
36
+ * </BitkitUISideNav>
37
+ * ```
38
+ *
39
+ * On desktop it is a 72px rail that widens to 256px under the pointer and while anything inside
40
+ * it holds keyboard focus. The rows are always laid out at the full width and clipped, so the
41
+ * labels appear without any text reflowing. It will not collapse while the workspace menu is
42
+ * open. There is no pin: the rail is the resting state.
43
+ *
44
+ * Below the `tablet` breakpoint it becomes an overlay drawer instead, opened by the header rather
45
+ * than by hovering. Pass `open` and `onOpenChange`; they are ignored on desktop.
46
+ *
47
+ * It does not position itself. The consumer decides where it sits and how tall it is, which is
48
+ * what lets a page slot it under a header of any height. The expanded rail overlays the page
49
+ * rather than pushing it, so give it a `position` of your own and reserve 72px beside it.
50
+ *
51
+ * Descendants can read the current state with `useUISideNav()`.
52
+ */
53
+ var BitkitUISideNav = forwardRef((props, ref) => {
54
+ const { children, css, expanded: expandedProp, onOpenChange, open = false, ...rest } = props;
55
+ const { isMobile } = useResponsive();
56
+ const [pointerInside, setPointerInside] = useState(false);
57
+ const [focusInside, setFocusInside] = useState(false);
58
+ const [menuOpen, setMenuOpen] = useState(false);
59
+ const menuContainerRef = useRef(null);
60
+ const styles = useSlotRecipe({ key: "uiSideNav" })({ layout: isMobile ? "drawer" : "rail" });
61
+ const expanded = isMobile || (expandedProp ?? (pointerInside || focusInside || menuOpen));
62
+ const handleBlur = (event) => {
63
+ if (event.currentTarget.contains(event.relatedTarget)) return;
64
+ setFocusInside(false);
65
+ };
66
+ const nav = /* @__PURE__ */ jsx(Box, {
67
+ ref,
68
+ "aria-label": "Platform navigation",
69
+ asChild: true,
70
+ "data-expanded": expanded ? "" : void 0,
71
+ ...rest,
72
+ css: [styles.root, css],
73
+ onBlur: isMobile ? void 0 : handleBlur,
74
+ onFocus: isMobile ? void 0 : () => setFocusInside(true),
75
+ onPointerEnter: isMobile ? void 0 : () => setPointerInside(true),
76
+ onPointerLeave: isMobile ? void 0 : () => setPointerInside(false),
77
+ children: /* @__PURE__ */ jsx("nav", { children })
78
+ });
79
+ const context = {
80
+ expanded,
81
+ isMobile,
82
+ menuContainerRef,
83
+ setMenuOpen,
84
+ styles
85
+ };
86
+ if (!isMobile) return /* @__PURE__ */ jsx(UISideNavContextProvider, {
87
+ value: context,
88
+ children: nav
89
+ });
90
+ return /* @__PURE__ */ jsx(UISideNavContextProvider, {
91
+ value: context,
92
+ children: /* @__PURE__ */ jsx(Drawer.Root, {
93
+ onOpenChange: (details) => onOpenChange?.(details.open),
94
+ open,
95
+ children: /* @__PURE__ */ jsxs(Portal, { children: [/* @__PURE__ */ jsx(Drawer.Backdrop, { css: styles.backdrop }), /* @__PURE__ */ jsx(Drawer.Positioner, {
96
+ css: styles.positioner,
97
+ children: /* @__PURE__ */ jsxs(Drawer.Content, {
98
+ ref: menuContainerRef,
99
+ css: styles.content,
100
+ children: [nav, /* @__PURE__ */ jsx(Box, {
101
+ css: styles.closeButton,
102
+ children: /* @__PURE__ */ jsx(BitkitCloseButton, {
103
+ "aria-label": "Close navigation",
104
+ colorVariant: "white",
105
+ onClick: () => onOpenChange?.(false),
106
+ size: "md"
107
+ })
108
+ })]
109
+ })
110
+ })] })
111
+ })
112
+ });
113
+ });
114
+ BitkitUISideNav.displayName = "BitkitUISideNav";
115
+ var BitkitUISideNav_default = withSubComponents(BitkitUISideNav, {
116
+ Body: UISideNavBody,
117
+ Footer: UISideNavFooter,
118
+ FooterHeading: UISideNavFooterHeading,
119
+ Item: UISideNavItem,
120
+ Link: UISideNavLink,
121
+ WorkspaceSelector: UISideNavWorkspaceSelector
122
+ });
123
+ //#endregion
124
+ export { BitkitUISideNav_default as default, uiSideNavRailWidth };
125
+
126
+ //# sourceMappingURL=BitkitUISideNav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BitkitUISideNav.js","names":[],"sources":["../../../lib/components/BitkitUISideNav/BitkitUISideNav.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { Drawer } from '@chakra-ui/react/drawer';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { type FocusEvent, forwardRef, type ReactNode, useRef, useState } from 'react';\n\nimport useResponsive from '../../hooks/useResponsive';\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitCloseButton from '../BitkitCloseButton/BitkitCloseButton';\nimport UISideNavBody from './UISideNavBody';\nimport { UISideNavContextProvider } from './UISideNavContext';\nimport UISideNavFooter from './UISideNavFooter';\nimport UISideNavFooterHeading from './UISideNavFooterHeading';\nimport UISideNavItem from './UISideNavItem';\nimport UISideNavLink from './UISideNavLink';\nimport UISideNavWorkspaceSelector from './UISideNavWorkspaceSelector';\n\nexport interface BitkitUISideNavProps extends Omit<BoxProps, 'children'> {\n children: ReactNode;\n /**\n * Forces the desktop rail open or shut, overriding the pointer and focus behaviour. Leave it\n * unset for the normal rail. Set it to `true` while something the rail does not know about is\n * anchored to it, such as a popover opened from the footer.\n */\n expanded?: boolean;\n /** Mobile drawer visibility. Controlled, because the header's menu button is what opens it. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\n/**\n * The platform's primary navigation. It expects a workspace selector, a body of navigation\n * items, and an optional footer:\n *\n * ```tsx\n * <BitkitUISideNav open={open} onOpenChange={setOpen}>\n * <BitkitUISideNav.WorkspaceSelector\n * workspaces={workspaces}\n * value={workspace}\n * onValueChange={setWorkspace}\n * />\n * <BitkitUISideNav.Body>\n * <BitkitUISideNav.Item href=\"/dashboard\" icon={IconDashboard} selectedIcon={IconDashboardFilled} selected>\n * Dashboard\n * </BitkitUISideNav.Item>\n * </BitkitUISideNav.Body>\n * <BitkitUISideNav.Footer>…</BitkitUISideNav.Footer>\n * </BitkitUISideNav>\n * ```\n *\n * On desktop it is a 72px rail that widens to 256px under the pointer and while anything inside\n * it holds keyboard focus. The rows are always laid out at the full width and clipped, so the\n * labels appear without any text reflowing. It will not collapse while the workspace menu is\n * open. There is no pin: the rail is the resting state.\n *\n * Below the `tablet` breakpoint it becomes an overlay drawer instead, opened by the header rather\n * than by hovering. Pass `open` and `onOpenChange`; they are ignored on desktop.\n *\n * It does not position itself. The consumer decides where it sits and how tall it is, which is\n * what lets a page slot it under a header of any height. The expanded rail overlays the page\n * rather than pushing it, so give it a `position` of your own and reserve 72px beside it.\n *\n * Descendants can read the current state with `useUISideNav()`.\n */\nconst BitkitUISideNav = forwardRef<HTMLElement, BitkitUISideNavProps>((props, ref) => {\n const { children, css, expanded: expandedProp, onOpenChange, open = false, ...rest } = props;\n\n const { isMobile } = useResponsive();\n\n const [pointerInside, setPointerInside] = useState(false);\n const [focusInside, setFocusInside] = useState(false);\n const [menuOpen, setMenuOpen] = useState(false);\n const menuContainerRef = useRef<HTMLDivElement>(null);\n\n const recipe = useSlotRecipe({ key: 'uiSideNav' });\n const styles = recipe({ layout: isMobile ? 'drawer' : 'rail' });\n\n // The drawer has no collapsed state to be in, so mobile is always expanded. On desktop an open\n // menu counts alongside the pointer: letting the pointer alone decide would collapse the rail\n // out from under an open workspace list.\n const expanded = isMobile || (expandedProp ?? (pointerInside || focusInside || menuOpen));\n\n const handleBlur = (event: FocusEvent<HTMLElement>) => {\n // `blur` also fires when focus moves between two rows. Only a target outside the nav counts.\n if (event.currentTarget.contains(event.relatedTarget)) return;\n setFocusInside(false);\n };\n\n const nav = (\n <Box\n ref={ref}\n aria-label=\"Platform navigation\"\n asChild\n data-expanded={expanded ? '' : undefined}\n {...rest}\n css={[styles.root, css]}\n onBlur={isMobile ? undefined : handleBlur}\n onFocus={isMobile ? undefined : () => setFocusInside(true)}\n onPointerEnter={isMobile ? undefined : () => setPointerInside(true)}\n onPointerLeave={isMobile ? undefined : () => setPointerInside(false)}\n >\n <nav>{children}</nav>\n </Box>\n );\n\n const context = { expanded, isMobile, menuContainerRef, setMenuOpen, styles };\n\n if (!isMobile) {\n return <UISideNavContextProvider value={context}>{nav}</UISideNavContextProvider>;\n }\n\n return (\n <UISideNavContextProvider value={context}>\n {/*\n No `placement`: the drawer recipe carries no placement variant, so Chakra does not accept\n the prop. Which edge the panel comes from is settled by the positioner and the slide\n animations in this component's own recipe.\n */}\n <Drawer.Root onOpenChange={(details) => onOpenChange?.(details.open)} open={open}>\n <Portal>\n <Drawer.Backdrop css={styles.backdrop} />\n <Drawer.Positioner css={styles.positioner}>\n <Drawer.Content ref={menuContainerRef} css={styles.content}>\n {nav}\n {/*\n Visually beside the panel, but still a child of the content so the dialog's focus\n trap includes it — a close button the keyboard cannot reach is not a close button.\n\n A plain button rather than `Drawer.CloseTrigger`: the trigger carries the drawer\n recipe's own `closeTrigger` slot, which pins itself inside the panel and paints the\n icon dark. The drawer is controlled anyway, so closing it is one call.\n */}\n <Box css={styles.closeButton}>\n <BitkitCloseButton\n aria-label=\"Close navigation\"\n colorVariant=\"white\"\n onClick={() => onOpenChange?.(false)}\n size=\"md\"\n />\n </Box>\n </Drawer.Content>\n </Drawer.Positioner>\n </Portal>\n </Drawer.Root>\n </UISideNavContextProvider>\n );\n});\n\nexport { uiSideNavRailWidth } from '../../theme/slot-recipes/UISideNav.recipe';\nexport { type BitkitUISideNavBodyProps } from './UISideNavBody';\nexport { type BitkitUISideNavFooterProps } from './UISideNavFooter';\nexport { type BitkitUISideNavFooterHeadingProps } from './UISideNavFooterHeading';\nexport { type BitkitUISideNavItemProps } from './UISideNavItem';\nexport {\n type BitkitUISideNavLinkAsAnchorProps,\n type BitkitUISideNavLinkAsButtonProps,\n type BitkitUISideNavLinkProps,\n} from './UISideNavLink';\nexport {\n type BitkitUISideNavWorkspaceProps,\n type BitkitUISideNavWorkspaceSelectorProps,\n} from './UISideNavWorkspaceSelector';\n\nBitkitUISideNav.displayName = 'BitkitUISideNav';\n\nexport default withSubComponents(BitkitUISideNav, {\n Body: UISideNavBody,\n Footer: UISideNavFooter,\n FooterHeading: UISideNavFooterHeading,\n Item: UISideNavItem,\n Link: UISideNavLink,\n WorkspaceSelector: UISideNavWorkspaceSelector,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,IAAM,kBAAkB,YAA+C,OAAO,QAAQ;CACpF,MAAM,EAAE,UAAU,KAAK,UAAU,cAAc,cAAc,OAAO,OAAO,GAAG,SAAS;CAEvF,MAAM,EAAE,aAAa,cAAc;CAEnC,MAAM,CAAC,eAAe,oBAAoB,SAAS,KAAK;CACxD,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK;CAC9C,MAAM,mBAAmB,OAAuB,IAAI;CAGpD,MAAM,SADS,cAAc,EAAE,KAAK,YAAY,CACjC,CAAA,CAAO,EAAE,QAAQ,WAAW,WAAW,OAAO,CAAC;CAK9D,MAAM,WAAW,aAAa,iBAAiB,iBAAiB,eAAe;CAE/E,MAAM,cAAc,UAAmC;EAErD,IAAI,MAAM,cAAc,SAAS,MAAM,aAAa,GAAG;EACvD,eAAe,KAAK;CACtB;CAEA,MAAM,MACJ,oBAAC,KAAD;EACO;EACL,cAAW;EACX,SAAA;EACA,iBAAe,WAAW,KAAK,KAAA;EAC/B,GAAI;EACJ,KAAK,CAAC,OAAO,MAAM,GAAG;EACtB,QAAQ,WAAW,KAAA,IAAY;EAC/B,SAAS,WAAW,KAAA,UAAkB,eAAe,IAAI;EACzD,gBAAgB,WAAW,KAAA,UAAkB,iBAAiB,IAAI;EAClE,gBAAgB,WAAW,KAAA,UAAkB,iBAAiB,KAAK;EAEnE,UAAA,oBAAC,OAAD,EAAM,SAAc,CAAA;CACjB,CAAA;CAGP,MAAM,UAAU;EAAE;EAAU;EAAU;EAAkB;EAAa;CAAO;CAE5E,IAAI,CAAC,UACH,OAAO,oBAAC,0BAAD;EAA0B,OAAO;EAAU,UAAA;CAA8B,CAAA;CAGlF,OACE,oBAAC,0BAAD;EAA0B,OAAO;EAM/B,UAAA,oBAAC,OAAO,MAAR;GAAa,eAAe,YAAY,eAAe,QAAQ,IAAI;GAAS;GAC1E,UAAA,qBAAC,QAAD,EAAA,UAAA,CACE,oBAAC,OAAO,UAAR,EAAiB,KAAK,OAAO,SAAW,CAAA,GACxC,oBAAC,OAAO,YAAR;IAAmB,KAAK,OAAO;IAC7B,UAAA,qBAAC,OAAO,SAAR;KAAgB,KAAK;KAAkB,KAAK,OAAO;KAAnD,UAAA,CACG,KASD,oBAAC,KAAD;MAAK,KAAK,OAAO;MACf,UAAA,oBAAC,mBAAD;OACE,cAAW;OACX,cAAa;OACb,eAAe,eAAe,KAAK;OACnC,MAAK;MACN,CAAA;KACE,CAAA,CACS;;GACC,CAAA,CACb,EAAA,CAAA;EACG,CAAA;CACW,CAAA;AAE9B,CAAC;AAiBD,gBAAgB,cAAc;AAE9B,IAAA,0BAAe,kBAAkB,iBAAiB;CAChD,MAAM;CACN,QAAQ;CACR,eAAe;CACf,MAAM;CACN,MAAM;CACN,mBAAmB;AACrB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { BoxProps } from '@chakra-ui/react/box';
2
+ import { ReactNode } from 'react';
3
+ export interface BitkitUISideNavBodyProps extends BoxProps {
4
+ children: ReactNode;
5
+ }
6
+ declare const UISideNavBody: import('react').ForwardRefExoticComponent<BitkitUISideNavBodyProps & import('react').RefAttributes<HTMLDivElement>>;
7
+ export default UISideNavBody;
@@ -0,0 +1,20 @@
1
+ import { useUISideNavContext } from "./UISideNavContext.js";
2
+ import { Box } from "@chakra-ui/react/box";
3
+ import { forwardRef } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region lib/components/BitkitUISideNav/UISideNavBody.tsx
6
+ var UISideNavBody = forwardRef((props, ref) => {
7
+ const { children, css, ...rest } = props;
8
+ const { styles } = useUISideNavContext();
9
+ return /* @__PURE__ */ jsx(Box, {
10
+ ref,
11
+ ...rest,
12
+ css: [styles.body, css],
13
+ children
14
+ });
15
+ });
16
+ UISideNavBody.displayName = "BitkitUISideNav.Body";
17
+ //#endregion
18
+ export { UISideNavBody as default };
19
+
20
+ //# sourceMappingURL=UISideNavBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UISideNavBody.js","names":[],"sources":["../../../lib/components/BitkitUISideNav/UISideNavBody.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { forwardRef, type ReactNode } from 'react';\n\nimport { useUISideNavContext } from './UISideNavContext';\n\nexport interface BitkitUISideNavBodyProps extends BoxProps {\n children: ReactNode;\n}\n\nconst UISideNavBody = forwardRef<HTMLDivElement, BitkitUISideNavBodyProps>((props, ref) => {\n const { children, css, ...rest } = props;\n\n const { styles } = useUISideNavContext();\n\n return (\n <Box ref={ref} {...rest} css={[styles.body, css]}>\n {children}\n </Box>\n );\n});\n\nUISideNavBody.displayName = 'BitkitUISideNav.Body';\n\nexport default UISideNavBody;\n"],"mappings":";;;;;AASA,IAAM,gBAAgB,YAAsD,OAAO,QAAQ;CACzF,MAAM,EAAE,UAAU,KAAK,GAAG,SAAS;CAEnC,MAAM,EAAE,WAAW,oBAAoB;CAEvC,OACE,oBAAC,KAAD;EAAU;EAAK,GAAI;EAAM,KAAK,CAAC,OAAO,MAAM,GAAG;EAC5C;CACE,CAAA;AAET,CAAC;AAED,cAAc,cAAc"}
@@ -0,0 +1,32 @@
1
+ import { SystemStyleObject } from '@chakra-ui/react/styled-system';
2
+ import { RefObject } from 'react';
3
+ export interface UISideNavContextValue {
4
+ /** True while the rail is showing its labels, and always true in the mobile drawer. */
5
+ expanded: boolean;
6
+ isMobile: boolean;
7
+ /**
8
+ * Where a menu opened inside the drawer has to be portalled: the panel itself. The panel
9
+ * scrolls, so a menu left in the flow would scroll with it and be clipped by it, and anywhere
10
+ * outside the panel is outside the dialog's focus trap.
11
+ */
12
+ menuContainerRef: RefObject<HTMLDivElement | null>;
13
+ /**
14
+ * How a descendant menu holds the rail open. The rail cannot collapse while a menu anchored
15
+ * inside it is open, or the menu would be left hanging beside a 72px strip.
16
+ */
17
+ setMenuOpen: (open: boolean) => void;
18
+ styles: Record<string, SystemStyleObject>;
19
+ }
20
+ declare const UISideNavContextProvider: import('react').Provider<UISideNavContextValue>, useUISideNavContext: () => UISideNavContextValue;
21
+ export { UISideNavContextProvider, useUISideNavContext };
22
+ /**
23
+ * Reads the side navigation's current state from inside it. Anything rendered in the footer that
24
+ * has to lay itself out differently in the collapsed rail should call this rather than have the
25
+ * state passed down to it.
26
+ *
27
+ * ```tsx
28
+ * const { expanded } = useUISideNav();
29
+ * return expanded ? <McpWidget /> : <McpWidgetIcon />;
30
+ * ```
31
+ */
32
+ export declare const useUISideNav: () => Pick<UISideNavContextValue, "expanded" | "isMobile">;
@@ -0,0 +1,28 @@
1
+ import { createContext } from "@chakra-ui/react";
2
+ //#region lib/components/BitkitUISideNav/UISideNavContext.tsx
3
+ var [UISideNavContextProvider, useUISideNavContext] = createContext({
4
+ hookName: "useUISideNavContext",
5
+ name: "UISideNavContext",
6
+ providerName: "<BitkitUISideNav />"
7
+ });
8
+ /**
9
+ * Reads the side navigation's current state from inside it. Anything rendered in the footer that
10
+ * has to lay itself out differently in the collapsed rail should call this rather than have the
11
+ * state passed down to it.
12
+ *
13
+ * ```tsx
14
+ * const { expanded } = useUISideNav();
15
+ * return expanded ? <McpWidget /> : <McpWidgetIcon />;
16
+ * ```
17
+ */
18
+ var useUISideNav = () => {
19
+ const { expanded, isMobile } = useUISideNavContext();
20
+ return {
21
+ expanded,
22
+ isMobile
23
+ };
24
+ };
25
+ //#endregion
26
+ export { UISideNavContextProvider, useUISideNav, useUISideNavContext };
27
+
28
+ //# sourceMappingURL=UISideNavContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UISideNavContext.js","names":[],"sources":["../../../lib/components/BitkitUISideNav/UISideNavContext.tsx"],"sourcesContent":["// eslint-disable-next-line no-restricted-imports\nimport { createContext } from '@chakra-ui/react';\nimport { type SystemStyleObject } from '@chakra-ui/react/styled-system';\nimport { type RefObject } from 'react';\n\nexport interface UISideNavContextValue {\n /** True while the rail is showing its labels, and always true in the mobile drawer. */\n expanded: boolean;\n isMobile: boolean;\n /**\n * Where a menu opened inside the drawer has to be portalled: the panel itself. The panel\n * scrolls, so a menu left in the flow would scroll with it and be clipped by it, and anywhere\n * outside the panel is outside the dialog's focus trap.\n */\n menuContainerRef: RefObject<HTMLDivElement | null>;\n /**\n * How a descendant menu holds the rail open. The rail cannot collapse while a menu anchored\n * inside it is open, or the menu would be left hanging beside a 72px strip.\n */\n setMenuOpen: (open: boolean) => void;\n styles: Record<string, SystemStyleObject>;\n}\n\nconst [UISideNavContextProvider, useUISideNavContext] = createContext<UISideNavContextValue>({\n hookName: 'useUISideNavContext',\n name: 'UISideNavContext',\n providerName: '<BitkitUISideNav />',\n});\n\nexport { UISideNavContextProvider, useUISideNavContext };\n\n/**\n * Reads the side navigation's current state from inside it. Anything rendered in the footer that\n * has to lay itself out differently in the collapsed rail should call this rather than have the\n * state passed down to it.\n *\n * ```tsx\n * const { expanded } = useUISideNav();\n * return expanded ? <McpWidget /> : <McpWidgetIcon />;\n * ```\n */\nexport const useUISideNav = (): Pick<UISideNavContextValue, 'expanded' | 'isMobile'> => {\n const { expanded, isMobile } = useUISideNavContext();\n return { expanded, isMobile };\n};\n"],"mappings":";;AAuBA,IAAM,CAAC,0BAA0B,uBAAuB,cAAqC;CAC3F,UAAU;CACV,MAAM;CACN,cAAc;AAChB,CAAC;;;;;;;;;;;AAcD,IAAa,qBAA2E;CACtF,MAAM,EAAE,UAAU,aAAa,oBAAoB;CACnD,OAAO;EAAE;EAAU;CAAS;AAC9B"}
@@ -0,0 +1,16 @@
1
+ import { BoxProps } from '@chakra-ui/react/box';
2
+ import { ReactNode } from 'react';
3
+ export interface BitkitUISideNavFooterProps extends BoxProps {
4
+ /**
5
+ * The rows below the navigation. Drop a `FooterHeading` between them to start a further
6
+ * section, the way the mobile drawer parts its status row from its Help links.
7
+ */
8
+ children: ReactNode;
9
+ /**
10
+ * An uppercase heading for the whole block, e.g. `Help`, drawn under the footer's own rule.
11
+ * The desktop rail has nowhere to show one when collapsed, so it usually has none.
12
+ */
13
+ label?: string;
14
+ }
15
+ declare const UISideNavFooter: import('react').ForwardRefExoticComponent<BitkitUISideNavFooterProps & import('react').RefAttributes<HTMLDivElement>>;
16
+ export default UISideNavFooter;
@@ -0,0 +1,28 @@
1
+ import { useUISideNavContext } from "./UISideNavContext.js";
2
+ import { Box } from "@chakra-ui/react/box";
3
+ import { forwardRef } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Text } from "@chakra-ui/react/text";
6
+ //#region lib/components/BitkitUISideNav/UISideNavFooter.tsx
7
+ var UISideNavFooter = forwardRef((props, ref) => {
8
+ const { children, css, label, ...rest } = props;
9
+ const { styles } = useUISideNavContext();
10
+ return /* @__PURE__ */ jsxs(Box, {
11
+ ref,
12
+ ...rest,
13
+ css: [styles.footer, css],
14
+ children: [
15
+ /* @__PURE__ */ jsx(Box, { css: styles.footerSeparator }),
16
+ label && /* @__PURE__ */ jsx(Text, {
17
+ css: styles.footerHeading,
18
+ children: label
19
+ }),
20
+ children
21
+ ]
22
+ });
23
+ });
24
+ UISideNavFooter.displayName = "BitkitUISideNav.Footer";
25
+ //#endregion
26
+ export { UISideNavFooter as default };
27
+
28
+ //# sourceMappingURL=UISideNavFooter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UISideNavFooter.js","names":[],"sources":["../../../lib/components/BitkitUISideNav/UISideNavFooter.tsx"],"sourcesContent":["import { Box, type BoxProps } from '@chakra-ui/react/box';\nimport { Text } from '@chakra-ui/react/text';\nimport { forwardRef, type ReactNode } from 'react';\n\nimport { useUISideNavContext } from './UISideNavContext';\n\nexport interface BitkitUISideNavFooterProps extends BoxProps {\n /**\n * The rows below the navigation. Drop a `FooterHeading` between them to start a further\n * section, the way the mobile drawer parts its status row from its Help links.\n */\n children: ReactNode;\n /**\n * An uppercase heading for the whole block, e.g. `Help`, drawn under the footer's own rule.\n * The desktop rail has nowhere to show one when collapsed, so it usually has none.\n */\n label?: string;\n}\n\nconst UISideNavFooter = forwardRef<HTMLDivElement, BitkitUISideNavFooterProps>((props, ref) => {\n const { children, css, label, ...rest } = props;\n\n const { styles } = useUISideNavContext();\n\n return (\n <Box ref={ref} {...rest} css={[styles.footer, css]}>\n {/* Always drawn: the design parts the footer from the navigation above it in both layouts. */}\n <Box css={styles.footerSeparator} />\n {label && <Text css={styles.footerHeading}>{label}</Text>}\n {children}\n </Box>\n );\n});\n\nUISideNavFooter.displayName = 'BitkitUISideNav.Footer';\n\nexport default UISideNavFooter;\n"],"mappings":";;;;;;AAmBA,IAAM,kBAAkB,YAAwD,OAAO,QAAQ;CAC7F,MAAM,EAAE,UAAU,KAAK,OAAO,GAAG,SAAS;CAE1C,MAAM,EAAE,WAAW,oBAAoB;CAEvC,OACE,qBAAC,KAAD;EAAU;EAAK,GAAI;EAAM,KAAK,CAAC,OAAO,QAAQ,GAAG;EAAjD,UAAA;GAEE,oBAAC,KAAD,EAAK,KAAK,OAAO,gBAAkB,CAAA;GAClC,SAAS,oBAAC,MAAD;IAAM,KAAK,OAAO;IAAgB,UAAA;GAAY,CAAA;GACvD;EACE;;AAET,CAAC;AAED,gBAAgB,cAAc"}