@lmb-it/kitsconcerto-native 0.1.253 → 0.1.254

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.
@@ -83,6 +83,7 @@ require('../../apps/mobile/src/Core/RadioButton/index.cjs');
83
83
  require('../../apps/mobile/src/Core/Input/index.cjs');
84
84
  require('../../apps/mobile/src/Core/Input/Field.cjs');
85
85
  require('../../apps/mobile/src/Core/Input/Slot.cjs');
86
+ var useRtlLineHeight = require('../../hooks/useRtlLineHeight.cjs');
86
87
  var index$1 = require('../../primitives/Box/index.cjs');
87
88
  var index_native = require('../../primitives/Icon/index.cjs');
88
89
  var index = require('../../layout/Flex/index.cjs');
@@ -148,6 +149,7 @@ function BottomTabBar(rawProps) {
148
149
  showLabels = true,
149
150
  testID
150
151
  } = props;
152
+ const rtlLineHeight = useRtlLineHeight.default(void 0, 11);
151
153
  const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
152
154
  const activeC = style.resolveThemeTokenForNative(activeColor);
153
155
  const inactiveC = style.resolveThemeTokenForNative(inactiveColor);
@@ -231,7 +233,7 @@ function BottomTabBar(rawProps) {
231
233
  /* @__PURE__ */ jsxRuntime.jsx(index_native.Icon, { name: iconName, size: 24, color }),
232
234
  item.badge != null && item.badge !== false && /* @__PURE__ */ jsxRuntime.jsx(Badge, { badge: item.badge, barBg: bg, dangerColor: danger })
233
235
  ] }),
234
- showLabels && item.label != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { numberOfLines: 1, style: { fontSize: 11, fontWeight: "500", color }, children: item.label })
236
+ showLabels && item.label != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { numberOfLines: 1, style: { fontSize: 11, fontWeight: "500", color, ...rtlLineHeight != null ? { lineHeight: rtlLineHeight } : {} }, children: item.label })
235
237
  ]
236
238
  },
237
239
  item.key
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/BottomTabBar/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {Pressable, Text, View} from \"react-native\";\nimport {useSafeAreaInsets} from \"react-native-safe-area-context\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport type {IBottomTabBarProps, ITabBarItem} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {Box} from \"../../primitives\";\nimport Flex from \"../../layout/Flex\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n// Mirrors the app's AMTabBar geometry (App/src/components/shared/layout).\nconst BAR_MIN_HEIGHT = 60;\nconst FAB_SIZE = 56;\n\nfunction Badge({badge, barBg, dangerColor}: {badge: number | boolean; barBg: string; dangerColor: string}) {\n const isDot = badge === true || badge === 0;\n if (isDot) {\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -2,\n right: -2,\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: dangerColor,\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n />\n );\n }\n const count = typeof badge === \"number\" ? (badge > 99 ? \"99+\" : String(badge)) : \"\";\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -6,\n right: -10,\n minWidth: 16,\n height: 16,\n borderRadius: 8,\n paddingHorizontal: 4,\n backgroundColor: dangerColor,\n alignItems: \"center\",\n justifyContent: \"center\",\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n >\n <Text style={{color: \"#FFFFFF\", fontSize: 9, fontWeight: \"700\", lineHeight: 11}}>{count}</Text>\n </Box>\n );\n}\n\n/**\n * BottomTabBar — iOS/Android bottom navigation with an elevated center FAB.\n *\n * Layout mirrors the app's working `AMTabBar`: a `row` / `space-between` bar\n * with four `flex:1` **column** slots and a content-width centre slot holding\n * the FAB. The FAB is lifted with `marginTop:-26` and ringed with a 3px\n * border so it sits above the bar plane — never absolutely positioned.\n * Presentational + controlled (router-agnostic).\n */\nexport function BottomTabBar<K extends string = string>(rawProps: IBottomTabBarProps<K>) {\n const props = useComponentDefaults<IBottomTabBarProps<K>>(\"BottomTabBar\", rawProps).mergedProps;\n const {\n items,\n value,\n onChange,\n activeColor = \"brand\",\n inactiveColor = \"text-secondary\",\n background = \"surface-card\",\n fabColor,\n showLabels = true,\n testID,\n } = props;\n\n const insets = useSafeAreaInsets();\n\n // Resolve tokens → hex with the standalone resolver (the one `Icon` uses),\n // so colors apply on raw RN elements in both app and Storybook contexts.\n const activeC = resolveThemeTokenForNative(activeColor);\n const inactiveC = resolveThemeTokenForNative(inactiveColor);\n const bg = resolveThemeTokenForNative(background);\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fabBg = resolveThemeTokenForNative(fabColor ?? activeColor);\n const danger = resolveThemeTokenForNative(\"danger\");\n\n return (\n <View\n testID={testID}\n style={{\n width: \"100%\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n minHeight: BAR_MIN_HEIGHT,\n paddingHorizontal: 20,\n paddingTop: 10,\n paddingBottom: Math.max(insets.bottom, 12),\n backgroundColor: bg,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {items.map((item: ITabBarItem<K>) => {\n const active = item.key === value;\n\n // Centre FAB — a content-width slot (NOT flex:1) so the four\n // side slots distribute evenly; the FAB is lifted in-flow.\n if (item.fab) {\n return (\n <Flex key={item.key} style={{alignItems: \"center\", justifyContent: \"center\"}}>\n <Pressable\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n hitSlop={8}\n style={({pressed}) => [\n {\n width: FAB_SIZE,\n height: FAB_SIZE,\n borderRadius: FAB_SIZE / 2,\n marginTop: -26,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: fabBg,\n borderWidth: 3,\n borderColor: bg,\n shadowColor: fabBg,\n shadowOffset: {width: 0, height: 6},\n shadowOpacity: 0.35,\n shadowRadius: 12,\n elevation: 8,\n },\n pressed && {opacity: 0.9},\n ]}\n >\n <Icon name={item.icon as never} size={26} color=\"#FFFFFF\" />\n </Pressable>\n </Flex>\n );\n }\n\n const color = active ? activeC : inactiveC;\n const iconName = active && item.activeIcon != null ? item.activeIcon : item.icon;\n\n return (\n <Pressable\n key={item.key}\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n style={({pressed}) => [\n {\n flex: 1,\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 4,\n paddingVertical: 6,\n paddingHorizontal: 4,\n minHeight: 44,\n },\n pressed && {opacity: 0.7},\n ]}\n >\n <View style={{alignItems: \"center\", justifyContent: \"center\", position: \"relative\"}}>\n <Icon name={iconName as never} size={24} color={color} />\n {item.badge != null && item.badge !== false && (\n <Badge badge={item.badge} barBg={bg} dangerColor={danger} />\n )}\n </View>\n {showLabels && item.label != null && (\n <Text numberOfLines={1} style={{fontSize: 11, fontWeight: \"500\", color}}>\n {item.label}\n </Text>\n )}\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nexport default BottomTabBar;\n"],"names":["jsx","Box","Text","useComponentDefaults","useSafeAreaInsets","resolveThemeTokenForNative","View","Flex","Pressable","Icon","jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/BottomTabBar/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {Pressable, Text, View} from \"react-native\";\nimport {useSafeAreaInsets} from \"react-native-safe-area-context\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\nimport type {IBottomTabBarProps, ITabBarItem} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {Box} from \"../../primitives\";\nimport Flex from \"../../layout/Flex\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n// Mirrors the app's AMTabBar geometry (App/src/components/shared/layout).\nconst BAR_MIN_HEIGHT = 60;\nconst FAB_SIZE = 56;\n\nfunction Badge({badge, barBg, dangerColor}: {badge: number | boolean; barBg: string; dangerColor: string}) {\n const isDot = badge === true || badge === 0;\n if (isDot) {\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -2,\n right: -2,\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: dangerColor,\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n />\n );\n }\n const count = typeof badge === \"number\" ? (badge > 99 ? \"99+\" : String(badge)) : \"\";\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -6,\n right: -10,\n minWidth: 16,\n height: 16,\n borderRadius: 8,\n paddingHorizontal: 4,\n backgroundColor: dangerColor,\n alignItems: \"center\",\n justifyContent: \"center\",\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n >\n <Text style={{color: \"#FFFFFF\", fontSize: 9, fontWeight: \"700\", lineHeight: 11}}>{count}</Text>\n </Box>\n );\n}\n\n/**\n * BottomTabBar — iOS/Android bottom navigation with an elevated center FAB.\n *\n * Layout mirrors the app's working `AMTabBar`: a `row` / `space-between` bar\n * with four `flex:1` **column** slots and a content-width centre slot holding\n * the FAB. The FAB is lifted with `marginTop:-26` and ringed with a 3px\n * border so it sits above the bar plane — never absolutely positioned.\n * Presentational + controlled (router-agnostic).\n */\nexport function BottomTabBar<K extends string = string>(rawProps: IBottomTabBarProps<K>) {\n const props = useComponentDefaults<IBottomTabBarProps<K>>(\"BottomTabBar\", rawProps).mergedProps;\n const {\n items,\n value,\n onChange,\n activeColor = \"brand\",\n inactiveColor = \"text-secondary\",\n background = \"surface-card\",\n fabColor,\n showLabels = true,\n testID,\n } = props;\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX — a raw react-native <Text>\n * with a fontSize and no lineHeight gets the FONT'S natural box, and\n * NotoKufiArabic's is too short for its own ascenders. In an RTL script\n * that reads as a BAD TRANSLATION rather than as clipping: ش/س, غ/ع and\n * ة/ه differ only by marks above the baseline.\n * ⚠️ undefined in LTR, so no English layout moves.\n */\n const rtlLineHeight = useRtlLineHeight(undefined, 11);\n\n const insets = useSafeAreaInsets();\n\n // Resolve tokens → hex with the standalone resolver (the one `Icon` uses),\n // so colors apply on raw RN elements in both app and Storybook contexts.\n const activeC = resolveThemeTokenForNative(activeColor);\n const inactiveC = resolveThemeTokenForNative(inactiveColor);\n const bg = resolveThemeTokenForNative(background);\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fabBg = resolveThemeTokenForNative(fabColor ?? activeColor);\n const danger = resolveThemeTokenForNative(\"danger\");\n\n return (\n <View\n testID={testID}\n style={{\n width: \"100%\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n minHeight: BAR_MIN_HEIGHT,\n paddingHorizontal: 20,\n paddingTop: 10,\n paddingBottom: Math.max(insets.bottom, 12),\n backgroundColor: bg,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {items.map((item: ITabBarItem<K>) => {\n const active = item.key === value;\n\n // Centre FAB — a content-width slot (NOT flex:1) so the four\n // side slots distribute evenly; the FAB is lifted in-flow.\n if (item.fab) {\n return (\n <Flex key={item.key} style={{alignItems: \"center\", justifyContent: \"center\"}}>\n <Pressable\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n hitSlop={8}\n style={({pressed}) => [\n {\n width: FAB_SIZE,\n height: FAB_SIZE,\n borderRadius: FAB_SIZE / 2,\n marginTop: -26,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: fabBg,\n borderWidth: 3,\n borderColor: bg,\n shadowColor: fabBg,\n shadowOffset: {width: 0, height: 6},\n shadowOpacity: 0.35,\n shadowRadius: 12,\n elevation: 8,\n },\n pressed && {opacity: 0.9},\n ]}\n >\n <Icon name={item.icon as never} size={26} color=\"#FFFFFF\" />\n </Pressable>\n </Flex>\n );\n }\n\n const color = active ? activeC : inactiveC;\n const iconName = active && item.activeIcon != null ? item.activeIcon : item.icon;\n\n return (\n <Pressable\n key={item.key}\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n style={({pressed}) => [\n {\n flex: 1,\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 4,\n paddingVertical: 6,\n paddingHorizontal: 4,\n minHeight: 44,\n },\n pressed && {opacity: 0.7},\n ]}\n >\n <View style={{alignItems: \"center\", justifyContent: \"center\", position: \"relative\"}}>\n <Icon name={iconName as never} size={24} color={color} />\n {item.badge != null && item.badge !== false && (\n <Badge badge={item.badge} barBg={bg} dangerColor={danger} />\n )}\n </View>\n {showLabels && item.label != null && (\n <Text numberOfLines={1} style={{fontSize: 11, fontWeight: \"500\", color, ...(rtlLineHeight != null ? {lineHeight: rtlLineHeight} : {})}}>\n {item.label}\n </Text>\n )}\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nexport default BottomTabBar;\n"],"names":["jsx","Box","Text","useComponentDefaults","useRtlLineHeight","useSafeAreaInsets","resolveThemeTokenForNative","View","Flex","Pressable","Icon","jsxs"],"mappings":"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"}
@@ -81,6 +81,7 @@ import '../../apps/mobile/src/Core/RadioButton/index.js';
81
81
  import '../../apps/mobile/src/Core/Input/index.js';
82
82
  import '../../apps/mobile/src/Core/Input/Field.js';
83
83
  import '../../apps/mobile/src/Core/Input/Slot.js';
84
+ import useRtlLineHeight from '../../hooks/useRtlLineHeight.js';
84
85
  import Box from '../../primitives/Box/index.js';
85
86
  import { Icon } from '../../primitives/Icon/index.js';
86
87
  import Flex from '../../layout/Flex/index.js';
@@ -146,6 +147,7 @@ function BottomTabBar(rawProps) {
146
147
  showLabels = true,
147
148
  testID
148
149
  } = props;
150
+ const rtlLineHeight = useRtlLineHeight(void 0, 11);
149
151
  const insets = useSafeAreaInsets();
150
152
  const activeC = resolveThemeTokenForNative(activeColor);
151
153
  const inactiveC = resolveThemeTokenForNative(inactiveColor);
@@ -229,7 +231,7 @@ function BottomTabBar(rawProps) {
229
231
  /* @__PURE__ */ jsx(Icon, { name: iconName, size: 24, color }),
230
232
  item.badge != null && item.badge !== false && /* @__PURE__ */ jsx(Badge, { badge: item.badge, barBg: bg, dangerColor: danger })
231
233
  ] }),
232
- showLabels && item.label != null && /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: { fontSize: 11, fontWeight: "500", color }, children: item.label })
234
+ showLabels && item.label != null && /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: { fontSize: 11, fontWeight: "500", color, ...rtlLineHeight != null ? { lineHeight: rtlLineHeight } : {} }, children: item.label })
233
235
  ]
234
236
  },
235
237
  item.key
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/components/BottomTabBar/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {Pressable, Text, View} from \"react-native\";\nimport {useSafeAreaInsets} from \"react-native-safe-area-context\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport type {IBottomTabBarProps, ITabBarItem} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {Box} from \"../../primitives\";\nimport Flex from \"../../layout/Flex\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n// Mirrors the app's AMTabBar geometry (App/src/components/shared/layout).\nconst BAR_MIN_HEIGHT = 60;\nconst FAB_SIZE = 56;\n\nfunction Badge({badge, barBg, dangerColor}: {badge: number | boolean; barBg: string; dangerColor: string}) {\n const isDot = badge === true || badge === 0;\n if (isDot) {\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -2,\n right: -2,\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: dangerColor,\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n />\n );\n }\n const count = typeof badge === \"number\" ? (badge > 99 ? \"99+\" : String(badge)) : \"\";\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -6,\n right: -10,\n minWidth: 16,\n height: 16,\n borderRadius: 8,\n paddingHorizontal: 4,\n backgroundColor: dangerColor,\n alignItems: \"center\",\n justifyContent: \"center\",\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n >\n <Text style={{color: \"#FFFFFF\", fontSize: 9, fontWeight: \"700\", lineHeight: 11}}>{count}</Text>\n </Box>\n );\n}\n\n/**\n * BottomTabBar — iOS/Android bottom navigation with an elevated center FAB.\n *\n * Layout mirrors the app's working `AMTabBar`: a `row` / `space-between` bar\n * with four `flex:1` **column** slots and a content-width centre slot holding\n * the FAB. The FAB is lifted with `marginTop:-26` and ringed with a 3px\n * border so it sits above the bar plane — never absolutely positioned.\n * Presentational + controlled (router-agnostic).\n */\nexport function BottomTabBar<K extends string = string>(rawProps: IBottomTabBarProps<K>) {\n const props = useComponentDefaults<IBottomTabBarProps<K>>(\"BottomTabBar\", rawProps).mergedProps;\n const {\n items,\n value,\n onChange,\n activeColor = \"brand\",\n inactiveColor = \"text-secondary\",\n background = \"surface-card\",\n fabColor,\n showLabels = true,\n testID,\n } = props;\n\n const insets = useSafeAreaInsets();\n\n // Resolve tokens → hex with the standalone resolver (the one `Icon` uses),\n // so colors apply on raw RN elements in both app and Storybook contexts.\n const activeC = resolveThemeTokenForNative(activeColor);\n const inactiveC = resolveThemeTokenForNative(inactiveColor);\n const bg = resolveThemeTokenForNative(background);\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fabBg = resolveThemeTokenForNative(fabColor ?? activeColor);\n const danger = resolveThemeTokenForNative(\"danger\");\n\n return (\n <View\n testID={testID}\n style={{\n width: \"100%\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n minHeight: BAR_MIN_HEIGHT,\n paddingHorizontal: 20,\n paddingTop: 10,\n paddingBottom: Math.max(insets.bottom, 12),\n backgroundColor: bg,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {items.map((item: ITabBarItem<K>) => {\n const active = item.key === value;\n\n // Centre FAB — a content-width slot (NOT flex:1) so the four\n // side slots distribute evenly; the FAB is lifted in-flow.\n if (item.fab) {\n return (\n <Flex key={item.key} style={{alignItems: \"center\", justifyContent: \"center\"}}>\n <Pressable\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n hitSlop={8}\n style={({pressed}) => [\n {\n width: FAB_SIZE,\n height: FAB_SIZE,\n borderRadius: FAB_SIZE / 2,\n marginTop: -26,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: fabBg,\n borderWidth: 3,\n borderColor: bg,\n shadowColor: fabBg,\n shadowOffset: {width: 0, height: 6},\n shadowOpacity: 0.35,\n shadowRadius: 12,\n elevation: 8,\n },\n pressed && {opacity: 0.9},\n ]}\n >\n <Icon name={item.icon as never} size={26} color=\"#FFFFFF\" />\n </Pressable>\n </Flex>\n );\n }\n\n const color = active ? activeC : inactiveC;\n const iconName = active && item.activeIcon != null ? item.activeIcon : item.icon;\n\n return (\n <Pressable\n key={item.key}\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n style={({pressed}) => [\n {\n flex: 1,\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 4,\n paddingVertical: 6,\n paddingHorizontal: 4,\n minHeight: 44,\n },\n pressed && {opacity: 0.7},\n ]}\n >\n <View style={{alignItems: \"center\", justifyContent: \"center\", position: \"relative\"}}>\n <Icon name={iconName as never} size={24} color={color} />\n {item.badge != null && item.badge !== false && (\n <Badge badge={item.badge} barBg={bg} dangerColor={danger} />\n )}\n </View>\n {showLabels && item.label != null && (\n <Text numberOfLines={1} style={{fontSize: 11, fontWeight: \"500\", color}}>\n {item.label}\n </Text>\n )}\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nexport default BottomTabBar;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,MAAM,cAAA,GAAiB,EAAA;AACvB,MAAM,QAAA,GAAW,EAAA;AAEjB,SAAS,KAAA,CAAM,EAAC,KAAA,EAAO,KAAA,EAAO,aAAW,EAAkE;AACvG,EAAA,MAAM,KAAA,GAAQ,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,CAAA;AAC1C,EAAA,IAAI,KAAA,EAAO;AACP,IAAA,uBACI,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACG,KAAA,EAAO;AAAA,UACH,QAAA,EAAU,UAAA;AAAA,UACV,GAAA,EAAK,EAAA;AAAA,UACL,KAAA,EAAO,EAAA;AAAA,UACP,KAAA,EAAO,EAAA;AAAA,UACP,MAAA,EAAQ,EAAA;AAAA,UACR,YAAA,EAAc,CAAA;AAAA,UACd,eAAA,EAAiB,WAAA;AAAA,UACjB,WAAA,EAAa,GAAA;AAAA,UACb,WAAA,EAAa,KAAA;AAAA,UACb,MAAA,EAAQ;AAAA;AACZ;AAAA,KACJ;AAAA,EAER;AACA,EAAA,MAAM,KAAA,GAAQ,OAAO,KAAA,KAAU,QAAA,GAAY,QAAQ,EAAA,GAAK,KAAA,GAAQ,MAAA,CAAO,KAAK,CAAA,GAAK,EAAA;AACjF,EAAA,uBACI,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACG,KAAA,EAAO;AAAA,QACH,QAAA,EAAU,UAAA;AAAA,QACV,GAAA,EAAK,EAAA;AAAA,QACL,KAAA,EAAO,GAAA;AAAA,QACP,QAAA,EAAU,EAAA;AAAA,QACV,MAAA,EAAQ,EAAA;AAAA,QACR,YAAA,EAAc,CAAA;AAAA,QACd,iBAAA,EAAmB,CAAA;AAAA,QACnB,eAAA,EAAiB,WAAA;AAAA,QACjB,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,QAAA;AAAA,QAChB,WAAA,EAAa,GAAA;AAAA,QACb,WAAA,EAAa,KAAA;AAAA,QACb,MAAA,EAAQ;AAAA,OACZ;AAAA,MAEA,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,EAAC,KAAA,EAAO,SAAA,EAAW,QAAA,EAAU,CAAA,EAAG,UAAA,EAAY,KAAA,EAAO,UAAA,EAAY,EAAA,IAAM,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA,GAC5F;AAER;AAWO,SAAS,aAAwC,QAAA,EAAiC;AACrF,EAAA,MAAM,KAAA,GAAQ,oBAAA,CAA4C,cAAA,EAAgB,QAAQ,CAAA,CAAE,WAAA;AACpF,EAAA,MAAM;AAAA,IACF,KAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA,GAAc,OAAA;AAAA,IACd,aAAA,GAAgB,gBAAA;AAAA,IAChB,UAAA,GAAa,cAAA;AAAA,IACb,QAAA;AAAA,IACA,UAAA,GAAa,IAAA;AAAA,IACb;AAAA,GACJ,GAAI,KAAA;AAEJ,EAAA,MAAM,SAAS,iBAAA,EAAkB;AAIjC,EAAA,MAAM,OAAA,GAAU,2BAA2B,WAAW,CAAA;AACtD,EAAA,MAAM,SAAA,GAAY,2BAA2B,aAAa,CAAA;AAC1D,EAAA,MAAM,EAAA,GAAK,2BAA2B,UAAU,CAAA;AAChD,EAAA,MAAM,MAAA,GAAS,2BAA2B,gBAAgB,CAAA;AAC1D,EAAA,MAAM,KAAA,GAAQ,0BAAA,CAA2B,QAAA,IAAY,WAAW,CAAA;AAChE,EAAA,MAAM,MAAA,GAAS,2BAA2B,QAAQ,CAAA;AAElD,EAAA,uBACI,GAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACG,MAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACH,KAAA,EAAO,MAAA;AAAA,QACP,aAAA,EAAe,KAAA;AAAA,QACf,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,eAAA;AAAA,QAChB,SAAA,EAAW,cAAA;AAAA,QACX,iBAAA,EAAmB,EAAA;AAAA,QACnB,UAAA,EAAY,EAAA;AAAA,QACZ,aAAA,EAAe,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,QAAQ,EAAE,CAAA;AAAA,QACzC,eAAA,EAAiB,EAAA;AAAA,QACjB,cAAA,EAAgB,CAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,OACpB;AAAA,MAEC,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAyB;AACjC,QAAA,MAAM,MAAA,GAAS,KAAK,GAAA,KAAQ,KAAA;AAI5B,QAAA,IAAI,KAAK,GAAA,EAAK;AACV,UAAA,uBACI,GAAA,CAAC,QAAoB,KAAA,EAAO,EAAC,YAAY,QAAA,EAAU,cAAA,EAAgB,UAAQ,EACvE,QAAA,kBAAA,GAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACG,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAAA,cAChC,iBAAA,EAAkB,QAAA;AAAA,cAClB,kBAAA,EAAoB,EAAC,QAAA,EAAU,MAAA,EAAM;AAAA,cACrC,OAAA,EAAS,CAAA;AAAA,cACT,KAAA,EAAO,CAAC,EAAC,OAAA,EAAO,KAAM;AAAA,gBAClB;AAAA,kBACI,KAAA,EAAO,QAAA;AAAA,kBACP,MAAA,EAAQ,QAAA;AAAA,kBACR,cAAc,QAAA,GAAW,CAAA;AAAA,kBACzB,SAAA,EAAW,GAAA;AAAA,kBACX,UAAA,EAAY,QAAA;AAAA,kBACZ,cAAA,EAAgB,QAAA;AAAA,kBAChB,eAAA,EAAiB,KAAA;AAAA,kBACjB,WAAA,EAAa,CAAA;AAAA,kBACb,WAAA,EAAa,EAAA;AAAA,kBACb,WAAA,EAAa,KAAA;AAAA,kBACb,YAAA,EAAc,EAAC,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,EAAC;AAAA,kBAClC,aAAA,EAAe,IAAA;AAAA,kBACf,YAAA,EAAc,EAAA;AAAA,kBACd,SAAA,EAAW;AAAA,iBACf;AAAA,gBACA,OAAA,IAAW,EAAC,OAAA,EAAS,GAAA;AAAG,eAC5B;AAAA,cAEA,QAAA,kBAAA,GAAA,CAAC,QAAK,IAAA,EAAM,IAAA,CAAK,MAAe,IAAA,EAAM,EAAA,EAAI,OAAM,SAAA,EAAU;AAAA;AAAA,WAC9D,EAAA,EA3BO,KAAK,GA4BhB,CAAA;AAAA,QAER;AAEA,QAAA,MAAM,KAAA,GAAQ,SAAS,OAAA,GAAU,SAAA;AACjC,QAAA,MAAM,WAAW,MAAA,IAAU,IAAA,CAAK,cAAc,IAAA,GAAO,IAAA,CAAK,aAAa,IAAA,CAAK,IAAA;AAE5E,QAAA,uBACI,IAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YAEG,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAAA,YAChC,iBAAA,EAAkB,QAAA;AAAA,YAClB,kBAAA,EAAoB,EAAC,QAAA,EAAU,MAAA,EAAM;AAAA,YACrC,KAAA,EAAO,CAAC,EAAC,OAAA,EAAO,KAAM;AAAA,cAClB;AAAA,gBACI,IAAA,EAAM,CAAA;AAAA,gBACN,aAAA,EAAe,QAAA;AAAA,gBACf,UAAA,EAAY,QAAA;AAAA,gBACZ,cAAA,EAAgB,QAAA;AAAA,gBAChB,GAAA,EAAK,CAAA;AAAA,gBACL,eAAA,EAAiB,CAAA;AAAA,gBACjB,iBAAA,EAAmB,CAAA;AAAA,gBACnB,SAAA,EAAW;AAAA,eACf;AAAA,cACA,OAAA,IAAW,EAAC,OAAA,EAAS,GAAA;AAAG,aAC5B;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,IAAA,CAAC,IAAA,EAAA,EAAK,OAAO,EAAC,UAAA,EAAY,UAAU,cAAA,EAAgB,QAAA,EAAU,QAAA,EAAU,UAAA,EAAU,EAC9E,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAM,QAAA,EAAmB,IAAA,EAAM,IAAI,KAAA,EAAc,CAAA;AAAA,gBACtD,IAAA,CAAK,KAAA,IAAS,IAAA,IAAQ,IAAA,CAAK,UAAU,KAAA,oBAClC,GAAA,CAAC,KAAA,EAAA,EAAM,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,KAAA,EAAO,EAAA,EAAI,aAAa,MAAA,EAAQ;AAAA,eAAA,EAElE,CAAA;AAAA,cACC,cAAc,IAAA,CAAK,KAAA,IAAS,IAAA,oBACzB,GAAA,CAAC,QAAK,aAAA,EAAe,CAAA,EAAG,KAAA,EAAO,EAAC,UAAU,EAAA,EAAI,UAAA,EAAY,OAAO,KAAA,EAAK,EACjE,eAAK,KAAA,EACV;AAAA;AAAA,WAAA;AAAA,UA3BC,IAAA,CAAK;AAAA,SA6Bd;AAAA,MAER,CAAC;AAAA;AAAA,GACL;AAER;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/BottomTabBar/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {Pressable, Text, View} from \"react-native\";\nimport {useSafeAreaInsets} from \"react-native-safe-area-context\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\nimport type {IBottomTabBarProps, ITabBarItem} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {Box} from \"../../primitives\";\nimport Flex from \"../../layout/Flex\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n// Mirrors the app's AMTabBar geometry (App/src/components/shared/layout).\nconst BAR_MIN_HEIGHT = 60;\nconst FAB_SIZE = 56;\n\nfunction Badge({badge, barBg, dangerColor}: {badge: number | boolean; barBg: string; dangerColor: string}) {\n const isDot = badge === true || badge === 0;\n if (isDot) {\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -2,\n right: -2,\n width: 10,\n height: 10,\n borderRadius: 5,\n backgroundColor: dangerColor,\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n />\n );\n }\n const count = typeof badge === \"number\" ? (badge > 99 ? \"99+\" : String(badge)) : \"\";\n return (\n <Box\n style={{\n position: \"absolute\",\n top: -6,\n right: -10,\n minWidth: 16,\n height: 16,\n borderRadius: 8,\n paddingHorizontal: 4,\n backgroundColor: dangerColor,\n alignItems: \"center\",\n justifyContent: \"center\",\n borderWidth: 1.5,\n borderColor: barBg,\n zIndex: 10,\n }}\n >\n <Text style={{color: \"#FFFFFF\", fontSize: 9, fontWeight: \"700\", lineHeight: 11}}>{count}</Text>\n </Box>\n );\n}\n\n/**\n * BottomTabBar — iOS/Android bottom navigation with an elevated center FAB.\n *\n * Layout mirrors the app's working `AMTabBar`: a `row` / `space-between` bar\n * with four `flex:1` **column** slots and a content-width centre slot holding\n * the FAB. The FAB is lifted with `marginTop:-26` and ringed with a 3px\n * border so it sits above the bar plane — never absolutely positioned.\n * Presentational + controlled (router-agnostic).\n */\nexport function BottomTabBar<K extends string = string>(rawProps: IBottomTabBarProps<K>) {\n const props = useComponentDefaults<IBottomTabBarProps<K>>(\"BottomTabBar\", rawProps).mergedProps;\n const {\n items,\n value,\n onChange,\n activeColor = \"brand\",\n inactiveColor = \"text-secondary\",\n background = \"surface-card\",\n fabColor,\n showLabels = true,\n testID,\n } = props;\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX — a raw react-native <Text>\n * with a fontSize and no lineHeight gets the FONT'S natural box, and\n * NotoKufiArabic's is too short for its own ascenders. In an RTL script\n * that reads as a BAD TRANSLATION rather than as clipping: ش/س, غ/ع and\n * ة/ه differ only by marks above the baseline.\n * ⚠️ undefined in LTR, so no English layout moves.\n */\n const rtlLineHeight = useRtlLineHeight(undefined, 11);\n\n const insets = useSafeAreaInsets();\n\n // Resolve tokens → hex with the standalone resolver (the one `Icon` uses),\n // so colors apply on raw RN elements in both app and Storybook contexts.\n const activeC = resolveThemeTokenForNative(activeColor);\n const inactiveC = resolveThemeTokenForNative(inactiveColor);\n const bg = resolveThemeTokenForNative(background);\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fabBg = resolveThemeTokenForNative(fabColor ?? activeColor);\n const danger = resolveThemeTokenForNative(\"danger\");\n\n return (\n <View\n testID={testID}\n style={{\n width: \"100%\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n minHeight: BAR_MIN_HEIGHT,\n paddingHorizontal: 20,\n paddingTop: 10,\n paddingBottom: Math.max(insets.bottom, 12),\n backgroundColor: bg,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {items.map((item: ITabBarItem<K>) => {\n const active = item.key === value;\n\n // Centre FAB — a content-width slot (NOT flex:1) so the four\n // side slots distribute evenly; the FAB is lifted in-flow.\n if (item.fab) {\n return (\n <Flex key={item.key} style={{alignItems: \"center\", justifyContent: \"center\"}}>\n <Pressable\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n hitSlop={8}\n style={({pressed}) => [\n {\n width: FAB_SIZE,\n height: FAB_SIZE,\n borderRadius: FAB_SIZE / 2,\n marginTop: -26,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: fabBg,\n borderWidth: 3,\n borderColor: bg,\n shadowColor: fabBg,\n shadowOffset: {width: 0, height: 6},\n shadowOpacity: 0.35,\n shadowRadius: 12,\n elevation: 8,\n },\n pressed && {opacity: 0.9},\n ]}\n >\n <Icon name={item.icon as never} size={26} color=\"#FFFFFF\" />\n </Pressable>\n </Flex>\n );\n }\n\n const color = active ? activeC : inactiveC;\n const iconName = active && item.activeIcon != null ? item.activeIcon : item.icon;\n\n return (\n <Pressable\n key={item.key}\n onPress={() => onChange(item.key)}\n accessibilityRole=\"button\"\n accessibilityState={{selected: active}}\n style={({pressed}) => [\n {\n flex: 1,\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 4,\n paddingVertical: 6,\n paddingHorizontal: 4,\n minHeight: 44,\n },\n pressed && {opacity: 0.7},\n ]}\n >\n <View style={{alignItems: \"center\", justifyContent: \"center\", position: \"relative\"}}>\n <Icon name={iconName as never} size={24} color={color} />\n {item.badge != null && item.badge !== false && (\n <Badge badge={item.badge} barBg={bg} dangerColor={danger} />\n )}\n </View>\n {showLabels && item.label != null && (\n <Text numberOfLines={1} style={{fontSize: 11, fontWeight: \"500\", color, ...(rtlLineHeight != null ? {lineHeight: rtlLineHeight} : {})}}>\n {item.label}\n </Text>\n )}\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nexport default BottomTabBar;\n"],"names":[],"mappings":"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"}
@@ -83,6 +83,7 @@ require('../../apps/mobile/src/Core/RadioButton/index.cjs');
83
83
  require('../../apps/mobile/src/Core/Input/index.cjs');
84
84
  require('../../apps/mobile/src/Core/Input/Field.cjs');
85
85
  require('../../apps/mobile/src/Core/Input/Slot.cjs');
86
+ var useRtlLineHeight = require('../../hooks/useRtlLineHeight.cjs');
86
87
  var index_native = require('../../primitives/Icon/index.cjs');
87
88
  require('../../contexts/DialogContext.cjs');
88
89
  var useComponentDefaults = require('../../hooks/useComponentDefaults.cjs');
@@ -97,6 +98,8 @@ function MessageComposer(rawProps) {
97
98
  const textColor = style.resolveThemeTokenForNative("text");
98
99
  const muted = style.resolveThemeTokenForNative("text-secondary");
99
100
  const disabledBg = style.resolveThemeTokenForNative("gray.300");
101
+ const rtlLockedLine = useRtlLineHeight.default(void 0, 13);
102
+ const rtlHintLine = useRtlLineHeight.default(void 0, 11);
100
103
  if (locked) {
101
104
  return /* @__PURE__ */ jsxRuntime.jsx(
102
105
  reactNative.View,
@@ -128,7 +131,7 @@ function MessageComposer(rawProps) {
128
131
  },
129
132
  children: [
130
133
  /* @__PURE__ */ jsxRuntime.jsx(index_native.Icon, { name: "lock", size: 17, color: muted }),
131
- lockedLabel != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 13, color: muted }, children: lockedLabel })
134
+ lockedLabel != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 13, color: muted, ...rtlLockedLine != null ? { lineHeight: rtlLockedLine } : {} }, children: lockedLabel })
132
135
  ]
133
136
  }
134
137
  )
@@ -197,7 +200,7 @@ function MessageComposer(rawProps) {
197
200
  children: [
198
201
  attachHint != null && /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: 12, paddingBottom: 8 }, children: [
199
202
  /* @__PURE__ */ jsxRuntime.jsx(index_native.Icon, { name: "info", size: 12, color: muted }),
200
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 11, color: muted }, children: attachHint })
203
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 11, color: muted, ...rtlHintLine != null ? { lineHeight: rtlHintLine } : {} }, children: attachHint })
201
204
  ] }),
202
205
  /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", alignItems: "flex-end", gap: 8, paddingHorizontal: 12 }, children: [
203
206
  onAttach != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 36, height: 36, alignItems: "center", justifyContent: "center", opacity: 0.5 }, children: /* @__PURE__ */ jsxRuntime.jsx(index_native.Icon, { name: "paperclip", size: 20, color: muted }) }),
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/MessageComposer/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {View, Text, TextInput, TouchableOpacity} from \"react-native\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport type {IMessageComposerProps} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n/**\n * MessageComposer (native) — attach + multiline input + send, mirroring the\n * app's chat input bar (RN TextInput + TouchableOpacity, library Icon).\n */\nexport function MessageComposer(rawProps: IMessageComposerProps) {\n const props = useComponentDefaults<IMessageComposerProps>(\"MessageComposer\", rawProps).mergedProps;\n const {value, onChangeText, onSend, onAttach, placeholder = \"Message…\", sendDisabled, accentColor = \"brand\", locked, lockedLabel, attachDisabled, attachHint, onSelectionChange, selection, inputRef, testID} = props;\n\n const accent = resolveThemeTokenForNative(accentColor);\n const surface = resolveThemeTokenForNative(\"surface-card\");\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fieldBg = resolveThemeTokenForNative(\"gray.100\");\n const textColor = resolveThemeTokenForNative(\"text\");\n const muted = resolveThemeTokenForNative(\"text-secondary\");\n const disabledBg = resolveThemeTokenForNative(\"gray.300\");\n\n if (locked) {\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n <View\n style={{\n flexGrow: 1,\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: fieldBg,\n borderWidth: 1,\n borderColor: border,\n borderRadius: 999,\n paddingHorizontal: 16,\n paddingVertical: 11,\n }}\n >\n <Icon name=\"lock\" size={17} color={muted} />\n {lockedLabel != null && <Text style={{fontSize: 13, color: muted}}>{lockedLabel}</Text>}\n </View>\n </View>\n );\n }\n\n const canSend = sendDisabled != null ? !sendDisabled : value.trim().length > 0;\n\n // Shared field + send (referenced by the default row AND the attach-disabled\n // branch — single source, so the input is never duplicated).\n //\n // onSelectionChange is adapted from RN's NativeSyntheticEvent shape to the\n // platform-agnostic {start, end} contract declared on IMessageComposerProps,\n // so consumers (e.g. @mention pickers) read the same shape on native and web.\n const field = (\n <TextInput\n ref={inputRef as React.Ref<TextInput>}\n style={{\n flex: 1,\n backgroundColor: fieldBg,\n borderRadius: 20,\n paddingHorizontal: 14,\n paddingVertical: 8,\n fontSize: 14,\n color: textColor,\n // Pin a single-line floor (= the 36px send button) so a\n // multiline RN TextInput doesn't measure a taller default on\n // frame 1 then settle on frame 2 — that re-measure re-flexes\n // the chat thread above it (a small shift-then-settle on open).\n // Still grows up to maxHeight when typing multiple lines.\n minHeight: 36,\n maxHeight: 120,\n }}\n placeholder={placeholder}\n placeholderTextColor={muted}\n value={value}\n onChangeText={onChangeText}\n selection={selection as {start: number; end?: number} | undefined}\n onSelectionChange={\n onSelectionChange\n ? e => onSelectionChange({start: e.nativeEvent.selection.start, end: e.nativeEvent.selection.end})\n : undefined\n }\n multiline\n />\n );\n\n const sendBtn = (\n <TouchableOpacity\n onPress={() => canSend && onSend?.()}\n disabled={!canSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send\"\n style={{\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: canSend ? accent : disabledBg,\n }}\n >\n <Icon name=\"send\" size={18} color=\"#FFFFFF\" />\n </TouchableOpacity>\n );\n\n if (attachDisabled) {\n return (\n <View\n testID={testID}\n style={{\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {attachHint != null && (\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 6, paddingHorizontal: 12, paddingBottom: 8}}>\n <Icon name=\"info\" size={12} color={muted} />\n <Text style={{fontSize: 11, color: muted}}>{attachHint}</Text>\n </View>\n )}\n <View style={{flexDirection: \"row\", alignItems: \"flex-end\", gap: 8, paddingHorizontal: 12}}>\n {onAttach != null && (\n <View style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\", opacity: 0.5}}>\n <Icon name=\"paperclip\" size={20} color={muted} />\n </View>\n )}\n {field}\n {sendBtn}\n </View>\n </View>\n );\n }\n\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"flex-end\",\n gap: 8,\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {onAttach != null && (\n <TouchableOpacity\n onPress={onAttach}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Attach\"\n style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\"}}\n >\n <Icon name=\"paperclip\" size={20} color={muted} />\n </TouchableOpacity>\n )}\n {field}\n {sendBtn}\n </View>\n );\n}\n\nexport default MessageComposer;\n"],"names":["useComponentDefaults","resolveThemeTokenForNative","jsx","View","jsxs","Icon","Text","TextInput","TouchableOpacity"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/MessageComposer/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {View, Text, TextInput, TouchableOpacity} from \"react-native\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\nimport type {IMessageComposerProps} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n/**\n * MessageComposer (native) — attach + multiline input + send, mirroring the\n * app's chat input bar (RN TextInput + TouchableOpacity, library Icon).\n */\nexport function MessageComposer(rawProps: IMessageComposerProps) {\n const props = useComponentDefaults<IMessageComposerProps>(\"MessageComposer\", rawProps).mergedProps;\n const {value, onChangeText, onSend, onAttach, placeholder = \"Message…\", sendDisabled, accentColor = \"brand\", locked, lockedLabel, attachDisabled, attachHint, onSelectionChange, selection, inputRef, testID} = props;\n\n const accent = resolveThemeTokenForNative(accentColor);\n const surface = resolveThemeTokenForNative(\"surface-card\");\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fieldBg = resolveThemeTokenForNative(\"gray.100\");\n const textColor = resolveThemeTokenForNative(\"text\");\n const muted = resolveThemeTokenForNative(\"text-secondary\");\n const disabledBg = resolveThemeTokenForNative(\"gray.300\");\n\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX. These render RAW\n * react-native <Text> with a fontSize and no lineHeight, so React Native\n * uses the FONT'S natural box — and NotoKufiArabic's is too short for its\n * own ascenders. In an RTL script that does not read as clipping, it reads\n * as a BAD TRANSLATION: ش/س, غ/ع and ة/ه differ only by marks above the\n * baseline. Both are undefined in LTR, so no English layout moves.\n *\n * ⚠️ THE INPUT ITSELF IS DELIBERATELY NOT TOUCHED. The TextInput below is\n * fontSize 14 with no lineHeight for the same reason, but it also carries\n * a hand-tuned single-line height floor and a comment about a two-frame\n * re-measure. Giving it a taller line box without being able to TYPE\n * Arabic into it and watch the field settle would be guessing at the one\n * control a person uses most. Recorded, not changed.\n */\n const rtlLockedLine = useRtlLineHeight(undefined, 13);\n const rtlHintLine = useRtlLineHeight(undefined, 11);\n\n if (locked) {\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n <View\n style={{\n flexGrow: 1,\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: fieldBg,\n borderWidth: 1,\n borderColor: border,\n borderRadius: 999,\n paddingHorizontal: 16,\n paddingVertical: 11,\n }}\n >\n <Icon name=\"lock\" size={17} color={muted} />\n {lockedLabel != null && <Text style={{fontSize: 13, color: muted, ...(rtlLockedLine != null ? {lineHeight: rtlLockedLine} : {})}}>{lockedLabel}</Text>}\n </View>\n </View>\n );\n }\n\n const canSend = sendDisabled != null ? !sendDisabled : value.trim().length > 0;\n\n // Shared field + send (referenced by the default row AND the attach-disabled\n // branch — single source, so the input is never duplicated).\n //\n // onSelectionChange is adapted from RN's NativeSyntheticEvent shape to the\n // platform-agnostic {start, end} contract declared on IMessageComposerProps,\n // so consumers (e.g. @mention pickers) read the same shape on native and web.\n const field = (\n <TextInput\n ref={inputRef as React.Ref<TextInput>}\n style={{\n flex: 1,\n backgroundColor: fieldBg,\n borderRadius: 20,\n paddingHorizontal: 14,\n paddingVertical: 8,\n fontSize: 14,\n color: textColor,\n // Pin a single-line floor (= the 36px send button) so a\n // multiline RN TextInput doesn't measure a taller default on\n // frame 1 then settle on frame 2 — that re-measure re-flexes\n // the chat thread above it (a small shift-then-settle on open).\n // Still grows up to maxHeight when typing multiple lines.\n minHeight: 36,\n maxHeight: 120,\n }}\n placeholder={placeholder}\n placeholderTextColor={muted}\n value={value}\n onChangeText={onChangeText}\n selection={selection as {start: number; end?: number} | undefined}\n onSelectionChange={\n onSelectionChange\n ? e => onSelectionChange({start: e.nativeEvent.selection.start, end: e.nativeEvent.selection.end})\n : undefined\n }\n multiline\n />\n );\n\n const sendBtn = (\n <TouchableOpacity\n onPress={() => canSend && onSend?.()}\n disabled={!canSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send\"\n style={{\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: canSend ? accent : disabledBg,\n }}\n >\n <Icon name=\"send\" size={18} color=\"#FFFFFF\" />\n </TouchableOpacity>\n );\n\n if (attachDisabled) {\n return (\n <View\n testID={testID}\n style={{\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {attachHint != null && (\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 6, paddingHorizontal: 12, paddingBottom: 8}}>\n <Icon name=\"info\" size={12} color={muted} />\n <Text style={{fontSize: 11, color: muted, ...(rtlHintLine != null ? {lineHeight: rtlHintLine} : {})}}>{attachHint}</Text>\n </View>\n )}\n <View style={{flexDirection: \"row\", alignItems: \"flex-end\", gap: 8, paddingHorizontal: 12}}>\n {onAttach != null && (\n <View style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\", opacity: 0.5}}>\n <Icon name=\"paperclip\" size={20} color={muted} />\n </View>\n )}\n {field}\n {sendBtn}\n </View>\n </View>\n );\n }\n\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"flex-end\",\n gap: 8,\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {onAttach != null && (\n <TouchableOpacity\n onPress={onAttach}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Attach\"\n style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\"}}\n >\n <Icon name=\"paperclip\" size={20} color={muted} />\n </TouchableOpacity>\n )}\n {field}\n {sendBtn}\n </View>\n );\n}\n\nexport default MessageComposer;\n"],"names":["useComponentDefaults","resolveThemeTokenForNative","useRtlLineHeight","jsx","View","jsxs","Icon","Text","TextInput","TouchableOpacity"],"mappings":"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"}
@@ -81,6 +81,7 @@ import '../../apps/mobile/src/Core/RadioButton/index.js';
81
81
  import '../../apps/mobile/src/Core/Input/index.js';
82
82
  import '../../apps/mobile/src/Core/Input/Field.js';
83
83
  import '../../apps/mobile/src/Core/Input/Slot.js';
84
+ import useRtlLineHeight from '../../hooks/useRtlLineHeight.js';
84
85
  import { Icon } from '../../primitives/Icon/index.js';
85
86
  import '../../contexts/DialogContext.js';
86
87
  import useComponentDefaults from '../../hooks/useComponentDefaults.js';
@@ -95,6 +96,8 @@ function MessageComposer(rawProps) {
95
96
  const textColor = resolveThemeTokenForNative("text");
96
97
  const muted = resolveThemeTokenForNative("text-secondary");
97
98
  const disabledBg = resolveThemeTokenForNative("gray.300");
99
+ const rtlLockedLine = useRtlLineHeight(void 0, 13);
100
+ const rtlHintLine = useRtlLineHeight(void 0, 11);
98
101
  if (locked) {
99
102
  return /* @__PURE__ */ jsx(
100
103
  View,
@@ -126,7 +129,7 @@ function MessageComposer(rawProps) {
126
129
  },
127
130
  children: [
128
131
  /* @__PURE__ */ jsx(Icon, { name: "lock", size: 17, color: muted }),
129
- lockedLabel != null && /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, color: muted }, children: lockedLabel })
132
+ lockedLabel != null && /* @__PURE__ */ jsx(Text, { style: { fontSize: 13, color: muted, ...rtlLockedLine != null ? { lineHeight: rtlLockedLine } : {} }, children: lockedLabel })
130
133
  ]
131
134
  }
132
135
  )
@@ -195,7 +198,7 @@ function MessageComposer(rawProps) {
195
198
  children: [
196
199
  attachHint != null && /* @__PURE__ */ jsxs(View, { style: { flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: 12, paddingBottom: 8 }, children: [
197
200
  /* @__PURE__ */ jsx(Icon, { name: "info", size: 12, color: muted }),
198
- /* @__PURE__ */ jsx(Text, { style: { fontSize: 11, color: muted }, children: attachHint })
201
+ /* @__PURE__ */ jsx(Text, { style: { fontSize: 11, color: muted, ...rtlHintLine != null ? { lineHeight: rtlHintLine } : {} }, children: attachHint })
199
202
  ] }),
200
203
  /* @__PURE__ */ jsxs(View, { style: { flexDirection: "row", alignItems: "flex-end", gap: 8, paddingHorizontal: 12 }, children: [
201
204
  onAttach != null && /* @__PURE__ */ jsx(View, { style: { width: 36, height: 36, alignItems: "center", justifyContent: "center", opacity: 0.5 }, children: /* @__PURE__ */ jsx(Icon, { name: "paperclip", size: 20, color: muted }) }),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/components/MessageComposer/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {View, Text, TextInput, TouchableOpacity} from \"react-native\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport type {IMessageComposerProps} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n/**\n * MessageComposer (native) — attach + multiline input + send, mirroring the\n * app's chat input bar (RN TextInput + TouchableOpacity, library Icon).\n */\nexport function MessageComposer(rawProps: IMessageComposerProps) {\n const props = useComponentDefaults<IMessageComposerProps>(\"MessageComposer\", rawProps).mergedProps;\n const {value, onChangeText, onSend, onAttach, placeholder = \"Message…\", sendDisabled, accentColor = \"brand\", locked, lockedLabel, attachDisabled, attachHint, onSelectionChange, selection, inputRef, testID} = props;\n\n const accent = resolveThemeTokenForNative(accentColor);\n const surface = resolveThemeTokenForNative(\"surface-card\");\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fieldBg = resolveThemeTokenForNative(\"gray.100\");\n const textColor = resolveThemeTokenForNative(\"text\");\n const muted = resolveThemeTokenForNative(\"text-secondary\");\n const disabledBg = resolveThemeTokenForNative(\"gray.300\");\n\n if (locked) {\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n <View\n style={{\n flexGrow: 1,\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: fieldBg,\n borderWidth: 1,\n borderColor: border,\n borderRadius: 999,\n paddingHorizontal: 16,\n paddingVertical: 11,\n }}\n >\n <Icon name=\"lock\" size={17} color={muted} />\n {lockedLabel != null && <Text style={{fontSize: 13, color: muted}}>{lockedLabel}</Text>}\n </View>\n </View>\n );\n }\n\n const canSend = sendDisabled != null ? !sendDisabled : value.trim().length > 0;\n\n // Shared field + send (referenced by the default row AND the attach-disabled\n // branch — single source, so the input is never duplicated).\n //\n // onSelectionChange is adapted from RN's NativeSyntheticEvent shape to the\n // platform-agnostic {start, end} contract declared on IMessageComposerProps,\n // so consumers (e.g. @mention pickers) read the same shape on native and web.\n const field = (\n <TextInput\n ref={inputRef as React.Ref<TextInput>}\n style={{\n flex: 1,\n backgroundColor: fieldBg,\n borderRadius: 20,\n paddingHorizontal: 14,\n paddingVertical: 8,\n fontSize: 14,\n color: textColor,\n // Pin a single-line floor (= the 36px send button) so a\n // multiline RN TextInput doesn't measure a taller default on\n // frame 1 then settle on frame 2 — that re-measure re-flexes\n // the chat thread above it (a small shift-then-settle on open).\n // Still grows up to maxHeight when typing multiple lines.\n minHeight: 36,\n maxHeight: 120,\n }}\n placeholder={placeholder}\n placeholderTextColor={muted}\n value={value}\n onChangeText={onChangeText}\n selection={selection as {start: number; end?: number} | undefined}\n onSelectionChange={\n onSelectionChange\n ? e => onSelectionChange({start: e.nativeEvent.selection.start, end: e.nativeEvent.selection.end})\n : undefined\n }\n multiline\n />\n );\n\n const sendBtn = (\n <TouchableOpacity\n onPress={() => canSend && onSend?.()}\n disabled={!canSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send\"\n style={{\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: canSend ? accent : disabledBg,\n }}\n >\n <Icon name=\"send\" size={18} color=\"#FFFFFF\" />\n </TouchableOpacity>\n );\n\n if (attachDisabled) {\n return (\n <View\n testID={testID}\n style={{\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {attachHint != null && (\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 6, paddingHorizontal: 12, paddingBottom: 8}}>\n <Icon name=\"info\" size={12} color={muted} />\n <Text style={{fontSize: 11, color: muted}}>{attachHint}</Text>\n </View>\n )}\n <View style={{flexDirection: \"row\", alignItems: \"flex-end\", gap: 8, paddingHorizontal: 12}}>\n {onAttach != null && (\n <View style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\", opacity: 0.5}}>\n <Icon name=\"paperclip\" size={20} color={muted} />\n </View>\n )}\n {field}\n {sendBtn}\n </View>\n </View>\n );\n }\n\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"flex-end\",\n gap: 8,\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {onAttach != null && (\n <TouchableOpacity\n onPress={onAttach}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Attach\"\n style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\"}}\n >\n <Icon name=\"paperclip\" size={20} color={muted} />\n </TouchableOpacity>\n )}\n {field}\n {sendBtn}\n </View>\n );\n}\n\nexport default MessageComposer;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/MessageComposer/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport {View, Text, TextInput, TouchableOpacity} from \"react-native\";\nimport {resolveThemeTokenForNative} from \"@lmb-it/kitsconcertomobile\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\nimport type {IMessageComposerProps} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n/**\n * MessageComposer (native) — attach + multiline input + send, mirroring the\n * app's chat input bar (RN TextInput + TouchableOpacity, library Icon).\n */\nexport function MessageComposer(rawProps: IMessageComposerProps) {\n const props = useComponentDefaults<IMessageComposerProps>(\"MessageComposer\", rawProps).mergedProps;\n const {value, onChangeText, onSend, onAttach, placeholder = \"Message…\", sendDisabled, accentColor = \"brand\", locked, lockedLabel, attachDisabled, attachHint, onSelectionChange, selection, inputRef, testID} = props;\n\n const accent = resolveThemeTokenForNative(accentColor);\n const surface = resolveThemeTokenForNative(\"surface-card\");\n const border = resolveThemeTokenForNative(\"surface-border\");\n const fieldBg = resolveThemeTokenForNative(\"gray.100\");\n const textColor = resolveThemeTokenForNative(\"text\");\n const muted = resolveThemeTokenForNative(\"text-secondary\");\n const disabledBg = resolveThemeTokenForNative(\"gray.300\");\n\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX. These render RAW\n * react-native <Text> with a fontSize and no lineHeight, so React Native\n * uses the FONT'S natural box — and NotoKufiArabic's is too short for its\n * own ascenders. In an RTL script that does not read as clipping, it reads\n * as a BAD TRANSLATION: ش/س, غ/ع and ة/ه differ only by marks above the\n * baseline. Both are undefined in LTR, so no English layout moves.\n *\n * ⚠️ THE INPUT ITSELF IS DELIBERATELY NOT TOUCHED. The TextInput below is\n * fontSize 14 with no lineHeight for the same reason, but it also carries\n * a hand-tuned single-line height floor and a comment about a two-frame\n * re-measure. Giving it a taller line box without being able to TYPE\n * Arabic into it and watch the field settle would be guessing at the one\n * control a person uses most. Recorded, not changed.\n */\n const rtlLockedLine = useRtlLineHeight(undefined, 13);\n const rtlHintLine = useRtlLineHeight(undefined, 11);\n\n if (locked) {\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n <View\n style={{\n flexGrow: 1,\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 10,\n backgroundColor: fieldBg,\n borderWidth: 1,\n borderColor: border,\n borderRadius: 999,\n paddingHorizontal: 16,\n paddingVertical: 11,\n }}\n >\n <Icon name=\"lock\" size={17} color={muted} />\n {lockedLabel != null && <Text style={{fontSize: 13, color: muted, ...(rtlLockedLine != null ? {lineHeight: rtlLockedLine} : {})}}>{lockedLabel}</Text>}\n </View>\n </View>\n );\n }\n\n const canSend = sendDisabled != null ? !sendDisabled : value.trim().length > 0;\n\n // Shared field + send (referenced by the default row AND the attach-disabled\n // branch — single source, so the input is never duplicated).\n //\n // onSelectionChange is adapted from RN's NativeSyntheticEvent shape to the\n // platform-agnostic {start, end} contract declared on IMessageComposerProps,\n // so consumers (e.g. @mention pickers) read the same shape on native and web.\n const field = (\n <TextInput\n ref={inputRef as React.Ref<TextInput>}\n style={{\n flex: 1,\n backgroundColor: fieldBg,\n borderRadius: 20,\n paddingHorizontal: 14,\n paddingVertical: 8,\n fontSize: 14,\n color: textColor,\n // Pin a single-line floor (= the 36px send button) so a\n // multiline RN TextInput doesn't measure a taller default on\n // frame 1 then settle on frame 2 — that re-measure re-flexes\n // the chat thread above it (a small shift-then-settle on open).\n // Still grows up to maxHeight when typing multiple lines.\n minHeight: 36,\n maxHeight: 120,\n }}\n placeholder={placeholder}\n placeholderTextColor={muted}\n value={value}\n onChangeText={onChangeText}\n selection={selection as {start: number; end?: number} | undefined}\n onSelectionChange={\n onSelectionChange\n ? e => onSelectionChange({start: e.nativeEvent.selection.start, end: e.nativeEvent.selection.end})\n : undefined\n }\n multiline\n />\n );\n\n const sendBtn = (\n <TouchableOpacity\n onPress={() => canSend && onSend?.()}\n disabled={!canSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send\"\n style={{\n width: 36,\n height: 36,\n borderRadius: 18,\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: canSend ? accent : disabledBg,\n }}\n >\n <Icon name=\"send\" size={18} color=\"#FFFFFF\" />\n </TouchableOpacity>\n );\n\n if (attachDisabled) {\n return (\n <View\n testID={testID}\n style={{\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {attachHint != null && (\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 6, paddingHorizontal: 12, paddingBottom: 8}}>\n <Icon name=\"info\" size={12} color={muted} />\n <Text style={{fontSize: 11, color: muted, ...(rtlHintLine != null ? {lineHeight: rtlHintLine} : {})}}>{attachHint}</Text>\n </View>\n )}\n <View style={{flexDirection: \"row\", alignItems: \"flex-end\", gap: 8, paddingHorizontal: 12}}>\n {onAttach != null && (\n <View style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\", opacity: 0.5}}>\n <Icon name=\"paperclip\" size={20} color={muted} />\n </View>\n )}\n {field}\n {sendBtn}\n </View>\n </View>\n );\n }\n\n return (\n <View\n testID={testID}\n style={{\n flexDirection: \"row\",\n alignItems: \"flex-end\",\n gap: 8,\n paddingHorizontal: 12,\n paddingVertical: 10,\n backgroundColor: surface,\n borderTopWidth: 1,\n borderTopColor: border,\n }}\n >\n {onAttach != null && (\n <TouchableOpacity\n onPress={onAttach}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Attach\"\n style={{width: 36, height: 36, alignItems: \"center\", justifyContent: \"center\"}}\n >\n <Icon name=\"paperclip\" size={20} color={muted} />\n </TouchableOpacity>\n )}\n {field}\n {sendBtn}\n </View>\n );\n}\n\nexport default MessageComposer;\n"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ var React = require('react');
5
5
  var reactNative = require('react-native');
6
6
  require('../../contexts/DialogContext.cjs');
7
7
  var useComponentDefaults = require('../../hooks/useComponentDefaults.cjs');
8
+ var useRtlLineHeight = require('../../hooks/useRtlLineHeight.cjs');
8
9
  var KitsThemeProvider_native = require('../../contexts/Theme/KitsThemeProvider.cjs');
9
10
 
10
11
  function TypingIndicator(rawProps) {
@@ -14,6 +15,7 @@ function TypingIndicator(rawProps) {
14
15
  const dot = resolveToken(dotColor);
15
16
  const bg = resolveToken(bubbleColor);
16
17
  const labelColor = resolveToken("text-secondary");
18
+ const rtlLineHeight = useRtlLineHeight.default(void 0, 11);
17
19
  const d0 = React.useRef(new reactNative.Animated.Value(0.3)).current;
18
20
  const d1 = React.useRef(new reactNative.Animated.Value(0.3)).current;
19
21
  const d2 = React.useRef(new reactNative.Animated.Value(0.3)).current;
@@ -33,7 +35,7 @@ function TypingIndicator(rawProps) {
33
35
  }, [d0, d1, d2]);
34
36
  const dots = /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { flexDirection: "row", gap: 5, alignItems: "center" }, children: [d0, d1, d2].map((v, i) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.Animated.View, { style: { width: 7, height: 7, borderRadius: 9999, backgroundColor: dot, opacity: v } }, i)) });
35
37
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { testID, style: { alignItems: "flex-start", gap: 4 }, children: [
36
- label != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 11, fontWeight: "600", color: labelColor }, children: label }),
38
+ label != null && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 11, fontWeight: "600", color: labelColor, ...rtlLineHeight != null ? { lineHeight: rtlLineHeight } : {} }, children: label }),
37
39
  bubble ? /* @__PURE__ */ jsxRuntime.jsx(
38
40
  reactNative.View,
39
41
  {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/TypingIndicator/index.native.tsx"],"sourcesContent":["import React, {useEffect, useRef} from \"react\";\nimport {View, Text, Animated, Easing} from \"react-native\";\nimport type {ITypingIndicatorProps} from \"@lmb-it/kitsconcerto-types\";\nimport {useKitsTheme} from \"../../contexts/Theme\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n/**\n * TypingIndicator (native) — three dots pulsing via RN `Animated` (opacity only,\n * which is native-driver-safe), optionally inside an incoming-style bubble, with\n * an optional resolved caption. Mirrors CircularProgress.native (Animated.loop +\n * useNativeDriver). Each loop is stopped on unmount. Colours resolve from tokens.\n */\nexport function TypingIndicator(rawProps: ITypingIndicatorProps) {\n const props = useComponentDefaults<ITypingIndicatorProps>(\"TypingIndicator\", rawProps).mergedProps;\n const {label, dotColor = \"text-secondary\", bubble = true, bubbleColor = \"surface-muted\", testID} = props;\n const {resolveToken} = useKitsTheme();\n const dot = resolveToken(dotColor);\n const bg = resolveToken(bubbleColor);\n const labelColor = resolveToken(\"text-secondary\");\n\n const d0 = useRef(new Animated.Value(0.3)).current;\n const d1 = useRef(new Animated.Value(0.3)).current;\n const d2 = useRef(new Animated.Value(0.3)).current;\n\n useEffect(() => {\n const values = [d0, d1, d2];\n const loops = values.map((v, i) =>\n Animated.loop(\n Animated.sequence([\n Animated.delay(i * 180),\n Animated.timing(v, {toValue: 1, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n Animated.timing(v, {toValue: 0.3, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n ]),\n ),\n );\n loops.forEach(l => l.start());\n return () => loops.forEach(l => l.stop());\n }, [d0, d1, d2]);\n\n const dots = (\n <View style={{flexDirection: \"row\", gap: 5, alignItems: \"center\"}}>\n {[d0, d1, d2].map((v, i) => (\n <Animated.View key={i} style={{width: 7, height: 7, borderRadius: 9999, backgroundColor: dot, opacity: v}} />\n ))}\n </View>\n );\n\n return (\n <View testID={testID} style={{alignItems: \"flex-start\", gap: 4}}>\n {label != null && <Text style={{fontSize: 11, fontWeight: \"600\", color: labelColor}}>{label}</Text>}\n {bubble ? (\n <View\n style={{\n backgroundColor: bg,\n borderRadius: 16,\n borderBottomLeftRadius: 4,\n paddingVertical: 10,\n paddingHorizontal: 14,\n alignSelf: \"flex-start\",\n }}\n >\n {dots}\n </View>\n ) : (\n dots\n )}\n </View>\n );\n}\n\nexport default TypingIndicator;\n"],"names":["useComponentDefaults","useKitsTheme","useRef","Animated","useEffect","Easing","jsx","View","jsxs","Text"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/TypingIndicator/index.native.tsx"],"sourcesContent":["import React, {useEffect, useRef} from \"react\";\nimport {View, Text, Animated, Easing} from \"react-native\";\nimport type {ITypingIndicatorProps} from \"@lmb-it/kitsconcerto-types\";\nimport {useKitsTheme} from \"../../contexts/Theme\";\nimport {useComponentDefaults} from \"../../hooks\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\n\n/**\n * TypingIndicator (native) — three dots pulsing via RN `Animated` (opacity only,\n * which is native-driver-safe), optionally inside an incoming-style bubble, with\n * an optional resolved caption. Mirrors CircularProgress.native (Animated.loop +\n * useNativeDriver). Each loop is stopped on unmount. Colours resolve from tokens.\n */\nexport function TypingIndicator(rawProps: ITypingIndicatorProps) {\n const props = useComponentDefaults<ITypingIndicatorProps>(\"TypingIndicator\", rawProps).mergedProps;\n const {label, dotColor = \"text-secondary\", bubble = true, bubbleColor = \"surface-muted\", testID} = props;\n const {resolveToken} = useKitsTheme();\n const dot = resolveToken(dotColor);\n const bg = resolveToken(bubbleColor);\n const labelColor = resolveToken(\"text-secondary\");\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX. This renders a RAW\n * react-native <Text> with a fontSize and no lineHeight, so React Native\n * uses the FONT'S natural line box — and NotoKufiArabic's is too short for\n * its own ascenders, cutting the glyph along its top edge. In an RTL\n * script that does not read as clipping, it reads as a BAD TRANSLATION:\n * ش/س, غ/ع and ة/ه differ only by marks above the baseline.\n * ⚠️ undefined in LTR, so no English layout moves.\n */\n const rtlLineHeight = useRtlLineHeight(undefined, 11);\n\n const d0 = useRef(new Animated.Value(0.3)).current;\n const d1 = useRef(new Animated.Value(0.3)).current;\n const d2 = useRef(new Animated.Value(0.3)).current;\n\n useEffect(() => {\n const values = [d0, d1, d2];\n const loops = values.map((v, i) =>\n Animated.loop(\n Animated.sequence([\n Animated.delay(i * 180),\n Animated.timing(v, {toValue: 1, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n Animated.timing(v, {toValue: 0.3, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n ]),\n ),\n );\n loops.forEach(l => l.start());\n return () => loops.forEach(l => l.stop());\n }, [d0, d1, d2]);\n\n const dots = (\n <View style={{flexDirection: \"row\", gap: 5, alignItems: \"center\"}}>\n {[d0, d1, d2].map((v, i) => (\n <Animated.View key={i} style={{width: 7, height: 7, borderRadius: 9999, backgroundColor: dot, opacity: v}} />\n ))}\n </View>\n );\n\n return (\n <View testID={testID} style={{alignItems: \"flex-start\", gap: 4}}>\n {label != null && <Text style={{fontSize: 11, fontWeight: \"600\", color: labelColor, ...(rtlLineHeight != null ? {lineHeight: rtlLineHeight} : {})}}>{label}</Text>}\n {bubble ? (\n <View\n style={{\n backgroundColor: bg,\n borderRadius: 16,\n borderBottomLeftRadius: 4,\n paddingVertical: 10,\n paddingHorizontal: 14,\n alignSelf: \"flex-start\",\n }}\n >\n {dots}\n </View>\n ) : (\n dots\n )}\n </View>\n );\n}\n\nexport default TypingIndicator;\n"],"names":["useComponentDefaults","useKitsTheme","useRtlLineHeight","useRef","Animated","useEffect","Easing","jsx","View","jsxs","Text"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { useRef, useEffect } from 'react';
3
3
  import { Animated, Easing, View, Text } from 'react-native';
4
4
  import '../../contexts/DialogContext.js';
5
5
  import useComponentDefaults from '../../hooks/useComponentDefaults.js';
6
+ import useRtlLineHeight from '../../hooks/useRtlLineHeight.js';
6
7
  import { useKitsTheme } from '../../contexts/Theme/KitsThemeProvider.js';
7
8
 
8
9
  function TypingIndicator(rawProps) {
@@ -12,6 +13,7 @@ function TypingIndicator(rawProps) {
12
13
  const dot = resolveToken(dotColor);
13
14
  const bg = resolveToken(bubbleColor);
14
15
  const labelColor = resolveToken("text-secondary");
16
+ const rtlLineHeight = useRtlLineHeight(void 0, 11);
15
17
  const d0 = useRef(new Animated.Value(0.3)).current;
16
18
  const d1 = useRef(new Animated.Value(0.3)).current;
17
19
  const d2 = useRef(new Animated.Value(0.3)).current;
@@ -31,7 +33,7 @@ function TypingIndicator(rawProps) {
31
33
  }, [d0, d1, d2]);
32
34
  const dots = /* @__PURE__ */ jsx(View, { style: { flexDirection: "row", gap: 5, alignItems: "center" }, children: [d0, d1, d2].map((v, i) => /* @__PURE__ */ jsx(Animated.View, { style: { width: 7, height: 7, borderRadius: 9999, backgroundColor: dot, opacity: v } }, i)) });
33
35
  return /* @__PURE__ */ jsxs(View, { testID, style: { alignItems: "flex-start", gap: 4 }, children: [
34
- label != null && /* @__PURE__ */ jsx(Text, { style: { fontSize: 11, fontWeight: "600", color: labelColor }, children: label }),
36
+ label != null && /* @__PURE__ */ jsx(Text, { style: { fontSize: 11, fontWeight: "600", color: labelColor, ...rtlLineHeight != null ? { lineHeight: rtlLineHeight } : {} }, children: label }),
35
37
  bubble ? /* @__PURE__ */ jsx(
36
38
  View,
37
39
  {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/components/TypingIndicator/index.native.tsx"],"sourcesContent":["import React, {useEffect, useRef} from \"react\";\nimport {View, Text, Animated, Easing} from \"react-native\";\nimport type {ITypingIndicatorProps} from \"@lmb-it/kitsconcerto-types\";\nimport {useKitsTheme} from \"../../contexts/Theme\";\nimport {useComponentDefaults} from \"../../hooks\";\n\n/**\n * TypingIndicator (native) — three dots pulsing via RN `Animated` (opacity only,\n * which is native-driver-safe), optionally inside an incoming-style bubble, with\n * an optional resolved caption. Mirrors CircularProgress.native (Animated.loop +\n * useNativeDriver). Each loop is stopped on unmount. Colours resolve from tokens.\n */\nexport function TypingIndicator(rawProps: ITypingIndicatorProps) {\n const props = useComponentDefaults<ITypingIndicatorProps>(\"TypingIndicator\", rawProps).mergedProps;\n const {label, dotColor = \"text-secondary\", bubble = true, bubbleColor = \"surface-muted\", testID} = props;\n const {resolveToken} = useKitsTheme();\n const dot = resolveToken(dotColor);\n const bg = resolveToken(bubbleColor);\n const labelColor = resolveToken(\"text-secondary\");\n\n const d0 = useRef(new Animated.Value(0.3)).current;\n const d1 = useRef(new Animated.Value(0.3)).current;\n const d2 = useRef(new Animated.Value(0.3)).current;\n\n useEffect(() => {\n const values = [d0, d1, d2];\n const loops = values.map((v, i) =>\n Animated.loop(\n Animated.sequence([\n Animated.delay(i * 180),\n Animated.timing(v, {toValue: 1, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n Animated.timing(v, {toValue: 0.3, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n ]),\n ),\n );\n loops.forEach(l => l.start());\n return () => loops.forEach(l => l.stop());\n }, [d0, d1, d2]);\n\n const dots = (\n <View style={{flexDirection: \"row\", gap: 5, alignItems: \"center\"}}>\n {[d0, d1, d2].map((v, i) => (\n <Animated.View key={i} style={{width: 7, height: 7, borderRadius: 9999, backgroundColor: dot, opacity: v}} />\n ))}\n </View>\n );\n\n return (\n <View testID={testID} style={{alignItems: \"flex-start\", gap: 4}}>\n {label != null && <Text style={{fontSize: 11, fontWeight: \"600\", color: labelColor}}>{label}</Text>}\n {bubble ? (\n <View\n style={{\n backgroundColor: bg,\n borderRadius: 16,\n borderBottomLeftRadius: 4,\n paddingVertical: 10,\n paddingHorizontal: 14,\n alignSelf: \"flex-start\",\n }}\n >\n {dots}\n </View>\n ) : (\n dots\n )}\n </View>\n );\n}\n\nexport default TypingIndicator;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/TypingIndicator/index.native.tsx"],"sourcesContent":["import React, {useEffect, useRef} from \"react\";\nimport {View, Text, Animated, Easing} from \"react-native\";\nimport type {ITypingIndicatorProps} from \"@lmb-it/kitsconcerto-types\";\nimport {useKitsTheme} from \"../../contexts/Theme\";\nimport {useComponentDefaults} from \"../../hooks\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\n\n/**\n * TypingIndicator (native) — three dots pulsing via RN `Animated` (opacity only,\n * which is native-driver-safe), optionally inside an incoming-style bubble, with\n * an optional resolved caption. Mirrors CircularProgress.native (Animated.loop +\n * useNativeDriver). Each loop is stopped on unmount. Colours resolve from tokens.\n */\nexport function TypingIndicator(rawProps: ITypingIndicatorProps) {\n const props = useComponentDefaults<ITypingIndicatorProps>(\"TypingIndicator\", rawProps).mergedProps;\n const {label, dotColor = \"text-secondary\", bubble = true, bubbleColor = \"surface-muted\", testID} = props;\n const {resolveToken} = useKitsTheme();\n const dot = resolveToken(dotColor);\n const bg = resolveToken(bubbleColor);\n const labelColor = resolveToken(\"text-secondary\");\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX. This renders a RAW\n * react-native <Text> with a fontSize and no lineHeight, so React Native\n * uses the FONT'S natural line box — and NotoKufiArabic's is too short for\n * its own ascenders, cutting the glyph along its top edge. In an RTL\n * script that does not read as clipping, it reads as a BAD TRANSLATION:\n * ش/س, غ/ع and ة/ه differ only by marks above the baseline.\n * ⚠️ undefined in LTR, so no English layout moves.\n */\n const rtlLineHeight = useRtlLineHeight(undefined, 11);\n\n const d0 = useRef(new Animated.Value(0.3)).current;\n const d1 = useRef(new Animated.Value(0.3)).current;\n const d2 = useRef(new Animated.Value(0.3)).current;\n\n useEffect(() => {\n const values = [d0, d1, d2];\n const loops = values.map((v, i) =>\n Animated.loop(\n Animated.sequence([\n Animated.delay(i * 180),\n Animated.timing(v, {toValue: 1, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n Animated.timing(v, {toValue: 0.3, duration: 400, easing: Easing.inOut(Easing.ease), useNativeDriver: true}),\n ]),\n ),\n );\n loops.forEach(l => l.start());\n return () => loops.forEach(l => l.stop());\n }, [d0, d1, d2]);\n\n const dots = (\n <View style={{flexDirection: \"row\", gap: 5, alignItems: \"center\"}}>\n {[d0, d1, d2].map((v, i) => (\n <Animated.View key={i} style={{width: 7, height: 7, borderRadius: 9999, backgroundColor: dot, opacity: v}} />\n ))}\n </View>\n );\n\n return (\n <View testID={testID} style={{alignItems: \"flex-start\", gap: 4}}>\n {label != null && <Text style={{fontSize: 11, fontWeight: \"600\", color: labelColor, ...(rtlLineHeight != null ? {lineHeight: rtlLineHeight} : {})}}>{label}</Text>}\n {bubble ? (\n <View\n style={{\n backgroundColor: bg,\n borderRadius: 16,\n borderBottomLeftRadius: 4,\n paddingVertical: 10,\n paddingHorizontal: 14,\n alignSelf: \"flex-start\",\n }}\n >\n {dots}\n </View>\n ) : (\n dots\n )}\n </View>\n );\n}\n\nexport default TypingIndicator;\n"],"names":[],"mappings":"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"}
@@ -16,14 +16,14 @@ function useSeverityColors(severity) {
16
16
  if (severity === "brand") {
17
17
  const primary = resolveToken("primary");
18
18
  if (colorMode === "dark") {
19
- const swapShade = (token, target) => resolveToken(token.replace(/\.\d+$/, `.${target}`));
19
+ const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
20
20
  return {
21
21
  solid: primary,
22
22
  solidText: resolveSolidText(),
23
- bgTint: swapShade(slots.solid, "900"),
23
+ bgTint: swapShade(slots.solid, "900", slots.bgTint),
24
24
  iconFg: primary,
25
- iconBg: swapShade(slots.solid, "800"),
26
- text: swapShade(slots.solid, "200"),
25
+ iconBg: swapShade(slots.solid, "800", slots.iconBg),
26
+ text: swapShade(slots.solid, "200", slots.text),
27
27
  border: primary
28
28
  };
29
29
  }
@@ -38,16 +38,14 @@ function useSeverityColors(severity) {
38
38
  };
39
39
  }
40
40
  if (colorMode === "dark") {
41
- const swapShade = (token, target) => {
42
- return resolveToken(token.replace(/\.\d+$/, `.${target}`));
43
- };
41
+ const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
44
42
  return {
45
43
  solid: resolveToken(slots.solid),
46
44
  solidText: resolveSolidText(),
47
- bgTint: swapShade(slots.solid, "900"),
48
- iconFg: swapShade(slots.solid, "300"),
49
- iconBg: swapShade(slots.solid, "800"),
50
- text: swapShade(slots.solid, "200"),
45
+ bgTint: swapShade(slots.solid, "900", slots.bgTint),
46
+ iconFg: swapShade(slots.solid, "300", slots.iconFg),
47
+ iconBg: swapShade(slots.solid, "800", slots.iconBg),
48
+ text: swapShade(slots.solid, "200", slots.text),
51
49
  border: resolveToken(slots.border)
52
50
  };
53
51
  }
@@ -74,16 +72,14 @@ function useAllSeverityColors() {
74
72
  const isBrand = key === "brand";
75
73
  const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;
76
74
  if (colorMode === "dark") {
77
- const swapShade = (token, target) => {
78
- return resolveToken(token.replace(/\.\d+$/, `.${target}`));
79
- };
75
+ const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
80
76
  result[key] = {
81
77
  solid: isBrand ? primary : resolveToken(slots.solid),
82
78
  solidText,
83
- bgTint: swapShade(slots.solid, "900"),
84
- iconFg: isBrand ? primary : swapShade(slots.solid, "300"),
85
- iconBg: swapShade(slots.solid, "800"),
86
- text: swapShade(slots.solid, "200"),
79
+ bgTint: swapShade(slots.solid, "900", slots.bgTint),
80
+ iconFg: isBrand ? primary : swapShade(slots.solid, "300", slots.iconFg),
81
+ iconBg: swapShade(slots.solid, "800", slots.iconBg),
82
+ text: swapShade(slots.solid, "200", slots.text),
87
83
  border: isBrand ? primary : resolveToken(slots.border)
88
84
  };
89
85
  } else {
@@ -1 +1 @@
1
- {"version":3,"file":"useSeverityColors.cjs","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n const fallback = resolveToken('gray.500');\n return {solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback};\n }\n\n // solidText: resolve if consumer provided it, otherwise default to white\n const resolveSolidText = () =>\n slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n const swapShade = (token: string, target: string) =>\n resolveToken(token.replace(/\\.\\d+$/, `.${target}`));\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900'),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800'),\n text: swapShade(slots.solid, '200'),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n const swapShade = (token: string, target: string) => {\n return resolveToken(token.replace(/\\.\\d+$/, `.${target}`));\n };\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900'),\n iconFg: swapShade(slots.solid, '300'),\n iconBg: swapShade(slots.solid, '800'),\n text: swapShade(slots.solid, '200'),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n const swapShade = (token: string, target: string) => {\n return resolveToken(token.replace(/\\.\\d+$/, `.${target}`));\n };\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900'),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300'),\n iconBg: swapShade(slots.solid, '800'),\n text: swapShade(slots.solid, '200'),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":["useKitsTheme","useMemo"],"mappings":"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"}
1
+ {"version":3,"file":"useSeverityColors.cjs","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\n/**\n * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S\n * SEVEN SEVERITIES DO NOT HAVE ONE.\n *\n * Dark mode derives its tint and its text from the severity's `solid` value by\n * replacing the shade — `amber.500` → `amber.900` for the background and\n * `amber.200` for the text. That is only meaningful when `solid` LOOKS like\n * `name.NNN`. In `defaultTheme.ts` it often does not:\n *\n * brand brand.500 shaded → swap works\n * success green.500 shaded → swap works\n * secondary gray.500 shaded → swap works\n * danger #E3595B RAW HEX → swap is a no-op\n * warning #F59E0B RAW HEX → swap is a no-op\n * info #4F5BD5 RAW HEX → swap is a no-op\n * help #4F5BD5 RAW HEX → swap is a no-op\n *\n * ⛔ AND A NO-OP HERE IS NOT \"NO CHANGE\" — IT IS A COLLISION. The regex matches\n * nothing, so BOTH the background and the text resolve to the SAME raw hex, and\n * the text becomes invisible on its own background. Measured on the device\n * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled\n * pixels of #F59E0B with no text ink in it at all — the label and its reason\n * had vanished while the banner still looked like a banner.\n *\n * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and\n * help — and this hook is SHARED, not native-only, so web surfaces have it too.\n *\n * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,\n * the light slots are used instead: they are a pair someone chose to be legible\n * together, which is the one thing that must be true here. A dark-mode tint\n * would look better and is a palette decision, not a correctness one.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n const fallback = resolveToken('gray.500');\n return {solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback};\n }\n\n // solidText: resolve if consumer provided it, otherwise default to white\n const resolveSolidText = () =>\n slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n // Same shade-guard as below: a `solid` with no shade cannot be\n // swapped, and collapsing it would put the text on its own colour.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n // `fallbackSlot` is used when `token` carries no shade to swap —\n // see the note above this function.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n // Same shade-guard as useSeverityColors — four of the seven\n // default severities carry a raw hex, which cannot be swapped.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":["useKitsTheme","useMemo"],"mappings":"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"}
@@ -14,14 +14,14 @@ function useSeverityColors(severity) {
14
14
  if (severity === "brand") {
15
15
  const primary = resolveToken("primary");
16
16
  if (colorMode === "dark") {
17
- const swapShade = (token, target) => resolveToken(token.replace(/\.\d+$/, `.${target}`));
17
+ const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
18
18
  return {
19
19
  solid: primary,
20
20
  solidText: resolveSolidText(),
21
- bgTint: swapShade(slots.solid, "900"),
21
+ bgTint: swapShade(slots.solid, "900", slots.bgTint),
22
22
  iconFg: primary,
23
- iconBg: swapShade(slots.solid, "800"),
24
- text: swapShade(slots.solid, "200"),
23
+ iconBg: swapShade(slots.solid, "800", slots.iconBg),
24
+ text: swapShade(slots.solid, "200", slots.text),
25
25
  border: primary
26
26
  };
27
27
  }
@@ -36,16 +36,14 @@ function useSeverityColors(severity) {
36
36
  };
37
37
  }
38
38
  if (colorMode === "dark") {
39
- const swapShade = (token, target) => {
40
- return resolveToken(token.replace(/\.\d+$/, `.${target}`));
41
- };
39
+ const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
42
40
  return {
43
41
  solid: resolveToken(slots.solid),
44
42
  solidText: resolveSolidText(),
45
- bgTint: swapShade(slots.solid, "900"),
46
- iconFg: swapShade(slots.solid, "300"),
47
- iconBg: swapShade(slots.solid, "800"),
48
- text: swapShade(slots.solid, "200"),
43
+ bgTint: swapShade(slots.solid, "900", slots.bgTint),
44
+ iconFg: swapShade(slots.solid, "300", slots.iconFg),
45
+ iconBg: swapShade(slots.solid, "800", slots.iconBg),
46
+ text: swapShade(slots.solid, "200", slots.text),
49
47
  border: resolveToken(slots.border)
50
48
  };
51
49
  }
@@ -72,16 +70,14 @@ function useAllSeverityColors() {
72
70
  const isBrand = key === "brand";
73
71
  const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;
74
72
  if (colorMode === "dark") {
75
- const swapShade = (token, target) => {
76
- return resolveToken(token.replace(/\.\d+$/, `.${target}`));
77
- };
73
+ const swapShade = (token, target, fallbackSlot) => /\.\d+$/.test(token) ? resolveToken(token.replace(/\.\d+$/, `.${target}`)) : resolveToken(fallbackSlot);
78
74
  result[key] = {
79
75
  solid: isBrand ? primary : resolveToken(slots.solid),
80
76
  solidText,
81
- bgTint: swapShade(slots.solid, "900"),
82
- iconFg: isBrand ? primary : swapShade(slots.solid, "300"),
83
- iconBg: swapShade(slots.solid, "800"),
84
- text: swapShade(slots.solid, "200"),
77
+ bgTint: swapShade(slots.solid, "900", slots.bgTint),
78
+ iconFg: isBrand ? primary : swapShade(slots.solid, "300", slots.iconFg),
79
+ iconBg: swapShade(slots.solid, "800", slots.iconBg),
80
+ text: swapShade(slots.solid, "200", slots.text),
85
81
  border: isBrand ? primary : resolveToken(slots.border)
86
82
  };
87
83
  } else {
@@ -1 +1 @@
1
- {"version":3,"file":"useSeverityColors.js","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n const fallback = resolveToken('gray.500');\n return {solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback};\n }\n\n // solidText: resolve if consumer provided it, otherwise default to white\n const resolveSolidText = () =>\n slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n const swapShade = (token: string, target: string) =>\n resolveToken(token.replace(/\\.\\d+$/, `.${target}`));\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900'),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800'),\n text: swapShade(slots.solid, '200'),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n const swapShade = (token: string, target: string) => {\n return resolveToken(token.replace(/\\.\\d+$/, `.${target}`));\n };\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900'),\n iconFg: swapShade(slots.solid, '300'),\n iconBg: swapShade(slots.solid, '800'),\n text: swapShade(slots.solid, '200'),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n const swapShade = (token: string, target: string) => {\n return resolveToken(token.replace(/\\.\\d+$/, `.${target}`));\n };\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900'),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300'),\n iconBg: swapShade(slots.solid, '800'),\n text: swapShade(slots.solid, '200'),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSeverityColors.js","sources":["../../../src/hooks/useSeverityColors.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\nimport type {Severity, ISeverityColorSlots} from '@lmb-it/kitsconcerto-types';\n\nexport interface ResolvedSeverityColors {\n solid: string;\n solidText: string;\n bgTint: string;\n iconFg: string;\n iconBg: string;\n text: string;\n border: string;\n}\n\nconst WHITE = '#ffffff';\n\n/**\n * Resolves all severity color slots for a given severity using the current theme.\n * All slot values go through resolveToken() — so they support:\n * - Raw values: '#ff0000', 'black', 'rgb(..)'\n * - Semantic tokens: 'primary', 'danger'\n * - Dot-notation: 'red.700', 'blue.500'\n * - Prefixed tokens: '$spacing.4'\n *\n * solidText defaults to white if not explicitly set by the consumer.\n */\n/**\n * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S\n * SEVEN SEVERITIES DO NOT HAVE ONE.\n *\n * Dark mode derives its tint and its text from the severity's `solid` value by\n * replacing the shade — `amber.500` → `amber.900` for the background and\n * `amber.200` for the text. That is only meaningful when `solid` LOOKS like\n * `name.NNN`. In `defaultTheme.ts` it often does not:\n *\n * brand brand.500 shaded → swap works\n * success green.500 shaded → swap works\n * secondary gray.500 shaded → swap works\n * danger #E3595B RAW HEX → swap is a no-op\n * warning #F59E0B RAW HEX → swap is a no-op\n * info #4F5BD5 RAW HEX → swap is a no-op\n * help #4F5BD5 RAW HEX → swap is a no-op\n *\n * ⛔ AND A NO-OP HERE IS NOT \"NO CHANGE\" — IT IS A COLLISION. The regex matches\n * nothing, so BOTH the background and the text resolve to the SAME raw hex, and\n * the text becomes invisible on its own background. Measured on the device\n * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled\n * pixels of #F59E0B with no text ink in it at all — the label and its reason\n * had vanished while the banner still looked like a banner.\n *\n * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and\n * help — and this hook is SHARED, not native-only, so web surfaces have it too.\n *\n * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,\n * the light slots are used instead: they are a pair someone chose to be legible\n * together, which is the one thing that must be true here. A dark-mode tint\n * would look better and is a palette decision, not a correctness one.\n */\nexport function useSeverityColors(severity: Severity): ResolvedSeverityColors {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const slots: ISeverityColorSlots = theme.severity?.[severity] ?? theme.severity?.secondary;\n if (!slots) {\n const fallback = resolveToken('gray.500');\n return {solid: fallback, solidText: WHITE, bgTint: fallback, iconFg: fallback, iconBg: fallback, text: fallback, border: fallback};\n }\n\n // solidText: resolve if consumer provided it, otherwise default to white\n const resolveSolidText = () =>\n slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n // Brand severity: solid/border/iconFg dynamically follow the primary token\n if (severity === 'brand') {\n const primary = resolveToken('primary');\n if (colorMode === 'dark') {\n // Same shade-guard as below: a `solid` with no shade cannot be\n // swapped, and collapsing it would put the text on its own colour.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: primary,\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: primary,\n };\n }\n return {\n solid: primary,\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: primary,\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: primary,\n };\n }\n\n if (colorMode === 'dark') {\n // `fallbackSlot` is used when `token` carries no shade to swap —\n // see the note above this function.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: resolveToken(slots.border),\n };\n }\n\n return {\n solid: resolveToken(slots.solid),\n solidText: resolveSolidText(),\n bgTint: resolveToken(slots.bgTint),\n iconFg: resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: resolveToken(slots.border),\n };\n }, [theme.severity, severity, resolveToken, colorMode]);\n}\n\n/**\n * Returns the full resolved map for all severities.\n */\nexport function useAllSeverityColors(): Record<Severity, ResolvedSeverityColors> {\n const {theme, resolveToken, colorMode} = useKitsTheme();\n\n return useMemo(() => {\n const severities: Severity[] = ['success', 'info', 'warning', 'danger', 'help', 'secondary', 'brand'];\n const result = {} as Record<Severity, ResolvedSeverityColors>;\n const primary = resolveToken('primary');\n\n for (const key of severities) {\n const slots = theme.severity?.[key];\n if (!slots) continue;\n\n const isBrand = key === 'brand';\n const solidText = slots.solidText ? resolveToken(slots.solidText) : WHITE;\n\n if (colorMode === 'dark') {\n // Same shade-guard as useSeverityColors — four of the seven\n // default severities carry a raw hex, which cannot be swapped.\n const swapShade = (token: string, target: string, fallbackSlot: string) =>\n /\\.\\d+$/.test(token)\n ? resolveToken(token.replace(/\\.\\d+$/, `.${target}`))\n : resolveToken(fallbackSlot);\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: swapShade(slots.solid, '900', slots.bgTint),\n iconFg: isBrand ? primary : swapShade(slots.solid, '300', slots.iconFg),\n iconBg: swapShade(slots.solid, '800', slots.iconBg),\n text: swapShade(slots.solid, '200', slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n } else {\n result[key] = {\n solid: isBrand ? primary : resolveToken(slots.solid),\n solidText,\n bgTint: resolveToken(slots.bgTint),\n iconFg: isBrand ? primary : resolveToken(slots.iconFg),\n iconBg: resolveToken(slots.iconBg),\n text: resolveToken(slots.text),\n border: isBrand ? primary : resolveToken(slots.border),\n };\n }\n }\n\n return result;\n }, [theme.severity, resolveToken, colorMode]);\n}\n"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -9138,6 +9138,38 @@ export interface ResolvedSeverityColors {
9138
9138
  *
9139
9139
  * solidText defaults to white if not explicitly set by the consumer.
9140
9140
  */
9141
+ /**
9142
+ * ⛔ SHADE-SWAPPING ONLY WORKS ON A SHADED TOKEN, AND FOUR OF THIS LIBRARY'S
9143
+ * SEVEN SEVERITIES DO NOT HAVE ONE.
9144
+ *
9145
+ * Dark mode derives its tint and its text from the severity's `solid` value by
9146
+ * replacing the shade — `amber.500` → `amber.900` for the background and
9147
+ * `amber.200` for the text. That is only meaningful when `solid` LOOKS like
9148
+ * `name.NNN`. In `defaultTheme.ts` it often does not:
9149
+ *
9150
+ * brand brand.500 shaded → swap works
9151
+ * success green.500 shaded → swap works
9152
+ * secondary gray.500 shaded → swap works
9153
+ * danger #E3595B RAW HEX → swap is a no-op
9154
+ * warning #F59E0B RAW HEX → swap is a no-op
9155
+ * info #4F5BD5 RAW HEX → swap is a no-op
9156
+ * help #4F5BD5 RAW HEX → swap is a no-op
9157
+ *
9158
+ * ⛔ AND A NO-OP HERE IS NOT "NO CHANGE" — IT IS A COLLISION. The regex matches
9159
+ * nothing, so BOTH the background and the text resolve to the SAME raw hex, and
9160
+ * the text becomes invisible on its own background. Measured on the device
9161
+ * (AlphaMatch, Me tab, warning banner, dark): the action row was 6,923 sampled
9162
+ * pixels of #F59E0B with no text ink in it at all — the label and its reason
9163
+ * had vanished while the banner still looked like a banner.
9164
+ *
9165
+ * ⚠️ IT HITS THE FOUR SEVERITIES PEOPLE SEE MOST — errors, warnings, info and
9166
+ * help — and this hook is SHARED, not native-only, so web surfaces have it too.
9167
+ *
9168
+ * 💡 THE FALLBACK IS THE DESIGNED LIGHT PAIR. When there is no shade to swap,
9169
+ * the light slots are used instead: they are a pair someone chose to be legible
9170
+ * together, which is the one thing that must be true here. A dark-mode tint
9171
+ * would look better and is a palette decision, not a correctness one.
9172
+ */
9141
9173
  declare function useSeverityColors(severity: Severity): ResolvedSeverityColors;
9142
9174
  /**
9143
9175
  * Returns the full resolved map for all severities.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmb-it/kitsconcerto-native",
3
- "version": "0.1.253",
3
+ "version": "0.1.254",
4
4
  "description": "KitsConcerto — Native (React Native) UI components",
5
5
  "main": "index.cjs",
6
6
  "module": "index.js",
@@ -85,11 +85,13 @@ require('../../apps/mobile/src/Core/RadioButton/index.cjs');
85
85
  require('../../apps/mobile/src/Core/Input/index.cjs');
86
86
  require('../../apps/mobile/src/Core/Input/Field.cjs');
87
87
  require('../../apps/mobile/src/Core/Input/Slot.cjs');
88
+ var useRtlLineHeight = require('../../hooks/useRtlLineHeight.cjs');
88
89
  var useThemedFont = require('../../hooks/useThemedFont.cjs');
89
90
  var KitsThemeProvider_native = require('../../contexts/Theme/KitsThemeProvider.cjs');
90
91
 
91
92
  const Divider = (props) => {
92
93
  const { nativeProps } = useSeparator.default(props);
94
+ const rtlLineHeight = useRtlLineHeight.default(void 0, 14);
93
95
  const {
94
96
  align = "center",
95
97
  children,
@@ -151,7 +153,7 @@ const Divider = (props) => {
151
153
  { backgroundColor: dividerColor },
152
154
  align === "left" || align === "top" ? { flex: 0, width: isHorizontal ? 24 : void 0, height: !isHorizontal ? 24 : void 0 } : { flex: 1 }
153
155
  ] }),
154
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.contentText, { color: resolveToken("text-secondary") }, contentFont ? { fontFamily: contentFont } : null], children }),
156
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.contentText, { color: resolveToken("text-secondary") }, rtlLineHeight != null ? { lineHeight: rtlLineHeight } : null, contentFont ? { fontFamily: contentFont } : null], children }),
155
157
  /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
156
158
  isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,
157
159
  { backgroundColor: dividerColor },
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/primitives/Divider/index.native.tsx"],"sourcesContent":["import React from 'react';\nimport {View, Text, StyleSheet} from 'react-native';\nimport type {IDividerComponent} from '@lmb-it/kitsconcerto-types';\nimport {useSeparator} from \"../../factory\";\nimport {useKitsTheme} from '../../contexts/Theme';\nimport useThemedFont from '../../hooks/useThemedFont';\n\nconst Divider: React.FC<IDividerComponent> = (props) => {\n const {nativeProps} = useSeparator<any>(props);\n const {\n align = 'center',\n children,\n layout = 'horizontal',\n type: borderType = 'solid',\n unstyled = false,\n ...rest\n } = nativeProps;\n\n const {resolveToken} = useKitsTheme();\n // `color` overrides the line colour (resolved through the theme — token,\n // hex, or named); falls back to the `divider` token when omitted.\n const dividerColor = typeof props.color === 'string'\n ? resolveToken(props.color)\n : resolveToken('divider');\n const contentFont = useThemedFont('body');\n\n const isHorizontal = layout === 'horizontal';\n\n if (unstyled) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n rest.style,\n ]}\n />\n );\n }\n\n const lineStyle = isHorizontal\n ? [styles.horizontalLine, {borderBottomStyle: borderType, borderBottomColor: dividerColor}]\n : [styles.verticalLine, {borderLeftStyle: borderType, borderLeftColor: dividerColor}];\n\n if (!children) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n isHorizontal\n ? {borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: dividerColor, borderStyle: borderType}\n : {borderLeftWidth: StyleSheet.hairlineWidth, borderLeftColor: dividerColor, borderStyle: borderType},\n rest.style,\n ]}\n />\n );\n }\n\n const alignMap: Record<string, 'flex-start' | 'center' | 'flex-end'> = {\n left: 'flex-start',\n top: 'flex-start',\n center: 'center',\n right: 'flex-end',\n bottom: 'flex-end',\n };\n const justifyContent = alignMap[align] ?? 'center';\n\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontalWithContent : styles.verticalWithContent,\n {justifyContent},\n rest.style,\n ]}>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'left' || align === 'top' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n <Text style={[styles.contentText, {color: resolveToken('text-secondary')}, contentFont ? {fontFamily: contentFont} : null]}>\n {children}\n </Text>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'right' || align === 'bottom' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n horizontal: {\n width: '100%',\n flexDirection: 'row',\n },\n vertical: {\n height: '100%',\n flexDirection: 'column',\n },\n horizontalWithContent: {\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n verticalWithContent: {\n height: '100%',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 12,\n },\n horizontalLine: {\n width: '100%',\n },\n verticalLine: {\n height: '100%',\n },\n lineSegment: {\n height: StyleSheet.hairlineWidth,\n flex: 1,\n },\n lineSegmentVertical: {\n width: StyleSheet.hairlineWidth,\n flex: 1,\n },\n contentText: {\n fontSize: 14,\n },\n});\n\nexport default Divider;\n"],"names":["useSeparator","useKitsTheme","useThemedFont","jsx","View","StyleSheet","jsxs","Text"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,MAAM,OAAA,GAAuC,CAAC,KAAA,KAAU;AACpD,EAAA,MAAM,EAAC,WAAA,EAAW,GAAIA,oBAAA,CAAkB,KAAK,CAAA;AAC7C,EAAA,MAAM;AAAA,IACF,KAAA,GAAQ,QAAA;AAAA,IACR,QAAA;AAAA,IACA,MAAA,GAAS,YAAA;AAAA,IACT,MAAM,UAAA,GAAa,OAAA;AAAA,IACnB,QAAA,GAAW,KAAA;AAAA,IACX,GAAG;AAAA,GACP,GAAI,WAAA;AAEJ,EAAA,MAAM,EAAC,YAAA,EAAY,GAAIC,qCAAA,EAAa;AAGpC,EAAA,MAAM,YAAA,GAAe,OAAO,KAAA,CAAM,KAAA,KAAU,QAAA,GACtC,aAAa,KAAA,CAAM,KAAK,CAAA,GACxB,YAAA,CAAa,SAAS,CAAA;AAC5B,EAAA,MAAM,WAAA,GAAcC,sBAAc,MAAM,CAAA;AAExC,EAAA,MAAM,eAAe,MAAA,KAAW,YAAA;AAEhC,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,uBACIC,cAAA;AAAA,MAACC,gBAAA;AAAA,MAAA;AAAA,QACI,GAAG,IAAA;AAAA,QACJ,KAAA,EAAO;AAAA,UACH,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,QAAA;AAAA,UAC1C,IAAA,CAAK;AAAA;AACT;AAAA,KACJ;AAAA,EAER;AAEA,EAAkB,eACZ,CAAC,MAAA,CAAO,gBAAgB,EAAC,iBAAA,EAAmB,YAAY,iBAAA,EAAmB,YAAA,EAAa,CAAA,GACxF,CAAC,OAAO,YAAA,EAAc,EAAC,iBAAiB,UAAA,EAAY,eAAA,EAAiB,cAAa;AAExF,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA,uBACID,cAAA;AAAA,MAACC,gBAAA;AAAA,MAAA;AAAA,QACI,GAAG,IAAA;AAAA,QACJ,KAAA,EAAO;AAAA,UACH,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,QAAA;AAAA,UAC1C,eACM,EAAC,iBAAA,EAAmBC,sBAAA,CAAW,aAAA,EAAe,mBAAmB,YAAA,EAAc,WAAA,EAAa,UAAA,EAAU,GACtG,EAAC,eAAA,EAAiBA,sBAAA,CAAW,eAAe,eAAA,EAAiB,YAAA,EAAc,aAAa,UAAA,EAAU;AAAA,UACxG,IAAA,CAAK;AAAA;AACT;AAAA,KACJ;AAAA,EAER;AAEA,EAAA,MAAM,QAAA,GAAiE;AAAA,IACnE,IAAA,EAAM,YAAA;AAAA,IACN,GAAA,EAAK,YAAA;AAAA,IACL,MAAA,EAAQ,QAAA;AAAA,IACR,KAAA,EAAO,UAAA;AAAA,IACP,MAAA,EAAQ;AAAA,GACZ;AACA,EAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,KAAK,CAAA,IAAK,QAAA;AAE1C,EAAA,uBACIC,eAAA;AAAA,IAACF,gBAAA;AAAA,IAAA;AAAA,MACI,GAAG,IAAA;AAAA,MACJ,KAAA,EAAO;AAAA,QACH,YAAA,GAAe,MAAA,CAAO,qBAAA,GAAwB,MAAA,CAAO,mBAAA;AAAA,QACrD,EAAC,cAAA,EAAc;AAAA,QACf,IAAA,CAAK;AAAA,OACT;AAAA,MACA,QAAA,EAAA;AAAA,wBAAAD,cAAA,CAACC,oBAAK,KAAA,EAAO;AAAA,UACT,YAAA,GAAe,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,mBAAA;AAAA,UAC3C,EAAC,iBAAiB,YAAA,EAAY;AAAA,UAC9B,UAAU,MAAA,IAAU,KAAA,KAAU,QAAQ,EAAC,IAAA,EAAM,GAAG,KAAA,EAAO,YAAA,GAAe,KAAK,MAAA,EAAW,MAAA,EAAQ,CAAC,YAAA,GAAe,EAAA,GAAK,QAAS,GAAI,EAAC,MAAM,CAAA;AAAC,SAC5I,EAAG,CAAA;AAAA,uCACFG,gBAAA,EAAA,EAAK,KAAA,EAAO,CAAC,MAAA,CAAO,WAAA,EAAa,EAAC,KAAA,EAAO,YAAA,CAAa,gBAAgB,CAAA,EAAC,EAAG,cAAc,EAAC,UAAA,EAAY,aAAW,GAAI,IAAI,GACpH,QAAA,EACL,CAAA;AAAA,wBACAJ,cAAA,CAACC,oBAAK,KAAA,EAAO;AAAA,UACT,YAAA,GAAe,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,mBAAA;AAAA,UAC3C,EAAC,iBAAiB,YAAA,EAAY;AAAA,UAC9B,UAAU,OAAA,IAAW,KAAA,KAAU,WAAW,EAAC,IAAA,EAAM,GAAG,KAAA,EAAO,YAAA,GAAe,KAAK,MAAA,EAAW,MAAA,EAAQ,CAAC,YAAA,GAAe,EAAA,GAAK,QAAS,GAAI,EAAC,MAAM,CAAA;AAAC,SAChJ,EAAG;AAAA;AAAA;AAAA,GACP;AAER;AAEA,MAAM,MAAA,GAASC,uBAAW,MAAA,CAAO;AAAA,EAC7B,UAAA,EAAY;AAAA,IACR,KAAA,EAAO,MAAA;AAAA,IACP,aAAA,EAAe;AAAA,GACnB;AAAA,EACA,QAAA,EAAU;AAAA,IACN,MAAA,EAAQ,MAAA;AAAA,IACR,aAAA,EAAe;AAAA,GACnB;AAAA,EACA,qBAAA,EAAuB;AAAA,IACnB,KAAA,EAAO,MAAA;AAAA,IACP,aAAA,EAAe,KAAA;AAAA,IACf,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK;AAAA,GACT;AAAA,EACA,mBAAA,EAAqB;AAAA,IACjB,MAAA,EAAQ,MAAA;AAAA,IACR,aAAA,EAAe,QAAA;AAAA,IACf,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK;AAAA,GACT;AAAA,EACA,cAAA,EAAgB;AAAA,IACZ,KAAA,EAAO;AAAA,GACX;AAAA,EACA,YAAA,EAAc;AAAA,IACV,MAAA,EAAQ;AAAA,GACZ;AAAA,EACA,WAAA,EAAa;AAAA,IACT,QAAQA,sBAAA,CAAW,aAAA;AAAA,IACnB,IAAA,EAAM;AAAA,GACV;AAAA,EACA,mBAAA,EAAqB;AAAA,IACjB,OAAOA,sBAAA,CAAW,aAAA;AAAA,IAClB,IAAA,EAAM;AAAA,GACV;AAAA,EACA,WAAA,EAAa;AAAA,IACT,QAAA,EAAU;AAAA;AAElB,CAAC,CAAA;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/primitives/Divider/index.native.tsx"],"sourcesContent":["import React from 'react';\nimport {View, Text, StyleSheet} from 'react-native';\nimport type {IDividerComponent} from '@lmb-it/kitsconcerto-types';\nimport {useSeparator} from \"../../factory\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\nimport {useKitsTheme} from '../../contexts/Theme';\nimport useThemedFont from '../../hooks/useThemedFont';\n\nconst Divider: React.FC<IDividerComponent> = (props) => {\n const {nativeProps} = useSeparator<any>(props);\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX — a raw react-native <Text>\n * with a fontSize and no lineHeight gets the FONT'S natural box, and\n * NotoKufiArabic's is too short for its own ascenders. In an RTL script\n * that reads as a BAD TRANSLATION rather than as clipping: ش/س, غ/ع and\n * ة/ه differ only by marks above the baseline.\n * ⚠️ undefined in LTR, so no English layout moves.\n */\n const rtlLineHeight = useRtlLineHeight(undefined, 14);\n const {\n align = 'center',\n children,\n layout = 'horizontal',\n type: borderType = 'solid',\n unstyled = false,\n ...rest\n } = nativeProps;\n\n const {resolveToken} = useKitsTheme();\n // `color` overrides the line colour (resolved through the theme — token,\n // hex, or named); falls back to the `divider` token when omitted.\n const dividerColor = typeof props.color === 'string'\n ? resolveToken(props.color)\n : resolveToken('divider');\n const contentFont = useThemedFont('body');\n\n const isHorizontal = layout === 'horizontal';\n\n if (unstyled) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n rest.style,\n ]}\n />\n );\n }\n\n const lineStyle = isHorizontal\n ? [styles.horizontalLine, {borderBottomStyle: borderType, borderBottomColor: dividerColor}]\n : [styles.verticalLine, {borderLeftStyle: borderType, borderLeftColor: dividerColor}];\n\n if (!children) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n isHorizontal\n ? {borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: dividerColor, borderStyle: borderType}\n : {borderLeftWidth: StyleSheet.hairlineWidth, borderLeftColor: dividerColor, borderStyle: borderType},\n rest.style,\n ]}\n />\n );\n }\n\n const alignMap: Record<string, 'flex-start' | 'center' | 'flex-end'> = {\n left: 'flex-start',\n top: 'flex-start',\n center: 'center',\n right: 'flex-end',\n bottom: 'flex-end',\n };\n const justifyContent = alignMap[align] ?? 'center';\n\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontalWithContent : styles.verticalWithContent,\n {justifyContent},\n rest.style,\n ]}>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'left' || align === 'top' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n <Text style={[styles.contentText, {color: resolveToken('text-secondary')}, rtlLineHeight != null ? {lineHeight: rtlLineHeight} : null, contentFont ? {fontFamily: contentFont} : null]}>\n {children}\n </Text>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'right' || align === 'bottom' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n horizontal: {\n width: '100%',\n flexDirection: 'row',\n },\n vertical: {\n height: '100%',\n flexDirection: 'column',\n },\n horizontalWithContent: {\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n verticalWithContent: {\n height: '100%',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 12,\n },\n horizontalLine: {\n width: '100%',\n },\n verticalLine: {\n height: '100%',\n },\n lineSegment: {\n height: StyleSheet.hairlineWidth,\n flex: 1,\n },\n lineSegmentVertical: {\n width: StyleSheet.hairlineWidth,\n flex: 1,\n },\n contentText: {\n fontSize: 14,\n },\n});\n\nexport default Divider;\n"],"names":["useSeparator","useRtlLineHeight","useKitsTheme","useThemedFont","jsx","View","StyleSheet","jsxs","Text"],"mappings":"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"}
@@ -81,11 +81,13 @@ import '../../apps/mobile/src/Core/RadioButton/index.js';
81
81
  import '../../apps/mobile/src/Core/Input/index.js';
82
82
  import '../../apps/mobile/src/Core/Input/Field.js';
83
83
  import '../../apps/mobile/src/Core/Input/Slot.js';
84
+ import useRtlLineHeight from '../../hooks/useRtlLineHeight.js';
84
85
  import useThemedFont from '../../hooks/useThemedFont.js';
85
86
  import { useKitsTheme } from '../../contexts/Theme/KitsThemeProvider.js';
86
87
 
87
88
  const Divider = (props) => {
88
89
  const { nativeProps } = useSeparator(props);
90
+ const rtlLineHeight = useRtlLineHeight(void 0, 14);
89
91
  const {
90
92
  align = "center",
91
93
  children,
@@ -147,7 +149,7 @@ const Divider = (props) => {
147
149
  { backgroundColor: dividerColor },
148
150
  align === "left" || align === "top" ? { flex: 0, width: isHorizontal ? 24 : void 0, height: !isHorizontal ? 24 : void 0 } : { flex: 1 }
149
151
  ] }),
150
- /* @__PURE__ */ jsx(Text, { style: [styles.contentText, { color: resolveToken("text-secondary") }, contentFont ? { fontFamily: contentFont } : null], children }),
152
+ /* @__PURE__ */ jsx(Text, { style: [styles.contentText, { color: resolveToken("text-secondary") }, rtlLineHeight != null ? { lineHeight: rtlLineHeight } : null, contentFont ? { fontFamily: contentFont } : null], children }),
151
153
  /* @__PURE__ */ jsx(View, { style: [
152
154
  isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,
153
155
  { backgroundColor: dividerColor },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/primitives/Divider/index.native.tsx"],"sourcesContent":["import React from 'react';\nimport {View, Text, StyleSheet} from 'react-native';\nimport type {IDividerComponent} from '@lmb-it/kitsconcerto-types';\nimport {useSeparator} from \"../../factory\";\nimport {useKitsTheme} from '../../contexts/Theme';\nimport useThemedFont from '../../hooks/useThemedFont';\n\nconst Divider: React.FC<IDividerComponent> = (props) => {\n const {nativeProps} = useSeparator<any>(props);\n const {\n align = 'center',\n children,\n layout = 'horizontal',\n type: borderType = 'solid',\n unstyled = false,\n ...rest\n } = nativeProps;\n\n const {resolveToken} = useKitsTheme();\n // `color` overrides the line colour (resolved through the theme — token,\n // hex, or named); falls back to the `divider` token when omitted.\n const dividerColor = typeof props.color === 'string'\n ? resolveToken(props.color)\n : resolveToken('divider');\n const contentFont = useThemedFont('body');\n\n const isHorizontal = layout === 'horizontal';\n\n if (unstyled) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n rest.style,\n ]}\n />\n );\n }\n\n const lineStyle = isHorizontal\n ? [styles.horizontalLine, {borderBottomStyle: borderType, borderBottomColor: dividerColor}]\n : [styles.verticalLine, {borderLeftStyle: borderType, borderLeftColor: dividerColor}];\n\n if (!children) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n isHorizontal\n ? {borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: dividerColor, borderStyle: borderType}\n : {borderLeftWidth: StyleSheet.hairlineWidth, borderLeftColor: dividerColor, borderStyle: borderType},\n rest.style,\n ]}\n />\n );\n }\n\n const alignMap: Record<string, 'flex-start' | 'center' | 'flex-end'> = {\n left: 'flex-start',\n top: 'flex-start',\n center: 'center',\n right: 'flex-end',\n bottom: 'flex-end',\n };\n const justifyContent = alignMap[align] ?? 'center';\n\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontalWithContent : styles.verticalWithContent,\n {justifyContent},\n rest.style,\n ]}>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'left' || align === 'top' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n <Text style={[styles.contentText, {color: resolveToken('text-secondary')}, contentFont ? {fontFamily: contentFont} : null]}>\n {children}\n </Text>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'right' || align === 'bottom' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n horizontal: {\n width: '100%',\n flexDirection: 'row',\n },\n vertical: {\n height: '100%',\n flexDirection: 'column',\n },\n horizontalWithContent: {\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n verticalWithContent: {\n height: '100%',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 12,\n },\n horizontalLine: {\n width: '100%',\n },\n verticalLine: {\n height: '100%',\n },\n lineSegment: {\n height: StyleSheet.hairlineWidth,\n flex: 1,\n },\n lineSegmentVertical: {\n width: StyleSheet.hairlineWidth,\n flex: 1,\n },\n contentText: {\n fontSize: 14,\n },\n});\n\nexport default Divider;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/primitives/Divider/index.native.tsx"],"sourcesContent":["import React from 'react';\nimport {View, Text, StyleSheet} from 'react-native';\nimport type {IDividerComponent} from '@lmb-it/kitsconcerto-types';\nimport {useSeparator} from \"../../factory\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\nimport {useKitsTheme} from '../../contexts/Theme';\nimport useThemedFont from '../../hooks/useThemedFont';\n\nconst Divider: React.FC<IDividerComponent> = (props) => {\n const {nativeProps} = useSeparator<any>(props);\n /*\n * ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX — a raw react-native <Text>\n * with a fontSize and no lineHeight gets the FONT'S natural box, and\n * NotoKufiArabic's is too short for its own ascenders. In an RTL script\n * that reads as a BAD TRANSLATION rather than as clipping: ش/س, غ/ع and\n * ة/ه differ only by marks above the baseline.\n * ⚠️ undefined in LTR, so no English layout moves.\n */\n const rtlLineHeight = useRtlLineHeight(undefined, 14);\n const {\n align = 'center',\n children,\n layout = 'horizontal',\n type: borderType = 'solid',\n unstyled = false,\n ...rest\n } = nativeProps;\n\n const {resolveToken} = useKitsTheme();\n // `color` overrides the line colour (resolved through the theme — token,\n // hex, or named); falls back to the `divider` token when omitted.\n const dividerColor = typeof props.color === 'string'\n ? resolveToken(props.color)\n : resolveToken('divider');\n const contentFont = useThemedFont('body');\n\n const isHorizontal = layout === 'horizontal';\n\n if (unstyled) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n rest.style,\n ]}\n />\n );\n }\n\n const lineStyle = isHorizontal\n ? [styles.horizontalLine, {borderBottomStyle: borderType, borderBottomColor: dividerColor}]\n : [styles.verticalLine, {borderLeftStyle: borderType, borderLeftColor: dividerColor}];\n\n if (!children) {\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontal : styles.vertical,\n isHorizontal\n ? {borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: dividerColor, borderStyle: borderType}\n : {borderLeftWidth: StyleSheet.hairlineWidth, borderLeftColor: dividerColor, borderStyle: borderType},\n rest.style,\n ]}\n />\n );\n }\n\n const alignMap: Record<string, 'flex-start' | 'center' | 'flex-end'> = {\n left: 'flex-start',\n top: 'flex-start',\n center: 'center',\n right: 'flex-end',\n bottom: 'flex-end',\n };\n const justifyContent = alignMap[align] ?? 'center';\n\n return (\n <View\n {...rest}\n style={[\n isHorizontal ? styles.horizontalWithContent : styles.verticalWithContent,\n {justifyContent},\n rest.style,\n ]}>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'left' || align === 'top' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n <Text style={[styles.contentText, {color: resolveToken('text-secondary')}, rtlLineHeight != null ? {lineHeight: rtlLineHeight} : null, contentFont ? {fontFamily: contentFont} : null]}>\n {children}\n </Text>\n <View style={[\n isHorizontal ? styles.lineSegment : styles.lineSegmentVertical,\n {backgroundColor: dividerColor},\n align === 'right' || align === 'bottom' ? {flex: 0, width: isHorizontal ? 24 : undefined, height: !isHorizontal ? 24 : undefined} : {flex: 1},\n ]} />\n </View>\n );\n};\n\nconst styles = StyleSheet.create({\n horizontal: {\n width: '100%',\n flexDirection: 'row',\n },\n vertical: {\n height: '100%',\n flexDirection: 'column',\n },\n horizontalWithContent: {\n width: '100%',\n flexDirection: 'row',\n alignItems: 'center',\n gap: 12,\n },\n verticalWithContent: {\n height: '100%',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 12,\n },\n horizontalLine: {\n width: '100%',\n },\n verticalLine: {\n height: '100%',\n },\n lineSegment: {\n height: StyleSheet.hairlineWidth,\n flex: 1,\n },\n lineSegmentVertical: {\n width: StyleSheet.hairlineWidth,\n flex: 1,\n },\n contentText: {\n fontSize: 14,\n },\n});\n\nexport default Divider;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,MAAM,OAAA,GAAuC,CAAC,KAAA,KAAU;AACpD,EAAA,MAAM,EAAC,WAAA,EAAW,GAAI,YAAA,CAAkB,KAAK,CAAA;AAS7C,EAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,MAAA,EAAW,EAAE,CAAA;AACpD,EAAA,MAAM;AAAA,IACF,KAAA,GAAQ,QAAA;AAAA,IACR,QAAA;AAAA,IACA,MAAA,GAAS,YAAA;AAAA,IACT,MAAM,UAAA,GAAa,OAAA;AAAA,IACnB,QAAA,GAAW,KAAA;AAAA,IACX,GAAG;AAAA,GACP,GAAI,WAAA;AAEJ,EAAA,MAAM,EAAC,YAAA,EAAY,GAAI,YAAA,EAAa;AAGpC,EAAA,MAAM,YAAA,GAAe,OAAO,KAAA,CAAM,KAAA,KAAU,QAAA,GACtC,aAAa,KAAA,CAAM,KAAK,CAAA,GACxB,YAAA,CAAa,SAAS,CAAA;AAC5B,EAAA,MAAM,WAAA,GAAc,cAAc,MAAM,CAAA;AAExC,EAAA,MAAM,eAAe,MAAA,KAAW,YAAA;AAEhC,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,uBACI,GAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACI,GAAG,IAAA;AAAA,QACJ,KAAA,EAAO;AAAA,UACH,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,QAAA;AAAA,UAC1C,IAAA,CAAK;AAAA;AACT;AAAA,KACJ;AAAA,EAER;AAEA,EAAkB,eACZ,CAAC,MAAA,CAAO,gBAAgB,EAAC,iBAAA,EAAmB,YAAY,iBAAA,EAAmB,YAAA,EAAa,CAAA,GACxF,CAAC,OAAO,YAAA,EAAc,EAAC,iBAAiB,UAAA,EAAY,eAAA,EAAiB,cAAa;AAExF,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA,uBACI,GAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACI,GAAG,IAAA;AAAA,QACJ,KAAA,EAAO;AAAA,UACH,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,QAAA;AAAA,UAC1C,eACM,EAAC,iBAAA,EAAmB,UAAA,CAAW,aAAA,EAAe,mBAAmB,YAAA,EAAc,WAAA,EAAa,UAAA,EAAU,GACtG,EAAC,eAAA,EAAiB,UAAA,CAAW,eAAe,eAAA,EAAiB,YAAA,EAAc,aAAa,UAAA,EAAU;AAAA,UACxG,IAAA,CAAK;AAAA;AACT;AAAA,KACJ;AAAA,EAER;AAEA,EAAA,MAAM,QAAA,GAAiE;AAAA,IACnE,IAAA,EAAM,YAAA;AAAA,IACN,GAAA,EAAK,YAAA;AAAA,IACL,MAAA,EAAQ,QAAA;AAAA,IACR,KAAA,EAAO,UAAA;AAAA,IACP,MAAA,EAAQ;AAAA,GACZ;AACA,EAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,KAAK,CAAA,IAAK,QAAA;AAE1C,EAAA,uBACI,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACI,GAAG,IAAA;AAAA,MACJ,KAAA,EAAO;AAAA,QACH,YAAA,GAAe,MAAA,CAAO,qBAAA,GAAwB,MAAA,CAAO,mBAAA;AAAA,QACrD,EAAC,cAAA,EAAc;AAAA,QACf,IAAA,CAAK;AAAA,OACT;AAAA,MACA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,QAAK,KAAA,EAAO;AAAA,UACT,YAAA,GAAe,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,mBAAA;AAAA,UAC3C,EAAC,iBAAiB,YAAA,EAAY;AAAA,UAC9B,UAAU,MAAA,IAAU,KAAA,KAAU,QAAQ,EAAC,IAAA,EAAM,GAAG,KAAA,EAAO,YAAA,GAAe,KAAK,MAAA,EAAW,MAAA,EAAQ,CAAC,YAAA,GAAe,EAAA,GAAK,QAAS,GAAI,EAAC,MAAM,CAAA;AAAC,SAC5I,EAAG,CAAA;AAAA,wBACH,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,CAAC,MAAA,CAAO,WAAA,EAAa,EAAC,KAAA,EAAO,YAAA,CAAa,gBAAgB,CAAA,EAAC,EAAG,aAAA,IAAiB,OAAO,EAAC,UAAA,EAAY,aAAA,EAAa,GAAI,IAAA,EAAM,WAAA,GAAc,EAAC,UAAA,EAAY,WAAA,EAAW,GAAI,IAAI,CAAA,EAChL,QAAA,EACL,CAAA;AAAA,wBACA,GAAA,CAAC,QAAK,KAAA,EAAO;AAAA,UACT,YAAA,GAAe,MAAA,CAAO,WAAA,GAAc,MAAA,CAAO,mBAAA;AAAA,UAC3C,EAAC,iBAAiB,YAAA,EAAY;AAAA,UAC9B,UAAU,OAAA,IAAW,KAAA,KAAU,WAAW,EAAC,IAAA,EAAM,GAAG,KAAA,EAAO,YAAA,GAAe,KAAK,MAAA,EAAW,MAAA,EAAQ,CAAC,YAAA,GAAe,EAAA,GAAK,QAAS,GAAI,EAAC,MAAM,CAAA;AAAC,SAChJ,EAAG;AAAA;AAAA;AAAA,GACP;AAER;AAEA,MAAM,MAAA,GAAS,WAAW,MAAA,CAAO;AAAA,EAC7B,UAAA,EAAY;AAAA,IACR,KAAA,EAAO,MAAA;AAAA,IACP,aAAA,EAAe;AAAA,GACnB;AAAA,EACA,QAAA,EAAU;AAAA,IACN,MAAA,EAAQ,MAAA;AAAA,IACR,aAAA,EAAe;AAAA,GACnB;AAAA,EACA,qBAAA,EAAuB;AAAA,IACnB,KAAA,EAAO,MAAA;AAAA,IACP,aAAA,EAAe,KAAA;AAAA,IACf,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK;AAAA,GACT;AAAA,EACA,mBAAA,EAAqB;AAAA,IACjB,MAAA,EAAQ,MAAA;AAAA,IACR,aAAA,EAAe,QAAA;AAAA,IACf,UAAA,EAAY,QAAA;AAAA,IACZ,GAAA,EAAK;AAAA,GACT;AAAA,EACA,cAAA,EAAgB;AAAA,IACZ,KAAA,EAAO;AAAA,GACX;AAAA,EACA,YAAA,EAAc;AAAA,IACV,MAAA,EAAQ;AAAA,GACZ;AAAA,EACA,WAAA,EAAa;AAAA,IACT,QAAQ,UAAA,CAAW,aAAA;AAAA,IACnB,IAAA,EAAM;AAAA,GACV;AAAA,EACA,mBAAA,EAAqB;AAAA,IACjB,OAAO,UAAA,CAAW,aAAA;AAAA,IAClB,IAAA,EAAM;AAAA,GACV;AAAA,EACA,WAAA,EAAa;AAAA,IACT,QAAA,EAAU;AAAA;AAElB,CAAC,CAAA;;;;"}