@collabchron/notiq 0.2.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/README.md +71 -0
- package/components.json +21 -0
- package/eslint.config.mjs +16 -0
- package/next.config.ts +12 -0
- package/package.json +108 -0
- package/postcss.config.mjs +5 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/images/icons/plus.svg +10 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/src/app/actions.ts +2 -0
- package/src/app/api/ai/route.ts +175 -0
- package/src/app/api/edgestore/[...edgestore]/route.ts +28 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +205 -0
- package/src/app/layout.tsx +38 -0
- package/src/app/page.tsx +12 -0
- package/src/components/editor/Core.tsx +220 -0
- package/src/components/editor/hooks/instructions-messages.ts +300 -0
- package/src/components/editor/hooks/use-mobile.ts +19 -0
- package/src/components/editor/hooks/useReport.ts +67 -0
- package/src/components/editor/hooks/useResizeObservert.ts +22 -0
- package/src/components/editor/index.tsx +39 -0
- package/src/components/editor/lexical-on-change.tsx +28 -0
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleContainerNode.ts +92 -0
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleContentNode.ts +65 -0
- package/src/components/editor/nodes/CollapsibleNode/CollapsibleTitleNode.ts +105 -0
- package/src/components/editor/nodes/EquationNode/EquationComponent.tsx +143 -0
- package/src/components/editor/nodes/EquationNode/EquationNode.tsx +170 -0
- package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx +228 -0
- package/src/components/editor/nodes/ExcalidrawNode/ExcalidrawImage.tsx +137 -0
- package/src/components/editor/nodes/ExcalidrawNode/ImageResizer.tsx +317 -0
- package/src/components/editor/nodes/ExcalidrawNode/index.tsx +204 -0
- package/src/components/editor/nodes/FigmaNode/FigmaNode.tsx +134 -0
- package/src/components/editor/nodes/Hint/HintComponet.tsx +221 -0
- package/src/components/editor/nodes/Hint/index.tsx +190 -0
- package/src/components/editor/nodes/ImageNode/index.tsx +328 -0
- package/src/components/editor/nodes/InlineImageNode/InlineImageComponent.tsx +383 -0
- package/src/components/editor/nodes/InlineImageNode/InlineImageNode.css +94 -0
- package/src/components/editor/nodes/InlineImageNode/InlineImageNode.tsx +309 -0
- package/src/components/editor/nodes/LayoutNode/LayoutContainerNode.ts +146 -0
- package/src/components/editor/nodes/LayoutNode/LayoutItemNode.ts +79 -0
- package/src/components/editor/nodes/PollNode/index.tsx +204 -0
- package/src/components/editor/nodes/Stepper/index.tsx +260 -0
- package/src/components/editor/nodes/TweetNode/index.tsx +214 -0
- package/src/components/editor/nodes/index.ts +81 -0
- package/src/components/editor/plugins/AutoEmbedPlugin/index.tsx +350 -0
- package/src/components/editor/plugins/AutoLinkPlugin/index.tsx +56 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/components/CopyButton.tsx +70 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/components/PrettierButton.tsx +192 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/index.tsx +217 -0
- package/src/components/editor/plugins/CodeActionMenuPlugin/utils.ts +26 -0
- package/src/components/editor/plugins/CodeHighlightPlugin/index.ts +21 -0
- package/src/components/editor/plugins/CollapsiblePlugin/Collapsible.css +76 -0
- package/src/components/editor/plugins/CollapsiblePlugin/index.ts +228 -0
- package/src/components/editor/plugins/DragDropPastePlugin/index.tsx +44 -0
- package/src/components/editor/plugins/DraggableBlockPlugin/index.tsx +52 -0
- package/src/components/editor/plugins/EquationsPlugin/index.tsx +85 -0
- package/src/components/editor/plugins/ExcalidrawPlugin/index.tsx +98 -0
- package/src/components/editor/plugins/FigmaPlugin/index.tsx +42 -0
- package/src/components/editor/plugins/FloatingLinkEditorPlugin/index.tsx +445 -0
- package/src/components/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +275 -0
- package/src/components/editor/plugins/ImagesPlugin/index.tsx +222 -0
- package/src/components/editor/plugins/InlineImagePlugin/index.tsx +351 -0
- package/src/components/editor/plugins/LayoutPlugin/index.tsx +238 -0
- package/src/components/editor/plugins/LinkPlugin/index.tsx +36 -0
- package/src/components/editor/plugins/LinkWithMetaData/index.tsx +271 -0
- package/src/components/editor/plugins/MarkdownShortcutPlugin/index.tsx +11 -0
- package/src/components/editor/plugins/MarkdownTransformers/index.tsx +304 -0
- package/src/components/editor/plugins/PollPlugin/index.tsx +49 -0
- package/src/components/editor/plugins/ShortcutsPlugin/index.tsx +180 -0
- package/src/components/editor/plugins/ShortcutsPlugin/shortcuts.ts +253 -0
- package/src/components/editor/plugins/SlashCommand/index.tsx +621 -0
- package/src/components/editor/plugins/SpeechToTextPlugin/index.ts +127 -0
- package/src/components/editor/plugins/TabFocusPlugin/index.ts +58 -0
- package/src/components/editor/plugins/TableCellActionMenuPlugin/index.tsx +759 -0
- package/src/components/editor/plugins/TableCellResizer/index.tsx +438 -0
- package/src/components/editor/plugins/TableHoverActionsPlugin/index.tsx +314 -0
- package/src/components/editor/plugins/TablePlugin/index.tsx +99 -0
- package/src/components/editor/plugins/ToolbarPlugin/index.tsx +522 -0
- package/src/components/editor/plugins/TwitterPlugin/index.ts +35 -0
- package/src/components/editor/plugins/YouTubeNode/index.tsx +179 -0
- package/src/components/editor/plugins/YouTubePlugin/index.ts +41 -0
- package/src/components/editor/themes/editor-theme.ts +113 -0
- package/src/components/editor/themes/theme.css +377 -0
- package/src/components/editor/utils/ai.ts +291 -0
- package/src/components/editor/utils/canUseDOM.ts +12 -0
- package/src/components/editor/utils/editorFormatting.ts +282 -0
- package/src/components/editor/utils/environment.ts +50 -0
- package/src/components/editor/utils/extract-data.ts +166 -0
- package/src/components/editor/utils/getAllLexicalChildren.ts +13 -0
- package/src/components/editor/utils/getDOMRangeRect.ts +27 -0
- package/src/components/editor/utils/getSelectedNode.ts +27 -0
- package/src/components/editor/utils/gif.ts +29 -0
- package/src/components/editor/utils/invariant.ts +15 -0
- package/src/components/editor/utils/setFloatingElemPosition.ts +51 -0
- package/src/components/editor/utils/setFloatingElemPositionForLinkEditor.ts +40 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/getNodePlaceholder.ts +51 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/setNodePlaceholderFromSelection.ts +15 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/setPlaceholderOnSelection.ts +114 -0
- package/src/components/editor/utils/setNodePlaceholderFromSelection/styles.css +6 -0
- package/src/components/editor/utils/url.ts +109 -0
- package/src/components/editor/utils/useLayoutEffect.ts +13 -0
- package/src/components/providers/QueryProvider.tsx +15 -0
- package/src/components/providers/SharedHistoryContext.tsx +28 -0
- package/src/components/providers/ToolbarContext.tsx +123 -0
- package/src/components/providers/theme-provider.tsx +11 -0
- package/src/components/theme/ModeToggle.tsx +40 -0
- package/src/components/ui/FileInput.tsx +40 -0
- package/src/components/ui/Input.css +32 -0
- package/src/components/ui/Select.css +42 -0
- package/src/components/ui/Select.tsx +36 -0
- package/src/components/ui/TextInput.tsx +48 -0
- package/src/components/ui/ai/ai-button.tsx +574 -0
- package/src/components/ui/ai/border.tsx +99 -0
- package/src/components/ui/ai/placeholder-input-vanish.tsx +282 -0
- package/src/components/ui/button.tsx +89 -0
- package/src/components/ui/card.tsx +76 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/command.tsx +153 -0
- package/src/components/ui/dialog/Dialog.css +25 -0
- package/src/components/ui/dialog/Dialog.tsx +34 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/drop-downs/background-color.tsx +183 -0
- package/src/components/ui/drop-downs/block-format.tsx +159 -0
- package/src/components/ui/drop-downs/code.tsx +42 -0
- package/src/components/ui/drop-downs/color.tsx +177 -0
- package/src/components/ui/drop-downs/font-size.tsx +138 -0
- package/src/components/ui/drop-downs/font.tsx +155 -0
- package/src/components/ui/drop-downs/index.tsx +122 -0
- package/src/components/ui/drop-downs/insert-node.tsx +213 -0
- package/src/components/ui/drop-downs/text-align.tsx +123 -0
- package/src/components/ui/drop-downs/text-format.tsx +104 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/equation/EquationEditor.css +38 -0
- package/src/components/ui/equation/EquationEditor.tsx +56 -0
- package/src/components/ui/equation/KatexEquationAlterer.css +41 -0
- package/src/components/ui/equation/KatexEquationAlterer.tsx +83 -0
- package/src/components/ui/equation/KatexRenderer.tsx +66 -0
- package/src/components/ui/excalidraw/ExcalidrawModal.css +64 -0
- package/src/components/ui/excalidraw/ExcalidrawModal.tsx +234 -0
- package/src/components/ui/excalidraw/Modal.css +62 -0
- package/src/components/ui/excalidraw/Modal.tsx +110 -0
- package/src/components/ui/hover-card.tsx +29 -0
- package/src/components/ui/image/error-image.tsx +17 -0
- package/src/components/ui/image/file-upload.tsx +240 -0
- package/src/components/ui/image/image-resizer.tsx +297 -0
- package/src/components/ui/image/image-toolbar.tsx +264 -0
- package/src/components/ui/image/index.tsx +408 -0
- package/src/components/ui/image/lazy-image.tsx +68 -0
- package/src/components/ui/image/lazy-video.tsx +71 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/models/custom-dialog.tsx +320 -0
- package/src/components/ui/models/insert-gif.tsx +90 -0
- package/src/components/ui/models/insert-image.tsx +52 -0
- package/src/components/ui/models/insert-poll.tsx +29 -0
- package/src/components/ui/models/insert-table.tsx +62 -0
- package/src/components/ui/models/use-model.tsx +91 -0
- package/src/components/ui/poll/poll-component.tsx +304 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/progress.tsx +28 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/sonner.tsx +31 -0
- package/src/components/ui/stepper/step.tsx +179 -0
- package/src/components/ui/stepper/stepper.tsx +89 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/toggle.tsx +71 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/components/ui/write/text-format-floting-toolbar.tsx +346 -0
- package/src/lib/edgestore.ts +9 -0
- package/src/lib/pinecone-client.ts +0 -0
- package/src/lib/utils.ts +6 -0
- package/src/utils/docSerialization.ts +77 -0
- package/src/utils/emoji-list.ts +16615 -0
- package/src/utils/getDOMRangeRect.ts +27 -0
- package/src/utils/getSelectedNode.ts +27 -0
- package/src/utils/getThemeSelector.ts +25 -0
- package/src/utils/isMobileWidth.ts +7 -0
- package/src/utils/joinClasses.ts +13 -0
- package/src/utils/setFloatingElemPosition.ts +74 -0
- package/src/utils/setFloatingElemPositionForLinkEditor.ts +46 -0
- package/src/utils/swipe.ts +127 -0
- package/src/utils/url.ts +38 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
export function getDOMRangeRect(
|
|
9
|
+
nativeSelection: Selection,
|
|
10
|
+
rootElement: HTMLElement,
|
|
11
|
+
): DOMRect {
|
|
12
|
+
const domRange = nativeSelection.getRangeAt(0);
|
|
13
|
+
|
|
14
|
+
let rect;
|
|
15
|
+
|
|
16
|
+
if (nativeSelection.anchorNode === rootElement) {
|
|
17
|
+
let inner = rootElement;
|
|
18
|
+
while (inner.firstElementChild != null) {
|
|
19
|
+
inner = inner.firstElementChild as HTMLElement;
|
|
20
|
+
}
|
|
21
|
+
rect = inner.getBoundingClientRect();
|
|
22
|
+
} else {
|
|
23
|
+
rect = domRange.getBoundingClientRect();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return rect;
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import {$isAtNodeEnd} from '@lexical/selection';
|
|
9
|
+
import {ElementNode, RangeSelection, TextNode} from 'lexical';
|
|
10
|
+
|
|
11
|
+
export function getSelectedNode(
|
|
12
|
+
selection: RangeSelection,
|
|
13
|
+
): TextNode | ElementNode {
|
|
14
|
+
const anchor = selection.anchor;
|
|
15
|
+
const focus = selection.focus;
|
|
16
|
+
const anchorNode = selection.anchor.getNode();
|
|
17
|
+
const focusNode = selection.focus.getNode();
|
|
18
|
+
if (anchorNode === focusNode) {
|
|
19
|
+
return anchorNode;
|
|
20
|
+
}
|
|
21
|
+
const isBackward = selection.isBackward();
|
|
22
|
+
if (isBackward) {
|
|
23
|
+
return $isAtNodeEnd(focus) ? anchorNode : focusNode;
|
|
24
|
+
} else {
|
|
25
|
+
return $isAtNodeEnd(anchor) ? anchorNode : focusNode;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {EditorThemeClasses} from 'lexical';
|
|
10
|
+
|
|
11
|
+
export function getThemeSelector(
|
|
12
|
+
getTheme: () => EditorThemeClasses | null | undefined,
|
|
13
|
+
name: keyof EditorThemeClasses,
|
|
14
|
+
): string {
|
|
15
|
+
const className = getTheme()?.[name];
|
|
16
|
+
if (typeof className !== 'string') {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`getThemeClass: required theme property ${name} not defined`,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return className
|
|
22
|
+
.split(/\s+/g)
|
|
23
|
+
.map((cls) => `.${cls}`)
|
|
24
|
+
.join();
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export default function joinClasses(
|
|
10
|
+
...args: Array<string | boolean | null | undefined>
|
|
11
|
+
) {
|
|
12
|
+
return args.filter(Boolean).join(' ');
|
|
13
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
const VERTICAL_GAP = 10;
|
|
9
|
+
const HORIZONTAL_OFFSET = 5;
|
|
10
|
+
|
|
11
|
+
export function setFloatingElemPosition(
|
|
12
|
+
targetRect: DOMRect | null,
|
|
13
|
+
floatingElem: HTMLElement,
|
|
14
|
+
anchorElem: HTMLElement,
|
|
15
|
+
isLink: boolean = false,
|
|
16
|
+
verticalGap: number = VERTICAL_GAP,
|
|
17
|
+
horizontalOffset: number = HORIZONTAL_OFFSET,
|
|
18
|
+
): void {
|
|
19
|
+
const scrollerElem = anchorElem.parentElement;
|
|
20
|
+
|
|
21
|
+
if (targetRect === null || !scrollerElem) {
|
|
22
|
+
floatingElem.style.opacity = '0';
|
|
23
|
+
floatingElem.style.transform = 'translate(-10000px, -10000px)';
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const floatingElemRect = floatingElem.getBoundingClientRect();
|
|
28
|
+
const anchorElementRect = anchorElem.getBoundingClientRect();
|
|
29
|
+
const editorScrollerRect = scrollerElem.getBoundingClientRect();
|
|
30
|
+
|
|
31
|
+
let top = targetRect.top - floatingElemRect.height - verticalGap;
|
|
32
|
+
let left = targetRect.left - horizontalOffset;
|
|
33
|
+
|
|
34
|
+
// Check if text is end-aligned
|
|
35
|
+
const selection = window.getSelection();
|
|
36
|
+
if (selection && selection.rangeCount > 0) {
|
|
37
|
+
const range = selection.getRangeAt(0);
|
|
38
|
+
const textNode = range.startContainer;
|
|
39
|
+
if (textNode.nodeType === Node.ELEMENT_NODE || textNode.parentElement) {
|
|
40
|
+
const textElement =
|
|
41
|
+
textNode.nodeType === Node.ELEMENT_NODE
|
|
42
|
+
? (textNode as Element)
|
|
43
|
+
: (textNode.parentElement as Element);
|
|
44
|
+
const textAlign = window.getComputedStyle(textElement).textAlign;
|
|
45
|
+
|
|
46
|
+
if (textAlign === 'right' || textAlign === 'end') {
|
|
47
|
+
// For end-aligned text, position the toolbar relative to the text end
|
|
48
|
+
left = targetRect.right - floatingElemRect.width + horizontalOffset;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (top < editorScrollerRect.top) {
|
|
54
|
+
// adjusted height for link element if the element is at top
|
|
55
|
+
top +=
|
|
56
|
+
floatingElemRect.height +
|
|
57
|
+
targetRect.height +
|
|
58
|
+
verticalGap * (isLink ? 9 : 2);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (left + floatingElemRect.width > editorScrollerRect.right) {
|
|
62
|
+
left = editorScrollerRect.right - floatingElemRect.width - horizontalOffset;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (left < editorScrollerRect.left) {
|
|
66
|
+
left = editorScrollerRect.left + horizontalOffset;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
top -= anchorElementRect.top;
|
|
70
|
+
left -= anchorElementRect.left;
|
|
71
|
+
|
|
72
|
+
floatingElem.style.opacity = '1';
|
|
73
|
+
floatingElem.style.transform = `translate(${left}px, ${top}px)`;
|
|
74
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
const VERTICAL_GAP = 10;
|
|
9
|
+
const HORIZONTAL_OFFSET = 5;
|
|
10
|
+
|
|
11
|
+
export function setFloatingElemPositionForLinkEditor(
|
|
12
|
+
targetRect: DOMRect | null,
|
|
13
|
+
floatingElem: HTMLElement,
|
|
14
|
+
anchorElem: HTMLElement,
|
|
15
|
+
verticalGap: number = VERTICAL_GAP,
|
|
16
|
+
horizontalOffset: number = HORIZONTAL_OFFSET,
|
|
17
|
+
): void {
|
|
18
|
+
const scrollerElem = anchorElem.parentElement;
|
|
19
|
+
|
|
20
|
+
if (targetRect === null || !scrollerElem) {
|
|
21
|
+
floatingElem.style.opacity = '0';
|
|
22
|
+
floatingElem.style.transform = 'translate(-10000px, -10000px)';
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const floatingElemRect = floatingElem.getBoundingClientRect();
|
|
27
|
+
const anchorElementRect = anchorElem.getBoundingClientRect();
|
|
28
|
+
const editorScrollerRect = scrollerElem.getBoundingClientRect();
|
|
29
|
+
|
|
30
|
+
let top = targetRect.top - verticalGap;
|
|
31
|
+
let left = targetRect.left - horizontalOffset;
|
|
32
|
+
|
|
33
|
+
if (top < editorScrollerRect.top) {
|
|
34
|
+
top += floatingElemRect.height + targetRect.height + verticalGap * 2;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (left + floatingElemRect.width > editorScrollerRect.right) {
|
|
38
|
+
left = editorScrollerRect.right - floatingElemRect.width - horizontalOffset;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
top -= anchorElementRect.top;
|
|
42
|
+
left -= anchorElementRect.left;
|
|
43
|
+
|
|
44
|
+
floatingElem.style.opacity = '1';
|
|
45
|
+
floatingElem.style.transform = `translate(${left}px, ${top}px)`;
|
|
46
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
type Force = [number, number];
|
|
10
|
+
type Listener = (force: Force, e: TouchEvent) => void;
|
|
11
|
+
type ElementValues = {
|
|
12
|
+
start: null | Force;
|
|
13
|
+
listeners: Set<Listener>;
|
|
14
|
+
handleTouchstart: (e: TouchEvent) => void;
|
|
15
|
+
handleTouchend: (e: TouchEvent) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const elements = new WeakMap<HTMLElement, ElementValues>();
|
|
19
|
+
|
|
20
|
+
function readTouch(e: TouchEvent): [number, number] | null {
|
|
21
|
+
const touch = e.changedTouches[0];
|
|
22
|
+
if (touch === undefined) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return [touch.clientX, touch.clientY];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function addListener(element: HTMLElement, cb: Listener): () => void {
|
|
29
|
+
let elementValues = elements.get(element);
|
|
30
|
+
if (elementValues === undefined) {
|
|
31
|
+
const listeners = new Set<Listener>();
|
|
32
|
+
const handleTouchstart = (e: TouchEvent) => {
|
|
33
|
+
if (elementValues !== undefined) {
|
|
34
|
+
elementValues.start = readTouch(e);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const handleTouchend = (e: TouchEvent) => {
|
|
38
|
+
if (elementValues === undefined) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const start = elementValues.start;
|
|
42
|
+
if (start === null) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const end = readTouch(e);
|
|
46
|
+
for (const listener of listeners) {
|
|
47
|
+
if (end !== null) {
|
|
48
|
+
listener([end[0] - start[0], end[1] - start[1]], e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
element.addEventListener('touchstart', handleTouchstart);
|
|
53
|
+
element.addEventListener('touchend', handleTouchend);
|
|
54
|
+
|
|
55
|
+
elementValues = {
|
|
56
|
+
handleTouchend,
|
|
57
|
+
handleTouchstart,
|
|
58
|
+
listeners,
|
|
59
|
+
start: null,
|
|
60
|
+
};
|
|
61
|
+
elements.set(element, elementValues);
|
|
62
|
+
}
|
|
63
|
+
elementValues.listeners.add(cb);
|
|
64
|
+
return () => deleteListener(element, cb);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function deleteListener(element: HTMLElement, cb: Listener): void {
|
|
68
|
+
const elementValues = elements.get(element);
|
|
69
|
+
if (elementValues === undefined) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const listeners = elementValues.listeners;
|
|
73
|
+
listeners.delete(cb);
|
|
74
|
+
if (listeners.size === 0) {
|
|
75
|
+
elements.delete(element);
|
|
76
|
+
element.removeEventListener('touchstart', elementValues.handleTouchstart);
|
|
77
|
+
element.removeEventListener('touchend', elementValues.handleTouchend);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function addSwipeLeftListener(
|
|
82
|
+
element: HTMLElement,
|
|
83
|
+
cb: (_force: number, e: TouchEvent) => void,
|
|
84
|
+
) {
|
|
85
|
+
return addListener(element, (force, e) => {
|
|
86
|
+
const [x, y] = force;
|
|
87
|
+
if (x < 0 && -x > Math.abs(y)) {
|
|
88
|
+
cb(x, e);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function addSwipeRightListener(
|
|
94
|
+
element: HTMLElement,
|
|
95
|
+
cb: (_force: number, e: TouchEvent) => void,
|
|
96
|
+
) {
|
|
97
|
+
return addListener(element, (force, e) => {
|
|
98
|
+
const [x, y] = force;
|
|
99
|
+
if (x > 0 && x > Math.abs(y)) {
|
|
100
|
+
cb(x, e);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function addSwipeUpListener(
|
|
106
|
+
element: HTMLElement,
|
|
107
|
+
cb: (_force: number, e: TouchEvent) => void,
|
|
108
|
+
) {
|
|
109
|
+
return addListener(element, (force, e) => {
|
|
110
|
+
const [x, y] = force;
|
|
111
|
+
if (y < 0 && -y > Math.abs(x)) {
|
|
112
|
+
cb(x, e);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function addSwipeDownListener(
|
|
118
|
+
element: HTMLElement,
|
|
119
|
+
cb: (_force: number, e: TouchEvent) => void,
|
|
120
|
+
) {
|
|
121
|
+
return addListener(element, (force, e) => {
|
|
122
|
+
const [x, y] = force;
|
|
123
|
+
if (y > 0 && y > Math.abs(x)) {
|
|
124
|
+
cb(x, e);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
package/src/utils/url.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const SUPPORTED_URL_PROTOCOLS = new Set([
|
|
10
|
+
'http:',
|
|
11
|
+
'https:',
|
|
12
|
+
'mailto:',
|
|
13
|
+
'sms:',
|
|
14
|
+
'tel:',
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
export function sanitizeUrl(url: string): string {
|
|
18
|
+
try {
|
|
19
|
+
const parsedUrl = new URL(url);
|
|
20
|
+
// eslint-disable-next-line no-script-url
|
|
21
|
+
if (!SUPPORTED_URL_PROTOCOLS.has(parsedUrl.protocol)) {
|
|
22
|
+
return 'about:blank';
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
return url;
|
|
26
|
+
}
|
|
27
|
+
return url;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Source: https://stackoverflow.com/a/8234912/2013580
|
|
31
|
+
const urlRegExp = new RegExp(
|
|
32
|
+
/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/,
|
|
33
|
+
);
|
|
34
|
+
export function validateUrl(url: string): boolean {
|
|
35
|
+
// TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.
|
|
36
|
+
// Maybe show a dialog where they user can type the URL before inserting it.
|
|
37
|
+
return url === 'https://' || urlRegExp.test(url);
|
|
38
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
26
|
+
"exclude": ["node_modules"]
|
|
27
|
+
}
|