@rive-app/canvas-lite 2.37.7 → 2.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/rive.js CHANGED
@@ -2546,7 +2546,7 @@ moduleRtn = da;
2546
2546
  /* 5 */
2547
2547
  /***/ ((module) => {
2548
2548
 
2549
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@rive-app/canvas-lite","version":"2.37.7","description":"A lite version of Rive\'s canvas based web api.","main":"rive.js","homepage":"https://rive.app","repository":{"type":"git","url":"https://github.com/rive-app/rive-wasm/tree/master/js"},"keywords":["rive","animation"],"author":"Rive","contributors":["Luigi Rosso <luigi@rive.app> (https://rive.app)","Maxwell Talbot <max@rive.app> (https://rive.app)","Arthur Vivian <arthur@rive.app> (https://rive.app)","Umberto Sonnino <umberto@rive.app> (https://rive.app)","Matthew Sullivan <matt.j.sullivan@gmail.com> (mailto:matt.j.sullivan@gmail.com)"],"license":"MIT","files":["rive.js","rive.js.map","rive.wasm","rive_fallback.wasm","rive.d.ts","rive_advanced.mjs.d.ts","runtimeLoader.d.ts","utils"],"typings":"rive.d.ts","dependencies":{},"browser":{"fs":false,"path":false}}');
2549
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@rive-app/canvas-lite","version":"2.38.0","description":"A lite version of Rive\'s canvas based web api.","main":"rive.js","homepage":"https://rive.app","repository":{"type":"git","url":"https://github.com/rive-app/rive-wasm/tree/master/js"},"keywords":["rive","animation"],"author":"Rive","contributors":["Luigi Rosso <luigi@rive.app> (https://rive.app)","Maxwell Talbot <max@rive.app> (https://rive.app)","Arthur Vivian <arthur@rive.app> (https://rive.app)","Umberto Sonnino <umberto@rive.app> (https://rive.app)","Matthew Sullivan <matt.j.sullivan@gmail.com> (mailto:matt.j.sullivan@gmail.com)"],"license":"MIT","files":["rive.js","rive.js.map","rive.wasm","rive_fallback.wasm","rive.d.ts","rive_advanced.mjs.d.ts","runtimeLoader.d.ts","utils"],"typings":"rive.d.ts","dependencies":{},"browser":{"fs":false,"path":false}}');
2550
2550
 
2551
2551
  /***/ }),
2552
2552
  /* 6 */
@@ -2554,26 +2554,30 @@ module.exports = /*#__PURE__*/JSON.parse('{"name":"@rive-app/canvas-lite","versi
2554
2554
 
2555
2555
  __webpack_require__.r(__webpack_exports__);
2556
2556
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2557
- /* harmony export */ AudioAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.AudioAssetWrapper),
2558
- /* harmony export */ AudioWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.AudioWrapper),
2559
- /* harmony export */ BLANK_URL: () => (/* reexport safe */ _sanitizeUrl__WEBPACK_IMPORTED_MODULE_1__.BLANK_URL),
2560
- /* harmony export */ CustomFileAssetLoaderWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.CustomFileAssetLoaderWrapper),
2561
- /* harmony export */ FileAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.FileAssetWrapper),
2562
- /* harmony export */ FileFinalizer: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.FileFinalizer),
2563
- /* harmony export */ FontAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.FontAssetWrapper),
2564
- /* harmony export */ FontWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.FontWrapper),
2565
- /* harmony export */ ImageAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.ImageAssetWrapper),
2566
- /* harmony export */ ImageWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.ImageWrapper),
2567
- /* harmony export */ RiveFont: () => (/* reexport safe */ _riveFont__WEBPACK_IMPORTED_MODULE_3__.RiveFont),
2568
- /* harmony export */ createFinalization: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.createFinalization),
2569
- /* harmony export */ finalizationRegistry: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__.finalizationRegistry),
2557
+ /* harmony export */ AudioAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.AudioAssetWrapper),
2558
+ /* harmony export */ AudioWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.AudioWrapper),
2559
+ /* harmony export */ BLANK_URL: () => (/* reexport safe */ _sanitizeUrl__WEBPACK_IMPORTED_MODULE_2__.BLANK_URL),
2560
+ /* harmony export */ CustomFileAssetLoaderWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.CustomFileAssetLoaderWrapper),
2561
+ /* harmony export */ FileAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FileAssetWrapper),
2562
+ /* harmony export */ FileFinalizer: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FileFinalizer),
2563
+ /* harmony export */ FocusSessionState: () => (/* reexport safe */ _registerKeyboardInteractions__WEBPACK_IMPORTED_MODULE_1__.FocusSessionState),
2564
+ /* harmony export */ FontAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FontAssetWrapper),
2565
+ /* harmony export */ FontWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FontWrapper),
2566
+ /* harmony export */ ImageAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.ImageAssetWrapper),
2567
+ /* harmony export */ ImageWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.ImageWrapper),
2568
+ /* harmony export */ KeyboardInteractions: () => (/* reexport safe */ _registerKeyboardInteractions__WEBPACK_IMPORTED_MODULE_1__.KeyboardInteractions),
2569
+ /* harmony export */ RiveFont: () => (/* reexport safe */ _riveFont__WEBPACK_IMPORTED_MODULE_4__.RiveFont),
2570
+ /* harmony export */ createFinalization: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.createFinalization),
2571
+ /* harmony export */ finalizationRegistry: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.finalizationRegistry),
2570
2572
  /* harmony export */ registerTouchInteractions: () => (/* reexport safe */ _registerTouchInteractions__WEBPACK_IMPORTED_MODULE_0__.registerTouchInteractions),
2571
- /* harmony export */ sanitizeUrl: () => (/* reexport safe */ _sanitizeUrl__WEBPACK_IMPORTED_MODULE_1__.sanitizeUrl)
2573
+ /* harmony export */ sanitizeUrl: () => (/* reexport safe */ _sanitizeUrl__WEBPACK_IMPORTED_MODULE_2__.sanitizeUrl)
2572
2574
  /* harmony export */ });
2573
2575
  /* harmony import */ var _registerTouchInteractions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7);
2574
- /* harmony import */ var _sanitizeUrl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
2575
- /* harmony import */ var _finalizationRegistry__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9);
2576
- /* harmony import */ var _riveFont__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
2576
+ /* harmony import */ var _registerKeyboardInteractions__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8);
2577
+ /* harmony import */ var _sanitizeUrl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9);
2578
+ /* harmony import */ var _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
2579
+ /* harmony import */ var _riveFont__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(11);
2580
+
2577
2581
 
2578
2582
 
2579
2583
 
@@ -2660,7 +2664,7 @@ var getClientCoordinates = function (event, isTouchScrollEnabled, enableMultiTou
2660
2664
  * the state machine pointer move/up/down functions based on cursor interaction
2661
2665
  */
2662
2666
  var registerTouchInteractions = function (_a) {
2663
- var canvas = _a.canvas, artboard = _a.artboard, _b = _a.stateMachines, stateMachines = _b === void 0 ? [] : _b, renderer = _a.renderer, rive = _a.rive, fit = _a.fit, alignment = _a.alignment, _c = _a.isTouchScrollEnabled, isTouchScrollEnabled = _c === void 0 ? false : _c, _d = _a.dispatchPointerExit, dispatchPointerExit = _d === void 0 ? true : _d, _e = _a.enableMultiTouch, enableMultiTouch = _e === void 0 ? false : _e, _f = _a.layoutScaleFactor, layoutScaleFactor = _f === void 0 ? 1.0 : _f;
2667
+ var canvas = _a.canvas, artboard = _a.artboard, _b = _a.stateMachines, stateMachines = _b === void 0 ? [] : _b, renderer = _a.renderer, rive = _a.rive, fit = _a.fit, alignment = _a.alignment, _c = _a.isTouchScrollEnabled, isTouchScrollEnabled = _c === void 0 ? false : _c, _d = _a.dispatchPointerExit, dispatchPointerExit = _d === void 0 ? true : _d, _e = _a.enableMultiTouch, enableMultiTouch = _e === void 0 ? false : _e, _f = _a.layoutScaleFactor, layoutScaleFactor = _f === void 0 ? 1.0 : _f, advanceAndDrain = _a.advanceAndDrain;
2664
2668
  if (!canvas ||
2665
2669
  !stateMachines.length ||
2666
2670
  !renderer ||
@@ -2803,6 +2807,8 @@ var registerTouchInteractions = function (_a) {
2803
2807
  var stateMachine = stateMachines_3[_c];
2804
2808
  _loop_3(stateMachine);
2805
2809
  }
2810
+ // Advance the state machine immediately so pointer down(s) takes effect synchronously
2811
+ advanceAndDrain(0);
2806
2812
  break;
2807
2813
  }
2808
2814
  // Pointer click released on the canvas
@@ -2817,6 +2823,8 @@ var registerTouchInteractions = function (_a) {
2817
2823
  var stateMachine = stateMachines_4[_d];
2818
2824
  _loop_4(stateMachine);
2819
2825
  }
2826
+ // Advance the state machine immediately so pointer up(s) takes effect synchronously
2827
+ advanceAndDrain(0);
2820
2828
  // Release the primary touch lock once that finger lifts so the next
2821
2829
  // touchstart can claim a new primary finger.
2822
2830
  if (!enableMultiTouch &&
@@ -2835,6 +2843,8 @@ var registerTouchInteractions = function (_a) {
2835
2843
  var stateMachine = stateMachines_5[_e];
2836
2844
  _loop_5(stateMachine);
2837
2845
  }
2846
+ // Advance the state machine immediately so pointer up(s) takes effect synchronously
2847
+ advanceAndDrain(0);
2838
2848
  break;
2839
2849
  }
2840
2850
  default:
@@ -2875,6 +2885,153 @@ var registerTouchInteractions = function (_a) {
2875
2885
  /* 8 */
2876
2886
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2877
2887
 
2888
+ __webpack_require__.r(__webpack_exports__);
2889
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2890
+ /* harmony export */ FocusSessionState: () => (/* binding */ FocusSessionState),
2891
+ /* harmony export */ KeyboardInteractions: () => (/* binding */ KeyboardInteractions)
2892
+ /* harmony export */ });
2893
+ /**
2894
+ * Tracks the relationship between the canvas's DOM focus and Rive's internal focus for the
2895
+ * current focus session.
2896
+ *
2897
+ * NotFocused — the canvas is not the active DOM element, or Rive entered and then released focus
2898
+ * internally this session. Either way the next Tab should move on to the next page
2899
+ * element, so Tab events are ignored.
2900
+ * EntryPending — the canvas has DOM focus but Rive holds no active focus node yet, and the next Tab should enter
2901
+ * the focus tree. This is the resting state for pointer-driven focus (a click on the
2902
+ * canvas), or an edge case for keyboard focus where initial focus action did not land on a focus node.
2903
+ * RiveFocused — a Rive node currently holds focus. Tab/Shift+Tab are routed to the Rive focus
2904
+ * manager and trapped inside the canvas until Rive notifies focus has ended.
2905
+ *
2906
+ * When keyboard focus lands on the canvas, onCanvasFocus reads the direction focus came from and
2907
+ * moves into the focus tree immediately, going straight to RiveFocused. EntryPending is only set via pointer focus (or keyboard focus
2908
+ * where focusNext()/focusPrevious() return false but respects tabindex).
2909
+ */
2910
+ var FocusSessionState;
2911
+ (function (FocusSessionState) {
2912
+ FocusSessionState["NotFocused"] = "notFocused";
2913
+ FocusSessionState["EntryPending"] = "entryPending";
2914
+ FocusSessionState["RiveFocused"] = "riveFocused";
2915
+ })(FocusSessionState || (FocusSessionState = {}));
2916
+ /**
2917
+ * Manages keyboard and DOM focus interactions for a Rive canvas.
2918
+ *
2919
+ * Tracks the canvas focus session state (focusSessionState) and routes
2920
+ * Tab/Shift+Tab to the Rive state machine's focus manager. Exposes shared
2921
+ * state as properties so the Rive render loop can read them directly.
2922
+ */
2923
+ var KeyboardInteractions = /** @class */ (function () {
2924
+ function KeyboardInteractions(_a) {
2925
+ var canvas = _a.canvas, stateMachine = _a.stateMachine, hasFocusNodes = _a.hasFocusNodes;
2926
+ var _this = this;
2927
+ this.focusSessionState = FocusSessionState.NotFocused;
2928
+ /**
2929
+ * Handles the canvas gaining browser focus. The behavior differs based on how focus was gained -
2930
+ *
2931
+ * Pointer-driven focus: the canvas now has focus but Rive holds nothing yet, so we move to EntryPending — this lets the
2932
+ * next Tab enter the focus tree even when the focus is pointer-driven
2933
+ *
2934
+ * Keyboard-driven focus: we enter the Rive focus tree immediately once canvas gains focus.
2935
+ * The direction is inferred from where focus came from: an element before the canvas in DOM order
2936
+ * means a forward Tab (focusNext), one after means a Shift+Tab (focusPrevious). :focus-visible
2937
+ * gates this so a click doesn't yank Rive focus to the first node on the focus event itself.
2938
+ */
2939
+ this.onCanvasFocus = function (event) {
2940
+ if (!_this.hasFocusNodes)
2941
+ return;
2942
+ if (_this.mainSm.focusState().hasFocus)
2943
+ return;
2944
+ _this.focusSessionState = FocusSessionState.EntryPending;
2945
+ // Pointer focus waits for the user's next Tab (handled in onKeyDown). Keyboard focus enters now.
2946
+ if (!_this.isKeyboardDrivenFocus())
2947
+ return;
2948
+ var forward = _this.cameFromBeforeCanvas(event.relatedTarget);
2949
+ if (forward ? _this.mainSm.focusNext() : _this.mainSm.focusPrevious()) {
2950
+ _this.focusSessionState = FocusSessionState.RiveFocused;
2951
+ }
2952
+ };
2953
+ this.onCanvasBlur = function (_event) {
2954
+ _this.focusSessionState = FocusSessionState.NotFocused;
2955
+ };
2956
+ this.onKeyDown = function (event) {
2957
+ if (_this.focusSessionState === FocusSessionState.NotFocused)
2958
+ return;
2959
+ if (event.code === "Tab" && _this.hasFocusNodes) {
2960
+ var forward = !event.shiftKey;
2961
+ var focusMoved = forward ? _this.mainSm.focusNext() : _this.mainSm.focusPrevious();
2962
+ if (focusMoved) {
2963
+ // A Rive node accepted focus — keep trapping Tab inside the canvas.
2964
+ _this.focusSessionState = FocusSessionState.RiveFocused;
2965
+ event.preventDefault();
2966
+ }
2967
+ else {
2968
+ // No more traversable nodes — release Tab to the page.
2969
+ // Set state immediately; onCanvasBlur will also fire naturally.
2970
+ _this.focusSessionState = FocusSessionState.NotFocused;
2971
+ }
2972
+ }
2973
+ };
2974
+ this.canvas = canvas;
2975
+ this.mainSm = stateMachine;
2976
+ this.hasFocusNodes = hasFocusNodes;
2977
+ canvas.addEventListener("focus", this.onCanvasFocus);
2978
+ canvas.addEventListener("blur", this.onCanvasBlur);
2979
+ canvas.addEventListener("keydown", this.onKeyDown);
2980
+ }
2981
+ /**
2982
+ * Set the FocusSessionState. Useful for invoking a Rive "blur" without actually blurring from the <canvas>. This
2983
+ * helps put the DOM focus state on the canvas rather than the <body>, so the user doesn't lose the spot in page navigation
2984
+ *
2985
+ * @param state FocusSessionState enum
2986
+ */
2987
+ KeyboardInteractions.prototype.setFocusSessionState = function (state) {
2988
+ this.focusSessionState = state;
2989
+ };
2990
+ /**
2991
+ * Called by pollFocusState on the Rive instance when it observes hasFocus=true. Rive acquired
2992
+ * focus internally (e.g. via a listener action or state transition) without a DOM focus event,
2993
+ * so mark the session RiveFocused.
2994
+ */
2995
+ KeyboardInteractions.prototype.notifyRiveFocused = function () {
2996
+ this.focusSessionState = FocusSessionState.RiveFocused;
2997
+ };
2998
+ /**
2999
+ * Whether the canvas currently matches :focus-visible — the browser's heuristic for keyboard-
3000
+ * (vs pointer-) driven focus. For older browser versions that don't support this selector, return false
3001
+ * so that we don't incorrectly assume pointer vs keyboard focus. Next tab would enter the focus tree in those edge cases.
3002
+ */
3003
+ KeyboardInteractions.prototype.isKeyboardDrivenFocus = function () {
3004
+ try {
3005
+ return this.canvas.matches(":focus-visible");
3006
+ }
3007
+ catch (_a) {
3008
+ return false;
3009
+ }
3010
+ };
3011
+ KeyboardInteractions.prototype.cameFromBeforeCanvas = function (from) {
3012
+ if (!from)
3013
+ return true;
3014
+ var position = this.canvas.compareDocumentPosition(from);
3015
+ if (position & Node.DOCUMENT_POSITION_PRECEDING)
3016
+ return true;
3017
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING)
3018
+ return false;
3019
+ return true;
3020
+ };
3021
+ KeyboardInteractions.prototype.cleanup = function () {
3022
+ this.canvas.removeEventListener("focus", this.onCanvasFocus);
3023
+ this.canvas.removeEventListener("blur", this.onCanvasBlur);
3024
+ this.canvas.removeEventListener("keydown", this.onKeyDown);
3025
+ };
3026
+ return KeyboardInteractions;
3027
+ }());
3028
+
3029
+
3030
+
3031
+ /***/ }),
3032
+ /* 9 */
3033
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
3034
+
2878
3035
  __webpack_require__.r(__webpack_exports__);
2879
3036
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2880
3037
  /* harmony export */ BLANK_URL: () => (/* binding */ BLANK_URL),
@@ -2925,7 +3082,7 @@ function sanitizeUrl(url) {
2925
3082
 
2926
3083
 
2927
3084
  /***/ }),
2928
- /* 9 */
3085
+ /* 10 */
2929
3086
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
2930
3087
 
2931
3088
  __webpack_require__.r(__webpack_exports__);
@@ -3066,6 +3223,9 @@ var CustomFileAssetLoaderWrapper = /** @class */ (function () {
3066
3223
  else if (asset.isFont) {
3067
3224
  assetWrapper = new FontAssetWrapper(asset);
3068
3225
  }
3226
+ else {
3227
+ return false;
3228
+ }
3069
3229
  return this._assetLoaderCallback(assetWrapper, bytes);
3070
3230
  };
3071
3231
  return CustomFileAssetLoaderWrapper;
@@ -3204,7 +3364,7 @@ var createFinalization = function (target, finalizable) {
3204
3364
 
3205
3365
 
3206
3366
  /***/ }),
3207
- /* 10 */
3367
+ /* 11 */
3208
3368
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
3209
3369
 
3210
3370
  __webpack_require__.r(__webpack_exports__);
@@ -3705,6 +3865,7 @@ var StateMachine = /** @class */ (function () {
3705
3865
  this.inputs = [];
3706
3866
  this.instance = new runtime.StateMachineInstance(stateMachine, artboard);
3707
3867
  this.initInputs(runtime);
3868
+ this.hasFocusNodes = this.instance.hasFocusNodes();
3708
3869
  }
3709
3870
  Object.defineProperty(StateMachine.prototype, "name", {
3710
3871
  get: function () {
@@ -3800,6 +3961,19 @@ var StateMachine = /** @class */ (function () {
3800
3961
  this.instance.bindViewModelInstance(viewModelInstance.runtimeInstance);
3801
3962
  }
3802
3963
  };
3964
+ /**
3965
+ * Get metadata about the state of focus if applicable for this state machine.
3966
+ * @returns FocusState - { hasFocus: boolean, expectsKeyboardInput: boolean }
3967
+ */
3968
+ StateMachine.prototype.focusState = function () {
3969
+ return this.instance.focusState();
3970
+ };
3971
+ /**
3972
+ * Clear focus from the Rive focus node tree.
3973
+ */
3974
+ StateMachine.prototype.clearFocus = function () {
3975
+ this.instance.clearFocus();
3976
+ };
3803
3977
  return StateMachine;
3804
3978
  }());
3805
3979
  // #endregion
@@ -4806,7 +4980,7 @@ var RiveFile = /** @class */ (function () {
4806
4980
  var Rive = /** @class */ (function () {
4807
4981
  function Rive(params) {
4808
4982
  var _this = this;
4809
- var _a, _b;
4983
+ var _a, _b, _c;
4810
4984
  // Tracks if a Rive file is loaded
4811
4985
  this.loaded = false;
4812
4986
  // Tracks if a Rive file is destroyed
@@ -4823,8 +4997,10 @@ var Rive = /** @class */ (function () {
4823
4997
  this.readyForPlaying = false;
4824
4998
  // Runtime artboard
4825
4999
  this.artboard = null;
4826
- // place to clear up event listeners
5000
+ // place to clear up pointer/touch event listeners
4827
5001
  this.eventCleanup = null;
5002
+ // Manages keyboard and DOM-focus interactions for the canvas.
5003
+ this._keyboardInteractions = null;
4828
5004
  this.shouldDisableRiveListeners = false;
4829
5005
  this.automaticallyHandleEvents = false;
4830
5006
  this.dispatchPointerExit = true;
@@ -4852,8 +5028,20 @@ var Rive = /** @class */ (function () {
4852
5028
  this._audioEventListener = null;
4853
5029
  // draw method bound to the class
4854
5030
  this._boundDraw = null;
5031
+ // Page visibility handler — prevents state machine advancing / rAF from being invoked with large time delta
5032
+ // when the browser tab is switched back to after being hidden.
5033
+ this._pageVisibilityHandler = null;
5034
+ // True only when the page visibility handler itself cancelled an active frame.
5035
+ // Set by stopRendering(), cleared by startRendering(). Prevents the
5036
+ // visibilitychange handler from restarting a rendering loop the caller intentionally stopped.
5037
+ this._explicitlyStoppedRendering = false;
4855
5038
  this._viewModelInstance = null;
4856
5039
  this._dataEnums = null;
5040
+ this._tabIndex = null;
5041
+ this._prevHasFocus = false;
5042
+ this._focusOptions = {
5043
+ allowFocusInterrupt: false,
5044
+ };
4857
5045
  this.drawOptimization = DrawOptimizationOptions.DrawOnChanged;
4858
5046
  // When true, emits performance.mark/measure entries for load and render.
4859
5047
  this.enablePerfMarks = false;
@@ -4874,12 +5062,18 @@ var Rive = /** @class */ (function () {
4874
5062
  _this.resizeToCanvas();
4875
5063
  }
4876
5064
  };
5065
+ // Tracks the current animation frame request
5066
+ this.frameRequestId = null;
4877
5067
  /**
4878
5068
  * Used be draw to track when a second of active rendering time has passed.
4879
5069
  * Used for debugging purposes
4880
5070
  */
4881
5071
  this.renderSecondTimer = 0;
4882
5072
  this._boundDraw = this.draw.bind(this);
5073
+ if (typeof document !== 'undefined') {
5074
+ this._pageVisibilityHandler = this._onPageVisibilityChange.bind(this);
5075
+ document.addEventListener('visibilitychange', this._pageVisibilityHandler);
5076
+ }
4883
5077
  this.canvas = params.canvas;
4884
5078
  if (params.canvas.constructor === HTMLCanvasElement) {
4885
5079
  this._observed = observers.add(this.canvas, this.onCanvasResize);
@@ -4906,6 +5100,7 @@ var Rive = /** @class */ (function () {
4906
5100
  this.enablePerfMarks = !!params.enablePerfMarks;
4907
5101
  if (this.enablePerfMarks)
4908
5102
  _runtimeLoader__WEBPACK_IMPORTED_MODULE_1__.RuntimeLoader.enablePerfMarks = true;
5103
+ this._focusOptions = (_c = params.focusOptions) !== null && _c !== void 0 ? _c : this._focusOptions;
4909
5104
  // New event management system
4910
5105
  this.eventManager = new EventManager();
4911
5106
  if (params.onLoad)
@@ -4958,6 +5153,7 @@ var Rive = /** @class */ (function () {
4958
5153
  stateMachines: params.stateMachines,
4959
5154
  artboard: params.artboard,
4960
5155
  useOffscreenRenderer: params.useOffscreenRenderer,
5156
+ tabIndex: params.tabIndex,
4961
5157
  });
4962
5158
  }
4963
5159
  Object.defineProperty(Rive.prototype, "viewModelCount", {
@@ -4979,13 +5175,14 @@ var Rive = /** @class */ (function () {
4979
5175
  // Initializes the Rive object either from constructor or load()
4980
5176
  Rive.prototype.init = function (_a) {
4981
5177
  var _this = this;
4982
- var src = _a.src, buffer = _a.buffer, riveFile = _a.riveFile, animations = _a.animations, stateMachines = _a.stateMachines, artboard = _a.artboard, _b = _a.autoplay, autoplay = _b === void 0 ? false : _b, _c = _a.useOffscreenRenderer, useOffscreenRenderer = _c === void 0 ? false : _c, _d = _a.autoBind, autoBind = _d === void 0 ? false : _d;
5178
+ var src = _a.src, buffer = _a.buffer, riveFile = _a.riveFile, animations = _a.animations, stateMachines = _a.stateMachines, artboard = _a.artboard, _b = _a.autoplay, autoplay = _b === void 0 ? false : _b, _c = _a.useOffscreenRenderer, useOffscreenRenderer = _c === void 0 ? false : _c, _d = _a.autoBind, autoBind = _d === void 0 ? false : _d, tabIndex = _a.tabIndex;
4983
5179
  if (this.destroyed) {
4984
5180
  return;
4985
5181
  }
4986
5182
  this.src = src;
4987
5183
  this.buffer = buffer;
4988
5184
  this.riveFile = riveFile;
5185
+ this._tabIndex = tabIndex !== null && tabIndex !== void 0 ? tabIndex : null;
4989
5186
  // If no source file url specified, it's a bust
4990
5187
  if (!this.src && !this.buffer && !this.riveFile) {
4991
5188
  throw new RiveError(Rive.missingErrorMessage);
@@ -5056,9 +5253,11 @@ var Rive = /** @class */ (function () {
5056
5253
  if (this.eventCleanup) {
5057
5254
  this.eventCleanup();
5058
5255
  }
5256
+ this.cleanupKeyboardInteractions();
5059
5257
  if (!this.shouldDisableRiveListeners) {
5060
- var activeStateMachines = (this.animator.stateMachines || [])
5061
- .filter(function (sm) { return sm.playing && _this.runtime.hasListeners(sm.instance); })
5258
+ var playingStateMachines = this.animator.stateMachines.filter(function (sm) { return sm.playing; });
5259
+ var activeStateMachines = playingStateMachines
5260
+ .filter(function (sm) { return _this.runtime.hasListeners(sm.instance); })
5062
5261
  .map(function (sm) { return sm.instance; });
5063
5262
  var touchScrollEnabledOption = this.isTouchScrollEnabled;
5064
5263
  var dispatchPointerExit = this.dispatchPointerExit;
@@ -5079,7 +5278,34 @@ var Rive = /** @class */ (function () {
5079
5278
  dispatchPointerExit: dispatchPointerExit,
5080
5279
  enableMultiTouch: enableMultiTouch,
5081
5280
  layoutScaleFactor: this._layout.layoutScaleFactor,
5281
+ advanceAndDrain: this.advanceAndReportChanges.bind(this)
5082
5282
  });
5283
+ // Wire up keyboard interactions for state machines that have focus nodes.
5284
+ // hasFocusNodes — unified focus tree check, gates tab traversal
5285
+ var smWithFocusNodes = playingStateMachines.filter(function (sm) { return sm.hasFocusNodes; });
5286
+ if (smWithFocusNodes.length) {
5287
+ // Set the canvas as a tabbable element if there are any focus nodes.
5288
+ // Prefer the tabIndex param set by the user, otherwise use 0.
5289
+ // But do not override any explicit tabIndex already set on the canvas, if any.
5290
+ var currentCanvasTabIndex = this.canvas.tabIndex;
5291
+ // By default, canvas elements have a tabIndex of -1
5292
+ if (currentCanvasTabIndex === -1 || isNaN(currentCanvasTabIndex)) {
5293
+ this.canvas.tabIndex = (this._tabIndex !== null ? this._tabIndex : 0);
5294
+ }
5295
+ if (typeof window !== "undefined") {
5296
+ this._keyboardInteractions = new _utils__WEBPACK_IMPORTED_MODULE_2__.KeyboardInteractions({
5297
+ canvas: this.canvas,
5298
+ stateMachine: smWithFocusNodes[0].instance, // work off assumption of single state machine
5299
+ hasFocusNodes: true,
5300
+ });
5301
+ }
5302
+ }
5303
+ }
5304
+ };
5305
+ Rive.prototype.cleanupKeyboardInteractions = function () {
5306
+ if (this._keyboardInteractions) {
5307
+ this._keyboardInteractions.cleanup();
5308
+ this._keyboardInteractions = null;
5083
5309
  }
5084
5310
  };
5085
5311
  /**
@@ -5090,6 +5316,7 @@ var Rive = /** @class */ (function () {
5090
5316
  this.eventCleanup();
5091
5317
  this.eventCleanup = null;
5092
5318
  }
5319
+ this.cleanupKeyboardInteractions();
5093
5320
  };
5094
5321
  /**
5095
5322
  * If the instance has audio and the system audio is not ready
@@ -5267,27 +5494,53 @@ var Rive = /** @class */ (function () {
5267
5494
  return changed;
5268
5495
  };
5269
5496
  /**
5270
- * Draw rendering loop; renders animation frames at the correct time interval.
5271
- * @param time the time at which to render a frame
5497
+ * Poll focus state each frame to see if we should focus/blur the canvas in case
5498
+ * Rive internally updated focus outside of user interaction (e.g., via listener action)
5272
5499
  */
5273
- Rive.prototype.draw = function (time, onSecond) {
5274
- var _a;
5275
- // Clear the frameRequestId, as we're now rendering a fresh frame
5276
- this.frameRequestId = null;
5277
- var before = performance.now();
5278
- // On the first pass, make sure lastTime has a valid value
5279
- if (!this.lastRenderTime) {
5280
- this.lastRenderTime = time;
5500
+ Rive.prototype.pollFocusState = function () {
5501
+ if (!this._keyboardInteractions) {
5502
+ this._prevHasFocus = false;
5503
+ return;
5281
5504
  }
5282
- // Handle the onSecond callback
5283
- this.renderSecondTimer += time - this.lastRenderTime;
5284
- if (this.renderSecondTimer > 5000) {
5285
- this.renderSecondTimer = 0;
5286
- onSecond === null || onSecond === void 0 ? void 0 : onSecond();
5505
+ var activeSm = this.animator.stateMachines.find(function (sm) { return sm.playing && sm.hasFocusNodes; }); // work off assumption of single state machine
5506
+ if (!activeSm) {
5507
+ this._prevHasFocus = false;
5508
+ return;
5287
5509
  }
5288
- // Calculate the elapsed time between frames in seconds
5289
- var elapsedTime = (time - this.lastRenderTime) / 1000;
5290
- this.lastRenderTime = time;
5510
+ if (this.canvas instanceof HTMLCanvasElement) {
5511
+ var hasFocus = activeSm.focusState().hasFocus;
5512
+ if (hasFocus) {
5513
+ // Rive has an active focus node. Mark the session RiveFocused so Tab stays
5514
+ // trapped and a later internal release (hasFocus true → false) is detected.
5515
+ this._keyboardInteractions.notifyRiveFocused();
5516
+ // Only steal DOM focus on the false→true transition. If hasFocus stays
5517
+ // true across frames and the user clicks away, do not re-focus the canvas again.
5518
+ if (!this._prevHasFocus) {
5519
+ if (this.canvas !== document.activeElement && this._focusOptions.allowFocusInterrupt) {
5520
+ this.canvas.focus();
5521
+ }
5522
+ this._prevHasFocus = true;
5523
+ }
5524
+ return;
5525
+ }
5526
+ this._prevHasFocus = false;
5527
+ // hasFocus is false — only act when Rive previously held focus and released it internally
5528
+ // (state change clears focus). Release the DOM Tab trap so the next Tab moves to the next
5529
+ // page element. EntryPending and NotFocused cases are intentional no-ops — EntryPending in
5530
+ // particular must stay in its state (a click awaiting its first Tab) rather than be reset here.
5531
+ if (this._keyboardInteractions.focusSessionState === _utils__WEBPACK_IMPORTED_MODULE_2__.FocusSessionState.RiveFocused) {
5532
+ this._keyboardInteractions.setFocusSessionState(_utils__WEBPACK_IMPORTED_MODULE_2__.FocusSessionState.NotFocused);
5533
+ }
5534
+ }
5535
+ };
5536
+ /**
5537
+ * Handles important sequence of reporting Rive events, advancing the state machine or animation, and invoking various callbacks
5538
+ * due to state changes, view model property changes, etc.
5539
+ *
5540
+ * @param elapsedTime time to advance the state machine by
5541
+ */
5542
+ Rive.prototype.advanceAndReportChanges = function (elapsedTime) {
5543
+ var _a;
5291
5544
  // - Advance non-paused animations by the elapsed number of seconds
5292
5545
  // - Advance any animations that require scrubbing
5293
5546
  // - Advance to the first frame even when autoplay is false
@@ -5351,13 +5604,48 @@ var Rive = /** @class */ (function () {
5351
5604
  performance.mark("rive:sm-advance:end:f".concat(_perfFrame));
5352
5605
  performance.measure("rive:sm-advance:f".concat(_perfFrame), "rive:sm-advance:start:f".concat(_perfFrame), "rive:sm-advance:end:f".concat(_perfFrame));
5353
5606
  }
5354
- // stateMachine.instance.apply(this.artboard);
5355
5607
  }
5356
- // Once the animations have been applied to the artboard, advance it
5608
+ // For linear animations that have been applied to the artboard, advance it
5357
5609
  // by the elapsed time.
5358
5610
  if (this.animator.stateMachines.length == 0) {
5359
5611
  this.artboard.advance(elapsedTime);
5360
5612
  }
5613
+ // Check for any animations that looped
5614
+ this.animator.handleLooping();
5615
+ // Check for any state machines that had a state change
5616
+ this.animator.handleStateChanges();
5617
+ // Report advanced time
5618
+ this.animator.handleAdvancing(elapsedTime);
5619
+ // Poll focus state to see whether or not to blur or pull up a virtual keyboard for any change to a text input node.
5620
+ this.pollFocusState();
5621
+ // Handle callbacks for view model property changes
5622
+ (_a = this._viewModelInstance) === null || _a === void 0 ? void 0 : _a.handleCallbacks();
5623
+ };
5624
+ /**
5625
+ * Draw rendering loop; renders animation frames at the correct time interval.
5626
+ * @param time the time at which to render a frame
5627
+ */
5628
+ Rive.prototype.draw = function (time, onSecond) {
5629
+ // Clear the frameRequestId, as we're now rendering a fresh frame
5630
+ this.frameRequestId = null;
5631
+ var before = performance.now();
5632
+ // Instrument the first 3 frames so the Performance timeline shows precise
5633
+ // per-call latency for advance, draw, and flush without polluting the trace.
5634
+ var _perfFrame = this.enablePerfMarks && this.frameCount < 3 ? this.frameCount : -1;
5635
+ // On the first pass, make sure lastTime has a valid value
5636
+ if (!this.lastRenderTime) {
5637
+ this.lastRenderTime = time;
5638
+ }
5639
+ // Handle the onSecond callback
5640
+ this.renderSecondTimer += time - this.lastRenderTime;
5641
+ if (this.renderSecondTimer > 5000) {
5642
+ this.renderSecondTimer = 0;
5643
+ onSecond === null || onSecond === void 0 ? void 0 : onSecond();
5644
+ }
5645
+ // Calculate the elapsed time between frames in seconds
5646
+ var elapsedTime = (time - this.lastRenderTime) / 1000;
5647
+ this.lastRenderTime = time;
5648
+ this.advanceAndReportChanges(elapsedTime);
5361
5649
  var renderer = this.renderer;
5362
5650
  // Do not draw on 0 canvas size
5363
5651
  if (!this._hasZeroSize) {
@@ -5395,12 +5683,6 @@ var Rive = /** @class */ (function () {
5395
5683
  this._needsRedraw = false;
5396
5684
  }
5397
5685
  }
5398
- // Check for any animations that looped
5399
- this.animator.handleLooping();
5400
- // Check for any state machines that had a state change
5401
- this.animator.handleStateChanges();
5402
- // Report advanced time
5403
- this.animator.handleAdvancing(elapsedTime);
5404
5686
  // Add duration to create frame to durations array
5405
5687
  this.frameCount++;
5406
5688
  var after = performance.now();
@@ -5410,7 +5692,6 @@ var Rive = /** @class */ (function () {
5410
5692
  this.frameTimes.shift();
5411
5693
  this.durations.shift();
5412
5694
  }
5413
- (_a = this._viewModelInstance) === null || _a === void 0 ? void 0 : _a.handleCallbacks();
5414
5695
  // Calling requestAnimationFrame will rerun draw() at the correct rate:
5415
5696
  // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations
5416
5697
  if (this.animator.isPlaying) {
@@ -5489,6 +5770,10 @@ var Rive = /** @class */ (function () {
5489
5770
  audioManager.remove(this._audioEventListener);
5490
5771
  this._audioEventListener = null;
5491
5772
  }
5773
+ if (this._pageVisibilityHandler) {
5774
+ document.removeEventListener('visibilitychange', this._pageVisibilityHandler);
5775
+ this._pageVisibilityHandler = null;
5776
+ }
5492
5777
  (_b = this._viewModelInstance) === null || _b === void 0 ? void 0 : _b.cleanup();
5493
5778
  this._viewModelInstance = null;
5494
5779
  this._dataEnums = null;
@@ -5513,6 +5798,7 @@ var Rive = /** @class */ (function () {
5513
5798
  if (this.eventCleanup !== null) {
5514
5799
  this.eventCleanup();
5515
5800
  }
5801
+ this.cleanupKeyboardInteractions();
5516
5802
  // Delete all animation and state machine instances
5517
5803
  this.stop();
5518
5804
  if (this.artboard) {
@@ -5581,6 +5867,7 @@ var Rive = /** @class */ (function () {
5581
5867
  if (this.eventCleanup) {
5582
5868
  this.eventCleanup();
5583
5869
  }
5870
+ this.cleanupKeyboardInteractions();
5584
5871
  this.setupRiveListeners();
5585
5872
  this.startRendering();
5586
5873
  };
@@ -5598,6 +5885,7 @@ var Rive = /** @class */ (function () {
5598
5885
  if (this.eventCleanup) {
5599
5886
  this.eventCleanup();
5600
5887
  }
5888
+ this.cleanupKeyboardInteractions();
5601
5889
  this.animator.pause(animationNames);
5602
5890
  };
5603
5891
  Rive.prototype.scrub = function (animationNames, value) {
@@ -5633,6 +5921,7 @@ var Rive = /** @class */ (function () {
5633
5921
  if (this.eventCleanup) {
5634
5922
  this.eventCleanup();
5635
5923
  }
5924
+ this.cleanupKeyboardInteractions();
5636
5925
  };
5637
5926
  /**
5638
5927
  * Resets the animation
@@ -6092,6 +6381,7 @@ var Rive = /** @class */ (function () {
6092
6381
  * they would have been at if rendering had not been stopped.
6093
6382
  */
6094
6383
  Rive.prototype.stopRendering = function () {
6384
+ this._explicitlyStoppedRendering = true;
6095
6385
  if (this.loaded && this.frameRequestId) {
6096
6386
  if (this.runtime.cancelAnimationFrame) {
6097
6387
  this.runtime.cancelAnimationFrame(this.frameRequestId);
@@ -6107,6 +6397,7 @@ var Rive = /** @class */ (function () {
6107
6397
  * renderer is already active, then this will have zero effect.
6108
6398
  */
6109
6399
  Rive.prototype.startRendering = function () {
6400
+ this._explicitlyStoppedRendering = false;
6110
6401
  this.drawFrame();
6111
6402
  };
6112
6403
  Rive.prototype.scheduleRendering = function () {
@@ -6119,6 +6410,31 @@ var Rive = /** @class */ (function () {
6119
6410
  }
6120
6411
  }
6121
6412
  };
6413
+ /**
6414
+ * Called when document.visibilitychange fires (tab change, window minimize, etc.).
6415
+ * Cancels the rAF loop on hide and resets the time reference so that no accumulated time is
6416
+ * applied to state machines when the tab becomes visible again. This prevents state machine
6417
+ * advances with large time deltas when rAF starts up again.
6418
+ */
6419
+ Rive.prototype._onPageVisibilityChange = function () {
6420
+ var _a, _b;
6421
+ if (document.hidden) {
6422
+ if (this.frameRequestId !== null) {
6423
+ if ((_a = this.runtime) === null || _a === void 0 ? void 0 : _a.cancelAnimationFrame) {
6424
+ this.runtime.cancelAnimationFrame(this.frameRequestId);
6425
+ }
6426
+ else {
6427
+ cancelAnimationFrame(this.frameRequestId);
6428
+ }
6429
+ this.frameRequestId = null;
6430
+ }
6431
+ // Reset so the first resumed frame starts with elapsedTime === 0.
6432
+ this.lastRenderTime = 0;
6433
+ }
6434
+ else if (((_b = this.animator) === null || _b === void 0 ? void 0 : _b.isPlaying) && !this._explicitlyStoppedRendering) {
6435
+ this.scheduleRendering();
6436
+ }
6437
+ };
6122
6438
  /**
6123
6439
  * Enables frames-per-second (FPS) reporting for the runtime
6124
6440
  * If no callback is provided, Rive will append a fixed-position div at the top-right corner of
@@ -6356,6 +6672,14 @@ var Rive = /** @class */ (function () {
6356
6672
  var _a, _b;
6357
6673
  return (_b = (_a = this.riveFile) === null || _a === void 0 ? void 0 : _a.getDefaultBindableArtboard()) !== null && _b !== void 0 ? _b : null;
6358
6674
  };
6675
+ /**
6676
+ * Clear focus applicable to active state machines with focus nodes. Useful if users want to
6677
+ * reset focus state and behavior within the Rive graphic at any point (i.e. blurring off the canvas)
6678
+ */
6679
+ Rive.prototype.clearFocus = function () {
6680
+ var playingStateMachines = this.animator.stateMachines.filter(function (sm) { return sm.playing && sm.hasFocusNodes; });
6681
+ playingStateMachines.forEach(function (sm) { return sm.clearFocus(); });
6682
+ };
6359
6683
  // Error message for missing source or buffer
6360
6684
  Rive.missingErrorMessage = "Rive source file or data buffer required";
6361
6685
  // Error message for removed rive file