Rename post folder name

This commit is contained in:
DefectingCat
2022-12-16 08:53:21 +08:00
parent d899e211a5
commit e5466c43da
32 changed files with 18 additions and 18 deletions

View File

@ -0,0 +1,302 @@
export const multi = `import { useSyncExternalStore } from 'react';
export type SetState<S> = (stateOrFn: S | ((state: S) => S)) => void;
export type GetSnapshot<S> = () => S;
export type Subscribe = (listener: () => void) => () => void;
export type CreateStore = <T extends Record<string, unknown> | unknown[]>(
initialState: T
) => {
getSnapshot: GetSnapshot<T>;
setState: SetState<T>;
subscribe: Subscribe;
};
export const createStore: CreateStore = <
T extends Record<string, unknown> | unknown[]
>(
initialState: T
) => {
let state = initialState;
const listeners = new Set<() => void>();
const getSnapshot = () => state;
const setState: SetState<T> = (stateOrFn) => {
state = typeof stateOrFn === 'function' ? stateOrFn(state) : stateOrFn;
listeners.forEach((listener) => listener());
};
const subscribe = (listener: () => void) => {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
};
return {
getSnapshot,
setState,
subscribe,
};
};
export type Todo = {
id: number;
content: string;
}[];
const initialTodo: Todo = [
{ id: 0, content: 'React' },
{ id: 1, content: 'Vue' },
];
const todoStore = createStore(initialTodo);
export const useTodoStore = (): [Todo, SetState<Todo>] => [
useSyncExternalStore(todoStore.subscribe, todoStore.getSnapshot),
todoStore.setState,
];
type Count = {
count: number;
info: string;
};
const initialCount: Count = {
count: 0,
info: 'Hello',
};
const countStore = createStore(initialCount);
export const useCountStore = (): [Count, SetState<Count>] => [
useSyncExternalStore(countStore.subscribe, countStore.getSnapshot),
countStore.setState,
];`;
export const miniRedux = `import { useSyncExternalStore } from 'react';
export type RUAState = Record<string, unknown> | unknown[];
export type RUAAction<P = unknown, T extends string = string> = {
payload: P;
type: T;
};
export type RUAReducer<S extends RUAState, A extends RUAAction> = (
state: S,
action: A
) => S;
export type RUADispatch<A extends RUAAction> = (action: A) => void;
export type GetSnapshot<S> = () => S;
export type Subscribe = (listener: () => void) => () => void;
export const createStore = <S extends RUAState, A extends RUAAction>(
reducer: RUAReducer<S, A>,
initialState: S
) => {
let state = initialState;
const listeners = new Set<() => void>();
const getSnapshot = () => state;
const dispatch: RUADispatch<A> = (action) => {
state = reducer(state, action);
listeners.forEach((listener) => listener());
};
const subscribe = (listener: () => void) => {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
};
return {
subscribe,
getSnapshot,
dispatch,
};
};
export type Todo = {
id: number;
content: string;
}[];
const initialTodo: Todo = [
{ id: 0, content: 'React' },
{ id: 1, content: 'Vue' },
];
export type TodoAction = RUAAction<number | string, 'add' | 'delete'>;
const reducer: RUAReducer<Todo, TodoAction> = (state, action) => {
switch (action.type) {
case 'add': {
if (action.payload == null) throw new Error('Add todo without payload!');
return [
...state,
{
id: state[state.length - 1].id + 1,
content: action.payload.toString(),
},
];
}
case 'delete': {
if (action.payload == null)
throw new Error('Delete todo without payload!');
return state.filter((todo) => todo.id !== action.payload);
}
default:
throw new Error('Dispatch a reducer without action!');
}
};
const todoStore = createStore(reducer, initialTodo);
export const useTodoStore = (): [Todo, RUADispatch<TodoAction>] => [
useSyncExternalStore(todoStore.subscribe, todoStore.getSnapshot),
todoStore.dispatch,
];`;
export const MultiStore = `import Button from './Button';
import Input from './Input';
import { useState } from 'react';
import { useCountStore, useTodoStore } from './multi';
const Todo = () => {
const [todos, setTodo] = useTodoStore();
const [value, setValue] = useState('');
const handleAdd = () => {
if (!value) return;
setTodo((d) => [...d, { id: d[d.length - 1].id + 1, content: value }]);
setValue('');
};
return (
<>
<div>
<ul>
{todos.map((todo) => (
<div key={todo.id}
style={{
display: 'flex',
alignItems: 'center',
}}
className="flex items-center mb-2"
>
<li className="mr-2">{todo.content}</li>
<Button
onClick={() =>
setTodo((d) => d.filter((item) => item.id !== todo.id))
}
>
Delete
</Button>
</div>
))}
</ul>
<div>
<Input
type="text"
className="mr-1"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<Button onClick={handleAdd}>Add</Button>
</div>
</div>
</>
);
};
const Count = () => {
const [{ count, info }, setState] = useCountStore();
return (
<>
<div>
<div>
Count: <span>{count}</span>
</div>
<div>
Info: <span>{info}</span>
</div>
<div>
<Button
onClick={() => setState((d) => ({ ...d, count: d.count + 1 }))}
>
Add
</Button>
</div>
<div>
<Input
type="text"
onChange={(e) => setState((d) => ({ ...d, info: e.target.value }))}
value={info}
/>
</div>
</div>
</>
);
};
const MultiStore = () => {
return (
<>
<div className="p-4">
<Todo />
<hr className="my-4" />
<Count />
</div>
</>
);
};
export default MultiStore;`;
export const Reducer = `import Button from './Button';
import Input from './Input';
import { useState } from 'react';
import { useTodoStore } from './store.ts';
const Reducer = () => {
const [todos, dispatch] = useTodoStore();
const [value, setValue] = useState('');
const handleAdd = () => {
if (!value) return;
dispatch({
type: 'add',
payload: value,
});
setValue('');
};
return (
<>
<div className="p-4">
<div>
<ul>
{todos.map((todo) => (
<div key={todo.id}
style={{
display: 'flex',
alignItems: 'center',
}}
className="flex items-center mb-2"
>
<li className="mr-2">{todo.content}</li>
<Button
onClick={() => dispatch({ type: 'delete', payload: todo.id })}
>
Delete
</Button>
</div>
))}
</ul>
<div>
<Input
type="text"
className="mr-1"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<Button onClick={handleAdd}>Add</Button>
</div>
</div>
</div>
</>
);
};
export default Reducer;`;

View File

@ -0,0 +1,90 @@
export const genericApp = `import "./styles.css";
import Child from "./Child";
const testData = {
name: "xfy",
age: 18
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div>
<Child data={testData} name="name" />
</div>
</div>
);
}`;
export const genericChild = `import { useState } from "react";
type Props<T extends Record<string, unknown>> = {
name: keyof T;
data: T;
};
const Child = <T extends Record<string, unknown>>({ name, data }: Props<T>) => {
const [showName, setShowName] = useState<T[keyof T]>();
const valid = () => {
console.log(data[name]);
setShowName(data[name]);
};
return (
<>
<div>{name}</div>
<button onClick={valid}>Show {name}</button>
<div>{JSON.stringify(showName)}</div>
</>
);
};
export default Child;`;
export const hookApp = `import { useForm } from 'react-hook-form';
type Pet = 'Cat' | 'Dog';
type FormData = {
firstName: string;
lastName: string;
favorite: Pet;
};
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>();
const onSubmit = handleSubmit((data) => console.log(data));
return (
<div>
<form onSubmit={onSubmit}>
<div>
<label htmlFor="firstname">First name:</label>
<input type="text" id="firstname" {...register('firstName')} />
</div>
<div>
<label htmlFor="lastname">Last name:</label>
<input type="text" id="lastname" {...register('lastName')} />
</div>
<div>
<label htmlFor="favorite">Favorite pet:</label>
<select id="favorite" {...register('favorite')}>
<option value="cat">Cat</option>
<option value="dog">Dog</option>
</select>
</div>
<button>Submit</button>
</form>
</div>
);
}`;

View File

@ -0,0 +1,3 @@
export const hello = `export default function App() {
return <h1>Hello world</h1>
}`;

View File

@ -0,0 +1,116 @@
export const firstScene = `import { useEffect, useRef } from 'react';
import * as THREE from 'three';
export default function App() {
const ref = useRef(null);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
useEffect(() => {
const renderer = new THREE.WebGLRenderer({
canvas: ref.current,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
const render = (time) => {
renderer.render(scene, camera);
requestAnimationFrame(render);
};
requestAnimationFrame(render);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render(0);
}
window.addEventListener('resize', onWindowResize);
return () => {
window.removeEventListener('resize', onWindowResize);
};
}, []);
return (
<>
<canvas ref={ref}></canvas>
</>
)
}`;
export const loadBackground = `import { useEffect, useRef } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
const manager = new THREE.LoadingManager();
manager.onProgress = (item, loaded, total) => {
console.log(loaded, total);
};
export default function App() {
const ref = useRef(null);
useEffect(() => {
const scene = new THREE.Scene();
const sky = new THREE.CubeTextureLoader(manager).load([
"https://raw.githubusercontent.com/DefectingCat/three-playground/master/src/assets/images/corona/corona_ft.png",
"https://raw.githubusercontent.com/DefectingCat/three-playground/master/src/assets/images/corona/corona_bk.png",
"https://raw.githubusercontent.com/DefectingCat/three-playground/master/src/assets/images/corona/corona_up.png",
"https://raw.githubusercontent.com/DefectingCat/three-playground/master/src/assets/images/corona/corona_dn.png",
"https://raw.githubusercontent.com/DefectingCat/three-playground/master/src/assets/images/corona/corona_rt.png",
"https://raw.githubusercontent.com/DefectingCat/three-playground/master/src/assets/images/corona/corona_lf.png"
]);
scene.background = sky;
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 1, 0);
camera.up.set(0, 0, 1);
scene.add(camera);
const renderer = new THREE.WebGLRenderer({
canvas: ref.current
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
const controls = new OrbitControls(camera, ref.current);
controls.enablePan = false;
controls.target.set(0, 0, 0);
controls.update();
const render = (time) => {
renderer.render(scene, camera);
requestAnimationFrame(render);
};
requestAnimationFrame(render);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render(0);
}
window.addEventListener("resize", onWindowResize);
return () => {
window.removeEventListener("resize", onWindowResize);
};
}, []);
return (
<>
<canvas ref={ref}></canvas>
</>
);
}
`;
export const resetStyles = `* {
padding: 0;
margin: 0;
}`;

208
content/sandpack/index.ts Normal file
View File

@ -0,0 +1,208 @@
export const Button = `type ButtonProps = {} & React.DetailedHTMLProps<
React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>;
const Button = ({ ...rest }: ButtonProps) => {
const { children, className, ...props } = rest;
return (
<>
<button
className={\`rua-button \${className}\`}
{...props}
>
{children}
</button>
<style>
{\`.rua-button {
-webkit-text-size-adjust: 100%;
tab-size: 4;
box-sizing: border-box;
border-style: solid;
border-color: #e5e7eb;
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
font-family: inherit;
font-size: 100%;
font-weight: inherit;
line-height: inherit;
color: inherit;
margin: 0;
text-transform: none;
-webkit-appearance: button;
background-color: transparent;
background-image: none;
cursor: pointer;
margin-right: 1rem;
border-radius: 0.375rem;
border-width: 1px;
padding-left: 1.25rem;
padding-right: 1.25rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.rua-button:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
\`}
</style>
</>
);
};
export default Button;`;
export const Input = `type InputProps = {} & React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>;
const Input = ({ ...rest }: InputProps) => {
const { className, ...props } = rest;
return (
<>
<input
className={\`rua-input \${className}\`}
{...props}
/>
<style>{\`
.rua-input {
-webkit-text-size-adjust: 100%;
tab-size: 4;
box-sizing: border-box;
border-style: solid;
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
font-family: inherit;
font-size: 100%;
font-weight: inherit;
line-height: inherit;
margin: 0;
margin-top: 0.5rem;
border-radius: 0.375rem;
border-width: 1px;
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity));
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.rua-input:focus {
--tw-border-opacity: 1;
border-color: rgb(96 165 250 / var(--tw-border-opacity));
outline: 2px solid transparent;
outline-offset: 2px;
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
--tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity));
--tw-ring-opacity: 0.8;
}\`}
</style>
</>
);
};
export default Input;`;

View File

@ -0,0 +1,258 @@
export const useTransition = `import Button from './Button';
import { useState, useTransition } from 'react';
const UseTransition = () => {
const [value, setValue] = useState(0);
const [value2, setValue2] = useState(-1);
const [length, setLength] = useState(30000);
const [pending, setTransiton] = useTransition();
const handleClick = () => {
setValue((v) => v + 1);
setTransiton(() => setLength((l) => l + 1));
// setLength((l) => l + 1);
};
return (
<>
<div className="my-4">
<Button onClick={handleClick}>{value}</Button>
<Button onClick={() => setValue2((v) => v - 1)}>{value2}</Button>
</div>
<div
className={\`wrapper \${pending && \`fade\`}\`}
>
{Array.from({ length }).map((_, i) => (
<div className="p-2 mb-2 mr-2 rounded-md shadow" key={length - i}>
{length - i}
</div>
))}
</div>
<style>{\`
.wrapper {
transition: all 0.3 ease;
}
.fade {
opacity: 0.5;
}\`}
</style>
</>
);
};
export default UseTransition;`;
export const useDeferredValue = `import Button from './Button';
import { useDeferredValue, useState } from 'react';
const UseDeferredValue = () => {
const [value, setValue] = useState(0);
const deferred = useDeferredValue(value);
return (
<>
<div className="my-4">
<div>
Deferred:
<Button onClick={() => setValue((v) => v + 1)}>{deferred}</Button>
</div>
<div>
Primtive:
<Button onClick={() => setValue((v) => v + 1)}>{value}</Button>
</div>
</div>
<div>
{Array.from({ length: 30000 }).map((_, i) => (
<div className="p-2 mb-2 mr-2 rounded-md shadow" key={i}>
{i}
</div>
))}
</div>
</>
);
};
export default UseDeferredValue;`;
export const useId = `import Input from './Input';
import { useId } from 'react';
const RUAForm = () => {
const id = useId();
return (
<>
<label htmlFor={\`\${id}\`}>Label 1: </label>
<div>
<Input type="text" id={\`\${id}\`} />
</div>
</>
);
};
const UseId = () => {
return (
<>
<RUAForm />
<RUAForm />
</>
);
};
export default UseId;`;
export const store = `export type State = {
count: number;
info: string;
};
export type Store = {
state: State;
setState: (
stateOrFn: State | ((state: State) => State)
) => void;
subscribe: (listener: () => void) => () => void;
listeners: Set<() => void>;
getSnapshot: () => State;
};
const store: Store = {
state: {
count: 0,
info: 'Hello',
},
setState(stateOrFn) {
const newState =
typeof stateOrFn === 'function' ? stateOrFn(store.state) : stateOrFn;
store.state = {
...store.state,
...newState,
};
store.listeners.forEach((listener) => listener());
},
listeners: new Set(),
subscribe(listener) {
store.listeners.add(listener);
return () => {
store.listeners.delete(listener);
};
},
getSnapshot() {
return store.state;
},
};
export default store;`;
export const useSyncExternalStore = `import Button from './Button';
import Input from './Input';
import { useSyncExternalStore } from 'react';
import store from './store';
const Couter = () => {
const { count, info } = useSyncExternalStore(
store.subscribe,
store.getSnapshot
);
return (
<>
<div>
<div>
Count: <span>{count}</span>
</div>
<div>
Info: <span>{info}</span>
</div>
<div>
<Button
onClick={() => store.setState((d) => ({ ...d, count: d.count + 1 }))}
>
Add
</Button>
</div>
</div>
</>
);
};
const Infor = () => {
const { count, info } = useSyncExternalStore(
store.subscribe,
store.getSnapshot
);
return (
<>
<div>
<div>
Count: <span>{count}</span>
</div>
<div>
Info: <span>{info}</span>
</div>
<div>
<Input
type="text"
onChange={(e) => store.setState((d) => ({ ...d, info: e.target.value }))}
value={info}
/>
</div>
</div>
</>
);
};
const UseSyncExternalStore = () => {
return (
<>
<Couter />
<hr className="my-4" />
<Infor />
</>
);
};
export default UseSyncExternalStore;`;
export const useInsertionEffect = `import { useEffect, useLayoutEffect, useInsertionEffect } from 'react';
const Child = () => {
useEffect(() => {
console.log('useEffect child is called');
});
useLayoutEffect(() => {
console.log('useLayoutEffect child is called');
});
useInsertionEffect(() => {
console.log('useInsertionEffect child is called');
});
return <></>;
};
const UseInsertionEffect = () => {
useEffect(() => {
console.log('useEffect app is called');
});
useLayoutEffect(() => {
console.log('useLayoutEffect app is called');
});
useInsertionEffect(() => {
console.log('useInsertionEffect app is called');
});
return (
<>
<Child />
<div>Check console in DevTools</div>
</>
);
};
export default UseInsertionEffect;`;