@cleanweb/oore 2.0.0-alpha.24 → 2.0.0-alpha.26
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/build/_cjs/helpers/debounce/index.d.ts +55 -0
- package/build/_cjs/helpers/debounce/index.js +114 -0
- package/build/_cjs/helpers/debounce/react.d.ts +7 -0
- package/build/_cjs/helpers/debounce/react.js +19 -0
- package/build/_cjs/helpers/object-gate.d.ts +74 -0
- package/build/_cjs/helpers/object-gate.js +67 -0
- package/build/_cjs/slots/hook.js +16 -12
- package/build/_cjs/slots/types.d.ts +1 -6
- package/build/helpers/debounce/index.d.ts +55 -0
- package/build/helpers/debounce/index.js +110 -0
- package/build/helpers/debounce/react.d.ts +7 -0
- package/build/helpers/debounce/react.js +16 -0
- package/build/helpers/object-gate.d.ts +74 -0
- package/build/helpers/object-gate.js +64 -0
- package/build/slots/hook.js +16 -12
- package/build/slots/types.d.ts +1 -6
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
interface IDebouncedFunction<TFunc extends AnyFunction> {
|
|
2
|
+
(...args: Parameters<TFunc>): Promise<ReturnType<TFunc>>;
|
|
3
|
+
/**
|
|
4
|
+
* Called internally to trigger the callback with the most recent args
|
|
5
|
+
* after the delay expires. Can be used to manually trigger the callback
|
|
6
|
+
* before the normal delay time. If no pending call exists, flush() becomes a no-op.
|
|
7
|
+
*/
|
|
8
|
+
flush: (isEager?: true) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface IDelayConfig {
|
|
11
|
+
/**
|
|
12
|
+
* A non-zero delay in milliseconds.
|
|
13
|
+
* @default 0
|
|
14
|
+
*/
|
|
15
|
+
delay?: number;
|
|
16
|
+
/**
|
|
17
|
+
* The 'last-call' value specifies that the timer should be applied from the time of the most recent call.
|
|
18
|
+
* That means each new call while a delay is active will reset the timer, thereby extending the delay.
|
|
19
|
+
* In other words, it is a "time after inactivity" delay.
|
|
20
|
+
* Specifying 'first-call' instead will make it use a "time after initial call" delay strategy.
|
|
21
|
+
*/
|
|
22
|
+
anchor?: 'first-call' | 'last-call';
|
|
23
|
+
/**
|
|
24
|
+
* Controls eager execution behavior:
|
|
25
|
+
* - `false`: Initial call waits for the delay period before executing.
|
|
26
|
+
* - `'no-queue'`: Initial call fires immediately. Subsequent calls during the delay period
|
|
27
|
+
* are skipped and return the promise from the initial call. Ideal for preventing
|
|
28
|
+
* duplicate actions like clicking a download button twice.
|
|
29
|
+
* - `'with-queue'`: Initial call fires immediately. After the initial flush, the promise
|
|
30
|
+
* is discarded. The next call during the delay period creates a new workorder that will
|
|
31
|
+
* be maintained until the next flush. Ideal for debounced search inputs and similar use cases.
|
|
32
|
+
* @default 'with-queue'
|
|
33
|
+
*/
|
|
34
|
+
eager?: false | 'no-queue' | 'with-queue';
|
|
35
|
+
}
|
|
36
|
+
interface IDebounce {
|
|
37
|
+
<TFunc extends AnyFunction>(callback: TFunc, delayConfigArg?: number | IDelayConfig): IDebouncedFunction<TFunc>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Wraps the provided function with a debounce.
|
|
41
|
+
*
|
|
42
|
+
* Behavior during the delay period depends on the `eager` configuration:
|
|
43
|
+
* - `eager: false`: All calls wait for the delay. New calls overwrite the existing call.
|
|
44
|
+
* - `eager: 'no-queue'`: First call fires immediately. Subsequent calls during the delay
|
|
45
|
+
* period are skipped and return the same promise as the initial call.
|
|
46
|
+
* - `eager: 'with-queue'` (default): First call fires immediately. After the flush, the next call
|
|
47
|
+
* creates a new workorder that will be fired after the delay. New calls overwrite queued args.
|
|
48
|
+
*
|
|
49
|
+
* Once the timer expires, the most recent call is fired.
|
|
50
|
+
*
|
|
51
|
+
* Note: Returned promises may resolve with values from calls made with
|
|
52
|
+
* different arguments. Avoid using this for functions where argument-specific results matter.
|
|
53
|
+
*/
|
|
54
|
+
export declare const debounce: IDebounce;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.debounce = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Wraps the provided function with a debounce.
|
|
15
|
+
*
|
|
16
|
+
* Behavior during the delay period depends on the `eager` configuration:
|
|
17
|
+
* - `eager: false`: All calls wait for the delay. New calls overwrite the existing call.
|
|
18
|
+
* - `eager: 'no-queue'`: First call fires immediately. Subsequent calls during the delay
|
|
19
|
+
* period are skipped and return the same promise as the initial call.
|
|
20
|
+
* - `eager: 'with-queue'` (default): First call fires immediately. After the flush, the next call
|
|
21
|
+
* creates a new workorder that will be fired after the delay. New calls overwrite queued args.
|
|
22
|
+
*
|
|
23
|
+
* Once the timer expires, the most recent call is fired.
|
|
24
|
+
*
|
|
25
|
+
* Note: Returned promises may resolve with values from calls made with
|
|
26
|
+
* different arguments. Avoid using this for functions where argument-specific results matter.
|
|
27
|
+
*/
|
|
28
|
+
const debounce = (...init) => {
|
|
29
|
+
const [callback, delayArg] = init;
|
|
30
|
+
const delayConfig = {
|
|
31
|
+
delay: 1000,
|
|
32
|
+
anchor: 'first-call',
|
|
33
|
+
eager: 'with-queue',
|
|
34
|
+
};
|
|
35
|
+
if (typeof delayArg === 'number') {
|
|
36
|
+
delayConfig.delay = delayArg || 1000;
|
|
37
|
+
}
|
|
38
|
+
else if (delayArg) {
|
|
39
|
+
for (const _key in delayArg) {
|
|
40
|
+
const key = _key;
|
|
41
|
+
if (delayArg[key] !== undefined) {
|
|
42
|
+
// @ts-expect-error
|
|
43
|
+
delayConfig[key] = delayArg[key];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
let nextCall = null;
|
|
48
|
+
const debouncedFunction = (...args) => {
|
|
49
|
+
let currentWork;
|
|
50
|
+
if (nextCall) {
|
|
51
|
+
if (delayConfig.eager !== 'no-queue') {
|
|
52
|
+
nextCall = Object.assign(Object.assign({}, nextCall), { args, work: nextCall.work || Promise.withResolvers() });
|
|
53
|
+
}
|
|
54
|
+
currentWork = nextCall.work;
|
|
55
|
+
if (delayConfig.anchor === 'last-call') {
|
|
56
|
+
clearTimeout(nextCall.timeout);
|
|
57
|
+
nextCall.timeout = setTimeout(debouncedFunction.flush, delayConfig.delay);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// No active delay, create new call
|
|
62
|
+
nextCall = {
|
|
63
|
+
args,
|
|
64
|
+
timeout: setTimeout(debouncedFunction.flush, delayConfig.delay),
|
|
65
|
+
work: Promise.withResolvers(),
|
|
66
|
+
};
|
|
67
|
+
currentWork = nextCall.work;
|
|
68
|
+
// Fire immediately if eager mode is enabled (no-queue or with-queue)
|
|
69
|
+
if (delayConfig.eager !== false) {
|
|
70
|
+
debouncedFunction.flush(true);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!currentWork) {
|
|
74
|
+
throw new Error('[debounce] `currentWork` was not initialized.');
|
|
75
|
+
}
|
|
76
|
+
return currentWork.promise;
|
|
77
|
+
};
|
|
78
|
+
debouncedFunction.flush = (isEager) => {
|
|
79
|
+
if (!(nextCall === null || nextCall === void 0 ? void 0 : nextCall.args)) {
|
|
80
|
+
nextCall = null;
|
|
81
|
+
// console.log('Queue is empty. Nothing to flush.');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Capture queue values.
|
|
85
|
+
const { resolve, reject } = nextCall.work || {};
|
|
86
|
+
const args = nextCall.args;
|
|
87
|
+
// Clear the queue for new debounced calls.
|
|
88
|
+
if (isEager) {
|
|
89
|
+
delete nextCall.args;
|
|
90
|
+
if (delayConfig.eager === 'with-queue') {
|
|
91
|
+
delete nextCall.work;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
nextCall = null;
|
|
96
|
+
}
|
|
97
|
+
// Execute the pending call.
|
|
98
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
var _a;
|
|
100
|
+
try {
|
|
101
|
+
const result = (_a = (yield callback(...args))) !== null && _a !== void 0 ? _a : {};
|
|
102
|
+
result.__debounceFlushedWithArgs = args;
|
|
103
|
+
resolve === null || resolve === void 0 ? void 0 : resolve(result);
|
|
104
|
+
}
|
|
105
|
+
catch (_reason) {
|
|
106
|
+
const reason = _reason !== null && _reason !== void 0 ? _reason : {};
|
|
107
|
+
reason.__debounceFlushedWithArgs = args;
|
|
108
|
+
reject === null || reject === void 0 ? void 0 : reject(reason);
|
|
109
|
+
}
|
|
110
|
+
}))();
|
|
111
|
+
};
|
|
112
|
+
return debouncedFunction;
|
|
113
|
+
};
|
|
114
|
+
exports.debounce = debounce;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { debounce } from './index.js';
|
|
2
|
+
type TDebounceConfig = Exclude<Parameters<typeof debounce>[1], number>;
|
|
3
|
+
type TDelayConfig = number | TDebounceConfig & {
|
|
4
|
+
staging?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function useDebouncedState<T extends any>(init: T, config: TDelayConfig): readonly [T, (value: T) => void, T];
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDebouncedState = useDebouncedState;
|
|
4
|
+
const react_1 = require("react.js");
|
|
5
|
+
const _1 = require("./index.js");
|
|
6
|
+
function useDebouncedState(init, config) {
|
|
7
|
+
const [debouncedValue, setDebouncedValue] = (0, react_1.useState)(init);
|
|
8
|
+
const [stagedValue, setStagedValue] = (0, react_1.useState)(init);
|
|
9
|
+
const enableStaging = typeof config === 'object' && config.staging === true;
|
|
10
|
+
const debounceArgs = [setDebouncedValue, config];
|
|
11
|
+
const debouncedSetter = (0, react_1.useCallback)((0, _1.debounce)(...debounceArgs), debounceArgs);
|
|
12
|
+
const setter = (0, react_1.useCallback)((value) => {
|
|
13
|
+
if (enableStaging) {
|
|
14
|
+
setStagedValue(value);
|
|
15
|
+
}
|
|
16
|
+
debouncedSetter(value);
|
|
17
|
+
}, [enableStaging, debouncedSetter]);
|
|
18
|
+
return [debouncedValue, setter, stagedValue];
|
|
19
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
type TRecord = Record<keyof any, any>;
|
|
2
|
+
declare namespace _ObjectGate {
|
|
3
|
+
/** Configure property access for a proxy object. */
|
|
4
|
+
interface IGateConfig<TSource extends TRecord> {
|
|
5
|
+
/**
|
|
6
|
+
* The keys to be exposed for read access through the proxy.
|
|
7
|
+
* Defaults to [`Reflect.ownKeys(source)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/ownKeys) —
|
|
8
|
+
* so if omitted, all ["_own properties_"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Enumerability_and_ownership_of_properties)
|
|
9
|
+
* present on the source at
|
|
10
|
+
* instantiation time will be exposed for read access through the proxy.
|
|
11
|
+
*/
|
|
12
|
+
getters?: Readonly<Array<keyof TSource>>;
|
|
13
|
+
/**
|
|
14
|
+
* Keys that should definitely be omitted from read access,
|
|
15
|
+
* even if they are present in {@link getters}.
|
|
16
|
+
* @default [] - Empty array.
|
|
17
|
+
*/
|
|
18
|
+
gettersExclude?: Readonly<Array<keyof TSource>>;
|
|
19
|
+
/**
|
|
20
|
+
* The keys to be exposed for write access through the proxy.
|
|
21
|
+
* This defaults to an empty array, so if omitted, none of the gated
|
|
22
|
+
* properties will be writeable.
|
|
23
|
+
* @default [] - Empty array.
|
|
24
|
+
*/
|
|
25
|
+
setters?: Readonly<Array<keyof TSource> | true>;
|
|
26
|
+
/**
|
|
27
|
+
* Keys that should definitely be omitted from write access,
|
|
28
|
+
* even if they are present in {@link setters}.
|
|
29
|
+
* @default [] - Empty array.
|
|
30
|
+
*/
|
|
31
|
+
settersExclude?: Readonly<Array<keyof TSource>>;
|
|
32
|
+
}
|
|
33
|
+
type Params<TSource extends TRecord> = [
|
|
34
|
+
/**
|
|
35
|
+
* The target object, where the actual values are stored.
|
|
36
|
+
* Keys on the created gate object will use JavaScript getters to return
|
|
37
|
+
* the real-time value of the same key from this source object.
|
|
38
|
+
*/
|
|
39
|
+
source: TSource,
|
|
40
|
+
/** @see {@link IGateConfig} */
|
|
41
|
+
config?: Readonly<IGateConfig<TSource>>
|
|
42
|
+
];
|
|
43
|
+
class Gate<TSource extends TRecord> {
|
|
44
|
+
constructor(...params: Params<TSource>);
|
|
45
|
+
}
|
|
46
|
+
interface IConstructor {
|
|
47
|
+
new <TOutput extends Partial<TSource>, TSource extends TRecord>(...params: _ObjectGate.Params<TSource>): TOutput;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new object that acts as a real-time proxy
|
|
52
|
+
* for the {@link _ObjectGate.Params | `source`} object.
|
|
53
|
+
* This lets you prevent access to some properties, effectively making them private,
|
|
54
|
+
* while selectively exposing access to only the properties you specify
|
|
55
|
+
* in the {@link _ObjectGate.IGateConfig.getters | `getters`} config option.
|
|
56
|
+
*
|
|
57
|
+
* The exposed properties are read-only by default,
|
|
58
|
+
* exposing only a [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description)
|
|
59
|
+
* with no corresponding [setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set#description).
|
|
60
|
+
*
|
|
61
|
+
* The {@link _ObjectGate.Params | `config`} argument also lets you selectively allow
|
|
62
|
+
* write access to specific properties through the
|
|
63
|
+
* {@link _ObjectGate.IGateConfig.setters | `setters`} config option.
|
|
64
|
+
*
|
|
65
|
+
* Unlike [`structuredClone`](https://developer.mozilla.org/docs/Web/API/Window/structuredClone)
|
|
66
|
+
* this doesn't return a _copy_ of the `source` object.
|
|
67
|
+
*
|
|
68
|
+
* Instead, it returns a _**Real-time proxy**_. This means that a value is read
|
|
69
|
+
* from the source object each time a property is accessed through the proxy.
|
|
70
|
+
* So accessing a property through the gate object is guaranteed to always return
|
|
71
|
+
* the latest value.
|
|
72
|
+
*/
|
|
73
|
+
export declare const ObjectGate: _ObjectGate.IConstructor;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ObjectGate = void 0;
|
|
4
|
+
var _ObjectGate;
|
|
5
|
+
(function (_ObjectGate) {
|
|
6
|
+
class Gate {
|
|
7
|
+
constructor(...params) {
|
|
8
|
+
var _a, _b, _c, _d;
|
|
9
|
+
const [source, config] = params;
|
|
10
|
+
const getters = (_a = config === null || config === void 0 ? void 0 : config.getters) !== null && _a !== void 0 ? _a : Reflect.ownKeys(source);
|
|
11
|
+
const gettersExclude = (_b = config === null || config === void 0 ? void 0 : config.gettersExclude) !== null && _b !== void 0 ? _b : [];
|
|
12
|
+
const setters = (config === null || config === void 0 ? void 0 : config.setters) === true
|
|
13
|
+
? getters
|
|
14
|
+
: ((_c = config === null || config === void 0 ? void 0 : config.setters) !== null && _c !== void 0 ? _c : []);
|
|
15
|
+
const settersExclude = (_d = config === null || config === void 0 ? void 0 : config.settersExclude) !== null && _d !== void 0 ? _d : [];
|
|
16
|
+
getters.forEach((_key) => {
|
|
17
|
+
const key = _key;
|
|
18
|
+
if (gettersExclude.includes(key))
|
|
19
|
+
return;
|
|
20
|
+
Object.defineProperty(this, key, {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
get() {
|
|
24
|
+
return source[key];
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
setters.forEach((_key) => {
|
|
29
|
+
const key = _key;
|
|
30
|
+
if (settersExclude.includes(key))
|
|
31
|
+
return;
|
|
32
|
+
Object.defineProperty(this, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
set(value) {
|
|
35
|
+
source[key] = value;
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
_ObjectGate.Gate = Gate;
|
|
42
|
+
;
|
|
43
|
+
})(_ObjectGate || (_ObjectGate = {}));
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new object that acts as a real-time proxy
|
|
46
|
+
* for the {@link _ObjectGate.Params | `source`} object.
|
|
47
|
+
* This lets you prevent access to some properties, effectively making them private,
|
|
48
|
+
* while selectively exposing access to only the properties you specify
|
|
49
|
+
* in the {@link _ObjectGate.IGateConfig.getters | `getters`} config option.
|
|
50
|
+
*
|
|
51
|
+
* The exposed properties are read-only by default,
|
|
52
|
+
* exposing only a [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description)
|
|
53
|
+
* with no corresponding [setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set#description).
|
|
54
|
+
*
|
|
55
|
+
* The {@link _ObjectGate.Params | `config`} argument also lets you selectively allow
|
|
56
|
+
* write access to specific properties through the
|
|
57
|
+
* {@link _ObjectGate.IGateConfig.setters | `setters`} config option.
|
|
58
|
+
*
|
|
59
|
+
* Unlike [`structuredClone`](https://developer.mozilla.org/docs/Web/API/Window/structuredClone)
|
|
60
|
+
* this doesn't return a _copy_ of the `source` object.
|
|
61
|
+
*
|
|
62
|
+
* Instead, it returns a _**Real-time proxy**_. This means that a value is read
|
|
63
|
+
* from the source object each time a property is accessed through the proxy.
|
|
64
|
+
* So accessing a property through the gate object is guaranteed to always return
|
|
65
|
+
* the latest value.
|
|
66
|
+
*/
|
|
67
|
+
exports.ObjectGate = _ObjectGate.Gate;
|
package/build/_cjs/slots/hook.js
CHANGED
|
@@ -50,6 +50,9 @@ const getComponentSlotName = (TargetComponent, child) => {
|
|
|
50
50
|
else if ('displayName' in TargetComponent) {
|
|
51
51
|
return TargetComponent.displayName;
|
|
52
52
|
}
|
|
53
|
+
else if ('name' in TargetComponent) {
|
|
54
|
+
return TargetComponent.name;
|
|
55
|
+
}
|
|
53
56
|
return undefined;
|
|
54
57
|
};
|
|
55
58
|
exports.getComponentSlotName = getComponentSlotName;
|
|
@@ -72,14 +75,18 @@ exports.isPortalChild = isPortalChild;
|
|
|
72
75
|
const useSlots = (children, Caller) => {
|
|
73
76
|
const slotsAliasLookup = (0, react_1.useMemo)(() => {
|
|
74
77
|
const entries = Object.entries(Caller.Slots);
|
|
75
|
-
const aliasLookup = {
|
|
78
|
+
const aliasLookup = {
|
|
79
|
+
byName: {},
|
|
80
|
+
byIdentity: new Map(),
|
|
81
|
+
};
|
|
76
82
|
entries.forEach(([alias, RegisteredSlotComponent]) => {
|
|
77
83
|
const slotName = (0, exports.getComponentSlotName)(RegisteredSlotComponent);
|
|
78
84
|
if (!slotName) {
|
|
79
|
-
(
|
|
80
|
-
|
|
85
|
+
aliasLookup.byIdentity.set(RegisteredSlotComponent, alias);
|
|
86
|
+
aliasLookup.byName[alias] = alias;
|
|
81
87
|
}
|
|
82
|
-
|
|
88
|
+
else
|
|
89
|
+
aliasLookup.byName[slotName] = alias;
|
|
83
90
|
});
|
|
84
91
|
return aliasLookup;
|
|
85
92
|
}, [Caller.Slots]);
|
|
@@ -93,7 +100,6 @@ const useSlots = (children, Caller) => {
|
|
|
93
100
|
...((_a = Caller.requiredSlotAliases) !== null && _a !== void 0 ? _a : [])
|
|
94
101
|
];
|
|
95
102
|
react_1.default.Children.forEach(children, (_child) => {
|
|
96
|
-
var _a;
|
|
97
103
|
const child = _child;
|
|
98
104
|
if (!child) {
|
|
99
105
|
invalidChildren.push(child);
|
|
@@ -111,16 +117,13 @@ const useSlots = (children, Caller) => {
|
|
|
111
117
|
return;
|
|
112
118
|
}
|
|
113
119
|
const slotAlias = (() => {
|
|
114
|
-
var _a;
|
|
115
120
|
const slotName = (0, exports.getComponentSlotName)(child.type, child);
|
|
116
|
-
|
|
121
|
+
const alias = slotName
|
|
122
|
+
? slotsAliasLookup.byName[slotName]
|
|
123
|
+
: slotsAliasLookup.byIdentity.get(child.type);
|
|
124
|
+
return alias !== null && alias !== void 0 ? alias : null;
|
|
117
125
|
})();
|
|
118
126
|
if (slotAlias) {
|
|
119
|
-
if (typeof Caller.Slots[slotAlias] !== 'string') {
|
|
120
|
-
if ((_a = Caller.Slots[slotAlias]) === null || _a === void 0 ? void 0 : _a.isRequiredSlot) {
|
|
121
|
-
requiredSlotAliases.push(slotAlias);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
127
|
if (slotNodes[slotAlias]) {
|
|
125
128
|
slotNodes[slotAlias].push(child);
|
|
126
129
|
}
|
|
@@ -131,6 +134,7 @@ const useSlots = (children, Caller) => {
|
|
|
131
134
|
else
|
|
132
135
|
unmatchedChildren.push(child);
|
|
133
136
|
});
|
|
137
|
+
/** @todo Type keys as NonNullable if included in this array. */
|
|
134
138
|
requiredSlotAliases.forEach((slotAlias) => {
|
|
135
139
|
if (!slotNodes[slotAlias]) {
|
|
136
140
|
(0, errors_1.throwDevError)(`Missing required slot "${String(slotAlias)}".`);
|
|
@@ -18,12 +18,7 @@ export type DisplayNamedComponent<TComponent extends ComponentType<any> = Compon
|
|
|
18
18
|
displayName: TName;
|
|
19
19
|
};
|
|
20
20
|
interface ISlotConfig<TName> {
|
|
21
|
-
slotName
|
|
22
|
-
/**
|
|
23
|
-
* @deprecated The SlottedComponent should be responsible for indicating which slots it requires.
|
|
24
|
-
* Individual slot components may be reused by multiple slotted components with varying requirements.
|
|
25
|
-
*/
|
|
26
|
-
isRequiredSlot?: boolean;
|
|
21
|
+
slotName?: TName;
|
|
27
22
|
}
|
|
28
23
|
/**
|
|
29
24
|
* A child component used to insert content into a specific slot in the parent component.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
interface IDebouncedFunction<TFunc extends AnyFunction> {
|
|
2
|
+
(...args: Parameters<TFunc>): Promise<ReturnType<TFunc>>;
|
|
3
|
+
/**
|
|
4
|
+
* Called internally to trigger the callback with the most recent args
|
|
5
|
+
* after the delay expires. Can be used to manually trigger the callback
|
|
6
|
+
* before the normal delay time. If no pending call exists, flush() becomes a no-op.
|
|
7
|
+
*/
|
|
8
|
+
flush: (isEager?: true) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface IDelayConfig {
|
|
11
|
+
/**
|
|
12
|
+
* A non-zero delay in milliseconds.
|
|
13
|
+
* @default 0
|
|
14
|
+
*/
|
|
15
|
+
delay?: number;
|
|
16
|
+
/**
|
|
17
|
+
* The 'last-call' value specifies that the timer should be applied from the time of the most recent call.
|
|
18
|
+
* That means each new call while a delay is active will reset the timer, thereby extending the delay.
|
|
19
|
+
* In other words, it is a "time after inactivity" delay.
|
|
20
|
+
* Specifying 'first-call' instead will make it use a "time after initial call" delay strategy.
|
|
21
|
+
*/
|
|
22
|
+
anchor?: 'first-call' | 'last-call';
|
|
23
|
+
/**
|
|
24
|
+
* Controls eager execution behavior:
|
|
25
|
+
* - `false`: Initial call waits for the delay period before executing.
|
|
26
|
+
* - `'no-queue'`: Initial call fires immediately. Subsequent calls during the delay period
|
|
27
|
+
* are skipped and return the promise from the initial call. Ideal for preventing
|
|
28
|
+
* duplicate actions like clicking a download button twice.
|
|
29
|
+
* - `'with-queue'`: Initial call fires immediately. After the initial flush, the promise
|
|
30
|
+
* is discarded. The next call during the delay period creates a new workorder that will
|
|
31
|
+
* be maintained until the next flush. Ideal for debounced search inputs and similar use cases.
|
|
32
|
+
* @default 'with-queue'
|
|
33
|
+
*/
|
|
34
|
+
eager?: false | 'no-queue' | 'with-queue';
|
|
35
|
+
}
|
|
36
|
+
interface IDebounce {
|
|
37
|
+
<TFunc extends AnyFunction>(callback: TFunc, delayConfigArg?: number | IDelayConfig): IDebouncedFunction<TFunc>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Wraps the provided function with a debounce.
|
|
41
|
+
*
|
|
42
|
+
* Behavior during the delay period depends on the `eager` configuration:
|
|
43
|
+
* - `eager: false`: All calls wait for the delay. New calls overwrite the existing call.
|
|
44
|
+
* - `eager: 'no-queue'`: First call fires immediately. Subsequent calls during the delay
|
|
45
|
+
* period are skipped and return the same promise as the initial call.
|
|
46
|
+
* - `eager: 'with-queue'` (default): First call fires immediately. After the flush, the next call
|
|
47
|
+
* creates a new workorder that will be fired after the delay. New calls overwrite queued args.
|
|
48
|
+
*
|
|
49
|
+
* Once the timer expires, the most recent call is fired.
|
|
50
|
+
*
|
|
51
|
+
* Note: Returned promises may resolve with values from calls made with
|
|
52
|
+
* different arguments. Avoid using this for functions where argument-specific results matter.
|
|
53
|
+
*/
|
|
54
|
+
export declare const debounce: IDebounce;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Wraps the provided function with a debounce.
|
|
12
|
+
*
|
|
13
|
+
* Behavior during the delay period depends on the `eager` configuration:
|
|
14
|
+
* - `eager: false`: All calls wait for the delay. New calls overwrite the existing call.
|
|
15
|
+
* - `eager: 'no-queue'`: First call fires immediately. Subsequent calls during the delay
|
|
16
|
+
* period are skipped and return the same promise as the initial call.
|
|
17
|
+
* - `eager: 'with-queue'` (default): First call fires immediately. After the flush, the next call
|
|
18
|
+
* creates a new workorder that will be fired after the delay. New calls overwrite queued args.
|
|
19
|
+
*
|
|
20
|
+
* Once the timer expires, the most recent call is fired.
|
|
21
|
+
*
|
|
22
|
+
* Note: Returned promises may resolve with values from calls made with
|
|
23
|
+
* different arguments. Avoid using this for functions where argument-specific results matter.
|
|
24
|
+
*/
|
|
25
|
+
export const debounce = (...init) => {
|
|
26
|
+
const [callback, delayArg] = init;
|
|
27
|
+
const delayConfig = {
|
|
28
|
+
delay: 1000,
|
|
29
|
+
anchor: 'first-call',
|
|
30
|
+
eager: 'with-queue',
|
|
31
|
+
};
|
|
32
|
+
if (typeof delayArg === 'number') {
|
|
33
|
+
delayConfig.delay = delayArg || 1000;
|
|
34
|
+
}
|
|
35
|
+
else if (delayArg) {
|
|
36
|
+
for (const _key in delayArg) {
|
|
37
|
+
const key = _key;
|
|
38
|
+
if (delayArg[key] !== undefined) {
|
|
39
|
+
// @ts-expect-error
|
|
40
|
+
delayConfig[key] = delayArg[key];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let nextCall = null;
|
|
45
|
+
const debouncedFunction = (...args) => {
|
|
46
|
+
let currentWork;
|
|
47
|
+
if (nextCall) {
|
|
48
|
+
if (delayConfig.eager !== 'no-queue') {
|
|
49
|
+
nextCall = Object.assign(Object.assign({}, nextCall), { args, work: nextCall.work || Promise.withResolvers() });
|
|
50
|
+
}
|
|
51
|
+
currentWork = nextCall.work;
|
|
52
|
+
if (delayConfig.anchor === 'last-call') {
|
|
53
|
+
clearTimeout(nextCall.timeout);
|
|
54
|
+
nextCall.timeout = setTimeout(debouncedFunction.flush, delayConfig.delay);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// No active delay, create new call
|
|
59
|
+
nextCall = {
|
|
60
|
+
args,
|
|
61
|
+
timeout: setTimeout(debouncedFunction.flush, delayConfig.delay),
|
|
62
|
+
work: Promise.withResolvers(),
|
|
63
|
+
};
|
|
64
|
+
currentWork = nextCall.work;
|
|
65
|
+
// Fire immediately if eager mode is enabled (no-queue or with-queue)
|
|
66
|
+
if (delayConfig.eager !== false) {
|
|
67
|
+
debouncedFunction.flush(true);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!currentWork) {
|
|
71
|
+
throw new Error('[debounce] `currentWork` was not initialized.');
|
|
72
|
+
}
|
|
73
|
+
return currentWork.promise;
|
|
74
|
+
};
|
|
75
|
+
debouncedFunction.flush = (isEager) => {
|
|
76
|
+
if (!(nextCall === null || nextCall === void 0 ? void 0 : nextCall.args)) {
|
|
77
|
+
nextCall = null;
|
|
78
|
+
// console.log('Queue is empty. Nothing to flush.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Capture queue values.
|
|
82
|
+
const { resolve, reject } = nextCall.work || {};
|
|
83
|
+
const args = nextCall.args;
|
|
84
|
+
// Clear the queue for new debounced calls.
|
|
85
|
+
if (isEager) {
|
|
86
|
+
delete nextCall.args;
|
|
87
|
+
if (delayConfig.eager === 'with-queue') {
|
|
88
|
+
delete nextCall.work;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
nextCall = null;
|
|
93
|
+
}
|
|
94
|
+
// Execute the pending call.
|
|
95
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
96
|
+
var _a;
|
|
97
|
+
try {
|
|
98
|
+
const result = (_a = (yield callback(...args))) !== null && _a !== void 0 ? _a : {};
|
|
99
|
+
result.__debounceFlushedWithArgs = args;
|
|
100
|
+
resolve === null || resolve === void 0 ? void 0 : resolve(result);
|
|
101
|
+
}
|
|
102
|
+
catch (_reason) {
|
|
103
|
+
const reason = _reason !== null && _reason !== void 0 ? _reason : {};
|
|
104
|
+
reason.__debounceFlushedWithArgs = args;
|
|
105
|
+
reject === null || reject === void 0 ? void 0 : reject(reason);
|
|
106
|
+
}
|
|
107
|
+
}))();
|
|
108
|
+
};
|
|
109
|
+
return debouncedFunction;
|
|
110
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { debounce } from './index.js';
|
|
2
|
+
type TDebounceConfig = Exclude<Parameters<typeof debounce>[1], number>;
|
|
3
|
+
type TDelayConfig = number | TDebounceConfig & {
|
|
4
|
+
staging?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function useDebouncedState<T extends any>(init: T, config: TDelayConfig): readonly [T, (value: T) => void, T];
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react.js';
|
|
2
|
+
import { debounce } from './index.js';
|
|
3
|
+
export function useDebouncedState(init, config) {
|
|
4
|
+
const [debouncedValue, setDebouncedValue] = useState(init);
|
|
5
|
+
const [stagedValue, setStagedValue] = useState(init);
|
|
6
|
+
const enableStaging = typeof config === 'object' && config.staging === true;
|
|
7
|
+
const debounceArgs = [setDebouncedValue, config];
|
|
8
|
+
const debouncedSetter = useCallback(debounce(...debounceArgs), debounceArgs);
|
|
9
|
+
const setter = useCallback((value) => {
|
|
10
|
+
if (enableStaging) {
|
|
11
|
+
setStagedValue(value);
|
|
12
|
+
}
|
|
13
|
+
debouncedSetter(value);
|
|
14
|
+
}, [enableStaging, debouncedSetter]);
|
|
15
|
+
return [debouncedValue, setter, stagedValue];
|
|
16
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
type TRecord = Record<keyof any, any>;
|
|
2
|
+
declare namespace _ObjectGate {
|
|
3
|
+
/** Configure property access for a proxy object. */
|
|
4
|
+
interface IGateConfig<TSource extends TRecord> {
|
|
5
|
+
/**
|
|
6
|
+
* The keys to be exposed for read access through the proxy.
|
|
7
|
+
* Defaults to [`Reflect.ownKeys(source)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/ownKeys) —
|
|
8
|
+
* so if omitted, all ["_own properties_"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Enumerability_and_ownership_of_properties)
|
|
9
|
+
* present on the source at
|
|
10
|
+
* instantiation time will be exposed for read access through the proxy.
|
|
11
|
+
*/
|
|
12
|
+
getters?: Readonly<Array<keyof TSource>>;
|
|
13
|
+
/**
|
|
14
|
+
* Keys that should definitely be omitted from read access,
|
|
15
|
+
* even if they are present in {@link getters}.
|
|
16
|
+
* @default [] - Empty array.
|
|
17
|
+
*/
|
|
18
|
+
gettersExclude?: Readonly<Array<keyof TSource>>;
|
|
19
|
+
/**
|
|
20
|
+
* The keys to be exposed for write access through the proxy.
|
|
21
|
+
* This defaults to an empty array, so if omitted, none of the gated
|
|
22
|
+
* properties will be writeable.
|
|
23
|
+
* @default [] - Empty array.
|
|
24
|
+
*/
|
|
25
|
+
setters?: Readonly<Array<keyof TSource> | true>;
|
|
26
|
+
/**
|
|
27
|
+
* Keys that should definitely be omitted from write access,
|
|
28
|
+
* even if they are present in {@link setters}.
|
|
29
|
+
* @default [] - Empty array.
|
|
30
|
+
*/
|
|
31
|
+
settersExclude?: Readonly<Array<keyof TSource>>;
|
|
32
|
+
}
|
|
33
|
+
type Params<TSource extends TRecord> = [
|
|
34
|
+
/**
|
|
35
|
+
* The target object, where the actual values are stored.
|
|
36
|
+
* Keys on the created gate object will use JavaScript getters to return
|
|
37
|
+
* the real-time value of the same key from this source object.
|
|
38
|
+
*/
|
|
39
|
+
source: TSource,
|
|
40
|
+
/** @see {@link IGateConfig} */
|
|
41
|
+
config?: Readonly<IGateConfig<TSource>>
|
|
42
|
+
];
|
|
43
|
+
class Gate<TSource extends TRecord> {
|
|
44
|
+
constructor(...params: Params<TSource>);
|
|
45
|
+
}
|
|
46
|
+
interface IConstructor {
|
|
47
|
+
new <TOutput extends Partial<TSource>, TSource extends TRecord>(...params: _ObjectGate.Params<TSource>): TOutput;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new object that acts as a real-time proxy
|
|
52
|
+
* for the {@link _ObjectGate.Params | `source`} object.
|
|
53
|
+
* This lets you prevent access to some properties, effectively making them private,
|
|
54
|
+
* while selectively exposing access to only the properties you specify
|
|
55
|
+
* in the {@link _ObjectGate.IGateConfig.getters | `getters`} config option.
|
|
56
|
+
*
|
|
57
|
+
* The exposed properties are read-only by default,
|
|
58
|
+
* exposing only a [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description)
|
|
59
|
+
* with no corresponding [setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set#description).
|
|
60
|
+
*
|
|
61
|
+
* The {@link _ObjectGate.Params | `config`} argument also lets you selectively allow
|
|
62
|
+
* write access to specific properties through the
|
|
63
|
+
* {@link _ObjectGate.IGateConfig.setters | `setters`} config option.
|
|
64
|
+
*
|
|
65
|
+
* Unlike [`structuredClone`](https://developer.mozilla.org/docs/Web/API/Window/structuredClone)
|
|
66
|
+
* this doesn't return a _copy_ of the `source` object.
|
|
67
|
+
*
|
|
68
|
+
* Instead, it returns a _**Real-time proxy**_. This means that a value is read
|
|
69
|
+
* from the source object each time a property is accessed through the proxy.
|
|
70
|
+
* So accessing a property through the gate object is guaranteed to always return
|
|
71
|
+
* the latest value.
|
|
72
|
+
*/
|
|
73
|
+
export declare const ObjectGate: _ObjectGate.IConstructor;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
var _ObjectGate;
|
|
2
|
+
(function (_ObjectGate) {
|
|
3
|
+
class Gate {
|
|
4
|
+
constructor(...params) {
|
|
5
|
+
var _a, _b, _c, _d;
|
|
6
|
+
const [source, config] = params;
|
|
7
|
+
const getters = (_a = config === null || config === void 0 ? void 0 : config.getters) !== null && _a !== void 0 ? _a : Reflect.ownKeys(source);
|
|
8
|
+
const gettersExclude = (_b = config === null || config === void 0 ? void 0 : config.gettersExclude) !== null && _b !== void 0 ? _b : [];
|
|
9
|
+
const setters = (config === null || config === void 0 ? void 0 : config.setters) === true
|
|
10
|
+
? getters
|
|
11
|
+
: ((_c = config === null || config === void 0 ? void 0 : config.setters) !== null && _c !== void 0 ? _c : []);
|
|
12
|
+
const settersExclude = (_d = config === null || config === void 0 ? void 0 : config.settersExclude) !== null && _d !== void 0 ? _d : [];
|
|
13
|
+
getters.forEach((_key) => {
|
|
14
|
+
const key = _key;
|
|
15
|
+
if (gettersExclude.includes(key))
|
|
16
|
+
return;
|
|
17
|
+
Object.defineProperty(this, key, {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
get() {
|
|
21
|
+
return source[key];
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
setters.forEach((_key) => {
|
|
26
|
+
const key = _key;
|
|
27
|
+
if (settersExclude.includes(key))
|
|
28
|
+
return;
|
|
29
|
+
Object.defineProperty(this, key, {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
set(value) {
|
|
32
|
+
source[key] = value;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
_ObjectGate.Gate = Gate;
|
|
39
|
+
;
|
|
40
|
+
})(_ObjectGate || (_ObjectGate = {}));
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new object that acts as a real-time proxy
|
|
43
|
+
* for the {@link _ObjectGate.Params | `source`} object.
|
|
44
|
+
* This lets you prevent access to some properties, effectively making them private,
|
|
45
|
+
* while selectively exposing access to only the properties you specify
|
|
46
|
+
* in the {@link _ObjectGate.IGateConfig.getters | `getters`} config option.
|
|
47
|
+
*
|
|
48
|
+
* The exposed properties are read-only by default,
|
|
49
|
+
* exposing only a [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get#description)
|
|
50
|
+
* with no corresponding [setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set#description).
|
|
51
|
+
*
|
|
52
|
+
* The {@link _ObjectGate.Params | `config`} argument also lets you selectively allow
|
|
53
|
+
* write access to specific properties through the
|
|
54
|
+
* {@link _ObjectGate.IGateConfig.setters | `setters`} config option.
|
|
55
|
+
*
|
|
56
|
+
* Unlike [`structuredClone`](https://developer.mozilla.org/docs/Web/API/Window/structuredClone)
|
|
57
|
+
* this doesn't return a _copy_ of the `source` object.
|
|
58
|
+
*
|
|
59
|
+
* Instead, it returns a _**Real-time proxy**_. This means that a value is read
|
|
60
|
+
* from the source object each time a property is accessed through the proxy.
|
|
61
|
+
* So accessing a property through the gate object is guaranteed to always return
|
|
62
|
+
* the latest value.
|
|
63
|
+
*/
|
|
64
|
+
export const ObjectGate = _ObjectGate.Gate;
|
package/build/slots/hook.js
CHANGED
|
@@ -23,6 +23,9 @@ export const getComponentSlotName = (TargetComponent, child) => {
|
|
|
23
23
|
else if ('displayName' in TargetComponent) {
|
|
24
24
|
return TargetComponent.displayName;
|
|
25
25
|
}
|
|
26
|
+
else if ('name' in TargetComponent) {
|
|
27
|
+
return TargetComponent.name;
|
|
28
|
+
}
|
|
26
29
|
return undefined;
|
|
27
30
|
};
|
|
28
31
|
export const isPortalChild = (child) => {
|
|
@@ -43,14 +46,18 @@ export const isPortalChild = (child) => {
|
|
|
43
46
|
export const useSlots = (children, Caller) => {
|
|
44
47
|
const slotsAliasLookup = useMemo(() => {
|
|
45
48
|
const entries = Object.entries(Caller.Slots);
|
|
46
|
-
const aliasLookup = {
|
|
49
|
+
const aliasLookup = {
|
|
50
|
+
byName: {},
|
|
51
|
+
byIdentity: new Map(),
|
|
52
|
+
};
|
|
47
53
|
entries.forEach(([alias, RegisteredSlotComponent]) => {
|
|
48
54
|
const slotName = getComponentSlotName(RegisteredSlotComponent);
|
|
49
55
|
if (!slotName) {
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
aliasLookup.byIdentity.set(RegisteredSlotComponent, alias);
|
|
57
|
+
aliasLookup.byName[alias] = alias;
|
|
52
58
|
}
|
|
53
|
-
|
|
59
|
+
else
|
|
60
|
+
aliasLookup.byName[slotName] = alias;
|
|
54
61
|
});
|
|
55
62
|
return aliasLookup;
|
|
56
63
|
}, [Caller.Slots]);
|
|
@@ -64,7 +71,6 @@ export const useSlots = (children, Caller) => {
|
|
|
64
71
|
...((_a = Caller.requiredSlotAliases) !== null && _a !== void 0 ? _a : [])
|
|
65
72
|
];
|
|
66
73
|
React.Children.forEach(children, (_child) => {
|
|
67
|
-
var _a;
|
|
68
74
|
const child = _child;
|
|
69
75
|
if (!child) {
|
|
70
76
|
invalidChildren.push(child);
|
|
@@ -82,16 +88,13 @@ export const useSlots = (children, Caller) => {
|
|
|
82
88
|
return;
|
|
83
89
|
}
|
|
84
90
|
const slotAlias = (() => {
|
|
85
|
-
var _a;
|
|
86
91
|
const slotName = getComponentSlotName(child.type, child);
|
|
87
|
-
|
|
92
|
+
const alias = slotName
|
|
93
|
+
? slotsAliasLookup.byName[slotName]
|
|
94
|
+
: slotsAliasLookup.byIdentity.get(child.type);
|
|
95
|
+
return alias !== null && alias !== void 0 ? alias : null;
|
|
88
96
|
})();
|
|
89
97
|
if (slotAlias) {
|
|
90
|
-
if (typeof Caller.Slots[slotAlias] !== 'string') {
|
|
91
|
-
if ((_a = Caller.Slots[slotAlias]) === null || _a === void 0 ? void 0 : _a.isRequiredSlot) {
|
|
92
|
-
requiredSlotAliases.push(slotAlias);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
98
|
if (slotNodes[slotAlias]) {
|
|
96
99
|
slotNodes[slotAlias].push(child);
|
|
97
100
|
}
|
|
@@ -102,6 +105,7 @@ export const useSlots = (children, Caller) => {
|
|
|
102
105
|
else
|
|
103
106
|
unmatchedChildren.push(child);
|
|
104
107
|
});
|
|
108
|
+
/** @todo Type keys as NonNullable if included in this array. */
|
|
105
109
|
requiredSlotAliases.forEach((slotAlias) => {
|
|
106
110
|
if (!slotNodes[slotAlias]) {
|
|
107
111
|
throwDevError(`Missing required slot "${String(slotAlias)}".`);
|
package/build/slots/types.d.ts
CHANGED
|
@@ -18,12 +18,7 @@ export type DisplayNamedComponent<TComponent extends ComponentType<any> = Compon
|
|
|
18
18
|
displayName: TName;
|
|
19
19
|
};
|
|
20
20
|
interface ISlotConfig<TName> {
|
|
21
|
-
slotName
|
|
22
|
-
/**
|
|
23
|
-
* @deprecated The SlottedComponent should be responsible for indicating which slots it requires.
|
|
24
|
-
* Individual slot components may be reused by multiple slotted components with varying requirements.
|
|
25
|
-
*/
|
|
26
|
-
isRequiredSlot?: boolean;
|
|
21
|
+
slotName?: TName;
|
|
27
22
|
}
|
|
28
23
|
/**
|
|
29
24
|
* A child component used to insert content into a specific slot in the parent component.
|
package/package.json
CHANGED