UNPKG

@enact/sandstone

Version:

Large-screen/TV support library for Enact, containing a variety of UI components.

456 lines (448 loc) 17.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.DropdownDecorator = exports.DropdownBase = exports.Dropdown = void 0; var _propTypes = _interopRequireDefault(require("@enact/core/internal/prop-types")); var _handle = require("@enact/core/handle"); var _kind = _interopRequireDefault(require("@enact/core/kind")); var _util = require("@enact/core/util"); var _I18nDecorator = require("@enact/i18n/I18nDecorator"); var _Pause = _interopRequireDefault(require("@enact/spotlight/Pause")); var _SpotlightContainerDecorator = _interopRequireDefault(require("@enact/spotlight/SpotlightContainerDecorator")); var _Changeable = _interopRequireDefault(require("@enact/ui/Changeable")); var _ForwardRef = _interopRequireDefault(require("@enact/ui/ForwardRef")); var _IdProvider = _interopRequireDefault(require("@enact/ui/internal/IdProvider")); var _Pure = _interopRequireDefault(require("@enact/ui/internal/Pure")); var _resolution = _interopRequireDefault(require("@enact/ui/resolution")); var _Toggleable = _interopRequireDefault(require("@enact/ui/Toggleable")); var _propTypes2 = _interopRequireDefault(require("prop-types")); var _compose = _interopRequireDefault(require("ramda/src/compose")); var _warning = _interopRequireDefault(require("warning")); var _$L = _interopRequireDefault(require("../internal/$L")); var _Button = _interopRequireDefault(require("../Button")); var _ContextualPopupDecorator = _interopRequireDefault(require("../ContextualPopupDecorator")); var _util2 = require("../internal/util"); var _Heading = _interopRequireDefault(require("../Heading")); var _Skinnable = _interopRequireDefault(require("../Skinnable")); var _DropdownList = _interopRequireWildcard(require("./DropdownList")); var _DropdownModule = _interopRequireDefault(require("./Dropdown.module.css")); var _jsxRuntime = require("react/jsx-runtime"); var _excluded = ["forwardRef"], _excluded2 = ["aria-label", "ariaLabelledBy", "children", "direction", "disabled", "handleSpotlightPause", "onClose", "onOpen", "onSelect", "open", "placeholder", "selected", "size", "title", "width"]; /** * Sandstone styled Dropdown components * * @example * <Dropdown * defaultSelected={2} * inline * title="Options" * > * {['Option 1', 'Option 2', 'Option 3', 'Option 4']} * </Dropdown> * * @module sandstone/Dropdown * @exports Dropdown * @exports DropdownBase * @exports DropdownBaseDecorator */ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 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(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(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); } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } var pause = new _Pause["default"]('dropdown'); function pauseSpotlight(bool) { if (bool) { pause.pause(); return true; } else { return pause.resume(); } } var DropdownButtonBase = (0, _kind["default"])({ name: 'DropdownButtonBase', propTypes: { forwardRef: _propTypes["default"].ref }, render: function render(_ref) { var forwardRef = _ref.forwardRef, props = _objectWithoutProperties(_ref, _excluded); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button["default"], _objectSpread(_objectSpread({}, props), {}, { css: _DropdownModule["default"], ref: forwardRef, iconPosition: "after" })); } }); var DropdownButton = (0, _ContextualPopupDecorator["default"])({ noArrow: true }, (0, _ForwardRef["default"])(DropdownButtonBase)); DropdownButton.displayName = 'DropdownButton'; /** * A stateless Dropdown component. * * @class DropdownBase * @memberof sandstone/Dropdown * @extends sandstone/Button.Button * @extends sandstone/ContextualPopupDecorator.ContextualPopupDecorator * @omit popupComponent * @ui * @public */ var DropdownBase = exports.DropdownBase = (0, _kind["default"])({ name: 'Dropdown', propTypes: /** @lends sandstone/Dropdown.DropdownBase.prototype */{ /** * The "aria-label" for the Dropdown. * * @type {String} * @public */ 'aria-label': _propTypes2["default"].string, /** * Items to be displayed in the `Dropdown` when `open`. * * Takes either an array of strings or an array of objects. When strings, the values will be * used in the generated components as the readable text. When objects, the properties will * be passed onto an `Item` component; `children` as well as a unique `key` properties are * required. * * @type {String[]|Array.<{key: (Number|String), children: (String|Component)}>} * @public */ children: _propTypes2["default"].oneOfType([_propTypes2["default"].arrayOf(_propTypes2["default"].string), _propTypes2["default"].arrayOf(_propTypes2["default"].shape({ children: _propTypes["default"].renderable.isRequired, key: _propTypes2["default"].oneOfType([_propTypes2["default"].string, _propTypes2["default"].number]).isRequired }))]), /** * Placement of the Dropdown. * * @type {('above'|'below')} * @default 'below' * @public */ direction: _propTypes2["default"].oneOf(['above', 'below']), /** * Disables Dropdown, making it non-interactive. * * @type {Boolean} * @public */ disabled: _propTypes2["default"].bool, /** * The `id` of Dropdown referred to when generating id for `'title'`. * * @type {String} * @private */ id: _propTypes2["default"].string, /** * Called when the Dropdown is closing. * * @type {Function} * @public */ onClose: _propTypes2["default"].func, /** * Called when the Dropdown is opening. * * @type {Function} * @public */ onOpen: _propTypes2["default"].func, /** * Called when an item is selected. * * The event payload will be an object with the following members: * * `data` - The value for the option as received in the `children` prop * * `selected` - Number representing the selected option, 0 indexed * * @type {Function} * @public */ onSelect: _propTypes2["default"].func, /** * Displays the items. * * @type {Boolean} * @default false * @public */ open: _propTypes2["default"].bool, /** * Text displayed in the Dropdown when nothing is selected. * * The placeholder will be replaced by the selected item. * * @type {String} * @default 'No Selection' * @public */ placeholder: _propTypes2["default"].string, /** * Indicates the locale's text direction is right-to-left. * * @type {Boolean} * @private */ rtl: _propTypes2["default"].bool, /** * Index of the selected item. * * @type {Number} * @public */ selected: _propTypes2["default"].number, /** * The size of the Dropdown's {@link sandstone/Button.Button|Button} component. * * @type {('large'|'small')} * @default 'small' * @public */ size: _propTypes2["default"].oneOf(['large', 'small']), /** * Primary title text of the Dropdown. * * @type {String} * @public */ title: _propTypes2["default"].string, /** * Width of the Dropdown. * * @type {('huge'|'large'|'x-large'|'medium'|'small'|'tiny')|number} * @default 'medium' * @public */ width: _propTypes2["default"].oneOfType([_propTypes2["default"].oneOf(['tiny', 'small', 'medium', 'large', 'x-large', 'huge']), _propTypes2["default"].number]) }, defaultProps: { direction: 'below', open: false, size: 'small', width: 'medium' }, handlers: { onSelect: (0, _handle.handle)((0, _handle.forwardCustom)('onSelect', function (ev) { return ev; }), (0, _handle.forward)('onClose')), onOpen: (0, _handle.handle)((0, _handle.forward)('onClick'), (0, _handle.not)((0, _handle.forProp)('disabled', true)), (0, _handle.not)((0, _handle.forProp)('open', true)), function () { return pauseSpotlight(true); }, (0, _handle.forward)('onOpen')) }, styles: { css: _DropdownModule["default"], className: 'dropdown' }, computed: { ariaLabelledBy: function ariaLabelledBy(_ref2) { var id = _ref2.id, title = _ref2.title; return title ? "".concat(id, "_title") : void 0; }, children: function children(_ref3) { var _children = _ref3.children, selected = _ref3.selected; if (!Array.isArray(_children)) return []; return _children.map(function (child, i) { var aria = { role: 'checkbox', 'aria-checked': selected === i }; process.env.NODE_ENV !== "production" ? (0, _warning["default"])(child != null, "Unsupported null or undefined child provided at index ".concat(i, " which will not be visible when rendered.")) : void 0; if (typeof child === 'string') { return _objectSpread(_objectSpread({}, aria), {}, { children: child, key: "item_".concat(child) }); } return _objectSpread(_objectSpread({}, aria), child); }); }, className: function className(_ref4) { var width = _ref4.width, title = _ref4.title, styler = _ref4.styler; return styler.append(typeof width === 'string' ? "".concat(width, "Width") : null, { hasTitle: Boolean(title) }); }, direction: function direction(_ref5) { var _direction = _ref5.direction; return "".concat(_direction, " center"); }, handleSpotlightPause: function handleSpotlightPause() { return pauseSpotlight; }, placeholder: function placeholder(_ref6) { var children = _ref6.children, _ref6$placeholder = _ref6.placeholder, _placeholder = _ref6$placeholder === void 0 ? (0, _$L["default"])('No Selection') : _ref6$placeholder, selected = _ref6.selected; if ((0, _DropdownList.isSelectedValid)({ children: children, selected: selected })) { var child = children[selected]; return typeof child === 'object' ? child.children : child; } return _placeholder; }, title: function title(_ref7) { var id = _ref7.id, _title = _ref7.title, width = _ref7.width; return _title && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Heading["default"], { className: _DropdownModule["default"].title, id: "".concat(id, "_title"), size: "tiny", style: { width: typeof width === 'number' ? _resolution["default"].scaleToRem(width) : null }, children: _title }); } }, render: function render(_ref8) { var ariaLabel = _ref8['aria-label'], ariaLabelledBy = _ref8.ariaLabelledBy, children = _ref8.children, direction = _ref8.direction, disabled = _ref8.disabled, handleSpotlightPause = _ref8.handleSpotlightPause, onClose = _ref8.onClose, onOpen = _ref8.onOpen, onSelect = _ref8.onSelect, open = _ref8.open, placeholder = _ref8.placeholder, selected = _ref8.selected, size = _ref8.size, title = _ref8.title, width = _ref8.width, rest = _objectWithoutProperties(_ref8, _excluded2); delete rest.rtl; var ariaProps = (0, _util.extractAriaProps)(rest); var calcAriaProps = ariaLabel != null ? null : { role: 'region', 'aria-labelledby': ariaLabelledBy }; var popupProps = { 'aria-live': null, children: children, handleSpotlightPause: handleSpotlightPause, onSelect: onSelect, selected: selected, width: width, role: null }; var voiceProps = (0, _util2.extractVoiceProps)(rest); // `ui/Group`/`ui/Repeater` will throw an error if empty so we disable the Dropdown and // prevent Dropdown to open if there are no children. var hasChildren = children.length > 0; var openDropdown = hasChildren && !disabled && open; return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread(_objectSpread({}, calcAriaProps), rest), {}, { children: [title, /*#__PURE__*/(0, _jsxRuntime.jsx)(DropdownButton, _objectSpread(_objectSpread(_objectSpread({ "aria-label": (ariaLabel || placeholder) + " ".concat((0, _$L["default"])('Dropdown')), direction: direction, disabled: hasChildren ? disabled : true, focusEffect: "static", icon: openDropdown ? 'arrowlargeup' : 'arrowlargedown', popupProps: popupProps, popupComponent: _DropdownList["default"], onClick: onOpen, onClose: onClose, open: openDropdown, size: size, spotlightRestrict: "self-only", style: { width: typeof width === 'number' ? _resolution["default"].scaleToRem(width) : null } }, ariaProps), voiceProps), {}, { children: placeholder }))] })); } }); /** * Applies Sandstone specific behaviors and functionality to * {@link sandstone/Dropdown.DropdownBase|DropdownBase}. * * @hoc * @memberof sandstone/Dropdown * @mixes ui/Changeable.Changeable * @mixes ui/Toggleable.Toggleable * @mixes spotlight/SpotlightContainerDecorator.SpotlightContainerDecorator * @omit selected * @omit defaultSelected * @omit value * @omit defaultValue * @omit onChange * @public */ var DropdownDecorator = exports.DropdownDecorator = (0, _compose["default"])((0, _Pure["default"])({ propComparators: { children: _util2.compareChildren } }), _SpotlightContainerDecorator["default"], (0, _I18nDecorator.I18nContextDecorator)({ rtlProp: 'rtl' }), (0, _IdProvider["default"])({ generateProp: null, prefix: 'd_' }), (0, _Changeable["default"])({ change: 'onSelect', prop: 'selected' }), (0, _Toggleable["default"])({ activate: 'onOpen', deactivate: 'onClose', prop: 'open', toggle: null }), _Skinnable["default"]); /** * Displays the items. * * @name open * @memberof sandstone/Dropdown.DropdownDecorator.prototype * @type {Boolean} * @default false * @public */ /** * Index of the selected item. * * @name selected * @memberof sandstone/Dropdown.DropdownDecorator.prototype * @type {Number} * @public */ /** * The initial selected index when `selected` is not defined. * * @name defaultSelected * @memberof sandstone/Dropdown.DropdownDecorator.prototype * @type {Number} * @public */ /** * A Sandstone Dropdown component. * * By default, `Dropdown` maintains the state of its `selected` property. Supply the * `defaultSelected` property to control its initial value. If you wish to directly control updates * to the component, supply a value to `selected` at creation time and update it in response to * `onSelect` events. * * @class Dropdown * @memberof sandstone/Dropdown * @extends sandstone/Dropdown.DropdownBase * @ui * @public */ var Dropdown = exports.Dropdown = DropdownDecorator(DropdownBase); var _default = exports["default"] = Dropdown;