@box/blueprint-web 7.32.0 → 7.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib-esm/index.css CHANGED
@@ -5374,6 +5374,53 @@ table.bp_inline_table_module_inlineTable--b023b tr:not(:last-child) td{
5374
5374
  position:relative;
5375
5375
  width:100%;
5376
5376
  }
5377
+ .bp_styles_module_splitButton--2a32d{
5378
+ display:inline-flex;
5379
+ position:relative;
5380
+ }
5381
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonLeft--2a32d{
5382
+ border-bottom-right-radius:0;
5383
+ border-top-right-radius:0;
5384
+ width:100%;
5385
+ }
5386
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonLeft--2a32d.bp_styles_module_gap--2a32d{
5387
+ margin-inline-end:1px;
5388
+ }
5389
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonLeft--2a32d:focus-visible{
5390
+ z-index:1;
5391
+ }
5392
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonLeft--2a32d.bp_styles_module_skipRightBorder--2a32d{
5393
+ border-inline-end-color:#0000 !important;
5394
+ }
5395
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonLeft--2a32d.bp_styles_module_skipRightBorder--2a32d:focus-visible{
5396
+ border-inline-end-color:var(--border-cta-border-secondary-hover) !important;
5397
+ }
5398
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_loadingButton--2a32d{
5399
+ width:100%;
5400
+ }
5401
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonRight--2a32d{
5402
+ border-end-start-radius:0;
5403
+ border-start-start-radius:0;
5404
+ padding:0 var(--size-4) !important;
5405
+ }
5406
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonRight--2a32d svg{
5407
+ height:var(--size-3);
5408
+ width:var(--size-3);
5409
+ }
5410
+ .bp_styles_module_splitButton--2a32d .bp_styles_module_splitButtonRight--2a32d:focus-visible{
5411
+ z-index:1;
5412
+ }
5413
+
5414
+ .bp_styles_module_invisible--2a32d{
5415
+ left:0;
5416
+ position:absolute;
5417
+ top:0;
5418
+ visibility:hidden;
5419
+ }
5420
+
5421
+ .bp_styles_module_dropdown--2a32d{
5422
+ min-width:160px;
5423
+ }
5377
5424
 
5378
5425
  .bp_switch_module_option--db15a{
5379
5426
  display:flex;
@@ -50,6 +50,7 @@ export * from './select';
50
50
  export * from './side-panel';
51
51
  export * from './slider';
52
52
  export * from './small-list-item';
53
+ export * from './split-button';
53
54
  export * from './status';
54
55
  export * from './switch';
55
56
  export * from './text';
@@ -62,6 +63,7 @@ export * from './tooltip';
62
63
  export * from './trigger-button';
63
64
  export * from './util-components/focus-trap';
64
65
  export * from './util-components/interactive-icon';
66
+ export * from './util-components/labelable/types';
65
67
  export * from './util-components/scrollable-container/scrollable-container';
66
68
  export * from './util-components/text-with-info-badge';
67
69
  export * from './utils/keyboardUtils';
package/lib-esm/index.js CHANGED
@@ -65,6 +65,7 @@ export { SELECT_EMPTY_VALUE, Select } from './select/select.js';
65
65
  export { SidePanel } from './side-panel/side-panel.js';
66
66
  export { Slider } from './slider/slider.js';
67
67
  export { SmallList } from './small-list-item/index.js';
68
+ export { SplitButton } from './split-button/split-button.js';
68
69
  export { Status } from './status/status.js';
69
70
  export { Switch } from './switch/index.js';
70
71
  export { Text } from './text/text.js';
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
+ export type DropdownMenuGroupProps = DropdownMenuPrimitive.DropdownMenuGroupProps;
4
+ /**
5
+ * Based on Radix-UI Group
6
+ * @see https://www.radix-ui.com/docs/primitives/components/dropdown-menu#group
7
+ */
8
+ export declare const DropdownMenuGroup: import("react").ForwardRefExoticComponent<DropdownMenuPrimitive.DropdownMenuGroupProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,17 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
+ import { forwardRef } from 'react';
4
+
5
+ /**
6
+ * Based on Radix-UI Group
7
+ * @see https://www.radix-ui.com/docs/primitives/components/dropdown-menu#group
8
+ */
9
+ const DropdownMenuGroup = /*#__PURE__*/forwardRef((props, forwardedRef) => {
10
+ return jsx(DropdownMenuPrimitive.Group, {
11
+ ...props,
12
+ ref: forwardedRef
13
+ });
14
+ });
15
+ DropdownMenuGroup.displayName = 'DropdownMenuGroup';
16
+
17
+ export { DropdownMenuGroup };
@@ -4,6 +4,7 @@ export declare const DropdownMenu: {
4
4
  (props: import("@radix-ui/react-dropdown-menu").DropdownMenuProps): import("react/jsx-runtime").JSX.Element;
5
5
  displayName: string;
6
6
  };
7
+ Group: import("react").ForwardRefExoticComponent<import("@radix-ui/react-dropdown-menu").DropdownMenuGroupProps & import("react").RefAttributes<HTMLDivElement>>;
7
8
  RadioGroup: import("react").ForwardRefExoticComponent<import("@radix-ui/react-dropdown-menu").DropdownMenuRadioGroupProps & import("react").RefAttributes<HTMLDivElement>>;
8
9
  Trigger: import("react").ForwardRefExoticComponent<import("@radix-ui/react-dropdown-menu").DropdownMenuTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
9
10
  RadioSelectItem: import("react").ForwardRefExoticComponent<import("@radix-ui/react-dropdown-menu").DropdownMenuRadioItemProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -1,5 +1,6 @@
1
1
  import { DropdownMenuCheckboxItem } from './dropdown-menu-checkbox-item.js';
2
2
  import { DropdownMenuContent } from './dropdown-menu-content.js';
3
+ import { DropdownMenuGroup } from './dropdown-menu-group.js';
3
4
  import { DropdownMenuItem } from './dropdown-menu-item.js';
4
5
  import { DropdownMenuRadioGroup } from './dropdown-menu-radio-group.js';
5
6
  import { DropdownMenuRadioSelectItem } from './dropdown-menu-radio-select-item.js';
@@ -12,6 +13,7 @@ import { DropdownMenuTrigger } from './dropdown-menu-trigger.js';
12
13
 
13
14
  const DropdownMenu = {
14
15
  Root: DropdownMenuRoot,
16
+ Group: DropdownMenuGroup,
15
17
  RadioGroup: DropdownMenuRadioGroup,
16
18
  Trigger: DropdownMenuTrigger,
17
19
  RadioSelectItem: DropdownMenuRadioSelectItem,
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ interface SplitTriggerButtonProps {
3
+ ariaLabel: string;
4
+ isOpened: boolean;
5
+ disabled: boolean;
6
+ size: 'small' | 'large';
7
+ variant: 'primary' | 'secondary';
8
+ isInvisible?: boolean;
9
+ }
10
+ export declare const SplitTriggerButton: import("react").ForwardRefExoticComponent<SplitTriggerButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
11
+ export {};
@@ -0,0 +1,32 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import clsx from 'clsx';
3
+ import { forwardRef } from 'react';
4
+ import { TriggerButton } from '../trigger-button/trigger-button.js';
5
+ import styles from './styles.module.js';
6
+
7
+ const SplitTriggerButton = /*#__PURE__*/forwardRef((props, ref) => {
8
+ const {
9
+ isInvisible,
10
+ ariaLabel: dropdownTriggerAriaLabel,
11
+ isOpened,
12
+ disabled,
13
+ size,
14
+ variant,
15
+ ...rest
16
+ } = props;
17
+ return jsx(TriggerButton, {
18
+ ref: ref,
19
+ "aria-label": dropdownTriggerAriaLabel,
20
+ caretDirection: isOpened ? 'up' : 'down',
21
+ className: clsx(styles.splitButtonRight, {
22
+ [styles.invisible]: isInvisible,
23
+ [styles.gap]: variant === 'primary'
24
+ }),
25
+ disabled: disabled,
26
+ size: size,
27
+ variant: variant,
28
+ ...rest
29
+ });
30
+ });
31
+
32
+ export { SplitTriggerButton };
@@ -0,0 +1,2 @@
1
+ export { SplitButton } from './split-button';
2
+ export { type SplitButtonProps } from './types';
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { type SplitButtonProps } from './types';
3
+ export declare const SplitButton: import("react").ForwardRefExoticComponent<SplitButtonProps & import("react").RefAttributes<unknown>>;
@@ -0,0 +1,95 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import clsx from 'clsx';
3
+ import { forwardRef, useState, useCallback } from 'react';
4
+ import { Button } from '../button/button.js';
5
+ import { DropdownMenu } from '../primitives/dropdown-menu/index.js';
6
+ import { useControllableState } from '../utils/useControllableState.js';
7
+ import { SplitTriggerButton } from './SplitTriggerButton.js';
8
+ import styles from './styles.module.js';
9
+
10
+ const SplitButton = /*#__PURE__*/forwardRef(props => {
11
+ const {
12
+ align = 'end',
13
+ children,
14
+ disabled,
15
+ dropdownTriggerAriaLabel,
16
+ label,
17
+ loading,
18
+ loadingAriaLabel,
19
+ open: openProp,
20
+ onOpenChange,
21
+ defaultOpen = false,
22
+ size = 'large',
23
+ variant = 'primary'
24
+ } = props;
25
+ const [leftButtonSize, setLeftButtonSize] = useState(undefined);
26
+ const [rightButtonSize, setRightButtonSize] = useState(undefined);
27
+ const [open = false, setOpen] = useControllableState({
28
+ prop: openProp,
29
+ onChange: onOpenChange,
30
+ defaultProp: defaultOpen
31
+ });
32
+ const onLeftButtonMountCallback = useCallback(button => {
33
+ const buttonWidth = button?.offsetWidth;
34
+ if (buttonWidth) {
35
+ setLeftButtonSize(buttonWidth);
36
+ }
37
+ }, []);
38
+ const onRightButtonMountCallback = useCallback(button => {
39
+ const buttonWidth = button?.offsetWidth;
40
+ if (buttonWidth) {
41
+ setRightButtonSize(buttonWidth);
42
+ }
43
+ }, []);
44
+ const onOpenChangeLocal = useCallback(() => {
45
+ if (!disabled) {
46
+ setOpen(!open);
47
+ }
48
+ }, [disabled, open, setOpen]);
49
+ const alignOpts = {
50
+ align,
51
+ ...(align === 'start' && leftButtonSize && {
52
+ alignOffset: -leftButtonSize
53
+ })
54
+ };
55
+ return jsxs(DropdownMenu.Root, {
56
+ onOpenChange: onOpenChangeLocal,
57
+ open: open,
58
+ children: [jsxs("span", {
59
+ className: styles.splitButton,
60
+ children: [jsx(Button, {
61
+ ref: onLeftButtonMountCallback,
62
+ className: loading ? styles.loadingButton : clsx(styles.splitButtonLeft, {
63
+ [styles.gap]: variant === 'primary',
64
+ [styles.skipRightBorder]: variant !== 'primary'
65
+ }),
66
+ disabled: disabled,
67
+ loading: loading,
68
+ loadingAriaLabel: loadingAriaLabel,
69
+ size: size,
70
+ style: {
71
+ width: loading && leftButtonSize && rightButtonSize ? leftButtonSize + rightButtonSize : undefined
72
+ },
73
+ variant: variant,
74
+ children: label
75
+ }), jsx(DropdownMenu.Trigger, {
76
+ children: jsx(SplitTriggerButton, {
77
+ ref: onRightButtonMountCallback,
78
+ ariaLabel: dropdownTriggerAriaLabel,
79
+ disabled: !!disabled,
80
+ isInvisible: loading,
81
+ isOpened: open,
82
+ size: size,
83
+ variant: variant
84
+ })
85
+ })]
86
+ }), jsx(DropdownMenu.Content, {
87
+ className: styles.dropdown,
88
+ ...alignOpts,
89
+ children: children
90
+ })]
91
+ });
92
+ });
93
+ SplitButton.displayName = 'SplitButton';
94
+
95
+ export { SplitButton };
@@ -0,0 +1,4 @@
1
+ import '../index.css';
2
+ var styles = {"splitButton":"bp_styles_module_splitButton--2a32d","splitButtonLeft":"bp_styles_module_splitButtonLeft--2a32d","gap":"bp_styles_module_gap--2a32d","skipRightBorder":"bp_styles_module_skipRightBorder--2a32d","loadingButton":"bp_styles_module_loadingButton--2a32d","splitButtonRight":"bp_styles_module_splitButtonRight--2a32d","invisible":"bp_styles_module_invisible--2a32d","dropdown":"bp_styles_module_dropdown--2a32d"};
3
+
4
+ export { styles as default };
@@ -0,0 +1,40 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type RequireAllOrNone } from 'type-fest';
3
+ interface Loading {
4
+ /** Whether the button is loading. */
5
+ loading?: boolean;
6
+ /** The aria-label for the loading indicator. */
7
+ loadingAriaLabel?: string;
8
+ }
9
+ export interface BasicSplitButtonProps {
10
+ /** Contents of the dropdown */
11
+ children: ReactNode;
12
+ /** The text of the left button */
13
+ label: string;
14
+ /** Aria-label of the right button, a.k.a DropdownMenu Trigger */
15
+ dropdownTriggerAriaLabel: string;
16
+ /** The start is the leftmost edge of the left button, end is the rightmost edge of the right button. default: end */
17
+ align?: 'start' | 'end' | 'center';
18
+ /** The size of the button. default: large */
19
+ size?: 'small' | 'large';
20
+ /** The visual style of the button. default: primary */
21
+ variant?: 'primary' | 'secondary';
22
+ /**
23
+ * The uncontrolled pressed state of the split button when initially rendered. Use `defaultOpened`
24
+ * if you do not need to control the state of the button.
25
+ * @defaultValue false
26
+ */
27
+ defaultOpen?: boolean;
28
+ /**
29
+ * The controlled state of the split button.
30
+ */
31
+ open?: boolean;
32
+ /**
33
+ * The callback that fires when the state of the dropdown menu changes.
34
+ */
35
+ onOpenChange?(pressed: boolean): void;
36
+ /** Should both buttons be disabled */
37
+ disabled?: boolean;
38
+ }
39
+ export type SplitButtonProps = BasicSplitButtonProps & RequireAllOrNone<Loading, keyof Loading>;
40
+ export {};
@@ -1,10 +1,10 @@
1
1
  /// <reference types="react" />
2
- export declare const TextArea: import("react").ForwardRefExoticComponent<(Omit<import("../util-components/labelable/types").Labelable & Omit<import("./text-area-autosize/types").TextareaAutosizeProps, "hasError"> & {
2
+ export declare const TextArea: import("react").ForwardRefExoticComponent<(Omit<import("../..").Labelable & Omit<import("./text-area-autosize/types").TextareaAutosizeProps, "hasError"> & {
3
3
  hideLabel?: boolean | undefined;
4
4
  disabled?: boolean | undefined;
5
5
  required?: boolean | undefined;
6
6
  error?: import("react").ReactNode;
7
- } & Required<Pick<import("./types").Loading, keyof import("./types").Loading>> & Omit<import("./types").Loading, keyof import("./types").Loading>, "ref"> | Omit<import("../util-components/labelable/types").Labelable & Omit<import("./text-area-autosize/types").TextareaAutosizeProps, "hasError"> & {
7
+ } & Required<Pick<import("./types").Loading, keyof import("./types").Loading>> & Omit<import("./types").Loading, keyof import("./types").Loading>, "ref"> | Omit<import("../..").Labelable & Omit<import("./text-area-autosize/types").TextareaAutosizeProps, "hasError"> & {
8
8
  hideLabel?: boolean | undefined;
9
9
  disabled?: boolean | undefined;
10
10
  required?: boolean | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/blueprint-web",
3
- "version": "7.32.0",
3
+ "version": "7.33.0",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {
@@ -63,7 +63,7 @@
63
63
  "react-stately": "^3.31.1",
64
64
  "tsx": "^4.16.5"
65
65
  },
66
- "gitHead": "a917668414b5d0e1dc46512bd579e9cc958b51ea",
66
+ "gitHead": "655a58b8accd00ab49186551834a7a0c7b9237f4",
67
67
  "module": "lib-esm/index.js",
68
68
  "main": "lib-esm/index.js",
69
69
  "exports": {