@mittwald/flow-react-components 1.6.0-next.54 → 1.6.0-next.55
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.
|
@@ -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, 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, "");
|
|
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, editable = 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();
|
|
@@ -116,6 +116,7 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
|
116
116
|
});
|
|
117
117
|
const stableOnChange = useCallback((value) => handlersRef.current.onChange(value), []);
|
|
118
118
|
const stableOnStatistics = useCallback((statistics) => handlersRef.current.onStatistics?.(statistics), []);
|
|
119
|
+
const isEditable = editable && !isDisabled;
|
|
119
120
|
const highlightActiveLine = showActiveLineMarker && !isDisabled;
|
|
120
121
|
const basicSetup = useMemo(() => ({
|
|
121
122
|
highlightActiveLine,
|
|
@@ -123,8 +124,9 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
|
123
124
|
autocompletion: false,
|
|
124
125
|
lineNumbers: false,
|
|
125
126
|
foldGutter: false,
|
|
126
|
-
highlightSelectionMatches: false
|
|
127
|
-
|
|
127
|
+
highlightSelectionMatches: false,
|
|
128
|
+
bracketMatching: isEditable
|
|
129
|
+
}), [highlightActiveLine, isEditable]);
|
|
128
130
|
const localRef = useObjectRef(ref);
|
|
129
131
|
useMakeFocusable(localRef);
|
|
130
132
|
const isSkeleton = useSkeletonMode();
|
|
@@ -146,7 +148,7 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
|
|
|
146
148
|
"data-invalid": isInvalid || void 0,
|
|
147
149
|
"data-disabled": isDisabled || void 0,
|
|
148
150
|
readOnly: isReadOnly || isDisabled,
|
|
149
|
-
editable:
|
|
151
|
+
editable: isEditable,
|
|
150
152
|
className: clsx(CodeEditor_module_default.codeMirror, isReadOnly && CodeEditor_module_default.readonly),
|
|
151
153
|
ref: (codeMirrorRef) => {
|
|
152
154
|
if (codeMirrorRef?.editor) localRef.current = codeMirrorRef.editor;
|
|
@@ -1 +1 @@
|
|
|
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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"}
|
|
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 editable = 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 isEditable = editable && !isDisabled;\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 bracketMatching: isEditable,\n }),\n [highlightActiveLine, isEditable],\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={isEditable}\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":";;;;;;;;;;;;;;;;;;;;;;;AAwFA,IAAa,aAAa,cAAc,eAAe,UAAU;CAC/D,MAAM,EACJ,KACA,UACA,WACA,UACA,YACA,YACA,YACA,WACA,YACA,oBAAoB,4BACpB,OACA,UACA,cACA,kBAAkB,MAClB,kBAAkB,MAClB,4BAA4B,MAC5B,oBAAoB,MACpB,uBAAuB,MACvB,WAAW,MACX,WAAW,MACX,QACA,WACA,cAAc,WACd,mBAAmB,gBACnB,GAAG,SACD,4BAA4B,OAAO,EAAE;CAEzC,MAAM,EACJ,gBACA,0BACA,cACA,cACA,sBACE,kBAAkB,OAAO,YAAY;CAEzC,MAAM,gBAAgB,KACpB,aAAa,WACbA,0BAAO,YACP,SACF;CAEA,MAAM,UAAU,MAAM;CACtB,MAAM,gBAAgB,MAAM;;;;;;;CAQ5B,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK;CAC9C,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,KAAK;CAC1D,MAAM,WAAW,aAAa,YAA4B;EACxD,YAAY,CAAC,CAAC,OAAO;CACvB,GAAG,CAAC,CAAC;CACL,MAAM,iBAAiB,aAAa,YAA4B;EAC9D,kBAAkB,CAAC,CAAC,OAAO;CAC7B,GAAG,CAAC,CAAC;;;;;;;CAQL,MAAM,eAA6B;EACjC,GAAG;EACH,OAAO;GACL,GAAG,kBAAkB;GACrB,IAAI;GACJ,KAAK;GACL,QAAQ;IAAE,IAAI;IAAS,WAAW;GAAa;EACjD;EACA,kBAAkB;GAChB,GAAG,kBAAkB;GACrB,IAAI;GACJ,KAAK;GACL,QAAQ;IAAE,IAAI;IAAoB,WAAW;GAAa;EAC5D;CACF;CAEA,MAAM,oBAAoB,wBAAwB,UAAU,YAAY;EACrD;EACU;EACV;EACE;CACrB,CAAC;;;;;;;;CASD,MAAM,aAAa,QAAQ,gBAAgB,YAAY,OAAO;CAC9D,MAAM,cAAc,QAClB,kBAAkB,eAClB,aAAa,mBACf;;;;;;CAOA,MAAM,gBAAgB,cACd,CACJ,GAAG,mBACH,WAAW,kBAAkB,GAAG;EAC9B,GAAI,aAAa,EAAE,mBAAmB,WAAW,IAAI,CAAC;EACtD,GAAI,YAAY,EAAE,cAAc,UAAU,IAAI,CAAC;EAC/C,GAAI,cAAc,EAAE,oBAAoB,YAAY,IAAI,CAAC;EACzD,GAAI,aAAa,EAAE,iBAAiB,OAAO,IAAI,CAAC;EAChD,GAAI,YAAY,EAAE,gBAAgB,OAAO,IAAI,CAAC;EAC9C,GAAI,aAAa,EAAE,iBAAiB,OAAO,IAAI,CAAC;CAClD,CAAC,CACH,GACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAOA,MAAM,cAAc,OAAO;EAAE;EAAU;CAAa,CAAC;CACrD,sBAAsB;EACpB,YAAY,UAAU;GAAE;GAAU;EAAa;CACjD,CAAC;CACD,MAAM,iBAAiB,aACpB,UAAkB,YAAY,QAAQ,SAAS,KAAK,GACrD,CAAC,CACH;CACA,MAAM,qBAAqB,aACxB,eAA2B,YAAY,QAAQ,eAAe,UAAU,GACzE,CAAC,CACH;CAEA,MAAM,aAAa,YAAY,CAAC;CAChC,MAAM,sBAAsB,wBAAwB,CAAC;CACrD,MAAM,aAAa,eACV;EACL;EACA,2BAA2B;EAC3B,gBAAgB;EAChB,aAAa;EACb,YAAY;EACZ,2BAA2B;EAC3B,iBAAiB;CACnB,IACA,CAAC,qBAAqB,UAAU,CAClC;CAEA,MAAM,WAAW,aAAa,GAAG;CAEjC,iBAAiB,QAAQ;CAEzB,MAAM,aAAa,gBAAgB;CAKnC,MAAM,WACJ,qBAAC,OAAD;EACE,WAAW,KACTA,0BAAO,YACP,cAAcA,0BAAO,UACrBA,0BAAO,QACT;EALF,UAAA,CAOE,oBAAC,OAAD;GACE,WAAWA,0BAAO;GAClB,OAAO,EAAE,QAAQ,UAAU,UAAU;GAEnC,WAAA,SAAS,GAAA,CAAI,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,UACpC,oBAAC,OAAD,EAAA,UAAkB,QAAQ,IAAS,GAAzB,KAAyB,CACpC;EACE,CAAA,GACJ,QACE;;CAGP,MAAM,SACJ,qBAAC,YAAD;EACE,GAAI;EACG;EACP,UAAU;EACV,cAAc;EACF;EACZ,OAAO;EACP,gBAAc,aAAa,KAAA;EAC3B,iBAAe,cAAc,KAAA;EAC7B,UAAU,cAAc;EACxB,UAAU;EACV,WAAW,KAAKA,0BAAO,YAAY,cAAcA,0BAAO,QAAQ;EAChE,MAAM,kBAAkB;GACtB,IAAI,eAAe,QACjB,SAAS,UAAU,cAAc;EAErC;EACA,YAAY;EACZ,QAAQ,UAAU;EAlBpB,UAAA,CAoBG,YACC,oBAAC,YAAD;GACE,WAAWA,0BAAO;GAClB,MAAK;GACL,SAAQ;GACR,MAAM;GACM;EACb,CAAA,GAEF,QACS;;CAGd,OACE,oBAAC,OAAD;EACE,WAAW;EACX,iBAAe,cAAc,KAAA;EAC7B,OAAO,cAAc,KAAA;EAErB,UAAA,qBAAC,sBAAD;GAAsB,OAAO;GAA7B,UAAA;IACE,oBAAC,uBAAD;KAAuB,IAAG;KAAQ,WAAU;IAAc,CAAA;IAC1D,oBAAC,0BAAD,EAAA,UACG,aAAa,WAAW,OACD,CAAA;IAC1B,oBAAC,uBAAD;KAAuB,IAAG;KAAmB,WAAU;IAAc,CAAA;IACrE,oBAAC,gBAAD,CAAiB,CAAA;GACG;;CACnB,CAAA;AAET,CAAC"}
|
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.55",
|
|
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.55",
|
|
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.55",
|
|
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.55",
|
|
143
|
+
"@mittwald/flow-core": "1.6.0-next.55",
|
|
144
|
+
"@mittwald/flow-design-tokens": "1.6.0-next.55",
|
|
145
|
+
"@mittwald/flow-icons-base": "1.6.0-next.55",
|
|
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.55",
|
|
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.55",
|
|
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": "7e70bf2d15f59f627ab74cdaedc1e7fecfb2c746"
|
|
227
227
|
}
|