@citolab/tspci 2.0.7 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -674
- package/package.json +2 -2
- package/public/index.html +289 -289
- package/readme.md +338 -338
- package/release-notes.md +17 -13
- package/src/cli.js +143 -143
- package/src/rollup-plugin-live-server.js +32 -32
- package/src/rollup.config.dev.js +28 -28
- package/src/rollup.config.js +82 -82
- package/src/rollup.config.prod.js +10 -10
- package/types/index.d.ts +88 -88
package/readme.md
CHANGED
|
@@ -1,338 +1,338 @@
|
|
|
1
|
-
<h1>
|
|
2
|
-
A modern QTI-PCI development environment creating and testing portable custom interactions
|
|
3
|
-
</h1>
|
|
4
|
-
|
|
5
|
-
<p align="center">
|
|
6
|
-
<img src="https://github.com/Citolab/tspci/blob/main/lib/tspci/tspci-development.png" alt="Typescript Pci Builder">
|
|
7
|
-
</p>
|
|
8
|
-
|
|
9
|
-
[Release notes](https://github.com/Citolab/tspci/lib/tspci/release-notes.md)
|
|
10
|
-
|
|
11
|
-
## ✨ Features <a name="features"></a>
|
|
12
|
-
|
|
13
|
-
- Use modern tooling like typescript, preact, postcss and tailwind
|
|
14
|
-
- Build and bundle your library PCI using only a `package.json`
|
|
15
|
-
- Test and develop all your PCI states, configs, responses and lifecycle without uploading
|
|
16
|
-
- Develop in live server which directly updates on code changes
|
|
17
|
-
- Produces a single bundle .js file to use in any delivery engine that supports the latest IMS PCI standard
|
|
18
|
-
- 0 configuration TypeScript support
|
|
19
|
-
- Bundles all your css, images and json files.
|
|
20
|
-
- Postcss support, use CSS nesting out of the box.
|
|
21
|
-
- First class (p)react and tailwind support
|
|
22
|
-
- Extension for TAO, configuring icon, label, support for setting correct response and pci-properties
|
|
23
|
-
|
|
24
|
-
## 🔧 Installation & Setup
|
|
25
|
-
|
|
26
|
-
1️. **Install** by running: `npm i -D @citolab/tspci`
|
|
27
|
-
|
|
28
|
-
2️. **Set up** your `package.json`:
|
|
29
|
-
|
|
30
|
-
`// package.json`
|
|
31
|
-
```json
|
|
32
|
-
{
|
|
33
|
-
"name": "@citolab/hello-world",
|
|
34
|
-
"description": "Hello world pci",
|
|
35
|
-
"version": "1.0.0",
|
|
36
|
-
"main": "dist/index.js",
|
|
37
|
-
"types": "dist/types.d.ts",
|
|
38
|
-
"dependencies": {},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@citolab/tspci": "^1.5.6",
|
|
41
|
-
"@citolab/tspci-tao": "^1.0.0"
|
|
42
|
-
},
|
|
43
|
-
"scripts": {
|
|
44
|
-
"dev": "tspci --dev",
|
|
45
|
-
"prod": "tspci"
|
|
46
|
-
},
|
|
47
|
-
"source": "src/index.ts"
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Add the following PCI in the src folder `index.ts`
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
// src/index.ts
|
|
55
|
-
import { Configuration, IMSpci } from "@citolab/tspci";
|
|
56
|
-
import * as ctx from "qtiCustomInteractionContext";
|
|
57
|
-
|
|
58
|
-
class Pci implements IMSpci<{}> {
|
|
59
|
-
typeIdentifier = "HelloWorld"; // same as in package.json
|
|
60
|
-
shadowdom: ShadowRoot;
|
|
61
|
-
|
|
62
|
-
constructor() {
|
|
63
|
-
ctx && ctx.register(this);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
getInstance = (dom: HTMLElement, config: Configuration<any>, state: string) => {
|
|
67
|
-
this.shadowdom = dom.attachShadow({ mode: "closed" });
|
|
68
|
-
this.render();
|
|
69
|
-
config.onready(this);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
private render = () => {
|
|
73
|
-
this.shadowdom.innerHTML = `<div>Hello-World</div>`;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
getResponse = () => {
|
|
77
|
-
return null;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
getState = () => null;
|
|
81
|
-
}
|
|
82
|
-
export default new Pci();
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Add this in your root project: `global.d.ts` file
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
// global.d.ts
|
|
89
|
-
declare module "qtiCustomInteractionContext" {
|
|
90
|
-
const register: { register: (PortableInteraction) => void };
|
|
91
|
-
export = register;
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Add a `tsconfig.json` to your project for type checking
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"compilerOptions": {
|
|
100
|
-
"declaration": true,
|
|
101
|
-
"lib": ["es6", "dom", "dom.iterable"],
|
|
102
|
-
"module": "es6",
|
|
103
|
-
"moduleResolution": "node",
|
|
104
|
-
"removeComments": true,
|
|
105
|
-
"sourceMap": true,
|
|
106
|
-
"strict": false,
|
|
107
|
-
"target": "es6",
|
|
108
|
-
"outDir": "./dist",
|
|
109
|
-
"jsx": "react-jsx",
|
|
110
|
-
"jsxImportSource": "preact",
|
|
111
|
-
"allowSyntheticDefaultImports": true,
|
|
112
|
-
"resolveJsonModule": true,
|
|
113
|
-
"esModuleInterop": true,
|
|
114
|
-
},
|
|
115
|
-
"include": ["**/*"],
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**Try it out** by running `tspci --dev`.
|
|
120
|
-
|
|
121
|
-
### All CLI Options
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
Usage
|
|
125
|
-
$ tspci <command> [options]
|
|
126
|
-
|
|
127
|
-
Available Commands
|
|
128
|
-
--dev -d Start development server
|
|
129
|
-
--watch -w Only watch changes
|
|
130
|
-
--help -h Help about commandos
|
|
131
|
-
--target -t Build production for platform
|
|
132
|
-
|
|
133
|
-
Examples package.json scripts
|
|
134
|
-
$ "dev": "tspci --dev",
|
|
135
|
-
$ "prod": "tspci",
|
|
136
|
-
$ "watch": "tspci --watch",
|
|
137
|
-
$ "package-tao": "tspci --target tao"
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## 🛣 What's next
|
|
141
|
-
|
|
142
|
-
Use one of the [examples](https://github.com/Citolab/tspci-
|
|
143
|
-
|
|
144
|
-
Or read further how we build our PCIs
|
|
145
|
-
|
|
146
|
-
Our prefered layout of our PCIs
|
|
147
|
-
```
|
|
148
|
-
your-pci-project
|
|
149
|
-
│ package.json // Definition of your PCI in a standard package.json, TAO adds some props
|
|
150
|
-
│ global.d.ts // Tell typescript qtiCustomInteractionContext is supplied later, adds a shim
|
|
151
|
-
│ tsconfig.json // Typescript configuration, also for type checking your code
|
|
152
|
-
│
|
|
153
|
-
└───src
|
|
154
|
-
│ │ config.json // Used to configure PCI, and in TAO for authors
|
|
155
|
-
│ │ index.ts // The api for the player and bootstraps your interaction
|
|
156
|
-
│ │ interaction.ts // the actual interaction, preferably a main preact component
|
|
157
|
-
│ │ store.ts // definition of the state and all possible state mutations of your pci
|
|
158
|
-
│ └───style.css // css styles, imported by your pci and possible to use tailwind classes
|
|
159
|
-
│
|
|
160
|
-
│ postcss.config.js // optionally adds postcss processing of css
|
|
161
|
-
│ tailwind.config.js // include tailwind classes
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
### Use JSX
|
|
166
|
-
Use (p)react in your PCI's to create interactions and bind your data to HTML
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
+ import { h, render } from "preact";
|
|
170
|
-
|
|
171
|
-
render(null, this.shadowdom);
|
|
172
|
-
|
|
173
|
-
render = () => {
|
|
174
|
-
+ render(null, this.shadowdom);
|
|
175
|
-
+ render(<Interaction config={this.config.properties} />, this.shadowdom);
|
|
176
|
-
};
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Bundle your css
|
|
180
|
-
Import and bundle css
|
|
181
|
-
Appending css to shadowdom will prevent styles leaking into your player
|
|
182
|
-
|
|
183
|
-
```ts
|
|
184
|
-
+ import style from "./style.css";
|
|
185
|
-
|
|
186
|
-
render = () => {
|
|
187
|
-
render(...
|
|
188
|
-
+ const css = document.createElement("style");
|
|
189
|
-
+ css.innerHTML = style;
|
|
190
|
-
+ this.shadowdom.appendChild(css);
|
|
191
|
-
render(...
|
|
192
|
-
};
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Use modern css
|
|
196
|
-
|
|
197
|
-
install autoprefixer
|
|
198
|
-
|
|
199
|
-
``` sh
|
|
200
|
-
npm i -D autoprefixer
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
add `postcss.config.js` with autoprefixer
|
|
204
|
-
|
|
205
|
-
// postcss.config.js
|
|
206
|
-
```js
|
|
207
|
-
module.exports = {
|
|
208
|
-
plugins: [
|
|
209
|
-
require('postcss-import'),
|
|
210
|
-
require('autoprefixer'),
|
|
211
|
-
]
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Modern UI with existing classes
|
|
216
|
-
|
|
217
|
-
add tailwind to `postcss.config.js`
|
|
218
|
-
and add a `tailwind.config.js`
|
|
219
|
-
|
|
220
|
-
```js
|
|
221
|
-
// postcss.config.js
|
|
222
|
-
plugins: [
|
|
223
|
-
+ require('tailwindcss/nesting'),
|
|
224
|
-
+ require('tailwindcss'),
|
|
225
|
-
];
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
```js
|
|
229
|
-
// tailwind.config.js
|
|
230
|
-
module.exports = {
|
|
231
|
-
content: ["./src/**/*.{html,js,ts,jsx,tsx}", "./*.xml"], // html/javascript and typescript, and everything in pci markup
|
|
232
|
-
theme: {
|
|
233
|
-
extend: {},
|
|
234
|
-
},
|
|
235
|
-
plugins: [],
|
|
236
|
-
};
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### Bundle all your images
|
|
240
|
-
Images are bundled in the js by importing them in code:
|
|
241
|
-
imports JPG, PNG, GIF, SVG, and WebP files
|
|
242
|
-
|
|
243
|
-
```ts
|
|
244
|
-
import procenten from "./assets/procenten.png";
|
|
245
|
-
<img src={procenten} />;
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### Create advanced PCIs with 3D libraries
|
|
249
|
-
For example, import threejs to create 3D pci's
|
|
250
|
-
|
|
251
|
-
```ts
|
|
252
|
-
// src/interaction.ts
|
|
253
|
-
import * as THREE from "three";
|
|
254
|
-
|
|
255
|
-
class VoxelPainterClass {
|
|
256
|
-
private scene: THREE.Scene;
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### Record user interaction
|
|
260
|
-
A store will centralize your PCI state but also all mutations.
|
|
261
|
-
This means, this way you could replay everything a user did
|
|
262
|
-
And you can use Redux devtools to debug
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
// src/index.ts
|
|
266
|
-
const [state, dispatch] = useStore<StateModel, ActionType>((type, payload) => {});
|
|
267
|
-
|
|
268
|
-
dispatch<{ x: number }>("ADD_ACTION", { x: +inputValue });
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Let authors configure your PCI in QTI
|
|
272
|
-
Use properties in config.json to let authors configure your PCI
|
|
273
|
-
Also used in the TAO export for configuring PCIs in TAO
|
|
274
|
-
`// src/config.json`
|
|
275
|
-
```json
|
|
276
|
-
{
|
|
277
|
-
"buttonText": "Calculate",
|
|
278
|
-
"sum1" : "$1 * 14 + 1",
|
|
279
|
-
"sum2" : "$1 * 2 + 21",
|
|
280
|
-
"tableSize" : "4"
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
```ts
|
|
284
|
-
// src/index.ts
|
|
285
|
-
+ import configProps from "./config.json";
|
|
286
|
-
+ type PropTypes = typeof configProps;
|
|
287
|
-
|
|
288
|
-
// add to types
|
|
289
|
-
+ private config: Configuration<PropTypes>;
|
|
290
|
-
|
|
291
|
-
getInstance = (dom: HTMLElement, config: Configuration<PropTypes>, stateString: string) => {
|
|
292
|
-
+ config.properties = { ...configProps, ...config.properties }; // merge our props with players
|
|
293
|
-
+ this.config = config;
|
|
294
|
-
|
|
295
|
-
// destructure props for use in PCI
|
|
296
|
-
+ const { sum1, sum2, buttonText, tableSize } = config;
|
|
297
|
-
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Make use of existing react hooks
|
|
301
|
-
```ts
|
|
302
|
-
// src/useMousePosition
|
|
303
|
-
import { useEffect, useState } from "react";
|
|
304
|
-
|
|
305
|
-
export const useMousePosition = () => {
|
|
306
|
-
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
307
|
-
|
|
308
|
-
useEffect(() => {
|
|
309
|
-
const setPosFromEvent = (e) => setPosition({ x: e.clientX, y: e.clientY });
|
|
310
|
-
window.addEventListener("mousemove", setPosFromEvent);
|
|
311
|
-
return () => window.removeEventListener("mousemove", setPosFromEvent);
|
|
312
|
-
}, []);
|
|
313
|
-
|
|
314
|
-
return { clientX: position.x, clientY: position.y }
|
|
315
|
-
};
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
### Use in TAO
|
|
319
|
-
Tao adds some lifecycle methods which you can implement and we supply an extended interfaee on top of the IMS one.
|
|
320
|
-
|
|
321
|
-
More info, see our extension
|
|
322
|
-
- [github](
|
|
323
|
-
- [@citolab/tspci-tao](https://www.npmjs.com/package/@citolab/tspci-tao)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
## Roadmap
|
|
327
|
-
|
|
328
|
-
- Packager for Facet
|
|
329
|
-
- Packager for Trifork
|
|
330
|
-
- Create PCI with Vue
|
|
331
|
-
- Create PCI with Haunted
|
|
332
|
-
|
|
333
|
-
If you want your platform to be support, [contact us](mailto://getinspiredbycitolab@gmail.com)
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
## License
|
|
337
|
-
|
|
338
|
-
[GPLv3](
|
|
1
|
+
<h1>
|
|
2
|
+
A modern QTI-PCI development environment creating and testing portable custom interactions
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<img src="https://github.com/Citolab/tspci/blob/main/lib/tspci/tspci-development.png" alt="Typescript Pci Builder">
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
[Release notes](https://github.com/Citolab/tspci/blob/main/lib/tspci/release-notes.md)
|
|
10
|
+
|
|
11
|
+
## ✨ Features <a name="features"></a>
|
|
12
|
+
|
|
13
|
+
- Use modern tooling like typescript, preact, postcss and tailwind
|
|
14
|
+
- Build and bundle your library PCI using only a `package.json`
|
|
15
|
+
- Test and develop all your PCI states, configs, responses and lifecycle without uploading
|
|
16
|
+
- Develop in live server which directly updates on code changes
|
|
17
|
+
- Produces a single bundle .js file to use in any delivery engine that supports the latest IMS PCI standard
|
|
18
|
+
- 0 configuration TypeScript support
|
|
19
|
+
- Bundles all your css, images and json files.
|
|
20
|
+
- Postcss support, use CSS nesting out of the box.
|
|
21
|
+
- First class (p)react and tailwind support
|
|
22
|
+
- Extension for TAO, configuring icon, label, support for setting correct response and pci-properties
|
|
23
|
+
|
|
24
|
+
## 🔧 Installation & Setup
|
|
25
|
+
|
|
26
|
+
1️. **Install** by running: `npm i -D @citolab/tspci`
|
|
27
|
+
|
|
28
|
+
2️. **Set up** your `package.json`:
|
|
29
|
+
|
|
30
|
+
`// package.json`
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"name": "@citolab/hello-world",
|
|
34
|
+
"description": "Hello world pci",
|
|
35
|
+
"version": "1.0.0",
|
|
36
|
+
"main": "dist/index.js",
|
|
37
|
+
"types": "dist/types.d.ts",
|
|
38
|
+
"dependencies": {},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@citolab/tspci": "^1.5.6",
|
|
41
|
+
"@citolab/tspci-tao": "^1.0.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"dev": "tspci --dev",
|
|
45
|
+
"prod": "tspci"
|
|
46
|
+
},
|
|
47
|
+
"source": "src/index.ts"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Add the following PCI in the src folder `index.ts`
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
// src/index.ts
|
|
55
|
+
import { Configuration, IMSpci } from "@citolab/tspci";
|
|
56
|
+
import * as ctx from "qtiCustomInteractionContext";
|
|
57
|
+
|
|
58
|
+
class Pci implements IMSpci<{}> {
|
|
59
|
+
typeIdentifier = "HelloWorld"; // same as in package.json
|
|
60
|
+
shadowdom: ShadowRoot;
|
|
61
|
+
|
|
62
|
+
constructor() {
|
|
63
|
+
ctx && ctx.register(this);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getInstance = (dom: HTMLElement, config: Configuration<any>, state: string) => {
|
|
67
|
+
this.shadowdom = dom.attachShadow({ mode: "closed" });
|
|
68
|
+
this.render();
|
|
69
|
+
config.onready(this);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
private render = () => {
|
|
73
|
+
this.shadowdom.innerHTML = `<div>Hello-World</div>`;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
getResponse = () => {
|
|
77
|
+
return null;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
getState = () => null;
|
|
81
|
+
}
|
|
82
|
+
export default new Pci();
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Add this in your root project: `global.d.ts` file
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// global.d.ts
|
|
89
|
+
declare module "qtiCustomInteractionContext" {
|
|
90
|
+
const register: { register: (PortableInteraction) => void };
|
|
91
|
+
export = register;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Add a `tsconfig.json` to your project for type checking
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"compilerOptions": {
|
|
100
|
+
"declaration": true,
|
|
101
|
+
"lib": ["es6", "dom", "dom.iterable"],
|
|
102
|
+
"module": "es6",
|
|
103
|
+
"moduleResolution": "node",
|
|
104
|
+
"removeComments": true,
|
|
105
|
+
"sourceMap": true,
|
|
106
|
+
"strict": false,
|
|
107
|
+
"target": "es6",
|
|
108
|
+
"outDir": "./dist",
|
|
109
|
+
"jsx": "react-jsx",
|
|
110
|
+
"jsxImportSource": "preact",
|
|
111
|
+
"allowSyntheticDefaultImports": true,
|
|
112
|
+
"resolveJsonModule": true,
|
|
113
|
+
"esModuleInterop": true,
|
|
114
|
+
},
|
|
115
|
+
"include": ["**/*"],
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Try it out** by running `tspci --dev`.
|
|
120
|
+
|
|
121
|
+
### All CLI Options
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
Usage
|
|
125
|
+
$ tspci <command> [options]
|
|
126
|
+
|
|
127
|
+
Available Commands
|
|
128
|
+
--dev -d Start development server
|
|
129
|
+
--watch -w Only watch changes
|
|
130
|
+
--help -h Help about commandos
|
|
131
|
+
--target -t Build production for platform
|
|
132
|
+
|
|
133
|
+
Examples package.json scripts
|
|
134
|
+
$ "dev": "tspci --dev",
|
|
135
|
+
$ "prod": "tspci",
|
|
136
|
+
$ "watch": "tspci --watch",
|
|
137
|
+
$ "package-tao": "tspci --target tao"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 🛣 What's next
|
|
141
|
+
|
|
142
|
+
Use one of the [examples](https://github.com/Citolab/tspci-examples) to get a headstart
|
|
143
|
+
|
|
144
|
+
Or read further how we build our PCIs
|
|
145
|
+
|
|
146
|
+
Our prefered layout of our PCIs
|
|
147
|
+
```
|
|
148
|
+
your-pci-project
|
|
149
|
+
│ package.json // Definition of your PCI in a standard package.json, TAO adds some props
|
|
150
|
+
│ global.d.ts // Tell typescript qtiCustomInteractionContext is supplied later, adds a shim
|
|
151
|
+
│ tsconfig.json // Typescript configuration, also for type checking your code
|
|
152
|
+
│
|
|
153
|
+
└───src
|
|
154
|
+
│ │ config.json // Used to configure PCI, and in TAO for authors
|
|
155
|
+
│ │ index.ts // The api for the player and bootstraps your interaction
|
|
156
|
+
│ │ interaction.ts // the actual interaction, preferably a main preact component
|
|
157
|
+
│ │ store.ts // definition of the state and all possible state mutations of your pci
|
|
158
|
+
│ └───style.css // css styles, imported by your pci and possible to use tailwind classes
|
|
159
|
+
│
|
|
160
|
+
│ postcss.config.js // optionally adds postcss processing of css
|
|
161
|
+
│ tailwind.config.js // include tailwind classes
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
### Use JSX
|
|
166
|
+
Use (p)react in your PCI's to create interactions and bind your data to HTML
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
+ import { h, render } from "preact";
|
|
170
|
+
|
|
171
|
+
render(null, this.shadowdom);
|
|
172
|
+
|
|
173
|
+
render = () => {
|
|
174
|
+
+ render(null, this.shadowdom);
|
|
175
|
+
+ render(<Interaction config={this.config.properties} />, this.shadowdom);
|
|
176
|
+
};
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Bundle your css
|
|
180
|
+
Import and bundle css
|
|
181
|
+
Appending css to shadowdom will prevent styles leaking into your player
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
+ import style from "./style.css";
|
|
185
|
+
|
|
186
|
+
render = () => {
|
|
187
|
+
render(...
|
|
188
|
+
+ const css = document.createElement("style");
|
|
189
|
+
+ css.innerHTML = style;
|
|
190
|
+
+ this.shadowdom.appendChild(css);
|
|
191
|
+
render(...
|
|
192
|
+
};
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Use modern css
|
|
196
|
+
|
|
197
|
+
install autoprefixer
|
|
198
|
+
|
|
199
|
+
``` sh
|
|
200
|
+
npm i -D autoprefixer
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
add `postcss.config.js` with autoprefixer
|
|
204
|
+
|
|
205
|
+
// postcss.config.js
|
|
206
|
+
```js
|
|
207
|
+
module.exports = {
|
|
208
|
+
plugins: [
|
|
209
|
+
require('postcss-import'),
|
|
210
|
+
require('autoprefixer'),
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Modern UI with existing classes
|
|
216
|
+
|
|
217
|
+
add tailwind to `postcss.config.js`
|
|
218
|
+
and add a `tailwind.config.js`
|
|
219
|
+
|
|
220
|
+
```js
|
|
221
|
+
// postcss.config.js
|
|
222
|
+
plugins: [
|
|
223
|
+
+ require('tailwindcss/nesting'),
|
|
224
|
+
+ require('tailwindcss'),
|
|
225
|
+
];
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
// tailwind.config.js
|
|
230
|
+
module.exports = {
|
|
231
|
+
content: ["./src/**/*.{html,js,ts,jsx,tsx}", "./*.xml"], // html/javascript and typescript, and everything in pci markup
|
|
232
|
+
theme: {
|
|
233
|
+
extend: {},
|
|
234
|
+
},
|
|
235
|
+
plugins: [],
|
|
236
|
+
};
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Bundle all your images
|
|
240
|
+
Images are bundled in the js by importing them in code:
|
|
241
|
+
imports JPG, PNG, GIF, SVG, and WebP files
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
import procenten from "./assets/procenten.png";
|
|
245
|
+
<img src={procenten} />;
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Create advanced PCIs with 3D libraries
|
|
249
|
+
For example, import threejs to create 3D pci's
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
// src/interaction.ts
|
|
253
|
+
import * as THREE from "three";
|
|
254
|
+
|
|
255
|
+
class VoxelPainterClass {
|
|
256
|
+
private scene: THREE.Scene;
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Record user interaction
|
|
260
|
+
A store will centralize your PCI state but also all mutations.
|
|
261
|
+
This means, this way you could replay everything a user did
|
|
262
|
+
And you can use Redux devtools to debug
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
// src/index.ts
|
|
266
|
+
const [state, dispatch] = useStore<StateModel, ActionType>((type, payload) => {});
|
|
267
|
+
|
|
268
|
+
dispatch<{ x: number }>("ADD_ACTION", { x: +inputValue });
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Let authors configure your PCI in QTI
|
|
272
|
+
Use properties in config.json to let authors configure your PCI
|
|
273
|
+
Also used in the TAO export for configuring PCIs in TAO
|
|
274
|
+
`// src/config.json`
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"buttonText": "Calculate",
|
|
278
|
+
"sum1" : "$1 * 14 + 1",
|
|
279
|
+
"sum2" : "$1 * 2 + 21",
|
|
280
|
+
"tableSize" : "4"
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
```ts
|
|
284
|
+
// src/index.ts
|
|
285
|
+
+ import configProps from "./config.json";
|
|
286
|
+
+ type PropTypes = typeof configProps;
|
|
287
|
+
|
|
288
|
+
// add to types
|
|
289
|
+
+ private config: Configuration<PropTypes>;
|
|
290
|
+
|
|
291
|
+
getInstance = (dom: HTMLElement, config: Configuration<PropTypes>, stateString: string) => {
|
|
292
|
+
+ config.properties = { ...configProps, ...config.properties }; // merge our props with players
|
|
293
|
+
+ this.config = config;
|
|
294
|
+
|
|
295
|
+
// destructure props for use in PCI
|
|
296
|
+
+ const { sum1, sum2, buttonText, tableSize } = config;
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Make use of existing react hooks
|
|
301
|
+
```ts
|
|
302
|
+
// src/useMousePosition
|
|
303
|
+
import { useEffect, useState } from "react";
|
|
304
|
+
|
|
305
|
+
export const useMousePosition = () => {
|
|
306
|
+
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
const setPosFromEvent = (e) => setPosition({ x: e.clientX, y: e.clientY });
|
|
310
|
+
window.addEventListener("mousemove", setPosFromEvent);
|
|
311
|
+
return () => window.removeEventListener("mousemove", setPosFromEvent);
|
|
312
|
+
}, []);
|
|
313
|
+
|
|
314
|
+
return { clientX: position.x, clientY: position.y }
|
|
315
|
+
};
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Use in TAO
|
|
319
|
+
Tao adds some lifecycle methods which you can implement and we supply an extended interfaee on top of the IMS one.
|
|
320
|
+
|
|
321
|
+
More info, see our extension
|
|
322
|
+
- [github](https://github.com/Citolab/tspci/blob/main/lib/tspci-tao)
|
|
323
|
+
- [@citolab/tspci-tao](https://www.npmjs.com/package/@citolab/tspci-tao)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
## Roadmap
|
|
327
|
+
|
|
328
|
+
- Packager for Facet
|
|
329
|
+
- Packager for Trifork
|
|
330
|
+
- Create PCI with Vue
|
|
331
|
+
- Create PCI with Haunted
|
|
332
|
+
|
|
333
|
+
If you want your platform to be support, [contact us](mailto://getinspiredbycitolab@gmail.com)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
## License
|
|
337
|
+
|
|
338
|
+
[GPLv3](https://github.com/Citolab/tspci/blob/main/LICENSE)
|