├── .changeset ├── README.md └── config.json ├── .github ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── code_quality.yml │ └── release.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── apps ├── desktop │ ├── .eslintrc │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── src-tauri │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── icons │ │ │ ├── 128x128.png │ │ │ ├── 128x128@2x.png │ │ │ ├── 32x32.png │ │ │ ├── Square107x107Logo.png │ │ │ ├── Square142x142Logo.png │ │ │ ├── Square150x150Logo.png │ │ │ ├── Square284x284Logo.png │ │ │ ├── Square30x30Logo.png │ │ │ ├── Square310x310Logo.png │ │ │ ├── Square44x44Logo.png │ │ │ ├── Square71x71Logo.png │ │ │ ├── Square89x89Logo.png │ │ │ ├── StoreLogo.png │ │ │ ├── icon.icns │ │ │ ├── icon.ico │ │ │ └── icon.png │ │ ├── src │ │ │ └── main.rs │ │ └── tauri.conf.json │ ├── src │ │ ├── components │ │ │ └── app │ │ │ │ ├── app.css.ts │ │ │ │ └── app.tsx │ │ ├── index.tsx │ │ └── types.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite-env.d.ts │ └── vite.config.ts ├── graphql-yoga-server │ ├── constants.ts │ ├── index.ts │ └── package.json ├── ladle │ ├── .env.development.local.example │ ├── .eslintrc.json │ ├── .ladle │ │ ├── components.tsx │ │ ├── config.mjs │ │ └── styles.css │ ├── package.json │ ├── tsconfig.json │ └── vite.config.ts └── website │ ├── .gitignore │ ├── README.md │ ├── astro.config.mjs │ ├── package.json │ ├── public │ ├── favicon.svg │ └── og.jpg │ ├── src │ ├── components │ │ ├── Card.astro │ │ └── DownloadButton.tsx │ ├── env.d.ts │ ├── images │ │ ├── bg.png │ │ ├── oss.png │ │ ├── powerful-foundation.png │ │ ├── preview.png │ │ ├── schema-browser.png │ │ └── visual-operation-builder.png │ ├── layouts │ │ └── Layout.astro │ └── pages │ │ └── index.astro │ ├── tailwind.config.js │ └── tsconfig.json ├── examples ├── nextjs-example │ ├── .eslintrc.json │ ├── CHANGELOG.md │ ├── README.md │ ├── next-env.d.ts │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── next.svg │ │ └── vercel.svg │ ├── src │ │ └── app │ │ │ ├── favicon.ico │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── tailwind.config.js │ └── tsconfig.json └── vite-example │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.css │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── flake.lock ├── flake.nix ├── package.json ├── packages ├── eslint-config │ ├── eslint-config.js │ └── package.json ├── react │ ├── .eslintrc │ ├── .gitignore │ ├── CHANGELOG.md │ ├── __mocks__ │ │ ├── monaco-editor │ │ │ ├── canvas.ts │ │ │ ├── get-selection.ts │ │ │ ├── match-media.ts │ │ │ ├── query-command-supported.ts │ │ │ ├── resize-observer.ts │ │ │ └── worker.ts │ │ └── zustand.ts │ ├── package.json │ ├── src │ │ ├── compass │ │ │ ├── compass-store │ │ │ │ ├── actions │ │ │ │ │ ├── add-target-argument.ts │ │ │ │ │ ├── add-target-field.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── remove-target-argument.ts │ │ │ │ │ ├── remove-target-field.ts │ │ │ │ │ └── toggle.ts │ │ │ │ ├── compass-store.tsx │ │ │ │ ├── compass-store.types.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ ├── state.ts │ │ │ │ └── utils │ │ │ │ │ ├── find-next-token-kind-in-location.ts │ │ │ │ │ ├── find-selection.ts │ │ │ │ │ ├── generate-argument-text.ts │ │ │ │ │ ├── generate-selection-breadcrumbs-from-ancestors.ts │ │ │ │ │ ├── generate-text.ts │ │ │ │ │ ├── generate-variable-text.ts │ │ │ │ │ ├── get-active-definition-range.ts │ │ │ │ │ ├── get-add-edit.ts │ │ │ │ │ ├── get-add-range-for-field-from-location.ts │ │ │ │ │ ├── get-ancestor-text.ts │ │ │ │ │ ├── get-enum-values.ts │ │ │ │ │ ├── get-location-from-ancestor.ts │ │ │ │ │ ├── get-position-at-end-of-location.ts │ │ │ │ │ ├── get-previous-ancestor.ts │ │ │ │ │ ├── get-range-from-string-in-active-definition.ts │ │ │ │ │ ├── get-remove-range-for-field-from-location.ts │ │ │ │ │ ├── get-remove-range.ts │ │ │ │ │ ├── get-root-ancestor.ts │ │ │ │ │ ├── get-selected-arguments-count.ts │ │ │ │ │ ├── get-variable-definitions-count.ts │ │ │ │ │ ├── has-sibling-selections.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── insert-new-operation.ts │ │ │ │ │ └── unwrap-non-null-argument-type.ts │ │ │ ├── compass.css.ts │ │ │ ├── compass.tsx │ │ │ ├── components │ │ │ │ ├── argument │ │ │ │ │ ├── argument.css.ts │ │ │ │ │ ├── argument.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── arguments │ │ │ │ │ ├── arguments.css.ts │ │ │ │ │ ├── arguments.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── collapse-control │ │ │ │ │ ├── collapse-control.css.ts │ │ │ │ │ ├── collapse-control.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── details-actions │ │ │ │ │ ├── details-actions.css.ts │ │ │ │ │ ├── details-actions.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── details │ │ │ │ │ ├── details.css.ts │ │ │ │ │ ├── details.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── field │ │ │ │ │ ├── field.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── fields │ │ │ │ │ ├── fields.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── indicator-leaf │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── indicator-leaf.css.ts │ │ │ │ │ └── indicator-leaf.tsx │ │ │ │ ├── list-item │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── list-item.css.ts │ │ │ │ │ ├── list-item.tsx │ │ │ │ │ └── list-item.types.ts │ │ │ │ ├── quick-docs │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── quick-docs.css.ts │ │ │ │ │ └── quick-docs.tsx │ │ │ │ ├── root-operation │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── root-operation.css.ts │ │ │ │ │ └── root-operation.tsx │ │ │ │ └── union │ │ │ │ │ ├── index.ts │ │ │ │ │ └── union.tsx │ │ │ └── index.ts │ │ ├── components │ │ │ ├── action-execute-subscription │ │ │ │ ├── action-execute-subscription.css.ts │ │ │ │ ├── action-execute-subscription.tsx │ │ │ │ └── index.ts │ │ │ ├── action-execute │ │ │ │ ├── action-execute.tsx │ │ │ │ └── index.ts │ │ │ ├── action-prettier │ │ │ │ ├── action-prettier.tsx │ │ │ │ └── index.ts │ │ │ ├── actions-bar │ │ │ │ ├── actions-bar.css.ts │ │ │ │ ├── actions-bar.tsx │ │ │ │ ├── components--actions-bar.stories.tsx │ │ │ │ └── index.ts │ │ │ ├── analyze │ │ │ │ ├── analyze.css.ts │ │ │ │ ├── analyze.tsx │ │ │ │ └── index.ts │ │ │ ├── beacon-animated │ │ │ │ ├── beacon-animated.css.ts │ │ │ │ ├── beacon-animated.tsx │ │ │ │ └── index.ts │ │ │ ├── button │ │ │ │ ├── button.css.ts │ │ │ │ ├── button.tsx │ │ │ │ └── index.ts │ │ │ ├── compass-animated │ │ │ │ ├── compass-animated.css.ts │ │ │ │ ├── compass-animated.tsx │ │ │ │ ├── components--compass-animated.stories.tsx │ │ │ │ └── index.ts │ │ │ ├── connect │ │ │ │ ├── connect.css.ts │ │ │ │ ├── connect.tsx │ │ │ │ └── index.ts │ │ │ ├── connection-bar │ │ │ │ ├── connection-bar.css.ts │ │ │ │ ├── connection-bar.tsx │ │ │ │ └── index.ts │ │ │ ├── control │ │ │ │ ├── components--control.stories.tsx │ │ │ │ ├── control.css.ts │ │ │ │ ├── control.tsx │ │ │ │ ├── control.types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── input.tsx │ │ │ │ └── select.tsx │ │ │ ├── document-notification │ │ │ │ ├── document-notification.css.ts │ │ │ │ ├── document-notification.tsx │ │ │ │ └── index.ts │ │ │ ├── dropdown │ │ │ │ ├── dropdown.css.ts │ │ │ │ ├── dropdown.tsx │ │ │ │ └── index.ts │ │ │ ├── editor-tabs │ │ │ │ ├── editor-tabs.css.ts │ │ │ │ ├── editor-tabs.tsx │ │ │ │ └── index.ts │ │ │ ├── editor │ │ │ │ ├── components--editor.stories.tsx │ │ │ │ ├── editor.css.ts │ │ │ │ ├── editor.tsx │ │ │ │ ├── editor.types.ts │ │ │ │ ├── index.ts │ │ │ │ └── workers.ts │ │ │ ├── history │ │ │ │ ├── history-item-request │ │ │ │ │ ├── history-item-request.css.ts │ │ │ │ │ ├── history-item-request.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── history-item-response │ │ │ │ │ ├── history-item-response.css.ts │ │ │ │ │ ├── history-item-response.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── history-list-item │ │ │ │ │ ├── history-list-item.css.ts │ │ │ │ │ ├── history-list-item.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── history.css.ts │ │ │ │ ├── history.tsx │ │ │ │ └── index.ts │ │ │ ├── http-header-control │ │ │ │ ├── components--http-header-control.stories.tsx │ │ │ │ ├── http-header-control.css.ts │ │ │ │ ├── http-header-control.tsx │ │ │ │ └── index.ts │ │ │ ├── icon-button │ │ │ │ ├── components--iconbutton.stories.tsx │ │ │ │ ├── icon-button.css.ts │ │ │ │ ├── icon-button.tsx │ │ │ │ └── index.ts │ │ │ ├── icon │ │ │ │ ├── arrow-right │ │ │ │ │ ├── arrow-right.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── caret │ │ │ │ │ ├── caret.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── chevron │ │ │ │ │ ├── chevron.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── close │ │ │ │ │ ├── close.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── compass │ │ │ │ │ ├── compass.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── components--icon.stories.tsx │ │ │ │ ├── delete │ │ │ │ │ ├── delete.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── docs │ │ │ │ │ ├── docs.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ellipsis │ │ │ │ │ ├── ellipsis.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── gear │ │ │ │ │ ├── gear.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── graphql │ │ │ │ │ ├── graphql.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── icon.css.ts │ │ │ │ ├── icon.tsx │ │ │ │ ├── icon.types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── insert-new-operation │ │ │ │ │ ├── index.ts │ │ │ │ │ └── insert-new-operation.tsx │ │ │ │ ├── interpunct │ │ │ │ │ ├── index.ts │ │ │ │ │ └── interpunct.tsx │ │ │ │ ├── magnifing-glass │ │ │ │ │ ├── index.ts │ │ │ │ │ └── magnifing-glass.tsx │ │ │ │ ├── pause │ │ │ │ │ ├── index.ts │ │ │ │ │ └── pause.tsx │ │ │ │ ├── plus │ │ │ │ │ ├── index.ts │ │ │ │ │ └── plus.tsx │ │ │ │ └── prettier │ │ │ │ │ ├── index.ts │ │ │ │ │ └── prettier.tsx │ │ │ ├── index.ts │ │ │ ├── kbd │ │ │ │ ├── components--kdb.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── kbd.css.ts │ │ │ │ └── kbd.tsx │ │ │ ├── loading-schema │ │ │ │ ├── index.ts │ │ │ │ ├── loading-schema.css.ts │ │ │ │ └── loading-schema.tsx │ │ │ ├── operate │ │ │ │ ├── components--operate.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── operate.css.ts │ │ │ │ └── operate.tsx │ │ │ ├── pill │ │ │ │ ├── components--pill.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── pill.css.ts │ │ │ │ └── pill.tsx │ │ │ ├── pre │ │ │ │ ├── index.ts │ │ │ │ ├── pre.css.ts │ │ │ │ └── pre.tsx │ │ │ ├── resizer │ │ │ │ ├── components--resizer.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── resizer-store │ │ │ │ │ ├── actions │ │ │ │ │ │ ├── get-initial-grid-template.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── reset-pane.ts │ │ │ │ │ │ └── set-resizer-state.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── resizer-store.ts │ │ │ │ │ ├── resizer-store.types.ts │ │ │ │ │ └── use-resizer-store.ts │ │ │ │ ├── resizer.css.ts │ │ │ │ ├── resizer.tsx │ │ │ │ └── resizer.types.ts │ │ │ ├── scout-tools │ │ │ │ ├── components--scout-tools.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── scout-tools.css.ts │ │ │ │ └── scout-tools.tsx │ │ │ ├── sessions │ │ │ │ ├── index.ts │ │ │ │ ├── sessions.css.ts │ │ │ │ └── sessions.tsx │ │ │ ├── spinner │ │ │ │ ├── index.ts │ │ │ │ ├── spinner.css.ts │ │ │ │ └── spinner.tsx │ │ │ ├── switch │ │ │ │ ├── components--switch.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── switch.css.ts │ │ │ │ └── switch.tsx │ │ │ ├── tabs │ │ │ │ ├── components--tabs.stories.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── tabs.css.ts │ │ │ │ ├── tabs.tsx │ │ │ │ └── tabs.types.ts │ │ │ ├── theme-switcher │ │ │ │ ├── index.ts │ │ │ │ └── theme-switcher.tsx │ │ │ └── variables │ │ │ │ ├── index.ts │ │ │ │ ├── variables.css.ts │ │ │ │ └── variables.tsx │ │ ├── ide │ │ │ ├── ide.tsx │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── pathfinder │ │ │ ├── index.ts │ │ │ ├── pathfinder.css.ts │ │ │ ├── pathfinder.stories.tsx │ │ │ ├── pathfinder.test.tsx │ │ │ ├── pathfinder.tsx │ │ │ └── pathfinder.types.ts │ │ ├── reference │ │ │ ├── index.ts │ │ │ ├── reference.css.ts │ │ │ └── reference.tsx │ │ ├── schema-documentation │ │ │ ├── components │ │ │ │ ├── arguments-list │ │ │ │ │ ├── arguments-list.css.ts │ │ │ │ │ ├── arguments-list.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── default-value │ │ │ │ │ ├── default-value.css.ts │ │ │ │ │ ├── default-value.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── delimiter │ │ │ │ │ ├── delimiter.css.ts │ │ │ │ │ ├── delimiter.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── leaf │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── leaf.css.ts │ │ │ │ ├── markdown │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── markdown.css.ts │ │ │ │ │ └── markdown.tsx │ │ │ │ ├── schema-documentation │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema-documentation.css.ts │ │ │ │ │ └── schema-documentation.tsx │ │ │ │ ├── secondary-pane │ │ │ │ │ ├── secondary-pane.css.ts │ │ │ │ │ └── secondary-pane.tsx │ │ │ │ ├── section │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── section.css.ts │ │ │ │ ├── summary │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── summary.css.ts │ │ │ │ │ └── summary.tsx │ │ │ │ ├── tertiary-pane │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── tertiary-pane.css.ts │ │ │ │ │ └── tertiary-pane.tsx │ │ │ │ ├── type-system-nav-button │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── type-system-nav-button.css.ts │ │ │ │ │ └── type-system-nav-button.tsx │ │ │ │ └── types-nav.tsx │ │ │ ├── index.ts │ │ │ ├── schema-documentation.stories.tsx │ │ │ ├── shared.styles.css.ts │ │ │ ├── store │ │ │ │ ├── actions.ts │ │ │ │ ├── index.ts │ │ │ │ ├── schema-documentation-store.tsx │ │ │ │ ├── schema-documentation-store.types.ts │ │ │ │ └── state.ts │ │ │ ├── types │ │ │ │ └── index.ts │ │ │ └── utils │ │ │ │ ├── index.ts │ │ │ │ └── sort-types.ts │ │ ├── schema-view │ │ │ ├── index.tsx │ │ │ ├── schema-view.css.ts │ │ │ ├── schema-view.stories.tsx │ │ │ └── schema-view.tsx │ │ ├── scout │ │ │ ├── index.ts │ │ │ ├── scout.css.ts │ │ │ └── scout.tsx │ │ └── types.ts │ ├── tsconfig.json │ ├── vite-env.d.ts │ ├── vite.config.ts │ ├── vite.lite.config.ts │ ├── vitest.setup.ts │ └── workers │ │ └── build-workers.js ├── shared │ ├── .eslintrc │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── graphql │ │ │ ├── index.ts │ │ │ └── unwrap-type.ts │ │ │ ├── index.ts │ │ │ ├── misc │ │ │ └── generate-cuid.ts │ │ │ └── zustand │ │ │ ├── create-zustand-selectors.ts │ │ │ └── index.ts │ └── tsconfig.json ├── stores │ ├── .eslintrc │ ├── package.json │ ├── src │ │ ├── cleanup-stores.ts │ │ ├── graphql-document-store │ │ │ ├── actions │ │ │ │ ├── get-parsed-document.ts │ │ │ │ ├── handle-active-definition.ts │ │ │ │ ├── handle-inactive-definition.ts │ │ │ │ ├── index.ts │ │ │ │ ├── is-operation-name-changing.ts │ │ │ │ ├── reset-document-state.ts │ │ │ │ ├── set-active-document-entry.ts │ │ │ │ ├── set-document-notifications.ts │ │ │ │ ├── set-document-state.ts │ │ │ │ └── update-document-entry-operation-name.ts │ │ │ ├── graphql-document-store.ts │ │ │ ├── graphql-document-store.types.ts │ │ │ ├── index.ts │ │ │ ├── state.ts │ │ │ ├── use-graphql-document-store.ts │ │ │ └── utils.ts │ │ ├── index.ts │ │ ├── monaco-editor-store │ │ │ ├── actions │ │ │ │ ├── create-monaco-editor.ts │ │ │ │ ├── dispose-monaco-editor.ts │ │ │ │ ├── get-monaco-editor.ts │ │ │ │ ├── index.ts │ │ │ │ ├── initialize-monaco-editor.ts │ │ │ │ ├── monaco-import.ts │ │ │ │ ├── push-monaco-editor-edit.ts │ │ │ │ ├── run-execute-operation.ts │ │ │ │ └── set-monaco-editor-theme.ts │ │ │ ├── helpers │ │ │ │ ├── editor-options.ts │ │ │ │ └── editor-theme.ts │ │ │ ├── index.ts │ │ │ ├── monaco-editor-store.ts │ │ │ ├── monaco-editor-store.types.ts │ │ │ ├── state.ts │ │ │ └── use-monaco-editor-store.ts │ │ ├── monaco-graphql-store │ │ │ ├── actions │ │ │ │ ├── index.ts │ │ │ │ ├── init-monaco-graphql-api.ts │ │ │ │ └── set-monaco-graphql-schema.ts │ │ │ ├── index.ts │ │ │ ├── monaco-graphql-store.ts │ │ │ └── monaco-graphql-store.types.ts │ │ ├── schema-store │ │ │ ├── actions │ │ │ │ ├── do-introspection.ts │ │ │ │ ├── do-schema-polling.ts │ │ │ │ ├── execute-operation.ts │ │ │ │ ├── http-fetcher.ts │ │ │ │ ├── index.ts │ │ │ │ ├── load-schema.ts │ │ │ │ ├── reset-schema-polling.ts │ │ │ │ └── set-schema-polling-timer.ts │ │ │ ├── helpers │ │ │ │ ├── merge-results.ts │ │ │ │ └── using-defer.ts │ │ │ ├── index.ts │ │ │ ├── schema-store.ts │ │ │ ├── schema-store.types.ts │ │ │ ├── state.ts │ │ │ ├── test-schema │ │ │ │ ├── index.ts │ │ │ │ └── scalar-stubs.ts │ │ │ └── use-schema-store.ts │ │ ├── session-store │ │ │ ├── actions │ │ │ │ ├── get-sessions.ts │ │ │ │ ├── index.ts │ │ │ │ ├── init-session.ts │ │ │ │ └── load-session.ts │ │ │ ├── index.ts │ │ │ ├── session-store-state.ts │ │ │ ├── session-store.ts │ │ │ ├── session-store.types.ts │ │ │ ├── slices │ │ │ │ ├── editor-tabs │ │ │ │ │ ├── actions │ │ │ │ │ │ ├── close-editor-tab.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── init-new-editor-tab.ts │ │ │ │ │ │ ├── set-editor-values.ts │ │ │ │ │ │ ├── switch-editor-tab.ts │ │ │ │ │ │ └── update-editor-tab.ts │ │ │ │ │ ├── editor-tabs-state.ts │ │ │ │ │ ├── editor-tabs.types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── history │ │ │ │ │ ├── actions │ │ │ │ │ │ ├── clear-history.ts │ │ │ │ │ │ ├── delete-from-history.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── history-state.ts │ │ │ │ │ ├── history.types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── http-headers │ │ │ │ │ ├── actions │ │ │ │ │ │ ├── add-empty-header.ts │ │ │ │ │ │ ├── get-enabled-http-header-values.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── remove-header.ts │ │ │ │ │ │ └── update-header.ts │ │ │ │ │ ├── http-headers-state.ts │ │ │ │ │ ├── http-headers.types.ts │ │ │ │ │ └── index.ts │ │ │ │ └── variables │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── variables-state.ts │ │ │ │ │ └── variables.types.ts │ │ │ └── use-session-store.ts │ │ ├── storage.ts │ │ ├── theme-store │ │ │ ├── actions │ │ │ │ ├── index.ts │ │ │ │ ├── initialize-theme.ts │ │ │ │ ├── listen-for-prefers-color-scheme-change.ts │ │ │ │ ├── set-theme-overrides.ts │ │ │ │ └── set-theme.ts │ │ │ ├── index.ts │ │ │ ├── theme-store.ts │ │ │ ├── theme-store.types.ts │ │ │ ├── use-theme-store.ts │ │ │ └── utils │ │ │ │ ├── getUserPreferredTheme.ts │ │ │ │ ├── index.ts │ │ │ │ └── munge-theme-overrides.ts │ │ └── ui-store │ │ │ ├── index.ts │ │ │ ├── ui-store.ts │ │ │ └── ui-store.types.ts │ └── tsconfig.json ├── style │ ├── .eslintrc │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── shared │ │ │ ├── hairline-border.css.ts │ │ │ ├── index.ts │ │ │ ├── resets.css.ts │ │ │ ├── scrollbars.css.ts │ │ │ └── transitions.ts │ │ ├── theme │ │ │ ├── color.ts │ │ │ ├── contract.css.ts │ │ │ ├── dark.css.ts │ │ │ ├── fonts.ts │ │ │ ├── global.css.ts │ │ │ ├── index.ts │ │ │ ├── light.css.ts │ │ │ └── space.ts │ │ ├── types.ts │ │ └── utils │ │ │ ├── index.ts │ │ │ └── to-title-case.ts │ └── tsconfig.json └── tsconfig │ ├── base.json │ ├── package.json │ └── react.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json └── turbo.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [ 11 | "@pathfinder-ide/website", 12 | "nextjs-example", 13 | "vite-example", 14 | "desktop", 15 | "ladle" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. 4 | Please also include relevant motivation and context. 5 | 6 | # Type of change 7 | 8 | - [ ] 💔 Breaking 9 | - [ ] 🚀 Feature 10 | - [ ] 🐛 Fix 11 | - [ ] 🛠️ Tooling 12 | - [ ] 🔨 Refactoring 13 | - [ ] 🧪 Test 14 | - [ ] 📦 Dependency 15 | - [ ] 📖 Requires documentation update 16 | -------------------------------------------------------------------------------- /.github/workflows/code_quality.yml: -------------------------------------------------------------------------------- 1 | name: Code quality 2 | 3 | on: push 4 | 5 | jobs: 6 | code_quality: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout Repo 11 | uses: actions/checkout@v4 12 | 13 | - name: Install pnpm 14 | uses: pnpm/action-setup@v3 15 | with: 16 | version: 9 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version: 20 20 | cache: 'pnpm' 21 | - run: pnpm install 22 | 23 | - name: Types check 24 | run: pnpm types 25 | 26 | - name: Lint check 27 | run: pnpm lint 28 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: ${{ github.workflow }}-${{ github.ref }} 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-22.04 14 | steps: 15 | - name: Checkout Repo 16 | uses: actions/checkout@v4 17 | 18 | - name: Install pnpm 19 | uses: pnpm/action-setup@v3 20 | with: 21 | version: 9 22 | - uses: actions/setup-node@v4 23 | with: 24 | node-version: 20 25 | cache: 'pnpm' 26 | - run: pnpm install 27 | 28 | - name: Create Release Pull Request or Publish to npm 29 | id: changesets 30 | uses: changesets/action@v1 31 | with: 32 | # This expects you to have a script called release which does a build for your packages and calls changeset publish 33 | publish: pnpm release 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | NPM_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | .pnp 4 | .pnp.js 5 | 6 | # next.js 7 | .next/ 8 | out/ 9 | 10 | # production 11 | build 12 | dist 13 | 14 | # misc 15 | .DS_Store 16 | *.pem 17 | 18 | # debug 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # local env files 24 | .env 25 | .env.local 26 | .env.development.local 27 | .env.test.local 28 | .env.production.local 29 | 30 | # typescript 31 | *.tsbuildinfo 32 | 33 | # ide 34 | .idea 35 | .vscode 36 | 37 | # Turbo 38 | .turbo 39 | .direnv 40 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # all examples 2 | /examples/* 3 | 4 | # built workers 5 | /packages/react/workers/*.bundle.js 6 | 7 | **/node_modules 8 | 9 | pnpm-lock.yaml 10 | 11 | # artifacts: 12 | build 13 | dist 14 | public 15 | coverage 16 | /apps/desktop/src-tauri/target/* -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 90, 3 | "semi": true, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /apps/desktop/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@pathfinder-ide/eslint-config"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/desktop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "desktop", 3 | "private": true, 4 | "version": "0.1.5", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview", 10 | "tauri": "tauri", 11 | "types": "tsc --noEmit" 12 | }, 13 | "dependencies": { 14 | "react": "18.3.1", 15 | "react-dom": "18.3.1", 16 | "@tauri-apps/api": "^1.4.0" 17 | }, 18 | "devDependencies": { 19 | "@pathfinder-ide/react": "workspace:*", 20 | "@pathfinder-ide/eslint-config": "workspace:*", 21 | "@pathfinder-ide/style": "workspace:*", 22 | "@tauri-apps/cli": "^1.4.0", 23 | "@types/react": "18.3.12", 24 | "@types/react-dom": "18.3.1", 25 | "@vanilla-extract/css": "1.14.2", 26 | "@vanilla-extract/vite-plugin": "3.9.5", 27 | "@vitejs/plugin-react": "4.3.3", 28 | "typescript": "5.5.4", 29 | "vite": "5.4.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "desktop" 3 | version = "0.1.5" 4 | description = "The Pathfinder desktop application" 5 | authors = ["Grafbase"] 6 | license = "MPL-2.0" 7 | repository = "https://github.com/grafbase/pathfinder" 8 | edition = "2021" 9 | 10 | [build-dependencies] 11 | tauri-build = { version = "1.5", features = [] } 12 | 13 | [dependencies] 14 | tauri = { version = "1.5", features = [ "window-close", "window-start-dragging", "window-maximize", "window-hide", "window-minimize", "window-show", "window-unminimize", "window-unmaximize", "shell-open"] } 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_json = "1.0" 17 | 18 | [features] 19 | # this feature is used for production builds or when `devPath` points to the filesystem 20 | # DO NOT REMOVE!! 21 | custom-protocol = ["tauri/custom-protocol"] 22 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tauri_build::build() 3 | } 4 | -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/128x128.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/128x128@2x.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/32x32.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square107x107Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square107x107Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square142x142Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square142x142Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square150x150Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square284x284Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square284x284Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square30x30Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square30x30Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square310x310Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square310x310Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square44x44Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square71x71Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square71x71Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/Square89x89Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/Square89x89Logo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/StoreLogo.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/icon.icns -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/icon.ico -------------------------------------------------------------------------------- /apps/desktop/src-tauri/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/desktop/src-tauri/icons/icon.png -------------------------------------------------------------------------------- /apps/desktop/src-tauri/src/main.rs: -------------------------------------------------------------------------------- 1 | // Prevents additional console window on Windows in release, DO NOT REMOVE!! 2 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 3 | 4 | fn main() { 5 | tauri::Builder::default() 6 | .run(tauri::generate_context!()) 7 | .expect("error while running Pathfinder"); 8 | } 9 | -------------------------------------------------------------------------------- /apps/desktop/src/components/app/app.css.ts: -------------------------------------------------------------------------------- 1 | import { style, globalStyle } from '@pathfinder-ide/style'; 2 | 3 | export const appContainer = style({ 4 | display: 'block', 5 | height: '100%', 6 | padding: 0, 7 | margin: 0, 8 | }); 9 | 10 | globalStyle('html', { 11 | background: 'rgb(35,35,35)', 12 | }); 13 | -------------------------------------------------------------------------------- /apps/desktop/src/components/app/app.tsx: -------------------------------------------------------------------------------- 1 | // relative path import here to src components 2 | // this allows us to dev without the build step and forgo importing the built css file 3 | import { Pathfinder } from '../../../../../packages/react/src'; 4 | 5 | import { appContainer } from './app.css'; 6 | 7 | export const App = () => { 8 | return ( 9 |
10 | 11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /apps/desktop/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | 3 | import { createRoot } from 'react-dom/client'; 4 | 5 | import { App } from './components/app/app'; 6 | 7 | const container = document.getElementById('root') as HTMLElement; 8 | 9 | const root = createRoot(container); 10 | 11 | root.render( 12 | 13 | 14 | , 15 | ); 16 | -------------------------------------------------------------------------------- /apps/desktop/src/types.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // vite 4 | interface ImportMetaEnv { 5 | readonly VITE_GRAFBASE_API_KEY: string; 6 | readonly VITE_GRAFBASE_ENDPOINT: string; 7 | } 8 | 9 | interface ImportMeta { 10 | readonly env: ImportMetaEnv; 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /apps/desktop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "moduleResolution": "bundler", 9 | "allowImportingTsExtensions": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "noEmit": true, 13 | "jsx": "react-jsx", 14 | "strict": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "noFallthroughCasesInSwitch": true, 18 | "types": ["node", "./vite-env.d.ts"] 19 | }, 20 | "include": ["src"], 21 | "references": [{ "path": "./tsconfig.node.json" }] 22 | } 23 | -------------------------------------------------------------------------------- /apps/desktop/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/desktop/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ImportMeta { 4 | readonly __IS_LITE_MODE_?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /apps/desktop/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; 4 | 5 | export default defineConfig(() => { 6 | return { 7 | base: '/', 8 | build: { 9 | rollupOptions: { 10 | output: { 11 | entryFileNames: `assets/[name].js`, 12 | chunkFileNames: `assets/[name].js`, 13 | assetFileNames: `assets/[name].[ext]`, 14 | }, 15 | }, 16 | }, 17 | // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` 18 | // 19 | // 1. prevent vite from obscuring rust errors 20 | clearScreen: false, 21 | // 2. tauri expects a fixed port, fail if that port is not available 22 | server: { 23 | port: 1420, 24 | strictPort: true, 25 | }, 26 | // 3. to make use of `TAURI_DEBUG` and other env variables 27 | // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand 28 | envPrefix: ['VITE_', 'TAURI_'], 29 | plugins: [react(), vanillaExtractPlugin({})], 30 | }; 31 | }); 32 | -------------------------------------------------------------------------------- /apps/graphql-yoga-server/constants.ts: -------------------------------------------------------------------------------- 1 | export const PORT = 4123; 2 | -------------------------------------------------------------------------------- /apps/graphql-yoga-server/index.ts: -------------------------------------------------------------------------------- 1 | import { createServer } from 'node:http'; 2 | import { createYoga } from 'graphql-yoga'; 3 | import { testSchema } from '../../packages/stores/src/schema-store/test-schema'; 4 | import { PORT } from './constants'; 5 | import { useDeferStream } from '@graphql-yoga/plugin-defer-stream'; 6 | 7 | // Create a Yoga instance with a GraphQL schema. 8 | const yoga = createYoga({ schema: testSchema, plugins: [useDeferStream()] }); 9 | 10 | // Pass it into a server to hook into request handlers. 11 | const server = createServer(yoga); 12 | 13 | // Start the server and you're done! 14 | server.listen(PORT, () => { 15 | console.info(`Server is running on http://localhost:${PORT}/graphql`); 16 | }); 17 | -------------------------------------------------------------------------------- /apps/graphql-yoga-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-yoga-server", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "ts-node ./index.ts" 7 | }, 8 | "devDependencies": { 9 | "@pathfinder-ide/stores": "workspace:*", 10 | "graphql-yoga": "5.7.0", 11 | "ts-node": "^10.9.1" 12 | }, 13 | "dependencies": { 14 | "@graphql-yoga/plugin-defer-stream": "3.7.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /apps/ladle/.env.development.local.example: -------------------------------------------------------------------------------- 1 | VITE_LOCAL_GRAPHQL_ENDPOINT=http://localhost:4123/graphql 2 | VITE_REMOTE_GRAPHQL_ENDPOINT= 3 | VITE_REMOTE_GRAPHQL_API_KEY= -------------------------------------------------------------------------------- /apps/ladle/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@pathfinder-ide/eslint-config"], 3 | "ignorePatterns": ["!.ladle"] 4 | } 5 | -------------------------------------------------------------------------------- /apps/ladle/.ladle/config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | stories: ['../../packages/react/src/**/*.stories.tsx'], 3 | addons: { 4 | theme: { 5 | enabled: false, 6 | defaultState: 'light', 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /apps/ladle/.ladle/styles.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | width: 100%; 5 | } 6 | 7 | #ladle-root { 8 | height: 100%; 9 | width: 100%; 10 | position: relative; 11 | 12 | .ladle-theme-switcher { 13 | position: absolute; 14 | bottom: 0; 15 | right: 0; 16 | z-index: 10; 17 | } 18 | } 19 | 20 | .ladle-main { 21 | padding: 0; 22 | position: relative; 23 | } 24 | -------------------------------------------------------------------------------- /apps/ladle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ladle", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "preview": "ladle preview", 9 | "serve": "NODE_ENV=development ladle serve", 10 | "dev": "concurrently \"pnpm serve\" \"pnpm --filter graphql-yoga-server dev\"", 11 | "types": "tsc --noEmit" 12 | }, 13 | "dependencies": { 14 | "@ladle/react": "4.0.2", 15 | "monaco-editor": "0.40.0", 16 | "monaco-graphql": "1.3.0", 17 | "react": "18.3.1", 18 | "react-dom": "18.3.1" 19 | }, 20 | "devDependencies": { 21 | "@pathfinder-ide/eslint-config": "workspace:*", 22 | "@pathfinder-ide/react": "workspace:*", 23 | "@pathfinder-ide/style": "workspace:*", 24 | "@pathfinder-ide/tsconfig": "workspace:*", 25 | "@types/react": "18.3.12", 26 | "@types/react-dom": "18.3.1", 27 | "@vanilla-extract/vite-plugin": "3.9.5", 28 | "@vitejs/plugin-react": "4.3.3", 29 | "concurrently": "^8.2.2", 30 | "vite": "5.4.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/ladle/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@pathfinder-ide/tsconfig/react.json", 3 | "compilerOptions": { 4 | "types": ["vite/client"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps/ladle/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { defineConfig } from 'vite'; 4 | 5 | import pluginReact from '@vitejs/plugin-react'; 6 | 7 | import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; 8 | 9 | export default defineConfig(({ command, mode }) => { 10 | console.log('launching ladle:', { command, mode }); 11 | return { 12 | server: { 13 | open: false, 14 | }, 15 | plugins: [ 16 | pluginReact(), 17 | vanillaExtractPlugin({ 18 | identifiers: 'debug', 19 | }), 20 | ], 21 | }; 22 | }); 23 | -------------------------------------------------------------------------------- /apps/website/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | 4 | # generated types 5 | .astro/ 6 | 7 | # vercel 8 | .vercel/ 9 | 10 | # dependencies 11 | node_modules/ 12 | 13 | # logs 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | 19 | # environment variables 20 | .env 21 | .env.production 22 | 23 | # macOS-specific files 24 | .DS_Store 25 | -------------------------------------------------------------------------------- /apps/website/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import tailwind from '@astrojs/tailwind'; 2 | import react from '@astrojs/react'; 3 | import { defineConfig } from 'astro/config'; 4 | import vercel from '@astrojs/vercel/static'; 5 | 6 | // https://astro.build/config 7 | export default defineConfig({ 8 | integrations: [tailwind(), react()], 9 | adapter: vercel({ 10 | imageService: true, 11 | }), 12 | }); 13 | -------------------------------------------------------------------------------- /apps/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pathfinder-ide/website", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "private": true, 6 | "scripts": { 7 | "dev": "astro dev", 8 | "start": "astro dev", 9 | "build": "astro build", 10 | "preview": "astro preview", 11 | "astro": "astro" 12 | }, 13 | "dependencies": { 14 | "@astrojs/react": "3.6.2", 15 | "@astrojs/tailwind": "5.1.2", 16 | "@astrojs/vercel": "7.8.2", 17 | "@fontsource/inter": "5.1.0", 18 | "astro": "3.6.5", 19 | "react": "18.3.1", 20 | "react-dom": "18.3.1", 21 | "sharp": "0.33.4", 22 | "tailwindcss": "3.4.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /apps/website/public/og.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/public/og.jpg -------------------------------------------------------------------------------- /apps/website/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/website/src/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/src/images/bg.png -------------------------------------------------------------------------------- /apps/website/src/images/oss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/src/images/oss.png -------------------------------------------------------------------------------- /apps/website/src/images/powerful-foundation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/src/images/powerful-foundation.png -------------------------------------------------------------------------------- /apps/website/src/images/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/src/images/preview.png -------------------------------------------------------------------------------- /apps/website/src/images/schema-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/src/images/schema-browser.png -------------------------------------------------------------------------------- /apps/website/src/images/visual-operation-builder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/apps/website/src/images/visual-operation-builder.png -------------------------------------------------------------------------------- /apps/website/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme'); 2 | 3 | /** @type {import('tailwindcss').Config} */ 4 | module.exports = { 5 | content: ['./src/**/*.{astro,tsx}'], 6 | theme: { 7 | extend: { 8 | fontFamily: { 9 | sans: ['Inter', ...defaultTheme.fontFamily.sans], 10 | }, 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /apps/website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable top-level await, and other modern ESM features. 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | // Enable node-style module resolution, for things like npm package imports. 7 | "moduleResolution": "node", 8 | // Enable JSON imports. 9 | "resolveJsonModule": true, 10 | // Enable stricter transpilation for better output. 11 | "isolatedModules": true, 12 | // Astro will directly run your TypeScript code, no transpilation needed. 13 | "noEmit": true, 14 | // Enable strict type checking. 15 | "strict": true, 16 | "jsx": "react" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/nextjs-example/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals", 3 | "rules": { 4 | "@next/next/no-html-link-for-pages": "off" 5 | } 6 | } -------------------------------------------------------------------------------- /examples/nextjs-example/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # nextjs-example 2 | 3 | ## 0.1.2 4 | 5 | ### Patch Changes 6 | 7 | - d4040c1: remove types script from nextjs-example 8 | 9 | ## 0.1.1 10 | 11 | ### Patch Changes 12 | 13 | - Updated dependencies [e331579] 14 | - @pathfinder-ide/react@0.1.1 15 | -------------------------------------------------------------------------------- /examples/nextjs-example/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/nextjs-example/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | 3 | const nextConfig = { 4 | reactStrictMode: true, 5 | } 6 | 7 | module.exports = nextConfig; 8 | -------------------------------------------------------------------------------- /examples/nextjs-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-example", 3 | "version": "0.1.2", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "lint": "next lint", 8 | "start": "next start", 9 | "types:check": "tsc --noEmit" 10 | }, 11 | "dependencies": { 12 | "@pathfinder-ide/react": "workspace:*", 13 | "@types/node": "20.4.5", 14 | "@types/react": "18.2.48", 15 | "@types/react-dom": "18.2.7", 16 | "autoprefixer": "10.4.14", 17 | "eslint": "8.56.0", 18 | "eslint-config-next": "13.4.12", 19 | "graphql": "^16.9.0", 20 | "next": "13.5.3", 21 | "next-global-css": "1.3.1", 22 | "postcss": "8.4.27", 23 | "react": "18.2.0", 24 | "react-dom": "18.2.0", 25 | "tailwindcss": "3.4.1", 26 | "typescript": "5.1.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/nextjs-example/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /examples/nextjs-example/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/nextjs-example/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafbase/pathfinder/e6ac1c75a80fa06e2806399d9148fa8bce304f65/examples/nextjs-example/src/app/favicon.ico -------------------------------------------------------------------------------- /examples/nextjs-example/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | html { 20 | height: 100%; 21 | width: 100%; 22 | } 23 | 24 | body { 25 | height: 100%; 26 | width: 100%; 27 | color: rgb(var(--foreground-rgb)); 28 | background: linear-gradient( 29 | to bottom, 30 | transparent, 31 | rgb(var(--background-end-rgb)) 32 | ) 33 | rgb(var(--background-start-rgb)); 34 | } 35 | -------------------------------------------------------------------------------- /examples/nextjs-example/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /examples/nextjs-example/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /examples/nextjs-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["dom", "dom.iterable", "ESNext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "ESNext", 12 | "moduleResolution": "bundler", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /examples/vite-example/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /examples/vite-example/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/vite-example/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # vite-example 2 | 3 | ## 0.0.1 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies [1611586] 8 | - @pathfinder-ide/react@0.3.2 9 | -------------------------------------------------------------------------------- /examples/vite-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/vite-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-example", 3 | "private": true, 4 | "version": "0.0.1", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite --force", 8 | "build": "tsc && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@pathfinder-ide/react": "workspace:*", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^18.2.48", 19 | "@types/react-dom": "^18.2.13", 20 | "@typescript-eslint/eslint-plugin": "^6.0.0", 21 | "@typescript-eslint/parser": "^6.0.0", 22 | "@vitejs/plugin-react": "^4.0.3", 23 | "eslint": "^8.56.0", 24 | "eslint-plugin-react-hooks": "^4.6.0", 25 | "eslint-plugin-react-refresh": "^0.4.3", 26 | "typescript": "^5.0.2", 27 | "vite": "5.4.2" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/vite-example/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | width: 100%; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | } 6 | 7 | .logo { 8 | height: 6em; 9 | padding: 1.5em; 10 | will-change: filter; 11 | transition: filter 300ms; 12 | } 13 | .logo:hover { 14 | filter: drop-shadow(0 0 2em #646cffaa); 15 | } 16 | .logo.react:hover { 17 | filter: drop-shadow(0 0 2em #61dafbaa); 18 | } 19 | 20 | @keyframes logo-spin { 21 | from { 22 | transform: rotate(0deg); 23 | } 24 | to { 25 | transform: rotate(360deg); 26 | } 27 | } 28 | 29 | @media (prefers-reduced-motion: no-preference) { 30 | a:nth-of-type(2) .logo { 31 | animation: logo-spin infinite 20s linear; 32 | } 33 | } 34 | 35 | .card { 36 | padding: 2em; 37 | } 38 | 39 | .read-the-docs { 40 | color: #888; 41 | } 42 | 43 | .pathfinder-wrap { 44 | height: 35vh; 45 | } 46 | -------------------------------------------------------------------------------- /examples/vite-example/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /examples/vite-example/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/vite-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /examples/vite-example/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /examples/vite-example/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pathfinder-ide/eslint-config", 3 | "version": "0.0.1", 4 | "private": true, 5 | "main": "eslint-config.js", 6 | "devDependencies": { 7 | "@typescript-eslint/eslint-plugin": "6.10.0", 8 | "@typescript-eslint/parser": "6.10.0", 9 | "eslint": "8.57.1", 10 | "eslint-plugin-jest-dom": "5.4.0", 11 | "eslint-plugin-react-hooks": "4.6.2", 12 | "eslint-plugin-testing-library": "6.2.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/react/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@pathfinder-ide/eslint-config"], 3 | "ignorePatterns": ["workers/*.bundle.js"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/react/.gitignore: -------------------------------------------------------------------------------- 1 | # workers 2 | *.worker.bundle.js 3 | lite-dist 4 | -------------------------------------------------------------------------------- /packages/react/__mocks__/monaco-editor/canvas.ts: -------------------------------------------------------------------------------- 1 | import 'vitest-canvas-mock'; 2 | -------------------------------------------------------------------------------- /packages/react/__mocks__/monaco-editor/get-selection.ts: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest'; 2 | 3 | Range.prototype.getBoundingClientRect = () => ({ 4 | bottom: 0, 5 | height: 0, 6 | left: 0, 7 | right: 0, 8 | top: 0, 9 | width: 0, 10 | x: 0, 11 | y: 0, 12 | toJSON: vi.fn(), 13 | }); 14 | 15 | // this isn't pretty but it gets us past an error (TypeError: Cannot read properties of undefined (reading 'top')) in "monaco-editor/esm/vs/editor/browser/view/domLineBreaksComputer.js" 16 | Range.prototype.getClientRects = () => [ 17 | // @ts-ignore 18 | { 19 | top: 0, 20 | }, 21 | ]; 22 | -------------------------------------------------------------------------------- /packages/react/__mocks__/monaco-editor/match-media.ts: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest'; 2 | 3 | Object.defineProperty(window, 'matchMedia', { 4 | writable: true, 5 | value: vi.fn().mockImplementation((query) => ({ 6 | matches: false, 7 | media: query, 8 | onchange: null, 9 | addListener: vi.fn(), // deprecated 10 | removeListener: vi.fn(), // deprecated 11 | addEventListener: vi.fn(), 12 | removeEventListener: vi.fn(), 13 | dispatchEvent: vi.fn(), 14 | })), 15 | }); 16 | -------------------------------------------------------------------------------- /packages/react/__mocks__/monaco-editor/query-command-supported.ts: -------------------------------------------------------------------------------- 1 | global.document.queryCommandSupported = () => false; 2 | -------------------------------------------------------------------------------- /packages/react/__mocks__/monaco-editor/resize-observer.ts: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest'; 2 | 3 | global.ResizeObserver = vi.fn().mockImplementation(() => ({ 4 | observe: vi.fn(), 5 | unobserve: vi.fn(), 6 | disconnect: vi.fn(), 7 | })); 8 | -------------------------------------------------------------------------------- /packages/react/__mocks__/monaco-editor/worker.ts: -------------------------------------------------------------------------------- 1 | window.URL.createObjectURL = function () { 2 | return ''; 3 | }; 4 | if (typeof Worker === 'undefined') { 5 | global.Worker = class { 6 | addEventListener() {} 7 | 8 | removeEventListener() {} 9 | 10 | dispatchEvent() { 11 | return false; 12 | } 13 | 14 | onmessage() {} 15 | 16 | onmessageerror() {} 17 | 18 | onerror() {} 19 | 20 | postMessage() {} 21 | 22 | terminate() {} 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { addTargetArgument } from './add-target-argument'; 2 | 3 | export { addTargetField } from './add-target-field'; 4 | 5 | export { removeTargetArgument } from './remove-target-argument'; 6 | 7 | export { removeTargetField } from './remove-target-field'; 8 | 9 | export { toggle } from './toggle'; 10 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/compass-store.tsx: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import { compassState } from './state'; 4 | 5 | import type { CompassState } from './compass-store.types'; 6 | 7 | export const compassStore = createStore(() => ({ 8 | ...compassState, 9 | })); 10 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/constants.ts: -------------------------------------------------------------------------------- 1 | export const INDENT_SIZE = 2; 2 | 3 | const PHONE_NUMBER = '+14155550169'; 4 | // @ts-ignore 5 | const JSON = []; 6 | const URL = 'https://grafbase.com/'; 7 | const TIMESTAMP = '1682626018389'; 8 | const IP_ADDRESS = '(123.12.34.56)'; 9 | const EMAIL = 'example@grafbase.com'; 10 | const DATE_TIME = '2007-12-03T10:15:30Z'; 11 | const DATE = '2007-12-03'; 12 | const BOOLEAN = true; 13 | const FLOAT = String(parseFloat('1.23')); 14 | const INT = String(parseInt('10', 10)); 15 | const STRING = ''; 16 | const ID = 'some_id_123456789'; 17 | 18 | export const DEFAULT_SCALAR_VALUES = { 19 | PHONE_NUMBER, 20 | // @ts-ignore 21 | JSON, 22 | URL, 23 | TIMESTAMP, 24 | IP_ADDRESS, 25 | EMAIL, 26 | DATE_TIME, 27 | DATE, 28 | BOOLEAN, 29 | FLOAT, 30 | INT, 31 | STRING, 32 | ID, 33 | }; 34 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/index.ts: -------------------------------------------------------------------------------- 1 | export { toggle } from './actions'; 2 | 3 | export { compassStore } from './compass-store'; 4 | 5 | export type { 6 | AncestorArgument, 7 | AncestorField, 8 | AncestorInlineFragment, 9 | AncestorRoot, 10 | AncestorTypes, 11 | AncestorsArray, 12 | } from './compass-store.types'; 13 | 14 | export { 15 | findSelection, 16 | generateSelectionBreadcrumbsFromAncestors, 17 | insertNewOperation, 18 | } from './utils'; 19 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/state.ts: -------------------------------------------------------------------------------- 1 | import { CompassState } from './compass-store.types'; 2 | 3 | export const compassState: CompassState = { 4 | argumentHandlingMode: 'INLINE', 5 | }; 6 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/find-next-token-kind-in-location.ts: -------------------------------------------------------------------------------- 1 | import { Token, TokenKind } from 'graphql'; 2 | 3 | export const findNextTokenKindInLocation = ({ 4 | startToken, 5 | tokenKind, 6 | }: { 7 | startToken: Token; 8 | tokenKind: TokenKind; 9 | }): Token | null => { 10 | const nextToken = startToken.next; 11 | 12 | if (!nextToken) { 13 | return null; 14 | } 15 | 16 | if (nextToken.kind === tokenKind) { 17 | return nextToken; 18 | } else { 19 | return findNextTokenKindInLocation({ startToken: nextToken, tokenKind }); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/generate-selection-breadcrumbs-from-ancestors.ts: -------------------------------------------------------------------------------- 1 | import { AncestorsArray } from '../compass-store.types'; 2 | 3 | // selection breadcrumbs help identify toggle buttons in tests 4 | export const generateSelectionBreadcrumbsFromAncestors = ({ 5 | ancestors, 6 | }: { 7 | ancestors: AncestorsArray; 8 | }) => 9 | [...ancestors] 10 | // eslint-disable-next-line consistent-return 11 | .map((ancestor) => { 12 | if (ancestor.type === 'FIELD') { 13 | return ancestor.field.name; 14 | } 15 | if (ancestor.type === 'ARGUMENT') { 16 | return ancestor.argument.name; 17 | } 18 | if (ancestor.type === 'INLINE_FRAGMENT') { 19 | return `on${ancestor.onType}`; 20 | } 21 | }) 22 | .join('/'); 23 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/generate-variable-text.ts: -------------------------------------------------------------------------------- 1 | import type { GraphQLArgument } from 'graphql'; 2 | 3 | export const generateVariableText = ({ argument }: { argument: GraphQLArgument }) => 4 | `$${argument.name}: ${argument.type.toString()}`; 5 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-active-definition-range.ts: -------------------------------------------------------------------------------- 1 | import { type MonacoIRange, graphQLDocumentStore } from '@pathfinder-ide/stores'; 2 | 3 | export const getActiveDefinitionRange = (): MonacoIRange | null => { 4 | const activeDocumentEntry = graphQLDocumentStore.getState().activeDocumentEntry; 5 | 6 | if (activeDocumentEntry?.node.loc) { 7 | return { 8 | startColumn: activeDocumentEntry.node.loc.startToken.column, 9 | endColumn: activeDocumentEntry.node.loc.endToken.column + 1, 10 | startLineNumber: activeDocumentEntry.node.loc.startToken.line, 11 | endLineNumber: activeDocumentEntry.node.loc.endToken.line, 12 | }; 13 | } 14 | return null; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-ancestor-text.ts: -------------------------------------------------------------------------------- 1 | import type { AncestorField, AncestorInlineFragment } from '../compass-store.types'; 2 | 3 | export const getAncestorText = ({ 4 | ancestor, 5 | }: { 6 | ancestor: AncestorField | AncestorInlineFragment; 7 | }) => { 8 | if (ancestor.type === 'FIELD') { 9 | return ancestor.field.name; 10 | } 11 | if (ancestor.type === 'INLINE_FRAGMENT') { 12 | return `... on ${ancestor.onType}`; 13 | } 14 | return console.error('error generating ancestor text'); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-enum-values.ts: -------------------------------------------------------------------------------- 1 | import { type GraphQLSchema, isEnumType } from 'graphql'; 2 | 3 | export const getEnumValues = ({ 4 | enumTypeName, 5 | schema, 6 | }: { 7 | enumTypeName: string; 8 | schema: GraphQLSchema; 9 | }): Array<{ name: string; value: string }> | undefined => { 10 | const enumType = schema.getType(enumTypeName); 11 | 12 | if (!isEnumType(enumType)) { 13 | return undefined; 14 | } 15 | 16 | return enumType.getValues().map((v) => ({ 17 | value: v.value, 18 | name: v.name, 19 | description: v.description || undefined, 20 | })); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-location-from-ancestor.ts: -------------------------------------------------------------------------------- 1 | import { type AncestorTypes } from '../compass-store.types'; 2 | 3 | export const getLocationFromAncestor = ({ ancestor }: { ancestor: AncestorTypes }) => { 4 | if ( 5 | (ancestor.type === 'INLINE_FRAGMENT' || ancestor.type === 'FIELD') && 6 | ancestor.selection 7 | ) { 8 | return ancestor.selection.loc; 9 | } 10 | if (ancestor.type === 'ROOT' && ancestor.operationDefinition) { 11 | return ancestor.operationDefinition.loc; 12 | } 13 | return null; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-position-at-end-of-location.ts: -------------------------------------------------------------------------------- 1 | import { type Location } from 'graphql'; 2 | 3 | import { DOCUMENT_EDITOR_ID } from '@pathfinder-ide/shared'; 4 | 5 | import { type MonacoIPosition, getMonacoEditor } from '@pathfinder-ide/stores'; 6 | 7 | export const getPositionAtEndOfLocation = ({ 8 | location, 9 | newTextLength, 10 | }: { 11 | location: Location; 12 | newTextLength: number; 13 | }): MonacoIPosition => { 14 | const locationEndPosition = getMonacoEditor({ editorId: DOCUMENT_EDITOR_ID }) 15 | ?.getModel() 16 | ?.getPositionAt(location.end) as MonacoIPosition; 17 | 18 | const position = { 19 | lineNumber: locationEndPosition.lineNumber, 20 | column: locationEndPosition.column + newTextLength, 21 | }; 22 | return position; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-previous-ancestor.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AncestorArgument, 3 | AncestorTypes, 4 | AncestorsArray, 5 | } from '../compass-store.types'; 6 | 7 | export const getPreviousAncestor = ({ 8 | ancestors, 9 | target, 10 | }: { 11 | ancestors: AncestorsArray; 12 | target: AncestorTypes; 13 | }) => { 14 | const index = ancestors.findIndex((a) => a === target); 15 | 16 | return ancestors[index - 1] as Exclude; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-range-from-string-in-active-definition.ts: -------------------------------------------------------------------------------- 1 | import type { MonacoEditorITextModel, MonacoIRange } from '@pathfinder-ide/stores'; 2 | 3 | import { getActiveDefinitionRange } from './get-active-definition-range'; 4 | 5 | export const getRangeFromStringInActiveDefinition = ({ 6 | model, 7 | string, 8 | }: { 9 | model: MonacoEditorITextModel; 10 | string: string; 11 | }): MonacoIRange | null => { 12 | const activeDefinitionRange = getActiveDefinitionRange(); 13 | 14 | if (model && activeDefinitionRange) { 15 | const matches = model.findMatches( 16 | string, 17 | activeDefinitionRange, 18 | false, 19 | false, 20 | null, 21 | true, 22 | ); 23 | 24 | // console.log('matches', { matches, string }) 25 | 26 | if (matches.length === 1) { 27 | return matches[0].range; 28 | } 29 | } 30 | 31 | return null; 32 | }; 33 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-root-ancestor.ts: -------------------------------------------------------------------------------- 1 | import type { AncestorRoot, AncestorsArray } from '../compass-store.types'; 2 | 3 | export const getRootAncestor = ({ ancestors }: { ancestors: AncestorsArray }) => { 4 | return ancestors[0] as AncestorRoot; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-selected-arguments-count.ts: -------------------------------------------------------------------------------- 1 | import type { AncestorField } from '../compass-store.types'; 2 | 3 | export const getSelectedArgumentsCount = ({ 4 | previousAncestor, 5 | }: { 6 | previousAncestor: AncestorField; 7 | }): number => { 8 | if ( 9 | previousAncestor.selection && 10 | 'arguments' in previousAncestor.selection && 11 | previousAncestor.selection.arguments 12 | ) { 13 | return previousAncestor.selection.arguments.length; 14 | } 15 | return 0; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/get-variable-definitions-count.ts: -------------------------------------------------------------------------------- 1 | import { Kind } from 'graphql'; 2 | 3 | import { graphQLDocumentStore } from '@pathfinder-ide/stores'; 4 | 5 | export const getVariableDefinitionsCount = (): number => { 6 | const activeDocumentEntry = graphQLDocumentStore.getState().activeDocumentEntry; 7 | 8 | if ( 9 | activeDocumentEntry?.node.kind === Kind.OPERATION_DEFINITION && 10 | activeDocumentEntry.node.variableDefinitions 11 | ) { 12 | return activeDocumentEntry.node.variableDefinitions.length; 13 | } 14 | return 0; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/has-sibling-selections.ts: -------------------------------------------------------------------------------- 1 | import type { AncestorTypes } from '../compass-store.types'; 2 | 3 | export const hasSiblingSelections = ({ 4 | mode, 5 | previousAncestor, 6 | }: { 7 | mode: 'ADD' | 'REMOVE'; 8 | previousAncestor: AncestorTypes; 9 | }): boolean => { 10 | const greaterThan = mode === 'ADD' ? 0 : 1; 11 | if ( 12 | (previousAncestor.type === 'INLINE_FRAGMENT' || previousAncestor.type === 'FIELD') && 13 | previousAncestor.selection && 14 | 'selectionSet' in previousAncestor.selection && 15 | previousAncestor.selection.selectionSet 16 | ) { 17 | return previousAncestor.selection.selectionSet.selections.length > greaterThan; 18 | } 19 | if ( 20 | previousAncestor.type === 'ROOT' && 21 | previousAncestor.operationDefinition && 22 | 'selectionSet' in previousAncestor.operationDefinition && 23 | previousAncestor.operationDefinition.selectionSet 24 | ) { 25 | return ( 26 | previousAncestor.operationDefinition.selectionSet.selections.length > greaterThan 27 | ); 28 | } 29 | return false; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass-store/utils/unwrap-non-null-argument-type.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLArgument, GraphQLInputType, isNonNullType } from 'graphql'; 2 | 3 | export const unwrapNonNullArgumentType = ({ 4 | argumentType, 5 | }: { 6 | argumentType: GraphQLArgument['type']; 7 | }): GraphQLInputType => { 8 | if (isNonNullType(argumentType)) { 9 | return argumentType.ofType; 10 | } 11 | return argumentType; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/react/src/compass/compass.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@pathfinder-ide/style'; 2 | 3 | export const compassClass = style({ 4 | position: 'relative', 5 | height: '100%', 6 | width: '100%', 7 | overflow: 'hidden', 8 | }); 9 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/argument/argument.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const argumentClass = style({ 4 | display: 'flex', 5 | position: 'relative', 6 | paddingLeft: 16, 7 | 8 | selectors: { 9 | '&::before': { 10 | content: '', 11 | position: 'absolute', 12 | top: 10, 13 | left: 2, 14 | height: 1, 15 | width: 6, 16 | backgroundColor: contract.color.neutral[4], 17 | }, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/argument/argument.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type AncestorArgument, 3 | type AncestorsArray, 4 | generateSelectionBreadcrumbsFromAncestors, 5 | } from '../../compass-store'; 6 | 7 | import { Details } from '../details'; 8 | 9 | import { argumentClass } from './argument.css'; 10 | 11 | export const Argument = ({ ancestors }: { ancestors: AncestorsArray }) => { 12 | const { argument, selection } = ancestors[ancestors.length - 1] as AncestorArgument; 13 | 14 | return ( 15 |
16 |
undefined} 21 | type={argument} 22 | variant={'ARGUMENT'} 23 | /> 24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/argument/index.ts: -------------------------------------------------------------------------------- 1 | export { Argument } from './argument'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/arguments/index.ts: -------------------------------------------------------------------------------- 1 | export { Arguments } from './arguments'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/collapse-control/collapse-control.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, recipe } from '@pathfinder-ide/style'; 2 | 3 | export const collapseControlClass = recipe({ 4 | base: { 5 | height: contract.space[20], 6 | width: contract.space[20], 7 | transformOrigin: 'center', 8 | }, 9 | variants: { 10 | isExpanded: { 11 | true: { 12 | transform: 'rotate(0deg)', 13 | }, 14 | false: { 15 | transform: 'rotate(-90deg)', 16 | }, 17 | }, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/collapse-control/collapse-control.tsx: -------------------------------------------------------------------------------- 1 | import { IconButton } from '../../../components/icon-button'; 2 | import { collapseControlClass } from './collapse-control.css'; 3 | 4 | export const CollapseControl = ({ 5 | isExpanded, 6 | setIsExpanded, 7 | title, 8 | }: { 9 | isExpanded: boolean; 10 | setIsExpanded: React.Dispatch>; 11 | title: string; 12 | }) => { 13 | return ( 14 |
15 | setIsExpanded(!isExpanded)} 17 | iconName="Chevron" 18 | onSurface={1} 19 | title={title} 20 | size="small" 21 | /> 22 |
23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/collapse-control/index.ts: -------------------------------------------------------------------------------- 1 | export { CollapseControl } from './collapse-control'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/details-actions/details-actions.css.ts: -------------------------------------------------------------------------------- 1 | import { recipe, shared, style } from '@pathfinder-ide/style'; 2 | 3 | export const detailsActionsClass = recipe({ 4 | base: { 5 | transition: `all .35s ${shared.transitions.authenticMotion}`, 6 | }, 7 | 8 | variants: { 9 | showActions: { 10 | true: { 11 | visibility: `visible`, 12 | opacity: 1, 13 | }, 14 | false: { 15 | visibility: `hidden`, 16 | opacity: 0, 17 | }, 18 | }, 19 | }, 20 | }); 21 | 22 | export const detailsActionsControlsClass = style({ 23 | display: `flex`, 24 | gap: 2, 25 | alignContent: `center`, 26 | }); 27 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/details-actions/index.ts: -------------------------------------------------------------------------------- 1 | export { DetailsActions } from './details-actions'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/details/index.ts: -------------------------------------------------------------------------------- 1 | export { Details } from './details'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/field/index.ts: -------------------------------------------------------------------------------- 1 | export { Field } from './field'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/fields/fields.tsx: -------------------------------------------------------------------------------- 1 | import { GraphQLFieldMap, SelectionNode } from 'graphql'; 2 | 3 | import { type AncestorsArray, findSelection } from '../../compass-store'; 4 | 5 | import { Field } from '../field'; 6 | 7 | export const Fields = ({ 8 | ancestors, 9 | fields, 10 | parentSelections, 11 | }: { 12 | ancestors: AncestorsArray; 13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 14 | fields: GraphQLFieldMap; 15 | parentSelections: ReadonlyArray; 16 | }) => { 17 | return ( 18 | <> 19 | {Object.keys(fields).map((f) => ( 20 | 35 | ))} 36 | 37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/fields/index.ts: -------------------------------------------------------------------------------- 1 | export { Fields } from './fields'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Argument } from './argument'; 2 | 3 | export { QuickDocs } from './quick-docs'; 4 | 5 | export { RootOperation } from './root-operation'; 6 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/indicator-leaf/index.ts: -------------------------------------------------------------------------------- 1 | export { IndicatorLeaf } from './indicator-leaf'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/indicator-leaf/indicator-leaf.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const indicatorLeafClass = style({ 4 | height: contract.space[20], 5 | width: contract.space[20], 6 | display: 'flex', 7 | justifyContent: 'center', 8 | alignItems: 'center', 9 | }); 10 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/indicator-leaf/indicator-leaf.tsx: -------------------------------------------------------------------------------- 1 | import { Icon } from '../../../components'; 2 | 3 | import { indicatorLeafClass } from './indicator-leaf.css'; 4 | 5 | export const IndicatorLeaf = () => { 6 | return ( 7 |
8 | 9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/list-item/index.ts: -------------------------------------------------------------------------------- 1 | export { ListItem } from './list-item'; 2 | 3 | export type { ListItemTypeTypes, ListItemVariants } from './list-item.types'; 4 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/list-item/list-item.types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | GraphQLArgument, 3 | GraphQLField, 4 | GraphQLInputObjectType, 5 | GraphQLObjectType, 6 | } from 'graphql'; 7 | 8 | import type { AncestorsArray } from '../../compass-store'; 9 | 10 | export type ListItemVariants = 'FIELD' | 'INLINE_FRAGMENT' | 'INPUT_OBJECT' | 'ARGUMENT'; 11 | 12 | export type ListItemTypeTypes = 13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 14 | GraphQLField | GraphQLArgument | GraphQLInputObjectType | GraphQLObjectType; 15 | 16 | type ListItemBaseProps = { 17 | ancestors: AncestorsArray; 18 | isSelected: boolean; 19 | type: ListItemTypeTypes; 20 | variant: ListItemVariants; 21 | }; 22 | 23 | type ListItemWithCollapserProps = { 24 | collapsibleContent?: { 25 | arguments?: React.ReactNode; 26 | renderChildFields?: () => React.ReactNode; 27 | }; 28 | }; 29 | 30 | export type ListItemProps = ListItemBaseProps & ListItemWithCollapserProps; 31 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/quick-docs/index.ts: -------------------------------------------------------------------------------- 1 | export { QuickDocs } from './quick-docs'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/quick-docs/quick-docs.tsx: -------------------------------------------------------------------------------- 1 | import { TertiaryPane, useSchemaDocumentationStore } from '../../../schema-documentation'; 2 | 3 | import { quickDocsClass } from './quick-docs.css'; 4 | 5 | export const QuickDocs = () => { 6 | const activeTertiaryPane = useSchemaDocumentationStore.use.activeTertiaryPane(); 7 | 8 | return ( 9 |
14 | {activeTertiaryPane && } 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/root-operation/index.ts: -------------------------------------------------------------------------------- 1 | export { RootOperation } from './root-operation'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/components/union/index.ts: -------------------------------------------------------------------------------- 1 | export { Union } from './union'; 2 | -------------------------------------------------------------------------------- /packages/react/src/compass/index.ts: -------------------------------------------------------------------------------- 1 | export { Compass } from './compass'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/action-execute-subscription/index.ts: -------------------------------------------------------------------------------- 1 | export { ActionExecuteSubscription } from './action-execute-subscription'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/action-execute/action-execute.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | executeOperation, 3 | useGraphQLDocumentStore, 4 | useSchemaStore, 5 | } from '@pathfinder-ide/stores'; 6 | 7 | import { Button } from '../button'; 8 | 9 | export const ActionExecute = () => { 10 | const activeDocumentEntry = useGraphQLDocumentStore.use.activeDocumentEntry(); 11 | const documentNotifications = useGraphQLDocumentStore.use.documentNotifications(); 12 | 13 | const isExecuting = useSchemaStore.use.isExecuting(); 14 | 15 | const shouldBeDisabled = 16 | !activeDocumentEntry || documentNotifications.length > 0 || isExecuting; 17 | 18 | return ( 19 | 38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /packages/react/src/components/icon-button/index.ts: -------------------------------------------------------------------------------- 1 | export { IconButton } from './icon-button'; 2 | 3 | export type { IconButtonProps } from './icon-button'; 4 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/arrow-right/arrow-right.tsx: -------------------------------------------------------------------------------- 1 | export const ArrowRight = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/arrow-right/index.ts: -------------------------------------------------------------------------------- 1 | export { ArrowRight } from './arrow-right'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/caret/caret.tsx: -------------------------------------------------------------------------------- 1 | export const Caret = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/caret/index.ts: -------------------------------------------------------------------------------- 1 | export { Caret } from './caret'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/chevron/chevron.tsx: -------------------------------------------------------------------------------- 1 | export const Chevron = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/chevron/index.ts: -------------------------------------------------------------------------------- 1 | export { Chevron } from './chevron'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/close/close.tsx: -------------------------------------------------------------------------------- 1 | export const Close = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/close/index.ts: -------------------------------------------------------------------------------- 1 | export { Close } from './close'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/compass/compass.tsx: -------------------------------------------------------------------------------- 1 | export const Compass = () => { 2 | return ( 3 | 4 | 5 | 6 | 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/compass/index.ts: -------------------------------------------------------------------------------- 1 | export { Compass } from './compass'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/components--icon.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Icon } from './icon'; 2 | 3 | export const Icons = () => { 4 | return ( 5 |
6 |
7 | Prettier 8 | 9 | 10 | 11 | 12 |
13 |
14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/delete/delete.tsx: -------------------------------------------------------------------------------- 1 | export const Delete = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/delete/index.ts: -------------------------------------------------------------------------------- 1 | export { Delete } from './delete'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/docs/docs.tsx: -------------------------------------------------------------------------------- 1 | export const Docs = () => { 2 | return ( 3 | 4 | 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/docs/index.ts: -------------------------------------------------------------------------------- 1 | export { Docs } from './docs'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/ellipsis/ellipsis.tsx: -------------------------------------------------------------------------------- 1 | export const Ellipsis = () => { 2 | return ( 3 | 4 | 8 | 9 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/ellipsis/index.ts: -------------------------------------------------------------------------------- 1 | export { Ellipsis } from './ellipsis'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/gear/gear.tsx: -------------------------------------------------------------------------------- 1 | export const Gear = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/gear/index.ts: -------------------------------------------------------------------------------- 1 | export { Gear } from './gear'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/graphql/index.ts: -------------------------------------------------------------------------------- 1 | export { GraphQL } from './graphql'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/icon.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, globalStyle, shared, recipe } from '@pathfinder-ide/style'; 2 | 3 | export const iconClass = recipe({ 4 | base: { 5 | display: 'flex', 6 | transform: 'rotate(0deg)', 7 | }, 8 | 9 | variants: { 10 | rotate: { 11 | '90': { 12 | transform: `rotate(90deg)`, 13 | }, 14 | '180': { 15 | transform: `rotate(180deg)`, 16 | }, 17 | '270': { 18 | transform: `rotate(270deg)`, 19 | }, 20 | }, 21 | size: { 22 | small: { 23 | height: contract.space[12], 24 | width: contract.space[12], 25 | }, 26 | medium: { 27 | height: contract.space[16], 28 | width: contract.space[16], 29 | }, 30 | large: { 31 | height: contract.space[20], 32 | width: contract.space[20], 33 | }, 34 | }, 35 | }, 36 | }); 37 | 38 | globalStyle(`${iconClass()} svg path`, { 39 | fill: contract.color.neutral[11], 40 | transition: `all .15s ${shared.transitions.authenticMotion}`, 41 | }); 42 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/icon.tsx: -------------------------------------------------------------------------------- 1 | import { iconClass } from './icon.css'; 2 | import { IconMap, IconProps } from './icon.types'; 3 | 4 | export const Icon = ({ name, rotate, size = 'small' }: IconProps) => { 5 | const TheIcon = IconMap[name]; 6 | return ( 7 |
13 | 14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/index.ts: -------------------------------------------------------------------------------- 1 | export { Icon } from './icon'; 2 | 3 | export type { IconNames } from './icon.types'; 4 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/insert-new-operation/index.ts: -------------------------------------------------------------------------------- 1 | export { InsertNewOperation } from './insert-new-operation'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/interpunct/index.ts: -------------------------------------------------------------------------------- 1 | export { Interpunct } from './interpunct'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/interpunct/interpunct.tsx: -------------------------------------------------------------------------------- 1 | export const Interpunct = () => { 2 | return ( 3 | 4 | 5 | 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/magnifing-glass/index.ts: -------------------------------------------------------------------------------- 1 | export { MagnifingGlass } from './magnifing-glass'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/magnifing-glass/magnifing-glass.tsx: -------------------------------------------------------------------------------- 1 | export const MagnifingGlass = () => { 2 | return ( 3 | 4 | 5 | 6 | 7 | 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/pause/index.ts: -------------------------------------------------------------------------------- 1 | export { Pause } from './pause'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/pause/pause.tsx: -------------------------------------------------------------------------------- 1 | export const Pause = () => { 2 | return ( 3 | 4 | 8 | 9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/plus/index.ts: -------------------------------------------------------------------------------- 1 | export { Plus } from './plus'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/plus/plus.tsx: -------------------------------------------------------------------------------- 1 | export const Plus = () => { 2 | return ( 3 | 4 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/react/src/components/icon/prettier/index.ts: -------------------------------------------------------------------------------- 1 | export { Prettier } from './prettier'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { Analyze } from './analyze'; 2 | 3 | export { Dropdown } from './dropdown'; 4 | 5 | export { CompassAnimated } from './compass-animated'; 6 | 7 | export { Connect } from './connect'; 8 | 9 | export { Editor } from './editor'; 10 | 11 | export { EditorTabs } from './editor-tabs'; 12 | 13 | export { Icon } from './icon'; 14 | 15 | export { LoadingSchema } from './loading-schema'; 16 | 17 | export { Operate } from './operate'; 18 | 19 | export { Pill } from './pill'; 20 | 21 | export { Pre } from './pre'; 22 | 23 | export { Resizer } from './resizer'; 24 | 25 | export { ScoutTools } from './scout-tools'; 26 | 27 | export { Tabs } from './tabs'; 28 | 29 | export { ThemeSwitcher } from './theme-switcher'; 30 | -------------------------------------------------------------------------------- /packages/react/src/components/kbd/components--kdb.stories.tsx: -------------------------------------------------------------------------------- 1 | import { KBD } from './kbd'; 2 | 3 | export const Options = () => { 4 | return ( 5 |
6 |
7 | COMMAND_CONTROL 8 | 9 |
10 |
11 | RETURN 12 | 13 |
14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/react/src/components/kbd/index.ts: -------------------------------------------------------------------------------- 1 | export { KBD } from './kbd'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/kbd/kbd.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const kbdClass = style({ 4 | boxSizing: 'border-box', 5 | display: 'inline-flex', 6 | alignItems: 'center', 7 | justifyContent: 'center', 8 | height: contract.space[20], 9 | minWidth: contract.space[20], 10 | padding: `0 ${contract.space[4]}`, 11 | backgroundColor: contract.color.neutral[1], 12 | color: contract.color.neutral[10], 13 | borderRadius: contract.space[4], 14 | border: `1px solid ${contract.color.neutral[6]}`, 15 | fontSize: 12, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/react/src/components/kbd/kbd.tsx: -------------------------------------------------------------------------------- 1 | import { kbdClass } from './kbd.css'; 2 | 3 | const keyMap = { 4 | COMMAND_CONTROL: { 5 | mac: '⌘', 6 | other: 'Ctrl', 7 | }, 8 | RETURN: { 9 | mac: '↩', 10 | other: '↩', 11 | }, 12 | }; 13 | 14 | export const KBD = ({ shortcut }: { shortcut: keyof typeof keyMap }) => { 15 | const isMacUserAgent = navigator.platform.toUpperCase().indexOf('MAC') >= 0; 16 | 17 | return ( 18 | {keyMap[shortcut][isMacUserAgent ? 'mac' : 'other']} 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/react/src/components/loading-schema/index.ts: -------------------------------------------------------------------------------- 1 | export { LoadingSchema } from './loading-schema'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/loading-schema/loading-schema.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const loadingSchemaClass = style({ 4 | height: '100%', 5 | width: '100%', 6 | position: 'relative', 7 | display: 'flex', 8 | alignItems: 'center', 9 | justifyContent: 'center', 10 | gap: 12, 11 | color: contract.color.neutral[11], 12 | fontFamily: contract.fonts.mono, 13 | fontSize: 12, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/react/src/components/loading-schema/loading-schema.tsx: -------------------------------------------------------------------------------- 1 | import { CompassAnimated } from '../compass-animated'; 2 | import { loadingSchemaClass } from './loading-schema.css'; 3 | 4 | export const LoadingSchema = () => { 5 | return ( 6 |
7 | Loading schema... 8 | 9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/react/src/components/operate/components--operate.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Operate } from './operate'; 2 | 3 | export const Story = () => { 4 | return ; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/react/src/components/operate/index.ts: -------------------------------------------------------------------------------- 1 | export { Operate } from './operate'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/operate/operate.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const operateClass = style({ 4 | width: '100%', 5 | height: '100%', 6 | display: 'flex', 7 | flexDirection: 'column', 8 | justifyContent: 'flex-end', 9 | position: 'relative', 10 | paddingRight: contract.space[12], 11 | paddingLeft: contract.space[12], 12 | }); 13 | 14 | export const documentEditorWrapClass = style({ 15 | overflowY: 'auto', 16 | height: '100%', 17 | position: 'relative', 18 | paddingTop: contract.space[12], 19 | paddingBottom: contract.space[12], 20 | paddingLeft: contract.space[12], 21 | }); 22 | 23 | export const separatorClass = style({ 24 | display: 'block', 25 | paddingLeft: contract.space[4], 26 | paddingRight: contract.space[4], 27 | 28 | selectors: { 29 | '&:after': { 30 | content: '', 31 | display: 'block', 32 | marginTop: 2, 33 | height: 20, 34 | width: 1, 35 | backgroundColor: contract.color.neutral[3], 36 | }, 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /packages/react/src/components/pill/components--pill.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Pill } from './pill'; 2 | 3 | export const Options = () => { 4 | return ( 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/src/components/pill/index.ts: -------------------------------------------------------------------------------- 1 | export { Pill } from './pill'; 2 | 3 | export type { PillProps } from './pill'; 4 | -------------------------------------------------------------------------------- /packages/react/src/components/pill/pill.tsx: -------------------------------------------------------------------------------- 1 | import { pillClass } from './pill.css'; 2 | 3 | import type { RecipeVariants } from '@pathfinder-ide/style'; 4 | 5 | export type PillProps = { 6 | copy: string; 7 | variant: RecipeVariants; 8 | }; 9 | 10 | export const Pill = ({ copy, variant }: PillProps) => { 11 | return ( 12 | 17 | {copy} 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/react/src/components/pre/index.ts: -------------------------------------------------------------------------------- 1 | export { Pre } from './pre'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/pre/pre.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, recipe } from '@pathfinder-ide/style'; 2 | 3 | export const preClass = recipe({ 4 | base: { 5 | margin: 0, 6 | lineHeight: 1.5, 7 | fontWeight: 400, 8 | fontSize: 11, 9 | fontFamily: contract.fonts.mono, 10 | }, 11 | variants: { 12 | status: { 13 | info: { 14 | color: contract.color.neutral[10], 15 | }, 16 | error: { 17 | color: contract.color.red[10], 18 | }, 19 | }, 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /packages/react/src/components/pre/pre.tsx: -------------------------------------------------------------------------------- 1 | import { RecipeVariants } from '@pathfinder-ide/style'; 2 | import { preClass } from './pre.css'; 3 | 4 | export const Pre = ({ 5 | code, 6 | status, 7 | }: { 8 | code: string; 9 | status: Pick>, 'status'>['status']; 10 | }) => { 11 | return ( 12 |
17 |       {code}
18 |     
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/index.ts: -------------------------------------------------------------------------------- 1 | export { Resizer } from './resizer'; 2 | 3 | export { resetPane, useResizerStore } from './resizer-store'; 4 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/actions/get-initial-grid-template.ts: -------------------------------------------------------------------------------- 1 | import { ResizerProps } from '../../resizer.types'; 2 | 3 | export const getInitialGridTemplate = ({ 4 | pane2InitialSize, 5 | }: { 6 | pane2InitialSize: ResizerProps['pane2']['initialSize']; 7 | }) => { 8 | if (pane2InitialSize.type === 'PERCENT') { 9 | const initialSize = Number((1 - pane2InitialSize.value * 0.01).toFixed(5)); 10 | return `minmax(0, ${initialSize}fr) 0px minmax(0, ${Number( 11 | (1 - initialSize).toFixed(5), 12 | )}fr)`; 13 | } else { 14 | return `1fr 0 ${pane2InitialSize.value}px`; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { getInitialGridTemplate } from './get-initial-grid-template'; 2 | 3 | export { resetPane } from './reset-pane'; 4 | 5 | export { setResizerState } from './set-resizer-state'; 6 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/actions/reset-pane.ts: -------------------------------------------------------------------------------- 1 | import { resizerStore } from '../resizer-store'; 2 | import { ResizerStoreActions } from '../resizer-store.types'; 3 | import { getInitialGridTemplate } from './get-initial-grid-template'; 4 | import { setResizerState } from './set-resizer-state'; 5 | 6 | export const resetPane: ResizerStoreActions['resetPane'] = ({ resizerName }) => { 7 | const { pane2InitialSize } = resizerStore.getState()[resizerName]; 8 | 9 | const initialGridTemplate = getInitialGridTemplate({ 10 | pane2InitialSize, 11 | }); 12 | 13 | setResizerState({ 14 | name: resizerName, 15 | updates: { 16 | gridTemplate: initialGridTemplate, 17 | startingGridTemplate: initialGridTemplate, 18 | }, 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/actions/set-resizer-state.ts: -------------------------------------------------------------------------------- 1 | import { resizerStore } from '../resizer-store'; 2 | import { ResizerStoreActions } from '../resizer-store.types'; 3 | 4 | export const setResizerState: ResizerStoreActions['setResizerState'] = ({ 5 | name, 6 | updates, 7 | }) => { 8 | const existingResizer = resizerStore.getState()[name]; 9 | return resizerStore.setState({ 10 | [name]: { ...existingResizer, ...updates }, 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './actions'; 2 | 3 | export { resizerStore } from './resizer-store'; 4 | 5 | export { useResizerStore } from './use-resizer-store'; 6 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/resizer-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import type { Resizer, ResizerStore } from './resizer-store.types'; 4 | 5 | const commonResizerDefaults: Omit = { 6 | pane2InitialSize: { 7 | type: 'PIXELS', 8 | value: 0, 9 | }, 10 | gridTemplate: 'minmax(0, 0.5fr) 0px minmax(0, 0.5fr)', 11 | startingGridTemplate: null, 12 | }; 13 | 14 | export const resizerStore = createStore()(() => ({ 15 | ide_resizer: { 16 | name: 'ide_resizer', 17 | ...commonResizerDefaults, 18 | }, 19 | editors_resizer: { 20 | name: 'editors_resizer', 21 | ...commonResizerDefaults, 22 | }, 23 | scout_resizer: { 24 | name: 'scout_resizer', 25 | ...commonResizerDefaults, 26 | }, 27 | history_resizer: { 28 | name: 'history_resizer', 29 | ...commonResizerDefaults, 30 | }, 31 | schema_docs_1: { 32 | name: 'schema_docs_1', 33 | ...commonResizerDefaults, 34 | }, 35 | schema_docs_2: { 36 | name: 'schema_docs_2', 37 | ...commonResizerDefaults, 38 | }, 39 | })); 40 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/resizer-store.types.ts: -------------------------------------------------------------------------------- 1 | import { ResizerProps } from '../resizer.types'; 2 | 3 | export type AvailableResizers = 4 | | 'ide_resizer' 5 | | 'editors_resizer' 6 | | 'scout_resizer' 7 | | 'history_resizer' 8 | | 'schema_docs_1' 9 | | 'schema_docs_2'; 10 | 11 | export type Resizer = { 12 | name: AvailableResizers; 13 | pane2InitialSize: ResizerProps['pane2']['initialSize']; 14 | gridTemplate: string; 15 | startingGridTemplate: string | null; 16 | }; 17 | 18 | export type ResizerStoreActions = { 19 | resetPane: ({ resizerName }: { resizerName: AvailableResizers }) => void; 20 | setResizerState: ({ 21 | name, 22 | updates, 23 | }: { 24 | name: AvailableResizers; 25 | updates: Partial>; 26 | }) => void; 27 | }; 28 | 29 | type ResizerStoreState = { 30 | ide_resizer: Resizer; 31 | editors_resizer: Resizer; 32 | scout_resizer: Resizer; 33 | history_resizer: Resizer; 34 | schema_docs_1: Resizer; 35 | schema_docs_2: Resizer; 36 | }; 37 | 38 | export type ResizerStore = ResizerStoreState; 39 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer-store/use-resizer-store.ts: -------------------------------------------------------------------------------- 1 | import { resizerStore } from './resizer-store'; 2 | 3 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 4 | 5 | export const useResizerStore = createZustandSelectors(resizerStore); 6 | -------------------------------------------------------------------------------- /packages/react/src/components/resizer/resizer.types.ts: -------------------------------------------------------------------------------- 1 | import { AvailableResizers } from './resizer-store/resizer-store.types'; 2 | 3 | export type ResizerOrientation = 'HORIZONTAL' | 'VERTICAL'; 4 | 5 | export type ResizerInitialSize = 6 | | { type: 'PIXELS'; value: number } 7 | | { type: 'PERCENT'; value: number }; 8 | 9 | export type ResizerProps = { 10 | resizerName: AvailableResizers; 11 | onSurface: 1 | 2 | 3; 12 | orientation: ResizerOrientation; 13 | pane1: { 14 | component: React.ReactElement; 15 | minimumSize?: number; 16 | }; 17 | pane2: { 18 | component: React.ReactElement; 19 | initialSize: ResizerInitialSize; 20 | minimumSize?: number; 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/react/src/components/scout-tools/components--scout-tools.stories.tsx: -------------------------------------------------------------------------------- 1 | import { ScoutTools } from './scout-tools'; 2 | 3 | export const Story = () => { 4 | return ; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/react/src/components/scout-tools/index.ts: -------------------------------------------------------------------------------- 1 | export { ScoutTools } from './scout-tools'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/scout-tools/scout-tools.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const scoutToolsClass = style({ 4 | display: 'flex', 5 | flexDirection: 'column', 6 | height: '100%', 7 | width: '100%', 8 | position: 'relative', 9 | backgroundColor: contract.color.neutral[2], 10 | }); 11 | -------------------------------------------------------------------------------- /packages/react/src/components/sessions/index.ts: -------------------------------------------------------------------------------- 1 | export { Sessions } from './sessions'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/sessions/sessions.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, shared, style } from '@pathfinder-ide/style'; 2 | 3 | export const sessionsClass = style({}); 4 | 5 | export const sessionSelectButtonClass = style([ 6 | shared.resets.buttonReset, 7 | { 8 | padding: 12, 9 | marginBottom: 12, 10 | width: '100%', 11 | fontFamily: contract.fonts.mono, 12 | fontSize: 11, 13 | backgroundColor: contract.color.neutral[11], 14 | color: contract.color.neutral[2], 15 | fontWeight: 500, 16 | borderRadius: 2, 17 | transition: `all .1s ${shared.transitions.authenticMotion}`, 18 | 19 | selectors: { 20 | '&:hover': { 21 | backgroundColor: contract.color.neutral[12], 22 | color: contract.color.neutral[1], 23 | }, 24 | }, 25 | }, 26 | ]); 27 | -------------------------------------------------------------------------------- /packages/react/src/components/sessions/sessions.tsx: -------------------------------------------------------------------------------- 1 | import { STORAGE_NAME_SESSION } from '@pathfinder-ide/shared'; 2 | 3 | import { loadSession, useSessionStore } from '@pathfinder-ide/stores'; 4 | 5 | import { sessionsClass, sessionSelectButtonClass } from './sessions.css'; 6 | 7 | export const Sessions = ({ sessionNames }: { sessionNames: string[] }) => { 8 | return ( 9 |
10 | {sessionNames.map((sessionName, i) => ( 11 | 21 | ))} 22 |
23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/react/src/components/spinner/index.ts: -------------------------------------------------------------------------------- 1 | export { Spinner } from './spinner'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/spinner/spinner.tsx: -------------------------------------------------------------------------------- 1 | import type { RecipeVariants } from '@pathfinder-ide/style'; 2 | 3 | import { useThemeStore } from '@pathfinder-ide/stores'; 4 | 5 | import { spinnerInnerClass, spinnerOuterClass } from './spinner.css'; 6 | 7 | export const Spinner = ({ 8 | variant, 9 | }: { 10 | variant: Omit>, 'theme'>; 11 | }) => { 12 | const activeTheme = useThemeStore.use.activeTheme(); 13 | return ( 14 |
15 |
21 |
22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/react/src/components/switch/index.ts: -------------------------------------------------------------------------------- 1 | export { Switch } from './switch'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { Tabs } from './tabs'; 2 | 3 | // export type { TabItem, TabsProps } from "./tabs.types"; 4 | -------------------------------------------------------------------------------- /packages/react/src/components/tabs/tabs.types.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export type TabItem = { 4 | action?: () => void; 5 | buttonContent: () => ReactNode; 6 | name: string; 7 | panelContent: () => ReactNode; 8 | }; 9 | 10 | export type TabsProps = TabItem[]; 11 | -------------------------------------------------------------------------------- /packages/react/src/components/theme-switcher/index.ts: -------------------------------------------------------------------------------- 1 | export { ThemeSwitcher } from './theme-switcher'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/theme-switcher/theme-switcher.tsx: -------------------------------------------------------------------------------- 1 | import { setTheme, useThemeStore } from '@pathfinder-ide/stores'; 2 | 3 | export const ThemeSwitcher = () => { 4 | const activeTheme = useThemeStore.use.activeTheme(); 5 | 6 | return ( 7 |
8 | 18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/react/src/components/variables/index.ts: -------------------------------------------------------------------------------- 1 | export { Variables } from './variables'; 2 | -------------------------------------------------------------------------------- /packages/react/src/components/variables/variables.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const variablesWrapClass = style({ 4 | display: 'flex', 5 | flexDirection: 'column', 6 | width: '100%', 7 | height: '100%', 8 | padding: contract.space[12], 9 | }); 10 | 11 | export const variablesEditorWrapClass = style({ 12 | paddingTop: contract.space[16], 13 | paddingRight: contract.space[16], 14 | height: '100%', 15 | }); 16 | -------------------------------------------------------------------------------- /packages/react/src/ide/ide.tsx: -------------------------------------------------------------------------------- 1 | import { useThemeStore } from '@pathfinder-ide/stores'; 2 | 3 | import { Compass } from '../compass'; 4 | import { Resizer } from '../components'; 5 | import { Scout } from '../scout'; 6 | 7 | export const IDE = () => { 8 | const activeTheme = useThemeStore.use.activeTheme(); 9 | 10 | if (!activeTheme) { 11 | return

Please wrap IDE with the Pathfinder component.

; 12 | } 13 | 14 | return ( 15 | , 21 | }} 22 | pane2={{ 23 | component: , 24 | initialSize: { type: 'PERCENT', value: 70 }, 25 | }} 26 | /> 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/react/src/ide/index.ts: -------------------------------------------------------------------------------- 1 | export { IDE } from './ide'; 2 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | import { setMonacoImporter } from '@pathfinder-ide/stores'; 2 | 3 | // store functions 4 | export { 5 | setTheme as setPathfinderTheme, 6 | useThemeStore as usePathfinderThemeStore, 7 | setMonacoImporter, 8 | } from '@pathfinder-ide/stores'; 9 | 10 | export { Pathfinder } from './pathfinder'; 11 | 12 | export { useSchemaDocumentationStore } from './schema-documentation/index'; 13 | 14 | // schema-dependent components 15 | export { SchemaDocumentation } from './schema-documentation'; 16 | export { SchemaView } from './schema-view'; 17 | 18 | if (import.meta.__IS_LITE_MODE_ !== true) { 19 | setMonacoImporter(() => import('monaco-graphql/esm/monaco-editor')); 20 | } 21 | -------------------------------------------------------------------------------- /packages/react/src/pathfinder/index.ts: -------------------------------------------------------------------------------- 1 | export { Pathfinder } from './pathfinder'; 2 | -------------------------------------------------------------------------------- /packages/react/src/pathfinder/pathfinder.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const pathfinderClass = style({ 4 | height: '100%', 5 | width: '100%', 6 | backgroundColor: contract.color.neutral[1], 7 | fontFamily: contract.fonts.body, 8 | }); 9 | 10 | export const connectWrapClass = style({ 11 | height: '100%', 12 | width: '100%', 13 | backgroundColor: contract.color.neutral[1], 14 | paddingLeft: '25%', 15 | paddingRight: '25%', 16 | display: 'flex', 17 | alignContent: 'center', 18 | justifyContent: 'center', 19 | }); 20 | -------------------------------------------------------------------------------- /packages/react/src/pathfinder/pathfinder.types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HTTPHeaderValue, 3 | SchemaStoreState, 4 | WatchHeaders, 5 | } from '@pathfinder-ide/stores'; 6 | import { SharedComponentProps } from '../types'; 7 | 8 | export type PathfinderProps = SharedComponentProps & { 9 | mode?: 'IDE' | 'SCOUT' | 'REFERENCE'; 10 | fetcherOptions?: { 11 | endpoint: string; 12 | headers?: Pick[]; 13 | }; 14 | schemaPollingOptions?: Partial< 15 | Pick 16 | >; 17 | watchHeaders?: WatchHeaders; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/react/src/reference/index.ts: -------------------------------------------------------------------------------- 1 | export { Reference } from './reference'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/arguments-list/arguments-list.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, recipe, style } from '@pathfinder-ide/style'; 2 | 3 | export const argumentListClass = style({ 4 | display: 'flex', 5 | flexDirection: 'column', 6 | gap: 10, 7 | paddingTop: 8, 8 | paddingRight: 0, 9 | paddingBottom: 8, 10 | paddingLeft: 12, 11 | }); 12 | 13 | export const argumentClass = recipe({ 14 | base: {}, 15 | 16 | variants: { 17 | showBorder: { 18 | true: { 19 | borderLeft: `1px solid ${contract.color.neutral[4]}`, 20 | marginLeft: -12, 21 | paddingLeft: 12, 22 | }, 23 | }, 24 | showDescription: { 25 | true: { 26 | display: 'flex', 27 | flexDirection: 'column', 28 | }, 29 | }, 30 | }, 31 | }); 32 | 33 | export const inputObjectName = style({ 34 | color: contract.color.orange[11], 35 | }); 36 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/arguments-list/index.ts: -------------------------------------------------------------------------------- 1 | export { ArgumentsList } from './arguments-list'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/default-value/default-value.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const defaultValueClass = style({ 4 | color: contract.color.yellow[10], 5 | cursor: 'default', 6 | }); 7 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/default-value/default-value.tsx: -------------------------------------------------------------------------------- 1 | import { GraphQLArgument, GraphQLInputField, astFromValue, print } from 'graphql'; 2 | 3 | import { defaultValueClass } from './default-value.css'; 4 | 5 | export const DefaultValue = ({ 6 | inputFieldOrArgument, 7 | }: { 8 | inputFieldOrArgument: GraphQLInputField | GraphQLArgument; 9 | }) => { 10 | const defaultValue = () => { 11 | if (inputFieldOrArgument.defaultValue !== undefined) { 12 | const ast = astFromValue( 13 | inputFieldOrArgument.defaultValue, 14 | inputFieldOrArgument.type, 15 | ); 16 | if (!ast) { 17 | return null; 18 | } 19 | return print(ast); 20 | } 21 | return null; 22 | }; 23 | 24 | const dVal = defaultValue(); 25 | 26 | if (!dVal) { 27 | return null; 28 | } 29 | 30 | return ( 31 | <> 32 | = 33 | 34 | {dVal} 35 | 36 | 37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/default-value/index.ts: -------------------------------------------------------------------------------- 1 | export { DefaultValue } from './default-value'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/delimiter/delimiter.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, recipe } from '@pathfinder-ide/style'; 2 | 3 | export const delimiterClass = recipe({ 4 | base: { 5 | color: contract.color.neutral[10], 6 | }, 7 | variants: { 8 | spacing: { 9 | LEFT: { paddingLeft: 2 }, 10 | RIGHT: { paddingRight: 2 }, 11 | LEFT_AND_RIGHT: { paddingLeft: 2, paddingRight: 2 }, 12 | }, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/delimiter/delimiter.tsx: -------------------------------------------------------------------------------- 1 | import type { RecipeVariants } from '@pathfinder-ide/style'; 2 | 3 | import { delimiterClass } from './delimiter.css'; 4 | 5 | export const Delimiter = ({ 6 | spacing, 7 | value, 8 | }: { 9 | spacing: Pick>, 'spacing'>['spacing']; 10 | value: ':' | '(' | ')'; 11 | }) => { 12 | return {value}; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/delimiter/index.ts: -------------------------------------------------------------------------------- 1 | export { Delimiter } from './delimiter'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/index.ts: -------------------------------------------------------------------------------- 1 | export { SchemaDocumentation } from './schema-documentation'; 2 | 3 | export { TertiaryPane } from './tertiary-pane'; 4 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/leaf/leaf.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const directiveLocationClass = style({ 4 | color: contract.color.yellow[10], 5 | marginBottom: 8, 6 | }); 7 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/markdown/index.ts: -------------------------------------------------------------------------------- 1 | export { Markdown } from './markdown'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/markdown/markdown.tsx: -------------------------------------------------------------------------------- 1 | import ReactMarkdown from 'react-markdown'; 2 | 3 | import { markdownClass } from './markdown.css'; 4 | 5 | export const Markdown = ({ content }: { content: string }) => { 6 | return ( 7 |
8 | {content} 9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/schema-documentation/index.ts: -------------------------------------------------------------------------------- 1 | export { SchemaDocumentation } from './schema-documentation'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/summary/index.tsx: -------------------------------------------------------------------------------- 1 | export { SummaryField, SummaryInputField, SummaryType } from './summary'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/summary/summary.css.ts: -------------------------------------------------------------------------------- 1 | import { style, contract } from '@pathfinder-ide/style'; 2 | 3 | export const summaryFieldClass = style({ 4 | borderLeft: `1px solid ${contract.color.neutral[4]}`, 5 | margin: '12px 0', 6 | paddingLeft: 8, 7 | 8 | selectors: { 9 | '&:first-child': { 10 | marginTop: 0, 11 | }, 12 | }, 13 | }); 14 | 15 | export const summaryTypeClass = style({ 16 | display: 'flex', 17 | flexDirection: 'column', 18 | borderLeft: contract.color.neutral[6], 19 | }); 20 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/tertiary-pane/index.ts: -------------------------------------------------------------------------------- 1 | export { TertiaryPane } from './tertiary-pane'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/type-system-nav-button/index.ts: -------------------------------------------------------------------------------- 1 | export { TypeSystemNavButton } from './type-system-nav-button'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/components/types-nav.tsx: -------------------------------------------------------------------------------- 1 | import type { SortedTypeMap, TopLevelPane } from '../types'; 2 | 3 | import { Section } from './section'; 4 | import { TypeSystemNavButton } from './type-system-nav-button'; 5 | 6 | export const TypesNav = ({ sortedTypes }: { sortedTypes: SortedTypeMap }) => { 7 | return ( 8 |
9 | {Object.keys(sortedTypes).map((s) => { 10 | return ( 11 | 17 | ); 18 | })} 19 |
20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/index.ts: -------------------------------------------------------------------------------- 1 | export { SchemaDocumentation, TertiaryPane } from './components'; 2 | 3 | export { useSchemaDocumentationStore } from './store'; 4 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/store/index.ts: -------------------------------------------------------------------------------- 1 | export { useSchemaDocumentationStore } from './schema-documentation-store'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/store/schema-documentation-store.tsx: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import { schemaDocumentationStoreActions } from './actions'; 4 | import { schemaDocumentationState } from './state'; 5 | import { 6 | SchemaDocumentationStoreState, 7 | SchemaDocumentationStoreActions, 8 | } from './schema-documentation-store.types'; 9 | 10 | const schemaDocumentationStore = createStore< 11 | SchemaDocumentationStoreState & SchemaDocumentationStoreActions 12 | >()((set, get) => ({ 13 | ...schemaDocumentationState, 14 | ...schemaDocumentationStoreActions(set, get), 15 | })); 16 | 17 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 18 | 19 | export const useSchemaDocumentationStore = createZustandSelectors( 20 | schemaDocumentationStore, 21 | ); 22 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/store/state.ts: -------------------------------------------------------------------------------- 1 | import { SchemaDocumentationStoreState } from './schema-documentation-store.types'; 2 | 3 | export const schemaDocumentationState: SchemaDocumentationStoreState = { 4 | activePrimaryPane: 'Query', 5 | activeTertiaryPane: null, 6 | tertiaryPaneStack: [], 7 | }; 8 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/types/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLDirective, 3 | GraphQLEnumType, 4 | GraphQLField, 5 | GraphQLInputField, 6 | GraphQLInputObjectType, 7 | GraphQLInterfaceType, 8 | GraphQLNamedType, 9 | GraphQLObjectType, 10 | GraphQLScalarType, 11 | GraphQLUnionType, 12 | } from 'graphql'; 13 | 14 | export type SortedTypeMap = { 15 | Scalars: GraphQLScalarType[]; 16 | Enums: GraphQLEnumType[]; 17 | Objects: GraphQLObjectType[]; 18 | 'Input Objects': GraphQLInputObjectType[]; 19 | Unions: GraphQLUnionType[]; 20 | Interfaces: GraphQLInterfaceType[]; 21 | }; 22 | 23 | export type TertiaryPaneType = 24 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 25 | | GraphQLField 26 | | GraphQLNamedType 27 | | GraphQLDirective 28 | | GraphQLInterfaceType 29 | | GraphQLInputField; 30 | 31 | export type TopLevelPane = 32 | | 'Query' 33 | | 'Mutation' 34 | | 'Subscription' 35 | | 'Directives' 36 | | 'Scalars' 37 | | 'Enums' 38 | | 'Objects' 39 | | 'Input Objects' 40 | | 'Unions' 41 | | 'Interfaces'; 42 | -------------------------------------------------------------------------------- /packages/react/src/schema-documentation/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { sortTypes } from './sort-types'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-view/index.tsx: -------------------------------------------------------------------------------- 1 | export { SchemaView } from './schema-view'; 2 | -------------------------------------------------------------------------------- /packages/react/src/schema-view/schema-view.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@pathfinder-ide/style'; 2 | 3 | export const schemaViewClass = style({ 4 | height: '100%', 5 | width: '100%', 6 | }); 7 | 8 | export const schemaViewInnerClass = style({ 9 | height: '100%', 10 | width: '100%', 11 | paddingTop: 12, 12 | paddingBottom: 12, 13 | }); 14 | -------------------------------------------------------------------------------- /packages/react/src/schema-view/schema-view.stories.tsx: -------------------------------------------------------------------------------- 1 | import { printSchema } from 'graphql'; 2 | import { SchemaView } from './schema-view'; 3 | import { testSchema } from '@pathfinder-ide/stores/src/schema-store/test-schema'; 4 | import { useEffect, useState } from 'react'; 5 | 6 | export const WithSchema = () => { 7 | return ; 8 | }; 9 | 10 | export const WithDelayedSchema = () => { 11 | const [schema, setSchema] = useState(null); 12 | useEffect(() => { 13 | setTimeout(() => { 14 | setSchema(printSchema(testSchema)); 15 | }, 2000); 16 | }); 17 | 18 | return ; 19 | }; 20 | 21 | export const WithoutSchema = () => { 22 | return ; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/react/src/scout/index.ts: -------------------------------------------------------------------------------- 1 | export { Scout } from './scout'; 2 | -------------------------------------------------------------------------------- /packages/react/src/scout/scout.css.ts: -------------------------------------------------------------------------------- 1 | import { contract, style } from '@pathfinder-ide/style'; 2 | 3 | export const scoutClass = style({ 4 | height: '100%', 5 | width: '100%', 6 | display: 'flex', 7 | backgroundColor: contract.color.neutral[1], 8 | fontFamily: contract.fonts.body, 9 | color: contract.color.neutral[12], 10 | }); 11 | 12 | export const scoutEditorWrapClass = style({ 13 | height: '100%', 14 | width: '100%', 15 | display: 'flex', 16 | flexDirection: 'column', 17 | }); 18 | -------------------------------------------------------------------------------- /packages/react/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { ThemeOptions } from '@pathfinder-ide/stores'; 2 | import { GraphQLSchema } from 'graphql'; 3 | 4 | export type SharedComponentProps = { 5 | schema?: GraphQLSchema; 6 | themeOptions?: Partial; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@pathfinder-ide/tsconfig/react.json", 3 | "compilerOptions": { 4 | "types": ["@testing-library/jest-dom", "vite/client", "vitest/globals"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/react/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | interface ImportMetaEnv { 4 | readonly DEV: boolean; 5 | } 6 | 7 | interface ImportMeta { 8 | readonly env: ImportMetaEnv; 9 | 10 | readonly __IS_LITE_MODE_?: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /packages/react/vite.lite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { defineConfig, mergeConfig } from 'vitest/config'; 4 | import defaultConfig from './vite.config'; 5 | 6 | const overrideConfig = defineConfig({ 7 | define: { 8 | 'import.meta.__IS_LITE_MODE_': 'true', 9 | }, 10 | build: { 11 | outDir: 'lite-dist', 12 | rollupOptions: { 13 | external: [/^monaco-editor(\/.*)?/, /^monaco-graphql(\/.*)?/], 14 | }, 15 | }, 16 | }); 17 | 18 | export default mergeConfig(defaultConfig, overrideConfig); 19 | -------------------------------------------------------------------------------- /packages/react/vitest.setup.ts: -------------------------------------------------------------------------------- 1 | import 'fake-indexeddb/auto'; 2 | import '@testing-library/jest-dom/vitest'; 3 | 4 | import { afterEach } from 'vitest'; 5 | import { cleanup } from '@testing-library/react'; 6 | 7 | // runs a cleanup after each test case (e.g. clearing jsdom) 8 | afterEach(() => { 9 | cleanup(); 10 | }); 11 | 12 | // mocks 13 | import './__mocks__/monaco-editor/canvas'; 14 | import './__mocks__/monaco-editor/get-selection'; 15 | import './__mocks__/monaco-editor/match-media'; 16 | import './__mocks__/monaco-editor/query-command-supported'; 17 | import './__mocks__/monaco-editor/resize-observer'; 18 | import './__mocks__/monaco-editor/worker'; 19 | 20 | vi.mock('zustand'); 21 | -------------------------------------------------------------------------------- /packages/react/workers/build-workers.js: -------------------------------------------------------------------------------- 1 | import * as esbuild from 'esbuild'; 2 | 3 | esbuild.build({ 4 | bundle: true, 5 | entryNames: '[name].bundle', 6 | entryPoints: { 7 | 'editor.worker': 'monaco-editor/esm/vs/editor/editor.worker.js', 8 | 'json.worker': 'monaco-editor/esm/vs/language/json/json.worker.js', 9 | 'graphql.worker': 'monaco-graphql/esm/graphql.worker.js', 10 | }, 11 | format: 'esm', 12 | minify: false, 13 | outdir: './workers', 14 | }); 15 | -------------------------------------------------------------------------------- /packages/shared/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@pathfinder-ide/eslint-config"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pathfinder-ide/shared", 3 | "private": true, 4 | "version": "0.0.1", 5 | "main": "./src/index.ts", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "types": "tsc --noEmit" 9 | }, 10 | "devDependencies": { 11 | "@paralleldrive/cuid2": "^2.2.2", 12 | "@pathfinder-ide/eslint-config": "workspace:*", 13 | "@pathfinder-ide/tsconfig": "workspace:*", 14 | "zustand": "4.4.7" 15 | }, 16 | "peerDependencies": { 17 | "graphql": "16.9.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/shared/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const DOCUMENT_EDITOR_ID = 'pathfinder-document-editor'; 2 | export const DOCUMENT_EDITOR_DEFAULT_VALUE = ``; 3 | export const DOCUMENT_MODEL_NAME = 'pathfinder-document-model'; 4 | 5 | export const RESPONSE_EDITOR_ID = 'pathfinder-response-editor'; 6 | export const RESPONSE_EDITOR_DEFAULT_VALUE = ``; 7 | export const RESPONSE_MODEL_NAME = 'pathfinder-response-model'; 8 | 9 | export const VARIABLES_EDITOR_ID = 'pathfinder-variables-editor'; 10 | export const VARIABLES_EDITOR_DEFAULT_VALUE = `{ 11 | 12 | }`; 13 | export const VARIABLES_MODEL_NAME = 'pathfinder-variables-model'; 14 | 15 | export const STORAGE_NAME_SESSION = 'pathfinder-storage-session'; 16 | 17 | export const INACTIVE_DEFINITION_CLASSNAME = 'inactive-definition'; 18 | -------------------------------------------------------------------------------- /packages/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | 3 | export * from './utils'; 4 | 5 | export type { AvailableThemes } from './types'; 6 | -------------------------------------------------------------------------------- /packages/shared/src/types.ts: -------------------------------------------------------------------------------- 1 | export type AvailableThemes = 'dark' | 'light'; 2 | -------------------------------------------------------------------------------- /packages/shared/src/utils/graphql/index.ts: -------------------------------------------------------------------------------- 1 | export { unwrapType } from './unwrap-type'; 2 | -------------------------------------------------------------------------------- /packages/shared/src/utils/graphql/unwrap-type.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLNamedType, GraphQLType, isWrappingType } from 'graphql'; 2 | 3 | export const unwrapType = (type: GraphQLType): GraphQLNamedType => { 4 | let unwrappedType = type; 5 | while (isWrappingType(unwrappedType)) { 6 | unwrappedType = unwrappedType.ofType; 7 | } 8 | return unwrappedType; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/shared/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { generateCuid } from './misc/generate-cuid'; 2 | 3 | export { unwrapType } from './graphql'; 4 | 5 | export { createZustandSelectors } from './zustand'; 6 | -------------------------------------------------------------------------------- /packages/shared/src/utils/misc/generate-cuid.ts: -------------------------------------------------------------------------------- 1 | import { init } from '@paralleldrive/cuid2'; 2 | 3 | export const generateCuid = ({ length = 10 }: { length?: number }) => { 4 | return init({ length })(); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/shared/src/utils/zustand/create-zustand-selectors.ts: -------------------------------------------------------------------------------- 1 | import { StoreApi, useStore as zustandStore } from 'zustand'; 2 | 3 | // ? https://docs.pmnd.rs/zustand/guides/auto-generating-selectors#vanilla-store 4 | 5 | type WithSelectors = S extends { getState: () => infer T } 6 | ? S & { use: { [K in keyof T]: () => T[K] } } 7 | : never; 8 | 9 | export const createZustandSelectors = >(_store: S) => { 10 | const store = _store as WithSelectors; 11 | store.use = {}; 12 | for (const k of Object.keys(store.getState())) { 13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 14 | (store.use as any)[k] = () => zustandStore(_store, (s) => s[k as keyof typeof s]); 15 | } 16 | 17 | return store; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/shared/src/utils/zustand/index.ts: -------------------------------------------------------------------------------- 1 | export { createZustandSelectors } from './create-zustand-selectors'; 2 | -------------------------------------------------------------------------------- /packages/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@pathfinder-ide/tsconfig/base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/stores/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@pathfinder-ide/eslint-config"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/stores/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pathfinder-ide/stores", 3 | "version": "0.0.1", 4 | "private": true, 5 | "main": "./src/index.ts", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "types": "tsc --noEmit" 9 | }, 10 | "dependencies": { 11 | "@pathfinder-ide/shared": "workspace:*", 12 | "@pathfinder-ide/style": "workspace:*", 13 | "graphql-sse": "^2.3.0", 14 | "idb-keyval": "6.2.1", 15 | "lodash.merge": "^4.6.2", 16 | "lodash.update": "^4.10.2", 17 | "monaco-editor": "0.40.0", 18 | "monaco-graphql": "1.3.0", 19 | "zustand": "4.4.7" 20 | }, 21 | "devDependencies": { 22 | "@pathfinder-ide/eslint-config": "workspace:*", 23 | "@pathfinder-ide/tsconfig": "workspace:*", 24 | "@types/lodash.merge": "^4.6.7", 25 | "@types/lodash.update": "^4.10.7" 26 | }, 27 | "peerDependencies": { 28 | "graphql": "16.9.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/actions/get-parsed-document.ts: -------------------------------------------------------------------------------- 1 | import { DOCUMENT_EDITOR_ID } from '@pathfinder-ide/shared'; 2 | import { getMonacoEditor } from '../../monaco-editor-store'; 3 | import { parseDocument } from '../utils'; 4 | 5 | export const getParsedDocument = () => { 6 | const documentEditor = getMonacoEditor({ editorId: DOCUMENT_EDITOR_ID }); 7 | 8 | const model = documentEditor?.getModel(); 9 | 10 | if (model) { 11 | const modelValue = model?.getValue(); 12 | 13 | const parsedDocument = parseDocument({ documentString: modelValue }); 14 | if (!(parsedDocument instanceof Error)) { 15 | return parsedDocument; 16 | } else return null; 17 | } 18 | return null; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { getParsedDocument } from './get-parsed-document'; 2 | 3 | export { handleActiveDefinition } from './handle-active-definition'; 4 | 5 | export { handleInactiveDefinition } from './handle-inactive-definition'; 6 | 7 | export { isOperationNameChanging } from './is-operation-name-changing'; 8 | 9 | export { resetDocumentState } from './reset-document-state'; 10 | 11 | export { setActiveDocumentEntry } from './set-active-document-entry'; 12 | 13 | export { setDocumentNotifications } from './set-document-notifications'; 14 | 15 | export { setDocumentState } from './set-document-state'; 16 | 17 | export { updateDocumentEntryOperationName } from './update-document-entry-operation-name'; 18 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/actions/is-operation-name-changing.ts: -------------------------------------------------------------------------------- 1 | import { OperationDefinitionNode } from 'graphql'; 2 | 3 | import type { GraphQLDocumentStoreActions } from '../graphql-document-store.types'; 4 | 5 | export const isOperationNameChanging: GraphQLDocumentStoreActions['isOperationNameChanging'] = 6 | ({ definition, definitions }) => { 7 | const foundEntryAtLocation = definitions.find( 8 | (d) => d.loc?.start === definition.loc?.start, 9 | ); 10 | 11 | if (foundEntryAtLocation) { 12 | const stringifiedFoundEntry = JSON.stringify({ 13 | start: (foundEntryAtLocation as OperationDefinitionNode).name?.loc?.start, 14 | end: (foundEntryAtLocation as OperationDefinitionNode).name?.loc?.end, 15 | }); 16 | const stringifiedDefinition = JSON.stringify({ 17 | start: definition.name?.loc?.start, 18 | end: definition.name?.loc?.end, 19 | }); 20 | 21 | if (stringifiedFoundEntry === stringifiedDefinition) { 22 | return false; 23 | } 24 | return true; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/actions/reset-document-state.ts: -------------------------------------------------------------------------------- 1 | import { INITIAL_GRAPHQL_DOCUMENT_STATE } from '../state'; 2 | import { graphQLDocumentStore } from '../graphql-document-store'; 3 | 4 | export const resetDocumentState = () => { 5 | graphQLDocumentStore.setState({ ...INITIAL_GRAPHQL_DOCUMENT_STATE }); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/actions/set-active-document-entry.ts: -------------------------------------------------------------------------------- 1 | import { graphQLDocumentStore } from '../graphql-document-store'; 2 | 3 | import type { GraphQLDocumentStoreActions } from '../graphql-document-store.types'; 4 | 5 | export const setActiveDocumentEntry: GraphQLDocumentStoreActions['setActiveDocumentEntry'] = 6 | ({ operationEntry }) => { 7 | graphQLDocumentStore.setState({ activeDocumentEntry: operationEntry }); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/graphql-document-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import { graphQLDocumentState } from './state'; 4 | 5 | import { GraphQLDocumentStoreState } from './graphql-document-store.types'; 6 | 7 | export const graphQLDocumentStore = createStore()(() => ({ 8 | ...graphQLDocumentState, 9 | })); 10 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/index.ts: -------------------------------------------------------------------------------- 1 | export { graphQLDocumentStore } from './graphql-document-store'; 2 | 3 | export type { 4 | DocumentNotificationType, 5 | OperationEntry, 6 | } from './graphql-document-store.types'; 7 | 8 | export { getParsedDocument, setDocumentState } from './actions'; 9 | 10 | export { useGraphQLDocumentStore } from './use-graphql-document-store'; 11 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/state.ts: -------------------------------------------------------------------------------- 1 | import type { GraphQLDocumentStoreState } from './graphql-document-store.types'; 2 | 3 | export const INITIAL_GRAPHQL_DOCUMENT_STATE: GraphQLDocumentStoreState = { 4 | activeDocumentEntry: null, 5 | documentNotifications: [], 6 | isParseable: true, 7 | }; 8 | 9 | export const graphQLDocumentState = { 10 | ...INITIAL_GRAPHQL_DOCUMENT_STATE, 11 | }; 12 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/use-graphql-document-store.ts: -------------------------------------------------------------------------------- 1 | import { graphQLDocumentStore } from './graphql-document-store'; 2 | 3 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 4 | 5 | export const useGraphQLDocumentStore = createZustandSelectors(graphQLDocumentStore); 6 | -------------------------------------------------------------------------------- /packages/stores/src/graphql-document-store/utils.ts: -------------------------------------------------------------------------------- 1 | import { parse } from 'graphql'; 2 | 3 | import type { DefinitionNode, DocumentNode, Location } from 'graphql'; 4 | 5 | import { Range } from 'monaco-graphql/esm/monaco-editor'; 6 | 7 | export const getLocationAndRangeForDefinition = ({ 8 | definition, 9 | }: { 10 | definition: DefinitionNode; 11 | }): { range: Range; startLine: number; endLine: number } => { 12 | const location = definition.loc as Location; 13 | const startLine = location.startToken.line; 14 | const endLine = location.endToken.line; 15 | const range = new Range( 16 | startLine, 17 | location.startToken.column, 18 | endLine, 19 | location.endToken.column + 1, 20 | ); 21 | return { range, startLine, endLine }; 22 | }; 23 | 24 | export const parseDocument = ({ 25 | documentString, 26 | }: { 27 | documentString: string; 28 | }): DocumentNode | null | Error => { 29 | try { 30 | if (!documentString.trim()) { 31 | return null; 32 | } 33 | 34 | return parse(documentString); 35 | } catch (err) { 36 | return err as Error; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/actions/get-monaco-editor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DOCUMENT_EDITOR_ID, 3 | RESPONSE_EDITOR_ID, 4 | VARIABLES_EDITOR_ID, 5 | } from '@pathfinder-ide/shared'; 6 | 7 | import { monacoEditorStore } from '../monaco-editor-store'; 8 | 9 | import { 10 | MonacoEditorIStandaloneCodeEditor, 11 | MonacoEditorStoreActions, 12 | } from '../monaco-editor-store.types'; 13 | 14 | export const getMonacoEditor: MonacoEditorStoreActions['getMonacoEditor'] = ({ 15 | editorId, 16 | }) => { 17 | let editor: MonacoEditorIStandaloneCodeEditor | null = null; 18 | 19 | if ( 20 | editorId === DOCUMENT_EDITOR_ID || 21 | editorId === RESPONSE_EDITOR_ID || 22 | editorId === VARIABLES_EDITOR_ID 23 | ) { 24 | editor = monacoEditorStore.getState().managedEditors[editorId]; 25 | } else { 26 | editor = monacoEditorStore.getState().unmanagedEditors[editorId]; 27 | } 28 | return editor; 29 | }; 30 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { createMonacoEditor } from './create-monaco-editor'; 2 | 3 | export { disposeMonacoEditor } from './dispose-monaco-editor'; 4 | 5 | export { getMonacoEditor } from './get-monaco-editor'; 6 | 7 | export { initializeMonacoEditor } from './initialize-monaco-editor'; 8 | 9 | export { pushMonacoEditorEdit } from './push-monaco-editor-edit'; 10 | 11 | export { runExecuteOperation } from './run-execute-operation'; 12 | 13 | export { setMonacoEditorTheme } from './set-monaco-editor-theme'; 14 | 15 | export { setMonacoImporter } from './monaco-import'; 16 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/actions/initialize-monaco-editor.ts: -------------------------------------------------------------------------------- 1 | import { themeStore } from '../../theme-store'; 2 | import { editorTheme } from '../helpers/editor-theme'; 3 | import { monacoEditorStore } from '../monaco-editor-store'; 4 | import { MonacoEditorStoreActions } from '../monaco-editor-store.types'; 5 | import { importMonaco } from './monaco-import'; 6 | import { setMonacoEditorTheme } from './set-monaco-editor-theme'; 7 | 8 | export const initializeMonacoEditor: MonacoEditorStoreActions['initializeMonacoEditor'] = 9 | async () => { 10 | const { editor } = await importMonaco(); 11 | 12 | const activeTheme = themeStore.getState().activeTheme; 13 | 14 | // define the themes that we're making available to monaco editor 15 | editor.defineTheme('pathfinder-editor-dark', editorTheme({ variant: 'dark' })); 16 | editor.defineTheme('pathfinder-editor-light', editorTheme({ variant: 'light' })); 17 | 18 | if (activeTheme) { 19 | setMonacoEditorTheme({ theme: activeTheme }); 20 | } 21 | 22 | monacoEditorStore.setState({ 23 | isInitialized: true, 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/actions/run-execute-operation.ts: -------------------------------------------------------------------------------- 1 | import { KeyCode, KeyMod } from 'monaco-graphql/esm/monaco-editor'; 2 | 3 | import { executeOperation } from '../../schema-store'; 4 | 5 | import type { MonacoEditorIActionDescriptor } from '../monaco-editor-store.types'; 6 | 7 | export const runExecuteOperation: MonacoEditorIActionDescriptor = { 8 | id: 'run-execute-operation', 9 | label: 'Execute Operation', 10 | keybindings: [KeyMod.CtrlCmd | KeyCode.Enter], 11 | run: executeOperation, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/actions/set-monaco-editor-theme.ts: -------------------------------------------------------------------------------- 1 | import { monacoEditorStore } from '../monaco-editor-store'; 2 | import { MonacoEditorStoreActions } from '../monaco-editor-store.types'; 3 | import { importMonaco } from './monaco-import'; 4 | 5 | export const setMonacoEditorTheme: MonacoEditorStoreActions['setMonacoEditorTheme'] = 6 | async ({ theme }) => { 7 | const { editor } = await importMonaco(); 8 | const isInitialized = monacoEditorStore.getState().isInitialized; 9 | 10 | if (!isInitialized) { 11 | // bail if we haven't initialized monaco editor 12 | // we'll get here when the app loads due to calling setTheme in initializeTheme, and setTheme calls this function 13 | return; 14 | } 15 | 16 | editor.setTheme(`pathfinder-editor-${theme}`); 17 | 18 | return monacoEditorStore.setState({ isReady: true }); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | createMonacoEditor, 3 | disposeMonacoEditor, 4 | getMonacoEditor, 5 | pushMonacoEditorEdit, 6 | runExecuteOperation, 7 | setMonacoEditorTheme, 8 | setMonacoImporter, 9 | } from './actions'; 10 | 11 | export { monacoEditorStore } from './monaco-editor-store'; 12 | 13 | export { useMonacoEditorStore } from './use-monaco-editor-store'; 14 | 15 | export type { 16 | AvailableEditors, 17 | EditorEdit, 18 | MonacoIPosition, 19 | MonacoIRange, 20 | MonacoEditorITextModel, 21 | MonacoEditorIActionDescriptor, 22 | } from './monaco-editor-store.types'; 23 | 24 | export { INITIAL_MONACO_EDITOR_STORE_STATE } from './state'; 25 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/monaco-editor-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import type { MonacoEditorStoreState } from './monaco-editor-store.types'; 4 | 5 | import { monacoEditorStoreState } from './state'; 6 | 7 | export const monacoEditorStore = createStore()(() => ({ 8 | ...monacoEditorStoreState, 9 | })); 10 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/state.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DOCUMENT_EDITOR_ID, 3 | RESPONSE_EDITOR_ID, 4 | VARIABLES_EDITOR_ID, 5 | } from '@pathfinder-ide/shared'; 6 | 7 | import type { MonacoEditorStoreState } from './monaco-editor-store.types'; 8 | 9 | export const INITIAL_MONACO_EDITOR_STORE_STATE: MonacoEditorStoreState = { 10 | managedEditors: { 11 | [DOCUMENT_EDITOR_ID]: null, 12 | [RESPONSE_EDITOR_ID]: null, 13 | [VARIABLES_EDITOR_ID]: null, 14 | }, 15 | unmanagedEditors: {}, 16 | isInitialized: false, 17 | isReady: false, 18 | }; 19 | 20 | export const monacoEditorStoreState = { 21 | ...INITIAL_MONACO_EDITOR_STORE_STATE, 22 | }; 23 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-editor-store/use-monaco-editor-store.ts: -------------------------------------------------------------------------------- 1 | import { monacoEditorStore } from './monaco-editor-store'; 2 | 3 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 4 | 5 | export const useMonacoEditorStore = createZustandSelectors(monacoEditorStore); 6 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-graphql-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { initMonacoGraphQLAPI } from './init-monaco-graphql-api'; 2 | 3 | export { setMonacoGraphQLSchema } from './set-monaco-graphql-schema'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-graphql-store/actions/init-monaco-graphql-api.ts: -------------------------------------------------------------------------------- 1 | import { initializeMode } from 'monaco-graphql/esm/initializeMode'; 2 | 3 | import { monacoGraphQLStore } from '../monaco-graphql-store'; 4 | import type { MonacoGraphQLStoreActions } from '../monaco-graphql-store.types'; 5 | 6 | export const initMonacoGraphQLAPI: MonacoGraphQLStoreActions['initMonacoGraphQLAPI'] = 7 | async () => { 8 | monacoGraphQLStore.setState({ 9 | monacoGraphQLAPI: initializeMode({ 10 | formattingOptions: { 11 | prettierConfig: { 12 | printWidth: 40, 13 | }, 14 | }, 15 | }), 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-graphql-store/actions/set-monaco-graphql-schema.ts: -------------------------------------------------------------------------------- 1 | import { initMonacoGraphQLAPI } from './init-monaco-graphql-api'; 2 | 3 | import { monacoGraphQLStore } from '../monaco-graphql-store'; 4 | 5 | import type { MonacoGraphQLStoreActions } from '../monaco-graphql-store.types'; 6 | 7 | export const setMonacoGraphQLSchema: MonacoGraphQLStoreActions['setMonacoGraphQLSchema'] = 8 | async ({ schema }) => { 9 | if (!monacoGraphQLStore.getState().monacoGraphQLAPI) { 10 | await initMonacoGraphQLAPI(); 11 | } 12 | monacoGraphQLStore.getState().monacoGraphQLAPI?.setSchemaConfig([ 13 | { 14 | schema, 15 | uri: `schema.graphql`, 16 | }, 17 | ]); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-graphql-store/index.ts: -------------------------------------------------------------------------------- 1 | export { monacoGraphQLStore } from './monaco-graphql-store'; 2 | 3 | export { setMonacoGraphQLSchema } from './actions'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-graphql-store/monaco-graphql-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import { MonacoGraphQLStoreState } from './monaco-graphql-store.types'; 4 | 5 | export const INITIAL_MONACO_GRAPHQL_STORE_STATE = { 6 | monacoGraphQLAPI: null, 7 | }; 8 | 9 | export const monacoGraphQLStore = createStore()(() => ({ 10 | ...INITIAL_MONACO_GRAPHQL_STORE_STATE, 11 | })); 12 | -------------------------------------------------------------------------------- /packages/stores/src/monaco-graphql-store/monaco-graphql-store.types.ts: -------------------------------------------------------------------------------- 1 | import type { GraphQLSchema } from 'graphql'; 2 | import type { MonacoGraphQLAPI } from 'monaco-graphql'; 3 | 4 | export type MonacoGraphQLStoreState = { 5 | monacoGraphQLAPI: MonacoGraphQLAPI | null; 6 | }; 7 | 8 | export type MonacoGraphQLStoreActions = { 9 | initMonacoGraphQLAPI: () => Promise; 10 | setMonacoGraphQLSchema: ({ schema }: { schema: GraphQLSchema }) => Promise; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/actions/http-fetcher.ts: -------------------------------------------------------------------------------- 1 | import { getEnabledHTTPHeaderValues } from '../../session-store'; 2 | import type { SchemaStoreActions } from '../schema-store.types'; 3 | import { useSchemaStore } from '../use-schema-store'; 4 | 5 | export const httpFetcher: SchemaStoreActions['httpFetcher'] = async ({ 6 | graphQLParams, 7 | fetchOptions, 8 | }) => { 9 | const body = JSON.stringify(graphQLParams); 10 | 11 | const fetchResponse = await fetch(fetchOptions.endpoint, { 12 | method: 'POST', 13 | headers: fetchOptions.headers 14 | ? getEnabledHTTPHeaderValues({ headers: fetchOptions.headers }) 15 | : undefined, 16 | credentials: 'same-origin', 17 | body, 18 | }).catch((error) => { 19 | console.warn('Error during fetch attempt:', { 20 | error, 21 | }); 22 | }); 23 | 24 | if (fetchResponse && !fetchResponse.ok) { 25 | useSchemaStore.setState({ 26 | isIntrospecting: false, 27 | introspectionErrors: ['Response not OK. Do you need to add headers?'], 28 | }); 29 | } else { 30 | return fetchResponse; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { doIntrospection } from './do-introspection'; 2 | 3 | export { doSchemaPolling } from './do-schema-polling'; 4 | 5 | export { executeOperation } from './execute-operation'; 6 | 7 | export { httpFetcher } from './http-fetcher'; 8 | 9 | export { loadSchema } from './load-schema'; 10 | 11 | export { resetSchemaPolling } from './reset-schema-polling'; 12 | 13 | export { setSchemaPollingTimer } from './set-schema-polling-timer'; 14 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/actions/reset-schema-polling.ts: -------------------------------------------------------------------------------- 1 | import { schemaStore } from '../schema-store'; 2 | 3 | import type { SchemaStoreActions } from '../schema-store.types'; 4 | import { setSchemaPollingTimer } from './set-schema-polling-timer'; 5 | 6 | export const resetSchemaPolling: SchemaStoreActions['resetSchemaPolling'] = () => { 7 | // do we have an existing timer? 8 | const timer = schemaStore.getState().polling.timer; 9 | 10 | // if so, clear the interval and remove it from state 11 | if (timer) { 12 | clearTimeout(timer); 13 | return setSchemaPollingTimer({ timer: null }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/actions/set-schema-polling-timer.ts: -------------------------------------------------------------------------------- 1 | import { schemaStore } from '../schema-store'; 2 | 3 | import type { SchemaStoreActions } from '../schema-store.types'; 4 | 5 | export const setSchemaPollingTimer: SchemaStoreActions['setSchemaPollingTimer'] = ({ 6 | timer, 7 | }) => { 8 | const polling = schemaStore.getState().polling; 9 | 10 | schemaStore.setState({ 11 | polling: { 12 | ...polling, 13 | timer, 14 | }, 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/helpers/merge-results.ts: -------------------------------------------------------------------------------- 1 | import update from 'lodash.update'; 2 | 3 | import merge from 'lodash.merge'; 4 | 5 | import { type ExecutionResult } from 'graphql-sse'; 6 | 7 | export const mergeResults = ( 8 | result: ExecutionResult, unknown>, 9 | lastResult?: ExecutionResult, unknown>, 10 | ) => { 11 | // bit of weird typing here, result should probably be returned as ExecutionResult | ExecutionPatchResult from graphql-sse 12 | // but that isn't the case 13 | if (!('path' in result) || lastResult === undefined) { 14 | return result; 15 | } 16 | 17 | const path = result.path as string[]; 18 | 19 | const combined = update(lastResult, ['data', ...path], (value) => 20 | merge(value, result.data), 21 | ); 22 | 23 | const errors = [...(lastResult?.errors ?? []), ...(result.errors ?? [])]; 24 | 25 | return { ...combined, ...(errors.length > 0 ? { errors } : undefined) }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/helpers/using-defer.ts: -------------------------------------------------------------------------------- 1 | import { Kind, type SelectionSetNode } from 'graphql'; 2 | 3 | enum Directive { 4 | Defer = 'defer', 5 | } 6 | 7 | export const usingDefer = (set: SelectionSetNode | undefined): boolean => 8 | set?.selections.some((selection) => { 9 | // add Kind.FRAGMENT_SPREAD once we support named fragments 10 | const inlineFragment = selection.kind == Kind.INLINE_FRAGMENT; 11 | const usingDeferOnCurrentSelection = 12 | inlineFragment && 13 | (selection.directives?.some((node) => node.name.value === Directive.Defer) ?? 14 | false); 15 | const hasSelectionSet = 'selectionSet' in selection; 16 | return ( 17 | usingDeferOnCurrentSelection || 18 | (hasSelectionSet && usingDefer(selection.selectionSet)) 19 | ); 20 | }) ?? false; 21 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | executeOperation, 3 | doIntrospection, 4 | httpFetcher, 5 | loadSchema, 6 | resetSchemaPolling, 7 | } from './actions'; 8 | 9 | export type { 10 | EndpointConnectionDetails, 11 | ExecutionResponse, 12 | GraphQLOperationParams, 13 | SchemaStoreState, 14 | WatchHeaders, 15 | } from './schema-store.types'; 16 | 17 | export { schemaStore } from './schema-store'; 18 | 19 | export { useSchemaStore } from './use-schema-store'; 20 | 21 | export { INITIAL_SCHEMA_STORE_STATE } from './state'; 22 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/schema-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import { schemaStoreState } from './state'; 4 | import type { SchemaStoreState } from './schema-store.types'; 5 | 6 | export const schemaStore = createStore()(() => ({ 7 | ...schemaStoreState, 8 | })); 9 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/state.ts: -------------------------------------------------------------------------------- 1 | import type { SchemaStoreState } from './schema-store.types'; 2 | 3 | export const INITIAL_SCHEMA_STORE_STATE: SchemaStoreState = { 4 | introspectionErrors: [], 5 | isExecuting: false, 6 | isIntrospecting: false, 7 | isLoadingSchema: false, 8 | latestResponse: null, 9 | polling: { 10 | enabled: false, 11 | interval: 10000, 12 | timer: null, 13 | }, 14 | schema: null, 15 | watchHeaders: null, 16 | }; 17 | 18 | export const schemaStoreState = { 19 | ...INITIAL_SCHEMA_STORE_STATE, 20 | }; 21 | -------------------------------------------------------------------------------- /packages/stores/src/schema-store/use-schema-store.ts: -------------------------------------------------------------------------------- 1 | import { schemaStore } from './schema-store'; 2 | 3 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 4 | 5 | export const useSchemaStore = createZustandSelectors(schemaStore); 6 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/actions/get-sessions.ts: -------------------------------------------------------------------------------- 1 | import { keys } from 'idb-keyval'; 2 | 3 | import { STORAGE_NAME_SESSION } from '@pathfinder-ide/shared'; 4 | 5 | export const getSessions = () => { 6 | return keys().then((keys) => { 7 | return keys.filter((key) => { 8 | if (typeof key === 'string' && key.includes(STORAGE_NAME_SESSION)) { 9 | return true; 10 | } 11 | }); 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { getSessions } from './get-sessions'; 2 | 3 | export { initSession } from './init-session'; 4 | 5 | export { loadSession } from './load-session'; 6 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/index.ts: -------------------------------------------------------------------------------- 1 | export { getSessions, initSession, loadSession } from './actions'; 2 | 3 | export { 4 | closeEditorTab, 5 | initNewEditorTab, 6 | switchEditorTab, 7 | updateEditorTab, 8 | } from './slices/editor-tabs/actions'; 9 | 10 | export { clearHistory, deleteFromHistory } from './slices/history/actions'; 11 | 12 | export { 13 | addEmptyHeader, 14 | getEnabledHTTPHeaderValues, 15 | getEnabledHTTPHeaderValueRecord, 16 | removeHeader, 17 | updateHeader, 18 | } from './slices/http-headers/actions'; 19 | 20 | export type { HTTPHeaderValue } from './slices/http-headers/http-headers.types'; 21 | 22 | export { useSessionStore } from './use-session-store'; 23 | 24 | export { sessionStore } from './session-store'; 25 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/session-store-state.ts: -------------------------------------------------------------------------------- 1 | import type { SessionStoreBaseState } from './session-store.types'; 2 | 3 | export const sessionStoreState: SessionStoreBaseState = { 4 | endpoint: null, 5 | connectionDialogOpen: false, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/session-store.types.ts: -------------------------------------------------------------------------------- 1 | import type { EditorTabsState } from './slices/editor-tabs'; 2 | import type { HistoryState } from './slices/history'; 3 | import type { HTTPHeadersState } from './slices/http-headers'; 4 | import type { VariablesState } from './slices/variables'; 5 | 6 | export type SessionStoreBaseState = { 7 | /** 8 | * The current target GraphQL endpoint 9 | */ 10 | endpoint?: string | null; 11 | /** 12 | * A boolean indicating whether the connection dialog is open 13 | */ 14 | connectionDialogOpen: boolean; 15 | }; 16 | 17 | export type SessionStoreState = SessionStoreBaseState & 18 | EditorTabsState & 19 | HistoryState & 20 | HTTPHeadersState & 21 | VariablesState; 22 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/editor-tabs/actions/close-editor-tab.ts: -------------------------------------------------------------------------------- 1 | import { sessionStore } from '../../../session-store'; 2 | 3 | import { setEditorValues } from './set-editor-values'; 4 | 5 | import type { EditorTabsActions } from '..//editor-tabs.types'; 6 | 7 | export const closeEditorTab: EditorTabsActions['closeEditorTab'] = ({ tabId }) => { 8 | const isActiveTab = tabId === sessionStore.getState().activeTab?.tabId; 9 | 10 | const filteredTabs = sessionStore.getState().tabs.filter((tab) => tab.tabId !== tabId); 11 | 12 | if (isActiveTab) { 13 | // if we're closing the active tab, we set the first tab as the activeTab 14 | sessionStore.setState({ 15 | activeTab: filteredTabs[0], 16 | tabs: filteredTabs, 17 | }); 18 | 19 | return setEditorValues({ 20 | newDocumentEditorValue: filteredTabs[0].documentString, 21 | newResponseEditorValue: JSON.stringify( 22 | filteredTabs[0].latestResponse?.response.data, 23 | null, 24 | 2, 25 | ), 26 | }); 27 | } else { 28 | return sessionStore.setState({ 29 | tabs: filteredTabs, 30 | }); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/editor-tabs/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { closeEditorTab } from './close-editor-tab'; 2 | 3 | export { initNewEditorTab } from './init-new-editor-tab'; 4 | 5 | export { switchEditorTab } from './switch-editor-tab'; 6 | 7 | export { updateEditorTab } from './update-editor-tab'; 8 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/editor-tabs/actions/init-new-editor-tab.ts: -------------------------------------------------------------------------------- 1 | import { DOCUMENT_EDITOR_DEFAULT_VALUE, generateCuid } from '@pathfinder-ide/shared'; 2 | 3 | import { sessionStore } from '../../../session-store'; 4 | 5 | import { setEditorValues } from './set-editor-values'; 6 | 7 | import type { EditorTab, EditorTabsActions } from '../editor-tabs.types'; 8 | 9 | export const initNewEditorTab: EditorTabsActions['initNewEditorTab'] = () => { 10 | const TAB_ID = generateCuid({}); 11 | 12 | const newTab: EditorTab = { 13 | tabId: TAB_ID, 14 | tabName: 'Untitled', 15 | cursorPosition: null, 16 | documentString: DOCUMENT_EDITOR_DEFAULT_VALUE, 17 | latestResponse: null, 18 | }; 19 | 20 | sessionStore.setState({ 21 | activeTab: newTab, 22 | tabs: [...sessionStore.getState().tabs, newTab], 23 | }); 24 | 25 | return setEditorValues({ 26 | newDocumentEditorValue: newTab.documentString, 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/editor-tabs/actions/set-editor-values.ts: -------------------------------------------------------------------------------- 1 | import { DOCUMENT_EDITOR_ID, RESPONSE_EDITOR_ID } from '@pathfinder-ide/shared'; 2 | 3 | import { getMonacoEditor } from '../../../../monaco-editor-store'; 4 | 5 | export const setEditorValues = ({ 6 | newDocumentEditorValue, 7 | newResponseEditorValue, 8 | }: { 9 | newDocumentEditorValue?: string; 10 | newResponseEditorValue?: string; 11 | }): void => { 12 | if (newDocumentEditorValue !== undefined) { 13 | const documentEditor = getMonacoEditor({ editorId: DOCUMENT_EDITOR_ID }); 14 | documentEditor?.setValue(newDocumentEditorValue); 15 | } 16 | 17 | if (newResponseEditorValue !== undefined) { 18 | const responseEditor = getMonacoEditor({ editorId: RESPONSE_EDITOR_ID }); 19 | responseEditor?.setValue(newResponseEditorValue); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/editor-tabs/editor-tabs-state.ts: -------------------------------------------------------------------------------- 1 | import { DOCUMENT_EDITOR_DEFAULT_VALUE, generateCuid } from '@pathfinder-ide/shared'; 2 | 3 | import type { EditorTab, EditorTabsState } from './editor-tabs.types'; 4 | 5 | const INITIAL_EDITOR_TAB_ID = generateCuid({}); 6 | 7 | export const INITIAL_EDITOR_TAB: EditorTab = { 8 | tabId: INITIAL_EDITOR_TAB_ID, 9 | tabName: 'Untitled', 10 | cursorPosition: null, 11 | documentString: DOCUMENT_EDITOR_DEFAULT_VALUE, 12 | latestResponse: null, 13 | }; 14 | 15 | const INITIAL_EDITOR_TABS_STATE: EditorTabsState = { 16 | activeTab: INITIAL_EDITOR_TAB, 17 | tabs: [INITIAL_EDITOR_TAB], 18 | }; 19 | 20 | export const editorTabsState = { 21 | ...INITIAL_EDITOR_TABS_STATE, 22 | }; 23 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/editor-tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { editorTabsState } from './editor-tabs-state'; 2 | 3 | export type { EditorTabsActions, EditorTabsState } from './editor-tabs.types'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/history/actions/clear-history.ts: -------------------------------------------------------------------------------- 1 | import { sessionStore } from '../../../session-store'; 2 | import { HistoryActions } from '../history.types'; 3 | 4 | export const clearHistory: HistoryActions['clearHistory'] = () => { 5 | sessionStore.setState({ 6 | executions: [], 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/history/actions/delete-from-history.ts: -------------------------------------------------------------------------------- 1 | import { sessionStore } from '../../../session-store'; 2 | import { HistoryActions } from '../history.types'; 3 | 4 | export const deleteFromHistory: HistoryActions['deleteFromHistory'] = ({ timestamp }) => { 5 | const executions = sessionStore.getState().executions; 6 | 7 | const filteredExecutions = executions.filter( 8 | (execution) => execution.timestamp !== timestamp, 9 | ); 10 | 11 | return sessionStore.setState({ 12 | executions: filteredExecutions, 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/history/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { clearHistory } from './clear-history'; 2 | 3 | export { deleteFromHistory } from './delete-from-history'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/history/history-state.ts: -------------------------------------------------------------------------------- 1 | import { HistoryState } from './history.types'; 2 | 3 | const INITIAL_HISTORY_STORE_STATE: HistoryState = { 4 | executions: [], 5 | }; 6 | 7 | export const historyState = { 8 | ...INITIAL_HISTORY_STORE_STATE, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/history/history.types.ts: -------------------------------------------------------------------------------- 1 | import { ExecutionResponse } from '../../../schema-store'; 2 | 3 | export type HistoryActions = { 4 | clearHistory: () => void; 5 | deleteFromHistory: ({ timestamp }: { timestamp: Date }) => void; 6 | }; 7 | 8 | export type HistoryState = { 9 | executions: ExecutionResponse[]; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/history/index.ts: -------------------------------------------------------------------------------- 1 | export { historyState } from './history-state'; 2 | 3 | export type { HistoryState } from './history.types'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/actions/add-empty-header.ts: -------------------------------------------------------------------------------- 1 | import { generateCuid } from '@pathfinder-ide/shared'; 2 | 3 | import { sessionStore } from '../../../session-store'; 4 | 5 | import type { HTTPHeaderValue, HTTPHeadersActions } from '../http-headers.types'; 6 | 7 | const baseHeader = ({ 8 | enabled, 9 | id, 10 | }: { 11 | enabled: boolean; 12 | id: string; 13 | }): HTTPHeaderValue => ({ 14 | id, 15 | enabled, 16 | key: '', 17 | value: '', 18 | }); 19 | 20 | export const addEmptyHeader: HTTPHeadersActions['addEmptyHeader'] = ({ 21 | enabled = false, 22 | }) => { 23 | sessionStore.setState({ 24 | headers: [ 25 | ...sessionStore.getState().headers, 26 | baseHeader({ enabled, id: generateCuid({}) }), 27 | ], 28 | }); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { addEmptyHeader } from './add-empty-header'; 2 | 3 | export { 4 | getEnabledHTTPHeaderValues, 5 | getEnabledHTTPHeaderValueRecord, 6 | } from './get-enabled-http-header-values'; 7 | 8 | export { removeHeader } from './remove-header'; 9 | 10 | export { updateHeader } from './update-header'; 11 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/actions/remove-header.ts: -------------------------------------------------------------------------------- 1 | import { sessionStore } from '../../../session-store'; 2 | 3 | import type { HTTPHeadersActions } from '../http-headers.types'; 4 | 5 | export const removeHeader: HTTPHeadersActions['removeHeader'] = ({ id }) => { 6 | const headers = sessionStore.getState().headers; 7 | sessionStore.setState({ 8 | headers: headers.filter((header) => header.id !== id), 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/actions/update-header.ts: -------------------------------------------------------------------------------- 1 | import { sessionStore } from '../../../session-store'; 2 | 3 | import type { HTTPHeadersActions } from '../http-headers.types'; 4 | 5 | export const updateHeader: HTTPHeadersActions['updateHeader'] = ({ id, payload }) => { 6 | const update = 7 | 'keyOrValue' in payload 8 | ? { [payload.keyOrValue]: payload.value } 9 | : { enabled: payload.enabled }; 10 | 11 | const headers = [...sessionStore.getState().headers]; 12 | const existingHeaderIndex = headers.findIndex((header) => header.id === id); 13 | 14 | headers[existingHeaderIndex] = { 15 | ...headers[existingHeaderIndex], 16 | ...update, 17 | }; 18 | 19 | return sessionStore.setState({ headers }); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/http-headers-state.ts: -------------------------------------------------------------------------------- 1 | import { generateCuid } from '@pathfinder-ide/shared'; 2 | import { HTTPHeadersState } from './http-headers.types'; 3 | 4 | export const INITIAL_HTTP_HEADERS_STATE: HTTPHeadersState = { 5 | headers: [ 6 | { 7 | id: generateCuid({}), 8 | enabled: true, 9 | key: 'Content-Type', 10 | value: 'application/json', 11 | }, 12 | ], 13 | }; 14 | 15 | export const httpHeadersState = { 16 | ...INITIAL_HTTP_HEADERS_STATE, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/http-headers.types.ts: -------------------------------------------------------------------------------- 1 | export type HTTPHeaderValue = { 2 | id: string; 3 | enabled: boolean; 4 | key: string; 5 | value: string; 6 | }; 7 | 8 | export type UpdateHeaderKeyOrValue = { 9 | keyOrValue: 'key' | 'value'; 10 | value: string; 11 | }; 12 | 13 | export type UpdateHeaderStatus = { 14 | enabled: boolean; 15 | }; 16 | 17 | export type HTTPHeadersActions = { 18 | addEmptyHeader: ({ enabled }: { enabled?: boolean }) => void; 19 | getEnabledHTTPHeaderValues: ({ 20 | headers, 21 | }: { 22 | headers: HTTPHeaderValue[]; 23 | }) => HeadersInit; 24 | getEnabledHTTPHeaderValueRecord: ({ 25 | headers, 26 | }: { 27 | headers: HTTPHeaderValue[]; 28 | }) => Record; 29 | removeHeader: ({ id }: { id: string }) => void; 30 | updateHeader: ({ 31 | id, 32 | payload, 33 | }: { 34 | id: string; 35 | payload: UpdateHeaderKeyOrValue | UpdateHeaderStatus; 36 | }) => void; 37 | }; 38 | 39 | export type HTTPHeadersState = { 40 | headers: HTTPHeaderValue[]; 41 | }; 42 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/http-headers/index.ts: -------------------------------------------------------------------------------- 1 | export { httpHeadersState } from './http-headers-state'; 2 | 3 | export type { HTTPHeadersState, HTTPHeaderValue } from './http-headers.types'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/variables/index.ts: -------------------------------------------------------------------------------- 1 | export { variablesState } from './variables-state'; 2 | 3 | export type { VariablesState } from './variables.types'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/variables/variables-state.ts: -------------------------------------------------------------------------------- 1 | import { VARIABLES_EDITOR_DEFAULT_VALUE } from '@pathfinder-ide/shared'; 2 | 3 | import type { VariablesState } from './variables.types'; 4 | 5 | export const INITIAL_VARIABLES_STATE: VariablesState = { 6 | variablesString: VARIABLES_EDITOR_DEFAULT_VALUE, 7 | }; 8 | 9 | export const variablesState = { 10 | ...INITIAL_VARIABLES_STATE, 11 | }; 12 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/slices/variables/variables.types.ts: -------------------------------------------------------------------------------- 1 | export type VariablesState = { 2 | /** 3 | * The full string value of the variables editor, used during rehydration 4 | */ 5 | variablesString: string; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/stores/src/session-store/use-session-store.ts: -------------------------------------------------------------------------------- 1 | import { sessionStore } from './session-store'; 2 | 3 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 4 | 5 | export const useSessionStore = createZustandSelectors(sessionStore); 6 | -------------------------------------------------------------------------------- /packages/stores/src/storage.ts: -------------------------------------------------------------------------------- 1 | import { del, get, set } from 'idb-keyval'; 2 | import { PersistStorage } from 'zustand/middleware'; 3 | 4 | export const storage = (): PersistStorage => ({ 5 | getItem: async (name) => { 6 | return (await get(name)) || null; 7 | }, 8 | setItem: async (name, value) => { 9 | return await set(name, structuredClone(value)); 10 | }, 11 | removeItem: async (name) => { 12 | await del(name); 13 | }, 14 | }); 15 | 16 | export const getNamespacedStorageName = ({ 17 | endpoint, 18 | storageName, 19 | }: { 20 | endpoint: string; 21 | storageName: string; 22 | }) => { 23 | return `${storageName}-${endpoint}`; 24 | }; 25 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { initializeTheme } from './initialize-theme'; 2 | 3 | export { setTheme } from './set-theme'; 4 | 5 | export { setThemeOverrides } from './set-theme-overrides'; 6 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/actions/initialize-theme.ts: -------------------------------------------------------------------------------- 1 | import { setTheme } from './set-theme'; 2 | import { setThemeOverrides } from './set-theme-overrides'; 3 | import { ThemeOptions } from '../theme-store.types'; 4 | import { themeStore } from '../theme-store'; 5 | 6 | export const initializeTheme = ({ 7 | options = { defaultTheme: 'system' }, 8 | }: { 9 | options?: ThemeOptions; 10 | }) => { 11 | const isThemeInitialized = themeStore.getState().isInitialized; 12 | 13 | if (!isThemeInitialized) { 14 | // if we receive theme overrides, set them to state here 15 | if (options.overrides) { 16 | setThemeOverrides({ overrides: options.overrides }); 17 | } 18 | 19 | return setTheme({ theme: options.defaultTheme ?? 'system' }); 20 | } 21 | 22 | return; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/actions/listen-for-prefers-color-scheme-change.ts: -------------------------------------------------------------------------------- 1 | import { setTheme } from './set-theme'; 2 | 3 | let remove: (() => void) | null = null; 4 | 5 | export const listenForPrefersColorSchemeChange = () => { 6 | if (remove != null) { 7 | remove(); 8 | } 9 | const media = matchMedia('(prefers-color-scheme:dark)'); 10 | 11 | if (media.matches) { 12 | setTheme({ theme: 'dark' }); 13 | } else { 14 | setTheme({ theme: 'light' }); 15 | } 16 | 17 | media.addEventListener('change', listenForPrefersColorSchemeChange); 18 | 19 | remove = () => { 20 | media.removeEventListener('change', listenForPrefersColorSchemeChange); 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/actions/set-theme-overrides.ts: -------------------------------------------------------------------------------- 1 | import { ThemeContractOverrides } from '@pathfinder-ide/style'; 2 | import { themeStore } from '../theme-store'; 3 | 4 | export const setThemeOverrides = ({ 5 | overrides, 6 | }: { 7 | overrides: ThemeContractOverrides; 8 | }) => { 9 | return themeStore.setState({ themeOverrides: overrides }); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/index.ts: -------------------------------------------------------------------------------- 1 | export { initializeTheme, setTheme } from './actions'; 2 | 3 | export type { ThemeOptions } from './theme-store.types'; 4 | 5 | export { themeStore } from './theme-store'; 6 | 7 | export { useThemeStore } from './use-theme-store'; 8 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/theme-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import type { ThemeStore } from './theme-store.types'; 4 | import { getUserPreferredTheme } from './utils'; 5 | 6 | export const themeStore = createStore()(() => ({ 7 | activeTheme: getUserPreferredTheme()(), 8 | isInitialized: false, 9 | themeOverrides: null, 10 | })); 11 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/theme-store.types.ts: -------------------------------------------------------------------------------- 1 | import type { AvailableThemes } from '@pathfinder-ide/shared'; 2 | import type { ThemeContractOverrides } from '@pathfinder-ide/style'; 3 | 4 | export type ThemeOptions = { 5 | defaultTheme?: AvailableThemes | 'system'; 6 | overrides?: ThemeContractOverrides; 7 | }; 8 | 9 | type ThemeStoreState = { 10 | activeTheme: AvailableThemes; 11 | isInitialized: boolean; 12 | themeOverrides: ThemeContractOverrides | null; 13 | }; 14 | 15 | export type ThemeStore = ThemeStoreState; 16 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/use-theme-store.ts: -------------------------------------------------------------------------------- 1 | import { themeStore } from './theme-store'; 2 | 3 | import { createZustandSelectors } from '@pathfinder-ide/shared'; 4 | 5 | export const useThemeStore = createZustandSelectors(themeStore); 6 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/utils/getUserPreferredTheme.ts: -------------------------------------------------------------------------------- 1 | import { AvailableThemes } from '@pathfinder-ide/shared'; 2 | 3 | export const getUserPreferredTheme = () => (): AvailableThemes => { 4 | const media = matchMedia('(prefers-color-scheme:dark)'); 5 | 6 | if (media.matches) { 7 | return 'dark'; 8 | } else { 9 | return 'light'; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { getUserPreferredTheme } from './getUserPreferredTheme'; 2 | 3 | export { mungeThemeOverrides } from './munge-theme-overrides'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/theme-store/utils/munge-theme-overrides.ts: -------------------------------------------------------------------------------- 1 | import type { ThemeContractOverrides } from '@pathfinder-ide/style'; 2 | import { toTitleCase } from '@pathfinder-ide/style'; 3 | 4 | export const mungeThemeOverrides = ({ 5 | overrides, 6 | parentKey, 7 | }: { 8 | overrides: ThemeContractOverrides; 9 | parentKey?: string; 10 | }) => { 11 | let result = {}; 12 | 13 | Object.keys(overrides).forEach((key) => { 14 | const value = overrides[key as keyof object]; 15 | // our final key will be in this format: "dark__--ColorSurface1" | "light__--FontBody" 16 | // we'll split on the "__" and have our target theme in split[0] and our css variable name in split[1] 17 | const _key = parentKey ? parentKey + toTitleCase(key) : `${key}__--`; 18 | 19 | if (typeof value === 'object') { 20 | result = { 21 | ...result, 22 | ...mungeThemeOverrides({ overrides: value, parentKey: _key }), 23 | }; 24 | } else { 25 | result[_key as keyof object] = value; 26 | } 27 | }); 28 | 29 | return result; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/stores/src/ui-store/index.ts: -------------------------------------------------------------------------------- 1 | export { uiStore } from './ui-store'; 2 | 3 | export type { ActiveSubscriptionEntry } from './ui-store.types'; 4 | -------------------------------------------------------------------------------- /packages/stores/src/ui-store/ui-store.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'zustand'; 2 | 3 | import { UIStore } from './ui-store.types'; 4 | 5 | export const uiStore = createStore()(() => ({ 6 | isHydrated: false, 7 | activeSubscriptions: [], 8 | })); 9 | -------------------------------------------------------------------------------- /packages/stores/src/ui-store/ui-store.types.ts: -------------------------------------------------------------------------------- 1 | export type ActiveSubscriptionEntry = { 2 | dispose: () => void; 3 | tabId: string; 4 | operationName: string; 5 | }; 6 | 7 | type UIStoreState = { 8 | isHydrated: boolean; 9 | activeSubscriptions: ActiveSubscriptionEntry[]; 10 | }; 11 | 12 | export type UIStore = UIStoreState; 13 | -------------------------------------------------------------------------------- /packages/stores/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@pathfinder-ide/tsconfig/base.json", 3 | "compilerOptions": { 4 | "lib": ["DOM", "ESNext"], 5 | "module": "ESNext", 6 | "types": ["node"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/style/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@pathfinder-ide/eslint-config"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/style/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pathfinder-ide/style", 3 | "version": "0.0.1", 4 | "private": true, 5 | "main": "./src/index.ts", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "types": "tsc --noEmit" 9 | }, 10 | "dependencies": { 11 | "@pathfinder-ide/shared": "workspace:*", 12 | "@radix-ui/colors": "3.0.0", 13 | "@vanilla-extract/css": "1.14.2", 14 | "@vanilla-extract/dynamic": "2.1.2", 15 | "@vanilla-extract/recipes": "0.5.5", 16 | "zustand": "4.4.7" 17 | }, 18 | "devDependencies": { 19 | "@pathfinder-ide/eslint-config": "workspace:*", 20 | "@pathfinder-ide/tsconfig": "workspace:*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/style/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const HAIRLINE_BORDER_VAR = '--hairline-border-width'; 2 | 3 | export const ROOT_SELECTOR = ':root'; 4 | 5 | export const THEME_MODE_ATTRIBUTE = 'data-theme-mode'; 6 | -------------------------------------------------------------------------------- /packages/style/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | createGlobalTheme, 3 | globalStyle, 4 | keyframes, 5 | style, 6 | styleVariants, 7 | } from '@vanilla-extract/css'; 8 | 9 | export { assignInlineVars } from '@vanilla-extract/dynamic'; 10 | 11 | export { recipe } from '@vanilla-extract/recipes'; 12 | 13 | export type { RecipeVariants } from '@vanilla-extract/recipes'; 14 | 15 | export { THEME_MODE_ATTRIBUTE } from './constants'; 16 | 17 | export { shared } from './shared'; 18 | 19 | export { contract } from './theme'; 20 | 21 | export type { ThemeContractOverrides } from './types'; 22 | 23 | export { toTitleCase } from './utils'; 24 | -------------------------------------------------------------------------------- /packages/style/src/shared/index.ts: -------------------------------------------------------------------------------- 1 | import { hairlineBorder } from './hairline-border.css'; 2 | import { buttonReset } from './resets.css'; 3 | import { scrollbars } from './scrollbars.css'; 4 | import { authenticMotion } from './transitions'; 5 | 6 | export const shared = { 7 | hairlineBorder, 8 | resets: { 9 | buttonReset, 10 | }, 11 | scrollbars, 12 | transitions: { 13 | authenticMotion, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /packages/style/src/shared/resets.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const buttonReset = style({ 4 | all: 'unset', 5 | cursor: 'pointer', 6 | border: 'none', 7 | backgroundColor: 'transparent', 8 | margin: 0, 9 | padding: 0, 10 | boxSizing: 'border-box', 11 | }); 12 | -------------------------------------------------------------------------------- /packages/style/src/shared/scrollbars.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | import { contract } from '../theme'; 3 | 4 | export const scrollbars = style({ 5 | // firefox 6 | scrollbarWidth: 'thin', 7 | scrollbarColor: `${contract.color.neutral[7]} transparent`, 8 | 9 | selectors: { 10 | // Chrome, Edge, and Safari 11 | '&::-webkit-scrollbar': { 12 | width: 2, 13 | height: 2, 14 | }, 15 | '&::-webkit-scrollbar-track': { 16 | background: 'transparent', 17 | }, 18 | '&::-webkit-scrollbar-thumb': { 19 | backgroundColor: contract.color.neutral[7], 20 | borderRadius: 4, 21 | }, 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /packages/style/src/shared/transitions.ts: -------------------------------------------------------------------------------- 1 | export const authenticMotion = 'cubic-bezier(0.4, 0, 0.2, 1)'; 2 | -------------------------------------------------------------------------------- /packages/style/src/theme/color.ts: -------------------------------------------------------------------------------- 1 | import { ColorRange } from '../types'; 2 | 3 | const colorObject: ColorRange = { 4 | 1: '', 5 | 2: '', 6 | 3: '', 7 | 4: '', 8 | 5: '', 9 | 6: '', 10 | 7: '', 11 | 8: '', 12 | 9: '', 13 | 10: '', 14 | 11: '', 15 | 12: '', 16 | }; 17 | 18 | export const color = { 19 | neutral: colorObject, 20 | neutralAlpha: colorObject, 21 | amber: colorObject, 22 | blue: colorObject, 23 | green: colorObject, 24 | orange: colorObject, 25 | purple: colorObject, 26 | red: colorObject, 27 | yellow: colorObject, 28 | }; 29 | -------------------------------------------------------------------------------- /packages/style/src/theme/contract.css.ts: -------------------------------------------------------------------------------- 1 | import { createGlobalThemeContract } from '@vanilla-extract/css'; 2 | import { toTitleCase } from '../utils'; 3 | 4 | import { color } from './color'; 5 | import { fonts } from './fonts'; 6 | import { space } from './space'; 7 | 8 | export const contract = createGlobalThemeContract( 9 | { 10 | color, 11 | fonts, 12 | space, 13 | }, 14 | (_value, path) => `${path.map(toTitleCase).join('')}`, 15 | ); 16 | -------------------------------------------------------------------------------- /packages/style/src/theme/fonts.ts: -------------------------------------------------------------------------------- 1 | export const fonts = { 2 | body: 'Inter, -apple-system, BlinkMacSystemFont, avenir next, avenir, helvetica neue, helvetica, Ubuntu, roboto, noto, segoe ui, arial, sans-serif', 3 | mono: 'Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace', 4 | }; 5 | -------------------------------------------------------------------------------- /packages/style/src/theme/global.css.ts: -------------------------------------------------------------------------------- 1 | import { globalStyle } from '@vanilla-extract/css'; 2 | 3 | import { HAIRLINE_BORDER_VAR } from '../constants'; 4 | 5 | export const globalAllCSS = globalStyle('*', { 6 | boxSizing: 'border-box', 7 | }); 8 | 9 | export const globalRootCss = globalStyle(':root', { 10 | vars: { 11 | [`${HAIRLINE_BORDER_VAR}`]: '1px', 12 | }, 13 | 14 | '@media': { 15 | '(min-resolution: 2x)': { 16 | vars: { 17 | [`${HAIRLINE_BORDER_VAR}`]: `calc(1px / 2)`, 18 | }, 19 | }, 20 | '(min-resolution: 3x)': { 21 | vars: { 22 | [`${HAIRLINE_BORDER_VAR}`]: `calc(1px / 3)`, 23 | }, 24 | }, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /packages/style/src/theme/index.ts: -------------------------------------------------------------------------------- 1 | export { contract } from './contract.css'; 2 | 3 | export { darkColors } from './dark.css'; 4 | 5 | export { globalAllCSS, globalRootCss } from './global.css'; 6 | 7 | export { lightColors } from './light.css'; 8 | -------------------------------------------------------------------------------- /packages/style/src/theme/space.ts: -------------------------------------------------------------------------------- 1 | export const space = { 2 | none: '0', 3 | 2: '2px', 4 | 4: '4px', 5 | 8: '8px', 6 | 12: '12px', 7 | 16: '16px', 8 | 20: '20px', 9 | 24: '24px', 10 | 28: '28px', 11 | auto: 'auto', 12 | full: '100%', 13 | fit: 'fit-content', 14 | max: 'max-content', 15 | min: 'min-content', 16 | }; 17 | -------------------------------------------------------------------------------- /packages/style/src/types.ts: -------------------------------------------------------------------------------- 1 | export type ColorRange = { 2 | 1: string; 3 | 2: string; 4 | 3: string; 5 | 4: string; 6 | 5: string; 7 | 6: string; 8 | 7: string; 9 | 8: string; 10 | 9: string; 11 | 10: string; 12 | 11: string; 13 | 12: string; 14 | }; 15 | 16 | type Subset = { 17 | [attr in keyof K]?: K[attr] extends object 18 | ? Subset 19 | : K[attr] extends object | null 20 | ? Subset | null 21 | : K[attr] extends object | null | undefined 22 | ? Subset | null | undefined 23 | : K[attr]; 24 | }; 25 | 26 | type ThemeContract = { 27 | color: { 28 | neutral: ColorRange; 29 | red: ColorRange; 30 | orange: ColorRange; 31 | yellow: ColorRange; 32 | green: ColorRange; 33 | blue: ColorRange; 34 | purple: ColorRange; 35 | }; 36 | font: { 37 | body: string; 38 | }; 39 | }; 40 | 41 | export type SubsetThemeContract = Subset; 42 | 43 | export type ThemeContractOverrides = { 44 | dark?: SubsetThemeContract; 45 | light?: SubsetThemeContract; 46 | }; 47 | -------------------------------------------------------------------------------- /packages/style/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { toTitleCase } from './to-title-case'; 2 | -------------------------------------------------------------------------------- /packages/style/src/utils/to-title-case.ts: -------------------------------------------------------------------------------- 1 | export const toTitleCase = (s: string) => { 2 | const res = `${s.charAt(0).toUpperCase()}${s.slice(1)}`; 3 | return res; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/style/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@pathfinder-ide/tsconfig/base.json", 3 | "compilerOptions": { 4 | "lib": ["ESNext", "DOM"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Base", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "Node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ESNext" 19 | }, 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pathfinder-ide/tsconfig", 3 | "version": "0.0.1", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /packages/tsconfig/react.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 8 | "module": "ESNext", 9 | "target": "ESNext" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'apps/*' 3 | - 'examples/*' 4 | - 'packages/*' 5 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base", "schedule:weekly"], 4 | "packageRules": [ 5 | { 6 | "groupName": "dependencies-major", 7 | "matchUpdateTypes": ["major"], 8 | "excludePackageNames": ["node", "@types/node"] 9 | } 10 | ], 11 | "ignoreDeps": ["@ladle/react", "monaco-editor", "monaco-graphql", "vitest"] 12 | } 13 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "tasks": { 4 | "lint": {}, 5 | "types": {}, 6 | "dev": {}, 7 | "test:once": {}, 8 | "test:watch": {} 9 | } 10 | } 11 | --------------------------------------------------------------------------------