@sprucelabs/spruce-heartwood-utils 38.17.4 → 38.17.6

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.
Files changed (43) hide show
  1. package/README.md +117 -33
  2. package/build/app/SkillViewEmitter.d.ts +167 -0
  3. package/build/app/SkillViewEmitter.js +69 -0
  4. package/build/esm/__tests__/support/MockRemoteViewControllerFactory.js +13 -29
  5. package/build/esm/__tests__/support/heartwoodEventFaker.js +20 -31
  6. package/build/esm/__tests__/support/remoteVcAssert.js +51 -63
  7. package/build/esm/app/SkillViewEmitter.d.ts +167 -0
  8. package/build/esm/app/SkillViewEmitter.js +65 -0
  9. package/build/esm/components/DelayedPlacer.js +11 -15
  10. package/build/esm/components/Settings.js +1 -2
  11. package/build/esm/components/Sizer.js +12 -30
  12. package/build/esm/components/animation/DelayedPlacerExport.js +2 -14
  13. package/build/esm/components/animation/SimpleEmitter.js +3 -6
  14. package/build/esm/components/animation/SizerExport.js +6 -27
  15. package/build/esm/devices/HeartwoodDevice.js +34 -52
  16. package/build/esm/errors/SpruceError.js +1 -1
  17. package/build/esm/hooks/queueShow.js +6 -7
  18. package/build/esm/index-testing.d.ts +6 -0
  19. package/build/esm/index-testing.js +4 -0
  20. package/build/esm/index-web.d.ts +11 -0
  21. package/build/esm/index-web.js +7 -0
  22. package/build/esm/theming/ThemeManager.js +55 -82
  23. package/build/esm/theming/loadActiveThemeForOrg.js +6 -17
  24. package/build/esm/views/CardRegistrar.js +46 -58
  25. package/build/esm/views/RemoteViewControllerFactory.js +60 -76
  26. package/build/index-testing.d.ts +6 -0
  27. package/build/index-testing.js +15 -0
  28. package/build/index-web.d.ts +11 -0
  29. package/build/index-web.js +33 -0
  30. package/package.json +33 -14
  31. package/docs/animation/README.md +0 -1697
  32. package/docs/animation/animation-emitter.md +0 -78
  33. package/docs/animation/delayed-placer.md +0 -156
  34. package/docs/animation/queue-show.md +0 -309
  35. package/docs/animation/settings.md +0 -117
  36. package/docs/animation/size-util.md +0 -102
  37. package/docs/animation/sizer.md +0 -161
  38. package/docs/bundle-optimization.md +0 -100
  39. package/docs/conferenceStage/plan.md +0 -167
  40. package/docs/heartwood-utils.md +0 -709
  41. package/docs/theme_prompt.md +0 -76
  42. package/docs/utilities/getDeviceOrientation.md +0 -131
  43. package/docs/utilities/skillViewState.md +0 -140
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @sprucelabs/spruce-heartwood-utils
2
2
 
3
- Tools for building Spruce skills that integrate with Heartwood remote card loading, auto-logout control, animation primitives, and testing utilities.
3
+ Heartwood integration toolkit for Spruce skills. Use this package to load remote cards, register and render cross-skill views, apply shared theme behavior, drive animation/layout primitives, and test the full flow with built-in mocks.
4
4
 
5
5
  ---
6
6
 
@@ -14,16 +14,99 @@ This package is designed for use inside a Spruce skill. It expects `@sprucelabs/
14
14
 
15
15
  ---
16
16
 
17
+ ## Project Pitch
18
+
19
+ Building a Spruce experience usually means combining:
20
+ - browser/runtime view infrastructure
21
+ - test utilities for remote card/event flows
22
+ - animation and layout primitives used in Heartwood views
23
+
24
+ `@sprucelabs/spruce-heartwood-utils` packages those into one module with explicit entrypoints so you can keep browser bundles clean while still getting first-class testing helpers.
25
+
26
+ ---
27
+
28
+ ## What You Get
29
+
30
+ - Remote view controller infrastructure:
31
+ `RemoteViewControllerFactoryImpl`, `CardRegistrar`, shared remote VC types
32
+ - Theming and plugins:
33
+ `loadActiveThemeForOrg`, `AutoLogoutPlugin`
34
+ - Test harness pieces:
35
+ `remoteVcAssert`, `fakeGetViews`, `MockRemoteViewControllerFactory`, `SpyAutoLogoutPlugin`
36
+ - Animation/layout primitives:
37
+ `Sizer`, `DelayedPlacer`, queue/show helpers, emitters, settings utilities
38
+
39
+ ---
40
+
41
+ ## Import Paths
42
+
43
+ - `@sprucelabs/spruce-heartwood-utils/web` for browser-safe runtime imports (recommended for Vite/Bun/ESM apps)
44
+ - `@sprucelabs/spruce-heartwood-utils/testing` for test helpers and mocks
45
+ - `@sprucelabs/spruce-heartwood-utils` keeps the legacy mixed export surface for existing consumers
46
+
47
+ ---
48
+
49
+ ## Get Started
50
+
51
+ ### Web Only
52
+
53
+ Use this when you are shipping runtime/browser code and do not need test helpers in that code path.
54
+
55
+ ```ts
56
+ import {
57
+ CardRegistrar,
58
+ RemoteViewControllerFactoryImpl,
59
+ AutoLogoutPlugin,
60
+ loadActiveThemeForOrg,
61
+ Sizer,
62
+ SimpleEmitter,
63
+ } from '@sprucelabs/spruce-heartwood-utils/web'
64
+ ```
65
+
66
+ ### Tests Only
67
+
68
+ Use this in test suites where you need to fake remote views and assert event-driven card registration.
69
+
70
+ ```ts
71
+ import {
72
+ remoteVcAssert,
73
+ fakeGetViews,
74
+ MockRemoteViewControllerFactory,
75
+ SpyAutoLogoutPlugin,
76
+ } from '@sprucelabs/spruce-heartwood-utils/testing'
77
+ ```
78
+
79
+ ### Web + Tests
80
+
81
+ Use split imports so runtime code stays browser-safe while tests get all mocks/helpers.
82
+
83
+ ```ts
84
+ import {
85
+ CardRegistrar,
86
+ RemoteViewControllerFactoryImpl,
87
+ } from '@sprucelabs/spruce-heartwood-utils/web'
88
+ import {
89
+ remoteVcAssert,
90
+ MockRemoteViewControllerFactory,
91
+ } from '@sprucelabs/spruce-heartwood-utils/testing'
92
+ ```
93
+
94
+ ---
95
+
17
96
  ## Table of Contents
18
97
 
19
- 1. [Remote View Controllers](#remote-view-controllers)
20
- 2. [CardRegistrar](#cardregistrar)
21
- 3. [Types](#types)
22
- 4. [Theming](#theming)
23
- 5. [Plugins](#plugins)
24
- 6. [Test Utilities](#test-utilities)
25
- 7. [Device & Layout Utilities](#device--layout-utilities)
26
- 8. [Animation](#animation)
98
+ 1. [Project Pitch](#project-pitch)
99
+ 2. [What You Get](#what-you-get)
100
+ 3. [Import Paths](#import-paths)
101
+ 4. [Get Started](#get-started)
102
+ 5. [Remote View Controllers](#remote-view-controllers)
103
+ 6. [CardRegistrar](#cardregistrar)
104
+ 7. [Types](#types)
105
+ 8. [Theming](#theming)
106
+ 9. [Plugins](#plugins)
107
+ 10. [Test Utilities](#test-utilities)
108
+ 11. [Device & Layout Utilities](#device--layout-utilities)
109
+ 12. [Animation](#animation)
27
110
  - [Quick Start](#quick-start)
28
111
  - [Required CSS](#required-css)
29
112
  - [System Architecture](#system-architecture)
@@ -49,7 +132,7 @@ Fetches compiled ViewController source from the `heartwood.get-skill-views` even
49
132
  import {
50
133
  RemoteViewControllerFactoryImpl,
51
134
  RemoteViewControllerFactory,
52
- } from '@sprucelabs/spruce-heartwood-utils'
135
+ } from '@sprucelabs/spruce-heartwood-utils/web'
53
136
  ```
54
137
 
55
138
  **Injecting a mock factory in tests:**
@@ -77,7 +160,7 @@ const vc = await remoteVcFactory.RemoteController(
77
160
  The interface that both `RemoteViewControllerFactoryImpl` and `MockRemoteViewControllerFactory` implement. Use this type for any field that may hold the real factory or a test mock:
78
161
 
79
162
  ```ts
80
- import { RemoteViewControllerFactory } from '@sprucelabs/spruce-heartwood-utils'
163
+ import { RemoteViewControllerFactory } from '@sprucelabs/spruce-heartwood-utils/web'
81
164
 
82
165
  private remoteVcFactory: RemoteViewControllerFactory
83
166
  ```
@@ -89,7 +172,7 @@ private remoteVcFactory: RemoteViewControllerFactory
89
172
  Options passed to `RemoteViewControllerFactoryImpl.Factory()`.
90
173
 
91
174
  ```ts
92
- import { RemoteFactoryOptions } from '@sprucelabs/spruce-heartwood-utils'
175
+ import { RemoteFactoryOptions } from '@sprucelabs/spruce-heartwood-utils/web'
93
176
 
94
177
  interface RemoteFactoryOptions {
95
178
  connectToApi: () => Promise<MercuryClient>
@@ -104,7 +187,7 @@ interface RemoteFactoryOptions {
104
187
  A narrowed subset of `ViewControllerFactory` containing only what the remote factory needs. Use this type when accepting or storing a factory reference to avoid a full `ViewControllerFactory` dependency:
105
188
 
106
189
  ```ts
107
- import { VcFactoryForRemoteFactory } from '@sprucelabs/spruce-heartwood-utils'
190
+ import { VcFactoryForRemoteFactory } from '@sprucelabs/spruce-heartwood-utils/web'
108
191
 
109
192
  private views: VcFactoryForRemoteFactory
110
193
  ```
@@ -121,7 +204,7 @@ import {
121
204
  CardRegistrarOptions,
122
205
  CardFetchOptions,
123
206
  EachCardHandler,
124
- } from '@sprucelabs/spruce-heartwood-utils'
207
+ } from '@sprucelabs/spruce-heartwood-utils/web'
125
208
  ```
126
209
 
127
210
  ### `CardRegistrar.Registrar(options)`
@@ -203,7 +286,7 @@ type CardFetchOptions<Contract, Name> = {
203
286
  The shape of a card loaded from another skill. Extends `ViewController<Card>` with an optional `load()` method so you can forward load arguments after the card is rendered.
204
287
 
205
288
  ```ts
206
- import { RemoteDashboardCard } from '@sprucelabs/spruce-heartwood-utils'
289
+ import { RemoteDashboardCard } from '@sprucelabs/spruce-heartwood-utils/web'
207
290
 
208
291
  interface RemoteDashboardCard extends ViewController<Card> {
209
292
  load?(options: SkillViewControllerLoadOptions): Promise<void>
@@ -235,7 +318,7 @@ cards: [
235
318
  Fetches the active Heartwood theme for an organization so your skill can apply the same visual style.
236
319
 
237
320
  ```ts
238
- import { loadActiveThemeForOrg } from '@sprucelabs/spruce-heartwood-utils'
321
+ import { loadActiveThemeForOrg } from '@sprucelabs/spruce-heartwood-utils/web'
239
322
  ```
240
323
 
241
324
  **Signature:**
@@ -264,7 +347,7 @@ const theme = await loadActiveThemeForOrg(client, organizationId)
264
347
  Sends `enableAutoLogout` / `disableAutoLogout` commands to the native Heartwood device layer. Register it with your skill's `ViewControllerFactory` to give your skill views control over session timeout behavior.
265
348
 
266
349
  ```ts
267
- import { AutoLogoutPlugin } from '@sprucelabs/spruce-heartwood-utils'
350
+ import { AutoLogoutPlugin } from '@sprucelabs/spruce-heartwood-utils/web'
268
351
 
269
352
  const plugin = factory.BuildPlugin(AutoLogoutPlugin)
270
353
 
@@ -279,7 +362,7 @@ plugin.disableAutoLogout() // cancel a pending auto-logout
279
362
  Use this type when you want to reference the plugin without coupling to the concrete class — for example, when declaring a field that holds either the real plugin or a spy:
280
363
 
281
364
  ```ts
282
- import type { AutoLogoutViewPlugin } from '@sprucelabs/spruce-heartwood-utils'
365
+ import type { AutoLogoutViewPlugin } from '@sprucelabs/spruce-heartwood-utils/web'
283
366
 
284
367
  // Field declaration — works with both AutoLogoutPlugin and SpyAutoLogoutPlugin:
285
368
  private autoLogoutPlugin: AutoLogoutViewPlugin
@@ -301,7 +384,7 @@ interface AutoLogoutViewPlugin extends ViewControllerPlugin {
301
384
  A test double that records calls to `enableAutoLogout` and `disableAutoLogout`. Swap it in during test setup to assert your skill calls the plugin correctly:
302
385
 
303
386
  ```ts
304
- import { SpyAutoLogoutPlugin } from '@sprucelabs/spruce-heartwood-utils'
387
+ import { SpyAutoLogoutPlugin } from '@sprucelabs/spruce-heartwood-utils/testing'
305
388
 
306
389
  protected async beforeEach() {
307
390
  const factory = this.views.getFactory()
@@ -341,7 +424,7 @@ Use these in your skill's test suite to verify that your skill correctly registe
341
424
  High-level assertion helper. Verifies that your skill view emits the expected registration event and that the returned cards are rendered.
342
425
 
343
426
  ```ts
344
- import { remoteVcAssert } from '@sprucelabs/spruce-heartwood-utils'
427
+ import { remoteVcAssert } from '@sprucelabs/spruce-heartwood-utils/testing'
345
428
  ```
346
429
 
347
430
  **Basic assertion — confirm your skill view emits the event and renders cards:**
@@ -387,7 +470,7 @@ await remoteVcAssert.assertSkillViewRendersRemoteCards({
387
470
  ### `AssertRendersRemoteCardsOptions<Svc>`
388
471
 
389
472
  ```ts
390
- import { AssertRendersRemoteCardsOptions } from '@sprucelabs/spruce-heartwood-utils'
473
+ import { AssertRendersRemoteCardsOptions } from '@sprucelabs/spruce-heartwood-utils/testing'
391
474
 
392
475
  interface AssertRendersRemoteCardsOptions<Svc extends SkillViewController = SkillViewController> {
393
476
  svc: Svc
@@ -410,7 +493,7 @@ interface AssertRendersRemoteCardsOptions<Svc extends SkillViewController = Skil
410
493
  Intercepts `heartwood.get-skill-views::v2021_02_11` and returns stub ViewController source. Useful when you need manual control over what remote views are returned in a test — `remoteVcAssert` uses this internally, but you can call it directly for custom scenarios.
411
494
 
412
495
  ```ts
413
- import { fakeGetViews } from '@sprucelabs/spruce-heartwood-utils'
496
+ import { fakeGetViews } from '@sprucelabs/spruce-heartwood-utils/testing'
414
497
 
415
498
  // Stub two remote views:
416
499
  await fakeGetViews.fakeGetViews(['your-skill.card-a', 'your-skill.card-b'])
@@ -439,7 +522,8 @@ A drop-in replacement for the real remote factory. Controls exactly which VC cla
439
522
  import {
440
523
  MockRemoteViewControllerFactory,
441
524
  RemoteViewControllerFactoryImpl,
442
- } from '@sprucelabs/spruce-heartwood-utils'
525
+ } from '@sprucelabs/spruce-heartwood-utils/web'
526
+ import { MockDroppedInControllers } from '@sprucelabs/spruce-heartwood-utils/testing'
443
527
  ```
444
528
 
445
529
  **Setup — inject the mock before your skill view creates its factory:**
@@ -497,7 +581,7 @@ if (mockFactory.hasController('your-skill.some-card')) { ... }
497
581
  Type for the map of card IDs to VC classes held by `MockRemoteViewControllerFactory`:
498
582
 
499
583
  ```ts
500
- import { MockDroppedInControllers } from '@sprucelabs/spruce-heartwood-utils'
584
+ import { MockDroppedInControllers } from '@sprucelabs/spruce-heartwood-utils/testing'
501
585
 
502
586
  type MockDroppedInControllers = Record<
503
587
  string,
@@ -596,7 +680,7 @@ import {
596
680
  AnimationEmitter,
597
681
  SizerProps,
598
682
  DelayedPlacerProps,
599
- } from '@sprucelabs/spruce-heartwood-utils'
683
+ } from '@sprucelabs/spruce-heartwood-utils/web'
600
684
  ```
601
685
 
602
686
  ---
@@ -692,7 +776,7 @@ Pass the **same emitter instance** to `Sizer` and `DelayedPlacer` when they are
692
776
  The interface `Sizer` and `DelayedPlacer` use to communicate layout-change events. Pass an instance as the `emitter` prop to coordinate components. The package exports `SimpleEmitter` — a lightweight in-memory implementation you can use directly:
693
777
 
694
778
  ```ts
695
- import { SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils'
779
+ import { SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils/web'
696
780
 
697
781
  const emitter = new SimpleEmitter()
698
782
  ```
@@ -720,7 +804,7 @@ interface AnimationEmitter {
720
804
  2. **Create an emitter** — one per component tree, stable across renders:
721
805
 
722
806
  ```ts
723
- import { SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils'
807
+ import { SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils/web'
724
808
 
725
809
  const emitter = useMemo(() => new SimpleEmitter(), [])
726
810
  ```
@@ -990,7 +1074,7 @@ Wraps children in a div whose `height` is set via inline style to match the meas
990
1074
  2. **Wrap your content** — `shouldHideOverflow` clips children during the height transition:
991
1075
 
992
1076
  ```tsx
993
- import { Sizer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils'
1077
+ import { Sizer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils/web'
994
1078
 
995
1079
  const emitter = useMemo(() => new SimpleEmitter(), [])
996
1080
 
@@ -1058,7 +1142,7 @@ sizer.current?.hideOverflow(): void // re-apply overflow: hidden
1058
1142
  #### Usage
1059
1143
 
1060
1144
  ```tsx
1061
- import { Sizer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils'
1145
+ import { Sizer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils/web'
1062
1146
 
1063
1147
  // Simplest — just clip overflow during height transition:
1064
1148
  <Sizer shouldHideOverflow>
@@ -1120,7 +1204,7 @@ When `isEnabled={false}`, children render inline with no wrapper.
1120
1204
  2. **Wrap your content** — `isEnabled`, `className`, and `isFocused` are all required:
1121
1205
 
1122
1206
  ```tsx
1123
- import { DelayedPlacer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils'
1207
+ import { DelayedPlacer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils/web'
1124
1208
 
1125
1209
  const emitter = useMemo(() => new SimpleEmitter(), [])
1126
1210
 
@@ -1190,7 +1274,7 @@ delayedPlacer.current?.placeRightAway(): void // re-measure and re-place immedi
1190
1274
 
1191
1275
  ```tsx
1192
1276
  import React, { useRef, useMemo } from 'react'
1193
- import { DelayedPlacer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils'
1277
+ import { DelayedPlacer, SimpleEmitter } from '@sprucelabs/spruce-heartwood-utils/web'
1194
1278
 
1195
1279
  function YourPanel({ isFocused }: { isFocused: () => boolean }) {
1196
1280
  const placerRef = useRef<React.ElementRef<typeof DelayedPlacer>>(null)
@@ -1282,7 +1366,7 @@ A complete example showing all three systems working together in a card componen
1282
1366
  import React, { useMemo } from 'react'
1283
1367
  import {
1284
1368
  Sizer, DelayedPlacer, queueShow, Settings, SimpleEmitter,
1285
- } from '@sprucelabs/spruce-heartwood-utils'
1369
+ } from '@sprucelabs/spruce-heartwood-utils/web'
1286
1370
 
1287
1371
  function YourCard({ isPlaced, isFocused }: { isPlaced: boolean; isFocused: () => boolean }) {
1288
1372
  const emitter = useMemo(() => new SimpleEmitter(), [])
@@ -1321,7 +1405,7 @@ queueShow removes .hidden from each element with a 40ms stagger
1321
1405
  **Test setup for animation components:**
1322
1406
 
1323
1407
  ```ts
1324
- import { Settings, stopQueue } from '@sprucelabs/spruce-heartwood-utils'
1408
+ import { Settings, stopQueue } from '@sprucelabs/spruce-heartwood-utils/web'
1325
1409
  import { skillViewState } from '@sprucelabs/spruce-heartwood-utils/build/components/skillViews/skillViewState'
1326
1410
 
1327
1411
  protected async beforeEach() {
@@ -0,0 +1,167 @@
1
+ import { AbstractEventEmitter } from '@sprucelabs/mercury-event-emitter';
2
+ import { EventContract, EventContractEmitPayloads, MercuryEventEmitter } from '@sprucelabs/mercury-types';
3
+ declare const contract: {
4
+ eventSignatures: {
5
+ 'did-change-orientation': {};
6
+ 'did-resize': {};
7
+ 'did-render': {};
8
+ 'did-resize-content': {};
9
+ 'did-place-cards': {};
10
+ 'will-change-route': {};
11
+ 'did-render-dialog': {};
12
+ 'did-keydown': {
13
+ emitPayloadSchema: {
14
+ id: string;
15
+ fields: {
16
+ e: {
17
+ type: "raw";
18
+ isRequired: true;
19
+ options: {
20
+ valueType: string;
21
+ };
22
+ };
23
+ };
24
+ };
25
+ };
26
+ 'did-scroll': {
27
+ emitPayloadSchema: {
28
+ id: string;
29
+ fields: {
30
+ scrollTop: {
31
+ type: "number";
32
+ isRequired: true;
33
+ };
34
+ skillViewNode: {
35
+ type: "raw";
36
+ isRequired: true;
37
+ options: {
38
+ valueType: string;
39
+ };
40
+ };
41
+ };
42
+ };
43
+ };
44
+ 'connection-status-change': {
45
+ emitPayloadSchema: {
46
+ id: string;
47
+ fields: {
48
+ payload: {
49
+ type: "schema";
50
+ isRequired: true;
51
+ options: {
52
+ schema: {
53
+ id: string;
54
+ fields: {
55
+ status: {
56
+ type: "select";
57
+ isRequired: true;
58
+ options: {
59
+ choices: ({
60
+ readonly label: "Connecting";
61
+ readonly value: "connecting";
62
+ } | {
63
+ readonly label: "Connected";
64
+ readonly value: "connected";
65
+ } | {
66
+ readonly label: "Disconnected";
67
+ readonly value: "disconnected";
68
+ })[];
69
+ };
70
+ };
71
+ };
72
+ };
73
+ };
74
+ };
75
+ };
76
+ };
77
+ };
78
+ };
79
+ };
80
+ export type SkillViewEventContract = typeof contract;
81
+ export type SkillViewEvents = SkillViewEventContract['eventSignatures'];
82
+ export type SkillViewEmitPayloads = EventContractEmitPayloads<SkillViewEventContract>;
83
+ export type SkillViewEmitter = MercuryEventEmitter<SkillViewEventContract>;
84
+ export default class SkillViewEmitterImpl<Contract extends EventContract = SkillViewEventContract> extends AbstractEventEmitter<Contract> implements MercuryEventEmitter<Contract> {
85
+ private static instance;
86
+ private constructor();
87
+ static Emitter(): SkillViewEmitterImpl<{
88
+ eventSignatures: {
89
+ 'did-change-orientation': {};
90
+ 'did-resize': {};
91
+ 'did-render': {};
92
+ 'did-resize-content': {};
93
+ 'did-place-cards': {};
94
+ 'will-change-route': {};
95
+ 'did-render-dialog': {};
96
+ 'did-keydown': {
97
+ emitPayloadSchema: {
98
+ id: string;
99
+ fields: {
100
+ e: {
101
+ type: "raw";
102
+ isRequired: true;
103
+ options: {
104
+ valueType: string;
105
+ };
106
+ };
107
+ };
108
+ };
109
+ };
110
+ 'did-scroll': {
111
+ emitPayloadSchema: {
112
+ id: string;
113
+ fields: {
114
+ scrollTop: {
115
+ type: "number";
116
+ isRequired: true;
117
+ };
118
+ skillViewNode: {
119
+ type: "raw";
120
+ isRequired: true;
121
+ options: {
122
+ valueType: string;
123
+ };
124
+ };
125
+ };
126
+ };
127
+ };
128
+ 'connection-status-change': {
129
+ emitPayloadSchema: {
130
+ id: string;
131
+ fields: {
132
+ payload: {
133
+ type: "schema";
134
+ isRequired: true;
135
+ options: {
136
+ schema: {
137
+ id: string;
138
+ fields: {
139
+ status: {
140
+ type: "select";
141
+ isRequired: true;
142
+ options: {
143
+ choices: ({
144
+ readonly label: "Connecting";
145
+ readonly value: "connecting";
146
+ } | {
147
+ readonly label: "Connected";
148
+ readonly value: "connected";
149
+ } | {
150
+ readonly label: "Disconnected";
151
+ readonly value: "disconnected";
152
+ })[];
153
+ };
154
+ };
155
+ };
156
+ };
157
+ };
158
+ };
159
+ };
160
+ };
161
+ };
162
+ };
163
+ }>;
164
+ static reset(): void;
165
+ static getInstance(): SkillViewEmitter;
166
+ }
167
+ export {};
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mercury_client_1 = require("@sprucelabs/mercury-client");
4
+ const mercury_event_emitter_1 = require("@sprucelabs/mercury-event-emitter");
5
+ const mercury_types_1 = require("@sprucelabs/mercury-types");
6
+ const schema_1 = require("@sprucelabs/schema");
7
+ const contract = (0, mercury_types_1.buildEventContract)({
8
+ eventSignatures: {
9
+ ...mercury_client_1.connectionStatusContract.eventSignatures,
10
+ 'did-change-orientation': {},
11
+ 'did-resize': {},
12
+ 'did-render': {},
13
+ 'did-resize-content': {},
14
+ 'did-place-cards': {},
15
+ 'will-change-route': {},
16
+ 'did-render-dialog': {},
17
+ 'did-keydown': {
18
+ emitPayloadSchema: (0, schema_1.buildSchema)({
19
+ id: 'didKeydownEmitPayload',
20
+ fields: {
21
+ e: {
22
+ type: 'raw',
23
+ isRequired: true,
24
+ options: {
25
+ valueType: 'KeyboardEvent',
26
+ },
27
+ },
28
+ },
29
+ }),
30
+ },
31
+ 'did-scroll': {
32
+ emitPayloadSchema: (0, schema_1.buildSchema)({
33
+ id: 'didScrollEmitPayload',
34
+ fields: {
35
+ scrollTop: {
36
+ type: 'number',
37
+ isRequired: true,
38
+ },
39
+ skillViewNode: {
40
+ type: 'raw',
41
+ isRequired: true,
42
+ options: {
43
+ valueType: 'HTMLDivElement',
44
+ },
45
+ },
46
+ },
47
+ }),
48
+ },
49
+ },
50
+ });
51
+ class SkillViewEmitterImpl extends mercury_event_emitter_1.AbstractEventEmitter {
52
+ constructor(contract) {
53
+ super(contract);
54
+ }
55
+ static Emitter() {
56
+ return new this(contract);
57
+ }
58
+ static reset() {
59
+ this.instance = null;
60
+ }
61
+ static getInstance() {
62
+ if (!this.instance) {
63
+ this.instance = this.Emitter();
64
+ }
65
+ return this.instance;
66
+ }
67
+ }
68
+ exports.default = SkillViewEmitterImpl;
69
+ //# sourceMappingURL=SkillViewEmitter.js.map
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { vcAssert, } from '@sprucelabs/heartwood-view-controllers';
11
2
  import { assert } from '@sprucelabs/test-utils';
12
3
  class MockRemoteViewControllerFactory {
@@ -45,8 +36,7 @@ class MockRemoteViewControllerFactory {
45
36
  }
46
37
  }
47
38
  assertSkillViewRendersRemoteCard(vc, name, id) {
48
- var _a;
49
- const Class = (_a = MockRemoteViewControllerFactory.controllers) === null || _a === void 0 ? void 0 : _a[name];
39
+ const Class = MockRemoteViewControllerFactory.controllers?.[name];
50
40
  assert.isTruthy(Class, `You did not drop in a remote card with the name '${name}'! Try MockRemoteViewControllerFactory.dropInRemoteController('${name}', Class) in your beforeEach().`);
51
41
  const cards = vcAssert.assertSkillViewRendersCards(vc);
52
42
  const cardsWithNoControllers = cards.filter((c) => !c);
@@ -92,7 +82,7 @@ class MockRemoteViewControllerFactory {
92
82
  try {
93
83
  this.assertFetchedRemoteController(id);
94
84
  }
95
- catch (_a) {
85
+ catch {
96
86
  return;
97
87
  }
98
88
  assert.fail(`You fetched the controller with the id '${id}' but you should not have.`);
@@ -107,23 +97,17 @@ class MockRemoteViewControllerFactory {
107
97
  assert.isEqualDeep(this.constructorOptionsById[id], expected, `The constructor options for the remote card with id '${id}' do not match the expected options. Make sure the card you are rendering has an id using this.views.Controller('card', { id })`);
108
98
  }
109
99
  hasController(name) {
110
- var _a;
111
- return (_a = this.loadedControllers[name]) !== null && _a !== void 0 ? _a : false;
112
- }
113
- RemoteController(id, options) {
114
- return __awaiter(this, void 0, void 0, function* () {
115
- var _a, _b;
116
- assert.isTruthy((_a = MockRemoteViewControllerFactory.controllers) === null || _a === void 0 ? void 0 : _a[id], `Could not find a remote card with the id '${id}'! Try MockRemoteViewControllerFactory.dropInRemoteController('${id}', Class) in your beforeEach().`);
117
- this.loadedControllers[id] = true;
118
- this.constructorOptionsById[(_b = options.id) !== null && _b !== void 0 ? _b : id] = options;
119
- this.lastRemoteCostructorOptions = options;
120
- return this.views.Controller(id, options);
121
- });
122
- }
123
- loadViewsForNamespace(namespace) {
124
- return __awaiter(this, void 0, void 0, function* () {
125
- this.loadedNamespaces[namespace] = true;
126
- });
100
+ return this.loadedControllers[name] ?? false;
101
+ }
102
+ async RemoteController(id, options) {
103
+ assert.isTruthy(MockRemoteViewControllerFactory.controllers?.[id], `Could not find a remote card with the id '${id}'! Try MockRemoteViewControllerFactory.dropInRemoteController('${id}', Class) in your beforeEach().`);
104
+ this.loadedControllers[id] = true;
105
+ this.constructorOptionsById[options.id ?? id] = options;
106
+ this.lastRemoteCostructorOptions = options;
107
+ return this.views.Controller(id, options);
108
+ }
109
+ async loadViewsForNamespace(namespace) {
110
+ this.loadedNamespaces[namespace] = true;
127
111
  }
128
112
  assertLoadedViewsForNamespace(namespace) {
129
113
  assert.isTrue(this.loadedNamespaces[namespace], `You did not load views for the namespace '${namespace}'. Try removeVc.loadViewsForNamespace('${namespace}').`);