Compare commits

...

2 Commits

Author SHA1 Message Date
e560248
048120adae different form examples 2025-04-07 15:07:00 +02:00
e560248
8a3165a26d MemoCallback 2025-04-07 14:29:13 +02:00
8 changed files with 563 additions and 2 deletions

View File

@@ -22,7 +22,8 @@
"globals": "^15.15.0",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
"vite": "^6.2.0",
"vitest": "^3.1.1"
}
},
"node_modules/@ampproject/remapping": {
@@ -1665,6 +1666,119 @@
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0"
}
},
"node_modules/@vitest/expect": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/expect/-/expect-3.1.1.tgz",
"integrity": "sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/spy": "3.1.1",
"@vitest/utils": "3.1.1",
"chai": "^5.2.0",
"tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/mocker": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/mocker/-/mocker-3.1.1.tgz",
"integrity": "sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/spy": "3.1.1",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.17"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"msw": "^2.4.9",
"vite": "^5.0.0 || ^6.0.0"
},
"peerDependenciesMeta": {
"msw": {
"optional": true
},
"vite": {
"optional": true
}
}
},
"node_modules/@vitest/pretty-format": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/pretty-format/-/pretty-format-3.1.1.tgz",
"integrity": "sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==",
"dev": true,
"license": "MIT",
"dependencies": {
"tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/runner": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/runner/-/runner-3.1.1.tgz",
"integrity": "sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/utils": "3.1.1",
"pathe": "^2.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/snapshot": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/snapshot/-/snapshot-3.1.1.tgz",
"integrity": "sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/pretty-format": "3.1.1",
"magic-string": "^0.30.17",
"pathe": "^2.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/spy": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/spy/-/spy-3.1.1.tgz",
"integrity": "sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"tinyspy": "^3.0.2"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/utils": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/@vitest/utils/-/utils-3.1.1.tgz",
"integrity": "sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/pretty-format": "3.1.1",
"loupe": "^3.1.3",
"tinyrainbow": "^2.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/acorn": {
"version": "8.14.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/acorn/-/acorn-8.14.1.tgz",
@@ -1728,6 +1842,16 @@
"dev": true,
"license": "Python-2.0"
},
"node_modules/assertion-error": {
"version": "2.0.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/assertion-error/-/assertion-error-2.0.1.tgz",
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1792,6 +1916,16 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/cac/-/cac-6.7.14.tgz",
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/callsites/-/callsites-3.1.0.tgz",
@@ -1823,6 +1957,23 @@
],
"license": "CC-BY-4.0"
},
"node_modules/chai": {
"version": "5.2.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/chai/-/chai-5.2.0.tgz",
"integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
"dev": true,
"license": "MIT",
"dependencies": {
"assertion-error": "^2.0.1",
"check-error": "^2.1.1",
"deep-eql": "^5.0.1",
"loupe": "^3.1.0",
"pathval": "^2.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/chalk/-/chalk-4.1.2.tgz",
@@ -1840,6 +1991,16 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/check-error": {
"version": "2.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/check-error/-/check-error-2.1.1.tgz",
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 16"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/color-convert/-/color-convert-2.0.1.tgz",
@@ -1914,6 +2075,16 @@
}
}
},
"node_modules/deep-eql": {
"version": "5.0.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/deep-eql/-/deep-eql-5.0.2.tgz",
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/deep-is/-/deep-is-0.1.4.tgz",
@@ -1928,6 +2099,13 @@
"dev": true,
"license": "ISC"
},
"node_modules/es-module-lexer": {
"version": "1.6.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
"dev": true,
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.25.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/esbuild/-/esbuild-0.25.2.tgz",
@@ -2160,6 +2338,16 @@
"node": ">=4.0"
}
},
"node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/esutils/-/esutils-2.0.3.tgz",
@@ -2170,6 +2358,16 @@
"node": ">=0.10.0"
}
},
"node_modules/expect-type": {
"version": "1.2.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/expect-type/-/expect-type-1.2.1.tgz",
"integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2554,6 +2752,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/loupe": {
"version": "3.1.3",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/loupe/-/loupe-3.1.3.tgz",
"integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
"dev": true,
"license": "MIT"
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -2564,6 +2769,16 @@
"yallist": "^3.0.2"
}
},
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/merge2/-/merge2-1.4.1.tgz",
@@ -2724,6 +2939,23 @@
"node": ">=8"
}
},
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true,
"license": "MIT"
},
"node_modules/pathval": {
"version": "2.0.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/pathval/-/pathval-2.0.0.tgz",
"integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.16"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/picocolors/-/picocolors-1.1.1.tgz",
@@ -2969,6 +3201,13 @@
"node": ">=8"
}
},
"node_modules/siginfo": {
"version": "2.0.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/siginfo/-/siginfo-2.0.0.tgz",
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
"dev": true,
"license": "ISC"
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -2979,6 +3218,20 @@
"node": ">=0.10.0"
}
},
"node_modules/stackback": {
"version": "0.0.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/stackback/-/stackback-0.0.2.tgz",
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
"dev": true,
"license": "MIT"
},
"node_modules/std-env": {
"version": "3.9.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/std-env/-/std-env-3.9.0.tgz",
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
"dev": true,
"license": "MIT"
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -3005,6 +3258,50 @@
"node": ">=8"
}
},
"node_modules/tinybench": {
"version": "2.9.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/tinybench/-/tinybench-2.9.0.tgz",
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
"dev": true,
"license": "MIT"
},
"node_modules/tinyexec": {
"version": "0.3.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/tinyexec/-/tinyexec-0.3.2.tgz",
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
"dev": true,
"license": "MIT"
},
"node_modules/tinypool": {
"version": "1.0.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/tinypool/-/tinypool-1.0.2.tgz",
"integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.0.0 || >=20.0.0"
}
},
"node_modules/tinyrainbow": {
"version": "2.0.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/tinyspy": {
"version": "3.0.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/tinyspy/-/tinyspy-3.0.2.tgz",
"integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -3194,6 +3491,99 @@
}
}
},
"node_modules/vite-node": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/vite-node/-/vite-node-3.1.1.tgz",
"integrity": "sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.4.0",
"es-module-lexer": "^1.6.0",
"pathe": "^2.0.3",
"vite": "^5.0.0 || ^6.0.0"
},
"bin": {
"vite-node": "vite-node.mjs"
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/vitest": {
"version": "3.1.1",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/vitest/-/vitest-3.1.1.tgz",
"integrity": "sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/expect": "3.1.1",
"@vitest/mocker": "3.1.1",
"@vitest/pretty-format": "^3.1.1",
"@vitest/runner": "3.1.1",
"@vitest/snapshot": "3.1.1",
"@vitest/spy": "3.1.1",
"@vitest/utils": "3.1.1",
"chai": "^5.2.0",
"debug": "^4.4.0",
"expect-type": "^1.2.0",
"magic-string": "^0.30.17",
"pathe": "^2.0.3",
"std-env": "^3.8.1",
"tinybench": "^2.9.0",
"tinyexec": "^0.3.2",
"tinypool": "^1.0.2",
"tinyrainbow": "^2.0.0",
"vite": "^5.0.0 || ^6.0.0",
"vite-node": "3.1.1",
"why-is-node-running": "^2.3.0"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/debug": "^4.1.12",
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
"@vitest/browser": "3.1.1",
"@vitest/ui": "3.1.1",
"happy-dom": "*",
"jsdom": "*"
},
"peerDependenciesMeta": {
"@edge-runtime/vm": {
"optional": true
},
"@types/debug": {
"optional": true
},
"@types/node": {
"optional": true
},
"@vitest/browser": {
"optional": true
},
"@vitest/ui": {
"optional": true
},
"happy-dom": {
"optional": true
},
"jsdom": {
"optional": true
}
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/which/-/which-2.0.2.tgz",
@@ -3210,6 +3600,23 @@
"node": ">= 8"
}
},
"node_modules/why-is-node-running": {
"version": "2.3.0",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
"dev": true,
"license": "MIT",
"dependencies": {
"siginfo": "^2.0.0",
"stackback": "0.0.2"
},
"bin": {
"why-is-node-running": "cli.js"
},
"engines": {
"node": ">=8"
}
},
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://bin.sbb.ch/artifactory/api/npm/npm/word-wrap/-/word-wrap-1.2.5.tgz",

View File

@@ -24,6 +24,7 @@
"globals": "^15.15.0",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
"vite": "^6.2.0",
"vitest": "^3.1.1"
}
}

View File

@@ -40,3 +40,8 @@
.read-the-docs {
color: #888;
}
input[type="text"] {
border-radius: 6px;
padding: 1rem 0.5rem;
}

View File

@@ -0,0 +1,12 @@
import React, { memo } from "react";
interface SearchProps {
onChange: (text: string) => void;
}
function Search({ onChange }: SearchProps): React.ReactElement {
console.log("Search rendered");
return <input type="text" onChange={(e) => onChange(e.target.value)} placeholder="Search user..." />;
}
export default memo(Search);

View File

@@ -0,0 +1,34 @@
import { useCallback, useState } from "react";
import { shuffleArray, users } from "../../../utils/shuffle";
import Search from "./Search";
export default function MemoCallback() {
console.log("MemoCallback rendered");
const [allUsers, setAllUsers] = useState(users);
const handleSearch = useCallback((text: string) => {
const filteredUsers = users.filter((user) => {
return user.toLowerCase().includes(text.toLowerCase());
});
setAllUsers(filteredUsers);
}, []);
const handleShuffle = () => {
setAllUsers(shuffleArray(users));
};
const ListOfUsers = allUsers.map((user) => {
return <p key={user}>{user}</p>;
});
return (
<div>
<h1>Memo Callback Übung</h1>
<button onClick={handleShuffle}>Shuffle</button>
<Search onChange={handleSearch} />
<div>
{ListOfUsers}
</div>
</div>
);
}

View File

@@ -0,0 +1,69 @@
import { FormEvent, useRef, useState } from "react";
export default function RefExercise(): React.ReactElement {
console.log("RefExercise rendered");
const emailRef = useRef<HTMLInputElement>(null);
const passwordRef = useRef<HTMLInputElement>(null);
const handleSubmit = () => {
console.log("submit", {
email: emailRef.current?.value,
password: passwordRef.current?.value
});
passwordRef.current?.focus();
}
const [formData, setFormData] = useState({
strasse: "",
city: ""
});
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[event.target.name]: event.target.value
});
}
const handleChangeSubmit = () => {
const strasse = document.querySelector('input[name="strasse"]') as HTMLInputElement;
const city = document.querySelector('input[name="city"]') as HTMLInputElement;
console.log("submit", {
strasse: strasse.value,
city: city.value
});
}
function handleFormSubmit(e: FormEvent) {
e.preventDefault();
const data = new FormData(e.target as HTMLFormElement);
console.log('handleFormSubmit', {
email: data.get('email'),
password: data.get('password')
});
}
return (
<div style={{ display: "flex", flexDirection: "column", gap: "3rem" }}>
<div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
<h3>values by ref</h3>
<input type="text" placeholder="email" ref={emailRef}/>
<input type="text" placeholder="password" ref={passwordRef}/>
<button onClick={handleSubmit}>Submit</button>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
<h3>change event (bad way, but validation is possible)</h3>
<input type="text" name="strasse" placeholder="Strasse" onChange={handleChange} />
<input type="text" name="city" placeholder="Stadt" onChange={handleChange}/>
<button onClick={handleChangeSubmit}>submit</button>
</div>
<form onSubmit={handleFormSubmit} style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
<h3>By Form Event</h3>
<input type="text" name="email" placeholder="Email" />
<input type="text" name="password" placeholder="password" />
<button type="submit">Send</button>
</form>
</div>
);
}

View File

@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest';
import { shuffleArray, users } from './shuffle';
describe('shuffleArray', () => {
it('should shuffle the array and return a new order', () => {
const originalArray = [...users];
const shuffledArray = shuffleArray([...users]);
expect(shuffledArray).not.toEqual(originalArray); // Ensure the order is different
expect(shuffledArray.sort()).toEqual(originalArray.sort()); // Ensure all elements are still present
});
it('should return an empty array when input is empty', () => {
const result = shuffleArray([]);
expect(result).toEqual([]);
});
it('should handle arrays with one element', () => {
const result = shuffleArray(['onlyElement']);
expect(result).toEqual(['onlyElement']);
});
});

View File

@@ -0,0 +1,11 @@
export function shuffleArray(array: string[]){
for(let i = array.length -1; i>0; i--){
const j = Math.floor(Math.random()* (i +1));
[array[i], array[j]] = [array[j], array[i]];
}
return [...array]
}
export const users =['John', 'Peter', 'Stefanie', 'Marta', 'Klaus', 'Anna']