@krizaka/charts 0.1.0 → 0.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 (193) hide show
  1. package/README.md +17 -5
  2. package/dist/bar.js +5 -4
  3. package/dist/candlestick.js +3 -3
  4. package/dist/chart.js +3 -3
  5. package/dist/{chunk-EK3Z647J.js → chunk-4LBXEAGC.js} +3 -3
  6. package/dist/{chunk-AHQXJSAQ.js → chunk-AA5EWWYV.js} +2 -2
  7. package/dist/{chunk-VKO2OYYM.js → chunk-ARARFMNE.js} +2 -2
  8. package/dist/{chunk-WBH2QU77.js → chunk-BV4DBGN7.js} +2 -2
  9. package/dist/{chunk-BZ5CQFPH.js → chunk-C4MFZLJM.js} +2 -2
  10. package/dist/{chunk-XAJ3KCC4.js → chunk-CSSZLFLO.js} +3 -3
  11. package/dist/{chunk-UNK4MJVG.js → chunk-CVWSMUUB.js} +8 -8
  12. package/dist/chunk-E5DKBSWX.js +2 -0
  13. package/dist/chunk-E5DKBSWX.js.map +1 -0
  14. package/dist/chunk-EEP7PS2L.js +54 -0
  15. package/dist/chunk-EEP7PS2L.js.map +1 -0
  16. package/dist/{chunk-DZB6HEVO.js → chunk-EQLC2QVN.js} +2 -2
  17. package/dist/chunk-FINOPIDN.js +2 -0
  18. package/dist/chunk-FINOPIDN.js.map +1 -0
  19. package/dist/chunk-G2KF2WL4.js +2 -0
  20. package/dist/chunk-G2KF2WL4.js.map +1 -0
  21. package/dist/{chunk-PTSB3H5Q.js → chunk-I3D7KUGN.js} +2 -2
  22. package/dist/chunk-IKQV3NSL.js +76 -0
  23. package/dist/chunk-IKQV3NSL.js.map +1 -0
  24. package/dist/{chunk-DWJPPEMC.js → chunk-JTKR7ZWP.js} +73 -60
  25. package/dist/chunk-JTKR7ZWP.js.map +1 -0
  26. package/dist/chunk-KNDHO67X.js +78 -0
  27. package/dist/chunk-KNDHO67X.js.map +1 -0
  28. package/dist/chunk-L2EKYWVI.js +94 -0
  29. package/dist/chunk-L2EKYWVI.js.map +1 -0
  30. package/dist/{chunk-XC6BQ3RN.js → chunk-MXLITIGU.js} +3 -3
  31. package/dist/{chunk-OER6ETT4.js → chunk-NCIQMRV3.js} +3 -3
  32. package/dist/chunk-OIRHLJBC.js +83 -0
  33. package/dist/chunk-OIRHLJBC.js.map +1 -0
  34. package/dist/{chunk-WIRCIOLH.js → chunk-PBQV3B6O.js} +5 -5
  35. package/dist/chunk-POQIHFAZ.js +2 -0
  36. package/dist/chunk-POQIHFAZ.js.map +1 -0
  37. package/dist/{chunk-I5QUZVU2.js → chunk-PWMMXRMC.js} +2 -2
  38. package/dist/chunk-SLEJDQ3A.js +81 -0
  39. package/dist/chunk-SLEJDQ3A.js.map +1 -0
  40. package/dist/{chunk-7TIFCK5E.js → chunk-VKZZY2QD.js} +3 -3
  41. package/dist/{chunk-VKTZD7UT.js → chunk-W5ILLSPK.js} +3 -3
  42. package/dist/chunk-WBHFVBSK.js +25 -0
  43. package/dist/chunk-WBHFVBSK.js.map +1 -0
  44. package/dist/chunk-WNUFGMS7.js +113 -0
  45. package/dist/chunk-WNUFGMS7.js.map +1 -0
  46. package/dist/{chunk-XR4ZJDOV.js → chunk-WVTIKOII.js} +2 -2
  47. package/dist/{chunk-7CSAGFBW.js → chunk-XDDALY4C.js} +3 -3
  48. package/dist/credits.d.ts +42 -0
  49. package/dist/credits.js +21 -0
  50. package/dist/credits.js.map +1 -0
  51. package/dist/earnings.d.ts +29 -0
  52. package/dist/earnings.js +22 -0
  53. package/dist/earnings.js.map +1 -0
  54. package/dist/funnel.js +3 -3
  55. package/dist/gauge.js +3 -2
  56. package/dist/geo.js +2 -2
  57. package/dist/globe.js +2 -2
  58. package/dist/goal.d.ts +26 -0
  59. package/dist/goal.js +17 -0
  60. package/dist/goal.js.map +1 -0
  61. package/dist/heatmap.js +3 -3
  62. package/dist/index.d.ts +7 -0
  63. package/dist/index.js +80 -33
  64. package/dist/labels-DE_743fQ.d.ts +72 -0
  65. package/dist/latency.d.ts +33 -0
  66. package/dist/latency.js +24 -0
  67. package/dist/latency.js.map +1 -0
  68. package/dist/line.js +5 -4
  69. package/dist/native.d.ts +195 -1
  70. package/dist/native.js +383 -14
  71. package/dist/native.js.map +1 -1
  72. package/dist/pie.js +3 -3
  73. package/dist/radar.js +3 -3
  74. package/dist/sankey.js +3 -3
  75. package/dist/scatter.js +3 -3
  76. package/dist/sparkline.js +4 -3
  77. package/dist/throughput.d.ts +37 -0
  78. package/dist/throughput.js +24 -0
  79. package/dist/throughput.js.map +1 -0
  80. package/dist/ticker.d.ts +38 -0
  81. package/dist/ticker.js +22 -0
  82. package/dist/ticker.js.map +1 -0
  83. package/dist/treemap.js +3 -3
  84. package/package.json +100 -4
  85. package/registry/area-chart.json +1 -0
  86. package/registry/bar-chart.json +1 -0
  87. package/registry/calendar-heatmap.json +1 -0
  88. package/registry/candlestick.json +1 -0
  89. package/registry/chart.json +1 -0
  90. package/registry/charts-provider.json +1 -0
  91. package/registry/credit-usage.json +473 -0
  92. package/registry/earnings-chart.json +703 -0
  93. package/registry/examples/credit-usage/monthly-credits.d.ts +4 -0
  94. package/registry/examples/credit-usage/monthly-credits.js +24 -0
  95. package/registry/examples/credit-usage/monthly-credits.tsx +19 -0
  96. package/registry/examples/credit-usage/native/monthly-credits.d.ts +4 -0
  97. package/registry/examples/credit-usage/native/monthly-credits.dark.png +0 -0
  98. package/registry/examples/credit-usage/native/monthly-credits.js +23 -0
  99. package/registry/examples/credit-usage/native/monthly-credits.light.png +0 -0
  100. package/registry/examples/credit-usage/native/monthly-credits.tsx +18 -0
  101. package/registry/examples/credit-usage/storage-plan.d.ts +4 -0
  102. package/registry/examples/credit-usage/storage-plan.js +21 -0
  103. package/registry/examples/credit-usage/storage-plan.tsx +15 -0
  104. package/registry/examples/earnings-chart/creator-month.d.ts +4 -0
  105. package/registry/examples/earnings-chart/creator-month.js +29 -0
  106. package/registry/examples/earnings-chart/creator-month.tsx +24 -0
  107. package/registry/examples/earnings-chart/gross-and-net.d.ts +4 -0
  108. package/registry/examples/earnings-chart/gross-and-net.js +29 -0
  109. package/registry/examples/earnings-chart/gross-and-net.tsx +24 -0
  110. package/registry/examples/earnings-chart/native/creator-month.d.ts +4 -0
  111. package/registry/examples/earnings-chart/native/creator-month.dark.png +0 -0
  112. package/registry/examples/earnings-chart/native/creator-month.js +29 -0
  113. package/registry/examples/earnings-chart/native/creator-month.light.png +0 -0
  114. package/registry/examples/earnings-chart/native/creator-month.tsx +24 -0
  115. package/registry/examples/goal-progress/challenge-pot.d.ts +4 -0
  116. package/registry/examples/goal-progress/challenge-pot.js +22 -0
  117. package/registry/examples/goal-progress/challenge-pot.tsx +16 -0
  118. package/registry/examples/goal-progress/goal-reached.d.ts +4 -0
  119. package/registry/examples/goal-progress/goal-reached.js +11 -0
  120. package/registry/examples/goal-progress/goal-reached.tsx +6 -0
  121. package/registry/examples/goal-progress/native/challenge-pot.d.ts +4 -0
  122. package/registry/examples/goal-progress/native/challenge-pot.dark.png +0 -0
  123. package/registry/examples/goal-progress/native/challenge-pot.js +11 -0
  124. package/registry/examples/goal-progress/native/challenge-pot.light.png +0 -0
  125. package/registry/examples/goal-progress/native/challenge-pot.tsx +6 -0
  126. package/registry/examples/job-throughput/live-hours.d.ts +4 -0
  127. package/registry/examples/job-throughput/live-hours.js +33 -0
  128. package/registry/examples/job-throughput/live-hours.tsx +28 -0
  129. package/registry/examples/job-throughput/native/week-of-jobs.d.ts +4 -0
  130. package/registry/examples/job-throughput/native/week-of-jobs.dark.png +0 -0
  131. package/registry/examples/job-throughput/native/week-of-jobs.js +20 -0
  132. package/registry/examples/job-throughput/native/week-of-jobs.light.png +0 -0
  133. package/registry/examples/job-throughput/native/week-of-jobs.tsx +16 -0
  134. package/registry/examples/job-throughput/week-of-jobs.d.ts +4 -0
  135. package/registry/examples/job-throughput/week-of-jobs.js +20 -0
  136. package/registry/examples/job-throughput/week-of-jobs.tsx +16 -0
  137. package/registry/examples/latency-chart/by-capability.d.ts +4 -0
  138. package/registry/examples/latency-chart/by-capability.js +26 -0
  139. package/registry/examples/latency-chart/by-capability.tsx +21 -0
  140. package/registry/examples/latency-chart/native/by-capability.d.ts +4 -0
  141. package/registry/examples/latency-chart/native/by-capability.dark.png +0 -0
  142. package/registry/examples/latency-chart/native/by-capability.js +17 -0
  143. package/registry/examples/latency-chart/native/by-capability.light.png +0 -0
  144. package/registry/examples/latency-chart/native/by-capability.tsx +13 -0
  145. package/registry/examples/latency-chart/time-to-result.d.ts +4 -0
  146. package/registry/examples/latency-chart/time-to-result.js +27 -0
  147. package/registry/examples/latency-chart/time-to-result.tsx +22 -0
  148. package/registry/examples/price-ticker/auction-room.d.ts +4 -0
  149. package/registry/examples/price-ticker/auction-room.js +21 -0
  150. package/registry/examples/price-ticker/auction-room.tsx +17 -0
  151. package/registry/examples/price-ticker/native/auction-room.d.ts +4 -0
  152. package/registry/examples/price-ticker/native/auction-room.dark.png +0 -0
  153. package/registry/examples/price-ticker/native/auction-room.js +19 -0
  154. package/registry/examples/price-ticker/native/auction-room.light.png +0 -0
  155. package/registry/examples/price-ticker/native/auction-room.tsx +15 -0
  156. package/registry/examples/price-ticker/no-bid-yet.d.ts +4 -0
  157. package/registry/examples/price-ticker/no-bid-yet.js +11 -0
  158. package/registry/examples/price-ticker/no-bid-yet.tsx +6 -0
  159. package/registry/funnel.json +1 -0
  160. package/registry/gauge.json +1 -0
  161. package/registry/geo-map.json +1 -0
  162. package/registry/globe.json +1 -0
  163. package/registry/goal-progress.json +520 -0
  164. package/registry/heatmap.json +1 -0
  165. package/registry/index.json +163 -1
  166. package/registry/job-throughput.json +654 -0
  167. package/registry/latency-chart.json +671 -0
  168. package/registry/line-chart.json +1 -0
  169. package/registry/pie-chart.json +1 -0
  170. package/registry/price-ticker.json +684 -0
  171. package/registry/radar-chart.json +1 -0
  172. package/registry/sankey.json +1 -0
  173. package/registry/scatter-chart.json +1 -0
  174. package/registry/sparkline.json +1 -0
  175. package/registry/treemap.json +1 -0
  176. package/dist/chunk-DWJPPEMC.js.map +0 -1
  177. /package/dist/{chunk-EK3Z647J.js.map → chunk-4LBXEAGC.js.map} +0 -0
  178. /package/dist/{chunk-AHQXJSAQ.js.map → chunk-AA5EWWYV.js.map} +0 -0
  179. /package/dist/{chunk-VKO2OYYM.js.map → chunk-ARARFMNE.js.map} +0 -0
  180. /package/dist/{chunk-WBH2QU77.js.map → chunk-BV4DBGN7.js.map} +0 -0
  181. /package/dist/{chunk-BZ5CQFPH.js.map → chunk-C4MFZLJM.js.map} +0 -0
  182. /package/dist/{chunk-XAJ3KCC4.js.map → chunk-CSSZLFLO.js.map} +0 -0
  183. /package/dist/{chunk-UNK4MJVG.js.map → chunk-CVWSMUUB.js.map} +0 -0
  184. /package/dist/{chunk-DZB6HEVO.js.map → chunk-EQLC2QVN.js.map} +0 -0
  185. /package/dist/{chunk-PTSB3H5Q.js.map → chunk-I3D7KUGN.js.map} +0 -0
  186. /package/dist/{chunk-XC6BQ3RN.js.map → chunk-MXLITIGU.js.map} +0 -0
  187. /package/dist/{chunk-OER6ETT4.js.map → chunk-NCIQMRV3.js.map} +0 -0
  188. /package/dist/{chunk-WIRCIOLH.js.map → chunk-PBQV3B6O.js.map} +0 -0
  189. /package/dist/{chunk-I5QUZVU2.js.map → chunk-PWMMXRMC.js.map} +0 -0
  190. /package/dist/{chunk-7TIFCK5E.js.map → chunk-VKZZY2QD.js.map} +0 -0
  191. /package/dist/{chunk-VKTZD7UT.js.map → chunk-W5ILLSPK.js.map} +0 -0
  192. /package/dist/{chunk-XR4ZJDOV.js.map → chunk-WVTIKOII.js.map} +0 -0
  193. /package/dist/{chunk-7CSAGFBW.js.map → chunk-XDDALY4C.js.map} +0 -0
package/dist/native.js CHANGED
@@ -66,6 +66,14 @@ function fill(template, values) {
66
66
  return template.replace(/\{(\w+)\}/g, (match, name) => name in values ? String(values[name]) : match);
67
67
  }
68
68
 
69
+ // src/needs/statuses.ts
70
+ var DEFAULT_STATUSES = [
71
+ { key: "completed", label: "Completed", tone: "success", outcome: "succeeded" },
72
+ { key: "failed", label: "Failed", tone: "danger", outcome: "failed" },
73
+ { key: "running", label: "Running", tone: "info" },
74
+ { key: "queued", label: "Queued", tone: "neutral" }
75
+ ];
76
+
69
77
  // src/native/cartesian.tsx
70
78
  import { useMemo as useMemo2, useState as useState2 } from "react";
71
79
  import Svg, { Circle, G, Line, Path, Text as SvgText } from "react-native-svg";
@@ -145,12 +153,12 @@ function summarize(series, categories, writeCategory) {
145
153
  let max = null;
146
154
  let first = null;
147
155
  let last = null;
148
- let total = 0;
156
+ let total2 = 0;
149
157
  let count = 0;
150
158
  series.values.forEach((v, i) => {
151
159
  if (v == null) return;
152
160
  count += 1;
153
- total += v;
161
+ total2 += v;
154
162
  if (first === null) first = v;
155
163
  last = v;
156
164
  if (!min || v < min.value) min = { value: v, category: writeCategory(categories[i]) };
@@ -158,7 +166,7 @@ function summarize(series, categories, writeCategory) {
158
166
  });
159
167
  const change = first !== null && last !== null && first !== 0 && count > 1 ? last / first - 1 : null;
160
168
  const trend = count < 2 || change === null ? count < 2 ? "none" : last > first ? "up" : last < first ? "down" : "flat" : Math.abs(change) < 0.01 ? "flat" : change > 0 ? "up" : "down";
161
- return { label: series.label, count, min, max, first, last, total, change, trend };
169
+ return { label: series.label, count, min, max, first, last, total: total2, change, trend };
162
170
  }
163
171
 
164
172
  // src/core/describe.ts
@@ -183,11 +191,11 @@ function describeSeries(table, { kind, labels, value, category, share, threshold
183
191
  return [intro, ...sentences, ...marks.length ? [`${marks.join(", ")}.`] : []].join(" ");
184
192
  }
185
193
  function describeParts(kind, parts, { labels, value, share }) {
186
- const total = parts.reduce((sum, p) => sum + Math.max(0, p.value), 0);
194
+ const total2 = parts.reduce((sum, p) => sum + Math.max(0, p.value), 0);
187
195
  const intro = fill(labels.summaryIntro, { kind: labels.kinds[kind], count: parts.length });
188
196
  const sorted = [...parts].sort((a, b) => b.value - a.value);
189
- const items = sorted.map((p) => fill(labels.summaryShare, { label: p.label, value: value(p.value), share: share(total ? p.value / total : 0) }));
190
- return `${intro} ${items.join(", ")}. ${capitalize(fill(labels.summaryTotal, { total: value(total) }))}.`;
197
+ const items = sorted.map((p) => fill(labels.summaryShare, { label: p.label, value: value(p.value), share: share(total2 ? p.value / total2 : 0) }));
198
+ return `${intro} ${items.join(", ")}. ${capitalize(fill(labels.summaryTotal, { total: value(total2) }))}.`;
191
199
  }
192
200
 
193
201
  // src/core/format.ts
@@ -458,15 +466,25 @@ var themes = /* @__PURE__ */ Object.freeze({ dark: /* @__PURE__ */ Object.freeze
458
466
  "brandGradientTo": "#0c0c0e",
459
467
  "success": "#10b77f",
460
468
  "successText": "#36d399",
469
+ "successSoft": "rgba(16,183,127,0.14)",
461
470
  "warning": "#f59f0a",
462
471
  "warningText": "#f6a823",
472
+ "warningSoft": "rgba(245,159,10,0.14)",
463
473
  "danger": "#ef4343",
464
474
  "dangerText": "#f87272",
475
+ "dangerSoft": "rgba(239,67,67,0.14)",
465
476
  "info": "#196df5",
466
477
  "infoText": "#629cf8",
467
478
  "scrim": "rgba(0,0,0,0.6)",
468
479
  "scrimStrong": "rgba(0,0,0,0.8)",
469
- "overlay": "rgba(0,0,0,0.7)"
480
+ "overlay": "rgba(0,0,0,0.7)",
481
+ "surfaceSheen": "rgba(255,255,255,0.045)",
482
+ "fillShade": "rgba(0,0,0,0.12)",
483
+ "edgeLight": "rgba(255,255,255,0.07)",
484
+ "edgeOnFill": "rgba(255,255,255,0.22)",
485
+ "edgeWell": "rgba(4,4,7,0.5)",
486
+ "glassBg": "rgba(29,29,32,0.88)",
487
+ "glassBorder": "rgba(255,255,255,0.1)"
470
488
  }), light: /* @__PURE__ */ Object.freeze({
471
489
  "surface0": "#fafafa",
472
490
  "surface1": "#ffffff",
@@ -492,15 +510,25 @@ var themes = /* @__PURE__ */ Object.freeze({ dark: /* @__PURE__ */ Object.freeze
492
510
  "brandGradientTo": "#fafafa",
493
511
  "success": "#10b77f",
494
512
  "successText": "#0a714e",
513
+ "successSoft": "rgba(16,183,127,0.1)",
495
514
  "warning": "#f59f0a",
496
515
  "warningText": "#955104",
516
+ "warningSoft": "rgba(245,159,10,0.12)",
497
517
  "danger": "#ef4343",
498
518
  "dangerText": "#af1d1d",
519
+ "dangerSoft": "rgba(239,67,67,0.1)",
499
520
  "info": "#0a64f5",
500
521
  "infoText": "#0954ce",
501
522
  "scrim": "rgba(0,0,0,0.6)",
502
523
  "scrimStrong": "rgba(0,0,0,0.8)",
503
- "overlay": "rgba(0,0,0,0.7)"
524
+ "overlay": "rgba(0,0,0,0.7)",
525
+ "surfaceSheen": "rgba(255,255,255,0.7)",
526
+ "fillShade": "rgba(0,0,0,0.12)",
527
+ "edgeLight": "rgba(255,255,255,0.9)",
528
+ "edgeOnFill": "rgba(255,255,255,0.22)",
529
+ "edgeWell": "rgba(48,52,80,0.08)",
530
+ "glassBg": "rgba(255,255,255,0.88)",
531
+ "glassBorder": "rgba(0,0,0,0.08)"
504
532
  }) });
505
533
 
506
534
  // src/native/frame.tsx
@@ -727,6 +755,108 @@ function BarChart({ stacked, ...props }) {
727
755
  return /* @__PURE__ */ jsx2(NativeCartesian, { props, mode: { kind: "bar", stacked } });
728
756
  }
729
757
 
758
+ // src/native/needs.tsx
759
+ import { StyleSheet as StyleSheet2, Text as Text2, View as View2 } from "react-native";
760
+ import Svg3, { Path as Path3 } from "react-native-svg";
761
+
762
+ // src/needs/labels.ts
763
+ var EARNINGS_LABELS = {
764
+ total: "earned over {count} periods",
765
+ change: "{change} vs the previous period",
766
+ gross: "Gross",
767
+ net: "Net"
768
+ };
769
+ var THROUGHPUT_LABELS = { total: "jobs over {count} periods", success: "{rate} succeeded" };
770
+ var LATENCY_LABELS = {
771
+ p50: "Median (p50)",
772
+ p95: "p95",
773
+ slowest: "p95 of {name}, the slowest",
774
+ over: "{count} over the objective",
775
+ within: "all within the objective"
776
+ };
777
+ var CREDIT_LABELS = {
778
+ remaining: "left of {limit}",
779
+ used: "{used} used ({percent})",
780
+ runsOut: "At this pace, runs out on {date}",
781
+ steady: "No use lately",
782
+ renews: "Renews on {date}",
783
+ daily: "Use per day"
784
+ };
785
+ var GOAL_LABELS = { raised: "raised of {goal}", reached: "Goal reached", supporters: "{count} supporters", left: "{time} left" };
786
+ var TICKER_LABELS = {
787
+ current: "current bid",
788
+ change: "{change} since the opening \xB7 {count} bids",
789
+ opening: "opening price, no bid yet",
790
+ reserve: "Reserve price",
791
+ price: "Price"
792
+ };
793
+
794
+ // src/needs/model.ts
795
+ import { currencyDigits as currencyDigits2, getNumberFormat as getNumberFormat2 } from "@krizaka/intl";
796
+ function numberOf(row, accessor, index) {
797
+ const value = typeof accessor === "function" ? accessor(row, index) : row[accessor];
798
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
799
+ }
800
+ function total(rows, accessor) {
801
+ return rows.reduce((sum, row, i) => sum + (numberOf(row, accessor, i) ?? 0), 0);
802
+ }
803
+ function lastChange(values) {
804
+ if (values.length < 2) return null;
805
+ const last = values[values.length - 1];
806
+ const previous = values[values.length - 2];
807
+ if (last == null || previous == null || previous === 0) return null;
808
+ return last / previous - 1;
809
+ }
810
+ function direction(change) {
811
+ if (change == null) return null;
812
+ return Math.abs(change) < 5e-3 ? "flat" : change > 0 ? "up" : "down";
813
+ }
814
+ function successRate(succeeded, failed) {
815
+ const finished = succeeded + failed;
816
+ return finished > 0 ? succeeded / finished : null;
817
+ }
818
+ function daysLeft(remaining, daily, days = 7) {
819
+ const recent = daily.slice(-days).filter((v) => v != null && v >= 0);
820
+ if (recent.length === 0) return null;
821
+ const pace = recent.reduce((a, b) => a + b, 0) / recent.length;
822
+ if (pace <= 0) return null;
823
+ return Math.max(0, Math.floor(remaining / pace));
824
+ }
825
+ var addDays = (from, days) => new Date(from.getTime() + days * 864e5);
826
+ function quotaLevel(ratio, warning = 0.8, danger = 0.95) {
827
+ return ratio >= danger ? "danger" : ratio >= warning ? "warning" : "ok";
828
+ }
829
+ function fillIn(template, values) {
830
+ return template.replace(/\{(\w+)\}/g, (match, key) => key in values ? String(values[key]) : match);
831
+ }
832
+ function signedPercent(change, locale) {
833
+ return getNumberFormat2(locale, { style: "percent", signDisplay: "exceptZero", maximumFractionDigits: Math.abs(change) < 0.1 ? 1 : 0 }).format(change);
834
+ }
835
+ function formatDuration(ms, locale) {
836
+ const unit = (value, name, digits) => getNumberFormat2(locale, { style: "unit", unit: name, unitDisplay: "short", maximumFractionDigits: digits }).format(value);
837
+ const abs = Math.abs(ms);
838
+ if (abs < 1e3) return unit(Math.round(ms), "millisecond", 0);
839
+ if (abs < 6e4) return unit(ms / 1e3, "second", abs < 1e4 ? 1 : 0);
840
+ if (abs < 36e5) return unit(ms / 6e4, "minute", 1);
841
+ return unit(ms / 36e5, "hour", 1);
842
+ }
843
+ function roundMoney(currency) {
844
+ const digits = currencyDigits2(currency);
845
+ return (value, locale) => {
846
+ const minor = Math.round(value);
847
+ const whole = minor % 10 ** digits === 0;
848
+ return getNumberFormat2(locale, { style: "currency", currency, minimumFractionDigits: whole ? 0 : digits, maximumFractionDigits: whole ? 0 : digits }).format(minor / 10 ** digits);
849
+ };
850
+ }
851
+
852
+ // src/needs/ticker.ts
853
+ function tickerModel(bids, opening, openedAt) {
854
+ const sorted = [...bids].sort((a, b) => new Date(a.at).getTime() - new Date(b.at).getTime());
855
+ const points = [...openedAt ? [{ at: openedAt, amount: opening }] : [], ...sorted];
856
+ const current = sorted.length > 0 ? sorted[sorted.length - 1].amount : opening;
857
+ return { points, current, change: current - opening, ratio: opening > 0 ? current / opening - 1 : null, count: sorted.length };
858
+ }
859
+
730
860
  // src/native/round.tsx
731
861
  import { useMemo as useMemo3, useState as useState3 } from "react";
732
862
  import Svg2, { Circle as Circle2, Line as Line2, Path as Path2, Text as SvgText2 } from "react-native-svg";
@@ -743,9 +873,9 @@ function PieChart(props) {
743
873
  if (rows.length > maxSlices) out.push({ label: otherLabel, value: rows.slice(maxSlices - 1).reduce((s, r2) => s + r2.value, 0), color: theme.textMuted });
744
874
  return out;
745
875
  }, [data, label, value, maxSlices, otherLabel, color, theme.textMuted]);
746
- const total = slices.reduce((s, x) => s + x.value, 0);
876
+ const total2 = slices.reduce((s, x) => s + x.value, 0);
747
877
  const [active, setActive] = useState3(null);
748
- const isEmpty = total <= 0;
878
+ const isEmpty = total2 <= 0;
749
879
  const summary = isEmpty ? labels.empty : describeParts(donut ? "donut" : "pie", slices, { labels, value: fmt.value, share: fmt.share });
750
880
  return /* @__PURE__ */ jsx3(
751
881
  NativeFrame,
@@ -755,10 +885,10 @@ function PieChart(props) {
755
885
  resolved,
756
886
  summary,
757
887
  isEmpty,
758
- points: slices.map((s) => `${s.label}: ${fmt.value(s.value)} (${fmt.share(total ? s.value / total : 0)})`),
888
+ points: slices.map((s) => `${s.label}: ${fmt.value(s.value)} (${fmt.share(total2 ? s.value / total2 : 0)})`),
759
889
  active,
760
890
  onActive: setActive,
761
- legend: /* @__PURE__ */ jsx3(NativeLegend, { theme, items: slices.map((s) => ({ label: `${s.label} \xB7 ${fmt.share(total ? s.value / total : 0)}`, color: s.color })) }),
891
+ legend: /* @__PURE__ */ jsx3(NativeLegend, { theme, items: slices.map((s) => ({ label: `${s.label} \xB7 ${fmt.share(total2 ? s.value / total2 : 0)}`, color: s.color })) }),
762
892
  children: (width, height) => {
763
893
  const radius = Math.max(10, Math.min(width, height) / 2 - 6);
764
894
  const inner = donut ? radius * 0.64 : 0;
@@ -766,10 +896,10 @@ function PieChart(props) {
766
896
  return /* @__PURE__ */ jsxs3(Svg2, { width, height, children: [
767
897
  slices.map((s, i) => {
768
898
  const start = angle;
769
- angle += total ? s.value / total * Math.PI * 2 : 0;
899
+ angle += total2 ? s.value / total2 * Math.PI * 2 : 0;
770
900
  return /* @__PURE__ */ jsx3(Path2, { d: arcPath(width / 2, height / 2, inner, radius, start, angle), fill: s.color, stroke: theme.surface1, strokeWidth: slices.length > 1 ? 2 : 0, opacity: active !== null && active !== i ? 0.4 : 1 }, s.label);
771
901
  }),
772
- donut && /* @__PURE__ */ jsx3(SvgText2, { x: width / 2, y: height / 2 + (centerLabel ? 0 : 7), fontSize: Math.max(14, Math.min(24, inner / 3)), fontWeight: "600", fill: theme.textPrimary, textAnchor: "middle", children: fmt.value(total) }),
902
+ donut && /* @__PURE__ */ jsx3(SvgText2, { x: width / 2, y: height / 2 + (centerLabel ? 0 : 7), fontSize: Math.max(14, Math.min(24, inner / 3)), fontWeight: "600", fill: theme.textPrimary, textAnchor: "middle", children: fmt.value(total2) }),
773
903
  donut && centerLabel ? /* @__PURE__ */ jsx3(SvgText2, { x: width / 2, y: height / 2 + 18, fontSize: 11, fill: theme.textSecondary, textAnchor: "middle", children: centerLabel }) : null
774
904
  ] });
775
905
  }
@@ -861,15 +991,254 @@ function Sparkline(props) {
861
991
  }
862
992
  );
863
993
  }
994
+
995
+ // src/native/needs.tsx
996
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
997
+ var ARROW = { up: "M7 17 17 7M8 7h9v9", down: "M7 7l10 10M17 8v9H8", flat: "M5 12h14M13 6l6 6-6 6" };
998
+ function toneColor(resolved, tone) {
999
+ return resolved.color(tone, 1);
1000
+ }
1001
+ function Headline({
1002
+ resolved,
1003
+ title,
1004
+ hideTitle,
1005
+ value,
1006
+ label,
1007
+ delta,
1008
+ way,
1009
+ tone = "neutral"
1010
+ }) {
1011
+ const { theme } = resolved;
1012
+ return /* @__PURE__ */ jsxs4(View2, { style: styles2.head, children: [
1013
+ !hideTitle ? /* @__PURE__ */ jsx4(Text2, { role: "heading", style: [styles2.title, { color: theme.textPrimary }], children: title }) : null,
1014
+ /* @__PURE__ */ jsxs4(View2, { style: styles2.kpi, children: [
1015
+ /* @__PURE__ */ jsx4(Text2, { style: [styles2.value, { color: theme.textPrimary }], children: value }),
1016
+ label ? /* @__PURE__ */ jsx4(Text2, { style: [styles2.small, { color: theme.textSecondary }], children: label }) : null
1017
+ ] }),
1018
+ delta ? /* @__PURE__ */ jsxs4(View2, { style: styles2.delta, children: [
1019
+ way ? /* @__PURE__ */ jsx4(Svg3, { width: 12, height: 12, viewBox: "0 0 24 24", "aria-hidden": true, children: /* @__PURE__ */ jsx4(Path3, { d: ARROW[way], fill: "none", stroke: toneColor(resolved, tone), strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round" }) }) : null,
1020
+ /* @__PURE__ */ jsx4(Text2, { style: [styles2.small, styles2.strong, { color: theme.textPrimary }], children: delta })
1021
+ ] }) : null
1022
+ ] });
1023
+ }
1024
+ var good = (way, up) => !way || way === "flat" ? "neutral" : way === "up" === up ? "success" : "danger";
1025
+ function EarningsChart({ x = "month", net, gross, currency, period = "month", payoutThreshold, labels: given, title, hideTitle, data, ...props }) {
1026
+ const words = { ...EARNINGS_LABELS, ...given };
1027
+ const resolved = useNativeSettings(props);
1028
+ const format = { style: "money", currency };
1029
+ const change = lastChange(data.map((row, i) => numberOf(row, net, i)));
1030
+ const way = direction(change);
1031
+ const series = gross ? [{ key: gross, label: words.gross, color: 2 }, { key: net, label: words.net, color: 1 }] : [{ key: net, label: words.net, color: 1 }];
1032
+ return /* @__PURE__ */ jsxs4(View2, { style: styles2.root, children: [
1033
+ /* @__PURE__ */ jsx4(
1034
+ Headline,
1035
+ {
1036
+ resolved,
1037
+ title,
1038
+ hideTitle,
1039
+ value: valueFormatter(format, resolved.locale)(total(data, net)),
1040
+ label: fillIn(words.total, { count: data.length }),
1041
+ delta: change == null ? null : fillIn(words.change, { change: signedPercent(change, resolved.locale) }),
1042
+ way,
1043
+ tone: good(way, true)
1044
+ }
1045
+ ),
1046
+ /* @__PURE__ */ jsx4(BarChart, { ...props, title, hideTitle: true, data, x, series, format, xFormat: period, thresholds: payoutThreshold ? [{ tone: "success", ...payoutThreshold }] : void 0 })
1047
+ ] });
1048
+ }
1049
+ function JobThroughput({ x = "day", period = "day", statuses = DEFAULT_STATUSES, labels: given, title, hideTitle, data, ...props }) {
1050
+ const words = { ...THROUGHPUT_LABELS, ...given };
1051
+ const resolved = useNativeSettings(props);
1052
+ const sum = (outcome) => statuses.filter((s) => outcome === void 0 || s.outcome === outcome).reduce((n, s) => n + total(data, s.key), 0);
1053
+ const rate = successRate(sum("succeeded"), sum("failed"));
1054
+ const series = statuses.map((s) => ({ key: s.key, label: s.label, color: s.tone }));
1055
+ return /* @__PURE__ */ jsxs4(View2, { style: styles2.root, children: [
1056
+ /* @__PURE__ */ jsx4(
1057
+ Headline,
1058
+ {
1059
+ resolved,
1060
+ title,
1061
+ hideTitle,
1062
+ value: valueFormatter("integer", resolved.locale)(sum()),
1063
+ label: fillIn(words.total, { count: data.length }),
1064
+ delta: rate == null ? null : fillIn(words.success, { rate: valueFormatter("percent", resolved.locale)(rate) })
1065
+ }
1066
+ ),
1067
+ /* @__PURE__ */ jsx4(BarChart, { ...props, title, hideTitle: true, data, x, xFormat: period, series, format: "integer", stacked: true })
1068
+ ] });
1069
+ }
1070
+ function LatencyChart({
1071
+ x = "name",
1072
+ p50 = "p50",
1073
+ p95 = "p95",
1074
+ objective,
1075
+ labels: given,
1076
+ title,
1077
+ hideTitle,
1078
+ data,
1079
+ ...props
1080
+ }) {
1081
+ const words = { ...LATENCY_LABELS, ...given };
1082
+ const resolved = useNativeSettings(props);
1083
+ const tail = p95 ?? p50;
1084
+ const measured = data.map((row, i) => ({ row, i, value: numberOf(row, tail, i) ?? 0 }));
1085
+ const slowest = measured.reduce((a, m) => !a || m.value > a.value ? m : a, null);
1086
+ const over = objective ? measured.filter((m) => m.value > objective.value).length : 0;
1087
+ const nameOf = (row, i) => String(typeof x === "function" ? x(row, i) : row[x]);
1088
+ const series = [{ key: p50, label: words.p50, color: "neutral" }, ...p95 ? [{ key: p95, label: words.p95, color: 1 }] : []];
1089
+ return /* @__PURE__ */ jsxs4(View2, { style: styles2.root, children: [
1090
+ /* @__PURE__ */ jsx4(
1091
+ Headline,
1092
+ {
1093
+ resolved,
1094
+ title,
1095
+ hideTitle,
1096
+ value: slowest ? formatDuration(slowest.value, resolved.locale) : "\u2014",
1097
+ label: slowest ? fillIn(words.slowest, { name: nameOf(slowest.row, slowest.i) }) : void 0,
1098
+ delta: objective ? over > 0 ? fillIn(words.over, { count: over }) : words.within : null,
1099
+ way: objective ? over > 0 ? "up" : "flat" : null,
1100
+ tone: over > 0 ? "danger" : "success"
1101
+ }
1102
+ ),
1103
+ /* @__PURE__ */ jsx4(
1104
+ BarChart,
1105
+ {
1106
+ ...props,
1107
+ title,
1108
+ hideTitle: true,
1109
+ data,
1110
+ x,
1111
+ series,
1112
+ format: (value, l) => formatDuration(value, l),
1113
+ thresholds: objective ? [{ ...objective, tone: "danger" }] : void 0
1114
+ }
1115
+ )
1116
+ ] });
1117
+ }
1118
+ function CreditUsage({ title, hideTitle, used, limit, format = "integer", daily, renewsAt, now, levels = [0.8, 0.95], labels: given, style, ...settings }) {
1119
+ const words = { ...CREDIT_LABELS, ...given };
1120
+ const resolved = useNativeSettings(settings);
1121
+ const { theme, locale } = resolved;
1122
+ const write = valueFormatter(format, locale);
1123
+ const date = categoryFormatter("date", locale);
1124
+ const ratio = limit > 0 ? Math.min(1, Math.max(0, used / limit)) : 0;
1125
+ const level = quotaLevel(ratio, levels[0], levels[1]);
1126
+ const remaining = Math.max(0, limit - used);
1127
+ const usedText = fillIn(words.used, { used: write(used), percent: valueFormatter("percent", locale)(ratio) });
1128
+ const left = daily ? daysLeft(remaining, daily) : null;
1129
+ const runOut = left == null ? null : addDays(now ?? /* @__PURE__ */ new Date(), left);
1130
+ const renews = renewsAt ? new Date(renewsAt) : null;
1131
+ const projection = daily ? runOut && (!renews || runOut < renews) ? fillIn(words.runsOut, { date: date(runOut) }) : left == null ? words.steady : null : null;
1132
+ const fill2 = level === "danger" ? theme.danger : level === "warning" ? theme.warning : theme.accent;
1133
+ return /* @__PURE__ */ jsxs4(View2, { style: [styles2.root, style], children: [
1134
+ /* @__PURE__ */ jsx4(Headline, { resolved, title, hideTitle, value: write(remaining), label: fillIn(words.remaining, { limit: write(limit) }) }),
1135
+ /* @__PURE__ */ jsx4(
1136
+ View2,
1137
+ {
1138
+ role: "meter",
1139
+ "aria-label": title,
1140
+ "aria-valuemin": 0,
1141
+ "aria-valuemax": limit,
1142
+ "aria-valuenow": Math.min(limit, Math.max(0, used)),
1143
+ "aria-valuetext": usedText,
1144
+ accessible: true,
1145
+ style: [styles2.meter, { backgroundColor: theme.surface3 }],
1146
+ children: /* @__PURE__ */ jsx4(View2, { style: [styles2.meterFill, { width: `${ratio * 100}%`, backgroundColor: fill2 }] })
1147
+ }
1148
+ ),
1149
+ /* @__PURE__ */ jsxs4(View2, { style: styles2.row, children: [
1150
+ /* @__PURE__ */ jsx4(Text2, { style: [styles2.small, { color: theme.textSecondary }], children: usedText }),
1151
+ renews ? /* @__PURE__ */ jsx4(Text2, { style: [styles2.small, { color: theme.textSecondary }], children: fillIn(words.renews, { date: date(renews) }) }) : null
1152
+ ] }),
1153
+ daily && daily.length > 1 ? /* @__PURE__ */ jsx4(Sparkline, { ...settings, title: words.daily, data: daily, variant: "bar", format, height: 36 }) : null,
1154
+ projection ? /* @__PURE__ */ jsx4(Text2, { style: [styles2.small, styles2.strong, { color: theme.textPrimary }], children: projection }) : null
1155
+ ] });
1156
+ }
1157
+ function GoalProgress({ raised, goal, currency, supporters, timeLeft, labels: given, ...props }) {
1158
+ const words = { ...GOAL_LABELS, ...given };
1159
+ const resolved = useNativeSettings(props);
1160
+ const format = roundMoney(currency);
1161
+ const reached = goal > 0 && raised >= goal;
1162
+ const facts = [
1163
+ supporters != null ? fillIn(words.supporters, { count: valueFormatter("integer", resolved.locale)(supporters) }) : null,
1164
+ reached ? words.reached : null,
1165
+ timeLeft ? fillIn(words.left, { time: timeLeft }) : null
1166
+ ].filter(Boolean);
1167
+ return /* @__PURE__ */ jsxs4(View2, { style: styles2.root, children: [
1168
+ /* @__PURE__ */ jsx4(Gauge, { ...props, value: raised, max: goal, format, caption: fillIn(words.raised, { goal: valueFormatter(format, resolved.locale)(goal) }), tone: reached ? "success" : "accent" }),
1169
+ facts.length > 0 ? /* @__PURE__ */ jsx4(Text2, { style: [styles2.small, { color: resolved.theme.textSecondary, textAlign: "center" }], children: facts.join(" \xB7 ") }) : null
1170
+ ] });
1171
+ }
1172
+ function PriceTicker({ bids, opening, openedAt, currency, reserve, timeFormat = "time", labels: given, title, hideTitle, ...props }) {
1173
+ const words = { ...TICKER_LABELS, ...given };
1174
+ const resolved = useNativeSettings(props);
1175
+ const format = { style: "money", currency };
1176
+ const write = valueFormatter(format, resolved.locale);
1177
+ const model = tickerModel(bids, opening, openedAt);
1178
+ const way = model.count > 0 ? direction(model.ratio) : null;
1179
+ const signed = `${model.change > 0 ? "+" : ""}${write(model.change)}`;
1180
+ const change = model.ratio == null ? signed : `${signed} (${signedPercent(model.ratio, resolved.locale)})`;
1181
+ return /* @__PURE__ */ jsxs4(View2, { style: styles2.root, children: [
1182
+ /* @__PURE__ */ jsx4(
1183
+ Headline,
1184
+ {
1185
+ resolved,
1186
+ title,
1187
+ hideTitle,
1188
+ value: write(model.current),
1189
+ label: model.count > 0 ? words.current : words.opening,
1190
+ delta: model.count > 0 ? fillIn(words.change, { change, count: model.count }) : null,
1191
+ way,
1192
+ tone: good(way, true)
1193
+ }
1194
+ ),
1195
+ /* @__PURE__ */ jsx4(
1196
+ LineChart,
1197
+ {
1198
+ ...props,
1199
+ title,
1200
+ hideTitle: true,
1201
+ data: model.points,
1202
+ x: "at",
1203
+ y: "amount",
1204
+ yLabel: words.price,
1205
+ xFormat: timeFormat,
1206
+ format,
1207
+ curve: "step",
1208
+ thresholds: reserve != null && model.current < reserve ? [{ value: reserve, label: words.reserve, tone: "warning" }] : void 0
1209
+ }
1210
+ )
1211
+ ] });
1212
+ }
1213
+ var styles2 = StyleSheet2.create({
1214
+ root: { gap: 8 },
1215
+ head: { gap: 2 },
1216
+ title: { fontSize: 14, fontWeight: "600", lineHeight: 20 },
1217
+ kpi: { flexDirection: "row", flexWrap: "wrap", alignItems: "baseline", columnGap: 8 },
1218
+ value: { fontSize: 24, lineHeight: 30, fontWeight: "800", fontVariant: ["tabular-nums"] },
1219
+ delta: { flexDirection: "row", alignItems: "center", gap: 4 },
1220
+ small: { fontSize: 12, lineHeight: 16, fontVariant: ["tabular-nums"] },
1221
+ strong: { fontWeight: "600" },
1222
+ meter: { height: 10, borderRadius: 999, overflow: "hidden" },
1223
+ meterFill: { height: "100%", borderRadius: 999 },
1224
+ row: { flexDirection: "row", flexWrap: "wrap", justifyContent: "space-between", columnGap: 12 }
1225
+ });
864
1226
  export {
865
1227
  AreaChart,
866
1228
  BarChart,
867
1229
  ChartsProvider,
1230
+ CreditUsage,
868
1231
  DEFAULT_LABELS,
1232
+ DEFAULT_STATUSES,
869
1233
  DonutChart,
1234
+ EarningsChart,
870
1235
  Gauge,
1236
+ GoalProgress,
1237
+ JobThroughput,
1238
+ LatencyChart,
871
1239
  LineChart,
872
1240
  PieChart,
1241
+ PriceTicker,
873
1242
  Sparkline
874
1243
  };
875
1244
  //# sourceMappingURL=native.js.map