react-science 0.25.0 → 0.26.2

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 (166) hide show
  1. package/lib/app/explorer/MeasurementExplorer.js +29 -7
  2. package/lib/app/explorer/MeasurementExplorerWithState.js +2 -2
  3. package/lib/app/helpers/MeasurementPlot.js +28 -19
  4. package/lib/app/helpers/react-plot.js +1 -1
  5. package/lib/app/kinds/mass/MassPlotView.js +2 -2
  6. package/lib/app/kinds/mass/MeasurementMassPlot.js +49 -33
  7. package/lib/app/panels/measurement-info/MeasurementInfoPanel.js +13 -58
  8. package/lib/app-data/state/data/data.helpers.js +32 -8
  9. package/lib/components/forms/Checkbox.js +4 -5
  10. package/lib/components/forms/Input.js +3 -87
  11. package/lib/components/forms/TextArea.js +25 -0
  12. package/lib/components/forms/index.js +2 -0
  13. package/lib/components/forms/radio-group/ButtonRadioItem.js +76 -0
  14. package/lib/components/forms/radio-group/ClassicRadioItem.js +92 -0
  15. package/lib/components/forms/radio-group/RadioGroup.js +69 -0
  16. package/lib/components/forms/radio-group/index.js +17 -0
  17. package/lib/components/forms/styles.js +80 -0
  18. package/lib/components/forms/utils/SubText.js +20 -0
  19. package/lib/components/forms/utils/index.js +17 -0
  20. package/lib/components/header/PanelHeader.js +51 -0
  21. package/lib/components/header/index.js +1 -0
  22. package/lib/components/index.js +1 -0
  23. package/lib/components/info-panel/InfoPanel.js +94 -0
  24. package/lib/components/info-panel/index.js +17 -0
  25. package/lib/components/modal/ConfirmModal.js +3 -2
  26. package/lib/components/modal/Modal.js +3 -1
  27. package/lib/components/table/Table.js +2 -2
  28. package/lib/components/toolbar/PanelPreferencesToolbar.js +26 -0
  29. package/lib/components/toolbar/index.js +1 -0
  30. package/lib-esm/app/explorer/MeasurementExplorer.d.ts.map +1 -1
  31. package/lib-esm/app/explorer/MeasurementExplorer.js +30 -8
  32. package/lib-esm/app/explorer/MeasurementExplorer.js.map +1 -1
  33. package/lib-esm/app/explorer/MeasurementExplorerWithState.d.ts.map +1 -1
  34. package/lib-esm/app/explorer/MeasurementExplorerWithState.js +2 -2
  35. package/lib-esm/app/explorer/MeasurementExplorerWithState.js.map +1 -1
  36. package/lib-esm/app/helpers/MeasurementPlot.d.ts +3 -3
  37. package/lib-esm/app/helpers/MeasurementPlot.d.ts.map +1 -1
  38. package/lib-esm/app/helpers/MeasurementPlot.js +28 -19
  39. package/lib-esm/app/helpers/MeasurementPlot.js.map +1 -1
  40. package/lib-esm/app/helpers/react-plot.d.ts.map +1 -1
  41. package/lib-esm/app/helpers/react-plot.js +1 -1
  42. package/lib-esm/app/helpers/react-plot.js.map +1 -1
  43. package/lib-esm/app/kinds/mass/MassPlotView.d.ts.map +1 -1
  44. package/lib-esm/app/kinds/mass/MassPlotView.js +2 -2
  45. package/lib-esm/app/kinds/mass/MassPlotView.js.map +1 -1
  46. package/lib-esm/app/kinds/mass/MeasurementMassPlot.d.ts.map +1 -1
  47. package/lib-esm/app/kinds/mass/MeasurementMassPlot.js +49 -33
  48. package/lib-esm/app/kinds/mass/MeasurementMassPlot.js.map +1 -1
  49. package/lib-esm/app/panels/measurement-info/MeasurementInfoPanel.d.ts.map +1 -1
  50. package/lib-esm/app/panels/measurement-info/MeasurementInfoPanel.js +15 -60
  51. package/lib-esm/app/panels/measurement-info/MeasurementInfoPanel.js.map +1 -1
  52. package/lib-esm/app-data/state/data/data.helpers.d.ts +20 -12
  53. package/lib-esm/app-data/state/data/data.helpers.d.ts.map +1 -1
  54. package/lib-esm/app-data/state/data/data.helpers.js +30 -7
  55. package/lib-esm/app-data/state/data/data.helpers.js.map +1 -1
  56. package/lib-esm/components/forms/Checkbox.d.ts.map +1 -1
  57. package/lib-esm/components/forms/Checkbox.js +1 -2
  58. package/lib-esm/components/forms/Checkbox.js.map +1 -1
  59. package/lib-esm/components/forms/Input.d.ts +4 -2
  60. package/lib-esm/components/forms/Input.d.ts.map +1 -1
  61. package/lib-esm/components/forms/Input.js +3 -87
  62. package/lib-esm/components/forms/Input.js.map +1 -1
  63. package/lib-esm/components/forms/TextArea.d.ts +8 -0
  64. package/lib-esm/components/forms/TextArea.d.ts.map +1 -0
  65. package/lib-esm/components/forms/TextArea.js +19 -0
  66. package/lib-esm/components/forms/TextArea.js.map +1 -0
  67. package/lib-esm/components/forms/index.d.ts +2 -0
  68. package/lib-esm/components/forms/index.d.ts.map +1 -1
  69. package/lib-esm/components/forms/index.js +2 -0
  70. package/lib-esm/components/forms/index.js.map +1 -1
  71. package/lib-esm/components/forms/radio-group/ButtonRadioItem.d.ts +3 -0
  72. package/lib-esm/components/forms/radio-group/ButtonRadioItem.d.ts.map +1 -0
  73. package/lib-esm/components/forms/radio-group/ButtonRadioItem.js +50 -0
  74. package/lib-esm/components/forms/radio-group/ButtonRadioItem.js.map +1 -0
  75. package/lib-esm/components/forms/radio-group/ClassicRadioItem.d.ts +3 -0
  76. package/lib-esm/components/forms/radio-group/ClassicRadioItem.d.ts.map +1 -0
  77. package/lib-esm/components/forms/radio-group/ClassicRadioItem.js +66 -0
  78. package/lib-esm/components/forms/radio-group/ClassicRadioItem.js.map +1 -0
  79. package/lib-esm/components/forms/radio-group/RadioGroup.d.ts +18 -0
  80. package/lib-esm/components/forms/radio-group/RadioGroup.d.ts.map +1 -0
  81. package/lib-esm/components/forms/radio-group/RadioGroup.js +43 -0
  82. package/lib-esm/components/forms/radio-group/RadioGroup.js.map +1 -0
  83. package/lib-esm/components/forms/radio-group/index.d.ts +2 -0
  84. package/lib-esm/components/forms/radio-group/index.d.ts.map +1 -0
  85. package/lib-esm/components/forms/radio-group/index.js +2 -0
  86. package/lib-esm/components/forms/radio-group/index.js.map +1 -0
  87. package/lib-esm/components/forms/styles.d.ts +26 -0
  88. package/lib-esm/components/forms/styles.d.ts.map +1 -0
  89. package/lib-esm/components/forms/styles.js +75 -0
  90. package/lib-esm/components/forms/styles.js.map +1 -0
  91. package/lib-esm/components/forms/utils/SubText.d.ts +7 -0
  92. package/lib-esm/components/forms/utils/SubText.d.ts.map +1 -0
  93. package/lib-esm/components/forms/utils/SubText.js +17 -0
  94. package/lib-esm/components/forms/utils/SubText.js.map +1 -0
  95. package/lib-esm/components/forms/utils/index.d.ts +2 -0
  96. package/lib-esm/components/forms/utils/index.d.ts.map +1 -0
  97. package/lib-esm/components/forms/utils/index.js +2 -0
  98. package/lib-esm/components/forms/utils/index.js.map +1 -0
  99. package/lib-esm/components/header/PanelHeader.d.ts +10 -0
  100. package/lib-esm/components/header/PanelHeader.d.ts.map +1 -0
  101. package/lib-esm/components/header/PanelHeader.js +48 -0
  102. package/lib-esm/components/header/PanelHeader.js.map +1 -0
  103. package/lib-esm/components/header/index.d.ts +1 -0
  104. package/lib-esm/components/header/index.d.ts.map +1 -1
  105. package/lib-esm/components/header/index.js +1 -0
  106. package/lib-esm/components/header/index.js.map +1 -1
  107. package/lib-esm/components/index.d.ts +1 -0
  108. package/lib-esm/components/index.d.ts.map +1 -1
  109. package/lib-esm/components/index.js +1 -0
  110. package/lib-esm/components/index.js.map +1 -1
  111. package/lib-esm/components/info-panel/InfoPanel.d.ts +15 -0
  112. package/lib-esm/components/info-panel/InfoPanel.d.ts.map +1 -0
  113. package/lib-esm/components/info-panel/InfoPanel.js +91 -0
  114. package/lib-esm/components/info-panel/InfoPanel.js.map +1 -0
  115. package/lib-esm/components/info-panel/index.d.ts +2 -0
  116. package/lib-esm/components/info-panel/index.d.ts.map +1 -0
  117. package/lib-esm/components/info-panel/index.js +2 -0
  118. package/lib-esm/components/info-panel/index.js.map +1 -0
  119. package/lib-esm/components/modal/ConfirmModal.d.ts.map +1 -1
  120. package/lib-esm/components/modal/ConfirmModal.js +3 -2
  121. package/lib-esm/components/modal/ConfirmModal.js.map +1 -1
  122. package/lib-esm/components/modal/Modal.d.ts.map +1 -1
  123. package/lib-esm/components/modal/Modal.js +3 -1
  124. package/lib-esm/components/modal/Modal.js.map +1 -1
  125. package/lib-esm/components/table/Table.d.ts +2 -3
  126. package/lib-esm/components/table/Table.d.ts.map +1 -1
  127. package/lib-esm/components/table/Table.js +2 -2
  128. package/lib-esm/components/table/Table.js.map +1 -1
  129. package/lib-esm/components/toolbar/PanelPreferencesToolbar.d.ts +7 -0
  130. package/lib-esm/components/toolbar/PanelPreferencesToolbar.d.ts.map +1 -0
  131. package/lib-esm/components/toolbar/PanelPreferencesToolbar.js +23 -0
  132. package/lib-esm/components/toolbar/PanelPreferencesToolbar.js.map +1 -0
  133. package/lib-esm/components/toolbar/index.d.ts +1 -0
  134. package/lib-esm/components/toolbar/index.d.ts.map +1 -1
  135. package/lib-esm/components/toolbar/index.js +1 -0
  136. package/lib-esm/components/toolbar/index.js.map +1 -1
  137. package/package.json +16 -14
  138. package/src/app/explorer/MeasurementExplorer.tsx +34 -12
  139. package/src/app/explorer/MeasurementExplorerWithState.tsx +2 -2
  140. package/src/app/helpers/MeasurementPlot.tsx +44 -33
  141. package/src/app/helpers/react-plot.tsx +6 -4
  142. package/src/app/kinds/mass/MassPlotView.tsx +2 -2
  143. package/src/app/kinds/mass/MeasurementMassPlot.tsx +57 -37
  144. package/src/app/panels/measurement-info/MeasurementInfoPanel.tsx +14 -84
  145. package/src/app-data/state/data/data.helpers.ts +49 -16
  146. package/src/components/forms/Checkbox.tsx +2 -3
  147. package/src/components/forms/Input.tsx +14 -125
  148. package/src/components/forms/TextArea.tsx +45 -0
  149. package/src/components/forms/index.ts +2 -0
  150. package/src/components/forms/radio-group/ButtonRadioItem.tsx +77 -0
  151. package/src/components/forms/radio-group/ClassicRadioItem.tsx +95 -0
  152. package/src/components/forms/radio-group/RadioGroup.tsx +83 -0
  153. package/src/components/forms/radio-group/index.ts +1 -0
  154. package/src/components/forms/styles.ts +96 -0
  155. package/src/components/forms/utils/SubText.tsx +31 -0
  156. package/src/components/forms/utils/index.ts +1 -0
  157. package/src/components/header/PanelHeader.tsx +75 -0
  158. package/src/components/header/index.ts +1 -0
  159. package/src/components/index.ts +1 -0
  160. package/src/components/info-panel/InfoPanel.tsx +150 -0
  161. package/src/components/info-panel/index.ts +1 -0
  162. package/src/components/modal/ConfirmModal.tsx +3 -2
  163. package/src/components/modal/Modal.tsx +3 -1
  164. package/src/components/table/Table.tsx +3 -5
  165. package/src/components/toolbar/PanelPreferencesToolbar.tsx +46 -0
  166. package/src/components/toolbar/index.ts +1 -0
@@ -1,96 +1,16 @@
1
1
  import styled from '@emotion/styled';
2
- import { CSSProperties, InputHTMLAttributes, ReactNode } from 'react';
2
+ import { InputHTMLAttributes, ReactNode } from 'react';
3
3
 
4
4
  import { FullSpinner } from '../index';
5
5
 
6
6
  import { useFieldsContext } from './context/FieldsContext';
7
-
8
- type InputVariant = 'default' | 'small';
9
-
10
- interface StyledProps {
11
- variant: InputVariant;
12
- hasLeading: boolean;
13
- hasTrailing: boolean;
14
- }
15
-
16
- const LabelStyled = styled.label<StyledProps>`
17
- padding: ${(props) =>
18
- props.variant === 'default'
19
- ? props.hasTrailing
20
- ? '2px 9px 4px 9px'
21
- : '2px 9px'
22
- : props.hasTrailing
23
- ? '1px 7px 1px 7px'
24
- : '1px 7px'};
25
-
26
- font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')};
27
- line-height: '17px';
28
-
29
- background-color: white;
30
- border-width: 1px;
31
- align-items: center;
32
- flex-direction: row;
33
- flex: 1 1 0%;
34
- display: flex;
35
- position: relative;
36
-
37
- border-top-right-radius: ${(props) =>
38
- props.hasLeading && !props.hasTrailing && '0.375rem'};
39
-
40
- border-bottom-right-radius: ${(props) =>
41
- props.hasLeading && !props.hasTrailing && '0.375rem'};
42
-
43
- border-top-left-radius: ${(props) =>
44
- props.hasTrailing && !props.hasLeading && '0.375rem'};
45
-
46
- border-bottom-left-radius: ${(props) =>
47
- props.hasTrailing && !props.hasLeading && '0.375rem'};
48
-
49
- border-radius: ${(props) =>
50
- !props.hasLeading && !props.hasTrailing && '0.375rem'};
51
-
52
- border-color: var(--custom-border-color);
53
- `;
54
-
55
- function getStyleColor(hasError: boolean, hasValid: boolean) {
56
- if (hasError) {
57
- return {
58
- default: '#ffa39e',
59
- hover: '#f95d55',
60
- };
61
- }
62
-
63
- if (hasValid) {
64
- return {
65
- default: '#6adc24',
66
- hover: '#62cb21',
67
- };
68
- }
69
-
70
- return {
71
- default: 'rgb(217, 217, 217)',
72
- hover: '#4096ff',
73
- };
74
- }
75
-
76
- const GroupStyled = styled.div<{ hasError: boolean; hasValid: boolean }>`
77
- display: flex;
78
- border-radius: 0.375rem;
79
- margin-top: 0.25rem;
80
-
81
- .addon {
82
- color: ${({ hasError }) => hasError && '#f95d55'};
83
- }
84
-
85
- --custom-border-color: ${({ hasError, hasValid }) =>
86
- getStyleColor(hasError, hasValid).default};
87
-
88
- :hover,
89
- :focus-within {
90
- --custom-border-color: ${({ hasError, hasValid }) =>
91
- getStyleColor(hasError, hasValid).hover};
92
- }
93
- `;
7
+ import {
8
+ InputContainer,
9
+ GroupStyled,
10
+ LabelStyled,
11
+ InputVariant,
12
+ } from './styles';
13
+ import { SubText, SubTextProps } from './utils';
94
14
 
95
15
  const InputStyled = styled.input`
96
16
  padding: 0;
@@ -142,27 +62,20 @@ const TrailingInlineAddonStyled = styled.div`
142
62
  padding-left: 0.5rem;
143
63
  `;
144
64
 
145
- const RootInput = styled.div`
146
- display: flex;
147
- flex-direction: column;
148
- gap: 2px;
149
- `;
150
-
151
65
  interface RenderAddon {
152
66
  addon: ReactNode;
153
67
  inline?: boolean;
154
68
  }
155
69
 
156
- export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
157
- variant?: 'default' | 'small';
158
-
70
+ export interface InputProps
71
+ extends InputHTMLAttributes<HTMLInputElement>,
72
+ SubTextProps {
73
+ variant?: InputVariant;
159
74
  leadingAddon?: RenderAddon;
160
75
  trailingAddon?: RenderAddon;
161
-
162
76
  help?: string;
163
77
  error?: string;
164
78
  valid?: true | string;
165
-
166
79
  loading?: boolean;
167
80
  }
168
81
 
@@ -185,7 +98,7 @@ export function Input(props: InputProps) {
185
98
  const variant = variantProps || contextVariant;
186
99
 
187
100
  return (
188
- <RootInput>
101
+ <InputContainer>
189
102
  <GroupStyled hasError={!!error} hasValid={!!valid}>
190
103
  {leadingAddon && !leadingAddon.inline && (
191
104
  <LeadingAddonStyled>{leadingAddon.addon}</LeadingAddonStyled>
@@ -226,30 +139,6 @@ export function Input(props: InputProps) {
226
139
  </GroupStyled>
227
140
 
228
141
  <SubText error={error} help={help} valid={valid} />
229
- </RootInput>
142
+ </InputContainer>
230
143
  );
231
144
  }
232
-
233
- function SubText(props: Pick<InputProps, 'help' | 'error' | 'valid'>) {
234
- const { error, help, valid: validProps } = props;
235
-
236
- const valid = typeof validProps === 'string' ? validProps : undefined;
237
- const text = error || valid || help;
238
-
239
- return <p style={{ color: getColor(error, validProps) }}>{text}</p>;
240
- }
241
-
242
- function getColor(
243
- error?: string,
244
- valid?: true | string,
245
- ): CSSProperties['color'] {
246
- if (error) {
247
- return '#f95d55';
248
- }
249
-
250
- if (valid && typeof valid !== 'boolean') {
251
- return '#62cb21';
252
- }
253
-
254
- return 'gray';
255
- }
@@ -0,0 +1,45 @@
1
+ import styled from '@emotion/styled';
2
+ import { TextareaHTMLAttributes } from 'react';
3
+
4
+ import { useFieldsContext } from './context/FieldsContext';
5
+ import {
6
+ InputContainer,
7
+ GroupStyled,
8
+ LabelStyled,
9
+ InputVariant,
10
+ } from './styles';
11
+ import { SubText, SubTextProps } from './utils';
12
+
13
+ const TextAreaStyled = styled.textarea`
14
+ padding: 0;
15
+ flex: 1 1 0%;
16
+ border: none;
17
+ position: relative;
18
+ outline: none;
19
+ `;
20
+
21
+ export interface TextAreaProps
22
+ extends TextareaHTMLAttributes<HTMLTextAreaElement>,
23
+ SubTextProps {
24
+ variant?: InputVariant;
25
+ }
26
+
27
+ export function TextArea(props: TextAreaProps) {
28
+ const { variant: variantProps, help, error, valid, ...otherProps } = props;
29
+
30
+ const { name, variant: contextVariant } = useFieldsContext();
31
+
32
+ const variant = variantProps || contextVariant;
33
+
34
+ return (
35
+ <InputContainer>
36
+ <GroupStyled hasError={!!error} hasValid={!!valid}>
37
+ <LabelStyled variant={variant}>
38
+ <TextAreaStyled id={name} name={name} {...otherProps} />
39
+ </LabelStyled>
40
+ </GroupStyled>
41
+
42
+ <SubText error={error} help={help} valid={valid} />
43
+ </InputContainer>
44
+ );
45
+ }
@@ -1,4 +1,6 @@
1
1
  export * from './Input';
2
+ export * from './TextArea';
2
3
  export * from './Checkbox';
3
4
  export * from './context';
4
5
  export * from './Select';
6
+ export * from './radio-group';
@@ -0,0 +1,77 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css } from '@emotion/react';
3
+ import * as RadioGroup from '@radix-ui/react-radio-group';
4
+
5
+ import { enabledColor, InputVariant } from '../styles';
6
+
7
+ import { RadioOption, RadioGroupProps } from './RadioGroup';
8
+
9
+ const buttonStyles = {
10
+ container: css({
11
+ border: '1px solid rgba(0, 0, 0, 0.25)',
12
+ borderRightWidth: 0,
13
+ position: 'relative',
14
+ }),
15
+ item: (disabled: boolean, variant?: InputVariant) =>
16
+ css({
17
+ opacity: disabled ? 0.25 : 1,
18
+ padding: variant === 'default' ? '0px 15px' : '0px 7px',
19
+ width: '100%',
20
+ height: '100%',
21
+ cursor: 'pointer',
22
+ ':hover': {
23
+ '& > label': {
24
+ color: disabled ? '' : enabledColor,
25
+ },
26
+ },
27
+ }),
28
+
29
+ indicator: css({
30
+ position: 'absolute',
31
+ top: -1,
32
+ left: -1,
33
+ right: -1,
34
+ bottom: -1,
35
+ zIndex: 10,
36
+ border: '1px solid',
37
+ borderColor: enabledColor,
38
+
39
+ '& ~ label': {
40
+ color: enabledColor,
41
+ },
42
+ }),
43
+
44
+ label: (variant?: InputVariant) =>
45
+ css({
46
+ cursor: 'pointer',
47
+ fontSize: variant === 'small' ? '1em' : '1.125em',
48
+ lineHeight: variant === 'default' ? '30px' : '22px',
49
+ }),
50
+ };
51
+
52
+ export function ButtonRadioItem(
53
+ prop: RadioOption & Pick<RadioGroupProps, 'onSelect' | 'variant' | 'name'>,
54
+ ) {
55
+ const { value, label, disabled = false, onSelect, variant, name } = prop;
56
+ return (
57
+ <div css={buttonStyles.container}>
58
+ <RadioGroup.Item
59
+ css={buttonStyles.item(disabled, variant)}
60
+ value={value}
61
+ id={`${value}${name}`}
62
+ onClick={() => {
63
+ if (!disabled) onSelect?.(prop);
64
+ }}
65
+ >
66
+ <RadioGroup.Indicator css={buttonStyles.indicator} />
67
+ <label
68
+ css={buttonStyles.label(variant)}
69
+ htmlFor={`${value}${name}`}
70
+ style={{}}
71
+ >
72
+ {label}
73
+ </label>
74
+ </RadioGroup.Item>
75
+ </div>
76
+ );
77
+ }
@@ -0,0 +1,95 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css } from '@emotion/react';
3
+ import * as RadioGroup from '@radix-ui/react-radio-group';
4
+
5
+ import { disabledColor, enabledColor, InputVariant } from '../styles';
6
+
7
+ import { RadioOption, RadioGroupProps } from './RadioGroup';
8
+
9
+ const classicStyles = {
10
+ container: (disabled: boolean) =>
11
+ css({
12
+ display: 'flex',
13
+ alignItems: 'center',
14
+ flexDirection: 'row-reverse',
15
+ opacity: disabled ? 0.25 : 1,
16
+ overflow: 'hidden',
17
+ border: 'none',
18
+ }),
19
+ item: (disabled: boolean, variant?: InputVariant) =>
20
+ css({
21
+ position: 'relative',
22
+ width: variant === 'default' ? 16 : 14,
23
+ height: variant === 'default' ? 16 : 14,
24
+ borderRadius: '50%',
25
+ border: '1px solid grey',
26
+ backgroundColor: disabled ? disabledColor : 'white',
27
+ ':hover': {
28
+ borderColor: disabled ? 'grey' : enabledColor,
29
+ },
30
+ }),
31
+
32
+ indicator: css({
33
+ position: 'absolute',
34
+ top: -1,
35
+ left: -1,
36
+ right: -1,
37
+ bottom: -1,
38
+ zIndex: 10,
39
+ display: 'flex',
40
+ alignItems: 'center',
41
+ justifyContent: 'center',
42
+ backgroundColor: enabledColor,
43
+ borderRadius: '50%',
44
+ }),
45
+ circle: css({
46
+ width: '40%',
47
+ height: '40%',
48
+ borderRadius: '50%',
49
+ backgroundColor: 'white',
50
+ }),
51
+
52
+ label: (disabled: boolean) =>
53
+ css({
54
+ cursor: 'pointer',
55
+ lineHeight: 1,
56
+ paddingLeft: 5,
57
+ fontSize: '12px',
58
+ ':hover': {
59
+ '& ~ button': {
60
+ borderColor: disabled ? 'grey' : enabledColor,
61
+ },
62
+ },
63
+ }),
64
+ };
65
+
66
+ export function ClassicRadioItem(
67
+ props: RadioOption & Pick<RadioGroupProps, 'onSelect' | 'variant' | 'name'>,
68
+ ) {
69
+ const { value, label, disabled = false, onSelect, variant, name } = props;
70
+ return (
71
+ <div css={classicStyles.container(disabled)}>
72
+ <label
73
+ css={classicStyles.label(disabled)}
74
+ style={{
75
+ fontSize: variant === 'small' ? '1em' : '1.125em',
76
+ }}
77
+ htmlFor={`${value}${name}`}
78
+ >
79
+ {label}
80
+ </label>
81
+ <RadioGroup.Item
82
+ css={classicStyles.item(disabled, variant)}
83
+ value={value}
84
+ id={`${value}${name}`}
85
+ onClick={() => {
86
+ if (!disabled) onSelect?.(props);
87
+ }}
88
+ >
89
+ <RadioGroup.Indicator css={classicStyles.indicator}>
90
+ <div css={classicStyles.circle} />
91
+ </RadioGroup.Indicator>
92
+ </RadioGroup.Item>
93
+ </div>
94
+ );
95
+ }
@@ -0,0 +1,83 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css } from '@emotion/react';
3
+ import * as RadioGroupRadix from '@radix-ui/react-radio-group';
4
+ import { ReactNode } from 'react';
5
+
6
+ import { InputVariant } from '../styles';
7
+
8
+ import { ButtonRadioItem } from './ButtonRadioItem';
9
+ import { ClassicRadioItem } from './ClassicRadioItem';
10
+
11
+ export interface RadioOption {
12
+ value: string;
13
+ label: ReactNode;
14
+ disabled?: boolean;
15
+ }
16
+ export interface RadioGroupProps {
17
+ selected?: RadioOption;
18
+ type?: 'classic' | 'button';
19
+ options?: RadioOption[];
20
+ onSelect?: (option: RadioOption) => void;
21
+ name?: string;
22
+ disabled?: boolean;
23
+ variant?: InputVariant;
24
+ }
25
+ const rootStyles = {
26
+ basic: css({
27
+ display: 'flex',
28
+ flexDirection: 'row',
29
+ width: 'fit-content',
30
+ }),
31
+ button: (variant: InputVariant) =>
32
+ css({
33
+ ' & > *:first-of-type, & > *:first-of-type span': {
34
+ borderRadius: variant === 'default' ? '6px 0 0 6px' : '4px 0 0 4px',
35
+ },
36
+ ' & > *:last-of-type, & > *:last-of-type span': {
37
+ borderRightWidth: 1,
38
+ borderRadius: variant === 'default' ? '0 6px 6px 0' : '0 4px 4px 0',
39
+ },
40
+ }),
41
+ };
42
+ export function RadioGroup(props: RadioGroupProps) {
43
+ const {
44
+ selected,
45
+ type = 'classic',
46
+ disabled: groupDisabled = false,
47
+ options = [],
48
+ onSelect,
49
+ name = '',
50
+ variant = 'default',
51
+ } = props;
52
+ return (
53
+ <RadioGroupRadix.Root
54
+ css={[
55
+ rootStyles.basic,
56
+ type === 'classic' ? null : rootStyles.button(variant),
57
+ ]}
58
+ style={{
59
+ gap: type === 'classic' ? (variant === 'default' ? 10 : 5) : 0,
60
+ }}
61
+ value={selected?.value}
62
+ name={name}
63
+ disabled={groupDisabled}
64
+ >
65
+ {options?.map(({ value, label, disabled }) => {
66
+ const childProps = {
67
+ key: value,
68
+ value,
69
+ label,
70
+ disabled: groupDisabled || disabled,
71
+ onSelect,
72
+ variant,
73
+ name,
74
+ };
75
+ return type === 'classic' ? (
76
+ <ClassicRadioItem {...childProps} />
77
+ ) : (
78
+ <ButtonRadioItem {...childProps} />
79
+ );
80
+ })}
81
+ </RadioGroupRadix.Root>
82
+ );
83
+ }
@@ -0,0 +1 @@
1
+ export * from './RadioGroup';
@@ -0,0 +1,96 @@
1
+ import styled from '@emotion/styled';
2
+
3
+ export type InputVariant = 'default' | 'small';
4
+
5
+ interface StyledProps {
6
+ variant: InputVariant;
7
+ hasLeading?: boolean;
8
+ hasTrailing?: boolean;
9
+ }
10
+ export const enabledColor = '#1677ff';
11
+ export const disabledColor = '#b8b8b8';
12
+
13
+ export const LabelStyled = styled.label<StyledProps>`
14
+ padding: ${(props) =>
15
+ props.variant === 'default'
16
+ ? props.hasTrailing
17
+ ? '2px 9px 4px 9px'
18
+ : '2px 9px'
19
+ : props.hasTrailing
20
+ ? '1px 7px 1px 7px'
21
+ : '1px 7px'};
22
+
23
+ font-size: ${(props) => (props.variant === 'small' ? '1em' : '1.125em')};
24
+ line-height: '17px';
25
+
26
+ background-color: white;
27
+ border-width: 1px;
28
+ align-items: center;
29
+ flex-direction: row;
30
+ flex: 1 1 0%;
31
+ display: flex;
32
+ position: relative;
33
+
34
+ border-top-right-radius: ${(props) =>
35
+ props.hasLeading && !props.hasTrailing && '0.375rem'};
36
+
37
+ border-bottom-right-radius: ${(props) =>
38
+ props.hasLeading && !props.hasTrailing && '0.375rem'};
39
+
40
+ border-top-left-radius: ${(props) =>
41
+ props.hasTrailing && !props.hasLeading && '0.375rem'};
42
+
43
+ border-bottom-left-radius: ${(props) =>
44
+ props.hasTrailing && !props.hasLeading && '0.375rem'};
45
+
46
+ border-radius: ${(props) =>
47
+ !props.hasLeading && !props.hasTrailing && '0.375rem'};
48
+
49
+ border-color: var(--custom-border-color);
50
+ `;
51
+
52
+ function getStyleColor(hasError: boolean, hasValid: boolean) {
53
+ if (hasError) {
54
+ return {
55
+ default: '#ffa39e',
56
+ hover: '#f95d55',
57
+ };
58
+ }
59
+
60
+ if (hasValid) {
61
+ return {
62
+ default: '#6adc24',
63
+ hover: '#62cb21',
64
+ };
65
+ }
66
+
67
+ return {
68
+ default: 'rgb(217, 217, 217)',
69
+ hover: '#4096ff',
70
+ };
71
+ }
72
+
73
+ export const GroupStyled = styled.div<{ hasError: boolean; hasValid: boolean }>`
74
+ display: flex;
75
+ border-radius: 0.375rem;
76
+ margin-top: 0.25rem;
77
+
78
+ .addon {
79
+ color: ${({ hasError }) => hasError && '#f95d55'};
80
+ }
81
+
82
+ --custom-border-color: ${({ hasError, hasValid }) =>
83
+ getStyleColor(hasError, hasValid).default};
84
+
85
+ :hover,
86
+ :focus-within {
87
+ --custom-border-color: ${({ hasError, hasValid }) =>
88
+ getStyleColor(hasError, hasValid).hover};
89
+ }
90
+ `;
91
+
92
+ export const InputContainer = styled.div`
93
+ display: flex;
94
+ flex-direction: column;
95
+ gap: 2px;
96
+ `;
@@ -0,0 +1,31 @@
1
+ import { CSSProperties } from 'react';
2
+
3
+ export interface SubTextProps {
4
+ help?: string;
5
+ error?: string;
6
+ valid?: true | string;
7
+ }
8
+
9
+ export function SubText(props: SubTextProps) {
10
+ const { error, help, valid: validProps } = props;
11
+
12
+ const valid = typeof validProps === 'string' ? validProps : undefined;
13
+ const text = error || valid || help;
14
+
15
+ return <p style={{ color: getColor(error, validProps) }}>{text}</p>;
16
+ }
17
+
18
+ function getColor(
19
+ error?: string,
20
+ valid?: true | string,
21
+ ): CSSProperties['color'] {
22
+ if (error) {
23
+ return '#f95d55';
24
+ }
25
+
26
+ if (valid && typeof valid !== 'boolean') {
27
+ return '#62cb21';
28
+ }
29
+
30
+ return 'gray';
31
+ }
@@ -0,0 +1 @@
1
+ export * from './SubText';
@@ -0,0 +1,75 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css } from '@emotion/react';
3
+ import { ReactNode, useEffect, useRef } from 'react';
4
+ import { FaCog } from 'react-icons/fa';
5
+
6
+ import { Button } from '../button/Button';
7
+
8
+ const styles = {
9
+ container: css({
10
+ display: 'flex',
11
+ flexDirection: 'row',
12
+ alignItems: 'center',
13
+ justifyContent: 'space-between',
14
+ borderBottom: '0.55px solid rgb(240, 240, 240)',
15
+ }),
16
+ leftContainer: css({
17
+ display: 'flex',
18
+ flexDirection: 'row',
19
+ flex: 1,
20
+ '& > button': {
21
+ padding: '0 5px',
22
+ minWidth: 'auto',
23
+ },
24
+ }),
25
+ counterLabel: css({
26
+ margin: 0,
27
+ textAlign: 'right',
28
+ lineHeight: '22px',
29
+ whiteSpace: 'nowrap',
30
+ }),
31
+ };
32
+
33
+ interface PanelHeaderProps {
34
+ total?: number;
35
+ current?: number;
36
+ onClickSettings?: () => void;
37
+ children?: ReactNode;
38
+ }
39
+
40
+ export function PanelHeader({
41
+ total,
42
+ current,
43
+ children,
44
+ onClickSettings,
45
+ }: PanelHeaderProps) {
46
+ const labelRef = useRef<HTMLParagraphElement>(null);
47
+
48
+ useEffect(() => {
49
+ if (!labelRef.current) return;
50
+
51
+ if (current !== undefined && total !== undefined) {
52
+ labelRef.current.textContent = `${current} / ${total}`;
53
+ } else if (current !== undefined) {
54
+ labelRef.current.textContent = `[ ${current} ]`;
55
+ } else if (total !== undefined) {
56
+ labelRef.current.textContent = `[ ${total} ]`;
57
+ }
58
+ }, [current, total]);
59
+
60
+ return (
61
+ <div css={styles.container}>
62
+ <div css={styles.leftContainer}>{children}</div>
63
+ <p ref={labelRef} css={styles.counterLabel} />
64
+ {onClickSettings && (
65
+ <Button
66
+ onClick={onClickSettings}
67
+ color={{ basic: 'black', hover: 'black' }}
68
+ backgroundColor={{ basic: 'white', hover: '#f7f7f7' }}
69
+ >
70
+ <FaCog />
71
+ </Button>
72
+ )}
73
+ </div>
74
+ );
75
+ }
@@ -1 +1,2 @@
1
1
  export * from './Header';
2
+ export * from './PanelHeader';