@exmg/exm-form 1.1.35 → 1.1.37-alpha.31

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.
Files changed (25) hide show
  1. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form-base.d.ts +56 -0
  2. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form-base.js +190 -0
  3. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form-dirty-mixin.d.ts +10 -0
  4. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form-dirty-mixin.js +92 -0
  5. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form-validate-mixin.d.ts +10 -0
  6. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form-validate-mixin.js +66 -0
  7. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form.d.ts +10 -0
  8. package/.rollup.cache/root/repo/packages/exm-form/dist/exm-form.js +15 -0
  9. package/.rollup.cache/root/repo/packages/exm-form/dist/index.d.ts +6 -0
  10. package/.rollup.cache/root/repo/packages/exm-form/dist/index.js +7 -0
  11. package/.rollup.cache/root/repo/packages/exm-form/dist/styles/exm-form-base-css.d.ts +1 -0
  12. package/.rollup.cache/root/repo/packages/exm-form/dist/styles/exm-form-base-css.js +91 -0
  13. package/.rollup.cache/root/repo/packages/exm-form/dist/styles/exm-form-css.d.ts +1 -0
  14. package/.rollup.cache/root/repo/packages/exm-form/dist/styles/exm-form-css.js +59 -0
  15. package/.rollup.cache/root/repo/packages/exm-form/dist/utils/serializeFormData.d.ts +1 -0
  16. package/.rollup.cache/root/repo/packages/exm-form/dist/utils/serializeFormData.js +64 -0
  17. package/dist/exm-form-base.js +6 -3
  18. package/dist/exm-form-dirty-mixin.js +7 -6
  19. package/dist/exm-form-validate-mixin.js +8 -7
  20. package/dist/exm-form.js +4 -2
  21. package/dist/index.js +1 -1
  22. package/dist/styles/exm-form-base-css.js +5 -2
  23. package/dist/styles/exm-form-css.js +5 -2
  24. package/dist/utils/serializeFormData.js +4 -2
  25. package/package.json +3 -3
@@ -0,0 +1,56 @@
1
+ import '@exmg/exm-button/exm-text-button.js';
2
+ import '@material/web/button/outlined-button.js';
3
+ import '@material/web/button/filled-button.js';
4
+ import '@material/web/divider/divider.js';
5
+ import { ExmgElement } from '@exmg/lit-base';
6
+ declare const ExmFormBase_base: import("./exm-form-dirty-mixin.js").Constructor<import("./exm-form-dirty-mixin.js").FormDirtyMixinInterface> & import("./exm-form-validate-mixin.js").Constructor<import("./exm-form-validate-mixin.js").FormValidateMixinInterface> & typeof ExmgElement;
7
+ export declare class ExmFormBase extends ExmFormBase_base {
8
+ /**
9
+ * Submit button copy
10
+ */
11
+ submitBtn: string;
12
+ /**
13
+ * Cancel button copy
14
+ */
15
+ cancelBtn: string;
16
+ /**
17
+ * Hide cancel button
18
+ */
19
+ hideCancelButton: boolean;
20
+ /**
21
+ * Show reset button
22
+ */
23
+ showResetButton: boolean;
24
+ /**
25
+ * Disabled the submit,
26
+ */
27
+ disableSubmitButton?: boolean;
28
+ /**
29
+ * Internall used to show button spinner.
30
+ */
31
+ submitting: boolean;
32
+ boundHandleBlur?: (e: Event) => void;
33
+ boundHandleKeyup?: (e: Event) => void;
34
+ hasDescription: boolean;
35
+ hasHeader: boolean;
36
+ errorMessage?: string | null;
37
+ reset(): void;
38
+ submit(): void;
39
+ /**
40
+ * Action method that needs to be implemented
41
+ * @param {CustomEvent} e
42
+ */
43
+ doAction?(formData: unknown): Promise<void> | void;
44
+ protected handleSubmit(): Promise<void>;
45
+ showError(message: string): void;
46
+ slotHasContent(slot: HTMLSlotElement): boolean;
47
+ handleDescriptionSlotChange(event: CustomEvent): void;
48
+ handleHeaderSlotChange(event: CustomEvent): void;
49
+ protected renderToolbar(): import("lit-html").TemplateResult<1>;
50
+ renderFormContent(): import("lit-html").TemplateResult<1>;
51
+ protected renderDescription(): import("lit-html").TemplateResult<1>;
52
+ protected renderError(): import("lit-html").TemplateResult<1>;
53
+ protected renderActions(): import("lit-html").TemplateResult<1>;
54
+ protected render(): import("lit-html").TemplateResult<1>;
55
+ }
56
+ export {};
@@ -0,0 +1,190 @@
1
+ import { __decorate } from "tslib";
2
+ import { html, nothing } from 'lit';
3
+ import { property, state } from 'lit/decorators.js';
4
+ import '@exmg/exm-button/exm-text-button.js';
5
+ import '@material/web/button/outlined-button.js';
6
+ import '@material/web/button/filled-button.js';
7
+ import '@material/web/divider/divider.js';
8
+ import { ExmgElement } from '@exmg/lit-base';
9
+ import { classMap } from 'lit/directives/class-map.js';
10
+ import { ExmFormValidateMixin } from './exm-form-validate-mixin.js';
11
+ import { serializeFormData } from './utils/serializeFormData.js';
12
+ import { ExmFormDirtyMixin } from './exm-form-dirty-mixin.js';
13
+ export class ExmFormBase extends ExmFormDirtyMixin(ExmFormValidateMixin(ExmgElement)) {
14
+ constructor() {
15
+ super(...arguments);
16
+ /**
17
+ * Submit button copy
18
+ */
19
+ this.submitBtn = 'Save';
20
+ /**
21
+ * Cancel button copy
22
+ */
23
+ this.cancelBtn = 'Cancel';
24
+ /**
25
+ * Hide cancel button
26
+ */
27
+ this.hideCancelButton = false;
28
+ /**
29
+ * Show reset button
30
+ */
31
+ this.showResetButton = false;
32
+ /**
33
+ * Disabled the submit,
34
+ */
35
+ this.disableSubmitButton = false;
36
+ /**
37
+ * Internall used to show button spinner.
38
+ */
39
+ this.submitting = false;
40
+ this.hasDescription = false;
41
+ this.hasHeader = false;
42
+ }
43
+ reset() {
44
+ const form = this.getForm();
45
+ form === null || form === void 0 ? void 0 : form.reset();
46
+ }
47
+ submit() {
48
+ this.handleSubmit();
49
+ }
50
+ async handleSubmit() {
51
+ this.errorMessage = null;
52
+ const form = this.getForm();
53
+ // Check form validity
54
+ this.checkFormValidity();
55
+ // Return when there are invalid fields
56
+ if (!this.formValid) {
57
+ return;
58
+ }
59
+ // Serialize form data
60
+ const data = serializeFormData(form);
61
+ if (this.doAction) {
62
+ try {
63
+ this.submitting = true;
64
+ await this.doAction(data);
65
+ this.fire('form-success', null, true);
66
+ }
67
+ catch (error) {
68
+ this.showError(error instanceof Error ? error.message : 'Unknown error');
69
+ this.fire('form-error', { message: error instanceof Error ? error.message : 'Unknown error' }, true);
70
+ }
71
+ finally {
72
+ this.submitting = false;
73
+ this.fire('form-submit-finished', { success: !this.errorMessage });
74
+ }
75
+ }
76
+ else {
77
+ this.fire('form-submit', data, true);
78
+ }
79
+ }
80
+ showError(message) {
81
+ this.errorMessage = message;
82
+ }
83
+ slotHasContent(slot) {
84
+ const nodes = slot.assignedNodes({ flatten: true });
85
+ return nodes.length > 0;
86
+ }
87
+ handleDescriptionSlotChange(event) {
88
+ this.hasDescription = this.slotHasContent(event.target);
89
+ }
90
+ handleHeaderSlotChange(event) {
91
+ this.hasHeader = this.slotHasContent(event.target);
92
+ }
93
+ renderToolbar() {
94
+ return html `
95
+ <header class="toolbar-container">
96
+ <slot name="toolbar" @slotchange="${this.handleHeaderSlotChange}"></slot>
97
+ </header>
98
+ `;
99
+ }
100
+ renderFormContent() {
101
+ return html `
102
+ <section class="content">
103
+ <slot></slot>
104
+ </section>
105
+ `;
106
+ }
107
+ renderDescription() {
108
+ return html `
109
+ <section class="description">
110
+ <slot name="description" @slotchange="${this.handleDescriptionSlotChange}"></slot>
111
+ </section>
112
+ `;
113
+ }
114
+ renderError() {
115
+ return html `
116
+ <div class="form-error">
117
+ <div>${this.errorMessage}</div>
118
+ </div>
119
+ `;
120
+ }
121
+ renderActions() {
122
+ return html `
123
+ <footer class="actions">
124
+ ${this.showResetButton
125
+ ? html `
126
+ <md-icon-button ?disabled=${!this.dirty} @click=${this.reset}>
127
+ <md-icon>restart_alt</md-icon>
128
+ </md-icon-button>
129
+ `
130
+ : nothing}
131
+ ${this.hideCancelButton
132
+ ? nothing
133
+ : html `
134
+ <md-outlined-button dialogFocus @click=${() => this.fire('form-cancel')}>
135
+ ${this.cancelBtn}
136
+ </md-outlined-button>
137
+ `}
138
+ <md-filled-button
139
+ type="button"
140
+ @click=${this.handleSubmit}
141
+ ?disabled=${this.disableSubmitButton || this.submitting || !this.formValid}
142
+ ?loading=${this.submitting}
143
+ >
144
+ ${this.submitBtn}
145
+ </md-filled-button>
146
+ </footer>
147
+ `;
148
+ }
149
+ render() {
150
+ const classNames = {
151
+ 'has-description': this.hasDescription,
152
+ 'has-header': this.hasHeader,
153
+ 'has-error': !!this.errorMessage,
154
+ };
155
+ return html `
156
+ <article class="form-container ${classMap(classNames)}">
157
+ ${this.renderToolbar()} ${this.renderDescription()} ${this.errorMessage ? this.renderError() : nothing}
158
+ ${this.renderFormContent()} ${this.renderActions()}
159
+ </article>
160
+ `;
161
+ }
162
+ }
163
+ __decorate([
164
+ property({ type: String })
165
+ ], ExmFormBase.prototype, "submitBtn", void 0);
166
+ __decorate([
167
+ property({ type: String })
168
+ ], ExmFormBase.prototype, "cancelBtn", void 0);
169
+ __decorate([
170
+ property({ type: Boolean, attribute: 'hide-cancel-button' })
171
+ ], ExmFormBase.prototype, "hideCancelButton", void 0);
172
+ __decorate([
173
+ property({ type: Boolean, attribute: 'show-reset-button' })
174
+ ], ExmFormBase.prototype, "showResetButton", void 0);
175
+ __decorate([
176
+ property({ type: Boolean, attribute: 'disable-submit-button' })
177
+ ], ExmFormBase.prototype, "disableSubmitButton", void 0);
178
+ __decorate([
179
+ property({ type: Boolean })
180
+ ], ExmFormBase.prototype, "submitting", void 0);
181
+ __decorate([
182
+ state()
183
+ ], ExmFormBase.prototype, "hasDescription", void 0);
184
+ __decorate([
185
+ state()
186
+ ], ExmFormBase.prototype, "hasHeader", void 0);
187
+ __decorate([
188
+ property({ type: String })
189
+ ], ExmFormBase.prototype, "errorMessage", void 0);
190
+ //# sourceMappingURL=exm-form-base.js.map
@@ -0,0 +1,10 @@
1
+ import { LitElement } from 'lit';
2
+ export type Constructor<T> = new (...args: any[]) => T;
3
+ export declare class FormDirtyMixinClass extends LitElement {
4
+ }
5
+ export declare class FormDirtyMixinInterface {
6
+ dirty: boolean;
7
+ getForm(): HTMLFormElement | null;
8
+ takeFormDataSnapshot(): void;
9
+ }
10
+ export declare const ExmFormDirtyMixin: <T extends Constructor<LitElement & FormDirtyMixinClass>>(superClass: T) => Constructor<FormDirtyMixinInterface> & T;
@@ -0,0 +1,92 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement } from 'lit';
3
+ import { state } from 'lit/decorators.js';
4
+ export class FormDirtyMixinClass extends LitElement {
5
+ }
6
+ export const ExmFormDirtyMixin = (superClass) => {
7
+ class FormDirtyMixinElement extends superClass {
8
+ constructor(...args) {
9
+ super(...args);
10
+ this.dirty = false;
11
+ this.onFormChanged = this.updateDirtyState.bind(this);
12
+ }
13
+ getForm() {
14
+ var _a, _b;
15
+ return (_b = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('form')) !== null && _b !== void 0 ? _b : null;
16
+ }
17
+ getCurrentFormData() {
18
+ const form = this.getForm();
19
+ if (!form)
20
+ return;
21
+ return new FormData(form);
22
+ }
23
+ // NOTE: We have to compare formdata like this... we can't do a direct comparison unfortunately
24
+ formDataEquals(formData1, formData2) {
25
+ if (!formData1 || !formData2)
26
+ return false;
27
+ return JSON.stringify([...formData1]) === JSON.stringify([...formData2]);
28
+ }
29
+ fireDirtyChanged() {
30
+ this.dispatchEvent(new CustomEvent('form-dirty-changed', {
31
+ detail: this.dirty,
32
+ bubbles: true,
33
+ composed: true,
34
+ }));
35
+ }
36
+ async updateDirtyState() {
37
+ await this.updateComplete;
38
+ const current = this.getCurrentFormData();
39
+ if (!current)
40
+ return;
41
+ if (this.formDataEquals(current, this.formDataSnapshot)) {
42
+ this.resetDirtyState();
43
+ return;
44
+ }
45
+ if (!this.dirty) {
46
+ this.dirty = true;
47
+ this.fireDirtyChanged();
48
+ }
49
+ }
50
+ resetDirtyState() {
51
+ if (this.dirty) {
52
+ this.dirty = false;
53
+ this.fireDirtyChanged();
54
+ }
55
+ }
56
+ // NOTE: Sometimes we want to make a snapshot from a form on for example drawer open instead of on firstUpdated
57
+ takeFormDataSnapshot() {
58
+ const form = this.getForm();
59
+ if (!form)
60
+ return;
61
+ this.formDataSnapshot = new FormData(form);
62
+ }
63
+ async firstUpdated() {
64
+ var _a;
65
+ // @ts-ignore
66
+ (_a = super.firstUpdated) === null || _a === void 0 ? void 0 : _a.call(this);
67
+ await this.updateComplete;
68
+ const form = this.getForm();
69
+ if (!form)
70
+ return;
71
+ this.takeFormDataSnapshot();
72
+ form.addEventListener('input', this.onFormChanged);
73
+ form.addEventListener('change', this.onFormChanged);
74
+ form.addEventListener('reset', this.onFormChanged);
75
+ }
76
+ async disconnectedCallback() {
77
+ var _a;
78
+ const form = this.getForm();
79
+ if (form) {
80
+ form.removeEventListener('input', this.onFormChanged);
81
+ form.removeEventListener('change', this.onFormChanged);
82
+ form.removeEventListener('reset', this.onFormChanged);
83
+ }
84
+ (_a = super.disconnectedCallback) === null || _a === void 0 ? void 0 : _a.call(this);
85
+ }
86
+ }
87
+ __decorate([
88
+ state()
89
+ ], FormDirtyMixinElement.prototype, "dirty", void 0);
90
+ return FormDirtyMixinElement;
91
+ };
92
+ //# sourceMappingURL=exm-form-dirty-mixin.js.map
@@ -0,0 +1,10 @@
1
+ import { LitElement } from 'lit';
2
+ export type Constructor<T> = new (...args: any[]) => T;
3
+ export declare class FormValidateMixinClass extends LitElement {
4
+ }
5
+ export declare class FormValidateMixinInterface {
6
+ formValid: boolean;
7
+ getForm(): HTMLFormElement | null;
8
+ checkFormValidity(): void;
9
+ }
10
+ export declare const ExmFormValidateMixin: <T extends Constructor<LitElement & FormValidateMixinClass>>(superClass: T) => Constructor<FormValidateMixinInterface> & T;
@@ -0,0 +1,66 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement } from 'lit';
3
+ import { async, debounce } from '@exmg/lit-base/index.js';
4
+ import { state } from 'lit/decorators.js';
5
+ export class FormValidateMixinClass extends LitElement {
6
+ }
7
+ export const ExmFormValidateMixin = (superClass) => {
8
+ class FormvalidateMixinElement extends superClass {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.formValid = false;
12
+ }
13
+ getForm() {
14
+ return this === null || this === void 0 ? void 0 : this.shadowRoot.querySelector('form');
15
+ }
16
+ checkFormValidity() {
17
+ const form = this.getForm();
18
+ if (!form) {
19
+ return;
20
+ }
21
+ const formElements = form === null || form === void 0 ? void 0 : form.elements;
22
+ let allValid = true;
23
+ for (const el of formElements || []) {
24
+ let isValid = true;
25
+ // @ts-ignore
26
+ if (typeof el.reportValidity === 'function') {
27
+ // @ts-ignore
28
+ isValid = el.checkValidity();
29
+ }
30
+ if (!isValid) {
31
+ allValid = false;
32
+ }
33
+ }
34
+ this.formValid = allValid;
35
+ }
36
+ _handleInputChange(e) {
37
+ const target = e.target;
38
+ // Only check validation every 200ms max
39
+ this.debouncer = debounce.Debouncer.debounce(this.debouncer, async.timeOut.after(200), () => {
40
+ // @ts-ignore
41
+ typeof target.reportValidity === 'function' && target.reportValidity();
42
+ this.checkFormValidity();
43
+ });
44
+ }
45
+ async firstUpdated() {
46
+ const form = this.getForm();
47
+ if (!form) {
48
+ return;
49
+ }
50
+ this.boundHandleChange = this._handleInputChange.bind(this);
51
+ form.addEventListener('keyup', this.boundHandleChange, true);
52
+ form.addEventListener('input', this.boundHandleChange, true);
53
+ }
54
+ async disconnectedCallback() {
55
+ const form = this.getForm();
56
+ this.boundHandleChange && form.addEventListener('keyup', this.boundHandleChange, true);
57
+ this.boundHandleChange && form.addEventListener('input', this.boundHandleChange, true);
58
+ super.disconnectedCallback();
59
+ }
60
+ }
61
+ __decorate([
62
+ state()
63
+ ], FormvalidateMixinElement.prototype, "formValid", void 0);
64
+ return FormvalidateMixinElement;
65
+ };
66
+ //# sourceMappingURL=exm-form-validate-mixin.js.map
@@ -0,0 +1,10 @@
1
+ import { ExmFormBase } from './exm-form-base.js';
2
+ export declare class ExmForm extends ExmFormBase {
3
+ static styles: import("lit").CSSResult[];
4
+ getForm(): HTMLFormElement | null;
5
+ }
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ 'exm-form': ExmForm;
9
+ }
10
+ }
@@ -0,0 +1,15 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement } from 'lit/decorators.js';
3
+ import { style } from './styles/exm-form-base-css.js';
4
+ import { ExmFormBase } from './exm-form-base.js';
5
+ let ExmForm = class ExmForm extends ExmFormBase {
6
+ getForm() {
7
+ return this.querySelector('form');
8
+ }
9
+ };
10
+ ExmForm.styles = [style];
11
+ ExmForm = __decorate([
12
+ customElement('exm-form')
13
+ ], ExmForm);
14
+ export { ExmForm };
15
+ //# sourceMappingURL=exm-form.js.map
@@ -0,0 +1,6 @@
1
+ export { ExmForm } from './exm-form.js';
2
+ export { ExmFormValidateMixin, Constructor } from './exm-form-validate-mixin.js';
3
+ export { ExmFormBase } from './exm-form-base.js';
4
+ export { serializeFormData } from './utils/serializeFormData.js';
5
+ export { style as formStyles } from './styles/exm-form-css.js';
6
+ export { style as formBaseStyles } from './styles/exm-form-base-css.js';
@@ -0,0 +1,7 @@
1
+ export { ExmForm } from './exm-form.js';
2
+ export { ExmFormValidateMixin } from './exm-form-validate-mixin.js';
3
+ export { ExmFormBase } from './exm-form-base.js';
4
+ export { serializeFormData } from './utils/serializeFormData.js';
5
+ export { style as formStyles } from './styles/exm-form-css.js';
6
+ export { style as formBaseStyles } from './styles/exm-form-base-css.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ export declare const style: import("lit").CSSResult;
@@ -0,0 +1,91 @@
1
+ import { css } from 'lit';
2
+ export const style = css `
3
+ :host {
4
+ display: block;
5
+ --_exm-form-content-margin-left: var(--exm-form-content-margin-left, 0);
6
+ --_exm-form-container-margin-top: var(--exm-form-container-margin-top, 1rem);
7
+ --_exm-form-container-margin-bottom: var(--exm-form-container-margin-bottom, 1rem);
8
+ --_exm-form-divider-margin-top: var(--exm-form-divider-margin-top, 2rem);
9
+ --_exm-form-aside-font-size: var(--exm-form-aside-font-size, 0.875rem);
10
+ --_exm-form-aside-line-height: var(--exm-form-aside-line-height, 1.25rem);
11
+ --_exm-form-aside-letter-spacing: var(--exm-form-aside-letter-spacing, 0.0142857143em);
12
+ --_exm-form-aside-font-weight: var(--exm-form-aside-font-weight, 400);
13
+ --_exm-form-aside-margin-left: var(--exm-form-aside-margin-left, 1rem);
14
+ --_exm-form-aside-margin-right: var(--exm-form-aside-margin-right, 5rem);
15
+ --_exm-form-aside-min-width: var(--exm-form-aside-min-width, 180px);
16
+ }
17
+
18
+ .form-container {
19
+ display: grid;
20
+ grid-template-rows: auto auto auto 1fr auto;
21
+ height: 100%;
22
+ }
23
+
24
+ ::slotted(.toolbar) {
25
+ grid-area: 1/1/2/2;
26
+ display: none;
27
+ align-items: center;
28
+ padding: 0.5rem 1rem;
29
+ min-height: 3.5rem;
30
+ box-sizing: border-box;
31
+ }
32
+
33
+ ::slotted(.toolbar) .title {
34
+ line-height: 1.5rem;
35
+ font-size: 1rem;
36
+ letter-spacing: 0.00625em;
37
+ font-weight: 500;
38
+ color: var(--md-sys-color-on-surface);
39
+ box-sizing: border-box;
40
+ overflow-wrap: break-word;
41
+ }
42
+
43
+ .has-header ::slotted(.toolbar) {
44
+ display: flex;
45
+ }
46
+
47
+ .description {
48
+ grid-area: 2/1/3/2;
49
+ display: none;
50
+ padding: 0.5rem 1rem;
51
+ line-height: var(--_exm-form-aside-line-height);
52
+ font-size: var(--_exm-form-aside-font-size);
53
+ letter-spacing: var(--_exm-form-aside-letter-spacing);
54
+ font-weight: var(--_exm-form-aside-font-weight);
55
+ color: var(--_exm-form-aside-color, var(--md-sys-color-on-surface));
56
+ height: 100%;
57
+ }
58
+
59
+ .has-description .description {
60
+ display: initial;
61
+ }
62
+
63
+ .content {
64
+ grid-area: 4/1/5/2;
65
+ padding: 0.5rem 1rem;
66
+ overflow: auto;
67
+ }
68
+
69
+ .actions {
70
+ grid-area: 5/1/6/2;
71
+ display: flex;
72
+ padding: 1rem;
73
+ margin-top: 1rem;
74
+ gap: 0.5rem;
75
+ justify-content: flex-end;
76
+ border-top: 1px solid var(--md-sys-color-outline-variant);
77
+ }
78
+
79
+ .form-error {
80
+ grid-area: 3/1/4/2;
81
+ padding: 0.5rem 1rem;
82
+ }
83
+
84
+ .form-error > div {
85
+ padding: 1rem;
86
+ border-radius: 1rem;
87
+ background-color: var(--_exm-form-error-background, var(--md-sys-color-error-container, red));
88
+ color: var(--_exm-form-error-color, var(--md-sys-color-on-error-container, white));
89
+ }
90
+ `;
91
+ //# sourceMappingURL=exm-form-base-css.js.map
@@ -0,0 +1 @@
1
+ export declare const style: import("lit").CSSResult;
@@ -0,0 +1,59 @@
1
+ import { css } from 'lit';
2
+ export const style = css `
3
+ .section-title {
4
+ line-height: 1.5rem;
5
+ font-size: 1rem;
6
+ letter-spacing: 0.00625em;
7
+ font-weight: 500;
8
+ color: var(--_exm-form-title-color, var(--md-sys-color-on-surface));
9
+ padding-bottom: 8px;
10
+ }
11
+
12
+ form {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: 0.75rem;
16
+ width: 100%;
17
+ }
18
+
19
+ form > * {
20
+ display: contents;
21
+ }
22
+
23
+ form .row {
24
+ display: flex;
25
+ gap: 0.75rem;
26
+ }
27
+
28
+ form .row > * {
29
+ flex: 1;
30
+ height: fit-content;
31
+ }
32
+
33
+ .no-flex {
34
+ display: block;
35
+ }
36
+
37
+ .extra-margin {
38
+ margin-top: 2rem;
39
+ display: block;
40
+ }
41
+
42
+ label.checkbox {
43
+ display: flex;
44
+ justify-content: flex-start;
45
+ align-items: center;
46
+ font-size: 1rem;
47
+ font-weight: 500;
48
+ margin: 0.5rem 1rem;
49
+ }
50
+
51
+ label.checkbox md-checkbox {
52
+ margin-right: 1rem;
53
+ }
54
+
55
+ a {
56
+ color: var(--md-sys-color-primary);
57
+ }
58
+ `;
59
+ //# sourceMappingURL=exm-form-css.js.map
@@ -0,0 +1 @@
1
+ export declare const serializeFormData: (form: HTMLFormElement) => {};
@@ -0,0 +1,64 @@
1
+ export const serializeFormData = (form) => {
2
+ const obj = {};
3
+ const formElements = form === null || form === void 0 ? void 0 : form.elements;
4
+ const formElementsArray = Array.from(formElements);
5
+ /**
6
+ * Create list of checkbox elements. If no value is set the return value of the checkbox for 'on' will be a boolean
7
+ */
8
+ const checkboxNames = formElementsArray
9
+ .filter((input) => {
10
+ return input.value === 'on' && (input.type === 'checkbox' || input.tagName.toLowerCase().includes('checkbox'));
11
+ })
12
+ .map((input) => input.name);
13
+ /* Same for the radio items */
14
+ const radioNames = formElementsArray
15
+ .filter((input) => {
16
+ return input.type === 'radio' || input.tagName.toLowerCase().includes('radio');
17
+ })
18
+ .map((input) => input.name);
19
+ const numberNames = formElementsArray
20
+ .filter((input) => {
21
+ return input.type === 'number';
22
+ })
23
+ .map((input) => input.name);
24
+ const formData = new FormData(form);
25
+ for (const [key, value] of formData.entries()) {
26
+ if (Object.hasOwnProperty.call(obj, key)) {
27
+ if (!Array.isArray(obj[key])) {
28
+ obj[key] = [obj[key]];
29
+ }
30
+ obj[key].push(value);
31
+ continue;
32
+ }
33
+ if (numberNames.includes(key)) {
34
+ obj[key] = value ? parseFloat(`${value}`) : undefined;
35
+ continue;
36
+ }
37
+ // When set to on convert to boolean return value
38
+ // @ts-ignore
39
+ if (checkboxNames.includes(key)) {
40
+ obj[key] = value === 'on';
41
+ continue;
42
+ }
43
+ // Check for a default value of on for radio items to set to true, if not, set to the value
44
+ if (radioNames.includes(key)) {
45
+ if (value === 'on') {
46
+ obj[key] = value === 'on';
47
+ }
48
+ else {
49
+ obj[key] = value;
50
+ }
51
+ continue;
52
+ }
53
+ obj[key] = formData.get(key);
54
+ }
55
+ // All checkboxes that are not checked will not be included in the form data and need to return false
56
+ for (const name of checkboxNames) {
57
+ // check for
58
+ if (!Object.hasOwnProperty.call(obj, name)) {
59
+ obj[name] = false;
60
+ }
61
+ }
62
+ return obj;
63
+ };
64
+ //# sourceMappingURL=serializeFormData.js.map
@@ -1,4 +1,4 @@
1
- import { __decorate } from "tslib";
1
+ import { __decorate } from 'tslib';
2
2
  import { html, nothing } from 'lit';
3
3
  import { property, state } from 'lit/decorators.js';
4
4
  import '@exmg/exm-button/exm-text-button.js';
@@ -10,7 +10,8 @@ import { classMap } from 'lit/directives/class-map.js';
10
10
  import { ExmFormValidateMixin } from './exm-form-validate-mixin.js';
11
11
  import { serializeFormData } from './utils/serializeFormData.js';
12
12
  import { ExmFormDirtyMixin } from './exm-form-dirty-mixin.js';
13
- export class ExmFormBase extends ExmFormDirtyMixin(ExmFormValidateMixin(ExmgElement)) {
13
+
14
+ class ExmFormBase extends ExmFormDirtyMixin(ExmFormValidateMixin(ExmgElement)) {
14
15
  constructor() {
15
16
  super(...arguments);
16
17
  /**
@@ -187,4 +188,6 @@ __decorate([
187
188
  __decorate([
188
189
  property({ type: String })
189
190
  ], ExmFormBase.prototype, "errorMessage", void 0);
190
- //# sourceMappingURL=exm-form-base.js.map
191
+
192
+ export { ExmFormBase };
193
+ //# sourceMappingURL=exm-form-base.js.map
@@ -1,9 +1,8 @@
1
- import { __decorate } from "tslib";
2
- import { LitElement } from 'lit';
1
+ import { __decorate } from 'tslib';
2
+ import 'lit';
3
3
  import { state } from 'lit/decorators.js';
4
- export class FormDirtyMixinClass extends LitElement {
5
- }
6
- export const ExmFormDirtyMixin = (superClass) => {
4
+
5
+ const ExmFormDirtyMixin = (superClass) => {
7
6
  class FormDirtyMixinElement extends superClass {
8
7
  constructor(...args) {
9
8
  super(...args);
@@ -89,4 +88,6 @@ export const ExmFormDirtyMixin = (superClass) => {
89
88
  ], FormDirtyMixinElement.prototype, "dirty", void 0);
90
89
  return FormDirtyMixinElement;
91
90
  };
92
- //# sourceMappingURL=exm-form-dirty-mixin.js.map
91
+
92
+ export { ExmFormDirtyMixin };
93
+ //# sourceMappingURL=exm-form-dirty-mixin.js.map
@@ -1,10 +1,9 @@
1
- import { __decorate } from "tslib";
2
- import { LitElement } from 'lit';
3
- import { async, debounce } from '@exmg/lit-base/index.js';
1
+ import { __decorate } from 'tslib';
2
+ import 'lit';
3
+ import { debounce, async } from '@exmg/lit-base/index.js';
4
4
  import { state } from 'lit/decorators.js';
5
- export class FormValidateMixinClass extends LitElement {
6
- }
7
- export const ExmFormValidateMixin = (superClass) => {
5
+
6
+ const ExmFormValidateMixin = (superClass) => {
8
7
  class FormvalidateMixinElement extends superClass {
9
8
  constructor() {
10
9
  super(...arguments);
@@ -63,4 +62,6 @@ export const ExmFormValidateMixin = (superClass) => {
63
62
  ], FormvalidateMixinElement.prototype, "formValid", void 0);
64
63
  return FormvalidateMixinElement;
65
64
  };
66
- //# sourceMappingURL=exm-form-validate-mixin.js.map
65
+
66
+ export { ExmFormValidateMixin };
67
+ //# sourceMappingURL=exm-form-validate-mixin.js.map
package/dist/exm-form.js CHANGED
@@ -1,7 +1,8 @@
1
- import { __decorate } from "tslib";
1
+ import { __decorate } from 'tslib';
2
2
  import { customElement } from 'lit/decorators.js';
3
3
  import { style } from './styles/exm-form-base-css.js';
4
4
  import { ExmFormBase } from './exm-form-base.js';
5
+
5
6
  let ExmForm = class ExmForm extends ExmFormBase {
6
7
  getForm() {
7
8
  return this.querySelector('form');
@@ -11,5 +12,6 @@ ExmForm.styles = [style];
11
12
  ExmForm = __decorate([
12
13
  customElement('exm-form')
13
14
  ], ExmForm);
15
+
14
16
  export { ExmForm };
15
- //# sourceMappingURL=exm-form.js.map
17
+ //# sourceMappingURL=exm-form.js.map
package/dist/index.js CHANGED
@@ -4,4 +4,4 @@ export { ExmFormBase } from './exm-form-base.js';
4
4
  export { serializeFormData } from './utils/serializeFormData.js';
5
5
  export { style as formStyles } from './styles/exm-form-css.js';
6
6
  export { style as formBaseStyles } from './styles/exm-form-base-css.js';
7
- //# sourceMappingURL=index.js.map
7
+ //# sourceMappingURL=index.js.map
@@ -1,5 +1,6 @@
1
1
  import { css } from 'lit';
2
- export const style = css `
2
+
3
+ const style = css `
3
4
  :host {
4
5
  display: block;
5
6
  --_exm-form-content-margin-left: var(--exm-form-content-margin-left, 0);
@@ -88,4 +89,6 @@ export const style = css `
88
89
  color: var(--_exm-form-error-color, var(--md-sys-color-on-error-container, white));
89
90
  }
90
91
  `;
91
- //# sourceMappingURL=exm-form-base-css.js.map
92
+
93
+ export { style };
94
+ //# sourceMappingURL=exm-form-base-css.js.map
@@ -1,5 +1,6 @@
1
1
  import { css } from 'lit';
2
- export const style = css `
2
+
3
+ const style = css `
3
4
  .section-title {
4
5
  line-height: 1.5rem;
5
6
  font-size: 1rem;
@@ -56,4 +57,6 @@ export const style = css `
56
57
  color: var(--md-sys-color-primary);
57
58
  }
58
59
  `;
59
- //# sourceMappingURL=exm-form-css.js.map
60
+
61
+ export { style };
62
+ //# sourceMappingURL=exm-form-css.js.map
@@ -1,4 +1,4 @@
1
- export const serializeFormData = (form) => {
1
+ const serializeFormData = (form) => {
2
2
  const obj = {};
3
3
  const formElements = form === null || form === void 0 ? void 0 : form.elements;
4
4
  const formElementsArray = Array.from(formElements);
@@ -61,4 +61,6 @@ export const serializeFormData = (form) => {
61
61
  }
62
62
  return obj;
63
63
  };
64
- //# sourceMappingURL=serializeFormData.js.map
64
+
65
+ export { serializeFormData };
66
+ //# sourceMappingURL=serializeFormData.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exmg/exm-form",
3
- "version": "1.1.35",
3
+ "version": "1.1.37-alpha.31+513140a",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@exmg/exm-button": "^1.1.35"
34
+ "@exmg/exm-button": "^1.1.37-alpha.31+513140a"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "lit": "^3.2.1",
@@ -41,5 +41,5 @@
41
41
  "publishConfig": {
42
42
  "access": "public"
43
43
  },
44
- "gitHead": "1e671cd5dd060b682c8d9bb8c8a519a690c87782"
44
+ "gitHead": "513140a59e3a5a9a0fa572147ba6c0cf9801816e"
45
45
  }