@lmb-it/kitsconcerto-native 0.1.284 → 0.1.286
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/AutoComplete/index.cjs +12 -4
- package/apps/mobile/src/Core/AutoComplete/index.cjs.map +1 -1
- package/apps/mobile/src/Core/AutoComplete/index.js +12 -4
- package/apps/mobile/src/Core/AutoComplete/index.js.map +1 -1
- package/apps/mobile/src/Core/MultiSelect/index.cjs +7 -4
- package/apps/mobile/src/Core/MultiSelect/index.cjs.map +1 -1
- package/apps/mobile/src/Core/MultiSelect/index.js +7 -4
- package/apps/mobile/src/Core/MultiSelect/index.js.map +1 -1
- package/apps/mobile/src/ui/accordion/index.js +2 -2
- package/components/ImageCropper/compression.cjs +63 -0
- package/components/ImageCropper/compression.cjs.map +1 -0
- package/components/ImageCropper/compression.js +58 -0
- package/components/ImageCropper/compression.js.map +1 -0
- package/components/ImageCropper/constants.cjs +35 -0
- package/components/ImageCropper/constants.cjs.map +1 -0
- package/components/ImageCropper/constants.js +23 -0
- package/components/ImageCropper/constants.js.map +1 -0
- package/components/ImageCropper/cropperState.cjs +119 -0
- package/components/ImageCropper/cropperState.cjs.map +1 -0
- package/components/ImageCropper/cropperState.js +114 -0
- package/components/ImageCropper/cropperState.js.map +1 -0
- package/components/ImageCropper/encode.cjs +45 -0
- package/components/ImageCropper/encode.cjs.map +1 -0
- package/components/ImageCropper/encode.js +42 -0
- package/components/ImageCropper/encode.js.map +1 -0
- package/components/ImageCropper/encoderRegistry.cjs +13 -0
- package/components/ImageCropper/encoderRegistry.cjs.map +1 -0
- package/components/ImageCropper/encoderRegistry.js +9 -0
- package/components/ImageCropper/encoderRegistry.js.map +1 -0
- package/components/ImageCropper/encoders/rnImageEncoder.cjs +54 -0
- package/components/ImageCropper/encoders/rnImageEncoder.cjs.map +1 -0
- package/components/ImageCropper/encoders/rnImageEncoder.js +51 -0
- package/components/ImageCropper/encoders/rnImageEncoder.js.map +1 -0
- package/components/ImageCropper/geometry.cjs +208 -0
- package/components/ImageCropper/geometry.cjs.map +1 -0
- package/components/ImageCropper/geometry.js +186 -0
- package/components/ImageCropper/geometry.js.map +1 -0
- package/components/ImageCropper/index.cjs +436 -0
- package/components/ImageCropper/index.cjs.map +1 -0
- package/components/ImageCropper/index.js +434 -0
- package/components/ImageCropper/index.js.map +1 -0
- package/components/ImageCropper/pinchZoom.cjs +8 -0
- package/components/ImageCropper/pinchZoom.cjs.map +1 -0
- package/components/ImageCropper/pinchZoom.js +5 -0
- package/components/ImageCropper/pinchZoom.js.map +1 -0
- package/components/ImageCropper/useImageSource.cjs +87 -0
- package/components/ImageCropper/useImageSource.cjs.map +1 -0
- package/components/ImageCropper/useImageSource.js +84 -0
- package/components/ImageCropper/useImageSource.js.map +1 -0
- package/form/helpers/FormContainer/index.cjs +12 -2
- package/form/helpers/FormContainer/index.cjs.map +1 -1
- package/form/helpers/FormContainer/index.js +12 -2
- package/form/helpers/FormContainer/index.js.map +1 -1
- package/form/selects/AutoComplete/index.cjs +10 -1
- package/form/selects/AutoComplete/index.cjs.map +1 -1
- package/form/selects/AutoComplete/index.js +11 -2
- package/form/selects/AutoComplete/index.js.map +1 -1
- package/form/selects/MultiSelect/index.cjs +8 -1
- package/form/selects/MultiSelect/index.cjs.map +1 -1
- package/form/selects/MultiSelect/index.js +9 -2
- package/form/selects/MultiSelect/index.js.map +1 -1
- package/hooks/useComponentDefaults.cjs +62 -8
- package/hooks/useComponentDefaults.cjs.map +1 -1
- package/hooks/useComponentDefaults.js +62 -8
- package/hooks/useComponentDefaults.js.map +1 -1
- package/index.cjs +120 -115
- package/index.cjs.map +1 -1
- package/index.d.ts +494 -16
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/package.json +13 -1
- package/packages/types/src/Theme/defaultTheme.cjs +135 -4
- package/packages/types/src/Theme/defaultTheme.cjs.map +1 -1
- package/packages/types/src/Theme/defaultTheme.js +135 -4
- package/packages/types/src/Theme/defaultTheme.js.map +1 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactNative = require('react-native');
|
|
5
|
+
|
|
6
|
+
const resolveNativeSource = (source) => {
|
|
7
|
+
if (!source) return { kind: "none" };
|
|
8
|
+
if (typeof source === "number") {
|
|
9
|
+
const resolved = reactNative.Image.resolveAssetSource(source);
|
|
10
|
+
if (!resolved?.uri || !resolved.width || !resolved.height) {
|
|
11
|
+
return {
|
|
12
|
+
kind: "error",
|
|
13
|
+
error: { reason: "decode-failed", message: "That bundled image could not be resolved." }
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
kind: "ready",
|
|
18
|
+
image: { uri: resolved.uri, width: resolved.width, height: resolved.height }
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (typeof source !== "string") {
|
|
22
|
+
return {
|
|
23
|
+
kind: "error",
|
|
24
|
+
error: {
|
|
25
|
+
reason: "decode-failed",
|
|
26
|
+
message: "On a device the cropper needs a file URI or a require()'d asset, not a File object."
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return { kind: "measure", uri: source };
|
|
31
|
+
};
|
|
32
|
+
const useImageSource = (source, onError) => {
|
|
33
|
+
const [image, setImage] = React.useState(null);
|
|
34
|
+
const [error, setError] = React.useState(null);
|
|
35
|
+
const [loading, setLoading] = React.useState(false);
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
setImage(null);
|
|
38
|
+
setError(null);
|
|
39
|
+
const plan = resolveNativeSource(source);
|
|
40
|
+
if (plan.kind === "none") {
|
|
41
|
+
setLoading(false);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (plan.kind === "error") {
|
|
45
|
+
setError(plan.error);
|
|
46
|
+
setLoading(false);
|
|
47
|
+
onError?.(plan.error);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (plan.kind === "ready") {
|
|
51
|
+
setImage(plan.image);
|
|
52
|
+
setLoading(false);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
setLoading(true);
|
|
56
|
+
let cancelled = false;
|
|
57
|
+
reactNative.Image.getSize(
|
|
58
|
+
plan.uri,
|
|
59
|
+
(width, height) => {
|
|
60
|
+
if (cancelled) return;
|
|
61
|
+
setImage({ uri: plan.uri, width, height });
|
|
62
|
+
setLoading(false);
|
|
63
|
+
},
|
|
64
|
+
() => {
|
|
65
|
+
if (cancelled) return;
|
|
66
|
+
const failure = {
|
|
67
|
+
// ⚠️ THE MESSAGE NAMES THE LIKELY CAUSE, because the
|
|
68
|
+
// honest-sounding one sent us looking at the image. The file
|
|
69
|
+
// is usually fine; what failed is REACHING it.
|
|
70
|
+
reason: "decode-failed",
|
|
71
|
+
message: "That image could not be read. If it is a bundled asset, pass require('\u2026') instead of a URI \u2014 a dev-server URL is often unreachable from a physical device."
|
|
72
|
+
};
|
|
73
|
+
setError(failure);
|
|
74
|
+
setLoading(false);
|
|
75
|
+
onError?.(failure);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
return () => {
|
|
79
|
+
cancelled = true;
|
|
80
|
+
};
|
|
81
|
+
}, [source]);
|
|
82
|
+
return { image, loading, error };
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
exports.resolveNativeSource = resolveNativeSource;
|
|
86
|
+
exports.useImageSource = useImageSource;
|
|
87
|
+
//# sourceMappingURL=useImageSource.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useImageSource.cjs","sources":["../../../../src/components/ImageCropper/useImageSource.native.ts"],"sourcesContent":["import {useEffect, useState} from \"react\";\nimport {Image} from \"react-native\";\nimport type {ICropError} from \"@lmb-it/kitsconcerto-types\";\n\n/** What the stage needs before it can draw anything. */\nexport interface ILoadedImage {\n uri: string;\n width: number;\n height: number;\n}\n\n/**\n * Resolves a URI to its natural pixel size.\n *\n * ⛔ THE SIZE IS FETCHED, NOT GUESSED, AND NOTHING CAN DRAW UNTIL IT ARRIVES.\n * Every number in `geometry.ts` is relative to the source's real dimensions; a\n * stage that renders against a placeholder and corrects later shows the user a\n * framing that then jumps. `Image.getSize` is asynchronous for a remote URI and\n * near-instant for a local one, so the wait is only visible on the former.\n *\n * ⛔ A BUNDLED ASSET NEVER TOUCHES THE NETWORK, AND THAT IS THE WHOLE POINT OF\n * THE `require()` BRANCH. `Image.resolveAssetSource` returns `{uri, width,\n * height, scale}` SYNCHRONOUSLY from the asset registry — the dimensions are\n * already known, so there is nothing to fetch and nothing to fail.\n *\n * ⚠️ THIS WAS A REAL BUG, ON A REAL PHONE. The native stories resolved the\n * asset and then threw the dimensions away, passing only `.uri` — so this hook\n * took the string branch and asked `Image.getSize` to fetch them back. In\n * development that URI points at the Metro dev server; a physical device on a\n * different host cannot reach it, `getSize` failed, and the cropper reported\n * \"That image could not be opened\" over a perfectly good PNG. In a release\n * build the same URI is not fetchable that way either. The UI rendered, the\n * image never did.\n *\n * ⚠️ NATIVE TAKES A URI OR AN ASSET, NOT A `File`. The prop accepts\n * `string | File | number` so one config compiles on both platforms — the same\n * accepted-and-inert contract the selects' `popup` carries — but there is no\n * `File` on a device, and a picker hands back a `file://` path. A `File` here\n * is reported rather than ignored, because silently showing nothing is worse.\n */\n/**\n * What to do with a given `source`, decided without React.\n *\n * ⛔ A PURE FUNCTION BECAUSE THIS REPO'S VITEST HAS NO DOM — the same reason\n * `cropperState` is a reducer rather than a hook. The branch below is the one\n * that shipped a bug to a physical phone; leaving it inside an effect would\n * have meant shipping the fix untested too, since React's ESM exports cannot\n * be spied on.\n */\nexport type NativeSourcePlan =\n /** Nothing to load. */\n | {kind: \"none\"}\n /** A bundled asset: dimensions came back with it, no I/O needed. */\n | {kind: \"ready\"; image: ILoadedImage}\n /** A URI of unknown size: `Image.getSize` has to go and look. */\n | {kind: \"measure\"; uri: string}\n | {kind: \"error\"; error: ICropError};\n\nexport const resolveNativeSource = (\n source: string | File | number | null | undefined,\n): NativeSourcePlan => {\n if (!source) return {kind: \"none\"};\n\n /* ⛔ A BUNDLED ASSET NEVER TOUCHES THE NETWORK. `resolveAssetSource`\n returns `{uri, width, height, scale}` synchronously from the asset\n registry — the dimensions are already known, so there is nothing to\n fetch and nothing to fail. */\n if (typeof source === \"number\") {\n const resolved = Image.resolveAssetSource(source);\n if (!resolved?.uri || !resolved.width || !resolved.height) {\n // ⚠️ TYPED NON-NULL, NOT ALWAYS NON-NULL. An asset the packager did\n // not register comes back null or dimensionless, and reading `.uri`\n // off that throws inside an effect — which React surfaces as a\n // render crash somewhere else, not as this component's own error.\n return {\n kind: \"error\",\n error: {reason: \"decode-failed\", message: \"That bundled image could not be resolved.\"},\n };\n }\n return {\n kind: \"ready\",\n image: {uri: resolved.uri, width: resolved.width, height: resolved.height},\n };\n }\n\n if (typeof source !== \"string\") {\n return {\n kind: \"error\",\n error: {\n reason: \"decode-failed\",\n message: \"On a device the cropper needs a file URI or a require()'d asset, not a File object.\",\n },\n };\n }\n\n return {kind: \"measure\", uri: source};\n};\n\nexport const useImageSource = (\n source: string | File | number | null | undefined,\n onError?: (error: ICropError) => void,\n): {image: ILoadedImage | null; loading: boolean; error: ICropError | null} => {\n const [image, setImage] = useState<ILoadedImage | null>(null);\n const [error, setError] = useState<ICropError | null>(null);\n const [loading, setLoading] = useState(false);\n\n useEffect(() => {\n setImage(null);\n setError(null);\n\n const plan = resolveNativeSource(source);\n\n if (plan.kind === \"none\") {\n setLoading(false);\n return;\n }\n\n if (plan.kind === \"error\") {\n setError(plan.error);\n setLoading(false);\n onError?.(plan.error);\n return;\n }\n\n if (plan.kind === \"ready\") {\n setImage(plan.image);\n setLoading(false);\n return;\n }\n\n setLoading(true);\n let cancelled = false;\n\n Image.getSize(\n plan.uri,\n (width, height) => {\n if (cancelled) return;\n setImage({uri: plan.uri, width, height});\n setLoading(false);\n },\n () => {\n if (cancelled) return;\n const failure: ICropError = {\n // ⚠️ THE MESSAGE NAMES THE LIKELY CAUSE, because the\n // honest-sounding one sent us looking at the image. The file\n // is usually fine; what failed is REACHING it.\n reason: \"decode-failed\",\n message:\n \"That image could not be read. If it is a bundled asset, pass \" +\n \"require('…') instead of a URI — a dev-server URL is often \" +\n \"unreachable from a physical device.\",\n };\n setError(failure);\n setLoading(false);\n onError?.(failure);\n },\n );\n\n return () => {\n cancelled = true;\n };\n // ⚠️ `onError` IS DELIBERATELY NOT A DEPENDENCY — consumers pass an inline\n // arrow far more often than not, and including it re-runs the load on\n // every parent render. Same reasoning as the web twin.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [source]);\n\n return {image, loading, error};\n};\n"],"names":["Image","useState","useEffect"],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { Image } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const resolveNativeSource = (source) => {
|
|
5
|
+
if (!source) return { kind: "none" };
|
|
6
|
+
if (typeof source === "number") {
|
|
7
|
+
const resolved = Image.resolveAssetSource(source);
|
|
8
|
+
if (!resolved?.uri || !resolved.width || !resolved.height) {
|
|
9
|
+
return {
|
|
10
|
+
kind: "error",
|
|
11
|
+
error: { reason: "decode-failed", message: "That bundled image could not be resolved." }
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
kind: "ready",
|
|
16
|
+
image: { uri: resolved.uri, width: resolved.width, height: resolved.height }
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (typeof source !== "string") {
|
|
20
|
+
return {
|
|
21
|
+
kind: "error",
|
|
22
|
+
error: {
|
|
23
|
+
reason: "decode-failed",
|
|
24
|
+
message: "On a device the cropper needs a file URI or a require()'d asset, not a File object."
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return { kind: "measure", uri: source };
|
|
29
|
+
};
|
|
30
|
+
const useImageSource = (source, onError) => {
|
|
31
|
+
const [image, setImage] = useState(null);
|
|
32
|
+
const [error, setError] = useState(null);
|
|
33
|
+
const [loading, setLoading] = useState(false);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
setImage(null);
|
|
36
|
+
setError(null);
|
|
37
|
+
const plan = resolveNativeSource(source);
|
|
38
|
+
if (plan.kind === "none") {
|
|
39
|
+
setLoading(false);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (plan.kind === "error") {
|
|
43
|
+
setError(plan.error);
|
|
44
|
+
setLoading(false);
|
|
45
|
+
onError?.(plan.error);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (plan.kind === "ready") {
|
|
49
|
+
setImage(plan.image);
|
|
50
|
+
setLoading(false);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
setLoading(true);
|
|
54
|
+
let cancelled = false;
|
|
55
|
+
Image.getSize(
|
|
56
|
+
plan.uri,
|
|
57
|
+
(width, height) => {
|
|
58
|
+
if (cancelled) return;
|
|
59
|
+
setImage({ uri: plan.uri, width, height });
|
|
60
|
+
setLoading(false);
|
|
61
|
+
},
|
|
62
|
+
() => {
|
|
63
|
+
if (cancelled) return;
|
|
64
|
+
const failure = {
|
|
65
|
+
// ⚠️ THE MESSAGE NAMES THE LIKELY CAUSE, because the
|
|
66
|
+
// honest-sounding one sent us looking at the image. The file
|
|
67
|
+
// is usually fine; what failed is REACHING it.
|
|
68
|
+
reason: "decode-failed",
|
|
69
|
+
message: "That image could not be read. If it is a bundled asset, pass require('\u2026') instead of a URI \u2014 a dev-server URL is often unreachable from a physical device."
|
|
70
|
+
};
|
|
71
|
+
setError(failure);
|
|
72
|
+
setLoading(false);
|
|
73
|
+
onError?.(failure);
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
return () => {
|
|
77
|
+
cancelled = true;
|
|
78
|
+
};
|
|
79
|
+
}, [source]);
|
|
80
|
+
return { image, loading, error };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export { resolveNativeSource, useImageSource };
|
|
84
|
+
//# sourceMappingURL=useImageSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useImageSource.js","sources":["../../../../src/components/ImageCropper/useImageSource.native.ts"],"sourcesContent":["import {useEffect, useState} from \"react\";\nimport {Image} from \"react-native\";\nimport type {ICropError} from \"@lmb-it/kitsconcerto-types\";\n\n/** What the stage needs before it can draw anything. */\nexport interface ILoadedImage {\n uri: string;\n width: number;\n height: number;\n}\n\n/**\n * Resolves a URI to its natural pixel size.\n *\n * ⛔ THE SIZE IS FETCHED, NOT GUESSED, AND NOTHING CAN DRAW UNTIL IT ARRIVES.\n * Every number in `geometry.ts` is relative to the source's real dimensions; a\n * stage that renders against a placeholder and corrects later shows the user a\n * framing that then jumps. `Image.getSize` is asynchronous for a remote URI and\n * near-instant for a local one, so the wait is only visible on the former.\n *\n * ⛔ A BUNDLED ASSET NEVER TOUCHES THE NETWORK, AND THAT IS THE WHOLE POINT OF\n * THE `require()` BRANCH. `Image.resolveAssetSource` returns `{uri, width,\n * height, scale}` SYNCHRONOUSLY from the asset registry — the dimensions are\n * already known, so there is nothing to fetch and nothing to fail.\n *\n * ⚠️ THIS WAS A REAL BUG, ON A REAL PHONE. The native stories resolved the\n * asset and then threw the dimensions away, passing only `.uri` — so this hook\n * took the string branch and asked `Image.getSize` to fetch them back. In\n * development that URI points at the Metro dev server; a physical device on a\n * different host cannot reach it, `getSize` failed, and the cropper reported\n * \"That image could not be opened\" over a perfectly good PNG. In a release\n * build the same URI is not fetchable that way either. The UI rendered, the\n * image never did.\n *\n * ⚠️ NATIVE TAKES A URI OR AN ASSET, NOT A `File`. The prop accepts\n * `string | File | number` so one config compiles on both platforms — the same\n * accepted-and-inert contract the selects' `popup` carries — but there is no\n * `File` on a device, and a picker hands back a `file://` path. A `File` here\n * is reported rather than ignored, because silently showing nothing is worse.\n */\n/**\n * What to do with a given `source`, decided without React.\n *\n * ⛔ A PURE FUNCTION BECAUSE THIS REPO'S VITEST HAS NO DOM — the same reason\n * `cropperState` is a reducer rather than a hook. The branch below is the one\n * that shipped a bug to a physical phone; leaving it inside an effect would\n * have meant shipping the fix untested too, since React's ESM exports cannot\n * be spied on.\n */\nexport type NativeSourcePlan =\n /** Nothing to load. */\n | {kind: \"none\"}\n /** A bundled asset: dimensions came back with it, no I/O needed. */\n | {kind: \"ready\"; image: ILoadedImage}\n /** A URI of unknown size: `Image.getSize` has to go and look. */\n | {kind: \"measure\"; uri: string}\n | {kind: \"error\"; error: ICropError};\n\nexport const resolveNativeSource = (\n source: string | File | number | null | undefined,\n): NativeSourcePlan => {\n if (!source) return {kind: \"none\"};\n\n /* ⛔ A BUNDLED ASSET NEVER TOUCHES THE NETWORK. `resolveAssetSource`\n returns `{uri, width, height, scale}` synchronously from the asset\n registry — the dimensions are already known, so there is nothing to\n fetch and nothing to fail. */\n if (typeof source === \"number\") {\n const resolved = Image.resolveAssetSource(source);\n if (!resolved?.uri || !resolved.width || !resolved.height) {\n // ⚠️ TYPED NON-NULL, NOT ALWAYS NON-NULL. An asset the packager did\n // not register comes back null or dimensionless, and reading `.uri`\n // off that throws inside an effect — which React surfaces as a\n // render crash somewhere else, not as this component's own error.\n return {\n kind: \"error\",\n error: {reason: \"decode-failed\", message: \"That bundled image could not be resolved.\"},\n };\n }\n return {\n kind: \"ready\",\n image: {uri: resolved.uri, width: resolved.width, height: resolved.height},\n };\n }\n\n if (typeof source !== \"string\") {\n return {\n kind: \"error\",\n error: {\n reason: \"decode-failed\",\n message: \"On a device the cropper needs a file URI or a require()'d asset, not a File object.\",\n },\n };\n }\n\n return {kind: \"measure\", uri: source};\n};\n\nexport const useImageSource = (\n source: string | File | number | null | undefined,\n onError?: (error: ICropError) => void,\n): {image: ILoadedImage | null; loading: boolean; error: ICropError | null} => {\n const [image, setImage] = useState<ILoadedImage | null>(null);\n const [error, setError] = useState<ICropError | null>(null);\n const [loading, setLoading] = useState(false);\n\n useEffect(() => {\n setImage(null);\n setError(null);\n\n const plan = resolveNativeSource(source);\n\n if (plan.kind === \"none\") {\n setLoading(false);\n return;\n }\n\n if (plan.kind === \"error\") {\n setError(plan.error);\n setLoading(false);\n onError?.(plan.error);\n return;\n }\n\n if (plan.kind === \"ready\") {\n setImage(plan.image);\n setLoading(false);\n return;\n }\n\n setLoading(true);\n let cancelled = false;\n\n Image.getSize(\n plan.uri,\n (width, height) => {\n if (cancelled) return;\n setImage({uri: plan.uri, width, height});\n setLoading(false);\n },\n () => {\n if (cancelled) return;\n const failure: ICropError = {\n // ⚠️ THE MESSAGE NAMES THE LIKELY CAUSE, because the\n // honest-sounding one sent us looking at the image. The file\n // is usually fine; what failed is REACHING it.\n reason: \"decode-failed\",\n message:\n \"That image could not be read. If it is a bundled asset, pass \" +\n \"require('…') instead of a URI — a dev-server URL is often \" +\n \"unreachable from a physical device.\",\n };\n setError(failure);\n setLoading(false);\n onError?.(failure);\n },\n );\n\n return () => {\n cancelled = true;\n };\n // ⚠️ `onError` IS DELIBERATELY NOT A DEPENDENCY — consumers pass an inline\n // arrow far more often than not, and including it re-runs the load on\n // every parent render. Same reasoning as the web twin.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [source]);\n\n return {image, loading, error};\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -112,9 +112,18 @@ const KitsContainer = (props) => {
|
|
|
112
112
|
containerStyle,
|
|
113
113
|
disabled,
|
|
114
114
|
bare,
|
|
115
|
-
elementStyles: parentElementStyles
|
|
115
|
+
elementStyles: parentElementStyles,
|
|
116
|
+
elementProps: parentElementProps
|
|
116
117
|
} = props;
|
|
117
118
|
const elStyles = useResolvedElementStyles.default(parentElementStyles || {});
|
|
119
|
+
const elProps = parentElementProps || {};
|
|
120
|
+
const stripClassName = (slot) => {
|
|
121
|
+
if (!slot) return {};
|
|
122
|
+
const { className: _ignoredOnNative, ...rest } = slot;
|
|
123
|
+
return rest;
|
|
124
|
+
};
|
|
125
|
+
const containerSlotProps = stripClassName(elProps.container);
|
|
126
|
+
const inputGroupSlotProps = stripClassName(elProps.inputGroup);
|
|
118
127
|
const { resolveToken } = KitsThemeProvider_native.useKitsTheme();
|
|
119
128
|
const themedFont = useThemedFont.default("body");
|
|
120
129
|
const elementId = id ? `${id}_element` : _.uniqueId("element_");
|
|
@@ -168,7 +177,7 @@ const KitsContainer = (props) => {
|
|
|
168
177
|
paddingVertical: 8,
|
|
169
178
|
backgroundColor: resolveToken("bg-input")
|
|
170
179
|
};
|
|
171
|
-
const contentElement = /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: inputGroupStyle, children: [
|
|
180
|
+
const contentElement = /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: inputGroupStyle, ...inputGroupSlotProps, children: [
|
|
172
181
|
leftAddon ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
173
182
|
reactNative.View,
|
|
174
183
|
{
|
|
@@ -207,6 +216,7 @@ const KitsContainer = (props) => {
|
|
|
207
216
|
isDisabled: disabled,
|
|
208
217
|
isReadOnly: disabled,
|
|
209
218
|
isRequired: required,
|
|
219
|
+
...containerSlotProps,
|
|
210
220
|
style: {
|
|
211
221
|
width: "100%",
|
|
212
222
|
gap: 4,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../../../src/form/helpers/FormContainer/index.native.tsx"],"sourcesContent":["import React, { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport { uniqueId } from \"lodash\";\nimport ErrorMessage from \"../ErrorMessage\";\nimport type {IKitsContainer} from \"@lmb-it/kitsconcerto-types\";\nimport {\n FormControl,\n FormControlHelper,\n FormControlHelperText,\n style as resolveStyle,\n} from \"@lmb-it/kitsconcertomobile\"\nimport { Label, Text, useKitsTheme } from \"../../../_compat\";\nimport {useResolvedElementStyles, useThemedFont} from \"@lmb-it/kitsconcerto/hooks\";\n\n/**\n * KitsContainer (native) — wraps all form inputs with label, addons, helper\n * text, and errors. Mirror of the web variant: a pure renderer that does NO\n * independent theme lookup. Every slot style comes from `elementStyles`\n * passed by the parent input (already merged through the\n * FormElement < Input/Select < InputText/DropdownSelect/… < per-instance slots\n * chain by the parent's `useComponentDefaults` call).\n *\n * Addon rendering is inlined here (matches web FormContainer). There is NO\n * `Addons` component on either platform anymore — the previous native Addons\n * helper re-resolved tokens and hardcoded `borderRadius / borderWidth /\n * padding / backgroundColor / borderColor` defaults that clobbered\n * `kitsTheme.components.*.leftAddon.style` overrides. Both bugs are fixed by\n * deleting the indirection.\n *\n * Element slots applied here (identical contract to web):\n * container → outer FormControl wrapper\n * label → Label component (plain Text path on native — see Label.native)\n * inputGroup → input group wrapper (around addons + input). On native this\n * wrapper carries the visual border that web gets from the\n * `.p-inputgroup` CSS class.\n * leftAddon → left addon View\n * rightAddon → right addon View\n * helperText → helper text below the group\n * error → error message below the group\n *\n * The `root` slot is NOT applied here — it is applied by the parent form\n * input component directly to the inner Input/Textarea element.\n */\nconst KitsContainer: FC<PropsWithChildren<IKitsContainer>> = (props) => {\n const {\n id,\n helperText,\n children,\n rightAddon,\n leftAddon,\n errors,\n invalid,\n required,\n hideError,\n label,\n isFloatedLabel,\n containerStyle,\n disabled,\n bare,\n elementStyles: parentElementStyles,\n } = props;\n\n // Pure renderer: resolve the elementStyles passed in by the parent.\n // No `useComponentDefaults('FormContainer', …)` lookup — that key is\n // intentionally not part of the consumer-facing theme contract.\n const elStyles = useResolvedElementStyles(parentElementStyles || {});\n const { resolveToken } = useKitsTheme();\n const themedFont = useThemedFont('body');\n\n // Generate a unique element ID (for parity with web; not used in native labels)\n const elementId = id ? `${id}_element` : uniqueId(\"element_\");\n\n // Derive label placement from the label prop\n const placement = useMemo(() => {\n if (label && typeof label === 'object' && 'placement' in label) {\n return label.placement; // \"RL\" | \"B\" | \"T\"\n }\n return \"T\"; // default: top\n }, [label]);\n\n // Determine layout direction based on placement\n // T = top (column, label first), B = bottom (column-reverse), RL = side-by-side (row)\n const isHorizontal = placement === \"RL\";\n const isBottom = placement === \"B\";\n\n // Label uses the plain Text path (NOT the FormControlLabel path) because\n // @lmb-it/kitsconcertomobile's FormControlLabelText strips arbitrary\n // inline styles, which broke `kitsTheme.components.Input.label.style`\n // overrides on native. The plain Text path forwards `style` directly.\n const labelElement = !isFloatedLabel ? (\n <Label label={label} elementId={elementId} required={required} style={elStyles.label || undefined} />\n ) : null;\n\n /**\n * Inline addon renderer. Mirrors the dispatch web uses in FormContainer\n * (string → text, ReactElement → element) AND adds the function-arg\n * branch native needs because lucide-react-native icons are passed as\n * functions `(props) => <Icon …/>`. The function-arg branch never runs\n * on web (web never goes through this code) so it cannot affect web.\n */\n const renderAddon = (\n addon: IKitsContainer[\"leftAddon\"] | IKitsContainer[\"rightAddon\"],\n ) => {\n if (!addon) return null;\n if (typeof addon === \"string\" || typeof addon === \"number\") {\n return <Text fontSize={14}>{addon}</Text>;\n }\n if (typeof addon === \"function\") {\n return (addon as (args: { size: number }) => React.ReactNode)({ size: 16 });\n }\n if (React.isValidElement(addon)) {\n return addon;\n }\n return null;\n };\n\n // Resolved inputGroup wrapper style. The default theme provides\n // `Input.inputGroup.style.{borderColor, borderRadius, borderWidth, height}`\n // — these are what give the group its visual frame. Defaults are layered\n // *under* the user's resolved style, so a per-instance override always wins.\n //\n // The `invalid` border color is applied as a fallback default (after\n // theme defaults, before user `inputGroup.borderColor` override). When\n // `bare` is set, the whole frame is suppressed (matches web's\n // `bareInputGroupStyle`).\n const inputGroupStyle = useMemo(() => {\n if (bare) {\n // Bare mode (FilePicker, Radio, Checkbox group, …): drop ALL\n // inputGroup chrome including `height: 52` from the theme. Web's\n // FormContainer does the same — it passes `style={{}}` when\n // bare (see helpers/FormContainer/index.web.tsx, the bare\n // branch of the row Flex). Without this, the non-classic file\n // uploader's 200px dashed drop zone was being squashed to 52px.\n return {\n width: \"100%\" as const,\n borderWidth: 0,\n borderRadius: 0,\n overflow: \"visible\" as const,\n };\n }\n const userStyle = elStyles.inputGroup || {};\n const userOverrodeBorderColor = \"borderColor\" in userStyle;\n return {\n width: \"100%\" as const,\n flexDirection: \"row\" as const,\n alignItems: \"stretch\" as const,\n overflow: \"hidden\" as const,\n ...userStyle,\n ...(invalid && !userOverrodeBorderColor\n ? { borderColor: resolveToken(\"danger\") }\n : {}),\n };\n }, [bare, elStyles.inputGroup, invalid, resolveToken]);\n\n // Addon baseline chrome — mirrors what PrimeReact's `.p-inputgroup-addon`\n // CSS class gives web addons (gray fill + horizontal padding + 1px\n // separator border on the input-facing edge). On web these defaults\n // come from CSS; on native we must apply them inline. Theme overrides\n // (`elStyles.leftAddon` / `rightAddon`) are spread LAST so per-instance\n // values always win. The separator border colour falls back to the\n // inputGroup border colour for visual continuity.\n const addonSeparatorColor = (\n (elStyles.inputGroup && elStyles.inputGroup.borderColor) ||\n resolveToken(\"border\")\n );\n const addonBaseStyle = {\n alignItems: \"center\" as const,\n justifyContent: \"center\" as const,\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: resolveToken(\"bg-input\"),\n };\n\n const contentElement = (\n <View style={inputGroupStyle}>\n {leftAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderEndWidth: 1,\n borderEndColor: addonSeparatorColor,\n ...(elStyles.leftAddon || {}),\n }}\n >\n {renderAddon(leftAddon)}\n </View>\n ) : null}\n\n {/* `justifyContent: 'center'` vertically centres the inner Input\n inside the 52px-tall inputGroup (matching web, where flex\n items default to vertical alignment via the inputGroup row\n + the input's intrinsic line-box centring). Without this,\n placeholders and selected values sat near the top edge of\n the input. Tall children that already fill the height\n (textarea) are unaffected because `justifyContent: 'center'`\n is a no-op on items that match the parent's cross-axis. */}\n <View style={{ flex: 1, justifyContent: 'center' }}>{children}</View>\n\n {rightAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderStartWidth: 1,\n borderStartColor: addonSeparatorColor,\n ...(elStyles.rightAddon || {}),\n }}\n >\n {renderAddon(rightAddon)}\n </View>\n ) : null}\n </View>\n );\n\n const containerRnStyle = useMemo(\n () => (containerStyle && Object.keys(containerStyle).length ? resolveStyle(containerStyle) : {}),\n [containerStyle],\n );\n\n return(\n <FormControl\n isInvalid={invalid}\n size=\"md\"\n isDisabled={disabled}\n isReadOnly={disabled}\n isRequired={required}\n style={{\n width:'100%', gap: 4,\n // `bare` strips the container's DEFAULT frame, but must not\n // override an explicit `container` slot. Spread it FIRST so a\n // user's borderRadius / borderWidth / overflow (e.g. an Object\n // or Group styled as a card) wins over the reset.\n ...(bare ? { borderWidth: 0, borderRadius: 0, overflow: 'visible' } : {}),\n ...(elStyles.container || {}),\n ...(containerRnStyle || {}),\n }}\n >\n {isHorizontal ? (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, width: '100%' }}>\n {labelElement}\n <View style={{ flex: 1 }}>{contentElement}</View>\n </View>\n ) : isBottom ? (\n <>\n {contentElement}\n {labelElement}\n </>\n ) : (\n <>\n {labelElement}\n {contentElement}\n </>\n )}\n {helperText && typeof helperText !== \"function\" && <FormControlHelper>\n <FormControlHelperText style={{...(themedFont ? {fontFamily: themedFont} : {}), ...(elStyles.helperText || {})}}>\n {helperText}\n </FormControlHelperText>\n </FormControlHelper>}\n\n {!hideError && <ErrorMessage invalid={invalid} errors={errors} style={elStyles.error || undefined} />}\n </FormControl>\n )\n};\n\nexport default KitsContainer;\n"],"names":["useResolvedElementStyles","useKitsTheme","useThemedFont","uniqueId","useMemo","jsx","Label","Text","jsxs","View","resolveStyle","FormControl","Fragment","FormControlHelper","FormControlHelperText","ErrorMessage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../../../src/form/helpers/FormContainer/index.native.tsx"],"sourcesContent":["import React, { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport { uniqueId } from \"lodash\";\nimport ErrorMessage from \"../ErrorMessage\";\nimport type {IKitsContainer} from \"@lmb-it/kitsconcerto-types\";\nimport {\n FormControl,\n FormControlHelper,\n FormControlHelperText,\n style as resolveStyle,\n} from \"@lmb-it/kitsconcertomobile\"\nimport { Label, Text, useKitsTheme } from \"../../../_compat\";\nimport {useResolvedElementStyles, useThemedFont} from \"@lmb-it/kitsconcerto/hooks\";\n\n/**\n * KitsContainer (native) — wraps all form inputs with label, addons, helper\n * text, and errors. Mirror of the web variant: a pure renderer that does NO\n * independent theme lookup. Every slot style comes from `elementStyles`\n * passed by the parent input (already merged through the\n * FormElement < Input/Select < InputText/DropdownSelect/… < per-instance slots\n * chain by the parent's `useComponentDefaults` call).\n *\n * Addon rendering is inlined here (matches web FormContainer). There is NO\n * `Addons` component on either platform anymore — the previous native Addons\n * helper re-resolved tokens and hardcoded `borderRadius / borderWidth /\n * padding / backgroundColor / borderColor` defaults that clobbered\n * `kitsTheme.components.*.leftAddon.style` overrides. Both bugs are fixed by\n * deleting the indirection.\n *\n * Element slots applied here (identical contract to web):\n * container → outer FormControl wrapper\n * label → Label component (plain Text path on native — see Label.native)\n * inputGroup → input group wrapper (around addons + input). On native this\n * wrapper carries the visual border that web gets from the\n * `.p-inputgroup` CSS class.\n * leftAddon → left addon View\n * rightAddon → right addon View\n * helperText → helper text below the group\n * error → error message below the group\n *\n * The `root` slot is NOT applied here — it is applied by the parent form\n * input component directly to the inner Input/Textarea element.\n */\nconst KitsContainer: FC<PropsWithChildren<IKitsContainer>> = (props) => {\n const {\n id,\n helperText,\n children,\n rightAddon,\n leftAddon,\n errors,\n invalid,\n required,\n hideError,\n label,\n isFloatedLabel,\n containerStyle,\n disabled,\n bare,\n elementStyles: parentElementStyles,\n elementProps: parentElementProps,\n } = props;\n\n // Pure renderer: resolve the elementStyles passed in by the parent.\n // No `useComponentDefaults('FormContainer', …)` lookup — that key is\n // intentionally not part of the consumer-facing theme contract.\n const elStyles = useResolvedElementStyles(parentElementStyles || {});\n // Slot `props` — the web twin of this spreads them onto the DOM nodes.\n // On native `className` has no meaning, so it is dropped here; everything\n // else (testID, accessibility*, pointerEvents, …) is a legitimate View\n // prop and is forwarded. Same slot contract, honest about the platform.\n const elProps = parentElementProps || {};\n const stripClassName = (slot?: Record<string, any>) => {\n if (!slot) return {};\n const {className: _ignoredOnNative, ...rest} = slot;\n return rest;\n };\n const containerSlotProps = stripClassName(elProps.container);\n const inputGroupSlotProps = stripClassName(elProps.inputGroup);\n const { resolveToken } = useKitsTheme();\n const themedFont = useThemedFont('body');\n\n // Generate a unique element ID (for parity with web; not used in native labels)\n const elementId = id ? `${id}_element` : uniqueId(\"element_\");\n\n // Derive label placement from the label prop\n const placement = useMemo(() => {\n if (label && typeof label === 'object' && 'placement' in label) {\n return label.placement; // \"RL\" | \"B\" | \"T\"\n }\n return \"T\"; // default: top\n }, [label]);\n\n // Determine layout direction based on placement\n // T = top (column, label first), B = bottom (column-reverse), RL = side-by-side (row)\n const isHorizontal = placement === \"RL\";\n const isBottom = placement === \"B\";\n\n // Label uses the plain Text path (NOT the FormControlLabel path) because\n // @lmb-it/kitsconcertomobile's FormControlLabelText strips arbitrary\n // inline styles, which broke `kitsTheme.components.Input.label.style`\n // overrides on native. The plain Text path forwards `style` directly.\n const labelElement = !isFloatedLabel ? (\n <Label label={label} elementId={elementId} required={required} style={elStyles.label || undefined} />\n ) : null;\n\n /**\n * Inline addon renderer. Mirrors the dispatch web uses in FormContainer\n * (string → text, ReactElement → element) AND adds the function-arg\n * branch native needs because lucide-react-native icons are passed as\n * functions `(props) => <Icon …/>`. The function-arg branch never runs\n * on web (web never goes through this code) so it cannot affect web.\n */\n const renderAddon = (\n addon: IKitsContainer[\"leftAddon\"] | IKitsContainer[\"rightAddon\"],\n ) => {\n if (!addon) return null;\n if (typeof addon === \"string\" || typeof addon === \"number\") {\n return <Text fontSize={14}>{addon}</Text>;\n }\n if (typeof addon === \"function\") {\n return (addon as (args: { size: number }) => React.ReactNode)({ size: 16 });\n }\n if (React.isValidElement(addon)) {\n return addon;\n }\n return null;\n };\n\n // Resolved inputGroup wrapper style. The default theme provides\n // `Input.inputGroup.style.{borderColor, borderRadius, borderWidth, height}`\n // — these are what give the group its visual frame. Defaults are layered\n // *under* the user's resolved style, so a per-instance override always wins.\n //\n // The `invalid` border color is applied as a fallback default (after\n // theme defaults, before user `inputGroup.borderColor` override). When\n // `bare` is set, the whole frame is suppressed (matches web's\n // `bareInputGroupStyle`).\n const inputGroupStyle = useMemo(() => {\n if (bare) {\n // Bare mode (FilePicker, Radio, Checkbox group, …): drop ALL\n // inputGroup chrome including `height: 52` from the theme. Web's\n // FormContainer does the same — it passes `style={{}}` when\n // bare (see helpers/FormContainer/index.web.tsx, the bare\n // branch of the row Flex). Without this, the non-classic file\n // uploader's 200px dashed drop zone was being squashed to 52px.\n return {\n width: \"100%\" as const,\n borderWidth: 0,\n borderRadius: 0,\n overflow: \"visible\" as const,\n };\n }\n const userStyle = elStyles.inputGroup || {};\n const userOverrodeBorderColor = \"borderColor\" in userStyle;\n return {\n width: \"100%\" as const,\n flexDirection: \"row\" as const,\n alignItems: \"stretch\" as const,\n overflow: \"hidden\" as const,\n ...userStyle,\n ...(invalid && !userOverrodeBorderColor\n ? { borderColor: resolveToken(\"danger\") }\n : {}),\n };\n }, [bare, elStyles.inputGroup, invalid, resolveToken]);\n\n // Addon baseline chrome — mirrors what PrimeReact's `.p-inputgroup-addon`\n // CSS class gives web addons (gray fill + horizontal padding + 1px\n // separator border on the input-facing edge). On web these defaults\n // come from CSS; on native we must apply them inline. Theme overrides\n // (`elStyles.leftAddon` / `rightAddon`) are spread LAST so per-instance\n // values always win. The separator border colour falls back to the\n // inputGroup border colour for visual continuity.\n const addonSeparatorColor = (\n (elStyles.inputGroup && elStyles.inputGroup.borderColor) ||\n resolveToken(\"border\")\n );\n const addonBaseStyle = {\n alignItems: \"center\" as const,\n justifyContent: \"center\" as const,\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: resolveToken(\"bg-input\"),\n };\n\n const contentElement = (\n <View style={inputGroupStyle} {...inputGroupSlotProps}>\n {leftAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderEndWidth: 1,\n borderEndColor: addonSeparatorColor,\n ...(elStyles.leftAddon || {}),\n }}\n >\n {renderAddon(leftAddon)}\n </View>\n ) : null}\n\n {/* `justifyContent: 'center'` vertically centres the inner Input\n inside the 52px-tall inputGroup (matching web, where flex\n items default to vertical alignment via the inputGroup row\n + the input's intrinsic line-box centring). Without this,\n placeholders and selected values sat near the top edge of\n the input. Tall children that already fill the height\n (textarea) are unaffected because `justifyContent: 'center'`\n is a no-op on items that match the parent's cross-axis. */}\n <View style={{ flex: 1, justifyContent: 'center' }}>{children}</View>\n\n {rightAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderStartWidth: 1,\n borderStartColor: addonSeparatorColor,\n ...(elStyles.rightAddon || {}),\n }}\n >\n {renderAddon(rightAddon)}\n </View>\n ) : null}\n </View>\n );\n\n const containerRnStyle = useMemo(\n () => (containerStyle && Object.keys(containerStyle).length ? resolveStyle(containerStyle) : {}),\n [containerStyle],\n );\n\n return(\n <FormControl\n isInvalid={invalid}\n size=\"md\"\n isDisabled={disabled}\n isReadOnly={disabled}\n isRequired={required}\n {...containerSlotProps}\n style={{\n width:'100%', gap: 4,\n // `bare` strips the container's DEFAULT frame, but must not\n // override an explicit `container` slot. Spread it FIRST so a\n // user's borderRadius / borderWidth / overflow (e.g. an Object\n // or Group styled as a card) wins over the reset.\n ...(bare ? { borderWidth: 0, borderRadius: 0, overflow: 'visible' } : {}),\n ...(elStyles.container || {}),\n ...(containerRnStyle || {}),\n }}\n >\n {isHorizontal ? (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, width: '100%' }}>\n {labelElement}\n <View style={{ flex: 1 }}>{contentElement}</View>\n </View>\n ) : isBottom ? (\n <>\n {contentElement}\n {labelElement}\n </>\n ) : (\n <>\n {labelElement}\n {contentElement}\n </>\n )}\n {helperText && typeof helperText !== \"function\" && <FormControlHelper>\n <FormControlHelperText style={{...(themedFont ? {fontFamily: themedFont} : {}), ...(elStyles.helperText || {})}}>\n {helperText}\n </FormControlHelperText>\n </FormControlHelper>}\n\n {!hideError && <ErrorMessage invalid={invalid} errors={errors} style={elStyles.error || undefined} />}\n </FormControl>\n )\n};\n\nexport default KitsContainer;\n"],"names":["useResolvedElementStyles","useKitsTheme","useThemedFont","uniqueId","useMemo","jsx","Label","Text","jsxs","View","resolveStyle","FormControl","Fragment","FormControlHelper","FormControlHelperText","ErrorMessage"],"mappings":"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"}
|
|
@@ -108,9 +108,18 @@ const KitsContainer = (props) => {
|
|
|
108
108
|
containerStyle,
|
|
109
109
|
disabled,
|
|
110
110
|
bare,
|
|
111
|
-
elementStyles: parentElementStyles
|
|
111
|
+
elementStyles: parentElementStyles,
|
|
112
|
+
elementProps: parentElementProps
|
|
112
113
|
} = props;
|
|
113
114
|
const elStyles = useResolvedElementStyles(parentElementStyles || {});
|
|
115
|
+
const elProps = parentElementProps || {};
|
|
116
|
+
const stripClassName = (slot) => {
|
|
117
|
+
if (!slot) return {};
|
|
118
|
+
const { className: _ignoredOnNative, ...rest } = slot;
|
|
119
|
+
return rest;
|
|
120
|
+
};
|
|
121
|
+
const containerSlotProps = stripClassName(elProps.container);
|
|
122
|
+
const inputGroupSlotProps = stripClassName(elProps.inputGroup);
|
|
114
123
|
const { resolveToken } = useKitsTheme();
|
|
115
124
|
const themedFont = useThemedFont("body");
|
|
116
125
|
const elementId = id ? `${id}_element` : uniqueId("element_");
|
|
@@ -164,7 +173,7 @@ const KitsContainer = (props) => {
|
|
|
164
173
|
paddingVertical: 8,
|
|
165
174
|
backgroundColor: resolveToken("bg-input")
|
|
166
175
|
};
|
|
167
|
-
const contentElement = /* @__PURE__ */ jsxs(View, { style: inputGroupStyle, children: [
|
|
176
|
+
const contentElement = /* @__PURE__ */ jsxs(View, { style: inputGroupStyle, ...inputGroupSlotProps, children: [
|
|
168
177
|
leftAddon ? /* @__PURE__ */ jsx(
|
|
169
178
|
View,
|
|
170
179
|
{
|
|
@@ -203,6 +212,7 @@ const KitsContainer = (props) => {
|
|
|
203
212
|
isDisabled: disabled,
|
|
204
213
|
isReadOnly: disabled,
|
|
205
214
|
isRequired: required,
|
|
215
|
+
...containerSlotProps,
|
|
206
216
|
style: {
|
|
207
217
|
width: "100%",
|
|
208
218
|
gap: 4,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../src/form/helpers/FormContainer/index.native.tsx"],"sourcesContent":["import React, { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport { uniqueId } from \"lodash\";\nimport ErrorMessage from \"../ErrorMessage\";\nimport type {IKitsContainer} from \"@lmb-it/kitsconcerto-types\";\nimport {\n FormControl,\n FormControlHelper,\n FormControlHelperText,\n style as resolveStyle,\n} from \"@lmb-it/kitsconcertomobile\"\nimport { Label, Text, useKitsTheme } from \"../../../_compat\";\nimport {useResolvedElementStyles, useThemedFont} from \"@lmb-it/kitsconcerto/hooks\";\n\n/**\n * KitsContainer (native) — wraps all form inputs with label, addons, helper\n * text, and errors. Mirror of the web variant: a pure renderer that does NO\n * independent theme lookup. Every slot style comes from `elementStyles`\n * passed by the parent input (already merged through the\n * FormElement < Input/Select < InputText/DropdownSelect/… < per-instance slots\n * chain by the parent's `useComponentDefaults` call).\n *\n * Addon rendering is inlined here (matches web FormContainer). There is NO\n * `Addons` component on either platform anymore — the previous native Addons\n * helper re-resolved tokens and hardcoded `borderRadius / borderWidth /\n * padding / backgroundColor / borderColor` defaults that clobbered\n * `kitsTheme.components.*.leftAddon.style` overrides. Both bugs are fixed by\n * deleting the indirection.\n *\n * Element slots applied here (identical contract to web):\n * container → outer FormControl wrapper\n * label → Label component (plain Text path on native — see Label.native)\n * inputGroup → input group wrapper (around addons + input). On native this\n * wrapper carries the visual border that web gets from the\n * `.p-inputgroup` CSS class.\n * leftAddon → left addon View\n * rightAddon → right addon View\n * helperText → helper text below the group\n * error → error message below the group\n *\n * The `root` slot is NOT applied here — it is applied by the parent form\n * input component directly to the inner Input/Textarea element.\n */\nconst KitsContainer: FC<PropsWithChildren<IKitsContainer>> = (props) => {\n const {\n id,\n helperText,\n children,\n rightAddon,\n leftAddon,\n errors,\n invalid,\n required,\n hideError,\n label,\n isFloatedLabel,\n containerStyle,\n disabled,\n bare,\n elementStyles: parentElementStyles,\n } = props;\n\n // Pure renderer: resolve the elementStyles passed in by the parent.\n // No `useComponentDefaults('FormContainer', …)` lookup — that key is\n // intentionally not part of the consumer-facing theme contract.\n const elStyles = useResolvedElementStyles(parentElementStyles || {});\n const { resolveToken } = useKitsTheme();\n const themedFont = useThemedFont('body');\n\n // Generate a unique element ID (for parity with web; not used in native labels)\n const elementId = id ? `${id}_element` : uniqueId(\"element_\");\n\n // Derive label placement from the label prop\n const placement = useMemo(() => {\n if (label && typeof label === 'object' && 'placement' in label) {\n return label.placement; // \"RL\" | \"B\" | \"T\"\n }\n return \"T\"; // default: top\n }, [label]);\n\n // Determine layout direction based on placement\n // T = top (column, label first), B = bottom (column-reverse), RL = side-by-side (row)\n const isHorizontal = placement === \"RL\";\n const isBottom = placement === \"B\";\n\n // Label uses the plain Text path (NOT the FormControlLabel path) because\n // @lmb-it/kitsconcertomobile's FormControlLabelText strips arbitrary\n // inline styles, which broke `kitsTheme.components.Input.label.style`\n // overrides on native. The plain Text path forwards `style` directly.\n const labelElement = !isFloatedLabel ? (\n <Label label={label} elementId={elementId} required={required} style={elStyles.label || undefined} />\n ) : null;\n\n /**\n * Inline addon renderer. Mirrors the dispatch web uses in FormContainer\n * (string → text, ReactElement → element) AND adds the function-arg\n * branch native needs because lucide-react-native icons are passed as\n * functions `(props) => <Icon …/>`. The function-arg branch never runs\n * on web (web never goes through this code) so it cannot affect web.\n */\n const renderAddon = (\n addon: IKitsContainer[\"leftAddon\"] | IKitsContainer[\"rightAddon\"],\n ) => {\n if (!addon) return null;\n if (typeof addon === \"string\" || typeof addon === \"number\") {\n return <Text fontSize={14}>{addon}</Text>;\n }\n if (typeof addon === \"function\") {\n return (addon as (args: { size: number }) => React.ReactNode)({ size: 16 });\n }\n if (React.isValidElement(addon)) {\n return addon;\n }\n return null;\n };\n\n // Resolved inputGroup wrapper style. The default theme provides\n // `Input.inputGroup.style.{borderColor, borderRadius, borderWidth, height}`\n // — these are what give the group its visual frame. Defaults are layered\n // *under* the user's resolved style, so a per-instance override always wins.\n //\n // The `invalid` border color is applied as a fallback default (after\n // theme defaults, before user `inputGroup.borderColor` override). When\n // `bare` is set, the whole frame is suppressed (matches web's\n // `bareInputGroupStyle`).\n const inputGroupStyle = useMemo(() => {\n if (bare) {\n // Bare mode (FilePicker, Radio, Checkbox group, …): drop ALL\n // inputGroup chrome including `height: 52` from the theme. Web's\n // FormContainer does the same — it passes `style={{}}` when\n // bare (see helpers/FormContainer/index.web.tsx, the bare\n // branch of the row Flex). Without this, the non-classic file\n // uploader's 200px dashed drop zone was being squashed to 52px.\n return {\n width: \"100%\" as const,\n borderWidth: 0,\n borderRadius: 0,\n overflow: \"visible\" as const,\n };\n }\n const userStyle = elStyles.inputGroup || {};\n const userOverrodeBorderColor = \"borderColor\" in userStyle;\n return {\n width: \"100%\" as const,\n flexDirection: \"row\" as const,\n alignItems: \"stretch\" as const,\n overflow: \"hidden\" as const,\n ...userStyle,\n ...(invalid && !userOverrodeBorderColor\n ? { borderColor: resolveToken(\"danger\") }\n : {}),\n };\n }, [bare, elStyles.inputGroup, invalid, resolveToken]);\n\n // Addon baseline chrome — mirrors what PrimeReact's `.p-inputgroup-addon`\n // CSS class gives web addons (gray fill + horizontal padding + 1px\n // separator border on the input-facing edge). On web these defaults\n // come from CSS; on native we must apply them inline. Theme overrides\n // (`elStyles.leftAddon` / `rightAddon`) are spread LAST so per-instance\n // values always win. The separator border colour falls back to the\n // inputGroup border colour for visual continuity.\n const addonSeparatorColor = (\n (elStyles.inputGroup && elStyles.inputGroup.borderColor) ||\n resolveToken(\"border\")\n );\n const addonBaseStyle = {\n alignItems: \"center\" as const,\n justifyContent: \"center\" as const,\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: resolveToken(\"bg-input\"),\n };\n\n const contentElement = (\n <View style={inputGroupStyle}>\n {leftAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderEndWidth: 1,\n borderEndColor: addonSeparatorColor,\n ...(elStyles.leftAddon || {}),\n }}\n >\n {renderAddon(leftAddon)}\n </View>\n ) : null}\n\n {/* `justifyContent: 'center'` vertically centres the inner Input\n inside the 52px-tall inputGroup (matching web, where flex\n items default to vertical alignment via the inputGroup row\n + the input's intrinsic line-box centring). Without this,\n placeholders and selected values sat near the top edge of\n the input. Tall children that already fill the height\n (textarea) are unaffected because `justifyContent: 'center'`\n is a no-op on items that match the parent's cross-axis. */}\n <View style={{ flex: 1, justifyContent: 'center' }}>{children}</View>\n\n {rightAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderStartWidth: 1,\n borderStartColor: addonSeparatorColor,\n ...(elStyles.rightAddon || {}),\n }}\n >\n {renderAddon(rightAddon)}\n </View>\n ) : null}\n </View>\n );\n\n const containerRnStyle = useMemo(\n () => (containerStyle && Object.keys(containerStyle).length ? resolveStyle(containerStyle) : {}),\n [containerStyle],\n );\n\n return(\n <FormControl\n isInvalid={invalid}\n size=\"md\"\n isDisabled={disabled}\n isReadOnly={disabled}\n isRequired={required}\n style={{\n width:'100%', gap: 4,\n // `bare` strips the container's DEFAULT frame, but must not\n // override an explicit `container` slot. Spread it FIRST so a\n // user's borderRadius / borderWidth / overflow (e.g. an Object\n // or Group styled as a card) wins over the reset.\n ...(bare ? { borderWidth: 0, borderRadius: 0, overflow: 'visible' } : {}),\n ...(elStyles.container || {}),\n ...(containerRnStyle || {}),\n }}\n >\n {isHorizontal ? (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, width: '100%' }}>\n {labelElement}\n <View style={{ flex: 1 }}>{contentElement}</View>\n </View>\n ) : isBottom ? (\n <>\n {contentElement}\n {labelElement}\n </>\n ) : (\n <>\n {labelElement}\n {contentElement}\n </>\n )}\n {helperText && typeof helperText !== \"function\" && <FormControlHelper>\n <FormControlHelperText style={{...(themedFont ? {fontFamily: themedFont} : {}), ...(elStyles.helperText || {})}}>\n {helperText}\n </FormControlHelperText>\n </FormControlHelper>}\n\n {!hideError && <ErrorMessage invalid={invalid} errors={errors} style={elStyles.error || undefined} />}\n </FormControl>\n )\n};\n\nexport default KitsContainer;\n"],"names":["resolveStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../src/form/helpers/FormContainer/index.native.tsx"],"sourcesContent":["import React, { type FC, type PropsWithChildren, useMemo } from \"react\";\nimport { View } from \"react-native\";\nimport { uniqueId } from \"lodash\";\nimport ErrorMessage from \"../ErrorMessage\";\nimport type {IKitsContainer} from \"@lmb-it/kitsconcerto-types\";\nimport {\n FormControl,\n FormControlHelper,\n FormControlHelperText,\n style as resolveStyle,\n} from \"@lmb-it/kitsconcertomobile\"\nimport { Label, Text, useKitsTheme } from \"../../../_compat\";\nimport {useResolvedElementStyles, useThemedFont} from \"@lmb-it/kitsconcerto/hooks\";\n\n/**\n * KitsContainer (native) — wraps all form inputs with label, addons, helper\n * text, and errors. Mirror of the web variant: a pure renderer that does NO\n * independent theme lookup. Every slot style comes from `elementStyles`\n * passed by the parent input (already merged through the\n * FormElement < Input/Select < InputText/DropdownSelect/… < per-instance slots\n * chain by the parent's `useComponentDefaults` call).\n *\n * Addon rendering is inlined here (matches web FormContainer). There is NO\n * `Addons` component on either platform anymore — the previous native Addons\n * helper re-resolved tokens and hardcoded `borderRadius / borderWidth /\n * padding / backgroundColor / borderColor` defaults that clobbered\n * `kitsTheme.components.*.leftAddon.style` overrides. Both bugs are fixed by\n * deleting the indirection.\n *\n * Element slots applied here (identical contract to web):\n * container → outer FormControl wrapper\n * label → Label component (plain Text path on native — see Label.native)\n * inputGroup → input group wrapper (around addons + input). On native this\n * wrapper carries the visual border that web gets from the\n * `.p-inputgroup` CSS class.\n * leftAddon → left addon View\n * rightAddon → right addon View\n * helperText → helper text below the group\n * error → error message below the group\n *\n * The `root` slot is NOT applied here — it is applied by the parent form\n * input component directly to the inner Input/Textarea element.\n */\nconst KitsContainer: FC<PropsWithChildren<IKitsContainer>> = (props) => {\n const {\n id,\n helperText,\n children,\n rightAddon,\n leftAddon,\n errors,\n invalid,\n required,\n hideError,\n label,\n isFloatedLabel,\n containerStyle,\n disabled,\n bare,\n elementStyles: parentElementStyles,\n elementProps: parentElementProps,\n } = props;\n\n // Pure renderer: resolve the elementStyles passed in by the parent.\n // No `useComponentDefaults('FormContainer', …)` lookup — that key is\n // intentionally not part of the consumer-facing theme contract.\n const elStyles = useResolvedElementStyles(parentElementStyles || {});\n // Slot `props` — the web twin of this spreads them onto the DOM nodes.\n // On native `className` has no meaning, so it is dropped here; everything\n // else (testID, accessibility*, pointerEvents, …) is a legitimate View\n // prop and is forwarded. Same slot contract, honest about the platform.\n const elProps = parentElementProps || {};\n const stripClassName = (slot?: Record<string, any>) => {\n if (!slot) return {};\n const {className: _ignoredOnNative, ...rest} = slot;\n return rest;\n };\n const containerSlotProps = stripClassName(elProps.container);\n const inputGroupSlotProps = stripClassName(elProps.inputGroup);\n const { resolveToken } = useKitsTheme();\n const themedFont = useThemedFont('body');\n\n // Generate a unique element ID (for parity with web; not used in native labels)\n const elementId = id ? `${id}_element` : uniqueId(\"element_\");\n\n // Derive label placement from the label prop\n const placement = useMemo(() => {\n if (label && typeof label === 'object' && 'placement' in label) {\n return label.placement; // \"RL\" | \"B\" | \"T\"\n }\n return \"T\"; // default: top\n }, [label]);\n\n // Determine layout direction based on placement\n // T = top (column, label first), B = bottom (column-reverse), RL = side-by-side (row)\n const isHorizontal = placement === \"RL\";\n const isBottom = placement === \"B\";\n\n // Label uses the plain Text path (NOT the FormControlLabel path) because\n // @lmb-it/kitsconcertomobile's FormControlLabelText strips arbitrary\n // inline styles, which broke `kitsTheme.components.Input.label.style`\n // overrides on native. The plain Text path forwards `style` directly.\n const labelElement = !isFloatedLabel ? (\n <Label label={label} elementId={elementId} required={required} style={elStyles.label || undefined} />\n ) : null;\n\n /**\n * Inline addon renderer. Mirrors the dispatch web uses in FormContainer\n * (string → text, ReactElement → element) AND adds the function-arg\n * branch native needs because lucide-react-native icons are passed as\n * functions `(props) => <Icon …/>`. The function-arg branch never runs\n * on web (web never goes through this code) so it cannot affect web.\n */\n const renderAddon = (\n addon: IKitsContainer[\"leftAddon\"] | IKitsContainer[\"rightAddon\"],\n ) => {\n if (!addon) return null;\n if (typeof addon === \"string\" || typeof addon === \"number\") {\n return <Text fontSize={14}>{addon}</Text>;\n }\n if (typeof addon === \"function\") {\n return (addon as (args: { size: number }) => React.ReactNode)({ size: 16 });\n }\n if (React.isValidElement(addon)) {\n return addon;\n }\n return null;\n };\n\n // Resolved inputGroup wrapper style. The default theme provides\n // `Input.inputGroup.style.{borderColor, borderRadius, borderWidth, height}`\n // — these are what give the group its visual frame. Defaults are layered\n // *under* the user's resolved style, so a per-instance override always wins.\n //\n // The `invalid` border color is applied as a fallback default (after\n // theme defaults, before user `inputGroup.borderColor` override). When\n // `bare` is set, the whole frame is suppressed (matches web's\n // `bareInputGroupStyle`).\n const inputGroupStyle = useMemo(() => {\n if (bare) {\n // Bare mode (FilePicker, Radio, Checkbox group, …): drop ALL\n // inputGroup chrome including `height: 52` from the theme. Web's\n // FormContainer does the same — it passes `style={{}}` when\n // bare (see helpers/FormContainer/index.web.tsx, the bare\n // branch of the row Flex). Without this, the non-classic file\n // uploader's 200px dashed drop zone was being squashed to 52px.\n return {\n width: \"100%\" as const,\n borderWidth: 0,\n borderRadius: 0,\n overflow: \"visible\" as const,\n };\n }\n const userStyle = elStyles.inputGroup || {};\n const userOverrodeBorderColor = \"borderColor\" in userStyle;\n return {\n width: \"100%\" as const,\n flexDirection: \"row\" as const,\n alignItems: \"stretch\" as const,\n overflow: \"hidden\" as const,\n ...userStyle,\n ...(invalid && !userOverrodeBorderColor\n ? { borderColor: resolveToken(\"danger\") }\n : {}),\n };\n }, [bare, elStyles.inputGroup, invalid, resolveToken]);\n\n // Addon baseline chrome — mirrors what PrimeReact's `.p-inputgroup-addon`\n // CSS class gives web addons (gray fill + horizontal padding + 1px\n // separator border on the input-facing edge). On web these defaults\n // come from CSS; on native we must apply them inline. Theme overrides\n // (`elStyles.leftAddon` / `rightAddon`) are spread LAST so per-instance\n // values always win. The separator border colour falls back to the\n // inputGroup border colour for visual continuity.\n const addonSeparatorColor = (\n (elStyles.inputGroup && elStyles.inputGroup.borderColor) ||\n resolveToken(\"border\")\n );\n const addonBaseStyle = {\n alignItems: \"center\" as const,\n justifyContent: \"center\" as const,\n paddingHorizontal: 12,\n paddingVertical: 8,\n backgroundColor: resolveToken(\"bg-input\"),\n };\n\n const contentElement = (\n <View style={inputGroupStyle} {...inputGroupSlotProps}>\n {leftAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderEndWidth: 1,\n borderEndColor: addonSeparatorColor,\n ...(elStyles.leftAddon || {}),\n }}\n >\n {renderAddon(leftAddon)}\n </View>\n ) : null}\n\n {/* `justifyContent: 'center'` vertically centres the inner Input\n inside the 52px-tall inputGroup (matching web, where flex\n items default to vertical alignment via the inputGroup row\n + the input's intrinsic line-box centring). Without this,\n placeholders and selected values sat near the top edge of\n the input. Tall children that already fill the height\n (textarea) are unaffected because `justifyContent: 'center'`\n is a no-op on items that match the parent's cross-axis. */}\n <View style={{ flex: 1, justifyContent: 'center' }}>{children}</View>\n\n {rightAddon ? (\n <View\n style={{\n ...addonBaseStyle,\n borderStartWidth: 1,\n borderStartColor: addonSeparatorColor,\n ...(elStyles.rightAddon || {}),\n }}\n >\n {renderAddon(rightAddon)}\n </View>\n ) : null}\n </View>\n );\n\n const containerRnStyle = useMemo(\n () => (containerStyle && Object.keys(containerStyle).length ? resolveStyle(containerStyle) : {}),\n [containerStyle],\n );\n\n return(\n <FormControl\n isInvalid={invalid}\n size=\"md\"\n isDisabled={disabled}\n isReadOnly={disabled}\n isRequired={required}\n {...containerSlotProps}\n style={{\n width:'100%', gap: 4,\n // `bare` strips the container's DEFAULT frame, but must not\n // override an explicit `container` slot. Spread it FIRST so a\n // user's borderRadius / borderWidth / overflow (e.g. an Object\n // or Group styled as a card) wins over the reset.\n ...(bare ? { borderWidth: 0, borderRadius: 0, overflow: 'visible' } : {}),\n ...(elStyles.container || {}),\n ...(containerRnStyle || {}),\n }}\n >\n {isHorizontal ? (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, width: '100%' }}>\n {labelElement}\n <View style={{ flex: 1 }}>{contentElement}</View>\n </View>\n ) : isBottom ? (\n <>\n {contentElement}\n {labelElement}\n </>\n ) : (\n <>\n {labelElement}\n {contentElement}\n </>\n )}\n {helperText && typeof helperText !== \"function\" && <FormControlHelper>\n <FormControlHelperText style={{...(themedFont ? {fontFamily: themedFont} : {}), ...(elStyles.helperText || {})}}>\n {helperText}\n </FormControlHelperText>\n </FormControlHelper>}\n\n {!hideError && <ErrorMessage invalid={invalid} errors={errors} style={elStyles.error || undefined} />}\n </FormControl>\n )\n};\n\nexport default KitsContainer;\n"],"names":["resolveStyle"],"mappings":"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"}
|
|
@@ -95,9 +95,13 @@ var useResolvedStyle = require('../../../hooks/useResolvedStyle.cjs');
|
|
|
95
95
|
var KitsThemeProvider_native = require('../../../contexts/Theme/KitsThemeProvider.cjs');
|
|
96
96
|
|
|
97
97
|
const KitsAutoComplete = ({ ref, ...rawProps }) => {
|
|
98
|
-
const { mergedProps: props, themeStyle, elementStyles } = useComponentDefaults.default("AutoComplete", rawProps, "Select");
|
|
98
|
+
const { mergedProps: props, themeStyle, elementStyles, elementProps } = useComponentDefaults.default("AutoComplete", rawProps, "Select");
|
|
99
99
|
const resolvedThemeStyle = useResolvedStyle.default(themeStyle);
|
|
100
100
|
const resolvedRootStyle = useResolvedStyle.default(elementStyles?.root || {});
|
|
101
|
+
const resolvedTokenContainer = useResolvedStyle.default(elementStyles?.tokenContainer || {});
|
|
102
|
+
const resolvedToken = useResolvedStyle.default(elementStyles?.token || {});
|
|
103
|
+
const resolvedTokenIcon = useResolvedStyle.default(elementStyles?.tokenIcon || {});
|
|
104
|
+
const { wrapper: tokenBoxStyle, text: tokenLabelStyle } = useResolvedStyle.splitTextStyle(resolvedToken);
|
|
101
105
|
const {
|
|
102
106
|
id,
|
|
103
107
|
rightAddon,
|
|
@@ -162,6 +166,10 @@ const KitsAutoComplete = ({ ref, ...rawProps }) => {
|
|
|
162
166
|
optionGroupLabel: childrenKey ? labelKey : void 0,
|
|
163
167
|
style: { width: "100%", borderRadius: 0, border: "none", backgroundColor: "transparent" },
|
|
164
168
|
inputStyle: { flexDirection: "row", borderRadius: 0, border: "none", width: "100%", backgroundColor: "transparent", ...resolvedRootStyle || resolvedThemeStyle },
|
|
169
|
+
tokenContainerStyle: resolvedTokenContainer,
|
|
170
|
+
tokenStyle: tokenBoxStyle,
|
|
171
|
+
tokenLabelStyle,
|
|
172
|
+
tokenIconStyle: resolvedTokenIcon,
|
|
165
173
|
onChange: (event) => {
|
|
166
174
|
setInputValue(event.value);
|
|
167
175
|
handleOnChange(event);
|
|
@@ -199,6 +207,7 @@ const KitsAutoComplete = ({ ref, ...rawProps }) => {
|
|
|
199
207
|
label,
|
|
200
208
|
containerStyle,
|
|
201
209
|
elementStyles: overflowEscape,
|
|
210
|
+
elementProps,
|
|
202
211
|
children: Element
|
|
203
212
|
}
|
|
204
213
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../../../../src/form/selects/AutoComplete/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport KitsContainer from \"../../helpers/FormContainer\";\nimport {AutoComplete, useSeparator} from \"@lmb-it/kitsconcertomobile\";\nimport type { IAutoCompleteElement } from \"@lmb-it/kitsconcerto-types\";\nimport { useAutoCompleteLogic } from \"../hooks/useAutoCompleteLogic\";\nimport { useComponentDefaults, useResolvedStyle } from \"../../../hooks\";\nimport { useKitsTheme } from \"../../../contexts/Theme\";\n\nconst KitsAutoComplete = ({ ref, ...rawProps }: IAutoCompleteElement) => {\n const { mergedProps: props, themeStyle, elementStyles } = useComponentDefaults('AutoComplete', rawProps, 'Select');\n const resolvedThemeStyle = useResolvedStyle(themeStyle);\n const resolvedRootStyle = useResolvedStyle(elementStyles?.root || {});\n const {\n id,\n rightAddon,\n leftAddon,\n errors,\n invalid,\n label,\n hideError,\n disabled,\n required,\n isFloatedLabel,\n inputSize = \"md\",\n forceSelection,\n completeMethod,\n helperText,\n withArrow,\n placeholder,\n isMultiple,\n localProps,\n delay,\n minLength,\n selectionLimit,\n showEmptyMessage,\n emptyMessage,\n attached,\n containerStyle,\n } = props;\n\n const { nativeProps } = useSeparator<HTMLSelectElement>(props);\n\n const { resolveToken } = useKitsTheme();\n const primaryColor = resolveToken('primary');\n const borderColor = resolveToken('border');\n\n const {\n inputValue,\n setInputValue,\n filteredList,\n search,\n handleOnChange,\n list,\n childrenKey,\n labelKey,\n } = useAutoCompleteLogic({ isMultiple, forceSelection, completeMethod, ref });\n\n const hasThemeStyle = Object.keys(themeStyle).length > 0;\n\n\n const Element = <AutoComplete\n disabled={disabled}\n placeholder={placeholder}\n value={inputValue}\n forceSelection={forceSelection}\n suggestions={Array.isArray(filteredList) ? filteredList : list}\n completeMethod={search}\n dropdown={withArrow}\n multiple={isMultiple}\n field={labelKey}\n invalid={!!invalid}\n emptyMessage={emptyMessage ?? \"No results found\"}\n {...(delay != null ? { delay } : {})}\n {...(minLength != null ? { minLength } : {})}\n {...(selectionLimit != null ? { selectionLimit } : {})}\n showEmptyMessage={showEmptyMessage ?? true}\n optionGroupChildren={childrenKey ?? undefined}\n optionGroupLabel={childrenKey ? labelKey : undefined}\n style={{ width: \"100%\", borderRadius: 0, border:'none', backgroundColor:'transparent' }}\n inputStyle={{ flexDirection: \"row\", borderRadius: 0, border:'none', width: \"100%\",backgroundColor:'transparent', ...(resolvedRootStyle || resolvedThemeStyle) }}\n onChange={(event) => {\n setInputValue(event.value);\n handleOnChange(event);\n }}\n {...(localProps ?? {})}\n />\n\n if (attached) {\n return Element;\n }\n\n // KitsContainer's `inputGroup` wrapper defaults to `overflow: 'hidden'`\n // (so rounded borders clip the input cleanly). For AutoComplete that\n // would clip the floating suggestions panel back to the input's bounds\n // — the panel renders but is invisible, which is the \"list never\n // appears\" symptom on mobile. Force `overflow: 'visible'` on the\n // container chain so the panel can escape.\n const overflowEscape = {\n ...elementStyles,\n container: {\n ...(elementStyles?.container || {}),\n overflow: 'visible' as const,\n },\n inputGroup: {\n ...(elementStyles?.inputGroup || {}),\n overflow: 'visible' as const,\n },\n };\n\n return (\n <KitsContainer\n id={id}\n inputSize={inputSize}\n isFloatedLabel={isFloatedLabel}\n hideError={hideError}\n rightAddon={rightAddon}\n leftAddon={leftAddon}\n required={required}\n helperText={helperText}\n errors={errors}\n invalid={invalid}\n label={label}\n containerStyle={containerStyle}\n elementStyles={overflowEscape}\n >\n {Element}\n </KitsContainer>\n );\n};\n\nexport default KitsAutoComplete;\n"],"names":["useComponentDefaults","useResolvedStyle","useSeparator","useKitsTheme","useAutoCompleteLogic","jsx","AutoComplete","KitsContainer"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../../../../src/form/selects/AutoComplete/index.native.tsx"],"sourcesContent":["import React from \"react\";\nimport KitsContainer from \"../../helpers/FormContainer\";\nimport {AutoComplete, useSeparator} from \"@lmb-it/kitsconcertomobile\";\nimport type { IAutoCompleteElement } from \"@lmb-it/kitsconcerto-types\";\nimport { useAutoCompleteLogic } from \"../hooks/useAutoCompleteLogic\";\nimport { useComponentDefaults, useResolvedStyle } from \"../../../hooks\";\nimport { splitTextStyle } from \"../../../hooks/useResolvedStyle\";\nimport { useKitsTheme } from \"../../../contexts/Theme\";\n\nconst KitsAutoComplete = ({ ref, ...rawProps }: IAutoCompleteElement) => {\n const { mergedProps: props, themeStyle, elementStyles, elementProps } = useComponentDefaults('AutoComplete', rawProps, 'Select');\n const resolvedThemeStyle = useResolvedStyle(themeStyle);\n const resolvedRootStyle = useResolvedStyle(elementStyles?.root || {});\n /* ─── Chips field slots — the native half of the same contract ──────────\n `tokenContainer` is the field wrapper View that holds the chips and the\n TextInput (web: `ul.p-autocomplete-multiple-container`). `token` splits\n in two on native, because a React Native `View` cannot carry `color` or\n `fontSize` — the text half goes to the chip's `Text`, which is what the\n CSS cascade does for free on web. */\n const resolvedTokenContainer = useResolvedStyle(elementStyles?.tokenContainer || {});\n const resolvedToken = useResolvedStyle(elementStyles?.token || {});\n const resolvedTokenIcon = useResolvedStyle(elementStyles?.tokenIcon || {});\n const {wrapper: tokenBoxStyle, text: tokenLabelStyle} = splitTextStyle(resolvedToken);\n const {\n id,\n rightAddon,\n leftAddon,\n errors,\n invalid,\n label,\n hideError,\n disabled,\n required,\n isFloatedLabel,\n inputSize = \"md\",\n forceSelection,\n completeMethod,\n helperText,\n withArrow,\n placeholder,\n isMultiple,\n localProps,\n delay,\n minLength,\n selectionLimit,\n showEmptyMessage,\n emptyMessage,\n attached,\n containerStyle,\n } = props;\n\n const { nativeProps } = useSeparator<HTMLSelectElement>(props);\n\n const { resolveToken } = useKitsTheme();\n const primaryColor = resolveToken('primary');\n const borderColor = resolveToken('border');\n\n const {\n inputValue,\n setInputValue,\n filteredList,\n search,\n handleOnChange,\n list,\n childrenKey,\n labelKey,\n } = useAutoCompleteLogic({ isMultiple, forceSelection, completeMethod, ref });\n\n const hasThemeStyle = Object.keys(themeStyle).length > 0;\n\n\n const Element = <AutoComplete\n disabled={disabled}\n placeholder={placeholder}\n value={inputValue}\n forceSelection={forceSelection}\n suggestions={Array.isArray(filteredList) ? filteredList : list}\n completeMethod={search}\n dropdown={withArrow}\n multiple={isMultiple}\n field={labelKey}\n invalid={!!invalid}\n emptyMessage={emptyMessage ?? \"No results found\"}\n {...(delay != null ? { delay } : {})}\n {...(minLength != null ? { minLength } : {})}\n {...(selectionLimit != null ? { selectionLimit } : {})}\n showEmptyMessage={showEmptyMessage ?? true}\n optionGroupChildren={childrenKey ?? undefined}\n optionGroupLabel={childrenKey ? labelKey : undefined}\n style={{ width: \"100%\", borderRadius: 0, border:'none', backgroundColor:'transparent' }}\n inputStyle={{ flexDirection: \"row\", borderRadius: 0, border:'none', width: \"100%\",backgroundColor:'transparent', ...(resolvedRootStyle || resolvedThemeStyle) }}\n tokenContainerStyle={resolvedTokenContainer}\n tokenStyle={tokenBoxStyle}\n tokenLabelStyle={tokenLabelStyle}\n tokenIconStyle={resolvedTokenIcon}\n onChange={(event) => {\n setInputValue(event.value);\n handleOnChange(event);\n }}\n {...(localProps ?? {})}\n />\n\n if (attached) {\n return Element;\n }\n\n // KitsContainer's `inputGroup` wrapper defaults to `overflow: 'hidden'`\n // (so rounded borders clip the input cleanly). For AutoComplete that\n // would clip the floating suggestions panel back to the input's bounds\n // — the panel renders but is invisible, which is the \"list never\n // appears\" symptom on mobile. Force `overflow: 'visible'` on the\n // container chain so the panel can escape.\n const overflowEscape = {\n ...elementStyles,\n container: {\n ...(elementStyles?.container || {}),\n overflow: 'visible' as const,\n },\n inputGroup: {\n ...(elementStyles?.inputGroup || {}),\n overflow: 'visible' as const,\n },\n };\n\n return (\n <KitsContainer\n id={id}\n inputSize={inputSize}\n isFloatedLabel={isFloatedLabel}\n hideError={hideError}\n rightAddon={rightAddon}\n leftAddon={leftAddon}\n required={required}\n helperText={helperText}\n errors={errors}\n invalid={invalid}\n label={label}\n containerStyle={containerStyle}\n elementStyles={overflowEscape}\n elementProps={elementProps}\n >\n {Element}\n </KitsContainer>\n );\n};\n\nexport default KitsAutoComplete;\n"],"names":["useComponentDefaults","useResolvedStyle","splitTextStyle","useSeparator","useKitsTheme","useAutoCompleteLogic","jsx","AutoComplete","KitsContainer"],"mappings":"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"}
|
|
@@ -87,13 +87,17 @@ import '../../../contexts/DialogContext.js';
|
|
|
87
87
|
import '../../../contexts/PermissionsContext.js';
|
|
88
88
|
import '../../../contexts/BreadcrumbContext.js';
|
|
89
89
|
import useComponentDefaults from '../../../hooks/useComponentDefaults.js';
|
|
90
|
-
import useResolvedStyle from '../../../hooks/useResolvedStyle.js';
|
|
90
|
+
import useResolvedStyle, { splitTextStyle } from '../../../hooks/useResolvedStyle.js';
|
|
91
91
|
import { useKitsTheme } from '../../../contexts/Theme/KitsThemeProvider.js';
|
|
92
92
|
|
|
93
93
|
const KitsAutoComplete = ({ ref, ...rawProps }) => {
|
|
94
|
-
const { mergedProps: props, themeStyle, elementStyles } = useComponentDefaults("AutoComplete", rawProps, "Select");
|
|
94
|
+
const { mergedProps: props, themeStyle, elementStyles, elementProps } = useComponentDefaults("AutoComplete", rawProps, "Select");
|
|
95
95
|
const resolvedThemeStyle = useResolvedStyle(themeStyle);
|
|
96
96
|
const resolvedRootStyle = useResolvedStyle(elementStyles?.root || {});
|
|
97
|
+
const resolvedTokenContainer = useResolvedStyle(elementStyles?.tokenContainer || {});
|
|
98
|
+
const resolvedToken = useResolvedStyle(elementStyles?.token || {});
|
|
99
|
+
const resolvedTokenIcon = useResolvedStyle(elementStyles?.tokenIcon || {});
|
|
100
|
+
const { wrapper: tokenBoxStyle, text: tokenLabelStyle } = splitTextStyle(resolvedToken);
|
|
97
101
|
const {
|
|
98
102
|
id,
|
|
99
103
|
rightAddon,
|
|
@@ -158,6 +162,10 @@ const KitsAutoComplete = ({ ref, ...rawProps }) => {
|
|
|
158
162
|
optionGroupLabel: childrenKey ? labelKey : void 0,
|
|
159
163
|
style: { width: "100%", borderRadius: 0, border: "none", backgroundColor: "transparent" },
|
|
160
164
|
inputStyle: { flexDirection: "row", borderRadius: 0, border: "none", width: "100%", backgroundColor: "transparent", ...resolvedRootStyle || resolvedThemeStyle },
|
|
165
|
+
tokenContainerStyle: resolvedTokenContainer,
|
|
166
|
+
tokenStyle: tokenBoxStyle,
|
|
167
|
+
tokenLabelStyle,
|
|
168
|
+
tokenIconStyle: resolvedTokenIcon,
|
|
161
169
|
onChange: (event) => {
|
|
162
170
|
setInputValue(event.value);
|
|
163
171
|
handleOnChange(event);
|
|
@@ -195,6 +203,7 @@ const KitsAutoComplete = ({ ref, ...rawProps }) => {
|
|
|
195
203
|
label,
|
|
196
204
|
containerStyle,
|
|
197
205
|
elementStyles: overflowEscape,
|
|
206
|
+
elementProps,
|
|
198
207
|
children: Element
|
|
199
208
|
}
|
|
200
209
|
);
|