├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .husky
└── pre-commit
├── .lintstagedrc
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── core
├── README.md
├── if.d.ts
├── package.json
├── src
│ ├── If.tsx
│ ├── index.tsx
│ └── switch.tsx
├── switch.d.ts
└── tsconfig.json
├── lerna.json
├── package.json
├── renovate.json
├── test
├── If.test.tsx
├── index.test.tsx
└── switch.test.tsx
├── tsconfig.json
└── www
├── .kktrc.ts
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── Example.tsx
├── index.tsx
└── react-app-env.d.ts
└── tsconfig.json
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: jaywcjlove
2 | buy_me_a_coffee: jaywcjlove
3 | custom: ["https://www.paypal.me/kennyiseeyou", "https://jaywcjlove.github.io/#/sponsor"]
4 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Build & Deploy
2 | on:
3 | push:
4 | branches:
5 | - main
6 |
7 | jobs:
8 | build-deploy:
9 | runs-on: ubuntu-latest
10 | permissions:
11 | contents: write
12 | id-token: write
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: actions/setup-node@v4
16 | with:
17 | node-version: 20
18 | registry-url: 'https://registry.npmjs.org'
19 |
20 | - run: npm install
21 | - run: npm run build
22 | - run: npm run doc
23 | - run: npm run coverage
24 | - run: cp -rp ./coverage www/build
25 |
26 | - name: Create Tag
27 | id: create_tag
28 | uses: jaywcjlove/create-tag-action@main
29 | with:
30 | package-path: ./core/package.json
31 |
32 | - name: Generate Contributors Images
33 | uses: jaywcjlove/github-action-contributors@main
34 | with:
35 | filter-author: (renovate\[bot\]|renovate\-bot|dependabot\[bot\])
36 | output: www/build/CONTRIBUTORS.svg
37 | avatarSize: 42
38 |
39 | - name: Create Coverage Badges
40 | uses: jaywcjlove/coverage-badges-cli@main
41 | with:
42 | output: www/build/badges.svg
43 |
44 | - name: Generate Changelog
45 | id: changelog
46 | uses: jaywcjlove/changelog-generator@main
47 | with:
48 | token: ${{ secrets.GITHUB_TOKEN }}
49 | head-ref: ${{steps.create_tag.outputs.version}}
50 | filter-author: (renovate-bot|Renovate Bot)
51 | filter: '[R|r]elease[d]\s+[v|V]\d(\.\d+){0,2}'
52 |
53 | - name: Deploy
54 | uses: peaceiris/actions-gh-pages@v4
55 | with:
56 | github_token: ${{ secrets.GITHUB_TOKEN }}
57 | publish_dir: ./www/build
58 |
59 | - name: Create Release
60 | uses: ncipollo/release-action@v1
61 | if: steps.create_tag.outputs.successful
62 | with:
63 | allowUpdates: true
64 | name: ${{ steps.create_tag.outputs.version }}
65 | tag: ${{ steps.create_tag.outputs.version }}
66 | token: ${{ secrets.GITHUB_TOKEN }}
67 | body: |
68 | [](https://jaywcjlove.github.io/#/sponsor) [](https://uiwjs.github.io/npm-unpkg/#/pkg/@uiw/react-only-when@${{steps.changelog.outputs.version}}/file/README.md) [](https://coveralls.io/github/uiwjs/react-only-when?branch=main) [](https://www.npmjs.com/package/@uiw/react-only-when)
69 |
70 | ```bash
71 | npm i @uiw/react-only-when@${{steps.changelog.outputs.version}}
72 | ```
73 |
74 | ${{ steps.changelog.outputs.compareurl }}
75 | ${{ steps.changelog.outputs.changelog }}
76 |
77 | - run: npm publish --access public --provenance
78 | name: 📦 @uiw/react-only-when publish to NPM
79 | continue-on-error: true
80 | working-directory: core
81 | env:
82 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | cjs
2 | esm
3 | build
4 | coverage
5 | node_modules
6 | npm-debug.log*
7 | package-lock.json
8 |
9 | .eslintcache
10 | .DS_Store
11 | .cache
12 | .vscode
13 |
14 | *.bak
15 | *.tem
16 | *.temp
17 | #.swp
18 | *.*~
19 | ~*.*
20 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | npx --no-install lint-staged
2 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,jsx,tsx,ts,less,md,json}": [
3 | "prettier --write"
4 | ]
5 | }
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.md
2 | **/*.svg
3 | **/*.ejs
4 | **/*.yml
5 | package.json
6 | node_modules
7 | dist
8 | build
9 | lib
10 | cjs
11 | esm
12 | test
13 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 120,
5 | "overrides": [
6 | {
7 | "files": ".prettierrc",
8 | "options": { "parser": "json" }
9 | },
10 | {
11 | "files": "*.{js,jsx}",
12 | "options": { "parser": "babel" }
13 | },
14 | {
15 | "files": "*.{ts,tsx}",
16 | "options": { "parser": "babel-ts" }
17 | },
18 | {
19 | "files": "*.{ts,tsx}",
20 | "options": { "parser": "typescript" }
21 | },
22 | {
23 | "files": "*.{less,css}",
24 | "options": { "parser": "css" }
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 uiw
4 | Copyright (c) sag1v https://github.com/sag1v
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ./core/README.md
--------------------------------------------------------------------------------
/core/README.md:
--------------------------------------------------------------------------------
1 | react-only-when
2 | ===
3 |
4 | [](https://jaywcjlove.github.io/#/sponsor)
5 | [](https://github.com/uiwjs/react-only-when/actions/workflows/ci.yml)
6 | [](https://www.npmjs.com/package/@uiw/react-only-when)
7 | [](https://www.npmjs.com/package/@uiw/react-only-when)
8 | [](https://uiwjs.github.io/react-only-when/coverage/lcov-report/)
9 |
10 | A declarative component for conditional rendering. Copy [`react-only-when`](https://github.com/sag1v/react-only-when), let it support TypeScript.
11 |
12 | ## Quick Start
13 |
14 | ```bash
15 | $ npm install --save @uiw/react-only-when
16 | ```
17 |
18 | ## Usage
19 |
20 | ```jsx
21 | import Only from '@uiw/react-only-when'
22 |
23 |
24 | Here I Am
25 |
26 | ```
27 |
28 | ```jsx
29 | import { If } from '@uiw/react-only-when/if'
30 |
31 |
32 | {props.error}
33 |
34 | ```
35 |
36 | ```jsx
37 | import { Switch, Case, Default } from '@uiw/react-only-when/switch'
38 |
39 |
40 | preschool
41 | = 6}>primary school
42 | you graduated
43 |
44 | ```
45 |
46 | ## \
47 |
48 | React component that renders the children if the `condition` prop is `true`.
49 |
50 | ```jsx
51 | import { If } from '@uiw/react-only-when';
52 | // Or
53 | import { If } from '@uiw/react-only-when/if'
54 |
55 |
56 | (
59 | {props.error}
60 | )}
61 | />
62 |
63 | {props.error}
64 |
65 |
66 | ```
67 |
68 | Or you could just use plain JavaScript:
69 |
70 | ```jsx
71 |
72 | {props.error && (
73 |
{props.error}
74 | )}
75 |
76 | ```
77 |
78 | Only Example
79 |
80 | ```jsx mdx:preview&background=#fff&codePen=true
81 | import React, { useState } from 'react';
82 | import Only from '@uiw/react-only-when';
83 |
84 | export default function App() {
85 | const [show, setShow] = useState(true)
86 | return (
87 |
88 |
89 |
90 | Here I Am
91 |
92 |
93 | )
94 | }
95 | ```
96 |
97 | ## \
98 |
99 | ```jsx
100 | import { Switch, Case, Default } from '@uiw/react-only-when/switch'
101 |
102 |
103 | preschool
104 | = 6}>primary school
105 | you graduated
106 |
107 | ```
108 |
109 | ```jsx mdx:preview&background=#fff&codePen=true
110 | import React, { useState, Fragment } from 'react';
111 | import { Switch, Case, Default } from '@uiw/react-only-when/switch'
112 |
113 | export default function App() {
114 | const [age, setAge] = useState(19)
115 | return (
116 |
117 | setAge(Number(evn.target.value))} /> {age}
118 |
119 | Preschool
120 | = 6 && age < 18}>Primary school
121 | = 18 && age < 60}>Went to college
122 | you graduated
123 |
124 |
125 | );
126 | }
127 | ```
128 |
129 | Defaults to specifying a wrapped HTML Element.
130 |
131 | ```jsx mdx:preview&background=#fff&codePen=true
132 | import React, { useState, Fragment } from 'react';
133 | import { Switch, Case, Default } from '@uiw/react-only-when/switch'
134 |
135 | export default function App() {
136 | const [age, setAge] = useState(19)
137 | return (
138 |
139 | setAge(Number(evn.target.value))} /> {age}
140 |
141 |
142 | Preschool
143 | = 6 && age < 18}>Primary school
144 | = 18 && age < 60}>Went to college
145 | you graduated
146 |
147 |
148 | );
149 | }
150 | ```
151 |
152 | ## `` props
153 |
154 | | prop name | type | default | isRequired | description |
155 | | ----- | ----- | ----- | ----- | ----- |
156 | | children | react element | `null` | `true` | A single child element |
157 | | when | bool | `false` | `true` | When true, children will rendered as is |
158 | | hiddenMode | string | `null` | `false` | Determines how children should be hidden |
159 | | className | string | `w-hidden` | `false` | This is working in combination with `hiddenMode={"css"}` |
160 |
161 | **`hiddenMode` enum**
162 |
163 | | hiddenMode | description |
164 | | ----- | ----- |
165 | | `null` | Will not render the child |
166 | | `display` | Will render the child with `display:none` |
167 | | `visibility` | Will render the child with `visibility:hidden` |
168 | | `css` | Will render the child with a CSS class (you can pass it a custom `className` prop) |
169 |
170 | ## `` Props
171 |
172 | ```tsx
173 | import { ReactElement } from 'react';
174 | import { FC, PropsWithChildren } from 'react';
175 | export interface IfProps {
176 | readonly condition?: boolean;
177 | readonly render?: () => ReactElement;
178 | }
179 | export declare const If: FC>;
180 | ```
181 |
182 | ## `` `` `` Props
183 |
184 | ```tsx
185 | import type { FC, PropsWithChildren } from 'react';
186 | export const Switch: FC>;
187 | type TagType = React.ElementType | keyof JSX.IntrinsicElements;
188 | interface CaseElementProps {
189 | as?: T;
190 | readonly condition?: boolean;
191 | }
192 | export type CaseProps = CaseElementProps & React.ComponentPropsWithoutRef;
193 | export const Case: (props: CaseProps) => any;
194 | export const Default: (props: Omit, 'condition'>) => import("react/jsx-runtime").JSX.Element;
195 | ```
196 |
197 | ## Development
198 |
199 | Runs the project in development mode.
200 |
201 | ```bash
202 | # Step 1, run first, listen to the component compile and output the .js file
203 | # listen for compilation output type .d.ts file
204 | npm run watch
205 | # Step 2, development mode, listen to compile preview website instance
206 | npm run start
207 | ```
208 |
209 | **production**
210 |
211 | Builds the app for production to the build folder.
212 |
213 | ```bash
214 | npm run build
215 | ```
216 |
217 | The build is minified and the filenames include the hashes.
218 | Your app is ready to be deployed!
219 |
220 | ## Contributors
221 |
222 | As always, thanks to our amazing contributors!
223 |
224 |
225 |
226 |
227 |
228 | Made with [contributors](https://github.com/jaywcjlove/github-action-contributors).
229 |
230 |
231 | ## License
232 |
233 | MIT © [`sag1v`](https://github.com/sag1v) & [`uiwjs`](https://github.com/uiwjs)
--------------------------------------------------------------------------------
/core/if.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@uiw/react-only-when/if' {
2 | import { ReactElement } from 'react';
3 | import { FC, PropsWithChildren } from 'react';
4 | export interface IfProps {
5 | readonly condition?: boolean;
6 | readonly render?: () => ReactElement;
7 | }
8 | export const If: FC>;
9 | }
10 |
--------------------------------------------------------------------------------
/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uiw/react-only-when",
3 | "version": "3.0.2",
4 | "description": "A declarative component for conditional rendering.",
5 | "main": "cjs/index.js",
6 | "module": "esm/index.js",
7 | "homepage": "https://uiwjs.github.io/react-only-when",
8 | "funding": "https://jaywcjlove.github.io/#/sponsor",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/uiwjs/react-only-when.git"
12 | },
13 | "exports": {
14 | ".": {
15 | "import": "./esm/index.js",
16 | "require": "./cjs/index.js",
17 | "types": "./esm/index.d.ts"
18 | },
19 | "./if": {
20 | "import": "./esm/If.js",
21 | "require": "./cjs/If.js",
22 | "types": "./esm/If.d.ts"
23 | },
24 | "./switch": {
25 | "import": "./esm/switch.js",
26 | "require": "./cjs/switch.js",
27 | "types": "./esm/switch.d.ts"
28 | }
29 | },
30 | "author": "Kenny Wang",
31 | "license": "MIT",
32 | "peerDependencies": {
33 | "@babel/runtime": ">=7.10.0",
34 | "react": ">=18.0.0",
35 | "react-dom": ">=18.0.0"
36 | },
37 | "files": [
38 | "src",
39 | "cjs",
40 | "esm"
41 | ],
42 | "keywords": [
43 | "component",
44 | "only-when",
45 | "react",
46 | "react-component"
47 | ],
48 | "dependencies": {
49 | "@babel/runtime": "^7.22.6"
50 | },
51 | "devDependencies": {
52 | "@testing-library/react": "^14.0.0",
53 | "@types/react-test-renderer": "^18.0.0",
54 | "react": "^18.2.0",
55 | "react-dom": "^18.2.0",
56 | "react-test-renderer": "^18.2.0"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/If.tsx:
--------------------------------------------------------------------------------
1 | import type { ReactElement } from 'react';
2 | import type { FC, PropsWithChildren } from 'react';
3 |
4 | export interface IfProps {
5 | readonly condition?: boolean;
6 | readonly render?: () => ReactElement;
7 | }
8 |
9 | export const If: FC> = (props) =>
10 | props.condition ? (props.render ? props.render() : (props.children as ReactElement)) : null;
11 |
--------------------------------------------------------------------------------
/core/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { type PropsWithChildren } from 'react';
2 | import { If } from './If';
3 |
4 | export * from './If';
5 |
6 | export interface OnlyWhenProps {
7 | /** A single child element */
8 | children: React.ReactElement;
9 | /** When true, children will rendered as is */
10 | when: boolean;
11 | /** This is working in combination with hiddenMode={"css"} */
12 | className?: string;
13 | /**
14 | * Determines how "react-only-when" should hide the child element
15 | * "null": Will not render the child
16 | * "display": Will render the child with display:none
17 | * "visibility": Will render the child with visibility:hidden
18 | * "css": Will render the child with a CSS class (you can pass it a custom className prop)
19 | */
20 | hiddenMode?: 'null' | 'display' | 'visibility' | 'css';
21 | }
22 |
23 | export default function OnlyWhen(props: PropsWithChildren) {
24 | const { children, when, hiddenMode = 'null', className = 'w-hidden' } = props;
25 | const singleChild = React.Children.only(children);
26 | const { style, ...restOfChildProps } = singleChild.props;
27 | const extendedProps = { ...restOfChildProps };
28 |
29 | const keepNode = hiddenMode && hiddenMode !== 'null';
30 | if (keepNode) {
31 | if (hiddenMode === 'css') {
32 | extendedProps.className = `${extendedProps.className || ''} ${className || ''}`.trim();
33 | } else {
34 | extendedProps.style = {
35 | ...style,
36 | ...(hiddenMode === 'display' && { display: 'none' }),
37 | ...(hiddenMode === 'visibility' && { visibility: 'hidden' }),
38 | };
39 | }
40 | }
41 | const cloned = React.cloneElement(singleChild, extendedProps);
42 | const toHide = {cloned};
43 |
44 | return when ? singleChild : toHide;
45 | }
46 |
--------------------------------------------------------------------------------
/core/src/switch.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, PropsWithChildren } from 'react';
2 |
3 | type Child = typeof Case | typeof Default;
4 | export const Switch: FC> = ({ children }) => {
5 | let matchChild: Child | null = null;
6 | let defaultCase: typeof Default | null = null;
7 |
8 | const childs = Array.isArray(children) ? children : [children];
9 | childs.some((child) => {
10 | if (!defaultCase && child && child.type === Default) {
11 | defaultCase = child;
12 | }
13 | if (child && child.type === Case) {
14 | const { condition } = child.props;
15 | const conditionIsTrue = Boolean(condition);
16 | if (conditionIsTrue) {
17 | matchChild = child;
18 | return true;
19 | }
20 | }
21 | return false;
22 | });
23 | return matchChild ?? defaultCase ?? null;
24 | };
25 |
26 | type TagType = React.ElementType | keyof JSX.IntrinsicElements;
27 | interface CaseElementProps {
28 | as?: T;
29 | readonly condition?: boolean;
30 | }
31 |
32 | export type CaseProps = CaseElementProps & React.ComponentPropsWithoutRef;
33 |
34 | export const Case = (props: CaseProps) => {
35 | const { children, condition, as: Comp, ...reset } = props;
36 | const Elm = Comp as TagType;
37 | return Elm ? {children} : children;
38 | };
39 |
40 | export const Default = (props: Omit, 'condition'>) => (
41 | )} />
42 | );
43 |
--------------------------------------------------------------------------------
/core/switch.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@uiw/react-only-when/switch' {
2 | import type { FC, PropsWithChildren } from 'react';
3 | export const Switch: FC>;
4 | type TagType = React.ElementType | keyof JSX.IntrinsicElements;
5 | interface CaseElementProps {
6 | as?: T;
7 | readonly condition?: boolean;
8 | }
9 | export type CaseProps = CaseElementProps & React.ComponentPropsWithoutRef;
10 | export const Case: (props: CaseProps) => any;
11 | export const Default: (
12 | props: Omit, 'condition'>,
13 | ) => import('react/jsx-runtime').JSX.Element;
14 | }
15 |
--------------------------------------------------------------------------------
/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig",
3 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts"],
4 | "compilerOptions": {
5 | "outDir": "../cjs",
6 | "baseUrl": ".",
7 | "noEmit": false,
8 | "paths": {
9 | "*": ["*", "types/*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.2",
3 | "packages": ["core", "www"]
4 | }
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "lerna exec --scope website -- npm run start",
5 | "doc": "lerna exec --scope website -- npm run build",
6 | "⬇️⬇️⬇️⬇️⬇️ package ⬇️⬇️⬇️⬇️⬇️": "▼▼▼▼▼ package ▼▼▼▼▼",
7 | "watch": "lerna exec --scope @uiw/react-only-when -- tsbb watch \"src/*.{ts,tsx}\" --use-babel --cjs cjs",
8 | "build": "lerna exec --scope @uiw/react-only-when -- tsbb build \"src/*.{ts,tsx}\" --use-babel --cjs cjs",
9 | "⬆️⬆️⬆️⬆️⬆️ package ⬆️⬆️⬆️⬆️⬆️": "▲▲▲▲▲ package ▲▲▲▲▲",
10 | "type-check": "tsc --noEmit",
11 | "test": "tsbb test",
12 | "coverage": "tsbb test --coverage --bail",
13 | "prepare": "husky",
14 | "publish": "lerna publish from-package --yes --no-verify-access",
15 | "version": "lerna version --exact --force-publish --no-push --no-git-tag-version",
16 | "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
17 | "remove": "npm run clean && lerna exec \"rm -rf package-lock.json\" --scope @uiw/react-only-when --scope website",
18 | "clean": "lerna clean --yes"
19 | },
20 | "license": "MIT",
21 | "workspaces": [
22 | "core",
23 | "www"
24 | ],
25 | "engines": {
26 | "node": ">=16.0.0"
27 | },
28 | "jest": {
29 | "collectCoverageFrom": [
30 | "/core/src/*.{tsx,ts}"
31 | ],
32 | "coverageReporters": [
33 | "lcov",
34 | "json-summary"
35 | ]
36 | },
37 | "overrides": {
38 | "typescript": "^5.1.3"
39 | },
40 | "devDependencies": {
41 | "husky": "^9.0.0",
42 | "lint-staged": "^15.0.0",
43 | "lerna": "^8.0.0",
44 | "prettier": "^3.0.0",
45 | "tsbb": "^4.5.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["config:base"],
3 | "packageRules": [
4 | {
5 | "matchPackagePatterns": ["*"],
6 | "rangeStrategy": "replace"
7 | }
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/test/If.test.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable jest/no-conditional-expect */
2 | import TestRenderer from 'react-test-renderer';
3 | import { If } from '../core/src/If';
4 |
5 | describe('', () => {
6 | it('Not rendering children', () => {
7 | const component = TestRenderer.create(
8 |
9 |
10 | ,
11 | );
12 | let only = component.toJSON();
13 | expect(only).toBeNull();
14 | });
15 |
16 | it('rendering children', () => {
17 | const component = TestRenderer.create(
18 |
19 |
20 | ,
21 | );
22 | let only = component.toJSON();
23 |
24 | if (only && !Array.isArray(only)) {
25 | expect(only.type).toEqual('span');
26 | expect(only.props.id).toEqual('child');
27 | }
28 | });
29 |
30 | it('render props', () => {
31 | const component = TestRenderer.create( } />);
32 | let only = component.toJSON();
33 |
34 | if (only && !Array.isArray(only)) {
35 | expect(only.type).toEqual('span');
36 | expect(only.props.id).toEqual('child');
37 | }
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/test/index.test.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable jest/no-conditional-expect */
2 | import TestRenderer from 'react-test-renderer';
3 | import Only from '../core/src';
4 |
5 | describe('', () => {
6 | it('Not rendering children', () => {
7 | const component = TestRenderer.create(
8 |
9 |
10 | ,
11 | );
12 |
13 | let only = component.toJSON();
14 | expect(only).toBeNull();
15 | });
16 |
17 | it('Not touching the style or className', () => {
18 | const classNameToTest = 'test-className';
19 | const component = TestRenderer.create(
20 |
21 |
22 | ,
23 | );
24 |
25 | let only = component.toJSON();
26 | if (only && !Array.isArray(only)) {
27 | expect(only.type).toEqual('span');
28 | expect(only.props.id).toEqual('child');
29 | expect(only.props.children).toBeUndefined();
30 | expect(only.props.className).toEqual(classNameToTest);
31 | expect(only.props.style).toEqual({ color: 'green' });
32 | }
33 | });
34 |
35 | it('Adding style visibility (without deleting other styles', () => {
36 | const component = TestRenderer.create(
37 |
38 |
39 | ,
40 | );
41 |
42 | let only = component.toJSON();
43 | if (only && !Array.isArray(only)) {
44 | expect(only.type).toEqual('span');
45 | expect(only.props.id).toEqual('child');
46 | expect(only.props.children).toBeUndefined();
47 | expect(only.props.style).toEqual({ color: 'green', visibility: 'hidden' });
48 | }
49 | });
50 |
51 | it('Adding style display (without deleting other styles)', () => {
52 | const component = TestRenderer.create(
53 |
54 |
55 | ,
56 | );
57 |
58 | let only = component.toJSON();
59 | if (only && !Array.isArray(only)) {
60 | expect(only.type).toEqual('span');
61 | expect(only.props.id).toEqual('child');
62 | expect(only.props.children).toBeUndefined();
63 | expect(only.props.style).toEqual({ color: 'green', display: 'none' });
64 | }
65 | });
66 |
67 | it('Joining className (default class)', () => {
68 | const testClassName = 'test-className';
69 | const component = TestRenderer.create(
70 |
71 |
72 | ,
73 | );
74 |
75 | let only = component.toJSON();
76 | if (only && !Array.isArray(only)) {
77 | expect(only.type).toEqual('span');
78 | expect(only.props.id).toEqual('child');
79 | expect(only.props.children).toBeUndefined();
80 | expect(only.props.className).toEqual('test-className w-hidden');
81 | expect(only.props.style).toEqual({ color: 'green' });
82 | }
83 | });
84 |
85 | it('Joining className (as prop)', () => {
86 | const testClassName = 'test-className';
87 | const component = TestRenderer.create(
88 |
89 |
90 | ,
91 | );
92 |
93 | let only = component.toJSON();
94 | if (only && !Array.isArray(only)) {
95 | expect(only.type).toEqual('span');
96 | expect(only.props.id).toEqual('child');
97 | expect(only.props.children).toBeUndefined();
98 | expect(only.props.className).toEqual('test-className www');
99 | expect(only.props.style).toEqual({ color: 'green' });
100 | }
101 | });
102 |
103 | it('Joining className default value', () => {
104 | const component = TestRenderer.create(
105 |
106 |
107 | ,
108 | );
109 |
110 | let only = component.toJSON();
111 | if (only && !Array.isArray(only)) {
112 | expect(only.type).toEqual('span');
113 | expect(only.props.id).toEqual('child');
114 | expect(only.props.children).toBeUndefined();
115 | expect(only.props.className).toEqual('w-hidden');
116 | expect(only.props.style).toEqual({ color: 'green' });
117 | }
118 | });
119 | });
120 |
--------------------------------------------------------------------------------
/test/switch.test.tsx:
--------------------------------------------------------------------------------
1 | import renderer from 'react-test-renderer';
2 | import { render, screen } from '@testing-library/react';
3 | import { Switch, Case, Default } from '../core/src/switch';
4 |
5 | it('', () => {
6 | const component = renderer.create(
7 |
8 | );
9 | const only = component.toJSON();
10 | expect(only).toBeNull();
11 | });
12 |
13 | it('', () => {
14 | const { container } = render(
15 |
16 | you graduated
17 |
18 | );
19 | expect(container.innerHTML).toEqual('you graduated');
20 | });
21 |
22 | it('', () => {
23 | const { container } = render(
24 |
25 | preschool
26 | you graduated
27 |
28 | );
29 | expect(container.innerHTML).toEqual('preschool');
30 | });
31 |
32 | it(' 1', () => {
33 | const { container } = render(
34 |
35 | preschool
36 | primary school
37 | you graduated
38 |
39 | );
40 | expect(container.innerHTML).toEqual('preschool');
41 | });
42 |
43 | it(' 2', () => {
44 | const { container } = render(
45 |
46 | preschool
47 | primary school
48 | you graduated
49 |
50 | );
51 | expect(container.innerHTML).toEqual('you graduated');
52 | });
53 |
54 |
55 | it('', () => {
56 | render(
57 |
58 | preschool
59 |
60 | );
61 | const span = screen.getByTestId('span');
62 | expect(span.tagName).toEqual('SPAN');
63 | expect(span.innerHTML).toEqual('preschool');
64 | });
65 |
66 |
67 | it('', () => {
68 | render(
69 |
70 | you graduated
71 |
72 | );
73 | const elm = screen.getByTestId('elm');
74 | expect(elm.tagName).toEqual('P');
75 | expect(elm.innerHTML).toEqual('you graduated');
76 | expect(elm.title).toEqual('test case');
77 | });
78 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "declaration": true,
16 | "baseUrl": ".",
17 | "jsx": "react-jsx",
18 | "noFallthroughCasesInSwitch": true,
19 | "noEmit": true
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/www/.kktrc.ts:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 | import { LoaderConfOptions, WebpackConfiguration } from 'kkt';
3 | import rawModules from '@kkt/raw-modules';
4 | import { disableScopePlugin } from '@kkt/scope-plugin-options';
5 | import { mdCodeModulesLoader } from 'markdown-react-code-preview-loader';
6 | import pkg from './package.json';
7 |
8 | export default (conf: WebpackConfiguration, env: 'production' | 'development', options: LoaderConfOptions) => {
9 | conf = rawModules(conf, env, { ...options });
10 | conf = mdCodeModulesLoader(conf);
11 | conf = disableScopePlugin(conf);
12 | // Get the project version.
13 | conf.plugins!.push(
14 | new webpack.DefinePlugin({
15 | VERSION: JSON.stringify(pkg.version),
16 | }),
17 | );
18 | conf.module!.exprContextCritical = false;
19 | conf.ignoreWarnings = [
20 | {
21 | module: /node_modules[\\/]parse5[\\/]/,
22 | },
23 | ];
24 | if (env === 'production') {
25 | conf.output = { ...conf.output, publicPath: './' };
26 | conf.optimization = {
27 | ...conf.optimization,
28 | splitChunks: {
29 | automaticNameDelimiter: '.',
30 | maxSize: 500000,
31 | minSize: 100000,
32 | cacheGroups: {
33 | reactvendor: {
34 | test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
35 | name: 'react-vendor',
36 | reuseExistingChunk: true,
37 | chunks: 'all',
38 | priority: -10,
39 | },
40 | refractor: {
41 | test: /[\\/]node_modules[\\/](refractor)[\\/]/,
42 | name: 'refractor-prismjs-vendor',
43 | chunks: 'all',
44 | },
45 | },
46 | },
47 | };
48 | }
49 | return conf;
50 | };
51 |
--------------------------------------------------------------------------------
/www/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "website",
3 | "version": "3.0.2",
4 | "preview": true,
5 | "scripts": {
6 | "build": "kkt build",
7 | "start": "kkt start",
8 | "map": "source-map-explorer build/static/js/*.js --html build/website-result.html"
9 | },
10 | "dependencies": {
11 | "@uiw/react-markdown-preview-example": "^2.1.4",
12 | "@uiw/react-only-when": "3.0.2",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
18 | "@kkt/raw-modules": "^7.5.1",
19 | "@kkt/scope-plugin-options": "^7.5.1",
20 | "@types/react": "^18.0.31",
21 | "@types/react-dom": "^18.0.11",
22 | "kkt": "^7.5.1",
23 | "markdown-react-code-preview-loader": "^2.1.2",
24 | "source-map-explorer": "^2.5.3"
25 | },
26 | "eslintConfig": {
27 | "extends": [
28 | "react-app",
29 | "react-app/jest"
30 | ]
31 | },
32 | "browserslist": {
33 | "production": [
34 | ">0.2%",
35 | "not dead",
36 | "not op_mini all"
37 | ],
38 | "development": [
39 | "last 1 chrome version",
40 | "last 1 firefox version",
41 | "last 1 safari version"
42 | ]
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/www/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uiwjs/react-only-when/e6b9d56992958f962ac995410345d7ae4910478c/www/public/favicon.ico
--------------------------------------------------------------------------------
/www/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
19 | React App - A declarative component for conditional rendering.
20 |
21 |
22 |
23 |
26 |
27 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/www/src/Example.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import Only, { OnlyWhenProps } from '@uiw/react-only-when';
3 |
4 | type CheckboxProps = {
5 | hiddenMode?: OnlyWhenProps['hiddenMode'];
6 | value?: OnlyWhenProps['hiddenMode'];
7 | onChange?: (evn: React.ChangeEvent) => void;
8 | };
9 |
10 | function Checkbox(props: CheckboxProps) {
11 | const { hiddenMode, value, onChange } = props;
12 | return (
13 |
17 | );
18 | }
19 |
20 | const App: React.FC = () => {
21 | const [when, setWhen] = useState(true);
22 | const [hiddenMode, setHiddenMode] = useState('null');
23 | return (
24 |
25 |
28 |
29 | setHiddenMode('null')} />
30 | setHiddenMode('display')} />
31 | setHiddenMode('visibility')} />
32 | setHiddenMode('css')} />
33 |
34 |
35 | Here I Am
36 |
37 |
38 | );
39 | };
40 |
41 | export default App;
42 |
--------------------------------------------------------------------------------
/www/src/index.tsx:
--------------------------------------------------------------------------------
1 | import { createRoot } from 'react-dom/client';
2 | import MarkdownPreviewExample from '@uiw/react-markdown-preview-example';
3 | import data from '../../core/README.md';
4 | import pkg from '../../core/package.json';
5 | import OnlyWhenExample from './Example';
6 |
7 | const Github = MarkdownPreviewExample.Github;
8 | const Example = MarkdownPreviewExample.Example;
9 |
10 | const container = document.getElementById('root');
11 | const root = createRoot(container!);
12 | root.render(
13 |
21 |
22 |
23 |
24 |
25 | ,
26 | );
27 |
--------------------------------------------------------------------------------
/www/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare var VERSION: string;
4 |
5 | declare module '*.md' {
6 | import { CodeBlockData } from 'markdown-react-code-preview-loader';
7 | const src: CodeBlockData;
8 | export default src;
9 | }
10 |
--------------------------------------------------------------------------------
/www/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig",
3 | "include": ["src/*", ".kktrc.ts"],
4 | "compilerOptions": {
5 | "noEmit": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------