@mittwald/flow-react-components 1.1.18 → 1.1.20

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.
@@ -1,17 +1,18 @@
1
1
  "use client"
2
2
  /* */
3
3
  import { flowComponent } from "../../lib/componentFactory/flowComponent.mjs";
4
- import { extractTextFromFirstChild } from "../../lib/react/remote.mjs";
4
+ import { extractTextFromChildren } from "../../lib/react/remote.mjs";
5
5
  import { IconCheck } from "../Icon/components/icons/IconCheck.mjs";
6
6
  import Option_module_default from "./Option.module.mjs";
7
7
  import clsx from "clsx";
8
- import { Children } from "react";
8
+ import { Children, useEffect, useRef } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import * as Aria from "react-aria-components";
11
11
  //#region src/components/Option/Option.tsx
12
12
  /** @flr-generate all */
13
13
  var Option = flowComponent("Option", (props) => {
14
- const { className, children, textValue = extractTextFromFirstChild(children), value = textValue, ref, ...rest } = props;
14
+ const { className, children, textValue = extractTextFromChildren(children), value = textValue, ref, ...rest } = props;
15
+ useWarnMissingValue(value === void 0);
15
16
  const rootClassName = clsx(Option_module_default.option, className);
16
17
  const hasChildren = Children.count(children) >= 1;
17
18
  return /* @__PURE__ */ jsxs(Aria.ListBoxItem, {
@@ -29,6 +30,14 @@ var Option = flowComponent("Option", (props) => {
29
30
  })]
30
31
  });
31
32
  });
33
+ var useWarnMissingValue = (isMissing) => {
34
+ const hasWarned = useRef(false);
35
+ useEffect(() => {
36
+ if (!isMissing || hasWarned.current) return;
37
+ hasWarned.current = true;
38
+ console.error("An <Option> has no 'value' and none could be inferred from its children, so it falls back to a generated, render-order-dependent key. Pass a 'value' to give the option a stable key.");
39
+ }, [isMissing]);
40
+ };
32
41
  //#endregion
33
42
  export { Option, Option as default };
34
43
 
@@ -1 +1 @@
1
- {"version":3,"file":"Option.mjs","names":[],"sources":["../../../../../../../src/components/Option/Option.tsx"],"sourcesContent":["import { type PropsWithChildren } from \"react\";\nimport { Children } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"./Option.module.scss\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { extractTextFromFirstChild } from \"@/lib/react/remote\";\nimport { IconCheck } from \"@/components/Icon/components/icons\";\n\nexport interface OptionProps\n extends\n Omit<Aria.ListBoxItemProps, \"children\" | \"value\" | \"id\">,\n PropsWithChildren,\n FlowComponentProps {\n value?: string | number;\n}\n\n/** @flr-generate all */\nexport const Option = flowComponent(\"Option\", (props) => {\n const {\n className,\n children,\n textValue = extractTextFromFirstChild(children),\n value = textValue,\n ref,\n ...rest\n } = props;\n\n const rootClassName = clsx(styles.option, className);\n const hasChildren = Children.count(children) >= 1;\n\n return (\n <Aria.ListBoxItem\n className={rootClassName}\n ref={ref}\n id={value}\n {...rest}\n textValue={textValue}\n >\n <span className={styles.content}>\n {hasChildren ? children : textValue}\n </span>\n <IconCheck aria-hidden className={styles.checkMark} />\n </Aria.ListBoxItem>\n );\n});\n\nexport default Option;\n"],"mappings":";;;;;;;;;;;;AAmBA,IAAa,SAAS,cAAc,WAAW,UAAU;CACvD,MAAM,EACJ,WACA,UACA,YAAY,0BAA0B,QAAQ,GAC9C,QAAQ,WACR,KACA,GAAG,SACD;CAEJ,MAAM,gBAAgB,KAAK,sBAAO,QAAQ,SAAS;CACnD,MAAM,cAAc,SAAS,MAAM,QAAQ,KAAK;CAEhD,OACE,qBAAC,KAAK,aAAN;EACE,WAAW;EACN;EACL,IAAI;EACJ,GAAI;EACO;EALb,UAAA,CAOE,oBAAC,QAAD;GAAM,WAAW,sBAAO;GACrB,UAAA,cAAc,WAAW;EACtB,CAAA,GACN,oBAAC,WAAD;GAAW,eAAA;GAAY,WAAW,sBAAO;EAAY,CAAA,CACrC;;AAEtB,CAAC"}
1
+ {"version":3,"file":"Option.mjs","names":[],"sources":["../../../../../../../src/components/Option/Option.tsx"],"sourcesContent":["import { type PropsWithChildren } from \"react\";\nimport { Children, useEffect, useRef } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport clsx from \"clsx\";\nimport styles from \"./Option.module.scss\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport { extractTextFromChildren } from \"@/lib/react/remote\";\nimport { IconCheck } from \"@/components/Icon/components/icons\";\n\nexport interface OptionProps\n extends\n Omit<Aria.ListBoxItemProps, \"children\" | \"value\" | \"id\">,\n PropsWithChildren,\n FlowComponentProps {\n /**\n * The value this option contributes to the field's selection, and the key\n * `defaultValue` / `value` of the surrounding field target.\n *\n * Defaults to `textValue`, which itself defaults to the text among the\n * option's children — element children such as a `Badge` do not contribute,\n * so `<Option>Millennium Falcon <Badge>Latest</Badge></Option>` is\n * `\"Millennium Falcon\"`. Pass it explicitly when the value must not follow\n * the display text, or when the children carry no text at all.\n */\n value?: string | number;\n}\n\n/** @flr-generate all */\nexport const Option = flowComponent(\"Option\", (props) => {\n const {\n className,\n children,\n textValue = extractTextFromChildren(children),\n value = textValue,\n ref,\n ...rest\n } = props;\n\n useWarnMissingValue(value === undefined);\n\n const rootClassName = clsx(styles.option, className);\n const hasChildren = Children.count(children) >= 1;\n\n return (\n <Aria.ListBoxItem\n className={rootClassName}\n ref={ref}\n id={value}\n {...rest}\n textValue={textValue}\n >\n <span className={styles.content}>\n {hasChildren ? children : textValue}\n </span>\n <IconCheck aria-hidden className={styles.checkMark} />\n </Aria.ListBoxItem>\n );\n});\n\n/*\n * Without an `id`, react-aria gives the item a key off a render-order counter\n * (`react-aria-1`). That key is what the field reports as its selected value\n * and what `defaultValue` has to match, so an option without a `value` silently\n * submits a meaningless string and cannot be preselected — and the key shifts\n * when unrelated markup around it changes. react-aria warns about the missing\n * `textValue` in this situation but says nothing about the key, which is the\n * expensive half (#3028).\n *\n * Warn in an effect rather than during render, so a double render in StrictMode\n * does not log twice; the ref keeps it to once per option.\n */\nconst useWarnMissingValue = (isMissing: boolean): void => {\n const hasWarned = useRef(false);\n\n useEffect(() => {\n if (!isMissing || hasWarned.current) {\n return;\n }\n\n hasWarned.current = true;\n console.error(\n \"An <Option> has no 'value' and none could be inferred from its children, so it falls back to a generated, render-order-dependent key. Pass a 'value' to give the option a stable key.\",\n );\n }, [isMissing]);\n};\n\nexport default Option;\n"],"mappings":";;;;;;;;;;;;AA6BA,IAAa,SAAS,cAAc,WAAW,UAAU;CACvD,MAAM,EACJ,WACA,UACA,YAAY,wBAAwB,QAAQ,GAC5C,QAAQ,WACR,KACA,GAAG,SACD;CAEJ,oBAAoB,UAAU,KAAA,CAAS;CAEvC,MAAM,gBAAgB,KAAK,sBAAO,QAAQ,SAAS;CACnD,MAAM,cAAc,SAAS,MAAM,QAAQ,KAAK;CAEhD,OACE,qBAAC,KAAK,aAAN;EACE,WAAW;EACN;EACL,IAAI;EACJ,GAAI;EACO;EALb,UAAA,CAOE,oBAAC,QAAD;GAAM,WAAW,sBAAO;GACrB,UAAA,cAAc,WAAW;EACtB,CAAA,GACN,oBAAC,WAAD;GAAW,eAAA;GAAY,WAAW,sBAAO;EAAY,CAAA,CACrC;;AAEtB,CAAC;AAcD,IAAM,uBAAuB,cAA6B;CACxD,MAAM,YAAY,OAAO,KAAK;CAE9B,gBAAgB;EACd,IAAI,CAAC,aAAa,UAAU,SAC1B;EAGF,UAAU,UAAU;EACpB,QAAQ,MACN,uLACF;CACF,GAAG,CAAC,SAAS,CAAC;AAChB"}
@@ -16,7 +16,7 @@ var Tabs = flowComponent("Tabs", (props) => {
16
16
  const { children, className, defaultSelectedKey, selectedKey: selectedKeyProps, disabledKeys, ref, onSelectionChange, tabNotFoundView, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...rest } = props;
17
17
  const rootClassName = clsx(Tabs_module_default.tabs, className);
18
18
  const [selectedKeyState, setSelectedKeyState] = useState(defaultSelectedKey);
19
- const selectedKey = selectedKeyProps ?? selectedKeyState;
19
+ const selectedKey = selectedKeyProps ?? selectedKeyState ?? null;
20
20
  const isSsr = useIsSSR();
21
21
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [children, /* @__PURE__ */ jsxs(Aria.Tabs, {
22
22
  slot: null,
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.mjs","names":[],"sources":["../../../../../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { TabList } from \"@/components/Tabs/components/TabList\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport clsx from \"clsx\";\nimport type { PropsWithChildren, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport styles from \"./Tabs.module.scss\";\nimport { FallbackTab } from \"@/components/Tabs/components/FallbackTab\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\nimport { useIsSSR } from \"react-aria\";\n\nexport interface TabsProps\n extends\n Omit<Aria.TabsProps, \"children\">,\n PropsWithChildren,\n FlowComponentProps {\n /**\n * An accessible name for the tab list. `Tabs` has no `Label` slot, so this is\n * how the group is named when the surrounding heading does not already do\n * it.\n */\n \"aria-label\"?: string;\n /** The id of an element that names the tab list. */\n \"aria-labelledby\"?: string;\n /**\n * The view rendered when the selected tab does not exist. Defaults to a\n * built-in IllustratedMessage.\n */\n tabNotFoundView?: ReactNode;\n}\n\n/** @flr-generate all */\nexport const Tabs = flowComponent(\"Tabs\", (props) => {\n const {\n children,\n className,\n defaultSelectedKey,\n selectedKey: selectedKeyProps,\n disabledKeys,\n ref,\n onSelectionChange,\n tabNotFoundView,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n ...rest\n } = props;\n\n const rootClassName = clsx(styles.tabs, className);\n const [selectedKeyState, setSelectedKeyState] = useState<\n Aria.Key | undefined\n >(defaultSelectedKey);\n\n const selectedKey = selectedKeyProps ?? selectedKeyState;\n\n const isSsr = useIsSSR();\n\n return (\n <>\n {children}\n <Aria.Tabs\n slot={null}\n className={rootClassName}\n {...rest}\n selectedKey={selectedKey}\n onSelectionChange={(key) => {\n setSelectedKeyState(key);\n if (onSelectionChange) {\n onSelectionChange(key);\n }\n }}\n disabledKeys={disabledKeys}\n ref={ref}\n >\n <TabList\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n selection={selectedKey}\n onContextMenuSelectionChange={(key) => {\n setSelectedKeyState(key);\n if (onSelectionChange) {\n onSelectionChange(key);\n }\n }}\n disabledKeys={disabledKeys}\n />\n <UiComponentTunnelExit id=\"Panels\" component=\"Tabs\" />\n {!isSsr && <FallbackTab tabNotFoundView={tabNotFoundView} />}\n </Aria.Tabs>\n </>\n );\n});\n\nexport default Tabs;\n"],"mappings":";;;;;;;;;;;;;;AAiCA,IAAa,OAAO,cAAc,SAAS,UAAU;CACnD,MAAM,EACJ,UACA,WACA,oBACA,aAAa,kBACb,cACA,KACA,mBACA,iBACA,cAAc,WACd,mBAAmB,gBACnB,GAAG,SACD;CAEJ,MAAM,gBAAgB,KAAK,oBAAO,MAAM,SAAS;CACjD,MAAM,CAAC,kBAAkB,uBAAuB,SAE9C,kBAAkB;CAEpB,MAAM,cAAc,oBAAoB;CAExC,MAAM,QAAQ,SAAS;CAEvB,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,UACD,qBAAC,KAAK,MAAN;EACE,MAAM;EACN,WAAW;EACX,GAAI;EACS;EACb,oBAAoB,QAAQ;GAC1B,oBAAoB,GAAG;GACvB,IAAI,mBACF,kBAAkB,GAAG;EAEzB;EACc;EACT;EAZP,UAAA;GAcE,oBAAC,SAAD;IACE,cAAY;IACZ,mBAAiB;IACjB,WAAW;IACX,+BAA+B,QAAQ;KACrC,oBAAoB,GAAG;KACvB,IAAI,mBACF,kBAAkB,GAAG;IAEzB;IACc;GACf,CAAA;GACD,oBAAC,uBAAD;IAAuB,IAAG;IAAS,WAAU;GAAQ,CAAA;GACpD,CAAC,SAAS,oBAAC,aAAD,EAA8B,gBAAkB,CAAA;EAClD;CACX,CAAA,CAAA,EAAA,CAAA;AAEN,CAAC"}
1
+ {"version":3,"file":"Tabs.mjs","names":[],"sources":["../../../../../../../src/components/Tabs/Tabs.tsx"],"sourcesContent":["import { TabList } from \"@/components/Tabs/components/TabList\";\nimport type { FlowComponentProps } from \"@/lib/componentFactory/flowComponent\";\nimport { flowComponent } from \"@/lib/componentFactory/flowComponent\";\nimport clsx from \"clsx\";\nimport type { PropsWithChildren, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport styles from \"./Tabs.module.scss\";\nimport { FallbackTab } from \"@/components/Tabs/components/FallbackTab\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\nimport { useIsSSR } from \"react-aria\";\n\nexport interface TabsProps\n extends\n Omit<Aria.TabsProps, \"children\">,\n PropsWithChildren,\n FlowComponentProps {\n /**\n * An accessible name for the tab list. `Tabs` has no `Label` slot, so this is\n * how the group is named when the surrounding heading does not already do\n * it.\n */\n \"aria-label\"?: string;\n /** The id of an element that names the tab list. */\n \"aria-labelledby\"?: string;\n /**\n * The view rendered when the selected tab does not exist. Defaults to a\n * built-in IllustratedMessage.\n */\n tabNotFoundView?: ReactNode;\n}\n\n/** @flr-generate all */\nexport const Tabs = flowComponent(\"Tabs\", (props) => {\n const {\n children,\n className,\n defaultSelectedKey,\n selectedKey: selectedKeyProps,\n disabledKeys,\n ref,\n onSelectionChange,\n tabNotFoundView,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n ...rest\n } = props;\n\n const rootClassName = clsx(styles.tabs, className);\n const [selectedKeyState, setSelectedKeyState] = useState<\n Aria.Key | undefined\n >(defaultSelectedKey);\n\n /*\n * `null`, not `undefined`, keeps `Aria.Tabs` controlled while nothing is\n * selected yet — see the controlled-from-the-first-render convention in\n * AGENTS.md. `Aria.TabsProps` narrows `selectedKey` to `Key`, hence the cast\n * below.\n */\n const selectedKey = selectedKeyProps ?? selectedKeyState ?? null;\n\n const isSsr = useIsSSR();\n\n return (\n <>\n {children}\n <Aria.Tabs\n slot={null}\n className={rootClassName}\n {...rest}\n selectedKey={selectedKey as Aria.Key | undefined}\n onSelectionChange={(key) => {\n setSelectedKeyState(key);\n if (onSelectionChange) {\n onSelectionChange(key);\n }\n }}\n disabledKeys={disabledKeys}\n ref={ref}\n >\n <TabList\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n selection={selectedKey}\n onContextMenuSelectionChange={(key) => {\n setSelectedKeyState(key);\n if (onSelectionChange) {\n onSelectionChange(key);\n }\n }}\n disabledKeys={disabledKeys}\n />\n <UiComponentTunnelExit id=\"Panels\" component=\"Tabs\" />\n {!isSsr && <FallbackTab tabNotFoundView={tabNotFoundView} />}\n </Aria.Tabs>\n </>\n );\n});\n\nexport default Tabs;\n"],"mappings":";;;;;;;;;;;;;;AAiCA,IAAa,OAAO,cAAc,SAAS,UAAU;CACnD,MAAM,EACJ,UACA,WACA,oBACA,aAAa,kBACb,cACA,KACA,mBACA,iBACA,cAAc,WACd,mBAAmB,gBACnB,GAAG,SACD;CAEJ,MAAM,gBAAgB,KAAK,oBAAO,MAAM,SAAS;CACjD,MAAM,CAAC,kBAAkB,uBAAuB,SAE9C,kBAAkB;CAQpB,MAAM,cAAc,oBAAoB,oBAAoB;CAE5D,MAAM,QAAQ,SAAS;CAEvB,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,UACD,qBAAC,KAAK,MAAN;EACE,MAAM;EACN,WAAW;EACX,GAAI;EACS;EACb,oBAAoB,QAAQ;GAC1B,oBAAoB,GAAG;GACvB,IAAI,mBACF,kBAAkB,GAAG;EAEzB;EACc;EACT;EAZP,UAAA;GAcE,oBAAC,SAAD;IACE,cAAY;IACZ,mBAAiB;IACjB,WAAW;IACX,+BAA+B,QAAQ;KACrC,oBAAoB,GAAG;KACvB,IAAI,mBACF,kBAAkB,GAAG;IAEzB;IACc;GACf,CAAA;GACD,oBAAC,uBAAD;IAAuB,IAAG;IAAS,WAAU;GAAQ,CAAA;GACpD,CAAC,SAAS,oBAAC,aAAD,EAA8B,gBAAkB,CAAA;EAClD;CACX,CAAA,CAAA,EAAA,CAAA;AAEN,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TabList.mjs","names":[],"sources":["../../../../../../../../../src/components/Tabs/components/TabList/TabList.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useId } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport styles from \"./TabList.module.scss\";\nimport { useTabIndicator } from \"../../lib/useTabIndicator\";\nimport { useObserveOverflow } from \"@/lib/hooks/dom/useObserveOverflow\";\nimport { Button } from \"@/components/Button\";\nimport clsx from \"clsx\";\nimport { useMergeRefs } from \"use-callback-ref\";\nimport ContextMenuTriggerView from \"@/views/ContextMenuTriggerView\";\nimport ContextMenuView from \"@/views/ContextMenuView\";\nimport { IconChevronDown } from \"@/components/Icon/components/icons\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\n\ninterface Props {\n selection: Aria.Key | undefined;\n onContextMenuSelectionChange: (key: Aria.Key) => void;\n disabledKeys?: Iterable<Aria.Key>;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n}\n\nexport const TabList: FC<Props> = (props) => {\n const {\n selection,\n disabledKeys,\n onContextMenuSelectionChange,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n } = props;\n\n const titleCollapsedElementId = useId();\n const overflowObserver = useObserveOverflow();\n const isCollapsed = overflowObserver.isOverflowing;\n const rootClassName = clsx(styles.tabList, isCollapsed && styles.collapsed);\n const tabIndicator = useTabIndicator(isCollapsed);\n\n const setTitlesRef = useMergeRefs<HTMLDivElement>([\n overflowObserver.ref,\n tabIndicator.titlesRef,\n ]);\n\n const handleContextMenuSelectionChange = (key: Aria.Key) => {\n onContextMenuSelectionChange(key);\n };\n\n const regularTabTitles = (\n <Aria.TabList\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n className={styles.titles}\n ref={setTitlesRef}\n >\n <UiComponentTunnelExit id=\"Titles\" component=\"Tabs\" />\n </Aria.TabList>\n );\n\n const contextMenuWhenCollapsed = isCollapsed && (\n <ContextMenuTriggerView>\n <Button\n variant=\"solid\"\n className={styles.contextMenuButton}\n color=\"light\"\n aria-labelledby={titleCollapsedElementId}\n >\n <UiComponentTunnelExit id=\"ActiveTitle\" component=\"Tabs\" />\n <IconChevronDown />\n </Button>\n\n <ContextMenuView\n disabledKeys={disabledKeys}\n selectedKeys={selection ? [selection] : undefined}\n selectionMode=\"navigation\"\n onAction={(key) => handleContextMenuSelectionChange(key)}\n >\n <UiComponentTunnelExit id=\"ContextMenuItems\" component=\"Tabs\" />\n </ContextMenuView>\n </ContextMenuTriggerView>\n );\n\n return (\n <div className={rootClassName} ref={tabIndicator.rootRef}>\n {!isCollapsed && tabIndicator.indicatorStyle && (\n <div\n aria-hidden=\"true\"\n className={clsx(\n styles.activeIndicator,\n tabIndicator.isAnimated && styles.animated,\n )}\n style={tabIndicator.indicatorStyle}\n />\n )}\n {regularTabTitles}\n {contextMenuWhenCollapsed}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,IAAa,WAAsB,UAAU;CAC3C,MAAM,EACJ,WACA,cACA,8BACA,cAAc,WACd,mBAAmB,mBACjB;CAEJ,MAAM,0BAA0B,MAAM;CACtC,MAAM,mBAAmB,mBAAmB;CAC5C,MAAM,cAAc,iBAAiB;CACrC,MAAM,gBAAgB,KAAK,uBAAO,SAAS,eAAe,uBAAO,SAAS;CAC1E,MAAM,eAAe,gBAAgB,WAAW;CAEhD,MAAM,eAAe,aAA6B,CAChD,iBAAiB,KACjB,aAAa,SACf,CAAC;CAED,MAAM,oCAAoC,QAAkB;EAC1D,6BAA6B,GAAG;CAClC;CAEA,MAAM,mBACJ,oBAAC,KAAK,SAAN;EACE,cAAY;EACZ,mBAAiB;EACjB,WAAW,uBAAO;EAClB,KAAK;EAEL,UAAA,oBAAC,uBAAD;GAAuB,IAAG;GAAS,WAAU;EAAQ,CAAA;CACzC,CAAA;CAGhB,MAAM,2BAA2B,eAC/B,qBAAC,wBAAD,EAAA,UAAA,CACE,qBAAC,QAAD;EACE,SAAQ;EACR,WAAW,uBAAO;EAClB,OAAM;EACN,mBAAiB;EAJnB,UAAA,CAME,oBAAC,uBAAD;GAAuB,IAAG;GAAc,WAAU;EAAQ,CAAA,GAC1D,oBAAC,iBAAD,CAAkB,CAAA,CACZ;CAER,CAAA,GAAA,oBAAC,iBAAD;EACgB;EACd,cAAc,YAAY,CAAC,SAAS,IAAI,KAAA;EACxC,eAAc;EACd,WAAW,QAAQ,iCAAiC,GAAG;EAEvD,UAAA,oBAAC,uBAAD;GAAuB,IAAG;GAAmB,WAAU;EAAQ,CAAA;CAChD,CAAA,CACK,EAAA,CAAA;CAG1B,OACE,qBAAC,OAAD;EAAK,WAAW;EAAe,KAAK,aAAa;EAAjD,UAAA;GACG,CAAC,eAAe,aAAa,kBAC5B,oBAAC,OAAD;IACE,eAAY;IACZ,WAAW,KACT,uBAAO,iBACP,aAAa,cAAc,uBAAO,QACpC;IACA,OAAO,aAAa;GACrB,CAAA;GAEF;GACA;EACE;;AAET"}
1
+ {"version":3,"file":"TabList.mjs","names":[],"sources":["../../../../../../../../../src/components/Tabs/components/TabList/TabList.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useId } from \"react\";\nimport * as Aria from \"react-aria-components\";\nimport styles from \"./TabList.module.scss\";\nimport { useTabIndicator } from \"../../lib/useTabIndicator\";\nimport { useObserveOverflow } from \"@/lib/hooks/dom/useObserveOverflow\";\nimport { Button } from \"@/components/Button\";\nimport clsx from \"clsx\";\nimport { useMergeRefs } from \"use-callback-ref\";\nimport ContextMenuTriggerView from \"@/views/ContextMenuTriggerView\";\nimport ContextMenuView from \"@/views/ContextMenuView\";\nimport { IconChevronDown } from \"@/components/Icon/components/icons\";\nimport { UiComponentTunnelExit } from \"@/components/UiComponentTunnel/UiComponentTunnelExit\";\n\ninterface Props {\n selection: Aria.Key | null;\n onContextMenuSelectionChange: (key: Aria.Key) => void;\n disabledKeys?: Iterable<Aria.Key>;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n}\n\nexport const TabList: FC<Props> = (props) => {\n const {\n selection,\n disabledKeys,\n onContextMenuSelectionChange,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n } = props;\n\n const titleCollapsedElementId = useId();\n const overflowObserver = useObserveOverflow();\n const isCollapsed = overflowObserver.isOverflowing;\n const rootClassName = clsx(styles.tabList, isCollapsed && styles.collapsed);\n const tabIndicator = useTabIndicator(isCollapsed);\n\n const setTitlesRef = useMergeRefs<HTMLDivElement>([\n overflowObserver.ref,\n tabIndicator.titlesRef,\n ]);\n\n const handleContextMenuSelectionChange = (key: Aria.Key) => {\n onContextMenuSelectionChange(key);\n };\n\n const regularTabTitles = (\n <Aria.TabList\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n className={styles.titles}\n ref={setTitlesRef}\n >\n <UiComponentTunnelExit id=\"Titles\" component=\"Tabs\" />\n </Aria.TabList>\n );\n\n const contextMenuWhenCollapsed = isCollapsed && (\n <ContextMenuTriggerView>\n <Button\n variant=\"solid\"\n className={styles.contextMenuButton}\n color=\"light\"\n aria-labelledby={titleCollapsedElementId}\n >\n <UiComponentTunnelExit id=\"ActiveTitle\" component=\"Tabs\" />\n <IconChevronDown />\n </Button>\n\n <ContextMenuView\n disabledKeys={disabledKeys}\n selectedKeys={selection ? [selection] : undefined}\n selectionMode=\"navigation\"\n onAction={(key) => handleContextMenuSelectionChange(key)}\n >\n <UiComponentTunnelExit id=\"ContextMenuItems\" component=\"Tabs\" />\n </ContextMenuView>\n </ContextMenuTriggerView>\n );\n\n return (\n <div className={rootClassName} ref={tabIndicator.rootRef}>\n {!isCollapsed && tabIndicator.indicatorStyle && (\n <div\n aria-hidden=\"true\"\n className={clsx(\n styles.activeIndicator,\n tabIndicator.isAnimated && styles.animated,\n )}\n style={tabIndicator.indicatorStyle}\n />\n )}\n {regularTabTitles}\n {contextMenuWhenCollapsed}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,IAAa,WAAsB,UAAU;CAC3C,MAAM,EACJ,WACA,cACA,8BACA,cAAc,WACd,mBAAmB,mBACjB;CAEJ,MAAM,0BAA0B,MAAM;CACtC,MAAM,mBAAmB,mBAAmB;CAC5C,MAAM,cAAc,iBAAiB;CACrC,MAAM,gBAAgB,KAAK,uBAAO,SAAS,eAAe,uBAAO,SAAS;CAC1E,MAAM,eAAe,gBAAgB,WAAW;CAEhD,MAAM,eAAe,aAA6B,CAChD,iBAAiB,KACjB,aAAa,SACf,CAAC;CAED,MAAM,oCAAoC,QAAkB;EAC1D,6BAA6B,GAAG;CAClC;CAEA,MAAM,mBACJ,oBAAC,KAAK,SAAN;EACE,cAAY;EACZ,mBAAiB;EACjB,WAAW,uBAAO;EAClB,KAAK;EAEL,UAAA,oBAAC,uBAAD;GAAuB,IAAG;GAAS,WAAU;EAAQ,CAAA;CACzC,CAAA;CAGhB,MAAM,2BAA2B,eAC/B,qBAAC,wBAAD,EAAA,UAAA,CACE,qBAAC,QAAD;EACE,SAAQ;EACR,WAAW,uBAAO;EAClB,OAAM;EACN,mBAAiB;EAJnB,UAAA,CAME,oBAAC,uBAAD;GAAuB,IAAG;GAAc,WAAU;EAAQ,CAAA,GAC1D,oBAAC,iBAAD,CAAkB,CAAA,CACZ;CAER,CAAA,GAAA,oBAAC,iBAAD;EACgB;EACd,cAAc,YAAY,CAAC,SAAS,IAAI,KAAA;EACxC,eAAc;EACd,WAAW,QAAQ,iCAAiC,GAAG;EAEvD,UAAA,oBAAC,uBAAD;GAAuB,IAAG;GAAmB,WAAU;EAAQ,CAAA;CAChD,CAAA,CACK,EAAA,CAAA;CAG1B,OACE,qBAAC,OAAD;EAAK,WAAW;EAAe,KAAK,aAAa;EAAjD,UAAA;GACG,CAAC,eAAe,aAAa,kBAC5B,oBAAC,OAAD;IACE,eAAY;IACZ,WAAW,KACT,uBAAO,iBACP,aAAa,cAAc,uBAAO,QACpC;IACA,OAAO,aAAa;GACrB,CAAA;GAEF;GACA;EACE;;AAET"}
@@ -1,18 +1,51 @@
1
1
  "use client"
2
2
  /* */
3
3
  import { Children, Fragment, isValidElement } from "react";
4
- import { isObjectType, isString } from "remeda";
4
+ import { isNumber, isObjectType, isString } from "remeda";
5
5
  //#region src/lib/react/remote.ts
6
6
  function isRemoteComponentRendererProps(props) {
7
7
  return isObjectType(props) && "element" in props && "components" in props && "receiver" in props;
8
8
  }
9
- /** Whether the node renders text — a string, number, or remote counterpart. */
10
- var isTextNode = (child) => typeof child === "string" || typeof child === "number" || isValidElement(child) && isRemoteTextRenderProps(child.props);
11
9
  /**
12
- * `Children.toArray` treats a fragment as a single child, so recurse into one
13
- * to reach the text a component like `Link` passes down through it.
10
+ * The text `children` are _themselves_ — plain strings and numbers locally,
11
+ * `RemoteTextRenderer` elements remotely — joined and trimmed. `undefined` when
12
+ * there is none.
13
+ *
14
+ * Text inside an element child is deliberately left out, because it belongs to
15
+ * that element rather than to the component being described:
16
+ * `<Option>Millennium Falcon <Badge>Latest</Badge></Option>` is the option
17
+ * "Millennium Falcon", not "Millennium Falcon Latest". A fragment is grouping
18
+ * rather than rendered output, so this looks through it.
19
+ *
20
+ * Use this over {@link extractTextFromFirstChild} when the question is "what
21
+ * does this read as", not "are the children one single text node".
22
+ */
23
+ var extractTextFromChildren = (children) => {
24
+ const text = joinTextChildren(children).trim();
25
+ return text === "" ? void 0 : text;
26
+ };
27
+ var joinTextChildren = (children) => Children.toArray(children).map((child) => {
28
+ if (isString(child) || isNumber(child)) return String(child);
29
+ if (!isValidElement(child)) return "";
30
+ if (isRemoteTextRenderProps(child.props)) return child.props.remote.data;
31
+ return child.type === Fragment ? joinTextChildren(child.props.children) : "";
32
+ }).join("");
33
+ /**
34
+ * Whether `children` render any text of their own — what `Button` and `Link`
35
+ * ask to tell a labelled control from an icon-only one. The same reading as
36
+ * {@link extractTextFromChildren}, so fragments are transparent and children
37
+ * that are only whitespace do not count as a label.
38
+ */
39
+ var containsTextChild = (children) => extractTextFromChildren(children) !== void 0;
40
+ /**
41
+ * The text of `children` when they are exactly one text node — locally a
42
+ * string, remotely a `RemoteTextRenderer` element. `undefined` for anything
43
+ * else, including a single string next to anything at all.
44
+ *
45
+ * That strictness is the point for its callers: `Markdown` takes it as the
46
+ * markdown source, and `Initials` and `Truncate` operate on the whole content.
47
+ * For "what does this read as", use {@link extractTextFromChildren}.
14
48
  */
15
- var containsTextChild = (children) => Children.toArray(children).some((child) => isTextNode(child) || isValidElement(child) && child.type === Fragment && containsTextChild(child.props.children));
16
49
  var extractTextFromFirstChild = (children) => {
17
50
  if (Children.count(children) !== 1) return;
18
51
  const firstChild = Children.toArray(children)[0];
@@ -22,6 +55,6 @@ function isRemoteTextRenderProps(props) {
22
55
  return isObjectType(props) && "remote" in props && isObjectType(props.remote) && "data" in props.remote && isString(props.remote.data);
23
56
  }
24
57
  //#endregion
25
- export { containsTextChild, extractTextFromFirstChild, isRemoteComponentRendererProps, isRemoteTextRenderProps };
58
+ export { containsTextChild, extractTextFromChildren, extractTextFromFirstChild, isRemoteComponentRendererProps, isRemoteTextRenderProps };
26
59
 
27
60
  //# sourceMappingURL=remote.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote.mjs","names":[],"sources":["../../../../../../../src/lib/react/remote.ts"],"sourcesContent":["import type {\n RemoteComponentRendererProps,\n RemoteTextRendererProps,\n} from \"@mittwald/remote-dom-react/host\";\nimport { isObjectType, isString } from \"remeda\";\nimport {\n Children,\n Fragment,\n isValidElement,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\n\nexport function isRemoteComponentRendererProps(\n props: unknown,\n): props is RemoteComponentRendererProps {\n return (\n isObjectType(props) &&\n \"element\" in props &&\n \"components\" in props &&\n \"receiver\" in props\n );\n}\n\n/** Whether the node renders text — a string, number, or remote counterpart. */\nconst isTextNode = (child: ReactNode): boolean =>\n typeof child === \"string\" ||\n typeof child === \"number\" ||\n (isValidElement(child) && isRemoteTextRenderProps(child.props));\n\n/**\n * `Children.toArray` treats a fragment as a single child, so recurse into one\n * to reach the text a component like `Link` passes down through it.\n */\nexport const containsTextChild = (children: ReactNode): boolean =>\n Children.toArray(children).some(\n (child) =>\n isTextNode(child) ||\n (isValidElement<PropsWithChildren>(child) &&\n child.type === Fragment &&\n containsTextChild(child.props.children)),\n );\n\nexport const extractTextFromFirstChild = (children: ReactNode) => {\n if (Children.count(children) !== 1) {\n return undefined;\n }\n\n const firstChild = Children.toArray(children)[0];\n\n return typeof firstChild === \"string\"\n ? firstChild\n : isValidElement(firstChild) && isRemoteTextRenderProps(firstChild.props)\n ? firstChild.props.remote.data\n : undefined;\n};\n\nexport function isRemoteTextRenderProps(\n props: unknown,\n): props is RemoteTextRendererProps {\n return (\n isObjectType(props) &&\n \"remote\" in props &&\n isObjectType(props.remote) &&\n \"data\" in props.remote &&\n isString(props.remote.data)\n );\n}\n"],"mappings":";;;;;AAaA,SAAgB,+BACd,OACuC;CACvC,OACE,aAAa,KAAK,KAClB,aAAa,SACb,gBAAgB,SAChB,cAAc;AAElB;;AAGA,IAAM,cAAc,UAClB,OAAO,UAAU,YACjB,OAAO,UAAU,YAChB,eAAe,KAAK,KAAK,wBAAwB,MAAM,KAAK;;;;;AAM/D,IAAa,qBAAqB,aAChC,SAAS,QAAQ,QAAQ,CAAC,CAAC,MACxB,UACC,WAAW,KAAK,KACf,eAAkC,KAAK,KACtC,MAAM,SAAS,YACf,kBAAkB,MAAM,MAAM,QAAQ,CAC5C;AAEF,IAAa,6BAA6B,aAAwB;CAChE,IAAI,SAAS,MAAM,QAAQ,MAAM,GAC/B;CAGF,MAAM,aAAa,SAAS,QAAQ,QAAQ,CAAC,CAAC;CAE9C,OAAO,OAAO,eAAe,WACzB,aACA,eAAe,UAAU,KAAK,wBAAwB,WAAW,KAAK,IACpE,WAAW,MAAM,OAAO,OACxB,KAAA;AACR;AAEA,SAAgB,wBACd,OACkC;CAClC,OACE,aAAa,KAAK,KAClB,YAAY,SACZ,aAAa,MAAM,MAAM,KACzB,UAAU,MAAM,UAChB,SAAS,MAAM,OAAO,IAAI;AAE9B"}
1
+ {"version":3,"file":"remote.mjs","names":[],"sources":["../../../../../../../src/lib/react/remote.ts"],"sourcesContent":["import type {\n RemoteComponentRendererProps,\n RemoteTextRendererProps,\n} from \"@mittwald/remote-dom-react/host\";\nimport { isNumber, isObjectType, isString } from \"remeda\";\nimport {\n Children,\n Fragment,\n isValidElement,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\n\nexport function isRemoteComponentRendererProps(\n props: unknown,\n): props is RemoteComponentRendererProps {\n return (\n isObjectType(props) &&\n \"element\" in props &&\n \"components\" in props &&\n \"receiver\" in props\n );\n}\n\n/**\n * The text `children` are _themselves_ — plain strings and numbers locally,\n * `RemoteTextRenderer` elements remotely — joined and trimmed. `undefined` when\n * there is none.\n *\n * Text inside an element child is deliberately left out, because it belongs to\n * that element rather than to the component being described:\n * `<Option>Millennium Falcon <Badge>Latest</Badge></Option>` is the option\n * \"Millennium Falcon\", not \"Millennium Falcon Latest\". A fragment is grouping\n * rather than rendered output, so this looks through it.\n *\n * Use this over {@link extractTextFromFirstChild} when the question is \"what\n * does this read as\", not \"are the children one single text node\".\n */\nexport const extractTextFromChildren = (\n children: ReactNode,\n): string | undefined => {\n const text = joinTextChildren(children).trim();\n\n return text === \"\" ? undefined : text;\n};\n\nconst joinTextChildren = (children: ReactNode): string =>\n Children.toArray(children)\n .map((child) => {\n if (isString(child) || isNumber(child)) {\n return String(child);\n }\n\n if (!isValidElement(child)) {\n return \"\";\n }\n\n if (isRemoteTextRenderProps(child.props)) {\n return child.props.remote.data;\n }\n\n return child.type === Fragment\n ? joinTextChildren((child.props as PropsWithChildren).children)\n : \"\";\n })\n .join(\"\");\n\n/**\n * Whether `children` render any text of their own — what `Button` and `Link`\n * ask to tell a labelled control from an icon-only one. The same reading as\n * {@link extractTextFromChildren}, so fragments are transparent and children\n * that are only whitespace do not count as a label.\n */\nexport const containsTextChild = (children: ReactNode): boolean =>\n extractTextFromChildren(children) !== undefined;\n\n/**\n * The text of `children` when they are exactly one text node — locally a\n * string, remotely a `RemoteTextRenderer` element. `undefined` for anything\n * else, including a single string next to anything at all.\n *\n * That strictness is the point for its callers: `Markdown` takes it as the\n * markdown source, and `Initials` and `Truncate` operate on the whole content.\n * For \"what does this read as\", use {@link extractTextFromChildren}.\n */\nexport const extractTextFromFirstChild = (children: ReactNode) => {\n if (Children.count(children) !== 1) {\n return undefined;\n }\n\n const firstChild = Children.toArray(children)[0];\n\n return typeof firstChild === \"string\"\n ? firstChild\n : isValidElement(firstChild) && isRemoteTextRenderProps(firstChild.props)\n ? firstChild.props.remote.data\n : undefined;\n};\n\nexport function isRemoteTextRenderProps(\n props: unknown,\n): props is RemoteTextRendererProps {\n return (\n isObjectType(props) &&\n \"remote\" in props &&\n isObjectType(props.remote) &&\n \"data\" in props.remote &&\n isString(props.remote.data)\n );\n}\n"],"mappings":";;;;;AAaA,SAAgB,+BACd,OACuC;CACvC,OACE,aAAa,KAAK,KAClB,aAAa,SACb,gBAAgB,SAChB,cAAc;AAElB;;;;;;;;;;;;;;;AAgBA,IAAa,2BACX,aACuB;CACvB,MAAM,OAAO,iBAAiB,QAAQ,CAAC,CAAC,KAAK;CAE7C,OAAO,SAAS,KAAK,KAAA,IAAY;AACnC;AAEA,IAAM,oBAAoB,aACxB,SAAS,QAAQ,QAAQ,CAAC,CACvB,KAAK,UAAU;CACd,IAAI,SAAS,KAAK,KAAK,SAAS,KAAK,GACnC,OAAO,OAAO,KAAK;CAGrB,IAAI,CAAC,eAAe,KAAK,GACvB,OAAO;CAGT,IAAI,wBAAwB,MAAM,KAAK,GACrC,OAAO,MAAM,MAAM,OAAO;CAG5B,OAAO,MAAM,SAAS,WAClB,iBAAkB,MAAM,MAA4B,QAAQ,IAC5D;AACN,CAAC,CAAC,CACD,KAAK,EAAE;;;;;;;AAQZ,IAAa,qBAAqB,aAChC,wBAAwB,QAAQ,MAAM,KAAA;;;;;;;;;;AAWxC,IAAa,6BAA6B,aAAwB;CAChE,IAAI,SAAS,MAAM,QAAQ,MAAM,GAC/B;CAGF,MAAM,aAAa,SAAS,QAAQ,QAAQ,CAAC,CAAC;CAE9C,OAAO,OAAO,eAAe,WACzB,aACA,eAAe,UAAU,KAAK,wBAAwB,WAAW,KAAK,IACpE,WAAW,MAAM,OAAO,OACxB,KAAA;AACR;AAEA,SAAgB,wBACd,OACkC;CAClC,OACE,aAAa,KAAK,KAClB,YAAY,SACZ,aAAa,MAAM,MAAM,KACzB,UAAU,MAAM,UAChB,SAAS,MAAM,OAAO,IAAI;AAE9B"}
@@ -2,6 +2,16 @@ import { PropsWithChildren } from 'react';
2
2
  import { FlowComponentProps } from '../../lib/componentFactory/flowComponent';
3
3
  import * as Aria from "react-aria-components";
4
4
  export interface OptionProps extends Omit<Aria.ListBoxItemProps, "children" | "value" | "id">, PropsWithChildren, FlowComponentProps {
5
+ /**
6
+ * The value this option contributes to the field's selection, and the key
7
+ * `defaultValue` / `value` of the surrounding field target.
8
+ *
9
+ * Defaults to `textValue`, which itself defaults to the text among the
10
+ * option's children — element children such as a `Badge` do not contribute,
11
+ * so `<Option>Millennium Falcon <Badge>Latest</Badge></Option>` is
12
+ * `"Millennium Falcon"`. Pass it explicitly when the value must not follow
13
+ * the display text, or when the children carry no text at all.
14
+ */
5
15
  value?: string | number;
6
16
  }
7
17
  /** @flr-generate all */
@@ -1 +1 @@
1
- {"version":3,"file":"Option.d.ts","sourceRoot":"","sources":["../../../../src/components/Option/Option.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE/C,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAG9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAK/E,MAAM,WAAW,WACf,SACE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAAC,EACxD,iBAAiB,EACjB,kBAAkB;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,wBAAwB;AACxB,eAAO,MAAM,MAAM,gGA2BjB,CAAC;AAEH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Option.d.ts","sourceRoot":"","sources":["../../../../src/components/Option/Option.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAE/C,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAG9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAK/E,MAAM,WAAW,WACf,SACE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,OAAO,GAAG,IAAI,CAAC,EACxD,iBAAiB,EACjB,kBAAkB;IACpB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,wBAAwB;AACxB,eAAO,MAAM,MAAM,gGA6BjB,CAAC;AA6BH,eAAe,MAAM,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../../src/components/Tabs/Tabs.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAM9C,MAAM,WAAW,SACf,SACE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAChC,iBAAiB,EACjB,kBAAkB;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED,wBAAwB;AACxB,eAAO,MAAM,IAAI,8FA0Df,CAAC;AAEH,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../../src/components/Tabs/Tabs.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAM9C,MAAM,WAAW,SACf,SACE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAChC,iBAAiB,EACjB,kBAAkB;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED,wBAAwB;AACxB,eAAO,MAAM,IAAI,8FAgEf,CAAC;AAEH,eAAe,IAAI,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { FC } from 'react';
2
2
  import * as Aria from "react-aria-components";
3
3
  interface Props {
4
- selection: Aria.Key | undefined;
4
+ selection: Aria.Key | null;
5
5
  onContextMenuSelectionChange: (key: Aria.Key) => void;
6
6
  disabledKeys?: Iterable<Aria.Key>;
7
7
  "aria-label"?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"TabList.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tabs/components/TabList/TabList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAY9C,UAAU,KAAK;IACb,SAAS,EAAE,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;IAChC,4BAA4B,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC;IACtD,YAAY,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,KAAK,CA0E7B,CAAC"}
1
+ {"version":3,"file":"TabList.d.ts","sourceRoot":"","sources":["../../../../../../src/components/Tabs/components/TabList/TabList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAY9C,UAAU,KAAK;IACb,SAAS,EAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;IAC3B,4BAA4B,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC;IACtD,YAAY,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,KAAK,CA0E7B,CAAC"}
@@ -2,10 +2,36 @@ import { RemoteComponentRendererProps, RemoteTextRendererProps } from '@mittwald
2
2
  import { ReactNode } from 'react';
3
3
  export declare function isRemoteComponentRendererProps(props: unknown): props is RemoteComponentRendererProps;
4
4
  /**
5
- * `Children.toArray` treats a fragment as a single child, so recurse into one
6
- * to reach the text a component like `Link` passes down through it.
5
+ * The text `children` are _themselves_ — plain strings and numbers locally,
6
+ * `RemoteTextRenderer` elements remotely — joined and trimmed. `undefined` when
7
+ * there is none.
8
+ *
9
+ * Text inside an element child is deliberately left out, because it belongs to
10
+ * that element rather than to the component being described:
11
+ * `<Option>Millennium Falcon <Badge>Latest</Badge></Option>` is the option
12
+ * "Millennium Falcon", not "Millennium Falcon Latest". A fragment is grouping
13
+ * rather than rendered output, so this looks through it.
14
+ *
15
+ * Use this over {@link extractTextFromFirstChild} when the question is "what
16
+ * does this read as", not "are the children one single text node".
17
+ */
18
+ export declare const extractTextFromChildren: (children: ReactNode) => string | undefined;
19
+ /**
20
+ * Whether `children` render any text of their own — what `Button` and `Link`
21
+ * ask to tell a labelled control from an icon-only one. The same reading as
22
+ * {@link extractTextFromChildren}, so fragments are transparent and children
23
+ * that are only whitespace do not count as a label.
7
24
  */
8
25
  export declare const containsTextChild: (children: ReactNode) => boolean;
26
+ /**
27
+ * The text of `children` when they are exactly one text node — locally a
28
+ * string, remotely a `RemoteTextRenderer` element. `undefined` for anything
29
+ * else, including a single string next to anything at all.
30
+ *
31
+ * That strictness is the point for its callers: `Markdown` takes it as the
32
+ * markdown source, and `Initials` and `Truncate` operate on the whole content.
33
+ * For "what does this read as", use {@link extractTextFromChildren}.
34
+ */
9
35
  export declare const extractTextFromFirstChild: (children: ReactNode) => string | undefined;
10
36
  export declare function isRemoteTextRenderProps(props: unknown): props is RemoteTextRendererProps;
11
37
  //# sourceMappingURL=remote.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../../src/lib/react/remote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,4BAA4B,CAOvC;AAQD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,SAAS,KAAG,OAOrD,CAAC;AAEJ,eAAO,MAAM,yBAAyB,GAAI,UAAU,SAAS,uBAY5D,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,uBAAuB,CAQlC"}
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../../src/lib/react/remote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,uBAAuB,EACxB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,4BAA4B,CAOvC;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,SAAS,KAClB,MAAM,GAAG,SAIX,CAAC;AAuBF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,SAAS,KAAG,OACP,CAAC;AAElD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAU,SAAS,uBAY5D,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,uBAAuB,CAQlC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mittwald/flow-react-components",
3
- "version": "1.1.18",
3
+ "version": "1.1.20",
4
4
  "type": "module",
5
5
  "description": "A React implementation of Flow, mittwald’s design system",
6
6
  "homepage": "https://flow.mittwald.de",
@@ -78,9 +78,9 @@
78
78
  "@internationalized/string-compiler": "^3.4.1",
79
79
  "@lezer/common": "^1.5.2",
80
80
  "@lezer/highlight": "^1.2.3",
81
- "@mittwald/flow-icons": "1.1.18",
81
+ "@mittwald/flow-icons": "1.1.20",
82
82
  "@mittwald/password-tools-js": "3.0.0-alpha.31",
83
- "@mittwald/react-tunnel": "1.1.18",
83
+ "@mittwald/react-tunnel": "1.1.20",
84
84
  "@mittwald/react-use-promise": "^4.2.2",
85
85
  "@react-aria/form": "^3.2.1",
86
86
  "@react-aria/i18n": "^3.13.1",
@@ -134,12 +134,12 @@
134
134
  "@internationalized/date": "^3.12.3",
135
135
  "@lezer/generator": "^1.8.0",
136
136
  "@lezer/lr": "^1.4.10",
137
- "@mittwald/flow-core": "1.1.18",
138
- "@mittwald/flow-design-tokens": "1.1.18",
139
- "@mittwald/flow-icons-base": "1.1.18",
137
+ "@mittwald/flow-core": "1.1.20",
138
+ "@mittwald/flow-design-tokens": "1.1.20",
139
+ "@mittwald/flow-icons-base": "1.1.20",
140
140
  "@mittwald/react-use-promise": "^4.2.2",
141
141
  "@mittwald/remote-dom-react": "1.2.2-mittwald.10",
142
- "@mittwald/typescript-config": "1.1.18",
142
+ "@mittwald/typescript-config": "1.1.20",
143
143
  "@nx/storybook": "^22.7.6",
144
144
  "@storybook/addon-a11y": "^10.5.10",
145
145
  "@storybook/addon-actions": "^9.0.8",
@@ -190,7 +190,7 @@
190
190
  },
191
191
  "peerDependencies": {
192
192
  "@internationalized/date": "^3.12.2",
193
- "@mittwald/flow-icons-pro": "1.1.18",
193
+ "@mittwald/flow-icons-pro": "1.1.20",
194
194
  "@mittwald/react-use-promise": "^4.2.2",
195
195
  "next": "^16.2.3",
196
196
  "react": "^19.2.0",
@@ -211,5 +211,5 @@
211
211
  "optional": true
212
212
  }
213
213
  },
214
- "gitHead": "960e4a6f68430012c6c4f9e731796e1b442404d3"
214
+ "gitHead": "17efdf9c9a545733dce93ad9b5a0afe82c9a5252"
215
215
  }