Skip to content

Commit 5ee0013

Browse files
committed
Merge branch 'master' into release
2 parents 006cdbb + 1d10a24 commit 5ee0013

File tree

272 files changed

+12964
-10976
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

272 files changed

+12964
-10976
lines changed

.github/workflows/node.js.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ jobs:
1818

1919
steps:
2020
- uses: actions/checkout@v3
21-
- name: Use Node.js 16.x
21+
- name: Use Node.js 18.x
2222
uses: actions/setup-node@v3
2323
with:
24-
node-version: '16.x'
24+
node-version: '18.x'
2525
cache: 'npm'
2626
- run: npm ci
2727
- run: npm run build

.github/workflows/publish-docs.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ jobs:
88
runs-on: windows-latest
99
steps:
1010
- uses: actions/checkout@v3
11-
- name: Use Node.js 16.x
11+
- name: Use Node.js 18.x
1212
uses: actions/setup-node@v3
1313
with:
14-
node-version: '16.x'
14+
node-version: '18.x'
1515
cache: 'npm'
1616
- run: npm ci
1717
- run: npm run docs:build

.github/workflows/update-ci-snapshots.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ jobs:
88
runs-on: windows-latest
99
steps:
1010
- uses: actions/checkout@v3
11-
- name: Use Node.js 16.x
11+
- name: Use Node.js 18.x
1212
uses: actions/setup-node@v3
1313
with:
14-
node-version: '16.x'
14+
node-version: '18.x'
1515
cache: 'npm'
1616
- run: npm ci
1717
- run: npm run test-e2e --- -u

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ docs/.vitepress/api-docs/.temp
1515
test-e2e/test-page-lib/impl/dist
1616
.updated-snapshots
1717
**/dist/**/*
18-
!dist
18+
!dist
19+
*.tsbuildinfo

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var context = infiniteCanvas.getContext("2d");
2323
Include `InfiniteCanvas` in your web page:
2424

2525
```html
26-
<script src="https://cdn.jsdelivr.net/npm/[email protected].6/dist/infinite-canvas.umd.cjs"></script>
26+
<script src="https://cdn.jsdelivr.net/npm/[email protected].7/dist/infinite-canvas.umd.cjs"></script>
2727
```
2828

2929
or install it using npm:
@@ -49,4 +49,9 @@ npm run test-e2e
4949
```
5050
which will start a server that serves pages in which `InfiniteCanvas` is used, and which will then run `jest` tests that use [Puppeteer](https://pptr.dev/) to manipulate those pages and [`jest-image-snapshot`](https://github.com/americanexpress/jest-image-snapshot#readme) to compare screenshots.
5151

52+
## Local development
53+
54+
First run `npm run dev-app:build` once. Then `npm run dev` will run an app that displays all manner of use cases for InfiniteCanvas, served by Vite.
55+
56+
5257
*Even though not much has happened in this repository lately, I have not forgotten about it. Quite to the contrary, there are a lot more features I'm planning to add in the not-too-distant future.*

dev-app/backend/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const PORT = 8080;
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { type PluginOption } from 'vite'
2+
import { type Express } from 'express'
3+
import { createRouter } from './router';
4+
5+
function devBackend(): PluginOption{
6+
let apiRouter: Express | undefined;
7+
return {
8+
name: 'vite-plugin-dev-app-backend',
9+
apply: 'serve',
10+
configureServer(server){
11+
server.middlewares.use('/api', apiRouter || (apiRouter = createRouter()))
12+
}
13+
}
14+
}
15+
16+
export function backend(): PluginOption[]{
17+
return [devBackend()]
18+
}

dev-app/backend/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './frontend-vite-plugin'

dev-app/backend/router.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { default as express, type Express, type Request, type Response, json } from 'express'
2+
import { ExampleDescription } from '../shared';
3+
import { createExample, getExamplesMetadata } from '../../examples/access'
4+
import { getTestCasesMetadata } from '../../test-cases/backend'
5+
import { CreateExampleRequest } from '../../examples/shared';
6+
7+
function logRequest(req: Request, res: Response): void{
8+
console.log(`responding with ${res.statusCode} to ${req.path}`)
9+
}
10+
11+
export function createRouter(): Express{
12+
const app = express();
13+
app.use(json())
14+
app.get('/examples', async (_, res, next) => {
15+
const [examples, testCases] = await Promise.all([getExamplesMetadata(), getTestCasesMetadata()])
16+
const exampleDescriptions: ExampleDescription[] = examples.map(({dirName, title}) => ({
17+
id: dirName,
18+
title,
19+
kind: 'use-case'
20+
}));
21+
const testCaseDescriptions: ExampleDescription[] = testCases.map(({id, title}) => ({
22+
id,
23+
title,
24+
kind: 'test-case'
25+
}))
26+
res.json(exampleDescriptions.concat(testCaseDescriptions))
27+
next()
28+
}, logRequest)
29+
app.post('/examples/create', async (req, res) => {
30+
const {dirName, title} = await createExample(req.body)
31+
const newDescription: ExampleDescription = {
32+
id: dirName,
33+
title,
34+
kind: 'use-case'
35+
};
36+
res.json(newDescription)
37+
})
38+
return app;
39+
}

dev-app/backend/run.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import http from 'http'
2+
import fs from 'fs'
3+
import { createServer } from 'vite'
4+
import express from 'express'
5+
import { fileURLToPath } from 'url'
6+
import { createRouter } from './router';
7+
import { PORT } from './constants';
8+
import { createViteConfig } from '../examples-runner/create-vite-config';
9+
10+
async function run(){
11+
const app = express();
12+
const server = http.createServer(app)
13+
app.use('/api', createRouter())
14+
const frontendPath = fileURLToPath(new URL('../frontend/dist', import.meta.url))
15+
if(!fs.existsSync(frontendPath)){
16+
console.warn(`Directory '${frontendPath}' does not exist. Did you run \`npm run dev-app:build\`?`)
17+
return;
18+
}
19+
app.use(express.static(frontendPath))
20+
app.use((await createServer(createViteConfig(server))).middlewares)
21+
22+
await new Promise<void>(res => {
23+
server.listen(PORT, res);
24+
})
25+
console.log(`http://localhost:${PORT}`)
26+
}
27+
28+
run();

dev-app/backend/tsconfig.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"extends": "../../tsconfig.node.json",
3+
"include": [
4+
"**/*.ts",
5+
"../shared/**/*.ts",
6+
"../examples-runner/**/*.ts",
7+
"../../utils/vite/**/*.ts"
8+
],
9+
"exclude": ["../examples-runner/test-case/src/**/*.ts"],
10+
"references": [
11+
{"path": "../../test-cases/tsconfig.node.json"},
12+
{"path": "../../examples/tsconfig.node.json"}
13+
],
14+
"compilerOptions": {
15+
"composite": true,
16+
"noEmit": true,
17+
"rootDir": "../.."
18+
}
19+
}

dev-app/examples-runner/add-runner.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { PluginOption } from 'vite'
2+
import { fileURLToPath } from "url";
3+
import { createViteConfig as createExamplesViteConfig, ExampleRunnerOptions } from '../../examples/runner'
4+
import { serveOther, OtherServerOptions } from '../../utils/vite';
5+
import { TestCaseRunnerOptions } from './test-case/options';
6+
import { createViteConfig as createTestCasesViteConfig } from './test-case/create-vite-config'
7+
8+
function serveTestCases(options: TestCaseRunnerOptions, server: OtherServerOptions): PluginOption{
9+
return serveOther({
10+
id: 'test-cases',
11+
path: '/test-case',
12+
config: createTestCasesViteConfig(options),
13+
server
14+
})
15+
}
16+
17+
function serveExamples(options: ExampleRunnerOptions, server: OtherServerOptions): PluginOption{
18+
return serveOther({
19+
id: 'examples',
20+
path: '/examples',
21+
config: createExamplesViteConfig(options),
22+
server
23+
})
24+
}
25+
26+
export function addRunner(server: OtherServerOptions): PluginOption[]{
27+
const infiniteCanvasPath = fileURLToPath(new URL('../../src/infinite-canvas.ts', import.meta.url))
28+
return [
29+
serveExamples({infiniteCanvasPath}, server),
30+
serveTestCases({infiniteCanvasPath}, server),
31+
]
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import http from 'http'
2+
import { InlineConfig } from "vite";
3+
import { fileURLToPath } from "url";
4+
import { addRunner } from './add-runner'
5+
import { PORT } from "../backend/constants";
6+
7+
export function createViteConfig(server: http.Server): InlineConfig{
8+
const root = fileURLToPath(new URL('.', import.meta.url));
9+
return {
10+
root,
11+
optimizeDeps: {
12+
exclude: ['virtual:test-cases-list', 'infinite-canvas']
13+
},
14+
plugins: [addRunner({port: PORT, server})],
15+
server: {
16+
middlewareMode: { server: server },
17+
hmr: {
18+
port: PORT,
19+
server: server
20+
}
21+
}
22+
};
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { fileURLToPath } from "url";
2+
import { InlineConfig } from "vite";
3+
import { TestCaseRunnerOptions } from "./options";
4+
import { addDarkTheme } from "../../../utils/dark-theme/vite-plugin";
5+
import { addTestCasesList } from "../../../test-cases/vite-plugins";
6+
7+
export function createViteConfig({infiniteCanvasPath}: TestCaseRunnerOptions): InlineConfig{
8+
const root = fileURLToPath(new URL('.', import.meta.url))
9+
return {
10+
root,
11+
resolve: {
12+
alias: {
13+
'infinite-canvas': infiniteCanvasPath
14+
}
15+
},
16+
plugins: [addDarkTheme(), addTestCasesList()]
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
:root{
2+
background-color: #333;
3+
--light: #bbb;
4+
color: var(--light);
5+
6+
}
7+
.canvas-container{
8+
border-color: var(--light)
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
:root{
2+
--dark: #333;
3+
font-family: Roboto, sans-serif;
4+
color: var(--dark);
5+
}
6+
.canvas-display{
7+
display: inline-block;
8+
}
9+
.canvas-container{
10+
width: 400px;
11+
height: 400px;
12+
border: 1px solid var(--dark);
13+
}
14+
.canvas-container canvas{
15+
width: 100%;
16+
height: 100%;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Test case</title>
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6+
<link rel="stylesheet" type="text/css" href="index.css"/>
7+
</head>
8+
<body>
9+
<div class="canvas-display">
10+
<div class="canvas-container">
11+
<canvas width="400" height="400" id="regular-canvas"></canvas>
12+
</div>
13+
<div class="canvas-display-label">
14+
regular canvas
15+
</div>
16+
</div>
17+
<div class="canvas-display">
18+
<div class="canvas-container">
19+
<canvas width="400" height="400" id="infinite-canvas"></canvas>
20+
</div>
21+
<div class="canvas-display-label">
22+
infinite canvas
23+
</div>
24+
</div>
25+
<script type="module" src="src/main.ts"></script>
26+
</body>
27+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export interface TestCaseRunnerOptions{
2+
infiniteCanvasPath: string
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { TestCaseDistortion } from "test-case";
2+
3+
export interface CanvasElement{
4+
ctx: CanvasRenderingContext2D;
5+
el: HTMLCanvasElement;
6+
applyDistortion(distortion: TestCaseDistortion): void
7+
reset(): void
8+
}
9+
10+
export function createCanvasElement(el: HTMLCanvasElement): CanvasElement{
11+
const width = el.width;
12+
const height = el.height;
13+
const ctx = el.getContext('2d') as CanvasRenderingContext2D;
14+
function reset(): void{
15+
el.width = width;
16+
el.height = height;
17+
el.style.removeProperty('width')
18+
el.style.removeProperty('height')
19+
}
20+
function applyDistortion(distortion: TestCaseDistortion): void{
21+
el.style.width = distortion.screenWidth;
22+
el.style.height = distortion.screenHeight;
23+
el.width = distortion.viewboxWidth;
24+
el.height = distortion.viewboxHeight;
25+
}
26+
return { el, ctx, reset, applyDistortion }
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { TestCase } from "test-case";
2+
import InfiniteCanvas from "infinite-canvas";
3+
import type { TestCaseDisplay } from "./test-case-display";
4+
import type { CanvasElement } from "./canvas-element";
5+
6+
export function createInfiniteDisplay(canvasEl: CanvasElement): TestCaseDisplay{
7+
function displayTestCase(testCase: TestCase): void{
8+
canvasEl.reset();
9+
if(testCase.distortion){
10+
canvasEl.applyDistortion(testCase.distortion);
11+
}
12+
const infCanvas = new InfiniteCanvas(canvasEl.el);
13+
const ctx = infCanvas.getContext('2d');
14+
testCase.code(ctx);
15+
}
16+
return { displayTestCase }
17+
}

0 commit comments

Comments
 (0)