diff --git a/.changeset/modern-students-tie.md b/.changeset/modern-students-tie.md
new file mode 100644
index 000000000..8a15f22ec
--- /dev/null
+++ b/.changeset/modern-students-tie.md
@@ -0,0 +1,5 @@
+---
+'houdini-react': patch
+---
+
+Fix $handle reference
diff --git a/e2e/_api/graphql.mjs b/e2e/_api/graphql.mjs
index 6f2b3c117..2a893fc50 100644
--- a/e2e/_api/graphql.mjs
+++ b/e2e/_api/graphql.mjs
@@ -67,7 +67,7 @@ let monkeys = [
]
// example data
-const dataUsers = [
+export const dataUsers = [
{
id: '1',
name: 'Bruce Willis',
@@ -135,7 +135,7 @@ const listA = []
const listB = []
const userSnapshots = {}
-function getUserSnapshot(snapshot) {
+export function getUserSnapshot(snapshot) {
if (!userSnapshots[snapshot]) {
userSnapshots[snapshot] = dataUsers.map((user) => ({
...user,
@@ -325,6 +325,9 @@ export const resolvers = {
return null
},
+ avatarURL: (user, { size }) => {
+ return !size ? user.avatarURL : user.avatarURL + `?size=${size}`
+ },
},
Mutation: {
diff --git a/e2e/_api/graphql.mjs.d.ts b/e2e/_api/graphql.mjs.d.ts
new file mode 100644
index 000000000..2596b1531
--- /dev/null
+++ b/e2e/_api/graphql.mjs.d.ts
@@ -0,0 +1,9 @@
+export type User = {
+ id: string
+ name: string
+ birthDate: Date
+ avatarURL: string
+}
+
+export const dataUsers: User[] = []
+export function getUserSnapshot(snapshot: string): User {}
diff --git a/e2e/react/.gitignore b/e2e/react/.gitignore
index f61753d63..a43c38604 100644
--- a/e2e/react/.gitignore
+++ b/e2e/react/.gitignore
@@ -25,3 +25,5 @@ dist-ssr
*.sln
*.sw?
vite.config.ts.*
+
+test-results/
diff --git a/e2e/react/package.json b/e2e/react/package.json
index 23385e2aa..d8fa61f14 100644
--- a/e2e/react/package.json
+++ b/e2e/react/package.json
@@ -14,8 +14,9 @@
"web": "vite dev",
"dev": "concurrently \"pnpm run web\" \"pnpm run api\" -n \"web,api\" -c \"green,magenta\"",
"build": "vite build",
- "tests": "playwright test ",
+ "tests": "playwright test",
"test": "npm run tests",
+ "tw": "npx tailwindcss -i ./src/styles.css -o ./public/assets/output.css --watch",
"preview": "vite dev"
},
"dependencies": {
diff --git a/e2e/react/playwright.config.ts b/e2e/react/playwright.config.ts
index 90556d762..814f9f959 100644
--- a/e2e/react/playwright.config.ts
+++ b/e2e/react/playwright.config.ts
@@ -8,7 +8,7 @@ export default defineConfig({
testIgnore: '**/$houdini/**',
webServer: {
- command: 'npm run dev -- --port 3008',
+ command: 'PORT=3008 npm run dev',
port: 3008,
timeout: 120 * 1000,
},
diff --git a/e2e/react/public/assets/output.css b/e2e/react/public/assets/output.css
new file mode 100644
index 000000000..83ca34012
--- /dev/null
+++ b/e2e/react/public/assets/output.css
@@ -0,0 +1,1471 @@
+/*
+! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
+*/
+
+/*
+1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
+2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
+*/
+
+*,
+::before,
+::after {
+ box-sizing: border-box;
+ /* 1 */
+ border-width: 0;
+ /* 2 */
+ border-style: solid;
+ /* 2 */
+ border-color: #e5e7eb;
+ /* 2 */
+}
+
+::before,
+::after {
+ --tw-content: '';
+}
+
+/*
+1. Use a consistent sensible line-height in all browsers.
+2. Prevent adjustments of font size after orientation changes in iOS.
+3. Use a more readable tab size.
+4. Use the user's configured `sans` font-family by default.
+5. Use the user's configured `sans` font-feature-settings by default.
+6. Use the user's configured `sans` font-variation-settings by default.
+*/
+
+html {
+ line-height: 1.5;
+ /* 1 */
+ -webkit-text-size-adjust: 100%;
+ /* 2 */
+ -moz-tab-size: 4;
+ /* 3 */
+ -o-tab-size: 4;
+ tab-size: 4;
+ /* 3 */
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ /* 4 */
+ font-feature-settings: normal;
+ /* 5 */
+ font-variation-settings: normal;
+ /* 6 */
+}
+
+/*
+1. Remove the margin in all browsers.
+2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
+*/
+
+body {
+ margin: 0;
+ /* 1 */
+ line-height: inherit;
+ /* 2 */
+}
+
+/*
+1. Add the correct height in Firefox.
+2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
+3. Ensure horizontal rules are visible by default.
+*/
+
+hr {
+ height: 0;
+ /* 1 */
+ color: inherit;
+ /* 2 */
+ border-top-width: 1px;
+ /* 3 */
+}
+
+/*
+Add the correct text decoration in Chrome, Edge, and Safari.
+*/
+
+abbr:where([title]) {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+}
+
+/*
+Remove the default font size and weight for headings.
+*/
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size: inherit;
+ font-weight: inherit;
+}
+
+/*
+Reset links to optimize for opt-in styling instead of opt-out.
+*/
+
+a {
+ color: inherit;
+ text-decoration: inherit;
+}
+
+/*
+Add the correct font weight in Edge and Safari.
+*/
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/*
+1. Use the user's configured `mono` font family by default.
+2. Correct the odd `em` font sizing in all browsers.
+*/
+
+code,
+kbd,
+samp,
+pre {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ /* 1 */
+ font-size: 1em;
+ /* 2 */
+}
+
+/*
+Add the correct font size in all browsers.
+*/
+
+small {
+ font-size: 80%;
+}
+
+/*
+Prevent `sub` and `sup` elements from affecting the line height in all browsers.
+*/
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/*
+1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
+2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
+3. Remove gaps between table borders by default.
+*/
+
+table {
+ text-indent: 0;
+ /* 1 */
+ border-color: inherit;
+ /* 2 */
+ border-collapse: collapse;
+ /* 3 */
+}
+
+/*
+1. Change the font styles in all browsers.
+2. Remove the margin in Firefox and Safari.
+3. Remove default padding in all browsers.
+*/
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit;
+ /* 1 */
+ font-feature-settings: inherit;
+ /* 1 */
+ font-variation-settings: inherit;
+ /* 1 */
+ font-size: 100%;
+ /* 1 */
+ font-weight: inherit;
+ /* 1 */
+ line-height: inherit;
+ /* 1 */
+ color: inherit;
+ /* 1 */
+ margin: 0;
+ /* 2 */
+ padding: 0;
+ /* 3 */
+}
+
+/*
+Remove the inheritance of text transform in Edge and Firefox.
+*/
+
+button,
+select {
+ text-transform: none;
+}
+
+/*
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Remove default button styles.
+*/
+
+button,
+[type='button'],
+[type='reset'],
+[type='submit'] {
+ -webkit-appearance: button;
+ /* 1 */
+ background-color: transparent;
+ /* 2 */
+ background-image: none;
+ /* 2 */
+}
+
+/*
+Use the modern Firefox focus style for all focusable elements.
+*/
+
+:-moz-focusring {
+ outline: auto;
+}
+
+/*
+Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
+*/
+
+:-moz-ui-invalid {
+ box-shadow: none;
+}
+
+/*
+Add the correct vertical alignment in Chrome and Firefox.
+*/
+
+progress {
+ vertical-align: baseline;
+}
+
+/*
+Correct the cursor style of increment and decrement buttons in Safari.
+*/
+
+::-webkit-inner-spin-button,
+::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/*
+1. Correct the odd appearance in Chrome and Safari.
+2. Correct the outline style in Safari.
+*/
+
+[type='search'] {
+ -webkit-appearance: textfield;
+ /* 1 */
+ outline-offset: -2px;
+ /* 2 */
+}
+
+/*
+Remove the inner padding in Chrome and Safari on macOS.
+*/
+
+::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/*
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Change font properties to `inherit` in Safari.
+*/
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button;
+ /* 1 */
+ font: inherit;
+ /* 2 */
+}
+
+/*
+Add the correct display in Chrome and Safari.
+*/
+
+summary {
+ display: list-item;
+}
+
+/*
+Removes the default spacing and border for appropriate elements.
+*/
+
+blockquote,
+dl,
+dd,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+hr,
+figure,
+p,
+pre {
+ margin: 0;
+}
+
+fieldset {
+ margin: 0;
+ padding: 0;
+}
+
+legend {
+ padding: 0;
+}
+
+ol,
+ul,
+menu {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+/*
+Reset default styling for dialogs.
+*/
+
+dialog {
+ padding: 0;
+}
+
+/*
+Prevent resizing textareas horizontally by default.
+*/
+
+textarea {
+ resize: vertical;
+}
+
+/*
+1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
+2. Set the default placeholder color to the user's configured gray 400 color.
+*/
+
+input::-moz-placeholder, textarea::-moz-placeholder {
+ opacity: 1;
+ /* 1 */
+ color: #9ca3af;
+ /* 2 */
+}
+
+input::placeholder,
+textarea::placeholder {
+ opacity: 1;
+ /* 1 */
+ color: #9ca3af;
+ /* 2 */
+}
+
+/*
+Set the default cursor for buttons.
+*/
+
+button,
+[role="button"] {
+ cursor: pointer;
+}
+
+/*
+Make sure disabled buttons don't get the pointer cursor.
+*/
+
+:disabled {
+ cursor: default;
+}
+
+/*
+1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
+2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
+ This can trigger a poorly considered lint error in some tools but is included by design.
+*/
+
+img,
+svg,
+video,
+canvas,
+audio,
+iframe,
+embed,
+object {
+ display: block;
+ /* 1 */
+ vertical-align: middle;
+ /* 2 */
+}
+
+/*
+Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
+*/
+
+img,
+video {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Make elements with the HTML hidden attribute stay hidden by default */
+
+[hidden] {
+ display: none;
+}
+
+*, ::before, ::after {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+}
+
+::backdrop {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+}
+
+.static {
+ position: static;
+}
+
+.mb-4 {
+ margin-bottom: 1rem;
+}
+
+.block {
+ display: block;
+}
+
+.flex {
+ display: flex;
+}
+
+.w-full {
+ width: 100%;
+}
+
+.flex-row {
+ flex-direction: row;
+}
+
+.flex-col {
+ flex-direction: column;
+}
+
+.flex-wrap {
+ flex-wrap: wrap;
+}
+
+.gap-12 {
+ gap: 3rem;
+}
+
+.gap-2 {
+ gap: 0.5rem;
+}
+
+.border-2 {
+ border-width: 2px;
+}
+
+.border-solid {
+ border-style: solid;
+}
+
+.border-white {
+ --tw-border-opacity: 1;
+ border-color: rgb(255 255 255 / var(--tw-border-opacity));
+}
+
+.border-\[var\(--links\)\] {
+ border-color: var(--links);
+}
+
+.p-4 {
+ padding: 1rem;
+}
+
+.p-2 {
+ padding: 0.5rem;
+}
+
+/**
+ * Forced dark theme version
+ */
+
+:root {
+ --background-body: #202b38;
+ --background: #161f27;
+ --background-alt: #1a242f;
+ --selection: #1c76c5;
+ --text-main: #dbdbdb;
+ --text-bright: #fff;
+ --text-muted: #a9b1ba;
+ --links: #41adff;
+ --focus: #0096bfab;
+ --border: #526980;
+ --code: #ffbe85;
+ --animation-duration: 0.1s;
+ --button-base: #0c151c;
+ --button-hover: #040a0f;
+ --scrollbar-thumb: var(--button-hover);
+ --scrollbar-thumb-hover: rgb(0, 0, 0);
+ --form-placeholder: #a9a9a9;
+ --form-text: #fff;
+ --variable: #d941e2;
+ --highlight: #efdb43;
+ --select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E");
+}
+
+html {
+ scrollbar-color: #040a0f #202b38;
+ scrollbar-color: var(--scrollbar-thumb) var(--background-body);
+ scrollbar-width: thin;
+}
+
+body {
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
+ line-height: 1.4;
+ max-width: 800px;
+ margin: 20px auto;
+ padding: 0 10px;
+ word-wrap: break-word;
+ color: #dbdbdb;
+ color: var(--text-main);
+ background: #202b38;
+ background: var(--background-body);
+ text-rendering: optimizeLegibility;
+}
+
+button {
+ transition:
+ background-color 0.1s linear,
+ border-color 0.1s linear,
+ color 0.1s linear,
+ box-shadow 0.1s linear,
+ transform 0.1s ease;
+ transition:
+ background-color var(--animation-duration) linear,
+ border-color var(--animation-duration) linear,
+ color var(--animation-duration) linear,
+ box-shadow var(--animation-duration) linear,
+ transform var(--animation-duration) ease;
+}
+
+input {
+ transition:
+ background-color 0.1s linear,
+ border-color 0.1s linear,
+ color 0.1s linear,
+ box-shadow 0.1s linear,
+ transform 0.1s ease;
+ transition:
+ background-color var(--animation-duration) linear,
+ border-color var(--animation-duration) linear,
+ color var(--animation-duration) linear,
+ box-shadow var(--animation-duration) linear,
+ transform var(--animation-duration) ease;
+}
+
+textarea {
+ transition:
+ background-color 0.1s linear,
+ border-color 0.1s linear,
+ color 0.1s linear,
+ box-shadow 0.1s linear,
+ transform 0.1s ease;
+ transition:
+ background-color var(--animation-duration) linear,
+ border-color var(--animation-duration) linear,
+ color var(--animation-duration) linear,
+ box-shadow var(--animation-duration) linear,
+ transform var(--animation-duration) ease;
+}
+
+h1 {
+ font-size: 2.2em;
+ margin-top: 0;
+}
+
+h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ margin-bottom: 12px;
+ margin-top: 24px;
+}
+
+h1 {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+h2 {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+h3 {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+h4 {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+h5 {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+h6 {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+strong {
+ color: #fff;
+ color: var(--text-bright);
+}
+
+h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6,
+ b,
+ strong,
+ th {
+ font-weight: 600;
+}
+
+q::before {
+ content: none;
+}
+
+q::after {
+ content: none;
+}
+
+blockquote {
+ border-left: 4px solid #0096bfab;
+ border-left: 4px solid var(--focus);
+ margin: 1.5em 0;
+ padding: 0.5em 1em;
+ font-style: italic;
+}
+
+q {
+ border-left: 4px solid #0096bfab;
+ border-left: 4px solid var(--focus);
+ margin: 1.5em 0;
+ padding: 0.5em 1em;
+ font-style: italic;
+}
+
+blockquote > footer {
+ font-style: normal;
+ border: 0;
+}
+
+blockquote cite {
+ font-style: normal;
+}
+
+address {
+ font-style: normal;
+}
+
+a[href^='mailto\:']::before {
+ content: '📧 ';
+}
+
+a[href^='tel\:']::before {
+ content: '📞 ';
+}
+
+a[href^='sms\:']::before {
+ content: '💬 ';
+}
+
+mark {
+ background-color: #efdb43;
+ background-color: var(--highlight);
+ border-radius: 2px;
+ padding: 0 2px 0 2px;
+ color: #000;
+}
+
+a > code,
+ a > strong {
+ color: inherit;
+}
+
+button,
+ select,
+ input[type='submit'],
+ input[type='reset'],
+ input[type='button'],
+ input[type='checkbox'],
+ input[type='range'],
+ input[type='radio'] {
+ cursor: pointer;
+}
+
+input,
+ select {
+ display: block;
+}
+
+[type='checkbox'],
+ [type='radio'] {
+ display: initial;
+}
+
+input {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+}
+
+button {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+}
+
+textarea {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+}
+
+select {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+}
+
+button {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+}
+
+input[type='submit'] {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+}
+
+input[type='reset'] {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+}
+
+input[type='button'] {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+}
+
+button:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+}
+
+input[type='submit']:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+}
+
+input[type='reset']:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+}
+
+input[type='button']:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+}
+
+input[type='color'] {
+ min-height: 2rem;
+ padding: 8px;
+ cursor: pointer;
+}
+
+input[type='checkbox'],
+ input[type='radio'] {
+ height: 1em;
+ width: 1em;
+}
+
+input[type='radio'] {
+ border-radius: 100%;
+}
+
+input {
+ vertical-align: top;
+}
+
+label {
+ vertical-align: middle;
+ margin-bottom: 4px;
+ display: inline-block;
+}
+
+input:not([type='checkbox']):not([type='radio']),
+ input[type='range'],
+ select,
+ button,
+ textarea {
+ -webkit-appearance: none;
+}
+
+textarea {
+ display: block;
+ margin-right: 0;
+ box-sizing: border-box;
+ resize: vertical;
+}
+
+textarea:not([cols]) {
+ width: 100%;
+}
+
+textarea:not([rows]) {
+ min-height: 40px;
+ height: 140px;
+}
+
+select {
+ background: #161f27 url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat;
+ background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat;
+ padding-right: 35px;
+}
+
+select::-ms-expand {
+ display: none;
+}
+
+select[multiple] {
+ padding-right: 10px;
+ background-image: none;
+ overflow-y: auto;
+}
+
+input:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+}
+
+select:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+}
+
+button:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+}
+
+textarea:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+}
+
+input[type='checkbox']:active,
+ input[type='radio']:active,
+ input[type='submit']:active,
+ input[type='reset']:active,
+ input[type='button']:active,
+ input[type='range']:active,
+ button:active {
+ transform: translateY(2px);
+}
+
+input:disabled,
+ select:disabled,
+ button:disabled,
+ textarea:disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
+
+::-moz-placeholder {
+ color: #a9a9a9;
+ color: var(--form-placeholder);
+}
+
+::placeholder {
+ color: #a9a9a9;
+ color: var(--form-placeholder);
+}
+
+fieldset {
+ border: 1px #0096bfab solid;
+ border: 1px var(--focus) solid;
+ border-radius: 6px;
+ margin: 0;
+ margin-bottom: 12px;
+ padding: 10px;
+}
+
+legend {
+ font-size: 0.9em;
+ font-weight: 600;
+}
+
+input[type='range'] {
+ margin: 10px 0;
+ padding: 10px 0;
+ background: transparent;
+}
+
+input[type='range']:focus {
+ outline: none;
+}
+
+input[type='range']::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 9.5px;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+ background: #161f27;
+ background: var(--background);
+ border-radius: 3px;
+}
+
+input[type='range']::-webkit-slider-thumb {
+ box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ background: #526980;
+ background: var(--border);
+ -webkit-appearance: none;
+ margin-top: -7px;
+}
+
+input[type='range']:focus::-webkit-slider-runnable-track {
+ background: #161f27;
+ background: var(--background);
+}
+
+input[type='range']::-moz-range-track {
+ width: 100%;
+ height: 9.5px;
+ -moz-transition: 0.2s;
+ transition: 0.2s;
+ background: #161f27;
+ background: var(--background);
+ border-radius: 3px;
+}
+
+input[type='range']::-moz-range-thumb {
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ background: #526980;
+ background: var(--border);
+}
+
+input[type='range']::-ms-track {
+ width: 100%;
+ height: 9.5px;
+ background: transparent;
+ border-color: transparent;
+ border-width: 16px 0;
+ color: transparent;
+}
+
+input[type='range']::-ms-fill-lower {
+ background: #161f27;
+ background: var(--background);
+ border: 0.2px solid #010101;
+ border-radius: 3px;
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+}
+
+input[type='range']::-ms-fill-upper {
+ background: #161f27;
+ background: var(--background);
+ border: 0.2px solid #010101;
+ border-radius: 3px;
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+}
+
+input[type='range']::-ms-thumb {
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+ border: 1px solid #000;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ background: #526980;
+ background: var(--border);
+}
+
+input[type='range']:focus::-ms-fill-lower {
+ background: #161f27;
+ background: var(--background);
+}
+
+input[type='range']:focus::-ms-fill-upper {
+ background: #161f27;
+ background: var(--background);
+}
+
+a {
+ text-decoration: none;
+ color: #41adff;
+ color: var(--links);
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+code {
+ background: #161f27;
+ background: var(--background);
+ color: #ffbe85;
+ color: var(--code);
+ padding: 2.5px 5px;
+ border-radius: 6px;
+ font-size: 1em;
+}
+
+samp {
+ background: #161f27;
+ background: var(--background);
+ color: #ffbe85;
+ color: var(--code);
+ padding: 2.5px 5px;
+ border-radius: 6px;
+ font-size: 1em;
+}
+
+time {
+ background: #161f27;
+ background: var(--background);
+ color: #ffbe85;
+ color: var(--code);
+ padding: 2.5px 5px;
+ border-radius: 6px;
+ font-size: 1em;
+}
+
+pre > code {
+ padding: 10px;
+ display: block;
+ overflow-x: auto;
+}
+
+var {
+ color: #d941e2;
+ color: var(--variable);
+ font-style: normal;
+ font-family: monospace;
+}
+
+kbd {
+ background: #161f27;
+ background: var(--background);
+ border: 1px solid #526980;
+ border: 1px solid var(--border);
+ border-radius: 2px;
+ color: #dbdbdb;
+ color: var(--text-main);
+ padding: 2px 4px 2px 4px;
+}
+
+img,
+ video {
+ max-width: 100%;
+ height: auto;
+}
+
+hr {
+ border: none;
+ border-top: 1px solid #526980;
+ border-top: 1px solid var(--border);
+}
+
+table {
+ border-collapse: collapse;
+ margin-bottom: 10px;
+ width: 100%;
+ table-layout: fixed;
+}
+
+table caption {
+ text-align: left;
+}
+
+td,
+ th {
+ padding: 6px;
+ text-align: left;
+ vertical-align: top;
+ word-wrap: break-word;
+}
+
+thead {
+ border-bottom: 1px solid #526980;
+ border-bottom: 1px solid var(--border);
+}
+
+tfoot {
+ border-top: 1px solid #526980;
+ border-top: 1px solid var(--border);
+}
+
+tbody tr:nth-child(even) {
+ background-color: #161f27;
+ background-color: var(--background);
+}
+
+tbody tr:nth-child(even) button {
+ background-color: #1a242f;
+ background-color: var(--background-alt);
+}
+
+tbody tr:nth-child(even) button:hover {
+ background-color: #202b38;
+ background-color: var(--background-body);
+}
+
+::-webkit-scrollbar {
+ height: 10px;
+ width: 10px;
+}
+
+::-webkit-scrollbar-track {
+ background: #161f27;
+ background: var(--background);
+ border-radius: 6px;
+}
+
+::-webkit-scrollbar-thumb {
+ background: #040a0f;
+ background: var(--scrollbar-thumb);
+ border-radius: 6px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: rgb(0, 0, 0);
+ background: var(--scrollbar-thumb-hover);
+}
+
+::-moz-selection {
+ background-color: #1c76c5;
+ background-color: var(--selection);
+ color: #fff;
+ color: var(--text-bright);
+}
+
+::selection {
+ background-color: #1c76c5;
+ background-color: var(--selection);
+ color: #fff;
+ color: var(--text-bright);
+}
+
+details {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ background-color: #1a242f;
+ background-color: var(--background-alt);
+ padding: 10px 10px 0;
+ margin: 1em 0;
+ border-radius: 6px;
+ overflow: hidden;
+}
+
+details[open] {
+ padding: 10px;
+}
+
+details > :last-child {
+ margin-bottom: 0;
+}
+
+details[open] summary {
+ margin-bottom: 10px;
+}
+
+summary {
+ display: list-item;
+ background-color: #161f27;
+ background-color: var(--background);
+ padding: 10px;
+ margin: -10px -10px 0;
+ cursor: pointer;
+ outline: none;
+}
+
+summary:hover,
+ summary:focus {
+ text-decoration: underline;
+}
+
+details > :not(summary) {
+ margin-top: 0;
+}
+
+summary::-webkit-details-marker {
+ color: #dbdbdb;
+ color: var(--text-main);
+}
+
+dialog {
+ background-color: #1a242f;
+ background-color: var(--background-alt);
+ color: #dbdbdb;
+ color: var(--text-main);
+ border: none;
+ border-radius: 6px;
+ border-color: #526980;
+ border-color: var(--border);
+ padding: 10px 30px;
+}
+
+dialog > header:first-child {
+ background-color: #161f27;
+ background-color: var(--background);
+ border-radius: 6px 6px 0 0;
+ margin: -10px -30px 10px;
+ padding: 10px;
+ text-align: center;
+}
+
+dialog::backdrop {
+ background: #0000009c;
+ -webkit-backdrop-filter: blur(4px);
+ backdrop-filter: blur(4px);
+}
+
+footer {
+ border-top: 1px solid #526980;
+ border-top: 1px solid var(--border);
+ padding-top: 10px;
+ color: #a9b1ba;
+ color: var(--text-muted);
+}
+
+body > footer {
+ margin-top: 40px;
+}
+
+@media print {
+ body,
+ pre,
+ code,
+ summary,
+ details,
+ button,
+ input,
+ textarea {
+ background-color: #fff;
+ }
+
+ button,
+ input,
+ textarea {
+ border: 1px solid #000;
+ }
+
+ body,
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6,
+ pre,
+ code,
+ button,
+ input,
+ textarea,
+ footer,
+ summary,
+ strong {
+ color: #000;
+ }
+
+ summary::marker {
+ color: #000;
+ }
+
+ summary::-webkit-details-marker {
+ color: #000;
+ }
+
+ tbody tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+
+ a {
+ color: #00f;
+ text-decoration: underline;
+ }
+}
diff --git a/e2e/react/schema.graphql b/e2e/react/schema.graphql
index 296f94979..42c28bca3 100644
--- a/e2e/react/schema.graphql
+++ b/e2e/react/schema.graphql
@@ -40,8 +40,13 @@ scalar DateTime
scalar File
enum ForceReturn {
+ """Some error"""
ERROR
+
+ """Normal"""
NORMAL
+
+ """No value"""
NULL
}
@@ -55,10 +60,15 @@ type Message1 {
message: String!
}
+"""A monkey."""
type Monkey implements Animal & Node {
+ """Whether the monkey has a banana or not"""
hasBanana: Boolean!
id: ID!
name: String!
+
+ """Whether the monkey has a banana or not"""
+ oldHasBanana: Boolean @deprecated(reason: "Use hasBanana")
}
type MonkeyConnection implements AnimalConnection {
@@ -76,7 +86,16 @@ type Mutation {
addCity(name: String!): City!
addLibrary(city: ID!, name: String!): Library!
addNonNullUser(birthDate: DateTime!, delay: Int, enumValue: MyEnum, force: ForceReturn, name: String!, snapshot: String!, types: [TypeOfUser!]): User!
- addUser(birthDate: DateTime!, delay: Int, enumValue: MyEnum, force: ForceReturn, name: String!, snapshot: String!, types: [TypeOfUser!]): User
+ addUser(
+ """The users birth date"""
+ birthDate: DateTime!
+ delay: Int
+ enumValue: MyEnum
+ force: ForceReturn
+ name: String!
+ snapshot: String!
+ types: [TypeOfUser!]
+ ): User
createA(a: String!): A!
createB(b: String!): B!
deleteBook(book: ID!, delay: Int, force: ForceReturn): Book
@@ -88,11 +107,16 @@ type Mutation {
updateUser(birthDate: DateTime, delay: Int, id: ID!, name: String, snapshot: String!): User!
}
+"""Can be Value1 or Value2."""
enum MyEnum {
+ """The first value"""
Value1
- Value2
+
+ """The second value"""
+ Value2 @deprecated(reason: "Use Value1 instead")
}
+"""A node."""
interface Node {
id: ID!
}
@@ -111,6 +135,8 @@ type Query {
cities: [City]!
city(delay: Int, id: ID!): City
hello: String
+
+ """Get a monkey by its id"""
monkey(id: ID!): Monkey
monkeys: MonkeyConnection!
node(id: ID!): Node
diff --git a/e2e/react/src/+index.jsx b/e2e/react/src/+index.jsx
index 5b75493ab..0af98d792 100644
--- a/e2e/react/src/+index.jsx
+++ b/e2e/react/src/+index.jsx
@@ -7,10 +7,7 @@ export default function App({ children }) {
Houdini • e2e • React
-
+
{children}
diff --git a/e2e/react/src/routes/+layout.tsx b/e2e/react/src/routes/+layout.tsx
index e9bd1e29e..0c322c8fa 100644
--- a/e2e/react/src/routes/+layout.tsx
+++ b/e2e/react/src/routes/+layout.tsx
@@ -3,7 +3,6 @@ import React from 'react'
import { routes } from '~/utils/routes'
import type { LayoutProps } from './$types'
-import './index.css'
export default function ({ children }: LayoutProps) {
// save the cache reference on the window
@@ -13,22 +12,24 @@ export default function ({ children }: LayoutProps) {
// @ts-ignore
globalThis.window.cache = cache
}
- })
+ }, [])
return (
<>
-
+
{children}
>
)
diff --git a/e2e/react/src/routes/component_fields/arguments/test.ts b/e2e/react/src/routes/component_fields/arguments/test.ts
index 4e2a41d9c..3ceccc588 100644
--- a/e2e/react/src/routes/component_fields/arguments/test.ts
+++ b/e2e/react/src/routes/component_fields/arguments/test.ts
@@ -9,7 +9,6 @@ test('Component fields with correct argument value', async ({ page }) => {
const images = await page.locator('img').all()
// every image should have a size of 50
for (const image of images) {
- expect(await image.getAttribute('height')).toBe('50')
- expect(await image.getAttribute('src')).toContain('size=50')
+ expect(await image.getAttribute('src')).toContain('size=100')
}
})
diff --git a/e2e/react/src/routes/handle/[userID]/+page.gql b/e2e/react/src/routes/handle/[userID]/+page.gql
new file mode 100644
index 000000000..500454466
--- /dev/null
+++ b/e2e/react/src/routes/handle/[userID]/+page.gql
@@ -0,0 +1,5 @@
+query HandleUserQuery($userID: ID!, $size: Int) {
+ user(id: $userID, snapshot: "route_params") {
+ avatarURL(size: $size)
+ }
+}
diff --git a/e2e/react/src/routes/handle/[userID]/+page.tsx b/e2e/react/src/routes/handle/[userID]/+page.tsx
new file mode 100644
index 000000000..cdbf96162
--- /dev/null
+++ b/e2e/react/src/routes/handle/[userID]/+page.tsx
@@ -0,0 +1,45 @@
+import { PageProps } from './$types'
+
+export default function HandleTest({ HandleUserQuery, HandleUserQuery$handle }: PageProps) {
+ // grab the current size from the query handle
+ const currentSize = HandleUserQuery$handle.variables.size ?? 50
+
+ return (
+
+
+ HandleUserQuery$handle.fetch({ variables: { userID: '1' } })}
+ >
+ load 1
+
+ HandleUserQuery$handle.fetch({ variables: { userID: '2' } })}
+ >
+ load 2
+
+
+ HandleUserQuery$handle.fetch({
+ variables: {
+ size: currentSize + 1,
+ },
+ })
+ }
+ >
+ larger
+
+
+
+ {HandleUserQuery.user.avatarURL}
+
+
{JSON.stringify(HandleUserQuery$handle.variables)}
+
+ )
+}
diff --git a/e2e/react/src/routes/handle/test.ts b/e2e/react/src/routes/handle/test.ts
new file mode 100644
index 000000000..4fcf59997
--- /dev/null
+++ b/e2e/react/src/routes/handle/test.ts
@@ -0,0 +1,69 @@
+import { expect, test } from '@playwright/test'
+import { dataUsers } from 'e2e-api/graphql.mjs'
+import { routes } from '~/utils/routes'
+import { goto } from '~/utils/testsHelper.js'
+
+test('handle fetch remembers server-side variables', async function ({ page }) {
+ // in this test, variables are stringified in the #variables div
+ const getVariables = async () => {
+ return JSON.parse((await page.textContent('#variables')) as string)
+ }
+
+ // visit the page for user 2
+ await goto(page, routes.handle_2)
+ await expect(page.textContent('#result')).resolves.toEqual(dataUsers[1].avatarURL)
+
+ // check the variables
+ await expect(getVariables()).resolves.toEqual({ userID: '2' })
+
+ // load the larger image and wait for it to resolve
+ await page.click('#larger')
+ await page.waitForSelector('[data-size="51"]', {
+ timeout: 1000,
+ })
+
+ // make sure the and variables line up
+ await expect(page.textContent('#result')).resolves.toContain(dataUsers[1].avatarURL)
+ await expect(getVariables()).resolves.toEqual({ userID: '2', size: 51 })
+
+ // now load user 1
+ await page.click('#user-1')
+ await page.waitForSelector('[data-user="1"]', {
+ timeout: 1000,
+ })
+
+ // make sure the and variables line up
+ await expect(page.textContent('#result')).resolves.toContain(dataUsers[0].avatarURL)
+ await expect(getVariables()).resolves.toEqual({ userID: '1', size: 51 })
+})
+
+test('handle survives navigation', async function ({ page }) {
+ // in this test, variables are stringified in the #variables div
+ const getVariables = async () => {
+ return JSON.parse((await page.textContent('#variables')) as string)
+ }
+
+ // visit the page for user 2
+ await goto(page, routes.handle_2)
+ await expect(page.textContent('#result')).resolves.toEqual(dataUsers[1].avatarURL)
+ await expect(getVariables()).resolves.toEqual({ userID: '2' })
+
+ // navigate to the page for user 1 by clicking on the nav link
+ await page.click(`a[href="${routes.handle_1}"]`)
+ // wait for the page to load
+ await page.waitForSelector('[data-user="1"]', {
+ timeout: 1000,
+ })
+ await expect(page.textContent('#result')).resolves.toEqual(dataUsers[0].avatarURL)
+ await expect(getVariables()).resolves.toEqual({ userID: '1' })
+
+ // click on the larger button and wait for it to resolve
+ await page.click('#larger')
+ await page.waitForSelector('[data-size="51"]', {
+ timeout: 1000,
+ })
+
+ // make sure the and variables line up
+ await expect(page.textContent('#result')).resolves.toContain(dataUsers[0].avatarURL)
+ await expect(getVariables()).resolves.toEqual({ userID: '1', size: 51 })
+})
diff --git a/e2e/react/src/routes/hello-world/+page.tsx b/e2e/react/src/routes/hello-world/+page.tsx
index 601f66f7e..c1d6c3dcc 100644
--- a/e2e/react/src/routes/hello-world/+page.tsx
+++ b/e2e/react/src/routes/hello-world/+page.tsx
@@ -1,5 +1,5 @@
import type { PageProps } from './$types'
export default function ({ HelloWorld }: PageProps) {
- return {HelloWorld.hello}
+ return {HelloWorld.hello}
}
diff --git a/e2e/react/src/routes/hello-world/test.ts b/e2e/react/src/routes/hello-world/test.ts
new file mode 100644
index 000000000..1be1dc80d
--- /dev/null
+++ b/e2e/react/src/routes/hello-world/test.ts
@@ -0,0 +1,9 @@
+import { expect, test } from '@playwright/test'
+import { routes } from '~/utils/routes'
+import { goto } from '~/utils/testsHelper.js'
+
+test('Hello World', async ({ page }) => {
+ await goto(page, routes.hello)
+
+ await expect(page.textContent('#result')).resolves.toEqual('Hello World! // From Houdini!')
+})
diff --git a/e2e/react/src/routes/index.css b/e2e/react/src/routes/index.css
deleted file mode 100644
index b5c61c956..000000000
--- a/e2e/react/src/routes/index.css
+++ /dev/null
@@ -1,3 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
diff --git a/e2e/react/src/routes/pagination/query/connection-backwards/+page.gql b/e2e/react/src/routes/pagination/query/connection-backwards/+page.gql
new file mode 100644
index 000000000..1fb273882
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-backwards/+page.gql
@@ -0,0 +1,9 @@
+query BackwardsCursorPaginationQuery {
+ usersConnection(last: 2, snapshot: "pagination-query-backwards-cursor") @paginate {
+ edges {
+ node {
+ name
+ }
+ }
+ }
+}
diff --git a/e2e/react/src/routes/pagination/query/connection-backwards/+page.tsx b/e2e/react/src/routes/pagination/query/connection-backwards/+page.tsx
new file mode 100644
index 000000000..f2acd5f39
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-backwards/+page.tsx
@@ -0,0 +1,30 @@
+import { CachePolicy } from '$houdini'
+
+import type { PageProps } from './$types'
+
+export default function ({
+ BackwardsCursorPaginationQuery,
+ BackwardsCursorPaginationQuery$handle,
+}: PageProps) {
+ const handle = BackwardsCursorPaginationQuery$handle
+
+ return (
+ <>
+
+ {BackwardsCursorPaginationQuery.usersConnection.edges
+ .map(({ node }) => node?.name)
+ .join(', ')}
+
+
+ {JSON.stringify(handle.pageInfo)}
+
+ handle.loadPrevious()}>
+ previous
+
+
+ handle.fetch({ policy: CachePolicy.NetworkOnly })}>
+ refetch
+
+ >
+ )
+}
diff --git a/e2e/react/src/routes/pagination/query/connection-backwards/test.ts b/e2e/react/src/routes/pagination/query/connection-backwards/test.ts
new file mode 100644
index 000000000..0e5d4faba
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-backwards/test.ts
@@ -0,0 +1,59 @@
+import { expect, test } from '@playwright/test'
+import { routes } from '~/utils/routes.js'
+import {
+ expect_1_gql,
+ expect_0_gql,
+ expect_to_be,
+ expectToContain,
+ goto,
+} from '~/utils/testsHelper.js'
+
+test.describe('backwards cursor paginatedQuery', () => {
+ test('loadPreviousPage', async ({ page }) => {
+ await goto(page, routes.pagination_query_backwards)
+
+ await expect_to_be(page, 'Eddie Murphy, Clint Eastwood')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=previous]')
+
+ // make sure we got the new content
+ await expect_to_be(page, 'Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood')
+ })
+
+ test('refetch', async ({ page }) => {
+ await goto(page, routes.pagination_query_backwards)
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=previous]')
+
+ // wait for the api response
+ const response = await expect_1_gql(page, 'button[id=refetch]')
+ await expect_to_be(page, 'Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood')
+ })
+
+ test('page info tracks connection state', async ({ page }) => {
+ await goto(page, routes.pagination_query_backwards)
+
+ const data = [
+ 'Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood',
+ 'Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood',
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood',
+ ]
+
+ // load the previous 3 pages
+ for (let i = 0; i < 3; i++) {
+ // wait for the request to resolve
+ await expect_1_gql(page, 'button[id=previous]')
+ // check the page info
+ await expect_to_be(page, data[i])
+ }
+
+ // make sure we have all of the data loaded
+ await expect_to_be(page, data[2])
+
+ await expectToContain(page, `"hasPreviousPage":false`)
+
+ await expect_0_gql(page, 'button[id=previous]')
+ })
+})
diff --git a/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.gql b/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.gql
new file mode 100644
index 000000000..e1213ac02
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.gql
@@ -0,0 +1,13 @@
+query BidirectionalPaginationQuery {
+ usersConnection(
+ after: "YXJyYXljb25uZWN0aW9uOjE="
+ first: 2
+ snapshot: "pagination-query-bdiriectional-cursor"
+ ) @paginate {
+ edges {
+ node {
+ name
+ }
+ }
+ }
+}
diff --git a/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.svelte b/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.svelte
new file mode 100644
index 000000000..bc919f58d
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.svelte
@@ -0,0 +1,34 @@
+
+
+
+ {$result.data?.usersConnection.edges.map(({ node }) => node?.name).join(', ')}
+
+
+
+ {JSON.stringify($result.pageInfo)}
+
+
+ result.loadPreviousPage()}>previous
+ result.loadNextPage()}>next
+
+ result.fetch({ policy: CachePolicy.NetworkOnly })}
+ >refetch
diff --git a/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.tsx b/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.tsx
new file mode 100644
index 000000000..90ccd9235
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-bidirectional/+page.tsx
@@ -0,0 +1,34 @@
+import { CachePolicy } from '$houdini'
+
+import type { PageProps } from './$types'
+
+export default function ({
+ BidirectionalPaginationQuery,
+ BidirectionalPaginationQuery$handle,
+}: PageProps) {
+ const handle = BidirectionalPaginationQuery$handle
+
+ return (
+ <>
+
+ {BidirectionalPaginationQuery.usersConnection.edges
+ .map(({ node }) => node?.name)
+ .join(', ')}
+
+
+ {JSON.stringify(handle.pageInfo)}
+
+ handle.loadPrevious()}>
+ previous
+
+
+ handle.loadNext()}>
+ next
+
+
+ handle.fetch({ policy: CachePolicy.NetworkOnly })}>
+ refetch
+
+ >
+ )
+}
diff --git a/e2e/react/src/routes/pagination/query/connection-bidirectional/spec.ts b/e2e/react/src/routes/pagination/query/connection-bidirectional/spec.ts
new file mode 100644
index 000000000..cf4fbaf38
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-bidirectional/spec.ts
@@ -0,0 +1,107 @@
+import { test } from '@playwright/test'
+import { routes } from '~/utils/routes.js'
+import { expect_to_be, expectToContain, expect_1_gql, goto } from '~/utils/testsHelper.js'
+
+test.describe('bidirectional cursor paginated query', () => {
+ test('backwards and then forwards', async ({ page }) => {
+ await goto(page, routes.pagination_query_bidirectional)
+
+ await expect_to_be(page, 'Morgan Freeman, Tom Hanks')
+
+ /// Click on the previous button
+
+ // load the previous page and wait for the response
+ await expect_1_gql(page, 'button[id=previous]')
+
+ // make sure we got the new content
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+
+ // there should be a next page
+ await expectToContain(page, `"hasNextPage":true`)
+ // there should be no previous page
+ await expectToContain(page, `"hasPreviousPage":false`)
+
+ /// Click on the next button
+
+ // load the next page and wait for the response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // there should be no previous page
+ await expectToContain(page, `"hasPreviousPage":false`)
+ // there should be a next page
+ await expectToContain(page, `"hasNextPage":true`)
+
+ // make sure we got the new content
+ await expect_to_be(
+ page,
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford'
+ )
+
+ /// Click on the next button
+
+ // load the next page and wait for the response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // there should be no previous page
+ await expectToContain(page, `"hasPreviousPage":false`)
+ // there should be a next page
+ await expectToContain(page, `"hasNextPage":false`)
+
+ // make sure we got the new content
+ await expect_to_be(
+ page,
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood'
+ )
+ })
+
+ test('forwards then backwards and then forwards again', async ({ page }) => {
+ await goto(page, routes.pagination_query_bidirectional)
+
+ await expect_to_be(page, 'Morgan Freeman, Tom Hanks')
+
+ /// Click on the next button
+
+ // load the next page and wait for the response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // there should be no previous page
+ await expectToContain(page, `"hasPreviousPage":true`)
+ // there should be a next page
+ await expectToContain(page, `"hasNextPage":true`)
+
+ // make sure we got the new content
+ await expect_to_be(page, 'Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford')
+
+ /// Click on the previous button
+
+ // load the previous page and wait for the response
+ await expect_1_gql(page, 'button[id=previous]')
+
+ // make sure we got the new content
+ await expect_to_be(
+ page,
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford'
+ )
+
+ // there should be a next page
+ await expectToContain(page, `"hasNextPage":true`)
+ // there should be no previous page
+ await expectToContain(page, `"hasPreviousPage":false`)
+
+ /// Click on the next button
+
+ // load the next page and wait for the response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // there should be no previous page
+ await expectToContain(page, `"hasPreviousPage":false`)
+ // there should be a next page
+ await expectToContain(page, `"hasNextPage":false`)
+
+ // make sure we got the new content
+ await expect_to_be(
+ page,
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood'
+ )
+ })
+})
diff --git a/e2e/react/src/routes/pagination/query/connection-forwards/+page.gql b/e2e/react/src/routes/pagination/query/connection-forwards/+page.gql
new file mode 100644
index 000000000..a4d8953f3
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-forwards/+page.gql
@@ -0,0 +1,9 @@
+query ForwardsCursorPaginationQuery {
+ usersConnection(first: 2, snapshot: "pagination-query-forwards-cursor") @paginate {
+ edges {
+ node {
+ name
+ }
+ }
+ }
+}
diff --git a/e2e/react/src/routes/pagination/query/connection-forwards/+page.tsx b/e2e/react/src/routes/pagination/query/connection-forwards/+page.tsx
new file mode 100644
index 000000000..ca47082b8
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-forwards/+page.tsx
@@ -0,0 +1,30 @@
+import { CachePolicy } from '$houdini'
+
+import type { PageProps } from './$types'
+
+export default function ({
+ ForwardsCursorPaginationQuery,
+ ForwardsCursorPaginationQuery$handle,
+}: PageProps) {
+ const handle = ForwardsCursorPaginationQuery$handle
+
+ return (
+ <>
+
+ {ForwardsCursorPaginationQuery.usersConnection.edges
+ .map(({ node }) => node?.name)
+ .join(', ')}
+
+
+ {JSON.stringify(handle.pageInfo)}
+
+ handle.loadNext()}>
+ next
+
+
+ handle.fetch({ policy: CachePolicy.NetworkOnly })}>
+ refetch
+
+ >
+ )
+}
diff --git a/e2e/react/src/routes/pagination/query/connection-forwards/test.ts b/e2e/react/src/routes/pagination/query/connection-forwards/test.ts
new file mode 100644
index 000000000..944182bde
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/connection-forwards/test.ts
@@ -0,0 +1,60 @@
+import { expect, test } from '@playwright/test'
+import { routes } from '~/utils/routes.js'
+import {
+ expect_1_gql,
+ expect_0_gql,
+ expect_to_be,
+ expectToContain,
+ goto,
+} from '~/utils/testsHelper.js'
+
+test.describe('forwards cursor paginatedQuery', () => {
+ test('loadNextPage', async ({ page }) => {
+ await goto(page, routes.pagination_query_forwards)
+
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // make sure we got the new content
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+ })
+
+ test('refetch', async ({ page }) => {
+ await goto(page, routes.pagination_query_forwards)
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=refetch]')
+ // make sure we got the new content
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+ })
+
+ test('page info tracks connection state', async ({ page }) => {
+ await goto(page, routes.pagination_query_forwards)
+
+ const data = [
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks',
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford',
+ 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood',
+ ]
+
+ // load the next 3 pages
+ for (let i = 0; i < 3; i++) {
+ // wait for the request to resolve
+ await expect_1_gql(page, 'button[id=next]')
+ // check the page info
+ await expect_to_be(page, data[i])
+ }
+
+ // make sure we have all of the data loaded
+ await expect_to_be(page, data[2])
+
+ await expectToContain(page, `"hasNextPage":false`)
+
+ await expect_0_gql(page, 'button[id=next]')
+ })
+})
diff --git a/e2e/react/src/routes/pagination/query/offset-singlepage/+page.gql b/e2e/react/src/routes/pagination/query/offset-singlepage/+page.gql
new file mode 100644
index 000000000..a3fffd54b
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset-singlepage/+page.gql
@@ -0,0 +1,6 @@
+query OffsetPaginationSinglePageQuery {
+ usersList(limit: 2, snapshot: "pagination-query-offset-single-page")
+ @paginate(mode: SinglePage) {
+ name
+ }
+}
diff --git a/e2e/react/src/routes/pagination/query/offset-singlepage/+page.tsx b/e2e/react/src/routes/pagination/query/offset-singlepage/+page.tsx
new file mode 100644
index 000000000..7371afe2d
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset-singlepage/+page.tsx
@@ -0,0 +1,26 @@
+import { CachePolicy } from '$houdini'
+
+import type { PageProps } from './$types'
+
+export default function ({
+ OffsetPaginationSinglePageQuery,
+ OffsetPaginationSinglePageQuery$handle,
+}: PageProps) {
+ const handle = OffsetPaginationSinglePageQuery$handle
+
+ return (
+ <>
+
+ {OffsetPaginationSinglePageQuery.usersList.map((user) => user?.name).join(', ')}
+
+
+ handle.loadNext()}>
+ next
+
+
+ handle.fetch({ policy: CachePolicy.NetworkOnly })}>
+ refetch
+
+ >
+ )
+}
diff --git a/e2e/react/src/routes/pagination/query/offset-singlepage/test.ts b/e2e/react/src/routes/pagination/query/offset-singlepage/test.ts
new file mode 100644
index 000000000..a6cfe419f
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset-singlepage/test.ts
@@ -0,0 +1,23 @@
+import { expect, test } from '@playwright/test'
+import { routes } from '~/utils/routes.js'
+import { expect_1_gql, expect_to_be, goto } from '~/utils/testsHelper.js'
+
+test.describe('offset paginatedQuery', () => {
+ test('loadNextPage', async ({ page }) => {
+ await goto(page, routes.pagination_query_offset_singlepage)
+
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // make sure we got the new page
+ await expect_to_be(page, 'Morgan Freeman, Tom Hanks')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // make sure we got the new page
+ await expect_to_be(page, 'Will Smith, Harrison Ford')
+ })
+})
diff --git a/e2e/react/src/routes/pagination/query/offset-variable/[limit]/+page.gql b/e2e/react/src/routes/pagination/query/offset-variable/[limit]/+page.gql
new file mode 100644
index 000000000..7286c4e04
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset-variable/[limit]/+page.gql
@@ -0,0 +1,5 @@
+query OffsetVariablePaginationQuery($limit: Int!) {
+ usersList(limit: $limit, snapshot: "pagination-query-offset-variables") @paginate {
+ name
+ }
+}
diff --git a/e2e/react/src/routes/pagination/query/offset-variable/[limit]/+page.tsx b/e2e/react/src/routes/pagination/query/offset-variable/[limit]/+page.tsx
new file mode 100644
index 000000000..19413d161
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset-variable/[limit]/+page.tsx
@@ -0,0 +1,26 @@
+import { CachePolicy } from '$houdini'
+
+import type { PageProps } from './$types'
+
+export default function ({
+ OffsetVariablePaginationQuery,
+ OffsetVariablePaginationQuery$handle,
+}: PageProps) {
+ const handle = OffsetVariablePaginationQuery$handle
+
+ return (
+ <>
+
+ {OffsetVariablePaginationQuery.usersList.map((user) => user?.name).join(', ')}
+
+
+ handle.loadNext()}>
+ next
+
+
+ handle.fetch({ policy: CachePolicy.NetworkOnly })}>
+ refetch
+
+ >
+ )
+}
diff --git a/e2e/react/src/routes/pagination/query/offset-variable/[limit]/test.ts b/e2e/react/src/routes/pagination/query/offset-variable/[limit]/test.ts
new file mode 100644
index 000000000..cf4b987d7
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset-variable/[limit]/test.ts
@@ -0,0 +1,28 @@
+import { expect, test } from '@playwright/test'
+import { routes } from '~/utils/routes.js'
+import { expect_1_gql, expect_to_be, goto } from '~/utils/testsHelper.js'
+
+test.describe('offset paginatedQuery', () => {
+ test('loadNextPage', async ({ page }) => {
+ await goto(page, routes.pagination_query_offset_variable)
+
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // make sure we got the new content
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+ })
+
+ test('refetch', async ({ page }) => {
+ await goto(page, routes.pagination_query_offset_variable)
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=refetch]')
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+ })
+})
diff --git a/e2e/react/src/routes/pagination/query/offset/+page.gql b/e2e/react/src/routes/pagination/query/offset/+page.gql
new file mode 100644
index 000000000..0fc7963cb
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset/+page.gql
@@ -0,0 +1,5 @@
+query OffsetPaginationQuery {
+ usersList(limit: 2, snapshot: "pagination-query-offset") @paginate {
+ name
+ }
+}
diff --git a/e2e/react/src/routes/pagination/query/offset/+page.tsx b/e2e/react/src/routes/pagination/query/offset/+page.tsx
new file mode 100644
index 000000000..e44eaf45c
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset/+page.tsx
@@ -0,0 +1,23 @@
+import { CachePolicy } from '$houdini'
+
+import type { PageProps } from './$types'
+
+export default function ({ OffsetPaginationQuery, OffsetPaginationQuery$handle }: PageProps) {
+ const handle = OffsetPaginationQuery$handle
+
+ return (
+ <>
+
+ {OffsetPaginationQuery.usersList.map((user) => user?.name).join(', ')}
+
+
+ handle.loadNext()}>
+ next
+
+
+ handle.fetch({ policy: CachePolicy.NetworkOnly })}>
+ refetch
+
+ >
+ )
+}
diff --git a/e2e/react/src/routes/pagination/query/offset/test.ts b/e2e/react/src/routes/pagination/query/offset/test.ts
new file mode 100644
index 000000000..eef83a7f4
--- /dev/null
+++ b/e2e/react/src/routes/pagination/query/offset/test.ts
@@ -0,0 +1,29 @@
+import { expect, test } from '@playwright/test'
+import { routes } from '~/utils/routes.js'
+import { expect_1_gql, expect_to_be, goto } from '~/utils/testsHelper.js'
+
+test.describe('offset paginatedQuery', () => {
+ test('loadNextPage', async ({ page }) => {
+ await goto(page, routes.pagination_query_offset)
+
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // make sure we got the new content
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+ })
+
+ test('refetch', async ({ page }) => {
+ await goto(page, routes.pagination_query_offset)
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=next]')
+
+ // wait for the api response
+ await expect_1_gql(page, 'button[id=refetch]')
+ // make sure we got the new content
+ await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks')
+ })
+})
diff --git a/e2e/react/src/routes/route_params/[id]/+page.tsx b/e2e/react/src/routes/route_params/[id]/+page.tsx
index 528b326e7..72a7ca426 100644
--- a/e2e/react/src/routes/route_params/[id]/+page.tsx
+++ b/e2e/react/src/routes/route_params/[id]/+page.tsx
@@ -8,7 +8,7 @@ export default function ({ RouteParamsUserInfo }: PageProps) {
const { user } = RouteParamsUserInfo
return (
-
+
{route.params.id}: {user.name}
diff --git a/e2e/react/src/routes/route_params/test.ts b/e2e/react/src/routes/route_params/test.ts
index 828a744a8..d08bdd80b 100644
--- a/e2e/react/src/routes/route_params/test.ts
+++ b/e2e/react/src/routes/route_params/test.ts
@@ -10,7 +10,7 @@ test('Component fields with correct argument value', async ({ page }) => {
await expect_to_be(page, '1:Bruce Willis')
// click on the link 2
- await page.click('user-link-2')
+ await page.click('#user-link-2')
// wait some time
await sleep(100)
diff --git a/e2e/react/src/routes/scalars/test.ts b/e2e/react/src/routes/scalars/test.ts
index 88107f81c..bdd68bad3 100644
--- a/e2e/react/src/routes/scalars/test.ts
+++ b/e2e/react/src/routes/scalars/test.ts
@@ -5,5 +5,7 @@ import { goto } from '~/utils/testsHelper.js'
test('Scalars', async ({ page }) => {
await goto(page, routes.scalars)
- expect(page.textContent('#result')).toMatchSnapshot()
+ await expect(page.textContent('#result')).resolves.toEqual(
+ 'Bruce Willis-3/18/1955Samuel Jackson-12/20/1948Morgan Freeman-5/30/1937Tom Hanks-7/8/1956'
+ )
})
diff --git a/e2e/react/src/routes/spec.ts b/e2e/react/src/routes/spec.ts
deleted file mode 100644
index 3c11b4cd0..000000000
--- a/e2e/react/src/routes/spec.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { test } from '@playwright/test'
-
-import { expect_to_be } from '../utils/testsHelper.js'
-
-test('Integration has the right title, we can start 🚀', async ({ page }) => {
- await page.goto('/')
-
- await expect_to_be(page, "Houdini's React Interation tests", 'h1')
-})
diff --git a/e2e/react/src/styles.css b/e2e/react/src/styles.css
new file mode 100644
index 000000000..61028c43c
--- /dev/null
+++ b/e2e/react/src/styles.css
@@ -0,0 +1,890 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/**
+ * Forced dark theme version
+ */
+
+ :root {
+ --background-body: #202b38;
+ --background: #161f27;
+ --background-alt: #1a242f;
+ --selection: #1c76c5;
+ --text-main: #dbdbdb;
+ --text-bright: #fff;
+ --text-muted: #a9b1ba;
+ --links: #41adff;
+ --focus: #0096bfab;
+ --border: #526980;
+ --code: #ffbe85;
+ --animation-duration: 0.1s;
+ --button-base: #0c151c;
+ --button-hover: #040a0f;
+ --scrollbar-thumb: var(--button-hover);
+ --scrollbar-thumb-hover: rgb(0, 0, 0);
+ --form-placeholder: #a9a9a9;
+ --form-text: #fff;
+ --variable: #d941e2;
+ --highlight: #efdb43;
+ --select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E");
+ }
+
+ html {
+ scrollbar-color: #040a0f #202b38;
+ scrollbar-color: var(--scrollbar-thumb) var(--background-body);
+ scrollbar-width: thin;
+ }
+
+ body {
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif;
+ line-height: 1.4;
+ max-width: 800px;
+ margin: 20px auto;
+ padding: 0 10px;
+ word-wrap: break-word;
+ color: #dbdbdb;
+ color: var(--text-main);
+ background: #202b38;
+ background: var(--background-body);
+ text-rendering: optimizeLegibility;
+ }
+
+ button {
+ transition:
+ background-color 0.1s linear,
+ border-color 0.1s linear,
+ color 0.1s linear,
+ box-shadow 0.1s linear,
+ transform 0.1s ease;
+ transition:
+ background-color var(--animation-duration) linear,
+ border-color var(--animation-duration) linear,
+ color var(--animation-duration) linear,
+ box-shadow var(--animation-duration) linear,
+ transform var(--animation-duration) ease;
+ }
+
+ input {
+ transition:
+ background-color 0.1s linear,
+ border-color 0.1s linear,
+ color 0.1s linear,
+ box-shadow 0.1s linear,
+ transform 0.1s ease;
+ transition:
+ background-color var(--animation-duration) linear,
+ border-color var(--animation-duration) linear,
+ color var(--animation-duration) linear,
+ box-shadow var(--animation-duration) linear,
+ transform var(--animation-duration) ease;
+ }
+
+ textarea {
+ transition:
+ background-color 0.1s linear,
+ border-color 0.1s linear,
+ color 0.1s linear,
+ box-shadow 0.1s linear,
+ transform 0.1s ease;
+ transition:
+ background-color var(--animation-duration) linear,
+ border-color var(--animation-duration) linear,
+ color var(--animation-duration) linear,
+ box-shadow var(--animation-duration) linear,
+ transform var(--animation-duration) ease;
+ }
+
+ h1 {
+ font-size: 2.2em;
+ margin-top: 0;
+ }
+
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ margin-bottom: 12px;
+ margin-top: 24px;
+ }
+
+ h1 {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ h2 {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ h3 {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ h4 {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ h5 {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ h6 {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ strong {
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6,
+ b,
+ strong,
+ th {
+ font-weight: 600;
+ }
+
+ q::before {
+ content: none;
+ }
+
+ q::after {
+ content: none;
+ }
+
+ blockquote {
+ border-left: 4px solid #0096bfab;
+ border-left: 4px solid var(--focus);
+ margin: 1.5em 0;
+ padding: 0.5em 1em;
+ font-style: italic;
+ }
+
+ q {
+ border-left: 4px solid #0096bfab;
+ border-left: 4px solid var(--focus);
+ margin: 1.5em 0;
+ padding: 0.5em 1em;
+ font-style: italic;
+ }
+
+ blockquote > footer {
+ font-style: normal;
+ border: 0;
+ }
+
+ blockquote cite {
+ font-style: normal;
+ }
+
+ address {
+ font-style: normal;
+ }
+
+ a[href^='mailto\:']::before {
+ content: '📧 ';
+ }
+
+ a[href^='tel\:']::before {
+ content: '📞 ';
+ }
+
+ a[href^='sms\:']::before {
+ content: '💬 ';
+ }
+
+ mark {
+ background-color: #efdb43;
+ background-color: var(--highlight);
+ border-radius: 2px;
+ padding: 0 2px 0 2px;
+ color: #000;
+ }
+
+ a > code,
+ a > strong {
+ color: inherit;
+ }
+
+ button,
+ select,
+ input[type='submit'],
+ input[type='reset'],
+ input[type='button'],
+ input[type='checkbox'],
+ input[type='range'],
+ input[type='radio'] {
+ cursor: pointer;
+ }
+
+ input,
+ select {
+ display: block;
+ }
+
+ [type='checkbox'],
+ [type='radio'] {
+ display: initial;
+ }
+
+ input {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+ }
+
+ button {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+ }
+
+ textarea {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+ }
+
+ select {
+ color: #fff;
+ color: var(--form-text);
+ background-color: #161f27;
+ background-color: var(--background);
+ font-family: inherit;
+ font-size: inherit;
+ margin-right: 6px;
+ margin-bottom: 6px;
+ padding: 10px;
+ border: none;
+ border-radius: 6px;
+ outline: none;
+ }
+
+ button {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+ }
+
+ input[type='submit'] {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+ }
+
+ input[type='reset'] {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+ }
+
+ input[type='button'] {
+ background-color: #0c151c;
+ background-color: var(--button-base);
+ padding-right: 30px;
+ padding-left: 30px;
+ }
+
+ button:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+ }
+
+ input[type='submit']:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+ }
+
+ input[type='reset']:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+ }
+
+ input[type='button']:hover {
+ background: #040a0f;
+ background: var(--button-hover);
+ }
+
+ input[type='color'] {
+ min-height: 2rem;
+ padding: 8px;
+ cursor: pointer;
+ }
+
+ input[type='checkbox'],
+ input[type='radio'] {
+ height: 1em;
+ width: 1em;
+ }
+
+ input[type='radio'] {
+ border-radius: 100%;
+ }
+
+ input {
+ vertical-align: top;
+ }
+
+ label {
+ vertical-align: middle;
+ margin-bottom: 4px;
+ display: inline-block;
+ }
+
+ input:not([type='checkbox']):not([type='radio']),
+ input[type='range'],
+ select,
+ button,
+ textarea {
+ -webkit-appearance: none;
+ }
+
+ textarea {
+ display: block;
+ margin-right: 0;
+ box-sizing: border-box;
+ resize: vertical;
+ }
+
+ textarea:not([cols]) {
+ width: 100%;
+ }
+
+ textarea:not([rows]) {
+ min-height: 40px;
+ height: 140px;
+ }
+
+ select {
+ background: #161f27 url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat;
+ background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat;
+ padding-right: 35px;
+ }
+
+ select::-ms-expand {
+ display: none;
+ }
+
+ select[multiple] {
+ padding-right: 10px;
+ background-image: none;
+ overflow-y: auto;
+ }
+
+ input:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+ }
+
+ select:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+ }
+
+ button:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+ }
+
+ textarea:focus {
+ box-shadow: 0 0 0 2px #0096bfab;
+ box-shadow: 0 0 0 2px var(--focus);
+ }
+
+ input[type='checkbox']:active,
+ input[type='radio']:active,
+ input[type='submit']:active,
+ input[type='reset']:active,
+ input[type='button']:active,
+ input[type='range']:active,
+ button:active {
+ transform: translateY(2px);
+ }
+
+ input:disabled,
+ select:disabled,
+ button:disabled,
+ textarea:disabled {
+ cursor: not-allowed;
+ opacity: 0.5;
+ }
+
+ ::-moz-placeholder {
+ color: #a9a9a9;
+ color: var(--form-placeholder);
+ }
+
+ :-ms-input-placeholder {
+ color: #a9a9a9;
+ color: var(--form-placeholder);
+ }
+
+ ::-ms-input-placeholder {
+ color: #a9a9a9;
+ color: var(--form-placeholder);
+ }
+
+ ::placeholder {
+ color: #a9a9a9;
+ color: var(--form-placeholder);
+ }
+
+ fieldset {
+ border: 1px #0096bfab solid;
+ border: 1px var(--focus) solid;
+ border-radius: 6px;
+ margin: 0;
+ margin-bottom: 12px;
+ padding: 10px;
+ }
+
+ legend {
+ font-size: 0.9em;
+ font-weight: 600;
+ }
+
+ input[type='range'] {
+ margin: 10px 0;
+ padding: 10px 0;
+ background: transparent;
+ }
+
+ input[type='range']:focus {
+ outline: none;
+ }
+
+ input[type='range']::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 9.5px;
+ -webkit-transition: 0.2s;
+ transition: 0.2s;
+ background: #161f27;
+ background: var(--background);
+ border-radius: 3px;
+ }
+
+ input[type='range']::-webkit-slider-thumb {
+ box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ background: #526980;
+ background: var(--border);
+ -webkit-appearance: none;
+ margin-top: -7px;
+ }
+
+ input[type='range']:focus::-webkit-slider-runnable-track {
+ background: #161f27;
+ background: var(--background);
+ }
+
+ input[type='range']::-moz-range-track {
+ width: 100%;
+ height: 9.5px;
+ -moz-transition: 0.2s;
+ transition: 0.2s;
+ background: #161f27;
+ background: var(--background);
+ border-radius: 3px;
+ }
+
+ input[type='range']::-moz-range-thumb {
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ background: #526980;
+ background: var(--border);
+ }
+
+ input[type='range']::-ms-track {
+ width: 100%;
+ height: 9.5px;
+ background: transparent;
+ border-color: transparent;
+ border-width: 16px 0;
+ color: transparent;
+ }
+
+ input[type='range']::-ms-fill-lower {
+ background: #161f27;
+ background: var(--background);
+ border: 0.2px solid #010101;
+ border-radius: 3px;
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+ }
+
+ input[type='range']::-ms-fill-upper {
+ background: #161f27;
+ background: var(--background);
+ border: 0.2px solid #010101;
+ border-radius: 3px;
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+ }
+
+ input[type='range']::-ms-thumb {
+ box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
+ border: 1px solid #000;
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ background: #526980;
+ background: var(--border);
+ }
+
+ input[type='range']:focus::-ms-fill-lower {
+ background: #161f27;
+ background: var(--background);
+ }
+
+ input[type='range']:focus::-ms-fill-upper {
+ background: #161f27;
+ background: var(--background);
+ }
+
+ a {
+ text-decoration: none;
+ color: #41adff;
+ color: var(--links);
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ code {
+ background: #161f27;
+ background: var(--background);
+ color: #ffbe85;
+ color: var(--code);
+ padding: 2.5px 5px;
+ border-radius: 6px;
+ font-size: 1em;
+ }
+
+ samp {
+ background: #161f27;
+ background: var(--background);
+ color: #ffbe85;
+ color: var(--code);
+ padding: 2.5px 5px;
+ border-radius: 6px;
+ font-size: 1em;
+ }
+
+ time {
+ background: #161f27;
+ background: var(--background);
+ color: #ffbe85;
+ color: var(--code);
+ padding: 2.5px 5px;
+ border-radius: 6px;
+ font-size: 1em;
+ }
+
+ pre > code {
+ padding: 10px;
+ display: block;
+ overflow-x: auto;
+ }
+
+ var {
+ color: #d941e2;
+ color: var(--variable);
+ font-style: normal;
+ font-family: monospace;
+ }
+
+ kbd {
+ background: #161f27;
+ background: var(--background);
+ border: 1px solid #526980;
+ border: 1px solid var(--border);
+ border-radius: 2px;
+ color: #dbdbdb;
+ color: var(--text-main);
+ padding: 2px 4px 2px 4px;
+ }
+
+ img,
+ video {
+ max-width: 100%;
+ height: auto;
+ }
+
+ hr {
+ border: none;
+ border-top: 1px solid #526980;
+ border-top: 1px solid var(--border);
+ }
+
+ table {
+ border-collapse: collapse;
+ margin-bottom: 10px;
+ width: 100%;
+ table-layout: fixed;
+ }
+
+ table caption {
+ text-align: left;
+ }
+
+ td,
+ th {
+ padding: 6px;
+ text-align: left;
+ vertical-align: top;
+ word-wrap: break-word;
+ }
+
+ thead {
+ border-bottom: 1px solid #526980;
+ border-bottom: 1px solid var(--border);
+ }
+
+ tfoot {
+ border-top: 1px solid #526980;
+ border-top: 1px solid var(--border);
+ }
+
+ tbody tr:nth-child(even) {
+ background-color: #161f27;
+ background-color: var(--background);
+ }
+
+ tbody tr:nth-child(even) button {
+ background-color: #1a242f;
+ background-color: var(--background-alt);
+ }
+
+ tbody tr:nth-child(even) button:hover {
+ background-color: #202b38;
+ background-color: var(--background-body);
+ }
+
+ ::-webkit-scrollbar {
+ height: 10px;
+ width: 10px;
+ }
+
+ ::-webkit-scrollbar-track {
+ background: #161f27;
+ background: var(--background);
+ border-radius: 6px;
+ }
+
+ ::-webkit-scrollbar-thumb {
+ background: #040a0f;
+ background: var(--scrollbar-thumb);
+ border-radius: 6px;
+ }
+
+ ::-webkit-scrollbar-thumb:hover {
+ background: rgb(0, 0, 0);
+ background: var(--scrollbar-thumb-hover);
+ }
+
+ ::-moz-selection {
+ background-color: #1c76c5;
+ background-color: var(--selection);
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ ::selection {
+ background-color: #1c76c5;
+ background-color: var(--selection);
+ color: #fff;
+ color: var(--text-bright);
+ }
+
+ details {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ background-color: #1a242f;
+ background-color: var(--background-alt);
+ padding: 10px 10px 0;
+ margin: 1em 0;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ details[open] {
+ padding: 10px;
+ }
+
+ details > :last-child {
+ margin-bottom: 0;
+ }
+
+ details[open] summary {
+ margin-bottom: 10px;
+ }
+
+ summary {
+ display: list-item;
+ background-color: #161f27;
+ background-color: var(--background);
+ padding: 10px;
+ margin: -10px -10px 0;
+ cursor: pointer;
+ outline: none;
+ }
+
+ summary:hover,
+ summary:focus {
+ text-decoration: underline;
+ }
+
+ details > :not(summary) {
+ margin-top: 0;
+ }
+
+ summary::-webkit-details-marker {
+ color: #dbdbdb;
+ color: var(--text-main);
+ }
+
+ dialog {
+ background-color: #1a242f;
+ background-color: var(--background-alt);
+ color: #dbdbdb;
+ color: var(--text-main);
+ border: none;
+ border-radius: 6px;
+ border-color: #526980;
+ border-color: var(--border);
+ padding: 10px 30px;
+ }
+
+ dialog > header:first-child {
+ background-color: #161f27;
+ background-color: var(--background);
+ border-radius: 6px 6px 0 0;
+ margin: -10px -30px 10px;
+ padding: 10px;
+ text-align: center;
+ }
+
+ dialog::-webkit-backdrop {
+ background: #0000009c;
+ -webkit-backdrop-filter: blur(4px);
+ backdrop-filter: blur(4px);
+ }
+
+ dialog::backdrop {
+ background: #0000009c;
+ -webkit-backdrop-filter: blur(4px);
+ backdrop-filter: blur(4px);
+ }
+
+ footer {
+ border-top: 1px solid #526980;
+ border-top: 1px solid var(--border);
+ padding-top: 10px;
+ color: #a9b1ba;
+ color: var(--text-muted);
+ }
+
+ body > footer {
+ margin-top: 40px;
+ }
+
+ @media print {
+ body,
+ pre,
+ code,
+ summary,
+ details,
+ button,
+ input,
+ textarea {
+ background-color: #fff;
+ }
+
+ button,
+ input,
+ textarea {
+ border: 1px solid #000;
+ }
+
+ body,
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6,
+ pre,
+ code,
+ button,
+ input,
+ textarea,
+ footer,
+ summary,
+ strong {
+ color: #000;
+ }
+
+ summary::marker {
+ color: #000;
+ }
+
+ summary::-webkit-details-marker {
+ color: #000;
+ }
+
+ tbody tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+
+ a {
+ color: #00f;
+ text-decoration: underline;
+ }
+ }
diff --git a/e2e/react/src/utils/routes.ts b/e2e/react/src/utils/routes.ts
index 9d1040ab7..481cbbcf1 100644
--- a/e2e/react/src/utils/routes.ts
+++ b/e2e/react/src/utils/routes.ts
@@ -1,7 +1,15 @@
export const routes = {
hello: '/hello-world',
- scalars: 'scalars',
+ scalars: '/scalars',
componentFields_simple: '/component_fields/simple',
componentFields_arguments: '/component_fields/arguments',
route_params: '/route_params/1',
-}
+ handle_1: '/handle/1',
+ handle_2: '/handle/2',
+ pagination_query_backwards: '/pagination/query/connection-backwards',
+ pagination_query_forwards: '/pagination/query/connection-forwards',
+ pagination_query_bidirectional: '/pagination/query/connection-bidirectional',
+ pagination_query_offset: '/pagination/query/offset',
+ pagination_query_offset_singlepage: '/pagination/query/offset-singlepage',
+ pagination_query_offset_variable: '/pagination/query/offset-variable/2',
+} as const
diff --git a/e2e/react/src/utils/testsHelper.ts b/e2e/react/src/utils/testsHelper.ts
index 0d8adadb7..976cf5840 100644
--- a/e2e/react/src/utils/testsHelper.ts
+++ b/e2e/react/src/utils/testsHelper.ts
@@ -53,16 +53,9 @@ export async function expect_n_gql(
let nbResponse = 0
const listStr: string[] = []
- // function fnReq(request: any) {
- // // console.log('>>', request.method(), request.url());
- // if (request.url().endsWith(routes.GraphQL)) {
- // nbRequest++;
- // }
- // }
-
async function fnRes(response: Response) {
// console.log('<<', response.status(), response.url());
- if (response.url().endsWith('/_api')) {
+ if (response.url().endsWith('/graphql')) {
timing.push(new Date().valueOf() - start)
try {
const json = await response.json()
@@ -171,12 +164,8 @@ export async function locator_click(page: Page, selector: string) {
* By default goto expect NO graphql response, if you expect some, use: `goto_expect_n_gql`
* @returns The response of the page
*/
-export async function goto(
- page: Page,
- url: string,
- waitUntil: 'domcontentloaded' | 'load' | 'networkidle' | 'commit' = 'domcontentloaded'
-): Promise
{
- const res = await page.goto(url, { waitUntil })
+export async function goto(page: Page, url: string): Promise {
+ const res = await page.goto(url, { waitUntil: 'domcontentloaded' })
await expect_n_gql(page, null, 0)
return res
}
diff --git a/e2e/react/vite.config.ts b/e2e/react/vite.config.ts
index 1102503b2..9c34cc985 100644
--- a/e2e/react/vite.config.ts
+++ b/e2e/react/vite.config.ts
@@ -5,5 +5,8 @@ import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
+ server: {
+ port: process.env.PORT ? parseInt(process.env.PORT) : 5173,
+ },
plugins: [houdini({ adapter }), react({ fastRefresh: false })],
})
diff --git a/packages/create-houdini/templates/react-typescript/package.json b/packages/create-houdini/templates/react-typescript/package.json
index 3cce7786e..e34f760d6 100644
--- a/packages/create-houdini/templates/react-typescript/package.json
+++ b/packages/create-houdini/templates/react-typescript/package.json
@@ -12,8 +12,8 @@
"houdini": "^HOUDINI_VERSION",
"houdini-react": "^HOUDINI_VERSION",
"houdini-adapter-auto": "^HOUDINI_VERSION",
- "react": "^18.3.0-canary-09fbee89d-20231013",
- "react-dom": "^18.3.0-canary-09fbee89d-20231013",
+ "react": "19.0.0-canary-2b036d3f1-20240327",
+ "react-dom": "19.0.0-canary-2b036d3f1-20240327",
"graphql-yoga": "4.0.4",
"graphql": "15.8.0",
"@whatwg-node/server": "^0.9.14"
@@ -27,7 +27,7 @@
},
"resolutions": {
"graphql": "15.8.0",
- "react": "18.3.0-canary-09fbee89d-20231013",
- "react-dom": "18.3.0-canary-09fbee89d-20231013"
+ "react": "19.0.0-canary-2b036d3f1-20240327",
+ "react-dom": "19.0.0-canary-2b036d3f1-20240327"
}
}
diff --git a/packages/create-houdini/templates/react/package.json b/packages/create-houdini/templates/react/package.json
index 4f4ea50f5..9ca1789e7 100644
--- a/packages/create-houdini/templates/react/package.json
+++ b/packages/create-houdini/templates/react/package.json
@@ -12,8 +12,8 @@
"houdini": "^HOUDINI_VERSION",
"houdini-react": "^HOUDINI_VERSION",
"houdini-adapter-auto": "^HOUDINI_VERSION",
- "react": "^18.3.0-canary-09fbee89d-20231013",
- "react-dom": "^18.3.0-canary-09fbee89d-20231013",
+ "react": "19.0.0-canary-2b036d3f1-20240327",
+ "react-dom": "19.0.0-canary-2b036d3f1-20240327",
"graphql-yoga": "4.0.4",
"graphql": "15.8.0",
"@whatwg-node/server": "^0.9.14"
@@ -24,7 +24,7 @@
},
"resolutions": {
"graphql": "15.8.0",
- "react": "18.3.0-canary-09fbee89d-20231013",
- "react-dom": "18.3.0-canary-09fbee89d-20231013"
+ "react": "19.0.0-canary-2b036d3f1-20240327",
+ "react-dom": "19.0.0-canary-2b036d3f1-20240327"
}
}
diff --git a/packages/houdini-react/package.json b/packages/houdini-react/package.json
index c5b8973cd..764c248c5 100644
--- a/packages/houdini-react/package.json
+++ b/packages/houdini-react/package.json
@@ -42,8 +42,8 @@
"graphql": "^15.8.0",
"graphql-yoga": "^4.0.4",
"houdini": "workspace:^",
- "react": "18.3.0-canary-09fbee89d-20231013",
- "react-dom": "18.3.0-canary-09fbee89d-20231013",
+ "react": "19.0.0-canary-2b036d3f1-20240327",
+ "react-dom": "19.0.0-canary-2b036d3f1-20240327",
"react-streaming-compat": "^0.3.18",
"recast": "^0.23.1",
"rollup": "^3.7.4",
diff --git a/packages/houdini-react/src/plugin/vite.tsx b/packages/houdini-react/src/plugin/vite.tsx
index 99d63c8b8..4d8ee1bc2 100644
--- a/packages/houdini-react/src/plugin/vite.tsx
+++ b/packages/houdini-react/src/plugin/vite.tsx
@@ -261,6 +261,12 @@ export default {
initialVariables: variables,
})
+ // initialize the observer we just created
+ observer.send({
+ setup: true,
+ variables,
+ })
+
// save it in the cache
initialData[artifactName] = observer
initialVariables[artifactName] = variables
diff --git a/packages/houdini-react/src/runtime/clientPlugin.ts b/packages/houdini-react/src/runtime/clientPlugin.ts
index 22a26381a..733557c01 100644
--- a/packages/houdini-react/src/runtime/clientPlugin.ts
+++ b/packages/houdini-react/src/runtime/clientPlugin.ts
@@ -6,7 +6,7 @@ const plugin: () => ClientPlugin = () => () => {
next({
...ctx,
cacheParams: {
- ...ctx.fetchParams,
+ ...ctx.cacheParams,
serverSideFallback: false,
},
})
diff --git a/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts b/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts
index 787d9be92..8580449a1 100644
--- a/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts
+++ b/packages/houdini-react/src/runtime/hooks/useDocumentHandle.ts
@@ -15,7 +15,7 @@ import type {
} from '$houdini/runtime/lib/types'
import React from 'react'
-import { useSession } from '../routing/Router'
+import { useClient, useSession } from '../routing/Router'
export function useDocumentHandle<
_Artifact extends QueryArtifact,
@@ -36,6 +36,17 @@ export function useDocumentHandle<
// grab the current session value
const [session] = useSession()
+ // we want to use a separate observer for pagination queries
+ const client = useClient()
+ const paginationObserver = React.useMemo(() => {
+ // if the artifact doesn't support pagination, don't do anything
+ if (!artifact.refetch?.paginated) {
+ return null
+ }
+
+ return client.observe<_Data, _Input>({ artifact })
+ }, [artifact.name])
+
// @ts-expect-error: avoiding an as DocumentHandle<_Artifact, _Data, _Input>
return React.useMemo>(() => {
const wrapLoad = <_Result>(
@@ -60,7 +71,9 @@ export function useDocumentHandle<
// only consider paginated queries
if (artifact.kind !== ArtifactKind.Query || !artifact.refetch?.paginated) {
return {
+ artifact,
data: storeValue.data,
+ variables: storeValue.variables,
fetch: fetchQuery,
partial: storeValue.partial,
}
@@ -74,12 +87,12 @@ export function useDocumentHandle<
getVariables: () => storeValue.variables!,
fetch: fetchQuery,
fetchUpdate: (args, updates) => {
- return observer.send({
+ return paginationObserver!.send({
...args,
cacheParams: {
+ ...args?.cacheParams,
disableSubscriptions: true,
applyUpdates: updates,
- ...args?.cacheParams,
},
session,
})
@@ -88,7 +101,9 @@ export function useDocumentHandle<
})
return {
+ artifact,
data: storeValue.data,
+ variables: storeValue.variables,
fetch: handlers.fetch,
partial: storeValue.partial,
loadNext: wrapLoad(setForwardPending, handlers.loadNextPage),
@@ -107,7 +122,7 @@ export function useDocumentHandle<
storeName: artifact.name,
fetch: fetchQuery,
fetchUpdate: async (args, updates = ['append']) => {
- return observer.send({
+ return paginationObserver!.send({
...args,
cacheParams: {
disableSubscriptions: true,
@@ -120,7 +135,9 @@ export function useDocumentHandle<
})
return {
+ artifact,
data: storeValue.data,
+ variables: storeValue.variables,
fetch: handlers.fetch,
partial: storeValue.partial,
loadNext: wrapLoad(setForwardPending, handlers.loadNextPage),
@@ -130,12 +147,14 @@ export function useDocumentHandle<
// we don't want to add anything
return {
+ artifact,
data: storeValue.data,
+ variables: storeValue.variables,
fetch: fetchQuery,
refetch: fetchQuery,
partial: storeValue.partial,
}
- }, [artifact, observer, session, storeValue, true, true])
+ }, [artifact, observer, session, storeValue])
}
export type DocumentHandle<
@@ -145,6 +164,8 @@ export type DocumentHandle<
> = {
data: _Data
partial: boolean
+ fetch: FetchFn<_Data, Partial<_Input>>
+ variables: _Input
} & RefetchHandlers<_Artifact, _Data, _Input>
type RefetchHandlers<_Artifact extends QueryArtifact, _Data extends GraphQLObject, _Input> =
diff --git a/packages/houdini-react/src/runtime/hooks/useQueryHandle.ts b/packages/houdini-react/src/runtime/hooks/useQueryHandle.ts
index 66a2c6657..ad7af0045 100644
--- a/packages/houdini-react/src/runtime/hooks/useQueryHandle.ts
+++ b/packages/houdini-react/src/runtime/hooks/useQueryHandle.ts
@@ -133,6 +133,7 @@ export function useQueryHandle<
},
})
.then((value) => {
+ // @ts-expect-error
// the final value
suspenseUnit.resolved = {
...handle,
@@ -155,7 +156,7 @@ export function useQueryHandle<
// make sure we prefer the latest store value instead of the initial version we loaded on mount
if (!result && suspenseValue?.resolved) {
- return suspenseValue.resolved as DocumentHandle<_Artifact, _Data, _Input>
+ return suspenseValue.resolved as unknown as DocumentHandle<_Artifact, _Data, _Input>
}
return {
diff --git a/packages/houdini-react/src/runtime/routing/Router.tsx b/packages/houdini-react/src/runtime/routing/Router.tsx
index b2a4ae08a..6affa1a21 100644
--- a/packages/houdini-react/src/runtime/routing/Router.tsx
+++ b/packages/houdini-react/src/runtime/routing/Router.tsx
@@ -11,6 +11,7 @@ import type { RouterManifest, RouterPageManifest } from '$houdini/runtime/router
import React from 'react'
import { useContext } from 'react'
+import { DocumentHandle, useDocumentHandle } from '../hooks/useDocumentHandle'
import { useDocumentStore } from '../hooks/useDocumentStore'
import { SuspenseCache, suspense_cache } from './cache'
@@ -50,7 +51,7 @@ export function Router({
})
// find the matching page for the current route
- const [page, variables] = find_match(manifest, currentURL)
+ const [page, variables] = find_match(configFile, manifest, currentURL)
// if we dont have a page, its a 404
if (!page) {
throw new Error('404')
@@ -108,7 +109,7 @@ export function Router({
// there are 2 things that we could preload: the page component and the data
// look for the matching route information
- const [page, variables] = find_match(manifest, url)
+ const [page, variables] = find_match(configFile, manifest, url)
// load the page component if necessary
if (['both', 'component'].includes(which)) {
@@ -199,7 +200,6 @@ function usePageData({
observer
.send({
variables: variables,
- cacheParams: { disableSubscriptions: true },
session,
})
.then(async () => {
@@ -246,9 +246,10 @@ function usePageData({
config: configFile,
})
)}
+ }).then(() => {
+ window.__houdini__nav_caches__?.data_cache.set(artifactName, new_store)
})
- window.__houdini__nav_caches__?.data_cache.set(artifactName, new_store)
}
@@ -589,23 +590,35 @@ const LocationContext = React.createContext<{ pathname: string; params: Record(
name: string
-): [_Data | null, DocumentStore<_Data, _Input>] {
- const store_ref = useRouterContext().data_cache.get(name)! as unknown as DocumentStore<
- _Data,
- _Input
- >
+): [_Data | null, DocumentHandle] {
+ // pull the global context values
+ const { data_cache, artifact_cache } = useRouterContext()
+
+ // load the store reference (this will suspend)
+ const store_ref = data_cache.get(name)! as unknown as DocumentStore<_Data, _Input>
+
// get the live data from the store
- const [{ data, errors }, observer] = useDocumentStore<_Data, _Input>({
+ const [storeValue, observer] = useDocumentStore<_Data, _Input>({
artifact: store_ref.artifact,
observer: store_ref,
})
+ // pull out the store values we care about
+ const { data, errors } = storeValue
+
// if there is an error in the response we need to throw to the nearest boundary
if (errors && errors.length > 0) {
throw new Error(JSON.stringify(errors))
}
+ // create the handle that we will use to interact with the store
+ const handle = useDocumentHandle({
+ artifact: artifact_cache.get(name)!,
+ observer,
+ storeValue,
+ })
- return [data, observer]
+ // we're done
+ return [data, handle]
}
function useLinkBehavior({
diff --git a/packages/houdini/src/lib/router/manifest.test.ts b/packages/houdini/src/lib/router/manifest.test.ts
index 2a2b35be8..19aa135b6 100644
--- a/packages/houdini/src/lib/router/manifest.test.ts
+++ b/packages/houdini/src/lib/router/manifest.test.ts
@@ -614,6 +614,27 @@ describe('extractQueries', async () => {
`,
expected: ['title', 'content'],
},
+ {
+ name: '$handle',
+ source: `
+ import React from 'react';
+
+ interface Props {
+ title: string;
+ content: string;
+ }
+
+ const MyComponent = ({ title$handle }: Props) => (
+
+ );
+
+ export default MyComponent;
+ `,
+ expected: ['title'],
+ },
{
name: 'Functional component with function expression',
source: `
@@ -658,6 +679,20 @@ describe('extractQueries', async () => {
`,
expected: ['firstName', 'lastName'],
},
+ {
+ name: "handle and query don't duplicate",
+ source: `
+ import React from 'react';
+
+ export default function({ Query, Query$handle }) {
+ return (
+
+
+ );
+ };
+ `,
+ expected: ['Query'],
+ },
]
for (const testCase of testCases) {
diff --git a/packages/houdini/src/lib/router/manifest.ts b/packages/houdini/src/lib/router/manifest.ts
index ffec4f2c5..4c9bcd7a7 100644
--- a/packages/houdini/src/lib/router/manifest.ts
+++ b/packages/houdini/src/lib/router/manifest.ts
@@ -225,6 +225,7 @@ async function add_view(args: {
}) {
const target = args.type === 'page' ? args.project.pages : args.project.layouts
const queries = await extractQueries(args.contents)
+
// look for any queries that we are asking for that aren't available
const missing_queries = queries.filter((query) => !args.queries.includes(query))
if (missing_queries.length > 0) {
@@ -387,5 +388,22 @@ export async function extractQueries(source: string): Promise {
return []
}
- return props.filter((p) => p !== 'children')
+ return props.reduce((queries, query) => {
+ // skip the children prop
+ if (query === 'children') {
+ return queries
+ }
+
+ // if the query ends with $handle just use the query name
+ if (query.endsWith('$handle')) {
+ query = query.substring(0, query.length - '$handle'.length)
+ }
+
+ // if the query already exists, don't add it again
+ if (queries.includes(query)) {
+ return queries
+ }
+
+ return queries.concat([query])
+ }, [])
}
diff --git a/packages/houdini/src/runtime/router/match.test.ts b/packages/houdini/src/runtime/router/match.test.ts
index f0022225e..b7a54592f 100644
--- a/packages/houdini/src/runtime/router/match.test.ts
+++ b/packages/houdini/src/runtime/router/match.test.ts
@@ -1,5 +1,6 @@
import { test, expect, describe } from 'vitest'
+import { testConfigFile } from '../../test'
import { exec, find_match, parse_page_pattern } from './match'
import type { RouterManifest } from './types'
@@ -137,8 +138,10 @@ describe('find_match parse and match', async function () {
),
}
+ const configFile = testConfigFile()
+
// find the match
- const [match] = find_match(manifest, expected)
+ const [match] = find_match(configFile, manifest, expected)
expect(match?.id).toEqual(expected)
})
}
diff --git a/packages/houdini/src/runtime/router/match.ts b/packages/houdini/src/runtime/router/match.ts
index cb48272f2..d084917c9 100644
--- a/packages/houdini/src/runtime/router/match.ts
+++ b/packages/houdini/src/runtime/router/match.ts
@@ -1,5 +1,6 @@
import type { GraphQLVariables } from '$houdini/runtime/lib/types'
+import { parseScalar, type ConfigFile } from '../lib'
import type { RouterManifest, RouterPageManifest } from './types'
/**
@@ -21,16 +22,19 @@ export interface ParamMatcher {
// find the matching page given the current path
export function find_match<_ComponentType>(
+ config: ConfigFile,
manifest: RouterManifest<_ComponentType>,
current: string,
allowNull: true
): [RouterPageManifest<_ComponentType> | null, GraphQLVariables]
export function find_match<_ComponentType>(
+ config: ConfigFile,
manifest: RouterManifest<_ComponentType>,
current: string,
allowNull?: false
): [RouterPageManifest<_ComponentType>, GraphQLVariables]
export function find_match<_ComponentType>(
+ config: ConfigFile,
manifest: RouterManifest<_ComponentType>,
current: string,
allowNull: boolean = true
@@ -38,6 +42,7 @@ export function find_match<_ComponentType>(
// find the matching path (if it exists)
let match: RouterPageManifest<_ComponentType> | null = null
let matchVariables: GraphQLVariables = null
+
for (const page of Object.values(manifest.pages)) {
// check if the current url matches
const urlMatch = current.match(page.pattern)
@@ -55,8 +60,21 @@ export function find_match<_ComponentType>(
throw new Error('404')
}
+ // we might have to marshal the variables
+ let variables: GraphQLVariables = {}
+ // each of the matched documents might tell us how to handle a subset of the
+ // matchVariables. look at every document's input specification and marshal
+ // any values that are in matchVariables
+ for (const document of Object.values(match?.documents ?? {})) {
+ for (const [variable, { type }] of Object.entries(document.variables)) {
+ if (matchVariables?.[variable]) {
+ variables[variable] = parseScalar(config, type, matchVariables[variable])
+ }
+ }
+ }
+
// @ts-ignore
- return [match, matchVariables]
+ return [match, variables]
}
/**
diff --git a/packages/houdini/src/runtime/router/server.ts b/packages/houdini/src/runtime/router/server.ts
index 69f4f0d37..d96930df7 100644
--- a/packages/houdini/src/runtime/router/server.ts
+++ b/packages/houdini/src/runtime/router/server.ts
@@ -87,7 +87,7 @@ export function _serverHandler({
// the request is for a server-side rendered page
// find the matching url
- const [match] = find_match(manifest, url)
+ const [match] = find_match(config_file, manifest, url)
// call the framework-specific render hook with the latest session
const rendered = await on_render({
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f12615edf..c19b5676c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -566,14 +566,14 @@ importers:
specifier: workspace:^
version: link:../houdini
react:
- specifier: 18.3.0-canary-09fbee89d-20231013
- version: 18.3.0-canary-09fbee89d-20231013
+ specifier: 19.0.0-canary-2b036d3f1-20240327
+ version: 19.0.0-canary-2b036d3f1-20240327
react-dom:
- specifier: 18.3.0-canary-09fbee89d-20231013
- version: 18.3.0-canary-09fbee89d-20231013(react@18.3.0-canary-09fbee89d-20231013)
+ specifier: 19.0.0-canary-2b036d3f1-20240327
+ version: 19.0.0-canary-2b036d3f1-20240327(react@19.0.0-canary-2b036d3f1-20240327)
react-streaming-compat:
specifier: ^0.3.18
- version: 0.3.18(react-dom@18.3.0-canary-09fbee89d-20231013)(react@18.3.0-canary-09fbee89d-20231013)
+ version: 0.3.18(react-dom@19.0.0-canary-2b036d3f1-20240327)(react@19.0.0-canary-2b036d3f1-20240327)
recast:
specifier: ^0.23.1
version: 0.23.1
@@ -582,7 +582,7 @@ importers:
version: 3.14.0
use-deep-compare-effect:
specifier: ^1.8.1
- version: 1.8.1(react@18.3.0-canary-09fbee89d-20231013)
+ version: 1.8.1(react@19.0.0-canary-2b036d3f1-20240327)
devDependencies:
'@types/cookie-parser':
specifier: ^1.4.3
@@ -607,7 +607,7 @@ importers:
version: 18.0.11
next:
specifier: ^13.0.1
- version: 13.1.1(@babel/core@7.20.7)(react-dom@18.3.0-canary-09fbee89d-20231013)(react@18.3.0-canary-09fbee89d-20231013)
+ version: 13.1.1(@babel/core@7.20.7)(react-dom@19.0.0-canary-2b036d3f1-20240327)(react@19.0.0-canary-2b036d3f1-20240327)
scripts:
specifier: workspace:^
version: link:../_scripts
@@ -8750,7 +8750,7 @@ packages:
engines: {node: '>= 0.6'}
dev: false
- /next@13.1.1(@babel/core@7.20.7)(react-dom@18.3.0-canary-09fbee89d-20231013)(react@18.3.0-canary-09fbee89d-20231013):
+ /next@13.1.1(@babel/core@7.20.7)(react-dom@19.0.0-canary-2b036d3f1-20240327)(react@19.0.0-canary-2b036d3f1-20240327):
resolution: {integrity: sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==}
engines: {node: '>=14.6.0'}
hasBin: true
@@ -8772,9 +8772,9 @@ packages:
'@swc/helpers': 0.4.14
caniuse-lite: 1.0.30001441
postcss: 8.4.14
- react: 18.3.0-canary-09fbee89d-20231013
- react-dom: 18.3.0-canary-09fbee89d-20231013(react@18.3.0-canary-09fbee89d-20231013)
- styled-jsx: 5.1.1(@babel/core@7.20.7)(react@18.3.0-canary-09fbee89d-20231013)
+ react: 19.0.0-canary-2b036d3f1-20240327
+ react-dom: 19.0.0-canary-2b036d3f1-20240327(react@19.0.0-canary-2b036d3f1-20240327)
+ styled-jsx: 5.1.1(@babel/core@7.20.7)(react@19.0.0-canary-2b036d3f1-20240327)
optionalDependencies:
'@next/swc-android-arm-eabi': 13.1.1
'@next/swc-android-arm64': 13.1.1
@@ -9483,7 +9483,7 @@ packages:
/puppeteer@1.20.0:
resolution: {integrity: sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==}
engines: {node: '>=6.4.0'}
- deprecated: < 21.5.0 is no longer supported
+ deprecated: < 21.8.0 is no longer supported
requiresBuild: true
dependencies:
debug: 4.3.4(supports-color@9.3.1)
@@ -9570,15 +9570,6 @@ packages:
scheduler: 0.19.1
dev: true
- /react-dom@18.3.0-canary-09fbee89d-20231013(react@18.3.0-canary-09fbee89d-20231013):
- resolution: {integrity: sha512-whQiynFSqI6eQ2KuiQm0lxM10XmMfHzEGN+Z4qGzyQ+hUz8d53rPN2EfmHjQc5GUvqL7z6et7W5d3BeWX69vog==}
- peerDependencies:
- react: 18.3.0-canary-09fbee89d-20231013
- dependencies:
- loose-envify: 1.4.0
- react: 18.3.0-canary-09fbee89d-20231013
- scheduler: 0.24.0-canary-09fbee89d-20231013
-
/react-dom@18.3.0-canary-d6dcad6a8-20230914(react@18.3.0-canary-d7a98a5e9-20230517):
resolution: {integrity: sha512-KzS+Jy/WXC6I9bi9PtBU0+iMPHPNvNLdyIDJqgX91AiBP9IDDMjaDbgW0QKphi1qIOesYMeJz0uZkajhlfS8lg==}
peerDependencies:
@@ -9589,6 +9580,14 @@ packages:
scheduler: 0.24.0-canary-d6dcad6a8-20230914
dev: false
+ /react-dom@19.0.0-canary-2b036d3f1-20240327(react@19.0.0-canary-2b036d3f1-20240327):
+ resolution: {integrity: sha512-pxGk4bDSRFDqVa+hAdkTva+EdMbrxC0X1mR1QC1comx2U2EQfocy1SySSa//m3ivU674sYW7saKDo/fQV8rprw==}
+ peerDependencies:
+ react: 19.0.0-canary-2b036d3f1-20240327
+ dependencies:
+ react: 19.0.0-canary-2b036d3f1-20240327
+ scheduler: 0.25.0-canary-2b036d3f1-20240327
+
/react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
@@ -9606,7 +9605,7 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
- /react-streaming-compat@0.3.18(react-dom@18.3.0-canary-09fbee89d-20231013)(react@18.3.0-canary-09fbee89d-20231013):
+ /react-streaming-compat@0.3.18(react-dom@18.3.0-canary-d6dcad6a8-20230914)(react@18.3.0-canary-d7a98a5e9-20230517):
resolution: {integrity: sha512-KyvJHZ3JLQyNQSU/Rg+FYPaU/LGjSrdByE1zHS5DP/I6hxEmDUJYXf9eWdZZMi3lq+sUEwy1P7ije4blb0wF/A==}
peerDependencies:
react: '>=18'
@@ -9615,11 +9614,11 @@ packages:
'@brillout/import': 0.2.3
'@brillout/json-serializer': 0.5.6
isbot-fast: 1.2.0
- react: 18.3.0-canary-09fbee89d-20231013
- react-dom: 18.3.0-canary-09fbee89d-20231013(react@18.3.0-canary-09fbee89d-20231013)
+ react: 18.3.0-canary-d7a98a5e9-20230517
+ react-dom: 18.3.0-canary-d6dcad6a8-20230914(react@18.3.0-canary-d7a98a5e9-20230517)
dev: false
- /react-streaming-compat@0.3.18(react-dom@18.3.0-canary-d6dcad6a8-20230914)(react@18.3.0-canary-d7a98a5e9-20230517):
+ /react-streaming-compat@0.3.18(react-dom@19.0.0-canary-2b036d3f1-20240327)(react@19.0.0-canary-2b036d3f1-20240327):
resolution: {integrity: sha512-KyvJHZ3JLQyNQSU/Rg+FYPaU/LGjSrdByE1zHS5DP/I6hxEmDUJYXf9eWdZZMi3lq+sUEwy1P7ije4blb0wF/A==}
peerDependencies:
react: '>=18'
@@ -9628,8 +9627,8 @@ packages:
'@brillout/import': 0.2.3
'@brillout/json-serializer': 0.5.6
isbot-fast: 1.2.0
- react: 18.3.0-canary-d7a98a5e9-20230517
- react-dom: 18.3.0-canary-d6dcad6a8-20230914(react@18.3.0-canary-d7a98a5e9-20230517)
+ react: 19.0.0-canary-2b036d3f1-20240327
+ react-dom: 19.0.0-canary-2b036d3f1-20240327(react@19.0.0-canary-2b036d3f1-20240327)
dev: false
/react@16.14.0:
@@ -9641,12 +9640,6 @@ packages:
prop-types: 15.8.1
dev: true
- /react@18.3.0-canary-09fbee89d-20231013:
- resolution: {integrity: sha512-MV2EqcBD9pAt8IfI5XkPj+/mQwIDPG3CSqbzir8kzjUeETuoMAOTbUl34CH4sS02JBq79jhvrY9L5rmL83OPWg==}
- engines: {node: '>=0.10.0'}
- dependencies:
- loose-envify: 1.4.0
-
/react@18.3.0-canary-d7a98a5e9-20230517:
resolution: {integrity: sha512-WCoMOYGg0OR7IoQ9YhubaJ4j7743LBTx4OOcaRuI4wZkshvPIOuVWrZNOarMuKRj8bm/5DKuAV/p2kd74AbQmg==}
engines: {node: '>=0.10.0'}
@@ -9654,6 +9647,10 @@ packages:
loose-envify: 1.4.0
dev: false
+ /react@19.0.0-canary-2b036d3f1-20240327:
+ resolution: {integrity: sha512-dI3DePzDBPIypHcn+84a1H/9IUX67XyK1kCi1KETaKIJrf3LciB1gKSQ5P0G7HEVEIeSKuvpq0QB0uLC3Ta+wA==}
+ engines: {node: '>=0.10.0'}
+
/read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
dependencies:
@@ -10048,17 +10045,15 @@ packages:
object-assign: 4.1.1
dev: true
- /scheduler@0.24.0-canary-09fbee89d-20231013:
- resolution: {integrity: sha512-EJY9WbhIa1tGdFCDtDmWU/FwwcPrmglpFkQp9IHu5tDjFpbNHMRxO+dles31SPOCIPR6wkRisoLA2/GuNs2niA==}
- dependencies:
- loose-envify: 1.4.0
-
/scheduler@0.24.0-canary-d6dcad6a8-20230914:
resolution: {integrity: sha512-tC/9jHWGULTtIk39bb16jrDYyqwz0BHlQlNa3kZYyyFx8JsxioqzT/WoaInIrbkwRaY/zjYzm8IUzE3zH2wKqg==}
dependencies:
loose-envify: 1.4.0
dev: false
+ /scheduler@0.25.0-canary-2b036d3f1-20240327:
+ resolution: {integrity: sha512-ZaJBj3+g9DPMfnsCrCvxQ4G+/6RcH3dRE1dSfB0/mGJB72ZE1agIvwNOGOgbf5wQw4Ka3w3vv0KcHt3jOAH6Lg==}
+
/selfsigned@2.1.1:
resolution: {integrity: sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==}
engines: {node: '>=10'}
@@ -10514,7 +10509,7 @@ packages:
acorn: 8.10.0
dev: true
- /styled-jsx@5.1.1(@babel/core@7.20.7)(react@18.3.0-canary-09fbee89d-20231013):
+ /styled-jsx@5.1.1(@babel/core@7.20.7)(react@19.0.0-canary-2b036d3f1-20240327):
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
engines: {node: '>= 12.0.0'}
peerDependencies:
@@ -10529,7 +10524,7 @@ packages:
dependencies:
'@babel/core': 7.20.7
client-only: 0.0.1
- react: 18.3.0-canary-09fbee89d-20231013
+ react: 19.0.0-canary-2b036d3f1-20240327
dev: true
/stylis@4.1.3:
@@ -11318,7 +11313,7 @@ packages:
resolution: {integrity: sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==}
dev: false
- /use-deep-compare-effect@1.8.1(react@18.3.0-canary-09fbee89d-20231013):
+ /use-deep-compare-effect@1.8.1(react@19.0.0-canary-2b036d3f1-20240327):
resolution: {integrity: sha512-kbeNVZ9Zkc0RFGpfMN3MNfaKNvcLNyxOAAd9O4CBZ+kCBXXscn9s/4I+8ytUER4RDpEYs5+O6Rs4PqiZ+rHr5Q==}
engines: {node: '>=10', npm: '>=6'}
peerDependencies:
@@ -11326,7 +11321,7 @@ packages:
dependencies:
'@babel/runtime': 7.20.7
dequal: 2.0.3
- react: 18.3.0-canary-09fbee89d-20231013
+ react: 19.0.0-canary-2b036d3f1-20240327
dev: false
/util-deprecate@1.0.2: