@box/blueprint-web 7.10.2 → 7.11.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
@@ -5285,6 +5285,50 @@ table.bp_inline_table_module_inlineTable--b023b tr:not(:last-child) td{
5285
5285
  .bp_text_input_module_textInput--3c0cc input:has(+ .bp_text_input_module_iconLoading--3c0cc){
5286
5286
  padding-inline-end:1.875rem;
5287
5287
  }
5288
+
5289
+ .bp_text_toggle_button_module_textToggleButton--527c5{
5290
+ background:var(--surface-toggle-surface);
5291
+ border:var(--border-1) solid var(--border-switch-border);
5292
+ border-radius:var(--radius-2);
5293
+ color:var(--text-text-on-light);
5294
+ cursor:pointer;
5295
+ font-family:Lato, -apple-system, BlinkMacSystemFont, "San Francisco", "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
5296
+ font-size:.875rem;
5297
+ font-weight:400;
5298
+ letter-spacing:.01875rem;
5299
+ line-height:1.25rem;
5300
+ min-height:var(--size-8);
5301
+ outline:0;
5302
+ padding-inline:var(--space-2);
5303
+ text-decoration:none;
5304
+ text-transform:none;
5305
+ -webkit-user-select:none;
5306
+ user-select:none;
5307
+ white-space:nowrap;
5308
+ }
5309
+ .bp_text_toggle_button_module_textToggleButton--527c5:disabled{
5310
+ opacity:.3;
5311
+ pointer-events:none;
5312
+ }
5313
+ .bp_text_toggle_button_module_textToggleButton--527c5[data-focus-visible]{
5314
+ box-shadow:0 0 0 .0625rem #fff,0 0 0 .1875rem #2486fc;
5315
+ }
5316
+ .bp_text_toggle_button_module_textToggleButton--527c5:active,.bp_text_toggle_button_module_textToggleButton--527c5[data-focus-visible]{
5317
+ background:var(--surface-switch-surface-hover);
5318
+ border:var(--border-1) solid var(--border-switch-border-hover);
5319
+ }
5320
+ .bp_text_toggle_button_module_textToggleButton--527c5:hover{
5321
+ background:var(--surface-toggle-surface-hover);
5322
+ }
5323
+ .bp_text_toggle_button_module_textToggleButton--527c5[aria-pressed=true]{
5324
+ background:var(--surface-toggle-surface-pressed);
5325
+ border:var(--border-1) solid var(--surface-toggle-surface-pressed);
5326
+ color:var(--text-text-on-dark);
5327
+ }
5328
+ .bp_text_toggle_button_module_textToggleButton--527c5[aria-pressed=true]:active,.bp_text_toggle_button_module_textToggleButton--527c5[aria-pressed=true]:hover,.bp_text_toggle_button_module_textToggleButton--527c5[aria-pressed=true][data-focus-visible]{
5329
+ background:var(--surface-toggle-surface-pressed-hover);
5330
+ border:var(--border-1) solid var(--surface-toggle-surface-pressed-hover);
5331
+ }
5288
5332
  :root{
5289
5333
  --notification-default-paragraph-indent:0rem;
5290
5334
  --notification-default-paragraph-spacing:0;
@@ -54,6 +54,7 @@ export * from './text';
54
54
  export * from './text-area';
55
55
  export * from './text-button';
56
56
  export * from './text-input';
57
+ export * from './text-toggle-button';
57
58
  export * from './toolbar';
58
59
  export * from './tooltip';
59
60
  export * from './trigger-button';
package/lib-esm/index.js CHANGED
@@ -69,6 +69,7 @@ export { Text } from './text/text.js';
69
69
  export { TextArea } from './text-area/text-area.js';
70
70
  export { TextButton } from './text-button/text-button.js';
71
71
  export { TextInput } from './text-input/text-input.js';
72
+ export { TextToggleButton } from './text-toggle-button/text-toggle-button.js';
72
73
  export { Toolbar } from './toolbar/index.js';
73
74
  export { Tooltip, TooltipProvider } from './tooltip/tooltip.js';
74
75
  export { TriggerButton } from './trigger-button/trigger-button.js';
@@ -0,0 +1,2 @@
1
+ export { TextToggleButton } from './text-toggle-button';
2
+ export type { TextToggleButtonProps } from './types';
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { type TextToggleButtonProps } from './types';
3
+ export declare const TextToggleButton: import("react").ForwardRefExoticComponent<Omit<TextToggleButtonProps, "ref"> & import("react").RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,40 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Button } from '@ariakit/react';
3
+ import clsx from 'clsx';
4
+ import { forwardRef } from 'react';
5
+ import { composeEventHandlers } from '../utils/composeEventHandlers.js';
6
+ import { useControllableState } from '../utils/useControllableState.js';
7
+ import styles from './text-toggle-button.module.js';
8
+
9
+ const TextToggleButton = /*#__PURE__*/forwardRef(({
10
+ pressed: pressedProp,
11
+ defaultPressed = false,
12
+ onPressedChange,
13
+ disabled,
14
+ onClick,
15
+ className,
16
+ ...rest
17
+ }, ref) => {
18
+ const [pressed = false, setPressed] = useControllableState({
19
+ prop: pressedProp,
20
+ onChange: onPressedChange,
21
+ defaultProp: defaultPressed
22
+ });
23
+ return jsx(Button, {
24
+ "aria-pressed": pressed,
25
+ "data-disabled": disabled ? '' : undefined,
26
+ "data-state": pressed ? 'on' : 'off',
27
+ ...rest,
28
+ ref: ref,
29
+ className: clsx(styles.textToggleButton, className),
30
+ disabled: disabled,
31
+ onClick: composeEventHandlers(onClick, () => {
32
+ if (!disabled) {
33
+ setPressed(!pressed);
34
+ }
35
+ })
36
+ });
37
+ });
38
+ TextToggleButton.displayName = 'TextToggleButton';
39
+
40
+ export { TextToggleButton };
@@ -0,0 +1,4 @@
1
+ import '../index.css';
2
+ var styles = {"textToggleButton":"bp_text_toggle_button_module_textToggleButton--527c5"};
3
+
4
+ export { styles as default };
@@ -0,0 +1,21 @@
1
+ import { type ButtonProps as AriakitButtonProps } from '@ariakit/react';
2
+ export interface TextToggleButtonProps extends AriakitButtonProps {
3
+ /**
4
+ * The text content of the button.
5
+ */
6
+ children: string;
7
+ /**
8
+ * The controlled state of the toggle.
9
+ */
10
+ pressed?: boolean;
11
+ /**
12
+ * The state of the toggle when initially rendered. Use `defaultPressed`
13
+ * if you do not need to control the state of the toggle.
14
+ * @defaultValue false
15
+ */
16
+ defaultPressed?: boolean;
17
+ /**
18
+ * The callback that fires when the state of the toggle changes.
19
+ */
20
+ onPressedChange?(pressed: boolean): void;
21
+ }
@@ -0,0 +1,4 @@
1
+ declare function composeEventHandlers<E>(originalEventHandler?: (event: E) => void, ourEventHandler?: (event: E) => void, { checkForDefaultPrevented }?: {
2
+ checkForDefaultPrevented?: boolean | undefined;
3
+ }): (event: E) => void;
4
+ export { composeEventHandlers };
@@ -0,0 +1,13 @@
1
+ // copy of radix function: https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx
2
+ function composeEventHandlers(originalEventHandler, ourEventHandler, {
3
+ checkForDefaultPrevented = true
4
+ } = {}) {
5
+ return function handleEvent(event) {
6
+ originalEventHandler?.(event);
7
+ if (checkForDefaultPrevented === false || !event.defaultPrevented) {
8
+ ourEventHandler?.(event);
9
+ }
10
+ };
11
+ }
12
+
13
+ export { composeEventHandlers };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
3
+ * prop or avoid re-executing effects when passed as a dependency
4
+ */
5
+ declare function useCallbackRef<T extends (...args: any[]) => any>(callback: T | undefined): T;
6
+ export { useCallbackRef };
@@ -0,0 +1,18 @@
1
+ import * as React from 'react';
2
+
3
+ // copy of radix hook: https://github.com/radix-ui/primitives/blob/main/packages/react/use-callback-ref/src/useCallbackRef.tsx
4
+ /**
5
+ * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
6
+ * prop or avoid re-executing effects when passed as a dependency
7
+ */
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ function useCallbackRef(callback) {
10
+ const callbackRef = React.useRef(callback);
11
+ React.useEffect(() => {
12
+ callbackRef.current = callback;
13
+ });
14
+ // https://github.com/facebook/react/issues/19240
15
+ return React.useMemo(() => (...args) => callbackRef.current?.(...args), []);
16
+ }
17
+
18
+ export { useCallbackRef };
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ interface UseControllableStateParams<T> {
3
+ prop?: T | undefined;
4
+ defaultProp?: T | undefined;
5
+ onChange?: (state: T) => void;
6
+ }
7
+ declare function useControllableState<T>({ prop, defaultProp, onChange }: UseControllableStateParams<T>): readonly [T | undefined, React.Dispatch<React.SetStateAction<T | undefined>>];
8
+ export { useControllableState };
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+ import { useCallbackRef } from './useCallbackRef.js';
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
5
+ function useControllableState({
6
+ prop,
7
+ defaultProp,
8
+ onChange = () => {}
9
+ }) {
10
+ const [uncontrolledProp, setUncontrolledProp] = useUncontrolledState({
11
+ defaultProp,
12
+ onChange
13
+ });
14
+ const isControlled = prop !== undefined;
15
+ const value = isControlled ? prop : uncontrolledProp;
16
+ const handleChange = useCallbackRef(onChange);
17
+ const setValue = React.useCallback(nextValue => {
18
+ if (isControlled) {
19
+ const setter = nextValue;
20
+ // renamed variable since it overlapped with variable "value" in the outer scope of hook
21
+ const internalValue = typeof nextValue === 'function' ? setter(prop) : nextValue;
22
+ if (internalValue !== prop) {
23
+ handleChange(internalValue);
24
+ }
25
+ } else {
26
+ setUncontrolledProp(nextValue);
27
+ }
28
+ }, [isControlled, prop, setUncontrolledProp, handleChange]);
29
+ return [value, setValue];
30
+ }
31
+ function useUncontrolledState({
32
+ defaultProp,
33
+ onChange
34
+ }) {
35
+ const uncontrolledState = React.useState(defaultProp);
36
+ const [value] = uncontrolledState;
37
+ const prevValueRef = React.useRef(value);
38
+ const handleChange = useCallbackRef(onChange);
39
+ React.useEffect(() => {
40
+ if (prevValueRef.current !== value) {
41
+ handleChange(value);
42
+ prevValueRef.current = value;
43
+ }
44
+ }, [value, prevValueRef, handleChange]);
45
+ return uncontrolledState;
46
+ }
47
+
48
+ export { useControllableState };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/blueprint-web",
3
- "version": "7.10.2",
3
+ "version": "7.11.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -25,23 +25,23 @@
25
25
  "@ariakit/react-core": "0.4.5",
26
26
  "@box/blueprint-web-assets": "^4.16.0",
27
27
  "@internationalized/date": "^3.5.4",
28
- "@radix-ui/react-accordion": "^1.1.2",
29
- "@radix-ui/react-checkbox": "^1.0.4",
30
- "@radix-ui/react-collapsible": "^1.0.3",
31
- "@radix-ui/react-context-menu": "^2.1.5",
32
- "@radix-ui/react-dialog": "^1.0.5",
33
- "@radix-ui/react-dropdown-menu": "^2.0.6",
34
- "@radix-ui/react-label": "^2.0.2",
35
- "@radix-ui/react-popover": "^1.0.7",
36
- "@radix-ui/react-radio-group": "^1.1.3",
37
- "@radix-ui/react-scroll-area": "^1.0.5",
38
- "@radix-ui/react-select": "^2.0.0",
39
- "@radix-ui/react-slider": "^1.1.2",
40
- "@radix-ui/react-switch": "^1.0.3",
41
- "@radix-ui/react-toast": "^1.1.5",
42
- "@radix-ui/react-toggle-group": "^1.0.4",
43
- "@radix-ui/react-toolbar": "^1.0.4",
44
- "@radix-ui/react-tooltip": "^1.0.7",
28
+ "@radix-ui/react-accordion": "1.1.2",
29
+ "@radix-ui/react-checkbox": "1.0.4",
30
+ "@radix-ui/react-collapsible": "1.0.3",
31
+ "@radix-ui/react-context-menu": "2.1.5",
32
+ "@radix-ui/react-dialog": "1.0.5",
33
+ "@radix-ui/react-dropdown-menu": "2.0.6",
34
+ "@radix-ui/react-label": "2.0.2",
35
+ "@radix-ui/react-popover": "1.0.7",
36
+ "@radix-ui/react-radio-group": "1.1.3",
37
+ "@radix-ui/react-scroll-area": "1.0.5",
38
+ "@radix-ui/react-select": "2.0.0",
39
+ "@radix-ui/react-slider": "1.1.2",
40
+ "@radix-ui/react-switch": "1.0.3",
41
+ "@radix-ui/react-toast": "1.1.5",
42
+ "@radix-ui/react-toggle-group": "1.0.4",
43
+ "@radix-ui/react-toolbar": "1.0.4",
44
+ "@radix-ui/react-tooltip": "1.0.7",
45
45
  "@react-aria/i18n": "^3.11.1",
46
46
  "@react-aria/utils": "^3.24.1",
47
47
  "@react-types/shared": "^3.23.1",
@@ -54,10 +54,10 @@
54
54
  "type-fest": "^3.2.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@box/storybook-utils": "^0.2.1",
57
+ "@box/storybook-utils": "^0.3.0",
58
58
  "react-stately": "^3.31.1"
59
59
  },
60
- "gitHead": "ddba2891d68474dbfaf1eadc9f45934fbcc3834d",
60
+ "gitHead": "64f24026d06c71ca4145bf9f77a9adb4acd37787",
61
61
  "module": "lib-esm/index.js",
62
62
  "main": "lib-esm/index.js",
63
63
  "exports": {