-
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
9dc48e8
commit 59bbcca
Showing
7 changed files
with
275 additions
and
2 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,41 @@ | ||
/** | ||
* @typedef {import("./WithStacksProps.mjs").WithStacksProps} WithStacksProps | ||
*/ | ||
import React, { useContext } from "react"; | ||
import WithStacksProps from "./WithStacksProps.mjs"; | ||
|
||
const h = React.createElement; | ||
|
||
/** | ||
* @param {React.PropsWithChildren<WithStacksProps>} props | ||
*/ | ||
const WithStacks = (props) => { | ||
return h( | ||
WithStacks.Context.Provider, | ||
{ | ||
value: WithStacksProps(props.left, props.right), | ||
}, | ||
props.children | ||
); | ||
}; | ||
|
||
WithStacks.displayName = "WithStacks"; | ||
|
||
WithStacks.Context = React.createContext( | ||
/** @type {WithStacksProps | null} */ (null) | ||
); | ||
/** | ||
* @type {() => WithStacksProps} | ||
*/ | ||
WithStacks.useStacks = () => { | ||
const ctx = useContext(WithStacks.Context); | ||
if (!ctx) { | ||
throw Error( | ||
"WithStacks.Context is not found." + | ||
"\nPlease, make sure you use WithStacks.Context.Provider in parent component." | ||
); | ||
} | ||
return ctx; | ||
}; | ||
|
||
export default WithStacks; |
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,45 @@ | ||
/** | ||
* @typedef {import("@farjs/blessed").Widgets.BlessedElement} BlessedElement | ||
*/ | ||
import PanelStack from "./PanelStack.mjs"; | ||
|
||
/** | ||
* @typedef {{ | ||
* readonly stack: PanelStack; | ||
* readonly input: BlessedElement; | ||
* }} WithStacksData | ||
*/ | ||
|
||
/** | ||
* @typedef {{ | ||
* readonly left: WithStacksData; | ||
* readonly right: WithStacksData; | ||
* }} WithStacksProps | ||
*/ | ||
|
||
/** | ||
* @param {WithStacksData} left | ||
* @param {WithStacksData} right | ||
* @returns {WithStacksProps} | ||
*/ | ||
function WithStacksProps(left, right) { | ||
return { left, right }; | ||
} | ||
|
||
/** | ||
* @param {WithStacksProps} stacks | ||
* @returns {WithStacksData} | ||
*/ | ||
WithStacksProps.active = (stacks) => { | ||
return stacks.left.stack.isActive ? stacks.left : stacks.right; | ||
}; | ||
|
||
/** | ||
* @param {WithStacksProps} stacks | ||
* @returns {WithStacksData} | ||
*/ | ||
WithStacksProps.nonActive = (stacks) => { | ||
return !stacks.left.stack.isActive ? stacks.left : stacks.right; | ||
}; | ||
|
||
export default WithStacksProps; |
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
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,132 @@ | ||
/** | ||
* @typedef {import("@farjs/blessed").Widgets.BlessedElement} BlessedElement | ||
* @typedef {import("../../src/stack/WithStacksProps.mjs").WithStacksProps} WithStacksProps | ||
*/ | ||
import React from "react"; | ||
import assert from "node:assert/strict"; | ||
import mockFunction from "mock-fn"; | ||
import TestRenderer from "react-test-renderer"; | ||
import { assertComponents, TestErrorBoundary } from "react-assert"; | ||
import PanelStack from "../../src/stack/PanelStack.mjs"; | ||
import WithStacksProps from "../../src/stack/WithStacksProps.mjs"; | ||
import WithStacks from "../../src/stack/WithStacks.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 props = WithStacksProps( | ||
{ | ||
stack: new PanelStack(true, [], mockFunction()), | ||
input: /** @type {BlessedElement} */ ({}), | ||
}, | ||
{ | ||
stack: new PanelStack(false, [], mockFunction()), | ||
input: /** @type {BlessedElement} */ ({}), | ||
} | ||
); | ||
|
||
describe("WithStacks.test.mjs", () => { | ||
it("should fail if no context when useStacks", () => { | ||
//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 = () => { | ||
WithStacks.useStacks(); | ||
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: WithStacks.Context is not found." + | ||
"\nPlease, make sure you use WithStacks.Context.Provider in parent component." | ||
) | ||
); | ||
}); | ||
|
||
it("should render component with context provider", () => { | ||
//given | ||
const [stacksCtx, stacksComp] = getStacksCtxHook(); | ||
|
||
//when | ||
const result = TestRenderer.create( | ||
h( | ||
WithStacks, | ||
props, | ||
h(stacksComp, null), | ||
h(React.Fragment, null, "some other content") | ||
) | ||
).root; | ||
|
||
//then | ||
assert.deepEqual(WithStacks.displayName, "WithStacks"); | ||
assert.deepEqual(stacksCtx.current, props); | ||
assert.deepEqual(result.children.length, 2); | ||
const [resCtxHook, otherContent] = result.children.map( | ||
(_) => /** @type {TestRenderer.ReactTestInstance} */ (_) | ||
); | ||
assert.deepEqual(resCtxHook.type, stacksComp); | ||
assert.deepEqual(otherContent, "some other content"); | ||
}); | ||
|
||
it("should return active stack when WithStacksProps.active()", () => { | ||
//given | ||
const { left, right } = props; | ||
|
||
//when & then | ||
assert.deepEqual(WithStacksProps.active(props), props.left); | ||
assert.deepEqual( | ||
WithStacksProps.active({ left: right, right: left }), | ||
props.left | ||
); | ||
}); | ||
|
||
it("should return non-active stack when WithStacksProps.nonActive()", () => { | ||
//given | ||
const { left, right } = props; | ||
|
||
//when & then | ||
assert.deepEqual(WithStacksProps.nonActive(props), props.right); | ||
assert.deepEqual( | ||
WithStacksProps.nonActive({ left: right, right: left }), | ||
props.right | ||
); | ||
}); | ||
}); | ||
|
||
/** | ||
* @returns {[React.MutableRefObject<WithStacksProps | null>, () => React.ReactElement]} | ||
*/ | ||
function getStacksCtxHook() { | ||
/** @type {React.MutableRefObject<WithStacksProps | null>} */ | ||
const ref = React.createRef(); | ||
const comp = () => { | ||
const ctx = WithStacks.useStacks(); | ||
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,13 @@ | ||
export default WithStacks; | ||
export type WithStacksProps = import("./WithStacksProps.mjs").WithStacksProps; | ||
/** | ||
* @param {React.PropsWithChildren<WithStacksProps>} props | ||
*/ | ||
declare function WithStacks(props: React.PropsWithChildren<WithStacksProps>): React.FunctionComponentElement<React.ProviderProps<import("./WithStacksProps.mjs").WithStacksProps | null>>; | ||
declare namespace WithStacks { | ||
const displayName: string; | ||
const Context: React.Context<import("./WithStacksProps.mjs").WithStacksProps | null>; | ||
function useStacks(): import("./WithStacksProps.mjs").WithStacksProps; | ||
} | ||
import React from "react"; | ||
import WithStacksProps from "./WithStacksProps.mjs"; |
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,41 @@ | ||
export default WithStacksProps; | ||
export type WithStacksData = { | ||
readonly stack: PanelStack; | ||
readonly input: BlessedElement; | ||
}; | ||
export type WithStacksProps = { | ||
readonly left: WithStacksData; | ||
readonly right: WithStacksData; | ||
}; | ||
export type BlessedElement = import("@farjs/blessed").Widgets.BlessedElement; | ||
/** | ||
* @typedef {{ | ||
* readonly stack: PanelStack; | ||
* readonly input: BlessedElement; | ||
* }} WithStacksData | ||
*/ | ||
/** | ||
* @typedef {{ | ||
* readonly left: WithStacksData; | ||
* readonly right: WithStacksData; | ||
* }} WithStacksProps | ||
*/ | ||
/** | ||
* @param {WithStacksData} left | ||
* @param {WithStacksData} right | ||
* @returns {WithStacksProps} | ||
*/ | ||
declare function WithStacksProps(left: WithStacksData, right: WithStacksData): WithStacksProps; | ||
declare namespace WithStacksProps { | ||
/** | ||
* @param {WithStacksProps} stacks | ||
* @returns {WithStacksData} | ||
*/ | ||
function active(stacks: WithStacksProps): WithStacksData; | ||
/** | ||
* @param {WithStacksProps} stacks | ||
* @returns {WithStacksData} | ||
*/ | ||
function nonActive(stacks: WithStacksProps): WithStacksData; | ||
} | ||
import PanelStack from "./PanelStack.mjs"; |