@api-client/ui 0.1.7 → 0.1.9

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.
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { nothing, TemplateResult } from 'lit'
3
- import { ActivityState, IntentResult, type Intent } from './ActivityManager.js'
3
+ import { ActivityLifecycle, IntentResult, type Intent } from './ActivityManager.js'
4
4
  import { FragmentManager } from './FragmentManager.js'
5
5
  import type { Fragment } from './Fragment.js'
6
6
  import type { Application, UpdateRequest } from './Application.js'
@@ -9,54 +9,88 @@ import type { ActivityDetail, ActivityWithResultDetail } from '../events/IntentE
9
9
  import { EventTypes } from '../events/EventTypes.js'
10
10
 
11
11
  /**
12
- * `Activity` is a crucial component of your app. An application sends an intent
13
- * to bring the activity. If it's found, the activity gets to the foreground and start its activity.
12
+ * ## Activity
14
13
  *
15
- * **Lifecycle**
14
+ * `Activity` is a core building block of your application, representing a single,
15
+ * focused operation that a user can perform.
16
+ * Activities manage their own lifecycle, UI, and fragments, and communicate with the application
17
+ * and other activities via intents.
16
18
  *
17
- * - `onCreated()` - fires when the system first creates the activity.
18
- * - `onStart()` - the activity becomes visible to the user as the app prepares for
19
- * the activity to enter the foreground and become interactive.
20
- * - `onResume()` - the state in which the app interacts with the user.
21
- * - `onPause()` - the first indication that the user is leaving your activity.
22
- * - `onStop()` - your activity is no longer visible to the user.
23
- * - `onDestroy()`- is called before the activity is destroyed
19
+ * Activities are managed by the application and can be started, paused, resumed, stopped,
20
+ * and destroyed according to the app's navigation and user actions.
21
+ * They can also start other activities for results, manage fragments, and handle intent
22
+ * events dispatched by hosted web components.
23
+ *
24
+ * ### Lifecycle Methods
25
+ * - `onCreate(intent?)` - Called when the activity is first created.
26
+ * - `onStart()` - Called when the activity becomes visible to the user.
27
+ * - `onResume()` - Called when the activity gains focus and becomes interactive.
28
+ * - `onPause()` - Called when the activity loses focus but is still visible.
29
+ * - `onStop()` - Called when the activity is no longer visible.
30
+ * - `onDestroy()` - Called before the activity is destroyed.
31
+ * - `onRestart()` - Called after the activity has been stopped, just prior to it being started again.
32
+ *
33
+ * ### Example
34
+ * ```typescript
35
+ * class MyActivity extends Activity {
36
+ * async onCreate(intent?: Intent) {
37
+ * super.onCreate(intent);
38
+ * // Initialization logic here
39
+ * }
40
+ *
41
+ * render() {
42
+ * return html`<h1>Hello from MyActivity!</h1>`;
43
+ * }
44
+ * }
45
+ * ```
24
46
  */
25
47
  export class Activity extends EventTarget {
26
48
  /**
27
- * To be set by an activity to replace the default render root.
28
- * This is particularly useful when the activity is a modal dialog
29
- * and the content should be rendered outside the application's render root.
49
+ * The root element where the activity's content should be rendered.
50
+ * Set this if you want to render outside the application's default render root (e.g., for modals).
30
51
  */
31
52
  renderRoot?: HTMLElement
53
+
32
54
  /**
33
- * An activity can define its action name that does not change.
34
- * It then should be used as the activity registration key.
35
- * This way other activities/fragments can use it to call the activity.
55
+ * An optional static action name for the activity.
56
+ * Use this as the registration key for referencing the activity in intents.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * class LoginActivity extends Activity {
61
+ * static action = 'login';
62
+ * }
63
+ * ```
36
64
  */
37
65
  static action?: string
38
66
 
39
- public state: ActivityState = ActivityState.Initialized
67
+ /** The current lifecycle state of the activity. */
68
+ public lifecycle: ActivityLifecycle = ActivityLifecycle.Initialized
69
+
70
+ /** The parent application instance. */
40
71
  protected parent: Application
41
- /**
42
- * The fragment manager that manages fragments in this activity.
43
- */
72
+
73
+ /** The fragment manager for managing fragments within this activity. */
44
74
  protected manager: FragmentManager
75
+
76
+ /** Data to be returned as a result to the calling activity. */
45
77
  protected resultData?: unknown
46
78
 
79
+ /** The exit code for the activity result. */
47
80
  protected exitCode = IntentResult.RESULT_CANCELED
48
81
 
82
+ /** Gets the current result code for the activity. */
49
83
  get resultCode(): IntentResult {
50
84
  return this.exitCode
51
85
  }
52
86
 
53
- /**
54
- * When starting an new activity for result, we add the request code here
55
- * so that the manager can track which activity originally called the
56
- * activity for result.
57
- */
87
+ /** Tracks pending request codes for activities started for result. */
58
88
  protected pendingRequestCodes: number[] = []
59
89
 
90
+ /**
91
+ * Constructs a new Activity.
92
+ * @param parent The parent application instance.
93
+ */
60
94
  constructor(parent: Application) {
61
95
  super()
62
96
  this.parent = parent
@@ -64,82 +98,76 @@ export class Activity extends EventTarget {
64
98
  }
65
99
 
66
100
  /**
67
- * Called when the activity is starting. This is where most initialization should go.
68
- * You can call `finish()` from within this function, in which case `onDestroy()` will be
69
- * immediately called after `onCreate()` without any of the rest of the activity lifecycle
70
- * (`onStart()`, `onResume()`, `onPause()`, etc) executing.
71
- *
72
- * In the `onCreate()` method, perform basic activity startup logic that happens only once
73
- * for the entire life of the activity.
101
+ * Checks if the activity is in the `Destroyed` state.
102
+ * @returns `true` if destroyed, `false` otherwise.
103
+ */
104
+ isDestroyed(): boolean {
105
+ return this.lifecycle === ActivityLifecycle.Destroyed
106
+ }
107
+
108
+ /**
109
+ * Checks if the activity is in the `Resumed` state.
110
+ * @returns `true` if resumed, `false` otherwise.
111
+ */
112
+ isResumed(): boolean {
113
+ return this.lifecycle === ActivityLifecycle.Resumed
114
+ }
115
+
116
+ /**
117
+ * Called when the activity is starting. Override to perform initialization logic.
74
118
  * @param intent Optional intent data.
119
+ * @example
120
+ * ```typescript
121
+ * async onCreate(intent?: Intent) {
122
+ * await fetchData();
123
+ * }
124
+ * ```
75
125
  */
76
126
  onCreate(intent?: Intent): void | Promise<void> {
77
127
  this.dispatchEvent(new CustomEvent('activity:create', { detail: intent }))
78
128
  }
79
129
 
80
130
  /**
81
- * Called when the activity becomes visible.
82
- * As `onCreate()` exits, the activity enters the `Started` state, and the activity becomes visible
83
- * to the user. This callback contains what amounts to the activity’s final preparations for coming
84
- * to the foreground and becoming interactive.
85
- *
86
- * Called after `onCreate()`. It will usually be followed by onResume().
87
- * This is a good place to begin running animations, etc.
88
- * You can call `finish()` from within this function, in which case `onStop()` will be
89
- * immediately called after `onStart()` without the lifecycle transitions
90
- * in-between (`onResume()`, `onPause()`, etc) executing.
131
+ * Called when the activity becomes visible to the user.
132
+ * Override to start animations or prepare UI.
91
133
  */
92
134
  onStart(): void | Promise<void> {
93
135
  this.dispatchEvent(new CustomEvent('activity:start', { detail: null }))
94
136
  }
95
137
 
96
138
  /**
97
- * Called when the activity gains focus.
98
- * Called after the `onPause()`. This is usually a hint for your activity to start interacting
99
- * with the user, which is a good indicator that the activity became active and ready to receive input.
100
- * This sometimes could also be a transit state toward another resting state.
101
- * For instance, an activity may be relaunched to `onPause()` due to configuration changes and
102
- * the activity was visible, but wasn't the top-most activity of an activity task.
103
- * The `render()` function is always called after this callback.
139
+ * Called when the activity gains focus and becomes interactive.
140
+ * Override to start input handling or resume tasks.
104
141
  */
105
142
  onResume(): void | Promise<void> {
106
143
  this.dispatchEvent(new CustomEvent('activity:resume', { detail: null }))
107
144
  }
108
145
 
109
146
  /**
110
- * Called when the activity loses focus.
111
- * Called as part of the activity lifecycle when the user no longer actively interacts with the activity,
112
- * but it is still visible on screen. The counterpart to `onResume()`.
113
- *
114
- * When activity B is launched in front of activity A, this callback will be invoked on A.
115
- * B will not be created until A's `onPause()` returns, so be sure to not do anything lengthy here.
116
- *
117
- * This callback is mostly used for saving any persistent state the activity is editing,
118
- * to present a "edit in place" model to the user and making sure nothing is lost if there are
119
- * not enough resources to start the new activity without first killing this one.
120
- * This is also a good place to stop things that consume a noticeable amount of CPU in order
121
- * to make the switch to the next activity as fast as possible.
147
+ * Called when the activity loses focus but is still visible.
148
+ * Override to pause ongoing tasks or save state.
122
149
  */
123
150
  onPause(): void | Promise<void> {
124
151
  this.dispatchEvent(new CustomEvent('activity:pause', { detail: null }))
125
152
  }
126
153
 
127
154
  /**
128
- * Called when you are no longer visible to the user.
129
- * You will next receive either onRestart(), onDestroy(), or nothing, depending on later user activity.
130
- * This is a good place to stop refreshing UI, running animations and other visual things.
155
+ * Called when the activity is no longer visible to the user.
156
+ * Override to stop UI updates or animations.
131
157
  */
132
158
  onStop(): void | Promise<void> {
133
159
  this.dispatchEvent(new CustomEvent('activity:stop', { detail: null }))
134
160
  }
135
161
 
162
+ /**
163
+ * Called after the activity has been stopped, just prior to it being started again.
164
+ */
136
165
  onRestart(): void | Promise<void> {
137
166
  this.dispatchEvent(new CustomEvent('activity:restart', { detail: null }))
138
167
  }
139
168
 
140
169
  /**
141
- * Perform any final cleanup before an activity is destroyed.
142
- * This can happen because the activity is finishing (someone called finish() on it).
170
+ * Called before the activity is destroyed. Override to clean up resources.
143
171
  */
144
172
  onDestroy(): void | Promise<void> {
145
173
  this.dispatchEvent(new CustomEvent('activity:destroy', { detail: null }))
@@ -147,45 +175,54 @@ export class Activity extends EventTarget {
147
175
  }
148
176
 
149
177
  /**
150
- * Called when a new intent is delivered
178
+ * Called when a new intent is delivered to the activity.
179
+ * Override to handle new intents.
151
180
  * @param intent New intent data.
152
181
  */
153
182
  onNewIntent(intent: Intent): void | Promise<void> {
154
- //
183
+ // Override in subclass if needed
155
184
  }
156
185
 
157
186
  /**
158
187
  * Called by the renderer when the activity is rendered for the first time.
188
+ * Override to perform actions after first render.
159
189
  */
160
190
  onFirstRender(): void {
161
- //
191
+ // Override in subclass if needed
162
192
  }
163
193
 
164
194
  /**
165
- * A function called when it should render the view.
195
+ * Renders the activity's view. Override to provide UI.
196
+ * @returns A Lit TemplateResult or `nothing` if nothing should be rendered.
197
+ * @example
198
+ * ```typescript
199
+ * render() {
200
+ * return html`<div>Hello, world!</div>`;
201
+ * }
202
+ * ```
166
203
  */
167
204
  render(): TemplateResult | typeof nothing {
168
205
  return nothing
169
206
  }
170
207
 
171
208
  /**
172
- * Finishes the activity.
209
+ * Finishes the activity and notifies the application.
210
+ * @example
211
+ * ```typescript
212
+ * await this.finish();
213
+ * ```
173
214
  */
174
215
  async finish(): Promise<void> {
175
216
  await this.getApplication().manager.finishActivity(this)
176
217
  }
177
218
 
178
219
  /**
179
- * When the activity changes its state it should call the
180
- * `requestUpdate()` method to inform the parent application to
181
- * perform the render operation.
182
- * The function dispatches the `activity:update` custom event
183
- * that is handled by the parent application.
184
- *
185
- * Note, the application may choose to not call the render procedure
186
- * (for example, when the activity is not visible). The rendering
187
- * function is asynchronous. The only way to know the activity is being rendered,
188
- * is when the `render()` method if called.
220
+ * Requests the parent application to update the UI.
221
+ * @param opts Update options.
222
+ * @example
223
+ * ```typescript
224
+ * this.requestUpdate();
225
+ * ```
189
226
  */
190
227
  requestUpdate(opts: UpdateRequest = {}): void {
191
228
  const { activity = true } = opts
@@ -196,18 +233,32 @@ export class Activity extends EventTarget {
196
233
  }
197
234
 
198
235
  /**
199
- * Registers a new fragment.
200
- * @param key The name of the fragment
201
- * @param fragment The fragment to register.
236
+ * Registers a new fragment with this activity.
237
+ * @param key The fragment's key.
238
+ * @param fragment The fragment instance.
239
+ * @param data Optional data to pass to the fragment.
240
+ * @example
241
+ * ```typescript
242
+ * await this.addFragment('profile', new ProfileFragment());
243
+ * ```
202
244
  */
203
245
  async addFragment(key: string, fragment: Fragment, data?: unknown): Promise<void> {
204
246
  await this.manager.attachFragment(key, fragment, this, data)
205
247
  }
206
248
 
249
+ /**
250
+ * Shows a registered fragment.
251
+ * @param key The fragment's key.
252
+ * @param root Optional root element to render into.
253
+ */
207
254
  async showFragment(key: string, root?: HTMLElement): Promise<void> {
208
255
  await this.manager.showFragment(key, root)
209
256
  }
210
257
 
258
+ /**
259
+ * Hides a registered fragment.
260
+ * @param key The fragment's key.
261
+ */
211
262
  async hideFragment(key: string): Promise<void> {
212
263
  const fragment = this.manager.findFragment(key)
213
264
  if (fragment) {
@@ -216,16 +267,20 @@ export class Activity extends EventTarget {
216
267
  }
217
268
 
218
269
  /**
219
- * Unifies Fragment and Activity interfaces.
220
- * @returns `this`
270
+ * Returns the parent application instance.
271
+ * @returns The application.
221
272
  */
222
273
  getApplication(): Application {
223
274
  return this.parent
224
275
  }
225
276
 
226
277
  /**
227
- * A shortcut to the `manager` function.
228
- * @param intent The intent to start
278
+ * Starts a new activity.
279
+ * @param intent The intent to start.
280
+ * @example
281
+ * ```typescript
282
+ * await this.startActivity({ action: 'login' });
283
+ * ```
229
284
  */
230
285
  startActivity(intent: Intent): Promise<void> {
231
286
  return this.parent.manager.startActivity(intent)
@@ -233,8 +288,12 @@ export class Activity extends EventTarget {
233
288
 
234
289
  /**
235
290
  * Starts a new activity for a result.
236
- * @param intent The intent that created this activity.
237
- * @returns The request code created with this call.
291
+ * @param intent The intent to start.
292
+ * @returns The request code for the started activity.
293
+ * @example
294
+ * ```typescript
295
+ * const code = await this.startActivityForResult({ action: 'pickFile' });
296
+ * ```
238
297
  */
239
298
  async startActivityForResult(intent: Intent): Promise<number> {
240
299
  const { manager } = this.getApplication()
@@ -245,8 +304,13 @@ export class Activity extends EventTarget {
245
304
  }
246
305
 
247
306
  /**
248
- * Call this method to return data to the activity that started this activity.
249
- * @param data The data to return.
307
+ * Sets the result to be returned to the calling activity.
308
+ * @param resultCode The result code.
309
+ * @param data Optional result data.
310
+ * @example
311
+ * ```typescript
312
+ * this.setResult(IntentResult.RESULT_OK, { userId: 123 });
313
+ * ```
250
314
  */
251
315
  setResult(resultCode: IntentResult, data?: unknown): void {
252
316
  this.exitCode = resultCode
@@ -254,17 +318,19 @@ export class Activity extends EventTarget {
254
318
  }
255
319
 
256
320
  /**
257
- * Called when an activity you launched exits, giving you the `requestCode` you started it with,
258
- * the `resultCode` it returned, and any additional data from it. The `resultCode` will be `RESULT_CANCELED`
259
- * if the activity explicitly returned that, didn't return any result, or crashed during its operation.
260
- *
261
- * An activity can never receive a result in the resumed state. You can count on `onResume()` being called
262
- * after this method, though not necessarily immediately after. If the activity was resumed,
263
- * it will be paused and the result will be delivered, followed by `onResume()`.
264
- *
265
- * @param requestCode The request code passed to startActivityForResult.
266
- * @param data The result from the activity.
321
+ * Called when an activity you launched exits, giving you the request code, result code, and intent.
322
+ * Override to handle results from started activities.
323
+ * @param requestCode The request code.
324
+ * @param resultCode The result code.
267
325
  * @param intent The intent that was used to start the activity.
326
+ * @example
327
+ * ```typescript
328
+ * async onActivityResult(requestCode, resultCode, intent) {
329
+ * if (resultCode === IntentResult.RESULT_OK) {
330
+ * // handle result
331
+ * }
332
+ * }
333
+ * ```
268
334
  */
269
335
  async onActivityResult(requestCode: number, resultCode: IntentResult, intent: Intent): Promise<void> {
270
336
  const index = this.pendingRequestCodes.indexOf(requestCode)
@@ -285,37 +351,42 @@ export class Activity extends EventTarget {
285
351
  }
286
352
  }
287
353
 
354
+ /**
355
+ * Returns the current activity instance.
356
+ * @returns This activity.
357
+ */
288
358
  getActivity(): Activity {
289
359
  return this
290
360
  }
291
361
 
292
362
  /**
293
- * Checks whether this activity initiated the activity for result.
294
- * @param code The request code to look for.
295
- * @returns `true` if the activity has the request code.
363
+ * Checks if this activity initiated the activity for result with the given code.
364
+ * @param code The request code.
365
+ * @returns `true` if the code is pending, `false` otherwise.
296
366
  */
297
367
  hasRequestCode(code: number): boolean {
298
368
  return this.pendingRequestCodes.includes(code)
299
369
  }
300
370
 
371
+ /**
372
+ * Gets the result data set by `setResult`.
373
+ * @returns The result data or `undefined`.
374
+ */
301
375
  getResult(): unknown | undefined {
302
376
  return this.resultData
303
377
  }
304
378
 
305
379
  /**
306
- * A handler for the intent event dispatched by web components hosted by this activity.
307
- *
308
- * **Usage example:**
380
+ * Handles intent events dispatched by web components hosted by this activity.
309
381
  *
310
- * ```ts
382
+ * Usage example:
383
+ * ```html
311
384
  * <custom-element @startactivity="${this.handleIntentEvent}"></custom-element>
312
385
  * <custom-element @startactivityforresult="${this.handleIntentEvent}"></custom-element>
313
386
  * ```
314
387
  *
315
- * @param event The event that was dispatched.
316
- * @returns A promise that resolves when the intent is handled.
317
- * @throws An error if the activity has no activity.
318
- * @throws An error if the event type is not recognized.
388
+ * @param event The intent event.
389
+ * @throws Error if the event type is not recognized.
319
390
  */
320
391
  @bound
321
392
  async handleIntentEvent(event: CustomEvent<ActivityDetail | ActivityWithResultDetail>): Promise<void> {