@enact/ui
Version:
A collection of simplified unstyled cross-platform UI components for Enact
438 lines (432 loc) • 16.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Cell", {
enumerable: true,
get: function get() {
return _Cell.Cell;
}
});
Object.defineProperty(exports, "CellBase", {
enumerable: true,
get: function get() {
return _Cell.CellBase;
}
});
Object.defineProperty(exports, "CellDecorator", {
enumerable: true,
get: function get() {
return _Cell.CellDecorator;
}
});
exports["default"] = exports.Row = exports.LayoutDecorator = exports.LayoutBase = exports.Layout = exports.Column = void 0;
var _propTypes = _interopRequireDefault(require("@enact/core/internal/prop-types"));
var _kind = _interopRequireDefault(require("@enact/core/kind"));
var _propTypes2 = _interopRequireDefault(require("prop-types"));
var _ForwardRef = _interopRequireDefault(require("../ForwardRef"));
var _Cell = require("./Cell");
var _LayoutModule = _interopRequireDefault(require("./Layout.module.css"));
var _jsxRuntime = require("react/jsx-runtime");
var _excluded = ["component", "componentRef"];
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
* A convenient tool for laying-out content using `Layout`, `Cell`, `Row`, and `Column`.
*
* Layout is a powerful and versatile tool used for arranging content on the screen. On a conceptual
* level, it mixes the best parts of HTML tables with the best parts of HTML framesets, both of
* which were largely abandoned for their drawbacks, ignoring their strengths. A `Layout` is simply
* a container for `Cell`, the only "legal" child. Conversely, `Cell` may only be used in a
* `Layout`. Cells in a Layout can either be positioned next to each other (horizontally) or
* above/below each other (vertically) in what we refer to as a {@link ui/Layout.Row|Row} or
* {@link ui/Layout.Column|Column}, respectively.
*
* The `Row` and `Column` layout presets describe the direction of layout for their children. This
* can sometimes cause confusion. A `Row` of children naturally forms a _layout_ whose children can
* have the _appearance_ of columns. To keep things clear, think about the layout rather than
* what the children themselves represent.
*
* `Layout` is an implementation of flex-box, but with built-in rails, properties, and features to
* help avoid common problems with flex-box; things like content overflowing, sizing quirks, and
* positioning problems regarding content of unknown or undefined dimension.
*
* The following scenarios are some common cases where `Layout` can truly help out. A quality of
* `Cell` you'll see below is that when a `Cell` has no defined size, it automatically sizes to fill
* any remaining space in the `Layout`. If there are multiple auto-sizing `Cell` components, they
* share the space, subdividing it equally among themselves. It's great to leverage this and only
* apply sizes to `Cell`s which must have defined sizes. `shrink` is one of the ways you can impose
* size guidelines on a `Cell`. It automatically fits the size of the Cell to the size of its
* content.
*
* A row of cells where the last one should always attach to the right side, regardless of the size
* of the main "content" cell:
* ```
* ┌───────┬─┐
* │Main │R│
* └───────┴─┘
* ```
*
* ```
* <Row>
* <Cell>Main Content</Cell>
* <Cell shrink>Right Side</Cell>
* </Row>
* ```
*
* A "two-column" layout with equal sized cells using `Row`:
* ```
* ┌────┬────┐
* │L │R │
* └────┴────┘
* ```
*
* ```
* <Row style={{height: '100%'}}>
* <Cell>Left Column</Cell>
* <Cell>Right Column</Cell>
* </Row>
* ```
* *Remember:* The cells of the `Row` are the columns in our layout. It's likely that in a complex
* layout `Column` would be used inside the left and right cells to arrange the components, as in
* the example below.
*
* A full-height sidebar with a header and body to the right:
* ```
* ┌──┬──────┐
* │S │HEADER│
* │ ├──────┤
* │ │Body │
* │ │ │
* └──┴──────┘
* ```
*
* ```
* <Row style={{height: '100%'}}>
* <Cell size="20%">Sidebar</Cell>
* <Cell>
* <Column>
* <Cell size={90} component="header">
* <h1>HEADER</h1>
* </Cell>
* <Cell>
* <p>Body area</p>
* </Cell>
* </Column>
* </Cell>
* </Row>
* ```
* *Note:* Here, we've set the height of `Row` so it fills the height of the screen, allowing the
* Sidebar Cell and content Cell to stretch from the top to the bottom. We've also leveraged the
* `component` prop on the header cell, which tells `Cell` to render itself as a "header" HTML tag
* rather than its usual "div" tag.
*
* The example below produces a layout like the following:
* ```
* ┌─┬─────┬─┐
* │o│Item │o│
* └─┴─────┴─┘
* ```
*
* You'll notice the use of some special classes in the example: `"debug layout"`. Adding these on
* any element in your DOM hierarchy will enable borders in Layout and Cell to help visualize what
* is happening in the layout. They automatically change color the deeper in the stack they go.
*
* @example
* <Layout className="debug layout">
* <Cell shrink>
* <button>First</button>
* </Cell>
* <Cell>
* <div>A div with some long text in it</div>
* </Cell>
* <Cell shrink>
* <button>Last</button>
* </Cell>
* </Layout>
*
* @module ui/Layout
* @exports Cell
* @exports CellBase
* @exports CellDecorator
* @exports Column
* @exports Layout
* @exports LayoutBase
* @exports LayoutDecorator
* @exports Row
*/ /**
* A container for `Cell`s.
*
* A stateless component that acts as a containing area for {@link ui/Layout.Cell|Cells} to be
* positioned in a row or a column (horizontally or vertically, respectively. It supports an
* {@link ui/Layout.LayoutBase.orientation|orientation} property for laying-out its contents
* (`Cells`) in an organized, readable way.
*
* Example:
* ```
* import Input from '@enact/moonstone/Input';
* import css from './LayoutExample.less';
* ...
* <fieldset>
* <Layout align="center">
* <Cell component="label" size="40%" className={css.label} shrink>First Name</Cell>
* <Cell component={Input} placeholder="First" className={css.input} />
* </Layout>
* <Layout align="center">
* <Cell component="label" size="40%" className={css.label} shrink>Last Name</Cell>
* <Cell component={Input} placeholder="Last" className={css.input} />
* </Layout>
* </fieldset>
* ```
*
* @class LayoutBase
* @ui
* @memberof ui/Layout
* @public
*/
var LayoutBase = exports.LayoutBase = (0, _kind["default"])({
name: 'LayoutBase',
propTypes: /** @lends ui/Layout.LayoutBase.prototype */{
/**
* The alignment of children.
*
* Aligns the children {@link ui/Layout.Cell|Cells} vertically in the case of a horizontal
* layout or horizontally in the case of a vertical layout. `"start"`, `"center"` and
* `"end"` are the most commonly used, although all values of `align-items` are supported.
* `"start"` refers to the top in a horizontal layout, and left in a vertical LTR layout
* `"end"` refers to the bottom in a horizontal layout, and right in a vertical LTR layout
* `"start"` and `"end"` reverse places when in a vertical layout in a RTL locale.
* This includes support shorthand for combining `align-items` and `justify-content` into
* a single property, separated by a space, in that order. This allows you to specify both
* the horizontal and vertical alignment in one property, separated by a space.
*
* For example, `align="center space-between"` means `align-items: center` and
* `justify-content: space-between` for each. `justify-content` property can be used to
* align the Cells on the main axis and adjust gaps among the Cells. To declare the
* `justify-content` property only, just add a heading space for `align` prop string like
* `align=" space-between"`. The default value for `align-items` is `stretch`. It can be
* also used for `align` prop like `align="stretch space-between"`. All values of
* `justify-content` are supported, like `start`, `end`, `center`, `space-between`,
* `space-around`, and `space-evenly`.
*
* ```
* <Layout align="center space-around">
* <Cell>Left Column</Cell>
* <Cell>Right Column</Cell>
* </Layout>
* ```
* ```
* <Layout align=" space-between">
* <Cell>Left Column</Cell>
* <Cell>Right Column</Cell>
* </Layout>
* ```
*
* @type {String}
* @public
*/
align: _propTypes2["default"].string,
/**
* Only {@link ui/Layout.Cell|Cell} components are supported as children.
*
* @type {Cell|Cell[]}
* @public
*/
children: _propTypes2["default"].any,
/**
* The type of component to use to render as the `Layout`. May be a DOM node name (e.g 'div',
* 'span', etc.) or a custom component.
*
* @type {String|Component}
* @default 'div'
* @public
*/
component: _propTypes["default"].renderable,
/**
* Called with a reference to the root component.
*
* When using {@link ui/Layout.Layout}, the `ref` prop is forwarded to this component
* as `componentRef`.
*
* @type {Object|Function}
* @public
*/
componentRef: _propTypes["default"].ref,
/**
* Allows this `Layout` to have following siblings drawn on the same line as itself
* instead of carving out the entire horizontal space for itself.
*
* @type {Boolean}
* @default false
* @public
*/
inline: _propTypes2["default"].bool,
/**
* The orientation of the `Layout`, i.e. how the children {@link ui/Layout.Cell|Cells} are
* positioned on the screen. Must be either `'horizontal'` or `'vertical'`.
*
* @type {String}
* @default 'horizontal'
* @public
*/
orientation: _propTypes2["default"].oneOf(['horizontal', 'vertical']),
/**
* Sets the Layout's `flex-wrap` values.
*
* Determines how a Layout handles its cells if there are more than fit in the available
* space. This works like a normal `Boolean` prop, but also accepts strings for customization
* beyond the basic on/off support. In addition to `true` and `false`, the following strings
* are supported: 'wrap', 'nowrap', 'reverse'. 'reverse' performs standard line wrapping but
* additional lines are placed above/before the preceding line instead of below/after.
*
* @type {Boolean|String}
* @public
*/
wrap: _propTypes2["default"].oneOfType([_propTypes2["default"].bool, _propTypes2["default"].oneOf(['reverse', 'nowrap', 'wrap'])])
},
defaultProps: {
component: 'div',
inline: false,
orientation: 'horizontal',
wrap: false
},
styles: {
css: _LayoutModule["default"],
className: 'layout'
},
computed: {
className: function className(_ref) {
var inline = _ref.inline,
orientation = _ref.orientation,
wrap = _ref.wrap,
styler = _ref.styler;
return styler.append(orientation, {
inline: inline,
nowrap: wrap === false || wrap === 'nowrap',
wrap: wrap === true || wrap === 'wrap',
wrapReverse: wrap === 'wrapReverse'
});
},
style: function style(_ref2) {
var align = _ref2.align,
_style = _ref2.style;
if (!align) return _style;
// This is effectively a polyfill for the upcoming `place-items` prop which is shorthand
// for align-items and justify-items together
var alignParts = align.split(' ');
return _objectSpread(_objectSpread({}, _style), {}, {
alignItems: (0, _Cell.toFlexAlign)(alignParts[0]),
justifyContent: (0, _Cell.toFlexAlign)(alignParts[1])
});
}
},
render: function render(_ref3) {
var Component = _ref3.component,
componentRef = _ref3.componentRef,
rest = _objectWithoutProperties(_ref3, _excluded);
delete rest.align;
delete rest.inline;
delete rest.orientation;
delete rest.wrap;
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Component, _objectSpread({
ref: componentRef
}, rest));
}
});
/**
* Applies Layout behaviors.
*
* @hoc
* @memberof ui/Layout
* @mixes ui/ForwardRef.ForwardRef
* @public
*/
var LayoutDecorator = exports.LayoutDecorator = (0, _ForwardRef["default"])({
prop: 'componentRef'
});
/**
* A container for `Cell`s.
*
* A stateless component that acts as a containing area for {@link ui/Layout.Cell|Cells} to be
* positioned in a row or a column (horizontally or vertically, respectively. It supports an
* {@link ui/Layout.LayoutBase.orientation|orientation} property for laying-out its contents
* (`Cells`) in an organized, readable way.
*
* Example:
* ```
* import Input from '@enact/moonstone/Input';
* import css from './LayoutExample.less';
* ...
* <fieldset>
* <Layout align="center">
* <Cell component="label" size="40%" className={css.label} shrink>First Name</Cell>
* <Cell component={Input} placeholder="First" className={css.input} />
* </Layout>
* <Layout align="center">
* <Cell component="label" size="40%" className={css.label} shrink>Last Name</Cell>
* <Cell component={Input} placeholder="Last" className={css.input} />
* </Layout>
* </fieldset>
* ```
*
* @class Layout
* @memberof ui/Layout
* @extends ui/Layout.LayoutBase
* @mixes ui/ForwardRef.ForwardRef
* @omit componentRef
* @ui
* @public
*/
var Layout = exports.Layout = LayoutDecorator(LayoutBase);
/**
* Shorthand for `<Layout orientation="vertical">`, which positions its
* {@link ui/Layout.Cell|Cells} vertically.
* ```
* ┌────┐
* ├────┤
* ├────┤
* ├────┤
* └────┘
* ```
*
* @class Column
* @memberof ui/Layout
* @extends ui/Layout.Layout
* @mixes ui/ForwardRef.ForwardRef
* @ui
* @public
*/
var Column = exports.Column = LayoutDecorator(function (props) {
return LayoutBase.inline(_objectSpread(_objectSpread({}, props), {}, {
orientation: 'vertical'
}));
});
Column.displayName = 'Column';
/**
* Shorthand for `<Layout orientation="horizontal">`, which positions its
* {@link ui/Layout.Cell|Cells} horizontally.
* ```
* ┌─┬─┬─┬─┐
* │ │ │ │ │
* └─┴─┴─┴─┘
* ```
*
* @class Row
* @memberof ui/Layout
* @extends ui/Layout.Layout
* @mixes ui/ForwardRef.ForwardRef
* @ui
* @public
*/
var Row = exports.Row = LayoutDecorator(function (props) {
return LayoutBase.inline(_objectSpread(_objectSpread({}, props), {}, {
orientation: 'horizontal'
}));
});
Row.displayName = 'Row';
var _default = exports["default"] = Layout;