@lmb-it/kitsconcerto-native 0.1.252 → 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.
Files changed (42) hide show
  1. package/components/Banner/banner.cjs +16 -6
  2. package/components/Banner/banner.cjs.map +1 -1
  3. package/components/Banner/banner.js +17 -7
  4. package/components/Banner/banner.js.map +1 -1
  5. package/components/BottomTabBar/index.cjs +3 -1
  6. package/components/BottomTabBar/index.cjs.map +1 -1
  7. package/components/BottomTabBar/index.js +3 -1
  8. package/components/BottomTabBar/index.js.map +1 -1
  9. package/components/Chip/index.cjs +13 -1
  10. package/components/Chip/index.cjs.map +1 -1
  11. package/components/Chip/index.js +13 -1
  12. package/components/Chip/index.js.map +1 -1
  13. package/components/MessageComposer/index.cjs +5 -2
  14. package/components/MessageComposer/index.cjs.map +1 -1
  15. package/components/MessageComposer/index.js +5 -2
  16. package/components/MessageComposer/index.js.map +1 -1
  17. package/components/TypingIndicator/index.cjs +3 -1
  18. package/components/TypingIndicator/index.cjs.map +1 -1
  19. package/components/TypingIndicator/index.js +3 -1
  20. package/components/TypingIndicator/index.js.map +1 -1
  21. package/hooks/useSeverityColors.cjs +14 -18
  22. package/hooks/useSeverityColors.cjs.map +1 -1
  23. package/hooks/useSeverityColors.js +14 -18
  24. package/hooks/useSeverityColors.js.map +1 -1
  25. package/index.d.ts +34 -0
  26. package/locale/ar.json.cjs +4 -1
  27. package/locale/ar.json.cjs.map +1 -1
  28. package/locale/ar.json.js +4 -2
  29. package/locale/ar.json.js.map +1 -1
  30. package/locale/en.json.cjs +4 -1
  31. package/locale/en.json.cjs.map +1 -1
  32. package/locale/en.json.js +4 -2
  33. package/locale/en.json.js.map +1 -1
  34. package/package.json +1 -1
  35. package/primitives/Divider/index.cjs +3 -1
  36. package/primitives/Divider/index.cjs.map +1 -1
  37. package/primitives/Divider/index.js +3 -1
  38. package/primitives/Divider/index.js.map +1 -1
  39. package/primitives/Text/index.cjs +6 -2
  40. package/primitives/Text/index.cjs.map +1 -1
  41. package/primitives/Text/index.js +6 -2
  42. package/primitives/Text/index.js.map +1 -1
@@ -5,6 +5,7 @@ import { IconMap } from '../../assets/Icons/index.js';
5
5
  import { useSeverityColors } from '../../hooks/useSeverityColors.js';
6
6
  import '../../contexts/DialogContext.js';
7
7
  import useResolvedStyle from '../../hooks/useResolvedStyle.js';
8
+ import useRtlLineHeight from '../../hooks/useRtlLineHeight.js';
8
9
 
9
10
  const SIZE_MAP = {
10
11
  sm: { fontSize: 12, px: 8, py: 4, gap: 6, iconSize: 12, height: 24, removeSize: 12 },
@@ -53,6 +54,7 @@ function Chip(props) {
53
54
  const sizeStr = String(rawSize ?? "md");
54
55
  const size = sizeStr === "sm" || sizeStr === "lg" ? sizeStr : "md";
55
56
  const sizeConfig = SIZE_MAP[size];
57
+ const rtlLineHeight = useRtlLineHeight(size, sizeConfig.fontSize);
56
58
  const sevColors = useSeverityColors(severity);
57
59
  const visual = useMemo(() => {
58
60
  if (selected && !outlined) {
@@ -103,7 +105,17 @@ function Chip(props) {
103
105
  style: {
104
106
  fontSize: sizeConfig.fontSize,
105
107
  fontWeight: "500",
106
- color: visual.textColor
108
+ color: visual.textColor,
109
+ /* ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX, AND THE
110
+ CHIP'S OWN HEIGHT DOES NOT SAVE IT. Every SIZE_MAP
111
+ row is already tall enough — 24/32/40 against font
112
+ sizes 12/14/16, all above the 1.5x this script needs.
113
+ The container was never the problem: React Native
114
+ gives this raw <Text> the FONT'S natural line box,
115
+ and NotoKufiArabic's is too short for its own
116
+ ascenders, so the glyph is cut inside a box with room
117
+ to spare. undefined in LTR — English is unchanged. */
118
+ ...rtlLineHeight != null ? { lineHeight: rtlLineHeight } : {}
107
119
  },
108
120
  numberOfLines: 1,
109
121
  children: content
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/components/Chip/index.native.tsx"],"sourcesContent":["import React, {useMemo} from \"react\";\nimport {Pressable, Text, View, StyleSheet} from \"react-native\";\nimport type {IChipProps, IconName} from \"@lmb-it/kitsconcerto-types\";\nimport {IconMap} from \"../../assets/Icons\";\nimport {useSeverityColors} from \"../../hooks/useSeverityColors\";\nimport {useResolvedStyle} from \"../../hooks\";\n\nconst SIZE_MAP = {\n sm: {fontSize: 12, px: 8, py: 4, gap: 6, iconSize: 12, height: 24, removeSize: 12},\n md: {fontSize: 14, px: 12, py: 6, gap: 6, iconSize: 14, height: 32, removeSize: 14},\n lg: {fontSize: 16, px: 14, py: 8, gap: 8, iconSize: 16, height: 40, removeSize: 16},\n} as const;\n\nfunction resolveIcon(icon: unknown, color: string, iconSize: number): React.ReactNode {\n if (!icon) return null;\n if (icon === \"dot\") {\n return (\n <View\n style={{\n width: 6,\n height: 6,\n borderRadius: 3,\n backgroundColor: color,\n }}\n />\n );\n }\n if (React.isValidElement(icon)) return icon;\n if (typeof icon !== \"string\") return null;\n const Component = IconMap[icon as IconName];\n if (Component) return <Component size={iconSize} color={color}/>;\n return null;\n}\n\nexport function Chip(props: IChipProps) {\n const {\n label,\n children,\n icon,\n selected = false,\n onPress,\n disabled = false,\n onRemove,\n severity = \"secondary\",\n size: rawSize,\n outlined,\n testID,\n style,\n // LEGIT-PLATFORM-ONLY (web): className is a CSS class hook with no\n // native equivalent — use `style` for cross-platform overrides.\n } = props;\n const resolvedStyle = useResolvedStyle(style || {});\n\n const sizeStr = String(rawSize ?? \"md\");\n const size: \"sm\" | \"md\" | \"lg\" = sizeStr === \"sm\" || sizeStr === \"lg\" ? sizeStr : \"md\";\n const sizeConfig = SIZE_MAP[size];\n\n const sevColors = useSeverityColors(severity as any);\n\n const visual = useMemo(() => {\n if (selected && !outlined) {\n return {\n backgroundColor: sevColors.solid,\n textColor: sevColors.solidText,\n borderColor: sevColors.border || sevColors.solid,\n };\n }\n if (outlined) {\n return {\n backgroundColor: \"transparent\",\n textColor: sevColors.solid,\n borderColor: sevColors.solid,\n };\n }\n return {\n backgroundColor: sevColors.bgTint,\n textColor: sevColors.text,\n borderColor: sevColors.border,\n };\n }, [selected, outlined, sevColors]);\n\n const resolvedIcon = resolveIcon(icon, visual.textColor, sizeConfig.iconSize);\n const content = label ?? children;\n const isInteractive = !!onPress && !disabled;\n\n const containerStyle = {\n flexDirection: \"row\" as const,\n alignItems: \"center\" as const,\n justifyContent: \"center\" as const,\n gap: sizeConfig.gap,\n height: sizeConfig.height,\n paddingHorizontal: sizeConfig.px,\n paddingRight: onRemove ? sizeConfig.gap : sizeConfig.px,\n borderRadius: 9999,\n borderWidth: 1,\n borderStyle: \"solid\" as const,\n backgroundColor: visual.backgroundColor,\n borderColor: visual.borderColor,\n opacity: disabled ? 0.5 : 1,\n // Consumer `style` wins last — mirrors web's computedCss merge order.\n ...(resolvedStyle as object),\n };\n\n const inner = (\n <>\n {resolvedIcon}\n {content != null && (\n <Text\n style={{\n fontSize: sizeConfig.fontSize,\n fontWeight: \"500\",\n color: visual.textColor,\n }}\n numberOfLines={1}\n >\n {content}\n </Text>\n )}\n {onRemove && (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Remove\"\n onPress={(e) => {\n e.stopPropagation?.();\n if (!disabled) onRemove();\n }}\n hitSlop={6}\n style={{\n marginLeft: 2,\n width: sizeConfig.removeSize + 4,\n height: sizeConfig.removeSize + 4,\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: (sizeConfig.removeSize + 4) / 2,\n }}\n >\n <Text style={{fontSize: sizeConfig.removeSize, color: visual.textColor, lineHeight: sizeConfig.removeSize + 2}}>×</Text>\n </Pressable>\n )}\n </>\n );\n\n if (isInteractive) {\n return (\n <Pressable\n onPress={onPress}\n disabled={disabled}\n accessibilityRole=\"button\"\n accessibilityState={{selected, disabled}}\n testID={testID}\n style={({pressed}) => [containerStyle, pressed && styles.pressed]}\n >\n {inner}\n </Pressable>\n );\n }\n\n return (\n <View style={containerStyle} testID={testID}>\n {inner}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n pressed: {\n opacity: 0.7,\n },\n});\n\nexport default Chip;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/Chip/index.native.tsx"],"sourcesContent":["import React, {useMemo} from \"react\";\nimport {Pressable, Text, View, StyleSheet} from \"react-native\";\nimport type {IChipProps, IconName} from \"@lmb-it/kitsconcerto-types\";\nimport {IconMap} from \"../../assets/Icons\";\nimport {useSeverityColors} from \"../../hooks/useSeverityColors\";\nimport {useResolvedStyle} from \"../../hooks\";\nimport useRtlLineHeight from \"../../hooks/useRtlLineHeight\";\n\nconst SIZE_MAP = {\n sm: {fontSize: 12, px: 8, py: 4, gap: 6, iconSize: 12, height: 24, removeSize: 12},\n md: {fontSize: 14, px: 12, py: 6, gap: 6, iconSize: 14, height: 32, removeSize: 14},\n lg: {fontSize: 16, px: 14, py: 8, gap: 8, iconSize: 16, height: 40, removeSize: 16},\n} as const;\n\nfunction resolveIcon(icon: unknown, color: string, iconSize: number): React.ReactNode {\n if (!icon) return null;\n if (icon === \"dot\") {\n return (\n <View\n style={{\n width: 6,\n height: 6,\n borderRadius: 3,\n backgroundColor: color,\n }}\n />\n );\n }\n if (React.isValidElement(icon)) return icon;\n if (typeof icon !== \"string\") return null;\n const Component = IconMap[icon as IconName];\n if (Component) return <Component size={iconSize} color={color}/>;\n return null;\n}\n\nexport function Chip(props: IChipProps) {\n const {\n label,\n children,\n icon,\n selected = false,\n onPress,\n disabled = false,\n onRemove,\n severity = \"secondary\",\n size: rawSize,\n outlined,\n testID,\n style,\n // LEGIT-PLATFORM-ONLY (web): className is a CSS class hook with no\n // native equivalent — use `style` for cross-platform overrides.\n } = props;\n const resolvedStyle = useResolvedStyle(style || {});\n\n const sizeStr = String(rawSize ?? \"md\");\n const size: \"sm\" | \"md\" | \"lg\" = sizeStr === \"sm\" || sizeStr === \"lg\" ? sizeStr : \"md\";\n const sizeConfig = SIZE_MAP[size];\n\n // RTL only: NotoKufiArabic needs a taller line box than its own metrics\n // give it. `undefined` in LTR, so English chips are byte-identical.\n const rtlLineHeight = useRtlLineHeight(size as string, sizeConfig.fontSize);\n\n const sevColors = useSeverityColors(severity as any);\n\n const visual = useMemo(() => {\n if (selected && !outlined) {\n return {\n backgroundColor: sevColors.solid,\n textColor: sevColors.solidText,\n borderColor: sevColors.border || sevColors.solid,\n };\n }\n if (outlined) {\n return {\n backgroundColor: \"transparent\",\n textColor: sevColors.solid,\n borderColor: sevColors.solid,\n };\n }\n return {\n backgroundColor: sevColors.bgTint,\n textColor: sevColors.text,\n borderColor: sevColors.border,\n };\n }, [selected, outlined, sevColors]);\n\n const resolvedIcon = resolveIcon(icon, visual.textColor, sizeConfig.iconSize);\n const content = label ?? children;\n const isInteractive = !!onPress && !disabled;\n\n const containerStyle = {\n flexDirection: \"row\" as const,\n alignItems: \"center\" as const,\n justifyContent: \"center\" as const,\n gap: sizeConfig.gap,\n height: sizeConfig.height,\n paddingHorizontal: sizeConfig.px,\n paddingRight: onRemove ? sizeConfig.gap : sizeConfig.px,\n borderRadius: 9999,\n borderWidth: 1,\n borderStyle: \"solid\" as const,\n backgroundColor: visual.backgroundColor,\n borderColor: visual.borderColor,\n opacity: disabled ? 0.5 : 1,\n // Consumer `style` wins last — mirrors web's computedCss merge order.\n ...(resolvedStyle as object),\n };\n\n const inner = (\n <>\n {resolvedIcon}\n {content != null && (\n <Text\n style={{\n fontSize: sizeConfig.fontSize,\n fontWeight: \"500\",\n color: visual.textColor,\n /* ⛔ ARABIC CLIPS WITHOUT AN EXPLICIT LINE BOX, AND THE\n CHIP'S OWN HEIGHT DOES NOT SAVE IT. Every SIZE_MAP\n row is already tall enough — 24/32/40 against font\n sizes 12/14/16, all above the 1.5x this script needs.\n The container was never the problem: React Native\n gives this raw <Text> the FONT'S natural line box,\n and NotoKufiArabic's is too short for its own\n ascenders, so the glyph is cut inside a box with room\n to spare. undefined in LTR — English is unchanged. */\n ...(rtlLineHeight != null ? {lineHeight: rtlLineHeight} : {}),\n }}\n numberOfLines={1}\n >\n {content}\n </Text>\n )}\n {onRemove && (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel=\"Remove\"\n onPress={(e) => {\n e.stopPropagation?.();\n if (!disabled) onRemove();\n }}\n hitSlop={6}\n style={{\n marginLeft: 2,\n width: sizeConfig.removeSize + 4,\n height: sizeConfig.removeSize + 4,\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: (sizeConfig.removeSize + 4) / 2,\n }}\n >\n <Text style={{fontSize: sizeConfig.removeSize, color: visual.textColor, lineHeight: sizeConfig.removeSize + 2}}>×</Text>\n </Pressable>\n )}\n </>\n );\n\n if (isInteractive) {\n return (\n <Pressable\n onPress={onPress}\n disabled={disabled}\n accessibilityRole=\"button\"\n accessibilityState={{selected, disabled}}\n testID={testID}\n style={({pressed}) => [containerStyle, pressed && styles.pressed]}\n >\n {inner}\n </Pressable>\n );\n }\n\n return (\n <View style={containerStyle} testID={testID}>\n {inner}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n pressed: {\n opacity: 0.7,\n },\n});\n\nexport default Chip;\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 {