diff:
@@ -61,10 +61,6 @@ const props = () => ({
id: text('MultiSelect ID (id)', 'carbon-multiselect-example'),
titleText: text('Title (titleText)', 'Multiselect title'),
helperText: text('Helper text (helperText)', 'This is not helper text'),
- filterable: boolean(
- 'Filterable (`<MultiSelect.Filterable>` instead of `<MultiSelect>`)',
- false
- ),
disabled: boolean('Disabled (disabled)', false),
light: boolean('Light variant (light)', false),
useTitleInItem: boolean('Show tooltip on hover', false),
@@ -99,20 +95,16 @@ storiesOf('MultiSelect', module)
'default',
withReadme(readme, () => {
const {
- filterable,
listBoxMenuIconTranslationIds,
selectionFeedback,
...multiSelectProps
} = props();
- const ComponentToUse = !filterable ? MultiSelect : MultiSelect.Filterable;
- const placeholder = !filterable ? undefined : defaultPlaceholder;
return (

- <ComponentToUse
+ <MultiSelect
{...multiSelectProps}
items={items}
itemToString={item => (item ? item.text : '')}
- placeholder={placeholder}
translateWithId={id => listBoxMenuIconTranslationIds[id]}
selectionFeedback={selectionFeedback}
/>
@@ -131,22 +123,18 @@ storiesOf('MultiSelect', module)
'with initial selected items',
withReadme(readme, () => {
const {
- filterable,
listBoxMenuIconTranslationIds,
selectionFeedback,
...multiSelectProps
} = props();
- const ComponentToUse = !filterable ? MultiSelect : MultiSelect.Filterable;
- const placeholder = !filterable ? undefined : defaultPlaceholder;
return (

- <ComponentToUse
+ <MultiSelect
{...multiSelectProps}
items={items}
itemToString={item => (item ? item.text : '')}
initialSelectedItems={[items[0], items[1]]}
- placeholder={placeholder}
translateWithId={id => listBoxMenuIconTranslationIds[id]}
selectionFeedback={selectionFeedback}
/>
@@ -160,4 +148,34 @@ storiesOf('MultiSelect', module)
`,
},
}
+ )
+ .add(
+ 'filterable',
+ withReadme(readme, () => {
+ const {
+ listBoxMenuIconTranslationIds,
+ selectionFeedback,
+ ...multiSelectProps
+ } = props();
+
+ return (
+

+ <MultiSelect.Filterable
+ {...multiSelectProps}
+ items={items}
+ itemToString={item => (item ? item.text : '')}
+ placeholder={defaultPlaceholder}
+ translateWithId={id => listBoxMenuIconTranslationIds[id]}
+ selectionFeedback={selectionFeedback}
+ />
+

+ );
+ }),
+ {
+ info: {
+ text: `
+ When a list contains more than 25 items, use \`MultiSelect.Filterable\` to help find options from the list.
+ `,
+ },
+ }
);

original_message: docs: move Multiselect.Filterable from knobs to it's own story (#5294)


change_type: MODIFY

diff:
@@ -3326,7 +3326,7 @@ $hover-danger: if(
'hover-danger'
),
map-get($carbon--theme, 'hover-danger'),
- #ba1b23
+ #b81921
);
```

change_type: ADD

diff:
+/**
+ * Copyright IBM Corp. 2018, 2018
+ *
+ * This source code is licensed under the Apache-2.0 license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @jest-environment node
+ */
+
+import Color from 'color';
+import { adjustLightness } from '../tools';
+import { blue60 } from '@carbon/colors';
+
+describe('tools', () => {
+ describe('adjustLightness', () => {
+ const SHIFT_AMOUNT = 5;
+
+ const baseColor = Color(blue60);
+ const baseLightness = baseColor
+ .hsl()
+ .round()
+ .object().l;
+
+ it('should increase lightness by a specified amount', () => {
+ const newColor = Color(adjustLightness(blue60, SHIFT_AMOUNT));
+ const newLightness = newColor
+ .hsl()
+ .round()
+ .object().l;
+ expect(newLightness).toEqual(baseLightness + SHIFT_AMOUNT);
+ });
+
+ it('should decrease lightness by a specified amount when given a negative shift', () => {
+ const newColor = Color(adjustLightness(blue60, SHIFT_AMOUNT * -1));
+ const newLightness = newColor
+ .hsl()
+ .round()
+ .object().l;
+
+ expect(newLightness).toEqual(baseLightness - SHIFT_AMOUNT);
+ });
+ });
+});

diff:
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
+import { adjustLightness } from './tools';
import {
// Blue
@@ -111,7 +112,7 @@ export const inverseHoverUI = '#4c4c4c';
export const hoverSelectedUI = '#cacaca';
-export const hoverDanger = '#ba1b23';
+export const hoverDanger = adjustLightness(danger, -8);
export const activeDanger = red80;
export const hoverRow = '#e5e5e5';

diff:
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
+import { adjustLightness } from './tools';
import {
// Blue
@@ -110,7 +111,7 @@ export const inverseHoverUI = '#e5e5e5';
export const hoverSelectedUI = '#4c4c4c';
-export const hoverDanger = '#ba1b23';
+export const hoverDanger = adjustLightness(danger, -8);
export const activeDanger = red80;
export const hoverRow = '#353535';

diff:
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
+import { adjustLightness } from './tools';
import {
// Blue
@@ -111,7 +112,7 @@ export const inverseHoverUI = '#e5e5e5';
export const hoverSelectedUI = '#656565';
-export const hoverDanger = '#ba1b23';
+export const hoverDanger = adjustLightness(danger, -8);
export const activeDanger = red80;
export const hoverRow = '#4c4c4c';

diff:
+/**
+ * Copyright IBM Corp. 2016, 2018
+ *
+ * This source code is licensed under the Apache-2.0 license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+import Color from 'color';
+
+/**
+ * Adjust a given token's lightness by a specified percentage
+ * Example: token = hsl(10, 10, 10);
+ * adjustLightness(token, 5) === hsl(10, 10, 15);
+ * adjustLightness(token, -5) === hsl(10, 10, 5);
+ * @param {string} token
+ * @param {integer} shift The number of percentage points (positive or negative) by which to shift the lightness of a token.
+ * @returns {string}
+ */
+export function adjustLightness(token, shift) {
+ const original = Color(token)
+ .hsl()
+ .object();
+
+ return Color({ ...original, l: (original.l += shift) })
+ .round()
+ .hex()
+ .toLowerCase();
+}

diff:
@@ -6708,7 +6708,7 @@ color@3.0.x:
color-convert "^1.9.1"
color-string "^1.5.2"
-color@^3.0.0:
+color@^3.0.0, color@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==

license: Apache License 2.0

repo: carbon-design-system/carbon

original_message: feat(themes): enable dynamic values for interactive color tokens (#5269)


diff:
.#{$prefix}--action-list .#{$prefix}--btn {
color: $text-04;
+ padding: $button-padding-ghost;
}
.#{$prefix}--action-list .#{$prefix}--btn .#{$prefix}--btn__icon {
fill: $icon-03;
+ position: static;
margin-left: $spacing-03;
}

original_message: fix(data-table): correct padding for batch action buttons (#5413)


message: fix(overflow-menu): correct hover color

diff:
); //used to center svg without setting display flex //display block needed for overflow text truncation
}
+ .#{$prefix}--data-table .#{$prefix}--overflow-menu,
+ .#{$prefix}--data-table .#{$prefix}--overflow-menu__trigger {
+ &:hover {
+ background-color: $hover-selected-ui;
+ }
+ }
+
.#{$prefix}--data-table--selected .#{$prefix}--overflow-menu,
.#{$prefix}--data-table--selected .#{$prefix}--overflow-menu__trigger {
&:hover {

diff:
}
&:hover {
- background-color: $hover-selected-ui;
+ background-color: $hover-ui;
}
}

original_message:
fix(overflow-menu): correct hover color (#5513)

Co-authored-by: TJ Egan <tw15egan@gmail.com>


diff:
@@ -21,7 +21,7 @@ root_path=$PWD
echo "Cleaning vendor directory..."
VENDOR_DIR="$PWD/src/globals/scss/vendor"
-rm -rf $VENDOR_DIR
+rm -rf "$VENDOR_DIR"
for package in node_modules/@carbon/*; do
PKG_NAME="@carbon/$(basename $package)"
@@ -30,8 +30,8 @@ for package in node_modules/@carbon/*; do
if [ -d "$SCSS_FILES" ]; then
echo "Copying scss files for package: $PKG_NAME to $TARGET_DIR"
- mkdir -p $TARGET_DIR
- cp -R $SCSS_FILES $TARGET_DIR
+ mkdir -p "$TARGET_DIR"
+ cp -R $SCSS_FILES "$TARGET_DIR"
fi
done
@@ -44,8 +44,8 @@ for symlink in $(find ../../node_modules/@carbon -type l -maxdepth 1); do
if [ -d "$SCSS_FILES" ]; then
echo "Copying scss files for package: $PKG_NAME to $TARGET_DIR"
- mkdir -p $TARGET_DIR
- cp -R $SCSS_FILES $TARGET_DIR
+ mkdir -p "$TARGET_DIR"
+ cp -R $SCSS_FILES "$TARGET_DIR"
fi
done

original_message: chore: support spaces in folder names (components package build) (#5512)


diff:
@@ -6279,7 +6279,6 @@ $ui-04: if(
- **Type**: `{undefined}`
- **Used by**:
- [carbon--theme [mixin]](#carbon--theme-mixin)
- - [button-theme [mixin]](#button-theme-mixin)
- [date-picker [mixin]](#date-picker-mixin)
- [dropdown [mixin]](#dropdown-mixin)
- [file-uploader [mixin]](#file-uploader-mixin)
@@ -7669,7 +7668,6 @@ $disabled-02: if(
- [carbon--theme [mixin]](#carbon--theme-mixin)
- [button [mixin]](#button-mixin)
- [button-base [mixin]](#button-base-mixin)
- - [button-theme [mixin]](#button-theme-mixin)
- [checkbox [mixin]](#checkbox-mixin)
- [combo-box [mixin]](#combo-box-mixin)
- [content-switcher [mixin]](#content-switcher-mixin)
@@ -13211,11 +13209,16 @@ Button base styles
margin: 0;
&:disabled,
- &.#{$prefix}--btn--disabled {
+ &:hover:disabled,
+ &:focus:disabled,
+ &.#{$prefix}--btn--disabled,
+ &.#{$prefix}--btn--disabled:hover,
+ &.#{$prefix}--btn--disabled:focus {
cursor: not-allowed;
color: $disabled-03;
background: $disabled-02;
border-color: $disabled-02;
+ box-shadow: none;
}
.#{$prefix}--btn__icon {
@@ -13263,17 +13266,6 @@ Button variant styles
($button-border-width + $button-outline-width) $ui-02;
}
- &:disabled:hover,
- &:disabled:focus,
- &:hover.#{$prefix}--btn--disabled,
- &:focus.#{$prefix}--btn--disabled {
- color: $ui-04;
- background-color: $disabled-02;
- border-color: $disabled-02;
- text-decoration: none;
- box-shadow: none;
- }
-
&:active {
background-color: $active-color;
}
@@ -13292,8 +13284,6 @@ Button variant styles
- [focus [variable]](#focus-variable)
- [ui-02 [variable]](#ui-02-variable)
- [prefix [variable]](#prefix-variable)
- - [ui-04 [variable]](#ui-04-variable)
- - [disabled-02 [variable]](#disabled-02-variable)
- **Used by**:
- [button [mixin]](#button-mixin)

diff:
margin: 0;
&:disabled,
- &.#{$prefix}--btn--disabled {
+ &:hover:disabled,
+ &:focus:disabled,
+ &.#{$prefix}--btn--disabled,
+ &.#{$prefix}--btn--disabled:hover,
+ &.#{$prefix}--btn--disabled:focus {
cursor: not-allowed;
color: $disabled-03;
background: $disabled-02;
border-color: $disabled-02;
+ box-shadow: none;
}
.#{$prefix}--btn__icon {
inset 0 0 0 ($button-border-width + $button-outline-width) $ui-02;
}
- &:disabled:hover,
- &:disabled:focus,
- &:hover.#{$prefix}--btn--disabled,
- &:focus.#{$prefix}--btn--disabled {
- color: $ui-04;
- background-color: $disabled-02;
- border-color: $disabled-02;
- text-decoration: none;
- box-shadow: none;
- }
-
&:active {
background-color: $active-color;
}

original_message:
fix(button): prevent hover on disabled buttons in g90/g100 theme (#5678)

Co-authored-by: TJ Egan <tw15egan@gmail.com>


diff:
@@ -3411,7 +3411,6 @@ $carbon--spacing-04: 0.75rem;
- **Used by**:
- [dropdown [mixin]](#dropdown-mixin)
- [lists [mixin]](#lists-mixin)
- - [inline-notifications [mixin]](#inline-notifications-mixin)
- [text-area [mixin]](#text-area-mixin)
- [tooltip--definition--legacy [mixin]](#tooltip--definition--legacy-mixin)
@@ -19574,14 +19573,12 @@ Inline notification styles
.#{$prefix}--inline-notification__text-wrapper {
display: flex;
flex-wrap: wrap;
- align-items: center;
- padding: $carbon--spacing-04 0;
+ padding: rem(15px) 0;
}
.#{$prefix}--inline-notification__title {
@include type-style('productive-heading-01');
margin: 0 $carbon--spacing-02 0 0;
- line-height: rem(24px);
}
.#{$prefix}--inline-notification__subtitle {
@@ -19684,7 +19681,6 @@ Inline notification styles
- [support-04 [variable]](#support-04-variable)
- [inverse-support-03 [variable]](#inverse-support-03-variable)
- [support-03 [variable]](#support-03-variable)
- - [carbon--spacing-04 [variable]](#carbon--spacing-04-variable)
- [carbon--spacing-02 [variable]](#carbon--spacing-02-variable)
- [carbon--spacing-03 [variable]](#carbon--spacing-03-variable)
- [inverse-focus-ui [variable]](#inverse-focus-ui-variable)

original_message: fix(inline-notification): fix headline line-height (#5754)


diff:
@@ -58,7 +58,7 @@ const ToggleSmall = ({
onKeyUp={evt => {
if (match(evt, keys.Enter)) {
input.checked = !input.checked;
- onChange(evt);
+ onChange && onChange(evt);
onToggle(input.checked, id, evt);
}
}}

original_message: fix(toggle-small): only emit onChange on keyUp if it exists (#5931)


message: docs: update docs to reflect intent

diff:
@@ -125,7 +125,7 @@ $carbon--grid-breakpoints: (
@return '-#{$name}';
}
-/// Generate a media query up to the width of the given breakpoint name
+/// Generate a media query from the width of the given breakpoint to infinity
/// @param {String | Number} $name
/// @param {Map} $breakpoints [$carbon--grid-breakpoints] - A map of breakpoints where the key is the name
/// @content

original_message:
docs: update docs to reflect intent (#6398)

Co-authored-by: Vince Picone <Vincent.Patrick.Picone@ibm.com>
Co-authored-by: Josh Black <josh@josh.black>


diff:
@@ -104,6 +104,7 @@ function PaginationItem({
[`${prefix}--pagination-nav__page--active`]: isActive,
})}
onClick={onClick}
+ data-page={page}
aria-current={isActive ? 'page' : null}>
<span className={`${prefix}--pagination-nav__accessibility-label`}>
{isActive
@@ -139,6 +140,7 @@ function PaginationOverflow({
{[...Array(count)].map((e, i) => (
<option
value={(fromIndex + i).toString()}
+ data-page={fromIndex + i + 1}
key={`overflow-${fromIndex + i}`}>
{fromIndex + i + 1}
</option>

original_message:
fix(pagination-nav): add data-page attributes (#6437)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


message: fix(PaginationNav): add forwardRef

diff:
@@ -4138,6 +4138,7 @@ Map {
},
},
"PaginationNav" => Object {
+ "$$typeof": Symbol(react.forward_ref),
"propTypes": Object {
"className": Object {
"type": "string",
@@ -4161,6 +4162,7 @@ Map {
"type": "func",
},
},
+ "render": [Function],
},
"PrimaryButton" => Object {},
"ProgressIndicator" => Object {

diff:
@@ -172,7 +172,8 @@ function PaginationOverflow({
return null;
}
-export default function PaginationNav({
+const PaginationNav = React.forwardRef(function PaginationNav(
+ {
className,
onChange = () => {},
totalItems,
@@ -181,7 +182,9 @@ export default function PaginationNav({
loop = false,
translateWithId: t = translateWithId,
...rest
-}) {
+ },
+ ref
+) {
const [currentPage, setCurrentPage] = useState(page);
const [itemsThatFit, setItemsThatFit] = useState(
itemsShown >= 4 ? itemsShown : 4
@@ -266,7 +269,7 @@ export default function PaginationNav({
const startOffset = itemsThatFit <= 4 && currentPage > 1 ? 0 : 1;
return (
- <nav className={classNames} {...rest} aria-label="pagination">
+ <nav className={classNames} ref={ref} {...rest} aria-label="pagination">
<ul className={`${prefix}--pagination-nav__list`}>
<DirectionButton
direction="backward"
@@ -353,7 +356,7 @@ export default function PaginationNav({
</div>
</nav>
);
-}
+});
DirectionButton.propTypes = {
/**
@@ -460,3 +463,5 @@ PaginationNav.propTypes = {
*/
translateWithId: PropTypes.func,
};
+
+export default PaginationNav;

original_message:
fix(PaginationNav): add forwardRef (#6647)

Co-authored-by: TJ Egan <tw15egan@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -749,6 +749,7 @@ Map {
},
"ContentSwitcher" => Object {
"defaultProps": Object {
+ "onChange": [Function],
"selectedIndex": 0,
"selectionMode": "automatic",
},

diff:
@@ -60,6 +60,7 @@ export default class ContentSwitcher extends React.Component {
static defaultProps = {
selectedIndex: 0,
selectionMode: 'automatic',
+ onChange: () => {},
};
static getDerivedStateFromProps({ selectedIndex }, state) {

original_message:
fix(content-switcher): provide empty default onChange prop (#6945)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


message: feat(dropdown): add warn prop

diff:
.#{$prefix}--text-area__wrapper[data-invalid],
.#{$prefix}--select-input__wrapper[data-invalid],
.#{$prefix}--time-picker[data-invalid],
- .#{$prefix}--list-box[data-invalid] {
+ .#{$prefix}--list-box[data-invalid],
+ .#{$prefix}--list-box--warning {
~ .#{$prefix}--form-requirement {
display: block;
max-height: rem(200px);

diff:
@@ -121,7 +121,19 @@ $list-box-menu-width: rem(300px);
fill: $support-01;
}
- .#{$prefix}--list-box[data-invalid] .#{$prefix}--list-box__field {
+ .#{$prefix}--list-box__invalid-icon--warning {
+ fill: $support-03;
+ }
+
+ .#{$prefix}--list-box__invalid-icon--warning
+ path[data-icon-path='inner-path'] {
+ opacity: 1;
+ fill: $carbon__black-100;
+ }
+
+ .#{$prefix}--list-box[data-invalid] .#{$prefix}--list-box__field,
+ .#{$prefix}--list-box.#{$prefix}--list-box--warning
+ .#{$prefix}--list-box__field {
padding-right: carbon--mini-units(8);
border-bottom: 0;
}

diff:
@@ -66,6 +66,11 @@ const props = () => ({
'Form validation UI content (invalidText)',
'A valid value is required'
),
+ warn: boolean('Show warning state (warn)', false),
+ warnText: text(
+ 'Warning state text (warnText)',
+ 'This mode may perform worse on older machines'
+ ),
});
export default {

diff:
@@ -10,7 +10,11 @@ import { useSelect } from 'downshift';
import { settings } from 'carbon-components';
import cx from 'classnames';
import PropTypes from 'prop-types';
-import { Checkmark16, WarningFilled16 } from '@carbon/icons-react';
+import {
+ Checkmark16,
+ WarningAltFilled16,
+ WarningFilled16,
+} from '@carbon/icons-react';
import ListBox, { PropTypes as ListBoxPropTypes } from '../ListBox';
import { mapDownshiftProps } from '../../tools/createPropAdapter';
import deprecate from '../../prop-types/deprecate';
@@ -45,6 +49,8 @@ const Dropdown = React.forwardRef(function Dropdown(
light,
invalid,
invalidText,
+ warn,
+ warnText,
initialSelectedItem,
selectedItem: controlledSelectedItem,
downshiftProps,
@@ -76,9 +82,11 @@ const Dropdown = React.forwardRef(function Dropdown(
selectedItem,
} = useSelect(selectProps);
const inline = type === 'inline';
+ const showWarning = !invalid && warn;
const className = cx(`${prefix}--dropdown`, containerClassName, {
[`${prefix}--dropdown--invalid`]: invalid,
+ [`${prefix}--dropdown--warning`]: showWarning,
[`${prefix}--dropdown--open`]: isOpen,
[`${prefix}--dropdown--inline`]: inline,
[`${prefix}--dropdown--disabled`]: disabled,
@@ -132,12 +140,19 @@ const Dropdown = React.forwardRef(function Dropdown(
className={className}
invalid={invalid}
invalidText={invalidText}
+ warn={warn}
+ warnText={warnText}
light={light}
isOpen={isOpen}
id={id}>
{invalid && (
<WarningFilled16 className={`${prefix}--list-box__invalid-icon`} />
)}
+ {showWarning && (
+ <WarningAltFilled16
+ className={`${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`}
+ />
+ )}
<button
type="button"
ref={ref}
@@ -178,7 +193,7 @@ const Dropdown = React.forwardRef(function Dropdown(
})}
</ListBox.Menu>
</ListBox>
- {!inline && !invalid && helper}
+ {!inline && !invalid && !warn && helper}
</div>
);
});
@@ -310,6 +325,16 @@ Dropdown.propTypes = {
* The dropdown type, `default` or `inline`
*/
type: ListBoxPropTypes.ListBoxType,
+
+ /**
+ * Specify whether the control is currently in warning state
+ */
+ warn: PropTypes.bool,
+
+ /**
+ * Provide the text that is displayed when the control is in warning state
+ */
+ warnText: PropTypes.string,
};
Dropdown.defaultProps = {

diff:
@@ -37,12 +37,16 @@ const ListBox = React.forwardRef(function ListBox(
size,
invalid,
invalidText,
+ warn,
+ warnText,
light,
isOpen,
...rest
},
ref
) {
+ const showWarning = !invalid && warn;
+
const className = cx({
[containerClassName]: !!containerClassName,
[`${prefix}--list-box`]: true,
@@ -51,6 +55,7 @@ const ListBox = React.forwardRef(function ListBox(
[`${prefix}--list-box--disabled`]: disabled,
[`${prefix}--list-box--light`]: light,
[`${prefix}--list-box--expanded`]: isOpen,
+ [`${prefix}--list-box--warning`]: showWarning,
});
return (
<>
@@ -67,6 +72,9 @@ const ListBox = React.forwardRef(function ListBox(
{invalid ? (
<div className={`${prefix}--form-requirement`}>{invalidText}

) : null}
+ {showWarning ? (
+ <div className={`${prefix}--form-requirement`}>{warnText}

+ ) : null}
</>
);
});
@@ -118,6 +126,16 @@ ListBox.propTypes = {
* `inline` as an option.
*/
type: ListBoxType.isRequired,
+
+ /**
+ * Specify whether the control is currently in warning state
+ */
+ warn: PropTypes.bool,
+
+ /**
+ * Provide the text that is displayed when the control is in warning state
+ */
+ warnText: PropTypes.string,
};
ListBox.defaultProps = {

original_message:
feat(dropdown): add warn prop (#6959)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
height: rem(40px);
}
+ .#{$prefix}--content-switcher--sm {
+ height: rem(32px);
+ }
+
+ .#{$prefix}--content-switcher--xl {
+ height: rem(48px);
+ }
+
.#{$prefix}--content-switcher--disabled {
cursor: not-allowed;
}

diff:
@@ -17,6 +17,12 @@ const selectionModes = {
'Change selection on explicit gesture (manual)': 'manual',
};
+const sizes = {
+ 'Extra large size (xl)': 'xl',
+ 'Default size': undefined,
+ 'Small size (sm)': 'sm',
+};
+
const props = {
contentSwitcher: () => ({
light: boolean('Light variant (light)', false),
@@ -26,6 +32,7 @@ const props = {
selectionModes,
'automatic'
),
+ size: select('Field size (size)', sizes, undefined) || undefined,
onChange: action('onChange'),
}),
switch: () => ({

diff:
@@ -55,6 +55,11 @@ export default class ContentSwitcher extends React.Component {
* Choose whether or not to automatically change selection on focus
*/
selectionMode: PropTypes.oneOf(['automatic', 'manual']),
+
+ /**
+ * Specify the size of the Content Switcher. Currently supports either `sm` or `xl` as an option.
+ */
+ size: PropTypes.oneOf(['sm', 'xl']),
};
static defaultProps = {
@@ -118,11 +123,13 @@ export default class ContentSwitcher extends React.Component {
light,
selectedIndex, // eslint-disable-line no-unused-vars
selectionMode, // eslint-disable-line no-unused-vars
+ size,
...other
} = this.props;
const classes = classNames(`${prefix}--content-switcher`, className, {
[`${prefix}--content-switcher--light`]: light,
+ [`${prefix}--content-switcher--${size}`]: size,
});
return (

original_message:
feat(content-switcher): add support for sm and xl size (#6946)

Co-authored-by: jeanservaas <43144260+jeanservaas@users.noreply.github.com>


diff:
@@ -8,7 +8,7 @@ import { adjustLightness } from './tools';
import {
// Blue
- blue20,
+ blue10,
blue40,
blue60,
blue70,
@@ -124,7 +124,7 @@ export const disabled01 = white;
export const disabled02 = gray30;
export const disabled03 = gray50;
-export const highlight = blue20;
+export const highlight = blue10;
export const decorative01 = gray20;

original_message:
fix(themes): correct color for highlight token in g10 theme (#7035)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


message: feat(multi-select): add warn prop

diff:
.#{$prefix}--combo-box .#{$prefix}--list-box__field,
.#{$prefix}--combo-box.#{$prefix}--list-box[data-invalid]
.#{$prefix}--list-box__field,
+ .#{$prefix}--combo-box.#{$prefix}--list-box--warning
+ .#{$prefix}--list-box__field,
.#{$prefix}--combo-box.#{$prefix}--list-box--disabled.#{$prefix}--list-box[data-invalid]
+ .#{$prefix}--list-box__field,
+ .#{$prefix}--combo-box.#{$prefix}--list-box--disabled.#{$prefix}--list-box--warning
.#{$prefix}--list-box__field {
padding: 0;
}

diff:
.#{$prefix}--date-picker-input__wrapper,
.#{$prefix}--time-picker--invalid,
.#{$prefix}--text-input__field-wrapper[data-invalid],
+ .#{$prefix}--text-input__field-wrapper--warning,
.#{$prefix}--text-input__field-wrapper--warning > .#{$prefix}--text-input,
.#{$prefix}--text-area__wrapper[data-invalid],
.#{$prefix}--select-input__wrapper[data-invalid],

diff:
@@ -315,6 +315,9 @@ $list-box-menu-width: rem(300px);
// invalid && populated input field
.#{$prefix}--list-box[data-invalid]
+ .#{$prefix}--list-box__field
+ .#{$prefix}--text-input,
+ .#{$prefix}--list-box--warning
.#{$prefix}--list-box__field
.#{$prefix}--text-input {
// to account for clear input button outline
@@ -322,6 +325,10 @@ $list-box-menu-width: rem(300px);
}
.#{$prefix}--list-box[data-invalid]
+ .#{$prefix}--list-box__field
+ .#{$prefix}--text-input
+ + .#{$prefix}--list-box__invalid-icon,
+ .#{$prefix}--list-box--warning
.#{$prefix}--list-box__field
.#{$prefix}--text-input
+ .#{$prefix}--list-box__invalid-icon {
@@ -336,12 +343,19 @@ $list-box-menu-width: rem(300px);
// invalid && empty input field
.#{$prefix}--list-box[data-invalid]
+ .#{$prefix}--list-box__field
+ .#{$prefix}--text-input--empty,
+ .#{$prefix}--list-box--warning
.#{$prefix}--list-box__field
.#{$prefix}--text-input--empty {
padding-right: carbon--mini-units(9);
}
.#{$prefix}--list-box[data-invalid]
+ .#{$prefix}--list-box__field
+ .#{$prefix}--text-input--empty
+ + .#{$prefix}--list-box__invalid-icon,
+ .#{$prefix}--list-box--warning
.#{$prefix}--list-box__field
.#{$prefix}--text-input--empty
+ .#{$prefix}--list-box__invalid-icon {

diff:
@@ -3544,6 +3544,12 @@ Map {
"useTitleInItem": Object {
"type": "bool",
},
+ "warn": Object {
+ "type": "bool",
+ },
+ "warnText": Object {
+ "type": "string",
+ },
},
},
"defaultProps": Object {
@@ -3778,6 +3784,12 @@ Map {
"useTitleInItem": Object {
"type": "bool",
},
+ "warn": Object {
+ "type": "bool",
+ },
+ "warnText": Object {
+ "type": "string",
+ },
},
"render": [Function],
},

diff:
@@ -11,7 +11,7 @@ import React from 'react';
import Downshift from 'downshift';
import isEqual from 'lodash.isequal';
import { settings } from 'carbon-components';
-import { WarningFilled16 } from '@carbon/icons-react';
+import { WarningFilled16, WarningAltFilled16 } from '@carbon/icons-react';
import ListBox, { PropTypes as ListBoxPropTypes } from '../ListBox';
import Checkbox from '../Checkbox';
import Selection from '../../internal/Selection';
@@ -129,6 +129,16 @@ export default class FilterableMultiSelect extends React.Component {
* Specify title to show title on hover
*/
useTitleInItem: PropTypes.bool,
+
+ /**
+ * Specify whether the control is currently in warning state
+ */
+ warn: PropTypes.bool,
+
+ /**
+ * Provide the text that is displayed when the control is in warning state
+ */
+ warnText: PropTypes.string,
};
static getDerivedStateFromProps({ open }, state) {
@@ -277,11 +287,15 @@ export default class FilterableMultiSelect extends React.Component {
light,
invalid,
invalidText,
+ warn,
+ warnText,
useTitleInItem,
translateWithId,
downshiftProps,
} = this.props;
const inline = type === 'inline';
+ const showWarning = !invalid && warn;
+
const wrapperClasses = cx(
`${prefix}--multi-select__wrapper`,
`${prefix}--list-box__wrapper`,
@@ -376,6 +390,8 @@ export default class FilterableMultiSelect extends React.Component {
light={light}
invalid={invalid}
invalidText={invalidText}
+ warn={warn}
+ warnText={warnText}
isOpen={isOpen}
size={size}
{...getRootProps()}>
@@ -410,6 +426,11 @@ export default class FilterableMultiSelect extends React.Component {
className={`${prefix}--list-box__invalid-icon`}
/>
)}
+ {showWarning && (
+ <WarningAltFilled16
+ className={`${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`}
+ />
+ )}
{inputValue && isOpen && (
<ListBox.Selection
clearSelection={this.clearInputValue}
@@ -478,7 +499,7 @@ export default class FilterableMultiSelect extends React.Component {
<div className={wrapperClasses}>
{title}
{input}
- {!inline && !invalid ? helper : null}
+ {!inline && !invalid && !warn ? helper : null}
</div>
);
}

diff:
@@ -82,6 +82,11 @@ const props = () => ({
'Form validation UI content (invalidText)',
'Invalid Selection'
),
+ warn: boolean('Show warning state (warn)', false),
+ warnText: text(
+ 'Warning state text (warnText)',
+ 'Selecting more items may increase processing time'
+ ),
onChange: action('onChange'),
listBoxMenuIconTranslationIds: object(
'Listbox menu icon translation IDs (for translateWithId callback)',

diff:
* LICENSE file in the root directory of this source tree.
*/
-import { WarningFilled16 } from '@carbon/icons-react';
+import { WarningFilled16, WarningAltFilled16 } from '@carbon/icons-react';
import { settings } from 'carbon-components';
import cx from 'classnames';
import Downshift, { useSelect } from 'downshift';
@@ -52,6 +52,8 @@ const MultiSelect = React.forwardRef(function MultiSelect(
light,
invalid,
invalidText,
+ warn,
+ warnText,
useTitleInItem,
translateWithId,
downshiftProps,
@@ -104,6 +106,8 @@ const MultiSelect = React.forwardRef(function MultiSelect(
}
const inline = type === 'inline';
+ const showWarning = !invalid && warn;
+
const wrapperClasses = cx(
`${prefix}--multi-select__wrapper`,
`${prefix}--list-box__wrapper`,
@@ -127,6 +131,7 @@ const MultiSelect = React.forwardRef(function MultiSelect(
const className = cx(`${prefix}--multi-select`, containerClassName, {
[`${prefix}--multi-select--invalid`]: invalid,
+ [`${prefix}--multi-select--warning`]: showWarning,
[`${prefix}--multi-select--inline`]: inline,
[`${prefix}--multi-select--selected`]:
selectedItems && selectedItems.length > 0,
@@ -189,11 +194,18 @@ const MultiSelect = React.forwardRef(function MultiSelect(
light={light}
invalid={invalid}
invalidText={invalidText}
+ warn={warn}
+ warnText={warnText}
isOpen={isOpen}
id={id}>
{invalid && (
<WarningFilled16 className={`${prefix}--list-box__invalid-icon`} />
)}
+ {showWarning && (
+ <WarningAltFilled16
+ className={`${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`}
+ />
+ )}
<button
type="button"
ref={ref}
@@ -245,7 +257,7 @@ const MultiSelect = React.forwardRef(function MultiSelect(
})}
</ListBox.Menu>
</ListBox>
- {!inline && !invalid && helperText && (
+ {!inline && !invalid && !warn && helperText && (
<div id={helperId} className={helperClasses}>
{helperText}
</div>
@@ -368,6 +380,16 @@ MultiSelect.propTypes = {
* Specify title to show title on hover
*/
useTitleInItem: PropTypes.bool,
+
+ /**
+ * Specify whether the control is currently in warning state
+ */
+ warn: PropTypes.bool,
+
+ /**
+ * Provide the text that is displayed when the control is in warning state
+ */
+ warnText: PropTypes.string,
};
MultiSelect.defaultProps = {

original_message:
feat(multi-select): add warn prop (#7043)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


message: fix(tile-group): correct legend style

diff:
@@ -113,7 +113,7 @@ export default class TileGroup extends React.Component {
renderLegend = (legend) => {
if (legend) {
- return <legend>{legend}</legend>;
+ return <legend className={`${prefix}--label`}>{legend}</legend>;
}
};

original_message:
fix(tile-group): correct legend style (#7099)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -285,7 +285,7 @@ export class ProgressIndicator extends Component {
}
if (index > this.state.currentIndex) {
return React.cloneElement(child, {
- complete: false,
+ complete: child.props.complete || false,
index,
onClick,
});

original_message:
fix(progress-indicator): don't overwrite explicit "complete" on step (#7345)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


message: fix(checkbox): correct line-height

diff:
position: relative;
display: flex;
min-height: rem(24px);
+ padding-top: rem(3px);
padding-left: rem(20px);
- line-height: 1.5rem;
cursor: pointer;
user-select: none;
}

original_message:
fix(checkbox): correct line-height (#7373)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
}
}
- .#{$prefix}--inline-notification--low-contrast
- .#{$prefix}--inline-notification__action-button.#{$prefix}--btn--ghost {
- color: $link-01;
- }
-
.#{$prefix}--inline-notification__action-button.#{$prefix}--btn--ghost:active,
.#{$prefix}--inline-notification__action-button.#{$prefix}--btn--ghost:hover {
background-color: $inverse-hover-ui;

original_message:
fix(inline-notification): remove ghost button color override (#7695)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -20,7 +20,10 @@ $enable-css-custom-properties: feature-flag-enabled(
/// @example get-token-value($component-tokens, 'tag-background-red');
/// @returns {String} Token value
/// @group component-tokens
-@function get-token-value($tokens, $name) {
+@function get-token-value($tokens, $name, $force-static-values: false) {
+ $emit-as-css-custom-property: $force-static-values == false and
+ feature-flag-enabled('enable-css-custom-properties');
+
@if map-has-key($tokens, $name) {
$config: map-get($tokens, $name);
$fallback: map-get($config, 'fallback');
@@ -33,7 +36,7 @@ $enable-css-custom-properties: feature-flag-enabled(
$value: map-get($option, 'value');
@return if(
- feature-flag-enabled('enable-css-custom-properties'),
+ $emit-as-css-custom-property,
var(--#{$custom-property-prefix}-#{$name}, #{$value}),
$value
);
@@ -41,7 +44,7 @@ $enable-css-custom-properties: feature-flag-enabled(
}
@return if(
- feature-flag-enabled('enable-css-custom-properties'),
+ $emit-as-css-custom-property,
var(--#{$custom-property-prefix}-#{$name}, #{$fallback}),
$fallback
);
@@ -73,6 +76,6 @@ $enable-css-custom-properties: feature-flag-enabled(
/// @example @include emit-component-tokens($component-tokens);
@mixin emit-component-tokens($tokens) {
@each $key, $options in $tokens {
- @include custom-property($key, get-token-value($tokens, $key));
+ @include custom-property($key, get-token-value($tokens, $key, true));
}
}

original_message:
fix(component-tokens): only emit static values in emit-component-tokens (#7801)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -187,7 +187,8 @@ $list-box-menu-width: rem(300px);
color: $disabled-02;
}
- .#{$prefix}--list-box--disabled .#{$prefix}--list-box__menu-icon > svg {
+ .#{$prefix}--list-box--disabled .#{$prefix}--list-box__menu-icon > svg,
+ .#{$prefix}--list-box--disabled .#{$prefix}--list-box__selection > svg {
fill: $disabled-02;
// Windows, Firefox HCM Fix

original_message:
fix(combobox): match "clear selection" icon fill when disabled (#8208)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
.#{$prefix}--context-menu-option {
position: relative;
height: $spacing-07;
+ color: $text-01;
background-color: $ui-01;
cursor: pointer;
transition: background-color $duration--fast-01 motion(standard, productive);
background-color: $hover-ui;
}
+ .#{$prefix}--context-menu-option--danger:hover,
+ .#{$prefix}--context-menu-option--danger:focus {
+ color: $text-04;
+ background-color: $danger-01;
+ }
+
.#{$prefix}--context-menu-option > .#{$prefix}--context-menu {
margin-top: calc(#{$spacing-02} * -1);
}
}
.#{$prefix}--context-menu-option__content--disabled {
+ color: $disabled-02;
background-color: $ui-01;
cursor: not-allowed;
}
- .#{$prefix}--context-menu-option__content--disabled
- .#{$prefix}--context-menu-option__label,
- .#{$prefix}--context-menu-option__content--disabled
- .#{$prefix}--context-menu-option__info,
- .#{$prefix}--context-menu-option__content--disabled
- .#{$prefix}--context-menu-option__icon {
- color: $disabled-02;
- }
-
.#{$prefix}--context-menu-option__content--indented
.#{$prefix}--context-menu-option__label {
margin-left: $spacing-05;
// add top/bottom padding to make sure letters are not cut off by hidden overflow
padding: $spacing-02 0;
overflow: hidden;
- color: $text-01;
white-space: nowrap;
text-align: start;
text-overflow: ellipsis;
.#{$prefix}--context-menu-option__info {
display: inline-flex;
margin-left: $spacing-05;
- color: $icon-01;
}
.#{$prefix}--context-menu-option__icon {
width: 1rem;
height: 1rem;
margin-right: $spacing-03;
- color: $icon-01;
}
.#{$prefix}--context-menu-divider {

diff:
@@ -7682,6 +7682,15 @@ Map {
"disabled": Object {
"type": "bool",
},
+ "kind": Object {
+ "args": Array [
+ Array [
+ "default",
+ "danger",
+ ],
+ ],
+ "type": "oneOf",
+ },
"label": Object {
"isRequired": true,
"type": "node",
@@ -7769,6 +7778,15 @@ Map {
"disabled": Object {
"type": "bool",
},
+ "kind": Object {
+ "args": Array [
+ Array [
+ "default",
+ "danger",
+ ],
+ ],
+ "type": "oneOf",
+ },
"label": Object {
"isRequired": true,
"type": "node",

diff:
@@ -87,6 +87,31 @@ describe('ContextMenu', () => {
).toBe(true);
});
+ it('supports danger kind', () => {
+ const wrapper = mount(<ContextMenuItem label="Delete" kind="danger" />);
+ const option = wrapper.find(`.${prefix}--context-menu-option`);
+
+ expect(option.hasClass(`${prefix}--context-menu-option--danger`)).toBe(
+ true
+ );
+ });
+
+ it('ignores danger kind when it has children', () => {
+ const wrapper = mount(
+ <ContextMenu>
+ <ContextMenuItem label="Remove" kind="danger">
+ <ContextMenuItem label="Move to trash" />
+ <ContextMenuItem label="Delete" />
+ </ContextMenuItem>
+ </ContextMenu>
+ );
+ const option = wrapper.find(`.${prefix}--context-menu-option`).at(0);
+
+ expect(option.hasClass(`${prefix}--context-menu-option--danger`)).toBe(
+ false
+ );
+ });
+
it('renders props.children as submenu', () => {
const wrapper = mount(
<ContextMenu>

diff:
@@ -10,12 +10,20 @@ import PropTypes from 'prop-types';
import ContextMenuOption from './ContextMenuOption';
-function ContextMenuItem({ label, children, disabled, shortcut, ...rest }) {
+function ContextMenuItem({
+ label,
+ children,
+ disabled,
+ kind = 'default',
+ shortcut,
+ ...rest
+}) {
return (
<ContextMenuOption
{...rest}
label={label}
disabled={disabled}
+ kind={kind}
shortcut={shortcut}>
{children}
</ContextMenuOption>
@@ -33,6 +41,11 @@ ContextMenuItem.propTypes = {
*/
disabled: PropTypes.bool,
+ /**
+ * Optional prop to specify the kind of the ContextMenuItem
+ */
+ kind: PropTypes.oneOf(['default', 'danger']),
+
/**
* Rendered label for the ContextMenuItem
*/

diff:
@@ -55,6 +55,7 @@ function ContextMenuOption({
children,
disabled,
indented,
+ kind = 'default',
label,
level,
onClick = () => {},
@@ -133,6 +134,8 @@ function ContextMenuOption({
const classes = classnames(`${prefix}--context-menu-option`, {
[`${prefix}--context-menu-option--disabled`]: disabled,
[`${prefix}--context-menu-option--active`]: subOptions && submenuOpen,
+ [`${prefix}--context-menu-option--danger`]:
+ !subOptions && kind === 'danger',
});
const allowedRoles = ['menuitemradio', 'menuitemcheckbox'];
@@ -233,6 +236,11 @@ ContextMenuOption.propTypes = {
*/
indented: PropTypes.bool,
+ /**
+ * Optional prop to specify the kind of the ContextMenuOption
+ */
+ kind: PropTypes.oneOf(['default', 'danger']),
+
/**
* Rendered label for the ContextMenuOption
*/

original_message:
feat(context-menu-item): add support for danger kind (#8195)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
fill: $icon-01;
}
- .#{$prefix}--text-input--invalid {
+ .#{$prefix}--text-input--invalid,
+ .#{$prefix}--text-input--warning {
padding-right: $carbon--spacing-08;
}

diff:
@@ -43,6 +43,7 @@ const TextInput = React.forwardRef(function TextInput(
const textInputClasses = classNames(`${prefix}--text-input`, className, {
[`${prefix}--text-input--light`]: light,
[`${prefix}--text-input--invalid`]: invalid,
+ [`${prefix}--text-input--warning`]: !invalid && warn,
[`${prefix}--text-input--${size}`]: size,
});
const sharedTextInputProps = {

original_message:
fix(text-input): correct padding when in warning state (#8394)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
flex-shrink: 0;
width: rem(18px);
height: rem(18px);
- margin: rem(2px) $carbon--spacing-03 rem(2px) rem(2px);
+ margin: rem(1px) $carbon--spacing-03 rem(2px) rem(2px);
background-color: transparent;
border: $radio-border-width solid $icon-01;
border-radius: 50%;
.#{$prefix}--radio-button-wrapper .#{$prefix}--radio-button__label {
display: flex;
- align-items: center;
+ align-items: flex-start;
justify-content: center;
margin: 0;
}

original_message:
fix(radio-button): top-align wrapping labels (#8381)

Co-authored-by: Lauren Rice <43969356+laurenmrice@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
margin-top: 0;
}
+ // No steppers
+ .#{$prefix}--number--nosteppers input[type='number'] {
+ padding-right: rem(48px);
+ }
+
+ .#{$prefix}--number--nosteppers .#{$prefix}--number__invalid {
+ right: rem(16px);
+ }
+
// Skeleton State
.#{$prefix}--number.#{$prefix}--skeleton {
@include skeleton;

diff:
@@ -32,6 +32,7 @@ const props = () => ({
id: 'tj-input',
label: text('Label (label)', 'NumberInput label'),
hideLabel: boolean('No label (hideLabel)', false),
+ hideSteppers: boolean('No steppers (hideSteppers)', false),
min: number('Minimum value (min)', 0),
max: number('Maximum value (max)', 100),
value: number('Value (value)', 50),

diff:
@@ -78,6 +78,11 @@ class NumberInput extends Component {
*/
hideLabel: PropTypes.bool,
+ /**
+ * Specify whether you want the steppers to be hidden
+ */
+ hideSteppers: PropTypes.bool,
+
/**
* Provide a description for up/down icons that can be read by screen readers
*/
@@ -317,6 +322,7 @@ class NumberInput extends Component {
iconDescription, // eslint-disable-line
id,
hideLabel,
+ hideSteppers,
label,
max,
min,
@@ -347,6 +353,7 @@ class NumberInput extends Component {
[`${prefix}--number--readonly`]: readOnly,
[`${prefix}--number--light`]: light,
[`${prefix}--number--nolabel`]: hideLabel,
+ [`${prefix}--number--nosteppers`]: hideSteppers,
[`${prefix}--number--mobile`]: isMobile,
[`${prefix}--number--${size}`]: size,
}
@@ -466,6 +473,7 @@ class NumberInput extends Component {
className={`${prefix}--number__invalid ${prefix}--number__invalid--warning`}
/>
)}
+ {!hideSteppers && (
<div className={`${prefix}--number__controls`}>
<button
type="button"
@@ -490,6 +498,7 @@ class NumberInput extends Component {
</button>
<div className={`${prefix}--number__rule-divider`}>

+ )}

{error ? null : helper}
</>

original_message:
feat(number-input): add option to hide steppers (#8646)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -5625,7 +5625,7 @@ Map {
"placeholder": Object {
"type": "string",
},
- "readonly": Object {
+ "readOnly": Object {
"type": "bool",
},
"size": Object {

diff:
@@ -81,7 +81,7 @@ const props = {
onChange: action('onChange'),
}),
TextInputProps: () => ({
- readonly: boolean('Readonly variant (readonly)', false),
+ readOnly: boolean('Readonly variant (readOnly)', false),
}),
PasswordInputProps: () => ({
tooltipPosition: select(

diff:
@@ -35,14 +35,14 @@ const TextInput = React.forwardRef(function TextInput(
light,
size,
inline,
- readonly,
+ readOnly,
...other
},
ref
) {
const normalizedProps = useNormalizedInputProps({
id,
- readonly,
+ readOnly,
disabled,
invalid,
invalidText,
@@ -74,14 +74,14 @@ const TextInput = React.forwardRef(function TextInput(
className: textInputClasses,
title: placeholder,
disabled: normalizedProps.disabled,
- readOnly: readonly,
+ readOnly,
...other,
};
const inputWrapperClasses = classNames(
`${prefix}--form-item`,
`${prefix}--text-input-wrapper`,
{
- [`${prefix}--text-input-wrapper--readonly`]: readonly,
+ [`${prefix}--text-input-wrapper--readonly`]: readOnly,
[`${prefix}--text-input-wrapper--light`]: light,
[`${prefix}--text-input-wrapper--inline`]: inline,
}
@@ -112,7 +112,7 @@ const TextInput = React.forwardRef(function TextInput(
[`${prefix}--text-input__invalid-icon`]:
normalizedProps.invalid || normalizedProps.warn,
[`${prefix}--text-input__invalid-icon--warning`]: normalizedProps.warn,
- [`${prefix}--text-input__readonly-icon`]: readonly,
+ [`${prefix}--text-input__readonly-icon`]: readOnly,
});
const label = labelText ? (
@@ -244,7 +244,7 @@ TextInput.propTypes = {
/**
* Whether the input should be read-only
*/
- readonly: PropTypes.bool,
+ readOnly: PropTypes.bool,
/**
* Specify the size of the Text Input. Currently supports either `sm`, 'md' (default) or 'lg` as an option.

diff:
@@ -18,7 +18,7 @@ const { prefix } = settings;
/**
* @typedef {object} InputProps
* @property {string} id - The input's id
- * @property {boolean} readonly - Whether the input should be readonly
+ * @property {boolean} readOnly - Whether the input should be readonly
* @property {boolean} disabled - Whether the input should be disabled
* @property {boolean} invalid - Whether the input should be marked as invalid
* @property {string} invalidText - The validation message displayed in case the input is considered invalid
@@ -52,7 +52,7 @@ const { prefix } = settings;
*/
export function useNormalizedInputProps({
id,
- readonly,
+ readOnly,
disabled,
invalid,
invalidText,
@@ -60,16 +60,16 @@ export function useNormalizedInputProps({
warnText,
}) {
const normalizedProps = {
- disabled: !readonly && disabled,
- invalid: !readonly && invalid,
+ disabled: !readOnly && disabled,
+ invalid: !readOnly && invalid,
invalidId: `${id}-error-msg`,
- warn: !readonly && !invalid && warn,
+ warn: !readOnly && !invalid && warn,
warnId: `${id}-warn-msg`,
validation: null,
icon: null,
};
- if (readonly) {
+ if (readOnly) {
normalizedProps.icon = EditOff16;
} else {
if (normalizedProps.invalid) {

original_message: fix(text-input): align "readOnly" prop capitalization (#8949)


diff:
padding-right: rem(112px);
}
- .#{$prefix}--number input[type='number']:disabled,
- .#{$prefix}--number--readonly input[type='number'] {
+ .#{$prefix}--number input[type='number']:disabled {
border-bottom-color: transparent;
background-color: $field-disabled;
color: $text-disabled;
background-color: transparent;
}
- .#{$prefix}--number--readonly .#{$prefix}--number__control-btn {
- display: none;
- }
-
.#{$prefix}--number__invalid {
position: absolute;
right: rem(96px);
}
// V11: Possibly deprecate
- .#{$prefix}--number--light input[type='number']:disabled,
- .#{$prefix}--number--light
- .#{$prefix}--number--readonly
- input[type='number'] {
+ .#{$prefix}--number--light input[type='number']:disabled {
background-color: $field-02;
}
right: rem(16px);
}
+ // Readonly
+ .#{$prefix}--number--readonly input[type='number'] {
+ background: transparent;
+ }
+
+ .#{$prefix}--number--readonly .#{$prefix}--number__controls {
+ display: none;
+ }
+
+ .#{$prefix}--number__readonly-icon {
+ position: absolute;
+ right: rem(16px);
+ }
+
// Skeleton State
.#{$prefix}--number.#{$prefix}--skeleton {
@include skeleton;

diff:
@@ -9,14 +9,12 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import classNames from 'classnames';
import { settings } from 'carbon-components';
-import {
- Add16,
- Subtract16,
- WarningFilled16,
- WarningAltFilled16,
-} from '@carbon/icons-react';
+import { Add16, Subtract16 } from '@carbon/icons-react';
import mergeRefs from '../../tools/mergeRefs';
import requiredIfValueExists from '../../prop-types/requiredIfValueExists';
+// replace "use" prefix to avoid react thinking this is a hook that
+// can only be placed in a function component
+import { useNormalizedInputProps as getNormalizedInputProps } from '../../internal/useNormalizedInputProps';
import { useControlledStateWithValue } from '../../internal/FeatureFlags';
import deprecate from '../../prop-types/deprecate';
@@ -359,29 +357,6 @@ class NumberInput extends Component {
}
);
- const props = {
- disabled,
- id,
- max,
- min,
- step,
- onChange: this.handleChange,
- value:
- useControlledStateWithValue && this.isControlled
- ? value
- : this.state.value,
- readOnly,
- 'aria-label': label ? null : ariaLabel,
- };
-
- const buttonProps = {
- disabled,
- };
-
- const inputWrapperProps = {};
- let errorId = null;
- let error = null;
-
let isInputInvalid;
// If the user supplied `invalid` through props, we'll defer to the passed in value
@@ -402,25 +377,43 @@ class NumberInput extends Component {
}
}
- if (isInputInvalid) {
+ const normalizedProps = getNormalizedInputProps({
+ id,
+ readOnly,
+ disabled,
+ invalid: isInputInvalid,
+ invalidText,
+ warn,
+ warnText,
+ });
+
+ const props = {
+ disabled: normalizedProps.disabled,
+ id,
+ max,
+ min,
+ step,
+ onChange: this.handleChange,
+ value:
+ useControlledStateWithValue && this.isControlled
+ ? value
+ : this.state.value,
+ readOnly,
+ 'aria-label': label ? null : ariaLabel,
+ };
+
+ const buttonProps = {
+ disabled,
+ };
+
+ const inputWrapperProps = {};
+
+ if (normalizedProps.invalid) {
inputWrapperProps['data-invalid'] = true;
- errorId = `${id}-error-id`;
- error = (
- <div className={`${prefix}--form-requirement`} id={errorId}>
- {invalidText}
-

- );
- } else if (warn) {
- errorId = `${id}-error-id`;
- error = (
- <div className={`${prefix}--form-requirement`} id={errorId}>
- {warnText}
-

- );
}
const helperTextClasses = classNames(`${prefix}--form__helper-text`, {
- [`${prefix}--form__helper-text--disabled`]: disabled,
+ [`${prefix}--form__helper-text--disabled`]: normalizedProps.disabled,
});
const helper = helperText ? (
@@ -428,7 +421,7 @@ class NumberInput extends Component {
) : null;
const labelClasses = classNames(`${prefix}--label`, {
- [`${prefix}--label--disabled`]: disabled,
+ [`${prefix}--label--disabled`]: normalizedProps.disabled,
[`${prefix}--visually-hidden`]: hideLabel,
});
@@ -444,9 +437,24 @@ class NumberInput extends Component {
];
const wrapperClasses = classNames(`${prefix}--number__input-wrapper`, {
- [`${prefix}--number__input-wrapper--warning`]: !isInputInvalid && warn,
+ [`${prefix}--number__input-wrapper--warning`]: normalizedProps.warn,
});
+ const iconClasses = classNames({
+ [`${prefix}--number__invalid`]:
+ normalizedProps.invalid || normalizedProps.warn,
+ [`${prefix}--number__invalid--warning`]: normalizedProps.warn,
+ [`${prefix}--number__readonly-icon`]: readOnly,
+ });
+
+ let ariaDescribedBy = null;
+ if (normalizedProps.invalid) {
+ ariaDescribedBy = normalizedProps.invalidId;
+ }
+ if (normalizedProps.warn) {
+ ariaDescribedBy = normalizedProps.warnId;
+ }
+
return (
<div className={`${prefix}--form-item`}>

@@ -456,22 +464,17 @@ class NumberInput extends Component {
{labelText}

<input
- data-invalid={isInputInvalid}
- aria-invalid={isInputInvalid}
- aria-describedby={errorId}
+ data-invalid={normalizedProps.invalid}
+ aria-invalid={normalizedProps.invalid}
+ aria-describedby={ariaDescribedBy}
type="number"
pattern="[0-9]*"
{...other}
{...props}
ref={mergeRefs(ref, this._handleInputRef)}
/>
- {isInputInvalid && (
- <WarningFilled16 className={`${prefix}--number__invalid`} />
- )}
- {!isInputInvalid && warn && (
- <WarningAltFilled16
- className={`${prefix}--number__invalid ${prefix}--number__invalid--warning`}
- />
+ {normalizedProps.icon && (
+ <normalizedProps.icon className={iconClasses} />
)}
{!hideSteppers && (
<div className={`${prefix}--number__controls`}>
@@ -500,11 +503,11 @@ class NumberInput extends Component {

)}

- {error ? null : helper}
+ {normalizedProps.validation ? null : helper}
</>
);
})()}
- {error}
+ {normalizedProps.validation}

);

original_message:
feat(number-input): match readonly variant (#8992)

Co-authored-by: TJ Egan <tw15egan@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


old_path: .all-contributorsrc

new_path: .all-contributorsrc

diff:
"avatar_url": "https://avatars2.githubusercontent.com/u/28265588?v=4",
"profile": "https://janhassel.de/",
"contributions": [
- "code"
+ "code",
+ "doc"
]
},
{

diff:
+# Toggle
+
+## Markup
+
+| Change | Rationale |
+| :--------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| The underlying element was changed from a checkbox (`<input type="checkbox">`) to a switch button (`<button role="switch">`) |

The switch button better resembles the toggle component from an accessibility standpoint: _"A type of checkbox that represents on/off values, as opposed to checked/unchecked values" (https://www.w3.org/TR/2017/REC-wai-aria-1.1-20171214/#switch)_

A toggle cannot present a mixed state which a checkbox can

A switch button natively supports being toggled on Enter

 |
+| `props['aria-label']` is no longer required | The new markup ensures `props.labelText` will always be available to screen readers without the use of `aria-label` |
+
+### New markup
+
+```html
+<div class="bx--toggle">
+ <button
+ id="toggle-id"
+ class="bx--toggle__button"
+ role="switch"
+ type="button"
+ aria-checked="true"
+ ></button>
+ <label class="bx--toggle__label" for="toggle-id">
+ <span class="bx--toggle__label-text bx--visually-hidden">Toggle label</span>
+ <div class="bx--toggle__appearance">
+ <span class="bx--toggle__text" aria-hidden="true">On</span>
+ </div>
+ </label>
+</div>
+```
+
+### Old markup
+
+```html
+<div class="bx--form-item">
+ <input type="checkbox" id="toggle-id" class="bx--toggle-input" checked />
+ <label class="bx--toggle-input__label" for="toggle-id">
+ Toggle label
+ <span class="bx--toggle__switch">
+ <span class="bx--toggle__text--off" aria-hidden="true">Off</span>
+ <span class="bx--toggle__text--on" aria-hidden="true">On</span>
+ </span>
+ </label>
+</div>
+```
+
+## Props
+
+| v7 | v11 | Note |
+| :----------- | :---------- | :------------------------------------------------------------------------------------------- |
+| `aria-label` | - | Removed. No longer required. If still passed, it will be emitted on the `<button>` element. |
+| - | `hideLabel` | New. Visually hides the label above the toggle while keeping it available to screen readers. |
+| `onChange` | - | Removed. Not available on `<button>` elements. |
+| - | `onClick` | New. To substitute previous `props.onChange` |

original_message: docs(toggle): add v11 migration guidance (#9167)


diff:
.#{$prefix}--menu--invisible {
opacity: 0;
+ pointer-events: none;
}
.#{$prefix}--menu-option {

original_message:
fix(menu): prevent hover color flash when opening (#9549)

Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>


diff:
@@ -25,8 +25,8 @@ describe('ProgressBar', () => {
describe('renders as expected', () => {
it('progress bar and label ids match', () => {
const bar = wrapper.getByRole('progressbar');
- const label = wrapper.container.querySelector('label');
- expect(bar.id).toBe(label.htmlFor);
+ const label = wrapper.container.querySelector('span');
+ expect(bar.getAttribute('aria-labelledby')).toBe(label.id);
});
it('renders helper text when passed', () => {
@@ -44,7 +44,7 @@ describe('ProgressBar', () => {
it('still renders accessible when hideLabel is passed', () => {
wrapper.rerender(<ProgressBar {...props} hideLabel />);
- const label = wrapper.container.querySelector('label');
+ const label = wrapper.container.querySelector('span');
expect(label.textContent).toBe(props.label);
expect(label.classList.contains(`${prefix}--visually-hidden`)).toBe(true);

diff:
@@ -21,7 +21,7 @@ function ProgressBar({
value,
helperText,
}) {
- const id = useId('progress-bar');
+ const labelId = useId('progress-bar');
const helperId = useId('progress-bar-helper');
const indeterminate = value === null || value === undefined;
@@ -50,17 +50,17 @@ function ProgressBar({
return (

-
+
{label}
-
+
<div
className={`${prefix}--progress-bar__track`}
- id={id}
role="progressbar"
+ aria-labelledby={labelId}
+ aria-describedby={helperText ? helperId : null}
aria-valuemin={!indeterminate ? 0 : null}
aria-valuemax={!indeterminate ? max : null}
- aria-valuenow={!indeterminate ? cappedValue : null}
- aria-describedby={helperText ? helperId : null}>
+ aria-valuenow={!indeterminate ? cappedValue : null}>
<div
className={`${prefix}--progress-bar__bar`}
style={{ transform: `scaleX(${percentage})` }}

original_message:
fix(progress-bar): fix label accessibility violation (#9479)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
| `aria-label` | - | Removed. No longer required. If still passed, it will be emitted on the `<button>` element. |
| - | `hideLabel` | New. Visually hides the label above the toggle while keeping it available to screen readers. |
| `onChange` | - | Removed. Not available on `<button>` elements. |
-| - | `onClick` | New. To substitute previous `props.onChange` |
+| - | `onClick` | New. To substitute previous `props.onChange`. |
+| `labelA` | `labelA` | Made optional. Default: "Off". |
+| `labelB` | `labelB` | Made optional. Default: "On". |

diff:
@@ -129,12 +129,12 @@ Toggle.propTypes = {
/**
* Specify the label for the "off" position
*/
- labelA: PropTypes.node.isRequired,
+ labelA: PropTypes.node,
/**
* Specify the label for the "on" position
*/
- labelB: PropTypes.node.isRequired,
+ labelB: PropTypes.node,
/**
* Provide the text that will be read by a screen reader when visiting this

original_message:
refactor(toggle): make props.labelA and props.labelB optional (#9550)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -140,7 +140,7 @@ const props = {
disabled: boolean('Disabled (disabled)', false),
role: text('ARIA role of the button (role)', ''),
tabIndex: number('Tab index (tabIndex)', 0),
- onChange: action('onChange'),
+ onAddFiles: action('onAddFiles'),
}),
};

original_message:
docs(file-uploader): show onAddFiles action in storybook (#9626)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
.#{$prefix}--accordion--start .#{$prefix}--accordion__arrow {
// Alters `$accordion-arrow-margin` token:
- margin: 2px 0 0 $carbon--spacing-03;
+ margin: 2px 0 0 $carbon--spacing-05;
+ }
+
+ .#{$prefix}--accordion--start .#{$prefix}--accordion__title {
+ margin-right: $carbon--spacing-05;
}
.#{$prefix}--accordion--start .#{$prefix}--accordion__content {
- margin-left: $carbon--spacing-06;
+ margin-left: $carbon--spacing-07;
}
.#{$prefix}--accordion__item--collapsing .#{$prefix}--accordion__content,

diff:
@@ -183,11 +183,15 @@ $content-padding: 0 0 0 $spacing-05 !default;
.#{$prefix}--accordion--start .#{$prefix}--accordion__arrow {
// Alters `$arrow-margin` token:
- margin: 2px 0 0 $spacing-03;
+ margin: 2px 0 0 $spacing-05;
+ }
+
+ .#{$prefix}--accordion--start .#{$prefix}--accordion__title {
+ margin-right: $spacing-05;
}
.#{$prefix}--accordion--start .#{$prefix}--accordion__content {
- margin-left: $spacing-06;
+ margin-left: $spacing-07;
}
.#{$prefix}--accordion__item--collapsing .#{$prefix}--accordion__content,

original_message:
fix(accordion): update arrow spacing for start variant (#9777)

Co-authored-by: Josefina Mancilla <32556167+jnm2377@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -13,7 +13,7 @@ import React, { useEffect } from 'react';
function Container({ story, id }) {
useEffect(() => {
const originalDirection = document.documentElement.dir;
- if (process.env.CARBON_REACT_STORYBOOK_USE_RTL === 'true') {
+ if (process.env.STORYBOOK_USE_RTL === 'true') {
document.documentElement.dir = 'rtl';
}
return () => {

original_message:
fix(storybook): remove CARBON_REACT prefix from rtl env var (#10826)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>


diff:
@@ -946,7 +946,7 @@ below.
| `TimePicker` | Updated from a class to functional component |
| `TimePickerSelect` | Updated from a class to functional component |
| `ToastNotification` | View changes [here](#notifications) |
-| `Toggle` | Updated from a class to functional component |
+| `Toggle` | View changes [here](#toggle) |
| `ToggleSkeleton` | Removed |
| `ToggleSmall` | Removed |
| `ToggleSmallSkeleton` | Removed |
@@ -1056,6 +1056,26 @@ ToastNotification` updates:
- The `closeOnEscape` prop toggles the closing of notifications via the `escape`
key.
+### Toggle
+
+The toggle component has been updated to improve its accessibility, rtl
+compatibility and flexibility to layout.
+
+- The underlying element has been changed from a checkbox
+ (`<input type="checkbox">`) to a switch button (`<button role="switch">`).
+ - `props.onChange` has been removed since it's not available on `<button>`
+ elements.
+ - `props.onClick` has been added to substitute the previous `onChange` event.
+- `props['aria-label']` is no longer required.
+ - `props.labelText` will always be available to screen readers without the use
+ of `aria-label`.
+ - If `props['aria-label']` is still passed, it will be emitted on the
+ `<button>` element.
+- `props.hideLabel` has been added. This hides `labelA` and `labelB` while
+ moving `labelText` to the side for height-restricted layouts.
+- `props.labelA` and `props.labelB` have been made optional and default to "Off"
+ and "On" respectively.
+
### Tabs
### Tooltips

change_type: DELETE

diff:
-# Toggle
-
-## Markup
-
-| Change | Rationale |
-| :--------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| The underlying element was changed from a checkbox (`<input type="checkbox">`) to a switch button (`<button role="switch">`) |

The switch button better resembles the toggle component from an accessibility standpoint: _"A type of checkbox that represents on/off values, as opposed to checked/unchecked values" (https://www.w3.org/TR/2017/REC-wai-aria-1.1-20171214/#switch)_

A toggle cannot present a mixed state which a checkbox can

A switch button natively supports being toggled on Enter

 |
-| `props['aria-label']` is no longer required | The new markup ensures `props.labelText` will always be available to screen readers without the use of `aria-label` |
-
-### New markup
-
-```html
-<div class="bx--toggle">
- <button
- id="toggle-id"
- class="bx--toggle__button"
- role="switch"
- type="button"
- aria-checked="true"
- ></button>
- <label class="bx--toggle__label" for="toggle-id">
- <span class="bx--toggle__label-text bx--visually-hidden">Toggle label</span>
- <div class="bx--toggle__appearance">
- <span class="bx--toggle__text" aria-hidden="true">On</span>
- </div>
- </label>
-</div>
-```
-
-### Old markup
-
-```html
-<div class="bx--form-item">
- <input type="checkbox" id="toggle-id" class="bx--toggle-input" checked />
- <label class="bx--toggle-input__label" for="toggle-id">
- Toggle label
- <span class="bx--toggle__switch">
- <span class="bx--toggle__text--off" aria-hidden="true">Off</span>
- <span class="bx--toggle__text--on" aria-hidden="true">On</span>
- </span>
- </label>
-</div>
-```
-
-## Props
-
-| v7 | v11 | Note |
-| :----------- | :---------- | :------------------------------------------------------------------------------------------- |
-| `aria-label` | - | Removed. No longer required. If still passed, it will be emitted on the `<button>` element. |
-| - | `hideLabel` | New. Visually hides the label above the toggle while keeping it available to screen readers. |
-| `onChange` | - | Removed. Not available on `<button>` elements. |
-| - | `onClick` | New. To substitute previous `props.onChange`. |
-| `labelA` | `labelA` | Made optional. Default: "Off". |
-| `labelB` | `labelB` | Made optional. Default: "On". |

original_message:
docs(toggle): move migration guide to general v11 documentation (#10827)

Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
Co-authored-by: Alessandra Davila <aledavila@ibm.com>


diff:
height: 100%;
background-color: $interactive;
transform: scaleX(0);
- transform-origin: 0 50%;
+ transform-origin: 0 center #{'/*rtl:100% center*/'};
transition: transform $duration--fast-02 motion(standard, productive);
}

diff:
height: 100%;
background-color: $interactive;
transform: scaleX(0);
- transform-origin: 0 50%;
+ transform-origin: 0 center #{'/*rtl:100% center*/'};
transition: transform $duration-fast-02 motion(standard, productive);
}

original_message:
fix(progress-bar): mirror bar for rtl layouts (#10825)

Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
background-position-x: -105%;
}
}
+
+ .#{$prefix}--progress-bar--inline {
+ display: flex;
+ align-items: center;
+ }
+
+ .#{$prefix}--progress-bar--inline .#{$prefix}--progress-bar__label {
+ flex-shrink: 0;
+ margin-right: $spacing-05;
+ margin-bottom: 0;
+ }
+
+ .#{$prefix}--progress-bar--inline .#{$prefix}--progress-bar__helper-text {
+ @include hidden;
+ }
+
+ .#{$prefix}--progress-bar--indented .#{$prefix}--progress-bar__label,
+ .#{$prefix}--progress-bar--indented .#{$prefix}--progress-bar__helper-text {
+ padding-right: $spacing-05;
+ padding-left: $spacing-05;
+ }
}
@include exports('progress-bar') {

diff:
@@ -8718,6 +8718,16 @@ Map {
],
"type": "oneOf",
},
+ "type": Object {
+ "args": Array [
+ Array [
+ "default",
+ "inline",
+ "indented",
+ ],
+ ],
+ "type": "oneOf",
+ },
"value": Object {
"type": "number",
},

diff:
@@ -21,12 +21,19 @@ const sizes = {
'Big (big) - default': 'big',
};
+const types = {
+ 'Default (default)': 'default',
+ 'Inline (inline)': 'inline',
+ 'indented (indented)': 'indented',
+};
+
const props = () => ({
helperText: text('Helper text (helperText)', 'Optional helper text'),
hideLabel: boolean('Hide the label (hideLabel)', false),
label: text('Label text (label)', 'Progress bar label'),
max: number('Maximum value (max)', 100),
size: select('Size (size)', sizes, 'big'),
+ type: select('Type (type)', types, 'default'),
value: number('Current value (value)', 75),
});

diff:
@@ -20,6 +20,7 @@ function ProgressBar({
label,
max = 100,
size = 'big',
+ type = 'default',
value,
}) {
const labelId = useId('progress-bar');
@@ -40,6 +41,7 @@ function ProgressBar({
const wrapperClasses = classNames(
`${prefix}--progress-bar`,
`${prefix}--progress-bar--${size}`,
+ `${prefix}--progress-bar--${type}`,
{
[`${prefix}--progress-bar--indeterminate`]: indeterminate,
},
@@ -108,6 +110,11 @@ ProgressBar.propTypes = {
*/
size: PropTypes.oneOf(['small', 'big']),
+ /**
+ * Defines the alignment variant of the progress bar.
+ */
+ type: PropTypes.oneOf(['default', 'inline', 'indented']),
+
/**
* The current value.
*/

diff:
@use '../../theme' as *;
@use '../../type' as *;
@use '../../utilities/convert' as *;
+@use '../../utilities/visually-hidden' as *;
/// Progress Bar styles
/// @access public
background-position-x: -105%;
}
}
+
+ .#{$prefix}--progress-bar--inline {
+ display: flex;
+ align-items: center;
+ }
+
+ .#{$prefix}--progress-bar--inline .#{$prefix}--progress-bar__label {
+ flex-shrink: 0;
+ margin-bottom: 0;
+ margin-inline-end: $spacing-05;
+ }
+
+ .#{$prefix}--progress-bar--inline .#{$prefix}--progress-bar__helper-text {
+ @include visually-hidden;
+ }
+
+ .#{$prefix}--progress-bar--indented .#{$prefix}--progress-bar__label,
+ .#{$prefix}--progress-bar--indented .#{$prefix}--progress-bar__helper-text {
+ padding-inline: $spacing-05;
+ }
}

original_message:
feat(progress-bar): add alignment variants (#10769)

Co-authored-by: Abbey Hart <abbeyhrt@gmail.com>
Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
}
.#{$prefix}--action-list .#{$prefix}--btn:disabled {
- color: $text-on-color-disabled;
+ border-color: transparent;
+ background-color: transparent;
+ color: $text-on-color;
+ opacity: 0.5;
}
.#{$prefix}--action-list .#{$prefix}--btn .#{$prefix}--btn__icon {

original_message:
style(data-table): adjust disabled button style in batch action bar (#12211)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
/// @group toggle
@mixin toggle {
.#{$prefix}--toggle {
+ display: inline-block;
user-select: none;
}
}
.#{$prefix}--toggle__appearance {
- display: grid;
+ display: inline-grid;
align-items: center;
column-gap: $spacing-03;
cursor: pointer;

original_message:
fix(toggle): ensure toggle click target matches visual representation (#12212)

Co-authored-by: Alessandra Davila <adavila91@gmail.com>
Co-authored-by: Taylor Jones <tay1orjones@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -812,6 +812,7 @@ $list-box-menu-width: rem(300px);
.#{$prefix}--list-box input[type='text'] {
min-width: 0;
background-color: inherit;
+ text-overflow: ellipsis;
}
// Windows HCM fix

original_message:
fix(combobox): render ellipsis when label is overflowing (#12210)

Co-authored-by: Scott Strubberg <sstrubberg@protonmail.com>


diff:
@@ -311,13 +311,19 @@ export const Playground = PlaygroundStory.bind({});
Playground.argTypes = {
action: {
- control: false,
+ table: {
+ disable: true,
+ },
},
children: {
- control: false,
+ table: {
+ disable: true,
+ },
},
className: {
- control: false,
+ table: {
+ disable: true,
+ },
},
label: {
defaultValue: 'List title',

original_message:
docs(contained-list): remove unnecessary storybook controls (#12346)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


diff:
@@ -11,7 +11,6 @@ import { action } from '@storybook/addon-actions';
import {
Apple,
Fish,
- Information,
Strawberry,
SubtractAlt,
Wheat,
@@ -21,7 +20,6 @@ import Button from '../../Button';
import ExpandableSearch from '../../ExpandableSearch';
import { Layer } from '../../Layer';
import Tag from '../../Tag';
-import { Tooltip } from '../../Tooltip/next';
import ContainedList, { ContainedListItem } from '../';
@@ -77,14 +75,6 @@ export const WithInteractiveItems = () => {
<ContainedListItem onClick={onClick}>List item</ContainedListItem>
<ContainedListItem onClick={onClick}>List item</ContainedListItem>
</ContainedList>
- <ContainedList label="List title" kind="disclosed">
- <ContainedListItem onClick={onClick}>List item</ContainedListItem>
- <ContainedListItem onClick={onClick} disabled>
- List item
- </ContainedListItem>
- <ContainedListItem onClick={onClick}>List item</ContainedListItem>
- <ContainedListItem onClick={onClick}>List item</ContainedListItem>
- </ContainedList>
</VStack>
);
};
@@ -106,19 +96,6 @@ export const WithActions = () => {
kind="on-page"
action={<ExpandableSearch placeholder="Find item" size="lg" />}>
<ContainedListItem action={itemAction}>List item</ContainedListItem>
- <ContainedListItem action={itemAction}>List item</ContainedListItem>
- <ContainedListItem action={itemAction}>List item</ContainedListItem>
- <ContainedListItem action={itemAction}>List item</ContainedListItem>
- </ContainedList>
- <ContainedList
- label="List title"
- kind="disclosed"
- action={
- <Button kind="ghost" size="sm">
- Dismiss all
- </Button>
- }>
- <ContainedListItem action={itemAction}>List item</ContainedListItem>
<ContainedListItem action={itemAction} disabled>
List item
</ContainedListItem>
@@ -159,27 +136,6 @@ export const WithInteractiveItemsAndActions = () => {
List item
</ContainedListItem>
</ContainedList>
- <ContainedList
- label="List title"
- kind="disclosed"
- action={
- <Button kind="ghost" size="sm">
- Dismiss all
- </Button>
- }>
- <ContainedListItem action={itemAction} onClick={onClick}>
- List item
- </ContainedListItem>
- <ContainedListItem action={itemAction} onClick={onClick}>
- List item
- </ContainedListItem>
- <ContainedListItem action={itemAction} onClick={onClick}>
- List item
- </ContainedListItem>
- <ContainedListItem action={itemAction} onClick={onClick}>
- List item
- </ContainedListItem>
- </ContainedList>
</VStack>
);
};
@@ -205,26 +161,6 @@ export const WithListTitleDecorators = () => {
<ContainedListItem>List item</ContainedListItem>
<ContainedListItem>List item</ContainedListItem>
</ContainedList>
- <ContainedList
- label={
-

- List title
- <Tooltip align="top" label="Tooltip content">
- <button
- className="sb-tooltip-trigger"
- style={{ color: 'inherit', border: 'none' }}
- type="button">
- <Information style={{ fill: 'currentColor' }} />
- </button>
- </Tooltip>
-

- }
- kind="disclosed">
- <ContainedListItem>List item</ContainedListItem>
- <ContainedListItem>List item</ContainedListItem>
- <ContainedListItem>List item</ContainedListItem>
- <ContainedListItem>List item</ContainedListItem>
- </ContainedList>
</VStack>
);
};
@@ -238,12 +174,6 @@ export const WithIcons = () => {
<ContainedListItem renderIcon={Strawberry}>List item</ContainedListItem>
<ContainedListItem renderIcon={Fish}>List item</ContainedListItem>
</ContainedList>
- <ContainedList label="List title" kind="disclosed">
- <ContainedListItem renderIcon={Apple}>List item</ContainedListItem>
- <ContainedListItem renderIcon={Wheat}>List item</ContainedListItem>
- <ContainedListItem renderIcon={Strawberry}>List item</ContainedListItem>
- <ContainedListItem renderIcon={Fish}>List item</ContainedListItem>
- </ContainedList>
</VStack>
);
};
@@ -271,26 +201,6 @@ export const WithLayer = () => {
</VStack>
</Layer>
</VStack>
- <VStack gap={5}>
- <ContainedList label="List title" kind="disclosed">
- <ContainedListItem>List item</ContainedListItem>
- <ContainedListItem>List item</ContainedListItem>
- </ContainedList>
- <Layer>
- <VStack gap={5}>
- <ContainedList label="List title" kind="disclosed">
- <ContainedListItem>List item</ContainedListItem>
- <ContainedListItem>List item</ContainedListItem>
- </ContainedList>
- <Layer>
- <ContainedList label="List title" kind="disclosed">
- <ContainedListItem>List item</ContainedListItem>
- <ContainedListItem>List item</ContainedListItem>
- </ContainedList>
- </Layer>
- </VStack>
- </Layer>
- </VStack>
</VStack>
);
};

original_message:
docs(contained-list): remove disclosed variant from demo stories (#12371)

Co-authored-by: Scott Strubberg <sstrubberg@protonmail.com>


message: docs: match story docs and shell themes

diff:
@@ -14,6 +14,8 @@ import React from 'react';
import { breakpoints } from '@carbon/layout';
import { GlobalTheme } from '../src/components/Theme';
+import theme from './theme';
+
export const globalTypes = {
locale: {
name: 'Locale',
@@ -87,6 +89,9 @@ export const parameters = {
darkMode: {
current: 'light',
},
+ docs: {
+ theme,
+ },
// Small (<672)
// Medium (672 - 1056px)
// Large (1056 - 1312px)

original_message:
docs: match story docs and shell themes (#12399)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: TJ Egan <tw15egan@gmail.com>


diff:
@@ -1363,6 +1363,17 @@ Map {
"isRequired": true,
"type": "oneOfType",
},
+ "size": Object {
+ "args": Array [
+ Array [
+ "sm",
+ "md",
+ "lg",
+ "xl",
+ ],
+ ],
+ "type": "oneOf",
+ },
},
},
"ContainedListItem" => Object {

diff:
@@ -19,6 +19,7 @@ function ContainedList({
className,
kind = variants[0],
label,
+ size = 'lg',
}) {
const labelId = `${useId('contained-list')}-header`;
const prefix = usePrefix();
@@ -26,6 +27,7 @@ function ContainedList({
const classes = classNames(
`${prefix}--contained-list`,
`${prefix}--contained-list--${kind}`,
+ `${prefix}--contained-list--${size}`,
className
);
@@ -69,6 +71,11 @@ ContainedList.propTypes = {
* A label describing the contained list.
*/
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
+
+ /**
+ * Specify the size of the contained list.
+ */
+ size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
};
export default ContainedList;

diff:
@@ -90,7 +90,6 @@ export const WithInteractiveItems = () => {
const onClick = action('onClick (ContainedListItem)');
return (
- <VStack gap={12}>
<ContainedList label="List title" kind="on-page">
<ContainedListItem onClick={onClick}>List item</ContainedListItem>
<ContainedListItem onClick={onClick} disabled>
@@ -99,7 +98,6 @@ export const WithInteractiveItems = () => {
<ContainedListItem onClick={onClick}>List item</ContainedListItem>
<ContainedListItem onClick={onClick}>List item</ContainedListItem>
</ContainedList>
- </VStack>
);
};
@@ -114,7 +112,6 @@ export const WithActions = () => {
);
return (
- <VStack gap={12}>
<ContainedList
label="List title"
kind="on-page"
@@ -126,7 +123,6 @@ export const WithActions = () => {
<ContainedListItem action={itemAction}>List item</ContainedListItem>
<ContainedListItem action={itemAction}>List item</ContainedListItem>
</ContainedList>
- </VStack>
);
};
@@ -142,7 +138,6 @@ export const WithInteractiveItemsAndActions = () => {
);
return (
- <VStack gap={12}>
<ContainedList
label="List title"
kind="on-page"
@@ -160,13 +155,11 @@ export const WithInteractiveItemsAndActions = () => {
List item
</ContainedListItem>
</ContainedList>
- </VStack>
);
};
export const WithListTitleDecorators = () => {
return (
- <VStack gap={12}>
<ContainedList
label={
<div
@@ -185,26 +178,22 @@ export const WithListTitleDecorators = () => {
<ContainedListItem>List item</ContainedListItem>
<ContainedListItem>List item</ContainedListItem>
</ContainedList>
- </VStack>
);
};
export const WithIcons = () => {
return (
- <VStack gap={12}>
<ContainedList label="List title" kind="on-page">
<ContainedListItem renderIcon={Apple}>List item</ContainedListItem>
<ContainedListItem renderIcon={Wheat}>List item</ContainedListItem>
<ContainedListItem renderIcon={Strawberry}>List item</ContainedListItem>
<ContainedListItem renderIcon={Fish}>List item</ContainedListItem>
</ContainedList>
- </VStack>
);
};
export const WithLayer = () => {
return (
- <VStack gap={12}>
<VStack gap={5}>
<ContainedList label="List title" kind="on-page">
<ContainedListItem>List item</ContainedListItem>
@@ -225,7 +214,6 @@ export const WithLayer = () => {
</VStack>
</Layer>
</VStack>
- </VStack>
);
};
@@ -250,4 +238,7 @@ Playground.argTypes = {
kind: {
defaultValue: 'on-page',
},
+ size: {
+ defaultValue: 'lg',
+ },
};

diff:
// LICENSE file in the root directory of this source tree.
//
+@use 'sass:list';
+
@use '../../config' as *;
@use '../../motion' as *;
@use '../../spacing' as *;
width: 100%;
}
+ // Sizes
+
+ $sizes: (
+ // size: (height, item-block-padding)
+ 'sm': (rem(32px), $spacing-03),
+ 'md': (rem(40px), $spacing-04),
+ 'lg': (rem(48px), $spacing-05),
+ 'xl': (rem(64px), $spacing-06)
+ );
+
+ @each $size, $definition in $sizes {
+ $height: list.nth($definition, 1);
+ $item-block-padding: list.nth($definition, 2);
+
+ .#{$prefix}--contained-list--on-page.#{$prefix}--contained-list--#{$size}
+ .#{$prefix}--contained-list__header {
+ height: $height;
+ }
+
+ .#{$prefix}--contained-list--#{$size}
+ .#{$prefix}--contained-list-item__content,
+ .#{$prefix}--contained-list--#{$size}
+ .#{$prefix}--contained-list-item--clickable
+ .#{$prefix}--contained-list-item__content {
+ min-height: $height;
+ padding: calc(#{$item-block-padding} - #{rem(2px)}) $spacing-05;
+ }
+ }
+
// "On Page" variant
.#{$prefix}--contained-list--on-page + .#{$prefix}--contained-list--on-page {
.#{$prefix}--contained-list--on-page .#{$prefix}--contained-list__header {
@include type-style('heading-compact-01');
- height: $spacing-09;
border-bottom: 1px solid $border-subtle;
background-color: $background;
color: $text-primary;
.#{$prefix}--contained-list-item__content {
@include type-style('body-01');
- padding: calc(#{$spacing-05} - #{rem(2px)}) $spacing-05;
color: $text-primary;
}

original_message:
feat(contained-list): add support for sizes (#12609)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>


message: handle `null` commit

diff:
@@ -195,10 +195,14 @@ class CommitInfo {
return null;
}
- return new CommitInfo()
- ..sha = input['sha']
- ..tree =
- GitTree.fromJSON(input['commit']['tree'] as Map<String, dynamic>);
+ var info = new CommitInfo()..sha = input['sha'];
+
+ var commit = input['commit'] as Map<String, dynamic>;
+ if (commit != null) {
+ info.tree = GitTree.fromJSON(commit['tree']);
+ }
+
+ return info;
}
}

license: MIT License

original_message: handle `null` commit


message: Cleanup RepositoriesServiec.listPublicRepositories

diff:
@@ -65,19 +65,13 @@ class RepositoriesService extends Service {
var pages = limit != null ? (limit / 30).ceil() : null;
- // TODO: Close this, but where?
- var controller = new StreamController<Repository>.broadcast();
-
- new PaginationHelper(_github)
+ return new PaginationHelper(_github)
.fetchStreamed("GET", "/repositories", pages: pages, params: params)
- .listen((http.Response response) {
- var list = JSON.decode(response.body);
- var repos = new List.from(
- list.map((Map<String, dynamic> it) => Repository.fromJSON(it)));
- for (var repo in repos) controller.add(repo);
- });
+ .expand((http.Response response) {
+ var list = JSON.decode(response.body) as List<Map<String, dynamic>>;
- return controller.stream.take(limit);
+ return list.map((Map<String, dynamic> it) => Repository.fromJSON(it));
+ });
}
/// Creates a repository with [repository]. If an [org] is specified, the new


message:
Store GitHubFile.content without newlines (if they exist)
This is much better for future decoding

diff:
library github.common;
import "dart:async";
-import "dart:convert" show BASE64, JSON, UTF8;
+import "dart:convert" show BASE64, JSON, UTF8, LineSplitter;
import "package:html/dom.dart" as html;
import "package:html/parser.dart" as html_parser;

diff:
@@ -58,7 +58,9 @@ class GitHubFile {
..size = input['size']
..name = input['name']
..path = input['path']
- ..content = input['content']
+ ..content = input['content'] == null
+ ? null
+ : LineSplitter.split(input['content']).join()
..sha = input['sha']
..gitUrl = input['git_url']
..htmlUrl = input['html_url']


message: initial support for comparing commits

diff:
## v4.0.0
-* Make fields in many objects read-only.
+- Make fields in many objects read-only.
+- Initial support for comparing commits.
## v3.0.0

diff:
@@ -28,6 +28,18 @@ GitTreeEntry _$GitTreeEntryFromJson(Map json) => new GitTreeEntry(
json['sha'] as String,
json['url'] as String);
+// **************************************************************************
+// Generator: JsonSerializableGenerator
+// Target: class GitHubComparison
+// **************************************************************************
+
+GitHubComparison _$GitHubComparisonFromJson(Map json) => new GitHubComparison(
+ json['url'] as String,
+ json['status'] as String,
+ json['ahead_by'] as int,
+ json['behind_by'] as int,
+ json['total_commits'] as int);
+
// **************************************************************************
// Generator: JsonSerializableGenerator
// Target: class Tag

diff:
part of github.common;
+@JsonSerializable(createToJson: false)
+class GitHubComparison {
+ final String url;
+
+ final String status;
+
+ @JsonKey('ahead_by')
+ final int aheadBy;
+
+ @JsonKey('behind_by')
+ final int behindBy;
+
+ @JsonKey('total_commits')
+ final int totalCommits;
+
+ GitHubComparison(
+ this.url, this.status, this.aheadBy, this.behindBy, this.totalCommits);
+
+ factory GitHubComparison.fromJson(Map<String, dynamic> json) =>
+ _$GitHubComparisonFromJson(json);
+
+ String toString() {
+ switch (status) {
+ case 'identical':
+ return "GitHubComparison: identical";
+ case 'behind':
+ return "GitHubComparison: behind ($behindBy)";
+ case 'diverged':
+ return "GitHubComparison: diverged";
+ case 'ahead':
+ return "GitHubComparison: ahead ($aheadBy)";
+ default:
+ return "Huh??? - $status";
+ }
+ }
+}
+
/// Model class for a repository.
class Repository {
/// Repository Name

diff:
@@ -270,7 +270,14 @@ class RepositoriesService extends Service {
convert: RepositoryCommit.fromJSON) as Future<RepositoryCommit>;
}
- // TODO: Implement compareCommits: https://developer.github.com/v3/repos/commits/#compare-two-commits
+ /// [refBase] and [refHead] can be the same value for a branch, commit, or ref
+ /// in [slug] or specify other repositories by using `repo:ref` syntax.
+ ///
+ /// API docs: https://developer.github.com/v3/repos/commits/#compare-two-commits
+ Future<GitHubComparison> compareCommits(
+ RepositorySlug slug, String refBase, String refHead) =>
+ _github.getJSON("/repos/${slug.fullName}/compare/${refBase}...${refHead}",
+ convert: (j) => new GitHubComparison.fromJson(j));
/// Fetches the readme file for a repository.
///

original_message: initial support for comparing commits