@idp.global/catalog 1.1.1

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 (88) hide show
  1. package/assets/v2/draw-41d55381-b162-433d-956c-fe4cd400212e.png +0 -0
  2. package/assets/v2/draw-bd386bf3-ce94-4452-88da-05ae372fae35.png +0 -0
  3. package/assets/v2/draw-be69231a-f491-4bd3-9a47-71561ce14c15.png +0 -0
  4. package/assets/v2/draw-d58859a8-0615-44ec-80fe-626033c888f7.png +0 -0
  5. package/assets/v2/draw-db67b502-d987-4226-a5f8-d57e3f8d7ba9.png +0 -0
  6. package/assets/v2/draw-e6ac3ef5-5a93-464d-9d3f-5ae7b7278bdd.png +0 -0
  7. package/changelog.md +26 -0
  8. package/dist_bundle/bundle.js +6385 -0
  9. package/dist_ts_web/00_commitinfo_data.d.ts +8 -0
  10. package/dist_ts_web/00_commitinfo_data.js +9 -0
  11. package/dist_ts_web/elements/idp-admin-shell.d.ts +292 -0
  12. package/dist_ts_web/elements/idp-admin-shell.js +2615 -0
  13. package/dist_ts_web/elements/idp-approval-card.d.ts +25 -0
  14. package/dist_ts_web/elements/idp-approval-card.js +274 -0
  15. package/dist_ts_web/elements/idp-badge.d.ts +14 -0
  16. package/dist_ts_web/elements/idp-badge.js +135 -0
  17. package/dist_ts_web/elements/idp-button.d.ts +21 -0
  18. package/dist_ts_web/elements/idp-button.js +234 -0
  19. package/dist_ts_web/elements/idp-card.d.ts +15 -0
  20. package/dist_ts_web/elements/idp-card.js +139 -0
  21. package/dist_ts_web/elements/idp-checkbox.d.ts +23 -0
  22. package/dist_ts_web/elements/idp-checkbox.js +233 -0
  23. package/dist_ts_web/elements/idp-dashboard-window.d.ts +23 -0
  24. package/dist_ts_web/elements/idp-dashboard-window.js +587 -0
  25. package/dist_ts_web/elements/idp-data-table.d.ts +45 -0
  26. package/dist_ts_web/elements/idp-data-table.js +472 -0
  27. package/dist_ts_web/elements/idp-form-submit.d.ts +20 -0
  28. package/dist_ts_web/elements/idp-form-submit.js +136 -0
  29. package/dist_ts_web/elements/idp-form.d.ts +31 -0
  30. package/dist_ts_web/elements/idp-form.js +197 -0
  31. package/dist_ts_web/elements/idp-icon.d.ts +18 -0
  32. package/dist_ts_web/elements/idp-icon.js +204 -0
  33. package/dist_ts_web/elements/idp-inbox-preview.d.ts +18 -0
  34. package/dist_ts_web/elements/idp-inbox-preview.js +245 -0
  35. package/dist_ts_web/elements/idp-input.d.ts +26 -0
  36. package/dist_ts_web/elements/idp-input.js +249 -0
  37. package/dist_ts_web/elements/idp-landing-hero.d.ts +15 -0
  38. package/dist_ts_web/elements/idp-landing-hero.js +209 -0
  39. package/dist_ts_web/elements/idp-landing-page.d.ts +21 -0
  40. package/dist_ts_web/elements/idp-landing-page.js +694 -0
  41. package/dist_ts_web/elements/idp-mobile-frame.d.ts +14 -0
  42. package/dist_ts_web/elements/idp-mobile-frame.js +195 -0
  43. package/dist_ts_web/elements/idp-mobile-showcase.d.ts +16 -0
  44. package/dist_ts_web/elements/idp-mobile-showcase.js +339 -0
  45. package/dist_ts_web/elements/idp-select.d.ts +28 -0
  46. package/dist_ts_web/elements/idp-select.js +179 -0
  47. package/dist_ts_web/elements/idp-toggle.d.ts +15 -0
  48. package/dist_ts_web/elements/idp-toggle.js +134 -0
  49. package/dist_ts_web/elements/index.d.ts +20 -0
  50. package/dist_ts_web/elements/index.js +21 -0
  51. package/dist_ts_web/elements/tokens.d.ts +21 -0
  52. package/dist_ts_web/elements/tokens.js +190 -0
  53. package/dist_ts_web/index.d.ts +1 -0
  54. package/dist_ts_web/index.js +2 -0
  55. package/dist_ts_web/pages/index.d.ts +5 -0
  56. package/dist_ts_web/pages/index.js +23 -0
  57. package/dist_watch/bundle.js +120699 -0
  58. package/dist_watch/bundle.js.map +7 -0
  59. package/dist_watch/index.html +29 -0
  60. package/html/index.html +29 -0
  61. package/html/index.ts +39 -0
  62. package/license +21 -0
  63. package/package.json +64 -0
  64. package/readme.md +103 -0
  65. package/ts_web/00_commitinfo_data.ts +8 -0
  66. package/ts_web/elements/idp-admin-shell.ts +2664 -0
  67. package/ts_web/elements/idp-approval-card.ts +182 -0
  68. package/ts_web/elements/idp-badge.ts +84 -0
  69. package/ts_web/elements/idp-button.ts +166 -0
  70. package/ts_web/elements/idp-card.ts +76 -0
  71. package/ts_web/elements/idp-checkbox.ts +143 -0
  72. package/ts_web/elements/idp-dashboard-window.ts +564 -0
  73. package/ts_web/elements/idp-data-table.ts +407 -0
  74. package/ts_web/elements/idp-form-submit.ts +65 -0
  75. package/ts_web/elements/idp-form.ts +159 -0
  76. package/ts_web/elements/idp-icon.ts +263 -0
  77. package/ts_web/elements/idp-inbox-preview.ts +192 -0
  78. package/ts_web/elements/idp-input.ts +151 -0
  79. package/ts_web/elements/idp-landing-hero.ts +165 -0
  80. package/ts_web/elements/idp-landing-page.ts +655 -0
  81. package/ts_web/elements/idp-mobile-frame.ts +137 -0
  82. package/ts_web/elements/idp-mobile-showcase.ts +295 -0
  83. package/ts_web/elements/idp-select.ts +119 -0
  84. package/ts_web/elements/idp-toggle.ts +77 -0
  85. package/ts_web/elements/index.ts +20 -0
  86. package/ts_web/elements/tokens.ts +193 -0
  87. package/ts_web/index.ts +1 -0
  88. package/ts_web/pages/index.ts +26 -0
@@ -0,0 +1,407 @@
1
+ import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
2
+ import { idpElementStyles } from './tokens.js';
3
+ import './idp-badge.js';
4
+
5
+ export type TIdpDataTableCell = TemplateResult | string | number | null | undefined;
6
+
7
+ export interface IIdpDataTableColumn {
8
+ label: string;
9
+ width?: string;
10
+ align?: 'left' | 'center' | 'right';
11
+ mono?: boolean;
12
+ hideBelow?: 'mobile' | 'tablet';
13
+ }
14
+
15
+ export interface IIdpDataTableRow {
16
+ id?: string;
17
+ cells: TIdpDataTableCell[];
18
+ }
19
+
20
+ export interface IIdpDataTableTab {
21
+ id: string;
22
+ label: string;
23
+ count?: string | number;
24
+ }
25
+
26
+ export interface IIdpDataTableTabSelectEventDetail {
27
+ tabId: string;
28
+ }
29
+
30
+ declare global {
31
+ interface HTMLElementTagNameMap {
32
+ 'idp-data-table': IdpDataTable;
33
+ }
34
+ }
35
+
36
+ @customElement('idp-data-table')
37
+ export class IdpDataTable extends DeesElement {
38
+ public static demo = () => html`
39
+ <idp-data-table
40
+ title="Recent activity"
41
+ badge="3 total"
42
+ .columns=${[
43
+ { label: 'User' },
44
+ { label: 'Action' },
45
+ { label: 'Device', mono: true, hideBelow: 'mobile' },
46
+ { label: 'Status' },
47
+ { label: 'When', align: 'right', mono: true },
48
+ ]}
49
+ .tabs=${[
50
+ { id: 'all', label: 'All' },
51
+ { id: 'pending', label: 'Pending' },
52
+ { id: 'denied', label: 'Denied' },
53
+ ]}
54
+ selected-tab="all"
55
+ .rows=${[
56
+ {
57
+ cells: [
58
+ html`<div class="identity-cell"><span class="identity-avatar">EU</span><div><div class="identity-primary">Example User</div><div class="identity-secondary">user@example.com</div></div></div>`,
59
+ 'OAuth grant',
60
+ 'Desktop',
61
+ html`<idp-badge variant="ok">approved</idp-badge>`,
62
+ '2m ago',
63
+ ],
64
+ },
65
+ ]}
66
+ ></idp-data-table>
67
+ `;
68
+ public static demoGroups = ['idp.global v3 primitives'];
69
+
70
+ @property({ type: String })
71
+ public accessor title = '';
72
+
73
+ @property({ type: String })
74
+ public accessor subtitle = '';
75
+
76
+ @property({ type: String })
77
+ public accessor badge = '';
78
+
79
+ @property({ type: String, attribute: 'selected-tab' })
80
+ public accessor selectedTab = '';
81
+
82
+ @property({ type: String, attribute: 'empty-title' })
83
+ public accessor emptyTitle = 'No rows';
84
+
85
+ @property({ type: String, attribute: 'empty-description' })
86
+ public accessor emptyDescription = 'There is no data to display yet.';
87
+
88
+ @property({ type: Array })
89
+ public accessor columns: IIdpDataTableColumn[] = [];
90
+
91
+ @property({ type: Array })
92
+ public accessor rows: IIdpDataTableRow[] = [];
93
+
94
+ @property({ type: Array })
95
+ public accessor tabs: IIdpDataTableTab[] = [];
96
+
97
+ public static styles = [
98
+ ...idpElementStyles,
99
+ css`
100
+ :host {
101
+ display: block;
102
+ }
103
+ .table-card {
104
+ overflow: hidden;
105
+ border: 1px solid var(--idp-border);
106
+ border-radius: 8px;
107
+ background: var(--idp-card);
108
+ }
109
+ .table-head {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 10px;
113
+ padding: 12px 16px;
114
+ border-bottom: 1px solid var(--idp-border-soft);
115
+ }
116
+ .title-wrap {
117
+ min-width: 0;
118
+ }
119
+ .title-row {
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 10px;
123
+ }
124
+ .title {
125
+ color: var(--idp-fg);
126
+ font-size: 13px;
127
+ font-weight: 600;
128
+ }
129
+ .subtitle {
130
+ margin-top: 2px;
131
+ color: var(--idp-muted-fg);
132
+ font-size: 11.5px;
133
+ }
134
+ .count-pill {
135
+ display: inline-flex;
136
+ align-items: center;
137
+ gap: 4px;
138
+ padding: 2px 8px;
139
+ border: 1px solid var(--idp-border);
140
+ border-radius: 999px;
141
+ background: var(--idp-muted);
142
+ color: var(--idp-muted-fg);
143
+ font-family: var(--idp-mono);
144
+ font-size: 10px;
145
+ font-weight: 600;
146
+ letter-spacing: 0.04em;
147
+ line-height: 16px;
148
+ }
149
+ .tabs {
150
+ display: flex;
151
+ align-items: center;
152
+ gap: 2px;
153
+ margin-left: auto;
154
+ }
155
+ .tab {
156
+ padding: 4px 10px;
157
+ border: 0;
158
+ border-radius: 4px;
159
+ background: transparent;
160
+ color: var(--idp-muted-fg);
161
+ cursor: pointer;
162
+ font-family: var(--idp-font);
163
+ font-size: 11px;
164
+ }
165
+ .tab:hover,
166
+ .tab.active {
167
+ background: var(--idp-bg-2);
168
+ color: var(--idp-fg);
169
+ }
170
+ .table-scroll {
171
+ overflow-x: auto;
172
+ }
173
+ table {
174
+ width: 100%;
175
+ border-collapse: collapse;
176
+ }
177
+ th,
178
+ td {
179
+ border-bottom: 1px solid var(--idp-border-soft);
180
+ text-align: left;
181
+ vertical-align: middle;
182
+ }
183
+ th {
184
+ padding: 9px 16px;
185
+ background: var(--idp-muted);
186
+ color: var(--idp-fg-3);
187
+ font-family: var(--idp-mono);
188
+ font-size: 10px;
189
+ font-weight: 600;
190
+ letter-spacing: 0.08em;
191
+ text-transform: uppercase;
192
+ white-space: nowrap;
193
+ }
194
+ td {
195
+ padding: 10px 16px;
196
+ color: var(--idp-fg-2);
197
+ font-size: 12.5px;
198
+ }
199
+ tbody tr:last-child td {
200
+ border-bottom: 0;
201
+ }
202
+ tbody tr:hover td {
203
+ background: var(--idp-bg-2);
204
+ }
205
+ .align-center {
206
+ text-align: center;
207
+ }
208
+ .align-right {
209
+ text-align: right;
210
+ }
211
+ .mono-cell {
212
+ color: var(--idp-muted-fg);
213
+ font-family: var(--idp-mono);
214
+ font-size: 11.5px;
215
+ }
216
+ .identity-cell {
217
+ display: flex;
218
+ align-items: center;
219
+ gap: 8px;
220
+ min-width: 190px;
221
+ }
222
+ .identity-avatar {
223
+ width: 22px;
224
+ height: 22px;
225
+ display: inline-flex;
226
+ align-items: center;
227
+ justify-content: center;
228
+ flex-shrink: 0;
229
+ border: 1px solid var(--idp-border);
230
+ border-radius: 999px;
231
+ background: var(--idp-bg-2);
232
+ color: var(--avatar-color, var(--idp-accent));
233
+ font-family: var(--idp-mono);
234
+ font-size: 9.5px;
235
+ font-weight: 600;
236
+ }
237
+ .identity-primary {
238
+ color: var(--idp-fg);
239
+ font-size: 12.5px;
240
+ font-weight: 500;
241
+ }
242
+ .identity-secondary,
243
+ .cell-secondary {
244
+ margin-top: 1px;
245
+ color: var(--idp-muted-fg);
246
+ font-size: 11px;
247
+ line-height: 1.35;
248
+ }
249
+ .chip-row,
250
+ .cell-actions {
251
+ display: flex;
252
+ align-items: center;
253
+ gap: 8px;
254
+ flex-wrap: wrap;
255
+ }
256
+ .cell-actions {
257
+ justify-content: flex-end;
258
+ }
259
+ .table-action {
260
+ min-height: 28px;
261
+ padding: 5px 10px;
262
+ border: 1px solid var(--idp-border);
263
+ border-radius: 7px;
264
+ background: transparent;
265
+ color: var(--idp-fg);
266
+ cursor: pointer;
267
+ font-family: var(--idp-font);
268
+ font-size: 12px;
269
+ }
270
+ .table-action:hover {
271
+ background: var(--idp-bg-2);
272
+ }
273
+ .table-action.destructive {
274
+ border-color: var(--idp-error-border);
275
+ color: var(--idp-error);
276
+ }
277
+ .table-action.primary {
278
+ border-color: var(--idp-accent);
279
+ background: var(--idp-accent);
280
+ color: var(--idp-accent-fg);
281
+ }
282
+ .empty-state {
283
+ padding: 32px 20px;
284
+ color: var(--idp-muted-fg);
285
+ text-align: center;
286
+ }
287
+ .empty-title {
288
+ color: var(--idp-fg);
289
+ font-size: 13px;
290
+ font-weight: 600;
291
+ }
292
+ .empty-description {
293
+ max-width: 420px;
294
+ margin: 6px auto 0;
295
+ font-size: 12px;
296
+ line-height: 1.5;
297
+ }
298
+ @media (max-width: 900px) {
299
+ .hide-tablet {
300
+ display: none;
301
+ }
302
+ }
303
+ @media (max-width: 720px) {
304
+ .table-head {
305
+ align-items: flex-start;
306
+ flex-direction: column;
307
+ gap: 12px;
308
+ }
309
+ .tabs {
310
+ width: 100%;
311
+ margin-left: 0;
312
+ overflow-x: auto;
313
+ }
314
+ th,
315
+ td {
316
+ padding-left: 16px;
317
+ padding-right: 16px;
318
+ }
319
+ .hide-mobile {
320
+ display: none;
321
+ }
322
+ }
323
+ `,
324
+ ];
325
+
326
+ private selectTab(tabIdArg: string) {
327
+ this.selectedTab = tabIdArg;
328
+ this.dispatchEvent(new CustomEvent<IIdpDataTableTabSelectEventDetail>('idp-data-table-tab-select', {
329
+ detail: { tabId: tabIdArg },
330
+ bubbles: true,
331
+ composed: true,
332
+ }));
333
+ }
334
+
335
+ private columnClass(columnArg: IIdpDataTableColumn): string {
336
+ const classes = [
337
+ columnArg.align === 'center' ? 'align-center' : '',
338
+ columnArg.align === 'right' ? 'align-right' : '',
339
+ columnArg.hideBelow === 'mobile' ? 'hide-mobile' : '',
340
+ columnArg.hideBelow === 'tablet' ? 'hide-tablet' : '',
341
+ ];
342
+ return classes.filter(Boolean).join(' ');
343
+ }
344
+
345
+ private renderCell(contentArg: TIdpDataTableCell, columnArg: IIdpDataTableColumn): TemplateResult {
346
+ const content = contentArg === null || contentArg === undefined || contentArg === '' ? '-' : contentArg;
347
+ return columnArg.mono ? html`<span class="mono-cell">${content}</span>` : html`${content}`;
348
+ }
349
+
350
+ public render(): TemplateResult {
351
+ const selectedTab = this.selectedTab || this.tabs[0]?.id || '';
352
+ return html`
353
+ <section class="table-card">
354
+ ${this.title || this.badge || this.tabs.length ? html`
355
+ <div class="table-head">
356
+ <div class="title-wrap">
357
+ <div class="title-row">
358
+ ${this.title ? html`<div class="title">${this.title}</div>` : html``}
359
+ ${this.badge ? html`<span class="count-pill">${this.badge}</span>` : html``}
360
+ </div>
361
+ ${this.subtitle ? html`<div class="subtitle">${this.subtitle}</div>` : html``}
362
+ </div>
363
+ ${this.tabs.length ? html`
364
+ <div class="tabs" role="tablist">
365
+ ${this.tabs.map((tabArg) => html`
366
+ <button
367
+ class="tab ${tabArg.id === selectedTab ? 'active' : ''}"
368
+ role="tab"
369
+ aria-selected=${tabArg.id === selectedTab ? 'true' : 'false'}
370
+ @click=${() => this.selectTab(tabArg.id)}
371
+ >${tabArg.label}${tabArg.count !== undefined ? html` (${tabArg.count})` : html``}</button>
372
+ `)}
373
+ </div>
374
+ ` : html``}
375
+ </div>
376
+ ` : html``}
377
+ ${this.rows.length ? html`
378
+ <div class="table-scroll">
379
+ <table>
380
+ <thead>
381
+ <tr>
382
+ ${this.columns.map((columnArg) => html`
383
+ <th class=${this.columnClass(columnArg)} style=${columnArg.width ? `width:${columnArg.width}` : ''}>${columnArg.label}</th>
384
+ `)}
385
+ </tr>
386
+ </thead>
387
+ <tbody>
388
+ ${this.rows.map((rowArg) => html`
389
+ <tr>
390
+ ${this.columns.map((columnArg, indexArg) => html`
391
+ <td class=${this.columnClass(columnArg)}>${this.renderCell(rowArg.cells[indexArg], columnArg)}</td>
392
+ `)}
393
+ </tr>
394
+ `)}
395
+ </tbody>
396
+ </table>
397
+ </div>
398
+ ` : html`
399
+ <div class="empty-state">
400
+ <div class="empty-title">${this.emptyTitle}</div>
401
+ <div class="empty-description">${this.emptyDescription}</div>
402
+ </div>
403
+ `}
404
+ </section>
405
+ `;
406
+ }
407
+ }
@@ -0,0 +1,65 @@
1
+ import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
2
+ import { idpElementStyles } from './tokens.js';
3
+ import './idp-button.js';
4
+ import type { TIdpButtonSize, TIdpButtonVariant } from './idp-button.js';
5
+
6
+ declare global {
7
+ interface HTMLElementTagNameMap {
8
+ 'idp-form-submit': IdpFormSubmit;
9
+ }
10
+ }
11
+
12
+ @customElement('idp-form-submit')
13
+ export class IdpFormSubmit extends DeesElement {
14
+ public static demo = () => html`<idp-form-submit>Continue</idp-form-submit>`;
15
+ public static demoGroups = ['idp.global v3 primitives'];
16
+
17
+ @property({ type: String })
18
+ public accessor text = '';
19
+
20
+ @property({ type: String })
21
+ public accessor variant: TIdpButtonVariant = 'accent';
22
+
23
+ @property({ type: String })
24
+ public accessor size: TIdpButtonSize = 'md';
25
+
26
+ @property({ type: Boolean, reflect: true })
27
+ public accessor disabled = false;
28
+
29
+ @property({ type: Boolean, reflect: true })
30
+ public accessor loading = false;
31
+
32
+ public static styles = [
33
+ ...idpElementStyles,
34
+ css`
35
+ :host {
36
+ display: block;
37
+ }
38
+ idp-button {
39
+ width: 100%;
40
+ }
41
+ `,
42
+ ];
43
+
44
+ private handleClick() {
45
+ if (this.disabled || this.loading) {
46
+ return;
47
+ }
48
+ this.dispatchEvent(new CustomEvent('idp-form-submit-request', {
49
+ bubbles: true,
50
+ composed: true,
51
+ }));
52
+ }
53
+
54
+ public render(): TemplateResult {
55
+ return html`
56
+ <idp-button
57
+ variant=${this.variant}
58
+ size=${this.size}
59
+ .disabled=${this.disabled || this.loading}
60
+ .loading=${this.loading}
61
+ @click=${this.handleClick}
62
+ >${this.text || html`<slot></slot>`}</idp-button>
63
+ `;
64
+ }
65
+ }
@@ -0,0 +1,159 @@
1
+ import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
2
+ import { idpElementStyles } from './tokens.js';
3
+ import './idp-input.js';
4
+ import './idp-checkbox.js';
5
+
6
+ export type TIdpFormStatus = 'idle' | 'pending' | 'success' | 'error';
7
+ export type TIdpFormData = Record<string, string | boolean>;
8
+
9
+ export interface IIdpFormSubmitEventDetail {
10
+ data: TIdpFormData;
11
+ form: IdpForm;
12
+ }
13
+
14
+ type TFormControl = HTMLElement & {
15
+ name?: string;
16
+ key?: string;
17
+ value?: string;
18
+ checked?: boolean;
19
+ validate?: () => boolean;
20
+ };
21
+
22
+ declare global {
23
+ interface HTMLElementTagNameMap {
24
+ 'idp-form': IdpForm;
25
+ }
26
+ }
27
+
28
+ @customElement('idp-form')
29
+ export class IdpForm extends DeesElement {
30
+ public static demo = () => html`
31
+ <idp-form>
32
+ <idp-input name="email" label="Email" type="email" required></idp-input>
33
+ <idp-form-submit>Continue</idp-form-submit>
34
+ </idp-form>
35
+ `;
36
+ public static demoGroups = ['idp.global v3 primitives'];
37
+
38
+ @property({ type: String, reflect: true })
39
+ public accessor status: TIdpFormStatus = 'idle';
40
+
41
+ @property({ type: String })
42
+ public accessor statusMessage = '';
43
+
44
+ @property({ type: Boolean, reflect: true })
45
+ public accessor disabled = false;
46
+
47
+ public static styles = [
48
+ ...idpElementStyles,
49
+ css`
50
+ :host {
51
+ display: block;
52
+ }
53
+ form {
54
+ display: flex;
55
+ flex-direction: column;
56
+ gap: 16px;
57
+ }
58
+ ::slotted(idp-form-submit) {
59
+ margin-top: 2px;
60
+ }
61
+ .status {
62
+ padding: 11px 13px;
63
+ border-radius: 10px;
64
+ border: 1px solid var(--idp-border);
65
+ background: var(--idp-muted);
66
+ color: var(--idp-muted-fg);
67
+ font-size: 13px;
68
+ line-height: 1.45;
69
+ }
70
+ .status.pending {
71
+ border-color: color-mix(in srgb, var(--idp-accent), transparent 60%);
72
+ color: var(--idp-accent);
73
+ }
74
+ .status.success {
75
+ border-color: color-mix(in srgb, var(--idp-ok), transparent 60%);
76
+ color: var(--idp-ok);
77
+ }
78
+ .status.error {
79
+ border-color: color-mix(in srgb, var(--idp-destructive), transparent 60%);
80
+ color: var(--idp-destructive);
81
+ }
82
+ `,
83
+ ];
84
+
85
+ public setStatus(statusArg: TIdpFormStatus, messageArg = '') {
86
+ this.status = statusArg;
87
+ this.statusMessage = messageArg;
88
+ }
89
+
90
+ public resetStatus() {
91
+ this.setStatus('idle', '');
92
+ }
93
+
94
+ public submit() {
95
+ this.handleSubmit();
96
+ }
97
+
98
+ private getControls() {
99
+ return Array.from(this.querySelectorAll('idp-input, idp-checkbox')) as TFormControl[];
100
+ }
101
+
102
+ private validateControls() {
103
+ return this.getControls().every((controlArg) => controlArg.validate ? controlArg.validate() : true);
104
+ }
105
+
106
+ private getFormData(): TIdpFormData {
107
+ const data: TIdpFormData = {};
108
+ for (const control of this.getControls()) {
109
+ const name = control.name || control.key;
110
+ if (!name) {
111
+ continue;
112
+ }
113
+
114
+ if (typeof control.checked === 'boolean') {
115
+ data[name] = control.checked;
116
+ } else {
117
+ data[name] = control.value || '';
118
+ }
119
+ }
120
+ return data;
121
+ }
122
+
123
+ private handleSubmitRequest(eventArg: Event) {
124
+ eventArg.preventDefault();
125
+ eventArg.stopPropagation();
126
+ this.handleSubmit();
127
+ }
128
+
129
+ private handleSubmit(eventArg?: Event) {
130
+ eventArg?.preventDefault();
131
+ if (this.disabled || this.status === 'pending') {
132
+ return;
133
+ }
134
+ if (!this.validateControls()) {
135
+ this.setStatus('error', 'Please check the highlighted fields.');
136
+ return;
137
+ }
138
+
139
+ this.dispatchEvent(new CustomEvent<IIdpFormSubmitEventDetail>('idp-submit', {
140
+ detail: {
141
+ data: this.getFormData(),
142
+ form: this,
143
+ },
144
+ bubbles: true,
145
+ composed: true,
146
+ }));
147
+ }
148
+
149
+ public render(): TemplateResult {
150
+ return html`
151
+ <form novalidate @submit=${this.handleSubmit} @idp-form-submit-request=${this.handleSubmitRequest}>
152
+ <slot></slot>
153
+ ${this.statusMessage
154
+ ? html`<div class="status ${this.status}" role="status">${this.statusMessage}</div>`
155
+ : html``}
156
+ </form>
157
+ `;
158
+ }
159
+ }