Skip to content

Commit

Permalink
feat: add inspectChildren function
Browse files Browse the repository at this point in the history
  • Loading branch information
juanrgm committed Nov 22, 2022
1 parent a90da3c commit 64eae19
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changeset/silver-mice-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@suid/base": minor
"@suid/system": minor
---

Add internal hook for inspecting all suid components
3 changes: 2 additions & 1 deletion packages/base/src/createComponentFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import useBaseThemeProps, {
PropDefaultsCb,
ThemePropOptions,
} from "./useThemeProps";
import { componentTrap } from "@suid/system/inspect";
import {
InPropsOf,
PropsOf,
Expand Down Expand Up @@ -84,7 +85,7 @@ function createComponentFactory<
cb: (props: Props) => JSXElement
): C extends OverridableTypeMap ? OverridableComponent<C> : SuidElement<C> {
cb.toString = () => `${options.name}-root`;
return cb as any;
return componentTrap(cb) as any;
}

function component(
Expand Down
85 changes: 85 additions & 0 deletions packages/system/src/inspect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Component, createMemo, JSX } from "solid-js";

export const $INSPECT = Symbol("solid-inspect");

export type ComponentObject<T = any> = {
Component: Component<T>;
props: T;
};

type PrivateComponentObject<T = any> = ComponentObject<T> & {
$INSPECT: Symbol;
};

export type InspectResult = JSX.Element | ComponentObject;

let inspectionEnabled = false;

export function inspect(fn: () => JSX.Element): InspectResult[] {
try {
inspectionEnabled = true;
const result = fn();
return Array.isArray(result) ? result : [result];
} finally {
inspectionEnabled = false;
}
}

export function componentTrap<T>(fn: Component<T>): Component<T> {
function Component(props: T) {
if (inspectionEnabled)
return {
Component,
props,
$INSPECT,
} as PrivateComponentObject as any;
return fn(props);
}
Object.defineProperty(Component, "name", {
value: fn.name,
});
Component.toString = fn.toString;
return Component;
}

export function isComponentObject(input: unknown): input is ComponentObject;
export function isComponentObject<T>(
input: unknown,
component: Component<T>
): input is ComponentObject<T>;
export function isComponentObject(input: unknown, component?: Component) {
return (
!!input &&
(input as PrivateComponentObject).$INSPECT === $INSPECT &&
(!component || (input as PrivateComponentObject).Component === component)
);
}

export function resolveChildren(children: any): unknown {
if (typeof children === "function" && !children.length)
return resolveChildren(children());
if (Array.isArray(children)) {
const results: any[] = [];
for (let i = 0; i < children.length; i++) {
const result = resolveChildren(children[i]);
Array.isArray(result)
? // eslint-disable-next-line prefer-spread
results.push.apply(results, result)
: results.push(result);
}
return results;
}
return children;
}

export function inspectChildren(fn: () => any) {
const children = createMemo(() => inspect(fn));
const memo = createMemo(() =>
inspect(() => resolveChildren(children()) as any)
);
(memo as any).toArray = () => {
const c = memo();
return Array.isArray(c) ? c : c != null ? [c] : [];
};
return children;
}

0 comments on commit 64eae19

Please sign in to comment.