@ai-matrx/rich-content 0.2.9 → 0.2.15

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.
Files changed (124) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/copy/copy-commands.d.ts +42 -0
  3. package/dist/copy/copy-commands.js +119 -0
  4. package/dist/copy/markdown-copy-html.d.ts +3 -0
  5. package/dist/copy/markdown-copy-html.js +8 -0
  6. package/dist/copy/markdown-readable-text.d.ts +4 -0
  7. package/dist/copy/markdown-readable-text.js +62 -0
  8. package/dist/display/blocks/json/json-tabular-utils.d.ts +7 -5
  9. package/dist/display/blocks/json/json-tabular-utils.js +26 -17
  10. package/dist/display/blocks/table/StreamingTableRenderer.js +11 -16
  11. package/dist/display/chat-markdown/BasicMarkdownContent.js +8 -6
  12. package/dist/display/chat-markdown/ConfigurableMarkdownContent.js +8 -6
  13. package/dist/display/chat-markdown/block-registry/BlockComponentRegistry.js +2 -0
  14. package/dist/display/chat-markdown/block-registry/block-dispatch.js +2 -0
  15. package/dist/display/tables/MarkdownTable.js +11 -16
  16. package/dist/display/tables/TableWithSeparatedControls.js +11 -16
  17. package/dist/display/tables/table-csv.d.ts +7 -0
  18. package/dist/display/tables/table-csv.js +19 -0
  19. package/dist/host/app-bindings.d.ts +32 -0
  20. package/dist/host/app-bindings.js +40 -0
  21. package/dist/host/feedback-subject.d.ts +16 -0
  22. package/dist/host/feedback-subject.js +0 -0
  23. package/dist/host/manual-copy.d.ts +7 -0
  24. package/dist/host/manual-copy.js +11 -0
  25. package/dist/host/registry.d.ts +2 -0
  26. package/dist/host/registry.js +10 -0
  27. package/dist/host/session-knob.d.ts +5 -0
  28. package/dist/host/session-knob.js +7 -0
  29. package/dist/host/types.d.ts +24 -0
  30. package/dist/rich-document/RegistryContextMenu.d.ts +29 -0
  31. package/dist/rich-document/RegistryContextMenu.js +40 -0
  32. package/dist/rich-document/RichDocument.d.ts +78 -0
  33. package/dist/rich-document/RichDocument.js +218 -0
  34. package/dist/rich-document/RichDocumentActionProvider.d.ts +18 -0
  35. package/dist/rich-document/RichDocumentActionProvider.js +18 -0
  36. package/dist/rich-document/RichDocumentActionSurface.d.ts +11 -0
  37. package/dist/rich-document/RichDocumentActionSurface.js +59 -0
  38. package/dist/rich-document/RichDocumentActions.d.ts +12 -0
  39. package/dist/rich-document/RichDocumentActions.js +29 -0
  40. package/dist/rich-document/actions/hostActions.d.ts +5 -0
  41. package/dist/rich-document/actions/hostActions.js +31 -0
  42. package/dist/rich-document/actions/labels.d.ts +9 -0
  43. package/dist/rich-document/actions/labels.js +8 -0
  44. package/dist/rich-document/actions/markdownTable.d.ts +9 -0
  45. package/dist/rich-document/actions/markdownTable.js +39 -0
  46. package/dist/rich-document/actions/provider.d.ts +58 -0
  47. package/dist/rich-document/actions/provider.js +245 -0
  48. package/dist/rich-document/actions/resumePendingAuthAction.d.ts +3 -0
  49. package/dist/rich-document/actions/resumePendingAuthAction.js +31 -0
  50. package/dist/rich-document/actions/sources/index.d.ts +9 -0
  51. package/dist/rich-document/actions/sources/index.js +22 -0
  52. package/dist/rich-document/actions/sources/raw.d.ts +4 -0
  53. package/dist/rich-document/actions/sources/raw.js +35 -0
  54. package/dist/rich-document/actions/useRichDocumentProvider.d.ts +1 -0
  55. package/dist/rich-document/actions/useRichDocumentProvider.js +13 -0
  56. package/dist/rich-document/host-types.d.ts +51 -0
  57. package/dist/rich-document/host-types.js +0 -0
  58. package/dist/rich-document/registrations.d.ts +1 -0
  59. package/dist/rich-document/registrations.js +13 -0
  60. package/dist/rich-document/review/applyTargets.d.ts +16 -0
  61. package/dist/rich-document/review/applyTargets.js +32 -0
  62. package/dist/rich-document/review/proposedEdit.d.ts +22 -0
  63. package/dist/rich-document/review/proposedEdit.js +48 -0
  64. package/dist/rich-document/review/protectedSpans.d.ts +14 -0
  65. package/dist/rich-document/review/protectedSpans.js +61 -0
  66. package/dist/rich-document/runtime/actionSurfacesStore.d.ts +30 -0
  67. package/dist/rich-document/runtime/actionSurfacesStore.js +79 -0
  68. package/dist/rich-document/runtime/contextMenuFor.d.ts +6 -0
  69. package/dist/rich-document/runtime/contextMenuFor.js +7 -0
  70. package/dist/rich-document/runtime/providerBridge.d.ts +20 -0
  71. package/dist/rich-document/runtime/providerBridge.js +23 -0
  72. package/dist/rich-document/runtime/useActionSurfaceProvider.d.ts +33 -0
  73. package/dist/rich-document/runtime/useActionSurfaceProvider.js +214 -0
  74. package/dist/rich-document/search/ContentFindControl.d.ts +8 -0
  75. package/dist/rich-document/search/ContentFindControl.js +46 -0
  76. package/dist/rich-document/search/RenderedFindBar.d.ts +8 -0
  77. package/dist/rich-document/search/RenderedFindBar.js +110 -0
  78. package/dist/rich-document/search/renderedFind.d.ts +1 -0
  79. package/dist/rich-document/search/renderedFind.js +1 -0
  80. package/dist/rich-document/types.d.ts +384 -0
  81. package/dist/rich-document/types.js +0 -0
  82. package/dist/rich-document/variants/ActionBar.d.ts +17 -0
  83. package/dist/rich-document/variants/ActionBar.js +48 -0
  84. package/dist/rich-document/variants/MenuVariant.d.ts +15 -0
  85. package/dist/rich-document/variants/MenuVariant.js +17 -0
  86. package/dist/rich-document/variants/MiniActionBar.d.ts +5 -0
  87. package/dist/rich-document/variants/MiniActionBar.js +11 -0
  88. package/dist/rich-document/variants/RegistryActionList.d.ts +17 -0
  89. package/dist/rich-document/variants/RegistryActionList.js +94 -0
  90. package/dist/rich-document/variants/RegistryActionMenu.d.ts +24 -0
  91. package/dist/rich-document/variants/RegistryActionMenu.js +74 -0
  92. package/dist/rich-document/variants/shared/AlchemyDocumentMenu.d.ts +7 -0
  93. package/dist/rich-document/variants/shared/AlchemyDocumentMenu.js +83 -0
  94. package/dist/rich-document/variants/shared/OpenOneMenuButton.d.ts +9 -0
  95. package/dist/rich-document/variants/shared/OpenOneMenuButton.js +70 -0
  96. package/dist/rich-document/variants/shared/StandaloneOneMenu.d.ts +8 -0
  97. package/dist/rich-document/variants/shared/StandaloneOneMenu.js +32 -0
  98. package/dist/rich-document/variants/shared/categories.d.ts +4 -0
  99. package/dist/rich-document/variants/shared/categories.js +31 -0
  100. package/dist/rich-document/variants/shared/iconMap.d.ts +2 -0
  101. package/dist/rich-document/variants/shared/iconMap.js +73 -0
  102. package/dist/rich-document/variants/shared/menuStructure.d.ts +81 -0
  103. package/dist/rich-document/variants/shared/menuStructure.js +268 -0
  104. package/dist/rich-document/variants/shared/runAction.d.ts +17 -0
  105. package/dist/rich-document/variants/shared/runAction.js +24 -0
  106. package/dist/selection-toolbar/SelectionToolbarFrame.d.ts +64 -0
  107. package/dist/selection-toolbar/SelectionToolbarFrame.js +191 -0
  108. package/dist/selection-toolbar/common-actions.d.ts +2 -0
  109. package/dist/selection-toolbar/common-actions.js +103 -0
  110. package/dist/selection-toolbar/selection-actions.d.ts +126 -0
  111. package/dist/selection-toolbar/selection-actions.js +240 -0
  112. package/dist/selection-toolbar/selection-copy.d.ts +19 -0
  113. package/dist/selection-toolbar/selection-copy.js +98 -0
  114. package/dist/selection-toolbar/selection-shape.d.ts +1 -0
  115. package/dist/selection-toolbar/selection-shape.js +15 -0
  116. package/dist/selection-toolbar/selection-zones.d.ts +90 -0
  117. package/dist/selection-toolbar/selection-zones.js +85 -0
  118. package/dist/selection-toolbar/textarea-caret.d.ts +8 -0
  119. package/dist/selection-toolbar/textarea-caret.js +69 -0
  120. package/dist/utils/alchemy-icon-keys.d.ts +18 -0
  121. package/dist/utils/alchemy-icon-keys.js +29 -0
  122. package/dist/utils/rendered-find.d.ts +9 -0
  123. package/dist/utils/rendered-find.js +68 -0
  124. package/package.json +21 -5
@@ -0,0 +1,214 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ import {
4
+ useHostDispatch,
5
+ useHostGetState,
6
+ useIsAuthenticated,
7
+ useIsSuperAdmin,
8
+ useActiveOrganizationId
9
+ } from "../../host/app-bindings.js";
10
+ import {
11
+ registerProvider,
12
+ unregisterProvider,
13
+ updateProviderSpecs
14
+ } from "./actionSurfacesStore.js";
15
+ import { getSourceAdapter } from "../actions/sources/index.js";
16
+ import { shortHash } from "../actions/sources/raw.js";
17
+ import { resolveActions, richDocumentClickTarget } from "../actions/provider.js";
18
+ import { resolveActionLabel } from "../actions/labels.js";
19
+ import {
20
+ registerBridge,
21
+ unregisterBridge,
22
+ updateBridge
23
+ } from "./providerBridge.js";
24
+ function actionsToSpecs(actions, ctx) {
25
+ return actions.map((action) => {
26
+ const disabledResult = action.disabled?.(ctx);
27
+ const isDisabled = disabledResult === true || typeof disabledResult === "object" && disabledResult !== null;
28
+ const disabledReason = typeof disabledResult === "object" && disabledResult !== null ? disabledResult.reason : void 0;
29
+ return {
30
+ id: action.id,
31
+ label: resolveActionLabel(action.label, ctx),
32
+ iconName: action.icon.displayName ?? action.icon.name ?? "Circle",
33
+ category: action.category,
34
+ renderSlot: action.renderSlot ?? "overflow",
35
+ order: action.order ?? 0,
36
+ disabled: isDisabled,
37
+ disabledReason
38
+ };
39
+ });
40
+ }
41
+ function specsKey(specs, contentSourceId) {
42
+ return `${contentSourceId}::${specs.map(
43
+ (s) => `${s.id}|${s.label}|${s.disabled ? 1 : 0}|${s.disabledReason ?? ""}`
44
+ ).join(";")}`;
45
+ }
46
+ function buildContext(args) {
47
+ const adapter = getSourceAdapter(args.source.type);
48
+ const prefix = adapter.instanceKeyPrefix(args.source);
49
+ const instancePrefix = args.source.type === "raw" ? `${prefix}-${shortHash(args.content).slice(0, 8)}` : prefix;
50
+ return {
51
+ content: args.content,
52
+ source: args.source,
53
+ metadata: args.host?.metadata ?? null,
54
+ dispatch: args.dispatch,
55
+ getState: args.getState,
56
+ organizationId: args.organizationId,
57
+ isAuthenticated: args.isAuthenticated,
58
+ isAdmin: args.isAdmin,
59
+ isCreator: args.host?.isCreator ?? false,
60
+ surfaceKey: args.host?.surfaceKey ?? null,
61
+ onClose: () => {
62
+ },
63
+ instanceKey: (suffix) => `${instancePrefix}-${suffix}`,
64
+ sourceAdapter: adapter,
65
+ callbacks: args.callbacks,
66
+ extensions: args.extensions
67
+ };
68
+ }
69
+ function useActionSurfaceProvider(args) {
70
+ const {
71
+ content,
72
+ source,
73
+ actions: actionsProp,
74
+ actionsVariant,
75
+ actionsSurfaceId
76
+ } = args;
77
+ const dispatch = useHostDispatch();
78
+ const getState = useHostGetState();
79
+ const isAuthenticated = Boolean(useIsAuthenticated());
80
+ const isAdmin = Boolean(useIsSuperAdmin());
81
+ const organizationId = useActiveOrganizationId();
82
+ const providerId = React.useId();
83
+ const contentRef = React.useRef(content ?? "");
84
+ const sourceRef = React.useRef(source);
85
+ const callbacksRef = React.useRef(actionsProp?.callbacks);
86
+ const extensionsRef = React.useRef(
87
+ actionsProp?.extensions
88
+ );
89
+ const hostRef = React.useRef(actionsProp);
90
+ const dispatchRef = React.useRef(dispatch);
91
+ const isAuthRef = React.useRef(isAuthenticated);
92
+ const isAdminRef = React.useRef(isAdmin);
93
+ React.useLayoutEffect(() => {
94
+ contentRef.current = content ?? "";
95
+ sourceRef.current = source;
96
+ callbacksRef.current = actionsProp?.callbacks;
97
+ extensionsRef.current = actionsProp?.extensions;
98
+ hostRef.current = actionsProp;
99
+ dispatchRef.current = dispatch;
100
+ isAuthRef.current = isAuthenticated;
101
+ isAdminRef.current = isAdmin;
102
+ });
103
+ const getCtx = () => buildContext({
104
+ content: contentRef.current,
105
+ source: sourceRef.current,
106
+ callbacks: callbacksRef.current,
107
+ extensions: extensionsRef.current,
108
+ host: hostRef.current,
109
+ dispatch: dispatchRef.current,
110
+ getState,
111
+ isAuthenticated: isAuthRef.current,
112
+ isAdmin: isAdminRef.current,
113
+ organizationId
114
+ });
115
+ const ctx = buildContext({
116
+ content: content ?? "",
117
+ source,
118
+ callbacks: actionsProp?.callbacks,
119
+ extensions: actionsProp?.extensions,
120
+ host: actionsProp,
121
+ dispatch,
122
+ getState,
123
+ isAuthenticated,
124
+ isAdmin,
125
+ organizationId
126
+ });
127
+ const resolvedActions = resolveActions(ctx, {
128
+ exclude: actionsProp?.exclude,
129
+ extra: actionsProp?.extra
130
+ });
131
+ const specs = actionsToSpecs(resolvedActions, ctx);
132
+ const targetKey = [
133
+ ctx.instanceKey("target"),
134
+ source.readOnly ? 1 : 0,
135
+ isAuthenticated ? 1 : 0,
136
+ isAdmin ? 1 : 0,
137
+ organizationId ?? "",
138
+ actionsProp?.isCreator ? 1 : 0,
139
+ (actionsProp?.exclude ?? []).join(","),
140
+ (actionsProp?.extra ?? []).map((a) => a.id).join(","),
141
+ shortHash(content ?? ""),
142
+ resolvedActions.map((a) => a.id).join(",")
143
+ ].join("|");
144
+ const [targetState, setTargetState] = React.useState(() => ({
145
+ key: targetKey,
146
+ target: richDocumentClickTarget(ctx, {
147
+ getCtx,
148
+ exclude: actionsProp?.exclude ?? [],
149
+ extra: actionsProp?.extra ?? []
150
+ })
151
+ }));
152
+ if (targetState.key !== targetKey) {
153
+ setTargetState({
154
+ key: targetKey,
155
+ target: richDocumentClickTarget(ctx, {
156
+ getCtx,
157
+ exclude: actionsProp?.exclude ?? [],
158
+ extra: actionsProp?.extra ?? []
159
+ })
160
+ });
161
+ }
162
+ const target = targetState.target;
163
+ const contentSourceId = ctx.instanceKey("alchemy");
164
+ const lastSpecsKey = React.useRef("");
165
+ React.useEffect(() => {
166
+ if (actionsVariant !== "remote" || !actionsSurfaceId) return void 0;
167
+ registerProvider({
168
+ surfaceId: actionsSurfaceId,
169
+ registration: {
170
+ providerId,
171
+ computedActionSpecs: specs,
172
+ contentSourceId,
173
+ sourceType: source.type
174
+ }
175
+ });
176
+ lastSpecsKey.current = specsKey(specs, contentSourceId);
177
+ return () => {
178
+ unregisterProvider({
179
+ surfaceId: actionsSurfaceId,
180
+ providerId
181
+ });
182
+ };
183
+ }, [actionsVariant, actionsSurfaceId, providerId, dispatch, source.type]);
184
+ React.useEffect(() => {
185
+ if (actionsVariant !== "remote" || !actionsSurfaceId) return;
186
+ const key = specsKey(specs, contentSourceId);
187
+ if (key === lastSpecsKey.current) return;
188
+ lastSpecsKey.current = key;
189
+ updateProviderSpecs({
190
+ surfaceId: actionsSurfaceId,
191
+ providerId,
192
+ computedActionSpecs: specs,
193
+ contentSourceId
194
+ });
195
+ }, [
196
+ actionsVariant,
197
+ actionsSurfaceId,
198
+ providerId,
199
+ dispatch,
200
+ specs,
201
+ contentSourceId
202
+ ]);
203
+ React.useEffect(() => {
204
+ registerBridge(providerId, { getCtx, resolvedActions, target });
205
+ return () => unregisterBridge(providerId);
206
+ }, [providerId]);
207
+ React.useEffect(() => {
208
+ updateBridge(providerId, { getCtx, resolvedActions, target });
209
+ });
210
+ return { ctx, getCtx, resolvedActions, target };
211
+ }
212
+ export {
213
+ useActionSurfaceProvider
214
+ };
@@ -0,0 +1,8 @@
1
+ import { type RefObject } from "react";
2
+ /** Places the shared rendered-content finder in a reader's existing header. */
3
+ export declare function ContentFindControl({ rootRef, label, inline, onOpenChange, }: {
4
+ rootRef: RefObject<HTMLElement | null>;
5
+ label?: string;
6
+ inline?: boolean;
7
+ onOpenChange?: (open: boolean) => void;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { Search } from "lucide-react";
5
+ import { Button } from "@ai-matrx/design-system/controls";
6
+ import { RenderedFindBar } from "./RenderedFindBar.js";
7
+ import { surfaceOwnsKey } from "@ai-matrx/kit/keyboard-scope";
8
+ function ContentFindControl({
9
+ rootRef,
10
+ label = "Find in this content",
11
+ inline = false,
12
+ onOpenChange
13
+ }) {
14
+ const [open, setOpen] = useState(false);
15
+ const [focusRequest, setFocusRequest] = useState(0);
16
+ const openFind = () => {
17
+ setOpen(true);
18
+ onOpenChange?.(true);
19
+ setFocusRequest((value) => value + 1);
20
+ };
21
+ const closeFind = () => {
22
+ setOpen(false);
23
+ onOpenChange?.(false);
24
+ };
25
+ useEffect(() => {
26
+ const onKeyDown = (event) => {
27
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "f" && !event.shiftKey && !event.altKey) {
28
+ if (!surfaceOwnsKey(event, rootRef.current)) return;
29
+ event.preventDefault();
30
+ setOpen(true);
31
+ onOpenChange?.(true);
32
+ setFocusRequest((value) => value + 1);
33
+ }
34
+ };
35
+ window.addEventListener("keydown", onKeyDown, true);
36
+ return () => window.removeEventListener("keydown", onKeyDown, true);
37
+ }, [onOpenChange, rootRef]);
38
+ if (inline && open) return /* @__PURE__ */ jsx("div", { className: "min-w-0 w-full sm:w-[360px]", children: /* @__PURE__ */ jsx(RenderedFindBar, { rootRef, label, focusRequest, onClose: closeFind, compact: true }) });
39
+ return /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
40
+ /* @__PURE__ */ jsx(Button, { icon: /* @__PURE__ */ jsx(Search, { "aria-hidden": true }), type: "button", variant: "quiet", "aria-label": label, title: label, onClick: openFind }),
41
+ open && /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-full z-30 mt-1 w-[min(88vw,520px)]", children: /* @__PURE__ */ jsx(RenderedFindBar, { rootRef, label, focusRequest, onClose: closeFind }) })
42
+ ] });
43
+ }
44
+ export {
45
+ ContentFindControl
46
+ };
@@ -0,0 +1,8 @@
1
+ /** A read-only find bar for any rendered RichDocument. Never mutates content or selection. */
2
+ export declare function RenderedFindBar({ rootRef, onClose, label, focusRequest, compact }: {
3
+ rootRef: React.RefObject<HTMLElement | null>;
4
+ onClose: () => void;
5
+ label?: string;
6
+ focusRequest?: number;
7
+ compact?: boolean;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,110 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useRef, useState } from "react";
4
+ import { CaseSensitive, ChevronDown, ChevronUp, Regex, Search, WholeWord, X } from "lucide-react";
5
+ import { collectRenderedFindRanges } from "./renderedFind.js";
6
+ function highlightApi() {
7
+ const css = window.CSS;
8
+ const Highlight = window.Highlight;
9
+ return css?.highlights && Highlight ? { registry: css.highlights, Highlight } : null;
10
+ }
11
+ function clearHighlights(all, active) {
12
+ const api = highlightApi();
13
+ api?.registry.delete(all);
14
+ api?.registry.delete(active);
15
+ }
16
+ function RenderedFindBar({ rootRef, onClose, label = "Find in document", focusRequest = 0, compact = false }) {
17
+ const inputRef = useRef(null);
18
+ const [query, setQuery] = useState("");
19
+ const [options, setOptions] = useState({});
20
+ const [ranges, setRanges] = useState([]);
21
+ const [current, setCurrent] = useState(0);
22
+ const [version, setVersion] = useState(0);
23
+ const instance = useId().replace(/[^a-zA-Z0-9_-]/g, "_");
24
+ const allHighlight = `matrx-rendered-find-${instance}`;
25
+ const activeHighlight = `${allHighlight}-active`;
26
+ const scope = `${allHighlight}-scope`;
27
+ useEffect(() => {
28
+ const root = rootRef.current;
29
+ if (!root) return;
30
+ root.classList.add(scope);
31
+ return () => root.classList.remove(scope);
32
+ }, [rootRef, scope]);
33
+ useEffect(() => {
34
+ inputRef.current?.focus();
35
+ inputRef.current?.select();
36
+ }, [focusRequest]);
37
+ useEffect(() => () => clearHighlights(allHighlight, activeHighlight), [allHighlight, activeHighlight]);
38
+ useEffect(() => {
39
+ const root = rootRef.current;
40
+ if (!root || !query.trim()) return;
41
+ let timer;
42
+ const observer = new MutationObserver(() => {
43
+ if (timer) clearTimeout(timer);
44
+ timer = setTimeout(() => setVersion((value) => value + 1), 150);
45
+ });
46
+ observer.observe(root, { childList: true, subtree: true, characterData: true });
47
+ return () => {
48
+ observer.disconnect();
49
+ if (timer) clearTimeout(timer);
50
+ };
51
+ }, [rootRef, query]);
52
+ useEffect(() => {
53
+ const root = rootRef.current;
54
+ const found = root ? collectRenderedFindRanges(root, query, options) : [];
55
+ setRanges(found);
56
+ setCurrent(0);
57
+ }, [rootRef, query, options, version]);
58
+ useEffect(() => {
59
+ const api = highlightApi();
60
+ if (api) {
61
+ if (ranges.length) api.registry.set(allHighlight, new api.Highlight(...ranges));
62
+ else api.registry.delete(allHighlight);
63
+ const active = ranges[current];
64
+ if (active) api.registry.set(activeHighlight, new api.Highlight(active));
65
+ else api.registry.delete(activeHighlight);
66
+ }
67
+ ranges[current]?.startContainer.parentElement?.scrollIntoView({ block: "center", behavior: "smooth" });
68
+ }, [ranges, current, allHighlight, activeHighlight]);
69
+ const step = (direction) => {
70
+ if (ranges.length) setCurrent((value) => (value + direction + ranges.length) % ranges.length);
71
+ };
72
+ const toggle = (key) => setOptions((value) => ({ ...value, [key]: !value[key] }));
73
+ const validRegex = !options.regex || (() => {
74
+ try {
75
+ new RegExp(query);
76
+ return true;
77
+ } catch {
78
+ return false;
79
+ }
80
+ })();
81
+ return /* @__PURE__ */ jsxs("div", { role: "search", "aria-label": label, "data-find-ignore": "", className: `flex min-w-0 items-center gap-1 rounded-lg border border-border bg-card px-2 py-1 shadow-sm ${compact ? "flex-nowrap" : "flex-wrap"}`, children: [
82
+ /* @__PURE__ */ jsx("style", { children: `.${scope}::highlight(${allHighlight}), .${scope} ::highlight(${allHighlight}) { background-color: rgb(250 204 21 / .5); color: inherit; } .${scope}::highlight(${activeHighlight}), .${scope} ::highlight(${activeHighlight}) { background-color: rgb(249 115 22 / .85); color: white; }` }),
83
+ /* @__PURE__ */ jsx(Search, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
84
+ /* @__PURE__ */ jsx("input", { ref: inputRef, type: "search", value: query, onChange: (event) => setQuery(event.target.value), onKeyDown: (event) => {
85
+ if (event.key === "Enter") {
86
+ event.preventDefault();
87
+ step(event.shiftKey ? -1 : 1);
88
+ }
89
+ if (event.key === "Escape") {
90
+ event.preventDefault();
91
+ onClose();
92
+ }
93
+ }, placeholder: label, "aria-label": label, className: "min-w-0 flex-1 bg-transparent text-base outline-none md:text-sm" }),
94
+ /* @__PURE__ */ jsx("span", { className: "min-w-12 text-right text-xs tabular-nums text-muted-foreground", "aria-live": "polite", children: !validRegex ? "Invalid pattern" : !query.trim() ? "" : ranges.length ? `${current + 1} of ${ranges.length}` : "No matches" }),
95
+ !compact && /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ /* @__PURE__ */ jsx(OptionButton, { label: "Match case", pressed: !!options.caseSensitive, onClick: () => toggle("caseSensitive"), children: /* @__PURE__ */ jsx(CaseSensitive, { className: "h-4 w-4" }) }),
97
+ /* @__PURE__ */ jsx(OptionButton, { label: "Whole word", pressed: !!options.wholeWord, onClick: () => toggle("wholeWord"), children: /* @__PURE__ */ jsx(WholeWord, { className: "h-4 w-4" }) }),
98
+ /* @__PURE__ */ jsx(OptionButton, { label: "Regular expression", pressed: !!options.regex, onClick: () => toggle("regex"), children: /* @__PURE__ */ jsx(Regex, { className: "h-4 w-4" }) })
99
+ ] }),
100
+ /* @__PURE__ */ jsx(OptionButton, { label: "Previous match", disabled: !ranges.length, onClick: () => step(-1), children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" }) }),
101
+ /* @__PURE__ */ jsx(OptionButton, { label: "Next match", disabled: !ranges.length, onClick: () => step(1), children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" }) }),
102
+ /* @__PURE__ */ jsx(OptionButton, { label: "Close search", onClick: onClose, children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) })
103
+ ] });
104
+ }
105
+ function OptionButton({ label, pressed, disabled, onClick, children }) {
106
+ return /* @__PURE__ */ jsx("button", { type: "button", "aria-label": label, title: label, "aria-pressed": pressed, disabled, onClick, className: "rounded p-1 text-muted-foreground hover:bg-accent hover:text-foreground aria-pressed:bg-primary/10 aria-pressed:text-primary-ink disabled:opacity-40", children });
107
+ }
108
+ export {
109
+ RenderedFindBar
110
+ };
@@ -0,0 +1 @@
1
+ export * from "../../utils/rendered-find.js";
@@ -0,0 +1 @@
1
+ export * from "../../utils/rendered-find.js";