UI infrastructure and simple "Help" dialog (#3)

Sets up some WIP infrastructure for building out the UI, and adds a simple popup
to show the navigation controls for the app.
This commit is contained in:
Danny McGee
2023-10-09 22:19:58 -04:00
committed by GitHub
parent 57d64f08f0
commit c84fd31387
40 changed files with 1608 additions and 590 deletions
+11
View File
@@ -0,0 +1,11 @@
# utility
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build utility` to build the library.
## Running unit tests
Run `nx test utility` to execute the unit tests via [Jest](https://jestjs.io).
+8
View File
@@ -0,0 +1,8 @@
{
"name": "@storyteller/utility",
"version": "0.0.1",
"dependencies": {},
"main": "./index.js",
"module": "./index.mjs",
"typings": "./index.d.ts"
}
+24
View File
@@ -0,0 +1,24 @@
{
"name": "utility",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "utility/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/utility"
}
},
"test": {
"executor": "@nx/vite:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"passWithNoTests": true,
"reportsDirectory": "../coverage/utility"
}
}
},
"tags": []
}
+2
View File
@@ -0,0 +1,2 @@
export * from "./lib/match";
export * from "./lib/types";
+93
View File
@@ -0,0 +1,93 @@
import { Fn } from "./types";
type Key = string | number;
type ExhaustiveMatcher<Union extends Key>
= Record<Union, () => any>
;
type MatcherWithFallback<Union extends Key>
= Partial<Record<Union, () => any>>
& { _: () => any }
;
type Matcher<Union extends Key>
= ExhaustiveMatcher<Union>
| MatcherWithFallback<Union>
;
type MatchReturn<K extends Key, T extends Matcher<K>>
// if K is a known, specific key of T, infer the matching function's return type
= T[K] extends Fn<[], infer R> ? R
// if K is unknown at comptime, infer the union of all matcher return types
: T[keyof T] extends Fn<[], infer R> ? R
// Unreachable
: never
;
/**
* Behaves like a simple [switch expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression)
* for JavaScript.
*
* @example
* ```typescript
* enum Direction {
* Forward,
* Left,
* Back,
* Right,
* }
*
* function getDirection(event: KeyboardEvent): Direction {
* return match (event.key, {
* "W": () => Direction.Forward,
* "A": () => Direction.Left,
* "S": () => Direction.Back,
* "D": () => Direction.Right,
* _: () => {
* throw new Error(`${event.key} is not bound to a direction!`);
* },
* });
* }
* ```
* An enum can also be used as the subject, as long as its enumerators are
* assigned to values that can be used as JavaScript object keys (i.e. `string`,
* `number`, or `symbol`):
*
* @example
* ```typescript
* enum Direction {
* Up = "up",
* Down = "down",
* Right = "right",
* Left = "left",
* }
*
* enum Orientation {
* North,
* South,
* East,
* West,
* }
*
* function toOrientation(direction: Direction): Orientation {
* // Note that if the `matcher` argument is exhaustive,
* // you don't need to provide a `_` fallback.
* return match (direction, {
* [Direction.Up]: () => Orientation.North,
* [Direction.Right]: () => Orientation.East,
* [Direction.Down]: () => Orientation.South,
* [Direction.Left]: () => Orientation.West,
* });
* }
* ```
*/
export function match<K extends Key, T extends Matcher<K>>(
subject: K | null | undefined,
matcher: T,
): MatchReturn<K, T> {
if (subject && subject in matcher)
return matcher[subject]!();
if ("_" in matcher)
return matcher._();
throw new Error(`No match found for subject \`${subject}\` in matcher`);
}
+3
View File
@@ -0,0 +1,3 @@
export interface Fn<Args extends any[] = [], R = void> {
(...args: Args): R;
}
+22
View File
@@ -0,0 +1,22 @@
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../dist/out-tsc",
"declaration": true,
"types": ["node", "vite/client"]
},
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}
+25
View File
@@ -0,0 +1,25 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": [
"vitest/globals",
"vitest/importMeta",
"vite/client",
"node",
"vitest"
]
},
"include": [
"vite.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
]
}
+50
View File
@@ -0,0 +1,50 @@
/// <reference types='vitest' />
import { defineConfig } from "vite";
import dts from "vite-plugin-dts";
import * as path from "node:path";
import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin";
export default defineConfig({
cacheDir: "../node_modules/.vite/utility",
plugins: [
nxViteTsPaths(),
dts({
entryRoot: "src",
tsConfigFilePath: path.join(__dirname, "tsconfig.lib.json"),
skipDiagnostics: true,
}),
],
// Uncomment this if you are using workers.
// worker: {
// plugins: [ nxViteTsPaths() ],
// },
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: "src/index.ts",
name: "utility",
fileName: "index",
// Change this to the formats you want to support.
// Don't forget to update your package.json as well.
formats: ["es", "cjs"],
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: [],
},
},
test: {
globals: true,
cache: {
dir: "../node_modules/.vitest",
},
environment: "node",
include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
},
});