@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/assets/doc-properties.json +652 -933
  3. package/dist/js/components/src/components/Action/models/ActionState.mjs.map +1 -1
  4. package/dist/js/components/src/components/MarkdownEditor/MarkdownEditor.mjs +16 -20
  5. package/dist/js/components/src/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
  6. package/dist/js/components/src/components/MarkdownEditor/components/ModeButton.mjs +6 -4
  7. package/dist/js/components/src/components/MarkdownEditor/components/ModeButton.mjs.map +1 -1
  8. package/dist/js/components/src/components/MarkdownEditor/components/Toolbar.mjs +14 -11
  9. package/dist/js/components/src/components/MarkdownEditor/components/Toolbar.mjs.map +1 -1
  10. package/dist/js/components/src/components/MarkdownEditor/components/ToolbarButton.mjs +3 -13
  11. package/dist/js/components/src/components/MarkdownEditor/components/ToolbarButton.mjs.map +1 -1
  12. package/dist/js/components/src/components/MarkdownEditor/lib/handleKeyDown.mjs +7 -12
  13. package/dist/js/components/src/components/MarkdownEditor/lib/handleKeyDown.mjs.map +1 -1
  14. package/dist/js/components/src/components/MarkdownEditor/lib/insertAtCursor.mjs +4 -3
  15. package/dist/js/components/src/components/MarkdownEditor/lib/insertAtCursor.mjs.map +1 -1
  16. package/dist/js/components/src/components/PasswordCreationField/PasswordCreationField.mjs +4 -19
  17. package/dist/js/components/src/components/PasswordCreationField/PasswordCreationField.mjs.map +1 -1
  18. package/dist/js/components/src/components/PasswordCreationField/components/PasswordGenerateButton/PasswordGenerateButton.mjs +1 -1
  19. package/dist/js/components/src/components/PasswordCreationField/components/PasswordGenerateButton/PasswordGenerateButton.mjs.map +1 -1
  20. package/dist/js/components/src/integrations/react-hook-form/components/Form/Form.mjs +15 -26
  21. package/dist/js/components/src/integrations/react-hook-form/components/Form/Form.mjs.map +1 -1
  22. package/dist/js/components/src/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.mjs +70 -0
  23. package/dist/js/components/src/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.mjs.map +1 -0
  24. package/dist/js/components/src/lib/hooks/useManagedValue.mjs +23 -0
  25. package/dist/js/components/src/lib/hooks/useManagedValue.mjs.map +1 -0
  26. package/dist/types/components/Action/models/ActionState.d.ts +1 -1
  27. package/dist/types/components/Action/models/ActionState.d.ts.map +1 -1
  28. package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
  29. package/dist/types/components/MarkdownEditor/components/ModeButton.d.ts +5 -6
  30. package/dist/types/components/MarkdownEditor/components/ModeButton.d.ts.map +1 -1
  31. package/dist/types/components/MarkdownEditor/components/Toolbar.d.ts +9 -11
  32. package/dist/types/components/MarkdownEditor/components/Toolbar.d.ts.map +1 -1
  33. package/dist/types/components/MarkdownEditor/components/ToolbarButton.d.ts +5 -11
  34. package/dist/types/components/MarkdownEditor/components/ToolbarButton.d.ts.map +1 -1
  35. package/dist/types/components/MarkdownEditor/lib/handleKeyDown.d.ts +1 -1
  36. package/dist/types/components/MarkdownEditor/lib/handleKeyDown.d.ts.map +1 -1
  37. package/dist/types/components/MarkdownEditor/lib/insertAtCursor.d.ts +1 -1
  38. package/dist/types/components/MarkdownEditor/lib/insertAtCursor.d.ts.map +1 -1
  39. package/dist/types/components/MarkdownEditor/stories/Default.stories.d.ts.map +1 -1
  40. package/dist/types/components/PasswordCreationField/PasswordCreationField.d.ts.map +1 -1
  41. package/dist/types/integrations/react-hook-form/components/Form/Form.d.ts +2 -2
  42. package/dist/types/integrations/react-hook-form/components/Form/Form.d.ts.map +1 -1
  43. package/dist/types/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.d.ts +7 -0
  44. package/dist/types/integrations/react-hook-form/components/Form/lib/useRegisterActionStateContext.d.ts.map +1 -0
  45. package/dist/types/lib/hooks/useManagedValue.d.ts +11 -0
  46. package/dist/types/lib/hooks/useManagedValue.d.ts.map +1 -0
  47. package/package.json +4 -4
  48. package/dist/js/components/src/components/Action/ActionStateContext.mjs +0 -24
  49. package/dist/js/components/src/components/Action/ActionStateContext.mjs.map +0 -1
  50. package/dist/js/components/src/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.mjs +0 -44
  51. package/dist/js/components/src/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.mjs.map +0 -1
  52. package/dist/js/components/src/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.mjs +0 -32
  53. package/dist/js/components/src/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.mjs.map +0 -1
  54. package/dist/types/components/Action/ActionStateContext.d.ts +0 -9
  55. package/dist/types/components/Action/ActionStateContext.d.ts.map +0 -1
  56. package/dist/types/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.d.ts +0 -7
  57. package/dist/types/integrations/react-hook-form/components/ActionGroupWrapper/SubmitButtonStateProvider.d.ts.map +0 -1
  58. package/dist/types/integrations/react-hook-form/components/AfterFormSubmitEffect/AfterFormSubmitEffect.d.ts +0 -15
  59. 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: 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
+ {"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, useRef } from 'react';
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 { mergeRefs } from '@react-aria/utils';
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 textAreaRef = useRef(null);
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: mergeRefs(textAreaRef, ref),
42
- value: value !== void 0 ? value : markdown,
41
+ ref: textAreaRef,
42
+ value,
43
43
  rows,
44
44
  autoResizeMaxRows,
45
45
  onChange: (v) => {
46
- if (onChange) {
47
- onChange(v);
48
- }
49
- setMarkdown(v);
46
+ handleOnChange(v);
50
47
  },
51
- onKeyDown: (e) => handleKeyDown(e, textAreaRef, setMarkdown, onChange),
48
+ onKeyDown: (e) => handleKeyDown(e, textAreaRef, handleOnChange),
52
49
  children: [
53
50
  /* @__PURE__ */ jsx(
54
51
  Toolbar,
55
52
  {
56
- markdown,
57
- setMarkdown,
58
- textAreaRef,
59
- setMode,
60
- mode,
53
+ currentMode: mode,
61
54
  isDisabled,
62
- onChange
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: markdown
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, { useRef, 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 { mergeRefs } from \"@react-aria/utils\";\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 value,\n onChange,\n rows,\n autoResizeMaxRows,\n headingOffset,\n ref,\n ...rest\n } = props;\n\n const [markdown, setMarkdown] = useState(value ?? \"\");\n const [mode, setMode] = useState<MarkdownEditorMode>(\"editor\");\n const textAreaRef = useRef<HTMLTextAreaElement>(null);\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={mergeRefs(textAreaRef, ref)}\n value={value !== undefined ? value : markdown}\n rows={rows}\n autoResizeMaxRows={autoResizeMaxRows}\n onChange={(v) => {\n if (onChange) {\n onChange(v);\n }\n setMarkdown(v);\n }}\n onKeyDown={(e) => handleKeyDown(e, textAreaRef, setMarkdown, onChange)}\n >\n <Toolbar\n markdown={markdown}\n setMarkdown={setMarkdown}\n textAreaRef={textAreaRef}\n setMode={setMode}\n mode={mode}\n isDisabled={isDisabled}\n onChange={onChange}\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 {markdown}\n </Markdown>\n\n {children}\n </TextArea>\n );\n});\n\nexport default MarkdownEditor;\n"],"names":[],"mappings":";;;;;;;;;;;AAgBO,MAAM,cAAiB,GAAA,aAAA,CAAc,gBAAkB,EAAA,CAAC,KAAU,KAAA;AACvE,EAAM,MAAA;AAAA,IACJ,UAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAG;AAAA,GACD,GAAA,KAAA;AAEJ,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,CAAI,GAAA,QAAA,CAAS,SAAS,EAAE,CAAA;AACpD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAA6B,QAAQ,CAAA;AAC7D,EAAM,MAAA,WAAA,GAAc,OAA4B,IAAI,CAAA;AAEpD,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,GAAA,EAAK,SAAU,CAAA,WAAA,EAAa,GAAG,CAAA;AAAA,MAC/B,KAAA,EAAO,KAAU,KAAA,MAAA,GAAY,KAAQ,GAAA,QAAA;AAAA,MACrC,IAAA;AAAA,MACA,iBAAA;AAAA,MACA,QAAA,EAAU,CAAC,CAAM,KAAA;AACf,QAAA,IAAI,QAAU,EAAA;AACZ,UAAA,QAAA,CAAS,CAAC,CAAA;AAAA;AAEZ,QAAA,WAAA,CAAY,CAAC,CAAA;AAAA,OACf;AAAA,MACA,WAAW,CAAC,CAAA,KAAM,cAAc,CAAG,EAAA,WAAA,EAAa,aAAa,QAAQ,CAAA;AAAA,MAErE,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,QAAA;AAAA,YACA,WAAA;AAAA,YACA,WAAA;AAAA,YACA,OAAA;AAAA,YACA,IAAA;AAAA,YACA,UAAA;AAAA,YACA;AAAA;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;;;;"}
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 { setMode, mode, isDisabled } = props;
11
+ const { currentMode, onChange, ...rest } = props;
12
12
  const stringFormatter = useLocalizedStringFormatter(locales);
13
- const otherMode = mode === "editor" ? "preview" : "editor";
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: () => setMode(otherMode),
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\ninterface Props {\n mode: MarkdownEditorMode;\n setMode: (mode: MarkdownEditorMode) => void;\n isDisabled?: boolean;\n}\n\nexport const ModeButton: FC<Props> = (props) => {\n const { setMode, mode, isDisabled } = props;\n\n const stringFormatter = useLocalizedStringFormatter(locales);\n\n const otherMode = mode === \"editor\" ? \"preview\" : \"editor\";\n\n return (\n <Button\n isDisabled={isDisabled}\n className={styles.modeButton}\n size=\"s\"\n variant=\"plain\"\n color=\"dark\"\n onPress={() => setMode(otherMode)}\n >\n {stringFormatter.format(`mode.${otherMode}`)}\n </Button>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAaa,MAAA,UAAA,GAAwB,CAAC,KAAU,KAAA;AAC9C,EAAA,MAAM,EAAE,OAAA,EAAS,IAAM,EAAA,UAAA,EAAe,GAAA,KAAA;AAEtC,EAAM,MAAA,eAAA,GAAkB,4BAA4B,OAAO,CAAA;AAE3D,EAAM,MAAA,SAAA,GAAY,IAAS,KAAA,QAAA,GAAW,SAAY,GAAA,QAAA;AAElD,EACE,uBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,UAAA;AAAA,MACA,WAAW,MAAO,CAAA,UAAA;AAAA,MAClB,IAAK,EAAA,GAAA;AAAA,MACL,OAAQ,EAAA,OAAA;AAAA,MACR,KAAM,EAAA,MAAA;AAAA,MACN,OAAA,EAAS,MAAM,OAAA,CAAQ,SAAS,CAAA;AAAA,MAE/B,QAAgB,EAAA,eAAA,CAAA,MAAA,CAAO,CAAQ,KAAA,EAAA,SAAS,CAAE,CAAA;AAAA;AAAA,GAC7C;AAEJ;;;;"}
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 { setMode, ...rest } = props;
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, { ...rest, type: "bold", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconBold, {}) }) }),
19
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "italic", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconItalic, {}) }) }),
20
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "strikeThrough", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconStrikethrough, {}) }) }),
21
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "quote", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconQuoteFilled, {}) }) }),
22
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "code", children: /* @__PURE__ */ jsx(IconCode, {}) }),
23
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "link", children: /* @__PURE__ */ jsx(IconLink, {}) }),
24
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "unorderedList", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconList, {}) }) }),
25
- /* @__PURE__ */ jsx(ToolbarButton, { ...rest, type: "orderedList", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(IconListNumbers, {}) }) })
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
- setMode,
31
- mode: props.mode,
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, type RefObject } 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 { ToolbarButton } from \"@/components/MarkdownEditor/components/ToolbarButton\";\nimport type { MarkdownEditorMode } from \"@/components/MarkdownEditor/MarkdownEditor\";\nimport { ModeButton } from \"@/components/MarkdownEditor/components/ModeButton\";\n\ninterface Props {\n markdown: string;\n setMarkdown: (markdown: string) => void;\n textAreaRef: RefObject<HTMLTextAreaElement | null>;\n setMode: (mode: MarkdownEditorMode) => void;\n mode: MarkdownEditorMode;\n isDisabled?: boolean;\n onChange?: (markdown: string) => void;\n}\n\nexport const Toolbar: FC<Props> = (props) => {\n const { setMode, ...rest } = props;\n\n return (\n <header className={styles.toolbar} role=\"toolbar\">\n <div className={styles.toolbarButtons}>\n <ToolbarButton {...rest} type=\"bold\">\n <Icon>\n <IconBold />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"italic\">\n <Icon>\n <IconItalic />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"strikeThrough\">\n <Icon>\n <IconStrikethrough />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"quote\">\n <Icon>\n <IconQuoteFilled />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"code\">\n <IconCode />\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"link\">\n <IconLink />\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"unorderedList\">\n <Icon>\n <IconList />\n </Icon>\n </ToolbarButton>\n\n <ToolbarButton {...rest} type=\"orderedList\">\n <Icon>\n <IconListNumbers />\n </Icon>\n </ToolbarButton>\n </div>\n\n <ModeButton\n setMode={setMode}\n mode={props.mode}\n isDisabled={props.isDisabled}\n />\n </header>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AA0Ba,MAAA,OAAA,GAAqB,CAAC,KAAU,KAAA;AAC3C,EAAA,MAAM,EAAE,OAAA,EAAS,GAAG,IAAA,EAAS,GAAA,KAAA;AAE7B,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,IAAA,EAAM,IAAK,EAAA,MAAA,EAC5B,8BAAC,IACC,EAAA,EAAA,QAAA,kBAAA,GAAA,CAAC,QAAS,EAAA,EAAA,CAAA,EACZ,CACF,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,IAAM,EAAA,IAAA,EAAK,QAC5B,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,IAAM,EAAA,IAAA,EAAK,eAC5B,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,IAAM,EAAA,IAAA,EAAK,OAC5B,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,IAAA,EAAM,MAAK,MAC5B,EAAA,QAAA,kBAAA,GAAA,CAAC,YAAS,CACZ,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,iBAAe,GAAG,IAAA,EAAM,MAAK,MAC5B,EAAA,QAAA,kBAAA,GAAA,CAAC,YAAS,CACZ,EAAA,CAAA;AAAA,sBAEA,GAAA,CAAC,aAAe,EAAA,EAAA,GAAG,IAAM,EAAA,IAAA,EAAK,eAC5B,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,IAAM,EAAA,IAAA,EAAK,aAC5B,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,OAAA;AAAA,QACA,MAAM,KAAM,CAAA,IAAA;AAAA,QACZ,YAAY,KAAM,CAAA;AAAA;AAAA;AACpB,GACF,EAAA,CAAA;AAEJ;;;;"}
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
- isDisabled: isDisabled || mode === "preview",
15
+ ...rest,
26
16
  "aria-label": stringFormatter.format(`toolbar.${type}`),
27
17
  size: "s",
28
18
  variant: "plain",
29
19
  color: "dark",
30
- onPress: () => insertAtCursor(markdown, setMarkdown, textAreaRef, type, onChange),
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, type PropsWithChildren, type RefObject } from \"react\";\nimport {\n insertAtCursor,\n type InsertType,\n} from \"@/components/MarkdownEditor/lib/insertAtCursor\";\nimport { Button } from \"@/components/Button\";\nimport { useLocalizedStringFormatter } from \"react-aria\";\nimport locales from \"../locales/*.locale.json\";\nimport type { MarkdownEditorMode } from \"@/components/MarkdownEditor/MarkdownEditor\";\n\ninterface Props extends PropsWithChildren {\n markdown: string;\n setMarkdown: (markdown: string) => void;\n textAreaRef: RefObject<HTMLTextAreaElement | null>;\n isDisabled?: boolean;\n type: InsertType;\n onChange?: (markdown: string) => void;\n mode: MarkdownEditorMode;\n}\n\nexport const ToolbarButton: FC<Props> = (props) => {\n const {\n markdown,\n setMarkdown,\n textAreaRef,\n children,\n isDisabled,\n type,\n onChange,\n mode,\n } = props;\n\n const stringFormatter = useLocalizedStringFormatter(locales);\n\n return (\n <Button\n isDisabled={isDisabled || mode === \"preview\"}\n aria-label={stringFormatter.format(`toolbar.${type}`)}\n size=\"s\"\n variant=\"plain\"\n color=\"dark\"\n onPress={() =>\n insertAtCursor(markdown, setMarkdown, textAreaRef, type, onChange)\n }\n >\n {children}\n </Button>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAoBa,MAAA,aAAA,GAA2B,CAAC,KAAU,KAAA;AACjD,EAAM,MAAA;AAAA,IACJ,QAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AAEJ,EAAM,MAAA,eAAA,GAAkB,4BAA4B,OAAO,CAAA;AAE3D,EACE,uBAAA,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,UAAA,EAAY,cAAc,IAAS,KAAA,SAAA;AAAA,MACnC,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,SAAS,MACP,cAAA,CAAe,UAAU,WAAa,EAAA,WAAA,EAAa,MAAM,QAAQ,CAAA;AAAA,MAGlE;AAAA;AAAA,GACH;AAEJ;;;;"}
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, onChange) => {
13
- if (e.key !== "Enter") return;
12
+ const handleKeyDown = (e, textAreaRef, setMarkdown) => {
13
+ if (e.key !== "Enter") {
14
+ return;
15
+ }
14
16
  const textarea = textAreaRef.current;
15
- if (!textarea) return;
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 onChange?: (markdown: string) => void,\n) => {\n if (e.key !== \"Enter\") return;\n\n const textarea = textAreaRef.current;\n\n if (!textarea) return;\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 const newText = value.slice(0, lineStart) + \"\\n\" + after;\n\n setMarkdown(newText);\n\n if (onChange) {\n onChange(newText);\n }\n\n requestAnimationFrame(() => {\n textarea.selectionStart = textarea.selectionEnd = lineStart + 1;\n scrollToCursor(textarea);\n });\n return;\n }\n\n if (orderedMatch) {\n e.preventDefault();\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\n setMarkdown(newText);\n\n if (onChange) {\n onChange(newText);\n }\n\n requestAnimationFrame(() => {\n textarea.selectionStart = textarea.selectionEnd = start + insert.length;\n scrollToCursor(textarea);\n });\n } else if (unorderedMatch) {\n e.preventDefault();\n const indent = unorderedMatch[1];\n const bullet = unorderedMatch[2];\n const insert = `\\n${indent}${bullet} `;\n\n const newText = before + insert + after;\n\n setMarkdown(newText);\n\n if (onChange) {\n onChange(newText);\n }\n\n requestAnimationFrame(() => {\n textarea.selectionStart = textarea.selectionEnd = start + insert.length;\n scrollToCursor(textarea);\n });\n }\n};\n"],"names":[],"mappings":"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"}
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, onChange) => {
21
+ const insertAtCursor = (markdown, setMarkdown, textAreaRef, type) => {
22
22
  const textarea = textAreaRef.current;
23
- if (!textarea) return;
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 isControlled = typeof valueFromProps !== "undefined";
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
- onChangeHandler(generatedPassword);
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: onChangeHandler,
200
+ onChange: handleOnChange,
216
201
  onPaste: onPasswordPasteHandler,
217
202
  className: clsx(className, formFieldStyles.formField),
218
203
  isDisabled,