@lmb-it/kitsconcerto-native 0.1.250 → 0.1.251

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.
@@ -91,6 +91,7 @@ require('../../contexts/DialogContext.cjs');
91
91
  var useComponentDefaults = require('../../hooks/useComponentDefaults.cjs');
92
92
  var useSeverityColors = require('../../hooks/useSeverityColors.cjs');
93
93
  var useThemedFont = require('../../hooks/useThemedFont.cjs');
94
+ var KitsThemeProvider_native = require('../../contexts/Theme/KitsThemeProvider.cjs');
94
95
 
95
96
  const SIZE_MAP = {
96
97
  sm: { height: 32, fontSize: 12, px: 10, py: 6, gap: 6, iconSize: 14 },
@@ -143,9 +144,11 @@ function Button(rawProps) {
143
144
  const resolvedLabel = typeof children === "string" ? children : loading && isLoadingText ? isLoadingText : label ? t(label) : "";
144
145
  const hasLabel = !!resolvedLabel;
145
146
  const isIconOnly = !hasLabel && !!icon;
146
- const textColor = outlined ? sevColors.solid : sevColors.solidText;
147
- const bgColor = outlined ? "transparent" : sevColors.solid;
148
- const borderColor = sevColors.border || sevColors.solid;
147
+ const { resolveToken } = KitsThemeProvider_native.useKitsTheme();
148
+ const disabledText = resolveToken("text-subtle");
149
+ const textColor = isDisabled ? disabledText : outlined ? sevColors.solid : sevColors.solidText;
150
+ const bgColor = outlined ? "transparent" : isDisabled ? resolveToken("surface-muted") : sevColors.solid;
151
+ const borderColor = isDisabled ? resolveToken("border") : sevColors.border || sevColors.solid;
149
152
  const computedCss = React.useMemo(() => ({
150
153
  backgroundColor: bgColor,
151
154
  borderColor,
@@ -160,7 +163,9 @@ function Button(rawProps) {
160
163
  alignItems: "center",
161
164
  justifyContent: "center",
162
165
  gap: sizeConfig.gap,
163
- opacity: isDisabled ? 50 : 100,
166
+ // ⚠️ NO OPACITY BRANCH. The colours above carry the state now; fading
167
+ // them as well would take the new muted label back below legibility.
168
+ opacity: 100,
164
169
  alignSelf: "flex-start",
165
170
  overflow: "hidden",
166
171
  ...raised ? {
@@ -1 +1 @@
1
- {"version":3,"file":"Button.cjs","sources":["../../../../src/components/Button/Button.native.tsx"],"sourcesContent":["import React, {useMemo, useCallback, type ElementType, type ReactElement} from 'react';\nimport {\n ActivityIndicator,\n Text as RNText,\n type TextStyle,\n type GestureResponderEvent,\n} from 'react-native';\nimport type {IButtonProps, IconName, IStyleClasses} from '@lmb-it/kitsconcerto-types';\nimport {ResponsiveElement, useSeparator, style as resolveStyle} from '@lmb-it/kitsconcertomobile';\nimport {IconMap} from '../../assets/Icons';\nimport {useLanguage, useComponentDefaults, useThemedFont} from '../../hooks';\nimport {useSeverityColors} from '../../hooks/useSeverityColors';\n\n/* ─── Size configuration (matches web) ────────────────────────── */\nconst SIZE_MAP = {\n sm: {height: 32, fontSize: 12, px: 10, py: 6, gap: 6, iconSize: 14},\n md: {height: 40, fontSize: 14, px: 16, py: 10, gap: 8, iconSize: 16},\n lg: {height: 48, fontSize: 16, px: 24, py: 12, gap: 10, iconSize: 18},\n} as const;\n\n/* ─── Icon resolver ──────────────────────────────────────────── */\nfunction resolveIcon(\n icon: unknown,\n color: string,\n iconSize: number,\n): React.ReactNode {\n if (!icon) return null;\n if (React.isValidElement(icon)) {\n return React.cloneElement(icon as ReactElement<any>, {color, size: iconSize});\n }\n if (typeof icon === 'function') {\n const Comp = icon as ElementType;\n return <Comp size={iconSize} color={color} />;\n }\n if (typeof icon !== 'string') return null;\n const piMatches = icon.match(/pi-([a-z-]+)/g);\n const iconName = piMatches\n ? (piMatches[piMatches.length - 1]!.replace('pi-', '') as IconName)\n : (icon as IconName);\n const Component = IconMap[iconName];\n if (Component) return <Component size={iconSize} color={color} />;\n return null;\n}\n\n/* ─── Button Component ───────────────────────────────────────── */\nexport function Button(rawProps: IButtonProps<IconName | string | ElementType | ReactElement>) {\n const {mergedProps: props, themeStyle, elementStyles} = useComponentDefaults('Button', rawProps);\n const {\n children,\n label,\n isLoadingText,\n severity = 'brand',\n size = 'md',\n loading,\n iconPos = 'left',\n icon,\n disabled,\n outlined,\n raised,\n rounded,\n testID,\n style: styleProp,\n onPress,\n onClick,\n ...rest\n } = props;\n\n const {t} = useLanguage();\n const labelFont = useThemedFont('body');\n const {cssProps, nativeProps} = useSeparator<Record<any, any>>(rest);\n const sevColors = useSeverityColors((severity as any) ?? 'brand');\n\n const sizeConfig = SIZE_MAP[size as keyof typeof SIZE_MAP] ?? SIZE_MAP.md;\n const isDisabled = disabled || loading;\n\n /* ── Resolve label text ── */\n const resolvedLabel = typeof children === 'string'\n ? children\n : loading && isLoadingText\n ? isLoadingText\n : label ? t(label) : '';\n\n const hasLabel = !!resolvedLabel;\n const isIconOnly = !hasLabel && !!icon;\n\n /* ── Severity colors ── */\n const textColor = outlined ? sevColors.solid : sevColors.solidText;\n const bgColor = outlined ? 'transparent' : sevColors.solid;\n const borderColor = sevColors.border || sevColors.solid;\n\n /* ── Build CSS props for ResponsiveElement ── */\n const computedCss:IStyleClasses = useMemo(() => ({\n backgroundColor: bgColor,\n borderColor,\n borderWidth: 1,\n height: sizeConfig.height,\n paddingLeft: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingRight: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingTop: sizeConfig.py,\n paddingBottom: sizeConfig.py,\n borderRadius: rounded ? 9999 : 6,\n flexDirection: iconPos === 'top' || iconPos === 'bottom'\n ? (iconPos === 'bottom' ? 'column-reverse' : 'column')\n : (iconPos === 'right' ? 'row-reverse' : 'row'),\n alignItems: 'center',\n justifyContent: 'center',\n gap: sizeConfig.gap,\n opacity: isDisabled ? 50 : 100,\n alignSelf: 'flex-start',\n overflow: 'hidden',\n ...(raised ? {\n shadowColor: '#000',\n shadowOffset: {width: 0, height: 3},\n shadowOpacity: 0.16,\n shadowRadius: 6,\n elevation: 4,\n } : {}),\n // Theme overrides the defaults above: shared `root` first, then the\n // `text` slot (label buttons) or the `iconOnly` slot. Icon-only buttons\n // are forced square so a `root`/`text` height can never stretch them —\n // the `iconOnly` slot can still override the square if needed.\n ...themeStyle,\n ...(elementStyles.root || {}),\n ...(isIconOnly\n ? {\n width: sizeConfig.height,\n height: sizeConfig.height,\n minWidth: sizeConfig.height,\n ...(elementStyles.iconOnly || {}),\n }\n : (elementStyles.text || {})),\n ...cssProps,\n ...styleProp,\n }), [themeStyle, elementStyles, cssProps, bgColor, borderColor, sizeConfig,\n hasLabel, icon, iconPos, rounded, raised, isDisabled, styleProp, isIconOnly]);\n\n /* ── Icon element ── */\n const iconElement = loading\n ? <ActivityIndicator size=\"small\" color={textColor} />\n : resolveIcon(icon, textColor, sizeConfig.iconSize);\n\n /* ── Text style ── */\n const labelStyle: TextStyle = useMemo(() => ({\n color: textColor,\n fontSize: sizeConfig.fontSize,\n fontWeight: '600',\n lineHeight: sizeConfig.fontSize * 1.2,\n ...(labelFont ? {fontFamily: labelFont} : {}),\n // Theme/per-instance label slot wins — e.g. theme.components.Button.label.style\n // = { lineHeight: 22 } to stop Arabic (NotoKufiArabic) glyphs clipping.\n ...((elementStyles.label as TextStyle) || {}),\n }), [textColor, sizeConfig, labelFont, elementStyles.label]);\n\n /* ── Press handler ── */\n const handlePress = useCallback((e: GestureResponderEvent) => {\n if (isDisabled) return;\n if (onPress) onPress(e as any);\n if (onClick) onClick(e as any);\n }, [isDisabled, onPress, onClick]);\n\n return (\n <ResponsiveElement\n as=\"Pressable\"\n cssProps={computedCss}\n nativeProps={{\n ...nativeProps,\n onPress: handlePress,\n disabled: isDisabled,\n testID,\n accessibilityRole: 'button',\n accessibilityState: {disabled: isDisabled, busy: loading},\n accessibilityLabel: resolvedLabel || undefined,\n }}\n >\n {iconElement}\n {!!hasLabel && (\n <RNText style={labelStyle} numberOfLines={1}>\n {resolvedLabel}\n </RNText>\n )}\n {typeof children !== 'string' ? children : undefined}\n </ResponsiveElement>\n );\n}\n\nexport default Button;\n"],"names":["jsx","IconMap","useComponentDefaults","useLanguage","useThemedFont","useSeparator","useSeverityColors","useMemo","ActivityIndicator","useCallback","jsxs","ResponsiveElement","RNText"],"mappings":"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"}
1
+ {"version":3,"file":"Button.cjs","sources":["../../../../src/components/Button/Button.native.tsx"],"sourcesContent":["import React, {useMemo, useCallback, type ElementType, type ReactElement} from 'react';\nimport {\n ActivityIndicator,\n Text as RNText,\n type TextStyle,\n type GestureResponderEvent,\n} from 'react-native';\nimport type {IButtonProps, IconName, IStyleClasses} from '@lmb-it/kitsconcerto-types';\nimport {ResponsiveElement, useSeparator, style as resolveStyle} from '@lmb-it/kitsconcertomobile';\nimport {IconMap} from '../../assets/Icons';\nimport {useLanguage, useComponentDefaults, useThemedFont} from '../../hooks';\nimport {useSeverityColors} from '../../hooks/useSeverityColors';\nimport {useKitsTheme} from '../../contexts/Theme';\n\n/* ─── Size configuration (matches web) ────────────────────────── */\nconst SIZE_MAP = {\n sm: {height: 32, fontSize: 12, px: 10, py: 6, gap: 6, iconSize: 14},\n md: {height: 40, fontSize: 14, px: 16, py: 10, gap: 8, iconSize: 16},\n lg: {height: 48, fontSize: 16, px: 24, py: 12, gap: 10, iconSize: 18},\n} as const;\n\n/* ─── Icon resolver ──────────────────────────────────────────── */\nfunction resolveIcon(\n icon: unknown,\n color: string,\n iconSize: number,\n): React.ReactNode {\n if (!icon) return null;\n if (React.isValidElement(icon)) {\n return React.cloneElement(icon as ReactElement<any>, {color, size: iconSize});\n }\n if (typeof icon === 'function') {\n const Comp = icon as ElementType;\n return <Comp size={iconSize} color={color} />;\n }\n if (typeof icon !== 'string') return null;\n const piMatches = icon.match(/pi-([a-z-]+)/g);\n const iconName = piMatches\n ? (piMatches[piMatches.length - 1]!.replace('pi-', '') as IconName)\n : (icon as IconName);\n const Component = IconMap[iconName];\n if (Component) return <Component size={iconSize} color={color} />;\n return null;\n}\n\n/* ─── Button Component ───────────────────────────────────────── */\nexport function Button(rawProps: IButtonProps<IconName | string | ElementType | ReactElement>) {\n const {mergedProps: props, themeStyle, elementStyles} = useComponentDefaults('Button', rawProps);\n const {\n children,\n label,\n isLoadingText,\n severity = 'brand',\n size = 'md',\n loading,\n iconPos = 'left',\n icon,\n disabled,\n outlined,\n raised,\n rounded,\n testID,\n style: styleProp,\n onPress,\n onClick,\n ...rest\n } = props;\n\n const {t} = useLanguage();\n const labelFont = useThemedFont('body');\n const {cssProps, nativeProps} = useSeparator<Record<any, any>>(rest);\n const sevColors = useSeverityColors((severity as any) ?? 'brand');\n\n const sizeConfig = SIZE_MAP[size as keyof typeof SIZE_MAP] ?? SIZE_MAP.md;\n const isDisabled = disabled || loading;\n\n /* ── Resolve label text ── */\n const resolvedLabel = typeof children === 'string'\n ? children\n : loading && isLoadingText\n ? isLoadingText\n : label ? t(label) : '';\n\n const hasLabel = !!resolvedLabel;\n const isIconOnly = !hasLabel && !!icon;\n\n /* ── Severity colors ── */\n /*\n * ⛔ A DISABLED BUTTON STOPS BEING THE BRAND, IT DOES NOT FADE — and this is\n * the phone's half of the same change made on web.\n *\n * The only disabled treatment was `opacity: isDisabled ? 50 : 100`, so the\n * button kept its brand fill, its white label and its brand border at half\n * strength. Same colour family, same filled shape, same affordance: it reads\n * as a slightly lighter LIVE button, and white on half-opacity brand is near\n * 1.7:1, so the fade hurts the label more than it announces the state.\n *\n * ⛔ THE COMP ALREADY ANSWERED IT: the locked bid rows draw a disabled\n * control as `#EEF0F2` ground with `#9CA3AF` text at FULL opacity.\n * `surface-muted` and `text-subtle` are the theme's own nearest tokens.\n *\n * ⚠️ OUTLINED KEEPS ITS TRANSPARENT GROUND. Filling it grey would make a\n * quiet control louder disabled than enabled.\n */\n const {resolveToken} = useKitsTheme();\n const disabledText = resolveToken('text-subtle');\n const textColor = isDisabled\n ? disabledText\n : outlined ? sevColors.solid : sevColors.solidText;\n const bgColor = outlined\n ? 'transparent'\n : isDisabled ? resolveToken('surface-muted') : sevColors.solid;\n const borderColor = isDisabled\n ? resolveToken('border')\n : sevColors.border || sevColors.solid;\n\n /* ── Build CSS props for ResponsiveElement ── */\n const computedCss:IStyleClasses = useMemo(() => ({\n backgroundColor: bgColor,\n borderColor,\n borderWidth: 1,\n height: sizeConfig.height,\n paddingLeft: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingRight: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingTop: sizeConfig.py,\n paddingBottom: sizeConfig.py,\n borderRadius: rounded ? 9999 : 6,\n flexDirection: iconPos === 'top' || iconPos === 'bottom'\n ? (iconPos === 'bottom' ? 'column-reverse' : 'column')\n : (iconPos === 'right' ? 'row-reverse' : 'row'),\n alignItems: 'center',\n justifyContent: 'center',\n gap: sizeConfig.gap,\n // ⚠️ NO OPACITY BRANCH. The colours above carry the state now; fading\n // them as well would take the new muted label back below legibility.\n opacity: 100,\n alignSelf: 'flex-start',\n overflow: 'hidden',\n ...(raised ? {\n shadowColor: '#000',\n shadowOffset: {width: 0, height: 3},\n shadowOpacity: 0.16,\n shadowRadius: 6,\n elevation: 4,\n } : {}),\n // Theme overrides the defaults above: shared `root` first, then the\n // `text` slot (label buttons) or the `iconOnly` slot. Icon-only buttons\n // are forced square so a `root`/`text` height can never stretch them —\n // the `iconOnly` slot can still override the square if needed.\n ...themeStyle,\n ...(elementStyles.root || {}),\n ...(isIconOnly\n ? {\n width: sizeConfig.height,\n height: sizeConfig.height,\n minWidth: sizeConfig.height,\n ...(elementStyles.iconOnly || {}),\n }\n : (elementStyles.text || {})),\n ...cssProps,\n ...styleProp,\n }), [themeStyle, elementStyles, cssProps, bgColor, borderColor, sizeConfig,\n hasLabel, icon, iconPos, rounded, raised, isDisabled, styleProp, isIconOnly]);\n\n /* ── Icon element ── */\n const iconElement = loading\n ? <ActivityIndicator size=\"small\" color={textColor} />\n : resolveIcon(icon, textColor, sizeConfig.iconSize);\n\n /* ── Text style ── */\n const labelStyle: TextStyle = useMemo(() => ({\n color: textColor,\n fontSize: sizeConfig.fontSize,\n fontWeight: '600',\n lineHeight: sizeConfig.fontSize * 1.2,\n ...(labelFont ? {fontFamily: labelFont} : {}),\n // Theme/per-instance label slot wins — e.g. theme.components.Button.label.style\n // = { lineHeight: 22 } to stop Arabic (NotoKufiArabic) glyphs clipping.\n ...((elementStyles.label as TextStyle) || {}),\n }), [textColor, sizeConfig, labelFont, elementStyles.label]);\n\n /* ── Press handler ── */\n const handlePress = useCallback((e: GestureResponderEvent) => {\n if (isDisabled) return;\n if (onPress) onPress(e as any);\n if (onClick) onClick(e as any);\n }, [isDisabled, onPress, onClick]);\n\n return (\n <ResponsiveElement\n as=\"Pressable\"\n cssProps={computedCss}\n nativeProps={{\n ...nativeProps,\n onPress: handlePress,\n disabled: isDisabled,\n testID,\n accessibilityRole: 'button',\n accessibilityState: {disabled: isDisabled, busy: loading},\n accessibilityLabel: resolvedLabel || undefined,\n }}\n >\n {iconElement}\n {!!hasLabel && (\n <RNText style={labelStyle} numberOfLines={1}>\n {resolvedLabel}\n </RNText>\n )}\n {typeof children !== 'string' ? children : undefined}\n </ResponsiveElement>\n );\n}\n\nexport default Button;\n"],"names":["jsx","IconMap","useComponentDefaults","useLanguage","useThemedFont","useSeparator","useSeverityColors","useKitsTheme","useMemo","ActivityIndicator","useCallback","jsxs","ResponsiveElement","RNText"],"mappings":"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"}
@@ -87,6 +87,7 @@ import '../../contexts/DialogContext.js';
87
87
  import useComponentDefaults from '../../hooks/useComponentDefaults.js';
88
88
  import { useSeverityColors } from '../../hooks/useSeverityColors.js';
89
89
  import useThemedFont from '../../hooks/useThemedFont.js';
90
+ import { useKitsTheme } from '../../contexts/Theme/KitsThemeProvider.js';
90
91
 
91
92
  const SIZE_MAP = {
92
93
  sm: { height: 32, fontSize: 12, px: 10, py: 6, gap: 6, iconSize: 14 },
@@ -139,9 +140,11 @@ function Button(rawProps) {
139
140
  const resolvedLabel = typeof children === "string" ? children : loading && isLoadingText ? isLoadingText : label ? t(label) : "";
140
141
  const hasLabel = !!resolvedLabel;
141
142
  const isIconOnly = !hasLabel && !!icon;
142
- const textColor = outlined ? sevColors.solid : sevColors.solidText;
143
- const bgColor = outlined ? "transparent" : sevColors.solid;
144
- const borderColor = sevColors.border || sevColors.solid;
143
+ const { resolveToken } = useKitsTheme();
144
+ const disabledText = resolveToken("text-subtle");
145
+ const textColor = isDisabled ? disabledText : outlined ? sevColors.solid : sevColors.solidText;
146
+ const bgColor = outlined ? "transparent" : isDisabled ? resolveToken("surface-muted") : sevColors.solid;
147
+ const borderColor = isDisabled ? resolveToken("border") : sevColors.border || sevColors.solid;
145
148
  const computedCss = useMemo(() => ({
146
149
  backgroundColor: bgColor,
147
150
  borderColor,
@@ -156,7 +159,9 @@ function Button(rawProps) {
156
159
  alignItems: "center",
157
160
  justifyContent: "center",
158
161
  gap: sizeConfig.gap,
159
- opacity: isDisabled ? 50 : 100,
162
+ // ⚠️ NO OPACITY BRANCH. The colours above carry the state now; fading
163
+ // them as well would take the new muted label back below legibility.
164
+ opacity: 100,
160
165
  alignSelf: "flex-start",
161
166
  overflow: "hidden",
162
167
  ...raised ? {
@@ -1 +1 @@
1
- {"version":3,"file":"Button.js","sources":["../../../../src/components/Button/Button.native.tsx"],"sourcesContent":["import React, {useMemo, useCallback, type ElementType, type ReactElement} from 'react';\nimport {\n ActivityIndicator,\n Text as RNText,\n type TextStyle,\n type GestureResponderEvent,\n} from 'react-native';\nimport type {IButtonProps, IconName, IStyleClasses} from '@lmb-it/kitsconcerto-types';\nimport {ResponsiveElement, useSeparator, style as resolveStyle} from '@lmb-it/kitsconcertomobile';\nimport {IconMap} from '../../assets/Icons';\nimport {useLanguage, useComponentDefaults, useThemedFont} from '../../hooks';\nimport {useSeverityColors} from '../../hooks/useSeverityColors';\n\n/* ─── Size configuration (matches web) ────────────────────────── */\nconst SIZE_MAP = {\n sm: {height: 32, fontSize: 12, px: 10, py: 6, gap: 6, iconSize: 14},\n md: {height: 40, fontSize: 14, px: 16, py: 10, gap: 8, iconSize: 16},\n lg: {height: 48, fontSize: 16, px: 24, py: 12, gap: 10, iconSize: 18},\n} as const;\n\n/* ─── Icon resolver ──────────────────────────────────────────── */\nfunction resolveIcon(\n icon: unknown,\n color: string,\n iconSize: number,\n): React.ReactNode {\n if (!icon) return null;\n if (React.isValidElement(icon)) {\n return React.cloneElement(icon as ReactElement<any>, {color, size: iconSize});\n }\n if (typeof icon === 'function') {\n const Comp = icon as ElementType;\n return <Comp size={iconSize} color={color} />;\n }\n if (typeof icon !== 'string') return null;\n const piMatches = icon.match(/pi-([a-z-]+)/g);\n const iconName = piMatches\n ? (piMatches[piMatches.length - 1]!.replace('pi-', '') as IconName)\n : (icon as IconName);\n const Component = IconMap[iconName];\n if (Component) return <Component size={iconSize} color={color} />;\n return null;\n}\n\n/* ─── Button Component ───────────────────────────────────────── */\nexport function Button(rawProps: IButtonProps<IconName | string | ElementType | ReactElement>) {\n const {mergedProps: props, themeStyle, elementStyles} = useComponentDefaults('Button', rawProps);\n const {\n children,\n label,\n isLoadingText,\n severity = 'brand',\n size = 'md',\n loading,\n iconPos = 'left',\n icon,\n disabled,\n outlined,\n raised,\n rounded,\n testID,\n style: styleProp,\n onPress,\n onClick,\n ...rest\n } = props;\n\n const {t} = useLanguage();\n const labelFont = useThemedFont('body');\n const {cssProps, nativeProps} = useSeparator<Record<any, any>>(rest);\n const sevColors = useSeverityColors((severity as any) ?? 'brand');\n\n const sizeConfig = SIZE_MAP[size as keyof typeof SIZE_MAP] ?? SIZE_MAP.md;\n const isDisabled = disabled || loading;\n\n /* ── Resolve label text ── */\n const resolvedLabel = typeof children === 'string'\n ? children\n : loading && isLoadingText\n ? isLoadingText\n : label ? t(label) : '';\n\n const hasLabel = !!resolvedLabel;\n const isIconOnly = !hasLabel && !!icon;\n\n /* ── Severity colors ── */\n const textColor = outlined ? sevColors.solid : sevColors.solidText;\n const bgColor = outlined ? 'transparent' : sevColors.solid;\n const borderColor = sevColors.border || sevColors.solid;\n\n /* ── Build CSS props for ResponsiveElement ── */\n const computedCss:IStyleClasses = useMemo(() => ({\n backgroundColor: bgColor,\n borderColor,\n borderWidth: 1,\n height: sizeConfig.height,\n paddingLeft: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingRight: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingTop: sizeConfig.py,\n paddingBottom: sizeConfig.py,\n borderRadius: rounded ? 9999 : 6,\n flexDirection: iconPos === 'top' || iconPos === 'bottom'\n ? (iconPos === 'bottom' ? 'column-reverse' : 'column')\n : (iconPos === 'right' ? 'row-reverse' : 'row'),\n alignItems: 'center',\n justifyContent: 'center',\n gap: sizeConfig.gap,\n opacity: isDisabled ? 50 : 100,\n alignSelf: 'flex-start',\n overflow: 'hidden',\n ...(raised ? {\n shadowColor: '#000',\n shadowOffset: {width: 0, height: 3},\n shadowOpacity: 0.16,\n shadowRadius: 6,\n elevation: 4,\n } : {}),\n // Theme overrides the defaults above: shared `root` first, then the\n // `text` slot (label buttons) or the `iconOnly` slot. Icon-only buttons\n // are forced square so a `root`/`text` height can never stretch them —\n // the `iconOnly` slot can still override the square if needed.\n ...themeStyle,\n ...(elementStyles.root || {}),\n ...(isIconOnly\n ? {\n width: sizeConfig.height,\n height: sizeConfig.height,\n minWidth: sizeConfig.height,\n ...(elementStyles.iconOnly || {}),\n }\n : (elementStyles.text || {})),\n ...cssProps,\n ...styleProp,\n }), [themeStyle, elementStyles, cssProps, bgColor, borderColor, sizeConfig,\n hasLabel, icon, iconPos, rounded, raised, isDisabled, styleProp, isIconOnly]);\n\n /* ── Icon element ── */\n const iconElement = loading\n ? <ActivityIndicator size=\"small\" color={textColor} />\n : resolveIcon(icon, textColor, sizeConfig.iconSize);\n\n /* ── Text style ── */\n const labelStyle: TextStyle = useMemo(() => ({\n color: textColor,\n fontSize: sizeConfig.fontSize,\n fontWeight: '600',\n lineHeight: sizeConfig.fontSize * 1.2,\n ...(labelFont ? {fontFamily: labelFont} : {}),\n // Theme/per-instance label slot wins — e.g. theme.components.Button.label.style\n // = { lineHeight: 22 } to stop Arabic (NotoKufiArabic) glyphs clipping.\n ...((elementStyles.label as TextStyle) || {}),\n }), [textColor, sizeConfig, labelFont, elementStyles.label]);\n\n /* ── Press handler ── */\n const handlePress = useCallback((e: GestureResponderEvent) => {\n if (isDisabled) return;\n if (onPress) onPress(e as any);\n if (onClick) onClick(e as any);\n }, [isDisabled, onPress, onClick]);\n\n return (\n <ResponsiveElement\n as=\"Pressable\"\n cssProps={computedCss}\n nativeProps={{\n ...nativeProps,\n onPress: handlePress,\n disabled: isDisabled,\n testID,\n accessibilityRole: 'button',\n accessibilityState: {disabled: isDisabled, busy: loading},\n accessibilityLabel: resolvedLabel || undefined,\n }}\n >\n {iconElement}\n {!!hasLabel && (\n <RNText style={labelStyle} numberOfLines={1}>\n {resolvedLabel}\n </RNText>\n )}\n {typeof children !== 'string' ? children : undefined}\n </ResponsiveElement>\n );\n}\n\nexport default Button;\n"],"names":["RNText"],"mappings":"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"}
1
+ {"version":3,"file":"Button.js","sources":["../../../../src/components/Button/Button.native.tsx"],"sourcesContent":["import React, {useMemo, useCallback, type ElementType, type ReactElement} from 'react';\nimport {\n ActivityIndicator,\n Text as RNText,\n type TextStyle,\n type GestureResponderEvent,\n} from 'react-native';\nimport type {IButtonProps, IconName, IStyleClasses} from '@lmb-it/kitsconcerto-types';\nimport {ResponsiveElement, useSeparator, style as resolveStyle} from '@lmb-it/kitsconcertomobile';\nimport {IconMap} from '../../assets/Icons';\nimport {useLanguage, useComponentDefaults, useThemedFont} from '../../hooks';\nimport {useSeverityColors} from '../../hooks/useSeverityColors';\nimport {useKitsTheme} from '../../contexts/Theme';\n\n/* ─── Size configuration (matches web) ────────────────────────── */\nconst SIZE_MAP = {\n sm: {height: 32, fontSize: 12, px: 10, py: 6, gap: 6, iconSize: 14},\n md: {height: 40, fontSize: 14, px: 16, py: 10, gap: 8, iconSize: 16},\n lg: {height: 48, fontSize: 16, px: 24, py: 12, gap: 10, iconSize: 18},\n} as const;\n\n/* ─── Icon resolver ──────────────────────────────────────────── */\nfunction resolveIcon(\n icon: unknown,\n color: string,\n iconSize: number,\n): React.ReactNode {\n if (!icon) return null;\n if (React.isValidElement(icon)) {\n return React.cloneElement(icon as ReactElement<any>, {color, size: iconSize});\n }\n if (typeof icon === 'function') {\n const Comp = icon as ElementType;\n return <Comp size={iconSize} color={color} />;\n }\n if (typeof icon !== 'string') return null;\n const piMatches = icon.match(/pi-([a-z-]+)/g);\n const iconName = piMatches\n ? (piMatches[piMatches.length - 1]!.replace('pi-', '') as IconName)\n : (icon as IconName);\n const Component = IconMap[iconName];\n if (Component) return <Component size={iconSize} color={color} />;\n return null;\n}\n\n/* ─── Button Component ───────────────────────────────────────── */\nexport function Button(rawProps: IButtonProps<IconName | string | ElementType | ReactElement>) {\n const {mergedProps: props, themeStyle, elementStyles} = useComponentDefaults('Button', rawProps);\n const {\n children,\n label,\n isLoadingText,\n severity = 'brand',\n size = 'md',\n loading,\n iconPos = 'left',\n icon,\n disabled,\n outlined,\n raised,\n rounded,\n testID,\n style: styleProp,\n onPress,\n onClick,\n ...rest\n } = props;\n\n const {t} = useLanguage();\n const labelFont = useThemedFont('body');\n const {cssProps, nativeProps} = useSeparator<Record<any, any>>(rest);\n const sevColors = useSeverityColors((severity as any) ?? 'brand');\n\n const sizeConfig = SIZE_MAP[size as keyof typeof SIZE_MAP] ?? SIZE_MAP.md;\n const isDisabled = disabled || loading;\n\n /* ── Resolve label text ── */\n const resolvedLabel = typeof children === 'string'\n ? children\n : loading && isLoadingText\n ? isLoadingText\n : label ? t(label) : '';\n\n const hasLabel = !!resolvedLabel;\n const isIconOnly = !hasLabel && !!icon;\n\n /* ── Severity colors ── */\n /*\n * ⛔ A DISABLED BUTTON STOPS BEING THE BRAND, IT DOES NOT FADE — and this is\n * the phone's half of the same change made on web.\n *\n * The only disabled treatment was `opacity: isDisabled ? 50 : 100`, so the\n * button kept its brand fill, its white label and its brand border at half\n * strength. Same colour family, same filled shape, same affordance: it reads\n * as a slightly lighter LIVE button, and white on half-opacity brand is near\n * 1.7:1, so the fade hurts the label more than it announces the state.\n *\n * ⛔ THE COMP ALREADY ANSWERED IT: the locked bid rows draw a disabled\n * control as `#EEF0F2` ground with `#9CA3AF` text at FULL opacity.\n * `surface-muted` and `text-subtle` are the theme's own nearest tokens.\n *\n * ⚠️ OUTLINED KEEPS ITS TRANSPARENT GROUND. Filling it grey would make a\n * quiet control louder disabled than enabled.\n */\n const {resolveToken} = useKitsTheme();\n const disabledText = resolveToken('text-subtle');\n const textColor = isDisabled\n ? disabledText\n : outlined ? sevColors.solid : sevColors.solidText;\n const bgColor = outlined\n ? 'transparent'\n : isDisabled ? resolveToken('surface-muted') : sevColors.solid;\n const borderColor = isDisabled\n ? resolveToken('border')\n : sevColors.border || sevColors.solid;\n\n /* ── Build CSS props for ResponsiveElement ── */\n const computedCss:IStyleClasses = useMemo(() => ({\n backgroundColor: bgColor,\n borderColor,\n borderWidth: 1,\n height: sizeConfig.height,\n paddingLeft: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingRight: hasLabel ? sizeConfig.px : sizeConfig.py,\n paddingTop: sizeConfig.py,\n paddingBottom: sizeConfig.py,\n borderRadius: rounded ? 9999 : 6,\n flexDirection: iconPos === 'top' || iconPos === 'bottom'\n ? (iconPos === 'bottom' ? 'column-reverse' : 'column')\n : (iconPos === 'right' ? 'row-reverse' : 'row'),\n alignItems: 'center',\n justifyContent: 'center',\n gap: sizeConfig.gap,\n // ⚠️ NO OPACITY BRANCH. The colours above carry the state now; fading\n // them as well would take the new muted label back below legibility.\n opacity: 100,\n alignSelf: 'flex-start',\n overflow: 'hidden',\n ...(raised ? {\n shadowColor: '#000',\n shadowOffset: {width: 0, height: 3},\n shadowOpacity: 0.16,\n shadowRadius: 6,\n elevation: 4,\n } : {}),\n // Theme overrides the defaults above: shared `root` first, then the\n // `text` slot (label buttons) or the `iconOnly` slot. Icon-only buttons\n // are forced square so a `root`/`text` height can never stretch them —\n // the `iconOnly` slot can still override the square if needed.\n ...themeStyle,\n ...(elementStyles.root || {}),\n ...(isIconOnly\n ? {\n width: sizeConfig.height,\n height: sizeConfig.height,\n minWidth: sizeConfig.height,\n ...(elementStyles.iconOnly || {}),\n }\n : (elementStyles.text || {})),\n ...cssProps,\n ...styleProp,\n }), [themeStyle, elementStyles, cssProps, bgColor, borderColor, sizeConfig,\n hasLabel, icon, iconPos, rounded, raised, isDisabled, styleProp, isIconOnly]);\n\n /* ── Icon element ── */\n const iconElement = loading\n ? <ActivityIndicator size=\"small\" color={textColor} />\n : resolveIcon(icon, textColor, sizeConfig.iconSize);\n\n /* ── Text style ── */\n const labelStyle: TextStyle = useMemo(() => ({\n color: textColor,\n fontSize: sizeConfig.fontSize,\n fontWeight: '600',\n lineHeight: sizeConfig.fontSize * 1.2,\n ...(labelFont ? {fontFamily: labelFont} : {}),\n // Theme/per-instance label slot wins — e.g. theme.components.Button.label.style\n // = { lineHeight: 22 } to stop Arabic (NotoKufiArabic) glyphs clipping.\n ...((elementStyles.label as TextStyle) || {}),\n }), [textColor, sizeConfig, labelFont, elementStyles.label]);\n\n /* ── Press handler ── */\n const handlePress = useCallback((e: GestureResponderEvent) => {\n if (isDisabled) return;\n if (onPress) onPress(e as any);\n if (onClick) onClick(e as any);\n }, [isDisabled, onPress, onClick]);\n\n return (\n <ResponsiveElement\n as=\"Pressable\"\n cssProps={computedCss}\n nativeProps={{\n ...nativeProps,\n onPress: handlePress,\n disabled: isDisabled,\n testID,\n accessibilityRole: 'button',\n accessibilityState: {disabled: isDisabled, busy: loading},\n accessibilityLabel: resolvedLabel || undefined,\n }}\n >\n {iconElement}\n {!!hasLabel && (\n <RNText style={labelStyle} numberOfLines={1}>\n {resolvedLabel}\n </RNText>\n )}\n {typeof children !== 'string' ? children : undefined}\n </ResponsiveElement>\n );\n}\n\nexport default Button;\n"],"names":["RNText"],"mappings":"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"}
@@ -164,7 +164,7 @@ const FieldWrapper = ({
164
164
  {
165
165
  ...elementStyle?.container,
166
166
  ...animation,
167
- zIndex: isFocused ? 1e3 : "auto",
167
+ zIndex: isFocused ? 1e3 : void 0,
168
168
  w: "100%",
169
169
  onTouchStart: onFocus,
170
170
  children: children(fieldLogic)
@@ -1 +1 @@
1
- {"version":3,"file":"FieldWrapper.cjs","sources":["../../../../../src/form-renderer/components/layout/FieldWrapper.native.tsx"],"sourcesContent":["// components/layout/FieldWrapper.native.tsx\n\nimport React, {useCallback, useEffect, useMemo, useRef} from \"react\";\nimport type {FieldValues} from \"react-hook-form\";\nimport {useWatch} from \"react-hook-form\";\nimport {useFieldLogic} from \"../../hooks\";\nimport type {FieldWrapperProps, GroupFieldConfigs} from \"@lmb-it/kitsconcerto-types\";\nimport {Flex} from \"../../../_compat\";\nimport {createStyleContext, resolveResponsiveValue} from \"@lmb-it/kitsconcertomobile\";\n\n/**\n * Native layout contract:\n * - Container MUST be flex-row + flex-wrap\n * - Grid semantics are approximated via percentages\n *\n * Supported mappings:\n * - columns -> virtual column count\n * - colSpan -> width %\n * - colOffset -> marginLeft %\n * - columnGap -> item horizontal padding\n * - rowGap -> item vertical padding\n * - rowSpan -> minHeight approximation\n *\n * Ignored (grid-only semantics):\n * - templateAreas\n * - area\n * - gridTemplateRows\n * - gridTemplateColumns\n * - rowStart / rowEnd\n * - colStart / colEnd\n */\n\nconst DEFAULT_COLUMNS = 12;\nconst DEFAULT_ROW_HEIGHT = 56;\n\nexport const FieldWrapper = <T extends FieldValues>({\n element,\n control,\n getValues,\n setFocusedField,\n focusedField,\n children,\n grid,\n onGridChange,\n groupField,\n }: FieldWrapperProps<T>) => {\n /* ---------------- helpers (no hooks) ---------------- */\n\n const currentLayout = useRef<any>(null);\n const resolveDepPath = (dep: string, groupField?: GroupFieldConfigs<T>['groupField']): string => {\n if (!groupField || groupField.index === undefined || groupField.index < 0) return dep;\n\n const parts = dep.split(\".\");\n const {name, index} = groupField;\n\n // Must be \"<groupRef>.current.<field...>\"\n if (parts.length < 2 || parts[1] !== \"current\") return dep;\n\n // Group-relative deps are authored against the group's own id\n // (e.g. \"addresses.current.x\"). When the group is nested inside an\n // Object the live `name` is the fully-qualified dotted path\n // (e.g. \"addressGroup.addresses\"), so match the dep's first segment\n // against EITHER the full name or its trailing segment, then rebuild\n // against the fully-qualified name so useWatch hits the real path.\n const nameLast = name.includes(\".\") ? name.slice(name.lastIndexOf(\".\") + 1) : name;\n if (parts[0] !== name && parts[0] !== nameLast) return dep;\n\n return [name, String(index), ...parts.slice(2)].join(\".\");\n };\n\n const flattenPaths = (obj: any, prefix = ''): string[] =>\n Object.keys(obj ?? {}).flatMap((key) => {\n const path = prefix ? `${prefix}.${key}` : key;\n return typeof obj[key] === 'object' && obj[key] !== null\n ? [path, ...flattenPaths(obj[key], path)]\n : [path];\n });\n\n // 1. Determine which fields to watch for changes.\n const dependencies = useMemo(() => {\n const deps = new Set<string>([...(element.deps ?? []), ...(element.logic?.deps ?? [])]);\n\n if (deps.has('*')) {\n return flattenPaths(getValues());\n }\n\n return Array.from(deps).map((d) => resolveDepPath(d, groupField));\n }, [element, groupField]);\n\n\n // 2. Efficiently watch only the necessary fields.\n const watchedValues = useWatch({\n name: dependencies as any,\n compute:(fieldValue)=>{\n return fieldValue\n },\n exact:true,\n disabled:dependencies.length === 0\n });\n\n useEffect(() => {\n // console.log('watchedValues', watchedValues)\n }, [watchedValues]);\n // This single hook provides all the necessary logic and state for the field.\n const fieldLogic = useFieldLogic({element, control, getValues, isFocused: focusedField === element.id, groupField, watchedValues});\n\n const {\n field,\n isShown,\n layout,\n style:elementStyle,\n animation\n } = fieldLogic;\n const isFocused = focusedField === field.name;\n\n const onFocus = useCallback(() => setFocusedField(field.name), [setFocusedField, field.name]);\n const onBlur: React.FocusEventHandler<any> = useCallback((event) => {\n const cl = event.target['className'];\n // @ts-ignore\n if(!cl || cl.includes(`${element.id}_option_item`) || cl.includes(`p-multiselect-filter`)){\n return;\n }\n setFocusedField('');\n field.onBlur(); // Call the original onBlur from react-hook-form\n }, [setFocusedField, field.onBlur]);\n\n // Grid layout effect — MUST be before any conditional return (Rules of Hooks)\n useEffect(() => {\n if(layout.colSpan && currentLayout.current != JSON.stringify(layout)){\n const ctx = createStyleContext();\n\n const colSpan = resolveResponsiveValue<string | number>(layout.colSpan, ctx);\n\n onGridChange?.(colSpan?.toString() ?? '12')\n\n currentLayout.current = JSON.stringify(layout)\n }\n\n }, [layout]);\n\n // If the logic dictates this field should not be shown, render nothing.\n if (!isShown || !children) {\n return null;\n }\n\n\n\n // @ts-ignore\n return <Flex {...elementStyle?.container} {...animation}\n zIndex={isFocused ? 1000 : ('auto' as unknown as number)}\n w={'100%'} onTouchStart={onFocus}>\n {children(fieldLogic)}\n </Flex>\n};\n"],"names":["useRef","groupField","useMemo","useWatch","useEffect","useFieldLogic","useCallback","createStyleContext","resolveResponsiveValue","jsx","Flex"],"mappings":"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"}
1
+ {"version":3,"file":"FieldWrapper.cjs","sources":["../../../../../src/form-renderer/components/layout/FieldWrapper.native.tsx"],"sourcesContent":["// components/layout/FieldWrapper.native.tsx\n\nimport React, {useCallback, useEffect, useMemo, useRef} from \"react\";\nimport type {FieldValues} from \"react-hook-form\";\nimport {useWatch} from \"react-hook-form\";\nimport {useFieldLogic} from \"../../hooks\";\nimport type {FieldWrapperProps, GroupFieldConfigs} from \"@lmb-it/kitsconcerto-types\";\nimport {Flex} from \"../../../_compat\";\nimport {createStyleContext, resolveResponsiveValue} from \"@lmb-it/kitsconcertomobile\";\n\n/**\n * Native layout contract:\n * - Container MUST be flex-row + flex-wrap\n * - Grid semantics are approximated via percentages\n *\n * Supported mappings:\n * - columns -> virtual column count\n * - colSpan -> width %\n * - colOffset -> marginLeft %\n * - columnGap -> item horizontal padding\n * - rowGap -> item vertical padding\n * - rowSpan -> minHeight approximation\n *\n * Ignored (grid-only semantics):\n * - templateAreas\n * - area\n * - gridTemplateRows\n * - gridTemplateColumns\n * - rowStart / rowEnd\n * - colStart / colEnd\n */\n\nconst DEFAULT_COLUMNS = 12;\nconst DEFAULT_ROW_HEIGHT = 56;\n\nexport const FieldWrapper = <T extends FieldValues>({\n element,\n control,\n getValues,\n setFocusedField,\n focusedField,\n children,\n grid,\n onGridChange,\n groupField,\n }: FieldWrapperProps<T>) => {\n /* ---------------- helpers (no hooks) ---------------- */\n\n const currentLayout = useRef<any>(null);\n const resolveDepPath = (dep: string, groupField?: GroupFieldConfigs<T>['groupField']): string => {\n if (!groupField || groupField.index === undefined || groupField.index < 0) return dep;\n\n const parts = dep.split(\".\");\n const {name, index} = groupField;\n\n // Must be \"<groupRef>.current.<field...>\"\n if (parts.length < 2 || parts[1] !== \"current\") return dep;\n\n // Group-relative deps are authored against the group's own id\n // (e.g. \"addresses.current.x\"). When the group is nested inside an\n // Object the live `name` is the fully-qualified dotted path\n // (e.g. \"addressGroup.addresses\"), so match the dep's first segment\n // against EITHER the full name or its trailing segment, then rebuild\n // against the fully-qualified name so useWatch hits the real path.\n const nameLast = name.includes(\".\") ? name.slice(name.lastIndexOf(\".\") + 1) : name;\n if (parts[0] !== name && parts[0] !== nameLast) return dep;\n\n return [name, String(index), ...parts.slice(2)].join(\".\");\n };\n\n const flattenPaths = (obj: any, prefix = ''): string[] =>\n Object.keys(obj ?? {}).flatMap((key) => {\n const path = prefix ? `${prefix}.${key}` : key;\n return typeof obj[key] === 'object' && obj[key] !== null\n ? [path, ...flattenPaths(obj[key], path)]\n : [path];\n });\n\n // 1. Determine which fields to watch for changes.\n const dependencies = useMemo(() => {\n const deps = new Set<string>([...(element.deps ?? []), ...(element.logic?.deps ?? [])]);\n\n if (deps.has('*')) {\n return flattenPaths(getValues());\n }\n\n return Array.from(deps).map((d) => resolveDepPath(d, groupField));\n }, [element, groupField]);\n\n\n // 2. Efficiently watch only the necessary fields.\n const watchedValues = useWatch({\n name: dependencies as any,\n compute:(fieldValue)=>{\n return fieldValue\n },\n exact:true,\n disabled:dependencies.length === 0\n });\n\n useEffect(() => {\n // console.log('watchedValues', watchedValues)\n }, [watchedValues]);\n // This single hook provides all the necessary logic and state for the field.\n const fieldLogic = useFieldLogic({element, control, getValues, isFocused: focusedField === element.id, groupField, watchedValues});\n\n const {\n field,\n isShown,\n layout,\n style:elementStyle,\n animation\n } = fieldLogic;\n const isFocused = focusedField === field.name;\n\n const onFocus = useCallback(() => setFocusedField(field.name), [setFocusedField, field.name]);\n const onBlur: React.FocusEventHandler<any> = useCallback((event) => {\n const cl = event.target['className'];\n // @ts-ignore\n if(!cl || cl.includes(`${element.id}_option_item`) || cl.includes(`p-multiselect-filter`)){\n return;\n }\n setFocusedField('');\n field.onBlur(); // Call the original onBlur from react-hook-form\n }, [setFocusedField, field.onBlur]);\n\n // Grid layout effect — MUST be before any conditional return (Rules of Hooks)\n useEffect(() => {\n if(layout.colSpan && currentLayout.current != JSON.stringify(layout)){\n const ctx = createStyleContext();\n\n const colSpan = resolveResponsiveValue<string | number>(layout.colSpan, ctx);\n\n onGridChange?.(colSpan?.toString() ?? '12')\n\n currentLayout.current = JSON.stringify(layout)\n }\n\n }, [layout]);\n\n // If the logic dictates this field should not be shown, render nothing.\n if (!isShown || !children) {\n return null;\n }\n\n\n\n // @ts-ignore\n return <Flex {...elementStyle?.container} {...animation}\n zIndex={isFocused ? 1000 : undefined}\n w={'100%'} onTouchStart={onFocus}>\n {children(fieldLogic)}\n </Flex>\n};\n"],"names":["useRef","groupField","useMemo","useWatch","useEffect","useFieldLogic","useCallback","createStyleContext","resolveResponsiveValue","jsx","Flex"],"mappings":"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"}
@@ -162,7 +162,7 @@ const FieldWrapper = ({
162
162
  {
163
163
  ...elementStyle?.container,
164
164
  ...animation,
165
- zIndex: isFocused ? 1e3 : "auto",
165
+ zIndex: isFocused ? 1e3 : void 0,
166
166
  w: "100%",
167
167
  onTouchStart: onFocus,
168
168
  children: children(fieldLogic)
@@ -1 +1 @@
1
- {"version":3,"file":"FieldWrapper.js","sources":["../../../../../src/form-renderer/components/layout/FieldWrapper.native.tsx"],"sourcesContent":["// components/layout/FieldWrapper.native.tsx\n\nimport React, {useCallback, useEffect, useMemo, useRef} from \"react\";\nimport type {FieldValues} from \"react-hook-form\";\nimport {useWatch} from \"react-hook-form\";\nimport {useFieldLogic} from \"../../hooks\";\nimport type {FieldWrapperProps, GroupFieldConfigs} from \"@lmb-it/kitsconcerto-types\";\nimport {Flex} from \"../../../_compat\";\nimport {createStyleContext, resolveResponsiveValue} from \"@lmb-it/kitsconcertomobile\";\n\n/**\n * Native layout contract:\n * - Container MUST be flex-row + flex-wrap\n * - Grid semantics are approximated via percentages\n *\n * Supported mappings:\n * - columns -> virtual column count\n * - colSpan -> width %\n * - colOffset -> marginLeft %\n * - columnGap -> item horizontal padding\n * - rowGap -> item vertical padding\n * - rowSpan -> minHeight approximation\n *\n * Ignored (grid-only semantics):\n * - templateAreas\n * - area\n * - gridTemplateRows\n * - gridTemplateColumns\n * - rowStart / rowEnd\n * - colStart / colEnd\n */\n\nconst DEFAULT_COLUMNS = 12;\nconst DEFAULT_ROW_HEIGHT = 56;\n\nexport const FieldWrapper = <T extends FieldValues>({\n element,\n control,\n getValues,\n setFocusedField,\n focusedField,\n children,\n grid,\n onGridChange,\n groupField,\n }: FieldWrapperProps<T>) => {\n /* ---------------- helpers (no hooks) ---------------- */\n\n const currentLayout = useRef<any>(null);\n const resolveDepPath = (dep: string, groupField?: GroupFieldConfigs<T>['groupField']): string => {\n if (!groupField || groupField.index === undefined || groupField.index < 0) return dep;\n\n const parts = dep.split(\".\");\n const {name, index} = groupField;\n\n // Must be \"<groupRef>.current.<field...>\"\n if (parts.length < 2 || parts[1] !== \"current\") return dep;\n\n // Group-relative deps are authored against the group's own id\n // (e.g. \"addresses.current.x\"). When the group is nested inside an\n // Object the live `name` is the fully-qualified dotted path\n // (e.g. \"addressGroup.addresses\"), so match the dep's first segment\n // against EITHER the full name or its trailing segment, then rebuild\n // against the fully-qualified name so useWatch hits the real path.\n const nameLast = name.includes(\".\") ? name.slice(name.lastIndexOf(\".\") + 1) : name;\n if (parts[0] !== name && parts[0] !== nameLast) return dep;\n\n return [name, String(index), ...parts.slice(2)].join(\".\");\n };\n\n const flattenPaths = (obj: any, prefix = ''): string[] =>\n Object.keys(obj ?? {}).flatMap((key) => {\n const path = prefix ? `${prefix}.${key}` : key;\n return typeof obj[key] === 'object' && obj[key] !== null\n ? [path, ...flattenPaths(obj[key], path)]\n : [path];\n });\n\n // 1. Determine which fields to watch for changes.\n const dependencies = useMemo(() => {\n const deps = new Set<string>([...(element.deps ?? []), ...(element.logic?.deps ?? [])]);\n\n if (deps.has('*')) {\n return flattenPaths(getValues());\n }\n\n return Array.from(deps).map((d) => resolveDepPath(d, groupField));\n }, [element, groupField]);\n\n\n // 2. Efficiently watch only the necessary fields.\n const watchedValues = useWatch({\n name: dependencies as any,\n compute:(fieldValue)=>{\n return fieldValue\n },\n exact:true,\n disabled:dependencies.length === 0\n });\n\n useEffect(() => {\n // console.log('watchedValues', watchedValues)\n }, [watchedValues]);\n // This single hook provides all the necessary logic and state for the field.\n const fieldLogic = useFieldLogic({element, control, getValues, isFocused: focusedField === element.id, groupField, watchedValues});\n\n const {\n field,\n isShown,\n layout,\n style:elementStyle,\n animation\n } = fieldLogic;\n const isFocused = focusedField === field.name;\n\n const onFocus = useCallback(() => setFocusedField(field.name), [setFocusedField, field.name]);\n const onBlur: React.FocusEventHandler<any> = useCallback((event) => {\n const cl = event.target['className'];\n // @ts-ignore\n if(!cl || cl.includes(`${element.id}_option_item`) || cl.includes(`p-multiselect-filter`)){\n return;\n }\n setFocusedField('');\n field.onBlur(); // Call the original onBlur from react-hook-form\n }, [setFocusedField, field.onBlur]);\n\n // Grid layout effect — MUST be before any conditional return (Rules of Hooks)\n useEffect(() => {\n if(layout.colSpan && currentLayout.current != JSON.stringify(layout)){\n const ctx = createStyleContext();\n\n const colSpan = resolveResponsiveValue<string | number>(layout.colSpan, ctx);\n\n onGridChange?.(colSpan?.toString() ?? '12')\n\n currentLayout.current = JSON.stringify(layout)\n }\n\n }, [layout]);\n\n // If the logic dictates this field should not be shown, render nothing.\n if (!isShown || !children) {\n return null;\n }\n\n\n\n // @ts-ignore\n return <Flex {...elementStyle?.container} {...animation}\n zIndex={isFocused ? 1000 : ('auto' as unknown as number)}\n w={'100%'} onTouchStart={onFocus}>\n {children(fieldLogic)}\n </Flex>\n};\n"],"names":["groupField"],"mappings":"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"}
1
+ {"version":3,"file":"FieldWrapper.js","sources":["../../../../../src/form-renderer/components/layout/FieldWrapper.native.tsx"],"sourcesContent":["// components/layout/FieldWrapper.native.tsx\n\nimport React, {useCallback, useEffect, useMemo, useRef} from \"react\";\nimport type {FieldValues} from \"react-hook-form\";\nimport {useWatch} from \"react-hook-form\";\nimport {useFieldLogic} from \"../../hooks\";\nimport type {FieldWrapperProps, GroupFieldConfigs} from \"@lmb-it/kitsconcerto-types\";\nimport {Flex} from \"../../../_compat\";\nimport {createStyleContext, resolveResponsiveValue} from \"@lmb-it/kitsconcertomobile\";\n\n/**\n * Native layout contract:\n * - Container MUST be flex-row + flex-wrap\n * - Grid semantics are approximated via percentages\n *\n * Supported mappings:\n * - columns -> virtual column count\n * - colSpan -> width %\n * - colOffset -> marginLeft %\n * - columnGap -> item horizontal padding\n * - rowGap -> item vertical padding\n * - rowSpan -> minHeight approximation\n *\n * Ignored (grid-only semantics):\n * - templateAreas\n * - area\n * - gridTemplateRows\n * - gridTemplateColumns\n * - rowStart / rowEnd\n * - colStart / colEnd\n */\n\nconst DEFAULT_COLUMNS = 12;\nconst DEFAULT_ROW_HEIGHT = 56;\n\nexport const FieldWrapper = <T extends FieldValues>({\n element,\n control,\n getValues,\n setFocusedField,\n focusedField,\n children,\n grid,\n onGridChange,\n groupField,\n }: FieldWrapperProps<T>) => {\n /* ---------------- helpers (no hooks) ---------------- */\n\n const currentLayout = useRef<any>(null);\n const resolveDepPath = (dep: string, groupField?: GroupFieldConfigs<T>['groupField']): string => {\n if (!groupField || groupField.index === undefined || groupField.index < 0) return dep;\n\n const parts = dep.split(\".\");\n const {name, index} = groupField;\n\n // Must be \"<groupRef>.current.<field...>\"\n if (parts.length < 2 || parts[1] !== \"current\") return dep;\n\n // Group-relative deps are authored against the group's own id\n // (e.g. \"addresses.current.x\"). When the group is nested inside an\n // Object the live `name` is the fully-qualified dotted path\n // (e.g. \"addressGroup.addresses\"), so match the dep's first segment\n // against EITHER the full name or its trailing segment, then rebuild\n // against the fully-qualified name so useWatch hits the real path.\n const nameLast = name.includes(\".\") ? name.slice(name.lastIndexOf(\".\") + 1) : name;\n if (parts[0] !== name && parts[0] !== nameLast) return dep;\n\n return [name, String(index), ...parts.slice(2)].join(\".\");\n };\n\n const flattenPaths = (obj: any, prefix = ''): string[] =>\n Object.keys(obj ?? {}).flatMap((key) => {\n const path = prefix ? `${prefix}.${key}` : key;\n return typeof obj[key] === 'object' && obj[key] !== null\n ? [path, ...flattenPaths(obj[key], path)]\n : [path];\n });\n\n // 1. Determine which fields to watch for changes.\n const dependencies = useMemo(() => {\n const deps = new Set<string>([...(element.deps ?? []), ...(element.logic?.deps ?? [])]);\n\n if (deps.has('*')) {\n return flattenPaths(getValues());\n }\n\n return Array.from(deps).map((d) => resolveDepPath(d, groupField));\n }, [element, groupField]);\n\n\n // 2. Efficiently watch only the necessary fields.\n const watchedValues = useWatch({\n name: dependencies as any,\n compute:(fieldValue)=>{\n return fieldValue\n },\n exact:true,\n disabled:dependencies.length === 0\n });\n\n useEffect(() => {\n // console.log('watchedValues', watchedValues)\n }, [watchedValues]);\n // This single hook provides all the necessary logic and state for the field.\n const fieldLogic = useFieldLogic({element, control, getValues, isFocused: focusedField === element.id, groupField, watchedValues});\n\n const {\n field,\n isShown,\n layout,\n style:elementStyle,\n animation\n } = fieldLogic;\n const isFocused = focusedField === field.name;\n\n const onFocus = useCallback(() => setFocusedField(field.name), [setFocusedField, field.name]);\n const onBlur: React.FocusEventHandler<any> = useCallback((event) => {\n const cl = event.target['className'];\n // @ts-ignore\n if(!cl || cl.includes(`${element.id}_option_item`) || cl.includes(`p-multiselect-filter`)){\n return;\n }\n setFocusedField('');\n field.onBlur(); // Call the original onBlur from react-hook-form\n }, [setFocusedField, field.onBlur]);\n\n // Grid layout effect — MUST be before any conditional return (Rules of Hooks)\n useEffect(() => {\n if(layout.colSpan && currentLayout.current != JSON.stringify(layout)){\n const ctx = createStyleContext();\n\n const colSpan = resolveResponsiveValue<string | number>(layout.colSpan, ctx);\n\n onGridChange?.(colSpan?.toString() ?? '12')\n\n currentLayout.current = JSON.stringify(layout)\n }\n\n }, [layout]);\n\n // If the logic dictates this field should not be shown, render nothing.\n if (!isShown || !children) {\n return null;\n }\n\n\n\n // @ts-ignore\n return <Flex {...elementStyle?.container} {...animation}\n zIndex={isFocused ? 1000 : undefined}\n w={'100%'} onTouchStart={onFocus}>\n {children(fieldLogic)}\n </Flex>\n};\n"],"names":["groupField"],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1357,7 +1357,22 @@ export interface IKitsThemeContextValues {
1357
1357
  * `theme.shadows[<preset>].native`.
1358
1358
  */
1359
1359
  /** Preset names recognised by the cross-platform `shadow` key / prop. */
1360
- declare const SHADOW_PRESET_KEYS: readonly ["none", "xs", "sm", "md", "lg"];
1360
+ /**
1361
+ * ⛔ `up` IS A DIRECTION, NOT A SIZE, AND THAT IS WHY IT SITS OUTSIDE THE SCALE.
1362
+ * `xs → lg` is one axis: how far off the page a thing floats. Every one of them
1363
+ * casts DOWNWARD (`shadowOffset.height` ≥ 0), which is correct for a card on a
1364
+ * page and wrong for anything anchored to the BOTTOM of the screen — a sticky
1365
+ * bid footer, a bottom sheet, a tab bar. Those need the light to come from the
1366
+ * same place it always does and the shadow to fall UPWARD, onto the content
1367
+ * they are covering. Without it a bottom-anchored block reads as painted on
1368
+ * rather than lifted.
1369
+ *
1370
+ * ⚠️ IT IS DELIBERATELY ONE PRESET, NOT A SECOND SCALE. `up-sm`/`up-md`/`up-lg`
1371
+ * would double the vocabulary for a case that has exactly one job: separating a
1372
+ * fixed bar from what scrolls beneath it. Add sizes when a second real use
1373
+ * appears, not before.
1374
+ */
1375
+ declare const SHADOW_PRESET_KEYS: readonly ["none", "xs", "sm", "md", "lg", "up"];
1361
1376
  export type ShadowPreset = (typeof SHADOW_PRESET_KEYS)[number];
1362
1377
  /** Type guard: is `value` one of the cross-platform shadow presets? */
1363
1378
  declare function isShadowPreset(value: unknown): value is ShadowPreset;
@@ -1425,6 +1440,16 @@ declare const DEFAULT_NATIVE_SHADOWS: {
1425
1440
  shadowRadius: number;
1426
1441
  elevation: number;
1427
1442
  };
1443
+ up: {
1444
+ shadowColor: string;
1445
+ shadowOffset: {
1446
+ width: number;
1447
+ height: number;
1448
+ };
1449
+ shadowOpacity: number;
1450
+ shadowRadius: number;
1451
+ elevation: number;
1452
+ };
1428
1453
  };
1429
1454
  /** Publish the theme's native shadow scale. Merged over the built-in defaults. */
1430
1455
  declare function setActiveNativeShadows(scale: Record<string, INativeShadow>): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lmb-it/kitsconcerto-native",
3
- "version": "0.1.250",
3
+ "version": "0.1.251",
4
4
  "description": "KitsConcerto — Native (React Native) UI components",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -523,6 +523,9 @@ const defaultTheme = {
523
523
  sm: { web: "0 1px 2px rgba(15,26,28,0.04)", native: shadows.DEFAULT_NATIVE_SHADOWS.sm },
524
524
  md: { web: "0 2px 4px rgba(15,26,28,0.05), 0 6px 16px rgba(15,26,28,0.06)", native: shadows.DEFAULT_NATIVE_SHADOWS.md },
525
525
  lg: { web: "0 4px 16px rgba(15,26,28,0.06), 0 20px 40px rgba(15,26,28,0.08)", native: shadows.DEFAULT_NATIVE_SHADOWS.lg },
526
+ // ⛔ THE ONLY PRESET THAT CASTS UPWARD. For blocks anchored to the
527
+ // bottom of the viewport; see the note on `up` in `shadows.ts`.
528
+ up: { web: "0 -3px 5px rgba(15,26,28,0.05), 0 -8px 20px rgba(15,26,28,0.06)", native: shadows.DEFAULT_NATIVE_SHADOWS.up },
526
529
  // Web-only legacy levels (no cross-platform native mapping).
527
530
  base: "0 1px 2px rgba(15,26,28,0.04), 0 4px 12px rgba(15,26,28,0.04)",
528
531
  // AM.shadow