Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b51838
## What
kensternberg-authentik Mar 18, 2026
0037547
Merge branch 'main' into dev
kensternberg-authentik Mar 20, 2026
7c60c42
Merge branch 'main' into dev
kensternberg-authentik Mar 23, 2026
b6d8df0
Merge branch 'main' into dev
kensternberg-authentik Mar 24, 2026
23536f9
Merge branch 'main' into dev
kensternberg-authentik Mar 25, 2026
7aa9920
Merge branch 'main' into dev
kensternberg-authentik Mar 26, 2026
631c3c7
Merge branch 'main' into dev
kensternberg-authentik Mar 26, 2026
7d7e2e9
Merge branch 'main' into dev
kensternberg-authentik Mar 30, 2026
3d40620
Merge branch 'main' into dev
kensternberg-authentik Mar 31, 2026
faf515e
Merge branch 'main' into dev
kensternberg-authentik Apr 1, 2026
380349a
Merge branch 'main' into dev
kensternberg-authentik Apr 2, 2026
ca6fd3d
Merge branch 'main' into dev
kensternberg-authentik Apr 2, 2026
118d34a
Merge branch 'main' into dev
kensternberg-authentik Apr 7, 2026
1a5f7b0
Merge branch 'main' into dev
kensternberg-authentik Apr 8, 2026
639f02a
Merge branch 'main' into dev
kensternberg-authentik Apr 10, 2026
0d0690a
Merge branch 'main' into dev
kensternberg-authentik Apr 28, 2026
2f5ad86
Merge branch 'main' into dev
kensternberg-authentik Apr 30, 2026
41e6a98
Merge branch 'main' into dev
kensternberg-authentik May 1, 2026
1860593
Merge branch 'main' into dev
kensternberg-authentik May 4, 2026
3e966ee
Merge branch 'main' into dev
kensternberg-authentik May 5, 2026
cc9c06d
Merge branch 'main' into dev
kensternberg-authentik May 6, 2026
44a1381
Merge branch 'web/element/new-drawer' into web/flow/expose-flow-in-li…
kensternberg-authentik May 6, 2026
da2424d
This commit puts the FlowExecutor into the lightDOM.
kensternberg-authentik May 6, 2026
a438eda
End-to-end lightDOM!
kensternberg-authentik May 6, 2026
da79d23
No idea what's happening here.
kensternberg-authentik May 6, 2026
19f3b80
Fix typo; ensure form is defined in global space.
kensternberg-authentik May 6, 2026
a3e9788
Prettier having opinions.
kensternberg-authentik May 6, 2026
72d42bc
Removed the helper.
kensternberg-authentik May 6, 2026
e751386
This commit puts the Login input sequence into the lightDOM.
kensternberg-authentik May 7, 2026
da98c6f
Merge branch 'main' into web/flow/expose-flow-in-lightdom
kensternberg-authentik May 7, 2026
43e035c
Merge branch 'main' into web/flow/expose-flow-in-lightdom
kensternberg-authentik May 7, 2026
3d38c5b
Some minor cleanup of Flow
kensternberg-authentik May 7, 2026
e65fbed
Merge branch 'web/element/new-drawer' into web/flow/expose-flow-in-li…
kensternberg-authentik May 7, 2026
8a1563c
Add the `part` detail to the overlay, so that it can be addressed by …
kensternberg-authentik May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions authentik/flows/templates/if/flow.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
<ak-skip-to-content></ak-skip-to-content>
<ak-message-container></ak-message-container>
<ak-drawer id="flow-drawer">
<ak-flow-executor
<ak-flow
slug="{{ flow.slug }}"
class="pf-c-login"
data-layout="{{ flow.layout|default:'stacked' }}"
Expand All @@ -57,7 +57,7 @@
{% include "base/placeholder.html" %}

<ak-brand-links name="flow-links" slot="footer"></ak-brand-links>
</ak-flow-executor>
</ak-flow>

<ak-flow-inspector
slot="panel"
Expand Down
114 changes: 114 additions & 0 deletions web/src/elements/directives/light.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { html, noChange, nothing, render, TemplateResult } from "lit";
import { AsyncDirective, DirectiveResult } from "lit/async-directive.js";
import { ChildPart, directive, PartInfo, PartType } from "lit/directive.js";
import { RootPart } from "lit/html.js";

export interface LightChildOptions {
// Optional alternative target for any `@event`-style handlers passed into the template. NOTE:
// this only works if the handlers do not already have a `this` bound to them, so only ordinary
// functions and methods will respond to this parameter; arrow function class fields and bound
// functions will use the `this` to which they were bound.

host?: Element;
slotName?: string;
}

class LightChildDirective extends AsyncDirective {
// These must remain public: the dependency tree of all of these leads to their being imported
// into parts of the DOM by the host, and TSC complains otherwise.

public slotName: string | null = null;
public slot: HTMLSlotElement | null = null;
public host: Element | null = null;
public rootPart: RootPart | null = null;
public sentinel: Comment | null = null;

constructor(partInfo: PartInfo) {
super(partInfo);
if (partInfo.type !== PartType.CHILD) {
throw new Error("The `light()` directive can only be use in child position");
}
}

// This is for SSR only.
render(_template?: TemplateResult | DirectiveResult, options?: LightChildOptions) {
this.slotName ??= options?.slotName ?? `lc-${Math.random().toString(36).slice(2, 8)}`;
return html`<slot name="${this.slotName}"></slot>`;
}

update(
part: ChildPart,
[template, options = {}]: [TemplateResult | DirectiveResult, LightChildOptions],
) {
this.slotName ??= options?.slotName ?? `lc-${Math.random().toString(36).slice(2, 8)}`;

// This places a comment in the LightDom that belongs to this directive. Comments are not
// part of the DOM tree for the purposes of CSS, so it will be possible to style this child
// directly without a wrapper.

if (!this.sentinel) {
const rootNode = part.parentNode.getRootNode();
this.host ??= (part.options?.host ||
(rootNode instanceof ShadowRoot ? rootNode.host : null)) as Element | null;

if (!this.host) {
throw new Error(
"light() must be used inside a shadow root or a valid options.host",
);
}

this.sentinel = document.createComment("");
this.host.appendChild(this.sentinel);
}

if (!this.sentinel.parentNode) {
throw new Error("Could not assign sentinel to element.");
}

const renderOptions = Object.fromEntries(
Object.entries(options).filter(([key]) => ["host"].includes(key)),
);

this.rootPart = render(template, this.sentinel.parentNode as HTMLElement, {
renderBefore: this.sentinel,
...renderOptions,
});

const rendered = this.sentinel.previousSibling;
if (rendered instanceof Element) {
rendered.slot = this.slotName;
}

if (!this.slot) {
this.slot = Object.assign(document.createElement("slot"), {
name: this.slotName,
});
return this.slot;
}

return noChange;
}

disconnected() {
if (this.sentinel?.parentNode && this.host?.isConnected) {
// The node that contains the directive has been disconnected, *not* the host. We need
// to clean up the associated lightDOM element.
render(nothing, this.sentinel.parentNode as HTMLElement, {
renderBefore: this.sentinel,
});
this.sentinel.remove();
this.sentinel = null;
this.rootPart = null;
return;
}

// The host has been disconnected. Inform any child components.
this.rootPart?.setConnected(false);
}

reconnected() {
this.rootPart?.setConnected(true);
}
}

export const light = directive(LightChildDirective);
11 changes: 11 additions & 0 deletions web/src/flow/Flow.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import "@patternfly/patternfly/components/Login/login.css";
import "#stories/flow-interface";
import "#flow/stages/dummy/DummyStage";

import { flowFactory } from "#stories/flow-interface";

export default {
title: "Flow / ak-flow-executor",
};

export const BackgroundImage = flowFactory("ak-stage-dummy");
Loading