@@ -46,10 +46,18 @@ export interface ElementControllerStrategy {
4646 new ( element : HTMLElement , definition : FASTElementDefinition ) : ElementController ;
4747}
4848
49- const enum Stages {
49+ /**
50+ * The various lifecycle stages of an ElementController.
51+ * @public
52+ */
53+ export const enum Stages {
54+ /** The element is in the process of connecting. */
5055 connecting ,
56+ /** The element is connected. */
5157 connected ,
58+ /** The element is in the process of disconnecting. */
5259 disconnecting ,
60+ /** The element is disconnected. */
5361 disconnected ,
5462}
5563
@@ -61,24 +69,58 @@ export class ElementController<TElement extends HTMLElement = HTMLElement>
6169 extends PropertyChangeNotifier
6270 implements HostController < TElement >
6371{
72+ /**
73+ * A map of observable properties that were set on the element before upgrade.
74+ */
6475 private boundObservables : Record < string , any > | null = null ;
76+
77+ /**
78+ * Indicates whether the controller needs to perform initial rendering.
79+ */
6580 protected needsInitialization : boolean = true ;
66- private hasExistingShadowRoot = false ;
81+
82+ /**
83+ * Indicates whether the element has an existing shadow root (e.g. from declarative shadow DOM).
84+ */
85+ protected hasExistingShadowRoot = false ;
86+
87+ /**
88+ * The template used to render the component.
89+ */
6790 private _template : ElementViewTemplate < TElement > | null = null ;
91+
92+ /**
93+ * The shadow root options for the component.
94+ */
6895 private _shadowRootOptions : ShadowRootOptions | undefined ;
96+
97+ /**
98+ * The current lifecycle stage of the controller.
99+ */
69100 protected stage : Stages = Stages . disconnected ;
101+
70102 /**
71103 * A guard against connecting behaviors multiple times
72104 * during connect in scenarios where a behavior adds
73105 * another behavior during it's connectedCallback
74106 */
75107 private guardBehaviorConnection = false ;
108+
109+ /**
110+ * The behaviors associated with the component.
111+ */
76112 protected behaviors : Map < HostBehavior < TElement > , number > | null = null ;
113+
77114 /**
78115 * Tracks whether behaviors are connected so that
79116 * behaviors cant be connected multiple times
80117 */
81118 private behaviorsConnected : boolean = false ;
119+
120+ /**
121+ * The main set of styles used for the component, independent of any
122+ * dynamically added styles.
123+ */
82124 private _mainStyles : ElementStyles | null = null ;
83125
84126 /**
@@ -173,6 +215,9 @@ export class ElementController<TElement extends HTMLElement = HTMLElement>
173215 }
174216 }
175217
218+ /**
219+ * The shadow root options for the component.
220+ */
176221 public get shadowOptions ( ) : ShadowRootOptions | undefined {
177222 return this . _shadowRootOptions ;
178223 }
@@ -409,6 +454,9 @@ export class ElementController<TElement extends HTMLElement = HTMLElement>
409454 Observable . notify ( this , isConnectedPropertyName ) ;
410455 }
411456
457+ /**
458+ * Binds any observables that were set before upgrade.
459+ */
412460 protected bindObservables ( ) {
413461 if ( this . boundObservables !== null ) {
414462 const element = this . source ;
@@ -424,6 +472,9 @@ export class ElementController<TElement extends HTMLElement = HTMLElement>
424472 }
425473 }
426474
475+ /**
476+ * Connects any existing behaviors on the associated element.
477+ */
427478 protected connectBehaviors ( ) {
428479 if ( this . behaviorsConnected === false ) {
429480 const behaviors = this . behaviors ;
@@ -440,6 +491,9 @@ export class ElementController<TElement extends HTMLElement = HTMLElement>
440491 }
441492 }
442493
494+ /**
495+ * Disconnects any behaviors on the associated element.
496+ */
443497 protected disconnectBehaviors ( ) {
444498 if ( this . behaviorsConnected === true ) {
445499 const behaviors = this . behaviors ;
@@ -514,6 +568,13 @@ export class ElementController<TElement extends HTMLElement = HTMLElement>
514568 return false ;
515569 }
516570
571+ /**
572+ * Renders the provided template to the element.
573+ *
574+ * @param template - The template to render.
575+ * @remarks
576+ * If `null` is provided, any existing view will be removed.
577+ */
517578 protected renderTemplate ( template : ElementViewTemplate | null | undefined ) : void {
518579 // When getting the host to render to, we start by looking
519580 // up the shadow root. If there isn't one, then that means
@@ -750,7 +811,16 @@ if (ElementStyles.supportsAdoptedStyleSheets) {
750811 ElementStyles . setDefaultStrategy ( StyleElementStrategy ) ;
751812}
752813
814+ /**
815+ * The attribute used to defer hydration of an element.
816+ * @public
817+ */
753818export const deferHydrationAttribute = "defer-hydration" ;
819+
820+ /**
821+ * The attribute used to indicate that an element needs hydration.
822+ * @public
823+ */
754824export const needsHydrationAttribute = "needs-hydration" ;
755825
756826/**
@@ -793,6 +863,24 @@ export class HydratableElementController<
793863 HydratableElementController . hydrationObserverHandler
794864 ) ;
795865
866+ /**
867+ * {@inheritdoc ElementController.shadowOptions }
868+ */
869+ public get shadowOptions ( ) : ShadowRootOptions | undefined {
870+ return super . shadowOptions ;
871+ }
872+
873+ public set shadowOptions ( value : ShadowRootOptions | undefined ) {
874+ super . shadowOptions = value ;
875+ if (
876+ this . hasExistingShadowRoot &&
877+ this . definition . templateOptions === TemplateOptions . deferAndHydrate
878+ ) {
879+ this . source . toggleAttribute ( deferHydrationAttribute , true ) ;
880+ this . source . toggleAttribute ( needsHydrationAttribute , true ) ;
881+ }
882+ }
883+
796884 /**
797885 * Lifecycle callbacks for hydration events
798886 */
@@ -864,28 +952,13 @@ export class HydratableElementController<
864952 }
865953 }
866954
867- public static forCustomElement (
868- element : HTMLElement ,
869- override ?: boolean
870- ) : ElementController < HTMLElement > {
871- const definition = FASTElementDefinition . getForInstance ( element ) ;
872-
873- if (
874- definition ?. templateOptions === TemplateOptions . deferAndHydrate &&
875- ! definition . template
876- ) {
877- element . toggleAttribute ( deferHydrationAttribute , true ) ;
878- element . toggleAttribute ( needsHydrationAttribute , true ) ;
879- }
880-
881- return super . forCustomElement ( element , override ) ;
882- }
883-
955+ /**
956+ * Runs connected lifecycle behavior on the associated element.
957+ */
884958 public connect ( ) {
885959 // Initialize needsHydration on first connect
886960 this . needsHydration =
887- this . needsHydration ??
888- this . source . getAttribute ( needsHydrationAttribute ) !== null ;
961+ this . needsHydration ?? this . source . hasAttribute ( needsHydrationAttribute ) ;
889962
890963 if ( this . needsHydration ) {
891964 HydratableElementController . lifecycleCallbacks ?. elementWillHydrate ?.(
@@ -1009,11 +1082,20 @@ export class HydratableElementController<
10091082 }
10101083 }
10111084
1085+ /**
1086+ * Unregisters the hydration observer when the element is disconnected.
1087+ */
10121088 public disconnect ( ) {
10131089 super . disconnect ( ) ;
10141090 HydratableElementController . hydrationObserver . unobserve ( this . source ) ;
10151091 }
10161092
1093+ /**
1094+ * Sets the ElementController strategy to HydratableElementController.
1095+ * @remarks
1096+ * This method is typically called during application startup to enable
1097+ * hydration support for FAST elements.
1098+ */
10171099 public static install ( ) {
10181100 ElementController . setStrategy ( HydratableElementController ) ;
10191101 }
0 commit comments