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 @@
# framework
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build framework` to build the library.
## Running unit tests
Run `nx test framework` to execute the unit tests via [Jest](https://jestjs.io).
+8
View File
@@ -0,0 +1,8 @@
{
"name": "@storyteller/framework",
"version": "0.0.1",
"dependencies": {},
"main": "./index.js",
"module": "./index.mjs",
"typings": "./index.d.ts"
}
+24
View File
@@ -0,0 +1,24 @@
{
"name": "framework",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "framework/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/framework"
}
},
"test": {
"executor": "@nx/vite:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"passWithNoTests": true,
"reportsDirectory": "../coverage/framework"
}
}
},
"tags": []
}
+1
View File
@@ -0,0 +1 @@
export * from "./lib/decorators/on";
+33
View File
@@ -0,0 +1,33 @@
import { LitElement } from "lit";
import { customElement, state } from "lit/decorators.js";
import { on } from "./on";
@customElement("test-counter")
class TestCounter extends LitElement {
@state() count = 0;
@on("click")
incrementCount(): void {
this.count += 1;
}
}
declare global {
interface HTMLElementTagNameMap {
"test-counter": TestCounter;
}
}
describe("@on(eventName)", () => {
it("binds a Custom Element method as an event handler", () => {
const counter = document.createElement("test-counter");
document.body.appendChild(counter);
counter.click();
counter.click();
counter.click();
expect(counter.count).toBe(3);
});
});
+51
View File
@@ -0,0 +1,51 @@
import { match } from "@storyteller/utility";
import type { LitElement } from "lit";
/**
* Adds the decorated method as an event listener for the given event name, and
* automatically cleans up the listener when the element is removed from the
* DOM.
*
* The event name can be prefixed with `window:` or `document:` to add the
* listener to one of those targets instead of the custom element itself.
*/
export function on(eventSelector: string) {
const [targetName, eventName] = eventSelector.includes(":")
? eventSelector.split(":")
: [null, eventSelector];
let target = match (targetName, {
"window": () => window as EventTarget,
"document": () => document as EventTarget,
_: () => null,
});
return <T extends LitElement>(proto: T, propName: keyof T, desc: PropertyDescriptor) => {
const handler = desc?.value ?? proto[propName] ?? (() => {});
const connectedCb = proto.connectedCallback;
const disconnectedCb = proto.disconnectedCallback;
Object.defineProperty(proto, "connectedCallback", {
value: function (this: HTMLElement) {
target ??= this;
target.addEventListener(eventName, handler);
connectedCb.call(this);
},
configurable: true,
writable: true,
});
Object.defineProperty(proto, "disconnectedCallback", {
value: function (this: HTMLElement) {
target ??= this;
target.removeEventListener(eventName, handler);
disconnectedCb.call(this);
},
configurable: true,
writable: true,
});
return desc;
}
}
+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 "path";
import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin";
export default defineConfig({
cacheDir: "../node_modules/.vite/framework",
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: "framework",
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: "jsdom",
include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
},
});