From 369119b6fd8a696a08e3f5d33b3bb43f46b51549 Mon Sep 17 00:00:00 2001 From: istarkov Date: Mon, 27 Jan 2025 17:37:51 +0000 Subject: [PATCH] Add polyfill loader Add test Initial styles Ranges support Comments Done Fix type errors Add comments Fix Do not load polyfill in chrome Support range units not defined in polyfill patch polyfill Add progress and closest examples Fix Add elephants Add submodules Add branch Test Test dd Test private checkout Try SSH Test animate branch in submodule Test local action Check Use submodules sh Fix name Fix Check it fails Test env Check again Test workflow call from env fix Test Fix Test Pass secret hack Pass env as input too Add comments etc Check submodules Test Check Improve Move from the main repo --- .../actions/submodules-checkout/action.yml | 46 +++++++ .github/workflows/check-submodules.yml | 67 +++++++++++ .github/workflows/chromatic.yml | 8 ++ .github/workflows/cli-r2-static.yaml | 2 + .github/workflows/cli-r2.yaml | 5 + .github/workflows/fixtures-test.yml | 15 ++- .github/workflows/main.yml | 44 +++++-- .github/workflows/vercel-deploy-staging.yml | 14 ++- .gitmodules | 4 + .storybook/main.ts | 34 +++++- @types/scroll-timeline.d.ts | 14 +++ apps/builder/app/routes/_ui.playground.tsx | 92 ++++++++++++++ apps/builder/vite.config.ts | 26 +++- package.json | 3 +- .../sdk-components-animation/package.json | 11 +- packages/sdk-components-animation/private-src | 1 + .../src/components.ts | 2 +- .../sdk-components-animation/src/scroll.tsx | 14 +++ .../src/shared/animation-types.tsx | 113 ++++++++++++++++++ .../src/shared/proxy.ts | 3 - .../sdk-components-animation/tsconfig.json | 11 +- patches/scroll-timeline-polyfill@1.1.0.patch | 25 ++++ pnpm-lock.yaml | 26 ++++ submodules.sh | 25 ++++ 24 files changed, 581 insertions(+), 24 deletions(-) create mode 100644 .github/actions/submodules-checkout/action.yml create mode 100644 .github/workflows/check-submodules.yml create mode 100644 .gitmodules create mode 100644 @types/scroll-timeline.d.ts create mode 100644 apps/builder/app/routes/_ui.playground.tsx create mode 160000 packages/sdk-components-animation/private-src create mode 100644 packages/sdk-components-animation/src/scroll.tsx create mode 100644 packages/sdk-components-animation/src/shared/animation-types.tsx delete mode 100644 packages/sdk-components-animation/src/shared/proxy.ts create mode 100644 patches/scroll-timeline-polyfill@1.1.0.patch create mode 100755 submodules.sh diff --git a/.github/actions/submodules-checkout/action.yml b/.github/actions/submodules-checkout/action.yml new file mode 100644 index 000000000000..0b47233e94ce --- /dev/null +++ b/.github/actions/submodules-checkout/action.yml @@ -0,0 +1,46 @@ +name: CI setup + +description: | + Sets up the CI environment for the project. + +inputs: + submodules-ssh-key: + description: "The SSH key to private submodules to use for the checkout" + required: true + +runs: + using: "composite" + + steps: + - name: Set up SSH for Git + if: ${{ inputs.submodules-ssh-key }} + run: | + mkdir -p ~/.ssh + echo "${{ inputs.submodules-ssh-key }}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan github.com >> ~/.ssh/known_hosts + shell: bash + + - name: Verify SSH Connection (Optional) + if: ${{ inputs.submodules-ssh-key }} + run: | + ssh -T git@github.com || true + shell: bash + + - name: Verify SSH Connection (Optional) + if: ${{ inputs.submodules-ssh-key }} + run: | + echo Branch is ${{ github.event.pull_request.head.ref || github.ref_name }} + shell: bash + + - name: Try checkout submodules to the same branch as main repo + if: ${{ inputs.submodules-ssh-key }} + run: | + ./submodules.sh ${{ github.event.pull_request.head.ref || github.ref_name }} + shell: bash + + - name: Show main readme + if: ${{ inputs.submodules-ssh-key }} + run: | + cat ./packages/sdk-components-animation/private-src/README.md || echo "No README found" + shell: bash diff --git a/.github/workflows/check-submodules.yml b/.github/workflows/check-submodules.yml new file mode 100644 index 000000000000..c97bdf016b2c --- /dev/null +++ b/.github/workflows/check-submodules.yml @@ -0,0 +1,67 @@ +name: Check submodules + +on: + pull_request: + +# cancel in-progress runs on new commits to same PR (gitub.event.number) +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.sha }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + checks: + timeout-minutes: 20 + + environment: + name: development + + env: + DATABASE_URL: postgres:// + AUTH_SECRET: test + + runs-on: ubuntu-24.04-arm + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} + + - name: Check if any submodule branch matches github.ref_name + run: | + echo "C ${{ github.workflow }}-${{ github.event.number || github.sha }}" + # Get the current branch or tag name + REF_NAME="${{ github.event.pull_request.head.ref || github.ref_name }}" + + echo "Branch is:" $REF_NAME + + # List all submodule paths + SUBMODULES=$(git submodule status | awk '{print $2}') + + # Check each submodule's branch + for SUBMODULE in $SUBMODULES; do + echo "Checking submodule: $SUBMODULE" + ( + cd "$SUBMODULE" + # Get the current branch of the submodule + SUBMODULE_BRANCH=$(git rev-parse --abbrev-ref HEAD) + echo "Submodule branch: $SUBMODULE_BRANCH" + + # Compare the submodule branch to the ref_name + if [ "$SUBMODULE_BRANCH" = "$REF_NAME" ]; then + echo "::error::Submodule '$SUBMODULE' is on branch '$SUBMODULE_BRANCH', which matches the current ref '$REF_NAME'." + exit 1 + fi + ) + if [ $? -ne 0 ]; then + exit 1 # Fail the workflow if any submodule branch matches + fi + done + + echo "No submodule is on the same branch as the current ref '$REF_NAME'." diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 8f166944635f..549d9a0c634f 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -20,12 +20,20 @@ jobs: runs-on: ubuntu-latest + environment: + name: development + steps: - uses: actions/checkout@v4 with: fetch-depth: 2 # we need to fetch at least parent commit to satisfy Chromatic ref: ${{ github.event.pull_request.head.sha || github.sha }} # HEAD commit instead of merge commit + # Storybook with submodules + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} + - uses: ./.github/actions/ci-setup - name: Chromatic diff --git a/.github/workflows/cli-r2-static.yaml b/.github/workflows/cli-r2-static.yaml index bbf61abfabbb..d21ecd265bc4 100644 --- a/.github/workflows/cli-r2-static.yaml +++ b/.github/workflows/cli-r2-static.yaml @@ -30,6 +30,8 @@ jobs: with: ref: ${{ github.sha }} # HEAD commit instead of merge commit + # Do not checkout submodules, they are not needed for this workflow + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 diff --git a/.github/workflows/cli-r2.yaml b/.github/workflows/cli-r2.yaml index 4b36b5087bc6..b8e3247cf035 100644 --- a/.github/workflows/cli-r2.yaml +++ b/.github/workflows/cli-r2.yaml @@ -31,6 +31,11 @@ jobs: with: ref: ${{ github.sha }} # HEAD commit instead of merge commit + # We need submodules here as this is used for the cloudflare build + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 diff --git a/.github/workflows/fixtures-test.yml b/.github/workflows/fixtures-test.yml index 5f37750af516..e627224a96f3 100644 --- a/.github/workflows/fixtures-test.yml +++ b/.github/workflows/fixtures-test.yml @@ -9,6 +9,12 @@ on: builder-host: required: true type: string + environment: + required: true + type: string + secrets: + PRIVATE_GITHUB_DEPLOY_TOKEN: + required: true permissions: contents: read # to fetch code (actions/checkout) @@ -23,6 +29,9 @@ jobs: runs-on: ${{ matrix.os }} + environment: + name: ${{ inputs.environment }} + env: DATABASE_URL: postgres:// AUTH_SECRET: test @@ -32,7 +41,11 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} # HEAD commit instead of merge commit + ref: ${{ github.event.pull_request.head.sha || github.sha }} + # Test that everything is working with submodules + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} - uses: ./.github/actions/ci-setup diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3fec2ba4d15f..ef5082bca988 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,6 +18,15 @@ jobs: checks: timeout-minutes: 20 + strategy: + matrix: + environment: + - empty + - development + + environment: + name: ${{ matrix.environment }} + env: DATABASE_URL: postgres:// AUTH_SECRET: test @@ -27,7 +36,12 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} # HEAD commit instead of merge commit + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + # Will not checkout submodules on empty environment, and will on development + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} - uses: ./.github/actions/ci-setup @@ -41,21 +55,35 @@ jobs: - run: echo ===SHA USED=== ${{ github.event.pull_request.head.sha || github.sha }} # todo: remove after check whats happening on main - - run: pnpm prettier --cache --check "**/*.{js,md,ts,tsx}" + - run: | + pnpm prettier --cache --check "**/*.{js,md,ts,tsx}" + + - name: Lint + run: | + pnpm lint --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslint-cache - - run: pnpm lint --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslint-cache + - name: Test + run: | + pnpm -r test - - run: pnpm -r test - - run: pnpm --filter=@webstudio-is/prisma-client build - - run: pnpm -r typecheck + - name: Typecheck + run: | + pnpm -r typecheck check-size: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm + + environment: + name: development steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} # HEAD commit instead of merge commit + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} - uses: ./.github/actions/ci-setup diff --git a/.github/workflows/vercel-deploy-staging.yml b/.github/workflows/vercel-deploy-staging.yml index ba79625ac6ec..883ccc710235 100644 --- a/.github/workflows/vercel-deploy-staging.yml +++ b/.github/workflows/vercel-deploy-staging.yml @@ -5,7 +5,7 @@ on: # cancel in-progress runs on new commits to same PR (gitub.event.number) concurrency: - group: vercel-deploy-${{ github.workflow }}-${{ github.event.number || github.sha }} + group: vercel-deploy-${{ github.workflow }}-${{ github.sha }} cancel-in-progress: true permissions: @@ -38,9 +38,14 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} # HEAD commit instead of merge commit + ref: ${{ github.sha }} + + - uses: ./.github/actions/submodules-checkout + with: + submodules-ssh-key: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 with: node-version: 20 @@ -85,6 +90,11 @@ jobs: with: builder-url: ${{ needs.deployment.outputs.builder-url }} builder-host: ${{ needs.deployment.outputs.builder-host }} + environment: development + secrets: + # We are not passing the secret here (as it does not exist in the current environment). + # Instead, this serves as a signal to the calling workflow that it has permission to extract it from the environment. + PRIVATE_GITHUB_DEPLOY_TOKEN: ${{ secrets.PRIVATE_GITHUB_DEPLOY_TOKEN }} delete-github-deployments: needs: fixtures-test diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000000..76cab76f4653 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "packages/sdk-components-animation/private-src"] + path = packages/sdk-components-animation/private-src + url = git@github.com:webstudio-is/sdk-components-animation.git + branch = main diff --git a/.storybook/main.ts b/.storybook/main.ts index 191dd8425b15..cc31e8098476 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,5 +1,19 @@ import * as path from "node:path"; import type { StorybookConfig } from "@storybook/react-vite"; +import { existsSync, readdirSync } from "node:fs"; + +const isFolderEmptyOrNotExists = (folderPath: string) => { + if (!existsSync(folderPath)) { + return true; // Folder does not exist + } + const contents = readdirSync(folderPath); + + return contents.length === 0; +}; + +const hasPrivateFolders = !isFolderEmptyOrNotExists( + path.join(__dirname, "../../packages/sdk-components-animation/private-src") +); const visualTestingStories: StorybookConfig["stories"] = [ { @@ -37,6 +51,10 @@ export default { directory: "../packages/sdk-components-react-radix", titlePrefix: "SDK Components React Radix", }, + { + directory: "../packages/sdk-components-animation", + titlePrefix: "SDK Components Animation", + }, ], framework: { name: "@storybook/react-vite", @@ -50,6 +68,10 @@ export default { async viteFinal(config) { return { ...config, + optimizeDeps: { + exclude: ["scroll-timeline-polyfill"], + }, + define: { ...config.define, // storybook use "util" package internally which is bundled with stories @@ -59,7 +81,17 @@ export default { }, resolve: { ...config.resolve, - conditions: ["webstudio", "import", "module", "browser", "default"], + conditions: hasPrivateFolders + ? [ + "webstudio-private", + "webstudio", + "import", + "module", + "browser", + "default", + ] + : ["webstudio", "import", "module", "browser", "default"], + alias: [ { find: "~", diff --git a/@types/scroll-timeline.d.ts b/@types/scroll-timeline.d.ts new file mode 100644 index 000000000000..eea03a78a8f6 --- /dev/null +++ b/@types/scroll-timeline.d.ts @@ -0,0 +1,14 @@ +type ScrollAxis = "block" | "inline" | "x" | "y"; + +interface ScrollTimelineOptions { + source?: Element | Document | null; + axis?: ScrollAxis; +} + +declare class ScrollTimeline extends AnimationTimeline { + constructor(options?: ScrollTimelineOptions); +} + +declare class ViewTimeline extends ScrollTimeline { + constructor(options?: ScrollTimelineOptions); +} diff --git a/apps/builder/app/routes/_ui.playground.tsx b/apps/builder/app/routes/_ui.playground.tsx new file mode 100644 index 000000000000..1336ca563972 --- /dev/null +++ b/apps/builder/app/routes/_ui.playground.tsx @@ -0,0 +1,92 @@ +import { Scroll } from "@webstudio-is/sdk-components-animation"; +import { parseCssValue } from "@webstudio-is/css-data"; +import { Box, styled } from "@webstudio-is/design-system"; + +const H1 = styled("h1"); + +const DEBUG = false; + +const Playground = () => { + return ( + + +

+ HELLO WORLD +

+
+ + Start scrolling, and when the current box scrolls out, the “HELLO WORLD” + header will fly in and become hoverable. (During the animation, it won’t + be hoverable.) + + + + When you see this box, the “HELLO WORLD” header will fly out. + +
+ ); +}; + +export default Playground; + +// Reduces Vercel function size from 29MB to 9MB for unknown reasons; effective when used in limited files. +export const config = { + maxDuration: 30, +}; diff --git a/apps/builder/vite.config.ts b/apps/builder/vite.config.ts index 3357db040a3d..c4780a2cc208 100644 --- a/apps/builder/vite.config.ts +++ b/apps/builder/vite.config.ts @@ -1,4 +1,4 @@ -import { resolve } from "node:path"; +import path, { resolve } from "node:path"; import { defineConfig, type CorsOptions } from "vite"; import { vitePlugin as remix } from "@remix-run/dev"; import { vercelPreset } from "@vercel/remix/vite"; @@ -9,13 +9,28 @@ import { getAuthorizationServerOrigin, isBuilderUrl, } from "./app/shared/router-utils/origins"; -import { readFileSync } from "node:fs"; +import { readFileSync, readdirSync, existsSync } from "node:fs"; + +const isFolderEmptyOrNotExists = (folderPath: string) => { + if (!existsSync(folderPath)) { + return true; // Folder does not exist + } + const contents = readdirSync(folderPath); + + return contents.length === 0; +}; + +const hasPrivateFolders = !isFolderEmptyOrNotExists( + path.join(__dirname, "../../packages/sdk-components-animation/private-src") +); export default defineConfig(({ mode }) => { if (mode === "test") { return { resolve: { - conditions: ["webstudio"], + conditions: hasPrivateFolders + ? ["webstudio-private", "webstudio"] + : ["webstudio"], alias: [ { find: "~", @@ -69,7 +84,10 @@ export default defineConfig(({ mode }) => { }, ], resolve: { - conditions: ["webstudio"], + conditions: hasPrivateFolders + ? ["webstudio-private", "webstudio"] + : ["webstudio"], + alias: [ { find: "~", diff --git a/package.json b/package.json index 32bac180599e..5418bee673da 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,8 @@ "css-tree@2.3.1": "patches/css-tree@2.3.1.patch", "@types/css-tree@2.3.1": "patches/@types__css-tree@2.3.1.patch", "@radix-ui/react-scroll-area@1.0.5": "patches/@radix-ui__react-scroll-area@1.0.5.patch", - "@remix-run/dev": "patches/@remix-run__dev.patch" + "@remix-run/dev": "patches/@remix-run__dev.patch", + "scroll-timeline-polyfill@1.1.0": "patches/scroll-timeline-polyfill@1.1.0.patch" } } } diff --git a/packages/sdk-components-animation/package.json b/packages/sdk-components-animation/package.json index b130dc72275c..4c32dda89905 100644 --- a/packages/sdk-components-animation/package.json +++ b/packages/sdk-components-animation/package.json @@ -14,6 +14,7 @@ ], "exports": { ".": { + "webstudio-private": "./private-src/components.ts", "webstudio": "./src/components.ts", "types": "./lib/types/components.d.ts", "import": "./lib/components.js" @@ -51,9 +52,12 @@ "react-dom": "18.3.0-canary-14898b6a9-20240318" }, "dependencies": { + "@webstudio-is/css-engine": "workspace:*", "@webstudio-is/icons": "workspace:*", "@webstudio-is/react-sdk": "workspace:*", - "@webstudio-is/sdk": "workspace:*" + "@webstudio-is/sdk": "workspace:*", + "react-error-boundary": "^5.0.0", + "scroll-timeline-polyfill": "^1.1.0" }, "devDependencies": { "@types/react": "^18.2.70", @@ -63,7 +67,10 @@ "@webstudio-is/sdk-components-react": "workspace:*", "@webstudio-is/template": "workspace:*", "@webstudio-is/tsconfig": "workspace:*", + "@webstudio-is/css-data": "workspace:*", + "@webstudio-is/design-system": "workspace:*", "react": "18.3.0-canary-14898b6a9-20240318", - "react-dom": "18.3.0-canary-14898b6a9-20240318" + "react-dom": "18.3.0-canary-14898b6a9-20240318", + "type-fest": "^4.32.0" } } diff --git a/packages/sdk-components-animation/private-src b/packages/sdk-components-animation/private-src new file mode 160000 index 000000000000..33beb37e4f7d --- /dev/null +++ b/packages/sdk-components-animation/private-src @@ -0,0 +1 @@ +Subproject commit 33beb37e4f7dccb89a2e4a8cf70b041bb554f65d diff --git a/packages/sdk-components-animation/src/components.ts b/packages/sdk-components-animation/src/components.ts index cb0ff5c3b541..b8a77f059a67 100644 --- a/packages/sdk-components-animation/src/components.ts +++ b/packages/sdk-components-animation/src/components.ts @@ -1 +1 @@ -export {}; +export { Scroll } from "./scroll"; diff --git a/packages/sdk-components-animation/src/scroll.tsx b/packages/sdk-components-animation/src/scroll.tsx new file mode 100644 index 000000000000..17e0cc3f5aab --- /dev/null +++ b/packages/sdk-components-animation/src/scroll.tsx @@ -0,0 +1,14 @@ +import { forwardRef, type ElementRef } from "react"; +import type { AnimationAction } from "./shared/animation-types"; + +type ScrollProps = { + debug?: boolean; + children?: React.ReactNode; + action: AnimationAction; +}; + +export const Scroll = forwardRef, ScrollProps>( + ({ debug = false, action, ...props }, ref) => { + return
; + } +); diff --git a/packages/sdk-components-animation/src/shared/animation-types.tsx b/packages/sdk-components-animation/src/shared/animation-types.tsx new file mode 100644 index 000000000000..e997c6e9f661 --- /dev/null +++ b/packages/sdk-components-animation/src/shared/animation-types.tsx @@ -0,0 +1,113 @@ +import type { StyleValue, UnitValue } from "@webstudio-is/css-engine"; + +export type KeyframeStyles = { [property: string]: StyleValue | undefined }; + +export type AnimationKeyframe = { + offset: number | undefined; + // We are using composite: auto as the default value for now + // composite?: CompositeOperationOrAuto; + styles: KeyframeStyles; +}; + +const RANGE_UNITS = [ + "%", + "px", + // Does not supported by polyfill and we are converting it to px ourselfs + "cm", + "mm", + "q", + "in", + "pt", + "pc", + "em", + "rem", + "ex", + "rex", + "cap", + "rcap", + "ch", + "rch", + "lh", + "rlh", + "vw", + "svw", + "lvw", + "dvw", + "vh", + "svh", + "lvh", + "dvh", + "vi", + "svi", + "lvi", + "dvi", + "vb", + "svb", + "lvb", + "dvb", + "vmin", + "svmin", + "lvmin", + "dvmin", + "vmax", + "svmax", + "lvmax", + "dvmax", +] as const; + +export type RangeUnit = (typeof RANGE_UNITS)[number]; + +export const isRangeUnit = (value: unknown): value is RangeUnit => + RANGE_UNITS.includes(value as RangeUnit); + +export type RangeUnitValue = { type: "unit"; value: number; unit: RangeUnit }; + +({}) as RangeUnitValue satisfies UnitValue; + +type KeyframeEffectOptions = { + easing?: string; + fill?: FillMode; +}; + +/** + * Scroll does not support https://drafts.csswg.org/scroll-animations/#named-ranges + * However, for simplicity and type unification with the view, we will use the names "start" and "end," + * which will be transformed as follows: + * - "start" → `calc(0% + range)` + * - "end" → `calc(100% - range)` + */ +type ScrollNamedRange = "start" | "end"; + +/** + * Scroll does not support https://drafts.csswg.org/scroll-animations/#named-ranges + * However, for simplicity and type unification with the view, we will use the names "start" and "end," + * See ScrollNamedRange type for more information. + */ +export type ScrollRangeValue = [name: ScrollNamedRange, value: RangeUnitValue]; + +type ScrollRangeOptions = { + rangeStart?: ScrollRangeValue | undefined; + rangeEnd?: ScrollRangeValue | undefined; +}; + +/* +type AnimationTiming = { + delay?: number; + duration?: number; + easing?: string; + fill?: FillMode; +}; +*/ + +type ScrollAction = { + type: "scroll"; + source?: "closest" | "nearest" | "root"; + axis?: "block" | "inline" | "x" | "y"; + animations: { + timing: KeyframeEffectOptions & ScrollRangeOptions; + keyframes: AnimationKeyframe[]; + }[]; +}; + +// | ViewAction | ... +export type AnimationAction = ScrollAction; diff --git a/packages/sdk-components-animation/src/shared/proxy.ts b/packages/sdk-components-animation/src/shared/proxy.ts deleted file mode 100644 index 8145a83a563f..000000000000 --- a/packages/sdk-components-animation/src/shared/proxy.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { createProxy } from "@webstudio-is/template"; - -export const animation = createProxy("@webstudio-is/sdk-components-animation:"); diff --git a/packages/sdk-components-animation/tsconfig.json b/packages/sdk-components-animation/tsconfig.json index d2e5040f8f2c..a7f8652f07c9 100644 --- a/packages/sdk-components-animation/tsconfig.json +++ b/packages/sdk-components-animation/tsconfig.json @@ -1,3 +1,12 @@ { - "extends": "@webstudio-is/tsconfig/base.json" + "extends": "@webstudio-is/tsconfig/base.json", + "include": [ + "src", + "../../@types/**/scroll-timeline.d.ts", + "private-src/scroll.stories.tsx", + "private-src/scroll.tsx" + ], + "compilerOptions": { + "types": ["react/experimental", "react-dom/experimental", "@types/node"] + } } diff --git a/patches/scroll-timeline-polyfill@1.1.0.patch b/patches/scroll-timeline-polyfill@1.1.0.patch new file mode 100644 index 000000000000..8b78d3071d0d --- /dev/null +++ b/patches/scroll-timeline-polyfill@1.1.0.patch @@ -0,0 +1,25 @@ +diff --git a/src/scroll-timeline-base.js b/src/scroll-timeline-base.js +index 2c854928701c5dae23c985eb04f73a6ca2b661c3..abf1a7629568f411dd83dd509640850706d59528 100644 +--- a/src/scroll-timeline-base.js ++++ b/src/scroll-timeline-base.js +@@ -162,13 +162,19 @@ function isValidAxis(axis) { + */ + export function measureSource (source) { + const style = getComputedStyle(source); ++ const clientHeight = source.clientHeight; + return { + scrollLeft: source.scrollLeft, + scrollTop: source.scrollTop, + scrollWidth: source.scrollWidth, + scrollHeight: source.scrollHeight, + clientWidth: source.clientWidth, +- clientHeight: source.clientHeight, ++ get clientHeight() { ++ if (document.scrollingElement === source) { ++ return window.innerHeight; ++ } ++ return clientHeight; ++ }, + writingMode: style.writingMode, + direction: style.direction, + scrollPaddingTop: style.scrollPaddingTop, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57c6cc58877e..19dc6862febf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ patchedDependencies: css-tree@2.3.1: hash: epgcmebti7rfrc2ej4odb3t4jy path: patches/css-tree@2.3.1.patch + scroll-timeline-polyfill@1.1.0: + hash: i4g3vdpump4efgy2hri5l5rsfm + path: patches/scroll-timeline-polyfill@1.1.0.patch importers: @@ -1914,6 +1917,9 @@ importers: packages/sdk-components-animation: dependencies: + '@webstudio-is/css-engine': + specifier: workspace:* + version: link:../css-engine '@webstudio-is/icons': specifier: workspace:* version: link:../icons @@ -1923,6 +1929,12 @@ importers: '@webstudio-is/sdk': specifier: workspace:* version: link:../sdk + react-error-boundary: + specifier: ^5.0.0 + version: 5.0.0(react@18.3.0-canary-14898b6a9-20240318) + scroll-timeline-polyfill: + specifier: ^1.1.0 + version: 1.1.0(patch_hash=i4g3vdpump4efgy2hri5l5rsfm) devDependencies: '@types/react': specifier: ^18.2.70 @@ -1930,6 +1942,12 @@ importers: '@types/react-dom': specifier: ^18.2.25 version: 18.2.25 + '@webstudio-is/css-data': + specifier: workspace:* + version: link:../css-data + '@webstudio-is/design-system': + specifier: workspace:* + version: link:../design-system '@webstudio-is/generate-arg-types': specifier: workspace:* version: link:../generate-arg-types @@ -1951,6 +1969,9 @@ importers: react-dom: specifier: 18.3.0-canary-14898b6a9-20240318 version: 18.3.0-canary-14898b6a9-20240318(react@18.3.0-canary-14898b6a9-20240318) + type-fest: + specifier: ^4.32.0 + version: 4.32.0 packages/sdk-components-react: dependencies: @@ -8398,6 +8419,9 @@ packages: scheduler@0.24.0-canary-14898b6a9-20240318: resolution: {integrity: sha512-ifDO3bUdooS4OlxvGxMyoDEC/aq14MvJLDd0thjrUSZGeLJA7WBc+sr9NZxIxrXfVqMl1GTGGPwXqRJZDNW76w==} + scroll-timeline-polyfill@1.1.0: + resolution: {integrity: sha512-BpL3gk3Ynt/5VYaDFUNUP/FTkDldwKQnWcA07g/mDHkMVS9pQUyUXBpsy4RZYAgsfFeI1tWcnPNrEFtCpQoO9Q==} + selfsigned@2.1.1: resolution: {integrity: sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==} engines: {node: '>=10'} @@ -16336,6 +16360,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + scroll-timeline-polyfill@1.1.0(patch_hash=i4g3vdpump4efgy2hri5l5rsfm): {} + selfsigned@2.1.1: dependencies: node-forge: 1.3.1 diff --git a/submodules.sh b/submodules.sh new file mode 100755 index 000000000000..0c624f2d6cc0 --- /dev/null +++ b/submodules.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +BRANCH="$1" + + +git submodule update --init --recursive + +git submodule foreach ' + # If a branch parameter is provided, use it; otherwise, determine the branch dynamically + if [ -n "'"$BRANCH"'" ]; then + SUBMODULE_BRANCH="'"$BRANCH"'" + else + SUBMODULE_BRANCH=$(git -C $toplevel rev-parse --abbrev-ref HEAD) + fi + + echo "Checking out \"$SUBMODULE_BRANCH\" branch in \"$name\" submodule" + + # Check if the branch exists in the remote + if git ls-remote --exit-code --heads origin "$SUBMODULE_BRANCH" > /dev/null; then + git checkout "$SUBMODULE_BRANCH" && git pull origin "$SUBMODULE_BRANCH" + else + # Fallback to "main" if the branch does not exist + git checkout "main" && git pull origin "main" + fi +' \ No newline at end of file