@communitiesuk/svelte-component-library 0.1.19-beta.11 → 0.1.19-beta.14

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 (44) hide show
  1. package/dist/assets/icons/MaterialIcon.svelte +0 -1
  2. package/dist/components/data-vis/axis/Axis.svelte +141 -33
  3. package/dist/components/data-vis/axis/Axis.svelte.d.ts +29 -30
  4. package/dist/components/data-vis/axis/Ticks.svelte +125 -45
  5. package/dist/components/data-vis/axis/Ticks.svelte.d.ts +22 -30
  6. package/dist/components/data-vis/histogram/Histogram.svelte +252 -0
  7. package/dist/components/data-vis/histogram/Histogram.svelte.d.ts +47 -0
  8. package/dist/components/data-vis/line-chart/LineChart.svelte.d.ts +1 -1
  9. package/dist/components/data-vis/line-chart/ValueLabel.svelte +26 -14
  10. package/dist/components/data-vis/line-chart/ValueLabel.svelte.d.ts +2 -0
  11. package/dist/components/data-vis/position-chart/PositionChart.svelte +976 -328
  12. package/dist/components/data-vis/position-chart/PositionChart.svelte.d.ts +39 -7
  13. package/dist/components/data-vis/position-chart/PositionChartAxis.svelte +30 -20
  14. package/dist/components/data-vis/position-chart/PositionChartAxis.svelte.d.ts +4 -0
  15. package/dist/components/data-vis/position-chart/assignBinColors.d.ts +1 -0
  16. package/dist/components/data-vis/position-chart/assignBinColors.js +13 -0
  17. package/dist/components/data-vis/position-chart/createEqualWidthBins.d.ts +12 -0
  18. package/dist/components/data-vis/position-chart/createEqualWidthBins.js +42 -0
  19. package/dist/components/data-vis/position-chart/getColorsForValues.d.ts +1 -0
  20. package/dist/components/data-vis/position-chart/getColorsForValues.js +16 -0
  21. package/dist/components/data-vis/position-chart/interpolateColors.d.ts +1 -0
  22. package/dist/components/data-vis/position-chart/interpolateColors.js +68 -0
  23. package/dist/components/data-vis/position-chart/splitGroupsAndAverages.d.ts +4 -0
  24. package/dist/components/data-vis/position-chart/splitGroupsAndAverages.js +20 -0
  25. package/dist/components/layout/Footer.svelte +2 -1
  26. package/dist/components/ui/Button.svelte +7 -31
  27. package/dist/components/ui/Button.svelte.d.ts +0 -4
  28. package/dist/components/ui/Card.svelte +51 -61
  29. package/dist/components/ui/Card.svelte.d.ts +26 -12
  30. package/dist/components/ui/CardHeader.svelte +43 -0
  31. package/dist/components/ui/CardHeader.svelte.d.ts +19 -0
  32. package/dist/components/ui/CheckBox.svelte +2 -2
  33. package/dist/components/ui/MultiSelectSearchAutocomplete.svelte +204 -311
  34. package/dist/components/ui/MultiSelectSearchAutocomplete.svelte.d.ts +2 -1
  35. package/dist/components/ui/Radios.svelte +8 -23
  36. package/dist/components/ui/Radios.svelte.d.ts +0 -1
  37. package/dist/components/ui/SearchAutocomplete.svelte +69 -44
  38. package/dist/components/ui/SearchAutocomplete.svelte.d.ts +1 -0
  39. package/dist/components/ui/Tabs.svelte +5 -6
  40. package/dist/index.d.ts +2 -0
  41. package/dist/index.js +2 -0
  42. package/dist/server/lastUpdated.d.ts +1 -0
  43. package/dist/server/lastUpdated.js +10 -0
  44. package/package.json +2 -1
@@ -23,7 +23,6 @@
23
23
  class="c inline h-16 w-16"
24
24
  viewBox="0 0 48 48"
25
25
  style={`transform: rotate(${rotation}deg)`}
26
- aria-hidden={true}
27
26
  >
28
27
  {#each paths as path}
29
28
  <path d={path}></path>
@@ -1,51 +1,159 @@
1
- <script>
2
- import { FolderArrowRightSolid } from "flowbite-svelte-icons";
1
+ <script lang="ts">
2
+ import {
3
+ scaleLinear,
4
+ type ScaleContinuousNumeric,
5
+ type ScaleLinear,
6
+ } from "d3-scale";
3
7
  import Ticks from "./Ticks.svelte";
4
8
 
9
+ type AxisName = "x" | "y";
10
+ type Polarity = "standard" | "reverse";
11
+
12
+ type AxisPosition = "bottom" | "top" | "left" | "right";
13
+ type Orientation = { axis: AxisName; position: AxisPosition };
14
+ type AxisProjector = (value: number) => number;
15
+ type LabelFormatter = (
16
+ tick: number,
17
+ index: number,
18
+ numberOfTicks: number,
19
+ values: number[],
20
+ ) => string | number;
21
+
5
22
  let {
6
- chartHeight,
7
- chartWidth,
8
- numberOfTicks,
9
- ticksArray = $bindable(),
10
- axisFunction,
11
- values,
12
- orientation,
13
- prefix,
14
- suffix,
15
- floor,
16
- ceiling,
17
- yearsInput,
23
+ chartHeight = 100,
24
+ chartWidth = $bindable<number>(200),
25
+
26
+ numberOfTicks = 2,
27
+
28
+ // Bindable, but avoid binding undefined – initialize as [] for safety
29
+ ticksArray = $bindable<number[]>([]),
30
+
31
+ // Values to derive ticks/domain from if ticksArray not provided
32
+ values = undefined as number[] | undefined,
33
+
34
+ orientation = { axis: "x", position: "bottom" } as Orientation,
35
+
36
+ floor = null,
37
+ ceiling = null,
38
+
39
+ paddingTop = 100,
40
+ paddingBottom = 100,
41
+ paddingLeft = 0,
42
+ paddingRight = 0,
43
+
44
+ labelFormatter = undefined as LabelFormatter | undefined,
45
+
46
+ // --- New inputs for D3 scale + optional overrides ---
47
+ // A ready-made D3 continuous scale (linear/log/time, etc.)
48
+ // For this component we use numeric-only; time scales also implement numeric mapping.
49
+ scale = undefined as ScaleContinuousNumeric<number, number> | undefined,
50
+
51
+ // Optional overrides for domain/range applied to a COPY of the provided scale
52
+ domain = undefined as [number, number] | undefined,
53
+ range = undefined as [number, number] | undefined,
54
+ fontSize = 19,
55
+ polarity = "standard" as Polarity,
56
+ }: {
57
+ chartHeight?: number;
58
+ chartWidth?: number;
59
+ numberOfTicks?: number;
60
+ ticksArray?: number[];
61
+ values?: number[];
62
+ orientation?: Orientation;
63
+ floor?: number | null;
64
+ ceiling?: number | null;
65
+ paddingTop?: number;
66
+ paddingBottom?: number;
67
+ paddingLeft?: number;
68
+ paddingRight?: number;
69
+ labelFormatter?: LabelFormatter;
70
+
71
+ // New
72
+ scale?: ScaleContinuousNumeric<number, number>;
73
+ domain?: [number, number];
74
+ range?: [number, number];
75
+ fontSize?: number;
76
+ polarity?: Polarity;
18
77
  } = $props();
78
+
79
+ // --- Helpers to compute default domain/range when not supplied ---
80
+ const innerWidth = $derived(Math.max(0, chartWidth));
81
+ const innerHeight = $derived(Math.max(0, chartHeight));
82
+
83
+ function computeDefaultDomain(): [number, number] {
84
+ const arr = (ticksArray && ticksArray.length ? ticksArray : values) ?? [];
85
+ const dMin =
86
+ floor ?? (arr.length ? arr.reduce((a, b) => (a < b ? a : b)) : 0);
87
+ const dMax =
88
+ ceiling ?? (arr.length ? arr.reduce((a, b) => (a > b ? a : b)) : 1);
89
+ return [dMin, dMax];
90
+ }
91
+
92
+ function computeDefaultRange(innerWidth, innerHeight): [number, number] {
93
+ if (orientation.axis === "x") {
94
+ return [0, innerWidth];
95
+ } else {
96
+ return [innerHeight, 0];
97
+ }
98
+ }
99
+ //Returns d3 scale function
100
+ const resolvedScale = $derived(() => {
101
+ const base: ScaleContinuousNumeric<number, number> = scale
102
+ ? scale.copy()
103
+ : scaleLinear<number, number>();
104
+
105
+ const useDomain = domain ?? computeDefaultDomain();
106
+ base.domain(useDomain);
107
+
108
+ let useRange = range ?? computeDefaultRange(innerWidth, innerHeight);
109
+ if (polarity === "reverse") {
110
+ useRange = [...useRange].reverse();
111
+ }
112
+ base.range([...useRange]);
113
+
114
+ return base;
115
+ });
116
+
117
+ const axisFunction: AxisProjector = (v) => {
118
+ const s = resolvedScale();
119
+ const r = s.range();
120
+ const lo = Math.min(r[0], r[1]);
121
+ const hi = Math.max(r[0], r[1]);
122
+ const px = s(v);
123
+ return Math.max(lo, Math.min(hi, px));
124
+ };
19
125
  </script>
20
126
 
21
127
  <g
22
128
  data-role="{orientation.axis}-axis"
23
- transform="translate({orientation.position != 'right'
129
+ transform="translate({orientation.position !== 'right'
24
130
  ? 0
25
131
  : chartWidth},{orientation.position === 'bottom' ? chartHeight : 0})"
26
132
  >
27
133
  <line
28
- x1="0"
134
+ x1={0}
29
135
  y1="0"
30
136
  x2={orientation.axis === "x" ? chartWidth : 0}
31
137
  y2={orientation.axis === "y" ? chartHeight : 0}
32
- stroke="black"
138
+ stroke="darkgrey"
33
139
  stroke-width="2px"
34
140
  ></line>
35
- {#key numberOfTicks}
36
- <Ticks
37
- bind:ticksArray
38
- {chartWidth}
39
- {chartHeight}
40
- {axisFunction}
41
- {values}
42
- {numberOfTicks}
43
- {orientation}
44
- {floor}
45
- {ceiling}
46
- {yearsInput}
47
- {suffix}
48
- {prefix}
49
- ></Ticks>
50
- {/key}
141
+ {#if values}
142
+ {#key numberOfTicks}
143
+ <Ticks
144
+ bind:ticksArray
145
+ {chartWidth}
146
+ {chartHeight}
147
+ {axisFunction}
148
+ {values}
149
+ {numberOfTicks}
150
+ {orientation}
151
+ {floor}
152
+ {ceiling}
153
+ {labelFormatter}
154
+ {fontSize}
155
+ {polarity}
156
+ />
157
+ {/key}
158
+ {/if}
51
159
  </g>
@@ -1,33 +1,32 @@
1
- export default Axis;
2
- type Axis = {
3
- $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: Partial<$$ComponentProps>): void;
1
+ import { type ScaleContinuousNumeric } from "d3-scale";
2
+ type AxisName = "x" | "y";
3
+ type Polarity = "standard" | "reverse";
4
+ type AxisPosition = "bottom" | "top" | "left" | "right";
5
+ type Orientation = {
6
+ axis: AxisName;
7
+ position: AxisPosition;
5
8
  };
6
- declare const Axis: import("svelte").Component<{
7
- chartHeight: any;
8
- chartWidth: any;
9
- numberOfTicks: any;
10
- ticksArray?: any;
11
- axisFunction: any;
12
- values: any;
13
- orientation: any;
14
- prefix: any;
15
- suffix: any;
16
- floor: any;
17
- ceiling: any;
18
- yearsInput: any;
19
- }, {}, "ticksArray">;
9
+ type LabelFormatter = (tick: number, index: number, numberOfTicks: number, values: number[]) => string | number;
20
10
  type $$ComponentProps = {
21
- chartHeight: any;
22
- chartWidth: any;
23
- numberOfTicks: any;
24
- ticksArray?: any;
25
- axisFunction: any;
26
- values: any;
27
- orientation: any;
28
- prefix: any;
29
- suffix: any;
30
- floor: any;
31
- ceiling: any;
32
- yearsInput: any;
11
+ chartHeight?: number;
12
+ chartWidth?: number;
13
+ numberOfTicks?: number;
14
+ ticksArray?: number[];
15
+ values?: number[];
16
+ orientation?: Orientation;
17
+ floor?: number | null;
18
+ ceiling?: number | null;
19
+ paddingTop?: number;
20
+ paddingBottom?: number;
21
+ paddingLeft?: number;
22
+ paddingRight?: number;
23
+ labelFormatter?: LabelFormatter;
24
+ scale?: ScaleContinuousNumeric<number, number>;
25
+ domain?: [number, number];
26
+ range?: [number, number];
27
+ fontSize?: number;
28
+ polarity?: Polarity;
33
29
  };
30
+ declare const Axis: import("svelte").Component<$$ComponentProps, {}, "ticksArray" | "chartWidth">;
31
+ type Axis = ReturnType<typeof Axis>;
32
+ export default Axis;
@@ -1,10 +1,19 @@
1
- <script>
1
+ <script lang="ts">
2
2
  import Decimal from "decimal.js";
3
3
 
4
+ // Types
5
+ type Axis = "x" | "y";
6
+ type Polarity = "standard" | "reverse";
7
+ type Position = "left" | "right" | "top" | "bottom";
8
+
9
+ interface Orientation {
10
+ axis: Axis;
11
+ position: Position;
12
+ }
13
+
14
+ // Props with defaults
4
15
  let {
5
- ticksArray = $bindable(),
6
- prefix,
7
- suffix,
16
+ ticksArray = $bindable<number[]>(),
8
17
  chartWidth,
9
18
  chartHeight,
10
19
  axisFunction,
@@ -13,69 +22,135 @@
13
22
  floor,
14
23
  ceiling,
15
24
  orientation,
16
- yearsInput,
25
+ labelFormatter,
26
+ fontSize = 19,
27
+ clamp = false,
28
+ polarity = "standard",
29
+ }: {
30
+ ticksArray?: number[];
31
+ chartWidth: number;
32
+ chartHeight: number;
33
+ axisFunction: any;
34
+ values: number[];
35
+ numberOfTicks?: number;
36
+ floor?: number | null;
37
+ ceiling?: number | null;
38
+ orientation: Orientation;
39
+ labelFormatter?: (
40
+ tick: number,
41
+ index: number,
42
+ numberOfTicks: number,
43
+ values: number[],
44
+ ) => string;
45
+ fontSize?: number;
46
+ clamp: boolean;
47
+ polarity: Polarity;
17
48
  } = $props();
18
49
 
19
- $inspect(ticksArray);
50
+ // Axis value helper
51
+ function axisValue(fn: any, tick: number): number {
52
+ try {
53
+ const v = fn(tick);
54
+ if (typeof v === "number") return v;
55
+ } catch {}
56
+ const inner = fn();
57
+ return inner(tick);
58
+ }
20
59
 
21
- function generateTicks(data, numTicks, floor, ceiling) {
22
- let minValueFromData = Decimal.min(...data);
60
+ // Generate ticks safely
61
+ function generateTicks(
62
+ data: number[],
63
+ numTicks: number,
64
+ floorVal?: number | null,
65
+ ceilingVal?: number | null,
66
+ ): number[] {
67
+ if (!data || data.length === 0) return [];
23
68
 
24
- let minVal = floor
25
- ? Decimal.max(floor, minValueFromData)
26
- : minValueFromData;
69
+ const dataMin = Decimal.min(...data);
70
+ const dataMax = Decimal.max(...data);
27
71
 
28
- let maxValueFromData = Decimal.max(...data);
72
+ const minVal = floorVal != null ? new Decimal(floorVal) : dataMin;
73
+ const maxVal = ceilingVal != null ? new Decimal(ceilingVal) : dataMax;
29
74
 
30
- let maxVal = ceiling
31
- ? Decimal.min(ceiling, maxValueFromData)
32
- : maxValueFromData;
75
+ const rangeVal = maxVal.minus(minVal);
33
76
 
34
- let rangeVal = maxVal.minus(minVal);
77
+ // Ensure at least 2 ticks
78
+ const stepCount = Math.max(2, numTicks - 1);
79
+ const roughStep = rangeVal.div(stepCount);
35
80
 
36
- let roughStep = rangeVal.div(numTicks - 1);
37
- let normalizedSteps = [1, 2, 5, 10];
81
+ const normalizedSteps = [
82
+ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1, 2, 2.5, 3, 4, 5, 6, 8, 10, 12, 15,
83
+ 25, 30, 35, 40, 45,
84
+ ];
38
85
 
39
- let stepPower = Decimal.pow(
86
+ const stepPower = Decimal.pow(
40
87
  10,
41
88
  -Math.floor(Math.log10(roughStep.toNumber())),
42
89
  );
43
- let normalizedStep = roughStep.mul(stepPower);
44
- let optimalStep = new Decimal(
45
- normalizedSteps.find((step) => step >= normalizedStep.toNumber()),
46
- ).div(stepPower);
47
90
 
48
- let scaleMin = minVal.div(optimalStep).floor().mul(optimalStep);
49
- let scaleMax = maxVal.div(optimalStep).ceil().mul(optimalStep);
91
+ const normalizedStep = roughStep.mul(stepPower);
92
+ const chosen = normalizedSteps.find(
93
+ (step) => step >= normalizedStep.toNumber(),
94
+ );
95
+ const optimalStep = new Decimal(chosen ?? 10).div(stepPower);
96
+
97
+ const scaleMin = minVal.div(optimalStep).floor().mul(optimalStep);
98
+ const scaleMax = maxVal.div(optimalStep).ceil().mul(optimalStep);
50
99
 
51
- let ticks = [];
100
+ const ticks: number[] = [];
52
101
  for (let i = scaleMin; i.lte(scaleMax); i = i.plus(optimalStep)) {
53
102
  ticks.push(i.toNumber());
54
103
  }
55
104
  return ticks;
56
105
  }
57
106
 
58
- function tickCount(chartWidth, chartHeight) {
59
- let tickNum = orientation.axis === "y" ? chartHeight / 50 : chartWidth / 50;
60
- return tickNum;
107
+ // Default label generator
108
+ function defaultLabel(tick: number): string {
109
+ return String(tick);
61
110
  }
62
111
 
63
- function yearsFormat(ticks) {
64
- return ticks.map((tick) => `FY ${tick % 100}-${(tick % 100) + 1}`);
112
+ // Compute number of ticks
113
+ function tickCount(w: number, h: number): number {
114
+ const rawTicks = orientation.axis === "y" ? h / 50 : w / 50;
115
+ return Math.max(2, Math.floor(rawTicks));
65
116
  }
66
117
 
67
- numberOfTicks = tickCount(chartWidth, chartHeight);
118
+ // Clamp ticks safely
119
+ function clampTickEnds(
120
+ ticks: number[],
121
+ floorVal?: number | null,
122
+ ceilingVal?: number | null,
123
+ ): number[] {
124
+ if (!ticks || ticks.length === 0) return ticks;
125
+ const out = ticks.slice();
126
+
127
+ if (floorVal != null && out[0] < floorVal) {
128
+ out[0] = floorVal;
129
+ }
130
+ if (ceilingVal != null && out[out.length - 1] > ceilingVal) {
131
+ out[out.length - 1] = ceilingVal;
132
+ }
133
+ return out;
134
+ }
135
+
136
+ // Compute derived ticks
137
+ const computedTickCount = numberOfTicks ?? tickCount(chartWidth, chartHeight);
138
+
139
+ let derivedTicks = $derived(() => {
140
+ const ticks = generateTicks(values, computedTickCount, floor, ceiling);
141
+ return clamp ? clampTickEnds(ticks, floor, ceiling) : ticks;
142
+ });
68
143
 
69
- ticksArray = generateTicks(values, numberOfTicks, floor, ceiling);
70
- let yearTicks = yearsInput ? yearsFormat(ticksArray) : [];
144
+ ticksArray = derivedTicks();
71
145
  </script>
72
146
 
73
- {#if axisFunction && ticksArray && orientation.axis && orientation.position}
147
+ {#if axisFunction && ticksArray?.length && orientation.axis && orientation.position}
74
148
  {#each ticksArray as tick, index}
75
149
  <g
76
- transform="translate({orientation.axis === 'x'
77
- ? axisFunction(tick)
78
- : 0},{orientation.axis === 'y' ? axisFunction(tick) : 0})"
150
+ transform="translate(
151
+ {orientation.axis === 'x' ? axisValue(axisFunction, tick) : 0},
152
+ {orientation.axis === 'y' ? axisValue(axisFunction, tick) : 0}
153
+ )"
79
154
  >
80
155
  <path
81
156
  d={orientation.axis === "y"
@@ -85,28 +160,33 @@
85
160
  : orientation.position === "top"
86
161
  ? "M0 0 l0 -8"
87
162
  : "M0 0 l0 8"}
88
- stroke="black"
163
+ stroke="darkgrey"
89
164
  stroke-width="2px"
90
165
  ></path>
91
166
  <text
92
- transform="translate({orientation.axis === 'x'
167
+ transform="translate(
168
+ {orientation.axis === 'x'
93
169
  ? 0
94
170
  : orientation.position === 'left'
95
171
  ? -10
96
- : 10}, {orientation.axis === 'y'
172
+ : 10},
173
+ {orientation.axis === 'y'
97
174
  ? 5
98
175
  : orientation.position === 'top'
99
176
  ? -10
100
- : 23})"
101
- font-size="19"
177
+ : 23}
178
+ )"
179
+ font-size={fontSize}
102
180
  text-anchor={orientation.axis === "x"
103
181
  ? "middle"
104
182
  : orientation.position === "left"
105
183
  ? "end"
106
184
  : "start"}
107
- fill="black"
185
+ fill="#666666"
108
186
  >
109
- {yearsInput ? yearTicks[index] : prefix + tick + suffix}
187
+ {labelFormatter
188
+ ? labelFormatter(tick, index, ticksArray.length, values)
189
+ : defaultLabel(tick)}
110
190
  </text>
111
191
  </g>
112
192
  {/each}
@@ -1,33 +1,25 @@
1
- export default Ticks;
2
- type Ticks = {
3
- $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: Partial<$$ComponentProps>): void;
5
- };
6
- declare const Ticks: import("svelte").Component<{
7
- ticksArray?: any;
8
- prefix: any;
9
- suffix: any;
10
- chartWidth: any;
11
- chartHeight: any;
12
- axisFunction: any;
13
- values: any;
14
- numberOfTicks: any;
15
- floor: any;
16
- ceiling: any;
17
- orientation: any;
18
- yearsInput: any;
19
- }, {}, "ticksArray">;
1
+ type Axis = "x" | "y";
2
+ type Polarity = "standard" | "reverse";
3
+ type Position = "left" | "right" | "top" | "bottom";
4
+ interface Orientation {
5
+ axis: Axis;
6
+ position: Position;
7
+ }
20
8
  type $$ComponentProps = {
21
- ticksArray?: any;
22
- prefix: any;
23
- suffix: any;
24
- chartWidth: any;
25
- chartHeight: any;
9
+ ticksArray?: number[];
10
+ chartWidth: number;
11
+ chartHeight: number;
26
12
  axisFunction: any;
27
- values: any;
28
- numberOfTicks: any;
29
- floor: any;
30
- ceiling: any;
31
- orientation: any;
32
- yearsInput: any;
13
+ values: number[];
14
+ numberOfTicks?: number;
15
+ floor?: number | null;
16
+ ceiling?: number | null;
17
+ orientation: Orientation;
18
+ labelFormatter?: (tick: number, index: number, numberOfTicks: number, values: number[]) => string;
19
+ fontSize?: number;
20
+ clamp: boolean;
21
+ polarity: Polarity;
33
22
  };
23
+ declare const Ticks: import("svelte").Component<$$ComponentProps, {}, "ticksArray">;
24
+ type Ticks = ReturnType<typeof Ticks>;
25
+ export default Ticks;