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