iryx-ui 0.8.0 → 0.10.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 (164) hide show
  1. package/README.md +279 -7
  2. package/dist/component-names.d.ts +1 -1
  3. package/dist/component-names.js +4 -0
  4. package/dist/{packages/iryx-ui/src/components → components}/Alert.vue_vue_type_script_setup_true_lang.js +1 -1
  5. package/dist/{packages/iryx-ui/src/components → components}/Banner.vue_vue_type_script_setup_true_lang.js +1 -1
  6. package/dist/components/BarChart.js +5 -0
  7. package/dist/components/BarChart.vue.d.ts +95 -0
  8. package/dist/components/BarChart.vue_vue_type_script_setup_true_lang.js +258 -0
  9. package/dist/{packages/iryx-ui/src/components → components}/Breadcrumb.vue_vue_type_script_setup_true_lang.js +1 -1
  10. package/dist/{packages/iryx-ui/src/components → components}/Button.vue_vue_type_script_setup_true_lang.js +1 -1
  11. package/dist/components/ChartLegend.js +5 -0
  12. package/dist/components/ChartLegend.vue.d.ts +12 -0
  13. package/dist/components/ChartLegend.vue_vue_type_script_setup_true_lang.js +31 -0
  14. package/dist/{packages/iryx-ui/src/components → components}/Checkbox.vue_vue_type_script_setup_true_lang.js +1 -1
  15. package/dist/{packages/iryx-ui/src/components → components}/Combobox.vue_vue_type_script_setup_true_lang.js +1 -1
  16. package/dist/{packages/iryx-ui/src/components → components}/DatePicker.vue_vue_type_script_setup_true_lang.js +1 -1
  17. package/dist/{packages/iryx-ui/src/components → components}/DateRangePicker.vue_vue_type_script_setup_true_lang.js +1 -1
  18. package/dist/components/Dialog.vue_vue_type_script_setup_true_lang.js +102 -0
  19. package/dist/{packages/iryx-ui/src/components → components}/DropdownMenuItems.vue_vue_type_script_setup_true_lang.js +1 -1
  20. package/dist/{packages/iryx-ui/src/components → components}/FileUpload.vue_vue_type_script_setup_true_lang.js +1 -1
  21. package/dist/{packages/iryx-ui/src/components → components}/Icon.vue_vue_type_script_setup_true_lang.js +1 -1
  22. package/dist/{packages/iryx-ui/src/components → components}/Input.vue_vue_type_script_setup_true_lang.js +1 -1
  23. package/dist/components/LineChart.js +5 -0
  24. package/dist/components/LineChart.vue.d.ts +100 -0
  25. package/dist/components/LineChart.vue_vue_type_script_setup_true_lang.js +265 -0
  26. package/dist/{packages/iryx-ui/src/components → components}/NumberInput.vue_vue_type_script_setup_true_lang.js +1 -1
  27. package/dist/{packages/iryx-ui/src/components → components}/Pagination.vue_vue_type_script_setup_true_lang.js +1 -1
  28. package/dist/{packages/iryx-ui/src/components → components}/PasswordInput.vue_vue_type_script_setup_true_lang.js +1 -1
  29. package/dist/{packages/iryx-ui/src/components → components}/Select.vue_vue_type_script_setup_true_lang.js +1 -1
  30. package/dist/components/Sparkline.js +5 -0
  31. package/dist/components/Sparkline.vue.d.ts +38 -0
  32. package/dist/components/Sparkline.vue_vue_type_script_setup_true_lang.js +110 -0
  33. package/dist/{packages/iryx-ui/src/components → components}/Stat.vue_vue_type_script_setup_true_lang.js +1 -1
  34. package/dist/{packages/iryx-ui/src/components → components}/Stepper.vue_vue_type_script_setup_true_lang.js +1 -1
  35. package/dist/{packages/iryx-ui/src/components → components}/Table.vue_vue_type_script_setup_true_lang.js +1 -1
  36. package/dist/{packages/iryx-ui/src/components → components}/Toaster.vue_vue_type_script_setup_true_lang.js +1 -1
  37. package/dist/components/index.d.ts +4 -0
  38. package/dist/components/index.js +88 -0
  39. package/dist/composables/cartesian.d.ts +105 -0
  40. package/dist/composables/cartesian.js +43 -0
  41. package/dist/{packages/iryx-ui/src/composables → composables}/date.js +4 -4
  42. package/dist/composables/element-size.d.ts +15 -0
  43. package/dist/composables/element-size.js +22 -0
  44. package/dist/composables/scale.d.ts +36 -0
  45. package/dist/composables/scale.js +43 -0
  46. package/dist/index.d.ts +7 -0
  47. package/dist/index.js +94 -83
  48. package/dist/nuxt.js +1 -1
  49. package/dist/theme/bar-chart.d.ts +132 -0
  50. package/dist/theme/bar-chart.js +19 -0
  51. package/dist/theme/breadcrumb.d.ts +3 -3
  52. package/dist/theme/chart-legend.d.ts +55 -0
  53. package/dist/theme/chart-legend.js +10 -0
  54. package/dist/theme/index.d.ts +4 -0
  55. package/dist/theme/line-chart.d.ts +143 -0
  56. package/dist/theme/line-chart.js +22 -0
  57. package/dist/theme/sparkline.d.ts +58 -0
  58. package/dist/theme/sparkline.js +15 -0
  59. package/package.json +8 -8
  60. package/theme.css +42 -0
  61. package/dist/packages/iryx-ui/src/component-names.js +0 -4
  62. package/dist/packages/iryx-ui/src/components/Dialog.vue_vue_type_script_setup_true_lang.js +0 -99
  63. package/dist/packages/iryx-ui/src/components/index.js +0 -80
  64. /package/dist/{packages/iryx-ui/src/components → components}/Alert.js +0 -0
  65. /package/dist/{packages/iryx-ui/src/components → components}/App.js +0 -0
  66. /package/dist/{packages/iryx-ui/src/components → components}/App.vue_vue_type_script_setup_true_lang.js +0 -0
  67. /package/dist/{packages/iryx-ui/src/components → components}/Badge.js +0 -0
  68. /package/dist/{packages/iryx-ui/src/components → components}/Badge.vue_vue_type_script_setup_true_lang.js +0 -0
  69. /package/dist/{packages/iryx-ui/src/components → components}/Banner.js +0 -0
  70. /package/dist/{packages/iryx-ui/src/components → components}/Breadcrumb.js +0 -0
  71. /package/dist/{packages/iryx-ui/src/components → components}/Button.js +0 -0
  72. /package/dist/{packages/iryx-ui/src/components → components}/ButtonGroup.js +0 -0
  73. /package/dist/{packages/iryx-ui/src/components → components}/ButtonGroup.vue_vue_type_script_setup_true_lang.js +0 -0
  74. /package/dist/{packages/iryx-ui/src/components → components}/Card.js +0 -0
  75. /package/dist/{packages/iryx-ui/src/components → components}/Card.vue_vue_type_script_setup_true_lang.js +0 -0
  76. /package/dist/{packages/iryx-ui/src/components → components}/Checkbox.js +0 -0
  77. /package/dist/{packages/iryx-ui/src/components → components}/Combobox.js +0 -0
  78. /package/dist/{packages/iryx-ui/src/components → components}/ConfirmDialog.js +0 -0
  79. /package/dist/{packages/iryx-ui/src/components → components}/ConfirmDialog.vue_vue_type_script_setup_true_lang.js +0 -0
  80. /package/dist/{packages/iryx-ui/src/components → components}/DatePicker.js +0 -0
  81. /package/dist/{packages/iryx-ui/src/components → components}/DateRangePicker.js +0 -0
  82. /package/dist/{packages/iryx-ui/src/components → components}/Dialog.js +0 -0
  83. /package/dist/{packages/iryx-ui/src/components → components}/DropdownMenu.js +0 -0
  84. /package/dist/{packages/iryx-ui/src/components → components}/DropdownMenu.vue_vue_type_script_setup_true_lang.js +0 -0
  85. /package/dist/{packages/iryx-ui/src/components → components}/DropdownMenuItems.js +0 -0
  86. /package/dist/{packages/iryx-ui/src/components → components}/EmptyState.js +0 -0
  87. /package/dist/{packages/iryx-ui/src/components → components}/EmptyState.vue_vue_type_script_setup_true_lang.js +0 -0
  88. /package/dist/{packages/iryx-ui/src/components → components}/FileUpload.js +0 -0
  89. /package/dist/{packages/iryx-ui/src/components → components}/Form.js +0 -0
  90. /package/dist/{packages/iryx-ui/src/components → components}/Form.vue_vue_type_script_setup_true_lang.js +0 -0
  91. /package/dist/{packages/iryx-ui/src/components → components}/FormField.js +0 -0
  92. /package/dist/{packages/iryx-ui/src/components → components}/FormField.vue_vue_type_script_setup_true_lang.js +0 -0
  93. /package/dist/{packages/iryx-ui/src/components → components}/Icon.js +0 -0
  94. /package/dist/{packages/iryx-ui/src/components → components}/Input.js +0 -0
  95. /package/dist/{packages/iryx-ui/src/components → components}/Label.js +0 -0
  96. /package/dist/{packages/iryx-ui/src/components → components}/Label.vue_vue_type_script_setup_true_lang.js +0 -0
  97. /package/dist/{packages/iryx-ui/src/components → components}/NumberInput.js +0 -0
  98. /package/dist/{packages/iryx-ui/src/components → components}/Pagination.js +0 -0
  99. /package/dist/{packages/iryx-ui/src/components → components}/PasswordInput.js +0 -0
  100. /package/dist/{packages/iryx-ui/src/components → components}/Progress.js +0 -0
  101. /package/dist/{packages/iryx-ui/src/components → components}/Progress.vue_vue_type_script_setup_true_lang.js +0 -0
  102. /package/dist/{packages/iryx-ui/src/components → components}/RadioGroup.js +0 -0
  103. /package/dist/{packages/iryx-ui/src/components → components}/RadioGroup.vue_vue_type_script_setup_true_lang.js +0 -0
  104. /package/dist/{packages/iryx-ui/src/components → components}/Select.js +0 -0
  105. /package/dist/{packages/iryx-ui/src/components → components}/Separator.js +0 -0
  106. /package/dist/{packages/iryx-ui/src/components → components}/Separator.vue_vue_type_script_setup_true_lang.js +0 -0
  107. /package/dist/{packages/iryx-ui/src/components → components}/Skeleton.js +0 -0
  108. /package/dist/{packages/iryx-ui/src/components → components}/Skeleton.vue_vue_type_script_setup_true_lang.js +0 -0
  109. /package/dist/{packages/iryx-ui/src/components → components}/Stat.js +0 -0
  110. /package/dist/{packages/iryx-ui/src/components → components}/Stepper.js +0 -0
  111. /package/dist/{packages/iryx-ui/src/components → components}/Switch.js +0 -0
  112. /package/dist/{packages/iryx-ui/src/components → components}/Switch.vue_vue_type_script_setup_true_lang.js +0 -0
  113. /package/dist/{packages/iryx-ui/src/components → components}/Table.js +0 -0
  114. /package/dist/{packages/iryx-ui/src/components → components}/Tabs.js +0 -0
  115. /package/dist/{packages/iryx-ui/src/components → components}/Tabs.vue_vue_type_script_setup_true_lang.js +0 -0
  116. /package/dist/{packages/iryx-ui/src/components → components}/Textarea.js +0 -0
  117. /package/dist/{packages/iryx-ui/src/components → components}/Textarea.vue_vue_type_script_setup_true_lang.js +0 -0
  118. /package/dist/{packages/iryx-ui/src/components → components}/Toaster.js +0 -0
  119. /package/dist/{packages/iryx-ui/src/components → components}/Tooltip.js +0 -0
  120. /package/dist/{packages/iryx-ui/src/components → components}/Tooltip.vue_vue_type_script_setup_true_lang.js +0 -0
  121. /package/dist/{packages/iryx-ui/src/composables → composables}/appearance.js +0 -0
  122. /package/dist/{packages/iryx-ui/src/composables → composables}/button-group.js +0 -0
  123. /package/dist/{packages/iryx-ui/src/composables → composables}/confirm.js +0 -0
  124. /package/dist/{packages/iryx-ui/src/composables → composables}/data-table.js +0 -0
  125. /package/dist/{packages/iryx-ui/src/composables → composables}/decimal.js +0 -0
  126. /package/dist/{packages/iryx-ui/src/composables → composables}/dropdown-menu.js +0 -0
  127. /package/dist/{packages/iryx-ui/src/composables → composables}/form.js +0 -0
  128. /package/dist/{packages/iryx-ui/src/composables → composables}/icon.js +0 -0
  129. /package/dist/{packages/iryx-ui/src/composables → composables}/toast.js +0 -0
  130. /package/dist/{packages/iryx-ui/src/config.js → config.js} +0 -0
  131. /package/dist/{packages/iryx-ui/src/plugin.js → plugin.js} +0 -0
  132. /package/dist/{packages/iryx-ui/src/theme → theme}/alert.js +0 -0
  133. /package/dist/{packages/iryx-ui/src/theme → theme}/badge.js +0 -0
  134. /package/dist/{packages/iryx-ui/src/theme → theme}/banner.js +0 -0
  135. /package/dist/{packages/iryx-ui/src/theme → theme}/breadcrumb.js +0 -0
  136. /package/dist/{packages/iryx-ui/src/theme → theme}/button-group.js +0 -0
  137. /package/dist/{packages/iryx-ui/src/theme → theme}/button.js +0 -0
  138. /package/dist/{packages/iryx-ui/src/theme → theme}/card.js +0 -0
  139. /package/dist/{packages/iryx-ui/src/theme → theme}/checkbox.js +0 -0
  140. /package/dist/{packages/iryx-ui/src/theme → theme}/combobox.js +0 -0
  141. /package/dist/{packages/iryx-ui/src/theme → theme}/date-picker.js +0 -0
  142. /package/dist/{packages/iryx-ui/src/theme → theme}/dialog.js +0 -0
  143. /package/dist/{packages/iryx-ui/src/theme → theme}/dropdown-menu.js +0 -0
  144. /package/dist/{packages/iryx-ui/src/theme → theme}/empty-state.js +0 -0
  145. /package/dist/{packages/iryx-ui/src/theme → theme}/file-upload.js +0 -0
  146. /package/dist/{packages/iryx-ui/src/theme → theme}/form.js +0 -0
  147. /package/dist/{packages/iryx-ui/src/theme → theme}/input.js +0 -0
  148. /package/dist/{packages/iryx-ui/src/theme → theme}/label.js +0 -0
  149. /package/dist/{packages/iryx-ui/src/theme → theme}/number-input.js +0 -0
  150. /package/dist/{packages/iryx-ui/src/theme → theme}/pagination.js +0 -0
  151. /package/dist/{packages/iryx-ui/src/theme → theme}/password-input.js +0 -0
  152. /package/dist/{packages/iryx-ui/src/theme → theme}/presets.js +0 -0
  153. /package/dist/{packages/iryx-ui/src/theme → theme}/progress.js +0 -0
  154. /package/dist/{packages/iryx-ui/src/theme → theme}/radio-group.js +0 -0
  155. /package/dist/{packages/iryx-ui/src/theme → theme}/select.js +0 -0
  156. /package/dist/{packages/iryx-ui/src/theme → theme}/separator.js +0 -0
  157. /package/dist/{packages/iryx-ui/src/theme → theme}/skeleton.js +0 -0
  158. /package/dist/{packages/iryx-ui/src/theme → theme}/stat.js +0 -0
  159. /package/dist/{packages/iryx-ui/src/theme → theme}/stepper.js +0 -0
  160. /package/dist/{packages/iryx-ui/src/theme → theme}/switch.js +0 -0
  161. /package/dist/{packages/iryx-ui/src/theme → theme}/table.js +0 -0
  162. /package/dist/{packages/iryx-ui/src/theme → theme}/tabs.js +0 -0
  163. /package/dist/{packages/iryx-ui/src/theme → theme}/toast.js +0 -0
  164. /package/dist/{packages/iryx-ui/src/theme → theme}/tooltip.js +0 -0
package/README.md CHANGED
@@ -199,21 +199,20 @@ For a static re-brand, plain CSS works too — tokens are just variables:
199
199
 
200
200
  ### Typeface
201
201
 
202
- The library ships **no webfont** — that would put font files, a licence and a
203
- network request into every app whether it wanted them or not. It reads one
204
- variable, defaulting to the system stack. Point it at your own family and
205
- everything follows, including Tailwind's `font-sans`:
202
+ Set `--iryx-font-sans` and everything follows, including Tailwind's
203
+ `font-sans`. Load the family however you like a package, a `<link>`, or
204
+ self-hosted:
206
205
 
207
206
  ```css
208
- @import "@fontsource-variable/instrument-sans"; /* or a <link>, or self-hosted */
207
+ @import "@fontsource-variable/instrument-sans";
209
208
 
210
209
  :root {
211
210
  --iryx-font-sans: "Instrument Sans", ui-sans-serif, system-ui, sans-serif;
212
211
  }
213
212
  ```
214
213
 
215
- Unlike the colour tokens, this one is not mode-specific — there is no `.dark`
216
- counterpart to keep in sync.
214
+ Leave it unset to use the system stack. There is no `.dark` counterpart for
215
+ this one.
217
216
 
218
217
  Available tokens, each usable as a Tailwind color (`bg-primary`,
219
218
  `text-muted-foreground`, …):
@@ -290,6 +289,9 @@ app.use(createIryxUi({ unstyled: true }))
290
289
  | `IFormField` | Label, description, hint, help and error text around a control |
291
290
  | `IInput` | Text field with `sm`/`md`/`lg` sizes, `invalid` state, `v-model`, `leading`/`trailing` slots, `clearable`, `loading`, `debounce` |
292
291
  | `INumberInput` | Decimal-safe numeric field — the model is a **string**, with `min`/`max`/`step`, `precision` and locale-aware display |
292
+ | `ISparkline` | Tiny inline trend chart — pure SVG, no charting dependency |
293
+ | `IBarChart` | Categorical bar chart with a round-number axis, hover tooltip and a table view |
294
+ | `ILineChart` | Line or area chart with a crosshair, hover marker and a table view |
293
295
  | `IFileUpload` | Drag-and-drop file field with `accept` / `maxSize` / `maxFiles`, thumbnails and a remove action |
294
296
  | `IDatePicker` | Calendar in a popover; the model is an ISO `YYYY-MM-DD` **string** |
295
297
  | `IDateRangePicker` | Two-month range calendar; the model is `{ start, end }` ISO strings |
@@ -481,6 +483,276 @@ chrome; use `ui` to reach the parts (`root`, `input`, `leading`, `trailing`,
481
483
  forwarded to the `<input>` itself. `ref` exposes the element as `.input` for
482
484
  focus management.
483
485
 
486
+ #### Multiple series
487
+
488
+ Both charts take plain rows plus a `series` descriptor — the same shape
489
+ `ITable` uses. Omit `series` for the single-measure case.
490
+
491
+ ```vue
492
+ <IBarChart
493
+ :data="[
494
+ { label: 'Jan', revenue: 4200, expenses: 3100 },
495
+ { label: 'Feb', revenue: 5600, expenses: 3400 },
496
+ ]"
497
+ :series="[
498
+ { key: 'revenue', name: 'Revenue', slot: 0 },
499
+ { key: 'expenses', name: 'Expenses', slot: 1 },
500
+ ]"
501
+ label="Cashflow by month"
502
+ />
503
+ ```
504
+
505
+ Bars group inside their category; lines draw one path each. One hover reports
506
+ **every** series for that category in a single tooltip, so the reader compares
507
+ in one place instead of chasing marks.
508
+
509
+ **`slot` pins a series to a palette colour.** Without it, colour follows array
510
+ position — so filtering a series out repaints the survivors and the reader has
511
+ to relearn the chart. Pin the slots whenever series can be toggled.
512
+
513
+ **The legend is mandatory from two series up.** `legend: false` only silences
514
+ the single-series case, where the title already names what is plotted. Colour
515
+ alone is never a dependable identity channel, so this is not configurable.
516
+
517
+ Past eight series the colours stop identifying anything; the chart warns in
518
+ development and you should fold the tail into "Other" or switch to small
519
+ multiples.
520
+
521
+ `variant="area"` is ignored for multiple series — overlapping washes muddy into
522
+ a colour that belongs to neither.
523
+
524
+ #### Annotations, and why there is no plugin API
525
+
526
+ Chart.js has plugins because canvas is opaque — once painted you cannot select
527
+ or style anything, so the only way in is an imperative draw hook. SVG has no
528
+ such problem, so these charts hand you the layout and let you write ordinary
529
+ markup into it:
530
+
531
+ ```vue
532
+ <ILineChart :data="revenue" label="Revenue against target">
533
+ <template #overlay="{ plot, value }">
534
+ <line
535
+ :x1="plot.left" :y1="value(7000)"
536
+ :x2="plot.left + plot.width" :y2="value(7000)"
537
+ stroke="var(--iryx-warning)" stroke-width="2" stroke-dasharray="4 4"
538
+ />
539
+ </template>
540
+ </ILineChart>
541
+ ```
542
+
543
+ `#underlay` renders behind the marks — target bands, shaded regions. `#overlay`
544
+ renders in front — reference lines, callouts. Both sit below the hit targets,
545
+ so hovering keeps working through whatever you draw.
546
+
547
+ Both receive the `CartesianLayout`:
548
+
549
+ | Prop | What it gives you |
550
+ | --- | --- |
551
+ | `plot` | `{ left, top, width, height }` of the plot rectangle, in px |
552
+ | `value(n)` | A data value to its pixel on the value axis |
553
+ | `bandCentre(i)` | The centre of category `i`, in px |
554
+ | `bandWidth` | Size of one category slot |
555
+ | `ticks` | The axis values actually drawn |
556
+ | `orientation` | `'vertical'` or `'horizontal'` |
557
+
558
+ That's strictly more capable than a draw hook: it's declarative, reactive, and
559
+ type-checked, with no lifecycle or registration order to learn.
560
+
561
+ For a chart type that doesn't exist here, the same primitives are exported —
562
+ `cartesianLayout`, `linearScale`, `niceTicks`, `seriesColor` — so you can build
563
+ one on the same spine rather than starting over.
564
+
565
+ #### Chart colours
566
+
567
+ Eight categorical slots, `--iryx-chart-1` … `--iryx-chart-8`, usable as Tailwind
568
+ colours (`text-chart-3`, `fill-chart-5`). They encode **identity** — which
569
+ series a mark belongs to — never magnitude.
570
+
571
+ ```vue
572
+ <!-- One series per slot, assigned in order. -->
573
+ <ISparkline :data="revenue" class="text-chart-1" />
574
+
575
+ <ISparkline :data="expenses" class="text-chart-2" />
576
+ ```
577
+
578
+ Three rules, and they are not stylistic:
579
+
580
+ - **Assign in order, never cycle.** A ninth series is not a generated ninth
581
+ hue — fold it into "Other", or switch to small multiples. A generated colour
582
+ hasn't been checked for separation against its neighbours.
583
+ - **Status colours are never series colours.** A series that happens to land in
584
+ slot 4 must not read as a warning. `success`/`warning`/`danger`/`info` stay
585
+ reserved.
586
+ - **Colour follows the entity, not its rank.** If a filter removes a series,
587
+ the survivors keep their slots rather than shifting up.
588
+
589
+ Tailwind scans source text, so a class name assembled at runtime is never
590
+ generated — write the slots out, or reach for the variable:
591
+
592
+ ```vue
593
+ <!-- Silently unstyled: Tailwind never sees this string -->
594
+ <ISparkline :class="`text-chart-${index + 1}`" />
595
+
596
+ <!-- Either of these works -->
597
+ <ISparkline :class="['text-chart-1', 'text-chart-2'][index]" />
598
+
599
+ <ISparkline :style="{ color: `var(--iryx-chart-${index + 1})` }" />
600
+ ```
601
+
602
+ The steps are not eyeballed. Each clears a lightness band, a chroma floor, and
603
+ protanopia/deuteranopia separation against its own surface, checked with a
604
+ validator rather than by eye. **Dark has its own steps**, validated against the
605
+ dark background — not an automatic flip of the light ones.
606
+
607
+ Two caps worth knowing before you design around them:
608
+
609
+ | Chart form | Max series |
610
+ | --- | --- |
611
+ | Bars, lines, stacks — only neighbours touch | **8** |
612
+ | Scatter, bubble, small multiples — any two marks can sit side by side | **3** |
613
+
614
+ Past those, the answer is fewer series or facets, not more colours. If you
615
+ re-step any slot, re-run the validator for **both** modes.
616
+
617
+ #### Line charts
618
+
619
+ ```vue
620
+ <ILineChart
621
+ :data="[
622
+ { label: 'Jan', value: 4200 },
623
+ { label: 'Feb', value: null },
624
+ { label: 'Mar', value: 5600 },
625
+ ]"
626
+ variant="area"
627
+ label="Revenue by month"
628
+ />
629
+ ```
630
+
631
+ Same `data`, `height`, `ticks`, `axis`, `locale`, `format` and `label` props as
632
+ `IBarChart`, plus:
633
+
634
+ | Prop | Effect |
635
+ | --- | --- |
636
+ | `variant` | `line` (default) or `area`, which adds a wash beneath the line |
637
+ | `zero` | Force zero onto the axis. **Off by default** |
638
+
639
+ **`zero` is off here and always on for bars, deliberately.** A bar is read by
640
+ length, so a truncated baseline lies about the comparison. A line is read by
641
+ its *shape*, and a series hovering around 8,000 flattens into a straight edge
642
+ once the axis starts at nothing. Turn it on when the distance from zero is the
643
+ point.
644
+
645
+ `null` breaks the line rather than bridging it, so a missing reading never
646
+ draws a slope that didn't happen.
647
+
648
+ Hovering shows a crosshair and a single ringed marker on the reading under the
649
+ cursor — not a dot on every point, which is noise the axis and tooltip already
650
+ cover.
651
+
652
+ #### Bar charts
653
+
654
+ ```vue
655
+ <IBarChart
656
+ :data="[
657
+ { label: 'Jan', value: 4200 },
658
+ { label: 'Feb', value: 5600 },
659
+ { label: 'Mar', value: null },
660
+ ]"
661
+ label="Revenue by month"
662
+ locale="de-DE"
663
+ :format="{ style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }"
664
+ />
665
+ ```
666
+
667
+ | Prop | Effect |
668
+ | --- | --- |
669
+ | `data` | `{ label, value }[]`. `value: null` is a **missing reading** — no bar, which is not a zero |
670
+ | `height` | Rendered height in px (default 240). Width fills the container |
671
+ | `ticks` | Target tick count. A hint — the axis lands on round numbers first |
672
+ | `axis` | Set `false` to drop the value axis and gridlines |
673
+ | `locale` / `format` | `Intl.NumberFormat` settings, applied to ticks and tooltip alike |
674
+ | `label` | Accessible name for the figure |
675
+
676
+ **The axis picks the domain, not the data.** Values are snapped outwards to a
677
+ 1/2/5 step, so an axis reads `0 / 2,000 / 4,000` rather than `0 / 1,726.8`.
678
+ Zero is always included, because bars are compared by length and a truncated
679
+ baseline makes that comparison a lie.
680
+
681
+ Bars are capped at 24px and never fill their slot — the gap between them is
682
+ what separates them. They're rounded at the data end and square at the
683
+ baseline, so the rounding reads as the tip of the value.
684
+
685
+ Hovering a bar dims the rest and shows a tooltip; hit targets span the full
686
+ band and plot height, so a short bar is no harder to hit than a tall one.
687
+
688
+ **Accessibility:** the SVG is `aria-hidden` and the data is exposed as a
689
+ visually-hidden table instead, so a screen reader gets the actual numbers
690
+ rather than a blank graphic. That table renders even before the container has
691
+ been measured — the data is never gated behind layout.
692
+
693
+ **`orientation="horizontal"`** runs the categories down the side:
694
+
695
+ ```vue
696
+ <IBarChart :data="spend" orientation="horizontal" label="Spend by category" />
697
+ ```
698
+
699
+ Vertical charts thin colliding labels to every *n*th, which is fine for `Jan`
700
+ / `Feb` and lossy for `Travel and accommodation`. Turn the chart and the names
701
+ get real width, so nothing is dropped — that's the case horizontal is for.
702
+ Everything else behaves the same: grouped series, the tooltip, the round-number
703
+ axis anchored at zero.
704
+
705
+ #### Sparklines
706
+
707
+ A trend at a glance, for a stat tile or a table cell. Plain SVG — no charting
708
+ library, no canvas, nothing to install.
709
+
710
+ ```vue
711
+ <ISparkline
712
+ :data="[4200, 4600, 4100, 5200, 5800, 6300]"
713
+ variant="area"
714
+ end-dot
715
+ label="Revenue over six months, trending up"
716
+ />
717
+ ```
718
+
719
+ Because it is SVG, colour comes from `currentColor`: recolour it with a text
720
+ utility, and it follows your theme preset and light/dark automatically with no
721
+ JavaScript. A canvas chart cannot read CSS variables, so it would need a
722
+ re-render on every theme change.
723
+
724
+ | Prop | Effect |
725
+ | --- | --- |
726
+ | `data` | Values, oldest first. `null` is a **gap**, not a zero — the line breaks |
727
+ | `variant` | `line` (default) or `area`, which adds a wash beneath the line |
728
+ | `endDot` | Marks the most recent point |
729
+ | `baseline` | Lower edge of the `area` wash: `min` (default) or `zero` |
730
+ | `min` / `max` | Pin the domain — set both to put several sparklines on one scale |
731
+ | `muted` | Draw in muted ink, for a de-emphasised trend |
732
+ | `height` | Rendered height in px (default 32). Width always fills the container |
733
+
734
+ Width is fluid and the stroke never distorts: the drawing stretches via
735
+ `preserveAspectRatio="none"`, while every stroke carries
736
+ `vector-effect="non-scaling-stroke"`, so a 2px line stays 2px and the end dot
737
+ stays circular at any aspect ratio.
738
+
739
+ `label` sets an accessible description. **Without one the sparkline is hidden
740
+ from assistive tech as decorative** — which is correct when it sits beside a
741
+ value that already states the number, and wrong if it is the only thing
742
+ carrying the information.
743
+
744
+ Edge cases behave: an empty series draws nothing, a flat series draws through
745
+ the middle rather than collapsing to an edge, and a single reading is a dot.
746
+
747
+ The scale helpers are exported for building your own marks:
748
+
749
+ ```ts
750
+ import { extent, linearScale } from 'iryx-ui'
751
+
752
+ extent([3, null, 9, 1]) // [1, 9] — gaps ignored
753
+ linearScale([0, 10], [100, 0])(10) // 0 — ranges may be inverted for SVG's y-axis
754
+ ```
755
+
484
756
  #### Files
485
757
 
486
758
  ```vue
@@ -3,5 +3,5 @@
3
3
  * Consumed by the Vue plugin (global registration) and the Nuxt module
4
4
  * (auto-imports). Keep in sync with `src/components/index.ts`.
5
5
  */
6
- export declare const componentNames: readonly ["Alert", "App", "Badge", "Banner", "Breadcrumb", "Button", "ButtonGroup", "Card", "Checkbox", "Combobox", "ConfirmDialog", "DatePicker", "DateRangePicker", "Dialog", "DropdownMenu", "EmptyState", "FileUpload", "Form", "FormField", "Input", "Label", "NumberInput", "Pagination", "PasswordInput", "Progress", "RadioGroup", "Select", "Separator", "Skeleton", "Stat", "Stepper", "Switch", "Table", "Tabs", "Textarea", "Toaster", "Tooltip"];
6
+ export declare const componentNames: readonly ["Alert", "App", "Badge", "BarChart", "Banner", "Breadcrumb", "Button", "ButtonGroup", "Card", "ChartLegend", "Checkbox", "Combobox", "ConfirmDialog", "DatePicker", "DateRangePicker", "Dialog", "DropdownMenu", "EmptyState", "FileUpload", "Form", "FormField", "Input", "Label", "LineChart", "NumberInput", "Pagination", "PasswordInput", "Progress", "RadioGroup", "Select", "Separator", "Skeleton", "Sparkline", "Stat", "Stepper", "Switch", "Table", "Tabs", "Textarea", "Toaster", "Tooltip"];
7
7
  export type ComponentName = (typeof componentNames)[number];
@@ -0,0 +1,4 @@
1
+ //#region src/component-names.ts
2
+ var e = /* @__PURE__ */ "Alert.App.Badge.BarChart.Banner.Breadcrumb.Button.ButtonGroup.Card.ChartLegend.Checkbox.Combobox.ConfirmDialog.DatePicker.DateRangePicker.Dialog.DropdownMenu.EmptyState.FileUpload.Form.FormField.Input.Label.LineChart.NumberInput.Pagination.PasswordInput.Progress.RadioGroup.Select.Separator.Skeleton.Sparkline.Stat.Stepper.Switch.Table.Tabs.Textarea.Toaster.Tooltip".split(".");
3
+ //#endregion
4
+ export { e as componentNames };
@@ -1,4 +1,4 @@
1
- import { Alert02Icon as e, AlertCircleIcon as t, Cancel01Icon as n, CheckmarkCircle02Icon as r, InformationCircleIcon as i } from "../../../../node_modules/.pnpm/@hugeicons_core-free-icons@4.2.3/node_modules/@hugeicons/core-free-icons/dist/esm/index.js";
1
+ import { Alert02Icon as e, AlertCircleIcon as t, Cancel01Icon as n, CheckmarkCircle02Icon as r, InformationCircleIcon as i } from "../node_modules/.pnpm/@hugeicons_core-free-icons@4.2.3/node_modules/@hugeicons/core-free-icons/dist/esm/index.js";
2
2
  import { useIryxUiConfig as a } from "../config.js";
3
3
  import { alertTheme as o } from "../theme/alert.js";
4
4
  import s from "./Icon.js";
@@ -1,4 +1,4 @@
1
- import { Cancel01Icon as e } from "../../../../node_modules/.pnpm/@hugeicons_core-free-icons@4.2.3/node_modules/@hugeicons/core-free-icons/dist/esm/index.js";
1
+ import { Cancel01Icon as e } from "../node_modules/.pnpm/@hugeicons_core-free-icons@4.2.3/node_modules/@hugeicons/core-free-icons/dist/esm/index.js";
2
2
  import { useIryxUiConfig as t } from "../config.js";
3
3
  import n from "./Icon.js";
4
4
  import { bannerTheme as r } from "../theme/banner.js";
@@ -0,0 +1,5 @@
1
+ import e from "./BarChart.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/BarChart.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
@@ -0,0 +1,95 @@
1
+ import type { ChartSeries } from '../composables/cartesian';
2
+ import type { SparseValue } from '../composables/scale';
3
+ /**
4
+ * A row. `value` is the single-series shortcut; with `series` set, each entry
5
+ * reads its own key off the row instead — plain objects and a descriptor, the
6
+ * same shape `ITable` uses.
7
+ */
8
+ export interface BarChartDatum {
9
+ label: string;
10
+ /** `null` is a missing reading — no bar is drawn, which is not the same as 0. */
11
+ value?: SparseValue;
12
+ [key: string]: unknown;
13
+ }
14
+ export interface BarChartProps {
15
+ data?: readonly BarChartDatum[];
16
+ /** Two or more measures per category. Omit for the single-series case. */
17
+ series?: readonly ChartSeries[];
18
+ /**
19
+ * `horizontal` runs the categories down the side, where a long name has room
20
+ * to be read. Vertical charts thin their labels to avoid collisions, so long
21
+ * or numerous category names are the case to turn the chart for.
22
+ */
23
+ orientation?: 'vertical' | 'horizontal';
24
+ /** Rendered height in px. Width always fills the container. */
25
+ height?: number;
26
+ /** Target tick count. The axis lands on round numbers, so this is a hint. */
27
+ ticks?: number;
28
+ /** Drop the value axis and its gridlines. */
29
+ axis?: boolean;
30
+ /** Drop the legend. Only honoured for a single series — see below. */
31
+ legend?: boolean;
32
+ /** Locale and options for every number shown — ticks and tooltip alike. */
33
+ locale?: string;
34
+ format?: Intl.NumberFormatOptions;
35
+ /**
36
+ * Accessible name for the figure. The bars are hidden from assistive tech
37
+ * and the data is exposed as a table instead, so this names what that is.
38
+ */
39
+ label?: string;
40
+ /** Skip built-in classes; you take over styling entirely. */
41
+ unstyled?: boolean;
42
+ class?: string;
43
+ ui?: Partial<Record<'root' | 'svg' | 'grid' | 'tick' | 'category' | 'bar' | 'tooltip' | 'tooltipLabel' | 'tooltipValue' | 'table', string>>;
44
+ }
45
+ declare var __VLS_6: {
46
+ orientation: import("..").ChartOrientation;
47
+ ticks: number[];
48
+ plot: {
49
+ left: number;
50
+ top: number;
51
+ width: number;
52
+ height: number;
53
+ };
54
+ value: (value: number) => number;
55
+ y: (value: number) => number;
56
+ bandWidth: number;
57
+ labelStep: number;
58
+ bandCentre: (index: number) => number;
59
+ }, __VLS_8: {
60
+ orientation: import("..").ChartOrientation;
61
+ ticks: number[];
62
+ plot: {
63
+ left: number;
64
+ top: number;
65
+ width: number;
66
+ height: number;
67
+ };
68
+ value: (value: number) => number;
69
+ y: (value: number) => number;
70
+ bandWidth: number;
71
+ labelStep: number;
72
+ bandCentre: (index: number) => number;
73
+ };
74
+ type __VLS_Slots = {} & {
75
+ underlay?: (props: typeof __VLS_6) => any;
76
+ } & {
77
+ overlay?: (props: typeof __VLS_8) => any;
78
+ };
79
+ declare const __VLS_base: import("vue").DefineComponent<BarChartProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<BarChartProps> & Readonly<{}>, {
80
+ unstyled: boolean;
81
+ data: readonly BarChartDatum[];
82
+ legend: boolean;
83
+ orientation: "vertical" | "horizontal";
84
+ height: number;
85
+ ticks: number;
86
+ axis: boolean;
87
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
88
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
89
+ declare const _default: typeof __VLS_export;
90
+ export default _default;
91
+ type __VLS_WithSlots<T, S> = T & {
92
+ new (): {
93
+ $slots: S;
94
+ };
95
+ };