@mittwald/flow-react-components 1.6.0-next.21 → 1.6.0-next.23
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/dist/assets/component-index.json +1 -1
- package/dist/assets/doc-properties.json +1 -1
- package/dist/js/packages/components/src/components/CodeEditor/CodeEditor.mjs +41 -12
- package/dist/js/packages/components/src/components/CodeEditor/CodeEditor.mjs.map +1 -1
- package/dist/js/packages/components/src/components/CodeEditor/hooks/useCodeEditorExtensions.mjs +29 -16
- package/dist/js/packages/components/src/components/CodeEditor/hooks/useCodeEditorExtensions.mjs.map +1 -1
- package/dist/js/packages/components/src/components/DeprecationWarningProvider/DeprecationWarningProvider.mjs +40 -8
- package/dist/js/packages/components/src/components/DeprecationWarningProvider/DeprecationWarningProvider.mjs.map +1 -1
- package/dist/js/packages/components/src/components/Markdown/Markdown.mjs +9 -5
- package/dist/js/packages/components/src/components/Markdown/Markdown.mjs.map +1 -1
- package/package.json +10 -10
|
@@ -12,7 +12,7 @@ import { defaultLightTheme } from "./themes/defaultEditorTheme.mjs";
|
|
|
12
12
|
import { useCodeEditorExtensions } from "./hooks/useCodeEditorExtensions.mjs";
|
|
13
13
|
import { CopyButton } from "../CopyButton/CopyButton.mjs";
|
|
14
14
|
import clsx from "clsx";
|
|
15
|
-
import { useCallback, useId, useState } from "react";
|
|
15
|
+
import { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
16
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
17
|
import { useObjectRef } from "react-aria";
|
|
18
18
|
import CodeMirror, { EditorView } from "@uiw/react-codemirror";
|
|
@@ -22,7 +22,7 @@ import CodeMirror, { EditorView } from "@uiw/react-codemirror";
|
|
|
22
22
|
* @flowStatus new
|
|
23
23
|
*/
|
|
24
24
|
var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
25
|
-
const { ref, children, className, language, extensions, isReadOnly, isDisabled, isInvalid, isRequired, validationBehavior: _ignoredValidationBehavior, value, showLineNumbers = true, showCodeFolding = true, showCodeIndentationMakers = true, showLinterMarkers = true, showActiveLineMarker = true, copyable = true, height, minHeight, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest } = useControlledHostValueProps(props, "");
|
|
25
|
+
const { ref, children, className, language, extensions, isReadOnly, isDisabled, isInvalid, isRequired, validationBehavior: _ignoredValidationBehavior, value, onChange, onStatistics, showLineNumbers = true, showCodeFolding = true, showCodeIndentationMakers = true, showLinterMarkers = true, showActiveLineMarker = true, copyable = true, height, minHeight, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...rest } = useControlledHostValueProps(props, "");
|
|
26
26
|
const { FieldErrorView, FieldErrorCaptureContext, wrapperProps, controlProps, fieldPropsContext } = useFieldComponent(props, "CodeEditor");
|
|
27
27
|
const rootClassName = clsx(wrapperProps.className, CodeEditor_module_default.codeEditor, className);
|
|
28
28
|
const labelId = useId();
|
|
@@ -83,14 +83,48 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
|
83
83
|
*/
|
|
84
84
|
const labelledBy = joinIds(ariaLabelledBy, hasLabel && labelId);
|
|
85
85
|
const describedBy = joinIds(hasDescription && descriptionId, controlProps["aria-describedby"]);
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* CodeMirror reconfigures the editor whenever `extensions`, `basicSetup` or
|
|
88
|
+
* `onChange` is a new object. All three are stable, so a render with
|
|
89
|
+
* unchanged props leaves the editor as it is.
|
|
90
|
+
*/
|
|
91
|
+
const allExtensions = useMemo(() => [...enabledExtensions, EditorView.contentAttributes.of({
|
|
87
92
|
...labelledBy ? { "aria-labelledby": labelledBy } : {},
|
|
88
93
|
...ariaLabel ? { "aria-label": ariaLabel } : {},
|
|
89
94
|
...describedBy ? { "aria-describedby": describedBy } : {},
|
|
90
95
|
...isRequired ? { "aria-required": "true" } : {},
|
|
91
96
|
...isInvalid ? { "aria-invalid": "true" } : {},
|
|
92
97
|
...isDisabled ? { "aria-disabled": "true" } : {}
|
|
98
|
+
})], [
|
|
99
|
+
enabledExtensions,
|
|
100
|
+
labelledBy,
|
|
101
|
+
ariaLabel,
|
|
102
|
+
describedBy,
|
|
103
|
+
isRequired,
|
|
104
|
+
isInvalid,
|
|
105
|
+
isDisabled
|
|
106
|
+
]);
|
|
107
|
+
const handlersRef = useRef({
|
|
108
|
+
onChange,
|
|
109
|
+
onStatistics
|
|
93
110
|
});
|
|
111
|
+
useLayoutEffect(() => {
|
|
112
|
+
handlersRef.current = {
|
|
113
|
+
onChange,
|
|
114
|
+
onStatistics
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
const stableOnChange = useCallback((value) => handlersRef.current.onChange(value), []);
|
|
118
|
+
const stableOnStatistics = useCallback((statistics) => handlersRef.current.onStatistics?.(statistics), []);
|
|
119
|
+
const highlightActiveLine = showActiveLineMarker && !isDisabled;
|
|
120
|
+
const basicSetup = useMemo(() => ({
|
|
121
|
+
highlightActiveLine,
|
|
122
|
+
highlightActiveLineGutter: highlightActiveLine,
|
|
123
|
+
autocompletion: false,
|
|
124
|
+
lineNumbers: false,
|
|
125
|
+
foldGutter: false,
|
|
126
|
+
highlightSelectionMatches: false
|
|
127
|
+
}), [highlightActiveLine]);
|
|
94
128
|
const localRef = useObjectRef(ref);
|
|
95
129
|
useMakeFocusable(localRef);
|
|
96
130
|
const isSkeleton = useSkeletonMode();
|
|
@@ -105,14 +139,9 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
|
105
139
|
const editor = /* @__PURE__ */ jsxs(CodeMirror, {
|
|
106
140
|
...rest,
|
|
107
141
|
value,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
autocompletion: false,
|
|
112
|
-
lineNumbers: false,
|
|
113
|
-
foldGutter: false,
|
|
114
|
-
highlightSelectionMatches: false
|
|
115
|
-
},
|
|
142
|
+
onChange: stableOnChange,
|
|
143
|
+
onStatistics: stableOnStatistics,
|
|
144
|
+
basicSetup,
|
|
116
145
|
theme: defaultLightTheme,
|
|
117
146
|
"data-invalid": isInvalid || void 0,
|
|
118
147
|
"data-disabled": isDisabled || void 0,
|
|
@@ -122,7 +151,7 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
|
122
151
|
ref: (codeMirrorRef) => {
|
|
123
152
|
if (codeMirrorRef?.editor) localRef.current = codeMirrorRef.editor;
|
|
124
153
|
},
|
|
125
|
-
extensions:
|
|
154
|
+
extensions: allExtensions,
|
|
126
155
|
height: height ?? minHeight,
|
|
127
156
|
children: [copyable && /* @__PURE__ */ jsx(CopyButton, {
|
|
128
157
|
className: CodeEditor_module_default.copyButton,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeEditor.mjs","names":["styles"],"sources":["../../../../../../../src/components/CodeEditor/CodeEditor.tsx"],"sourcesContent":["import type { ReactCodeMirrorProps } from \"@uiw/react-codemirror\";\nimport CodeMirror, { EditorView } from \"@uiw/react-codemirror\";\nimport { useCallback, useId, useState } from \"react\";\nimport {\n flowComponent,\n type FlowComponentProps,\n} from \"@/lib/componentFactory/flowComponent\";\nimport { useControlledHostValueProps } from \"@/lib/remote/useControlledHostValueProps\";\nimport { joinIds, useFieldComponent } from \"@/lib/hooks/useFieldComponent\";\nimport { type PropsContext, PropsContextProvider } from \"@/lib/propsContext\";\nimport clsx from \"clsx\";\nimport styles from \"./CodeEditor.module.scss\";\nimport { type CodeEditorLanguage } from \"@/components/CodeEditor/languages\";\nimport { useMakeFocusable } from \"@/lib/hooks/dom/useMakeFocusable\";\nimport { useObjectRef } from \"react-aria\";\nimport { defaultLightTheme } from \"@/components/CodeEditor/themes/defaultEditorTheme\";\nimport {\n type CodeEditorSetup,\n useCodeEditorExtensions,\n} from \"@/components/CodeEditor/hooks/useCodeEditorExtensions\";\nimport { CopyButton } from \"@/components/CopyButton\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\nimport { useSkeletonMode } from \"@/components/SkeletonMode/skeletonModeContext\";\n\nexport interface CodeEditorProps\n extends\n Omit<ReactCodeMirrorProps, \"theme\" | \"lang\" | \"basicSetup\" | \"readOnly\">,\n CodeEditorSetup,\n FlowComponentProps {\n /** The initial code of an uncontrolled editor. */\n defaultValue?: string;\n /**\n * Whether the code can be read but not edited.\n *\n * @default false\n */\n isReadOnly?: boolean;\n /**\n * Whether the editor is disabled. The code can neither be edited, focused nor\n * copied.\n *\n * @default false\n */\n isDisabled?: boolean;\n /**\n * Whether the editor is displayed as invalid.\n *\n * @default false\n */\n isInvalid?: boolean;\n /** The elements class name. */\n className?: string;\n /**\n * The language the code is highlighted as. A language the editor does not\n * know is shown as plain text.\n */\n language?: CodeEditorLanguage | (string & {});\n /**\n * Whether a button to copy the code to the clipboard is shown.\n *\n * @default true\n */\n copyable?: boolean;\n /**\n * Whether the field must be filled in. Only marks the editor as required for\n * assistive technology — the editor does not validate itself.\n *\n * @default false\n */\n isRequired?: boolean;\n /**\n * @internal Set by `<Field />` on every form field. The editor has no\n * react-aria validation to forward it to and drops it.\n */\n validationBehavior?: unknown;\n}\n\n/**\n * @flr-generate all\n * @flowStatus new\n */\nexport const CodeEditor = flowComponent(\"CodeEditor\", (props) => {\n const {\n ref,\n children,\n className,\n language,\n extensions,\n isReadOnly,\n isDisabled,\n isInvalid,\n isRequired,\n validationBehavior: _ignoredValidationBehavior,\n value,\n showLineNumbers = true,\n showCodeFolding = true,\n showCodeIndentationMakers = true,\n showLinterMarkers = true,\n showActiveLineMarker = true,\n copyable = true,\n height,\n minHeight,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...rest\n } = useControlledHostValueProps(props, \"\");\n\n const {\n FieldErrorView,\n FieldErrorCaptureContext,\n wrapperProps,\n controlProps,\n fieldPropsContext,\n } = useFieldComponent(props, \"CodeEditor\");\n\n const rootClassName = clsx(\n wrapperProps.className,\n styles.codeEditor,\n className,\n );\n\n const labelId = useId();\n const descriptionId = useId();\n\n /**\n * Both are optional. Their refs tell whether they are rendered, so the editor\n * never references an element that does not exist – a dangling id fails HTML\n * validators and a11y checks. The callbacks are stable: a new one per render\n * would detach and re-attach on every render.\n */\n const [hasLabel, setHasLabel] = useState(false);\n const [hasDescription, setHasDescription] = useState(false);\n const labelRef = useCallback((element: Element | null) => {\n setHasLabel(!!element);\n }, []);\n const descriptionRef = useCallback((element: Element | null) => {\n setHasDescription(!!element);\n }, []);\n\n /**\n * The label and the field description are declared as children of the code\n * editor, but must be rendered outside of the editor itself. They are\n * tunneled out of the editor – just like the field error. Their ids are the\n * ones the editor references.\n */\n const propsContext: PropsContext = {\n ...fieldPropsContext,\n Label: {\n ...fieldPropsContext.Label,\n id: labelId,\n ref: labelRef,\n tunnel: { id: \"label\", component: \"CodeEditor\" },\n },\n FieldDescription: {\n ...fieldPropsContext.FieldDescription,\n id: descriptionId,\n ref: descriptionRef,\n tunnel: { id: \"fieldDescription\", component: \"CodeEditor\" },\n },\n };\n\n const enabledExtensions = useCodeEditorExtensions(language, extensions, {\n showLineNumbers: showLineNumbers,\n showCodeIndentationMakers: showCodeIndentationMakers,\n showCodeFolding: showCodeFolding,\n showLinterMarkers: showLinterMarkers,\n });\n\n /**\n * The editable element of CodeMirror is the `.cm-content` element – not the\n * root element the props are applied to. Its ARIA attributes are set through\n * the content attributes facet.\n *\n * Without a label, an `aria-label` names the editor instead.\n */\n const labelledBy = joinIds(ariaLabelledBy, hasLabel && labelId);\n const describedBy = joinIds(\n hasDescription && descriptionId,\n controlProps[\"aria-describedby\"],\n );\n\n const contentAttributes = EditorView.contentAttributes.of({\n ...(labelledBy ? { \"aria-labelledby\": labelledBy } : {}),\n ...(ariaLabel ? { \"aria-label\": ariaLabel } : {}),\n ...(describedBy ? { \"aria-describedby\": describedBy } : {}),\n ...(isRequired ? { \"aria-required\": \"true\" } : {}),\n ...(isInvalid ? { \"aria-invalid\": \"true\" } : {}),\n ...(isDisabled ? { \"aria-disabled\": \"true\" } : {}),\n });\n\n const localRef = useObjectRef(ref);\n\n useMakeFocusable(localRef);\n\n const isSkeleton = useSkeletonMode();\n\n /* No CodeMirror: one surface, as high as the code in the editor's line\n height. The children still render, so a label or a field description\n tunnels out and follows its own skeleton rule. */\n const skeleton = (\n <div\n className={clsx(\n styles.codeMirror,\n isReadOnly && styles.readonly,\n styles.skeleton,\n )}\n >\n <div\n className={styles.skeletonLines}\n style={{ height: height ?? minHeight }}\n >\n {(value ?? \"\").split(\"\\n\").map((line, index) => (\n <div key={index}>{line || \" \"}</div>\n ))}\n </div>\n {children}\n </div>\n );\n\n const editor = (\n <CodeMirror\n {...rest}\n value={value}\n basicSetup={{\n highlightActiveLine: showActiveLineMarker && !isDisabled,\n highlightActiveLineGutter: showActiveLineMarker && !isDisabled,\n autocompletion: false,\n lineNumbers: false,\n foldGutter: false,\n highlightSelectionMatches: false,\n }}\n theme={defaultLightTheme}\n data-invalid={isInvalid || undefined}\n data-disabled={isDisabled || undefined}\n readOnly={isReadOnly || isDisabled}\n editable={!isDisabled}\n className={clsx(styles.codeMirror, isReadOnly && styles.readonly)}\n ref={(codeMirrorRef) => {\n if (codeMirrorRef?.editor) {\n localRef.current = codeMirrorRef.editor;\n }\n }}\n extensions={[...enabledExtensions, contentAttributes]}\n height={height ?? minHeight}\n >\n {copyable && (\n <CopyButton\n className={styles.copyButton}\n size=\"s\"\n variant=\"soft\"\n text={value}\n isDisabled={isDisabled}\n />\n )}\n {children}\n </CodeMirror>\n );\n\n return (\n <div\n className={rootClassName}\n data-disabled={isDisabled || undefined}\n inert={isSkeleton || undefined}\n >\n <PropsContextProvider props={propsContext}>\n <UiComponentTunnelExit id=\"label\" component=\"CodeEditor\" />\n <FieldErrorCaptureContext>\n {isSkeleton ? skeleton : editor}\n </FieldErrorCaptureContext>\n <UiComponentTunnelExit id=\"fieldDescription\" component=\"CodeEditor\" />\n <FieldErrorView />\n </PropsContextProvider>\n </div>\n );\n});\n\nexport default CodeEditor;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CodeEditor.mjs","names":["styles"],"sources":["../../../../../../../src/components/CodeEditor/CodeEditor.tsx"],"sourcesContent":["import type { ReactCodeMirrorProps, Statistics } from \"@uiw/react-codemirror\";\nimport CodeMirror, { EditorView } from \"@uiw/react-codemirror\";\nimport {\n useCallback,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n flowComponent,\n type FlowComponentProps,\n} from \"@/lib/componentFactory/flowComponent\";\nimport { useControlledHostValueProps } from \"@/lib/remote/useControlledHostValueProps\";\nimport { joinIds, useFieldComponent } from \"@/lib/hooks/useFieldComponent\";\nimport { type PropsContext, PropsContextProvider } from \"@/lib/propsContext\";\nimport clsx from \"clsx\";\nimport styles from \"./CodeEditor.module.scss\";\nimport { type CodeEditorLanguage } from \"@/components/CodeEditor/languages\";\nimport { useMakeFocusable } from \"@/lib/hooks/dom/useMakeFocusable\";\nimport { useObjectRef } from \"react-aria\";\nimport { defaultLightTheme } from \"@/components/CodeEditor/themes/defaultEditorTheme\";\nimport {\n type CodeEditorSetup,\n useCodeEditorExtensions,\n} from \"@/components/CodeEditor/hooks/useCodeEditorExtensions\";\nimport { CopyButton } from \"@/components/CopyButton\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\nimport { useSkeletonMode } from \"@/components/SkeletonMode/skeletonModeContext\";\n\nexport interface CodeEditorProps\n extends\n Omit<ReactCodeMirrorProps, \"theme\" | \"lang\" | \"basicSetup\" | \"readOnly\">,\n CodeEditorSetup,\n FlowComponentProps {\n /** The initial code of an uncontrolled editor. */\n defaultValue?: string;\n /**\n * Whether the code can be read but not edited.\n *\n * @default false\n */\n isReadOnly?: boolean;\n /**\n * Whether the editor is disabled. The code can neither be edited, focused nor\n * copied.\n *\n * @default false\n */\n isDisabled?: boolean;\n /**\n * Whether the editor is displayed as invalid.\n *\n * @default false\n */\n isInvalid?: boolean;\n /** The elements class name. */\n className?: string;\n /**\n * The language the code is highlighted as. A language the editor does not\n * know is shown as plain text.\n */\n language?: CodeEditorLanguage | (string & {});\n /**\n * Whether a button to copy the code to the clipboard is shown.\n *\n * @default true\n */\n copyable?: boolean;\n /**\n * Whether the field must be filled in. Only marks the editor as required for\n * assistive technology — the editor does not validate itself.\n *\n * @default false\n */\n isRequired?: boolean;\n /**\n * @internal Set by `<Field />` on every form field. The editor has no\n * react-aria validation to forward it to and drops it.\n */\n validationBehavior?: unknown;\n}\n\n/**\n * @flr-generate all\n * @flowStatus new\n */\nexport const CodeEditor = flowComponent(\"CodeEditor\", (props) => {\n const {\n ref,\n children,\n className,\n language,\n extensions,\n isReadOnly,\n isDisabled,\n isInvalid,\n isRequired,\n validationBehavior: _ignoredValidationBehavior,\n value,\n onChange,\n onStatistics,\n showLineNumbers = true,\n showCodeFolding = true,\n showCodeIndentationMakers = true,\n showLinterMarkers = true,\n showActiveLineMarker = true,\n copyable = true,\n height,\n minHeight,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...rest\n } = useControlledHostValueProps(props, \"\");\n\n const {\n FieldErrorView,\n FieldErrorCaptureContext,\n wrapperProps,\n controlProps,\n fieldPropsContext,\n } = useFieldComponent(props, \"CodeEditor\");\n\n const rootClassName = clsx(\n wrapperProps.className,\n styles.codeEditor,\n className,\n );\n\n const labelId = useId();\n const descriptionId = useId();\n\n /**\n * Both are optional. Their refs tell whether they are rendered, so the editor\n * never references an element that does not exist – a dangling id fails HTML\n * validators and a11y checks. The callbacks are stable: a new one per render\n * would detach and re-attach on every render.\n */\n const [hasLabel, setHasLabel] = useState(false);\n const [hasDescription, setHasDescription] = useState(false);\n const labelRef = useCallback((element: Element | null) => {\n setHasLabel(!!element);\n }, []);\n const descriptionRef = useCallback((element: Element | null) => {\n setHasDescription(!!element);\n }, []);\n\n /**\n * The label and the field description are declared as children of the code\n * editor, but must be rendered outside of the editor itself. They are\n * tunneled out of the editor – just like the field error. Their ids are the\n * ones the editor references.\n */\n const propsContext: PropsContext = {\n ...fieldPropsContext,\n Label: {\n ...fieldPropsContext.Label,\n id: labelId,\n ref: labelRef,\n tunnel: { id: \"label\", component: \"CodeEditor\" },\n },\n FieldDescription: {\n ...fieldPropsContext.FieldDescription,\n id: descriptionId,\n ref: descriptionRef,\n tunnel: { id: \"fieldDescription\", component: \"CodeEditor\" },\n },\n };\n\n const enabledExtensions = useCodeEditorExtensions(language, extensions, {\n showLineNumbers: showLineNumbers,\n showCodeIndentationMakers: showCodeIndentationMakers,\n showCodeFolding: showCodeFolding,\n showLinterMarkers: showLinterMarkers,\n });\n\n /**\n * The editable element of CodeMirror is the `.cm-content` element – not the\n * root element the props are applied to. Its ARIA attributes are set through\n * the content attributes facet.\n *\n * Without a label, an `aria-label` names the editor instead.\n */\n const labelledBy = joinIds(ariaLabelledBy, hasLabel && labelId);\n const describedBy = joinIds(\n hasDescription && descriptionId,\n controlProps[\"aria-describedby\"],\n );\n\n /**\n * CodeMirror reconfigures the editor whenever `extensions`, `basicSetup` or\n * `onChange` is a new object. All three are stable, so a render with\n * unchanged props leaves the editor as it is.\n */\n const allExtensions = useMemo(\n () => [\n ...enabledExtensions,\n EditorView.contentAttributes.of({\n ...(labelledBy ? { \"aria-labelledby\": labelledBy } : {}),\n ...(ariaLabel ? { \"aria-label\": ariaLabel } : {}),\n ...(describedBy ? { \"aria-describedby\": describedBy } : {}),\n ...(isRequired ? { \"aria-required\": \"true\" } : {}),\n ...(isInvalid ? { \"aria-invalid\": \"true\" } : {}),\n ...(isDisabled ? { \"aria-disabled\": \"true\" } : {}),\n }),\n ],\n [\n enabledExtensions,\n labelledBy,\n ariaLabel,\n describedBy,\n isRequired,\n isInvalid,\n isDisabled,\n ],\n );\n\n /*\n * A new `onChange` on every render would reconfigure the editor as well.\n * CodeMirror's update listener captures `onStatistics` along with it, so both\n * call the latest handler through a ref.\n */\n const handlersRef = useRef({ onChange, onStatistics });\n useLayoutEffect(() => {\n handlersRef.current = { onChange, onStatistics };\n });\n const stableOnChange = useCallback(\n (value: string) => handlersRef.current.onChange(value),\n [],\n );\n const stableOnStatistics = useCallback(\n (statistics: Statistics) => handlersRef.current.onStatistics?.(statistics),\n [],\n );\n\n const highlightActiveLine = showActiveLineMarker && !isDisabled;\n const basicSetup = useMemo(\n () => ({\n highlightActiveLine,\n highlightActiveLineGutter: highlightActiveLine,\n autocompletion: false,\n lineNumbers: false,\n foldGutter: false,\n highlightSelectionMatches: false,\n }),\n [highlightActiveLine],\n );\n\n const localRef = useObjectRef(ref);\n\n useMakeFocusable(localRef);\n\n const isSkeleton = useSkeletonMode();\n\n /* No CodeMirror: one surface, as high as the code in the editor's line\n height. The children still render, so a label or a field description\n tunnels out and follows its own skeleton rule. */\n const skeleton = (\n <div\n className={clsx(\n styles.codeMirror,\n isReadOnly && styles.readonly,\n styles.skeleton,\n )}\n >\n <div\n className={styles.skeletonLines}\n style={{ height: height ?? minHeight }}\n >\n {(value ?? \"\").split(\"\\n\").map((line, index) => (\n <div key={index}>{line || \" \"}</div>\n ))}\n </div>\n {children}\n </div>\n );\n\n const editor = (\n <CodeMirror\n {...rest}\n value={value}\n onChange={stableOnChange}\n onStatistics={stableOnStatistics}\n basicSetup={basicSetup}\n theme={defaultLightTheme}\n data-invalid={isInvalid || undefined}\n data-disabled={isDisabled || undefined}\n readOnly={isReadOnly || isDisabled}\n editable={!isDisabled}\n className={clsx(styles.codeMirror, isReadOnly && styles.readonly)}\n ref={(codeMirrorRef) => {\n if (codeMirrorRef?.editor) {\n localRef.current = codeMirrorRef.editor;\n }\n }}\n extensions={allExtensions}\n height={height ?? minHeight}\n >\n {copyable && (\n <CopyButton\n className={styles.copyButton}\n size=\"s\"\n variant=\"soft\"\n text={value}\n isDisabled={isDisabled}\n />\n )}\n {children}\n </CodeMirror>\n );\n\n return (\n <div\n className={rootClassName}\n data-disabled={isDisabled || undefined}\n inert={isSkeleton || undefined}\n >\n <PropsContextProvider props={propsContext}>\n <UiComponentTunnelExit id=\"label\" component=\"CodeEditor\" />\n <FieldErrorCaptureContext>\n {isSkeleton ? skeleton : editor}\n </FieldErrorCaptureContext>\n <UiComponentTunnelExit id=\"fieldDescription\" component=\"CodeEditor\" />\n <FieldErrorView />\n </PropsContextProvider>\n </div>\n );\n});\n\nexport default CodeEditor;\n"],"mappings":"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"}
|
package/dist/js/packages/components/src/components/CodeEditor/hooks/useCodeEditorExtensions.mjs
CHANGED
|
@@ -2,38 +2,51 @@
|
|
|
2
2
|
/* */
|
|
3
3
|
import supportedCodeEditorLanguages, { isCodeEditorLanguage } from "../languages/index.mjs";
|
|
4
4
|
import { gutterSpacer } from "../extensions/gutterSpacer.mjs";
|
|
5
|
+
import { useMemo } from "react";
|
|
5
6
|
import { lineNumbers } from "@uiw/react-codemirror";
|
|
6
7
|
import { foldGutter } from "@codemirror/language";
|
|
7
8
|
import { lintGutter } from "@codemirror/lint";
|
|
8
9
|
import { indentationMarkers } from "@replit/codemirror-indentation-markers";
|
|
9
10
|
//#region src/components/CodeEditor/hooks/useCodeEditorExtensions.tsx
|
|
10
11
|
var markerColor = "var(--code-editor--indentation-marker-color)";
|
|
11
|
-
var
|
|
12
|
+
var codeIndentationMarkers = indentationMarkers({ colors: {
|
|
12
13
|
light: markerColor,
|
|
13
14
|
dark: markerColor,
|
|
14
15
|
activeLight: markerColor,
|
|
15
16
|
activeDark: markerColor
|
|
16
|
-
};
|
|
17
|
+
} });
|
|
18
|
+
var noExtensions = [];
|
|
17
19
|
/** @internal */
|
|
18
|
-
var useCodeEditorExtensions = (language, extensions =
|
|
20
|
+
var useCodeEditorExtensions = (language, extensions = noExtensions, options = {
|
|
19
21
|
showCodeFolding: true,
|
|
20
22
|
showCodeIndentationMakers: true,
|
|
21
23
|
showLineNumbers: true,
|
|
22
24
|
showLinterMarkers: true
|
|
23
25
|
}) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
const { showCodeFolding, showCodeIndentationMakers, showLineNumbers, showLinterMarkers } = options;
|
|
27
|
+
return useMemo(() => {
|
|
28
|
+
const enabledExtensions = [...extensions];
|
|
29
|
+
if (showLineNumbers) enabledExtensions.push(lineNumbers());
|
|
30
|
+
if (showCodeFolding) enabledExtensions.push(foldGutter({ markerDOM: (open) => {
|
|
31
|
+
const element = document.createElement("span");
|
|
32
|
+
element.classList.add("cm-foldGutter");
|
|
33
|
+
element.classList.add(open ? "cm-foldGutter-open" : "cm-foldGutter-closed");
|
|
34
|
+
element.innerText = open ? "⌄" : "›";
|
|
35
|
+
return element;
|
|
36
|
+
} }));
|
|
37
|
+
if (showLinterMarkers) enabledExtensions.push(lintGutter());
|
|
38
|
+
if (showLineNumbers && (!showCodeFolding || !showLinterMarkers)) enabledExtensions.push(gutterSpacer());
|
|
39
|
+
if (showCodeIndentationMakers) enabledExtensions.push(codeIndentationMarkers);
|
|
40
|
+
if (language && isCodeEditorLanguage(language)) for (const loader of supportedCodeEditorLanguages[language] ?? []) enabledExtensions.push(loader());
|
|
41
|
+
return enabledExtensions;
|
|
42
|
+
}, [
|
|
43
|
+
language,
|
|
44
|
+
extensions,
|
|
45
|
+
showCodeFolding,
|
|
46
|
+
showCodeIndentationMakers,
|
|
47
|
+
showLineNumbers,
|
|
48
|
+
showLinterMarkers
|
|
49
|
+
]);
|
|
37
50
|
};
|
|
38
51
|
//#endregion
|
|
39
52
|
export { useCodeEditorExtensions };
|
package/dist/js/packages/components/src/components/CodeEditor/hooks/useCodeEditorExtensions.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCodeEditorExtensions.mjs","names":[],"sources":["../../../../../../../../src/components/CodeEditor/hooks/useCodeEditorExtensions.tsx"],"sourcesContent":["import { type Extension, lineNumbers } from \"@uiw/react-codemirror\";\nimport { lintGutter } from \"@codemirror/lint\";\nimport supportedCodeEditorLanguages, {\n isCodeEditorLanguage,\n} from \"@/components/CodeEditor/languages\";\nimport { indentationMarkers } from \"@replit/codemirror-indentation-markers\";\nimport { foldGutter } from \"@codemirror/language\";\nimport { gutterSpacer } from \"@/components/CodeEditor/extensions/gutterSpacer\";\n\n/*\n * Every slot gets the same color: the library picks between its light and dark\n * one by CodeMirror's dark theme flag, which Flow's theme never sets, and the\n * active block needs no color of its own.\n */\nconst markerColor = \"var(--code-editor--indentation-marker-color)\";\nconst
|
|
1
|
+
{"version":3,"file":"useCodeEditorExtensions.mjs","names":[],"sources":["../../../../../../../../src/components/CodeEditor/hooks/useCodeEditorExtensions.tsx"],"sourcesContent":["import { type Extension, lineNumbers } from \"@uiw/react-codemirror\";\nimport { lintGutter } from \"@codemirror/lint\";\nimport supportedCodeEditorLanguages, {\n isCodeEditorLanguage,\n} from \"@/components/CodeEditor/languages\";\nimport { indentationMarkers } from \"@replit/codemirror-indentation-markers\";\nimport { foldGutter } from \"@codemirror/language\";\nimport { gutterSpacer } from \"@/components/CodeEditor/extensions/gutterSpacer\";\nimport { useMemo } from \"react\";\n\n/*\n * Every slot gets the same color: the library picks between its light and dark\n * one by CodeMirror's dark theme flag, which Flow's theme never sets, and the\n * active block needs no color of its own.\n */\nconst markerColor = \"var(--code-editor--indentation-marker-color)\";\n\n/*\n * Created once: every call brings a new style module along, and CodeMirror\n * never unmounts a style module – one per render grows the document's styles.\n */\nconst codeIndentationMarkers = indentationMarkers({\n colors: {\n light: markerColor,\n dark: markerColor,\n activeLight: markerColor,\n activeDark: markerColor,\n },\n});\n\nexport interface CodeEditorSetup {\n /**\n * Whether the line the cursor is on is highlighted.\n *\n * @default true\n */\n showActiveLineMarker?: boolean;\n /**\n * Whether the gutter offers controls to fold and unfold code blocks.\n *\n * @default true\n */\n showCodeFolding?: boolean;\n /**\n * Whether indentation levels are visualized with guide lines.\n *\n * @default true\n */\n showCodeIndentationMakers?: boolean;\n /**\n * Whether line numbers are shown in the gutter.\n *\n * @default true\n */\n showLineNumbers?: boolean;\n /**\n * Whether linter results are shown in the gutter.\n *\n * @default true\n */\n showLinterMarkers?: boolean;\n}\n\nconst noExtensions: Extension[] = [];\n\n/** @internal */\nexport const useCodeEditorExtensions = (\n language?: string,\n extensions: Extension[] = noExtensions,\n options: CodeEditorSetup = {\n showCodeFolding: true,\n showCodeIndentationMakers: true,\n showLineNumbers: true,\n showLinterMarkers: true,\n },\n): Extension[] => {\n const {\n showCodeFolding,\n showCodeIndentationMakers,\n showLineNumbers,\n showLinterMarkers,\n } = options;\n\n return useMemo(() => {\n const enabledExtensions = [...extensions];\n\n if (showLineNumbers) {\n enabledExtensions.push(lineNumbers());\n }\n\n if (showCodeFolding) {\n enabledExtensions.push(\n foldGutter({\n markerDOM: (open) => {\n const element = document.createElement(\"span\");\n element.classList.add(\"cm-foldGutter\");\n element.classList.add(\n open ? \"cm-foldGutter-open\" : \"cm-foldGutter-closed\",\n );\n element.innerText = open ? \"⌄\" : \"›\";\n return element;\n },\n }),\n );\n }\n\n if (showLinterMarkers) {\n enabledExtensions.push(lintGutter());\n }\n\n if (showLineNumbers && (!showCodeFolding || !showLinterMarkers)) {\n enabledExtensions.push(gutterSpacer());\n }\n\n if (showCodeIndentationMakers) {\n enabledExtensions.push(codeIndentationMarkers);\n }\n\n if (language && isCodeEditorLanguage(language)) {\n for (const loader of supportedCodeEditorLanguages[language] ?? []) {\n enabledExtensions.push(loader());\n }\n }\n\n return enabledExtensions;\n }, [\n language,\n extensions,\n showCodeFolding,\n showCodeIndentationMakers,\n showLineNumbers,\n showLinterMarkers,\n ]);\n};\n"],"mappings":";;;;;;;;;;AAeA,IAAM,cAAc;AAMpB,IAAM,yBAAyB,mBAAmB,EAChD,QAAQ;CACN,OAAO;CACP,MAAM;CACN,aAAa;CACb,YAAY;AACd,EACF,CAAC;AAmCD,IAAM,eAA4B,CAAC;;AAGnC,IAAa,2BACX,UACA,aAA0B,cAC1B,UAA2B;CACzB,iBAAiB;CACjB,2BAA2B;CAC3B,iBAAiB;CACjB,mBAAmB;AACrB,MACgB;CAChB,MAAM,EACJ,iBACA,2BACA,iBACA,sBACE;CAEJ,OAAO,cAAc;EACnB,MAAM,oBAAoB,CAAC,GAAG,UAAU;EAExC,IAAI,iBACF,kBAAkB,KAAK,YAAY,CAAC;EAGtC,IAAI,iBACF,kBAAkB,KAChB,WAAW,EACT,YAAY,SAAS;GACnB,MAAM,UAAU,SAAS,cAAc,MAAM;GAC7C,QAAQ,UAAU,IAAI,eAAe;GACrC,QAAQ,UAAU,IAChB,OAAO,uBAAuB,sBAChC;GACA,QAAQ,YAAY,OAAO,MAAM;GACjC,OAAO;EACT,EACF,CAAC,CACH;EAGF,IAAI,mBACF,kBAAkB,KAAK,WAAW,CAAC;EAGrC,IAAI,oBAAoB,CAAC,mBAAmB,CAAC,oBAC3C,kBAAkB,KAAK,aAAa,CAAC;EAGvC,IAAI,2BACF,kBAAkB,KAAK,sBAAsB;EAG/C,IAAI,YAAY,qBAAqB,QAAQ,GAC3C,KAAK,MAAM,UAAU,6BAA6B,aAAa,CAAC,GAC9D,kBAAkB,KAAK,OAAO,CAAC;EAInC,OAAO;CACT,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH"}
|
|
@@ -1,33 +1,65 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
/* */
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useRef } from "react";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/DeprecationWarningProvider/DeprecationWarningProvider.tsx
|
|
6
6
|
var DeprecationWarningContext = createContext(void 0);
|
|
7
|
+
/**
|
|
8
|
+
* Messages a provider has passed to its `onWarning`. Held by the provider, not
|
|
9
|
+
* keyed by the handler: an inline `onWarning` is a new function on every
|
|
10
|
+
* render.
|
|
11
|
+
*/
|
|
12
|
+
var ReportedWarningsContext = createContext(void 0);
|
|
13
|
+
/** Messages already written to `console.warn`, across all providers. */
|
|
14
|
+
var consoleReportedWarnings = /* @__PURE__ */ new Set();
|
|
15
|
+
/**
|
|
16
|
+
* Fallback for a bare `DeprecationWarningContext.Provider`, which has no
|
|
17
|
+
* provider-held set.
|
|
18
|
+
*/
|
|
19
|
+
var reportedWarningsByHandler = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
var getHandlerReportedWarnings = (handler) => {
|
|
21
|
+
let reported = reportedWarningsByHandler.get(handler);
|
|
22
|
+
if (!reported) {
|
|
23
|
+
reported = /* @__PURE__ */ new Set();
|
|
24
|
+
reportedWarningsByHandler.set(handler, reported);
|
|
25
|
+
}
|
|
26
|
+
return reported;
|
|
27
|
+
};
|
|
7
28
|
var DeprecationWarningProvider = (props) => {
|
|
8
29
|
const { children, onWarning } = props;
|
|
30
|
+
const [reportedWarnings] = useState(() => /* @__PURE__ */ new Set());
|
|
9
31
|
return /* @__PURE__ */ jsx(DeprecationWarningContext.Provider, {
|
|
10
32
|
value: onWarning,
|
|
11
|
-
children
|
|
33
|
+
children: /* @__PURE__ */ jsx(ReportedWarningsContext.Provider, {
|
|
34
|
+
value: reportedWarnings,
|
|
35
|
+
children
|
|
36
|
+
})
|
|
12
37
|
});
|
|
13
38
|
};
|
|
14
39
|
var useWarnDeprecation = () => {
|
|
15
40
|
const onWarning = useContext(DeprecationWarningContext);
|
|
16
|
-
const
|
|
41
|
+
const providerReportedWarnings = useContext(ReportedWarningsContext);
|
|
42
|
+
const handlerReportedWarnings = onWarning ? providerReportedWarnings ?? getHandlerReportedWarnings(onWarning) : void 0;
|
|
17
43
|
const pendingWarnings = useRef([]);
|
|
18
44
|
useEffect(() => {
|
|
45
|
+
if (pendingWarnings.current.length === 0) return;
|
|
19
46
|
const warnings = pendingWarnings.current;
|
|
20
47
|
pendingWarnings.current = [];
|
|
21
48
|
for (const message of warnings) {
|
|
22
|
-
|
|
23
|
-
|
|
49
|
+
if (!consoleReportedWarnings.has(message)) {
|
|
50
|
+
consoleReportedWarnings.add(message);
|
|
51
|
+
console.warn(message);
|
|
52
|
+
}
|
|
53
|
+
if (onWarning && !handlerReportedWarnings?.has(message)) {
|
|
54
|
+
handlerReportedWarnings?.add(message);
|
|
55
|
+
onWarning(message);
|
|
56
|
+
}
|
|
24
57
|
}
|
|
25
58
|
});
|
|
26
59
|
return useCallback((message) => {
|
|
27
|
-
if (
|
|
28
|
-
reportedWarnings.current.add(message);
|
|
60
|
+
if (consoleReportedWarnings.has(message) && (handlerReportedWarnings?.has(message) ?? true) || pendingWarnings.current.includes(message)) return;
|
|
29
61
|
pendingWarnings.current.push(message);
|
|
30
|
-
}, []);
|
|
62
|
+
}, [handlerReportedWarnings]);
|
|
31
63
|
};
|
|
32
64
|
//#endregion
|
|
33
65
|
export { DeprecationWarningContext, DeprecationWarningProvider, DeprecationWarningProvider as default, useWarnDeprecation };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeprecationWarningProvider.mjs","names":[],"sources":["../../../../../../../src/components/DeprecationWarningProvider/DeprecationWarningProvider.tsx"],"sourcesContent":["import {\n createContext,\n type FC,\n type PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useRef,\n} from \"react\";\n\nexport type DeprecationWarningHandler = (message: string) => void;\n\nexport interface DeprecationWarningProviderProps extends PropsWithChildren {\n onWarning?: DeprecationWarningHandler;\n}\n\nexport const DeprecationWarningContext = createContext<\n DeprecationWarningHandler | undefined\n>(undefined);\n\nexport const DeprecationWarningProvider: FC<DeprecationWarningProviderProps> = (\n props,\n) => {\n const { children, onWarning } = props;\n\n return (\n <DeprecationWarningContext.Provider value={onWarning}>\n {children}\n </DeprecationWarningContext.Provider>\n );\n};\n\nexport const useWarnDeprecation = () => {\n const onWarning = useContext(DeprecationWarningContext);\n const
|
|
1
|
+
{"version":3,"file":"DeprecationWarningProvider.mjs","names":[],"sources":["../../../../../../../src/components/DeprecationWarningProvider/DeprecationWarningProvider.tsx"],"sourcesContent":["import {\n createContext,\n type FC,\n type PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nexport type DeprecationWarningHandler = (message: string) => void;\n\nexport interface DeprecationWarningProviderProps extends PropsWithChildren {\n onWarning?: DeprecationWarningHandler;\n}\n\nexport const DeprecationWarningContext = createContext<\n DeprecationWarningHandler | undefined\n>(undefined);\n\n/**\n * Messages a provider has passed to its `onWarning`. Held by the provider, not\n * keyed by the handler: an inline `onWarning` is a new function on every\n * render.\n */\nconst ReportedWarningsContext = createContext<Set<string> | undefined>(\n undefined,\n);\n\n/** Messages already written to `console.warn`, across all providers. */\nconst consoleReportedWarnings = new Set<string>();\n\n/**\n * Fallback for a bare `DeprecationWarningContext.Provider`, which has no\n * provider-held set.\n */\nconst reportedWarningsByHandler = new WeakMap<\n DeprecationWarningHandler,\n Set<string>\n>();\n\nconst getHandlerReportedWarnings = (handler: DeprecationWarningHandler) => {\n let reported = reportedWarningsByHandler.get(handler);\n if (!reported) {\n reported = new Set();\n reportedWarningsByHandler.set(handler, reported);\n }\n return reported;\n};\n\nexport const DeprecationWarningProvider: FC<DeprecationWarningProviderProps> = (\n props,\n) => {\n const { children, onWarning } = props;\n const [reportedWarnings] = useState(() => new Set<string>());\n\n return (\n <DeprecationWarningContext.Provider value={onWarning}>\n <ReportedWarningsContext.Provider value={reportedWarnings}>\n {children}\n </ReportedWarningsContext.Provider>\n </DeprecationWarningContext.Provider>\n );\n};\n\nexport const useWarnDeprecation = () => {\n const onWarning = useContext(DeprecationWarningContext);\n const providerReportedWarnings = useContext(ReportedWarningsContext);\n const handlerReportedWarnings = onWarning\n ? (providerReportedWarnings ?? getHandlerReportedWarnings(onWarning))\n : undefined;\n\n const pendingWarnings = useRef<string[]>([]);\n\n useEffect(() => {\n if (pendingWarnings.current.length === 0) {\n return;\n }\n\n const warnings = pendingWarnings.current;\n pendingWarnings.current = [];\n\n for (const message of warnings) {\n if (!consoleReportedWarnings.has(message)) {\n consoleReportedWarnings.add(message);\n console.warn(message);\n }\n if (onWarning && !handlerReportedWarnings?.has(message)) {\n handlerReportedWarnings?.add(message);\n onWarning(message);\n }\n }\n });\n\n return useCallback(\n (message: string) => {\n const isReported =\n consoleReportedWarnings.has(message) &&\n (handlerReportedWarnings?.has(message) ?? true);\n\n if (isReported || pendingWarnings.current.includes(message)) {\n return;\n }\n pendingWarnings.current.push(message);\n },\n [handlerReportedWarnings],\n );\n};\n\nexport default DeprecationWarningProvider;\n"],"mappings":";;;;;AAiBA,IAAa,4BAA4B,cAEvC,KAAA,CAAS;;;;;;AAOX,IAAM,0BAA0B,cAC9B,KAAA,CACF;;AAGA,IAAM,0CAA0B,IAAI,IAAY;;;;;AAMhD,IAAM,4CAA4B,IAAI,QAGpC;AAEF,IAAM,8BAA8B,YAAuC;CACzE,IAAI,WAAW,0BAA0B,IAAI,OAAO;CACpD,IAAI,CAAC,UAAU;EACb,2BAAW,IAAI,IAAI;EACnB,0BAA0B,IAAI,SAAS,QAAQ;CACjD;CACA,OAAO;AACT;AAEA,IAAa,8BACX,UACG;CACH,MAAM,EAAE,UAAU,cAAc;CAChC,MAAM,CAAC,oBAAoB,+BAAe,IAAI,IAAY,CAAC;CAE3D,OACE,oBAAC,0BAA0B,UAA3B;EAAoC,OAAO;EACzC,UAAA,oBAAC,wBAAwB,UAAzB;GAAkC,OAAO;GACtC;EAC+B,CAAA;CACA,CAAA;AAExC;AAEA,IAAa,2BAA2B;CACtC,MAAM,YAAY,WAAW,yBAAyB;CACtD,MAAM,2BAA2B,WAAW,uBAAuB;CACnE,MAAM,0BAA0B,YAC3B,4BAA4B,2BAA2B,SAAS,IACjE,KAAA;CAEJ,MAAM,kBAAkB,OAAiB,CAAC,CAAC;CAE3C,gBAAgB;EACd,IAAI,gBAAgB,QAAQ,WAAW,GACrC;EAGF,MAAM,WAAW,gBAAgB;EACjC,gBAAgB,UAAU,CAAC;EAE3B,KAAK,MAAM,WAAW,UAAU;GAC9B,IAAI,CAAC,wBAAwB,IAAI,OAAO,GAAG;IACzC,wBAAwB,IAAI,OAAO;IACnC,QAAQ,KAAK,OAAO;GACtB;GACA,IAAI,aAAa,CAAC,yBAAyB,IAAI,OAAO,GAAG;IACvD,yBAAyB,IAAI,OAAO;IACpC,UAAU,OAAO;GACnB;EACF;CACF,CAAC;CAED,OAAO,aACJ,YAAoB;EAKnB,IAHE,wBAAwB,IAAI,OAAO,MAClC,yBAAyB,IAAI,OAAO,KAAK,SAE1B,gBAAgB,QAAQ,SAAS,OAAO,GACxD;EAEF,gBAAgB,QAAQ,KAAK,OAAO;CACtC,GACA,CAAC,uBAAuB,CAC1B;AACF"}
|
|
@@ -13,7 +13,7 @@ import { getHeadingLevelWithOffset } from "./lib/getHeadingLevelWithOffset.mjs";
|
|
|
13
13
|
import { isExternalHref } from "./lib/isExternalHref.mjs";
|
|
14
14
|
import { SkeletonBlockText, SkeletonInlineContent } from "./components/SkeletonBlocks.mjs";
|
|
15
15
|
import clsx from "clsx";
|
|
16
|
-
import { Children, isValidElement, useId } from "react";
|
|
16
|
+
import { Children, isValidElement, useId, useMemo } from "react";
|
|
17
17
|
import { jsx } from "react/jsx-runtime";
|
|
18
18
|
import ReactMarkdown from "react-markdown";
|
|
19
19
|
import remarkGfm from "remark-gfm";
|
|
@@ -26,7 +26,7 @@ var Markdown = (props) => {
|
|
|
26
26
|
const { children, color = "default", className, headingOffset = 0, components: customComponents, ref, allowElement, allowedElements, disallowedElements, rehypePlugins, remarkPlugins, remarkRehypeOptions, skipHtml, unwrapDisallowed, urlTransform, ...rest } = props;
|
|
27
27
|
const isSkeleton = useSkeletonMode();
|
|
28
28
|
const clobberPrefix = `user-content-${useId().replace(/[^\w-]/g, "")}-`;
|
|
29
|
-
const defaultComponents = {
|
|
29
|
+
const defaultComponents = useMemo(() => ({
|
|
30
30
|
a: (props) => /* @__PURE__ */ jsx(Link, {
|
|
31
31
|
id: props.id,
|
|
32
32
|
"aria-label": props["aria-label"],
|
|
@@ -115,12 +115,16 @@ var Markdown = (props) => {
|
|
|
115
115
|
color,
|
|
116
116
|
children: /* @__PURE__ */ jsx("blockquote", { children: props.children })
|
|
117
117
|
})
|
|
118
|
-
}
|
|
118
|
+
}), [
|
|
119
|
+
color,
|
|
120
|
+
headingOffset,
|
|
121
|
+
isSkeleton
|
|
122
|
+
]);
|
|
119
123
|
const textContent = extractTextFromFirstChild(children);
|
|
120
|
-
const mergedComponents = {
|
|
124
|
+
const mergedComponents = useMemo(() => ({
|
|
121
125
|
...defaultComponents,
|
|
122
126
|
...customComponents
|
|
123
|
-
};
|
|
127
|
+
}), [defaultComponents, customComponents]);
|
|
124
128
|
return /* @__PURE__ */ jsx("div", {
|
|
125
129
|
className: clsx(Markdown_module_default.markdown, className),
|
|
126
130
|
...rest,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.mjs","names":["styles"],"sources":["../../../../../../../src/components/Markdown/Markdown.tsx"],"sourcesContent":["import { CodeBlock } from \"@/components/CodeBlock\";\nimport { Heading } from \"@/components/Heading\";\nimport { InlineCode } from \"@/components/InlineCode\";\nimport { Link } from \"@/components/Link\";\nimport { Separator } from \"@/components/Separator\";\nimport { Text } from \"@/components/Text\";\nimport type { CSSProperties, FC, Ref } from \"react\";\nimport { Children, isValidElement, useId } from \"react\";\nimport type { Components, Options } from \"react-markdown\";\nimport ReactMarkdown from \"react-markdown\";\nimport styles from \"./Markdown.module.scss\";\nimport { extractTextFromFirstChild } from \"@/lib/react/remote\";\nimport type { AlphaColor, PropsWithClassName } from \"@/lib/types/props\";\nimport clsx from \"clsx\";\nimport remarkGfm from \"remark-gfm\";\nimport { getHeadingLevelWithOffset } from \"@/components/Markdown/lib/getHeadingLevelWithOffset\";\nimport { isExternalHref } from \"@/components/Markdown/lib/isExternalHref\";\nimport type { CodeEditorLanguage } from \"@/components/CodeEditor/languages\";\nimport {\n SkeletonBlockText,\n SkeletonInlineContent,\n} from \"@/components/Markdown/components/SkeletonBlocks\";\nimport { useSkeletonMode } from \"@/components/SkeletonMode/skeletonModeContext\";\n\nexport interface MarkdownProps\n extends PropsWithClassName, Omit<Options, \"components\"> {\n /** The color schema of the markdown component. @default \"default\" */\n color?: \"default\" | AlphaColor;\n /** Shifts all heading levels by the given offset. @default 0 */\n headingOffset?: number;\n /** Allows overriding markdown element renderers from outside. */\n components?: Components;\n /** @internal */\n style?: CSSProperties;\n /** A ref to the elements root. */\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * @flr-generate all\n * @flr-ignore-props components\n */\nexport const Markdown: FC<MarkdownProps> = (props) => {\n const {\n children,\n color = \"default\",\n className,\n headingOffset = 0,\n components: customComponents,\n ref,\n allowElement,\n allowedElements,\n disallowedElements,\n rehypePlugins,\n remarkPlugins,\n remarkRehypeOptions,\n skipHtml,\n unwrapDisallowed,\n urlTransform,\n ...rest\n } = props;\n\n const isSkeleton = useSkeletonMode();\n /* Footnote ids are per document, so two instances on one page would share\n them and a back link would jump into the other one. */\n const clobberPrefix = `user-content-${useId().replace(/[^\\w-]/g, \"\")}-`;\n\n const defaultComponents: Components = {\n /* GFM footnotes link through `id` (the back link's target), `aria-label`\n and `aria-describedby`. */\n a: (props) => (\n <Link\n id={props.id}\n aria-label={props[\"aria-label\"]}\n aria-describedby={props[\"aria-describedby\"]}\n target={isExternalHref(props.href) ? \"_blank\" : undefined}\n color={color}\n href={props.href}\n >\n {props.children}\n </Link>\n ),\n p: (props) => (\n <Text elementType=\"p\" color={color}>\n {props.children}\n </Text>\n ),\n code: (props) => <InlineCode color={color}>{props.children}</InlineCode>,\n h1: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(1, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h2: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(2, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h3: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(3, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h4: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(4, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h5: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(5, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h6: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(6, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n hr: () => <Separator />,\n pre: (props) => {\n const preElementContent = Children.toArray(props.children)[0];\n\n return (\n <CodeBlock\n copyable={false}\n language={\n isValidElement<{ className?: string }>(preElementContent) &&\n preElementContent.props.className\n ? (preElementContent.props.className.replace(\n \"language-\",\n \"\",\n ) as CodeEditorLanguage)\n : undefined\n }\n code={String(\n isValidElement<{ children: string }>(preElementContent)\n ? preElementContent.props.children\n : preElementContent,\n ).trim()}\n />\n );\n },\n ul: ({ node: ignoredNode, ...props }) => (\n <SkeletonBlockText color={color}>\n <ul {...props} />\n </SkeletonBlockText>\n ),\n ol: ({ node: ignoredNode, ...props }) => (\n <SkeletonBlockText color={color}>\n <ol {...props} />\n </SkeletonBlockText>\n ),\n li: ({ node: ignoredNode, children, ...props }) => (\n <li {...props}>\n <SkeletonInlineContent>{children}</SkeletonInlineContent>\n </li>\n ),\n th: ({ node: ignoredNode, children, ...props }) => (\n <th {...props}>\n <SkeletonInlineContent>{children}</SkeletonInlineContent>\n </th>\n ),\n td: ({ node: ignoredNode, children, ...props }) => (\n <td {...props}>\n <SkeletonInlineContent>{children}</SkeletonInlineContent>\n </td>\n ),\n /* A text bar resets the mode for its content, so the image reads it\n from here. A skeleton issues no request. */\n img: ({ node: ignoredNode, ...props }) =>\n isSkeleton ? null : <img {...props} />,\n blockquote: (props) => (\n <SkeletonBlockText color={color}>\n <blockquote>{props.children}</blockquote>\n </SkeletonBlockText>\n ),\n };\n\n const textContent = extractTextFromFirstChild(children);\n const mergedComponents: Components = {\n ...defaultComponents,\n ...customComponents,\n };\n\n return (\n <div className={clsx(styles.markdown, className)} {...rest} ref={ref}>\n <ReactMarkdown\n allowElement={allowElement}\n allowedElements={allowedElements}\n disallowedElements={disallowedElements}\n rehypePlugins={rehypePlugins}\n remarkPlugins={remarkPlugins ?? [remarkGfm]}\n remarkRehypeOptions={{ clobberPrefix, ...remarkRehypeOptions }}\n skipHtml={skipHtml}\n unwrapDisallowed={unwrapDisallowed}\n urlTransform={urlTransform}\n components={mergedComponents}\n >\n {textContent}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Markdown.mjs","names":["styles"],"sources":["../../../../../../../src/components/Markdown/Markdown.tsx"],"sourcesContent":["import { CodeBlock } from \"@/components/CodeBlock\";\nimport { Heading } from \"@/components/Heading\";\nimport { InlineCode } from \"@/components/InlineCode\";\nimport { Link } from \"@/components/Link\";\nimport { Separator } from \"@/components/Separator\";\nimport { Text } from \"@/components/Text\";\nimport type { CSSProperties, FC, Ref } from \"react\";\nimport { Children, isValidElement, useId, useMemo } from \"react\";\nimport type { Components, Options } from \"react-markdown\";\nimport ReactMarkdown from \"react-markdown\";\nimport styles from \"./Markdown.module.scss\";\nimport { extractTextFromFirstChild } from \"@/lib/react/remote\";\nimport type { AlphaColor, PropsWithClassName } from \"@/lib/types/props\";\nimport clsx from \"clsx\";\nimport remarkGfm from \"remark-gfm\";\nimport { getHeadingLevelWithOffset } from \"@/components/Markdown/lib/getHeadingLevelWithOffset\";\nimport { isExternalHref } from \"@/components/Markdown/lib/isExternalHref\";\nimport type { CodeEditorLanguage } from \"@/components/CodeEditor/languages\";\nimport {\n SkeletonBlockText,\n SkeletonInlineContent,\n} from \"@/components/Markdown/components/SkeletonBlocks\";\nimport { useSkeletonMode } from \"@/components/SkeletonMode/skeletonModeContext\";\n\nexport interface MarkdownProps\n extends PropsWithClassName, Omit<Options, \"components\"> {\n /** The color schema of the markdown component. @default \"default\" */\n color?: \"default\" | AlphaColor;\n /** Shifts all heading levels by the given offset. @default 0 */\n headingOffset?: number;\n /** Allows overriding markdown element renderers from outside. */\n components?: Components;\n /** @internal */\n style?: CSSProperties;\n /** A ref to the elements root. */\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * @flr-generate all\n * @flr-ignore-props components\n */\nexport const Markdown: FC<MarkdownProps> = (props) => {\n const {\n children,\n color = \"default\",\n className,\n headingOffset = 0,\n components: customComponents,\n ref,\n allowElement,\n allowedElements,\n disallowedElements,\n rehypePlugins,\n remarkPlugins,\n remarkRehypeOptions,\n skipHtml,\n unwrapDisallowed,\n urlTransform,\n ...rest\n } = props;\n\n const isSkeleton = useSkeletonMode();\n /* Footnote ids are per document, so two instances on one page would share\n them and a back link would jump into the other one. */\n const clobberPrefix = `user-content-${useId().replace(/[^\\w-]/g, \"\")}-`;\n\n /* react-markdown uses the renderers as element types: new ones on every\n render would remount the whole tree. */\n const defaultComponents = useMemo<Components>(\n () => ({\n /* GFM footnotes link through `id` (the back link's target), `aria-label`\n and `aria-describedby`. */\n a: (props) => (\n <Link\n id={props.id}\n aria-label={props[\"aria-label\"]}\n aria-describedby={props[\"aria-describedby\"]}\n target={isExternalHref(props.href) ? \"_blank\" : undefined}\n color={color}\n href={props.href}\n >\n {props.children}\n </Link>\n ),\n p: (props) => (\n <Text elementType=\"p\" color={color}>\n {props.children}\n </Text>\n ),\n code: (props) => <InlineCode color={color}>{props.children}</InlineCode>,\n h1: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(1, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h2: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(2, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h3: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(3, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h4: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(4, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h5: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(5, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n h6: (props) => (\n <Heading\n id={props.id}\n level={getHeadingLevelWithOffset(6, headingOffset)}\n color={color}\n >\n {props.children}\n </Heading>\n ),\n hr: () => <Separator />,\n pre: (props) => {\n const preElementContent = Children.toArray(props.children)[0];\n\n return (\n <CodeBlock\n copyable={false}\n language={\n isValidElement<{ className?: string }>(preElementContent) &&\n preElementContent.props.className\n ? (preElementContent.props.className.replace(\n \"language-\",\n \"\",\n ) as CodeEditorLanguage)\n : undefined\n }\n code={String(\n isValidElement<{ children: string }>(preElementContent)\n ? preElementContent.props.children\n : preElementContent,\n ).trim()}\n />\n );\n },\n ul: ({ node: ignoredNode, ...props }) => (\n <SkeletonBlockText color={color}>\n <ul {...props} />\n </SkeletonBlockText>\n ),\n ol: ({ node: ignoredNode, ...props }) => (\n <SkeletonBlockText color={color}>\n <ol {...props} />\n </SkeletonBlockText>\n ),\n li: ({ node: ignoredNode, children, ...props }) => (\n <li {...props}>\n <SkeletonInlineContent>{children}</SkeletonInlineContent>\n </li>\n ),\n th: ({ node: ignoredNode, children, ...props }) => (\n <th {...props}>\n <SkeletonInlineContent>{children}</SkeletonInlineContent>\n </th>\n ),\n td: ({ node: ignoredNode, children, ...props }) => (\n <td {...props}>\n <SkeletonInlineContent>{children}</SkeletonInlineContent>\n </td>\n ),\n /* A text bar resets the mode for its content, so the image reads it\n from here. A skeleton issues no request. */\n img: ({ node: ignoredNode, ...props }) =>\n isSkeleton ? null : <img {...props} />,\n blockquote: (props) => (\n <SkeletonBlockText color={color}>\n <blockquote>{props.children}</blockquote>\n </SkeletonBlockText>\n ),\n }),\n [color, headingOffset, isSkeleton],\n );\n\n const textContent = extractTextFromFirstChild(children);\n const mergedComponents = useMemo<Components>(\n () => ({\n ...defaultComponents,\n ...customComponents,\n }),\n [defaultComponents, customComponents],\n );\n\n return (\n <div className={clsx(styles.markdown, className)} {...rest} ref={ref}>\n <ReactMarkdown\n allowElement={allowElement}\n allowedElements={allowedElements}\n disallowedElements={disallowedElements}\n rehypePlugins={rehypePlugins}\n remarkPlugins={remarkPlugins ?? [remarkGfm]}\n remarkRehypeOptions={{ clobberPrefix, ...remarkRehypeOptions }}\n skipHtml={skipHtml}\n unwrapDisallowed={unwrapDisallowed}\n urlTransform={urlTransform}\n components={mergedComponents}\n >\n {textContent}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mittwald/flow-react-components",
|
|
3
|
-
"version": "1.6.0-next.
|
|
3
|
+
"version": "1.6.0-next.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A React implementation of Flow, mittwald’s design system",
|
|
6
6
|
"homepage": "https://flow.mittwald.de",
|
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
"@internationalized/string-compiler": "^3.4.1",
|
|
85
85
|
"@lezer/common": "^1.5.2",
|
|
86
86
|
"@lezer/highlight": "^1.2.3",
|
|
87
|
-
"@mittwald/flow-icons": "^1.6.0-next.
|
|
87
|
+
"@mittwald/flow-icons": "^1.6.0-next.23",
|
|
88
88
|
"@mittwald/password-tools-js": "^3.0.0",
|
|
89
|
-
"@mittwald/react-tunnel": "^1.6.0-next.
|
|
89
|
+
"@mittwald/react-tunnel": "^1.6.0-next.23",
|
|
90
90
|
"@mittwald/react-use-promise": "^4.2.2",
|
|
91
91
|
"@react-aria/form": "^3.2.1",
|
|
92
92
|
"@react-aria/i18n": "^3.13.1",
|
|
@@ -139,13 +139,13 @@
|
|
|
139
139
|
"@internationalized/date": "^3.12.3",
|
|
140
140
|
"@lezer/generator": "^1.8.0",
|
|
141
141
|
"@lezer/lr": "^1.4.10",
|
|
142
|
-
"@mittwald/flow-components-base": "1.6.0-next.
|
|
143
|
-
"@mittwald/flow-core": "1.6.0-next.
|
|
144
|
-
"@mittwald/flow-design-tokens": "1.6.0-next.
|
|
145
|
-
"@mittwald/flow-icons-base": "1.6.0-next.
|
|
142
|
+
"@mittwald/flow-components-base": "1.6.0-next.23",
|
|
143
|
+
"@mittwald/flow-core": "1.6.0-next.23",
|
|
144
|
+
"@mittwald/flow-design-tokens": "1.6.0-next.23",
|
|
145
|
+
"@mittwald/flow-icons-base": "1.6.0-next.23",
|
|
146
146
|
"@mittwald/react-use-promise": "^4.2.2",
|
|
147
147
|
"@mittwald/remote-dom-react": "1.2.2-mittwald.10",
|
|
148
|
-
"@mittwald/typescript-config": "1.6.0-next.
|
|
148
|
+
"@mittwald/typescript-config": "1.6.0-next.23",
|
|
149
149
|
"@nx/storybook": "^22.7.6",
|
|
150
150
|
"@storybook/addon-a11y": "^10.5.10",
|
|
151
151
|
"@storybook/addon-actions": "^9.0.8",
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
},
|
|
200
200
|
"peerDependencies": {
|
|
201
201
|
"@internationalized/date": "^3.12.2",
|
|
202
|
-
"@mittwald/flow-icons-pro": "1.6.0-next.
|
|
202
|
+
"@mittwald/flow-icons-pro": "1.6.0-next.23",
|
|
203
203
|
"@mittwald/react-use-promise": "^4.2.2",
|
|
204
204
|
"next": "^16.2.3",
|
|
205
205
|
"react": "^19.2.0",
|
|
@@ -223,5 +223,5 @@
|
|
|
223
223
|
"browserslist": [
|
|
224
224
|
"baseline widely available"
|
|
225
225
|
],
|
|
226
|
-
"gitHead": "
|
|
226
|
+
"gitHead": "782622840cbf82aa1170c6d0bab099f85e63312f"
|
|
227
227
|
}
|