react-text-range 1.0.6 → 1.0.8
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/README.md +36 -0
- package/dist/cjs/esm/ReactTextRange.d.ts +18 -0
- package/dist/cjs/esm/TextSelectionZone.d.ts +7 -2
- package/dist/cjs/esm/handler-pos.d.ts +1 -0
- package/dist/cjs/esm/index-sample.d.ts +1 -0
- package/dist/cjs/esm/index.d.ts +2 -3
- package/dist/cjs/esm/rect.d.ts +6 -0
- package/dist/cjs/esm/useTextSelectionEditor.d.ts +2 -1
- package/dist/cjs/index.html +17 -0
- package/dist/cjs/index.js +118 -92
- package/dist/esm/ReactTextRange.d.ts +18 -0
- package/dist/esm/TextSelectionZone.d.ts +7 -2
- package/dist/esm/handler-pos.d.ts +1 -0
- package/dist/esm/index-sample.d.ts +1 -0
- package/dist/esm/index.d.ts +2 -3
- package/dist/esm/index.html +17 -0
- package/dist/esm/index.js +105 -78
- package/dist/esm/rect.d.ts +6 -0
- package/dist/esm/useTextSelectionEditor.d.ts +2 -1
- package/dist/index.d.ts +11 -5
- package/package.json +16 -6
package/README.md
CHANGED
|
@@ -1 +1,37 @@
|
|
|
1
1
|
# react-text-range
|
|
2
|
+
|
|
3
|
+
## using
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
// ...
|
|
7
|
+
import { TextContainer, RangeState, ReactTextRange } from "./ReactTextRange";
|
|
8
|
+
|
|
9
|
+
const MyTextContainer: TextContainer = React.forwardRef(({ children }, ref) =>
|
|
10
|
+
<div ref={ref} style={{
|
|
11
|
+
fontSize: 30,
|
|
12
|
+
width: '320px',
|
|
13
|
+
backgroundColor: 'rgba(253, 224, 71, .2)',
|
|
14
|
+
userSelect: 'none',
|
|
15
|
+
padding: '20px',
|
|
16
|
+
}}>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const App: FunctionComponent = () => {
|
|
22
|
+
const [myPos, setMyPos] = useState<RangeState>({ left: 23, right: 37 })
|
|
23
|
+
return (
|
|
24
|
+
<div style={{ margin: 20 }}>
|
|
25
|
+
<ReactTextRange initLeftPos={23} initRightPos={37}
|
|
26
|
+
Container={MyTextContainer} onChange={setMyPos}>
|
|
27
|
+
Some text or even some real good text here and there and here again
|
|
28
|
+
</ReactTextRange>
|
|
29
|
+
<div>
|
|
30
|
+
<span>{myPos?.left}</span>
|
|
31
|
+
|
|
32
|
+
<span>{myPos?.right}</span>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export type TextContainer = React.ForwardRefExoticComponent<{
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
export interface RangeState {
|
|
7
|
+
left: number;
|
|
8
|
+
right: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const ReactTextRange: FC<{
|
|
11
|
+
initLeftPos: number;
|
|
12
|
+
initRightPos: number;
|
|
13
|
+
Container: TextContainer;
|
|
14
|
+
children: string;
|
|
15
|
+
onChange: (state: RangeState) => void;
|
|
16
|
+
props?: React.CSSProperties;
|
|
17
|
+
}>;
|
|
18
|
+
export default ReactTextRange;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
-
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export type TextContainer = React.ForwardRefExoticComponent<{
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
export declare const ReactTextRange: FC<{
|
|
3
7
|
initLeftPos: number;
|
|
4
8
|
initRightPos: number;
|
|
9
|
+
Container: TextContainer;
|
|
5
10
|
children: string;
|
|
6
11
|
}>;
|
|
7
|
-
export default
|
|
12
|
+
export default ReactTextRange;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cjs/esm/index.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export { FullWindow, TextSelectionZone };
|
|
1
|
+
import { TextContainer, RangeState, ReactTextRange } from "./ReactTextRange";
|
|
2
|
+
export { RangeState, TextContainer, ReactTextRange };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HandlerPos } from './handler-pos';
|
|
3
|
+
import { Rect } from './rect';
|
|
3
4
|
declare global {
|
|
4
5
|
interface Document {
|
|
5
6
|
caretPositionFromPoint: any;
|
|
@@ -9,5 +10,5 @@ export declare const useTextSelectionEditor: (initLeftPos: number, initRightPos:
|
|
|
9
10
|
React.MutableRefObject<HTMLDivElement | null>,
|
|
10
11
|
HandlerPos | null,
|
|
11
12
|
HandlerPos | null,
|
|
12
|
-
|
|
13
|
+
Rect[] | null
|
|
13
14
|
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Document</title>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script defer src="/index.js"></script>
|
|
13
|
+
</body>
|
|
14
|
+
|
|
15
|
+
</body>
|
|
16
|
+
|
|
17
|
+
</html>
|
package/dist/cjs/index.js
CHANGED
|
@@ -3,75 +3,33 @@
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
|
|
5
5
|
function _interopNamespaceDefault(e) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
var n = Object.create(null);
|
|
7
|
+
if (e) {
|
|
8
|
+
Object.keys(e).forEach(function (k) {
|
|
9
|
+
if (k !== 'default') {
|
|
10
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
11
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return e[k]; }
|
|
14
|
+
});
|
|
15
|
+
}
|
|
14
16
|
});
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
n.default = e;
|
|
19
|
-
return Object.freeze(n);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
23
|
-
|
|
24
|
-
function styleInject(css, ref) {
|
|
25
|
-
if ( ref === void 0 ) ref = {};
|
|
26
|
-
var insertAt = ref.insertAt;
|
|
27
|
-
|
|
28
|
-
if (!css || typeof document === 'undefined') { return; }
|
|
29
|
-
|
|
30
|
-
var head = document.head || document.getElementsByTagName('head')[0];
|
|
31
|
-
var style = document.createElement('style');
|
|
32
|
-
style.type = 'text/css';
|
|
33
|
-
|
|
34
|
-
if (insertAt === 'top') {
|
|
35
|
-
if (head.firstChild) {
|
|
36
|
-
head.insertBefore(style, head.firstChild);
|
|
37
|
-
} else {
|
|
38
|
-
head.appendChild(style);
|
|
39
17
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (style.styleSheet) {
|
|
45
|
-
style.styleSheet.cssText = css;
|
|
46
|
-
} else {
|
|
47
|
-
style.appendChild(document.createTextNode(css));
|
|
48
|
-
}
|
|
18
|
+
n.default = e;
|
|
19
|
+
return Object.freeze(n);
|
|
49
20
|
}
|
|
50
21
|
|
|
51
|
-
var
|
|
52
|
-
styleInject(css_248z,{"insertAt":"top"});
|
|
53
|
-
|
|
54
|
-
const fullWindow = {
|
|
55
|
-
height: '100vh',
|
|
56
|
-
widows: '100%',
|
|
57
|
-
};
|
|
58
|
-
const centroContainer = Object.assign(Object.assign({}, fullWindow), { display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' });
|
|
59
|
-
const FullWindow = ({ children }) => {
|
|
60
|
-
return (React.createElement("div", { style: centroContainer }, children));
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const _TextContainer = ({ children }, ref) => {
|
|
64
|
-
return (React.createElement("div", { ref: ref, draggable: false, className: "basis-80 w-80 bg-yellow-50 p-11 text-3xl select-none bg-transparent" }, children));
|
|
65
|
-
};
|
|
66
|
-
const TextContainer = React.forwardRef(_TextContainer);
|
|
22
|
+
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
67
23
|
|
|
68
24
|
const getHandlerRect = (index, node) => {
|
|
69
25
|
const range = document.createRange();
|
|
70
26
|
range.setStart(node, index);
|
|
71
27
|
range.setEnd(node, index);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
28
|
+
if (range.getClientRects) {
|
|
29
|
+
const rects = range.getClientRects();
|
|
30
|
+
if (rects.length === 1) {
|
|
31
|
+
return rects[0];
|
|
32
|
+
}
|
|
75
33
|
}
|
|
76
34
|
return null;
|
|
77
35
|
};
|
|
@@ -79,7 +37,12 @@ const getAllRects = (node, start, end) => {
|
|
|
79
37
|
const range = document.createRange();
|
|
80
38
|
range.setStart(node, start);
|
|
81
39
|
range.setEnd(node, end);
|
|
82
|
-
|
|
40
|
+
if (range.getClientRects) {
|
|
41
|
+
return range.getClientRects();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return new DOMRectList();
|
|
45
|
+
}
|
|
83
46
|
};
|
|
84
47
|
const getNodeAndOffsetFromPoint = (x, y) => {
|
|
85
48
|
let range;
|
|
@@ -92,8 +55,10 @@ const getNodeAndOffsetFromPoint = (x, y) => {
|
|
|
92
55
|
}
|
|
93
56
|
else if (document.caretRangeFromPoint) {
|
|
94
57
|
range = document.caretRangeFromPoint(x, y);
|
|
95
|
-
|
|
96
|
-
|
|
58
|
+
if (range) {
|
|
59
|
+
textNode = range.startContainer;
|
|
60
|
+
offset = range.startOffset;
|
|
61
|
+
}
|
|
97
62
|
}
|
|
98
63
|
else {
|
|
99
64
|
return null;
|
|
@@ -115,6 +80,11 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
115
80
|
const [rects, setRects] = React.useState(null);
|
|
116
81
|
// reference
|
|
117
82
|
const textDiv = React.useRef(null);
|
|
83
|
+
React.useEffect(() => {
|
|
84
|
+
if (textDiv.current) {
|
|
85
|
+
textDiv.current.style.position = 'relative';
|
|
86
|
+
}
|
|
87
|
+
}, [textDiv]);
|
|
118
88
|
// mouse move handler
|
|
119
89
|
// left handler
|
|
120
90
|
React.useEffect(() => {
|
|
@@ -169,10 +139,12 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
169
139
|
setRects(null);
|
|
170
140
|
}
|
|
171
141
|
else {
|
|
142
|
+
const divRect = textDiv.current.getBoundingClientRect();
|
|
172
143
|
setLeftHandler({
|
|
173
144
|
height: rect.height,
|
|
174
|
-
left: rect.left,
|
|
175
|
-
top: rect.top,
|
|
145
|
+
left: rect.left - divRect.left,
|
|
146
|
+
top: rect.top - divRect.top,
|
|
147
|
+
pos: currentLeftPos,
|
|
176
148
|
});
|
|
177
149
|
}
|
|
178
150
|
}
|
|
@@ -188,10 +160,12 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
188
160
|
setRects(null);
|
|
189
161
|
}
|
|
190
162
|
else {
|
|
163
|
+
const divRect = textDiv.current.getBoundingClientRect();
|
|
191
164
|
setRightHandler({
|
|
192
165
|
height: rect.height,
|
|
193
|
-
left: rect.left,
|
|
194
|
-
top: rect.top,
|
|
166
|
+
left: rect.left - divRect.left,
|
|
167
|
+
top: rect.top - divRect.top,
|
|
168
|
+
pos: currentRightPos,
|
|
195
169
|
});
|
|
196
170
|
}
|
|
197
171
|
}
|
|
@@ -199,8 +173,26 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
199
173
|
React.useEffect(() => {
|
|
200
174
|
var _a;
|
|
201
175
|
const n = (_a = textDiv.current) === null || _a === void 0 ? void 0 : _a.childNodes[0];
|
|
202
|
-
if (n)
|
|
203
|
-
setRects(
|
|
176
|
+
if (!n) {
|
|
177
|
+
setRects(null);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const rawRects = getAllRects(n, currentLeftPos, currentRightPos);
|
|
181
|
+
let rectArray = [];
|
|
182
|
+
if (rawRects && textDiv.current) {
|
|
183
|
+
const divRect = textDiv.current.getBoundingClientRect();
|
|
184
|
+
for (let i = 0; i < rawRects.length; ++i) {
|
|
185
|
+
const aa = rawRects.item(i);
|
|
186
|
+
if (aa)
|
|
187
|
+
rectArray.push({
|
|
188
|
+
height: aa.height,
|
|
189
|
+
left: aa.left - divRect.left,
|
|
190
|
+
top: aa.top - divRect.top,
|
|
191
|
+
width: aa.width,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
setRects(rectArray);
|
|
204
196
|
}, [currentLeftPos, currentRightPos]);
|
|
205
197
|
// return
|
|
206
198
|
return [textDiv, leftHandler, rightHandler, rects];
|
|
@@ -230,6 +222,36 @@ var SvgQuoteRight = function SvgQuoteRight(props) {
|
|
|
230
222
|
})));
|
|
231
223
|
};
|
|
232
224
|
|
|
225
|
+
function styleInject(css, ref) {
|
|
226
|
+
if ( ref === void 0 ) ref = {};
|
|
227
|
+
var insertAt = ref.insertAt;
|
|
228
|
+
|
|
229
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
230
|
+
|
|
231
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
232
|
+
var style = document.createElement('style');
|
|
233
|
+
style.type = 'text/css';
|
|
234
|
+
|
|
235
|
+
if (insertAt === 'top') {
|
|
236
|
+
if (head.firstChild) {
|
|
237
|
+
head.insertBefore(style, head.firstChild);
|
|
238
|
+
} else {
|
|
239
|
+
head.appendChild(style);
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
head.appendChild(style);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (style.styleSheet) {
|
|
246
|
+
style.styleSheet.cssText = css;
|
|
247
|
+
} else {
|
|
248
|
+
style.appendChild(document.createTextNode(css));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
var css_248z = "/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:\"\"}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;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;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,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{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--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;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--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;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--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;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--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;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.flex{display:flex}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.bg-yellow-300{--tw-bg-opacity:1;background-color:rgb(253 224 71/var(--tw-bg-opacity))}.opacity-80{opacity:.8}";
|
|
253
|
+
styleInject(css_248z,{"insertAt":"top"});
|
|
254
|
+
|
|
233
255
|
const SelectionHandler = ({ pos, grab, setGrab, left }) => {
|
|
234
256
|
return (pos &&
|
|
235
257
|
React.createElement("div", { draggable: false, className: `bg-yellow-300 opacity-80 ${left ? 'rounded-l-md' : 'rounded-r-md'}`, style: {
|
|
@@ -255,34 +277,38 @@ const SelectionHandler = ({ pos, grab, setGrab, left }) => {
|
|
|
255
277
|
: React.createElement(SvgQuoteRight, null)));
|
|
256
278
|
};
|
|
257
279
|
|
|
258
|
-
const
|
|
280
|
+
const ReactTextRange = ({ initLeftPos, initRightPos, Container, children, onChange, props, }) => {
|
|
259
281
|
const [mouseOnLeft, setMouseOnLeft] = React.useState(false);
|
|
260
282
|
const [mouseOnRight, setMouseOnRight] = React.useState(false);
|
|
261
283
|
const [textDiv, leftHandler, rightHandler, rects] = useTextSelectionEditor(initLeftPos, initRightPos, mouseOnLeft, mouseOnRight);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
284
|
+
React.useEffect(() => {
|
|
285
|
+
if (leftHandler && rightHandler) {
|
|
286
|
+
onChange({
|
|
287
|
+
left: leftHandler.pos,
|
|
288
|
+
right: rightHandler.pos,
|
|
289
|
+
});
|
|
268
290
|
}
|
|
269
|
-
}
|
|
270
|
-
return (React.createElement("div", { draggable: false, style: {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
divs.map((d, i) => React.createElement("div", { key: i, className: 'bg-yellow-300', style: {
|
|
274
|
-
userSelect: 'none',
|
|
275
|
-
position: 'absolute',
|
|
276
|
-
top: `${d.top}px`,
|
|
277
|
-
left: `${d.left}px`,
|
|
278
|
-
width: `${d.width}px`,
|
|
279
|
-
height: `${d.height}px`,
|
|
280
|
-
zIndex: -2,
|
|
281
|
-
} }, "\u00A0")),
|
|
291
|
+
}, [leftHandler, rightHandler]);
|
|
292
|
+
return (React.createElement("div", { draggable: false, style: Object.assign({ position: 'relative' }, props) },
|
|
293
|
+
React.createElement(SelectionRects, { rects: rects }),
|
|
294
|
+
React.createElement(Container, { ref: textDiv }, children),
|
|
282
295
|
React.createElement(SelectionHandler, { grab: mouseOnLeft, left: true, pos: leftHandler, setGrab: (v) => setMouseOnLeft(v) }),
|
|
283
|
-
React.createElement(TextContainer, { ref: textDiv }, children),
|
|
284
296
|
React.createElement(SelectionHandler, { grab: mouseOnRight, left: false, pos: rightHandler, setGrab: (v) => setMouseOnRight(v) })));
|
|
285
297
|
};
|
|
298
|
+
const SelectionRects = ({ rects }) => {
|
|
299
|
+
if (!rects)
|
|
300
|
+
return null;
|
|
301
|
+
return (React.createElement(React.Fragment, null, rects.map((d, i) => React.createElement(SelectionRect, { key: i, rect: d }))));
|
|
302
|
+
};
|
|
303
|
+
const SelectionRect = ({ rect }) => {
|
|
304
|
+
return (React.createElement("div", { className: 'bg-yellow-300', style: {
|
|
305
|
+
userSelect: 'none',
|
|
306
|
+
position: 'absolute',
|
|
307
|
+
top: `${rect.top}px`,
|
|
308
|
+
left: `${rect.left}px`,
|
|
309
|
+
width: `${rect.width}px`,
|
|
310
|
+
height: `${rect.height}px`,
|
|
311
|
+
} }, "\u00A0"));
|
|
312
|
+
};
|
|
286
313
|
|
|
287
|
-
exports.
|
|
288
|
-
exports.TextSelectionZone = TextSelectionZone;
|
|
314
|
+
exports.ReactTextRange = ReactTextRange;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export type TextContainer = React.ForwardRefExoticComponent<{
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
export interface RangeState {
|
|
7
|
+
left: number;
|
|
8
|
+
right: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const ReactTextRange: FC<{
|
|
11
|
+
initLeftPos: number;
|
|
12
|
+
initRightPos: number;
|
|
13
|
+
Container: TextContainer;
|
|
14
|
+
children: string;
|
|
15
|
+
onChange: (state: RangeState) => void;
|
|
16
|
+
props?: React.CSSProperties;
|
|
17
|
+
}>;
|
|
18
|
+
export default ReactTextRange;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
-
|
|
2
|
+
import React from 'react';
|
|
3
|
+
export type TextContainer = React.ForwardRefExoticComponent<{
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
export declare const ReactTextRange: FC<{
|
|
3
7
|
initLeftPos: number;
|
|
4
8
|
initRightPos: number;
|
|
9
|
+
Container: TextContainer;
|
|
5
10
|
children: string;
|
|
6
11
|
}>;
|
|
7
|
-
export default
|
|
12
|
+
export default ReactTextRange;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export { FullWindow, TextSelectionZone };
|
|
1
|
+
import { TextContainer, RangeState, ReactTextRange } from "./ReactTextRange";
|
|
2
|
+
export { RangeState, TextContainer, ReactTextRange };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Document</title>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script type="module" src="/index.js"></script>
|
|
13
|
+
</body>
|
|
14
|
+
|
|
15
|
+
</body>
|
|
16
|
+
|
|
17
|
+
</html>
|
package/dist/esm/index.js
CHANGED
|
@@ -1,57 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default, { useState, useRef, useEffect } from 'react';
|
|
3
3
|
|
|
4
|
-
function styleInject(css, ref) {
|
|
5
|
-
if ( ref === void 0 ) ref = {};
|
|
6
|
-
var insertAt = ref.insertAt;
|
|
7
|
-
|
|
8
|
-
if (!css || typeof document === 'undefined') { return; }
|
|
9
|
-
|
|
10
|
-
var head = document.head || document.getElementsByTagName('head')[0];
|
|
11
|
-
var style = document.createElement('style');
|
|
12
|
-
style.type = 'text/css';
|
|
13
|
-
|
|
14
|
-
if (insertAt === 'top') {
|
|
15
|
-
if (head.firstChild) {
|
|
16
|
-
head.insertBefore(style, head.firstChild);
|
|
17
|
-
} else {
|
|
18
|
-
head.appendChild(style);
|
|
19
|
-
}
|
|
20
|
-
} else {
|
|
21
|
-
head.appendChild(style);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (style.styleSheet) {
|
|
25
|
-
style.styleSheet.cssText = css;
|
|
26
|
-
} else {
|
|
27
|
-
style.appendChild(document.createTextNode(css));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
var css_248z = "/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:\"\"}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;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;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,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{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--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;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--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;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--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;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--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;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.flex{display:flex}.w-80{width:20rem}.basis-80{flex-basis:20rem}.select-none{user-select:none}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.bg-transparent{background-color:transparent}.bg-yellow-300{--tw-bg-opacity:1;background-color:rgb(253 224 71/var(--tw-bg-opacity))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity))}.p-11{padding:2.75rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.opacity-80{opacity:.8}";
|
|
32
|
-
styleInject(css_248z,{"insertAt":"top"});
|
|
33
|
-
|
|
34
|
-
const fullWindow = {
|
|
35
|
-
height: '100vh',
|
|
36
|
-
widows: '100%',
|
|
37
|
-
};
|
|
38
|
-
const centroContainer = Object.assign(Object.assign({}, fullWindow), { display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' });
|
|
39
|
-
const FullWindow = ({ children }) => {
|
|
40
|
-
return (React__default.createElement("div", { style: centroContainer }, children));
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const _TextContainer = ({ children }, ref) => {
|
|
44
|
-
return (React__default.createElement("div", { ref: ref, draggable: false, className: "basis-80 w-80 bg-yellow-50 p-11 text-3xl select-none bg-transparent" }, children));
|
|
45
|
-
};
|
|
46
|
-
const TextContainer = React__default.forwardRef(_TextContainer);
|
|
47
|
-
|
|
48
4
|
const getHandlerRect = (index, node) => {
|
|
49
5
|
const range = document.createRange();
|
|
50
6
|
range.setStart(node, index);
|
|
51
7
|
range.setEnd(node, index);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
8
|
+
if (range.getClientRects) {
|
|
9
|
+
const rects = range.getClientRects();
|
|
10
|
+
if (rects.length === 1) {
|
|
11
|
+
return rects[0];
|
|
12
|
+
}
|
|
55
13
|
}
|
|
56
14
|
return null;
|
|
57
15
|
};
|
|
@@ -59,7 +17,12 @@ const getAllRects = (node, start, end) => {
|
|
|
59
17
|
const range = document.createRange();
|
|
60
18
|
range.setStart(node, start);
|
|
61
19
|
range.setEnd(node, end);
|
|
62
|
-
|
|
20
|
+
if (range.getClientRects) {
|
|
21
|
+
return range.getClientRects();
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return new DOMRectList();
|
|
25
|
+
}
|
|
63
26
|
};
|
|
64
27
|
const getNodeAndOffsetFromPoint = (x, y) => {
|
|
65
28
|
let range;
|
|
@@ -72,8 +35,10 @@ const getNodeAndOffsetFromPoint = (x, y) => {
|
|
|
72
35
|
}
|
|
73
36
|
else if (document.caretRangeFromPoint) {
|
|
74
37
|
range = document.caretRangeFromPoint(x, y);
|
|
75
|
-
|
|
76
|
-
|
|
38
|
+
if (range) {
|
|
39
|
+
textNode = range.startContainer;
|
|
40
|
+
offset = range.startOffset;
|
|
41
|
+
}
|
|
77
42
|
}
|
|
78
43
|
else {
|
|
79
44
|
return null;
|
|
@@ -95,6 +60,11 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
95
60
|
const [rects, setRects] = useState(null);
|
|
96
61
|
// reference
|
|
97
62
|
const textDiv = useRef(null);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (textDiv.current) {
|
|
65
|
+
textDiv.current.style.position = 'relative';
|
|
66
|
+
}
|
|
67
|
+
}, [textDiv]);
|
|
98
68
|
// mouse move handler
|
|
99
69
|
// left handler
|
|
100
70
|
useEffect(() => {
|
|
@@ -149,10 +119,12 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
149
119
|
setRects(null);
|
|
150
120
|
}
|
|
151
121
|
else {
|
|
122
|
+
const divRect = textDiv.current.getBoundingClientRect();
|
|
152
123
|
setLeftHandler({
|
|
153
124
|
height: rect.height,
|
|
154
|
-
left: rect.left,
|
|
155
|
-
top: rect.top,
|
|
125
|
+
left: rect.left - divRect.left,
|
|
126
|
+
top: rect.top - divRect.top,
|
|
127
|
+
pos: currentLeftPos,
|
|
156
128
|
});
|
|
157
129
|
}
|
|
158
130
|
}
|
|
@@ -168,10 +140,12 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
168
140
|
setRects(null);
|
|
169
141
|
}
|
|
170
142
|
else {
|
|
143
|
+
const divRect = textDiv.current.getBoundingClientRect();
|
|
171
144
|
setRightHandler({
|
|
172
145
|
height: rect.height,
|
|
173
|
-
left: rect.left,
|
|
174
|
-
top: rect.top,
|
|
146
|
+
left: rect.left - divRect.left,
|
|
147
|
+
top: rect.top - divRect.top,
|
|
148
|
+
pos: currentRightPos,
|
|
175
149
|
});
|
|
176
150
|
}
|
|
177
151
|
}
|
|
@@ -179,8 +153,26 @@ const useTextSelectionEditor = (initLeftPos, initRightPos, leftDrag, rightDrag)
|
|
|
179
153
|
useEffect(() => {
|
|
180
154
|
var _a;
|
|
181
155
|
const n = (_a = textDiv.current) === null || _a === void 0 ? void 0 : _a.childNodes[0];
|
|
182
|
-
if (n)
|
|
183
|
-
setRects(
|
|
156
|
+
if (!n) {
|
|
157
|
+
setRects(null);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const rawRects = getAllRects(n, currentLeftPos, currentRightPos);
|
|
161
|
+
let rectArray = [];
|
|
162
|
+
if (rawRects && textDiv.current) {
|
|
163
|
+
const divRect = textDiv.current.getBoundingClientRect();
|
|
164
|
+
for (let i = 0; i < rawRects.length; ++i) {
|
|
165
|
+
const aa = rawRects.item(i);
|
|
166
|
+
if (aa)
|
|
167
|
+
rectArray.push({
|
|
168
|
+
height: aa.height,
|
|
169
|
+
left: aa.left - divRect.left,
|
|
170
|
+
top: aa.top - divRect.top,
|
|
171
|
+
width: aa.width,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
setRects(rectArray);
|
|
184
176
|
}, [currentLeftPos, currentRightPos]);
|
|
185
177
|
// return
|
|
186
178
|
return [textDiv, leftHandler, rightHandler, rects];
|
|
@@ -210,6 +202,36 @@ var SvgQuoteRight = function SvgQuoteRight(props) {
|
|
|
210
202
|
})));
|
|
211
203
|
};
|
|
212
204
|
|
|
205
|
+
function styleInject(css, ref) {
|
|
206
|
+
if ( ref === void 0 ) ref = {};
|
|
207
|
+
var insertAt = ref.insertAt;
|
|
208
|
+
|
|
209
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
210
|
+
|
|
211
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
212
|
+
var style = document.createElement('style');
|
|
213
|
+
style.type = 'text/css';
|
|
214
|
+
|
|
215
|
+
if (insertAt === 'top') {
|
|
216
|
+
if (head.firstChild) {
|
|
217
|
+
head.insertBefore(style, head.firstChild);
|
|
218
|
+
} else {
|
|
219
|
+
head.appendChild(style);
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
head.appendChild(style);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (style.styleSheet) {
|
|
226
|
+
style.styleSheet.cssText = css;
|
|
227
|
+
} else {
|
|
228
|
+
style.appendChild(document.createTextNode(css));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
var css_248z = "/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:\"\"}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;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;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,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{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--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;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--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;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--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;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--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;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.flex{display:flex}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.bg-yellow-300{--tw-bg-opacity:1;background-color:rgb(253 224 71/var(--tw-bg-opacity))}.opacity-80{opacity:.8}";
|
|
233
|
+
styleInject(css_248z,{"insertAt":"top"});
|
|
234
|
+
|
|
213
235
|
const SelectionHandler = ({ pos, grab, setGrab, left }) => {
|
|
214
236
|
return (pos &&
|
|
215
237
|
React__default.createElement("div", { draggable: false, className: `bg-yellow-300 opacity-80 ${left ? 'rounded-l-md' : 'rounded-r-md'}`, style: {
|
|
@@ -235,33 +257,38 @@ const SelectionHandler = ({ pos, grab, setGrab, left }) => {
|
|
|
235
257
|
: React__default.createElement(SvgQuoteRight, null)));
|
|
236
258
|
};
|
|
237
259
|
|
|
238
|
-
const
|
|
260
|
+
const ReactTextRange = ({ initLeftPos, initRightPos, Container, children, onChange, props, }) => {
|
|
239
261
|
const [mouseOnLeft, setMouseOnLeft] = useState(false);
|
|
240
262
|
const [mouseOnRight, setMouseOnRight] = useState(false);
|
|
241
263
|
const [textDiv, leftHandler, rightHandler, rects] = useTextSelectionEditor(initLeftPos, initRightPos, mouseOnLeft, mouseOnRight);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
if (leftHandler && rightHandler) {
|
|
266
|
+
onChange({
|
|
267
|
+
left: leftHandler.pos,
|
|
268
|
+
right: rightHandler.pos,
|
|
269
|
+
});
|
|
248
270
|
}
|
|
249
|
-
}
|
|
250
|
-
return (React__default.createElement("div", { draggable: false, style: {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
divs.map((d, i) => React__default.createElement("div", { key: i, className: 'bg-yellow-300', style: {
|
|
254
|
-
userSelect: 'none',
|
|
255
|
-
position: 'absolute',
|
|
256
|
-
top: `${d.top}px`,
|
|
257
|
-
left: `${d.left}px`,
|
|
258
|
-
width: `${d.width}px`,
|
|
259
|
-
height: `${d.height}px`,
|
|
260
|
-
zIndex: -2,
|
|
261
|
-
} }, "\u00A0")),
|
|
271
|
+
}, [leftHandler, rightHandler]);
|
|
272
|
+
return (React__default.createElement("div", { draggable: false, style: Object.assign({ position: 'relative' }, props) },
|
|
273
|
+
React__default.createElement(SelectionRects, { rects: rects }),
|
|
274
|
+
React__default.createElement(Container, { ref: textDiv }, children),
|
|
262
275
|
React__default.createElement(SelectionHandler, { grab: mouseOnLeft, left: true, pos: leftHandler, setGrab: (v) => setMouseOnLeft(v) }),
|
|
263
|
-
React__default.createElement(TextContainer, { ref: textDiv }, children),
|
|
264
276
|
React__default.createElement(SelectionHandler, { grab: mouseOnRight, left: false, pos: rightHandler, setGrab: (v) => setMouseOnRight(v) })));
|
|
265
277
|
};
|
|
278
|
+
const SelectionRects = ({ rects }) => {
|
|
279
|
+
if (!rects)
|
|
280
|
+
return null;
|
|
281
|
+
return (React__default.createElement(React__default.Fragment, null, rects.map((d, i) => React__default.createElement(SelectionRect, { key: i, rect: d }))));
|
|
282
|
+
};
|
|
283
|
+
const SelectionRect = ({ rect }) => {
|
|
284
|
+
return (React__default.createElement("div", { className: 'bg-yellow-300', style: {
|
|
285
|
+
userSelect: 'none',
|
|
286
|
+
position: 'absolute',
|
|
287
|
+
top: `${rect.top}px`,
|
|
288
|
+
left: `${rect.left}px`,
|
|
289
|
+
width: `${rect.width}px`,
|
|
290
|
+
height: `${rect.height}px`,
|
|
291
|
+
} }, "\u00A0"));
|
|
292
|
+
};
|
|
266
293
|
|
|
267
|
-
export {
|
|
294
|
+
export { ReactTextRange };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HandlerPos } from './handler-pos';
|
|
3
|
+
import { Rect } from './rect';
|
|
3
4
|
declare global {
|
|
4
5
|
interface Document {
|
|
5
6
|
caretPositionFromPoint: any;
|
|
@@ -9,5 +10,5 @@ export declare const useTextSelectionEditor: (initLeftPos: number, initRightPos:
|
|
|
9
10
|
React.MutableRefObject<HTMLDivElement | null>,
|
|
10
11
|
HandlerPos | null,
|
|
11
12
|
HandlerPos | null,
|
|
12
|
-
|
|
13
|
+
Rect[] | null
|
|
13
14
|
];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import React, { FC } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type TextContainer = React.ForwardRefExoticComponent<{
|
|
4
4
|
children: React.ReactNode;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
interface RangeState {
|
|
7
|
+
left: number;
|
|
8
|
+
right: number;
|
|
9
|
+
}
|
|
10
|
+
declare const ReactTextRange: FC<{
|
|
8
11
|
initLeftPos: number;
|
|
9
12
|
initRightPos: number;
|
|
13
|
+
Container: TextContainer;
|
|
10
14
|
children: string;
|
|
15
|
+
onChange: (state: RangeState) => void;
|
|
16
|
+
props?: React.CSSProperties;
|
|
11
17
|
}>;
|
|
12
18
|
|
|
13
|
-
export {
|
|
19
|
+
export { type RangeState, ReactTextRange, type TextContainer };
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-text-range",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "text selection editor for React",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
7
7
|
"types": "./dist/esm/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
|
+
"build:sample": "rollup -c && cp ./src/server.js ./dist/cjs && cp ./src/index.html ./dist/cjs",
|
|
9
10
|
"build": "rollup -c",
|
|
10
11
|
"test": "jest --config jestconfig.json",
|
|
11
12
|
"prepare": "npm run build",
|
|
@@ -29,17 +30,21 @@
|
|
|
29
30
|
"LICENSE",
|
|
30
31
|
"README.md"
|
|
31
32
|
],
|
|
32
|
-
"peerDependencies": {
|
|
33
|
-
"react": ">=16",
|
|
34
|
-
"react-dom": ">=16"
|
|
35
|
-
},
|
|
36
33
|
"devDependencies": {
|
|
34
|
+
"@babel/core": "^7.23.0",
|
|
35
|
+
"@babel/preset-env": "^7.22.20",
|
|
36
|
+
"@babel/preset-react": "^7.22.15",
|
|
37
|
+
"@rollup/plugin-babel": "^6.0.3",
|
|
38
|
+
"@rollup/plugin-commonjs": "^25.0.4",
|
|
39
|
+
"@rollup/plugin-node-resolve": "^15.2.1",
|
|
40
|
+
"@rollup/plugin-replace": "^5.0.2",
|
|
37
41
|
"@rollup/plugin-typescript": "^11.1.4",
|
|
38
42
|
"@svgr/rollup": "^8.1.0",
|
|
39
43
|
"@testing-library/react": "^14.0.0",
|
|
40
44
|
"@types/jest": "^29.5.5",
|
|
41
45
|
"@types/react": "^18.2.24",
|
|
42
46
|
"autoprefixer": "^10.4.16",
|
|
47
|
+
"connect": "^3.7.0",
|
|
43
48
|
"jest": "^29.7.0",
|
|
44
49
|
"jest-canvas-mock": "^2.5.2",
|
|
45
50
|
"jest-environment-jsdom": "^29.7.0",
|
|
@@ -50,9 +55,14 @@
|
|
|
50
55
|
"rollup-plugin-dts": "^6.0.2",
|
|
51
56
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
52
57
|
"rollup-plugin-postcss": "^4.0.2",
|
|
58
|
+
"serve-static": "^1.15.0",
|
|
53
59
|
"tailwindcss": "^3.3.3",
|
|
54
60
|
"ts-jest": "^29.1.1",
|
|
55
61
|
"tslib": "^2.6.2",
|
|
56
62
|
"typescript": "^5.2.2"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"react": ">=16",
|
|
66
|
+
"react-dom": ">=16"
|
|
57
67
|
}
|
|
58
|
-
}
|
|
68
|
+
}
|