react-science 19.1.0 → 19.3.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 (197) hide show
  1. package/lib/components/accordion/accordion.js +1 -1
  2. package/lib/components/color-picker/react-color/ColorPicker.d.ts.map +1 -1
  3. package/lib/components/color-picker/react-color/ColorPicker.js +7 -5
  4. package/lib/components/color-picker/react-color/ColorPicker.js.map +1 -1
  5. package/lib/components/doi/doi.js +2 -2
  6. package/lib/components/doi/doi.js.map +1 -1
  7. package/lib/components/doi/doi_logo.d.ts +6 -0
  8. package/lib/components/doi/doi_logo.d.ts.map +1 -0
  9. package/lib/components/doi/doi_logo.js +16 -0
  10. package/lib/components/doi/doi_logo.js.map +1 -0
  11. package/lib/components/form/components/input/checkbox.d.ts +7 -0
  12. package/lib/components/form/components/input/checkbox.d.ts.map +1 -0
  13. package/lib/components/form/components/input/checkbox.js +26 -0
  14. package/lib/components/form/components/input/checkbox.js.map +1 -0
  15. package/lib/components/form/components/input/input.d.ts +7 -0
  16. package/lib/components/form/components/input/input.d.ts.map +1 -0
  17. package/lib/components/form/components/input/input.js +17 -0
  18. package/lib/components/form/components/input/input.js.map +1 -0
  19. package/lib/components/form/components/input/numeric_input.d.ts +9 -0
  20. package/lib/components/form/components/input/numeric_input.d.ts.map +1 -0
  21. package/lib/components/form/components/input/numeric_input.js +19 -0
  22. package/lib/components/form/components/input/numeric_input.js.map +1 -0
  23. package/lib/components/form/components/input/reset_button.d.ts +7 -0
  24. package/lib/components/form/components/input/reset_button.d.ts.map +1 -0
  25. package/lib/components/form/components/input/reset_button.js +9 -0
  26. package/lib/components/form/components/input/reset_button.js.map +1 -0
  27. package/lib/components/form/components/input/select.d.ts +11 -0
  28. package/lib/components/form/components/input/select.d.ts.map +1 -0
  29. package/lib/components/form/components/input/select.js +21 -0
  30. package/lib/components/form/components/input/select.js.map +1 -0
  31. package/lib/components/form/components/input/submit_button.d.ts +5 -0
  32. package/lib/components/form/components/input/submit_button.d.ts.map +1 -0
  33. package/lib/components/form/components/input/submit_button.js +11 -0
  34. package/lib/components/form/components/input/submit_button.js.map +1 -0
  35. package/lib/components/form/components/input/switch.d.ts +10 -0
  36. package/lib/components/form/components/input/switch.d.ts.map +1 -0
  37. package/lib/components/form/components/input/switch.js +24 -0
  38. package/lib/components/form/components/input/switch.js.map +1 -0
  39. package/lib/components/form/components/input_groups/form.d.ts +11 -0
  40. package/lib/components/form/components/input_groups/form.d.ts.map +1 -0
  41. package/lib/components/form/components/input_groups/form.js +17 -0
  42. package/lib/components/form/components/input_groups/form.js.map +1 -0
  43. package/lib/components/form/components/input_groups/form_group.d.ts +25 -0
  44. package/lib/components/form/components/input_groups/form_group.d.ts.map +1 -0
  45. package/lib/components/form/components/input_groups/form_group.js +45 -0
  46. package/lib/components/form/components/input_groups/form_group.js.map +1 -0
  47. package/lib/components/form/components/input_groups/select.d.ts +56 -0
  48. package/lib/components/form/components/input_groups/select.d.ts.map +1 -0
  49. package/lib/components/form/components/input_groups/select.js +26 -0
  50. package/lib/components/form/components/input_groups/select.js.map +1 -0
  51. package/lib/components/form/components/layout/Section.d.ts +9 -0
  52. package/lib/components/form/components/layout/Section.d.ts.map +1 -0
  53. package/lib/components/form/components/layout/Section.js +38 -0
  54. package/lib/components/form/components/layout/Section.js.map +1 -0
  55. package/lib/components/form/components/util/select.d.ts +20 -0
  56. package/lib/components/form/components/util/select.d.ts.map +1 -0
  57. package/lib/components/form/components/util/select.js +20 -0
  58. package/lib/components/form/components/util/select.js.map +1 -0
  59. package/lib/components/form/context/use_ts_form.d.ts +45 -0
  60. package/lib/components/form/context/use_ts_form.d.ts.map +1 -0
  61. package/lib/components/form/context/use_ts_form.js +29 -0
  62. package/lib/components/form/context/use_ts_form.js.map +1 -0
  63. package/lib/components/form/utils/use_field_id.d.ts +2 -0
  64. package/lib/components/form/utils/use_field_id.d.ts.map +1 -0
  65. package/lib/components/form/utils/use_field_id.js +5 -0
  66. package/lib/components/form/utils/use_field_id.js.map +1 -0
  67. package/lib/components/form/utils/use_intent.d.ts +3 -0
  68. package/lib/components/form/utils/use_intent.d.ts.map +1 -0
  69. package/lib/components/form/utils/use_intent.js +4 -0
  70. package/lib/components/form/utils/use_intent.js.map +1 -0
  71. package/lib/components/index.d.ts +3 -1
  72. package/lib/components/index.d.ts.map +1 -1
  73. package/lib/components/index.js +3 -1
  74. package/lib/components/index.js.map +1 -1
  75. package/lib/components/info-panel/InfoPanel.d.ts.map +1 -1
  76. package/lib/components/info-panel/InfoPanel.js +3 -3
  77. package/lib/components/info-panel/InfoPanel.js.map +1 -1
  78. package/lib/components/input/index.d.ts.map +1 -0
  79. package/lib/components/input/index.js.map +1 -0
  80. package/lib/components/{forms → input}/radio-button-group/RadioButton.d.ts.map +1 -1
  81. package/lib/components/{forms → input}/radio-button-group/RadioButton.js +4 -4
  82. package/lib/components/{forms → input}/radio-button-group/RadioButton.js.map +1 -1
  83. package/lib/components/{forms → input}/radio-button-group/RadioButtonGroup.d.ts.map +1 -1
  84. package/lib/components/{forms → input}/radio-button-group/RadioButtonGroup.js +2 -2
  85. package/lib/components/{forms → input}/radio-button-group/RadioButtonGroup.js.map +1 -1
  86. package/lib/components/{forms → input}/radio-button-group/index.d.ts.map +1 -1
  87. package/lib/components/input/radio-button-group/index.js.map +1 -0
  88. package/lib/components/input/styles.d.ts.map +1 -0
  89. package/lib/components/{forms → input}/styles.js.map +1 -1
  90. package/lib/components/{forms → input}/utils/SubText.d.ts.map +1 -1
  91. package/lib/components/{forms → input}/utils/SubText.js.map +1 -1
  92. package/lib/components/input/utils/index.d.ts.map +1 -0
  93. package/lib/components/input/utils/index.js.map +1 -0
  94. package/lib/components/{forms → input}/utils/use_input_id.d.ts.map +1 -1
  95. package/lib/components/{forms → input}/utils/use_input_id.js.map +1 -1
  96. package/lib/components/root-layout/css-reset/customPreflight.js +1 -1
  97. package/lib/components/split_pane/use_split_pane_size.d.ts.map +1 -1
  98. package/lib/components/split_pane/use_split_pane_size.js +47 -46
  99. package/lib/components/split_pane/use_split_pane_size.js.map +1 -1
  100. package/lib/components/svg/index.d.ts +5 -0
  101. package/lib/components/svg/index.d.ts.map +1 -0
  102. package/lib/components/svg/index.js +5 -0
  103. package/lib/components/svg/index.js.map +1 -0
  104. package/lib/components/svg/styled/svg_styled_line.d.ts +6 -0
  105. package/lib/components/svg/styled/svg_styled_line.d.ts.map +1 -0
  106. package/lib/components/svg/styled/svg_styled_line.js +7 -0
  107. package/lib/components/svg/styled/svg_styled_line.js.map +1 -0
  108. package/lib/components/svg/styled/svg_styled_path.d.ts +6 -0
  109. package/lib/components/svg/styled/svg_styled_path.d.ts.map +1 -0
  110. package/lib/components/svg/styled/svg_styled_path.js +7 -0
  111. package/lib/components/svg/styled/svg_styled_path.js.map +1 -0
  112. package/lib/components/svg/styled/svg_styled_text.d.ts +6 -0
  113. package/lib/components/svg/styled/svg_styled_text.d.ts.map +1 -0
  114. package/lib/components/svg/styled/svg_styled_text.js +6 -0
  115. package/lib/components/svg/styled/svg_styled_text.js.map +1 -0
  116. package/lib/components/svg/styled/svg_styled_types.d.ts +56 -0
  117. package/lib/components/svg/styled/svg_styled_types.d.ts.map +1 -0
  118. package/lib/components/svg/styled/svg_styled_types.js +2 -0
  119. package/lib/components/svg/styled/svg_styled_types.js.map +1 -0
  120. package/lib/components/svg/styled/svg_styled_utils.d.ts +3 -0
  121. package/lib/components/svg/styled/svg_styled_utils.d.ts.map +1 -0
  122. package/lib/components/svg/styled/svg_styled_utils.js +10 -0
  123. package/lib/components/svg/styled/svg_styled_utils.js.map +1 -0
  124. package/lib/components/table/reorder_rows/use_drop_monitor.d.ts.map +1 -1
  125. package/lib/components/table/reorder_rows/use_drop_monitor.js +33 -32
  126. package/lib/components/table/reorder_rows/use_drop_monitor.js.map +1 -1
  127. package/lib/components/toolbar/PanelPreferencesToolbar.js +1 -1
  128. package/lib/components/toolbar/Toolbar.d.ts.map +1 -1
  129. package/lib/components/toolbar/Toolbar.js +7 -5
  130. package/lib/components/toolbar/Toolbar.js.map +1 -1
  131. package/lib/components/toolbar/TooltipHelpContent.js +3 -3
  132. package/package.json +36 -33
  133. package/src/components/accordion/accordion.tsx +1 -1
  134. package/src/components/color-picker/react-color/ColorPicker.tsx +8 -6
  135. package/src/components/doi/doi.tsx +2 -2
  136. package/src/components/doi/{Logo.tsx → doi_logo.tsx} +9 -5
  137. package/src/components/form/components/input/checkbox.tsx +53 -0
  138. package/src/components/form/components/input/input.tsx +57 -0
  139. package/src/components/form/components/input/numeric_input.tsx +64 -0
  140. package/src/components/form/components/input/reset_button.tsx +19 -0
  141. package/src/components/form/components/input/select.tsx +54 -0
  142. package/src/components/form/components/input/submit_button.tsx +23 -0
  143. package/src/components/form/components/input/switch.tsx +55 -0
  144. package/src/components/form/components/input_groups/form.tsx +32 -0
  145. package/src/components/form/components/input_groups/form_group.tsx +126 -0
  146. package/src/components/form/components/input_groups/select.tsx +175 -0
  147. package/src/components/form/components/layout/Section.tsx +57 -0
  148. package/src/components/form/components/util/select.tsx +67 -0
  149. package/src/components/form/context/use_ts_form.ts +33 -0
  150. package/src/components/form/utils/use_field_id.ts +5 -0
  151. package/src/components/form/utils/use_intent.ts +5 -0
  152. package/src/components/index.ts +3 -1
  153. package/src/components/info-panel/InfoPanel.tsx +4 -3
  154. package/src/components/{forms → input}/radio-button-group/RadioButton.tsx +4 -4
  155. package/src/components/{forms → input}/radio-button-group/RadioButtonGroup.tsx +2 -2
  156. package/src/components/root-layout/css-reset/customPreflight.ts +1 -1
  157. package/src/components/split_pane/use_split_pane_size.tsx +54 -53
  158. package/src/components/svg/index.ts +4 -0
  159. package/src/components/svg/styled/svg_styled_line.tsx +27 -0
  160. package/src/components/svg/styled/svg_styled_path.tsx +29 -0
  161. package/src/components/svg/styled/svg_styled_text.tsx +12 -0
  162. package/src/components/svg/styled/svg_styled_types.ts +67 -0
  163. package/src/components/svg/styled/svg_styled_utils.ts +15 -0
  164. package/src/components/table/reorder_rows/use_drop_monitor.ts +41 -38
  165. package/src/components/toolbar/PanelPreferencesToolbar.tsx +1 -1
  166. package/src/components/toolbar/Toolbar.tsx +9 -5
  167. package/src/components/toolbar/TooltipHelpContent.tsx +3 -3
  168. package/lib/components/doi/Logo.d.ts +0 -6
  169. package/lib/components/doi/Logo.d.ts.map +0 -1
  170. package/lib/components/doi/Logo.js +0 -16
  171. package/lib/components/doi/Logo.js.map +0 -1
  172. package/lib/components/forms/index.d.ts.map +0 -1
  173. package/lib/components/forms/index.js.map +0 -1
  174. package/lib/components/forms/radio-button-group/index.js.map +0 -1
  175. package/lib/components/forms/styles.d.ts.map +0 -1
  176. package/lib/components/forms/utils/index.d.ts.map +0 -1
  177. package/lib/components/forms/utils/index.js.map +0 -1
  178. /package/lib/components/{forms → input}/index.d.ts +0 -0
  179. /package/lib/components/{forms → input}/index.js +0 -0
  180. /package/lib/components/{forms → input}/radio-button-group/RadioButton.d.ts +0 -0
  181. /package/lib/components/{forms → input}/radio-button-group/RadioButtonGroup.d.ts +0 -0
  182. /package/lib/components/{forms → input}/radio-button-group/index.d.ts +0 -0
  183. /package/lib/components/{forms → input}/radio-button-group/index.js +0 -0
  184. /package/lib/components/{forms → input}/styles.d.ts +0 -0
  185. /package/lib/components/{forms → input}/styles.js +0 -0
  186. /package/lib/components/{forms → input}/utils/SubText.d.ts +0 -0
  187. /package/lib/components/{forms → input}/utils/SubText.js +0 -0
  188. /package/lib/components/{forms → input}/utils/index.d.ts +0 -0
  189. /package/lib/components/{forms → input}/utils/index.js +0 -0
  190. /package/lib/components/{forms → input}/utils/use_input_id.d.ts +0 -0
  191. /package/lib/components/{forms → input}/utils/use_input_id.js +0 -0
  192. /package/src/components/{forms → input}/index.ts +0 -0
  193. /package/src/components/{forms → input}/radio-button-group/index.ts +0 -0
  194. /package/src/components/{forms → input}/styles.ts +0 -0
  195. /package/src/components/{forms → input}/utils/SubText.tsx +0 -0
  196. /package/src/components/{forms → input}/utils/index.ts +0 -0
  197. /package/src/components/{forms → input}/utils/use_input_id.ts +0 -0
@@ -0,0 +1,126 @@
1
+ import type { Intent } from '@blueprintjs/core';
2
+ import { Classes } from '@blueprintjs/core';
3
+ import styled from '@emotion/styled';
4
+ import type { ReactNode } from 'react';
5
+
6
+ import type { Layout } from './form.js';
7
+ import { useFormContext } from './form.js';
8
+
9
+ const INPUT_HEIGHT = 30;
10
+
11
+ const FormContainer = styled.div<{
12
+ layout?: Layout;
13
+ }>`
14
+ min-height: ${INPUT_HEIGHT}px;
15
+ width: 100%;
16
+ display: grid;
17
+ margin: 0;
18
+ grid-template-columns: ${(props) =>
19
+ props.layout === 'inline' ? '[label] 30% [input] 70%' : '1fr'};
20
+ grid-template-rows: ${(props) =>
21
+ props.layout === 'inline' ? 'auto auto' : 'auto'};
22
+ `;
23
+
24
+ const RequiredSpan = styled.span`
25
+ color: red;
26
+ `;
27
+
28
+ const ContainerElement = styled.div<{
29
+ height?: number | 'auto';
30
+ fullWidth?: boolean;
31
+ layout?: Layout;
32
+ }>`
33
+ display: inline-block;
34
+ grid-column: ${(props) =>
35
+ props.fullWidth
36
+ ? '1 / -1'
37
+ : props.layout === 'inline'
38
+ ? 'input'
39
+ : '1 / -1'};
40
+ height: ${(props) =>
41
+ props.height === 'auto' ? props.height : `${props.height}px`};
42
+ width: fit-content;
43
+ `;
44
+
45
+ const Label = styled.label<{ layout: Layout }>`
46
+ padding-top: calc(${INPUT_HEIGHT}px - 26px);
47
+ grid-column: ${(props) => (props.layout === 'inline' ? 'label' : '1 / -1')};
48
+ height: 30px;
49
+
50
+ @media (width < 48rem) {
51
+ padding: 0;
52
+ }
53
+ `;
54
+
55
+ const ErrorAndHelpText = styled.div`
56
+ display: flex;
57
+ flex-direction: column;
58
+ `;
59
+
60
+ export interface FormGroupInputProps {
61
+ label?: string;
62
+ required?: boolean;
63
+ placeholder?: string;
64
+ helpText?: string;
65
+ layout?: Layout;
66
+ fullWidth?: boolean;
67
+ }
68
+
69
+ interface FormGroupProps {
70
+ label?: string;
71
+ intent?: Intent;
72
+ name: string;
73
+ required?: boolean;
74
+ helpText?: string;
75
+ children?: ReactNode;
76
+ error?: string;
77
+ layout?: Layout;
78
+ fullWidth?: boolean;
79
+ }
80
+
81
+ export function FormGroup(props: FormGroupProps) {
82
+ const {
83
+ label,
84
+ intent,
85
+ name,
86
+ required,
87
+ children,
88
+ helpText,
89
+ error,
90
+ layout,
91
+ fullWidth = false,
92
+ } = props;
93
+
94
+ const { layout: formLayout } = useFormContext();
95
+
96
+ return (
97
+ <FormContainer
98
+ layout={layout || formLayout}
99
+ className={`${Classes.FORM_GROUP} ${Classes.intentClass(intent)}`}
100
+ >
101
+ {label && (
102
+ <Label
103
+ layout={layout || formLayout}
104
+ className={Classes.LABEL}
105
+ htmlFor={name}
106
+ >
107
+ {label}{' '}
108
+ {required && (
109
+ <RequiredSpan className={Classes.TEXT_MUTED}>*</RequiredSpan>
110
+ )}
111
+ </Label>
112
+ )}
113
+ <ContainerElement fullWidth={fullWidth} layout={layout || formLayout}>
114
+ {children}
115
+
116
+ <ErrorAndHelpText>
117
+ {helpText && (
118
+ <span className={Classes.FORM_HELPER_TEXT}>{helpText}</span>
119
+ )}
120
+
121
+ {error && <span className={Classes.FORM_HELPER_TEXT}>{error}</span>}
122
+ </ErrorAndHelpText>
123
+ </ContainerElement>
124
+ </FormContainer>
125
+ );
126
+ }
@@ -0,0 +1,175 @@
1
+ import type { FormGroup, FormGroupProps } from '@blueprintjs/core';
2
+ import type { SelectProps as BPSelectProps } from '@blueprintjs/select';
3
+ import { Select as BPSelect } from '@blueprintjs/select';
4
+ import type { ComponentProps, ReactElement, ReactNode } from 'react';
5
+ import { useCallback, useMemo } from 'react';
6
+
7
+ import { Button } from '../../../button/index.js';
8
+ import type {
9
+ GetOptionLabel,
10
+ GetOptionValue,
11
+ SelectId,
12
+ SelectOption,
13
+ SelectOptionLabel,
14
+ } from '../util/select.js';
15
+ import {
16
+ getItemRenderer,
17
+ getSelectLabel,
18
+ getSelectValue,
19
+ } from '../util/select.js';
20
+
21
+ type FieldGroupProps = Pick<FormGroupProps, 'label' | 'inline'>;
22
+
23
+ export interface SelectPropsRenderButtonState<OptionType> {
24
+ error: string | undefined;
25
+ selectedOption: OptionType | undefined;
26
+ }
27
+
28
+ interface SelectCustomProps<OptionType, ID extends SelectId> {
29
+ renderButton?: (state: SelectPropsRenderButtonState<OptionType>) => ReactNode;
30
+ onChange?: (selected: ID | undefined, option: OptionType | undefined) => void;
31
+ id?: string;
32
+ selected?: ID;
33
+
34
+ required?: boolean;
35
+ }
36
+
37
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
38
+ type SelectGetValue<OptionType, ID extends SelectId> = {
39
+ /**
40
+ * Optional if OptionType extends SelectOption<ID>
41
+ * @default getSelectValue
42
+ */
43
+ getValue: GetOptionValue<OptionType, ID>;
44
+ };
45
+
46
+ type SelectGetValueProps<OptionType, ID extends SelectId> =
47
+ OptionType extends SelectOption<ID>
48
+ ? Partial<SelectGetValue<OptionType, ID>>
49
+ : SelectGetValue<OptionType, ID>;
50
+
51
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
52
+ type SelectGetLabel<OptionType> = {
53
+ /**
54
+ * Optional if OptionType extends SelectOptionLabel
55
+ * @default getSelectLabel
56
+ */
57
+ getLabel: GetOptionLabel<OptionType>;
58
+ };
59
+
60
+ type SelectGetLabelProps<OptionType> = OptionType extends SelectOptionLabel
61
+ ? Partial<SelectGetLabel<OptionType>>
62
+ : SelectGetLabel<OptionType>;
63
+
64
+ export type SelectProps<OptionType, ID extends SelectId> = FieldGroupProps &
65
+ Pick<
66
+ BPSelectProps<OptionType>,
67
+ | 'placeholder'
68
+ | 'items'
69
+ | 'className'
70
+ | 'disabled'
71
+ | 'popoverProps'
72
+ | 'filterable'
73
+ | 'itemDisabled'
74
+ | 'itemListPredicate'
75
+ | 'resetOnClose'
76
+ > &
77
+ Pick<ComponentProps<typeof FormGroup>, 'helperText' | 'intent'> &
78
+ SelectCustomProps<OptionType, ID> &
79
+ SelectGetValueProps<OptionType, ID> &
80
+ SelectGetLabelProps<OptionType>;
81
+
82
+ /**
83
+ * A wrapper for the BlueprintJS Select component that integrates with react-hook-form.
84
+ * Store in form the selected value.
85
+ * Find selected option getValue.
86
+ * Display options with getLabel.
87
+ *
88
+ * @param props
89
+ * @constructor
90
+ */
91
+
92
+ interface RealSelectProps<OptionType, ID extends SelectId>
93
+ extends Pick<BPSelectProps<OptionType>, 'filterable' | 'items'> {
94
+ onBlur: () => void;
95
+ renderButton?: (
96
+ state: SelectPropsRenderButtonState<OptionType>,
97
+ onBlur: () => void,
98
+ ) => ReactNode;
99
+ disabled?: boolean;
100
+ selected?: ID;
101
+ onChange?: (selected: ID | undefined, option: OptionType | undefined) => void;
102
+ getLabel?: GetOptionLabel<OptionType>;
103
+ getValue?: GetOptionValue<OptionType, ID>;
104
+ intent?: FormGroupProps['intent'];
105
+ name?: string;
106
+ }
107
+
108
+ export function Select<
109
+ OptionType extends SelectOption<ID>,
110
+ ID extends SelectId,
111
+ >(props: RealSelectProps<OptionType, ID>): ReactElement {
112
+ const {
113
+ renderButton,
114
+ disabled,
115
+ selected,
116
+ getLabel: _getLabel,
117
+ getValue: _getValue,
118
+ intent,
119
+ // Weirdly, setting the filterable prop on BP's Select component activates the filter input
120
+ filterable = false,
121
+ items,
122
+ onChange,
123
+ onBlur,
124
+ name = null,
125
+ } = props;
126
+
127
+ const getValue: GetOptionValue<OptionType, ID> = _getValue ?? getSelectValue;
128
+ const getLabel: GetOptionLabel<OptionType> = _getLabel ?? getSelectLabel;
129
+
130
+ const selectedOption = useMemo(
131
+ () => items.find((item) => getValue(item) === selected),
132
+ [getValue, items, selected],
133
+ );
134
+
135
+ const itemRenderer = useMemo(() => {
136
+ return getItemRenderer<OptionType, ID>({
137
+ selected,
138
+ getValue,
139
+ getLabel,
140
+ });
141
+ }, [getLabel, getValue, selected]);
142
+
143
+ const onItemSelect = useCallback(
144
+ (option: OptionType | undefined) => {
145
+ const value = getValue(option);
146
+ onChange?.(value, option);
147
+ },
148
+ [getValue, onChange],
149
+ );
150
+
151
+ return (
152
+ <BPSelect<OptionType>
153
+ filterable={filterable}
154
+ items={items}
155
+ onItemSelect={onItemSelect}
156
+ itemRenderer={itemRenderer}
157
+ disabled={disabled}
158
+ >
159
+ {renderButton ? (
160
+ renderButton({ selectedOption, error: undefined }, onBlur)
161
+ ) : (
162
+ <Button
163
+ id={name || undefined}
164
+ text={getLabel(selectedOption) || 'Select ...'}
165
+ endIcon="double-caret-vertical"
166
+ variant="outlined"
167
+ intent={intent}
168
+ disabled={disabled}
169
+ style={{ minWidth: 180 }}
170
+ onBlur={onBlur}
171
+ />
172
+ )}
173
+ </BPSelect>
174
+ );
175
+ }
@@ -0,0 +1,57 @@
1
+ import styled from '@emotion/styled';
2
+ import type { ReactNode } from 'react';
3
+
4
+ const ContainerInformation = styled.div`
5
+ display: flex;
6
+ flex-direction: column;
7
+
8
+ > h2 {
9
+ font-weight: 600;
10
+ font-size: 1rem;
11
+ line-height: 1.75rem;
12
+ }
13
+
14
+ > h3 {
15
+ color: #737373;
16
+ font-size: 0.875rem;
17
+ line-height: 1.5rem;
18
+ }
19
+ `;
20
+
21
+ const Container = styled.div`
22
+ margin-top: 15px;
23
+ gap: 5px;
24
+ display: flex;
25
+ flex-direction: column;
26
+ `;
27
+
28
+ const ContainerContent = styled.div`
29
+ outline: 1px solid rgb(17 24 39 / 5%);
30
+ box-shadow: 0 1px 2px 0 rgb(0 0 0 / 5%);
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: 2px;
34
+ border-radius: 0.75rem;
35
+ padding: 7px 10px 2px;
36
+ `;
37
+
38
+ interface SectionProps {
39
+ title: string;
40
+ description?: string;
41
+ children: ReactNode;
42
+ }
43
+
44
+ export function Section(props: SectionProps) {
45
+ const { title, description, children } = props;
46
+
47
+ return (
48
+ <Container>
49
+ <ContainerInformation>
50
+ <h2>{title}</h2>
51
+ <h3>{description}</h3>
52
+ </ContainerInformation>
53
+
54
+ <ContainerContent>{children}</ContainerContent>
55
+ </Container>
56
+ );
57
+ }
@@ -0,0 +1,67 @@
1
+ import { MenuItem } from '@blueprintjs/core';
2
+ import type { ItemRenderer } from '@blueprintjs/select';
3
+ import type { ReactNode } from 'react';
4
+
5
+ export type SelectId = string | number | null;
6
+
7
+ export type GetOptionValue<OptionType, ID extends SelectId> = (
8
+ option: OptionType | undefined,
9
+ ) => ID | undefined;
10
+ export type GetOptionLabel<OptionType> = (
11
+ option: OptionType | undefined,
12
+ ) => ReactNode;
13
+
14
+ export interface GetItemRendererOptions<OptionType, ID extends SelectId> {
15
+ selected: ID | undefined;
16
+ getValue: GetOptionValue<OptionType, ID>;
17
+ getLabel: GetOptionLabel<OptionType>;
18
+ }
19
+
20
+ export function getItemRenderer<OptionType, ID extends SelectId>(
21
+ options: GetItemRendererOptions<OptionType, ID>,
22
+ ) {
23
+ const { selected, getValue, getLabel } = options;
24
+
25
+ const render: ItemRenderer<OptionType> = (
26
+ item,
27
+ { handleClick, handleFocus, modifiers, index },
28
+ ) => {
29
+ const label = getLabel(item);
30
+ const { active, disabled, matchesPredicate } = modifiers;
31
+ if (!matchesPredicate) return null;
32
+ return (
33
+ <MenuItem
34
+ active={active}
35
+ disabled={disabled}
36
+ selected={selected === getValue(item)}
37
+ key={index}
38
+ onClick={handleClick}
39
+ onFocus={handleFocus}
40
+ roleStructure="listoption"
41
+ text={label}
42
+ />
43
+ );
44
+ };
45
+
46
+ return render;
47
+ }
48
+
49
+ export interface SelectOptionLabel {
50
+ label: string;
51
+ }
52
+
53
+ export function getSelectLabel(
54
+ option: SelectOptionLabel | undefined,
55
+ ): string | undefined {
56
+ return option?.label;
57
+ }
58
+
59
+ export interface SelectOption<ID> extends SelectOptionLabel {
60
+ value: ID;
61
+ }
62
+
63
+ export function getSelectValue<Option extends SelectOption<unknown>>(
64
+ option: Option | undefined,
65
+ ): Option['value'] | undefined {
66
+ return option?.value;
67
+ }
@@ -0,0 +1,33 @@
1
+ import { createFormHook, createFormHookContexts } from '@tanstack/react-form';
2
+
3
+ import { Checkbox } from '../components/input/checkbox.js';
4
+ import { Input } from '../components/input/input.js';
5
+ import { NumericInput } from '../components/input/numeric_input.js';
6
+ import { ResetButton } from '../components/input/reset_button.js';
7
+ import { Select } from '../components/input/select.js';
8
+ import { SubmitButton } from '../components/input/submit_button.js';
9
+ import { Switch } from '../components/input/switch.js';
10
+ import { Section } from '../components/layout/Section.js';
11
+
12
+ const { useFormContext, useFieldContext, formContext, fieldContext } =
13
+ createFormHookContexts();
14
+
15
+ const { useAppForm, withForm } = createFormHook({
16
+ fieldContext,
17
+ formContext,
18
+ formComponents: {
19
+ SubmitButton,
20
+ ResetButton,
21
+ Section,
22
+ },
23
+ fieldComponents: {
24
+ Input,
25
+ NumericInput,
26
+ Checkbox,
27
+ Select,
28
+ Switch,
29
+ },
30
+ });
31
+
32
+ export const useForm = useAppForm;
33
+ export { useFieldContext, useFormContext, withForm };
@@ -0,0 +1,5 @@
1
+ import { useId } from 'react';
2
+
3
+ export function useFieldId(fieldName: string) {
4
+ return `input-${fieldName}-${useId()}`;
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { Intent } from '@blueprintjs/core';
2
+
3
+ export function getIntent(error?: string): Intent | undefined {
4
+ return error !== undefined ? 'danger' : undefined;
5
+ }
@@ -4,7 +4,7 @@ export * from './color-picker/index.js';
4
4
  export * from './dialog/index.js';
5
5
  export * from './doi/index.js';
6
6
  export * from './drop-zone/index.js';
7
- export * from './forms/index.js';
7
+ export * from './input/index.js';
8
8
  export * from './fullscreen/index.js';
9
9
  export * from './header/index.js';
10
10
  export * from './hooks/index.js';
@@ -14,8 +14,10 @@ export * from './root-layout/index.js';
14
14
  export * from './split_pane/index.js';
15
15
  export * from './table/index.js';
16
16
  export * from './toolbar/index.js';
17
+ export * from './form/context/use_ts_form.js';
17
18
  export * from './activity_bar/index.js';
18
19
  export * from './activity_panel/index.js';
19
20
  export * from './utils/index.js';
20
21
  export * from './selected-total/index.js';
22
+ export * from './svg/index.js';
21
23
  export * as ValueRenderers from './value-renderers/index.js';
@@ -110,9 +110,10 @@ export function InfoPanel(props: InfoPanelProps) {
110
110
  const includes: InfoPanelDatum[] = [];
111
111
  const valueContains: InfoPanelDatum[] = [];
112
112
 
113
- for (const [parameter, value] of Object.entries(data).sort(([a], [b]) => {
114
- return a.localeCompare(b);
115
- })) {
113
+ const sortedDataEntries = Object.entries(data);
114
+ sortedDataEntries.sort(([a], [b]) => a.localeCompare(b));
115
+
116
+ for (const [parameter, value] of sortedDataEntries) {
116
117
  const lowerKey = parameter.toLowerCase();
117
118
  const lowerSearch = search.toLowerCase();
118
119
  if (lowerKey === lowerSearch) {
@@ -12,12 +12,12 @@ const HiddenInput = styled.input`
12
12
  padding: 0;
13
13
  margin: -1px;
14
14
  overflow: hidden;
15
- clip: rect(0, 0, 0, 0);
15
+ clip-path: inset(50%);
16
16
  white-space: nowrap;
17
17
  border-width: 0;
18
18
 
19
19
  /* Label associated with the checked input. */
20
- &:checked + label {
20
+ :checked + label {
21
21
  color: ${enabledColor};
22
22
  border-color: ${enabledColor};
23
23
  opacity: ${(props) => (props.disabled ? 0.25 : 1)};
@@ -25,7 +25,7 @@ const HiddenInput = styled.input`
25
25
  }
26
26
 
27
27
  /* Next label after the one that is checked. */
28
- &:checked + label + input + label {
28
+ :checked + label + input + label {
29
29
  border-left-width: 0;
30
30
  }
31
31
  `;
@@ -46,7 +46,7 @@ const Label = styled.label<{ size?: RadioProps['size']; disabled?: boolean }>`
46
46
  cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
47
47
  white-space: nowrap;
48
48
 
49
- &:hover {
49
+ :hover {
50
50
  color: ${enabledColor};
51
51
  }
52
52
  `;
@@ -12,14 +12,14 @@ export interface RadioButtonGroupProps extends RadioGroupProps {
12
12
  const RadioButtonContainer = styled.div<{ size?: RadioProps['size'] }>`
13
13
  display: flex;
14
14
 
15
- & label:first-of-type {
15
+ label:first-of-type {
16
16
  border-bottom-left-radius: ${(props) =>
17
17
  props.size === 'large' ? '6px' : '4px'};
18
18
  border-top-left-radius: ${(props) =>
19
19
  props.size === 'large' ? '6px' : '4px'};
20
20
  }
21
21
 
22
- & label:last-of-type {
22
+ label:last-of-type {
23
23
  border-right-width: 1px;
24
24
  border-bottom-right-radius: ${(props) =>
25
25
  props.size === 'large' ? '6px' : '4px'};
@@ -25,7 +25,7 @@ export const CustomDivPreflight = styled.div`
25
25
  height: 100%;
26
26
  position: relative;
27
27
 
28
- &:fullscreen::backdrop,
28
+ :fullscreen::backdrop,
29
29
  *:fullscreen::backdrop {
30
30
  /* Override user agent default */
31
31
  background-color: white;
@@ -42,63 +42,64 @@ export function useSplitPaneSize(options: UseSplitPaneSizeOptions) {
42
42
  }, [onResize, onSizeChange]);
43
43
 
44
44
  useEffect(() => {
45
- if (isResizing) {
46
- let lastSize: ParsedSplitPaneSize | null = null;
47
- function moveCallback(event: PointerEvent) {
48
- if (!splitterRef.current) return;
49
- const { clientX, clientY } = event;
50
- const parentDiv = splitterRef.current.parentElement as HTMLDivElement;
51
- const bounds = parentDiv.getBoundingClientRect();
52
- const parentDimension =
53
- direction === 'horizontal'
54
- ? parentDiv.clientWidth
55
- : parentDiv.clientHeight;
56
-
57
- const client =
58
- direction === 'horizontal'
59
- ? clientX - bounds.left
60
- : clientY - bounds.top;
61
-
62
- const centralizingValue =
63
- direction === 'horizontal'
64
- ? splitterRef.current.clientWidth / 2
65
- : splitterRef.current.clientHeight / 2;
66
-
67
- const value =
68
- controlledSide === 'start' ? client : parentDimension - client;
69
-
70
- if (sizeType === 'px') {
71
- const newSize = getValueFromSplitter(value - centralizingValue, {
72
- min: 0,
73
- max: parentDimension,
74
- });
75
- lastSize = { value: newSize, type: sizeType };
76
- onSizeChangeRef.current?.(lastSize);
77
- } else if (sizeType === '%') {
78
- const valueDiff = (value / parentDimension) * 100;
79
- const newSize = getValueFromSplitter(valueDiff, {
80
- min: 0,
81
- max: 100,
82
- });
83
- lastSize = { value: newSize, type: sizeType };
84
- onSizeChangeRef.current?.(lastSize);
85
- }
45
+ if (!isResizing) {
46
+ return;
47
+ }
48
+ let lastSize: ParsedSplitPaneSize | null = null;
49
+ function moveCallback(event: PointerEvent) {
50
+ if (!splitterRef.current) return;
51
+ const { clientX, clientY } = event;
52
+ const parentDiv = splitterRef.current.parentElement as HTMLDivElement;
53
+ const bounds = parentDiv.getBoundingClientRect();
54
+ const parentDimension =
55
+ direction === 'horizontal'
56
+ ? parentDiv.clientWidth
57
+ : parentDiv.clientHeight;
58
+
59
+ const client =
60
+ direction === 'horizontal'
61
+ ? clientX - bounds.left
62
+ : clientY - bounds.top;
63
+
64
+ const centralizingValue =
65
+ direction === 'horizontal'
66
+ ? splitterRef.current.clientWidth / 2
67
+ : splitterRef.current.clientHeight / 2;
68
+
69
+ const value =
70
+ controlledSide === 'start' ? client : parentDimension - client;
71
+
72
+ if (sizeType === 'px') {
73
+ const newSize = getValueFromSplitter(value - centralizingValue, {
74
+ min: 0,
75
+ max: parentDimension,
76
+ });
77
+ lastSize = { value: newSize, type: sizeType };
78
+ onSizeChangeRef.current?.(lastSize);
79
+ } else if (sizeType === '%') {
80
+ const valueDiff = (value / parentDimension) * 100;
81
+ const newSize = getValueFromSplitter(valueDiff, {
82
+ min: 0,
83
+ max: 100,
84
+ });
85
+ lastSize = { value: newSize, type: sizeType };
86
+ onSizeChangeRef.current?.(lastSize);
86
87
  }
87
- function upCallback() {
88
- setIsResizing(false);
89
- if (lastSize) {
90
- onResizeRef.current?.(serializeSize(lastSize));
91
- }
88
+ }
89
+ function upCallback() {
90
+ setIsResizing(false);
91
+ if (lastSize) {
92
+ onResizeRef.current?.(serializeSize(lastSize));
92
93
  }
94
+ }
93
95
 
94
- window.addEventListener('pointermove', moveCallback);
95
- window.addEventListener('pointerup', upCallback);
96
+ window.addEventListener('pointermove', moveCallback);
97
+ window.addEventListener('pointerup', upCallback);
96
98
 
97
- return () => {
98
- window.removeEventListener('pointermove', moveCallback);
99
- window.removeEventListener('pointerup', upCallback);
100
- };
101
- }
99
+ return () => {
100
+ window.removeEventListener('pointermove', moveCallback);
101
+ window.removeEventListener('pointerup', upCallback);
102
+ };
102
103
  }, [isResizing, controlledSide, direction, sizeType, splitterRef]);
103
104
 
104
105
  return {