├── .github
└── dependabot.yml
├── .gitignore
├── README.md
├── trivia-game-react
├── .editorconfig
├── .gitignore
├── .node-version
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── README.md
├── babel-plugin-macros.config.js
├── config.json
├── cypress.json
├── cypress
│ ├── fixtures
│ │ └── example.json
│ ├── plugins
│ │ └── index.js
│ ├── support
│ │ ├── commands.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ └── webpack.config.js
├── netlify.toml
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.test.tsx
│ ├── App.tsx
│ ├── components
│ │ ├── Actions.ts
│ │ ├── Button.ts
│ │ ├── Container.ts
│ │ ├── CorrectIcon.tsx
│ │ ├── GlobalStyle.ts
│ │ ├── TextContainer.ts
│ │ ├── Typography.ts
│ │ ├── WrongIcon.tsx
│ │ ├── __tests__
│ │ │ ├── Actions.tsx
│ │ │ ├── Button.tsx
│ │ │ ├── Container.tsx
│ │ │ ├── CorrectIcon.tsx
│ │ │ ├── GlobalStyle.tsx
│ │ │ ├── TextContainer.tsx
│ │ │ ├── Typography.tsx
│ │ │ ├── WrongIcon.tsx
│ │ │ └── __snapshots__
│ │ │ │ ├── Actions.tsx.snap
│ │ │ │ ├── Button.tsx.snap
│ │ │ │ ├── Container.tsx.snap
│ │ │ │ ├── CorrectIcon.tsx.snap
│ │ │ │ ├── GlobalStyle.tsx.snap
│ │ │ │ ├── TextContainer.tsx.snap
│ │ │ │ ├── Typography.tsx.snap
│ │ │ │ └── WrongIcon.tsx.snap
│ │ └── index.ts
│ ├── index.tsx
│ ├── machine.ts
│ ├── react-app-env.d.ts
│ ├── screens
│ │ ├── Failure.tsx
│ │ ├── Loading.tsx
│ │ ├── Quiz.tsx
│ │ ├── Results.tsx
│ │ ├── Welcome.tsx
│ │ └── index.ts
│ ├── setupTests.ts
│ ├── tailwind.config.js
│ ├── types.ts
│ └── utils
│ │ ├── fetchAndNormalizeQuizData.ts
│ │ ├── fetchQuizData.ts
│ │ ├── index.ts
│ │ └── normalizeQuizData.ts
├── tsconfig.json
└── yarn.lock
├── trivia-game-svelte
├── .editorconfig
├── .gitignore
├── .node-version
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── README.md
├── netlify.toml
├── package.json
├── postcss.config.js
├── public
│ ├── favicon.png
│ └── index.html
├── rollup.config.js
├── rollup_start_dev.js
├── src
│ ├── App.svelte
│ ├── components
│ │ ├── Actions.svelte
│ │ ├── Button.svelte
│ │ ├── Container.svelte
│ │ ├── CorrectIcon.svelte
│ │ ├── GlobalStyle.svelte
│ │ ├── H1.svelte
│ │ ├── P.svelte
│ │ ├── TextContainer.svelte
│ │ └── WrongIcon.svelte
│ ├── machine.js
│ ├── main.js
│ ├── screens
│ │ ├── Failure.svelte
│ │ ├── Loading.svelte
│ │ ├── Quiz.svelte
│ │ ├── Results.svelte
│ │ └── Welcome.svelte
│ └── utils
│ │ ├── fetchAndNormalizeQuizData.js
│ │ ├── fetchQuizData.js
│ │ ├── index.js
│ │ └── normalizeQuizData.js
├── tailwind.config.js
└── yarn.lock
└── trivia-game-vue
├── .editorconfig
├── .gitignore
├── .node-version
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── README.md
├── babel.config.js
├── netlify.toml
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── assets
│ └── tailwind.css
├── components
│ ├── Actions.vue
│ ├── Button.vue
│ ├── Container.vue
│ ├── CorrectIcon.vue
│ ├── H1.vue
│ ├── P.vue
│ ├── TextContainer.vue
│ ├── Toggle.vue
│ └── WrongIcon.vue
├── machine.js
├── main.js
├── screens
│ ├── Failure.vue
│ ├── Loading.vue
│ ├── Quiz.vue
│ ├── Results.vue
│ └── Welcome.vue
└── utils
│ ├── fetchAndNormalizeQuizData.js
│ ├── fetchQuizData.js
│ ├── index.js
│ └── normalizeQuizData.js
└── yarn.lock
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/trivia-game-svelte"
5 | schedule:
6 | interval: daily
7 | time: "10:00"
8 | open-pull-requests-limit: 10
9 | - package-ecosystem: npm
10 | directory: "/trivia-game-vue"
11 | schedule:
12 | interval: daily
13 | time: "10:00"
14 | open-pull-requests-limit: 10
15 | - package-ecosystem: npm
16 | directory: "/trivia-game-react"
17 | schedule:
18 | interval: daily
19 | time: "10:00"
20 | open-pull-requests-limit: 10
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xstate-examples
2 |
3 | ## Explanation
4 | This repo serves as a resource for any developer curious about [state machines](https://statecharts.github.io/what-is-a-state-machine.html) and [statecharts](https://statecharts.github.io). I've heard developers that _want_ to use state machines, but have not found the "perfect reason" to utilize them. Now the "perfect reason" is easier to find. 😉
5 |
6 | ## Repository Structure
7 | - Each example is in it's own directory.
8 | - Each example is a small application created with [Create React App](https://create-react-app.dev)/[vue-cli](https://cli.vuejs.org/)/[Svelte Template](https://github.com/sveltejs/template), [Xstate](https://xstate.js.org), [tailwind](https://tailwindcss.com), [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)/[Vue Testing Library](https://testing-library.com/docs/vue-testing-library/intro)/[Svelte Testing Library](https://testing-library.com/docs/svelte-testing-library/intro), and [cypress](https://www.cypress.io).
9 | - Each example has a README with link to the [xstate visualization tool](https://xstate.js.org/viz/) for that example's state machine/statechart.
10 | - Each example uses [model-based testing](https://css-tricks.com/model-based-testing-in-react-with-state-machines/) and state machine/statechart best practices.
11 |
12 | ## Current Examples
13 | - Trivia Game [React](/trivia-game-react) | [Vue](/trivia-game-vue) | [Svelte](/trivia-game-svelte)
14 |
15 | ## Future Examples
16 | - React Native "Simon Says" game
17 | - Authentication flow
18 | - Welcome/walkthrough flow
19 | - Todos
20 | - Ticket selection and payment flow
21 | - Stepped form/wizard
22 | - Medium-like article creation/updating
23 |
24 | ## Examples Showing Specific State Machine Concepts
25 | - [Guards](https://xstate.js.org/docs/guides/guards.html): Trivia Game [React](/trivia-game-react/src/machine.ts#L47) | [Vue](/trivia-game-vue/src/machine.js#L46) | [Svelte](/trivia-game-svelte/src/machine.js#L46)
26 | - [Transient Transitions](https://xstate.js.org/docs/guides/transitions.html#transient-transitions): Trivia Game [React](/trivia-game-react/src/machine.ts#L44-L48) | [Vue](/trivia-game-vue/src/machine.js#L43-L47) | [Svelte](/trivia-game-svelte/src/machine.js#L43-L47)
27 | - [Invoking Services (Promises)](https://xstate.js.org/docs/guides/communication.html#the-invoke-property): Trivia Game [React](/trivia-game-react/src/machine.ts#L22-L34) | [Vue](/trivia-game-vue/src/machine.js#L21-L33) | [Svelte](/trivia-game-svelte/src/machine.js#L21-L33)
28 |
29 | ## Handy Resources
30 | - [Xstate documentation](https://xstate.js.org)
31 | - [Statecharts community](https://spectrum.chat/statecharts)
32 | - [World of Statecharts](https://statecharts.github.io)
33 |
--------------------------------------------------------------------------------
/trivia-game-react/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | insert_final_newline = true
9 |
10 |
--------------------------------------------------------------------------------
/trivia-game-react/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/trivia-game-react/.node-version:
--------------------------------------------------------------------------------
1 | 10.16.3
2 |
3 |
--------------------------------------------------------------------------------
/trivia-game-react/.nvmrc:
--------------------------------------------------------------------------------
1 | 10.16.3
2 |
3 |
--------------------------------------------------------------------------------
/trivia-game-react/.prettierignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 | /.pnp
4 | .pnp.js
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 | /public
12 |
13 | # misc
14 | *.DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .en.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
24 | .cache
25 |
26 |
--------------------------------------------------------------------------------
/trivia-game-react/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "avoid",
3 | "bracketSpacing": false,
4 | "htmlWhitespaceSensitivity": "css",
5 | "insertPragma": false,
6 | "jsxBracketSameLine": false,
7 | "jsxSingleQuote": true,
8 | "printWidth": 80,
9 | "proseWrap": "always",
10 | "requirePragma": false,
11 | "semi": false,
12 | "singleQuote": true,
13 | "tabWidth": 2,
14 | "trailingComma": "all",
15 | "useTabs": false
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/trivia-game-react/README.md:
--------------------------------------------------------------------------------
1 | # Trivia Game
2 |
3 | This example showcases several state machine concepts including guards,
4 | transient functions, and invoking services.
5 |
6 | [Trivia Game machine visualized](https://xstate.js.org/viz/?gist=3abe97296e6d6cebcbda9c903d6da068)
7 |
8 | ## Running Locally
9 |
10 | 1. After cloning and navigating into the `trivia-game-react` directory, execute:
11 |
12 | ```
13 | yarn && yarn test
14 | ```
15 |
16 | or
17 |
18 | ```
19 | npm install && npm t
20 | ```
21 |
22 | This will install dependencies and run tests to verify no issues
23 |
24 | 2. Start the application by executing:
25 |
26 | ```
27 | yarn start
28 | ```
29 |
30 | or
31 |
32 | ```
33 | npm start
34 | ```
35 |
--------------------------------------------------------------------------------
/trivia-game-react/babel-plugin-macros.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | styledComponents: {
3 | displayName: true,
4 | },
5 | tailwind: {
6 | config: './src/tailwind.config.js',
7 | styled: 'styled-components/macro',
8 | },
9 | }
10 |
--------------------------------------------------------------------------------
/trivia-game-react/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "reporterEnabled": "spec, mocha-junit-reporter",
3 | "mochaJunitReporterReporterOptions": {
4 | "mochaFile": "cypress/results/junit/results.[hash].xml"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "http://localhost:3000",
3 | "integrationFolder": "cypress/e2e",
4 | "reporter": "mocha-multi-reporters",
5 | "reporterOptions": {
6 | "configFile": "config.json"
7 | },
8 | "supportFile": "cypress/support/index.ts",
9 | "ignoreTestFiles": "**/*.{js,ts}"
10 | }
11 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example plugins/index.js can be used to load plugins
3 | //
4 | // You can change the location of this file or turn off loading
5 | // the plugins file with the 'pluginsFile' configuration option.
6 | //
7 | // You can read more here:
8 | // https://on.cypress.io/plugins-guide
9 | // ***********************************************************
10 |
11 | // This function is called when a project is opened or re-opened (e.g. due to
12 | // the project's config changing)
13 |
14 | const wp = require('@cypress/webpack-preprocessor')
15 |
16 | module.exports = on => {
17 | const options = {
18 | webpackOptions: require('../webpack.config'),
19 | }
20 | on('file:preprocessor', wp(options))
21 | // `on` is used to hook into various events Cypress emits
22 | // `config` is the resolved Cypress config
23 | }
24 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress/support/commands.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************
2 | // This example commands.js shows you how to
3 | // create various custom commands and overwrite
4 | // existing commands.
5 | //
6 | // For more comprehensive examples of custom
7 | // commands please read more here:
8 | // https://on.cypress.io/custom-commands
9 | // ***********************************************
10 | //
11 | //
12 | // -- This is a parent command --
13 | // Cypress.Commands.add("login", (email, password) => { ... })
14 | //
15 | //
16 | // -- This is a child command --
17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
18 | //
19 | //
20 | // -- This is a dual command --
21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
22 | //
23 | //
24 | // -- This is will overwrite an existing command --
25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
26 |
27 | // add a custom command cy.foo()
28 | Cypress.Commands.add('foo', () => 'foo')
29 |
30 | // see more example of adding custom commands to Cypress TS interface
31 | // in https://github.com/cypress-io/add-cypress-custom-command-in-typescript
32 | // add new command to the existing Cypress interface
33 | // tslint:disable-next-line no-namespace
34 | declare namespace Cypress {
35 | // tslint:disable-next-line interface-name
36 | interface Chainable {
37 | foo: () => string
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress/support/index.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import '@testing-library/cypress/add-commands'
18 | import './commands'
19 |
20 | // Alternatively you can use CommonJS syntax:
21 | // require('./commands')
22 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "../node_modules",
4 | "lib": ["es5", "dom"],
5 | "module": "commonjs",
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "target": "es5",
9 | "types": ["cypress", "@testing-library/cypress"]
10 | },
11 | "include": ["**/*.ts"]
12 | }
13 |
--------------------------------------------------------------------------------
/trivia-game-react/cypress/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | resolve: {
3 | extensions: ['.ts', '.js'],
4 | },
5 | module: {
6 | rules: [
7 | {
8 | test: /\.ts$/,
9 | exclude: [/node_modules/],
10 | use: [
11 | {
12 | loader: 'ts-loader',
13 | },
14 | ],
15 | },
16 | {
17 | test: /\.feature$/,
18 | use: [
19 | {
20 | loader: 'cypress-cucumber-preprocessor/loader',
21 | },
22 | ],
23 | },
24 | ],
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/trivia-game-react/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | base = ""
3 | command = "yarn build"
4 | publish = "/build"
5 |
--------------------------------------------------------------------------------
/trivia-game-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trivia-game",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "react-scripts build",
7 | "commit": "git-cz",
8 | "cy:open": "cypress open",
9 | "cy:run": "cypress run",
10 | "format": "yarn prettier --write",
11 | "prettier": "prettier \"**/*.+(js|jsx|json|yml|yaml|css|less|scss|ts|tsx|md|graphql|mdx)\"",
12 | "preserve": "yarn build",
13 | "serve": "serve -s build -l 3000",
14 | "setup": "yarn && yarn validate",
15 | "start": "react-scripts start",
16 | "test": "is-ci \"test:ci\" \"test:watch\"",
17 | "test:ci": "react-scripts test --ci --coverage --runInBand --reporters=default --reporters=jest-junit",
18 | "test:coverage": "react-scripts test --coverage",
19 | "test:e2e": "is-ci \"test:e2e:run\" \"test:e2e:dev\"",
20 | "test:e2e:dev": "start-server-and-test start http://localhost:3000 cy:open",
21 | "test:e2e:run": "start-server-and-test serve http://localhost:3000 cy:run",
22 | "test:watch": "react-scripts test",
23 | "validate": "lint-staged"
24 | },
25 | "dependencies": {
26 | "@xstate/react": "5.0.5",
27 | "lean-he": "2.1.2",
28 | "react": "18.3.1",
29 | "react-dom": "19.1.0",
30 | "react-scripts": "5.0.1",
31 | "styled-components": "6.1.18",
32 | "tailwind.macro": "1.0.0-alpha.10",
33 | "typescript": "5.8.3",
34 | "xstate": "5.19.4"
35 | },
36 | "devDependencies": {
37 | "@testing-library/cypress": "10.0.3",
38 | "@testing-library/jest-dom": "6.6.3",
39 | "@testing-library/react": "15.0.7",
40 | "@types/jest": "29.5.14",
41 | "@types/node": "22.15.30",
42 | "@types/react": "18.3.13",
43 | "@types/react-dom": "19.1.6",
44 | "@types/styled-components": "5.1.34",
45 | "@xstate/graph": "3.0.4",
46 | "@xstate/test": "0.5.1",
47 | "commitizen": "4.3.1",
48 | "cypress": "14.4.1",
49 | "cz-conventional-changelog": "3.3.0",
50 | "husky": "9.1.7",
51 | "is-ci-cli": "2.2.0",
52 | "jest-axe": "10.0.0",
53 | "jest-junit": "16.0.0",
54 | "jest-styled-components": "beta",
55 | "lint-staged": "16.1.0",
56 | "mocha": "11.5.0",
57 | "mocha-junit-reporter": "2.2.1",
58 | "mocha-multi-reporters": "1.5.1",
59 | "prettier": "3.5.3",
60 | "serve": "14.2.4",
61 | "start-server-and-test": "2.0.12"
62 | },
63 | "eslintConfig": {
64 | "extends": "react-app"
65 | },
66 | "browserslist": {
67 | "production": [
68 | ">0.2%",
69 | "not dead",
70 | "not op_mini all"
71 | ],
72 | "development": [
73 | "last 1 chrome version",
74 | "last 1 firefox version",
75 | "last 1 safari version"
76 | ]
77 | },
78 | "husky": {
79 | "hooks": {
80 | "pre-commit": "yarn validate"
81 | }
82 | },
83 | "config": {
84 | "commitizen": {
85 | "path": "cz-conventional-changelog"
86 | }
87 | },
88 | "repository": {
89 | "type": "git",
90 | "url": "https://github.com/DevanB/xstate-examples/trivia-game"
91 | },
92 | "lint-staged": {
93 | "**/*.+(js|jsx|json|yml|yaml|css|less|scss|ts|tsx|md|graphql|mdx)": [
94 | "prettier --write",
95 | "git add"
96 | ]
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/trivia-game-react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-react/public/favicon.ico
--------------------------------------------------------------------------------
/trivia-game-react/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/trivia-game-react/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-react/public/logo192.png
--------------------------------------------------------------------------------
/trivia-game-react/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-react/public/logo512.png
--------------------------------------------------------------------------------
/trivia-game-react/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/trivia-game-react/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/trivia-game-react/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {cleanup, fireEvent, render} from '@testing-library/react'
3 | import App from './App'
4 | import {createModel} from '@xstate/test'
5 | import {assign, Machine} from 'xstate'
6 |
7 | const testMachine = Machine(
8 | {
9 | id: 'Machine',
10 | initial: 'welcome',
11 | context: {
12 | currentQuestion: 0,
13 | currentQuestionDisplay: 1,
14 | questions: [],
15 | totalCorrectAnswers: 0,
16 | },
17 | states: {
18 | welcome: {
19 | on: {
20 | START_QUIZ: 'loading',
21 | },
22 | meta: {
23 | test: ({getByTestId}: {getByTestId: any}) => {
24 | expect(getByTestId('welcome-header'))
25 | },
26 | },
27 | },
28 | loading: {
29 | on: {
30 | SUCCESS: {
31 | target: 'quiz',
32 | actions: 'resolveData',
33 | },
34 | FAILURE: 'failure',
35 | },
36 | meta: {
37 | test: ({getByTestId}: {getByTestId: any}) => {
38 | expect(getByTestId('loading-header'))
39 | },
40 | },
41 | },
42 | failure: {
43 | on: {
44 | RETRY: 'loading',
45 | START_OVER: 'welcome',
46 | },
47 | meta: {
48 | test: ({getByTestId}: {getByTestId: any}) => {
49 | expect(getByTestId('failure-header'))
50 | },
51 | },
52 | },
53 | quiz: {
54 | on: {
55 | '': {
56 | target: 'results',
57 | cond: 'allQuestionsAnswered',
58 | },
59 | ANSWER_FALSE: {
60 | actions: 'updateAnswer',
61 | },
62 | ANSWER_TRUE: {
63 | actions: 'updateAnswer',
64 | },
65 | },
66 | meta: {
67 | test: ({getByTestId}: {getByTestId: any}) => {
68 | expect(getByTestId('quiz-header'))
69 | },
70 | },
71 | },
72 | results: {
73 | on: {
74 | PLAY_AGAIN: 'welcome',
75 | },
76 | meta: {
77 | test: ({getByTestId}: {getByTestId: any}) => {
78 | expect(getByTestId('results-header'))
79 | },
80 | },
81 | exit: 'resetGame',
82 | },
83 | },
84 | },
85 | {
86 | actions: {
87 | resetGame: assign({
88 | currentQuestion: 0,
89 | currentQuestionDisplay: 1,
90 | questions: [],
91 | totalCorrectAnswers: 0,
92 | }),
93 | resolveData: assign({
94 | questions: [
95 | {
96 | category: 'Entertainment: Video Games',
97 | question: 'Unturned originally started as a Roblox game.',
98 | correctAnswer: true,
99 | userAnswer: undefined,
100 | correct: undefined,
101 | },
102 | {
103 | category: 'Entertainment: Comics',
104 | question:
105 | 'In the comic book "Archie", Betty is friends with Veronica because she is rich.',
106 | correctAnswer: false,
107 | userAnswer: undefined,
108 | correct: undefined,
109 | },
110 | {
111 | category: 'Entertainment: Video Games',
112 | question:
113 | 'In Undertale, having a "Fun Value" set to 56-57 will play the "Wrong Number Song Call".',
114 | correctAnswer: false,
115 | userAnswer: undefined,
116 | correct: undefined,
117 | },
118 | {
119 | category: 'Entertainment: Video Games',
120 | question:
121 | 'TF2: Sentry rocket damage falloff is calculated ba…try and the enemy, not the engineer and the enemy',
122 | correctAnswer: false,
123 | userAnswer: undefined,
124 | correct: undefined,
125 | },
126 | {
127 | category: 'Mythology',
128 | question:
129 | 'Rannamaari was a sea demon that haunted the people…ased monthly with the sacrifice of a virgin girl.',
130 | correctAnswer: true,
131 | userAnswer: undefined,
132 | correct: undefined,
133 | },
134 | {
135 | category: 'General Knowledge',
136 | question: 'In Scandinavian languages, the letter Å means river.',
137 | correctAnswer: true,
138 | userAnswer: undefined,
139 | correct: undefined,
140 | },
141 | {
142 | category: 'Entertainment: Music',
143 | question: 'The band STRFKR was also briefly known as Pyramiddd.',
144 | correctAnswer: true,
145 | userAnswer: undefined,
146 | correct: undefined,
147 | },
148 | {
149 | category: 'Politics',
150 | question:
151 | "Nazi Germany surrendered on Harry Truman's birthday while he was president.",
152 | correctAnswer: true,
153 | userAnswer: undefined,
154 | correct: undefined,
155 | },
156 | {
157 | category: 'Celebrities',
158 | question:
159 | "Lady Gaga's real name is Stefani Joanne Angelina Germanotta.",
160 | correctAnswer: true,
161 | userAnswer: undefined,
162 | correct: undefined,
163 | },
164 | {
165 | category: 'History',
166 | question:
167 | "During the Winter War, the amount of Soviet Union … went missing was five times more than Finland's.",
168 | correctAnswer: true,
169 | userAnswer: undefined,
170 | correct: undefined,
171 | },
172 | ],
173 | }),
174 | updateAnswer: assign((ctx: any, event: any) => ({
175 | questions: [
176 | ...ctx.questions.slice(0, ctx.currentQuestion),
177 | {
178 | ...ctx.questions[ctx.currentQuestion],
179 | userAnswer: event.answer,
180 | correct:
181 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer,
182 | },
183 | ...ctx.questions.slice(ctx.currentQuestion + 1),
184 | ],
185 | totalCorrectAnswers:
186 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer
187 | ? (ctx.totalCorrectAnswers += 1)
188 | : ctx.totalCorrectAnswers,
189 | currentQuestion: ctx.currentQuestion += 1,
190 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1,
191 | })),
192 | },
193 | guards: {
194 | allQuestionsAnswered: ctx => {
195 | return (
196 | ctx.questions.filter(
197 | (question: any) => question.correct !== undefined,
198 | ).length === ctx.questions.length && true
199 | )
200 | },
201 | },
202 | },
203 | )
204 |
205 | describe('trivia app', () => {
206 | const testModel = createModel(testMachine).withEvents({
207 | START_QUIZ: ({getByTestId}: {getByTestId: any}) => {
208 | fireEvent.click(getByTestId('begin-button'))
209 | },
210 | FAILURE: () => {},
211 | SUCCESS: () => {},
212 | RETRY: ({getByTestId}: {getByTestId: any}) => {
213 | fireEvent.click(getByTestId('retry-button'))
214 | },
215 | START_OVER: ({getByTestId}: {getByTestId: any}) => {
216 | fireEvent.click(getByTestId('start-over-button'))
217 | },
218 | ANSWER_TRUE: ({getByTestId}: {getByTestId: any}) => {
219 | fireEvent.click(getByTestId('answer-true-button'))
220 | },
221 | ANSWER_FALSE: ({getByTestId}: {getByTestId: any}) => {
222 | fireEvent.click(getByTestId('answer-false-button'))
223 | },
224 | PLAY_AGAIN: ({getByTestId}: {getByTestId: any}) => {
225 | fireEvent.click(getByTestId('play-again-button'))
226 | },
227 | })
228 |
229 | const testPlans = testModel.getSimplePathPlans()
230 | testPlans.forEach((plan: any) => {
231 | describe(plan.description, () => {
232 | afterEach(cleanup)
233 | plan.paths.forEach((path: any) => {
234 | it(path.description, () => {
235 | const rendered = render()
236 | return path.test(rendered)
237 | })
238 | })
239 | })
240 | })
241 |
242 | it('coverage', () => {
243 | testModel.testCoverage()
244 | })
245 | })
246 |
--------------------------------------------------------------------------------
/trivia-game-react/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {useMachine} from '@xstate/react'
3 | import tw from 'tailwind.macro'
4 | import {GlobalStyle} from './components'
5 | import machine from './machine'
6 | import {
7 | Failure as FailureScreen,
8 | Loading as LoadingScreen,
9 | Quiz as QuizScreen,
10 | Results as ResultsScreen,
11 | Welcome as WelcomeScreen,
12 | } from './screens'
13 |
14 | const AppWrapper = tw.div`min-h-screen min-w-screen h-screen w-screen flex justify-center items-center bg-gray-200`
15 | const Main = tw.main`z-20 w-11/12 h-auto max-h-screen overflow-y-scroll m-4 flex flex-col items-center bg-white rounded shadow md:w-3/4 lg:w-1/2 md:m-0`
16 |
17 | function App() {
18 | const [current, send] = useMachine(machine)
19 |
20 | const renderScreen = () => {
21 | switch (current.value) {
22 | case 'welcome':
23 | return send('START_QUIZ')} />
24 | case 'loading':
25 | return
26 | case 'failure':
27 | return (
28 | send('RETRY')}
30 | startOver={() => send('START_OVER')}
31 | />
32 | )
33 | case 'quiz':
34 | return (
35 | send({type: 'ANSWER_FALSE', answer: false})}
37 | answerTrue={() => send({type: 'ANSWER_TRUE', answer: true})}
38 | currentQuestionNumber={current.context.currentQuestionDisplay}
39 | question={
40 | current.context.questions[current.context.currentQuestion]
41 | }
42 | totalQuestions={current.context.questions.length}
43 | />
44 | )
45 | case 'results':
46 | return (
47 | send('PLAY_AGAIN')}
49 | questions={current.context.questions}
50 | totalCorrectAnswers={current.context.totalCorrectAnswers}
51 | totalQuestions={current.context.questions.length}
52 | />
53 | )
54 | default:
55 | return null
56 | }
57 | }
58 |
59 | return (
60 |
61 |
62 | {renderScreen()}
63 |
64 | )
65 | }
66 |
67 | export default App
68 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/Actions.ts:
--------------------------------------------------------------------------------
1 | import tw from 'tailwind.macro'
2 |
3 | export const Actions = tw.div`flex flex-col md:flex-row w-full md:w-1/2 justify-around`
4 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/Button.ts:
--------------------------------------------------------------------------------
1 | import tw from 'tailwind.macro'
2 |
3 | export const Button = tw.button`mt-4 mb-2 md:mt-0 md:mb-0 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded`
4 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/Container.ts:
--------------------------------------------------------------------------------
1 | import tw from 'tailwind.macro'
2 |
3 | export const Container = tw.div`flex flex-col justify-between items-center w-full h-full p-5`
4 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/CorrectIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import tw from 'tailwind.macro'
3 |
4 | const CheckmarkSvg = () => (
5 |
8 | )
9 |
10 | const Icon = tw.div`h-4 w-4 text-green-500 hover:text-green-700`
11 |
12 | export const CorrectIcon = () => (
13 |
14 |
15 |
16 | )
17 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/GlobalStyle.ts:
--------------------------------------------------------------------------------
1 | import {createGlobalStyle} from 'styled-components'
2 |
3 | export const GlobalStyle = createGlobalStyle`
4 | html {
5 | line-height: 1.15;
6 | -webkit-text-size-adjust: 100%;
7 | }
8 | body {
9 | margin: 0;
10 | }
11 | main {
12 | display: block;
13 | }
14 | h1 {
15 | font-size: 2em;
16 | margin: 0.67em 0;
17 | }
18 | hr {
19 | box-sizing: content-box;
20 | height: 0;
21 | overflow: visible;
22 | }
23 | pre {
24 | font-family: monospace, monospace;
25 | font-size: 1em;
26 | }
27 | a {
28 | background-color: transparent;
29 | }
30 | abbr[title] {
31 | border-bottom: none;
32 | text-decoration: underline;
33 | -webkit-text-decoration: underline dotted;
34 | text-decoration: underline dotted;
35 | }
36 | b,
37 | strong {
38 | font-weight: bolder;
39 | }
40 | code,
41 | kbd,
42 | samp {
43 | font-family: monospace, monospace;
44 | font-size: 1em;
45 | }
46 | small {
47 | font-size: 80%;
48 | }
49 | sub,
50 | sup {
51 | font-size: 75%;
52 | line-height: 0;
53 | position: relative;
54 | vertical-align: baseline;
55 | }
56 | sub {
57 | bottom: -0.25em;
58 | }
59 | sup {
60 | top: -0.5em;
61 | }
62 | img {
63 | border-style: none;
64 | }
65 | button,
66 | input,
67 | optgroup,
68 | select,
69 | textarea {
70 | font-family: inherit;
71 | font-size: 100%;
72 | line-height: 1.15;
73 | margin: 0;
74 | }
75 | button,
76 | input {
77 | overflow: visible;
78 | }
79 | button,
80 | select {
81 | text-transform: none;
82 | }
83 | button,
84 | [type="button"],
85 | [type="reset"],
86 | [type="submit"] {
87 | -webkit-appearance: button;
88 | }
89 | button::-moz-focus-inner,
90 | [type="button"]::-moz-focus-inner,
91 | [type="reset"]::-moz-focus-inner,
92 | [type="submit"]::-moz-focus-inner {
93 | border-style: none;
94 | padding: 0;
95 | }
96 | button:-moz-focusring,
97 | [type="button"]:-moz-focusring,
98 | [type="reset"]:-moz-focusring,
99 | [type="submit"]:-moz-focusring {
100 | outline: 1px dotted ButtonText;
101 | }
102 | fieldset {
103 | padding: 0.35em 0.75em 0.625em;
104 | }
105 | legend {
106 | box-sizing: border-box;
107 | color: inherit;
108 | display: table;
109 | max-width: 100%;
110 | padding: 0;
111 | white-space: normal;
112 | }
113 | progress {
114 | vertical-align: baseline;
115 | }
116 | textarea {
117 | overflow: auto;
118 | }
119 | [type="checkbox"],
120 | [type="radio"] {
121 | box-sizing: border-box;
122 | padding: 0;
123 | }
124 | [type="number"]::-webkit-inner-spin-button,
125 | [type="number"]::-webkit-outer-spin-button {
126 | height: auto;
127 | }
128 | [type="search"] {
129 | -webkit-appearance: textfield;
130 | outline-offset: -2px;
131 | }
132 | [type="search"]::-webkit-search-decoration {
133 | -webkit-appearance: none;
134 | }
135 | ::-webkit-file-upload-button {
136 | -webkit-appearance: button;
137 | font: inherit;
138 | }
139 | details {
140 | display: block;
141 | }
142 | summary {
143 | display: list-item;
144 | }
145 | template {
146 | display: none;
147 | }
148 | [hidden] {
149 | display: none;
150 | }
151 | html {
152 | box-sizing: border-box;
153 | font-family: sans-serif;
154 | }
155 | *,
156 | *::before,
157 | *::after {
158 | box-sizing: inherit;
159 | }
160 | blockquote,
161 | dl,
162 | dd,
163 | h1,
164 | h2,
165 | h3,
166 | h4,
167 | h5,
168 | h6,
169 | figure,
170 | p,
171 | pre {
172 | margin: 0;
173 | }
174 | button {
175 | background: transparent;
176 | padding: 0;
177 | }
178 | button:focus {
179 | outline: 1px dotted;
180 | outline: 5px auto -webkit-focus-ring-color;
181 | }
182 | fieldset {
183 | margin: 0;
184 | padding: 0;
185 | }
186 | ol,
187 | ul {
188 | list-style: none;
189 | margin: 0;
190 | padding: 0;
191 | }
192 | html {
193 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 1 */
194 | line-height: 1.5;
195 | }
196 | *,
197 | *::before,
198 | *::after {
199 | border-width: 0;
200 | border-style: solid;
201 | border-color: #e2e8f0;
202 | }
203 | img {
204 | border-style: solid;
205 | }
206 | textarea {
207 | resize: vertical;
208 | }
209 | input:-ms-input-placeholder,
210 | textarea:-ms-input-placeholder {
211 | color: inherit;
212 | opacity: 0.5;
213 | }
214 | input::-ms-input-placeholder,
215 | textarea::-ms-input-placeholder {
216 | color: inherit;
217 | opacity: 0.5;
218 | }
219 | input::placeholder,
220 | textarea::placeholder {
221 | color: inherit;
222 | opacity: 0.5;
223 | }
224 | button,
225 | [role="button"] {
226 | cursor: pointer;
227 | }
228 | table {
229 | border-collapse: collapse;
230 | }
231 | h1,
232 | h2,
233 | h3,
234 | h4,
235 | h5,
236 | h6 {
237 | font-size: inherit;
238 | font-weight: inherit;
239 | }
240 | a {
241 | color: inherit;
242 | text-decoration: inherit;
243 | }
244 | button,
245 | input,
246 | optgroup,
247 | select,
248 | textarea {
249 | padding: 0;
250 | line-height: inherit;
251 | color: inherit;
252 | }
253 | pre,
254 | code,
255 | kbd,
256 | samp {
257 | font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
258 | }
259 | img,
260 | svg,
261 | video,
262 | canvas,
263 | audio,
264 | iframe,
265 | embed,
266 | object {
267 | display: block;
268 | vertical-align: middle;
269 | }
270 | img,
271 | video {
272 | max-width: 100%;
273 | height: auto;
274 | }
275 | `
276 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/TextContainer.ts:
--------------------------------------------------------------------------------
1 | import tw from 'tailwind.macro'
2 |
3 | export const TextContainer = tw.div`flex flex-col items-center my-4`
4 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/Typography.ts:
--------------------------------------------------------------------------------
1 | import tw from 'tailwind.macro'
2 |
3 | export const H1 = tw.h1`antialiased font-sans text-2xl font-bold text-gray-800 text-center`
4 |
5 | export const P = tw.p`antialiased font-sans text-base font-nomral text-gray-800 text-center`
6 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/WrongIcon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import tw from 'tailwind.macro'
3 |
4 | const CloseSvg = () => (
5 |
11 | )
12 |
13 | const Icon = tw.div`h-4 w-4 text-red-500 hover:text-red-700`
14 |
15 | export const WrongIcon = () => (
16 |
17 |
18 |
19 | )
20 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/Actions.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {Actions} from '../Actions'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/Button.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {Button} from '../Button'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/Container.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {Container} from '../Container'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/CorrectIcon.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {CorrectIcon} from '../CorrectIcon'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/GlobalStyle.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {GlobalStyle} from '../GlobalStyle'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/TextContainer.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {TextContainer} from '../TextContainer'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/Typography.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {H1, P} from '../Typography'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
12 | describe('', () => {
13 | it('should match snapshot', () => {
14 | const {container} = render()
15 | expect(container).toMatchSnapshot()
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/WrongIcon.tsx:
--------------------------------------------------------------------------------
1 | import {render} from '@testing-library/react'
2 | import React from 'react'
3 | import {WrongIcon} from '../WrongIcon'
4 |
5 | describe('', () => {
6 | it('should match snapshot', () => {
7 | const {container} = render()
8 | expect(container).toMatchSnapshot()
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/Actions.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
9 | `;
10 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/Button.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
5 |
8 |
9 | `;
10 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/Container.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
9 | `;
10 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/CorrectIcon.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
18 | `;
19 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/GlobalStyle.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = ``;
4 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/TextContainer.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
9 | `;
10 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/Typography.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
5 |
8 |
9 | `;
10 |
11 | exports[` should match snapshot 1`] = `
12 |
17 | `;
18 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/__tests__/__snapshots__/WrongIcon.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[` should match snapshot 1`] = `
4 |
18 | `;
19 |
--------------------------------------------------------------------------------
/trivia-game-react/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Actions'
2 | export * from './Button'
3 | export * from './Container'
4 | export * from './CorrectIcon'
5 | export * from './GlobalStyle'
6 | export * from './TextContainer'
7 | export * from './Typography'
8 | export * from './WrongIcon'
9 |
--------------------------------------------------------------------------------
/trivia-game-react/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 |
5 | ReactDOM.render(, document.getElementById('root'))
6 |
--------------------------------------------------------------------------------
/trivia-game-react/src/machine.ts:
--------------------------------------------------------------------------------
1 | import {assign, Machine} from 'xstate'
2 | import {AppMachineContext, AppMachineEvent, AppMachineSchema} from './types'
3 | import {fetchAndNormalizeQuizData} from './utils'
4 |
5 | const machine = Machine(
6 | {
7 | id: 'Machine',
8 | initial: 'welcome',
9 | context: {
10 | currentQuestion: 0,
11 | currentQuestionDisplay: 1,
12 | questions: [],
13 | totalCorrectAnswers: 0,
14 | },
15 | states: {
16 | welcome: {
17 | on: {
18 | START_QUIZ: 'loading',
19 | },
20 | },
21 | loading: {
22 | invoke: {
23 | id: 'getQuizData',
24 | src: 'fetchAndNormalizeQuizData',
25 | onDone: {
26 | target: 'quiz',
27 | actions: assign({
28 | questions: (_, event) => event.data,
29 | }),
30 | },
31 | onError: {
32 | target: 'failure',
33 | },
34 | },
35 | },
36 | failure: {
37 | on: {
38 | RETRY: 'loading',
39 | START_OVER: 'welcome',
40 | },
41 | },
42 | quiz: {
43 | on: {
44 | '': {
45 | target: 'results',
46 | actions: [],
47 | cond: 'allQuestionsAnswered',
48 | },
49 | ANSWER_FALSE: {
50 | actions: 'updateAnswer',
51 | },
52 | ANSWER_TRUE: {
53 | actions: 'updateAnswer',
54 | },
55 | },
56 | },
57 | results: {
58 | on: {
59 | PLAY_AGAIN: 'welcome',
60 | },
61 | exit: 'resetGame',
62 | },
63 | },
64 | },
65 | {
66 | actions: {
67 | resetGame: assign({
68 | currentQuestion: 0,
69 | currentQuestionDisplay: 1,
70 | questions: [],
71 | totalCorrectAnswers: 0,
72 | }),
73 | updateAnswer: assign((ctx, event: any) => ({
74 | questions: [
75 | ...ctx.questions.slice(0, ctx.currentQuestion),
76 | {
77 | ...ctx.questions[ctx.currentQuestion],
78 | userAnswer: event.answer,
79 | correct:
80 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer,
81 | },
82 | ...ctx.questions.slice(ctx.currentQuestion + 1),
83 | ],
84 | totalCorrectAnswers:
85 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer
86 | ? (ctx.totalCorrectAnswers += 1)
87 | : ctx.totalCorrectAnswers,
88 | currentQuestion: ctx.currentQuestion += 1,
89 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1,
90 | })),
91 | },
92 | guards: {
93 | allQuestionsAnswered: ctx => {
94 | return (
95 | ctx.questions.filter(
96 | (question: any) => question.correct !== undefined,
97 | ).length === ctx.questions.length && true
98 | )
99 | },
100 | },
101 | services: {
102 | fetchAndNormalizeQuizData: () => fetchAndNormalizeQuizData(),
103 | },
104 | },
105 | )
106 |
107 | export default machine
108 |
--------------------------------------------------------------------------------
/trivia-game-react/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module 'lean-he/decode'
4 | declare module 'tailwind.macro'
5 |
--------------------------------------------------------------------------------
/trivia-game-react/src/screens/Failure.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {State} from 'xstate'
3 | import {Actions, Button, Container, H1, P, TextContainer} from '../components'
4 | import {AppMachineContext, AppMachineEvent} from '../types'
5 |
6 | interface FailureProps {
7 | retry: () => State
8 | startOver: () => State
9 | }
10 |
11 | export const Failure: React.FC = ({retry, startOver}) => (
12 |
13 | Failure!
14 |
15 | Looks like there where a problem.
16 | You can retry loading the game or start over.
17 |
18 |
19 |
22 |
25 |
26 |
27 | )
28 |
--------------------------------------------------------------------------------
/trivia-game-react/src/screens/Loading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import tw from 'tailwind.macro'
3 | import {Container as Wrapper, H1} from '../components'
4 |
5 | const Container = tw(Wrapper)`justify-center`
6 |
7 | export const Loading: React.FC = () => (
8 |
9 | Loading...
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/trivia-game-react/src/screens/Quiz.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import tw from 'tailwind.macro'
3 | import {State} from 'xstate'
4 | import {Actions, Button, Container, H1, P} from '../components'
5 | import {AppMachineContext, AppMachineEvent, Question} from '../types'
6 |
7 | const QuestionText = tw(P)`w-full md:w-4/5 mb-2 text-center`
8 | const QuestionsCount = tw(P)`text-sm mt-2`
9 | const Content = tw(Container)`w-full md:w-3/4 p-0 md:p-5`
10 |
11 | interface QuizProps {
12 | answerFalse: () => State
13 | answerTrue: () => State
14 | currentQuestionNumber: number
15 | question: Question
16 | totalQuestions: number
17 | }
18 | export const Quiz: React.FC = ({
19 | answerFalse,
20 | answerTrue,
21 | currentQuestionNumber,
22 | question,
23 | totalQuestions,
24 | }) => {
25 | return (
26 |
27 | {question.category}
28 |
29 | {question.question}
30 |
31 |
34 |
37 |
38 |
39 |
40 | {currentQuestionNumber} of {totalQuestions}
41 |
42 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/trivia-game-react/src/screens/Results.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import tw from 'tailwind.macro'
3 | import {State} from 'xstate'
4 | import {Button, Container, CorrectIcon, H1, WrongIcon} from '../components'
5 | import {AppMachineContext, AppMachineEvent, Question} from '../types'
6 |
7 | const QuestionResults = tw.ul`w-3/4 my-4`
8 | const Icon = tw.span`mr-4`
9 | const Result = tw.li`flex mb-4 items-center`
10 |
11 | interface ResultsProps {
12 | questions: Question[]
13 | playAgain: () => State
14 | totalCorrectAnswers: number
15 | totalQuestions: number
16 | }
17 |
18 | export const Results: React.FC = ({
19 | playAgain,
20 | questions,
21 | totalCorrectAnswers,
22 | totalQuestions,
23 | }) => (
24 |
25 |
26 | You scored
27 |
28 | {totalCorrectAnswers} / {totalQuestions}
29 |
30 |
31 | {questions.map(question => (
32 |
33 |
34 | {question.correct === true ? : }
35 | {' '}
36 | {question.question}
37 |
38 | ))}
39 |
40 |
43 |
44 | )
45 |
--------------------------------------------------------------------------------
/trivia-game-react/src/screens/Welcome.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {State} from 'xstate'
3 | import {Button, Container, H1, P, TextContainer} from '../components'
4 | import {AppMachineContext, AppMachineEvent} from '../types'
5 |
6 | interface WelcomeProps {
7 | startQuiz: () => State
8 | }
9 | export const Welcome: React.FC = ({startQuiz}) => (
10 |
11 | Welcome to the Trivia Challenge
12 |
13 | You will be presented with 10 true or false questions.
14 | Can you score 100%?
15 |
16 |
19 |
20 | )
21 |
--------------------------------------------------------------------------------
/trivia-game-react/src/screens/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Failure'
2 | export * from './Loading'
3 | export * from './Quiz'
4 | export * from './Results'
5 | export * from './Welcome'
6 |
--------------------------------------------------------------------------------
/trivia-game-react/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | import 'jest-axe/extend-expect'
2 | import '@testing-library/jest-dom/extend-expect'
3 |
--------------------------------------------------------------------------------
/trivia-game-react/src/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | theme: {},
3 | variants: {},
4 | plugins: [],
5 | }
6 |
--------------------------------------------------------------------------------
/trivia-game-react/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface QuizDataQuestion {
2 | category: string
3 | type: string
4 | difficulty: string
5 | question: string
6 | correct_answer: string
7 | incorrect_answers: string[]
8 | }
9 |
10 | export interface FetchQuizDataResponse {
11 | response_code: number
12 | results: Question[]
13 | }
14 |
15 | export interface Question {
16 | category: string
17 | question: string
18 | correctAnswer: boolean
19 | userAnswer?: boolean
20 | correct?: boolean
21 | }
22 |
23 | export interface AppMachineSchema {
24 | states: {
25 | welcome: {}
26 | loading: {}
27 | failure: {}
28 | quiz: {}
29 | results: {}
30 | }
31 | }
32 |
33 | export type AppMachineEvent =
34 | | {type: 'START_QUIZ'}
35 | | {type: 'RETRY'}
36 | | {type: 'START_OVER'}
37 | | {type: 'ANSWER_FALSE'; answer: boolean}
38 | | {type: 'ANSWER_TRUE'; answer: boolean}
39 | | {type: 'PLAY_AGAIN'}
40 |
41 | export interface AppMachineContext {
42 | currentQuestion: number
43 | currentQuestionDisplay: number
44 | questions: Question[]
45 | totalCorrectAnswers: number
46 | }
47 |
--------------------------------------------------------------------------------
/trivia-game-react/src/utils/fetchAndNormalizeQuizData.ts:
--------------------------------------------------------------------------------
1 | import {fetchQuizData, normalizeQuizData} from '.'
2 |
3 | export const fetchAndNormalizeQuizData = async () => {
4 | try {
5 | const data = await fetchQuizData()
6 | return Promise.resolve(normalizeQuizData(data.results))
7 | } catch (error) {
8 | return Promise.reject(error)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/trivia-game-react/src/utils/fetchQuizData.ts:
--------------------------------------------------------------------------------
1 | export const fetchQuizData = () =>
2 | fetch(
3 | `https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`,
4 | ).then(response => response.json())
5 |
--------------------------------------------------------------------------------
/trivia-game-react/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './fetchAndNormalizeQuizData'
2 | export * from './fetchQuizData'
3 | export * from './normalizeQuizData'
4 |
--------------------------------------------------------------------------------
/trivia-game-react/src/utils/normalizeQuizData.ts:
--------------------------------------------------------------------------------
1 | import decode from 'lean-he/decode'
2 | import {Question, QuizDataQuestion} from '../types'
3 |
4 | export const normalizeQuizData = (data: QuizDataQuestion[]): Question[] =>
5 | data.reduce(
6 | (acc: Question[], obj: QuizDataQuestion) => [
7 | ...acc,
8 | {
9 | category: decode(obj.category),
10 | question: decode(obj.question),
11 | correctAnswer: obj.correct_answer === 'True' ? true : false,
12 | userAnswer: undefined,
13 | correct: undefined,
14 | },
15 | ],
16 | [],
17 | )
18 |
--------------------------------------------------------------------------------
/trivia-game-react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noEmit": true,
16 | "jsx": "react"
17 | },
18 | "include": ["src"]
19 | }
20 |
--------------------------------------------------------------------------------
/trivia-game-svelte/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | insert_final_newline = true
9 |
10 |
--------------------------------------------------------------------------------
/trivia-game-svelte/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | public/bundle.*
4 |
--------------------------------------------------------------------------------
/trivia-game-svelte/.node-version:
--------------------------------------------------------------------------------
1 | 10.16.3
2 |
3 |
--------------------------------------------------------------------------------
/trivia-game-svelte/.nvmrc:
--------------------------------------------------------------------------------
1 | 10.16.3
2 |
3 |
--------------------------------------------------------------------------------
/trivia-game-svelte/.prettierignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | .env.local
6 | .env.*.local
7 |
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 |
12 | .idea
13 | .vscode
14 | *.suo
15 | *.ntvs*
16 | *.njsproj
17 | *.sln
18 | *.sw?
19 |
20 |
--------------------------------------------------------------------------------
/trivia-game-svelte/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "avoid",
3 | "bracketSpacing": false,
4 | "htmlWhitespaceSensitivity": "css",
5 | "insertPragma": false,
6 | "jsxBracketSameLine": false,
7 | "jsxSingleQuote": true,
8 | "printWidth": 80,
9 | "proseWrap": "always",
10 | "requirePragma": false,
11 | "semi": false,
12 | "singleQuote": true,
13 | "tabWidth": 2,
14 | "trailingComma": "all",
15 | "useTabs": false
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/trivia-game-svelte/README.md:
--------------------------------------------------------------------------------
1 | # Trivia Game
2 |
3 | This example showcases several state machine concepts including guards,
4 | transient functions, and invoking services.
5 |
6 | [Trivia Game machine visualized](https://xstate.js.org/viz/?gist=3abe97296e6d6cebcbda9c903d6da068)
7 |
8 | ## Running Locally
9 |
10 | 1. After cloning and navigating into the `trivia-game-svelte` directory, execute:
11 |
12 | ```
13 | yarn && yarn test
14 | ```
15 |
16 | or
17 |
18 | ```
19 | npm install && npm t
20 | ```
21 |
22 | This will install dependencies and run tests to verify no issues
23 |
24 | 2. Start the application by executing:
25 |
26 | ```
27 | yarn start
28 | ```
29 |
30 | or
31 |
32 | ```
33 | npm start
34 | ```
35 |
--------------------------------------------------------------------------------
/trivia-game-svelte/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | base = ""
3 | command = "yarn build"
4 | publish = "/dist"
5 |
--------------------------------------------------------------------------------
/trivia-game-svelte/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-app",
3 | "version": "1.0.0",
4 | "devDependencies": {
5 | "@fullhuman/postcss-purgecss": "^7.0.2",
6 | "@rollup/plugin-commonjs": "^28.0.3",
7 | "@rollup/plugin-node-resolve": "^16.0.1",
8 | "@rollup/plugin-replace": "^6.0.2",
9 | "lean-he": "2.1.2",
10 | "postcss": "^8.5.4",
11 | "postcss-load-config": "^6.0.1",
12 | "rollup": "^4.41.1",
13 | "rollup-plugin-livereload": "^2.0.5",
14 | "rollup-plugin-svelte": "^7.2.2",
15 | "rollup-plugin-terser": "^7.0.2",
16 | "svelte": "^5.33.14",
17 | "svelte-preprocess": "^6.0.3",
18 | "tailwindcss": "4.1.8",
19 | "xstate": "4.38.3"
20 | },
21 | "dependencies": {
22 | "sirv-cli": "^3.0.1",
23 | "svelte-xstate": "^1.0.1"
24 | },
25 | "scripts": {
26 | "build": "rollup -c",
27 | "start": "rollup -c -w",
28 | "start:prod": "sirv public --single",
29 | "start:dev": "sirv public --single --dev"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/trivia-game-svelte/postcss.config.js:
--------------------------------------------------------------------------------
1 | const purgecss = require('@fullhuman/postcss-purgecss')({
2 | content: [
3 | './src/**/*.html',
4 | './src/**/*.svelte'
5 | ],
6 |
7 | whitelistPatterns: [/svelte-/],
8 |
9 | defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
10 | });
11 |
12 | const production = !process.env.ROLLUP_WATCH
13 |
14 | module.exports = {
15 | plugins: [
16 | require('tailwindcss'),
17 | ...(production ? [purgecss] : [])
18 | ]
19 | };
20 |
--------------------------------------------------------------------------------
/trivia-game-svelte/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-svelte/public/favicon.png
--------------------------------------------------------------------------------
/trivia-game-svelte/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Svelte app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/trivia-game-svelte/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import replace from '@rollup/plugin-replace';
3 | import resolve from '@rollup/plugin-node-resolve';
4 | import commonjs from '@rollup/plugin-commonjs';
5 | import livereload from 'rollup-plugin-livereload';
6 | import { terser } from 'rollup-plugin-terser';
7 | import sveltePreprocess from 'svelte-preprocess';
8 |
9 | import rollup_start_dev from './rollup_start_dev';
10 |
11 | const production = !process.env.ROLLUP_WATCH;
12 |
13 | export default {
14 | input: 'src/main.js',
15 | output: {
16 | sourcemap: true,
17 | format: 'iife',
18 | name: 'app',
19 | file: 'public/bundle.js'
20 | },
21 | plugins: [
22 | svelte({
23 | preprocess: sveltePreprocess({ postcss: true }),
24 | // enable run-time checks when not in production
25 | dev: !production,
26 | // we'll extract any component CSS out into
27 | // a separate file — better for performance
28 | css: css => {
29 | css.write('public/bundle.css');
30 | }
31 | }),
32 | replace({
33 | "process.env.NODE_ENV": production
34 | ? JSON.stringify("production")
35 | : JSON.stringify("development")
36 | }),
37 |
38 | // If you have external dependencies installed from
39 | // npm, you'll most likely need these plugins. In
40 | // some cases you'll need additional configuration —
41 | // consult the documentation for details:
42 | // https://github.com/rollup/rollup-plugin-commonjs
43 | resolve({
44 | browser: true,
45 | dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
46 | }),
47 | commonjs(),
48 |
49 | // In dev mode, call `npm run start:dev` once
50 | // the bundle has been generated
51 | !production && rollup_start_dev,
52 |
53 | // Watch the `public` directory and refresh the
54 | // browser on changes when not in production
55 | !production && livereload('public'),
56 |
57 | // If we're building for production (npm run build
58 | // instead of npm run dev), minify
59 | production && terser()
60 | ],
61 | watch: {
62 | clearScreen: false
63 | }
64 | };
65 |
--------------------------------------------------------------------------------
/trivia-game-svelte/rollup_start_dev.js:
--------------------------------------------------------------------------------
1 | import * as child_process from 'child_process';
2 |
3 | let running_dev_server = false;
4 |
5 | export default {
6 | writeBundle() {
7 | if (!running_dev_server) {
8 | running_dev_server = true;
9 | child_process.spawn('npm', ['run', 'start:dev'], { stdio: ['ignore', 'inherit', 'inherit'], shell: true });
10 | }
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/App.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {#if $current.matches('welcome')}
5 |
6 | {:else if $current.matches('loading')}
7 |
8 | {:else if $current.matches('failure')}
9 |
10 | {:else if $current.matches('quiz')}
11 |
18 | {:else if $current.matches('results')}
19 |
25 | {/if}
26 |
27 |
28 |
29 |
60 |
61 |
82 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/Actions.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/Button.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
14 |
15 |
30 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/Container.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/CorrectIcon.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
16 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/GlobalStyle.svelte:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/H1.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/P.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/TextContainer.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/components/WrongIcon.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
19 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/machine.js:
--------------------------------------------------------------------------------
1 | import {assign, Machine} from 'xstate'
2 | import {fetchAndNormalizeQuizData} from './utils'
3 |
4 | const machine = Machine(
5 | {
6 | id: 'Machine',
7 | initial: 'welcome',
8 | context: {
9 | currentQuestion: 0,
10 | currentQuestionDisplay: 1,
11 | questions: [],
12 | totalCorrectAnswers: 0,
13 | },
14 | states: {
15 | welcome: {
16 | on: {
17 | START_QUIZ: 'loading',
18 | },
19 | },
20 | loading: {
21 | invoke: {
22 | id: 'getQuizData',
23 | src: 'fetchAndNormalizeQuizData',
24 | onDone: {
25 | target: 'quiz',
26 | actions: assign({
27 | questions: (_, event) => event.data,
28 | }),
29 | },
30 | onError: {
31 | target: 'failure',
32 | },
33 | },
34 | },
35 | failure: {
36 | on: {
37 | RETRY: 'loading',
38 | START_OVER: 'welcome',
39 | },
40 | },
41 | quiz: {
42 | on: {
43 | '': {
44 | target: 'results',
45 | actions: [],
46 | cond: 'allQuestionsAnswered',
47 | },
48 | ANSWER_FALSE: {
49 | actions: 'updateAnswer',
50 | },
51 | ANSWER_TRUE: {
52 | actions: 'updateAnswer',
53 | },
54 | },
55 | },
56 | results: {
57 | on: {
58 | PLAY_AGAIN: 'welcome',
59 | },
60 | exit: 'resetGame',
61 | },
62 | },
63 | },
64 | {
65 | actions: {
66 | resetGame: assign({
67 | currentQuestion: 0,
68 | currentQuestionDisplay: 1,
69 | questions: [],
70 | totalCorrectAnswers: 0,
71 | }),
72 | updateAnswer: assign((ctx, event) => ({
73 | questions: [
74 | ...ctx.questions.slice(0, ctx.currentQuestion),
75 | {
76 | ...ctx.questions[ctx.currentQuestion],
77 | userAnswer: event.answer,
78 | correct:
79 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer,
80 | },
81 | ...ctx.questions.slice(ctx.currentQuestion + 1),
82 | ],
83 | totalCorrectAnswers:
84 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer
85 | ? (ctx.totalCorrectAnswers += 1)
86 | : ctx.totalCorrectAnswers,
87 | currentQuestion: ctx.currentQuestion += 1,
88 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1,
89 | })),
90 | },
91 | guards: {
92 | allQuestionsAnswered: ctx => {
93 | return (
94 | ctx.questions.filter(
95 | (question) => question.correct !== undefined,
96 | ).length === ctx.questions.length && true
97 | )
98 | },
99 | },
100 | services: {
101 | fetchAndNormalizeQuizData: () => fetchAndNormalizeQuizData(),
102 | },
103 | },
104 | )
105 |
106 | export default machine
107 |
108 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/main.js:
--------------------------------------------------------------------------------
1 | import App from './App.svelte';
2 |
3 | const app = new App({
4 | target: document.body,
5 | props: {
6 | name: 'world'
7 | }
8 | });
9 |
10 | export default app;
--------------------------------------------------------------------------------
/trivia-game-svelte/src/screens/Failure.svelte:
--------------------------------------------------------------------------------
1 |
2 | Failure!
3 |
4 | Looks like there where a problem.
5 | You can retry loading the game or start over.
6 |
7 |
8 |
11 |
14 |
15 |
16 |
17 |
36 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/screens/Loading.svelte:
--------------------------------------------------------------------------------
1 |
2 | Loading...
3 |
4 |
5 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/screens/Quiz.svelte:
--------------------------------------------------------------------------------
1 |
2 | {question.category}
3 |
4 | {question.question}
5 |
6 |
9 |
12 |
13 |
14 |
15 | { currentQuestionNumber } of { totalQuestions }
16 |
17 |
18 |
19 |
40 |
41 |
66 |
67 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/screens/Results.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 | You scored
4 |
5 | {totalCorrectAnswers} / {totalQuestions}
6 |
7 |
8 | {#each questions as question (question.question)}
9 | -
10 |
11 | {#if question.correct === true}
12 |
13 | {:else if question.correct === false}
14 |
15 | {/if}
16 |
17 | {question.question}
18 |
19 | {/each}
20 |
21 |
24 |
25 |
26 |
44 |
45 |
58 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/screens/Welcome.svelte:
--------------------------------------------------------------------------------
1 |
2 | Welcome to the Trivia Challenge
3 |
4 | You will be presented with 10 true or false questions.
5 | Can you score 100%?
6 |
7 |
10 |
11 |
12 |
26 |
27 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/utils/fetchAndNormalizeQuizData.js:
--------------------------------------------------------------------------------
1 | import {normalizeQuizData} from './normalizeQuizData'
2 | import {fetchQuizData} from './fetchQuizData'
3 |
4 | export const fetchAndNormalizeQuizData = async () => {
5 | try {
6 | const data = await fetchQuizData()
7 | return Promise.resolve(normalizeQuizData(data.results))
8 | } catch (error) {
9 | return Promise.reject(error)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/utils/fetchQuizData.js:
--------------------------------------------------------------------------------
1 | export const fetchQuizData = () =>
2 | fetch(
3 | `https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`,
4 | ).then(response =>
5 | response.json());
6 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/utils/index.js:
--------------------------------------------------------------------------------
1 | export * from './fetchAndNormalizeQuizData'
2 | export * from './fetchQuizData'
3 | export * from './normalizeQuizData'
4 |
--------------------------------------------------------------------------------
/trivia-game-svelte/src/utils/normalizeQuizData.js:
--------------------------------------------------------------------------------
1 | import decode from 'lean-he/decode'
2 |
3 | export const normalizeQuizData = data =>
4 | data.reduce(
5 | (acc, obj) => [
6 | ...acc,
7 | {
8 | category: decode(obj.category),
9 | question: decode(obj.question),
10 | correctAnswer: obj.correct_answer === 'True' ? true : false,
11 | userAnswer: undefined,
12 | correct: undefined,
13 | },
14 | ],
15 | [],
16 | )
17 |
--------------------------------------------------------------------------------
/trivia-game-svelte/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | theme: {
3 | extend: {}
4 | },
5 | variants: {},
6 | plugins: []
7 | }
8 |
--------------------------------------------------------------------------------
/trivia-game-svelte/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@ampproject/remapping@^2.3.0":
6 | version "2.3.0"
7 | resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
8 | integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
9 | dependencies:
10 | "@jridgewell/gen-mapping" "^0.3.5"
11 | "@jridgewell/trace-mapping" "^0.3.24"
12 |
13 | "@babel/code-frame@^7.10.4":
14 | version "7.10.4"
15 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
16 | integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
17 | dependencies:
18 | "@babel/highlight" "^7.10.4"
19 |
20 | "@babel/helper-validator-identifier@^7.10.4":
21 | version "7.10.4"
22 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
23 | integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
24 |
25 | "@babel/highlight@^7.10.4":
26 | version "7.10.4"
27 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
28 | integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
29 | dependencies:
30 | "@babel/helper-validator-identifier" "^7.10.4"
31 | chalk "^2.0.0"
32 | js-tokens "^4.0.0"
33 |
34 | "@fullhuman/postcss-purgecss@^7.0.2":
35 | version "7.0.2"
36 | resolved "https://registry.yarnpkg.com/@fullhuman/postcss-purgecss/-/postcss-purgecss-7.0.2.tgz#ccacdbc312248c76c42cfac359f4ca5121001e67"
37 | integrity sha512-U4zAXNaVztbDxO9EdcLp51F3UxxYsb/7DN89rFxFJhfk2Wua2pvw2Kf3HdspbPhW/wpHjSjsxWYoIlbTgRSjbQ==
38 | dependencies:
39 | purgecss "^7.0.2"
40 |
41 | "@isaacs/cliui@^8.0.2":
42 | version "8.0.2"
43 | resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
44 | integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
45 | dependencies:
46 | string-width "^5.1.2"
47 | string-width-cjs "npm:string-width@^4.2.0"
48 | strip-ansi "^7.0.1"
49 | strip-ansi-cjs "npm:strip-ansi@^6.0.1"
50 | wrap-ansi "^8.1.0"
51 | wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
52 |
53 | "@jridgewell/gen-mapping@^0.3.0":
54 | version "0.3.2"
55 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
56 | integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
57 | dependencies:
58 | "@jridgewell/set-array" "^1.0.1"
59 | "@jridgewell/sourcemap-codec" "^1.4.10"
60 | "@jridgewell/trace-mapping" "^0.3.9"
61 |
62 | "@jridgewell/gen-mapping@^0.3.5":
63 | version "0.3.5"
64 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
65 | integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
66 | dependencies:
67 | "@jridgewell/set-array" "^1.2.1"
68 | "@jridgewell/sourcemap-codec" "^1.4.10"
69 | "@jridgewell/trace-mapping" "^0.3.24"
70 |
71 | "@jridgewell/resolve-uri@^3.1.0":
72 | version "3.1.2"
73 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
74 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
75 |
76 | "@jridgewell/set-array@^1.0.1":
77 | version "1.1.2"
78 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
79 | integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
80 |
81 | "@jridgewell/set-array@^1.2.1":
82 | version "1.2.1"
83 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
84 | integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
85 |
86 | "@jridgewell/source-map@^0.3.2":
87 | version "0.3.2"
88 | resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
89 | integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
90 | dependencies:
91 | "@jridgewell/gen-mapping" "^0.3.0"
92 | "@jridgewell/trace-mapping" "^0.3.9"
93 |
94 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0":
95 | version "1.5.0"
96 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
97 | integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
98 |
99 | "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.9":
100 | version "0.3.25"
101 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
102 | integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
103 | dependencies:
104 | "@jridgewell/resolve-uri" "^3.1.0"
105 | "@jridgewell/sourcemap-codec" "^1.4.14"
106 |
107 | "@polka/url@^1.0.0-next.24":
108 | version "1.0.0-next.28"
109 | resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73"
110 | integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==
111 |
112 | "@rollup/plugin-commonjs@^28.0.3":
113 | version "28.0.3"
114 | resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz#44c2cc7c955c6113b96696b55e6bc2446bd67913"
115 | integrity sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==
116 | dependencies:
117 | "@rollup/pluginutils" "^5.0.1"
118 | commondir "^1.0.1"
119 | estree-walker "^2.0.2"
120 | fdir "^6.2.0"
121 | is-reference "1.2.1"
122 | magic-string "^0.30.3"
123 | picomatch "^4.0.2"
124 |
125 | "@rollup/plugin-node-resolve@^16.0.1":
126 | version "16.0.1"
127 | resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz#2fc6b54ca3d77e12f3fb45b2a55b50720de4c95d"
128 | integrity sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==
129 | dependencies:
130 | "@rollup/pluginutils" "^5.0.1"
131 | "@types/resolve" "1.20.2"
132 | deepmerge "^4.2.2"
133 | is-module "^1.0.0"
134 | resolve "^1.22.1"
135 |
136 | "@rollup/plugin-replace@^6.0.2":
137 | version "6.0.2"
138 | resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz#2f565d312d681e4570ff376c55c5c08eb6f1908d"
139 | integrity sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==
140 | dependencies:
141 | "@rollup/pluginutils" "^5.0.1"
142 | magic-string "^0.30.3"
143 |
144 | "@rollup/pluginutils@^4.1.0":
145 | version "4.2.1"
146 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
147 | integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
148 | dependencies:
149 | estree-walker "^2.0.1"
150 | picomatch "^2.2.2"
151 |
152 | "@rollup/pluginutils@^5.0.1":
153 | version "5.0.1"
154 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.1.tgz#63def51f5a76dadd984689d33c7f000164152a97"
155 | integrity sha512-4HaCVEXXuObvcPUaUlLt4faHYHCeQOOWNj8NKFGaRSrw3ZLD0TWeAFZicV9vXjnE2nkNuaVTfTuwAnjR+6uc9A==
156 | dependencies:
157 | "@types/estree" "^1.0.0"
158 | estree-walker "^2.0.2"
159 | picomatch "^2.3.1"
160 |
161 | "@rollup/rollup-android-arm-eabi@4.41.1":
162 | version "4.41.1"
163 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz#f39f09f60d4a562de727c960d7b202a2cf797424"
164 | integrity sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==
165 |
166 | "@rollup/rollup-android-arm64@4.41.1":
167 | version "4.41.1"
168 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz#d19af7e23760717f1d879d4ca3d2cd247742dff2"
169 | integrity sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==
170 |
171 | "@rollup/rollup-darwin-arm64@4.41.1":
172 | version "4.41.1"
173 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz#1c3a2fbf205d80641728e05f4a56c909e95218b7"
174 | integrity sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==
175 |
176 | "@rollup/rollup-darwin-x64@4.41.1":
177 | version "4.41.1"
178 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz#aa66d2ba1a25e609500e13bef06dc0e71cc0c0d4"
179 | integrity sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==
180 |
181 | "@rollup/rollup-freebsd-arm64@4.41.1":
182 | version "4.41.1"
183 | resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz#df10a7b6316a0ef1028c6ca71a081124c537e30d"
184 | integrity sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==
185 |
186 | "@rollup/rollup-freebsd-x64@4.41.1":
187 | version "4.41.1"
188 | resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz#a3fdce8a05e95b068cbcb46e4df5185e407d0c35"
189 | integrity sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==
190 |
191 | "@rollup/rollup-linux-arm-gnueabihf@4.41.1":
192 | version "4.41.1"
193 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz#49f766c55383bd0498014a9d76924348c2f3890c"
194 | integrity sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==
195 |
196 | "@rollup/rollup-linux-arm-musleabihf@4.41.1":
197 | version "4.41.1"
198 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz#1d4d7d32fc557e17d52e1857817381ea365e2959"
199 | integrity sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==
200 |
201 | "@rollup/rollup-linux-arm64-gnu@4.41.1":
202 | version "4.41.1"
203 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz#f4fc317268441e9589edad3be8f62b6c03009bc1"
204 | integrity sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==
205 |
206 | "@rollup/rollup-linux-arm64-musl@4.41.1":
207 | version "4.41.1"
208 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz#63a1f1b0671cb17822dabae827fef0e443aebeb7"
209 | integrity sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==
210 |
211 | "@rollup/rollup-linux-loongarch64-gnu@4.41.1":
212 | version "4.41.1"
213 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz#c659b01cc6c0730b547571fc3973e1e955369f98"
214 | integrity sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==
215 |
216 | "@rollup/rollup-linux-powerpc64le-gnu@4.41.1":
217 | version "4.41.1"
218 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz#612e746f9ad7e58480f964d65e0d6c3f4aae69a8"
219 | integrity sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==
220 |
221 | "@rollup/rollup-linux-riscv64-gnu@4.41.1":
222 | version "4.41.1"
223 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz#4610dbd1dcfbbae32fbc10c20ae7387acb31110c"
224 | integrity sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==
225 |
226 | "@rollup/rollup-linux-riscv64-musl@4.41.1":
227 | version "4.41.1"
228 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz#054911fab40dc83fafc21e470193c058108f19d8"
229 | integrity sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==
230 |
231 | "@rollup/rollup-linux-s390x-gnu@4.41.1":
232 | version "4.41.1"
233 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz#98896eca8012547c7f04bd07eaa6896825f9e1a5"
234 | integrity sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==
235 |
236 | "@rollup/rollup-linux-x64-gnu@4.41.1":
237 | version "4.41.1"
238 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz#01cf56844a1e636ee80dfb364e72c2b7142ad896"
239 | integrity sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==
240 |
241 | "@rollup/rollup-linux-x64-musl@4.41.1":
242 | version "4.41.1"
243 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz#e67c7531df6dff0b4c241101d4096617fbca87c3"
244 | integrity sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==
245 |
246 | "@rollup/rollup-win32-arm64-msvc@4.41.1":
247 | version "4.41.1"
248 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz#7eeada98444e580674de6989284e4baacd48ea65"
249 | integrity sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==
250 |
251 | "@rollup/rollup-win32-ia32-msvc@4.41.1":
252 | version "4.41.1"
253 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz#516c4b54f80587b4a390aaf4940b40870271d35d"
254 | integrity sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==
255 |
256 | "@rollup/rollup-win32-x64-msvc@4.41.1":
257 | version "4.41.1"
258 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz#848f99b0d9936d92221bb6070baeff4db6947a30"
259 | integrity sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==
260 |
261 | "@sveltejs/acorn-typescript@^1.0.5":
262 | version "1.0.5"
263 | resolved "https://registry.yarnpkg.com/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz#f518101d1b2e12ce80854f1cd850d3b9fb91d710"
264 | integrity sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==
265 |
266 | "@types/estree@*", "@types/estree@1.0.7", "@types/estree@^1.0.0", "@types/estree@^1.0.5", "@types/estree@^1.0.6":
267 | version "1.0.7"
268 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
269 | integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
270 |
271 | "@types/node@*":
272 | version "13.1.2"
273 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.2.tgz#fe94285bf5e0782e1a9e5a8c482b1c34465fa385"
274 | integrity sha512-B8emQA1qeKerqd1dmIsQYnXi+mmAzTB7flExjmy5X1aVAKFNNNDubkavwR13kR6JnpeLp3aLoJhwn9trWPAyFQ==
275 |
276 | "@types/resolve@1.20.2":
277 | version "1.20.2"
278 | resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
279 | integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
280 |
281 | acorn@^8.12.1, acorn@^8.5.0:
282 | version "8.13.0"
283 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3"
284 | integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==
285 |
286 | ansi-regex@^5.0.1:
287 | version "5.0.1"
288 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
289 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
290 |
291 | ansi-regex@^6.0.1:
292 | version "6.0.1"
293 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
294 | integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
295 |
296 | ansi-styles@^3.2.1:
297 | version "3.2.1"
298 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
299 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
300 | dependencies:
301 | color-convert "^1.9.0"
302 |
303 | ansi-styles@^4.0.0:
304 | version "4.3.0"
305 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
306 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
307 | dependencies:
308 | color-convert "^2.0.1"
309 |
310 | ansi-styles@^6.1.0:
311 | version "6.2.1"
312 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
313 | integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
314 |
315 | anymatch@~3.1.2:
316 | version "3.1.2"
317 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
318 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
319 | dependencies:
320 | normalize-path "^3.0.0"
321 | picomatch "^2.0.4"
322 |
323 | aria-query@^5.3.1:
324 | version "5.3.2"
325 | resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59"
326 | integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==
327 |
328 | async-limiter@~1.0.0:
329 | version "1.0.1"
330 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
331 | integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
332 |
333 | axobject-query@^4.1.0:
334 | version "4.1.0"
335 | resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee"
336 | integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==
337 |
338 | balanced-match@^1.0.0:
339 | version "1.0.2"
340 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
341 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
342 |
343 | binary-extensions@^2.0.0:
344 | version "2.0.0"
345 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
346 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
347 |
348 | brace-expansion@^2.0.1:
349 | version "2.0.1"
350 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
351 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
352 | dependencies:
353 | balanced-match "^1.0.0"
354 |
355 | braces@~3.0.2:
356 | version "3.0.3"
357 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
358 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
359 | dependencies:
360 | fill-range "^7.1.1"
361 |
362 | buffer-from@^1.0.0:
363 | version "1.1.2"
364 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
365 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
366 |
367 | chalk@^2.0.0:
368 | version "2.4.2"
369 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
370 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
371 | dependencies:
372 | ansi-styles "^3.2.1"
373 | escape-string-regexp "^1.0.5"
374 | supports-color "^5.3.0"
375 |
376 | chokidar@^3.3.0:
377 | version "3.6.0"
378 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
379 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
380 | dependencies:
381 | anymatch "~3.1.2"
382 | braces "~3.0.2"
383 | glob-parent "~5.1.2"
384 | is-binary-path "~2.1.0"
385 | is-glob "~4.0.1"
386 | normalize-path "~3.0.0"
387 | readdirp "~3.6.0"
388 | optionalDependencies:
389 | fsevents "~2.3.2"
390 |
391 | clsx@^2.1.1:
392 | version "2.1.1"
393 | resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
394 | integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
395 |
396 | color-convert@^1.9.0:
397 | version "1.9.3"
398 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
399 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
400 | dependencies:
401 | color-name "1.1.3"
402 |
403 | color-convert@^2.0.1:
404 | version "2.0.1"
405 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
406 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
407 | dependencies:
408 | color-name "~1.1.4"
409 |
410 | color-name@1.1.3:
411 | version "1.1.3"
412 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
413 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
414 |
415 | color-name@~1.1.4:
416 | version "1.1.4"
417 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
418 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
419 |
420 | commander@^12.1.0:
421 | version "12.1.0"
422 | resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
423 | integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
424 |
425 | commander@^2.20.0:
426 | version "2.20.3"
427 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
428 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
429 |
430 | commondir@^1.0.1:
431 | version "1.0.1"
432 | resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
433 | integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
434 |
435 | console-clear@^1.1.0:
436 | version "1.1.1"
437 | resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7"
438 | integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==
439 |
440 | cross-spawn@^7.0.0:
441 | version "7.0.6"
442 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
443 | integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
444 | dependencies:
445 | path-key "^3.1.0"
446 | shebang-command "^2.0.0"
447 | which "^2.0.1"
448 |
449 | cssesc@^3.0.0:
450 | version "3.0.0"
451 | resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
452 | integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
453 |
454 | deepmerge@^4.2.2:
455 | version "4.2.2"
456 | resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
457 | integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
458 |
459 | eastasianwidth@^0.2.0:
460 | version "0.2.0"
461 | resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
462 | integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
463 |
464 | emoji-regex@^8.0.0:
465 | version "8.0.0"
466 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
467 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
468 |
469 | emoji-regex@^9.2.2:
470 | version "9.2.2"
471 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
472 | integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
473 |
474 | escape-string-regexp@^1.0.5:
475 | version "1.0.5"
476 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
477 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
478 |
479 | esm-env@^1.2.1:
480 | version "1.2.1"
481 | resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.2.1.tgz#34c2a0ba60582948afbe7bd779bc66f9d3aece7e"
482 | integrity sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==
483 |
484 | esrap@^1.4.6:
485 | version "1.4.6"
486 | resolved "https://registry.yarnpkg.com/esrap/-/esrap-1.4.6.tgz#d203ce1ee397aa2a6a716a3a2dc8619f83208c6a"
487 | integrity sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==
488 | dependencies:
489 | "@jridgewell/sourcemap-codec" "^1.4.15"
490 |
491 | estree-walker@^2.0.1, estree-walker@^2.0.2:
492 | version "2.0.2"
493 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
494 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
495 |
496 | fdir@^6.2.0:
497 | version "6.4.0"
498 | resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.0.tgz#8e80ab4b18a2ac24beebf9d20d71e1bc2627dbae"
499 | integrity sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==
500 |
501 | fill-range@^7.1.1:
502 | version "7.1.1"
503 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
504 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
505 | dependencies:
506 | to-regex-range "^5.0.1"
507 |
508 | foreground-child@^3.1.0:
509 | version "3.1.1"
510 | resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
511 | integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
512 | dependencies:
513 | cross-spawn "^7.0.0"
514 | signal-exit "^4.0.1"
515 |
516 | fsevents@~2.3.2:
517 | version "2.3.2"
518 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
519 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
520 |
521 | function-bind@^1.1.2:
522 | version "1.1.2"
523 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
524 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
525 |
526 | get-port@^5.1.1:
527 | version "5.1.1"
528 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
529 | integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
530 |
531 | glob-parent@~5.1.2:
532 | version "5.1.2"
533 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
534 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
535 | dependencies:
536 | is-glob "^4.0.1"
537 |
538 | glob@^11.0.0:
539 | version "11.0.0"
540 | resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.0.tgz#6031df0d7b65eaa1ccb9b29b5ced16cea658e77e"
541 | integrity sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==
542 | dependencies:
543 | foreground-child "^3.1.0"
544 | jackspeak "^4.0.1"
545 | minimatch "^10.0.0"
546 | minipass "^7.1.2"
547 | package-json-from-dist "^1.0.0"
548 | path-scurry "^2.0.0"
549 |
550 | has-flag@^3.0.0:
551 | version "3.0.0"
552 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
553 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
554 |
555 | has-flag@^4.0.0:
556 | version "4.0.0"
557 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
558 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
559 |
560 | hasown@^2.0.2:
561 | version "2.0.2"
562 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
563 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
564 | dependencies:
565 | function-bind "^1.1.2"
566 |
567 | is-binary-path@~2.1.0:
568 | version "2.1.0"
569 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
570 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
571 | dependencies:
572 | binary-extensions "^2.0.0"
573 |
574 | is-core-module@^2.13.0:
575 | version "2.15.1"
576 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37"
577 | integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==
578 | dependencies:
579 | hasown "^2.0.2"
580 |
581 | is-extglob@^2.1.1:
582 | version "2.1.1"
583 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
584 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
585 |
586 | is-fullwidth-code-point@^3.0.0:
587 | version "3.0.0"
588 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
589 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
590 |
591 | is-glob@^4.0.1, is-glob@~4.0.1:
592 | version "4.0.3"
593 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
594 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
595 | dependencies:
596 | is-extglob "^2.1.1"
597 |
598 | is-module@^1.0.0:
599 | version "1.0.0"
600 | resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
601 | integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
602 |
603 | is-number@^7.0.0:
604 | version "7.0.0"
605 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
606 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
607 |
608 | is-reference@1.2.1:
609 | version "1.2.1"
610 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
611 | integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
612 | dependencies:
613 | "@types/estree" "*"
614 |
615 | is-reference@^3.0.3:
616 | version "3.0.3"
617 | resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f"
618 | integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==
619 | dependencies:
620 | "@types/estree" "^1.0.6"
621 |
622 | isexe@^2.0.0:
623 | version "2.0.0"
624 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
625 | integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
626 |
627 | jackspeak@^4.0.1:
628 | version "4.0.2"
629 | resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015"
630 | integrity sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==
631 | dependencies:
632 | "@isaacs/cliui" "^8.0.2"
633 |
634 | jest-worker@^26.2.1:
635 | version "26.2.1"
636 | resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.2.1.tgz#5d630ab93f666b53f911615bc13e662b382bd513"
637 | integrity sha512-+XcGMMJDTeEGncRb5M5Zq9P7K4sQ1sirhjdOxsN1462h6lFo9w59bl2LVQmdGEEeU3m+maZCkS2Tcc9SfCHO4A==
638 | dependencies:
639 | "@types/node" "*"
640 | merge-stream "^2.0.0"
641 | supports-color "^7.0.0"
642 |
643 | js-tokens@^4.0.0:
644 | version "4.0.0"
645 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
646 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
647 |
648 | kleur@^4.1.4:
649 | version "4.1.4"
650 | resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
651 | integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
652 |
653 | lean-he@2.1.2:
654 | version "2.1.2"
655 | resolved "https://registry.yarnpkg.com/lean-he/-/lean-he-2.1.2.tgz#50c2422f0ca42f6737c9c1988b555cf00ebc712f"
656 | integrity sha512-g/cq01j/rnv7JWoxFmeLgJdd/CucksyDtS+pyepO89EdT0O4KfHJokOVz/xQ4mvjKJzcrj87Q3/s2ESou90WCQ==
657 |
658 | lilconfig@^3.1.1:
659 | version "3.1.3"
660 | resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4"
661 | integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
662 |
663 | livereload-js@^3.1.0:
664 | version "3.2.2"
665 | resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-3.2.2.tgz#fffb018fb8a8b06d366ca1b03af6048b8732d20f"
666 | integrity sha512-xhScbNeC687ZINjEf/bD+BMiPx4s4q0mehcLb3zCc8+mykOtmaBR4vqzyIV9rIGdG9JjHaT0LiFdscvivCjX1Q==
667 |
668 | livereload@^0.9.1:
669 | version "0.9.1"
670 | resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.9.1.tgz#65125dabdf2db4fd3f1169e953fe56e3bcc6f477"
671 | integrity sha512-9g7sua11kkyZNo2hLRCG3LuZZwqexoyEyecSlV8cAsfAVVCZqLzVir6XDqmH0r+Vzgnd5LrdHDMyjtFnJQLAYw==
672 | dependencies:
673 | chokidar "^3.3.0"
674 | livereload-js "^3.1.0"
675 | opts ">= 1.2.0"
676 | ws "^6.2.1"
677 |
678 | local-access@^1.0.1:
679 | version "1.0.1"
680 | resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.0.1.tgz#5121258146d64e869046c642ea4f1dd39ff942bb"
681 | integrity sha512-ykt2pgN0aqIy6KQC1CqdWTWkmUwNgaOS6dcpHVjyBJONA+Xi7AtSB1vuxC/U/0tjIP3wcRudwQk1YYzUvzk2bA==
682 |
683 | locate-character@^3.0.0:
684 | version "3.0.0"
685 | resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974"
686 | integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==
687 |
688 | lru-cache@^11.0.0:
689 | version "11.0.2"
690 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39"
691 | integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==
692 |
693 | magic-string@^0.30.11, magic-string@^0.30.3:
694 | version "0.30.12"
695 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.12.tgz#9eb11c9d072b9bcb4940a5b2c2e1a217e4ee1a60"
696 | integrity sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==
697 | dependencies:
698 | "@jridgewell/sourcemap-codec" "^1.5.0"
699 |
700 | merge-stream@^2.0.0:
701 | version "2.0.0"
702 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
703 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
704 |
705 | minimatch@^10.0.0:
706 | version "10.0.1"
707 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b"
708 | integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==
709 | dependencies:
710 | brace-expansion "^2.0.1"
711 |
712 | minipass@^7.1.2:
713 | version "7.1.2"
714 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
715 | integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
716 |
717 | mri@^1.1.0:
718 | version "1.1.4"
719 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
720 | integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==
721 |
722 | mrmime@^2.0.0:
723 | version "2.0.0"
724 | resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4"
725 | integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==
726 |
727 | nanoid@^3.3.11:
728 | version "3.3.11"
729 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
730 | integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
731 |
732 | normalize-path@^3.0.0, normalize-path@~3.0.0:
733 | version "3.0.0"
734 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
735 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
736 |
737 | "opts@>= 1.2.0":
738 | version "1.2.7"
739 | resolved "https://registry.yarnpkg.com/opts/-/opts-1.2.7.tgz#4de4721d592c96901dae623a438c988e9ea7779f"
740 | integrity sha512-hwZhzGGG/GQ7igxAVFOEun2N4fWul31qE9nfBdCnZGQCB5+L7tN9xZ+94B4aUpLOJx/of3zZs5XsuubayQYQjA==
741 |
742 | package-json-from-dist@^1.0.0:
743 | version "1.0.1"
744 | resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
745 | integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
746 |
747 | path-key@^3.1.0:
748 | version "3.1.1"
749 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
750 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
751 |
752 | path-parse@^1.0.7:
753 | version "1.0.7"
754 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
755 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
756 |
757 | path-scurry@^2.0.0:
758 | version "2.0.0"
759 | resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580"
760 | integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==
761 | dependencies:
762 | lru-cache "^11.0.0"
763 | minipass "^7.1.2"
764 |
765 | picocolors@^1.1.1:
766 | version "1.1.1"
767 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
768 | integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
769 |
770 | picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
771 | version "2.3.1"
772 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
773 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
774 |
775 | picomatch@^4.0.2:
776 | version "4.0.2"
777 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab"
778 | integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==
779 |
780 | postcss-load-config@^6.0.1:
781 | version "6.0.1"
782 | resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096"
783 | integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==
784 | dependencies:
785 | lilconfig "^3.1.1"
786 |
787 | postcss-selector-parser@^6.1.2:
788 | version "6.1.2"
789 | resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
790 | integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
791 | dependencies:
792 | cssesc "^3.0.0"
793 | util-deprecate "^1.0.2"
794 |
795 | postcss@^8.4.47, postcss@^8.5.4:
796 | version "8.5.4"
797 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.4.tgz#d61014ac00e11d5f58458ed7247d899bd65f99c0"
798 | integrity sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==
799 | dependencies:
800 | nanoid "^3.3.11"
801 | picocolors "^1.1.1"
802 | source-map-js "^1.2.1"
803 |
804 | purgecss@^7.0.2:
805 | version "7.0.2"
806 | resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-7.0.2.tgz#b7dccc3ead65a4301eed98e014793719a511c633"
807 | integrity sha512-4Ku8KoxNhOWi9X1XJ73XY5fv+I+hhTRedKpGs/2gaBKU8ijUiIKF/uyyIyh7Wo713bELSICF5/NswjcuOqYouQ==
808 | dependencies:
809 | commander "^12.1.0"
810 | glob "^11.0.0"
811 | postcss "^8.4.47"
812 | postcss-selector-parser "^6.1.2"
813 |
814 | randombytes@^2.1.0:
815 | version "2.1.0"
816 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
817 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
818 | dependencies:
819 | safe-buffer "^5.1.0"
820 |
821 | readdirp@~3.6.0:
822 | version "3.6.0"
823 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
824 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
825 | dependencies:
826 | picomatch "^2.2.1"
827 |
828 | resolve.exports@^2.0.0:
829 | version "2.0.0"
830 | resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.0.tgz#c1a0028c2d166ec2fbf7d0644584927e76e7400e"
831 | integrity sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==
832 |
833 | resolve@^1.22.1:
834 | version "1.22.8"
835 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
836 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
837 | dependencies:
838 | is-core-module "^2.13.0"
839 | path-parse "^1.0.7"
840 | supports-preserve-symlinks-flag "^1.0.0"
841 |
842 | rollup-plugin-livereload@^2.0.5:
843 | version "2.0.5"
844 | resolved "https://registry.yarnpkg.com/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.5.tgz#4747fa292a2cceb0c972c573d71b3d66b4252b37"
845 | integrity sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA==
846 | dependencies:
847 | livereload "^0.9.1"
848 |
849 | rollup-plugin-svelte@^7.2.2:
850 | version "7.2.2"
851 | resolved "https://registry.yarnpkg.com/rollup-plugin-svelte/-/rollup-plugin-svelte-7.2.2.tgz#2dc4dc9564ba7a92fb1ecb5a38db4a5ff5ac8408"
852 | integrity sha512-hgnIblTRewaBEVQD6N0Q43o+y6q1TmDRhBjaEzQCi50bs8TXqjc+d1zFZyE8tsfgcfNHZQzclh4RxlFUB85H8Q==
853 | dependencies:
854 | "@rollup/pluginutils" "^4.1.0"
855 | resolve.exports "^2.0.0"
856 |
857 | rollup-plugin-terser@^7.0.2:
858 | version "7.0.2"
859 | resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
860 | integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
861 | dependencies:
862 | "@babel/code-frame" "^7.10.4"
863 | jest-worker "^26.2.1"
864 | serialize-javascript "^4.0.0"
865 | terser "^5.0.0"
866 |
867 | rollup@^4.41.1:
868 | version "4.41.1"
869 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.41.1.tgz#46ddc1b33cf1b0baa99320d3b0b4973dc2253b6a"
870 | integrity sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==
871 | dependencies:
872 | "@types/estree" "1.0.7"
873 | optionalDependencies:
874 | "@rollup/rollup-android-arm-eabi" "4.41.1"
875 | "@rollup/rollup-android-arm64" "4.41.1"
876 | "@rollup/rollup-darwin-arm64" "4.41.1"
877 | "@rollup/rollup-darwin-x64" "4.41.1"
878 | "@rollup/rollup-freebsd-arm64" "4.41.1"
879 | "@rollup/rollup-freebsd-x64" "4.41.1"
880 | "@rollup/rollup-linux-arm-gnueabihf" "4.41.1"
881 | "@rollup/rollup-linux-arm-musleabihf" "4.41.1"
882 | "@rollup/rollup-linux-arm64-gnu" "4.41.1"
883 | "@rollup/rollup-linux-arm64-musl" "4.41.1"
884 | "@rollup/rollup-linux-loongarch64-gnu" "4.41.1"
885 | "@rollup/rollup-linux-powerpc64le-gnu" "4.41.1"
886 | "@rollup/rollup-linux-riscv64-gnu" "4.41.1"
887 | "@rollup/rollup-linux-riscv64-musl" "4.41.1"
888 | "@rollup/rollup-linux-s390x-gnu" "4.41.1"
889 | "@rollup/rollup-linux-x64-gnu" "4.41.1"
890 | "@rollup/rollup-linux-x64-musl" "4.41.1"
891 | "@rollup/rollup-win32-arm64-msvc" "4.41.1"
892 | "@rollup/rollup-win32-ia32-msvc" "4.41.1"
893 | "@rollup/rollup-win32-x64-msvc" "4.41.1"
894 | fsevents "~2.3.2"
895 |
896 | sade@^1.6.0:
897 | version "1.7.3"
898 | resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.3.tgz#a217ccc4fb4abb2d271648bf48f6628b2636fa1b"
899 | integrity sha512-m4BctppMvJ60W1dXnHq7jMmFe3hPJZDAH85kQ3ACTo7XZNVUuTItCQ+2HfyaMeV5cKrbw7l4vD/6We3GBxvdJw==
900 | dependencies:
901 | mri "^1.1.0"
902 |
903 | safe-buffer@^5.1.0:
904 | version "5.2.1"
905 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
906 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
907 |
908 | semiver@^1.0.0:
909 | version "1.1.0"
910 | resolved "https://registry.yarnpkg.com/semiver/-/semiver-1.1.0.tgz#9c97fb02c21c7ce4fcf1b73e2c7a24324bdddd5f"
911 | integrity sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==
912 |
913 | serialize-javascript@^4.0.0:
914 | version "4.0.0"
915 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
916 | integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
917 | dependencies:
918 | randombytes "^2.1.0"
919 |
920 | shebang-command@^2.0.0:
921 | version "2.0.0"
922 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
923 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
924 | dependencies:
925 | shebang-regex "^3.0.0"
926 |
927 | shebang-regex@^3.0.0:
928 | version "3.0.0"
929 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
930 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
931 |
932 | signal-exit@^4.0.1:
933 | version "4.1.0"
934 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
935 | integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
936 |
937 | sirv-cli@^3.0.1:
938 | version "3.0.1"
939 | resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-3.0.1.tgz#9a53e4fa85fdc08d54a76fd76a7c866cd4c3988b"
940 | integrity sha512-ICXaF2u6IQhLZ0EXF6nqUF4YODfSQSt+mGykt4qqO5rY+oIiwdg7B8w2PVDBJlQulaS2a3J8666CUoDoAuCGvg==
941 | dependencies:
942 | console-clear "^1.1.0"
943 | get-port "^5.1.1"
944 | kleur "^4.1.4"
945 | local-access "^1.0.1"
946 | sade "^1.6.0"
947 | semiver "^1.0.0"
948 | sirv "^3.0.0"
949 | tinydate "^1.0.0"
950 |
951 | sirv@^3.0.0:
952 | version "3.0.0"
953 | resolved "https://registry.yarnpkg.com/sirv/-/sirv-3.0.0.tgz#f8d90fc528f65dff04cb597a88609d4e8a4361ce"
954 | integrity sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==
955 | dependencies:
956 | "@polka/url" "^1.0.0-next.24"
957 | mrmime "^2.0.0"
958 | totalist "^3.0.0"
959 |
960 | source-map-js@^1.2.1:
961 | version "1.2.1"
962 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
963 | integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
964 |
965 | source-map-support@~0.5.20:
966 | version "0.5.21"
967 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
968 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
969 | dependencies:
970 | buffer-from "^1.0.0"
971 | source-map "^0.6.0"
972 |
973 | source-map@^0.6.0:
974 | version "0.6.1"
975 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
976 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
977 |
978 | "string-width-cjs@npm:string-width@^4.2.0":
979 | version "4.2.3"
980 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
981 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
982 | dependencies:
983 | emoji-regex "^8.0.0"
984 | is-fullwidth-code-point "^3.0.0"
985 | strip-ansi "^6.0.1"
986 |
987 | string-width@^4.1.0:
988 | version "4.2.3"
989 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
990 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
991 | dependencies:
992 | emoji-regex "^8.0.0"
993 | is-fullwidth-code-point "^3.0.0"
994 | strip-ansi "^6.0.1"
995 |
996 | string-width@^5.0.1, string-width@^5.1.2:
997 | version "5.1.2"
998 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
999 | integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
1000 | dependencies:
1001 | eastasianwidth "^0.2.0"
1002 | emoji-regex "^9.2.2"
1003 | strip-ansi "^7.0.1"
1004 |
1005 | "strip-ansi-cjs@npm:strip-ansi@^6.0.1":
1006 | version "6.0.1"
1007 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1008 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
1009 | dependencies:
1010 | ansi-regex "^5.0.1"
1011 |
1012 | strip-ansi@^6.0.0, strip-ansi@^6.0.1:
1013 | version "6.0.1"
1014 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1015 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
1016 | dependencies:
1017 | ansi-regex "^5.0.1"
1018 |
1019 | strip-ansi@^7.0.1:
1020 | version "7.1.0"
1021 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
1022 | integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
1023 | dependencies:
1024 | ansi-regex "^6.0.1"
1025 |
1026 | supports-color@^5.3.0:
1027 | version "5.5.0"
1028 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1029 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1030 | dependencies:
1031 | has-flag "^3.0.0"
1032 |
1033 | supports-color@^7.0.0:
1034 | version "7.1.0"
1035 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
1036 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
1037 | dependencies:
1038 | has-flag "^4.0.0"
1039 |
1040 | supports-preserve-symlinks-flag@^1.0.0:
1041 | version "1.0.0"
1042 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
1043 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
1044 |
1045 | svelte-preprocess@^6.0.3:
1046 | version "6.0.3"
1047 | resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-6.0.3.tgz#fdc1f9dc41b6f22bf8b1f059e9f21eaaae181eeb"
1048 | integrity sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA==
1049 |
1050 | svelte-xstate@^1.0.1:
1051 | version "1.0.1"
1052 | resolved "https://registry.yarnpkg.com/svelte-xstate/-/svelte-xstate-1.0.1.tgz#e04b75700ec611b057bf8a14b8ce6f35a7d7d929"
1053 | integrity sha512-k/U5goMuPnfkNIo2BlwBaHejScebULsg1RmlVgosbslxvw9FRSzV4NYzXtEWyowspJC9O9g9iVQ4WkRFXMSRlQ==
1054 | dependencies:
1055 | svelte "^3.12.1"
1056 | xstate "^4.6.7"
1057 |
1058 | svelte@^3.12.1:
1059 | version "3.59.2"
1060 | resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.59.2.tgz#a137b28e025a181292b2ae2e3dca90bf8ec73aec"
1061 | integrity sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==
1062 |
1063 | svelte@^5.33.14:
1064 | version "5.33.14"
1065 | resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.33.14.tgz#e4fcdb01f00361373e46763947b591f878cf24fc"
1066 | integrity sha512-kRlbhIlMTijbFmVDQFDeKXPLlX1/ovXwV0I162wRqQhRcygaqDIcu1d/Ese3H2uI+yt3uT8E7ndgDthQv5v5BA==
1067 | dependencies:
1068 | "@ampproject/remapping" "^2.3.0"
1069 | "@jridgewell/sourcemap-codec" "^1.5.0"
1070 | "@sveltejs/acorn-typescript" "^1.0.5"
1071 | "@types/estree" "^1.0.5"
1072 | acorn "^8.12.1"
1073 | aria-query "^5.3.1"
1074 | axobject-query "^4.1.0"
1075 | clsx "^2.1.1"
1076 | esm-env "^1.2.1"
1077 | esrap "^1.4.6"
1078 | is-reference "^3.0.3"
1079 | locate-character "^3.0.0"
1080 | magic-string "^0.30.11"
1081 | zimmerframe "^1.1.2"
1082 |
1083 | tailwindcss@4.1.8:
1084 | version "4.1.8"
1085 | resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.8.tgz#5d66d095ee7d82f03d6dbc6158bc248e064a5c05"
1086 | integrity sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og==
1087 |
1088 | terser@^5.0.0:
1089 | version "5.14.2"
1090 | resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
1091 | integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
1092 | dependencies:
1093 | "@jridgewell/source-map" "^0.3.2"
1094 | acorn "^8.5.0"
1095 | commander "^2.20.0"
1096 | source-map-support "~0.5.20"
1097 |
1098 | tinydate@^1.0.0:
1099 | version "1.2.0"
1100 | resolved "https://registry.yarnpkg.com/tinydate/-/tinydate-1.2.0.tgz#36b4bb02715f89743f3ef9073d3573d005a28d0e"
1101 | integrity sha512-3GwPk8VhDFnUZ2TrgkhXJs6hcMAIIw4x/xkz+ayK6dGoQmp2nUwKzBXK0WnMsqkh6vfUhpqQicQF3rbshfyJkg==
1102 |
1103 | to-regex-range@^5.0.1:
1104 | version "5.0.1"
1105 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1106 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1107 | dependencies:
1108 | is-number "^7.0.0"
1109 |
1110 | totalist@^3.0.0:
1111 | version "3.0.1"
1112 | resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
1113 | integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==
1114 |
1115 | util-deprecate@^1.0.2:
1116 | version "1.0.2"
1117 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1118 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
1119 |
1120 | which@^2.0.1:
1121 | version "2.0.2"
1122 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
1123 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
1124 | dependencies:
1125 | isexe "^2.0.0"
1126 |
1127 | "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
1128 | version "7.0.0"
1129 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1130 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
1131 | dependencies:
1132 | ansi-styles "^4.0.0"
1133 | string-width "^4.1.0"
1134 | strip-ansi "^6.0.0"
1135 |
1136 | wrap-ansi@^8.1.0:
1137 | version "8.1.0"
1138 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
1139 | integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
1140 | dependencies:
1141 | ansi-styles "^6.1.0"
1142 | string-width "^5.0.1"
1143 | strip-ansi "^7.0.1"
1144 |
1145 | ws@^6.2.1:
1146 | version "6.2.3"
1147 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee"
1148 | integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==
1149 | dependencies:
1150 | async-limiter "~1.0.0"
1151 |
1152 | xstate@4.38.3, xstate@^4.6.7:
1153 | version "4.38.3"
1154 | resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.38.3.tgz#4e15e7ad3aa0ca1eea2010548a5379966d8f1075"
1155 | integrity sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==
1156 |
1157 | zimmerframe@^1.1.2:
1158 | version "1.1.2"
1159 | resolved "https://registry.yarnpkg.com/zimmerframe/-/zimmerframe-1.1.2.tgz#5b75f1fa83b07ae2a428d51e50f58e2ae6855e5e"
1160 | integrity sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==
1161 |
--------------------------------------------------------------------------------
/trivia-game-vue/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | insert_final_newline = true
9 |
10 |
--------------------------------------------------------------------------------
/trivia-game-vue/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/trivia-game-vue/.node-version:
--------------------------------------------------------------------------------
1 | 10.16.3
2 |
3 |
--------------------------------------------------------------------------------
/trivia-game-vue/.nvmrc:
--------------------------------------------------------------------------------
1 | 10.16.3
2 |
3 |
--------------------------------------------------------------------------------
/trivia-game-vue/.prettierignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | .env.local
6 | .env.*.local
7 |
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 |
12 | .idea
13 | .vscode
14 | *.suo
15 | *.ntvs*
16 | *.njsproj
17 | *.sln
18 | *.sw?
19 |
20 |
--------------------------------------------------------------------------------
/trivia-game-vue/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "avoid",
3 | "bracketSpacing": false,
4 | "htmlWhitespaceSensitivity": "css",
5 | "insertPragma": false,
6 | "jsxBracketSameLine": false,
7 | "jsxSingleQuote": true,
8 | "printWidth": 80,
9 | "proseWrap": "always",
10 | "requirePragma": false,
11 | "semi": false,
12 | "singleQuote": true,
13 | "tabWidth": 2,
14 | "trailingComma": "all",
15 | "useTabs": false
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/trivia-game-vue/README.md:
--------------------------------------------------------------------------------
1 | # Trivia Game
2 |
3 | This example showcases several state machine concepts including guards,
4 | transient functions, and invoking services.
5 |
6 | [Trivia Game machine visualized](https://xstate.js.org/viz/?gist=3abe97296e6d6cebcbda9c903d6da068)
7 |
8 | ## Running Locally
9 |
10 | 1. After cloning and navigating into the `trivia-game-vue` directory, execute:
11 |
12 | ```
13 | yarn && yarn test
14 | ```
15 |
16 | or
17 |
18 | ```
19 | npm install && npm t
20 | ```
21 |
22 | This will install dependencies and run tests to verify no issues
23 |
24 | 2. Start the application by executing:
25 |
26 | ```
27 | yarn start
28 | ```
29 |
30 | or
31 |
32 | ```
33 | npm start
34 | ```
35 |
--------------------------------------------------------------------------------
/trivia-game-vue/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/trivia-game-vue/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | base = ""
3 | command = "yarn build"
4 | publish = "/dist"
5 |
--------------------------------------------------------------------------------
/trivia-game-vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "trivia-game-vue",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "build": "vue-cli-service build",
7 | "lint": "vue-cli-service lint",
8 | "start": "vue-cli-service serve"
9 | },
10 | "dependencies": {
11 | "core-js": "3.42.0",
12 | "lean-he": "2.1.2",
13 | "tailwindcss": "4.1.8",
14 | "vue": "3.5.16",
15 | "xstate": "5.19.4"
16 | },
17 | "devDependencies": {
18 | "@vue/cli-plugin-babel": "5.0.8",
19 | "@vue/cli-plugin-eslint": "5.0.8",
20 | "@vue/cli-service": "5.0.8",
21 | "babel-eslint": "10.1.0",
22 | "eslint": "9.28.0",
23 | "eslint-plugin-vue": "9.33.0",
24 | "vue-template-compiler": "2.7.16"
25 | },
26 | "eslintConfig": {
27 | "root": true,
28 | "env": {
29 | "node": true
30 | },
31 | "extends": [
32 | "plugin:vue/essential",
33 | "eslint:recommended"
34 | ],
35 | "rules": {},
36 | "parserOptions": {
37 | "parser": "babel-eslint"
38 | }
39 | },
40 | "browserslist": [
41 | "> 1%",
42 | "last 2 versions"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/trivia-game-vue/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "plugins": [
3 | require('tailwindcss'),
4 | require('autoprefixer'),
5 | ]
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/trivia-game-vue/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevanB/xstate-examples/24fc1abf994ddfbca3ee59a7607fdcc374d13a9f/trivia-game-vue/public/favicon.ico
--------------------------------------------------------------------------------
/trivia-game-vue/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | trivia-game-vue
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
29 |
30 |
31 |
32 |
33 |
34 |
71 |
72 |
93 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/assets/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 |
3 | @tailwind components;
4 |
5 | @tailwind utilities;
6 |
7 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/Actions.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
24 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/Button.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
18 |
19 |
34 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/Container.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/CorrectIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
15 |
24 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/H1.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/P.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/TextContainer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/Toggle.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
54 |
55 |
68 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/components/WrongIcon.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
18 |
27 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/machine.js:
--------------------------------------------------------------------------------
1 | import {assign, Machine} from 'xstate'
2 | import {fetchAndNormalizeQuizData} from './utils'
3 |
4 | const machine = Machine(
5 | {
6 | id: 'Machine',
7 | initial: 'welcome',
8 | context: {
9 | currentQuestion: 0,
10 | currentQuestionDisplay: 1,
11 | questions: [],
12 | totalCorrectAnswers: 0,
13 | },
14 | states: {
15 | welcome: {
16 | on: {
17 | START_QUIZ: 'loading',
18 | },
19 | },
20 | loading: {
21 | invoke: {
22 | id: 'getQuizData',
23 | src: 'fetchAndNormalizeQuizData',
24 | onDone: {
25 | target: 'quiz',
26 | actions: assign({
27 | questions: (_, event) => event.data,
28 | }),
29 | },
30 | onError: {
31 | target: 'failure',
32 | },
33 | },
34 | },
35 | failure: {
36 | on: {
37 | RETRY: 'loading',
38 | START_OVER: 'welcome',
39 | },
40 | },
41 | quiz: {
42 | on: {
43 | '': {
44 | target: 'results',
45 | actions: [],
46 | cond: 'allQuestionsAnswered',
47 | },
48 | ANSWER_FALSE: {
49 | actions: 'updateAnswer',
50 | },
51 | ANSWER_TRUE: {
52 | actions: 'updateAnswer',
53 | },
54 | },
55 | },
56 | results: {
57 | on: {
58 | PLAY_AGAIN: 'welcome',
59 | },
60 | exit: 'resetGame',
61 | },
62 | },
63 | },
64 | {
65 | actions: {
66 | resetGame: assign({
67 | currentQuestion: 0,
68 | currentQuestionDisplay: 1,
69 | questions: [],
70 | totalCorrectAnswers: 0,
71 | }),
72 | updateAnswer: assign((ctx, event) => ({
73 | questions: [
74 | ...ctx.questions.slice(0, ctx.currentQuestion),
75 | {
76 | ...ctx.questions[ctx.currentQuestion],
77 | userAnswer: event.answer,
78 | correct:
79 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer,
80 | },
81 | ...ctx.questions.slice(ctx.currentQuestion + 1),
82 | ],
83 | totalCorrectAnswers:
84 | ctx.questions[ctx.currentQuestion].correctAnswer === event.answer
85 | ? (ctx.totalCorrectAnswers += 1)
86 | : ctx.totalCorrectAnswers,
87 | currentQuestion: ctx.currentQuestion += 1,
88 | currentQuestionDisplay: ctx.currentQuestionDisplay += 1,
89 | })),
90 | },
91 | guards: {
92 | allQuestionsAnswered: ctx => {
93 | return (
94 | ctx.questions.filter(
95 | (question) => question.correct !== undefined,
96 | ).length === ctx.questions.length && true
97 | )
98 | },
99 | },
100 | services: {
101 | fetchAndNormalizeQuizData: () => fetchAndNormalizeQuizData(),
102 | },
103 | },
104 | )
105 |
106 | export default machine
107 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 |
4 | import './assets/tailwind.css'
5 |
6 | Vue.config.productionTip = false
7 |
8 | new Vue({
9 | render: h => h(App),
10 | }).$mount('#app')
11 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/screens/Failure.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Failure!
4 |
5 | Looks like there where a problem.
6 | You can retry loading the game or start over.
7 |
8 |
9 |
12 |
15 |
16 |
17 |
18 |
19 |
47 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/screens/Loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Loading...
4 |
5 |
6 |
7 |
19 |
20 |
25 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/screens/Quiz.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{question.category}}
4 |
5 | {{question.question}}
6 |
7 |
10 |
13 |
14 |
15 |
16 | {{ currentQuestionNumber }} of {{ totalQuestions }}
17 |
18 |
19 |
20 |
21 |
52 |
53 |
78 |
79 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/screens/Results.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | You scored
5 |
6 | {{totalCorrectAnswers}} / {{totalQuestions}}
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{question.question}}
19 |
20 |
21 |
24 |
25 |
26 |
27 |
55 |
56 |
69 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/screens/Welcome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Welcome to the Trivia Challenge
4 |
5 | You will be presented with 10 true or false questions.
6 | Can you score 100%?
7 |
8 |
11 |
12 |
13 |
14 |
37 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/utils/fetchAndNormalizeQuizData.js:
--------------------------------------------------------------------------------
1 | import {fetchQuizData, normalizeQuizData} from '.'
2 |
3 | export const fetchAndNormalizeQuizData = async () => {
4 | try {
5 | const data = await fetchQuizData()
6 | return Promise.resolve(normalizeQuizData(data.results))
7 | } catch (error) {
8 | return Promise.reject(error)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/utils/fetchQuizData.js:
--------------------------------------------------------------------------------
1 | export const fetchQuizData = () =>
2 | fetch(
3 | `https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`,
4 | ).then(response =>
5 | response.json());
6 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/utils/index.js:
--------------------------------------------------------------------------------
1 | export * from './fetchAndNormalizeQuizData'
2 | export * from './fetchQuizData'
3 | export * from './normalizeQuizData'
4 |
--------------------------------------------------------------------------------
/trivia-game-vue/src/utils/normalizeQuizData.js:
--------------------------------------------------------------------------------
1 | import decode from 'lean-he/decode'
2 |
3 | export const normalizeQuizData = data =>
4 | data.reduce(
5 | (acc, obj) => [
6 | ...acc,
7 | {
8 | category: decode(obj.category),
9 | question: decode(obj.question),
10 | correctAnswer: obj.correct_answer === 'True' ? true : false,
11 | userAnswer: undefined,
12 | correct: undefined,
13 | },
14 | ],
15 | [],
16 | )
17 |
--------------------------------------------------------------------------------