Skip to content

Commit fe69f8a

Browse files
web: patternfly hints as ak-web-component
Patternfly 5's "Hints" React Component, but ported to web components. The discovery that CSS Custom Properties are still available in child components, even if they're within independent ShadowDOMs, made this fairly easy to port from Handlebars to Lit-HTML. Moving the definitions into `:host` and the applications into the root DIV of the component made duplicating the Patternfly 5 structure straightforward. Despite the [Patternfly Elements]documentation](https://patternflyelements.org/docs/develop/create/), there's a lot to Patternfly Elements that isn't well documented, such as their slot controller, which near as I can tell just makes it easy to determine if a slot with the given name is actually being used by the client code, but it's hard to tell why, other than that it provides an easy way to determine if some CSS should be included.
1 parent 7ac25e2 commit fe69f8a

File tree

7 files changed

+273
-0
lines changed

7 files changed

+273
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { MessageLevel } from "@goauthentik/common/messages";
2+
import "@goauthentik/components/ak-hint/ak-hint";
3+
import "@goauthentik/components/ak-hint/ak-hint-body";
4+
import { AKElement } from "@goauthentik/elements/Base";
5+
import "@goauthentik/elements/buttons/ActionButton/ak-action-button";
6+
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
7+
8+
import { html } from "lit";
9+
import { customElement } from "lit/decorators.js";
10+
11+
import PFPage from "@patternfly/patternfly/components/Page/page.css";
12+
13+
@customElement("ak-application-wizard-hint")
14+
export class AkApplicationWizardHint extends AKElement {
15+
static get styles() {
16+
return [PFPage];
17+
}
18+
19+
render() {
20+
return html` <section class="pf-c-page__main-section pf-m-no-padding-mobile">
21+
<ak-hint>
22+
<ak-hint-body>
23+
<p>
24+
Authentik has a new Application Wizard that can configure both an
25+
application and its authentication provider at the same time.
26+
<a href="(link to docs)">Learn more about the wizard here.</a>
27+
</p>
28+
<ak-action-button
29+
class="pf-m-secondary"
30+
.apiRequest=${() => {
31+
showMessage({
32+
message: "This would have shown the wizard",
33+
level: MessageLevel.success,
34+
});
35+
}}
36+
>Create with Wizard</ak-action-button
37+
></ak-hint-body
38+
>
39+
</ak-hint>
40+
</section>`;
41+
}
42+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { AKElement } from "@goauthentik/app/elements/Base";
2+
3+
import { css, html } from "lit";
4+
import { customElement } from "lit/decorators.js";
5+
6+
const style = css`
7+
div {
8+
display: inline-grid;
9+
grid-row: 1;
10+
grid-column: 2;
11+
grid-auto-flow: column;
12+
margin-left: var(--ak-hint__actions--MarginLeft);
13+
text-align: right;
14+
}
15+
16+
::slotted(ak-hint-body) {
17+
grid-column: 1;
18+
}
19+
`;
20+
21+
@customElement("ak-hint-actions")
22+
export class AkHintActions extends AKElement {
23+
get styles() {
24+
return [style];
25+
}
26+
27+
render() {
28+
return html`<div><slot></slot></div>`;
29+
}
30+
}
31+
32+
export default AkHintActions;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { AKElement } from "@goauthentik/app/elements/Base";
2+
3+
import { css, html } from "lit";
4+
import { customElement } from "lit/decorators.js";
5+
6+
const style = css`
7+
div {
8+
grid-column: 1 / -1;
9+
font-size: var(--ak-hint__body--FontSize);
10+
}
11+
`;
12+
13+
@customElement("ak-hint-body")
14+
export class AkHintBody extends AKElement {
15+
get styles() {
16+
return [style];
17+
}
18+
19+
render() {
20+
return html`<div><slot></slot></div>`;
21+
}
22+
}
23+
24+
export default AkHintBody;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { AKElement } from "@goauthentik/app/elements/Base";
2+
3+
import { css, html } from "lit";
4+
import { customElement } from "lit/decorators.js";
5+
6+
const style = css`
7+
#host {
8+
grid-column: 1 / -1;
9+
}
10+
::slotted(div#host > *:not(:last-child)) {
11+
margin-right: var(--ak-hint__footer--child--MarginRight);
12+
}
13+
`;
14+
15+
@customElement("ak-hint-footer")
16+
export class AkHintFooter extends AKElement {
17+
get styles() {
18+
return [style];
19+
}
20+
21+
render() {
22+
return html`<div id="host"><slot></slot></div>`;
23+
}
24+
}
25+
26+
export default AkHintFooter;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { AKElement } from "@goauthentik/app/elements/Base";
2+
3+
import { css, html } from "lit";
4+
import { customElement } from "lit/decorators.js";
5+
6+
const style = css`
7+
::slotted(*) {
8+
font-size: var(--ak-hint__title--FontSize);
9+
}
10+
`;
11+
12+
@customElement("ak-hint-title")
13+
export class AkHintTitle extends AKElement {
14+
get styles() {
15+
return [style];
16+
}
17+
18+
render() {
19+
return html`<div><slot></slot></div>`;
20+
}
21+
}
22+
23+
export default AkHintTitle;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { MessageLevel } from "@goauthentik/common/messages";
2+
import "@goauthentik/elements/buttons/ActionButton/ak-action-button";
3+
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
4+
import { Meta } from "@storybook/web-components";
5+
6+
import { TemplateResult, html } from "lit";
7+
8+
import "../ak-radio-input";
9+
import "./ak-hint";
10+
import AkHint from "./ak-hint";
11+
import "./ak-hint-body";
12+
import "./ak-hint-title";
13+
14+
const metadata: Meta<AkHint> = {
15+
title: "Components / Patternfly Hint",
16+
component: "ak-hint",
17+
parameters: {
18+
docs: {
19+
description: {
20+
component: "A stylized hint box",
21+
},
22+
},
23+
},
24+
};
25+
26+
export default metadata;
27+
28+
const container = (testItem: TemplateResult) =>
29+
html` <div style="background: #fff; padding: 2em">
30+
<style>
31+
li {
32+
display: block;
33+
}
34+
p {
35+
color: black;
36+
margin-top: 1em;
37+
}
38+
</style>
39+
40+
${testItem}
41+
42+
<ul id="radio-message-pad" style="margin-top: 1em"></ul>
43+
</div>`;
44+
45+
export const Default = () => {
46+
return container(
47+
html` <section class="pf-c-page__main-section pf-m-no-padding-mobile">
48+
<ak-hint>
49+
<ak-hint-body>
50+
<p style="padding-bottom: 1rem;">
51+
Authentik has a new Application Wizard that can configure both an
52+
application and its authentication provider at the same time.
53+
<a href="(link to docs)">Learn more about the wizard here.</a>
54+
</p>
55+
<ak-action-button
56+
class="pf-m-secondary"
57+
.apiRequest=${() => {
58+
showMessage({
59+
message: "This would have shown the wizard",
60+
level: MessageLevel.success,
61+
});
62+
}}
63+
>Create with Wizard</ak-action-button
64+
></ak-hint-body
65+
>
66+
</ak-hint>
67+
</section>`
68+
);
69+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { AKElement } from "@goauthentik/app/elements/Base";
2+
3+
import { css, html } from "lit";
4+
import { customElement } from "lit/decorators.js";
5+
6+
const styles = css`
7+
:host {
8+
--ak-hint--GridRowGap: var(--pf-global--spacer--md);
9+
--ak-hint--PaddingTop: var(--pf-global--spacer--lg);
10+
--ak-hint--PaddingRight: var(--pf-global--spacer--lg);
11+
--ak-hint--PaddingBottom: var(--pf-global--spacer--lg);
12+
--ak-hint--PaddingLeft: var(--pf-global--spacer--lg);
13+
--ak-hint--BackgroundColor: var(--pf-global--palette--blue-50);
14+
--ak-hint--BorderColor: var(--pf-global--palette--blue-100);
15+
--ak-hint--BorderWidth: var(--pf-global--BorderWidth--sm);
16+
--ak-hint--BoxShadow: var(--pf-global--BoxShadow--sm);
17+
--ak-hint--Color: var(--pf-global--Color--100);
18+
19+
// Hint Title
20+
--ak-hint__title--FontSize: var(--pf-global--FontSize--lg);
21+
22+
// Hint Body
23+
--ak-hint__body--FontSize: var(--pf-global--FontSize--md);
24+
25+
// Hint Footer
26+
--ak-hint__footer--child--MarginRight: var(--pf-global--spacer--md);
27+
28+
// Hint Actions
29+
--ak-hint__actions--MarginLeft: var(--pf-global--spacer--2xl);
30+
--ak-hint__actions--c-dropdown--MarginTop: calc(
31+
var(--pf-global--spacer--form-element) * -1
32+
);
33+
}
34+
35+
div#host {
36+
display: grid;
37+
grid-template-columns: 1fr auto;
38+
grid-row-gap: var(--ak-hint--GridRowGap);
39+
padding: var(--ak-hint--PaddingTop) var(--ak-hint--PaddingRight)
40+
var(--ak-hint--PaddingBottom) var(--ak-hint--PaddingLeft);
41+
color: var(--ak-hint--Color);
42+
background-color: var(--ak-hint--BackgroundColor);
43+
border: var(--ak-hint--BorderWidth) solid var(--ak-hint--BorderColor);
44+
box-shadow: var(--ak-hint--BoxShadow);
45+
}
46+
`;
47+
48+
@customElement("ak-hint")
49+
export class AkHint extends AKElement {
50+
static get styles() { return [styles]; }
51+
52+
render() {
53+
return html`<div id="host"><slot></slot></div>`;
54+
}
55+
}
56+
57+
export default AkHint;

0 commit comments

Comments
 (0)