@neptune.fintech/web-ui 2.1.0 → 2.2.0

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 (40) hide show
  1. package/dist/components/cards.d.ts +64 -0
  2. package/dist/components/cards.d.ts.map +1 -0
  3. package/dist/components/cards.js +498 -0
  4. package/dist/components/cards.js.map +1 -0
  5. package/dist/components/corporate.d.ts +84 -0
  6. package/dist/components/corporate.d.ts.map +1 -0
  7. package/dist/components/corporate.js +782 -0
  8. package/dist/components/corporate.js.map +1 -0
  9. package/dist/components/data-viz.d.ts +69 -0
  10. package/dist/components/data-viz.d.ts.map +1 -0
  11. package/dist/components/data-viz.js +526 -0
  12. package/dist/components/data-viz.js.map +1 -0
  13. package/dist/components/feedback-status.d.ts +80 -0
  14. package/dist/components/feedback-status.d.ts.map +1 -0
  15. package/dist/components/feedback-status.js +537 -0
  16. package/dist/components/feedback-status.js.map +1 -0
  17. package/dist/components/money-inputs.d.ts +105 -0
  18. package/dist/components/money-inputs.d.ts.map +1 -0
  19. package/dist/components/money-inputs.js +766 -0
  20. package/dist/components/money-inputs.js.map +1 -0
  21. package/dist/components/money-movement.d.ts +79 -0
  22. package/dist/components/money-movement.d.ts.map +1 -0
  23. package/dist/components/money-movement.js +740 -0
  24. package/dist/components/money-movement.js.map +1 -0
  25. package/dist/components/shell-layout.d.ts +103 -0
  26. package/dist/components/shell-layout.d.ts.map +1 -0
  27. package/dist/components/shell-layout.js +582 -0
  28. package/dist/components/shell-layout.js.map +1 -0
  29. package/dist/components/wallet-pay.d.ts +85 -0
  30. package/dist/components/wallet-pay.d.ts.map +1 -0
  31. package/dist/components/wallet-pay.js +633 -0
  32. package/dist/components/wallet-pay.js.map +1 -0
  33. package/dist/index.d.ts +9 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +9 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/register.d.ts.map +1 -1
  38. package/dist/register.js +65 -0
  39. package/dist/register.js.map +1 -1
  40. package/package.json +1 -1
@@ -0,0 +1,740 @@
1
+ // © 2026 Neptune.Fintech (neptune.ly) · Neptune Odyssey Community License v1.0
2
+ // Neptune Odyssey — money-movement flow
3
+ // <npt-stepper>, <npt-step>, <npt-transfer-review>, <npt-success>,
4
+ // <npt-receipt>, <npt-beneficiary-tile>, <npt-method-row>.
5
+ // Custom-property driven only; logical layout → mirrors in RTL.
6
+ import { NptElement, css, html, A11Y, define } from "./base.js";
7
+ const esc = (v) => (v ?? "").replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);
8
+ /** A single declarative step label, consumed by <npt-stepper>. Renders nothing on its own. */
9
+ export class NptStep extends NptElement {
10
+ styles() {
11
+ return css `
12
+ :host {
13
+ display: none;
14
+ }
15
+ `;
16
+ }
17
+ render() {
18
+ return html ``;
19
+ }
20
+ }
21
+ /**
22
+ * <npt-stepper active="1" steps="Amount,Review,Done"></npt-stepper>
23
+ * or with light-DOM <npt-step>Amount</npt-step> children.
24
+ * Horizontal progress indicator with numbered nodes + connectors.
25
+ */
26
+ export class NptStepper extends NptElement {
27
+ attributeChangedCallback() {
28
+ if (this.isConnected)
29
+ this.update();
30
+ }
31
+ labels() {
32
+ const attr = this.getAttribute("steps");
33
+ if (attr && attr.trim()) {
34
+ return attr
35
+ .split(",")
36
+ .map((s) => s.trim())
37
+ .filter((s) => s.length > 0);
38
+ }
39
+ return Array.from(this.querySelectorAll("npt-step")).map((s) => (s.textContent ?? "").trim());
40
+ }
41
+ styles() {
42
+ return css `
43
+ ${A11Y}
44
+ :host {
45
+ display: block;
46
+ }
47
+ .stepper {
48
+ display: flex;
49
+ align-items: flex-start;
50
+ gap: var(--npt-space-1, 4px);
51
+ font-family: var(--npt-font-text);
52
+ }
53
+ .step {
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: center;
57
+ gap: var(--npt-space-2, 8px);
58
+ flex: 0 0 auto;
59
+ min-inline-size: 56px;
60
+ }
61
+ .node {
62
+ inline-size: 32px;
63
+ block-size: 32px;
64
+ border-radius: var(--npt-corner-full, 999px);
65
+ display: grid;
66
+ place-items: center;
67
+ font-family: var(--npt-font-num);
68
+ font-variant-numeric: tabular-nums;
69
+ font-size: var(--npt-text-label, 14px);
70
+ font-weight: 600;
71
+ background: var(--md-sys-color-surface-container-highest);
72
+ color: var(--md-sys-color-on-surface-variant);
73
+ border: 2px solid var(--md-sys-color-outline-variant);
74
+ box-sizing: border-box;
75
+ transition: background-color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease),
76
+ border-color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease),
77
+ color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease);
78
+ }
79
+ .step[data-state="active"] .node {
80
+ background: var(--md-sys-color-primary);
81
+ color: var(--md-sys-color-on-primary);
82
+ border-color: var(--md-sys-color-primary);
83
+ }
84
+ .step[data-state="done"] .node {
85
+ background: var(--md-sys-color-success);
86
+ color: var(--md-sys-color-on-success);
87
+ border-color: var(--md-sys-color-success);
88
+ }
89
+ .label {
90
+ font-size: var(--npt-text-caption, 12px);
91
+ color: var(--md-sys-color-on-surface-variant);
92
+ text-align: center;
93
+ max-inline-size: 80px;
94
+ }
95
+ .step[data-state="active"] .label {
96
+ color: var(--md-sys-color-on-surface);
97
+ font-weight: 600;
98
+ }
99
+ .connector {
100
+ flex: 1 1 auto;
101
+ block-size: 2px;
102
+ margin-block-start: 15px;
103
+ margin-inline: var(--npt-space-1, 4px);
104
+ min-inline-size: var(--npt-space-4, 16px);
105
+ background: var(--md-sys-color-outline-variant);
106
+ border-radius: var(--npt-corner-full, 999px);
107
+ transition: background-color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease);
108
+ }
109
+ .connector[data-done="true"] {
110
+ background: var(--md-sys-color-success);
111
+ }
112
+ `;
113
+ }
114
+ render() {
115
+ const labels = this.labels();
116
+ const active = Math.max(0, Number(this.getAttribute("active") ?? 0));
117
+ const total = labels.length;
118
+ const nodes = labels
119
+ .map((label, i) => {
120
+ const state = i < active ? "done" : i === active ? "active" : "upcoming";
121
+ const current = state === "active" ? html `aria-current="step"` : "";
122
+ const mark = state === "done" ? "✓" : String(i + 1);
123
+ const step = html `<li
124
+ class="step"
125
+ part="step"
126
+ data-state="${state}"
127
+ role="listitem"
128
+ ${current}
129
+ >
130
+ <span class="node" aria-hidden="true">${mark}</span>
131
+ <span class="label">${esc(label)}</span>
132
+ </li>`;
133
+ if (i < total - 1) {
134
+ const done = i < active ? "true" : "false";
135
+ return html `${step}<span class="connector" part="connector" data-done="${done}" aria-hidden="true"></span>`;
136
+ }
137
+ return step;
138
+ })
139
+ .join("");
140
+ const label = `Step ${Math.min(active + 1, Math.max(total, 1))} of ${total}`;
141
+ return html `<ol class="stepper" part="stepper" role="list" aria-label="${esc(label)}">${nodes}</ol>`;
142
+ }
143
+ }
144
+ NptStepper.observedAttributes = ["steps", "active"];
145
+ /**
146
+ * <npt-transfer-review rows='[{"label":"To","value":"Mona K"}]'
147
+ * total="1,250.00" currency="LYD"></npt-transfer-review>
148
+ * Light-DOM rows are also supported: place elements with [slot="rows"].
149
+ * Key/value summary with a highlighted total footer.
150
+ */
151
+ export class NptTransferReview extends NptElement {
152
+ attributeChangedCallback() {
153
+ if (this.isConnected)
154
+ this.update();
155
+ }
156
+ rows() {
157
+ const raw = this.getAttribute("rows");
158
+ if (!raw)
159
+ return [];
160
+ try {
161
+ const parsed = JSON.parse(raw);
162
+ if (!Array.isArray(parsed))
163
+ return [];
164
+ return parsed
165
+ .filter((r) => typeof r === "object" && r !== null)
166
+ .map((r) => ({ label: String(r["label"] ?? ""), value: String(r["value"] ?? "") }));
167
+ }
168
+ catch {
169
+ return [];
170
+ }
171
+ }
172
+ styles() {
173
+ return css `
174
+ ${A11Y}
175
+ :host {
176
+ display: block;
177
+ }
178
+ .review {
179
+ background: var(--md-sys-color-surface-container-low);
180
+ color: var(--md-sys-color-on-surface);
181
+ border-radius: var(--npt-corner-lg, 24px);
182
+ padding: var(--npt-space-5, 20px);
183
+ box-sizing: border-box;
184
+ }
185
+ dl {
186
+ margin: 0;
187
+ display: grid;
188
+ gap: var(--npt-space-3, 12px);
189
+ }
190
+ .row {
191
+ display: flex;
192
+ align-items: baseline;
193
+ justify-content: space-between;
194
+ gap: var(--npt-space-4, 16px);
195
+ }
196
+ dt {
197
+ font-family: var(--npt-font-text);
198
+ font-size: var(--npt-text-body, 14px);
199
+ color: var(--md-sys-color-on-surface-variant);
200
+ margin: 0;
201
+ }
202
+ dd {
203
+ font-family: var(--npt-font-text);
204
+ font-size: var(--npt-text-body-lg, 16px);
205
+ color: var(--md-sys-color-on-surface);
206
+ margin: 0;
207
+ text-align: end;
208
+ min-inline-size: 0;
209
+ overflow-wrap: anywhere;
210
+ }
211
+ .total {
212
+ margin-block-start: var(--npt-space-4, 16px);
213
+ padding-block-start: var(--npt-space-4, 16px);
214
+ border-block-start: 1px solid var(--md-sys-color-outline-variant);
215
+ display: flex;
216
+ align-items: baseline;
217
+ justify-content: space-between;
218
+ gap: var(--npt-space-4, 16px);
219
+ }
220
+ .total-label {
221
+ font-family: var(--npt-font-text);
222
+ font-size: var(--npt-text-label, 14px);
223
+ font-weight: 600;
224
+ color: var(--md-sys-color-on-surface);
225
+ }
226
+ .total-value {
227
+ font-family: var(--npt-font-num);
228
+ font-feature-settings: "tnum" 1;
229
+ font-variant-numeric: tabular-nums;
230
+ font-size: var(--npt-text-title-lg, 22px);
231
+ font-weight: 700;
232
+ color: var(--md-sys-color-primary);
233
+ white-space: nowrap;
234
+ }
235
+ .total-currency {
236
+ font-size: var(--npt-text-body, 14px);
237
+ opacity: 0.85;
238
+ margin-inline-start: var(--npt-space-1, 4px);
239
+ }
240
+ ::slotted([slot="rows"]) {
241
+ display: block;
242
+ }
243
+ `;
244
+ }
245
+ render() {
246
+ const total = esc(this.getAttribute("total"));
247
+ const currency = esc(this.getAttribute("currency"));
248
+ const totalLabel = esc(this.getAttribute("total-label")) || "Total";
249
+ const rows = this.rows()
250
+ .map((r) => html `<div class="row" part="row">
251
+ <dt>${esc(r.label)}</dt>
252
+ <dd>${esc(r.value)}</dd>
253
+ </div>`)
254
+ .join("");
255
+ const totalBlock = total
256
+ ? html `<div class="total" part="total">
257
+ <span class="total-label">${totalLabel}</span>
258
+ <span class="total-value"
259
+ >${total}${currency ? html `<span class="total-currency">${currency}</span>` : ""}</span
260
+ >
261
+ </div>`
262
+ : "";
263
+ return html `<section
264
+ class="review"
265
+ part="review"
266
+ role="group"
267
+ aria-label="${totalLabel} ${total} ${currency}"
268
+ >
269
+ <dl>${rows}</dl>
270
+ <slot name="rows"></slot>
271
+ ${totalBlock}
272
+ </section>`;
273
+ }
274
+ }
275
+ NptTransferReview.observedAttributes = ["rows", "total", "currency", "total-label"];
276
+ /**
277
+ * <npt-success title="Transfer sent" message="Your money is on the way.">
278
+ * <npt-button slot="actions">Done</npt-button>
279
+ * </npt-success>
280
+ * Success hero with a spring-in check; honours reduced motion.
281
+ */
282
+ export class NptSuccess extends NptElement {
283
+ attributeChangedCallback() {
284
+ if (this.isConnected)
285
+ this.update();
286
+ }
287
+ styles() {
288
+ return css `
289
+ ${A11Y}
290
+ :host {
291
+ display: block;
292
+ }
293
+ .hero {
294
+ display: flex;
295
+ flex-direction: column;
296
+ align-items: center;
297
+ text-align: center;
298
+ gap: var(--npt-space-4, 16px);
299
+ padding: var(--npt-space-6, 24px);
300
+ box-sizing: border-box;
301
+ }
302
+ .ring {
303
+ inline-size: 96px;
304
+ block-size: 96px;
305
+ border-radius: var(--npt-corner-full, 999px);
306
+ display: grid;
307
+ place-items: center;
308
+ background: var(--md-sys-color-success-container, var(--md-sys-color-secondary-container));
309
+ color: var(--md-sys-color-success);
310
+ animation: spring-in var(--npt-dur-slow, 400ms) var(--npt-ease-spring, ease) both;
311
+ }
312
+ .check {
313
+ font-size: var(--npt-text-display-md, 45px);
314
+ line-height: 1;
315
+ animation: check-pop var(--npt-dur-standard, 300ms) var(--npt-ease-spring, ease) both;
316
+ animation-delay: var(--npt-dur-fast, 200ms);
317
+ }
318
+ .title {
319
+ font-family: var(--npt-font-display);
320
+ font-size: var(--npt-text-headline, 24px);
321
+ font-weight: 700;
322
+ color: var(--md-sys-color-on-surface);
323
+ margin: 0;
324
+ }
325
+ .message {
326
+ font-family: var(--npt-font-text);
327
+ font-size: var(--npt-text-body-lg, 16px);
328
+ color: var(--md-sys-color-on-surface-variant);
329
+ margin: 0;
330
+ max-inline-size: 40ch;
331
+ }
332
+ .actions {
333
+ display: flex;
334
+ flex-wrap: wrap;
335
+ justify-content: center;
336
+ gap: var(--npt-space-3, 12px);
337
+ margin-block-start: var(--npt-space-2, 8px);
338
+ }
339
+ @keyframes spring-in {
340
+ 0% {
341
+ transform: scale(0.6);
342
+ opacity: 0;
343
+ }
344
+ 60% {
345
+ transform: scale(1.08);
346
+ opacity: 1;
347
+ }
348
+ 100% {
349
+ transform: scale(1);
350
+ }
351
+ }
352
+ @keyframes check-pop {
353
+ 0% {
354
+ transform: scale(0);
355
+ }
356
+ 100% {
357
+ transform: scale(1);
358
+ }
359
+ }
360
+ `;
361
+ }
362
+ render() {
363
+ const title = esc(this.getAttribute("title"));
364
+ const message = esc(this.getAttribute("message"));
365
+ return html `<div class="hero" part="hero" role="status" aria-live="polite">
366
+ <span class="ring" part="ring" aria-hidden="true"><span class="check">✓</span></span>
367
+ ${title ? html `<h2 class="title" part="title">${title}</h2>` : ""}
368
+ ${message ? html `<p class="message" part="message">${message}</p>` : ""}
369
+ <div class="actions" part="actions"><slot name="actions"></slot></div>
370
+ </div>`;
371
+ }
372
+ }
373
+ NptSuccess.observedAttributes = ["title", "message"];
374
+ /**
375
+ * <npt-receipt merchant="Acme" amount="42.00" currency="LYD"
376
+ * date="27 Jun 2026" status="Completed" reference="TX-9931"></npt-receipt>
377
+ * Receipt card with a dashed tear divider; extra rows via the default slot.
378
+ */
379
+ export class NptReceipt extends NptElement {
380
+ attributeChangedCallback() {
381
+ if (this.isConnected)
382
+ this.update();
383
+ }
384
+ styles() {
385
+ return css `
386
+ ${A11Y}
387
+ :host {
388
+ display: block;
389
+ }
390
+ .receipt {
391
+ background: var(--md-sys-color-surface-container-lowest);
392
+ color: var(--md-sys-color-on-surface);
393
+ border: 1px solid var(--md-sys-color-outline-variant);
394
+ border-radius: var(--npt-corner-lg, 24px);
395
+ padding: var(--npt-space-5, 20px);
396
+ box-sizing: border-box;
397
+ }
398
+ .merchant {
399
+ font-family: var(--npt-font-display);
400
+ font-size: var(--npt-text-title, 18px);
401
+ font-weight: 700;
402
+ margin: 0;
403
+ }
404
+ .amount {
405
+ font-family: var(--npt-font-num);
406
+ font-feature-settings: "tnum" 1;
407
+ font-variant-numeric: tabular-nums;
408
+ font-size: var(--npt-text-display-md, 45px);
409
+ line-height: var(--npt-leading-display-md, 52px);
410
+ font-weight: 700;
411
+ letter-spacing: -0.02em;
412
+ margin: var(--npt-space-2, 8px) 0 0;
413
+ display: flex;
414
+ align-items: baseline;
415
+ gap: var(--npt-space-2, 8px);
416
+ }
417
+ .amount .currency {
418
+ font-size: var(--npt-text-title, 18px);
419
+ opacity: 0.85;
420
+ }
421
+ .divider {
422
+ block-size: 0;
423
+ border: none;
424
+ border-block-start: 2px dashed var(--md-sys-color-outline-variant);
425
+ margin-block: var(--npt-space-4, 16px);
426
+ }
427
+ dl {
428
+ margin: 0;
429
+ display: grid;
430
+ gap: var(--npt-space-3, 12px);
431
+ }
432
+ .row {
433
+ display: flex;
434
+ align-items: baseline;
435
+ justify-content: space-between;
436
+ gap: var(--npt-space-4, 16px);
437
+ }
438
+ dt {
439
+ font-family: var(--npt-font-text);
440
+ font-size: var(--npt-text-body, 14px);
441
+ color: var(--md-sys-color-on-surface-variant);
442
+ margin: 0;
443
+ }
444
+ dd {
445
+ font-family: var(--npt-font-text);
446
+ font-size: var(--npt-text-body-lg, 16px);
447
+ color: var(--md-sys-color-on-surface);
448
+ margin: 0;
449
+ text-align: end;
450
+ overflow-wrap: anywhere;
451
+ }
452
+ dd.num {
453
+ font-family: var(--npt-font-num);
454
+ font-variant-numeric: tabular-nums;
455
+ }
456
+ .status {
457
+ display: inline-flex;
458
+ align-items: center;
459
+ gap: var(--npt-space-2, 8px);
460
+ font-weight: 600;
461
+ color: var(--md-sys-color-success);
462
+ }
463
+ .status::before {
464
+ content: "";
465
+ inline-size: 8px;
466
+ block-size: 8px;
467
+ border-radius: var(--npt-corner-full, 999px);
468
+ background: currentColor;
469
+ }
470
+ ::slotted(*) {
471
+ margin-block-start: var(--npt-space-3, 12px);
472
+ }
473
+ `;
474
+ }
475
+ render() {
476
+ const merchant = esc(this.getAttribute("merchant"));
477
+ const amount = esc(this.getAttribute("amount"));
478
+ const currency = esc(this.getAttribute("currency"));
479
+ const date = esc(this.getAttribute("date"));
480
+ const status = esc(this.getAttribute("status"));
481
+ const reference = esc(this.getAttribute("reference"));
482
+ return html `<article
483
+ class="receipt"
484
+ part="receipt"
485
+ role="group"
486
+ aria-label="Receipt ${merchant} ${amount} ${currency}"
487
+ >
488
+ ${merchant ? html `<p class="merchant" part="merchant">${merchant}</p>` : ""}
489
+ ${amount
490
+ ? html `<p class="amount" part="amount">
491
+ ${currency ? html `<span class="currency">${currency}</span>` : ""}${amount}
492
+ </p>`
493
+ : ""}
494
+ <hr class="divider" part="divider" aria-hidden="true" />
495
+ <dl>
496
+ ${date ? html `<div class="row"><dt>Date</dt><dd>${date}</dd></div>` : ""}
497
+ ${reference
498
+ ? html `<div class="row"><dt>Reference</dt><dd class="num">${reference}</dd></div>`
499
+ : ""}
500
+ ${status
501
+ ? html `<div class="row">
502
+ <dt>Status</dt>
503
+ <dd><span class="status">${status}</span></dd>
504
+ </div>`
505
+ : ""}
506
+ </dl>
507
+ <slot></slot>
508
+ </article>`;
509
+ }
510
+ }
511
+ NptReceipt.observedAttributes = ["merchant", "amount", "currency", "date", "status", "reference"];
512
+ /**
513
+ * <npt-beneficiary-tile name="Mona Kamel" account="•••• 4821" [favorite]>
514
+ * </npt-beneficiary-tile>
515
+ * Avatar/initials + name + masked account + trailing chevron.
516
+ */
517
+ export class NptBeneficiaryTile extends NptElement {
518
+ attributeChangedCallback() {
519
+ if (this.isConnected)
520
+ this.update();
521
+ }
522
+ initials(name) {
523
+ const parts = name.trim().split(/\s+/).filter(Boolean);
524
+ if (parts.length === 0)
525
+ return "•";
526
+ const first = parts[0]?.charAt(0) ?? "";
527
+ const last = parts.length > 1 ? (parts[parts.length - 1]?.charAt(0) ?? "") : "";
528
+ return (first + last).toUpperCase() || "•";
529
+ }
530
+ styles() {
531
+ return css `
532
+ ${A11Y}
533
+ :host {
534
+ display: block;
535
+ }
536
+ .tile {
537
+ inline-size: 100%;
538
+ display: flex;
539
+ align-items: center;
540
+ gap: var(--npt-space-4, 16px);
541
+ min-height: 56px;
542
+ padding-inline: var(--npt-space-3, 12px);
543
+ padding-block: var(--npt-space-3, 12px);
544
+ border: none;
545
+ background: transparent;
546
+ color: inherit;
547
+ text-align: start;
548
+ font-family: var(--npt-font-text);
549
+ cursor: pointer;
550
+ border-radius: var(--npt-corner-md, 16px);
551
+ box-sizing: border-box;
552
+ transition: background-color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease);
553
+ }
554
+ .tile:hover {
555
+ background: var(--md-sys-color-surface-container-high);
556
+ }
557
+ .avatar {
558
+ position: relative;
559
+ inline-size: 44px;
560
+ block-size: 44px;
561
+ flex: 0 0 auto;
562
+ border-radius: var(--npt-corner-full, 999px);
563
+ display: grid;
564
+ place-items: center;
565
+ background: var(--md-sys-color-primary-container);
566
+ color: var(--md-sys-color-on-primary-container);
567
+ font-family: var(--npt-font-display);
568
+ font-weight: 600;
569
+ font-size: var(--npt-text-label, 14px);
570
+ }
571
+ .star {
572
+ position: absolute;
573
+ inset-block-end: -2px;
574
+ inset-inline-end: -2px;
575
+ inline-size: 18px;
576
+ block-size: 18px;
577
+ border-radius: var(--npt-corner-full, 999px);
578
+ display: grid;
579
+ place-items: center;
580
+ font-size: var(--npt-text-caption, 12px);
581
+ background: var(--md-sys-color-tertiary);
582
+ color: var(--md-sys-color-on-tertiary);
583
+ }
584
+ .body {
585
+ flex: 1 1 auto;
586
+ min-inline-size: 0;
587
+ }
588
+ .name {
589
+ font-size: var(--npt-text-body-lg, 16px);
590
+ color: var(--md-sys-color-on-surface);
591
+ margin: 0;
592
+ white-space: nowrap;
593
+ overflow: hidden;
594
+ text-overflow: ellipsis;
595
+ }
596
+ .account {
597
+ font-family: var(--npt-font-num);
598
+ font-variant-numeric: tabular-nums;
599
+ font-size: var(--npt-text-body, 14px);
600
+ color: var(--md-sys-color-on-surface-variant);
601
+ margin: 2px 0 0;
602
+ }
603
+ .chevron {
604
+ flex: 0 0 auto;
605
+ color: var(--md-sys-color-on-surface-variant);
606
+ font-size: var(--npt-text-title, 18px);
607
+ line-height: 1;
608
+ }
609
+ `;
610
+ }
611
+ render() {
612
+ const name = esc(this.getAttribute("name"));
613
+ const account = esc(this.getAttribute("account"));
614
+ const favorite = this.hasAttribute("favorite");
615
+ const initials = this.initials(name);
616
+ const label = favorite ? `${name}, favourite${account ? `, ${account}` : ""}` : `${name}${account ? `, ${account}` : ""}`;
617
+ return html `<button class="tile" part="tile" type="button" aria-label="${esc(label)}">
618
+ <span class="avatar" aria-hidden="true">
619
+ ${initials}${favorite ? html `<span class="star">★</span>` : ""}
620
+ </span>
621
+ <span class="body">
622
+ <span class="name">${name}</span>
623
+ ${account ? html `<span class="account">${account}</span>` : ""}
624
+ </span>
625
+ <span class="chevron" aria-hidden="true">›</span>
626
+ </button>`;
627
+ }
628
+ }
629
+ NptBeneficiaryTile.observedAttributes = ["name", "account", "favorite"];
630
+ /**
631
+ * <npt-method-row title="Bank transfer" subtitle="1–2 business days" [recommended]>
632
+ * <span slot="icon">🏦</span>
633
+ * </npt-method-row>
634
+ * Transfer-method row: leading icon slot, title/subtitle, trailing chevron, badge.
635
+ */
636
+ export class NptMethodRow extends NptElement {
637
+ attributeChangedCallback() {
638
+ if (this.isConnected)
639
+ this.update();
640
+ }
641
+ styles() {
642
+ return css `
643
+ ${A11Y}
644
+ :host {
645
+ display: block;
646
+ }
647
+ .row {
648
+ inline-size: 100%;
649
+ display: flex;
650
+ align-items: center;
651
+ gap: var(--npt-space-4, 16px);
652
+ min-height: 64px;
653
+ padding-inline: var(--npt-space-4, 16px);
654
+ padding-block: var(--npt-space-3, 12px);
655
+ border: 1px solid var(--md-sys-color-outline-variant);
656
+ border-radius: var(--npt-corner-md, 16px);
657
+ background: var(--md-sys-color-surface-container-lowest);
658
+ color: inherit;
659
+ text-align: start;
660
+ font-family: var(--npt-font-text);
661
+ cursor: pointer;
662
+ box-sizing: border-box;
663
+ transition: border-color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease),
664
+ background-color var(--npt-dur-fast, 200ms) var(--npt-ease-standard, ease);
665
+ }
666
+ .row:hover {
667
+ border-color: var(--md-sys-color-primary);
668
+ background: var(--md-sys-color-surface-container);
669
+ }
670
+ .icon {
671
+ inline-size: 40px;
672
+ block-size: 40px;
673
+ flex: 0 0 auto;
674
+ border-radius: var(--npt-corner-sm, 12px);
675
+ display: grid;
676
+ place-items: center;
677
+ background: var(--md-sys-color-secondary-container);
678
+ color: var(--md-sys-color-on-secondary-container);
679
+ font-size: var(--npt-text-title, 18px);
680
+ }
681
+ .body {
682
+ flex: 1 1 auto;
683
+ min-inline-size: 0;
684
+ }
685
+ .titlebar {
686
+ display: flex;
687
+ align-items: center;
688
+ gap: var(--npt-space-2, 8px);
689
+ flex-wrap: wrap;
690
+ }
691
+ .title {
692
+ font-size: var(--npt-text-body-lg, 16px);
693
+ font-weight: 600;
694
+ color: var(--md-sys-color-on-surface);
695
+ margin: 0;
696
+ }
697
+ .subtitle {
698
+ font-size: var(--npt-text-body, 14px);
699
+ color: var(--md-sys-color-on-surface-variant);
700
+ margin: 2px 0 0;
701
+ }
702
+ .badge {
703
+ font-size: var(--npt-text-caption, 12px);
704
+ font-weight: 600;
705
+ line-height: 1;
706
+ padding-inline: var(--npt-space-2, 8px);
707
+ padding-block: var(--npt-space-1, 4px);
708
+ border-radius: var(--npt-corner-full, 999px);
709
+ background: var(--md-sys-color-success-container, var(--md-sys-color-tertiary-container));
710
+ color: var(--md-sys-color-on-success-container, var(--md-sys-color-on-tertiary-container));
711
+ }
712
+ .chevron {
713
+ flex: 0 0 auto;
714
+ color: var(--md-sys-color-on-surface-variant);
715
+ font-size: var(--npt-text-title, 18px);
716
+ line-height: 1;
717
+ }
718
+ `;
719
+ }
720
+ render() {
721
+ const title = esc(this.getAttribute("title"));
722
+ const subtitle = esc(this.getAttribute("subtitle"));
723
+ const recommended = this.hasAttribute("recommended");
724
+ const label = recommended ? `${title}, recommended` : title;
725
+ return html `<button class="row" part="row" type="button" aria-label="${esc(label)}">
726
+ <span class="icon" aria-hidden="true"><slot name="icon"></slot></span>
727
+ <span class="body">
728
+ <span class="titlebar">
729
+ <span class="title">${title}</span>
730
+ ${recommended ? html `<span class="badge" part="badge">Recommended</span>` : ""}
731
+ </span>
732
+ ${subtitle ? html `<span class="subtitle">${subtitle}</span>` : ""}
733
+ </span>
734
+ <span class="chevron" aria-hidden="true">›</span>
735
+ </button>`;
736
+ }
737
+ }
738
+ NptMethodRow.observedAttributes = ["title", "subtitle", "recommended"];
739
+ void define;
740
+ //# sourceMappingURL=money-movement.js.map