@ukhomeoffice/formio-gds-template 2.0.2 → 3.0.0-alpha

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 (68) hide show
  1. package/LICENCE.md +21 -0
  2. package/eslint.config.mjs +58 -0
  3. package/lib/components/datamap/GDSDataMap.d.ts +4 -14
  4. package/lib/components/datamap/GDSDataMap.js +9 -29
  5. package/lib/components/datetime/GDSDatetimeComponent.d.ts +30 -22
  6. package/lib/components/datetime/GDSDatetimeComponent.js +148 -178
  7. package/lib/components/index.js +4 -4
  8. package/lib/components/selectboxes/GDSCheckBoxes.d.ts +4 -2
  9. package/lib/components/selectboxes/GDSCheckBoxes.js +7 -33
  10. package/lib/components/time/GDSTimeComponent.d.ts +12 -10
  11. package/lib/components/time/GDSTimeComponent.js +59 -84
  12. package/lib/components/util/TimeHelper.d.ts +5 -4
  13. package/lib/components/util/TimeHelper.js +13 -16
  14. package/lib/index.d.ts +2 -2
  15. package/lib/index.js +2 -2
  16. package/lib/templates/gds/button/index.js +1 -1
  17. package/lib/templates/gds/checkbox/index.js +1 -1
  18. package/lib/templates/gds/columns/index.js +1 -1
  19. package/lib/templates/gds/component/index.js +1 -1
  20. package/lib/templates/gds/container/index.js +1 -1
  21. package/lib/templates/gds/datagrid/index.js +1 -1
  22. package/lib/templates/gds/datamap/index.js +1 -1
  23. package/lib/templates/gds/datetime/index.js +1 -1
  24. package/lib/templates/gds/day/index.js +1 -1
  25. package/lib/templates/gds/editgrid/index.js +1 -1
  26. package/lib/templates/gds/field/index.js +1 -1
  27. package/lib/templates/gds/fieldset/index.js +1 -1
  28. package/lib/templates/gds/file/index.js +1 -1
  29. package/lib/templates/gds/iconClass.d.ts +1 -1
  30. package/lib/templates/gds/iconClass.js +3 -3
  31. package/lib/templates/gds/index.d.ts +2 -2
  32. package/lib/templates/gds/index.js +72 -64
  33. package/lib/templates/gds/input/index.js +1 -1
  34. package/lib/templates/gds/label/index.js +1 -1
  35. package/lib/templates/gds/message/index.js +1 -1
  36. package/lib/templates/gds/panel/index.js +1 -1
  37. package/lib/templates/gds/radio/index.js +1 -1
  38. package/lib/templates/gds/select/index.js +1 -1
  39. package/lib/templates/gds/selectOption/index.js +1 -1
  40. package/lib/templates/gds/selectboxes/index.js +1 -1
  41. package/lib/templates/gds/survey/index.js +1 -1
  42. package/lib/templates/gds/tab/index.js +1 -1
  43. package/lib/templates/gds/table/index.js +1 -1
  44. package/lib/templates/gds/template.css +16 -0
  45. package/lib/templates/gds/template.css.map +1 -1
  46. package/lib/templates/gds/time/index.js +1 -1
  47. package/lib/templates/gds/warning/index.js +1 -1
  48. package/lib/templates/gds/wizard/index.js +1 -1
  49. package/lib/templates/gds/wizardHeader/index.js +1 -1
  50. package/lib/templates/gds/wizardNav/index.js +1 -1
  51. package/lib/templates/index.d.ts +2 -2
  52. package/lib/templates/index.js +1 -1
  53. package/lib/types.d.ts +36 -0
  54. package/lib/types.js +2 -0
  55. package/package.json +13 -7
  56. package/src/components/datamap/GDSDataMap.ts +5 -14
  57. package/src/components/datetime/GDSDatetimeComponent.ts +109 -91
  58. package/src/components/selectboxes/GDSCheckBoxes.ts +7 -8
  59. package/src/components/time/GDSTimeComponent.ts +37 -27
  60. package/src/components/util/TimeHelper.ts +6 -5
  61. package/src/css.d.ts +4 -0
  62. package/src/templates/gds/iconClass.ts +1 -1
  63. package/src/templates/gds/index.ts +43 -33
  64. package/src/templates/gds/template.scss +30 -1
  65. package/src/types.ts +55 -0
  66. package/tsconfig.json +6 -3
  67. package/webpack.config.js +1 -1
  68. package/tslint.json +0 -22
@@ -1,20 +1,19 @@
1
- import {Components} from 'formiojs';
1
+ import { Components } from '@formio/js';
2
+ import { SelectBoxesComponent } from '../../types';
3
+
2
4
  const Field = Components.components.field;
3
5
  const SelectBoxes = Components.components.selectboxes;
4
6
 
5
7
  export default class GDSCheckBoxes extends SelectBoxes {
6
- public render() {
7
- // @ts-ignore
8
+ // Narrow the inherited `component: any` using the @formio/core SelectBoxesComponent schema.
9
+ declare component: SelectBoxesComponent;
10
+
11
+ public render(): string {
8
12
  return Field.prototype.render.call(this, this.renderTemplate('selectboxes', {
9
- // @ts-ignore
10
13
  input: this.inputInfo,
11
- // @ts-ignore
12
14
  inline: this.component.inline,
13
- // @ts-ignore
14
15
  values: this.component.values,
15
- // @ts-ignore
16
16
  value: this.dataValue,
17
- // @ts-ignore
18
17
  row: this.row,
19
18
  }));
20
19
  }
@@ -1,23 +1,31 @@
1
- import {Components} from 'formiojs';
1
+ import { Components } from '@formio/js';
2
2
  import moment from 'moment';
3
3
  import TimeHelper from '../util/TimeHelper';
4
+ import { CoreTimeComponent } from '../../types';
4
5
 
5
6
  const Field = Components.components.field;
6
7
  const Time = Components.components.time;
7
8
 
8
- // @ts-ignore
9
9
  export default class GDSTimeComponent extends Time {
10
10
  public static MAX_LENGTH = 2;
11
11
 
12
- private refs: any;
13
- private component: any;
14
- private loadRefs: any;
15
- private checkComponentValidity: any;
16
- private updateValue: any;
12
+ // Narrow the inherited `component: any` using the @formio/core TimeComponent schema.
13
+ declare component: CoreTimeComponent;
14
+
15
+ // Narrow `refs: {}` to the specific refs loaded by this component.
16
+ declare refs: {
17
+ hour: HTMLInputElement;
18
+ minute: HTMLInputElement;
19
+ };
20
+
21
+ // Narrow `data: any` to a typed record.
22
+ declare data: Record<string, unknown>;
17
23
 
18
24
  private timeHelper: TimeHelper = new TimeHelper();
19
25
 
20
- public attach(element) {
26
+ // element typed as `any` to match the base component attach(element: any) override signature
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ public attach(element: any): Promise<void> {
21
29
  this.loadRefs(element, {
22
30
  hour: 'single',
23
31
  minute: 'single',
@@ -27,47 +35,48 @@ export default class GDSTimeComponent extends Time {
27
35
  this.timeHelper.checkAndValidateHour(this.refs.hour);
28
36
  this.setPristine(false);
29
37
  this.checkComponentValidity(this.data, true);
30
- this.updateValue(null, {modified: true});
38
+ this.updateValue(null, { modified: true });
31
39
  });
32
40
 
33
41
  this.addEventListener(this.refs.minute, 'input', () => {
34
42
  this.timeHelper.checkAndValidateMinutes(this.refs.minute);
35
43
  this.setPristine(false);
36
44
  this.checkComponentValidity(this.data, true);
37
- this.updateValue(null, {modified: true});
45
+ this.updateValue(null, { modified: true });
38
46
  });
39
47
 
40
- this.addEventListener(this.refs.hour, 'keypress', (evt) => {
48
+ this.addEventListener(this.refs.hour, 'keypress', (evt: KeyboardEvent) => {
41
49
  this.timeHelper.preventNonNumericKeyPress(evt);
42
50
  });
43
51
 
44
- this.addEventListener(this.refs.minute, 'keypress', (evt) => {
52
+ this.addEventListener(this.refs.minute, 'keypress', (evt: KeyboardEvent) => {
45
53
  this.timeHelper.preventNonNumericKeyPress(evt);
46
54
  });
55
+
47
56
  return super.attach(element);
48
57
  }
49
58
 
50
- public setErrorClasses(elements, dirty, hasError) {
51
- // @ts-ignore
52
- super.setErrorClasses( [this.refs.hour, this.refs.minute, ...elements], dirty, hasError);
59
+ // elements typed as `any` to match the base Day.setErrorClasses(elements: any, ...) override signature
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ public setErrorClasses(elements: any, dirty: any, hasError: any): void {
62
+ super.setErrorClasses([this.refs.hour, this.refs.minute, ...elements], dirty, hasError);
53
63
  }
54
64
 
55
- // @ts-ignore
56
- public addInputError(message: any, dirty: boolean, element: any): void {
57
- // @ts-ignore
65
+ // message/dirty/element typed as `any` to match the base Component.addInputError(message: any, dirty: any, elements: any) signature
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ public addInputError(message: any, dirty: any, element: any): void {
58
68
  super.addInputError(message, dirty, [this.refs.hour, this.refs.minute]);
59
- // @ts-ignore
60
69
  super.addInputError(message, dirty, element);
61
70
  }
62
71
 
63
- public removeInputError(elements) {
64
- // @ts-ignore
72
+ // elements typed as `any` to match the base Component.removeInputError(elements: any) signature
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ public removeInputError(elements: any): void {
65
75
  super.removeInputError([this.refs.hour, this.refs.minute]);
66
- // @ts-ignore
67
76
  super.removeInputError(elements);
68
77
  }
69
78
 
70
- public getValue() {
79
+ public getValue(): string {
71
80
  if (!this.refs.hour.value || !this.refs.minute.value) {
72
81
  return '';
73
82
  }
@@ -75,10 +84,11 @@ export default class GDSTimeComponent extends Time {
75
84
  return moment(value, this.component.format).format(this.component.dataFormat);
76
85
  }
77
86
 
78
- public setValue(value: any, flags: any) {
79
-
87
+ // value/flags typed as `any` to match the base Component.setValue(value: any, flags: any) override signature
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ public setValue(value: any, _flags: any): boolean {
80
90
  if (this.refs.hour && this.refs.minute && value) {
81
- const parts = value.split(':');
91
+ const parts = (value as string).split(':');
82
92
  this.refs.hour.value = parts[0];
83
93
  this.refs.minute.value = parts[1];
84
94
  return true;
@@ -86,7 +96,7 @@ export default class GDSTimeComponent extends Time {
86
96
  return false;
87
97
  }
88
98
 
89
- public render() {
99
+ public render(): string {
90
100
  return Field.prototype.render.call(this, this.renderTemplate('time', {
91
101
  hour: super.getValue().split(':')[0],
92
102
  minute: super.getValue().split(':')[1],
@@ -1,8 +1,10 @@
1
+ import { InputElementLike } from '../../types';
2
+
1
3
  export default class TimeHelper {
2
4
 
3
5
  public static MAX_LENGTH = 2;
4
6
 
5
- public checkAndValidateMinutes(element: any): void {
7
+ public checkAndValidateMinutes(element: InputElementLike): void {
6
8
  if (element.value) {
7
9
  if (element.value.length > TimeHelper.MAX_LENGTH) {
8
10
  element.value = element.value.slice(0, 2);
@@ -17,8 +19,7 @@ export default class TimeHelper {
17
19
  }
18
20
  }
19
21
 
20
- public checkAndValidateHour(element: any): void {
21
-
22
+ public checkAndValidateHour(element: InputElementLike): void {
22
23
  if (element.value) {
23
24
  if (element.value.length > TimeHelper.MAX_LENGTH) {
24
25
  element.value = element.value.slice(0, 2);
@@ -34,13 +35,13 @@ export default class TimeHelper {
34
35
  }
35
36
  }
36
37
 
37
- public preventNonNumericKeyPress(evt: any) {
38
+ public preventNonNumericKeyPress(evt: KeyboardEvent): void {
38
39
  if (evt.which !== 8 && evt.which !== 0 && evt.which < 48 || evt.which > 57) {
39
40
  evt.preventDefault();
40
41
  }
41
42
  }
42
43
 
43
- validateDateInput(element: any, length: number) {
44
+ public validateDateInput(element: InputElementLike, length: number): void {
44
45
  if (element.value && element.value.length > length) {
45
46
  element.value = element.value.slice(0, length);
46
47
  }
package/src/css.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ declare module '*.css' {
2
+ const content: string;
3
+ export default content;
4
+ }
@@ -1,4 +1,4 @@
1
- export default (iconset, name, spinning) => {
1
+ export default (iconset: string, name: string, spinning: boolean): string => {
2
2
  if (iconset === 'fa') {
3
3
  switch (name) {
4
4
  case 'save':
@@ -31,46 +31,56 @@ import wizard from './wizard';
31
31
  import wizardHeader from './wizardHeader';
32
32
  import wizardNav from './wizardNav';
33
33
 
34
+ // Unwrap CJS default exports to handle ESM/CJS interop in Vite.
35
+ // Uses a generic so the return type matches the input type — no `any` needed.
36
+ const unwrap = <T>(mod: T | { default: T }): T =>
37
+ (mod !== null && typeof mod === 'object' && 'default' in (mod as object))
38
+ ? (mod as { default: T }).default
39
+ : (mod as T);
40
+
34
41
  export default {
35
- transform(type, text) {
42
+ transform(type: string, text: string) {
36
43
  if (!text) {
37
44
  return text;
38
45
  }
39
46
  if (type === 'class') {
40
- return this.cssClasses.hasOwnProperty(text.toString()) ? this.cssClasses[text.toString()] : text;
47
+ const key = text.toString();
48
+ return Object.prototype.hasOwnProperty.call(this.cssClasses, key)
49
+ ? this.cssClasses[key as keyof typeof this.cssClasses]
50
+ : text;
41
51
  }
42
52
  return text;
43
53
  },
44
54
  defaultIconset: 'fa',
45
- iconClass,
46
- cssClasses,
47
- button,
48
- checkbox,
49
- columns,
50
- component,
51
- container,
52
- datetime,
53
- day,
54
- datagrid,
55
- datamap,
56
- input,
57
- editgrid,
58
- field,
59
- file,
60
- fieldset,
61
- label,
62
- message,
63
- panel,
64
- radio,
65
- select,
66
- selectboxes,
67
- selectOption,
68
- survey,
69
- table,
70
- tab,
71
- time,
72
- warning,
73
- wizard,
74
- wizardHeader,
75
- wizardNav,
55
+ iconClass: unwrap(iconClass),
56
+ cssClasses: unwrap(cssClasses),
57
+ button: unwrap(button),
58
+ checkbox: unwrap(checkbox),
59
+ columns: unwrap(columns),
60
+ component: unwrap(component),
61
+ container: unwrap(container),
62
+ datetime: unwrap(datetime),
63
+ day: unwrap(day),
64
+ datagrid: unwrap(datagrid),
65
+ datamap: unwrap(datamap),
66
+ input: unwrap(input),
67
+ editgrid: unwrap(editgrid),
68
+ field: unwrap(field),
69
+ file: unwrap(file),
70
+ fieldset: unwrap(fieldset),
71
+ label: unwrap(label),
72
+ message: unwrap(message),
73
+ panel: unwrap(panel),
74
+ radio: unwrap(radio),
75
+ select: unwrap(select),
76
+ selectboxes: unwrap(selectboxes),
77
+ selectOption: unwrap(selectOption),
78
+ survey: unwrap(survey),
79
+ table: unwrap(table),
80
+ tab: unwrap(tab),
81
+ time: unwrap(time),
82
+ warning: unwrap(warning),
83
+ wizard: unwrap(wizard),
84
+ wizardHeader: unwrap(wizardHeader),
85
+ wizardNav: unwrap(wizardNav),
76
86
  };
@@ -82,6 +82,25 @@
82
82
 
83
83
  .govuk-details {
84
84
  margin-bottom: 0 !important;
85
+
86
+ // govuk-frontend@5.x sets font-weight:bold on the summary — reset to normal
87
+ &__summary {
88
+ font-weight: 400 !important;
89
+ }
90
+ }
91
+
92
+ // @formio/js@5.x injects error messages into messageContainer on container components
93
+ // (datagrid, editgrid, datamap, panel) which causes double error messages since child
94
+ // components already show their own errors. Hide the outer messageContainer for these types.
95
+ .formio-component-datagrid,
96
+ .formio-component-editgrid,
97
+ .formio-component-datamap,
98
+ .formio-component-panel,
99
+ .formio-component-container,
100
+ .formio-component-fieldset {
101
+ > [ref="messageContainer"] {
102
+ display: none;
103
+ }
85
104
  }
86
105
 
87
106
  .small-button {
@@ -144,4 +163,14 @@
144
163
 
145
164
  .govuk-select.auto-height {
146
165
  height: auto;
147
- }
166
+ }
167
+
168
+ // govuk-frontend@5.4+ sets overflow:clip (with auto visible fallback) on
169
+ // .govuk-form-group--error to contain the error border. This clips the focus
170
+ // rings and left borders of nested formio child components. Reset it so
171
+ // nested form groups are never clipped.
172
+ .govuk-form-group--error {
173
+ .govuk-form-group {
174
+ overflow: visible;
175
+ }
176
+ }
package/src/types.ts ADDED
@@ -0,0 +1,55 @@
1
+ import type {
2
+ DayComponent,
3
+ DateTimeComponent,
4
+ TimeComponent as CoreTimeComponent,
5
+ SelectBoxesComponent,
6
+ DataMapComponent,
7
+ } from '@formio/core';
8
+
9
+ /**
10
+ * Minimal interface for DOM input-like elements.
11
+ * Used as the typed parameter in TimeHelper methods so callers can pass any
12
+ * object that has a writable `.value: string` (e.g. HTMLInputElement).
13
+ */
14
+ export interface InputElementLike {
15
+ value: string;
16
+ }
17
+
18
+ /**
19
+ * The shape of a single GDS date/time field definition.
20
+ * Extends the base formio field definition with an optional placeholder.
21
+ */
22
+ export type GDSFieldDefinition = {
23
+ type?: string;
24
+ placeholder?: string;
25
+ required?: boolean;
26
+ };
27
+
28
+ /**
29
+ * Component schema for GDSDatetimeComponent.
30
+ *
31
+ * GDSDatetimeComponent extends the formio Day component but adds hour/minute
32
+ * fields (from a datetime hybrid) and uses datePicker / defaultDate from
33
+ * DateTimeComponent. This type captures the full shape of `this.component`
34
+ * as used in GDSDatetimeComponent.
35
+ */
36
+ export type GDSDatetimeComponentSchema =
37
+ // Omit `suffix` from the base so our wider `string | null` declaration wins
38
+ // the intersection (BaseComponent declares `suffix?: string`, which would
39
+ // collapse `string | null` back to `string` in a plain &-intersection).
40
+ // Also omit `fields` so we can extend it with hour/minute below.
41
+ Omit<DayComponent, 'suffix' | 'fields'> &
42
+ Pick<DateTimeComponent, 'datePicker' | 'defaultDate'> & {
43
+ /** suffix is set to null in init() — null must be allowed */
44
+ suffix?: string | null;
45
+ /** fields extended with GDS hour/minute additions */
46
+ fields: DayComponent['fields'] & {
47
+ hour?: GDSFieldDefinition;
48
+ minute?: GDSFieldDefinition;
49
+ };
50
+ };
51
+
52
+ // Re-export @formio/core schema types used as `declare component` overrides
53
+ // in each GDS component class. Aliased to avoid colliding with the @formio/js
54
+ // runtime class variables (e.g. `const Time = Components.components.time`).
55
+ export type { CoreTimeComponent, SelectBoxesComponent, DataMapComponent };
package/tsconfig.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es5",
4
- "module": "commonjs",
3
+ "target": "es2018",
4
+ "lib": ["es2018", "dom"],
5
+ "module": "nodenext",
6
+ "moduleResolution": "nodenext",
5
7
  "preserveConstEnums": true,
6
8
  "outDir": "lib",
7
- "noImplicitAny": false,
9
+ "noImplicitAny": true,
10
+ "skipLibCheck": true,
8
11
  "sourceMap": false,
9
12
  "declaration": true,
10
13
  "rootDir": "src",
package/webpack.config.js CHANGED
@@ -10,7 +10,7 @@ module.exports = {
10
10
  filename: 'gds.js',
11
11
  },
12
12
  externals: {
13
- formiojs: 'Formio'
13
+ '@formio/js': 'Formio'
14
14
  },
15
15
  module: {
16
16
  rules: [
package/tslint.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "defaultSeverity": "error",
3
- "extends": [
4
- "tslint:recommended"
5
- ],
6
- "jsRules": {},
7
- "rules": {
8
- "quotemark": [true, "single", "avoid-escape", "avoid-template"],
9
- "one-line": [false, "check-catch", "check-finally", "check-else"],
10
- "object-literal-sort-keys": false,
11
- "no-shadowed-variable": false,
12
- "variable-name": {
13
- "options": [
14
- "allow-leading-underscore",
15
- "allow-pascal-case",
16
- "ban-keywords"
17
- ]
18
- },
19
- "max-classes-per-file": [false]
20
- },
21
- "rulesDirectory": []
22
- }