Skip to content

Commit e8fb558

Browse files
author
Fergus Bisset
committed
Build of SimpleSortableTable
1 parent 804867c commit e8fb558

File tree

8 files changed

+512
-10
lines changed

8 files changed

+512
-10
lines changed

dist/components/ProductRoadmap/ProductRoadmap.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ span .nhsuk-u-visually-hidden {
9494
--roadmap-row-gap: 8px;
9595
--item-height: 2;
9696
--roadmap-line-height: 1.5rem;
97-
--roadmap-item-block-height: calc(var(--roadmap-line-height) * var(--item-height));
97+
--roadmap-item-block-height: calc(
98+
var(--roadmap-line-height) * var(--item-height)
99+
);
98100
--roadmap-item-horizontal-inset: 16px;
99101
display: grid;
100102
grid-auto-rows: auto;
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
.nhsuk-u-visually-hidden {
2+
position: absolute !important;
3+
width: 1px !important;
4+
height: 1px !important;
5+
padding: 0 !important;
6+
margin: -1px !important;
7+
overflow: hidden !important;
8+
clip: rect(0, 0, 0, 0) !important;
9+
white-space: nowrap !important;
10+
border: 0 !important;
11+
}
12+
.nhsuk-u-hidden {
13+
display: none !important;
14+
}
15+
.nhsuk-u-show {
16+
display: block !important;
17+
}
18+
.nhsuk-u-text-left {
19+
text-align: left !important;
20+
}
21+
.nhsuk-u-text-center {
22+
text-align: center !important;
23+
}
24+
.nhsuk-u-text-right {
25+
text-align: right !important;
26+
}
27+
.nhsuk-u-margin-0 {
28+
margin: 0 !important;
29+
}
30+
.nhsuk-u-margin-bottom-0 {
31+
margin-bottom: 0 !important;
32+
}
33+
.nhsuk-u-margin-top-0 {
34+
margin-top: 0 !important;
35+
}
36+
.nhsuk-u-padding-0 {
37+
padding: 0 !important;
38+
}
39+
.nhsuk-u-padding-bottom-0 {
40+
padding-bottom: 0 !important;
41+
}
42+
.nhsuk-u-padding-top-0 {
43+
padding-top: 0 !important;
44+
}
45+
.nhsuk-u-clearfix::after {
46+
content: "";
47+
display: table;
48+
clear: both;
49+
}
50+
51+
.nhsuk-header .nhsuk-u-visually-hidden,
52+
.nhsuk-header__search .nhsuk-u-visually-hidden,
53+
label .nhsuk-u-visually-hidden,
54+
span .nhsuk-u-visually-hidden {
55+
position: absolute !important;
56+
width: 1px !important;
57+
height: 1px !important;
58+
padding: 0 !important;
59+
margin: -1px !important;
60+
overflow: hidden !important;
61+
clip: rect(0, 0, 0, 0) !important;
62+
-webkit-clip-path: inset(50%) !important;
63+
clip-path: inset(50%) !important;
64+
white-space: nowrap !important;
65+
border: 0 !important;
66+
}
67+
68+
.nhsuk-width-container {
69+
margin: 0 auto;
70+
padding: 0 24px;
71+
max-width: 1200px;
72+
}
73+
@media (min-width: 768px) {
74+
.nhsuk-width-container {
75+
padding: 0 32px;
76+
}
77+
}
78+
@media (min-width: 1020px) {
79+
.nhsuk-width-container {
80+
padding: 0 40px;
81+
}
82+
}
83+
84+
.nhsuk-icon {
85+
width: auto !important;
86+
height: 2em;
87+
vertical-align: text-bottom;
88+
flex-shrink: 0;
89+
}
90+
91+
.nhsuk-sortable-table-container {
92+
position: relative;
93+
}
94+
95+
.nhsuk-sortable-table__button {
96+
font-family: Frutiger W01, Arial, sans-serif;
97+
font-size: 14px;
98+
font-weight: 600;
99+
line-height: 24px;
100+
background: none;
101+
border: 0;
102+
color: #212b32;
103+
cursor: pointer;
104+
display: flex;
105+
align-items: center;
106+
gap: 8px;
107+
padding: 0;
108+
text-align: left;
109+
width: 100%;
110+
}
111+
@media (min-width: 768px) {
112+
.nhsuk-sortable-table__button {
113+
font-size: 16px;
114+
line-height: 24px;
115+
}
116+
}
117+
.nhsuk-sortable-table__button:hover {
118+
color: #005eb8;
119+
}
120+
.nhsuk-sortable-table__button:hover .nhsuk-sortable-table__icon {
121+
fill: #005eb8;
122+
}
123+
.nhsuk-sortable-table__button:focus {
124+
outline: 3px solid transparent;
125+
outline-offset: 2px;
126+
color: #212b32 !important;
127+
background-color: #ffeb3b;
128+
box-shadow: 0 -2px #ffeb3b, 0 3px #212b32;
129+
text-decoration: none;
130+
}
131+
.nhsuk-sortable-table__button:focus svg.nhsuk-sortable-table__icon {
132+
fill: #212b32 !important;
133+
}
134+
.nhsuk-sortable-table__button:active {
135+
color: #212b32;
136+
}
137+
138+
.nhsuk-sortable-table__button-text {
139+
flex: 1;
140+
}
141+
142+
.nhsuk-sortable-table__icon-wrapper {
143+
display: flex;
144+
align-items: center;
145+
flex-shrink: 0;
146+
}
147+
148+
.nhsuk-sortable-table__icon {
149+
width: 13px;
150+
height: 17px;
151+
fill: #212b32;
152+
transition: fill 0.2s ease;
153+
}
154+
155+
th[aria-sort=ascending] .nhsuk-sortable-table__button,
156+
th[aria-sort=descending] .nhsuk-sortable-table__button {
157+
color: #005eb8;
158+
}
159+
th[aria-sort=ascending] .nhsuk-sortable-table__button .nhsuk-sortable-table__icon,
160+
th[aria-sort=descending] .nhsuk-sortable-table__button .nhsuk-sortable-table__icon {
161+
fill: #005eb8;
162+
}

dist/components/_internal/Mermaid.css

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ span .nhsuk-u-visually-hidden {
112112
--mermaid-node-extra-padding-x: 0;
113113
--mermaid-node-extra-padding-y: 0;
114114
/* Extra padding to apply to the SVG viewBox (in px) to avoid edge clipping */
115-
--mermaid-svg-extra-padding-x: 6;
116-
--mermaid-svg-extra-padding-y: 4;
115+
--mermaid-svg-extra-padding-x: 20;
116+
--mermaid-svg-extra-padding-y: 16;
117117
/* Edge label sizing controls */
118118
--mermaid-edge-label-padding-x: 4;
119119
--mermaid-edge-label-padding-y: 2;
@@ -126,8 +126,8 @@ span .nhsuk-u-visually-hidden {
126126
font-family: Frutiger W01, Arial, sans-serif;
127127
line-height: 1.3;
128128
position: relative;
129-
/* Scroll hint (fade) */
130-
mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
129+
/* Scroll hint (fade) - removed to prevent edge clipping */
130+
/* Use overflow-x: auto for horizontal scrolling instead */
131131
}
132132

133133
/* Optional utility variants to quickly tweak padding per-diagram */
@@ -150,6 +150,9 @@ span .nhsuk-u-visually-hidden {
150150
.mermaid-diagram.is-airy {
151151
--mermaid-node-base-padding-x: 24;
152152
--mermaid-node-base-padding-y: 16;
153+
--mermaid-svg-extra-padding-x: 32;
154+
--mermaid-svg-extra-padding-y: 24;
155+
padding: 32px;
153156
}
154157

155158
.mermaid-error {
@@ -175,7 +178,10 @@ span .nhsuk-u-visually-hidden {
175178
width: 100%;
176179
height: auto;
177180
/* Token-driven class styles (no need for Mermaid classDef colours) */
181+
/* Lifecycle diagram specific styles */
178182
/* Edges */
183+
/* Markers (arrowheads) - ensure they render on top and are visible */
184+
/* Ensure markers render above nodes by adjusting SVG rendering order */
179185
}
180186
.mermaid-diagram svg .node {
181187
/* Base shapes (specificity via svg .node + !important) */
@@ -292,10 +298,127 @@ span .nhsuk-u-visually-hidden {
292298
.mermaid-diagram svg .node.warning .nodeLabel {
293299
color: #b71c1c !important;
294300
}
301+
.mermaid-diagram svg .node.lifecycle-start rect, .mermaid-diagram svg .node.lifecycle-start polygon, .mermaid-diagram svg .node.lifecycle-start circle, .mermaid-diagram svg .node.lifecycle-start ellipse {
302+
fill: #e1f5fe !important; /* Light blue */
303+
stroke: #01579b !important;
304+
}
305+
.mermaid-diagram svg .node.lifecycle-start text {
306+
fill: #01579b !important;
307+
}
308+
.mermaid-diagram svg .node.lifecycle-start .nodeLabel {
309+
color: #01579b !important;
310+
}
311+
.mermaid-diagram svg .node.lifecycle-ready rect, .mermaid-diagram svg .node.lifecycle-ready polygon, .mermaid-diagram svg .node.lifecycle-ready circle, .mermaid-diagram svg .node.lifecycle-ready ellipse {
312+
fill: #c8e6c9 !important; /* Light green */
313+
stroke: #1b5e20 !important;
314+
}
315+
.mermaid-diagram svg .node.lifecycle-ready text {
316+
fill: #1b5e20 !important;
317+
}
318+
.mermaid-diagram svg .node.lifecycle-ready .nodeLabel {
319+
color: #1b5e20 !important;
320+
}
321+
.mermaid-diagram svg .node.lifecycle-error rect, .mermaid-diagram svg .node.lifecycle-error polygon, .mermaid-diagram svg .node.lifecycle-error circle, .mermaid-diagram svg .node.lifecycle-error ellipse {
322+
fill: #ffcdd2 !important; /* Light red */
323+
stroke: #b71c1c !important;
324+
}
325+
.mermaid-diagram svg .node.lifecycle-error text {
326+
fill: #b71c1c !important;
327+
}
328+
.mermaid-diagram svg .node.lifecycle-error .nodeLabel {
329+
color: #b71c1c !important;
330+
}
331+
.mermaid-diagram svg .node.lifecycle-phase rect, .mermaid-diagram svg .node.lifecycle-phase polygon, .mermaid-diagram svg .node.lifecycle-phase circle, .mermaid-diagram svg .node.lifecycle-phase ellipse {
332+
fill: #fff9c4 !important; /* Yellow */
333+
stroke: #f57f17 !important;
334+
}
335+
.mermaid-diagram svg .node.lifecycle-phase text {
336+
fill: #f57f17 !important;
337+
}
338+
.mermaid-diagram svg .node.lifecycle-phase .nodeLabel {
339+
color: #f57f17 !important;
340+
}
341+
.mermaid-diagram svg .node.lifecycle-user-action rect, .mermaid-diagram svg .node.lifecycle-user-action polygon, .mermaid-diagram svg .node.lifecycle-user-action circle, .mermaid-diagram svg .node.lifecycle-user-action ellipse {
342+
fill: #f8bbd0 !important; /* Pink */
343+
stroke: #880e4f !important;
344+
}
345+
.mermaid-diagram svg .node.lifecycle-user-action text {
346+
fill: #880e4f !important;
347+
}
348+
.mermaid-diagram svg .node.lifecycle-user-action .nodeLabel {
349+
color: #880e4f !important;
350+
}
351+
.mermaid-diagram svg .node.lifecycle-complete rect, .mermaid-diagram svg .node.lifecycle-complete polygon, .mermaid-diagram svg .node.lifecycle-complete circle, .mermaid-diagram svg .node.lifecycle-complete ellipse {
352+
fill: #d1c4e9 !important; /* Light purple */
353+
stroke: #4a148c !important;
354+
}
355+
.mermaid-diagram svg .node.lifecycle-complete text {
356+
fill: #4a148c !important;
357+
}
358+
.mermaid-diagram svg .node.lifecycle-complete .nodeLabel {
359+
color: #4a148c !important;
360+
}
361+
.mermaid-diagram svg .node.lifecycle-announce rect, .mermaid-diagram svg .node.lifecycle-announce polygon, .mermaid-diagram svg .node.lifecycle-announce circle, .mermaid-diagram svg .node.lifecycle-announce ellipse {
362+
fill: #b2dfdb !important; /* Light teal */
363+
stroke: #004d40 !important;
364+
}
365+
.mermaid-diagram svg .node.lifecycle-announce text {
366+
fill: #004d40 !important;
367+
}
368+
.mermaid-diagram svg .node.lifecycle-announce .nodeLabel {
369+
color: #004d40 !important;
370+
}
371+
.mermaid-diagram svg .node.initPhase rect, .mermaid-diagram svg .node.initPhase polygon, .mermaid-diagram svg .node.initPhase circle, .mermaid-diagram svg .node.initPhase ellipse {
372+
fill: #fff3e0 !important; /* Light orange */
373+
stroke: #ff6f00 !important;
374+
stroke-width: 2px !important;
375+
}
376+
.mermaid-diagram svg .node.initPhase text {
377+
fill: #e65100 !important;
378+
}
379+
.mermaid-diagram svg .node.initPhase .nodeLabel {
380+
color: #e65100 !important;
381+
}
382+
.mermaid-diagram svg .node.sortPhase rect, .mermaid-diagram svg .node.sortPhase polygon, .mermaid-diagram svg .node.sortPhase circle, .mermaid-diagram svg .node.sortPhase ellipse {
383+
fill: #e8eaf6 !important; /* Light indigo */
384+
stroke: #3f51b5 !important;
385+
stroke-width: 2px !important;
386+
}
387+
.mermaid-diagram svg .node.sortPhase text {
388+
fill: #1a237e !important;
389+
}
390+
.mermaid-diagram svg .node.sortPhase .nodeLabel {
391+
color: #1a237e !important;
392+
}
393+
.mermaid-diagram svg .node.domPhase rect, .mermaid-diagram svg .node.domPhase polygon, .mermaid-diagram svg .node.domPhase circle, .mermaid-diagram svg .node.domPhase ellipse {
394+
fill: #e0f2f1 !important; /* Light teal */
395+
stroke: #009688 !important;
396+
stroke-width: 2px !important;
397+
}
398+
.mermaid-diagram svg .node.domPhase text {
399+
fill: #004d40 !important;
400+
}
401+
.mermaid-diagram svg .node.domPhase .nodeLabel {
402+
color: #004d40 !important;
403+
}
295404
.mermaid-diagram svg .edgePath path.path {
296405
stroke: var(--_mm-border) !important;
297406
stroke-width: 1.2px !important;
298407
}
408+
.mermaid-diagram svg marker {
409+
overflow: visible !important;
410+
}
411+
.mermaid-diagram svg marker path {
412+
fill: var(--_mm-border) !important;
413+
stroke: var(--_mm-border) !important;
414+
}
415+
.mermaid-diagram svg defs marker {
416+
/* Markers are defined in defs, ensure they're styled */
417+
}
418+
.mermaid-diagram svg defs marker path {
419+
fill: var(--_mm-border) !important;
420+
stroke: none !important;
421+
}
299422
.mermaid-diagram svg .edgeLabel {
300423
background-color: #ffffff !important; /* optional background */
301424
overflow: visible !important; /* allow expansion */

dist/nhs-fdp-design-system.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from "react";
2+
import type { TableProps } from "./Table.types";
3+
import "./SimpleSortableTable.scss";
4+
export interface SimpleSortableTableProps extends Omit<TableProps, "head" | "rows" | "columns" | "data"> {
5+
/**
6+
* Column definitions for the sortable table
7+
*/
8+
columns: Array<{
9+
key: string;
10+
title: string;
11+
sortable?: boolean;
12+
format?: string;
13+
headerClasses?: string;
14+
cellClasses?: string;
15+
/** Custom sort value accessor - if not provided, uses the key */
16+
sortValue?: (row: any) => string | number;
17+
}>;
18+
/**
19+
* Data rows for the table
20+
*/
21+
data: any[];
22+
/**
23+
* Optional initial sort column key
24+
*/
25+
initialSort?: {
26+
key: string;
27+
direction: "ascending" | "descending";
28+
};
29+
/**
30+
* Callback when sort changes
31+
*/
32+
onSortChange?: (key: string, direction: "ascending" | "descending") => void;
33+
}
34+
/**
35+
* SimpleSortableTable - Progressive enhancement sortable table
36+
*
37+
* Applies MOJ Frontend SortableTable patterns to NHS FDP Design System Table component.
38+
*
39+
* Features:
40+
* - Progressive enhancement (base table works without JS)
41+
* - ARIA live region for sort announcements
42+
* - Visual sort indicators (SVG arrows)
43+
* - Accessible button-based column headers
44+
* - Keyboard navigable
45+
* - Numeric and string sorting with locale awareness
46+
*/
47+
export declare const SimpleSortableTable: React.FC<SimpleSortableTableProps>;
48+
export default SimpleSortableTable;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { default as Table, TableCaption, TableBodyRow, TableHeaderCell, TableCell } from './Table';
2+
export { default as SimpleSortableTable } from './SimpleSortableTable';
23
export type { TableProps, TableCellData, TableHeaderCellType, TableCaptionProps, TableBodyRowProps, TableHeaderCellComponentProps, TableDataCellComponentProps, TableColumn, } from './Table.types';

0 commit comments

Comments
 (0)