@enact/sandstone
Version:
Large-screen/TV support library for Enact, containing a variety of UI components.
456 lines (448 loc) • 17.9 kB
JavaScript
"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;