@kanaries/graphic-walker 0.2.9 → 0.2.10

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 (52) hide show
  1. package/dist/App.d.ts +0 -2
  2. package/dist/components/callout.d.ts +7 -0
  3. package/dist/components/sizeSetting.d.ts +1 -0
  4. package/dist/components/toolbar/components.d.ts +11 -0
  5. package/dist/components/toolbar/index.d.ts +15 -0
  6. package/dist/components/toolbar/toolbar-button.d.ts +7 -0
  7. package/dist/components/toolbar/toolbar-item.d.ts +40 -0
  8. package/dist/components/toolbar/toolbar-select-button.d.ts +18 -0
  9. package/dist/components/toolbar/toolbar-toggle-button.d.ts +8 -0
  10. package/dist/components/tooltip.d.ts +13 -0
  11. package/dist/fields/datasetFields/dimFields.d.ts +1 -1
  12. package/dist/fields/datasetFields/meaFields.d.ts +1 -1
  13. package/dist/fields/filterField/filterPill.d.ts +1 -1
  14. package/dist/fields/obComponents/obFContainer.d.ts +1 -1
  15. package/dist/fields/obComponents/obPill.d.ts +1 -1
  16. package/dist/graphic-walker.es.js +56487 -55304
  17. package/dist/graphic-walker.es.js.map +1 -1
  18. package/dist/graphic-walker.umd.js +501 -288
  19. package/dist/graphic-walker.umd.js.map +1 -1
  20. package/dist/index.d.ts +4 -0
  21. package/dist/style.css +0 -1
  22. package/dist/utils/throttle.d.ts +5 -0
  23. package/dist/visualSettings/menubar.d.ts +8 -0
  24. package/package.json +4 -2
  25. package/src/App.tsx +0 -4
  26. package/src/components/callout.tsx +58 -0
  27. package/src/components/sizeSetting.tsx +61 -49
  28. package/src/components/tabs/pureTab.tsx +7 -1
  29. package/src/components/toolbar/components.tsx +110 -0
  30. package/src/components/toolbar/index.tsx +57 -0
  31. package/src/components/toolbar/toolbar-button.tsx +28 -0
  32. package/src/components/toolbar/toolbar-item.tsx +218 -0
  33. package/src/components/toolbar/toolbar-select-button.tsx +196 -0
  34. package/src/components/toolbar/toolbar-toggle-button.tsx +70 -0
  35. package/src/components/tooltip.tsx +135 -0
  36. package/src/empty_sheet.css +9 -0
  37. package/src/fields/aestheticFields.tsx +1 -1
  38. package/src/fields/datasetFields/dimFields.tsx +3 -3
  39. package/src/fields/datasetFields/index.tsx +2 -2
  40. package/src/fields/datasetFields/meaFields.tsx +3 -3
  41. package/src/fields/fieldsContext.tsx +1 -1
  42. package/src/fields/filterField/filterPill.tsx +1 -1
  43. package/src/fields/filterField/index.tsx +1 -1
  44. package/src/fields/obComponents/obFContainer.tsx +1 -1
  45. package/src/fields/obComponents/obPill.tsx +1 -1
  46. package/src/fields/posFields/index.tsx +1 -1
  47. package/src/global.d.ts +7 -0
  48. package/src/index.tsx +47 -8
  49. package/src/store/visualSpecStore.ts +1 -1
  50. package/src/utils/throttle.ts +28 -0
  51. package/src/visualSettings/index.tsx +316 -321
  52. package/src/visualSettings/menubar.tsx +1 -1
@@ -1,15 +1,39 @@
1
- import { BarsArrowDownIcon, BarsArrowUpIcon, ChevronDownIcon, PhotoIcon } from '@heroicons/react/24/outline';
1
+ import {
2
+ ArrowUturnLeftIcon,
3
+ BarsArrowDownIcon,
4
+ BarsArrowUpIcon,
5
+ PhotoIcon,
6
+ ArrowPathIcon,
7
+ ArrowsPointingOutIcon,
8
+ CubeIcon,
9
+ Square3Stack3DIcon,
10
+ StopIcon,
11
+ ArrowUturnRightIcon,
12
+ LockClosedIcon,
13
+ LockOpenIcon,
14
+ ViewfinderCircleIcon,
15
+ ChatBubbleBottomCenterTextIcon,
16
+ PaintBrushIcon,
17
+ CursorArrowRaysIcon,
18
+ WrenchIcon,
19
+ ChevronUpDownIcon,
20
+ XMarkIcon,
21
+ ChevronDoubleUpIcon,
22
+ ArrowsUpDownIcon,
23
+ LightBulbIcon,
24
+ } from '@heroicons/react/24/outline';
2
25
  import { observer } from 'mobx-react-lite';
3
- import React from 'react';
26
+ import React, { SVGProps, useCallback, useMemo } from 'react';
4
27
  import styled from 'styled-components'
5
- import { ArrowPathIcon } from '@heroicons/react/24/solid';
6
28
  import { useTranslation } from 'react-i18next';
7
- import { LiteForm } from '../components/liteForm';
8
- import SizeSetting from '../components/sizeSetting';
29
+ import { ResizeDialog } from '../components/sizeSetting';
9
30
  import { GEMO_TYPES, STACK_MODE, CHART_LAYOUT_TYPE } from '../config';
10
31
  import { useGlobalStore } from '../store';
11
32
  import { IStackMode, EXPLORATION_TYPES, IBrushDirection, BRUSH_DIRECTIONS } from '../interfaces';
12
33
  import { IReactVegaHandler } from '../vis/react-vega';
34
+ import Toolbar, { ToolbarItemProps } from '../components/toolbar';
35
+ import { ButtonWithShortcut } from './menubar';
36
+ import throttle from '../utils/throttle';
13
37
 
14
38
 
15
39
  export const LiteContainer = styled.div`
@@ -33,343 +57,314 @@ export const LiteContainer = styled.div`
33
57
  }
34
58
  `;
35
59
 
60
+ const Invisible = styled.div`
61
+ clip: rect(1px, 1px, 1px, 1px);
62
+ clip-path: inset(50%);
63
+ height: 1px;
64
+ width: 1px;
65
+ margin: -1px;
66
+ overflow: hidden;
67
+ padding: 0;
68
+ position: absolute;
69
+ `;
70
+
71
+ const FormContainer = styled.div`
72
+ margin: 2px;
73
+ border-radius: 1.2px;
74
+ padding: 0.5em;
75
+ display: flex;
76
+ flex-direction: column;
77
+ `;
78
+
36
79
  interface IVisualSettings {
37
80
  rendererHandler?: React.RefObject<IReactVegaHandler>;
38
81
  }
39
82
 
40
83
  const VisualSettings: React.FC<IVisualSettings> = ({ rendererHandler }) => {
41
84
  const { vizStore } = useGlobalStore();
42
- const { visualConfig, sortCondition } = vizStore;
85
+ const { visualConfig, canUndo, canRedo } = vizStore;
43
86
  const { t: tGlobal } = useTranslation();
44
87
  const { t } = useTranslation('translation', { keyPrefix: 'main.tabpanel.settings' });
45
88
 
46
- return <LiteContainer>
47
- <LiteForm style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center' }}>
48
- <div className="item">
49
- <input
50
- className="cursor-pointer"
51
- type="checkbox"
52
- id="toggle:aggregation"
53
- aria-describedby="toggle:aggregation:label"
54
- checked={visualConfig.defaultAggregated}
55
- onChange={(e) => {
56
- vizStore.setVisualConfig('defaultAggregated', e.target.checked);
57
- }}
58
- />
59
- <label
60
- className="text-xs text-color-gray-700 ml-2 cursor-pointer"
61
- id="toggle:aggregation:label"
62
- htmlFor="toggle:aggregation"
63
- >
64
- {t('toggle.aggregation')}
65
- </label>
66
- </div>
67
- <div className="item">
68
- <label
69
- className="px-2"
70
- id="dropdown:mark_type:label"
71
- htmlFor="dropdown:mark_type"
72
- >
73
- {tGlobal('constant.mark_type.__enum__')}
74
- </label>
75
- <select
76
- className="border border-gray-500 rounded-sm text-xs pt-0.5 pb-0.5 pl-2 pr-2 cursor-pointer"
77
- id="dropdown:mark_type"
78
- aria-describedby="dropdown:mark_type:label"
79
- value={visualConfig.geoms[0]}
80
- onChange={(e) => {
81
- vizStore.setVisualConfig('geoms', [e.target.value]);
82
- }}
83
- >
84
- {GEMO_TYPES.map(g => (
85
- <option
86
- key={g}
87
- value={g}
88
- aria-selected={visualConfig.geoms[0] === g}
89
- className="cursor-pointer"
90
- >
91
- {tGlobal(`constant.mark_type.${g}`)}
92
- </option>
93
- ))}
94
- </select>
95
- </div>
96
- <div className="item">
97
- <label
98
- className="px-2"
99
- id="dropdown:stack:label"
100
- htmlFor="dropdown:stack"
101
- >
102
- {tGlobal('constant.stack_mode.__enum__')}
103
- </label>
104
- <select
105
- className="border border-gray-500 rounded-sm text-xs pt-0.5 pb-0.5 pl-2 pr-2 cursor-pointer"
106
- id="dropdown:stack"
107
- aria-describedby="dropdown:stack:label"
108
- value={visualConfig.stack}
109
- onChange={(e) => {
110
- vizStore.setVisualConfig('stack', e.target.value as IStackMode);
111
- }}
112
- >
113
- {STACK_MODE.map(g => (
114
- <option
115
- key={g}
116
- value={g}
117
- aria-selected={visualConfig.stack === g}
118
- className="cursor-pointer"
119
- >
120
- {tGlobal(`constant.stack_mode.${g}`)}
121
- </option>
122
- ))}
123
- </select>
124
- </div>
125
- <div className="item">
126
- <input
127
- type="checkbox"
128
- className="cursor-pointer"
129
- id="toggle:axes_resize"
130
- aria-describedby="toggle:axes_resize:label"
131
- checked={visualConfig.interactiveScale}
132
- onChange={(e) => {
133
- vizStore.setVisualConfig('interactiveScale', e.target.checked);
134
- }}
135
- />
136
- <label
137
- className="text-xs text-color-gray-700 ml-2 cursor-pointer"
138
- id="toggle:axes_resize:label"
139
- htmlFor="toggle:axes_resize"
140
- >
141
- {t('toggle.axes_resize')}
142
- </label>
143
- </div>
144
- <div className="item">
145
- <label className="text-xs text-color-gray-700 mx-2">
146
- {t('sort')}
147
- </label>
148
- <BarsArrowUpIcon
149
- className={`w-4 inline-block mr-1 ${!sortCondition ? 'text-gray-300 cursor-not-allowed' : 'cursor-pointer'}`}
150
- onClick={() => {
151
- vizStore.applyDefaultSort('ascending')
152
- }}
153
- role="button"
154
- tabIndex={!sortCondition ? undefined : 0}
155
- aria-disabled={!sortCondition}
156
- xlinkTitle={t('button.ascending')}
157
- aria-label={t('button.ascending')}
158
- />
159
- <BarsArrowDownIcon
160
- className={`w-4 inline-block mr-1 ${!sortCondition ? 'text-gray-300 cursor-not-allowed' : 'cursor-pointer'}`}
161
- onClick={() => {
162
- vizStore.applyDefaultSort('descending');
163
- }}
164
- role="button"
165
- tabIndex={!sortCondition ? undefined : 0}
166
- aria-disabled={!sortCondition}
167
- xlinkTitle={t('button.descending')}
168
- aria-label={t('button.descending')}
169
- />
170
- </div>
171
- <div className='item'>
172
- <label
173
- className="text-xs text-color-gray-700 mr-2"
174
- htmlFor="button:transpose"
175
- id="button:transpose:label"
176
- >
177
- {t('button.transpose')}
178
- </label>
179
- <ArrowPathIcon
180
- className="w-4 inline-block mr-1 cursor-pointer"
181
- role="button"
182
- tabIndex={0}
183
- id="button:transpose"
184
- aria-describedby="button:transpose:label"
185
- xlinkTitle={t('button.transpose')}
186
- aria-label={t('button.transpose')}
187
- onClick={() => {
188
- vizStore.transpose();
189
- }}
190
- />
191
- </div>
192
- <div className="item">
193
- <label
194
- id="dropdown:layout_type:label"
195
- htmlFor="dropdown:layout_type"
196
- >
197
- {tGlobal(`constant.layout_type.__enum__`)}
198
- </label>
199
- <select
200
- className="border border-gray-500 rounded-sm text-xs pt-0.5 pb-0.5 pl-2 pr-2 cursor-pointer"
201
- id="dropdown:layout_type"
202
- aria-describedby="dropdown:layout_type:label"
203
- value={visualConfig.size.mode}
204
- onChange={(e) => {
205
- // vizStore.setVisualConfig('geoms', [e.target.value]);
206
- vizStore.setChartLayout({
207
- mode: e.target.value as any
208
- })
209
- }}
210
- >
211
- {CHART_LAYOUT_TYPE.map(g => (
212
- <option
213
- key={g}
214
- value={g}
215
- className="cursor-pointer"
216
- aria-selected={visualConfig.size.mode === g}
217
- >
218
- {tGlobal(`constant.layout_type.${g}`)}
219
- </option>
220
- ))}
221
- </select>
222
- </div>
223
- <div className="item hover:bg-yellow-100">
224
- <SizeSetting
225
- width={visualConfig.size.width}
226
- height={visualConfig.size.height}
227
- onHeightChange={(v) => {
228
- vizStore.setChartLayout({
229
- mode: "fixed",
230
- height: v
231
- })
232
- }}
233
- onWidthChange={(v) => {
234
- vizStore.setChartLayout({
235
- mode: "fixed",
236
- width: v
237
- })
238
- }}
239
- />
240
- <label
241
- className="text-xs text-color-gray-700 ml-2"
242
- htmlFor="button:size_setting"
243
- id="button:size_setting:label"
244
- >
245
- {t('size')}
246
- </label>
247
- </div>
248
- <div className="item">
249
- <label
250
- id="dropdown:exploration_mode:label"
251
- htmlFor="dropdown:exploration_mode"
252
- >
253
- {tGlobal(`constant.exploration_mode.__enum__`)}
254
- </label>
255
- <select
256
- className="border border-gray-500 rounded-sm text-xs pt-0.5 pb-0.5 pl-2 pr-2 cursor-pointer"
257
- id="dropdown:exploration_mode"
258
- aria-describedby="dropdown:exploration_mode:label"
259
- value={visualConfig.exploration.mode}
260
- onChange={e => {
261
- vizStore.setExploration({
262
- mode: e.target.value as (typeof EXPLORATION_TYPES)[number]
263
- });
264
- }}
265
- >
266
- {EXPLORATION_TYPES.map(g => (
267
- <option
268
- key={g}
269
- value={g}
270
- className="cursor-pointer"
271
- aria-selected={visualConfig.exploration.mode === g}
89
+ const {
90
+ defaultAggregated, geoms: [markType], stack, interactiveScale, size: { mode: sizeMode, width, height },
91
+ exploration: { mode: explorationMode, brushDirection }, showActions,
92
+ } = visualConfig;
93
+
94
+ const downloadPNG = useCallback(throttle(() => {
95
+ rendererHandler?.current?.downloadPNG();
96
+ }, 200), [rendererHandler]);
97
+
98
+ const downloadSVG = useCallback(throttle(() => {
99
+ rendererHandler?.current?.downloadSVG();
100
+ }, 200), [rendererHandler]);
101
+
102
+ const items = useMemo<ToolbarItemProps[]>(() => {
103
+ return [
104
+ {
105
+ key: 'undo',
106
+ label: 'undo (Ctrl + Z)',
107
+ icon: () => (
108
+ <>
109
+ <ArrowUturnLeftIcon />
110
+ <Invisible aria-hidden>
111
+ <ButtonWithShortcut
112
+ label="undo"
113
+ disabled={!canUndo}
114
+ handler={vizStore.undo.bind(vizStore)}
115
+ shortcut="Ctrl+Z"
116
+ />
117
+ </Invisible>
118
+ </>
119
+ ),
120
+ onClick: () => vizStore.undo(),
121
+ disabled: !canUndo,
122
+ },
123
+ {
124
+ key: 'redo',
125
+ label: 'redo (Ctrl+Shift+Z)',
126
+ icon: () => (
127
+ <>
128
+ <ArrowUturnRightIcon />
129
+ <Invisible aria-hidden>
130
+ <ButtonWithShortcut
131
+ label="redo"
132
+ disabled={!canRedo}
133
+ handler={vizStore.redo.bind(vizStore)}
134
+ shortcut="Ctrl+Shift+Z"
135
+ />
136
+ </Invisible>
137
+ </>
138
+ ),
139
+ onClick: () => vizStore.redo(),
140
+ disabled: !canRedo,
141
+ },
142
+ '-',
143
+ {
144
+ key: 'aggregation',
145
+ label: t('toggle.aggregation'),
146
+ icon: CubeIcon,
147
+ checked: defaultAggregated,
148
+ onChange: checked => {
149
+ vizStore.setVisualConfig('defaultAggregated', checked);
150
+ },
151
+ },
152
+ {
153
+ key: 'mark_type',
154
+ label: tGlobal('constant.mark_type.__enum__'),
155
+ icon: StopIcon,
156
+ options: GEMO_TYPES.map(g => ({
157
+ key: g,
158
+ label: tGlobal(`constant.mark_type.${g}`),
159
+ icon: {
160
+ auto: LightBulbIcon,
161
+ bar: (props: SVGProps<SVGSVGElement>) => <svg stroke="currentColor" fill="none" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M9,4v16h6v-16Z" /></svg>,
162
+ line: (props: SVGProps<SVGSVGElement>) => <svg stroke="currentColor" fill="none" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M5,6L19,18" /></svg>,
163
+ area: (props: SVGProps<SVGSVGElement>) => <svg stroke="none" fill="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M5,20v-17l14,4V20Z" /></svg>,
164
+ trail: (props: SVGProps<SVGSVGElement>) => <svg stroke="none" fill="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M5,6l7,4l7-2v2l-7,4l-7,-4z" /></svg>,
165
+ point: (props: SVGProps<SVGSVGElement>) => <svg stroke="currentColor" fill="none" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M9,12 A3,3,0,0,1,16,12 A3,3,0,0,1,9,12" /></svg>,
166
+ circle: (props: SVGProps<SVGSVGElement>) => <svg stroke="none" fill="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M6,12 A6,6,0,0,1,18,12 A6,6,0,0,1,6,12" /></svg>,
167
+ tick: (props: SVGProps<SVGSVGElement>) => <svg stroke="currentColor" fill="none" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M5,12h14" /></svg>,
168
+ rect: (props: SVGProps<SVGSVGElement>) => <svg stroke="none" fill="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M5,5v14h14v-14z" /></svg>,
169
+ arc: (props: SVGProps<SVGSVGElement>) => <svg stroke="none" fill="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M12,21l-9,-15a12,12,0,0,1,18,0Z" /></svg>,
170
+ boxplot: (props: SVGProps<SVGSVGElement>) => <svg stroke="currentColor" fill="none" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden {...props}><path strokeLinecap="round" strokeLinejoin="round" d="M7,7v9h10v-9Zm0,4h8M12,7v-6m-3,0h6M12,16v7m-3,0h6" /></svg>,
171
+ }[g],
172
+ })),
173
+ value: markType,
174
+ onSelect: value => {
175
+ vizStore.setVisualConfig('geoms', [value]);
176
+ },
177
+ },
178
+ {
179
+ key: 'stack_mode',
180
+ label: tGlobal('constant.stack_mode.__enum__'),
181
+ icon: Square3Stack3DIcon,
182
+ options: STACK_MODE.map(g => ({
183
+ key: g,
184
+ label: tGlobal(`constant.stack_mode.${g}`),
185
+ icon: {
186
+ none: XMarkIcon,
187
+ stack: ChevronDoubleUpIcon,
188
+ normalize: ArrowsUpDownIcon,
189
+ }[g],
190
+ })),
191
+ value: stack,
192
+ onSelect: value => {
193
+ vizStore.setVisualConfig('stack', value as IStackMode);
194
+ },
195
+ },
196
+ '-',
197
+ {
198
+ key: 'transpose',
199
+ label: t('button.transpose'),
200
+ icon: ArrowPathIcon,
201
+ onClick: () => vizStore.transpose(),
202
+ },
203
+ {
204
+ key: 'sort:asc',
205
+ label: t('button.ascending'),
206
+ icon: BarsArrowUpIcon,
207
+ onClick: () => vizStore.applyDefaultSort('ascending'),
208
+ },
209
+ {
210
+ key: 'sort:dec',
211
+ label: t('button.descending'),
212
+ icon: BarsArrowDownIcon,
213
+ onClick: () => vizStore.applyDefaultSort('descending'),
214
+ },
215
+ '-',
216
+ {
217
+ key: 'axes_resize',
218
+ label: t('toggle.axes_resize'),
219
+ icon: ChevronUpDownIcon,
220
+ checked: interactiveScale,
221
+ onChange: checked => {
222
+ vizStore.setVisualConfig('interactiveScale', checked);
223
+ },
224
+ },
225
+ {
226
+ key: 'scale',
227
+ icon: ArrowsPointingOutIcon,
228
+ label: tGlobal(`constant.layout_type.__enum__`),
229
+ options: CHART_LAYOUT_TYPE.map(g => ({
230
+ key: g,
231
+ label: tGlobal(`constant.layout_type.${g}`),
232
+ icon: g === 'auto' ? LockClosedIcon : LockOpenIcon,
233
+ })),
234
+ value: sizeMode,
235
+ onSelect: key => {
236
+ vizStore.setChartLayout({ mode: key as 'fixed' | 'auto' });
237
+ },
238
+ form: (
239
+ <FormContainer>
240
+ <ResizeDialog
241
+ width={width}
242
+ height={height}
243
+ onHeightChange={(v) => {
244
+ vizStore.setChartLayout({
245
+ mode: "fixed",
246
+ height: v
247
+ });
248
+ }}
249
+ onWidthChange={(v) => {
250
+ vizStore.setChartLayout({
251
+ mode: "fixed",
252
+ width: v
253
+ });
254
+ }}
255
+ />
256
+ </FormContainer>
257
+ ),
258
+ },
259
+ '-',
260
+ {
261
+ key: 'exploration_mode',
262
+ icon: ViewfinderCircleIcon,
263
+ label: tGlobal(`constant.exploration_mode.__enum__`),
264
+ options: EXPLORATION_TYPES.map(g => ({
265
+ key: g,
266
+ label: tGlobal(`constant.exploration_mode.${g}`),
267
+ icon: {
268
+ none: ChatBubbleBottomCenterTextIcon,
269
+ brush: PaintBrushIcon,
270
+ point: CursorArrowRaysIcon,
271
+ }[g],
272
+ })),
273
+ value: explorationMode,
274
+ onSelect: key => {
275
+ vizStore.setExploration({
276
+ mode: key as (typeof EXPLORATION_TYPES)[number]
277
+ });
278
+ },
279
+ form: explorationMode === 'brush' ? (
280
+ <FormContainer>
281
+ <label
282
+ id="dropdown:brush_mode:label"
283
+ htmlFor="dropdown:brush_mode"
272
284
  >
273
- {tGlobal(`constant.exploration_mode.${g}`)}
274
- </option>
275
- ))}
276
- </select>
277
- </div>
278
- <div className="item" style={{ opacity: visualConfig.exploration.mode !== 'brush' ? 0.3 : undefined }}>
279
- <label
280
- id="dropdown:brush_mode:label"
281
- htmlFor="dropdown:brush_mode"
282
- >
283
- {tGlobal(`constant.brush_mode.__enum__`)}
284
- </label>
285
- <select
286
- className="border border-gray-500 rounded-sm text-xs pt-0.5 pb-0.5 pl-2 pr-2 cursor-pointer"
287
- id="dropdown:brush_mode"
288
- aria-describedby="dropdown:brush_mode:label"
289
- disabled={visualConfig.exploration.mode !== 'brush'}
290
- aria-disabled={visualConfig.exploration.mode !== 'brush'}
291
- value={visualConfig.exploration.brushDirection}
292
- onChange={e => {
293
- vizStore.setExploration({
294
- brushDirection: e.target.value as IBrushDirection
295
- });
296
- }}
297
- >
298
- {BRUSH_DIRECTIONS.map(g => (
299
- <option
300
- key={g}
301
- value={g}
302
- className="cursor-pointer"
303
- aria-selected={visualConfig.exploration.brushDirection === g}
285
+ {tGlobal(`constant.brush_mode.__enum__`)}
286
+ </label>
287
+ <select
288
+ className="border border-gray-500 rounded-sm text-xs pt-0.5 pb-0.5 pl-2 pr-2 cursor-pointer"
289
+ id="dropdown:brush_mode"
290
+ aria-describedby="dropdown:brush_mode:label"
291
+ disabled={explorationMode !== 'brush'}
292
+ aria-disabled={explorationMode !== 'brush'}
293
+ value={brushDirection}
294
+ onChange={e => {
295
+ vizStore.setExploration({
296
+ brushDirection: e.target.value as IBrushDirection
297
+ });
298
+ }}
304
299
  >
305
- {tGlobal(`constant.brush_mode.${g}`)}
306
- </option>
307
- ))}
308
- </select>
309
- </div>
310
- <div className="item">
311
- <input
312
- type="checkbox"
313
- checked={visualConfig.showActions}
314
- id="toggle:debug"
315
- aria-describedby="toggle:debug:label"
316
- className="cursor-pointer"
317
- onChange={(e) => {
318
- vizStore.setVisualConfig('showActions', e.target.checked);
319
- }}
320
- />
321
- <label
322
- className="text-xs text-color-gray-700 ml-2 cursor-pointer"
323
- id="toggle:debug:label"
324
- htmlFor="toggle:debug"
325
- >
326
- {t('toggle.debug')}
327
- </label>
328
- </div>
329
- <div className='item'>
330
- <label
331
- className="text-xs text-color-gray-700 mr-2"
332
- htmlFor="button:transpose"
333
- id="button:transpose:label"
334
- >
335
- {t('button.export_chart')}
336
- </label>
337
- <PhotoIcon
338
- className="w-4 inline-block cursor-pointer"
339
- role="button"
340
- tabIndex={0}
341
- id="button:export_chart"
342
- aria-describedby="button:export_chart:label"
343
- xlinkTitle={t('button.export_chart')}
344
- aria-label={t('button.export_chart')}
345
- onClick={() => rendererHandler?.current?.downloadPNG()}
346
- />
347
- <div className="menu-root flex flex-col items-center justify-center">
348
- <ChevronDownIcon
349
- className="w-4 h-3 inline-block mr-1 cursor-pointer trigger"
350
- role="button"
351
- tabIndex={0}
352
- />
353
- <div>
300
+ {BRUSH_DIRECTIONS.map(g => (
301
+ <option
302
+ key={g}
303
+ value={g}
304
+ className="cursor-pointer"
305
+ aria-selected={brushDirection === g}
306
+ >
307
+ {tGlobal(`constant.brush_mode.${g}`)}
308
+ </option>
309
+ ))}
310
+ </select>
311
+ </FormContainer>
312
+ ) : undefined,
313
+ },
314
+ {
315
+ key: 'debug',
316
+ label: t('toggle.debug'),
317
+ icon: WrenchIcon,
318
+ checked: showActions,
319
+ onChange: checked => {
320
+ vizStore.setVisualConfig('showActions', checked);
321
+ },
322
+ },
323
+ {
324
+ key: 'export_chart',
325
+ label: t('button.export_chart'),
326
+ icon: PhotoIcon,
327
+ form: (
328
+ <FormContainer>
354
329
  <button
355
- className="text-xs min-w-96 w-full pt-1 pb-1 pl-6 pr-6 bg-white hover:bg-gray-200"
330
+ className="text-xs pt-1 pb-1 pl-6 pr-6 bg-white hover:bg-gray-200"
356
331
  aria-label={t('button.export_chart_as', { type: 'png' })}
357
- onClick={() => rendererHandler?.current?.downloadPNG()}
332
+ onClick={() => downloadPNG()}
358
333
  >
359
334
  {t('button.export_chart_as', { type: 'png' })}
360
335
  </button>
361
336
  <button
362
- className="text-xs min-w-96 w-full pt-1 pb-1 pl-6 pr-6 bg-white hover:bg-gray-200"
337
+ className="text-xs pt-1 pb-1 pl-6 pr-6 bg-white hover:bg-gray-200"
363
338
  aria-label={t('button.export_chart_as', { type: 'svg' })}
364
- onClick={() => rendererHandler?.current?.downloadSVG()}
339
+ onClick={() => downloadSVG()}
365
340
  >
366
341
  {t('button.export_chart_as', { type: 'svg' })}
367
342
  </button>
368
- </div>
369
- </div>
370
- </div>
371
- </LiteForm>
372
- </LiteContainer>
343
+ </FormContainer>
344
+ ),
345
+ },
346
+ ];
347
+ }, [vizStore, canUndo, canRedo, defaultAggregated, markType, stack, interactiveScale, sizeMode, width, height, explorationMode, brushDirection, showActions, downloadPNG, downloadSVG]);
348
+
349
+ return <div style={{ margin: '0.38em 0.28em 0.2em 0.18em' }}>
350
+ <Toolbar
351
+ items={items}
352
+ styles={{
353
+ root: {
354
+ '--background-color': '#fff',
355
+ '--color': '#777',
356
+ '--color-hover': '#555',
357
+ '--blue': '#282958',
358
+ '--blue-dark': '#1d1e38',
359
+ },
360
+ container: {
361
+ border: '1px solid #d9d9d9',
362
+ boxSizing: 'content-box',
363
+ borderRadius: '1px',
364
+ },
365
+ }}
366
+ />
367
+ </div>
373
368
  }
374
369
 
375
370
  export default observer(VisualSettings);