@erplora/outfitkit 0.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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +457 -0
  3. package/dist/base/anchor.d.ts +13 -0
  4. package/dist/base/define.d.ts +1 -0
  5. package/dist/base/relay.d.ts +1 -0
  6. package/dist/cdn.d.ts +96 -0
  7. package/dist/components/ok-app-launcher/ok-app-launcher.d.ts +57 -0
  8. package/dist/components/ok-audio/ok-audio.d.ts +45 -0
  9. package/dist/components/ok-avatar/ok-avatar.d.ts +36 -0
  10. package/dist/components/ok-avatar-group/ok-avatar-group.d.ts +38 -0
  11. package/dist/components/ok-bar-list/ok-bar-list.d.ts +36 -0
  12. package/dist/components/ok-bento/ok-bento.d.ts +17 -0
  13. package/dist/components/ok-bento-item/ok-bento-item.d.ts +34 -0
  14. package/dist/components/ok-calculator/ok-calculator.d.ts +46 -0
  15. package/dist/components/ok-calendar/ok-calendar.d.ts +63 -0
  16. package/dist/components/ok-carousel/ok-carousel.d.ts +48 -0
  17. package/dist/components/ok-chart/ok-chart.d.ts +55 -0
  18. package/dist/components/ok-chat/ok-chat.d.ts +54 -0
  19. package/dist/components/ok-coachmark/ok-coachmark.d.ts +69 -0
  20. package/dist/components/ok-code/ok-code.d.ts +28 -0
  21. package/dist/components/ok-color-picker/ok-color-picker.d.ts +63 -0
  22. package/dist/components/ok-combo/ok-combo.d.ts +46 -0
  23. package/dist/components/ok-command-palette/ok-command-palette.d.ts +72 -0
  24. package/dist/components/ok-contact-form/ok-contact-form.d.ts +54 -0
  25. package/dist/components/ok-cropper/ok-cropper.d.ts +60 -0
  26. package/dist/components/ok-cta-band/ok-cta-band.d.ts +18 -0
  27. package/dist/components/ok-currency/ok-currency.d.ts +31 -0
  28. package/dist/components/ok-data-table/ok-data-table.d.ts +312 -0
  29. package/dist/components/ok-date-picker/ok-date-picker.d.ts +81 -0
  30. package/dist/components/ok-detail-list/ok-detail-list.d.ts +30 -0
  31. package/dist/components/ok-diff/ok-diff.d.ts +38 -0
  32. package/dist/components/ok-donut/ok-donut.d.ts +38 -0
  33. package/dist/components/ok-drawer/ok-drawer.d.ts +56 -0
  34. package/dist/components/ok-dropzone/ok-dropzone.d.ts +48 -0
  35. package/dist/components/ok-empty-state/ok-empty-state.d.ts +16 -0
  36. package/dist/components/ok-error-page/ok-error-page.d.ts +77 -0
  37. package/dist/components/ok-event-card/ok-event-card.d.ts +56 -0
  38. package/dist/components/ok-feature-card/ok-feature-card.d.ts +23 -0
  39. package/dist/components/ok-file-item/ok-file-item.d.ts +31 -0
  40. package/dist/components/ok-file-manager/ok-file-manager.d.ts +145 -0
  41. package/dist/components/ok-footer/ok-footer.d.ts +10 -0
  42. package/dist/components/ok-funnel/ok-funnel.d.ts +31 -0
  43. package/dist/components/ok-gallery/ok-gallery.d.ts +34 -0
  44. package/dist/components/ok-gauge/ok-gauge.d.ts +49 -0
  45. package/dist/components/ok-heatmap/ok-heatmap.d.ts +45 -0
  46. package/dist/components/ok-hero/ok-hero.d.ts +10 -0
  47. package/dist/components/ok-hover-card/ok-hover-card.d.ts +76 -0
  48. package/dist/components/ok-icon-tile/ok-icon-tile.d.ts +24 -0
  49. package/dist/components/ok-image/ok-image.d.ts +56 -0
  50. package/dist/components/ok-inline-feedback/ok-inline-feedback.d.ts +33 -0
  51. package/dist/components/ok-invoice/ok-invoice.d.ts +137 -0
  52. package/dist/components/ok-json-viewer/ok-json-viewer.d.ts +31 -0
  53. package/dist/components/ok-kanban/ok-kanban.d.ts +56 -0
  54. package/dist/components/ok-kbd/ok-kbd.d.ts +21 -0
  55. package/dist/components/ok-keyboard/ok-keyboard.d.ts +35 -0
  56. package/dist/components/ok-kpi/ok-kpi.d.ts +24 -0
  57. package/dist/components/ok-language-select/ok-language-select.d.ts +31 -0
  58. package/dist/components/ok-lightbox/ok-lightbox.d.ts +59 -0
  59. package/dist/components/ok-logo-cloud/ok-logo-cloud.d.ts +14 -0
  60. package/dist/components/ok-loyalty-card/ok-loyalty-card.d.ts +35 -0
  61. package/dist/components/ok-mail/ok-mail.d.ts +117 -0
  62. package/dist/components/ok-menu/ok-menu.d.ts +75 -0
  63. package/dist/components/ok-menubar/ok-menubar.d.ts +75 -0
  64. package/dist/components/ok-navbar/ok-navbar.d.ts +42 -0
  65. package/dist/components/ok-notification-center/ok-notification-center.d.ts +79 -0
  66. package/dist/components/ok-org-chart/ok-org-chart.d.ts +67 -0
  67. package/dist/components/ok-otp/ok-otp.d.ts +31 -0
  68. package/dist/components/ok-page-header/ok-page-header.d.ts +23 -0
  69. package/dist/components/ok-pagination/ok-pagination.d.ts +44 -0
  70. package/dist/components/ok-pdf/ok-pdf.d.ts +32 -0
  71. package/dist/components/ok-phone/ok-phone.d.ts +48 -0
  72. package/dist/components/ok-pinpad/ok-pinpad.d.ts +29 -0
  73. package/dist/components/ok-pricing-card/ok-pricing-card.d.ts +31 -0
  74. package/dist/components/ok-product-card/ok-product-card.d.ts +25 -0
  75. package/dist/components/ok-qr/ok-qr.d.ts +24 -0
  76. package/dist/components/ok-qty-stepper/ok-qty-stepper.d.ts +35 -0
  77. package/dist/components/ok-range-dual/ok-range-dual.d.ts +38 -0
  78. package/dist/components/ok-rating/ok-rating.d.ts +33 -0
  79. package/dist/components/ok-receipt/ok-receipt.d.ts +103 -0
  80. package/dist/components/ok-reveal/ok-reveal.d.ts +21 -0
  81. package/dist/components/ok-rich-text/ok-rich-text.d.ts +46 -0
  82. package/dist/components/ok-scheduler/ok-scheduler.d.ts +74 -0
  83. package/dist/components/ok-select-card/ok-select-card.d.ts +37 -0
  84. package/dist/components/ok-signature/ok-signature.d.ts +55 -0
  85. package/dist/components/ok-skeleton/ok-skeleton.d.ts +40 -0
  86. package/dist/components/ok-sparkline/ok-sparkline.d.ts +27 -0
  87. package/dist/components/ok-split-button/ok-split-button.d.ts +49 -0
  88. package/dist/components/ok-splitter/ok-splitter.d.ts +36 -0
  89. package/dist/components/ok-stat/ok-stat.d.ts +16 -0
  90. package/dist/components/ok-status-dot/ok-status-dot.d.ts +24 -0
  91. package/dist/components/ok-status-pill/ok-status-pill.d.ts +22 -0
  92. package/dist/components/ok-stepper/ok-stepper.d.ts +33 -0
  93. package/dist/components/ok-store/ok-store.d.ts +33 -0
  94. package/dist/components/ok-tag-input/ok-tag-input.d.ts +39 -0
  95. package/dist/components/ok-testimonial/ok-testimonial.d.ts +21 -0
  96. package/dist/components/ok-time-picker/ok-time-picker.d.ts +50 -0
  97. package/dist/components/ok-timeline/ok-timeline.d.ts +33 -0
  98. package/dist/components/ok-tree/ok-tree.d.ts +46 -0
  99. package/dist/components/ok-video/ok-video.d.ts +49 -0
  100. package/dist/components/ok-widget-board/ok-widget-board.d.ts +71 -0
  101. package/dist/components/ok-wizard/ok-wizard.d.ts +30 -0
  102. package/dist/define.js +8 -0
  103. package/dist/erplora.css +112 -0
  104. package/dist/index.d.ts +158 -0
  105. package/dist/index.js +197 -0
  106. package/dist/layout.css +338 -0
  107. package/dist/ok-app-launcher.js +396 -0
  108. package/dist/ok-audio.js +308 -0
  109. package/dist/ok-avatar-group.js +158 -0
  110. package/dist/ok-avatar.js +179 -0
  111. package/dist/ok-bar-list.js +189 -0
  112. package/dist/ok-bento-item.js +168 -0
  113. package/dist/ok-bento.js +63 -0
  114. package/dist/ok-calculator.js +406 -0
  115. package/dist/ok-calendar.js +541 -0
  116. package/dist/ok-carousel.js +352 -0
  117. package/dist/ok-chart.js +325 -0
  118. package/dist/ok-chat.js +320 -0
  119. package/dist/ok-coachmark.js +500 -0
  120. package/dist/ok-code.js +190 -0
  121. package/dist/ok-color-picker.js +569 -0
  122. package/dist/ok-combo.js +294 -0
  123. package/dist/ok-command-palette.js +448 -0
  124. package/dist/ok-contact-form.js +288 -0
  125. package/dist/ok-cropper.js +404 -0
  126. package/dist/ok-cta-band.js +134 -0
  127. package/dist/ok-currency.js +172 -0
  128. package/dist/ok-data-table.js +1281 -0
  129. package/dist/ok-date-picker.js +736 -0
  130. package/dist/ok-detail-list.js +156 -0
  131. package/dist/ok-diff.js +200 -0
  132. package/dist/ok-donut.js +280 -0
  133. package/dist/ok-drawer.js +357 -0
  134. package/dist/ok-dropzone.js +376 -0
  135. package/dist/ok-empty-state.js +104 -0
  136. package/dist/ok-error-page.js +547 -0
  137. package/dist/ok-event-card.js +384 -0
  138. package/dist/ok-feature-card.js +152 -0
  139. package/dist/ok-file-item.js +259 -0
  140. package/dist/ok-file-manager.js +1116 -0
  141. package/dist/ok-footer.js +67 -0
  142. package/dist/ok-funnel.js +181 -0
  143. package/dist/ok-gallery.js +293 -0
  144. package/dist/ok-gauge.js +385 -0
  145. package/dist/ok-heatmap.js +268 -0
  146. package/dist/ok-hero.js +43 -0
  147. package/dist/ok-hover-card.js +480 -0
  148. package/dist/ok-icon-tile.js +123 -0
  149. package/dist/ok-image.js +471 -0
  150. package/dist/ok-inline-feedback.js +221 -0
  151. package/dist/ok-invoice.js +229 -0
  152. package/dist/ok-json-viewer.js +330 -0
  153. package/dist/ok-kanban.js +427 -0
  154. package/dist/ok-kbd.js +159 -0
  155. package/dist/ok-keyboard.js +402 -0
  156. package/dist/ok-kpi.js +147 -0
  157. package/dist/ok-language-select.js +188 -0
  158. package/dist/ok-lightbox.js +490 -0
  159. package/dist/ok-logo-cloud.js +92 -0
  160. package/dist/ok-loyalty-card.js +353 -0
  161. package/dist/ok-mail.js +562 -0
  162. package/dist/ok-menu.js +529 -0
  163. package/dist/ok-menubar.js +628 -0
  164. package/dist/ok-navbar.js +306 -0
  165. package/dist/ok-notification-center.js +545 -0
  166. package/dist/ok-org-chart.js +619 -0
  167. package/dist/ok-otp.js +199 -0
  168. package/dist/ok-page-header.js +202 -0
  169. package/dist/ok-pagination.js +366 -0
  170. package/dist/ok-pdf.js +160 -0
  171. package/dist/ok-phone.js +225 -0
  172. package/dist/ok-pinpad.js +171 -0
  173. package/dist/ok-pricing-card.js +184 -0
  174. package/dist/ok-product-card.js +178 -0
  175. package/dist/ok-qr.js +652 -0
  176. package/dist/ok-qty-stepper.js +212 -0
  177. package/dist/ok-range-dual.js +280 -0
  178. package/dist/ok-rating.js +199 -0
  179. package/dist/ok-receipt.js +183 -0
  180. package/dist/ok-reveal.js +94 -0
  181. package/dist/ok-rich-text.js +538 -0
  182. package/dist/ok-scheduler.js +518 -0
  183. package/dist/ok-select-card.js +231 -0
  184. package/dist/ok-signature.js +267 -0
  185. package/dist/ok-skeleton.js +345 -0
  186. package/dist/ok-sparkline.js +150 -0
  187. package/dist/ok-split-button.js +251 -0
  188. package/dist/ok-splitter.js +289 -0
  189. package/dist/ok-stat.js +77 -0
  190. package/dist/ok-status-dot.js +163 -0
  191. package/dist/ok-status-pill.js +123 -0
  192. package/dist/ok-stepper.js +299 -0
  193. package/dist/ok-store.js +83 -0
  194. package/dist/ok-tag-input.js +358 -0
  195. package/dist/ok-testimonial.js +136 -0
  196. package/dist/ok-time-picker.js +472 -0
  197. package/dist/ok-timeline.js +251 -0
  198. package/dist/ok-tree.js +266 -0
  199. package/dist/ok-video.js +362 -0
  200. package/dist/ok-widget-board.js +265 -0
  201. package/dist/ok-wizard.js +153 -0
  202. package/dist/outfitkit.js +96 -0
  203. package/dist/shared/anchor.js +14 -0
  204. package/dist/store/controller.d.ts +17 -0
  205. package/dist/store/idb.d.ts +16 -0
  206. package/dist/store/store.d.ts +39 -0
  207. package/dist/store-controller.js +31 -0
  208. package/dist/store.js +182 -0
  209. package/dist/theme.example.css +70 -0
  210. package/package.json +147 -0
@@ -0,0 +1,229 @@
1
+ import { LitElement, css, html, nothing } from "lit";
2
+ import { property } from "lit/decorators.js";
3
+ import { define } from "./define.js";
4
+ import "./ok-qr.js";
5
+ var __defProp = Object.defineProperty;
6
+ var __decorateClass = (decorators, target, key, kind) => {
7
+ var result = void 0;
8
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
9
+ if (decorator = decorators[i])
10
+ result = decorator(target, key, result) || result;
11
+ if (result) __defProp(target, key, result);
12
+ return result;
13
+ };
14
+ const DEFAULT_LABELS = {
15
+ empty: "No invoice data.",
16
+ invoice: "Invoice",
17
+ number: "No.",
18
+ date: "Date",
19
+ dueDate: "Due date",
20
+ billTo: "Bill to",
21
+ description: "Description",
22
+ qty: "Qty",
23
+ price: "Price",
24
+ discount: "Disc.",
25
+ tax: "Tax",
26
+ amount: "Amount",
27
+ noLines: "— No lines —",
28
+ taxBase: "Tax base",
29
+ discountTotal: "Discount",
30
+ total: "TOTAL",
31
+ paymentMethod: "Payment method"
32
+ };
33
+ class OkInvoice extends LitElement {
34
+ constructor() {
35
+ super(...arguments);
36
+ this.qrSize = 96;
37
+ this.labels = {};
38
+ }
39
+ static {
40
+ this.styles = css`
41
+ :host {
42
+ --ink: var(--ok-text, var(--ion-text-color, #1c1b18));
43
+ --muted: #6b6b6b;
44
+ --rule: #d9d6cf;
45
+ --accent: var(--ok-color-primary, var(--ion-color-primary, #0091ce));
46
+ --soft: color-mix(in srgb, var(--accent) 8%, #fff);
47
+ display: block;
48
+ width: 100%;
49
+ }
50
+ .sheet {
51
+ box-sizing: border-box;
52
+ /* A4: ancho de papel. Overridable vía --invoice-width. */
53
+ width: var(--invoice-width, 210mm);
54
+ max-width: 100%;
55
+ margin: 0 auto;
56
+ padding: 16mm 14mm;
57
+ background: #fff;
58
+ color: var(--ink);
59
+ font-family: var(--ok-font, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif);
60
+ font-size: 12px;
61
+ line-height: 1.5;
62
+ }
63
+ /* Cabecera: emisor a la izquierda, bloque "FACTURA" a la derecha. */
64
+ .top { display: flex; justify-content: space-between; gap: 2rem; align-items: flex-start; }
65
+ .issuer-logo { max-height: 18mm; max-width: 55mm; margin-bottom: .5rem; display: block; }
66
+ .issuer-name { font-size: 15px; font-weight: 700; }
67
+ .issuer-meta, .party-meta { color: var(--muted); font-size: 11px; white-space: pre-line; }
68
+ .doc { text-align: right; min-width: 48mm; }
69
+ .doc-title { font-size: 24px; font-weight: 800; letter-spacing: .06em; color: var(--accent); text-transform: uppercase; }
70
+ .doc-type { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; }
71
+ .doc-grid { margin-top: .6rem; display: grid; grid-template-columns: auto auto; gap: .1rem .8rem; justify-content: end; font-size: 11px; }
72
+ .doc-grid .k { color: var(--muted); text-align: right; }
73
+ .doc-grid .v { font-weight: 600; text-align: right; }
74
+ /* Bloque receptor. */
75
+ .bill-to { margin: 9mm 0 6mm; padding: 3mm 4mm; background: var(--soft); border-radius: 8px; }
76
+ .bill-to .label { font-size: 9px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }
77
+ .bill-to .name { font-weight: 700; font-size: 13px; }
78
+ /* Tabla de líneas. */
79
+ table.lines { width: 100%; border-collapse: collapse; margin-top: 2mm; }
80
+ table.lines thead th {
81
+ font-size: 9px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
82
+ text-align: left; padding: 2mm 2mm; border-bottom: 1.5px solid var(--ink);
83
+ }
84
+ table.lines tbody td { padding: 2mm 2mm; border-bottom: 1px solid var(--rule); vertical-align: top; }
85
+ .num { text-align: right; white-space: nowrap; }
86
+ .desc { width: 42%; }
87
+ /* Resumen de totales (derecha). */
88
+ .summary { display: flex; justify-content: flex-end; margin-top: 4mm; }
89
+ .summary table { border-collapse: collapse; min-width: 70mm; }
90
+ .summary td { padding: 1mm 2mm; }
91
+ .summary td.num { text-align: right; white-space: nowrap; }
92
+ .summary .grand td { font-size: 15px; font-weight: 800; border-top: 1.5px solid var(--ink); padding-top: 2mm; }
93
+ .summary .grand td.num { color: var(--accent); }
94
+ .muted { color: var(--muted); }
95
+ /* Pie: pago, notas, QR. */
96
+ .foot { margin-top: 8mm; display: flex; justify-content: space-between; gap: 2rem; align-items: flex-start; }
97
+ .pay-box { font-size: 11px; }
98
+ .pay-box .h { font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
99
+ .qr-wrap { display: flex; flex-direction: column; align-items: center; gap: 1mm; }
100
+ .qr-note { font-size: 8px; max-width: 36mm; text-align: center; color: var(--muted); word-break: break-word; }
101
+ .legal { margin-top: 8mm; padding-top: 3mm; border-top: 1px solid var(--rule); font-size: 9px; color: var(--muted); white-space: pre-line; text-align: center; }
102
+ .empty { padding: 12mm; text-align: center; color: #999; font-style: italic; }
103
+ `;
104
+ }
105
+ get t() {
106
+ return { ...DEFAULT_LABELS, ...this.labels };
107
+ }
108
+ cur() {
109
+ return this.invoice?.currency ?? "€";
110
+ }
111
+ money(n) {
112
+ return `${Number(n ?? 0).toFixed(2)} ${this.cur()}`;
113
+ }
114
+ render() {
115
+ const inv = this.invoice;
116
+ if (!inv) return html`<div class="sheet empty">${this.t.empty}</div>`;
117
+ return html`<div class="sheet" part="sheet">
118
+ ${this.renderTop(inv)}
119
+ ${this.renderBillTo(inv)}
120
+ ${this.renderLines(inv)}
121
+ ${this.renderSummary(inv)}
122
+ ${this.renderFoot(inv)}
123
+ ${inv.footer ? html`<div class="legal">${inv.footer}</div>` : nothing}
124
+ </div>`;
125
+ }
126
+ party(p) {
127
+ const loc = [p.postal_code, p.city].filter(Boolean).join(" ");
128
+ const lines = [p.address, loc, p.country, p.tax_id, p.email, p.phone].filter(Boolean);
129
+ return html`${lines.map((l) => html`<div>${l}</div>`)}`;
130
+ }
131
+ renderTop(inv) {
132
+ const iss = inv.issuer ?? { name: "" };
133
+ return html`<div class="top">
134
+ <div>
135
+ ${iss.logo_url ? html`<img class="issuer-logo" src=${iss.logo_url} alt=${iss.name || "logo"} />` : nothing}
136
+ <div class="issuer-name">${iss.name}</div>
137
+ <div class="issuer-meta">${this.party(iss)}</div>
138
+ </div>
139
+ <div class="doc">
140
+ <div class="doc-title">${this.t.invoice}</div>
141
+ ${inv.type ? html`<div class="doc-type">${inv.type}</div>` : nothing}
142
+ <div class="doc-grid">
143
+ <span class="k">${this.t.number}</span><span class="v">${inv.number}</span>
144
+ <span class="k">${this.t.date}</span><span class="v">${inv.issue_date}</span>
145
+ ${inv.due_date ? html`<span class="k">${this.t.dueDate}</span><span class="v">${inv.due_date}</span>` : nothing}
146
+ </div>
147
+ </div>
148
+ </div>`;
149
+ }
150
+ renderBillTo(inv) {
151
+ const c = inv.customer;
152
+ if (!c) return nothing;
153
+ return html`<div class="bill-to">
154
+ <div class="label">${this.t.billTo}</div>
155
+ <div class="name">${c.name}</div>
156
+ <div class="party-meta">${this.party(c)}</div>
157
+ </div>`;
158
+ }
159
+ renderLines(inv) {
160
+ const lines = inv.lines ?? [];
161
+ const hasDisc = lines.some((l) => l.discount_percent);
162
+ const hasTax = lines.some((l) => l.tax_rate != null);
163
+ return html`<table class="lines">
164
+ <thead>
165
+ <tr>
166
+ <th class="desc">${this.t.description}</th>
167
+ <th class="num">${this.t.qty}</th>
168
+ <th class="num">${this.t.price}</th>
169
+ ${hasDisc ? html`<th class="num">${this.t.discount}</th>` : nothing}
170
+ ${hasTax ? html`<th class="num">${this.t.tax}</th>` : nothing}
171
+ <th class="num">${this.t.amount}</th>
172
+ </tr>
173
+ </thead>
174
+ <tbody>
175
+ ${lines.length ? lines.map(
176
+ (l) => html`<tr>
177
+ <td class="desc">${l.description}</td>
178
+ <td class="num">${l.qty}</td>
179
+ <td class="num">${this.money(l.unit_price)}</td>
180
+ ${hasDisc ? html`<td class="num">${l.discount_percent ? `${l.discount_percent}%` : "—"}</td>` : nothing}
181
+ ${hasTax ? html`<td class="num">${l.tax_rate != null ? `${l.tax_rate}%` : "—"}</td>` : nothing}
182
+ <td class="num">${this.money(l.total)}</td>
183
+ </tr>`
184
+ ) : html`<tr><td colspan="6" class="muted" style="text-align:center;padding:6mm">${this.t.noLines}</td></tr>`}
185
+ </tbody>
186
+ </table>`;
187
+ }
188
+ renderSummary(inv) {
189
+ const taxes = inv.taxes ?? [];
190
+ return html`<div class="summary">
191
+ <table>
192
+ <tr><td class="muted">${this.t.taxBase}</td><td class="num">${this.money(inv.subtotal)}</td></tr>
193
+ ${inv.discount_total ? html`<tr><td class="muted">${this.t.discountTotal}</td><td class="num">−${this.money(inv.discount_total)}</td></tr>` : nothing}
194
+ ${taxes.map(
195
+ (t) => html`<tr><td class="muted">${t.label}${t.base != null ? html` <span class="muted">(${this.money(t.base)})</span>` : nothing}</td><td class="num">${this.money(t.amount)}</td></tr>`
196
+ )}
197
+ <tr class="grand"><td>${this.t.total}</td><td class="num">${this.money(inv.total)}</td></tr>
198
+ </table>
199
+ </div>`;
200
+ }
201
+ renderFoot(inv) {
202
+ const hasPay = inv.payment_method || inv.payment_terms || inv.notes;
203
+ if (!hasPay && !inv.qr) return nothing;
204
+ return html`<div class="foot">
205
+ <div class="pay-box">
206
+ ${inv.payment_method ? html`<div class="h">${this.t.paymentMethod}</div><div>${inv.payment_method}</div>` : nothing}
207
+ ${inv.payment_terms ? html`<div style="margin-top:2mm" class="muted">${inv.payment_terms}</div>` : nothing}
208
+ ${inv.notes ? html`<div style="margin-top:3mm">${inv.notes}</div>` : nothing}
209
+ </div>
210
+ ${inv.qr ? html`<div class="qr-wrap">
211
+ <ok-qr .value=${inv.qr} .size=${this.qrSize} ec="M"></ok-qr>
212
+ ${inv.qr_note ? html`<div class="qr-note">${inv.qr_note}</div>` : nothing}
213
+ </div>` : nothing}
214
+ </div>`;
215
+ }
216
+ }
217
+ __decorateClass([
218
+ property({ attribute: false })
219
+ ], OkInvoice.prototype, "invoice");
220
+ __decorateClass([
221
+ property({ type: Number, attribute: "qr-size" })
222
+ ], OkInvoice.prototype, "qrSize");
223
+ __decorateClass([
224
+ property({ attribute: false })
225
+ ], OkInvoice.prototype, "labels");
226
+ define("ok-invoice", OkInvoice);
227
+ export {
228
+ OkInvoice
229
+ };
@@ -0,0 +1,330 @@
1
+ import { LitElement, css, html } from "lit";
2
+ import { property, state } from "lit/decorators.js";
3
+ import { define } from "./define.js";
4
+ var __defProp = Object.defineProperty;
5
+ var __decorateClass = (decorators, target, key, kind) => {
6
+ var result = void 0;
7
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
8
+ if (decorator = decorators[i])
9
+ result = decorator(target, key, result) || result;
10
+ if (result) __defProp(target, key, result);
11
+ return result;
12
+ };
13
+ const _OkJsonViewer = class _OkJsonViewer2 extends LitElement {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.data = null;
17
+ this.size = "default";
18
+ this.expandedDepth = 1;
19
+ this.collapsed = /* @__PURE__ */ new Set();
20
+ }
21
+ static {
22
+ this.styles = css`
23
+ :host {
24
+ /* Tokens propios estilo Ionic (overridables): --ok-* → --ion-* → hex. */
25
+ --bg: var(--ok-surface, var(--ion-background-color, #ffffff));
26
+ --border: var(--ok-border, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.12));
27
+ --guide: var(--ok-border-soft, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.1));
28
+ --ink: var(--ok-text, var(--ion-text-color, #1c1b17));
29
+ --ink-muted: var(--ok-text-muted, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.55));
30
+ --ink-faint: var(--ok-text-faint, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.4));
31
+ --hover-bg: var(--ok-hover, rgba(var(--ion-text-color-rgb, 28, 27, 23), 0.06));
32
+ --radius: var(--ok-radius, 8px);
33
+ /* Colores por tipo (cada uno con su cadena de fallback). */
34
+ --key-color: var(--ok-json-key, var(--ion-color-primary, #3880ff));
35
+ --string-color: var(--ok-json-string, var(--ion-color-success, #2dd36f));
36
+ --number-color: var(--ok-json-number, var(--ion-color-warning, #ffc409));
37
+ --bool-color: var(--ok-json-bool, var(--ion-color-secondary, #6030ff));
38
+ --null-color: var(--ok-json-null, var(--ink-faint));
39
+ --font-mono: var(--ok-font-mono, ui-monospace, 'SFMono-Regular', 'Menlo', 'Consolas', monospace);
40
+
41
+ display: block;
42
+ width: 100%;
43
+ }
44
+
45
+ .json {
46
+ box-sizing: border-box;
47
+ width: 100%;
48
+ font-family: var(--font-mono);
49
+ font-size: 0.8125rem;
50
+ font-variant-numeric: tabular-nums;
51
+ line-height: 1.55;
52
+ color: var(--ink);
53
+ background: var(--bg);
54
+ border: 1px solid var(--border);
55
+ border-radius: var(--radius);
56
+ padding: 0.625rem 0.875rem;
57
+ overflow: auto;
58
+ }
59
+ /* Tamaños: ajustan fuente, padding e indentación. */
60
+ .json.compact {
61
+ font-size: 0.75rem;
62
+ padding: 0.5rem 0.625rem;
63
+ --indent: 14px;
64
+ }
65
+ .json.default {
66
+ --indent: 18px;
67
+ }
68
+ .json.lg {
69
+ font-size: 0.9375rem;
70
+ padding: 0.875rem 1.125rem;
71
+ --indent: 22px;
72
+ }
73
+
74
+ .group {
75
+ margin: 0;
76
+ padding: 0 0 0 var(--indent);
77
+ list-style: none;
78
+ /* Guía de indentación a la izquierda. */
79
+ border-left: 1px solid var(--guide);
80
+ margin-left: 6px;
81
+ }
82
+
83
+ .row {
84
+ display: flex;
85
+ align-items: flex-start;
86
+ gap: 4px;
87
+ white-space: pre;
88
+ border-radius: 4px;
89
+ }
90
+ .row.has-children {
91
+ cursor: pointer;
92
+ }
93
+ @media (hover: hover) {
94
+ .row.has-children:hover {
95
+ background: var(--hover-bg);
96
+ }
97
+ }
98
+
99
+ /* Chevron: botón que rota 90deg al expandir. Reserva hueco en las hojas. */
100
+ .caret {
101
+ flex: 0 0 auto;
102
+ display: inline-flex;
103
+ align-items: center;
104
+ justify-content: center;
105
+ width: 14px;
106
+ height: 1.55em;
107
+ padding: 0;
108
+ border: 0;
109
+ background: none;
110
+ color: var(--ink-muted);
111
+ cursor: pointer;
112
+ border-radius: 3px;
113
+ transition: transform 0.18s ease, color 0.15s ease;
114
+ }
115
+ .caret.open {
116
+ transform: rotate(90deg);
117
+ }
118
+ .caret.leaf {
119
+ visibility: hidden;
120
+ cursor: default;
121
+ }
122
+ .caret svg {
123
+ width: 9px;
124
+ height: 9px;
125
+ display: block;
126
+ }
127
+
128
+ /* Colores por tipo. */
129
+ .key {
130
+ color: var(--key-color);
131
+ font-weight: 500;
132
+ }
133
+ .key::after {
134
+ content: ': ';
135
+ color: var(--ink-faint);
136
+ }
137
+ .idx {
138
+ color: var(--ink-faint);
139
+ }
140
+ .idx::after {
141
+ content: ': ';
142
+ }
143
+ .string {
144
+ color: var(--string-color);
145
+ white-space: pre-wrap;
146
+ word-break: break-word;
147
+ }
148
+ .string::before,
149
+ .string::after {
150
+ content: '"';
151
+ opacity: 0.7;
152
+ }
153
+ .number {
154
+ color: var(--number-color);
155
+ }
156
+ .bool {
157
+ color: var(--bool-color);
158
+ font-weight: 500;
159
+ }
160
+ .null {
161
+ color: var(--null-color);
162
+ font-style: italic;
163
+ }
164
+ .bracket,
165
+ .comma {
166
+ color: var(--ink-faint);
167
+ }
168
+
169
+ /* Badge de recuento al colapsar ("3 keys" / "5 items"). */
170
+ .count {
171
+ color: var(--ink-faint);
172
+ font-style: italic;
173
+ font-size: 0.875em;
174
+ margin-left: 6px;
175
+ }
176
+
177
+ @media (prefers-reduced-motion: reduce) {
178
+ .caret {
179
+ transition: none;
180
+ }
181
+ }
182
+ `;
183
+ }
184
+ // Parsea `data` si viene como string JSON; si falla, devuelve el string crudo.
185
+ get value() {
186
+ const d = this.data;
187
+ if (typeof d === "string") {
188
+ try {
189
+ return JSON.parse(d);
190
+ } catch {
191
+ return d;
192
+ }
193
+ }
194
+ return d;
195
+ }
196
+ // ¿Es un contenedor (objeto/array no vacío) que se puede colapsar?
197
+ static hasChildren(v) {
198
+ if (Array.isArray(v)) return v.length > 0;
199
+ return v !== null && typeof v === "object" && Object.keys(v).length > 0;
200
+ }
201
+ // Decide si un path está expandido: el override del usuario manda; si no, la profundidad inicial.
202
+ isExpanded(path, depth) {
203
+ if (this.collapsed.has(path)) return false;
204
+ if (this.expandedDepth < 0) return true;
205
+ return depth < this.expandedDepth;
206
+ }
207
+ // Alterna expansión de un contenedor y emite `ok-toggle`.
208
+ toggle(path, depth) {
209
+ const next = new Set(this.collapsed);
210
+ const wasExpanded = this.isExpanded(path, depth);
211
+ if (wasExpanded) next.add(path);
212
+ else next.delete(path);
213
+ this.collapsed = next;
214
+ this.dispatchEvent(
215
+ new CustomEvent("ok-toggle", {
216
+ detail: { path, expanded: !wasExpanded },
217
+ bubbles: true,
218
+ composed: true
219
+ })
220
+ );
221
+ }
222
+ // Chevron SVG inline (sin dependencias).
223
+ static caretSvg() {
224
+ return html`<svg viewBox="0 0 10 10" aria-hidden="true">
225
+ <path d="M3 1.5 L7 5 L3 8.5" fill="none" stroke="currentColor" stroke-width="1.6"
226
+ stroke-linecap="round" stroke-linejoin="round"></path>
227
+ </svg>`;
228
+ }
229
+ // Render del valor "hoja" (string/number/bool/null) con su clase de color.
230
+ static renderLeaf(v) {
231
+ if (v === null) return html`<span class="null">null</span>`;
232
+ switch (typeof v) {
233
+ case "string":
234
+ return html`<span class="string">${v}</span>`;
235
+ case "number":
236
+ return html`<span class="number">${String(v)}</span>`;
237
+ case "boolean":
238
+ return html`<span class="bool">${v ? "true" : "false"}</span>`;
239
+ default:
240
+ return html`<span class="string">${String(v)}</span>`;
241
+ }
242
+ }
243
+ // Texto del badge de recuento de un contenedor colapsado.
244
+ static countLabel(v) {
245
+ if (Array.isArray(v)) {
246
+ return `${v.length} ${v.length === 1 ? "item" : "items"}`;
247
+ }
248
+ const n = Object.keys(v).length;
249
+ return `${n} ${n === 1 ? "key" : "keys"}`;
250
+ }
251
+ // Render recursivo de una fila. `keyLabel` es la clave de objeto o el índice de array (o null
252
+ // para la raíz); `path` identifica la fila; `depth` controla la expansión inicial.
253
+ renderRow(keyLabel, v, path, depth, trailingComma) {
254
+ const children = _OkJsonViewer2.hasChildren(v);
255
+ const isArr = Array.isArray(v);
256
+ const open = children && this.isExpanded(path, depth);
257
+ const label = keyLabel ? keyLabel.kind === "key" ? html`<span class="key">${keyLabel.text}</span>` : html`<span class="idx">${keyLabel.text}</span>` : null;
258
+ const comma = trailingComma ? html`<span class="comma">,</span>` : null;
259
+ if (!children) {
260
+ if (v !== null && typeof v === "object") {
261
+ return html`<div class="row">
262
+ <span class="caret leaf">${_OkJsonViewer2.caretSvg()}</span>
263
+ ${label}<span class="bracket">${isArr ? "[]" : "{}"}</span>${comma}
264
+ </div>`;
265
+ }
266
+ return html`<div class="row">
267
+ <span class="caret leaf">${_OkJsonViewer2.caretSvg()}</span>
268
+ ${label}${_OkJsonViewer2.renderLeaf(v)}${comma}
269
+ </div>`;
270
+ }
271
+ const entries = isArr ? v.map((item, i) => [{ kind: "idx", text: String(i) }, item]) : Object.entries(v).map(([k, item]) => [
272
+ { kind: "key", text: k },
273
+ item
274
+ ]);
275
+ const openB = isArr ? "[" : "{";
276
+ const closeB = isArr ? "]" : "}";
277
+ return html`<div>
278
+ <div
279
+ class="row has-children"
280
+ role="button"
281
+ tabindex="0"
282
+ aria-expanded=${String(open)}
283
+ @click=${() => this.toggle(path, depth)}
284
+ @keydown=${(e) => {
285
+ if (e.key === "Enter" || e.key === " ") {
286
+ e.preventDefault();
287
+ this.toggle(path, depth);
288
+ }
289
+ }}
290
+ >
291
+ <span class=${`caret ${open ? "open" : ""}`}>${_OkJsonViewer2.caretSvg()}</span>
292
+ ${label}<span class="bracket">${openB}</span>
293
+ ${open ? null : html`<span class="count">${_OkJsonViewer2.countLabel(v)}</span>`}
294
+ ${open ? null : html`<span class="bracket">${closeB}</span>`}${open ? null : comma}
295
+ </div>
296
+ ${open ? html`<div class="group" role="group">
297
+ ${entries.map(
298
+ ([kl, item], i) => this.renderRow(kl, item, `${path}/${kl.text}`, depth + 1, i < entries.length - 1)
299
+ )}
300
+ </div>
301
+ <div class="row">
302
+ <span class="caret leaf">${_OkJsonViewer2.caretSvg()}</span>
303
+ <span class="bracket">${closeB}</span>${comma}
304
+ </div>` : null}
305
+ </div>`;
306
+ }
307
+ render() {
308
+ const size = ["compact", "default", "lg"].includes(this.size) ? this.size : "default";
309
+ return html`<div class=${`json ${size}`} role="tree">
310
+ ${this.renderRow(null, this.value, "$", 0, false)}
311
+ </div>`;
312
+ }
313
+ };
314
+ __decorateClass([
315
+ property({ attribute: false })
316
+ ], _OkJsonViewer.prototype, "data");
317
+ __decorateClass([
318
+ property()
319
+ ], _OkJsonViewer.prototype, "size");
320
+ __decorateClass([
321
+ property({ type: Number, attribute: "expanded-depth" })
322
+ ], _OkJsonViewer.prototype, "expandedDepth");
323
+ __decorateClass([
324
+ state()
325
+ ], _OkJsonViewer.prototype, "collapsed");
326
+ let OkJsonViewer = _OkJsonViewer;
327
+ define("ok-json-viewer", OkJsonViewer);
328
+ export {
329
+ OkJsonViewer
330
+ };