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

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 (33) hide show
  1. package/dist/assets/icons/MaterialIcon.svelte +1 -0
  2. package/dist/components/data-vis/line-chart/ValueLabel.svelte +4 -5
  3. package/dist/components/data-vis/position-chart/PositionChart.svelte +235 -204
  4. package/dist/components/data-vis/position-chart/PositionChart.svelte.d.ts +10 -2
  5. package/dist/components/data-vis/position-chart/PositionChartAxis.svelte +40 -26
  6. package/dist/components/data-vis/position-chart/PositionChartAxis.svelte.d.ts +2 -0
  7. package/dist/components/layout/Footer.svelte +10 -2
  8. package/dist/components/layout/Footer.svelte.d.ts +1 -0
  9. package/dist/components/layout/PhaseBanner.svelte +10 -1
  10. package/dist/components/layout/PhaseBanner.svelte.d.ts +1 -0
  11. package/dist/components/layout/ServiceNavigation.svelte +19 -1
  12. package/dist/components/layout/ServiceNavigation.svelte.d.ts +2 -0
  13. package/dist/components/ui/Button.svelte +32 -7
  14. package/dist/components/ui/Button.svelte.d.ts +4 -0
  15. package/dist/components/ui/Card.svelte +23 -17
  16. package/dist/components/ui/CheckBox.svelte +1 -0
  17. package/dist/components/ui/Details.svelte +10 -2
  18. package/dist/components/ui/Details.svelte.d.ts +2 -0
  19. package/dist/components/ui/Masthead.svelte +36 -6
  20. package/dist/components/ui/Masthead.svelte.d.ts +4 -0
  21. package/dist/components/ui/MultiSelectSearchAutocomplete.svelte +311 -204
  22. package/dist/components/ui/MultiSelectSearchAutocomplete.svelte.d.ts +1 -2
  23. package/dist/components/ui/PostcodeOrAreaSearch.svelte +12 -0
  24. package/dist/components/ui/PostcodeOrAreaSearch.svelte.d.ts +4 -0
  25. package/dist/components/ui/Radios.svelte +23 -8
  26. package/dist/components/ui/Radios.svelte.d.ts +1 -0
  27. package/dist/components/ui/RelatedContent.svelte +4 -1
  28. package/dist/components/ui/RelatedContent.svelte.d.ts +1 -0
  29. package/dist/components/ui/SearchAutocomplete.svelte +156 -30
  30. package/dist/components/ui/SearchAutocomplete.svelte.d.ts +4 -0
  31. package/dist/components/ui/Tabs.svelte +196 -23
  32. package/dist/components/ui/Tabs.svelte.d.ts +1 -0
  33. package/package.json +1 -1
@@ -23,6 +23,7 @@
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}
26
27
  >
27
28
  {#each paths as path}
28
29
  <path d={path}></path>
@@ -41,16 +41,15 @@ left: {markerRect?.x +
41
41
  border-radius: 5px;"
42
42
  >
43
43
  {#if tooltipContent}
44
- <div>
44
+ <div role="tooltip">
45
45
  {activeMarkerId[tooltipContent]}
46
46
  </div>
47
47
  {:else}
48
- <div>
49
- <div>{activeMarkerId?.value ?? activeMarkerId}</div>
50
- </div>{/if}
48
+ <div role="tooltip">{activeMarkerId?.value ?? activeMarkerId}</div>
49
+ {/if}
51
50
  </div>
52
51
  {:else}
53
- <div>
52
+ <div role="tooltip">
54
53
  {@render tooltipSnippet(activeMarkerId)}
55
54
  </div>
56
55
  {/if}
@@ -2,6 +2,8 @@
2
2
  import { scaleLinear } from "d3-scale";
3
3
  import PositionChartAxis from "./PositionChartAxis.svelte";
4
4
  import ValueLabel from "../line-chart/ValueLabel.svelte";
5
+ import Button from "../../ui/Button.svelte";
6
+ import InsetText from "../../content/InsetText.svelte";
5
7
  let {
6
8
  value = undefined,
7
9
  min = undefined,
@@ -10,7 +12,7 @@
10
12
  showAxis = true,
11
13
  chartWidth = $bindable(500), // the 'chart' is the bar and the marker
12
14
  chartHeight = 24,
13
- colour = "#CA357C",
15
+ color = "#CA357C",
14
16
  nSegments = 10,
15
17
  startColor = "#8EB8DC",
16
18
  endColor = "#0F385C",
@@ -20,10 +22,12 @@
20
22
  annotation = undefined,
21
23
  showIcon = false,
22
24
  moreInfo = undefined,
25
+ markerRadius = chartHeight / 2,
26
+ options = [],
23
27
  rowData = [
24
28
  {
25
29
  value: value,
26
- colour: colour,
30
+ color: color,
27
31
  opacity: opacity,
28
32
  annotation: annotation,
29
33
  },
@@ -75,10 +79,12 @@
75
79
  activeMarkerId = null;
76
80
  },
77
81
  activeMarkerId = undefined,
82
+ ariaLabel,
83
+ axisTextSize,
78
84
  } = $props();
79
85
 
80
86
  // base defaults that apply to every row
81
- const baseRow = { value, colour, opacity, annotation };
87
+ const baseRow = { value, color, opacity, annotation };
82
88
 
83
89
  // base defaults that apply to every chart
84
90
  const baseChart = { label, chartHeight, min, max, showAxis };
@@ -117,16 +123,12 @@
117
123
  }),
118
124
  );
119
125
 
120
- $inspect(allDataNormalized);
121
-
122
- // holds open/closed state for each label
123
- let openStates = $state({});
126
+ let moreInfoTogglesArray = $state(
127
+ Array.from({ length: options.length }, () => false),
128
+ );
124
129
 
125
- function toggle(label) {
126
- openStates = {
127
- ...openStates,
128
- [label]: !openStates[label], // flip true/false
129
- };
130
+ function updateMoreInfoTogglesArray(index) {
131
+ moreInfoTogglesArray[index] = !moreInfoTogglesArray[index];
130
132
  }
131
133
 
132
134
  let showLabel = $derived(
@@ -147,12 +149,6 @@
147
149
  allDataNormalized.some((obj) => obj.divider !== undefined),
148
150
  );
149
151
 
150
- let gridTemplateRows = $derived(() => {
151
- let rows = showAxis ? numberOfPositionCharts + 2 : numberOfPositionCharts;
152
- if (open) rows += 1;
153
- if (divider) rows += 1;
154
- return `repeat(${rows}, auto)`;
155
- });
156
152
  const range = $derived(Array.from({ length: nSegments }, (_, i) => i));
157
153
 
158
154
  function interpolateColors(hex1, hex2, steps, hexMid = null) {
@@ -224,9 +220,6 @@
224
220
  return result;
225
221
  }
226
222
 
227
- // the 'marker' is the circle
228
- let markerRadius = $derived(chartHeight / 2);
229
-
230
223
  // the 'bar' is the 10 rectangles side by side
231
224
  let barWidth = $derived(chartWidth - markerRadius * 2);
232
225
  let barHeight = $derived((chartHeight * 5) / 6);
@@ -242,199 +235,245 @@
242
235
  (d) => typeof d.annotation === "string" && d.annotation.length > 0,
243
236
  ),
244
237
  );
238
+
239
+ $inspect(allDataNormalized, "allDataNormalized");
240
+
241
+ let gridTemplateRows = $derived(
242
+ allDataNormalized
243
+ .map((item, i) => {
244
+ const sizes = ["minmax(28px,1fr)"];
245
+ if (moreInfoTogglesArray[i]) sizes.push("minmax(50px,auto)");
246
+ if (item.divider) sizes.push("0px");
247
+ return sizes.join(" "); // still fine because number of rows matches
248
+ })
249
+ .concat(showAxis ? ["minmax(0px,auto)"] : [])
250
+ .join(" "),
251
+ );
245
252
  </script>
246
253
 
247
- {#if annotations.length}
248
- {#each annotations as d (d.value)}
249
- <div bind:clientWidth={topWidth}>
250
- <svg width={topWidth} height="60">
251
- <g>
252
- <text
253
- font-family="GDS Transport"
254
- id="label"
255
- x={d.value}
256
- y="20"
257
- fill={d.colour}
258
- font-size="18"
259
- opacity={typeof activeMarkerId !== "undefined" && activeMarkerId
260
- ? 0.2
261
- : 1}
262
- >
263
- {d.annotation}
264
- </text>
265
- </g>
266
- <defs>
267
- <marker
268
- id="arrow-down"
269
- markerWidth="10"
270
- markerHeight="10"
271
- refX="3"
272
- refY="3"
273
- orient="auto"
274
- markerUnits="strokeWidth"
254
+ <div role="img" aria-label={ariaLabel}>
255
+ {#if annotations.length}
256
+ {#each annotations as d (d.value)}
257
+ <div bind:clientWidth={topWidth} aria-hidden={true}>
258
+ <svg width={topWidth} height="60">
259
+ <g>
260
+ <text
261
+ font-family="GDS Transport"
262
+ id="label"
263
+ x={d.value}
264
+ y="20"
265
+ fill={d.color}
266
+ font-size="18"
267
+ opacity={typeof activeMarkerId !== "undefined" && activeMarkerId
268
+ ? 0.2
269
+ : 1}
270
+ >
271
+ {d.annotation}
272
+ </text>
273
+ </g>
274
+ <defs>
275
+ <marker
276
+ id="arrow-down"
277
+ markerWidth="10"
278
+ markerHeight="10"
279
+ refX="3"
280
+ refY="3"
281
+ orient="auto"
282
+ markerUnits="strokeWidth"
283
+ opacity={typeof activeMarkerId !== "undefined" && activeMarkerId
284
+ ? 0.2
285
+ : 1}
286
+ >
287
+ <path d="M 0 0 L 6 3 L 0 6 z" fill={d.color}></path>
288
+ </marker>
289
+ </defs>
290
+ <path
291
+ d="M 4 25 v 10 h {xFunction(min, max)(d.value) +
292
+ markerRadius -
293
+ 4 +
294
+ (topWidth - chartWidth)} v 15"
295
+ fill="none"
296
+ stroke={d.color}
297
+ stroke-width="1.5"
298
+ marker-end="url(#arrow-down)"
275
299
  opacity={typeof activeMarkerId !== "undefined" && activeMarkerId
276
300
  ? 0.2
277
301
  : 1}
278
- >
279
- <path d="M 0 0 L 6 3 L 0 6 z" fill={d.colour}></path>
280
- </marker>
281
- </defs>
282
- <path
283
- d="M 4 25 v 10 h {xFunction(min, max)(d.value) +
284
- markerRadius -
285
- 4 +
286
- (topWidth - chartWidth)} v 15"
287
- fill="none"
288
- stroke={d.colour}
289
- stroke-width="1.5"
290
- marker-end="url(#arrow-down)"
291
- opacity={typeof activeMarkerId !== "undefined" && activeMarkerId
292
- ? 0.2
293
- : 1}
294
- ></path>
295
- </svg>
296
- </div>
297
- {/each}
298
- {/if}
302
+ ></path>
303
+ </svg>
304
+ </div>
305
+ {/each}
306
+ {/if}
299
307
 
300
- <div
301
- class="grid-container"
302
- bind:this={container}
303
- style="
308
+ <div
309
+ class="grid-container"
310
+ bind:this={container}
311
+ style="
304
312
  position: relative;
305
313
  grid-template-columns: {gridTemplateColumns};
306
314
  grid-template-rows: {gridTemplateRows};
307
315
  "
308
- >
309
- {#each allDataNormalized as positionChart, i}
310
- {#if showLabel}
311
- <p class="label">{positionChart.label}</p>
312
- {/if}
313
- {#if showIcon}
314
- <button
315
- id="info-{positionChart.label}"
316
- onclick={() => toggle(positionChart.label)}>ⓘ</button
316
+ >
317
+ {#each allDataNormalized as positionChart, i}
318
+ {#if showLabel}
319
+ <p
320
+ aria-hidden={true}
321
+ class="govuk-body-s"
322
+ style=" text-align: right;
323
+ margin: 0;
324
+ line-height: 1.05;"
325
+ >
326
+ {positionChart.label}
327
+ </p>
328
+ {/if}
329
+ {#if showIcon}
330
+ <Button
331
+ textContent="i"
332
+ buttonType="moreInfo"
333
+ noPadding={true}
334
+ onClickFunction={() => updateMoreInfoTogglesArray(i)}
335
+ ariaExpanded={moreInfoTogglesArray[i]}
336
+ ></Button>
337
+ {/if}
338
+ <div
339
+ class="chart"
340
+ style="height: {positionChart.chartHeight}px"
341
+ bind:clientWidth={chartWidth}
317
342
  >
318
- {/if}
319
- <div
320
- class="chart"
321
- style="height: {positionChart.chartHeight}px"
322
- bind:clientWidth={chartWidth}
323
- >
324
- <svg width={chartWidth} height={positionChart.chartHeight}>
325
- {#each range as number}
326
- <g
327
- transform="translate({markerRadius +
328
- (barWidth * number) / nSegments},{(positionChart.chartHeight -
329
- barHeight) /
330
- 2})"
331
- ><rect
332
- width={barWidth / nSegments}
333
- height={barHeight}
334
- fill={colorScale && colorScale.length > 0
335
- ? colorScale[number]
336
- : interpolateColors(startColor, endColor, nSegments, midColor)[
337
- number
338
- ]}
339
- ></rect></g
340
- >{/each}
341
- {#each Object.entries(positionChart.rowData) as [tier, points]}
342
- {#each points as rowValue, i}
343
- {@const markerId = "marker-" + rowValue.value}
343
+ <svg
344
+ width={chartWidth}
345
+ height={positionChart.chartHeight}
346
+ aria-hidden={true}
347
+ >
348
+ <rect
349
+ x={markerRadius}
350
+ y={(positionChart.chartHeight - barHeight) / 2}
351
+ width={barWidth}
352
+ height={barHeight}
353
+ fill="none"
354
+ stroke="grey"
355
+ stroke-width="1"
356
+ ></rect>
357
+ {#each range as number}
344
358
  <g
345
- data-id={markerId}
346
- onclick={interactiveMarkers
347
- ? (event) => onClickMarker(event, rowValue, markerId)
348
- : null}
349
- onmouseenter={interactiveMarkers
350
- ? (event) =>
351
- onMouseEnterMarker(
352
- event,
353
- rowValue,
354
- markerId,
355
- event.currentTarget.getBoundingClientRect(),
356
- )
357
- : null}
358
- onmouseleave={interactiveMarkers
359
- ? (event) => onMouseLeaveMarker(event, rowValue, markerId)
360
- : null}
361
- role="button"
362
- tabindex="0"
363
- onkeydown={interactiveMarkers
364
- ? (e) => e.key === "Enter" && onClickMarker(e, value)
365
- : null}
366
- pointer-events={interactiveMarkers ? null : "none"}
367
- transform="translate({xFunction(
368
- positionChart.min,
369
- positionChart.max,
370
- )(rowValue.value) + markerRadius},{positionChart.chartHeight /
359
+ transform="translate({markerRadius +
360
+ (barWidth * number) / nSegments},{(positionChart.chartHeight -
361
+ barHeight) /
371
362
  2})"
372
- >
373
- <circle
374
- r={markerRadius}
375
- cx="0"
376
- cy="0"
377
- fill={rowValue.colour}
378
- stroke="white"
379
- opacity={rowValue.opacity}
380
- ></circle>
381
- </g>
363
+ ><rect
364
+ width={barWidth / nSegments}
365
+ height={barHeight}
366
+ fill={colorScale && colorScale.length > 0
367
+ ? colorScale[number]
368
+ : interpolateColors(
369
+ startColor,
370
+ endColor,
371
+ nSegments,
372
+ midColor,
373
+ )[number]}
374
+ ></rect></g
375
+ >{/each}
376
+
377
+ {#each Object.entries(positionChart.rowData) as [tier, points]}
378
+ {#each points as rowValue, i}
379
+ {#if !isNaN(Number(rowValue.value))}
380
+ {@const markerId = "marker-" + rowValue.value}
381
+ <g
382
+ data-id={markerId}
383
+ onclick={interactiveMarkers
384
+ ? (event) => onClickMarker(event, rowValue, markerId)
385
+ : null}
386
+ onmouseenter={interactiveMarkers
387
+ ? (event) =>
388
+ onMouseEnterMarker(
389
+ event,
390
+ rowValue,
391
+ markerId,
392
+ event.currentTarget.getBoundingClientRect(),
393
+ )
394
+ : null}
395
+ onmouseleave={interactiveMarkers
396
+ ? (event) => onMouseLeaveMarker(event, rowValue, markerId)
397
+ : null}
398
+ onfocus={interactiveMarkers
399
+ ? (event) =>
400
+ onMouseEnterMarker(
401
+ event,
402
+ rowValue,
403
+ markerId,
404
+ event.currentTarget.getBoundingClientRect(),
405
+ )
406
+ : null}
407
+ onblur={interactiveMarkers
408
+ ? (event) => onMouseLeaveMarker(event, rowValue, markerId)
409
+ : null}
410
+ role="button"
411
+ aria-label={tooltipContent}
412
+ tabindex="0"
413
+ onkeydown={interactiveMarkers
414
+ ? (event) => onClickMarker(event, rowValue, markerId)
415
+ : null}
416
+ pointer-events={interactiveMarkers ? null : "none"}
417
+ transform="translate({xFunction(
418
+ positionChart.min,
419
+ positionChart.max,
420
+ )(rowValue.value) + markerRadius},{positionChart.chartHeight /
421
+ 2})"
422
+ >
423
+ <circle
424
+ r={markerRadius}
425
+ cx="0"
426
+ cy="0"
427
+ fill={rowValue.color}
428
+ stroke="white"
429
+ opacity={rowValue.opacity}
430
+ ></circle>
431
+ </g>
432
+ {/if}
433
+ {/each}
382
434
  {/each}
383
- {/each}
384
- </svg>
385
- </div>
386
- {#if openStates[positionChart.label]}
387
- <div
388
- class="accordion"
389
- style="grid-column:1 / -1; background-color:lightgrey; padding:10px; margin-right:{markerRadius}px"
390
- >
391
- <p>
392
- {positionChart.moreInfo}
393
- </p>
394
- </div>
395
- {/if}
396
- {#if positionChart.divider}
397
- <div style="grid-column:1 / -1">
398
- <svg width="100%" height="10">
399
- <line
400
- x1="0"
401
- y1="5"
402
- x2="100%"
403
- y2="5"
404
- stroke="black"
405
- stroke-width="2"
406
- stroke-dasharray="2,6"
407
- ></line>
408
435
  </svg>
409
- </div>{/if}
410
- {/each}
436
+ </div>
437
+ {#if moreInfoTogglesArray[i]}
438
+ <div class="accordion" style="grid-column:1 / -1" aria-live="assertive">
439
+ <InsetText content={positionChart.moreInfo} renderStringAsHTML={true}
440
+ ></InsetText>
441
+ </div>
442
+ {/if}
443
+ {#if positionChart.divider}
444
+ <div
445
+ style="grid-column:1 / -1; border-bottom: solid 1px #d5dade;"
446
+ ></div>{/if}
447
+ {/each}
411
448
 
412
- {#if showAxis}
413
- {#if showIcon}
414
- <div class="empty"></div>
449
+ {#if showAxis}
450
+ {#if showIcon}
451
+ <div class="empty"></div>
452
+ {/if}
453
+ {#if showLabel}
454
+ <div class="empty"></div>
455
+ {/if}
456
+ <div class="axis" aria-hidden="true">
457
+ <PositionChartAxis {markerRadius} {barWidth} textSize={axisTextSize}
458
+ ></PositionChartAxis>
459
+ </div>
415
460
  {/if}
416
- {#if showLabel}
417
- <div class="empty"></div>
461
+ {#if activeMarkerId}
462
+ <ValueLabel
463
+ {activeMarkerId}
464
+ labelColor="lightgrey"
465
+ labelTextColor="black"
466
+ {labelText}
467
+ {tooltipContent}
468
+ {xFunction}
469
+ {yFunction}
470
+ {x}
471
+ {y}
472
+ {markerRect}
473
+ {tooltipSnippet}
474
+ ></ValueLabel>
418
475
  {/if}
419
- <div class="axis">
420
- <PositionChartAxis {markerRadius} {barWidth}></PositionChartAxis>
421
- </div>
422
- {/if}
423
- {#if activeMarkerId}
424
- <ValueLabel
425
- {activeMarkerId}
426
- labelColor="lightgrey"
427
- labelTextColor="black"
428
- {labelText}
429
- {tooltipContent}
430
- {xFunction}
431
- {yFunction}
432
- {x}
433
- {y}
434
- {markerRect}
435
- {tooltipSnippet}
436
- ></ValueLabel>
437
- {/if}
476
+ </div>
438
477
  </div>
439
478
 
440
479
  <style>
@@ -445,18 +484,10 @@
445
484
  column-gap: 2%;
446
485
  row-gap: 2%;
447
486
  }
448
- .label {
449
- text-align: right;
450
- margin: 0;
451
- line-height: 1.05;
452
- }
453
487
  .chart {
454
488
  display: flex;
455
489
  flex-direction: column;
456
490
  justify-content: flex-end;
457
491
  min-width: 0;
458
492
  }
459
- .accordion {
460
- max-height: 500px !important; /* large enough to fit content */
461
- }
462
493
  </style>
@@ -11,7 +11,7 @@ declare const PositionChart: import("svelte").Component<{
11
11
  showAxis?: boolean;
12
12
  chartWidth?: number;
13
13
  chartHeight?: number;
14
- colour?: string;
14
+ color?: string;
15
15
  nSegments?: number;
16
16
  startColor?: string;
17
17
  endColor?: string;
@@ -21,6 +21,8 @@ declare const PositionChart: import("svelte").Component<{
21
21
  annotation?: any;
22
22
  showIcon?: boolean;
23
23
  moreInfo?: any;
24
+ markerRadius?: any;
25
+ options?: any[];
24
26
  rowData?: any[];
25
27
  allData?: any[];
26
28
  markerStyles?: Record<string, any>;
@@ -40,6 +42,8 @@ declare const PositionChart: import("svelte").Component<{
40
42
  onMouseEnterMarker?: Function;
41
43
  onMouseLeaveMarker?: Function;
42
44
  activeMarkerId?: any;
45
+ ariaLabel: any;
46
+ axisTextSize: any;
43
47
  }, {}, "chartWidth">;
44
48
  type $$ComponentProps = {
45
49
  value?: any;
@@ -49,7 +53,7 @@ type $$ComponentProps = {
49
53
  showAxis?: boolean;
50
54
  chartWidth?: number;
51
55
  chartHeight?: number;
52
- colour?: string;
56
+ color?: string;
53
57
  nSegments?: number;
54
58
  startColor?: string;
55
59
  endColor?: string;
@@ -59,6 +63,8 @@ type $$ComponentProps = {
59
63
  annotation?: any;
60
64
  showIcon?: boolean;
61
65
  moreInfo?: any;
66
+ markerRadius?: any;
67
+ options?: any[];
62
68
  rowData?: any[];
63
69
  allData?: any[];
64
70
  markerStyles?: Record<string, any>;
@@ -78,4 +84,6 @@ type $$ComponentProps = {
78
84
  onMouseEnterMarker?: Function;
79
85
  onMouseLeaveMarker?: Function;
80
86
  activeMarkerId?: any;
87
+ ariaLabel: any;
88
+ axisTextSize: any;
81
89
  };