@rive-app/canvas-lite 2.37.8 → 2.38.1

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.8","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.1","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 */
@@ -2560,14 +2560,15 @@ __webpack_require__.r(__webpack_exports__);
2560
2560
  /* harmony export */ CustomFileAssetLoaderWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.CustomFileAssetLoaderWrapper),
2561
2561
  /* harmony export */ FileAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FileAssetWrapper),
2562
2562
  /* harmony export */ FileFinalizer: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FileFinalizer),
2563
+ /* harmony export */ FocusSessionState: () => (/* reexport safe */ _registerKeyboardInteractions__WEBPACK_IMPORTED_MODULE_1__.FocusSessionState),
2563
2564
  /* harmony export */ FontAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FontAssetWrapper),
2564
2565
  /* harmony export */ FontWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.FontWrapper),
2565
2566
  /* harmony export */ ImageAssetWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.ImageAssetWrapper),
2566
2567
  /* harmony export */ ImageWrapper: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.ImageWrapper),
2568
+ /* harmony export */ KeyboardInteractions: () => (/* reexport safe */ _registerKeyboardInteractions__WEBPACK_IMPORTED_MODULE_1__.KeyboardInteractions),
2567
2569
  /* harmony export */ RiveFont: () => (/* reexport safe */ _riveFont__WEBPACK_IMPORTED_MODULE_4__.RiveFont),
2568
2570
  /* harmony export */ createFinalization: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.createFinalization),
2569
2571
  /* harmony export */ finalizationRegistry: () => (/* reexport safe */ _finalizationRegistry__WEBPACK_IMPORTED_MODULE_3__.finalizationRegistry),
2570
- /* harmony export */ registerKeyboardInteractions: () => (/* reexport safe */ _registerKeyboardInteractions__WEBPACK_IMPORTED_MODULE_1__.registerKeyboardInteractions),
2571
2572
  /* harmony export */ registerTouchInteractions: () => (/* reexport safe */ _registerTouchInteractions__WEBPACK_IMPORTED_MODULE_0__.registerTouchInteractions),
2572
2573
  /* harmony export */ sanitizeUrl: () => (/* reexport safe */ _sanitizeUrl__WEBPACK_IMPORTED_MODULE_2__.sanitizeUrl)
2573
2574
  /* harmony export */ });
@@ -2663,7 +2664,7 @@ var getClientCoordinates = function (event, isTouchScrollEnabled, enableMultiTou
2663
2664
  * the state machine pointer move/up/down functions based on cursor interaction
2664
2665
  */
2665
2666
  var registerTouchInteractions = function (_a) {
2666
- 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;
2667
2668
  if (!canvas ||
2668
2669
  !stateMachines.length ||
2669
2670
  !renderer ||
@@ -2806,6 +2807,8 @@ var registerTouchInteractions = function (_a) {
2806
2807
  var stateMachine = stateMachines_3[_c];
2807
2808
  _loop_3(stateMachine);
2808
2809
  }
2810
+ // Advance the state machine immediately so pointer down(s) takes effect synchronously
2811
+ advanceAndDrain(0);
2809
2812
  break;
2810
2813
  }
2811
2814
  // Pointer click released on the canvas
@@ -2820,6 +2823,8 @@ var registerTouchInteractions = function (_a) {
2820
2823
  var stateMachine = stateMachines_4[_d];
2821
2824
  _loop_4(stateMachine);
2822
2825
  }
2826
+ // Advance the state machine immediately so pointer up(s) takes effect synchronously
2827
+ advanceAndDrain(0);
2823
2828
  // Release the primary touch lock once that finger lifts so the next
2824
2829
  // touchstart can claim a new primary finger.
2825
2830
  if (!enableMultiTouch &&
@@ -2838,6 +2843,8 @@ var registerTouchInteractions = function (_a) {
2838
2843
  var stateMachine = stateMachines_5[_e];
2839
2844
  _loop_5(stateMachine);
2840
2845
  }
2846
+ // Advance the state machine immediately so pointer up(s) takes effect synchronously
2847
+ advanceAndDrain(0);
2841
2848
  break;
2842
2849
  }
2843
2850
  default:
@@ -2880,60 +2887,145 @@ var registerTouchInteractions = function (_a) {
2880
2887
 
2881
2888
  __webpack_require__.r(__webpack_exports__);
2882
2889
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2883
- /* harmony export */ registerKeyboardInteractions: () => (/* binding */ registerKeyboardInteractions)
2890
+ /* harmony export */ FocusSessionState: () => (/* binding */ FocusSessionState),
2891
+ /* harmony export */ KeyboardInteractions: () => (/* binding */ KeyboardInteractions)
2884
2892
  /* harmony export */ });
2885
2893
  /**
2886
- * Registers focus and tab-traversal event handlers on the canvas to route
2887
- * Tab/Shift+Tab to the active Rive state machine's focus manager.
2894
+ * Tracks the relationship between the canvas's DOM focus and Rive's internal focus for the
2895
+ * current focus session.
2888
2896
  *
2889
- * Mirrors registerTouchInteractions for pointer events.
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.
2890
2905
  *
2891
- * Returns a cleanup function that removes all registered event listeners,
2892
- * or null if the setup conditions are not met.
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).
2893
2909
  */
2894
- var registerKeyboardInteractions = function (_a) {
2895
- var canvas = _a.canvas, stateMachine = _a.stateMachine, rive = _a.rive, hasFocusNodes = _a.hasFocusNodes;
2896
- if (!canvas ||
2897
- !stateMachine ||
2898
- !rive ||
2899
- typeof window === "undefined") {
2900
- return null;
2901
- }
2902
- // Work off an assumption of a single state machine
2903
- var mainSm = stateMachine;
2904
- var canvasHasFocus = false;
2905
- var onCanvasFocus = function (_event) {
2906
- canvasHasFocus = true;
2907
- };
2908
- var onCanvasBlur = function (_event) {
2909
- canvasHasFocus = false;
2910
- };
2911
- var onKeyDown = function (event) {
2912
- if (!canvasHasFocus)
2913
- return;
2914
- if (event.code === "Tab" && hasFocusNodes) {
2915
- var forward = !event.shiftKey;
2916
- var focusMoved = forward ? mainSm.focusNext() : mainSm.focusPrevious();
2917
- if (focusMoved) {
2918
- // Keep Tab inside the canvas a Rive node received focus.
2919
- event.preventDefault();
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;
2920
2951
  }
2921
- else {
2922
- // No more traversable nodes — release Tab to the page.
2923
- // Since we're not preventing default, blur event will fire on the canvas
2924
- canvasHasFocus = false;
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
+ }
2925
2972
  }
2926
- }
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;
2927
2989
  };
2928
- canvas.addEventListener("focus", onCanvasFocus);
2929
- canvas.addEventListener("blur", onCanvasBlur);
2930
- canvas.addEventListener("keydown", onKeyDown);
2931
- return function () {
2932
- canvas.removeEventListener("focus", onCanvasFocus);
2933
- canvas.removeEventListener("blur", onCanvasBlur);
2934
- canvas.removeEventListener("keydown", onKeyDown);
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;
2935
2997
  };
2936
- };
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
+
2937
3029
 
2938
3030
 
2939
3031
  /***/ }),
@@ -3131,6 +3223,9 @@ var CustomFileAssetLoaderWrapper = /** @class */ (function () {
3131
3223
  else if (asset.isFont) {
3132
3224
  assetWrapper = new FontAssetWrapper(asset);
3133
3225
  }
3226
+ else {
3227
+ return false;
3228
+ }
3134
3229
  return this._assetLoaderCallback(assetWrapper, bytes);
3135
3230
  };
3136
3231
  return CustomFileAssetLoaderWrapper;
@@ -3770,6 +3865,7 @@ var StateMachine = /** @class */ (function () {
3770
3865
  this.inputs = [];
3771
3866
  this.instance = new runtime.StateMachineInstance(stateMachine, artboard);
3772
3867
  this.initInputs(runtime);
3868
+ this.hasFocusNodes = this.instance.hasFocusNodes();
3773
3869
  }
3774
3870
  Object.defineProperty(StateMachine.prototype, "name", {
3775
3871
  get: function () {
@@ -3865,6 +3961,19 @@ var StateMachine = /** @class */ (function () {
3865
3961
  this.instance.bindViewModelInstance(viewModelInstance.runtimeInstance);
3866
3962
  }
3867
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
+ };
3868
3977
  return StateMachine;
3869
3978
  }());
3870
3979
  // #endregion
@@ -4871,7 +4980,7 @@ var RiveFile = /** @class */ (function () {
4871
4980
  var Rive = /** @class */ (function () {
4872
4981
  function Rive(params) {
4873
4982
  var _this = this;
4874
- var _a, _b;
4983
+ var _a, _b, _c;
4875
4984
  // Tracks if a Rive file is loaded
4876
4985
  this.loaded = false;
4877
4986
  // Tracks if a Rive file is destroyed
@@ -4890,8 +4999,8 @@ var Rive = /** @class */ (function () {
4890
4999
  this.artboard = null;
4891
5000
  // place to clear up pointer/touch event listeners
4892
5001
  this.eventCleanup = null;
4893
- // place to clear up focus/keyboard event listeners
4894
- this.keyboardEventCleanup = null;
5002
+ // Manages keyboard and DOM-focus interactions for the canvas.
5003
+ this._keyboardInteractions = null;
4895
5004
  this.shouldDisableRiveListeners = false;
4896
5005
  this.automaticallyHandleEvents = false;
4897
5006
  this.dispatchPointerExit = true;
@@ -4929,6 +5038,10 @@ var Rive = /** @class */ (function () {
4929
5038
  this._viewModelInstance = null;
4930
5039
  this._dataEnums = null;
4931
5040
  this._tabIndex = null;
5041
+ this._prevHasFocus = false;
5042
+ this._focusOptions = {
5043
+ allowFocusInterrupt: false,
5044
+ };
4932
5045
  this.drawOptimization = DrawOptimizationOptions.DrawOnChanged;
4933
5046
  // When true, emits performance.mark/measure entries for load and render.
4934
5047
  this.enablePerfMarks = false;
@@ -4987,6 +5100,7 @@ var Rive = /** @class */ (function () {
4987
5100
  this.enablePerfMarks = !!params.enablePerfMarks;
4988
5101
  if (this.enablePerfMarks)
4989
5102
  _runtimeLoader__WEBPACK_IMPORTED_MODULE_1__.RuntimeLoader.enablePerfMarks = true;
5103
+ this._focusOptions = (_c = params.focusOptions) !== null && _c !== void 0 ? _c : this._focusOptions;
4990
5104
  // New event management system
4991
5105
  this.eventManager = new EventManager();
4992
5106
  if (params.onLoad)
@@ -5139,10 +5253,7 @@ var Rive = /** @class */ (function () {
5139
5253
  if (this.eventCleanup) {
5140
5254
  this.eventCleanup();
5141
5255
  }
5142
- if (this.keyboardEventCleanup) {
5143
- this.keyboardEventCleanup();
5144
- this.keyboardEventCleanup = null;
5145
- }
5256
+ this.cleanupKeyboardInteractions();
5146
5257
  if (!this.shouldDisableRiveListeners) {
5147
5258
  var playingStateMachines = this.animator.stateMachines.filter(function (sm) { return sm.playing; });
5148
5259
  var activeStateMachines = playingStateMachines
@@ -5167,12 +5278,11 @@ var Rive = /** @class */ (function () {
5167
5278
  dispatchPointerExit: dispatchPointerExit,
5168
5279
  enableMultiTouch: enableMultiTouch,
5169
5280
  layoutScaleFactor: this._layout.layoutScaleFactor,
5281
+ advanceAndDrain: this.advanceAndReportChanges.bind(this)
5170
5282
  });
5171
5283
  // Wire up keyboard interactions for state machines that have focus nodes.
5172
5284
  // hasFocusNodes — unified focus tree check, gates tab traversal
5173
- var smWithFocusNodes = playingStateMachines
5174
- .filter(function (sm) { return sm.instance.hasFocusNodes(); })
5175
- .map(function (sm) { return sm.instance; });
5285
+ var smWithFocusNodes = playingStateMachines.filter(function (sm) { return sm.hasFocusNodes; });
5176
5286
  if (smWithFocusNodes.length) {
5177
5287
  // Set the canvas as a tabbable element if there are any focus nodes.
5178
5288
  // Prefer the tabIndex param set by the user, otherwise use 0.
@@ -5182,15 +5292,22 @@ var Rive = /** @class */ (function () {
5182
5292
  if (currentCanvasTabIndex === -1 || isNaN(currentCanvasTabIndex)) {
5183
5293
  this.canvas.tabIndex = (this._tabIndex !== null ? this._tabIndex : 0);
5184
5294
  }
5185
- this.keyboardEventCleanup = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.registerKeyboardInteractions)({
5186
- canvas: this.canvas,
5187
- stateMachine: smWithFocusNodes[0], // work off assumption of single state machine
5188
- rive: this.runtime,
5189
- hasFocusNodes: smWithFocusNodes.length > 0,
5190
- });
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
+ }
5191
5302
  }
5192
5303
  }
5193
5304
  };
5305
+ Rive.prototype.cleanupKeyboardInteractions = function () {
5306
+ if (this._keyboardInteractions) {
5307
+ this._keyboardInteractions.cleanup();
5308
+ this._keyboardInteractions = null;
5309
+ }
5310
+ };
5194
5311
  /**
5195
5312
  * Remove Rive Listeners setup on the canvas
5196
5313
  */
@@ -5199,10 +5316,7 @@ var Rive = /** @class */ (function () {
5199
5316
  this.eventCleanup();
5200
5317
  this.eventCleanup = null;
5201
5318
  }
5202
- if (this.keyboardEventCleanup) {
5203
- this.keyboardEventCleanup();
5204
- this.keyboardEventCleanup = null;
5205
- }
5319
+ this.cleanupKeyboardInteractions();
5206
5320
  };
5207
5321
  /**
5208
5322
  * If the instance has audio and the system audio is not ready
@@ -5380,27 +5494,53 @@ var Rive = /** @class */ (function () {
5380
5494
  return changed;
5381
5495
  };
5382
5496
  /**
5383
- * Draw rendering loop; renders animation frames at the correct time interval.
5384
- * @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)
5385
5499
  */
5386
- Rive.prototype.draw = function (time, onSecond) {
5387
- var _a;
5388
- // Clear the frameRequestId, as we're now rendering a fresh frame
5389
- this.frameRequestId = null;
5390
- var before = performance.now();
5391
- // On the first pass, make sure lastTime has a valid value
5392
- if (!this.lastRenderTime) {
5393
- this.lastRenderTime = time;
5500
+ Rive.prototype.pollFocusState = function () {
5501
+ if (!this._keyboardInteractions) {
5502
+ this._prevHasFocus = false;
5503
+ return;
5394
5504
  }
5395
- // Handle the onSecond callback
5396
- this.renderSecondTimer += time - this.lastRenderTime;
5397
- if (this.renderSecondTimer > 5000) {
5398
- this.renderSecondTimer = 0;
5399
- 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;
5400
5509
  }
5401
- // Calculate the elapsed time between frames in seconds
5402
- var elapsedTime = (time - this.lastRenderTime) / 1000;
5403
- 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;
5404
5544
  // - Advance non-paused animations by the elapsed number of seconds
5405
5545
  // - Advance any animations that require scrubbing
5406
5546
  // - Advance to the first frame even when autoplay is false
@@ -5464,13 +5604,48 @@ var Rive = /** @class */ (function () {
5464
5604
  performance.mark("rive:sm-advance:end:f".concat(_perfFrame));
5465
5605
  performance.measure("rive:sm-advance:f".concat(_perfFrame), "rive:sm-advance:start:f".concat(_perfFrame), "rive:sm-advance:end:f".concat(_perfFrame));
5466
5606
  }
5467
- // stateMachine.instance.apply(this.artboard);
5468
5607
  }
5469
- // Once the animations have been applied to the artboard, advance it
5608
+ // For linear animations that have been applied to the artboard, advance it
5470
5609
  // by the elapsed time.
5471
5610
  if (this.animator.stateMachines.length == 0) {
5472
5611
  this.artboard.advance(elapsedTime);
5473
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);
5474
5649
  var renderer = this.renderer;
5475
5650
  // Do not draw on 0 canvas size
5476
5651
  if (!this._hasZeroSize) {
@@ -5508,12 +5683,6 @@ var Rive = /** @class */ (function () {
5508
5683
  this._needsRedraw = false;
5509
5684
  }
5510
5685
  }
5511
- // Check for any animations that looped
5512
- this.animator.handleLooping();
5513
- // Check for any state machines that had a state change
5514
- this.animator.handleStateChanges();
5515
- // Report advanced time
5516
- this.animator.handleAdvancing(elapsedTime);
5517
5686
  // Add duration to create frame to durations array
5518
5687
  this.frameCount++;
5519
5688
  var after = performance.now();
@@ -5523,7 +5692,6 @@ var Rive = /** @class */ (function () {
5523
5692
  this.frameTimes.shift();
5524
5693
  this.durations.shift();
5525
5694
  }
5526
- (_a = this._viewModelInstance) === null || _a === void 0 ? void 0 : _a.handleCallbacks();
5527
5695
  // Calling requestAnimationFrame will rerun draw() at the correct rate:
5528
5696
  // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations
5529
5697
  if (this.animator.isPlaying) {
@@ -5630,10 +5798,7 @@ var Rive = /** @class */ (function () {
5630
5798
  if (this.eventCleanup !== null) {
5631
5799
  this.eventCleanup();
5632
5800
  }
5633
- if (this.keyboardEventCleanup) {
5634
- this.keyboardEventCleanup();
5635
- this.keyboardEventCleanup = null;
5636
- }
5801
+ this.cleanupKeyboardInteractions();
5637
5802
  // Delete all animation and state machine instances
5638
5803
  this.stop();
5639
5804
  if (this.artboard) {
@@ -5702,10 +5867,7 @@ var Rive = /** @class */ (function () {
5702
5867
  if (this.eventCleanup) {
5703
5868
  this.eventCleanup();
5704
5869
  }
5705
- if (this.keyboardEventCleanup) {
5706
- this.keyboardEventCleanup();
5707
- this.keyboardEventCleanup = null;
5708
- }
5870
+ this.cleanupKeyboardInteractions();
5709
5871
  this.setupRiveListeners();
5710
5872
  this.startRendering();
5711
5873
  };
@@ -5723,10 +5885,7 @@ var Rive = /** @class */ (function () {
5723
5885
  if (this.eventCleanup) {
5724
5886
  this.eventCleanup();
5725
5887
  }
5726
- if (this.keyboardEventCleanup) {
5727
- this.keyboardEventCleanup();
5728
- this.keyboardEventCleanup = null;
5729
- }
5888
+ this.cleanupKeyboardInteractions();
5730
5889
  this.animator.pause(animationNames);
5731
5890
  };
5732
5891
  Rive.prototype.scrub = function (animationNames, value) {
@@ -5762,10 +5921,7 @@ var Rive = /** @class */ (function () {
5762
5921
  if (this.eventCleanup) {
5763
5922
  this.eventCleanup();
5764
5923
  }
5765
- if (this.keyboardEventCleanup) {
5766
- this.keyboardEventCleanup();
5767
- this.keyboardEventCleanup = null;
5768
- }
5924
+ this.cleanupKeyboardInteractions();
5769
5925
  };
5770
5926
  /**
5771
5927
  * Resets the animation
@@ -6516,6 +6672,14 @@ var Rive = /** @class */ (function () {
6516
6672
  var _a, _b;
6517
6673
  return (_b = (_a = this.riveFile) === null || _a === void 0 ? void 0 : _a.getDefaultBindableArtboard()) !== null && _b !== void 0 ? _b : null;
6518
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
+ };
6519
6683
  // Error message for missing source or buffer
6520
6684
  Rive.missingErrorMessage = "Rive source file or data buffer required";
6521
6685
  // Error message for removed rive file