@enact/sandstone
Version:
Large-screen/TV support library for Enact, containing a variety of UI components.
192 lines (186 loc) • 11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.ScrollbarTrackBase = exports.ScrollbarTrack = void 0;
var _classnames = _interopRequireDefault(require("classnames"));
var _keymap = require("@enact/core/keymap");
var _Accelerator = _interopRequireDefault(require("@enact/spotlight/Accelerator"));
var _Spottable = _interopRequireDefault(require("@enact/spotlight/Spottable"));
var _AnnounceDecorator = require("@enact/ui/AnnounceDecorator");
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = require("react");
var _$L = _interopRequireDefault(require("../internal/$L"));
var _ScrollbarTrackModule = _interopRequireDefault(require("./ScrollbarTrack.module.css"));
var _jsxRuntime = require("react/jsx-runtime");
var _excluded = ["aria-label", "cbAlertScrollbarTrack", "focusableScrollbar", "onInteractionForScroll", "rtl", "scrollbarTrackCss", "vertical"];
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 nop = function nop() {};
var isDown = (0, _keymap.is)('down'),
isLeft = (0, _keymap.is)('left'),
isPageUp = (0, _keymap.is)('pageUp'),
isPageDown = (0, _keymap.is)('pageDown'),
isRight = (0, _keymap.is)('right'),
isUp = (0, _keymap.is)('up');
var scrollStopWaiting = 500; // Wait for finishing scroll animation.
var SpotlightAccelerator = new _Accelerator["default"]();
var SpottableDiv = (0, _Spottable["default"])('div');
/**
* A Sandstone-styled scrollbar track with sandstone behavior
*
* @class ScrollbarTrack
* @memberof sandstone/useScroll
* @ui
* @private
*/
var ScrollbarTrack = exports.ScrollbarTrackBase = exports.ScrollbarTrack = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
var ariaLabel = props['aria-label'],
cbAlertScrollbarTrack = props.cbAlertScrollbarTrack,
focusableScrollbar = props.focusableScrollbar,
onInteractionForScroll = props.onInteractionForScroll,
rtl = props.rtl,
scrollbarTrackCss = props.scrollbarTrackCss,
vertical = props.vertical,
rest = _objectWithoutProperties(props, _excluded),
className = (0, _classnames["default"])(_ScrollbarTrackModule["default"].scrollbarTrack, _defineProperty(_defineProperty({}, _ScrollbarTrackModule["default"].vertical, vertical), _ScrollbarTrackModule["default"].focusableScrollbar, focusableScrollbar)),
ScrollbarThumb = focusableScrollbar ? SpottableDiv : 'div',
announceRef = (0, _react.useRef)({});
(0, _react.useEffect)(function () {
cbAlertScrollbarTrack();
SpotlightAccelerator.reset();
return function () {
SpotlightAccelerator.reset();
};
}, []); // eslint-disable-line react-hooks/exhaustive-deps
var consumeEventWithScroll = (0, _react.useCallback)(function (scrollParam, ev) {
ev.preventDefault();
ev.stopPropagation(); // stop propagation of React synthetic event to other components like PopupDecorator
ev.nativeEvent.stopImmediatePropagation(); // stop propagation of browser native event to Spotlight
onInteractionForScroll(scrollParam);
}, [onInteractionForScroll]);
var onKeyDown = (0, _react.useCallback)(function (ev) {
if (SpotlightAccelerator.processKey(ev, nop)) {
ev.stopPropagation(); // stop propagation of React synthetic event to other components like PopupDecorator
ev.nativeEvent.stopImmediatePropagation(); // stop propagation of browser native event to Spotlight
} else {
var keyCode = ev.keyCode,
isLeftRight = isLeft(keyCode) || isRight(keyCode),
isUpDown = isUp(keyCode) || isDown(keyCode),
isPageKey = isPageUp(keyCode) || isPageDown(keyCode),
scrollParam = {
inputType: isPageKey ? 'pageKey' : 'arrowKey',
isPagination: isPageKey,
isForward: !rtl && isRight(keyCode) || rtl && isLeft(keyCode) || isDown(keyCode) || isPageDown(keyCode),
isVerticalScrollBar: vertical
},
scrollProgress = Number(ref.current && ref.current.style.getPropertyValue('--scrollbar-thumb-progress-ratio')),
scrollSize = Number(ref.current && ref.current.style.getPropertyValue('--scrollbar-thumb-size-ratio'));
if (vertical && (isUpDown || isPageKey) || !vertical && isLeftRight) {
// Do nothing when (!vertical && pageKey)
if (!ev.repeat && announceRef.current.announce) {
announceRef.current.announce((isDown(keyCode) || isPageDown(keyCode)) && (0, _$L["default"])('DOWN') || (isUp(keyCode) || isPageUp(keyCode)) && (0, _$L["default"])('UP') || isLeft(keyCode) && (0, _$L["default"])('LEFT') || (0, _$L["default"])('RIGHT') // the case that isRight(keyCode) is true
);
}
if (ev.repeat || scrollSize !== 1 && (scrollParam.isForward && scrollProgress !== 1 || !scrollParam.isForward && scrollProgress !== 0)) {
consumeEventWithScroll(scrollParam, ev);
setTimeout(function () {
var updatedScrollProgress = Number(ref.current && ref.current.style.getPropertyValue('--scrollbar-thumb-progress-ratio'));
var horizontalReachLeftMost = rtl ? updatedScrollProgress === 1 : updatedScrollProgress === 0;
var horizontalReachRightMost = rtl ? updatedScrollProgress === 0 : updatedScrollProgress === 1;
// Current UX announce only after Scroll via Scrollthumb.
if (announceRef.current.announce && (updatedScrollProgress === 0 || updatedScrollProgress === 1)) {
announceRef.current.announce((isDown(keyCode) || isPageDown(keyCode)) && updatedScrollProgress === 1 && (0, _$L["default"])('DOWNMOST') || (isUp(keyCode) || isPageUp(keyCode)) && updatedScrollProgress === 0 && (0, _$L["default"])('UPMOST') || isLeft(keyCode) && horizontalReachLeftMost && (0, _$L["default"])('LEFTMOST') || isRight(keyCode) && horizontalReachRightMost && (0, _$L["default"])('RIGHTMOST') // the case that isRight(keyCode) is true
);
}
}, scrollStopWaiting);
}
}
if (!ev.repeat) {
SpotlightAccelerator.reset();
}
}
}, [consumeEventWithScroll, ref, rtl, vertical]);
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", _objectSpread(_objectSpread({}, rest), {}, {
className: (0, _classnames["default"])(className, scrollbarTrackCss && scrollbarTrackCss.scrollbarTrack),
ref: ref,
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(ScrollbarThumb, {
"aria-label": ariaLabel,
className: (0, _classnames["default"])(_ScrollbarTrackModule["default"].thumb, scrollbarTrackCss && scrollbarTrackCss.thumb),
"data-spotlight-ignore-restore": true,
onKeyDown: onKeyDown,
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: (0, _classnames["default"])(_ScrollbarTrackModule["default"].directionIndicator, _ScrollbarTrackModule["default"].backward)
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
className: (0, _classnames["default"])(_ScrollbarTrackModule["default"].directionIndicator, _ScrollbarTrackModule["default"].forward)
})]
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_AnnounceDecorator.Announce, {
ref: announceRef
}, "announce")]
}));
});
ScrollbarTrack.displayName = 'ScrollbarTrack';
ScrollbarTrack.propTypes = /** @lends sandstone/useScroll.ScrollbarTrack.prototype */{
/**
* Called when {@link sandstone/useScroll.ScrollbarTrack|ScrollbarTrack} is updated.
*
* @type {Function}
* @private
*/
cbAlertScrollbarTrack: _propTypes["default"].func,
/**
* `true` if scroll thumb is spottable.
*
* @type {Boolean|'byEnter'}
* @private
*/
focusableScrollbar: _propTypes["default"].oneOfType([_propTypes["default"].bool, _propTypes["default"].oneOf(['byEnter'])]),
/**
* Called when the user requests scroll.
*
* @type {Function}
* @private
*/
onInteractionForScroll: _propTypes["default"].func,
/**
* `true` if rtl, `false` if ltr.
*
* @type {Boolean}
* @private
*/
rtl: _propTypes["default"].bool,
/**
* Customizes the component by mapping the supplied collection of CSS class names to the
* corresponding internal elements and states of this component.
*
* The following classes are supported:
*
* * `scrollbarTrack` - The scrollbarTrack component class
* * `thumb` - The scrollbar thumb component class
*
* @type {Object}
* @public
*/
scrollbarTrackCss: _propTypes["default"].object,
/**
* `true` if vertical scroll, `false` if horizontal scroll.
*
* @type {Boolean}
* @private
*/
vertical: _propTypes["default"].bool
};
ScrollbarTrack.defaultProps = {
cbAlertScrollbarTrack: nop,
focusableScrollbar: false,
onInteractionForScroll: nop,
rtl: false,
vertical: true
};
var _default = exports["default"] = ScrollbarTrack;