UNPKG

@enact/sandstone

Version:

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

345 lines (338 loc) 14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.SpriteBase = exports.Sprite = void 0; var _kind = _interopRequireDefault(require("@enact/core/kind")); var _resolution = require("@enact/ui/resolution"); var _propTypes = _interopRequireDefault(require("prop-types")); var _react = require("react"); var _Image = _interopRequireDefault(require("../Image")); var _SpriteModule = _interopRequireDefault(require("./Sprite.module.css")); var _jsxRuntime = require("react/jsx-runtime"); var _excluded = ["columns", "duration", "height", "iterations", "onSpriteAnimation", "orientation", "paused", "rows", "stopped", "src", "width"]; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 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; } 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); } /** * A "sprite" is an animated sequence of cells. * * Cells, like a film-strip, are pre-arranged in one or more rows and one or more columns. * This component steps through those cells to create an animation. * * Example: * ``` * <Sprite * src="images/sprite-sheet.png" * height={60} * width={60} * rows={5} * columns={10} * /> * ``` * * @module sandstone/Sprite * @exports Sprite */ var createKeyframe = function createKeyframe(_ref) { var dimension = _ref.dimension, axis = _ref.axis, vertical = _ref.vertical, offset = _ref.offset; var x = (0, _resolution.scaleToRem)(vertical ? axis : dimension); var y = (0, _resolution.scaleToRem)(vertical ? dimension : axis); var keyframe = { transform: "translate(".concat(x, ", ").concat(y, ")") }; if (offset != null) keyframe.offset = offset; return keyframe; }; /** * Renders a Sprite animation. * * @class Sprite * @memberof sandstone/Sprite * @ui * @public */ var SpriteBase = exports.SpriteBase = exports.Sprite = (0, _kind["default"])({ name: 'Sprite', functional: true, propTypes: /** @lends sandstone/Sprite.Sprite.prototype */{ /** * The amount of animation cells spread across the X (horizontal) axis. * * @type {Number} * @default 1 * @public */ columns: _propTypes["default"].number, /** * The length of the animation in milliseconds. * * @type {Number} * @default 1000 * @public */ duration: _propTypes["default"].number, /** * The height of a single cell in pixels. * * This value is scaled automatically based on the "base" screen resolution for * this theme. All measurements should be with respect to a 4k UHD display. * * @type {Number} * @default 120 * @public */ height: _propTypes["default"].number, /** * The number of times the animation should repeat. * * The JavaScript reserved word `Infinity` is a valid option here (set by default) that * means "repeat indefinitely". * * @type {Number} * @default Infinity * @public */ iterations: _propTypes["default"].number, /** * Sets the left distance that the first cell is from the top left corner. * * This can be useful if you have several sprite animations in one image file. * * This value is scaled automatically based on the "base" screen resolution for * this theme. All measurements should be with respect to a 4k UHD display. * * @type {Number} * @default 0 * @public */ offsetLeft: _propTypes["default"].number, /** * Sets the top distance that the first cell is from the top left corner. * * This can be useful if you have several sprite animations in one image file. * * This value is scaled automatically based on the "base" screen resolution for * this theme. All measurements should be with respect to a 4k UHD display. * * @type {Number} * @default 0 * @public */ offsetTop: _propTypes["default"].number, /** * Event callback for when animation events occur. * * This callback can be used for more fine-grained control of the sprite animation. * The arguments payload contains an object with the following keys: * * `animation`: the `animate` handle {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/animate} * * `playing`: boolean representing the "playing" vs "stopped" state * * `paused`: boolean representing whether the animation has paused * * Note: Playing and paused are handled separately, since a paused animation is * still in a playing state, while a stopped animation is both not paused and * not playing. * * @type {Function} * @public */ onSpriteAnimation: _propTypes["default"].func, /** * Sets the orientation of the frames on the sprite sheet (`src`). * * A horizontal setting would indicate that the cells are arranged left to right with the * next row starting below the first row. * A vertical setting would indicate that the cells are arranged top to bottom with the * next column starting to the right of the first column. * * @type {('horizontal'|'vertical')} * @default 'horizontal' * @public */ orientation: _propTypes["default"].oneOf(['horizontal', 'vertical']), /** * Pauses the animation, holding on the current frame. * * @type {Boolean} * @private */ paused: _propTypes["default"].bool, /** * The amount of animation cells spread across the Y (vertical) axis. * * @type {Number} * @default 1 * @public */ rows: _propTypes["default"].number, /** * The sprite-sheet image with all of the cells on it. * * @see {@link ui/Image.ImageBase.src} * @type {String|Object} * @public */ src: _propTypes["default"].oneOfType([_propTypes["default"].string, _propTypes["default"].object]), /** * Stops the animation from playing, resetting to the beginning. * * @type {Boolean} * @public */ stopped: _propTypes["default"].bool, /** * The width of a single cell in pixels. * * This value is scaled automatically based on the "base" screen resolution for * this theme. All measurements should be with respect to a 4k UHD display. * * @type {Number} * @default 120 * @public */ width: _propTypes["default"].number }, styles: { css: _SpriteModule["default"], className: 'sprite' }, computed: { style: function style(_ref2) { var _ref2$offsetTop = _ref2.offsetTop, offsetTop = _ref2$offsetTop === void 0 ? 0 : _ref2$offsetTop, _ref2$offsetLeft = _ref2.offsetLeft, offsetLeft = _ref2$offsetLeft === void 0 ? 0 : _ref2$offsetLeft, _ref2$rows = _ref2.rows, rows = _ref2$rows === void 0 ? 1 : _ref2$rows, _ref2$columns = _ref2.columns, columns = _ref2$columns === void 0 ? 1 : _ref2$columns, _ref2$height = _ref2.height, height = _ref2$height === void 0 ? 120 : _ref2$height, _ref2$width = _ref2.width, width = _ref2$width === void 0 ? 120 : _ref2$width, _style = _ref2.style; return _objectSpread(_objectSpread({}, _style), {}, { '--sand-sprite-offset-top': (0, _resolution.scaleToRem)(offsetTop), '--sand-sprite-offset-left': (0, _resolution.scaleToRem)(offsetLeft), '--sand-sprite-rows': rows, '--sand-sprite-columns': columns, '--sand-sprite-height': (0, _resolution.scaleToRem)(height), '--sand-sprite-width': (0, _resolution.scaleToRem)(width) }); } }, render: function render(_ref3) { var _ref3$columns = _ref3.columns, columns = _ref3$columns === void 0 ? 1 : _ref3$columns, _ref3$duration = _ref3.duration, duration = _ref3$duration === void 0 ? 1000 : _ref3$duration, _ref3$height = _ref3.height, height = _ref3$height === void 0 ? 120 : _ref3$height, _ref3$iterations = _ref3.iterations, iterations = _ref3$iterations === void 0 ? Infinity : _ref3$iterations, onSpriteAnimation = _ref3.onSpriteAnimation, _ref3$orientation = _ref3.orientation, orientation = _ref3$orientation === void 0 ? 'horizontal' : _ref3$orientation, _ref3$paused = _ref3.paused, paused = _ref3$paused === void 0 ? false : _ref3$paused, _ref3$rows = _ref3.rows, rows = _ref3$rows === void 0 ? 1 : _ref3$rows, stopped = _ref3.stopped, src = _ref3.src, _ref3$width = _ref3.width, width = _ref3$width === void 0 ? 120 : _ref3$width, rest = _objectWithoutProperties(_ref3, _excluded); delete rest.offsetTop; delete rest.offsetLeft; // eslint-disable-next-line react-hooks/rules-of-hooks var imageRef = (0, _react.useRef)(); // eslint-disable-next-line react-hooks/rules-of-hooks var animation = (0, _react.useRef)(); // eslint-disable-next-line react-hooks/rules-of-hooks var keyframes = (0, _react.useMemo)(function () { var framesets = []; var vertical = orientation === 'vertical'; // Orientation agnostic terms to generate keyframes var steps = vertical ? rows : columns; var sets = vertical ? columns : rows; var dimension = vertical ? height : width; var axis = vertical ? width : height; for (var i = 0; i < sets; i++) { var axisValue = i * axis * -1; var dimentionValue = (steps - 0) * dimension * -1; framesets.push(createKeyframe({ offset: i / sets, vertical: vertical, dimension: 0, axis: axisValue }), createKeyframe({ offset: (i + 1) / sets, vertical: vertical, dimension: dimentionValue, axis: axisValue })); } return framesets; }, [ // Only update if these change columns, height, orientation, rows, width]); // eslint-disable-next-line react-hooks/rules-of-hooks (0, _react.useLayoutEffect)(function () { if (imageRef && imageRef.current) { var node = imageRef.current; var frameCount = columns * rows; if (animation.current) { animation.current.cancel(); } animation.current = node.animate(keyframes, { easing: "steps(".concat(frameCount, ", end)"), duration: duration, iterations: iterations || Infinity }); // Playing and paused are handled separately, since a paused animation is // still in a playing state, while a stopped animation is both not paused and // not playing. var eventPayload = { type: 'onSpriteAnimation', animation: animation.current, value: 'testing', paused: false, playing: false }; if (stopped) { if (animation.current.pause) animation.current.pause(); } else if (paused) { if (animation.current.pause) animation.current.pause(); eventPayload.paused = true; eventPayload.playing = true; } else { if (animation.current.play) animation.current.play(); eventPayload.playing = true; } if (typeof onSpriteAnimation === 'function') { onSpriteAnimation(eventPayload); } } }, [ // Only update if these change columns, duration, iterations, keyframes, onSpriteAnimation, paused, rows, stopped]); return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", _objectSpread(_objectSpread({}, rest), {}, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Image["default"], { src: src, ref: imageRef, className: _SpriteModule["default"].image }) })); } }); SpriteBase.defaultPropValues = { iterations: Infinity }; var _default = exports["default"] = SpriteBase;