@mittwald/flow-react-components 0.2.0-alpha.477 → 0.2.0-alpha.479
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/assets/doc-properties.json +652 -933
- package/dist/js/components/src/components/Action/models/ActionState.mjs.map +1 -1
- package/dist/js/components/src/components/MarkdownEditor/MarkdownEditor.mjs +16 -20
- package/dist/js/components/src/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
- package/dist/js/components/src/components/MarkdownEditor/components/ModeButton.mjs +6 -4
- package/dist/js/components/src/components/MarkdownEditor/components/ModeButton.mjs.map +1 -1
- package/dist/js/components/src/components/MarkdownEditor/components/Toolbar.mjs +14 -11
- package/dist/js/components/src/components/MarkdownEditor/components/Toolbar.mjs.map +1 -1
- package/dist/js/components/src/components/MarkdownEditor/components/ToolbarButton.mjs +3 -13
- package/dist/js/components/src/components/MarkdownEditor/components/ToolbarButton.mjs.map +1 -1
- package/dist/js/components/src/components/MarkdownEditor/lib/handleKeyDown.mjs +7 -12
- package/dist/js/components/src/components/MarkdownEditor/lib/handleKeyDown.mjs.map +1 -1
- package/dist/js/components/src/components/MarkdownEditor/lib/insertAtCursor.mjs +4 -3
- package/dist/js/components/src/components/MarkdownEditor/lib/insertAtCursor.mjs.map +1 -1
- package/dist/js/components/src/components/PasswordCreationField/PasswordCreationField.mjs +4 -19
- package/dist/js/components/src/components/PasswordCreationField/PasswordCreationField.mjs.map +1 -1
- package/dist/js/components/src/components/PasswordCreationField/components/PasswordGenerateButton/PasswordGenerateButton.mjs +1 -1
- package/dist/js/components/src/components/PasswordCreationField/components/PasswordGenerateButton/PasswordGenerateButton.mjs.map +1 -1
- package/dist/js/components/src/integrations/react-hook-form/components/Form/Form.mjs +15 -26
- package/dist/js/components/src/integrations/react-hook-form/components/Form/Form.mjs.map +1 -1
- package/dist/js/components/src/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.mjs +70 -0
- package/dist/js/components/src/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.mjs.map +1 -0
- package/dist/js/components/src/lib/hooks/useManagedValue.mjs +23 -0
- package/dist/js/components/src/lib/hooks/useManagedValue.mjs.map +1 -0
- package/dist/types/components/Action/models/ActionState.d.ts +1 -1
- package/dist/types/components/Action/models/ActionState.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/components/ModeButton.d.ts +5 -6
- package/dist/types/components/MarkdownEditor/components/ModeButton.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/components/Toolbar.d.ts +9 -11
- package/dist/types/components/MarkdownEditor/components/Toolbar.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/components/ToolbarButton.d.ts +5 -11
- package/dist/types/components/MarkdownEditor/components/ToolbarButton.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/lib/handleKeyDown.d.ts +1 -1
- package/dist/types/components/MarkdownEditor/lib/handleKeyDown.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/lib/insertAtCursor.d.ts +1 -1
- package/dist/types/components/MarkdownEditor/lib/insertAtCursor.d.ts.map +1 -1
- package/dist/types/components/MarkdownEditor/stories/Default.stories.d.ts.map +1 -1
- package/dist/types/components/PasswordCreationField/PasswordCreationField.d.ts.map +1 -1
- package/dist/types/integrations/react-hook-form/components/Form/Form.d.ts +2 -2
- package/dist/types/integrations/react-hook-form/components/Form/Form.d.ts.map +1 -1
- package/dist/types/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.d.ts +7 -0
- package/dist/types/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.d.ts.map +1 -0
- package/dist/types/lib/hooks/useManagedValue.d.ts +11 -0
- package/dist/types/lib/hooks/useManagedValue.d.ts.map +1 -0
- package/package.json +4 -4
- package/dist/js/components/src/components/Action/ActionStateContext.mjs +0 -24
- package/dist/js/components/src/components/Action/ActionStateContext.mjs.map +0 -1
- package/dist/js/components/src/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.mjs +0 -44
- package/dist/js/components/src/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.mjs.map +0 -1
- package/dist/js/components/src/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.mjs +0 -32
- package/dist/js/components/src/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.mjs.map +0 -1
- package/dist/types/components/Action/ActionStateContext.d.ts +0 -9
- package/dist/types/components/Action/ActionStateContext.d.ts.map +0 -1
- package/dist/types/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.d.ts +0 -7
- package/dist/types/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.d.ts.map +0 -1
- package/dist/types/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.d.ts +0 -15
- package/dist/types/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionState.mjs","sources":["../../../../../../../src/components/Action/models/ActionState.ts"],"sourcesContent":["import {\n action as mobxAction,\n computed,\n makeObservable,\n observable,\n} from \"mobx\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { sleep } from \"@/lib/promises/sleep\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\n\nexport type ActionStateValue =\n | \"isIdle\"\n | \"isSucceeded\"\n | \"isPending\"\n | \"isExecuting\"\n | \"isFailed\";\n\nconst duration = {\n pending: 1000,\n succeeded: 1500,\n failed: 2000,\n};\n\nexport class ActionState {\n private showFeedback?: boolean;\n public state: ActionStateValue = \"isIdle\";\n private setPendingTimeout: number | undefined;\n public error: unknown;\n private isAsync = false;\n\n public constructor() {\n makeObservable(this, {\n state: observable,\n updateState: mobxAction,\n isBusy: computed,\n });\n }\n\n public static useNew(): ActionState {\n return useStatic(() => new ActionState());\n }\n\n public updateState(newState: ActionStateValue): void {\n this.state = newState;\n }\n\n public useValue(): ActionStateValue {\n return useSelector(() => this.state, [this]);\n }\n\n public useIsBusy(): boolean {\n return useSelector(() => this.isBusy, [this]);\n }\n\n public get isBusy(): boolean {\n return this.state !== \"isIdle\";\n }\n\n public onAsyncStart(): void {\n this.isAsync = true;\n this.updateState(\"isExecuting\");\n this.setPendingTimeout = window.setTimeout(\n () => this.startPending(),\n duration.pending,\n );\n }\n\n public async onSucceeded(): Promise<void> {\n await this.onDone();\n }\n\n public async onFailed(error
|
|
1
|
+
{"version":3,"file":"ActionState.mjs","sources":["../../../../../../../src/components/Action/models/ActionState.ts"],"sourcesContent":["import {\n action as mobxAction,\n computed,\n makeObservable,\n observable,\n} from \"mobx\";\nimport useSelector from \"@/lib/mobx/useSelector\";\nimport { sleep } from \"@/lib/promises/sleep\";\nimport { useStatic } from \"@/lib/hooks/useStatic\";\n\nexport type ActionStateValue =\n | \"isIdle\"\n | \"isSucceeded\"\n | \"isPending\"\n | \"isExecuting\"\n | \"isFailed\";\n\nconst duration = {\n pending: 1000,\n succeeded: 1500,\n failed: 2000,\n};\n\nexport class ActionState {\n private showFeedback?: boolean;\n public state: ActionStateValue = \"isIdle\";\n private setPendingTimeout: number | undefined;\n public error: unknown;\n private isAsync = false;\n\n public constructor() {\n makeObservable(this, {\n state: observable,\n updateState: mobxAction,\n isBusy: computed,\n });\n }\n\n public static useNew(): ActionState {\n return useStatic(() => new ActionState());\n }\n\n public updateState(newState: ActionStateValue): void {\n this.state = newState;\n }\n\n public useValue(): ActionStateValue {\n return useSelector(() => this.state, [this]);\n }\n\n public useIsBusy(): boolean {\n return useSelector(() => this.isBusy, [this]);\n }\n\n public get isBusy(): boolean {\n return this.state !== \"isIdle\";\n }\n\n public onAsyncStart(): void {\n this.isAsync = true;\n this.updateState(\"isExecuting\");\n this.setPendingTimeout = window.setTimeout(\n () => this.startPending(),\n duration.pending,\n );\n }\n\n public async onSucceeded(): Promise<void> {\n await this.onDone();\n }\n\n public async onFailed(error?: unknown): Promise<void> {\n this.error = error ?? new Error(\"Unknown error\");\n await this.onDone();\n }\n\n public withFeedback(feedback?: boolean): ActionState {\n this.showFeedback = feedback;\n return this;\n }\n\n private async startFailedFeedback(): Promise<void> {\n this.updateState(\"isFailed\");\n await sleep(duration.failed);\n this.resetAfterDone();\n }\n\n private async startSucceededFeedback(): Promise<void> {\n this.updateState(\"isSucceeded\");\n await sleep(duration.succeeded);\n this.resetAfterDone();\n }\n\n private resetAfterDone(): void {\n this.updateState(\"isIdle\");\n this.isAsync = false;\n this.error = undefined;\n }\n\n private async onDone(): Promise<void> {\n if (this.setPendingTimeout) {\n window.clearTimeout(this.setPendingTimeout);\n }\n if (this.error) {\n await this.startFailedFeedback();\n } else if (\n this.showFeedback !== false &&\n (this.showFeedback || this.isAsync)\n ) {\n await this.startSucceededFeedback();\n } else {\n this.resetAfterDone();\n }\n }\n\n private startPending(): void {\n this.updateState(\"isPending\");\n }\n}\n"],"names":["mobxAction"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
import { useState
|
|
4
|
+
import { useState } from 'react';
|
|
5
5
|
import styles from './MarkdownEditor.module.scss.mjs';
|
|
6
6
|
import { Markdown } from '../Markdown/Markdown.mjs';
|
|
7
7
|
import { TextArea } from '../TextArea/TextArea.mjs';
|
|
@@ -9,24 +9,24 @@ import { Toolbar } from './components/Toolbar.mjs';
|
|
|
9
9
|
import clsx from 'clsx';
|
|
10
10
|
import { flowComponent } from '../../lib/componentFactory/flowComponent.mjs';
|
|
11
11
|
import { handleKeyDown } from './lib/handleKeyDown.mjs';
|
|
12
|
-
import {
|
|
12
|
+
import { useObjectRef } from '@react-aria/utils';
|
|
13
|
+
import { useManagedValue } from '../../lib/hooks/useManagedValue.mjs';
|
|
14
|
+
import { insertAtCursor } from './lib/insertAtCursor.mjs';
|
|
13
15
|
|
|
14
16
|
const MarkdownEditor = flowComponent("MarkdownEditor", (props) => {
|
|
15
17
|
const {
|
|
16
18
|
isDisabled,
|
|
17
19
|
children,
|
|
18
20
|
className,
|
|
19
|
-
value,
|
|
20
|
-
onChange,
|
|
21
21
|
rows,
|
|
22
22
|
autoResizeMaxRows,
|
|
23
23
|
headingOffset,
|
|
24
24
|
ref,
|
|
25
25
|
...rest
|
|
26
26
|
} = props;
|
|
27
|
-
const [markdown, setMarkdown] = useState(value ?? "");
|
|
28
27
|
const [mode, setMode] = useState("editor");
|
|
29
|
-
const
|
|
28
|
+
const { value, handleOnChange } = useManagedValue(props);
|
|
29
|
+
const textAreaRef = useObjectRef(ref);
|
|
30
30
|
const rootClassName = clsx(
|
|
31
31
|
styles.markdownEditor,
|
|
32
32
|
className,
|
|
@@ -38,28 +38,24 @@ const MarkdownEditor = flowComponent("MarkdownEditor", (props) => {
|
|
|
38
38
|
...rest,
|
|
39
39
|
isDisabled: isDisabled || mode === "preview",
|
|
40
40
|
className: rootClassName,
|
|
41
|
-
ref:
|
|
42
|
-
value
|
|
41
|
+
ref: textAreaRef,
|
|
42
|
+
value,
|
|
43
43
|
rows,
|
|
44
44
|
autoResizeMaxRows,
|
|
45
45
|
onChange: (v) => {
|
|
46
|
-
|
|
47
|
-
onChange(v);
|
|
48
|
-
}
|
|
49
|
-
setMarkdown(v);
|
|
46
|
+
handleOnChange(v);
|
|
50
47
|
},
|
|
51
|
-
onKeyDown: (e) => handleKeyDown(e, textAreaRef,
|
|
48
|
+
onKeyDown: (e) => handleKeyDown(e, textAreaRef, handleOnChange),
|
|
52
49
|
children: [
|
|
53
50
|
/* @__PURE__ */ jsx(
|
|
54
51
|
Toolbar,
|
|
55
52
|
{
|
|
56
|
-
|
|
57
|
-
setMarkdown,
|
|
58
|
-
textAreaRef,
|
|
59
|
-
setMode,
|
|
60
|
-
mode,
|
|
53
|
+
currentMode: mode,
|
|
61
54
|
isDisabled,
|
|
62
|
-
|
|
55
|
+
onModeChange: (newMode) => setMode(newMode),
|
|
56
|
+
onToolPressed: (type) => {
|
|
57
|
+
insertAtCursor(value, handleOnChange, textAreaRef, type);
|
|
58
|
+
}
|
|
63
59
|
}
|
|
64
60
|
),
|
|
65
61
|
/* @__PURE__ */ jsx(
|
|
@@ -70,7 +66,7 @@ const MarkdownEditor = flowComponent("MarkdownEditor", (props) => {
|
|
|
70
66
|
style: {
|
|
71
67
|
maxHeight: `calc(var(--line-height--m) * ${autoResizeMaxRows ?? rows} + (var(--form-control--padding-y) * 2))`
|
|
72
68
|
},
|
|
73
|
-
children:
|
|
69
|
+
children: value
|
|
74
70
|
}
|
|
75
71
|
),
|
|
76
72
|
children
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkdownEditor.mjs","sources":["../../../../../../src/components/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["import React, {
|
|
1
|
+
{"version":3,"file":"MarkdownEditor.mjs","sources":["../../../../../../src/components/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport styles from \"./MarkdownEditor.module.scss\";\nimport { Markdown, type MarkdownProps } from \"@/components/Markdown\";\nimport { TextArea, type TextAreaProps } from \"@/components/TextArea\";\nimport { Toolbar } from \"@/components/MarkdownEditor/components/Toolbar\";\nimport clsx from \"clsx\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { handleKeyDown } from \"@/components/MarkdownEditor/lib/handleKeyDown\";\nimport { useObjectRef } from \"@react-aria/utils\";\nimport { useManagedValue } from \"@/lib/hooks/useManagedValue\";\nimport { insertAtCursor } from \"@/components/MarkdownEditor/lib/insertAtCursor\";\n\nexport type MarkdownEditorMode = \"editor\" | \"preview\";\n\nexport type MarkdownEditorProps = TextAreaProps &\n Pick<MarkdownProps, \"headingOffset\">;\n\n/** @flr-generate all */\nexport const MarkdownEditor = flowComponent(\"MarkdownEditor\", (props) => {\n const {\n isDisabled,\n children,\n className,\n rows,\n autoResizeMaxRows,\n headingOffset,\n ref,\n ...rest\n } = props;\n\n const [mode, setMode] = useState<MarkdownEditorMode>(\"editor\");\n const { value, handleOnChange } = useManagedValue(props);\n const textAreaRef = useObjectRef<HTMLTextAreaElement>(ref);\n\n const rootClassName = clsx(\n styles.markdownEditor,\n className,\n styles[`mode-${mode}`],\n );\n\n return (\n <TextArea\n {...rest}\n isDisabled={isDisabled || mode === \"preview\"}\n className={rootClassName}\n ref={textAreaRef}\n value={value}\n rows={rows}\n autoResizeMaxRows={autoResizeMaxRows}\n onChange={(v) => {\n handleOnChange(v);\n }}\n onKeyDown={(e) => handleKeyDown(e, textAreaRef, handleOnChange)}\n >\n <Toolbar\n currentMode={mode}\n isDisabled={isDisabled}\n onModeChange={(newMode) => setMode(newMode)}\n onToolPressed={(type) => {\n insertAtCursor(value, handleOnChange, textAreaRef, type);\n }}\n />\n\n <Markdown\n headingOffset={headingOffset}\n className={styles.markdown}\n style={{\n maxHeight: `calc(var(--line-height--m) * ${autoResizeMaxRows ?? rows} + (var(--form-control--padding-y) * 2))`,\n }}\n >\n {value}\n </Markdown>\n\n {children}\n </TextArea>\n );\n});\n\nexport default MarkdownEditor;\n"],"names":[],"mappings":";;;;;;;;;;;;;AAkBO,MAAM,cAAiB,GAAA,aAAA,CAAc,gBAAkB,EAAA,CAAC,KAAU,KAAA;AACvE,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,IAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAG;AAAA,GACD,GAAA,KAAA;AAEJ,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAA6B,QAAQ,CAAA;AAC7D,EAAA,MAAM,EAAE,KAAA,EAAO,cAAe,EAAA,GAAI,gBAAgB,KAAK,CAAA;AACvD,EAAM,MAAA,WAAA,GAAc,aAAkC,GAAG,CAAA;AAEzD,EAAA,MAAM,aAAgB,GAAA,IAAA;AAAA,IACpB,MAAO,CAAA,cAAA;AAAA,IACP,SAAA;AAAA,IACA,MAAA,CAAO,CAAQ,KAAA,EAAA,IAAI,CAAE,CAAA;AAAA,GACvB;AAEA,EACE,uBAAA,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,UAAA,EAAY,cAAc,IAAS,KAAA,SAAA;AAAA,MACnC,SAAW,EAAA,aAAA;AAAA,MACX,GAAK,EAAA,WAAA;AAAA,MACL,KAAA;AAAA,MACA,IAAA;AAAA,MACA,iBAAA;AAAA,MACA,QAAA,EAAU,CAAC,CAAM,KAAA;AACf,QAAA,cAAA,CAAe,CAAC,CAAA;AAAA,OAClB;AAAA,MACA,WAAW,CAAC,CAAA,KAAM,aAAc,CAAA,CAAA,EAAG,aAAa,cAAc,CAAA;AAAA,MAE9D,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,WAAa,EAAA,IAAA;AAAA,YACb,UAAA;AAAA,YACA,YAAc,EAAA,CAAC,OAAY,KAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,YAC1C,aAAA,EAAe,CAAC,IAAS,KAAA;AACvB,cAAe,cAAA,CAAA,KAAA,EAAO,cAAgB,EAAA,WAAA,EAAa,IAAI,CAAA;AAAA;AACzD;AAAA,SACF;AAAA,wBAEA,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,aAAA;AAAA,YACA,WAAW,MAAO,CAAA,QAAA;AAAA,YAClB,KAAO,EAAA;AAAA,cACL,SAAA,EAAW,CAAgC,6BAAA,EAAA,iBAAA,IAAqB,IAAI,CAAA,wCAAA;AAAA,aACtE;AAAA,YAEC,QAAA,EAAA;AAAA;AAAA,SACH;AAAA,QAEC;AAAA;AAAA;AAAA,GACH;AAEJ,CAAC;;;;"}
|
|
@@ -8,18 +8,20 @@ import locales from '../../../../../_virtual/_.locale.json@bb0db7b5021f874310cbe
|
|
|
8
8
|
import styles from '../MarkdownEditor.module.scss.mjs';
|
|
9
9
|
|
|
10
10
|
const ModeButton = (props) => {
|
|
11
|
-
const {
|
|
11
|
+
const { currentMode, onChange, ...rest } = props;
|
|
12
12
|
const stringFormatter = useLocalizedStringFormatter(locales);
|
|
13
|
-
const otherMode =
|
|
13
|
+
const otherMode = currentMode === "editor" ? "preview" : "editor";
|
|
14
14
|
return /* @__PURE__ */ jsx(
|
|
15
15
|
Button,
|
|
16
16
|
{
|
|
17
|
-
isDisabled,
|
|
18
17
|
className: styles.modeButton,
|
|
19
18
|
size: "s",
|
|
20
19
|
variant: "plain",
|
|
21
20
|
color: "dark",
|
|
22
|
-
onPress: () =>
|
|
21
|
+
onPress: () => {
|
|
22
|
+
onChange?.(otherMode);
|
|
23
|
+
},
|
|
24
|
+
...rest,
|
|
23
25
|
children: stringFormatter.format(`mode.${otherMode}`)
|
|
24
26
|
}
|
|
25
27
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModeButton.mjs","sources":["../../../../../../../src/components/MarkdownEditor/components/ModeButton.tsx"],"sourcesContent":["import React, { type FC } from \"react\";\nimport { Button } from \"@/components/Button\";\nimport { useLocalizedStringFormatter } from \"react-aria\";\nimport locales from \"../locales/*.locale.json\";\nimport type { MarkdownEditorMode } from \"@/components/MarkdownEditor/MarkdownEditor\";\nimport styles from \"../MarkdownEditor.module.scss\";\n\
|
|
1
|
+
{"version":3,"file":"ModeButton.mjs","sources":["../../../../../../../src/components/MarkdownEditor/components/ModeButton.tsx"],"sourcesContent":["import React, { type FC } from \"react\";\nimport { Button, type ButtonProps } from \"@/components/Button\";\nimport { useLocalizedStringFormatter } from \"react-aria\";\nimport locales from \"../locales/*.locale.json\";\nimport type { MarkdownEditorMode } from \"@/components/MarkdownEditor/MarkdownEditor\";\nimport styles from \"../MarkdownEditor.module.scss\";\n\nexport interface ModeButtonProps extends Pick<ButtonProps, \"isDisabled\"> {\n currentMode: MarkdownEditorMode;\n onChange?: (newMode: MarkdownEditorMode) => void;\n}\n\nexport const ModeButton: FC<ModeButtonProps> = (props) => {\n const { currentMode, onChange, ...rest } = props;\n\n const stringFormatter = useLocalizedStringFormatter(locales);\n const otherMode = currentMode === \"editor\" ? \"preview\" : \"editor\";\n\n return (\n <Button\n className={styles.modeButton}\n size=\"s\"\n variant=\"plain\"\n color=\"dark\"\n onPress={() => {\n onChange?.(otherMode);\n }}\n {...rest}\n >\n {stringFormatter.format(`mode.${otherMode}`)}\n </Button>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAYa,MAAA,UAAA,GAAkC,CAAC,KAAU,KAAA;AACxD,EAAA,MAAM,EAAE,WAAA,EAAa,QAAU,EAAA,GAAG,MAAS,GAAA,KAAA;AAE3C,EAAM,MAAA,eAAA,GAAkB,4BAA4B,OAAO,CAAA;AAC3D,EAAM,MAAA,SAAA,GAAY,WAAgB,KAAA,QAAA,GAAW,SAAY,GAAA,QAAA;AAEzD,EACE,uBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,UAAA;AAAA,MAClB,IAAK,EAAA,GAAA;AAAA,MACL,OAAQ,EAAA,OAAA;AAAA,MACR,KAAM,EAAA,MAAA;AAAA,MACN,SAAS,MAAM;AACb,QAAA,QAAA,GAAW,SAAS,CAAA;AAAA,OACtB;AAAA,MACC,GAAG,IAAA;AAAA,MAEH,QAAgB,EAAA,eAAA,CAAA,MAAA,CAAO,CAAQ,KAAA,EAAA,SAAS,CAAE,CAAA;AAAA;AAAA,GAC7C;AAEJ;;;;"}
|
|
@@ -12,23 +12,26 @@ import { ToolbarButton } from './ToolbarButton.mjs';
|
|
|
12
12
|
import { ModeButton } from './ModeButton.mjs';
|
|
13
13
|
|
|
14
14
|
const Toolbar = (props) => {
|
|
15
|
-
const
|
|
15
|
+
const sharedToolButtonProps = {
|
|
16
|
+
onPress: props.onToolPressed,
|
|
17
|
+
isDisabled: props.isDisabled || props.currentMode === "preview"
|
|
18
|
+
};
|
|
16
19
|
return /* @__PURE__ */ jsxs("header", { className: styles.toolbar, role: "toolbar", children: [
|
|
17
20
|
/* @__PURE__ */ jsxs("div", { className: styles.toolbarButtons, children: [
|
|
18
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
19
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
20
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
21
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
22
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
23
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
24
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
25
|
-
/* @__PURE__ */ jsx(ToolbarButton, { ...
|
|
21
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "bold", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconBold, {}) }) }),
|
|
22
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "italic", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconItalic, {}) }) }),
|
|
23
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "strikeThrough", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconStrikethrough, {}) }) }),
|
|
24
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "quote", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconQuoteFilled, {}) }) }),
|
|
25
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "code", children: /* @__PURE__ */ jsx(IconCode, {}) }),
|
|
26
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "link", children: /* @__PURE__ */ jsx(IconLink, {}) }),
|
|
27
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "unorderedList", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconList, {}) }) }),
|
|
28
|
+
/* @__PURE__ */ jsx(ToolbarButton, { ...sharedToolButtonProps, type: "orderedList", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconListNumbers, {}) }) })
|
|
26
29
|
] }),
|
|
27
30
|
/* @__PURE__ */ jsx(
|
|
28
31
|
ModeButton,
|
|
29
32
|
{
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
onChange: props.onModeChange,
|
|
34
|
+
currentMode: props.currentMode,
|
|
32
35
|
isDisabled: props.isDisabled
|
|
33
36
|
}
|
|
34
37
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.mjs","sources":["../../../../../../../src/components/MarkdownEditor/components/Toolbar.tsx"],"sourcesContent":["import React, { type FC
|
|
1
|
+
{"version":3,"file":"Toolbar.mjs","sources":["../../../../../../../src/components/MarkdownEditor/components/Toolbar.tsx"],"sourcesContent":["import React, { type FC } from \"react\";\nimport styles from \"@/components/MarkdownEditor/MarkdownEditor.module.scss\";\nimport { Icon } from \"@/components/Icon\";\nimport {\n IconBold,\n IconItalic,\n IconList,\n IconListNumbers,\n IconQuoteFilled,\n IconStrikethrough,\n} from \"@tabler/icons-react\";\nimport { IconCode, IconLink } from \"@/components/Icon/components/icons\";\nimport {\n ToolbarButton,\n type ToolBarButtonProps,\n} from \"@/components/MarkdownEditor/components/ToolbarButton\";\nimport {\n ModeButton,\n type ModeButtonProps,\n} from \"@/components/MarkdownEditor/components/ModeButton\";\nimport type { ButtonProps } from \"@/components/Button\";\n\ninterface ToolbarProps extends Pick<ButtonProps, \"isDisabled\"> {\n currentMode: ModeButtonProps[\"currentMode\"];\n onModeChange: ModeButtonProps[\"onChange\"];\n onToolPressed: ToolBarButtonProps[\"onPress\"];\n}\n\nexport const Toolbar: FC<ToolbarProps> = (props) => {\n const sharedToolButtonProps: Partial<ToolBarButtonProps> = {\n onPress: props.onToolPressed,\n isDisabled: props.isDisabled || props.currentMode === \"preview\",\n };\n\n return (\n <header className={styles.toolbar} role=\"toolbar\">\n <div className={styles.toolbarButtons}>\n <ToolbarButton {...sharedToolButtonProps} type=\"bold\">\n <Icon>\n <IconBold />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"italic\">\n <Icon>\n <IconItalic />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"strikeThrough\">\n <Icon>\n <IconStrikethrough />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"quote\">\n <Icon>\n <IconQuoteFilled />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"code\">\n <IconCode />\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"link\">\n <IconLink />\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"unorderedList\">\n <Icon>\n <IconList />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...sharedToolButtonProps} type=\"orderedList\">\n <Icon>\n <IconListNumbers />\n </Icon>\n </ToolbarButton>\n </div>\n\n <ModeButton\n onChange={props.onModeChange}\n currentMode={props.currentMode}\n isDisabled={props.isDisabled}\n />\n </header>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AA4Ba,MAAA,OAAA,GAA4B,CAAC,KAAU,KAAA;AAClD,EAAA,MAAM,qBAAqD,GAAA;AAAA,IACzD,SAAS,KAAM,CAAA,aAAA;AAAA,IACf,UAAY,EAAA,KAAA,CAAM,UAAc,IAAA,KAAA,CAAM,WAAgB,KAAA;AAAA,GACxD;AAEA,EAAA,4BACG,QAAO,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,OAAA,EAAS,MAAK,SACtC,EAAA,QAAA,EAAA;AAAA,oBAAC,IAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,MAAA,CAAO,cACrB,EAAA,QAAA,EAAA;AAAA,sBAAC,GAAA,CAAA,aAAA,EAAA,EAAe,GAAG,qBAAA,EAAuB,IAAK,EAAA,MAAA,EAC7C,8BAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,QAAS,EAAA,EAAA,CAAA,EACZ,CACF,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,qBAAuB,EAAA,IAAA,EAAK,QAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,CAAA,EACd,CACF,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,qBAAuB,EAAA,IAAA,EAAK,eAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,iBAAkB,EAAA,EAAA,CAAA,EACrB,CACF,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,qBAAuB,EAAA,IAAA,EAAK,OAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,eAAgB,EAAA,EAAA,CAAA,EACnB,CACF,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,iBAAe,GAAG,qBAAA,EAAuB,MAAK,MAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,YAAS,CACZ,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,iBAAe,GAAG,qBAAA,EAAuB,MAAK,MAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,YAAS,CACZ,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,qBAAuB,EAAA,IAAA,EAAK,eAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,QAAS,EAAA,EAAA,CAAA,EACZ,CACF,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,qBAAuB,EAAA,IAAA,EAAK,aAC7C,EAAA,QAAA,kBAAA,GAAA,CAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,eAAgB,EAAA,EAAA,CAAA,EACnB,CACF,EAAA;AAAA,KACF,EAAA,CAAA;AAAA,oBAEA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,UAAU,KAAM,CAAA,YAAA;AAAA,QAChB,aAAa,KAAM,CAAA,WAAA;AAAA,QACnB,YAAY,KAAM,CAAA;AAAA;AAAA;AACpB,GACF,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -2,32 +2,22 @@
|
|
|
2
2
|
/* */
|
|
3
3
|
import { jsx } from 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
|
-
import { insertAtCursor } from '../lib/insertAtCursor.mjs';
|
|
6
5
|
import { Button } from '../../Button/Button.mjs';
|
|
7
6
|
import { useLocalizedStringFormatter } from 'react-aria';
|
|
8
7
|
import locales from '../../../../../_virtual/_.locale.json@bb0db7b5021f874310cbe5b6cc3d9cac.mjs';
|
|
9
8
|
|
|
10
9
|
const ToolbarButton = (props) => {
|
|
11
|
-
const {
|
|
12
|
-
markdown,
|
|
13
|
-
setMarkdown,
|
|
14
|
-
textAreaRef,
|
|
15
|
-
children,
|
|
16
|
-
isDisabled,
|
|
17
|
-
type,
|
|
18
|
-
onChange,
|
|
19
|
-
mode
|
|
20
|
-
} = props;
|
|
10
|
+
const { children, type, onPress, ...rest } = props;
|
|
21
11
|
const stringFormatter = useLocalizedStringFormatter(locales);
|
|
22
12
|
return /* @__PURE__ */ jsx(
|
|
23
13
|
Button,
|
|
24
14
|
{
|
|
25
|
-
|
|
15
|
+
...rest,
|
|
26
16
|
"aria-label": stringFormatter.format(`toolbar.${type}`),
|
|
27
17
|
size: "s",
|
|
28
18
|
variant: "plain",
|
|
29
19
|
color: "dark",
|
|
30
|
-
onPress: () =>
|
|
20
|
+
onPress: () => onPress?.(type),
|
|
31
21
|
children
|
|
32
22
|
}
|
|
33
23
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolbarButton.mjs","sources":["../../../../../../../src/components/MarkdownEditor/components/ToolbarButton.tsx"],"sourcesContent":["import React, { type FC
|
|
1
|
+
{"version":3,"file":"ToolbarButton.mjs","sources":["../../../../../../../src/components/MarkdownEditor/components/ToolbarButton.tsx"],"sourcesContent":["import React, { type FC } from \"react\";\nimport { type InsertType } from \"@/components/MarkdownEditor/lib/insertAtCursor\";\nimport { Button, type ButtonProps } from \"@/components/Button\";\nimport { useLocalizedStringFormatter } from \"react-aria\";\nimport locales from \"../locales/*.locale.json\";\n\nexport interface ToolBarButtonProps\n extends Pick<ButtonProps, \"isDisabled\" | \"children\"> {\n type: InsertType;\n onPress?: (type: InsertType) => void;\n}\n\nexport const ToolbarButton: FC<ToolBarButtonProps> = (props) => {\n const { children, type, onPress, ...rest } = props;\n\n const stringFormatter = useLocalizedStringFormatter(locales);\n\n return (\n <Button\n {...rest}\n aria-label={stringFormatter.format(`toolbar.${type}`)}\n size=\"s\"\n variant=\"plain\"\n color=\"dark\"\n onPress={() => onPress?.(type)}\n >\n {children}\n </Button>\n );\n};\n"],"names":[],"mappings":";;;;;;AAYa,MAAA,aAAA,GAAwC,CAAC,KAAU,KAAA;AAC9D,EAAA,MAAM,EAAE,QAAU,EAAA,IAAA,EAAM,OAAS,EAAA,GAAG,MAAS,GAAA,KAAA;AAE7C,EAAM,MAAA,eAAA,GAAkB,4BAA4B,OAAO,CAAA;AAE3D,EACE,uBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACE,GAAG,IAAA;AAAA,MACJ,YAAY,EAAA,eAAA,CAAgB,MAAO,CAAA,CAAA,QAAA,EAAW,IAAI,CAAE,CAAA,CAAA;AAAA,MACpD,IAAK,EAAA,GAAA;AAAA,MACL,OAAQ,EAAA,OAAA;AAAA,MACR,KAAM,EAAA,MAAA;AAAA,MACN,OAAA,EAAS,MAAM,OAAA,GAAU,IAAI,CAAA;AAAA,MAE5B;AAAA;AAAA,GACH;AAEJ;;;;"}
|
|
@@ -9,10 +9,14 @@ const scrollToCursor = (textarea) => {
|
|
|
9
9
|
const lines = textarea.value.slice(0, selectionStart).split("\n").length;
|
|
10
10
|
textarea.scrollTop = (lines - 1) * lineHeight;
|
|
11
11
|
};
|
|
12
|
-
const handleKeyDown = (e, textAreaRef, setMarkdown
|
|
13
|
-
if (e.key !== "Enter")
|
|
12
|
+
const handleKeyDown = (e, textAreaRef, setMarkdown) => {
|
|
13
|
+
if (e.key !== "Enter") {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
14
16
|
const textarea = textAreaRef.current;
|
|
15
|
-
if (!textarea)
|
|
17
|
+
if (!textarea) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
16
20
|
const start = textarea.selectionStart;
|
|
17
21
|
const end = textarea.selectionEnd;
|
|
18
22
|
const value = textarea.value;
|
|
@@ -26,9 +30,6 @@ const handleKeyDown = (e, textAreaRef, setMarkdown, onChange) => {
|
|
|
26
30
|
e.preventDefault();
|
|
27
31
|
const newText = value.slice(0, lineStart) + "\n" + after;
|
|
28
32
|
setMarkdown(newText);
|
|
29
|
-
if (onChange) {
|
|
30
|
-
onChange(newText);
|
|
31
|
-
}
|
|
32
33
|
requestAnimationFrame(() => {
|
|
33
34
|
textarea.selectionStart = textarea.selectionEnd = lineStart + 1;
|
|
34
35
|
scrollToCursor(textarea);
|
|
@@ -43,9 +44,6 @@ const handleKeyDown = (e, textAreaRef, setMarkdown, onChange) => {
|
|
|
43
44
|
${indent}${nextNum}. `;
|
|
44
45
|
const newText = before + insert + after;
|
|
45
46
|
setMarkdown(newText);
|
|
46
|
-
if (onChange) {
|
|
47
|
-
onChange(newText);
|
|
48
|
-
}
|
|
49
47
|
requestAnimationFrame(() => {
|
|
50
48
|
textarea.selectionStart = textarea.selectionEnd = start + insert.length;
|
|
51
49
|
scrollToCursor(textarea);
|
|
@@ -58,9 +56,6 @@ ${indent}${nextNum}. `;
|
|
|
58
56
|
${indent}${bullet} `;
|
|
59
57
|
const newText = before + insert + after;
|
|
60
58
|
setMarkdown(newText);
|
|
61
|
-
if (onChange) {
|
|
62
|
-
onChange(newText);
|
|
63
|
-
}
|
|
64
59
|
requestAnimationFrame(() => {
|
|
65
60
|
textarea.selectionStart = textarea.selectionEnd = start + insert.length;
|
|
66
61
|
scrollToCursor(textarea);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleKeyDown.mjs","sources":["../../../../../../../src/components/MarkdownEditor/lib/handleKeyDown.ts"],"sourcesContent":["import type { KeyboardEvent, RefObject } from \"react\";\n\nconst scrollToCursor = (textarea: HTMLTextAreaElement) => {\n const { selectionStart } = textarea;\n const lineHeight = parseInt(\n getComputedStyle(textarea).lineHeight || \"20\",\n 10,\n );\n const lines = textarea.value.slice(0, selectionStart).split(\"\\n\").length;\n textarea.scrollTop = (lines - 1) * lineHeight;\n};\n\nexport const handleKeyDown = (\n e: KeyboardEvent,\n textAreaRef: RefObject<HTMLTextAreaElement | null>,\n setMarkdown: (markdown: string) => void,\n
|
|
1
|
+
{"version":3,"file":"handleKeyDown.mjs","sources":["../../../../../../../src/components/MarkdownEditor/lib/handleKeyDown.ts"],"sourcesContent":["import type { KeyboardEvent, RefObject } from \"react\";\n\nconst scrollToCursor = (textarea: HTMLTextAreaElement) => {\n const { selectionStart } = textarea;\n const lineHeight = parseInt(\n getComputedStyle(textarea).lineHeight || \"20\",\n 10,\n );\n const lines = textarea.value.slice(0, selectionStart).split(\"\\n\").length;\n textarea.scrollTop = (lines - 1) * lineHeight;\n};\n\nexport const handleKeyDown = (\n e: KeyboardEvent,\n textAreaRef: RefObject<HTMLTextAreaElement | null>,\n setMarkdown: (markdown: string) => void,\n) => {\n if (e.key !== \"Enter\") {\n return;\n }\n\n const textarea = textAreaRef.current;\n if (!textarea) {\n return;\n }\n\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const value = textarea.value;\n\n const before = value.slice(0, start);\n const after = value.slice(end);\n const lineStart = before.lastIndexOf(\"\\n\") + 1;\n const currentLine = before.slice(lineStart);\n\n const orderedMatch = currentLine.match(/^(\\s*)(\\d+)\\.\\s+/);\n const unorderedMatch = currentLine.match(/^(\\s*)([-*+])\\s+/);\n\n if (\n (orderedMatch || unorderedMatch) &&\n currentLine.trim().match(/^([-*+]|\\d+\\.)$/)\n ) {\n e.preventDefault();\n\n const newText = value.slice(0, lineStart) + \"\\n\" + after;\n setMarkdown(newText);\n\n requestAnimationFrame(() => {\n textarea.selectionStart = textarea.selectionEnd = lineStart + 1;\n scrollToCursor(textarea);\n });\n\n return;\n }\n\n if (orderedMatch) {\n e.preventDefault();\n\n const indent = orderedMatch[1];\n const nextNum = parseInt(orderedMatch[2] ?? \"\", 10) + 1;\n const insert = `\\n${indent}${nextNum}. `;\n\n const newText = before + insert + after;\n setMarkdown(newText);\n\n requestAnimationFrame(() => {\n textarea.selectionStart = textarea.selectionEnd = start + insert.length;\n scrollToCursor(textarea);\n });\n } else if (unorderedMatch) {\n e.preventDefault();\n\n const indent = unorderedMatch[1];\n const bullet = unorderedMatch[2];\n const insert = `\\n${indent}${bullet} `;\n\n const newText = before + insert + after;\n setMarkdown(newText);\n\n requestAnimationFrame(() => {\n textarea.selectionStart = textarea.selectionEnd = start + insert.length;\n scrollToCursor(textarea);\n });\n }\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -18,9 +18,11 @@ const getLineEnd = (text, pos) => {
|
|
|
18
18
|
const nextNewline = text.indexOf("\n", pos);
|
|
19
19
|
return nextNewline === -1 ? text.length : nextNewline;
|
|
20
20
|
};
|
|
21
|
-
const insertAtCursor = (markdown, setMarkdown, textAreaRef, type
|
|
21
|
+
const insertAtCursor = (markdown, setMarkdown, textAreaRef, type) => {
|
|
22
22
|
const textarea = textAreaRef.current;
|
|
23
|
-
if (!textarea)
|
|
23
|
+
if (!textarea) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
24
26
|
const { before, after = "", toggleable = false } = markdownSyntax[type];
|
|
25
27
|
const start = textarea.selectionStart;
|
|
26
28
|
const end = textarea.selectionEnd;
|
|
@@ -141,7 +143,6 @@ ${before} `;
|
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
setMarkdown(newText);
|
|
144
|
-
if (onChange) onChange(newText);
|
|
145
146
|
requestAnimationFrame(() => {
|
|
146
147
|
textarea.setSelectionRange(selectionStart, selectionEnd);
|
|
147
148
|
textarea.focus();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insertAtCursor.mjs","sources":["../../../../../../../src/components/MarkdownEditor/lib/insertAtCursor.ts"],"sourcesContent":["import type { RefObject } from \"react\";\n\nexport type InsertType =\n | \"bold\"\n | \"italic\"\n | \"strikeThrough\"\n | \"quote\"\n | \"code\"\n | \"link\"\n | \"unorderedList\"\n | \"orderedList\";\n\nconst markdownSyntax: Record<\n InsertType,\n { before: string; after?: string; toggleable?: boolean }\n> = {\n bold: { before: \"**\", after: \"**\", toggleable: true },\n italic: { before: \"_\", after: \"_\", toggleable: true },\n strikeThrough: { before: \"~~\", after: \"~~\", toggleable: true },\n quote: { before: \"> \" },\n code: { before: \"`\", after: \"`\", toggleable: true },\n link: { before: \"[\", after: \"](https://)\" },\n unorderedList: { before: \"- \" },\n orderedList: { before: \"1. \" },\n};\n\nconst getLineStart = (text: string, pos: number) => {\n const lastNewline = text.lastIndexOf(\"\\n\", pos - 1);\n return lastNewline === -1 ? 0 : lastNewline + 1;\n};\n\nconst getLineEnd = (text: string, pos: number) => {\n const nextNewline = text.indexOf(\"\\n\", pos);\n return nextNewline === -1 ? text.length : nextNewline;\n};\n\nexport const insertAtCursor = (\n markdown: string,\n setMarkdown: (markdown: string) => void,\n textAreaRef: RefObject<HTMLTextAreaElement | null>,\n type: InsertType,\n onChange?: (markdown: string) => void,\n) => {\n const textarea = textAreaRef.current;\n if (!textarea) return;\n\n const { before, after = \"\", toggleable = false } = markdownSyntax[type];\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const selectedText = markdown.substring(start, end);\n const lines = selectedText.split(\"\\n\");\n\n let newText = markdown;\n let selectionStart = start;\n let selectionEnd = end;\n\n if (type === \"code\" && selectedText.includes(\"\\n\")) {\n newText =\n markdown.substring(0, start) +\n \"```\\n\" +\n selectedText +\n \"\\n```\\n\" +\n markdown.substring(end);\n selectionStart = start + 4;\n selectionEnd = selectionStart + selectedText.length;\n } else if (type === \"orderedList\") {\n if (selectedText) {\n const numbered = lines.map((line, i) => `${i + 1}. ${line}`).join(\"\\n\");\n newText =\n markdown.substring(0, start) + numbered + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + numbered.length;\n } else {\n const lineStart = getLineStart(markdown, start);\n const lineEnd = getLineEnd(markdown, start);\n const numberedLine = `1. ${markdown.substring(lineStart, lineEnd)}`;\n\n newText =\n markdown.substring(0, lineStart) +\n before +\n markdown.substring(lineStart);\n selectionStart = lineStart + numberedLine.length;\n selectionEnd = selectionStart;\n }\n } else if (type === \"unorderedList\") {\n if (selectedText) {\n const bulleted = lines.map((line) => `${before}${line}`).join(\"\\n\");\n newText =\n markdown.substring(0, start) + bulleted + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + bulleted.length;\n } else {\n const lineStart = getLineStart(markdown, start);\n const lineEnd = getLineEnd(markdown, start);\n const bulletedLine = `- ${markdown.substring(lineStart, lineEnd)}`;\n\n newText =\n markdown.substring(0, lineStart) +\n before +\n markdown.substring(lineStart);\n selectionStart = lineStart + bulletedLine.length;\n selectionEnd = selectionStart;\n }\n } else if (type === \"quote\") {\n if (selectedText) {\n const quoted = lines.map((line) => `${before}${line}`).join(\"\\n\");\n newText = markdown.substring(0, start) + quoted + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + quoted.length;\n } else {\n const quoteLine = `\\n${before} `;\n newText =\n markdown.substring(0, start) + quoteLine + markdown.substring(end);\n selectionStart = start + quoteLine.length;\n selectionEnd = selectionStart;\n }\n } else if (toggleable) {\n const prefix = markdown.substring(start - before.length, start);\n const suffix = markdown.substring(end, end + after.length);\n const isSurrounded = prefix === before && suffix === after;\n const isWrappedInside =\n selectedText.startsWith(before) && selectedText.endsWith(after);\n\n if (isSurrounded) {\n // Remove external wrapping (not selected)\n newText =\n markdown.substring(0, start - before.length) +\n selectedText +\n markdown.substring(end + after.length);\n selectionStart = start - before.length;\n selectionEnd = selectionStart + selectedText.length;\n } else if (isWrappedInside) {\n // Remove internal wrapping (selected)\n const unwrapped = selectedText.slice(\n before.length,\n selectedText.length - after.length,\n );\n newText =\n markdown.substring(0, start) + unwrapped + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + unwrapped.length;\n } else {\n // Add wrapping\n newText =\n markdown.substring(0, start) +\n before +\n selectedText +\n after +\n markdown.substring(end);\n\n if (selectedText.length === 0) {\n selectionStart = start + before.length;\n selectionEnd = selectionStart;\n } else {\n selectionStart = start + before.length;\n selectionEnd = selectionStart + selectedText.length;\n }\n }\n } else if (type === \"link\") {\n let linkText = \"\";\n let linkUrl = \"\";\n let inserted = \"\";\n let cursorOffsetStart = 0;\n\n const isValidUrl = (str: string): boolean => {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n };\n\n if (selectedText) {\n if (isValidUrl(selectedText)) {\n linkUrl = selectedText;\n inserted = `[](${linkUrl})`;\n cursorOffsetStart = start + 1;\n } else {\n linkText = selectedText;\n inserted = `[${linkText}]()`;\n cursorOffsetStart = start + inserted.indexOf(\"](\") + 2;\n }\n } else {\n inserted = `[](https://)`;\n cursorOffsetStart = start + 1;\n }\n\n newText = markdown.substring(0, start) + inserted + markdown.substring(end);\n selectionStart = selectionEnd = cursorOffsetStart;\n } else {\n // Fallback for non-toggleable, inline syntax\n newText =\n markdown.substring(0, start) +\n before +\n selectedText +\n after +\n markdown.substring(end);\n\n if (selectedText.length === 0) {\n // No text selected – place cursor between syntax\n selectionStart = start + before.length;\n selectionEnd = selectionStart;\n } else {\n // Keep selection\n selectionStart = start + before.length;\n selectionEnd = selectionStart + selectedText.length;\n }\n }\n\n setMarkdown(newText);\n if (onChange) onChange(newText);\n\n requestAnimationFrame(() => {\n textarea.setSelectionRange(selectionStart, selectionEnd);\n textarea.focus();\n });\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"insertAtCursor.mjs","sources":["../../../../../../../src/components/MarkdownEditor/lib/insertAtCursor.ts"],"sourcesContent":["import type { RefObject } from \"react\";\n\nexport type InsertType =\n | \"bold\"\n | \"italic\"\n | \"strikeThrough\"\n | \"quote\"\n | \"code\"\n | \"link\"\n | \"unorderedList\"\n | \"orderedList\";\n\nconst markdownSyntax: Record<\n InsertType,\n { before: string; after?: string; toggleable?: boolean }\n> = {\n bold: { before: \"**\", after: \"**\", toggleable: true },\n italic: { before: \"_\", after: \"_\", toggleable: true },\n strikeThrough: { before: \"~~\", after: \"~~\", toggleable: true },\n quote: { before: \"> \" },\n code: { before: \"`\", after: \"`\", toggleable: true },\n link: { before: \"[\", after: \"](https://)\" },\n unorderedList: { before: \"- \" },\n orderedList: { before: \"1. \" },\n};\n\nconst getLineStart = (text: string, pos: number) => {\n const lastNewline = text.lastIndexOf(\"\\n\", pos - 1);\n return lastNewline === -1 ? 0 : lastNewline + 1;\n};\n\nconst getLineEnd = (text: string, pos: number) => {\n const nextNewline = text.indexOf(\"\\n\", pos);\n return nextNewline === -1 ? text.length : nextNewline;\n};\n\nexport const insertAtCursor = (\n markdown: string,\n setMarkdown: (markdown: string) => void,\n textAreaRef: RefObject<HTMLTextAreaElement | null>,\n type: InsertType,\n) => {\n const textarea = textAreaRef.current;\n if (!textarea) {\n return;\n }\n\n const { before, after = \"\", toggleable = false } = markdownSyntax[type];\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const selectedText = markdown.substring(start, end);\n const lines = selectedText.split(\"\\n\");\n\n let newText = markdown;\n let selectionStart = start;\n let selectionEnd = end;\n\n if (type === \"code\" && selectedText.includes(\"\\n\")) {\n newText =\n markdown.substring(0, start) +\n \"```\\n\" +\n selectedText +\n \"\\n```\\n\" +\n markdown.substring(end);\n selectionStart = start + 4;\n selectionEnd = selectionStart + selectedText.length;\n } else if (type === \"orderedList\") {\n if (selectedText) {\n const numbered = lines.map((line, i) => `${i + 1}. ${line}`).join(\"\\n\");\n newText =\n markdown.substring(0, start) + numbered + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + numbered.length;\n } else {\n const lineStart = getLineStart(markdown, start);\n const lineEnd = getLineEnd(markdown, start);\n const numberedLine = `1. ${markdown.substring(lineStart, lineEnd)}`;\n\n newText =\n markdown.substring(0, lineStart) +\n before +\n markdown.substring(lineStart);\n selectionStart = lineStart + numberedLine.length;\n selectionEnd = selectionStart;\n }\n } else if (type === \"unorderedList\") {\n if (selectedText) {\n const bulleted = lines.map((line) => `${before}${line}`).join(\"\\n\");\n newText =\n markdown.substring(0, start) + bulleted + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + bulleted.length;\n } else {\n const lineStart = getLineStart(markdown, start);\n const lineEnd = getLineEnd(markdown, start);\n const bulletedLine = `- ${markdown.substring(lineStart, lineEnd)}`;\n\n newText =\n markdown.substring(0, lineStart) +\n before +\n markdown.substring(lineStart);\n selectionStart = lineStart + bulletedLine.length;\n selectionEnd = selectionStart;\n }\n } else if (type === \"quote\") {\n if (selectedText) {\n const quoted = lines.map((line) => `${before}${line}`).join(\"\\n\");\n newText = markdown.substring(0, start) + quoted + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + quoted.length;\n } else {\n const quoteLine = `\\n${before} `;\n newText =\n markdown.substring(0, start) + quoteLine + markdown.substring(end);\n selectionStart = start + quoteLine.length;\n selectionEnd = selectionStart;\n }\n } else if (toggleable) {\n const prefix = markdown.substring(start - before.length, start);\n const suffix = markdown.substring(end, end + after.length);\n const isSurrounded = prefix === before && suffix === after;\n const isWrappedInside =\n selectedText.startsWith(before) && selectedText.endsWith(after);\n\n if (isSurrounded) {\n // Remove external wrapping (not selected)\n newText =\n markdown.substring(0, start - before.length) +\n selectedText +\n markdown.substring(end + after.length);\n selectionStart = start - before.length;\n selectionEnd = selectionStart + selectedText.length;\n } else if (isWrappedInside) {\n // Remove internal wrapping (selected)\n const unwrapped = selectedText.slice(\n before.length,\n selectedText.length - after.length,\n );\n newText =\n markdown.substring(0, start) + unwrapped + markdown.substring(end);\n selectionStart = start;\n selectionEnd = start + unwrapped.length;\n } else {\n // Add wrapping\n newText =\n markdown.substring(0, start) +\n before +\n selectedText +\n after +\n markdown.substring(end);\n\n if (selectedText.length === 0) {\n selectionStart = start + before.length;\n selectionEnd = selectionStart;\n } else {\n selectionStart = start + before.length;\n selectionEnd = selectionStart + selectedText.length;\n }\n }\n } else if (type === \"link\") {\n let linkText = \"\";\n let linkUrl = \"\";\n let inserted = \"\";\n let cursorOffsetStart = 0;\n\n const isValidUrl = (str: string): boolean => {\n try {\n new URL(str);\n return true;\n } catch {\n return false;\n }\n };\n\n if (selectedText) {\n if (isValidUrl(selectedText)) {\n linkUrl = selectedText;\n inserted = `[](${linkUrl})`;\n cursorOffsetStart = start + 1;\n } else {\n linkText = selectedText;\n inserted = `[${linkText}]()`;\n cursorOffsetStart = start + inserted.indexOf(\"](\") + 2;\n }\n } else {\n inserted = `[](https://)`;\n cursorOffsetStart = start + 1;\n }\n\n newText = markdown.substring(0, start) + inserted + markdown.substring(end);\n selectionStart = selectionEnd = cursorOffsetStart;\n } else {\n // Fallback for non-toggleable, inline syntax\n newText =\n markdown.substring(0, start) +\n before +\n selectedText +\n after +\n markdown.substring(end);\n\n if (selectedText.length === 0) {\n // No text selected – place cursor between syntax\n selectionStart = start + before.length;\n selectionEnd = selectionStart;\n } else {\n // Keep selection\n selectionStart = start + before.length;\n selectionEnd = selectionStart + selectedText.length;\n }\n }\n\n setMarkdown(newText);\n requestAnimationFrame(() => {\n textarea.setSelectionRange(selectionStart, selectionEnd);\n textarea.focus();\n });\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -33,6 +33,7 @@ import 'remeda';
|
|
|
33
33
|
import '@mittwald/password-tools-js/rules';
|
|
34
34
|
import '@mittwald/password-tools-js/generator';
|
|
35
35
|
import { usePolicyValidationResult } from './lib/usePolicyValidationResult.mjs';
|
|
36
|
+
import { useManagedValue } from '../../lib/hooks/useManagedValue.mjs';
|
|
36
37
|
|
|
37
38
|
const PasswordCreationField = flowComponent(
|
|
38
39
|
"PasswordCreationField",
|
|
@@ -42,13 +43,10 @@ const PasswordCreationField = flowComponent(
|
|
|
42
43
|
className,
|
|
43
44
|
ref,
|
|
44
45
|
isDisabled,
|
|
45
|
-
onChange: onChangeFromProps,
|
|
46
46
|
onValidationResult,
|
|
47
47
|
isInvalid: invalidFromProps,
|
|
48
48
|
validationPolicy: validationPolicyFromProps = defaultPasswordCreationPolicy,
|
|
49
49
|
isRequired,
|
|
50
|
-
value: valueFromProps,
|
|
51
|
-
defaultValue,
|
|
52
50
|
...rest
|
|
53
51
|
} = props;
|
|
54
52
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -57,12 +55,7 @@ const PasswordCreationField = flowComponent(
|
|
|
57
55
|
() => Policy.fromDeclaration(validationPolicyFromProps),
|
|
58
56
|
[validationPolicyFromProps]
|
|
59
57
|
);
|
|
60
|
-
const
|
|
61
|
-
const hasDefaultValue = typeof defaultValue !== "undefined";
|
|
62
|
-
const [internalValue, setInternalValue] = useState(
|
|
63
|
-
hasDefaultValue ? defaultValue : ""
|
|
64
|
-
);
|
|
65
|
-
const value = isControlled ? valueFromProps : internalValue;
|
|
58
|
+
const { value, handleOnChange } = useManagedValue(props);
|
|
66
59
|
const deferredValue = useDeferredValue(value);
|
|
67
60
|
const [isPasswordRevealed, setIsPasswordRevealed] = useState(false);
|
|
68
61
|
const initialPolicyValidationState = {
|
|
@@ -125,19 +118,11 @@ const PasswordCreationField = flowComponent(
|
|
|
125
118
|
isValid: true
|
|
126
119
|
}));
|
|
127
120
|
};
|
|
128
|
-
const onChangeHandler = (value2) => {
|
|
129
|
-
if (onChangeFromProps) {
|
|
130
|
-
onChangeFromProps(value2);
|
|
131
|
-
}
|
|
132
|
-
if (!isControlled) {
|
|
133
|
-
setInternalValue(() => value2);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
121
|
const onPasswordGenerateHandler = async () => {
|
|
137
122
|
const generatedPassword = await generatePassword(validationPolicy);
|
|
138
123
|
setOptimisticPolicyValidationResult();
|
|
139
124
|
setIsPasswordRevealed(true);
|
|
140
|
-
|
|
125
|
+
handleOnChange(generatedPassword);
|
|
141
126
|
};
|
|
142
127
|
const onPasswordPasteHandler = (event) => {
|
|
143
128
|
const pastedValue = event.clipboardData.getData("text");
|
|
@@ -212,7 +197,7 @@ const PasswordCreationField = flowComponent(
|
|
|
212
197
|
...rest,
|
|
213
198
|
value,
|
|
214
199
|
type: isPasswordRevealed ? "text" : "password",
|
|
215
|
-
onChange:
|
|
200
|
+
onChange: handleOnChange,
|
|
216
201
|
onPaste: onPasswordPasteHandler,
|
|
217
202
|
className: clsx(className, formFieldStyles.formField),
|
|
218
203
|
isDisabled,
|