@joanroucoux/cairn-ui 0.6.4 → 0.6.5

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.
@@ -2318,6 +2318,33 @@ const isCoreTick = (index, count) => {
2318
2318
  const middle = Math.floor((count - 1) / 2);
2319
2319
  return index === 0 || index === count - 1 || index === middle;
2320
2320
  };
2321
+ const firstOfEachRun = (labels, included) => {
2322
+ let previous = null;
2323
+ return labels.map((text, index) => {
2324
+ if (!included(index)) {
2325
+ return false;
2326
+ }
2327
+ const distinct = text !== previous;
2328
+ previous = text;
2329
+ return distinct;
2330
+ });
2331
+ };
2332
+ const tickLabels = (ticks, format, mode) => {
2333
+ const labels = ticks.map((tick) => format(tick.t));
2334
+ const count = labels.length;
2335
+ const core = (index) => isCoreTick(index, count);
2336
+ const everyTick = firstOfEachRun(labels, () => true);
2337
+ const coreTicks = firstOfEachRun(labels, core);
2338
+ return labels.map((text, index) => {
2339
+ const wide = mode === 3 ? coreTicks[index] : everyTick[index];
2340
+ const narrow = coreTicks[index];
2341
+ if (!wide && !narrow) {
2342
+ return null;
2343
+ }
2344
+ const classes = mode === 'auto' ? `${narrow ? '' : 'max-sm:hidden'} ${wide ? '' : 'sm:hidden'}`.trim() : wide ? '' : 'hidden';
2345
+ return { text, classes };
2346
+ });
2347
+ };
2321
2348
 
2322
2349
  const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
2323
2350
  const nearestPointIndex = (points, x) => {
@@ -2544,6 +2571,11 @@ const wideViewport = () => {
2544
2571
  /**
2545
2572
  * Value over time: a monotone curve with a dashed line at the starting value and a tooltip.
2546
2573
  *
2574
+ * Axis labels are never repeated: a tick whose `axisFormat` text equals the previous drawn label is
2575
+ * not rendered. The first tick always is, so only the last edge label can drop. With `axisTicks="3"`
2576
+ * only the first, middle and last ticks count; with `auto` every tick counts from `sm` up and the
2577
+ * three core ticks below it. Tick positions are unchanged.
2578
+ *
2547
2579
  * @example
2548
2580
  * <ui-line-chart [points]="points" label="Net worth over one month" startLabel="Since" [valueFormat]="formatEur" />
2549
2581
  */
@@ -2580,7 +2612,6 @@ class UiLineChart {
2580
2612
  #frame = null;
2581
2613
  #hasRenderedOnce = false;
2582
2614
  #previousGeometry = null;
2583
- isCoreTick = isCoreTick;
2584
2615
  svgRef = viewChild.required('svgRef', /* @ts-ignore */
2585
2616
  ...(ngDevMode ? [{ debugName: "svgRef" }] : /* istanbul ignore next */ []));
2586
2617
  activeIndex = signal(null, /* @ts-ignore */
@@ -2608,6 +2639,8 @@ class UiLineChart {
2608
2639
  ...(ngDevMode ? [{ debugName: "displayLine" }] : /* istanbul ignore next */ []));
2609
2640
  ticks = computed(() => axisTicks(this.geometry().points), /* @ts-ignore */
2610
2641
  ...(ngDevMode ? [{ debugName: "ticks" }] : /* istanbul ignore next */ []));
2642
+ tickTexts = computed(() => tickLabels(this.ticks(), this.axisFormat(), this.axisTicks()), /* @ts-ignore */
2643
+ ...(ngDevMode ? [{ debugName: "tickTexts" }] : /* istanbul ignore next */ []));
2611
2644
  active = computed(() => {
2612
2645
  const geometry = this.geometry();
2613
2646
  const index = this.activeIndex();
@@ -2777,25 +2810,19 @@ class UiLineChart {
2777
2810
  [attr.cy]="geometry.end.y"
2778
2811
  />
2779
2812
 
2780
- @for (
2781
- tick of ticks();
2782
- track tick.t;
2783
- let index = $index;
2784
- let count = $count;
2785
- let first = $first;
2786
- let last = $last
2787
- ) {
2788
- <text
2789
- class="text-caption fill-(--subtle-foreground) tabular-nums"
2790
- data-chart-axis-tick
2791
- [attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
2792
- [attr.x]="tick.x"
2793
- [attr.y]="effectiveHeight() - 4"
2794
- [class.hidden]="axisTicks() === 3 && !isCoreTick(index, count)"
2795
- [class.max-sm:hidden]="axisTicks() === 'auto' && !isCoreTick(index, count)"
2796
- >
2797
- {{ axisFormat()(tick.t) }}
2798
- </text>
2813
+ @for (tick of ticks(); track tick.t; let index = $index; let first = $first; let last = $last) {
2814
+ @if (tickTexts()[index]; as label) {
2815
+ <text
2816
+ class="text-caption fill-(--subtle-foreground) tabular-nums"
2817
+ data-chart-axis-tick
2818
+ [attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
2819
+ [attr.x]="tick.x"
2820
+ [attr.y]="effectiveHeight() - 4"
2821
+ [class]="label.classes"
2822
+ >
2823
+ {{ label.text }}
2824
+ </text>
2825
+ }
2799
2826
  }
2800
2827
 
2801
2828
  @if (active(); as point) {
@@ -2925,25 +2952,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
2925
2952
  [attr.cy]="geometry.end.y"
2926
2953
  />
2927
2954
 
2928
- @for (
2929
- tick of ticks();
2930
- track tick.t;
2931
- let index = $index;
2932
- let count = $count;
2933
- let first = $first;
2934
- let last = $last
2935
- ) {
2936
- <text
2937
- class="text-caption fill-(--subtle-foreground) tabular-nums"
2938
- data-chart-axis-tick
2939
- [attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
2940
- [attr.x]="tick.x"
2941
- [attr.y]="effectiveHeight() - 4"
2942
- [class.hidden]="axisTicks() === 3 && !isCoreTick(index, count)"
2943
- [class.max-sm:hidden]="axisTicks() === 'auto' && !isCoreTick(index, count)"
2944
- >
2945
- {{ axisFormat()(tick.t) }}
2946
- </text>
2955
+ @for (tick of ticks(); track tick.t; let index = $index; let first = $first; let last = $last) {
2956
+ @if (tickTexts()[index]; as label) {
2957
+ <text
2958
+ class="text-caption fill-(--subtle-foreground) tabular-nums"
2959
+ data-chart-axis-tick
2960
+ [attr.text-anchor]="first ? 'start' : last ? 'end' : 'middle'"
2961
+ [attr.x]="tick.x"
2962
+ [attr.y]="effectiveHeight() - 4"
2963
+ [class]="label.classes"
2964
+ >
2965
+ {{ label.text }}
2966
+ </text>
2967
+ }
2947
2968
  }
2948
2969
 
2949
2970
  @if (active(); as point) {