@cleanweb/oore 2.0.0-beta.3 → 2.0.0-beta.4

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.
@@ -1,10 +1,11 @@
1
- import type { ReactElement, ReactNode } from 'react';
1
+ import type { ReactElement, ReactNode, ReactPortal } from 'react';
2
2
  import type { IUseSlots, PotentialSlotComponent } from './types';
3
3
  export declare const isElementChild: (child: ReactNode) => child is ReactElement<any, any>;
4
4
  interface IGetSlotName {
5
5
  (TargetComponent: PotentialSlotComponent, child?: ReactElement): string | undefined;
6
6
  }
7
7
  export declare const getComponentSlotName: IGetSlotName;
8
+ export declare const isPortalChild: (child: ReactNode) => child is ReactPortal;
8
9
  /**
9
10
  * Groups `children` prop into predefined slots.
10
11
  *
@@ -16,4 +17,4 @@ export declare const getComponentSlotName: IGetSlotName;
16
17
  * @see {@link SlotComponent} for more on how to use the returned slot nodes.
17
18
  */
18
19
  export declare const useSlots: IUseSlots;
19
- export type { SlotNamedComponent, Slotted as SlottedComponent, TSlotsRecord, PotentialSlotComponent, } from './types';
20
+ export type { SlottedComponent, TSlotsRecord, PotentialSlotComponent, } from './types';
@@ -32,7 +32,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
32
32
  return to.concat(ar || Array.prototype.slice.call(from));
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.useSlots = exports.getComponentSlotName = exports.isElementChild = void 0;
35
+ exports.useSlots = exports.isPortalChild = exports.getComponentSlotName = exports.isElementChild = void 0;
36
36
  var errors_1 = require("../helpers/errors");
37
37
  var react_1 = __importStar(require("react"));
38
38
  var isElementChild = function (child) {
@@ -65,6 +65,12 @@ var getComponentSlotName = function (TargetComponent, child) {
65
65
  return undefined;
66
66
  };
67
67
  exports.getComponentSlotName = getComponentSlotName;
68
+ var isPortalChild = function (child) {
69
+ return (!!child
70
+ && typeof child === 'object'
71
+ && 'children' in child);
72
+ };
73
+ exports.isPortalChild = isPortalChild;
68
74
  /**
69
75
  * Groups `children` prop into predefined slots.
70
76
  *
@@ -96,8 +102,9 @@ var useSlots = function (children, Caller) {
96
102
  var unmatchedChildren = [];
97
103
  var invalidChildren = [];
98
104
  var requiredSlotAliases = __spreadArray([], ((_a = Caller.requiredSlotAliases) !== null && _a !== void 0 ? _a : []), true);
99
- react_1.default.Children.forEach(children, function (child) {
105
+ react_1.default.Children.forEach(children, function (_child) {
100
106
  var _a;
107
+ var child = _child;
101
108
  if (!child) {
102
109
  invalidChildren.push(child);
103
110
  return;
@@ -114,15 +121,16 @@ var useSlots = function (children, Caller) {
114
121
  return;
115
122
  }
116
123
  var slotAlias = (function () {
124
+ var _a;
117
125
  var slotName = (0, exports.getComponentSlotName)(child.type, child);
118
- return slotName ? slotsAliasLookup[slotName] : null;
126
+ return slotName ? (_a = slotsAliasLookup[slotName]) !== null && _a !== void 0 ? _a : null : null;
119
127
  })();
120
- if (slotAlias && (typeof Caller.Slots[slotAlias] !== 'string')) {
121
- if ((_a = Caller.Slots[slotAlias]) === null || _a === void 0 ? void 0 : _a.isRequiredSlot) {
122
- requiredSlotAliases.push(slotAlias);
123
- }
124
- }
125
128
  if (slotAlias) {
129
+ if (typeof Caller.Slots[slotAlias] !== 'string') {
130
+ if ((_a = Caller.Slots[slotAlias]) === null || _a === void 0 ? void 0 : _a.isRequiredSlot) {
131
+ requiredSlotAliases.push(slotAlias);
132
+ }
133
+ }
126
134
  if (slotNodes[slotAlias]) {
127
135
  slotNodes[slotAlias].push(child);
128
136
  }
@@ -1,7 +1,7 @@
1
- import { ComponentMethods } from '../base';
2
- import { ComponentLogic } from '../classy';
3
- import type { ReactElement, ReactNode, JSXElementConstructor } from 'react';
4
- export type TComponent = JSXElementConstructor<any> | ComponentLogic | ComponentMethods;
1
+ import type { ReactElement, ReactNode, ComponentType, ReactPortal } from 'react';
2
+ type JSXTagLike = string | keyof JSX.IntrinsicElements | ComponentType<any>;
3
+ /** This fixes overly narrow T type used by React's ComponentProps type. */
4
+ export type ComponentProps<T extends JSXTagLike> = (T extends ComponentType<infer P> ? P : T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : {});
5
5
  export type TSlotName = keyof any;
6
6
  export type TSlotAlias = keyof any;
7
7
  /**
@@ -11,18 +11,24 @@ export type TSlotAlias = keyof any;
11
11
  * each alias in this record to hold any `ReactNode`s rendered for that slot.
12
12
  */
13
13
  export type TSlotsRecord<TKey extends TSlotAlias = TSlotAlias> = {
14
- [Key in TKey]: string | SlotComponent;
14
+ [Key in TKey]: SlotComponent<string | ComponentType<any>>;
15
15
  };
16
- export type DisplayNamedComponent<TComponentArg extends TComponent = TComponent, TDisplayNameArg extends string = string> = TComponentArg & {
17
- displayName: TDisplayNameArg;
18
- };
19
- export type SlotNamedComponent<TComponentArg extends TComponent = TComponent, TSlotNameArg extends TSlotName = TSlotName> = TComponentArg & {
20
- slotName: TSlotNameArg;
16
+ export type DisplayNamedComponent<TComponent extends ComponentType<any> = ComponentType<any>, TName extends string = string> = TComponent & {
17
+ displayName: TName;
21
18
  };
19
+ interface ISlotConfig<TName> {
20
+ slotName: TName;
21
+ /**
22
+ * @deprecated The SlottedComponent should be responsible for indicating which slots it requires.
23
+ * Individual slot components may be reused by multiple slotted components with varying requirements.
24
+ */
25
+ isRequiredSlot?: boolean;
26
+ }
22
27
  /**
23
28
  * A child component used to insert content into a specific slot in the parent component.
24
29
  * This can either be a string, or a React component with a `slotName` property.
25
- * If `slotName` is missing `displayName` will be used as a fallback.
30
+ *
31
+ * > `displayName` is no longer supported as a fallback for `slotName`.
26
32
  *
27
33
  * ### Strings
28
34
  * For strings, they are treated by React a native tags. This lets you use custom strings
@@ -38,7 +44,7 @@ export type SlotNamedComponent<TComponentArg extends TComponent = TComponent, TS
38
44
  * and you can map that to
39
45
  * ```jsx
40
46
  * <button
41
- * {...slotNodes.Option.props}
47
+ * {...slotNodes.Option[0].props}
42
48
  * type="button"
43
49
  * />
44
50
  * ```
@@ -49,9 +55,9 @@ export type SlotNamedComponent<TComponentArg extends TComponent = TComponent, TS
49
55
  *
50
56
  * So consumers may pass the following as `children`.
51
57
  * ```jsx
52
- * <Parent.slots.Content>
58
+ * <Parent.Slots.Content>
53
59
  * Some awesome content.
54
- * </Parent.slots.Content>
60
+ * </Parent.Slots.Content>
55
61
  * ```
56
62
  * and you can map that to
57
63
  * ```jsx
@@ -62,7 +68,7 @@ export type SlotNamedComponent<TComponentArg extends TComponent = TComponent, TS
62
68
  * </>
63
69
  * ```
64
70
  *
65
- * This means `Parent.slots.Content` must be defined as a proper React component
71
+ * This means `Parent.Slots.Content` must be defined as a proper React component
66
72
  * and is solely responsible for doing something with the `"Some awesome content."`
67
73
  * which was passed into it as children.
68
74
  *
@@ -70,9 +76,7 @@ export type SlotNamedComponent<TComponentArg extends TComponent = TComponent, TS
70
76
  * extracts the props passed to the slot and handles
71
77
  * what the slot actually renders.
72
78
  */
73
- export type SlotComponent<TComponentArg extends TComponent = TComponent> = (SlotNamedComponent<TComponentArg> | DisplayNamedComponent<TComponentArg>) & {
74
- isRequiredSlot?: boolean;
75
- };
79
+ export type SlotComponent<TComponent extends JSXTagLike = ComponentType<any>, TName extends TSlotName = TSlotName> = (TComponent extends string ? TComponent : TComponent & ISlotConfig<TName>);
76
80
  /**
77
81
  * A parent component which accepts content that can be grouped into predefined slots.
78
82
  * By convention, it should have a `slots` property which is a {@link TSlotsRecord}.
@@ -81,18 +85,20 @@ export type SlotComponent<TComponentArg extends TComponent = TComponent> = (Slot
81
85
  * directly from the parent component itself,
82
86
  * through an alias that is easy to remember.
83
87
  */
84
- export type Slotted<TComponentArg extends object = TComponent, TSlotAliasArg extends TSlotAlias = TSlotAlias, TSlotsRecordArg extends TSlotsRecord<TSlotAliasArg> = TSlotsRecord<TSlotAliasArg>> = TComponentArg & {
85
- Slots: TSlotsRecordArg;
86
- requiredSlotAliases?: TSlotAliasArg[];
88
+ export type SlottedComponent<TOwner extends object = ComponentType<any>, TSlots extends TSlotsRecord = TSlotsRecord> = TOwner & {
89
+ Slots: TSlots;
90
+ requiredSlotAliases?: Array<keyof TSlots>;
87
91
  };
92
+ export type TypedNode<P, T extends JSXTagLike> = (ReactElement<P, T> | (ReactElement<P, T> & ReactPortal));
93
+ export type TSlotNode<TSlottted extends SlottedComponent> = TypedNode<ComponentProps<valueof<TSlottted['Slots']>>, valueof<TSlottted['Slots']>>;
88
94
  /**
89
95
  * A record of slot aliases mapped to the corresponding `ReactNode`(s)
90
96
  * to be rendered for that slot.
91
97
  */
92
- export type TSlotNodes<TSlotAliasArg extends TSlotAlias> = {
93
- [Key in TSlotAliasArg]?: Array<ReactElement<any>>;
98
+ export type TSlotNodes<TSlottted extends SlottedComponent> = {
99
+ [Key in keyof TSlottted['Slots']]?: Array<TSlotNode<TSlottted>>;
94
100
  };
95
- export type TUseSlotsResult<TSlotAliasArg extends TSlotAlias = TSlotAlias> = Readonly<[
101
+ export type TUseSlotsResult<TSlotted extends SlottedComponent> = Readonly<[
96
102
  /**
97
103
  * A record of slot aliases to their corresponding React nodes.
98
104
  * Each alias maps to an array of one or more React nodes that were passed
@@ -100,7 +106,7 @@ export type TUseSlotsResult<TSlotAliasArg extends TSlotAlias = TSlotAlias> = Rea
100
106
  *
101
107
  * If a slot was not rendered in `children`, it's alias will be `undefined` in this object.
102
108
  */
103
- slotNodes: TSlotNodes<TSlotAliasArg>,
109
+ slotNodes: TSlotNodes<TSlotted>,
104
110
  /**
105
111
  * Valid React nodes passed as children which did not match any of the
106
112
  * predefined slots.
@@ -112,12 +118,13 @@ export type TUseSlotsResult<TSlotAliasArg extends TSlotAlias = TSlotAlias> = Rea
112
118
  invalidChildren: any[]
113
119
  ]>;
114
120
  export interface IUseSlots {
115
- <TSlotAliasArg extends TSlotAlias = TSlotAlias>(
121
+ <TSlotted extends SlottedComponent>(
116
122
  /**
117
123
  * Your component's `children` prop.
118
124
  * The nodes it contains will be categorized and
119
125
  * grouped according to the predefined {@link slotComponents}.
120
126
  */
121
- children: ReactNode, Caller: Slotted<TComponent, TSlotAliasArg, TSlotsRecord<TSlotAliasArg>>): TUseSlotsResult<TSlotAliasArg>;
127
+ children: ReactNode, Caller: TSlotted): TUseSlotsResult<TSlotted>;
122
128
  }
123
- export type PotentialSlotComponent = string | SlotComponent | TComponent;
129
+ export type PotentialSlotComponent = string | SlotComponent | ComponentType<any>;
130
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleanweb/oore",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.0-beta.4",
4
4
  "description": "A library of helpers for writing cleaner React function components with object-oriented patterns.",
5
5
  "engines": {
6
6
  "node": ">=22"