@storkspear/post-editor-react 0.1.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.
- package/LICENSE +21 -0
- package/README.md +12 -0
- package/dist/ColorPicker.d.ts +11 -0
- package/dist/ColorPicker.d.ts.map +1 -0
- package/dist/ColorPicker.js +30 -0
- package/dist/ColorPicker.js.map +1 -0
- package/dist/DrawioModal.d.ts +9 -0
- package/dist/DrawioModal.d.ts.map +1 -0
- package/dist/DrawioModal.js +97 -0
- package/dist/DrawioModal.js.map +1 -0
- package/dist/FontMenu.d.ts +14 -0
- package/dist/FontMenu.d.ts.map +1 -0
- package/dist/FontMenu.js +14 -0
- package/dist/FontMenu.js.map +1 -0
- package/dist/Icon.d.ts +69 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/Icon.js +47 -0
- package/dist/Icon.js.map +1 -0
- package/dist/InsertHandle.d.ts +14 -0
- package/dist/InsertHandle.d.ts.map +1 -0
- package/dist/InsertHandle.js +60 -0
- package/dist/InsertHandle.js.map +1 -0
- package/dist/PickMenu.d.ts +61 -0
- package/dist/PickMenu.d.ts.map +1 -0
- package/dist/PickMenu.js +57 -0
- package/dist/PickMenu.js.map +1 -0
- package/dist/Popover.d.ts +20 -0
- package/dist/Popover.d.ts.map +1 -0
- package/dist/Popover.js +22 -0
- package/dist/Popover.js.map +1 -0
- package/dist/PostTitle.d.ts +33 -0
- package/dist/PostTitle.d.ts.map +1 -0
- package/dist/PostTitle.js +171 -0
- package/dist/PostTitle.js.map +1 -0
- package/dist/SelectionBubble.d.ts +6 -0
- package/dist/SelectionBubble.d.ts.map +1 -0
- package/dist/SelectionBubble.js +71 -0
- package/dist/SelectionBubble.js.map +1 -0
- package/dist/TableTools.d.ts +10 -0
- package/dist/TableTools.d.ts.map +1 -0
- package/dist/TableTools.js +200 -0
- package/dist/TableTools.js.map +1 -0
- package/dist/Toolbar.d.ts +17 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Toolbar.js +333 -0
- package/dist/Toolbar.js.map +1 -0
- package/dist/UrlPrompt.d.ts +24 -0
- package/dist/UrlPrompt.d.ts.map +1 -0
- package/dist/UrlPrompt.js +53 -0
- package/dist/UrlPrompt.js.map +1 -0
- package/dist/VariantMenu.d.ts +47 -0
- package/dist/VariantMenu.d.ts.map +1 -0
- package/dist/VariantMenu.js +21 -0
- package/dist/VariantMenu.js.map +1 -0
- package/dist/WidthToggle.d.ts +19 -0
- package/dist/WidthToggle.d.ts.map +1 -0
- package/dist/WidthToggle.js +17 -0
- package/dist/WidthToggle.js.map +1 -0
- package/dist/bubbleShows.d.ts +10 -0
- package/dist/bubbleShows.d.ts.map +1 -0
- package/dist/bubbleShows.js +29 -0
- package/dist/bubbleShows.js.map +1 -0
- package/dist/content-baked.d.ts +22 -0
- package/dist/content-baked.d.ts.map +1 -0
- package/dist/content-baked.js +21 -0
- package/dist/content-baked.js.map +1 -0
- package/dist/content.d.ts +29 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +35 -0
- package/dist/content.js.map +1 -0
- package/dist/extensions/DiagramView.d.ts +26 -0
- package/dist/extensions/DiagramView.d.ts.map +1 -0
- package/dist/extensions/DiagramView.js +146 -0
- package/dist/extensions/DiagramView.js.map +1 -0
- package/dist/extensions/FigureView.d.ts +3 -0
- package/dist/extensions/FigureView.d.ts.map +1 -0
- package/dist/extensions/FigureView.js +108 -0
- package/dist/extensions/FigureView.js.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/dist/objects/ObjectFloat.d.ts +11 -0
- package/dist/objects/ObjectFloat.d.ts.map +1 -0
- package/dist/objects/ObjectFloat.js +42 -0
- package/dist/objects/ObjectFloat.js.map +1 -0
- package/dist/objects/ObjectLayer.d.ts +10 -0
- package/dist/objects/ObjectLayer.d.ts.map +1 -0
- package/dist/objects/ObjectLayer.js +20 -0
- package/dist/objects/ObjectLayer.js.map +1 -0
- package/dist/objects/blockSize.d.ts +30 -0
- package/dist/objects/blockSize.d.ts.map +1 -0
- package/dist/objects/blockSize.js +56 -0
- package/dist/objects/blockSize.js.map +1 -0
- package/dist/objects/code.d.ts +3 -0
- package/dist/objects/code.d.ts.map +1 -0
- package/dist/objects/code.js +55 -0
- package/dist/objects/code.js.map +1 -0
- package/dist/objects/diagram.d.ts +21 -0
- package/dist/objects/diagram.d.ts.map +1 -0
- package/dist/objects/diagram.js +109 -0
- package/dist/objects/diagram.js.map +1 -0
- package/dist/objects/diagramGlyphs.d.ts +12 -0
- package/dist/objects/diagramGlyphs.d.ts.map +1 -0
- package/dist/objects/diagramGlyphs.js +49 -0
- package/dist/objects/diagramGlyphs.js.map +1 -0
- package/dist/objects/divider.d.ts +22 -0
- package/dist/objects/divider.d.ts.map +1 -0
- package/dist/objects/divider.js +60 -0
- package/dist/objects/divider.js.map +1 -0
- package/dist/objects/figure.d.ts +3 -0
- package/dist/objects/figure.d.ts.map +1 -0
- package/dist/objects/figure.js +62 -0
- package/dist/objects/figure.js.map +1 -0
- package/dist/objects/imageRow.d.ts +3 -0
- package/dist/objects/imageRow.d.ts.map +1 -0
- package/dist/objects/imageRow.js +29 -0
- package/dist/objects/imageRow.js.map +1 -0
- package/dist/objects/quote.d.ts +6 -0
- package/dist/objects/quote.d.ts.map +1 -0
- package/dist/objects/quote.js +13 -0
- package/dist/objects/quote.js.map +1 -0
- package/dist/objects/quoteGlyphs.d.ts +6 -0
- package/dist/objects/quoteGlyphs.d.ts.map +1 -0
- package/dist/objects/quoteGlyphs.js +28 -0
- package/dist/objects/quoteGlyphs.js.map +1 -0
- package/dist/objects/quoteRow.d.ts +3 -0
- package/dist/objects/quoteRow.d.ts.map +1 -0
- package/dist/objects/quoteRow.js +61 -0
- package/dist/objects/quoteRow.js.map +1 -0
- package/dist/objects/registry.d.ts +60 -0
- package/dist/objects/registry.d.ts.map +1 -0
- package/dist/objects/registry.js +45 -0
- package/dist/objects/registry.js.map +1 -0
- package/dist/objects/table.d.ts +11 -0
- package/dist/objects/table.d.ts.map +1 -0
- package/dist/objects/table.js +136 -0
- package/dist/objects/table.js.map +1 -0
- package/dist/objects/useDomRect.d.ts +14 -0
- package/dist/objects/useDomRect.d.ts.map +1 -0
- package/dist/objects/useDomRect.js +32 -0
- package/dist/objects/useDomRect.js.map +1 -0
- package/dist/objects/useEngaged.d.ts +14 -0
- package/dist/objects/useEngaged.d.ts.map +1 -0
- package/dist/objects/useEngaged.js +41 -0
- package/dist/objects/useEngaged.js.map +1 -0
- package/dist/pickItems.d.ts +36 -0
- package/dist/pickItems.d.ts.map +1 -0
- package/dist/pickItems.js +40 -0
- package/dist/pickItems.js.map +1 -0
- package/dist/recentColors.d.ts +7 -0
- package/dist/recentColors.d.ts.map +1 -0
- package/dist/recentColors.js +30 -0
- package/dist/recentColors.js.map +1 -0
- package/dist/seeds/drawio/aws.d.ts +15 -0
- package/dist/seeds/drawio/aws.d.ts.map +1 -0
- package/dist/seeds/drawio/aws.js +15 -0
- package/dist/seeds/drawio/aws.js.map +1 -0
- package/dist/seeds/drawio/azure.d.ts +14 -0
- package/dist/seeds/drawio/azure.d.ts.map +1 -0
- package/dist/seeds/drawio/azure.js +14 -0
- package/dist/seeds/drawio/azure.js.map +1 -0
- package/dist/seeds/drawio/ec2docker.d.ts +15 -0
- package/dist/seeds/drawio/ec2docker.d.ts.map +1 -0
- package/dist/seeds/drawio/ec2docker.js +15 -0
- package/dist/seeds/drawio/ec2docker.js.map +1 -0
- package/dist/seeds/drawio/userflow.d.ts +21 -0
- package/dist/seeds/drawio/userflow.d.ts.map +1 -0
- package/dist/seeds/drawio/userflow.js +21 -0
- package/dist/seeds/drawio/userflow.js.map +1 -0
- package/dist/seeds/mermaid.d.ts +19 -0
- package/dist/seeds/mermaid.d.ts.map +1 -0
- package/dist/seeds/mermaid.js +82 -0
- package/dist/seeds/mermaid.js.map +1 -0
- package/dist/useAnchoredPos.d.ts +22 -0
- package/dist/useAnchoredPos.d.ts.map +1 -0
- package/dist/useAnchoredPos.js +57 -0
- package/dist/useAnchoredPos.js.map +1 -0
- package/dist/useDismiss.d.ts +17 -0
- package/dist/useDismiss.d.ts.map +1 -0
- package/dist/useDismiss.js +36 -0
- package/dist/useDismiss.js.map +1 -0
- package/dist/useLastVariant.d.ts +9 -0
- package/dist/useLastVariant.d.ts.map +1 -0
- package/dist/useLastVariant.js +33 -0
- package/dist/useLastVariant.js.map +1 -0
- package/dist/useUploadCount.d.ts +3 -0
- package/dist/useUploadCount.d.ts.map +1 -0
- package/dist/useUploadCount.js +9 -0
- package/dist/useUploadCount.js.map +1 -0
- package/package.json +57 -0
- package/src/editor-ui.css +737 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 storkspear
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @storkspear/post-editor-react
|
|
2
|
+
|
|
3
|
+
`@storkspear/post-editor-core` 의 React UI — 툴바·글자 버블·객체 도구·좌측 `+`.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { PostEditor } from '@storkspear/post-editor-react'
|
|
7
|
+
import '@storkspear/post-editor-core/styles.css'
|
|
8
|
+
import '@storkspear/post-editor-react/styles.css'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**공개 페이지는 이 패키지의 `index` 를 쓰면 안 된다.** 편집기 전체가 딸려 온다.
|
|
12
|
+
읽기 전용은 `@storkspear/post-editor-react/content` 에서 `PostContent` 만 가져온다.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
export declare function ColorPicker({ value, onPick, onClear, onClose, label, recent, anchorRef, }: {
|
|
3
|
+
anchorRef?: RefObject<HTMLElement | null>;
|
|
4
|
+
value?: string;
|
|
5
|
+
onPick: (hex: string) => void;
|
|
6
|
+
onClear: () => void;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
label: string;
|
|
9
|
+
recent?: string[];
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=ColorPicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorPicker.d.ts","sourceRoot":"","sources":["../src/ColorPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAsB9C,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAW,EAAE,SAAS,GAC/D,EAAE;IACD,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;IACzC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAClB,+BA0CA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { useAnchoredPos } from './useAnchoredPos.js';
|
|
4
|
+
import { useDismiss } from './useDismiss.js';
|
|
5
|
+
import { Portal } from './Popover.js';
|
|
6
|
+
/**
|
|
7
|
+
* 색 팔레트 — 네이버처럼 격자로 펼치되, 채도가 튀는 원색 대신 단계가 고른 색을 쓴다.
|
|
8
|
+
* 열 = 색상, 행 = 밝기. 맨 앞은 "색 없음".
|
|
9
|
+
*/
|
|
10
|
+
const HUES = [
|
|
11
|
+
['회색', ['#f1f3f5', '#dee2e6', '#adb5bd', '#5c636a', '#16191d']],
|
|
12
|
+
['빨강', ['#ffe3e3', '#ffa8a8', '#fa5252', '#c92a2a', '#801515']],
|
|
13
|
+
['주황', ['#ffe8cc', '#ffc078', '#fd7e14', '#d9480f', '#8c2d04']],
|
|
14
|
+
['노랑', ['#fff3bf', '#ffe066', '#fab005', '#e67700', '#8a4b00']],
|
|
15
|
+
['초록', ['#d3f9d8', '#8ce99a', '#40c057', '#2b8a3e', '#14532d']],
|
|
16
|
+
['청록', ['#c3fae8', '#63e6be', '#12b886', '#087f5b', '#0b3d2e']],
|
|
17
|
+
['하늘', ['#d0ebff', '#74c0fc', '#228be6', '#1864ab', '#0b3c69']],
|
|
18
|
+
['파랑', ['#dbe4ff', '#91a7ff', '#4c6ef5', '#3b5bdb', '#1e3a8a']],
|
|
19
|
+
['보라', ['#e5dbff', '#b197fc', '#7950f2', '#5f3dc4', '#3b2380']],
|
|
20
|
+
['분홍', ['#ffdeeb', '#faa2c1', '#e64980', '#a61e4d', '#6b1233']],
|
|
21
|
+
];
|
|
22
|
+
export function ColorPicker({ value, onPick, onClear, onClose, label, recent = [], anchorRef, }) {
|
|
23
|
+
const ref = useRef(null);
|
|
24
|
+
const pos = useAnchoredPos(anchorRef ?? { current: null }, !!anchorRef, 280, ref);
|
|
25
|
+
// 여는 버튼을 「바깥」으로 치면 다시 눌러도 안 닫힌다(mousedown 이 닫고 click 이 도로 연다).
|
|
26
|
+
// 그 함정을 이미 한 번 밟아서 useDismiss 가 anchor 를 받게 만들어 뒀다 — 팔레트도 같은 규약을 쓴다.
|
|
27
|
+
useDismiss(true, ref, onClose, anchorRef);
|
|
28
|
+
return (_jsx(Portal, { active: !!pos, children: _jsxs("div", { className: "cp", "data-editor-ui": "", ref: ref, role: "dialog", "aria-label": label, style: pos ? { position: 'fixed', left: pos.left, top: pos.top, maxHeight: pos.maxHeight, overflowY: 'auto' } : undefined, children: [_jsx("div", { className: "cp-head", children: label }), recent.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "cp-sub", children: "\uCD5C\uADFC \uC0AC\uC6A9\uD55C \uC0C9" }), _jsx("div", { className: "cp-recent", children: recent.map((hex) => (_jsx("button", { className: "cp-cell", style: { background: hex }, title: hex, onMouseDown: (e) => e.preventDefault(), onClick: () => { onPick(hex); onClose(); } }, hex))) })] })), _jsxs("div", { className: "cp-grid", children: [_jsx("button", { className: "cp-cell cp-none", title: "\uC0C9 \uC5C6\uC74C", onMouseDown: (e) => e.preventDefault(), onClick: () => { onClear(); onClose(); }, children: _jsx("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: _jsx("line", { x1: "3", y1: "17", x2: "17", y2: "3" }) }) }), HUES.map(([name, shades]) => (_jsx("div", { className: "cp-col", children: shades.map((hex) => (_jsx("button", { className: `cp-cell${value?.toLowerCase() === hex ? ' is-on' : ''}`, style: { background: hex }, title: `${name} ${hex}`, "aria-label": `${name} ${hex}`, onMouseDown: (e) => e.preventDefault(), onClick: () => { onPick(hex); onClose(); } }, hex))) }, name)))] })] }) }));
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=ColorPicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorPicker.js","sourceRoot":"","sources":["../src/ColorPicker.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAElC;;;GAGG;AACH,MAAM,IAAI,GAAyB;IACjC,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;CAChE,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,EAAE,SAAS,GAS/D;IACC,MAAM,GAAG,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IACxC,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IACjF,+DAA+D;IAC/D,qEAAqE;IACrE,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,CAAA;IAEzC,OAAO,CACL,KAAC,MAAM,IAAC,MAAM,EAAE,CAAC,CAAC,GAAG,YACrB,eAAK,SAAS,EAAC,IAAI,oBAAgB,EAAE,EAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,QAAQ,gBAAa,KAAK,EAC7E,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,aACzH,cAAK,SAAS,EAAC,SAAS,YAAE,KAAK,GAAO,EACrC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CACpB,8BACE,cAAK,SAAS,EAAC,QAAQ,uDAAe,EACtC,cAAK,SAAS,EAAC,WAAW,YACvB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACnB,iBAAkB,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,EAC1E,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAA,CAAC,CAAC,IADtE,GAAG,CACuE,CACxF,CAAC,GACE,IACL,CACJ,EACD,eAAK,SAAS,EAAC,SAAS,aACtB,iBAAQ,SAAS,EAAC,iBAAiB,EAAC,KAAK,EAAC,qBAAM,EAC9C,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAA,CAAC,CAAC,YAC/E,cAAK,OAAO,EAAC,WAAW,iBAAa,MAAM,YAAC,eAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,GAAG,GAAM,GACjF,EACR,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAC5B,cAAK,SAAS,EAAC,QAAQ,YACpB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACnB,iBAAkB,SAAS,EAAE,UAAU,KAAK,EAAE,WAAW,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EACnF,KAAK,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,gBAAc,GAAG,IAAI,IAAI,GAAG,EAAE,EACjF,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,EAAE,EACtC,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAA,CAAC,CAAC,IAH9B,GAAG,CAG+B,CAChD,CAAC,IANyB,IAAI,CAO3B,CACP,CAAC,IACE,IACF,GACG,CACV,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawioModal.d.ts","sourceRoot":"","sources":["../src/DrawioModal.tsx"],"names":[],"mappings":"AAiCA,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,QAAQ,GACT,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IACpD,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB,+BA6EA"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
/**
|
|
5
|
+
* draw.io 를 iframe 으로 띄운다.
|
|
6
|
+
*
|
|
7
|
+
* ## 왜 iframe 인가
|
|
8
|
+
*
|
|
9
|
+
* AWS·Azure·GCP 아이콘까지 포함해 도형이 1만 개다. 그걸 우리 번들에 넣을 방법은 없고,
|
|
10
|
+
* 넣을 이유도 없다 — 공식 임베드 모드가 `postMessage` 로 말을 주고받는 길을 열어 뒀다.
|
|
11
|
+
* **라이브러리를 하나도 안 싣는다.**
|
|
12
|
+
*
|
|
13
|
+
* ## 주고받는 말
|
|
14
|
+
*
|
|
15
|
+
* iframe → 우리 init 준비됐다. `load` 를 달라
|
|
16
|
+
* save 사용자가 저장을 눌렀다 (xml 이 딸려 온다)
|
|
17
|
+
* export 내보내기가 끝났다 (data 가 딸려 온다)
|
|
18
|
+
* exit 나가겠다
|
|
19
|
+
* 우리 → iframe load 이 도면을 열어라
|
|
20
|
+
* export 이 형식으로 내놔라
|
|
21
|
+
*
|
|
22
|
+
* 저장 흐름은 **save → export(xmlsvg) → 닫기** 다. `xmlsvg` 는 도면 XML 이 박힌 SVG 라
|
|
23
|
+
* 그림과 원본이 한 덩어리지만, 우리는 원본을 따로 들고 있으므로 **SVG 만 쓰고 XML 은
|
|
24
|
+
* `save` 가 준 것을 쓴다** — 속성에서 XML 을 다시 캐내는 일을 안 하려고.
|
|
25
|
+
*
|
|
26
|
+
* ## 밖으로 무엇이 나가나
|
|
27
|
+
*
|
|
28
|
+
* 도면 XML 이 iframe 안에서 돈다(embed.diagrams.net). 저장은 우리 서버로만 간다 —
|
|
29
|
+
* 그쪽에 파일이 남지 않는다. 그게 걸리면 draw.io 를 직접 띄우고 `EMBED_URL` 만 바꾸면 된다.
|
|
30
|
+
*/
|
|
31
|
+
const EMBED_URL = 'https://embed.diagrams.net/?embed=1&ui=min&spin=1&proto=json&noSaveBtn=0&saveAndExit=1&noExitBtn=0&libraries=1';
|
|
32
|
+
export function DrawioModal({ xml, onDone, onCancel, }) {
|
|
33
|
+
const frameRef = useRef(null);
|
|
34
|
+
const xmlRef = useRef(xml);
|
|
35
|
+
const [ready, setReady] = useState(false);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const send = (msg) => frameRef.current?.contentWindow?.postMessage(JSON.stringify(msg), '*');
|
|
38
|
+
const onMsg = (e) => {
|
|
39
|
+
/* 우리 iframe 이 보낸 것만 듣는다 — 다른 창이 흉내 내지 못하게 */
|
|
40
|
+
if (e.source !== frameRef.current?.contentWindow)
|
|
41
|
+
return;
|
|
42
|
+
let m;
|
|
43
|
+
try {
|
|
44
|
+
m = JSON.parse(String(e.data));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (m.event === 'init') {
|
|
50
|
+
setReady(true);
|
|
51
|
+
send({ action: 'load', autosave: 0, xml: xmlRef.current || '' });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (m.event === 'save') {
|
|
55
|
+
/* 저장한 XML 을 들고, 그림은 따로 뽑는다 */
|
|
56
|
+
xmlRef.current = m.xml ?? xmlRef.current;
|
|
57
|
+
send({ action: 'export', format: 'xmlsvg', spin: '내보내는 중' });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (m.event === 'export') {
|
|
61
|
+
const data = String(m.data ?? '');
|
|
62
|
+
/* data:image/svg+xml;base64,… 로 온다 */
|
|
63
|
+
const svg = data.startsWith('data:')
|
|
64
|
+
? decodeURIComponent(escape(atob(data.slice(data.indexOf(',') + 1))))
|
|
65
|
+
: data;
|
|
66
|
+
onDone({ xml: xmlRef.current, svg });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (m.event === 'exit')
|
|
70
|
+
onCancel();
|
|
71
|
+
};
|
|
72
|
+
window.addEventListener('message', onMsg);
|
|
73
|
+
return () => window.removeEventListener('message', onMsg);
|
|
74
|
+
}, [onDone, onCancel]);
|
|
75
|
+
/* Esc 로 닫기 — 편집기가 이 키를 먹지 않게 여기서 멈춘다 */
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const onKey = (e) => {
|
|
78
|
+
if (e.key === 'Escape') {
|
|
79
|
+
e.stopPropagation();
|
|
80
|
+
onCancel();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
window.addEventListener('keydown', onKey, true);
|
|
84
|
+
return () => window.removeEventListener('keydown', onKey, true);
|
|
85
|
+
}, [onCancel]);
|
|
86
|
+
/**
|
|
87
|
+
* **`document.body` 로 내보낸다(포털).**
|
|
88
|
+
*
|
|
89
|
+
* 이 컴포넌트는 툴바 줄 안에서 그려지는데, 그 줄은 제 쌓임 맥락(sticky + z-index)을 만든다.
|
|
90
|
+
* 그 안에서는 `position: fixed; z-index: 200` 이 바깥의 머리줄을 못 이긴다 —
|
|
91
|
+
* 화면을 덮은 것처럼 보이지만 머리줄이 그 위에 남고 iframe 이 잘린다. 실제로 그랬다.
|
|
92
|
+
*/
|
|
93
|
+
return createPortal(_jsxs("div", { className: "dio", "data-editor-ui": "", role: "dialog", "aria-modal": "true", "aria-label": "\uB2E4\uC774\uC5B4\uADF8\uB7A8 \uADF8\uB9AC\uAE30", children: [_jsxs("div", { className: "dio-bar", children: [_jsx("span", { className: "dio-t", children: "\uB2E4\uC774\uC5B4\uADF8\uB7A8 \uADF8\uB9AC\uAE30" }), _jsx("span", { className: "dio-hint", children: "\uC800\uC7A5 \uC2DC, \uC791\uC131\uD558\uB358 \uD654\uBA74\uC73C\uB85C \uB418\uB3CC\uC544\uAC11\uB2C8\uB2E4." }), _jsx("button", { type: "button", className: "dio-x", onClick: onCancel, "aria-label": "\uB2EB\uAE30", children: "\u2715" })] }), !ready && _jsx("p", { className: "dio-wait", children: "draw.io \uB97C \uBD88\uB7EC\uC624\uB294 \uC911\u2026" }), _jsx("iframe", { ref: frameRef, className: "dio-frame", src: EMBED_URL, title: "draw.io",
|
|
94
|
+
/* 저장은 postMessage 로만 온다 — 이 창이 우리 쪽을 직접 만지지 못하게 */
|
|
95
|
+
sandbox: "allow-scripts allow-same-origin allow-popups allow-forms" })] }), document.body);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=DrawioModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawioModal.js","sourceRoot":"","sources":["../src/DrawioModal.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 글꼴 고르기 — 이름을 **그 글꼴로** 보여 준다(네이버 블로그와 같은 방식).
|
|
3
|
+
* 이름만 나열하면 「고운바탕」이 어떻게 생겼는지 모른 채 골라야 한다.
|
|
4
|
+
*
|
|
5
|
+
* 고르는 칸의 공통 부품(PickMenu)에 글꼴만 얹은 것이다 —
|
|
6
|
+
* 문단 스타일·글자 크기·언어가 전부 같은 메뉴를 쓴다.
|
|
7
|
+
*/
|
|
8
|
+
export declare function FontMenu({ value, onPick, onClose, anchorRef }: {
|
|
9
|
+
value: string;
|
|
10
|
+
onPick: (v: string) => void;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=FontMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FontMenu.d.ts","sourceRoot":"","sources":["../src/FontMenu.tsx"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE;IAC9D,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;CAC/C,+BAKA"}
|
package/dist/FontMenu.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PickMenu } from './PickMenu.js';
|
|
3
|
+
import { fontItems } from './pickItems.js';
|
|
4
|
+
/**
|
|
5
|
+
* 글꼴 고르기 — 이름을 **그 글꼴로** 보여 준다(네이버 블로그와 같은 방식).
|
|
6
|
+
* 이름만 나열하면 「고운바탕」이 어떻게 생겼는지 모른 채 골라야 한다.
|
|
7
|
+
*
|
|
8
|
+
* 고르는 칸의 공통 부품(PickMenu)에 글꼴만 얹은 것이다 —
|
|
9
|
+
* 문단 스타일·글자 크기·언어가 전부 같은 메뉴를 쓴다.
|
|
10
|
+
*/
|
|
11
|
+
export function FontMenu({ value, onPick, onClose, anchorRef }) {
|
|
12
|
+
return (_jsx(PickMenu, { ariaLabel: "\uAE00\uAF34", width: 200, items: fontItems(), value: value, onPick: onPick, onClose: onClose, anchorRef: anchorRef }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=FontMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FontMenu.js","sourceRoot":"","sources":["../src/FontMenu.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAK3D;IACC,OAAO,CACL,KAAC,QAAQ,IAAC,SAAS,EAAC,cAAI,EAAC,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,KAAK,EACnE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAI,CAC7D,CAAA;AACH,CAAC"}
|
package/dist/Icon.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 툴바 아이콘 — lucide-react 를 쓴다.
|
|
3
|
+
*
|
|
4
|
+
* 직접 그리지 않는 이유: 손으로 그린 SVG 는 획 굵기·여백·시각 중심이 제각각이라
|
|
5
|
+
* 나란히 놓으면 티가 나고, 아이콘이 늘 때마다 그 부담이 커진다.
|
|
6
|
+
* template-react-admin 도 lucide-react 를 쓰므로 스택도 맞는다.
|
|
7
|
+
*
|
|
8
|
+
* 호출부는 이름만 알면 되게 얇게 감싼다 — 나중에 라이브러리를 바꿔도 여기만 고친다.
|
|
9
|
+
* (라이브러리 분리 시 이 파일은 react 패키지로 간다. core 는 아이콘을 모른다.)
|
|
10
|
+
*/
|
|
11
|
+
declare const MAP: {
|
|
12
|
+
readonly bold: import("lucide-react").LucideIcon;
|
|
13
|
+
readonly italic: import("lucide-react").LucideIcon;
|
|
14
|
+
readonly underline: import("lucide-react").LucideIcon;
|
|
15
|
+
readonly strike: import("lucide-react").LucideIcon;
|
|
16
|
+
readonly code: import("lucide-react").LucideIcon;
|
|
17
|
+
readonly highlight: import("lucide-react").LucideIcon;
|
|
18
|
+
readonly h2: import("lucide-react").LucideIcon;
|
|
19
|
+
readonly h3: import("lucide-react").LucideIcon;
|
|
20
|
+
readonly bullet: import("lucide-react").LucideIcon;
|
|
21
|
+
readonly ordered: import("lucide-react").LucideIcon;
|
|
22
|
+
readonly alignLeft: import("lucide-react").LucideIcon;
|
|
23
|
+
readonly alignCenter: import("lucide-react").LucideIcon;
|
|
24
|
+
readonly alignRight: import("lucide-react").LucideIcon;
|
|
25
|
+
readonly alignJustify: import("lucide-react").LucideIcon;
|
|
26
|
+
readonly lineHeight: import("lucide-react").LucideIcon;
|
|
27
|
+
readonly quote: import("lucide-react").LucideIcon;
|
|
28
|
+
readonly pullQuote: import("lucide-react").LucideIcon;
|
|
29
|
+
readonly divider: import("lucide-react").LucideIcon;
|
|
30
|
+
readonly codeBlock: import("lucide-react").LucideIcon;
|
|
31
|
+
readonly diagram: import("lucide-react").LucideIcon;
|
|
32
|
+
readonly info: import("lucide-react").LucideIcon;
|
|
33
|
+
readonly tip: import("lucide-react").LucideIcon;
|
|
34
|
+
readonly warn: import("lucide-react").LucideIcon;
|
|
35
|
+
readonly callout: import("lucide-react").LucideIcon;
|
|
36
|
+
readonly image: import("lucide-react").LucideIcon;
|
|
37
|
+
readonly table: import("lucide-react").LucideIcon;
|
|
38
|
+
readonly video: import("lucide-react").LucideIcon;
|
|
39
|
+
readonly link: import("lucide-react").LucideIcon;
|
|
40
|
+
readonly rowPlus: import("lucide-react").LucideIcon;
|
|
41
|
+
readonly colPlus: import("lucide-react").LucideIcon;
|
|
42
|
+
readonly trash: import("lucide-react").LucideIcon;
|
|
43
|
+
readonly plus: import("lucide-react").LucideIcon;
|
|
44
|
+
readonly pencil: import("lucide-react").LucideIcon;
|
|
45
|
+
readonly bucket: import("lucide-react").LucideIcon;
|
|
46
|
+
readonly text: import("lucide-react").LucideIcon;
|
|
47
|
+
readonly none: import("lucide-react").LucideIcon;
|
|
48
|
+
readonly move: import("lucide-react").LucideIcon;
|
|
49
|
+
readonly rowMerge: import("lucide-react").LucideIcon;
|
|
50
|
+
readonly rowSplit: import("lucide-react").LucideIcon;
|
|
51
|
+
readonly rowLift: import("lucide-react").LucideIcon;
|
|
52
|
+
readonly swap: import("lucide-react").LucideIcon;
|
|
53
|
+
readonly tableStyle: import("lucide-react").LucideIcon;
|
|
54
|
+
readonly tableBorder: import("lucide-react").LucideIcon;
|
|
55
|
+
readonly cellMerge: import("lucide-react").LucideIcon;
|
|
56
|
+
readonly cellSplit: import("lucide-react").LucideIcon;
|
|
57
|
+
};
|
|
58
|
+
export type IconName = keyof typeof MAP;
|
|
59
|
+
/**
|
|
60
|
+
* `stroke` 는 획 굵기다. 기본 1.9 는 17px 아이콘 기준이고,
|
|
61
|
+
* 20px 짜리 넣기 타일에서는 같은 굵기가 뭉툭해 보여 더 가늘게 준다.
|
|
62
|
+
*/
|
|
63
|
+
export declare function Icon({ name, size, stroke }: {
|
|
64
|
+
name: IconName | string;
|
|
65
|
+
size?: number;
|
|
66
|
+
stroke?: number;
|
|
67
|
+
}): import("react").JSX.Element | null;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=Icon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../src/Icon.tsx"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,QAAA,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBC,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,GAAG,CAAA;AAEvC;;;GAGG;AACH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,IAAS,EAAE,MAAY,EAAE,EAAE;IAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,sCAIlH"}
|
package/dist/Icon.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AlignCenter, AlignJustify, AlignLeft, AlignRight, AlignVerticalSpaceAround, ArrowLeftRight, BadgeInfo, Ban, BetweenHorizontalStart, BetweenVerticalStart, Bold, Braces, CircleCheck, CirclePlay, Code, Columns2, GitBranch, Heading2, Heading3, Highlighter, Image as ImageIcon, Info, Italic, Link as LinkIcon, List, ListOrdered, Minus, Move, PaintBucket, Pencil, Plus, Quote, Square, SquareSplitHorizontal, Strikethrough, Ungroup, Table as TableIcon, TableCellsMerge, TableCellsSplit, TableProperties, TextQuote, Trash2, TriangleAlert, Type, Underline, } from 'lucide-react';
|
|
3
|
+
/**
|
|
4
|
+
* 툴바 아이콘 — lucide-react 를 쓴다.
|
|
5
|
+
*
|
|
6
|
+
* 직접 그리지 않는 이유: 손으로 그린 SVG 는 획 굵기·여백·시각 중심이 제각각이라
|
|
7
|
+
* 나란히 놓으면 티가 나고, 아이콘이 늘 때마다 그 부담이 커진다.
|
|
8
|
+
* template-react-admin 도 lucide-react 를 쓰므로 스택도 맞는다.
|
|
9
|
+
*
|
|
10
|
+
* 호출부는 이름만 알면 되게 얇게 감싼다 — 나중에 라이브러리를 바꿔도 여기만 고친다.
|
|
11
|
+
* (라이브러리 분리 시 이 파일은 react 패키지로 간다. core 는 아이콘을 모른다.)
|
|
12
|
+
*/
|
|
13
|
+
const MAP = {
|
|
14
|
+
bold: Bold, italic: Italic, underline: Underline, strike: Strikethrough,
|
|
15
|
+
code: Code, highlight: Highlighter,
|
|
16
|
+
h2: Heading2, h3: Heading3,
|
|
17
|
+
bullet: List, ordered: ListOrdered,
|
|
18
|
+
alignLeft: AlignLeft, alignCenter: AlignCenter, alignRight: AlignRight, alignJustify: AlignJustify,
|
|
19
|
+
// 줄 간격 — 위아래 선 사이의 덩어리. 「행간」을 글자 없이 말하는 가장 흔한 그림이다.
|
|
20
|
+
lineHeight: AlignVerticalSpaceAround,
|
|
21
|
+
// 인용은 따옴표 덩어리(Quote)가 아니라 **따옴표+글줄**. 큰 인용만 덩어리 쪽을 쓴다.
|
|
22
|
+
quote: TextQuote, pullQuote: Quote, divider: Minus,
|
|
23
|
+
/* 소스코드는 네모 상자가 아니라 **중괄호**다. 네이버도 `{ }` 를 쓴다 —
|
|
24
|
+
넣기 줄에 네모 상자가 셋이나 서면(사진·영상·코드) 서로 구별이 안 되고 줄이 둔해 보인다. */
|
|
25
|
+
codeBlock: Braces,
|
|
26
|
+
diagram: GitBranch,
|
|
27
|
+
info: Info, tip: CircleCheck, warn: TriangleAlert, callout: BadgeInfo,
|
|
28
|
+
// 영상은 **동그란 재생 표시**. 네모 무리 속에서 혼자 둥글어 한눈에 갈린다.
|
|
29
|
+
image: ImageIcon, table: TableIcon, video: CirclePlay, link: LinkIcon,
|
|
30
|
+
rowPlus: BetweenHorizontalStart, colPlus: BetweenVerticalStart,
|
|
31
|
+
trash: Trash2, plus: Plus, pencil: Pencil, bucket: PaintBucket, text: Type, none: Ban,
|
|
32
|
+
move: Move,
|
|
33
|
+
// 사진 행 — 합치기(두 칸)·풀기(가운데를 가름)·한 장 빼기·자리 바꿈
|
|
34
|
+
rowMerge: Columns2, rowSplit: SquareSplitHorizontal, rowLift: Ungroup, swap: ArrowLeftRight,
|
|
35
|
+
tableStyle: TableProperties, tableBorder: Square, cellMerge: TableCellsMerge, cellSplit: TableCellsSplit,
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* `stroke` 는 획 굵기다. 기본 1.9 는 17px 아이콘 기준이고,
|
|
39
|
+
* 20px 짜리 넣기 타일에서는 같은 굵기가 뭉툭해 보여 더 가늘게 준다.
|
|
40
|
+
*/
|
|
41
|
+
export function Icon({ name, size = 17, stroke = 1.9 }) {
|
|
42
|
+
const C = MAP[name];
|
|
43
|
+
if (!C)
|
|
44
|
+
return null;
|
|
45
|
+
return _jsx(C, { size: size, strokeWidth: stroke, "aria-hidden": "true" });
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=Icon.js.map
|
package/dist/Icon.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Icon.js","sourceRoot":"","sources":["../src/Icon.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,wBAAwB,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,EAAE,sBAAsB,EAAE,oBAAoB,EACxJ,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,SAAS,EAAE,IAAI,EAC3H,MAAM,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EACnF,KAAK,EAAE,MAAM,EAAE,qBAAqB,EAAE,aAAa,EAAE,OAAO,EAC5D,KAAK,IAAI,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAChF,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GACvC,MAAM,cAAc,CAAA;AAErB;;;;;;;;;GASG;AACH,MAAM,GAAG,GAAG;IACV,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa;IACvE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW;IAClC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ;IAC1B,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW;IAClC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY;IAClG,oDAAoD;IACpD,UAAU,EAAE,wBAAwB;IACpC,uDAAuD;IACvD,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK;IAClD;8DAC0D;IAC1D,SAAS,EAAE,MAAM;IACjB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS;IACrE,+CAA+C;IAC/C,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ;IACrE,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,oBAAoB;IAC9D,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG;IACrF,IAAI,EAAE,IAAI;IACV,2CAA2C;IAC3C,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc;IAC3F,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe;CAChG,CAAA;AAIV;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,MAAM,GAAG,GAAG,EAA+D;IACjH,MAAM,CAAC,GAAG,GAAG,CAAC,IAAgB,CAAC,CAAA;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnB,OAAO,KAAC,CAAC,IAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,iBAAc,MAAM,GAAG,CAAA;AAClE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Editor } from '@tiptap/react';
|
|
2
|
+
/**
|
|
3
|
+
* 현재 줄 왼쪽 여백에 뜨는 `+`.
|
|
4
|
+
*
|
|
5
|
+
* FloatingMenu 를 안 쓰는 이유: 그건 빈 텍스트블록에서만 뜨고 기준이 커서다.
|
|
6
|
+
* 여기서는 커서가 있는 **최상위 블록**이 기준이라 표 오버레이와 같은 방식(fixed 좌표)으로 그린다.
|
|
7
|
+
*
|
|
8
|
+
* 편집면에 패딩을 더해 여백을 만들지 않는다 — 발행면과 기하가 어긋난다.
|
|
9
|
+
* 여백이 없으면 왼쪽 끝에 붙여 클램프한다.
|
|
10
|
+
*/
|
|
11
|
+
export declare function InsertHandle({ editor }: {
|
|
12
|
+
editor: Editor;
|
|
13
|
+
}): import("react").JSX.Element | null;
|
|
14
|
+
//# sourceMappingURL=InsertHandle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InsertHandle.d.ts","sourceRoot":"","sources":["../src/InsertHandle.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,eAAe,CAAA;AAO3D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,sCAsE1D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useRef, useState } from 'react';
|
|
3
|
+
import { useDismiss } from './useDismiss.js';
|
|
4
|
+
import { insertImageFiles, pickImageFiles } from '@storkspear/post-editor-core/image';
|
|
5
|
+
import { useEditorState } from '@tiptap/react';
|
|
6
|
+
import { Icon } from './Icon.js';
|
|
7
|
+
import { VariantMenu } from './VariantMenu.js';
|
|
8
|
+
import { dividerItems } from './objects/divider.js';
|
|
9
|
+
import { quoteItems } from './objects/quote.js';
|
|
10
|
+
import { DIVIDER_KINDS, QUOTE_VARIANTS } from '@storkspear/post-editor-core/vocab';
|
|
11
|
+
/**
|
|
12
|
+
* 현재 줄 왼쪽 여백에 뜨는 `+`.
|
|
13
|
+
*
|
|
14
|
+
* FloatingMenu 를 안 쓰는 이유: 그건 빈 텍스트블록에서만 뜨고 기준이 커서다.
|
|
15
|
+
* 여기서는 커서가 있는 **최상위 블록**이 기준이라 표 오버레이와 같은 방식(fixed 좌표)으로 그린다.
|
|
16
|
+
*
|
|
17
|
+
* 편집면에 패딩을 더해 여백을 만들지 않는다 — 발행면과 기하가 어긋난다.
|
|
18
|
+
* 여백이 없으면 왼쪽 끝에 붙여 클램프한다.
|
|
19
|
+
*/
|
|
20
|
+
export function InsertHandle({ editor }) {
|
|
21
|
+
const [menu, setMenu] = useState(null);
|
|
22
|
+
const anchor = useRef(null);
|
|
23
|
+
const spot = useEditorState({
|
|
24
|
+
editor,
|
|
25
|
+
selector: ({ editor: e }) => {
|
|
26
|
+
if (!e.isEditable)
|
|
27
|
+
return null;
|
|
28
|
+
const { $from } = e.state.selection;
|
|
29
|
+
if ($from.depth < 1)
|
|
30
|
+
return null;
|
|
31
|
+
try {
|
|
32
|
+
const pos = $from.before(1);
|
|
33
|
+
const dom = e.view.nodeDOM(pos);
|
|
34
|
+
const el = dom instanceof HTMLElement ? dom : dom?.parentElement;
|
|
35
|
+
if (!el)
|
|
36
|
+
return null;
|
|
37
|
+
const r = el.getBoundingClientRect();
|
|
38
|
+
return { pos, left: r.left, top: r.top, lineH: parseFloat(getComputedStyle(el).lineHeight) || 24 };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
useDismiss(menu !== null, anchor, useCallback(() => setMenu(null), []));
|
|
46
|
+
if (!spot)
|
|
47
|
+
return null;
|
|
48
|
+
// 폰에서는 붙일 여백이 없다 — 아랫줄의 넣기 버튼이 같은 일을 한다.
|
|
49
|
+
// 터치 여부만 보면 좁은 데스크톱 창에서 여백을 뚫고 나오므로 폭도 같이 본다.
|
|
50
|
+
if (window.innerWidth <= 640 || window.matchMedia('(pointer: coarse)').matches)
|
|
51
|
+
return null;
|
|
52
|
+
const left = Math.max(4, spot.left - 36);
|
|
53
|
+
const top = spot.top + Math.max(0, (spot.lineH - 28) / 2);
|
|
54
|
+
return (_jsxs("div", { className: "ins-anchor", "data-editor-ui": "", style: { left, top }, ref: anchor, children: [_jsx("button", { type: "button", className: "ins-btn", title: "\uC5EC\uAE30\uC5D0 \uB123\uAE30", "aria-label": "\uC5EC\uAE30\uC5D0 \uB123\uAE30", "aria-haspopup": "menu", "aria-expanded": menu !== null, onMouseDown: (e) => e.preventDefault(), onClick: () => setMenu(menu ? null : 'root'), children: _jsx(Icon, { name: "plus", size: 16 }) }), menu === 'root' && (_jsxs("div", { className: "tb-menu ins-menu", role: "menu", children: [_jsxs("button", { onClick: () => { editor.chain().focus().toggleCodeBlock().run(); setMenu(null); }, children: [_jsx(Icon, { name: "codeBlock" }), _jsxs("span", { children: [_jsx("b", { children: "\uCF54\uB4DC" }), _jsx("i", { children: "\uBB38\uBC95 \uC0C9\u00B7\uC904 \uBC88\uD638" })] })] }), _jsxs("button", { onClick: () => {
|
|
55
|
+
setMenu(null);
|
|
56
|
+
void pickImageFiles().then((files) => { if (files.length)
|
|
57
|
+
void insertImageFiles(editor, files); });
|
|
58
|
+
}, children: [_jsx(Icon, { name: "image" }), _jsxs("span", { children: [_jsx("b", { children: "\uC0AC\uC9C4" }), _jsx("i", { children: "\uACE0\uB974\uAE30 \u00B7 \uB04C\uC5B4\uB193\uAE30 \u00B7 \uBD99\uC5EC\uB123\uAE30" })] })] }), _jsxs("button", { onClick: () => setMenu('divider'), children: [_jsx(Icon, { name: "divider" }), _jsxs("span", { children: [_jsx("b", { children: "\uAD6C\uBD84\uC120" }), _jsxs("i", { children: [DIVIDER_KINDS.length, "\uAC00\uC9C0 \uBAA8\uC591"] })] })] }), _jsxs("button", { onClick: () => setMenu('quote'), children: [_jsx(Icon, { name: "quote" }), _jsxs("span", { children: [_jsx("b", { children: "\uC778\uC6A9\uAD6C" }), _jsxs("i", { children: [QUOTE_VARIANTS.length, "\uAC00\uC9C0 \uBAA8\uC591"] })] })] }), _jsxs("button", { onClick: () => { editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(); setMenu(null); }, children: [_jsx(Icon, { name: "table" }), _jsx("span", { children: _jsx("b", { children: "\uD45C" }) })] })] })), menu === 'divider' && (_jsx(VariantMenu, { ariaLabel: "\uAD6C\uBD84\uC120 \uBAA8\uC591", columns: 4, anchorRef: anchor, items: dividerItems, onPick: (k) => editor.chain().focus().setDivider({ kind: k, align: 'center' }).run(), onClose: () => setMenu(null) })), menu === 'quote' && (_jsx(VariantMenu, { ariaLabel: "\uC778\uC6A9 \uBAA8\uC591", columns: 3, anchorRef: anchor, items: quoteItems, onPick: (v) => editor.chain().focus().setQuoteVariant(v).run(), onClose: () => setMenu(null) }))] }));
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=InsertHandle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InsertHandle.js","sourceRoot":"","sources":["../src/InsertHandle.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode, type RefObject } from 'react';
|
|
2
|
+
import { type IconName } from './Icon.js';
|
|
3
|
+
export type PickOption<T extends string> = {
|
|
4
|
+
value: T;
|
|
5
|
+
label: string;
|
|
6
|
+
/** 이름을 그 글꼴로 보여 줄 때만 (글꼴 고르기) */
|
|
7
|
+
font?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* 이름을 늘어놓고 하나 고르는 메뉴 — `<select>` 를 대신한다.
|
|
11
|
+
*
|
|
12
|
+
* `<select>` 를 안 쓰는 이유: macOS·윈도는 option 을 **OS 메뉴**로 그려서
|
|
13
|
+
* 우리 CSS 가 하나도 안 먹는다. 그래서 문단 스타일·글자 크기만 시커먼 시스템 메뉴로 떠서
|
|
14
|
+
* 나머지 편집 UI 와 따로 놀았다.
|
|
15
|
+
* 글꼴 메뉴는 같은 이유로 진작에 직접 만들어 뒀고 — 이제 셋이 한 부품을 쓴다.
|
|
16
|
+
*/
|
|
17
|
+
export declare function PickMenu<T extends string>({ items, value, onPick, onClose, anchorRef, width, ariaLabel, align, }: {
|
|
18
|
+
items: readonly PickOption<T>[];
|
|
19
|
+
value: T;
|
|
20
|
+
onPick: (v: T) => void;
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
anchorRef: RefObject<HTMLElement | null>;
|
|
23
|
+
width?: number;
|
|
24
|
+
ariaLabel: string;
|
|
25
|
+
align?: 'left' | 'center';
|
|
26
|
+
}): import("react").JSX.Element;
|
|
27
|
+
/**
|
|
28
|
+
* 고르는 칸 한 벌 — 버튼 + 메뉴.
|
|
29
|
+
* 툴바에 넷(글꼴·문단·크기·언어)이 같은 모양으로 서므로 여는 상태까지 여기서 갖는다.
|
|
30
|
+
*/
|
|
31
|
+
export declare function Picker<T extends string>({ items, value, onPick, title, width, className, style, align, children, }: {
|
|
32
|
+
items: readonly PickOption<T>[];
|
|
33
|
+
value: T;
|
|
34
|
+
onPick: (v: T) => void;
|
|
35
|
+
title: string;
|
|
36
|
+
width?: number;
|
|
37
|
+
className?: string;
|
|
38
|
+
style?: CSSProperties;
|
|
39
|
+
align?: 'left' | 'center';
|
|
40
|
+
/** 버튼에 보일 것 — 없으면 고른 항목의 이름 */
|
|
41
|
+
children?: ReactNode;
|
|
42
|
+
}): import("react").JSX.Element;
|
|
43
|
+
/**
|
|
44
|
+
* 아이콘만 세로로 늘어놓는 메뉴 — 목록·정렬이 쓴다(네이버 블로그와 같은 모양).
|
|
45
|
+
* 글자 설명이 없어도 아이콘 넷이면 무엇인지 다 말한다.
|
|
46
|
+
*/
|
|
47
|
+
export declare function IconMenu<T extends string>({ items, value, onPick, onClose, anchorRef, ariaLabel, footer, }: {
|
|
48
|
+
items: readonly {
|
|
49
|
+
value: T;
|
|
50
|
+
icon: IconName;
|
|
51
|
+
label: string;
|
|
52
|
+
}[];
|
|
53
|
+
value: T | null;
|
|
54
|
+
onPick: (v: T) => void;
|
|
55
|
+
onClose: () => void;
|
|
56
|
+
anchorRef: RefObject<HTMLElement | null>;
|
|
57
|
+
ariaLabel: string;
|
|
58
|
+
/** 목록 아래에 덧붙이는 줄 (예: 목록의 마커 모양) */
|
|
59
|
+
footer?: ReactNode;
|
|
60
|
+
}): import("react").JSX.Element;
|
|
61
|
+
//# sourceMappingURL=PickMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PickMenu.d.ts","sourceRoot":"","sources":["../src/PickMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqC,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAI7G,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE5C,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI;IACzC,KAAK,EAAE,CAAC,CAAA;IACR,KAAK,EAAE,MAAM,CAAA;IACb,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,EACzC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,KAAW,EAAE,SAAS,EAAE,KAAc,GACjF,EAAE;IACD,KAAK,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/B,KAAK,EAAE,CAAC,CAAA;IACR,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;IACtB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CAC1B,+BAsCA;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,EACvC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAW,EAAE,SAAc,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,GACjF,EAAE;IACD,KAAK,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/B,KAAK,EAAE,CAAC,CAAA;IACR,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB,+BAiBA;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,EACzC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAC5D,EAAE;IACD,KAAK,EAAE,SAAS;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC7D,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IACf,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;IACtB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,mCAAmC;IACnC,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,+BAoBA"}
|
package/dist/PickMenu.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useDismiss } from './useDismiss.js';
|
|
4
|
+
import { useAnchoredPos } from './useAnchoredPos.js';
|
|
5
|
+
import { Portal } from './Popover.js';
|
|
6
|
+
import { Icon } from './Icon.js';
|
|
7
|
+
/**
|
|
8
|
+
* 이름을 늘어놓고 하나 고르는 메뉴 — `<select>` 를 대신한다.
|
|
9
|
+
*
|
|
10
|
+
* `<select>` 를 안 쓰는 이유: macOS·윈도는 option 을 **OS 메뉴**로 그려서
|
|
11
|
+
* 우리 CSS 가 하나도 안 먹는다. 그래서 문단 스타일·글자 크기만 시커먼 시스템 메뉴로 떠서
|
|
12
|
+
* 나머지 편집 UI 와 따로 놀았다.
|
|
13
|
+
* 글꼴 메뉴는 같은 이유로 진작에 직접 만들어 뒀고 — 이제 셋이 한 부품을 쓴다.
|
|
14
|
+
*/
|
|
15
|
+
export function PickMenu({ items, value, onPick, onClose, anchorRef, width = 150, ariaLabel, align = 'left', }) {
|
|
16
|
+
const ref = useRef(null);
|
|
17
|
+
const pos = useAnchoredPos(anchorRef, true, width, ref);
|
|
18
|
+
useDismiss(true, ref, onClose, anchorRef);
|
|
19
|
+
// 크기 16줄·언어 27줄은 화면을 넘는다 — 열자마자 지금 값이 보이게 끌어온다.
|
|
20
|
+
// **딱 한 번만**: useAnchoredPos 는 스크롤마다 새 좌표 객체를 만들어 이 효과를 다시 돌리는데,
|
|
21
|
+
// 그러면 메뉴를 굴릴 때마다 고른 줄로 도로 튄다. 자리를 잡은 뒤(pos) 한 번이면 된다.
|
|
22
|
+
const pulled = useRef(false);
|
|
23
|
+
useLayoutEffect(() => {
|
|
24
|
+
if (!pos || pulled.current)
|
|
25
|
+
return;
|
|
26
|
+
pulled.current = true;
|
|
27
|
+
ref.current?.querySelector('.is-on')?.scrollIntoView({ block: 'nearest' });
|
|
28
|
+
}, [pos]);
|
|
29
|
+
return (_jsx(Portal, { active: !!pos, children: _jsx("div", { "data-editor-ui": "", ref: ref, role: "menu", "aria-label": ariaLabel, className: `pm${align === 'center' ? ' pm-center' : ''}${
|
|
30
|
+
// 글꼴 메뉴는 이름을 **그 글꼴로** 그린다 — 손글씨는 획이 가늘고 작게 앉아
|
|
31
|
+
// 본문과 같은 크기로는 읽히지 않는다. 이 메뉴만 키운다.
|
|
32
|
+
items.some((i) => i.font !== undefined) ? ' pm-fonts' : ''}${pos ? ' is-fixed' : ''}`, style: {
|
|
33
|
+
width,
|
|
34
|
+
...(pos ? { position: 'fixed', left: pos.left, top: pos.top, maxHeight: Math.min(pos.maxHeight, 430) } : null),
|
|
35
|
+
}, children: items.map((it) => (_jsx("button", { type: "button", role: "menuitemradio", "aria-checked": value === it.value, className: `pm-item${value === it.value ? ' is-on' : ''}`, style: it.font !== undefined ? { fontFamily: it.font || 'var(--font-body)' } : undefined, onMouseDown: (e) => e.preventDefault(), onClick: () => { onPick(it.value); onClose(); }, children: it.label }, it.value))) }) }));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 고르는 칸 한 벌 — 버튼 + 메뉴.
|
|
39
|
+
* 툴바에 넷(글꼴·문단·크기·언어)이 같은 모양으로 서므로 여는 상태까지 여기서 갖는다.
|
|
40
|
+
*/
|
|
41
|
+
export function Picker({ items, value, onPick, title, width = 150, className = '', style, align, children, }) {
|
|
42
|
+
const anchor = useRef(null);
|
|
43
|
+
const [open, setOpen] = useState(false);
|
|
44
|
+
const label = children ?? items.find((i) => i.value === value)?.label ?? '';
|
|
45
|
+
return (_jsxs("div", { className: "tb-anchor", ref: anchor, children: [_jsx("button", { type: "button", className: `tb-select ${className}${open ? ' is-open' : ''}`, title: title, "aria-haspopup": "menu", "aria-expanded": open, style: style, onMouseDown: (e) => e.preventDefault(), onClick: () => setOpen((v) => !v), children: label }), open && (_jsx(PickMenu, { ariaLabel: title, items: items, value: value, width: width, align: align, anchorRef: anchor, onPick: onPick, onClose: () => setOpen(false) }))] }));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 아이콘만 세로로 늘어놓는 메뉴 — 목록·정렬이 쓴다(네이버 블로그와 같은 모양).
|
|
49
|
+
* 글자 설명이 없어도 아이콘 넷이면 무엇인지 다 말한다.
|
|
50
|
+
*/
|
|
51
|
+
export function IconMenu({ items, value, onPick, onClose, anchorRef, ariaLabel, footer, }) {
|
|
52
|
+
const ref = useRef(null);
|
|
53
|
+
const pos = useAnchoredPos(anchorRef, true, 46, ref);
|
|
54
|
+
useDismiss(true, ref, onClose, anchorRef);
|
|
55
|
+
return (_jsx(Portal, { active: !!pos, children: _jsxs("div", { "data-editor-ui": "", ref: ref, role: "menu", "aria-label": ariaLabel, className: `tb-listmenu${pos ? ' is-fixed' : ''}`, style: pos ? { position: 'fixed', left: pos.left, top: pos.top, maxHeight: pos.maxHeight, overflowY: 'auto' } : undefined, children: [items.map((it) => (_jsx("button", { type: "button", role: "menuitemradio", "aria-checked": value === it.value, className: value === it.value ? 'is-on' : '', title: it.label, "aria-label": it.label, onMouseDown: (e) => e.preventDefault(), onClick: () => { onPick(it.value); onClose(); }, children: _jsx(Icon, { name: it.icon, size: 18 }) }, it.value))), footer] }) }));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=PickMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PickMenu.js","sourceRoot":"","sources":["../src/PickMenu.tsx"],"names":[],"mappings":"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"}
|