first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
@@ -0,0 +1,9 @@
import type { IComponentAs } from '../IComponentAs';
/**
* Composes two components which conform to the `IComponentAs` specification; that is, two
* components which accept a `defaultRender` prop, which is a 'default' implementation of
* a component which accepts the same overall props.
*
* @public
*/
export declare function composeComponentAs<TProps extends {}>(outer: IComponentAs<TProps>, inner: IComponentAs<TProps>): IComponentAs<TProps>;
+36
View File
@@ -0,0 +1,36 @@
import { __assign } from "tslib";
import * as React from 'react';
import { createMemoizer } from '../memoize';
function createComposedComponent(outer) {
var Outer = outer;
var outerMemoizer = createMemoizer(function (inner) {
if (outer === inner) {
throw new Error('Attempted to compose a component with itself.');
}
var Inner = inner;
var innerMemoizer = createMemoizer(function (defaultRender) {
var InnerWithDefaultRender = function (innerProps) {
return React.createElement(Inner, __assign({}, innerProps, { defaultRender: defaultRender }));
};
return InnerWithDefaultRender;
});
var OuterWithDefaultRender = function (outerProps) {
var defaultRender = outerProps.defaultRender;
return React.createElement(Outer, __assign({}, outerProps, { defaultRender: defaultRender ? innerMemoizer(defaultRender) : Inner }));
};
return OuterWithDefaultRender;
});
return outerMemoizer;
}
var componentAsMemoizer = createMemoizer(createComposedComponent);
/**
* Composes two components which conform to the `IComponentAs` specification; that is, two
* components which accept a `defaultRender` prop, which is a 'default' implementation of
* a component which accepts the same overall props.
*
* @public
*/
export function composeComponentAs(outer, inner) {
return componentAsMemoizer(outer)(inner);
}
//# sourceMappingURL=composeComponentAs.js.map
@@ -0,0 +1 @@
{"version":3,"file":"composeComponentAs.js","sourceRoot":"../src/","sources":["componentAs/composeComponentAs.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAS5C,SAAS,uBAAuB,CAC9B,KAA2B;IAE3B,IAAM,KAAK,GAAG,KAAK,CAAC;IAEpB,IAAM,aAAa,GAAG,cAAc,CAAC,UAAC,KAA2B;QAC/D,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,IAAM,KAAK,GAAG,KAAK,CAAC;QAEpB,IAAM,aAAa,GAAG,cAAc,CAAC,UAAC,aAAmC;YACvE,IAAM,sBAAsB,GAAmD,UAC7E,UAAqC;gBAErC,OAAO,oBAAC,KAAK,eAAK,UAAU,IAAE,aAAa,EAAE,aAAa,IAAI,CAAC;YACjE,CAAC,CAAC;YAEF,OAAO,sBAAsB,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,IAAM,sBAAsB,GAAmD,UAC7E,UAAqC;YAE7B,IAAA,aAAa,GAAK,UAAU,cAAf,CAAgB;YAErC,OAAO,oBAAC,KAAK,eAAK,UAAU,IAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;QACxG,CAAC,CAAC;QAEF,OAAO,sBAAsB,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,IAAM,mBAAmB,GAAG,cAAc,CAAsB,uBAAuB,CAAC,CAAC;AAEzF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAA2B,EAC3B,KAA2B;IAE3B,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC","sourcesContent":["import * as React from 'react';\nimport { createMemoizer } from '../memoize';\nimport type { IComponentAs, IComponentAsProps } from '../IComponentAs';\n\nimport type { JSXElement } from '../jsx';\n\ninterface IComposeComponentAs {\n <TProps extends {}>(outer: IComponentAs<TProps>): (inner: IComponentAs<TProps>) => IComponentAs<TProps>;\n}\n\nfunction createComposedComponent<TProps extends {}>(\n outer: IComponentAs<TProps>,\n): (inner: IComponentAs<TProps>) => IComponentAs<TProps> {\n const Outer = outer;\n\n const outerMemoizer = createMemoizer((inner: IComponentAs<TProps>) => {\n if (outer === inner) {\n throw new Error('Attempted to compose a component with itself.');\n }\n\n const Inner = inner;\n\n const innerMemoizer = createMemoizer((defaultRender: IComponentAs<TProps>) => {\n const InnerWithDefaultRender: React.ComponentType<IComponentAsProps<TProps>> = (\n innerProps: IComponentAsProps<TProps>,\n ): JSXElement => {\n return <Inner {...innerProps} defaultRender={defaultRender} />;\n };\n\n return InnerWithDefaultRender;\n });\n\n const OuterWithDefaultRender: React.ComponentType<IComponentAsProps<TProps>> = (\n outerProps: IComponentAsProps<TProps>,\n ): JSXElement => {\n const { defaultRender } = outerProps;\n\n return <Outer {...outerProps} defaultRender={defaultRender ? innerMemoizer(defaultRender) : Inner} />;\n };\n\n return OuterWithDefaultRender;\n });\n\n return outerMemoizer;\n}\n\nconst componentAsMemoizer = createMemoizer<IComposeComponentAs>(createComposedComponent);\n\n/**\n * Composes two components which conform to the `IComponentAs` specification; that is, two\n * components which accept a `defaultRender` prop, which is a 'default' implementation of\n * a component which accepts the same overall props.\n *\n * @public\n */\nexport function composeComponentAs<TProps extends {}>(\n outer: IComponentAs<TProps>,\n inner: IComponentAs<TProps>,\n): IComponentAs<TProps> {\n return componentAsMemoizer(outer)(inner);\n}\n"]}
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,42 @@
import { __assign, __rest } from "tslib";
import * as React from 'react';
import { render } from '@testing-library/react';
import { composeComponentAs } from './composeComponentAs';
var Base = function (props) {
return React.createElement("div", { "data-value": props.value });
};
var DecoratorA = function (props) {
var DefaultRender = props.defaultRender, exampleProps = __rest(props, ["defaultRender"]);
return React.createElement("div", { "data-a": "a" }, DefaultRender ? React.createElement(DefaultRender, __assign({}, exampleProps)) : null);
};
var DecoratorB = function (props) {
var DefaultRender = props.defaultRender, exampleProps = __rest(props, ["defaultRender"]);
return React.createElement("div", { "data-b": "b" }, DefaultRender ? React.createElement(DefaultRender, __assign({}, exampleProps)) : null);
};
describe('composeComponentAs', function () {
it('passes Base to DecoratorA', function () {
var DecoratorAWithBase = composeComponentAs(DecoratorA, Base);
var component = render(React.createElement(DecoratorAWithBase, { value: "test" }));
expect(component.container.firstChild).toMatchSnapshot();
});
it('passes Base to DecoratorB through DecoratorA', function () {
var DecoratorAAndBWithBase = composeComponentAs(DecoratorA, composeComponentAs(DecoratorB, Base));
var component = render(React.createElement(DecoratorAAndBWithBase, { value: "test" }));
expect(component.container.firstChild).toMatchSnapshot();
});
it('passes Base as defaultRender to DecoratorB through DecoratorA', function () {
var DecoratorAAroundB = composeComponentAs(DecoratorA, DecoratorB);
var component = render(React.createElement(DecoratorAAroundB, { value: "test", defaultRender: Base }));
expect(component.container.firstChild).toMatchSnapshot();
});
it('renders without defaultRender', function () {
var DecoratorAAroundB = composeComponentAs(DecoratorA, DecoratorB);
var component = render(React.createElement(DecoratorAAroundB, { value: "test" }));
expect(component.container.firstChild).toMatchSnapshot();
});
it('avoids recomposing already-composed components', function () {
var DecoratorAAroundB = composeComponentAs(DecoratorA, DecoratorB);
expect(composeComponentAs(DecoratorA, DecoratorB)).toBe(DecoratorAAroundB);
});
});
//# sourceMappingURL=composeComponentAs.test.js.map
@@ -0,0 +1 @@
{"version":3,"file":"composeComponentAs.test.js","sourceRoot":"../src/","sources":["componentAs/composeComponentAs.test.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAS1D,IAAM,IAAI,GAAuC,UAAC,KAAoB;IACpE,OAAO,2CAAiB,KAAK,CAAC,KAAK,GAAI,CAAC;AAC1C,CAAC,CAAC;AAEF,IAAM,UAAU,GAA0D,UACxE,KAAuC;IAE/B,IAAe,aAAa,GAAsB,KAAK,cAA3B,EAAK,YAAY,UAAK,KAAK,EAAzD,iBAAiD,CAAF,CAAW;IAEhE,OAAO,uCAAY,GAAG,IAAE,aAAa,CAAC,CAAC,CAAC,oBAAC,aAAa,eAAK,YAAY,EAAI,CAAC,CAAC,CAAC,IAAI,CAAO,CAAC;AAC5F,CAAC,CAAC;AAEF,IAAM,UAAU,GAA0D,UACxE,KAAuC;IAE/B,IAAe,aAAa,GAAsB,KAAK,cAA3B,EAAK,YAAY,UAAK,KAAK,EAAzD,iBAAiD,CAAF,CAAW;IAEhE,OAAO,uCAAY,GAAG,IAAE,aAAa,CAAC,CAAC,CAAC,oBAAC,aAAa,eAAK,YAAY,EAAI,CAAC,CAAC,CAAC,IAAI,CAAO,CAAC;AAC5F,CAAC,CAAC;AAEF,QAAQ,CAAC,oBAAoB,EAAE;IAC7B,EAAE,CAAC,2BAA2B,EAAE;QAC9B,IAAM,kBAAkB,GAAG,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAChE,IAAM,SAAS,GAAG,MAAM,CAAC,oBAAC,kBAAkB,IAAC,KAAK,EAAC,MAAM,GAAG,CAAC,CAAC;QAE9D,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,eAAe,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE;QACjD,IAAM,sBAAsB,GAAG,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QACpG,IAAM,SAAS,GAAG,MAAM,CAAC,oBAAC,sBAAsB,IAAC,KAAK,EAAC,MAAM,GAAG,CAAC,CAAC;QAElE,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,eAAe,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE;QAClE,IAAM,iBAAiB,GAAG,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAErE,IAAM,SAAS,GAAG,MAAM,CAAC,oBAAC,iBAAiB,IAAC,KAAK,EAAC,MAAM,EAAC,aAAa,EAAE,IAAI,GAAI,CAAC,CAAC;QAElF,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,eAAe,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE;QAClC,IAAM,iBAAiB,GAAG,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAErE,IAAM,SAAS,GAAG,MAAM,CAAC,oBAAC,iBAAiB,IAAC,KAAK,EAAC,MAAM,GAAG,CAAC,CAAC;QAE7D,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,eAAe,EAAE,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE;QACnD,IAAM,iBAAiB,GAAG,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAErE,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import * as React from 'react';\nimport { render } from '@testing-library/react';\nimport { composeComponentAs } from './composeComponentAs';\nimport type { IComponentAsProps } from '../IComponentAs';\n\nimport type { JSXElement } from '../jsx';\n\ninterface IExampleProps {\n value: string;\n}\n\nconst Base: React.ComponentType<IExampleProps> = (props: IExampleProps): JSXElement | null => {\n return <div data-value={props.value} />;\n};\n\nconst DecoratorA: React.ComponentType<IComponentAsProps<IExampleProps>> = (\n props: IComponentAsProps<IExampleProps>,\n): JSXElement | null => {\n const { defaultRender: DefaultRender, ...exampleProps } = props;\n\n return <div data-a=\"a\">{DefaultRender ? <DefaultRender {...exampleProps} /> : null}</div>;\n};\n\nconst DecoratorB: React.ComponentType<IComponentAsProps<IExampleProps>> = (\n props: IComponentAsProps<IExampleProps>,\n): JSXElement | null => {\n const { defaultRender: DefaultRender, ...exampleProps } = props;\n\n return <div data-b=\"b\">{DefaultRender ? <DefaultRender {...exampleProps} /> : null}</div>;\n};\n\ndescribe('composeComponentAs', () => {\n it('passes Base to DecoratorA', () => {\n const DecoratorAWithBase = composeComponentAs(DecoratorA, Base);\n const component = render(<DecoratorAWithBase value=\"test\" />);\n\n expect(component.container.firstChild).toMatchSnapshot();\n });\n\n it('passes Base to DecoratorB through DecoratorA', () => {\n const DecoratorAAndBWithBase = composeComponentAs(DecoratorA, composeComponentAs(DecoratorB, Base));\n const component = render(<DecoratorAAndBWithBase value=\"test\" />);\n\n expect(component.container.firstChild).toMatchSnapshot();\n });\n\n it('passes Base as defaultRender to DecoratorB through DecoratorA', () => {\n const DecoratorAAroundB = composeComponentAs(DecoratorA, DecoratorB);\n\n const component = render(<DecoratorAAroundB value=\"test\" defaultRender={Base} />);\n\n expect(component.container.firstChild).toMatchSnapshot();\n });\n\n it('renders without defaultRender', () => {\n const DecoratorAAroundB = composeComponentAs(DecoratorA, DecoratorB);\n\n const component = render(<DecoratorAAroundB value=\"test\" />);\n\n expect(component.container.firstChild).toMatchSnapshot();\n });\n\n it('avoids recomposing already-composed components', () => {\n const DecoratorAAroundB = composeComponentAs(DecoratorA, DecoratorB);\n\n expect(composeComponentAs(DecoratorA, DecoratorB)).toBe(DecoratorAAroundB);\n });\n});\n"]}