@carbon/react 1.84.0-rc.0 → 1.85.0-rc.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/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +943 -943
- package/es/components/AILabel/index.js +6 -1
- package/es/components/Checkbox/Checkbox.d.ts +2 -2
- package/es/components/Checkbox/Checkbox.js +8 -8
- package/es/components/CheckboxGroup/CheckboxGroup.d.ts +2 -2
- package/es/components/CheckboxGroup/CheckboxGroup.js +9 -8
- package/es/components/CodeSnippet/CodeSnippet.js +2 -4
- package/es/components/ComboBox/ComboBox.d.ts +1 -1
- package/es/components/ComboBox/ComboBox.js +8 -7
- package/es/components/ComposedModal/ComposedModal.d.ts +1 -1
- package/es/components/ComposedModal/ComposedModal.js +34 -12
- package/es/components/ContainedList/ContainedList.d.ts +1 -1
- package/es/components/ContainedList/ContainedList.js +4 -2
- package/es/components/ContentSwitcher/ContentSwitcher.js +6 -5
- package/es/components/DataTable/DataTable.js +3 -0
- package/es/components/DataTable/TableDecoratorRow.d.ts +2 -2
- package/es/components/DataTable/TableDecoratorRow.js +8 -8
- package/es/components/DataTable/TableExpandRow.d.ts +1 -1
- package/es/components/DataTable/TableExpandRow.js +15 -6
- package/es/components/DataTable/TableHeader.js +10 -10
- package/es/components/DataTable/TableRow.js +12 -4
- package/es/components/DataTable/tools/normalize.js +2 -1
- package/es/components/DatePickerInput/DatePickerInput.js +8 -7
- package/es/components/Dialog/index.d.ts +5 -1
- package/es/components/Dialog/index.js +20 -0
- package/es/components/Dropdown/Dropdown.d.ts +1 -1
- package/es/components/Dropdown/Dropdown.js +8 -10
- package/es/components/FileUploader/FileUploaderButton.js +2 -2
- package/es/components/FileUploader/FileUploaderDropContainer.js +2 -2
- package/es/components/FileUploader/FileUploaderItem.js +2 -2
- package/es/components/Layer/index.d.ts +1 -3
- package/es/components/Layer/index.js +9 -8
- package/es/components/Menu/Menu.js +0 -6
- package/es/components/Modal/Modal.d.ts +2 -2
- package/es/components/Modal/Modal.js +39 -11
- package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
- package/es/components/MultiSelect/FilterableMultiSelect.js +29 -7
- package/es/components/MultiSelect/MultiSelect.d.ts +1 -1
- package/es/components/MultiSelect/MultiSelect.js +8 -7
- package/es/components/NumberInput/NumberInput.d.ts +1 -1
- package/es/components/NumberInput/NumberInput.js +9 -8
- package/es/components/OverflowMenu/OverflowMenu.js +4 -5
- package/es/components/PageHeader/PageHeader.d.ts +10 -9
- package/es/components/PageHeader/PageHeader.js +94 -34
- package/es/components/PageHeader/index.d.ts +2 -2
- package/es/components/PageHeader/index.js +1 -1
- package/es/components/Popover/index.js +2 -1
- package/es/components/RadioButton/RadioButton.d.ts +2 -2
- package/es/components/RadioButton/RadioButton.js +8 -8
- package/es/components/RadioButtonGroup/RadioButtonGroup.d.ts +2 -2
- package/es/components/RadioButtonGroup/RadioButtonGroup.js +9 -8
- package/es/components/RadioTile/RadioTile.d.ts +1 -1
- package/es/components/RadioTile/RadioTile.js +8 -7
- package/es/components/Search/Search.js +0 -1
- package/es/components/Select/Select.d.ts +2 -2
- package/es/components/Select/Select.js +8 -7
- package/es/components/Slider/Slider.js +6 -0
- package/es/components/Tag/DismissibleTag.d.ts +1 -1
- package/es/components/Tag/DismissibleTag.js +9 -8
- package/es/components/Tag/Tag.d.ts +1 -1
- package/es/components/Tag/Tag.js +9 -8
- package/es/components/TextArea/TextArea.js +12 -11
- package/es/components/TextInput/TextInput.d.ts +1 -1
- package/es/components/TextInput/TextInput.js +20 -9
- package/es/components/Tile/Tile.d.ts +2 -2
- package/es/components/Tile/Tile.js +30 -36
- package/es/components/TileGroup/TileGroup.d.ts +4 -4
- package/es/components/TileGroup/TileGroup.js +45 -53
- package/es/components/TileGroup/index.d.ts +3 -3
- package/es/components/Toggletip/index.js +2 -2
- package/es/components/Tooltip/DefinitionTooltip.js +1 -0
- package/es/components/TreeView/TreeNode.js +3 -3
- package/es/components/TreeView/TreeView.js +3 -3
- package/es/components/UIShell/Content.d.ts +5 -3
- package/es/components/UIShell/HeaderMenuItem.js +2 -1
- package/es/components/UIShell/HeaderPanel.d.ts +2 -2
- package/es/components/UIShell/HeaderPanel.js +9 -5
- package/es/index.js +1 -1
- package/es/internal/Selection.js +8 -3
- package/es/internal/environment.js +1 -12
- package/es/internal/{__mocks__/mockHTMLElement.d.ts → index.d.ts} +2 -4
- package/es/internal/useOverflowItems.d.ts +29 -0
- package/es/internal/useOverflowItems.js +122 -0
- package/es/internal/useResizeObserver.d.ts +1 -1
- package/es/internal/utils.d.ts +14 -0
- package/es/internal/utils.js +18 -0
- package/es/tools/uniqueId.d.ts +1 -6
- package/lib/components/AILabel/index.js +6 -1
- package/lib/components/Checkbox/Checkbox.d.ts +2 -2
- package/lib/components/Checkbox/Checkbox.js +7 -7
- package/lib/components/CheckboxGroup/CheckboxGroup.d.ts +2 -2
- package/lib/components/CheckboxGroup/CheckboxGroup.js +8 -7
- package/lib/components/CodeSnippet/CodeSnippet.js +2 -4
- package/lib/components/ComboBox/ComboBox.d.ts +1 -1
- package/lib/components/ComboBox/ComboBox.js +11 -10
- package/lib/components/ComposedModal/ComposedModal.d.ts +1 -1
- package/lib/components/ComposedModal/ComposedModal.js +35 -13
- package/lib/components/ContainedList/ContainedList.d.ts +1 -1
- package/lib/components/ContainedList/ContainedList.js +4 -2
- package/lib/components/ContentSwitcher/ContentSwitcher.js +5 -4
- package/lib/components/DataTable/DataTable.js +3 -0
- package/lib/components/DataTable/TableDecoratorRow.d.ts +2 -2
- package/lib/components/DataTable/TableDecoratorRow.js +8 -8
- package/lib/components/DataTable/TableExpandRow.d.ts +1 -1
- package/lib/components/DataTable/TableExpandRow.js +14 -5
- package/lib/components/DataTable/TableHeader.js +9 -9
- package/lib/components/DataTable/TableRow.js +11 -3
- package/lib/components/DataTable/tools/normalize.js +2 -1
- package/lib/components/DatePickerInput/DatePickerInput.js +7 -6
- package/lib/components/Dialog/index.d.ts +5 -1
- package/lib/components/Dialog/index.js +20 -0
- package/lib/components/Dropdown/Dropdown.d.ts +1 -1
- package/lib/components/Dropdown/Dropdown.js +12 -14
- package/lib/components/FileUploader/FileUploaderButton.js +2 -2
- package/lib/components/FileUploader/FileUploaderDropContainer.js +2 -2
- package/lib/components/FileUploader/FileUploaderItem.js +2 -2
- package/lib/components/Layer/index.d.ts +1 -3
- package/lib/components/Layer/index.js +9 -8
- package/lib/components/Menu/Menu.js +0 -6
- package/lib/components/Modal/Modal.d.ts +2 -2
- package/lib/components/Modal/Modal.js +47 -19
- package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
- package/lib/components/MultiSelect/FilterableMultiSelect.js +33 -11
- package/lib/components/MultiSelect/MultiSelect.d.ts +1 -1
- package/lib/components/MultiSelect/MultiSelect.js +13 -12
- package/lib/components/NumberInput/NumberInput.d.ts +1 -1
- package/lib/components/NumberInput/NumberInput.js +8 -7
- package/lib/components/OverflowMenu/OverflowMenu.js +4 -5
- package/lib/components/PageHeader/PageHeader.d.ts +10 -9
- package/lib/components/PageHeader/PageHeader.js +92 -34
- package/lib/components/PageHeader/index.d.ts +2 -2
- package/lib/components/PageHeader/index.js +0 -2
- package/lib/components/Popover/index.js +2 -1
- package/lib/components/RadioButton/RadioButton.d.ts +2 -2
- package/lib/components/RadioButton/RadioButton.js +7 -7
- package/lib/components/RadioButtonGroup/RadioButtonGroup.d.ts +2 -2
- package/lib/components/RadioButtonGroup/RadioButtonGroup.js +10 -9
- package/lib/components/RadioTile/RadioTile.d.ts +1 -1
- package/lib/components/RadioTile/RadioTile.js +7 -6
- package/lib/components/Search/Search.js +0 -1
- package/lib/components/Select/Select.d.ts +2 -2
- package/lib/components/Select/Select.js +7 -6
- package/lib/components/Slider/Slider.js +6 -0
- package/lib/components/Tag/DismissibleTag.d.ts +1 -1
- package/lib/components/Tag/DismissibleTag.js +8 -7
- package/lib/components/Tag/Tag.d.ts +1 -1
- package/lib/components/Tag/Tag.js +8 -7
- package/lib/components/TextArea/TextArea.js +11 -10
- package/lib/components/TextInput/TextInput.d.ts +1 -1
- package/lib/components/TextInput/TextInput.js +19 -8
- package/lib/components/Tile/Tile.d.ts +2 -2
- package/lib/components/Tile/Tile.js +29 -35
- package/lib/components/TileGroup/TileGroup.d.ts +4 -4
- package/lib/components/TileGroup/TileGroup.js +44 -52
- package/lib/components/TileGroup/index.d.ts +3 -3
- package/lib/components/Toggletip/index.js +2 -2
- package/lib/components/Tooltip/DefinitionTooltip.js +1 -0
- package/lib/components/TreeView/TreeNode.js +3 -3
- package/lib/components/TreeView/TreeView.js +3 -3
- package/lib/components/UIShell/Content.d.ts +5 -3
- package/lib/components/UIShell/HeaderMenuItem.js +2 -1
- package/lib/components/UIShell/HeaderPanel.d.ts +2 -2
- package/lib/components/UIShell/HeaderPanel.js +8 -4
- package/lib/index.js +1 -1
- package/lib/internal/Selection.js +8 -3
- package/lib/internal/environment.js +1 -12
- package/lib/internal/{__mocks__/mockHTMLElement.d.ts → index.d.ts} +2 -4
- package/lib/internal/useOverflowItems.d.ts +29 -0
- package/lib/internal/useOverflowItems.js +126 -0
- package/lib/internal/useResizeObserver.d.ts +1 -1
- package/lib/internal/utils.d.ts +14 -0
- package/lib/internal/utils.js +22 -0
- package/lib/tools/uniqueId.d.ts +1 -6
- package/package.json +14 -23
- package/telemetry.yml +3 -0
- package/es/tools/uniqueId.js +0 -14
- package/lib/tools/uniqueId.js +0 -18
|
@@ -27,7 +27,12 @@ const AILabelContent = /*#__PURE__*/React.forwardRef(function AILabelContent({
|
|
|
27
27
|
const prefix = usePrefix();
|
|
28
28
|
const hasAILabelActions = React.Children.toArray(children).some(child => {
|
|
29
29
|
const item = child;
|
|
30
|
-
|
|
30
|
+
// TODO: Is there supposed to be a `return` here? If so, this issue would
|
|
31
|
+
// have been caught by ESLint. It's concerning that this code is 7 months
|
|
32
|
+
// old and no one has noticed any issues with it. It also makes me question
|
|
33
|
+
// whether the code is necessary.
|
|
34
|
+
// https://github.com/carbon-design-system/carbon/issues/18991
|
|
35
|
+
item.type === AILabelActions;
|
|
31
36
|
});
|
|
32
37
|
const aiLabelContentClasses = cx(className, {
|
|
33
38
|
[`${prefix}--ai-label-content`]: true,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright IBM Corp. 2016,
|
|
2
|
+
* Copyright IBM Corp. 2016, 2025
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import React, { ReactNode } from 'react';
|
|
7
|
+
import React, { type ReactNode } from 'react';
|
|
8
8
|
type ExcludedAttributes = 'id' | 'onChange' | 'onClick' | 'type';
|
|
9
9
|
export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, ExcludedAttributes> {
|
|
10
10
|
/**
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
|
-
import React from 'react';
|
|
10
|
+
import React, { cloneElement } from 'react';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import '../Text/index.js';
|
|
13
13
|
import deprecate from '../../prop-types/deprecate.js';
|
|
@@ -15,6 +15,8 @@ import { usePrefix } from '../../internal/usePrefix.js';
|
|
|
15
15
|
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
|
|
16
16
|
import { useId } from '../../internal/useId.js';
|
|
17
17
|
import { noopFn } from '../../internal/noopFn.js';
|
|
18
|
+
import { AILabel } from '../AILabel/index.js';
|
|
19
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
18
20
|
import { Text } from '../Text/Text.js';
|
|
19
21
|
|
|
20
22
|
const Checkbox = /*#__PURE__*/React.forwardRef(({
|
|
@@ -55,13 +57,11 @@ const Checkbox = /*#__PURE__*/React.forwardRef(({
|
|
|
55
57
|
const innerLabelClasses = cx(`${prefix}--checkbox-label-text`, {
|
|
56
58
|
[`${prefix}--visually-hidden`]: hideLabel
|
|
57
59
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
}
|
|
60
|
+
const candidate = slug ?? decorator;
|
|
61
|
+
const candidateIsAILabel = isComponentElement(candidate, AILabel);
|
|
62
|
+
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
|
|
63
|
+
size: candidate.props.kind === 'inline' ? 'md' : 'mini'
|
|
64
|
+
}) : null;
|
|
65
65
|
return /*#__PURE__*/React.createElement("div", {
|
|
66
66
|
className: wrapperClasses
|
|
67
67
|
}, /*#__PURE__*/React.createElement("input", _extends({}, other, {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright IBM Corp. 2016,
|
|
2
|
+
* Copyright IBM Corp. 2016, 2025
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import React, { ReactNode } from 'react';
|
|
7
|
+
import React, { type ReactNode } from 'react';
|
|
8
8
|
export interface CheckboxGroupProps {
|
|
9
9
|
children?: ReactNode;
|
|
10
10
|
className?: string;
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
|
-
import React from 'react';
|
|
10
|
+
import React, { cloneElement } from 'react';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import deprecate from '../../prop-types/deprecate.js';
|
|
13
13
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
14
14
|
import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
|
|
15
15
|
import { useId } from '../../internal/useId.js';
|
|
16
|
+
import { AILabel } from '../AILabel/index.js';
|
|
17
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
16
18
|
|
|
17
19
|
const CheckboxGroup = ({
|
|
18
20
|
children,
|
|
@@ -49,13 +51,12 @@ const CheckboxGroup = ({
|
|
|
49
51
|
});
|
|
50
52
|
|
|
51
53
|
// AILabel always size `mini`
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
54
|
+
const candidate = slug ?? decorator;
|
|
55
|
+
const candidateIsAILabel = isComponentElement(candidate, AILabel);
|
|
56
|
+
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
|
|
57
|
+
size: 'mini',
|
|
58
|
+
kind: 'default'
|
|
59
|
+
}) : null;
|
|
59
60
|
return /*#__PURE__*/React.createElement("fieldset", _extends({
|
|
60
61
|
className: fieldsetClasses,
|
|
61
62
|
"data-invalid": invalid ? true : undefined,
|
|
@@ -15,7 +15,7 @@ import Copy from '../Copy/Copy.js';
|
|
|
15
15
|
import Button from '../Button/Button.js';
|
|
16
16
|
import '../Button/Button.Skeleton.js';
|
|
17
17
|
import CopyButton from '../CopyButton/CopyButton.js';
|
|
18
|
-
import {
|
|
18
|
+
import { useId } from '../../internal/useId.js';
|
|
19
19
|
import copy from 'copy-to-clipboard';
|
|
20
20
|
import deprecate from '../../prop-types/deprecate.js';
|
|
21
21
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
@@ -56,7 +56,7 @@ function CodeSnippet({
|
|
|
56
56
|
const [shouldShowMoreLessBtn, setShouldShowMoreLessBtn] = useState(false);
|
|
57
57
|
const {
|
|
58
58
|
current: uid
|
|
59
|
-
} = useRef(
|
|
59
|
+
} = useRef(useId());
|
|
60
60
|
const codeContentRef = useRef(null);
|
|
61
61
|
const codeContainerRef = useRef(null);
|
|
62
62
|
const innerCodeRef = useRef(null);
|
|
@@ -100,8 +100,6 @@ function CodeSnippet({
|
|
|
100
100
|
setHasRightOverflow(horizontalOverflow && codeScrollLeft + codeClientWidth !== codeScrollWidth);
|
|
101
101
|
}, [type, getCodeRefDimensions]);
|
|
102
102
|
useResizeObserver({
|
|
103
|
-
// Cast the ref until the hook supports React 19
|
|
104
|
-
// https://github.com/ZeeCoder/use-resize-observer/issues/108
|
|
105
103
|
ref: getCodeRef(),
|
|
106
104
|
onResize: () => {
|
|
107
105
|
if (codeContentRef?.current && type === 'multi') {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import { UseComboboxProps, UseComboboxActions } from 'downshift';
|
|
8
|
-
import React, { type
|
|
8
|
+
import React, { type ComponentType, type InputHTMLAttributes, type MouseEvent, type PropsWithChildren, type PropsWithRef, type ReactElement, type ReactNode, type RefAttributes } from 'react';
|
|
9
9
|
import { type ListBoxSize } from '../ListBox';
|
|
10
10
|
import { TranslateWithId } from '../../types/common';
|
|
11
11
|
type ExcludedAttributes = 'id' | 'onChange' | 'onClick' | 'type' | 'size';
|
|
@@ -9,7 +9,7 @@ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js
|
|
|
9
9
|
import cx from 'classnames';
|
|
10
10
|
import { useCombobox } from 'downshift';
|
|
11
11
|
import PropTypes from 'prop-types';
|
|
12
|
-
import React, { forwardRef, useRef, useEffect, useState, useContext, useCallback, useMemo } from 'react';
|
|
12
|
+
import React, { forwardRef, useRef, useEffect, useState, useContext, useCallback, useMemo, cloneElement } from 'react';
|
|
13
13
|
import '../Text/index.js';
|
|
14
14
|
import { WarningFilled, WarningAltFilled, Checkmark } from '@carbon/icons-react';
|
|
15
15
|
import isEqual from 'react-fast-compare';
|
|
@@ -26,6 +26,8 @@ import '../FluidForm/FluidForm.js';
|
|
|
26
26
|
import { FormContext } from '../FluidForm/FormContext.js';
|
|
27
27
|
import { useFloating, flip, hide, autoUpdate } from '@floating-ui/react';
|
|
28
28
|
import { useFeatureFlag } from '../FeatureFlags/index.js';
|
|
29
|
+
import { AILabel } from '../AILabel/index.js';
|
|
30
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
29
31
|
import { ListBoxSizePropType } from '../ListBox/ListBoxPropTypes.js';
|
|
30
32
|
import { Text } from '../Text/Text.js';
|
|
31
33
|
|
|
@@ -437,12 +439,11 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
437
439
|
const ItemToElement = itemToElement;
|
|
438
440
|
|
|
439
441
|
// AILabel always size `mini`
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
442
|
+
const candidate = slug ?? decorator;
|
|
443
|
+
const candidateIsAILabel = isComponentElement(candidate, AILabel);
|
|
444
|
+
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
|
|
445
|
+
size: 'mini'
|
|
446
|
+
}) : null;
|
|
446
447
|
const {
|
|
447
448
|
// Prop getters
|
|
448
449
|
getInputProps,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import React, { type
|
|
7
|
+
import React, { type HTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactNode, type RefObject } from 'react';
|
|
8
8
|
export interface ModalBodyProps extends HTMLAttributes<HTMLDivElement> {
|
|
9
9
|
/** Specify the content to be placed in the ModalBody. */
|
|
10
10
|
children?: ReactNode;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
|
-
import React, { useRef, useState, useEffect } from 'react';
|
|
9
|
+
import React, { useRef, useState, useEffect, Children, cloneElement } from 'react';
|
|
10
10
|
import { isElement } from 'react-is';
|
|
11
11
|
import PropTypes from 'prop-types';
|
|
12
12
|
import { Layer } from '../Layer/index.js';
|
|
@@ -26,6 +26,8 @@ import { composeEventHandlers } from '../../tools/events.js';
|
|
|
26
26
|
import deprecate from '../../prop-types/deprecate.js';
|
|
27
27
|
import { unstable__Dialog } from '../Dialog/index.js';
|
|
28
28
|
import { warning } from '../../internal/warning.js';
|
|
29
|
+
import { AILabel } from '../AILabel/index.js';
|
|
30
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
29
31
|
import { debounce } from '../../node_modules/es-toolkit/dist/compat/function/debounce.mjs.js';
|
|
30
32
|
|
|
31
33
|
const ModalBody = /*#__PURE__*/React.forwardRef(function ModalBody({
|
|
@@ -168,7 +170,10 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
168
170
|
} = evt;
|
|
169
171
|
const mouseDownTarget = onMouseDownTarget.current;
|
|
170
172
|
evt.stopPropagation();
|
|
171
|
-
|
|
173
|
+
const containsModalFooter = Children.toArray(childrenWithProps).some(child => isComponentElement(child, ModalFooter));
|
|
174
|
+
const isPassive = !containsModalFooter;
|
|
175
|
+
const shouldCloseOnOutsideClick = isPassive ? preventCloseOnClickOutside !== false : preventCloseOnClickOutside === true;
|
|
176
|
+
if (shouldCloseOnOutsideClick && target instanceof Node && !elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && innerModal.current && !innerModal.current.contains(target) && !innerModal.current.contains(mouseDownTarget)) {
|
|
172
177
|
closeModal(evt);
|
|
173
178
|
}
|
|
174
179
|
}
|
|
@@ -176,7 +181,7 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
176
181
|
target: oldActiveNode,
|
|
177
182
|
relatedTarget: currentActiveNode
|
|
178
183
|
}) {
|
|
179
|
-
if (open && currentActiveNode && oldActiveNode && innerModal.current) {
|
|
184
|
+
if (!enableDialogElement && !focusTrapWithoutSentinels && open && currentActiveNode && oldActiveNode && innerModal.current) {
|
|
180
185
|
const {
|
|
181
186
|
current: bodyNode
|
|
182
187
|
} = innerModal;
|
|
@@ -195,6 +200,23 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
195
200
|
selectorsFloatingMenus: selectorsFloatingMenus?.filter(Boolean)
|
|
196
201
|
});
|
|
197
202
|
}
|
|
203
|
+
|
|
204
|
+
// Adjust scroll if needed so that element with focus is not obscured by gradient
|
|
205
|
+
const modalContent = document.querySelector(`.${prefix}--modal-content`);
|
|
206
|
+
if (!modalContent || !modalContent.classList.contains(`${prefix}--modal-scroll-content`) || !currentActiveNode || !modalContent.contains(currentActiveNode)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const lastContent = modalContent.children[modalContent.children.length - 1];
|
|
210
|
+
const gradientSpacing = modalContent.scrollHeight - lastContent.offsetTop - lastContent.clientHeight;
|
|
211
|
+
for (let elem of modalContent.children) {
|
|
212
|
+
if (elem.contains(currentActiveNode)) {
|
|
213
|
+
const spaceBelow = modalContent.clientHeight - elem.offsetTop + modalContent.scrollTop - elem.clientHeight;
|
|
214
|
+
if (spaceBelow < gradientSpacing) {
|
|
215
|
+
modalContent.scrollTop = modalContent.scrollTop + (gradientSpacing - spaceBelow);
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
198
220
|
}
|
|
199
221
|
function closeModal(evt) {
|
|
200
222
|
if (!onClose || onClose(evt) !== false) {
|
|
@@ -237,10 +259,10 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
237
259
|
useEffect(() => {
|
|
238
260
|
if (!enableDialogElement && !open && launcherButtonRef) {
|
|
239
261
|
setTimeout(() => {
|
|
240
|
-
launcherButtonRef
|
|
262
|
+
launcherButtonRef.current?.focus();
|
|
241
263
|
});
|
|
242
264
|
}
|
|
243
|
-
}, [open, launcherButtonRef]);
|
|
265
|
+
}, [enableDialogElement, open, launcherButtonRef]);
|
|
244
266
|
useEffect(() => {
|
|
245
267
|
if (!enableDialogElement) {
|
|
246
268
|
const initialFocus = focusContainerElement => {
|
|
@@ -267,14 +289,14 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
267
289
|
}, [open, selectorPrimaryFocus, isOpen]);
|
|
268
290
|
|
|
269
291
|
// AILabel is always size `sm`
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
292
|
+
const candidate = slug ?? decorator;
|
|
293
|
+
const candidateIsAILabel = isComponentElement(candidate, AILabel);
|
|
294
|
+
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
|
|
295
|
+
size: 'sm'
|
|
296
|
+
}) : null;
|
|
276
297
|
const modalBody = enableDialogElement ? /*#__PURE__*/React.createElement(unstable__Dialog, {
|
|
277
298
|
open: open,
|
|
299
|
+
focusAfterCloseRef: launcherButtonRef,
|
|
278
300
|
modal: true,
|
|
279
301
|
className: containerClass,
|
|
280
302
|
"aria-label": ariaLabel ? ariaLabel : generatedAriaLabel,
|
|
@@ -309,7 +331,7 @@ const ComposedModal = /*#__PURE__*/React.forwardRef(function ComposedModal({
|
|
|
309
331
|
role: "presentation",
|
|
310
332
|
ref: ref,
|
|
311
333
|
"aria-hidden": !open,
|
|
312
|
-
onBlur:
|
|
334
|
+
onBlur: handleBlur,
|
|
313
335
|
onClick: composeEventHandlers([rest?.onClick, handleOnClick]),
|
|
314
336
|
onMouseDown: composeEventHandlers([rest?.onMouseDown, handleOnMouseDown]),
|
|
315
337
|
onKeyDown: handleKeyDown,
|
|
@@ -13,6 +13,8 @@ import { LayoutConstraint } from '../Layout/index.js';
|
|
|
13
13
|
import { useId } from '../../internal/useId.js';
|
|
14
14
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
15
15
|
import ContainedListItem from './ContainedListItem/ContainedListItem.js';
|
|
16
|
+
import Search from '../Search/Search.js';
|
|
17
|
+
import '../Search/Search.Skeleton.js';
|
|
16
18
|
|
|
17
19
|
const variants = ['on-page', 'disclosed'];
|
|
18
20
|
function filterChildren(children) {
|
|
@@ -27,13 +29,13 @@ function filterChildren(children) {
|
|
|
27
29
|
function renderChildren(children) {
|
|
28
30
|
if (Array.isArray(children)) {
|
|
29
31
|
children.map((child, index) => {
|
|
30
|
-
if (index === 0 && child.type
|
|
32
|
+
if (index === 0 && child.type === Search) {
|
|
31
33
|
return child;
|
|
32
34
|
}
|
|
33
35
|
return child;
|
|
34
36
|
});
|
|
35
37
|
}
|
|
36
|
-
if (children && children.type
|
|
38
|
+
if (children && children.type === Search) {
|
|
37
39
|
return children;
|
|
38
40
|
}
|
|
39
41
|
return children;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
|
-
import React, { useContext, useState, useRef, Children, useEffect,
|
|
10
|
+
import React, { useContext, useState, useRef, Children, useEffect, isValidElement, cloneElement } from 'react';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import deprecate from '../../prop-types/deprecate.js';
|
|
13
13
|
import { LayoutConstraint } from '../Layout/index.js';
|
|
@@ -17,6 +17,8 @@ import { matches } from '../../internal/keyboard/match.js';
|
|
|
17
17
|
import { getNextIndex } from '../../internal/keyboard/navigation.js';
|
|
18
18
|
import { PrefixContext } from '../../internal/usePrefix.js';
|
|
19
19
|
import { noopFn } from '../../internal/noopFn.js';
|
|
20
|
+
import '../Switch/Switch.js';
|
|
21
|
+
import IconSwitch from '../Switch/IconSwitch.js';
|
|
20
22
|
|
|
21
23
|
const ContentSwitcher = ({
|
|
22
24
|
children,
|
|
@@ -79,10 +81,9 @@ const ContentSwitcher = ({
|
|
|
79
81
|
onChange(event);
|
|
80
82
|
}
|
|
81
83
|
};
|
|
82
|
-
const isIconOnly =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
child => child.type.displayName === 'IconSwitch');
|
|
84
|
+
const isIconOnly = Children.map(children, child => {
|
|
85
|
+
return /*#__PURE__*/isValidElement(child) ? child.type === IconSwitch : null;
|
|
86
|
+
})?.every(val => val === true);
|
|
86
87
|
const classes = cx(`${prefix}--content-switcher`, className, {
|
|
87
88
|
[`${prefix}--content-switcher--light`]: light,
|
|
88
89
|
[`${prefix}--content-switcher--${size}`]: size,
|
|
@@ -176,6 +176,7 @@ class DataTable extends Component {
|
|
|
176
176
|
return {
|
|
177
177
|
...rest,
|
|
178
178
|
key: row.id,
|
|
179
|
+
onClick,
|
|
179
180
|
// Compose the event handlers so we don't overwrite a consumer's `onClick`
|
|
180
181
|
// handler
|
|
181
182
|
onExpand: composeEventHandlers([this.handleOnExpandRow(row.id), onClick]),
|
|
@@ -298,6 +299,8 @@ class DataTable extends Component {
|
|
|
298
299
|
useStaticWidth
|
|
299
300
|
};
|
|
300
301
|
});
|
|
302
|
+
// TODO: `getHeaderProps` and `getRowProps` return `key` props. Would it be
|
|
303
|
+
// beneficial for this function to also return a `key` prop?
|
|
301
304
|
/**
|
|
302
305
|
* Get the props associated with the given table cell.
|
|
303
306
|
*/
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright IBM Corp. 2016,
|
|
2
|
+
* Copyright IBM Corp. 2016, 2025
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
|
-
import { ReactNode } from 'react';
|
|
8
|
+
import { type ReactNode } from 'react';
|
|
9
9
|
export interface TableDecoratorRowProps {
|
|
10
10
|
/**
|
|
11
11
|
* The CSS class names of the cell that wraps the underlying input control
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import PropTypes from 'prop-types';
|
|
9
|
-
import React from 'react';
|
|
10
8
|
import cx from 'classnames';
|
|
9
|
+
import PropTypes from 'prop-types';
|
|
10
|
+
import React, { cloneElement } from 'react';
|
|
11
11
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
12
|
+
import { AILabel } from '../AILabel/index.js';
|
|
13
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
12
14
|
|
|
13
15
|
const TableDecoratorRow = ({
|
|
14
16
|
className,
|
|
@@ -22,12 +24,10 @@ const TableDecoratorRow = ({
|
|
|
22
24
|
[`${prefix}--table-column-decorator`]: true,
|
|
23
25
|
[`${prefix}--table-column-decorator--active`]: decorator
|
|
24
26
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
}
|
|
27
|
+
const decoratorIsAILabel = isComponentElement(decorator, AILabel);
|
|
28
|
+
const normalizedDecorator = decoratorIsAILabel ? /*#__PURE__*/cloneElement(decorator, {
|
|
29
|
+
size: 'mini'
|
|
30
|
+
}) : null;
|
|
31
31
|
return /*#__PURE__*/React.createElement("td", {
|
|
32
32
|
className: TableDecoratorRowClasses
|
|
33
33
|
}, normalizedDecorator);
|
|
@@ -8,10 +8,14 @@
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import cx from 'classnames';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
|
-
import React from 'react';
|
|
11
|
+
import React, { Children, isValidElement } from 'react';
|
|
12
12
|
import { ChevronRight } from '@carbon/icons-react';
|
|
13
13
|
import TableCell from './TableCell.js';
|
|
14
14
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
15
|
+
import TableSlugRow from './TableSlugRow.js';
|
|
16
|
+
import TableDecoratorRow from './TableDecoratorRow.js';
|
|
17
|
+
import { AILabel } from '../AILabel/index.js';
|
|
18
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
15
19
|
|
|
16
20
|
const TableExpandRow = /*#__PURE__*/React.forwardRef(({
|
|
17
21
|
['aria-controls']: ariaControls,
|
|
@@ -30,16 +34,21 @@ const TableExpandRow = /*#__PURE__*/React.forwardRef(({
|
|
|
30
34
|
|
|
31
35
|
// We need to put the AILabel and Decorator before the expansion arrow and all other table cells after the arrow.
|
|
32
36
|
let rowHasAILabel;
|
|
33
|
-
const decorator =
|
|
34
|
-
if (child
|
|
35
|
-
if (child.props.slug
|
|
37
|
+
const decorator = Children.toArray(children).map(child => {
|
|
38
|
+
if (isComponentElement(child, TableSlugRow)) {
|
|
39
|
+
if (child.props.slug) {
|
|
40
|
+
rowHasAILabel = true;
|
|
41
|
+
}
|
|
42
|
+
return child;
|
|
43
|
+
} else if (isComponentElement(child, TableDecoratorRow)) {
|
|
44
|
+
if (isComponentElement(child.props.decorator, AILabel)) {
|
|
36
45
|
rowHasAILabel = true;
|
|
37
46
|
}
|
|
38
47
|
return child;
|
|
39
48
|
}
|
|
40
49
|
});
|
|
41
|
-
const normalizedChildren =
|
|
42
|
-
if (child.type
|
|
50
|
+
const normalizedChildren = Children.toArray(children).map(child => {
|
|
51
|
+
if (/*#__PURE__*/isValidElement(child) && child.type !== TableSlugRow && child.type !== TableDecoratorRow) {
|
|
43
52
|
return child;
|
|
44
53
|
}
|
|
45
54
|
});
|
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import cx from 'classnames';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
|
-
import React, { useRef } from 'react';
|
|
11
|
+
import React, { useRef, cloneElement } from 'react';
|
|
12
12
|
import { ArrowUp, ArrowsVertical } from '@carbon/icons-react';
|
|
13
13
|
import './state/sorting.js';
|
|
14
14
|
import { useId } from '../../internal/useId.js';
|
|
15
15
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
16
|
+
import { AILabel } from '../AILabel/index.js';
|
|
17
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
16
18
|
import { sortStates } from './state/sortStates.js';
|
|
17
19
|
|
|
18
20
|
const defaultScope = 'col';
|
|
@@ -61,15 +63,13 @@ const TableHeader = /*#__PURE__*/React.forwardRef(function TableHeader({
|
|
|
61
63
|
|
|
62
64
|
// AILabel is always size `mini`
|
|
63
65
|
const AILableRef = useRef(null);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
}
|
|
66
|
+
const candidate = slug ?? decorator;
|
|
67
|
+
const candidateIsAILabel = isComponentElement(candidate, AILabel);
|
|
68
|
+
const colHasAILabel = candidateIsAILabel;
|
|
69
|
+
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
|
|
70
|
+
size: 'mini',
|
|
71
|
+
ref: AILableRef
|
|
72
|
+
}) : null;
|
|
73
73
|
const headerLabelClassNames = cx({
|
|
74
74
|
[`${prefix}--table-header-label`]: true,
|
|
75
75
|
[`${prefix}--table-header-label--slug ${prefix}--table-header-label--ai-label`]: colHasAILabel,
|
|
@@ -6,20 +6,28 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
|
-
import React from 'react';
|
|
9
|
+
import React, { Children } from 'react';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
11
|
import cx from 'classnames';
|
|
12
12
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
13
|
+
import TableSlugRow from './TableSlugRow.js';
|
|
14
|
+
import TableDecoratorRow from './TableDecoratorRow.js';
|
|
15
|
+
import { AILabel } from '../AILabel/index.js';
|
|
16
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
13
17
|
|
|
14
18
|
const TableRow = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
15
19
|
const prefix = usePrefix();
|
|
16
20
|
let rowHasAILabel;
|
|
17
21
|
if (props?.children) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
// TODO: Why is this loop a `map`? It's not returning anything. Ideally,
|
|
23
|
+
// it seems that it should be a `some`. Maybe I'm missing something?
|
|
24
|
+
Children.toArray(props.children).map(child => {
|
|
25
|
+
if (isComponentElement(child, TableSlugRow)) {
|
|
26
|
+
if (child.props.slug) {
|
|
21
27
|
rowHasAILabel = true;
|
|
22
28
|
}
|
|
29
|
+
} else if (isComponentElement(child, TableDecoratorRow) && isComponentElement(child.props.decorator, AILabel)) {
|
|
30
|
+
rowHasAILabel = true;
|
|
23
31
|
}
|
|
24
32
|
});
|
|
25
33
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { AILabel } from '../../AILabel/index.js';
|
|
8
9
|
import { getCellId } from './cells.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -59,7 +60,7 @@ const normalize = (rows, headers, prevState = {}) => {
|
|
|
59
60
|
isEditing: false,
|
|
60
61
|
isValid: true,
|
|
61
62
|
errors: null,
|
|
62
|
-
hasAILabelHeader: !!(slug || decorator?.type
|
|
63
|
+
hasAILabelHeader: !!(slug || decorator?.type === AILabel),
|
|
63
64
|
info: {
|
|
64
65
|
header: key
|
|
65
66
|
}
|
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
import { WarningFilled, WarningAltFilled, Calendar } from '@carbon/icons-react';
|
|
9
9
|
import cx from 'classnames';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
|
-
import React, { useContext } from 'react';
|
|
11
|
+
import React, { useContext, cloneElement } from 'react';
|
|
12
12
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
13
13
|
import '../FluidForm/FluidForm.js';
|
|
14
14
|
import { FormContext } from '../FluidForm/FormContext.js';
|
|
15
15
|
import { useId } from '../../internal/useId.js';
|
|
16
16
|
import '../Text/index.js';
|
|
17
17
|
import deprecate from '../../prop-types/deprecate.js';
|
|
18
|
+
import { AILabel } from '../AILabel/index.js';
|
|
19
|
+
import { isComponentElement } from '../../internal/utils.js';
|
|
18
20
|
import { Text } from '../Text/Text.js';
|
|
19
21
|
|
|
20
22
|
const DatePickerInput = /*#__PURE__*/React.forwardRef(function DatePickerInput(props, ref) {
|
|
@@ -99,12 +101,11 @@ const DatePickerInput = /*#__PURE__*/React.forwardRef(function DatePickerInput(p
|
|
|
99
101
|
const input = /*#__PURE__*/React.createElement("input", inputProps);
|
|
100
102
|
|
|
101
103
|
// AILabel always size `mini`
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
104
|
+
const candidate = slug ?? decorator;
|
|
105
|
+
const candidateIsAILabel = isComponentElement(candidate, AILabel);
|
|
106
|
+
const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
|
|
107
|
+
size: 'mini'
|
|
108
|
+
}) : null;
|
|
108
109
|
return /*#__PURE__*/React.createElement("div", {
|
|
109
110
|
className: containerClasses
|
|
110
111
|
}, labelText && /*#__PURE__*/React.createElement(Text, {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the Apache-2.0 license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import React, { type HTMLAttributes } from 'react';
|
|
7
|
+
import React, { type HTMLAttributes, type RefObject } from 'react';
|
|
8
8
|
import { InlineLoadingStatus } from '../InlineLoading/InlineLoading';
|
|
9
9
|
/**
|
|
10
10
|
* ----------
|
|
@@ -20,6 +20,10 @@ interface DialogProps extends HTMLAttributes<HTMLDialogElement> {
|
|
|
20
20
|
* Specify an optional className to be applied to the modal root node
|
|
21
21
|
*/
|
|
22
22
|
className?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Provide a ref to return focus to once the dialog is closed.
|
|
25
|
+
*/
|
|
26
|
+
focusAfterCloseRef?: RefObject<HTMLElement | null>;
|
|
23
27
|
/**
|
|
24
28
|
* Specifies whether the dialog is modal or non-modal. This cannot be changed
|
|
25
29
|
* while open=true
|