@pixerate/editor-react 0.15.0 → 0.17.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 +6 -2
- package/dist/canvas/index.cjs +484 -119
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +122 -3
- package/dist/canvas/index.d.ts +122 -3
- package/dist/canvas/index.js +380 -0
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-I3E4KSA2.js +515 -0
- package/dist/chunk-I3E4KSA2.js.map +1 -0
- package/dist/chunk-JR5ZBDR7.js +2012 -0
- package/dist/chunk-JR5ZBDR7.js.map +1 -0
- package/dist/chunk-XWFU2CSG.js +167 -0
- package/dist/chunk-XWFU2CSG.js.map +1 -0
- package/dist/chunk-ZU54BMDC.js +2128 -0
- package/dist/chunk-ZU54BMDC.js.map +1 -0
- package/dist/generation/index.cjs +525 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +124 -0
- package/dist/generation/index.d.ts +124 -0
- package/dist/generation/index.js +19 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/image-editor/index.cjs +988 -337
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +92 -2
- package/dist/image-editor/index.d.ts +92 -2
- package/dist/image-editor/index.js +17 -3
- package/dist/index.cjs +3628 -754
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +226 -5
- package/dist/index.d.ts +226 -5
- package/dist/index.js +868 -77
- package/dist/index.js.map +1 -1
- package/dist/persistence/index.cjs +191 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +77 -0
- package/dist/persistence/index.d.ts +77 -0
- package/dist/persistence/index.js +9 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/spreadsheet/index.cjs +949 -111
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +121 -7
- package/dist/spreadsheet/index.d.ts +121 -7
- package/dist/spreadsheet/index.js +11 -1
- package/dist/tokens/index.cjs +395 -0
- package/dist/tokens/index.cjs.map +1 -0
- package/dist/tokens/index.d.cts +54 -0
- package/dist/tokens/index.d.ts +54 -0
- package/dist/tokens/index.js +375 -0
- package/dist/tokens/index.js.map +1 -0
- package/package.json +26 -2
- package/dist/chunk-LPFZMZ3L.js +0 -1461
- package/dist/chunk-LPFZMZ3L.js.map +0 -1
- package/dist/chunk-QVQYYHJ5.js +0 -1161
- package/dist/chunk-QVQYYHJ5.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FormulaHints,
|
|
3
|
+
NameManager,
|
|
4
|
+
SheetTabs,
|
|
5
|
+
SpreadsheetConditionalFormatPanel,
|
|
3
6
|
SpreadsheetContextMenu,
|
|
7
|
+
SpreadsheetDataValidationPanel,
|
|
4
8
|
SpreadsheetEditor,
|
|
5
9
|
SpreadsheetGroupRow,
|
|
10
|
+
SpreadsheetValidationDialog,
|
|
6
11
|
useFillHandle,
|
|
7
12
|
useSpreadsheetClipboard,
|
|
8
13
|
useSpreadsheetEditor
|
|
9
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JR5ZBDR7.js";
|
|
10
15
|
import {
|
|
16
|
+
AdjustmentLayersPanel,
|
|
17
|
+
ControlSlider,
|
|
18
|
+
CurvesEditor,
|
|
19
|
+
Histogram,
|
|
11
20
|
ImageEditor,
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
RefineEdgePanel,
|
|
22
|
+
SelectionOptionsBar,
|
|
23
|
+
useImageEditor,
|
|
24
|
+
useImageHistogram
|
|
25
|
+
} from "./chunk-ZU54BMDC.js";
|
|
14
26
|
import {
|
|
15
27
|
CommandPalette,
|
|
16
28
|
useCommandPalette,
|
|
17
29
|
useCommandShortcuts,
|
|
18
30
|
useRegisterCommands
|
|
19
31
|
} from "./chunk-4ZC2WCUO.js";
|
|
32
|
+
import {
|
|
33
|
+
RecoveryPrompt,
|
|
34
|
+
useAutosave
|
|
35
|
+
} from "./chunk-XWFU2CSG.js";
|
|
36
|
+
import {
|
|
37
|
+
AssetMentionChips,
|
|
38
|
+
GenerationHistory,
|
|
39
|
+
GenerationSettings,
|
|
40
|
+
JobProgress,
|
|
41
|
+
useGenerationPlan,
|
|
42
|
+
useGenerationRecords,
|
|
43
|
+
useJobProgress
|
|
44
|
+
} from "./chunk-I3E4KSA2.js";
|
|
20
45
|
|
|
21
46
|
// src/hooks/usePromptEditor.ts
|
|
22
47
|
import { useMemo, useEffect, useRef } from "react";
|
|
@@ -561,7 +586,8 @@ function useHistoryShortcuts(manager, options = {}) {
|
|
|
561
586
|
// src/hooks/useFileImport.ts
|
|
562
587
|
import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef6, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
563
588
|
import {
|
|
564
|
-
FileImportController
|
|
589
|
+
FileImportController,
|
|
590
|
+
summarizeImportStructure
|
|
565
591
|
} from "@pixerate/editor";
|
|
566
592
|
function useFileImport(editor, options = {}) {
|
|
567
593
|
const editorRef = useRef6(editor);
|
|
@@ -577,8 +603,10 @@ function useFileImport(editor, options = {}) {
|
|
|
577
603
|
controller.setOptions(options);
|
|
578
604
|
});
|
|
579
605
|
const state = useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
|
|
606
|
+
const structureSummary = useMemo3(() => summarizeImportStructure(state.lastOutcomes), [state.lastOutcomes]);
|
|
580
607
|
return {
|
|
581
608
|
...state,
|
|
609
|
+
structureSummary,
|
|
582
610
|
accept: controller.accept,
|
|
583
611
|
openFilePicker: controller.openFilePicker,
|
|
584
612
|
importFiles: controller.importFiles
|
|
@@ -660,11 +688,12 @@ var BubbleMenu = ({
|
|
|
660
688
|
// src/components/TemplateRenderer.tsx
|
|
661
689
|
import { useMemo as useMemo4 } from "react";
|
|
662
690
|
import {
|
|
691
|
+
describeConditionalTag,
|
|
663
692
|
evaluatePromptTokens,
|
|
693
|
+
formatConditionalTag,
|
|
664
694
|
resolveTemplates
|
|
665
695
|
} from "@pixerate/editor";
|
|
666
696
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
667
|
-
var CONDITIONAL_PREFIX = { if: "?", unless: "!", end: "/" };
|
|
668
697
|
var TemplateRenderer = ({
|
|
669
698
|
content,
|
|
670
699
|
templates = [],
|
|
@@ -747,8 +776,8 @@ var TemplateRenderer = ({
|
|
|
747
776
|
{
|
|
748
777
|
"data-conditional": token.conditional,
|
|
749
778
|
className: "inline-flex items-center px-1 py-0.5 mx-0.5 text-xs font-medium rounded-md border border-amber-400/40 bg-amber-400/15 text-amber-700 dark:text-amber-300",
|
|
750
|
-
title: token
|
|
751
|
-
children:
|
|
779
|
+
title: describeConditionalTag(token),
|
|
780
|
+
children: formatConditionalTag(token)
|
|
752
781
|
},
|
|
753
782
|
index
|
|
754
783
|
);
|
|
@@ -856,17 +885,312 @@ var VariableForm = ({
|
|
|
856
885
|
}) });
|
|
857
886
|
};
|
|
858
887
|
|
|
888
|
+
// src/components/MergePreview.tsx
|
|
889
|
+
import { useId as useId2, useState as useState7 } from "react";
|
|
890
|
+
|
|
891
|
+
// src/hooks/useMergePreview.ts
|
|
892
|
+
import { useCallback as useCallback5, useMemo as useMemo6, useState as useState6 } from "react";
|
|
893
|
+
import {
|
|
894
|
+
extractVariables,
|
|
895
|
+
matchFields,
|
|
896
|
+
mergeRecords,
|
|
897
|
+
parseDataSource,
|
|
898
|
+
recordToValues,
|
|
899
|
+
serializeMergeOutputs
|
|
900
|
+
} from "@pixerate/editor";
|
|
901
|
+
function useMergePreview(options) {
|
|
902
|
+
const { template, templates, bindings, parseOptions } = options;
|
|
903
|
+
const [sourceText, setSourceTextState] = useState6(options.initialSource ?? "");
|
|
904
|
+
const [overrides, setOverrides] = useState6({});
|
|
905
|
+
const [index, setIndexState] = useState6(0);
|
|
906
|
+
const [result, setResult] = useState6(null);
|
|
907
|
+
const source = useMemo6(
|
|
908
|
+
() => parseDataSource(sourceText, parseOptions),
|
|
909
|
+
[sourceText, parseOptions]
|
|
910
|
+
);
|
|
911
|
+
const variables = useMemo6(
|
|
912
|
+
() => extractVariables(template, { templates, bindings }).map((v) => v.name),
|
|
913
|
+
[template, templates, bindings]
|
|
914
|
+
);
|
|
915
|
+
const mapping = useMemo6(() => {
|
|
916
|
+
const merged = {
|
|
917
|
+
...matchFields(variables, source.fields).mapping
|
|
918
|
+
};
|
|
919
|
+
for (const [variable, field] of Object.entries(overrides)) {
|
|
920
|
+
if (variables.includes(variable) && (field === null || source.fields.includes(field))) {
|
|
921
|
+
merged[variable] = field;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return merged;
|
|
925
|
+
}, [variables, source.fields, overrides]);
|
|
926
|
+
const count = source.records.length;
|
|
927
|
+
const current = count === 0 ? 0 : Math.min(index, count - 1);
|
|
928
|
+
const record = source.records[current];
|
|
929
|
+
const values = useMemo6(
|
|
930
|
+
() => record ? recordToValues(record, mapping) : {},
|
|
931
|
+
[record, mapping]
|
|
932
|
+
);
|
|
933
|
+
const setSourceText = useCallback5((text) => {
|
|
934
|
+
setSourceTextState(text);
|
|
935
|
+
setIndexState(0);
|
|
936
|
+
setResult(null);
|
|
937
|
+
}, []);
|
|
938
|
+
const loadFile = useCallback5(
|
|
939
|
+
async (file) => setSourceText(await file.text()),
|
|
940
|
+
[setSourceText]
|
|
941
|
+
);
|
|
942
|
+
const setIndex = useCallback5(
|
|
943
|
+
(next) => setIndexState(Math.max(0, Math.min(next, count - 1))),
|
|
944
|
+
[count]
|
|
945
|
+
);
|
|
946
|
+
const setFieldMapping = useCallback5((variable, field) => {
|
|
947
|
+
setOverrides((previous) => ({ ...previous, [variable]: field }));
|
|
948
|
+
setResult(null);
|
|
949
|
+
}, []);
|
|
950
|
+
const resetMapping = useCallback5(() => setOverrides({}), []);
|
|
951
|
+
const merge = useCallback5(() => {
|
|
952
|
+
const merged = mergeRecords(template, source, {
|
|
953
|
+
templates,
|
|
954
|
+
bindings,
|
|
955
|
+
mapping,
|
|
956
|
+
skipIf: options.skipIf,
|
|
957
|
+
separator: options.separator,
|
|
958
|
+
maxOutputs: options.maxOutputs
|
|
959
|
+
});
|
|
960
|
+
setResult(merged);
|
|
961
|
+
return merged;
|
|
962
|
+
}, [template, source, templates, bindings, mapping, options.skipIf, options.separator, options.maxOutputs]);
|
|
963
|
+
const serialize = useCallback5(
|
|
964
|
+
(format) => result ? serializeMergeOutputs(result.outputs, format, options.separator) : "",
|
|
965
|
+
[result, options.separator]
|
|
966
|
+
);
|
|
967
|
+
return {
|
|
968
|
+
sourceText,
|
|
969
|
+
setSourceText,
|
|
970
|
+
loadFile,
|
|
971
|
+
source,
|
|
972
|
+
variables,
|
|
973
|
+
mapping,
|
|
974
|
+
setFieldMapping,
|
|
975
|
+
resetMapping,
|
|
976
|
+
index: current,
|
|
977
|
+
count,
|
|
978
|
+
setIndex,
|
|
979
|
+
next: () => setIndex(current + 1),
|
|
980
|
+
prev: () => setIndex(current - 1),
|
|
981
|
+
record,
|
|
982
|
+
values,
|
|
983
|
+
merge,
|
|
984
|
+
result,
|
|
985
|
+
serialize
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// src/components/MergePreview.tsx
|
|
990
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
991
|
+
function downloadText(text, fileName, type) {
|
|
992
|
+
if (typeof document === "undefined" || typeof URL.createObjectURL !== "function") {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
const url = URL.createObjectURL(new Blob([text], { type }));
|
|
996
|
+
const link = document.createElement("a");
|
|
997
|
+
link.href = url;
|
|
998
|
+
link.download = fileName;
|
|
999
|
+
link.click();
|
|
1000
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
1001
|
+
}
|
|
1002
|
+
var MergePreview = ({
|
|
1003
|
+
content,
|
|
1004
|
+
templates,
|
|
1005
|
+
bindings,
|
|
1006
|
+
templateColorMap,
|
|
1007
|
+
defaultSource,
|
|
1008
|
+
parseOptions,
|
|
1009
|
+
skipIf,
|
|
1010
|
+
separator,
|
|
1011
|
+
maxOutputs,
|
|
1012
|
+
onMerge,
|
|
1013
|
+
downloadName = "merged",
|
|
1014
|
+
className = "flex flex-col gap-3 text-sm"
|
|
1015
|
+
}) => {
|
|
1016
|
+
const id = useId2();
|
|
1017
|
+
const merge = useMergePreview({
|
|
1018
|
+
template: content,
|
|
1019
|
+
templates,
|
|
1020
|
+
bindings,
|
|
1021
|
+
initialSource: defaultSource,
|
|
1022
|
+
parseOptions,
|
|
1023
|
+
skipIf,
|
|
1024
|
+
separator,
|
|
1025
|
+
maxOutputs
|
|
1026
|
+
});
|
|
1027
|
+
const [copied, setCopied] = useState7(false);
|
|
1028
|
+
const { source, result } = merge;
|
|
1029
|
+
const copy = async () => {
|
|
1030
|
+
try {
|
|
1031
|
+
await navigator.clipboard.writeText(merge.serialize("text"));
|
|
1032
|
+
setCopied(true);
|
|
1033
|
+
} catch {
|
|
1034
|
+
setCopied(false);
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
return /* @__PURE__ */ jsxs3("div", { className, "data-merge-preview": "", children: [
|
|
1038
|
+
/* @__PURE__ */ jsxs3("label", { htmlFor: `${id}-source`, className: "flex flex-col gap-1", children: [
|
|
1039
|
+
/* @__PURE__ */ jsx4("span", { className: "font-medium", children: "Data source (CSV, TSV or JSON)" }),
|
|
1040
|
+
/* @__PURE__ */ jsx4(
|
|
1041
|
+
"textarea",
|
|
1042
|
+
{
|
|
1043
|
+
id: `${id}-source`,
|
|
1044
|
+
"data-merge-source": "",
|
|
1045
|
+
value: merge.sourceText,
|
|
1046
|
+
rows: 5,
|
|
1047
|
+
spellCheck: false,
|
|
1048
|
+
onChange: (event) => merge.setSourceText(event.target.value),
|
|
1049
|
+
className: "px-2 py-1 font-mono text-xs rounded-md border border-violet-400/40 bg-transparent"
|
|
1050
|
+
}
|
|
1051
|
+
)
|
|
1052
|
+
] }),
|
|
1053
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1054
|
+
/* @__PURE__ */ jsx4(
|
|
1055
|
+
"input",
|
|
1056
|
+
{
|
|
1057
|
+
type: "file",
|
|
1058
|
+
accept: ".csv,.tsv,.txt,.json,text/csv,application/json",
|
|
1059
|
+
"aria-label": "Load data source file",
|
|
1060
|
+
"data-merge-file": "",
|
|
1061
|
+
onChange: (event) => {
|
|
1062
|
+
const file = event.target.files?.[0];
|
|
1063
|
+
if (file) void merge.loadFile(file);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
),
|
|
1067
|
+
/* @__PURE__ */ jsx4("span", { "data-merge-summary": "", className: "opacity-70", children: `${source.records.length} record${source.records.length === 1 ? "" : "s"} \xB7 ${source.fields.length} field${source.fields.length === 1 ? "" : "s"}` })
|
|
1068
|
+
] }),
|
|
1069
|
+
source.warnings.length > 0 && merge.sourceText.trim() !== "" && /* @__PURE__ */ jsx4("ul", { "data-merge-warnings": "", className: "text-amber-600 text-xs", children: source.warnings.map((warning, i) => /* @__PURE__ */ jsx4("li", { children: warning.message }, i)) }),
|
|
1070
|
+
merge.variables.length > 0 && /* @__PURE__ */ jsxs3("fieldset", { className: "flex flex-col gap-1", children: [
|
|
1071
|
+
/* @__PURE__ */ jsx4("legend", { className: "font-medium", children: "Field mapping" }),
|
|
1072
|
+
merge.variables.map((variable) => /* @__PURE__ */ jsxs3(
|
|
1073
|
+
"label",
|
|
1074
|
+
{
|
|
1075
|
+
className: "flex items-center gap-2",
|
|
1076
|
+
"data-merge-mapping": variable,
|
|
1077
|
+
children: [
|
|
1078
|
+
/* @__PURE__ */ jsx4("span", { className: "min-w-24 font-mono", children: `{${variable}}` }),
|
|
1079
|
+
/* @__PURE__ */ jsxs3(
|
|
1080
|
+
"select",
|
|
1081
|
+
{
|
|
1082
|
+
value: merge.mapping[variable] ?? "",
|
|
1083
|
+
"aria-label": `Field for ${variable}`,
|
|
1084
|
+
onChange: (event) => merge.setFieldMapping(variable, event.target.value || null),
|
|
1085
|
+
className: "px-1 py-0.5 rounded-md border border-violet-400/40 bg-transparent",
|
|
1086
|
+
children: [
|
|
1087
|
+
/* @__PURE__ */ jsx4("option", { value: "", children: "(none)" }),
|
|
1088
|
+
source.fields.map((field) => /* @__PURE__ */ jsx4("option", { value: field, children: field }, field))
|
|
1089
|
+
]
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
1092
|
+
]
|
|
1093
|
+
},
|
|
1094
|
+
variable
|
|
1095
|
+
))
|
|
1096
|
+
] }),
|
|
1097
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2", children: [
|
|
1098
|
+
/* @__PURE__ */ jsx4(
|
|
1099
|
+
"button",
|
|
1100
|
+
{
|
|
1101
|
+
type: "button",
|
|
1102
|
+
"data-merge-prev": "",
|
|
1103
|
+
onClick: merge.prev,
|
|
1104
|
+
disabled: merge.index <= 0,
|
|
1105
|
+
children: "Prev"
|
|
1106
|
+
}
|
|
1107
|
+
),
|
|
1108
|
+
/* @__PURE__ */ jsx4("span", { "data-merge-position": "", children: merge.count === 0 ? "No records" : `Record ${merge.index + 1} of ${merge.count}` }),
|
|
1109
|
+
/* @__PURE__ */ jsx4(
|
|
1110
|
+
"button",
|
|
1111
|
+
{
|
|
1112
|
+
type: "button",
|
|
1113
|
+
"data-merge-next": "",
|
|
1114
|
+
onClick: merge.next,
|
|
1115
|
+
disabled: merge.index >= merge.count - 1,
|
|
1116
|
+
children: "Next"
|
|
1117
|
+
}
|
|
1118
|
+
)
|
|
1119
|
+
] }),
|
|
1120
|
+
/* @__PURE__ */ jsx4("div", { "data-merge-output": "", children: /* @__PURE__ */ jsx4(
|
|
1121
|
+
TemplateRenderer,
|
|
1122
|
+
{
|
|
1123
|
+
content,
|
|
1124
|
+
templates,
|
|
1125
|
+
bindings,
|
|
1126
|
+
templateColorMap,
|
|
1127
|
+
resolve: !!templates && templates.length > 0,
|
|
1128
|
+
values: merge.values
|
|
1129
|
+
}
|
|
1130
|
+
) }),
|
|
1131
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1132
|
+
/* @__PURE__ */ jsx4(
|
|
1133
|
+
"button",
|
|
1134
|
+
{
|
|
1135
|
+
type: "button",
|
|
1136
|
+
"data-merge-all": "",
|
|
1137
|
+
disabled: merge.count === 0,
|
|
1138
|
+
onClick: () => {
|
|
1139
|
+
const merged = merge.merge();
|
|
1140
|
+
setCopied(false);
|
|
1141
|
+
onMerge?.(merged);
|
|
1142
|
+
},
|
|
1143
|
+
children: "Merge all"
|
|
1144
|
+
}
|
|
1145
|
+
),
|
|
1146
|
+
result && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1147
|
+
/* @__PURE__ */ jsx4("span", { "data-merge-result": "", children: `${result.outputs.length} merged${result.skipped.length ? `, ${result.skipped.length} skipped` : ""}${result.truncated ? " (stopped early)" : ""}` }),
|
|
1148
|
+
/* @__PURE__ */ jsx4("button", { type: "button", "data-merge-copy": "", onClick: copy, children: copied ? "Copied" : "Copy" }),
|
|
1149
|
+
/* @__PURE__ */ jsx4(
|
|
1150
|
+
"button",
|
|
1151
|
+
{
|
|
1152
|
+
type: "button",
|
|
1153
|
+
"data-merge-download": "text",
|
|
1154
|
+
onClick: () => downloadText(merge.serialize("text"), `${downloadName}.txt`, "text/plain"),
|
|
1155
|
+
children: "Download .txt"
|
|
1156
|
+
}
|
|
1157
|
+
),
|
|
1158
|
+
/* @__PURE__ */ jsx4(
|
|
1159
|
+
"button",
|
|
1160
|
+
{
|
|
1161
|
+
type: "button",
|
|
1162
|
+
"data-merge-download": "json",
|
|
1163
|
+
onClick: () => downloadText(merge.serialize("json"), `${downloadName}.json`, "application/json"),
|
|
1164
|
+
children: "Download .json"
|
|
1165
|
+
}
|
|
1166
|
+
)
|
|
1167
|
+
] })
|
|
1168
|
+
] }),
|
|
1169
|
+
result && /* @__PURE__ */ jsx4(
|
|
1170
|
+
"textarea",
|
|
1171
|
+
{
|
|
1172
|
+
readOnly: true,
|
|
1173
|
+
"aria-label": "Merged output",
|
|
1174
|
+
"data-merge-text": "",
|
|
1175
|
+
rows: 6,
|
|
1176
|
+
value: merge.serialize("text"),
|
|
1177
|
+
className: "px-2 py-1 font-mono text-xs rounded-md border border-violet-400/40 bg-transparent"
|
|
1178
|
+
}
|
|
1179
|
+
)
|
|
1180
|
+
] });
|
|
1181
|
+
};
|
|
1182
|
+
|
|
859
1183
|
// src/hooks/useOutline.ts
|
|
860
|
-
import { useMemo as
|
|
1184
|
+
import { useMemo as useMemo7, useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
861
1185
|
import { createOutlineStore } from "@pixerate/editor";
|
|
862
1186
|
function useOutline(editor) {
|
|
863
|
-
const store =
|
|
1187
|
+
const store = useMemo7(() => createOutlineStore(editor), [editor]);
|
|
864
1188
|
return useSyncExternalStore4(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
865
1189
|
}
|
|
866
1190
|
|
|
867
1191
|
// src/components/OutlinePanel.tsx
|
|
868
1192
|
import { navigateToHeading } from "@pixerate/editor";
|
|
869
|
-
import { jsx as
|
|
1193
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
870
1194
|
var OutlinePanel = ({
|
|
871
1195
|
editor,
|
|
872
1196
|
title = "Outline",
|
|
@@ -880,11 +1204,11 @@ var OutlinePanel = ({
|
|
|
880
1204
|
}) => {
|
|
881
1205
|
const { headings, activeId } = useOutline(editor);
|
|
882
1206
|
const visible = headings.filter((h) => h.level <= maxLevel);
|
|
883
|
-
return /* @__PURE__ */
|
|
884
|
-
title != null && /* @__PURE__ */
|
|
885
|
-
visible.length === 0 ? /* @__PURE__ */
|
|
1207
|
+
return /* @__PURE__ */ jsxs4("nav", { className, "aria-label": "Document outline", "data-outline-panel": "", children: [
|
|
1208
|
+
title != null && /* @__PURE__ */ jsx5("div", { className: "pixerate-outline-title", children: title }),
|
|
1209
|
+
visible.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "pixerate-outline-empty", children: emptyState }) : /* @__PURE__ */ jsx5("ul", { role: "list", style: { listStyle: "none", margin: 0, padding: 0 }, children: visible.map((heading) => {
|
|
886
1210
|
const active = heading.id === activeId;
|
|
887
|
-
return /* @__PURE__ */
|
|
1211
|
+
return /* @__PURE__ */ jsx5("li", { "data-level": heading.level, children: /* @__PURE__ */ jsx5(
|
|
888
1212
|
"button",
|
|
889
1213
|
{
|
|
890
1214
|
type: "button",
|
|
@@ -905,6 +1229,168 @@ var OutlinePanel = ({
|
|
|
905
1229
|
] });
|
|
906
1230
|
};
|
|
907
1231
|
|
|
1232
|
+
// src/hooks/useParagraphStyles.ts
|
|
1233
|
+
import { useMemo as useMemo8, useSyncExternalStore as useSyncExternalStore5 } from "react";
|
|
1234
|
+
import {
|
|
1235
|
+
createParagraphStylesStore,
|
|
1236
|
+
getStyleRegistry
|
|
1237
|
+
} from "@pixerate/editor";
|
|
1238
|
+
function useParagraphStyles(editor) {
|
|
1239
|
+
const store = useMemo8(() => createParagraphStylesStore(editor), [editor]);
|
|
1240
|
+
const snapshot = useSyncExternalStore5(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
1241
|
+
return useMemo8(() => {
|
|
1242
|
+
const registry = getStyleRegistry(editor);
|
|
1243
|
+
const live = () => editor && !editor.isDestroyed ? editor : null;
|
|
1244
|
+
return {
|
|
1245
|
+
...snapshot,
|
|
1246
|
+
registry,
|
|
1247
|
+
currentStyle: snapshot.currentStyleId && registry?.get(snapshot.currentStyleId) || null,
|
|
1248
|
+
apply: (id) => !!live()?.chain().focus().setParagraphStyle(id).run(),
|
|
1249
|
+
clear: () => !!live()?.chain().focus().clearParagraphStyle().run(),
|
|
1250
|
+
updateFromSelection: (id) => !!live()?.chain().focus().updateParagraphStyleFromSelection(id).run(),
|
|
1251
|
+
createFromSelection: (name, options) => {
|
|
1252
|
+
const e = live();
|
|
1253
|
+
if (!e || !registry) return null;
|
|
1254
|
+
const id = options?.id ?? registry.newId(name.trim());
|
|
1255
|
+
const ok = e.chain().focus().createParagraphStyleFromSelection(name, { ...options, id }).run();
|
|
1256
|
+
return ok ? id : null;
|
|
1257
|
+
},
|
|
1258
|
+
applyCharacterStyle: (id) => !!live()?.chain().focus().setCharacterStyle(id).run()
|
|
1259
|
+
};
|
|
1260
|
+
}, [snapshot, editor]);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// src/components/StylesGallery.tsx
|
|
1264
|
+
import { useState as useState8 } from "react";
|
|
1265
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1266
|
+
var camel = (property) => property.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
1267
|
+
var keepSelection = (event) => event.preventDefault();
|
|
1268
|
+
var StylesGallery = ({
|
|
1269
|
+
editor,
|
|
1270
|
+
variant = "dropdown",
|
|
1271
|
+
showAllStyles = false,
|
|
1272
|
+
showActions = true,
|
|
1273
|
+
preview = true,
|
|
1274
|
+
className = "relative inline-flex flex-wrap items-center gap-1 text-sm",
|
|
1275
|
+
itemClassName = "rounded px-2 py-1 text-left text-xs text-foreground hover:bg-muted",
|
|
1276
|
+
activeItemClassName = "bg-primary/10 text-primary",
|
|
1277
|
+
onChange
|
|
1278
|
+
}) => {
|
|
1279
|
+
const styles = useParagraphStyles(editor);
|
|
1280
|
+
const [open, setOpen] = useState8(false);
|
|
1281
|
+
const [creating, setCreating] = useState8(false);
|
|
1282
|
+
const [name, setName] = useState8("");
|
|
1283
|
+
const list = showAllStyles ? styles.styles : styles.gallery;
|
|
1284
|
+
const current = styles.currentStyle;
|
|
1285
|
+
const expanded = variant === "gallery" || open;
|
|
1286
|
+
const close = () => {
|
|
1287
|
+
if (variant === "dropdown") setOpen(false);
|
|
1288
|
+
setCreating(false);
|
|
1289
|
+
setName("");
|
|
1290
|
+
};
|
|
1291
|
+
const previewStyle = (id) => {
|
|
1292
|
+
if (!preview || !styles.registry) return void 0;
|
|
1293
|
+
return Object.fromEntries(
|
|
1294
|
+
Object.entries(styles.registry.previewDeclarations(id)).map(([k, v]) => [camel(k), v])
|
|
1295
|
+
);
|
|
1296
|
+
};
|
|
1297
|
+
const apply = (id) => {
|
|
1298
|
+
if (styles.apply(id)) onChange?.({ type: "apply", id });
|
|
1299
|
+
close();
|
|
1300
|
+
};
|
|
1301
|
+
const create = (event) => {
|
|
1302
|
+
event.preventDefault();
|
|
1303
|
+
const id = name.trim() ? styles.createFromSelection(name) : null;
|
|
1304
|
+
if (id) onChange?.({ type: "create", id });
|
|
1305
|
+
close();
|
|
1306
|
+
};
|
|
1307
|
+
return /* @__PURE__ */ jsxs5("div", { className, role: "group", "aria-label": "Paragraph styles", "data-styles-gallery": variant, children: [
|
|
1308
|
+
variant === "dropdown" && /* @__PURE__ */ jsxs5(
|
|
1309
|
+
"button",
|
|
1310
|
+
{
|
|
1311
|
+
type: "button",
|
|
1312
|
+
className: itemClassName,
|
|
1313
|
+
"aria-haspopup": "listbox",
|
|
1314
|
+
"aria-expanded": open,
|
|
1315
|
+
disabled: !editor || !styles.registry,
|
|
1316
|
+
onMouseDown: keepSelection,
|
|
1317
|
+
onClick: () => setOpen((value) => !value),
|
|
1318
|
+
children: [
|
|
1319
|
+
current?.name ?? "Styles",
|
|
1320
|
+
" \u25BE"
|
|
1321
|
+
]
|
|
1322
|
+
}
|
|
1323
|
+
),
|
|
1324
|
+
expanded && /* @__PURE__ */ jsxs5(
|
|
1325
|
+
"div",
|
|
1326
|
+
{
|
|
1327
|
+
className: variant === "dropdown" ? "absolute left-0 top-full z-20 mt-1 flex min-w-[12rem] flex-col gap-0.5 rounded-md border border-border bg-background p-1 shadow-md" : "flex flex-wrap items-center gap-1",
|
|
1328
|
+
children: [
|
|
1329
|
+
/* @__PURE__ */ jsx6("div", { role: "listbox", "aria-label": "Styles", className: variant === "dropdown" ? "flex flex-col gap-0.5" : "flex flex-wrap gap-1", children: list.map((style) => {
|
|
1330
|
+
const active = style.id === styles.currentStyleId;
|
|
1331
|
+
return /* @__PURE__ */ jsx6(
|
|
1332
|
+
"button",
|
|
1333
|
+
{
|
|
1334
|
+
type: "button",
|
|
1335
|
+
role: "option",
|
|
1336
|
+
"aria-selected": active,
|
|
1337
|
+
"data-style-id": style.id,
|
|
1338
|
+
className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
|
|
1339
|
+
style: previewStyle(style.id),
|
|
1340
|
+
onMouseDown: keepSelection,
|
|
1341
|
+
onClick: () => apply(style.id),
|
|
1342
|
+
children: style.name
|
|
1343
|
+
},
|
|
1344
|
+
style.id
|
|
1345
|
+
);
|
|
1346
|
+
}) }),
|
|
1347
|
+
showActions && /* @__PURE__ */ jsxs5("div", { className: variant === "dropdown" ? "mt-1 flex flex-col gap-0.5 border-t border-border pt-1" : "flex items-center gap-1", children: [
|
|
1348
|
+
/* @__PURE__ */ jsx6(
|
|
1349
|
+
"button",
|
|
1350
|
+
{
|
|
1351
|
+
type: "button",
|
|
1352
|
+
className: itemClassName,
|
|
1353
|
+
disabled: !current,
|
|
1354
|
+
onMouseDown: keepSelection,
|
|
1355
|
+
onClick: () => {
|
|
1356
|
+
if (current && styles.updateFromSelection(current.id)) {
|
|
1357
|
+
onChange?.({ type: "update", id: current.id });
|
|
1358
|
+
}
|
|
1359
|
+
close();
|
|
1360
|
+
},
|
|
1361
|
+
children: current ? `Update ${current.name} to match selection` : "Update to match selection"
|
|
1362
|
+
}
|
|
1363
|
+
),
|
|
1364
|
+
creating ? /* @__PURE__ */ jsxs5("form", { className: "flex items-center gap-1", onSubmit: create, children: [
|
|
1365
|
+
/* @__PURE__ */ jsx6(
|
|
1366
|
+
"input",
|
|
1367
|
+
{
|
|
1368
|
+
"aria-label": "New style name",
|
|
1369
|
+
className: "w-32 rounded border border-border bg-background px-1 py-0.5 text-xs",
|
|
1370
|
+
value: name,
|
|
1371
|
+
autoFocus: true,
|
|
1372
|
+
onChange: (event) => setName(event.target.value)
|
|
1373
|
+
}
|
|
1374
|
+
),
|
|
1375
|
+
/* @__PURE__ */ jsx6("button", { type: "submit", className: itemClassName, disabled: !name.trim(), children: "Create" })
|
|
1376
|
+
] }) : /* @__PURE__ */ jsx6(
|
|
1377
|
+
"button",
|
|
1378
|
+
{
|
|
1379
|
+
type: "button",
|
|
1380
|
+
className: itemClassName,
|
|
1381
|
+
disabled: !editor || !styles.registry,
|
|
1382
|
+
onMouseDown: keepSelection,
|
|
1383
|
+
onClick: () => setCreating(true),
|
|
1384
|
+
children: "New style from selection"
|
|
1385
|
+
}
|
|
1386
|
+
)
|
|
1387
|
+
] })
|
|
1388
|
+
]
|
|
1389
|
+
}
|
|
1390
|
+
)
|
|
1391
|
+
] });
|
|
1392
|
+
};
|
|
1393
|
+
|
|
908
1394
|
// src/index.ts
|
|
909
1395
|
import {
|
|
910
1396
|
DirtyTracker as DirtyTracker2,
|
|
@@ -917,10 +1403,10 @@ import {
|
|
|
917
1403
|
} from "@pixerate/editor";
|
|
918
1404
|
|
|
919
1405
|
// src/slots.tsx
|
|
920
|
-
import { createContext, useContext, useMemo as
|
|
921
|
-
import { jsx as
|
|
1406
|
+
import { createContext, useContext, useMemo as useMemo9 } from "react";
|
|
1407
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
922
1408
|
var defaultSlots = {
|
|
923
|
-
Button: (props) => /* @__PURE__ */
|
|
1409
|
+
Button: (props) => /* @__PURE__ */ jsx7(
|
|
924
1410
|
"button",
|
|
925
1411
|
{
|
|
926
1412
|
type: "button",
|
|
@@ -930,26 +1416,26 @@ var defaultSlots = {
|
|
|
930
1416
|
children: props.children
|
|
931
1417
|
}
|
|
932
1418
|
),
|
|
933
|
-
Tooltip: (props) => /* @__PURE__ */
|
|
934
|
-
NodeHeader: (props) => /* @__PURE__ */
|
|
935
|
-
/* @__PURE__ */
|
|
1419
|
+
Tooltip: (props) => /* @__PURE__ */ jsx7("div", { className: `pixerate-tooltip-container ${props.className || ""}`, title: String(props.content), children: props.children }),
|
|
1420
|
+
NodeHeader: (props) => /* @__PURE__ */ jsxs6("div", { className: `pixerate-node-header flex items-center justify-between ${props.className || ""}`, children: [
|
|
1421
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
936
1422
|
props.icon,
|
|
937
|
-
/* @__PURE__ */
|
|
1423
|
+
/* @__PURE__ */ jsx7("span", { className: "font-semibold", children: props.title })
|
|
938
1424
|
] }),
|
|
939
|
-
props.onClose && /* @__PURE__ */
|
|
1425
|
+
props.onClose && /* @__PURE__ */ jsx7("button", { type: "button", onClick: props.onClose, className: "opacity-70 hover:opacity-100", children: "\xD7" })
|
|
940
1426
|
] })
|
|
941
1427
|
};
|
|
942
1428
|
var EditorSlotsContext = createContext(defaultSlots);
|
|
943
1429
|
function EditorSlotsProvider({ slots, children }) {
|
|
944
|
-
const mergedSlots =
|
|
945
|
-
return /* @__PURE__ */
|
|
1430
|
+
const mergedSlots = useMemo9(() => ({ ...defaultSlots, ...slots }), [slots]);
|
|
1431
|
+
return /* @__PURE__ */ jsx7(EditorSlotsContext.Provider, { value: mergedSlots, children });
|
|
946
1432
|
}
|
|
947
1433
|
function useEditorSlots() {
|
|
948
1434
|
return useContext(EditorSlotsContext);
|
|
949
1435
|
}
|
|
950
1436
|
|
|
951
1437
|
// src/review/useReview.ts
|
|
952
|
-
import { useCallback as
|
|
1438
|
+
import { useCallback as useCallback6, useMemo as useMemo10, useSyncExternalStore as useSyncExternalStore6 } from "react";
|
|
953
1439
|
import {
|
|
954
1440
|
getCommentStore,
|
|
955
1441
|
getTrackChangesStore
|
|
@@ -971,23 +1457,23 @@ function isCommentStore(value) {
|
|
|
971
1457
|
}
|
|
972
1458
|
function useComments(source) {
|
|
973
1459
|
const store = isCommentStore(source) ? source : getCommentStore(source);
|
|
974
|
-
const subscribe =
|
|
1460
|
+
const subscribe = useCallback6(
|
|
975
1461
|
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
976
1462
|
[store]
|
|
977
1463
|
);
|
|
978
1464
|
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
|
|
979
|
-
const snapshot =
|
|
980
|
-
return
|
|
1465
|
+
const snapshot = useSyncExternalStore6(subscribe, getSnapshot, getSnapshot);
|
|
1466
|
+
return useMemo10(() => ({ ...snapshot, store }), [snapshot, store]);
|
|
981
1467
|
}
|
|
982
1468
|
function useTrackChanges(editor) {
|
|
983
1469
|
const store = getTrackChangesStore(editor ?? null);
|
|
984
|
-
const subscribe =
|
|
1470
|
+
const subscribe = useCallback6(
|
|
985
1471
|
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
986
1472
|
[store]
|
|
987
1473
|
);
|
|
988
1474
|
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
|
|
989
|
-
const snapshot =
|
|
990
|
-
return
|
|
1475
|
+
const snapshot = useSyncExternalStore6(subscribe, getSnapshot, getSnapshot);
|
|
1476
|
+
return useMemo10(() => {
|
|
991
1477
|
const run = (fn) => () => {
|
|
992
1478
|
if (editor && !editor.isDestroyed) fn(editor);
|
|
993
1479
|
};
|
|
@@ -1001,18 +1487,21 @@ function useTrackChanges(editor) {
|
|
|
1001
1487
|
acceptAll: run((e) => e.commands.acceptAllChanges()),
|
|
1002
1488
|
rejectAll: run((e) => e.commands.rejectAllChanges()),
|
|
1003
1489
|
next: run((e) => e.chain().focus().selectNextChange().run()),
|
|
1004
|
-
previous: run((e) => e.chain().focus().selectPreviousChange().run())
|
|
1490
|
+
previous: run((e) => e.chain().focus().selectPreviousChange().run()),
|
|
1491
|
+
select: (id) => run((e) => e.chain().focus().selectChange(id).run())(),
|
|
1492
|
+
acceptMove: (id) => run((e) => e.commands.acceptMove(id))(),
|
|
1493
|
+
rejectMove: (id) => run((e) => e.commands.rejectMove(id))()
|
|
1005
1494
|
};
|
|
1006
1495
|
}, [snapshot, editor]);
|
|
1007
1496
|
}
|
|
1008
1497
|
|
|
1009
1498
|
// src/review/CommentsPanel.tsx
|
|
1010
|
-
import { useState as
|
|
1499
|
+
import { useState as useState9 } from "react";
|
|
1011
1500
|
import {
|
|
1012
1501
|
formatReviewTime,
|
|
1013
1502
|
getCommentAuthor
|
|
1014
1503
|
} from "@pixerate/editor";
|
|
1015
|
-
import { jsx as
|
|
1504
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1016
1505
|
var buttonClass = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
|
|
1017
1506
|
var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
|
|
1018
1507
|
var textareaClass = "w-full resize-y rounded-md border border-input bg-background p-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary";
|
|
@@ -1026,18 +1515,18 @@ var CommentsPanel = ({
|
|
|
1026
1515
|
emptyMessage = "No comments yet. Select text and add a comment."
|
|
1027
1516
|
}) => {
|
|
1028
1517
|
const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
|
|
1029
|
-
const [showResolved, setShowResolved] =
|
|
1518
|
+
const [showResolved, setShowResolved] = useState9(showResolvedInitial);
|
|
1030
1519
|
const author = authorProp ?? getCommentAuthor(editor) ?? { id: "anonymous", name: "Anonymous" };
|
|
1031
1520
|
const visible = threads.filter((t) => showResolved || !t.resolved);
|
|
1032
1521
|
const resolvedCount = threads.filter((t) => t.resolved).length;
|
|
1033
|
-
return /* @__PURE__ */
|
|
1034
|
-
/* @__PURE__ */
|
|
1035
|
-
/* @__PURE__ */
|
|
1522
|
+
return /* @__PURE__ */ jsxs7("aside", { className, "aria-label": "Comments", children: [
|
|
1523
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1524
|
+
/* @__PURE__ */ jsxs7("span", { className: "text-xs font-medium text-muted-foreground", children: [
|
|
1036
1525
|
threads.length - resolvedCount,
|
|
1037
1526
|
" open",
|
|
1038
1527
|
resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
|
|
1039
1528
|
] }),
|
|
1040
|
-
resolvedCount > 0 && /* @__PURE__ */
|
|
1529
|
+
resolvedCount > 0 && /* @__PURE__ */ jsx8(
|
|
1041
1530
|
"button",
|
|
1042
1531
|
{
|
|
1043
1532
|
type: "button",
|
|
@@ -1048,7 +1537,7 @@ var CommentsPanel = ({
|
|
|
1048
1537
|
}
|
|
1049
1538
|
)
|
|
1050
1539
|
] }),
|
|
1051
|
-
visible.length === 0 ? /* @__PURE__ */
|
|
1540
|
+
visible.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ jsx8("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ jsx8(
|
|
1052
1541
|
CommentThreadCard,
|
|
1053
1542
|
{
|
|
1054
1543
|
thread,
|
|
@@ -1070,7 +1559,7 @@ var CommentThreadCard = ({
|
|
|
1070
1559
|
author,
|
|
1071
1560
|
formatTime
|
|
1072
1561
|
}) => {
|
|
1073
|
-
const [draft, setDraft] =
|
|
1562
|
+
const [draft, setDraft] = useState9("");
|
|
1074
1563
|
const isDraft = thread.body === "";
|
|
1075
1564
|
const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
|
|
1076
1565
|
const live = editor && !editor.isDestroyed ? editor : null;
|
|
@@ -1096,7 +1585,7 @@ var CommentThreadCard = ({
|
|
|
1096
1585
|
setDraft("");
|
|
1097
1586
|
};
|
|
1098
1587
|
const stop = (e) => e.stopPropagation();
|
|
1099
|
-
return /* @__PURE__ */
|
|
1588
|
+
return /* @__PURE__ */ jsxs7(
|
|
1100
1589
|
"li",
|
|
1101
1590
|
{
|
|
1102
1591
|
className: `flex flex-col gap-2 rounded-md border bg-background p-3 cursor-pointer ${active ? "border-primary ring-1 ring-primary" : "border-border"} ${thread.resolved ? "opacity-70" : ""}`,
|
|
@@ -1112,24 +1601,24 @@ var CommentThreadCard = ({
|
|
|
1112
1601
|
}
|
|
1113
1602
|
},
|
|
1114
1603
|
children: [
|
|
1115
|
-
/* @__PURE__ */
|
|
1116
|
-
/* @__PURE__ */
|
|
1117
|
-
/* @__PURE__ */
|
|
1604
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
1605
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: thread.author.name }),
|
|
1606
|
+
/* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
|
|
1118
1607
|
] }),
|
|
1119
|
-
quote && /* @__PURE__ */
|
|
1120
|
-
thread.orphaned && /* @__PURE__ */
|
|
1121
|
-
thread.resolved && /* @__PURE__ */
|
|
1122
|
-
!isDraft && /* @__PURE__ */
|
|
1123
|
-
thread.replies.length > 0 && /* @__PURE__ */
|
|
1124
|
-
/* @__PURE__ */
|
|
1125
|
-
/* @__PURE__ */
|
|
1608
|
+
quote && /* @__PURE__ */ jsx8("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
|
|
1609
|
+
thread.orphaned && /* @__PURE__ */ jsx8("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
|
|
1610
|
+
thread.resolved && /* @__PURE__ */ jsx8("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
|
|
1611
|
+
!isDraft && /* @__PURE__ */ jsx8("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
|
|
1612
|
+
thread.replies.length > 0 && /* @__PURE__ */ jsx8("ul", { className: "flex flex-col gap-2 border-l border-border pl-3", role: "list", children: thread.replies.map((reply) => /* @__PURE__ */ jsxs7("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
|
|
1613
|
+
/* @__PURE__ */ jsxs7("span", { className: "text-xs", children: [
|
|
1614
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: reply.author.name }),
|
|
1126
1615
|
" ",
|
|
1127
|
-
/* @__PURE__ */
|
|
1616
|
+
/* @__PURE__ */ jsx8("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
|
|
1128
1617
|
] }),
|
|
1129
|
-
/* @__PURE__ */
|
|
1618
|
+
/* @__PURE__ */ jsx8("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
|
|
1130
1619
|
] }, reply.id)) }),
|
|
1131
|
-
(active || isDraft) && !thread.resolved && /* @__PURE__ */
|
|
1132
|
-
/* @__PURE__ */
|
|
1620
|
+
(active || isDraft) && !thread.resolved && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1", onClick: stop, children: [
|
|
1621
|
+
/* @__PURE__ */ jsx8(
|
|
1133
1622
|
"textarea",
|
|
1134
1623
|
{
|
|
1135
1624
|
className: textareaClass,
|
|
@@ -1147,9 +1636,9 @@ var CommentThreadCard = ({
|
|
|
1147
1636
|
}
|
|
1148
1637
|
}
|
|
1149
1638
|
),
|
|
1150
|
-
/* @__PURE__ */
|
|
1151
|
-
isDraft && /* @__PURE__ */
|
|
1152
|
-
/* @__PURE__ */
|
|
1639
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex justify-end gap-1", children: [
|
|
1640
|
+
isDraft && /* @__PURE__ */ jsx8("button", { type: "button", className: buttonClass, onClick: remove, children: "Cancel" }),
|
|
1641
|
+
/* @__PURE__ */ jsx8(
|
|
1153
1642
|
"button",
|
|
1154
1643
|
{
|
|
1155
1644
|
type: "button",
|
|
@@ -1161,9 +1650,9 @@ var CommentThreadCard = ({
|
|
|
1161
1650
|
)
|
|
1162
1651
|
] })
|
|
1163
1652
|
] }),
|
|
1164
|
-
!isDraft && /* @__PURE__ */
|
|
1165
|
-
/* @__PURE__ */
|
|
1166
|
-
/* @__PURE__ */
|
|
1653
|
+
!isDraft && /* @__PURE__ */ jsxs7("div", { className: "flex justify-end gap-1", onClick: stop, children: [
|
|
1654
|
+
/* @__PURE__ */ jsx8("button", { type: "button", className: buttonClass, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
|
|
1655
|
+
/* @__PURE__ */ jsx8(
|
|
1167
1656
|
"button",
|
|
1168
1657
|
{
|
|
1169
1658
|
type: "button",
|
|
@@ -1179,7 +1668,7 @@ var CommentThreadCard = ({
|
|
|
1179
1668
|
};
|
|
1180
1669
|
|
|
1181
1670
|
// src/review/ReviewToolbar.tsx
|
|
1182
|
-
import { jsx as
|
|
1671
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1183
1672
|
var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
|
|
1184
1673
|
var buttonClass2 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
1185
1674
|
var ReviewToolbar = ({
|
|
@@ -1192,8 +1681,8 @@ var ReviewToolbar = ({
|
|
|
1192
1681
|
const count = review.changes.length;
|
|
1193
1682
|
const current = review.currentChange;
|
|
1194
1683
|
const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
|
|
1195
|
-
return /* @__PURE__ */
|
|
1196
|
-
/* @__PURE__ */
|
|
1684
|
+
return /* @__PURE__ */ jsxs8("div", { className, role: "toolbar", "aria-label": "Review", children: [
|
|
1685
|
+
/* @__PURE__ */ jsx9(
|
|
1197
1686
|
"button",
|
|
1198
1687
|
{
|
|
1199
1688
|
type: "button",
|
|
@@ -1204,8 +1693,8 @@ var ReviewToolbar = ({
|
|
|
1204
1693
|
children: review.enabled ? "Tracking on" : "Track changes"
|
|
1205
1694
|
}
|
|
1206
1695
|
),
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */
|
|
1696
|
+
/* @__PURE__ */ jsx9("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
1697
|
+
/* @__PURE__ */ jsx9(
|
|
1209
1698
|
"button",
|
|
1210
1699
|
{
|
|
1211
1700
|
type: "button",
|
|
@@ -1216,8 +1705,8 @@ var ReviewToolbar = ({
|
|
|
1216
1705
|
children: "\u2039"
|
|
1217
1706
|
}
|
|
1218
1707
|
),
|
|
1219
|
-
/* @__PURE__ */
|
|
1220
|
-
/* @__PURE__ */
|
|
1708
|
+
/* @__PURE__ */ jsx9("span", { className: "min-w-[4rem] text-center text-xs text-muted-foreground", "aria-live": "polite", children: count === 0 ? "No changes" : current ? `${index} of ${count}` : `${count} changes` }),
|
|
1709
|
+
/* @__PURE__ */ jsx9(
|
|
1221
1710
|
"button",
|
|
1222
1711
|
{
|
|
1223
1712
|
type: "button",
|
|
@@ -1228,7 +1717,7 @@ var ReviewToolbar = ({
|
|
|
1228
1717
|
children: "\u203A"
|
|
1229
1718
|
}
|
|
1230
1719
|
),
|
|
1231
|
-
showDescription && current && /* @__PURE__ */
|
|
1720
|
+
showDescription && current && /* @__PURE__ */ jsxs8(
|
|
1232
1721
|
"span",
|
|
1233
1722
|
{
|
|
1234
1723
|
className: descriptionClassName,
|
|
@@ -1240,8 +1729,8 @@ var ReviewToolbar = ({
|
|
|
1240
1729
|
]
|
|
1241
1730
|
}
|
|
1242
1731
|
),
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
/* @__PURE__ */
|
|
1732
|
+
/* @__PURE__ */ jsx9("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
1733
|
+
/* @__PURE__ */ jsx9(
|
|
1245
1734
|
"button",
|
|
1246
1735
|
{
|
|
1247
1736
|
type: "button",
|
|
@@ -1251,7 +1740,7 @@ var ReviewToolbar = ({
|
|
|
1251
1740
|
children: "Accept"
|
|
1252
1741
|
}
|
|
1253
1742
|
),
|
|
1254
|
-
/* @__PURE__ */
|
|
1743
|
+
/* @__PURE__ */ jsx9(
|
|
1255
1744
|
"button",
|
|
1256
1745
|
{
|
|
1257
1746
|
type: "button",
|
|
@@ -1261,18 +1750,18 @@ var ReviewToolbar = ({
|
|
|
1261
1750
|
children: "Reject"
|
|
1262
1751
|
}
|
|
1263
1752
|
),
|
|
1264
|
-
/* @__PURE__ */
|
|
1265
|
-
/* @__PURE__ */
|
|
1753
|
+
/* @__PURE__ */ jsx9("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
|
|
1754
|
+
/* @__PURE__ */ jsx9("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
|
|
1266
1755
|
] });
|
|
1267
1756
|
};
|
|
1268
1757
|
|
|
1269
1758
|
// src/review/CommentButton.tsx
|
|
1270
|
-
import { jsx as
|
|
1759
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1271
1760
|
var CommentButton = ({
|
|
1272
1761
|
editor,
|
|
1273
1762
|
className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
|
|
1274
1763
|
children = "Comment"
|
|
1275
|
-
}) => /* @__PURE__ */
|
|
1764
|
+
}) => /* @__PURE__ */ jsx10(
|
|
1276
1765
|
"button",
|
|
1277
1766
|
{
|
|
1278
1767
|
type: "button",
|
|
@@ -1282,43 +1771,345 @@ var CommentButton = ({
|
|
|
1282
1771
|
children
|
|
1283
1772
|
}
|
|
1284
1773
|
);
|
|
1774
|
+
|
|
1775
|
+
// src/review/useDocumentCompare.ts
|
|
1776
|
+
import { useCallback as useCallback7, useMemo as useMemo11, useRef as useRef8, useState as useState10 } from "react";
|
|
1777
|
+
import {
|
|
1778
|
+
applyDocumentComparison
|
|
1779
|
+
} from "@pixerate/editor";
|
|
1780
|
+
function useDocumentCompare(editor, options) {
|
|
1781
|
+
const [summary, setSummary] = useState10(null);
|
|
1782
|
+
const defaults = useRef8(options);
|
|
1783
|
+
defaults.current = options;
|
|
1784
|
+
const compare = useCallback7(
|
|
1785
|
+
(original, revised, overrides) => {
|
|
1786
|
+
if (!editor || editor.isDestroyed) return null;
|
|
1787
|
+
const result = applyDocumentComparison(editor, original, revised, {
|
|
1788
|
+
...defaults.current,
|
|
1789
|
+
...overrides
|
|
1790
|
+
});
|
|
1791
|
+
setSummary(result.summary);
|
|
1792
|
+
return result.summary;
|
|
1793
|
+
},
|
|
1794
|
+
[editor]
|
|
1795
|
+
);
|
|
1796
|
+
const clear = useCallback7(() => setSummary(null), []);
|
|
1797
|
+
return useMemo11(() => ({ summary, compare, clear }), [summary, compare, clear]);
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
// src/review/TrackedChangesList.tsx
|
|
1801
|
+
import { trackedChangeLabel } from "@pixerate/editor";
|
|
1802
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1803
|
+
var buttonClass3 = "rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
|
|
1804
|
+
var TrackedChangesList = ({
|
|
1805
|
+
editor,
|
|
1806
|
+
className = "flex flex-col gap-1 text-sm",
|
|
1807
|
+
itemClassName = "flex items-center gap-2 rounded px-2 py-1 hover:bg-muted/50",
|
|
1808
|
+
activeItemClassName = "bg-primary/10",
|
|
1809
|
+
emptyState = "No tracked changes."
|
|
1810
|
+
}) => {
|
|
1811
|
+
const review = useTrackChanges(editor);
|
|
1812
|
+
if (review.changes.length === 0) {
|
|
1813
|
+
return /* @__PURE__ */ jsx11("div", { className, "data-tracked-changes-list": "", children: /* @__PURE__ */ jsx11("div", { className: "pixerate-changes-empty text-xs text-muted-foreground", children: emptyState }) });
|
|
1814
|
+
}
|
|
1815
|
+
return /* @__PURE__ */ jsx11("ul", { className, role: "list", "aria-label": "Tracked changes", "data-tracked-changes-list": "", children: review.changes.map((change) => {
|
|
1816
|
+
const active = change.id === review.currentChangeId;
|
|
1817
|
+
return /* @__PURE__ */ jsxs9(
|
|
1818
|
+
"li",
|
|
1819
|
+
{
|
|
1820
|
+
className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
|
|
1821
|
+
"data-change-type": change.type,
|
|
1822
|
+
"data-change-id": change.id,
|
|
1823
|
+
children: [
|
|
1824
|
+
/* @__PURE__ */ jsxs9(
|
|
1825
|
+
"button",
|
|
1826
|
+
{
|
|
1827
|
+
type: "button",
|
|
1828
|
+
className: "min-w-0 flex-1 truncate text-left text-xs",
|
|
1829
|
+
title: `${change.author.name}: ${change.description}`,
|
|
1830
|
+
onClick: () => review.select(change.id),
|
|
1831
|
+
children: [
|
|
1832
|
+
/* @__PURE__ */ jsx11("span", { className: "font-medium", children: trackedChangeLabel(change) }),
|
|
1833
|
+
change.author.name ? ` \xB7 ${change.author.name}` : "",
|
|
1834
|
+
/* @__PURE__ */ jsx11("span", { className: "block truncate text-muted-foreground", children: change.description })
|
|
1835
|
+
]
|
|
1836
|
+
}
|
|
1837
|
+
),
|
|
1838
|
+
/* @__PURE__ */ jsx11("button", { type: "button", className: buttonClass3, onClick: () => review.accept(change.id), children: "Accept" }),
|
|
1839
|
+
/* @__PURE__ */ jsx11("button", { type: "button", className: buttonClass3, onClick: () => review.reject(change.id), children: "Reject" })
|
|
1840
|
+
]
|
|
1841
|
+
},
|
|
1842
|
+
`${change.type}:${change.id}`
|
|
1843
|
+
);
|
|
1844
|
+
}) });
|
|
1845
|
+
};
|
|
1846
|
+
|
|
1847
|
+
// src/find-replace/useFindReplace.ts
|
|
1848
|
+
import { useCallback as useCallback8, useMemo as useMemo12, useSyncExternalStore as useSyncExternalStore7 } from "react";
|
|
1849
|
+
import {
|
|
1850
|
+
EMPTY_FIND_REPLACE_SNAPSHOT,
|
|
1851
|
+
getFindReplaceStore
|
|
1852
|
+
} from "@pixerate/editor";
|
|
1853
|
+
var noopUnsubscribe2 = () => {
|
|
1854
|
+
};
|
|
1855
|
+
function useFindReplace(editor) {
|
|
1856
|
+
const store = getFindReplaceStore(editor ?? null);
|
|
1857
|
+
const subscribe = useCallback8(
|
|
1858
|
+
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
|
|
1859
|
+
[store]
|
|
1860
|
+
);
|
|
1861
|
+
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_FIND_REPLACE_SNAPSHOT;
|
|
1862
|
+
const snapshot = useSyncExternalStore7(subscribe, getSnapshot, getSnapshot);
|
|
1863
|
+
return useMemo12(() => {
|
|
1864
|
+
const run = (fn) => {
|
|
1865
|
+
if (editor && !editor.isDestroyed && store) fn(editor);
|
|
1866
|
+
};
|
|
1867
|
+
return {
|
|
1868
|
+
...snapshot,
|
|
1869
|
+
available: !!store,
|
|
1870
|
+
matchCount: snapshot.matches.length,
|
|
1871
|
+
show: (mode = "find") => run((e) => e.commands.openFindReplace({ mode })),
|
|
1872
|
+
close: () => run((e) => e.commands.closeFindReplace()),
|
|
1873
|
+
setQuery: (query) => run((e) => e.commands.setSearch({ query })),
|
|
1874
|
+
setReplacement: (replacement) => run((e) => e.commands.setSearch({ replacement })),
|
|
1875
|
+
setOptions: (options) => run((e) => e.commands.setSearch({ options })),
|
|
1876
|
+
toggleOption: (option) => run((e) => e.commands.setSearch({ options: { [option]: !snapshot.options[option] } })),
|
|
1877
|
+
next: () => run((e) => e.commands.findNext()),
|
|
1878
|
+
previous: () => run((e) => e.commands.findPrevious()),
|
|
1879
|
+
replace: () => run((e) => e.commands.replaceCurrent()),
|
|
1880
|
+
replaceAll: () => run((e) => e.commands.replaceAll()),
|
|
1881
|
+
clear: () => run((e) => e.commands.clearSearch())
|
|
1882
|
+
};
|
|
1883
|
+
}, [snapshot, editor, store]);
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
// src/find-replace/FindReplaceBar.tsx
|
|
1887
|
+
import { useEffect as useEffect8, useRef as useRef9, useState as useState11 } from "react";
|
|
1888
|
+
import { FIND_OPTION_TOGGLES, formatFindStatus } from "@pixerate/editor";
|
|
1889
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1890
|
+
var inputClass = "min-w-0 flex-1 rounded border border-input bg-background px-2 py-1 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-ring";
|
|
1891
|
+
var buttonClass4 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
1892
|
+
var toggleClass = (on) => `${buttonClass4} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
|
|
1893
|
+
var isMod = (e) => e.metaKey || e.ctrlKey;
|
|
1894
|
+
var FindReplaceBar = ({
|
|
1895
|
+
editor,
|
|
1896
|
+
className = "flex flex-col gap-1 rounded-md border border-border bg-background p-1 text-sm shadow-sm",
|
|
1897
|
+
alwaysOpen = false,
|
|
1898
|
+
showMoreOptions = true,
|
|
1899
|
+
onClose
|
|
1900
|
+
}) => {
|
|
1901
|
+
const find = useFindReplace(editor);
|
|
1902
|
+
const findInput = useRef9(null);
|
|
1903
|
+
const [moreOpen, setMoreOpen] = useState11(false);
|
|
1904
|
+
const visible = find.available && (alwaysOpen || find.open);
|
|
1905
|
+
useEffect8(() => {
|
|
1906
|
+
if (!visible || find.focusRequest === 0) return;
|
|
1907
|
+
findInput.current?.focus();
|
|
1908
|
+
findInput.current?.select();
|
|
1909
|
+
}, [visible, find.focusRequest]);
|
|
1910
|
+
if (!visible) return null;
|
|
1911
|
+
const showReplace = find.mode === "replace";
|
|
1912
|
+
const status = formatFindStatus(find);
|
|
1913
|
+
const hasMatches = find.matchCount > 0;
|
|
1914
|
+
const close = () => {
|
|
1915
|
+
find.close();
|
|
1916
|
+
editor?.commands.focus();
|
|
1917
|
+
onClose?.();
|
|
1918
|
+
};
|
|
1919
|
+
const onBarKeyDown = (e) => {
|
|
1920
|
+
if (e.key === "Escape") {
|
|
1921
|
+
e.preventDefault();
|
|
1922
|
+
close();
|
|
1923
|
+
} else if (isMod(e) && (e.key === "f" || e.key === "F")) {
|
|
1924
|
+
e.preventDefault();
|
|
1925
|
+
find.show("find");
|
|
1926
|
+
} else if (isMod(e) && (e.key === "h" || e.key === "H")) {
|
|
1927
|
+
e.preventDefault();
|
|
1928
|
+
find.show("replace");
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
const onFindKeyDown = (e) => {
|
|
1932
|
+
if (e.key !== "Enter") return;
|
|
1933
|
+
e.preventDefault();
|
|
1934
|
+
if (e.shiftKey) find.previous();
|
|
1935
|
+
else find.next();
|
|
1936
|
+
};
|
|
1937
|
+
const onReplaceKeyDown = (e) => {
|
|
1938
|
+
if (e.key !== "Enter") return;
|
|
1939
|
+
e.preventDefault();
|
|
1940
|
+
if (isMod(e)) find.replaceAll();
|
|
1941
|
+
else find.replace();
|
|
1942
|
+
};
|
|
1943
|
+
return /* @__PURE__ */ jsxs10("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
|
|
1944
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
|
|
1945
|
+
/* @__PURE__ */ jsx12(
|
|
1946
|
+
"button",
|
|
1947
|
+
{
|
|
1948
|
+
type: "button",
|
|
1949
|
+
className: buttonClass4,
|
|
1950
|
+
"aria-label": "Toggle replace",
|
|
1951
|
+
"aria-expanded": showReplace,
|
|
1952
|
+
onClick: () => find.show(showReplace ? "find" : "replace"),
|
|
1953
|
+
children: showReplace ? "\u25BE" : "\u25B8"
|
|
1954
|
+
}
|
|
1955
|
+
),
|
|
1956
|
+
/* @__PURE__ */ jsx12(
|
|
1957
|
+
"input",
|
|
1958
|
+
{
|
|
1959
|
+
ref: findInput,
|
|
1960
|
+
type: "text",
|
|
1961
|
+
className: inputClass,
|
|
1962
|
+
placeholder: "Find",
|
|
1963
|
+
"aria-label": "Find",
|
|
1964
|
+
"aria-invalid": !!find.error,
|
|
1965
|
+
value: find.query,
|
|
1966
|
+
onChange: (e) => find.setQuery(e.target.value),
|
|
1967
|
+
onKeyDown: onFindKeyDown
|
|
1968
|
+
}
|
|
1969
|
+
),
|
|
1970
|
+
FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ jsx12(
|
|
1971
|
+
"button",
|
|
1972
|
+
{
|
|
1973
|
+
type: "button",
|
|
1974
|
+
className: toggleClass(!!find.options[t.key]),
|
|
1975
|
+
"aria-label": t.label,
|
|
1976
|
+
title: t.label,
|
|
1977
|
+
"aria-pressed": !!find.options[t.key],
|
|
1978
|
+
onClick: () => find.toggleOption(t.key),
|
|
1979
|
+
children: t.short
|
|
1980
|
+
},
|
|
1981
|
+
t.key
|
|
1982
|
+
)),
|
|
1983
|
+
/* @__PURE__ */ jsx12(
|
|
1984
|
+
"span",
|
|
1985
|
+
{
|
|
1986
|
+
className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
|
|
1987
|
+
"aria-live": "polite",
|
|
1988
|
+
role: find.error ? "alert" : "status",
|
|
1989
|
+
"data-testid": "find-status",
|
|
1990
|
+
children: status
|
|
1991
|
+
}
|
|
1992
|
+
),
|
|
1993
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass4, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
|
|
1994
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass4, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
|
|
1995
|
+
showMoreOptions && /* @__PURE__ */ jsx12(
|
|
1996
|
+
"button",
|
|
1997
|
+
{
|
|
1998
|
+
type: "button",
|
|
1999
|
+
className: buttonClass4,
|
|
2000
|
+
"aria-label": "More options",
|
|
2001
|
+
"aria-expanded": moreOpen,
|
|
2002
|
+
onClick: () => setMoreOpen((v) => !v),
|
|
2003
|
+
children: "\u2026"
|
|
2004
|
+
}
|
|
2005
|
+
),
|
|
2006
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass4, "aria-label": "Close find", onClick: close, children: "\xD7" })
|
|
2007
|
+
] }),
|
|
2008
|
+
showReplace && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 pl-7", children: [
|
|
2009
|
+
/* @__PURE__ */ jsx12(
|
|
2010
|
+
"input",
|
|
2011
|
+
{
|
|
2012
|
+
type: "text",
|
|
2013
|
+
className: inputClass,
|
|
2014
|
+
placeholder: "Replace",
|
|
2015
|
+
"aria-label": "Replace",
|
|
2016
|
+
value: find.replacement,
|
|
2017
|
+
onChange: (e) => find.setReplacement(e.target.value),
|
|
2018
|
+
onKeyDown: onReplaceKeyDown
|
|
2019
|
+
}
|
|
2020
|
+
),
|
|
2021
|
+
/* @__PURE__ */ jsx12(
|
|
2022
|
+
"button",
|
|
2023
|
+
{
|
|
2024
|
+
type: "button",
|
|
2025
|
+
className: buttonClass4,
|
|
2026
|
+
disabled: !hasMatches || find.currentIndex < 0,
|
|
2027
|
+
onClick: find.replace,
|
|
2028
|
+
children: "Replace"
|
|
2029
|
+
}
|
|
2030
|
+
),
|
|
2031
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: buttonClass4, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
|
|
2032
|
+
find.lastReplaceCount !== null && /* @__PURE__ */ jsx12("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
|
|
2033
|
+
] }),
|
|
2034
|
+
showMoreOptions && moreOpen && /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pl-7 text-xs text-muted-foreground", children: FIND_OPTION_TOGGLES.filter((t) => t.advanced).map((t) => /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-1", children: [
|
|
2035
|
+
/* @__PURE__ */ jsx12(
|
|
2036
|
+
"input",
|
|
2037
|
+
{
|
|
2038
|
+
type: "checkbox",
|
|
2039
|
+
checked: !!find.options[t.key],
|
|
2040
|
+
onChange: () => find.toggleOption(t.key)
|
|
2041
|
+
}
|
|
2042
|
+
),
|
|
2043
|
+
t.label
|
|
2044
|
+
] }, t.key)) })
|
|
2045
|
+
] });
|
|
2046
|
+
};
|
|
1285
2047
|
export {
|
|
2048
|
+
AdjustmentLayersPanel,
|
|
2049
|
+
AssetMentionChips,
|
|
1286
2050
|
BubbleMenu,
|
|
1287
2051
|
CommandPalette,
|
|
1288
2052
|
CommentButton,
|
|
1289
2053
|
CommentsPanel,
|
|
2054
|
+
ControlSlider,
|
|
2055
|
+
CurvesEditor,
|
|
1290
2056
|
DirtyTracker2 as DirtyTracker,
|
|
1291
2057
|
EditorContent,
|
|
1292
2058
|
EditorSlotsProvider,
|
|
2059
|
+
FindReplaceBar,
|
|
1293
2060
|
FormulaHints,
|
|
2061
|
+
GenerationHistory,
|
|
2062
|
+
GenerationSettings,
|
|
2063
|
+
Histogram,
|
|
1294
2064
|
HistoryManager2 as HistoryManager,
|
|
1295
2065
|
ImageEditor,
|
|
2066
|
+
JobProgress,
|
|
2067
|
+
MergePreview,
|
|
2068
|
+
NameManager,
|
|
1296
2069
|
OutlinePanel,
|
|
2070
|
+
RecoveryPrompt,
|
|
2071
|
+
RefineEdgePanel,
|
|
1297
2072
|
ReviewToolbar,
|
|
2073
|
+
SelectionOptionsBar,
|
|
2074
|
+
SheetTabs,
|
|
2075
|
+
SpreadsheetConditionalFormatPanel,
|
|
1298
2076
|
SpreadsheetContextMenu,
|
|
2077
|
+
SpreadsheetDataValidationPanel,
|
|
1299
2078
|
SpreadsheetEditor,
|
|
1300
2079
|
SpreadsheetGroupRow,
|
|
2080
|
+
SpreadsheetValidationDialog,
|
|
2081
|
+
StylesGallery,
|
|
1301
2082
|
TemplateRenderer,
|
|
2083
|
+
TrackedChangesList,
|
|
1302
2084
|
VariableForm,
|
|
1303
2085
|
bindDirtyToHistory2 as bindDirtyToHistory,
|
|
1304
2086
|
createDirtyTracker,
|
|
1305
2087
|
createHistoryManager2 as createHistoryManager,
|
|
1306
2088
|
defaultIsEqual,
|
|
1307
2089
|
useAgentToolProvider,
|
|
2090
|
+
useAutosave,
|
|
1308
2091
|
useCommandPalette,
|
|
1309
2092
|
useCommandShortcuts,
|
|
1310
2093
|
useComments,
|
|
1311
2094
|
useDismissGuard,
|
|
2095
|
+
useDocumentCompare,
|
|
1312
2096
|
useEditor2 as useEditor,
|
|
1313
2097
|
useEditorSlots,
|
|
1314
2098
|
useFileImport,
|
|
1315
2099
|
useFillHandle,
|
|
2100
|
+
useFindReplace,
|
|
2101
|
+
useGenerationPlan,
|
|
2102
|
+
useGenerationRecords,
|
|
1316
2103
|
useHistory,
|
|
1317
2104
|
useHistoryDirty,
|
|
1318
2105
|
useHistoryShortcuts,
|
|
1319
2106
|
useImageEditor,
|
|
2107
|
+
useImageHistogram,
|
|
2108
|
+
useJobProgress,
|
|
2109
|
+
useMergePreview,
|
|
1320
2110
|
useNavigationGuard,
|
|
1321
2111
|
useOutline,
|
|
2112
|
+
useParagraphStyles,
|
|
1322
2113
|
usePromptEditor,
|
|
1323
2114
|
useRegisterCommands,
|
|
1324
2115
|
useSpreadsheetClipboard,
|