@salesforcedevs/arch-components 1.20.17-alpha12 → 1.20.17-alpha13
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.
- package/package.json +1 -1
- package/src/modules/arch/context/context.html +1 -0
- package/src/modules/arch/context/context.ts +137 -0
- package/src/modules/arch/effectAdapter/effectAdapter.html +1 -0
- package/src/modules/arch/effectAdapter/effectAdapter.ts +18 -0
- package/src/modules/arch/reflectedElement/reflectedElement.ts +50 -0
- package/src/modules/arch/slot/slot.ts +20 -0
- package/src/modules/arch/alert/alert.css +0 -103
- package/src/modules/arch/alert/alert.html +0 -37
- package/src/modules/arch/alert/alert.ts +0 -137
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template></template>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ContextConsumer,
|
|
3
|
+
createContextProvider,
|
|
4
|
+
Contextualizer,
|
|
5
|
+
LightningElement,
|
|
6
|
+
wire,
|
|
7
|
+
WireAdapter
|
|
8
|
+
} from 'lwc';
|
|
9
|
+
|
|
10
|
+
import { EffectAdapter } from 'common/effectAdapter';
|
|
11
|
+
|
|
12
|
+
export interface ContextWireAdapter<Value, Config, Context>
|
|
13
|
+
extends WireAdapter<Value, Config, Context> {
|
|
14
|
+
value: Value;
|
|
15
|
+
}
|
|
16
|
+
export interface ContextWireAdapterConstructor<Value, Config, Context> {
|
|
17
|
+
new (setValue: (value: Value) => void): ContextWireAdapter<
|
|
18
|
+
Value,
|
|
19
|
+
Config,
|
|
20
|
+
Context
|
|
21
|
+
>;
|
|
22
|
+
setGlobalContext(context: Context): void;
|
|
23
|
+
setDefaultValue(value: Value): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createContextAdapter<Value, Config, Context>(
|
|
27
|
+
initDefaultValue: () => Value,
|
|
28
|
+
schema: Record<keyof Context, string>
|
|
29
|
+
): ContextWireAdapterConstructor<Value, Config, Context> {
|
|
30
|
+
const adapters = new Set<ContextWireAdapter<Value, Config, Context>>();
|
|
31
|
+
|
|
32
|
+
let globalContext: Context;
|
|
33
|
+
let defaultValue: Value;
|
|
34
|
+
|
|
35
|
+
return class ContextAdapter
|
|
36
|
+
implements ContextWireAdapter<Value, Config, Context>
|
|
37
|
+
{
|
|
38
|
+
static contextSchema = schema;
|
|
39
|
+
|
|
40
|
+
static setGlobalContext(context: Context) {
|
|
41
|
+
globalContext = context;
|
|
42
|
+
(adapters as Set<ContextAdapter>).forEach((adapter) =>
|
|
43
|
+
adapter.setValue(adapter.value)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static setDefaultValue(value: Value) {
|
|
48
|
+
defaultValue = value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
constructor(public setValue: (value: Value) => void) {
|
|
52
|
+
if (!defaultValue) {
|
|
53
|
+
defaultValue = initDefaultValue();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private config?: Config;
|
|
58
|
+
private context?: Context;
|
|
59
|
+
|
|
60
|
+
get value(): Value {
|
|
61
|
+
return {
|
|
62
|
+
...defaultValue,
|
|
63
|
+
...compactConfig<Context>(globalContext),
|
|
64
|
+
...compactConfig<Context>(this.context),
|
|
65
|
+
...compactConfig<Config>(this.config)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
connect() {
|
|
70
|
+
adapters.add(this);
|
|
71
|
+
this.setValue(this.value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
disconnect() {
|
|
75
|
+
adapters.delete(this);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
update(config: Config, context?: Context) {
|
|
79
|
+
this.config = config;
|
|
80
|
+
this.context = context;
|
|
81
|
+
this.setValue(this.value);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function compactConfig<T>(config?: T) {
|
|
87
|
+
return Object.fromEntries(
|
|
88
|
+
Object.entries({ ...config }).filter(
|
|
89
|
+
([key, value]) => typeof value !== 'undefined' && value !== null
|
|
90
|
+
)
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function createBaseContextProviderElement<Value, Config, Context>(
|
|
95
|
+
adapterClass: ContextWireAdapterConstructor<Value, Config, Context>
|
|
96
|
+
) {
|
|
97
|
+
const contextualizer = createContextProvider(adapterClass);
|
|
98
|
+
|
|
99
|
+
return class ProviderElement extends BaseProvider<Context> {
|
|
100
|
+
public get contextualizer() {
|
|
101
|
+
return contextualizer;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class BaseProvider<Context> extends LightningElement {
|
|
107
|
+
private consumers = new Set<ContextConsumer<Context>>();
|
|
108
|
+
|
|
109
|
+
public get contextualizer(): Contextualizer<Context> {
|
|
110
|
+
throw new Error('contextualizer not implenented');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@wire(EffectAdapter, {
|
|
114
|
+
localContext: '$localContext'
|
|
115
|
+
})
|
|
116
|
+
private updateConsumers({ localContext }: { localContext: Context }) {
|
|
117
|
+
for (let consumer of this.consumers) {
|
|
118
|
+
consumer.provide(localContext);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public get localContext(): Context {
|
|
123
|
+
return {} as Context;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
connectedCallback() {
|
|
127
|
+
this.contextualizer!(this, {
|
|
128
|
+
consumerConnectedCallback: (consumer) => {
|
|
129
|
+
this.consumers.add(consumer);
|
|
130
|
+
consumer.provide(this.localContext);
|
|
131
|
+
},
|
|
132
|
+
consumerDisconnectedCallback: (consumer) => {
|
|
133
|
+
this.consumers.delete(consumer);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template></template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { WireAdapter } from 'lwc';
|
|
2
|
+
|
|
3
|
+
export type EffectAdapterConfig<T> = {};
|
|
4
|
+
|
|
5
|
+
export class EffectAdapter<T>
|
|
6
|
+
implements
|
|
7
|
+
WireAdapter<EffectAdapterConfig<T>, EffectAdapterConfig<T>, void>
|
|
8
|
+
{
|
|
9
|
+
constructor(private setValue: (value: EffectAdapterConfig<T>) => void) {}
|
|
10
|
+
|
|
11
|
+
connect() {}
|
|
12
|
+
|
|
13
|
+
disconnect() {}
|
|
14
|
+
|
|
15
|
+
update(config: EffectAdapterConfig<T>) {
|
|
16
|
+
this.setValue(config);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* This element copies the innerHTML of the host (Light DOM)
|
|
4
|
+
* to the innerHTML of the element (Shadow DOM) returned by
|
|
5
|
+
* contentElement() (which must use the lwc:dom="manual" directive).
|
|
6
|
+
*/
|
|
7
|
+
import { LightningElement } from 'lwc';
|
|
8
|
+
|
|
9
|
+
export class ReflectedElement extends LightningElement {
|
|
10
|
+
private observer!: MutationObserver;
|
|
11
|
+
private didSetContent = false;
|
|
12
|
+
|
|
13
|
+
get contentElement(): Element {
|
|
14
|
+
throw new Error('Not Implemented');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
connectedCallback() {
|
|
18
|
+
this.observer = new MutationObserver((e) => {
|
|
19
|
+
this.setContent();
|
|
20
|
+
});
|
|
21
|
+
this.observer.observe(this.template.host, {
|
|
22
|
+
characterData: true,
|
|
23
|
+
childList: true,
|
|
24
|
+
subtree: true
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
disconnectedCallback() {
|
|
29
|
+
this.observer.disconnect();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
innerHTMLSetCallback() {}
|
|
33
|
+
|
|
34
|
+
renderedCallback() {
|
|
35
|
+
if (!this.didSetContent) {
|
|
36
|
+
this.didSetContent = true;
|
|
37
|
+
this.setContent();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
transformHTML(html: string): string {
|
|
42
|
+
return html;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private setContent() {
|
|
46
|
+
const element = this.contentElement;
|
|
47
|
+
element.innerHTML = this.transformHTML(this.template.host.innerHTML);
|
|
48
|
+
this.innerHTMLSetCallback();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function assignedSlotNames(template: {
|
|
2
|
+
querySelectorAll(selector: string): NodeList;
|
|
3
|
+
}) {
|
|
4
|
+
let slots = Array.from(
|
|
5
|
+
template.querySelectorAll('slot')
|
|
6
|
+
) as HTMLSlotElement[];
|
|
7
|
+
return slots
|
|
8
|
+
.filter(isSlotAssigned)
|
|
9
|
+
.map((slot) => slot.getAttribute('name') || 'default');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isSlotAssigned(slot: HTMLSlotElement): boolean {
|
|
13
|
+
let [element] = slot.assignedElements();
|
|
14
|
+
if (element) {
|
|
15
|
+
if (element.tagName === 'SLOT')
|
|
16
|
+
return isSlotAssigned(element as HTMLSlotElement);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return slot.children.length > 0;
|
|
20
|
+
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
@import "dxHelpers/reset";
|
|
2
|
-
@import "dxHelpers/text";
|
|
3
|
-
|
|
4
|
-
:host {
|
|
5
|
-
--dx-c-alert-top: 0;
|
|
6
|
-
--dx-c-alert-container-align-items: flex-start;
|
|
7
|
-
--dx-c-alert-vertical-padding: var(--dx-g-spacing-md);
|
|
8
|
-
--dx-c-alert-success-color: var(--dx-g-green-vibrant-95);
|
|
9
|
-
--dx-c-alert-warning-color: rgb(254 243 217);
|
|
10
|
-
--dx-c-alert-danger-color: var(--dx-g-red-vibrant-95);
|
|
11
|
-
--dx-c-alert-success-accent-color: var(--dx-g-green-vibrant-80);
|
|
12
|
-
--dx-c-alert-warning-accent-color: var(--dx-g-yellow-vibrant-80);
|
|
13
|
-
--dx-c-alert-danger-accent-color: var(--dx-g-red-vibrant-50);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.alert-icon {
|
|
17
|
-
margin-right: var(--dx-g-spacing-md);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.alert-base {
|
|
21
|
-
padding: var(--dx-c-alert-vertical-padding);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.alert-container {
|
|
25
|
-
display: flex;
|
|
26
|
-
flex-direction: column;
|
|
27
|
-
align-items: var(--dx-c-alert-container-align-items);
|
|
28
|
-
padding-left: var(--dx-g-global-header-padding-horizontal);
|
|
29
|
-
padding-right: var(--dx-g-global-header-padding-horizontal);
|
|
30
|
-
width: 100%;
|
|
31
|
-
border: none;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.alert-container.alert-type-success {
|
|
35
|
-
background-color: var(--dx-c-alert-success-color);
|
|
36
|
-
border-color: var(--dx-c-alert-success-accent-color);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.alert-container.alert-type-warning {
|
|
40
|
-
background-color: var(--dx-c-alert-warning-color);
|
|
41
|
-
border-color: var(--dx-c-alert-warning-accent-color);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.alert-container.alert-type-danger {
|
|
45
|
-
background-color: var(--dx-c-alert-danger-color);
|
|
46
|
-
border-color: var(--dx-c-alert-danger-accent-color);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.alert-container.alert-variant-accented {
|
|
50
|
-
border-style: solid;
|
|
51
|
-
border-width: 0;
|
|
52
|
-
border-left-width: 4px;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.alert-title-container {
|
|
56
|
-
display: flex;
|
|
57
|
-
flex-direction: row;
|
|
58
|
-
align-items: center;
|
|
59
|
-
width: 100%;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.alert-title {
|
|
63
|
-
font-weight: var(--dx-g-font-bold);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
dx-button {
|
|
67
|
-
margin-left: auto;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/*
|
|
71
|
-
NOTE: Here we are assuming that indicator height won't go beyond 1000px.
|
|
72
|
-
|
|
73
|
-
It's one of the suggested way to achieve the expand/collapse animation
|
|
74
|
-
Ref: https://stackoverflow.com/a/41164095
|
|
75
|
-
|
|
76
|
-
Otherwise we need to change the height when user clicks on button
|
|
77
|
-
Ref: https://stackoverflow.com/a/11837673
|
|
78
|
-
*/
|
|
79
|
-
|
|
80
|
-
.alert-body {
|
|
81
|
-
display: block;
|
|
82
|
-
max-height: 1000px;
|
|
83
|
-
overflow: hidden;
|
|
84
|
-
padding-top: var(--dx-g-spacing-smd);
|
|
85
|
-
transition: max-height 0.25s ease, padding 0.25s ease;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.alert-body-hidden {
|
|
89
|
-
max-height: 0;
|
|
90
|
-
padding-top: 0;
|
|
91
|
-
transition: max-height 0.1s ease-out, padding 0.25s ease-out;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.alert-body a {
|
|
95
|
-
color: var(--dx-g-blue-vibrant-50);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/* Small Devices */
|
|
99
|
-
@media screen and (max-width: 480px) {
|
|
100
|
-
.alert-container {
|
|
101
|
-
padding: var(--dx-c-alert-vertical-padding);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class={className} part="container">
|
|
3
|
-
<div class="alert-title-container">
|
|
4
|
-
<dx-icon
|
|
5
|
-
class="alert-icon"
|
|
6
|
-
symbol={iconName}
|
|
7
|
-
sprite={iconSprite}
|
|
8
|
-
size="large"
|
|
9
|
-
color={iconColor}
|
|
10
|
-
></dx-icon>
|
|
11
|
-
<p class="alert-title dx-text-body-3">{alertTitle}</p>
|
|
12
|
-
<dx-button
|
|
13
|
-
lwc:if={hideable}
|
|
14
|
-
variant="inline"
|
|
15
|
-
onclick={onShowHide}
|
|
16
|
-
aria-label={hideBodyText}
|
|
17
|
-
>
|
|
18
|
-
{hideBodyText}
|
|
19
|
-
</dx-button>
|
|
20
|
-
<dx-button
|
|
21
|
-
lwc:if={dismissible}
|
|
22
|
-
aria-label="Dismiss"
|
|
23
|
-
icon-color="status-icon-color"
|
|
24
|
-
icon-size="large"
|
|
25
|
-
icon-symbol="close"
|
|
26
|
-
onclick={onDismiss}
|
|
27
|
-
variant="icon-only"
|
|
28
|
-
></dx-button>
|
|
29
|
-
</div>
|
|
30
|
-
<!--
|
|
31
|
-
NOTE: Here we are rendering mark up using lwc:dom & innerHTML
|
|
32
|
-
option instead of slots because the html markup will come as a
|
|
33
|
-
property to the component from a configuration
|
|
34
|
-
-->
|
|
35
|
-
<span lwc:dom="manual" class={bodyClassName}></span>
|
|
36
|
-
</div>
|
|
37
|
-
</template>
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { LightningElement, api } from "lwc";
|
|
2
|
-
import cx from "classnames";
|
|
3
|
-
|
|
4
|
-
import { AlertInfo } from "typings/custom";
|
|
5
|
-
import { toJson } from "dxUtils/normalizers";
|
|
6
|
-
|
|
7
|
-
export default class Alert extends LightningElement {
|
|
8
|
-
_alertInfo: AlertInfo | null = null;
|
|
9
|
-
_dismissible = false;
|
|
10
|
-
_iconName = "";
|
|
11
|
-
_iconSprite = "";
|
|
12
|
-
_iconColor = "";
|
|
13
|
-
@api control: "none" | "hideable" | "dismissible" = "none";
|
|
14
|
-
@api type: "success" | "warning" | "danger" = "warning";
|
|
15
|
-
@api variant: "base" | "accented" = "base";
|
|
16
|
-
|
|
17
|
-
@api
|
|
18
|
-
get alertInfo(): AlertInfo | null {
|
|
19
|
-
return this._alertInfo;
|
|
20
|
-
}
|
|
21
|
-
set alertInfo(value) {
|
|
22
|
-
this._alertInfo = toJson(value);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@api
|
|
26
|
-
get iconColor(): string {
|
|
27
|
-
return this._iconColor || this.variant === "base"
|
|
28
|
-
? "gray-10"
|
|
29
|
-
: this.accentedIconColor;
|
|
30
|
-
}
|
|
31
|
-
set iconColor(value) {
|
|
32
|
-
if (value) {
|
|
33
|
-
this._iconColor = value;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@api
|
|
38
|
-
get iconName(): string {
|
|
39
|
-
return this._iconName || this.type === "success"
|
|
40
|
-
? "check-circle"
|
|
41
|
-
: "warning";
|
|
42
|
-
}
|
|
43
|
-
set iconName(value) {
|
|
44
|
-
if (value) {
|
|
45
|
-
this._iconName = value;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@api
|
|
50
|
-
get iconSprite(): string {
|
|
51
|
-
return this._iconSprite || this.type === "success"
|
|
52
|
-
? "general"
|
|
53
|
-
: "utility";
|
|
54
|
-
}
|
|
55
|
-
set iconSprite(value) {
|
|
56
|
-
if (value) {
|
|
57
|
-
this._iconSprite = value;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
get accentedIconColor() {
|
|
62
|
-
const baseColor =
|
|
63
|
-
this.type === "danger"
|
|
64
|
-
? "red"
|
|
65
|
-
: this.type === "warning"
|
|
66
|
-
? "yellow"
|
|
67
|
-
: "green";
|
|
68
|
-
return `${baseColor}-vibrant-50`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
get dismissible(): boolean {
|
|
72
|
-
return this.control === "dismissible";
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
get hideable(): boolean {
|
|
76
|
-
return this.control === "hideable";
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
get alertTitle() {
|
|
80
|
-
return this.alertInfo?.title;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
get hideBodyText() {
|
|
84
|
-
return this.isBodyHidden ? "Show" : "Hide";
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get alertType() {
|
|
88
|
-
return this.type || "warning";
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
get alertVariant() {
|
|
92
|
-
return this.variant || "base";
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
get className() {
|
|
96
|
-
return cx(
|
|
97
|
-
"alert-base",
|
|
98
|
-
"alert-container",
|
|
99
|
-
`alert-variant-${this.alertVariant}`,
|
|
100
|
-
`alert-type-${this.alertType}`
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
get bodyClassName() {
|
|
105
|
-
return cx(
|
|
106
|
-
"alert-body",
|
|
107
|
-
"dx-text-body-3",
|
|
108
|
-
this.isBodyHidden && "alert-body-hidden"
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
isBodyHidden = false;
|
|
113
|
-
|
|
114
|
-
renderedCallback() {
|
|
115
|
-
const phaseBodyContainer = this.template.querySelector(".alert-body");
|
|
116
|
-
if (phaseBodyContainer && this.alertInfo) {
|
|
117
|
-
// eslint-disable-next-line @lwc/lwc/no-inner-html
|
|
118
|
-
phaseBodyContainer.innerHTML = this.alertInfo.body;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
onShowHide() {
|
|
123
|
-
this.isBodyHidden = !this.isBodyHidden;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
onDismiss() {
|
|
127
|
-
this.dispatchEvent(
|
|
128
|
-
new CustomEvent("dismissphase", {
|
|
129
|
-
detail: {
|
|
130
|
-
alertInfo: this.alertInfo
|
|
131
|
-
},
|
|
132
|
-
composed: true,
|
|
133
|
-
bubbles: true
|
|
134
|
-
})
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
}
|