@itwin/itwinui-react 1.32.0-dev.0 → 1.32.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/cjs/core/Checkbox/Checkbox.d.ts +13 -0
  3. package/cjs/core/Checkbox/Checkbox.js +15 -22
  4. package/cjs/core/ColorPicker/ColorSwatch.d.ts +1 -1
  5. package/cjs/core/ComboBox/ComboBox.d.ts +11 -0
  6. package/cjs/core/ComboBox/ComboBox.js +52 -19
  7. package/cjs/core/ExpandableBlock/ExpandableBlock.d.ts +6 -0
  8. package/cjs/core/ExpandableBlock/ExpandableBlock.js +3 -2
  9. package/cjs/core/Menu/Menu.js +3 -3
  10. package/cjs/core/Radio/Radio.d.ts +13 -0
  11. package/cjs/core/Radio/Radio.js +7 -8
  12. package/cjs/core/Tree/Tree.d.ts +123 -0
  13. package/cjs/core/Tree/Tree.js +177 -0
  14. package/cjs/core/Tree/TreeContext.d.ts +25 -0
  15. package/cjs/core/Tree/TreeContext.js +20 -0
  16. package/cjs/core/Tree/TreeNode.d.ts +87 -0
  17. package/cjs/core/Tree/TreeNode.js +169 -0
  18. package/cjs/core/Tree/TreeNodeExpander.d.ts +8 -0
  19. package/cjs/core/Tree/TreeNodeExpander.js +46 -0
  20. package/cjs/core/Tree/index.d.ts +6 -0
  21. package/cjs/core/Tree/index.js +13 -0
  22. package/cjs/core/index.d.ts +2 -0
  23. package/cjs/core/index.js +5 -1
  24. package/cjs/core/utils/functions/focusable.js +6 -2
  25. package/esm/core/Checkbox/Checkbox.d.ts +13 -0
  26. package/esm/core/Checkbox/Checkbox.js +15 -22
  27. package/esm/core/ColorPicker/ColorSwatch.d.ts +1 -1
  28. package/esm/core/ComboBox/ComboBox.d.ts +11 -0
  29. package/esm/core/ComboBox/ComboBox.js +53 -20
  30. package/esm/core/ExpandableBlock/ExpandableBlock.d.ts +6 -0
  31. package/esm/core/ExpandableBlock/ExpandableBlock.js +3 -2
  32. package/esm/core/Menu/Menu.js +3 -3
  33. package/esm/core/Radio/Radio.d.ts +13 -0
  34. package/esm/core/Radio/Radio.js +7 -8
  35. package/esm/core/Tree/Tree.d.ts +123 -0
  36. package/esm/core/Tree/Tree.js +170 -0
  37. package/esm/core/Tree/TreeContext.d.ts +25 -0
  38. package/esm/core/Tree/TreeContext.js +13 -0
  39. package/esm/core/Tree/TreeNode.d.ts +87 -0
  40. package/esm/core/Tree/TreeNode.js +162 -0
  41. package/esm/core/Tree/TreeNodeExpander.d.ts +8 -0
  42. package/esm/core/Tree/TreeNodeExpander.js +39 -0
  43. package/esm/core/Tree/index.d.ts +6 -0
  44. package/esm/core/Tree/index.js +7 -0
  45. package/esm/core/index.d.ts +2 -0
  46. package/esm/core/index.js +1 -0
  47. package/esm/core/utils/functions/focusable.js +6 -2
  48. package/package.json +2 -2
@@ -32,6 +32,7 @@ import '@itwin/itwinui-css/css/inputs.css';
32
32
  /**
33
33
  * Simple input checkbox
34
34
  * @example
35
+ * <Checkbox />
35
36
  * <Checkbox label='Basic Checkbox' />
36
37
  * <Checkbox label='Disabled Checkbox' disabled />
37
38
  * <Checkbox label='Checked' checked />
@@ -41,8 +42,8 @@ import '@itwin/itwinui-css/css/inputs.css';
41
42
  * <Checkbox label='Visibility Checkbox' variant='eyeball' />
42
43
  */
43
44
  export var Checkbox = React.forwardRef(function (props, ref) {
44
- var _a;
45
- var className = props.className, _b = props.disabled, disabled = _b === void 0 ? false : _b, _c = props.indeterminate, indeterminate = _c === void 0 ? false : _c, label = props.label, status = props.status, _d = props.variant, variant = _d === void 0 ? 'default' : _d, setFocus = props.setFocus, _e = props.isLoading, isLoading = _e === void 0 ? false : _e, style = props.style, checkmarkClassName = props.checkmarkClassName, checkmarkStyle = props.checkmarkStyle, rest = __rest(props, ["className", "disabled", "indeterminate", "label", "status", "variant", "setFocus", "isLoading", "style", "checkmarkClassName", "checkmarkStyle"]);
45
+ var _a, _b;
46
+ var className = props.className, _c = props.disabled, disabled = _c === void 0 ? false : _c, _d = props.indeterminate, indeterminate = _d === void 0 ? false : _d, label = props.label, status = props.status, _e = props.variant, variant = _e === void 0 ? 'default' : _e, setFocus = props.setFocus, _f = props.isLoading, isLoading = _f === void 0 ? false : _f, style = props.style, checkmarkClassName = props.checkmarkClassName, checkmarkStyle = props.checkmarkStyle, rest = __rest(props, ["className", "disabled", "indeterminate", "label", "status", "variant", "setFocus", "isLoading", "style", "checkmarkClassName", "checkmarkStyle"]);
46
47
  useTheme();
47
48
  var inputElementRef = React.useRef(null);
48
49
  var refs = useMergedRefs(inputElementRef, ref);
@@ -59,27 +60,19 @@ export var Checkbox = React.forwardRef(function (props, ref) {
59
60
  : inputElementRef.current.checked;
60
61
  }
61
62
  });
62
- var defaultCheckbox = (React.createElement("svg", { viewBox: '0 0 16 16', "aria-hidden": 'true', focusable: 'false' },
63
- React.createElement("path", { className: 'iui-check', d: 'm6.5 12.5-4.5-4.5 1.5-1.5 3 3 6-6 1.5 1.5z' }),
64
- React.createElement("path", { className: 'iui-check-partial', d: 'm2.75 6.875h10.5v2.25h-10.5z' })));
65
- var visibilityCheckbox = (React.createElement("svg", { viewBox: '0 0 16 16', "aria-hidden": 'true', focusable: 'false' },
66
- React.createElement("path", { className: 'iui-check', d: 'm8 2.99051a8.81883 8.81883 0 0 0 -8 4.95062 8.74664 8.74664 0 0 0 8 5.06836 8.63266 8.63266 0 0 0 8-5.06836 8.83631 8.83631 0 0 0 -8-4.95062zm-1.31445 1.86981a1.47663 1.47663 0 1 1 -1.47663 1.47668 1.47665 1.47665 0 0 1 1.47663-1.47668zm1.31445 6.64917a7.17486 7.17486 0 0 1 -6.30475-3.55237 7.4952 7.4952 0 0 1 2.81475-2.6336 3.83956 3.83956 0 1 0 6.98126.00244 7.522 7.522 0 0 1 2.81774 2.63916 7.09785 7.09785 0 0 1 -6.309 3.54437z' }),
67
- React.createElement("g", { className: 'iui-check-partial' },
68
- React.createElement("path", { d: 'm8 3v7.9a4.01179 4.01179 0 0 0 4-4 6.7509 6.7509 0 0 0 -.2-1.4l.1.1a6.89429 6.89429 0 0 1 2.4 2.4 8.39088 8.39088 0 0 1 -2.3 2.3 6.89412 6.89412 0 0 1 -3.9 1.2c-.03345 0-.06653-.00677-.1-.0072v1.5072a8.90686 8.90686 0 0 0 8-5 8.90686 8.90686 0 0 0 -8-5z', opacity: '.33' }),
69
- React.createElement("path", { d: 'm8 0a1 1 0 0 0 -1 1v2.07135a8.91637 8.91637 0 0 0 -7 4.92865 8.91637 8.91637 0 0 0 7 4.92865v2.07135a1 1 0 0 0 2 0v-14a1 1 0 0 0 -1-1zm-1.5 4.9a1.55426 1.55426 0 0 1 .5.087v2.81451a1.40746 1.40746 0 0 1 -.5.09849 1.538 1.538 0 0 1 -1.5-1.5 1.53794 1.53794 0 0 1 1.5-1.5zm-2.3 5.4a6.97279 6.97279 0 0 1 -2.5-2.3 6.89429 6.89429 0 0 1 2.4-2.4c.1 0 .1-.1.2-.1a3.194 3.194 0 0 0 -.3 1.4 4.0047 4.0047 0 0 0 3 3.857v.65289a6.37491 6.37491 0 0 1 -2.8-1.10989z' })),
70
- React.createElement("path", { className: 'iui-uncheck', d: 'm1.70671 12.879 11.17218-11.17219 1.4142 1.4142-11.17218 11.17218zm.99329-1.679 1.1-1.1a5.06317 5.06317 0 0 1 -2-2.1 7.48268 7.48268 0 0 1 6.2-3.5 4.86877 4.86877 0 0 1 1.2.1l1.3-1.3a10.07431 10.07431 0 0 0 -2.5-.3 8.84129 8.84129 0 0 0 -8 5 8.42455 8.42455 0 0 0 2.7 3.2zm10.7-6.4-1.1 1.1a7.08625 7.08625 0 0 1 2 2.1 7.50323 7.50323 0 0 1 -6.2 3.5 8.31665 8.31665 0 0 1 -1.3-.2l-1.3 1.3a8.909 8.909 0 0 0 6.4-.5 9.04344 9.04344 0 0 0 4.1-4.1 9.168 9.168 0 0 0 -2.6-3.2z' })));
71
- return (React.createElement("label", { className: cx('iui-checkbox', (_a = {
63
+ var checkbox = (React.createElement(React.Fragment, null,
64
+ React.createElement("input", __assign({ className: cx('iui-checkbox', {
65
+ 'iui-checkbox-visibility': variant === 'eyeball',
66
+ 'iui-loading': isLoading,
67
+ }, className && (_a = {}, _a[className] = !label, _a), checkmarkClassName), style: __assign(__assign({}, (!label && style)), checkmarkStyle), disabled: disabled || isLoading, type: 'checkbox', ref: refs }, rest)),
68
+ isLoading && React.createElement(ProgressRadial, { size: 'x-small', indeterminate: true })));
69
+ return !label ? (checkbox) : (React.createElement("label", { className: cx('iui-checkbox-wrapper', (_b = {
72
70
  'iui-disabled': disabled
73
71
  },
74
- _a["iui-" + status] = !!status,
75
- _a['iui-loading'] = isLoading,
76
- _a['iui-checkbox-visibility'] = variant === 'eyeball',
77
- _a), className), style: style },
78
- React.createElement("input", __assign({ disabled: disabled || isLoading, type: 'checkbox', ref: refs }, rest)),
79
- React.createElement("span", { className: cx('iui-checkbox-checkmark', checkmarkClassName), style: checkmarkStyle },
80
- isLoading && React.createElement(ProgressRadial, { indeterminate: true }),
81
- !isLoading &&
82
- (variant === 'default' ? defaultCheckbox : visibilityCheckbox)),
83
- label && React.createElement("span", { className: 'iui-label' }, label)));
72
+ _b["iui-" + status] = !!status,
73
+ _b['iui-loading'] = isLoading,
74
+ _b), className), style: style },
75
+ checkbox,
76
+ label && React.createElement("span", { className: 'iui-checkbox-label' }, label)));
84
77
  });
85
78
  export default Checkbox;
@@ -17,5 +17,5 @@ export declare type ColorSwatchProps = {
17
17
  * <ColorSwatch color='#23450b' onClick={onClick}/>
18
18
  * <ColorSwatch color={{ r: 255, g: 255, b: 0 }} onClick={onClick}/>
19
19
  */
20
- export declare const ColorSwatch: React.ForwardRefExoticComponent<Pick<ColorSwatchProps, "dir" | "slot" | "style" | "title" | "id" | "role" | "children" | "className" | "accessKey" | "draggable" | "hidden" | "lang" | "translate" | "prefix" | "contentEditable" | "inputMode" | "tabIndex" | "onFocus" | "color" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "contextMenu" | "placeholder" | "spellCheck" | "radioGroup" | "about" | "datatype" | "inlist" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "is" | "isActive"> & React.RefAttributes<HTMLDivElement>>;
20
+ export declare const ColorSwatch: React.ForwardRefExoticComponent<Pick<ColorSwatchProps, "dir" | "slot" | "style" | "title" | "id" | "aria-disabled" | "role" | "children" | "className" | "accessKey" | "draggable" | "hidden" | "lang" | "translate" | "prefix" | "contentEditable" | "inputMode" | "tabIndex" | "onFocus" | "color" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "key" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "contextMenu" | "placeholder" | "spellCheck" | "radioGroup" | "about" | "datatype" | "inlist" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "is" | "isActive"> & React.RefAttributes<HTMLDivElement>>;
21
21
  export default ColorSwatch;
@@ -33,6 +33,17 @@ export declare type ComboBoxProps<T> = {
33
33
  * @default 'No options found'
34
34
  */
35
35
  emptyStateMessage?: string;
36
+ /**
37
+ * A custom item renderer can be specified to control the rendering.
38
+ * This function should ideally return a customized version of `MenuItem`,
39
+ * otherwise you will need to make sure to provide styling for the `isFocused` state.
40
+ */
41
+ itemRenderer?: (option: SelectOption<T>, states: {
42
+ isSelected: boolean;
43
+ isFocused: boolean;
44
+ id: string;
45
+ index: number;
46
+ }) => JSX.Element;
36
47
  } & Pick<InputContainerProps, 'status'> & Omit<CommonProps, 'title'>;
37
48
  /**
38
49
  * ComboBox component that allows typing a value to filter the options in dropdown list.
@@ -29,7 +29,7 @@ import cx from 'classnames';
29
29
  import { Input } from '../Input';
30
30
  import { Menu, MenuExtraContent, MenuItem } from '../Menu';
31
31
  import { Text } from '../Typography';
32
- import { InputContainer, useTheme, Popover, getFocusableElements, getRandomValue, } from '../utils';
32
+ import { InputContainer, useTheme, Popover, getFocusableElements, getRandomValue, mergeRefs, } from '../utils';
33
33
  import SvgCaretDownSmall from '@itwin/itwinui-icons-react/cjs/icons/CaretDownSmall';
34
34
  import 'tippy.js/animations/shift-away.css';
35
35
  /**
@@ -46,7 +46,7 @@ import 'tippy.js/animations/shift-away.css';
46
46
  * />
47
47
  */
48
48
  export var ComboBox = function (props) {
49
- var options = props.options, value = props.value, onChange = props.onChange, filterFunction = props.filterFunction, className = props.className, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _a = props.emptyStateMessage, emptyStateMessage = _a === void 0 ? 'No options found' : _a, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "className", "inputProps", "dropdownMenuProps", "emptyStateMessage"]);
49
+ var options = props.options, value = props.value, onChange = props.onChange, filterFunction = props.filterFunction, className = props.className, inputProps = props.inputProps, dropdownMenuProps = props.dropdownMenuProps, _a = props.emptyStateMessage, emptyStateMessage = _a === void 0 ? 'No options found' : _a, itemRenderer = props.itemRenderer, rest = __rest(props, ["options", "value", "onChange", "filterFunction", "className", "inputProps", "dropdownMenuProps", "emptyStateMessage", "itemRenderer"]);
50
50
  // Generate a stateful random id if not specified
51
51
  var id = React.useState(function () {
52
52
  var _a, _b;
@@ -61,16 +61,31 @@ export var ComboBox = function (props) {
61
61
  return value === options[index].value;
62
62
  });
63
63
  }, [options, id]);
64
+ var userOnChange = React.useRef(onChange);
64
65
  var memoizedItems = React.useMemo(function () {
65
- return options.map(function (_a, index) {
66
- var label = _a.label, value = _a.value, rest = __rest(_a, ["label", "value"]);
67
- return (React.createElement(MenuItem, __assign({ id: getOptionId(index), key: getOptionId(index), value: value, role: 'option', onClick: function (value) {
66
+ return options.map(function (option, index) {
67
+ var label = option.label, value = option.value, rest = __rest(option, ["label", "value"]);
68
+ var additionalProps = {
69
+ value: value,
70
+ role: 'option',
71
+ onClick: function () {
72
+ var _a;
68
73
  setSelectedValue(value);
69
- onChange === null || onChange === void 0 ? void 0 : onChange(value);
74
+ (_a = userOnChange.current) === null || _a === void 0 ? void 0 : _a.call(userOnChange, value);
70
75
  setIsOpen(false);
71
- } }, rest), label));
76
+ },
77
+ };
78
+ if (itemRenderer) {
79
+ return React.cloneElement(itemRenderer(option, {
80
+ id: getOptionId(index),
81
+ index: index,
82
+ isSelected: false,
83
+ isFocused: false,
84
+ }), additionalProps);
85
+ }
86
+ return (React.createElement(MenuItem, __assign({ id: getOptionId(index), key: getOptionId(index) }, additionalProps, rest), label));
72
87
  });
73
- }, [options, getOptionId, onChange]);
88
+ }, [options, getOptionId, itemRenderer]);
74
89
  var inputRef = React.useRef(null);
75
90
  var menuRef = React.useRef(null);
76
91
  var toggleButtonRef = React.useRef(null);
@@ -149,6 +164,7 @@ export var ComboBox = function (props) {
149
164
  });
150
165
  }, [inputValue, options, selectedValue, isOpen, filterFunction]);
151
166
  var onKeyDown = React.useCallback(function (event) {
167
+ var _a;
152
168
  var focusableOptions = getFocusableElements(menuRef.current);
153
169
  var focusedIndexInFilteredList = focusableOptions.findIndex(function (_a) {
154
170
  var _b;
@@ -182,7 +198,7 @@ export var ComboBox = function (props) {
182
198
  case 'Enter':
183
199
  if (isOpen) {
184
200
  setSelectedValue(options[focusedIndex].value);
185
- onChange === null || onChange === void 0 ? void 0 : onChange(options[focusedIndex].value);
201
+ (_a = userOnChange.current) === null || _a === void 0 ? void 0 : _a.call(userOnChange, options[focusedIndex].value);
186
202
  }
187
203
  setIsOpen(function (open) { return !open; });
188
204
  event.preventDefault();
@@ -202,26 +218,41 @@ export var ComboBox = function (props) {
202
218
  }
203
219
  break;
204
220
  }
205
- }, [focusedIndex, isOpen, options, getOptionId, onChange]);
221
+ }, [focusedIndex, isOpen, options, getOptionId]);
206
222
  var menuItems = React.useMemo(function () {
207
223
  if (filteredOptions.length === 0) {
208
- return (React.createElement(MenuExtraContent, null,
209
- React.createElement(Text, { isMuted: true }, emptyStateMessage)));
224
+ return [
225
+ React.createElement(MenuExtraContent, { key: 0 },
226
+ React.createElement(Text, { isMuted: true }, emptyStateMessage)),
227
+ ];
210
228
  }
211
229
  return filteredOptions.map(function (option) {
230
+ var _a;
212
231
  var index = options.findIndex(function (_a) {
213
232
  var value = _a.value;
214
233
  return option.value === value;
215
234
  });
216
235
  if (index < 0) {
217
- return;
236
+ return React.createElement(React.Fragment, null);
218
237
  }
219
- if (selectedValue === option.value || focusedIndex === index) {
220
- return React.cloneElement(memoizedItems[index], {
221
- isSelected: selectedValue === option.value,
222
- className: cx({ 'iui-focused': focusedIndex === index }),
223
- ref: function (el) {
224
- return focusedIndex === index && (el === null || el === void 0 ? void 0 : el.scrollIntoView(false));
238
+ var id = getOptionId(index);
239
+ var isSelected = selectedValue === option.value;
240
+ var isFocused = focusedIndex === index;
241
+ var focusScrollRef = function (el) {
242
+ return isFocused && (el === null || el === void 0 ? void 0 : el.scrollIntoView({ block: 'nearest' }));
243
+ };
244
+ if (isSelected || isFocused) {
245
+ var item = (_a = itemRenderer === null || itemRenderer === void 0 ? void 0 : itemRenderer(option, { index: index, id: id, isSelected: isSelected, isFocused: isFocused })) !== null && _a !== void 0 ? _a : React.cloneElement(memoizedItems[index], { isSelected: isSelected });
246
+ return React.cloneElement(item, {
247
+ className: cx({ 'iui-focused': isFocused }, item.props.className),
248
+ ref: mergeRefs(focusScrollRef, item.props.ref),
249
+ value: option.value,
250
+ role: 'option',
251
+ onClick: function () {
252
+ var _a;
253
+ setSelectedValue(option.value);
254
+ (_a = userOnChange.current) === null || _a === void 0 ? void 0 : _a.call(userOnChange, option.value);
255
+ setIsOpen(false);
225
256
  },
226
257
  });
227
258
  }
@@ -231,8 +262,10 @@ export var ComboBox = function (props) {
231
262
  filteredOptions,
232
263
  emptyStateMessage,
233
264
  options,
234
- focusedIndex,
265
+ getOptionId,
235
266
  selectedValue,
267
+ focusedIndex,
268
+ itemRenderer,
236
269
  memoizedItems,
237
270
  ]);
238
271
  return (React.createElement(InputContainer, __assign({ className: className, isIconInline: true }, rest, { id: id }),
@@ -38,6 +38,12 @@ export declare type ExpandableBlockProps = {
38
38
  * @default 'default'
39
39
  */
40
40
  size?: 'default' | 'small';
41
+ /**
42
+ * Style of the ExpandableBlock.
43
+ * Use 'borderless' to hide outline.
44
+ * @default 'default'
45
+ */
46
+ styleType?: 'default' | 'borderless';
41
47
  } & Omit<CommonProps, 'title'>;
42
48
  /**
43
49
  * Container that allows content to be hidden behind a brief title and a caption.
@@ -40,10 +40,10 @@ import '@itwin/itwinui-css/css/expandable-block.css';
40
40
  */
41
41
  export var ExpandableBlock = function (props) {
42
42
  var _a;
43
- var caption = props.caption, children = props.children, className = props.className, title = props.title, onToggle = props.onToggle, style = props.style, _b = props.isExpanded, isExpanded = _b === void 0 ? false : _b, endIcon = props.endIcon, status = props.status, _c = props.size, size = _c === void 0 ? 'default' : _c, rest = __rest(props, ["caption", "children", "className", "title", "onToggle", "style", "isExpanded", "endIcon", "status", "size"]);
43
+ var caption = props.caption, children = props.children, className = props.className, title = props.title, onToggle = props.onToggle, style = props.style, _b = props.isExpanded, isExpanded = _b === void 0 ? false : _b, endIcon = props.endIcon, status = props.status, _c = props.size, size = _c === void 0 ? 'default' : _c, _d = props.styleType, styleType = _d === void 0 ? 'default' : _d, rest = __rest(props, ["caption", "children", "className", "title", "onToggle", "style", "isExpanded", "endIcon", "status", "size", "styleType"]);
44
44
  useTheme();
45
45
  var icon = endIcon !== null && endIcon !== void 0 ? endIcon : (status && StatusIconMap[status]());
46
- var _d = React.useState(isExpanded), expanded = _d[0], setExpanded = _d[1];
46
+ var _e = React.useState(isExpanded), expanded = _e[0], setExpanded = _e[1];
47
47
  React.useEffect(function () {
48
48
  setExpanded(isExpanded);
49
49
  }, [isExpanded]);
@@ -62,6 +62,7 @@ export var ExpandableBlock = function (props) {
62
62
  'iui-with-caption': !!caption,
63
63
  'iui-expanded': expanded,
64
64
  'iui-small': size === 'small',
65
+ 'iui-borderless': styleType === 'borderless',
65
66
  }, className), style: style }, rest),
66
67
  React.createElement("div", { "aria-expanded": expanded, className: 'iui-header', tabIndex: 0, onClick: handleToggle, onKeyDown: onKeyDown },
67
68
  React.createElement(SvgChevronRight, { className: 'iui-icon', "aria-hidden": true }),
@@ -37,6 +37,9 @@ export var Menu = React.forwardRef(function (props, ref) {
37
37
  var _c = React.useState(), focusedIndex = _c[0], setFocusedIndex = _c[1];
38
38
  var menuRef = React.useRef(null);
39
39
  var refs = useMergedRefs(menuRef, ref);
40
+ React.useEffect(function () {
41
+ setFocusedIndex(null);
42
+ }, [children]);
40
43
  React.useEffect(function () {
41
44
  var _a;
42
45
  var items = getFocusableElements(menuRef.current);
@@ -49,9 +52,6 @@ export var Menu = React.forwardRef(function (props, ref) {
49
52
  setFocusedIndex(selectedIndex > -1 ? selectedIndex : 0);
50
53
  }
51
54
  }, [setFocus, focusedIndex]);
52
- React.useEffect(function () {
53
- setFocusedIndex(null);
54
- }, [children]);
55
55
  var onKeyDown = function (event) {
56
56
  var items = getFocusableElements(menuRef.current);
57
57
  if (!(items === null || items === void 0 ? void 0 : items.length)) {
@@ -11,10 +11,16 @@ export declare type RadioProps = {
11
11
  status?: 'positive' | 'warning' | 'negative';
12
12
  /**
13
13
  * Custom CSS class name for the checkmark element.
14
+ *
15
+ * @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
16
+ * The checkmark has been moved into a pseudo-element.
14
17
  */
15
18
  checkmarkClassName?: string;
16
19
  /**
17
20
  * Custom CSS Style for the checkmark element.
21
+ *
22
+ * @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
23
+ * The checkmark has been moved into a pseudo-element.
18
24
  */
19
25
  checkmarkStyle?: React.CSSProperties;
20
26
  /**
@@ -26,6 +32,7 @@ export declare type RadioProps = {
26
32
  /**
27
33
  * Basic radio input component
28
34
  * @example
35
+ * <Radio />
29
36
  * <Radio label='Radio' />
30
37
  * <Radio disabled={true} label='Radio' />
31
38
  * <Radio status='positive' label='Positive' />
@@ -43,10 +50,16 @@ export declare const Radio: React.ForwardRefExoticComponent<{
43
50
  status?: "positive" | "warning" | "negative" | undefined;
44
51
  /**
45
52
  * Custom CSS class name for the checkmark element.
53
+ *
54
+ * @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
55
+ * The checkmark has been moved into a pseudo-element.
46
56
  */
47
57
  checkmarkClassName?: string | undefined;
48
58
  /**
49
59
  * Custom CSS Style for the checkmark element.
60
+ *
61
+ * @deprecated As of 1.32.0, this is applied on the actual radio `<input>` element.
62
+ * The checkmark has been moved into a pseudo-element.
50
63
  */
51
64
  checkmarkStyle?: React.CSSProperties | undefined;
52
65
  /**
@@ -31,6 +31,7 @@ import '@itwin/itwinui-css/css/inputs.css';
31
31
  /**
32
32
  * Basic radio input component
33
33
  * @example
34
+ * <Radio />
34
35
  * <Radio label='Radio' />
35
36
  * <Radio disabled={true} label='Radio' />
36
37
  * <Radio status='positive' label='Positive' />
@@ -38,8 +39,8 @@ import '@itwin/itwinui-css/css/inputs.css';
38
39
  * <Radio status='negative' label='Negative' />
39
40
  */
40
41
  export var Radio = React.forwardRef(function (props, ref) {
41
- var _a;
42
- var className = props.className, _b = props.disabled, disabled = _b === void 0 ? false : _b, label = props.label, status = props.status, style = props.style, checkmarkClassName = props.checkmarkClassName, checkmarkStyle = props.checkmarkStyle, _c = props.setFocus, setFocus = _c === void 0 ? false : _c, rest = __rest(props, ["className", "disabled", "label", "status", "style", "checkmarkClassName", "checkmarkStyle", "setFocus"]);
42
+ var _a, _b;
43
+ var className = props.className, _c = props.disabled, disabled = _c === void 0 ? false : _c, label = props.label, status = props.status, style = props.style, checkmarkClassName = props.checkmarkClassName, checkmarkStyle = props.checkmarkStyle, _d = props.setFocus, setFocus = _d === void 0 ? false : _d, rest = __rest(props, ["className", "disabled", "label", "status", "style", "checkmarkClassName", "checkmarkStyle", "setFocus"]);
43
44
  useTheme();
44
45
  var inputElementRef = React.useRef(null);
45
46
  var refs = useMergedRefs(inputElementRef, ref);
@@ -48,11 +49,9 @@ export var Radio = React.forwardRef(function (props, ref) {
48
49
  inputElementRef.current.focus();
49
50
  }
50
51
  }, [setFocus]);
51
- return (React.createElement("label", { className: cx('iui-radio', (_a = { 'iui-disabled': disabled }, _a["iui-" + status] = !!status, _a), className), style: style },
52
- React.createElement("input", __assign({ disabled: disabled, type: 'radio', ref: refs }, rest)),
53
- React.createElement("span", { className: cx('iui-radio-dot', checkmarkClassName), style: checkmarkStyle },
54
- React.createElement("svg", { viewBox: '0 0 16 16', "aria-hidden": 'true', focusable: 'false' },
55
- React.createElement("circle", { cx: '8', cy: '8', r: '4' }))),
56
- label && React.createElement("span", { className: 'iui-label' }, label)));
52
+ var radio = (React.createElement("input", __assign({ className: cx('iui-radio', className && (_a = {}, _a[className] = !label, _a), checkmarkClassName), style: __assign(__assign({}, (!label && style)), checkmarkStyle), disabled: disabled, type: 'radio', ref: refs }, rest)));
53
+ return !label ? (radio) : (React.createElement("label", { className: cx('iui-radio-wrapper', (_b = { 'iui-disabled': disabled }, _b["iui-" + status] = !!status, _b), className), style: style },
54
+ radio,
55
+ label && React.createElement("span", { className: 'iui-radio-label' }, label)));
57
56
  });
58
57
  export default Radio;
@@ -0,0 +1,123 @@
1
+ /// <reference types="react" />
2
+ import { CommonProps } from '../utils';
3
+ import '@itwin/itwinui-css/css/tree.css';
4
+ export declare type NodeData<T> = {
5
+ /**
6
+ * Array of the child nodes contained in the node.
7
+ */
8
+ subNodes?: Array<T>;
9
+ /**
10
+ * Unique id of the node.
11
+ */
12
+ nodeId: string;
13
+ /**
14
+ * Custom type used to map type `T` to `NodeData`
15
+ */
16
+ node: T;
17
+ /**
18
+ * Flag whether the node is expanded.
19
+ */
20
+ isExpanded?: boolean;
21
+ /**
22
+ * Flag whether the node is disabled.
23
+ */
24
+ isDisabled?: boolean;
25
+ /**
26
+ * Flag whether the node is selected.
27
+ */
28
+ isSelected?: boolean;
29
+ /**
30
+ * Flag whether the node has sub-nodes.
31
+ * Used to determine if node should be expandable.
32
+ */
33
+ hasSubNodes: boolean;
34
+ };
35
+ export declare type NodeRenderProps<T> = Omit<NodeData<T>, 'subNodes'>;
36
+ export declare type TreeProps<T> = {
37
+ /**
38
+ * Render function that should return the node element.
39
+ * Recommended to use `TreeNode` component.
40
+ * Must be memoized.
41
+ * @example
42
+ * const nodeRenderer = React.useCallback(({ node, ...rest }: NodeRenderProps<DataType>) => (
43
+ * <TreeNode
44
+ * label={node.label}
45
+ * onNodeExpanded={onNodeExpanded}
46
+ * {...rest}
47
+ * />
48
+ * ), [onNodeExpanded])
49
+ */
50
+ nodeRenderer: (props: NodeRenderProps<T>) => JSX.Element;
51
+ /**
52
+ * Array of custom data used for `TreeNodes` inside `Tree`.
53
+ */
54
+ data: T[];
55
+ /**
56
+ * Function that maps your `data` entry to `NodeData` that has all info about the node state.
57
+ * It will be used to render a tree node in `nodeRenderer`.
58
+ * Must be memoized.
59
+ * @example
60
+ * const getNode = React.useCallback((node: DemoData): NodeData<DemoData> => {
61
+ * return {
62
+ * subNodes: node.subItems,
63
+ * nodeId: node.id,
64
+ * node,
65
+ * isExpanded: expandedNodes[node.id],
66
+ * hasSubNodes: node.subItems.length > 0,
67
+ * };
68
+ * }, [expandedNodes]);
69
+ */
70
+ getNode: (node: T) => NodeData<T>;
71
+ } & Omit<CommonProps, 'title'>;
72
+ /**
73
+ * Tree component used to display a hierarchical structure of `TreeNodes`.
74
+ * User should control state of expanded, selected and disabled nodes using `getNode` prop.
75
+ * @example
76
+ type DemoData = {
77
+ id: string;
78
+ label: string;
79
+ subItems: DemoData[];
80
+ };
81
+
82
+ const data: Array<DemoData> = [
83
+ {
84
+ id: 'Node-1',
85
+ label: 'Facility 1',
86
+ subItems: [{ id: 'Node-1-1', label: 'Unit 1', subItems: [] }],
87
+ },
88
+ {
89
+ id: 'Node-2',
90
+ label: 'Facility 2',
91
+ subItems: [{ id: 'Node-2-1', label: 'Unit 2', subItems: [] }],
92
+ },
93
+ ];
94
+
95
+ const [expandedNodes, setExpandedNodes] = React.useState<Record<string, boolean>>({});
96
+ const onNodeExpanded = React.useCallback((nodeId: string, isExpanded: boolean) => {
97
+ setExpandedNodes((oldExpanded) => ({ ...oldExpanded, [nodeId]: isExpanded }));
98
+ }, []);
99
+
100
+ const getNode = React.useCallback((node: DemoData): NodeData<DemoData> => {
101
+ return {
102
+ subNodes: node.subItems,
103
+ nodeId: node.id,
104
+ node,
105
+ isExpanded: expandedNodes[node.id],
106
+ hasSubNodes: node.subItems.length > 0,
107
+ };
108
+ }, [expandedNodes]);
109
+
110
+ <Tree<DemoData>
111
+ data={data}
112
+ getNode={getNode}
113
+ nodeRenderer={React.useCallback(({ node, ...rest }) => (
114
+ <TreeNode
115
+ label={node.label}
116
+ onNodeExpanded={onNodeExpanded}
117
+ {...rest}
118
+ />
119
+ ), [onNodeExpanded])}
120
+ />
121
+ */
122
+ export declare const Tree: <T>(props: TreeProps<T>) => JSX.Element;
123
+ export default Tree;