payload-intl 0.0.1
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 +67 -0
- package/dist/components/MessageController.d.ts +14 -0
- package/dist/components/MessageController.js +64 -0
- package/dist/components/MessageController.js.map +1 -0
- package/dist/components/MessagesForm.d.ts +11 -0
- package/dist/components/MessagesForm.js +91 -0
- package/dist/components/MessagesForm.js.map +1 -0
- package/dist/components/actions/JsonImport.d.ts +1 -0
- package/dist/components/actions/Move.d.ts +3 -0
- package/dist/components/inputs/InputWrapper.d.ts +7 -0
- package/dist/components/inputs/InputWrapper.js +23 -0
- package/dist/components/inputs/InputWrapper.js.map +1 -0
- package/dist/components/inputs/MessageInput.d.ts +10 -0
- package/dist/components/inputs/MessageInput.js +52 -0
- package/dist/components/inputs/MessageInput.js.map +1 -0
- package/dist/components/inputs/RichTextInput.d.ts +8 -0
- package/dist/components/inputs/RichTextInput.js +81 -0
- package/dist/components/inputs/RichTextInput.js.map +1 -0
- package/dist/components/inputs/toolbar/AlignmentControls.d.ts +5 -0
- package/dist/components/inputs/toolbar/AlignmentControls.js +59 -0
- package/dist/components/inputs/toolbar/AlignmentControls.js.map +1 -0
- package/dist/components/inputs/toolbar/BlockElementSelect.d.ts +5 -0
- package/dist/components/inputs/toolbar/BlockElementSelect.js +129 -0
- package/dist/components/inputs/toolbar/BlockElementSelect.js.map +1 -0
- package/dist/components/inputs/toolbar/LinkEditor.d.ts +58 -0
- package/dist/components/inputs/toolbar/LinkEditor.js +230 -0
- package/dist/components/inputs/toolbar/LinkEditor.js.map +1 -0
- package/dist/components/inputs/toolbar/MarkControls.d.ts +5 -0
- package/dist/components/inputs/toolbar/MarkControls.js +47 -0
- package/dist/components/inputs/toolbar/MarkControls.js.map +1 -0
- package/dist/components/inputs/toolbar/RichTextToolbar.d.ts +6 -0
- package/dist/components/inputs/toolbar/RichTextToolbar.js +32 -0
- package/dist/components/inputs/toolbar/RichTextToolbar.js.map +1 -0
- package/dist/components/inputs/variables/VariableChip.d.ts +2 -0
- package/dist/components/inputs/variables/VariableChip.js +60 -0
- package/dist/components/inputs/variables/VariableChip.js.map +1 -0
- package/dist/components/inputs/variables/VariableSuggestion.d.ts +8 -0
- package/dist/components/inputs/variables/VariableSuggestion.js +40 -0
- package/dist/components/inputs/variables/VariableSuggestion.js.map +1 -0
- package/dist/components/inputs/variables/editors/DateVariableEditor.d.ts +9 -0
- package/dist/components/inputs/variables/editors/PluralVariableEditor.d.ts +9 -0
- package/dist/components/inputs/variables/editors/PluralVariableEditor.js +149 -0
- package/dist/components/inputs/variables/editors/PluralVariableEditor.js.map +1 -0
- package/dist/components/inputs/variables/editors/SelectVariableEditor.d.ts +6 -0
- package/dist/components/inputs/variables/editors/SelectVariableEditor.js +42 -0
- package/dist/components/inputs/variables/editors/SelectVariableEditor.js.map +1 -0
- package/dist/components/inputs/variables/editors/TagVariableEditor.d.ts +6 -0
- package/dist/components/inputs/variables/editors/TagVariableEditor.js +32 -0
- package/dist/components/inputs/variables/editors/TagVariableEditor.js.map +1 -0
- package/dist/components/inputs/variables/editors/TimeVariableEditor.d.ts +9 -0
- package/dist/components/inputs/variables/extension.d.ts +3 -0
- package/dist/components/inputs/variables/extension.js +93 -0
- package/dist/components/inputs/variables/extension.js.map +1 -0
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.d.ts +6 -0
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.js +49 -0
- package/dist/components/inputs/variables/pickers/NumericVariablePicker.js.map +1 -0
- package/dist/components/inputs/variables/pickers/TemporalElementEditor.d.ts +6 -0
- package/dist/components/layout/MessageField.d.ts +9 -0
- package/dist/components/layout/MessageField.js +46 -0
- package/dist/components/layout/MessageField.js.map +1 -0
- package/dist/components/layout/MessagesTabs.d.ts +8 -0
- package/dist/components/layout/MessagesTabs.js +43 -0
- package/dist/components/layout/MessagesTabs.js.map +1 -0
- package/dist/components/layout/MessagesTree.d.ts +9 -0
- package/dist/components/layout/MessagesTree.js +67 -0
- package/dist/components/layout/MessagesTree.js.map +1 -0
- package/dist/context/messages-form.d.ts +30 -0
- package/dist/endpoints/get-messages.d.ts +2 -0
- package/dist/endpoints/get-messages.js +13 -0
- package/dist/endpoints/get-messages.js.map +1 -0
- package/dist/endpoints/set-messages.d.ts +2 -0
- package/dist/endpoints/set-messages.js +47 -0
- package/dist/endpoints/set-messages.js.map +1 -0
- package/dist/exports/link.d.ts +7 -0
- package/dist/exports/link.js +20 -0
- package/dist/exports/link.js.map +1 -0
- package/dist/exports/rsc.d.ts +2 -0
- package/dist/exports/rsc.js +7 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/exports/view.d.ts +10 -0
- package/dist/exports/view.js +56 -0
- package/dist/exports/view.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/requests/fetchMessages.d.ts +3 -0
- package/dist/requests/fetchMessages.js +29 -0
- package/dist/requests/fetchMessages.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/types.d.ts +48 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.js +19 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/format.d.ts +3 -0
- package/dist/utils/guards.d.ts +4 -0
- package/dist/utils/icu-tranform.d.ts +30 -0
- package/dist/utils/sanitize.d.ts +15 -0
- package/dist/utils/schema.d.ts +9 -0
- package/dist/utils/validate.d.ts +5 -0
- package/package.json +131 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Payload Intl Plugin
|
|
2
|
+
|
|
3
|
+
A Payload CMS plugin for internationalization (i18n) message management.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Manage translation messages through a user-friendly interface
|
|
8
|
+
- Support for multiple locales
|
|
9
|
+
- Tree and tab-based message organization
|
|
10
|
+
- Import/export functionality
|
|
11
|
+
- Copy messages between paths
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# npm
|
|
17
|
+
npm install payload-intl
|
|
18
|
+
|
|
19
|
+
# pnpm
|
|
20
|
+
pnpm add payload-intl
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { intlPlugin } from "payload-intl";
|
|
28
|
+
|
|
29
|
+
export default buildConfig({
|
|
30
|
+
plugins: [
|
|
31
|
+
intlPlugin({
|
|
32
|
+
schema: {
|
|
33
|
+
// Your message schema
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Set up a storage adapter and disable `disablePayloadAccessControl` to ensure the translations are fetched directly from the storage provider.
|
|
41
|
+
|
|
42
|
+
## Pain Points
|
|
43
|
+
|
|
44
|
+
- Messages can have missing/wrong arguments
|
|
45
|
+
- User does not know which arguments are required and how to use them
|
|
46
|
+
- User does not know the purpose of a field or where it is used
|
|
47
|
+
- Changing messages structure causes data loss
|
|
48
|
+
|
|
49
|
+
## Development
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Install dependencies
|
|
53
|
+
pnpm install
|
|
54
|
+
|
|
55
|
+
# Start development server
|
|
56
|
+
pnpm dev
|
|
57
|
+
|
|
58
|
+
# Build the plugin
|
|
59
|
+
pnpm build
|
|
60
|
+
|
|
61
|
+
# Run tests
|
|
62
|
+
pnpm test
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TemplateVariable } from '../types.ts';
|
|
2
|
+
import { MessageType } from '../utils/schema';
|
|
3
|
+
import { MessageValidator } from '../utils/validate';
|
|
4
|
+
interface MessageControllerProps {
|
|
5
|
+
type: MessageType;
|
|
6
|
+
label: string;
|
|
7
|
+
locale: string;
|
|
8
|
+
name: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
variables: TemplateVariable[];
|
|
11
|
+
validate: MessageValidator;
|
|
12
|
+
}
|
|
13
|
+
export declare function MessageController({ type, name, variables, label, locale, validate, className, }: MessageControllerProps): React.ReactNode;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Controller as l } from "react-hook-form";
|
|
2
|
+
import { useMessagesForm as s } from "@/context/messages-form";
|
|
3
|
+
import { MessageInput as p } from "./inputs/MessageInput.js";
|
|
4
|
+
import { RichTextInput as h } from "./inputs/RichTextInput.js";
|
|
5
|
+
function B({
|
|
6
|
+
type: c,
|
|
7
|
+
name: n,
|
|
8
|
+
variables: m,
|
|
9
|
+
label: o,
|
|
10
|
+
locale: t,
|
|
11
|
+
validate: g,
|
|
12
|
+
className: u
|
|
13
|
+
}) {
|
|
14
|
+
const { control: a } = s();
|
|
15
|
+
return c === "rich" ? /* @__PURE__ */ React.createElement(
|
|
16
|
+
l,
|
|
17
|
+
{
|
|
18
|
+
control: a,
|
|
19
|
+
name: n,
|
|
20
|
+
render: ({ field: r, fieldState: e }) => /* @__PURE__ */ React.createElement(
|
|
21
|
+
h,
|
|
22
|
+
{
|
|
23
|
+
className: u,
|
|
24
|
+
error: e.error,
|
|
25
|
+
label: o,
|
|
26
|
+
lang: t,
|
|
27
|
+
onChange: r.onChange,
|
|
28
|
+
onBlur: r.onBlur,
|
|
29
|
+
value: r.value || ""
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
rules: {
|
|
33
|
+
required: !0
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
) : /* @__PURE__ */ React.createElement(
|
|
37
|
+
l,
|
|
38
|
+
{
|
|
39
|
+
control: a,
|
|
40
|
+
name: n,
|
|
41
|
+
render: ({ field: r, fieldState: e }) => /* @__PURE__ */ React.createElement(
|
|
42
|
+
p,
|
|
43
|
+
{
|
|
44
|
+
label: o,
|
|
45
|
+
lang: t,
|
|
46
|
+
className: u,
|
|
47
|
+
value: r.value || "",
|
|
48
|
+
variables: m,
|
|
49
|
+
error: e.error,
|
|
50
|
+
onChange: r.onChange,
|
|
51
|
+
onBlur: r.onBlur
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
rules: {
|
|
55
|
+
required: !0,
|
|
56
|
+
validate: g
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
B as MessageController
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=MessageController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageController.js","sources":["../../src/components/MessageController.tsx"],"sourcesContent":["import type { TemplateVariable } from \"@/types\";\nimport type { MessageType } from \"@/utils/schema\";\nimport type { MessageValidator } from \"@/utils/validate\";\nimport { Controller } from \"react-hook-form\";\n\nimport { useMessagesForm } from \"@/context/messages-form\";\n\nimport { MessageInput } from \"./inputs/MessageInput\";\nimport { RichTextInput } from \"./inputs/RichTextInput\";\n\ninterface MessageControllerProps {\n type: MessageType;\n label: string;\n locale: string;\n name: string;\n className?: string;\n variables: TemplateVariable[];\n validate: MessageValidator;\n}\n\nexport function MessageController({\n type,\n name,\n variables,\n label,\n locale,\n validate,\n className,\n}: MessageControllerProps): React.ReactNode {\n const { control } = useMessagesForm();\n\n if (type === \"rich\") {\n return (\n <Controller\n control={control}\n name={name}\n render={({ field, fieldState }) => (\n <RichTextInput\n className={className}\n error={fieldState.error}\n label={label}\n lang={locale}\n onChange={field.onChange}\n onBlur={field.onBlur}\n value={(field.value as unknown as string) || \"\"}\n />\n )}\n rules={{\n required: true,\n }}\n />\n );\n }\n\n return (\n <Controller\n control={control}\n name={name}\n render={({ field, fieldState }) => (\n <MessageInput\n label={label}\n lang={locale}\n className={className}\n value={(field.value as unknown as string) || \"\"}\n variables={variables}\n error={fieldState.error}\n onChange={field.onChange}\n onBlur={field.onBlur}\n />\n )}\n rules={{\n required: true,\n validate,\n }}\n />\n );\n}\n"],"names":["MessageController","type","name","variables","label","locale","validate","className","control","useMessagesForm","Controller","field","fieldState","RichTextInput","MessageInput"],"mappings":";;;;AAoBO,SAASA,EAAkB;AAAA,EAChC,MAAAC;AAAA,EACA,MAAAC;AAAA,EACA,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC;AACF,GAA4C;AAC1C,QAAM,EAAE,SAAAC,EAAA,IAAYC,EAAA;AAEpB,SAAIR,MAAS,SAET,sBAAA;AAAA,IAACS;AAAA,IAAA;AAAA,MACC,SAAAF;AAAA,MACA,MAAAN;AAAA,MACA,QAAQ,CAAC,EAAE,OAAAS,GAAO,YAAAC,QAChB,sBAAA;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,WAAAN;AAAA,UACA,OAAOK,EAAW;AAAA,UAClB,OAAAR;AAAA,UACA,MAAMC;AAAA,UACN,UAAUM,EAAM;AAAA,UAChB,QAAQA,EAAM;AAAA,UACd,OAAQA,EAAM,SAA+B;AAAA,QAAA;AAAA,MAAA;AAAA,MAGjD,OAAO;AAAA,QACL,UAAU;AAAA,MAAA;AAAA,IACZ;AAAA,EAAA,IAMJ,sBAAA;AAAA,IAACD;AAAA,IAAA;AAAA,MACC,SAAAF;AAAA,MACA,MAAAN;AAAA,MACA,QAAQ,CAAC,EAAE,OAAAS,GAAO,YAAAC,QAChB,sBAAA;AAAA,QAACE;AAAA,QAAA;AAAA,UACC,OAAAV;AAAA,UACA,MAAMC;AAAA,UACN,WAAAE;AAAA,UACA,OAAQI,EAAM,SAA+B;AAAA,UAC7C,WAAAR;AAAA,UACA,OAAOS,EAAW;AAAA,UAClB,UAAUD,EAAM;AAAA,UAChB,QAAQA,EAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAGlB,OAAO;AAAA,QACL,UAAU;AAAA,QACV,UAAAL;AAAA,MAAA;AAAA,IACF;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { DeepPartial, Locales, Messages, MessagesSchema, RichTextEditorOptions, Translations } from '../types.ts';
|
|
2
|
+
interface MessagesFormProps {
|
|
3
|
+
locales: Locales;
|
|
4
|
+
schema: MessagesSchema;
|
|
5
|
+
tabs?: boolean;
|
|
6
|
+
values: Translations<DeepPartial<Messages>>;
|
|
7
|
+
endpointUrl: string;
|
|
8
|
+
richTextEditorOptions?: RichTextEditorOptions;
|
|
9
|
+
}
|
|
10
|
+
export declare function MessagesForm({ locales, schema, tabs, values, endpointUrl, richTextEditorOptions, }: MessagesFormProps): React.ReactNode;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useStepNav as N, Button as R } from "@payloadcms/ui";
|
|
3
|
+
import { isEqual as S } from "lodash-es";
|
|
4
|
+
import { useEffect as M, useState as x } from "react";
|
|
5
|
+
import { useForm as y } from "react-hook-form";
|
|
6
|
+
import { toast as f } from "sonner";
|
|
7
|
+
import { MessagesFormProvider as T } from "@/context/messages-form";
|
|
8
|
+
import { cn as d } from "@/utils/cn";
|
|
9
|
+
import { MessageField as j } from "./layout/MessageField.js";
|
|
10
|
+
import { MessagesTabs as F } from "./layout/MessagesTabs.js";
|
|
11
|
+
import { MessagesTree as p } from "./layout/MessagesTree.js";
|
|
12
|
+
function J({
|
|
13
|
+
locales: g,
|
|
14
|
+
schema: a,
|
|
15
|
+
tabs: r = !1,
|
|
16
|
+
values: c,
|
|
17
|
+
endpointUrl: h,
|
|
18
|
+
richTextEditorOptions: u
|
|
19
|
+
}) {
|
|
20
|
+
const { setStepNav: n } = N();
|
|
21
|
+
M(() => {
|
|
22
|
+
n([{ label: "Intl Messages", url: "/intl" }]);
|
|
23
|
+
}, [n]);
|
|
24
|
+
const s = y({
|
|
25
|
+
defaultValues: c,
|
|
26
|
+
reValidateMode: "onChange"
|
|
27
|
+
}), [m, b] = x(Object.keys(a)[0]), E = async (e) => {
|
|
28
|
+
const t = f.loading("Saving..."), v = Object.entries(e).reduce((o, [i, l]) => S(l, c[i]) ? o : {
|
|
29
|
+
...o,
|
|
30
|
+
[i]: l
|
|
31
|
+
}, {});
|
|
32
|
+
await fetch(h, {
|
|
33
|
+
method: "PUT",
|
|
34
|
+
body: JSON.stringify(v)
|
|
35
|
+
}), s.reset(e), f.success("Saved", { id: t });
|
|
36
|
+
};
|
|
37
|
+
return /* @__PURE__ */ React.createElement(
|
|
38
|
+
T,
|
|
39
|
+
{
|
|
40
|
+
form: s,
|
|
41
|
+
locales: g,
|
|
42
|
+
richTextEditorOptions: u
|
|
43
|
+
},
|
|
44
|
+
/* @__PURE__ */ React.createElement(
|
|
45
|
+
"form",
|
|
46
|
+
{
|
|
47
|
+
className: "flex h-[calc(100vh-var(--app-header-height))] flex-col",
|
|
48
|
+
onSubmit: s.handleSubmit(E)
|
|
49
|
+
},
|
|
50
|
+
/* @__PURE__ */ React.createElement("div", { className: "sticky top-0 z-10 bg-background" }, /* @__PURE__ */ React.createElement("header", { className: "mb-6 flex items-center justify-between gap-4" }, /* @__PURE__ */ React.createElement("h1", { className: "text-4xl" }, "Messages"), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(
|
|
51
|
+
R,
|
|
52
|
+
{
|
|
53
|
+
className: "my-0",
|
|
54
|
+
type: "submit",
|
|
55
|
+
disabled: !s.formState.isDirty
|
|
56
|
+
},
|
|
57
|
+
"Save"
|
|
58
|
+
))), r && /* @__PURE__ */ React.createElement(
|
|
59
|
+
F,
|
|
60
|
+
{
|
|
61
|
+
schema: a,
|
|
62
|
+
activeTab: m,
|
|
63
|
+
setActiveTab: b
|
|
64
|
+
}
|
|
65
|
+
)),
|
|
66
|
+
/* @__PURE__ */ React.createElement("div", { id: "messages-form-content", className: "overflow-y-auto pt-8 pb-16" }, !r && /* @__PURE__ */ React.createElement(p, { path: "", schema: a, nestingLevel: 0 }), r && Object.entries(a).map(([e, t]) => typeof t == "string" ? /* @__PURE__ */ React.createElement(
|
|
67
|
+
j,
|
|
68
|
+
{
|
|
69
|
+
schema: t,
|
|
70
|
+
key: e,
|
|
71
|
+
className: d({ hidden: m !== e }),
|
|
72
|
+
messageKey: e,
|
|
73
|
+
path: e
|
|
74
|
+
}
|
|
75
|
+
) : /* @__PURE__ */ React.createElement(
|
|
76
|
+
p,
|
|
77
|
+
{
|
|
78
|
+
className: d({ hidden: m !== e }),
|
|
79
|
+
key: e,
|
|
80
|
+
path: e,
|
|
81
|
+
schema: t,
|
|
82
|
+
nestingLevel: 0
|
|
83
|
+
}
|
|
84
|
+
)))
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
J as MessagesForm
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=MessagesForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessagesForm.js","sources":["../../src/components/MessagesForm.tsx"],"sourcesContent":["\"use client\";\n\nimport type { FormValues } from \"@/context/messages-form\";\nimport type {\n DeepPartial,\n Locales,\n Messages,\n MessagesSchema,\n RichTextEditorOptions,\n Translations,\n} from \"@/types\";\nimport { Button, useStepNav } from \"@payloadcms/ui\";\nimport { isEqual } from \"lodash-es\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\n\nimport { MessagesFormProvider } from \"@/context/messages-form\";\nimport { cn } from \"@/utils/cn\";\n\nimport { MessageField } from \"./layout/MessageField\";\nimport { MessagesTabs } from \"./layout/MessagesTabs\";\nimport { MessagesTree } from \"./layout/MessagesTree\";\n\ninterface MessagesFormProps {\n locales: Locales;\n schema: MessagesSchema;\n tabs?: boolean;\n values: Translations<DeepPartial<Messages>>;\n endpointUrl: string;\n richTextEditorOptions?: RichTextEditorOptions;\n}\n\nexport function MessagesForm({\n locales,\n schema,\n tabs = false,\n values,\n endpointUrl,\n richTextEditorOptions,\n}: MessagesFormProps): React.ReactNode {\n const { setStepNav } = useStepNav();\n useEffect(() => {\n setStepNav([{ label: \"Intl Messages\", url: \"/intl\" }]);\n }, [setStepNav]);\n\n const form = useForm<FormValues>({\n defaultValues: values,\n reValidateMode: \"onChange\",\n });\n const [activeTab, setActiveTab] = useState(Object.keys(schema)[0]);\n\n const handleSubmit = async (currentValues: FormValues) => {\n const toastId = toast.loading(\"Saving...\");\n const changes = Object.entries(currentValues).reduce<\n Translations<Messages>\n >((acc, [locale, value]) => {\n const hasChanged = !isEqual(value, values[locale]);\n if (!hasChanged) {\n return acc;\n }\n return {\n ...acc,\n [locale]: value,\n };\n }, {});\n\n await fetch(endpointUrl, {\n method: \"PUT\",\n body: JSON.stringify(changes),\n });\n\n form.reset(currentValues);\n toast.success(\"Saved\", { id: toastId });\n };\n\n return (\n <MessagesFormProvider\n form={form}\n locales={locales}\n richTextEditorOptions={richTextEditorOptions}\n >\n <form\n className=\"flex h-[calc(100vh-var(--app-header-height))] flex-col\"\n onSubmit={form.handleSubmit(handleSubmit)}\n >\n <div className=\"sticky top-0 z-10 bg-background\">\n <header className=\"mb-6 flex items-center justify-between gap-4\">\n <h1 className=\"text-4xl\">Messages</h1>\n <div className=\"flex items-center gap-2\">\n <Button\n className=\"my-0\"\n type=\"submit\"\n disabled={!form.formState.isDirty}\n >\n Save\n </Button>\n </div>\n </header>\n {tabs && (\n <MessagesTabs\n schema={schema}\n activeTab={activeTab}\n setActiveTab={setActiveTab}\n />\n )}\n </div>\n\n <div id=\"messages-form-content\" className=\"overflow-y-auto pt-8 pb-16\">\n {!tabs && <MessagesTree path=\"\" schema={schema} nestingLevel={0} />}\n {tabs &&\n Object.entries(schema).map(([key, value]) => {\n if (typeof value === \"string\") {\n return (\n <MessageField\n schema={value}\n key={key}\n className={cn({ hidden: activeTab !== key })}\n messageKey={key}\n path={key}\n />\n );\n }\n return (\n <MessagesTree\n className={cn({ hidden: activeTab !== key })}\n key={key}\n path={key}\n schema={value}\n nestingLevel={0}\n />\n );\n })}\n </div>\n </form>\n </MessagesFormProvider>\n );\n}\n"],"names":["MessagesForm","locales","schema","tabs","values","endpointUrl","richTextEditorOptions","setStepNav","useStepNav","useEffect","form","useForm","activeTab","setActiveTab","useState","handleSubmit","currentValues","toastId","toast","changes","acc","locale","value","isEqual","MessagesFormProvider","Button","MessagesTabs","MessagesTree","key","MessageField","cn"],"mappings":";;;;;;;;;;;AAiCO,SAASA,EAAa;AAAA,EAC3B,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,QAAAC;AAAA,EACA,aAAAC;AAAA,EACA,uBAAAC;AACF,GAAuC;AACrC,QAAM,EAAE,YAAAC,EAAA,IAAeC,EAAA;AACvB,EAAAC,EAAU,MAAM;AACd,IAAAF,EAAW,CAAC,EAAE,OAAO,iBAAiB,KAAK,QAAA,CAAS,CAAC;AAAA,EACvD,GAAG,CAACA,CAAU,CAAC;AAEf,QAAMG,IAAOC,EAAoB;AAAA,IAC/B,eAAeP;AAAA,IACf,gBAAgB;AAAA,EAAA,CACjB,GACK,CAACQ,GAAWC,CAAY,IAAIC,EAAS,OAAO,KAAKZ,CAAM,EAAE,CAAC,CAAC,GAE3Da,IAAe,OAAOC,MAA8B;AACxD,UAAMC,IAAUC,EAAM,QAAQ,WAAW,GACnCC,IAAU,OAAO,QAAQH,CAAa,EAAE,OAE5C,CAACI,GAAK,CAACC,GAAQC,CAAK,MACAC,EAAQD,GAAOlB,EAAOiB,CAAM,CAAC,IAExCD,IAEF;AAAA,MACL,GAAGA;AAAA,MACH,CAACC,CAAM,GAAGC;AAAA,IAAA,GAEX,CAAA,CAAE;AAEL,UAAM,MAAMjB,GAAa;AAAA,MACvB,QAAQ;AAAA,MACR,MAAM,KAAK,UAAUc,CAAO;AAAA,IAAA,CAC7B,GAEDT,EAAK,MAAMM,CAAa,GACxBE,EAAM,QAAQ,SAAS,EAAE,IAAID,GAAS;AAAA,EACxC;AAEA,SACE,sBAAA;AAAA,IAACO;AAAA,IAAA;AAAA,MACC,MAAAd;AAAA,MACA,SAAAT;AAAA,MACA,uBAAAK;AAAA,IAAA;AAAA,IAEA,sBAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,UAAUI,EAAK,aAAaK,CAAY;AAAA,MAAA;AAAA,0CAEvC,OAAA,EAAI,WAAU,kCAAA,GACb,sBAAA,cAAC,YAAO,WAAU,+CAAA,GAChB,sBAAA,cAAC,MAAA,EAAG,WAAU,WAAA,GAAW,UAAQ,GACjC,sBAAA,cAAC,OAAA,EAAI,WAAU,0BAAA,GACb,sBAAA;AAAA,QAACU;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,MAAK;AAAA,UACL,UAAU,CAACf,EAAK,UAAU;AAAA,QAAA;AAAA,QAC3B;AAAA,MAAA,CAGH,CACF,GACCP,KACC,sBAAA;AAAA,QAACuB;AAAA,QAAA;AAAA,UACC,QAAAxB;AAAA,UACA,WAAAU;AAAA,UACA,cAAAC;AAAA,QAAA;AAAA,MAAA,CAGN;AAAA,MAEA,sBAAA,cAAC,OAAA,EAAI,IAAG,yBAAwB,WAAU,6BAAA,GACvC,CAACV,KAAQ,sBAAA,cAACwB,GAAA,EAAa,MAAK,IAAG,QAAAzB,GAAgB,cAAc,EAAA,CAAG,GAChEC,KACC,OAAO,QAAQD,CAAM,EAAE,IAAI,CAAC,CAAC0B,GAAKN,CAAK,MACjC,OAAOA,KAAU,WAEjB,sBAAA;AAAA,QAACO;AAAA,QAAA;AAAA,UACC,QAAQP;AAAA,UACR,KAAAM;AAAA,UACA,WAAWE,EAAG,EAAE,QAAQlB,MAAcgB,GAAK;AAAA,UAC3C,YAAYA;AAAA,UACZ,MAAMA;AAAA,QAAA;AAAA,MAAA,IAKV,sBAAA;AAAA,QAACD;AAAA,QAAA;AAAA,UACC,WAAWG,EAAG,EAAE,QAAQlB,MAAcgB,GAAK;AAAA,UAC3C,KAAAA;AAAA,UACA,MAAMA;AAAA,UACN,QAAQN;AAAA,UACR,cAAc;AAAA,QAAA;AAAA,MAAA,CAGnB,CACL;AAAA,IAAA;AAAA,EACF;AAGN;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function JsonImport(): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FieldError } from 'react-hook-form';
|
|
2
|
+
export interface InputWrapperProps {
|
|
3
|
+
label: string;
|
|
4
|
+
error: FieldError | undefined;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function InputWrapper({ label, error, className, children, }: React.PropsWithChildren<InputWrapperProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FieldLabel as l } from "@payloadcms/ui";
|
|
2
|
+
import { cn as t } from "@/utils/cn";
|
|
3
|
+
function o({
|
|
4
|
+
label: a,
|
|
5
|
+
error: e,
|
|
6
|
+
className: r,
|
|
7
|
+
children: c
|
|
8
|
+
}) {
|
|
9
|
+
return /* @__PURE__ */ React.createElement("div", { className: t("flex flex-col gap-1", r) }, /* @__PURE__ */ React.createElement(
|
|
10
|
+
"fieldset",
|
|
11
|
+
{
|
|
12
|
+
className: t("mx-0 rounded-md focus-within:border-elevation-400", {
|
|
13
|
+
"border-error bg-error": e
|
|
14
|
+
})
|
|
15
|
+
},
|
|
16
|
+
/* @__PURE__ */ React.createElement("legend", { className: "-ml-2 px-1.5 text-base" }, /* @__PURE__ */ React.createElement(l, { label: a })),
|
|
17
|
+
c
|
|
18
|
+
), /* @__PURE__ */ React.createElement("p", { className: "text-base text-error" }, e?.message));
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
o as InputWrapper
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=InputWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InputWrapper.js","sources":["../../../src/components/inputs/InputWrapper.tsx"],"sourcesContent":["import type { FieldError } from \"react-hook-form\";\nimport { FieldLabel } from \"@payloadcms/ui\";\n\nimport { cn } from \"@/utils/cn\";\n\nexport interface InputWrapperProps {\n label: string;\n error: FieldError | undefined;\n className?: string;\n}\n\nexport function InputWrapper({\n label,\n error,\n className,\n children,\n}: React.PropsWithChildren<InputWrapperProps>) {\n return (\n <div className={cn(\"flex flex-col gap-1\", className)}>\n <fieldset\n className={cn(\"mx-0 rounded-md focus-within:border-elevation-400\", {\n \"border-error bg-error\": error,\n })}\n >\n <legend className=\"-ml-2 px-1.5 text-base\">\n <FieldLabel label={label} />\n </legend>\n {children}\n </fieldset>\n <p className=\"text-base text-error\">{error?.message}</p>\n </div>\n );\n}\n"],"names":["InputWrapper","label","error","className","children","cn","FieldLabel"],"mappings":";;AAWO,SAASA,EAAa;AAAA,EAC3B,OAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AACF,GAA+C;AAC7C,6CACG,OAAA,EAAI,WAAWC,EAAG,uBAAuBF,CAAS,KACjD,sBAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWE,EAAG,qDAAqD;AAAA,QACjE,yBAAyBH;AAAA,MAAA,CAC1B;AAAA,IAAA;AAAA,wCAEA,UAAA,EAAO,WAAU,4BAChB,sBAAA,cAACI,GAAA,EAAW,OAAAL,GAAc,CAC5B;AAAA,IACCG;AAAA,EAAA,GAEH,sBAAA,cAAC,KAAA,EAAE,WAAU,uBAAA,GAAwBF,GAAO,OAAQ,CACtD;AAEJ;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TemplateVariable } from '../../types.ts';
|
|
2
|
+
import { InputWrapperProps } from './InputWrapper';
|
|
3
|
+
export interface MessageInputProps extends InputWrapperProps {
|
|
4
|
+
value: string;
|
|
5
|
+
lang: string;
|
|
6
|
+
variables: TemplateVariable[];
|
|
7
|
+
onChange: (value: string) => void;
|
|
8
|
+
onBlur: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function MessageInput({ label, value, lang, error, variables, onChange, onBlur, className, }: MessageInputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useEditor as m, EditorContent as c } from "@tiptap/react";
|
|
2
|
+
import d from "@tiptap/starter-kit";
|
|
3
|
+
import { parseIcuToProseMirrorJSON as p } from "@/utils/icu-tranform";
|
|
4
|
+
import { InputWrapper as u } from "./InputWrapper.js";
|
|
5
|
+
import { VariableMention as b } from "./variables/extension.js";
|
|
6
|
+
function h({
|
|
7
|
+
label: e,
|
|
8
|
+
value: t,
|
|
9
|
+
lang: r,
|
|
10
|
+
error: o,
|
|
11
|
+
variables: a,
|
|
12
|
+
onChange: i,
|
|
13
|
+
onBlur: l,
|
|
14
|
+
className: s
|
|
15
|
+
}) {
|
|
16
|
+
const n = m({
|
|
17
|
+
immediatelyRender: !1,
|
|
18
|
+
content: p(t),
|
|
19
|
+
extensions: [
|
|
20
|
+
d.configure({
|
|
21
|
+
blockquote: !1,
|
|
22
|
+
bulletList: !1,
|
|
23
|
+
codeBlock: !1,
|
|
24
|
+
heading: !1,
|
|
25
|
+
horizontalRule: !1,
|
|
26
|
+
listItem: !1,
|
|
27
|
+
orderedList: !1,
|
|
28
|
+
bold: !1,
|
|
29
|
+
italic: !1,
|
|
30
|
+
link: !1,
|
|
31
|
+
underline: !1,
|
|
32
|
+
strike: !1,
|
|
33
|
+
code: !1
|
|
34
|
+
}),
|
|
35
|
+
b(a)
|
|
36
|
+
],
|
|
37
|
+
onUpdate: ({ editor: f }) => i(f.getText())
|
|
38
|
+
});
|
|
39
|
+
return /* @__PURE__ */ React.createElement(u, { label: e, error: o, className: s }, /* @__PURE__ */ React.createElement(
|
|
40
|
+
c,
|
|
41
|
+
{
|
|
42
|
+
className: "tiptap-editor min-h-8",
|
|
43
|
+
editor: n,
|
|
44
|
+
lang: r,
|
|
45
|
+
onBlur: l
|
|
46
|
+
}
|
|
47
|
+
));
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
h as MessageInput
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=MessageInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageInput.js","sources":["../../../src/components/inputs/MessageInput.tsx"],"sourcesContent":["import type { TemplateVariable } from \"@/types\";\nimport { EditorContent, useEditor } from \"@tiptap/react\";\nimport StarterKit from \"@tiptap/starter-kit\";\n\nimport { parseIcuToProseMirrorJSON } from \"@/utils/icu-tranform\";\n\nimport type { InputWrapperProps } from \"./InputWrapper\";\nimport { InputWrapper } from \"./InputWrapper\";\nimport { VariableMention } from \"./variables/extension\";\n\nexport interface MessageInputProps extends InputWrapperProps {\n value: string;\n lang: string;\n variables: TemplateVariable[];\n onChange: (value: string) => void;\n onBlur: () => void;\n}\n\n// TODO add variable editor (style, options, etc)\n// TODO add tooltip to show all variables\n\nexport function MessageInput({\n label,\n value,\n lang,\n error,\n variables,\n onChange,\n onBlur,\n className,\n}: MessageInputProps) {\n const editor = useEditor({\n immediatelyRender: false,\n content: parseIcuToProseMirrorJSON(value),\n extensions: [\n StarterKit.configure({\n blockquote: false,\n bulletList: false,\n codeBlock: false,\n heading: false,\n horizontalRule: false,\n listItem: false,\n orderedList: false,\n bold: false,\n italic: false,\n link: false,\n underline: false,\n strike: false,\n code: false,\n }),\n VariableMention(variables),\n ],\n onUpdate: ({ editor }) => onChange(editor.getText()),\n });\n\n return (\n <InputWrapper label={label} error={error} className={className}>\n <EditorContent\n className=\"tiptap-editor min-h-8\"\n editor={editor}\n lang={lang}\n onBlur={onBlur}\n />\n </InputWrapper>\n );\n}\n"],"names":["MessageInput","label","value","lang","error","variables","onChange","onBlur","className","editor","useEditor","parseIcuToProseMirrorJSON","StarterKit","VariableMention","InputWrapper","EditorContent"],"mappings":";;;;;AAqBO,SAASA,EAAa;AAAA,EAC3B,OAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AACF,GAAsB;AACpB,QAAMC,IAASC,EAAU;AAAA,IACvB,mBAAmB;AAAA,IACnB,SAASC,EAA0BT,CAAK;AAAA,IACxC,YAAY;AAAA,MACVU,EAAW,UAAU;AAAA,QACnB,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,aAAa;AAAA,QACb,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,MAAM;AAAA,MAAA,CACP;AAAA,MACDC,EAAgBR,CAAS;AAAA,IAAA;AAAA,IAE3B,UAAU,CAAC,EAAE,QAAAI,QAAaH,EAASG,EAAO,QAAA,CAAS;AAAA,EAAA,CACpD;AAED,SACE,sBAAA,cAACK,GAAA,EAAa,OAAAb,GAAc,OAAAG,GAAc,WAAAI,KACxC,sBAAA;AAAA,IAACO;AAAA,IAAA;AAAA,MACC,WAAU;AAAA,MACV,QAAAN;AAAA,MACA,MAAAN;AAAA,MACA,QAAAI;AAAA,IAAA;AAAA,EAAA,CAEJ;AAEJ;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { InputWrapperProps } from './InputWrapper';
|
|
2
|
+
export interface RichTextInputProps extends InputWrapperProps {
|
|
3
|
+
value: string;
|
|
4
|
+
lang: string;
|
|
5
|
+
onChange: (value: string) => void;
|
|
6
|
+
onBlur: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function RichTextInput({ error, label, lang, onBlur, onChange, value, className, }: RichTextInputProps): React.ReactNode;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import f from "@tiptap/extension-blockquote";
|
|
2
|
+
import c from "@tiptap/extension-bold";
|
|
3
|
+
import s from "@tiptap/extension-code-block";
|
|
4
|
+
import d from "@tiptap/extension-document";
|
|
5
|
+
import g from "@tiptap/extension-hard-break";
|
|
6
|
+
import u from "@tiptap/extension-heading";
|
|
7
|
+
import h from "@tiptap/extension-highlight";
|
|
8
|
+
import T from "@tiptap/extension-horizontal-rule";
|
|
9
|
+
import k from "@tiptap/extension-italic";
|
|
10
|
+
import x from "@tiptap/extension-link";
|
|
11
|
+
import { BulletList as R, OrderedList as E, ListItem as L, ListKeymap as y } from "@tiptap/extension-list";
|
|
12
|
+
import B from "@tiptap/extension-paragraph";
|
|
13
|
+
import H from "@tiptap/extension-strike";
|
|
14
|
+
import b from "@tiptap/extension-text";
|
|
15
|
+
import C from "@tiptap/extension-text-align";
|
|
16
|
+
import I from "@tiptap/extension-typography";
|
|
17
|
+
import N from "@tiptap/extension-underline";
|
|
18
|
+
import { UndoRedo as O, TrailingNode as U } from "@tiptap/extensions";
|
|
19
|
+
import { useEditor as q, EditorContent as w } from "@tiptap/react";
|
|
20
|
+
import { useMessagesForm as M } from "@/context/messages-form";
|
|
21
|
+
import { InputWrapper as S } from "./InputWrapper.js";
|
|
22
|
+
import { RichTextToolbar as z } from "./toolbar/RichTextToolbar.js";
|
|
23
|
+
function mo({
|
|
24
|
+
error: e,
|
|
25
|
+
label: t,
|
|
26
|
+
lang: i,
|
|
27
|
+
onBlur: m,
|
|
28
|
+
onChange: n,
|
|
29
|
+
value: p,
|
|
30
|
+
className: a
|
|
31
|
+
}) {
|
|
32
|
+
const { richTextEditorOptions: o } = M();
|
|
33
|
+
console.log(o);
|
|
34
|
+
const r = q({
|
|
35
|
+
content: p,
|
|
36
|
+
extensions: [
|
|
37
|
+
d,
|
|
38
|
+
...o?.heading !== !1 ? [u.configure(o?.heading)] : [],
|
|
39
|
+
B,
|
|
40
|
+
b,
|
|
41
|
+
g,
|
|
42
|
+
T,
|
|
43
|
+
f,
|
|
44
|
+
s,
|
|
45
|
+
R,
|
|
46
|
+
E,
|
|
47
|
+
L,
|
|
48
|
+
x.configure({
|
|
49
|
+
openOnClick: !1,
|
|
50
|
+
enableClickSelection: !0
|
|
51
|
+
}),
|
|
52
|
+
c,
|
|
53
|
+
k,
|
|
54
|
+
H,
|
|
55
|
+
N,
|
|
56
|
+
I,
|
|
57
|
+
h,
|
|
58
|
+
C.configure({
|
|
59
|
+
types: ["heading", "paragraph", "blockquote"]
|
|
60
|
+
}),
|
|
61
|
+
O,
|
|
62
|
+
U,
|
|
63
|
+
y
|
|
64
|
+
],
|
|
65
|
+
immediatelyRender: !1,
|
|
66
|
+
onUpdate: ({ editor: l }) => n?.(l.getHTML())
|
|
67
|
+
});
|
|
68
|
+
return /* @__PURE__ */ React.createElement(S, { label: t, error: e, className: a }, /* @__PURE__ */ React.createElement(z, { className: "mb-3 w-full min-w-max", editor: r }), /* @__PURE__ */ React.createElement(
|
|
69
|
+
w,
|
|
70
|
+
{
|
|
71
|
+
className: "tiptap-editor min-h-8",
|
|
72
|
+
editor: r,
|
|
73
|
+
lang: i,
|
|
74
|
+
onBlur: m
|
|
75
|
+
}
|
|
76
|
+
));
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
mo as RichTextInput
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=RichTextInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextInput.js","sources":["../../../src/components/inputs/RichTextInput.tsx"],"sourcesContent":["import Blockquote from \"@tiptap/extension-blockquote\";\nimport Bold from \"@tiptap/extension-bold\";\nimport CodeBlock from \"@tiptap/extension-code-block\";\nimport Document from \"@tiptap/extension-document\";\nimport HardBreak from \"@tiptap/extension-hard-break\";\nimport Heading from \"@tiptap/extension-heading\";\nimport Highlight from \"@tiptap/extension-highlight\";\nimport HorizontalRule from \"@tiptap/extension-horizontal-rule\";\nimport Italic from \"@tiptap/extension-italic\";\nimport Link from \"@tiptap/extension-link\";\nimport {\n BulletList,\n ListItem,\n ListKeymap,\n OrderedList,\n} from \"@tiptap/extension-list\";\nimport Paragraph from \"@tiptap/extension-paragraph\";\nimport Strike from \"@tiptap/extension-strike\";\nimport Text from \"@tiptap/extension-text\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Typography from \"@tiptap/extension-typography\";\nimport Underline from \"@tiptap/extension-underline\";\nimport { TrailingNode, UndoRedo } from \"@tiptap/extensions\";\nimport { EditorContent, useEditor } from \"@tiptap/react\";\n\nimport { useMessagesForm } from \"@/context/messages-form\";\n\nimport type { InputWrapperProps } from \"./InputWrapper\";\nimport { InputWrapper } from \"./InputWrapper\";\nimport { RichTextToolbar } from \"./toolbar/RichTextToolbar\";\n\nexport interface RichTextInputProps extends InputWrapperProps {\n value: string;\n lang: string;\n onChange: (value: string) => void;\n onBlur: () => void;\n}\n\nexport function RichTextInput({\n error,\n label,\n lang,\n onBlur,\n onChange,\n value,\n className,\n}: RichTextInputProps): React.ReactNode {\n const { richTextEditorOptions } = useMessagesForm();\n console.log(richTextEditorOptions);\n const editor = useEditor({\n content: value,\n extensions: [\n Document,\n ...(richTextEditorOptions?.heading !== false\n ? [Heading.configure(richTextEditorOptions?.heading)]\n : []),\n Paragraph,\n Text,\n HardBreak,\n HorizontalRule,\n Blockquote,\n CodeBlock,\n BulletList,\n OrderedList,\n ListItem,\n Link.configure({\n openOnClick: false,\n enableClickSelection: true,\n }),\n Bold,\n Italic,\n Strike,\n Underline,\n Typography,\n Highlight,\n TextAlign.configure({\n types: [\"heading\", \"paragraph\", \"blockquote\"],\n }),\n UndoRedo,\n TrailingNode,\n ListKeymap,\n ],\n immediatelyRender: false,\n onUpdate: ({ editor }) => onChange?.(editor.getHTML()),\n });\n\n return (\n <InputWrapper label={label} error={error} className={className}>\n <RichTextToolbar className=\"mb-3 w-full min-w-max\" editor={editor} />\n <EditorContent\n className=\"tiptap-editor min-h-8\"\n editor={editor}\n lang={lang}\n onBlur={onBlur}\n />\n </InputWrapper>\n );\n}\n"],"names":["RichTextInput","error","label","lang","onBlur","onChange","value","className","richTextEditorOptions","useMessagesForm","editor","useEditor","Document","Heading","Paragraph","Text","HardBreak","HorizontalRule","Blockquote","CodeBlock","BulletList","OrderedList","ListItem","Link","Bold","Italic","Strike","Underline","Typography","Highlight","TextAlign","UndoRedo","TrailingNode","ListKeymap","InputWrapper","RichTextToolbar","EditorContent"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsCO,SAASA,GAAc;AAAA,EAC5B,OAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AACF,GAAwC;AACtC,QAAM,EAAE,uBAAAC,EAAA,IAA0BC,EAAA;AAClC,UAAQ,IAAID,CAAqB;AACjC,QAAME,IAASC,EAAU;AAAA,IACvB,SAASL;AAAA,IACT,YAAY;AAAA,MACVM;AAAA,MACA,GAAIJ,GAAuB,YAAY,KACnC,CAACK,EAAQ,UAAUL,GAAuB,OAAO,CAAC,IAClD,CAAA;AAAA,MACJM;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC,EAAK,UAAU;AAAA,QACb,aAAa;AAAA,QACb,sBAAsB;AAAA,MAAA,CACvB;AAAA,MACDC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC,EAAU,UAAU;AAAA,QAClB,OAAO,CAAC,WAAW,aAAa,YAAY;AAAA,MAAA,CAC7C;AAAA,MACDC;AAAA,MACAC;AAAA,MACAC;AAAA,IAAA;AAAA,IAEF,mBAAmB;AAAA,IACnB,UAAU,CAAC,EAAE,QAAAvB,QAAaL,IAAWK,EAAO,QAAA,CAAS;AAAA,EAAA,CACtD;AAED,SACE,sBAAA,cAACwB,GAAA,EAAa,OAAAhC,GAAc,OAAAD,GAAc,WAAAM,yCACvC4B,GAAA,EAAgB,WAAU,yBAAwB,QAAAzB,EAAA,CAAgB,GACnE,sBAAA;AAAA,IAAC0B;AAAA,IAAA;AAAA,MACC,WAAU;AAAA,MACV,QAAA1B;AAAA,MACA,MAAAP;AAAA,MACA,QAAAC;AAAA,IAAA;AAAA,EAAA,CAEJ;AAEJ;"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { IconAlignLeft as c, IconAlignCenter as g, IconAlignRight as u } from "@tabler/icons-react";
|
|
2
|
+
import { useEditorState as d } from "@tiptap/react";
|
|
3
|
+
import { Toolbar as t } from "radix-ui";
|
|
4
|
+
function v({ editor: n }) {
|
|
5
|
+
const { value: a, disabled: r } = d({
|
|
6
|
+
editor: n,
|
|
7
|
+
selector: (e) => {
|
|
8
|
+
const i = e.editor?.getAttributes("paragraph"), l = e.editor?.getAttributes("heading"), s = e.editor?.getAttributes("blockquote");
|
|
9
|
+
return {
|
|
10
|
+
disabled: e.editor?.isActive("bulletList") || e.editor?.isActive("orderedList"),
|
|
11
|
+
value: i?.textAlign || l?.textAlign || s?.textAlign
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}) ?? { value: "left" }, o = (e) => {
|
|
15
|
+
n && n.chain().focus().setTextAlign(e).run();
|
|
16
|
+
};
|
|
17
|
+
return /* @__PURE__ */ React.createElement(
|
|
18
|
+
t.ToggleGroup,
|
|
19
|
+
{
|
|
20
|
+
type: "single",
|
|
21
|
+
className: "flex items-center",
|
|
22
|
+
"aria-label": "Text alignment",
|
|
23
|
+
value: a,
|
|
24
|
+
onValueChange: o,
|
|
25
|
+
disabled: r
|
|
26
|
+
},
|
|
27
|
+
/* @__PURE__ */ React.createElement(
|
|
28
|
+
t.ToggleItem,
|
|
29
|
+
{
|
|
30
|
+
className: "inline-flex h-7 flex-shrink-0 flex-grow-0 basis-auto cursor-pointer items-center justify-center rounded border-none bg-transparent px-2 leading-none hover:bg-elevation-250 focus:relative focus:outline data-[state=on]:bg-elevation-600 data-[state=on]:text-elevation-0",
|
|
31
|
+
value: "left",
|
|
32
|
+
"aria-label": "Left aligned"
|
|
33
|
+
},
|
|
34
|
+
/* @__PURE__ */ React.createElement(c, { size: 16 })
|
|
35
|
+
),
|
|
36
|
+
/* @__PURE__ */ React.createElement(
|
|
37
|
+
t.ToggleItem,
|
|
38
|
+
{
|
|
39
|
+
className: "inline-flex h-7 flex-shrink-0 flex-grow-0 basis-auto cursor-pointer items-center justify-center rounded border-none bg-transparent px-2 leading-none hover:bg-elevation-250 focus:relative focus:outline data-[state=on]:bg-elevation-600 data-[state=on]:text-elevation-0",
|
|
40
|
+
value: "center",
|
|
41
|
+
"aria-label": "Center aligned"
|
|
42
|
+
},
|
|
43
|
+
/* @__PURE__ */ React.createElement(g, { size: 16 })
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ React.createElement(
|
|
46
|
+
t.ToggleItem,
|
|
47
|
+
{
|
|
48
|
+
className: "inline-flex h-7 flex-shrink-0 flex-grow-0 basis-auto cursor-pointer items-center justify-center rounded border-none bg-transparent px-2 leading-none hover:bg-elevation-250 focus:relative focus:outline data-[state=on]:bg-elevation-600 data-[state=on]:text-elevation-0",
|
|
49
|
+
value: "right",
|
|
50
|
+
"aria-label": "Right aligned"
|
|
51
|
+
},
|
|
52
|
+
/* @__PURE__ */ React.createElement(u, { size: 16 })
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
v as AlignmentControls
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=AlignmentControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlignmentControls.js","sources":["../../../../src/components/inputs/toolbar/AlignmentControls.tsx"],"sourcesContent":["import type { Editor } from \"@tiptap/react\";\nimport {\n IconAlignCenter,\n IconAlignLeft,\n IconAlignRight,\n} from \"@tabler/icons-react\";\nimport { useEditorState } from \"@tiptap/react\";\nimport { Toolbar } from \"radix-ui\";\n\nexport interface AlignmentControlsProps {\n editor: Editor | null;\n}\n\nexport function AlignmentControls({ editor }: AlignmentControlsProps) {\n const { value, disabled } = useEditorState<{\n value: string;\n disabled?: boolean;\n }>({\n editor,\n selector: (state) => {\n const attrs = state.editor?.getAttributes(\"paragraph\");\n const headingAttrs = state.editor?.getAttributes(\"heading\");\n const blockquoteAttrs = state.editor?.getAttributes(\"blockquote\");\n\n return {\n disabled:\n state.editor?.isActive(\"bulletList\") ||\n state.editor?.isActive(\"orderedList\"),\n value:\n attrs?.textAlign ||\n headingAttrs?.textAlign ||\n blockquoteAttrs?.textAlign,\n };\n },\n }) ?? { value: \"left\" };\n\n const handleChange = (value: string) => {\n if (!editor) return;\n editor.chain().focus().setTextAlign(value).run();\n };\n\n return (\n <Toolbar.ToggleGroup\n type=\"single\"\n className=\"flex items-center\"\n aria-label=\"Text alignment\"\n value={value}\n onValueChange={handleChange}\n disabled={disabled}\n >\n <Toolbar.ToggleItem\n className=\"inline-flex h-7 flex-shrink-0 flex-grow-0 basis-auto cursor-pointer items-center justify-center rounded border-none bg-transparent px-2 leading-none hover:bg-elevation-250 focus:relative focus:outline data-[state=on]:bg-elevation-600 data-[state=on]:text-elevation-0\"\n value=\"left\"\n aria-label=\"Left aligned\"\n >\n <IconAlignLeft size={16} />\n </Toolbar.ToggleItem>\n <Toolbar.ToggleItem\n className=\"inline-flex h-7 flex-shrink-0 flex-grow-0 basis-auto cursor-pointer items-center justify-center rounded border-none bg-transparent px-2 leading-none hover:bg-elevation-250 focus:relative focus:outline data-[state=on]:bg-elevation-600 data-[state=on]:text-elevation-0\"\n value=\"center\"\n aria-label=\"Center aligned\"\n >\n <IconAlignCenter size={16} />\n </Toolbar.ToggleItem>\n <Toolbar.ToggleItem\n className=\"inline-flex h-7 flex-shrink-0 flex-grow-0 basis-auto cursor-pointer items-center justify-center rounded border-none bg-transparent px-2 leading-none hover:bg-elevation-250 focus:relative focus:outline data-[state=on]:bg-elevation-600 data-[state=on]:text-elevation-0\"\n value=\"right\"\n aria-label=\"Right aligned\"\n >\n <IconAlignRight size={16} />\n </Toolbar.ToggleItem>\n </Toolbar.ToggleGroup>\n );\n}\n"],"names":["AlignmentControls","editor","value","disabled","useEditorState","state","attrs","headingAttrs","blockquoteAttrs","handleChange","Toolbar","IconAlignLeft","IconAlignCenter","IconAlignRight"],"mappings":";;;AAaO,SAASA,EAAkB,EAAE,QAAAC,KAAkC;AACpE,QAAM,EAAE,OAAAC,GAAO,UAAAC,EAAA,IAAaC,EAGzB;AAAA,IACD,QAAAH;AAAA,IACA,UAAU,CAACI,MAAU;AACnB,YAAMC,IAAQD,EAAM,QAAQ,cAAc,WAAW,GAC/CE,IAAeF,EAAM,QAAQ,cAAc,SAAS,GACpDG,IAAkBH,EAAM,QAAQ,cAAc,YAAY;AAEhE,aAAO;AAAA,QACL,UACEA,EAAM,QAAQ,SAAS,YAAY,KACnCA,EAAM,QAAQ,SAAS,aAAa;AAAA,QACtC,OACEC,GAAO,aACPC,GAAc,aACdC,GAAiB;AAAA,MAAA;AAAA,IAEvB;AAAA,EAAA,CACD,KAAK,EAAE,OAAO,OAAA,GAETC,IAAe,CAACP,MAAkB;AACtC,IAAKD,KACLA,EAAO,QAAQ,MAAA,EAAQ,aAAaC,CAAK,EAAE,IAAA;AAAA,EAC7C;AAEA,SACE,sBAAA;AAAA,IAACQ,EAAQ;AAAA,IAAR;AAAA,MACC,MAAK;AAAA,MACL,WAAU;AAAA,MACV,cAAW;AAAA,MACX,OAAAR;AAAA,MACA,eAAeO;AAAA,MACf,UAAAN;AAAA,IAAA;AAAA,IAEA,sBAAA;AAAA,MAACO,EAAQ;AAAA,MAAR;AAAA,QACC,WAAU;AAAA,QACV,OAAM;AAAA,QACN,cAAW;AAAA,MAAA;AAAA,MAEX,sBAAA,cAACC,GAAA,EAAc,MAAM,GAAA,CAAI;AAAA,IAAA;AAAA,IAE3B,sBAAA;AAAA,MAACD,EAAQ;AAAA,MAAR;AAAA,QACC,WAAU;AAAA,QACV,OAAM;AAAA,QACN,cAAW;AAAA,MAAA;AAAA,MAEX,sBAAA,cAACE,GAAA,EAAgB,MAAM,GAAA,CAAI;AAAA,IAAA;AAAA,IAE7B,sBAAA;AAAA,MAACF,EAAQ;AAAA,MAAR;AAAA,QACC,WAAU;AAAA,QACV,OAAM;AAAA,QACN,cAAW;AAAA,MAAA;AAAA,MAEX,sBAAA,cAACG,GAAA,EAAe,MAAM,GAAA,CAAI;AAAA,IAAA;AAAA,EAC5B;AAGN;"}
|