@box/blueprint-web 12.1.3 → 12.3.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.
@@ -67,16 +67,12 @@ const Item = props => {
67
67
  // TODO: [DSYS-549] Refactor - spread props in a single place
68
68
  const {
69
69
  status,
70
- statusIcon,
71
- statusIconAriaLabel,
72
70
  title,
73
71
  disabled,
74
72
  error,
75
73
  errorIconAriaLabel,
76
74
  ...itemRest
77
75
  } = props;
78
- const hasStatusLabel = isDefined(status) && !isDefined(statusIcon);
79
- const hasStatusIcon = !isDefined(status) && isDefined(statusIcon);
80
76
  return jsxs(RadixAccordion.Item, {
81
77
  ...itemRest,
82
78
  className: accordionItemClasses,
@@ -91,17 +87,10 @@ const Item = props => {
91
87
  children: title
92
88
  }), jsxs("div", {
93
89
  className: styles.accordionHeaderTrigger,
94
- children: [hasStatusLabel && jsx(Status, {
90
+ children: [isDefined(status) && jsx(Status, {
95
91
  className: styles.accordionStatus,
96
92
  color: error ? statusColors.error : statusColors.default,
97
93
  text: `${status}`
98
- }), hasStatusIcon && jsx(Status, {
99
- "aria-label": statusIconAriaLabel,
100
- className: styles.accordionIconStatus,
101
- color: error ? statusColors.error : statusColors.default,
102
- hideText: true,
103
- icon: statusIcon,
104
- text: statusIconAriaLabel ?? ''
105
94
  }), jsx(PointerChevron, {
106
95
  "aria-hidden": "true",
107
96
  className: styles.accordionTriggerIcon
@@ -1,4 +1,4 @@
1
1
  import '../index.css';
2
- var styles = {"accordionContent":"bp_accordion_module_accordionContent--ae5da","slideDown":"bp_accordion_module_slideDown--ae5da","slideUp":"bp_accordion_module_slideUp--ae5da","accordionContentWrapper":"bp_accordion_module_accordionContentWrapper--ae5da","accordionInlineErrorWrapper":"bp_accordion_module_accordionInlineErrorWrapper--ae5da","accordionItem":"bp_accordion_module_accordionItem--ae5da","accordionFixedContent":"bp_accordion_module_accordionFixedContent--ae5da","accordionHeader":"bp_accordion_module_accordionHeader--ae5da","accordionHeaderTrigger":"bp_accordion_module_accordionHeaderTrigger--ae5da","accordionStatus":"bp_accordion_module_accordionStatus--ae5da","accordionIconStatus":"bp_accordion_module_accordionIconStatus--ae5da","accordionTrigger":"bp_accordion_module_accordionTrigger--ae5da","accordionTriggerIcon":"bp_accordion_module_accordionTriggerIcon--ae5da"};
2
+ var styles = {"accordionContent":"bp_accordion_module_accordionContent--eb917","slideDown":"bp_accordion_module_slideDown--eb917","slideUp":"bp_accordion_module_slideUp--eb917","accordionContentWrapper":"bp_accordion_module_accordionContentWrapper--eb917","accordionInlineErrorWrapper":"bp_accordion_module_accordionInlineErrorWrapper--eb917","accordionItem":"bp_accordion_module_accordionItem--eb917","accordionFixedContent":"bp_accordion_module_accordionFixedContent--eb917","accordionHeader":"bp_accordion_module_accordionHeader--eb917","accordionHeaderTrigger":"bp_accordion_module_accordionHeaderTrigger--eb917","accordionStatus":"bp_accordion_module_accordionStatus--eb917","accordionTrigger":"bp_accordion_module_accordionTrigger--eb917","accordionTriggerIcon":"bp_accordion_module_accordionTriggerIcon--eb917"};
3
3
 
4
4
  export { styles as default };
@@ -1,5 +1,4 @@
1
1
  import { type AccordionMultipleProps, type AccordionSingleProps, type AccordionItemProps as RadixAccordionItemProps } from '@radix-ui/react-accordion';
2
- import { type FunctionComponent, type PropsWithChildren, type SVGProps } from 'react';
3
2
  import { type RequireAllOrNone } from 'type-fest';
4
3
  interface Loading {
5
4
  /** Loading state of the section. Loading sections are displaying a placeholder. When this is true `loadingAriaLabel` must also be provided. */
@@ -17,23 +16,6 @@ interface Errorable {
17
16
  */
18
17
  errorIconAriaLabel?: string;
19
18
  }
20
- interface StatusIconProps {
21
- /**
22
- * Icon displayed in a status pill next to the title
23
- * */
24
- statusIcon: FunctionComponent<PropsWithChildren<SVGProps<SVGSVGElement>>>;
25
- /**
26
- * Description of icon displayed in a status pill next to the title
27
- * */
28
- statusIconAriaLabel: string;
29
- }
30
- type StatusProps = {
31
- status: number;
32
- statusIcon?: never;
33
- statusIconAriaLabel?: never;
34
- } | ({
35
- status?: never;
36
- } & RequireAllOrNone<StatusIconProps, keyof StatusIconProps>);
37
19
  export type AccordionBaseItem = {
38
20
  /**
39
21
  * Content of the accordion item that is displayed when the section is expanded
@@ -51,11 +33,15 @@ export type AccordionSectionItem = AccordionBaseItem & Omit<RadixAccordionItemPr
51
33
  * Header text displayed
52
34
  */
53
35
  title: string;
36
+ /**
37
+ * Number displayed in a status pill next to the title
38
+ * */
39
+ status?: number;
54
40
  /**
55
41
  * Disabled state of the section.
56
42
  */
57
43
  disabled?: boolean;
58
- } & StatusProps;
44
+ };
59
45
  export type AccordionItem = AccordionSectionItem | AccordionFixedItem;
60
46
  export type AccordionItemProps = AccordionItem & React.ComponentPropsWithRef<'div'>;
61
47
  export type AccordionProps = (AccordionSingleProps | AccordionMultipleProps) & React.ComponentPropsWithRef<'div'>;
@@ -79,6 +79,7 @@ const RootInner = ({
79
79
  clearButtonAriaLabel,
80
80
  endComboboxIcon,
81
81
  idForLabel,
82
+ displaySingleSelectionAsChip = multiselect,
82
83
  ...comboboxProps
83
84
  } = rest;
84
85
  const isInput = useMemo(() => as === 'input', [as]);
@@ -152,6 +153,11 @@ const RootInner = ({
152
153
  const {
153
154
  setValue: setSelectedValue
154
155
  } = selectStore;
156
+ useEffect(() => {
157
+ if (inputValue.trim() === '' && !multiselect && selectedValue && !displaySingleSelectionAsChip && !clearOnBlur) {
158
+ setSelectedValue('');
159
+ }
160
+ }, [inputValue, multiselect, setSelectedValue, selectedValue, displaySingleSelectionAsChip, clearOnBlur]);
155
161
  const resetSelectedValue = useCallback(() => {
156
162
  setSelectedValue(multiselect ? [] : '');
157
163
  }, [multiselect, setSelectedValue]);
@@ -165,15 +171,28 @@ const RootInner = ({
165
171
  const focusInput = useCallback(() => {
166
172
  inputRef.current?.focus();
167
173
  }, []);
174
+ const onOptionClick = useCallback(displayedValue => {
175
+ // Check if inputValue is different from displayedValue,
176
+ // if so, update inputValue to displayedValue
177
+ // Othwerwise, clicking the option will do nothing.
178
+ if (inputValue.trim() !== displayedValue && !displaySingleSelectionAsChip) {
179
+ setInputValue(displayedValue);
180
+ }
181
+ }, [inputValue, setInputValue, displaySingleSelectionAsChip]);
182
+ const createClickHandler = useCallback(displayedValue => () => {
183
+ onOptionClick(displayedValue);
184
+ }, [onOptionClick]);
168
185
  const renderSelectItemOption = useCallback(option => {
169
186
  const value = getOptionValue(option);
187
+ const displayedValue = displayValue ? displayValue(option) : value;
170
188
  return jsxs(OptionWithIndicator, {
171
189
  ...(typeof option === 'object' ? option : {}),
172
190
  disabled: typeof option === 'object' && option.disabled,
191
+ onClick: createClickHandler(displayedValue),
173
192
  value: value,
174
193
  children: [jsx(Indicator, {}), displayValue ? displayValue(option) : value]
175
194
  });
176
- }, [displayValue]);
195
+ }, [displayValue, createClickHandler]);
177
196
  const renderOptionFn = renderOption || renderSelectItemOption;
178
197
  // eslint-disable-next-line react-hooks/exhaustive-deps
179
198
  const selectedValueMemoized = useMemo(() => selectedValue, [JSON.stringify(selectedValue)]);
@@ -182,7 +201,8 @@ const RootInner = ({
182
201
  if (Array.isArray(selectedValueMemoized) || showSingleSelectChip) {
183
202
  setInputValue('');
184
203
  } else if (selectedValueMemoized) {
185
- setInputValue(getDisplayValueFromOptionValue(selectedValueMemoized, options, displayValue));
204
+ const selectedDisplayValue = getDisplayValueFromOptionValue(selectedValueMemoized, options, displayValue);
205
+ setInputValue(selectedDisplayValue);
186
206
  // Also focus input for single-select variant
187
207
  focusInput();
188
208
  }
@@ -259,7 +279,7 @@ const RootInner = ({
259
279
  const reference = useForkRef(inputRef, ref);
260
280
  const showChipsGroup = Array.isArray(selectedValue) && selectedValue.length > 0;
261
281
  const showComboboxCancelButton = clearButtonAriaLabel && (inputValue.length > 0 || (Array.isArray(selectedValue) ? selectedValue.length > 0 : !!selectedValue));
262
- const showSingleSelectChip = showComboboxCancelButton && !Array.isArray(selectedValue) && !!selectedValue;
282
+ const showSingleSelectChip = displaySingleSelectionAsChip && !Array.isArray(selectedValue) && !!selectedValue;
263
283
  const Label = useLabelable(label, comboboxId);
264
284
  const inlineErrorId = useUniqueId('inline-error-');
265
285
  const ariaDescribedBy = clsx(rest['aria-describedby'], {
@@ -217,6 +217,13 @@ export interface ComboboxBaseProps<Multiple extends boolean, FreeInput extends b
217
217
  * @default true
218
218
  */
219
219
  hideOnEscape?: ComboboxPopoverProps['hideOnEscape'];
220
+ /**
221
+ * If `true`, displays the single selected value in the input field as a chip.
222
+ * This is independent of the clear button visibility.
223
+ *
224
+ * @default false
225
+ */
226
+ displaySingleSelectionAsChip?: boolean;
220
227
  }
221
228
  export type ComboboxTextArea = Pick<TextAreaProps, 'maxRows' | 'minRows' | 'maxLength' | 'aria-describedby'> & {
222
229
  as: 'textarea';
@@ -612,19 +612,19 @@
612
612
  .bp_status_module_colorSurfaceStatusSurfaceGreen--6c98f.bp_status_module_interactiveStatus--6c98f:focus-visible{
613
613
  background-color:var(--surface-status-surface-green-focus);
614
614
  }
615
- .bp_accordion_module_accordionContent--ae5da[data-state=open]{
616
- animation:bp_accordion_module_slideDown--ae5da .15s ease-out;
615
+ .bp_accordion_module_accordionContent--eb917[data-state=open]{
616
+ animation:bp_accordion_module_slideDown--eb917 .15s ease-out;
617
617
  }
618
618
 
619
- .bp_accordion_module_accordionContent--ae5da[data-state=closed]{
620
- animation:bp_accordion_module_slideUp--ae5da .15s ease-out;
619
+ .bp_accordion_module_accordionContent--eb917[data-state=closed]{
620
+ animation:bp_accordion_module_slideUp--eb917 .15s ease-out;
621
621
  }
622
622
 
623
- .bp_accordion_module_accordionContent--ae5da{
623
+ .bp_accordion_module_accordionContent--eb917{
624
624
  overflow:hidden;
625
625
  }
626
626
 
627
- @keyframes bp_accordion_module_slideDown--ae5da{
627
+ @keyframes bp_accordion_module_slideDown--eb917{
628
628
  from{
629
629
  height:0;
630
630
  }
@@ -632,7 +632,7 @@
632
632
  height:var(--radix-accordion-content-height);
633
633
  }
634
634
  }
635
- @keyframes bp_accordion_module_slideUp--ae5da{
635
+ @keyframes bp_accordion_module_slideUp--eb917{
636
636
  from{
637
637
  height:var(--radix-accordion-content-height);
638
638
  }
@@ -640,7 +640,7 @@
640
640
  height:0;
641
641
  }
642
642
  }
643
- .bp_accordion_module_accordionContentWrapper--ae5da{
643
+ .bp_accordion_module_accordionContentWrapper--eb917{
644
644
  display:flex;
645
645
  flex-direction:column;
646
646
  gap:var(--space-4);
@@ -649,20 +649,20 @@
649
649
  padding-inline:var(--space-4);
650
650
  }
651
651
 
652
- .bp_accordion_module_accordionInlineErrorWrapper--ae5da{
652
+ .bp_accordion_module_accordionInlineErrorWrapper--eb917{
653
653
  padding-block-start:var(--space-4);
654
654
  padding-inline:var(--space-4);
655
655
  }
656
656
 
657
- .bp_accordion_module_accordionItem--ae5da{
657
+ .bp_accordion_module_accordionItem--eb917{
658
658
  border-bottom:var(--border-1) solid var(--border-divider-border);
659
659
  min-width:320px;
660
660
  }
661
- .bp_accordion_module_accordionItem--ae5da,.bp_accordion_module_accordionItem--ae5da > [data-state=open]{
661
+ .bp_accordion_module_accordionItem--eb917,.bp_accordion_module_accordionItem--eb917 > [data-state=open]{
662
662
  background-color:var(--surface-accordion-surface);
663
663
  }
664
664
 
665
- .bp_accordion_module_accordionFixedContent--ae5da{
665
+ .bp_accordion_module_accordionFixedContent--eb917{
666
666
  background-color:var(--surface-surface);
667
667
  display:flex;
668
668
  flex-direction:column;
@@ -671,7 +671,7 @@
671
671
  padding-inline:var(--space-4);
672
672
  }
673
673
 
674
- .bp_accordion_module_accordionHeader--ae5da{
674
+ .bp_accordion_module_accordionHeader--eb917{
675
675
  color:var(--text-text-on-light);
676
676
  display:flex;
677
677
  font-family:var(--title-small-font-family);
@@ -688,19 +688,16 @@
688
688
  width:100%;
689
689
  }
690
690
 
691
- .bp_accordion_module_accordionHeaderTrigger--ae5da{
691
+ .bp_accordion_module_accordionHeaderTrigger--eb917{
692
692
  align-items:center;
693
693
  display:flex;
694
694
  }
695
695
 
696
- .bp_accordion_module_accordionIconStatus--ae5da,.bp_accordion_module_accordionStatus--ae5da{
696
+ .bp_accordion_module_accordionStatus--eb917{
697
697
  margin-inline-start:var(--space-2);
698
698
  }
699
- .bp_accordion_module_accordionIconStatus--ae5da > span{
700
- padding:0 var(--space-1);
701
- }
702
699
 
703
- .bp_accordion_module_accordionTrigger--ae5da{
700
+ .bp_accordion_module_accordionTrigger--eb917{
704
701
  align-items:center;
705
702
  background-color:var(--surface-surface);
706
703
  border:none;
@@ -711,31 +708,31 @@
711
708
  text-transform:capitalize;
712
709
  width:100%;
713
710
  }
714
- .bp_accordion_module_accordionTrigger--ae5da:active{
711
+ .bp_accordion_module_accordionTrigger--eb917:active{
715
712
  background-color:var(--surface-surface);
716
713
  }
717
- .bp_accordion_module_accordionTrigger--ae5da:hover{
714
+ .bp_accordion_module_accordionTrigger--eb917:hover{
718
715
  background-color:var(--surface-accordion-surface-hover);
719
716
  cursor:pointer;
720
717
  }
721
- .bp_accordion_module_accordionTrigger--ae5da:focus-visible{
718
+ .bp_accordion_module_accordionTrigger--eb917:focus-visible{
722
719
  background-color:var(--surface-surface-hover);
723
720
  box-shadow:inset 0 0 0 var(--border-2) var(--outline-focus-on-light);
724
721
  outline:none;
725
722
  }
726
- .bp_accordion_module_accordionTrigger--ae5da:disabled{
723
+ .bp_accordion_module_accordionTrigger--eb917:disabled{
727
724
  cursor:default;
728
725
  opacity:.3;
729
726
  }
730
- .bp_accordion_module_accordionTrigger--ae5da:disabled:hover{
727
+ .bp_accordion_module_accordionTrigger--eb917:disabled:hover{
731
728
  background-color:var(--gray-white);
732
729
  }
733
- .bp_accordion_module_accordionTrigger--ae5da .bp_accordion_module_accordionTriggerIcon--ae5da{
730
+ .bp_accordion_module_accordionTrigger--eb917 .bp_accordion_module_accordionTriggerIcon--eb917{
734
731
  color:var(--gray-50);
735
732
  flex-shrink:0;
736
733
  margin-inline-start:var(--space-3);
737
734
  }
738
- .bp_accordion_module_accordionTrigger--ae5da[data-state=open] .bp_accordion_module_accordionTriggerIcon--ae5da{
735
+ .bp_accordion_module_accordionTrigger--eb917[data-state=open] .bp_accordion_module_accordionTriggerIcon--eb917{
739
736
  transform:rotate(180deg);
740
737
  }
741
738
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@box/blueprint-web",
3
- "version": "12.1.3",
3
+ "version": "12.3.0",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {