beez-ui 0.7.0 → 0.8.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/CHANGELOG.md +21 -3
- package/README.md +290 -274
- package/dist/components/account-menu.d.ts +53 -0
- package/dist/components/account-menu.js +405 -0
- package/dist/components/animated-collapse.d.ts +19 -0
- package/dist/components/animated-collapse.js +81 -0
- package/dist/components/animated-count.d.ts +13 -0
- package/dist/components/animated-count.js +105 -0
- package/dist/components/animated-list-item.d.ts +25 -0
- package/dist/components/animated-list-item.js +132 -0
- package/dist/components/bouncing-dots-loader.d.ts +19 -0
- package/dist/components/bouncing-dots-loader.js +47 -0
- package/dist/components/confirm-delete-button.d.ts +29 -0
- package/dist/components/confirm-delete-button.js +254 -0
- package/dist/components/empty-state.d.ts +24 -0
- package/dist/components/empty-state.js +37 -0
- package/dist/components/error-state.d.ts +20 -0
- package/dist/components/error-state.js +145 -0
- package/dist/components/external-browser-handoff.d.ts +27 -0
- package/dist/components/external-browser-handoff.js +306 -0
- package/dist/components/file-upload.d.ts +78 -0
- package/dist/components/file-upload.js +678 -0
- package/dist/components/info-popover.d.ts +23 -0
- package/dist/components/info-popover.js +158 -0
- package/dist/components/month-calendar-header.d.ts +65 -0
- package/dist/components/month-calendar-header.js +337 -0
- package/dist/components/month-grid.d.ts +59 -0
- package/dist/components/month-grid.js +301 -0
- package/dist/components/notification-bell.d.ts +50 -0
- package/dist/components/notification-bell.js +338 -0
- package/dist/components/notification-panel.d.ts +56 -0
- package/dist/components/notification-panel.js +281 -0
- package/dist/components/open-in-browser-cta.d.ts +22 -0
- package/dist/components/open-in-browser-cta.js +61 -0
- package/dist/components/presence-swap.d.ts +22 -0
- package/dist/components/presence-swap.js +162 -0
- package/dist/components/progress-ring.d.ts +20 -0
- package/dist/components/progress-ring.js +53 -0
- package/dist/components/pwa-update-control.d.ts +18 -0
- package/dist/components/pwa-update-control.js +119 -0
- package/dist/components/reaction-button.d.ts +26 -0
- package/dist/components/reaction-button.js +114 -0
- package/dist/components/rich-link-editor.d.ts +25 -0
- package/dist/components/rich-link-editor.js +320 -0
- package/dist/components/rich-markdown-content.d.ts +10 -0
- package/dist/components/rich-markdown-content.js +56 -0
- package/dist/components/rich-text-content.d.ts +19 -0
- package/dist/components/rich-text-content.js +26 -0
- package/dist/emoji-picker.d.ts +27 -0
- package/dist/emoji-picker.js +283 -0
- package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
- package/dist/hooks/use-horizontal-swipe.js +80 -0
- package/dist/hooks/use-is-hydrated.d.ts +6 -0
- package/dist/hooks/use-is-hydrated.js +20 -0
- package/dist/hooks/use-minute-clock.d.ts +23 -0
- package/dist/hooks/use-minute-clock.js +147 -0
- package/dist/hooks/use-month-transition-direction.d.ts +21 -0
- package/dist/hooks/use-month-transition-direction.js +110 -0
- package/dist/hooks/use-rich-link-editor.d.ts +55 -0
- package/dist/hooks/use-rich-link-editor.js +515 -0
- package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
- package/dist/hooks/use-viewer-time-zone.js +20 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +43 -0
- package/dist/lib/browser-clipboard.d.ts +13 -0
- package/dist/lib/browser-clipboard.js +48 -0
- package/dist/lib/browser-navigation.d.ts +21 -0
- package/dist/lib/browser-navigation.js +42 -0
- package/dist/lib/file-acceptance.d.ts +43 -0
- package/dist/lib/file-acceptance.js +107 -0
- package/dist/lib/format-file-size.d.ts +16 -0
- package/dist/lib/format-file-size.js +34 -0
- package/dist/lib/fuzzy-search.d.ts +17 -0
- package/dist/lib/fuzzy-search.js +183 -0
- package/dist/lib/horizontal-swipe.d.ts +23 -0
- package/dist/lib/horizontal-swipe.js +29 -0
- package/dist/lib/in-app-browser.d.ts +35 -0
- package/dist/lib/in-app-browser.js +80 -0
- package/dist/lib/month-grid.d.ts +42 -0
- package/dist/lib/month-grid.js +74 -0
- package/dist/lib/name-initials.d.ts +7 -0
- package/dist/lib/name-initials.js +11 -0
- package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
- package/dist/lib/rich-text/link-markdown-constants.js +458 -0
- package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
- package/dist/lib/rich-text/link-markdown-types.js +1 -0
- package/dist/lib/rich-text/link-markdown.d.ts +193 -0
- package/dist/lib/rich-text/link-markdown.js +592 -0
- package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
- package/dist/lib/rich-text/rich-markdown.js +105 -0
- package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
- package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
- package/dist/motion/tokens.d.ts +17 -1
- package/dist/motion/tokens.js +17 -1
- package/dist/styles.css +1 -1
- package/package.json +211 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { c as _c } from "react/compiler-runtime";
|
|
3
|
+
/** Tracks which way the visible month moved, to orient month entrance animations. */
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
export const MONTH_TRANSITION_DIRECTION = {
|
|
6
|
+
next: "next",
|
|
7
|
+
none: "none",
|
|
8
|
+
previous: "previous"
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* How long, in milliseconds, the last shown month still orients the next calendar mount. Month
|
|
12
|
+
* links may remount the calendar behind a route loading state, so the memory must outlive that
|
|
13
|
+
* gap but not a later, unrelated visit.
|
|
14
|
+
*/
|
|
15
|
+
const SHOWN_MONTH_MEMORY_MS = 5e3;
|
|
16
|
+
/**
|
|
17
|
+
* Last month shown by a calendar in this tab. It is written only from effects, which never run on
|
|
18
|
+
* the server, so server renders and the hydration render always read `null` and match.
|
|
19
|
+
*/
|
|
20
|
+
let lastShownMonth = null;
|
|
21
|
+
/**
|
|
22
|
+
* Records the month a calendar is showing.
|
|
23
|
+
* @param scopeKey - Calendar identity, such as a group or resource id.
|
|
24
|
+
* @param month - Visible `YYYY-MM` month.
|
|
25
|
+
*/
|
|
26
|
+
function rememberShownMonth(scopeKey, month) {
|
|
27
|
+
lastShownMonth = {
|
|
28
|
+
month,
|
|
29
|
+
shownAt: Date.now(),
|
|
30
|
+
scopeKey
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reads the month recently shown by the same calendar, if still within the memory window.
|
|
35
|
+
* @param scopeKey - Calendar identity.
|
|
36
|
+
* @returns The month, or null.
|
|
37
|
+
*/
|
|
38
|
+
function readRecentlyShownMonth(scopeKey) {
|
|
39
|
+
if (lastShownMonth === null || lastShownMonth.scopeKey !== scopeKey || Date.now() - lastShownMonth.shownAt > SHOWN_MONTH_MEMORY_MS) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return lastShownMonth.month;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Compares two `YYYY-MM` keys, which sort chronologically as plain strings.
|
|
46
|
+
* @param fromMonth - Month shown before, or null when there is none.
|
|
47
|
+
* @param toMonth - Month shown now.
|
|
48
|
+
* @returns `next` or `previous` when the month changed, `none` otherwise.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveMonthTransitionDirection(fromMonth, toMonth) {
|
|
51
|
+
if (fromMonth === null || fromMonth === toMonth) return MONTH_TRANSITION_DIRECTION.none;
|
|
52
|
+
return toMonth > fromMonth ? MONTH_TRANSITION_DIRECTION.next : MONTH_TRANSITION_DIRECTION.previous;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Direction of the latest month change of a calendar: a new `month` on the same instance, or a
|
|
56
|
+
* fresh mount right after another month of the same calendar was on screen.
|
|
57
|
+
* @param scopeKey - Calendar identity, so different calendars do not orient each other.
|
|
58
|
+
* @param month - Visible `YYYY-MM` month.
|
|
59
|
+
* @returns Direction to animate the month entrance with.
|
|
60
|
+
*/
|
|
61
|
+
export function useMonthTransitionDirection(scopeKey, month) {
|
|
62
|
+
const $ = _c(11);
|
|
63
|
+
let t0;
|
|
64
|
+
if ($[0] !== month || $[1] !== scopeKey) {
|
|
65
|
+
t0 = () => ({
|
|
66
|
+
direction: resolveMonthTransitionDirection(readRecentlyShownMonth(scopeKey), month),
|
|
67
|
+
month
|
|
68
|
+
});
|
|
69
|
+
$[0] = month;
|
|
70
|
+
$[1] = scopeKey;
|
|
71
|
+
$[2] = t0;
|
|
72
|
+
} else {
|
|
73
|
+
t0 = $[2];
|
|
74
|
+
}
|
|
75
|
+
const [transition, setTransition] = useState(t0);
|
|
76
|
+
if (transition.month !== month) {
|
|
77
|
+
setTransition({
|
|
78
|
+
direction: resolveMonthTransitionDirection(transition.month, month),
|
|
79
|
+
month
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
let t1;
|
|
83
|
+
let t2;
|
|
84
|
+
if ($[3] !== month || $[4] !== scopeKey) {
|
|
85
|
+
t1 = () => {
|
|
86
|
+
rememberShownMonth(scopeKey, month);
|
|
87
|
+
return () => rememberShownMonth(scopeKey, month);
|
|
88
|
+
};
|
|
89
|
+
t2 = [month, scopeKey];
|
|
90
|
+
$[3] = month;
|
|
91
|
+
$[4] = scopeKey;
|
|
92
|
+
$[5] = t1;
|
|
93
|
+
$[6] = t2;
|
|
94
|
+
} else {
|
|
95
|
+
t1 = $[5];
|
|
96
|
+
t2 = $[6];
|
|
97
|
+
}
|
|
98
|
+
useEffect(t1, t2);
|
|
99
|
+
let t3;
|
|
100
|
+
if ($[7] !== month || $[8] !== transition.direction || $[9] !== transition.month) {
|
|
101
|
+
t3 = transition.month === month ? transition.direction : resolveMonthTransitionDirection(transition.month, month);
|
|
102
|
+
$[7] = month;
|
|
103
|
+
$[8] = transition.direction;
|
|
104
|
+
$[9] = transition.month;
|
|
105
|
+
$[10] = t3;
|
|
106
|
+
} else {
|
|
107
|
+
t3 = $[10];
|
|
108
|
+
}
|
|
109
|
+
return t3;
|
|
110
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Owns the state of `RichLinkEditor`: content, tracked links, popover and selection. */
|
|
2
|
+
import { type ClipboardEvent, type FormEvent, type KeyboardEvent } from "react";
|
|
3
|
+
import { RICH_LINK_POPOVER_MODE } from "../lib/rich-text/link-markdown-constants.js";
|
|
4
|
+
import type { ActiveRichPreviewLink, RichLink, RichPreviewSegment } from "../lib/rich-text/link-markdown-types.js";
|
|
5
|
+
type RichLinkPopoverMode = (typeof RICH_LINK_POPOVER_MODE)[keyof typeof RICH_LINK_POPOVER_MODE];
|
|
6
|
+
/** Plain-text content plus tracked links, used to snapshot/restore the editor. */
|
|
7
|
+
export type RichLinkEditorDisplayState = {
|
|
8
|
+
content: string;
|
|
9
|
+
links: RichLink[];
|
|
10
|
+
};
|
|
11
|
+
type UseRichLinkEditorOptions = {
|
|
12
|
+
/** Persisted markdown loaded as the initial editor value. */
|
|
13
|
+
initialMarkdown?: string;
|
|
14
|
+
/** Called whenever the author changes the content (e.g. to clear errors). */
|
|
15
|
+
onContentChange?: () => void;
|
|
16
|
+
};
|
|
17
|
+
/** Imperative + reactive API exposed by `useRichLinkEditor` to the editor UI. */
|
|
18
|
+
export type RichLinkEditorController = {
|
|
19
|
+
setEditorElement: (node: HTMLDivElement | null) => void;
|
|
20
|
+
segments: RichPreviewSegment[];
|
|
21
|
+
hasContent: boolean;
|
|
22
|
+
content: string;
|
|
23
|
+
activeLink: ActiveRichPreviewLink | null;
|
|
24
|
+
linkTextInput: string;
|
|
25
|
+
linkUrlInput: string;
|
|
26
|
+
popoverMode: RichLinkPopoverMode;
|
|
27
|
+
/** Whether the popover draft has visible text and an http(s) URL, so it can be saved. */
|
|
28
|
+
isLinkEditValid: boolean;
|
|
29
|
+
/** Whether the author typed a URL that cannot become a safe http(s) link. */
|
|
30
|
+
hasInvalidLinkUrl: boolean;
|
|
31
|
+
setLinkTextInput: (value: string) => void;
|
|
32
|
+
setLinkUrlInput: (value: string) => void;
|
|
33
|
+
setPopoverMode: (mode: RichLinkPopoverMode) => void;
|
|
34
|
+
handleBeforeInput: (event: FormEvent<HTMLDivElement>) => void;
|
|
35
|
+
handleInput: (event: FormEvent<HTMLDivElement>) => void;
|
|
36
|
+
handleKeyDown: (event: KeyboardEvent<HTMLDivElement>) => void;
|
|
37
|
+
handlePaste: (event: ClipboardEvent<HTMLDivElement>) => void;
|
|
38
|
+
openLinkPopover: (segment: ActiveRichPreviewLink) => void;
|
|
39
|
+
closeLinkPopover: () => void;
|
|
40
|
+
removeLink: (segment: ActiveRichPreviewLink) => void;
|
|
41
|
+
saveLinkEdit: (segment: ActiveRichPreviewLink) => void;
|
|
42
|
+
serialize: () => string;
|
|
43
|
+
reset: (markdown?: string) => void;
|
|
44
|
+
getDisplayState: () => RichLinkEditorDisplayState;
|
|
45
|
+
loadFromDisplay: (state: RichLinkEditorDisplayState) => void;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Controls a rich link editor backed by a `contentEditable` element: it owns the
|
|
49
|
+
* plain-text content, the tracked explicit/suppressed links, the link popover
|
|
50
|
+
* state, and the selection bookkeeping, and exposes serialize/reset/snapshot
|
|
51
|
+
* helpers so a feature can persist or restore the value. The DOM rendering lives
|
|
52
|
+
* in `RichLinkEditor`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function useRichLinkEditor(options?: UseRichLinkEditorOptions): RichLinkEditorController;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { c as _c } from "react/compiler-runtime";
|
|
3
|
+
/** Owns the state of `RichLinkEditor`: content, tracked links, popover and selection. */
|
|
4
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
5
|
+
import { RICH_LINK_KIND, RICH_LINK_POPOVER_MODE, RICH_PREVIEW_LINK_SOURCE, RICH_TEXT_CLIPBOARD_DATA_TYPE, RICH_TEXT_EDITOR_INPUT_TYPE, RICH_TEXT_EDITOR_KEY, RICH_TEXT_EDITOR_KEY_LENGTH, RICH_TEXT_EDITOR_TEXT, RICH_TEXT_EDITOR_WORD_DIRECTION } from "../lib/rich-text/link-markdown-constants.js";
|
|
6
|
+
import { deserializeMarkdownForEditor, getLinksAfterTextChange, getWordDeletionRange, isLinkSynchronized, normalizeMarkdownUrl, parsePreviewSegments, rangesOverlap, serializeEditorContent } from "../lib/rich-text/link-markdown.js";
|
|
7
|
+
import { getEditorSelectionRange, setEditorSelectionRange } from "../lib/rich-text/rich-text-editor-dom.js";
|
|
8
|
+
const EMPTY_TEXT = "";
|
|
9
|
+
/**
|
|
10
|
+
* Controls a rich link editor backed by a `contentEditable` element: it owns the
|
|
11
|
+
* plain-text content, the tracked explicit/suppressed links, the link popover
|
|
12
|
+
* state, and the selection bookkeeping, and exposes serialize/reset/snapshot
|
|
13
|
+
* helpers so a feature can persist or restore the value. The DOM rendering lives
|
|
14
|
+
* in `RichLinkEditor`.
|
|
15
|
+
*/
|
|
16
|
+
export function useRichLinkEditor(t0) {
|
|
17
|
+
const $ = _c(72);
|
|
18
|
+
let t1;
|
|
19
|
+
if ($[0] !== t0) {
|
|
20
|
+
t1 = t0 === undefined ? {} : t0;
|
|
21
|
+
$[0] = t0;
|
|
22
|
+
$[1] = t1;
|
|
23
|
+
} else {
|
|
24
|
+
t1 = $[1];
|
|
25
|
+
}
|
|
26
|
+
const options = t1;
|
|
27
|
+
const editorRef = useRef(null);
|
|
28
|
+
let t2;
|
|
29
|
+
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
|
30
|
+
t2 = (node) => {
|
|
31
|
+
editorRef.current = node;
|
|
32
|
+
};
|
|
33
|
+
$[2] = t2;
|
|
34
|
+
} else {
|
|
35
|
+
t2 = $[2];
|
|
36
|
+
}
|
|
37
|
+
const setEditorElement = t2;
|
|
38
|
+
const pendingSelectionRef = useRef(null);
|
|
39
|
+
let t3;
|
|
40
|
+
if ($[3] !== options.initialMarkdown) {
|
|
41
|
+
t3 = () => deserializeMarkdownForEditor(options.initialMarkdown ?? EMPTY_TEXT).content;
|
|
42
|
+
$[3] = options.initialMarkdown;
|
|
43
|
+
$[4] = t3;
|
|
44
|
+
} else {
|
|
45
|
+
t3 = $[4];
|
|
46
|
+
}
|
|
47
|
+
const [content, setContent] = useState(t3);
|
|
48
|
+
let t4;
|
|
49
|
+
if ($[5] !== options.initialMarkdown) {
|
|
50
|
+
t4 = () => deserializeMarkdownForEditor(options.initialMarkdown ?? EMPTY_TEXT).links;
|
|
51
|
+
$[5] = options.initialMarkdown;
|
|
52
|
+
$[6] = t4;
|
|
53
|
+
} else {
|
|
54
|
+
t4 = $[6];
|
|
55
|
+
}
|
|
56
|
+
const [links, setLinks] = useState(t4);
|
|
57
|
+
const [activeLink, setActiveLink] = useState(null);
|
|
58
|
+
const [linkTextInput, setLinkTextInput] = useState("");
|
|
59
|
+
const [linkUrlInput, setLinkUrlInput] = useState("");
|
|
60
|
+
const [popoverMode, setPopoverMode] = useState(RICH_LINK_POPOVER_MODE.actions);
|
|
61
|
+
let t5;
|
|
62
|
+
if ($[7] !== content || $[8] !== links) {
|
|
63
|
+
t5 = parsePreviewSegments(content, links);
|
|
64
|
+
$[7] = content;
|
|
65
|
+
$[8] = links;
|
|
66
|
+
$[9] = t5;
|
|
67
|
+
} else {
|
|
68
|
+
t5 = $[9];
|
|
69
|
+
}
|
|
70
|
+
const segments = t5;
|
|
71
|
+
const hasContent = content.length > 0;
|
|
72
|
+
let t6;
|
|
73
|
+
if ($[10] !== linkUrlInput) {
|
|
74
|
+
t6 = normalizeMarkdownUrl(linkUrlInput);
|
|
75
|
+
$[10] = linkUrlInput;
|
|
76
|
+
$[11] = t6;
|
|
77
|
+
} else {
|
|
78
|
+
t6 = $[11];
|
|
79
|
+
}
|
|
80
|
+
const normalizedLinkUrlInput = t6;
|
|
81
|
+
let t7;
|
|
82
|
+
if ($[12] !== linkUrlInput || $[13] !== normalizedLinkUrlInput) {
|
|
83
|
+
t7 = linkUrlInput.trim().length > 0 && normalizedLinkUrlInput === null;
|
|
84
|
+
$[12] = linkUrlInput;
|
|
85
|
+
$[13] = normalizedLinkUrlInput;
|
|
86
|
+
$[14] = t7;
|
|
87
|
+
} else {
|
|
88
|
+
t7 = $[14];
|
|
89
|
+
}
|
|
90
|
+
const hasInvalidLinkUrl = t7;
|
|
91
|
+
let t8;
|
|
92
|
+
if ($[15] !== linkTextInput || $[16] !== normalizedLinkUrlInput) {
|
|
93
|
+
t8 = normalizedLinkUrlInput !== null && linkTextInput.trim().length > 0;
|
|
94
|
+
$[15] = linkTextInput;
|
|
95
|
+
$[16] = normalizedLinkUrlInput;
|
|
96
|
+
$[17] = t8;
|
|
97
|
+
} else {
|
|
98
|
+
t8 = $[17];
|
|
99
|
+
}
|
|
100
|
+
const isLinkEditValid = t8;
|
|
101
|
+
let t9;
|
|
102
|
+
if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
|
|
103
|
+
t9 = () => {
|
|
104
|
+
const editor = editorRef.current;
|
|
105
|
+
const selectionRange = pendingSelectionRef.current;
|
|
106
|
+
if (!editor || !selectionRange || !editor.contains(document.activeElement)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
setEditorSelectionRange(editor, selectionRange);
|
|
110
|
+
pendingSelectionRef.current = null;
|
|
111
|
+
};
|
|
112
|
+
$[18] = t9;
|
|
113
|
+
} else {
|
|
114
|
+
t9 = $[18];
|
|
115
|
+
}
|
|
116
|
+
let t10;
|
|
117
|
+
if ($[19] !== content || $[20] !== links) {
|
|
118
|
+
t10 = [content, links];
|
|
119
|
+
$[19] = content;
|
|
120
|
+
$[20] = links;
|
|
121
|
+
$[21] = t10;
|
|
122
|
+
} else {
|
|
123
|
+
t10 = $[21];
|
|
124
|
+
}
|
|
125
|
+
useLayoutEffect(t9, t10);
|
|
126
|
+
let t11;
|
|
127
|
+
if ($[22] !== content || $[23] !== options) {
|
|
128
|
+
t11 = (nextContent) => {
|
|
129
|
+
setLinks((currentLinks) => getLinksAfterTextChange({
|
|
130
|
+
links: currentLinks,
|
|
131
|
+
nextText: nextContent,
|
|
132
|
+
previousText: content
|
|
133
|
+
}));
|
|
134
|
+
setContent(nextContent);
|
|
135
|
+
options.onContentChange?.();
|
|
136
|
+
};
|
|
137
|
+
$[22] = content;
|
|
138
|
+
$[23] = options;
|
|
139
|
+
$[24] = t11;
|
|
140
|
+
} else {
|
|
141
|
+
t11 = $[24];
|
|
142
|
+
}
|
|
143
|
+
const handleContentChange = t11;
|
|
144
|
+
let t12;
|
|
145
|
+
if ($[25] !== content || $[26] !== handleContentChange) {
|
|
146
|
+
t12 = (replacementText, selectionRange_0) => {
|
|
147
|
+
const nextSelectionOffset = selectionRange_0.start + replacementText.length;
|
|
148
|
+
const nextContent_0 = content.slice(0, selectionRange_0.start) + replacementText + content.slice(selectionRange_0.end);
|
|
149
|
+
pendingSelectionRef.current = {
|
|
150
|
+
end: nextSelectionOffset,
|
|
151
|
+
start: nextSelectionOffset
|
|
152
|
+
};
|
|
153
|
+
handleContentChange(nextContent_0);
|
|
154
|
+
};
|
|
155
|
+
$[25] = content;
|
|
156
|
+
$[26] = handleContentChange;
|
|
157
|
+
$[27] = t12;
|
|
158
|
+
} else {
|
|
159
|
+
t12 = $[27];
|
|
160
|
+
}
|
|
161
|
+
const replaceContentText = t12;
|
|
162
|
+
let t13;
|
|
163
|
+
if ($[28] !== content || $[29] !== options || $[30] !== replaceContentText) {
|
|
164
|
+
t13 = (event) => {
|
|
165
|
+
const pastedText = event.clipboardData.getData(RICH_TEXT_CLIPBOARD_DATA_TYPE.plainText);
|
|
166
|
+
const pastedUrl = normalizeMarkdownUrl(pastedText);
|
|
167
|
+
const selectionRange_1 = getEditorSelectionRange(event.currentTarget) ?? {
|
|
168
|
+
end: content.length,
|
|
169
|
+
start: content.length
|
|
170
|
+
};
|
|
171
|
+
const hasSelectedText = selectionRange_1.start !== selectionRange_1.end;
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
if (!pastedUrl || !hasSelectedText) {
|
|
174
|
+
replaceContentText(pastedText, selectionRange_1);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
pendingSelectionRef.current = selectionRange_1;
|
|
178
|
+
setLinks((currentLinks_0) => [...currentLinks_0.filter((link) => !rangesOverlap(link, {
|
|
179
|
+
end: selectionRange_1.end,
|
|
180
|
+
start: selectionRange_1.start
|
|
181
|
+
})), {
|
|
182
|
+
end: selectionRange_1.end,
|
|
183
|
+
id: crypto.randomUUID(),
|
|
184
|
+
isSynced: isLinkSynchronized(content.slice(selectionRange_1.start, selectionRange_1.end), pastedUrl),
|
|
185
|
+
kind: RICH_LINK_KIND.explicit,
|
|
186
|
+
start: selectionRange_1.start,
|
|
187
|
+
url: pastedUrl
|
|
188
|
+
}]);
|
|
189
|
+
options.onContentChange?.();
|
|
190
|
+
};
|
|
191
|
+
$[28] = content;
|
|
192
|
+
$[29] = options;
|
|
193
|
+
$[30] = replaceContentText;
|
|
194
|
+
$[31] = t13;
|
|
195
|
+
} else {
|
|
196
|
+
t13 = $[31];
|
|
197
|
+
}
|
|
198
|
+
const handlePaste = t13;
|
|
199
|
+
let t14;
|
|
200
|
+
if ($[32] !== content || $[33] !== replaceContentText) {
|
|
201
|
+
t14 = (event_0) => {
|
|
202
|
+
if (event_0.altKey || event_0.metaKey) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (event_0.ctrlKey && event_0.key !== RICH_TEXT_EDITOR_KEY.backspace && event_0.key !== RICH_TEXT_EDITOR_KEY.delete) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const selectionRange_2 = getEditorSelectionRange(event_0.currentTarget) ?? {
|
|
209
|
+
end: content.length,
|
|
210
|
+
start: content.length
|
|
211
|
+
};
|
|
212
|
+
let replacementText_0 = null;
|
|
213
|
+
let replacementRange = selectionRange_2;
|
|
214
|
+
if (event_0.key.length === RICH_TEXT_EDITOR_KEY_LENGTH.character) {
|
|
215
|
+
replacementText_0 = event_0.key;
|
|
216
|
+
}
|
|
217
|
+
if (event_0.key === RICH_TEXT_EDITOR_KEY.enter) {
|
|
218
|
+
replacementText_0 = RICH_TEXT_EDITOR_TEXT.lineBreak;
|
|
219
|
+
}
|
|
220
|
+
if (event_0.key === RICH_TEXT_EDITOR_KEY.backspace) {
|
|
221
|
+
replacementText_0 = EMPTY_TEXT;
|
|
222
|
+
replacementRange = event_0.ctrlKey ? getWordDeletionRange({
|
|
223
|
+
direction: RICH_TEXT_EDITOR_WORD_DIRECTION.backward,
|
|
224
|
+
selectionRange: selectionRange_2,
|
|
225
|
+
text: content
|
|
226
|
+
}) : selectionRange_2.start === selectionRange_2.end ? {
|
|
227
|
+
end: selectionRange_2.end,
|
|
228
|
+
start: Math.max(selectionRange_2.start - 1, 0)
|
|
229
|
+
} : selectionRange_2;
|
|
230
|
+
}
|
|
231
|
+
if (event_0.key === RICH_TEXT_EDITOR_KEY.delete) {
|
|
232
|
+
replacementText_0 = EMPTY_TEXT;
|
|
233
|
+
replacementRange = event_0.ctrlKey ? getWordDeletionRange({
|
|
234
|
+
direction: RICH_TEXT_EDITOR_WORD_DIRECTION.forward,
|
|
235
|
+
selectionRange: selectionRange_2,
|
|
236
|
+
text: content
|
|
237
|
+
}) : selectionRange_2.start === selectionRange_2.end ? {
|
|
238
|
+
end: Math.min(selectionRange_2.end + 1, content.length),
|
|
239
|
+
start: selectionRange_2.start
|
|
240
|
+
} : selectionRange_2;
|
|
241
|
+
}
|
|
242
|
+
if (replacementText_0 === null) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
event_0.preventDefault();
|
|
246
|
+
replaceContentText(replacementText_0, replacementRange);
|
|
247
|
+
};
|
|
248
|
+
$[32] = content;
|
|
249
|
+
$[33] = replaceContentText;
|
|
250
|
+
$[34] = t14;
|
|
251
|
+
} else {
|
|
252
|
+
t14 = $[34];
|
|
253
|
+
}
|
|
254
|
+
const handleKeyDown = t14;
|
|
255
|
+
let t15;
|
|
256
|
+
if ($[35] !== content.length || $[36] !== replaceContentText) {
|
|
257
|
+
t15 = (event_1) => {
|
|
258
|
+
const nativeEvent = event_1.nativeEvent;
|
|
259
|
+
const selectionRange_3 = getEditorSelectionRange(event_1.currentTarget) ?? {
|
|
260
|
+
end: content.length,
|
|
261
|
+
start: content.length
|
|
262
|
+
};
|
|
263
|
+
let replacementText_1 = null;
|
|
264
|
+
let replacementRange_0 = selectionRange_3;
|
|
265
|
+
if (nativeEvent.inputType === RICH_TEXT_EDITOR_INPUT_TYPE.insertText) {
|
|
266
|
+
replacementText_1 = nativeEvent.data ?? EMPTY_TEXT;
|
|
267
|
+
}
|
|
268
|
+
if (nativeEvent.inputType === RICH_TEXT_EDITOR_INPUT_TYPE.insertParagraph || nativeEvent.inputType === RICH_TEXT_EDITOR_INPUT_TYPE.insertLineBreak) {
|
|
269
|
+
replacementText_1 = RICH_TEXT_EDITOR_TEXT.lineBreak;
|
|
270
|
+
}
|
|
271
|
+
if (nativeEvent.inputType === RICH_TEXT_EDITOR_INPUT_TYPE.deleteContentBackward) {
|
|
272
|
+
replacementText_1 = EMPTY_TEXT;
|
|
273
|
+
replacementRange_0 = selectionRange_3.start === selectionRange_3.end ? {
|
|
274
|
+
end: selectionRange_3.end,
|
|
275
|
+
start: Math.max(selectionRange_3.start - 1, 0)
|
|
276
|
+
} : selectionRange_3;
|
|
277
|
+
}
|
|
278
|
+
if (nativeEvent.inputType === RICH_TEXT_EDITOR_INPUT_TYPE.deleteContentForward) {
|
|
279
|
+
replacementText_1 = EMPTY_TEXT;
|
|
280
|
+
replacementRange_0 = selectionRange_3.start === selectionRange_3.end ? {
|
|
281
|
+
end: Math.min(selectionRange_3.end + 1, content.length),
|
|
282
|
+
start: selectionRange_3.start
|
|
283
|
+
} : selectionRange_3;
|
|
284
|
+
}
|
|
285
|
+
if (replacementText_1 === null) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
event_1.preventDefault();
|
|
289
|
+
replaceContentText(replacementText_1, replacementRange_0);
|
|
290
|
+
};
|
|
291
|
+
$[35] = content.length;
|
|
292
|
+
$[36] = replaceContentText;
|
|
293
|
+
$[37] = t15;
|
|
294
|
+
} else {
|
|
295
|
+
t15 = $[37];
|
|
296
|
+
}
|
|
297
|
+
const handleBeforeInput = t15;
|
|
298
|
+
let t16;
|
|
299
|
+
if ($[38] !== handleContentChange) {
|
|
300
|
+
t16 = (event_2) => {
|
|
301
|
+
const selectionRange_4 = getEditorSelectionRange(event_2.currentTarget);
|
|
302
|
+
if (selectionRange_4) {
|
|
303
|
+
pendingSelectionRef.current = selectionRange_4;
|
|
304
|
+
}
|
|
305
|
+
handleContentChange(event_2.currentTarget.textContent ?? EMPTY_TEXT);
|
|
306
|
+
};
|
|
307
|
+
$[38] = handleContentChange;
|
|
308
|
+
$[39] = t16;
|
|
309
|
+
} else {
|
|
310
|
+
t16 = $[39];
|
|
311
|
+
}
|
|
312
|
+
const handleInput = t16;
|
|
313
|
+
let t17;
|
|
314
|
+
if ($[40] === Symbol.for("react.memo_cache_sentinel")) {
|
|
315
|
+
t17 = (segment) => {
|
|
316
|
+
setActiveLink(segment);
|
|
317
|
+
setLinkTextInput(segment.text);
|
|
318
|
+
setLinkUrlInput(segment.url);
|
|
319
|
+
setPopoverMode(RICH_LINK_POPOVER_MODE.actions);
|
|
320
|
+
};
|
|
321
|
+
$[40] = t17;
|
|
322
|
+
} else {
|
|
323
|
+
t17 = $[40];
|
|
324
|
+
}
|
|
325
|
+
const openLinkPopover = t17;
|
|
326
|
+
let t18;
|
|
327
|
+
if ($[41] === Symbol.for("react.memo_cache_sentinel")) {
|
|
328
|
+
t18 = () => {
|
|
329
|
+
setActiveLink(null);
|
|
330
|
+
setLinkTextInput(EMPTY_TEXT);
|
|
331
|
+
setLinkUrlInput(EMPTY_TEXT);
|
|
332
|
+
setPopoverMode(RICH_LINK_POPOVER_MODE.actions);
|
|
333
|
+
};
|
|
334
|
+
$[41] = t18;
|
|
335
|
+
} else {
|
|
336
|
+
t18 = $[41];
|
|
337
|
+
}
|
|
338
|
+
const closeLinkPopover = t18;
|
|
339
|
+
let t19;
|
|
340
|
+
if ($[42] === Symbol.for("react.memo_cache_sentinel")) {
|
|
341
|
+
t19 = (segment_0) => {
|
|
342
|
+
const shouldSuppressVisibleUrl = Boolean(normalizeMarkdownUrl(segment_0.text));
|
|
343
|
+
const suppressedLink = {
|
|
344
|
+
end: segment_0.end,
|
|
345
|
+
id: crypto.randomUUID(),
|
|
346
|
+
kind: RICH_LINK_KIND.suppressed,
|
|
347
|
+
start: segment_0.start
|
|
348
|
+
};
|
|
349
|
+
setLinks((currentLinks_1) => {
|
|
350
|
+
const linksWithoutRemovedExplicitLink = segment_0.source === RICH_PREVIEW_LINK_SOURCE.explicit && segment_0.id ? currentLinks_1.filter((link_0) => link_0.id !== segment_0.id) : currentLinks_1;
|
|
351
|
+
return shouldSuppressVisibleUrl || segment_0.source === RICH_PREVIEW_LINK_SOURCE.automatic ? [...linksWithoutRemovedExplicitLink, suppressedLink] : linksWithoutRemovedExplicitLink;
|
|
352
|
+
});
|
|
353
|
+
closeLinkPopover();
|
|
354
|
+
};
|
|
355
|
+
$[42] = t19;
|
|
356
|
+
} else {
|
|
357
|
+
t19 = $[42];
|
|
358
|
+
}
|
|
359
|
+
const removeLink = t19;
|
|
360
|
+
let t20;
|
|
361
|
+
if ($[43] !== content || $[44] !== linkTextInput || $[45] !== linkUrlInput) {
|
|
362
|
+
t20 = (segment_1) => {
|
|
363
|
+
const nextUrl = normalizeMarkdownUrl(linkUrlInput);
|
|
364
|
+
const nextText = linkTextInput;
|
|
365
|
+
if (!nextUrl || !nextText.trim()) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const nextContent_1 = content.slice(0, segment_1.start) + nextText + content.slice(segment_1.end);
|
|
369
|
+
const nextEnd = segment_1.start + nextText.length;
|
|
370
|
+
const nextLinkRange = {
|
|
371
|
+
end: nextEnd,
|
|
372
|
+
start: segment_1.start
|
|
373
|
+
};
|
|
374
|
+
pendingSelectionRef.current = {
|
|
375
|
+
end: nextEnd,
|
|
376
|
+
start: nextEnd
|
|
377
|
+
};
|
|
378
|
+
setContent(nextContent_1);
|
|
379
|
+
setLinks((currentLinks_2) => {
|
|
380
|
+
const adjustedLinks = getLinksAfterTextChange({
|
|
381
|
+
links: currentLinks_2,
|
|
382
|
+
nextText: nextContent_1,
|
|
383
|
+
previousText: content
|
|
384
|
+
});
|
|
385
|
+
return [...adjustedLinks.filter((link_1) => {
|
|
386
|
+
if (segment_1.id && link_1.id === segment_1.id) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
return !rangesOverlap(link_1, nextLinkRange);
|
|
390
|
+
}), {
|
|
391
|
+
end: nextEnd,
|
|
392
|
+
id: segment_1.id ?? crypto.randomUUID(),
|
|
393
|
+
isSynced: isLinkSynchronized(nextText, nextUrl),
|
|
394
|
+
kind: RICH_LINK_KIND.explicit,
|
|
395
|
+
start: segment_1.start,
|
|
396
|
+
url: nextUrl
|
|
397
|
+
}];
|
|
398
|
+
});
|
|
399
|
+
closeLinkPopover();
|
|
400
|
+
};
|
|
401
|
+
$[43] = content;
|
|
402
|
+
$[44] = linkTextInput;
|
|
403
|
+
$[45] = linkUrlInput;
|
|
404
|
+
$[46] = t20;
|
|
405
|
+
} else {
|
|
406
|
+
t20 = $[46];
|
|
407
|
+
}
|
|
408
|
+
const saveLinkEdit = t20;
|
|
409
|
+
let t21;
|
|
410
|
+
if ($[47] !== content || $[48] !== links) {
|
|
411
|
+
t21 = () => serializeEditorContent(content, links);
|
|
412
|
+
$[47] = content;
|
|
413
|
+
$[48] = links;
|
|
414
|
+
$[49] = t21;
|
|
415
|
+
} else {
|
|
416
|
+
t21 = $[49];
|
|
417
|
+
}
|
|
418
|
+
const serialize = t21;
|
|
419
|
+
let t22;
|
|
420
|
+
if ($[50] === Symbol.for("react.memo_cache_sentinel")) {
|
|
421
|
+
t22 = (markdown) => {
|
|
422
|
+
const nextState = deserializeMarkdownForEditor(markdown ?? EMPTY_TEXT);
|
|
423
|
+
pendingSelectionRef.current = null;
|
|
424
|
+
setContent(nextState.content);
|
|
425
|
+
setLinks(nextState.links);
|
|
426
|
+
closeLinkPopover();
|
|
427
|
+
};
|
|
428
|
+
$[50] = t22;
|
|
429
|
+
} else {
|
|
430
|
+
t22 = $[50];
|
|
431
|
+
}
|
|
432
|
+
const reset = t22;
|
|
433
|
+
let t23;
|
|
434
|
+
if ($[51] !== content || $[52] !== links) {
|
|
435
|
+
t23 = () => ({
|
|
436
|
+
content,
|
|
437
|
+
links: links.map(_temp)
|
|
438
|
+
});
|
|
439
|
+
$[51] = content;
|
|
440
|
+
$[52] = links;
|
|
441
|
+
$[53] = t23;
|
|
442
|
+
} else {
|
|
443
|
+
t23 = $[53];
|
|
444
|
+
}
|
|
445
|
+
const getDisplayState = t23;
|
|
446
|
+
let t24;
|
|
447
|
+
if ($[54] === Symbol.for("react.memo_cache_sentinel")) {
|
|
448
|
+
t24 = (state) => {
|
|
449
|
+
pendingSelectionRef.current = null;
|
|
450
|
+
setContent(state.content);
|
|
451
|
+
setLinks(state.links.map(_temp2));
|
|
452
|
+
closeLinkPopover();
|
|
453
|
+
};
|
|
454
|
+
$[54] = t24;
|
|
455
|
+
} else {
|
|
456
|
+
t24 = $[54];
|
|
457
|
+
}
|
|
458
|
+
const loadFromDisplay = t24;
|
|
459
|
+
let t25;
|
|
460
|
+
if ($[55] !== activeLink || $[56] !== content || $[57] !== getDisplayState || $[58] !== handleBeforeInput || $[59] !== handleInput || $[60] !== handleKeyDown || $[61] !== handlePaste || $[62] !== hasContent || $[63] !== hasInvalidLinkUrl || $[64] !== isLinkEditValid || $[65] !== linkTextInput || $[66] !== linkUrlInput || $[67] !== popoverMode || $[68] !== saveLinkEdit || $[69] !== segments || $[70] !== serialize) {
|
|
461
|
+
t25 = {
|
|
462
|
+
activeLink,
|
|
463
|
+
closeLinkPopover,
|
|
464
|
+
content,
|
|
465
|
+
getDisplayState,
|
|
466
|
+
handleBeforeInput,
|
|
467
|
+
handleInput,
|
|
468
|
+
handleKeyDown,
|
|
469
|
+
handlePaste,
|
|
470
|
+
hasContent,
|
|
471
|
+
hasInvalidLinkUrl,
|
|
472
|
+
isLinkEditValid,
|
|
473
|
+
linkTextInput,
|
|
474
|
+
linkUrlInput,
|
|
475
|
+
loadFromDisplay,
|
|
476
|
+
openLinkPopover,
|
|
477
|
+
popoverMode,
|
|
478
|
+
removeLink,
|
|
479
|
+
reset,
|
|
480
|
+
saveLinkEdit,
|
|
481
|
+
segments,
|
|
482
|
+
serialize,
|
|
483
|
+
setEditorElement,
|
|
484
|
+
setLinkTextInput,
|
|
485
|
+
setLinkUrlInput,
|
|
486
|
+
setPopoverMode
|
|
487
|
+
};
|
|
488
|
+
$[55] = activeLink;
|
|
489
|
+
$[56] = content;
|
|
490
|
+
$[57] = getDisplayState;
|
|
491
|
+
$[58] = handleBeforeInput;
|
|
492
|
+
$[59] = handleInput;
|
|
493
|
+
$[60] = handleKeyDown;
|
|
494
|
+
$[61] = handlePaste;
|
|
495
|
+
$[62] = hasContent;
|
|
496
|
+
$[63] = hasInvalidLinkUrl;
|
|
497
|
+
$[64] = isLinkEditValid;
|
|
498
|
+
$[65] = linkTextInput;
|
|
499
|
+
$[66] = linkUrlInput;
|
|
500
|
+
$[67] = popoverMode;
|
|
501
|
+
$[68] = saveLinkEdit;
|
|
502
|
+
$[69] = segments;
|
|
503
|
+
$[70] = serialize;
|
|
504
|
+
$[71] = t25;
|
|
505
|
+
} else {
|
|
506
|
+
t25 = $[71];
|
|
507
|
+
}
|
|
508
|
+
return t25;
|
|
509
|
+
}
|
|
510
|
+
function _temp2(link_3) {
|
|
511
|
+
return { ...link_3 };
|
|
512
|
+
}
|
|
513
|
+
function _temp(link_2) {
|
|
514
|
+
return { ...link_2 };
|
|
515
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IANA time zone of the browser (for example "Europe/Madrid"). Returns null on
|
|
3
|
+
* the server and during hydration so zone-dependent copy never causes a
|
|
4
|
+
* markup mismatch; it settles right after hydration without an effect.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useViewerTimeZone(): string | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/** Reads the viewer IANA time zone once hydrated, so zone-dependent copy never mismatches. */
|
|
3
|
+
import { useSyncExternalStore } from "react";
|
|
4
|
+
function subscribeToNothing() {
|
|
5
|
+
return () => undefined;
|
|
6
|
+
}
|
|
7
|
+
function getViewerTimeZoneSnapshot() {
|
|
8
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
9
|
+
}
|
|
10
|
+
function getServerViewerTimeZoneSnapshot() {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* IANA time zone of the browser (for example "Europe/Madrid"). Returns null on
|
|
15
|
+
* the server and during hydration so zone-dependent copy never causes a
|
|
16
|
+
* markup mismatch; it settles right after hydration without an effect.
|
|
17
|
+
*/
|
|
18
|
+
export function useViewerTimeZone() {
|
|
19
|
+
return useSyncExternalStore(subscribeToNothing, getViewerTimeZoneSnapshot, getServerViewerTimeZoneSnapshot);
|
|
20
|
+
}
|