@eventuras/scribo 0.4.2

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.
@@ -0,0 +1,28 @@
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
+
10
+ .Placeholder__root {
11
+ font-size: 15px;
12
+ color: #999;
13
+ overflow: hidden;
14
+ position: absolute;
15
+ text-overflow: ellipsis;
16
+ top: 8px;
17
+ left: 28px;
18
+ right: 28px;
19
+ user-select: none;
20
+ white-space: nowrap;
21
+ display: inline-block;
22
+ pointer-events: none;
23
+ }
24
+ @media (max-width: 1025px) {
25
+ .Placeholder__root {
26
+ left: 8px;
27
+ }
28
+ }
@@ -0,0 +1,21 @@
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 type {JSX} from 'react';
9
+ import "./Placeholder.css";
10
+
11
+ import { ReactNode } from "react";
12
+
13
+ export default function Placeholder({
14
+ children,
15
+ className,
16
+ }: {
17
+ children: ReactNode;
18
+ className?: string;
19
+ }): JSX.Element {
20
+ return <div className={className || "Placeholder__root"}>{children}</div>;
21
+ }
@@ -0,0 +1,54 @@
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 const CAN_USE_DOM: boolean =
10
+ typeof window !== "undefined" &&
11
+ typeof window.document !== "undefined" &&
12
+ typeof window.document.createElement !== "undefined";
13
+
14
+ declare global {
15
+ interface Document {
16
+ documentMode?: unknown;
17
+ }
18
+
19
+ interface Window {
20
+ MSStream?: unknown;
21
+ }
22
+ }
23
+
24
+ const documentMode =
25
+ CAN_USE_DOM && "documentMode" in document ? document.documentMode : null;
26
+
27
+ //TODO forcing false on this to stop mismatch render between ssr and clientside
28
+ export const IS_APPLE = false;
29
+ //CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
30
+
31
+ export const IS_FIREFOX: boolean =
32
+ CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
33
+
34
+ export const CAN_USE_BEFORE_INPUT: boolean =
35
+ CAN_USE_DOM && "InputEvent" in window && !documentMode
36
+ ? "getTargetRanges" in new window.InputEvent("input")
37
+ : false;
38
+
39
+ export const IS_SAFARI: boolean =
40
+ CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
41
+
42
+ export const IS_IOS: boolean =
43
+ CAN_USE_DOM &&
44
+ /iPad|iPhone|iPod/.test(navigator.userAgent) &&
45
+ !window.MSStream;
46
+
47
+ // Keep these in case we need to use them in the future.
48
+ // export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
49
+ export const IS_CHROME: boolean =
50
+ CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent);
51
+ // export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
52
+
53
+ export const IS_APPLE_WEBKIT =
54
+ CAN_USE_DOM && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && !IS_CHROME;
@@ -0,0 +1,28 @@
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
+ * source: https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/utils/getSelectedNode.ts
8
+ */
9
+ import { $isAtNodeEnd } from "@lexical/selection";
10
+ import { ElementNode, RangeSelection, TextNode } from "lexical";
11
+
12
+ export function getSelectedNode(
13
+ selection: RangeSelection,
14
+ ): TextNode | ElementNode {
15
+ const anchor = selection.anchor;
16
+ const focus = selection.focus;
17
+ const anchorNode = selection.anchor.getNode();
18
+ const focusNode = selection.focus.getNode();
19
+ if (anchorNode === focusNode) {
20
+ return anchorNode;
21
+ }
22
+ const isBackward = selection.isBackward();
23
+ if (isBackward) {
24
+ return $isAtNodeEnd(focus) ? anchorNode : focusNode;
25
+ } else {
26
+ return $isAtNodeEnd(anchor) ? anchorNode : focusNode;
27
+ }
28
+ }
@@ -0,0 +1,51 @@
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
+ if (top < editorScrollerRect.top) {
35
+ // adjusted height for link element if the element is at top
36
+ top +=
37
+ floatingElemRect.height +
38
+ targetRect.height +
39
+ verticalGap * (isLink ? 9 : 2);
40
+ }
41
+
42
+ if (left + floatingElemRect.width > editorScrollerRect.right) {
43
+ left = editorScrollerRect.right - floatingElemRect.width - horizontalOffset;
44
+ }
45
+
46
+ top -= anchorElementRect.top;
47
+ left -= anchorElementRect.left;
48
+
49
+ floatingElem.style.opacity = '1';
50
+ floatingElem.style.transform = `translate(${left}px, ${top}px)`;
51
+ }
@@ -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,39 @@
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
+ * Source: https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/utils/url.ts
8
+ */
9
+
10
+ const SUPPORTED_URL_PROTOCOLS = new Set([
11
+ "http:",
12
+ "https:",
13
+ "mailto:",
14
+ "sms:",
15
+ "tel:",
16
+ ]);
17
+
18
+ export function sanitizeUrl(url: string): string {
19
+ try {
20
+ const parsedUrl = new URL(url);
21
+ // eslint-disable-next-line no-script-url
22
+ if (!SUPPORTED_URL_PROTOCOLS.has(parsedUrl.protocol)) {
23
+ return "about:blank";
24
+ }
25
+ } catch {
26
+ return url;
27
+ }
28
+ return url;
29
+ }
30
+
31
+ // Source: https://stackoverflow.com/a/8234912/2013580
32
+ const urlRegExp = new RegExp(
33
+ /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/,
34
+ );
35
+ export function validateUrl(url: string): boolean {
36
+ // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.
37
+ // Maybe show a dialog where they user can type the URL before inserting it.
38
+ return url === "https://" || urlRegExp.test(url);
39
+ }
@@ -0,0 +1,8 @@
1
+ // vite-env.d.ts
2
+ /// <reference types="vite/client" />
3
+
4
+ // allow raw‑text imports of Markdown files
5
+ declare module '*.md?raw' {
6
+ const content: string;
7
+ export default content;
8
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true,
8
+ "strict": true
9
+ },
10
+ "include": ["vite.config.ts"]
11
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react-swc';
3
+ import { resolve } from 'path';
4
+
5
+ // Check build mode
6
+ const buildSite = process.env.BUILD_SITE === 'true';
7
+
8
+ export default defineConfig({
9
+ plugins: [react()],
10
+ build: buildSite
11
+ ? {
12
+ // Build demo site
13
+ outDir: 'dist/site',
14
+ }
15
+ : {
16
+ // Build library
17
+ lib: {
18
+ entry: resolve(__dirname, 'src/main.tsx'),
19
+ name: 'Scribo',
20
+ fileName: 'scribo',
21
+ },
22
+ rollupOptions: {
23
+ external: ['react', 'react-dom'],
24
+ output: {
25
+ globals: {
26
+ react: 'React',
27
+ 'react-dom': 'ReactDOM',
28
+ },
29
+ },
30
+ },
31
+ },
32
+ });