@lmb-it/kitsconcerto-native 0.1.288 → 0.1.290
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.
- package/apps/mobile/src/Core/Dropdown/index.cjs +1 -0
- package/apps/mobile/src/Core/Dropdown/index.cjs.map +1 -1
- package/apps/mobile/src/Core/Dropdown/index.js +1 -0
- package/apps/mobile/src/Core/Dropdown/index.js.map +1 -1
- package/apps/mobile/src/Core/Trees/components/CoreToolbar.cjs +1 -0
- package/apps/mobile/src/Core/Trees/components/CoreToolbar.cjs.map +1 -1
- package/apps/mobile/src/Core/Trees/components/CoreToolbar.js +1 -0
- package/apps/mobile/src/Core/Trees/components/CoreToolbar.js.map +1 -1
- package/apps/mobile/src/Factory/ResponsiveElement.cjs +1 -0
- package/apps/mobile/src/Factory/ResponsiveElement.cjs.map +1 -1
- package/apps/mobile/src/Factory/ResponsiveElement.js +1 -0
- package/apps/mobile/src/Factory/ResponsiveElement.js.map +1 -1
- package/apps/mobile/src/Factory/helpers/cssVarMap.cjs +1 -0
- package/apps/mobile/src/Factory/helpers/cssVarMap.cjs.map +1 -1
- package/apps/mobile/src/Factory/helpers/cssVarMap.js +1 -0
- package/apps/mobile/src/Factory/helpers/cssVarMap.js.map +1 -1
- package/apps/mobile/src/Factory/helpers/style.cjs +1 -0
- package/apps/mobile/src/Factory/helpers/style.cjs.map +1 -1
- package/apps/mobile/src/Factory/helpers/style.js +1 -0
- package/apps/mobile/src/Factory/helpers/style.js.map +1 -1
- package/apps/mobile/src/Factory/useSeparator.cjs +1 -0
- package/apps/mobile/src/Factory/useSeparator.cjs.map +1 -1
- package/apps/mobile/src/Factory/useSeparator.js +1 -0
- package/apps/mobile/src/Factory/useSeparator.js.map +1 -1
- package/components/Accordion/accordion.cjs +1 -0
- package/components/Accordion/accordion.cjs.map +1 -1
- package/components/Accordion/accordion.js +1 -0
- package/components/Accordion/accordion.js.map +1 -1
- package/components/Badge/index.cjs +1 -0
- package/components/Badge/index.cjs.map +1 -1
- package/components/Badge/index.js +1 -0
- package/components/Badge/index.js.map +1 -1
- package/components/BottomTabBar/index.cjs +1 -0
- package/components/BottomTabBar/index.cjs.map +1 -1
- package/components/BottomTabBar/index.js +1 -0
- package/components/BottomTabBar/index.js.map +1 -1
- package/components/Button/Button.cjs +1 -0
- package/components/Button/Button.cjs.map +1 -1
- package/components/Button/Button.js +1 -0
- package/components/Button/Button.js.map +1 -1
- package/components/ImageCropper/index.cjs +584 -550
- package/components/ImageCropper/index.cjs.map +1 -1
- package/components/ImageCropper/index.js +585 -551
- package/components/ImageCropper/index.js.map +1 -1
- package/components/MessageComposer/index.cjs +1 -0
- package/components/MessageComposer/index.cjs.map +1 -1
- package/components/MessageComposer/index.js +1 -0
- package/components/MessageComposer/index.js.map +1 -1
- package/components/SegmentedControl/index.cjs +1 -0
- package/components/SegmentedControl/index.cjs.map +1 -1
- package/components/SegmentedControl/index.js +1 -0
- package/components/SegmentedControl/index.js.map +1 -1
- package/components/SkeletonText/index.cjs +1 -0
- package/components/SkeletonText/index.cjs.map +1 -1
- package/components/SkeletonText/index.js +1 -0
- package/components/SkeletonText/index.js.map +1 -1
- package/components/Tabs/index.cjs +3 -2
- package/components/Tabs/index.cjs.map +1 -1
- package/components/Tabs/index.js +3 -2
- package/components/Tabs/index.js.map +1 -1
- package/contexts/Locale/index.cjs +1 -0
- package/contexts/Locale/index.cjs.map +1 -1
- package/contexts/Locale/index.js +1 -0
- package/contexts/Locale/index.js.map +1 -1
- package/contexts/Main/index.cjs +1 -0
- package/contexts/Main/index.cjs.map +1 -1
- package/contexts/Main/index.js +1 -0
- package/contexts/Main/index.js.map +1 -1
- package/contexts/Theme/index.cjs +1 -0
- package/contexts/Theme/index.cjs.map +1 -1
- package/contexts/Theme/index.js +1 -0
- package/contexts/Theme/index.js.map +1 -1
- package/data/DataView/Pagination/index.cjs +1 -0
- package/data/DataView/Pagination/index.cjs.map +1 -1
- package/data/DataView/Pagination/index.js +1 -0
- package/data/DataView/Pagination/index.js.map +1 -1
- package/data/TreeView/index.cjs +1 -0
- package/data/TreeView/index.cjs.map +1 -1
- package/data/TreeView/index.js +1 -0
- package/data/TreeView/index.js.map +1 -1
- package/form/controls/Checkbox/checkbox.cjs +1 -0
- package/form/controls/Checkbox/checkbox.cjs.map +1 -1
- package/form/controls/Checkbox/checkbox.js +1 -0
- package/form/controls/Checkbox/checkbox.js.map +1 -1
- package/form/controls/RadioButton/radiobutton.cjs +1 -0
- package/form/controls/RadioButton/radiobutton.cjs.map +1 -1
- package/form/controls/RadioButton/radiobutton.js +1 -0
- package/form/controls/RadioButton/radiobutton.js.map +1 -1
- package/form/controls/SelectButton/index.cjs +1 -0
- package/form/controls/SelectButton/index.cjs.map +1 -1
- package/form/controls/SelectButton/index.js +1 -0
- package/form/controls/SelectButton/index.js.map +1 -1
- package/form/controls/TriStateCheckbox/index.cjs +1 -0
- package/form/controls/TriStateCheckbox/index.cjs.map +1 -1
- package/form/controls/TriStateCheckbox/index.js +1 -0
- package/form/controls/TriStateCheckbox/index.js.map +1 -1
- package/form/file-pickers/MainUploader/index.cjs +1 -0
- package/form/file-pickers/MainUploader/index.cjs.map +1 -1
- package/form/file-pickers/MainUploader/index.js +1 -0
- package/form/file-pickers/MainUploader/index.js.map +1 -1
- package/form/helpers/ErrorMessage/errormessage.cjs +1 -0
- package/form/helpers/ErrorMessage/errormessage.cjs.map +1 -1
- package/form/helpers/ErrorMessage/errormessage.js +1 -0
- package/form/helpers/ErrorMessage/errormessage.js.map +1 -1
- package/form/helpers/FormContainer/index.cjs +1 -0
- package/form/helpers/FormContainer/index.cjs.map +1 -1
- package/form/helpers/FormContainer/index.js +1 -0
- package/form/helpers/FormContainer/index.js.map +1 -1
- package/form/helpers/Label/label.cjs +1 -0
- package/form/helpers/Label/label.cjs.map +1 -1
- package/form/helpers/Label/label.js +1 -0
- package/form/helpers/Label/label.js.map +1 -1
- package/form/inputs/InputMask/index.cjs +1 -0
- package/form/inputs/InputMask/index.cjs.map +1 -1
- package/form/inputs/InputMask/index.js +1 -0
- package/form/inputs/InputMask/index.js.map +1 -1
- package/form/inputs/InputNumber/index.cjs +1 -0
- package/form/inputs/InputNumber/index.cjs.map +1 -1
- package/form/inputs/InputNumber/index.js +1 -0
- package/form/inputs/InputNumber/index.js.map +1 -1
- package/form/inputs/InputPassword/index.cjs +1 -0
- package/form/inputs/InputPassword/index.cjs.map +1 -1
- package/form/inputs/InputPassword/index.js +1 -0
- package/form/inputs/InputPassword/index.js.map +1 -1
- package/form/inputs/InputSwitch/index.cjs +1 -0
- package/form/inputs/InputSwitch/index.cjs.map +1 -1
- package/form/inputs/InputSwitch/index.js +1 -0
- package/form/inputs/InputSwitch/index.js.map +1 -1
- package/form/inputs/InputText/index.cjs +1 -0
- package/form/inputs/InputText/index.cjs.map +1 -1
- package/form/inputs/InputText/index.js +1 -0
- package/form/inputs/InputText/index.js.map +1 -1
- package/form/inputs/InputTextarea/index.cjs +1 -0
- package/form/inputs/InputTextarea/index.cjs.map +1 -1
- package/form/inputs/InputTextarea/index.js +1 -0
- package/form/inputs/InputTextarea/index.js.map +1 -1
- package/form/inputs/PhoneInput/index.cjs +1 -0
- package/form/inputs/PhoneInput/index.cjs.map +1 -1
- package/form/inputs/PhoneInput/index.js +1 -0
- package/form/inputs/PhoneInput/index.js.map +1 -1
- package/form/inputs/RadiusPicker/components/NumericRadiusInput.cjs +1 -0
- package/form/inputs/RadiusPicker/components/NumericRadiusInput.cjs.map +1 -1
- package/form/inputs/RadiusPicker/components/NumericRadiusInput.js +1 -0
- package/form/inputs/RadiusPicker/components/NumericRadiusInput.js.map +1 -1
- package/form/selects/AutoComplete/index.cjs +1 -0
- package/form/selects/AutoComplete/index.cjs.map +1 -1
- package/form/selects/AutoComplete/index.js +1 -0
- package/form/selects/AutoComplete/index.js.map +1 -1
- package/form/selects/Dropdown/index.cjs +1 -0
- package/form/selects/Dropdown/index.cjs.map +1 -1
- package/form/selects/Dropdown/index.js +1 -0
- package/form/selects/Dropdown/index.js.map +1 -1
- package/form/selects/ListBox/index.cjs +1 -0
- package/form/selects/ListBox/index.cjs.map +1 -1
- package/form/selects/ListBox/index.js +1 -0
- package/form/selects/ListBox/index.js.map +1 -1
- package/form/selects/MultiSelect/index.cjs +1 -0
- package/form/selects/MultiSelect/index.cjs.map +1 -1
- package/form/selects/MultiSelect/index.js +1 -0
- package/form/selects/MultiSelect/index.js.map +1 -1
- package/form/selects/TreeSelect/index.cjs +1 -0
- package/form/selects/TreeSelect/index.cjs.map +1 -1
- package/form/selects/TreeSelect/index.js +1 -0
- package/form/selects/TreeSelect/index.js.map +1 -1
- package/form/selects/helpers/SelectPopupOverlay.cjs +1 -0
- package/form/selects/helpers/SelectPopupOverlay.cjs.map +1 -1
- package/form/selects/helpers/SelectPopupOverlay.js +1 -0
- package/form/selects/helpers/SelectPopupOverlay.js.map +1 -1
- package/form-renderer/components/layout/FieldWrapper.cjs +1 -0
- package/form-renderer/components/layout/FieldWrapper.cjs.map +1 -1
- package/form-renderer/components/layout/FieldWrapper.js +1 -0
- package/form-renderer/components/layout/FieldWrapper.js.map +1 -1
- package/hooks/shadowPresets.cjs +1 -0
- package/hooks/shadowPresets.cjs.map +1 -1
- package/hooks/shadowPresets.js +1 -0
- package/hooks/shadowPresets.js.map +1 -1
- package/hooks/useFocusStyles.cjs +1 -0
- package/hooks/useFocusStyles.cjs.map +1 -1
- package/hooks/useFocusStyles.js +1 -0
- package/hooks/useFocusStyles.js.map +1 -1
- package/index.cjs +2 -0
- package/index.cjs.map +1 -1
- package/index.d.ts +117 -5
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/layout/Center/index.cjs +1 -0
- package/layout/Center/index.cjs.map +1 -1
- package/layout/Center/index.js +1 -0
- package/layout/Center/index.js.map +1 -1
- package/layout/Container/container.cjs +1 -0
- package/layout/Container/container.cjs.map +1 -1
- package/layout/Container/container.js +1 -0
- package/layout/Container/container.js.map +1 -1
- package/layout/Flex/index.cjs +1 -0
- package/layout/Flex/index.cjs.map +1 -1
- package/layout/Flex/index.js +1 -0
- package/layout/Flex/index.js.map +1 -1
- package/layout/HStack/index.cjs +1 -0
- package/layout/HStack/index.cjs.map +1 -1
- package/layout/HStack/index.js +1 -0
- package/layout/HStack/index.js.map +1 -1
- package/layout/List/index.cjs +1 -0
- package/layout/List/index.cjs.map +1 -1
- package/layout/List/index.js +1 -0
- package/layout/List/index.js.map +1 -1
- package/layout/ListItem/index.cjs +1 -0
- package/layout/ListItem/index.cjs.map +1 -1
- package/layout/ListItem/index.js +1 -0
- package/layout/ListItem/index.js.map +1 -1
- package/layout/ScrollView/index.cjs +1 -0
- package/layout/ScrollView/index.cjs.map +1 -1
- package/layout/ScrollView/index.js +1 -0
- package/layout/ScrollView/index.js.map +1 -1
- package/layout/VStack/index.cjs +1 -0
- package/layout/VStack/index.cjs.map +1 -1
- package/layout/VStack/index.js +1 -0
- package/layout/VStack/index.js.map +1 -1
- package/package.json +1 -1
- package/packages/types/src/Theme/resolvers.cjs +2 -55
- package/packages/types/src/Theme/resolvers.cjs.map +1 -1
- package/packages/types/src/Theme/resolvers.js +2 -55
- package/packages/types/src/Theme/resolvers.js.map +1 -1
- package/packages/types/src/Theme/semanticTokenNames.cjs +64 -0
- package/packages/types/src/Theme/semanticTokenNames.cjs.map +1 -0
- package/packages/types/src/Theme/semanticTokenNames.js +62 -0
- package/packages/types/src/Theme/semanticTokenNames.js.map +1 -0
- package/primitives/Box/index.cjs +1 -0
- package/primitives/Box/index.cjs.map +1 -1
- package/primitives/Box/index.js +1 -0
- package/primitives/Box/index.js.map +1 -1
- package/primitives/Card/index.cjs +1 -0
- package/primitives/Card/index.cjs.map +1 -1
- package/primitives/Card/index.js +1 -0
- package/primitives/Card/index.js.map +1 -1
- package/primitives/Divider/index.cjs +1 -0
- package/primitives/Divider/index.cjs.map +1 -1
- package/primitives/Divider/index.js +1 -0
- package/primitives/Divider/index.js.map +1 -1
- package/primitives/Heading/index.cjs +1 -0
- package/primitives/Heading/index.cjs.map +1 -1
- package/primitives/Heading/index.js +1 -0
- package/primitives/Heading/index.js.map +1 -1
- package/primitives/Image/index.cjs +1 -0
- package/primitives/Image/index.cjs.map +1 -1
- package/primitives/Image/index.js +1 -0
- package/primitives/Image/index.js.map +1 -1
- package/primitives/Skeleton/index.cjs +1 -0
- package/primitives/Skeleton/index.cjs.map +1 -1
- package/primitives/Skeleton/index.js +1 -0
- package/primitives/Skeleton/index.js.map +1 -1
- package/primitives/Svg/index.cjs +1 -0
- package/primitives/Svg/index.cjs.map +1 -1
- package/primitives/Svg/index.js +1 -0
- package/primitives/Svg/index.js.map +1 -1
- package/primitives/Text/index.cjs +1 -0
- package/primitives/Text/index.cjs.map +1 -1
- package/primitives/Text/index.js +1 -0
- package/primitives/Text/index.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/components/ImageCropper/index.native.tsx"],"sourcesContent":["import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from \"react\";\nimport {\n ActivityIndicator,\n Image,\n PanResponder,\n Pressable,\n Text as RNText,\n View,\n type LayoutChangeEvent,\n type PanResponderGestureState,\n type GestureResponderEvent,\n} from \"react-native\";\nimport Slider from \"@react-native-community/slider\";\nimport type {ICropError, ICropResult, IImageCropperProps} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {useComponentDefaults, useResolvedElementStyles} from \"../../hooks\";\nimport {\n cropperReducer,\n initialCropperState,\n scaleRange,\n zoomFraction,\n type ICropperConfig,\n} from \"./cropperState\";\nimport {aspectOf, cropToSourceRect, orientedSize} from \"./geometry\";\nimport {isUsablePinchReading, pinchScale, type IPinchBaseline} from \"./pinchZoom\";\nimport {\n CROP_ACCENT,\n CROP_ACCENT_SOFT,\n CROP_DANGER,\n DEFAULT_ASPECT,\n DEFAULT_FORMAT,\n DEFAULT_LABELS,\n DEFAULT_MAX_BYTES,\n DEFAULT_MAX_ZOOM,\n SQUARE_CROP_FACTOR,\n STAGE_ASPECT_NATIVE,\n STAGE_INSET_NATIVE,\n} from \"./constants\";\n/**\n * Gesture-handler, if the consumer installed it.\n *\n * ⛔ `require` IN A TRY, NOT AN `import`. A static import is evaluated when this\n * module loads, so an app without the optional peer would fail to render the\n * whole library rather than fall back. `uiPkg.devDependencies` is already in\n * the native rollup's externals list, so this is never bundled either way.\n */\nconst gestureHandler: typeof import(\"react-native-gesture-handler\") | null = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require\n return require(\"react-native-gesture-handler\");\n } catch {\n return null;\n }\n})();\n\nimport {useImageSource} from \"./useImageSource.native\";\nimport {encodeCropNative, hasCropEncoder} from \"./encode.native\";\n\n/**\n * ImageCropper (native).\n *\n * ⛔ IT RUNS THE SAME THREE MODULES AS THE WEB FILE. `cropperState`, `geometry`\n * and `compression` are imported unchanged; this file contributes gestures, a\n * slider, views, and the one platform call the web file makes with a canvas.\n * That is the whole reason those modules have no React in them — a cropper\n * whose platforms each own their own arithmetic produces a photo that is right\n * on the phone and off-centre on the dashboard from one upload.\n *\n * ⛔ GESTURE-HANDLER WHEN IT IS INSTALLED, `PanResponder` WHEN IT IS NOT — AND\n * THE REASON IS A BUG A SIMULATOR CANNOT SHOW YOU. `PanResponder` alone loses\n * every VERTICAL drag to an enclosing `ScrollView`, which is what a cropper\n * sits in inside any real form. A horizontal drag works, so the gesture looks\n * fine until someone drags the way people actually drag.\n *\n * It is not a responder negotiation that can be won from here.\n * `RCTScrollViewComponentView.touchesShouldCancelInContentView:` answers\n * `![self _shouldDisableScrollInteraction]`, and that helper walks the\n * SUPERVIEWS of the scroll view looking for a JS responder — upward, never\n * into its own content. A `PanResponder` in a DESCENDANT is therefore never\n * consulted, and UIScrollView cancels its touches natively. ⛔ So returning\n * `false` from `onPanResponderTerminationRequest`, or claiming the touch in\n * the capture phase, cannot help: there is no JS termination request to\n * refuse. Gesture-handler wins because it competes as a native gesture\n * recogniser, at the only layer where this contest is actually held.\n *\n * ⚠️ THE IMPORT IS GUARDED, NOT STATIC. Gesture-handler is an OPTIONAL peer —\n * the same contract this package already uses for the cropper's two encoder\n * libraries — so a consumer that never installed it must still get a working\n * component rather than a module-load crash. Without it the `PanResponder`\n * path below is used, and it is honestly degraded: fine standalone, beaten by\n * a vertical parent scroll.\n *\n * ⚠️ THE MATH IS NOT DUPLICATED. Both paths call the same `beginGesture` /\n * `applyPan` / `applyPinch` callbacks; only the event source differs. Two\n * copies of the pinch arithmetic would drift, and the fallback is the copy\n * nobody would notice drifting.\n *\n * ⚠️ RESIZING GRIPS ARE NOT OFFERED HERE, as the props type says. A finger has\n * no hover and a grip small enough to look right is too small to hit reliably;\n * native frames by pinch and pan against a fixed window instead.\n */\n\n/**\n * Puts the stage under gesture-handler when it is installed, and out of the way\n * when it is not.\n *\n * ⚠️ DECLARED AT MODULE SCOPE ON PURPOSE. A component defined inside the render\n * is a new type on every pass, so React would unmount and remount the stage —\n * which loses the measured viewport and resets the user's framing mid-drag.\n *\n * ⚠️ IT MOUNTS ITS OWN `GestureHandlerRootView`. Gesture-handler needs one\n * above the detector, and a library cannot assume the host app has mounted it;\n * nesting a second one inside an app that already has one is supported and is\n * what the library itself does for modals.\n */\nconst StageFrame = ({gesture, children}: {gesture: unknown; children: React.ReactNode}) => {\n if (!gestureHandler || !gesture) return <>{children}</>;\n const {GestureDetector, GestureHandlerRootView} = gestureHandler;\n return (\n <GestureHandlerRootView style={{width: \"100%\"}}>\n <GestureDetector gesture={gesture as never}>{children as never}</GestureDetector>\n </GestureHandlerRootView>\n );\n};\n\n/** Distance between the first two touches, for pinch. */\nconst touchDistance = (event: GestureResponderEvent): number => {\n const touches = event.nativeEvent.touches;\n if (touches.length < 2) return 0;\n const [a, b] = touches;\n return Math.hypot((b!.pageX ?? 0) - (a!.pageX ?? 0), (b!.pageY ?? 0) - (a!.pageY ?? 0));\n};\n\n/** Midpoint of the first two touches, in stage coordinates. */\nconst touchMidpoint = (\n event: GestureResponderEvent,\n origin: {x: number; y: number},\n): {x: number; y: number} => {\n const touches = event.nativeEvent.touches;\n if (touches.length < 2) return {x: 0, y: 0};\n const [a, b] = touches;\n return {\n x: ((a!.pageX ?? 0) + (b!.pageX ?? 0)) / 2 - origin.x,\n y: ((a!.pageY ?? 0) + (b!.pageY ?? 0)) / 2 - origin.y,\n };\n};\n\nexport function ImageCropper(rawProps: IImageCropperProps) {\n const {mergedProps: props, elementStyles} =\n useComponentDefaults<IImageCropperProps>(\"ImageCropper\", rawProps);\n const el = useResolvedElementStyles(elementStyles);\n\n const {\n source,\n aspect = DEFAULT_ASPECT,\n maskShape = \"rectangle\",\n output,\n onCrop,\n onCancel,\n onError,\n onInteractionChange,\n title,\n hidePreview,\n hideGrid,\n maxZoom = DEFAULT_MAX_ZOOM,\n labels,\n testID,\n } = props;\n\n const text = {...DEFAULT_LABELS, ...(labels ?? {})};\n const ratio = aspectOf(aspect);\n const isCircle = maskShape === \"circle\";\n\n const {image, loading, error} = useImageSource(source, onError);\n\n /* ─── The stage measures itself ──────────────────────────────────────── */\n const [viewport, setViewport] = useState({width: 0, height: 0});\n const originRef = useRef({x: 0, y: 0});\n const stageRef = useRef<View | null>(null);\n\n const onStageLayout = useCallback((e: LayoutChangeEvent) => {\n const {width, height} = e.nativeEvent.layout;\n setViewport({width: Math.round(width), height: Math.round(height)});\n // ⚠️ THE PAGE ORIGIN IS MEASURED SEPARATELY. `PanResponder` reports\n // touches in PAGE coordinates, and the geometry is written against the\n // STAGE's own space; without this offset every pinch anchors to a point\n // the user is not touching.\n stageRef.current?.measureInWindow((x, y) => {\n originRef.current = {x, y};\n });\n }, []);\n\n const config: ICropperConfig = useMemo(\n () => ({\n source: image ? {width: image.width, height: image.height} : {width: 1, height: 1},\n viewport: viewport.width > 0 ? viewport : {width: 1, height: 1},\n ratio,\n maxZoom,\n // ⚠️ ALWAYS FALSE ON NATIVE — see the note at the top of the file.\n resizable: false,\n inset: STAGE_INSET_NATIVE,\n squareFactor: SQUARE_CROP_FACTOR,\n }),\n [image, viewport, ratio, maxZoom],\n );\n\n const [state, dispatch] = useReducer(cropperReducer, config, initialCropperState);\n useEffect(() => {\n dispatch({type: \"configure\", config});\n }, [config]);\n\n const ready = !!image && viewport.width > 1 && viewport.height > 1;\n\n /* ─── Gestures ───────────────────────────────────────────────────────── */\n const pinchRef = useRef<IPinchBaseline | null>(null);\n const lastPanRef = useRef({x: 0, y: 0});\n const scaleRef = useRef(state.transform.scale);\n scaleRef.current = state.transform.scale;\n\n /**\n * The three things a gesture can say, shared by both input paths.\n *\n * ⚠️ THEY TAKE CUMULATIVE TRAVEL, NOT PER-FRAME DELTAS, because that is what\n * both sources report: `PanResponderGestureState.dx` and gesture-handler's\n * `translationX` are both measured from where the gesture began. The\n * differencing happens here, once.\n */\n /** Re-bases the pan so the next frame is measured from here, not from zero. */\n const resetPan = useCallback(() => {\n lastPanRef.current = {x: 0, y: 0};\n }, []);\n\n const beginGesture = useCallback(() => {\n pinchRef.current = null;\n lastPanRef.current = {x: 0, y: 0};\n }, []);\n\n const applyPan = useCallback((dx: number, dy: number) => {\n dispatch({\n type: \"pan\",\n dx: dx - lastPanRef.current.x,\n dy: dy - lastPanRef.current.y,\n });\n lastPanRef.current = {x: dx, y: dy};\n }, []);\n\n /**\n * One frame of a pinch.\n *\n * ⚠️ `reading` IS WHATEVER THE PLATFORM MEASURES A PINCH WITH, not a ratio.\n * Gesture-handler reports a cumulative `scale` starting at 1; `PanResponder`\n * gives nothing but the raw pixel distance between two fingers. The first\n * reading of a gesture becomes the baseline and every later one is divided\n * by it, so both mean the same thing by the time they arrive here and\n * neither call site has to do arithmetic of its own.\n *\n * ⛔ IT INITIALISES ITSELF, AND THAT IS NOT BELT-AND-BRACES. Requiring\n * `onBegin` to have run first makes the whole pinch depend on one callback\n * firing in one order; if it ever does not, every frame is dropped and\n * pinch is silently dead with nothing in the logs. Seeding from the first\n * reading instead means pinch works whether or not `onBegin` ran.\n *\n * ⚠️ THE SCALE IS READ FROM WHERE THE PINCH STARTED, never from the current\n * one. Multiplying the live scale by a factor that is itself cumulative\n * compounds it every frame, and the image runs away.\n */\n const applyPinch = useCallback((reading: number, anchor: {x: number; y: number}) => {\n if (!isUsablePinchReading(reading)) return;\n const pinch = pinchRef.current;\n if (!pinch) {\n pinchRef.current = {reading, scale: scaleRef.current};\n return;\n }\n dispatch({type: \"zoomAt\", anchor, scale: pinchScale(pinch, reading)});\n }, []);\n\n /**\n * Tells the host whether a finger is on the stage, so it can stand its\n * `ScrollView` down for the duration.\n *\n * ⚠️ IT DE-DUPLICATES. Both gesture paths can report a start more than once\n * for one touch — a pan and a pinch beginning together, or a pinch handing\n * back to a pan — and a host that re-renders on every one of those would\n * re-render mid-drag, repeatedly, for no change in state.\n */\n const interactingRef = useRef(false);\n const setInteracting = useCallback(\n (active: boolean) => {\n if (interactingRef.current === active) return;\n interactingRef.current = active;\n onInteractionChange?.(active);\n },\n [onInteractionChange],\n );\n\n /* ── Path A: gesture-handler, when the consumer installed it ──────────── */\n const detector = useMemo(() => {\n if (!gestureHandler) return null;\n const {Gesture} = gestureHandler;\n\n const pan = Gesture.Pan()\n // ⛔ `runOnJS` BECAUSE THE STATE IS A REDUCER, NOT A WORKLET. Without\n // it these callbacks are compiled as worklets and `dispatch` is not\n // one, which fails at the first finger movement.\n .runOnJS(true)\n .onBegin(() => { setInteracting(true); resetPan(); })\n .onUpdate((e) => {\n // ⛔ `numberOfPointers`, NOT JUST `pinchRef`. A pan tracks the\n // CENTROID of its touches, so the instant a second finger lands\n // the translation jumps by half the gap between the fingers —\n // often a hundred points. Waiting for the pinch gesture to\n // begin before suppressing leaves a window of one or more\n // frames where that jump is applied as a real pan, and the\n // image lurches at the start of every zoom. The pointer count\n // is known on the very first frame and does not depend on which\n // gesture's callback ran first.\n //\n // ⛔ THE BASELINE IS KEPT CURRENT RATHER THAN FROZEN, so a pinch\n // that ends does not become a fling: `translationX` goes on\n // accumulating through the two-finger phase even though the\n // zoom is handling it, and the frame after the fingers lift\n // would otherwise apply the whole pinch travel at once.\n if (e.numberOfPointers > 1 || pinchRef.current) {\n lastPanRef.current = {x: e.translationX, y: e.translationY};\n return;\n }\n applyPan(e.translationX, e.translationY);\n })\n .onFinalize(() => { setInteracting(false); resetPan(); });\n\n const pinch = Gesture.Pinch()\n .runOnJS(true)\n .onBegin(() => {\n setInteracting(true);\n pinchRef.current = {reading: 1, scale: scaleRef.current};\n })\n .onUpdate((e) => {\n applyPinch(e.scale, {x: e.focalX, y: e.focalY});\n })\n // ⚠️ CLEARS ONLY THE PINCH. The pan may still be running — these two\n // are simultaneous — and resetting its baseline here would make the\n // next frame replay the whole gesture as a jump.\n .onFinalize(() => {\n setInteracting(false);\n pinchRef.current = null;\n });\n\n // ⚠️ SIMULTANEOUS, so a pinch that drifts does not have to choose between\n // zooming and moving — which is how a two-finger adjustment actually\n // feels on a phone.\n return Gesture.Simultaneous(pan, pinch);\n }, [applyPan, applyPinch, resetPan, setInteracting]);\n\n /**\n * A `PanResponder` that claims the touch and then does nothing with it.\n *\n * ⛔ THIS IS WHAT STOPS AN ENCLOSING ScrollView EATING A VERTICAL DRAG, AND\n * GESTURE-HANDLER ALONE DOES NOT. A horizontal drag never competes with a\n * vertical scroll, so pan and pinch both looked fixed; the moment a finger\n * moved DOWN the scroll view took it. The chain that fixes it runs through\n * both libraries and no single file shows it:\n *\n * 1. gesture-handler replaces `UIManager.setJSResponder`\n * (`createHandler.tsx`), so every JS responder change is forwarded to\n * its native manager.\n * 2. `PanResponder` reports `blockNativeResponder` — and DEFAULTS IT TO\n * TRUE when `onShouldBlockNativeResponder` is absent\n * (`PanResponder.js`). The docs call it Android-only, and on iOS it\n * does nothing at all until step 1 is in place.\n * 3. gesture-handler's manager answers by calling `blockOtherRecognizers`\n * on its root recognisers, setting the root recogniser to `Began`.\n * 4. `RNRootViewGestureRecognizer.canPreventGestureRecognizer:` then\n * returns YES for every recogniser except RN's own touch handler —\n * UIScrollView's pan among them. The scroll view cannot recognise, so\n * it cannot scroll.\n *\n * ⛔ IT MUST NOT MOVE ANYTHING. The detector is already handling this\n * gesture; a second responder acting on the same fingers would apply every\n * delta twice. It claims the touch, refuses to hand it back, and leaves the\n * arithmetic alone.\n *\n * ⚠️ `onShouldBlockNativeResponder` IS SPELLED OUT rather than left to its\n * default, because that default IS the mechanism, and a later reader\n * deleting an \"unused\" line would quietly return vertical drags to the\n * scroll view.\n *\n * ⚠️ IT CANNOT HELP WHEN THE TOUCH NEVER ARRIVES. `UIScrollView` delays\n * content touches and, once it decides a gesture is a scroll, stops\n * delivering them at all — there is nothing left to claim. That case needs\n * the host to stand its scroll view down, which is what\n * `onInteractionChange` is for.\n */\n const scrollBlocker = useMemo(\n () =>\n PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n onPanResponderTerminationRequest: () => false,\n onShouldBlockNativeResponder: () => true,\n onPanResponderGrant: () => setInteracting(true),\n onPanResponderRelease: () => setInteracting(false),\n onPanResponderTerminate: () => setInteracting(false),\n }),\n [setInteracting],\n );\n\n /* ── Path B: PanResponder, the no-dependency fallback ─────────────────── */\n const responder = useMemo(\n () =>\n PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n // ⚠️ Refuses a JS-level handover. It does NOT save a vertical\n // drag inside a ScrollView — that cancellation is native and\n // never asks — but it does hold the gesture against JS\n // responders nearer the touch.\n onPanResponderTerminationRequest: () => false,\n onPanResponderGrant: () => { setInteracting(true); beginGesture(); },\n onPanResponderMove: (event: GestureResponderEvent, gesture: PanResponderGestureState) => {\n const touches = event.nativeEvent.touches.length;\n\n if (touches >= 2) {\n applyPinch(\n touchDistance(event),\n touchMidpoint(event, originRef.current),\n );\n return;\n }\n\n // ⛔ A PINCH THAT DROPS TO ONE FINGER MUST NOT BECOME A FLING.\n // `gesture.dx` is measured from where the whole gesture began,\n // so the frame after a finger lifts carries the entire pinch\n // travel as a pan. Clearing the pinch and re-basing the pan on\n // the next frame is what stops the image leaping.\n if (pinchRef.current) {\n pinchRef.current = null;\n lastPanRef.current = {x: gesture.dx, y: gesture.dy};\n return;\n }\n\n applyPan(gesture.dx, gesture.dy);\n },\n onPanResponderRelease: () => { setInteracting(false); beginGesture(); },\n onPanResponderTerminate: () => { setInteracting(false); beginGesture(); },\n }),\n [applyPan, applyPinch, beginGesture, setInteracting],\n );\n\n /* ─── Save ───────────────────────────────────────────────────────────── */\n const [busy, setBusy] = useState(false);\n const canSave = ready && !busy && hasCropEncoder();\n\n const save = useCallback(async () => {\n if (!ready || !image || busy) return;\n setBusy(true);\n try {\n const rect = cropToSourceRect(state.crop, state.transform, config.source, state.rotation);\n const format = output?.format ?? DEFAULT_FORMAT;\n const result = await encodeCropNative(\n image.uri,\n rect,\n config.source,\n state.rotation,\n {\n width: output?.maxWidth,\n height: output?.maxHeight,\n bytes: output?.maxBytes ?? DEFAULT_MAX_BYTES,\n },\n format,\n );\n if (!result.withinBudget) {\n onError?.({\n reason: \"too-large\",\n message: `The smallest version this could produce is ${Math.round(result.size / 1024)} KB.`,\n });\n }\n const {withinBudget: _ignored, ...payload} = result;\n onCrop?.(payload as ICropResult);\n } catch (cause) {\n onError?.({\n reason: \"encode-failed\",\n message: cause instanceof Error ? cause.message : \"The image could not be saved.\",\n });\n } finally {\n setBusy(false);\n }\n // ⚠️ THE ENCODER RUNS ON SAVE AND NOWHERE ELSE, which is what \"compute\n // the file size when the gesture settles, not during\" asks for — here it\n // holds by construction rather than by a debounce that could drift.\n }, [ready, image, busy, state, config.source, output, onCrop, onError]);\n\n /* ─── Render ─────────────────────────────────────────────────────────── */\n const {crop, transform, rotation} = state;\n const oriented = image ? orientedSize({width: image.width, height: image.height}, rotation) : null;\n const band = scaleRange(state);\n /**\n * ⚠️ A PERCENTAGE OF THE FIT, NOT A MULTIPLIER — the same reasoning as the\n * web file, and the two must agree or one platform reads 1.4 where the\n * other reads 140 for the identical framing.\n */\n const zoomLabel = Number.isFinite(band.min) && band.min > 0\n ? `${Math.round((transform.scale / band.min) * 100)}%`\n : \"100%\";\n\n /**\n * ⚠️ HALF THE CROP, NOT THE WHOLE OF IT. `borderRadius` is a RADIUS, so a\n * circular window is half the longer side. Passing the full side used to\n * look correct only because iOS silently clamps a radius larger than half\n * the box — which also meant the scrim's radius was being clamped to a\n * DIFFERENT value than the window's, and the two shapes stopped agreeing\n * the moment the crop was not square.\n */\n const windowRadius = isCircle\n ? Math.max(crop.width, crop.height) / 2\n : Number(el.mask?.borderRadius ?? 0);\n\n /**\n * ⛔ THE HOLE IS PUNCHED WITH A BORDER, NOT A BOX-SHADOW. React Native has\n * no 9999px shadow spread to lean on the way the web file does, and four\n * scrim rectangles around the window can only ever cut a RECTANGLE — the\n * avatar case would need a second code path. A view the size of the crop\n * with an enormous border draws the scrim on all four sides at once and\n * follows `borderRadius`, so the circle falls out of the same code.\n *\n * ⛔ IT IS MEASURED FROM THE STAGE, AND A FIXED 2000 DID NOT RENDER AT ALL.\n * The crop always sits inside the stage, so reaching one stage-length out\n * from each edge is already more than enough to cover it — and the stage\n * clips anything beyond. The border then stays the same order of magnitude\n * as the view it is drawn on, instead of a 4000pt border on a 300pt stage\n * that iOS declined to paint, leaving the image completely undimmed.\n *\n * ⚠️ KEEP `windowRadius + SCRIM` EQUAL TO HALF THE OUTER BOX. That is what\n * makes the hole exactly `windowRadius` and keeps it off the clamp.\n */\n const SCRIM = Math.ceil(Math.max(viewport.width, viewport.height)) || 1;\n\n /**\n * The sentence under the title.\n *\n * ⚠️ IT NAMES THE SHAPE, NOT THE PRODUCT — the same reasoning as the web\n * file, and the two must read the same or one platform brands the component\n * and the other does not.\n */\n const aspectLabel = `${aspect[0]}:${aspect[1]}`;\n const subtitle = ready\n ? \"Drag to move · pinch to zoom\"\n : isCircle\n ? `Circle · ${aspectLabel}`\n : `Banner · ${aspectLabel}`;\n\n /** The ceiling, in KB, so the footer can promise what it will actually do. */\n const budgetKb = Math.round((output?.maxBytes ?? DEFAULT_MAX_BYTES) / 1024);\n\n /** The mockup's phone preview: a 60px circle, or a 160×60 band for a cover. */\n const previewWidth = isCircle ? 60 : 160;\n const previewHeight = isCircle ? 60 : Math.round(160 / ratio);\n\n /**\n * Rotate and Reset: a round icon well with its label underneath, which is\n * what the mockup draws on a phone instead of the web file's bordered pill.\n * ⚠️ 44pt, BECAUSE THAT IS THE SMALLEST THING A THUMB RELIABLY HITS.\n */\n const stageTool = (icon: string, label: string, onPress: () => void) => (\n <Pressable\n onPress={onPress}\n disabled={!ready}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n accessibilityState={{disabled: !ready}}\n style={{width: 58, alignItems: \"center\", gap: 4}}\n >\n <View style={{\n width: 44, height: 44, borderRadius: 22,\n backgroundColor: \"rgba(255,255,255,0.09)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}>\n <Icon name={icon as never} size={19} color=\"#FFFFFF\" />\n </View>\n <RNText style={{fontSize: 11, fontWeight: \"600\", color: \"rgba(255,255,255,0.75)\"}}>\n {label}\n </RNText>\n </Pressable>\n );\n\n return (\n <View\n testID={testID}\n style={[\n /**\n * ⚠️ NO `flex: 1` HERE, THOUGH THE MOCKUP IS FULL-SCREEN. A\n * child with `flex: 1` inside a parent that was never given a\n * height measures 0 on Yoga, and this component does not own\n * the screen — a consumer mounts it in a modal, a sheet or a\n * form. The footer's `marginTop: 'auto'` gets the mockup's\n * pinned-to-the-bottom footer when the parent DOES bound the\n * height, and does nothing when it does not.\n */\n {width: \"100%\"},\n el.root,\n /**\n * ⛔ THE PHONE CROPPER IS A DARK SHEET, AND THAT OVERRIDES THE\n * `root` SLOT ON NATIVE ONLY. The mockup draws web as a light\n * modal card and the phone as a full-screen dark surface, and\n * one `root` token cannot be both. It has to be the dark one\n * here because the controls below it are load-bearing white:\n * on a light sheet the Rotate and Reset labels vanish.\n *\n * ⚠️ SO `slots.root.backgroundColor` DOES NOT REACH THIS ON\n * NATIVE. That is the deliberate cost; the stage's own colour\n * has carried the same argument since the component shipped.\n */\n {backgroundColor: \"#0B1517\"},\n ]}\n >\n {/* ⚠️ THE PHONE HEADER IS CENTRED, TIGHTER AND HAS NO DIVIDER. The\n `header` slot carries the web card's 24/18 padding and a\n hairline; the mockup's phone frame is 12/18/14 on a surface that\n needs no rule because the stage below it is darker. */}\n {title != null && (\n <View style={[\n {alignItems: \"center\"},\n el.header,\n {\n paddingLeft: 18, paddingRight: 18, paddingTop: 12, paddingBottom: 14,\n borderBottomWidth: 0, gap: 0,\n },\n ]}>\n <RNText style={[el.title, {fontSize: 16, fontWeight: \"800\", color: \"#FFFFFF\"}]}>\n {title}\n </RNText>\n <RNText style={{marginTop: 3, fontSize: 12, color: \"rgba(255,255,255,0.6)\"}}>\n {subtitle}\n </RNText>\n </View>\n )}\n\n {/* ⚠️ THE STAGE IS FULL-BLEED ON A PHONE. The `content` slot's 24px\n gutter is the web card's; the mockup runs the stage to both edges\n and indents only the tools under it. */}\n <View style={[el.content, {paddingLeft: 0, paddingRight: 0, paddingTop: 0, paddingBottom: 0}]}>\n {/* ⛔ THE STAGE IS ALWAYS MOUNTED, EMPTY OR NOT — `onStageLayout`\n is the only thing that tells the geometry how big the stage\n is, and it only fires while this view exists. The mockup\n keeps the dark stage and insets the drop target inside it. */}\n <StageFrame gesture={detector}>\n <View\n ref={stageRef}\n onLayout={onStageLayout}\n // ⚠️ ONLY ONE PATH MAY MOVE THE IMAGE. With the\n // detector active the responder's job is reduced to\n // claiming the touch so the scroll view is blocked;\n // letting the full one through as well would apply\n // every delta of the same drag twice.\n {...(detector ? scrollBlocker.panHandlers : responder.panHandlers)}\n style={[\n {width: \"100%\", aspectRatio: STAGE_ASPECT_NATIVE, overflow: \"hidden\"},\n el.container,\n ]}\n >\n {ready && image && oriented && (\n <Image\n source={{uri: image.uri}}\n // ⚠️ `resizeMode: 'stretch'` BECAUSE THE BOX IS ALREADY\n // THE RIGHT SHAPE. The geometry decides the exact\n // rectangle the image occupies; letting RN re-fit it\n // inside that rectangle would apply the scaling twice.\n resizeMode=\"stretch\"\n style={{\n position: \"absolute\",\n left: transform.x,\n top: transform.y,\n width: oriented.width * transform.scale,\n height: oriented.height * transform.scale,\n transform: [{rotate: `${rotation}deg`}],\n }}\n />\n )}\n\n {(!source || error) && (\n <View style={[\n {\n position: \"absolute\", left: 18, top: 18, right: 18, bottom: 18,\n alignItems: \"center\", justifyContent: \"center\",\n },\n el.dropZone,\n {borderRadius: 18},\n ]}>\n <View style={{\n width: 60, height: 60, borderRadius: 30,\n backgroundColor: \"rgba(32,170,176,0.16)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}>\n <Icon name={\"image\" as never} size={26} color={CROP_ACCENT_SOFT} />\n </View>\n <RNText style={{fontSize: 16, fontWeight: \"800\", color: \"#FFFFFF\", textAlign: \"center\"}}>\n {text.dropZone}\n </RNText>\n <RNText style={{fontSize: 12.5, color: \"rgba(255,255,255,0.6)\", textAlign: \"center\"}}>\n JPG, PNG or WebP\n </RNText>\n {error && (\n <RNText style={{\n fontSize: 12.5, fontWeight: \"600\",\n color: CROP_DANGER, textAlign: \"center\",\n }}>\n {error.message}\n </RNText>\n )}\n </View>\n )}\n\n {ready && (\n <>\n <View\n pointerEvents=\"none\"\n style={[\n {\n position: \"absolute\",\n left: crop.x - SCRIM,\n top: crop.y - SCRIM,\n width: crop.width + SCRIM * 2,\n height: crop.height + SCRIM * 2,\n borderWidth: SCRIM,\n borderColor: (el.shade?.backgroundColor as string) ?? \"rgba(0,0,0,0.6)\",\n borderRadius: windowRadius + SCRIM,\n },\n ]}\n />\n <View\n pointerEvents=\"none\"\n style={[\n {\n position: \"absolute\",\n left: crop.x, top: crop.y,\n width: crop.width, height: crop.height,\n borderStyle: \"solid\",\n },\n el.cropWindow,\n {borderRadius: windowRadius},\n ]}\n >\n {!hideGrid && [1, 2].map((n) => (\n <React.Fragment key={n}>\n <View style={[\n {position: \"absolute\", top: 0, bottom: 0, width: 1,\n left: (crop.width * n) / 3},\n el.gridLine,\n ]} />\n <View style={[\n {position: \"absolute\", left: 0, right: 0, height: 1,\n top: (crop.height * n) / 3},\n el.gridLine,\n ]} />\n </React.Fragment>\n ))}\n </View>\n\n {/* ⚠️ CENTRED ON A PHONE, TOP-LEFT ON THE WEB — the\n mockup splits here, and it is right to: a thumb\n framing a photo sits over the bottom-left of the\n stage, which is where the web file's chip would be\n read from. */}\n {/* ⛔ A FULL-WIDTH ROW, NOT `alignSelf` ON THE CHIP.\n `alignSelf` is read by the PARENT's flex layout,\n and an absolutely positioned box has none — the\n chip would have stayed pinned to the left edge. */}\n <View\n pointerEvents=\"none\"\n style={{position: \"absolute\", top: 12, left: 0, right: 0, alignItems: \"center\"}}\n >\n <View\n style={[\n {alignItems: \"center\", justifyContent: \"center\"},\n el.zoomChip,\n ]}\n >\n <RNText style={{\n color: (el.zoomChip?.color as string | undefined) ?? \"#FFFFFF\",\n fontSize: 11.5,\n fontWeight: \"700\",\n }}>\n {zoomLabel}\n </RNText>\n </View>\n </View>\n </>\n )}\n\n {/* ⚠️ THE OVERLAY COVERS THE STAGE, it is not a bar pinned to\n the bottom of it. While the encoder runs the framing must\n stop looking adjustable, and a 5pt line at the bottom does\n not say that. */}\n {(loading || busy) && (\n <View\n pointerEvents=\"none\"\n style={{\n position: \"absolute\", left: 0, top: 0, right: 0, bottom: 0,\n backgroundColor: \"rgba(6,14,16,0.74)\",\n alignItems: \"center\", justifyContent: \"center\", gap: 14,\n }}\n >\n <ActivityIndicator\n size=\"large\"\n color={(el.progressFill?.backgroundColor as string | undefined) ?? CROP_ACCENT}\n />\n {busy && (\n <RNText style={{fontSize: 14, fontWeight: \"700\", color: \"#FFFFFF\"}}>\n {text.processing}\n </RNText>\n )}\n </View>\n )}\n </View>\n </StageFrame>\n\n {/* The tool block. ⚠️ DIMMED AND INERT TOGETHER — opacity alone\n leaves a control that looks unavailable and still fires. */}\n <View\n pointerEvents={ready ? \"auto\" : \"none\"}\n style={{\n paddingTop: 16, paddingLeft: 18, paddingRight: 18,\n gap: 16, opacity: ready ? 1 : 0.4,\n }}\n >\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 12}}>\n {!hidePreview && ready && image && oriented && (\n /* The preview is the same image, clipped and offset so the\n crop fills the frame — no pixel work, and therefore\n nothing that has to wait for an encoder. */\n <View\n style={[\n {width: previewWidth, height: previewHeight, overflow: \"hidden\"},\n el.previewFrame,\n isCircle ? {borderRadius: previewWidth / 2} : null,\n /* ⚠️ A 2px RING, NOT THE CARD'S 4. The slot\n carries the desktop preview's ring; at 60pt\n a 4pt ring eats the thumbnail. */\n {borderWidth: 2},\n /* The mockup's float, in the native spelling —\n `boxShadow` is the web file's half of this. */\n {\n shadowColor: \"#000000\",\n shadowOpacity: 0.14,\n shadowRadius: 14,\n shadowOffset: {width: 0, height: 4},\n elevation: 4,\n },\n ]}\n >\n <Image\n source={{uri: image.uri}}\n resizeMode=\"stretch\"\n style={{\n position: \"absolute\",\n width: oriented.width * transform.scale * (previewWidth / crop.width),\n height: oriented.height * transform.scale * (previewWidth / crop.width),\n left: (transform.x - crop.x) * (previewWidth / crop.width),\n top: (transform.y - crop.y) * (previewWidth / crop.width),\n transform: [{rotate: `${rotation}deg`}],\n }}\n />\n </View>\n )}\n <View style={{flex: 1, alignItems: \"flex-end\"}}>\n <RNText style={{fontSize: 17, fontWeight: \"800\", color: \"#FFFFFF\"}}>\n {zoomLabel}\n </RNText>\n <RNText style={{marginTop: 2, fontSize: 11.5, color: \"rgba(255,255,255,0.6)\"}}>\n {`Under ${budgetKb} KB`}\n </RNText>\n </View>\n </View>\n\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 10}}>\n {stageTool(\"rotate-cw\", text.rotate, () => dispatch({type: \"rotate\"}))}\n <Slider\n style={{flex: 1}}\n minimumValue={0}\n maximumValue={1}\n value={zoomFraction(state)}\n disabled={!ready}\n minimumTrackTintColor={el.thumb?.backgroundColor as string | undefined}\n maximumTrackTintColor={el.track?.backgroundColor as string | undefined}\n thumbTintColor={el.thumb?.backgroundColor as string | undefined}\n onValueChange={(value) => dispatch({type: \"setZoom\", value})}\n />\n {stageTool(\"rotate-ccw\", text.reset, () => dispatch({type: \"reset\"}))}\n </View>\n </View>\n </View>\n\n <View style={[\n {flexDirection: \"row\", alignItems: \"center\", marginTop: \"auto\"},\n el.footer,\n {\n paddingLeft: 18, paddingRight: 18, paddingTop: 12, paddingBottom: 28,\n borderTopWidth: 1, borderTopColor: \"rgba(255,255,255,0.08)\", gap: 12,\n },\n ]}>\n <Pressable\n onPress={() => onCancel?.()}\n accessibilityRole=\"button\"\n accessibilityLabel={text.cancel}\n style={{\n flex: 1, height: 52, borderRadius: 26,\n backgroundColor: \"rgba(255,255,255,0.1)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}\n >\n <RNText style={{fontSize: 15, fontWeight: \"700\", color: \"#FFFFFF\"}}>\n {text.cancel}\n </RNText>\n </Pressable>\n {/* ⚠️ 1.4 AGAINST 1, NOT AN EQUAL SPLIT. The mockup gives Save the\n wider half so the primary action is the bigger target, which is\n the only cue a phone footer has — neither button has a border. */}\n <Pressable\n onPress={() => void save()}\n disabled={!canSave}\n accessibilityRole=\"button\"\n accessibilityLabel={text.save}\n accessibilityState={{disabled: !canSave}}\n style={{\n flex: 1.4, height: 52, borderRadius: 26,\n backgroundColor: canSave ? CROP_ACCENT : \"rgba(32,170,176,0.35)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}\n >\n <RNText style={{\n fontSize: 15, fontWeight: \"800\",\n color: canSave ? \"#FFFFFF\" : \"rgba(255,255,255,0.55)\",\n }}>\n {busy ? text.processing : text.save}\n </RNText>\n </Pressable>\n </View>\n </View>\n );\n}\n\nexport default ImageCropper;\n"],"names":["RNText"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/ImageCropper/index.native.tsx"],"sourcesContent":["import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useReducer, useRef, useState} from \"react\";\nimport {\n ActivityIndicator,\n Image,\n PanResponder,\n Pressable,\n Text as RNText,\n View,\n type LayoutChangeEvent,\n type PanResponderGestureState,\n type GestureResponderEvent,\n} from \"react-native\";\nimport Slider from \"@react-native-community/slider\";\nimport type {ICropError, ICropResult, IImageCropperHandle, IImageCropperProps} from \"@lmb-it/kitsconcerto-types\";\nimport {Icon} from \"../../primitives\";\nimport {useComponentDefaults, useResolvedElementStyles} from \"../../hooks\";\nimport {\n cropperReducer,\n initialCropperState,\n scaleRange,\n zoomFraction,\n type ICropperConfig,\n} from \"./cropperState\";\nimport {aspectOf, cropToSourceRect, orientedSize} from \"./geometry\";\nimport {isUsablePinchReading, pinchScale, type IPinchBaseline} from \"./pinchZoom\";\nimport {\n CROP_ACCENT,\n CROP_ACCENT_SOFT,\n CROP_DANGER,\n DEFAULT_ASPECT,\n DEFAULT_FORMAT,\n DEFAULT_LABELS,\n DEFAULT_MAX_BYTES,\n DEFAULT_MAX_ZOOM,\n SQUARE_CROP_FACTOR,\n STAGE_ASPECT_NATIVE,\n STAGE_INSET_NATIVE,\n} from \"./constants\";\n/**\n * Gesture-handler, if the consumer installed it.\n *\n * ⛔ `require` IN A TRY, NOT AN `import`. A static import is evaluated when this\n * module loads, so an app without the optional peer would fail to render the\n * whole library rather than fall back. `uiPkg.devDependencies` is already in\n * the native rollup's externals list, so this is never bundled either way.\n */\nconst gestureHandler: typeof import(\"react-native-gesture-handler\") | null = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require\n return require(\"react-native-gesture-handler\");\n } catch {\n return null;\n }\n})();\n\nimport {useImageSource} from \"./useImageSource.native\";\nimport {encodeCropNative, hasCropEncoder} from \"./encode.native\";\n\n/**\n * ImageCropper (native).\n *\n * ⛔ IT RUNS THE SAME THREE MODULES AS THE WEB FILE. `cropperState`, `geometry`\n * and `compression` are imported unchanged; this file contributes gestures, a\n * slider, views, and the one platform call the web file makes with a canvas.\n * That is the whole reason those modules have no React in them — a cropper\n * whose platforms each own their own arithmetic produces a photo that is right\n * on the phone and off-centre on the dashboard from one upload.\n *\n * ⛔ GESTURE-HANDLER WHEN IT IS INSTALLED, `PanResponder` WHEN IT IS NOT — AND\n * THE REASON IS A BUG A SIMULATOR CANNOT SHOW YOU. `PanResponder` alone loses\n * every VERTICAL drag to an enclosing `ScrollView`, which is what a cropper\n * sits in inside any real form. A horizontal drag works, so the gesture looks\n * fine until someone drags the way people actually drag.\n *\n * It is not a responder negotiation that can be won from here.\n * `RCTScrollViewComponentView.touchesShouldCancelInContentView:` answers\n * `![self _shouldDisableScrollInteraction]`, and that helper walks the\n * SUPERVIEWS of the scroll view looking for a JS responder — upward, never\n * into its own content. A `PanResponder` in a DESCENDANT is therefore never\n * consulted, and UIScrollView cancels its touches natively. ⛔ So returning\n * `false` from `onPanResponderTerminationRequest`, or claiming the touch in\n * the capture phase, cannot help: there is no JS termination request to\n * refuse. Gesture-handler wins because it competes as a native gesture\n * recogniser, at the only layer where this contest is actually held.\n *\n * ⚠️ THE IMPORT IS GUARDED, NOT STATIC. Gesture-handler is an OPTIONAL peer —\n * the same contract this package already uses for the cropper's two encoder\n * libraries — so a consumer that never installed it must still get a working\n * component rather than a module-load crash. Without it the `PanResponder`\n * path below is used, and it is honestly degraded: fine standalone, beaten by\n * a vertical parent scroll.\n *\n * ⚠️ THE MATH IS NOT DUPLICATED. Both paths call the same `beginGesture` /\n * `applyPan` / `applyPinch` callbacks; only the event source differs. Two\n * copies of the pinch arithmetic would drift, and the fallback is the copy\n * nobody would notice drifting.\n *\n * ⚠️ RESIZING GRIPS ARE NOT OFFERED HERE, as the props type says. A finger has\n * no hover and a grip small enough to look right is too small to hit reliably;\n * native frames by pinch and pan against a fixed window instead.\n */\n\n/**\n * Puts the stage under gesture-handler when it is installed, and out of the way\n * when it is not.\n *\n * ⚠️ DECLARED AT MODULE SCOPE ON PURPOSE. A component defined inside the render\n * is a new type on every pass, so React would unmount and remount the stage —\n * which loses the measured viewport and resets the user's framing mid-drag.\n *\n * ⚠️ IT MOUNTS ITS OWN `GestureHandlerRootView`. Gesture-handler needs one\n * above the detector, and a library cannot assume the host app has mounted it;\n * nesting a second one inside an app that already has one is supported and is\n * what the library itself does for modals.\n */\nconst StageFrame = ({gesture, children}: {gesture: unknown; children: React.ReactNode}) => {\n if (!gestureHandler || !gesture) return <>{children}</>;\n const {GestureDetector, GestureHandlerRootView} = gestureHandler;\n return (\n <GestureHandlerRootView style={{width: \"100%\"}}>\n <GestureDetector gesture={gesture as never}>{children as never}</GestureDetector>\n </GestureHandlerRootView>\n );\n};\n\n/** Distance between the first two touches, for pinch. */\nconst touchDistance = (event: GestureResponderEvent): number => {\n const touches = event.nativeEvent.touches;\n if (touches.length < 2) return 0;\n const [a, b] = touches;\n return Math.hypot((b!.pageX ?? 0) - (a!.pageX ?? 0), (b!.pageY ?? 0) - (a!.pageY ?? 0));\n};\n\n/** Midpoint of the first two touches, in stage coordinates. */\nconst touchMidpoint = (\n event: GestureResponderEvent,\n origin: {x: number; y: number},\n): {x: number; y: number} => {\n const touches = event.nativeEvent.touches;\n if (touches.length < 2) return {x: 0, y: 0};\n const [a, b] = touches;\n return {\n x: ((a!.pageX ?? 0) + (b!.pageX ?? 0)) / 2 - origin.x,\n y: ((a!.pageY ?? 0) + (b!.pageY ?? 0)) / 2 - origin.y,\n };\n};\n\nexport const ImageCropper = forwardRef<IImageCropperHandle, IImageCropperProps>(\n function ImageCropper(rawProps, ref) {\n const {mergedProps: props, elementStyles} =\n useComponentDefaults<IImageCropperProps>(\"ImageCropper\", rawProps);\n const el = useResolvedElementStyles(elementStyles);\n\n const {\n source,\n aspect = DEFAULT_ASPECT,\n maskShape = \"rectangle\",\n output,\n onCrop,\n onCancel,\n onError,\n onInteractionChange,\n title,\n hidePreview,\n hideFooter,\n onFrameChange,\n hideGrid,\n maxZoom = DEFAULT_MAX_ZOOM,\n labels,\n testID,\n } = props;\n\n const text = {...DEFAULT_LABELS, ...(labels ?? {})};\n const ratio = aspectOf(aspect);\n const isCircle = maskShape === \"circle\";\n\n const {image, loading, error} = useImageSource(source, onError);\n\n /* ─── The stage measures itself ──────────────────────────────────────── */\n const [viewport, setViewport] = useState({width: 0, height: 0});\n const originRef = useRef({x: 0, y: 0});\n const stageRef = useRef<View | null>(null);\n\n const onStageLayout = useCallback((e: LayoutChangeEvent) => {\n const {width, height} = e.nativeEvent.layout;\n setViewport({width: Math.round(width), height: Math.round(height)});\n // ⚠️ THE PAGE ORIGIN IS MEASURED SEPARATELY. `PanResponder` reports\n // touches in PAGE coordinates, and the geometry is written against the\n // STAGE's own space; without this offset every pinch anchors to a point\n // the user is not touching.\n stageRef.current?.measureInWindow((x, y) => {\n originRef.current = {x, y};\n });\n }, []);\n\n const config: ICropperConfig = useMemo(\n () => ({\n source: image ? {width: image.width, height: image.height} : {width: 1, height: 1},\n viewport: viewport.width > 0 ? viewport : {width: 1, height: 1},\n ratio,\n maxZoom,\n // ⚠️ ALWAYS FALSE ON NATIVE — see the note at the top of the file.\n resizable: false,\n inset: STAGE_INSET_NATIVE,\n squareFactor: SQUARE_CROP_FACTOR,\n }),\n [image, viewport, ratio, maxZoom],\n );\n\n const [state, dispatch] = useReducer(cropperReducer, config, initialCropperState);\n useEffect(() => {\n dispatch({type: \"configure\", config});\n }, [config]);\n\n const ready = !!image && viewport.width > 1 && viewport.height > 1;\n\n /* ─── Gestures ───────────────────────────────────────────────────────── */\n const pinchRef = useRef<IPinchBaseline | null>(null);\n const lastPanRef = useRef({x: 0, y: 0});\n const scaleRef = useRef(state.transform.scale);\n scaleRef.current = state.transform.scale;\n\n /**\n * The three things a gesture can say, shared by both input paths.\n *\n * ⚠️ THEY TAKE CUMULATIVE TRAVEL, NOT PER-FRAME DELTAS, because that is what\n * both sources report: `PanResponderGestureState.dx` and gesture-handler's\n * `translationX` are both measured from where the gesture began. The\n * differencing happens here, once.\n */\n /** Re-bases the pan so the next frame is measured from here, not from zero. */\n const resetPan = useCallback(() => {\n lastPanRef.current = {x: 0, y: 0};\n }, []);\n\n const beginGesture = useCallback(() => {\n pinchRef.current = null;\n lastPanRef.current = {x: 0, y: 0};\n }, []);\n\n const applyPan = useCallback((dx: number, dy: number) => {\n dispatch({\n type: \"pan\",\n dx: dx - lastPanRef.current.x,\n dy: dy - lastPanRef.current.y,\n });\n lastPanRef.current = {x: dx, y: dy};\n }, []);\n\n /**\n * One frame of a pinch.\n *\n * ⚠️ `reading` IS WHATEVER THE PLATFORM MEASURES A PINCH WITH, not a ratio.\n * Gesture-handler reports a cumulative `scale` starting at 1; `PanResponder`\n * gives nothing but the raw pixel distance between two fingers. The first\n * reading of a gesture becomes the baseline and every later one is divided\n * by it, so both mean the same thing by the time they arrive here and\n * neither call site has to do arithmetic of its own.\n *\n * ⛔ IT INITIALISES ITSELF, AND THAT IS NOT BELT-AND-BRACES. Requiring\n * `onBegin` to have run first makes the whole pinch depend on one callback\n * firing in one order; if it ever does not, every frame is dropped and\n * pinch is silently dead with nothing in the logs. Seeding from the first\n * reading instead means pinch works whether or not `onBegin` ran.\n *\n * ⚠️ THE SCALE IS READ FROM WHERE THE PINCH STARTED, never from the current\n * one. Multiplying the live scale by a factor that is itself cumulative\n * compounds it every frame, and the image runs away.\n */\n const applyPinch = useCallback((reading: number, anchor: {x: number; y: number}) => {\n if (!isUsablePinchReading(reading)) return;\n const pinch = pinchRef.current;\n if (!pinch) {\n pinchRef.current = {reading, scale: scaleRef.current};\n return;\n }\n dispatch({type: \"zoomAt\", anchor, scale: pinchScale(pinch, reading)});\n }, []);\n\n /**\n * Tells the host whether a finger is on the stage, so it can stand its\n * `ScrollView` down for the duration.\n *\n * ⚠️ IT DE-DUPLICATES. Both gesture paths can report a start more than once\n * for one touch — a pan and a pinch beginning together, or a pinch handing\n * back to a pan — and a host that re-renders on every one of those would\n * re-render mid-drag, repeatedly, for no change in state.\n */\n const interactingRef = useRef(false);\n const setInteracting = useCallback(\n (active: boolean) => {\n if (interactingRef.current === active) return;\n interactingRef.current = active;\n onInteractionChange?.(active);\n },\n [onInteractionChange],\n );\n\n /* ── Path A: gesture-handler, when the consumer installed it ──────────── */\n const detector = useMemo(() => {\n if (!gestureHandler) return null;\n const {Gesture} = gestureHandler;\n\n const pan = Gesture.Pan()\n // ⛔ `runOnJS` BECAUSE THE STATE IS A REDUCER, NOT A WORKLET. Without\n // it these callbacks are compiled as worklets and `dispatch` is not\n // one, which fails at the first finger movement.\n .runOnJS(true)\n .onBegin(() => { setInteracting(true); resetPan(); })\n .onUpdate((e) => {\n // ⛔ `numberOfPointers`, NOT JUST `pinchRef`. A pan tracks the\n // CENTROID of its touches, so the instant a second finger lands\n // the translation jumps by half the gap between the fingers —\n // often a hundred points. Waiting for the pinch gesture to\n // begin before suppressing leaves a window of one or more\n // frames where that jump is applied as a real pan, and the\n // image lurches at the start of every zoom. The pointer count\n // is known on the very first frame and does not depend on which\n // gesture's callback ran first.\n //\n // ⛔ THE BASELINE IS KEPT CURRENT RATHER THAN FROZEN, so a pinch\n // that ends does not become a fling: `translationX` goes on\n // accumulating through the two-finger phase even though the\n // zoom is handling it, and the frame after the fingers lift\n // would otherwise apply the whole pinch travel at once.\n if (e.numberOfPointers > 1 || pinchRef.current) {\n lastPanRef.current = {x: e.translationX, y: e.translationY};\n return;\n }\n applyPan(e.translationX, e.translationY);\n })\n .onFinalize(() => { setInteracting(false); resetPan(); });\n\n const pinch = Gesture.Pinch()\n .runOnJS(true)\n .onBegin(() => {\n setInteracting(true);\n pinchRef.current = {reading: 1, scale: scaleRef.current};\n })\n .onUpdate((e) => {\n applyPinch(e.scale, {x: e.focalX, y: e.focalY});\n })\n // ⚠️ CLEARS ONLY THE PINCH. The pan may still be running — these two\n // are simultaneous — and resetting its baseline here would make the\n // next frame replay the whole gesture as a jump.\n .onFinalize(() => {\n setInteracting(false);\n pinchRef.current = null;\n });\n\n // ⚠️ SIMULTANEOUS, so a pinch that drifts does not have to choose between\n // zooming and moving — which is how a two-finger adjustment actually\n // feels on a phone.\n return Gesture.Simultaneous(pan, pinch);\n }, [applyPan, applyPinch, resetPan, setInteracting]);\n\n /**\n * A `PanResponder` that claims the touch and then does nothing with it.\n *\n * ⛔ THIS IS WHAT STOPS AN ENCLOSING ScrollView EATING A VERTICAL DRAG, AND\n * GESTURE-HANDLER ALONE DOES NOT. A horizontal drag never competes with a\n * vertical scroll, so pan and pinch both looked fixed; the moment a finger\n * moved DOWN the scroll view took it. The chain that fixes it runs through\n * both libraries and no single file shows it:\n *\n * 1. gesture-handler replaces `UIManager.setJSResponder`\n * (`createHandler.tsx`), so every JS responder change is forwarded to\n * its native manager.\n * 2. `PanResponder` reports `blockNativeResponder` — and DEFAULTS IT TO\n * TRUE when `onShouldBlockNativeResponder` is absent\n * (`PanResponder.js`). The docs call it Android-only, and on iOS it\n * does nothing at all until step 1 is in place.\n * 3. gesture-handler's manager answers by calling `blockOtherRecognizers`\n * on its root recognisers, setting the root recogniser to `Began`.\n * 4. `RNRootViewGestureRecognizer.canPreventGestureRecognizer:` then\n * returns YES for every recogniser except RN's own touch handler —\n * UIScrollView's pan among them. The scroll view cannot recognise, so\n * it cannot scroll.\n *\n * ⛔ IT MUST NOT MOVE ANYTHING. The detector is already handling this\n * gesture; a second responder acting on the same fingers would apply every\n * delta twice. It claims the touch, refuses to hand it back, and leaves the\n * arithmetic alone.\n *\n * ⚠️ `onShouldBlockNativeResponder` IS SPELLED OUT rather than left to its\n * default, because that default IS the mechanism, and a later reader\n * deleting an \"unused\" line would quietly return vertical drags to the\n * scroll view.\n *\n * ⚠️ IT CANNOT HELP WHEN THE TOUCH NEVER ARRIVES. `UIScrollView` delays\n * content touches and, once it decides a gesture is a scroll, stops\n * delivering them at all — there is nothing left to claim. That case needs\n * the host to stand its scroll view down, which is what\n * `onInteractionChange` is for.\n */\n const scrollBlocker = useMemo(\n () =>\n PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n onPanResponderTerminationRequest: () => false,\n onShouldBlockNativeResponder: () => true,\n onPanResponderGrant: () => setInteracting(true),\n onPanResponderRelease: () => setInteracting(false),\n onPanResponderTerminate: () => setInteracting(false),\n }),\n [setInteracting],\n );\n\n /* ── Path B: PanResponder, the no-dependency fallback ─────────────────── */\n const responder = useMemo(\n () =>\n PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n // ⚠️ Refuses a JS-level handover. It does NOT save a vertical\n // drag inside a ScrollView — that cancellation is native and\n // never asks — but it does hold the gesture against JS\n // responders nearer the touch.\n onPanResponderTerminationRequest: () => false,\n onPanResponderGrant: () => { setInteracting(true); beginGesture(); },\n onPanResponderMove: (event: GestureResponderEvent, gesture: PanResponderGestureState) => {\n const touches = event.nativeEvent.touches.length;\n\n if (touches >= 2) {\n applyPinch(\n touchDistance(event),\n touchMidpoint(event, originRef.current),\n );\n return;\n }\n\n // ⛔ A PINCH THAT DROPS TO ONE FINGER MUST NOT BECOME A FLING.\n // `gesture.dx` is measured from where the whole gesture began,\n // so the frame after a finger lifts carries the entire pinch\n // travel as a pan. Clearing the pinch and re-basing the pan on\n // the next frame is what stops the image leaping.\n if (pinchRef.current) {\n pinchRef.current = null;\n lastPanRef.current = {x: gesture.dx, y: gesture.dy};\n return;\n }\n\n applyPan(gesture.dx, gesture.dy);\n },\n onPanResponderRelease: () => { setInteracting(false); beginGesture(); },\n onPanResponderTerminate: () => { setInteracting(false); beginGesture(); },\n }),\n [applyPan, applyPinch, beginGesture, setInteracting],\n );\n\n /* ─── Save ───────────────────────────────────────────────────────────── */\n const [busy, setBusy] = useState(false);\n const canSave = ready && !busy && hasCropEncoder();\n\n const save = useCallback(async () => {\n if (!ready || !image || busy) return;\n setBusy(true);\n try {\n const rect = cropToSourceRect(state.crop, state.transform, config.source, state.rotation);\n const format = output?.format ?? DEFAULT_FORMAT;\n const result = await encodeCropNative(\n image.uri,\n rect,\n config.source,\n state.rotation,\n {\n width: output?.maxWidth,\n height: output?.maxHeight,\n bytes: output?.maxBytes ?? DEFAULT_MAX_BYTES,\n },\n format,\n );\n if (!result.withinBudget) {\n onError?.({\n reason: \"too-large\",\n message: `The smallest version this could produce is ${Math.round(result.size / 1024)} KB.`,\n });\n }\n const {withinBudget: _ignored, ...payload} = result;\n onCrop?.(payload as ICropResult);\n } catch (cause) {\n onError?.({\n reason: \"encode-failed\",\n message: cause instanceof Error ? cause.message : \"The image could not be saved.\",\n });\n } finally {\n setBusy(false);\n }\n // ⚠️ THE ENCODER RUNS ON SAVE AND NOWHERE ELSE, which is what \"compute\n // the file size when the gesture settles, not during\" asks for — here it\n // holds by construction rather than by a debounce that could drift.\n }, [ready, image, busy, state, config.source, output, onCrop, onError]);\n\n /**\n * Encode once and report the size, without delivering a crop. The web\n * file's twin; see {@link IImageCropperHandle.estimate}.\n *\n * ⚠️ IT RETURNS `null` RATHER THAN THROWING WHEN NO ENCODER IS REGISTERED.\n * An estimate is decoration beside a crop; a screen that cannot show a\n * number is a worse reason to crash than one that shows none.\n */\n const estimate = useCallback(async (): Promise<number | null> => {\n if (!ready || !image || !hasCropEncoder()) return null;\n const rect = cropToSourceRect(state.crop, state.transform, config.source, state.rotation);\n const result = await encodeCropNative(\n image.uri,\n rect,\n config.source,\n state.rotation,\n {\n width: output?.maxWidth,\n height: output?.maxHeight,\n bytes: output?.maxBytes ?? DEFAULT_MAX_BYTES,\n },\n output?.format ?? DEFAULT_FORMAT,\n );\n return result.size;\n }, [ready, image, state, config.source, output]);\n\n useImperativeHandle(ref, () => ({save: () => void save(), estimate}), [save, estimate]);\n\n /**\n * ⚠️ IN AN EFFECT, NOT THE RENDER BODY — the web file carries the same note\n * and the same reason.\n */\n const frameCallbackRef = useRef(onFrameChange);\n frameCallbackRef.current = onFrameChange;\n useEffect(() => {\n if (!ready || !image) return;\n frameCallbackRef.current?.({\n crop: state.crop,\n transform: state.transform,\n rotation: state.rotation,\n source: {width: image.width, height: image.height},\n oriented: orientedSize({width: image.width, height: image.height}, state.rotation),\n });\n }, [ready, image, state]);\n\n /* ─── Render ─────────────────────────────────────────────────────────── */\n const {crop, transform, rotation} = state;\n const oriented = image ? orientedSize({width: image.width, height: image.height}, rotation) : null;\n const band = scaleRange(state);\n /**\n * ⚠️ A PERCENTAGE OF THE FIT, NOT A MULTIPLIER — the same reasoning as the\n * web file, and the two must agree or one platform reads 1.4 where the\n * other reads 140 for the identical framing.\n */\n const zoomLabel = Number.isFinite(band.min) && band.min > 0\n ? `${Math.round((transform.scale / band.min) * 100)}%`\n : \"100%\";\n\n /**\n * ⚠️ HALF THE CROP, NOT THE WHOLE OF IT. `borderRadius` is a RADIUS, so a\n * circular window is half the longer side. Passing the full side used to\n * look correct only because iOS silently clamps a radius larger than half\n * the box — which also meant the scrim's radius was being clamped to a\n * DIFFERENT value than the window's, and the two shapes stopped agreeing\n * the moment the crop was not square.\n */\n const windowRadius = isCircle\n ? Math.max(crop.width, crop.height) / 2\n : Number(el.mask?.borderRadius ?? 0);\n\n /**\n * ⛔ THE HOLE IS PUNCHED WITH A BORDER, NOT A BOX-SHADOW. React Native has\n * no 9999px shadow spread to lean on the way the web file does, and four\n * scrim rectangles around the window can only ever cut a RECTANGLE — the\n * avatar case would need a second code path. A view the size of the crop\n * with an enormous border draws the scrim on all four sides at once and\n * follows `borderRadius`, so the circle falls out of the same code.\n *\n * ⛔ IT IS MEASURED FROM THE STAGE, AND A FIXED 2000 DID NOT RENDER AT ALL.\n * The crop always sits inside the stage, so reaching one stage-length out\n * from each edge is already more than enough to cover it — and the stage\n * clips anything beyond. The border then stays the same order of magnitude\n * as the view it is drawn on, instead of a 4000pt border on a 300pt stage\n * that iOS declined to paint, leaving the image completely undimmed.\n *\n * ⚠️ KEEP `windowRadius + SCRIM` EQUAL TO HALF THE OUTER BOX. That is what\n * makes the hole exactly `windowRadius` and keeps it off the clamp.\n */\n const SCRIM = Math.ceil(Math.max(viewport.width, viewport.height)) || 1;\n\n /**\n * The sentence under the title.\n *\n * ⚠️ IT NAMES THE SHAPE, NOT THE PRODUCT — the same reasoning as the web\n * file, and the two must read the same or one platform brands the component\n * and the other does not.\n */\n const aspectLabel = `${aspect[0]}:${aspect[1]}`;\n const subtitle = ready\n ? \"Drag to move · pinch to zoom\"\n : isCircle\n ? `Circle · ${aspectLabel}`\n : `Banner · ${aspectLabel}`;\n\n /** The ceiling, in KB, so the footer can promise what it will actually do. */\n const budgetKb = Math.round((output?.maxBytes ?? DEFAULT_MAX_BYTES) / 1024);\n\n /** The mockup's phone preview: a 60px circle, or a 160×60 band for a cover. */\n const previewWidth = isCircle ? 60 : 160;\n const previewHeight = isCircle ? 60 : Math.round(160 / ratio);\n\n /**\n * Rotate and Reset: a round icon well with its label underneath, which is\n * what the mockup draws on a phone instead of the web file's bordered pill.\n * ⚠️ 44pt, BECAUSE THAT IS THE SMALLEST THING A THUMB RELIABLY HITS.\n */\n const stageTool = (icon: string, label: string, onPress: () => void) => (\n <Pressable\n onPress={onPress}\n disabled={!ready}\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n accessibilityState={{disabled: !ready}}\n style={{width: 58, alignItems: \"center\", gap: 4}}\n >\n <View style={{\n width: 44, height: 44, borderRadius: 22,\n backgroundColor: \"rgba(255,255,255,0.09)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}>\n <Icon name={icon as never} size={19} color=\"#FFFFFF\" />\n </View>\n <RNText style={{fontSize: 11, fontWeight: \"600\", color: \"rgba(255,255,255,0.75)\"}}>\n {label}\n </RNText>\n </Pressable>\n );\n\n return (\n <View\n testID={testID}\n style={[\n /**\n * ⚠️ NO `flex: 1` HERE, THOUGH THE MOCKUP IS FULL-SCREEN. A\n * child with `flex: 1` inside a parent that was never given a\n * height measures 0 on Yoga, and this component does not own\n * the screen — a consumer mounts it in a modal, a sheet or a\n * form. The footer's `marginTop: 'auto'` gets the mockup's\n * pinned-to-the-bottom footer when the parent DOES bound the\n * height, and does nothing when it does not.\n */\n {width: \"100%\"},\n el.root,\n /**\n * ⛔ THE PHONE CROPPER IS A DARK SHEET, AND THAT OVERRIDES THE\n * `root` SLOT ON NATIVE ONLY. The mockup draws web as a light\n * modal card and the phone as a full-screen dark surface, and\n * one `root` token cannot be both. It has to be the dark one\n * here because the controls below it are load-bearing white:\n * on a light sheet the Rotate and Reset labels vanish.\n *\n * ⚠️ SO `slots.root.backgroundColor` DOES NOT REACH THIS ON\n * NATIVE. That is the deliberate cost; the stage's own colour\n * has carried the same argument since the component shipped.\n */\n {backgroundColor: \"#0B1517\"},\n ]}\n >\n {/* ⚠️ THE PHONE HEADER IS CENTRED, TIGHTER AND HAS NO DIVIDER. The\n `header` slot carries the web card's 24/18 padding and a\n hairline; the mockup's phone frame is 12/18/14 on a surface that\n needs no rule because the stage below it is darker. */}\n {title != null && (\n <View style={[\n {alignItems: \"center\"},\n el.header,\n {\n paddingLeft: 18, paddingRight: 18, paddingTop: 12, paddingBottom: 14,\n borderBottomWidth: 0, gap: 0,\n },\n ]}>\n <RNText style={[el.title, {fontSize: 16, fontWeight: \"800\", color: \"#FFFFFF\"}]}>\n {title}\n </RNText>\n <RNText style={{marginTop: 3, fontSize: 12, color: \"rgba(255,255,255,0.6)\"}}>\n {subtitle}\n </RNText>\n </View>\n )}\n\n {/* ⚠️ THE STAGE IS FULL-BLEED ON A PHONE. The `content` slot's 24px\n gutter is the web card's; the mockup runs the stage to both edges\n and indents only the tools under it. */}\n <View style={[el.content, {paddingLeft: 0, paddingRight: 0, paddingTop: 0, paddingBottom: 0}]}>\n {/* ⛔ THE STAGE IS ALWAYS MOUNTED, EMPTY OR NOT — `onStageLayout`\n is the only thing that tells the geometry how big the stage\n is, and it only fires while this view exists. The mockup\n keeps the dark stage and insets the drop target inside it. */}\n <StageFrame gesture={detector}>\n <View\n ref={stageRef}\n onLayout={onStageLayout}\n // ⚠️ ONLY ONE PATH MAY MOVE THE IMAGE. With the\n // detector active the responder's job is reduced to\n // claiming the touch so the scroll view is blocked;\n // letting the full one through as well would apply\n // every delta of the same drag twice.\n {...(detector ? scrollBlocker.panHandlers : responder.panHandlers)}\n style={[\n {width: \"100%\", aspectRatio: STAGE_ASPECT_NATIVE, overflow: \"hidden\"},\n el.container,\n ]}\n >\n {ready && image && oriented && (\n <Image\n source={{uri: image.uri}}\n // ⚠️ `resizeMode: 'stretch'` BECAUSE THE BOX IS ALREADY\n // THE RIGHT SHAPE. The geometry decides the exact\n // rectangle the image occupies; letting RN re-fit it\n // inside that rectangle would apply the scaling twice.\n resizeMode=\"stretch\"\n style={{\n position: \"absolute\",\n left: transform.x,\n top: transform.y,\n width: oriented.width * transform.scale,\n height: oriented.height * transform.scale,\n transform: [{rotate: `${rotation}deg`}],\n }}\n />\n )}\n\n {(!source || error) && (\n <View style={[\n {\n position: \"absolute\", left: 18, top: 18, right: 18, bottom: 18,\n alignItems: \"center\", justifyContent: \"center\",\n },\n el.dropZone,\n {borderRadius: 18},\n ]}>\n <View style={{\n width: 60, height: 60, borderRadius: 30,\n backgroundColor: \"rgba(32,170,176,0.16)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}>\n <Icon name={\"image\" as never} size={26} color={CROP_ACCENT_SOFT} />\n </View>\n <RNText style={{fontSize: 16, fontWeight: \"800\", color: \"#FFFFFF\", textAlign: \"center\"}}>\n {text.dropZone}\n </RNText>\n <RNText style={{fontSize: 12.5, color: \"rgba(255,255,255,0.6)\", textAlign: \"center\"}}>\n JPG, PNG or WebP\n </RNText>\n {error && (\n <RNText style={{\n fontSize: 12.5, fontWeight: \"600\",\n color: CROP_DANGER, textAlign: \"center\",\n }}>\n {error.message}\n </RNText>\n )}\n </View>\n )}\n\n {ready && (\n <>\n <View\n pointerEvents=\"none\"\n style={[\n {\n position: \"absolute\",\n left: crop.x - SCRIM,\n top: crop.y - SCRIM,\n width: crop.width + SCRIM * 2,\n height: crop.height + SCRIM * 2,\n borderWidth: SCRIM,\n borderColor: (el.shade?.backgroundColor as string) ?? \"rgba(0,0,0,0.6)\",\n borderRadius: windowRadius + SCRIM,\n },\n ]}\n />\n <View\n pointerEvents=\"none\"\n style={[\n {\n position: \"absolute\",\n left: crop.x, top: crop.y,\n width: crop.width, height: crop.height,\n borderStyle: \"solid\",\n },\n el.cropWindow,\n {borderRadius: windowRadius},\n ]}\n >\n {!hideGrid && [1, 2].map((n) => (\n <React.Fragment key={n}>\n <View style={[\n {position: \"absolute\", top: 0, bottom: 0, width: 1,\n left: (crop.width * n) / 3},\n el.gridLine,\n ]} />\n <View style={[\n {position: \"absolute\", left: 0, right: 0, height: 1,\n top: (crop.height * n) / 3},\n el.gridLine,\n ]} />\n </React.Fragment>\n ))}\n </View>\n\n {/* ⚠️ CENTRED ON A PHONE, TOP-LEFT ON THE WEB — the\n mockup splits here, and it is right to: a thumb\n framing a photo sits over the bottom-left of the\n stage, which is where the web file's chip would be\n read from. */}\n {/* ⛔ A FULL-WIDTH ROW, NOT `alignSelf` ON THE CHIP.\n `alignSelf` is read by the PARENT's flex layout,\n and an absolutely positioned box has none — the\n chip would have stayed pinned to the left edge. */}\n <View\n pointerEvents=\"none\"\n style={{position: \"absolute\", top: 12, left: 0, right: 0, alignItems: \"center\"}}\n >\n <View\n style={[\n {alignItems: \"center\", justifyContent: \"center\"},\n el.zoomChip,\n ]}\n >\n <RNText style={{\n color: (el.zoomChip?.color as string | undefined) ?? \"#FFFFFF\",\n fontSize: 11.5,\n fontWeight: \"700\",\n }}>\n {zoomLabel}\n </RNText>\n </View>\n </View>\n </>\n )}\n\n {/* ⚠️ THE OVERLAY COVERS THE STAGE, it is not a bar pinned to\n the bottom of it. While the encoder runs the framing must\n stop looking adjustable, and a 5pt line at the bottom does\n not say that. */}\n {(loading || busy) && (\n <View\n pointerEvents=\"none\"\n style={{\n position: \"absolute\", left: 0, top: 0, right: 0, bottom: 0,\n backgroundColor: \"rgba(6,14,16,0.74)\",\n alignItems: \"center\", justifyContent: \"center\", gap: 14,\n }}\n >\n <ActivityIndicator\n size=\"large\"\n color={(el.progressFill?.backgroundColor as string | undefined) ?? CROP_ACCENT}\n />\n {busy && (\n <RNText style={{fontSize: 14, fontWeight: \"700\", color: \"#FFFFFF\"}}>\n {text.processing}\n </RNText>\n )}\n </View>\n )}\n </View>\n </StageFrame>\n\n {/* The tool block. ⚠️ DIMMED AND INERT TOGETHER — opacity alone\n leaves a control that looks unavailable and still fires. */}\n <View\n pointerEvents={ready ? \"auto\" : \"none\"}\n style={{\n paddingTop: 16, paddingLeft: 18, paddingRight: 18,\n gap: 16, opacity: ready ? 1 : 0.4,\n }}\n >\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 12}}>\n {!hidePreview && ready && image && oriented && (\n /* The preview is the same image, clipped and offset so the\n crop fills the frame — no pixel work, and therefore\n nothing that has to wait for an encoder. */\n <View\n style={[\n {width: previewWidth, height: previewHeight, overflow: \"hidden\"},\n el.previewFrame,\n isCircle ? {borderRadius: previewWidth / 2} : null,\n /* ⚠️ A 2px RING, NOT THE CARD'S 4. The slot\n carries the desktop preview's ring; at 60pt\n a 4pt ring eats the thumbnail. */\n {borderWidth: 2},\n /* The mockup's float, in the native spelling —\n `boxShadow` is the web file's half of this. */\n {\n shadowColor: \"#000000\",\n shadowOpacity: 0.14,\n shadowRadius: 14,\n shadowOffset: {width: 0, height: 4},\n elevation: 4,\n },\n ]}\n >\n <Image\n source={{uri: image.uri}}\n resizeMode=\"stretch\"\n style={{\n position: \"absolute\",\n width: oriented.width * transform.scale * (previewWidth / crop.width),\n height: oriented.height * transform.scale * (previewWidth / crop.width),\n left: (transform.x - crop.x) * (previewWidth / crop.width),\n top: (transform.y - crop.y) * (previewWidth / crop.width),\n transform: [{rotate: `${rotation}deg`}],\n }}\n />\n </View>\n )}\n <View style={{flex: 1, alignItems: \"flex-end\"}}>\n <RNText style={{fontSize: 17, fontWeight: \"800\", color: \"#FFFFFF\"}}>\n {zoomLabel}\n </RNText>\n <RNText style={{marginTop: 2, fontSize: 11.5, color: \"rgba(255,255,255,0.6)\"}}>\n {`Under ${budgetKb} KB`}\n </RNText>\n </View>\n </View>\n\n <View style={{flexDirection: \"row\", alignItems: \"center\", gap: 10}}>\n {stageTool(\"rotate-cw\", text.rotate, () => dispatch({type: \"rotate\"}))}\n <Slider\n style={{flex: 1}}\n minimumValue={0}\n maximumValue={1}\n value={zoomFraction(state)}\n disabled={!ready}\n minimumTrackTintColor={el.thumb?.backgroundColor as string | undefined}\n maximumTrackTintColor={el.track?.backgroundColor as string | undefined}\n thumbTintColor={el.thumb?.backgroundColor as string | undefined}\n onValueChange={(value) => dispatch({type: \"setZoom\", value})}\n />\n {stageTool(\"rotate-ccw\", text.reset, () => dispatch({type: \"reset\"}))}\n </View>\n </View>\n </View>\n\n {!hideFooter && (\n <View style={[\n {flexDirection: \"row\", alignItems: \"center\", marginTop: \"auto\"},\n el.footer,\n {\n paddingLeft: 18, paddingRight: 18, paddingTop: 12, paddingBottom: 28,\n borderTopWidth: 1, borderTopColor: \"rgba(255,255,255,0.08)\", gap: 12,\n },\n ]}>\n <Pressable\n onPress={() => onCancel?.()}\n accessibilityRole=\"button\"\n accessibilityLabel={text.cancel}\n style={{\n flex: 1, height: 52, borderRadius: 26,\n backgroundColor: \"rgba(255,255,255,0.1)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}\n >\n <RNText style={{fontSize: 15, fontWeight: \"700\", color: \"#FFFFFF\"}}>\n {text.cancel}\n </RNText>\n </Pressable>\n {/* ⚠️ 1.4 AGAINST 1, NOT AN EQUAL SPLIT. The mockup gives Save the\n wider half so the primary action is the bigger target, which is\n the only cue a phone footer has — neither button has a border. */}\n <Pressable\n onPress={() => void save()}\n disabled={!canSave}\n accessibilityRole=\"button\"\n accessibilityLabel={text.save}\n accessibilityState={{disabled: !canSave}}\n style={{\n flex: 1.4, height: 52, borderRadius: 26,\n backgroundColor: canSave ? CROP_ACCENT : \"rgba(32,170,176,0.35)\",\n alignItems: \"center\", justifyContent: \"center\",\n }}\n >\n <RNText style={{\n fontSize: 15, fontWeight: \"800\",\n color: canSave ? \"#FFFFFF\" : \"rgba(255,255,255,0.55)\",\n }}>\n {busy ? text.processing : text.save}\n </RNText>\n </Pressable>\n </View>\n )}\n </View>\n );\n});\n\nexport default ImageCropper;\n"],"names":["ImageCropper","RNText"],"mappings":";;;;;;;;;;;;;;;;;;AA8CA,MAAM,kBAAwE,MAAM;AAChF,EAAA,IAAI;AAEA,IAAA,OAAO,QAAQ,8BAA8B,CAAA;AAAA,EACjD,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACJ,CAAA,GAAG;AA8DH,MAAM,UAAA,GAAa,CAAC,EAAC,OAAA,EAAS,UAAQ,KAAqD;AACvF,EAAA,IAAI,CAAC,cAAA,IAAkB,CAAC,OAAA,EAAS,uCAAU,QAAA,EAAS,CAAA;AACpD,EAAA,MAAM,EAAC,eAAA,EAAiB,sBAAA,EAAsB,GAAI,cAAA;AAClD,EAAA,uBACI,GAAA,CAAC,sBAAA,EAAA,EAAuB,KAAA,EAAO,EAAC,KAAA,EAAO,MAAA,EAAM,EACzC,QAAA,kBAAA,GAAA,CAAC,eAAA,EAAA,EAAgB,OAAA,EAA4B,QAAA,EAAkB,CAAA,EACnE,CAAA;AAER,CAAA;AAGA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyC;AAC5D,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,OAAA;AAClC,EAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,OAAO,CAAA;AAC/B,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,OAAA;AACf,EAAA,OAAO,IAAA,CAAK,KAAA,CAAA,CAAO,CAAA,CAAG,KAAA,IAAS,CAAA,KAAM,CAAA,CAAG,KAAA,IAAS,CAAA,CAAA,EAAA,CAAK,CAAA,CAAG,KAAA,IAAS,CAAA,KAAM,CAAA,CAAG,SAAS,CAAA,CAAE,CAAA;AAC1F,CAAA;AAGA,MAAM,aAAA,GAAgB,CAClB,KAAA,EACA,MAAA,KACyB;AACzB,EAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,OAAA;AAClC,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG,OAAO,EAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAC;AAC1C,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,OAAA;AACf,EAAA,OAAO;AAAA,IACH,CAAA,EAAA,CAAA,CAAK,EAAG,KAAA,IAAS,CAAA,KAAM,EAAG,KAAA,IAAS,CAAA,CAAA,IAAM,IAAI,MAAA,CAAO,CAAA;AAAA,IACpD,CAAA,EAAA,CAAA,CAAK,EAAG,KAAA,IAAS,CAAA,KAAM,EAAG,KAAA,IAAS,CAAA,CAAA,IAAM,IAAI,MAAA,CAAO;AAAA,GACxD;AACJ,CAAA;AAEO,MAAM,YAAA,GAAe,UAAA;AAAA,EACxB,SAASA,aAAAA,CAAa,QAAA,EAAU,GAAA,EAAK;AACrC,IAAA,MAAM,EAAC,WAAA,EAAa,KAAA,EAAO,eAAa,GACpC,oBAAA,CAAyC,gBAAgB,QAAQ,CAAA;AACrE,IAAA,MAAM,EAAA,GAAK,yBAAyB,aAAa,CAAA;AAEjD,IAAA,MAAM;AAAA,MACF,MAAA;AAAA,MACA,MAAA,GAAS,cAAA;AAAA,MACT,SAAA,GAAY,WAAA;AAAA,MACZ,MAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA,mBAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,aAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA,GAAU,gBAAA;AAAA,MACV,MAAA;AAAA,MACA;AAAA,KACJ,GAAI,KAAA;AAEJ,IAAA,MAAM,OAAO,EAAC,GAAG,gBAAgB,GAAI,MAAA,IAAU,EAAC,EAAE;AAClD,IAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAC7B,IAAA,MAAM,WAAW,SAAA,KAAc,QAAA;AAE/B,IAAA,MAAM,EAAC,KAAA,EAAO,OAAA,EAAS,OAAK,GAAI,cAAA,CAAe,QAAQ,OAAO,CAAA;AAG9D,IAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAAS,EAAC,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAE,CAAA;AAC9D,IAAA,MAAM,YAAY,MAAA,CAAO,EAAC,GAAG,CAAA,EAAG,CAAA,EAAG,GAAE,CAAA;AACrC,IAAA,MAAM,QAAA,GAAW,OAAoB,IAAI,CAAA;AAEzC,IAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,CAAC,CAAA,KAAyB;AACxD,MAAA,MAAM,EAAC,KAAA,EAAO,MAAA,EAAM,GAAI,EAAE,WAAA,CAAY,MAAA;AACtC,MAAA,WAAA,CAAY,EAAC,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,EAAG,MAAA,EAAQ,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAE,CAAA;AAKlE,MAAA,QAAA,CAAS,OAAA,EAAS,eAAA,CAAgB,CAAC,CAAA,EAAG,CAAA,KAAM;AACxC,QAAA,SAAA,CAAU,OAAA,GAAU,EAAC,CAAA,EAAG,CAAA,EAAC;AAAA,MAC7B,CAAC,CAAA;AAAA,IACL,CAAA,EAAG,EAAE,CAAA;AAEL,IAAA,MAAM,MAAA,GAAyB,OAAA;AAAA,MAC3B,OAAO;AAAA,QACH,MAAA,EAAQ,KAAA,GAAQ,EAAC,KAAA,EAAO,MAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAM,GAAI,EAAC,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,EAAC;AAAA,QACjF,QAAA,EAAU,SAAS,KAAA,GAAQ,CAAA,GAAI,WAAW,EAAC,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAC;AAAA,QAC9D,KAAA;AAAA,QACA,OAAA;AAAA;AAAA,QAEA,SAAA,EAAW,KAAA;AAAA,QACX,KAAA,EAAO,kBAAA;AAAA,QACP,YAAA,EAAc;AAAA,OAClB,CAAA;AAAA,MACA,CAAC,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,OAAO;AAAA,KACpC;AAEA,IAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,IAAI,UAAA,CAAW,cAAA,EAAgB,QAAQ,mBAAmB,CAAA;AAChF,IAAA,SAAA,CAAU,MAAM;AACZ,MAAA,QAAA,CAAS,EAAC,IAAA,EAAM,WAAA,EAAa,MAAA,EAAO,CAAA;AAAA,IACxC,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,IAAA,MAAM,KAAA,GAAQ,CAAC,CAAC,KAAA,IAAS,SAAS,KAAA,GAAQ,CAAA,IAAK,SAAS,MAAA,GAAS,CAAA;AAGjE,IAAA,MAAM,QAAA,GAAW,OAA8B,IAAI,CAAA;AACnD,IAAA,MAAM,aAAa,MAAA,CAAO,EAAC,GAAG,CAAA,EAAG,CAAA,EAAG,GAAE,CAAA;AACtC,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,KAAA,CAAM,SAAA,CAAU,KAAK,CAAA;AAC7C,IAAA,QAAA,CAAS,OAAA,GAAU,MAAM,SAAA,CAAU,KAAA;AAWnC,IAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AAC/B,MAAA,UAAA,CAAW,OAAA,GAAU,EAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAC;AAAA,IACpC,CAAA,EAAG,EAAE,CAAA;AAEL,IAAA,MAAM,YAAA,GAAe,YAAY,MAAM;AACnC,MAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,MAAA,UAAA,CAAW,OAAA,GAAU,EAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAC;AAAA,IACpC,CAAA,EAAG,EAAE,CAAA;AAEL,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,CAAC,EAAA,EAAY,EAAA,KAAe;AACrD,MAAA,QAAA,CAAS;AAAA,QACL,IAAA,EAAM,KAAA;AAAA,QACN,EAAA,EAAI,EAAA,GAAK,UAAA,CAAW,OAAA,CAAQ,CAAA;AAAA,QAC5B,EAAA,EAAI,EAAA,GAAK,UAAA,CAAW,OAAA,CAAQ;AAAA,OAC/B,CAAA;AACD,MAAA,UAAA,CAAW,OAAA,GAAU,EAAC,CAAA,EAAG,EAAA,EAAI,GAAG,EAAA,EAAE;AAAA,IACtC,CAAA,EAAG,EAAE,CAAA;AAsBL,IAAA,MAAM,UAAA,GAAa,WAAA,CAAY,CAAC,OAAA,EAAiB,MAAA,KAAmC;AAChF,MAAA,IAAI,CAAC,oBAAA,CAAqB,OAAO,CAAA,EAAG;AACpC,MAAA,MAAM,QAAQ,QAAA,CAAS,OAAA;AACvB,MAAA,IAAI,CAAC,KAAA,EAAO;AACR,QAAA,QAAA,CAAS,OAAA,GAAU,EAAC,OAAA,EAAS,KAAA,EAAO,SAAS,OAAA,EAAO;AACpD,QAAA;AAAA,MACJ;AACA,MAAA,QAAA,CAAS,EAAC,MAAM,QAAA,EAAU,MAAA,EAAQ,OAAO,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA,EAAE,CAAA;AAAA,IACxE,CAAA,EAAG,EAAE,CAAA;AAWL,IAAA,MAAM,cAAA,GAAiB,OAAO,KAAK,CAAA;AACnC,IAAA,MAAM,cAAA,GAAiB,WAAA;AAAA,MACnB,CAAC,MAAA,KAAoB;AACjB,QAAA,IAAI,cAAA,CAAe,YAAY,MAAA,EAAQ;AACvC,QAAA,cAAA,CAAe,OAAA,GAAU,MAAA;AACzB,QAAA,mBAAA,GAAsB,MAAM,CAAA;AAAA,MAChC,CAAA;AAAA,MACA,CAAC,mBAAmB;AAAA,KACxB;AAGA,IAAA,MAAM,QAAA,GAAW,QAAQ,MAAM;AAC3B,MAAA,IAAI,CAAC,gBAAgB,OAAO,IAAA;AAC5B,MAAA,MAAM,EAAC,SAAO,GAAI,cAAA;AAElB,MAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,EAAI,CAInB,QAAQ,IAAI,CAAA,CACZ,QAAQ,MAAM;AAAE,QAAA,cAAA,CAAe,IAAI,CAAA;AAAG,QAAA,QAAA,EAAS;AAAA,MAAG,CAAC,CAAA,CACnD,QAAA,CAAS,CAAC,CAAA,KAAM;AAgBb,QAAA,IAAI,CAAA,CAAE,gBAAA,GAAmB,CAAA,IAAK,QAAA,CAAS,OAAA,EAAS;AAC5C,UAAA,UAAA,CAAW,UAAU,EAAC,CAAA,EAAG,EAAE,YAAA,EAAc,CAAA,EAAG,EAAE,YAAA,EAAY;AAC1D,UAAA;AAAA,QACJ;AACA,QAAA,QAAA,CAAS,CAAA,CAAE,YAAA,EAAc,CAAA,CAAE,YAAY,CAAA;AAAA,MAC3C,CAAC,CAAA,CACA,UAAA,CAAW,MAAM;AAAE,QAAA,cAAA,CAAe,KAAK,CAAA;AAAG,QAAA,QAAA,EAAS;AAAA,MAAG,CAAC,CAAA;AAE5D,MAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,EAAM,CACvB,QAAQ,IAAI,CAAA,CACZ,QAAQ,MAAM;AACX,QAAA,cAAA,CAAe,IAAI,CAAA;AACnB,QAAA,QAAA,CAAS,UAAU,EAAC,OAAA,EAAS,CAAA,EAAG,KAAA,EAAO,SAAS,OAAA,EAAO;AAAA,MAC3D,CAAC,CAAA,CACA,QAAA,CAAS,CAAC,CAAA,KAAM;AACb,QAAA,UAAA,CAAW,CAAA,CAAE,OAAO,EAAC,CAAA,EAAG,EAAE,MAAA,EAAQ,CAAA,EAAG,CAAA,CAAE,MAAA,EAAO,CAAA;AAAA,MAClD,CAAC,CAAA,CAIA,UAAA,CAAW,MAAM;AACd,QAAA,cAAA,CAAe,KAAK,CAAA;AACpB,QAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AAAA,MACvB,CAAC,CAAA;AAKL,MAAA,OAAO,OAAA,CAAQ,YAAA,CAAa,GAAA,EAAK,KAAK,CAAA;AAAA,IAC1C,GAAG,CAAC,QAAA,EAAU,UAAA,EAAY,QAAA,EAAU,cAAc,CAAC,CAAA;AAyCnD,IAAA,MAAM,aAAA,GAAgB,OAAA;AAAA,MAClB,MACI,aAAa,MAAA,CAAO;AAAA,QAChB,8BAA8B,MAAM,IAAA;AAAA,QACpC,6BAA6B,MAAM,IAAA;AAAA,QACnC,kCAAkC,MAAM,KAAA;AAAA,QACxC,8BAA8B,MAAM,IAAA;AAAA,QACpC,mBAAA,EAAqB,MAAM,cAAA,CAAe,IAAI,CAAA;AAAA,QAC9C,qBAAA,EAAuB,MAAM,cAAA,CAAe,KAAK,CAAA;AAAA,QACjD,uBAAA,EAAyB,MAAM,cAAA,CAAe,KAAK;AAAA,OACtD,CAAA;AAAA,MACL,CAAC,cAAc;AAAA,KACnB;AAGA,IAAA,MAAM,SAAA,GAAY,OAAA;AAAA,MACd,MACI,aAAa,MAAA,CAAO;AAAA,QAChB,8BAA8B,MAAM,IAAA;AAAA,QACpC,6BAA6B,MAAM,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKnC,kCAAkC,MAAM,KAAA;AAAA,QACxC,qBAAqB,MAAM;AAAE,UAAA,cAAA,CAAe,IAAI,CAAA;AAAG,UAAA,YAAA,EAAa;AAAA,QAAG,CAAA;AAAA,QACnE,kBAAA,EAAoB,CAAC,KAAA,EAA8B,OAAA,KAAsC;AACrF,UAAA,MAAM,OAAA,GAAU,KAAA,CAAM,WAAA,CAAY,OAAA,CAAQ,MAAA;AAE1C,UAAA,IAAI,WAAW,CAAA,EAAG;AACd,YAAA,UAAA;AAAA,cACI,cAAc,KAAK,CAAA;AAAA,cACnB,aAAA,CAAc,KAAA,EAAO,SAAA,CAAU,OAAO;AAAA,aAC1C;AACA,YAAA;AAAA,UACJ;AAOA,UAAA,IAAI,SAAS,OAAA,EAAS;AAClB,YAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,YAAA,UAAA,CAAW,UAAU,EAAC,CAAA,EAAG,QAAQ,EAAA,EAAI,CAAA,EAAG,QAAQ,EAAA,EAAE;AAClD,YAAA;AAAA,UACJ;AAEA,UAAA,QAAA,CAAS,OAAA,CAAQ,EAAA,EAAI,OAAA,CAAQ,EAAE,CAAA;AAAA,QACnC,CAAA;AAAA,QACA,uBAAuB,MAAM;AAAE,UAAA,cAAA,CAAe,KAAK,CAAA;AAAG,UAAA,YAAA,EAAa;AAAA,QAAG,CAAA;AAAA,QACtE,yBAAyB,MAAM;AAAE,UAAA,cAAA,CAAe,KAAK,CAAA;AAAG,UAAA,YAAA,EAAa;AAAA,QAAG;AAAA,OAC3E,CAAA;AAAA,MACL,CAAC,QAAA,EAAU,UAAA,EAAY,YAAA,EAAc,cAAc;AAAA,KACvD;AAGA,IAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,IAAA,MAAM,OAAA,GAAU,KAAA,IAAS,CAAC,IAAA,IAAQ,cAAA,EAAe;AAEjD,IAAA,MAAM,IAAA,GAAO,YAAY,YAAY;AACjC,MAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAA,IAAS,IAAA,EAAM;AAC9B,MAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,MAAA,IAAI;AACA,QAAA,MAAM,IAAA,GAAO,iBAAiB,KAAA,CAAM,IAAA,EAAM,MAAM,SAAA,EAAW,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,QAAQ,CAAA;AACxF,QAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,cAAA;AACjC,QAAA,MAAM,SAAS,MAAM,gBAAA;AAAA,UACjB,KAAA,CAAM,GAAA;AAAA,UACN,IAAA;AAAA,UACA,MAAA,CAAO,MAAA;AAAA,UACP,KAAA,CAAM,QAAA;AAAA,UACN;AAAA,YACI,OAAO,MAAA,EAAQ,QAAA;AAAA,YACf,QAAQ,MAAA,EAAQ,SAAA;AAAA,YAChB,KAAA,EAAO,QAAQ,QAAA,IAAY;AAAA,WAC/B;AAAA,UACA;AAAA,SACJ;AACA,QAAA,IAAI,CAAC,OAAO,YAAA,EAAc;AACtB,UAAA,OAAA,GAAU;AAAA,YACN,MAAA,EAAQ,WAAA;AAAA,YACR,SAAS,CAAA,2CAAA,EAA8C,IAAA,CAAK,MAAM,MAAA,CAAO,IAAA,GAAO,IAAI,CAAC,CAAA,IAAA;AAAA,WACxF,CAAA;AAAA,QACL;AACA,QAAA,MAAM,EAAC,YAAA,EAAc,QAAA,EAAU,GAAG,SAAO,GAAI,MAAA;AAC7C,QAAA,MAAA,GAAS,OAAsB,CAAA;AAAA,MACnC,SAAS,KAAA,EAAO;AACZ,QAAA,OAAA,GAAU;AAAA,UACN,MAAA,EAAQ,eAAA;AAAA,UACR,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,SACrD,CAAA;AAAA,MACL,CAAA,SAAE;AACE,QAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,MACjB;AAAA,IAIJ,CAAA,EAAG,CAAC,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,MAAA,CAAO,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAC,CAAA;AAUtE,IAAA,MAAM,QAAA,GAAW,YAAY,YAAoC;AAC7D,MAAA,IAAI,CAAC,KAAA,IAAS,CAAC,SAAS,CAAC,cAAA,IAAkB,OAAO,IAAA;AAClD,MAAA,MAAM,IAAA,GAAO,iBAAiB,KAAA,CAAM,IAAA,EAAM,MAAM,SAAA,EAAW,MAAA,CAAO,MAAA,EAAQ,KAAA,CAAM,QAAQ,CAAA;AACxF,MAAA,MAAM,SAAS,MAAM,gBAAA;AAAA,QACjB,KAAA,CAAM,GAAA;AAAA,QACN,IAAA;AAAA,QACA,MAAA,CAAO,MAAA;AAAA,QACP,KAAA,CAAM,QAAA;AAAA,QACN;AAAA,UACI,OAAO,MAAA,EAAQ,QAAA;AAAA,UACf,QAAQ,MAAA,EAAQ,SAAA;AAAA,UAChB,KAAA,EAAO,QAAQ,QAAA,IAAY;AAAA,SAC/B;AAAA,QACA,QAAQ,MAAA,IAAU;AAAA,OACtB;AACA,MAAA,OAAO,MAAA,CAAO,IAAA;AAAA,IAClB,CAAA,EAAG,CAAC,KAAA,EAAO,KAAA,EAAO,OAAO,MAAA,CAAO,MAAA,EAAQ,MAAM,CAAC,CAAA;AAE/C,IAAA,mBAAA,CAAoB,GAAA,EAAK,OAAO,EAAC,IAAA,EAAM,MAAM,KAAK,IAAA,EAAK,EAAG,QAAA,EAAQ,CAAA,EAAI,CAAC,IAAA,EAAM,QAAQ,CAAC,CAAA;AAMtF,IAAA,MAAM,gBAAA,GAAmB,OAAO,aAAa,CAAA;AAC7C,IAAA,gBAAA,CAAiB,OAAA,GAAU,aAAA;AAC3B,IAAA,SAAA,CAAU,MAAM;AACZ,MAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAA,EAAO;AACtB,MAAA,gBAAA,CAAiB,OAAA,GAAU;AAAA,QACvB,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,UAAU,KAAA,CAAM,QAAA;AAAA,QAChB,QAAQ,EAAC,KAAA,EAAO,MAAM,KAAA,EAAO,MAAA,EAAQ,MAAM,MAAA,EAAM;AAAA,QACjD,QAAA,EAAU,YAAA,CAAa,EAAC,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAM,EAAG,KAAA,CAAM,QAAQ;AAAA,OACpF,CAAA;AAAA,IACL,CAAA,EAAG,CAAC,KAAA,EAAO,KAAA,EAAO,KAAK,CAAC,CAAA;AAGxB,IAAA,MAAM,EAAC,IAAA,EAAM,SAAA,EAAW,QAAA,EAAQ,GAAI,KAAA;AACpC,IAAA,MAAM,QAAA,GAAW,KAAA,GAAQ,YAAA,CAAa,EAAC,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAM,EAAG,QAAQ,CAAA,GAAI,IAAA;AAC9F,IAAA,MAAM,IAAA,GAAO,WAAW,KAAK,CAAA;AAM7B,IAAA,MAAM,YAAY,MAAA,CAAO,QAAA,CAAS,KAAK,GAAG,CAAA,IAAK,KAAK,GAAA,GAAM,CAAA,GACpD,CAAA,EAAG,IAAA,CAAK,MAAO,SAAA,CAAU,KAAA,GAAQ,KAAK,GAAA,GAAO,GAAG,CAAC,CAAA,CAAA,CAAA,GACjD,MAAA;AAUN,IAAA,MAAM,YAAA,GAAe,QAAA,GACf,IAAA,CAAK,GAAA,CAAI,KAAK,KAAA,EAAO,IAAA,CAAK,MAAM,CAAA,GAAI,CAAA,GACpC,MAAA,CAAO,EAAA,CAAG,IAAA,EAAM,gBAAgB,CAAC,CAAA;AAoBvC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,SAAS,KAAA,EAAO,QAAA,CAAS,MAAM,CAAC,CAAA,IAAK,CAAA;AAStE,IAAA,MAAM,WAAA,GAAc,GAAG,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA;AAC7C,IAAA,MAAM,QAAA,GAAW,QACX,iCAAA,GACA,QAAA,GACI,eAAY,WAAW,CAAA,CAAA,GACvB,eAAY,WAAW,CAAA,CAAA;AAGjC,IAAA,MAAM,WAAW,IAAA,CAAK,KAAA,CAAA,CAAO,MAAA,EAAQ,QAAA,IAAY,qBAAqB,IAAI,CAAA;AAG1E,IAAA,MAAM,YAAA,GAAe,WAAW,EAAA,GAAK,GAAA;AACrC,IAAA,MAAM,gBAAgB,QAAA,GAAW,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,MAAM,KAAK,CAAA;AAO5D,IAAA,MAAM,SAAA,GAAY,CAAC,IAAA,EAAc,KAAA,EAAe,OAAA,qBAC5C,IAAA;AAAA,MAAC,SAAA;AAAA,MAAA;AAAA,QACG,OAAA;AAAA,QACA,UAAU,CAAC,KAAA;AAAA,QACX,iBAAA,EAAkB,QAAA;AAAA,QAClB,kBAAA,EAAoB,KAAA;AAAA,QACpB,kBAAA,EAAoB,EAAC,QAAA,EAAU,CAAC,KAAA,EAAK;AAAA,QACrC,OAAO,EAAC,KAAA,EAAO,IAAI,UAAA,EAAY,QAAA,EAAU,KAAK,CAAA,EAAC;AAAA,QAE/C,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,QAAK,KAAA,EAAO;AAAA,YACT,KAAA,EAAO,EAAA;AAAA,YAAI,MAAA,EAAQ,EAAA;AAAA,YAAI,YAAA,EAAc,EAAA;AAAA,YACrC,eAAA,EAAiB,wBAAA;AAAA,YACjB,UAAA,EAAY,QAAA;AAAA,YAAU,cAAA,EAAgB;AAAA,WAC1C,EACI,8BAAC,IAAA,EAAA,EAAK,IAAA,EAAM,MAAe,IAAA,EAAM,EAAA,EAAI,KAAA,EAAM,SAAA,EAAU,CAAA,EACzD,CAAA;AAAA,0BACA,GAAA,CAACC,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,wBAAA,EAAwB,EAC3E,QAAA,EAAA,KAAA,EACL;AAAA;AAAA;AAAA,KACJ;AAGJ,IAAA,uBACI,IAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACG,MAAA;AAAA,QACA,KAAA,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAUH,EAAC,OAAO,MAAA,EAAM;AAAA,UACd,EAAA,CAAG,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAaH,EAAC,iBAAiB,SAAA;AAAS,SAC/B;AAAA,QAMC,QAAA,EAAA;AAAA,UAAA,KAAA,IAAS,IAAA,oBACN,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO;AAAA,YACT,EAAC,YAAY,QAAA,EAAQ;AAAA,YACrB,EAAA,CAAG,MAAA;AAAA,YACH;AAAA,cACI,WAAA,EAAa,EAAA;AAAA,cAAI,YAAA,EAAc,EAAA;AAAA,cAAI,UAAA,EAAY,EAAA;AAAA,cAAI,aAAA,EAAe,EAAA;AAAA,cAClE,iBAAA,EAAmB,CAAA;AAAA,cAAG,GAAA,EAAK;AAAA;AAC/B,WACJ,EACI,QAAA,EAAA;AAAA,4BAAA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,CAAC,EAAA,CAAG,OAAO,EAAC,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,SAAA,EAAU,GACxE,QAAA,EAAA,KAAA,EACL,CAAA;AAAA,4BACA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,SAAA,EAAW,CAAA,EAAG,QAAA,EAAU,EAAA,EAAI,KAAA,EAAO,uBAAA,EAAuB,EACrE,QAAA,EAAA,QAAA,EACL;AAAA,WAAA,EACJ,CAAA;AAAA,+BAMH,IAAA,EAAA,EAAK,KAAA,EAAO,CAAC,EAAA,CAAG,SAAS,EAAC,WAAA,EAAa,CAAA,EAAG,YAAA,EAAc,GAAG,UAAA,EAAY,CAAA,EAAG,aAAA,EAAe,CAAA,EAAE,CAAA,EAKxF,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,UAAA,EAAA,EAAW,SAAS,QAAA,EACrB,QAAA,kBAAA,IAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBACG,GAAA,EAAK,QAAA;AAAA,gBACL,QAAA,EAAU,aAAA;AAAA,gBAMT,GAAI,QAAA,GAAW,aAAA,CAAc,WAAA,GAAc,SAAA,CAAU,WAAA;AAAA,gBACtD,KAAA,EAAO;AAAA,kBACH,EAAC,KAAA,EAAO,MAAA,EAAQ,WAAA,EAAa,mBAAA,EAAqB,UAAU,QAAA,EAAQ;AAAA,kBACpE,EAAA,CAAG;AAAA,iBACP;AAAA,gBAEC,QAAA,EAAA;AAAA,kBAAA,KAAA,IAAS,SAAS,QAAA,oBACf,GAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBACG,MAAA,EAAQ,EAAC,GAAA,EAAK,KAAA,CAAM,GAAA,EAAG;AAAA,sBAKvB,UAAA,EAAW,SAAA;AAAA,sBACX,KAAA,EAAO;AAAA,wBACH,QAAA,EAAU,UAAA;AAAA,wBACV,MAAM,SAAA,CAAU,CAAA;AAAA,wBAChB,KAAK,SAAA,CAAU,CAAA;AAAA,wBACf,KAAA,EAAO,QAAA,CAAS,KAAA,GAAQ,SAAA,CAAU,KAAA;AAAA,wBAClC,MAAA,EAAQ,QAAA,CAAS,MAAA,GAAS,SAAA,CAAU,KAAA;AAAA,wBACpC,WAAW,CAAC,EAAC,QAAQ,CAAA,EAAG,QAAQ,OAAM;AAAA;AAC1C;AAAA,mBACJ;AAAA,kBAAA,CAGF,CAAC,MAAA,IAAU,KAAA,qBACT,IAAA,CAAC,QAAK,KAAA,EAAO;AAAA,oBACT;AAAA,sBACI,QAAA,EAAU,UAAA;AAAA,sBAAY,IAAA,EAAM,EAAA;AAAA,sBAAI,GAAA,EAAK,EAAA;AAAA,sBAAI,KAAA,EAAO,EAAA;AAAA,sBAAI,MAAA,EAAQ,EAAA;AAAA,sBAC5D,UAAA,EAAY,QAAA;AAAA,sBAAU,cAAA,EAAgB;AAAA,qBAC1C;AAAA,oBACA,EAAA,CAAG,QAAA;AAAA,oBACH,EAAC,cAAc,EAAA;AAAE,mBACrB,EACI,QAAA,EAAA;AAAA,oCAAA,GAAA,CAAC,QAAK,KAAA,EAAO;AAAA,sBACT,KAAA,EAAO,EAAA;AAAA,sBAAI,MAAA,EAAQ,EAAA;AAAA,sBAAI,YAAA,EAAc,EAAA;AAAA,sBACrC,eAAA,EAAiB,uBAAA;AAAA,sBACjB,UAAA,EAAY,QAAA;AAAA,sBAAU,cAAA,EAAgB;AAAA,qBAC1C,EACI,8BAAC,IAAA,EAAA,EAAK,IAAA,EAAM,SAAkB,IAAA,EAAM,EAAA,EAAI,KAAA,EAAO,gBAAA,EAAkB,CAAA,EACrE,CAAA;AAAA,oCACA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,UAAU,EAAA,EAAI,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,SAAA,EAAW,SAAA,EAAW,QAAA,EAAQ,EACjF,eAAK,QAAA,EACV,CAAA;AAAA,oCACA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,QAAA,EAAU,IAAA,EAAM,KAAA,EAAO,uBAAA,EAAyB,SAAA,EAAW,QAAA,EAAQ,EAAG,QAAA,EAAA,kBAAA,EAEtF,CAAA;AAAA,oBACC,KAAA,oBACG,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO;AAAA,sBACX,QAAA,EAAU,IAAA;AAAA,sBAAM,UAAA,EAAY,KAAA;AAAA,sBAC5B,KAAA,EAAO,WAAA;AAAA,sBAAa,SAAA,EAAW;AAAA,qBACnC,EACK,gBAAM,OAAA,EACX;AAAA,mBAAA,EAER,CAAA;AAAA,kBAGH,yBACG,IAAA,CAAA,QAAA,EAAA,EACI,QAAA,EAAA;AAAA,oCAAA,GAAA;AAAA,sBAAC,IAAA;AAAA,sBAAA;AAAA,wBACG,aAAA,EAAc,MAAA;AAAA,wBACd,KAAA,EAAO;AAAA,0BACH;AAAA,4BACI,QAAA,EAAU,UAAA;AAAA,4BACV,IAAA,EAAM,KAAK,CAAA,GAAI,KAAA;AAAA,4BACf,GAAA,EAAK,KAAK,CAAA,GAAI,KAAA;AAAA,4BACd,KAAA,EAAO,IAAA,CAAK,KAAA,GAAQ,KAAA,GAAQ,CAAA;AAAA,4BAC5B,MAAA,EAAQ,IAAA,CAAK,MAAA,GAAS,KAAA,GAAQ,CAAA;AAAA,4BAC9B,WAAA,EAAa,KAAA;AAAA,4BACb,WAAA,EAAc,EAAA,CAAG,KAAA,EAAO,eAAA,IAA8B,iBAAA;AAAA,4BACtD,cAAc,YAAA,GAAe;AAAA;AACjC;AACJ;AAAA,qBACJ;AAAA,oCACA,GAAA;AAAA,sBAAC,IAAA;AAAA,sBAAA;AAAA,wBACG,aAAA,EAAc,MAAA;AAAA,wBACd,KAAA,EAAO;AAAA,0BACH;AAAA,4BACI,QAAA,EAAU,UAAA;AAAA,4BACV,MAAM,IAAA,CAAK,CAAA;AAAA,4BAAG,KAAK,IAAA,CAAK,CAAA;AAAA,4BACxB,OAAO,IAAA,CAAK,KAAA;AAAA,4BAAO,QAAQ,IAAA,CAAK,MAAA;AAAA,4BAChC,WAAA,EAAa;AAAA,2BACjB;AAAA,0BACA,EAAA,CAAG,UAAA;AAAA,0BACH,EAAC,cAAc,YAAA;AAAY,yBAC/B;AAAA,wBAEC,QAAA,EAAA,CAAC,QAAA,IAAY,CAAC,CAAA,EAAG,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,qBACtB,IAAA,CAAC,KAAA,CAAM,QAAA,EAAN,EACG,QAAA,EAAA;AAAA,0CAAA,GAAA,CAAC,QAAK,KAAA,EAAO;AAAA,4BACT;AAAA,8BAAC,QAAA,EAAU,UAAA;AAAA,8BAAY,GAAA,EAAK,CAAA;AAAA,8BAAG,MAAA,EAAQ,CAAA;AAAA,8BAAG,KAAA,EAAO,CAAA;AAAA,8BAChD,IAAA,EAAO,IAAA,CAAK,KAAA,GAAQ,CAAA,GAAK;AAAA,6BAAC;AAAA,4BAC3B,EAAA,CAAG;AAAA,2BACP,EAAG,CAAA;AAAA,0CACH,GAAA,CAAC,QAAK,KAAA,EAAO;AAAA,4BACT;AAAA,8BAAC,QAAA,EAAU,UAAA;AAAA,8BAAY,IAAA,EAAM,CAAA;AAAA,8BAAG,KAAA,EAAO,CAAA;AAAA,8BAAG,MAAA,EAAQ,CAAA;AAAA,8BACjD,GAAA,EAAM,IAAA,CAAK,MAAA,GAAS,CAAA,GAAK;AAAA,6BAAC;AAAA,4BAC3B,EAAA,CAAG;AAAA,2BACP,EAAG;AAAA,yBAAA,EAAA,EAVc,CAWrB,CACH;AAAA;AAAA,qBACL;AAAA,oCAWA,GAAA;AAAA,sBAAC,IAAA;AAAA,sBAAA;AAAA,wBACG,aAAA,EAAc,MAAA;AAAA,wBACd,KAAA,EAAO,EAAC,QAAA,EAAU,UAAA,EAAY,GAAA,EAAK,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,UAAA,EAAY,QAAA,EAAQ;AAAA,wBAElF,QAAA,kBAAA,GAAA;AAAA,0BAAC,IAAA;AAAA,0BAAA;AAAA,4BACG,KAAA,EAAO;AAAA,8BACH,EAAC,UAAA,EAAY,QAAA,EAAU,cAAA,EAAgB,QAAA,EAAQ;AAAA,8BAC/C,EAAA,CAAG;AAAA,6BACP;AAAA,4BAEA,QAAA,kBAAA,GAAA,CAACA,QAAO,KAAA,EAAO;AAAA,8BACX,KAAA,EAAQ,EAAA,CAAG,QAAA,EAAU,KAAA,IAAgC,SAAA;AAAA,8BACrD,QAAA,EAAU,IAAA;AAAA,8BACV,UAAA,EAAY;AAAA,+BAEX,QAAA,EAAA,SAAA,EACL;AAAA;AAAA;AACJ;AAAA;AACA,mBAAA,EACJ,CAAA;AAAA,kBAAA,CAOF,WAAW,IAAA,qBACT,IAAA;AAAA,oBAAC,IAAA;AAAA,oBAAA;AAAA,sBACG,aAAA,EAAc,MAAA;AAAA,sBACd,KAAA,EAAO;AAAA,wBACH,QAAA,EAAU,UAAA;AAAA,wBAAY,IAAA,EAAM,CAAA;AAAA,wBAAG,GAAA,EAAK,CAAA;AAAA,wBAAG,KAAA,EAAO,CAAA;AAAA,wBAAG,MAAA,EAAQ,CAAA;AAAA,wBACzD,eAAA,EAAiB,oBAAA;AAAA,wBACjB,UAAA,EAAY,QAAA;AAAA,wBAAU,cAAA,EAAgB,QAAA;AAAA,wBAAU,GAAA,EAAK;AAAA,uBACzD;AAAA,sBAEA,QAAA,EAAA;AAAA,wCAAA,GAAA;AAAA,0BAAC,iBAAA;AAAA,0BAAA;AAAA,4BACG,IAAA,EAAK,OAAA;AAAA,4BACL,KAAA,EAAQ,EAAA,CAAG,YAAA,EAAc,eAAA,IAA0C;AAAA;AAAA,yBACvE;AAAA,wBACC,IAAA,oBACG,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,SAAA,EAAS,EAC5D,eAAK,UAAA,EACV;AAAA;AAAA;AAAA;AAER;AAAA;AAAA,aAER,EACA,CAAA;AAAA,4BAIA,IAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBACG,aAAA,EAAe,QAAQ,MAAA,GAAS,MAAA;AAAA,gBAChC,KAAA,EAAO;AAAA,kBACH,UAAA,EAAY,EAAA;AAAA,kBAAI,WAAA,EAAa,EAAA;AAAA,kBAAI,YAAA,EAAc,EAAA;AAAA,kBAC/C,GAAA,EAAK,EAAA;AAAA,kBAAI,OAAA,EAAS,QAAQ,CAAA,GAAI;AAAA,iBAClC;AAAA,gBAEA,QAAA,EAAA;AAAA,kCAAA,IAAA,CAAC,IAAA,EAAA,EAAK,OAAO,EAAC,aAAA,EAAe,OAAO,UAAA,EAAY,QAAA,EAAU,GAAA,EAAK,EAAA,EAAE,EAC5D,QAAA,EAAA;AAAA,oBAAA,CAAC,WAAA,IAAe,SAAS,KAAA,IAAS,QAAA;AAAA;AAAA;AAAA,oCAI/B,GAAA;AAAA,sBAAC,IAAA;AAAA,sBAAA;AAAA,wBACG,KAAA,EAAO;AAAA,0BACH,EAAC,KAAA,EAAO,YAAA,EAAc,MAAA,EAAQ,aAAA,EAAe,UAAU,QAAA,EAAQ;AAAA,0BAC/D,EAAA,CAAG,YAAA;AAAA,0BACH,QAAA,GAAW,EAAC,YAAA,EAAc,YAAA,GAAe,GAAC,GAAI,IAAA;AAAA;AAAA;AAAA;AAAA,0BAI9C,EAAC,aAAa,CAAA,EAAC;AAAA;AAAA;AAAA,0BAGf;AAAA,4BACI,WAAA,EAAa,SAAA;AAAA,4BACb,aAAA,EAAe,IAAA;AAAA,4BACf,YAAA,EAAc,EAAA;AAAA,4BACd,YAAA,EAAc,EAAC,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,EAAC;AAAA,4BAClC,SAAA,EAAW;AAAA;AACf,yBACJ;AAAA,wBAEA,QAAA,kBAAA,GAAA;AAAA,0BAAC,KAAA;AAAA,0BAAA;AAAA,4BACG,MAAA,EAAQ,EAAC,GAAA,EAAK,KAAA,CAAM,GAAA,EAAG;AAAA,4BACvB,UAAA,EAAW,SAAA;AAAA,4BACX,KAAA,EAAO;AAAA,8BACH,QAAA,EAAU,UAAA;AAAA,8BACV,OAAO,QAAA,CAAS,KAAA,GAAQ,SAAA,CAAU,KAAA,IAAS,eAAe,IAAA,CAAK,KAAA,CAAA;AAAA,8BAC/D,QAAQ,QAAA,CAAS,MAAA,GAAS,SAAA,CAAU,KAAA,IAAS,eAAe,IAAA,CAAK,KAAA,CAAA;AAAA,8BACjE,OAAO,SAAA,CAAU,CAAA,GAAI,IAAA,CAAK,CAAA,KAAM,eAAe,IAAA,CAAK,KAAA,CAAA;AAAA,8BACpD,MAAM,SAAA,CAAU,CAAA,GAAI,IAAA,CAAK,CAAA,KAAM,eAAe,IAAA,CAAK,KAAA,CAAA;AAAA,8BACnD,WAAW,CAAC,EAAC,QAAQ,CAAA,EAAG,QAAQ,OAAM;AAAA;AAC1C;AAAA;AACJ;AAAA,qBACJ;AAAA,oCAEJ,IAAA,CAAC,QAAK,KAAA,EAAO,EAAC,MAAM,CAAA,EAAG,UAAA,EAAY,YAAU,EACzC,QAAA,EAAA;AAAA,sCAAA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,QAAA,EAAU,EAAA,EAAI,YAAY,KAAA,EAAO,KAAA,EAAO,SAAA,EAAS,EAC5D,QAAA,EAAA,SAAA,EACL,CAAA;AAAA,sCACA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,SAAA,EAAW,CAAA,EAAG,QAAA,EAAU,IAAA,EAAM,KAAA,EAAO,uBAAA,EAAuB,EACvE,QAAA,EAAA,CAAA,MAAA,EAAS,QAAQ,CAAA,GAAA,CAAA,EACtB;AAAA,qBAAA,EACJ;AAAA,mBAAA,EACJ,CAAA;AAAA,kCAEA,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,EAAC,aAAA,EAAe,OAAO,UAAA,EAAY,QAAA,EAAU,GAAA,EAAK,EAAA,EAAE,EAC5D,QAAA,EAAA;AAAA,oBAAA,SAAA,CAAU,WAAA,EAAa,KAAK,MAAA,EAAQ,MAAM,SAAS,EAAC,IAAA,EAAM,QAAA,EAAS,CAAC,CAAA;AAAA,oCACrE,GAAA;AAAA,sBAAC,MAAA;AAAA,sBAAA;AAAA,wBACG,KAAA,EAAO,EAAC,IAAA,EAAM,CAAA,EAAC;AAAA,wBACf,YAAA,EAAc,CAAA;AAAA,wBACd,YAAA,EAAc,CAAA;AAAA,wBACd,KAAA,EAAO,aAAa,KAAK,CAAA;AAAA,wBACzB,UAAU,CAAC,KAAA;AAAA,wBACX,qBAAA,EAAuB,GAAG,KAAA,EAAO,eAAA;AAAA,wBACjC,qBAAA,EAAuB,GAAG,KAAA,EAAO,eAAA;AAAA,wBACjC,cAAA,EAAgB,GAAG,KAAA,EAAO,eAAA;AAAA,wBAC1B,aAAA,EAAe,CAAC,KAAA,KAAU,QAAA,CAAS,EAAC,IAAA,EAAM,SAAA,EAAW,OAAM;AAAA;AAAA,qBAC/D;AAAA,oBACC,SAAA,CAAU,YAAA,EAAc,IAAA,CAAK,KAAA,EAAO,MAAM,SAAS,EAAC,IAAA,EAAM,OAAA,EAAQ,CAAC;AAAA,mBAAA,EACxE;AAAA;AAAA;AAAA;AACJ,WAAA,EACJ,CAAA;AAAA,UAEC,CAAC,UAAA,oBACF,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO;AAAA,YACT,EAAC,aAAA,EAAe,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,WAAW,MAAA,EAAM;AAAA,YAC9D,EAAA,CAAG,MAAA;AAAA,YACH;AAAA,cACI,WAAA,EAAa,EAAA;AAAA,cAAI,YAAA,EAAc,EAAA;AAAA,cAAI,UAAA,EAAY,EAAA;AAAA,cAAI,aAAA,EAAe,EAAA;AAAA,cAClE,cAAA,EAAgB,CAAA;AAAA,cAAG,cAAA,EAAgB,wBAAA;AAAA,cAA0B,GAAA,EAAK;AAAA;AACtE,WACJ,EACI,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,SAAA;AAAA,cAAA;AAAA,gBACG,OAAA,EAAS,MAAM,QAAA,IAAW;AAAA,gBAC1B,iBAAA,EAAkB,QAAA;AAAA,gBAClB,oBAAoB,IAAA,CAAK,MAAA;AAAA,gBACzB,KAAA,EAAO;AAAA,kBACH,IAAA,EAAM,CAAA;AAAA,kBAAG,MAAA,EAAQ,EAAA;AAAA,kBAAI,YAAA,EAAc,EAAA;AAAA,kBACnC,eAAA,EAAiB,uBAAA;AAAA,kBACjB,UAAA,EAAY,QAAA;AAAA,kBAAU,cAAA,EAAgB;AAAA,iBAC1C;AAAA,gBAEA,QAAA,kBAAA,GAAA,CAACA,IAAA,EAAA,EAAO,KAAA,EAAO,EAAC,QAAA,EAAU,EAAA,EAAI,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,SAAA,EAAS,EAC5D,QAAA,EAAA,IAAA,CAAK,MAAA,EACV;AAAA;AAAA,aACJ;AAAA,4BAIA,GAAA;AAAA,cAAC,SAAA;AAAA,cAAA;AAAA,gBACG,OAAA,EAAS,MAAM,KAAK,IAAA,EAAK;AAAA,gBACzB,UAAU,CAAC,OAAA;AAAA,gBACX,iBAAA,EAAkB,QAAA;AAAA,gBAClB,oBAAoB,IAAA,CAAK,IAAA;AAAA,gBACzB,kBAAA,EAAoB,EAAC,QAAA,EAAU,CAAC,OAAA,EAAO;AAAA,gBACvC,KAAA,EAAO;AAAA,kBACH,IAAA,EAAM,GAAA;AAAA,kBAAK,MAAA,EAAQ,EAAA;AAAA,kBAAI,YAAA,EAAc,EAAA;AAAA,kBACrC,eAAA,EAAiB,UAAU,WAAA,GAAc,uBAAA;AAAA,kBACzC,UAAA,EAAY,QAAA;AAAA,kBAAU,cAAA,EAAgB;AAAA,iBAC1C;AAAA,gBAEA,QAAA,kBAAA,GAAA,CAACA,QAAO,KAAA,EAAO;AAAA,kBACX,QAAA,EAAU,EAAA;AAAA,kBAAI,UAAA,EAAY,KAAA;AAAA,kBAC1B,KAAA,EAAO,UAAU,SAAA,GAAY;AAAA,iBACjC,EACK,QAAA,EAAA,IAAA,GAAO,IAAA,CAAK,UAAA,GAAa,KAAK,IAAA,EACnC;AAAA;AAAA;AACJ,WAAA,EACJ;AAAA;AAAA;AAAA,KAEJ;AAAA,EAER;AAAC;;;;"}
|
|
@@ -61,6 +61,7 @@ require('yup');
|
|
|
61
61
|
require('../../packages/types/src/Css/map/index.cjs');
|
|
62
62
|
require('../../packages/types/src/Theme/shadows.cjs');
|
|
63
63
|
require('../../packages/types/src/Theme/defaultTheme.cjs');
|
|
64
|
+
require('../../packages/types/src/Theme/resolvers.cjs');
|
|
64
65
|
require('../../packages/types/src/Theme/alphaColors.cjs');
|
|
65
66
|
require('../../apps/mobile/src/Factory/helpers/cssVarMap.cjs');
|
|
66
67
|
require('i18next');
|
|
@@ -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 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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"}
|
|
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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"}
|
|
@@ -59,6 +59,7 @@ import 'yup';
|
|
|
59
59
|
import '../../packages/types/src/Css/map/index.js';
|
|
60
60
|
import '../../packages/types/src/Theme/shadows.js';
|
|
61
61
|
import '../../packages/types/src/Theme/defaultTheme.js';
|
|
62
|
+
import '../../packages/types/src/Theme/resolvers.js';
|
|
62
63
|
import '../../packages/types/src/Theme/alphaColors.js';
|
|
63
64
|
import '../../apps/mobile/src/Factory/helpers/cssVarMap.js';
|
|
64
65
|
import 'i18next';
|
|
@@ -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 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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"}
|
|
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYO,SAAS,gBAAgB,QAAA,EAAiC;AAC7D,EAAA,MAAM,KAAA,GAAQ,oBAAA,CAA4C,iBAAA,EAAmB,QAAQ,CAAA,CAAE,WAAA;AACvF,EAAA,MAAM,EAAC,KAAA,EAAO,YAAA,EAAc,QAAQ,QAAA,EAAU,WAAA,GAAc,iBAAY,YAAA,EAAc,WAAA,GAAc,OAAA,EAAS,MAAA,EAAQ,aAAa,cAAA,EAAgB,UAAA,EAAY,mBAAmB,SAAA,EAAW,QAAA,EAAU,QAAM,GAAI,KAAA;AAEhN,EAAA,MAAM,MAAA,GAAS,2BAA2B,WAAW,CAAA;AACrD,EAAA,MAAM,OAAA,GAAU,2BAA2B,cAAc,CAAA;AACzD,EAAA,MAAM,MAAA,GAAS,2BAA2B,gBAAgB,CAAA;AAC1D,EAAA,MAAM,OAAA,GAAU,2BAA2B,UAAU,CAAA;AACrD,EAAA,MAAM,SAAA,GAAY,2BAA2B,MAAM,CAAA;AACnD,EAAA,MAAM,KAAA,GAAQ,2BAA2B,gBAAgB,CAAA;AACzD,EAAA,MAAM,UAAA,GAAa,2BAA2B,UAAU,CAAA;AAiBxD,EAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,MAAA,EAAW,EAAE,CAAA;AACpD,EAAA,MAAM,WAAA,GAAc,gBAAA,CAAiB,MAAA,EAAW,EAAE,CAAA;AAElD,EAAA,IAAI,MAAA,EAAQ;AACR,IAAA,uBACI,GAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACG,MAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACH,aAAA,EAAe,KAAA;AAAA,UACf,UAAA,EAAY,QAAA;AAAA,UACZ,iBAAA,EAAmB,EAAA;AAAA,UACnB,eAAA,EAAiB,EAAA;AAAA,UACjB,eAAA,EAAiB,OAAA;AAAA,UACjB,cAAA,EAAgB,CAAA;AAAA,UAChB,cAAA,EAAgB;AAAA,SACpB;AAAA,QAEA,QAAA,kBAAA,IAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YACG,KAAA,EAAO;AAAA,cACH,QAAA,EAAU,CAAA;AAAA,cACV,aAAA,EAAe,KAAA;AAAA,cACf,UAAA,EAAY,QAAA;AAAA,cACZ,GAAA,EAAK,EAAA;AAAA,cACL,eAAA,EAAiB,OAAA;AAAA,cACjB,WAAA,EAAa,CAAA;AAAA,cACb,WAAA,EAAa,MAAA;AAAA,cACb,YAAA,EAAc,GAAA;AAAA,cACd,iBAAA,EAAmB,EAAA;AAAA,cACnB,eAAA,EAAiB;AAAA,aACrB;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,QAAK,IAAA,EAAK,MAAA,EAAO,IAAA,EAAM,EAAA,EAAI,OAAO,KAAA,EAAO,CAAA;AAAA,cACzC,WAAA,IAAe,wBAAQ,GAAA,CAAC,IAAA,EAAA,EAAK,OAAO,EAAC,QAAA,EAAU,IAAI,KAAA,EAAO,KAAA,EAAO,GAAI,aAAA,IAAiB,IAAA,GAAO,EAAC,UAAA,EAAY,aAAA,KAAiB,EAAC,IAAM,QAAA,EAAA,WAAA,EAAY;AAAA;AAAA;AAAA;AACnJ;AAAA,KACJ;AAAA,EAER;AAEA,EAAA,MAAM,OAAA,GAAU,gBAAgB,IAAA,GAAO,CAAC,eAAe,KAAA,CAAM,IAAA,GAAO,MAAA,GAAS,CAAA;AAQ7E,EAAA,MAAM,KAAA,mBACF,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACG,GAAA,EAAK,QAAA;AAAA,MACL,KAAA,EAAO;AAAA,QACH,IAAA,EAAM,CAAA;AAAA,QACN,eAAA,EAAiB,OAAA;AAAA,QACjB,YAAA,EAAc,EAAA;AAAA,QACd,iBAAA,EAAmB,EAAA;AAAA,QACnB,eAAA,EAAiB,CAAA;AAAA,QACjB,QAAA,EAAU,EAAA;AAAA,QACV,KAAA,EAAO,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMP,SAAA,EAAW,EAAA;AAAA,QACX,SAAA,EAAW;AAAA,OACf;AAAA,MACA,WAAA;AAAA,MACA,oBAAA,EAAsB,KAAA;AAAA,MACtB,KAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,mBACI,iBAAA,GACM,CAAA,CAAA,KAAK,iBAAA,CAAkB,EAAC,OAAO,CAAA,CAAE,WAAA,CAAY,SAAA,CAAU,KAAA,EAAO,KAAK,CAAA,CAAE,WAAA,CAAY,SAAA,CAAU,GAAA,EAAI,CAAA,GAC/F,MAAA;AAAA,MAEV,SAAA,EAAS;AAAA;AAAA,GACb;AAGJ,EAAA,MAAM,OAAA,mBACF,GAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACG,OAAA,EAAS,MAAM,OAAA,IAAW,MAAA,IAAS;AAAA,MACnC,UAAU,CAAC,OAAA;AAAA,MACX,iBAAA,EAAkB,QAAA;AAAA,MAClB,kBAAA,EAAmB,MAAA;AAAA,MACnB,KAAA,EAAO;AAAA,QACH,KAAA,EAAO,EAAA;AAAA,QACP,MAAA,EAAQ,EAAA;AAAA,QACR,YAAA,EAAc,EAAA;AAAA,QACd,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,QAAA;AAAA,QAChB,eAAA,EAAiB,UAAU,MAAA,GAAS;AAAA,OACxC;AAAA,MAEA,8BAAC,IAAA,EAAA,EAAK,IAAA,EAAK,QAAO,IAAA,EAAM,EAAA,EAAI,OAAM,SAAA,EAAU;AAAA;AAAA,GAChD;AAGJ,EAAA,IAAI,cAAA,EAAgB;AAChB,IAAA,uBACI,IAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACG,MAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACH,eAAA,EAAiB,EAAA;AAAA,UACjB,eAAA,EAAiB,OAAA;AAAA,UACjB,cAAA,EAAgB,CAAA;AAAA,UAChB,cAAA,EAAgB;AAAA,SACpB;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,UAAA,IAAc,IAAA,oBACX,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,EAAC,aAAA,EAAe,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,KAAK,CAAA,EAAG,iBAAA,EAAmB,EAAA,EAAI,aAAA,EAAe,GAAC,EACrG,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,QAAK,IAAA,EAAK,MAAA,EAAO,IAAA,EAAM,EAAA,EAAI,OAAO,KAAA,EAAO,CAAA;AAAA,gCACzC,IAAA,EAAA,EAAK,KAAA,EAAO,EAAC,QAAA,EAAU,EAAA,EAAI,OAAO,KAAA,EAAO,GAAI,WAAA,IAAe,IAAA,GAAO,EAAC,UAAA,EAAY,WAAA,KAAe,EAAC,IAAM,QAAA,EAAA,UAAA,EAAW;AAAA,WAAA,EACtH,CAAA;AAAA,0BAEJ,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,EAAC,aAAA,EAAe,KAAA,EAAO,UAAA,EAAY,UAAA,EAAY,GAAA,EAAK,CAAA,EAAG,iBAAA,EAAmB,EAAA,EAAE,EACpF,QAAA,EAAA;AAAA,YAAA,QAAA,IAAY,IAAA,oBACT,GAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,EAAC,OAAO,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,UAAA,EAAY,QAAA,EAAU,cAAA,EAAgB,UAAU,OAAA,EAAS,GAAA,EAAG,EAC7F,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAK,aAAY,IAAA,EAAM,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,CAAA,EACnD,CAAA;AAAA,YAEH,KAAA;AAAA,YACA;AAAA,WAAA,EACL;AAAA;AAAA;AAAA,KACJ;AAAA,EAER;AAEA,EAAA,uBACI,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACG,MAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACH,aAAA,EAAe,KAAA;AAAA,QACf,UAAA,EAAY,UAAA;AAAA,QACZ,GAAA,EAAK,CAAA;AAAA,QACL,iBAAA,EAAmB,EAAA;AAAA,QACnB,eAAA,EAAiB,EAAA;AAAA,QACjB,eAAA,EAAiB,OAAA;AAAA,QACjB,cAAA,EAAgB,CAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,OACpB;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,QAAA,IAAY,IAAA,oBACT,GAAA;AAAA,UAAC,gBAAA;AAAA,UAAA;AAAA,YACG,OAAA,EAAS,QAAA;AAAA,YACT,iBAAA,EAAkB,QAAA;AAAA,YAClB,kBAAA,EAAmB,QAAA;AAAA,YACnB,KAAA,EAAO,EAAC,KAAA,EAAO,EAAA,EAAI,QAAQ,EAAA,EAAI,UAAA,EAAY,QAAA,EAAU,cAAA,EAAgB,QAAA,EAAQ;AAAA,YAE7E,8BAAC,IAAA,EAAA,EAAK,IAAA,EAAK,aAAY,IAAA,EAAM,EAAA,EAAI,OAAO,KAAA,EAAO;AAAA;AAAA,SACnD;AAAA,QAEH,KAAA;AAAA,QACA;AAAA;AAAA;AAAA,GACL;AAER;;;;"}
|
|
@@ -61,6 +61,7 @@ require('yup');
|
|
|
61
61
|
require('../../packages/types/src/Css/map/index.cjs');
|
|
62
62
|
require('../../packages/types/src/Theme/shadows.cjs');
|
|
63
63
|
require('../../packages/types/src/Theme/defaultTheme.cjs');
|
|
64
|
+
require('../../packages/types/src/Theme/resolvers.cjs');
|
|
64
65
|
require('../../packages/types/src/Theme/alphaColors.cjs');
|
|
65
66
|
require('../../apps/mobile/src/Factory/helpers/cssVarMap.cjs');
|
|
66
67
|
var useSeparator = require('../../apps/mobile/src/Factory/useSeparator.cjs');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../../src/components/SegmentedControl/index.tsx"],"sourcesContent":["import React, {useMemo} from \"react\";\nimport type {ISegmentedControlProps} from \"@lmb-it/kitsconcerto-types\";\nimport {ResponsiveElement, useSeparator} from \"../../factory\";\nimport {useComponentDefaults} from \"../../hooks\";\nimport {useKitsTheme} from \"../../contexts/Theme\";\n\nconst SIZE_MAP = {\n sm: {height: 30, fontSize: 11, px: 8, py: 4, descSize: 9.5, gap: 2},\n md: {height: 36, fontSize: 12.5, px: 12, py: 6, descSize: 10.5, gap: 4},\n lg: {height: 44, fontSize: 14, px: 16, py: 10, descSize: 11, gap: 4},\n} as const;\n\nexport function SegmentedControl<V extends string | number = string>(rawProps: ISegmentedControlProps<V>) {\n const {mergedProps: props, themeStyle} = useComponentDefaults<ISegmentedControlProps<V>>(\n \"SegmentedControl\",\n rawProps as any,\n );\n\n const {\n options,\n value,\n onChange,\n size = \"md\",\n fullWidth = true,\n disabled,\n id,\n testID,\n ...rest\n } = props;\n\n const {cssProps, nativeProps} = useSeparator<HTMLDivElement>(rest as any);\n const {resolveToken} = useKitsTheme();\n const sizeConfig = SIZE_MAP[size] ?? SIZE_MAP.md;\n\n const trackBg = resolveToken(\"surface-ground\");\n const borderColor = resolveToken(\"surface-border\");\n const inactiveText = resolveToken(\"text-secondary\");\n\n const containerCss = useMemo(\n () => ({\n ...themeStyle,\n ...cssProps,\n display: \"inline-flex\" as const,\n flexDirection: \"row\" as const,\n alignItems: \"stretch\" as const,\n gap: 2,\n padding: 2,\n backgroundColor: trackBg,\n border: `1px solid ${borderColor}`,\n borderRadius: 8,\n ...(fullWidth ? {width: \"100%\"} : {}),\n ...(disabled ? {opacity: \"0.55\", pointerEvents: \"none\" as const} : {}),\n }),\n [themeStyle, cssProps, trackBg, borderColor, fullWidth, disabled],\n );\n\n return (\n <ResponsiveElement\n as=\"Box\"\n //@ts-ignore\n cssProps={containerCss}\n nativeProps={{...nativeProps, id, \"data-testid\": testID, role: \"tablist\"}}\n additionalStyles={{}}\n >\n {options.map(opt => {\n const selected = opt.value === value;\n const isDisabled = disabled || opt.disabled;\n const accent = opt.color ? resolveToken(opt.color) : resolveToken(\"primary\");\n\n const buttonCss = {\n flex: fullWidth ? 1 : undefined,\n minHeight: sizeConfig.height,\n paddingLeft: sizeConfig.px,\n paddingRight: sizeConfig.px,\n paddingTop: sizeConfig.py,\n paddingBottom: sizeConfig.py,\n borderRadius: 6,\n border: \"none\",\n cursor: isDisabled ? \"not-allowed\" : \"pointer\",\n background: selected ? accent : \"transparent\",\n color: selected ? \"#FFFFFF\" : inactiveText,\n fontFamily: \"inherit\",\n fontWeight: \"700\",\n fontSize: sizeConfig.fontSize,\n lineHeight: \"1.1\",\n transition: \"background-color 0.15s, color 0.15s, box-shadow 0.15s\",\n boxShadow: selected ? \"0 1px 2px rgba(0,0,0,0.06)\" : \"none\",\n outline: \"none\",\n display: \"flex\",\n flexDirection: \"column\" as const,\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: sizeConfig.gap,\n textAlign: \"center\" as const,\n };\n\n return (\n <button\n key={String(opt.value)}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n disabled={isDisabled}\n onClick={() => !isDisabled && onChange(opt.value)}\n style={buttonCss as any}\n >\n <span style={{lineHeight: \"1.1\"}}>{opt.label}</span>\n {opt.description && (\n <span\n style={{\n fontSize: sizeConfig.descSize,\n fontWeight: 600,\n opacity: selected ? 0.85 : 0.7,\n }}\n >\n {opt.description}\n </span>\n )}\n </button>\n );\n })}\n </ResponsiveElement>\n );\n}\n\nexport default SegmentedControl;\n"],"names":["useComponentDefaults","useSeparator","useKitsTheme","useMemo","jsx","ResponsiveElement","jsxs"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../../src/components/SegmentedControl/index.tsx"],"sourcesContent":["import React, {useMemo} from \"react\";\nimport type {ISegmentedControlProps} from \"@lmb-it/kitsconcerto-types\";\nimport {ResponsiveElement, useSeparator} from \"../../factory\";\nimport {useComponentDefaults} from \"../../hooks\";\nimport {useKitsTheme} from \"../../contexts/Theme\";\n\nconst SIZE_MAP = {\n sm: {height: 30, fontSize: 11, px: 8, py: 4, descSize: 9.5, gap: 2},\n md: {height: 36, fontSize: 12.5, px: 12, py: 6, descSize: 10.5, gap: 4},\n lg: {height: 44, fontSize: 14, px: 16, py: 10, descSize: 11, gap: 4},\n} as const;\n\nexport function SegmentedControl<V extends string | number = string>(rawProps: ISegmentedControlProps<V>) {\n const {mergedProps: props, themeStyle} = useComponentDefaults<ISegmentedControlProps<V>>(\n \"SegmentedControl\",\n rawProps as any,\n );\n\n const {\n options,\n value,\n onChange,\n size = \"md\",\n fullWidth = true,\n disabled,\n id,\n testID,\n ...rest\n } = props;\n\n const {cssProps, nativeProps} = useSeparator<HTMLDivElement>(rest as any);\n const {resolveToken} = useKitsTheme();\n const sizeConfig = SIZE_MAP[size] ?? SIZE_MAP.md;\n\n const trackBg = resolveToken(\"surface-ground\");\n const borderColor = resolveToken(\"surface-border\");\n const inactiveText = resolveToken(\"text-secondary\");\n\n const containerCss = useMemo(\n () => ({\n ...themeStyle,\n ...cssProps,\n display: \"inline-flex\" as const,\n flexDirection: \"row\" as const,\n alignItems: \"stretch\" as const,\n gap: 2,\n padding: 2,\n backgroundColor: trackBg,\n border: `1px solid ${borderColor}`,\n borderRadius: 8,\n ...(fullWidth ? {width: \"100%\"} : {}),\n ...(disabled ? {opacity: \"0.55\", pointerEvents: \"none\" as const} : {}),\n }),\n [themeStyle, cssProps, trackBg, borderColor, fullWidth, disabled],\n );\n\n return (\n <ResponsiveElement\n as=\"Box\"\n //@ts-ignore\n cssProps={containerCss}\n nativeProps={{...nativeProps, id, \"data-testid\": testID, role: \"tablist\"}}\n additionalStyles={{}}\n >\n {options.map(opt => {\n const selected = opt.value === value;\n const isDisabled = disabled || opt.disabled;\n const accent = opt.color ? resolveToken(opt.color) : resolveToken(\"primary\");\n\n const buttonCss = {\n flex: fullWidth ? 1 : undefined,\n minHeight: sizeConfig.height,\n paddingLeft: sizeConfig.px,\n paddingRight: sizeConfig.px,\n paddingTop: sizeConfig.py,\n paddingBottom: sizeConfig.py,\n borderRadius: 6,\n border: \"none\",\n cursor: isDisabled ? \"not-allowed\" : \"pointer\",\n background: selected ? accent : \"transparent\",\n color: selected ? \"#FFFFFF\" : inactiveText,\n fontFamily: \"inherit\",\n fontWeight: \"700\",\n fontSize: sizeConfig.fontSize,\n lineHeight: \"1.1\",\n transition: \"background-color 0.15s, color 0.15s, box-shadow 0.15s\",\n boxShadow: selected ? \"0 1px 2px rgba(0,0,0,0.06)\" : \"none\",\n outline: \"none\",\n display: \"flex\",\n flexDirection: \"column\" as const,\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: sizeConfig.gap,\n textAlign: \"center\" as const,\n };\n\n return (\n <button\n key={String(opt.value)}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n disabled={isDisabled}\n onClick={() => !isDisabled && onChange(opt.value)}\n style={buttonCss as any}\n >\n <span style={{lineHeight: \"1.1\"}}>{opt.label}</span>\n {opt.description && (\n <span\n style={{\n fontSize: sizeConfig.descSize,\n fontWeight: 600,\n opacity: selected ? 0.85 : 0.7,\n }}\n >\n {opt.description}\n </span>\n )}\n </button>\n );\n })}\n </ResponsiveElement>\n );\n}\n\nexport default SegmentedControl;\n"],"names":["useComponentDefaults","useSeparator","useKitsTheme","useMemo","jsx","ResponsiveElement","jsxs"],"mappings":"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"}
|
|
@@ -57,6 +57,7 @@ import 'yup';
|
|
|
57
57
|
import '../../packages/types/src/Css/map/index.js';
|
|
58
58
|
import '../../packages/types/src/Theme/shadows.js';
|
|
59
59
|
import '../../packages/types/src/Theme/defaultTheme.js';
|
|
60
|
+
import '../../packages/types/src/Theme/resolvers.js';
|
|
60
61
|
import '../../packages/types/src/Theme/alphaColors.js';
|
|
61
62
|
import '../../apps/mobile/src/Factory/helpers/cssVarMap.js';
|
|
62
63
|
import useSeparator from '../../apps/mobile/src/Factory/useSeparator.js';
|