@mittwald/flow-react-components 1.5.0-next.25 → 1.5.0-next.27

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.
@@ -21,7 +21,7 @@ import CodeMirror, { EditorView } from "@uiw/react-codemirror";
21
21
  * @flowStatus new
22
22
  */
23
23
  var CodeEditor = flowComponent("CodeEditor", (props) => {
24
- const { ref, children, className, language, extensions, isReadOnly, 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, "");
24
+ 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
25
  const { FieldErrorView, FieldErrorCaptureContext, wrapperProps, controlProps, fieldPropsContext } = useFieldComponent(props, "CodeEditor");
26
26
  const rootClassName = clsx(wrapperProps.className, CodeEditor_module_default.codeEditor, className);
27
27
  const labelId = useId();
@@ -87,12 +87,14 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
87
87
  ...ariaLabel ? { "aria-label": ariaLabel } : {},
88
88
  ...describedBy ? { "aria-describedby": describedBy } : {},
89
89
  ...isRequired ? { "aria-required": "true" } : {},
90
- ...isInvalid ? { "aria-invalid": "true" } : {}
90
+ ...isInvalid ? { "aria-invalid": "true" } : {},
91
+ ...isDisabled ? { "aria-disabled": "true" } : {}
91
92
  });
92
93
  const localRef = useObjectRef(ref);
93
94
  useMakeFocusable(localRef);
94
95
  return /* @__PURE__ */ jsx("div", {
95
96
  className: rootClassName,
97
+ "data-disabled": isDisabled || void 0,
96
98
  children: /* @__PURE__ */ jsxs(PropsContextProvider, {
97
99
  props: propsContext,
98
100
  children: [
@@ -104,8 +106,8 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
104
106
  ...rest,
105
107
  value,
106
108
  basicSetup: {
107
- highlightActiveLine: showActiveLineMarker,
108
- highlightActiveLineGutter: showActiveLineMarker,
109
+ highlightActiveLine: showActiveLineMarker && !isDisabled,
110
+ highlightActiveLineGutter: showActiveLineMarker && !isDisabled,
109
111
  autocompletion: false,
110
112
  lineNumbers: false,
111
113
  foldGutter: false,
@@ -113,7 +115,9 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
113
115
  },
114
116
  theme: defaultLightTheme,
115
117
  "data-invalid": isInvalid || void 0,
116
- readOnly: isReadOnly,
118
+ "data-disabled": isDisabled || void 0,
119
+ readOnly: isReadOnly || isDisabled,
120
+ editable: !isDisabled,
117
121
  className: clsx(CodeEditor_module_default.codeMirror, isReadOnly && CodeEditor_module_default.readonly),
118
122
  ref: (codeMirrorRef) => {
119
123
  if (codeMirrorRef?.editor) localRef.current = codeMirrorRef.editor;
@@ -124,7 +128,8 @@ var CodeEditor = flowComponent("CodeEditor", (props) => {
124
128
  className: CodeEditor_module_default.copyButton,
125
129
  size: "s",
126
130
  variant: "soft",
127
- text: value
131
+ text: value,
132
+ isDisabled
128
133
  }), children]
129
134
  }) }),
130
135
  /* @__PURE__ */ jsx(UiComponentTunnelExit, {
@@ -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\";\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 displayed as invalid.\n *\n * @default false\n */\n isInvalid?: boolean;\n /** The elements class name. */\n className?: string;\n /** The language the code is highlighted as. */\n language?: CodeEditorLanguage;\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 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 });\n\n const localRef = useObjectRef(ref);\n\n useMakeFocusable(localRef);\n\n return (\n <div className={rootClassName}>\n <PropsContextProvider props={propsContext}>\n <UiComponentTunnelExit id=\"label\" component=\"CodeEditor\" />\n <FieldErrorCaptureContext>\n <CodeMirror\n {...rest}\n value={value}\n basicSetup={{\n highlightActiveLine: showActiveLineMarker,\n highlightActiveLineGutter: showActiveLineMarker,\n autocompletion: false,\n lineNumbers: false,\n foldGutter: false,\n highlightSelectionMatches: false,\n }}\n theme={defaultLightTheme}\n data-invalid={isInvalid || undefined}\n readOnly={isReadOnly}\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 />\n )}\n {children}\n </CodeMirror>\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 } 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\";\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 /** The language the code is highlighted as. */\n language?: CodeEditorLanguage;\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 return (\n <div className={rootClassName} data-disabled={isDisabled || undefined}>\n <PropsContextProvider props={propsContext}>\n <UiComponentTunnelExit id=\"label\" component=\"CodeEditor\" />\n <FieldErrorCaptureContext>\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 </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 +1 @@
1
- {"version":3,"file":"CodeEditor.module.mjs","names":[],"sources":["../../../../../../../src/components/CodeEditor/CodeEditor.module.scss"],"sourcesContent":["@use \"@/styles/mixins/formControl\";\n@use \"@/styles/mixins/scrollbar\";\n\n.codeEditor {\n outline: none;\n isolation: isolate;\n\n .codeMirror {\n @include formControl.formControl();\n\n position: relative;\n order: 2;\n\n /*\n * The inline padding is applied by the lines and the gutter instead, so\n * that the highlight of the active line spans the full editor width.\n */\n padding-inline: unset;\n\n /* the vertical padding applied by the form control mixin */\n --editor-padding: calc(\n var(--form-control--padding-y) - var(--form-control--border-width)\n );\n\n min-height: calc(var(--form-control--padding-y) * 2 + var(--line-height-m));\n\n &:hover {\n background-color: var(--form-control--background-color--default);\n }\n\n &.readonly {\n border-color: var(--form-control--border-color--default);\n }\n\n .copyButton {\n position: absolute;\n inset-block-start: var(--editor-padding);\n inset-inline-end: var(--form-control--padding-x);\n z-index: 1;\n }\n }\n}\n\n/*\n * CodeMirror ships its theme as unlayered `<style>` elements that it injects\n * into the document at runtime, outside of Flow's build. Unlayered CSS beats\n * layered CSS regardless of specificity, so these overrides only apply in the\n * layered stylesheet variant if they leave the cascade layer as well.\n */\n@layer flow.unlayered {\n .codeEditor .codeMirror {\n /*\n * The gutter needs an opaque background – the content scrolls underneath\n * it – but it must follow the background of the editor, which changes with\n * its state (invalid, disabled, …). Inheriting it down from the editor\n * beats the background the CodeMirror theme applies, which only serves as\n * a fallback.\n */\n & :global(.cm-editor),\n & :global(.cm-scroller),\n & :global(.cm-gutters) {\n background-color: inherit;\n }\n\n & :global(.cm-editor) {\n outline: none;\n\n & :global(.cm-scroller) {\n @include scrollbar.scrollbar;\n }\n\n & :global(.cm-lineNumbers .cm-gutterElement) {\n min-width: var(--code-editor--gutter-element-min-width);\n }\n\n & :global(.cm-foldGutter) {\n min-width: var(--code-editor--gutter-element-min-width);\n text-align: center;\n }\n\n & :global(.cm-panels) {\n display: none;\n }\n\n /* the block padding is applied by the editor itself */\n & :global(.cm-content) {\n padding-block: unset;\n }\n\n & :global(.cm-line) {\n padding-inline: var(--form-control--padding-x);\n }\n\n /*\n * The elements of the first gutter carry the inline start padding, so\n * that the highlight of the active line reaches the editor border.\n */\n & :global(.cm-gutters > .cm-gutter:first-child .cm-gutterElement) {\n padding-inline-start: var(--form-control--padding-x);\n }\n\n & :global(.cm-activeLineGutter),\n & :global(.cm-activeLine) {\n background-color: color-mix(\n in srgb,\n var(--form-control--background-color--hover) 65%,\n transparent\n );\n }\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"CodeEditor.module.mjs","names":[],"sources":["../../../../../../../src/components/CodeEditor/CodeEditor.module.scss"],"sourcesContent":["@use \"@/styles/mixins/formControl\";\n@use \"@/styles/mixins/scrollbar\";\n\n.codeEditor {\n outline: none;\n isolation: isolate;\n\n .codeMirror {\n @include formControl.formControl();\n\n position: relative;\n order: 2;\n\n /*\n * The inline padding is applied by the lines and the gutter instead, so\n * that the highlight of the active line spans the full editor width.\n */\n padding-inline: unset;\n\n /* the vertical padding applied by the form control mixin */\n --editor-padding: calc(\n var(--form-control--padding-y) - var(--form-control--border-width)\n );\n\n min-height: calc(var(--form-control--padding-y) * 2 + var(--line-height-m));\n\n &:hover {\n background-color: var(--form-control--background-color--default);\n }\n\n &.readonly {\n border-color: var(--form-control--border-color--default);\n }\n\n &[data-disabled] {\n --code-editor--gutter-separator-color: var(\n --form-control--border-color--disabled\n );\n --code-editor--indentation-marker-color: var(\n --form-control--border-color--disabled\n );\n\n background-color: var(--form-control--background-color--disabled);\n }\n\n .copyButton {\n position: absolute;\n inset-block-start: var(--editor-padding);\n inset-inline-end: var(--form-control--padding-x);\n z-index: 1;\n }\n }\n}\n\n/*\n * CodeMirror ships its theme as unlayered `<style>` elements that it injects\n * into the document at runtime, outside of Flow's build. Unlayered CSS beats\n * layered CSS regardless of specificity, so these overrides only apply in the\n * layered stylesheet variant if they leave the cascade layer as well.\n */\n@layer flow.unlayered {\n .codeEditor .codeMirror {\n /*\n * The gutter needs an opaque background – the content scrolls underneath\n * it – but it must follow the background of the editor, which changes with\n * its state (invalid, disabled, …). Inheriting it down from the editor\n * beats the background the CodeMirror theme applies, which only serves as\n * a fallback.\n */\n & :global(.cm-editor),\n & :global(.cm-scroller),\n & :global(.cm-gutters) {\n background-color: inherit;\n }\n\n /* The same goes for the text color of the code and the line numbers. */\n & :global(.cm-editor),\n & :global(.cm-gutters) {\n color: inherit;\n }\n\n /* Syntax highlighting would make disabled code look editable. */\n &[data-disabled] :global(.cm-content *) {\n color: inherit;\n }\n\n & :global(.cm-editor) {\n outline: none;\n\n & :global(.cm-scroller) {\n @include scrollbar.scrollbar;\n }\n\n & :global(.cm-lineNumbers .cm-gutterElement) {\n min-width: var(--code-editor--gutter-element-min-width);\n }\n\n & :global(.cm-foldGutter) {\n min-width: var(--code-editor--gutter-element-min-width);\n text-align: center;\n }\n\n & :global(.cm-panels) {\n display: none;\n }\n\n /* the block padding is applied by the editor itself */\n & :global(.cm-content) {\n padding-block: unset;\n }\n\n & :global(.cm-line) {\n padding-inline: var(--form-control--padding-x);\n }\n\n /*\n * The elements of the first gutter carry the inline start padding, so\n * that the highlight of the active line reaches the editor border.\n */\n & :global(.cm-gutters > .cm-gutter:first-child .cm-gutterElement) {\n padding-inline-start: var(--form-control--padding-x);\n }\n\n & :global(.cm-activeLineGutter),\n & :global(.cm-activeLine) {\n background-color: color-mix(\n in srgb,\n var(--form-control--background-color--hover) 65%,\n transparent\n );\n }\n }\n }\n}\n"],"mappings":""}
@@ -17,9 +17,14 @@ var overlayContainerAttribute = "data-flow-overlays";
17
17
  * blurs a focused field inside it (#3268). The same heuristic also spares
18
18
  * custom elements and shadow hosts the page itself appends, which then render
19
19
  * above open overlays.
20
+ *
21
+ * Hidden nodes don't count either: react-aria appends a `display: none`
22
+ * description node whenever a DatePicker's value changes, and moving the
23
+ * container for it on every keystroke resets the segment being typed into.
20
24
  */
25
+ var isHiddenNode = (node) => node instanceof HTMLElement && (node.hidden === true || node.style.display === "none");
21
26
  var isCoveredByPageContent = (container) => {
22
- for (let node = container.nextElementSibling; node; node = node.nextElementSibling) if (!isBrowserExtensionNode(node)) return true;
27
+ for (let node = container.nextElementSibling; node; node = node.nextElementSibling) if (!isBrowserExtensionNode(node) && !isHiddenNode(node)) return true;
23
28
  return false;
24
29
  };
25
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayContent.mjs","names":["styles"],"sources":["../../../../../../../../src/components/Overlay/components/OverlayContent.tsx"],"sourcesContent":["import * as Aria from \"react-aria-components\";\nimport { type FC, type PropsWithChildren, type Ref, Suspense } from \"react\";\nimport { UNSAFE_PortalProvider } from \"react-aria\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport { OverlaySuspenseFallback } from \"@/components/Overlay/components/OverlaySuspenseFallback\";\nimport styles from \"../Overlay.module.scss\";\nimport DivView from \"@/views/DivView\";\nimport {\n isBrowserExtensionNode,\n useKeepBrowserExtensionsInteractive,\n} from \"@/lib/hooks/dom/useKeepBrowserExtensionsInteractive\";\nimport { useIsActivityActive } from \"@/components/Activity/context\";\n\nconst overlayContainerAttribute = \"data-flow-overlays\";\n\n/**\n * Nodes a browser extension appends (e.g. 1Password's inline menu) don't count\n * as covering: they belong on top anyway, and moving the container for them\n * blurs a focused field inside it (#3268). The same heuristic also spares\n * custom elements and shadow hosts the page itself appends, which then render\n * above open overlays.\n */\nconst isCoveredByPageContent = (container: HTMLElement): boolean => {\n for (\n let node = container.nextElementSibling;\n node;\n node = node.nextElementSibling\n ) {\n if (!isBrowserExtensionNode(node)) {\n return true;\n }\n }\n return false;\n};\n\n/**\n * Only the container moves, never the nodes appended after it: those are\n * foreign, and moving them costs state we cannot restore (an iframe reloads).\n * The container's own state we can. Moving a node blurs the focused element\n * inside it and resets every scroll container inside to the top. `moveBefore`\n * keeps the focus (and, in Chromium, the scroll positions); the rest is\n * restored afterwards.\n */\nconst moveToEnd = (container: HTMLElement): void => {\n const body = document.body;\n const focused = document.activeElement;\n const scrolled = Array.from(container.querySelectorAll<HTMLElement>(\"*\"))\n .filter((element) => element.scrollTop !== 0 || element.scrollLeft !== 0)\n .map(\n (element) => [element, element.scrollTop, element.scrollLeft] as const,\n );\n\n if (typeof body.moveBefore === \"function\") {\n body.moveBefore(container, null);\n } else {\n body.append(container);\n }\n\n for (const [element, scrollTop, scrollLeft] of scrolled) {\n element.scrollTop = scrollTop;\n element.scrollLeft = scrollLeft;\n }\n if (\n focused instanceof HTMLElement &&\n container.contains(focused) &&\n document.activeElement !== focused\n ) {\n focused.focus({ preventScroll: true });\n }\n};\n\n/**\n * Render overlays into a dedicated container instead of `document.body`.\n *\n * React Aria `FocusScope` relies on nearby sibling nodes (sentinels + overlay).\n * Browser extensions (e.g. password managers) inject/reorder `body` children,\n * which can separate those nodes. Then focus scope detection breaks and may\n * cause recursive focus restoration.\n *\n * Keep the overlay container as the last child of body.\n *\n * React Aria normally portals overlays directly into body, so they are appended\n * last and render on top.\n *\n * If we create one persistent container only once, anything appended to body\n * later (toasts, third-party widgets, remounted app root) can render above open\n * overlays. Then overlays can appear behind page content, and the backdrop blur\n * no longer covers the page.\n */\nconst getOverlayContainer = (): HTMLElement | null => {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n const existingContainer = document.querySelector<HTMLElement>(\n `body > [${overlayContainerAttribute}]`,\n );\n\n if (existingContainer) {\n if (isCoveredByPageContent(existingContainer)) {\n moveToEnd(existingContainer);\n }\n return existingContainer;\n }\n\n const container = document.createElement(\"div\");\n container.setAttribute(overlayContainerAttribute, \"\");\n document.body.append(container);\n\n return container;\n};\n\nexport interface OverlayContentProps\n extends\n PropsWithChildren,\n PropsWithClassName,\n Pick<Aria.DialogProps, \"aria-labelledby\"> {\n ref?: Ref<HTMLDivElement>;\n onOpenChange: (isOpen: boolean) => void;\n isDismissable?: boolean;\n isOpen?: boolean;\n}\n\n/** @flr-generate all */\nexport const OverlayContent: FC<OverlayContentProps> = (props) => {\n const {\n children,\n className,\n \"aria-labelledby\": ariaLabelledBy,\n ...restProps\n } = props;\n\n const isActivityActive = useIsActivityActive();\n\n useKeepBrowserExtensionsInteractive(restProps.isOpen ?? false);\n\n const Fallback = () => {\n return (\n <DivView className={styles.suspense}>\n <OverlaySuspenseFallback {...restProps} />\n </DivView>\n );\n };\n\n if (!isActivityActive) {\n return null;\n }\n\n return (\n <UNSAFE_PortalProvider getContainer={getOverlayContainer}>\n <Aria.ModalOverlay {...restProps} className={className}>\n {/* The centering viewport between the backdrop and react-aria's modal\n wrapper. Classed so Modal/OffCanvas/LightBox can position it\n without selecting a bare `div`. */}\n <DivView className={styles.viewport}>\n <Aria.Modal>\n <Suspense fallback={<Fallback />}>\n <Aria.Dialog aria-labelledby={ariaLabelledBy}>\n {children}\n </Aria.Dialog>\n </Suspense>\n </Aria.Modal>\n </DivView>\n </Aria.ModalOverlay>\n </UNSAFE_PortalProvider>\n );\n};\n\nexport default OverlayContent;\n"],"mappings":";;;;;;;;;;;;AAaA,IAAM,4BAA4B;;;;;;;;AASlC,IAAM,0BAA0B,cAAoC;CAClE,KACE,IAAI,OAAO,UAAU,oBACrB,MACA,OAAO,KAAK,oBAEZ,IAAI,CAAC,uBAAuB,IAAI,GAC9B,OAAO;CAGX,OAAO;AACT;;;;;;;;;AAUA,IAAM,aAAa,cAAiC;CAClD,MAAM,OAAO,SAAS;CACtB,MAAM,UAAU,SAAS;CACzB,MAAM,WAAW,MAAM,KAAK,UAAU,iBAA8B,GAAG,CAAC,CAAC,CACtE,QAAQ,YAAY,QAAQ,cAAc,KAAK,QAAQ,eAAe,CAAC,CAAC,CACxE,KACE,YAAY;EAAC;EAAS,QAAQ;EAAW,QAAQ;CAAU,CAC9D;CAEF,IAAI,OAAO,KAAK,eAAe,YAC7B,KAAK,WAAW,WAAW,IAAI;MAE/B,KAAK,OAAO,SAAS;CAGvB,KAAK,MAAM,CAAC,SAAS,WAAW,eAAe,UAAU;EACvD,QAAQ,YAAY;EACpB,QAAQ,aAAa;CACvB;CACA,IACE,mBAAmB,eACnB,UAAU,SAAS,OAAO,KAC1B,SAAS,kBAAkB,SAE3B,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;AAoBA,IAAM,4BAAgD;CACpD,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,MAAM,oBAAoB,SAAS,cACjC,WAAW,0BAA0B,EACvC;CAEA,IAAI,mBAAmB;EACrB,IAAI,uBAAuB,iBAAiB,GAC1C,UAAU,iBAAiB;EAE7B,OAAO;CACT;CAEA,MAAM,YAAY,SAAS,cAAc,KAAK;CAC9C,UAAU,aAAa,2BAA2B,EAAE;CACpD,SAAS,KAAK,OAAO,SAAS;CAE9B,OAAO;AACT;;AAcA,IAAa,kBAA2C,UAAU;CAChE,MAAM,EACJ,UACA,WACA,mBAAmB,gBACnB,GAAG,cACD;CAEJ,MAAM,mBAAmB,oBAAoB;CAE7C,oCAAoC,UAAU,UAAU,KAAK;CAE7D,MAAM,iBAAiB;EACrB,OACE,oBAAC,SAAD;GAAS,WAAWA,uBAAO;GACzB,UAAA,oBAAC,yBAAD,EAAyB,GAAI,UAAY,CAAA;EAClC,CAAA;CAEb;CAEA,IAAI,CAAC,kBACH,OAAO;CAGT,OACE,oBAAC,uBAAD;EAAuB,cAAc;EACnC,UAAA,oBAAC,KAAK,cAAN;GAAmB,GAAI;GAAsB;GAI3C,UAAA,oBAAC,SAAD;IAAS,WAAWA,uBAAO;IACzB,UAAA,oBAAC,KAAK,OAAN,EAAA,UACE,oBAAC,UAAD;KAAU,UAAU,oBAAC,UAAD,CAAW,CAAA;KAC7B,UAAA,oBAAC,KAAK,QAAN;MAAa,mBAAiB;MAC3B;KACU,CAAA;IACL,CAAA,EACA,CAAA;GACL,CAAA;EACQ,CAAA;CACE,CAAA;AAE3B"}
1
+ {"version":3,"file":"OverlayContent.mjs","names":["styles"],"sources":["../../../../../../../../src/components/Overlay/components/OverlayContent.tsx"],"sourcesContent":["import * as Aria from \"react-aria-components\";\nimport { type FC, type PropsWithChildren, type Ref, Suspense } from \"react\";\nimport { UNSAFE_PortalProvider } from \"react-aria\";\nimport type { PropsWithClassName } from \"@/lib/types/props\";\nimport { OverlaySuspenseFallback } from \"@/components/Overlay/components/OverlaySuspenseFallback\";\nimport styles from \"../Overlay.module.scss\";\nimport DivView from \"@/views/DivView\";\nimport {\n isBrowserExtensionNode,\n useKeepBrowserExtensionsInteractive,\n} from \"@/lib/hooks/dom/useKeepBrowserExtensionsInteractive\";\nimport { useIsActivityActive } from \"@/components/Activity/context\";\n\nconst overlayContainerAttribute = \"data-flow-overlays\";\n\n/**\n * Nodes a browser extension appends (e.g. 1Password's inline menu) don't count\n * as covering: they belong on top anyway, and moving the container for them\n * blurs a focused field inside it (#3268). The same heuristic also spares\n * custom elements and shadow hosts the page itself appends, which then render\n * above open overlays.\n *\n * Hidden nodes don't count either: react-aria appends a `display: none`\n * description node whenever a DatePicker's value changes, and moving the\n * container for it on every keystroke resets the segment being typed into.\n */\nconst isHiddenNode = (node: Element): boolean =>\n node instanceof HTMLElement &&\n (node.hidden === true || node.style.display === \"none\");\n\nconst isCoveredByPageContent = (container: HTMLElement): boolean => {\n for (\n let node = container.nextElementSibling;\n node;\n node = node.nextElementSibling\n ) {\n if (!isBrowserExtensionNode(node) && !isHiddenNode(node)) {\n return true;\n }\n }\n return false;\n};\n\n/**\n * Only the container moves, never the nodes appended after it: those are\n * foreign, and moving them costs state we cannot restore (an iframe reloads).\n * The container's own state we can. Moving a node blurs the focused element\n * inside it and resets every scroll container inside to the top. `moveBefore`\n * keeps the focus (and, in Chromium, the scroll positions); the rest is\n * restored afterwards.\n */\nconst moveToEnd = (container: HTMLElement): void => {\n const body = document.body;\n const focused = document.activeElement;\n const scrolled = Array.from(container.querySelectorAll<HTMLElement>(\"*\"))\n .filter((element) => element.scrollTop !== 0 || element.scrollLeft !== 0)\n .map(\n (element) => [element, element.scrollTop, element.scrollLeft] as const,\n );\n\n if (typeof body.moveBefore === \"function\") {\n body.moveBefore(container, null);\n } else {\n body.append(container);\n }\n\n for (const [element, scrollTop, scrollLeft] of scrolled) {\n element.scrollTop = scrollTop;\n element.scrollLeft = scrollLeft;\n }\n if (\n focused instanceof HTMLElement &&\n container.contains(focused) &&\n document.activeElement !== focused\n ) {\n focused.focus({ preventScroll: true });\n }\n};\n\n/**\n * Render overlays into a dedicated container instead of `document.body`.\n *\n * React Aria `FocusScope` relies on nearby sibling nodes (sentinels + overlay).\n * Browser extensions (e.g. password managers) inject/reorder `body` children,\n * which can separate those nodes. Then focus scope detection breaks and may\n * cause recursive focus restoration.\n *\n * Keep the overlay container as the last child of body.\n *\n * React Aria normally portals overlays directly into body, so they are appended\n * last and render on top.\n *\n * If we create one persistent container only once, anything appended to body\n * later (toasts, third-party widgets, remounted app root) can render above open\n * overlays. Then overlays can appear behind page content, and the backdrop blur\n * no longer covers the page.\n */\nconst getOverlayContainer = (): HTMLElement | null => {\n if (typeof document === \"undefined\") {\n return null;\n }\n\n const existingContainer = document.querySelector<HTMLElement>(\n `body > [${overlayContainerAttribute}]`,\n );\n\n if (existingContainer) {\n if (isCoveredByPageContent(existingContainer)) {\n moveToEnd(existingContainer);\n }\n return existingContainer;\n }\n\n const container = document.createElement(\"div\");\n container.setAttribute(overlayContainerAttribute, \"\");\n document.body.append(container);\n\n return container;\n};\n\nexport interface OverlayContentProps\n extends\n PropsWithChildren,\n PropsWithClassName,\n Pick<Aria.DialogProps, \"aria-labelledby\"> {\n ref?: Ref<HTMLDivElement>;\n onOpenChange: (isOpen: boolean) => void;\n isDismissable?: boolean;\n isOpen?: boolean;\n}\n\n/** @flr-generate all */\nexport const OverlayContent: FC<OverlayContentProps> = (props) => {\n const {\n children,\n className,\n \"aria-labelledby\": ariaLabelledBy,\n ...restProps\n } = props;\n\n const isActivityActive = useIsActivityActive();\n\n useKeepBrowserExtensionsInteractive(restProps.isOpen ?? false);\n\n const Fallback = () => {\n return (\n <DivView className={styles.suspense}>\n <OverlaySuspenseFallback {...restProps} />\n </DivView>\n );\n };\n\n if (!isActivityActive) {\n return null;\n }\n\n return (\n <UNSAFE_PortalProvider getContainer={getOverlayContainer}>\n <Aria.ModalOverlay {...restProps} className={className}>\n {/* The centering viewport between the backdrop and react-aria's modal\n wrapper. Classed so Modal/OffCanvas/LightBox can position it\n without selecting a bare `div`. */}\n <DivView className={styles.viewport}>\n <Aria.Modal>\n <Suspense fallback={<Fallback />}>\n <Aria.Dialog aria-labelledby={ariaLabelledBy}>\n {children}\n </Aria.Dialog>\n </Suspense>\n </Aria.Modal>\n </DivView>\n </Aria.ModalOverlay>\n </UNSAFE_PortalProvider>\n );\n};\n\nexport default OverlayContent;\n"],"mappings":";;;;;;;;;;;;AAaA,IAAM,4BAA4B;;;;;;;;;;;;AAalC,IAAM,gBAAgB,SACpB,gBAAgB,gBACf,KAAK,WAAW,QAAQ,KAAK,MAAM,YAAY;AAElD,IAAM,0BAA0B,cAAoC;CAClE,KACE,IAAI,OAAO,UAAU,oBACrB,MACA,OAAO,KAAK,oBAEZ,IAAI,CAAC,uBAAuB,IAAI,KAAK,CAAC,aAAa,IAAI,GACrD,OAAO;CAGX,OAAO;AACT;;;;;;;;;AAUA,IAAM,aAAa,cAAiC;CAClD,MAAM,OAAO,SAAS;CACtB,MAAM,UAAU,SAAS;CACzB,MAAM,WAAW,MAAM,KAAK,UAAU,iBAA8B,GAAG,CAAC,CAAC,CACtE,QAAQ,YAAY,QAAQ,cAAc,KAAK,QAAQ,eAAe,CAAC,CAAC,CACxE,KACE,YAAY;EAAC;EAAS,QAAQ;EAAW,QAAQ;CAAU,CAC9D;CAEF,IAAI,OAAO,KAAK,eAAe,YAC7B,KAAK,WAAW,WAAW,IAAI;MAE/B,KAAK,OAAO,SAAS;CAGvB,KAAK,MAAM,CAAC,SAAS,WAAW,eAAe,UAAU;EACvD,QAAQ,YAAY;EACpB,QAAQ,aAAa;CACvB;CACA,IACE,mBAAmB,eACnB,UAAU,SAAS,OAAO,KAC1B,SAAS,kBAAkB,SAE3B,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;AAoBA,IAAM,4BAAgD;CACpD,IAAI,OAAO,aAAa,aACtB,OAAO;CAGT,MAAM,oBAAoB,SAAS,cACjC,WAAW,0BAA0B,EACvC;CAEA,IAAI,mBAAmB;EACrB,IAAI,uBAAuB,iBAAiB,GAC1C,UAAU,iBAAiB;EAE7B,OAAO;CACT;CAEA,MAAM,YAAY,SAAS,cAAc,KAAK;CAC9C,UAAU,aAAa,2BAA2B,EAAE;CACpD,SAAS,KAAK,OAAO,SAAS;CAE9B,OAAO;AACT;;AAcA,IAAa,kBAA2C,UAAU;CAChE,MAAM,EACJ,UACA,WACA,mBAAmB,gBACnB,GAAG,cACD;CAEJ,MAAM,mBAAmB,oBAAoB;CAE7C,oCAAoC,UAAU,UAAU,KAAK;CAE7D,MAAM,iBAAiB;EACrB,OACE,oBAAC,SAAD;GAAS,WAAWA,uBAAO;GACzB,UAAA,oBAAC,yBAAD,EAAyB,GAAI,UAAY,CAAA;EAClC,CAAA;CAEb;CAEA,IAAI,CAAC,kBACH,OAAO;CAGT,OACE,oBAAC,uBAAD;EAAuB,cAAc;EACnC,UAAA,oBAAC,KAAK,cAAN;GAAmB,GAAI;GAAsB;GAI3C,UAAA,oBAAC,SAAD;IAAS,WAAWA,uBAAO;IACzB,UAAA,oBAAC,KAAK,OAAN,EAAA,UACE,oBAAC,UAAD;KAAU,UAAU,oBAAC,UAAD,CAAW,CAAA;KAC7B,UAAA,oBAAC,KAAK,QAAN;MAAa,mBAAiB;MAC3B;KACU,CAAA;IACL,CAAA,EACA,CAAA;GACL,CAAA;EACQ,CAAA;CACE,CAAA;AAE3B"}
@@ -11,6 +11,13 @@ export interface CodeEditorProps extends Omit<ReactCodeMirrorProps, "theme" | "l
11
11
  * @default false
12
12
  */
13
13
  isReadOnly?: boolean;
14
+ /**
15
+ * Whether the editor is disabled. The code can neither be edited, focused nor
16
+ * copied.
17
+ *
18
+ * @default false
19
+ */
20
+ isDisabled?: boolean;
14
21
  /**
15
22
  * Whether the editor is displayed as invalid.
16
23
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mittwald/flow-react-components",
3
- "version": "1.5.0-next.25",
3
+ "version": "1.5.0-next.27",
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.5.0-next.25",
87
+ "@mittwald/flow-icons": "^1.5.0-next.27",
88
88
  "@mittwald/password-tools-js": "^3.0.0",
89
- "@mittwald/react-tunnel": "^1.5.0-next.25",
89
+ "@mittwald/react-tunnel": "^1.5.0-next.27",
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,12 +139,12 @@
139
139
  "@internationalized/date": "^3.12.3",
140
140
  "@lezer/generator": "^1.8.0",
141
141
  "@lezer/lr": "^1.4.10",
142
- "@mittwald/flow-core": "1.5.0-next.25",
143
- "@mittwald/flow-design-tokens": "1.5.0-next.25",
144
- "@mittwald/flow-icons-base": "1.5.0-next.25",
142
+ "@mittwald/flow-core": "1.5.0-next.27",
143
+ "@mittwald/flow-design-tokens": "1.5.0-next.27",
144
+ "@mittwald/flow-icons-base": "1.5.0-next.27",
145
145
  "@mittwald/react-use-promise": "^4.2.2",
146
146
  "@mittwald/remote-dom-react": "1.2.2-mittwald.10",
147
- "@mittwald/typescript-config": "1.5.0-next.25",
147
+ "@mittwald/typescript-config": "1.5.0-next.27",
148
148
  "@nx/storybook": "^22.7.6",
149
149
  "@storybook/addon-a11y": "^10.5.10",
150
150
  "@storybook/addon-actions": "^9.0.8",
@@ -196,7 +196,7 @@
196
196
  },
197
197
  "peerDependencies": {
198
198
  "@internationalized/date": "^3.12.2",
199
- "@mittwald/flow-icons-pro": "1.5.0-next.25",
199
+ "@mittwald/flow-icons-pro": "1.5.0-next.27",
200
200
  "@mittwald/react-use-promise": "^4.2.2",
201
201
  "next": "^16.2.3",
202
202
  "react": "^19.2.0",
@@ -220,5 +220,5 @@
220
220
  "browserslist": [
221
221
  "baseline widely available"
222
222
  ],
223
- "gitHead": "9c478d1c37c2221ab0323bcdadd9fa3eeecd57cf"
223
+ "gitHead": "d2a44c89190f8d4c910513506f0d97d68fcda417"
224
224
  }