@linzjs/step-ag-grid 8.1.0 → 8.2.0

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 (29) hide show
  1. package/dist/index.css +19 -5
  2. package/dist/src/components/gridForm/GridFormDropDown.d.ts +2 -2
  3. package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +1 -0
  4. package/dist/src/components/gridPopoverEdit/GridPopoverEditDropDown.d.ts +2 -2
  5. package/dist/src/utils/bearing.d.ts +2 -0
  6. package/dist/step-ag-grid.esm.js +39 -36
  7. package/dist/step-ag-grid.esm.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/components/GridCell.tsx +2 -2
  10. package/src/components/gridForm/GridFormDropDown.tsx +8 -4
  11. package/src/components/gridForm/GridFormEditBearing.tsx +1 -1
  12. package/src/components/gridForm/GridFormMultiSelect.tsx +10 -8
  13. package/src/components/gridPopoverEdit/GridPopoverEditBearing.ts +8 -13
  14. package/src/components/gridPopoverEdit/GridPopoverEditDropDown.ts +3 -3
  15. package/src/react-menu3/styles/_var.scss +1 -1
  16. package/src/stories/grid/gridForm/GridFormDropDown.stories.tsx +2 -6
  17. package/src/stories/grid/gridForm/GridFormEditBearing.stories.tsx +8 -12
  18. package/src/stories/grid/gridForm/GridFormEditBearingCorrection.stories.tsx +8 -12
  19. package/src/stories/grid/gridForm/GridFormMessage.stories.tsx +0 -1
  20. package/src/stories/grid/gridForm/GridFormMultiSelect.stories.tsx +70 -0
  21. package/src/stories/grid/gridForm/GridFormTextArea.stories.tsx +44 -0
  22. package/src/stories/grid/gridForm/GridFormTextInput.stories.tsx +44 -0
  23. package/src/styles/Grid.scss +1 -1
  24. package/src/styles/GridFormMultiSelect.scss +4 -0
  25. package/src/styles/GridIcon.scss +10 -0
  26. package/src/styles/lui-overrides.scss +1 -1
  27. package/src/styles/react-menu-customisations.scss +2 -2
  28. package/src/utils/bearing.test.ts +46 -3
  29. package/src/utils/bearing.ts +14 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@linzjs/step-ag-grid",
3
3
  "repository": "github:linz/step-ag-grid.git",
4
4
  "license": "MIT",
5
- "version": "8.1.0",
5
+ "version": "8.2.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -29,8 +29,8 @@ export const GridCellRenderer = (props: ICellRendererParams) => {
29
29
  return (
30
30
  <GridLoadableCell isLoading={checkUpdating(colDef.field ?? colDef.colId ?? "", props.data.id)}>
31
31
  <>
32
- {typeof warningText === "string" && <GridIcon icon={"ic_warning"} title={warningText} />}
33
- {typeof infoText === "string" && <GridIcon icon={"ic_info"} title={infoText} />}
32
+ {typeof warningText === "string" && <GridIcon icon={"ic_warning_outline"} title={warningText} />}
33
+ {typeof infoText === "string" && <GridIcon icon={"ic_info_outline"} title={infoText} />}
34
34
  <div style={{ display: "flex", flex: 1, overflow: "hidden" }}>
35
35
  {colDef?.cellRendererParams?.originalCellRenderer ? (
36
36
  <colDef.cellRendererParams.originalCellRenderer {...props} />
@@ -36,7 +36,7 @@ export const MenuHeaderItem = (title: string) => {
36
36
 
37
37
  export type SelectOption = null | string | FinalSelectOption;
38
38
 
39
- export interface GridFormPopoutDropDownProps<RowType extends GridBaseRow> extends CellEditorCommon {
39
+ export interface GridFormDropDownProps<RowType extends GridBaseRow> extends CellEditorCommon {
40
40
  // This overrides CellEditorCommon to provide some common class options
41
41
  className?:
42
42
  | "GridPopoverEditDropDown-containerSmall"
@@ -63,7 +63,7 @@ const fieldToString = (field: any) => {
63
63
  return typeof field == "symbol" ? field.toString() : `${field}`;
64
64
  };
65
65
 
66
- export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormPopoutDropDownProps<RowType>) => {
66
+ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDropDownProps<RowType>) => {
67
67
  const { selectedRows, field, data } = useGridPopoverContext<RowType>();
68
68
 
69
69
  // Save triggers during async action processing which triggers another selectItem(), this ref blocks that
@@ -215,7 +215,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormPop
215
215
  className={"LuiTextInput-input"}
216
216
  ref={ref}
217
217
  type="text"
218
- placeholder={props.filterPlaceholder ?? "Placeholder"}
218
+ placeholder={props.filterPlaceholder ?? "Filter..."}
219
219
  data-testid={"filteredMenu-free-text-input"}
220
220
  defaultValue={filter}
221
221
  data-allowtabtosave={true}
@@ -237,7 +237,11 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormPop
237
237
  <ComponentLoadingWrapper loading={!options} className={"GridFormDropDown-options"}>
238
238
  <>
239
239
  {options && (isEmpty(options) || (filteredValues && isEmpty(filteredValues))) && (
240
- <MenuItem key={`${fieldToString(field)}-empty`} className={"GridPopoverEditDropDown-noOptions"}>
240
+ <MenuItem
241
+ key={`${fieldToString(field)}-empty`}
242
+ className={"GridPopoverEditDropDown-noOptions"}
243
+ disabled={true}
244
+ >
241
245
  {props.noOptionsMessage ?? "No Options"}
242
246
  </MenuItem>
243
247
  )}
@@ -56,7 +56,7 @@ export const GridFormEditBearing = <RowType extends GridBaseRow>(props: GridForm
56
56
  });
57
57
 
58
58
  return popoverWrapper(
59
- <div className={"GridFormEditBearing-input Grid-popoverContainer"}>
59
+ <div className={"GridFormEditBearing-input"}>
60
60
  <TextInputFormatted
61
61
  value={defaultValue}
62
62
  onChange={(e) => {
@@ -52,6 +52,7 @@ export interface GridFormMultiSelectProps<RowType extends GridBaseRow> extends C
52
52
  filtered?: boolean;
53
53
  filterPlaceholder?: string;
54
54
  filterHelpText?: string | ((filter: string, options: MultiSelectOption[]) => string | undefined);
55
+ noOptionsMessage?: string;
55
56
  onSelectFilter?: (props: { filter: string; options: MultiSelectOption[] }) => void;
56
57
  onSave?: (props: { selectedRows: RowType[]; selectedOptions: MultiSelectOption[] }) => Promise<boolean>;
57
58
  headers?: GridFormMultiSelectGroup[];
@@ -117,7 +118,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow>(props: GridForm
117
118
  const headerGroups = useMemo(() => {
118
119
  if (!options) return undefined;
119
120
  const result = groupBy(
120
- options.filter((o) => textMatch(o.label, filter) && o.value),
121
+ options.filter((o) => textMatch(o.label, filter) && o.value != null),
121
122
  "filter",
122
123
  );
123
124
  // remove leading/trailing/duplicate dividers
@@ -163,8 +164,12 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow>(props: GridForm
163
164
  filterPlaceholder={props.filterPlaceholder}
164
165
  />
165
166
  )}
166
-
167
- {headerGroups && (
167
+ {headerGroups && (isEmpty(headerGroups) || !toPairs(headerGroups).some(([_, options]) => !isEmpty(options))) && (
168
+ <MenuItem key={"noOptions"} className={"GridMultiSelect-noOptions"} disabled={true}>
169
+ {props.noOptionsMessage ?? "No Options"}
170
+ </MenuItem>
171
+ )}
172
+ {headerGroups && !isEmpty(headerGroups) && (
168
173
  <div className={"GridFormMultiSelect-options"}>
169
174
  {headers.map((header, index) => {
170
175
  const subOptions = headerGroups[`${header.filter}`];
@@ -307,7 +312,7 @@ const FilterInput = (props: {
307
312
  <input
308
313
  className={"LuiTextInput-input"}
309
314
  type="text"
310
- placeholder={filterPlaceholder ?? "Placeholder"}
315
+ placeholder={filterPlaceholder ?? "Filter..."}
311
316
  data-testid={"filteredMenu-free-text-input"}
312
317
  value={filter}
313
318
  data-disableenterautosave={true}
@@ -328,9 +333,6 @@ const FilterInput = (props: {
328
333
  )}
329
334
  </FocusableItem>
330
335
  <MenuDivider key={`$$divider_filter`} />
331
- {headerGroups && !toPairs(headerGroups).some(([_, options]) => !isEmpty(options)) && (
332
- <div className={"szh-menu__item GridPopoverEditDropDown-noOptions"}>No Options</div>
333
- )}
334
336
  </>
335
337
  );
336
338
  };
@@ -365,7 +367,7 @@ const MenuRadioItem = (props: {
365
367
  value={`${item.value}`}
366
368
  label={
367
369
  <>
368
- {item.warning && <GridIcon icon={"ic_warning"} title={item.warning} />}
370
+ {item.warning && <GridIcon icon={"ic_warning_outline"} title={item.warning} />}
369
371
  {item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)}
370
372
  </>
371
373
  }
@@ -1,4 +1,9 @@
1
- import { bearingCorrectionValueFormatter, bearingValueFormatter } from "../../utils/bearing";
1
+ import {
2
+ bearingCorrectionRangeValidator,
3
+ bearingCorrectionValueFormatter,
4
+ bearingRangeValidator,
5
+ bearingValueFormatter,
6
+ } from "../../utils/bearing";
2
7
  import { ColDefT, GenericCellEditorProps, GridCell } from "../GridCell";
3
8
  import { GridFormEditBearing, GridFormEditBearingProps } from "../gridForm/GridFormEditBearing";
4
9
  import { GridBaseRow } from "../Grid";
@@ -27,12 +32,7 @@ const GridPopoverEditBearingLike = <RowType extends GridBaseRow>(
27
32
  export const GridPopoverEditBearingEditorParams = {
28
33
  placeHolder: "Enter bearing",
29
34
  formatValue: bearingValueFormatter,
30
- range: (value: number | null) => {
31
- if (value === null) return "Bearing is required";
32
- if (value >= 360) return "Bearing must be less than 360 degrees";
33
- if (value < 0) return "Bearing must not be negative";
34
- return null;
35
- },
35
+ range: bearingRangeValidator,
36
36
  };
37
37
 
38
38
  export const GridPopoverEditBearing = <RowType extends GridBaseRow>(
@@ -50,12 +50,7 @@ export const GridPopoverEditBearing = <RowType extends GridBaseRow>(
50
50
  export const GridPopoverEditBearingCorrectionEditorParams = {
51
51
  placeHolder: "Enter bearing correction",
52
52
  formatValue: bearingCorrectionValueFormatter,
53
- range: (value: number | null) => {
54
- if (value === null) return "Bearing correction is required";
55
- if (value >= 360) return "Bearing correction must be less than 360 degrees";
56
- if (value <= -180) return "Bearing correction must be greater then -180 degrees";
57
- return null;
58
- },
53
+ range: bearingCorrectionRangeValidator,
59
54
  };
60
55
 
61
56
  export const GridPopoverEditBearingCorrection = <RowType extends GridBaseRow>(
@@ -1,11 +1,11 @@
1
1
  import { ColDefT, GenericCellEditorProps, GridCell } from "../GridCell";
2
2
  import { GridBaseRow } from "../Grid";
3
- import { GridFormDropDown, GridFormPopoutDropDownProps } from "../gridForm/GridFormDropDown";
3
+ import { GridFormDropDown, GridFormDropDownProps } from "../gridForm/GridFormDropDown";
4
4
  import { GenericCellColDef } from "../gridRender/GridRenderGenericCell";
5
5
 
6
6
  export const GridPopoverEditDropDown = <RowType extends GridBaseRow>(
7
7
  colDef: GenericCellColDef<RowType>,
8
- props: GenericCellEditorProps<GridFormPopoutDropDownProps<RowType>>,
8
+ props: GenericCellEditorProps<GridFormDropDownProps<RowType>>,
9
9
  ): ColDefT<RowType> =>
10
10
  GridCell(colDef, {
11
11
  editor: GridFormDropDown,
@@ -13,6 +13,6 @@ export const GridPopoverEditDropDown = <RowType extends GridBaseRow>(
13
13
  editorParams: {
14
14
  // Defaults to large size container
15
15
  className: "GridPopoverEditDropDown-containerLarge",
16
- ...(props.editorParams as GridFormPopoutDropDownProps<RowType>),
16
+ ...(props.editorParams as GridFormDropDownProps<RowType>),
17
17
  },
18
18
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  $color: #212529;
4
4
  $color-dark: #cad1d8;
5
- $color-disabled: #aaa;
5
+ $color-disabled: #989189;
6
6
  $color-disabled-dark: #666;
7
7
 
8
8
  $header-color: #888;
@@ -2,11 +2,7 @@ import "@linzjs/lui/dist/scss/base.scss";
2
2
  import "@linzjs/lui/dist/fonts";
3
3
 
4
4
  import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
5
- import {
6
- GridFormDropDown,
7
- GridFormPopoutDropDownProps,
8
- MenuHeaderItem,
9
- } from "../../../components/gridForm/GridFormDropDown";
5
+ import { GridFormDropDown, GridFormDropDownProps, MenuHeaderItem } from "../../../components/gridForm/GridFormDropDown";
10
6
  import { GridContextProvider } from "../../../contexts/GridContextProvider";
11
7
  import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
12
8
  import { useRef } from "react";
@@ -19,7 +15,7 @@ export default {
19
15
  } as ComponentMeta<typeof GridFormDropDown>;
20
16
 
21
17
  const Template: ComponentStory<typeof GridFormDropDown> = (props) => {
22
- const configs: [string, GridFormPopoutDropDownProps<GridBaseRow>, string?][] = [
18
+ const configs: [string, GridFormDropDownProps<GridBaseRow>, string?][] = [
23
19
  ["No options", { options: [] }],
24
20
  ["Custom no options", { options: [], noOptionsMessage: "Custom no options" }],
25
21
  [
@@ -2,7 +2,7 @@ import "@linzjs/lui/dist/scss/base.scss";
2
2
  import "@linzjs/lui/dist/fonts";
3
3
 
4
4
  import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
5
- import { GridFormEditBearing } from "../../../components/gridForm/GridFormEditBearing";
5
+ import { GridFormEditBearing, GridFormEditBearingProps } from "../../../components/gridForm/GridFormEditBearing";
6
6
  import { GridContextProvider } from "../../../contexts/GridContextProvider";
7
7
  import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
8
8
  import { useRef } from "react";
@@ -15,14 +15,11 @@ export default {
15
15
  } as ComponentMeta<typeof GridFormEditBearing>;
16
16
 
17
17
  const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
18
- const values = [
19
- ["Null value", null],
20
- ["Minimum value", 0],
21
- ["Maximum value", 359.59599],
22
- ["5dp value", 1.23456],
23
- ["Invalid 6dp value", 1.234567],
24
- ["Invalid exceeds max value", 360],
25
- ["Invalid exceeds min value", -0.00001],
18
+ const values: [string, GridFormEditBearingProps<any>, number | null][] = [
19
+ ["Null value", {}, null],
20
+ ["Custom placeholder", { placeHolder: "Custom placeholder" }, null],
21
+ ["Valid value", {}, 90],
22
+ ["With error", {}, 1.234567],
26
23
  ];
27
24
  // eslint-disable-next-line react-hooks/rules-of-hooks
28
25
  const anchorRefs = values.map(() => useRef<HTMLHeadingElement>(null));
@@ -37,11 +34,11 @@ const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
37
34
  value={
38
35
  {
39
36
  anchorRef: anchorRefs[index],
40
- value: value[1],
37
+ value: value[2],
41
38
  } as any as GridPopoverContextType<any>
42
39
  }
43
40
  >
44
- <GridFormEditBearing {...props} {...GridPopoverEditBearingEditorParams} />
41
+ <GridFormEditBearing {...props} {...GridPopoverEditBearingEditorParams} {...value[1]} />
45
42
  </GridPopoverContext.Provider>
46
43
  </>
47
44
  ))}
@@ -51,4 +48,3 @@ const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
51
48
  };
52
49
 
53
50
  export const GridFormEditBearing_ = Template.bind({});
54
- GridFormEditBearing_.args = {};
@@ -2,7 +2,7 @@ import "@linzjs/lui/dist/scss/base.scss";
2
2
  import "@linzjs/lui/dist/fonts";
3
3
 
4
4
  import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
5
- import { GridFormEditBearing } from "../../../components/gridForm/GridFormEditBearing";
5
+ import { GridFormEditBearing, GridFormEditBearingProps } from "../../../components/gridForm/GridFormEditBearing";
6
6
  import { GridContextProvider } from "../../../contexts/GridContextProvider";
7
7
  import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
8
8
  import { useRef } from "react";
@@ -15,14 +15,11 @@ export default {
15
15
  } as ComponentMeta<typeof GridFormEditBearing>;
16
16
 
17
17
  const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
18
- const values = [
19
- ["Null value", null],
20
- ["Minimum value", -179.59599],
21
- ["Maximum value", 359.59599],
22
- ["5dp value", 1.23456],
23
- ["Invalid 6dp value", 1.234567],
24
- ["Invalid exceeds max value", 360],
25
- ["Invalid exceeds min value", -180],
18
+ const values: [string, GridFormEditBearingProps<any>, number | null][] = [
19
+ ["Null value", {}, null],
20
+ ["Custom placeholder", { placeHolder: "Custom placeholder" }, null],
21
+ ["Valid value", {}, -10],
22
+ ["With error", {}, 360],
26
23
  ];
27
24
  // eslint-disable-next-line react-hooks/rules-of-hooks
28
25
  const anchorRefs = values.map(() => useRef<HTMLHeadingElement>(null));
@@ -37,11 +34,11 @@ const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
37
34
  value={
38
35
  {
39
36
  anchorRef: anchorRefs[index],
40
- value: value[1],
37
+ value: value[2],
41
38
  } as any as GridPopoverContextType<any>
42
39
  }
43
40
  >
44
- <GridFormEditBearing {...props} {...GridPopoverEditBearingCorrectionEditorParams} />
41
+ <GridFormEditBearing {...props} {...GridPopoverEditBearingCorrectionEditorParams} {...value[1]} />
45
42
  </GridPopoverContext.Provider>
46
43
  </>
47
44
  ))}
@@ -51,4 +48,3 @@ const Template: ComponentStory<typeof GridFormEditBearing> = (props) => {
51
48
  };
52
49
 
53
50
  export const GridFormEditBearingCorrection_ = Template.bind({});
54
- GridFormEditBearingCorrection_.args = {};
@@ -29,4 +29,3 @@ const Template: ComponentStory<typeof GridFormMessage> = (props) => {
29
29
  };
30
30
 
31
31
  export const GridFormMessage_ = Template.bind({});
32
- GridFormMessage_.args = {};
@@ -0,0 +1,70 @@
1
+ import "@linzjs/lui/dist/scss/base.scss";
2
+ import "@linzjs/lui/dist/fonts";
3
+
4
+ import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
5
+ import { GridFormMultiSelect, GridFormMultiSelectProps } from "../../../components/gridForm/GridFormMultiSelect";
6
+ import { GridContextProvider } from "../../../contexts/GridContextProvider";
7
+ import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
8
+ import { useRef } from "react";
9
+ import { GridBaseRow } from "../../../components/Grid";
10
+
11
+ export default {
12
+ title: "GridForm / Testing",
13
+ component: GridFormMultiSelect,
14
+ args: {},
15
+ } as ComponentMeta<typeof GridFormMultiSelect>;
16
+
17
+ const Template: ComponentStory<typeof GridFormMultiSelect> = (props) => {
18
+ const configs: [string, GridFormMultiSelectProps<GridBaseRow>, string?][] = [
19
+ ["No options", { options: [] }],
20
+ ["Custom no options", { options: [], noOptionsMessage: "Custom no options" }],
21
+ [
22
+ "With options",
23
+ {
24
+ options: [
25
+ { label: "One", value: 0 },
26
+ { label: "Two", value: 1 },
27
+ ],
28
+ },
29
+ ],
30
+ [
31
+ "With filter",
32
+ {
33
+ filtered: true,
34
+ options: [
35
+ { label: "One", value: 0 },
36
+ { label: "With warning", value: 1, warning: "Test warning" },
37
+ { label: "Three", value: 2 },
38
+ ],
39
+ },
40
+ ],
41
+ ];
42
+ // eslint-disable-next-line react-hooks/rules-of-hooks
43
+ const anchorRefs = configs.map(() => useRef<HTMLHeadingElement>(null));
44
+
45
+ return (
46
+ <div className={"react-menu-inline-test"}>
47
+ <GridContextProvider>
48
+ {configs.map((config, index) => (
49
+ <div key={`${index}`}>
50
+ <h6 ref={anchorRefs[index]}>{config[0]}</h6>
51
+ <GridPopoverContext.Provider
52
+ value={
53
+ {
54
+ anchorRef: anchorRefs[index],
55
+ data: { value: config[2] },
56
+ value: config[2],
57
+ field: "value",
58
+ } as any as GridPopoverContextType<any>
59
+ }
60
+ >
61
+ <GridFormMultiSelect {...props} {...config[1]} />
62
+ </GridPopoverContext.Provider>
63
+ </div>
64
+ ))}
65
+ </GridContextProvider>
66
+ </div>
67
+ );
68
+ };
69
+
70
+ export const GridFormMultiSelect_ = Template.bind({});
@@ -0,0 +1,44 @@
1
+ import "@linzjs/lui/dist/scss/base.scss";
2
+ import "@linzjs/lui/dist/fonts";
3
+
4
+ import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
5
+ import { GridFormTextArea, GridFormTextAreaProps } from "../../../components/gridForm/GridFormTextArea";
6
+ import { GridContextProvider } from "../../../contexts/GridContextProvider";
7
+ import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
8
+ import { useRef } from "react";
9
+ import { GridBaseRow } from "../../../components/Grid";
10
+
11
+ export default {
12
+ title: "GridForm / Testing",
13
+ component: GridFormTextArea,
14
+ args: {},
15
+ } as ComponentMeta<typeof GridFormTextArea>;
16
+
17
+ const Template: ComponentStory<typeof GridFormTextArea> = (props) => {
18
+ const configs: [string, GridFormTextAreaProps<GridBaseRow>, string?][] = [
19
+ ["Text area", {}],
20
+ ["Text area with text", {}, "Some text"],
21
+ ["Text area with error & placeholder", { required: true, placeholder: "Custom placeholder" }],
22
+ ];
23
+ // eslint-disable-next-line react-hooks/rules-of-hooks
24
+ const anchorRefs = configs.map(() => useRef<HTMLHeadingElement>(null));
25
+
26
+ return (
27
+ <div className={"react-menu-inline-test"}>
28
+ <GridContextProvider>
29
+ {configs.map((config, index) => (
30
+ <>
31
+ <h6 ref={anchorRefs[index]}>{config[0]}</h6>
32
+ <GridPopoverContext.Provider
33
+ value={{ anchorRef: anchorRefs[index], value: config[2] } as any as GridPopoverContextType<any>}
34
+ >
35
+ <GridFormTextArea {...props} {...config[1]} />
36
+ </GridPopoverContext.Provider>
37
+ </>
38
+ ))}
39
+ </GridContextProvider>
40
+ </div>
41
+ );
42
+ };
43
+
44
+ export const GridFormTextArea_ = Template.bind({});
@@ -0,0 +1,44 @@
1
+ import "@linzjs/lui/dist/scss/base.scss";
2
+ import "@linzjs/lui/dist/fonts";
3
+
4
+ import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
5
+ import { GridFormTextInput, GridFormTextInputProps } from "../../../components/gridForm/GridFormTextInput";
6
+ import { GridContextProvider } from "../../../contexts/GridContextProvider";
7
+ import { GridPopoverContext, GridPopoverContextType } from "contexts/GridPopoverContext";
8
+ import { useRef } from "react";
9
+ import { GridBaseRow } from "../../../components/Grid";
10
+
11
+ export default {
12
+ title: "GridForm / Testing",
13
+ component: GridFormTextInput,
14
+ args: {},
15
+ } as ComponentMeta<typeof GridFormTextInput>;
16
+
17
+ const Template: ComponentStory<typeof GridFormTextInput> = (props) => {
18
+ const configs: [string, GridFormTextInputProps<GridBaseRow>, string?][] = [
19
+ ["Text input", {}],
20
+ ["Text input with text", {}, "Some text"],
21
+ ["Text input with error & placeholder", { required: true, placeholder: "Custom placeholder" }],
22
+ ];
23
+ // eslint-disable-next-line react-hooks/rules-of-hooks
24
+ const anchorRefs = configs.map(() => useRef<HTMLHeadingElement>(null));
25
+
26
+ return (
27
+ <div className={"react-menu-inline-test"}>
28
+ <GridContextProvider>
29
+ {configs.map((config, index) => (
30
+ <>
31
+ <h6 ref={anchorRefs[index]}>{config[0]}</h6>
32
+ <GridPopoverContext.Provider
33
+ value={{ anchorRef: anchorRefs[index], value: config[2] } as any as GridPopoverContextType<any>}
34
+ >
35
+ <GridFormTextInput {...props} {...config[1]} />
36
+ </GridPopoverContext.Provider>
37
+ </>
38
+ ))}
39
+ </GridContextProvider>
40
+ </div>
41
+ );
42
+ };
43
+
44
+ export const GridFormTextInput_ = Template.bind({});
@@ -32,7 +32,7 @@
32
32
  }
33
33
 
34
34
  .Grid-popoverContainer {
35
- padding: 4px 8px;
35
+ padding: 0.375rem 0.75rem;
36
36
  }
37
37
 
38
38
  .ag-cell .GridCell-editableIcon {
@@ -16,3 +16,7 @@
16
16
  .GridMultiSelect-containerUnlimited .GridFormMultiSelect-options {
17
17
  overflow-y: auto;
18
18
  }
19
+
20
+ .GridMultiSelect-noOptions {
21
+ justify-content: center;
22
+ }
@@ -9,11 +9,21 @@
9
9
  fill: colors.$info;
10
10
  }
11
11
 
12
+ .AgGridGenericCellRenderer-ic_info_outlineIcon {
13
+ margin-right: 4px;
14
+ fill: colors.$info;
15
+ }
16
+
12
17
  .AgGridGenericCellRenderer-ic_warningIcon {
13
18
  margin-right: 4px;
14
19
  fill: colors.$warning;
15
20
  }
16
21
 
22
+ .AgGridGenericCellRenderer-ic_warning_outlineIcon {
23
+ margin-right: 4px;
24
+ fill: colors.$warning;
25
+ }
26
+
17
27
  .GridIcon-disabled {
18
28
  fill: colors.$silver !important;
19
29
  }
@@ -23,7 +23,7 @@
23
23
 
24
24
  .szh-menu__item,
25
25
  .szh-menu__header {
26
- padding: 0.375rem 1.5rem;
26
+ padding: 0.375rem 0.75rem;
27
27
  }
28
28
 
29
29
  .LuiCheckboxInput {
@@ -9,13 +9,13 @@
9
9
  .step-ag-grid-react-menu.szh-menu {
10
10
  z-index: 900;
11
11
  color: colors.$base-type-color;
12
- @include fonts.font-light();
12
+ @include fonts.font-regular();
13
13
 
14
14
  div,
15
15
  a[role="menuitem"] {
16
16
  text-decoration: none;
17
17
  color: colors.$base-type-color;
18
- @include fonts.font-light();
18
+ @include fonts.font-regular();
19
19
  }
20
20
 
21
21
  li[role="menuitem"]:hover {
@@ -1,7 +1,12 @@
1
- import { convertDDToDMS } from "./bearing";
1
+ import {
2
+ bearingCorrectionRangeValidator,
3
+ bearingRangeValidator,
4
+ bearingStringValidator,
5
+ convertDDToDMS,
6
+ } from "./bearing";
2
7
 
3
- describe("convertDDToDMS", () => {
4
- test("converts decimal-ish degrees to DMS", () => {
8
+ describe("bearing", () => {
9
+ test("convertDDToDMS converts decimal-ish degrees to DMS", () => {
5
10
  expect(convertDDToDMS(-0.001, false, false)).toBe("-0° 00' 10\"");
6
11
  expect(convertDDToDMS(-10.001, false, false)).toBe("-10° 00' 10\"");
7
12
  expect(convertDDToDMS(-370.001, false, false)).toBe("-10° 00' 10\"");
@@ -27,4 +32,42 @@ describe("convertDDToDMS", () => {
27
32
  expect(convertDDToDMS(300.1, false, false)).toBe("300° 10'");
28
33
  expect(convertDDToDMS(0, false)).toBe("0° 00'");
29
34
  });
35
+
36
+ test("bearingStringValidator", () => {
37
+ const tests: [string, string | null][] = [
38
+ ["", null],
39
+ ["1", null],
40
+ ["1.2345", null],
41
+ ["-1.2345", null],
42
+ ["360.2345", null],
43
+ ["-360.2345", null],
44
+ ["1.2e6", "Bearing must be a number in D.MMSSS format"],
45
+ ["0.60000", "Bearing must be a number in D.MMSSS format"],
46
+ ["0.00600", "Bearing must be a number in D.MMSSS format"],
47
+ ["0.123456", "Bearing has a maximum of 5 decimal places"],
48
+ ];
49
+
50
+ tests.forEach((test, i) => {
51
+ expect(bearingStringValidator(test[0]), `Test ${i}: "${test[0]}" should return "${test[1]}"`).toBe(test[1]);
52
+ });
53
+
54
+ // calls custom invalid
55
+ const fn = jest.fn();
56
+ bearingStringValidator("1.2", fn);
57
+ expect(fn).toHaveBeenCalledWith(1.2);
58
+ });
59
+
60
+ test("bearingRangeValidator", () => {
61
+ expect(bearingRangeValidator(0)).toBeNull();
62
+ expect(bearingRangeValidator(359.595999)).toBeNull();
63
+ expect(bearingRangeValidator(-0.00001)).toBe("Bearing must not be negative");
64
+ expect(bearingRangeValidator(360)).toBe("Bearing must be less than 360 degrees");
65
+ });
66
+
67
+ test("bearingCorrectionRangeValidator", () => {
68
+ expect(bearingCorrectionRangeValidator(-179.59999)).toBeNull();
69
+ expect(bearingCorrectionRangeValidator(359.59999)).toBeNull();
70
+ expect(bearingCorrectionRangeValidator(-180)).toBe("Bearing correction must be greater then -180 degrees");
71
+ expect(bearingCorrectionRangeValidator(360)).toBe("Bearing correction must be less than 360 degrees");
72
+ });
30
73
  });
@@ -81,3 +81,17 @@ export const convertDDToDMS = (dd: number | null, showPositiveSymbol = true, add
81
81
 
82
82
  return dmsString;
83
83
  };
84
+
85
+ export const bearingRangeValidator = (value: number | null) => {
86
+ if (value === null) return "Bearing is required";
87
+ if (value >= 360) return "Bearing must be less than 360 degrees";
88
+ if (value < 0) return "Bearing must not be negative";
89
+ return null;
90
+ };
91
+
92
+ export const bearingCorrectionRangeValidator = (value: number | null) => {
93
+ if (value === null) return "Bearing correction is required";
94
+ if (value >= 360) return "Bearing correction must be less than 360 degrees";
95
+ if (value <= -180) return "Bearing correction must be greater then -180 degrees";
96
+ return null;
97
+ };