@pixerate/editor-react 0.15.0 → 0.16.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 +4 -0
- package/dist/canvas/index.cjs +219 -118
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +59 -3
- package/dist/canvas/index.d.ts +59 -3
- package/dist/canvas/index.js +103 -0
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-7SPRQZ6H.js +216 -0
- package/dist/chunk-7SPRQZ6H.js.map +1 -0
- package/dist/{chunk-QVQYYHJ5.js → chunk-FYIPXHAE.js} +21 -13
- package/dist/chunk-FYIPXHAE.js.map +1 -0
- package/dist/{chunk-LPFZMZ3L.js → chunk-XTFR3IMK.js} +676 -322
- package/dist/chunk-XTFR3IMK.js.map +1 -0
- package/dist/chunk-XWFU2CSG.js +167 -0
- package/dist/chunk-XWFU2CSG.js.map +1 -0
- package/dist/generation/index.cjs +235 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +60 -0
- package/dist/generation/index.d.ts +60 -0
- package/dist/generation/index.js +13 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/image-editor/index.cjs +684 -336
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +60 -2
- package/dist/image-editor/index.d.ts +60 -2
- package/dist/image-editor/index.js +13 -3
- package/dist/index.cjs +1881 -648
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +143 -4
- package/dist/index.d.ts +143 -4
- package/dist/index.js +626 -73
- 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 +17 -10
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +2 -0
- package/dist/spreadsheet/index.d.ts +2 -0
- package/dist/spreadsheet/index.js +1 -1
- package/package.json +18 -2
- package/dist/chunk-LPFZMZ3L.js.map +0 -1
- package/dist/chunk-QVQYYHJ5.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -30,40 +30,56 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
|
+
AdjustmentLayersPanel: () => AdjustmentLayersPanel,
|
|
33
34
|
BubbleMenu: () => BubbleMenu,
|
|
34
35
|
CommandPalette: () => CommandPalette,
|
|
35
36
|
CommentButton: () => CommentButton,
|
|
36
37
|
CommentsPanel: () => CommentsPanel,
|
|
37
|
-
|
|
38
|
+
ControlSlider: () => ControlSlider,
|
|
39
|
+
CurvesEditor: () => CurvesEditor,
|
|
40
|
+
DirtyTracker: () => import_editor16.DirtyTracker,
|
|
38
41
|
EditorContent: () => EditorContent,
|
|
39
42
|
EditorSlotsProvider: () => EditorSlotsProvider,
|
|
43
|
+
FindReplaceBar: () => FindReplaceBar,
|
|
40
44
|
FormulaHints: () => FormulaHints,
|
|
41
|
-
|
|
45
|
+
GenerationSettings: () => GenerationSettings,
|
|
46
|
+
Histogram: () => Histogram,
|
|
47
|
+
HistoryManager: () => import_editor16.HistoryManager,
|
|
42
48
|
ImageEditor: () => ImageEditor,
|
|
49
|
+
JobProgress: () => JobProgress,
|
|
50
|
+
MergePreview: () => MergePreview,
|
|
43
51
|
OutlinePanel: () => OutlinePanel,
|
|
52
|
+
RecoveryPrompt: () => RecoveryPrompt,
|
|
44
53
|
ReviewToolbar: () => ReviewToolbar,
|
|
45
54
|
SpreadsheetContextMenu: () => SpreadsheetContextMenu,
|
|
46
55
|
SpreadsheetEditor: () => SpreadsheetEditor,
|
|
47
56
|
SpreadsheetGroupRow: () => SpreadsheetGroupRow,
|
|
48
57
|
TemplateRenderer: () => TemplateRenderer,
|
|
49
58
|
VariableForm: () => VariableForm,
|
|
50
|
-
bindDirtyToHistory: () =>
|
|
51
|
-
createDirtyTracker: () =>
|
|
52
|
-
createHistoryManager: () =>
|
|
53
|
-
defaultIsEqual: () =>
|
|
59
|
+
bindDirtyToHistory: () => import_editor16.bindDirtyToHistory,
|
|
60
|
+
createDirtyTracker: () => import_editor16.createDirtyTracker,
|
|
61
|
+
createHistoryManager: () => import_editor16.createHistoryManager,
|
|
62
|
+
defaultIsEqual: () => import_editor16.defaultIsEqual,
|
|
54
63
|
useAgentToolProvider: () => useAgentToolProvider,
|
|
64
|
+
useAutosave: () => useAutosave,
|
|
55
65
|
useCommandPalette: () => useCommandPalette,
|
|
56
66
|
useCommandShortcuts: () => useCommandShortcuts,
|
|
57
67
|
useComments: () => useComments,
|
|
58
68
|
useDismissGuard: () => useDismissGuard,
|
|
69
|
+
useDocumentCompare: () => useDocumentCompare,
|
|
59
70
|
useEditor: () => useEditor2,
|
|
60
71
|
useEditorSlots: () => useEditorSlots,
|
|
61
72
|
useFileImport: () => useFileImport,
|
|
62
73
|
useFillHandle: () => useFillHandle,
|
|
74
|
+
useFindReplace: () => useFindReplace,
|
|
75
|
+
useGenerationPlan: () => useGenerationPlan,
|
|
63
76
|
useHistory: () => useHistory,
|
|
64
77
|
useHistoryDirty: () => useHistoryDirty,
|
|
65
78
|
useHistoryShortcuts: () => useHistoryShortcuts,
|
|
66
79
|
useImageEditor: () => useImageEditor,
|
|
80
|
+
useImageHistogram: () => useImageHistogram,
|
|
81
|
+
useJobProgress: () => useJobProgress,
|
|
82
|
+
useMergePreview: () => useMergePreview,
|
|
67
83
|
useNavigationGuard: () => useNavigationGuard,
|
|
68
84
|
useOutline: () => useOutline,
|
|
69
85
|
usePromptEditor: () => usePromptEditor,
|
|
@@ -71,7 +87,7 @@ __export(src_exports, {
|
|
|
71
87
|
useSpreadsheetClipboard: () => useSpreadsheetClipboard,
|
|
72
88
|
useSpreadsheetEditor: () => useSpreadsheetEditor,
|
|
73
89
|
useTrackChanges: () => useTrackChanges,
|
|
74
|
-
withoutDirty: () =>
|
|
90
|
+
withoutDirty: () => import_editor16.withoutDirty
|
|
75
91
|
});
|
|
76
92
|
module.exports = __toCommonJS(src_exports);
|
|
77
93
|
|
|
@@ -695,7 +711,6 @@ var BubbleMenu = ({
|
|
|
695
711
|
var import_react13 = require("react");
|
|
696
712
|
var import_editor6 = require("@pixerate/editor");
|
|
697
713
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
698
|
-
var CONDITIONAL_PREFIX = { if: "?", unless: "!", end: "/" };
|
|
699
714
|
var TemplateRenderer = ({
|
|
700
715
|
content,
|
|
701
716
|
templates = [],
|
|
@@ -778,8 +793,8 @@ var TemplateRenderer = ({
|
|
|
778
793
|
{
|
|
779
794
|
"data-conditional": token.conditional,
|
|
780
795
|
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",
|
|
781
|
-
title:
|
|
782
|
-
children:
|
|
796
|
+
title: (0, import_editor6.describeConditionalTag)(token),
|
|
797
|
+
children: (0, import_editor6.formatConditionalTag)(token)
|
|
783
798
|
},
|
|
784
799
|
index
|
|
785
800
|
);
|
|
@@ -884,17 +899,305 @@ var VariableForm = ({
|
|
|
884
899
|
}) });
|
|
885
900
|
};
|
|
886
901
|
|
|
887
|
-
// src/
|
|
902
|
+
// src/components/MergePreview.tsx
|
|
903
|
+
var import_react16 = require("react");
|
|
904
|
+
|
|
905
|
+
// src/hooks/useMergePreview.ts
|
|
888
906
|
var import_react15 = require("react");
|
|
889
907
|
var import_editor8 = require("@pixerate/editor");
|
|
908
|
+
function useMergePreview(options) {
|
|
909
|
+
const { template, templates, bindings, parseOptions } = options;
|
|
910
|
+
const [sourceText, setSourceTextState] = (0, import_react15.useState)(options.initialSource ?? "");
|
|
911
|
+
const [overrides, setOverrides] = (0, import_react15.useState)({});
|
|
912
|
+
const [index, setIndexState] = (0, import_react15.useState)(0);
|
|
913
|
+
const [result, setResult] = (0, import_react15.useState)(null);
|
|
914
|
+
const source = (0, import_react15.useMemo)(
|
|
915
|
+
() => (0, import_editor8.parseDataSource)(sourceText, parseOptions),
|
|
916
|
+
[sourceText, parseOptions]
|
|
917
|
+
);
|
|
918
|
+
const variables = (0, import_react15.useMemo)(
|
|
919
|
+
() => (0, import_editor8.extractVariables)(template, { templates, bindings }).map((v) => v.name),
|
|
920
|
+
[template, templates, bindings]
|
|
921
|
+
);
|
|
922
|
+
const mapping = (0, import_react15.useMemo)(() => {
|
|
923
|
+
const merged = {
|
|
924
|
+
...(0, import_editor8.matchFields)(variables, source.fields).mapping
|
|
925
|
+
};
|
|
926
|
+
for (const [variable, field] of Object.entries(overrides)) {
|
|
927
|
+
if (variables.includes(variable) && (field === null || source.fields.includes(field))) {
|
|
928
|
+
merged[variable] = field;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return merged;
|
|
932
|
+
}, [variables, source.fields, overrides]);
|
|
933
|
+
const count = source.records.length;
|
|
934
|
+
const current = count === 0 ? 0 : Math.min(index, count - 1);
|
|
935
|
+
const record = source.records[current];
|
|
936
|
+
const values = (0, import_react15.useMemo)(
|
|
937
|
+
() => record ? (0, import_editor8.recordToValues)(record, mapping) : {},
|
|
938
|
+
[record, mapping]
|
|
939
|
+
);
|
|
940
|
+
const setSourceText = (0, import_react15.useCallback)((text) => {
|
|
941
|
+
setSourceTextState(text);
|
|
942
|
+
setIndexState(0);
|
|
943
|
+
setResult(null);
|
|
944
|
+
}, []);
|
|
945
|
+
const loadFile = (0, import_react15.useCallback)(
|
|
946
|
+
async (file) => setSourceText(await file.text()),
|
|
947
|
+
[setSourceText]
|
|
948
|
+
);
|
|
949
|
+
const setIndex = (0, import_react15.useCallback)(
|
|
950
|
+
(next) => setIndexState(Math.max(0, Math.min(next, count - 1))),
|
|
951
|
+
[count]
|
|
952
|
+
);
|
|
953
|
+
const setFieldMapping = (0, import_react15.useCallback)((variable, field) => {
|
|
954
|
+
setOverrides((previous) => ({ ...previous, [variable]: field }));
|
|
955
|
+
setResult(null);
|
|
956
|
+
}, []);
|
|
957
|
+
const resetMapping = (0, import_react15.useCallback)(() => setOverrides({}), []);
|
|
958
|
+
const merge = (0, import_react15.useCallback)(() => {
|
|
959
|
+
const merged = (0, import_editor8.mergeRecords)(template, source, {
|
|
960
|
+
templates,
|
|
961
|
+
bindings,
|
|
962
|
+
mapping,
|
|
963
|
+
skipIf: options.skipIf,
|
|
964
|
+
separator: options.separator,
|
|
965
|
+
maxOutputs: options.maxOutputs
|
|
966
|
+
});
|
|
967
|
+
setResult(merged);
|
|
968
|
+
return merged;
|
|
969
|
+
}, [template, source, templates, bindings, mapping, options.skipIf, options.separator, options.maxOutputs]);
|
|
970
|
+
const serialize = (0, import_react15.useCallback)(
|
|
971
|
+
(format) => result ? (0, import_editor8.serializeMergeOutputs)(result.outputs, format, options.separator) : "",
|
|
972
|
+
[result, options.separator]
|
|
973
|
+
);
|
|
974
|
+
return {
|
|
975
|
+
sourceText,
|
|
976
|
+
setSourceText,
|
|
977
|
+
loadFile,
|
|
978
|
+
source,
|
|
979
|
+
variables,
|
|
980
|
+
mapping,
|
|
981
|
+
setFieldMapping,
|
|
982
|
+
resetMapping,
|
|
983
|
+
index: current,
|
|
984
|
+
count,
|
|
985
|
+
setIndex,
|
|
986
|
+
next: () => setIndex(current + 1),
|
|
987
|
+
prev: () => setIndex(current - 1),
|
|
988
|
+
record,
|
|
989
|
+
values,
|
|
990
|
+
merge,
|
|
991
|
+
result,
|
|
992
|
+
serialize
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// src/components/MergePreview.tsx
|
|
997
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
998
|
+
function downloadText(text, fileName, type) {
|
|
999
|
+
if (typeof document === "undefined" || typeof URL.createObjectURL !== "function") {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
const url = URL.createObjectURL(new Blob([text], { type }));
|
|
1003
|
+
const link = document.createElement("a");
|
|
1004
|
+
link.href = url;
|
|
1005
|
+
link.download = fileName;
|
|
1006
|
+
link.click();
|
|
1007
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
1008
|
+
}
|
|
1009
|
+
var MergePreview = ({
|
|
1010
|
+
content,
|
|
1011
|
+
templates,
|
|
1012
|
+
bindings,
|
|
1013
|
+
templateColorMap,
|
|
1014
|
+
defaultSource,
|
|
1015
|
+
parseOptions,
|
|
1016
|
+
skipIf,
|
|
1017
|
+
separator,
|
|
1018
|
+
maxOutputs,
|
|
1019
|
+
onMerge,
|
|
1020
|
+
downloadName = "merged",
|
|
1021
|
+
className = "flex flex-col gap-3 text-sm"
|
|
1022
|
+
}) => {
|
|
1023
|
+
const id = (0, import_react16.useId)();
|
|
1024
|
+
const merge = useMergePreview({
|
|
1025
|
+
template: content,
|
|
1026
|
+
templates,
|
|
1027
|
+
bindings,
|
|
1028
|
+
initialSource: defaultSource,
|
|
1029
|
+
parseOptions,
|
|
1030
|
+
skipIf,
|
|
1031
|
+
separator,
|
|
1032
|
+
maxOutputs
|
|
1033
|
+
});
|
|
1034
|
+
const [copied, setCopied] = (0, import_react16.useState)(false);
|
|
1035
|
+
const { source, result } = merge;
|
|
1036
|
+
const copy = async () => {
|
|
1037
|
+
try {
|
|
1038
|
+
await navigator.clipboard.writeText(merge.serialize("text"));
|
|
1039
|
+
setCopied(true);
|
|
1040
|
+
} catch {
|
|
1041
|
+
setCopied(false);
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, "data-merge-preview": "", children: [
|
|
1045
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { htmlFor: `${id}-source`, className: "flex flex-col gap-1", children: [
|
|
1046
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-medium", children: "Data source (CSV, TSV or JSON)" }),
|
|
1047
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1048
|
+
"textarea",
|
|
1049
|
+
{
|
|
1050
|
+
id: `${id}-source`,
|
|
1051
|
+
"data-merge-source": "",
|
|
1052
|
+
value: merge.sourceText,
|
|
1053
|
+
rows: 5,
|
|
1054
|
+
spellCheck: false,
|
|
1055
|
+
onChange: (event) => merge.setSourceText(event.target.value),
|
|
1056
|
+
className: "px-2 py-1 font-mono text-xs rounded-md border border-violet-400/40 bg-transparent"
|
|
1057
|
+
}
|
|
1058
|
+
)
|
|
1059
|
+
] }),
|
|
1060
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1061
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1062
|
+
"input",
|
|
1063
|
+
{
|
|
1064
|
+
type: "file",
|
|
1065
|
+
accept: ".csv,.tsv,.txt,.json,text/csv,application/json",
|
|
1066
|
+
"aria-label": "Load data source file",
|
|
1067
|
+
"data-merge-file": "",
|
|
1068
|
+
onChange: (event) => {
|
|
1069
|
+
const file = event.target.files?.[0];
|
|
1070
|
+
if (file) void merge.loadFile(file);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
),
|
|
1074
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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"}` })
|
|
1075
|
+
] }),
|
|
1076
|
+
source.warnings.length > 0 && merge.sourceText.trim() !== "" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { "data-merge-warnings": "", className: "text-amber-600 text-xs", children: source.warnings.map((warning, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: warning.message }, i)) }),
|
|
1077
|
+
merge.variables.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("fieldset", { className: "flex flex-col gap-1", children: [
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("legend", { className: "font-medium", children: "Field mapping" }),
|
|
1079
|
+
merge.variables.map((variable) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1080
|
+
"label",
|
|
1081
|
+
{
|
|
1082
|
+
className: "flex items-center gap-2",
|
|
1083
|
+
"data-merge-mapping": variable,
|
|
1084
|
+
children: [
|
|
1085
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "min-w-24 font-mono", children: `{${variable}}` }),
|
|
1086
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1087
|
+
"select",
|
|
1088
|
+
{
|
|
1089
|
+
value: merge.mapping[variable] ?? "",
|
|
1090
|
+
"aria-label": `Field for ${variable}`,
|
|
1091
|
+
onChange: (event) => merge.setFieldMapping(variable, event.target.value || null),
|
|
1092
|
+
className: "px-1 py-0.5 rounded-md border border-violet-400/40 bg-transparent",
|
|
1093
|
+
children: [
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "", children: "(none)" }),
|
|
1095
|
+
source.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: field, children: field }, field))
|
|
1096
|
+
]
|
|
1097
|
+
}
|
|
1098
|
+
)
|
|
1099
|
+
]
|
|
1100
|
+
},
|
|
1101
|
+
variable
|
|
1102
|
+
))
|
|
1103
|
+
] }),
|
|
1104
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1105
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1106
|
+
"button",
|
|
1107
|
+
{
|
|
1108
|
+
type: "button",
|
|
1109
|
+
"data-merge-prev": "",
|
|
1110
|
+
onClick: merge.prev,
|
|
1111
|
+
disabled: merge.index <= 0,
|
|
1112
|
+
children: "Prev"
|
|
1113
|
+
}
|
|
1114
|
+
),
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-merge-position": "", children: merge.count === 0 ? "No records" : `Record ${merge.index + 1} of ${merge.count}` }),
|
|
1116
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1117
|
+
"button",
|
|
1118
|
+
{
|
|
1119
|
+
type: "button",
|
|
1120
|
+
"data-merge-next": "",
|
|
1121
|
+
onClick: merge.next,
|
|
1122
|
+
disabled: merge.index >= merge.count - 1,
|
|
1123
|
+
children: "Next"
|
|
1124
|
+
}
|
|
1125
|
+
)
|
|
1126
|
+
] }),
|
|
1127
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { "data-merge-output": "", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1128
|
+
TemplateRenderer,
|
|
1129
|
+
{
|
|
1130
|
+
content,
|
|
1131
|
+
templates,
|
|
1132
|
+
bindings,
|
|
1133
|
+
templateColorMap,
|
|
1134
|
+
resolve: !!templates && templates.length > 0,
|
|
1135
|
+
values: merge.values
|
|
1136
|
+
}
|
|
1137
|
+
) }),
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1140
|
+
"button",
|
|
1141
|
+
{
|
|
1142
|
+
type: "button",
|
|
1143
|
+
"data-merge-all": "",
|
|
1144
|
+
disabled: merge.count === 0,
|
|
1145
|
+
onClick: () => {
|
|
1146
|
+
const merged = merge.merge();
|
|
1147
|
+
setCopied(false);
|
|
1148
|
+
onMerge?.(merged);
|
|
1149
|
+
},
|
|
1150
|
+
children: "Merge all"
|
|
1151
|
+
}
|
|
1152
|
+
),
|
|
1153
|
+
result && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "data-merge-result": "", children: `${result.outputs.length} merged${result.skipped.length ? `, ${result.skipped.length} skipped` : ""}${result.truncated ? " (stopped early)" : ""}` }),
|
|
1155
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", "data-merge-copy": "", onClick: copy, children: copied ? "Copied" : "Copy" }),
|
|
1156
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1157
|
+
"button",
|
|
1158
|
+
{
|
|
1159
|
+
type: "button",
|
|
1160
|
+
"data-merge-download": "text",
|
|
1161
|
+
onClick: () => downloadText(merge.serialize("text"), `${downloadName}.txt`, "text/plain"),
|
|
1162
|
+
children: "Download .txt"
|
|
1163
|
+
}
|
|
1164
|
+
),
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1166
|
+
"button",
|
|
1167
|
+
{
|
|
1168
|
+
type: "button",
|
|
1169
|
+
"data-merge-download": "json",
|
|
1170
|
+
onClick: () => downloadText(merge.serialize("json"), `${downloadName}.json`, "application/json"),
|
|
1171
|
+
children: "Download .json"
|
|
1172
|
+
}
|
|
1173
|
+
)
|
|
1174
|
+
] })
|
|
1175
|
+
] }),
|
|
1176
|
+
result && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1177
|
+
"textarea",
|
|
1178
|
+
{
|
|
1179
|
+
readOnly: true,
|
|
1180
|
+
"aria-label": "Merged output",
|
|
1181
|
+
"data-merge-text": "",
|
|
1182
|
+
rows: 6,
|
|
1183
|
+
value: merge.serialize("text"),
|
|
1184
|
+
className: "px-2 py-1 font-mono text-xs rounded-md border border-violet-400/40 bg-transparent"
|
|
1185
|
+
}
|
|
1186
|
+
)
|
|
1187
|
+
] });
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
// src/hooks/useOutline.ts
|
|
1191
|
+
var import_react17 = require("react");
|
|
1192
|
+
var import_editor9 = require("@pixerate/editor");
|
|
890
1193
|
function useOutline(editor) {
|
|
891
|
-
const store = (0,
|
|
892
|
-
return (0,
|
|
1194
|
+
const store = (0, import_react17.useMemo)(() => (0, import_editor9.createOutlineStore)(editor), [editor]);
|
|
1195
|
+
return (0, import_react17.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
893
1196
|
}
|
|
894
1197
|
|
|
895
1198
|
// src/components/OutlinePanel.tsx
|
|
896
|
-
var
|
|
897
|
-
var
|
|
1199
|
+
var import_editor10 = require("@pixerate/editor");
|
|
1200
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
898
1201
|
var OutlinePanel = ({
|
|
899
1202
|
editor,
|
|
900
1203
|
title = "Outline",
|
|
@@ -908,11 +1211,11 @@ var OutlinePanel = ({
|
|
|
908
1211
|
}) => {
|
|
909
1212
|
const { headings, activeId } = useOutline(editor);
|
|
910
1213
|
const visible = headings.filter((h) => h.level <= maxLevel);
|
|
911
|
-
return /* @__PURE__ */ (0,
|
|
912
|
-
title != null && /* @__PURE__ */ (0,
|
|
913
|
-
visible.length === 0 ? /* @__PURE__ */ (0,
|
|
1214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("nav", { className, "aria-label": "Document outline", "data-outline-panel": "", children: [
|
|
1215
|
+
title != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pixerate-outline-title", children: title }),
|
|
1216
|
+
visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pixerate-outline-empty", children: emptyState }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { role: "list", style: { listStyle: "none", margin: 0, padding: 0 }, children: visible.map((heading) => {
|
|
914
1217
|
const active = heading.id === activeId;
|
|
915
|
-
return /* @__PURE__ */ (0,
|
|
1218
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { "data-level": heading.level, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
916
1219
|
"button",
|
|
917
1220
|
{
|
|
918
1221
|
type: "button",
|
|
@@ -922,7 +1225,7 @@ var OutlinePanel = ({
|
|
|
922
1225
|
"data-heading-id": heading.id,
|
|
923
1226
|
onClick: () => {
|
|
924
1227
|
if (!editor) return;
|
|
925
|
-
if ((0,
|
|
1228
|
+
if ((0, import_editor10.navigateToHeading)(editor, heading, { focus: focusOnNavigate })) {
|
|
926
1229
|
onNavigate?.(heading);
|
|
927
1230
|
}
|
|
928
1231
|
},
|
|
@@ -934,16 +1237,16 @@ var OutlinePanel = ({
|
|
|
934
1237
|
};
|
|
935
1238
|
|
|
936
1239
|
// src/index.ts
|
|
937
|
-
var
|
|
1240
|
+
var import_editor16 = require("@pixerate/editor");
|
|
938
1241
|
|
|
939
1242
|
// src/spreadsheet/useSpreadsheetEditor.ts
|
|
940
|
-
var
|
|
1243
|
+
var import_react18 = require("react");
|
|
941
1244
|
var import_spreadsheet = require("@pixerate/editor/spreadsheet");
|
|
942
1245
|
function useSpreadsheetEditor(options = {}) {
|
|
943
|
-
const optionsRef = (0,
|
|
1246
|
+
const optionsRef = (0, import_react18.useRef)(options);
|
|
944
1247
|
optionsRef.current = options;
|
|
945
|
-
const settersRef = (0,
|
|
946
|
-
const [controller] = (0,
|
|
1248
|
+
const settersRef = (0, import_react18.useRef)({});
|
|
1249
|
+
const [controller] = (0, import_react18.useState)(
|
|
947
1250
|
() => new import_spreadsheet.SpreadsheetController({
|
|
948
1251
|
...options,
|
|
949
1252
|
onDocumentChange: (updated) => {
|
|
@@ -960,97 +1263,97 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
960
1263
|
}
|
|
961
1264
|
})
|
|
962
1265
|
);
|
|
963
|
-
const [doc, setDoc] = (0,
|
|
964
|
-
const [activeCell, setActiveCell] = (0,
|
|
965
|
-
const [selectedRange, setSelectedRange] = (0,
|
|
966
|
-
const [editingCell, setEditingCell] = (0,
|
|
967
|
-
const [draftValue, setDraftState] = (0,
|
|
1266
|
+
const [doc, setDoc] = (0, import_react18.useState)(() => ({ ...controller.document }));
|
|
1267
|
+
const [activeCell, setActiveCell] = (0, import_react18.useState)(controller.activeCell);
|
|
1268
|
+
const [selectedRange, setSelectedRange] = (0, import_react18.useState)(controller.selectedRange);
|
|
1269
|
+
const [editingCell, setEditingCell] = (0, import_react18.useState)(null);
|
|
1270
|
+
const [draftValue, setDraftState] = (0, import_react18.useState)("");
|
|
968
1271
|
settersRef.current = { setDoc, setActiveCell, setSelectedRange };
|
|
969
|
-
const setDraftValue = (0,
|
|
1272
|
+
const setDraftValue = (0, import_react18.useCallback)((value) => {
|
|
970
1273
|
controller.draftValue = value;
|
|
971
1274
|
setDraftState(value);
|
|
972
1275
|
}, [controller]);
|
|
973
|
-
const setCellValue = (0,
|
|
1276
|
+
const setCellValue = (0, import_react18.useCallback)((rowId, colId, raw) => {
|
|
974
1277
|
controller.setCellValue(rowId, colId, raw);
|
|
975
1278
|
setDoc({ ...controller.document });
|
|
976
1279
|
}, [controller]);
|
|
977
|
-
const selectCell = (0,
|
|
1280
|
+
const selectCell = (0, import_react18.useCallback)((row, col, extendSelection = false) => {
|
|
978
1281
|
controller.selectCell(row, col, extendSelection);
|
|
979
1282
|
setActiveCell(controller.activeCell);
|
|
980
1283
|
setSelectedRange(controller.selectedRange);
|
|
981
1284
|
}, [controller]);
|
|
982
|
-
const selectRange = (0,
|
|
1285
|
+
const selectRange = (0, import_react18.useCallback)((range) => {
|
|
983
1286
|
controller.selectRange(range);
|
|
984
1287
|
setSelectedRange(controller.selectedRange);
|
|
985
1288
|
}, [controller]);
|
|
986
|
-
const startEditing = (0,
|
|
1289
|
+
const startEditing = (0, import_react18.useCallback)((row, col, initialVal) => {
|
|
987
1290
|
controller.startEditing(row, col, initialVal);
|
|
988
1291
|
setActiveCell(controller.activeCell);
|
|
989
1292
|
setEditingCell(controller.editingCell);
|
|
990
1293
|
setDraftValue(controller.draftValue);
|
|
991
1294
|
}, [controller]);
|
|
992
|
-
const commitEditing = (0,
|
|
1295
|
+
const commitEditing = (0, import_react18.useCallback)((val) => {
|
|
993
1296
|
controller.commitEditing(val);
|
|
994
1297
|
setEditingCell(null);
|
|
995
1298
|
setDraftValue("");
|
|
996
1299
|
setDoc({ ...controller.document });
|
|
997
1300
|
}, [controller]);
|
|
998
|
-
const cancelEditing = (0,
|
|
1301
|
+
const cancelEditing = (0, import_react18.useCallback)(() => {
|
|
999
1302
|
controller.cancelEditing();
|
|
1000
1303
|
setEditingCell(null);
|
|
1001
1304
|
setDraftValue("");
|
|
1002
1305
|
}, [controller]);
|
|
1003
|
-
const moveCursor = (0,
|
|
1306
|
+
const moveCursor = (0, import_react18.useCallback)((dir, extend = false) => {
|
|
1004
1307
|
controller.moveCursor(dir, extend);
|
|
1005
1308
|
setActiveCell(controller.activeCell);
|
|
1006
1309
|
setSelectedRange(controller.selectedRange);
|
|
1007
1310
|
}, [controller]);
|
|
1008
|
-
const insertColumn = (0,
|
|
1311
|
+
const insertColumn = (0, import_react18.useCallback)((index, config) => {
|
|
1009
1312
|
controller.insertColumn(index, config);
|
|
1010
1313
|
setDoc({ ...controller.document });
|
|
1011
1314
|
}, [controller]);
|
|
1012
|
-
const deleteColumn = (0,
|
|
1315
|
+
const deleteColumn = (0, import_react18.useCallback)((colId) => {
|
|
1013
1316
|
controller.deleteColumn(colId);
|
|
1014
1317
|
setDoc({ ...controller.document });
|
|
1015
1318
|
}, [controller]);
|
|
1016
|
-
const insertRow = (0,
|
|
1319
|
+
const insertRow = (0, import_react18.useCallback)((index, config) => {
|
|
1017
1320
|
controller.insertRow(index, config);
|
|
1018
1321
|
setDoc({ ...controller.document });
|
|
1019
1322
|
}, [controller]);
|
|
1020
|
-
const deleteRow = (0,
|
|
1323
|
+
const deleteRow = (0, import_react18.useCallback)((rowId) => {
|
|
1021
1324
|
controller.deleteRow(rowId);
|
|
1022
1325
|
setDoc({ ...controller.document });
|
|
1023
1326
|
}, [controller]);
|
|
1024
|
-
const setColumnWidth = (0,
|
|
1327
|
+
const setColumnWidth = (0, import_react18.useCallback)((colId, width) => {
|
|
1025
1328
|
controller.setColumnWidth(colId, width);
|
|
1026
1329
|
setDoc({ ...controller.document });
|
|
1027
1330
|
}, [controller]);
|
|
1028
|
-
const autoFitColumnWidth = (0,
|
|
1331
|
+
const autoFitColumnWidth = (0, import_react18.useCallback)((colId, customWidth) => {
|
|
1029
1332
|
controller.autoFitColumnWidth(colId, customWidth);
|
|
1030
1333
|
setDoc({ ...controller.document });
|
|
1031
1334
|
}, [controller]);
|
|
1032
|
-
const registerDataSource = (0,
|
|
1335
|
+
const registerDataSource = (0, import_react18.useCallback)((ds) => {
|
|
1033
1336
|
controller.registerDataSource(ds);
|
|
1034
1337
|
setDoc({ ...controller.document });
|
|
1035
1338
|
}, [controller]);
|
|
1036
|
-
const setPrimaryDataSource = (0,
|
|
1339
|
+
const setPrimaryDataSource = (0, import_react18.useCallback)((id) => {
|
|
1037
1340
|
controller.setPrimaryDataSource(id);
|
|
1038
1341
|
setDoc({ ...controller.document });
|
|
1039
1342
|
}, [controller]);
|
|
1040
|
-
const recalculateAll = (0,
|
|
1343
|
+
const recalculateAll = (0, import_react18.useCallback)(() => {
|
|
1041
1344
|
controller.recalculateAll();
|
|
1042
1345
|
setDoc({ ...controller.document });
|
|
1043
1346
|
}, [controller]);
|
|
1044
|
-
const undo = (0,
|
|
1347
|
+
const undo = (0, import_react18.useCallback)(() => {
|
|
1045
1348
|
controller.undo();
|
|
1046
1349
|
setDoc({ ...controller.document });
|
|
1047
1350
|
}, [controller]);
|
|
1048
|
-
const redo = (0,
|
|
1351
|
+
const redo = (0, import_react18.useCallback)(() => {
|
|
1049
1352
|
controller.redo();
|
|
1050
1353
|
setDoc({ ...controller.document });
|
|
1051
1354
|
}, [controller]);
|
|
1052
|
-
const tableActions = (0,
|
|
1053
|
-
const viewModel = (0,
|
|
1355
|
+
const tableActions = (0, import_react18.useMemo)(() => (0, import_spreadsheet.bindSpreadsheetTableActions)(controller), [controller]);
|
|
1356
|
+
const viewModel = (0, import_react18.useMemo)(() => controller.getViewModel(), [controller, doc]);
|
|
1054
1357
|
return {
|
|
1055
1358
|
document: doc,
|
|
1056
1359
|
activeCell,
|
|
@@ -1102,20 +1405,20 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
1102
1405
|
}
|
|
1103
1406
|
|
|
1104
1407
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
1105
|
-
var
|
|
1408
|
+
var import_react22 = require("react");
|
|
1106
1409
|
var import_spreadsheet5 = require("@pixerate/editor/spreadsheet");
|
|
1107
1410
|
|
|
1108
1411
|
// src/spreadsheet/SpreadsheetContextMenu.tsx
|
|
1109
|
-
var
|
|
1412
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
1110
1413
|
var import_spreadsheet2 = require("@pixerate/editor/spreadsheet");
|
|
1111
|
-
var
|
|
1414
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1112
1415
|
var VIEWPORT_MARGIN = 4;
|
|
1113
1416
|
var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
1114
|
-
const menuRef = (0,
|
|
1115
|
-
const onCloseRef = (0,
|
|
1417
|
+
const menuRef = (0, import_react19.useRef)(null);
|
|
1418
|
+
const onCloseRef = (0, import_react19.useRef)(onClose);
|
|
1116
1419
|
onCloseRef.current = onClose;
|
|
1117
|
-
const [position, setPosition] = (0,
|
|
1118
|
-
(0,
|
|
1420
|
+
const [position, setPosition] = (0, import_react19.useState)({ x, y });
|
|
1421
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
1119
1422
|
const menu = menuRef.current;
|
|
1120
1423
|
if (!menu || typeof window === "undefined") return;
|
|
1121
1424
|
const { width, height } = menu.getBoundingClientRect();
|
|
@@ -1127,7 +1430,7 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
1127
1430
|
);
|
|
1128
1431
|
setPosition((prev) => prev.x === next.x && prev.y === next.y ? prev : next);
|
|
1129
1432
|
}, [x, y, items]);
|
|
1130
|
-
(0,
|
|
1433
|
+
(0, import_react19.useEffect)(() => {
|
|
1131
1434
|
const handlePointer = (e) => {
|
|
1132
1435
|
if (!menuRef.current?.contains(e.target)) onCloseRef.current();
|
|
1133
1436
|
};
|
|
@@ -1141,7 +1444,7 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
1141
1444
|
window.removeEventListener("keydown", handleKey);
|
|
1142
1445
|
};
|
|
1143
1446
|
}, []);
|
|
1144
|
-
return /* @__PURE__ */ (0,
|
|
1447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1145
1448
|
"div",
|
|
1146
1449
|
{
|
|
1147
1450
|
ref: menuRef,
|
|
@@ -1157,19 +1460,20 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
1157
1460
|
},
|
|
1158
1461
|
onContextMenu: (e) => e.preventDefault(),
|
|
1159
1462
|
onKeyDown: (e) => e.stopPropagation(),
|
|
1160
|
-
children: items.map((item) => /* @__PURE__ */ (0,
|
|
1161
|
-
item.separatorBefore && /* @__PURE__ */ (0,
|
|
1162
|
-
/* @__PURE__ */ (0,
|
|
1463
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react19.default.Fragment, { children: [
|
|
1464
|
+
item.separatorBefore && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { role: "separator", className: "my-1 h-px bg-border" }),
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1163
1466
|
"button",
|
|
1164
1467
|
{
|
|
1165
1468
|
type: "button",
|
|
1166
1469
|
role: "menuitem",
|
|
1167
1470
|
"data-action": item.id,
|
|
1471
|
+
"data-checked": item.checked ? "" : void 0,
|
|
1168
1472
|
disabled: item.disabled,
|
|
1169
|
-
className:
|
|
1473
|
+
className: `block w-full px-3 py-1 text-left hover:bg-muted disabled:cursor-default disabled:opacity-40 disabled:hover:bg-transparent ${item.checked ? "font-semibold" : ""}`,
|
|
1170
1474
|
onClick: () => {
|
|
1171
1475
|
onClose();
|
|
1172
|
-
|
|
1476
|
+
(0, import_spreadsheet2.runSpreadsheetMenuItem)(item);
|
|
1173
1477
|
},
|
|
1174
1478
|
children: item.label
|
|
1175
1479
|
}
|
|
@@ -1180,7 +1484,7 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
1180
1484
|
};
|
|
1181
1485
|
|
|
1182
1486
|
// src/spreadsheet/SpreadsheetGroupRow.tsx
|
|
1183
|
-
var
|
|
1487
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1184
1488
|
var formatSummary = (value) => value === null ? "\u2013" : String(value);
|
|
1185
1489
|
var SpreadsheetGroupRow = ({
|
|
1186
1490
|
group,
|
|
@@ -1190,8 +1494,8 @@ var SpreadsheetGroupRow = ({
|
|
|
1190
1494
|
trailingCell
|
|
1191
1495
|
}) => {
|
|
1192
1496
|
const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;
|
|
1193
|
-
return /* @__PURE__ */ (0,
|
|
1194
|
-
/* @__PURE__ */ (0,
|
|
1497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { className: "border-b border-border bg-muted/40 font-semibold", "data-group-key": group.key, style: { height: 28 }, children: [
|
|
1498
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1195
1499
|
"button",
|
|
1196
1500
|
{
|
|
1197
1501
|
type: "button",
|
|
@@ -1207,22 +1511,22 @@ var SpreadsheetGroupRow = ({
|
|
|
1207
1511
|
) }),
|
|
1208
1512
|
columns.map(({ column }) => {
|
|
1209
1513
|
const summary = group.summaries[column.id];
|
|
1210
|
-
return /* @__PURE__ */ (0,
|
|
1514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "border-r border-border px-2 py-1 truncate max-w-0 text-foreground", style: { maxWidth: 0, overflow: "hidden" }, children: column.id === labelColId ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "truncate", children: [
|
|
1211
1515
|
group.label,
|
|
1212
1516
|
" ",
|
|
1213
|
-
/* @__PURE__ */ (0,
|
|
1517
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "font-normal text-muted-foreground", children: [
|
|
1214
1518
|
"(",
|
|
1215
1519
|
group.rowIndices.length,
|
|
1216
1520
|
")"
|
|
1217
1521
|
] })
|
|
1218
|
-
] }) : summary !== void 0 ? /* @__PURE__ */ (0,
|
|
1522
|
+
] }) : summary !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate", "data-summary": column.id, children: formatSummary(summary) }) : null }, column.id);
|
|
1219
1523
|
}),
|
|
1220
|
-
trailingCell && /* @__PURE__ */ (0,
|
|
1524
|
+
trailingCell && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
|
|
1221
1525
|
] });
|
|
1222
1526
|
};
|
|
1223
1527
|
|
|
1224
1528
|
// src/spreadsheet/useSpreadsheetTableInteractions.ts
|
|
1225
|
-
var
|
|
1529
|
+
var import_react20 = require("react");
|
|
1226
1530
|
var import_spreadsheet3 = require("@pixerate/editor/spreadsheet");
|
|
1227
1531
|
function gridHasFocus(grid) {
|
|
1228
1532
|
if (!grid || typeof document === "undefined") return false;
|
|
@@ -1231,12 +1535,12 @@ function gridHasFocus(grid) {
|
|
|
1231
1535
|
return !(active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement);
|
|
1232
1536
|
}
|
|
1233
1537
|
function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
1234
|
-
const stateRef = (0,
|
|
1538
|
+
const stateRef = (0, import_react20.useRef)(state);
|
|
1235
1539
|
stateRef.current = state;
|
|
1236
|
-
const readOnlyRef = (0,
|
|
1540
|
+
const readOnlyRef = (0, import_react20.useRef)(readOnly);
|
|
1237
1541
|
readOnlyRef.current = readOnly;
|
|
1238
|
-
const copiedRef = (0,
|
|
1239
|
-
(0,
|
|
1542
|
+
const copiedRef = (0, import_react20.useRef)(false);
|
|
1543
|
+
(0, import_react20.useEffect)(() => {
|
|
1240
1544
|
if (typeof document === "undefined") return;
|
|
1241
1545
|
const handleCopy = (e) => {
|
|
1242
1546
|
const s = stateRef.current;
|
|
@@ -1259,7 +1563,7 @@ function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
|
1259
1563
|
document.removeEventListener("paste", handlePaste);
|
|
1260
1564
|
};
|
|
1261
1565
|
}, [gridRef]);
|
|
1262
|
-
const copyShortcutFallback = (0,
|
|
1566
|
+
const copyShortcutFallback = (0, import_react20.useCallback)(() => {
|
|
1263
1567
|
copiedRef.current = false;
|
|
1264
1568
|
setTimeout(() => {
|
|
1265
1569
|
if (copiedRef.current) return;
|
|
@@ -1271,13 +1575,13 @@ function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
|
1271
1575
|
return { copyShortcutFallback };
|
|
1272
1576
|
}
|
|
1273
1577
|
function useFillHandle(state) {
|
|
1274
|
-
const [drag, setDrag] = (0,
|
|
1275
|
-
const dragRef = (0,
|
|
1578
|
+
const [drag, setDrag] = (0, import_react20.useState)(null);
|
|
1579
|
+
const dragRef = (0, import_react20.useRef)(drag);
|
|
1276
1580
|
dragRef.current = drag;
|
|
1277
|
-
const stateRef = (0,
|
|
1581
|
+
const stateRef = (0, import_react20.useRef)(state);
|
|
1278
1582
|
stateRef.current = state;
|
|
1279
1583
|
const dragging = drag !== null;
|
|
1280
|
-
(0,
|
|
1584
|
+
(0, import_react20.useEffect)(() => {
|
|
1281
1585
|
if (!dragging) return;
|
|
1282
1586
|
const handleMouseUp = () => {
|
|
1283
1587
|
const current = dragRef.current;
|
|
@@ -1287,13 +1591,13 @@ function useFillHandle(state) {
|
|
|
1287
1591
|
window.addEventListener("mouseup", handleMouseUp);
|
|
1288
1592
|
return () => window.removeEventListener("mouseup", handleMouseUp);
|
|
1289
1593
|
}, [dragging]);
|
|
1290
|
-
const startFill = (0,
|
|
1594
|
+
const startFill = (0, import_react20.useCallback)((e) => {
|
|
1291
1595
|
e.preventDefault();
|
|
1292
1596
|
e.stopPropagation();
|
|
1293
1597
|
const range = stateRef.current.selectedRange;
|
|
1294
1598
|
if (range) setDrag({ source: (0, import_spreadsheet3.normalizeRange)(range), target: null });
|
|
1295
1599
|
}, []);
|
|
1296
|
-
const extendFill = (0,
|
|
1600
|
+
const extendFill = (0, import_react20.useCallback)((row, col) => {
|
|
1297
1601
|
const current = dragRef.current;
|
|
1298
1602
|
if (!current) return;
|
|
1299
1603
|
setDrag({ source: current.source, target: (0, import_spreadsheet3.computeFillTarget)(current.source, { row, col }) });
|
|
@@ -1302,24 +1606,24 @@ function useFillHandle(state) {
|
|
|
1302
1606
|
}
|
|
1303
1607
|
|
|
1304
1608
|
// src/spreadsheet/FormulaHints.tsx
|
|
1305
|
-
var
|
|
1609
|
+
var import_react21 = require("react");
|
|
1306
1610
|
var import_spreadsheet4 = require("@pixerate/editor/spreadsheet");
|
|
1307
|
-
var
|
|
1611
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1308
1612
|
var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
1309
|
-
const [caret, setCaret] = (0,
|
|
1310
|
-
const [focused, setFocused] = (0,
|
|
1311
|
-
const [selected, setSelected] = (0,
|
|
1312
|
-
const [dismissed, setDismissed] = (0,
|
|
1313
|
-
const [position, setPosition] = (0,
|
|
1314
|
-
const pendingCaret = (0,
|
|
1315
|
-
const hints = (0,
|
|
1613
|
+
const [caret, setCaret] = (0, import_react21.useState)(null);
|
|
1614
|
+
const [focused, setFocused] = (0, import_react21.useState)(false);
|
|
1615
|
+
const [selected, setSelected] = (0, import_react21.useState)(0);
|
|
1616
|
+
const [dismissed, setDismissed] = (0, import_react21.useState)(false);
|
|
1617
|
+
const [position, setPosition] = (0, import_react21.useState)(null);
|
|
1618
|
+
const pendingCaret = (0, import_react21.useRef)(null);
|
|
1619
|
+
const hints = (0, import_react21.useMemo)(
|
|
1316
1620
|
() => (0, import_spreadsheet4.getFormulaHints)(value, caret ?? value.length, { limit }),
|
|
1317
1621
|
[value, caret, limit]
|
|
1318
1622
|
);
|
|
1319
1623
|
const suggestions = dismissed ? [] : hints.suggestions;
|
|
1320
1624
|
const selectedIndex = Math.max(0, Math.min(selected, suggestions.length - 1));
|
|
1321
1625
|
const visible = focused && value.trimStart().startsWith("=") && (suggestions.length > 0 || !!hints.activeCall);
|
|
1322
|
-
const latest = (0,
|
|
1626
|
+
const latest = (0, import_react21.useRef)({ suggestions, selected: selectedIndex, value, caret, onAccept });
|
|
1323
1627
|
latest.current = { suggestions, selected: selectedIndex, value, caret, onAccept };
|
|
1324
1628
|
const accept = (index) => {
|
|
1325
1629
|
const { suggestions: list, value: current, caret: at, onAccept: commit } = latest.current;
|
|
@@ -1329,7 +1633,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1329
1633
|
pendingCaret.current = next.caret;
|
|
1330
1634
|
commit(next.value);
|
|
1331
1635
|
};
|
|
1332
|
-
(0,
|
|
1636
|
+
(0, import_react21.useEffect)(() => {
|
|
1333
1637
|
const input = inputRef.current;
|
|
1334
1638
|
if (!input) return;
|
|
1335
1639
|
const syncCaret = () => setCaret(input.selectionStart ?? input.value.length);
|
|
@@ -1379,7 +1683,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1379
1683
|
input.removeEventListener("keydown", onKeyDown);
|
|
1380
1684
|
};
|
|
1381
1685
|
}, [inputRef]);
|
|
1382
|
-
(0,
|
|
1686
|
+
(0, import_react21.useLayoutEffect)(() => {
|
|
1383
1687
|
const input = inputRef.current;
|
|
1384
1688
|
const at = pendingCaret.current;
|
|
1385
1689
|
if (!input || at === null || input.value !== value) return;
|
|
@@ -1388,7 +1692,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1388
1692
|
setCaret(at);
|
|
1389
1693
|
setSelected(0);
|
|
1390
1694
|
}, [value, inputRef]);
|
|
1391
|
-
(0,
|
|
1695
|
+
(0, import_react21.useLayoutEffect)(() => {
|
|
1392
1696
|
const input = inputRef.current;
|
|
1393
1697
|
if (!visible || !input) return;
|
|
1394
1698
|
const rect = input.getBoundingClientRect();
|
|
@@ -1396,7 +1700,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1396
1700
|
}, [visible, value, inputRef]);
|
|
1397
1701
|
if (!visible) return null;
|
|
1398
1702
|
const { activeCall } = hints;
|
|
1399
|
-
return /* @__PURE__ */ (0,
|
|
1703
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1400
1704
|
"div",
|
|
1401
1705
|
{
|
|
1402
1706
|
"data-formula-hints": "",
|
|
@@ -1412,8 +1716,8 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1412
1716
|
},
|
|
1413
1717
|
onMouseDown: (e) => e.preventDefault(),
|
|
1414
1718
|
children: [
|
|
1415
|
-
activeCall && /* @__PURE__ */ (0,
|
|
1416
|
-
/* @__PURE__ */ (0,
|
|
1719
|
+
activeCall && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { "data-formula-signature": "", className: "px-2 py-1.5 border-b border-border bg-muted/30", children: [
|
|
1720
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "font-mono", children: activeCall.parts.map((part, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1417
1721
|
"span",
|
|
1418
1722
|
{
|
|
1419
1723
|
"data-active": part.active ? "" : void 0,
|
|
@@ -1422,13 +1726,13 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1422
1726
|
},
|
|
1423
1727
|
i
|
|
1424
1728
|
)) }),
|
|
1425
|
-
/* @__PURE__ */ (0,
|
|
1426
|
-
/* @__PURE__ */ (0,
|
|
1729
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mt-0.5 text-muted-foreground", children: activeCall.argument ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1730
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "font-semibold", children: activeCall.argument.name }),
|
|
1427
1731
|
": ",
|
|
1428
1732
|
activeCall.argument.description
|
|
1429
1733
|
] }) : activeCall.description })
|
|
1430
1734
|
] }),
|
|
1431
|
-
suggestions.length > 0 && /* @__PURE__ */ (0,
|
|
1735
|
+
suggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { role: "listbox", "aria-label": "Formula suggestions", className: "max-h-64 overflow-auto py-1 m-0 list-none p-0", children: suggestions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1432
1736
|
"li",
|
|
1433
1737
|
{
|
|
1434
1738
|
role: "option",
|
|
@@ -1440,8 +1744,8 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1440
1744
|
accept(i);
|
|
1441
1745
|
},
|
|
1442
1746
|
children: [
|
|
1443
|
-
/* @__PURE__ */ (0,
|
|
1444
|
-
/* @__PURE__ */ (0,
|
|
1747
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "font-mono font-semibold text-foreground", children: s.signature }),
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-muted-foreground truncate", children: s.description })
|
|
1445
1749
|
]
|
|
1446
1750
|
},
|
|
1447
1751
|
s.name
|
|
@@ -1452,7 +1756,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1452
1756
|
};
|
|
1453
1757
|
|
|
1454
1758
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
1455
|
-
var
|
|
1759
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1456
1760
|
var COLUMN_HEADER_HEIGHT = 28;
|
|
1457
1761
|
var ROW_HEADER_WIDTH = 48;
|
|
1458
1762
|
function frozenCellStyle(viewRow, viewCol) {
|
|
@@ -1479,6 +1783,19 @@ function spillBorderStyle(range, row, col) {
|
|
|
1479
1783
|
borderRight: col === range.endCol ? line : void 0
|
|
1480
1784
|
};
|
|
1481
1785
|
}
|
|
1786
|
+
function CellText({ cell }) {
|
|
1787
|
+
const shown = (0, import_spreadsheet5.formatCellForDisplay)(cell);
|
|
1788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1789
|
+
"span",
|
|
1790
|
+
{
|
|
1791
|
+
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
1792
|
+
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
1793
|
+
"data-numeric": shown.numeric ? "" : void 0,
|
|
1794
|
+
style: shown.numeric || shown.color ? { ...shown.numeric ? { textAlign: "right" } : {}, ...shown.color ? { color: (0, import_spreadsheet5.numberFormatColorToCss)(shown.color) } : {} } : void 0,
|
|
1795
|
+
children: shown.text
|
|
1796
|
+
}
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1482
1799
|
var SpreadsheetEditor = ({
|
|
1483
1800
|
state: externalState,
|
|
1484
1801
|
readOnly = false,
|
|
@@ -1489,23 +1806,23 @@ var SpreadsheetEditor = ({
|
|
|
1489
1806
|
}) => {
|
|
1490
1807
|
const defaultState = useSpreadsheetEditor();
|
|
1491
1808
|
const state = externalState || defaultState;
|
|
1492
|
-
const gridRef = (0,
|
|
1493
|
-
const formulaBarRef = (0,
|
|
1494
|
-
const cellInputRef = (0,
|
|
1495
|
-
const [resizingColId, setResizingColId] = (0,
|
|
1496
|
-
const [hoveredColId, setHoveredColId] = (0,
|
|
1497
|
-
const [resizeStartX, setResizeStartX] = (0,
|
|
1498
|
-
const [resizeStartWidth, setResizeStartWidth] = (0,
|
|
1809
|
+
const gridRef = (0, import_react22.useRef)(null);
|
|
1810
|
+
const formulaBarRef = (0, import_react22.useRef)(null);
|
|
1811
|
+
const cellInputRef = (0, import_react22.useRef)(null);
|
|
1812
|
+
const [resizingColId, setResizingColId] = (0, import_react22.useState)(null);
|
|
1813
|
+
const [hoveredColId, setHoveredColId] = (0, import_react22.useState)(null);
|
|
1814
|
+
const [resizeStartX, setResizeStartX] = (0, import_react22.useState)(0);
|
|
1815
|
+
const [resizeStartWidth, setResizeStartWidth] = (0, import_react22.useState)(0);
|
|
1499
1816
|
const view = state.viewModel;
|
|
1500
1817
|
const { copyShortcutFallback } = useSpreadsheetClipboard(gridRef, state, readOnly);
|
|
1501
1818
|
const { fillTarget, startFill, extendFill } = useFillHandle(state);
|
|
1502
|
-
const [menu, setMenu] = (0,
|
|
1819
|
+
const [menu, setMenu] = (0, import_react22.useState)(null);
|
|
1503
1820
|
const filter = state.document.table?.filter;
|
|
1504
|
-
const filteredColIds = (0,
|
|
1821
|
+
const filteredColIds = (0, import_react22.useMemo)(
|
|
1505
1822
|
() => new Set(filter?.enabled ? filter.rules.map((r) => r.colId) : []),
|
|
1506
1823
|
[filter]
|
|
1507
1824
|
);
|
|
1508
|
-
const handleCellContextMenu = (0,
|
|
1825
|
+
const handleCellContextMenu = (0, import_react22.useCallback)((rIdx, cIdx, e) => {
|
|
1509
1826
|
if (readOnly) return;
|
|
1510
1827
|
e.preventDefault();
|
|
1511
1828
|
if (state.editingCell) state.commitEditing();
|
|
@@ -1514,28 +1831,28 @@ var SpreadsheetEditor = ({
|
|
|
1514
1831
|
}
|
|
1515
1832
|
setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet5.getSpreadsheetMenuItems)(state.controller, { row: rIdx, col: cIdx }) });
|
|
1516
1833
|
}, [readOnly, state]);
|
|
1517
|
-
const activeRawValue = (0,
|
|
1834
|
+
const activeRawValue = (0, import_react22.useMemo)(() => {
|
|
1518
1835
|
if (!state.activeCell) return "";
|
|
1519
1836
|
const row = state.document.rows[state.activeCell.row];
|
|
1520
1837
|
const col = state.document.columns[state.activeCell.col];
|
|
1521
1838
|
if (!row || !col) return "";
|
|
1522
1839
|
return state.getCell(row.id, col.id).raw;
|
|
1523
1840
|
}, [state.activeCell, state.document]);
|
|
1524
|
-
const activeSpill = (0,
|
|
1841
|
+
const activeSpill = (0, import_react22.useMemo)(
|
|
1525
1842
|
() => state.activeCell ? state.controller.getSpillAt(state.activeCell.row, state.activeCell.col) : null,
|
|
1526
1843
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1527
1844
|
[state.controller, state.activeCell, state.document]
|
|
1528
1845
|
);
|
|
1529
1846
|
const spillFormula = activeSpill && !activeRawValue && activeSpill.key !== coordKey(state.activeCell) ? activeSpill.formula : "";
|
|
1530
|
-
const coordLabel = (0,
|
|
1847
|
+
const coordLabel = (0, import_react22.useMemo)(() => {
|
|
1531
1848
|
if (!state.activeCell) return "--";
|
|
1532
1849
|
const colName = (0, import_spreadsheet5.indexToColName)(state.activeCell.col);
|
|
1533
1850
|
return `${colName}${state.activeCell.row + 1}`;
|
|
1534
1851
|
}, [state.activeCell]);
|
|
1535
|
-
const [formulaDraft, setFormulaDraft] = (0,
|
|
1852
|
+
const [formulaDraft, setFormulaDraft] = (0, import_react22.useState)(null);
|
|
1536
1853
|
const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
|
|
1537
1854
|
const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
|
|
1538
|
-
(0,
|
|
1855
|
+
(0, import_react22.useEffect)(() => {
|
|
1539
1856
|
setFormulaDraft(null);
|
|
1540
1857
|
}, [state.activeCell?.row, state.activeCell?.col]);
|
|
1541
1858
|
const commitFormulaBar = () => {
|
|
@@ -1551,19 +1868,19 @@ var SpreadsheetEditor = ({
|
|
|
1551
1868
|
}
|
|
1552
1869
|
setFormulaDraft(null);
|
|
1553
1870
|
};
|
|
1554
|
-
const handleCellClick = (0,
|
|
1871
|
+
const handleCellClick = (0, import_react22.useCallback)((rIdx, cIdx, e) => {
|
|
1555
1872
|
if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
|
|
1556
1873
|
state.commitEditing();
|
|
1557
1874
|
}
|
|
1558
1875
|
state.selectCell(rIdx, cIdx, e.shiftKey);
|
|
1559
1876
|
}, [state]);
|
|
1560
|
-
const handleCellDblClick = (0,
|
|
1877
|
+
const handleCellDblClick = (0, import_react22.useCallback)((rIdx, cIdx) => {
|
|
1561
1878
|
if (readOnly) return;
|
|
1562
1879
|
const col = state.document.columns[cIdx];
|
|
1563
1880
|
if (col?.readOnly) return;
|
|
1564
1881
|
state.startEditing(rIdx, cIdx);
|
|
1565
1882
|
}, [readOnly, state]);
|
|
1566
|
-
const handleKeyDown = (0,
|
|
1883
|
+
const handleKeyDown = (0, import_react22.useCallback)((e) => {
|
|
1567
1884
|
if (state.editingCell) {
|
|
1568
1885
|
if (e.key === "Enter") {
|
|
1569
1886
|
e.preventDefault();
|
|
@@ -1632,11 +1949,11 @@ var SpreadsheetEditor = ({
|
|
|
1632
1949
|
}
|
|
1633
1950
|
}
|
|
1634
1951
|
}, [readOnly, state, copyShortcutFallback]);
|
|
1635
|
-
const stateRef = (0,
|
|
1952
|
+
const stateRef = (0, import_react22.useRef)(state);
|
|
1636
1953
|
stateRef.current = state;
|
|
1637
|
-
const onColumnResizeRef = (0,
|
|
1954
|
+
const onColumnResizeRef = (0, import_react22.useRef)(onColumnResize);
|
|
1638
1955
|
onColumnResizeRef.current = onColumnResize;
|
|
1639
|
-
(0,
|
|
1956
|
+
(0, import_react22.useEffect)(() => {
|
|
1640
1957
|
if (!resizingColId) return;
|
|
1641
1958
|
if (typeof document !== "undefined") {
|
|
1642
1959
|
document.body.style.cursor = "col-resize";
|
|
@@ -1687,7 +2004,7 @@ var SpreadsheetEditor = ({
|
|
|
1687
2004
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
1688
2005
|
};
|
|
1689
2006
|
}, [resizingColId, resizeStartX, resizeStartWidth]);
|
|
1690
|
-
const measureElementContentWidth = (0,
|
|
2007
|
+
const measureElementContentWidth = (0, import_react22.useCallback)((el, container) => {
|
|
1691
2008
|
if (typeof document === "undefined") return 0;
|
|
1692
2009
|
let maxW = el.scrollWidth || 0;
|
|
1693
2010
|
const firstChild = el.firstElementChild;
|
|
@@ -1735,7 +2052,7 @@ var SpreadsheetEditor = ({
|
|
|
1735
2052
|
}
|
|
1736
2053
|
return maxW;
|
|
1737
2054
|
}, []);
|
|
1738
|
-
const autoFitColumn = (0,
|
|
2055
|
+
const autoFitColumn = (0, import_react22.useCallback)((colId, colIndex) => {
|
|
1739
2056
|
const col = state.document.columns.find((c) => c.id === colId);
|
|
1740
2057
|
if (!col) return;
|
|
1741
2058
|
let calculatedWidth = 0;
|
|
@@ -1771,12 +2088,12 @@ var SpreadsheetEditor = ({
|
|
|
1771
2088
|
onColumnResize(updatedCol.id, updatedCol.width || 130);
|
|
1772
2089
|
}
|
|
1773
2090
|
}, [state, measureElementContentWidth, onColumnResize]);
|
|
1774
|
-
const handleResizeDblClick = (0,
|
|
2091
|
+
const handleResizeDblClick = (0, import_react22.useCallback)((colId, colIndex, e) => {
|
|
1775
2092
|
e.preventDefault();
|
|
1776
2093
|
e.stopPropagation();
|
|
1777
2094
|
autoFitColumn(colId, colIndex);
|
|
1778
2095
|
}, [autoFitColumn]);
|
|
1779
|
-
const handleHeaderDblClick = (0,
|
|
2096
|
+
const handleHeaderDblClick = (0, import_react22.useCallback)((colId, colIndex, e) => {
|
|
1780
2097
|
const target = e.currentTarget;
|
|
1781
2098
|
if (target) {
|
|
1782
2099
|
const rect = target.getBoundingClientRect();
|
|
@@ -1798,7 +2115,7 @@ var SpreadsheetEditor = ({
|
|
|
1798
2115
|
const isActiveCell = (rIdx, cIdx) => {
|
|
1799
2116
|
return state.activeCell?.row === rIdx && state.activeCell?.col === cIdx;
|
|
1800
2117
|
};
|
|
1801
|
-
return /* @__PURE__ */ (0,
|
|
2118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1802
2119
|
"div",
|
|
1803
2120
|
{
|
|
1804
2121
|
ref: gridRef,
|
|
@@ -1808,10 +2125,10 @@ var SpreadsheetEditor = ({
|
|
|
1808
2125
|
role: "grid",
|
|
1809
2126
|
"aria-label": "Spreadsheet",
|
|
1810
2127
|
children: [
|
|
1811
|
-
/* @__PURE__ */ (0,
|
|
1812
|
-
/* @__PURE__ */ (0,
|
|
1813
|
-
/* @__PURE__ */ (0,
|
|
1814
|
-
/* @__PURE__ */ (0,
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2 border-b border-border bg-muted/20 px-3 py-1.5 text-xs font-mono", children: [
|
|
2129
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex h-6 min-w-[3rem] items-center justify-center rounded border border-border bg-background px-1.5 font-semibold text-foreground", children: coordLabel }),
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex items-center text-muted-foreground select-none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "italic font-serif font-bold text-sm text-primary", children: "fx" }) }),
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1815
2132
|
"input",
|
|
1816
2133
|
{
|
|
1817
2134
|
ref: formulaBarRef,
|
|
@@ -1847,7 +2164,7 @@ var SpreadsheetEditor = ({
|
|
|
1847
2164
|
}
|
|
1848
2165
|
}
|
|
1849
2166
|
),
|
|
1850
|
-
!formulaBarReadOnly && /* @__PURE__ */ (0,
|
|
2167
|
+
!formulaBarReadOnly && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1851
2168
|
FormulaHints,
|
|
1852
2169
|
{
|
|
1853
2170
|
inputRef: formulaBarRef,
|
|
@@ -1856,10 +2173,10 @@ var SpreadsheetEditor = ({
|
|
|
1856
2173
|
}
|
|
1857
2174
|
)
|
|
1858
2175
|
] }),
|
|
1859
|
-
/* @__PURE__ */ (0,
|
|
1860
|
-
/* @__PURE__ */ (0,
|
|
1861
|
-
/* @__PURE__ */ (0,
|
|
1862
|
-
view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ (0,
|
|
2176
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "relative flex-1 overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { className: "border-collapse table-fixed w-max min-w-full", children: [
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { className: "h-7 bg-muted sticky top-0 z-20 border-b border-border shadow-xs", children: [
|
|
2178
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-medium", children: "#" }),
|
|
2179
|
+
view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1863
2180
|
"th",
|
|
1864
2181
|
{
|
|
1865
2182
|
"data-col": cIdx,
|
|
@@ -1874,16 +2191,16 @@ var SpreadsheetEditor = ({
|
|
|
1874
2191
|
onClick: () => onColumnHeaderClick?.(col),
|
|
1875
2192
|
onDoubleClick: (e) => handleHeaderDblClick(col.id, cIdx, e),
|
|
1876
2193
|
children: [
|
|
1877
|
-
/* @__PURE__ */ (0,
|
|
1878
|
-
/* @__PURE__ */ (0,
|
|
1879
|
-
filteredColIds.has(col.id) && /* @__PURE__ */ (0,
|
|
1880
|
-
/* @__PURE__ */ (0,
|
|
2194
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between gap-1 min-w-0 overflow-hidden truncate", children: [
|
|
2195
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "truncate font-semibold text-foreground text-xs min-w-0", children: col.title }),
|
|
2196
|
+
filteredColIds.has(col.id) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[10px] text-primary shrink-0", title: "Filtered", "data-filtered": "true", children: "\u23F7" }),
|
|
2197
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "text-[10px] text-muted-foreground/70 font-mono font-normal shrink-0", children: [
|
|
1881
2198
|
"(",
|
|
1882
2199
|
col.key,
|
|
1883
2200
|
")"
|
|
1884
2201
|
] })
|
|
1885
2202
|
] }),
|
|
1886
|
-
/* @__PURE__ */ (0,
|
|
2203
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1887
2204
|
"div",
|
|
1888
2205
|
{
|
|
1889
2206
|
className: "col-resize-handle",
|
|
@@ -1900,7 +2217,7 @@ var SpreadsheetEditor = ({
|
|
|
1900
2217
|
onDoubleClick: (e) => handleResizeDblClick(col.id, cIdx, e),
|
|
1901
2218
|
role: "separator",
|
|
1902
2219
|
"aria-orientation": "vertical",
|
|
1903
|
-
children: /* @__PURE__ */ (0,
|
|
2220
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1904
2221
|
"div",
|
|
1905
2222
|
{
|
|
1906
2223
|
className: "col-resize-handle-line",
|
|
@@ -1919,19 +2236,19 @@ var SpreadsheetEditor = ({
|
|
|
1919
2236
|
},
|
|
1920
2237
|
col.id
|
|
1921
2238
|
)),
|
|
1922
|
-
onAddColumnClick && /* @__PURE__ */ (0,
|
|
2239
|
+
onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1923
2240
|
"th",
|
|
1924
2241
|
{
|
|
1925
2242
|
className: "w-10 min-w-[2.5rem] px-1 text-center bg-muted/40 hover:bg-muted cursor-pointer transition-colors",
|
|
1926
2243
|
onClick: onAddColumnClick,
|
|
1927
2244
|
title: "Add Column",
|
|
1928
|
-
children: /* @__PURE__ */ (0,
|
|
2245
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs font-bold text-muted-foreground", children: "+" })
|
|
1929
2246
|
}
|
|
1930
2247
|
)
|
|
1931
2248
|
] }) }),
|
|
1932
|
-
/* @__PURE__ */ (0,
|
|
2249
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: view.rows.map((viewRow) => {
|
|
1933
2250
|
if (viewRow.kind === "group") {
|
|
1934
|
-
return /* @__PURE__ */ (0,
|
|
2251
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1935
2252
|
SpreadsheetGroupRow,
|
|
1936
2253
|
{
|
|
1937
2254
|
group: viewRow.group,
|
|
@@ -1945,14 +2262,14 @@ var SpreadsheetEditor = ({
|
|
|
1945
2262
|
}
|
|
1946
2263
|
const displayRowIndex = viewRow.index;
|
|
1947
2264
|
const selection = state.selectedRange ? (0, import_spreadsheet5.normalizeRange)(state.selectedRange) : null;
|
|
1948
|
-
return /* @__PURE__ */ (0,
|
|
2265
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1949
2266
|
"tr",
|
|
1950
2267
|
{
|
|
1951
2268
|
"data-row": displayRowIndex,
|
|
1952
2269
|
className: `border-b border-border hover:bg-muted/10 transition-colors ${viewRow.section !== "body" ? "bg-muted/30 font-semibold" : ""}`,
|
|
1953
2270
|
style: { height: viewRow.row.height || 32 },
|
|
1954
2271
|
children: [
|
|
1955
|
-
/* @__PURE__ */ (0,
|
|
2272
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1956
2273
|
"td",
|
|
1957
2274
|
{
|
|
1958
2275
|
className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none",
|
|
@@ -1973,7 +2290,7 @@ var SpreadsheetEditor = ({
|
|
|
1973
2290
|
const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;
|
|
1974
2291
|
const inFillPreview = !!fillTarget && !selected && (0, import_spreadsheet5.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
|
|
1975
2292
|
const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_spreadsheet5.rangeContains)(span.merge, selection.endRow, selection.endCol) : selection.endRow === rIdx && selection.endCol === cIdx);
|
|
1976
|
-
return /* @__PURE__ */ (0,
|
|
2293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1977
2294
|
"td",
|
|
1978
2295
|
{
|
|
1979
2296
|
"data-row": rIdx,
|
|
@@ -1992,8 +2309,8 @@ var SpreadsheetEditor = ({
|
|
|
1992
2309
|
onContextMenu: (e) => handleCellContextMenu(rIdx, cIdx, e),
|
|
1993
2310
|
onMouseOver: () => extendFill(displayRowIndex, viewCol.index),
|
|
1994
2311
|
children: [
|
|
1995
|
-
isEditing ? /* @__PURE__ */ (0,
|
|
1996
|
-
/* @__PURE__ */ (0,
|
|
2312
|
+
isEditing ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2313
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1997
2314
|
"input",
|
|
1998
2315
|
{
|
|
1999
2316
|
ref: cellInputRef,
|
|
@@ -2009,17 +2326,10 @@ var SpreadsheetEditor = ({
|
|
|
2009
2326
|
autoFocus: true
|
|
2010
2327
|
}
|
|
2011
2328
|
),
|
|
2012
|
-
/* @__PURE__ */ (0,
|
|
2013
|
-
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0,
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
2017
|
-
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
2018
|
-
children: (0, import_spreadsheet5.formatCellDisplay)(cell)
|
|
2019
|
-
}
|
|
2020
|
-
),
|
|
2021
|
-
activeSpill && (0, import_spreadsheet5.rangeContains)(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
|
|
2022
|
-
showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2329
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FormulaHints, { inputRef: cellInputRef, value: state.draftValue, onAccept: state.setDraftValue })
|
|
2330
|
+
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CellText, { cell }),
|
|
2331
|
+
activeSpill && (0, import_spreadsheet5.rangeContains)(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
|
|
2332
|
+
showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2023
2333
|
"div",
|
|
2024
2334
|
{
|
|
2025
2335
|
className: "spreadsheet-fill-handle",
|
|
@@ -2034,14 +2344,14 @@ var SpreadsheetEditor = ({
|
|
|
2034
2344
|
viewCol.column.id
|
|
2035
2345
|
);
|
|
2036
2346
|
}),
|
|
2037
|
-
onAddColumnClick && /* @__PURE__ */ (0,
|
|
2347
|
+
onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
|
|
2038
2348
|
]
|
|
2039
2349
|
},
|
|
2040
2350
|
viewRow.row.id
|
|
2041
2351
|
);
|
|
2042
2352
|
}) })
|
|
2043
2353
|
] }) }),
|
|
2044
|
-
menu && /* @__PURE__ */ (0,
|
|
2354
|
+
menu && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2045
2355
|
SpreadsheetContextMenu,
|
|
2046
2356
|
{
|
|
2047
2357
|
items: menu.items,
|
|
@@ -2053,7 +2363,7 @@ var SpreadsheetEditor = ({
|
|
|
2053
2363
|
}
|
|
2054
2364
|
}
|
|
2055
2365
|
),
|
|
2056
|
-
/* @__PURE__ */ (0,
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("style", { children: `
|
|
2057
2367
|
.col-resize-handle:hover .col-resize-handle-line {
|
|
2058
2368
|
background-color: var(--primary, #6366f1);
|
|
2059
2369
|
opacity: 0.75;
|
|
@@ -2076,10 +2386,10 @@ var SpreadsheetEditor = ({
|
|
|
2076
2386
|
};
|
|
2077
2387
|
|
|
2078
2388
|
// src/slots.tsx
|
|
2079
|
-
var
|
|
2080
|
-
var
|
|
2389
|
+
var import_react23 = require("react");
|
|
2390
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2081
2391
|
var defaultSlots = {
|
|
2082
|
-
Button: (props) => /* @__PURE__ */ (0,
|
|
2392
|
+
Button: (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2083
2393
|
"button",
|
|
2084
2394
|
{
|
|
2085
2395
|
type: "button",
|
|
@@ -2089,112 +2399,128 @@ var defaultSlots = {
|
|
|
2089
2399
|
children: props.children
|
|
2090
2400
|
}
|
|
2091
2401
|
),
|
|
2092
|
-
Tooltip: (props) => /* @__PURE__ */ (0,
|
|
2093
|
-
NodeHeader: (props) => /* @__PURE__ */ (0,
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2402
|
+
Tooltip: (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: `pixerate-tooltip-container ${props.className || ""}`, title: String(props.content), children: props.children }),
|
|
2403
|
+
NodeHeader: (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `pixerate-node-header flex items-center justify-between ${props.className || ""}`, children: [
|
|
2404
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2095
2405
|
props.icon,
|
|
2096
|
-
/* @__PURE__ */ (0,
|
|
2406
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold", children: props.title })
|
|
2097
2407
|
] }),
|
|
2098
|
-
props.onClose && /* @__PURE__ */ (0,
|
|
2408
|
+
props.onClose && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", onClick: props.onClose, className: "opacity-70 hover:opacity-100", children: "\xD7" })
|
|
2099
2409
|
] })
|
|
2100
2410
|
};
|
|
2101
|
-
var EditorSlotsContext = (0,
|
|
2411
|
+
var EditorSlotsContext = (0, import_react23.createContext)(defaultSlots);
|
|
2102
2412
|
function EditorSlotsProvider({ slots, children }) {
|
|
2103
|
-
const mergedSlots = (0,
|
|
2104
|
-
return /* @__PURE__ */ (0,
|
|
2413
|
+
const mergedSlots = (0, import_react23.useMemo)(() => ({ ...defaultSlots, ...slots }), [slots]);
|
|
2414
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(EditorSlotsContext.Provider, { value: mergedSlots, children });
|
|
2105
2415
|
}
|
|
2106
2416
|
function useEditorSlots() {
|
|
2107
|
-
return (0,
|
|
2417
|
+
return (0, import_react23.useContext)(EditorSlotsContext);
|
|
2108
2418
|
}
|
|
2109
2419
|
|
|
2110
2420
|
// src/image-editor/useImageEditor.ts
|
|
2111
|
-
var
|
|
2421
|
+
var import_react24 = require("react");
|
|
2112
2422
|
var import_image_editor = require("@pixerate/editor/image-editor");
|
|
2113
2423
|
function useImageEditor(options = {}) {
|
|
2114
|
-
const controllerRef = (0,
|
|
2424
|
+
const controllerRef = (0, import_react24.useRef)(null);
|
|
2115
2425
|
if (!controllerRef.current) {
|
|
2116
2426
|
controllerRef.current = new import_image_editor.ImageEditorController(options);
|
|
2117
2427
|
}
|
|
2118
2428
|
const controller = controllerRef.current;
|
|
2119
|
-
const [state, setState] = (0,
|
|
2120
|
-
const [historyTicks, setHistoryTicks] = (0,
|
|
2121
|
-
(0,
|
|
2429
|
+
const [state, setState] = (0, import_react24.useState)(() => controller.getState());
|
|
2430
|
+
const [historyTicks, setHistoryTicks] = (0, import_react24.useState)(0);
|
|
2431
|
+
const [histogram, setHistogram] = (0, import_react24.useState)(() => controller.getHistogram());
|
|
2432
|
+
(0, import_react24.useEffect)(() => controller.subscribeHistogram(setHistogram), [controller]);
|
|
2433
|
+
(0, import_react24.useEffect)(() => {
|
|
2122
2434
|
const unsub = controller.subscribe((next) => {
|
|
2123
2435
|
setState(next);
|
|
2124
2436
|
setHistoryTicks((t) => t + 1);
|
|
2125
2437
|
});
|
|
2126
2438
|
return unsub;
|
|
2127
2439
|
}, [controller]);
|
|
2128
|
-
const loadedImageRef = (0,
|
|
2129
|
-
(0,
|
|
2440
|
+
const loadedImageRef = (0, import_react24.useRef)(options.image);
|
|
2441
|
+
(0, import_react24.useEffect)(() => {
|
|
2130
2442
|
if (options.image === loadedImageRef.current) return;
|
|
2131
2443
|
loadedImageRef.current = options.image;
|
|
2132
2444
|
if (options.image) {
|
|
2133
2445
|
controller.loadImage(options.image);
|
|
2134
2446
|
}
|
|
2135
2447
|
}, [options.image, controller]);
|
|
2136
|
-
const setTool = (0,
|
|
2137
|
-
const setCrop = (0,
|
|
2448
|
+
const setTool = (0, import_react24.useCallback)((tool) => controller.setTool(tool), [controller]);
|
|
2449
|
+
const setCrop = (0, import_react24.useCallback)(
|
|
2138
2450
|
(crop, addToHistory = true) => controller.setCrop(crop, addToHistory),
|
|
2139
2451
|
[controller]
|
|
2140
2452
|
);
|
|
2141
|
-
const applyCropPreset = (0,
|
|
2142
|
-
const resetCrop = (0,
|
|
2143
|
-
const rotate = (0,
|
|
2144
|
-
const setRotation = (0,
|
|
2145
|
-
const flipHorizontal = (0,
|
|
2146
|
-
const flipVertical = (0,
|
|
2147
|
-
const setAdjustments = (0,
|
|
2453
|
+
const applyCropPreset = (0, import_react24.useCallback)((ratio) => controller.applyCropPreset(ratio), [controller]);
|
|
2454
|
+
const resetCrop = (0, import_react24.useCallback)(() => controller.resetCrop(), [controller]);
|
|
2455
|
+
const rotate = (0, import_react24.useCallback)((deg) => controller.rotate(deg), [controller]);
|
|
2456
|
+
const setRotation = (0, import_react24.useCallback)((deg) => controller.setRotation(deg), [controller]);
|
|
2457
|
+
const flipHorizontal = (0, import_react24.useCallback)(() => controller.flipHorizontal(), [controller]);
|
|
2458
|
+
const flipVertical = (0, import_react24.useCallback)(() => controller.flipVertical(), [controller]);
|
|
2459
|
+
const setAdjustments = (0, import_react24.useCallback)(
|
|
2148
2460
|
(partial, commitToHistory = true) => controller.setAdjustments(partial, commitToHistory),
|
|
2149
2461
|
[controller]
|
|
2150
2462
|
);
|
|
2151
|
-
const resetAdjustments = (0,
|
|
2152
|
-
const upgradeProcess = (0,
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2463
|
+
const resetAdjustments = (0, import_react24.useCallback)(() => controller.resetAdjustments(), [controller]);
|
|
2464
|
+
const upgradeProcess = (0, import_react24.useCallback)(() => controller.upgradeProcess(), [controller]);
|
|
2465
|
+
const addAdjustmentLayer = (0, import_react24.useCallback)(
|
|
2466
|
+
(init, index) => controller.addAdjustmentLayer(init, index),
|
|
2467
|
+
[controller]
|
|
2468
|
+
);
|
|
2469
|
+
const updateAdjustmentLayer = (0, import_react24.useCallback)(
|
|
2470
|
+
(id, update, commitToHistory = true) => controller.updateAdjustmentLayer(id, update, commitToHistory),
|
|
2471
|
+
[controller]
|
|
2472
|
+
);
|
|
2473
|
+
const removeAdjustmentLayer = (0, import_react24.useCallback)((id) => controller.removeAdjustmentLayer(id), [controller]);
|
|
2474
|
+
const moveAdjustmentLayer = (0, import_react24.useCallback)((id, to) => controller.moveAdjustmentLayer(id, to), [controller]);
|
|
2475
|
+
const toggleAdjustmentLayer = (0, import_react24.useCallback)(
|
|
2476
|
+
(id, enabled) => controller.toggleAdjustmentLayer(id, enabled),
|
|
2477
|
+
[controller]
|
|
2478
|
+
);
|
|
2479
|
+
const setDepthMask = (0, import_react24.useCallback)((partial) => controller.setDepthMask(partial), [controller]);
|
|
2480
|
+
const resetDepthMask = (0, import_react24.useCallback)(() => controller.resetDepthMask(), [controller]);
|
|
2481
|
+
const addAnnotation = (0, import_react24.useCallback)((ann) => controller.addAnnotation(ann), [controller]);
|
|
2482
|
+
const updateAnnotation = (0, import_react24.useCallback)(
|
|
2157
2483
|
(id, partial, commitToHistory = true) => controller.updateAnnotation(id, partial, commitToHistory),
|
|
2158
2484
|
[controller]
|
|
2159
2485
|
);
|
|
2160
|
-
const removeAnnotation = (0,
|
|
2161
|
-
const clearAnnotations = (0,
|
|
2162
|
-
const selectAnnotation = (0,
|
|
2163
|
-
const undo = (0,
|
|
2164
|
-
const redo = (0,
|
|
2165
|
-
const reset = (0,
|
|
2166
|
-
const zoomIn = (0,
|
|
2167
|
-
const zoomOut = (0,
|
|
2168
|
-
const resetZoom = (0,
|
|
2169
|
-
const setZoom = (0,
|
|
2170
|
-
const setPan = (0,
|
|
2171
|
-
const setComparing = (0,
|
|
2172
|
-
const loadImage = (0,
|
|
2173
|
-
const toDataURL = (0,
|
|
2174
|
-
const toBlob = (0,
|
|
2175
|
-
const toJSON = (0,
|
|
2176
|
-
const loadJSON = (0,
|
|
2177
|
-
const renderMask = (0,
|
|
2486
|
+
const removeAnnotation = (0, import_react24.useCallback)((id) => controller.removeAnnotation(id), [controller]);
|
|
2487
|
+
const clearAnnotations = (0, import_react24.useCallback)(() => controller.clearAnnotations(), [controller]);
|
|
2488
|
+
const selectAnnotation = (0, import_react24.useCallback)((id) => controller.selectAnnotation(id), [controller]);
|
|
2489
|
+
const undo = (0, import_react24.useCallback)(() => controller.undo(), [controller]);
|
|
2490
|
+
const redo = (0, import_react24.useCallback)(() => controller.redo(), [controller]);
|
|
2491
|
+
const reset = (0, import_react24.useCallback)(() => controller.reset(), [controller]);
|
|
2492
|
+
const zoomIn = (0, import_react24.useCallback)((factor) => controller.zoomIn(factor), [controller]);
|
|
2493
|
+
const zoomOut = (0, import_react24.useCallback)((factor) => controller.zoomOut(factor), [controller]);
|
|
2494
|
+
const resetZoom = (0, import_react24.useCallback)(() => controller.resetZoom(), [controller]);
|
|
2495
|
+
const setZoom = (0, import_react24.useCallback)((zoom) => controller.setZoom(zoom), [controller]);
|
|
2496
|
+
const setPan = (0, import_react24.useCallback)((pan) => controller.setPan(pan), [controller]);
|
|
2497
|
+
const setComparing = (0, import_react24.useCallback)((comp) => controller.setComparing(comp), [controller]);
|
|
2498
|
+
const loadImage = (0, import_react24.useCallback)((src) => controller.loadImage(src), [controller]);
|
|
2499
|
+
const toDataURL = (0, import_react24.useCallback)((opts) => controller.toDataURL(opts), [controller]);
|
|
2500
|
+
const toBlob = (0, import_react24.useCallback)((opts) => controller.toBlob(opts), [controller]);
|
|
2501
|
+
const toJSON = (0, import_react24.useCallback)(() => controller.toJSON(), [controller]);
|
|
2502
|
+
const loadJSON = (0, import_react24.useCallback)((data) => controller.loadJSON(data), [controller]);
|
|
2503
|
+
const renderMask = (0, import_react24.useCallback)(
|
|
2178
2504
|
(opts) => controller.renderMask(opts),
|
|
2179
2505
|
[controller]
|
|
2180
2506
|
);
|
|
2181
|
-
const toMaskDataURL = (0,
|
|
2507
|
+
const toMaskDataURL = (0, import_react24.useCallback)(
|
|
2182
2508
|
(opts) => controller.toMaskDataURL(opts),
|
|
2183
2509
|
[controller]
|
|
2184
2510
|
);
|
|
2185
|
-
const toSourceDataURL = (0,
|
|
2511
|
+
const toSourceDataURL = (0, import_react24.useCallback)(
|
|
2186
2512
|
(opts) => controller.toSourceDataURL(opts),
|
|
2187
2513
|
[controller]
|
|
2188
2514
|
);
|
|
2189
|
-
const applyInpaintedImage = (0,
|
|
2515
|
+
const applyInpaintedImage = (0, import_react24.useCallback)(
|
|
2190
2516
|
(newDataUrl) => controller.applyInpaintedImage(newDataUrl),
|
|
2191
2517
|
[controller]
|
|
2192
2518
|
);
|
|
2193
|
-
const applyBackgroundRemovedImage = (0,
|
|
2519
|
+
const applyBackgroundRemovedImage = (0, import_react24.useCallback)(
|
|
2194
2520
|
(newDataUrl) => controller.applyBackgroundRemovedImage(newDataUrl),
|
|
2195
2521
|
[controller]
|
|
2196
2522
|
);
|
|
2197
|
-
return (0,
|
|
2523
|
+
return (0, import_react24.useMemo)(
|
|
2198
2524
|
() => ({
|
|
2199
2525
|
controller,
|
|
2200
2526
|
state,
|
|
@@ -2211,6 +2537,12 @@ function useImageEditor(options = {}) {
|
|
|
2211
2537
|
setAdjustments,
|
|
2212
2538
|
resetAdjustments,
|
|
2213
2539
|
upgradeProcess,
|
|
2540
|
+
addAdjustmentLayer,
|
|
2541
|
+
updateAdjustmentLayer,
|
|
2542
|
+
removeAdjustmentLayer,
|
|
2543
|
+
moveAdjustmentLayer,
|
|
2544
|
+
toggleAdjustmentLayer,
|
|
2545
|
+
histogram,
|
|
2214
2546
|
setDepthMask,
|
|
2215
2547
|
resetDepthMask,
|
|
2216
2548
|
addAnnotation,
|
|
@@ -2239,14 +2571,445 @@ function useImageEditor(options = {}) {
|
|
|
2239
2571
|
applyBackgroundRemovedImage
|
|
2240
2572
|
}),
|
|
2241
2573
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2242
|
-
[controller, state, historyTicks]
|
|
2574
|
+
[controller, state, historyTicks, histogram]
|
|
2243
2575
|
);
|
|
2244
2576
|
}
|
|
2245
2577
|
|
|
2246
2578
|
// src/image-editor/ImageEditor.tsx
|
|
2247
|
-
var
|
|
2579
|
+
var import_react28 = __toESM(require("react"), 1);
|
|
2580
|
+
var import_image_editor6 = require("@pixerate/editor/image-editor");
|
|
2581
|
+
|
|
2582
|
+
// src/image-editor/ControlSlider.tsx
|
|
2248
2583
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
2249
|
-
var
|
|
2584
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2585
|
+
var ControlSlider = ({ spec, value, onChange, disabled, label }) => {
|
|
2586
|
+
const name = label ?? spec.label;
|
|
2587
|
+
const track = (0, import_image_editor2.controlTrackBackground)(spec);
|
|
2588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "data-control-id": spec.id, children: [
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
2590
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: name }),
|
|
2591
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-mono", children: (0, import_image_editor2.formatControlValue)(spec, value) })
|
|
2592
|
+
] }),
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2594
|
+
"input",
|
|
2595
|
+
{
|
|
2596
|
+
type: "range",
|
|
2597
|
+
min: spec.min,
|
|
2598
|
+
max: spec.max,
|
|
2599
|
+
step: spec.step,
|
|
2600
|
+
"aria-label": name,
|
|
2601
|
+
disabled,
|
|
2602
|
+
value,
|
|
2603
|
+
onChange: (e) => onChange(Number(e.target.value)),
|
|
2604
|
+
className: "w-full accent-indigo-500 disabled:opacity-40"
|
|
2605
|
+
}
|
|
2606
|
+
),
|
|
2607
|
+
track && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "h-0.5 rounded-full opacity-70", style: { background: track } })
|
|
2608
|
+
] });
|
|
2609
|
+
};
|
|
2610
|
+
|
|
2611
|
+
// src/image-editor/Histogram.tsx
|
|
2612
|
+
var import_react25 = require("react");
|
|
2613
|
+
var import_image_editor3 = require("@pixerate/editor/image-editor");
|
|
2614
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2615
|
+
var FILL = {
|
|
2616
|
+
luminance: "rgba(148, 163, 184, 0.45)",
|
|
2617
|
+
red: "rgba(239, 68, 68, 0.45)",
|
|
2618
|
+
green: "rgba(34, 197, 94, 0.45)",
|
|
2619
|
+
blue: "rgba(59, 130, 246, 0.45)"
|
|
2620
|
+
};
|
|
2621
|
+
var W = 256;
|
|
2622
|
+
var Histogram = ({ histogram, channel = "rgb", height = 64, className = "", style }) => {
|
|
2623
|
+
const channels = channel === "rgb" ? ["luminance", "red", "green", "blue"] : [channel];
|
|
2624
|
+
const paths = (0, import_react25.useMemo)(
|
|
2625
|
+
() => histogram && histogram.samples > 0 ? channels.map((c) => ({ c, d: (0, import_image_editor3.histogramPath)(histogram, c, W, height) })) : [],
|
|
2626
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2627
|
+
[histogram, channel, height]
|
|
2628
|
+
);
|
|
2629
|
+
const clipLow = histogram && histogram.samples ? Math.max(...histogram.shadows) / histogram.samples : 0;
|
|
2630
|
+
const clipHigh = histogram && histogram.samples ? Math.max(...histogram.highlights) / histogram.samples : 0;
|
|
2631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
2632
|
+
"svg",
|
|
2633
|
+
{
|
|
2634
|
+
viewBox: `0 0 ${W} ${height}`,
|
|
2635
|
+
preserveAspectRatio: "none",
|
|
2636
|
+
role: "img",
|
|
2637
|
+
"aria-label": histogram ? `Histogram of ${histogram.samples} pixels` : "Histogram (no data)",
|
|
2638
|
+
"data-testid": "image-editor-histogram",
|
|
2639
|
+
className: `w-full rounded bg-slate-950/60 ${className}`,
|
|
2640
|
+
style: { height, ...style },
|
|
2641
|
+
children: [
|
|
2642
|
+
paths.map(({ c, d }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d, fill: FILL[c], stroke: "none" }, c)),
|
|
2643
|
+
clipLow > 5e-3 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: 0, y: 0, width: 3, height, fill: "#3b82f6", "data-testid": "histogram-clip-shadows" }),
|
|
2644
|
+
clipHigh > 5e-3 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { x: W - 3, y: 0, width: 3, height, fill: "#ef4444", "data-testid": "histogram-clip-highlights" })
|
|
2645
|
+
]
|
|
2646
|
+
}
|
|
2647
|
+
);
|
|
2648
|
+
};
|
|
2649
|
+
function useImageHistogram(controller) {
|
|
2650
|
+
const [histogram, setHistogram] = (0, import_react25.useState)(() => controller.getHistogram());
|
|
2651
|
+
(0, import_react25.useEffect)(() => controller.subscribeHistogram(setHistogram), [controller]);
|
|
2652
|
+
return histogram;
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
// src/image-editor/AdjustmentLayersPanel.tsx
|
|
2656
|
+
var import_react27 = require("react");
|
|
2657
|
+
var import_image_editor5 = require("@pixerate/editor/image-editor");
|
|
2658
|
+
|
|
2659
|
+
// src/image-editor/CurvesEditor.tsx
|
|
2660
|
+
var import_react26 = require("react");
|
|
2661
|
+
var import_image_editor4 = require("@pixerate/editor/image-editor");
|
|
2662
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2663
|
+
var BOX = 256;
|
|
2664
|
+
var STROKE = { master: "#e2e8f0", red: "#ef4444", green: "#22c55e", blue: "#3b82f6" };
|
|
2665
|
+
var CurvesEditor = ({ points, onChange, histogram, channel = "master", size = 200 }) => {
|
|
2666
|
+
const svgRef = (0, import_react26.useRef)(null);
|
|
2667
|
+
const [drag, setDrag] = (0, import_react26.useState)(null);
|
|
2668
|
+
const toBox = (e) => {
|
|
2669
|
+
const rect = svgRef.current?.getBoundingClientRect();
|
|
2670
|
+
if (!rect || !rect.width || !rect.height) return { x: 0, y: 0 };
|
|
2671
|
+
return { x: (e.clientX - rect.left) / rect.width * BOX, y: (e.clientY - rect.top) / rect.height * BOX };
|
|
2672
|
+
};
|
|
2673
|
+
const onPointerDown = (e) => {
|
|
2674
|
+
const { x, y } = toBox(e);
|
|
2675
|
+
let index = (0, import_image_editor4.hitTestCurvePoint)(points, x, y, BOX, BOX, 10);
|
|
2676
|
+
if (index === -1) {
|
|
2677
|
+
const inserted = (0, import_image_editor4.insertCurvePoint)(points, (0, import_image_editor4.boxToCurvePoint)(x, y, BOX, BOX));
|
|
2678
|
+
onChange(inserted.points, true);
|
|
2679
|
+
index = inserted.index;
|
|
2680
|
+
} else {
|
|
2681
|
+
onChange(points, true);
|
|
2682
|
+
}
|
|
2683
|
+
setDrag(index);
|
|
2684
|
+
e.target.setPointerCapture?.(e.pointerId);
|
|
2685
|
+
};
|
|
2686
|
+
const onPointerMove = (e) => {
|
|
2687
|
+
if (drag === null) return;
|
|
2688
|
+
onChange((0, import_image_editor4.moveCurvePoint)(points, drag, (0, import_image_editor4.boxToCurvePoint)(toBox(e).x, toBox(e).y, BOX, BOX)), false);
|
|
2689
|
+
};
|
|
2690
|
+
const onDoubleClick = (e) => {
|
|
2691
|
+
const { x, y } = toBox(e);
|
|
2692
|
+
const index = (0, import_image_editor4.hitTestCurvePoint)(points, x, y, BOX, BOX, 10);
|
|
2693
|
+
if (index !== -1 && points.length > 2) onChange((0, import_image_editor4.removeCurvePoint)(points, index), true);
|
|
2694
|
+
};
|
|
2695
|
+
const histChannel = channel === "master" ? "luminance" : channel;
|
|
2696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
2697
|
+
"svg",
|
|
2698
|
+
{
|
|
2699
|
+
ref: svgRef,
|
|
2700
|
+
viewBox: `0 0 ${BOX} ${BOX}`,
|
|
2701
|
+
width: size,
|
|
2702
|
+
height: size,
|
|
2703
|
+
role: "application",
|
|
2704
|
+
"aria-label": `${channel} curve`,
|
|
2705
|
+
"data-testid": "curves-editor",
|
|
2706
|
+
className: "rounded bg-slate-950/70 touch-none select-none cursor-crosshair",
|
|
2707
|
+
onPointerDown,
|
|
2708
|
+
onPointerMove,
|
|
2709
|
+
onPointerUp: () => setDrag(null),
|
|
2710
|
+
onPointerCancel: () => setDrag(null),
|
|
2711
|
+
onDoubleClick,
|
|
2712
|
+
children: [
|
|
2713
|
+
histogram && histogram.samples > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: (0, import_image_editor4.histogramPath)(histogram, histChannel, BOX, BOX), fill: "rgba(148, 163, 184, 0.25)" }),
|
|
2714
|
+
[64, 128, 192].map((v) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("g", { stroke: "rgba(148, 163, 184, 0.2)", strokeWidth: 1, children: [
|
|
2715
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("line", { x1: v, y1: 0, x2: v, y2: BOX }),
|
|
2716
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("line", { x1: 0, y1: v, x2: BOX, y2: v })
|
|
2717
|
+
] }, v)),
|
|
2718
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("line", { x1: 0, y1: BOX, x2: BOX, y2: 0, stroke: "rgba(148, 163, 184, 0.35)", strokeDasharray: "4 4" }),
|
|
2719
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: (0, import_image_editor4.curveSvgPath)(points, BOX, BOX), fill: "none", stroke: STROKE[channel], strokeWidth: 2 }),
|
|
2720
|
+
points.map((p, i) => {
|
|
2721
|
+
const b = (0, import_image_editor4.curvePointToBox)(p, BOX, BOX);
|
|
2722
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2723
|
+
"circle",
|
|
2724
|
+
{
|
|
2725
|
+
cx: b.x,
|
|
2726
|
+
cy: b.y,
|
|
2727
|
+
r: 5,
|
|
2728
|
+
fill: drag === i ? STROKE[channel] : "#0f172a",
|
|
2729
|
+
stroke: STROKE[channel],
|
|
2730
|
+
strokeWidth: 2,
|
|
2731
|
+
"aria-label": `Point ${p.input} to ${p.output}`
|
|
2732
|
+
},
|
|
2733
|
+
i
|
|
2734
|
+
);
|
|
2735
|
+
})
|
|
2736
|
+
]
|
|
2737
|
+
}
|
|
2738
|
+
);
|
|
2739
|
+
};
|
|
2740
|
+
|
|
2741
|
+
// src/image-editor/AdjustmentLayersPanel.tsx
|
|
2742
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2743
|
+
var CHANNELS = [
|
|
2744
|
+
{ id: "master", label: "RGB" },
|
|
2745
|
+
{ id: "red", label: "Red" },
|
|
2746
|
+
{ id: "green", label: "Green" },
|
|
2747
|
+
{ id: "blue", label: "Blue" }
|
|
2748
|
+
];
|
|
2749
|
+
var TONES = [
|
|
2750
|
+
{ id: "shadows", label: "Shadows" },
|
|
2751
|
+
{ id: "midtones", label: "Midtones" },
|
|
2752
|
+
{ id: "highlights", label: "Highlights" }
|
|
2753
|
+
];
|
|
2754
|
+
var selectClass = "bg-slate-800 border border-slate-700 rounded px-1.5 py-1 text-slate-200";
|
|
2755
|
+
var chipClass = (on) => `px-2 py-0.5 rounded text-[10px] ${on ? "bg-indigo-600 text-white" : "bg-slate-800 text-slate-400 hover:text-slate-200"}`;
|
|
2756
|
+
var HueRangeStrip = ({ bounds }) => {
|
|
2757
|
+
const pts = Array.from({ length: 73 }, (_, i) => `${i / 72 * 360},${20 - (0, import_image_editor5.hueRangeWeight)({ bounds }, i * 5) * 18}`).join(" ");
|
|
2758
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("svg", { viewBox: "0 0 360 20", preserveAspectRatio: "none", className: "w-full h-4 rounded", "data-testid": "hue-range-strip", children: [
|
|
2759
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("linearGradient", { id: "pixerate-hue-strip", children: [0, 60, 120, 180, 240, 300, 360].map((h) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("stop", { offset: `${h / 360 * 100}%`, stopColor: `hsl(${h}, 90%, 50%)` }, h)) }) }),
|
|
2760
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("rect", { width: 360, height: 20, fill: "url(#pixerate-hue-strip)", opacity: 0.6 }),
|
|
2761
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("polyline", { points: pts, fill: "none", stroke: "#fff", strokeWidth: 1.5 })
|
|
2762
|
+
] });
|
|
2763
|
+
};
|
|
2764
|
+
var AdjustmentLayersPanel = ({ controller, layers: layersProp, histogram }) => {
|
|
2765
|
+
const follow = layersProp === void 0;
|
|
2766
|
+
const [, setTick] = (0, import_react27.useState)(0);
|
|
2767
|
+
(0, import_react27.useEffect)(() => follow ? controller.subscribe(() => setTick((n) => n + 1)) : void 0, [controller, follow]);
|
|
2768
|
+
const layers = layersProp ?? controller.getAdjustmentLayers();
|
|
2769
|
+
const [newKind, setNewKind] = (0, import_react27.useState)("curves");
|
|
2770
|
+
const [selectedId, setSelectedId] = (0, import_react27.useState)(null);
|
|
2771
|
+
const [channel, setChannel] = (0, import_react27.useState)("master");
|
|
2772
|
+
const [range, setRange] = (0, import_react27.useState)(-1);
|
|
2773
|
+
const [tone, setTone] = (0, import_react27.useState)("midtones");
|
|
2774
|
+
const selected = layers.find((l) => l.id === selectedId) ?? null;
|
|
2775
|
+
const topFirst = [...layers].reverse();
|
|
2776
|
+
const setParam = (layer, path, value, commit = true) => controller.updateAdjustmentLayer(layer.id, { params: (0, import_image_editor5.setControlPath)(layer.params, path, value) }, commit);
|
|
2777
|
+
const slider = (layer, spec, label) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2778
|
+
ControlSlider,
|
|
2779
|
+
{
|
|
2780
|
+
spec,
|
|
2781
|
+
label,
|
|
2782
|
+
value: Number((0, import_image_editor5.getControlPath)(layer.params, spec.id) ?? spec.default),
|
|
2783
|
+
onChange: (v) => setParam(layer, spec.id, v)
|
|
2784
|
+
},
|
|
2785
|
+
spec.id
|
|
2786
|
+
);
|
|
2787
|
+
const controlsOf = (layer, filter = () => true) => import_image_editor5.ADJUSTMENT_LAYER_CONTROLS[layer.kind].filter(filter);
|
|
2788
|
+
const checkbox = (layer, path, label) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2789
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2790
|
+
"input",
|
|
2791
|
+
{
|
|
2792
|
+
type: "checkbox",
|
|
2793
|
+
checked: Boolean((0, import_image_editor5.getControlPath)(layer.params, path)),
|
|
2794
|
+
onChange: (e) => setParam(layer, path, e.target.checked),
|
|
2795
|
+
className: "accent-indigo-500"
|
|
2796
|
+
}
|
|
2797
|
+
),
|
|
2798
|
+
label
|
|
2799
|
+
] });
|
|
2800
|
+
const editor = (layer) => {
|
|
2801
|
+
switch (layer.kind) {
|
|
2802
|
+
case "curves":
|
|
2803
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2804
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Curve channel", children: CHANNELS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chipClass(channel === c.id), onClick: () => setChannel(c.id), children: c.label }, c.id)) }),
|
|
2805
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2806
|
+
CurvesEditor,
|
|
2807
|
+
{
|
|
2808
|
+
points: layer.params[channel],
|
|
2809
|
+
channel,
|
|
2810
|
+
histogram,
|
|
2811
|
+
onChange: (points, commit) => setParam(layer, channel, points, commit)
|
|
2812
|
+
}
|
|
2813
|
+
)
|
|
2814
|
+
] });
|
|
2815
|
+
case "levels":
|
|
2816
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2817
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Levels channel", children: CHANNELS.map((c) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chipClass(channel === c.id), onClick: () => setChannel(c.id), children: c.label }, c.id)) }),
|
|
2818
|
+
controlsOf(layer, (s) => s.id.startsWith(`${channel}.`)).map((s) => slider(layer, s))
|
|
2819
|
+
] });
|
|
2820
|
+
case "hueSaturation":
|
|
2821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2822
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-wrap gap-1", role: "group", "aria-label": "Hue range", children: [
|
|
2823
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chipClass(range === -1), onClick: () => setRange(-1), children: "Master" }),
|
|
2824
|
+
import_image_editor5.HUE_RANGE_LABELS.map((name, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chipClass(range === i), onClick: () => setRange(i), disabled: layer.params.colorize, children: name }, name))
|
|
2825
|
+
] }),
|
|
2826
|
+
range >= 0 && !layer.params.colorize && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(HueRangeStrip, { bounds: layer.params.ranges[range].bounds }),
|
|
2827
|
+
controlsOf(layer, (s) => range === -1 || layer.params.colorize ? !s.id.startsWith("ranges.") : s.id.startsWith(`ranges.${range}.`)).map(
|
|
2828
|
+
(s) => slider(layer, s)
|
|
2829
|
+
),
|
|
2830
|
+
range === -1 && checkbox(layer, "colorize", "Colorize")
|
|
2831
|
+
] });
|
|
2832
|
+
case "colorBalance":
|
|
2833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2834
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex gap-1", role: "group", "aria-label": "Tone", children: TONES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: chipClass(tone === t.id), onClick: () => setTone(t.id), children: t.label }, t.id)) }),
|
|
2835
|
+
controlsOf(layer, (s) => s.id.startsWith(`${tone}.`)).map((s) => slider(layer, s)),
|
|
2836
|
+
checkbox(layer, "preserveLuminosity", "Preserve luminosity")
|
|
2837
|
+
] });
|
|
2838
|
+
case "blackWhite":
|
|
2839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2840
|
+
controlsOf(layer).map((s) => slider(layer, s)),
|
|
2841
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2842
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2843
|
+
"input",
|
|
2844
|
+
{
|
|
2845
|
+
type: "checkbox",
|
|
2846
|
+
checked: layer.params.tint !== null,
|
|
2847
|
+
onChange: (e) => setParam(layer, "tint", e.target.checked ? "#e1d3b3" : null),
|
|
2848
|
+
className: "accent-indigo-500"
|
|
2849
|
+
}
|
|
2850
|
+
),
|
|
2851
|
+
"Tint",
|
|
2852
|
+
layer.params.tint && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2853
|
+
"input",
|
|
2854
|
+
{
|
|
2855
|
+
type: "color",
|
|
2856
|
+
"aria-label": "Tint colour",
|
|
2857
|
+
value: layer.params.tint,
|
|
2858
|
+
onChange: (e) => setParam(layer, "tint", e.target.value),
|
|
2859
|
+
className: "h-5 w-8 bg-transparent"
|
|
2860
|
+
}
|
|
2861
|
+
)
|
|
2862
|
+
] })
|
|
2863
|
+
] });
|
|
2864
|
+
case "photoFilter":
|
|
2865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2866
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 text-slate-300", children: [
|
|
2867
|
+
"Filter colour",
|
|
2868
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2869
|
+
"input",
|
|
2870
|
+
{
|
|
2871
|
+
type: "color",
|
|
2872
|
+
"aria-label": "Filter colour",
|
|
2873
|
+
value: layer.params.color,
|
|
2874
|
+
onChange: (e) => setParam(layer, "color", e.target.value),
|
|
2875
|
+
className: "h-5 w-8 bg-transparent"
|
|
2876
|
+
}
|
|
2877
|
+
)
|
|
2878
|
+
] }),
|
|
2879
|
+
controlsOf(layer).map((s) => slider(layer, s)),
|
|
2880
|
+
checkbox(layer, "preserveLuminosity", "Preserve luminosity")
|
|
2881
|
+
] });
|
|
2882
|
+
case "invert":
|
|
2883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-slate-500 text-[11px]", children: "Invert has no settings." });
|
|
2884
|
+
default:
|
|
2885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex flex-col gap-2", children: controlsOf(layer).map((s) => slider(layer, s)) });
|
|
2886
|
+
}
|
|
2887
|
+
};
|
|
2888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2 text-xs", "data-testid": "adjustment-layers-panel", children: [
|
|
2889
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Adjustment Layers" }) }),
|
|
2890
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-1.5", children: [
|
|
2891
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2892
|
+
"select",
|
|
2893
|
+
{
|
|
2894
|
+
"aria-label": "New adjustment layer kind",
|
|
2895
|
+
className: `${selectClass} flex-1`,
|
|
2896
|
+
value: newKind,
|
|
2897
|
+
onChange: (e) => setNewKind(e.target.value),
|
|
2898
|
+
children: import_image_editor5.ADJUSTMENT_KINDS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: k.kind, children: k.label }, k.kind))
|
|
2899
|
+
}
|
|
2900
|
+
),
|
|
2901
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2902
|
+
"button",
|
|
2903
|
+
{
|
|
2904
|
+
type: "button",
|
|
2905
|
+
className: "px-2 py-1 rounded bg-indigo-600 text-white hover:bg-indigo-500",
|
|
2906
|
+
onClick: () => {
|
|
2907
|
+
setSelectedId(controller.addAdjustmentLayer(newKind));
|
|
2908
|
+
setChannel("master");
|
|
2909
|
+
setRange(-1);
|
|
2910
|
+
},
|
|
2911
|
+
children: "Add Layer"
|
|
2912
|
+
}
|
|
2913
|
+
)
|
|
2914
|
+
] }),
|
|
2915
|
+
topFirst.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "flex flex-col gap-1", "aria-label": "Adjustment layers", children: topFirst.map((layer) => {
|
|
2916
|
+
const index = layers.indexOf(layer);
|
|
2917
|
+
const label = layer.name || (0, import_image_editor5.adjustmentKindLabel)(layer.kind);
|
|
2918
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2919
|
+
"li",
|
|
2920
|
+
{
|
|
2921
|
+
className: `flex items-center gap-1.5 rounded px-1.5 py-1 ${layer.id === selectedId ? "bg-indigo-600/20 ring-1 ring-indigo-500/50" : "bg-slate-800/60"}`,
|
|
2922
|
+
children: [
|
|
2923
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2924
|
+
"input",
|
|
2925
|
+
{
|
|
2926
|
+
type: "checkbox",
|
|
2927
|
+
"aria-label": `Show ${label}`,
|
|
2928
|
+
checked: layer.enabled,
|
|
2929
|
+
onChange: () => controller.toggleAdjustmentLayer(layer.id),
|
|
2930
|
+
className: "accent-indigo-500"
|
|
2931
|
+
}
|
|
2932
|
+
),
|
|
2933
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2934
|
+
"button",
|
|
2935
|
+
{
|
|
2936
|
+
type: "button",
|
|
2937
|
+
className: `flex-1 text-left truncate ${layer.enabled ? "text-slate-200" : "text-slate-500 line-through"}`,
|
|
2938
|
+
onClick: () => setSelectedId(layer.id === selectedId ? null : layer.id),
|
|
2939
|
+
"aria-pressed": layer.id === selectedId,
|
|
2940
|
+
children: label
|
|
2941
|
+
}
|
|
2942
|
+
),
|
|
2943
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2944
|
+
"button",
|
|
2945
|
+
{
|
|
2946
|
+
type: "button",
|
|
2947
|
+
"aria-label": `Move ${label} up`,
|
|
2948
|
+
disabled: index === layers.length - 1,
|
|
2949
|
+
onClick: () => controller.moveAdjustmentLayer(layer.id, index + 1),
|
|
2950
|
+
className: "px-1 text-slate-400 hover:text-slate-200 disabled:opacity-30",
|
|
2951
|
+
children: "\u2191"
|
|
2952
|
+
}
|
|
2953
|
+
),
|
|
2954
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2955
|
+
"button",
|
|
2956
|
+
{
|
|
2957
|
+
type: "button",
|
|
2958
|
+
"aria-label": `Move ${label} down`,
|
|
2959
|
+
disabled: index === 0,
|
|
2960
|
+
onClick: () => controller.moveAdjustmentLayer(layer.id, index - 1),
|
|
2961
|
+
className: "px-1 text-slate-400 hover:text-slate-200 disabled:opacity-30",
|
|
2962
|
+
children: "\u2193"
|
|
2963
|
+
}
|
|
2964
|
+
),
|
|
2965
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2966
|
+
"button",
|
|
2967
|
+
{
|
|
2968
|
+
type: "button",
|
|
2969
|
+
"aria-label": `Remove ${label}`,
|
|
2970
|
+
onClick: () => {
|
|
2971
|
+
controller.removeAdjustmentLayer(layer.id);
|
|
2972
|
+
if (selectedId === layer.id) setSelectedId(null);
|
|
2973
|
+
},
|
|
2974
|
+
className: "px-1 text-rose-400 hover:text-rose-300",
|
|
2975
|
+
children: "\u2715"
|
|
2976
|
+
}
|
|
2977
|
+
)
|
|
2978
|
+
]
|
|
2979
|
+
},
|
|
2980
|
+
layer.id
|
|
2981
|
+
);
|
|
2982
|
+
}) }),
|
|
2983
|
+
selected && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-2 rounded border border-slate-700/60 p-2", "data-testid": "adjustment-layer-editor", children: [
|
|
2984
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2985
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-slate-400", children: "Blend" }),
|
|
2986
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2987
|
+
"select",
|
|
2988
|
+
{
|
|
2989
|
+
"aria-label": "Blend mode",
|
|
2990
|
+
className: `${selectClass} flex-1`,
|
|
2991
|
+
value: selected.blend,
|
|
2992
|
+
onChange: (e) => controller.updateAdjustmentLayer(selected.id, { blend: e.target.value }),
|
|
2993
|
+
children: import_image_editor5.BLEND_MODES.map((m) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("option", { value: m.id, children: m.label }, m.id))
|
|
2994
|
+
}
|
|
2995
|
+
)
|
|
2996
|
+
] }),
|
|
2997
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2998
|
+
ControlSlider,
|
|
2999
|
+
{
|
|
3000
|
+
spec: import_image_editor5.ADJUSTMENT_LAYER_OPACITY_CONTROL,
|
|
3001
|
+
label: "Layer opacity",
|
|
3002
|
+
value: selected.opacity,
|
|
3003
|
+
onChange: (v) => controller.updateAdjustmentLayer(selected.id, { opacity: v })
|
|
3004
|
+
}
|
|
3005
|
+
),
|
|
3006
|
+
editor(selected)
|
|
3007
|
+
] })
|
|
3008
|
+
] });
|
|
3009
|
+
};
|
|
3010
|
+
|
|
3011
|
+
// src/image-editor/ImageEditor.tsx
|
|
3012
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
2250
3013
|
var ImageEditor = ({
|
|
2251
3014
|
editor: externalEditor,
|
|
2252
3015
|
src,
|
|
@@ -2261,17 +3024,17 @@ var ImageEditor = ({
|
|
|
2261
3024
|
const internalEditor = useImageEditor({ image: src });
|
|
2262
3025
|
const editor = externalEditor || internalEditor;
|
|
2263
3026
|
const { state, controller } = editor;
|
|
2264
|
-
const legacyProcess = (0,
|
|
2265
|
-
const canvasRef = (0,
|
|
2266
|
-
const containerRef = (0,
|
|
2267
|
-
const [activeTab, setActiveTab] = (0,
|
|
2268
|
-
const [activeCropRatio, setActiveCropRatio] = (0,
|
|
2269
|
-
const [inpaintPrompt, setInpaintPrompt] = (0,
|
|
2270
|
-
const [inpaintMaskMode, setInpaintMaskMode] = (0,
|
|
2271
|
-
const [isRemovingBg, setIsRemovingBg] = (0,
|
|
2272
|
-
const [isInpainting, setIsInpainting] = (0,
|
|
2273
|
-
const [aiError, setAiError] = (0,
|
|
2274
|
-
const [aiSuccess, setAiSuccess] = (0,
|
|
3027
|
+
const legacyProcess = (0, import_image_editor6.normalizeProcessVersion)(state.adjustments.process) < import_image_editor6.LATEST_PROCESS_VERSION;
|
|
3028
|
+
const canvasRef = (0, import_react28.useRef)(null);
|
|
3029
|
+
const containerRef = (0, import_react28.useRef)(null);
|
|
3030
|
+
const [activeTab, setActiveTab] = (0, import_react28.useState)("crop");
|
|
3031
|
+
const [activeCropRatio, setActiveCropRatio] = (0, import_react28.useState)(null);
|
|
3032
|
+
const [inpaintPrompt, setInpaintPrompt] = (0, import_react28.useState)("");
|
|
3033
|
+
const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react28.useState)("annotations");
|
|
3034
|
+
const [isRemovingBg, setIsRemovingBg] = (0, import_react28.useState)(false);
|
|
3035
|
+
const [isInpainting, setIsInpainting] = (0, import_react28.useState)(false);
|
|
3036
|
+
const [aiError, setAiError] = (0, import_react28.useState)(null);
|
|
3037
|
+
const [aiSuccess, setAiSuccess] = (0, import_react28.useState)(null);
|
|
2275
3038
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
2276
3039
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
2277
3040
|
const handleRemoveBackground = async () => {
|
|
@@ -2333,18 +3096,18 @@ var ImageEditor = ({
|
|
|
2333
3096
|
setIsInpainting(false);
|
|
2334
3097
|
}
|
|
2335
3098
|
};
|
|
2336
|
-
const [activeColor, setActiveColor] = (0,
|
|
2337
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
2338
|
-
const [fontSize, setFontSize] = (0,
|
|
2339
|
-
const [textInput, setTextInput] = (0,
|
|
2340
|
-
const draftAnnotationRef = (0,
|
|
2341
|
-
const draftCropRef = (0,
|
|
2342
|
-
const cropDragInfoRef = (0,
|
|
2343
|
-
const annotationDragInfoRef = (0,
|
|
2344
|
-
const isDrawingRef = (0,
|
|
2345
|
-
const currentPathRef = (0,
|
|
2346
|
-
const dragStartPointRef = (0,
|
|
2347
|
-
const renderCanvas = (0,
|
|
3099
|
+
const [activeColor, setActiveColor] = (0, import_react28.useState)("#ef4444");
|
|
3100
|
+
const [strokeWidth, setStrokeWidth] = (0, import_react28.useState)(3);
|
|
3101
|
+
const [fontSize, setFontSize] = (0, import_react28.useState)(24);
|
|
3102
|
+
const [textInput, setTextInput] = (0, import_react28.useState)("");
|
|
3103
|
+
const draftAnnotationRef = (0, import_react28.useRef)(null);
|
|
3104
|
+
const draftCropRef = (0, import_react28.useRef)(null);
|
|
3105
|
+
const cropDragInfoRef = (0, import_react28.useRef)(null);
|
|
3106
|
+
const annotationDragInfoRef = (0, import_react28.useRef)(null);
|
|
3107
|
+
const isDrawingRef = (0, import_react28.useRef)(false);
|
|
3108
|
+
const currentPathRef = (0, import_react28.useRef)([]);
|
|
3109
|
+
const dragStartPointRef = (0, import_react28.useRef)(null);
|
|
3110
|
+
const renderCanvas = (0, import_react28.useCallback)(
|
|
2348
3111
|
async (draftAnnotation, draftCrop) => {
|
|
2349
3112
|
const canvas = canvasRef.current;
|
|
2350
3113
|
const container = containerRef.current;
|
|
@@ -2363,7 +3126,7 @@ var ImageEditor = ({
|
|
|
2363
3126
|
},
|
|
2364
3127
|
[controller, activeTab]
|
|
2365
3128
|
);
|
|
2366
|
-
(0,
|
|
3129
|
+
(0, import_react28.useEffect)(() => {
|
|
2367
3130
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
2368
3131
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
2369
3132
|
const animId = raf(() => {
|
|
@@ -2371,12 +3134,12 @@ var ImageEditor = ({
|
|
|
2371
3134
|
});
|
|
2372
3135
|
return () => caf(animId);
|
|
2373
3136
|
}, [renderCanvas, state]);
|
|
2374
|
-
(0,
|
|
3137
|
+
(0, import_react28.useEffect)(() => {
|
|
2375
3138
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
2376
3139
|
editor.setTool("crop");
|
|
2377
3140
|
}
|
|
2378
3141
|
}, [activeTab, editor]);
|
|
2379
|
-
(0,
|
|
3142
|
+
(0, import_react28.useEffect)(() => {
|
|
2380
3143
|
const container = containerRef.current;
|
|
2381
3144
|
if (!container) return;
|
|
2382
3145
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -2413,8 +3176,8 @@ var ImageEditor = ({
|
|
|
2413
3176
|
width: state.imageDimensions.width,
|
|
2414
3177
|
height: state.imageDimensions.height
|
|
2415
3178
|
};
|
|
2416
|
-
const handle = (0,
|
|
2417
|
-
const startImgPt = (0,
|
|
3179
|
+
const handle = (0, import_image_editor6.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
3180
|
+
const startImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
2418
3181
|
if (handle) {
|
|
2419
3182
|
cropDragInfoRef.current = {
|
|
2420
3183
|
handle,
|
|
@@ -2433,12 +3196,12 @@ var ImageEditor = ({
|
|
|
2433
3196
|
return;
|
|
2434
3197
|
}
|
|
2435
3198
|
if (activeTab === "annotate") {
|
|
2436
|
-
const imgPt = (0,
|
|
3199
|
+
const imgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2437
3200
|
dragStartPointRef.current = imgPt;
|
|
2438
3201
|
if (state.activeTool === "select") {
|
|
2439
3202
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
2440
3203
|
const ann = state.annotations[i];
|
|
2441
|
-
if ((0,
|
|
3204
|
+
if ((0, import_image_editor6.hitTestAnnotation)(imgPt, ann)) {
|
|
2442
3205
|
editor.selectAnnotation(ann.id);
|
|
2443
3206
|
annotationDragInfoRef.current = {
|
|
2444
3207
|
annId: ann.id,
|
|
@@ -2475,7 +3238,7 @@ var ImageEditor = ({
|
|
|
2475
3238
|
if (activeTab === "crop") {
|
|
2476
3239
|
const drag = cropDragInfoRef.current;
|
|
2477
3240
|
if (drag) {
|
|
2478
|
-
const currentImgPt = (0,
|
|
3241
|
+
const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, true);
|
|
2479
3242
|
let newCrop;
|
|
2480
3243
|
if (drag.handle === "new") {
|
|
2481
3244
|
const minX = Math.max(0, Math.min(drag.startImgPt.x, currentImgPt.x));
|
|
@@ -2489,7 +3252,7 @@ var ImageEditor = ({
|
|
|
2489
3252
|
height: Math.round(Math.max(20, maxY - minY))
|
|
2490
3253
|
};
|
|
2491
3254
|
} else {
|
|
2492
|
-
newCrop = (0,
|
|
3255
|
+
newCrop = (0, import_image_editor6.calculateCropDrag)(
|
|
2493
3256
|
drag.startCrop,
|
|
2494
3257
|
drag.handle,
|
|
2495
3258
|
drag.startImgPt,
|
|
@@ -2509,15 +3272,15 @@ var ImageEditor = ({
|
|
|
2509
3272
|
width: state.imageDimensions.width,
|
|
2510
3273
|
height: state.imageDimensions.height
|
|
2511
3274
|
};
|
|
2512
|
-
const handle = (0,
|
|
2513
|
-
canvas.style.cursor = (0,
|
|
3275
|
+
const handle = (0, import_image_editor6.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
3276
|
+
canvas.style.cursor = (0, import_image_editor6.getCropCursor)(handle, state.transform);
|
|
2514
3277
|
}
|
|
2515
3278
|
return;
|
|
2516
3279
|
}
|
|
2517
3280
|
if (activeTab === "annotate") {
|
|
2518
3281
|
if (annotationDragInfoRef.current) {
|
|
2519
3282
|
const drag = annotationDragInfoRef.current;
|
|
2520
|
-
const currentImgPt2 = (0,
|
|
3283
|
+
const currentImgPt2 = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2521
3284
|
const dx = currentImgPt2.x - drag.startImgPt.x;
|
|
2522
3285
|
const dy = currentImgPt2.y - drag.startImgPt.y;
|
|
2523
3286
|
editor.updateAnnotation(drag.annId, {
|
|
@@ -2529,10 +3292,10 @@ var ImageEditor = ({
|
|
|
2529
3292
|
const startPt = dragStartPointRef.current;
|
|
2530
3293
|
if (!startPt) {
|
|
2531
3294
|
if (state.activeTool === "select") {
|
|
2532
|
-
const imgPt = (0,
|
|
3295
|
+
const imgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2533
3296
|
let hovered = false;
|
|
2534
3297
|
for (let i = state.annotations.length - 1; i >= 0; i--) {
|
|
2535
|
-
if ((0,
|
|
3298
|
+
if ((0, import_image_editor6.hitTestAnnotation)(imgPt, state.annotations[i])) {
|
|
2536
3299
|
hovered = true;
|
|
2537
3300
|
break;
|
|
2538
3301
|
}
|
|
@@ -2543,7 +3306,7 @@ var ImageEditor = ({
|
|
|
2543
3306
|
}
|
|
2544
3307
|
return;
|
|
2545
3308
|
}
|
|
2546
|
-
const currentImgPt = (0,
|
|
3309
|
+
const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2547
3310
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
2548
3311
|
currentPathRef.current.push(currentImgPt);
|
|
2549
3312
|
const draft = {
|
|
@@ -2638,7 +3401,7 @@ var ImageEditor = ({
|
|
|
2638
3401
|
}
|
|
2639
3402
|
const startPt = dragStartPointRef.current;
|
|
2640
3403
|
if (startPt) {
|
|
2641
|
-
const currentImgPt = (0,
|
|
3404
|
+
const currentImgPt = (0, import_image_editor6.canvasToImagePoint)(canvasPt, state, canvas.width, canvas.height, false);
|
|
2642
3405
|
if (state.activeTool === "pen" && isDrawingRef.current) {
|
|
2643
3406
|
if (currentPathRef.current.length > 1) {
|
|
2644
3407
|
editor.addAnnotation({
|
|
@@ -2734,15 +3497,15 @@ var ImageEditor = ({
|
|
|
2734
3497
|
link.click();
|
|
2735
3498
|
}
|
|
2736
3499
|
};
|
|
2737
|
-
return /* @__PURE__ */ (0,
|
|
3500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2738
3501
|
"div",
|
|
2739
3502
|
{
|
|
2740
3503
|
className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
|
|
2741
3504
|
style,
|
|
2742
3505
|
children: [
|
|
2743
|
-
/* @__PURE__ */ (0,
|
|
2744
|
-
/* @__PURE__ */ (0,
|
|
2745
|
-
/* @__PURE__ */ (0,
|
|
3506
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
|
|
3507
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
|
|
3508
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2746
3509
|
"button",
|
|
2747
3510
|
{
|
|
2748
3511
|
type: "button",
|
|
@@ -2754,7 +3517,7 @@ var ImageEditor = ({
|
|
|
2754
3517
|
children: "Transform & Crop"
|
|
2755
3518
|
}
|
|
2756
3519
|
),
|
|
2757
|
-
/* @__PURE__ */ (0,
|
|
3520
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2758
3521
|
"button",
|
|
2759
3522
|
{
|
|
2760
3523
|
type: "button",
|
|
@@ -2766,7 +3529,7 @@ var ImageEditor = ({
|
|
|
2766
3529
|
children: "Adjustments"
|
|
2767
3530
|
}
|
|
2768
3531
|
),
|
|
2769
|
-
/* @__PURE__ */ (0,
|
|
3532
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2770
3533
|
"button",
|
|
2771
3534
|
{
|
|
2772
3535
|
type: "button",
|
|
@@ -2778,7 +3541,7 @@ var ImageEditor = ({
|
|
|
2778
3541
|
children: "Annotations"
|
|
2779
3542
|
}
|
|
2780
3543
|
),
|
|
2781
|
-
/* @__PURE__ */ (0,
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2782
3545
|
"button",
|
|
2783
3546
|
{
|
|
2784
3547
|
type: "button",
|
|
@@ -2790,7 +3553,7 @@ var ImageEditor = ({
|
|
|
2790
3553
|
children: "Depth Mask"
|
|
2791
3554
|
}
|
|
2792
3555
|
),
|
|
2793
|
-
/* @__PURE__ */ (0,
|
|
3556
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
2794
3557
|
"button",
|
|
2795
3558
|
{
|
|
2796
3559
|
type: "button",
|
|
@@ -2800,14 +3563,14 @@ var ImageEditor = ({
|
|
|
2800
3563
|
},
|
|
2801
3564
|
className: `px-3 py-1.5 rounded-md font-medium transition-colors flex items-center gap-1.5 ${activeTab === "ai" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
|
|
2802
3565
|
children: [
|
|
2803
|
-
/* @__PURE__ */ (0,
|
|
3566
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
2804
3567
|
"AI Tools"
|
|
2805
3568
|
]
|
|
2806
3569
|
}
|
|
2807
3570
|
)
|
|
2808
3571
|
] }),
|
|
2809
|
-
/* @__PURE__ */ (0,
|
|
2810
|
-
/* @__PURE__ */ (0,
|
|
3572
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
3573
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2811
3574
|
"button",
|
|
2812
3575
|
{
|
|
2813
3576
|
type: "button",
|
|
@@ -2818,7 +3581,7 @@ var ImageEditor = ({
|
|
|
2818
3581
|
children: "\u21A9"
|
|
2819
3582
|
}
|
|
2820
3583
|
),
|
|
2821
|
-
/* @__PURE__ */ (0,
|
|
3584
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2822
3585
|
"button",
|
|
2823
3586
|
{
|
|
2824
3587
|
type: "button",
|
|
@@ -2829,7 +3592,7 @@ var ImageEditor = ({
|
|
|
2829
3592
|
children: "\u21AA"
|
|
2830
3593
|
}
|
|
2831
3594
|
),
|
|
2832
|
-
/* @__PURE__ */ (0,
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2833
3596
|
"button",
|
|
2834
3597
|
{
|
|
2835
3598
|
type: "button",
|
|
@@ -2838,8 +3601,8 @@ var ImageEditor = ({
|
|
|
2838
3601
|
children: "Reset"
|
|
2839
3602
|
}
|
|
2840
3603
|
),
|
|
2841
|
-
/* @__PURE__ */ (0,
|
|
2842
|
-
/* @__PURE__ */ (0,
|
|
3604
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
3605
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2843
3606
|
"button",
|
|
2844
3607
|
{
|
|
2845
3608
|
type: "button",
|
|
@@ -2849,11 +3612,11 @@ var ImageEditor = ({
|
|
|
2849
3612
|
children: "-"
|
|
2850
3613
|
}
|
|
2851
3614
|
),
|
|
2852
|
-
/* @__PURE__ */ (0,
|
|
3615
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
|
|
2853
3616
|
Math.round(state.zoom * 100),
|
|
2854
3617
|
"%"
|
|
2855
3618
|
] }),
|
|
2856
|
-
/* @__PURE__ */ (0,
|
|
3619
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2857
3620
|
"button",
|
|
2858
3621
|
{
|
|
2859
3622
|
type: "button",
|
|
@@ -2863,8 +3626,8 @@ var ImageEditor = ({
|
|
|
2863
3626
|
children: "+"
|
|
2864
3627
|
}
|
|
2865
3628
|
),
|
|
2866
|
-
/* @__PURE__ */ (0,
|
|
2867
|
-
/* @__PURE__ */ (0,
|
|
3629
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
|
|
3630
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2868
3631
|
"button",
|
|
2869
3632
|
{
|
|
2870
3633
|
type: "button",
|
|
@@ -2875,7 +3638,7 @@ var ImageEditor = ({
|
|
|
2875
3638
|
children: "Hold Compare"
|
|
2876
3639
|
}
|
|
2877
3640
|
),
|
|
2878
|
-
/* @__PURE__ */ (0,
|
|
3641
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2879
3642
|
"button",
|
|
2880
3643
|
{
|
|
2881
3644
|
type: "button",
|
|
@@ -2886,13 +3649,13 @@ var ImageEditor = ({
|
|
|
2886
3649
|
)
|
|
2887
3650
|
] })
|
|
2888
3651
|
] }),
|
|
2889
|
-
/* @__PURE__ */ (0,
|
|
2890
|
-
/* @__PURE__ */ (0,
|
|
3652
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
|
|
3653
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2891
3654
|
"div",
|
|
2892
3655
|
{
|
|
2893
3656
|
ref: containerRef,
|
|
2894
3657
|
className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
|
|
2895
|
-
children: /* @__PURE__ */ (0,
|
|
3658
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2896
3659
|
"canvas",
|
|
2897
3660
|
{
|
|
2898
3661
|
ref: canvasRef,
|
|
@@ -2905,11 +3668,11 @@ var ImageEditor = ({
|
|
|
2905
3668
|
)
|
|
2906
3669
|
}
|
|
2907
3670
|
),
|
|
2908
|
-
/* @__PURE__ */ (0,
|
|
2909
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
2910
|
-
/* @__PURE__ */ (0,
|
|
2911
|
-
/* @__PURE__ */ (0,
|
|
2912
|
-
/* @__PURE__ */ (0,
|
|
3671
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
|
|
3672
|
+
activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
3673
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
|
|
3674
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
3675
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2913
3676
|
"button",
|
|
2914
3677
|
{
|
|
2915
3678
|
type: "button",
|
|
@@ -2921,7 +3684,7 @@ var ImageEditor = ({
|
|
|
2921
3684
|
children: "Freeform"
|
|
2922
3685
|
}
|
|
2923
3686
|
),
|
|
2924
|
-
/* @__PURE__ */ (0,
|
|
3687
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2925
3688
|
"button",
|
|
2926
3689
|
{
|
|
2927
3690
|
type: "button",
|
|
@@ -2933,7 +3696,7 @@ var ImageEditor = ({
|
|
|
2933
3696
|
children: "1:1 Square"
|
|
2934
3697
|
}
|
|
2935
3698
|
),
|
|
2936
|
-
/* @__PURE__ */ (0,
|
|
3699
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2937
3700
|
"button",
|
|
2938
3701
|
{
|
|
2939
3702
|
type: "button",
|
|
@@ -2945,7 +3708,7 @@ var ImageEditor = ({
|
|
|
2945
3708
|
children: "4:3 Standard"
|
|
2946
3709
|
}
|
|
2947
3710
|
),
|
|
2948
|
-
/* @__PURE__ */ (0,
|
|
3711
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2949
3712
|
"button",
|
|
2950
3713
|
{
|
|
2951
3714
|
type: "button",
|
|
@@ -2957,7 +3720,7 @@ var ImageEditor = ({
|
|
|
2957
3720
|
children: "16:9 Wide"
|
|
2958
3721
|
}
|
|
2959
3722
|
),
|
|
2960
|
-
/* @__PURE__ */ (0,
|
|
3723
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2961
3724
|
"button",
|
|
2962
3725
|
{
|
|
2963
3726
|
type: "button",
|
|
@@ -2969,7 +3732,7 @@ var ImageEditor = ({
|
|
|
2969
3732
|
children: "3:2 Photo"
|
|
2970
3733
|
}
|
|
2971
3734
|
),
|
|
2972
|
-
/* @__PURE__ */ (0,
|
|
3735
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2973
3736
|
"button",
|
|
2974
3737
|
{
|
|
2975
3738
|
type: "button",
|
|
@@ -2982,10 +3745,10 @@ var ImageEditor = ({
|
|
|
2982
3745
|
}
|
|
2983
3746
|
)
|
|
2984
3747
|
] }),
|
|
2985
|
-
/* @__PURE__ */ (0,
|
|
2986
|
-
/* @__PURE__ */ (0,
|
|
2987
|
-
/* @__PURE__ */ (0,
|
|
2988
|
-
/* @__PURE__ */ (0,
|
|
3748
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
3749
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
|
|
3750
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
3751
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2989
3752
|
"button",
|
|
2990
3753
|
{
|
|
2991
3754
|
type: "button",
|
|
@@ -2994,7 +3757,7 @@ var ImageEditor = ({
|
|
|
2994
3757
|
children: "Rotate -90\xB0"
|
|
2995
3758
|
}
|
|
2996
3759
|
),
|
|
2997
|
-
/* @__PURE__ */ (0,
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
2998
3761
|
"button",
|
|
2999
3762
|
{
|
|
3000
3763
|
type: "button",
|
|
@@ -3003,7 +3766,7 @@ var ImageEditor = ({
|
|
|
3003
3766
|
children: "Rotate +90\xB0"
|
|
3004
3767
|
}
|
|
3005
3768
|
),
|
|
3006
|
-
/* @__PURE__ */ (0,
|
|
3769
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3007
3770
|
"button",
|
|
3008
3771
|
{
|
|
3009
3772
|
type: "button",
|
|
@@ -3012,7 +3775,7 @@ var ImageEditor = ({
|
|
|
3012
3775
|
children: "Flip Horizontal"
|
|
3013
3776
|
}
|
|
3014
3777
|
),
|
|
3015
|
-
/* @__PURE__ */ (0,
|
|
3778
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3016
3779
|
"button",
|
|
3017
3780
|
{
|
|
3018
3781
|
type: "button",
|
|
@@ -3023,10 +3786,10 @@ var ImageEditor = ({
|
|
|
3023
3786
|
)
|
|
3024
3787
|
] })
|
|
3025
3788
|
] }),
|
|
3026
|
-
activeTab === "adjust" && /* @__PURE__ */ (0,
|
|
3027
|
-
/* @__PURE__ */ (0,
|
|
3028
|
-
/* @__PURE__ */ (0,
|
|
3029
|
-
/* @__PURE__ */ (0,
|
|
3789
|
+
activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
3790
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3791
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3030
3793
|
"button",
|
|
3031
3794
|
{
|
|
3032
3795
|
type: "button",
|
|
@@ -3036,174 +3799,49 @@ var ImageEditor = ({
|
|
|
3036
3799
|
}
|
|
3037
3800
|
)
|
|
3038
3801
|
] }),
|
|
3039
|
-
/* @__PURE__ */ (0,
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
] }),
|
|
3044
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3045
|
-
"input",
|
|
3046
|
-
{
|
|
3047
|
-
type: "range",
|
|
3048
|
-
min: "-100",
|
|
3049
|
-
max: "100",
|
|
3050
|
-
value: state.adjustments.brightness,
|
|
3051
|
-
onChange: (e) => editor.setAdjustments({ brightness: Number(e.target.value) }),
|
|
3052
|
-
className: "w-full accent-indigo-500"
|
|
3053
|
-
}
|
|
3054
|
-
)
|
|
3055
|
-
] }),
|
|
3056
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3057
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3058
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Contrast" }),
|
|
3059
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.contrast })
|
|
3060
|
-
] }),
|
|
3061
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3062
|
-
"input",
|
|
3802
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Histogram, { histogram: editor.histogram }),
|
|
3803
|
+
import_image_editor6.IMAGE_ADJUSTMENT_CONTROLS.map((spec) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react28.default.Fragment, { children: [
|
|
3804
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3805
|
+
ControlSlider,
|
|
3063
3806
|
{
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
onChange: (e) => editor.setAdjustments({ contrast: Number(e.target.value) }),
|
|
3069
|
-
className: "w-full accent-indigo-500"
|
|
3807
|
+
spec,
|
|
3808
|
+
value: (0, import_image_editor6.readAdjustmentControls)(state.adjustments)[spec.id],
|
|
3809
|
+
disabled: spec.requiresProcess !== void 0 && legacyProcess,
|
|
3810
|
+
onChange: (v) => editor.setAdjustments({ [spec.id]: v })
|
|
3070
3811
|
}
|
|
3071
|
-
)
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3075
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Saturation" }),
|
|
3076
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.saturation })
|
|
3077
|
-
] }),
|
|
3078
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3079
|
-
"input",
|
|
3080
|
-
{
|
|
3081
|
-
type: "range",
|
|
3082
|
-
min: "-100",
|
|
3083
|
-
max: "100",
|
|
3084
|
-
value: state.adjustments.saturation,
|
|
3085
|
-
onChange: (e) => editor.setAdjustments({ saturation: Number(e.target.value) }),
|
|
3086
|
-
className: "w-full accent-indigo-500"
|
|
3087
|
-
}
|
|
3088
|
-
)
|
|
3089
|
-
] }),
|
|
3090
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3091
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3092
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Exposure" }),
|
|
3093
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.exposure })
|
|
3094
|
-
] }),
|
|
3095
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3096
|
-
"input",
|
|
3097
|
-
{
|
|
3098
|
-
type: "range",
|
|
3099
|
-
min: "-100",
|
|
3100
|
-
max: "100",
|
|
3101
|
-
value: state.adjustments.exposure,
|
|
3102
|
-
onChange: (e) => editor.setAdjustments({ exposure: Number(e.target.value) }),
|
|
3103
|
-
className: "w-full accent-indigo-500"
|
|
3104
|
-
}
|
|
3105
|
-
)
|
|
3106
|
-
] }),
|
|
3107
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3108
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3109
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Warmth / Temperature" }),
|
|
3110
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.temperature })
|
|
3111
|
-
] }),
|
|
3112
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3113
|
-
"input",
|
|
3114
|
-
{
|
|
3115
|
-
type: "range",
|
|
3116
|
-
min: "-100",
|
|
3117
|
-
max: "100",
|
|
3118
|
-
value: state.adjustments.temperature,
|
|
3119
|
-
onChange: (e) => editor.setAdjustments({ temperature: Number(e.target.value) }),
|
|
3120
|
-
className: "w-full accent-indigo-500"
|
|
3121
|
-
}
|
|
3122
|
-
)
|
|
3123
|
-
] }),
|
|
3124
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3125
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3126
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Tint" }),
|
|
3127
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.tint ?? 0 })
|
|
3128
|
-
] }),
|
|
3129
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3130
|
-
"input",
|
|
3812
|
+
),
|
|
3813
|
+
spec.id === "tint" && legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3814
|
+
"div",
|
|
3131
3815
|
{
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3816
|
+
className: "flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200",
|
|
3817
|
+
"data-testid": "image-editor-process-notice",
|
|
3818
|
+
children: [
|
|
3819
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
3820
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3821
|
+
"button",
|
|
3822
|
+
{
|
|
3823
|
+
type: "button",
|
|
3824
|
+
onClick: () => editor.upgradeProcess(),
|
|
3825
|
+
className: "shrink-0 rounded bg-amber-500/20 px-2 py-0.5 hover:bg-amber-500/30",
|
|
3826
|
+
children: "Update"
|
|
3827
|
+
}
|
|
3828
|
+
)
|
|
3829
|
+
]
|
|
3140
3830
|
}
|
|
3141
3831
|
)
|
|
3142
|
-
] }),
|
|
3143
|
-
|
|
3144
|
-
|
|
3832
|
+
] }, spec.id)),
|
|
3833
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "border-t border-slate-700/60 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3834
|
+
AdjustmentLayersPanel,
|
|
3145
3835
|
{
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
3150
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3151
|
-
"button",
|
|
3152
|
-
{
|
|
3153
|
-
type: "button",
|
|
3154
|
-
onClick: () => editor.upgradeProcess(),
|
|
3155
|
-
className: "shrink-0 rounded bg-amber-500/20 px-2 py-0.5 hover:bg-amber-500/30",
|
|
3156
|
-
children: "Update"
|
|
3157
|
-
}
|
|
3158
|
-
)
|
|
3159
|
-
]
|
|
3836
|
+
controller,
|
|
3837
|
+
layers: state.adjustments.layers,
|
|
3838
|
+
histogram: editor.histogram
|
|
3160
3839
|
}
|
|
3161
|
-
)
|
|
3162
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3163
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3164
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Blur" }),
|
|
3165
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
|
|
3166
|
-
state.adjustments.blur,
|
|
3167
|
-
"px"
|
|
3168
|
-
] })
|
|
3169
|
-
] }),
|
|
3170
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3171
|
-
"input",
|
|
3172
|
-
{
|
|
3173
|
-
type: "range",
|
|
3174
|
-
min: "0",
|
|
3175
|
-
max: "30",
|
|
3176
|
-
value: state.adjustments.blur,
|
|
3177
|
-
onChange: (e) => editor.setAdjustments({ blur: Number(e.target.value) }),
|
|
3178
|
-
className: "w-full accent-indigo-500"
|
|
3179
|
-
}
|
|
3180
|
-
)
|
|
3181
|
-
] }),
|
|
3182
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3183
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3184
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Opacity" }),
|
|
3185
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
|
|
3186
|
-
Math.round(state.adjustments.opacity * 100),
|
|
3187
|
-
"%"
|
|
3188
|
-
] })
|
|
3189
|
-
] }),
|
|
3190
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3191
|
-
"input",
|
|
3192
|
-
{
|
|
3193
|
-
type: "range",
|
|
3194
|
-
min: "0",
|
|
3195
|
-
max: "1",
|
|
3196
|
-
step: "0.05",
|
|
3197
|
-
value: state.adjustments.opacity,
|
|
3198
|
-
onChange: (e) => editor.setAdjustments({ opacity: Number(e.target.value) }),
|
|
3199
|
-
className: "w-full accent-indigo-500"
|
|
3200
|
-
}
|
|
3201
|
-
)
|
|
3202
|
-
] })
|
|
3840
|
+
) })
|
|
3203
3841
|
] }),
|
|
3204
|
-
activeTab === "annotate" && /* @__PURE__ */ (0,
|
|
3205
|
-
/* @__PURE__ */ (0,
|
|
3206
|
-
/* @__PURE__ */ (0,
|
|
3842
|
+
activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
3843
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
|
|
3844
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3207
3845
|
"button",
|
|
3208
3846
|
{
|
|
3209
3847
|
type: "button",
|
|
@@ -3213,9 +3851,9 @@ var ImageEditor = ({
|
|
|
3213
3851
|
},
|
|
3214
3852
|
t
|
|
3215
3853
|
)) }),
|
|
3216
|
-
/* @__PURE__ */ (0,
|
|
3217
|
-
/* @__PURE__ */ (0,
|
|
3218
|
-
/* @__PURE__ */ (0,
|
|
3854
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
3855
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-slate-400", children: "Color:" }),
|
|
3856
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3219
3857
|
"input",
|
|
3220
3858
|
{
|
|
3221
3859
|
type: "color",
|
|
@@ -3224,15 +3862,15 @@ var ImageEditor = ({
|
|
|
3224
3862
|
className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
|
|
3225
3863
|
}
|
|
3226
3864
|
),
|
|
3227
|
-
/* @__PURE__ */ (0,
|
|
3228
|
-
/* @__PURE__ */ (0,
|
|
3229
|
-
/* @__PURE__ */ (0,
|
|
3230
|
-
/* @__PURE__ */ (0,
|
|
3865
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex-1 ml-2", children: [
|
|
3866
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
|
|
3867
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Width:" }),
|
|
3868
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "font-mono", children: [
|
|
3231
3869
|
strokeWidth,
|
|
3232
3870
|
"px"
|
|
3233
3871
|
] })
|
|
3234
3872
|
] }),
|
|
3235
|
-
/* @__PURE__ */ (0,
|
|
3873
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3236
3874
|
"input",
|
|
3237
3875
|
{
|
|
3238
3876
|
type: "range",
|
|
@@ -3245,10 +3883,10 @@ var ImageEditor = ({
|
|
|
3245
3883
|
)
|
|
3246
3884
|
] })
|
|
3247
3885
|
] }),
|
|
3248
|
-
/* @__PURE__ */ (0,
|
|
3249
|
-
/* @__PURE__ */ (0,
|
|
3250
|
-
/* @__PURE__ */ (0,
|
|
3251
|
-
/* @__PURE__ */ (0,
|
|
3886
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
3887
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
|
|
3888
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-2", children: [
|
|
3889
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3252
3890
|
"input",
|
|
3253
3891
|
{
|
|
3254
3892
|
type: "text",
|
|
@@ -3259,7 +3897,7 @@ var ImageEditor = ({
|
|
|
3259
3897
|
className: "flex-1 bg-slate-950 border border-slate-700 rounded-lg px-2.5 py-1.5 text-xs text-slate-100 placeholder-slate-500 focus:outline-none focus:border-indigo-500"
|
|
3260
3898
|
}
|
|
3261
3899
|
),
|
|
3262
|
-
/* @__PURE__ */ (0,
|
|
3900
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3263
3901
|
"button",
|
|
3264
3902
|
{
|
|
3265
3903
|
type: "button",
|
|
@@ -3269,14 +3907,14 @@ var ImageEditor = ({
|
|
|
3269
3907
|
}
|
|
3270
3908
|
)
|
|
3271
3909
|
] }),
|
|
3272
|
-
/* @__PURE__ */ (0,
|
|
3273
|
-
/* @__PURE__ */ (0,
|
|
3274
|
-
/* @__PURE__ */ (0,
|
|
3910
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
|
|
3911
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Font Size:" }),
|
|
3912
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "font-mono", children: [
|
|
3275
3913
|
fontSize,
|
|
3276
3914
|
"px"
|
|
3277
3915
|
] })
|
|
3278
3916
|
] }),
|
|
3279
|
-
/* @__PURE__ */ (0,
|
|
3917
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3280
3918
|
"input",
|
|
3281
3919
|
{
|
|
3282
3920
|
type: "range",
|
|
@@ -3287,14 +3925,14 @@ var ImageEditor = ({
|
|
|
3287
3925
|
className: "w-full accent-indigo-500"
|
|
3288
3926
|
}
|
|
3289
3927
|
),
|
|
3290
|
-
/* @__PURE__ */ (0,
|
|
3291
|
-
/* @__PURE__ */ (0,
|
|
3292
|
-
/* @__PURE__ */ (0,
|
|
3928
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
|
|
3929
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3930
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "text-slate-400", children: [
|
|
3293
3931
|
"Layers (",
|
|
3294
3932
|
state.annotations.length,
|
|
3295
3933
|
")"
|
|
3296
3934
|
] }),
|
|
3297
|
-
state.selectedAnnotationId && /* @__PURE__ */ (0,
|
|
3935
|
+
state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3298
3936
|
"button",
|
|
3299
3937
|
{
|
|
3300
3938
|
type: "button",
|
|
@@ -3303,7 +3941,7 @@ var ImageEditor = ({
|
|
|
3303
3941
|
children: "Delete Selected"
|
|
3304
3942
|
}
|
|
3305
3943
|
),
|
|
3306
|
-
state.annotations.length > 0 && /* @__PURE__ */ (0,
|
|
3944
|
+
state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3307
3945
|
"button",
|
|
3308
3946
|
{
|
|
3309
3947
|
type: "button",
|
|
@@ -3314,10 +3952,10 @@ var ImageEditor = ({
|
|
|
3314
3952
|
)
|
|
3315
3953
|
] })
|
|
3316
3954
|
] }),
|
|
3317
|
-
activeTab === "depth" && /* @__PURE__ */ (0,
|
|
3318
|
-
/* @__PURE__ */ (0,
|
|
3319
|
-
/* @__PURE__ */ (0,
|
|
3320
|
-
/* @__PURE__ */ (0,
|
|
3955
|
+
activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
|
|
3956
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3957
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
|
|
3958
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3321
3959
|
"button",
|
|
3322
3960
|
{
|
|
3323
3961
|
type: "button",
|
|
@@ -3327,8 +3965,8 @@ var ImageEditor = ({
|
|
|
3327
3965
|
}
|
|
3328
3966
|
)
|
|
3329
3967
|
] }),
|
|
3330
|
-
/* @__PURE__ */ (0,
|
|
3331
|
-
/* @__PURE__ */ (0,
|
|
3968
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
|
|
3969
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3332
3970
|
"input",
|
|
3333
3971
|
{
|
|
3334
3972
|
type: "checkbox",
|
|
@@ -3337,12 +3975,12 @@ var ImageEditor = ({
|
|
|
3337
3975
|
className: "rounded accent-indigo-500"
|
|
3338
3976
|
}
|
|
3339
3977
|
),
|
|
3340
|
-
/* @__PURE__ */ (0,
|
|
3978
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
3341
3979
|
] }),
|
|
3342
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
3343
|
-
/* @__PURE__ */ (0,
|
|
3344
|
-
/* @__PURE__ */ (0,
|
|
3345
|
-
/* @__PURE__ */ (0,
|
|
3980
|
+
state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
3981
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
3982
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
|
|
3983
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3346
3984
|
"input",
|
|
3347
3985
|
{
|
|
3348
3986
|
type: "text",
|
|
@@ -3353,8 +3991,8 @@ var ImageEditor = ({
|
|
|
3353
3991
|
}
|
|
3354
3992
|
)
|
|
3355
3993
|
] }),
|
|
3356
|
-
/* @__PURE__ */ (0,
|
|
3357
|
-
/* @__PURE__ */ (0,
|
|
3994
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-2", children: [
|
|
3995
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3358
3996
|
"button",
|
|
3359
3997
|
{
|
|
3360
3998
|
type: "button",
|
|
@@ -3363,7 +4001,7 @@ var ImageEditor = ({
|
|
|
3363
4001
|
children: "Threshold Mode"
|
|
3364
4002
|
}
|
|
3365
4003
|
),
|
|
3366
|
-
/* @__PURE__ */ (0,
|
|
4004
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3367
4005
|
"button",
|
|
3368
4006
|
{
|
|
3369
4007
|
type: "button",
|
|
@@ -3373,12 +4011,12 @@ var ImageEditor = ({
|
|
|
3373
4011
|
}
|
|
3374
4012
|
)
|
|
3375
4013
|
] }),
|
|
3376
|
-
/* @__PURE__ */ (0,
|
|
3377
|
-
/* @__PURE__ */ (0,
|
|
3378
|
-
/* @__PURE__ */ (0,
|
|
3379
|
-
/* @__PURE__ */ (0,
|
|
4014
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
4015
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
4016
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Depth Start (Lower):" }),
|
|
4017
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
|
|
3380
4018
|
] }),
|
|
3381
|
-
/* @__PURE__ */ (0,
|
|
4019
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3382
4020
|
"input",
|
|
3383
4021
|
{
|
|
3384
4022
|
type: "range",
|
|
@@ -3392,12 +4030,12 @@ var ImageEditor = ({
|
|
|
3392
4030
|
}
|
|
3393
4031
|
)
|
|
3394
4032
|
] }),
|
|
3395
|
-
/* @__PURE__ */ (0,
|
|
3396
|
-
/* @__PURE__ */ (0,
|
|
3397
|
-
/* @__PURE__ */ (0,
|
|
3398
|
-
/* @__PURE__ */ (0,
|
|
4033
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
4034
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
4035
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Depth Stop (Upper):" }),
|
|
4036
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
|
|
3399
4037
|
] }),
|
|
3400
|
-
/* @__PURE__ */ (0,
|
|
4038
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3401
4039
|
"input",
|
|
3402
4040
|
{
|
|
3403
4041
|
type: "range",
|
|
@@ -3411,12 +4049,12 @@ var ImageEditor = ({
|
|
|
3411
4049
|
}
|
|
3412
4050
|
)
|
|
3413
4051
|
] }),
|
|
3414
|
-
/* @__PURE__ */ (0,
|
|
3415
|
-
/* @__PURE__ */ (0,
|
|
3416
|
-
/* @__PURE__ */ (0,
|
|
3417
|
-
/* @__PURE__ */ (0,
|
|
4052
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
4053
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
4054
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Softness:" }),
|
|
4055
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
|
|
3418
4056
|
] }),
|
|
3419
|
-
/* @__PURE__ */ (0,
|
|
4057
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3420
4058
|
"input",
|
|
3421
4059
|
{
|
|
3422
4060
|
type: "range",
|
|
@@ -3428,8 +4066,8 @@ var ImageEditor = ({
|
|
|
3428
4066
|
}
|
|
3429
4067
|
)
|
|
3430
4068
|
] }),
|
|
3431
|
-
/* @__PURE__ */ (0,
|
|
3432
|
-
/* @__PURE__ */ (0,
|
|
4069
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
|
|
4070
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3433
4071
|
"input",
|
|
3434
4072
|
{
|
|
3435
4073
|
type: "checkbox",
|
|
@@ -3438,52 +4076,52 @@ var ImageEditor = ({
|
|
|
3438
4076
|
className: "rounded accent-indigo-500"
|
|
3439
4077
|
}
|
|
3440
4078
|
),
|
|
3441
|
-
/* @__PURE__ */ (0,
|
|
4079
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Invert Mask" })
|
|
3442
4080
|
] })
|
|
3443
4081
|
] })
|
|
3444
4082
|
] }),
|
|
3445
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
3446
|
-
/* @__PURE__ */ (0,
|
|
3447
|
-
/* @__PURE__ */ (0,
|
|
3448
|
-
/* @__PURE__ */ (0,
|
|
3449
|
-
/* @__PURE__ */ (0,
|
|
4083
|
+
activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
|
|
4084
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
4085
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4086
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
4087
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
|
|
3450
4088
|
"Background Removal"
|
|
3451
4089
|
] }),
|
|
3452
|
-
isRemovingBg && /* @__PURE__ */ (0,
|
|
4090
|
+
isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
|
|
3453
4091
|
] }),
|
|
3454
|
-
/* @__PURE__ */ (0,
|
|
3455
|
-
/* @__PURE__ */ (0,
|
|
4092
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
|
|
4093
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3456
4094
|
"button",
|
|
3457
4095
|
{
|
|
3458
4096
|
type: "button",
|
|
3459
4097
|
onClick: handleRemoveBackground,
|
|
3460
4098
|
disabled: isRemovingBg || isInpainting,
|
|
3461
4099
|
className: "mt-1 px-3 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
|
|
3462
|
-
children: isRemovingBg ? /* @__PURE__ */ (0,
|
|
3463
|
-
/* @__PURE__ */ (0,
|
|
4100
|
+
children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
4101
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
3464
4102
|
"Removing Background..."
|
|
3465
|
-
] }) : /* @__PURE__ */ (0,
|
|
3466
|
-
/* @__PURE__ */ (0,
|
|
4103
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
4104
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
3467
4105
|
"Remove Background"
|
|
3468
4106
|
] })
|
|
3469
4107
|
}
|
|
3470
4108
|
)
|
|
3471
4109
|
] }),
|
|
3472
|
-
/* @__PURE__ */ (0,
|
|
3473
|
-
/* @__PURE__ */ (0,
|
|
3474
|
-
/* @__PURE__ */ (0,
|
|
3475
|
-
/* @__PURE__ */ (0,
|
|
3476
|
-
/* @__PURE__ */ (0,
|
|
3477
|
-
/* @__PURE__ */ (0,
|
|
4110
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
|
|
4111
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
4112
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
|
|
4113
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
4114
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
|
|
4115
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "m14 7 3 3" })
|
|
3478
4116
|
] }),
|
|
3479
4117
|
"Generative Inpainting"
|
|
3480
4118
|
] }),
|
|
3481
|
-
isInpainting && /* @__PURE__ */ (0,
|
|
4119
|
+
isInpainting && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
|
|
3482
4120
|
] }),
|
|
3483
|
-
/* @__PURE__ */ (0,
|
|
3484
|
-
/* @__PURE__ */ (0,
|
|
3485
|
-
/* @__PURE__ */ (0,
|
|
3486
|
-
/* @__PURE__ */ (0,
|
|
4121
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
|
|
4122
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
4123
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
|
|
4124
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3487
4125
|
"textarea",
|
|
3488
4126
|
{
|
|
3489
4127
|
id: "ai-inpaint-prompt-react",
|
|
@@ -3495,10 +4133,10 @@ var ImageEditor = ({
|
|
|
3495
4133
|
}
|
|
3496
4134
|
)
|
|
3497
4135
|
] }),
|
|
3498
|
-
/* @__PURE__ */ (0,
|
|
3499
|
-
/* @__PURE__ */ (0,
|
|
3500
|
-
/* @__PURE__ */ (0,
|
|
3501
|
-
/* @__PURE__ */ (0,
|
|
4136
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
4137
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
|
|
4138
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
|
|
4139
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3502
4140
|
"button",
|
|
3503
4141
|
{
|
|
3504
4142
|
type: "button",
|
|
@@ -3511,7 +4149,7 @@ var ImageEditor = ({
|
|
|
3511
4149
|
]
|
|
3512
4150
|
}
|
|
3513
4151
|
),
|
|
3514
|
-
/* @__PURE__ */ (0,
|
|
4152
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3515
4153
|
"button",
|
|
3516
4154
|
{
|
|
3517
4155
|
type: "button",
|
|
@@ -3526,25 +4164,25 @@ var ImageEditor = ({
|
|
|
3526
4164
|
)
|
|
3527
4165
|
] })
|
|
3528
4166
|
] }),
|
|
3529
|
-
/* @__PURE__ */ (0,
|
|
4167
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3530
4168
|
"button",
|
|
3531
4169
|
{
|
|
3532
4170
|
type: "button",
|
|
3533
4171
|
onClick: handleInpaint,
|
|
3534
4172
|
disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
|
|
3535
4173
|
className: "mt-1 px-3 py-2 rounded-lg bg-purple-600 hover:bg-purple-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
|
|
3536
|
-
children: isInpainting ? /* @__PURE__ */ (0,
|
|
3537
|
-
/* @__PURE__ */ (0,
|
|
4174
|
+
children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
4175
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
|
|
3538
4176
|
"Generating Inpaint..."
|
|
3539
|
-
] }) : /* @__PURE__ */ (0,
|
|
3540
|
-
/* @__PURE__ */ (0,
|
|
4177
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
4178
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
|
|
3541
4179
|
"Apply Inpainting"
|
|
3542
4180
|
] })
|
|
3543
4181
|
}
|
|
3544
4182
|
)
|
|
3545
4183
|
] }),
|
|
3546
|
-
aiError && /* @__PURE__ */ (0,
|
|
3547
|
-
aiSuccess && /* @__PURE__ */ (0,
|
|
4184
|
+
aiError && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
|
|
4185
|
+
aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
|
|
3548
4186
|
] })
|
|
3549
4187
|
] })
|
|
3550
4188
|
] })
|
|
@@ -3554,8 +4192,8 @@ var ImageEditor = ({
|
|
|
3554
4192
|
};
|
|
3555
4193
|
|
|
3556
4194
|
// src/review/useReview.ts
|
|
3557
|
-
var
|
|
3558
|
-
var
|
|
4195
|
+
var import_react29 = require("react");
|
|
4196
|
+
var import_editor11 = require("@pixerate/editor");
|
|
3559
4197
|
var EMPTY_COMMENTS = Object.freeze({
|
|
3560
4198
|
threads: [],
|
|
3561
4199
|
activeThreadId: null
|
|
@@ -3572,24 +4210,24 @@ function isCommentStore(value) {
|
|
|
3572
4210
|
return !!value && typeof value.getSnapshot === "function" && typeof value.createThread === "function";
|
|
3573
4211
|
}
|
|
3574
4212
|
function useComments(source) {
|
|
3575
|
-
const store = isCommentStore(source) ? source : (0,
|
|
3576
|
-
const subscribe = (0,
|
|
4213
|
+
const store = isCommentStore(source) ? source : (0, import_editor11.getCommentStore)(source);
|
|
4214
|
+
const subscribe = (0, import_react29.useCallback)(
|
|
3577
4215
|
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
3578
4216
|
[store]
|
|
3579
4217
|
);
|
|
3580
4218
|
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
|
|
3581
|
-
const snapshot = (0,
|
|
3582
|
-
return (0,
|
|
4219
|
+
const snapshot = (0, import_react29.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
4220
|
+
return (0, import_react29.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
|
|
3583
4221
|
}
|
|
3584
4222
|
function useTrackChanges(editor) {
|
|
3585
|
-
const store = (0,
|
|
3586
|
-
const subscribe = (0,
|
|
4223
|
+
const store = (0, import_editor11.getTrackChangesStore)(editor ?? null);
|
|
4224
|
+
const subscribe = (0, import_react29.useCallback)(
|
|
3587
4225
|
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
3588
4226
|
[store]
|
|
3589
4227
|
);
|
|
3590
4228
|
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
|
|
3591
|
-
const snapshot = (0,
|
|
3592
|
-
return (0,
|
|
4229
|
+
const snapshot = (0, import_react29.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
4230
|
+
return (0, import_react29.useMemo)(() => {
|
|
3593
4231
|
const run = (fn) => () => {
|
|
3594
4232
|
if (editor && !editor.isDestroyed) fn(editor);
|
|
3595
4233
|
};
|
|
@@ -3609,9 +4247,9 @@ function useTrackChanges(editor) {
|
|
|
3609
4247
|
}
|
|
3610
4248
|
|
|
3611
4249
|
// src/review/CommentsPanel.tsx
|
|
3612
|
-
var
|
|
3613
|
-
var
|
|
3614
|
-
var
|
|
4250
|
+
var import_react30 = require("react");
|
|
4251
|
+
var import_editor12 = require("@pixerate/editor");
|
|
4252
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3615
4253
|
var buttonClass = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
|
|
3616
4254
|
var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
|
|
3617
4255
|
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";
|
|
@@ -3621,22 +4259,22 @@ var CommentsPanel = ({
|
|
|
3621
4259
|
author: authorProp,
|
|
3622
4260
|
showResolved: showResolvedInitial = false,
|
|
3623
4261
|
className = "flex flex-col gap-2 text-sm text-foreground",
|
|
3624
|
-
formatTime = (t) => (0,
|
|
4262
|
+
formatTime = (t) => (0, import_editor12.formatReviewTime)(t),
|
|
3625
4263
|
emptyMessage = "No comments yet. Select text and add a comment."
|
|
3626
4264
|
}) => {
|
|
3627
4265
|
const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
|
|
3628
|
-
const [showResolved, setShowResolved] = (0,
|
|
3629
|
-
const author = authorProp ?? (0,
|
|
4266
|
+
const [showResolved, setShowResolved] = (0, import_react30.useState)(showResolvedInitial);
|
|
4267
|
+
const author = authorProp ?? (0, import_editor12.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
|
|
3630
4268
|
const visible = threads.filter((t) => showResolved || !t.resolved);
|
|
3631
4269
|
const resolvedCount = threads.filter((t) => t.resolved).length;
|
|
3632
|
-
return /* @__PURE__ */ (0,
|
|
3633
|
-
/* @__PURE__ */ (0,
|
|
3634
|
-
/* @__PURE__ */ (0,
|
|
4270
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("aside", { className, "aria-label": "Comments", children: [
|
|
4271
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
4272
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
|
|
3635
4273
|
threads.length - resolvedCount,
|
|
3636
4274
|
" open",
|
|
3637
4275
|
resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
|
|
3638
4276
|
] }),
|
|
3639
|
-
resolvedCount > 0 && /* @__PURE__ */ (0,
|
|
4277
|
+
resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3640
4278
|
"button",
|
|
3641
4279
|
{
|
|
3642
4280
|
type: "button",
|
|
@@ -3647,7 +4285,7 @@ var CommentsPanel = ({
|
|
|
3647
4285
|
}
|
|
3648
4286
|
)
|
|
3649
4287
|
] }),
|
|
3650
|
-
visible.length === 0 ? /* @__PURE__ */ (0,
|
|
4288
|
+
visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3651
4289
|
CommentThreadCard,
|
|
3652
4290
|
{
|
|
3653
4291
|
thread,
|
|
@@ -3669,7 +4307,7 @@ var CommentThreadCard = ({
|
|
|
3669
4307
|
author,
|
|
3670
4308
|
formatTime
|
|
3671
4309
|
}) => {
|
|
3672
|
-
const [draft, setDraft] = (0,
|
|
4310
|
+
const [draft, setDraft] = (0, import_react30.useState)("");
|
|
3673
4311
|
const isDraft = thread.body === "";
|
|
3674
4312
|
const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
|
|
3675
4313
|
const live = editor && !editor.isDestroyed ? editor : null;
|
|
@@ -3695,7 +4333,7 @@ var CommentThreadCard = ({
|
|
|
3695
4333
|
setDraft("");
|
|
3696
4334
|
};
|
|
3697
4335
|
const stop = (e) => e.stopPropagation();
|
|
3698
|
-
return /* @__PURE__ */ (0,
|
|
4336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
3699
4337
|
"li",
|
|
3700
4338
|
{
|
|
3701
4339
|
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" : ""}`,
|
|
@@ -3711,24 +4349,24 @@ var CommentThreadCard = ({
|
|
|
3711
4349
|
}
|
|
3712
4350
|
},
|
|
3713
4351
|
children: [
|
|
3714
|
-
/* @__PURE__ */ (0,
|
|
3715
|
-
/* @__PURE__ */ (0,
|
|
3716
|
-
/* @__PURE__ */ (0,
|
|
4352
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
4353
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-medium", children: thread.author.name }),
|
|
4354
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
|
|
3717
4355
|
] }),
|
|
3718
|
-
quote && /* @__PURE__ */ (0,
|
|
3719
|
-
thread.orphaned && /* @__PURE__ */ (0,
|
|
3720
|
-
thread.resolved && /* @__PURE__ */ (0,
|
|
3721
|
-
!isDraft && /* @__PURE__ */ (0,
|
|
3722
|
-
thread.replies.length > 0 && /* @__PURE__ */ (0,
|
|
3723
|
-
/* @__PURE__ */ (0,
|
|
3724
|
-
/* @__PURE__ */ (0,
|
|
4356
|
+
quote && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
|
|
4357
|
+
thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
|
|
4358
|
+
thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
|
|
4359
|
+
!isDraft && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
|
|
4360
|
+
thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ul", { className: "flex flex-col gap-2 border-l border-border pl-3", role: "list", children: thread.replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
|
|
4361
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-xs", children: [
|
|
4362
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "font-medium", children: reply.author.name }),
|
|
3725
4363
|
" ",
|
|
3726
|
-
/* @__PURE__ */ (0,
|
|
4364
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
|
|
3727
4365
|
] }),
|
|
3728
|
-
/* @__PURE__ */ (0,
|
|
4366
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
|
|
3729
4367
|
] }, reply.id)) }),
|
|
3730
|
-
(active || isDraft) && !thread.resolved && /* @__PURE__ */ (0,
|
|
3731
|
-
/* @__PURE__ */ (0,
|
|
4368
|
+
(active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
|
|
4369
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3732
4370
|
"textarea",
|
|
3733
4371
|
{
|
|
3734
4372
|
className: textareaClass,
|
|
@@ -3746,9 +4384,9 @@ var CommentThreadCard = ({
|
|
|
3746
4384
|
}
|
|
3747
4385
|
}
|
|
3748
4386
|
),
|
|
3749
|
-
/* @__PURE__ */ (0,
|
|
3750
|
-
isDraft && /* @__PURE__ */ (0,
|
|
3751
|
-
/* @__PURE__ */ (0,
|
|
4387
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-end gap-1", children: [
|
|
4388
|
+
isDraft && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass, onClick: remove, children: "Cancel" }),
|
|
4389
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3752
4390
|
"button",
|
|
3753
4391
|
{
|
|
3754
4392
|
type: "button",
|
|
@@ -3760,9 +4398,9 @@ var CommentThreadCard = ({
|
|
|
3760
4398
|
)
|
|
3761
4399
|
] })
|
|
3762
4400
|
] }),
|
|
3763
|
-
!isDraft && /* @__PURE__ */ (0,
|
|
3764
|
-
/* @__PURE__ */ (0,
|
|
3765
|
-
/* @__PURE__ */ (0,
|
|
4401
|
+
!isDraft && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
|
|
4402
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", className: buttonClass, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
|
|
4403
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3766
4404
|
"button",
|
|
3767
4405
|
{
|
|
3768
4406
|
type: "button",
|
|
@@ -3778,7 +4416,7 @@ var CommentThreadCard = ({
|
|
|
3778
4416
|
};
|
|
3779
4417
|
|
|
3780
4418
|
// src/review/ReviewToolbar.tsx
|
|
3781
|
-
var
|
|
4419
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3782
4420
|
var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
|
|
3783
4421
|
var buttonClass2 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
3784
4422
|
var ReviewToolbar = ({
|
|
@@ -3791,8 +4429,8 @@ var ReviewToolbar = ({
|
|
|
3791
4429
|
const count = review.changes.length;
|
|
3792
4430
|
const current = review.currentChange;
|
|
3793
4431
|
const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
|
|
3794
|
-
return /* @__PURE__ */ (0,
|
|
3795
|
-
/* @__PURE__ */ (0,
|
|
4432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
|
|
4433
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3796
4434
|
"button",
|
|
3797
4435
|
{
|
|
3798
4436
|
type: "button",
|
|
@@ -3803,8 +4441,8 @@ var ReviewToolbar = ({
|
|
|
3803
4441
|
children: review.enabled ? "Tracking on" : "Track changes"
|
|
3804
4442
|
}
|
|
3805
4443
|
),
|
|
3806
|
-
/* @__PURE__ */ (0,
|
|
3807
|
-
/* @__PURE__ */ (0,
|
|
4444
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
4445
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3808
4446
|
"button",
|
|
3809
4447
|
{
|
|
3810
4448
|
type: "button",
|
|
@@ -3815,8 +4453,8 @@ var ReviewToolbar = ({
|
|
|
3815
4453
|
children: "\u2039"
|
|
3816
4454
|
}
|
|
3817
4455
|
),
|
|
3818
|
-
/* @__PURE__ */ (0,
|
|
3819
|
-
/* @__PURE__ */ (0,
|
|
4456
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("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` }),
|
|
4457
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3820
4458
|
"button",
|
|
3821
4459
|
{
|
|
3822
4460
|
type: "button",
|
|
@@ -3827,7 +4465,7 @@ var ReviewToolbar = ({
|
|
|
3827
4465
|
children: "\u203A"
|
|
3828
4466
|
}
|
|
3829
4467
|
),
|
|
3830
|
-
showDescription && current && /* @__PURE__ */ (0,
|
|
4468
|
+
showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
3831
4469
|
"span",
|
|
3832
4470
|
{
|
|
3833
4471
|
className: descriptionClassName,
|
|
@@ -3839,8 +4477,8 @@ var ReviewToolbar = ({
|
|
|
3839
4477
|
]
|
|
3840
4478
|
}
|
|
3841
4479
|
),
|
|
3842
|
-
/* @__PURE__ */ (0,
|
|
3843
|
-
/* @__PURE__ */ (0,
|
|
4480
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
4481
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3844
4482
|
"button",
|
|
3845
4483
|
{
|
|
3846
4484
|
type: "button",
|
|
@@ -3850,7 +4488,7 @@ var ReviewToolbar = ({
|
|
|
3850
4488
|
children: "Accept"
|
|
3851
4489
|
}
|
|
3852
4490
|
),
|
|
3853
|
-
/* @__PURE__ */ (0,
|
|
4491
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3854
4492
|
"button",
|
|
3855
4493
|
{
|
|
3856
4494
|
type: "button",
|
|
@@ -3860,18 +4498,18 @@ var ReviewToolbar = ({
|
|
|
3860
4498
|
children: "Reject"
|
|
3861
4499
|
}
|
|
3862
4500
|
),
|
|
3863
|
-
/* @__PURE__ */ (0,
|
|
3864
|
-
/* @__PURE__ */ (0,
|
|
4501
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
|
|
4502
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
|
|
3865
4503
|
] });
|
|
3866
4504
|
};
|
|
3867
4505
|
|
|
3868
4506
|
// src/review/CommentButton.tsx
|
|
3869
|
-
var
|
|
4507
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3870
4508
|
var CommentButton = ({
|
|
3871
4509
|
editor,
|
|
3872
4510
|
className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
|
|
3873
4511
|
children = "Comment"
|
|
3874
|
-
}) => /* @__PURE__ */ (0,
|
|
4512
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3875
4513
|
"button",
|
|
3876
4514
|
{
|
|
3877
4515
|
type: "button",
|
|
@@ -3882,13 +4520,36 @@ var CommentButton = ({
|
|
|
3882
4520
|
}
|
|
3883
4521
|
);
|
|
3884
4522
|
|
|
4523
|
+
// src/review/useDocumentCompare.ts
|
|
4524
|
+
var import_react31 = require("react");
|
|
4525
|
+
var import_editor13 = require("@pixerate/editor");
|
|
4526
|
+
function useDocumentCompare(editor, options) {
|
|
4527
|
+
const [summary, setSummary] = (0, import_react31.useState)(null);
|
|
4528
|
+
const defaults = (0, import_react31.useRef)(options);
|
|
4529
|
+
defaults.current = options;
|
|
4530
|
+
const compare = (0, import_react31.useCallback)(
|
|
4531
|
+
(original, revised, overrides) => {
|
|
4532
|
+
if (!editor || editor.isDestroyed) return null;
|
|
4533
|
+
const result = (0, import_editor13.applyDocumentComparison)(editor, original, revised, {
|
|
4534
|
+
...defaults.current,
|
|
4535
|
+
...overrides
|
|
4536
|
+
});
|
|
4537
|
+
setSummary(result.summary);
|
|
4538
|
+
return result.summary;
|
|
4539
|
+
},
|
|
4540
|
+
[editor]
|
|
4541
|
+
);
|
|
4542
|
+
const clear = (0, import_react31.useCallback)(() => setSummary(null), []);
|
|
4543
|
+
return (0, import_react31.useMemo)(() => ({ summary, compare, clear }), [summary, compare, clear]);
|
|
4544
|
+
}
|
|
4545
|
+
|
|
3885
4546
|
// src/commands/useCommandPalette.ts
|
|
3886
|
-
var
|
|
4547
|
+
var import_react32 = require("react");
|
|
3887
4548
|
var import_commands2 = require("@pixerate/editor/commands");
|
|
3888
4549
|
function useCommandPalette(registry, options = {}) {
|
|
3889
|
-
const optionsRef = (0,
|
|
4550
|
+
const optionsRef = (0, import_react32.useRef)(options);
|
|
3890
4551
|
optionsRef.current = options;
|
|
3891
|
-
const controller = (0,
|
|
4552
|
+
const controller = (0, import_react32.useMemo)(
|
|
3892
4553
|
() => (0, import_commands2.createCommandPaletteController)(registry, {
|
|
3893
4554
|
context: () => {
|
|
3894
4555
|
const c = optionsRef.current.context;
|
|
@@ -3909,9 +4570,9 @@ function useCommandPalette(registry, options = {}) {
|
|
|
3909
4570
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3910
4571
|
[registry]
|
|
3911
4572
|
);
|
|
3912
|
-
const state = (0,
|
|
4573
|
+
const state = (0, import_react32.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
|
|
3913
4574
|
const { hotkey, hotkeyTarget } = options;
|
|
3914
|
-
(0,
|
|
4575
|
+
(0, import_react32.useEffect)(() => {
|
|
3915
4576
|
if (!hotkey) return;
|
|
3916
4577
|
const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
|
|
3917
4578
|
if (!target) return;
|
|
@@ -3939,13 +4600,13 @@ function useCommandPalette(registry, options = {}) {
|
|
|
3939
4600
|
}
|
|
3940
4601
|
|
|
3941
4602
|
// src/commands/CommandPalette.tsx
|
|
3942
|
-
var
|
|
3943
|
-
var
|
|
4603
|
+
var import_react33 = __toESM(require("react"), 1);
|
|
4604
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
3944
4605
|
function HighlightedLabel({ item }) {
|
|
3945
|
-
if (item.labelIndices.length === 0) return /* @__PURE__ */ (0,
|
|
4606
|
+
if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: item.label });
|
|
3946
4607
|
const marked = new Set(item.labelIndices);
|
|
3947
|
-
return /* @__PURE__ */ (0,
|
|
3948
|
-
(ch, i) => marked.has(i) ? /* @__PURE__ */ (0,
|
|
4608
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children: Array.from(item.label).map(
|
|
4609
|
+
(ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react33.default.Fragment, { children: ch }, i)
|
|
3949
4610
|
) });
|
|
3950
4611
|
}
|
|
3951
4612
|
var CommandPalette = ({
|
|
@@ -3954,22 +4615,22 @@ var CommandPalette = ({
|
|
|
3954
4615
|
emptyMessage = "No matching commands",
|
|
3955
4616
|
className = ""
|
|
3956
4617
|
}) => {
|
|
3957
|
-
const inputRef = (0,
|
|
3958
|
-
const listRef = (0,
|
|
3959
|
-
const baseId = (0,
|
|
4618
|
+
const inputRef = (0, import_react33.useRef)(null);
|
|
4619
|
+
const listRef = (0, import_react33.useRef)(null);
|
|
4620
|
+
const baseId = (0, import_react33.useId)();
|
|
3960
4621
|
const listId = `${baseId}-list`;
|
|
3961
4622
|
const optionId = (index) => `${baseId}-option-${index}`;
|
|
3962
4623
|
const { open, query, items, activeIndex } = palette;
|
|
3963
|
-
(0,
|
|
4624
|
+
(0, import_react33.useEffect)(() => {
|
|
3964
4625
|
if (open) inputRef.current?.focus();
|
|
3965
4626
|
}, [open]);
|
|
3966
|
-
(0,
|
|
4627
|
+
(0, import_react33.useEffect)(() => {
|
|
3967
4628
|
if (!open) return;
|
|
3968
4629
|
const active = listRef.current?.querySelector('[aria-selected="true"]');
|
|
3969
4630
|
active?.scrollIntoView?.({ block: "nearest" });
|
|
3970
4631
|
}, [open, activeIndex]);
|
|
3971
4632
|
if (!open) return null;
|
|
3972
|
-
return /* @__PURE__ */ (0,
|
|
4633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3973
4634
|
"div",
|
|
3974
4635
|
{
|
|
3975
4636
|
className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
|
|
@@ -3977,7 +4638,7 @@ var CommandPalette = ({
|
|
|
3977
4638
|
onMouseDown: (e) => {
|
|
3978
4639
|
if (e.target === e.currentTarget) palette.setOpen(false);
|
|
3979
4640
|
},
|
|
3980
|
-
children: /* @__PURE__ */ (0,
|
|
4641
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
3981
4642
|
"div",
|
|
3982
4643
|
{
|
|
3983
4644
|
role: "dialog",
|
|
@@ -3986,7 +4647,7 @@ var CommandPalette = ({
|
|
|
3986
4647
|
className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
|
|
3987
4648
|
style: { background: "var(--popover, var(--background, #fff))" },
|
|
3988
4649
|
children: [
|
|
3989
|
-
/* @__PURE__ */ (0,
|
|
4650
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3990
4651
|
"input",
|
|
3991
4652
|
{
|
|
3992
4653
|
ref: inputRef,
|
|
@@ -4006,7 +4667,7 @@ var CommandPalette = ({
|
|
|
4006
4667
|
className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
|
|
4007
4668
|
}
|
|
4008
4669
|
),
|
|
4009
|
-
items.length === 0 ? /* @__PURE__ */ (0,
|
|
4670
|
+
items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { ref: listRef, id: listId, role: "listbox", "aria-label": "Commands", className: "max-h-80 overflow-y-auto py-1", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
4010
4671
|
"li",
|
|
4011
4672
|
{
|
|
4012
4673
|
id: optionId(index),
|
|
@@ -4021,12 +4682,12 @@ var CommandPalette = ({
|
|
|
4021
4682
|
onClick: () => palette.run(item.id),
|
|
4022
4683
|
className: `flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm ${index === activeIndex ? "bg-muted" : ""} ${item.enabled ? "" : "cursor-default opacity-50"}`,
|
|
4023
4684
|
children: [
|
|
4024
|
-
/* @__PURE__ */ (0,
|
|
4025
|
-
/* @__PURE__ */ (0,
|
|
4026
|
-
item.disabledReason && /* @__PURE__ */ (0,
|
|
4685
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
4686
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(HighlightedLabel, { item }),
|
|
4687
|
+
item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
|
|
4027
4688
|
] }),
|
|
4028
|
-
item.group && /* @__PURE__ */ (0,
|
|
4029
|
-
item.shortcut && /* @__PURE__ */ (0,
|
|
4689
|
+
item.group && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
|
|
4690
|
+
item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
|
|
4030
4691
|
]
|
|
4031
4692
|
},
|
|
4032
4693
|
item.id
|
|
@@ -4039,12 +4700,12 @@ var CommandPalette = ({
|
|
|
4039
4700
|
};
|
|
4040
4701
|
|
|
4041
4702
|
// src/commands/useCommandShortcuts.ts
|
|
4042
|
-
var
|
|
4703
|
+
var import_react34 = require("react");
|
|
4043
4704
|
function useCommandShortcuts(registry, options = {}) {
|
|
4044
|
-
const optionsRef = (0,
|
|
4705
|
+
const optionsRef = (0, import_react34.useRef)(options);
|
|
4045
4706
|
optionsRef.current = options;
|
|
4046
4707
|
const { enabled = true, target } = options;
|
|
4047
|
-
(0,
|
|
4708
|
+
(0, import_react34.useEffect)(() => {
|
|
4048
4709
|
if (!registry || !enabled) return;
|
|
4049
4710
|
const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
|
|
4050
4711
|
if (!eventTarget) return;
|
|
@@ -4062,24 +4723,589 @@ function useCommandShortcuts(registry, options = {}) {
|
|
|
4062
4723
|
}, [registry, enabled, target]);
|
|
4063
4724
|
}
|
|
4064
4725
|
function useRegisterCommands(registry, specs) {
|
|
4065
|
-
(0,
|
|
4726
|
+
(0, import_react34.useEffect)(() => {
|
|
4066
4727
|
if (!registry || !specs || specs.length === 0) return;
|
|
4067
4728
|
return registry.register(specs);
|
|
4068
4729
|
}, [registry, specs]);
|
|
4069
4730
|
}
|
|
4731
|
+
|
|
4732
|
+
// src/persistence/useAutosave.ts
|
|
4733
|
+
var import_react35 = require("react");
|
|
4734
|
+
var import_persistence = require("@pixerate/editor/persistence");
|
|
4735
|
+
var IDLE = {
|
|
4736
|
+
status: "idle",
|
|
4737
|
+
error: null,
|
|
4738
|
+
failures: 0,
|
|
4739
|
+
nextAttemptAt: null,
|
|
4740
|
+
lastSavedAt: null,
|
|
4741
|
+
ready: false
|
|
4742
|
+
};
|
|
4743
|
+
function useAutosave(options) {
|
|
4744
|
+
const optionsRef = (0, import_react35.useRef)(options);
|
|
4745
|
+
optionsRef.current = options;
|
|
4746
|
+
const { storage, key, history, dirty } = options;
|
|
4747
|
+
const recover = options.recover !== false;
|
|
4748
|
+
const flushOnHide = options.flushOnHide !== false;
|
|
4749
|
+
const ready = options.ready !== false;
|
|
4750
|
+
const [controller, setController] = (0, import_react35.useState)(null);
|
|
4751
|
+
const [status, setStatus] = (0, import_react35.useState)(IDLE);
|
|
4752
|
+
const [recovery, setRecovery] = (0, import_react35.useState)(null);
|
|
4753
|
+
const [pendingRecovery, setPendingRecovery] = (0, import_react35.useState)(recover);
|
|
4754
|
+
const revisionsRef = (0, import_react35.useRef)(null);
|
|
4755
|
+
(0, import_react35.useEffect)(() => {
|
|
4756
|
+
const revisions = (0, import_persistence.createRevisionTracker)({ history, dirty });
|
|
4757
|
+
const o = optionsRef.current;
|
|
4758
|
+
const instance = (0, import_persistence.createAutosaveController)({
|
|
4759
|
+
storage,
|
|
4760
|
+
key,
|
|
4761
|
+
getSnapshot: () => optionsRef.current.getSnapshot(),
|
|
4762
|
+
serialize: o.serialize,
|
|
4763
|
+
deserialize: o.deserialize,
|
|
4764
|
+
name: () => optionsRef.current.name,
|
|
4765
|
+
revision: revisions.revision,
|
|
4766
|
+
savedRevision: revisions.savedRevision,
|
|
4767
|
+
interval: o.interval,
|
|
4768
|
+
debounceMs: o.debounceMs,
|
|
4769
|
+
retryBaseMs: o.retryBaseMs,
|
|
4770
|
+
retryMaxMs: o.retryMaxMs
|
|
4771
|
+
});
|
|
4772
|
+
const unsubscribeStatus = instance.subscribe(setStatus);
|
|
4773
|
+
const unsubscribeRevisions = revisions.subscribe(() => instance.notify());
|
|
4774
|
+
revisionsRef.current = revisions;
|
|
4775
|
+
setController(instance);
|
|
4776
|
+
setStatus(instance.getStatus());
|
|
4777
|
+
let active = true;
|
|
4778
|
+
if (recover) {
|
|
4779
|
+
setPendingRecovery(true);
|
|
4780
|
+
instance.checkRecovery().catch(() => null).then((found) => {
|
|
4781
|
+
if (!active) return;
|
|
4782
|
+
setRecovery(found);
|
|
4783
|
+
setPendingRecovery(found !== null);
|
|
4784
|
+
});
|
|
4785
|
+
} else {
|
|
4786
|
+
setRecovery(null);
|
|
4787
|
+
setPendingRecovery(false);
|
|
4788
|
+
}
|
|
4789
|
+
return () => {
|
|
4790
|
+
active = false;
|
|
4791
|
+
unsubscribeStatus();
|
|
4792
|
+
unsubscribeRevisions();
|
|
4793
|
+
revisions.destroy();
|
|
4794
|
+
instance.destroy();
|
|
4795
|
+
if (revisionsRef.current === revisions) revisionsRef.current = null;
|
|
4796
|
+
};
|
|
4797
|
+
}, [storage, key, history, dirty, recover]);
|
|
4798
|
+
(0, import_react35.useEffect)(() => {
|
|
4799
|
+
if (controller && ready && !pendingRecovery) controller.ready();
|
|
4800
|
+
}, [controller, ready, pendingRecovery]);
|
|
4801
|
+
(0, import_react35.useEffect)(() => {
|
|
4802
|
+
if (!controller || !flushOnHide || typeof window === "undefined") return;
|
|
4803
|
+
const flush = () => void controller.flushNow();
|
|
4804
|
+
const onVisibility = () => {
|
|
4805
|
+
if (document.visibilityState === "hidden") flush();
|
|
4806
|
+
};
|
|
4807
|
+
window.addEventListener("pagehide", flush);
|
|
4808
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
4809
|
+
return () => {
|
|
4810
|
+
window.removeEventListener("pagehide", flush);
|
|
4811
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
4812
|
+
};
|
|
4813
|
+
}, [controller, flushOnHide]);
|
|
4814
|
+
const restore = (0, import_react35.useCallback)(() => {
|
|
4815
|
+
const snapshot = recovery?.snapshot;
|
|
4816
|
+
setRecovery(null);
|
|
4817
|
+
setPendingRecovery(false);
|
|
4818
|
+
return snapshot;
|
|
4819
|
+
}, [recovery]);
|
|
4820
|
+
const discard = (0, import_react35.useCallback)(async () => {
|
|
4821
|
+
if (controller) await controller.discardRecovery();
|
|
4822
|
+
setRecovery(null);
|
|
4823
|
+
setPendingRecovery(false);
|
|
4824
|
+
}, [controller]);
|
|
4825
|
+
const flushNow = (0, import_react35.useCallback)(async () => {
|
|
4826
|
+
await controller?.flushNow();
|
|
4827
|
+
}, [controller]);
|
|
4828
|
+
const markClean = (0, import_react35.useCallback)(async () => {
|
|
4829
|
+
revisionsRef.current?.markSaved();
|
|
4830
|
+
await controller?.markClean();
|
|
4831
|
+
}, [controller]);
|
|
4832
|
+
const notifyChange = (0, import_react35.useCallback)(() => revisionsRef.current?.bump(), []);
|
|
4833
|
+
return { status, recovery, pendingRecovery, restore, discard, flushNow, markClean, notifyChange, controller };
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4836
|
+
// src/persistence/RecoveryPrompt.tsx
|
|
4837
|
+
var import_persistence2 = require("@pixerate/editor/persistence");
|
|
4838
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
4839
|
+
var RecoveryPrompt = ({
|
|
4840
|
+
recovery,
|
|
4841
|
+
onRestore,
|
|
4842
|
+
onDiscard,
|
|
4843
|
+
formatTime,
|
|
4844
|
+
restoreLabel = "Restore",
|
|
4845
|
+
discardLabel = "Discard",
|
|
4846
|
+
className = ""
|
|
4847
|
+
}) => {
|
|
4848
|
+
if (!recovery) return null;
|
|
4849
|
+
const { name } = recovery.meta;
|
|
4850
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
4851
|
+
"div",
|
|
4852
|
+
{
|
|
4853
|
+
role: "alertdialog",
|
|
4854
|
+
"aria-label": "Unsaved changes found",
|
|
4855
|
+
"data-recovery-prompt": "",
|
|
4856
|
+
className: `flex flex-wrap items-center gap-3 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm ${className}`,
|
|
4857
|
+
children: [
|
|
4858
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "min-w-0 flex-1", children: [
|
|
4859
|
+
(0, import_persistence2.formatRecoveryMessage)(recovery.meta, formatTime),
|
|
4860
|
+
name ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "ml-1 text-xs text-muted-foreground", children: [
|
|
4861
|
+
"(",
|
|
4862
|
+
name,
|
|
4863
|
+
")"
|
|
4864
|
+
] }) : null
|
|
4865
|
+
] }),
|
|
4866
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4867
|
+
"button",
|
|
4868
|
+
{
|
|
4869
|
+
type: "button",
|
|
4870
|
+
"data-recovery-restore": "",
|
|
4871
|
+
onClick: onRestore,
|
|
4872
|
+
className: "rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground hover:opacity-90",
|
|
4873
|
+
children: restoreLabel
|
|
4874
|
+
}
|
|
4875
|
+
),
|
|
4876
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
4877
|
+
"button",
|
|
4878
|
+
{
|
|
4879
|
+
type: "button",
|
|
4880
|
+
"data-recovery-discard": "",
|
|
4881
|
+
onClick: onDiscard,
|
|
4882
|
+
className: "rounded-md border border-border px-3 py-1 text-xs font-medium hover:bg-muted",
|
|
4883
|
+
children: discardLabel
|
|
4884
|
+
}
|
|
4885
|
+
)
|
|
4886
|
+
]
|
|
4887
|
+
}
|
|
4888
|
+
);
|
|
4889
|
+
};
|
|
4890
|
+
|
|
4891
|
+
// src/generation/useGenerationPlan.ts
|
|
4892
|
+
var import_react36 = require("react");
|
|
4893
|
+
var import_generation = require("@pixerate/editor/generation");
|
|
4894
|
+
function useGenerationPlan(request, capabilities, options = {}) {
|
|
4895
|
+
const key = JSON.stringify([request, capabilities, options]);
|
|
4896
|
+
return (0, import_react36.useMemo)(() => (0, import_generation.planGenerationRequest)(request, capabilities, options), [key]);
|
|
4897
|
+
}
|
|
4898
|
+
function useJobProgress(options) {
|
|
4899
|
+
const { startedAt, expectedMs, done, now, intervalMs = 1e3 } = options;
|
|
4900
|
+
const [tick, setTick] = (0, import_react36.useState)(() => Date.now());
|
|
4901
|
+
const ticking = !done && now === void 0;
|
|
4902
|
+
(0, import_react36.useEffect)(() => {
|
|
4903
|
+
if (!ticking) return;
|
|
4904
|
+
setTick(Date.now());
|
|
4905
|
+
const id = setInterval(() => setTick(Date.now()), Math.max(16, intervalMs));
|
|
4906
|
+
return () => clearInterval(id);
|
|
4907
|
+
}, [ticking, intervalMs]);
|
|
4908
|
+
return (0, import_generation.estimateJobProgress)({ startedAt, expectedMs, done, now: now ?? tick });
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
// src/generation/GenerationSettings.tsx
|
|
4912
|
+
var import_react37 = require("react");
|
|
4913
|
+
var import_generation2 = require("@pixerate/editor/generation");
|
|
4914
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4915
|
+
var inputClass = "w-full rounded-md border border-border bg-background px-2 py-1 text-sm outline-none focus:ring-1 focus:ring-ring";
|
|
4916
|
+
function Control({
|
|
4917
|
+
control,
|
|
4918
|
+
value,
|
|
4919
|
+
id,
|
|
4920
|
+
onValue
|
|
4921
|
+
}) {
|
|
4922
|
+
const shown = value ?? control.defaultValue;
|
|
4923
|
+
if (control.kind === "checkbox") {
|
|
4924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
4925
|
+
"input",
|
|
4926
|
+
{
|
|
4927
|
+
id,
|
|
4928
|
+
type: "checkbox",
|
|
4929
|
+
"data-field": control.key,
|
|
4930
|
+
checked: Boolean(shown),
|
|
4931
|
+
onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.checked))
|
|
4932
|
+
}
|
|
4933
|
+
);
|
|
4934
|
+
}
|
|
4935
|
+
if (control.kind === "select") {
|
|
4936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
4937
|
+
"select",
|
|
4938
|
+
{
|
|
4939
|
+
id,
|
|
4940
|
+
"data-field": control.key,
|
|
4941
|
+
className: inputClass,
|
|
4942
|
+
value: shown === void 0 ? "" : String(shown),
|
|
4943
|
+
onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value)),
|
|
4944
|
+
children: [
|
|
4945
|
+
shown === void 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "", children: "Default" }),
|
|
4946
|
+
control.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: String(option.value), children: option.label }, String(option.value)))
|
|
4947
|
+
]
|
|
4948
|
+
}
|
|
4949
|
+
);
|
|
4950
|
+
}
|
|
4951
|
+
if (control.kind === "textarea") {
|
|
4952
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
4953
|
+
"textarea",
|
|
4954
|
+
{
|
|
4955
|
+
id,
|
|
4956
|
+
"data-field": control.key,
|
|
4957
|
+
className: inputClass,
|
|
4958
|
+
rows: 2,
|
|
4959
|
+
maxLength: control.maxLength,
|
|
4960
|
+
value: typeof value === "string" ? value : "",
|
|
4961
|
+
onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
|
|
4962
|
+
}
|
|
4963
|
+
);
|
|
4964
|
+
}
|
|
4965
|
+
const numeric = typeof shown === "number" ? shown : void 0;
|
|
4966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
4967
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
4968
|
+
"input",
|
|
4969
|
+
{
|
|
4970
|
+
id,
|
|
4971
|
+
type: control.kind === "range" ? "range" : "number",
|
|
4972
|
+
"data-field": control.key,
|
|
4973
|
+
className: control.kind === "range" ? "flex-1" : inputClass,
|
|
4974
|
+
min: control.min,
|
|
4975
|
+
max: control.max,
|
|
4976
|
+
step: control.step ?? "any",
|
|
4977
|
+
value: numeric ?? (control.kind === "range" ? control.min ?? 0 : ""),
|
|
4978
|
+
onChange: (e) => onValue((0, import_generation2.parseControlValue)(control, e.target.value))
|
|
4979
|
+
}
|
|
4980
|
+
),
|
|
4981
|
+
control.kind === "range" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-10 text-right tabular-nums text-muted-foreground", "data-field-value": "", children: numeric ?? "\u2013" })
|
|
4982
|
+
] });
|
|
4983
|
+
}
|
|
4984
|
+
var GenerationSettings = ({
|
|
4985
|
+
capabilities,
|
|
4986
|
+
value,
|
|
4987
|
+
onChange,
|
|
4988
|
+
plan: planProp,
|
|
4989
|
+
strategy,
|
|
4990
|
+
showAdjustments = true,
|
|
4991
|
+
onAddReference,
|
|
4992
|
+
renderReference,
|
|
4993
|
+
className = ""
|
|
4994
|
+
}) => {
|
|
4995
|
+
const baseId = (0, import_react37.useId)();
|
|
4996
|
+
const controls = (0, import_react37.useMemo)(() => (0, import_generation2.getGenerationControls)(capabilities), [capabilities]);
|
|
4997
|
+
const computed = useGenerationPlan(value, capabilities, { strategy });
|
|
4998
|
+
const plan = planProp ?? computed;
|
|
4999
|
+
const slots = (0, import_generation2.getReferenceSlots)(capabilities, value);
|
|
5000
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `flex flex-col gap-3 text-sm ${className}`, "data-generation-settings": "", "data-model": capabilities.id, children: [
|
|
5001
|
+
controls.map((control) => {
|
|
5002
|
+
const id = `${baseId}-${control.key}`;
|
|
5003
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex flex-col gap-1", "data-control": control.key, children: [
|
|
5004
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: id, className: "text-xs font-medium text-muted-foreground", title: control.description, children: control.label }),
|
|
5005
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5006
|
+
Control,
|
|
5007
|
+
{
|
|
5008
|
+
control,
|
|
5009
|
+
id,
|
|
5010
|
+
value: (0, import_generation2.getRequestValue)(value, control.key),
|
|
5011
|
+
onValue: (next) => onChange((0, import_generation2.setRequestValue)(value, control.key, next))
|
|
5012
|
+
}
|
|
5013
|
+
)
|
|
5014
|
+
] }, control.key);
|
|
5015
|
+
}),
|
|
5016
|
+
slots.map((slot) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "flex flex-col gap-1", "data-reference-role": slot.role, children: [
|
|
5017
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("legend", { className: "text-xs font-medium text-muted-foreground", title: slot.description, children: [
|
|
5018
|
+
slot.label,
|
|
5019
|
+
" ",
|
|
5020
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "tabular-nums", "data-reference-count": "", children: [
|
|
5021
|
+
"(",
|
|
5022
|
+
slot.references.length,
|
|
5023
|
+
"/",
|
|
5024
|
+
slot.max,
|
|
5025
|
+
")"
|
|
5026
|
+
] }),
|
|
5027
|
+
slot.min > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-destructive", children: " *" })
|
|
5028
|
+
] }),
|
|
5029
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("ul", { className: "flex flex-wrap gap-1", children: [
|
|
5030
|
+
slot.references.map((ref) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-1 rounded border border-border px-1.5 py-0.5", "data-reference-id": ref.id, children: [
|
|
5031
|
+
renderReference ? renderReference(ref) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "max-w-[10rem] truncate", children: ref.id }),
|
|
5032
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5033
|
+
"button",
|
|
5034
|
+
{
|
|
5035
|
+
type: "button",
|
|
5036
|
+
"aria-label": `Remove ${slot.label} ${ref.id}`,
|
|
5037
|
+
className: "text-muted-foreground hover:text-foreground",
|
|
5038
|
+
onClick: () => onChange((0, import_generation2.removeReference)(value, slot.role, ref.id)),
|
|
5039
|
+
children: "\xD7"
|
|
5040
|
+
}
|
|
5041
|
+
)
|
|
5042
|
+
] }, ref.id)),
|
|
5043
|
+
onAddReference && slot.canAdd && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5044
|
+
"button",
|
|
5045
|
+
{
|
|
5046
|
+
type: "button",
|
|
5047
|
+
className: "rounded border border-dashed border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground",
|
|
5048
|
+
onClick: () => onAddReference(slot.role),
|
|
5049
|
+
children: "Add"
|
|
5050
|
+
}
|
|
5051
|
+
) })
|
|
5052
|
+
] })
|
|
5053
|
+
] }, slot.role)),
|
|
5054
|
+
showAdjustments && plan.adjustments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { role: "status", className: "flex flex-col gap-0.5 text-xs text-muted-foreground", "data-generation-adjustments": "", children: plan.adjustments.map((adjustment, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { "data-adjustment-field": adjustment.field, "data-adjustment-kind": adjustment.kind, children: adjustment.reason }, index)) }),
|
|
5055
|
+
showAdjustments && plan.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { role: "alert", className: "flex flex-col gap-0.5 text-xs text-destructive", "data-generation-errors": "", children: plan.errors.map((error, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { "data-error-field": error.field, children: error.message }, index)) })
|
|
5056
|
+
] });
|
|
5057
|
+
};
|
|
5058
|
+
|
|
5059
|
+
// src/generation/JobProgress.tsx
|
|
5060
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
5061
|
+
var JobProgress = ({ title, className = "", ...options }) => {
|
|
5062
|
+
const progress = useJobProgress(options);
|
|
5063
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: `flex flex-col gap-1 text-sm ${className}`, "data-job-progress": "", "data-done": options.done ? "" : void 0, children: [
|
|
5064
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center justify-between gap-2 text-muted-foreground", children: [
|
|
5065
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "truncate text-foreground", children: title }),
|
|
5066
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "data-job-progress-label": "", "aria-live": "polite", children: progress.label })
|
|
5067
|
+
] }),
|
|
5068
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5069
|
+
"div",
|
|
5070
|
+
{
|
|
5071
|
+
role: "progressbar",
|
|
5072
|
+
"aria-label": title ?? "Generation progress",
|
|
5073
|
+
"aria-valuemin": 0,
|
|
5074
|
+
"aria-valuemax": 100,
|
|
5075
|
+
"aria-valuenow": progress.percent,
|
|
5076
|
+
"aria-valuetext": `${progress.percent}%, ${progress.label}`,
|
|
5077
|
+
className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
|
|
5078
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
5079
|
+
"div",
|
|
5080
|
+
{
|
|
5081
|
+
className: "h-full rounded-full bg-primary transition-[width] duration-500",
|
|
5082
|
+
style: { width: `${progress.percent}%`, background: "var(--primary, currentColor)" }
|
|
5083
|
+
}
|
|
5084
|
+
)
|
|
5085
|
+
}
|
|
5086
|
+
)
|
|
5087
|
+
] });
|
|
5088
|
+
};
|
|
5089
|
+
|
|
5090
|
+
// src/find-replace/useFindReplace.ts
|
|
5091
|
+
var import_react38 = require("react");
|
|
5092
|
+
var import_editor14 = require("@pixerate/editor");
|
|
5093
|
+
var noopUnsubscribe2 = () => {
|
|
5094
|
+
};
|
|
5095
|
+
function useFindReplace(editor) {
|
|
5096
|
+
const store = (0, import_editor14.getFindReplaceStore)(editor ?? null);
|
|
5097
|
+
const subscribe = (0, import_react38.useCallback)(
|
|
5098
|
+
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe2,
|
|
5099
|
+
[store]
|
|
5100
|
+
);
|
|
5101
|
+
const getSnapshot = () => store?.getSnapshot() ?? import_editor14.EMPTY_FIND_REPLACE_SNAPSHOT;
|
|
5102
|
+
const snapshot = (0, import_react38.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
5103
|
+
return (0, import_react38.useMemo)(() => {
|
|
5104
|
+
const run = (fn) => {
|
|
5105
|
+
if (editor && !editor.isDestroyed && store) fn(editor);
|
|
5106
|
+
};
|
|
5107
|
+
return {
|
|
5108
|
+
...snapshot,
|
|
5109
|
+
available: !!store,
|
|
5110
|
+
matchCount: snapshot.matches.length,
|
|
5111
|
+
show: (mode = "find") => run((e) => e.commands.openFindReplace({ mode })),
|
|
5112
|
+
close: () => run((e) => e.commands.closeFindReplace()),
|
|
5113
|
+
setQuery: (query) => run((e) => e.commands.setSearch({ query })),
|
|
5114
|
+
setReplacement: (replacement) => run((e) => e.commands.setSearch({ replacement })),
|
|
5115
|
+
setOptions: (options) => run((e) => e.commands.setSearch({ options })),
|
|
5116
|
+
toggleOption: (option) => run((e) => e.commands.setSearch({ options: { [option]: !snapshot.options[option] } })),
|
|
5117
|
+
next: () => run((e) => e.commands.findNext()),
|
|
5118
|
+
previous: () => run((e) => e.commands.findPrevious()),
|
|
5119
|
+
replace: () => run((e) => e.commands.replaceCurrent()),
|
|
5120
|
+
replaceAll: () => run((e) => e.commands.replaceAll()),
|
|
5121
|
+
clear: () => run((e) => e.commands.clearSearch())
|
|
5122
|
+
};
|
|
5123
|
+
}, [snapshot, editor, store]);
|
|
5124
|
+
}
|
|
5125
|
+
|
|
5126
|
+
// src/find-replace/FindReplaceBar.tsx
|
|
5127
|
+
var import_react39 = require("react");
|
|
5128
|
+
var import_editor15 = require("@pixerate/editor");
|
|
5129
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
5130
|
+
var inputClass2 = "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";
|
|
5131
|
+
var buttonClass3 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
5132
|
+
var toggleClass = (on) => `${buttonClass3} font-mono ${on ? "bg-primary/10 text-primary" : "text-muted-foreground"}`;
|
|
5133
|
+
var isMod = (e) => e.metaKey || e.ctrlKey;
|
|
5134
|
+
var FindReplaceBar = ({
|
|
5135
|
+
editor,
|
|
5136
|
+
className = "flex flex-col gap-1 rounded-md border border-border bg-background p-1 text-sm shadow-sm",
|
|
5137
|
+
alwaysOpen = false,
|
|
5138
|
+
showMoreOptions = true,
|
|
5139
|
+
onClose
|
|
5140
|
+
}) => {
|
|
5141
|
+
const find = useFindReplace(editor);
|
|
5142
|
+
const findInput = (0, import_react39.useRef)(null);
|
|
5143
|
+
const [moreOpen, setMoreOpen] = (0, import_react39.useState)(false);
|
|
5144
|
+
const visible = find.available && (alwaysOpen || find.open);
|
|
5145
|
+
(0, import_react39.useEffect)(() => {
|
|
5146
|
+
if (!visible || find.focusRequest === 0) return;
|
|
5147
|
+
findInput.current?.focus();
|
|
5148
|
+
findInput.current?.select();
|
|
5149
|
+
}, [visible, find.focusRequest]);
|
|
5150
|
+
if (!visible) return null;
|
|
5151
|
+
const showReplace = find.mode === "replace";
|
|
5152
|
+
const status = (0, import_editor15.formatFindStatus)(find);
|
|
5153
|
+
const hasMatches = find.matchCount > 0;
|
|
5154
|
+
const close = () => {
|
|
5155
|
+
find.close();
|
|
5156
|
+
editor?.commands.focus();
|
|
5157
|
+
onClose?.();
|
|
5158
|
+
};
|
|
5159
|
+
const onBarKeyDown = (e) => {
|
|
5160
|
+
if (e.key === "Escape") {
|
|
5161
|
+
e.preventDefault();
|
|
5162
|
+
close();
|
|
5163
|
+
} else if (isMod(e) && (e.key === "f" || e.key === "F")) {
|
|
5164
|
+
e.preventDefault();
|
|
5165
|
+
find.show("find");
|
|
5166
|
+
} else if (isMod(e) && (e.key === "h" || e.key === "H")) {
|
|
5167
|
+
e.preventDefault();
|
|
5168
|
+
find.show("replace");
|
|
5169
|
+
}
|
|
5170
|
+
};
|
|
5171
|
+
const onFindKeyDown = (e) => {
|
|
5172
|
+
if (e.key !== "Enter") return;
|
|
5173
|
+
e.preventDefault();
|
|
5174
|
+
if (e.shiftKey) find.previous();
|
|
5175
|
+
else find.next();
|
|
5176
|
+
};
|
|
5177
|
+
const onReplaceKeyDown = (e) => {
|
|
5178
|
+
if (e.key !== "Enter") return;
|
|
5179
|
+
e.preventDefault();
|
|
5180
|
+
if (isMod(e)) find.replaceAll();
|
|
5181
|
+
else find.replace();
|
|
5182
|
+
};
|
|
5183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "search", "aria-label": "Find and replace", onKeyDown: onBarKeyDown, children: [
|
|
5184
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
5185
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5186
|
+
"button",
|
|
5187
|
+
{
|
|
5188
|
+
type: "button",
|
|
5189
|
+
className: buttonClass3,
|
|
5190
|
+
"aria-label": "Toggle replace",
|
|
5191
|
+
"aria-expanded": showReplace,
|
|
5192
|
+
onClick: () => find.show(showReplace ? "find" : "replace"),
|
|
5193
|
+
children: showReplace ? "\u25BE" : "\u25B8"
|
|
5194
|
+
}
|
|
5195
|
+
),
|
|
5196
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5197
|
+
"input",
|
|
5198
|
+
{
|
|
5199
|
+
ref: findInput,
|
|
5200
|
+
type: "text",
|
|
5201
|
+
className: inputClass2,
|
|
5202
|
+
placeholder: "Find",
|
|
5203
|
+
"aria-label": "Find",
|
|
5204
|
+
"aria-invalid": !!find.error,
|
|
5205
|
+
value: find.query,
|
|
5206
|
+
onChange: (e) => find.setQuery(e.target.value),
|
|
5207
|
+
onKeyDown: onFindKeyDown
|
|
5208
|
+
}
|
|
5209
|
+
),
|
|
5210
|
+
import_editor15.FIND_OPTION_TOGGLES.filter((t) => !t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5211
|
+
"button",
|
|
5212
|
+
{
|
|
5213
|
+
type: "button",
|
|
5214
|
+
className: toggleClass(!!find.options[t.key]),
|
|
5215
|
+
"aria-label": t.label,
|
|
5216
|
+
title: t.label,
|
|
5217
|
+
"aria-pressed": !!find.options[t.key],
|
|
5218
|
+
onClick: () => find.toggleOption(t.key),
|
|
5219
|
+
children: t.short
|
|
5220
|
+
},
|
|
5221
|
+
t.key
|
|
5222
|
+
)),
|
|
5223
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5224
|
+
"span",
|
|
5225
|
+
{
|
|
5226
|
+
className: `min-w-[5rem] px-1 text-center text-xs ${find.error ? "text-destructive" : "text-muted-foreground"}`,
|
|
5227
|
+
"aria-live": "polite",
|
|
5228
|
+
role: find.error ? "alert" : "status",
|
|
5229
|
+
"data-testid": "find-status",
|
|
5230
|
+
children: status
|
|
5231
|
+
}
|
|
5232
|
+
),
|
|
5233
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: buttonClass3, "aria-label": "Previous match", disabled: !hasMatches, onClick: find.previous, children: "\u2191" }),
|
|
5234
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: buttonClass3, "aria-label": "Next match", disabled: !hasMatches, onClick: find.next, children: "\u2193" }),
|
|
5235
|
+
showMoreOptions && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5236
|
+
"button",
|
|
5237
|
+
{
|
|
5238
|
+
type: "button",
|
|
5239
|
+
className: buttonClass3,
|
|
5240
|
+
"aria-label": "More options",
|
|
5241
|
+
"aria-expanded": moreOpen,
|
|
5242
|
+
onClick: () => setMoreOpen((v) => !v),
|
|
5243
|
+
children: "\u2026"
|
|
5244
|
+
}
|
|
5245
|
+
),
|
|
5246
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: buttonClass3, "aria-label": "Close find", onClick: close, children: "\xD7" })
|
|
5247
|
+
] }),
|
|
5248
|
+
showReplace && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1 pl-7", children: [
|
|
5249
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5250
|
+
"input",
|
|
5251
|
+
{
|
|
5252
|
+
type: "text",
|
|
5253
|
+
className: inputClass2,
|
|
5254
|
+
placeholder: "Replace",
|
|
5255
|
+
"aria-label": "Replace",
|
|
5256
|
+
value: find.replacement,
|
|
5257
|
+
onChange: (e) => find.setReplacement(e.target.value),
|
|
5258
|
+
onKeyDown: onReplaceKeyDown
|
|
5259
|
+
}
|
|
5260
|
+
),
|
|
5261
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5262
|
+
"button",
|
|
5263
|
+
{
|
|
5264
|
+
type: "button",
|
|
5265
|
+
className: buttonClass3,
|
|
5266
|
+
disabled: !hasMatches || find.currentIndex < 0,
|
|
5267
|
+
onClick: find.replace,
|
|
5268
|
+
children: "Replace"
|
|
5269
|
+
}
|
|
5270
|
+
),
|
|
5271
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", className: buttonClass3, disabled: !hasMatches, onClick: find.replaceAll, children: "Replace all" }),
|
|
5272
|
+
find.lastReplaceCount !== null && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "px-1 text-xs text-muted-foreground", "aria-live": "polite", children: find.lastReplaceCount === 1 ? "1 replaced" : `${find.lastReplaceCount} replaced` })
|
|
5273
|
+
] }),
|
|
5274
|
+
showMoreOptions && moreOpen && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pl-7 text-xs text-muted-foreground", children: import_editor15.FIND_OPTION_TOGGLES.filter((t) => t.advanced).map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className: "flex items-center gap-1", children: [
|
|
5275
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5276
|
+
"input",
|
|
5277
|
+
{
|
|
5278
|
+
type: "checkbox",
|
|
5279
|
+
checked: !!find.options[t.key],
|
|
5280
|
+
onChange: () => find.toggleOption(t.key)
|
|
5281
|
+
}
|
|
5282
|
+
),
|
|
5283
|
+
t.label
|
|
5284
|
+
] }, t.key)) })
|
|
5285
|
+
] });
|
|
5286
|
+
};
|
|
4070
5287
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4071
5288
|
0 && (module.exports = {
|
|
5289
|
+
AdjustmentLayersPanel,
|
|
4072
5290
|
BubbleMenu,
|
|
4073
5291
|
CommandPalette,
|
|
4074
5292
|
CommentButton,
|
|
4075
5293
|
CommentsPanel,
|
|
5294
|
+
ControlSlider,
|
|
5295
|
+
CurvesEditor,
|
|
4076
5296
|
DirtyTracker,
|
|
4077
5297
|
EditorContent,
|
|
4078
5298
|
EditorSlotsProvider,
|
|
5299
|
+
FindReplaceBar,
|
|
4079
5300
|
FormulaHints,
|
|
5301
|
+
GenerationSettings,
|
|
5302
|
+
Histogram,
|
|
4080
5303
|
HistoryManager,
|
|
4081
5304
|
ImageEditor,
|
|
5305
|
+
JobProgress,
|
|
5306
|
+
MergePreview,
|
|
4082
5307
|
OutlinePanel,
|
|
5308
|
+
RecoveryPrompt,
|
|
4083
5309
|
ReviewToolbar,
|
|
4084
5310
|
SpreadsheetContextMenu,
|
|
4085
5311
|
SpreadsheetEditor,
|
|
@@ -4091,18 +5317,25 @@ function useRegisterCommands(registry, specs) {
|
|
|
4091
5317
|
createHistoryManager,
|
|
4092
5318
|
defaultIsEqual,
|
|
4093
5319
|
useAgentToolProvider,
|
|
5320
|
+
useAutosave,
|
|
4094
5321
|
useCommandPalette,
|
|
4095
5322
|
useCommandShortcuts,
|
|
4096
5323
|
useComments,
|
|
4097
5324
|
useDismissGuard,
|
|
5325
|
+
useDocumentCompare,
|
|
4098
5326
|
useEditor,
|
|
4099
5327
|
useEditorSlots,
|
|
4100
5328
|
useFileImport,
|
|
4101
5329
|
useFillHandle,
|
|
5330
|
+
useFindReplace,
|
|
5331
|
+
useGenerationPlan,
|
|
4102
5332
|
useHistory,
|
|
4103
5333
|
useHistoryDirty,
|
|
4104
5334
|
useHistoryShortcuts,
|
|
4105
5335
|
useImageEditor,
|
|
5336
|
+
useImageHistogram,
|
|
5337
|
+
useJobProgress,
|
|
5338
|
+
useMergePreview,
|
|
4106
5339
|
useNavigationGuard,
|
|
4107
5340
|
useOutline,
|
|
4108
5341
|
usePromptEditor,
|