@box/blueprint-web 12.17.2 → 12.18.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.
@@ -6908,6 +6908,147 @@ div[data-radix-popper-content-wrapper]:has([role=menu]):has([data-state=open]):h
6908
6908
  background:var(--surface-toggletext-surface-on-pressed);
6909
6909
  border-color:var(--border-toggletext-border-on-pressed);
6910
6910
  }
6911
+
6912
+ .bp_time_picker_module_timePicker--7ed90{
6913
+ --time-picker-padding-right:var(--space-4);
6914
+ --time-picker-border-width:var(--border-2);
6915
+ --time-picker-focused-border-color:var(--outline-focus-on-light);
6916
+ --clear-time-picker-button-right:var(--size-11);
6917
+ --time-picker-icon-button-size:var(--size-6);
6918
+ --time-picker-icon-size:var(--size-4);
6919
+ width:100%;
6920
+ }
6921
+ .bp_time_picker_module_timePicker--7ed90.bp_time_picker_module_disabled--7ed90{
6922
+ opacity:60%;
6923
+ pointer-events:none;
6924
+ -webkit-user-select:none;
6925
+ user-select:none;
6926
+ }
6927
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_label--7ed90{
6928
+ cursor:default;
6929
+ display:block;
6930
+ font-family:var(--body-default-bold-font-family);
6931
+ font-size:var(--body-default-bold-font-size);
6932
+ font-weight:var(--body-default-bold-font-weight);
6933
+ letter-spacing:var(--body-default-bold-letter-spacing);
6934
+ line-height:var(--body-default-bold-line-height);
6935
+ margin-block-end:var(--space-2);
6936
+ -webkit-text-decoration:var(--body-default-bold-text-decoration);
6937
+ text-decoration:var(--body-default-bold-text-decoration);
6938
+ text-transform:var(--body-default-bold-text-case);
6939
+ width:-moz-fit-content;
6940
+ width:fit-content;
6941
+ }
6942
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_group--7ed90{
6943
+ align-items:center;
6944
+ border-radius:var(--radius-2);
6945
+ box-shadow:var(--innershadow-1);
6946
+ box-sizing:border-box;
6947
+ display:inline-flex;
6948
+ font-family:var(--body-default-font-family);
6949
+ font-size:var(--body-default-font-size);
6950
+ font-weight:var(--body-default-font-weight);
6951
+ letter-spacing:var(--body-default-letter-spacing);
6952
+ line-height:var(--body-default-line-height);
6953
+ outline:var(--border-1) solid var(--border-input-border);
6954
+ padding-inline:var(--space-3) var(--time-picker-padding-right);
6955
+ position:relative;
6956
+ -webkit-text-decoration:var(--body-default-text-decoration);
6957
+ text-decoration:var(--body-default-text-decoration);
6958
+ text-transform:var(--body-default-text-case);
6959
+ width:100%;
6960
+ }
6961
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_group--7ed90:focus-within{
6962
+ outline:var(--time-picker-border-width) solid var(--time-picker-focused-border-color);
6963
+ }
6964
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_group--7ed90.bp_time_picker_module_error--7ed90:not(:focus-within){
6965
+ outline:var(--time-picker-border-width) solid var(--text-text-error-on-light);
6966
+ }
6967
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_group--7ed90.bp_time_picker_module_error--7ed90:focus-within{
6968
+ outline:var(--time-picker-border-width) solid var(--time-picker-focused-border-color);
6969
+ }
6970
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInput--7ed90{
6971
+ align-items:center;
6972
+ display:inline-flex;
6973
+ height:var(--size-10);
6974
+ margin-inline-end:calc(var(--time-picker-icon-button-size) + var(--clear-time-picker-button-right));
6975
+ text-transform:uppercase;
6976
+ white-space:nowrap;
6977
+ }
6978
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90{
6979
+ border:unset;
6980
+ border-radius:unset;
6981
+ border-radius:var(--radius-1);
6982
+ box-shadow:unset;
6983
+ color:var(--text-text-on-light);
6984
+ height:-moz-fit-content;
6985
+ height:fit-content;
6986
+ padding:unset;
6987
+ transition:unset;
6988
+ width:unset;
6989
+ }
6990
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90[data-placeholder]{
6991
+ color:var(--text-text-on-light-secondary);
6992
+ }
6993
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90[role=spinbutton]{
6994
+ margin:0 var(--space-05);
6995
+ padding:0 var(--space-1);
6996
+ }
6997
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90:active,.bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90:focus{
6998
+ background:var(--box-blue-100);
6999
+ caret-color:#0000;
7000
+ color:var(--text-text-brand-on-color);
7001
+ outline:none;
7002
+ }
7003
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90:nth-child(1 of [role=spinbutton]){
7004
+ margin-inline-start:0;
7005
+ }
7006
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_timeInputSegment--7ed90[data-type=literal] + [data-type=dayPeriod]{
7007
+ margin-inline-start:calc(var(--space-1)*-1);
7008
+ }
7009
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90{
7010
+ align-items:center;
7011
+ background-color:initial;
7012
+ border:none;
7013
+ border-radius:var(--radius-2);
7014
+ cursor:pointer;
7015
+ display:flex;
7016
+ height:var(--time-picker-icon-button-size);
7017
+ justify-content:center;
7018
+ outline:none;
7019
+ padding:0;
7020
+ position:absolute;
7021
+ right:var(--clear-time-picker-button-right);
7022
+ width:var(--time-picker-icon-button-size);
7023
+ }
7024
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90:focus-visible,.bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90[data-focus-visible]{
7025
+ background-color:var(--surface-cta-surface-icon-pressed);
7026
+ outline:var(--border-2) solid var(--outline-focus-on-light);
7027
+ }
7028
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90:hover{
7029
+ background:var(--surface-cta-surface-icon-hover);
7030
+ }
7031
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90:hover *{
7032
+ fill:var(--icon-cta-icon-hover);
7033
+ }
7034
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90:active{
7035
+ background:var(--surface-cta-surface-icon-pressed);
7036
+ }
7037
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90:active *{
7038
+ fill:var(--icon-cta-icon-pressed);
7039
+ }
7040
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clearButton--7ed90:disabled{
7041
+ opacity:1;
7042
+ }
7043
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_clockIcon--7ed90{
7044
+ height:var(--time-picker-icon-size);
7045
+ position:absolute;
7046
+ right:var(--time-picker-padding-right);
7047
+ width:var(--time-picker-icon-size);
7048
+ }
7049
+ .bp_time_picker_module_timePicker--7ed90 .bp_time_picker_module_inlineError--7ed90{
7050
+ margin-block-start:var(--space-2);
7051
+ }
6911
7052
  :root{
6912
7053
  --surface-surface-brand:#0061d5;
6913
7054
  --surface-surface-brand-hover:#006ae9;
@@ -67,6 +67,7 @@ export * from './text-area';
67
67
  export * from './text-button';
68
68
  export * from './text-input';
69
69
  export * from './text-toggle-button';
70
+ export * from './time-picker';
70
71
  export * from './toolbar';
71
72
  export * from './tooltip';
72
73
  export * from './trigger-button';
@@ -85,6 +85,7 @@ export { TextArea } from './text-area/text-area.js';
85
85
  export { TextButton } from './text-button/text-button.js';
86
86
  export { TextInput } from './text-input/text-input.js';
87
87
  export { TextToggleButton } from './text-toggle-button/text-toggle-button.js';
88
+ export { TimePicker } from './time-picker/time-picker.js';
88
89
  export { Toolbar } from './toolbar/index.js';
89
90
  export { Tooltip, TooltipProvider } from './tooltip/tooltip.js';
90
91
  export { TriggerButton } from './trigger-button/trigger-button.js';
@@ -0,0 +1,2 @@
1
+ export { TimePicker } from './time-picker';
2
+ export { type TimePickerProps, type TimePickerTime } from './types';
@@ -0,0 +1,2 @@
1
+ import { type TimePickerProps } from './types';
2
+ export declare const TimePicker: import("react").ForwardRefExoticComponent<TimePickerProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,115 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { ClockBadge, XMark } from '@box/blueprint-web-assets/icons/Fill';
3
+ import { Gray65, Size4 } from '@box/blueprint-web-assets/tokens/tokens';
4
+ import clsx from 'clsx';
5
+ import { forwardRef, useRef, useCallback } from 'react';
6
+ import { TimeField, Group, DateInput, DateSegment } from 'react-aria-components';
7
+ import { IconButton } from '../primitives/icon-button/icon-button.js';
8
+ import { InlineError } from '../primitives/inline-error/inline-error.js';
9
+ import { useLabelable } from '../util-components/labelable/useLabelable.js';
10
+ import { useControllableState } from '../utils/useControllableState.js';
11
+ import { useUniqueId } from '../utils/useUniqueId.js';
12
+ import styles from './time-picker.module.js';
13
+
14
+ const ClearIcon = label => () => jsx(XMark, {
15
+ "aria-label": label,
16
+ color: Gray65,
17
+ height: Size4,
18
+ width: Size4
19
+ });
20
+ const TimePicker = /*#__PURE__*/forwardRef((props, forwardedRef) => {
21
+ const {
22
+ className,
23
+ onChange,
24
+ value,
25
+ defaultValue,
26
+ label,
27
+ error,
28
+ isDisabled,
29
+ hideLabel = false,
30
+ clearTimePickerAriaLabel,
31
+ clockIconAriaLabel,
32
+ shouldForceLeadingZeros = true,
33
+ ...rest
34
+ } = props;
35
+ // Component may be uncontrolled or controlled
36
+ const [time, setTimeValue] = useControllableState({
37
+ prop: value,
38
+ onChange,
39
+ defaultProp: defaultValue
40
+ });
41
+ const firstSegmentRef = useRef(null);
42
+ const handleClearInputButtonClicked = useCallback(() => {
43
+ setTimeValue(null);
44
+ }, [setTimeValue]);
45
+ const handleClearButtonKeypress = useCallback(({
46
+ key
47
+ }) => {
48
+ if ([' ', 'Enter'].includes(key)) {
49
+ handleClearInputButtonClicked();
50
+ firstSegmentRef.current?.focus();
51
+ }
52
+ }, [handleClearInputButtonClicked]);
53
+ const inlineErrorId = useUniqueId('inline-error-');
54
+ const Label = useLabelable(label, useUniqueId('time-picker-'));
55
+ const hasError = !!error && !isDisabled;
56
+ const ariaDescribedBy = clsx(rest['aria-describedby'], {
57
+ [inlineErrorId]: hasError
58
+ });
59
+ return jsxs(TimeField, {
60
+ ...rest,
61
+ ref: forwardedRef,
62
+ "aria-describedby": ariaDescribedBy,
63
+ className: clsx(styles.timePicker, {
64
+ [styles.disabled]: isDisabled
65
+ }, className),
66
+ isDisabled: isDisabled,
67
+ isInvalid: hasError,
68
+ onChange: setTimeValue,
69
+ shouldForceLeadingZeros: shouldForceLeadingZeros,
70
+ value: time,
71
+ children: [jsx(Label, {
72
+ className: clsx(styles.label, {
73
+ [styles.disabled]: isDisabled
74
+ }),
75
+ hideLabel: hideLabel
76
+ }), jsxs(Group, {
77
+ className: clsx(styles.group, {
78
+ [styles.error]: hasError
79
+ }),
80
+ children: [jsx(DateInput, {
81
+ className: clsx(styles.timeInput),
82
+ children: segment => jsx(DateSegment, {
83
+ ref: node => {
84
+ // We need to find the first actionable segment, i.e. spinbutton
85
+ if (!firstSegmentRef.current && node.role === 'spinbutton') {
86
+ firstSegmentRef.current = node;
87
+ }
88
+ },
89
+ className: styles.timeInputSegment,
90
+ segment: segment
91
+ })
92
+ }), (value || time) && jsx(IconButton, {
93
+ "aria-label": clearTimePickerAriaLabel,
94
+ className: styles.clearButton,
95
+ disabled: isDisabled,
96
+ icon: ClearIcon(clearTimePickerAriaLabel),
97
+ onClick: handleClearInputButtonClicked,
98
+ onKeyDownCapture: handleClearButtonKeypress,
99
+ size: "x-small"
100
+ }), jsx(ClockBadge, {
101
+ "aria-label": clockIconAriaLabel,
102
+ className: styles.clockIcon,
103
+ color: Gray65,
104
+ height: Size4,
105
+ width: Size4
106
+ })]
107
+ }), jsx(InlineError, {
108
+ className: styles.inlineError,
109
+ id: inlineErrorId,
110
+ children: error
111
+ })]
112
+ });
113
+ });
114
+
115
+ export { TimePicker };
@@ -0,0 +1,4 @@
1
+ import '../index.css';
2
+ var styles = {"timePicker":"bp_time_picker_module_timePicker--7ed90","disabled":"bp_time_picker_module_disabled--7ed90","label":"bp_time_picker_module_label--7ed90","group":"bp_time_picker_module_group--7ed90","error":"bp_time_picker_module_error--7ed90","timeInput":"bp_time_picker_module_timeInput--7ed90","timeInputSegment":"bp_time_picker_module_timeInputSegment--7ed90","clearButton":"bp_time_picker_module_clearButton--7ed90","clockIcon":"bp_time_picker_module_clockIcon--7ed90","inlineError":"bp_time_picker_module_inlineError--7ed90"};
3
+
4
+ export { styles as default };
@@ -0,0 +1,24 @@
1
+ import { type Time } from '@internationalized/date';
2
+ import { type TimeFieldProps as RACTimeFieldProps } from 'react-aria-components';
3
+ import { type Labelable } from '../util-components/labelable';
4
+ export type { Time as TimePickerTime };
5
+ export interface TimePickerProps extends Omit<RACTimeFieldProps<Time>, 'children'>, Labelable {
6
+ /**
7
+ * When `true`, label text is hidden.
8
+ *
9
+ * @default false
10
+ */
11
+ hideLabel?: boolean;
12
+ /**
13
+ * Aria label for button clearing TimePicker input
14
+ */
15
+ clearTimePickerAriaLabel: string;
16
+ /**
17
+ * Aria label for clock icon
18
+ */
19
+ clockIconAriaLabel: string;
20
+ /**
21
+ * The content of the error message.
22
+ */
23
+ error?: React.ReactNode;
24
+ }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
 
3
- // copy of radix hook: https://github.com/radix-ui/primitives/blob/main/packages/react/use-callback-ref/src/useCallbackRef.tsx
3
+ // copy of radix hook: https://github.com/radix-ui/primitives/blob/main/packages/react/use-callback-ref/src/use-callback-ref.tsx
4
4
  /**
5
5
  * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
6
6
  * prop or avoid re-executing effects when passed as a dependency
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/blueprint-web",
3
- "version": "12.17.2",
3
+ "version": "12.18.0",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {