UNPKG

@enact/ui

Version:

A collection of simplified unstyled cross-platform UI components for Enact

438 lines (432 loc) 16.8 kB
"use strict"; 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;