@carbon/react
Version:
React components for the Carbon Design System
346 lines (333 loc) • 10.8 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* 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 { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
import * as FeatureFlags from '@carbon/feature-flags';
import cx from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import { usePrefix } from '../../internal/usePrefix.js';
import { useGridSettings } from './GridContext.js';
const Column = /*#__PURE__*/React.forwardRef(({
as,
children,
className: customClassName,
sm,
md,
lg,
xlg,
max,
...rest
}, ref) => {
const {
mode
} = useGridSettings();
const prefix = usePrefix();
const BaseComponent = as || 'div';
if (mode === 'css-grid') {
return /*#__PURE__*/React.createElement(CSSGridColumn, _extends({
as: BaseComponent,
className: customClassName,
sm: sm,
md: md,
ref: ref,
lg: lg,
xlg: xlg,
max: max
}, rest), children);
}
const columnClassName = getClassNameForFlexGridBreakpoints([sm, md, lg, xlg, max], prefix);
const className = cx(customClassName, columnClassName, {
[`${prefix}--col`]: columnClassName.length === 0
});
return /*#__PURE__*/React.createElement(BaseComponent, _extends({
className: className,
ref: ref
}, rest), children);
});
const percentSpanType = PropTypes.oneOf(['25%', '50%', '75%', '100%']);
const spanPropType = FeatureFlags.enabled('enable-css-grid') ? PropTypes.oneOfType([PropTypes.bool, PropTypes.number, PropTypes.shape({
span: PropTypes.oneOfType([PropTypes.number, percentSpanType]),
offset: PropTypes.number,
start: PropTypes.number,
end: PropTypes.number
}), percentSpanType]) : PropTypes.oneOfType([PropTypes.bool, PropTypes.number, PropTypes.shape({
span: PropTypes.number,
offset: PropTypes.number
})]);
Column.propTypes = {
/**
* Provide a custom element to render instead of the default <div>
*/
as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
/**
* Pass in content that will be rendered within the `Column`
*/
children: PropTypes.node,
/**
* Specify a custom className to be applied to the `Column`
*/
className: PropTypes.string,
/**
* Specify column span for the `lg` breakpoint (Default breakpoint up to 1312px)
* This breakpoint supports 16 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
lg: spanPropType,
/**
* Specify column span for the `max` breakpoint. This breakpoint supports 16
* columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
max: spanPropType,
/**
* Specify column span for the `md` breakpoint (Default breakpoint up to 1056px)
* This breakpoint supports 8 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
md: spanPropType,
/**
* Specify column span for the `sm` breakpoint (Default breakpoint up to 672px)
* This breakpoint supports 4 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
sm: spanPropType,
/**
* Specify constant column span, start, or end values that will not change
* based on breakpoint
*/
span: PropTypes.oneOfType([PropTypes.number, percentSpanType]),
/**
* Specify column span for the `xlg` breakpoint (Default breakpoint up to
* 1584px) This breakpoint supports 16 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
xlg: spanPropType
};
const CSSGridColumn = /*#__PURE__*/React.forwardRef(({
as: BaseComponent = 'div',
children,
className: containerClassName,
sm,
md,
lg,
xlg,
max,
span,
...rest
}, ref) => {
// Add ref parameter
const prefix = usePrefix();
const breakpointClassName = getClassNameForBreakpoints([sm, md, lg, xlg, max], prefix);
const spanClassName = getClassNameForSpan(span, prefix);
const className = cx(containerClassName, breakpointClassName, spanClassName, {
[`${prefix}--css-grid-column`]: true
});
return /*#__PURE__*/React.createElement(BaseComponent, _extends({
className: className,
ref: ref
}, rest), children);
});
CSSGridColumn.propTypes = {
/**
* Provide a custom element to render instead of the default <div>
*/
as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
/**
* Pass in content that will be rendered within the `Column`
*/
children: PropTypes.node,
/**
* Specify a custom className to be applied to the `Column`
*/
className: PropTypes.string,
/**
* Specify column span for the `lg` breakpoint (Default breakpoint up to 1312px)
* This breakpoint supports 16 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
lg: spanPropType,
/**
* Specify column span for the `max` breakpoint. This breakpoint supports 16
* columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
max: spanPropType,
/**
* Specify column span for the `md` breakpoint (Default breakpoint up to 1056px)
* This breakpoint supports 8 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
md: spanPropType,
/**
* Specify column span for the `sm` breakpoint (Default breakpoint up to 672px)
* This breakpoint supports 4 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
sm: spanPropType,
/**
* Specify constant column span, start, or end values that will not change
* based on breakpoint
*/
span: PropTypes.oneOfType([PropTypes.number, percentSpanType, PropTypes.shape({
span: PropTypes.oneOfType([PropTypes.number, percentSpanType]),
start: PropTypes.number,
end: PropTypes.number
})]),
/**
* Specify column span for the `xlg` breakpoint (Default breakpoint up to
* 1584px) This breakpoint supports 16 columns by default.
*
* @see https://carbondesignsystem.com/elements/2x-grid/overview/#breakpoints
*/
xlg: spanPropType
};
const breakpointNames = ['sm', 'md', 'lg', 'xlg', 'max'];
/**
* @typedef {object} Breakpoint
* @property {boolean|number} [span]
* @property {number} [offset]
*/
/**
* Build the appropriate className for the given set of breakpoints.
* @param {Array<boolean|number|Breakpoint>} breakpoints
* @returns {string}
*/
function getClassNameForBreakpoints(breakpoints, prefix) {
const classNames = [];
for (let i = 0; i < breakpoints.length; i++) {
const breakpoint = breakpoints[i];
if (breakpoint === undefined || breakpoint === null) {
continue;
}
const name = breakpointNames[i];
// If our breakpoint is a boolean, the user has specified that the column
// should be "auto" at this size
if (breakpoint === true) {
classNames.push(`${prefix}--${name}:col-span-auto`);
continue;
}
// If our breakpoint is a string, the user might have specified a percent
// they'd like this column to span.
if (typeof breakpoint === 'string') {
classNames.push(`${prefix}--${name}:col-span-${breakpoint.replace('%', '')}`);
continue;
}
// If our breakpoint is a number, the user has specified the number of
// columns they'd like this column to span
if (typeof breakpoint === 'number') {
classNames.push(`${prefix}--${name}:col-span-${breakpoint}`);
continue;
}
if (typeof breakpoint === 'object') {
const {
span,
offset,
start,
end
} = breakpoint;
if (typeof offset === 'number') {
classNames.push(`${prefix}--${name}:col-start-${offset > 0 ? offset + 1 : 'auto'}`);
}
if (typeof start === 'number') {
classNames.push(`${prefix}--${name}:col-start-${start ? start : 'auto'}`);
}
if (typeof end === 'number') {
classNames.push(`${prefix}--${name}:col-end-${end}`);
}
if (typeof span === 'number') {
classNames.push(`${prefix}--${name}:col-span-${span}`);
} else if (typeof span === 'string') {
classNames.push(`${prefix}--${name}:col-span-${span.slice(0, -1)}`);
continue;
}
}
}
return classNames.join(' ');
}
/**
* Build the appropriate className for the given set of breakpoints.
* @param {Array<boolean|number|Breakpoint>} breakpoints
* @returns {string}
*/
function getClassNameForFlexGridBreakpoints(breakpoints, prefix) {
const classNames = [];
for (let i = 0; i < breakpoints.length; i++) {
const breakpoint = breakpoints[i];
if (breakpoint === undefined || breakpoint === null) {
continue;
}
const name = breakpointNames[i];
// If our breakpoint is a boolean, the user has specified that the column
// should be "auto" at this size
if (breakpoint === true) {
classNames.push(`${prefix}--col-${name}`);
continue;
}
// If our breakpoint is a number, the user has specified the number of
// columns they'd like this column to span
if (typeof breakpoint === 'number') {
classNames.push(`${prefix}--col-${name}-${breakpoint}`);
continue;
}
if (typeof breakpoint === 'object') {
const {
span,
offset
} = breakpoint;
if (typeof span === 'number') {
classNames.push(`${prefix}--col-${name}-${span}`);
}
if (span === true) {
classNames.push(`${prefix}--col-${name}`);
}
if (typeof offset === 'number') {
classNames.push(`${prefix}--offset-${name}-${offset}`);
}
}
}
return classNames.join(' ');
}
/**
* Build the appropriate className for a span value
*/
function getClassNameForSpan(value, prefix) {
const classNames = [];
if (typeof value === 'number') {
classNames.push(`${prefix}--col-span-${value}`);
}
// If value is a string, the user has specified a percent
// they'd like this column to span.
else if (typeof value === 'string') {
classNames.push(`${prefix}--col-span-${value.slice(0, -1)}`);
} else if (typeof value === 'object') {
const {
span,
start,
end
} = value;
if (span !== undefined && span !== null) {
classNames.push(`${prefix}--col-span-${span}`);
}
if (start !== undefined && start !== null) {
classNames.push(`${prefix}--col-start-${start}`);
}
if (end !== undefined && end !== null) {
classNames.push(`${prefix}--col-end-${end}`);
}
}
return classNames.join('');
}
export { Column as default };