@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.
- package/dist/App.d.ts +0 -2
- package/dist/components/callout.d.ts +7 -0
- package/dist/components/sizeSetting.d.ts +1 -0
- package/dist/components/toolbar/components.d.ts +11 -0
- package/dist/components/toolbar/index.d.ts +15 -0
- package/dist/components/toolbar/toolbar-button.d.ts +7 -0
- package/dist/components/toolbar/toolbar-item.d.ts +40 -0
- package/dist/components/toolbar/toolbar-select-button.d.ts +18 -0
- package/dist/components/toolbar/toolbar-toggle-button.d.ts +8 -0
- package/dist/components/tooltip.d.ts +13 -0
- package/dist/fields/datasetFields/dimFields.d.ts +1 -1
- package/dist/fields/datasetFields/meaFields.d.ts +1 -1
- package/dist/fields/filterField/filterPill.d.ts +1 -1
- package/dist/fields/obComponents/obFContainer.d.ts +1 -1
- package/dist/fields/obComponents/obPill.d.ts +1 -1
- package/dist/graphic-walker.es.js +56487 -55304
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +501 -288
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/style.css +0 -1
- package/dist/utils/throttle.d.ts +5 -0
- package/dist/visualSettings/menubar.d.ts +8 -0
- package/package.json +4 -2
- package/src/App.tsx +0 -4
- package/src/components/callout.tsx +58 -0
- package/src/components/sizeSetting.tsx +61 -49
- package/src/components/tabs/pureTab.tsx +7 -1
- package/src/components/toolbar/components.tsx +110 -0
- package/src/components/toolbar/index.tsx +57 -0
- package/src/components/toolbar/toolbar-button.tsx +28 -0
- package/src/components/toolbar/toolbar-item.tsx +218 -0
- package/src/components/toolbar/toolbar-select-button.tsx +196 -0
- package/src/components/toolbar/toolbar-toggle-button.tsx +70 -0
- package/src/components/tooltip.tsx +135 -0
- package/src/empty_sheet.css +9 -0
- package/src/fields/aestheticFields.tsx +1 -1
- package/src/fields/datasetFields/dimFields.tsx +3 -3
- package/src/fields/datasetFields/index.tsx +2 -2
- package/src/fields/datasetFields/meaFields.tsx +3 -3
- package/src/fields/fieldsContext.tsx +1 -1
- package/src/fields/filterField/filterPill.tsx +1 -1
- package/src/fields/filterField/index.tsx +1 -1
- package/src/fields/obComponents/obFContainer.tsx +1 -1
- package/src/fields/obComponents/obPill.tsx +1 -1
- package/src/fields/posFields/index.tsx +1 -1
- package/src/global.d.ts +7 -0
- package/src/index.tsx +47 -8
- package/src/store/visualSpecStore.ts +1 -1
- package/src/utils/throttle.ts +28 -0
- package/src/visualSettings/index.tsx +316 -321
- package/src/visualSettings/menubar.tsx +1 -1
package/dist/index.d.ts
CHANGED
package/dist/style.css
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com *//*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */*,:before,:after{box-sizing:border-box}html{tab-size:4}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"}hr{height:0;color:inherit}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}button,[type=button],[type=submit]{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}button{background-color:transparent;background-image:none}fieldset{margin:0;padding:0}ol,ul{list-style:none;margin:0;padding:0}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}body{font-family:inherit;line-height:inherit}*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:currentColor}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{padding:0;line-height:inherit;color:inherit}pre,code,kbd,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-opacity: 1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.top-2{top:.5rem}.right-2{right:.5rem}.z-auto{z-index:auto}.col-span-1{grid-column:span 1 / span 1}.col-span-5{grid-column:span 5 / span 5}.float-right{float:right}.m-1{margin:.25rem}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mr-0{margin-right:0}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-0\.5{margin-right:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.-mb-px{margin-bottom:-1px}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-16{height:4rem}.h-48{height:12rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-16{width:4rem}.w-60{width:15rem}.w-full{width:100%}.min-w-96{min-width:96px}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.flex-shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.border-collapse{border-collapse:collapse}.transform{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{transform:scale(2);opacity:0}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.select-none{-webkit-user-select:none;user-select:none}.resize{resize:both}.appearance-none{-webkit-appearance:none;appearance:none}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-center{justify-content:center}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.rounded-sm{border-radius:.125rem}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.border-2{border-width:2px}.border{border-width:1px}.border-t-2{border-top-width:2px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-l{border-left-width:1px}.border-transparent{border-color:transparent}.border-gray-200{--tw-border-opacity: 1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity: 1;border-color:rgba(156,163,175,var(--tw-border-opacity))}.border-gray-500{--tw-border-opacity: 1;border-color:rgba(107,114,128,var(--tw-border-opacity))}.border-blue-400{--tw-border-opacity: 1;border-color:rgba(96,165,250,var(--tw-border-opacity))}.border-blue-500{--tw-border-opacity: 1;border-color:rgba(59,130,246,var(--tw-border-opacity))}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgba(209,213,219,var(--tw-border-opacity))}.hover\:border-gray-600:hover{--tw-border-opacity: 1;border-color:rgba(75,85,99,var(--tw-border-opacity))}.focus\:border-gray-500:focus{--tw-border-opacity: 1;border-color:rgba(107,114,128,var(--tw-border-opacity))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgba(59,130,246,var(--tw-border-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgba(156,163,175,var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgba(239,68,68,var(--tw-bg-opacity))}.bg-yellow-600{--tw-bg-opacity: 1;background-color:rgba(217,119,6,var(--tw-bg-opacity))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgba(37,99,235,var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity: 1;background-color:rgba(238,242,255,var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgba(249,250,251,var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.hover\:bg-red-100:hover{--tw-bg-opacity: 1;background-color:rgba(254,226,226,var(--tw-bg-opacity))}.hover\:bg-yellow-100:hover{--tw-bg-opacity: 1;background-color:rgba(254,243,199,var(--tw-bg-opacity))}.hover\:bg-yellow-500:hover{--tw-bg-opacity: 1;background-color:rgba(245,158,11,var(--tw-bg-opacity))}.hover\:bg-green-50:hover{--tw-bg-opacity: 1;background-color:rgba(236,253,245,var(--tw-bg-opacity))}.hover\:bg-blue-100:hover{--tw-bg-opacity: 1;background-color:rgba(219,234,254,var(--tw-bg-opacity))}.disabled\:bg-gray-300:disabled{--tw-bg-opacity: 1;background-color:rgba(209,213,219,var(--tw-bg-opacity))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-0\.5{padding-top:.125rem}.pr-2{padding-right:.5rem}.pr-6{padding-right:1.5rem}.pb-0{padding-bottom:0}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-0\.5{padding-bottom:.125rem}.pl-2{padding-left:.5rem}.pl-6{padding-left:1.5rem}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.ordinal{--tw-ordinal: var(--tw-empty, );--tw-slashed-zero: var(--tw-empty, );--tw-numeric-figure: var(--tw-empty, );--tw-numeric-spacing: var(--tw-empty, );--tw-numeric-fraction: var(--tw-empty, );font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.ordinal{--tw-ordinal: ordinal}.leading-none{line-height:1}.text-black{--tw-text-opacity: 1;color:rgba(0,0,0,var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgba(255,255,255,var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgba(209,213,219,var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgba(156,163,175,var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgba(107,114,128,var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgba(75,85,99,var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgba(55,65,81,var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgba(31,41,55,var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgba(17,24,39,var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgba(220,38,38,var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity: 1;color:rgba(245,158,11,var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgba(16,185,129,var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgba(59,130,246,var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgba(55,65,81,var(--tw-text-opacity))}.hover\:text-purple-600:hover{--tw-text-opacity: 1;color:rgba(124,58,237,var(--tw-text-opacity))}.underline{text-decoration:underline}*,:before,:after{--tw-shadow: 0 0 #0000}.shadow{--tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 2px 0 rgba(0, 0, 0, .06);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}*,:before,:after{--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgba(59, 130, 246, .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000}.filter{--tw-blur: var(--tw-empty, );--tw-brightness: var(--tw-empty, );--tw-contrast: var(--tw-empty, );--tw-grayscale: var(--tw-empty, );--tw-hue-rotate: var(--tw-empty, );--tw-invert: var(--tw-empty, );--tw-saturate: var(--tw-empty, );--tw-sepia: var(--tw-empty, );--tw-drop-shadow: var(--tw-empty, );filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur{--tw-blur: blur(8px)}@media (min-width: 768px){.md\:col-span-2{grid-column:span 2 / span 2}.md\:col-span-3{grid-column:span 3 / span 3}.md\:col-span-7{grid-column:span 7 / span 7}.md\:grid{display:grid}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:flex-col{flex-direction:column}}@media (min-width: 1280px){.xl\:col-span-1{grid-column:span 1 / span 1}.xl\:col-span-4{grid-column:span 4 / span 4}.xl\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export declare const MenubarContainer: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
3
|
+
interface ButtonWithShortcutProps {
|
|
4
|
+
label: string;
|
|
5
|
+
shortcut: string;
|
|
6
|
+
disabled: boolean;
|
|
7
|
+
handler: () => void;
|
|
8
|
+
icon?: JSX.Element;
|
|
9
|
+
}
|
|
10
|
+
export declare const ButtonWithShortcut: React.FC<ButtonWithShortcutProps>;
|
|
3
11
|
declare const _default: React.FunctionComponent<{}>;
|
|
4
12
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanaries/graphic-walker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev:front_end": "vite --host",
|
|
6
6
|
"dev": "npm run dev:front_end",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"types": "./dist/index.d.ts",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@heroicons/react": "^2.0.8",
|
|
36
|
+
"@kanaries/react-beautiful-dnd": "0.0.1",
|
|
36
37
|
"@kanaries/web-data-loader": "0.1.5",
|
|
37
38
|
"autoprefixer": "^10.3.5",
|
|
38
39
|
"i18next": "^21.9.1",
|
|
@@ -41,10 +42,11 @@
|
|
|
41
42
|
"mobx": "^6.3.3",
|
|
42
43
|
"mobx-react-lite": "^3.2.1",
|
|
43
44
|
"postcss": "^8.3.7",
|
|
45
|
+
"postinstall-postinstall": "^2.1.0",
|
|
44
46
|
"re-resizable": "^6.9.8",
|
|
45
|
-
"react-beautiful-dnd": "^13.1.1",
|
|
46
47
|
"react-i18next": "^11.18.6",
|
|
47
48
|
"react-json-view": "^1.21.3",
|
|
49
|
+
"react-shadow": "^20.0.0",
|
|
48
50
|
"rxjs": "^7.3.0",
|
|
49
51
|
"tailwindcss": "^2.2.15",
|
|
50
52
|
"uuid": "^8.3.2",
|
package/src/App.tsx
CHANGED
|
@@ -19,10 +19,7 @@ import { useGlobalStore } from './store';
|
|
|
19
19
|
import { preAnalysis, destroyWorker } from './services'
|
|
20
20
|
import VisNav from './segments/visNav';
|
|
21
21
|
import { mergeLocaleRes, setLocaleLanguage } from './locales/i18n';
|
|
22
|
-
import Menubar from './visualSettings/menubar';
|
|
23
22
|
import FilterField from './fields/filterField';
|
|
24
|
-
import "tailwindcss/tailwind.css"
|
|
25
|
-
import './index.css'
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
export interface EditorProps {
|
|
@@ -99,7 +96,6 @@ const App: React.FC<EditorProps> = props => {
|
|
|
99
96
|
{/* <PureTabs tabs={[{label: 'a', key: 'a'}, {label: 'b', key: 'b'}]} selectedKey='a' onSelected={() => {}} /> */}
|
|
100
97
|
</div>
|
|
101
98
|
<Container style={{ marginTop: '0em', borderTop: 'none' }}>
|
|
102
|
-
<Menubar />
|
|
103
99
|
<VisualSettings rendererHandler={rendererRef} />
|
|
104
100
|
<div className="md:grid md:grid-cols-12 xl:grid-cols-6">
|
|
105
101
|
<div className="md:col-span-3 xl:col-span-1">
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React, { memo, ReactNode, useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { ShadowDomContext } from '..';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export interface CalloutProps {
|
|
8
|
+
target: string;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Bubble = styled.div`
|
|
13
|
+
border-radius: 1px;
|
|
14
|
+
transform: translate(-50%, 0);
|
|
15
|
+
filter: drop-shadow(0 1.6px 1px rgba(0, 0, 0, 0.24)) drop-shadow(0 -1px 0.8px rgba(0, 0, 0, 0.19));
|
|
16
|
+
user-select: none;
|
|
17
|
+
display: block;
|
|
18
|
+
width: max-content;
|
|
19
|
+
height: max-content;
|
|
20
|
+
::before {
|
|
21
|
+
content: "";
|
|
22
|
+
display: block;
|
|
23
|
+
position: absolute;
|
|
24
|
+
top: 0;
|
|
25
|
+
left: 50%;
|
|
26
|
+
width: 8px;
|
|
27
|
+
height: 8px;
|
|
28
|
+
transform: translate(-50%, -50%) rotate(45deg);
|
|
29
|
+
background-color: #fff;
|
|
30
|
+
border-radius: 1px;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const Callout = memo<CalloutProps>(function Callout ({ target, children }) {
|
|
35
|
+
const shadowDomMeta = useContext(ShadowDomContext);
|
|
36
|
+
const { root } = shadowDomMeta;
|
|
37
|
+
const [pos, setPos] = useState<[number, number] | null>(null);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const el = (
|
|
41
|
+
target.startsWith('#') ? root?.getElementById(target.slice(1)) : root?.querySelector(target)
|
|
42
|
+
) as HTMLElement | null;
|
|
43
|
+
if (el) {
|
|
44
|
+
const rect = el.getBoundingClientRect();
|
|
45
|
+
setPos([rect.x + rect.width / 2, rect.y + rect.height]);
|
|
46
|
+
}
|
|
47
|
+
}, [target, root]);
|
|
48
|
+
|
|
49
|
+
return root && pos && createPortal(
|
|
50
|
+
<Bubble role="dialog" className="fixed bg-white z-50" style={{ left: pos[0], top: pos[1] + 4 }}>
|
|
51
|
+
{children}
|
|
52
|
+
</Bubble>,
|
|
53
|
+
root
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export default Callout;
|
|
@@ -10,6 +10,45 @@ interface SizeSettingProps {
|
|
|
10
10
|
height: number;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export const ResizeDialog: React.FC<SizeSettingProps> = props => {
|
|
14
|
+
const { onWidthChange, onHeightChange, width, height, children } = props
|
|
15
|
+
const { t } = useTranslation('translation', { keyPrefix: 'main.tabpanel.settings.size_setting' });
|
|
16
|
+
|
|
17
|
+
return <>
|
|
18
|
+
{children}
|
|
19
|
+
<div className="mt-4 w-60">
|
|
20
|
+
<input className="w-full h-2 bg-blue-100 appearance-none"
|
|
21
|
+
style={{ cursor: 'ew-resize' }}
|
|
22
|
+
type="range"
|
|
23
|
+
name="width"
|
|
24
|
+
value={Math.sqrt(width / 1000)}
|
|
25
|
+
min="0" max="1" step="0.01"
|
|
26
|
+
onChange={(e) => {
|
|
27
|
+
onWidthChange(Math.round(Number(e.target.value) ** 2 * 1000))
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
<output className="text-sm ml-1" htmlFor="width">
|
|
31
|
+
{`${t('width')}: ${width}`}
|
|
32
|
+
</output>
|
|
33
|
+
</div>
|
|
34
|
+
<div className=" mt-2">
|
|
35
|
+
<input className="w-full h-2 bg-blue-100 appearance-none"
|
|
36
|
+
style={{ cursor: 'ew-resize' }}
|
|
37
|
+
type="range"
|
|
38
|
+
name="height"
|
|
39
|
+
value={Math.sqrt(height / 1000)}
|
|
40
|
+
min="0" max="1" step="0.01"
|
|
41
|
+
onChange={(e) => {
|
|
42
|
+
onHeightChange(Math.round(Number(e.target.value) ** 2 * 1000))
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
<output className="text-sm ml-1" htmlFor="height">
|
|
46
|
+
{`${t('height')}: ${height}`}
|
|
47
|
+
</output>
|
|
48
|
+
</div>
|
|
49
|
+
</>
|
|
50
|
+
};
|
|
51
|
+
|
|
13
52
|
const SizeSetting: React.FC<SizeSettingProps> = props => {
|
|
14
53
|
const { onWidthChange, onHeightChange, width, height } = props
|
|
15
54
|
const [show, setShow] = useState<boolean>(false);
|
|
@@ -21,10 +60,17 @@ const SizeSetting: React.FC<SizeSettingProps> = props => {
|
|
|
21
60
|
setShow(false);
|
|
22
61
|
};
|
|
23
62
|
|
|
24
|
-
|
|
63
|
+
let subscribed = false;
|
|
64
|
+
const timer = setTimeout(() => {
|
|
65
|
+
subscribed = true;
|
|
66
|
+
document.body.addEventListener('click', closeDialog);
|
|
67
|
+
}, 200);
|
|
25
68
|
|
|
26
69
|
return () => {
|
|
27
|
-
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
if (subscribed) {
|
|
72
|
+
document.body.removeEventListener('click', closeDialog);
|
|
73
|
+
}
|
|
28
74
|
};
|
|
29
75
|
}
|
|
30
76
|
}, [show]);
|
|
@@ -41,54 +87,20 @@ const SizeSetting: React.FC<SizeSettingProps> = props => {
|
|
|
41
87
|
}}
|
|
42
88
|
className="w-4 h-4 inline-block mr-0.5 text-gray-900"
|
|
43
89
|
/>
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
|
-
|
|
59
|
-
<div className="mt-4 w-60">
|
|
60
|
-
<input className="w-full h-2 bg-blue-100 appearance-none"
|
|
61
|
-
style={{ cursor: 'ew-resize' }}
|
|
62
|
-
type="range"
|
|
63
|
-
name="width"
|
|
64
|
-
value={Math.sqrt(width / 1000)}
|
|
65
|
-
min="0" max="1" step="0.01"
|
|
66
|
-
onChange={(e) => {
|
|
67
|
-
onWidthChange(Math.round(Number(e.target.value) ** 2 * 1000))
|
|
68
|
-
}}
|
|
69
|
-
/>
|
|
70
|
-
<output className="text-sm ml-1" htmlFor="width">
|
|
71
|
-
{`${t('width')}: ${width}`}
|
|
72
|
-
</output>
|
|
73
|
-
</div>
|
|
74
|
-
<div className=" mt-2">
|
|
75
|
-
<input className="w-full h-2 bg-blue-100 appearance-none"
|
|
76
|
-
style={{ cursor: 'ew-resize' }}
|
|
77
|
-
type="range"
|
|
78
|
-
name="height"
|
|
79
|
-
value={Math.sqrt(height / 1000)}
|
|
80
|
-
min="0" max="1" step="0.01"
|
|
81
|
-
onChange={(e) => {
|
|
82
|
-
onHeightChange(Math.round(Number(e.target.value) ** 2 * 1000))
|
|
83
|
-
}}
|
|
84
|
-
/>
|
|
85
|
-
<output className="text-sm ml-1" htmlFor="height">
|
|
86
|
-
{`${t('height')}: ${height}`}
|
|
87
|
-
</output>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
+
{show && <ResizeDialog {...props}>
|
|
91
|
+
<div>
|
|
92
|
+
<XMarkIcon
|
|
93
|
+
className="text-gray-900 absolute right-2 top-2 w-4 cursor-pointer hover:bg-red-100"
|
|
94
|
+
role="button"
|
|
95
|
+
tabIndex={0}
|
|
96
|
+
aria-label="close"
|
|
97
|
+
onClick={(e) => {
|
|
98
|
+
setShow(false);
|
|
99
|
+
e.stopPropagation();
|
|
100
|
+
}}
|
|
101
|
+
/>
|
|
90
102
|
</div>
|
|
91
|
-
}
|
|
103
|
+
</ResizeDialog>}
|
|
92
104
|
</div>
|
|
93
105
|
}
|
|
94
106
|
|
|
@@ -28,7 +28,7 @@ export default function PureTabs(props: PureTabsProps) {
|
|
|
28
28
|
}, [tabs.length]);
|
|
29
29
|
|
|
30
30
|
useEffect(() => {
|
|
31
|
-
clearEditStatus
|
|
31
|
+
clearEditStatus();
|
|
32
32
|
}, [clearEditStatus]);
|
|
33
33
|
|
|
34
34
|
return (
|
|
@@ -55,6 +55,12 @@ export default function PureTabs(props: PureTabsProps) {
|
|
|
55
55
|
onInput={(e) => {
|
|
56
56
|
onEditLabel && onEditLabel(`${e.currentTarget.textContent}`, tabIndex)
|
|
57
57
|
}}
|
|
58
|
+
onKeyDown={(e) => {
|
|
59
|
+
if (e.key === 'Enter') {
|
|
60
|
+
clearEditStatus();
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
}
|
|
63
|
+
}}
|
|
58
64
|
key={tab.key}
|
|
59
65
|
className={classNames(
|
|
60
66
|
tab.key === selectedKey
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { KeyboardEvent, MouseEvent, useMemo, useRef } from "react";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const useHandlers = (action: () => void, disabled: boolean, triggerKeys: string[] = ['Enter'], allowPropagation = true) => {
|
|
6
|
+
const actionRef = useRef(action);
|
|
7
|
+
actionRef.current = () => {
|
|
8
|
+
if (disabled) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
action();
|
|
12
|
+
};
|
|
13
|
+
const triggerKeysRef = useRef(triggerKeys);
|
|
14
|
+
triggerKeysRef.current = triggerKeys;
|
|
15
|
+
|
|
16
|
+
return useMemo(() => ({
|
|
17
|
+
onClick: (ev: MouseEvent) => {
|
|
18
|
+
if (!allowPropagation) {
|
|
19
|
+
ev.stopPropagation();
|
|
20
|
+
}
|
|
21
|
+
actionRef.current();
|
|
22
|
+
},
|
|
23
|
+
onKeyDown: (ev: KeyboardEvent) => {
|
|
24
|
+
if (!allowPropagation) {
|
|
25
|
+
ev.stopPropagation();
|
|
26
|
+
}
|
|
27
|
+
if (triggerKeysRef.current.includes(ev.key)) {
|
|
28
|
+
ev.stopPropagation();
|
|
29
|
+
ev.preventDefault();
|
|
30
|
+
actionRef.current();
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
onMouseOut: (ev: MouseEvent) => {
|
|
34
|
+
if (!allowPropagation) {
|
|
35
|
+
ev.stopPropagation();
|
|
36
|
+
}
|
|
37
|
+
(document.querySelector('*:focus') as null | HTMLElement)?.blur();
|
|
38
|
+
},
|
|
39
|
+
}), [allowPropagation]);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const ToolbarContainer = styled.div`
|
|
43
|
+
--height: 36px;
|
|
44
|
+
--icon-size: 18px;
|
|
45
|
+
width: 100%;
|
|
46
|
+
height: var(--height);
|
|
47
|
+
background-color: var(--background-color);
|
|
48
|
+
color: var(--color);
|
|
49
|
+
/* box-shadow: 0px 1px 3px 1px rgba(136, 136, 136, 0.1); */
|
|
50
|
+
border-radius: 2px;
|
|
51
|
+
overflow: hidden;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: row;
|
|
54
|
+
> * {
|
|
55
|
+
flex-grow: 0;
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
|
|
60
|
+
export const ToolbarSplitter = styled.div`
|
|
61
|
+
display: inline-block;
|
|
62
|
+
margin: calc(var(--height) / 6) calc(var(--icon-size) / 4);
|
|
63
|
+
height: calc(var(--height) * 2 / 3);
|
|
64
|
+
width: 1px;
|
|
65
|
+
background: #bbbbbb50;
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
export const ToolbarItemContainerElement = styled.div<{ split: boolean }>`
|
|
69
|
+
display: inline-flex;
|
|
70
|
+
flex-direction: row;
|
|
71
|
+
user-select: none;
|
|
72
|
+
outline: none;
|
|
73
|
+
width: ${({ split }) => split ? 'calc(var(--height) + 10px)' : 'var(--height)'};
|
|
74
|
+
height: var(--height);
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
color: var(--color);
|
|
77
|
+
position: relative;
|
|
78
|
+
> svg {
|
|
79
|
+
flex-grow: 0;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
width: var(--icon-size);
|
|
82
|
+
height: var(--icon-size);
|
|
83
|
+
margin: calc((var(--height) - var(--icon-size)) / 2);
|
|
84
|
+
margin-right: ${({ split }) => split ? 'calc((var(--height) - var(--icon-size)) / 4)' : ''};
|
|
85
|
+
transition: text-shadow 100ms;
|
|
86
|
+
}
|
|
87
|
+
--shadow-color: #0F172A55;
|
|
88
|
+
&[aria-disabled=true] {
|
|
89
|
+
cursor: default;
|
|
90
|
+
> * {
|
|
91
|
+
opacity: 0.33;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
&[aria-disabled=false] {
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
:hover, :focus, &.open {
|
|
97
|
+
background-image: linear-gradient(#FFFFFFCC, #FEFEFECC);
|
|
98
|
+
--background-color: #FEFEFE;
|
|
99
|
+
color: var(--color-hover);
|
|
100
|
+
&.split * svg {
|
|
101
|
+
pointer-events: none;
|
|
102
|
+
transform: translate(-50%, -20%);
|
|
103
|
+
}
|
|
104
|
+
& svg {
|
|
105
|
+
text-shadow: 0 0 1.5px var(--shadow-color);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
transition: color 100ms, background-image 100ms;
|
|
110
|
+
`;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { CSSProperties, memo, ReactNode, useState } from "react";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
import { ToolbarContainer, ToolbarSplitter } from "./components";
|
|
4
|
+
import ToolbarItem, { ToolbarItemProps, ToolbarItemSplitter } from "./toolbar-item";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const Root = styled.div`
|
|
8
|
+
width: 100%;
|
|
9
|
+
--background-color: #f7f7f7;
|
|
10
|
+
--color: #777;
|
|
11
|
+
--color-hover: #555;
|
|
12
|
+
--blue: #282958;
|
|
13
|
+
--blue-dark: #1d1e38;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
export interface ToolbarProps {
|
|
17
|
+
items: ToolbarItemProps[];
|
|
18
|
+
styles?: Partial<{
|
|
19
|
+
root: CSSProperties & Record<string, string>;
|
|
20
|
+
container: CSSProperties & Record<string, string>;
|
|
21
|
+
item: CSSProperties & Record<string, string>;
|
|
22
|
+
icon: CSSProperties & Record<string, string>;
|
|
23
|
+
splitIcon: CSSProperties & Record<string, string>;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const Toolbar = memo<ToolbarProps>(function Toolbar ({ items, styles }) {
|
|
28
|
+
const [openedKey, setOpenedKey] = useState<string | null>(null);
|
|
29
|
+
const [slot, setSlot] = useState<ReactNode>(null);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Root style={styles?.root}>
|
|
33
|
+
<ToolbarContainer style={styles?.container}>
|
|
34
|
+
{items.map((item, i) => {
|
|
35
|
+
if (item === ToolbarItemSplitter) {
|
|
36
|
+
return <ToolbarSplitter key={i} />;
|
|
37
|
+
}
|
|
38
|
+
return (
|
|
39
|
+
<ToolbarItem
|
|
40
|
+
key={item.key}
|
|
41
|
+
item={item}
|
|
42
|
+
styles={styles}
|
|
43
|
+
openedKey={openedKey}
|
|
44
|
+
setOpenedKey={setOpenedKey}
|
|
45
|
+
renderSlot={node => setSlot(node)}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
})}
|
|
49
|
+
</ToolbarContainer>
|
|
50
|
+
{slot}
|
|
51
|
+
</Root>
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
export default Toolbar;
|
|
57
|
+
export type { ToolbarItemProps };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { memo } from "react";
|
|
2
|
+
import { IToolbarItem, IToolbarProps, ToolbarItemContainer } from "./toolbar-item";
|
|
3
|
+
import { useHandlers } from "./components";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export interface ToolbarButtonItem extends IToolbarItem {
|
|
7
|
+
onClick?: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ToolbarButton = memo<IToolbarProps<ToolbarButtonItem>>(function ToolbarButton(props) {
|
|
11
|
+
const { item, styles } = props;
|
|
12
|
+
const { icon: Icon, label, disabled, onClick } = item;
|
|
13
|
+
const handlers = useHandlers(() => onClick?.(), disabled ?? false);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
<ToolbarItemContainer
|
|
18
|
+
props={props}
|
|
19
|
+
handlers={onClick ? handlers : null}
|
|
20
|
+
>
|
|
21
|
+
<Icon style={styles?.icon} />
|
|
22
|
+
</ToolbarItemContainer>
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export default ToolbarButton;
|