@lmb-it/kitsconcerto-native 0.1.285 → 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/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/hooks/useComponentDefaults.cjs +12 -0
- package/hooks/useComponentDefaults.cjs.map +1 -1
- package/hooks/useComponentDefaults.js +12 -0
- package/hooks/useComponentDefaults.js.map +1 -1
- package/index.cjs +120 -115
- package/index.cjs.map +1 -1
- package/index.d.ts +394 -3
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/package.json +13 -1
- package/packages/types/src/Theme/defaultTheme.cjs +111 -0
- package/packages/types/src/Theme/defaultTheme.cjs.map +1 -1
- package/packages/types/src/Theme/defaultTheme.js +111 -0
- 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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"}
|
|
@@ -136,6 +136,18 @@ const ELEMENT_SLOT_KEYS = /* @__PURE__ */ new Set([
|
|
|
136
136
|
"topBar",
|
|
137
137
|
"bulkBar",
|
|
138
138
|
"bulkBarText",
|
|
139
|
+
// ImageCropper (IImageCropperSlots). The other slots it uses — root,
|
|
140
|
+
// container, header, title, content, footer, icon, text, mask, track,
|
|
141
|
+
// thumb — are already in this set under the components that named them
|
|
142
|
+
// first, which is the point of reusing those names.
|
|
143
|
+
"cropWindow",
|
|
144
|
+
"shade",
|
|
145
|
+
"gridLine",
|
|
146
|
+
"handle",
|
|
147
|
+
"zoomChip",
|
|
148
|
+
"previewFrame",
|
|
149
|
+
"dropZone",
|
|
150
|
+
"progressFill",
|
|
139
151
|
// Accordion
|
|
140
152
|
"headerActive",
|
|
141
153
|
"headerHover",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useComponentDefaults.cjs","sources":["../../../src/hooks/useComponentDefaults.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\n\n/**\n * Known element slot keys. When a config key matches one of these\n * AND the value has `props` or `style`, it is treated as an element slot.\n *\n * To add a new slot: add the key here AND to the relevant slot interface\n * in packages/types/src/Theme/types.ts (and to the `AllSlotKeys` union).\n *\n * The order below mirrors the typed slot hierarchy in\n * `packages/types/src/Theme/types.ts`.\n */\nconst ELEMENT_SLOT_KEYS = new Set([\n // ── Form-element slots ──────────────────────────────────\n // Base (all form elements — IFormElementBaseSlots)\n 'label', 'helperText', 'error',\n // Text input specific (ITextInputSlots — also shared by ISelectSlots)\n 'root', 'container', 'inputGroup', 'leftAddon', 'rightAddon',\n // Select specific (ISelectSlots — option-list popover)\n // Radio / Checkbox also use `item` / `itemSelected` / `itemDisabled` /\n // `itemHover` for the per-list-item wrapper, plus `itemInvalid`.\n 'panel', 'item', 'itemSelected', 'itemFocused', 'itemHover', 'itemDisabled', 'itemInvalid',\n // Chip-bearing selects (IChipInputSlots — MultiSelect display=\"chip\"\n // AND AutoComplete/Tags with isMultiple). `tokenContainer` is the\n // bordered box that holds the chips and the caret — see the docblock\n // on IChipInputSlots for why it is neither `root` nor `container`.\n 'tokenContainer', 'token', 'tokenIcon',\n // MultiSelect specific (IMultiSelectSlots — per-item checkbox)\n 'checkboxBox', 'checkboxBoxChecked', 'checkboxIcon',\n // Datepicker specific (IDatepickerSlots — calendar popup; `panel` shared with Select)\n 'calendarHeader', 'calendarNavButton', 'weekDay',\n 'dayCell', 'daySelected', 'dayToday', 'dayDisabled',\n // Switch specific (ISwitchSlots) — RENAMED from slider/sliderChecked/thumbChecked\n 'track', 'trackOn', 'thumb', 'thumbOn',\n // Checkbox specific (ICheckboxSlots)\n 'box', 'boxChecked', 'checkIcon',\n // Radio specific (IRadioSlots)\n 'circle', 'circleInner',\n // Radio + Checkbox: wrapper Flex around all list items\n 'itemsContainer',\n\n // ── Non-form component slots (untouched by the form-element refactor) ──\n // Card / Button / generic\n 'icon', 'header', 'title', 'subTitle', 'content', 'footer',\n // Button variants — `text` applies only to buttons with a label,\n // `iconOnly` applies only to icon-only buttons (so styling one never\n // affects the other).\n 'text', 'iconOnly',\n // Table\n 'th', 'headerRow', 'headerCell', 'body', 'bodyRow', 'bodyCell',\n 'wrapper', 'table', 'tbody',\n 'filterRow', 'filterCell', 'filterClearButton',\n 'columnFilter', 'columnFilterInput',\n 'tfoot', 'footerRow', 'footerCell', 'footer', 'paginator', 'emptyMessage',\n 'loadingOverlay', 'loadingIcon',\n 'rowGroupHeader', 'rowGroupHeaderName', 'rowExpansion', 'rowGroupFooter',\n 'rowGroupToggler', 'rowGroupTogglerIcon',\n 'resizeHelper',\n 'reorderIndicatorUp', 'reorderIndicatorUpIcon',\n 'reorderIndicatorDown', 'reorderIndicatorDownIcon',\n 'tableHeader', 'searchInput',\n 'paginatorPageButton', 'paginatorPageLink', 'paginatorActivePageButton',\n 'paginatorPageReport', 'paginatorRowsPerPage', 'paginatorRowsPerPageDropdown',\n 'paginatorPages',\n 'sortedColumn', 'stripedRow', 'selectedRow', 'selectedRowAccent',\n 'filterBar', 'filterInput', 'filterLabel',\n 'toolbarRight', 'toolbarButton', 'clearFilterButton', 'columnPicker',\n // Toolbar sizing + placeholder, and the chrome the table renders itself.\n // NOTE: a slot missing from this allowlist is silently dropped — theming\n // it has no effect at all — so every new slot must be listed here as\n // well as in its component's ITableElementSlots.\n 'toolbarControl', 'filterPlaceholder',\n 'topBar', 'bulkBar', 'bulkBarText',\n // Accordion\n 'headerActive', 'headerHover',\n // Sidebar/Drawer\n 'headerTitle', 'closeButton', 'mask',\n // Group (repeatable field array)\n 'row', 'addButton', 'removeButton',\n // Header (app-shell top bar)\n 'toggleModeButton', 'avatarButton', 'breadcrumb',\n]);\n\nexport interface IElementConfig {\n style: Record<string, any>;\n /**\n * Extra attributes for this slot's element — `className`, `data-*`,\n * `aria-*`, anything the platform element accepts. Merged across the\n * whole chain (FormElement < baseGroup < component < instance slots),\n * with `className` CONCATENATED rather than replaced.\n */\n props: Record<string, any>;\n important?: boolean | string[];\n pseudo?: Record<string, Record<string, any>>;\n}\n\nexport interface UseComponentDefaultsResult<T> {\n /** Props with theme defaults merged in (user props always win) */\n mergedProps: T;\n /**\n * CSS style from root slot — backwards compat for components\n * that read themeStyle instead of elementStyles.root\n */\n themeStyle: Record<string, any>;\n /**\n * Per-element style maps. Each key is a slot name, value is the\n * merged IStyleClasses (not yet resolved to CSSProperties).\n * Use `useResolvedElementStyles(elementStyles)` to resolve.\n */\n elementStyles: Record<string, Record<string, any>>;\n /**\n * Per-element extra attributes. Each key is a slot name, value is the\n * merged `props` for that slot (`className`, `data-*`, `aria-*`, …).\n *\n * ⛔ EVERY SLOT, NOT JUST `root` — THAT WAS THE BUG. `IElementSlotConfig`\n * has advertised `props` on every slot since the slot system landed, but\n * only `root.props` was ever read (it is folded into `mergedProps`).\n * Anything a consumer put on another slot — the class a portal needs on a\n * tags field's outer box to make it match a text input — was parsed,\n * merged, and then thrown away with no warning and no type error.\n * Components apply `elementProps[slot]` to the matching element.\n */\n elementProps: Record<string, Record<string, any>>;\n /**\n * Full slot configs including `props`, `important` and `pseudo` fields.\n * Use this instead of `elementStyles` when you need those fields.\n */\n elementConfigs: Record<string, IElementConfig>;\n}\n\n/**\n * Merges slot `props` layers. Everything is last-wins EXCEPT `className`,\n * which is concatenated — a theme-level class and a consumer's class are\n * additive by nature, and dropping one of them is exactly the fault this\n * whole plumbing exists to fix.\n */\nfunction mergeSlotProps(layers: Array<Record<string, any> | undefined>): Record<string, any> {\n const out: Record<string, any> = {};\n const classes: string[] = [];\n for (const layer of layers) {\n if (!layer) continue;\n for (const [key, value] of Object.entries(layer)) {\n if (value === undefined) continue;\n if (key === 'className') {\n if (value) classes.push(String(value));\n } else {\n out[key] = value;\n }\n }\n }\n if (classes.length) {\n // De-duplicated, so a class repeated down the chain lands once.\n out.className = Array.from(new Set(classes.join(' ').split(/\\s+/).filter(Boolean))).join(' ');\n }\n return out;\n}\n\n/**\n * Merges theme-level component defaults with user-supplied props.\n *\n * Resolution chain (lowest → highest priority):\n * FormElement[slot] < baseGroup[slot] < component[slot] < instanceSlots[slot] < user props\n *\n * `FormElement` is the global base group for every form element\n * (label / helperText / error live there by default). It is applied\n * to every component regardless of whether a `baseGroup` is provided\n * — for non-form components like Button or Card, FormElement slots\n * are no-ops in practice because those components don't read\n * `elementStyles.label` / `helperText` / `error`.\n *\n * Element slots (`root`, `label`, `container`, etc.) are direct keys\n * on the component config. Each slot accepts `{ props?, style? }`.\n *\n * The `root` slot's `props` are merged into `mergedProps` alongside\n * user props (user always wins, except `className`, which concatenates).\n * The `root` slot's `style` is returned as both `themeStyle` (backwards\n * compat) and `elementStyles.root`.\n *\n * EVERY OTHER slot's `props` come back on `elementProps[slot]` — the\n * component is responsible for spreading them onto the element that slot\n * names. Before that existed, `props` on a non-root slot was silently\n * discarded, which is how a consumer's class on a tags field's outer box\n * disappeared without a single error.\n *\n * Supports base-group inheritance: e.g. `useComponentDefaults('InputText', rawProps, 'Input')`\n * merges FormElement first, then Input base, then InputText overrides,\n * then per-instance slots, then user props.\n *\n * @example\n * const { mergedProps, themeStyle, elementStyles } = useComponentDefaults('InputText', rawProps, 'Input');\n * // mergedProps → FormElement.root.props < Input.root.props < InputText.root.props < instanceSlots < user props\n * // elementStyles.label → FormElement.label.style < Input.label.style < InputText.label.style < instance label\n * // elementStyles.root → root element style (FormElement → Input → InputText → instance)\n * // elementStyles.container → container element style\n */\nexport default function useComponentDefaults<T extends Record<string, any>>(\n componentName: string,\n props: T,\n baseGroup?: string,\n): UseComponentDefaultsResult<T> {\n const {theme} = useKitsTheme();\n // Global base for every form element. Always looked up — if not\n // configured it is `undefined` and the merge contributes nothing.\n const formElementConfig = theme.components.FormElement;\n const baseConfig = baseGroup ? theme.components[baseGroup] : undefined;\n const config = theme.components[componentName];\n\n return useMemo(() => {\n // Extract per-instance slot overrides from props (IFormElement.slots passed through)\n const instanceSlots = (props as any).slots as Record<string, { props?: any; style?: any; important?: boolean | string[]; pseudo?: Record<string, Record<string, any>> }> | undefined;\n\n if (!config && !baseConfig && !instanceSlots && !formElementConfig) {\n return {mergedProps: props, themeStyle: {}, elementStyles: {}, elementProps: {}, elementConfigs: {}};\n }\n\n const formBase = (formElementConfig || {}) as Record<string, any>;\n const base = (baseConfig || {}) as Record<string, any>;\n const comp = (config || {}) as Record<string, any>;\n\n // --- Props merge: FormElement.root.props < base.root.props < config.root.props < instanceSlots.root.props < user props ---\n const merged = mergeSlotProps([\n formBase.root?.props,\n base.root?.props,\n comp.root?.props,\n instanceSlots?.root?.props,\n ]);\n\n const userClassName = typeof (props as any).className === 'string' ? (props as any).className : undefined;\n for (const key of Object.keys(props)) {\n // Skip 'slots' — it is consumed here, not forwarded\n if (key === 'slots') continue;\n // className is additive, not a replacement: a theme-level class on\n // `root.props` and the consumer's own class both have to survive.\n if (key === 'className') continue;\n if (props[key] !== undefined) {\n merged[key] = props[key];\n }\n }\n if (userClassName || merged.className) {\n merged.className = mergeSlotProps([\n {className: merged.className},\n {className: userClassName},\n ]).className;\n }\n\n // --- Element styles merge: FormElement[slot] < base[slot] < config[slot] < instanceSlots[slot] ---\n const allSlotKeys = new Set<string>();\n for (const key of Object.keys(formBase)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(base)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(comp)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n if (instanceSlots) {\n for (const key of Object.keys(instanceSlots)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n }\n\n const elementStyles: Record<string, Record<string, any>> = {};\n const elementProps: Record<string, Record<string, any>> = {};\n const elementConfigs: Record<string, IElementConfig> = {};\n for (const slotKey of allSlotKeys) {\n const style = {\n ...(formBase[slotKey]?.style || {}),\n ...(base[slotKey]?.style || {}),\n ...(comp[slotKey]?.style || {}),\n ...(instanceSlots?.[slotKey]?.style || {}),\n };\n elementStyles[slotKey] = style;\n\n const slotProps = mergeSlotProps([\n formBase[slotKey]?.props,\n base[slotKey]?.props,\n comp[slotKey]?.props,\n instanceSlots?.[slotKey]?.props,\n ]);\n elementProps[slotKey] = slotProps;\n\n const pseudoMerged = {\n ...(formBase[slotKey]?.pseudo || {}),\n ...(base[slotKey]?.pseudo || {}),\n ...(comp[slotKey]?.pseudo || {}),\n ...(instanceSlots?.[slotKey]?.pseudo || {}),\n };\n elementConfigs[slotKey] = {\n style,\n props: slotProps,\n important:\n instanceSlots?.[slotKey]?.important ??\n comp[slotKey]?.important ??\n base[slotKey]?.important ??\n formBase[slotKey]?.important,\n pseudo: Object.keys(pseudoMerged).length > 0 ? pseudoMerged : undefined,\n };\n }\n\n // themeStyle = root element style (backwards compat)\n const themeStyle = elementStyles.root || {};\n\n return {\n mergedProps: merged as T,\n themeStyle,\n elementStyles,\n elementProps,\n elementConfigs,\n };\n }, [formElementConfig, baseConfig, config, props]);\n}\n"],"names":["useKitsTheme","useMemo"],"mappings":";;;;;;;AAaA,MAAM,iBAAA,uBAAwB,GAAA,CAAI;AAAA;AAAA;AAAA,EAG9B,OAAA;AAAA,EAAS,YAAA;AAAA,EAAc,OAAA;AAAA;AAAA,EAEvB,MAAA;AAAA,EAAQ,WAAA;AAAA,EAAa,YAAA;AAAA,EAAc,WAAA;AAAA,EAAa,YAAA;AAAA;AAAA;AAAA;AAAA,EAIhD,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,cAAA;AAAA,EAAgB,aAAA;AAAA,EAAe,WAAA;AAAA,EAAa,cAAA;AAAA,EAAgB,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7E,gBAAA;AAAA,EAAkB,OAAA;AAAA,EAAS,WAAA;AAAA;AAAA,EAE3B,aAAA;AAAA,EAAe,oBAAA;AAAA,EAAsB,cAAA;AAAA;AAAA,EAErC,gBAAA;AAAA,EAAkB,mBAAA;AAAA,EAAqB,SAAA;AAAA,EACvC,SAAA;AAAA,EAAW,aAAA;AAAA,EAAe,UAAA;AAAA,EAAY,aAAA;AAAA;AAAA,EAEtC,OAAA;AAAA,EAAS,SAAA;AAAA,EAAW,OAAA;AAAA,EAAS,SAAA;AAAA;AAAA,EAE7B,KAAA;AAAA,EAAO,YAAA;AAAA,EAAc,WAAA;AAAA;AAAA,EAErB,QAAA;AAAA,EAAU,aAAA;AAAA;AAAA,EAEV,gBAAA;AAAA;AAAA;AAAA,EAIA,MAAA;AAAA,EAAQ,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,UAAA;AAAA,EAAY,SAAA;AAAA,EAAW,QAAA;AAAA;AAAA;AAAA;AAAA,EAIlD,MAAA;AAAA,EAAQ,UAAA;AAAA;AAAA,EAER,IAAA;AAAA,EAAM,WAAA;AAAA,EAAa,YAAA;AAAA,EAAc,MAAA;AAAA,EAAQ,SAAA;AAAA,EAAW,UAAA;AAAA,EACpD,SAAA;AAAA,EAAW,OAAA;AAAA,EAAS,OAAA;AAAA,EACpB,WAAA;AAAA,EAAa,YAAA;AAAA,EAAc,mBAAA;AAAA,EAC3B,cAAA;AAAA,EAAgB,mBAAA;AAAA,EAChB,OAAA;AAAA,EAAS,WAAA;AAAA,EAAa,YAAA;AAAA,EAAc,QAAA;AAAA,EAAU,WAAA;AAAA,EAAa,cAAA;AAAA,EAC3D,gBAAA;AAAA,EAAkB,aAAA;AAAA,EAClB,gBAAA;AAAA,EAAkB,oBAAA;AAAA,EAAsB,cAAA;AAAA,EAAgB,gBAAA;AAAA,EACxD,iBAAA;AAAA,EAAmB,qBAAA;AAAA,EACnB,cAAA;AAAA,EACA,oBAAA;AAAA,EAAsB,wBAAA;AAAA,EACtB,sBAAA;AAAA,EAAwB,0BAAA;AAAA,EACxB,aAAA;AAAA,EAAe,aAAA;AAAA,EACf,qBAAA;AAAA,EAAuB,mBAAA;AAAA,EAAqB,2BAAA;AAAA,EAC5C,qBAAA;AAAA,EAAuB,sBAAA;AAAA,EAAwB,8BAAA;AAAA,EAC/C,gBAAA;AAAA,EACA,cAAA;AAAA,EAAgB,YAAA;AAAA,EAAc,aAAA;AAAA,EAAe,mBAAA;AAAA,EAC7C,WAAA;AAAA,EAAa,aAAA;AAAA,EAAe,aAAA;AAAA,EAC5B,cAAA;AAAA,EAAgB,eAAA;AAAA,EAAiB,mBAAA;AAAA,EAAqB,cAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKtD,gBAAA;AAAA,EAAkB,mBAAA;AAAA,EAClB,QAAA;AAAA,EAAU,SAAA;AAAA,EAAW,aAAA;AAAA;AAAA,EAErB,cAAA;AAAA,EAAgB,aAAA;AAAA;AAAA,EAEhB,aAAA;AAAA,EAAe,aAAA;AAAA,EAAe,MAAA;AAAA;AAAA,EAE9B,KAAA;AAAA,EAAO,WAAA;AAAA,EAAa,cAAA;AAAA;AAAA,EAEpB,kBAAA;AAAA,EAAoB,cAAA;AAAA,EAAgB;AACxC,CAAC,CAAA;AAuDD,SAAS,eAAe,MAAA,EAAqE;AACzF,EAAA,MAAM,MAA2B,EAAC;AAClC,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AACxB,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC9C,MAAA,IAAI,UAAU,MAAA,EAAW;AACzB,MAAA,IAAI,QAAQ,WAAA,EAAa;AACrB,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,MACzC,CAAA,MAAO;AACH,QAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,MACf;AAAA,IACJ;AAAA,EACJ;AACA,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAEhB,IAAA,GAAA,CAAI,YAAY,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,OAAA,CAAQ,KAAK,GAAG,CAAA,CAAE,KAAA,CAAM,KAAK,EAAE,MAAA,CAAO,OAAO,CAAC,CAAC,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,EAChG;AACA,EAAA,OAAO,GAAA;AACX;AAwCA,SAAwB,oBAAA,CACpB,aAAA,EACA,KAAA,EACA,SAAA,EAC6B;AAC7B,EAAA,MAAM,EAAC,KAAA,EAAK,GAAIA,qCAAA,EAAa;AAG7B,EAAA,MAAM,iBAAA,GAAoB,MAAM,UAAA,CAAW,WAAA;AAC3C,EAAA,MAAM,UAAA,GAAa,SAAA,GAAY,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA,GAAI,MAAA;AAC7D,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,UAAA,CAAW,aAAa,CAAA;AAE7C,EAAA,OAAOC,cAAQ,MAAM;AAEjB,IAAA,MAAM,gBAAiB,KAAA,CAAc,KAAA;AAErC,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,cAAc,CAAC,aAAA,IAAiB,CAAC,iBAAA,EAAmB;AAChE,MAAA,OAAO,EAAC,WAAA,EAAa,KAAA,EAAO,UAAA,EAAY,EAAC,EAAG,aAAA,EAAe,EAAC,EAAG,YAAA,EAAc,EAAC,EAAG,cAAA,EAAgB,EAAC,EAAC;AAAA,IACvG;AAEA,IAAA,MAAM,QAAA,GAAY,qBAAqB,EAAC;AACxC,IAAA,MAAM,IAAA,GAAQ,cAAc,EAAC;AAC7B,IAAA,MAAM,IAAA,GAAQ,UAAU,EAAC;AAGzB,IAAA,MAAM,SAAS,cAAA,CAAe;AAAA,MAC1B,SAAS,IAAA,EAAM,KAAA;AAAA,MACf,KAAK,IAAA,EAAM,KAAA;AAAA,MACX,KAAK,IAAA,EAAM,KAAA;AAAA,MACX,eAAe,IAAA,EAAM;AAAA,KACxB,CAAA;AAED,IAAA,MAAM,gBAAgB,OAAQ,KAAA,CAAc,SAAA,KAAc,QAAA,GAAY,MAAc,SAAA,GAAY,MAAA;AAChG,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,EAAG;AAElC,MAAA,IAAI,QAAQ,OAAA,EAAS;AAGrB,MAAA,IAAI,QAAQ,WAAA,EAAa;AACzB,MAAA,IAAI,KAAA,CAAM,GAAG,CAAA,KAAM,MAAA,EAAW;AAC1B,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,KAAA,CAAM,GAAG,CAAA;AAAA,MAC3B;AAAA,IACJ;AACA,IAAA,IAAI,aAAA,IAAiB,OAAO,SAAA,EAAW;AACnC,MAAA,MAAA,CAAO,YAAY,cAAA,CAAe;AAAA,QAC9B,EAAC,SAAA,EAAW,MAAA,CAAO,SAAA,EAAS;AAAA,QAC5B,EAAC,WAAW,aAAA;AAAa,OAC5B,CAAA,CAAE,SAAA;AAAA,IACP;AAGA,IAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,EAAG;AACrC,MAAA,IAAI,kBAAkB,GAAA,CAAI,GAAG,CAAA,EAAG,WAAA,CAAY,IAAI,GAAG,CAAA;AAAA,IACvD;AACA,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,EAAG;AACjC,MAAA,IAAI,kBAAkB,GAAA,CAAI,GAAG,CAAA,EAAG,WAAA,CAAY,IAAI,GAAG,CAAA;AAAA,IACvD;AACA,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,EAAG;AACjC,MAAA,IAAI,kBAAkB,GAAA,CAAI,GAAG,CAAA,EAAG,WAAA,CAAY,IAAI,GAAG,CAAA;AAAA,IACvD;AACA,IAAA,IAAI,aAAA,EAAe;AACf,MAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA,EAAG;AAC1C,QAAA,IAAI,kBAAkB,GAAA,CAAI,GAAG,CAAA,EAAG,WAAA,CAAY,IAAI,GAAG,CAAA;AAAA,MACvD;AAAA,IACJ;AAEA,IAAA,MAAM,gBAAqD,EAAC;AAC5D,IAAA,MAAM,eAAoD,EAAC;AAC3D,IAAA,MAAM,iBAAiD,EAAC;AACxD,IAAA,KAAA,MAAW,WAAW,WAAA,EAAa;AAC/B,MAAA,MAAM,KAAA,GAAQ;AAAA,QACV,GAAI,QAAA,CAAS,OAAO,CAAA,EAAG,SAAS,EAAC;AAAA,QACjC,GAAI,IAAA,CAAK,OAAO,CAAA,EAAG,SAAS,EAAC;AAAA,QAC7B,GAAI,IAAA,CAAK,OAAO,CAAA,EAAG,SAAS,EAAC;AAAA,QAC7B,GAAI,aAAA,GAAgB,OAAO,CAAA,EAAG,SAAS;AAAC,OAC5C;AACA,MAAA,aAAA,CAAc,OAAO,CAAA,GAAI,KAAA;AAEzB,MAAA,MAAM,YAAY,cAAA,CAAe;AAAA,QAC7B,QAAA,CAAS,OAAO,CAAA,EAAG,KAAA;AAAA,QACnB,IAAA,CAAK,OAAO,CAAA,EAAG,KAAA;AAAA,QACf,IAAA,CAAK,OAAO,CAAA,EAAG,KAAA;AAAA,QACf,aAAA,GAAgB,OAAO,CAAA,EAAG;AAAA,OAC7B,CAAA;AACD,MAAA,YAAA,CAAa,OAAO,CAAA,GAAI,SAAA;AAExB,MAAA,MAAM,YAAA,GAAe;AAAA,QACjB,GAAI,QAAA,CAAS,OAAO,CAAA,EAAG,UAAU,EAAC;AAAA,QAClC,GAAI,IAAA,CAAK,OAAO,CAAA,EAAG,UAAU,EAAC;AAAA,QAC9B,GAAI,IAAA,CAAK,OAAO,CAAA,EAAG,UAAU,EAAC;AAAA,QAC9B,GAAI,aAAA,GAAgB,OAAO,CAAA,EAAG,UAAU;AAAC,OAC7C;AACA,MAAA,cAAA,CAAe,OAAO,CAAA,GAAI;AAAA,QACtB,KAAA;AAAA,QACA,KAAA,EAAO,SAAA;AAAA,QACP,SAAA,EACI,aAAA,GAAgB,OAAO,CAAA,EAAG,aAC1B,IAAA,CAAK,OAAO,CAAA,EAAG,SAAA,IACf,KAAK,OAAO,CAAA,EAAG,SAAA,IACf,QAAA,CAAS,OAAO,CAAA,EAAG,SAAA;AAAA,QACvB,QAAQ,MAAA,CAAO,IAAA,CAAK,YAAY,CAAA,CAAE,MAAA,GAAS,IAAI,YAAA,GAAe;AAAA,OAClE;AAAA,IACJ;AAGA,IAAA,MAAM,UAAA,GAAa,aAAA,CAAc,IAAA,IAAQ,EAAC;AAE1C,IAAA,OAAO;AAAA,MACH,WAAA,EAAa,MAAA;AAAA,MACb,UAAA;AAAA,MACA,aAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACJ;AAAA,EACJ,GAAG,CAAC,iBAAA,EAAmB,UAAA,EAAY,MAAA,EAAQ,KAAK,CAAC,CAAA;AACrD;;;;"}
|
|
1
|
+
{"version":3,"file":"useComponentDefaults.cjs","sources":["../../../src/hooks/useComponentDefaults.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\n\n/**\n * Known element slot keys. When a config key matches one of these\n * AND the value has `props` or `style`, it is treated as an element slot.\n *\n * To add a new slot: add the key here AND to the relevant slot interface\n * in packages/types/src/Theme/types.ts (and to the `AllSlotKeys` union).\n *\n * The order below mirrors the typed slot hierarchy in\n * `packages/types/src/Theme/types.ts`.\n */\nconst ELEMENT_SLOT_KEYS = new Set([\n // ── Form-element slots ──────────────────────────────────\n // Base (all form elements — IFormElementBaseSlots)\n 'label', 'helperText', 'error',\n // Text input specific (ITextInputSlots — also shared by ISelectSlots)\n 'root', 'container', 'inputGroup', 'leftAddon', 'rightAddon',\n // Select specific (ISelectSlots — option-list popover)\n // Radio / Checkbox also use `item` / `itemSelected` / `itemDisabled` /\n // `itemHover` for the per-list-item wrapper, plus `itemInvalid`.\n 'panel', 'item', 'itemSelected', 'itemFocused', 'itemHover', 'itemDisabled', 'itemInvalid',\n // Chip-bearing selects (IChipInputSlots — MultiSelect display=\"chip\"\n // AND AutoComplete/Tags with isMultiple). `tokenContainer` is the\n // bordered box that holds the chips and the caret — see the docblock\n // on IChipInputSlots for why it is neither `root` nor `container`.\n 'tokenContainer', 'token', 'tokenIcon',\n // MultiSelect specific (IMultiSelectSlots — per-item checkbox)\n 'checkboxBox', 'checkboxBoxChecked', 'checkboxIcon',\n // Datepicker specific (IDatepickerSlots — calendar popup; `panel` shared with Select)\n 'calendarHeader', 'calendarNavButton', 'weekDay',\n 'dayCell', 'daySelected', 'dayToday', 'dayDisabled',\n // Switch specific (ISwitchSlots) — RENAMED from slider/sliderChecked/thumbChecked\n 'track', 'trackOn', 'thumb', 'thumbOn',\n // Checkbox specific (ICheckboxSlots)\n 'box', 'boxChecked', 'checkIcon',\n // Radio specific (IRadioSlots)\n 'circle', 'circleInner',\n // Radio + Checkbox: wrapper Flex around all list items\n 'itemsContainer',\n\n // ── Non-form component slots (untouched by the form-element refactor) ──\n // Card / Button / generic\n 'icon', 'header', 'title', 'subTitle', 'content', 'footer',\n // Button variants — `text` applies only to buttons with a label,\n // `iconOnly` applies only to icon-only buttons (so styling one never\n // affects the other).\n 'text', 'iconOnly',\n // Table\n 'th', 'headerRow', 'headerCell', 'body', 'bodyRow', 'bodyCell',\n 'wrapper', 'table', 'tbody',\n 'filterRow', 'filterCell', 'filterClearButton',\n 'columnFilter', 'columnFilterInput',\n 'tfoot', 'footerRow', 'footerCell', 'footer', 'paginator', 'emptyMessage',\n 'loadingOverlay', 'loadingIcon',\n 'rowGroupHeader', 'rowGroupHeaderName', 'rowExpansion', 'rowGroupFooter',\n 'rowGroupToggler', 'rowGroupTogglerIcon',\n 'resizeHelper',\n 'reorderIndicatorUp', 'reorderIndicatorUpIcon',\n 'reorderIndicatorDown', 'reorderIndicatorDownIcon',\n 'tableHeader', 'searchInput',\n 'paginatorPageButton', 'paginatorPageLink', 'paginatorActivePageButton',\n 'paginatorPageReport', 'paginatorRowsPerPage', 'paginatorRowsPerPageDropdown',\n 'paginatorPages',\n 'sortedColumn', 'stripedRow', 'selectedRow', 'selectedRowAccent',\n 'filterBar', 'filterInput', 'filterLabel',\n 'toolbarRight', 'toolbarButton', 'clearFilterButton', 'columnPicker',\n // Toolbar sizing + placeholder, and the chrome the table renders itself.\n // NOTE: a slot missing from this allowlist is silently dropped — theming\n // it has no effect at all — so every new slot must be listed here as\n // well as in its component's ITableElementSlots.\n 'toolbarControl', 'filterPlaceholder',\n 'topBar', 'bulkBar', 'bulkBarText',\n // ImageCropper (IImageCropperSlots). The other slots it uses — root,\n // container, header, title, content, footer, icon, text, mask, track,\n // thumb — are already in this set under the components that named them\n // first, which is the point of reusing those names.\n 'cropWindow', 'shade', 'gridLine', 'handle',\n 'zoomChip', 'previewFrame', 'dropZone', 'progressFill',\n // Accordion\n 'headerActive', 'headerHover',\n // Sidebar/Drawer\n 'headerTitle', 'closeButton', 'mask',\n // Group (repeatable field array)\n 'row', 'addButton', 'removeButton',\n // Header (app-shell top bar)\n 'toggleModeButton', 'avatarButton', 'breadcrumb',\n]);\n\nexport interface IElementConfig {\n style: Record<string, any>;\n /**\n * Extra attributes for this slot's element — `className`, `data-*`,\n * `aria-*`, anything the platform element accepts. Merged across the\n * whole chain (FormElement < baseGroup < component < instance slots),\n * with `className` CONCATENATED rather than replaced.\n */\n props: Record<string, any>;\n important?: boolean | string[];\n pseudo?: Record<string, Record<string, any>>;\n}\n\nexport interface UseComponentDefaultsResult<T> {\n /** Props with theme defaults merged in (user props always win) */\n mergedProps: T;\n /**\n * CSS style from root slot — backwards compat for components\n * that read themeStyle instead of elementStyles.root\n */\n themeStyle: Record<string, any>;\n /**\n * Per-element style maps. Each key is a slot name, value is the\n * merged IStyleClasses (not yet resolved to CSSProperties).\n * Use `useResolvedElementStyles(elementStyles)` to resolve.\n */\n elementStyles: Record<string, Record<string, any>>;\n /**\n * Per-element extra attributes. Each key is a slot name, value is the\n * merged `props` for that slot (`className`, `data-*`, `aria-*`, …).\n *\n * ⛔ EVERY SLOT, NOT JUST `root` — THAT WAS THE BUG. `IElementSlotConfig`\n * has advertised `props` on every slot since the slot system landed, but\n * only `root.props` was ever read (it is folded into `mergedProps`).\n * Anything a consumer put on another slot — the class a portal needs on a\n * tags field's outer box to make it match a text input — was parsed,\n * merged, and then thrown away with no warning and no type error.\n * Components apply `elementProps[slot]` to the matching element.\n */\n elementProps: Record<string, Record<string, any>>;\n /**\n * Full slot configs including `props`, `important` and `pseudo` fields.\n * Use this instead of `elementStyles` when you need those fields.\n */\n elementConfigs: Record<string, IElementConfig>;\n}\n\n/**\n * Merges slot `props` layers. Everything is last-wins EXCEPT `className`,\n * which is concatenated — a theme-level class and a consumer's class are\n * additive by nature, and dropping one of them is exactly the fault this\n * whole plumbing exists to fix.\n */\nfunction mergeSlotProps(layers: Array<Record<string, any> | undefined>): Record<string, any> {\n const out: Record<string, any> = {};\n const classes: string[] = [];\n for (const layer of layers) {\n if (!layer) continue;\n for (const [key, value] of Object.entries(layer)) {\n if (value === undefined) continue;\n if (key === 'className') {\n if (value) classes.push(String(value));\n } else {\n out[key] = value;\n }\n }\n }\n if (classes.length) {\n // De-duplicated, so a class repeated down the chain lands once.\n out.className = Array.from(new Set(classes.join(' ').split(/\\s+/).filter(Boolean))).join(' ');\n }\n return out;\n}\n\n/**\n * Merges theme-level component defaults with user-supplied props.\n *\n * Resolution chain (lowest → highest priority):\n * FormElement[slot] < baseGroup[slot] < component[slot] < instanceSlots[slot] < user props\n *\n * `FormElement` is the global base group for every form element\n * (label / helperText / error live there by default). It is applied\n * to every component regardless of whether a `baseGroup` is provided\n * — for non-form components like Button or Card, FormElement slots\n * are no-ops in practice because those components don't read\n * `elementStyles.label` / `helperText` / `error`.\n *\n * Element slots (`root`, `label`, `container`, etc.) are direct keys\n * on the component config. Each slot accepts `{ props?, style? }`.\n *\n * The `root` slot's `props` are merged into `mergedProps` alongside\n * user props (user always wins, except `className`, which concatenates).\n * The `root` slot's `style` is returned as both `themeStyle` (backwards\n * compat) and `elementStyles.root`.\n *\n * EVERY OTHER slot's `props` come back on `elementProps[slot]` — the\n * component is responsible for spreading them onto the element that slot\n * names. Before that existed, `props` on a non-root slot was silently\n * discarded, which is how a consumer's class on a tags field's outer box\n * disappeared without a single error.\n *\n * Supports base-group inheritance: e.g. `useComponentDefaults('InputText', rawProps, 'Input')`\n * merges FormElement first, then Input base, then InputText overrides,\n * then per-instance slots, then user props.\n *\n * @example\n * const { mergedProps, themeStyle, elementStyles } = useComponentDefaults('InputText', rawProps, 'Input');\n * // mergedProps → FormElement.root.props < Input.root.props < InputText.root.props < instanceSlots < user props\n * // elementStyles.label → FormElement.label.style < Input.label.style < InputText.label.style < instance label\n * // elementStyles.root → root element style (FormElement → Input → InputText → instance)\n * // elementStyles.container → container element style\n */\nexport default function useComponentDefaults<T extends Record<string, any>>(\n componentName: string,\n props: T,\n baseGroup?: string,\n): UseComponentDefaultsResult<T> {\n const {theme} = useKitsTheme();\n // Global base for every form element. Always looked up — if not\n // configured it is `undefined` and the merge contributes nothing.\n const formElementConfig = theme.components.FormElement;\n const baseConfig = baseGroup ? theme.components[baseGroup] : undefined;\n const config = theme.components[componentName];\n\n return useMemo(() => {\n // Extract per-instance slot overrides from props (IFormElement.slots passed through)\n const instanceSlots = (props as any).slots as Record<string, { props?: any; style?: any; important?: boolean | string[]; pseudo?: Record<string, Record<string, any>> }> | undefined;\n\n if (!config && !baseConfig && !instanceSlots && !formElementConfig) {\n return {mergedProps: props, themeStyle: {}, elementStyles: {}, elementProps: {}, elementConfigs: {}};\n }\n\n const formBase = (formElementConfig || {}) as Record<string, any>;\n const base = (baseConfig || {}) as Record<string, any>;\n const comp = (config || {}) as Record<string, any>;\n\n // --- Props merge: FormElement.root.props < base.root.props < config.root.props < instanceSlots.root.props < user props ---\n const merged = mergeSlotProps([\n formBase.root?.props,\n base.root?.props,\n comp.root?.props,\n instanceSlots?.root?.props,\n ]);\n\n const userClassName = typeof (props as any).className === 'string' ? (props as any).className : undefined;\n for (const key of Object.keys(props)) {\n // Skip 'slots' — it is consumed here, not forwarded\n if (key === 'slots') continue;\n // className is additive, not a replacement: a theme-level class on\n // `root.props` and the consumer's own class both have to survive.\n if (key === 'className') continue;\n if (props[key] !== undefined) {\n merged[key] = props[key];\n }\n }\n if (userClassName || merged.className) {\n merged.className = mergeSlotProps([\n {className: merged.className},\n {className: userClassName},\n ]).className;\n }\n\n // --- Element styles merge: FormElement[slot] < base[slot] < config[slot] < instanceSlots[slot] ---\n const allSlotKeys = new Set<string>();\n for (const key of Object.keys(formBase)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(base)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(comp)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n if (instanceSlots) {\n for (const key of Object.keys(instanceSlots)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n }\n\n const elementStyles: Record<string, Record<string, any>> = {};\n const elementProps: Record<string, Record<string, any>> = {};\n const elementConfigs: Record<string, IElementConfig> = {};\n for (const slotKey of allSlotKeys) {\n const style = {\n ...(formBase[slotKey]?.style || {}),\n ...(base[slotKey]?.style || {}),\n ...(comp[slotKey]?.style || {}),\n ...(instanceSlots?.[slotKey]?.style || {}),\n };\n elementStyles[slotKey] = style;\n\n const slotProps = mergeSlotProps([\n formBase[slotKey]?.props,\n base[slotKey]?.props,\n comp[slotKey]?.props,\n instanceSlots?.[slotKey]?.props,\n ]);\n elementProps[slotKey] = slotProps;\n\n const pseudoMerged = {\n ...(formBase[slotKey]?.pseudo || {}),\n ...(base[slotKey]?.pseudo || {}),\n ...(comp[slotKey]?.pseudo || {}),\n ...(instanceSlots?.[slotKey]?.pseudo || {}),\n };\n elementConfigs[slotKey] = {\n style,\n props: slotProps,\n important:\n instanceSlots?.[slotKey]?.important ??\n comp[slotKey]?.important ??\n base[slotKey]?.important ??\n formBase[slotKey]?.important,\n pseudo: Object.keys(pseudoMerged).length > 0 ? pseudoMerged : undefined,\n };\n }\n\n // themeStyle = root element style (backwards compat)\n const themeStyle = elementStyles.root || {};\n\n return {\n mergedProps: merged as T,\n themeStyle,\n elementStyles,\n elementProps,\n elementConfigs,\n };\n }, [formElementConfig, baseConfig, config, props]);\n}\n"],"names":["useKitsTheme","useMemo"],"mappings":"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"}
|
|
@@ -132,6 +132,18 @@ const ELEMENT_SLOT_KEYS = /* @__PURE__ */ new Set([
|
|
|
132
132
|
"topBar",
|
|
133
133
|
"bulkBar",
|
|
134
134
|
"bulkBarText",
|
|
135
|
+
// ImageCropper (IImageCropperSlots). The other slots it uses — root,
|
|
136
|
+
// container, header, title, content, footer, icon, text, mask, track,
|
|
137
|
+
// thumb — are already in this set under the components that named them
|
|
138
|
+
// first, which is the point of reusing those names.
|
|
139
|
+
"cropWindow",
|
|
140
|
+
"shade",
|
|
141
|
+
"gridLine",
|
|
142
|
+
"handle",
|
|
143
|
+
"zoomChip",
|
|
144
|
+
"previewFrame",
|
|
145
|
+
"dropZone",
|
|
146
|
+
"progressFill",
|
|
135
147
|
// Accordion
|
|
136
148
|
"headerActive",
|
|
137
149
|
"headerHover",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useComponentDefaults.js","sources":["../../../src/hooks/useComponentDefaults.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\n\n/**\n * Known element slot keys. When a config key matches one of these\n * AND the value has `props` or `style`, it is treated as an element slot.\n *\n * To add a new slot: add the key here AND to the relevant slot interface\n * in packages/types/src/Theme/types.ts (and to the `AllSlotKeys` union).\n *\n * The order below mirrors the typed slot hierarchy in\n * `packages/types/src/Theme/types.ts`.\n */\nconst ELEMENT_SLOT_KEYS = new Set([\n // ── Form-element slots ──────────────────────────────────\n // Base (all form elements — IFormElementBaseSlots)\n 'label', 'helperText', 'error',\n // Text input specific (ITextInputSlots — also shared by ISelectSlots)\n 'root', 'container', 'inputGroup', 'leftAddon', 'rightAddon',\n // Select specific (ISelectSlots — option-list popover)\n // Radio / Checkbox also use `item` / `itemSelected` / `itemDisabled` /\n // `itemHover` for the per-list-item wrapper, plus `itemInvalid`.\n 'panel', 'item', 'itemSelected', 'itemFocused', 'itemHover', 'itemDisabled', 'itemInvalid',\n // Chip-bearing selects (IChipInputSlots — MultiSelect display=\"chip\"\n // AND AutoComplete/Tags with isMultiple). `tokenContainer` is the\n // bordered box that holds the chips and the caret — see the docblock\n // on IChipInputSlots for why it is neither `root` nor `container`.\n 'tokenContainer', 'token', 'tokenIcon',\n // MultiSelect specific (IMultiSelectSlots — per-item checkbox)\n 'checkboxBox', 'checkboxBoxChecked', 'checkboxIcon',\n // Datepicker specific (IDatepickerSlots — calendar popup; `panel` shared with Select)\n 'calendarHeader', 'calendarNavButton', 'weekDay',\n 'dayCell', 'daySelected', 'dayToday', 'dayDisabled',\n // Switch specific (ISwitchSlots) — RENAMED from slider/sliderChecked/thumbChecked\n 'track', 'trackOn', 'thumb', 'thumbOn',\n // Checkbox specific (ICheckboxSlots)\n 'box', 'boxChecked', 'checkIcon',\n // Radio specific (IRadioSlots)\n 'circle', 'circleInner',\n // Radio + Checkbox: wrapper Flex around all list items\n 'itemsContainer',\n\n // ── Non-form component slots (untouched by the form-element refactor) ──\n // Card / Button / generic\n 'icon', 'header', 'title', 'subTitle', 'content', 'footer',\n // Button variants — `text` applies only to buttons with a label,\n // `iconOnly` applies only to icon-only buttons (so styling one never\n // affects the other).\n 'text', 'iconOnly',\n // Table\n 'th', 'headerRow', 'headerCell', 'body', 'bodyRow', 'bodyCell',\n 'wrapper', 'table', 'tbody',\n 'filterRow', 'filterCell', 'filterClearButton',\n 'columnFilter', 'columnFilterInput',\n 'tfoot', 'footerRow', 'footerCell', 'footer', 'paginator', 'emptyMessage',\n 'loadingOverlay', 'loadingIcon',\n 'rowGroupHeader', 'rowGroupHeaderName', 'rowExpansion', 'rowGroupFooter',\n 'rowGroupToggler', 'rowGroupTogglerIcon',\n 'resizeHelper',\n 'reorderIndicatorUp', 'reorderIndicatorUpIcon',\n 'reorderIndicatorDown', 'reorderIndicatorDownIcon',\n 'tableHeader', 'searchInput',\n 'paginatorPageButton', 'paginatorPageLink', 'paginatorActivePageButton',\n 'paginatorPageReport', 'paginatorRowsPerPage', 'paginatorRowsPerPageDropdown',\n 'paginatorPages',\n 'sortedColumn', 'stripedRow', 'selectedRow', 'selectedRowAccent',\n 'filterBar', 'filterInput', 'filterLabel',\n 'toolbarRight', 'toolbarButton', 'clearFilterButton', 'columnPicker',\n // Toolbar sizing + placeholder, and the chrome the table renders itself.\n // NOTE: a slot missing from this allowlist is silently dropped — theming\n // it has no effect at all — so every new slot must be listed here as\n // well as in its component's ITableElementSlots.\n 'toolbarControl', 'filterPlaceholder',\n 'topBar', 'bulkBar', 'bulkBarText',\n // Accordion\n 'headerActive', 'headerHover',\n // Sidebar/Drawer\n 'headerTitle', 'closeButton', 'mask',\n // Group (repeatable field array)\n 'row', 'addButton', 'removeButton',\n // Header (app-shell top bar)\n 'toggleModeButton', 'avatarButton', 'breadcrumb',\n]);\n\nexport interface IElementConfig {\n style: Record<string, any>;\n /**\n * Extra attributes for this slot's element — `className`, `data-*`,\n * `aria-*`, anything the platform element accepts. Merged across the\n * whole chain (FormElement < baseGroup < component < instance slots),\n * with `className` CONCATENATED rather than replaced.\n */\n props: Record<string, any>;\n important?: boolean | string[];\n pseudo?: Record<string, Record<string, any>>;\n}\n\nexport interface UseComponentDefaultsResult<T> {\n /** Props with theme defaults merged in (user props always win) */\n mergedProps: T;\n /**\n * CSS style from root slot — backwards compat for components\n * that read themeStyle instead of elementStyles.root\n */\n themeStyle: Record<string, any>;\n /**\n * Per-element style maps. Each key is a slot name, value is the\n * merged IStyleClasses (not yet resolved to CSSProperties).\n * Use `useResolvedElementStyles(elementStyles)` to resolve.\n */\n elementStyles: Record<string, Record<string, any>>;\n /**\n * Per-element extra attributes. Each key is a slot name, value is the\n * merged `props` for that slot (`className`, `data-*`, `aria-*`, …).\n *\n * ⛔ EVERY SLOT, NOT JUST `root` — THAT WAS THE BUG. `IElementSlotConfig`\n * has advertised `props` on every slot since the slot system landed, but\n * only `root.props` was ever read (it is folded into `mergedProps`).\n * Anything a consumer put on another slot — the class a portal needs on a\n * tags field's outer box to make it match a text input — was parsed,\n * merged, and then thrown away with no warning and no type error.\n * Components apply `elementProps[slot]` to the matching element.\n */\n elementProps: Record<string, Record<string, any>>;\n /**\n * Full slot configs including `props`, `important` and `pseudo` fields.\n * Use this instead of `elementStyles` when you need those fields.\n */\n elementConfigs: Record<string, IElementConfig>;\n}\n\n/**\n * Merges slot `props` layers. Everything is last-wins EXCEPT `className`,\n * which is concatenated — a theme-level class and a consumer's class are\n * additive by nature, and dropping one of them is exactly the fault this\n * whole plumbing exists to fix.\n */\nfunction mergeSlotProps(layers: Array<Record<string, any> | undefined>): Record<string, any> {\n const out: Record<string, any> = {};\n const classes: string[] = [];\n for (const layer of layers) {\n if (!layer) continue;\n for (const [key, value] of Object.entries(layer)) {\n if (value === undefined) continue;\n if (key === 'className') {\n if (value) classes.push(String(value));\n } else {\n out[key] = value;\n }\n }\n }\n if (classes.length) {\n // De-duplicated, so a class repeated down the chain lands once.\n out.className = Array.from(new Set(classes.join(' ').split(/\\s+/).filter(Boolean))).join(' ');\n }\n return out;\n}\n\n/**\n * Merges theme-level component defaults with user-supplied props.\n *\n * Resolution chain (lowest → highest priority):\n * FormElement[slot] < baseGroup[slot] < component[slot] < instanceSlots[slot] < user props\n *\n * `FormElement` is the global base group for every form element\n * (label / helperText / error live there by default). It is applied\n * to every component regardless of whether a `baseGroup` is provided\n * — for non-form components like Button or Card, FormElement slots\n * are no-ops in practice because those components don't read\n * `elementStyles.label` / `helperText` / `error`.\n *\n * Element slots (`root`, `label`, `container`, etc.) are direct keys\n * on the component config. Each slot accepts `{ props?, style? }`.\n *\n * The `root` slot's `props` are merged into `mergedProps` alongside\n * user props (user always wins, except `className`, which concatenates).\n * The `root` slot's `style` is returned as both `themeStyle` (backwards\n * compat) and `elementStyles.root`.\n *\n * EVERY OTHER slot's `props` come back on `elementProps[slot]` — the\n * component is responsible for spreading them onto the element that slot\n * names. Before that existed, `props` on a non-root slot was silently\n * discarded, which is how a consumer's class on a tags field's outer box\n * disappeared without a single error.\n *\n * Supports base-group inheritance: e.g. `useComponentDefaults('InputText', rawProps, 'Input')`\n * merges FormElement first, then Input base, then InputText overrides,\n * then per-instance slots, then user props.\n *\n * @example\n * const { mergedProps, themeStyle, elementStyles } = useComponentDefaults('InputText', rawProps, 'Input');\n * // mergedProps → FormElement.root.props < Input.root.props < InputText.root.props < instanceSlots < user props\n * // elementStyles.label → FormElement.label.style < Input.label.style < InputText.label.style < instance label\n * // elementStyles.root → root element style (FormElement → Input → InputText → instance)\n * // elementStyles.container → container element style\n */\nexport default function useComponentDefaults<T extends Record<string, any>>(\n componentName: string,\n props: T,\n baseGroup?: string,\n): UseComponentDefaultsResult<T> {\n const {theme} = useKitsTheme();\n // Global base for every form element. Always looked up — if not\n // configured it is `undefined` and the merge contributes nothing.\n const formElementConfig = theme.components.FormElement;\n const baseConfig = baseGroup ? theme.components[baseGroup] : undefined;\n const config = theme.components[componentName];\n\n return useMemo(() => {\n // Extract per-instance slot overrides from props (IFormElement.slots passed through)\n const instanceSlots = (props as any).slots as Record<string, { props?: any; style?: any; important?: boolean | string[]; pseudo?: Record<string, Record<string, any>> }> | undefined;\n\n if (!config && !baseConfig && !instanceSlots && !formElementConfig) {\n return {mergedProps: props, themeStyle: {}, elementStyles: {}, elementProps: {}, elementConfigs: {}};\n }\n\n const formBase = (formElementConfig || {}) as Record<string, any>;\n const base = (baseConfig || {}) as Record<string, any>;\n const comp = (config || {}) as Record<string, any>;\n\n // --- Props merge: FormElement.root.props < base.root.props < config.root.props < instanceSlots.root.props < user props ---\n const merged = mergeSlotProps([\n formBase.root?.props,\n base.root?.props,\n comp.root?.props,\n instanceSlots?.root?.props,\n ]);\n\n const userClassName = typeof (props as any).className === 'string' ? (props as any).className : undefined;\n for (const key of Object.keys(props)) {\n // Skip 'slots' — it is consumed here, not forwarded\n if (key === 'slots') continue;\n // className is additive, not a replacement: a theme-level class on\n // `root.props` and the consumer's own class both have to survive.\n if (key === 'className') continue;\n if (props[key] !== undefined) {\n merged[key] = props[key];\n }\n }\n if (userClassName || merged.className) {\n merged.className = mergeSlotProps([\n {className: merged.className},\n {className: userClassName},\n ]).className;\n }\n\n // --- Element styles merge: FormElement[slot] < base[slot] < config[slot] < instanceSlots[slot] ---\n const allSlotKeys = new Set<string>();\n for (const key of Object.keys(formBase)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(base)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(comp)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n if (instanceSlots) {\n for (const key of Object.keys(instanceSlots)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n }\n\n const elementStyles: Record<string, Record<string, any>> = {};\n const elementProps: Record<string, Record<string, any>> = {};\n const elementConfigs: Record<string, IElementConfig> = {};\n for (const slotKey of allSlotKeys) {\n const style = {\n ...(formBase[slotKey]?.style || {}),\n ...(base[slotKey]?.style || {}),\n ...(comp[slotKey]?.style || {}),\n ...(instanceSlots?.[slotKey]?.style || {}),\n };\n elementStyles[slotKey] = style;\n\n const slotProps = mergeSlotProps([\n formBase[slotKey]?.props,\n base[slotKey]?.props,\n comp[slotKey]?.props,\n instanceSlots?.[slotKey]?.props,\n ]);\n elementProps[slotKey] = slotProps;\n\n const pseudoMerged = {\n ...(formBase[slotKey]?.pseudo || {}),\n ...(base[slotKey]?.pseudo || {}),\n ...(comp[slotKey]?.pseudo || {}),\n ...(instanceSlots?.[slotKey]?.pseudo || {}),\n };\n elementConfigs[slotKey] = {\n style,\n props: slotProps,\n important:\n instanceSlots?.[slotKey]?.important ??\n comp[slotKey]?.important ??\n base[slotKey]?.important ??\n formBase[slotKey]?.important,\n pseudo: Object.keys(pseudoMerged).length > 0 ? pseudoMerged : undefined,\n };\n }\n\n // themeStyle = root element style (backwards compat)\n const themeStyle = elementStyles.root || {};\n\n return {\n mergedProps: merged as T,\n themeStyle,\n elementStyles,\n elementProps,\n elementConfigs,\n };\n }, [formElementConfig, baseConfig, config, props]);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useComponentDefaults.js","sources":["../../../src/hooks/useComponentDefaults.ts"],"sourcesContent":["import {useMemo} from 'react';\nimport {useKitsTheme} from '../contexts/Theme';\n\n/**\n * Known element slot keys. When a config key matches one of these\n * AND the value has `props` or `style`, it is treated as an element slot.\n *\n * To add a new slot: add the key here AND to the relevant slot interface\n * in packages/types/src/Theme/types.ts (and to the `AllSlotKeys` union).\n *\n * The order below mirrors the typed slot hierarchy in\n * `packages/types/src/Theme/types.ts`.\n */\nconst ELEMENT_SLOT_KEYS = new Set([\n // ── Form-element slots ──────────────────────────────────\n // Base (all form elements — IFormElementBaseSlots)\n 'label', 'helperText', 'error',\n // Text input specific (ITextInputSlots — also shared by ISelectSlots)\n 'root', 'container', 'inputGroup', 'leftAddon', 'rightAddon',\n // Select specific (ISelectSlots — option-list popover)\n // Radio / Checkbox also use `item` / `itemSelected` / `itemDisabled` /\n // `itemHover` for the per-list-item wrapper, plus `itemInvalid`.\n 'panel', 'item', 'itemSelected', 'itemFocused', 'itemHover', 'itemDisabled', 'itemInvalid',\n // Chip-bearing selects (IChipInputSlots — MultiSelect display=\"chip\"\n // AND AutoComplete/Tags with isMultiple). `tokenContainer` is the\n // bordered box that holds the chips and the caret — see the docblock\n // on IChipInputSlots for why it is neither `root` nor `container`.\n 'tokenContainer', 'token', 'tokenIcon',\n // MultiSelect specific (IMultiSelectSlots — per-item checkbox)\n 'checkboxBox', 'checkboxBoxChecked', 'checkboxIcon',\n // Datepicker specific (IDatepickerSlots — calendar popup; `panel` shared with Select)\n 'calendarHeader', 'calendarNavButton', 'weekDay',\n 'dayCell', 'daySelected', 'dayToday', 'dayDisabled',\n // Switch specific (ISwitchSlots) — RENAMED from slider/sliderChecked/thumbChecked\n 'track', 'trackOn', 'thumb', 'thumbOn',\n // Checkbox specific (ICheckboxSlots)\n 'box', 'boxChecked', 'checkIcon',\n // Radio specific (IRadioSlots)\n 'circle', 'circleInner',\n // Radio + Checkbox: wrapper Flex around all list items\n 'itemsContainer',\n\n // ── Non-form component slots (untouched by the form-element refactor) ──\n // Card / Button / generic\n 'icon', 'header', 'title', 'subTitle', 'content', 'footer',\n // Button variants — `text` applies only to buttons with a label,\n // `iconOnly` applies only to icon-only buttons (so styling one never\n // affects the other).\n 'text', 'iconOnly',\n // Table\n 'th', 'headerRow', 'headerCell', 'body', 'bodyRow', 'bodyCell',\n 'wrapper', 'table', 'tbody',\n 'filterRow', 'filterCell', 'filterClearButton',\n 'columnFilter', 'columnFilterInput',\n 'tfoot', 'footerRow', 'footerCell', 'footer', 'paginator', 'emptyMessage',\n 'loadingOverlay', 'loadingIcon',\n 'rowGroupHeader', 'rowGroupHeaderName', 'rowExpansion', 'rowGroupFooter',\n 'rowGroupToggler', 'rowGroupTogglerIcon',\n 'resizeHelper',\n 'reorderIndicatorUp', 'reorderIndicatorUpIcon',\n 'reorderIndicatorDown', 'reorderIndicatorDownIcon',\n 'tableHeader', 'searchInput',\n 'paginatorPageButton', 'paginatorPageLink', 'paginatorActivePageButton',\n 'paginatorPageReport', 'paginatorRowsPerPage', 'paginatorRowsPerPageDropdown',\n 'paginatorPages',\n 'sortedColumn', 'stripedRow', 'selectedRow', 'selectedRowAccent',\n 'filterBar', 'filterInput', 'filterLabel',\n 'toolbarRight', 'toolbarButton', 'clearFilterButton', 'columnPicker',\n // Toolbar sizing + placeholder, and the chrome the table renders itself.\n // NOTE: a slot missing from this allowlist is silently dropped — theming\n // it has no effect at all — so every new slot must be listed here as\n // well as in its component's ITableElementSlots.\n 'toolbarControl', 'filterPlaceholder',\n 'topBar', 'bulkBar', 'bulkBarText',\n // ImageCropper (IImageCropperSlots). The other slots it uses — root,\n // container, header, title, content, footer, icon, text, mask, track,\n // thumb — are already in this set under the components that named them\n // first, which is the point of reusing those names.\n 'cropWindow', 'shade', 'gridLine', 'handle',\n 'zoomChip', 'previewFrame', 'dropZone', 'progressFill',\n // Accordion\n 'headerActive', 'headerHover',\n // Sidebar/Drawer\n 'headerTitle', 'closeButton', 'mask',\n // Group (repeatable field array)\n 'row', 'addButton', 'removeButton',\n // Header (app-shell top bar)\n 'toggleModeButton', 'avatarButton', 'breadcrumb',\n]);\n\nexport interface IElementConfig {\n style: Record<string, any>;\n /**\n * Extra attributes for this slot's element — `className`, `data-*`,\n * `aria-*`, anything the platform element accepts. Merged across the\n * whole chain (FormElement < baseGroup < component < instance slots),\n * with `className` CONCATENATED rather than replaced.\n */\n props: Record<string, any>;\n important?: boolean | string[];\n pseudo?: Record<string, Record<string, any>>;\n}\n\nexport interface UseComponentDefaultsResult<T> {\n /** Props with theme defaults merged in (user props always win) */\n mergedProps: T;\n /**\n * CSS style from root slot — backwards compat for components\n * that read themeStyle instead of elementStyles.root\n */\n themeStyle: Record<string, any>;\n /**\n * Per-element style maps. Each key is a slot name, value is the\n * merged IStyleClasses (not yet resolved to CSSProperties).\n * Use `useResolvedElementStyles(elementStyles)` to resolve.\n */\n elementStyles: Record<string, Record<string, any>>;\n /**\n * Per-element extra attributes. Each key is a slot name, value is the\n * merged `props` for that slot (`className`, `data-*`, `aria-*`, …).\n *\n * ⛔ EVERY SLOT, NOT JUST `root` — THAT WAS THE BUG. `IElementSlotConfig`\n * has advertised `props` on every slot since the slot system landed, but\n * only `root.props` was ever read (it is folded into `mergedProps`).\n * Anything a consumer put on another slot — the class a portal needs on a\n * tags field's outer box to make it match a text input — was parsed,\n * merged, and then thrown away with no warning and no type error.\n * Components apply `elementProps[slot]` to the matching element.\n */\n elementProps: Record<string, Record<string, any>>;\n /**\n * Full slot configs including `props`, `important` and `pseudo` fields.\n * Use this instead of `elementStyles` when you need those fields.\n */\n elementConfigs: Record<string, IElementConfig>;\n}\n\n/**\n * Merges slot `props` layers. Everything is last-wins EXCEPT `className`,\n * which is concatenated — a theme-level class and a consumer's class are\n * additive by nature, and dropping one of them is exactly the fault this\n * whole plumbing exists to fix.\n */\nfunction mergeSlotProps(layers: Array<Record<string, any> | undefined>): Record<string, any> {\n const out: Record<string, any> = {};\n const classes: string[] = [];\n for (const layer of layers) {\n if (!layer) continue;\n for (const [key, value] of Object.entries(layer)) {\n if (value === undefined) continue;\n if (key === 'className') {\n if (value) classes.push(String(value));\n } else {\n out[key] = value;\n }\n }\n }\n if (classes.length) {\n // De-duplicated, so a class repeated down the chain lands once.\n out.className = Array.from(new Set(classes.join(' ').split(/\\s+/).filter(Boolean))).join(' ');\n }\n return out;\n}\n\n/**\n * Merges theme-level component defaults with user-supplied props.\n *\n * Resolution chain (lowest → highest priority):\n * FormElement[slot] < baseGroup[slot] < component[slot] < instanceSlots[slot] < user props\n *\n * `FormElement` is the global base group for every form element\n * (label / helperText / error live there by default). It is applied\n * to every component regardless of whether a `baseGroup` is provided\n * — for non-form components like Button or Card, FormElement slots\n * are no-ops in practice because those components don't read\n * `elementStyles.label` / `helperText` / `error`.\n *\n * Element slots (`root`, `label`, `container`, etc.) are direct keys\n * on the component config. Each slot accepts `{ props?, style? }`.\n *\n * The `root` slot's `props` are merged into `mergedProps` alongside\n * user props (user always wins, except `className`, which concatenates).\n * The `root` slot's `style` is returned as both `themeStyle` (backwards\n * compat) and `elementStyles.root`.\n *\n * EVERY OTHER slot's `props` come back on `elementProps[slot]` — the\n * component is responsible for spreading them onto the element that slot\n * names. Before that existed, `props` on a non-root slot was silently\n * discarded, which is how a consumer's class on a tags field's outer box\n * disappeared without a single error.\n *\n * Supports base-group inheritance: e.g. `useComponentDefaults('InputText', rawProps, 'Input')`\n * merges FormElement first, then Input base, then InputText overrides,\n * then per-instance slots, then user props.\n *\n * @example\n * const { mergedProps, themeStyle, elementStyles } = useComponentDefaults('InputText', rawProps, 'Input');\n * // mergedProps → FormElement.root.props < Input.root.props < InputText.root.props < instanceSlots < user props\n * // elementStyles.label → FormElement.label.style < Input.label.style < InputText.label.style < instance label\n * // elementStyles.root → root element style (FormElement → Input → InputText → instance)\n * // elementStyles.container → container element style\n */\nexport default function useComponentDefaults<T extends Record<string, any>>(\n componentName: string,\n props: T,\n baseGroup?: string,\n): UseComponentDefaultsResult<T> {\n const {theme} = useKitsTheme();\n // Global base for every form element. Always looked up — if not\n // configured it is `undefined` and the merge contributes nothing.\n const formElementConfig = theme.components.FormElement;\n const baseConfig = baseGroup ? theme.components[baseGroup] : undefined;\n const config = theme.components[componentName];\n\n return useMemo(() => {\n // Extract per-instance slot overrides from props (IFormElement.slots passed through)\n const instanceSlots = (props as any).slots as Record<string, { props?: any; style?: any; important?: boolean | string[]; pseudo?: Record<string, Record<string, any>> }> | undefined;\n\n if (!config && !baseConfig && !instanceSlots && !formElementConfig) {\n return {mergedProps: props, themeStyle: {}, elementStyles: {}, elementProps: {}, elementConfigs: {}};\n }\n\n const formBase = (formElementConfig || {}) as Record<string, any>;\n const base = (baseConfig || {}) as Record<string, any>;\n const comp = (config || {}) as Record<string, any>;\n\n // --- Props merge: FormElement.root.props < base.root.props < config.root.props < instanceSlots.root.props < user props ---\n const merged = mergeSlotProps([\n formBase.root?.props,\n base.root?.props,\n comp.root?.props,\n instanceSlots?.root?.props,\n ]);\n\n const userClassName = typeof (props as any).className === 'string' ? (props as any).className : undefined;\n for (const key of Object.keys(props)) {\n // Skip 'slots' — it is consumed here, not forwarded\n if (key === 'slots') continue;\n // className is additive, not a replacement: a theme-level class on\n // `root.props` and the consumer's own class both have to survive.\n if (key === 'className') continue;\n if (props[key] !== undefined) {\n merged[key] = props[key];\n }\n }\n if (userClassName || merged.className) {\n merged.className = mergeSlotProps([\n {className: merged.className},\n {className: userClassName},\n ]).className;\n }\n\n // --- Element styles merge: FormElement[slot] < base[slot] < config[slot] < instanceSlots[slot] ---\n const allSlotKeys = new Set<string>();\n for (const key of Object.keys(formBase)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(base)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n for (const key of Object.keys(comp)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n if (instanceSlots) {\n for (const key of Object.keys(instanceSlots)) {\n if (ELEMENT_SLOT_KEYS.has(key)) allSlotKeys.add(key);\n }\n }\n\n const elementStyles: Record<string, Record<string, any>> = {};\n const elementProps: Record<string, Record<string, any>> = {};\n const elementConfigs: Record<string, IElementConfig> = {};\n for (const slotKey of allSlotKeys) {\n const style = {\n ...(formBase[slotKey]?.style || {}),\n ...(base[slotKey]?.style || {}),\n ...(comp[slotKey]?.style || {}),\n ...(instanceSlots?.[slotKey]?.style || {}),\n };\n elementStyles[slotKey] = style;\n\n const slotProps = mergeSlotProps([\n formBase[slotKey]?.props,\n base[slotKey]?.props,\n comp[slotKey]?.props,\n instanceSlots?.[slotKey]?.props,\n ]);\n elementProps[slotKey] = slotProps;\n\n const pseudoMerged = {\n ...(formBase[slotKey]?.pseudo || {}),\n ...(base[slotKey]?.pseudo || {}),\n ...(comp[slotKey]?.pseudo || {}),\n ...(instanceSlots?.[slotKey]?.pseudo || {}),\n };\n elementConfigs[slotKey] = {\n style,\n props: slotProps,\n important:\n instanceSlots?.[slotKey]?.important ??\n comp[slotKey]?.important ??\n base[slotKey]?.important ??\n formBase[slotKey]?.important,\n pseudo: Object.keys(pseudoMerged).length > 0 ? pseudoMerged : undefined,\n };\n }\n\n // themeStyle = root element style (backwards compat)\n const themeStyle = elementStyles.root || {};\n\n return {\n mergedProps: merged as T,\n themeStyle,\n elementStyles,\n elementProps,\n elementConfigs,\n };\n }, [formElementConfig, baseConfig, config, props]);\n}\n"],"names":[],"mappings":"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"}
|