@api-client/ui 0.5.34 → 0.5.36

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.
@@ -5,6 +5,7 @@ import type { Application, UpdateRequest } from './Application.js';
5
5
  import { FragmentRenderer } from './renderer/FragmentRenderer.js';
6
6
  import { Intent, IntentResult } from './ActivityManager.js';
7
7
  import type { ActivityDetail, ActivityWithResultDetail } from '../events/IntentEvents.js';
8
+ import { type RefOrCallback } from 'lit/directives/ref.js';
8
9
  export interface PendingActivityResult {
9
10
  onResult(result: IntentResult, intent: Intent): void;
10
11
  }
@@ -124,6 +125,19 @@ export declare class Fragment extends EventTarget {
124
125
  * @param key The name of the fragment to remove.
125
126
  */
126
127
  removeChild(key: string): Promise<void>;
128
+ /**
129
+ * Creates a RefCallback that can be used with lit's `ref()` directive
130
+ * to automatically show/hide a child fragment when its container element
131
+ * is added or removed from the DOM.
132
+ *
133
+ * @param key The key of the child fragment to manage.
134
+ * @returns A RefCallback to be used with the `ref()` directive.
135
+ *
136
+ * @example
137
+ * // In your parent fragment's render method:
138
+ * html`<div ${ref(this.createFragmentRef('my-child-fragment'))}></div>`
139
+ */
140
+ createFragmentRef(key: string): RefOrCallback<Element>;
127
141
  /**
128
142
  * A helper to request an update.
129
143
  * Application or parent Fragment will handle rendering.
@@ -1 +1 @@
1
- {"version":3,"file":"Fragment.d.ts","sourceRoot":"","sources":["../../../src/core/Fragment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Fragment.d.ts","sourceRoot":"","sources":["../../../src/core/Fragment.ts"],"names":[],"mappings":"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"}
@@ -187,17 +187,42 @@ let Fragment = (() => {
187
187
  this.children.delete(key);
188
188
  }
189
189
  }
190
+ /**
191
+ * Creates a RefCallback that can be used with lit's `ref()` directive
192
+ * to automatically show/hide a child fragment when its container element
193
+ * is added or removed from the DOM.
194
+ *
195
+ * @param key The key of the child fragment to manage.
196
+ * @returns A RefCallback to be used with the `ref()` directive.
197
+ *
198
+ * @example
199
+ * // In your parent fragment's render method:
200
+ * html`<div ${ref(this.createFragmentRef('my-child-fragment'))}></div>`
201
+ */
202
+ createFragmentRef(key) {
203
+ return (element) => {
204
+ if (element) {
205
+ this.fragmentManager.showFragment(key, element);
206
+ }
207
+ else {
208
+ const fragment = this.fragmentManager.findFragment(key);
209
+ if (fragment) {
210
+ this.fragmentManager.hideFragment(fragment);
211
+ }
212
+ }
213
+ };
214
+ }
190
215
  /**
191
216
  * A helper to request an update.
192
217
  * Application or parent Fragment will handle rendering.
193
218
  */
194
219
  requestUpdate(opts = {}) {
195
- const { fragment = true } = opts;
196
- if (fragment) {
197
- this.#renderer.requestUpdate();
220
+ if (opts.fragment !== false) {
221
+ this.renderer.requestUpdate();
222
+ }
223
+ if (this.parent && (opts.activity || opts.app)) {
224
+ this.parent.requestUpdate(opts);
198
225
  }
199
- this.parent?.requestUpdate(opts);
200
- // If no parent, do nothing (or maybe throw an error?)
201
226
  }
202
227
  getApplication() {
203
228
  return this.parent?.getApplication();
@@ -1 +1 @@
1
- {"version":3,"file":"Fragment.js","sourceRoot":"","sources":["../../../src/core/Fragment.ts"],"names":[],"mappings":"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","sourcesContent":["import { nothing, TemplateResult } from 'lit'\nimport { Activity } from './Activity.js'\nimport { FragmentState, type FragmentOptions, FragmentManager } from './FragmentManager.js'\nimport type { Application, UpdateRequest } from './Application.js'\nimport { FragmentRenderer } from './renderer/FragmentRenderer.js'\nimport { Intent, IntentResult } from './ActivityManager.js'\nimport { bound } from '../decorators/bound.js'\nimport type { ActivityDetail, ActivityWithResultDetail } from '../events/IntentEvents.js'\nimport { EventTypes } from '../events/EventTypes.js'\n\nexport interface PendingActivityResult {\n onResult(result: IntentResult, intent: Intent): void\n}\n\n/**\n * Similar to Activity, with lifecycle methods (onCreate, onAttach, onDetach, etc.).\n * The crucial difference is that a Fragment is always hosted by an `Activity` or\n * another `Fragment`.\n *\n * A `Fragment` represents a reusable portion of the app's UI.\n * A fragment defines and manages its own layout, has its own lifecycle,\n * and can handle its own input events.\n * Fragments can't live on their own. They must be hosted by an activity or another\n * fragment. The fragment’s view hierarchy becomes part of, or attaches to,\n * the host’s view hierarchy.\n */\nexport class Fragment extends EventTarget {\n public state: FragmentState = FragmentState.Initialized\n public parent?: Activity | Fragment\n protected children = new Map<string, Fragment>()\n protected fragmentManager: FragmentManager\n\n /**\n * The request code used to start an activity for a result.\n */\n requestCode = -1\n\n /**\n * A list of pending activity results that were requested by the components\n * hosted in this fragment.\n * The key is the request code and the value contains the callback\n * that will be called when the activity result is received.\n * The callback is called with the result code and the resulting intent.\n */\n pendingActivityResult: Map<number, PendingActivityResult> = new Map<number, PendingActivityResult>()\n\n #renderer: FragmentRenderer\n\n get renderer(): FragmentRenderer {\n return this.#renderer\n }\n\n constructor(options?: FragmentOptions) {\n super()\n this.parent = options?.parent\n this.fragmentManager = new FragmentManager(this)\n this.#renderer = new FragmentRenderer(this)\n }\n\n /**\n * When implemented, this method returns the class name to be used as a root class for the fragment.\n * This class name can be used to apply styles or identify the fragment in the DOM.\n * @returns The class name to be used as a root class for the fragment.\n */\n public rootClass(): string | undefined {\n return undefined\n }\n\n /**\n * @see {@link ./Renderer.js}\n */\n public setRenderRoot(renderRoot: HTMLElement | string): void {\n this.#renderer.setRenderRoot(renderRoot)\n }\n\n onData(data: unknown): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:data', { detail: data }))\n }\n\n /**\n * Called once when the fragment is created.\n *\n * In the `onCreate()` method, perform basic fragment startup logic that happens only once\n * for the entire life of the fragment.\n * @param data Optional init data.\n */\n onCreate(data?: unknown): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:create', { detail: data }))\n }\n\n /**\n * Called when the fragment is attached to a parent\n */\n onAttach(data?: unknown): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:attach', { detail: data }))\n }\n\n /**\n * Called when the fragment becomes visible.\n */\n onStart(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:start', { detail: null }))\n }\n\n /**\n * Called when the fragment gains focus.\n */\n onResume(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:resume', { detail: null }))\n }\n\n /**\n * Called when the fragment loses focus.\n */\n onPause(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:pause', { detail: null }))\n }\n\n /**\n * Called when the fragment is no longer visible.\n */\n onStop(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:stop', { detail: null }))\n }\n\n /**\n * Called when the fragment is detached from a parent\n */\n onDetach(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:detach', { detail: null }))\n }\n\n /**\n * Called before the fragment is destroyed.\n */\n onDestroy(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:destroy', { detail: null }))\n this.fragmentManager.onDestroy()\n }\n\n /**\n * Called by the renderer when the fragment is rendered for the first time.\n */\n onFirstRender(): void {\n //\n }\n\n /**\n * A function called when it should render the view.\n * By default it renders a fragment view if the fragment hosts other fragments and only one is visible.\n */\n render(): TemplateResult | typeof nothing {\n const fragment = this.getSingleVisibleFragment()\n if (fragment) {\n // we can manage the default rendering.\n // we make an assumption that by default only one fragment is rendered,\n // otherwise the parent activity or fragment would have to setup render roots.\n return fragment.render()\n }\n return nothing\n }\n\n /**\n * Checks whether there's only one `Fragment` that is in the `Resumed` state\n * and returns it. It returns `null` if there is no `Fragment`s or more than a single\n * visible `Fragment`.\n * @returns A Fragment that is the only fragment that should be visible.\n */\n getSingleVisibleFragment(): Fragment | null {\n const fragments = this.getVisibleFragments()\n return fragments.length === 1 ? fragments[0] : null\n }\n\n /**\n * Checks whether this fragment is a host for other fragments.\n * @returns `true` when this fragment hosts other fragments.\n */\n isRenderingFragments(): boolean {\n return this.children.size > 0\n }\n\n /**\n * @returns The list of all fragments that are in the Resumed state.\n */\n getVisibleFragments(): Fragment[] {\n return this.fragmentManager.getVisible()\n }\n\n /**\n * Adds a child fragment to this fragment.\n * The FragmentManager will handle lifecycle.\n * @param key The name of the fragment.\n * @param fragment The fragment to add.\n */\n async addChild(key: string, fragment: Fragment, data?: unknown): Promise<void> {\n this.children.set(key, fragment)\n await this.fragmentManager.attachFragment(key, fragment, this, data)\n }\n\n /**\n * Removes a fragment from this fragment.\n * @param key The name of the fragment to remove.\n */\n async removeChild(key: string): Promise<void> {\n const child = this.children.get(key)\n if (child) {\n await this.fragmentManager.detachFragment(key)\n this.children.delete(key)\n }\n }\n\n /**\n * A helper to request an update.\n * Application or parent Fragment will handle rendering.\n */\n requestUpdate(opts: UpdateRequest = {}): void {\n const { fragment = true } = opts\n if (fragment) {\n this.#renderer.requestUpdate()\n }\n this.parent?.requestUpdate(opts)\n // If no parent, do nothing (or maybe throw an error?)\n }\n\n getApplication(): Application | undefined {\n return this.parent?.getApplication()\n }\n\n getActivity(): Activity | undefined {\n return this.parent?.getActivity()\n }\n\n /**\n * Starts an activity for result.\n * @param intent The intent to start.\n */\n async startActivityForResult(intent: Intent): Promise<void> {\n const activity = this.getActivity()\n if (!activity) {\n throw new Error(`The fragment has no activity. Unable to start an intent.`)\n }\n this.requestCode = await activity.startActivityForResult(intent)\n }\n\n /**\n * Starts another activity.\n * @param intent The intent to start.\n */\n async startActivity(intent: Intent): Promise<void> {\n const activity = this.getActivity()\n if (!activity) {\n throw new Error(`The fragment has no activity. Unable to start an intent.`)\n }\n await activity.startActivity(intent)\n }\n\n /**\n * The callback method that is triggered when another activity that was\n * started for result finishes.\n *\n * @param requestCode The request code that was used to start the activity.\n * @param data The data that was passed back.\n * @param intent The intent that was used to start the activity.\n */\n async onActivityResult(requestCode: number, resultCode: IntentResult, intent: Intent): Promise<void> {\n const { pendingActivityResult, children } = this\n if (pendingActivityResult.has(requestCode)) {\n const { onResult } = pendingActivityResult.get(requestCode) as PendingActivityResult\n pendingActivityResult.delete(requestCode)\n onResult(resultCode, intent)\n return\n }\n for (const fragment of children.values()) {\n if (fragment.hasRequestCode(requestCode)) {\n fragment.onActivityResult(requestCode, resultCode, intent)\n return\n }\n }\n this.requestCode = -1\n if (this.constructor === Fragment) {\n // eslint-disable-next-line no-console\n console.info('Fragment#onActivityResult() not implemented', requestCode, resultCode, intent)\n }\n }\n\n hasRequestCode(requestCode: number): boolean {\n for (const fragment of this.children.values()) {\n if (fragment.hasRequestCode(requestCode)) {\n return true\n }\n }\n return this.requestCode === requestCode\n }\n\n /**\n * A handler for the intent event dispatched by web components hosted by this fragment.\n *\n * **Usage example:**\n *\n * ```ts\n * <custom-element @startactivity=\"${this.handleIntentEvent}\"></custom-element>\n * <custom-element @startactivityforresult=\"${this.handleIntentEvent}\"></custom-element>\n * ```\n *\n * @param event The event that was dispatched.\n * @returns A promise that resolves when the intent is handled.\n * @throws An error if the fragment has no activity.\n * @throws An error if the event type is not recognized.\n */\n @bound\n async handleIntentEvent(event: CustomEvent<ActivityDetail | ActivityWithResultDetail>): Promise<void> {\n const activity = this.getActivity()\n if (!activity) {\n throw new Error(`The fragment has no activity. Unable to start an intent.`)\n }\n if (event.type === EventTypes.Intent.startActivityForResult) {\n const info = event.detail as ActivityWithResultDetail\n const code = await activity.startActivityForResult(info.intent)\n this.requestCode = code\n this.pendingActivityResult.set(code, {\n onResult: info.onResult,\n })\n } else if (event.type === EventTypes.Intent.startActivity) {\n await activity.startActivity(event.detail.intent)\n } else {\n throw new Error(`Unrecognized intent event: ${event.type}`)\n }\n }\n}\n"]}
1
+ {"version":3,"file":"Fragment.js","sourceRoot":"","sources":["../../../src/core/Fragment.ts"],"names":[],"mappings":"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","sourcesContent":["import { nothing, TemplateResult } from 'lit'\nimport { Activity } from './Activity.js'\nimport { FragmentState, type FragmentOptions, FragmentManager } from './FragmentManager.js'\nimport type { Application, UpdateRequest } from './Application.js'\nimport { FragmentRenderer } from './renderer/FragmentRenderer.js'\nimport { Intent, IntentResult } from './ActivityManager.js'\nimport { bound } from '../decorators/bound.js'\nimport type { ActivityDetail, ActivityWithResultDetail } from '../events/IntentEvents.js'\nimport { EventTypes } from '../events/EventTypes.js'\nimport { type RefOrCallback } from 'lit/directives/ref.js'\n\nexport interface PendingActivityResult {\n onResult(result: IntentResult, intent: Intent): void\n}\n\n/**\n * Similar to Activity, with lifecycle methods (onCreate, onAttach, onDetach, etc.).\n * The crucial difference is that a Fragment is always hosted by an `Activity` or\n * another `Fragment`.\n *\n * A `Fragment` represents a reusable portion of the app's UI.\n * A fragment defines and manages its own layout, has its own lifecycle,\n * and can handle its own input events.\n * Fragments can't live on their own. They must be hosted by an activity or another\n * fragment. The fragment’s view hierarchy becomes part of, or attaches to,\n * the host’s view hierarchy.\n */\nexport class Fragment extends EventTarget {\n public state: FragmentState = FragmentState.Initialized\n public parent?: Activity | Fragment\n protected children = new Map<string, Fragment>()\n protected fragmentManager: FragmentManager\n\n /**\n * The request code used to start an activity for a result.\n */\n requestCode = -1\n\n /**\n * A list of pending activity results that were requested by the components\n * hosted in this fragment.\n * The key is the request code and the value contains the callback\n * that will be called when the activity result is received.\n * The callback is called with the result code and the resulting intent.\n */\n pendingActivityResult: Map<number, PendingActivityResult> = new Map<number, PendingActivityResult>()\n\n #renderer: FragmentRenderer\n\n get renderer(): FragmentRenderer {\n return this.#renderer\n }\n\n constructor(options?: FragmentOptions) {\n super()\n this.parent = options?.parent\n this.fragmentManager = new FragmentManager(this)\n this.#renderer = new FragmentRenderer(this)\n }\n\n /**\n * When implemented, this method returns the class name to be used as a root class for the fragment.\n * This class name can be used to apply styles or identify the fragment in the DOM.\n * @returns The class name to be used as a root class for the fragment.\n */\n public rootClass(): string | undefined {\n return undefined\n }\n\n /**\n * @see {@link ./Renderer.js}\n */\n public setRenderRoot(renderRoot: HTMLElement | string): void {\n this.#renderer.setRenderRoot(renderRoot)\n }\n\n onData(data: unknown): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:data', { detail: data }))\n }\n\n /**\n * Called once when the fragment is created.\n *\n * In the `onCreate()` method, perform basic fragment startup logic that happens only once\n * for the entire life of the fragment.\n * @param data Optional init data.\n */\n onCreate(data?: unknown): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:create', { detail: data }))\n }\n\n /**\n * Called when the fragment is attached to a parent\n */\n onAttach(data?: unknown): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:attach', { detail: data }))\n }\n\n /**\n * Called when the fragment becomes visible.\n */\n onStart(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:start', { detail: null }))\n }\n\n /**\n * Called when the fragment gains focus.\n */\n onResume(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:resume', { detail: null }))\n }\n\n /**\n * Called when the fragment loses focus.\n */\n onPause(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:pause', { detail: null }))\n }\n\n /**\n * Called when the fragment is no longer visible.\n */\n onStop(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:stop', { detail: null }))\n }\n\n /**\n * Called when the fragment is detached from a parent\n */\n onDetach(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:detach', { detail: null }))\n }\n\n /**\n * Called before the fragment is destroyed.\n */\n onDestroy(): void | Promise<void> {\n this.dispatchEvent(new CustomEvent('fragment:destroy', { detail: null }))\n this.fragmentManager.onDestroy()\n }\n\n /**\n * Called by the renderer when the fragment is rendered for the first time.\n */\n onFirstRender(): void {\n //\n }\n\n /**\n * A function called when it should render the view.\n * By default it renders a fragment view if the fragment hosts other fragments and only one is visible.\n */\n render(): TemplateResult | typeof nothing {\n const fragment = this.getSingleVisibleFragment()\n if (fragment) {\n // we can manage the default rendering.\n // we make an assumption that by default only one fragment is rendered,\n // otherwise the parent activity or fragment would have to setup render roots.\n return fragment.render()\n }\n return nothing\n }\n\n /**\n * Checks whether there's only one `Fragment` that is in the `Resumed` state\n * and returns it. It returns `null` if there is no `Fragment`s or more than a single\n * visible `Fragment`.\n * @returns A Fragment that is the only fragment that should be visible.\n */\n getSingleVisibleFragment(): Fragment | null {\n const fragments = this.getVisibleFragments()\n return fragments.length === 1 ? fragments[0] : null\n }\n\n /**\n * Checks whether this fragment is a host for other fragments.\n * @returns `true` when this fragment hosts other fragments.\n */\n isRenderingFragments(): boolean {\n return this.children.size > 0\n }\n\n /**\n * @returns The list of all fragments that are in the Resumed state.\n */\n getVisibleFragments(): Fragment[] {\n return this.fragmentManager.getVisible()\n }\n\n /**\n * Adds a child fragment to this fragment.\n * The FragmentManager will handle lifecycle.\n * @param key The name of the fragment.\n * @param fragment The fragment to add.\n */\n async addChild(key: string, fragment: Fragment, data?: unknown): Promise<void> {\n this.children.set(key, fragment)\n await this.fragmentManager.attachFragment(key, fragment, this, data)\n }\n\n /**\n * Removes a fragment from this fragment.\n * @param key The name of the fragment to remove.\n */\n async removeChild(key: string): Promise<void> {\n const child = this.children.get(key)\n if (child) {\n await this.fragmentManager.detachFragment(key)\n this.children.delete(key)\n }\n }\n\n /**\n * Creates a RefCallback that can be used with lit's `ref()` directive\n * to automatically show/hide a child fragment when its container element\n * is added or removed from the DOM.\n *\n * @param key The key of the child fragment to manage.\n * @returns A RefCallback to be used with the `ref()` directive.\n *\n * @example\n * // In your parent fragment's render method:\n * html`<div ${ref(this.createFragmentRef('my-child-fragment'))}></div>`\n */\n createFragmentRef(key: string): RefOrCallback<Element> {\n return (element?: Element) => {\n if (element) {\n this.fragmentManager.showFragment(key, element as HTMLElement)\n } else {\n const fragment = this.fragmentManager.findFragment(key)\n if (fragment) {\n this.fragmentManager.hideFragment(fragment)\n }\n }\n }\n }\n\n /**\n * A helper to request an update.\n * Application or parent Fragment will handle rendering.\n */\n requestUpdate(opts: UpdateRequest = {}): void {\n if (opts.fragment !== false) {\n this.renderer.requestUpdate()\n }\n if (this.parent && (opts.activity || opts.app)) {\n this.parent.requestUpdate(opts)\n }\n }\n\n getApplication(): Application | undefined {\n return this.parent?.getApplication()\n }\n\n getActivity(): Activity | undefined {\n return this.parent?.getActivity()\n }\n\n /**\n * Starts an activity for result.\n * @param intent The intent to start.\n */\n async startActivityForResult(intent: Intent): Promise<void> {\n const activity = this.getActivity()\n if (!activity) {\n throw new Error(`The fragment has no activity. Unable to start an intent.`)\n }\n this.requestCode = await activity.startActivityForResult(intent)\n }\n\n /**\n * Starts another activity.\n * @param intent The intent to start.\n */\n async startActivity(intent: Intent): Promise<void> {\n const activity = this.getActivity()\n if (!activity) {\n throw new Error(`The fragment has no activity. Unable to start an intent.`)\n }\n await activity.startActivity(intent)\n }\n\n /**\n * The callback method that is triggered when another activity that was\n * started for result finishes.\n *\n * @param requestCode The request code that was used to start the activity.\n * @param data The data that was passed back.\n * @param intent The intent that was used to start the activity.\n */\n async onActivityResult(requestCode: number, resultCode: IntentResult, intent: Intent): Promise<void> {\n const { pendingActivityResult, children } = this\n if (pendingActivityResult.has(requestCode)) {\n const { onResult } = pendingActivityResult.get(requestCode) as PendingActivityResult\n pendingActivityResult.delete(requestCode)\n onResult(resultCode, intent)\n return\n }\n for (const fragment of children.values()) {\n if (fragment.hasRequestCode(requestCode)) {\n fragment.onActivityResult(requestCode, resultCode, intent)\n return\n }\n }\n this.requestCode = -1\n if (this.constructor === Fragment) {\n // eslint-disable-next-line no-console\n console.info('Fragment#onActivityResult() not implemented', requestCode, resultCode, intent)\n }\n }\n\n hasRequestCode(requestCode: number): boolean {\n for (const fragment of this.children.values()) {\n if (fragment.hasRequestCode(requestCode)) {\n return true\n }\n }\n return this.requestCode === requestCode\n }\n\n /**\n * A handler for the intent event dispatched by web components hosted by this fragment.\n *\n * **Usage example:**\n *\n * ```ts\n * <custom-element @startactivity=\"${this.handleIntentEvent}\"></custom-element>\n * <custom-element @startactivityforresult=\"${this.handleIntentEvent}\"></custom-element>\n * ```\n *\n * @param event The event that was dispatched.\n * @returns A promise that resolves when the intent is handled.\n * @throws An error if the fragment has no activity.\n * @throws An error if the event type is not recognized.\n */\n @bound\n async handleIntentEvent(event: CustomEvent<ActivityDetail | ActivityWithResultDetail>): Promise<void> {\n const activity = this.getActivity()\n if (!activity) {\n throw new Error(`The fragment has no activity. Unable to start an intent.`)\n }\n if (event.type === EventTypes.Intent.startActivityForResult) {\n const info = event.detail as ActivityWithResultDetail\n const code = await activity.startActivityForResult(info.intent)\n this.requestCode = code\n this.pendingActivityResult.set(code, {\n onResult: info.onResult,\n })\n } else if (event.type === EventTypes.Intent.startActivity) {\n await activity.startActivity(event.detail.intent)\n } else {\n throw new Error(`Unrecognized intent event: ${event.type}`)\n }\n }\n}\n"]}
@@ -76,7 +76,7 @@ export declare class FragmentManager {
76
76
  /**
77
77
  * Hides a Fragment (calls lifecycle methods and removes from DOM if necessary)
78
78
  */
79
- hideFragment(fragment: Fragment): Promise<void>;
79
+ hideFragment(fragment: Fragment | string): Promise<void>;
80
80
  findFragment(key: string): Fragment | undefined;
81
81
  renderFragment(key: string): TemplateResult | typeof nothing;
82
82
  updateActiveFragments(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"FragmentManager.d.ts","sourceRoot":"","sources":["../../../src/core/FragmentManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,oBAAY,aAAa;IACvB,WAAW,IAAA;IACX,OAAO,IAAA;IACP,QAAQ,IAAA,CAAE,mCAAmC;IAC7C,OAAO,IAAA,CAAE,UAAU;IACnB,OAAO,IAAA,CAAE,YAAY;IACrB,MAAM,IAAA;IACN,OAAO,IAAA,CAAE,oBAAoB;IAC7B,QAAQ,IAAA,CAAE,uCAAuC;IACjD,SAAS,IAAA;CACV;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAC7B;AAED;;;;GAIG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACH,OAAO,CAAC,SAAS,CAA8B;IAC/C;;OAEG;IACH,OAAO,CAAC,IAAI,CAAqB;gBAErB,IAAI,EAAE,QAAQ,GAAG,QAAQ;IAI/B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC;;;;;;;OAOG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjH;;;;OAIG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBhD;;;;OAIG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB1E;;;;;;OAMG;IACH,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAiB3C;;;;;;OAMG;IACH,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAiB9C;;;OAGG;IACH,UAAU,IAAI,QAAQ,EAAE;IAIxB;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI/C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,OAAO;IAQ5D,qBAAqB,IAAI,IAAI;IAQ7B;;;;OAIG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;CAQxD"}
1
+ {"version":3,"file":"FragmentManager.d.ts","sourceRoot":"","sources":["../../../src/core/FragmentManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,oBAAY,aAAa;IACvB,WAAW,IAAA;IACX,OAAO,IAAA;IACP,QAAQ,IAAA,CAAE,mCAAmC;IAC7C,OAAO,IAAA,CAAE,UAAU;IACnB,OAAO,IAAA,CAAE,YAAY;IACrB,MAAM,IAAA;IACN,OAAO,IAAA,CAAE,oBAAoB;IAC7B,QAAQ,IAAA,CAAE,uCAAuC;IACjD,SAAS,IAAA;CACV;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAC7B;AAED;;;;GAIG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACH,OAAO,CAAC,SAAS,CAA8B;IAC/C;;OAEG;IACH,OAAO,CAAC,IAAI,CAAqB;gBAErB,IAAI,EAAE,QAAQ,GAAG,QAAQ;IAI/B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC;;;;;;;OAOG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjH;;;;OAIG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBhD;;;;OAIG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB1E;;;;;;OAMG;IACH,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAiB3C;;;;;;OAMG;IACH,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAiB9C;;;OAGG;IACH,UAAU,IAAI,QAAQ,EAAE;IAIxB;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI/C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,OAAO;IAQ5D,qBAAqB,IAAI,IAAI;IAQ7B;;;;OAIG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;CAQxD"}
@@ -156,11 +156,21 @@ export class FragmentManager {
156
156
  * Hides a Fragment (calls lifecycle methods and removes from DOM if necessary)
157
157
  */
158
158
  async hideFragment(fragment) {
159
- await fragment.onPause();
160
- fragment.state = FragmentState.Paused;
161
- await fragment.onStop();
162
- fragment.state = FragmentState.Stopped;
163
- this.removeFragmentStyles(fragment);
159
+ let ref;
160
+ if (typeof fragment === 'string') {
161
+ ref = this.findFragment(fragment);
162
+ }
163
+ else {
164
+ ref = fragment;
165
+ }
166
+ if (!ref) {
167
+ throw new Error(`Fragment not found`);
168
+ }
169
+ await ref.onPause();
170
+ ref.state = FragmentState.Paused;
171
+ await ref.onStop();
172
+ ref.state = FragmentState.Stopped;
173
+ this.removeFragmentStyles(ref);
164
174
  // if necessary, you would remove its template content from the DOM
165
175
  // however, with rendering logic encapsulated in Fragment, this isn't needed here
166
176
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FragmentManager.js","sourceRoot":"","sources":["../../../src/core/FragmentManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TemplateResult, nothing } from 'lit'\nimport type { Activity } from './Activity.js'\nimport type { Fragment } from './Fragment.js'\n\nexport enum FragmentState {\n Initialized,\n Created,\n Attached, // Added to an Activity or Fragment\n Started, // Visible\n Resumed, // Has focus\n Paused,\n Stopped, // No longer visible\n Detached, // Removed from an Activity or Fragment\n Destroyed,\n}\n\nexport interface FragmentOptions {\n parent?: Activity | Fragment\n}\n\n/**\n * `FragmentManager` is the class responsible for performing actions\n * on the app's fragments, such as adding, removing, or replacing them\n * and adding them to the back stack.\n */\nexport class FragmentManager {\n /**\n * Stores fragments by I\n */\n private fragments = new Map<string, Fragment>()\n /**\n * The reference to the host activity or fragment.\n */\n private host: Activity | Fragment\n\n constructor(host: Activity | Fragment) {\n this.host = host\n }\n\n async onDestroy(): Promise<void> {\n // Clean up all fragments when the host is destroyed\n for (const [key, fragment] of this.fragments) {\n await fragment.onDestroy()\n this.removeFragmentStyles(fragment)\n this.fragments.delete(key)\n }\n }\n\n /**\n * Attaches a fragment to a parent Activity or Fragment\n *\n * @param fragment The fragment to add.\n * @param parent The parent fragment or activity.\n * @param renderTarget Optional DOM target to render to.\n * @param data Optional data to pass to the `onCreate()` method.\n */\n async attachFragment(key: string, fragment: Fragment, parent: Activity | Fragment, data?: unknown): Promise<void> {\n // Ensure fragment has correct parent\n fragment.parent = parent\n\n this.fragments.set(key, fragment)\n await fragment.onCreate(data)\n fragment.state = FragmentState.Created\n await fragment.onAttach(data)\n fragment.state = FragmentState.Attached\n }\n\n /**\n * Detaches a fragment from its parent.\n * @param fragment\n * @returns\n */\n async detachFragment(key: string): Promise<void> {\n const fragment = this.findFragment(key)\n if (!fragment) {\n throw new Error(`Fragment with key ${key} not found.`)\n }\n\n this.hideFragment(fragment)\n await fragment.onDetach()\n fragment.state = FragmentState.Detached\n await fragment.onDestroy()\n fragment.state = FragmentState.Destroyed\n this.fragments.delete(key)\n // Clear parent reference\n fragment.parent = undefined\n }\n\n /**\n * Shows a Fragment (calls lifecycle methods and renders)\n * @param fragment The fragment to render.\n * @param renderTarget Optional render target, if any.\n */\n async showFragment(key: string, renderTarget?: HTMLElement): Promise<void> {\n const fragment = this.findFragment(key)\n if (!fragment) {\n throw new Error(`Fragment with key ${key} not found.`)\n }\n if (fragment.state === FragmentState.Resumed) {\n return\n }\n // Tell the fragment it is now started.\n await fragment.onStart()\n fragment.state = FragmentState.Started\n await fragment.onResume()\n fragment.state = FragmentState.Resumed\n if (renderTarget) {\n fragment.setRenderRoot(renderTarget)\n fragment.requestUpdate({ app: false, activity: false })\n } else {\n this.host.requestUpdate({ app: false, activity: true })\n }\n this.setFragmentStyles(fragment)\n }\n\n /**\n * Sets styles for a fragment by adding a class to the root element.\n * This is useful for applying specific styles to fragments.\n *\n * The root element is either fragment's render root or the document element.\n * @param fragment The fragment to set styles for.\n */\n setFragmentStyles(fragment: Fragment): void {\n const root = fragment.renderer.renderRoot ?? document?.documentElement\n if (!root) {\n return\n }\n const classes: string[] = []\n const ctor = fragment.constructor\n classes.push(ctor.name.toLowerCase())\n if (typeof fragment.rootClass === 'function') {\n const className = fragment.rootClass()\n if (className) {\n classes.push(className)\n }\n }\n root.classList.add(...classes)\n }\n\n /**\n * Removes styles for a fragment by removing a class from the root element.\n * This is useful for cleaning up styles when a fragment is no longer visible.\n *\n * The root element is either fragment's render root or the document element.\n * @param fragment The fragment to remove styles for.\n */\n removeFragmentStyles(fragment: Fragment): void {\n const root = fragment.renderer.renderRoot ?? document?.documentElement\n if (!root) {\n return\n }\n const classes: string[] = []\n const ctor = fragment.constructor\n classes.push(ctor.name.toLowerCase())\n if (typeof fragment.rootClass === 'function') {\n const className = fragment.rootClass()\n if (className) {\n classes.push(className)\n }\n }\n root.classList.remove(...classes)\n }\n\n /**\n * Lists all visible fragments, that is in the fragments with the `FragmentState.Resumed` state.\n * @returns The list of visible fragments\n */\n getVisible(): Fragment[] {\n return Array.from(this.fragments.values()).filter((fragment) => fragment.state === FragmentState.Resumed)\n }\n\n /**\n * Hides a Fragment (calls lifecycle methods and removes from DOM if necessary)\n */\n async hideFragment(fragment: Fragment): Promise<void> {\n await fragment.onPause()\n fragment.state = FragmentState.Paused\n await fragment.onStop()\n fragment.state = FragmentState.Stopped\n this.removeFragmentStyles(fragment)\n // if necessary, you would remove its template content from the DOM\n // however, with rendering logic encapsulated in Fragment, this isn't needed here\n }\n\n findFragment(key: string): Fragment | undefined {\n return this.fragments.get(key)\n }\n\n renderFragment(key: string): TemplateResult | typeof nothing {\n const fragment = this.findFragment(key)\n if (!fragment || fragment.state !== FragmentState.Resumed) {\n return nothing\n }\n return fragment.render() || nothing\n }\n\n updateActiveFragments(): void {\n for (const [, fragment] of this.fragments) {\n if ([FragmentState.Started, FragmentState.Resumed].includes(fragment.state)) {\n fragment.requestUpdate({ app: false, activity: false })\n }\n }\n }\n\n /**\n * Finds a fragment by activity request code.\n * @param requestCode The request code to find the fragment by.\n * @returns The corresponding fragment or `null`.\n */\n findByRequestCode(requestCode: number): Fragment | null {\n for (const [, fragment] of this.fragments) {\n if (fragment.hasRequestCode(requestCode)) {\n return fragment\n }\n }\n return null\n }\n}\n"]}
1
+ {"version":3,"file":"FragmentManager.js","sourceRoot":"","sources":["../../../src/core/FragmentManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,OAAO,EAAE,MAAM,KAAK,CAAA;AAIlD,MAAM,CAAN,IAAY,aAUX;AAVD,WAAY,aAAa;IACvB,+DAAW,CAAA;IACX,uDAAO,CAAA;IACP,yDAAQ,CAAA;IACR,uDAAO,CAAA;IACP,uDAAO,CAAA;IACP,qDAAM,CAAA;IACN,uDAAO,CAAA;IACP,yDAAQ,CAAA;IACR,2DAAS,CAAA;AACX,CAAC,EAVW,aAAa,KAAb,aAAa,QAUxB;AAMD;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAC1B;;OAEG;IACK,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAA;IAC/C;;OAEG;IACK,IAAI,CAAqB;IAEjC,YAAY,IAAyB;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAED,KAAK,CAAC,SAAS;QACb,oDAAoD;QACpD,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC7C,MAAM,QAAQ,CAAC,SAAS,EAAE,CAAA;YAC1B,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAA;YACnC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,cAAc,CAAC,GAAW,EAAE,QAAkB,EAAE,MAA2B,EAAE,IAAc;QAC/F,qCAAqC;QACrC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAA;QAExB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QACjC,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC7B,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,OAAO,CAAA;QACtC,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC7B,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAA;IACzC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,cAAc,CAAC,GAAW;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,aAAa,CAAC,CAAA;QACxD,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;QAC3B,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAA;QACzB,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAA;QACvC,MAAM,QAAQ,CAAC,SAAS,EAAE,CAAA;QAC1B,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,SAAS,CAAA;QACxC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC1B,yBAAyB;QACzB,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAA;IAC7B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,GAAW,EAAE,YAA0B;QACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,aAAa,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,QAAQ,CAAC,KAAK,KAAK,aAAa,CAAC,OAAO,EAAE,CAAC;YAC7C,OAAM;QACR,CAAC;QACD,uCAAuC;QACvC,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAA;QACxB,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,OAAO,CAAA;QACtC,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAA;QACzB,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,OAAO,CAAA;QACtC,IAAI,YAAY,EAAE,CAAC;YACjB,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;YACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QACzD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAClC,CAAC;IAED;;;;;;OAMG;IACH,iBAAiB,CAAC,QAAkB;QAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,IAAI,QAAQ,EAAE,eAAe,CAAA;QACtE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAA;QACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACrC,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAA;YACtC,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;IAChC,CAAC;IAED;;;;;;OAMG;IACH,oBAAoB,CAAC,QAAkB;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,IAAI,QAAQ,EAAE,eAAe,CAAA;QACtE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAA;QACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACrC,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAA;YACtC,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACzB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAA;IACnC,CAAC;IAED;;;OAGG;IACH,UAAU;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,KAAK,aAAa,CAAC,OAAO,CAAC,CAAA;IAC3G,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,QAA2B;QAC5C,IAAI,GAAyB,CAAA;QAC7B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;QACnC,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,QAAoB,CAAA;QAC5B,CAAC;QACD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAA;QACvC,CAAC;QACD,MAAM,GAAG,CAAC,OAAO,EAAE,CAAA;QACnB,GAAG,CAAC,KAAK,GAAG,aAAa,CAAC,MAAM,CAAA;QAChC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAA;QAClB,GAAG,CAAC,KAAK,GAAG,aAAa,CAAC,OAAO,CAAA;QACjC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAA;QAC9B,mEAAmE;QACnE,iFAAiF;IACnF,CAAC;IAED,YAAY,CAAC,GAAW;QACtB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAChC,CAAC;IAED,cAAc,CAAC,GAAW;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,KAAK,KAAK,aAAa,CAAC,OAAO,EAAE,CAAC;YAC1D,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,OAAO,QAAQ,CAAC,MAAM,EAAE,IAAI,OAAO,CAAA;IACrC,CAAC;IAED,qBAAqB;QACnB,KAAK,MAAM,CAAC,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC1C,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5E,QAAQ,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;YACzD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,iBAAiB,CAAC,WAAmB;QACnC,KAAK,MAAM,CAAC,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC1C,IAAI,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;gBACzC,OAAO,QAAQ,CAAA;YACjB,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;CACF","sourcesContent":["import { type TemplateResult, nothing } from 'lit'\nimport type { Activity } from './Activity.js'\nimport type { Fragment } from './Fragment.js'\n\nexport enum FragmentState {\n Initialized,\n Created,\n Attached, // Added to an Activity or Fragment\n Started, // Visible\n Resumed, // Has focus\n Paused,\n Stopped, // No longer visible\n Detached, // Removed from an Activity or Fragment\n Destroyed,\n}\n\nexport interface FragmentOptions {\n parent?: Activity | Fragment\n}\n\n/**\n * `FragmentManager` is the class responsible for performing actions\n * on the app's fragments, such as adding, removing, or replacing them\n * and adding them to the back stack.\n */\nexport class FragmentManager {\n /**\n * Stores fragments by I\n */\n private fragments = new Map<string, Fragment>()\n /**\n * The reference to the host activity or fragment.\n */\n private host: Activity | Fragment\n\n constructor(host: Activity | Fragment) {\n this.host = host\n }\n\n async onDestroy(): Promise<void> {\n // Clean up all fragments when the host is destroyed\n for (const [key, fragment] of this.fragments) {\n await fragment.onDestroy()\n this.removeFragmentStyles(fragment)\n this.fragments.delete(key)\n }\n }\n\n /**\n * Attaches a fragment to a parent Activity or Fragment\n *\n * @param fragment The fragment to add.\n * @param parent The parent fragment or activity.\n * @param renderTarget Optional DOM target to render to.\n * @param data Optional data to pass to the `onCreate()` method.\n */\n async attachFragment(key: string, fragment: Fragment, parent: Activity | Fragment, data?: unknown): Promise<void> {\n // Ensure fragment has correct parent\n fragment.parent = parent\n\n this.fragments.set(key, fragment)\n await fragment.onCreate(data)\n fragment.state = FragmentState.Created\n await fragment.onAttach(data)\n fragment.state = FragmentState.Attached\n }\n\n /**\n * Detaches a fragment from its parent.\n * @param fragment\n * @returns\n */\n async detachFragment(key: string): Promise<void> {\n const fragment = this.findFragment(key)\n if (!fragment) {\n throw new Error(`Fragment with key ${key} not found.`)\n }\n\n this.hideFragment(fragment)\n await fragment.onDetach()\n fragment.state = FragmentState.Detached\n await fragment.onDestroy()\n fragment.state = FragmentState.Destroyed\n this.fragments.delete(key)\n // Clear parent reference\n fragment.parent = undefined\n }\n\n /**\n * Shows a Fragment (calls lifecycle methods and renders)\n * @param fragment The fragment to render.\n * @param renderTarget Optional render target, if any.\n */\n async showFragment(key: string, renderTarget?: HTMLElement): Promise<void> {\n const fragment = this.findFragment(key)\n if (!fragment) {\n throw new Error(`Fragment with key ${key} not found.`)\n }\n if (fragment.state === FragmentState.Resumed) {\n return\n }\n // Tell the fragment it is now started.\n await fragment.onStart()\n fragment.state = FragmentState.Started\n await fragment.onResume()\n fragment.state = FragmentState.Resumed\n if (renderTarget) {\n fragment.setRenderRoot(renderTarget)\n fragment.requestUpdate({ app: false, activity: false })\n } else {\n this.host.requestUpdate({ app: false, activity: true })\n }\n this.setFragmentStyles(fragment)\n }\n\n /**\n * Sets styles for a fragment by adding a class to the root element.\n * This is useful for applying specific styles to fragments.\n *\n * The root element is either fragment's render root or the document element.\n * @param fragment The fragment to set styles for.\n */\n setFragmentStyles(fragment: Fragment): void {\n const root = fragment.renderer.renderRoot ?? document?.documentElement\n if (!root) {\n return\n }\n const classes: string[] = []\n const ctor = fragment.constructor\n classes.push(ctor.name.toLowerCase())\n if (typeof fragment.rootClass === 'function') {\n const className = fragment.rootClass()\n if (className) {\n classes.push(className)\n }\n }\n root.classList.add(...classes)\n }\n\n /**\n * Removes styles for a fragment by removing a class from the root element.\n * This is useful for cleaning up styles when a fragment is no longer visible.\n *\n * The root element is either fragment's render root or the document element.\n * @param fragment The fragment to remove styles for.\n */\n removeFragmentStyles(fragment: Fragment): void {\n const root = fragment.renderer.renderRoot ?? document?.documentElement\n if (!root) {\n return\n }\n const classes: string[] = []\n const ctor = fragment.constructor\n classes.push(ctor.name.toLowerCase())\n if (typeof fragment.rootClass === 'function') {\n const className = fragment.rootClass()\n if (className) {\n classes.push(className)\n }\n }\n root.classList.remove(...classes)\n }\n\n /**\n * Lists all visible fragments, that is in the fragments with the `FragmentState.Resumed` state.\n * @returns The list of visible fragments\n */\n getVisible(): Fragment[] {\n return Array.from(this.fragments.values()).filter((fragment) => fragment.state === FragmentState.Resumed)\n }\n\n /**\n * Hides a Fragment (calls lifecycle methods and removes from DOM if necessary)\n */\n async hideFragment(fragment: Fragment | string): Promise<void> {\n let ref: Fragment | undefined\n if (typeof fragment === 'string') {\n ref = this.findFragment(fragment)\n } else {\n ref = fragment as Fragment\n }\n if (!ref) {\n throw new Error(`Fragment not found`)\n }\n await ref.onPause()\n ref.state = FragmentState.Paused\n await ref.onStop()\n ref.state = FragmentState.Stopped\n this.removeFragmentStyles(ref)\n // if necessary, you would remove its template content from the DOM\n // however, with rendering logic encapsulated in Fragment, this isn't needed here\n }\n\n findFragment(key: string): Fragment | undefined {\n return this.fragments.get(key)\n }\n\n renderFragment(key: string): TemplateResult | typeof nothing {\n const fragment = this.findFragment(key)\n if (!fragment || fragment.state !== FragmentState.Resumed) {\n return nothing\n }\n return fragment.render() || nothing\n }\n\n updateActiveFragments(): void {\n for (const [, fragment] of this.fragments) {\n if ([FragmentState.Started, FragmentState.Resumed].includes(fragment.state)) {\n fragment.requestUpdate({ app: false, activity: false })\n }\n }\n }\n\n /**\n * Finds a fragment by activity request code.\n * @param requestCode The request code to find the fragment by.\n * @returns The corresponding fragment or `null`.\n */\n findByRequestCode(requestCode: number): Fragment | null {\n for (const [, fragment] of this.fragments) {\n if (fragment.hasRequestCode(requestCode)) {\n return fragment\n }\n }\n return null\n }\n}\n"]}
@@ -1,5 +1,12 @@
1
1
  import type { Fragment } from '../Fragment.js';
2
2
  import { Renderer } from './Renderer.js';
3
+ /**
4
+ * FragmentRenderer is responsible for rendering a Fragment instance.
5
+ * It extends the Renderer class and implements the rendering logic specific to Fragments.
6
+ *
7
+ * The fragment must decide how to render itself. Event when a fragment is a host
8
+ * and it only shows a single child, it still needs to render that child.
9
+ */
3
10
  export declare class FragmentRenderer extends Renderer {
4
11
  protected fragment: Fragment;
5
12
  constructor(fragment: Fragment);
@@ -1 +1 @@
1
- {"version":3,"file":"FragmentRenderer.d.ts","sourceRoot":"","sources":["../../../../src/core/renderer/FragmentRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,qBAAa,gBAAiB,SAAQ,QAAQ;IAChC,SAAS,CAAC,QAAQ,EAAE,QAAQ;gBAAlB,QAAQ,EAAE,QAAQ;IAIxC,SAAS,CAAC,QAAQ,IAAI,IAAI;CAe3B"}
1
+ {"version":3,"file":"FragmentRenderer.d.ts","sourceRoot":"","sources":["../../../../src/core/renderer/FragmentRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,QAAQ;IAChC,SAAS,CAAC,QAAQ,EAAE,QAAQ;gBAAlB,QAAQ,EAAE,QAAQ;IAIxC,SAAS,CAAC,QAAQ,IAAI,IAAI;CAc3B"}
@@ -1,4 +1,11 @@
1
1
  import { Renderer } from './Renderer.js';
2
+ /**
3
+ * FragmentRenderer is responsible for rendering a Fragment instance.
4
+ * It extends the Renderer class and implements the rendering logic specific to Fragments.
5
+ *
6
+ * The fragment must decide how to render itself. Event when a fragment is a host
7
+ * and it only shows a single child, it still needs to render that child.
8
+ */
2
9
  export class FragmentRenderer extends Renderer {
3
10
  fragment;
4
11
  constructor(fragment) {
@@ -11,10 +18,9 @@ export class FragmentRenderer extends Renderer {
11
18
  // return quietly. Fragments can be rendered directly.
12
19
  return;
13
20
  }
14
- const host = this.fragment.getSingleVisibleFragment() ?? this.fragment;
21
+ const host = this.fragment;
15
22
  if (!this.firstRendered) {
16
23
  this.firstRenderedFlag = true;
17
- // cleanup any pre-existing content.
18
24
  this._clearRoot(root);
19
25
  queueMicrotask(() => host.onFirstRender());
20
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FragmentRenderer.js","sourceRoot":"","sources":["../../../../src/core/renderer/FragmentRenderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,OAAO,gBAAiB,SAAQ,QAAQ;IACtB;IAAtB,YAAsB,QAAkB;QACtC,KAAK,EAAE,CAAA;QADa,aAAQ,GAAR,QAAQ,CAAU;IAExC,CAAC;IAES,QAAQ;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAA;QAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,sDAAsD;YACtD,OAAM;QACR,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,wBAAwB,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAA;QACtE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;YAC7B,oCAAoC;YACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YACrB,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;QAC5C,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACzC,CAAC;CACF","sourcesContent":["import type { Fragment } from '../Fragment.js'\nimport { Renderer } from './Renderer.js'\n\nexport class FragmentRenderer extends Renderer {\n constructor(protected fragment: Fragment) {\n super()\n }\n\n protected renderer(): void {\n const root = this.renderRoot\n if (!root) {\n // return quietly. Fragments can be rendered directly.\n return\n }\n const host = this.fragment.getSingleVisibleFragment() ?? this.fragment\n if (!this.firstRendered) {\n this.firstRenderedFlag = true\n // cleanup any pre-existing content.\n this._clearRoot(root)\n queueMicrotask(() => host.onFirstRender())\n }\n this._render(host.render(), root, host)\n }\n}\n"]}
1
+ {"version":3,"file":"FragmentRenderer.js","sourceRoot":"","sources":["../../../../src/core/renderer/FragmentRenderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC;;;;;;GAMG;AACH,MAAM,OAAO,gBAAiB,SAAQ,QAAQ;IACtB;IAAtB,YAAsB,QAAkB;QACtC,KAAK,EAAE,CAAA;QADa,aAAQ,GAAR,QAAQ,CAAU;IAExC,CAAC;IAES,QAAQ;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAA;QAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,sDAAsD;YACtD,OAAM;QACR,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC1B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;YAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YACrB,cAAc,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;QAC5C,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACzC,CAAC;CACF","sourcesContent":["import type { Fragment } from '../Fragment.js'\nimport { Renderer } from './Renderer.js'\n\n/**\n * FragmentRenderer is responsible for rendering a Fragment instance.\n * It extends the Renderer class and implements the rendering logic specific to Fragments.\n *\n * The fragment must decide how to render itself. Event when a fragment is a host\n * and it only shows a single child, it still needs to render that child.\n */\nexport class FragmentRenderer extends Renderer {\n constructor(protected fragment: Fragment) {\n super()\n }\n\n protected renderer(): void {\n const root = this.renderRoot\n if (!root) {\n // return quietly. Fragments can be rendered directly.\n return\n }\n const host = this.fragment\n if (!this.firstRendered) {\n this.firstRenderedFlag = true\n this._clearRoot(root)\n queueMicrotask(() => host.onFirstRender())\n }\n this._render(host.render(), root, host)\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@api-client/ui",
3
- "version": "0.5.34",
3
+ "version": "0.5.36",
4
4
  "description": "Internal UI component library for the API Client ecosystem.",
5
5
  "license": "UNLICENSED",
6
6
  "main": "build/src/index.js",
@@ -7,6 +7,7 @@ import { Intent, IntentResult } from './ActivityManager.js'
7
7
  import { bound } from '../decorators/bound.js'
8
8
  import type { ActivityDetail, ActivityWithResultDetail } from '../events/IntentEvents.js'
9
9
  import { EventTypes } from '../events/EventTypes.js'
10
+ import { type RefOrCallback } from 'lit/directives/ref.js'
10
11
 
11
12
  export interface PendingActivityResult {
12
13
  onResult(result: IntentResult, intent: Intent): void
@@ -209,17 +210,42 @@ export class Fragment extends EventTarget {
209
210
  }
210
211
  }
211
212
 
213
+ /**
214
+ * Creates a RefCallback that can be used with lit's `ref()` directive
215
+ * to automatically show/hide a child fragment when its container element
216
+ * is added or removed from the DOM.
217
+ *
218
+ * @param key The key of the child fragment to manage.
219
+ * @returns A RefCallback to be used with the `ref()` directive.
220
+ *
221
+ * @example
222
+ * // In your parent fragment's render method:
223
+ * html`<div ${ref(this.createFragmentRef('my-child-fragment'))}></div>`
224
+ */
225
+ createFragmentRef(key: string): RefOrCallback<Element> {
226
+ return (element?: Element) => {
227
+ if (element) {
228
+ this.fragmentManager.showFragment(key, element as HTMLElement)
229
+ } else {
230
+ const fragment = this.fragmentManager.findFragment(key)
231
+ if (fragment) {
232
+ this.fragmentManager.hideFragment(fragment)
233
+ }
234
+ }
235
+ }
236
+ }
237
+
212
238
  /**
213
239
  * A helper to request an update.
214
240
  * Application or parent Fragment will handle rendering.
215
241
  */
216
242
  requestUpdate(opts: UpdateRequest = {}): void {
217
- const { fragment = true } = opts
218
- if (fragment) {
219
- this.#renderer.requestUpdate()
243
+ if (opts.fragment !== false) {
244
+ this.renderer.requestUpdate()
245
+ }
246
+ if (this.parent && (opts.activity || opts.app)) {
247
+ this.parent.requestUpdate(opts)
220
248
  }
221
- this.parent?.requestUpdate(opts)
222
- // If no parent, do nothing (or maybe throw an error?)
223
249
  }
224
250
 
225
251
  getApplication(): Application | undefined {
@@ -172,12 +172,21 @@ export class FragmentManager {
172
172
  /**
173
173
  * Hides a Fragment (calls lifecycle methods and removes from DOM if necessary)
174
174
  */
175
- async hideFragment(fragment: Fragment): Promise<void> {
176
- await fragment.onPause()
177
- fragment.state = FragmentState.Paused
178
- await fragment.onStop()
179
- fragment.state = FragmentState.Stopped
180
- this.removeFragmentStyles(fragment)
175
+ async hideFragment(fragment: Fragment | string): Promise<void> {
176
+ let ref: Fragment | undefined
177
+ if (typeof fragment === 'string') {
178
+ ref = this.findFragment(fragment)
179
+ } else {
180
+ ref = fragment as Fragment
181
+ }
182
+ if (!ref) {
183
+ throw new Error(`Fragment not found`)
184
+ }
185
+ await ref.onPause()
186
+ ref.state = FragmentState.Paused
187
+ await ref.onStop()
188
+ ref.state = FragmentState.Stopped
189
+ this.removeFragmentStyles(ref)
181
190
  // if necessary, you would remove its template content from the DOM
182
191
  // however, with rendering logic encapsulated in Fragment, this isn't needed here
183
192
  }
@@ -1,6 +1,13 @@
1
1
  import type { Fragment } from '../Fragment.js'
2
2
  import { Renderer } from './Renderer.js'
3
3
 
4
+ /**
5
+ * FragmentRenderer is responsible for rendering a Fragment instance.
6
+ * It extends the Renderer class and implements the rendering logic specific to Fragments.
7
+ *
8
+ * The fragment must decide how to render itself. Event when a fragment is a host
9
+ * and it only shows a single child, it still needs to render that child.
10
+ */
4
11
  export class FragmentRenderer extends Renderer {
5
12
  constructor(protected fragment: Fragment) {
6
13
  super()
@@ -12,10 +19,9 @@ export class FragmentRenderer extends Renderer {
12
19
  // return quietly. Fragments can be rendered directly.
13
20
  return
14
21
  }
15
- const host = this.fragment.getSingleVisibleFragment() ?? this.fragment
22
+ const host = this.fragment
16
23
  if (!this.firstRendered) {
17
24
  this.firstRenderedFlag = true
18
- // cleanup any pre-existing content.
19
25
  this._clearRoot(root)
20
26
  queueMicrotask(() => host.onFirstRender())
21
27
  }
@@ -1,6 +1,6 @@
1
1
  import { assert } from '@esm-bundle/chai'
2
2
  import sinon from 'sinon'
3
- import { fixture, html } from '@open-wc/testing'
3
+ import { fixture, html, nextFrame } from '@open-wc/testing'
4
4
  import { Fragment } from '../../src/core/Fragment.js'
5
5
  import { Activity } from '../../src/core/Activity.js'
6
6
  import { Application } from '../../src/core/Application.js'
@@ -8,8 +8,9 @@ import { FragmentState, FragmentManager } from '../../src/core/FragmentManager.j
8
8
  import { IntentResult, type Intent, ActivityLifecycle } from '../../src/core/ActivityManager.js'
9
9
  import { FragmentRenderer } from '../../src/core/renderer/FragmentRenderer.js'
10
10
  import { EventTypes } from '../../src/events/EventTypes.js'
11
- import { nothing } from 'lit'
11
+ import { nothing, render } from 'lit'
12
12
  import type { ActivityDetail } from '../../src/events/IntentEvents.js'
13
+ import { ref } from 'lit/directives/ref.js'
13
14
 
14
15
  class TestActivity extends Activity {
15
16
  static override action = 'test-activity'
@@ -273,6 +274,35 @@ describe('Fragment', () => {
273
274
  })
274
275
  })
275
276
 
277
+ describe('createFragmentRef()', () => {
278
+ it('shows and hides a fragment via lit ref directive', async () => {
279
+ const childFragment = new TestFragment()
280
+ await fragment.addChild('childKey', childFragment)
281
+
282
+ const showSpy = sinon.spy(fragment['fragmentManager'], 'showFragment')
283
+ const hideSpy = sinon.spy(fragment['fragmentManager'], 'hideFragment')
284
+ // When the element is removed, the ref callback is called with `undefined`.
285
+ // The implementation then calls `findFragment` to get the fragment instance.
286
+ sinon.stub(fragment['fragmentManager'], 'findFragment').withArgs('childKey').returns(childFragment)
287
+ const root = document.createElement('div')
288
+ document.body.appendChild(root)
289
+ const tpl1 = html`<div class="target" ${ref(fragment.createFragmentRef('childKey'))}></div>`
290
+ render(tpl1, root)
291
+
292
+ const childDiv = root.querySelector<HTMLElement>('div')!
293
+
294
+ assert.isTrue(showSpy.calledOnce, 'showFragment should be called on render')
295
+ assert.isTrue(showSpy.calledWith('childKey', childDiv), 'showFragment called with correct arguments')
296
+
297
+ // Re-render without the ref to trigger disconnection
298
+ render(html`<span></span>`, root)
299
+ await nextFrame()
300
+ assert.isTrue(hideSpy.calledOnce, 'hideFragment should be called on removal')
301
+ assert.isTrue(hideSpy.calledWith(childFragment), 'hideFragment called with correct fragment instance')
302
+ assert.isNull(root.querySelector('div'), 'Target div should be removed from DOM')
303
+ })
304
+ })
305
+
276
306
  describe('requestUpdate()', () => {
277
307
  it('calls renderer.requestUpdate by default', () => {
278
308
  const rendererSpy = sinon.spy(fragment.renderer, 'requestUpdate')
@@ -288,7 +318,7 @@ describe('Fragment', () => {
288
318
 
289
319
  it('calls parent.requestUpdate', () => {
290
320
  const parentRequestUpdateSpy = sinon.spy(fragment.parent!, 'requestUpdate')
291
- const opts = { app: false }
321
+ const opts = { app: false, activity: true }
292
322
  fragment.requestUpdate(opts)
293
323
  assert.isTrue(parentRequestUpdateSpy.calledOnceWith(opts))
294
324
  })