├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE.md
├── README.md
├── archive
├── docs
│ ├── .gitattributes
│ ├── .gitignore
│ ├── LICENSE
│ ├── archive
│ │ ├── events-old.mdx
│ │ ├── learn
│ │ │ ├── actions.mdx
│ │ │ ├── async-events.mdx
│ │ │ ├── auto-events.mdx
│ │ │ ├── basics.mdx
│ │ │ ├── conditions.mdx
│ │ │ ├── data.mdx
│ │ │ ├── event-handlers.mdx
│ │ │ ├── events.mdx
│ │ │ ├── intro.mdx
│ │ │ ├── repeat-events.mdx
│ │ │ ├── results.mdx
│ │ │ ├── state.mdx
│ │ │ ├── states.mdx
│ │ │ ├── tips-and-tricks.mdx
│ │ │ ├── transition-events.mdx
│ │ │ ├── transitions.mdx
│ │ │ ├── type-support.png
│ │ │ └── values.mdx
│ │ ├── react-hook.mdx
│ │ ├── state.mdx
│ │ ├── states-old-1.mdx
│ │ ├── states-old.mdx
│ │ ├── the-problem.mdx
│ │ ├── tips.mdx
│ │ └── updates.mdx
│ ├── content
│ │ ├── definitions
│ │ │ ├── action.mdx
│ │ │ ├── active.mdx
│ │ │ ├── async.mdx
│ │ │ ├── auto-event.mdx
│ │ │ ├── branch-state.mdx
│ │ │ ├── condition.mdx
│ │ │ ├── configuration.mdx
│ │ │ ├── data.mdx
│ │ │ ├── do.mdx
│ │ │ ├── event-handler.mdx
│ │ │ ├── event.mdx
│ │ │ ├── if-any.mdx
│ │ │ ├── if.mdx
│ │ │ ├── inactive.mdx
│ │ │ ├── initial-state.mdx
│ │ │ ├── is-in.mdx
│ │ │ ├── machine.mdx
│ │ │ ├── on-enter.mdx
│ │ │ ├── on-event-complete.mdx
│ │ │ ├── on-event.mdx
│ │ │ ├── on-exit.mdx
│ │ │ ├── parallel-state.mdx
│ │ │ ├── payload.mdx
│ │ │ ├── previous.mdx
│ │ │ ├── repeat.mdx
│ │ │ ├── restore.mdx
│ │ │ ├── result.mdx
│ │ │ ├── send.mdx
│ │ │ ├── state-tree.mdx
│ │ │ ├── state.mdx
│ │ │ ├── transition.mdx
│ │ │ ├── unless.mdx
│ │ │ ├── update.mdx
│ │ │ └── when-in.mdx
│ │ ├── designing-state.mdx
│ │ ├── docs
│ │ │ ├── api
│ │ │ │ ├── createDesign.mdx
│ │ │ │ ├── createSelectorHook.mdx
│ │ │ │ ├── createState.mdx
│ │ │ │ ├── design
│ │ │ │ │ ├── event-handlers.mdx
│ │ │ │ │ ├── index.mdx
│ │ │ │ │ └── state-nodes.mdx
│ │ │ │ ├── state
│ │ │ │ │ └── index.mdx
│ │ │ │ ├── useSelector.mdx
│ │ │ │ └── useStateDesigner.mdx
│ │ │ ├── concepts.mdx
│ │ │ ├── examples.mdx
│ │ │ ├── framer-motion.mdx
│ │ │ ├── glossary.mdx
│ │ │ ├── packages
│ │ │ │ ├── core.mdx
│ │ │ │ └── react.mdx
│ │ │ ├── quick-start.mdx
│ │ │ └── usage
│ │ │ │ ├── javascript.mdx
│ │ │ │ ├── react.mdx
│ │ │ │ └── typescript.mdx
│ │ ├── examples
│ │ │ ├── breakout.mdx
│ │ │ ├── calculator.mdx
│ │ │ ├── counter.mdx
│ │ │ ├── dogs.mdx
│ │ │ ├── drawing.mdx
│ │ │ ├── input-save-cancel.mdx
│ │ │ ├── input.mdx
│ │ │ ├── localStorageCounter.mdx
│ │ │ ├── snake.mdx
│ │ │ ├── stopwatch.mdx
│ │ │ ├── tetris.mdx
│ │ │ ├── tiles.mdx
│ │ │ ├── timer.mdx
│ │ │ ├── todo.mdx
│ │ │ ├── todos.mdx
│ │ │ └── toggle.mdx
│ │ ├── index.mdx
│ │ └── nav
│ │ │ ├── 404.mdx
│ │ │ ├── footer.mdx
│ │ │ ├── header.mdx
│ │ │ └── sidebar.mdx
│ ├── gatsby-browser.js
│ ├── gatsby-config.js
│ ├── gatsby-node.js
│ ├── gatsby-ssr.js
│ ├── index.js
│ ├── package.json
│ ├── src
│ │ ├── components.js
│ │ ├── components
│ │ │ ├── .eslintrc
│ │ │ ├── 404.js
│ │ │ ├── CodeBlock.js
│ │ │ ├── codesandbox.js
│ │ │ ├── counter-toggle.js
│ │ │ ├── doc.js
│ │ │ ├── footer.js
│ │ │ ├── header-link.js
│ │ │ ├── header.js
│ │ │ ├── inline-link.js
│ │ │ ├── layout.js
│ │ │ ├── live-view.js
│ │ │ ├── lockup.svg
│ │ │ ├── menu-button.js
│ │ │ ├── nav-link.js
│ │ │ ├── page-links.js
│ │ │ ├── seo.js
│ │ │ ├── sidebar-link.js
│ │ │ ├── sidenav.js
│ │ │ ├── snippets.js
│ │ │ └── youtube.js
│ │ ├── hooks
│ │ │ └── useScrollPosition.js
│ │ ├── index.js
│ │ ├── styles.css
│ │ ├── templates
│ │ │ ├── 404.js
│ │ │ └── doc.js
│ │ └── theme.js
│ └── static
│ │ ├── atarist8x16systemfont.ttf
│ │ └── icon.png
├── editor
│ └── editor
│ │ ├── ActionOptionsButton.tsx
│ │ ├── CodeEditor.tsx
│ │ ├── CollectionsPanel.tsx
│ │ ├── ConditionOptionsButton.tsx
│ │ ├── DragDropList.tsx
│ │ ├── EventOptionsButton.tsx
│ │ ├── Segment.tsx
│ │ ├── Simulation.tsx
│ │ ├── StateListItem.tsx
│ │ ├── StateOptionsButton.tsx
│ │ ├── ValueOptionsButton.tsx
│ │ ├── content-panel
│ │ ├── ContentPanel.tsx
│ │ ├── DataEditor.tsx
│ │ ├── EventItem.tsx
│ │ └── StateBranchItem.tsx
│ │ ├── index.tsx
│ │ ├── panel
│ │ ├── Panel.tsx
│ │ ├── PanelHeading.tsx
│ │ ├── PanelItem.tsx
│ │ ├── PanelSelectItem.tsx
│ │ ├── ResizePanel.tsx
│ │ └── ResizePanelRight.tsx
│ │ ├── shared.tsx
│ │ ├── state-panel
│ │ ├── StateEditor.tsx
│ │ ├── StateNode.tsx
│ │ ├── StatePanel.tsx
│ │ └── event-handler
│ │ │ ├── EventHandler.tsx
│ │ │ ├── EventHandlerLink.tsx
│ │ │ └── HandlerOptionsButton.tsx
│ │ ├── state.ts
│ │ ├── theme.tsx
│ │ └── types.ts
├── example
│ ├── LICENSE
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── fonts
│ │ │ └── gameboy.ttf
│ │ ├── images
│ │ │ ├── bricks.svg
│ │ │ ├── ghost.svg
│ │ │ ├── i.svg
│ │ │ ├── j.svg
│ │ │ ├── l.svg
│ │ │ ├── o.svg
│ │ │ ├── s.svg
│ │ │ ├── t.svg
│ │ │ └── z.svg
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.tsx
│ │ ├── components
│ │ │ ├── Matrix
│ │ │ │ ├── Cell.tsx
│ │ │ │ ├── Container.tsx
│ │ │ │ ├── FallingPiece.tsx
│ │ │ │ ├── GhostPiece.tsx
│ │ │ │ └── NextPiece.tsx
│ │ │ ├── Next.tsx
│ │ │ ├── Playfield.tsx
│ │ │ └── Stats.tsx
│ │ ├── game
│ │ │ ├── index.ts
│ │ │ ├── static.ts
│ │ │ └── types.ts
│ │ ├── index.tsx
│ │ ├── react-app-env.d.ts
│ │ ├── scenes
│ │ │ ├── Playing.tsx
│ │ │ ├── Start.tsx
│ │ │ ├── Tests
│ │ │ │ ├── Nested.tsx
│ │ │ │ ├── Switches.tsx
│ │ │ │ └── Todo.tsx
│ │ │ └── Todos.tsx
│ │ └── styles.css
│ └── tsconfig.json
├── tutorials
│ ├── .gitignore
│ ├── jest.config.js
│ ├── jsconfig.json
│ ├── package.json
│ ├── public
│ │ ├── index.html
│ │ ├── lockup-dark.svg
│ │ └── lockup-light.svg
│ ├── sandbox.config.json
│ └── src
│ │ ├── App.js
│ │ ├── components
│ │ └── index.js
│ │ ├── index.js
│ │ ├── routes.js
│ │ ├── setupTests.js
│ │ ├── theme.js
│ │ ├── tutorials
│ │ ├── 1_counter
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 2_toggle
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 3_input
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 4_todo
│ │ │ ├── complete
│ │ │ │ ├── Todo.js
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ ├── Todo.js
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 5_todos
│ │ │ ├── complete
│ │ │ │ ├── Todo.js
│ │ │ │ ├── globalState.js
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ ├── Todo.js
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 6_stopwatch
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 7_timer
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── 8_tiles
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── breakout
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── calculator
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── dogs
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── dopewars
│ │ │ ├── complete
│ │ │ │ ├── game.js
│ │ │ │ ├── index.js
│ │ │ │ └── static.js
│ │ │ ├── starter
│ │ │ │ ├── Todo.js
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── drawing
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── player
│ │ │ ├── complete
│ │ │ │ └── index.js
│ │ │ ├── starter
│ │ │ │ └── index.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ ├── snake
│ │ │ ├── complete
│ │ │ │ ├── index.js
│ │ │ │ └── input.js
│ │ │ ├── starter
│ │ │ │ ├── index.js
│ │ │ │ └── input.js
│ │ │ └── tests
│ │ │ │ ├── complete.test.js
│ │ │ │ ├── index.js
│ │ │ │ └── starter.test.js
│ │ └── tetris
│ │ │ ├── complete
│ │ │ ├── game.js
│ │ │ ├── index.js
│ │ │ └── static.js
│ │ │ ├── starter
│ │ │ ├── index.js
│ │ │ └── static.js
│ │ │ └── tests
│ │ │ ├── complete.test.js
│ │ │ ├── index.js
│ │ │ └── starter.test.js
│ │ └── utils.js
└── viewer
│ ├── .babelrc
│ ├── .gitignore
│ ├── README.md
│ ├── auth
│ ├── firebaseAdmin.tsx
│ ├── initFirebase.tsx
│ └── useUser.tsx
│ ├── decs.d.ts
│ ├── next-env.d.ts
│ ├── next.config.js
│ ├── package.json
│ ├── pages
│ ├── [oid]
│ │ └── [pid]
│ │ │ ├── chart.tsx
│ │ │ ├── index.tsx
│ │ │ ├── preview.tsx
│ │ │ └── static-preview.tsx
│ ├── _app.js
│ ├── _document.js
│ ├── admin.tsx
│ ├── api
│ │ ├── [oid]
│ │ │ ├── [pid]
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ └── admin.tsx
│ ├── auth.tsx
│ ├── index.tsx
│ ├── styles.css
│ └── user.tsx
│ ├── public
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── browserconfig.xml
│ ├── cursor.svg
│ ├── discord-large.svg
│ ├── discord.svg
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── lockup_dark.svg
│ ├── lockup_light.svg
│ ├── mstile-150x150.png
│ ├── safari-pinned-tab.svg
│ ├── sd-icon.svg
│ ├── site.webmanifest
│ ├── splash_dark.png
│ ├── splash_light.png
│ └── vercel.svg
│ ├── site
│ ├── 404.tsx
│ ├── admin
│ │ └── index.tsx
│ ├── app
│ │ ├── components
│ │ │ ├── chart
│ │ │ │ ├── branch-node.tsx
│ │ │ │ ├── canvas-overlay.tsx
│ │ │ │ ├── canvas.tsx
│ │ │ │ ├── helpers.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── initial-marker.tsx
│ │ │ │ ├── leaf-node.tsx
│ │ │ │ ├── node-events.tsx
│ │ │ │ ├── node-heading.tsx
│ │ │ │ ├── parallel-divider.tsx
│ │ │ │ ├── parallel-node.tsx
│ │ │ │ └── state-node.tsx
│ │ │ ├── code
│ │ │ │ ├── code-editor.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── jsx-editor.tsx
│ │ │ │ ├── monaco.tsx
│ │ │ │ ├── save-row.tsx
│ │ │ │ ├── state-editor.tsx
│ │ │ │ ├── static-editor.tsx
│ │ │ │ ├── tabbed-editor.tsx
│ │ │ │ ├── tests-editor.tsx
│ │ │ │ └── theme-editor.tsx
│ │ │ ├── color-mode-toggle.tsx
│ │ │ ├── column.tsx
│ │ │ ├── content
│ │ │ │ ├── content-row-item.tsx
│ │ │ │ ├── content-section.tsx
│ │ │ │ ├── event-item.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── payload.tsx
│ │ │ │ └── state-item.tsx
│ │ │ ├── controls.tsx
│ │ │ ├── details
│ │ │ │ ├── data.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── log.tsx
│ │ │ │ ├── tests
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── test.tsx
│ │ │ │ └── values.tsx
│ │ │ ├── drag-handle-horizontal.tsx
│ │ │ ├── drag-handle-vertical.tsx
│ │ │ ├── drag-handle.tsx
│ │ │ ├── footer-column.tsx
│ │ │ ├── icon-select.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── main
│ │ │ │ ├── index.tsx
│ │ │ │ └── reset-button.tsx
│ │ │ ├── menu.tsx
│ │ │ ├── preview
│ │ │ │ └── index.tsx
│ │ │ ├── tabs.tsx
│ │ │ ├── title.tsx
│ │ │ └── value-input.tsx
│ │ ├── hooks
│ │ │ ├── gestures.tsx
│ │ │ └── useFirebaseCode.tsx
│ │ ├── index.tsx
│ │ ├── states
│ │ │ ├── createCodeEditorState.tsx
│ │ │ ├── createSimpleEditorState.tsx
│ │ │ ├── highlights.tsx
│ │ │ └── index.tsx
│ │ └── utils.tsx
│ ├── chart-page
│ │ └── index.tsx
│ ├── firebase-auth.tsx
│ ├── index.tsx
│ ├── landing-page
│ │ └── index.tsx
│ ├── loading-screen.tsx
│ ├── not-found.tsx
│ ├── preview-page
│ │ └── index.tsx
│ ├── static-preview-page
│ │ └── index.tsx
│ ├── static
│ │ ├── colors.tsx
│ │ ├── defaults.tsx
│ │ ├── example-links.tsx
│ │ ├── examples.tsx
│ │ ├── monaco-theme.json
│ │ └── scope-utils.tsx
│ ├── user
│ │ ├── index.tsx
│ │ └── layout.tsx
│ └── viewer.tsx
│ ├── theme.tsx
│ ├── todo.md
│ ├── tsconfig.json
│ ├── typings.worker.ts
│ └── utils
│ └── firebase.tsx
├── example
├── LICENSE.md
├── README.md
├── package.json
├── scripts
│ └── dev.mjs
├── src
│ ├── app.tsx
│ ├── constants.ts
│ ├── index.html
│ ├── index.tsx
│ ├── state.ts
│ └── styles.css
├── tsconfig.json
└── yarn.lock
├── lerna.json
├── package.json
├── packages
├── core
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── README.md
│ ├── docs
│ │ ├── .nojekyll
│ │ ├── assets
│ │ │ ├── highlight.css
│ │ │ ├── icons.css
│ │ │ ├── icons.png
│ │ │ ├── icons@2x.png
│ │ │ ├── main.js
│ │ │ ├── search.js
│ │ │ ├── style.css
│ │ │ ├── widgets.png
│ │ │ └── widgets@2x.png
│ │ ├── index.html
│ │ └── modules.html
│ ├── package.json
│ ├── scripts
│ │ ├── build.js
│ │ └── dev.js
│ ├── src
│ │ ├── createDesign.ts
│ │ ├── createEventChain.ts
│ │ ├── createState.ts
│ │ ├── customError.ts
│ │ ├── decs.d.ts
│ │ ├── getStateTreeFromDesign.ts
│ │ ├── index.ts
│ │ ├── stateTree.ts
│ │ ├── test
│ │ │ ├── createDesign.spec.ts
│ │ │ ├── createState.spec.ts
│ │ │ └── shared.ts
│ │ ├── testEventHandlerConditions.ts
│ │ ├── types.ts
│ │ └── utils.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── react
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── README.md
│ ├── card-repo.png
│ ├── docs
│ │ ├── .nojekyll
│ │ ├── assets
│ │ │ ├── highlight.css
│ │ │ ├── icons.css
│ │ │ ├── icons.png
│ │ │ ├── icons@2x.png
│ │ │ ├── main.js
│ │ │ ├── search.js
│ │ │ ├── style.css
│ │ │ ├── widgets.png
│ │ │ └── widgets@2x.png
│ │ ├── enums
│ │ │ └── S.VerboseType.html
│ │ ├── index.html
│ │ ├── interfaces
│ │ │ ├── S.Design.html
│ │ │ ├── S.DesignOptions.html
│ │ │ ├── S.DesignWithHelpers.html
│ │ │ ├── S.DesignedState.html
│ │ │ ├── S.State.html
│ │ │ └── S.StateDesign.html
│ │ ├── modules.html
│ │ └── modules
│ │ │ └── S.html
│ ├── package.json
│ ├── scripts
│ │ ├── build.js
│ │ └── dev.js
│ ├── src
│ │ ├── StateGraph.tsx
│ │ ├── createSelectorHook.tsx
│ │ ├── index.ts
│ │ ├── useGlobalState.tsx
│ │ ├── useLocalState.tsx
│ │ ├── useSelector.tsx
│ │ └── useStateDesigner.tsx
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── state-designer
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── README.md
│ ├── docs
│ ├── .nojekyll
│ ├── assets
│ │ ├── highlight.css
│ │ ├── icons.css
│ │ ├── icons.png
│ │ ├── icons@2x.png
│ │ ├── main.js
│ │ ├── search.js
│ │ ├── style.css
│ │ ├── widgets.png
│ │ └── widgets@2x.png
│ ├── enums
│ │ └── S.VerboseType.html
│ ├── index.html
│ ├── interfaces
│ │ ├── S.Design.html
│ │ ├── S.DesignOptions.html
│ │ ├── S.DesignWithHelpers.html
│ │ ├── S.DesignedState.html
│ │ ├── S.State.html
│ │ └── S.StateDesign.html
│ ├── modules.html
│ └── modules
│ │ └── S.html
│ ├── package.json
│ ├── scripts
│ ├── build.js
│ └── dev.js
│ ├── src
│ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── setupTests.ts
├── tsconfig.base.json
├── tsconfig.json
└── yarn.lock
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [steveruizok]
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | docs
4 | .DS_Store
5 | coverage
6 | *.log
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Stephen Ruiz Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/archive/docs/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/archive/docs/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Steve Ruiz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/async-events.mdx:
--------------------------------------------------------------------------------
1 | # Async Events
2 |
3 | You can wait on promises with async events.
4 |
5 | ```jsx
6 | async: {
7 | await: () => fetch("https://dog.ceo/api/breeds/image/random"),
8 | onResolve: {
9 | do: (data, payload, result) => console.log("Got an image: " + result),
10 | },
11 | onReject: {
12 | do: (data, payload, result) => console.log("Had a problem!", result),
13 | }
14 | }
15 | ```
16 |
17 |
23 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/conditions.mdx:
--------------------------------------------------------------------------------
1 | # Conditions
2 |
3 | You can control how an event handler works with **conditions**.
4 |
5 | ```jsx
6 | {
7 | if: () => Math.random() > .5,
8 | do: () => console.log("heads!"),
9 | elseDo: () => console.log("tails!")
10 | }
11 | ```
12 |
13 |
19 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/data.mdx:
--------------------------------------------------------------------------------
1 | # Using Data
2 |
3 | In a State Designer's configuration, you can use the `data` property to store any type of data that you'd like to keep track of.
4 |
5 | > **Note:** The interactive examples on this page use the `useStateDesigner` hook from `@state-designer/react`.
6 |
7 | Let's start with a very simple state configuration:
8 |
9 |
10 |
11 | In this example, we've defined our state's `data` property as an object with a property, `value`.
12 |
13 | The `useStateDesigner` hook will return the current value of `data`. In the component's JSX, we're displaying `data.value` in a heading.
14 |
15 | > 🏆 Challenge
16 | >
17 | > In the playground above, can you set `data.value` to `"Hello world!"` instead?
18 |
19 | **Hint:** You'll be creating a _string_ here, so be sure to include both quotes!
20 |
21 |
27 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/intro.mdx:
--------------------------------------------------------------------------------
1 | # Intro
2 |
3 | Welcome to this guide to learning State Designer. In the following articles, you'll learn to configure a state and use it to power a user interface. By the end of the guide, you'll be able to create states for any project or component.
4 |
5 | Throughout this guide, you'll find **interactive examples** like the one below.
6 |
7 |
8 |
9 | In these examples, the React code in the example's bottom section will determine the output in the top section. You can interact with the output or change the code and see your changes right away.
10 |
11 | You'll also find **challenges** like this one:
12 |
13 | > 🏆 **Challenge**
14 | >
15 | > Can you change the example's code so that the alert says `"Hello!"` instead?
16 |
17 | Go ahead and give it a shot!
18 |
19 | When you're ready to continue, click the link below.
20 |
21 |
22 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/repeat-events.mdx:
--------------------------------------------------------------------------------
1 | # Repeat Events
2 |
3 | You can use a **repeat event** to run the same event automatically on a regular interval while a state is active. When the state becomes inactive, the interval will automatically end.
4 |
5 | ```jsx
6 | repeat: {
7 | event: {
8 | do: () => console.log("tick!"),
9 | delay: 1
10 | }
11 | }
12 | ```
13 |
14 | The delay is measured in seconds. If you leave out the delay, the event will run on every animation frame.
15 |
16 | ```jsx
17 | repeat: {
18 | event: {
19 | do: () => console.log("tick!"),
20 | delay: 1
21 | }
22 | }
23 | ```
24 |
25 | In both cases, the event's initial result will include the total duration of the event as well as the elapsed time since the last time it ran.
26 |
27 | ```jsx
28 | repeat: {
29 | event: {
30 | do: (data, payload, result) => {
31 | console.log("It's been " + result.duration + " since this timer started.")
32 | console.log("It's been " + result.elapsed + " since this function last ran.")
33 | },
34 | delay: 1
35 | }
36 | }
37 | ```
38 |
39 |
45 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/results.mdx:
--------------------------------------------------------------------------------
1 | # Results
2 |
3 | You can compute properties within an event handler using **conditions**.
4 |
5 | ```jsx
6 | ASKED_THE_TIME: {
7 | get: () => Date.now(),
8 | do: (data, payload, result) => console.log("the time and date is ", result),
9 | }
10 | ```
11 |
12 |
18 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/state.mdx:
--------------------------------------------------------------------------------
1 | # State
2 |
3 | At the heart of State Designer is the **state**. A state stores information about a user interface and controls how and when that information should change. It also provides tools to help you use the state in your project.
4 |
5 | > 🏆 **Challenge**
6 | >
7 | > Can you change the example's code so that the count starts at 10?
8 |
9 | ### Creating a State
10 |
11 | To create a state, pass a **configuration** object to the [`useStateDesigner`](/docs/api/useStateDesigner) hook.
12 |
13 |
14 |
15 | A state's configuration contains everything about the state: its initial data and all of its events, child states, and collections. We'll learn about each part of a state's configuration in the following articles.
16 |
17 | > **Tip:** If you want to use the same state with more than one component, you can create a state with the [`createState`](/docs/api/useStateDesigner) function, then pass the state to the `useStateDesigner` hook. To learn more, check out the [`useStateDesigner`](/docs/api/useStateDesigner) article.
18 |
19 | In the next article, we'll learn how to configure a state to respond to events.
20 |
21 |
27 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/tips-and-tricks.mdx:
--------------------------------------------------------------------------------
1 | # Tips and Tricks
2 |
3 | Coming soon!
4 |
5 |
6 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/transition-events.mdx:
--------------------------------------------------------------------------------
1 | # Transition Events
2 |
3 | You can fire **transition events** automatically as you transition between states.
4 |
5 | ```jsx
6 | onEnter: { do: () => console.log("Entered the state!") },
7 | onExit: { do: () => console.log("Left the state!") },
8 | onEvent: { do: () => console.log("Something happened while I was active!") }
9 | ```
10 |
11 |
17 |
--------------------------------------------------------------------------------
/archive/docs/archive/learn/type-support.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/docs/archive/learn/type-support.png
--------------------------------------------------------------------------------
/archive/docs/archive/learn/values.mdx:
--------------------------------------------------------------------------------
1 | # Values
2 |
3 | Depending on what you're building, the values you're interested in might not be the same as the values that you store in `data`. To make this easier, you can add a `values` object to your configuration.
4 |
5 |
6 |
7 | The `values` object is an object made up of functions that, like actions, accept the state's current `data`. Unlike actions, what matters here is what the function returns.
8 |
9 | Each time the state is ready to update, it will run all of its `values` functions and return a new object—also named `values`—that contains whatever each function returned.
10 |
11 |
17 |
--------------------------------------------------------------------------------
/archive/docs/archive/the-problem.mdx:
--------------------------------------------------------------------------------
1 | # The Problem
2 |
3 | As developers, our understanding of how a system works is often very different than the code that we write to implement that system.
4 |
5 | This can lead to several problems.
6 |
7 | 1. As a system's complexity increases, so too does the _mental effort_ required to keep the system's model in mind.
8 | 2. New developers, unfamiliar with the system, must work backward from the code itself in order to _derive_ the system's model.
9 | 3. Communicating how a system works requires _separate documentation_: graphs, charts or descriptions that must be authored alongside the system's implementation.
10 |
11 | In the sections below, I will use [React](https://reactjs.com) to demonstrate this pattern in several components of a user interface. I will then argue in favor of more explicit implementations—of which State Designer is one example.
12 |
13 | ## The Counter
14 |
15 | Let's consider this counter.
16 |
17 | An implementation in React might look like this:
18 |
19 | ```jsx
20 | // counter.js
21 |
22 | const Counter = () => {
23 | const [count, setCount] = React.useState(0)
24 |
25 | return (
26 |
27 |
34 | {count}
35 |
42 |
43 | )
44 | }
45 | ```
46 |
--------------------------------------------------------------------------------
/archive/docs/archive/updates.mdx:
--------------------------------------------------------------------------------
1 | # Updates
2 |
3 | In State Designer, we call a state's changes **updates**. You can **subscribe** to a state's updates by passing a callback function to the state's `onUpdate` method.
4 |
5 | ```js
6 | state.onUpdate(() => {
7 | countElement.textContent = state.data.count
8 | })
9 | ```
10 |
11 | The state will call this function each time it updates. In the function's body, you can use the state's current information to update other parts of your project. To learn more about the `onUpdate` method, see [its page](/docs/api/onUpdate) in the API section.
12 |
13 | So far we've been learning to use State Designer in a regular JavaScript project. In the next article, we'll learn to use State Designer in a **React** project with the `useStateDesigner` hook.
14 |
15 |
21 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/action.mdx:
--------------------------------------------------------------------------------
1 | ## Action
2 |
3 | A function that receives the machine's current `data`, `payload`, and `result` as arguments, and that may mutate the machine's [data](#data).
4 |
5 | ```jsx
6 | const machine = createState({
7 | data: { count: 0 },
8 | on: {
9 | PLUS_CLICKED: "incrementCount",
10 | },
11 | actions: {
12 | // highlight-start
13 | incrementCount(data, payload, result) {
14 | data.count++
15 | },
16 | // highlight-end
17 | },
18 | })
19 | ```
20 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/active.mdx:
--------------------------------------------------------------------------------
1 | ## Active
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/async.mdx:
--------------------------------------------------------------------------------
1 | ## Async
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/auto-event.mdx:
--------------------------------------------------------------------------------
1 | ## Auto Event
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/branch-state.mdx:
--------------------------------------------------------------------------------
1 | ## Branch State
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/condition.mdx:
--------------------------------------------------------------------------------
1 | ## Condition
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/configuration.mdx:
--------------------------------------------------------------------------------
1 | ## Configuration
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/data.mdx:
--------------------------------------------------------------------------------
1 | ## Data
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/do.mdx:
--------------------------------------------------------------------------------
1 | ## Do
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/event-handler.mdx:
--------------------------------------------------------------------------------
1 | # Event Handler
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/event.mdx:
--------------------------------------------------------------------------------
1 | # Event
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/if-any.mdx:
--------------------------------------------------------------------------------
1 | # If Any
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/if.mdx:
--------------------------------------------------------------------------------
1 | # If
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/inactive.mdx:
--------------------------------------------------------------------------------
1 | # Inactive
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/initial-state.mdx:
--------------------------------------------------------------------------------
1 | # Initial State
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/is-in.mdx:
--------------------------------------------------------------------------------
1 | # Is In
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/machine.mdx:
--------------------------------------------------------------------------------
1 | # Machine
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/on-enter.mdx:
--------------------------------------------------------------------------------
1 | # onEnter
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/on-event-complete.mdx:
--------------------------------------------------------------------------------
1 | # onEventComplete
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/on-event.mdx:
--------------------------------------------------------------------------------
1 | # onEvent
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/on-exit.mdx:
--------------------------------------------------------------------------------
1 | # onExit
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/parallel-state.mdx:
--------------------------------------------------------------------------------
1 | # Parallel State
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/payload.mdx:
--------------------------------------------------------------------------------
1 | # Payload
2 |
3 | > _n._ The second (optional) argument of a machine's `send` method, containing a value that will be passed to all event handler functions.
4 |
5 | [Learn more](docs/api/events#payload)
6 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/previous.mdx:
--------------------------------------------------------------------------------
1 | # Previous
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/repeat.mdx:
--------------------------------------------------------------------------------
1 | # Repeat
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/restore.mdx:
--------------------------------------------------------------------------------
1 | # Restore
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/result.mdx:
--------------------------------------------------------------------------------
1 | # Result
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/send.mdx:
--------------------------------------------------------------------------------
1 | # Send
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/state-tree.mdx:
--------------------------------------------------------------------------------
1 | # State Tree
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/state.mdx:
--------------------------------------------------------------------------------
1 | # State
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/transition.mdx:
--------------------------------------------------------------------------------
1 | # Transition
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/unless.mdx:
--------------------------------------------------------------------------------
1 | # Unless
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/update.mdx:
--------------------------------------------------------------------------------
1 | # Update
2 |
--------------------------------------------------------------------------------
/archive/docs/content/definitions/when-in.mdx:
--------------------------------------------------------------------------------
1 | # When In
2 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/api/createDesign.mdx:
--------------------------------------------------------------------------------
1 | # `createDesign`
2 |
3 | If you want to use the same design for multiple states, but still get the same TypeScript support while you construct the design object, you can use the `createDesign` function.
4 |
5 | ```js
6 | const design = createDesign({ ... })
7 | ```
8 |
9 | The `createDesign` function doesn't do anything special—it just returns the same object that you've passed to the function. Its only purpose is to provide type support as you construct a design.
10 |
11 | However, having a separate design object might be useful in certain circumstances—and it's much easier to write a state with type support than without it.
12 |
13 | ```js
14 | const design = createDesign({
15 | data: {
16 | score: 0,
17 | lives: 3,
18 | },
19 | on: { ... },
20 | })
21 |
22 | function createStateWithCustomScore(score) {
23 | return createState({
24 | ...design,
25 | data: {
26 | ...design.data,
27 | score,
28 | },
29 | })
30 | }
31 |
32 | function createStateWithCustomLives(lives) {
33 | return createState({
34 | ...design,
35 | data: {
36 | ...design.data,
37 | lives,
38 | },
39 | })
40 | }
41 | ```
42 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/api/createSelectorHook.mdx:
--------------------------------------------------------------------------------
1 | # useStateDesigner
2 |
3 | ```js
4 | const useSelector = createSelectorHook(state)
5 | ```
6 |
7 | This is a helper that will generate a selector hook from a state. Unlike the library's regular `useSelector` hook, the hook returned by `createSelectorHook` does not require you to provide the state as a first argument.
8 |
9 | ```js
10 | import { createState, createSelectorHook } from '@state-designer/react'
11 |
12 | const state = createState({ ... })
13 |
14 | const useSelector = createSelectorHook(state)
15 | ```
16 |
17 | See the `useSelector` article for more on how to use selectors.
18 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/api/createState.mdx:
--------------------------------------------------------------------------------
1 | # `createState`
2 |
3 | You can create a state by passing a [design object](/docs/api/design/) to the `createState` function.
4 |
5 | ```js
6 | const state = createState({ ... })
7 | ```
8 |
9 | You can use and interact with the resulting state using the [state](/docs/api/state) API.
10 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/api/design/event-handlers.mdx:
--------------------------------------------------------------------------------
1 | # Event Handlers
2 |
3 | Conditions:
4 |
5 | - `if`
6 | - `ifAny`
7 | - `unless`
8 | - `unlessAny`
9 |
10 | Actions:
11 |
12 | - `do`
13 | - `secretlyDo`
14 |
15 | Transitions:
16 |
17 | - `to`
18 | - `secretlyTo`
19 |
20 | Misc:
21 |
22 | - `send`
23 | - `wait`
24 |
25 | Control flow:
26 |
27 | - `else`
28 | - `then`
29 | - `break`
30 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/framer-motion.mdx:
--------------------------------------------------------------------------------
1 | # Framer Motion
2 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/packages/core.mdx:
--------------------------------------------------------------------------------
1 | # @state-designer/core
2 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/packages/react.mdx:
--------------------------------------------------------------------------------
1 | # @state-designer/react
2 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/quick-start.mdx:
--------------------------------------------------------------------------------
1 | # Quick Start
2 |
3 | On this page, you'll find links to tutorial videos showing how you might use State Designer.
4 |
5 | ## Counter Tutorial
6 |
7 | [Starter File](https://codesandbox.io/s/state-designer-counter-starter-u0g28)
8 |
9 |
10 |
11 | ---
12 |
13 | ## Toggle Tutorial
14 |
15 | [Starter File](https://codesandbox.io/s/state-designer-counter-starter-u0g28)
16 |
17 |
18 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/usage/javascript.mdx:
--------------------------------------------------------------------------------
1 | # Using in JavaScript
2 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/usage/react.mdx:
--------------------------------------------------------------------------------
1 | # Using in React
2 |
--------------------------------------------------------------------------------
/archive/docs/content/docs/usage/typescript.mdx:
--------------------------------------------------------------------------------
1 | # Using in TypeScript
2 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/breakout.mdx:
--------------------------------------------------------------------------------
1 | # Breakout
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/calculator.mdx:
--------------------------------------------------------------------------------
1 | # Calculator
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/counter.mdx:
--------------------------------------------------------------------------------
1 | # Counter
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/dogs.mdx:
--------------------------------------------------------------------------------
1 | # Dogs
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/drawing.mdx:
--------------------------------------------------------------------------------
1 | # Drawing
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/input-save-cancel.mdx:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/input.mdx:
--------------------------------------------------------------------------------
1 | # Input
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/localStorageCounter.mdx:
--------------------------------------------------------------------------------
1 | # Local Storage Counter
2 |
3 | ```tsx
4 | import React from "react"
5 | import { useStateDesigner } from "@state-designer/react"
6 |
7 | function saveCounterData(data) {
8 | const string = JSON.stringify(data)
9 | localStorage.setItem("counter_data", string)
10 | }
11 |
12 | function localCounterData() {
13 | const string = localStorage.getItem("counter_data")
14 | return string && JSON.parse(string)
15 | }
16 |
17 | export function Counter({ id, onClick }) {
18 | const { data, send, onUpdate } = useStateDesigner({
19 | data: localCounterData() || { count: 0 },
20 | on: {
21 | CLICKED: (data) => data.count++,
22 | },
23 | })
24 |
25 | // highlight-start
26 | React.useEffect(() => {
27 | const cancelFunction = onUpdate(({ data }) => {
28 | saveCounterData(data)
29 | })
30 | return cancelFunction
31 | }, [])
32 | // highlight-end
33 |
34 | return (
35 |
36 |
37 |
38 | )
39 | }
40 | ```
41 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/snake.mdx:
--------------------------------------------------------------------------------
1 | # Snake
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/stopwatch.mdx:
--------------------------------------------------------------------------------
1 | # Stopwatch
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/tetris.mdx:
--------------------------------------------------------------------------------
1 | # Tetris
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/tiles.mdx:
--------------------------------------------------------------------------------
1 | # Tiles
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/timer.mdx:
--------------------------------------------------------------------------------
1 | # Timer
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/todo.mdx:
--------------------------------------------------------------------------------
1 | # Todo
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/todos.mdx:
--------------------------------------------------------------------------------
1 | # Todos
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/examples/toggle.mdx:
--------------------------------------------------------------------------------
1 | # Toggle
2 |
3 |
4 |
--------------------------------------------------------------------------------
/archive/docs/content/nav/404.mdx:
--------------------------------------------------------------------------------
1 | # Page not found
2 |
3 | Sorry, we weren't able to find a page at that URL.
4 |
--------------------------------------------------------------------------------
/archive/docs/content/nav/footer.mdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/docs/content/nav/footer.mdx
--------------------------------------------------------------------------------
/archive/docs/content/nav/header.mdx:
--------------------------------------------------------------------------------
1 | - [](https://github.com/steveruizok/state-designer)
2 | - [](https://twitter.com/steveruizok)
3 |
--------------------------------------------------------------------------------
/archive/docs/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | export { wrapRootElement } from './src'
2 |
--------------------------------------------------------------------------------
/archive/docs/gatsby-ssr.js:
--------------------------------------------------------------------------------
1 | export { wrapRootElement } from './src'
2 |
--------------------------------------------------------------------------------
/archive/docs/index.js:
--------------------------------------------------------------------------------
1 | // Noop
2 |
--------------------------------------------------------------------------------
/archive/docs/src/components/.eslintrc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/docs/src/components/.eslintrc
--------------------------------------------------------------------------------
/archive/docs/src/components/404.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from 'theme-ui'
3 | import { MDXProvider } from '@mdx-js/react'
4 | import Layout from './layout'
5 |
6 | import Content from '../../content/nav/404.mdx'
7 |
8 | export default () => {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/archive/docs/src/components/codesandbox.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 |
3 | export default function({ name, number }) {
4 | let path = number ? `${number}_${name}` : name
5 |
6 | return (
7 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/archive/docs/src/components/footer.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx, Container } from "theme-ui"
3 | import { MDXProvider } from "@mdx-js/react"
4 | // @ts-ignore
5 | import Content from "../../content/nav/footer.mdx"
6 |
7 | export default () => {
8 | return (
9 |
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/archive/docs/src/components/header-link.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from "theme-ui"
3 | import NavLink from "./nav-link"
4 |
5 | export default ({ ...props }) => {
6 | return
7 | }
8 |
--------------------------------------------------------------------------------
/archive/docs/src/components/inline-link.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from "theme-ui"
3 | import { Link } from "gatsby-plugin-modal-routing"
4 | import isAbsoluteURL from "is-absolute-url"
5 |
6 | export default ({ href, children, ...props }) => {
7 | const isExternal = isAbsoluteURL(href || "")
8 |
9 | if (isExternal) {
10 | return (
11 |
12 | {children}
13 |
14 | )
15 | }
16 |
17 | const to = props.to || href
18 |
19 | const isModal = to.includes("definitions")
20 |
21 | return (
22 |
28 | {children}
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/archive/docs/src/components/menu-button.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from 'theme-ui'
3 |
4 | const Burger = ({ size = '1em' }) => (
5 |
18 | )
19 |
20 | export default (props) => (
21 |
43 | )
44 |
--------------------------------------------------------------------------------
/archive/docs/src/components/nav-link.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from "theme-ui"
3 | import { Link } from "gatsby"
4 | import isAbsoluteURL from "is-absolute-url"
5 |
6 | export default ({ href, style, children, silent = false, ...props }) => {
7 | const isExternal = isAbsoluteURL(href || "")
8 |
9 | const styles = {
10 | display: "block",
11 | px: 0,
12 | color: silent ? "text" : "primary",
13 | textDecoration: "none",
14 | fontSize: 3,
15 | fontFamily: "heading",
16 | fontWeight: "bold",
17 | "&.active": {
18 | color: "primary",
19 | },
20 | "&.visited": {
21 | color: "primary",
22 | },
23 | "&:hover": {
24 | textDecoration: "underline",
25 | },
26 | ...style,
27 | }
28 |
29 | if (isExternal) {
30 | return (
31 |
32 | {children}
33 |
34 | )
35 | }
36 |
37 | const to = props.to || href
38 |
39 | return (
40 |
41 | {children}
42 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/archive/docs/src/components/page-links.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx, Flex } from "theme-ui"
3 | import NavLink from "./nav-link"
4 |
5 | export default ({ backTo, back, nextTo, next }) => {
6 | return (
7 |
18 | {back && « Back to {back}}
19 | {next && (
20 |
21 | Continue to {next} »
22 |
23 | )}
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/archive/docs/src/components/seo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useStaticQuery, graphql } from 'gatsby'
3 | import { Helmet } from 'react-helmet'
4 |
5 | export default ({ title, description }) => {
6 | const {
7 | site: { siteMetadata },
8 | } = useStaticQuery(graphql`
9 | {
10 | site {
11 | siteMetadata {
12 | title
13 | description
14 | }
15 | }
16 | }
17 | `)
18 |
19 | const fullTitle = title
20 | ? `${title} | ${siteMetadata.title}`
21 | : siteMetadata.title
22 |
23 | return (
24 |
25 | {fullTitle}
26 |
27 |
31 |
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/archive/docs/src/components/sidebar-link.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import { jsx } from "theme-ui"
3 | import { Link } from "gatsby"
4 | import isAbsoluteURL from "is-absolute-url"
5 |
6 | const styles = {
7 | display: "block",
8 | mx: -2,
9 | px: 2,
10 | py: 0,
11 | borderRadius: 4,
12 | lineHeight: 2,
13 | color: "text",
14 | textDecoration: "none",
15 | fontSize: [4, 1],
16 | fontFamily: "body",
17 | fontWeight: 2,
18 | color: "code",
19 | "&.active": {
20 | color: "text",
21 | backgroundColor: "muted",
22 | },
23 | "&.visited": {},
24 | "&:hover": {
25 | color: "text",
26 | backgroundColor: "muted",
27 | },
28 | "& code": {
29 | mx: -1,
30 | fontSize: [4, 0],
31 | },
32 | }
33 |
34 | export default ({ href, children, ...props }) => {
35 | const isExternal = isAbsoluteURL(href || "")
36 |
37 | if (isExternal) {
38 | return (
39 |
40 | {children}
41 |
42 | )
43 | }
44 |
45 | const to = props.to || href
46 |
47 | return (
48 |
49 | {children}
50 |
51 | )
52 | }
53 |
--------------------------------------------------------------------------------
/archive/docs/src/components/sidenav.js:
--------------------------------------------------------------------------------
1 | /** @jsx jsx */
2 | import React from "react"
3 | import { jsx } from "theme-ui"
4 | import { Sidenav } from "@theme-ui/sidenav"
5 |
6 | import { useScrollPosition } from "../hooks/useScrollPosition"
7 | import SidebarLink from "./sidebar-link"
8 | import Content from "../../content/nav/sidebar.mdx"
9 |
10 | export default React.forwardRef((props, ref) => {
11 | const scrollProps = useScrollPosition()
12 |
13 | return (
14 |
29 |
59 |
60 |
61 |
62 | )
63 | })
64 |
--------------------------------------------------------------------------------
/archive/docs/src/components/youtube.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | export default function ({ id }) {
4 | return (
5 |
13 |
26 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/archive/docs/src/hooks/useScrollPosition.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | export function useScrollPosition(id = "0") {
4 | const rScroll = React.useRef(null)
5 |
6 | function handleScroll(e) {
7 | if (window && window.localStorage) {
8 | window.localStorage.setItem(
9 | "sd_docs_scroll_position_" + id,
10 | e.target.scrollTop.toFixed()
11 | )
12 | }
13 | }
14 |
15 | React.useLayoutEffect(() => {
16 | if (window && window.localStorage) {
17 | const scroll = rScroll.current
18 | const scrollY = parseInt(
19 | window.localStorage.getItem("sd_docs_scroll_position_" + id)
20 | )
21 |
22 | if (scroll) {
23 | scroll.scrollTop = scrollY
24 | }
25 | }
26 | }, [])
27 |
28 | return { ref: rScroll, onScroll: handleScroll }
29 | }
30 |
--------------------------------------------------------------------------------
/archive/docs/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { ThemeProvider, Styled } from "theme-ui"
3 | import theme from "./theme"
4 | import components from "./components"
5 |
6 | export const wrapRootElement = ({ element }) => {
7 | return (
8 |
9 | {element}
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/archive/docs/src/templates/404.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Empty from '../components/404'
3 |
4 | export default () =>
5 |
--------------------------------------------------------------------------------
/archive/docs/src/templates/doc.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { graphql } from "gatsby";
3 |
4 | import Doc from "../components/doc";
5 |
6 | export default ({ data }) => ;
7 |
8 | export const pageQuery = graphql`
9 | query($id: String) {
10 | doc: docs(id: { eq: $id }) {
11 | id
12 | title
13 | description
14 | excerpt
15 | body
16 | headings {
17 | value
18 | }
19 | }
20 | }
21 | `;
22 |
--------------------------------------------------------------------------------
/archive/docs/static/atarist8x16systemfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/docs/static/atarist8x16systemfont.ttf
--------------------------------------------------------------------------------
/archive/docs/static/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/docs/static/icon.png
--------------------------------------------------------------------------------
/archive/editor/editor/DragDropList.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { DragDropContext, Droppable } from "react-beautiful-dnd"
3 |
4 | export const DragDropList: React.FC<{
5 | id: string
6 | type: string
7 | }> = ({ id, type, children }) => {
8 | return (
9 |
10 | {(provided) => (
11 |
12 | {children}
13 | {provided.placeholder}
14 |
15 | )}
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/archive/editor/editor/Segment.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reset
2 | import * as React from "react"
3 | import { Grid, Button, GridProps } from "theme-ui"
4 |
5 | export const Segment: React.FC<
6 | {
7 | options: string[]
8 | value: string
9 | disabled?: boolean
10 | onChange: (option: string) => void
11 | } & GridProps
12 | > = ({ value, disabled = false, options, onChange, ...rest }) => {
13 | return (
14 | button": {
22 | borderRadius: "0px 0px 0px 0px",
23 | },
24 | width: "100%",
25 | gridAutoColumns: "1fr",
26 | gridAutoFlow: "column",
27 | gap: 0,
28 | }}
29 | >
30 | {options.map((option, i) => (
31 |
39 | ))}
40 |
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/archive/editor/editor/StateListItem.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reset
2 | import * as React from "react"
3 | import globalState from "./state"
4 | import * as T from "./types"
5 | import { StateOptionsButton } from "./StateOptionsButton"
6 | import { Row } from "./shared"
7 | import { Button } from "theme-ui"
8 |
9 | export const StateListItem: React.FC<{ node: T.StateNode; depth: number }> = ({
10 | node,
11 | depth,
12 | }) => {
13 | return (
14 |
18 |
24 | {node.id !== "root" && }
25 |
26 | )
27 | }
28 |
29 | function getTreeChars(depth: number) {
30 | let str = ""
31 | if (depth === 0) return str
32 | for (let i = 1; i < depth; i++) {
33 | str += "\u00a0\u00a0\u00a0\u00a0\u00a0"
34 | }
35 | return str + "└─"
36 | }
37 |
--------------------------------------------------------------------------------
/archive/editor/editor/panel/Panel.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Heading, Box } from "theme-ui"
3 |
4 | export const Panel: React.FC<{}> = ({ children }) => {
5 | return (
6 |
16 | {children}
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/archive/editor/editor/panel/PanelHeading.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Heading, Box } from "theme-ui"
3 |
4 | export const PanelHeading: React.FC<{
5 | title: string
6 | as?: React.ElementType
7 | }> = ({ title, as = "h3", children }) => {
8 | return (
9 |
26 | {title}
27 | {children}
28 |
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/archive/editor/editor/state-panel/StatePanel.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reset
2 | import * as React from "react"
3 | import { useStateDesigner } from "@state-designer/react"
4 | import globalState from "../state"
5 | import { StateEditor } from "./StateEditor"
6 | import { ResizePanel } from "../panel/ResizePanel"
7 | import { Grid } from "theme-ui"
8 |
9 | export const StatePanel: React.FC<{}> = (props) => {
10 | const global = useStateDesigner(globalState)
11 | const { editingState } = global.values
12 |
13 | const rPanel = React.useRef(null)
14 |
15 | React.useEffect(() => {
16 | const panel = rPanel.current
17 | panel.scrollTo({ top: 0 })
18 | }, [editingState])
19 |
20 | return (
21 |
22 | {editingState && (
23 |
24 | )}
25 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/archive/editor/editor/types.ts:
--------------------------------------------------------------------------------
1 | export type Id = T["id"]
2 |
3 | export interface EventFunction {
4 | id: string
5 | index: number
6 | name: string
7 | code: string
8 | }
9 |
10 | export interface Action extends EventFunction {}
11 |
12 | export interface Condition extends EventFunction {}
13 |
14 | export interface Result extends EventFunction {}
15 |
16 | export interface Time extends EventFunction {}
17 |
18 | export interface Value extends EventFunction {}
19 |
20 | export type SendEvent = {
21 | id: string
22 | index: number
23 | name: string
24 | }
25 |
26 | export type StateBranch = {
27 | state: StateNode
28 | isInitial: boolean
29 | isFirst: boolean
30 | isLast: boolean
31 | descendants?: StateBranch[]
32 | }
33 |
34 | export type EventHandler = {
35 | id: string
36 | index: number
37 | event: string // id
38 | chain: Map
39 | }
40 |
41 | export enum TransitionType {
42 | Normal = "normal",
43 | Previous = "previous",
44 | Restore = "restore",
45 | }
46 |
47 | export type HandlerLink = {
48 | id: string
49 | index: number
50 | to?: Id // state id
51 | do: Id[] // action id
52 | if: Id[] // condition id
53 | transitionType: TransitionType
54 | }
55 |
56 | export type StateNode = {
57 | id: string
58 | index: number
59 | parent?: Id
60 | depth: number
61 | name: string
62 | eventHandlers: Map
63 | initial?: Id
64 | states: Set
65 | }
66 |
--------------------------------------------------------------------------------
/archive/example/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Steve
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/archive/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "state-designer-example",
3 | "version": "1.5.3",
4 | "private": true,
5 | "dependencies": {
6 | "@state-designer/core": "^1.5.6",
7 | "@state-designer/react": "^1.5.6",
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.3.2",
10 | "@testing-library/user-event": "^7.1.2",
11 | "@types/jest": "^24.0.0",
12 | "@types/lodash-es": "^4.17.3",
13 | "@types/node": "^12.0.0",
14 | "@types/react": "^16.9.0",
15 | "@types/react-dom": "^16.9.0",
16 | "@types/styled-components": "^5.1.0",
17 | "lodash-es": "^4.17.15",
18 | "react": "^16.13.1",
19 | "react-dom": "^16.13.1",
20 | "react-scripts": "3.4.1",
21 | "styled-components": "^5.1.0",
22 | "typescript": "~3.7.2"
23 | },
24 | "scripts": {
25 | "start": "react-scripts start",
26 | "build": "react-scripts build",
27 | "eject": "react-scripts eject"
28 | },
29 | "eslintConfig": {
30 | "extends": "react-app"
31 | },
32 | "browserslist": {
33 | "production": [
34 | ">0.2%",
35 | "not dead",
36 | "not op_mini all"
37 | ],
38 | "development": [
39 | "last 1 chrome version",
40 | "last 1 firefox version",
41 | "last 1 safari version"
42 | ]
43 | },
44 | "devDependencies": {
45 | "cra-workspaces": "^2.0.0"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/archive/example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/example/public/favicon.ico
--------------------------------------------------------------------------------
/archive/example/public/fonts/gameboy.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/example/public/fonts/gameboy.ttf
--------------------------------------------------------------------------------
/archive/example/public/images/bricks.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/archive/example/public/images/ghost.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/archive/example/public/images/i.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/archive/example/public/images/j.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/archive/example/public/images/l.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/archive/example/public/images/o.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/archive/example/public/images/s.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/archive/example/public/images/t.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/archive/example/public/images/z.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/archive/example/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/example/public/logo192.png
--------------------------------------------------------------------------------
/archive/example/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/example/public/logo512.png
--------------------------------------------------------------------------------
/archive/example/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 |
--------------------------------------------------------------------------------
/archive/example/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/archive/example/src/App.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import Start from "./scenes/Start"
4 | import Playing from "./scenes/Playing"
5 | import { Switches } from "./scenes/Tests/Switches"
6 |
7 | export default function App() {
8 | return (
9 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/archive/example/src/components/Matrix/Cell.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import * as Tetris from "../../game/types"
4 | import * as Static from "../../game/static"
5 |
6 | type CellProps = {
7 | x: number
8 | y: number
9 | cell: Tetris.Cell | "ghost"
10 | }
11 |
12 | const Cell: React.FC = ({ x, y, cell }) => (
13 |
23 | )
24 |
25 | export default Cell
26 |
--------------------------------------------------------------------------------
/archive/example/src/components/Matrix/Container.tsx:
--------------------------------------------------------------------------------
1 | import styled from "styled-components"
2 |
3 | type ContainerProps = {
4 | rows: number
5 | columns: number
6 | }
7 |
8 | const Container = styled.div((props) => ({
9 | display: "grid",
10 | width: "fit-content",
11 | gridTemplateColumns: `repeat(${props.columns}, var(--cell-size))`,
12 | gridAutoRows: `var(--cell-size)`,
13 | }))
14 |
15 | export default Container
16 |
--------------------------------------------------------------------------------
/archive/example/src/components/Matrix/FallingPiece.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import * as Tetris from "../../game/types"
4 | import * as Static from "../../game/static"
5 |
6 | import Cell from "./Cell"
7 |
8 | const FallingPiece: React.FC = ({
9 | type,
10 | orientation,
11 | origin,
12 | }) => {
13 | const tetromino = Static.tetrominos[type][orientation]
14 |
15 | return (
16 | <>
17 | {tetromino
18 | .filter((point) => origin.y + point.y - 20 >= 0)
19 | .map((point, i) => {
20 | return (
21 | |
27 | )
28 | })}
29 | >
30 | )
31 | }
32 |
33 | export default FallingPiece
34 |
--------------------------------------------------------------------------------
/archive/example/src/components/Matrix/GhostPiece.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import * as Tetris from "../../game/types"
4 | import * as Static from "../../game/static"
5 |
6 | import Cell from "./Cell"
7 |
8 | const GhostPiece: React.FC = ({ type, orientation, origin }) => {
9 | const tetromino = Static.tetrominos[type][orientation]
10 |
11 | return (
12 | <>
13 | {tetromino
14 | .filter((point) => origin.y + point.y - 20 >= 0)
15 | .map((point, i) => {
16 | return (
17 | |
23 | )
24 | })}
25 | >
26 | )
27 | }
28 |
29 | export default GhostPiece
30 |
--------------------------------------------------------------------------------
/archive/example/src/components/Matrix/NextPiece.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import * as Tetris from "../../game/types"
4 | import * as Static from "../../game/static"
5 |
6 | import Cell from "./Cell"
7 |
8 | const NextPiece: React.FC = ({ type, orientation, origin }) => {
9 | const tetromino = Static.tetrominos[type][orientation]
10 |
11 | return (
12 | <>
13 | {tetromino.map((point, i) => {
14 | return (
15 | |
21 | )
22 | })}
23 | >
24 | )
25 | }
26 |
27 | export default NextPiece
28 |
--------------------------------------------------------------------------------
/archive/example/src/components/Next.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { useStateDesigner } from "@state-designer/react"
3 | import game from "../game"
4 |
5 | import Container from "./Matrix/Container"
6 | import NextPiece from "./Matrix/NextPiece"
7 |
8 | const Next: React.FC<{}> = () => {
9 | const { data } = useStateDesigner(game)
10 | const { next } = data
11 |
12 | return (
13 |
14 | {next.map((tetrominoType, i) => (
15 |
16 |
21 |
22 | ))}
23 |
24 | )
25 | }
26 |
27 | export default Next
28 |
--------------------------------------------------------------------------------
/archive/example/src/components/Playfield.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { useStateDesigner } from "@state-designer/react"
3 | import game from "../game"
4 |
5 | import Container from "./Matrix/Container"
6 | import FallingPiece from "./Matrix/FallingPiece"
7 | import GhostPiece from "./Matrix/GhostPiece"
8 | import Cell from "./Matrix/Cell"
9 |
10 | const Playfield: React.FC<{}> = () => {
11 | const { data } = useStateDesigner(game)
12 | const { matrix, falling, ghost } = data
13 |
14 | return (
15 |
16 | {matrix
17 | .slice(-20)
18 | .map((row, y) =>
19 | row.map((cell, x) => (
20 | |
21 | ))
22 | )}
23 |
24 |
25 |
26 | )
27 | }
28 |
29 | export default Playfield
30 |
--------------------------------------------------------------------------------
/archive/example/src/components/Stats.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { useStateDesigner, StateGraph } from "@state-designer/react"
3 | import game from "../game"
4 |
5 | const Stats: React.FC = () => {
6 | const { data } = useStateDesigner(game)
7 |
8 | // const active = getActive(stateTree)
9 |
10 | return (
11 |
12 |
Score: {data.score}
13 |
Level: {data.level}
14 |
Lines: {data.lines}
15 |
16 |
17 |
18 | )
19 | }
20 |
21 | export default Stats
22 |
--------------------------------------------------------------------------------
/archive/example/src/game/types.ts:
--------------------------------------------------------------------------------
1 | export enum TetrominoType {
2 | O = "O",
3 | I = "I",
4 | S = "S",
5 | Z = "Z",
6 | L = "L",
7 | J = "J",
8 | T = "T",
9 | }
10 |
11 | export type Cell = 0 | TetrominoType
12 |
13 | export type Matrix = Cell[][]
14 |
15 | export type Point = { x: number; y: number }
16 |
17 | export type Tetromino = [Point, Point, Point, Point]
18 |
19 | export type Tetrominos = Record
20 |
21 | export type Colors = Record
22 |
23 | export type Piece = {
24 | type: TetrominoType
25 | orientation: number
26 | origin: Point
27 | }
28 |
29 | export type Data = {
30 | matrix: Matrix
31 | falling: Piece
32 | next: TetrominoType[]
33 | ghost: Piece
34 | score: number
35 | highscore: number
36 | lines: number
37 | level: number
38 | }
39 |
--------------------------------------------------------------------------------
/archive/example/src/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { render } from "react-dom"
3 | import "./styles.css"
4 |
5 | import App from "./App"
6 |
7 | const rootElement = document.getElementById("root")
8 | render(, rootElement)
9 |
--------------------------------------------------------------------------------
/archive/example/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/archive/example/src/scenes/Tests/Switches.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { useStateDesigner } from "@state-designer/react"
3 |
4 | type Switch = { id: string; switched: boolean }
5 |
6 | type SwitchCollection = Record
7 |
8 | const switches: SwitchCollection = {
9 | 0: { id: "0", switched: false },
10 | 1: { id: "1", switched: false },
11 | 2: { id: "2", switched: true },
12 | }
13 |
14 | export const Switches: React.FC = () => {
15 | const state = useStateDesigner({
16 | data: { switches },
17 | on: {
18 | FLIPPED_SWITCH: {
19 | get: "switch",
20 | do: "flipSwitch",
21 | },
22 | },
23 | results: {
24 | switch(data, payload: Switch) {
25 | return data.switches[payload.id]
26 | },
27 | },
28 | actions: {
29 | flipSwitch(data, payload, result: Switch) {
30 | result.switched = !result.switched
31 | },
32 | },
33 | })
34 |
35 | return (
36 |
37 | {Object.values(state.data.switches).map((s, i) => (
38 |
39 | state.send("FLIPPED_SWITCH", s)}
43 | />
44 |
45 | ))}
46 |
47 | )
48 | }
49 |
50 | export default Switches
51 |
--------------------------------------------------------------------------------
/archive/example/src/styles.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "Gameboy";
3 | src: url(/fonts/gameboy.ttf);
4 | }
5 |
6 | html,
7 | * {
8 | box-sizing: border-box;
9 | }
10 |
11 | :root {
12 | --gb-body: #c5c0be;
13 | --gb-grey: #8f8e93;
14 | --gb-lgrey: #bab6ad;
15 | --gb-dark: #404040;
16 | --gb-mdark: #6c7353;
17 | --gb-mlight: #8b956d;
18 | --gb-light: #c5d0a1;
19 | --gb-accent: #b83f76;
20 | --cell-size: 24px;
21 | }
22 |
23 | body {
24 | box-sizing: border-box;
25 | background-color: var(--gb-body);
26 | }
27 |
28 | .App {
29 | font-family: Gameboy;
30 | justify-content: center;
31 | display: flex;
32 | margin: 0 auto;
33 | flex-wrap: wrap;
34 | }
35 |
36 | .Bricks {
37 | width: 24px;
38 | background-image: url(/images/bricks.svg);
39 | background-size: 24px;
40 | }
41 |
42 | .Screen {
43 | display: flex;
44 | justify-content: flex-start;
45 | padding: 0px;
46 | border: 4px inset var(--gb-grey);
47 | background-color: var(--gb-light);
48 | border-radius: 4px;
49 | }
50 |
51 | .Screen > * {
52 | margin-right: 4px;
53 | }
54 |
55 | .Stats {
56 | margin: 16px;
57 | }
58 |
59 | li[data-active="true"] {
60 | color: var(--gb-accent);
61 | }
62 |
63 | li[data-active="false"] {
64 | color: #000;
65 | }
66 |
--------------------------------------------------------------------------------
/archive/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "include": [
4 | "src",
5 | "types",
6 | "decs.d.ts"
7 | ],
8 | "compilerOptions": {
9 | "target": "es5",
10 | "module": "esnext",
11 | "lib": [
12 | "dom",
13 | "esnext"
14 | ],
15 | "importHelpers": true,
16 | "declaration": true,
17 | "sourceMap": true,
18 | "rootDir": "./",
19 | "strict": true,
20 | "noImplicitAny": true,
21 | "strictNullChecks": true,
22 | "strictFunctionTypes": true,
23 | "strictPropertyInitialization": true,
24 | "noImplicitThis": false,
25 | "alwaysStrict": true,
26 | "noUnusedLocals": false,
27 | "noUnusedParameters": false,
28 | "noImplicitReturns": false,
29 | "noFallthroughCasesInSwitch": true,
30 | "moduleResolution": "node",
31 | "jsx": "react",
32 | "esModuleInterop": true,
33 | "baseUrl": "./",
34 | "allowJs": true,
35 | "skipLibCheck": true,
36 | "forceConsistentCasingInFileNames": true,
37 | "resolveJsonModule": true,
38 | "isolatedModules": true,
39 | "noEmit": true
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/archive/tutorials/.gitignore:
--------------------------------------------------------------------------------
1 | .vercel
--------------------------------------------------------------------------------
/archive/tutorials/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testTimeout: 30000,
3 | displayName: "sandbox",
4 | testMatch: ["**/complete.test.js"],
5 | testURL: "http://localhost",
6 | setupFiles: ["jest-canvas-mock"],
7 | }
8 |
--------------------------------------------------------------------------------
/archive/tutorials/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "src"
4 | }
5 | }
--------------------------------------------------------------------------------
/archive/tutorials/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "state-designer-tutorials",
3 | "version": "1.5.0",
4 | "private": true,
5 | "description": "",
6 | "keywords": [],
7 | "main": "src/index.js",
8 | "dependencies": {
9 | "@chakra-ui/core": "0.8.0",
10 | "@emotion/core": "10.0.28",
11 | "@emotion/styled": "10.0.27",
12 | "@state-designer/react": "^1.5.6",
13 | "@testing-library/jest-dom": "^5.9.0",
14 | "@testing-library/react": "^10.0.6",
15 | "@testing-library/user-event": "^11.0.0",
16 | "emotion-theming": "10.0.27",
17 | "framer-motion": "^1.11.0",
18 | "lodash": "^4.17.15",
19 | "lodash-es": "^4.17.15",
20 | "mdn-polyfills": "5.20.0",
21 | "react": "^17.0.1",
22 | "react-dom": "^17.0.1",
23 | "react-feather": "^2.0.8",
24 | "react-router-dom": "5.2.0",
25 | "react-scripts": "3.4.1"
26 | },
27 | "devDependencies": {
28 | "jest-canvas-mock": "^2.2.0",
29 | "typescript": "3.8.3"
30 | },
31 | "scripts": {
32 | "start": "react-scripts start",
33 | "build": "react-scripts build",
34 | "test": "react-scripts test --env=jsdom --testPathPattern=complete",
35 | "test-starter": "react-scripts test --env=jsdom --testPathPattern=starter",
36 | "eject": "react-scripts eject"
37 | },
38 | "browserslist": [
39 | ">0.2%",
40 | "not dead",
41 | "not ie <= 11",
42 | "not op_mini all"
43 | ],
44 | "baseUrl": "src"
45 | }
46 |
--------------------------------------------------------------------------------
/archive/tutorials/sandbox.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "infiniteLoopProtection": true,
3 | "hardReloadOnChange": false,
4 | "view": "browser"
5 | }
6 |
--------------------------------------------------------------------------------
/archive/tutorials/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import ReactDOM from "react-dom"
3 | import { BrowserRouter } from "react-router-dom"
4 | import { ThemeProvider, ColorModeProvider, CSSReset } from "@chakra-ui/core"
5 |
6 | import theme from "./theme"
7 | import App from "./App"
8 |
9 | const rootElement = document.getElementById("root")
10 | ReactDOM.render(
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ,
21 | rootElement
22 | )
23 |
--------------------------------------------------------------------------------
/archive/tutorials/src/setupTests.js:
--------------------------------------------------------------------------------
1 | import "@testing-library/jest-dom/extend-expect"
2 |
--------------------------------------------------------------------------------
/archive/tutorials/src/theme.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { theme } from "@chakra-ui/core"
3 | import { Play, Square, FastForward, Rewind, Pause } from "react-feather"
4 |
5 | export default {
6 | ...theme,
7 | fonts: {
8 | body: "Fira Sans, system-ui, sans-serif",
9 | heading: "Fira Sans, system-ui, sans-serif",
10 | mono: "Fira Code, Menlo, monospace",
11 | },
12 | icons: {
13 | ...theme.icons,
14 | play: {
15 | path: ,
16 | viewBox: "0 0 24 24",
17 | },
18 | pause: {
19 | path: ,
20 | viewBox: "0 0 24 24",
21 | },
22 | rewind: {
23 | path: ,
24 | viewBox: "0 0 24 24",
25 | },
26 | fastforward: {
27 | path: ,
28 | viewBox: "0 0 24 24",
29 | },
30 | stop: {
31 | path: ,
32 | viewBox: "0 0 24 24",
33 | },
34 | },
35 | }
36 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/1_counter/complete/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { CounterLayout, Count, PlusButton, MinusButton } from "components"
3 | import { useStateDesigner } from "@state-designer/react"
4 |
5 | export default function () {
6 | const state = useStateDesigner({
7 | data: { count: 0 },
8 | on: {
9 | DECREASED: { unless: "countIsAtMin", do: "decrementCount" },
10 | INCREASED: "incrementCount",
11 | },
12 | actions: {
13 | decrementCount(data) {
14 | data.count--
15 | },
16 | incrementCount(data) {
17 | data.count++
18 | },
19 | },
20 | conditions: {
21 | countIsAtMin(data) {
22 | return data.count === 0
23 | },
24 | },
25 | })
26 |
27 | return (
28 |
29 | state.send("DECREASED")}
32 | >
33 | Decrease
34 |
35 | {state.data.count}
36 | state.send("INCREASED")}>Increase
37 |
38 | )
39 | }
40 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/1_counter/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { CounterLayout, Count, PlusButton, MinusButton } from "components"
3 |
4 | export default function () {
5 | return (
6 |
7 | Decrease
8 | 0
9 | Increase
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/1_counter/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/1_counter/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/2_toggle/complete/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { ToggleLayout, Label, Toggle } from "components"
3 | import { useStateDesigner } from "@state-designer/react"
4 |
5 | export default function () {
6 | const state = useStateDesigner({
7 | initial: "toggledOff",
8 | states: {
9 | toggledOff: {
10 | on: { TOGGLED: { to: "toggledOn" } },
11 | },
12 | toggledOn: {
13 | on: { TOGGLED: { to: "toggledOff" } },
14 | },
15 | },
16 | })
17 |
18 | return (
19 |
20 | state.send("TOGGLED")}
23 | />
24 |
30 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/2_toggle/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { ToggleLayout, Toggle, Label } from "components"
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/2_toggle/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/2_toggle/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const components = {
14 | container: utils.getByLabelText("container"),
15 | toggle: utils.getByLabelText("toggle"),
16 | label: utils.getByLabelText("label"),
17 | }
18 |
19 | return { components, ...utils }
20 | }
21 |
22 | test("It should mount the component.", () => {
23 | const utils = setup()
24 | const { container } = utils.components
25 | expect(container).toBeInTheDocument()
26 | })
27 |
28 | test("It should start from toggled off.", () => {
29 | const utils = setup()
30 | const { toggle, label } = utils.components
31 | expect(toggle).not.toBeChecked()
32 | expect(label).toHaveTextContent("OFF")
33 | })
34 |
35 | test("It should toggle from off to on.", () => {
36 | const utils = setup()
37 | const { toggle, label } = utils.components
38 | fireEvent.click(toggle)
39 | expect(toggle).toBeChecked()
40 | expect(label).toHaveTextContent("ON")
41 | })
42 |
43 | test("It should toggle from on to off.", () => {
44 | const utils = setup()
45 | const { toggle, label } = utils.components
46 | fireEvent.click(toggle)
47 | fireEvent.click(toggle)
48 | expect(toggle).not.toBeChecked()
49 | expect(label).toHaveTextContent("OFF")
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/2_toggle/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/3_input/complete/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { useStateDesigner } from "@state-designer/react"
3 | import {
4 | ClearButton,
5 | InputLayout,
6 | NameHeading,
7 | TitleHeading,
8 | NameInput,
9 | TitleInput,
10 | } from "components"
11 |
12 | export default function () {
13 | const state = useStateDesigner({
14 | data: {
15 | name: "",
16 | title: "",
17 | },
18 | on: {
19 | CHANGED_NAME: "updateName",
20 | CHANGED_TITLE: "updateTitle",
21 | CLEARED: ["clearName", "clearTitle"],
22 | },
23 | actions: {
24 | updateName(data, payload) {
25 | data.name = payload
26 | },
27 | updateTitle(data, payload) {
28 | data.title = payload
29 | },
30 | clearName(data) {
31 | data.name = ""
32 | },
33 | clearTitle(data) {
34 | data.title = ""
35 | },
36 | },
37 | })
38 |
39 | return (
40 |
41 | {state.data.name || "Name"}
42 | {state.data.title || "Title"}
43 | state.send("CHANGED_NAME", e.target.value)}
46 | />
47 | state.send("CHANGED_TITLE", e.target.value)}
50 | />
51 | state.send("CLEARED")} />
52 |
53 | )
54 | }
55 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/3_input/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import {
3 | ClearButton,
4 | InputLayout,
5 | NameHeading,
6 | TitleHeading,
7 | NameInput,
8 | TitleInput,
9 | } from "components"
10 |
11 | export default function () {
12 | return (
13 |
14 | Name
15 | Title
16 |
17 |
18 |
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/3_input/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/3_input/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/4_todo/complete/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import Todo from "./Todo"
3 | import { Layout, VStack } from "components"
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/4_todo/starter/Todo.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { TodoContainer, Checkbox, TextInput } from "components"
3 |
4 | export default function ({ content = "", complete = false }) {
5 | return (
6 |
7 | {}}
11 | />
12 | {}} />
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/4_todo/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import Todo from "./Todo"
3 | import { Layout, VStack } from "components"
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/4_todo/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/4_todo/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/5_todos/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { TwoColumnLayout, VStack, PrimaryButton, NavButton } from "components"
3 | import Todo from "./Todo"
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 | Add Todo
10 | All (0)
11 | Incomplete (0)
12 | Complete (0)
13 | Clear Complete
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/5_todos/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/5_todos/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/6_stopwatch/complete/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import {
3 | StartButton,
4 | StopButton,
5 | StopwatchLayout,
6 | Time,
7 | ResetButton,
8 | } from "components"
9 | import { useStateDesigner } from "@state-designer/react"
10 |
11 | export default function () {
12 | const state = useStateDesigner({
13 | id: "myState",
14 | data: { milliseconds: 0 },
15 | initial: "stopped",
16 | states: {
17 | stopped: {
18 | on: {
19 | STARTED: { to: "running" },
20 | },
21 | },
22 | running: {
23 | on: {
24 | STOPPED: { to: "stopped" },
25 | RESET: { to: "stopped" },
26 | },
27 | repeat: {
28 | onRepeat: "addElapsedTime",
29 | },
30 | },
31 | },
32 | on: {
33 | RESET: "resetTime",
34 | },
35 | actions: {
36 | addElapsedTime(data, payload, result) {
37 | const { interval } = result
38 | data.milliseconds += interval
39 | },
40 | resetTime(data) {
41 | data.milliseconds = 0
42 | },
43 | },
44 | values: {
45 | seconds(data) {
46 | return (data.milliseconds / 1000).toFixed(2)
47 | },
48 | },
49 | })
50 |
51 | return (
52 |
53 |
54 | state.send("STARTED")}
57 | />
58 | state.send("STOPPED")}
61 | />
62 | state.send("RESET")} />
63 |
64 | )
65 | }
66 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/6_stopwatch/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import {
3 | StartButton,
4 | StopButton,
5 | StopwatchLayout,
6 | Time,
7 | ResetButton,
8 | } from "components"
9 |
10 | export default function () {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/6_stopwatch/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/6_stopwatch/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/7_timer/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import {
3 | TimerLayout,
4 | Time,
5 | StartStopButton,
6 | ResetButton,
7 | MinuteButton,
8 | SecondButton,
9 | } from "components"
10 |
11 | export default function () {
12 | return (
13 |
14 |
15 |
16 |
17 | Start
18 |
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/7_timer/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/7_timer/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/8_tiles/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { TileLayout, PlayButton, TileGrid, Tile } from "components"
3 | import { range, shuffle, swap } from "utils"
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 | {range(16).map((index) => {
10 | return
11 | })}
12 |
13 | PLAY
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/8_tiles/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/8_tiles/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { act, render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const components = {
14 | container: utils.getByLabelText("container"),
15 | }
16 |
17 | return { components, ...utils }
18 | }
19 |
20 | test("It should mount the component.", () => {
21 | const utils = setup()
22 | const { container } = utils.components
23 | expect(container).toBeInTheDocument()
24 | })
25 | }
26 |
27 | async function pause(duration = 1000) {
28 | return act(async () => {
29 | await new Promise((resolve) => setTimeout(resolve, duration))
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/8_tiles/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/breakout/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/breakout/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { act, render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const components = {
14 | container: utils.getByLabelText("container"),
15 | }
16 |
17 | return { components, ...utils }
18 | }
19 |
20 | test("It should mount the component.", () => {
21 | const utils = setup()
22 | const { container } = utils.components
23 | expect(container).toBeInTheDocument()
24 | })
25 | }
26 |
27 | async function pause(duration = 1000) {
28 | return act(async () => {
29 | await new Promise((resolve) => setTimeout(resolve, duration))
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/breakout/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/calculator/starter/index.js:
--------------------------------------------------------------------------------
1 | /* eslint no-eval: 0 */
2 | import React from "react"
3 | import { Calculator as C } from "components"
4 |
5 | export default function () {
6 | return (
7 |
8 | 0 + 0
9 | 0
10 | CE
11 | AC
12 | +/-
13 | /
14 | 1
15 | 2
16 | 3
17 | +
18 | 4
19 | 5
20 | 6
21 | -
22 | 7
23 | 8
24 | 9
25 | *
26 | 0
27 | .
28 | =
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/calculator/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/calculator/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const container = utils.getByLabelText("container")
14 |
15 | return {
16 | components: { container },
17 | ...utils,
18 | }
19 | }
20 |
21 | test("It should mount the component.", () => {
22 | const utils = setup()
23 | const { container } = utils.components
24 | expect(container).toBeInTheDocument()
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/calculator/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dogs/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Dogs as D } from "components"
3 | import { delay } from "utils"
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 | Fetch
10 | Cancel
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dogs/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dogs/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const container = utils.getByLabelText("container")
14 |
15 | return {
16 | components: { container },
17 | ...utils,
18 | }
19 | }
20 |
21 | test("It should mount the component.", () => {
22 | const utils = setup()
23 | const { container } = utils.components
24 | expect(container).toBeInTheDocument()
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dogs/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dopewars/starter/Todo.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { TodoContainer, Checkbox, TextInput } from "components"
3 |
4 | export default function ({ content = "", complete = false }) {
5 | return (
6 |
7 | {}}
11 | />
12 | {}} />
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dopewars/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import Todo from "./Todo"
3 | import { Layout, VStack } from "components"
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dopewars/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/dopewars/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/drawing/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Drawing as D, theme } from "components"
3 |
4 | const w = 320,
5 | h = 400,
6 | sizes = [1, 3, 6, 12, 24, 48],
7 | colors = ["green", "blue", "purple", "red", "orange", "yellow", "gray"]
8 |
9 | export default function () {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | {colors.map((color, i) => (
18 |
19 | ))}
20 |
21 |
22 | {sizes.map((size, i) => (
23 | {size}
24 | ))}
25 |
26 |
27 | Undo
28 | Redo
29 |
30 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/drawing/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/drawing/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { act, render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const components = {
14 | container: utils.getByLabelText("container"),
15 | }
16 |
17 | return { components, ...utils }
18 | }
19 |
20 | test("It should mount the component.", () => {
21 | const utils = setup()
22 | const { container } = utils.components
23 | expect(container).toBeInTheDocument()
24 | })
25 | }
26 |
27 | async function pause(duration = 1000) {
28 | return act(async () => {
29 | await new Promise((resolve) => setTimeout(resolve, duration))
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/drawing/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/player/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Player as P } from "components"
3 |
4 | export default function () {
5 | return (
6 |
7 | 00:37
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/player/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/player/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const container = utils.getByLabelText("container")
14 |
15 | return {
16 | components: { container },
17 | ...utils,
18 | }
19 | }
20 |
21 | test("It should mount the component.", () => {
22 | const utils = setup()
23 | const { container } = utils.components
24 | expect(container).toBeInTheDocument()
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/player/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/snake/complete/input.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | export default function ({ onKeyDown = {}, onKeyUp = {} }) {
4 | React.useEffect(() => {
5 | function handleKeydown(event) {
6 | if (onKeyDown[event.key] !== undefined) {
7 | event.preventDefault()
8 | onKeyDown[event.key]()
9 | }
10 | }
11 |
12 | function handleKeyup(event) {
13 | if (onKeyUp[event.key] !== undefined) {
14 | event.preventDefault()
15 | onKeyUp[event.key]()
16 | }
17 | }
18 |
19 | document.body.addEventListener("keydown", handleKeydown)
20 | document.body.addEventListener("keyup", handleKeyup)
21 | return () => {
22 | document.body.removeEventListener("keydown", handleKeydown)
23 | document.body.removeEventListener("keyup", handleKeyup)
24 | }
25 | }, [])
26 | }
27 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/snake/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Snake as S } from "components"
3 | import { useKeyboardInputs } from "utils"
4 |
5 | export default function () {
6 | useKeyboardInputs({
7 | onKeyDown: {},
8 | })
9 |
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Start
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/snake/starter/input.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | export default function () {
4 | React.useEffect(() => {
5 | function handleKeydown(event) {
6 | switch (event.key) {
7 | // Key Cases
8 | default:
9 | break
10 | }
11 | }
12 |
13 | function handleKeyup(event) {
14 | switch (event.key) {
15 | // Key Cases
16 | default:
17 | break
18 | }
19 | }
20 |
21 | document.body.addEventListener("keydown", handleKeydown)
22 | document.body.addEventListener("keyup", handleKeyup)
23 | return () => {
24 | document.body.removeEventListener("keydown", handleKeydown)
25 | document.body.removeEventListener("keyup", handleKeyup)
26 | }
27 | }, [])
28 | }
29 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/snake/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/snake/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { act, render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const components = {
14 | container: utils.getByLabelText("container"),
15 | }
16 |
17 | return { components, ...utils }
18 | }
19 |
20 | test("It should mount the component.", () => {
21 | const utils = setup()
22 | const { container } = utils.components
23 | expect(container).toBeInTheDocument()
24 | })
25 | }
26 |
27 | async function pause(duration = 1000) {
28 | return act(async () => {
29 | await new Promise((resolve) => setTimeout(resolve, duration))
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/snake/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/tetris/starter/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { colors, tetrominos } from "./static"
3 | import { useKeyboardInputs } from "utils"
4 | import { Tetris as T } from "components"
5 |
6 | export default function () {
7 | useKeyboardInputs({
8 | onKeyDown: {},
9 | onKeyUp: {},
10 | })
11 |
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
41 |
42 |
43 | Score {0}
44 | Level {0}
45 | Lines {0}
46 |
47 | Play
48 |
49 | )
50 | }
51 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/tetris/tests/complete.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../complete"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/tetris/tests/index.js:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { act, render, fireEvent } from "@testing-library/react"
3 | import { ThemeProvider } from "@chakra-ui/core"
4 |
5 | export default function (Component) {
6 | const setup = () => {
7 | const utils = render(
8 |
9 |
10 |
11 | )
12 |
13 | const components = {
14 | container: utils.getByLabelText("container"),
15 | }
16 |
17 | return { components, ...utils }
18 | }
19 |
20 | test("It should mount the component.", () => {
21 | const utils = setup()
22 | const { container } = utils.components
23 | expect(container).toBeInTheDocument()
24 | })
25 | }
26 |
27 | async function pause(duration = 1000) {
28 | return act(async () => {
29 | await new Promise((resolve) => setTimeout(resolve, duration))
30 | })
31 | }
32 |
--------------------------------------------------------------------------------
/archive/tutorials/src/tutorials/tetris/tests/starter.test.js:
--------------------------------------------------------------------------------
1 | import test from "./index"
2 | import Component from "../starter"
3 |
4 | test(Component)
5 |
--------------------------------------------------------------------------------
/archive/viewer/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["next/babel"],
3 | "plugins": [["emotion"]]
4 | }
5 |
--------------------------------------------------------------------------------
/archive/viewer/.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 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 |
21 | # debug
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | # local env files
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 |
32 | .vercel
--------------------------------------------------------------------------------
/archive/viewer/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | ```
12 |
13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14 |
15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16 |
17 | ## Learn More
18 |
19 | To learn more about Next.js, take a look at the following resources:
20 |
21 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
22 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
23 |
24 | You can check out [the Next.js GitHub repository](https://github.com/zeit/next.js/) - your feedback and contributions are welcome!
25 |
26 | ## Deploy on Vercel
27 |
28 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
29 |
30 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
31 |
--------------------------------------------------------------------------------
/archive/viewer/auth/firebaseAdmin.tsx:
--------------------------------------------------------------------------------
1 | import firebase from "firebase"
2 | import * as admin from "firebase-admin"
3 |
4 | export const initializeAdmin = () => {
5 | const firebasePrivateKey = process.env.FIREBASE_PRIVATE_KEY
6 |
7 | if (!admin.apps.length) {
8 | admin.initializeApp({
9 | credential: admin.credential.cert({
10 | projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
11 | clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
12 | // https://stackoverflow.com/a/41044630/1332513
13 | privateKey: firebasePrivateKey.replace(/\\n/g, "\n"),
14 | }),
15 | databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
16 | })
17 | }
18 |
19 | return admin
20 | }
21 |
22 | export const verifyIdToken = (token: string | string[]) => {
23 | const singleToken = Array.isArray(token) ? token[0] : token
24 |
25 | if (singleToken === "undefined") throw new Error("No token.")
26 |
27 | initializeAdmin()
28 |
29 | return admin
30 | .auth()
31 | .verifyIdToken(singleToken)
32 | .catch((error) => {
33 | throw error
34 | })
35 | }
36 |
37 | export const revokeIdToken = async (uids: string | string[]) => {
38 | const uid = Array.isArray(uids) ? uids[0] : uids
39 | initializeAdmin()
40 |
41 | await admin.auth().revokeRefreshTokens(uid)
42 | const userRecord = await admin.auth().getUser(uid)
43 | const timestamp = new Date(userRecord.tokensValidAfterTime).getTime() / 1000
44 | // console.log("Tokens revoked at: ", timestamp)
45 | }
46 |
--------------------------------------------------------------------------------
/archive/viewer/auth/initFirebase.tsx:
--------------------------------------------------------------------------------
1 | import firebase from "firebase/app"
2 | import "firebase/auth"
3 |
4 | const config = {
5 | apiKey: process.env.NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY,
6 | authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
7 | databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
8 | projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
9 | }
10 |
11 | export default function initFirebase() {
12 | if (!firebase.apps.length) {
13 | firebase.initializeApp(config)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/archive/viewer/decs.d.ts:
--------------------------------------------------------------------------------
1 | declare module "@theme-ui/presets"
2 |
--------------------------------------------------------------------------------
/archive/viewer/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/archive/viewer/next.config.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config()
2 |
3 | module.exports = {
4 | env: {},
5 | }
6 |
--------------------------------------------------------------------------------
/archive/viewer/pages/[oid]/[pid]/chart.tsx:
--------------------------------------------------------------------------------
1 | import { getProjectData } from "../../../utils/firebase"
2 | import NotFound404 from "../../../site/404"
3 | import { ProjectInfo } from "../../../utils/firebase"
4 | import { NextPage } from "next"
5 | import dynamic from "next/dynamic"
6 |
7 | const ChartPage = dynamic(() => import("../../../site/chart-page"), {
8 | ssr: false,
9 | })
10 |
11 | /**
12 | * A preview page that WILL subscribe to changes to the project document.
13 | * It's not "live" to the dirty changes — only saved changes will cause an update.
14 | */
15 | const LiveChart: NextPage<{ data: ProjectInfo }> = ({ data }) => {
16 | if (!data) return
17 | return
18 | }
19 |
20 | LiveChart.getInitialProps = async (ctx) => {
21 | let { oid, pid } = ctx.query
22 |
23 | pid = Array.isArray(pid) ? pid[0] : pid
24 | oid = Array.isArray(oid) ? oid[0] : oid
25 |
26 | if (!pid || !oid) return { data: undefined }
27 |
28 | const data = await getProjectData(pid, oid)
29 |
30 | return { data }
31 | }
32 |
33 | export default LiveChart
34 |
--------------------------------------------------------------------------------
/archive/viewer/pages/[oid]/[pid]/index.tsx:
--------------------------------------------------------------------------------
1 | import { useRouter } from "next/router"
2 | import useSWR from "swr"
3 | import { useUser } from "../../../auth/useUser"
4 | import dynamic from "next/dynamic"
5 |
6 | const Site = dynamic(() => import("../../../site/viewer"), {
7 | ssr: false,
8 | })
9 |
10 | const deadFetcher = () => {
11 | return undefined
12 | }
13 |
14 | const fetcher = (url: string, token: string) =>
15 | fetch(url, {
16 | method: "GET",
17 | headers: new Headers({ "Content-Type": "application/json", token }),
18 | credentials: "same-origin",
19 | }).then((res) => res.json())
20 |
21 | const Index = () => {
22 | const router = useRouter()
23 |
24 | const { oid, pid } = router.query
25 |
26 | const { user } = useUser()
27 |
28 | const { data } = useSWR(
29 | [`/api/${oid}/${pid}?uid=${user?.id}`, user?.token],
30 | pid ? fetcher : deadFetcher
31 | )
32 |
33 | return
34 | }
35 |
36 | export default Index
37 |
--------------------------------------------------------------------------------
/archive/viewer/pages/[oid]/[pid]/preview.tsx:
--------------------------------------------------------------------------------
1 | import { getProjectData } from "../../../utils/firebase"
2 | import NotFound404 from "../../../site/404"
3 | import { ProjectInfo } from "../../../utils/firebase"
4 | import { NextPage } from "next"
5 | import dynamic from "next/dynamic"
6 |
7 | const PreviewPage = dynamic(() => import("../../../site/preview-page"), {
8 | ssr: false,
9 | })
10 |
11 | /**
12 | * A preview page that WILL subscribe to changes to the project document.
13 | * It's not "live" to the dirty changes — only saved changes will cause an update.
14 | */
15 | const LivePreview: NextPage<{ data: ProjectInfo }> = ({ data }) => {
16 | if (!data) return
17 | return
18 | }
19 |
20 | LivePreview.getInitialProps = async (ctx) => {
21 | let { oid, pid } = ctx.query
22 |
23 | pid = Array.isArray(pid) ? pid[0] : pid
24 | oid = Array.isArray(oid) ? oid[0] : oid
25 |
26 | if (!pid || !oid) return { data: undefined }
27 |
28 | const data = await getProjectData(pid, oid)
29 |
30 | return { data }
31 | }
32 |
33 | export default LivePreview
34 |
--------------------------------------------------------------------------------
/archive/viewer/pages/[oid]/[pid]/static-preview.tsx:
--------------------------------------------------------------------------------
1 | import { getProjectData } from "../../../utils/firebase"
2 | import { ProjectInfo } from "../../../utils/firebase"
3 | import NotFound404 from "../../../site/404"
4 | import { NextPage } from "next"
5 | import dynamic from "next/dynamic"
6 |
7 | const StaticPreviewPage = dynamic(
8 | () => import("../../../site/static-preview-page"),
9 | {
10 | ssr: false,
11 | }
12 | )
13 |
14 | /**
15 | * A preview page that will NOT subscribe to changes to the project document.
16 | */
17 | const StaticPreview: NextPage<{ data: ProjectInfo }> = ({ data }) => {
18 | if (!data) return
19 | return
20 | }
21 |
22 | StaticPreview.getInitialProps = async (ctx) => {
23 | let { oid, pid } = ctx.query
24 |
25 | pid = Array.isArray(pid) ? pid[0] : pid
26 | oid = Array.isArray(oid) ? oid[0] : oid
27 |
28 | if (!pid || !oid) return { data: undefined }
29 |
30 | const data = await getProjectData(pid, oid)
31 |
32 | return { data }
33 | }
34 |
35 | export default StaticPreview
36 |
--------------------------------------------------------------------------------
/archive/viewer/pages/_app.js:
--------------------------------------------------------------------------------
1 | import Router from "next/router"
2 | import withGA from "next-ga"
3 | import "./styles.css"
4 | import { ThemeProvider } from "theme-ui"
5 | import { Global } from "@emotion/core"
6 | import theme from "../theme"
7 |
8 | function MyApp({ Component, pageProps }) {
9 | return (
10 |
11 | ({
13 | body: {
14 | fontFamily: theme.fonts.body,
15 | lineHeight: theme.lineHeights.body,
16 | fontWeight: theme.fontWeights.body,
17 | color: theme.colors.text,
18 | backgroundColor: theme.colors.background,
19 | margin: 0,
20 | minHeight: "100vh",
21 | position: "relative",
22 | display: "flex",
23 | flexDirection: "column",
24 | "*": {
25 | boxSizing: "border-box",
26 | },
27 | },
28 | })}
29 | />
30 |
31 |
32 |
33 |
34 | )
35 | }
36 |
37 | export default withGA("UA-159357149-1", Router)(MyApp)
38 |
--------------------------------------------------------------------------------
/archive/viewer/pages/_document.js:
--------------------------------------------------------------------------------
1 | import Document, { Html, Head, Main, NextScript } from "next/document"
2 |
3 | class CustomDocument extends Document {
4 | static async getInitialProps(ctx) {
5 | const initialProps = await Document.getInitialProps(ctx)
6 | return { ...initialProps }
7 | }
8 |
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 | CustomDocument.getInitialProps = async (ctx) => {
24 | return Document.getInitialProps(ctx)
25 | }
26 |
27 | export default CustomDocument
28 |
--------------------------------------------------------------------------------
/archive/viewer/pages/admin.tsx:
--------------------------------------------------------------------------------
1 | import useSWR from "swr"
2 | import * as React from "react"
3 | import { useUser } from "../auth/useUser"
4 | import { AdminResponse } from "../utils/firebase"
5 | import dynamic from "next/dynamic"
6 |
7 | const Admin = dynamic(() => import("../site/admin"), {
8 | ssr: false,
9 | })
10 |
11 | const fetcher = (url: string, token: string) =>
12 | fetch(url, {
13 | method: "GET",
14 | headers: new Headers({ "Content-Type": "application/json", token }),
15 | credentials: "same-origin",
16 | }).then((res) => res.json())
17 |
18 | const Index = () => {
19 | const { user } = useUser()
20 |
21 | const { data } = useSWR(
22 | [`/api/admin?uid=${user?.id}`, user?.token],
23 | fetcher
24 | )
25 |
26 | return
27 | }
28 |
29 | export default Index
30 |
--------------------------------------------------------------------------------
/archive/viewer/pages/api/[oid]/[pid]/index.tsx:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | import { NextApiRequest, NextApiResponse } from "next"
4 | import { verifyIdToken } from "../../../../auth/firebaseAdmin"
5 | import "firebase/firestore"
6 | import { ProjectResponse, getProjectInfo } from "../../../../utils/firebase"
7 |
8 | export default async (
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) => {
12 | const { token } = req.headers
13 | let { pid, oid, uid } = req.query
14 |
15 | pid = Array.isArray(pid) ? pid[0] : pid
16 | oid = Array.isArray(oid) ? oid[0] : oid
17 | uid = Array.isArray(uid) ? uid[0] : uid
18 |
19 | // Check whether project exists, and whether the current user
20 | // is the owner of that project
21 |
22 | const { isProject, isOwner } = await getProjectInfo(pid, oid, uid)
23 |
24 | try {
25 | await verifyIdToken(token)
26 | return res.status(200).json({
27 | oid,
28 | pid,
29 | uid,
30 | isProject,
31 | isOwner,
32 | isAuthenticated: true,
33 | error: undefined,
34 | })
35 | } catch (error) {
36 | return res.status(400).json({
37 | oid,
38 | pid,
39 | uid,
40 | isProject,
41 | isOwner,
42 | isAuthenticated: false,
43 | error,
44 | })
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/archive/viewer/pages/api/[oid]/index.tsx:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | import { NextApiRequest, NextApiResponse } from "next"
4 | import { verifyIdToken } from "../../../auth/firebaseAdmin"
5 | import "firebase/firestore"
6 | import {
7 | UserProjectsResponse,
8 | getUserProjects,
9 | addUser,
10 | } from "../../../utils/firebase"
11 |
12 | export default async (
13 | req: NextApiRequest,
14 | res: NextApiResponse
15 | ) => {
16 | const { token } = req.headers
17 | let { oid, uid } = req.query
18 |
19 | oid = Array.isArray(oid) ? oid[0] : oid
20 | uid = Array.isArray(uid) ? uid[0] : uid
21 |
22 | // Check whether project exists, and whether the current user
23 | // is the owner of that project
24 |
25 | const { projects } = await getUserProjects(oid)
26 |
27 | await addUser(uid)
28 |
29 | try {
30 | await verifyIdToken(token)
31 | return res.status(200).json({
32 | oid,
33 | uid,
34 | projects,
35 | isOwner: true,
36 | isAuthenticated: true,
37 | error: undefined,
38 | })
39 | } catch (error) {
40 | console.log("Could not verify token:", error.message)
41 | return res.status(400).json({
42 | oid,
43 | uid,
44 | projects,
45 | isOwner: true,
46 | isAuthenticated: false,
47 | error,
48 | })
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/archive/viewer/pages/api/admin.tsx:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | import { NextApiRequest, NextApiResponse } from "next"
4 | import { verifyIdToken } from "../../auth/firebaseAdmin"
5 | import "firebase/firestore"
6 | import { AdminResponse, addUser, getAdminData } from "../../utils/firebase"
7 |
8 | export default async (
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) => {
12 | const { token } = req.headers
13 | let { uid } = req.query
14 |
15 | uid = Array.isArray(uid) ? uid[0] : uid
16 |
17 | // Check whether project exists, and whether the current user
18 | // is the owner of that project
19 |
20 | await addUser(uid)
21 |
22 | const projects = await getAdminData()
23 |
24 | try {
25 | await verifyIdToken(token)
26 | return res.status(200).json({
27 | projects,
28 | isAuthenticated: true,
29 | error: undefined,
30 | })
31 | } catch (error) {
32 | return res.status(400).json({
33 | projects,
34 | isAuthenticated: false,
35 | error,
36 | })
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/archive/viewer/pages/auth.tsx:
--------------------------------------------------------------------------------
1 | import dynamic from "next/dynamic"
2 |
3 | const FirebaseAuth = dynamic(() => import("../site/firebase-auth"), {
4 | ssr: false,
5 | })
6 |
7 | const Auth = () => {
8 | return
9 | }
10 |
11 | export default Auth
12 |
--------------------------------------------------------------------------------
/archive/viewer/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Site from "../site"
2 |
3 | const Index = () => {
4 | return
5 | }
6 |
7 | export default Index
8 |
--------------------------------------------------------------------------------
/archive/viewer/pages/user.tsx:
--------------------------------------------------------------------------------
1 | import useSWR from "swr"
2 | import * as React from "react"
3 | import { useUser } from "../auth/useUser"
4 | import { UserProjectsResponse } from "../utils/firebase"
5 | import dynamic from "next/dynamic"
6 |
7 | const User = dynamic(() => import("../site/user"), {
8 | ssr: false,
9 | })
10 |
11 | const fetcher = (url: string, token: string) =>
12 | fetch(url, {
13 | method: "GET",
14 | headers: new Headers({ "Content-Type": "application/json", token }),
15 | credentials: "same-origin",
16 | }).then((res) => res.json())
17 |
18 | const Index = () => {
19 | const { user } = useUser()
20 |
21 | const { data } = useSWR(
22 | [`/api/${user?.id}?uid=${user?.id}`, user?.token],
23 | fetcher
24 | )
25 |
26 | return
27 | }
28 |
29 | export default Index
30 |
--------------------------------------------------------------------------------
/archive/viewer/public/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/android-chrome-192x192.png
--------------------------------------------------------------------------------
/archive/viewer/public/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/android-chrome-512x512.png
--------------------------------------------------------------------------------
/archive/viewer/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/archive/viewer/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/archive/viewer/public/cursor.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/archive/viewer/public/discord.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/archive/viewer/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/favicon-16x16.png
--------------------------------------------------------------------------------
/archive/viewer/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/favicon-32x32.png
--------------------------------------------------------------------------------
/archive/viewer/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/favicon.ico
--------------------------------------------------------------------------------
/archive/viewer/public/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/mstile-150x150.png
--------------------------------------------------------------------------------
/archive/viewer/public/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
24 |
--------------------------------------------------------------------------------
/archive/viewer/public/sd-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/archive/viewer/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/archive/viewer/public/splash_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/splash_dark.png
--------------------------------------------------------------------------------
/archive/viewer/public/splash_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/archive/viewer/public/splash_light.png
--------------------------------------------------------------------------------
/archive/viewer/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/archive/viewer/site/404.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reset
2 | import * as React from "react"
3 | import { Heading, Button, Flex } from "theme-ui"
4 | import { useRouter } from "next/router"
5 |
6 | const NotFound404: React.FC<{}> = () => {
7 | const router = useRouter()
8 | return (
9 |
10 | Page Not Found
11 |
12 |
15 |
16 |
17 |
18 | )
19 | }
20 |
21 | export default NotFound404
22 |
--------------------------------------------------------------------------------
/archive/viewer/site/admin/index.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import * as React from "react"
3 | import { useRouter } from "next/router"
4 | import { AdminResponse } from "../../utils/firebase"
5 | import { jsx, Styled, Box } from "theme-ui"
6 | import LoadingScreen from "../loading-screen"
7 |
8 | const User: React.FC<{ data: AdminResponse }> = ({ data }) => {
9 | const router = useRouter()
10 |
11 | React.useEffect(() => {
12 | if (data && !data.isAuthenticated) {
13 | router.push("/auth")
14 | }
15 | }, [data])
16 |
17 | if (!data) return
18 |
19 | let sorted: Record = {}
20 |
21 | for (let project of data.projects) {
22 | if (sorted[project.oid]) {
23 | sorted[project.oid].push(project)
24 | } else {
25 | sorted[project.oid] = [project]
26 | }
27 | }
28 |
29 | return (
30 |
31 |
32 | {Object.entries(sorted).map(([id, projects], i) => (
33 | -
34 | {id}
35 |
36 | {projects.map(({ pid, name }, i) => (
37 | -
38 | {name}
39 |
40 | ))}
41 |
42 |
43 | ))}
44 |
45 |
46 | )
47 | }
48 |
49 | export default User
50 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/chart/branch-node.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import sortBy from "lodash/sortBy"
3 | import { Flex, Card } from "theme-ui"
4 | import { S } from "@state-designer/react"
5 | import NodeHeading from "./node-heading"
6 | import StateNode from "./state-node"
7 | import NodeEvents from "./node-events"
8 |
9 | const BranchNode: React.FC<{ node: S.State }> = ({ node }) => {
10 | const childNodes = Object.values(node.states)
11 |
12 | function getSortedBranchChildNodes(nodes: S.State[]) {
13 | return sortBy(
14 | // sortBy(nodes, (n) => Object.values(n.states).length).reverse(),
15 | nodes,
16 | (n) => !n.isInitial
17 | )
18 | }
19 |
20 | return (
21 |
26 |
27 |
28 |
29 | {getSortedBranchChildNodes(childNodes).map((child, i) => (
30 |
31 | ))}
32 |
33 |
34 | )
35 | }
36 | export default BranchNode
37 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/chart/initial-marker.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Disc } from "react-feather"
3 |
4 | const InitialMarker: React.FC = () => {
5 | return
6 | }
7 |
8 | export default InitialMarker
9 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/chart/leaf-node.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Card } from "theme-ui"
3 | import { S } from "@state-designer/react"
4 | import NodeHeading from "./node-heading"
5 | import NodeEvents from "./node-events"
6 |
7 | const LeafNode: React.FC<{ node: S.State }> = ({ node }) => {
8 | return (
9 |
14 |
15 |
16 |
17 | )
18 | }
19 | export default LeafNode
20 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/chart/node-heading.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import { jsx, Heading, Flex } from "theme-ui"
3 | import { S } from "@state-designer/react"
4 | import IconSelect from "../icon-select"
5 | import { Disc, MoreVertical } from "react-feather"
6 | import { Project, UI } from "../../states"
7 |
8 | const NodeHeading: React.FC<{
9 | node: S.State
10 | isParallel?: boolean
11 | }> = ({ node, isParallel = false }) => {
12 | return (
13 |
20 |
21 | {node.isInitial && }
22 | {node.name}
23 |
24 | }
27 | title="State"
28 | options={{
29 | "Zoom to State": () => UI.send("ZOOMED_TO_NODE", { path: node.path }),
30 | "Force Transition": () =>
31 | Project.data.captive.forceTransition(node.name),
32 | "Force Previous Transition": () =>
33 | Project.data.captive.forceTransition(node.name + ".previous"),
34 | "Force Restore Transition": () =>
35 | Project.data.captive.forceTransition(node.name + ".restore"),
36 | }}
37 | />
38 |
39 | )
40 | }
41 |
42 | export default NodeHeading
43 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/chart/parallel-divider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Box } from "theme-ui"
3 |
4 | const Node: React.FC<{ isActive: boolean }> = ({ isActive }) => {
5 | return (
6 |
14 | )
15 | }
16 |
17 | export default Node
18 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/chart/state-node.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Flex } from "theme-ui"
3 | import { S } from "@state-designer/react"
4 | import ParallelNode from "./parallel-node"
5 | import BranchNode from "./branch-node"
6 | import LeafNode from "./leaf-node"
7 | import { Highlights } from "../../states/highlights"
8 |
9 | const StateNode = React.forwardRef }>(
10 | ({ node }, ref) => {
11 | const rContainer = React.useRef(null)
12 |
13 | React.useEffect(() => {
14 | Highlights.send("MOUNTED_NODE", { path: node.path, ref: rContainer })
15 | }, [node])
16 |
17 | return (
18 | {
25 | e.stopPropagation()
26 | Highlights.send("HIGHLIT_STATE", {
27 | stateName: node.name,
28 | shiftKey: e.shiftKey,
29 | path: node.path,
30 | })
31 | }}
32 | onMouseLeave={(e) => {
33 | e.stopPropagation()
34 | Highlights.send("CLEARED_STATE_HIGHLIGHT", { stateName: node.name })
35 | }}
36 | >
37 | {node.type === "parallel" ? (
38 |
39 | ) : node.type === "branch" ? (
40 |
41 | ) : (
42 |
43 | )}
44 |
45 | )
46 | }
47 | )
48 |
49 | export default StateNode
50 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/code/save-row.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import { Box, Text, IconButton, Grid, jsx } from "theme-ui"
3 | import {
4 | Circle,
5 | Save as SaveIcon,
6 | RefreshCcw,
7 | AlertOctagon,
8 | } from "react-feather"
9 | import { S, useStateDesigner } from "@state-designer/react"
10 |
11 | const SaveRow: React.FC<{ state: S.DesignedState }> = ({ state }) => {
12 | const local = useStateDesigner(state)
13 |
14 | return (
15 |
28 |
29 | {local.data.error.length > 0 && (
30 |
31 | )}{" "}
32 |
33 |
36 | {local.data.error}
37 |
38 | local.send("SAVED")}
42 | >
43 |
44 |
45 | local.send("CANCELLED")}
49 | >
50 |
51 |
52 |
53 | )
54 | }
55 | export default SaveRow
56 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/color-mode-toggle.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import * as React from "react"
3 | import { Sun, Moon } from "react-feather"
4 | import { jsx, IconButton, useColorMode, BoxProps } from "theme-ui"
5 |
6 | const ColorModeToggle: React.FC = (props) => {
7 | const [colorMode, setColorMode] = useColorMode()
8 |
9 | return (
10 | setColorMode(colorMode === "default" ? "dark" : "default")}
13 | sx={{ ml: 2, ...props.sx }}
14 | >
15 | {colorMode === "dark" ? : }
16 |
17 | )
18 | }
19 |
20 | export default ColorModeToggle
21 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/column.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Flex, BoxProps } from "theme-ui"
3 |
4 | const Column: React.FC = (props) => {
5 | return (
6 |
10 | )
11 | }
12 | export default Column
13 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/content/content-row-item.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import { jsx, Box, Styled, BoxProps } from "theme-ui"
3 |
4 | const ContentRowItem: React.FC = (props) => {
5 | return (
6 |
7 |
8 |
9 | )
10 | }
11 |
12 | export default ContentRowItem
13 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/controls.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import * as React from "react"
3 | import { Project } from "../states"
4 | import { Copy } from "react-feather"
5 | import { useStateDesigner } from "@state-designer/react"
6 | import ColorModeToggle from "./color-mode-toggle"
7 | import { jsx, Flex, IconButton, Button } from "theme-ui"
8 |
9 | const Controls: React.FC = ({}) => {
10 | const local = useStateDesigner(Project)
11 |
12 | return (
13 |
22 | {local.data.isOwner ? (
23 | local.send("FORKED_PROJECT")}
26 | >
27 |
28 |
29 | ) : (
30 |
42 | )}
43 |
44 |
45 | )
46 | }
47 |
48 | export default Controls
49 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/details/data.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Flex, Heading, Styled, Box } from "theme-ui"
3 |
4 | const Data: React.FC<{ data: any }> = ({ data }) => {
5 | return (
6 |
12 |
16 | Data
17 |
18 |
19 |
20 | {JSON.stringify(data, null, 2)}
21 |
22 |
23 |
24 | )
25 | }
26 | export default Data
27 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/details/log.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Flex, Heading, Styled, Box } from "theme-ui"
3 |
4 | const Log: React.FC<{ log: string[] }> = ({ log }) => {
5 | const rContainer = React.useRef()
6 |
7 | return (
8 |
18 |
22 | Log
23 |
24 |
25 |
26 | {log.map((entry, i) => (
27 | {entry}
28 | ))}
29 |
30 |
31 |
32 | )
33 | }
34 | export default Log
35 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/details/tests/test.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Box, Styled, Spinner, Text } from "theme-ui"
3 | import { XCircle, CheckCircle } from "react-feather"
4 |
5 | const colors = {
6 | running: "text",
7 | pass: "Green",
8 | fail: "accent",
9 | }
10 |
11 | const Test: React.FC<{
12 | name: string
13 | message: string
14 | state: "running" | "pass" | "fail"
15 | }> = ({ name, message, state }) => {
16 | const icons = {
17 | running: ,
18 | pass: ,
19 | fail: ,
20 | }
21 |
22 | return (
23 |
24 | {icons[state]}
25 | {name}
26 | {message && {message}}
27 |
28 | )
29 | }
30 |
31 | export default Test
32 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/details/values.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Flex, Heading, Styled, Box } from "theme-ui"
3 |
4 | const Values: React.FC<{ values: any }> = ({ values, children }) => {
5 | return (
6 |
15 |
19 | Values
20 |
21 |
22 |
23 | {JSON.stringify(values, null, 2)}
24 |
25 |
26 | {children}
27 |
28 | )
29 | }
30 | export default Values
31 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/drag-handle.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { motion, MotionValue, PanInfo } from "framer-motion"
3 |
4 | const DragHandleHorizontal: React.FC<{
5 | initial: number
6 | motionValue: MotionValue
7 | max?: number
8 | min?: number
9 | align?: "right" | "left"
10 | gridArea?: string
11 | onDoubleClick: () => void
12 | onPan: (e: any, info: PanInfo) => void
13 | }> = ({ gridArea, children, motionValue, onDoubleClick, onPan }) => {
14 | return (
15 | onPan && onPan(e, info)}
35 | onDoubleClick={onDoubleClick}
36 | >
37 | {children}
38 |
39 | )
40 | }
41 |
42 | export default DragHandleHorizontal
43 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/footer-column.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Box, BoxProps } from "theme-ui"
3 |
4 | const FooterColumn: React.FC = (props) => {
5 | return
6 | }
7 | export default FooterColumn
8 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/icon-select.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Box, BoxProps, IconButton } from "theme-ui"
3 |
4 | const IconSelect: React.FC<
5 | {
6 | title: string
7 | icon: React.ReactNode
8 | options: Record void)>
9 | } & BoxProps
10 | > = ({ icon, title, options, ...props }) => {
11 | return (
12 |
13 | {icon}
14 |
41 |
42 | )
43 | }
44 |
45 | export default IconSelect
46 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/main/reset-button.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import * as React from "react"
3 | import { jsx, Button } from "theme-ui"
4 | import { RefreshCw } from "react-feather"
5 | import { S, useStateDesigner } from "@state-designer/react"
6 |
7 | const ResetButton: React.FC<{ state: S.DesignedState }> = ({
8 | state,
9 | }) => {
10 | const local = useStateDesigner(state, [state])
11 |
12 | return (
13 |
27 | )
28 | }
29 |
30 | export default ResetButton
31 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/components/title.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Flex } from "theme-ui"
3 | import { Project } from "../states"
4 | import { useStateDesigner } from "@state-designer/react"
5 |
6 | const Title: React.FC = ({}) => {
7 | const local = useStateDesigner(Project)
8 | const captive = useStateDesigner(local.data.captive, [local.data.captive])
9 |
10 | return (
11 |
21 | {captive.id.slice(1)}
22 |
23 | )
24 | }
25 | export default Title
26 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/hooks/useFirebaseCode.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import firebase from "firebase"
3 |
4 | const db = firebase.firestore()
5 |
6 | export function useFirebaseCode(id: string) {
7 | const doc = React.useMemo(() => db.collection("projects").doc(id), [id])
8 |
9 | const [state, setState] = React.useState(null)
10 |
11 | React.useEffect(() => {
12 | doc.onSnapshot((doc) => {
13 | setState(doc.data().code)
14 | })
15 | }, [id])
16 |
17 | const update = React.useCallback(
18 | (code: string) =>
19 | doc.update({
20 | code: JSON.stringify(code),
21 | }),
22 | []
23 | )
24 |
25 | return [state, update] as const
26 | }
27 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import CodeColumn from "./components/code"
3 | import Menu from "./components/menu"
4 | import Main from "./components/main"
5 | import Title from "./components/title"
6 | import Layout from "./components/layout"
7 | import Content from "./components/content"
8 | import DetailRow from "./components/details"
9 | import Controls from "./components/controls"
10 | import Tabs from "./components/tabs"
11 |
12 | const Viewer: React.FC<{ authenticated: boolean }> = ({ authenticated }) => {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | )
25 | }
26 |
27 | export default Viewer
28 |
--------------------------------------------------------------------------------
/archive/viewer/site/app/utils.tsx:
--------------------------------------------------------------------------------
1 | import { S } from "@state-designer/react"
2 |
3 | export function getFlatStates(state: S.State): S.State[] {
4 | return [state].concat(...Object.values(state.states).map(getFlatStates))
5 | }
6 |
7 | export function getAllEvents(state: S.State): string[][] {
8 | const localEvents: string[][] = []
9 |
10 | localEvents.push(...Object.keys(state.on).map((k) => [state.name, k]))
11 |
12 | for (let child of Object.values(state.states)) {
13 | localEvents.push(...getAllEvents(child))
14 | }
15 |
16 | return localEvents
17 | }
18 |
19 | export function getEventsByState(events: string[][]): [string, string[]][] {
20 | const dict: Record = {}
21 |
22 | for (let [stateName, event] of events) {
23 | const prior = dict[event]
24 | if (prior === undefined) {
25 | dict[event] = [stateName]
26 | } else {
27 | dict[event].push(stateName)
28 | }
29 | }
30 |
31 | return Object.entries(dict)
32 | }
33 |
--------------------------------------------------------------------------------
/archive/viewer/site/index.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reset
2 | import * as React from "react"
3 |
4 | import Landing from "./landing-page"
5 | const App: React.FC<{}> = () => {
6 | return
7 | }
8 |
9 | export default App
10 |
--------------------------------------------------------------------------------
/archive/viewer/site/loading-screen.tsx:
--------------------------------------------------------------------------------
1 | // @jsx jsx
2 | import { jsx, Flex, Spinner, Box, BoxProps } from "theme-ui"
3 |
4 | const LoadingScreen: React.FC = ({ children, ...props }) => {
5 | return (
6 |
22 |
23 | {children}
24 |
25 | )
26 | }
27 |
28 | export default LoadingScreen
29 |
--------------------------------------------------------------------------------
/archive/viewer/site/static/colors.tsx:
--------------------------------------------------------------------------------
1 | export default {
2 | Black: "#1a1c2c",
3 | Purple: "#5d275d",
4 | Red: "#b13e53",
5 | Orange: "#ef7d57",
6 | Yellow: "#ffcd75",
7 | LightGreen: "#a7f070",
8 | Green: "#38b764",
9 | DarkGreen: "#257179",
10 | DarkBlue: "#29366f",
11 | Blue: "#3b5dc9",
12 | LightBlue: "#41a6f6",
13 | Aqua: "#73eff7",
14 | White: "#f4f4f4",
15 | LightGray: "#94b0c2",
16 | Gray: "#566c86",
17 | DarkGray: "#333c57",
18 | }
19 |
--------------------------------------------------------------------------------
/archive/viewer/site/static/defaults.tsx:
--------------------------------------------------------------------------------
1 | export const defaultTheme = JSON.stringify(`const theme = {
2 | colors: {
3 | text: '#000',
4 | background: '#fff',
5 | primary: '#11e',
6 | secondary: '#c0c',
7 | highlight: '#e0e',
8 | muted: '#f6f6ff',
9 | modes: {
10 | dark: {
11 | text: '#fff',
12 | background: '#fff',
13 | primary: '#0fc',
14 | secondary: '#0cf',
15 | highlight: '#f0c',
16 | muted: '#011',
17 | },
18 | },
19 | },
20 | fonts: {
21 | body: '"Avenir Next", system-ui, sans-serif',
22 | heading: 'inherit',
23 | monospace: 'Menlo, monospace',
24 | },
25 | fontWeights: {
26 | body: 400,
27 | heading: 600,
28 | bold: 700,
29 | },
30 | lineHeights: {
31 | body: 1.75,
32 | heading: 1.25,
33 | },
34 | }`)
35 |
36 | export const defaultStatics = JSON.stringify(
37 | `function getStatic() {
38 | return {
39 | date: new Date(),
40 | name: "Shingirayi"
41 | }
42 | }`
43 | )
44 |
45 | export const defaultTests = `"describe(\"Always fail!\", async () => {\n expect(2).toBe(1)\n })"`
46 |
--------------------------------------------------------------------------------
/archive/viewer/site/static/example-links.tsx:
--------------------------------------------------------------------------------
1 | export default [
2 | { name: "Toggle", id: "toggle" },
3 | { name: "Counter", id: "counter" },
4 | { name: "Dog Pics", id: "dogs" },
5 | { name: "Accordion", id: "accordion" },
6 | { name: "Todo", id: "input" },
7 | { name: "Code Editor", id: "editor" },
8 | { name: "Tile Puzzle", id: "tiles" },
9 | { name: "Calculator", id: "calculator" },
10 | { name: "Snake", id: "snake" },
11 | { name: "Drawing", id: "drawing" },
12 | { name: "Tetris", id: "tetris" },
13 | ]
14 |
--------------------------------------------------------------------------------
/archive/viewer/site/user/layout.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Grid } from "theme-ui"
3 |
4 | const Layout: React.FC = ({ children }) => {
5 | return (
6 |
38 | {children}
39 |
40 | )
41 | }
42 |
43 | export default Layout
44 |
--------------------------------------------------------------------------------
/archive/viewer/site/viewer.tsx:
--------------------------------------------------------------------------------
1 | // @refresh reset
2 | import * as React from "react"
3 | import NotFound from "./not-found"
4 | import FirebaseAuth from "./firebase-auth"
5 | import LoadingScreen from "./loading-screen"
6 | import Viewer from "./app"
7 | import { Project } from "./app/states"
8 | import { useStateDesigner } from "@state-designer/react"
9 | import { ProjectResponse } from "../utils/firebase"
10 | import router from "next/router"
11 | import { useUser } from "../auth/useUser"
12 |
13 | const App: React.FC<{ data: ProjectResponse }> = ({ data, children }) => {
14 | const project = useStateDesigner(Project)
15 |
16 | React.useEffect(() => {
17 | if (data) {
18 | project.send("OPENED_PROJECT", { data })
19 | }
20 | }, [data?.pid])
21 |
22 | if (!data || project.isIn("loading")) {
23 | return
24 | }
25 |
26 | const { oid, pid, uid, isAuthenticated } = data
27 |
28 | return project.whenIn({
29 | loading: ,
30 | ready: ,
31 | notFound: ,
32 | authenticating: ,
33 | default: hmm, there seems to be a problem
,
34 | })
35 | }
36 |
37 | export default App
38 |
--------------------------------------------------------------------------------
/archive/viewer/todo.md:
--------------------------------------------------------------------------------
1 | # State Designer IDE — Todo
2 |
3 | ## Someday
4 |
5 | - [ ] Change name from viewer to IDE
6 |
7 | ## Soon
8 |
9 | - [x] Cleanup project files, move editor into its own package
10 | - [ ] Make projects viewable to non-authenticated users
11 |
--------------------------------------------------------------------------------
/archive/viewer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "strict": false,
12 | "forceConsistentCasingInFileNames": true,
13 | "noEmit": true,
14 | "esModuleInterop": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "jsx": "preserve"
20 | },
21 | "exclude": [
22 | "node_modules"
23 | ],
24 | "include": [
25 | "next-env.d.ts",
26 | "**/*.ts",
27 | "**/*.tsx"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/example/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Stephen Ruiz Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # @state-designer example
2 |
3 | A (relatively) simple example project for `@state-designer`.
4 |
5 | To start this project:
6 |
7 | - run `yarn start` in the root directory
8 | - open `http://localhost:5420` in your browser
9 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.0",
3 | "name": "@state-designer/example",
4 | "description": "A simple example project for state-designer.",
5 | "author": "@steveruizok",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/steveruizok/state-designer.git"
9 | },
10 | "license": "MIT",
11 | "private": true,
12 | "scripts": {
13 | "start": "node scripts/dev.mjs -w"
14 | },
15 | "files": [],
16 | "devDependencies": {
17 | "@state-designer/core": "latest",
18 | "@state-designer/react": "latest",
19 | "@types/node": "^14.14.35",
20 | "@types/react": "^16.9.55",
21 | "@types/react-dom": "^16.9.9",
22 | "@types/react-router-dom": "^5.1.8",
23 | "concurrently": "6.0.1",
24 | "esbuild": "^0.13.8",
25 | "esbuild-serve": "^1.0.1",
26 | "react": ">=16.8",
27 | "react-dom": "^16.8 || ^17.0",
28 | "rimraf": "3.0.2",
29 | "typescript": "4.2.3"
30 | },
31 | "gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6"
32 | }
33 |
--------------------------------------------------------------------------------
/example/scripts/dev.mjs:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | import fs from 'fs'
3 | import esbuildServe from 'esbuild-serve'
4 |
5 | async function main() {
6 | if (!fs.existsSync('./dist')) {
7 | fs.mkdirSync('./dist')
8 | }
9 |
10 | fs.copyFile('./src/index.html', './dist/index.html', (err) => {
11 | if (err) throw err
12 | })
13 |
14 | try {
15 | await esbuildServe(
16 | {
17 | entryPoints: ['src/index.tsx'],
18 | outdir: 'dist',
19 | bundle: true,
20 | minify: false,
21 | sourcemap: true,
22 | incremental: true,
23 | target: ['chrome58', 'firefox57', 'safari11', 'edge18'],
24 | define: {
25 | 'process.env.NODE_ENV': '"development"',
26 | },
27 | watch: {
28 | onRebuild(err) {
29 | err ? error('❌ Failed') : log('✅ Updated')
30 | },
31 | },
32 | },
33 | {
34 | port: 5420,
35 | root: './dist',
36 | live: true,
37 | }
38 | )
39 | } catch (err) {
40 | process.exit(1)
41 | }
42 | }
43 |
44 | main()
45 |
--------------------------------------------------------------------------------
/example/src/app.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import { useStateDesigner } from '@state-designer/react'
3 | import { state } from './state'
4 |
5 | export default function App(): JSX.Element {
6 | const local = useStateDesigner(state)
7 | return ...
8 | }
9 |
--------------------------------------------------------------------------------
/example/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | tldraw
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/example/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './app'
4 | import './styles.css'
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | )
12 |
--------------------------------------------------------------------------------
/example/src/styles.css:
--------------------------------------------------------------------------------
1 | html,
2 | * {
3 | box-sizing: border-box;
4 | }
5 |
6 | body {
7 | overscroll-behavior: none;
8 | margin: 0px;
9 | padding: 0px;
10 | }
11 |
12 | .tldraw {
13 | position: fixed;
14 | top: 0px;
15 | left: 0px;
16 | right: 0px;
17 | bottom: 0px;
18 | width: 100%;
19 | height: 100%;
20 | }
21 |
--------------------------------------------------------------------------------
/example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.base.json",
3 | "include": ["src"],
4 | "exclude": ["node_modules", "dist", "docs"],
5 | "compilerOptions": {
6 | "outDir": "./dist/types",
7 | "rootDir": "src",
8 | "baseUrl": "src",
9 | "emitDeclarationOnly": false,
10 | "paths": {
11 | "@tldraw/core": ["../packages/core"]
12 | }
13 | },
14 | "references": [{ "path": "../packages/core" }],
15 | "typedocOptions": {
16 | "entryPoints": ["src/index.ts"],
17 | "out": "docs"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.0",
3 | "registry": "https://registry.npmjs.org/",
4 | "publishConfig": {
5 | "access": "public",
6 | "directory": "dist"
7 | },
8 | "npmClient": "yarn",
9 | "useWorkspaces": true
10 | }
11 |
--------------------------------------------------------------------------------
/packages/core/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 3.0.0
4 |
5 | - Rebuilds repo
6 |
--------------------------------------------------------------------------------
/packages/core/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Stephen Ruiz Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/core/docs/.nojekyll:
--------------------------------------------------------------------------------
1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false.
--------------------------------------------------------------------------------
/packages/core/docs/assets/highlight.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --light-code-background: #FFFFFF;
3 | --dark-code-background: #1E1E1E;
4 | }
5 |
6 | @media (prefers-color-scheme: light) { :root {
7 | --code-background: var(--light-code-background);
8 | } }
9 |
10 | @media (prefers-color-scheme: dark) { :root {
11 | --code-background: var(--dark-code-background);
12 | } }
13 |
14 | body.light {
15 | --code-background: var(--light-code-background);
16 | }
17 |
18 | body.dark {
19 | --code-background: var(--dark-code-background);
20 | }
21 |
22 | pre, code { background: var(--code-background); }
23 |
--------------------------------------------------------------------------------
/packages/core/docs/assets/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/core/docs/assets/icons.png
--------------------------------------------------------------------------------
/packages/core/docs/assets/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/core/docs/assets/icons@2x.png
--------------------------------------------------------------------------------
/packages/core/docs/assets/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/core/docs/assets/widgets.png
--------------------------------------------------------------------------------
/packages/core/docs/assets/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/core/docs/assets/widgets@2x.png
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.0",
3 | "name": "@state-designer/core",
4 | "description": "State management with state-charts.",
5 | "author": "@steveruizok",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/steveruizok/state-designer/core.git"
9 | },
10 | "license": "MIT",
11 | "keywords": [
12 | "react",
13 | "state",
14 | "statechart"
15 | ],
16 | "files": [
17 | "dist/**/*"
18 | ],
19 | "main": "./dist/cjs/index.js",
20 | "module": "./dist/esm/index.js",
21 | "types": "./dist/types/index.d.ts",
22 | "scripts": {
23 | "start": "node scripts/dev & yarn types:dev",
24 | "build": "node scripts/build && yarn types:build",
25 | "types:dev": "tsc -w --p tsconfig.build.json",
26 | "types:build": "tsc -p tsconfig.build.json",
27 | "lint": "eslint src/ --ext .ts,.tsx",
28 | "clean": "rm -rf dist",
29 | "test": "jest",
30 | "test:watch": "jest --watchAll",
31 | "docs": "typedoc",
32 | "docs:watch": "typedoc --watch"
33 | },
34 | "devDependencies": {
35 | "@types/jest": "^27.0.2",
36 | "@types/node": "^16.11.6"
37 | },
38 | "dependencies": {
39 | "immer": "^9.0.6",
40 | "nanoid": "^3.1.30"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/packages/core/scripts/dev.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const esbuild = require('esbuild')
3 | const pkg = require('../package.json')
4 |
5 | async function main() {
6 | esbuild.build({
7 | entryPoints: ['./src/index.ts'],
8 | outdir: 'dist/esm',
9 | minify: false,
10 | bundle: true,
11 | format: 'esm',
12 | target: 'es6',
13 | tsconfig: './tsconfig.build.json',
14 | external: Object.keys(pkg.dependencies),
15 | incremental: true,
16 | sourcemap: true,
17 | watch: {
18 | onRebuild(error) {
19 | if (error) {
20 | console.log(`× ${pkg.name}: An error in prevented the rebuild.`)
21 | return
22 | }
23 | console.log(`✔ ${pkg.name}: Rebuilt.`)
24 | },
25 | },
26 | })
27 | }
28 |
29 | main()
30 |
--------------------------------------------------------------------------------
/packages/core/src/customError.ts:
--------------------------------------------------------------------------------
1 | export default function customError(message: string, error: Error) {
2 | const err = new Error(message + ' ' + error.message)
3 | err.stack = error.stack
4 | return err
5 | }
6 |
--------------------------------------------------------------------------------
/packages/core/src/decs.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'object.entries'
2 |
--------------------------------------------------------------------------------
/packages/core/src/index.ts:
--------------------------------------------------------------------------------
1 | import { createDesign } from './createDesign'
2 | import { createState } from './createState'
3 |
4 | export { createDesign, createState }
5 | export * as S from './types'
6 |
--------------------------------------------------------------------------------
/packages/core/src/test/createDesign.spec.ts:
--------------------------------------------------------------------------------
1 | import { createDesign } from '../'
2 | import { design } from './shared'
3 |
4 | describe('createDesign', () => {
5 | it('Should create a design.', () => {
6 | expect(design).toBeTruthy()
7 | expect(createDesign({})).toBeTruthy()
8 | })
9 |
10 | it('Should include collections.', () => {
11 | expect(design.results).toBeTruthy()
12 | expect(design.conditions).toBeTruthy()
13 | expect(design.actions).toBeTruthy()
14 | expect(design.asyncs).toBeTruthy()
15 | expect(design.times).toBeTruthy()
16 | })
17 | })
18 |
--------------------------------------------------------------------------------
/packages/core/src/testEventHandlerConditions.ts:
--------------------------------------------------------------------------------
1 | import type * as S from './types'
2 |
3 | /**
4 | * Test whether a handler object would pass its conditions, given the current data, payload, and result.
5 | * @param h Handler
6 | * @param d Data
7 | * @param p Payload
8 | * @param r Result
9 | */
10 | export function testEventHandlerConditions(
11 | h: S.EventHandlerObject | S.InitialStateObject,
12 | d: D,
13 | p: P,
14 | r: R
15 | ) {
16 | try {
17 | if (h.if[0] && !h.if.every((c) => c(d, p, r))) return false
18 | if (h.ifAny[0] && !h.ifAny.some((c) => c(d, p, r))) return false
19 | if (h.unless[0] && !h.unless.every((c) => !c(d, p, r))) return false
20 | if (h.unlessAny[0] && !h.unlessAny.some((c) => !c(d, p, r))) return false
21 | return true
22 | } catch (e) {
23 | throw Error(`Error while testing conditions! ` + (e as any).message)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/core/src/utils.ts:
--------------------------------------------------------------------------------
1 | export function last(array: T[]): T {
2 | const length = array == null ? 0 : array.length
3 | return array[length - 1] as T
4 | }
5 |
6 | export function castArray(a: any | any[]) {
7 | return Array.isArray(a) ? a : [a]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/core/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": [
4 | "node_modules",
5 | "**/*.test.tsx",
6 | "**/*.test.ts",
7 | "**/*.spec.tsx",
8 | "**/*.spec.ts",
9 | "src/test",
10 | "dist",
11 | "docs"
12 | ],
13 | "compilerOptions": {
14 | "composite": false,
15 | "incremental": false,
16 | "declarationMap": false,
17 | "sourceMap": false,
18 | "emitDeclarationOnly": true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/core/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "include": ["src"],
4 | "exclude": ["node_modules", "dist", "docs"],
5 | "compilerOptions": {
6 | "outDir": "./dist/types",
7 | "rootDir": "src",
8 | "baseUrl": "src"
9 | },
10 | "typedocOptions": {
11 | "entryPoints": ["src/index.ts"],
12 | "out": "docs"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/react/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 3.0.0
4 |
5 | - Rebuilds repo
6 |
--------------------------------------------------------------------------------
/packages/react/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Stephen Ruiz Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/react/card-repo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/react/card-repo.png
--------------------------------------------------------------------------------
/packages/react/docs/.nojekyll:
--------------------------------------------------------------------------------
1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false.
--------------------------------------------------------------------------------
/packages/react/docs/assets/highlight.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --light-code-background: #FFFFFF;
3 | --dark-code-background: #1E1E1E;
4 | }
5 |
6 | @media (prefers-color-scheme: light) { :root {
7 | --code-background: var(--light-code-background);
8 | } }
9 |
10 | @media (prefers-color-scheme: dark) { :root {
11 | --code-background: var(--dark-code-background);
12 | } }
13 |
14 | body.light {
15 | --code-background: var(--light-code-background);
16 | }
17 |
18 | body.dark {
19 | --code-background: var(--dark-code-background);
20 | }
21 |
22 | pre, code { background: var(--code-background); }
23 |
--------------------------------------------------------------------------------
/packages/react/docs/assets/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/react/docs/assets/icons.png
--------------------------------------------------------------------------------
/packages/react/docs/assets/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/react/docs/assets/icons@2x.png
--------------------------------------------------------------------------------
/packages/react/docs/assets/search.js:
--------------------------------------------------------------------------------
1 | window.searchData = {"kinds":{"32":"Variable","64":"Function"},"rows":[{"id":0,"kind":64,"name":"useStateDesigner","url":"modules.html#useStateDesigner","classes":"tsd-kind-function tsd-has-type-parameter"},{"id":1,"kind":64,"name":"createSelectorHook","url":"modules.html#createSelectorHook","classes":"tsd-kind-function tsd-has-type-parameter"},{"id":2,"kind":64,"name":"useSelector","url":"modules.html#useSelector","classes":"tsd-kind-function tsd-has-type-parameter"},{"id":3,"kind":32,"name":"StateGraph","url":"modules.html#StateGraph","classes":"tsd-kind-variable"},{"id":4,"kind":64,"name":"useLocalState","url":"modules.html#useLocalState","classes":"tsd-kind-function tsd-has-type-parameter"},{"id":5,"kind":64,"name":"useGlobalState","url":"modules.html#useGlobalState","classes":"tsd-kind-function tsd-has-type-parameter"}],"index":{"version":"2.3.9","fields":["name","parent"],"fieldVectors":[["name/0",[0,15.404]],["parent/0",[]],["name/1",[1,15.404]],["parent/1",[]],["name/2",[2,15.404]],["parent/2",[]],["name/3",[3,15.404]],["parent/3",[]],["name/4",[4,15.404]],["parent/4",[]],["name/5",[5,15.404]],["parent/5",[]]],"invertedIndex":[["createselectorhook",{"_index":1,"name":{"1":{}},"parent":{}}],["stategraph",{"_index":3,"name":{"3":{}},"parent":{}}],["useglobalstate",{"_index":5,"name":{"5":{}},"parent":{}}],["uselocalstate",{"_index":4,"name":{"4":{}},"parent":{}}],["useselector",{"_index":2,"name":{"2":{}},"parent":{}}],["usestatedesigner",{"_index":0,"name":{"0":{}},"parent":{}}]],"pipeline":[]}}
--------------------------------------------------------------------------------
/packages/react/docs/assets/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/react/docs/assets/widgets.png
--------------------------------------------------------------------------------
/packages/react/docs/assets/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/react/docs/assets/widgets@2x.png
--------------------------------------------------------------------------------
/packages/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.0",
3 | "name": "@state-designer/react",
4 | "description": "State management with state-charts.",
5 | "author": "@steveruizok",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/steveruizok/state-designer/core.git"
9 | },
10 | "license": "MIT",
11 | "keywords": [
12 | "react",
13 | "state",
14 | "statechart"
15 | ],
16 | "files": [
17 | "dist/**/*"
18 | ],
19 | "main": "./dist/cjs/index.js",
20 | "module": "./dist/esm/index.js",
21 | "types": "./dist/types/index.d.ts",
22 | "scripts": {
23 | "start": "node scripts/dev & yarn types:dev",
24 | "build": "node scripts/build && yarn types:build",
25 | "types:dev": "tsc -w --p tsconfig.build.json",
26 | "types:build": "tsc -p tsconfig.build.json",
27 | "lint": "eslint src/ --ext .ts,.tsx",
28 | "clean": "rm -rf dist",
29 | "test": "jest",
30 | "test:watch": "jest --watchAll",
31 | "docs": "typedoc",
32 | "docs:watch": "typedoc --watch"
33 | },
34 | "dependencies": {
35 | "@state-designer/core": "latest"
36 | },
37 | "peerDependencies": {
38 | "react": ">=16.8",
39 | "react-dom": "^16.8 || ^17.0"
40 | },
41 | "devDependencies": {
42 | "@types/jest": "^27.0.2",
43 | "@types/node": "^16.11.6",
44 | "@types/react": "^17.0.33",
45 | "@types/react-dom": "^17.0.10"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/packages/react/scripts/dev.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const esbuild = require('esbuild')
3 | const pkg = require('../package.json')
4 |
5 | async function main() {
6 | esbuild.build({
7 | entryPoints: ['./src/index.ts'],
8 | outdir: 'dist/esm',
9 | minify: false,
10 | bundle: true,
11 | format: 'esm',
12 | target: 'es6',
13 | tsconfig: './tsconfig.build.json',
14 | jsxFactory: 'React.createElement',
15 | jsxFragment: 'React.Fragment',
16 | external: Object.keys(pkg.dependencies).concat(Object.keys(pkg.peerDependencies)),
17 | incremental: true,
18 | sourcemap: true,
19 | watch: {
20 | onRebuild(error) {
21 | if (error) {
22 | console.log(`× ${pkg.name}: An error in prevented the rebuild.`)
23 | return
24 | }
25 | console.log(`✔ ${pkg.name}: Rebuilt.`)
26 | },
27 | },
28 | })
29 | }
30 |
31 | main()
32 |
--------------------------------------------------------------------------------
/packages/react/src/createSelectorHook.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 | import { useReducer, useEffect } from 'react'
3 | import type { S } from '@state-designer/core'
4 |
5 | type InnerState = { count: number; current: T }
6 |
7 | /**
8 | * createSelectorHook
9 | * @description A function that returns a useSelector hook for the
10 | * given state. The hook works just like `useSelector`, except that
11 | * you do not need to pass the hook a state as its first argument.
12 | * @param state A state created with `createState`.
13 | * @example const useSelector = createSelectorHook(roomState)
14 | *
15 | * // In a component
16 | * const tables = useSelector((state) => state.data.tables)
17 | */
18 |
19 | export default function createSelectorHook>(state: State) {
20 | return function useSelector(
21 | selectFn: (update: State) => T,
22 | compareFn: (prev: T, next: T) => boolean = (prev, next) => prev === next
23 | ) {
24 | const [inner, dispatch] = useReducer(
25 | (state: InnerState, update: State): InnerState => {
26 | const next = selectFn(update)
27 | return compareFn(state.current, next)
28 | ? state
29 | : {
30 | count: state.count + 1,
31 | current: next,
32 | }
33 | },
34 | state,
35 | (state) => ({
36 | count: 0,
37 | current: selectFn(state),
38 | })
39 | )
40 |
41 | useEffect(() => state.onUpdate((update) => dispatch(update)), [dispatch])
42 |
43 | return inner.current
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/packages/react/src/index.ts:
--------------------------------------------------------------------------------
1 | import useLocalState from './useLocalState'
2 | import useGlobalState from './useGlobalState'
3 | import useStateDesigner from './useStateDesigner'
4 | import useSelector from './useSelector'
5 | import createSelectorHook from './createSelectorHook'
6 | import { StateGraph } from './StateGraph'
7 | import { S, createDesign, createState } from '@state-designer/core'
8 |
9 | export {
10 | S,
11 | createDesign,
12 | createState,
13 | useStateDesigner,
14 | createSelectorHook,
15 | useSelector,
16 | StateGraph,
17 | useLocalState,
18 | useGlobalState,
19 | }
20 |
--------------------------------------------------------------------------------
/packages/react/src/useGlobalState.tsx:
--------------------------------------------------------------------------------
1 | // @refresh-reset
2 | import * as React from 'react'
3 | import type { S } from '@state-designer/core'
4 |
5 | /**
6 | * Subscribe a component to a state created with createState.
7 | * @param design A state returned from createState.
8 | */
9 |
10 | export default function useGlobalState>>(
11 | design: S.DesignedState
12 | ) {
13 | const [current, setCurrent] = React.useState(() => design)
14 |
15 | React.useEffect(() => {
16 | setCurrent(design)
17 |
18 | return design.onUpdate((update) =>
19 | setCurrent((current) => ({
20 | ...current,
21 | index: update.index,
22 | data: update.data,
23 | active: update.active,
24 | stateTree: update.stateTree,
25 | values: update.values,
26 | log: update.log,
27 | }))
28 | )
29 | }, [design])
30 |
31 | return current
32 | }
33 |
--------------------------------------------------------------------------------
/packages/react/src/useSelector.tsx:
--------------------------------------------------------------------------------
1 | import { useReducer, useEffect } from 'react'
2 | import type { S } from '@state-designer/core'
3 |
4 | type InnerState = { count: number; current: T }
5 |
6 | /**
7 | * useSelector
8 | * @param state A state created with `createState`.
9 | * @param selectFn A function that returns information derived from a state update.
10 | * @param compareFn - (Optional) A function to test whether the new selection matches the old section.
11 | * @example const tables = useSelector(state, (update) => update.data.tables)
12 | */
13 | export default function useSelector(
14 | state: State,
15 | selectFn: (update: State) => T,
16 | compareFn: (prev: T, next: T) => boolean = (prev, next) => prev === next
17 | ): T {
18 | const [inner, dispatch] = useReducer(
19 | (state: InnerState, update: State): InnerState => {
20 | const next = selectFn(update)
21 | return compareFn(state.current, next)
22 | ? state
23 | : {
24 | count: state.count + 1,
25 | current: next,
26 | }
27 | },
28 | state,
29 | (state) => ({
30 | count: 0,
31 | current: selectFn(state),
32 | })
33 | )
34 |
35 | useEffect(() => state.onUpdate((update: State) => dispatch(update)), [state, dispatch])
36 |
37 | return inner.current
38 | }
39 |
--------------------------------------------------------------------------------
/packages/react/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": [
4 | "node_modules",
5 | "**/*.test.tsx",
6 | "**/*.test.ts",
7 | "**/*.spec.tsx",
8 | "**/*.spec.ts",
9 | "src/test",
10 | "dist",
11 | "docs"
12 | ],
13 | "compilerOptions": {
14 | "composite": false,
15 | "incremental": false,
16 | "declarationMap": false,
17 | "sourceMap": false,
18 | "emitDeclarationOnly": true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "include": ["src"],
4 | "exclude": ["node_modules", "dist", "docs"],
5 | "compilerOptions": {
6 | "outDir": "./dist/types",
7 | "rootDir": "src",
8 | "baseUrl": "src",
9 | "paths": {
10 | "~*": ["./*"]
11 | }
12 | },
13 | "typedocOptions": {
14 | "entryPoints": ["src/index.ts"],
15 | "out": "docs"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/state-designer/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 3.0.0
4 |
5 | - Rebuilds repo.
6 |
--------------------------------------------------------------------------------
/packages/state-designer/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Stephen Ruiz Ltd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/state-designer/README.md:
--------------------------------------------------------------------------------
1 | # State Designer
2 |
3 | Includes both [`@state-designer/core`](https://github.com/steveruizok/state-designer/tree/master/packages/core) and [`@state-designer/react`](https://github.com/steveruizok/state-designer/tree/master/packages/react).
4 |
5 | ```
6 | npm install state-designer
7 | ```
8 |
9 | or
10 |
11 | ```
12 | yarn add state-designer
13 | ```
14 |
--------------------------------------------------------------------------------
/packages/state-designer/docs/.nojekyll:
--------------------------------------------------------------------------------
1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false.
--------------------------------------------------------------------------------
/packages/state-designer/docs/assets/highlight.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --light-code-background: #FFFFFF;
3 | --dark-code-background: #1E1E1E;
4 | }
5 |
6 | @media (prefers-color-scheme: light) { :root {
7 | --code-background: var(--light-code-background);
8 | } }
9 |
10 | @media (prefers-color-scheme: dark) { :root {
11 | --code-background: var(--dark-code-background);
12 | } }
13 |
14 | body.light {
15 | --code-background: var(--light-code-background);
16 | }
17 |
18 | body.dark {
19 | --code-background: var(--dark-code-background);
20 | }
21 |
22 | pre, code { background: var(--code-background); }
23 |
--------------------------------------------------------------------------------
/packages/state-designer/docs/assets/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/state-designer/docs/assets/icons.png
--------------------------------------------------------------------------------
/packages/state-designer/docs/assets/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/state-designer/docs/assets/icons@2x.png
--------------------------------------------------------------------------------
/packages/state-designer/docs/assets/search.js:
--------------------------------------------------------------------------------
1 | window.searchData = {"kinds":{},"rows":[],"index":{"version":"2.3.9","fields":["name","parent"],"fieldVectors":[],"invertedIndex":[],"pipeline":[]}}
--------------------------------------------------------------------------------
/packages/state-designer/docs/assets/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/state-designer/docs/assets/widgets.png
--------------------------------------------------------------------------------
/packages/state-designer/docs/assets/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/state-designer/7c02166c43eba5f3b11d23fcfbae47f3cddfd901/packages/state-designer/docs/assets/widgets@2x.png
--------------------------------------------------------------------------------
/packages/state-designer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.0",
3 | "name": "state-designer",
4 | "description": "State management with state-charts.",
5 | "author": "@steveruizok",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/steveruizok/state-designer/core.git"
9 | },
10 | "license": "MIT",
11 | "keywords": [
12 | "react",
13 | "state",
14 | "statechart"
15 | ],
16 | "files": [
17 | "dist/**/*"
18 | ],
19 | "main": "./dist/cjs/index.js",
20 | "module": "./dist/esm/index.js",
21 | "types": "./dist/types/index.d.ts",
22 | "scripts": {
23 | "start": "node scripts/dev & yarn types:dev",
24 | "build": "node scripts/build && yarn types:build",
25 | "types:dev": "tsc -w --p tsconfig.build.json",
26 | "types:build": "tsc -p tsconfig.build.json",
27 | "lint": "eslint src/ --ext .ts,.tsx",
28 | "clean": "rm -rf dist",
29 | "test": "jest",
30 | "test:watch": "jest --watchAll",
31 | "docs": "typedoc",
32 | "docs:watch": "typedoc --watch"
33 | },
34 | "dependencies": {
35 | "@state-designer/react": "latest"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/state-designer/scripts/dev.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | const esbuild = require('esbuild')
3 | const pkg = require('../package.json')
4 |
5 | async function main() {
6 | esbuild.build({
7 | entryPoints: ['./src/index.ts'],
8 | outdir: 'dist/esm',
9 | minify: false,
10 | bundle: true,
11 | incremental: true,
12 | sourcemap: true,
13 | format: 'esm',
14 | target: 'es6',
15 | tsconfig: './tsconfig.build.json',
16 | jsxFactory: 'React.createElement',
17 | jsxFragment: 'React.Fragment',
18 | external: Object.keys(pkg.dependencies),
19 | watch: {
20 | onRebuild(error) {
21 | if (error) {
22 | console.log(`× ${pkg.name}: An error in prevented the rebuild.`)
23 | return
24 | }
25 | console.log(`✔ ${pkg.name}: Rebuilt.`)
26 | },
27 | },
28 | })
29 | }
30 |
31 | main()
32 |
--------------------------------------------------------------------------------
/packages/state-designer/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from '@state-designer/react'
2 |
--------------------------------------------------------------------------------
/packages/state-designer/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": [
4 | "node_modules",
5 | "**/*.test.tsx",
6 | "**/*.test.ts",
7 | "**/*.spec.tsx",
8 | "**/*.spec.ts",
9 | "src/test",
10 | "dist",
11 | "docs"
12 | ],
13 | "compilerOptions": {
14 | "composite": false,
15 | "incremental": false,
16 | "declarationMap": false,
17 | "sourceMap": false,
18 | "emitDeclarationOnly": true
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/state-designer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "include": ["src"],
4 | "exclude": ["node_modules", "dist", "docs"],
5 | "compilerOptions": {
6 | "outDir": "./dist/types",
7 | "rootDir": "src",
8 | "baseUrl": "src",
9 | "paths": {
10 | "~*": ["./*"]
11 | }
12 | },
13 | "typedocOptions": {
14 | "entryPoints": ["src/index.ts"],
15 | "out": "docs"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/setupTests.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom/extend-expect'
2 | global.ResizeObserver = require('resize-observer-polyfill')
3 |
--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "declarationMap": true,
5 | "composite": true,
6 | "sourceMap": true,
7 | "emitDeclarationOnly": true,
8 | "allowSyntheticDefaultImports": true,
9 | "esModuleInterop": true,
10 | "experimentalDecorators": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "importHelpers": true,
13 | "importsNotUsedAsValues": "error",
14 | "incremental": true,
15 | "jsx": "preserve",
16 | "lib": ["dom", "esnext"],
17 | "module": "esnext",
18 | "moduleResolution": "node",
19 | "noFallthroughCasesInSwitch": true,
20 | "noImplicitAny": true,
21 | "noImplicitReturns": true,
22 | "noUnusedLocals": false,
23 | "noUnusedParameters": false,
24 | "skipLibCheck": true,
25 | "strict": true,
26 | "strictFunctionTypes": true,
27 | "strictNullChecks": true,
28 | "stripInternal": true,
29 | "target": "es6",
30 | "types": ["node", "jest", "@testing-library/jest-dom", "@testing-library/react"]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "composite": true,
3 | "extends": "./tsconfig.base.json",
4 | "exclude": ["node_modules", "**/*.test.ts", "**/*.spec.ts"],
5 | "files": [],
6 | "references": [
7 | { "path": "./packages/core" },
8 | { "path": "./packages/react" },
9 | { "path": "./packages/state-designer" }
10 | ],
11 | "compilerOptions": {
12 | "baseUrl": ".",
13 | "paths": {
14 | "@state-designer/core": ["./packages/core"],
15 | "@state-designer/react": ["./packages/react"],
16 | "state-designer": ["./packages/state-designer"]
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------