-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c92161c
commit 9dc48e8
Showing
4 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/** | ||
* @typedef {import("@farjs/blessed").Widgets.BlessedElement} BlessedElement | ||
*/ | ||
import React, { useContext } from "react"; | ||
import WithSize from "@farjs/ui/WithSize.mjs"; | ||
import PanelStack from "./PanelStack.mjs"; | ||
|
||
const h = React.createElement; | ||
|
||
/** | ||
* @typedef {{ | ||
* readonly isRight: boolean; | ||
* readonly panelInput: BlessedElement; | ||
* readonly stack: PanelStack; | ||
* readonly width: number; | ||
* readonly height: number; | ||
* }} WithStackProps | ||
*/ | ||
|
||
/** | ||
* @param {WithStackProps} props | ||
*/ | ||
const WithStack = (props) => { | ||
const topComp = props.stack.peek().component; | ||
|
||
return h(WithStack.withSizeComp, { | ||
render: (width, height) => { | ||
return h( | ||
WithStack.Context.Provider, | ||
{ | ||
value: { ...props, width, height }, | ||
}, | ||
h(topComp) | ||
); | ||
}, | ||
}); | ||
}; | ||
|
||
WithStack.displayName = "WithStack"; | ||
WithStack.withSizeComp = WithSize; | ||
|
||
WithStack.Context = React.createContext( | ||
/** @type {WithStackProps | null} */ (null) | ||
); | ||
/** | ||
* @type {() => WithStackProps} | ||
*/ | ||
WithStack.useStack = () => { | ||
const ctx = useContext(WithStack.Context); | ||
if (!ctx) { | ||
throw Error( | ||
"WithStack.Context is not found." + | ||
"\nPlease, make sure you use WithStack.Context.Provider in parent component." | ||
); | ||
} | ||
return ctx; | ||
}; | ||
|
||
export default WithStack; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/** | ||
* @typedef {import("@farjs/blessed").Widgets.BlessedElement} BlessedElement | ||
* @typedef {import("../../src/stack/WithStack.mjs").WithStackProps} WithStackProps | ||
*/ | ||
import React, { useContext } from "react"; | ||
import assert from "node:assert/strict"; | ||
import mockFunction from "mock-fn"; | ||
import TestRenderer from "react-test-renderer"; | ||
import { | ||
assertComponents, | ||
mockComponent, | ||
TestErrorBoundary, | ||
} from "react-assert"; | ||
import WithSize from "@farjs/ui/WithSize.mjs"; | ||
import PanelStackItem from "../../src/stack/PanelStackItem.mjs"; | ||
import PanelStack from "../../src/stack/PanelStack.mjs"; | ||
import WithStack from "../../src/stack/WithStack.mjs"; | ||
|
||
const h = React.createElement; | ||
|
||
const { describe, it } = await (async () => { | ||
// @ts-ignore | ||
const module = process.isBun ? "bun:test" : "node:test"; | ||
// @ts-ignore | ||
return process.isBun // @ts-ignore | ||
? Promise.resolve({ describe: (_, fn) => fn(), it: test }) | ||
: import(module); | ||
})(); | ||
|
||
const OtherComponent = () => { | ||
return null; | ||
}; | ||
|
||
WithStack.withSizeComp = mockComponent(WithSize); | ||
const { withSizeComp } = WithStack; | ||
|
||
describe("WithStack.test.mjs", () => { | ||
it("should fail if no context when useStack", () => { | ||
//given | ||
// suppress intended error | ||
// see: https://github.com/facebook/react/issues/11098#issuecomment-412682721 | ||
const savedConsoleError = console.error; | ||
const consoleErrorMock = mockFunction(); | ||
console.error = consoleErrorMock; | ||
|
||
const Wrapper = () => { | ||
WithStack.useStack(); | ||
return h(React.Fragment); | ||
}; | ||
|
||
//when | ||
const result = TestRenderer.create( | ||
h(TestErrorBoundary, null, h(Wrapper)) | ||
).root; | ||
|
||
//then | ||
console.error = savedConsoleError; | ||
assert.deepEqual(consoleErrorMock.times, 1); | ||
assertComponents( | ||
result.children, | ||
h( | ||
"div", | ||
null, | ||
"Error: WithStack.Context is not found." + | ||
"\nPlease, make sure you use WithStack.Context.Provider in parent component." | ||
) | ||
); | ||
}); | ||
|
||
it("should render top component", () => { | ||
//given | ||
const [stackCtx, stackComp] = getStackCtxHook(); | ||
const top = new PanelStackItem(stackComp); | ||
const other = new PanelStackItem(OtherComponent); | ||
const stack = new PanelStack(false, [top, other], mockFunction()); | ||
const props = { | ||
isRight: true, | ||
panelInput: /** @type {BlessedElement} */ ({}), | ||
stack, | ||
width: 0, | ||
height: 0, | ||
}; | ||
const width = 25; | ||
const height = 15; | ||
|
||
//when | ||
const comp = TestRenderer.create(h(WithStack, props)).root; | ||
const withSizeProps = comp.findByType(withSizeComp).props; | ||
const result = TestRenderer.create( | ||
withSizeProps.render(width, height) | ||
).root; | ||
|
||
//then | ||
assert.deepEqual(WithStack.displayName, "WithStack"); | ||
assert.deepEqual(stackCtx.current, { ...props, width, height }); | ||
assert.deepEqual(result.type, stackComp); | ||
}); | ||
}); | ||
|
||
/** | ||
* @returns {[React.MutableRefObject<WithStackProps | null>, () => React.ReactElement]} | ||
*/ | ||
function getStackCtxHook() { | ||
/** @type {React.MutableRefObject<WithStackProps | null>} */ | ||
const ref = React.createRef(); | ||
const comp = () => { | ||
const ctx = useContext(WithStack.Context); | ||
ref.current = ctx; | ||
return h(React.Fragment, null); | ||
}; | ||
|
||
return [ref, comp]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
export default WithStack; | ||
export type BlessedElement = import("@farjs/blessed").Widgets.BlessedElement; | ||
export type WithStackProps = { | ||
readonly isRight: boolean; | ||
readonly panelInput: BlessedElement; | ||
readonly stack: PanelStack; | ||
readonly width: number; | ||
readonly height: number; | ||
}; | ||
/** | ||
* @typedef {{ | ||
* readonly isRight: boolean; | ||
* readonly panelInput: BlessedElement; | ||
* readonly stack: PanelStack; | ||
* readonly width: number; | ||
* readonly height: number; | ||
* }} WithStackProps | ||
*/ | ||
/** | ||
* @param {WithStackProps} props | ||
*/ | ||
declare function WithStack(props: WithStackProps): React.FunctionComponentElement<import("@farjs/ui/WithSize.mjs").WithSizeProps>; | ||
declare namespace WithStack { | ||
export const displayName: string; | ||
export { WithSize as withSizeComp }; | ||
export const Context: React.Context<WithStackProps | null>; | ||
export function useStack(): WithStackProps; | ||
} | ||
import PanelStack from "./PanelStack.mjs"; | ||
import React from "react"; | ||
import WithSize from "@farjs/ui/WithSize.mjs"; |