From efdc3231a7bde38cfe45d10086d0d36a24c1b9b4 Mon Sep 17 00:00:00 2001 From: pngwn Date: Wed, 14 Aug 2024 15:17:36 +0100 Subject: [PATCH] Initial SSR refactor (#9102) * changes * asd * fix tests * fix lint * fix ts * fix ts * cleanup * cleanup * fix * Apply suggestions from code review Co-authored-by: Yuichiro Tachibana (Tsuchiya) * fix * add changeset * fix gitignore * fix changeset * fix lockfile * format * fix * add changeset * githunore * kit bopilerplate * add changeset * fix website * add changeset --------- Co-authored-by: Yuichiro Tachibana (Tsuchiya) Co-authored-by: gradio-pr-bot --- .changeset/wise-buttons-act.md | 19 + .config/.prettierignore | 2 +- .config/.prettierrc.json | 3 +- .config/eslint.config.js | 2 +- .config/playwright-setup.js | 2 +- .config/vitest.config.ts | 2 +- .../actions/install-frontend-deps/action.yml | 2 +- .github/workflows/test-functional-lite.yml | 2 +- .github/workflows/trigger-changeset.yml | 1 + .gitignore | 5 + .vscode/settings.json | 2 +- =23.2 | 49 - CONTRIBUTING.md | 6 +- gradio/hash_seed.txt | 1 - js/_website/vite.config.ts | 3 +- ....timestamp-1721955124085-e178b44edfdf6.mjs | 159 - js/app/.gitignore | 22 +- js/app/README.md | 38 + js/app/package.json | 108 +- js/app/src/app.d.ts | 13 + js/app/src/app.html | 12 + js/app/src/lib/index.ts | 1 + js/app/src/routes/+page.svelte | 4 + js/app/static/favicon.png | Bin 0 -> 1571 bytes js/app/svelte.config.js | 18 + js/app/tsconfig.json | 20 + js/app/vite.config.ts | 217 +- js/audio/audio.test.ts | 4 +- js/audio/interactive/InteractiveAudio.svelte | 2 +- js/build/README.md | 3 + js/{app => build/dist}/component_loader.js | 0 js/build/dist/index.js | 316 + js/build/package.json | 19 + js/build/src/component_loader.js | 81 + .../build_plugins.ts => build/src/index.ts} | 7 +- js/button/main.ts | 2 + js/chatbot/shared/ChatBot.svelte | 5 +- js/checkboxgroup/checkboxgroup.test.ts | 2 +- js/core/.gitignore | 1 + js/core/blocks.ts | 1 + js/core/index.ts | 4 + js/core/login.ts | 1 + js/core/package.json | 78 + js/{app => core}/public/favicon.png | Bin js/{app => core}/public/static/img/Bunny.obj | 0 js/{app => core}/public/static/img/Duck.glb | Bin .../public/static/img/api-logo.svg | 0 js/{app => core}/public/static/img/camera.svg | 0 js/{app => core}/public/static/img/clear.svg | 0 js/{app => core}/public/static/img/edit.svg | 0 .../public/static/img/javascript.svg | 0 js/{app => core}/public/static/img/logo.svg | 0 .../public/static/img/logo_error.svg | 0 js/{app => core}/public/static/img/python.svg | 0 .../public/static/img/undo-solid.svg | 0 js/{app => core}/src/Blocks.svelte | 0 js/{app => core}/src/Embed.svelte | 0 js/{app => core}/src/Login.stories.svelte | 0 js/{app => core}/src/Login.svelte | 0 js/{app => core}/src/MountComponents.svelte | 0 js/{app => core}/src/Render.svelte | 0 js/{app => core}/src/RenderComponent.svelte | 0 .../src/api_docs/ApiBanner.svelte | 6 +- js/{app => core}/src/api_docs/ApiDocs.svelte | 0 .../src/api_docs/ApiRecorder.svelte | 0 .../src/api_docs/CodeSnippet.svelte | 14 +- .../src/api_docs/CopyButton.svelte | 0 .../src/api_docs/EndpointDetail.svelte | 0 .../src/api_docs/InputPayload.svelte | 0 .../src/api_docs/InstallSnippet.svelte | 0 js/{app => core}/src/api_docs/NoApi.svelte | 0 .../src/api_docs/ParametersSnippet.svelte | 0 .../src/api_docs/RecordingSnippet.svelte | 9 +- .../src/api_docs/ResponseSnippet.svelte | 0 .../src/api_docs/TryButton.svelte | 0 .../src/api_docs/img/api-logo.svg | 0 js/{app => core}/src/api_docs/img/bash.svg | 0 .../src/api_docs/img/clear.svelte | 0 .../src/api_docs/img/javascript.svg | 0 js/{app => core}/src/api_docs/img/python.svg | 0 js/{app => core}/src/api_docs/index.ts | 0 js/{app => core}/src/api_docs/utils.ts | 0 js/{app => core}/src/css.ts | 0 js/{app => core}/src/gradio_helper.ts | 0 js/{app => core}/src/i18n.test.ts | 0 js/{app => core}/src/i18n.ts | 0 js/{app => core}/src/images/lightning.svg | 0 js/{app => core}/src/images/logo.svg | 0 js/{app => core}/src/images/play.svg | 0 js/{app => core}/src/images/spaces.svg | 0 js/{app => core}/src/init.test.ts | 0 js/{app => core}/src/init.ts | 0 js/{app => core}/src/lang/BCP47_codes.js | 0 js/{app => core}/src/lang/README.md | 2 +- js/{app => core}/src/lang/ar.json | 0 js/{app => core}/src/lang/ca.json | 0 js/{app => core}/src/lang/ckb.json | 0 js/{app => core}/src/lang/de.json | 0 js/{app => core}/src/lang/en.json | 0 js/{app => core}/src/lang/es.json | 0 js/{app => core}/src/lang/eu.json | 0 js/{app => core}/src/lang/fa.json | 0 js/{app => core}/src/lang/fr.json | 0 js/{app => core}/src/lang/he.json | 0 js/{app => core}/src/lang/hi.json | 0 js/{app => core}/src/lang/ja.json | 0 js/{app => core}/src/lang/ko.json | 0 js/{app => core}/src/lang/lt.json | 0 js/{app => core}/src/lang/nl.json | 0 js/{app => core}/src/lang/pl.json | 0 js/{app => core}/src/lang/pt-BR.json | 0 js/{app => core}/src/lang/ru.json | 0 js/{app => core}/src/lang/ta.json | 0 js/{app => core}/src/lang/tr.json | 0 js/{app => core}/src/lang/uk.json | 0 js/{app => core}/src/lang/ur.json | 0 js/{app => core}/src/lang/uz.json | 0 js/{app => core}/src/lang/zh-CN.json | 0 js/{app => core}/src/lang/zh-TW.json | 0 js/core/src/s-blocks.ts | 1 + js/core/src/s-login.ts | 1 + js/{app => core}/src/stores.ts | 0 js/{app => core}/src/types.ts | 0 js/{app => core}/src/vite-env-override.d.ts | 0 js/dataframe/Dataframe.stories.svelte | 1 - js/dataframe/shared/Table.svelte | 2 +- js/dropdown/dropdown.test.ts | 2 +- js/gallery/Gallery.test.ts | 2 +- js/highlightedtext/highlightedtext.test.ts | 2 +- js/image/Image.test.ts | 3 +- js/{app => lite}/lite.html | 2 +- js/lite/package.json | 25 +- .../src/lite => lite/src}/ErrorDisplay.svelte | 2 +- .../src/lite => lite/src}/LiteIndex.svelte | 6 +- .../src/lite => lite/src}/Playground.svelte | 4 +- js/{app/src/lite => lite/src}/css.ts | 2 +- .../src}/custom-element/indent.ts | 0 .../src}/custom-element/index.test.ts | 0 .../lite => lite/src}/custom-element/index.ts | 2 +- js/{app/src/lite => lite/src}/dev/App.svelte | 0 js/{app/src/lite => lite/src}/fetch.ts | 0 js/lite/src/images/lightning.svg | 2 + js/lite/src/images/logo.svg | 19 + js/lite/src/images/play.svg | 2 + js/lite/src/images/spaces.svg | 7 + js/{app/src/lite => lite/src}/index.ts | 2 +- js/{app/src/lite => lite/src}/sse.ts | 0 js/lite/src/theme.css | 424 + js/lite/vite.config.ts | 197 + js/plot/shared/Plot.svelte | 2 +- js/spa/.gitignore | 1 + js/spa/component_loader.js | 81 + js/{app => spa}/index.html | 0 js/spa/package.json | 41 + js/{app => spa}/postcss.config.js | 0 js/spa/public/favicon.png | Bin 0 -> 3127 bytes js/spa/public/static/img/Bunny.obj | 7474 +++++++++++++++++ js/spa/public/static/img/Duck.glb | Bin 0 -> 120484 bytes js/spa/public/static/img/api-logo.svg | 4 + js/spa/public/static/img/camera.svg | 1 + js/spa/public/static/img/clear.svg | 67 + js/spa/public/static/img/edit.svg | 39 + js/spa/public/static/img/javascript.svg | 16 + .../public/static/img/logo.svg} | 0 js/spa/public/static/img/logo_error.svg | 134 + js/spa/public/static/img/python.svg | 20 + js/spa/public/static/img/undo-solid.svg | 1 + js/{app => spa}/src/Index.svelte | 20 +- js/{app => spa}/src/main.ts | 4 +- js/spa/src/vite-env-override.d.ts | 20 + .../test/audio_component_events.spec.ts | 0 js/{app => spa}/test/audio_debugger.spec.ts | 0 .../test/blocks_chained_events.spec.ts | 0 js/{app => spa}/test/blocks_essay.spec.ts | 0 .../test/blocks_flashcards.spec.ts | 0 js/{app => spa}/test/blocks_flipper.spec.ts | 0 js/{app => spa}/test/blocks_inputs.spec.ts | 0 js/{app => spa}/test/blocks_page_load.spec.ts | 0 js/{app => spa}/test/blocks_xray.spec.ts | 0 js/{app => spa}/test/cancel_events.spec.ts | 0 .../chatbot_core_components_simple.spec.ts | 0 .../test/chatbot_multimodal.spec.ts | 0 .../test/chatbot_with_tools.spec.ts | 0 js/{app => spa}/test/clear_components.spec.ts | 0 js/{app => spa}/test/components.test.ts | 4 +- js/{app => spa}/test/custom_css.spec.ts | 0 .../test/dataframe_colorful.spec.ts | 0 js/{app => spa}/test/datetimes.spec.ts | 0 .../test/file_component_events.spec.ts | 0 .../file_explorer_component_events.spec.ts | 0 js/{app => spa}/test/files/alphabet.txt | 0 js/{app => spa}/test/files/cheetah1.jpg | Bin js/{app => spa}/test/files/contract.pdf | Bin js/{app => spa}/test/files/face.obj | 0 js/{app => spa}/test/files/file_test.ogg | Bin js/spa/test/files/gradio-logo.svg | 19 + js/{app => spa}/test/files/time.csv | 0 js/{app => spa}/test/files/titanic.csv | 0 js/{app => spa}/test/files/world.mp4 | Bin js/{app => spa}/test/function_values.spec.ts | 0 .../test/gallery_component_events.spec.ts | 0 js/{app => spa}/test/gradio_pdf_demo.spec.ts | 0 .../test/hello_world.reload.spec.ts | 0 .../test/image_component_events.spec.ts | 0 .../test/image_editor_events.spec.ts | 0 js/{app => spa}/test/image_mod.spec.ts | 0 js/{app => spa}/test/input_output.spec.ts | 0 js/{app => spa}/test/kitchen_sink.spec.ts | 0 js/{app => spa}/test/media_data.ts | 0 js/{app => spa}/test/mini_leaderboard.spec.ts | 0 .../test/model3d_component_events.spec.ts | 0 js/{app => spa}/test/on_listener_test.spec.ts | 0 .../test/outbreak_forecast.spec.ts | 0 .../test/queue_full_e2e_test.spec.ts | 0 js/{app => spa}/test/rapid_generation.spec.ts | 0 js/{app => spa}/test/render_merge.spec.ts | 0 js/{app => spa}/test/state_change.spec.ts | 0 js/{app => spa}/test/stream_audio_out.spec.ts | 0 js/{app => spa}/test/sub_block_render.spec.ts | 0 js/{app => spa}/test/tabs.spec.ts | 0 .../test/test_chatinterface.reload.spec.ts | 0 .../test_chatinterface_streaming_echo.spec.ts | 0 js/{app => spa}/test/tests.md | 0 js/{app => spa}/test/theme_builder.spec.ts | 0 js/{app => spa}/test/todo_list.spec.ts | 0 .../test/unload_event_test.spec.ts | 0 .../upload_button_component_events.spec.ts | 0 .../test/upload_file_limit_test.spec.ts | 0 js/{app => spa}/test/utils.ts | 0 .../test/video_component_events.spec.ts | 0 js/spa/vite.config.ts | 159 + js/storybook/preview.ts | 4 +- js/storybook/vite.config.js | 3 +- js/uploadbutton/UploadButton.test.ts | 5 +- js/video/Video.test.ts | 2 +- js/video/shared/VideoPreview.svelte | 2 +- js/wasm/src/worker-proxy.ts | 2 +- js/wasm/tsconfig.json | 90 - js/wasm/vite.worker.config.js | 4 +- package.json | 21 +- pnpm-lock.yaml | 613 +- scripts/build_lite.sh | 2 +- scripts/run_lite.sh | 4 +- tsconfig.json | 2 +- 244 files changed, 9859 insertions(+), 982 deletions(-) create mode 100644 .changeset/wise-buttons-act.md delete mode 100644 =23.2 delete mode 100644 gradio/hash_seed.txt delete mode 100644 js/_website/vite.config.ts.timestamp-1721955124085-e178b44edfdf6.mjs create mode 100644 js/app/README.md create mode 100644 js/app/src/app.d.ts create mode 100644 js/app/src/app.html create mode 100644 js/app/src/lib/index.ts create mode 100644 js/app/src/routes/+page.svelte create mode 100644 js/app/static/favicon.png create mode 100644 js/app/svelte.config.js create mode 100644 js/app/tsconfig.json create mode 100644 js/build/README.md rename js/{app => build/dist}/component_loader.js (100%) create mode 100644 js/build/dist/index.js create mode 100644 js/build/package.json create mode 100644 js/build/src/component_loader.js rename js/{app/build_plugins.ts => build/src/index.ts} (97%) create mode 100644 js/button/main.ts create mode 100644 js/core/.gitignore create mode 100644 js/core/blocks.ts create mode 100644 js/core/index.ts create mode 100644 js/core/login.ts create mode 100644 js/core/package.json rename js/{app => core}/public/favicon.png (100%) rename js/{app => core}/public/static/img/Bunny.obj (100%) rename js/{app => core}/public/static/img/Duck.glb (100%) rename js/{app => core}/public/static/img/api-logo.svg (100%) rename js/{app => core}/public/static/img/camera.svg (100%) rename js/{app => core}/public/static/img/clear.svg (100%) rename js/{app => core}/public/static/img/edit.svg (100%) rename js/{app => core}/public/static/img/javascript.svg (100%) rename js/{app => core}/public/static/img/logo.svg (100%) rename js/{app => core}/public/static/img/logo_error.svg (100%) rename js/{app => core}/public/static/img/python.svg (100%) rename js/{app => core}/public/static/img/undo-solid.svg (100%) rename js/{app => core}/src/Blocks.svelte (100%) rename js/{app => core}/src/Embed.svelte (100%) rename js/{app => core}/src/Login.stories.svelte (100%) rename js/{app => core}/src/Login.svelte (100%) rename js/{app => core}/src/MountComponents.svelte (100%) rename js/{app => core}/src/Render.svelte (100%) rename js/{app => core}/src/RenderComponent.svelte (100%) rename js/{app => core}/src/api_docs/ApiBanner.svelte (96%) rename js/{app => core}/src/api_docs/ApiDocs.svelte (100%) rename js/{app => core}/src/api_docs/ApiRecorder.svelte (100%) rename js/{app => core}/src/api_docs/CodeSnippet.svelte (95%) rename js/{app => core}/src/api_docs/CopyButton.svelte (100%) rename js/{app => core}/src/api_docs/EndpointDetail.svelte (100%) rename js/{app => core}/src/api_docs/InputPayload.svelte (100%) rename js/{app => core}/src/api_docs/InstallSnippet.svelte (100%) rename js/{app => core}/src/api_docs/NoApi.svelte (100%) rename js/{app => core}/src/api_docs/ParametersSnippet.svelte (100%) rename js/{app => core}/src/api_docs/RecordingSnippet.svelte (96%) rename js/{app => core}/src/api_docs/ResponseSnippet.svelte (100%) rename js/{app => core}/src/api_docs/TryButton.svelte (100%) rename js/{app => core}/src/api_docs/img/api-logo.svg (100%) rename js/{app => core}/src/api_docs/img/bash.svg (100%) rename js/{app => core}/src/api_docs/img/clear.svelte (100%) rename js/{app => core}/src/api_docs/img/javascript.svg (100%) rename js/{app => core}/src/api_docs/img/python.svg (100%) rename js/{app => core}/src/api_docs/index.ts (100%) rename js/{app => core}/src/api_docs/utils.ts (100%) rename js/{app => core}/src/css.ts (100%) rename js/{app => core}/src/gradio_helper.ts (100%) rename js/{app => core}/src/i18n.test.ts (100%) rename js/{app => core}/src/i18n.ts (100%) rename js/{app => core}/src/images/lightning.svg (100%) rename js/{app => core}/src/images/logo.svg (100%) rename js/{app => core}/src/images/play.svg (100%) rename js/{app => core}/src/images/spaces.svg (100%) rename js/{app => core}/src/init.test.ts (100%) rename js/{app => core}/src/init.ts (100%) rename js/{app => core}/src/lang/BCP47_codes.js (100%) rename js/{app => core}/src/lang/README.md (85%) rename js/{app => core}/src/lang/ar.json (100%) rename js/{app => core}/src/lang/ca.json (100%) rename js/{app => core}/src/lang/ckb.json (100%) rename js/{app => core}/src/lang/de.json (100%) rename js/{app => core}/src/lang/en.json (100%) rename js/{app => core}/src/lang/es.json (100%) rename js/{app => core}/src/lang/eu.json (100%) rename js/{app => core}/src/lang/fa.json (100%) rename js/{app => core}/src/lang/fr.json (100%) rename js/{app => core}/src/lang/he.json (100%) rename js/{app => core}/src/lang/hi.json (100%) rename js/{app => core}/src/lang/ja.json (100%) rename js/{app => core}/src/lang/ko.json (100%) rename js/{app => core}/src/lang/lt.json (100%) rename js/{app => core}/src/lang/nl.json (100%) rename js/{app => core}/src/lang/pl.json (100%) rename js/{app => core}/src/lang/pt-BR.json (100%) rename js/{app => core}/src/lang/ru.json (100%) rename js/{app => core}/src/lang/ta.json (100%) rename js/{app => core}/src/lang/tr.json (100%) rename js/{app => core}/src/lang/uk.json (100%) rename js/{app => core}/src/lang/ur.json (100%) rename js/{app => core}/src/lang/uz.json (100%) rename js/{app => core}/src/lang/zh-CN.json (100%) rename js/{app => core}/src/lang/zh-TW.json (100%) create mode 100644 js/core/src/s-blocks.ts create mode 100644 js/core/src/s-login.ts rename js/{app => core}/src/stores.ts (100%) rename js/{app => core}/src/types.ts (100%) rename js/{app => core}/src/vite-env-override.d.ts (100%) rename js/{app => lite}/lite.html (92%) rename js/{app/src/lite => lite/src}/ErrorDisplay.svelte (96%) rename js/{app/src/lite => lite/src}/LiteIndex.svelte (97%) rename js/{app/src/lite => lite/src}/Playground.svelte (98%) rename js/{app/src/lite => lite/src}/css.ts (97%) rename js/{app/src/lite => lite/src}/custom-element/indent.ts (100%) rename js/{app/src/lite => lite/src}/custom-element/index.test.ts (100%) rename js/{app/src/lite => lite/src}/custom-element/index.ts (99%) rename js/{app/src/lite => lite/src}/dev/App.svelte (100%) rename js/{app/src/lite => lite/src}/fetch.ts (100%) create mode 100644 js/lite/src/images/lightning.svg create mode 100644 js/lite/src/images/logo.svg create mode 100644 js/lite/src/images/play.svg create mode 100644 js/lite/src/images/spaces.svg rename js/{app/src/lite => lite/src}/index.ts (98%) rename js/{app/src/lite => lite/src}/sse.ts (100%) create mode 100644 js/lite/src/theme.css create mode 100644 js/lite/vite.config.ts create mode 100644 js/spa/.gitignore create mode 100644 js/spa/component_loader.js rename js/{app => spa}/index.html (100%) create mode 100644 js/spa/package.json rename js/{app => spa}/postcss.config.js (100%) create mode 100644 js/spa/public/favicon.png create mode 100644 js/spa/public/static/img/Bunny.obj create mode 100644 js/spa/public/static/img/Duck.glb create mode 100644 js/spa/public/static/img/api-logo.svg create mode 100644 js/spa/public/static/img/camera.svg create mode 100644 js/spa/public/static/img/clear.svg create mode 100644 js/spa/public/static/img/edit.svg create mode 100644 js/spa/public/static/img/javascript.svg rename js/{app/test/files/gradio-logo.svg => spa/public/static/img/logo.svg} (100%) create mode 100644 js/spa/public/static/img/logo_error.svg create mode 100644 js/spa/public/static/img/python.svg create mode 100644 js/spa/public/static/img/undo-solid.svg rename js/{app => spa}/src/Index.svelte (96%) rename js/{app => spa}/src/main.ts (98%) create mode 100644 js/spa/src/vite-env-override.d.ts rename js/{app => spa}/test/audio_component_events.spec.ts (100%) rename js/{app => spa}/test/audio_debugger.spec.ts (100%) rename js/{app => spa}/test/blocks_chained_events.spec.ts (100%) rename js/{app => spa}/test/blocks_essay.spec.ts (100%) rename js/{app => spa}/test/blocks_flashcards.spec.ts (100%) rename js/{app => spa}/test/blocks_flipper.spec.ts (100%) rename js/{app => spa}/test/blocks_inputs.spec.ts (100%) rename js/{app => spa}/test/blocks_page_load.spec.ts (100%) rename js/{app => spa}/test/blocks_xray.spec.ts (100%) rename js/{app => spa}/test/cancel_events.spec.ts (100%) rename js/{app => spa}/test/chatbot_core_components_simple.spec.ts (100%) rename js/{app => spa}/test/chatbot_multimodal.spec.ts (100%) rename js/{app => spa}/test/chatbot_with_tools.spec.ts (100%) rename js/{app => spa}/test/clear_components.spec.ts (100%) rename js/{app => spa}/test/components.test.ts (98%) rename js/{app => spa}/test/custom_css.spec.ts (100%) rename js/{app => spa}/test/dataframe_colorful.spec.ts (100%) rename js/{app => spa}/test/datetimes.spec.ts (100%) rename js/{app => spa}/test/file_component_events.spec.ts (100%) rename js/{app => spa}/test/file_explorer_component_events.spec.ts (100%) rename js/{app => spa}/test/files/alphabet.txt (100%) rename js/{app => spa}/test/files/cheetah1.jpg (100%) rename js/{app => spa}/test/files/contract.pdf (100%) rename js/{app => spa}/test/files/face.obj (100%) rename js/{app => spa}/test/files/file_test.ogg (100%) create mode 100644 js/spa/test/files/gradio-logo.svg rename js/{app => spa}/test/files/time.csv (100%) rename js/{app => spa}/test/files/titanic.csv (100%) rename js/{app => spa}/test/files/world.mp4 (100%) rename js/{app => spa}/test/function_values.spec.ts (100%) rename js/{app => spa}/test/gallery_component_events.spec.ts (100%) rename js/{app => spa}/test/gradio_pdf_demo.spec.ts (100%) rename js/{app => spa}/test/hello_world.reload.spec.ts (100%) rename js/{app => spa}/test/image_component_events.spec.ts (100%) rename js/{app => spa}/test/image_editor_events.spec.ts (100%) rename js/{app => spa}/test/image_mod.spec.ts (100%) rename js/{app => spa}/test/input_output.spec.ts (100%) rename js/{app => spa}/test/kitchen_sink.spec.ts (100%) rename js/{app => spa}/test/media_data.ts (100%) rename js/{app => spa}/test/mini_leaderboard.spec.ts (100%) rename js/{app => spa}/test/model3d_component_events.spec.ts (100%) rename js/{app => spa}/test/on_listener_test.spec.ts (100%) rename js/{app => spa}/test/outbreak_forecast.spec.ts (100%) rename js/{app => spa}/test/queue_full_e2e_test.spec.ts (100%) rename js/{app => spa}/test/rapid_generation.spec.ts (100%) rename js/{app => spa}/test/render_merge.spec.ts (100%) rename js/{app => spa}/test/state_change.spec.ts (100%) rename js/{app => spa}/test/stream_audio_out.spec.ts (100%) rename js/{app => spa}/test/sub_block_render.spec.ts (100%) rename js/{app => spa}/test/tabs.spec.ts (100%) rename js/{app => spa}/test/test_chatinterface.reload.spec.ts (100%) rename js/{app => spa}/test/test_chatinterface_streaming_echo.spec.ts (100%) rename js/{app => spa}/test/tests.md (100%) rename js/{app => spa}/test/theme_builder.spec.ts (100%) rename js/{app => spa}/test/todo_list.spec.ts (100%) rename js/{app => spa}/test/unload_event_test.spec.ts (100%) rename js/{app => spa}/test/upload_button_component_events.spec.ts (100%) rename js/{app => spa}/test/upload_file_limit_test.spec.ts (100%) rename js/{app => spa}/test/utils.ts (100%) rename js/{app => spa}/test/video_component_events.spec.ts (100%) create mode 100644 js/spa/vite.config.ts diff --git a/.changeset/wise-buttons-act.md b/.changeset/wise-buttons-act.md new file mode 100644 index 0000000000..f318b9a370 --- /dev/null +++ b/.changeset/wise-buttons-act.md @@ -0,0 +1,19 @@ +--- +"@gradio/audio": patch +"@gradio/build": patch +"@gradio/button": patch +"@gradio/chatbot": patch +"@gradio/core": patch +"@gradio/dataframe": patch +"@gradio/lite": patch +"@gradio/plot": patch +"@gradio/spa": patch +"@gradio/storybook": patch +"@gradio/video": patch +"@gradio/wasm": patch +"app": patch +"gradio": patch +"website": patch +--- + +feat:Initial SSR refactor diff --git a/.config/.prettierignore b/.config/.prettierignore index 5d6bc02f33..aeb550d7b8 100644 --- a/.config/.prettierignore +++ b/.config/.prettierignore @@ -18,7 +18,7 @@ **/.mypy_cache/** !test-strategy.md **/js/_space-test/** -../js/app/src/lite/theme.css +../js/lite/src/theme.css ../js/storybook/theme.css **/gradio_cached_examples/** **/storybook-static/** diff --git a/.config/.prettierrc.json b/.config/.prettierrc.json index 0e8b0ad886..4e22682cf5 100644 --- a/.config/.prettierrc.json +++ b/.config/.prettierrc.json @@ -3,5 +3,6 @@ "singleQuote": false, "trailingComma": "none", "printWidth": 80, - "plugins": ["prettier-plugin-svelte"] + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] } diff --git a/.config/eslint.config.js b/.config/eslint.config.js index 91f8b304a2..d641d4256a 100644 --- a/.config/eslint.config.js +++ b/.config/eslint.config.js @@ -70,7 +70,7 @@ export default [ "**/*.spec.ts", "**/*.test.ts", "**/*.node-test.ts", - "js/app/test/**/*", + "js/spa/test/**/*", "**/*vite.config.ts", "**/_website/**/*", "**/_spaces-test/**/*", diff --git a/.config/playwright-setup.js b/.config/playwright-setup.js index a3fffc09a4..8ec01138ed 100644 --- a/.config/playwright-setup.js +++ b/.config/playwright-setup.js @@ -8,7 +8,7 @@ import kl from "kleur"; const __dirname = fileURLToPath(new URL(".", import.meta.url)); const TEST_APP_PATH = join(__dirname, "./test.py"); -const TEST_FILES_PATH = join(__dirname, "..", "js", "app", "test"); +const TEST_FILES_PATH = join(__dirname, "..", "js", "spa", "test"); const ROOT = join(__dirname, ".."); const test_files = readdirSync(TEST_FILES_PATH) diff --git a/.config/vitest.config.ts b/.config/vitest.config.ts index 9de93ad0ec..be7741d0a2 100644 --- a/.config/vitest.config.ts +++ b/.config/vitest.config.ts @@ -1,3 +1,3 @@ -import config from "../js/app/vite.config"; +import config from "../js/spa/vite.config"; export default config; diff --git a/.github/actions/install-frontend-deps/action.yml b/.github/actions/install-frontend-deps/action.yml index f2d714033d..07f726b978 100644 --- a/.github/actions/install-frontend-deps/action.yml +++ b/.github/actions/install-frontend-deps/action.yml @@ -48,4 +48,4 @@ runs: run: | . venv/bin/activate python -m pip install -U build hatch packaging>=23.2 # packaging>=23.2 is needed to build Lite due to https://github.com/pypa/hatch/issues/1381 - pnpm --filter @gradio/app build:lite + pnpm --filter @gradio/lite build diff --git a/.github/workflows/test-functional-lite.yml b/.github/workflows/test-functional-lite.yml index 2cefe198b1..f9b7d6d387 100644 --- a/.github/workflows/test-functional-lite.yml +++ b/.github/workflows/test-functional-lite.yml @@ -53,7 +53,7 @@ jobs: - name: Run Lite E2E tests run: | . venv/bin/activate - pnpm --filter @gradio/app test:browser:lite + pnpm --filter @gradio/lite test:browser - name: Get the performance result run: | export LITE_APP_LOAD_TIME=$(jq -r '.app_load_time' .lite-perf.json) diff --git a/.github/workflows/trigger-changeset.yml b/.github/workflows/trigger-changeset.yml index ffad71ed42..7b6c201bda 100644 --- a/.github/workflows/trigger-changeset.yml +++ b/.github/workflows/trigger-changeset.yml @@ -4,6 +4,7 @@ on: types: [opened, synchronize, reopened, edited, labeled, unlabeled] branches: - main + - 5.0-dev issue_comment: types: [edited] diff --git a/.gitignore b/.gitignore index 982d4ffc86..683223f124 100644 --- a/.gitignore +++ b/.gitignore @@ -8,12 +8,15 @@ __pycache__/ *.py[cod] *$py.class build/ +!js/build/ +!js/build/dist/ __tmp/* *.pyi !gradio/stubs/**/*.pyi py.typed .ipynb_checkpoints/ .python-version +=23.2 # JS build gradio/templates/* @@ -38,6 +41,8 @@ coverage.xml test.txt **/snapshots/**/*.png playwright-report/ +.hypothesis +.lite-perf.json # Demos demo/tmp.zip diff --git a/.vscode/settings.json b/.vscode/settings.json index e6ea6a28fb..f0632753d2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,6 +21,6 @@ }, "typescript.tsdk": "node_modules/typescript/lib", "i18n-ally.localesPaths": [ - "js/app/src/lang" + "js/spa/src/lang" ] } diff --git a/=23.2 b/=23.2 deleted file mode 100644 index 4b0ecdffc0..0000000000 --- a/=23.2 +++ /dev/null @@ -1,49 +0,0 @@ -Requirement already satisfied: build in ./venv/lib/python3.8/site-packages (1.2.1) -Requirement already satisfied: hatch in ./venv/lib/python3.8/site-packages (1.12.0) -Requirement already satisfied: packaging in ./venv/lib/python3.8/site-packages (24.1) -Requirement already satisfied: pyproject_hooks in ./venv/lib/python3.8/site-packages (from build) (1.0.0) -Requirement already satisfied: importlib-metadata>=4.6 in ./venv/lib/python3.8/site-packages (from build) (7.0.1) -Requirement already satisfied: tomli>=1.1.0 in ./venv/lib/python3.8/site-packages (from build) (2.0.1) -Requirement already satisfied: click>=8.0.6 in ./venv/lib/python3.8/site-packages (from hatch) (8.1.7) -Requirement already satisfied: hatchling>=1.24.2 in ./venv/lib/python3.8/site-packages (from hatch) (1.24.2) -Requirement already satisfied: httpx>=0.22.0 in ./venv/lib/python3.8/site-packages (from hatch) (0.27.0) -Requirement already satisfied: hyperlink>=21.0.0 in ./venv/lib/python3.8/site-packages (from hatch) (21.0.0) -Requirement already satisfied: keyring>=23.5.0 in ./venv/lib/python3.8/site-packages (from hatch) (25.2.0) -Requirement already satisfied: pexpect~=4.8 in ./venv/lib/python3.8/site-packages (from hatch) (4.8.0) -Requirement already satisfied: platformdirs>=2.5.0 in ./venv/lib/python3.8/site-packages (from hatch) (4.2.1) -Requirement already satisfied: rich>=11.2.0 in ./venv/lib/python3.8/site-packages (from hatch) (13.7.0) -Requirement already satisfied: shellingham>=1.4.0 in ./venv/lib/python3.8/site-packages (from hatch) (1.5.4) -Requirement already satisfied: tomli-w>=1.0 in ./venv/lib/python3.8/site-packages (from hatch) (1.0.0) -Requirement already satisfied: tomlkit>=0.11.1 in ./venv/lib/python3.8/site-packages (from hatch) (0.12.0) -Requirement already satisfied: userpath~=1.7 in ./venv/lib/python3.8/site-packages (from hatch) (1.9.2) -Requirement already satisfied: uv>=0.1.35 in ./venv/lib/python3.8/site-packages (from hatch) (0.1.42) -Requirement already satisfied: virtualenv>=20.26.1 in ./venv/lib/python3.8/site-packages (from hatch) (20.26.1) -Requirement already satisfied: zstandard<1 in ./venv/lib/python3.8/site-packages (from hatch) (0.22.0) -Requirement already satisfied: pathspec>=0.10.1 in ./venv/lib/python3.8/site-packages (from hatchling>=1.24.2->hatch) (0.12.1) -Requirement already satisfied: pluggy>=1.0.0 in ./venv/lib/python3.8/site-packages (from hatchling>=1.24.2->hatch) (1.0.0) -Requirement already satisfied: trove-classifiers in ./venv/lib/python3.8/site-packages (from hatchling>=1.24.2->hatch) (2024.4.10) -Requirement already satisfied: anyio in ./venv/lib/python3.8/site-packages (from httpx>=0.22.0->hatch) (3.6.1) -Requirement already satisfied: certifi in ./venv/lib/python3.8/site-packages (from httpx>=0.22.0->hatch) (2022.6.15) -Requirement already satisfied: httpcore==1.* in ./venv/lib/python3.8/site-packages (from httpx>=0.22.0->hatch) (1.0.5) -Requirement already satisfied: idna in ./venv/lib/python3.8/site-packages (from httpx>=0.22.0->hatch) (3.3) -Requirement already satisfied: sniffio in ./venv/lib/python3.8/site-packages (from httpx>=0.22.0->hatch) (1.2.0) -Requirement already satisfied: h11<0.15,>=0.13 in ./venv/lib/python3.8/site-packages (from httpcore==1.*->httpx>=0.22.0->hatch) (0.14.0) -Requirement already satisfied: zipp>=0.5 in ./venv/lib/python3.8/site-packages (from importlib-metadata>=4.6->build) (3.17.0) -Requirement already satisfied: jaraco.classes in ./venv/lib/python3.8/site-packages (from keyring>=23.5.0->hatch) (3.4.0) -Requirement already satisfied: jaraco.functools in ./venv/lib/python3.8/site-packages (from keyring>=23.5.0->hatch) (4.0.1) -Requirement already satisfied: jaraco.context in ./venv/lib/python3.8/site-packages (from keyring>=23.5.0->hatch) (5.3.0) -Requirement already satisfied: importlib-resources in ./venv/lib/python3.8/site-packages (from keyring>=23.5.0->hatch) (6.1.1) -Requirement already satisfied: SecretStorage>=3.2 in ./venv/lib/python3.8/site-packages (from keyring>=23.5.0->hatch) (3.3.3) -Requirement already satisfied: jeepney>=0.4.2 in ./venv/lib/python3.8/site-packages (from keyring>=23.5.0->hatch) (0.8.0) -Requirement already satisfied: ptyprocess>=0.5 in ./venv/lib/python3.8/site-packages (from pexpect~=4.8->hatch) (0.7.0) -Requirement already satisfied: markdown-it-py>=2.2.0 in ./venv/lib/python3.8/site-packages (from rich>=11.2.0->hatch) (3.0.0) -Requirement already satisfied: pygments<3.0.0,>=2.13.0 in ./venv/lib/python3.8/site-packages (from rich>=11.2.0->hatch) (2.17.2) -Requirement already satisfied: typing-extensions<5.0,>=4.0.0 in ./venv/lib/python3.8/site-packages (from rich>=11.2.0->hatch) (4.9.0) -Requirement already satisfied: distlib<1,>=0.3.7 in ./venv/lib/python3.8/site-packages (from virtualenv>=20.26.1->hatch) (0.3.8) -Requirement already satisfied: filelock<4,>=3.12.2 in ./venv/lib/python3.8/site-packages (from virtualenv>=20.26.1->hatch) (3.15.3) -Requirement already satisfied: mdurl~=0.1 in ./venv/lib/python3.8/site-packages (from markdown-it-py>=2.2.0->rich>=11.2.0->hatch) (0.1.2) -Requirement already satisfied: cryptography>=2.0 in ./venv/lib/python3.8/site-packages (from SecretStorage>=3.2->keyring>=23.5.0->hatch) (42.0.5) -Requirement already satisfied: more-itertools in ./venv/lib/python3.8/site-packages (from jaraco.classes->keyring>=23.5.0->hatch) (10.2.0) -Requirement already satisfied: backports.tarfile in ./venv/lib/python3.8/site-packages (from jaraco.context->keyring>=23.5.0->hatch) (1.1.1) -Requirement already satisfied: cffi>=1.12 in ./venv/lib/python3.8/site-packages (from cryptography>=2.0->SecretStorage>=3.2->keyring>=23.5.0->hatch) (1.16.0) -Requirement already satisfied: pycparser in ./venv/lib/python3.8/site-packages (from cffi>=1.12->cryptography>=2.0->SecretStorage>=3.2->keyring>=23.5.0->hatch) (2.22) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0db210a1ea..47d8976c17 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,7 +133,7 @@ bash scripts/run_all_tests.sh pnpm test ``` -- Browser tests are located in `js/app/test` and are defined as `*spec.ts` files. To run browser tests: +- Browser tests are located in `js/spa/test` and are defined as `*spec.ts` files. To run browser tests: ``` pnpm test:browser @@ -257,7 +257,7 @@ bash scripts/run_lite.sh If you make changes to the Python code during development, you will need to rebuild the Python packages loaded to Graio-Lite. To do this, run: ``` -pnpm --filter @gradio/app pybuild +pnpm --filter @gradio/lite pybuild ``` To generate the release build, run: @@ -309,7 +309,7 @@ Verify that you've used the correct filename of your gradio app, and that you're --- -```ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL @gradio/app@1.0.0 build:local: vite build --mode production:local --emptyOutDir "--emptyOutDir"``` +```ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL @gradio/spa@1.0.0 build:local: vite build --mode production:local --emptyOutDir "--emptyOutDir"``` Delete `/node_modules` and `pnpm-lock.yaml`: diff --git a/gradio/hash_seed.txt b/gradio/hash_seed.txt deleted file mode 100644 index 705dc5d29f..0000000000 --- a/gradio/hash_seed.txt +++ /dev/null @@ -1 +0,0 @@ -f7311342c5e04ba58dd320ef66cfecd0 \ No newline at end of file diff --git a/js/_website/vite.config.ts b/js/_website/vite.config.ts index 70b30b3601..14762ec0f6 100644 --- a/js/_website/vite.config.ts +++ b/js/_website/vite.config.ts @@ -1,7 +1,8 @@ import { sveltekit } from "@sveltejs/kit/vite"; import { defineConfig } from "vite"; -import { inject_component_loader } from "../app/build_plugins"; +import { inject_component_loader } from "../build/dist/index.js"; +//@ts-ignore export default defineConfig(({ mode }) => ({ plugins: [sveltekit(), inject_component_loader({ mode })] })); diff --git a/js/_website/vite.config.ts.timestamp-1721955124085-e178b44edfdf6.mjs b/js/_website/vite.config.ts.timestamp-1721955124085-e178b44edfdf6.mjs deleted file mode 100644 index 983167bb58..0000000000 --- a/js/_website/vite.config.ts.timestamp-1721955124085-e178b44edfdf6.mjs +++ /dev/null @@ -1,159 +0,0 @@ -// vite.config.ts -import { sveltekit } from "file:///Users/aliabdalla/Documents/dev/gradio/node_modules/.pnpm/@sveltejs+kit@2.5.7_@sveltejs+vite-plugin-svelte@3.1.0_svelte@4.2.15_vite@5.2.11_@types+node@_2u6hychzf2d76zlobih55fgrzy/node_modules/@sveltejs/kit/src/exports/vite/index.js"; -import { defineConfig } from "file:///Users/aliabdalla/Documents/dev/gradio/node_modules/.pnpm/vite@5.2.11_@types+node@20.12.8_lightningcss@1.24.1_sass@1.66.1_stylus@0.63.0_sugarss@4.0.1_postcss@8.4.38_/node_modules/vite/dist/node/index.js"; - -// ../app/build_plugins.ts -import { parse } from "file:///Users/aliabdalla/Documents/dev/gradio/node_modules/.pnpm/node-html-parser@6.1.13/node_modules/node-html-parser/dist/index.js"; -import { join } from "path"; -import * as url from "url"; -import { readdirSync, existsSync, readFileSync, statSync } from "fs"; -var __vite_injected_original_import_meta_url = - "file:///Users/aliabdalla/Documents/dev/gradio/js/app/build_plugins.ts"; -var __filename = url.fileURLToPath(__vite_injected_original_import_meta_url); -var __dirname = url.fileURLToPath( - new URL(".", __vite_injected_original_import_meta_url) -); -function get_export_path(path, root, pkg_json) { - if (!pkg_json.exports) return void 0; - const _path = join(root, "..", `${pkg_json.exports[`${path}`]}`); - return existsSync(_path) ? _path : void 0; -} -var ignore_list = [ - "tootils", - "_cdn-test", - "_spaces-test", - "_website", - "app", - "atoms", - "fallback", - "icons", - "lite", - "preview", - "simpledropdown", - "simpleimage", - "simpletextbox", - "storybook", - "theme", - "timeseries", - "tooltip", - "upload", - "utils", - "wasm" -]; -function generate_component_imports() { - const exports = readdirSync(join(__dirname, "..")) - .map((dir) => { - if (ignore_list.includes(dir)) return void 0; - if (!statSync(join(__dirname, "..", dir)).isDirectory()) return void 0; - const package_json_path = join(__dirname, "..", dir, "package.json"); - if (existsSync(package_json_path)) { - const package_json = JSON.parse( - readFileSync(package_json_path, "utf8") - ); - const component = get_export_path(".", package_json_path, package_json); - const example = get_export_path( - "./example", - package_json_path, - package_json - ); - const base = get_export_path("./base", package_json_path, package_json); - if (!component && !example) return void 0; - return { - name: package_json.name, - component, - example, - base - }; - } - return void 0; - }) - .filter((x) => x !== void 0); - const imports = exports.reduce((acc, _export) => { - if (!_export) return acc; - const example = _export.example - ? `example: () => import("${_export.name}/example"), -` - : ""; - const base = _export.base - ? `base: () => import("${_export.name}/base"), -` - : ""; - return `${acc}"${_export.name.replace("@gradio/", "")}": { - ${base} - ${example} - component: () => import("${_export.name}") - }, -`; - }, ""); - return imports; -} -function load_virtual_component_loader(mode) { - const loader_path = join(__dirname, "component_loader.js"); - let component_map = ""; - if (mode === "test") { - component_map = ` - const component_map = { - "test-component-one": { - component: () => import("@gradio-test/test-one"), - example: () => import("@gradio-test/test-one/example") - }, - "dataset": { - component: () => import("@gradio-test/test-two"), - example: () => import("@gradio-test/test-two/example") - }, - "image": { - component: () => import("@gradio/image"), - example: () => import("@gradio/image/example"), - base: () => import("@gradio/image/base") - }, - "audio": { - component: () => import("@gradio/audio"), - example: () => import("@gradio/audio/example"), - base: () => import("@gradio/audio/base") - }, - "video": { - component: () => import("@gradio/video"), - example: () => import("@gradio/video/example"), - base: () => import("@gradio/video/base") - }, - // "test-component-one": { - // component: () => import("@gradio-test/test-one"), - // example: () => import("@gradio-test/test-one/example") - // }, - }; - `; - } else { - component_map = ` - const component_map = { - ${generate_component_imports()} - }; - `; - } - return `${component_map} - -${readFileSync(loader_path, "utf8")}`; -} -function inject_component_loader({ mode }) { - const v_id = "virtual:component-loader"; - const resolved_v_id = "\0" + v_id; - return { - name: "inject-component-loader", - enforce: "pre", - resolveId(id) { - if (id === v_id) return resolved_v_id; - }, - load(id) { - this.addWatchFile(join(__dirname, "component_loader.js")); - if (id === resolved_v_id) { - return load_virtual_component_loader(mode); - } - } - }; -} - -// vite.config.ts -var vite_config_default = defineConfig(({ mode }) => ({ - plugins: [sveltekit(), inject_component_loader({ mode })] -})); -export { vite_config_default as default }; -//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiLCAiLi4vYXBwL2J1aWxkX3BsdWdpbnMudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvYWxpYWJkYWxsYS9Eb2N1bWVudHMvZGV2L2dyYWRpby9qcy9fd2Vic2l0ZVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL2FsaWFiZGFsbGEvRG9jdW1lbnRzL2Rldi9ncmFkaW8vanMvX3dlYnNpdGUvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL1VzZXJzL2FsaWFiZGFsbGEvRG9jdW1lbnRzL2Rldi9ncmFkaW8vanMvX3dlYnNpdGUvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBzdmVsdGVraXQgfSBmcm9tIFwiQHN2ZWx0ZWpzL2tpdC92aXRlXCI7XG5pbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHsgaW5qZWN0X2NvbXBvbmVudF9sb2FkZXIgfSBmcm9tIFwiLi4vYXBwL2J1aWxkX3BsdWdpbnNcIjtcblxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKCh7IG1vZGUgfSkgPT4gKHtcblx0cGx1Z2luczogW3N2ZWx0ZWtpdCgpLCBpbmplY3RfY29tcG9uZW50X2xvYWRlcih7IG1vZGUgfSldXG59KSk7XG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9Vc2Vycy9hbGlhYmRhbGxhL0RvY3VtZW50cy9kZXYvZ3JhZGlvL2pzL2FwcFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL2FsaWFiZGFsbGEvRG9jdW1lbnRzL2Rldi9ncmFkaW8vanMvYXBwL2J1aWxkX3BsdWdpbnMudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL1VzZXJzL2FsaWFiZGFsbGEvRG9jdW1lbnRzL2Rldi9ncmFkaW8vanMvYXBwL2J1aWxkX3BsdWdpbnMudHNcIjtpbXBvcnQgdHlwZSB7IFBsdWdpbiB9IGZyb20gXCJ2aXRlXCI7XG5pbXBvcnQgeyBwYXJzZSwgSFRNTEVsZW1lbnQgfSBmcm9tIFwibm9kZS1odG1sLXBhcnNlclwiO1xuXG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IHdyaXRlRmlsZVN5bmMgfSBmcm9tIFwiZnNcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIGluamVjdF9lanMoKTogUGx1Z2luIHtcblx0cmV0dXJuIHtcblx0XHRuYW1lOiBcImluamVjdC1lanNcIixcblx0XHRlbmZvcmNlOiBcInBvc3RcIixcblx0XHR0cmFuc2Zvcm1JbmRleEh0bWw6IChodG1sKSA9PiB7XG5cdFx0XHRjb25zdCByZXBsYWNlX2dyYWRpb19pbmZvX2luZm9faHRtbCA9IGh0bWwucmVwbGFjZShcblx0XHRcdFx0LyVncmFkaW9fYXBpX2luZm8lLyxcblx0XHRcdFx0YDxzY3JpcHQ+d2luZG93LmdyYWRpb19hcGlfaW5mbyA9IHt7IGdyYWRpb19hcGlfaW5mbyB8IHRvb3Jqc29uIH19Ozwvc2NyaXB0PmBcblx0XHRcdCk7XG5cdFx0XHRyZXR1cm4gcmVwbGFjZV9ncmFkaW9faW5mb19pbmZvX2h0bWwucmVwbGFjZShcblx0XHRcdFx0LyVncmFkaW9fY29uZmlnJS8sXG5cdFx0XHRcdGA8c2NyaXB0PndpbmRvdy5ncmFkaW9fY29uZmlnID0ge3sgY29uZmlnIHwgdG9vcmpzb24gfX07PC9zY3JpcHQ+YFxuXHRcdFx0KTtcblx0XHR9XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZV9jZG5fZW50cnkoe1xuXHR2ZXJzaW9uLFxuXHRjZG5fYmFzZVxufToge1xuXHR2ZXJzaW9uOiBzdHJpbmc7XG5cdGNkbl9iYXNlOiBzdHJpbmc7XG59KTogUGx1Z2luIHtcblx0cmV0dXJuIHtcblx0XHRuYW1lOiBcImdlbmVyYXRlLWNkbi1lbnRyeVwiLFxuXHRcdGVuZm9yY2U6IFwicG9zdFwiLFxuXHRcdHdyaXRlQnVuZGxlKGNvbmZpZywgYnVuZGxlKSB7XG5cdFx0XHRpZiAoXG5cdFx0XHRcdCFjb25maWcuZGlyIHx8XG5cdFx0XHRcdCFidW5kbGVbXCJpbmRleC5odG1sXCJdIHx8XG5cdFx0XHRcdGJ1bmRsZVtcImluZGV4Lmh0bWxcIl0udHlwZSAhPT0gXCJhc3NldFwiXG5cdFx0XHQpXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0Y29uc3Qgc291cmNlID0gYnVuZGxlW1wiaW5kZXguaHRtbFwiXS5zb3VyY2UgYXMgc3RyaW5nO1xuXHRcdFx0Y29uc3QgdHJlZSA9IHBhcnNlKHNvdXJjZSk7XG5cblx0XHRcdGNvbnN0IHNjcmlwdCA9IEFycmF5LmZyb20oXG5cdFx0XHRcdHRyZWUucXVlcnlTZWxlY3RvckFsbChcInNjcmlwdFt0eXBlPW1vZHVsZV1cIilcblx0XHRcdCkuZmluZCgobm9kZSkgPT4gbm9kZS5hdHRyaWJ1dGVzLnNyYz8uaW5jbHVkZXMoXCJhc3NldHNcIikpO1xuXG5cdFx0XHRjb25zdCBvdXRwdXRfbG9jYXRpb24gPSBqb2luKGNvbmZpZy5kaXIsIFwiZ3JhZGlvLmpzXCIpO1xuXG5cdFx0XHR3cml0ZUZpbGVTeW5jKG91dHB1dF9sb2NhdGlvbiwgbWFrZV9lbnRyeShzY3JpcHQ/LmF0dHJpYnV0ZXMuc3JjIHx8IFwiXCIpKTtcblxuXHRcdFx0aWYgKCFzY3JpcHQpIHJldHVybjtcblxuXHRcdFx0Y29uc3QgdHJhbnNmb3JtZWRfaHRtbCA9XG5cdFx0XHRcdChidW5kbGVbXCJpbmRleC5odG1sXCJdLnNvdXJjZSBhcyBzdHJpbmcpLnN1YnN0cmluZygwLCBzY3JpcHQ/LnJhbmdlWzBdKSArXG5cdFx0XHRcdGA8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIiBjcm9zc29yaWdpbiBzcmM9XCIke2Nkbl9iYXNlfS8ke3ZlcnNpb259L2dyYWRpby5qc1wiPjwvc2NyaXB0PmAgK1xuXHRcdFx0XHQoYnVuZGxlW1wiaW5kZXguaHRtbFwiXS5zb3VyY2UgYXMgc3RyaW5nKS5zdWJzdHJpbmcoXG5cdFx0XHRcdFx0c2NyaXB0Py5yYW5nZVsxXSxcblx0XHRcdFx0XHRzb3VyY2UubGVuZ3RoXG5cdFx0XHRcdCk7XG5cblx0XHRcdGNvbnN0IHNoYXJlX2h0bWxfbG9jYXRpb24gPSBqb2luKGNvbmZpZy5kaXIsIFwic2hhcmUuaHRtbFwiKTtcblx0XHRcdHdyaXRlRmlsZVN5bmMoc2hhcmVfaHRtbF9sb2NhdGlvbiwgdHJhbnNmb3JtZWRfaHRtbCk7XG5cdFx0fVxuXHR9O1xufVxuXG5jb25zdCBSRV9TVkVMVEVfSU1QT1JUID1cblx0L2ltcG9ydFxccysoW1xcdyp7fSxcXHNdKylcXHMrZnJvbVxccytbJ1wiXShzdmVsdGV8c3ZlbHRlXFwvaW50ZXJuYWwpWydcIl0vZztcblxuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlX2Rldl9lbnRyeSh7IGVuYWJsZSB9OiB7IGVuYWJsZTogYm9vbGVhbiB9KTogUGx1Z2luIHtcblx0cmV0dXJuIHtcblx0XHRuYW1lOiBcImdlbmVyYXRlLWRldi1lbnRyeVwiLFxuXHRcdHRyYW5zZm9ybShjb2RlLCBpZCkge1xuXHRcdFx0aWYgKCFlbmFibGUpIHJldHVybjtcblxuXHRcdFx0Y29uc3QgbmV3X2NvZGUgPSBjb2RlLnJlcGxhY2UoUkVfU1ZFTFRFX0lNUE9SVCwgKHN0ciwgJDEsICQyKSA9PiB7XG5cdFx0XHRcdHJldHVybiBgY29uc3QgJHskMVxuXHRcdFx0XHRcdC5yZXBsYWNlKC9cXCogYXMgLywgXCJcIilcblx0XHRcdFx0XHQucmVwbGFjZSgvIGFzIC9nLCBcIjogXCIpfSA9IHdpbmRvdy5fX2dyYWRpb19fc3ZlbHRlX19pbnRlcm5hbDtgO1xuXHRcdFx0fSk7XG5cblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGNvZGU6IG5ld19jb2RlLFxuXHRcdFx0XHRtYXA6IG51bGxcblx0XHRcdH07XG5cdFx0fVxuXHR9O1xufVxuXG5mdW5jdGlvbiBtYWtlX2VudHJ5KHNjcmlwdDogc3RyaW5nKTogc3RyaW5nIHtcblx0cmV0dXJuIGBpbXBvcnQoXCIke3NjcmlwdH1cIik7XG5gO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlX2NlX2NzcygpOiBQbHVnaW4ge1xuXHRyZXR1cm4ge1xuXHRcdGVuZm9yY2U6IFwicG9zdFwiLFxuXHRcdG5hbWU6IFwiY3VzdG9tLWVsZW1lbnQtY3NzXCIsXG5cblx0XHR3cml0ZUJ1bmRsZShjb25maWcsIGJ1bmRsZSkge1xuXHRcdFx0bGV0IGZpbGVfdG9faW5zZXJ0ID0ge1xuXHRcdFx0XHRmaWxlbmFtZTogXCJcIixcblx0XHRcdFx0c291cmNlOiBcIlwiXG5cdFx0XHR9O1xuXG5cdFx0XHRpZiAoXG5cdFx0XHRcdCFjb25maWcuZGlyIHx8XG5cdFx0XHRcdCFidW5kbGVbXCJpbmRleC5odG1sXCJdIHx8XG5cdFx0XHRcdGJ1bmRsZVtcImluZGV4Lmh0bWxcIl0udHlwZSAhPT0gXCJhc3NldFwiXG5cdFx0XHQpXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0Zm9yIChjb25zdCBrZXkgaW4gYnVuZGxlKSB7XG5cdFx0XHRcdGNvbnN0IGNodW5rID0gYnVuZGxlW2tleV07XG5cdFx0XHRcdGlmIChjaHVuay50eXBlID09PSBcImNodW5rXCIpIHtcblx0XHRcdFx0XHRjb25zdCBfY2h1bmsgPSBjaHVuaztcblxuXHRcdFx0XHRcdGNvbnN0IGZvdW5kID0gX2NodW5rLmNvZGU/LmluZGV4T2YoXCJFTlRSWV9DU1NcIik7XG5cblx0XHRcdFx0XHRpZiAoZm91bmQgPiAtMSlcblx0XHRcdFx0XHRcdGZpbGVfdG9faW5zZXJ0ID0ge1xuXHRcdFx0XHRcdFx0XHRmaWxlbmFtZTogam9pbihjb25maWcuZGlyLCBrZXkpLFxuXHRcdFx0XHRcdFx0XHRzb3VyY2U6IF9jaHVuay5jb2RlXG5cdFx0XHRcdFx0XHR9O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHRyZWUgPSBwYXJzZShidW5kbGVbXCJpbmRleC5odG1sXCJdLnNvdXJjZSBhcyBzdHJpbmcpO1xuXG5cdFx0XHRjb25zdCB7IHN0eWxlLCBmb250cyB9ID0gQXJyYXkuZnJvbShcblx0XHRcdFx0dHJlZS5xdWVyeVNlbGVjdG9yQWxsKFwibGlua1tyZWw9c3R5bGVzaGVldF1cIilcblx0XHRcdCkucmVkdWNlKFxuXHRcdFx0XHQoYWNjLCBuZXh0KSA9PiB7XG5cdFx0XHRcdFx0aWYgKC8uKlxcL2luZGV4KC4qPylcXC5jc3MvLnRlc3QobmV4dC5hdHRyaWJ1dGVzLmhyZWYpKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4geyAuLi5hY2MsIHN0eWxlOiBuZXh0IH07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiB7IC4uLmFjYywgZm9udHM6IFsuLi5hY2MuZm9udHMsIG5leHQuYXR0cmlidXRlcy5ocmVmXSB9O1xuXHRcdFx0XHR9LFxuXHRcdFx0XHR7IGZvbnRzOiBbXSwgc3R5bGU6IHVuZGVmaW5lZCB9IGFzIHtcblx0XHRcdFx0XHRmb250czogc3RyaW5nW107XG5cdFx0XHRcdFx0c3R5bGU6IEhUTUxFbGVtZW50IHwgdW5kZWZpbmVkO1xuXHRcdFx0XHR9XG5cdFx0XHQpO1xuXG5cdFx0XHR3cml0ZUZpbGVTeW5jKFxuXHRcdFx0XHRmaWxlX3RvX2luc2VydC5maWxlbmFtZSxcblx0XHRcdFx0ZmlsZV90b19pbnNlcnQuc291cmNlXG5cdFx0XHRcdFx0LnJlcGxhY2UoXCJfX0VOVFJZX0NTU19fXCIsIHN0eWxlIS5hdHRyaWJ1dGVzLmhyZWYpXG5cdFx0XHRcdFx0LnJlcGxhY2UoXG5cdFx0XHRcdFx0XHQnXCJfX0ZPTlRTX0NTU19fXCInLFxuXHRcdFx0XHRcdFx0YFske2ZvbnRzLm1hcCgoZikgPT4gYFwiJHtmfVwiYCkuam9pbihcIixcIil9XWBcblx0XHRcdFx0XHQpXG5cdFx0XHQpO1xuXG5cdFx0XHRjb25zdCBzaGFyZV9odG1sX2xvY2F0aW9uID0gam9pbihjb25maWcuZGlyLCBcInNoYXJlLmh0bWxcIik7XG5cdFx0XHRjb25zdCBzaGFyZV9odG1sID0gcmVhZEZpbGVTeW5jKHNoYXJlX2h0bWxfbG9jYXRpb24sIFwidXRmOFwiKTtcblx0XHRcdGNvbnN0IHNoYXJlX3RyZWUgPSBwYXJzZShzaGFyZV9odG1sKTtcblx0XHRcdGNvbnN0IG5vZGUgPSBBcnJheS5mcm9tKFxuXHRcdFx0XHRzaGFyZV90cmVlLnF1ZXJ5U2VsZWN0b3JBbGwoXCJsaW5rW3JlbD1zdHlsZXNoZWV0XVwiKVxuXHRcdFx0KS5maW5kKChub2RlKSA9PiAvLipcXC9pbmRleCguKj8pXFwuY3NzLy50ZXN0KG5vZGUuYXR0cmlidXRlcy5ocmVmKSk7XG5cblx0XHRcdGlmICghbm9kZSkgcmV0dXJuO1xuXHRcdFx0Y29uc3QgdHJhbnNmb3JtZWRfaHRtbCA9XG5cdFx0XHRcdHNoYXJlX2h0bWwuc3Vic3RyaW5nKDAsIG5vZGUucmFuZ2VbMF0pICtcblx0XHRcdFx0c2hhcmVfaHRtbC5zdWJzdHJpbmcobm9kZS5yYW5nZVsxXSwgc2hhcmVfaHRtbC5sZW5ndGgpO1xuXG5cdFx0XHR3cml0ZUZpbGVTeW5jKHNoYXJlX2h0bWxfbG9jYXRpb24sIHRyYW5zZm9ybWVkX2h0bWwpO1xuXHRcdH1cblx0fTtcbn1cblxuLy8gZ2VuZXJhdGUgY29tcG9uZW50IGltcG9ydHN5XG5cbmltcG9ydCAqIGFzIHVybCBmcm9tIFwidXJsXCI7XG5jb25zdCBfX2ZpbGVuYW1lID0gdXJsLmZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoXCIuXCIsIGltcG9ydC5tZXRhLnVybCkpO1xuXG5pbXBvcnQgeyByZWFkZGlyU3luYywgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBzdGF0U3luYyB9IGZyb20gXCJmc1wiO1xuXG5mdW5jdGlvbiBnZXRfZXhwb3J0X3BhdGgoXG5cdHBhdGg6IHN0cmluZyxcblx0cm9vdDogc3RyaW5nLFxuXHRwa2dfanNvbjogUmVjb3JkPHN0cmluZywgYW55PlxuKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcblx0aWYgKCFwa2dfanNvbi5leHBvcnRzKSByZXR1cm4gdW5kZWZpbmVkO1xuXHRjb25zdCBfcGF0aCA9IGpvaW4ocm9vdCwgXCIuLlwiLCBgJHtwa2dfanNvbi5leHBvcnRzW2Ake3BhdGh9YF19YCk7XG5cblx0cmV0dXJuIGV4aXN0c1N5bmMoX3BhdGgpID8gX3BhdGggOiB1bmRlZmluZWQ7XG59XG5cbmNvbnN0IGlnbm9yZV9saXN0ID0gW1xuXHRcInRvb3RpbHNcIixcblx0XCJfY2RuLXRlc3RcIixcblx0XCJfc3BhY2VzLXRlc3RcIixcblx0XCJfd2Vic2l0ZVwiLFxuXHRcImFwcFwiLFxuXHRcImF0b21zXCIsXG5cdFwiZmFsbGJhY2tcIixcblx0XCJpY29uc1wiLFxuXHRcImxpdGVcIixcblx0XCJwcmV2aWV3XCIsXG5cdFwic2ltcGxlZHJvcGRvd25cIixcblx0XCJzaW1wbGVpbWFnZVwiLFxuXHRcInNpbXBsZXRleHRib3hcIixcblx0XCJzdG9yeWJvb2tcIixcblx0XCJ0aGVtZVwiLFxuXHRcInRpbWVzZXJpZXNcIixcblx0XCJ0b29sdGlwXCIsXG5cdFwidXBsb2FkXCIsXG5cdFwidXRpbHNcIixcblx0XCJ3YXNtXCJcbl07XG5mdW5jdGlvbiBnZW5lcmF0ZV9jb21wb25lbnRfaW1wb3J0cygpOiBzdHJpbmcge1xuXHRjb25zdCBleHBvcnRzID0gcmVhZGRpclN5bmMoam9pbihfX2Rpcm5hbWUsIFwiLi5cIikpXG5cdFx0Lm1hcCgoZGlyKSA9PiB7XG5cdFx0XHRpZiAoaWdub3JlX2xpc3QuaW5jbHVkZXMoZGlyKSkgcmV0dXJuIHVuZGVmaW5lZDtcblx0XHRcdGlmICghc3RhdFN5bmMoam9pbihfX2Rpcm5hbWUsIFwiLi5cIiwgZGlyKSkuaXNEaXJlY3RvcnkoKSkgcmV0dXJuIHVuZGVmaW5lZDtcblxuXHRcdFx0Y29uc3QgcGFja2FnZV9qc29uX3BhdGggPSBqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBkaXIsIFwicGFja2FnZS5qc29uXCIpO1xuXHRcdFx0aWYgKGV4aXN0c1N5bmMocGFja2FnZV9qc29uX3BhdGgpKSB7XG5cdFx0XHRcdGNvbnN0IHBhY2thZ2VfanNvbiA9IEpTT04ucGFyc2UoXG5cdFx0XHRcdFx0cmVhZEZpbGVTeW5jKHBhY2thZ2VfanNvbl9wYXRoLCBcInV0ZjhcIilcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRjb25zdCBjb21wb25lbnQgPSBnZXRfZXhwb3J0X3BhdGgoXCIuXCIsIHBhY2thZ2VfanNvbl9wYXRoLCBwYWNrYWdlX2pzb24pO1xuXHRcdFx0XHRjb25zdCBleGFtcGxlID0gZ2V0X2V4cG9ydF9wYXRoKFxuXHRcdFx0XHRcdFwiLi9leGFtcGxlXCIsXG5cdFx0XHRcdFx0cGFja2FnZV9qc29uX3BhdGgsXG5cdFx0XHRcdFx0cGFja2FnZV9qc29uXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0Y29uc3QgYmFzZSA9IGdldF9leHBvcnRfcGF0aChcIi4vYmFzZVwiLCBwYWNrYWdlX2pzb25fcGF0aCwgcGFja2FnZV9qc29uKTtcblxuXHRcdFx0XHRpZiAoIWNvbXBvbmVudCAmJiAhZXhhbXBsZSkgcmV0dXJuIHVuZGVmaW5lZDtcblxuXHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdG5hbWU6IHBhY2thZ2VfanNvbi5uYW1lLFxuXHRcdFx0XHRcdGNvbXBvbmVudCxcblx0XHRcdFx0XHRleGFtcGxlLFxuXHRcdFx0XHRcdGJhc2Vcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdFx0fSlcblx0XHQuZmlsdGVyKCh4KSA9PiB4ICE9PSB1bmRlZmluZWQpO1xuXG5cdGNvbnN0IGltcG9ydHMgPSBleHBvcnRzLnJlZHVjZSgoYWNjLCBfZXhwb3J0KSA9PiB7XG5cdFx0aWYgKCFfZXhwb3J0KSByZXR1cm4gYWNjO1xuXG5cdFx0Y29uc3QgZXhhbXBsZSA9IF9leHBvcnQuZXhhbXBsZVxuXHRcdFx0PyBgZXhhbXBsZTogKCkgPT4gaW1wb3J0KFwiJHtfZXhwb3J0Lm5hbWV9L2V4YW1wbGVcIiksXFxuYFxuXHRcdFx0OiBcIlwiO1xuXHRcdGNvbnN0IGJhc2UgPSBfZXhwb3J0LmJhc2Vcblx0XHRcdD8gYGJhc2U6ICgpID0+IGltcG9ydChcIiR7X2V4cG9ydC5uYW1lfS9iYXNlXCIpLFxcbmBcblx0XHRcdDogXCJcIjtcblx0XHRyZXR1cm4gYCR7YWNjfVwiJHtfZXhwb3J0Lm5hbWUucmVwbGFjZShcIkBncmFkaW8vXCIsIFwiXCIpfVwiOiB7XG5cdFx0XHQke2Jhc2V9XG5cdFx0XHQke2V4YW1wbGV9XG5cdFx0XHRjb21wb25lbnQ6ICgpID0+IGltcG9ydChcIiR7X2V4cG9ydC5uYW1lfVwiKVxuXHRcdFx0fSxcXG5gO1xuXHR9LCBcIlwiKTtcblxuXHRyZXR1cm4gaW1wb3J0cztcbn1cblxuZnVuY3Rpb24gbG9hZF92aXJ0dWFsX2NvbXBvbmVudF9sb2FkZXIobW9kZTogc3RyaW5nKTogc3RyaW5nIHtcblx0Y29uc3QgbG9hZGVyX3BhdGggPSBqb2luKF9fZGlybmFtZSwgXCJjb21wb25lbnRfbG9hZGVyLmpzXCIpO1xuXHRsZXQgY29tcG9uZW50X21hcCA9IFwiXCI7XG5cblx0aWYgKG1vZGUgPT09IFwidGVzdFwiKSB7XG5cdFx0Y29tcG9uZW50X21hcCA9IGBcblx0XHRjb25zdCBjb21wb25lbnRfbWFwID0ge1xuXHRcdFx0XCJ0ZXN0LWNvbXBvbmVudC1vbmVcIjoge1xuXHRcdFx0XHRjb21wb25lbnQ6ICgpID0+IGltcG9ydChcIkBncmFkaW8tdGVzdC90ZXN0LW9uZVwiKSxcblx0XHRcdFx0ZXhhbXBsZTogKCkgPT4gaW1wb3J0KFwiQGdyYWRpby10ZXN0L3Rlc3Qtb25lL2V4YW1wbGVcIilcblx0XHRcdH0sXG5cdFx0XHRcImRhdGFzZXRcIjoge1xuXHRcdFx0XHRjb21wb25lbnQ6ICgpID0+IGltcG9ydChcIkBncmFkaW8tdGVzdC90ZXN0LXR3b1wiKSxcblx0XHRcdFx0ZXhhbXBsZTogKCkgPT4gaW1wb3J0KFwiQGdyYWRpby10ZXN0L3Rlc3QtdHdvL2V4YW1wbGVcIilcblx0XHRcdH0sXG5cdFx0XHRcImltYWdlXCI6IHtcblx0XHRcdFx0Y29tcG9uZW50OiAoKSA9PiBpbXBvcnQoXCJAZ3JhZGlvL2ltYWdlXCIpLFxuXHRcdFx0XHRleGFtcGxlOiAoKSA9PiBpbXBvcnQoXCJAZ3JhZGlvL2ltYWdlL2V4YW1wbGVcIiksXG5cdFx0XHRcdGJhc2U6ICgpID0+IGltcG9ydChcIkBncmFkaW8vaW1hZ2UvYmFzZVwiKVxuXHRcdFx0fSxcblx0XHRcdFwiYXVkaW9cIjoge1xuXHRcdFx0XHRjb21wb25lbnQ6ICgpID0+IGltcG9ydChcIkBncmFkaW8vYXVkaW9cIiksXG5cdFx0XHRcdGV4YW1wbGU6ICgpID0+IGltcG9ydChcIkBncmFkaW8vYXVkaW8vZXhhbXBsZVwiKSxcblx0XHRcdFx0YmFzZTogKCkgPT4gaW1wb3J0KFwiQGdyYWRpby9hdWRpby9iYXNlXCIpXG5cdFx0XHR9LFxuXHRcdFx0XCJ2aWRlb1wiOiB7XG5cdFx0XHRcdGNvbXBvbmVudDogKCkgPT4gaW1wb3J0KFwiQGdyYWRpby92aWRlb1wiKSxcblx0XHRcdFx0ZXhhbXBsZTogKCkgPT4gaW1wb3J0KFwiQGdyYWRpby92aWRlby9leGFtcGxlXCIpLFxuXHRcdFx0XHRiYXNlOiAoKSA9PiBpbXBvcnQoXCJAZ3JhZGlvL3ZpZGVvL2Jhc2VcIilcblx0XHRcdH0sXG5cdFx0XHQvLyBcInRlc3QtY29tcG9uZW50LW9uZVwiOiB7XG5cdFx0XHQvLyBcdGNvbXBvbmVudDogKCkgPT4gaW1wb3J0KFwiQGdyYWRpby10ZXN0L3Rlc3Qtb25lXCIpLFxuXHRcdFx0Ly8gXHRleGFtcGxlOiAoKSA9PiBpbXBvcnQoXCJAZ3JhZGlvLXRlc3QvdGVzdC1vbmUvZXhhbXBsZVwiKVxuXHRcdFx0Ly8gfSxcblx0XHR9O1xuXHRcdGA7XG5cdH0gZWxzZSB7XG5cdFx0Y29tcG9uZW50X21hcCA9IGBcblx0XHRjb25zdCBjb21wb25lbnRfbWFwID0ge1xuXHRcdFx0JHtnZW5lcmF0ZV9jb21wb25lbnRfaW1wb3J0cygpfVxuXHRcdH07XG5cdFx0YDtcblx0fVxuXG5cdHJldHVybiBgJHtjb21wb25lbnRfbWFwfVxcblxcbiR7cmVhZEZpbGVTeW5jKGxvYWRlcl9wYXRoLCBcInV0ZjhcIil9YDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGluamVjdF9jb21wb25lbnRfbG9hZGVyKHsgbW9kZSB9OiB7IG1vZGU6IHN0cmluZyB9KTogUGx1Z2luIHtcblx0Y29uc3Qgdl9pZCA9IFwidmlydHVhbDpjb21wb25lbnQtbG9hZGVyXCI7XG5cdGNvbnN0IHJlc29sdmVkX3ZfaWQgPSBcIlxcMFwiICsgdl9pZDtcblxuXHRyZXR1cm4ge1xuXHRcdG5hbWU6IFwiaW5qZWN0LWNvbXBvbmVudC1sb2FkZXJcIixcblx0XHRlbmZvcmNlOiBcInByZVwiLFxuXHRcdHJlc29sdmVJZChpZDogc3RyaW5nKSB7XG5cdFx0XHRpZiAoaWQgPT09IHZfaWQpIHJldHVybiByZXNvbHZlZF92X2lkO1xuXHRcdH0sXG5cdFx0bG9hZChpZDogc3RyaW5nKSB7XG5cdFx0XHR0aGlzLmFkZFdhdGNoRmlsZShqb2luKF9fZGlybmFtZSwgXCJjb21wb25lbnRfbG9hZGVyLmpzXCIpKTtcblx0XHRcdGlmIChpZCA9PT0gcmVzb2x2ZWRfdl9pZCkge1xuXHRcdFx0XHRyZXR1cm4gbG9hZF92aXJ0dWFsX2NvbXBvbmVudF9sb2FkZXIobW9kZSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZV9zdmVsdGUoZW5hYmxlOiBib29sZWFuKTogUGx1Z2luIHtcblx0cmV0dXJuIHtcblx0XHRlbmZvcmNlOiBcInByZVwiLFxuXHRcdG5hbWU6IFwicmVzb2x2ZS1zdmVsdGVcIixcblx0XHRhc3luYyByZXNvbHZlSWQoaWQ6IHN0cmluZykge1xuXHRcdFx0aWYgKCFlbmFibGUpIHJldHVybjtcblxuXHRcdFx0aWYgKFxuXHRcdFx0XHRpZCA9PT0gXCIuL3N2ZWx0ZS9zdmVsdGUuanNcIiB8fFxuXHRcdFx0XHRpZCA9PT0gXCJzdmVsdGVcIiB8fFxuXHRcdFx0XHRpZCA9PT0gXCJzdmVsdGUvaW50ZXJuYWxcIlxuXHRcdFx0KSB7XG5cdFx0XHRcdGNvbnN0IG1vZCA9IGpvaW4oXG5cdFx0XHRcdFx0X19kaXJuYW1lLFxuXHRcdFx0XHRcdFwiLi5cIixcblx0XHRcdFx0XHRcIi4uXCIsXG5cdFx0XHRcdFx0XCJncmFkaW9cIixcblx0XHRcdFx0XHRcInRlbXBsYXRlc1wiLFxuXHRcdFx0XHRcdFwiZnJvbnRlbmRcIixcblx0XHRcdFx0XHRcImFzc2V0c1wiLFxuXHRcdFx0XHRcdFwic3ZlbHRlXCIsXG5cdFx0XHRcdFx0XCJzdmVsdGUuanNcIlxuXHRcdFx0XHQpO1xuXHRcdFx0XHRyZXR1cm4geyBpZDogbW9kLCBleHRlcm5hbDogXCJhYnNvbHV0ZVwiIH07XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbW9ja19tb2R1bGVzKCk6IFBsdWdpbiB7XG5cdGNvbnN0IHZfaWRfMSA9IFwiQGdyYWRpby10ZXN0L3Rlc3Qtb25lXCI7XG5cdGNvbnN0IHZfaWRfMiA9IFwiQGdyYWRpby10ZXN0L3Rlc3QtdHdvXCI7XG5cdGNvbnN0IHZfaWRfMV9leGFtcGxlID0gXCJAZ3JhZGlvLXRlc3QvdGVzdC1vbmUvZXhhbXBsZVwiO1xuXHRjb25zdCB2X2lkXzJfZXhhbXBsZSA9IFwiQGdyYWRpby10ZXN0L3Rlc3QtdHdvL2V4YW1wbGVcIjtcblx0Y29uc3QgcmVzb2x2ZWRfdl9pZCA9IFwiXFwwXCIgKyB2X2lkXzE7XG5cdGNvbnN0IHJlc29sdmVkX3ZfaWRfMiA9IFwiXFwwXCIgKyB2X2lkXzI7XG5cdGNvbnN0IHJlc29sdmVkX3ZfaWRfMV9leGFtcGxlID0gXCJcXDBcIiArIHZfaWRfMV9leGFtcGxlO1xuXHRjb25zdCByZXNvbHZlZF92X2lkXzJfZXhhbXBsZSA9IFwiXFwwXCIgKyB2X2lkXzJfZXhhbXBsZTtcblx0Y29uc3QgZmFsbGJhY2tfZXhhbXBsZSA9IFwiQGdyYWRpby9mYWxsYmFjay9leGFtcGxlXCI7XG5cdGNvbnN0IHJlc29sdmVkX2ZhbGxiYWNrX2V4YW1wbGUgPSBcIlxcMFwiICsgZmFsbGJhY2tfZXhhbXBsZTtcblxuXHRyZXR1cm4ge1xuXHRcdG5hbWU6IFwibW9jay1tb2R1bGVzXCIsXG5cdFx0ZW5mb3JjZTogXCJwcmVcIixcblx0XHRyZXNvbHZlSWQoaWQ6IHN0cmluZykge1xuXHRcdFx0aWYgKGlkID09PSB2X2lkXzEpIHJldHVybiByZXNvbHZlZF92X2lkO1xuXHRcdFx0aWYgKGlkID09PSB2X2lkXzIpIHJldHVybiByZXNvbHZlZF92X2lkXzI7XG5cdFx0XHRpZiAoaWQgPT09IHZfaWRfMV9leGFtcGxlKSByZXR1cm4gcmVzb2x2ZWRfdl9pZF8xX2V4YW1wbGU7XG5cdFx0XHRpZiAoaWQgPT09IHZfaWRfMl9leGFtcGxlKSByZXR1cm4gcmVzb2x2ZWRfdl9pZF8yX2V4YW1wbGU7XG5cdFx0XHRpZiAoaWQgPT09IGZhbGxiYWNrX2V4YW1wbGUpIHJldHVybiByZXNvbHZlZF9mYWxsYmFja19leGFtcGxlO1xuXHRcdH0sXG5cdFx0bG9hZChpZDogc3RyaW5nKSB7XG5cdFx0XHRpZiAoXG5cdFx0XHRcdGlkID09PSByZXNvbHZlZF92X2lkIHx8XG5cdFx0XHRcdGlkID09PSByZXNvbHZlZF92X2lkXzIgfHxcblx0XHRcdFx0aWQgPT09IHJlc29sdmVkX3ZfaWRfMV9leGFtcGxlIHx8XG5cdFx0XHRcdGlkID09PSByZXNvbHZlZF92X2lkXzJfZXhhbXBsZSB8fFxuXHRcdFx0XHRpZCA9PT0gcmVzb2x2ZWRfZmFsbGJhY2tfZXhhbXBsZVxuXHRcdFx0KSB7XG5cdFx0XHRcdHJldHVybiBgZXhwb3J0IGRlZmF1bHQge31gO1xuXHRcdFx0fVxuXHRcdH1cblx0fTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBd1UsU0FBUyxpQkFBaUI7QUFDbFcsU0FBUyxvQkFBb0I7OztBQ0E3QixTQUFTLGFBQTBCO0FBRW5D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 diff --git a/js/app/.gitignore b/js/app/.gitignore index 6f8fe001ac..79518f7164 100644 --- a/js/app/.gitignore +++ b/js/app/.gitignore @@ -1 +1,21 @@ -/src/lite/theme.css +node_modules + +# Output +.output +.vercel +/.svelte-kit +/build + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.* +!.env.example +!.env.test + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/js/app/README.md b/js/app/README.md new file mode 100644 index 0000000000..5ce676612e --- /dev/null +++ b/js/app/README.md @@ -0,0 +1,38 @@ +# create-svelte + +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm create svelte@latest + +# create a new project in my-app +npm create svelte@latest my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/js/app/package.json b/js/app/package.json index ec43488f55..a793983d4f 100644 --- a/js/app/package.json +++ b/js/app/package.json @@ -1,96 +1,26 @@ { - "name": "@gradio/app", - "version": "1.39.2", + "name": "app", + "version": "0.0.1", "private": true, - "type": "module", "scripts": { - "dev": "vite --port 9876", - "dev:lite": "run-p dev:lite:*", - "dev:lite:self": "vite --port 9876 --mode development:lite", - "dev:lite:worker": "pnpm --filter @gradio/wasm dev", - "build": "vite build --mode production --emptyOutDir", - "cssbuild": "python ../../scripts/generate_theme.py --outfile ./src/lite/theme.css", - "pybuild:gradio": "cd ../../ && hatch build -t lite", - "pybuild:gradio-client": "cd ../../client/python && python -m build", - "pybuild": "run-p pybuild:*", - "build:lite": "pnpm pybuild && pnpm cssbuild && pnpm --filter @gradio/client build && pnpm --filter @gradio/wasm build && vite build --mode production:lite", + "dev": "vite dev", + "build": "vite build", "preview": "vite preview", - "test:snapshot": "pnpm exec playwright test snapshots/ --config=../../.config/playwright.config.js", - "test:browser": "pnpm exec playwright test test/ --grep-invert 'reload.spec.ts' --config=../../.config/playwright.config.js", - "test:browser:dev": "pnpm exec playwright test test/ --ui --config=../../.config/playwright.config.js", - "test:browser:reload": "CI=1 pnpm exec playwright test test/ --grep 'reload.spec.ts' --config=../../.config/playwright.config.js", - "test:browser:lite": "GRADIO_E2E_TEST_LITE=1 pnpm test:browser", - "test:browser:lite:dev": "GRADIO_E2E_TEST_LITE=1 pnpm test:browser:dev", - "build:css": "pollen -c pollen.config.cjs -o src/pollen-dev.css" + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check .", + "format": "prettier --write ." }, - "dependencies": { - "@gradio/accordion": "workspace:^", - "@gradio/annotatedimage": "workspace:^", - "@gradio/atoms": "workspace:^", - "@gradio/audio": "workspace:^", - "@gradio/box": "workspace:^", - "@gradio/button": "workspace:^", - "@gradio/chatbot": "workspace:^", - "@gradio/checkbox": "workspace:^", - "@gradio/checkboxgroup": "workspace:^", - "@gradio/client": "workspace:^", - "@gradio/code": "workspace:^", - "@gradio/colorpicker": "workspace:^", - "@gradio/column": "workspace:^", - "@gradio/dataframe": "workspace:^", - "@gradio/dataset": "workspace:^", - "@gradio/datetime": "workspace:^", - "@gradio/downloadbutton": "workspace:^", - "@gradio/dropdown": "workspace:^", - "@gradio/fallback": "workspace:^", - "@gradio/file": "workspace:^", - "@gradio/fileexplorer": "workspace:^", - "@gradio/form": "workspace:^", - "@gradio/gallery": "workspace:^", - "@gradio/group": "workspace:^", - "@gradio/highlightedtext": "workspace:^", - "@gradio/html": "workspace:^", - "@gradio/icons": "workspace:^", - "@gradio/image": "workspace:^", - "@gradio/imageeditor": "workspace:^", - "@gradio/json": "workspace:^", - "@gradio/label": "workspace:^", - "@gradio/markdown": "workspace:^", - "@gradio/model3d": "workspace:^", - "@gradio/multimodaltextbox": "workspace:^", - "@gradio/nativeplot": "workspace:^", - "@gradio/number": "workspace:^", - "@gradio/paramviewer": "workspace:^", - "@gradio/plot": "workspace:^", - "@gradio/radio": "workspace:^", - "@gradio/row": "workspace:^", - "@gradio/simpledropdown": "workspace:^", - "@gradio/simpleimage": "workspace:^", - "@gradio/simpletextbox": "workspace:^", - "@gradio/slider": "workspace:^", - "@gradio/state": "workspace:^", - "@gradio/statustracker": "workspace:^", - "@gradio/tabitem": "workspace:^", - "@gradio/tabs": "workspace:^", - "@gradio/textbox": "workspace:^", - "@gradio/theme": "workspace:^", - "@gradio/timer": "workspace:^", - "@gradio/upload": "workspace:^", - "@gradio/uploadbutton": "workspace:^", - "@gradio/utils": "workspace:^", - "@gradio/video": "workspace:^", - "@gradio/wasm": "workspace:^", - "@huggingface/space-header": "^1.0.3", - "@types/eventsource": "^1.1.15", - "cross-env": "^7.0.3", - "d3-dsv": "^3.0.1", - "eventsource": "^2.0.2", - "mime-types": "^2.1.34", - "postcss": "^8.4.21", - "postcss-prefix-selector": "^1.16.0" + "devDependencies": { + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "typescript": "^5.0.0", + "vite": "^5.0.3" }, - "msw": { - "workerDirectory": "public" - }, - "main_changeset": true + "type": "module" } diff --git a/js/app/src/app.d.ts b/js/app/src/app.d.ts new file mode 100644 index 0000000000..743f07b2e5 --- /dev/null +++ b/js/app/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/js/app/src/app.html b/js/app/src/app.html new file mode 100644 index 0000000000..77a5ff52c9 --- /dev/null +++ b/js/app/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/js/app/src/lib/index.ts b/js/app/src/lib/index.ts new file mode 100644 index 0000000000..856f2b6c38 --- /dev/null +++ b/js/app/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/js/app/src/routes/+page.svelte b/js/app/src/routes/+page.svelte new file mode 100644 index 0000000000..33d0736b34 --- /dev/null +++ b/js/app/src/routes/+page.svelte @@ -0,0 +1,4 @@ +

Welcome to SvelteKit

+

+ Visit kit.svelte.dev to read the documentation +

diff --git a/js/app/static/favicon.png b/js/app/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH { - if (tag === "beta") { - return `${v}b${tag_version}`; - } else if (tag === "alpha") { - return `${v}a${tag_version}`; - } else { - return version; - } - } - ); -} - -const python_version = convert_to_pypi_prerelease(version_raw); - -const client_version_path = resolve( - __dirname, - "../../client/python/gradio_client/package.json" -); -const client_version_raw = JSON.parse( - readFileSync(client_version_path, { - encoding: "utf-8" - }) -).version.trim(); - -const client_python_version = convert_to_pypi_prerelease(client_version_raw); - -import { - inject_ejs, - generate_cdn_entry, - generate_dev_entry, - handle_ce_css, - inject_component_loader, - resolve_svelte, - mock_modules -} from "./build_plugins"; - -const GRADIO_VERSION = version_raw || "asd_stub_asd"; -const CDN_BASE = "https://gradio.s3-us-west-2.amazonaws.com"; -const TEST_MODE = process.env.TEST_MODE || "happy-dom"; - -//@ts-ignore -export default defineConfig(({ mode }) => { - const targets = { - production: "../../gradio/templates/frontend", - "dev:custom": "../../gradio/templates/frontend" - }; - const production = mode === "production" || mode === "production:lite"; - const development = mode === "development" || mode === "development:lite"; - const is_lite = mode.endsWith(":lite"); - - return { - base: "./", - - server: { - port: 9876, - open: is_lite ? "/lite.html" : "/" - }, - - build: { - sourcemap: true, - target: "esnext", - minify: production, - outDir: is_lite ? resolve(__dirname, "../lite/dist") : targets[mode], - // To build Gradio-lite as a library, we can't use the library mode - // like `lib: is_lite && {}` - // because it inevitably enables inlining of all the static file assets, - // while we need to disable inlining for the wheel files to pass their URLs to `micropip.install()`. - // So we build it as an app and only use the bundled JS and CSS files as library assets, ignoring the HTML file. - // See also `lite.ts` about it. - rollupOptions: is_lite - ? { - input: "./lite.html", - output: { - // To use it as a library, we don't add the hash to the file name. - entryFileNames: "lite.js", - assetFileNames: (file) => { - if (file.name?.endsWith(".whl")) { - // Python wheel files must follow the naming rules to be installed, so adding a hash to the name is not allowed. - return `assets/[name].[ext]`; - } - if (file.name === "lite.css") { - // To use it as a library, we don't add the hash to the file name. - return `[name].[ext]`; - } else { - return `assets/[name]-[hash].[ext]`; - } - } - } - } - : { - external: ["./svelte/svelte.js"], - makeAbsoluteExternalsRelative: false - } - }, - - define: { - BUILD_MODE: production ? JSON.stringify("prod") : JSON.stringify("dev"), - BACKEND_URL: production - ? JSON.stringify("") - : JSON.stringify("http://localhost:7860/"), - GRADIO_VERSION: JSON.stringify(version) - }, - css: { - postcss: { - plugins: [ - prefixer({ - prefix: `.gradio-container-${version}`, - // @ts-ignore - transform(prefix, selector, prefixedSelector, fileName) { - if (selector.indexOf("gradio-container") > -1) { - return prefix; - } else if ( - selector.indexOf(":root") > -1 || - selector.indexOf("dark") > -1 || - selector.indexOf("body") > -1 || - fileName.indexOf(".svelte") > -1 - ) { - return selector; - } else if ( - // For the custom element . See theme/src/global.css for the details. - /^gradio-lite(\:[^\:]+)?/.test(selector) - ) { - return selector; - } - return prefixedSelector; - } - }), - custom_media() - ] - } - }, - plugins: [ - resolve_svelte(development && !is_lite), - - svelte({ - inspector: false, - compilerOptions: { - dev: true, - discloseVersion: false, - accessors: true - }, - hot: !process.env.VITEST && !production, - preprocess: sveltePreprocess({ - postcss: { - plugins: [ - global_data({ files: [theme_token_path] }), - custom_media() - ] - } - }) - }), - generate_dev_entry({ - enable: - !development && - !is_lite && // At the moment of https://github.com/gradio-app/gradio/pull/6398, I skipped to make Gradio-lite work custom component. Will do it, and remove this condition. - mode !== "test" - }), - inject_ejs(), - generate_cdn_entry({ version: GRADIO_VERSION, cdn_base: CDN_BASE }), - handle_ce_css(), - inject_component_loader({ mode }), - mode === "test" && mock_modules() - ], - optimizeDeps: { - exclude: ["@ffmpeg/ffmpeg", "@ffmpeg/util"] - }, - test: { - setupFiles: [resolve(__dirname, "../../.config/setup_vite_tests.ts")], - environment: TEST_MODE, - include: - TEST_MODE === "node" - ? ["**/*.node-test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"] - : ["**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], - exclude: ["**/node_modules/**", "**/gradio/gradio/**"], - globals: true, - onConsoleLog(log, type) { - if (log.includes("was created with unknown prop")) return false; - } - }, - - resolve: { - alias: { - // For the Wasm app to import the wheel file URLs. - "gradio.whl": resolve( - __dirname, - `../../dist-lite/gradio-${python_version}-py3-none-any.whl` - ), - "gradio_client.whl": resolve( - __dirname, - `../../client/python/dist/gradio_client-${client_python_version}-py3-none-any.whl` - ) - } - }, - assetsInclude: ["**/*.whl"] // To pass URLs of built wheel files to the Wasm worker. - }; +export default defineConfig({ + plugins: [sveltekit()] }); diff --git a/js/audio/audio.test.ts b/js/audio/audio.test.ts index 4b99ecb065..810e837ca7 100644 --- a/js/audio/audio.test.ts +++ b/js/audio/audio.test.ts @@ -1,8 +1,8 @@ -import { test, describe, assert, afterEach, vi } from "vitest"; +import { test, describe, assert, afterEach } from "vitest"; import { cleanup, render } from "@gradio/tootils"; import Audio from "./"; import type { LoadingStatus } from "@gradio/statustracker"; -import { setupi18n } from "../app/src/i18n"; +import { setupi18n } from "../core/src/i18n"; import ResizeObserver from "resize-observer-polyfill"; global.ResizeObserver = ResizeObserver; diff --git a/js/audio/interactive/InteractiveAudio.svelte b/js/audio/interactive/InteractiveAudio.svelte index 7876e67449..68c5344c41 100644 --- a/js/audio/interactive/InteractiveAudio.svelte +++ b/js/audio/interactive/InteractiveAudio.svelte @@ -7,7 +7,7 @@ import AudioPlayer from "../player/AudioPlayer.svelte"; import type { IBlobEvent, IMediaRecorder } from "extendable-media-recorder"; - import type { I18nFormatter } from "js/app/src/gradio_helper"; + import type { I18nFormatter } from "js/core/src/gradio_helper"; import AudioRecorder from "../recorder/AudioRecorder.svelte"; import StreamAudio from "../streaming/StreamAudio.svelte"; import { SelectSource } from "@gradio/atoms"; diff --git a/js/build/README.md b/js/build/README.md new file mode 100644 index 0000000000..9a8109d646 --- /dev/null +++ b/js/build/README.md @@ -0,0 +1,3 @@ +# `@gradio/build` + +Build utilities for the gradio frontend + lite. diff --git a/js/app/component_loader.js b/js/build/dist/component_loader.js similarity index 100% rename from js/app/component_loader.js rename to js/build/dist/component_loader.js diff --git a/js/build/dist/index.js b/js/build/dist/index.js new file mode 100644 index 0000000000..7dc3d60543 --- /dev/null +++ b/js/build/dist/index.js @@ -0,0 +1,316 @@ +// src/index.ts +import { parse } from "node-html-parser"; +import { join } from "path"; +import { writeFileSync } from "fs"; +import * as url from "url"; +import { readdirSync, existsSync, readFileSync, statSync } from "fs"; +function inject_ejs() { + return { + name: "inject-ejs", + enforce: "post", + transformIndexHtml: (html) => { + const replace_gradio_info_info_html = html.replace( + /%gradio_api_info%/, + `` + ); + return replace_gradio_info_info_html.replace( + /%gradio_config%/, + `` + ); + } + }; +} +function generate_cdn_entry({ + version, + cdn_base +}) { + return { + name: "generate-cdn-entry", + enforce: "post", + writeBundle(config, bundle) { + if (!config.dir || !bundle["index.html"] || bundle["index.html"].type !== "asset") + return; + const source = bundle["index.html"].source; + const tree = parse(source); + const script = Array.from( + tree.querySelectorAll("script[type=module]") + ).find((node) => node.attributes.src?.includes("assets")); + const output_location = join(config.dir, "gradio.js"); + writeFileSync(output_location, make_entry(script?.attributes.src || "")); + if (!script) return; + const transformed_html = bundle["index.html"].source.substring(0, script?.range[0]) + `` + bundle["index.html"].source.substring( + script?.range[1], + source.length + ); + const share_html_location = join(config.dir, "share.html"); + writeFileSync(share_html_location, transformed_html); + } + }; +} +var RE_SVELTE_IMPORT = /import\s+([\w*{},\s]+)\s+from\s+['"](svelte|svelte\/internal)['"]/g; +function generate_dev_entry({ enable }) { + return { + name: "generate-dev-entry", + transform(code, id) { + if (!enable) return; + const new_code = code.replace(RE_SVELTE_IMPORT, (str, $1, $2) => { + return `const ${$1.replace(/\* as /, "").replace(/ as /g, ": ")} = window.__gradio__svelte__internal;`; + }); + return { + code: new_code, + map: null + }; + } + }; +} +function make_entry(script) { + return `import("${script}"); +`; +} +function handle_ce_css() { + return { + enforce: "post", + name: "custom-element-css", + writeBundle(config, bundle) { + let file_to_insert = { + filename: "", + source: "" + }; + if (!config.dir || !bundle["index.html"] || bundle["index.html"].type !== "asset") + return; + for (const key in bundle) { + const chunk = bundle[key]; + if (chunk.type === "chunk") { + const _chunk = chunk; + const found = _chunk.code?.indexOf("ENTRY_CSS"); + if (found > -1) + file_to_insert = { + filename: join(config.dir, key), + source: _chunk.code + }; + } + } + const tree = parse(bundle["index.html"].source); + const { style, fonts } = Array.from( + tree.querySelectorAll("link[rel=stylesheet]") + ).reduce( + (acc, next) => { + if (/.*\/index(.*?)\.css/.test(next.attributes.href)) { + return { ...acc, style: next }; + } + return { ...acc, fonts: [...acc.fonts, next.attributes.href] }; + }, + { fonts: [], style: void 0 } + ); + writeFileSync( + file_to_insert.filename, + file_to_insert.source.replace("__ENTRY_CSS__", style.attributes.href).replace( + '"__FONTS_CSS__"', + `[${fonts.map((f) => `"${f}"`).join(",")}]` + ) + ); + const share_html_location = join(config.dir, "share.html"); + const share_html = readFileSync(share_html_location, "utf8"); + const share_tree = parse(share_html); + const node = Array.from( + share_tree.querySelectorAll("link[rel=stylesheet]") + ).find((node2) => /.*\/index(.*?)\.css/.test(node2.attributes.href)); + if (!node) return; + const transformed_html = share_html.substring(0, node.range[0]) + share_html.substring(node.range[1], share_html.length); + writeFileSync(share_html_location, transformed_html); + } + }; +} +var __filename = url.fileURLToPath(import.meta.url); +var __dirname = url.fileURLToPath(new URL(".", import.meta.url)); +function get_export_path(path, root, pkg_json) { + if (!pkg_json.exports) return void 0; + const _path = join(root, "..", `${pkg_json.exports[`${path}`]}`); + return existsSync(_path) ? _path : void 0; +} +var ignore_list = [ + "tootils", + "_cdn-test", + "_spaces-test", + "_website", + "app", + "atoms", + "fallback", + "icons", + "lite", + "preview", + "simpledropdown", + "simpleimage", + "simpletextbox", + "storybook", + "theme", + "timeseries", + "tooltip", + "upload", + "utils", + "wasm" +]; +function generate_component_imports() { + const exports = readdirSync(join(__dirname, "..", "..")).map((dir) => { + if (ignore_list.includes(dir)) return void 0; + if (!statSync(join(__dirname, "..", "..", dir)).isDirectory()) return void 0; + const package_json_path = join(__dirname, "..", "..", dir, "package.json"); + if (existsSync(package_json_path)) { + const package_json = JSON.parse( + readFileSync(package_json_path, "utf8") + ); + const component = get_export_path(".", package_json_path, package_json); + const example = get_export_path( + "./example", + package_json_path, + package_json + ); + const base = get_export_path("./base", package_json_path, package_json); + if (!component && !example) return void 0; + return { + name: package_json.name, + component, + example, + base + }; + } + return void 0; + }).filter((x) => x !== void 0); + const imports = exports.reduce((acc, _export) => { + if (!_export) return acc; + const example = _export.example ? `example: () => import("${_export.name}/example"), +` : ""; + const base = _export.base ? `base: () => import("${_export.name}/base"), +` : ""; + return `${acc}"${_export.name.replace("@gradio/", "")}": { + ${base} + ${example} + component: () => import("${_export.name}") + }, +`; + }, ""); + return imports; +} +function load_virtual_component_loader(mode) { + const loader_path = join(__dirname, "component_loader.js"); + let component_map = ""; + if (mode === "test") { + component_map = ` + const component_map = { + "test-component-one": { + component: () => import("@gradio-test/test-one"), + example: () => import("@gradio-test/test-one/example") + }, + "dataset": { + component: () => import("@gradio-test/test-two"), + example: () => import("@gradio-test/test-two/example") + }, + "image": { + component: () => import("@gradio/image"), + example: () => import("@gradio/image/example"), + base: () => import("@gradio/image/base") + }, + "audio": { + component: () => import("@gradio/audio"), + example: () => import("@gradio/audio/example"), + base: () => import("@gradio/audio/base") + }, + "video": { + component: () => import("@gradio/video"), + example: () => import("@gradio/video/example"), + base: () => import("@gradio/video/base") + }, + // "test-component-one": { + // component: () => import("@gradio-test/test-one"), + // example: () => import("@gradio-test/test-one/example") + // }, + }; + `; + } else { + component_map = ` + const component_map = { + ${generate_component_imports()} + }; + `; + } + return `${component_map} + +${readFileSync(loader_path, "utf8")}`; +} +function inject_component_loader({ mode }) { + const v_id = "virtual:component-loader"; + const resolved_v_id = "\0" + v_id; + return { + name: "inject-component-loader", + enforce: "pre", + resolveId(id) { + if (id === v_id) return resolved_v_id; + }, + load(id) { + this.addWatchFile(join(__dirname, "component_loader.js")); + if (id === resolved_v_id) { + return load_virtual_component_loader(mode); + } + } + }; +} +function resolve_svelte(enable) { + return { + enforce: "pre", + name: "resolve-svelte", + async resolveId(id) { + if (!enable) return; + if (id === "./svelte/svelte.js" || id === "svelte" || id === "svelte/internal") { + const mod = join( + __dirname, + "..", + "..", + "gradio", + "templates", + "frontend", + "assets", + "svelte", + "svelte.js" + ); + return { id: mod, external: "absolute" }; + } + } + }; +} +function mock_modules() { + const v_id_1 = "@gradio-test/test-one"; + const v_id_2 = "@gradio-test/test-two"; + const v_id_1_example = "@gradio-test/test-one/example"; + const v_id_2_example = "@gradio-test/test-two/example"; + const resolved_v_id = "\0" + v_id_1; + const resolved_v_id_2 = "\0" + v_id_2; + const resolved_v_id_1_example = "\0" + v_id_1_example; + const resolved_v_id_2_example = "\0" + v_id_2_example; + const fallback_example = "@gradio/fallback/example"; + const resolved_fallback_example = "\0" + fallback_example; + return { + name: "mock-modules", + enforce: "pre", + resolveId(id) { + if (id === v_id_1) return resolved_v_id; + if (id === v_id_2) return resolved_v_id_2; + if (id === v_id_1_example) return resolved_v_id_1_example; + if (id === v_id_2_example) return resolved_v_id_2_example; + if (id === fallback_example) return resolved_fallback_example; + }, + load(id) { + if (id === resolved_v_id || id === resolved_v_id_2 || id === resolved_v_id_1_example || id === resolved_v_id_2_example || id === resolved_fallback_example) { + return `export default {}`; + } + } + }; +} +export { + generate_cdn_entry, + generate_dev_entry, + handle_ce_css, + inject_component_loader, + inject_ejs, + mock_modules, + resolve_svelte +}; diff --git a/js/build/package.json b/js/build/package.json new file mode 100644 index 0000000000..a13c152291 --- /dev/null +++ b/js/build/package.json @@ -0,0 +1,19 @@ +{ + "name": "@gradio/build", + "version": "0.0.1", + "description": "Gradio UI packages", + "type": "module", + "main": "dist/index.js", + "private": "true", + "author": "", + "license": "ISC", + "scripts": { + "build": "esbuild src/index.ts --platform=node --format=esm --target=node18 --bundle --packages=external --outfile=dist/index.js" + }, + "dependencies": { + "@gradio/theme": "workspace:^", + "esbuild": "^0.21.0", + "svelte-i18n": "^3.6.0" + }, + "main_changeset": true +} diff --git a/js/build/src/component_loader.js b/js/build/src/component_loader.js new file mode 100644 index 0000000000..5b4362f8ac --- /dev/null +++ b/js/build/src/component_loader.js @@ -0,0 +1,81 @@ +// @ts-nocheck + +const request_map = {}; + +export function load_component({ api_url, name, id, variant }) { + const comps = window.__GRADIO__CC__; + + const _component_map = { + // eslint-disable-next-line no-undef + ...component_map, + ...(!comps ? {} : comps) + }; + + let _id = id || name; + + if (request_map[`${_id}-${variant}`]) { + return { component: request_map[`${_id}-${variant}`], name }; + } + try { + if (!_component_map?.[_id]?.[variant] && !_component_map?.[name]?.[variant]) + throw new Error(); + + request_map[`${_id}-${variant}`] = ( + _component_map?.[_id]?.[variant] || // for dev mode custom components + _component_map?.[name]?.[variant] + )(); + + return { + name, + component: request_map[`${_id}-${variant}`] + }; + } catch (e) { + if (!_id) throw new Error(`Component not found: ${name}`); + try { + request_map[`${_id}-${variant}`] = get_component_with_css( + api_url, + _id, + variant + ); + + return { + name, + component: request_map[`${_id}-${variant}`] + }; + } catch (e) { + if (variant === "example") { + request_map[`${_id}-${variant}`] = import("@gradio/fallback/example"); + + return { + name, + component: request_map[`${_id}-${variant}`] + }; + } + console.error(`failed to load: ${name}`); + console.error(e); + throw e; + } + } +} + +function load_css(url) { + return new Promise((resolve, reject) => { + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = url; + document.head.appendChild(link); + link.onload = () => resolve(); + link.onerror = () => reject(); + }); +} + +function get_component_with_css(api_url, id, variant) { + return Promise.all([ + load_css(`${api_url}/custom_component/${id}/${variant}/style.css`), + import( + /* @vite-ignore */ `${api_url}/custom_component/${id}/${variant}/index.js` + ) + ]).then(([_, module]) => { + return module; + }); +} diff --git a/js/app/build_plugins.ts b/js/build/src/index.ts similarity index 97% rename from js/app/build_plugins.ts rename to js/build/src/index.ts index e8b054a27b..2c5fd8891e 100644 --- a/js/app/build_plugins.ts +++ b/js/build/src/index.ts @@ -213,12 +213,12 @@ const ignore_list = [ "wasm" ]; function generate_component_imports(): string { - const exports = readdirSync(join(__dirname, "..")) + const exports = readdirSync(join(__dirname, "..", "..")) .map((dir) => { if (ignore_list.includes(dir)) return undefined; - if (!statSync(join(__dirname, "..", dir)).isDirectory()) return undefined; + if (!statSync(join(__dirname, "..","..", dir)).isDirectory()) return undefined; - const package_json_path = join(__dirname, "..", dir, "package.json"); + const package_json_path = join(__dirname, "..","..", dir, "package.json"); if (existsSync(package_json_path)) { const package_json = JSON.parse( readFileSync(package_json_path, "utf8") @@ -246,6 +246,7 @@ function generate_component_imports(): string { }) .filter((x) => x !== undefined); + const imports = exports.reduce((acc, _export) => { if (!_export) return acc; diff --git a/js/button/main.ts b/js/button/main.ts new file mode 100644 index 0000000000..c517399bd8 --- /dev/null +++ b/js/button/main.ts @@ -0,0 +1,2 @@ +export { default as default } from "./Index.svelte"; +export { default as BaseButton } from "./shared/Button.svelte"; diff --git a/js/chatbot/shared/ChatBot.svelte b/js/chatbot/shared/ChatBot.svelte index 7de0341828..a84a6caa48 100644 --- a/js/chatbot/shared/ChatBot.svelte +++ b/js/chatbot/shared/ChatBot.svelte @@ -20,7 +20,7 @@ import type { MessageRole } from "../types"; import { MarkdownCode as Markdown } from "@gradio/markdown"; import type { FileData, Client } from "@gradio/client"; - import type { I18nFormatter } from "js/app/src/gradio_helper"; + import type { I18nFormatter } from "js/core/src/gradio_helper"; import Pending from "./Pending.svelte"; import MessageBox from "./MessageBox.svelte"; @@ -29,7 +29,8 @@ import Component from "./Component.svelte"; import LikeButtons from "./ButtonPanel.svelte"; - import type { LoadedComponent } from "../../app/src/types"; + import type { LoadedComponent } from "../../core/src/types"; + import CopyAll from "./CopyAll.svelte"; export let _fetch: typeof fetch; diff --git a/js/checkboxgroup/checkboxgroup.test.ts b/js/checkboxgroup/checkboxgroup.test.ts index 1d7ce82bf9..98932629ce 100644 --- a/js/checkboxgroup/checkboxgroup.test.ts +++ b/js/checkboxgroup/checkboxgroup.test.ts @@ -1,7 +1,7 @@ import { test, describe, assert, afterEach, vi } from "vitest"; import { cleanup, render } from "@gradio/tootils"; import event from "@testing-library/user-event"; -import { setupi18n } from "../app/src/i18n"; +import { setupi18n } from "../core/src/i18n"; import CheckboxGroup from "./Index.svelte"; import type { LoadingStatus } from "@gradio/statustracker"; diff --git a/js/core/.gitignore b/js/core/.gitignore new file mode 100644 index 0000000000..6f8fe001ac --- /dev/null +++ b/js/core/.gitignore @@ -0,0 +1 @@ +/src/lite/theme.css diff --git a/js/core/blocks.ts b/js/core/blocks.ts new file mode 100644 index 0000000000..9e1db2fe86 --- /dev/null +++ b/js/core/blocks.ts @@ -0,0 +1 @@ +export { default as default } from "./src/Blocks.svelte"; diff --git a/js/core/index.ts b/js/core/index.ts new file mode 100644 index 0000000000..5f808cfb5d --- /dev/null +++ b/js/core/index.ts @@ -0,0 +1,4 @@ +export { default as Embed } from "./src/Embed.svelte"; +export { prefix_css, mount_css } from "./src/css"; +export * from "./src/i18n"; +export * from "./src/types"; diff --git a/js/core/login.ts b/js/core/login.ts new file mode 100644 index 0000000000..cfb757b1b7 --- /dev/null +++ b/js/core/login.ts @@ -0,0 +1 @@ +export { default as default } from "./src/Login.svelte"; diff --git a/js/core/package.json b/js/core/package.json new file mode 100644 index 0000000000..323f68b26b --- /dev/null +++ b/js/core/package.json @@ -0,0 +1,78 @@ +{ + "name": "@gradio/core", + "version": "0.0.1", + "type": "module", + "devDependencies": { + "@gradio/accordion": "workspace:^", + "@gradio/annotatedimage": "workspace:^", + "@gradio/atoms": "workspace:^", + "@gradio/audio": "workspace:^", + "@gradio/box": "workspace:^", + "@gradio/button": "workspace:^", + "@gradio/chatbot": "workspace:^", + "@gradio/checkbox": "workspace:^", + "@gradio/checkboxgroup": "workspace:^", + "@gradio/client": "workspace:^", + "@gradio/code": "workspace:^", + "@gradio/colorpicker": "workspace:^", + "@gradio/column": "workspace:^", + "@gradio/dataframe": "workspace:^", + "@gradio/dataset": "workspace:^", + "@gradio/datetime": "workspace:^", + "@gradio/downloadbutton": "workspace:^", + "@gradio/dropdown": "workspace:^", + "@gradio/fallback": "workspace:^", + "@gradio/file": "workspace:^", + "@gradio/fileexplorer": "workspace:^", + "@gradio/form": "workspace:^", + "@gradio/gallery": "workspace:^", + "@gradio/group": "workspace:^", + "@gradio/highlightedtext": "workspace:^", + "@gradio/html": "workspace:^", + "@gradio/icons": "workspace:^", + "@gradio/image": "workspace:^", + "@gradio/imageeditor": "workspace:^", + "@gradio/json": "workspace:^", + "@gradio/label": "workspace:^", + "@gradio/markdown": "workspace:^", + "@gradio/model3d": "workspace:^", + "@gradio/multimodaltextbox": "workspace:^", + "@gradio/nativeplot": "workspace:^", + "@gradio/number": "workspace:^", + "@gradio/paramviewer": "workspace:^", + "@gradio/plot": "workspace:^", + "@gradio/radio": "workspace:^", + "@gradio/row": "workspace:^", + "@gradio/simpledropdown": "workspace:^", + "@gradio/simpleimage": "workspace:^", + "@gradio/simpletextbox": "workspace:^", + "@gradio/slider": "workspace:^", + "@gradio/state": "workspace:^", + "@gradio/statustracker": "workspace:^", + "@gradio/tabitem": "workspace:^", + "@gradio/tabs": "workspace:^", + "@gradio/textbox": "workspace:^", + "@gradio/theme": "workspace:^", + "@gradio/timer": "workspace:^", + "@gradio/upload": "workspace:^", + "@gradio/uploadbutton": "workspace:^", + "@gradio/utils": "workspace:^", + "@gradio/video": "workspace:^", + "@gradio/wasm": "workspace:^" + }, + "msw": { + "workerDirectory": "public" + }, + "main_changeset": true, + "exports": { + "./blocks": { + "svelte": "./src/Blocks.svelte" + }, + "./login": { + "svelte": "./src/Login.svelte" + }, + "./package.json": "./package.json", + ".": "./index.ts" + }, + "main": "./index.ts" +} diff --git a/js/app/public/favicon.png b/js/core/public/favicon.png similarity index 100% rename from js/app/public/favicon.png rename to js/core/public/favicon.png diff --git a/js/app/public/static/img/Bunny.obj b/js/core/public/static/img/Bunny.obj similarity index 100% rename from js/app/public/static/img/Bunny.obj rename to js/core/public/static/img/Bunny.obj diff --git a/js/app/public/static/img/Duck.glb b/js/core/public/static/img/Duck.glb similarity index 100% rename from js/app/public/static/img/Duck.glb rename to js/core/public/static/img/Duck.glb diff --git a/js/app/public/static/img/api-logo.svg b/js/core/public/static/img/api-logo.svg similarity index 100% rename from js/app/public/static/img/api-logo.svg rename to js/core/public/static/img/api-logo.svg diff --git a/js/app/public/static/img/camera.svg b/js/core/public/static/img/camera.svg similarity index 100% rename from js/app/public/static/img/camera.svg rename to js/core/public/static/img/camera.svg diff --git a/js/app/public/static/img/clear.svg b/js/core/public/static/img/clear.svg similarity index 100% rename from js/app/public/static/img/clear.svg rename to js/core/public/static/img/clear.svg diff --git a/js/app/public/static/img/edit.svg b/js/core/public/static/img/edit.svg similarity index 100% rename from js/app/public/static/img/edit.svg rename to js/core/public/static/img/edit.svg diff --git a/js/app/public/static/img/javascript.svg b/js/core/public/static/img/javascript.svg similarity index 100% rename from js/app/public/static/img/javascript.svg rename to js/core/public/static/img/javascript.svg diff --git a/js/app/public/static/img/logo.svg b/js/core/public/static/img/logo.svg similarity index 100% rename from js/app/public/static/img/logo.svg rename to js/core/public/static/img/logo.svg diff --git a/js/app/public/static/img/logo_error.svg b/js/core/public/static/img/logo_error.svg similarity index 100% rename from js/app/public/static/img/logo_error.svg rename to js/core/public/static/img/logo_error.svg diff --git a/js/app/public/static/img/python.svg b/js/core/public/static/img/python.svg similarity index 100% rename from js/app/public/static/img/python.svg rename to js/core/public/static/img/python.svg diff --git a/js/app/public/static/img/undo-solid.svg b/js/core/public/static/img/undo-solid.svg similarity index 100% rename from js/app/public/static/img/undo-solid.svg rename to js/core/public/static/img/undo-solid.svg diff --git a/js/app/src/Blocks.svelte b/js/core/src/Blocks.svelte similarity index 100% rename from js/app/src/Blocks.svelte rename to js/core/src/Blocks.svelte diff --git a/js/app/src/Embed.svelte b/js/core/src/Embed.svelte similarity index 100% rename from js/app/src/Embed.svelte rename to js/core/src/Embed.svelte diff --git a/js/app/src/Login.stories.svelte b/js/core/src/Login.stories.svelte similarity index 100% rename from js/app/src/Login.stories.svelte rename to js/core/src/Login.stories.svelte diff --git a/js/app/src/Login.svelte b/js/core/src/Login.svelte similarity index 100% rename from js/app/src/Login.svelte rename to js/core/src/Login.svelte diff --git a/js/app/src/MountComponents.svelte b/js/core/src/MountComponents.svelte similarity index 100% rename from js/app/src/MountComponents.svelte rename to js/core/src/MountComponents.svelte diff --git a/js/app/src/Render.svelte b/js/core/src/Render.svelte similarity index 100% rename from js/app/src/Render.svelte rename to js/core/src/Render.svelte diff --git a/js/app/src/RenderComponent.svelte b/js/core/src/RenderComponent.svelte similarity index 100% rename from js/app/src/RenderComponent.svelte rename to js/core/src/RenderComponent.svelte diff --git a/js/app/src/api_docs/ApiBanner.svelte b/js/core/src/api_docs/ApiBanner.svelte similarity index 96% rename from js/app/src/api_docs/ApiBanner.svelte rename to js/core/src/api_docs/ApiBanner.svelte index bd2946fae0..f764434246 100644 --- a/js/app/src/api_docs/ApiBanner.svelte +++ b/js/core/src/api_docs/ApiBanner.svelte @@ -2,7 +2,7 @@ import { createEventDispatcher } from "svelte"; import api_logo from "./img/api-logo.svg"; import Clear from "./img/clear.svelte"; - import Button from "../../../button/shared/Button.svelte"; + import { BaseButton } from "@gradio/button"; export let root: string; export let api_count: number; @@ -19,7 +19,7 @@ - +

{api_count} API endpoint{#if api_count > 1}s{/if}
diff --git a/js/app/src/api_docs/ApiDocs.svelte b/js/core/src/api_docs/ApiDocs.svelte similarity index 100% rename from js/app/src/api_docs/ApiDocs.svelte rename to js/core/src/api_docs/ApiDocs.svelte diff --git a/js/app/src/api_docs/ApiRecorder.svelte b/js/core/src/api_docs/ApiRecorder.svelte similarity index 100% rename from js/app/src/api_docs/ApiRecorder.svelte rename to js/core/src/api_docs/ApiRecorder.svelte diff --git a/js/app/src/api_docs/CodeSnippet.svelte b/js/core/src/api_docs/CodeSnippet.svelte similarity index 95% rename from js/app/src/api_docs/CodeSnippet.svelte rename to js/core/src/api_docs/CodeSnippet.svelte index 4069f48080..6b05a8a309 100644 --- a/js/app/src/api_docs/CodeSnippet.svelte +++ b/js/core/src/api_docs/CodeSnippet.svelte @@ -54,7 +54,8 @@ class="highlight">import Client{#if has_file_path}, handle_file{/if} -client = Client("{space_id || root}"{#if username !== null}, auth=("{username}", **password**){/if}) +client = Client("{space_id || root}"{#if username !== null}, auth=("{username}", **password**){/if}) result = client.predict({#each endpoint_parameters as { python_type, example_input, parameter_name, parameter_has_default, parameter_default }, i}{:else}{represent_value(example_input, python_type.type, "bash")}{#if i < endpoint_parameters.length - 1}, + {represent_value( + example_input, + python_type.type, + "bash" + )}{#if i < endpoint_parameters.length - 1}, {/if} {/each} ]{"}"}' \ diff --git a/js/app/src/api_docs/CopyButton.svelte b/js/core/src/api_docs/CopyButton.svelte similarity index 100% rename from js/app/src/api_docs/CopyButton.svelte rename to js/core/src/api_docs/CopyButton.svelte diff --git a/js/app/src/api_docs/EndpointDetail.svelte b/js/core/src/api_docs/EndpointDetail.svelte similarity index 100% rename from js/app/src/api_docs/EndpointDetail.svelte rename to js/core/src/api_docs/EndpointDetail.svelte diff --git a/js/app/src/api_docs/InputPayload.svelte b/js/core/src/api_docs/InputPayload.svelte similarity index 100% rename from js/app/src/api_docs/InputPayload.svelte rename to js/core/src/api_docs/InputPayload.svelte diff --git a/js/app/src/api_docs/InstallSnippet.svelte b/js/core/src/api_docs/InstallSnippet.svelte similarity index 100% rename from js/app/src/api_docs/InstallSnippet.svelte rename to js/core/src/api_docs/InstallSnippet.svelte diff --git a/js/app/src/api_docs/NoApi.svelte b/js/core/src/api_docs/NoApi.svelte similarity index 100% rename from js/app/src/api_docs/NoApi.svelte rename to js/core/src/api_docs/NoApi.svelte diff --git a/js/app/src/api_docs/ParametersSnippet.svelte b/js/core/src/api_docs/ParametersSnippet.svelte similarity index 100% rename from js/app/src/api_docs/ParametersSnippet.svelte rename to js/core/src/api_docs/ParametersSnippet.svelte diff --git a/js/app/src/api_docs/RecordingSnippet.svelte b/js/core/src/api_docs/RecordingSnippet.svelte similarity index 96% rename from js/app/src/api_docs/RecordingSnippet.svelte rename to js/core/src/api_docs/RecordingSnippet.svelte index 6f85e8444e..ce05d948db 100644 --- a/js/app/src/api_docs/RecordingSnippet.svelte +++ b/js/core/src/api_docs/RecordingSnippet.svelte @@ -134,7 +134,8 @@ class="highlight">import Client, file -client = Client("{short_root}"{#if username !== null}, auth=("{username}", **password**){/if}) +client = Client("{short_root}"{#if username !== null}, auth=("{username}", **password**){/if}) {#each py_zipped as { call, api_name }} client."{short_root}"{#if username !== null}, {auth: ["{username}", **password**]}{/if}); {#each js_zipped as { call, api_name }} -await client.predict( +await client.predict( "/{api_name}"{#if call}, {/if}{call}); + >{#if call}, + {/if}{call}); {/each} diff --git a/js/app/src/api_docs/ResponseSnippet.svelte b/js/core/src/api_docs/ResponseSnippet.svelte similarity index 100% rename from js/app/src/api_docs/ResponseSnippet.svelte rename to js/core/src/api_docs/ResponseSnippet.svelte diff --git a/js/app/src/api_docs/TryButton.svelte b/js/core/src/api_docs/TryButton.svelte similarity index 100% rename from js/app/src/api_docs/TryButton.svelte rename to js/core/src/api_docs/TryButton.svelte diff --git a/js/app/src/api_docs/img/api-logo.svg b/js/core/src/api_docs/img/api-logo.svg similarity index 100% rename from js/app/src/api_docs/img/api-logo.svg rename to js/core/src/api_docs/img/api-logo.svg diff --git a/js/app/src/api_docs/img/bash.svg b/js/core/src/api_docs/img/bash.svg similarity index 100% rename from js/app/src/api_docs/img/bash.svg rename to js/core/src/api_docs/img/bash.svg diff --git a/js/app/src/api_docs/img/clear.svelte b/js/core/src/api_docs/img/clear.svelte similarity index 100% rename from js/app/src/api_docs/img/clear.svelte rename to js/core/src/api_docs/img/clear.svelte diff --git a/js/app/src/api_docs/img/javascript.svg b/js/core/src/api_docs/img/javascript.svg similarity index 100% rename from js/app/src/api_docs/img/javascript.svg rename to js/core/src/api_docs/img/javascript.svg diff --git a/js/app/src/api_docs/img/python.svg b/js/core/src/api_docs/img/python.svg similarity index 100% rename from js/app/src/api_docs/img/python.svg rename to js/core/src/api_docs/img/python.svg diff --git a/js/app/src/api_docs/index.ts b/js/core/src/api_docs/index.ts similarity index 100% rename from js/app/src/api_docs/index.ts rename to js/core/src/api_docs/index.ts diff --git a/js/app/src/api_docs/utils.ts b/js/core/src/api_docs/utils.ts similarity index 100% rename from js/app/src/api_docs/utils.ts rename to js/core/src/api_docs/utils.ts diff --git a/js/app/src/css.ts b/js/core/src/css.ts similarity index 100% rename from js/app/src/css.ts rename to js/core/src/css.ts diff --git a/js/app/src/gradio_helper.ts b/js/core/src/gradio_helper.ts similarity index 100% rename from js/app/src/gradio_helper.ts rename to js/core/src/gradio_helper.ts diff --git a/js/app/src/i18n.test.ts b/js/core/src/i18n.test.ts similarity index 100% rename from js/app/src/i18n.test.ts rename to js/core/src/i18n.test.ts diff --git a/js/app/src/i18n.ts b/js/core/src/i18n.ts similarity index 100% rename from js/app/src/i18n.ts rename to js/core/src/i18n.ts diff --git a/js/app/src/images/lightning.svg b/js/core/src/images/lightning.svg similarity index 100% rename from js/app/src/images/lightning.svg rename to js/core/src/images/lightning.svg diff --git a/js/app/src/images/logo.svg b/js/core/src/images/logo.svg similarity index 100% rename from js/app/src/images/logo.svg rename to js/core/src/images/logo.svg diff --git a/js/app/src/images/play.svg b/js/core/src/images/play.svg similarity index 100% rename from js/app/src/images/play.svg rename to js/core/src/images/play.svg diff --git a/js/app/src/images/spaces.svg b/js/core/src/images/spaces.svg similarity index 100% rename from js/app/src/images/spaces.svg rename to js/core/src/images/spaces.svg diff --git a/js/app/src/init.test.ts b/js/core/src/init.test.ts similarity index 100% rename from js/app/src/init.test.ts rename to js/core/src/init.test.ts diff --git a/js/app/src/init.ts b/js/core/src/init.ts similarity index 100% rename from js/app/src/init.ts rename to js/core/src/init.ts diff --git a/js/app/src/lang/BCP47_codes.js b/js/core/src/lang/BCP47_codes.js similarity index 100% rename from js/app/src/lang/BCP47_codes.js rename to js/core/src/lang/BCP47_codes.js diff --git a/js/app/src/lang/README.md b/js/core/src/lang/README.md similarity index 85% rename from js/app/src/lang/README.md rename to js/core/src/lang/README.md index db53473385..024b60f9f4 100644 --- a/js/app/src/lang/README.md +++ b/js/core/src/lang/README.md @@ -6,6 +6,6 @@ To add your language, do the following steps: 1. Create a new json file in this directory 2. Name the file after the language code (Here's a list: http://4umi.com/web/html/languagecodes.php) -3. Please provide clear and complete translations. Take a look at the [`en.json`](https://github.com/gradio-app/gradio/blob/master/js/app/public/lang/en.json) file for the corresponding English text. +3. Please provide clear and complete translations. Take a look at the [`en.json`](https://github.com/gradio-app/gradio/blob/master/js/core/public/lang/en.json) file for the corresponding English text. That's it! diff --git a/js/app/src/lang/ar.json b/js/core/src/lang/ar.json similarity index 100% rename from js/app/src/lang/ar.json rename to js/core/src/lang/ar.json diff --git a/js/app/src/lang/ca.json b/js/core/src/lang/ca.json similarity index 100% rename from js/app/src/lang/ca.json rename to js/core/src/lang/ca.json diff --git a/js/app/src/lang/ckb.json b/js/core/src/lang/ckb.json similarity index 100% rename from js/app/src/lang/ckb.json rename to js/core/src/lang/ckb.json diff --git a/js/app/src/lang/de.json b/js/core/src/lang/de.json similarity index 100% rename from js/app/src/lang/de.json rename to js/core/src/lang/de.json diff --git a/js/app/src/lang/en.json b/js/core/src/lang/en.json similarity index 100% rename from js/app/src/lang/en.json rename to js/core/src/lang/en.json diff --git a/js/app/src/lang/es.json b/js/core/src/lang/es.json similarity index 100% rename from js/app/src/lang/es.json rename to js/core/src/lang/es.json diff --git a/js/app/src/lang/eu.json b/js/core/src/lang/eu.json similarity index 100% rename from js/app/src/lang/eu.json rename to js/core/src/lang/eu.json diff --git a/js/app/src/lang/fa.json b/js/core/src/lang/fa.json similarity index 100% rename from js/app/src/lang/fa.json rename to js/core/src/lang/fa.json diff --git a/js/app/src/lang/fr.json b/js/core/src/lang/fr.json similarity index 100% rename from js/app/src/lang/fr.json rename to js/core/src/lang/fr.json diff --git a/js/app/src/lang/he.json b/js/core/src/lang/he.json similarity index 100% rename from js/app/src/lang/he.json rename to js/core/src/lang/he.json diff --git a/js/app/src/lang/hi.json b/js/core/src/lang/hi.json similarity index 100% rename from js/app/src/lang/hi.json rename to js/core/src/lang/hi.json diff --git a/js/app/src/lang/ja.json b/js/core/src/lang/ja.json similarity index 100% rename from js/app/src/lang/ja.json rename to js/core/src/lang/ja.json diff --git a/js/app/src/lang/ko.json b/js/core/src/lang/ko.json similarity index 100% rename from js/app/src/lang/ko.json rename to js/core/src/lang/ko.json diff --git a/js/app/src/lang/lt.json b/js/core/src/lang/lt.json similarity index 100% rename from js/app/src/lang/lt.json rename to js/core/src/lang/lt.json diff --git a/js/app/src/lang/nl.json b/js/core/src/lang/nl.json similarity index 100% rename from js/app/src/lang/nl.json rename to js/core/src/lang/nl.json diff --git a/js/app/src/lang/pl.json b/js/core/src/lang/pl.json similarity index 100% rename from js/app/src/lang/pl.json rename to js/core/src/lang/pl.json diff --git a/js/app/src/lang/pt-BR.json b/js/core/src/lang/pt-BR.json similarity index 100% rename from js/app/src/lang/pt-BR.json rename to js/core/src/lang/pt-BR.json diff --git a/js/app/src/lang/ru.json b/js/core/src/lang/ru.json similarity index 100% rename from js/app/src/lang/ru.json rename to js/core/src/lang/ru.json diff --git a/js/app/src/lang/ta.json b/js/core/src/lang/ta.json similarity index 100% rename from js/app/src/lang/ta.json rename to js/core/src/lang/ta.json diff --git a/js/app/src/lang/tr.json b/js/core/src/lang/tr.json similarity index 100% rename from js/app/src/lang/tr.json rename to js/core/src/lang/tr.json diff --git a/js/app/src/lang/uk.json b/js/core/src/lang/uk.json similarity index 100% rename from js/app/src/lang/uk.json rename to js/core/src/lang/uk.json diff --git a/js/app/src/lang/ur.json b/js/core/src/lang/ur.json similarity index 100% rename from js/app/src/lang/ur.json rename to js/core/src/lang/ur.json diff --git a/js/app/src/lang/uz.json b/js/core/src/lang/uz.json similarity index 100% rename from js/app/src/lang/uz.json rename to js/core/src/lang/uz.json diff --git a/js/app/src/lang/zh-CN.json b/js/core/src/lang/zh-CN.json similarity index 100% rename from js/app/src/lang/zh-CN.json rename to js/core/src/lang/zh-CN.json diff --git a/js/app/src/lang/zh-TW.json b/js/core/src/lang/zh-TW.json similarity index 100% rename from js/app/src/lang/zh-TW.json rename to js/core/src/lang/zh-TW.json diff --git a/js/core/src/s-blocks.ts b/js/core/src/s-blocks.ts new file mode 100644 index 0000000000..18a7039466 --- /dev/null +++ b/js/core/src/s-blocks.ts @@ -0,0 +1 @@ +export { default as default } from "./Blocks.svelte"; diff --git a/js/core/src/s-login.ts b/js/core/src/s-login.ts new file mode 100644 index 0000000000..623e994172 --- /dev/null +++ b/js/core/src/s-login.ts @@ -0,0 +1 @@ +export { default as default } from "./Login.svelte"; diff --git a/js/app/src/stores.ts b/js/core/src/stores.ts similarity index 100% rename from js/app/src/stores.ts rename to js/core/src/stores.ts diff --git a/js/app/src/types.ts b/js/core/src/types.ts similarity index 100% rename from js/app/src/types.ts rename to js/core/src/types.ts diff --git a/js/app/src/vite-env-override.d.ts b/js/core/src/vite-env-override.d.ts similarity index 100% rename from js/app/src/vite-env-override.d.ts rename to js/core/src/vite-env-override.d.ts diff --git a/js/dataframe/Dataframe.stories.svelte b/js/dataframe/Dataframe.stories.svelte index 6085b78303..818a3094dc 100644 --- a/js/dataframe/Dataframe.stories.svelte +++ b/js/dataframe/Dataframe.stories.svelte @@ -1,6 +1,5 @@ diff --git a/js/dataframe/shared/Table.svelte b/js/dataframe/shared/Table.svelte index 8a6c4d4fba..368f4fcd02 100644 --- a/js/dataframe/shared/Table.svelte +++ b/js/dataframe/shared/Table.svelte @@ -7,7 +7,7 @@ import { BaseButton } from "@gradio/button"; import EditableCell from "./EditableCell.svelte"; import type { SelectData } from "@gradio/utils"; - import type { I18nFormatter } from "js/app/src/gradio_helper"; + import type { I18nFormatter } from "js/core/src/gradio_helper"; import { type Client } from "@gradio/client"; import VirtualTable from "./VirtualTable.svelte"; import type { diff --git a/js/dropdown/dropdown.test.ts b/js/dropdown/dropdown.test.ts index 0b16da38de..8262f2cfdf 100644 --- a/js/dropdown/dropdown.test.ts +++ b/js/dropdown/dropdown.test.ts @@ -1,7 +1,7 @@ import { test, describe, assert, afterEach, vi } from "vitest"; import { cleanup, render } from "@gradio/tootils"; import event from "@testing-library/user-event"; -import { setupi18n } from "../app/src/i18n"; +import { setupi18n } from "../core/src/i18n"; import Dropdown from "./Index.svelte"; import type { LoadingStatus } from "@gradio/statustracker"; diff --git a/js/gallery/Gallery.test.ts b/js/gallery/Gallery.test.ts index b6a731344c..e94eaf2d1c 100644 --- a/js/gallery/Gallery.test.ts +++ b/js/gallery/Gallery.test.ts @@ -1,6 +1,6 @@ import { test, describe, assert, afterEach, vi } from "vitest"; import { cleanup, render } from "@gradio/tootils"; -import { setupi18n } from "../app/src/i18n"; +import { setupi18n } from "../core/src/i18n"; import Gallery from "./Index.svelte"; import type { LoadingStatus } from "@gradio/statustracker"; diff --git a/js/highlightedtext/highlightedtext.test.ts b/js/highlightedtext/highlightedtext.test.ts index f6d8e195a2..56d4e08bbc 100644 --- a/js/highlightedtext/highlightedtext.test.ts +++ b/js/highlightedtext/highlightedtext.test.ts @@ -1,6 +1,6 @@ import { test, describe, assert, afterEach } from "vitest"; import { cleanup, fireEvent, render } from "@gradio/tootils"; -import { setupi18n } from "../app/src/i18n"; +import { setupi18n } from "../core/src/i18n"; import HighlightedText from "./Index.svelte"; import type { LoadingStatus } from "@gradio/statustracker"; diff --git a/js/image/Image.test.ts b/js/image/Image.test.ts index 26dd23c8c2..2920f5d172 100644 --- a/js/image/Image.test.ts +++ b/js/image/Image.test.ts @@ -7,9 +7,8 @@ import { beforeAll, beforeEach } from "vitest"; -import { spy } from "tinyspy"; import { cleanup, render } from "@gradio/tootils"; -import { setupi18n } from "../app/src/i18n"; +import { setupi18n } from "../core/src/i18n"; import Image from "./Index.svelte"; import type { LoadingStatus } from "@gradio/statustracker"; diff --git a/js/app/lite.html b/js/lite/lite.html similarity index 92% rename from js/app/lite.html rename to js/lite/lite.html index 00e812b6e5..843ed059ea 100644 --- a/js/app/lite.html +++ b/js/lite/lite.html @@ -15,7 +15,7 @@ crossorigin="anonymous" /> - + - import type { ThemeMode } from "../types"; + import type { ThemeMode } from "@gradio/core"; import type { WorkerProxy } from "@gradio/wasm"; import { createEventDispatcher, onMount } from "svelte"; import { Block } from "@gradio/atoms"; import { BaseCode as Code } from "@gradio/code"; - import lightning from "../images/lightning.svg"; + import lightning from "./images/lightning.svg"; export let is_embed: boolean; export let theme_mode: ThemeMode | null = "system"; diff --git a/js/app/src/lite/css.ts b/js/lite/src/css.ts similarity index 97% rename from js/app/src/lite/css.ts rename to js/lite/src/css.ts index f61ebb6198..a38d9f6379 100644 --- a/js/app/src/lite/css.ts +++ b/js/lite/src/css.ts @@ -1,6 +1,6 @@ import type { WorkerProxy } from "@gradio/wasm"; import { is_self_host } from "@gradio/wasm/network"; -import { mount_css as default_mount_css } from "../css"; +import { mount_css as default_mount_css } from "@gradio/core"; // In the Wasm mode, we use a prebuilt CSS file `/static/css/theme.css` to apply the styles in the initialization phase, // because it will take a long time for `theme.css` to be available after opening the app and loading the Pyodide and the server code. diff --git a/js/app/src/lite/custom-element/indent.ts b/js/lite/src/custom-element/indent.ts similarity index 100% rename from js/app/src/lite/custom-element/indent.ts rename to js/lite/src/custom-element/indent.ts diff --git a/js/app/src/lite/custom-element/index.test.ts b/js/lite/src/custom-element/index.test.ts similarity index 100% rename from js/app/src/lite/custom-element/index.test.ts rename to js/lite/src/custom-element/index.test.ts diff --git a/js/app/src/lite/custom-element/index.ts b/js/lite/src/custom-element/index.ts similarity index 99% rename from js/app/src/lite/custom-element/index.ts rename to js/lite/src/custom-element/index.ts index 4d0c5babec..276b7fa94e 100644 --- a/js/app/src/lite/custom-element/index.ts +++ b/js/lite/src/custom-element/index.ts @@ -58,7 +58,7 @@ export function bootstrap_custom_element( this.innerHTML = ""; this.controller = create({ - target: this, // Same as `js/app/src/main.ts` + target: this, // Same as `js/spa/src/main.ts` code: gradioLiteAppOptions.code, requirements: gradioLiteAppOptions.requirements, files: gradioLiteAppOptions.files, diff --git a/js/app/src/lite/dev/App.svelte b/js/lite/src/dev/App.svelte similarity index 100% rename from js/app/src/lite/dev/App.svelte rename to js/lite/src/dev/App.svelte diff --git a/js/app/src/lite/fetch.ts b/js/lite/src/fetch.ts similarity index 100% rename from js/app/src/lite/fetch.ts rename to js/lite/src/fetch.ts diff --git a/js/lite/src/images/lightning.svg b/js/lite/src/images/lightning.svg new file mode 100644 index 0000000000..5ba9407ef6 --- /dev/null +++ b/js/lite/src/images/lightning.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/js/lite/src/images/logo.svg b/js/lite/src/images/logo.svg new file mode 100644 index 0000000000..9bfb39e2a1 --- /dev/null +++ b/js/lite/src/images/logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/lite/src/images/play.svg b/js/lite/src/images/play.svg new file mode 100644 index 0000000000..0501c58425 --- /dev/null +++ b/js/lite/src/images/play.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/js/lite/src/images/spaces.svg b/js/lite/src/images/spaces.svg new file mode 100644 index 0000000000..c6eb2143cb --- /dev/null +++ b/js/lite/src/images/spaces.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/js/app/src/lite/index.ts b/js/lite/src/index.ts similarity index 98% rename from js/app/src/lite/index.ts rename to js/lite/src/index.ts index a556293194..4b039745fd 100644 --- a/js/app/src/lite/index.ts +++ b/js/lite/src/index.ts @@ -1,5 +1,5 @@ import { type WorkerProxyOptions } from "@gradio/wasm"; -import type { ThemeMode } from "../types"; +import type { ThemeMode } from "@gradio/core"; import { bootstrap_custom_element } from "./custom-element"; declare let GRADIO_VERSION: string; diff --git a/js/app/src/lite/sse.ts b/js/lite/src/sse.ts similarity index 100% rename from js/app/src/lite/sse.ts rename to js/lite/src/sse.ts diff --git a/js/lite/src/theme.css b/js/lite/src/theme.css new file mode 100644 index 0000000000..19e647060c --- /dev/null +++ b/js/lite/src/theme.css @@ -0,0 +1,424 @@ +:root { + --name: default; + --primary-50: #fff7ed; + --primary-100: #ffedd5; + --primary-200: #fed7aa; + --primary-300: #fdba74; + --primary-400: #fb923c; + --primary-500: #f97316; + --primary-600: #ea580c; + --primary-700: #c2410c; + --primary-800: #9a3412; + --primary-900: #7c2d12; + --primary-950: #6c2e12; + --secondary-50: #eff6ff; + --secondary-100: #dbeafe; + --secondary-200: #bfdbfe; + --secondary-300: #93c5fd; + --secondary-400: #60a5fa; + --secondary-500: #3b82f6; + --secondary-600: #2563eb; + --secondary-700: #1d4ed8; + --secondary-800: #1e40af; + --secondary-900: #1e3a8a; + --secondary-950: #1d3660; + --neutral-50: #f9fafb; + --neutral-100: #f3f4f6; + --neutral-200: #e5e7eb; + --neutral-300: #d1d5db; + --neutral-400: #9ca3af; + --neutral-500: #6b7280; + --neutral-600: #4b5563; + --neutral-700: #374151; + --neutral-800: #1f2937; + --neutral-900: #111827; + --neutral-950: #0b0f19; + --spacing-xxs: 1px; + --spacing-xs: 2px; + --spacing-sm: 4px; + --spacing-md: 6px; + --spacing-lg: 8px; + --spacing-xl: 10px; + --spacing-xxl: 16px; + --radius-xxs: 1px; + --radius-xs: 2px; + --radius-sm: 4px; + --radius-md: 6px; + --radius-lg: 8px; + --radius-xl: 12px; + --radius-xxl: 22px; + --text-xxs: 9px; + --text-xs: 10px; + --text-sm: 12px; + --text-md: 14px; + --text-lg: 16px; + --text-xl: 22px; + --text-xxl: 26px; + --font: 'Source Sans Pro', 'ui-sans-serif', 'system-ui', sans-serif; + --font-mono: 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace; + --body-background-fill: var(--background-fill-primary); + --body-text-color: var(--neutral-800); + --body-text-size: var(--text-md); + --body-text-weight: 400; + --embed-radius: var(--radius-lg); + --color-accent: var(--primary-500); + --color-accent-soft: var(--primary-50); + --background-fill-primary: white; + --background-fill-secondary: var(--neutral-50); + --border-color-accent: var(--primary-300); + --border-color-primary: var(--neutral-200); + --link-text-color: var(--secondary-600); + --link-text-color-active: var(--secondary-600); + --link-text-color-hover: var(--secondary-700); + --link-text-color-visited: var(--secondary-500); + --body-text-color-subdued: var(--neutral-400); + --accordion-text-color: var(--body-text-color); + --table-text-color: var(--body-text-color); + --shadow-drop: rgba(0,0,0,0.05) 0px 1px 2px 0px; + --shadow-drop-lg: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --shadow-inset: rgba(0,0,0,0.05) 0px 2px 4px 0px inset; + --shadow-spread: 3px; + --block-background-fill: var(--background-fill-primary); + --block-border-color: var(--border-color-primary); + --block-border-width: 1px; + --block-info-text-color: var(--body-text-color-subdued); + --block-info-text-size: var(--text-sm); + --block-info-text-weight: 400; + --block-label-background-fill: var(--background-fill-primary); + --block-label-border-color: var(--border-color-primary); + --block-label-border-width: 1px; + --block-label-shadow: var(--block-shadow); + --block-label-text-color: var(--neutral-500); + --block-label-margin: 0; + --block-label-padding: var(--spacing-sm) var(--spacing-lg); + --block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0; + --block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px); + --block-label-text-size: var(--text-sm); + --block-label-text-weight: 400; + --block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px); + --block-radius: var(--radius-lg); + --block-shadow: var(--shadow-drop); + --block-title-background-fill: none; + --block-title-border-color: none; + --block-title-border-width: 0px; + --block-title-text-color: var(--neutral-500); + --block-title-padding: 0; + --block-title-radius: none; + --block-title-text-size: var(--text-md); + --block-title-text-weight: 400; + --container-radius: var(--radius-lg); + --form-gap-width: 1px; + --layout-gap: var(--spacing-xxl); + --panel-background-fill: var(--background-fill-secondary); + --panel-border-color: var(--border-color-primary); + --panel-border-width: 0; + --section-header-text-size: var(--text-md); + --section-header-text-weight: 400; + --border-color-accent-subdued: var(--primary-200); + --code-background-fill: var(--neutral-100); + --checkbox-background-color: var(--background-fill-primary); + --checkbox-background-color-focus: var(--checkbox-background-color); + --checkbox-background-color-hover: var(--checkbox-background-color); + --checkbox-background-color-selected: var(--secondary-600); + --checkbox-border-color: var(--neutral-300); + --checkbox-border-color-focus: var(--secondary-500); + --checkbox-border-color-hover: var(--neutral-300); + --checkbox-border-color-selected: var(--secondary-600); + --checkbox-border-radius: var(--radius-sm); + --checkbox-border-width: var(--input-border-width); + --checkbox-label-background-fill: linear-gradient(to top, var(--neutral-50), white); + --checkbox-label-background-fill-hover: linear-gradient(to top, var(--neutral-100), white); + --checkbox-label-background-fill-selected: var(--checkbox-label-background-fill); + --checkbox-label-border-color: var(--border-color-primary); + --checkbox-label-border-color-hover: var(--checkbox-label-border-color); + --checkbox-label-border-width: var(--input-border-width); + --checkbox-label-gap: var(--spacing-lg); + --checkbox-label-padding: var(--spacing-md) calc(2 * var(--spacing-md)); + --checkbox-label-shadow: var(--shadow-drop); + --checkbox-label-text-size: var(--text-md); + --checkbox-label-text-weight: 400; + --checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); + --radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + --checkbox-shadow: var(--input-shadow); + --checkbox-label-text-color: var(--body-text-color); + --checkbox-label-text-color-selected: var(--checkbox-label-text-color); + --error-background-fill: #fef2f2; + --error-border-color: #b91c1c; + --error-border-width: 1px; + --error-text-color: #b91c1c; + --error-icon-color: #b91c1c; + --input-background-fill: white; + --input-background-fill-focus: var(--secondary-500); + --input-background-fill-hover: var(--input-background-fill); + --input-border-color: var(--border-color-primary); + --input-border-color-focus: var(--secondary-300); + --input-border-color-hover: var(--input-border-color); + --input-border-width: 1px; + --input-padding: var(--spacing-xl); + --input-placeholder-color: var(--neutral-400); + --input-radius: var(--radius-lg); + --input-shadow: 0 0 0 var(--shadow-spread) transparent, var(--shadow-inset); + --input-shadow-focus: 0 0 0 var(--shadow-spread) var(--secondary-50), var(--shadow-inset); + --input-text-size: var(--text-md); + --input-text-weight: 400; + --loader-color: var(--color-accent); + --prose-text-size: var(--text-md); + --prose-text-weight: 400; + --prose-header-text-weight: 600; + --slider-color: #2563eb; + --stat-background-fill: linear-gradient(to right, var(--primary-400), var(--primary-200)); + --table-border-color: var(--neutral-300); + --table-even-background-fill: white; + --table-odd-background-fill: var(--neutral-50); + --table-radius: var(--radius-lg); + --table-row-focus: var(--color-accent-soft); + --button-border-width: var(--input-border-width); + --button-cancel-background-fill: linear-gradient(to bottom right, #fee2e2, #fecaca); + --button-cancel-background-fill-hover: linear-gradient(to bottom right, #fee2e2, #fee2e2); + --button-cancel-border-color: #fecaca; + --button-cancel-border-color-hover: var(--button-cancel-border-color); + --button-cancel-text-color: #dc2626; + --button-cancel-text-color-hover: var(--button-cancel-text-color); + --button-large-padding: var(--spacing-lg) calc(2 * var(--spacing-lg)); + --button-large-radius: var(--radius-lg); + --button-large-text-size: var(--text-lg); + --button-large-text-weight: 600; + --button-primary-background-fill: linear-gradient(to bottom right, var(--primary-100), var(--primary-300)); + --button-primary-background-fill-hover: linear-gradient(to bottom right, var(--primary-100), var(--primary-200)); + --button-primary-border-color: var(--primary-200); + --button-primary-border-color-hover: var(--button-primary-border-color); + --button-primary-text-color: var(--primary-600); + --button-primary-text-color-hover: var(--button-primary-text-color); + --button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-100), var(--neutral-200)); + --button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-100), var(--neutral-100)); + --button-secondary-border-color: var(--neutral-200); + --button-secondary-border-color-hover: var(--button-secondary-border-color); + --button-secondary-text-color: var(--neutral-700); + --button-secondary-text-color-hover: var(--button-secondary-text-color); + --button-shadow: var(--shadow-drop); + --button-shadow-active: var(--shadow-inset); + --button-shadow-hover: var(--shadow-drop-lg); + --button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm)); + --button-small-radius: var(--radius-lg); + --button-small-text-size: var(--text-md); + --button-small-text-weight: 400; + --button-transition: none; +} +.dark { + --body-background-fill: var(--background-fill-primary); + --body-text-color: var(--neutral-100); + --color-accent-soft: var(--neutral-700); + --background-fill-primary: var(--neutral-950); + --background-fill-secondary: var(--neutral-900); + --border-color-accent: var(--neutral-600); + --border-color-primary: var(--neutral-700); + --link-text-color-active: var(--secondary-500); + --link-text-color: var(--secondary-500); + --link-text-color-hover: var(--secondary-400); + --link-text-color-visited: var(--secondary-600); + --body-text-color-subdued: var(--neutral-400); + --accordion-text-color: var(--body-text-color); + --table-text-color: var(--body-text-color); + --shadow-spread: 1px; + --block-background-fill: var(--neutral-800); + --block-border-color: var(--border-color-primary); + --block_border_width: None; + --block-info-text-color: var(--body-text-color-subdued); + --block-label-background-fill: var(--background-fill-secondary); + --block-label-border-color: var(--border-color-primary); + --block_label_border_width: None; + --block-label-text-color: var(--neutral-200); + --block_shadow: None; + --block_title_background_fill: None; + --block_title_border_color: None; + --block_title_border_width: None; + --block-title-text-color: var(--neutral-200); + --panel-background-fill: var(--background-fill-secondary); + --panel-border-color: var(--border-color-primary); + --panel_border_width: None; + --border-color-accent-subdued: var(--border-color-accent); + --code-background-fill: var(--neutral-800); + --checkbox-background-color: var(--neutral-800); + --checkbox-background-color-focus: var(--checkbox-background-color); + --checkbox-background-color-hover: var(--checkbox-background-color); + --checkbox-background-color-selected: var(--secondary-600); + --checkbox-border-color: var(--neutral-700); + --checkbox-border-color-focus: var(--secondary-500); + --checkbox-border-color-hover: var(--neutral-600); + --checkbox-border-color-selected: var(--secondary-600); + --checkbox-border-width: var(--input-border-width); + --checkbox-label-background-fill: linear-gradient(to top, var(--neutral-900), var(--neutral-800)); + --checkbox-label-background-fill-hover: linear-gradient(to top, var(--neutral-900), var(--neutral-800)); + --checkbox-label-background-fill-selected: var(--checkbox-label-background-fill); + --checkbox-label-border-color: var(--border-color-primary); + --checkbox-label-border-color-hover: var(--checkbox-label-border-color); + --checkbox-label-border-width: var(--input-border-width); + --checkbox-label-text-color: var(--body-text-color); + --checkbox-label-text-color-selected: var(--checkbox-label-text-color); + --error-background-fill: var(--neutral-900); + --error-border-color: #ef4444; + --error_border_width: None; + --error-text-color: #fef2f2; + --error-icon-color: #ef4444; + --input-background-fill: var(--neutral-800); + --input-background-fill-focus: var(--secondary-600); + --input-background-fill-hover: var(--input-background-fill); + --input-border-color: var(--border-color-primary); + --input-border-color-focus: var(--neutral-700); + --input-border-color-hover: var(--input-border-color); + --input_border_width: None; + --input-placeholder-color: var(--neutral-500); + --input_shadow: None; + --input-shadow-focus: 0 0 0 var(--shadow-spread) var(--neutral-700), var(--shadow-inset); + --loader_color: None; + --slider_color: None; + --stat-background-fill: linear-gradient(to right, var(--primary-400), var(--primary-600)); + --table-border-color: var(--neutral-700); + --table-even-background-fill: var(--neutral-950); + --table-odd-background-fill: var(--neutral-900); + --table-row-focus: var(--color-accent-soft); + --button-border-width: var(--input-border-width); + --button-cancel-background-fill: linear-gradient(to bottom right, #dc2626, #b91c1c); + --button-cancel-background-fill-hover: linear-gradient(to bottom right, #dc2626, #dc2626); + --button-cancel-border-color: #dc2626; + --button-cancel-border-color-hover: var(--button-cancel-border-color); + --button-cancel-text-color: white; + --button-cancel-text-color-hover: var(--button-cancel-text-color); + --button-primary-background-fill: linear-gradient(to bottom right, var(--primary-500), var(--primary-600)); + --button-primary-background-fill-hover: linear-gradient(to bottom right, var(--primary-500), var(--primary-500)); + --button-primary-border-color: var(--primary-500); + --button-primary-border-color-hover: var(--button-primary-border-color); + --button-primary-text-color: white; + --button-primary-text-color-hover: var(--button-primary-text-color); + --button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-600), var(--neutral-700)); + --button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-600), var(--neutral-600)); + --button-secondary-border-color: var(--neutral-600); + --button-secondary-border-color-hover: var(--button-secondary-border-color); + --button-secondary-text-color: white; + --button-secondary-text-color-hover: var(--button-secondary-text-color); + --name: default; + --primary-50: #fff7ed; + --primary-100: #ffedd5; + --primary-200: #fed7aa; + --primary-300: #fdba74; + --primary-400: #fb923c; + --primary-500: #f97316; + --primary-600: #ea580c; + --primary-700: #c2410c; + --primary-800: #9a3412; + --primary-900: #7c2d12; + --primary-950: #6c2e12; + --secondary-50: #eff6ff; + --secondary-100: #dbeafe; + --secondary-200: #bfdbfe; + --secondary-300: #93c5fd; + --secondary-400: #60a5fa; + --secondary-500: #3b82f6; + --secondary-600: #2563eb; + --secondary-700: #1d4ed8; + --secondary-800: #1e40af; + --secondary-900: #1e3a8a; + --secondary-950: #1d3660; + --neutral-50: #f9fafb; + --neutral-100: #f3f4f6; + --neutral-200: #e5e7eb; + --neutral-300: #d1d5db; + --neutral-400: #9ca3af; + --neutral-500: #6b7280; + --neutral-600: #4b5563; + --neutral-700: #374151; + --neutral-800: #1f2937; + --neutral-900: #111827; + --neutral-950: #0b0f19; + --spacing-xxs: 1px; + --spacing-xs: 2px; + --spacing-sm: 4px; + --spacing-md: 6px; + --spacing-lg: 8px; + --spacing-xl: 10px; + --spacing-xxl: 16px; + --radius-xxs: 1px; + --radius-xs: 2px; + --radius-sm: 4px; + --radius-md: 6px; + --radius-lg: 8px; + --radius-xl: 12px; + --radius-xxl: 22px; + --text-xxs: 9px; + --text-xs: 10px; + --text-sm: 12px; + --text-md: 14px; + --text-lg: 16px; + --text-xl: 22px; + --text-xxl: 26px; + --font: 'Source Sans Pro', 'ui-sans-serif', 'system-ui', sans-serif; + --font-mono: 'IBM Plex Mono', 'ui-monospace', 'Consolas', monospace; + --body-text-size: var(--text-md); + --body-text-weight: 400; + --embed-radius: var(--radius-lg); + --color-accent: var(--primary-500); + --shadow-drop: rgba(0,0,0,0.05) 0px 1px 2px 0px; + --shadow-drop-lg: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --shadow-inset: rgba(0,0,0,0.05) 0px 2px 4px 0px inset; + --block-border-width: 1px; + --block-info-text-size: var(--text-sm); + --block-info-text-weight: 400; + --block-label-border-width: 1px; + --block-label-shadow: var(--block-shadow); + --block-label-margin: 0; + --block-label-padding: var(--spacing-sm) var(--spacing-lg); + --block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0; + --block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px); + --block-label-text-size: var(--text-sm); + --block-label-text-weight: 400; + --block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px); + --block-radius: var(--radius-lg); + --block-shadow: var(--shadow-drop); + --block-title-background-fill: none; + --block-title-border-color: none; + --block-title-border-width: 0px; + --block-title-padding: 0; + --block-title-radius: none; + --block-title-text-size: var(--text-md); + --block-title-text-weight: 400; + --container-radius: var(--radius-lg); + --form-gap-width: 1px; + --layout-gap: var(--spacing-xxl); + --panel-border-width: 0; + --section-header-text-size: var(--text-md); + --section-header-text-weight: 400; + --checkbox-border-radius: var(--radius-sm); + --checkbox-label-gap: var(--spacing-lg); + --checkbox-label-padding: var(--spacing-md) calc(2 * var(--spacing-md)); + --checkbox-label-shadow: var(--shadow-drop); + --checkbox-label-text-size: var(--text-md); + --checkbox-label-text-weight: 400; + --checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); + --radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + --checkbox-shadow: var(--input-shadow); + --error-border-width: 1px; + --input-border-width: 1px; + --input-padding: var(--spacing-xl); + --input-radius: var(--radius-lg); + --input-shadow: 0 0 0 var(--shadow-spread) transparent, var(--shadow-inset); + --input-text-size: var(--text-md); + --input-text-weight: 400; + --loader-color: var(--color-accent); + --prose-text-size: var(--text-md); + --prose-text-weight: 400; + --prose-header-text-weight: 600; + --slider-color: #2563eb; + --table-radius: var(--radius-lg); + --button-large-padding: var(--spacing-lg) calc(2 * var(--spacing-lg)); + --button-large-radius: var(--radius-lg); + --button-large-text-size: var(--text-lg); + --button-large-text-weight: 600; + --button-shadow: var(--shadow-drop); + --button-shadow-active: var(--shadow-inset); + --button-shadow-hover: var(--shadow-drop-lg); + --button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm)); + --button-small-radius: var(--radius-lg); + --button-small-text-size: var(--text-md); + --button-small-text-weight: 400; + --button-transition: none; +} \ No newline at end of file diff --git a/js/lite/vite.config.ts b/js/lite/vite.config.ts new file mode 100644 index 0000000000..7ee9c2a3b2 --- /dev/null +++ b/js/lite/vite.config.ts @@ -0,0 +1,197 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import sveltePreprocess from "svelte-preprocess"; +// @ts-ignore +import custom_media from "postcss-custom-media"; +import global_data from "@csstools/postcss-global-data"; +// @ts-ignore +import prefixer from "postcss-prefix-selector"; +import { readFileSync } from "fs"; +import { resolve } from "path"; + +const version_path = resolve(__dirname, "../../gradio/package.json"); +const theme_token_path = resolve(__dirname, "../theme/src/tokens.css"); +const version_raw = JSON.parse( + readFileSync(version_path, { encoding: "utf-8" }) +).version.trim(); +const version = version_raw.replace(/\./g, "-"); + +function convert_to_pypi_prerelease(version: string) { + return version.replace( + /(\d+\.\d+\.\d+)-([-a-z]+)\.(\d+)/, + (match, v, tag, tag_version) => { + if (tag === "beta") { + return `${v}b${tag_version}`; + } else if (tag === "alpha") { + return `${v}a${tag_version}`; + } else { + return version; + } + } + ); +} + +const python_version = convert_to_pypi_prerelease(version_raw); + +const client_version_path = resolve( + __dirname, + "../../client/python/gradio_client/package.json" +); +const client_version_raw = JSON.parse( + readFileSync(client_version_path, { + encoding: "utf-8" + }) +).version.trim(); + +const client_python_version = convert_to_pypi_prerelease(client_version_raw); + +import { + inject_ejs, + generate_cdn_entry, + handle_ce_css, + inject_component_loader, + mock_modules +} from "@gradio/build"; + +const GRADIO_VERSION = version_raw || "asd_stub_asd"; +const CDN_BASE = "https://gradio.s3-us-west-2.amazonaws.com"; +const TEST_MODE = process.env.TEST_MODE || "happy-dom"; + +//@ts-ignore +export default defineConfig(({ mode }) => { + const production = mode === "production"; + + return { + base: "./", + + server: { + port: 9876, + open: "/lite.html" + }, + + build: { + sourcemap: true, + target: "esnext", + minify: production, + outDir: resolve(__dirname, "../lite/dist"), + // To build Gradio-lite as a library, we can't use the library mode + // like `lib: is_lite && {}` + // because it inevitably enables inlining of all the static file assets, + // while we need to disable inlining for the wheel files to pass their URLs to `micropip.install()`. + // So we build it as an app and only use the bundled JS and CSS files as library assets, ignoring the HTML file. + // See also `lite.ts` about it. + rollupOptions: { + input: "./lite.html", + output: { + // To use it as a library, we don't add the hash to the file name. + entryFileNames: "lite.js", + assetFileNames: (file) => { + if (file.name?.endsWith(".whl")) { + // Python wheel files must follow the naming rules to be installed, so adding a hash to the name is not allowed. + return `assets/[name].[ext]`; + } + if (file.name === "lite.css") { + // To use it as a library, we don't add the hash to the file name. + return `[name].[ext]`; + } else { + return `assets/[name]-[hash].[ext]`; + } + } + } + } + }, + + define: { + BUILD_MODE: production ? JSON.stringify("prod") : JSON.stringify("dev"), + BACKEND_URL: production + ? JSON.stringify("") + : JSON.stringify("http://localhost:7860/"), + GRADIO_VERSION: JSON.stringify(version) + }, + css: { + postcss: { + plugins: [ + prefixer({ + prefix: `.gradio-container-${version}`, + // @ts-ignore + transform(prefix, selector, prefixedSelector, fileName) { + if (selector.indexOf("gradio-container") > -1) { + return prefix; + } else if ( + selector.indexOf(":root") > -1 || + selector.indexOf("dark") > -1 || + selector.indexOf("body") > -1 || + fileName.indexOf(".svelte") > -1 + ) { + return selector; + } else if ( + // For the custom element . See theme/src/global.css for the details. + /^gradio-lite(\:[^\:]+)?/.test(selector) + ) { + return selector; + } + return prefixedSelector; + } + }), + custom_media() + ] + } + }, + plugins: [ + svelte({ + inspector: false, + compilerOptions: { + dev: true, + discloseVersion: false, + accessors: true + }, + hot: !process.env.VITEST && !production, + preprocess: sveltePreprocess({ + postcss: { + plugins: [ + global_data({ files: [theme_token_path] }), + custom_media() + ] + } + }) + }), + + inject_ejs(), + generate_cdn_entry({ version: GRADIO_VERSION, cdn_base: CDN_BASE }), + handle_ce_css(), + inject_component_loader({ mode }), + mode === "test" && mock_modules() + ], + optimizeDeps: { + exclude: ["@ffmpeg/ffmpeg", "@ffmpeg/util"] + }, + test: { + setupFiles: [resolve(__dirname, "../../.config/setup_vite_tests.ts")], + environment: TEST_MODE, + include: + TEST_MODE === "node" + ? ["**/*.node-test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"] + : ["**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], + exclude: ["**/node_modules/**", "**/gradio/gradio/**"], + globals: true, + onConsoleLog(log, type) { + if (log.includes("was created with unknown prop")) return false; + } + }, + + resolve: { + alias: { + // For the Wasm app to import the wheel file URLs. + "gradio.whl": resolve( + __dirname, + `../../dist-lite/gradio-${python_version}-py3-none-any.whl` + ), + "gradio_client.whl": resolve( + __dirname, + `../../client/python/dist/gradio_client-${client_python_version}-py3-none-any.whl` + ) + } + }, + assetsInclude: ["**/*.whl"] // To pass URLs of built wheel files to the Wasm worker. + }; +}); diff --git a/js/plot/shared/Plot.svelte b/js/plot/shared/Plot.svelte index 05450cfad7..c9befc3d8e 100644 --- a/js/plot/shared/Plot.svelte +++ b/js/plot/shared/Plot.svelte @@ -2,7 +2,7 @@ //@ts-nocheck import { Plot as PlotIcon } from "@gradio/icons"; import { Empty } from "@gradio/atoms"; - import type { ThemeMode } from "js/app/src/components/types"; + import type { ThemeMode } from "js/core/src/components/types"; import type { Gradio, SelectData } from "@gradio/utils"; export let value; diff --git a/js/spa/.gitignore b/js/spa/.gitignore new file mode 100644 index 0000000000..6f8fe001ac --- /dev/null +++ b/js/spa/.gitignore @@ -0,0 +1 @@ +/src/lite/theme.css diff --git a/js/spa/component_loader.js b/js/spa/component_loader.js new file mode 100644 index 0000000000..5b4362f8ac --- /dev/null +++ b/js/spa/component_loader.js @@ -0,0 +1,81 @@ +// @ts-nocheck + +const request_map = {}; + +export function load_component({ api_url, name, id, variant }) { + const comps = window.__GRADIO__CC__; + + const _component_map = { + // eslint-disable-next-line no-undef + ...component_map, + ...(!comps ? {} : comps) + }; + + let _id = id || name; + + if (request_map[`${_id}-${variant}`]) { + return { component: request_map[`${_id}-${variant}`], name }; + } + try { + if (!_component_map?.[_id]?.[variant] && !_component_map?.[name]?.[variant]) + throw new Error(); + + request_map[`${_id}-${variant}`] = ( + _component_map?.[_id]?.[variant] || // for dev mode custom components + _component_map?.[name]?.[variant] + )(); + + return { + name, + component: request_map[`${_id}-${variant}`] + }; + } catch (e) { + if (!_id) throw new Error(`Component not found: ${name}`); + try { + request_map[`${_id}-${variant}`] = get_component_with_css( + api_url, + _id, + variant + ); + + return { + name, + component: request_map[`${_id}-${variant}`] + }; + } catch (e) { + if (variant === "example") { + request_map[`${_id}-${variant}`] = import("@gradio/fallback/example"); + + return { + name, + component: request_map[`${_id}-${variant}`] + }; + } + console.error(`failed to load: ${name}`); + console.error(e); + throw e; + } + } +} + +function load_css(url) { + return new Promise((resolve, reject) => { + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = url; + document.head.appendChild(link); + link.onload = () => resolve(); + link.onerror = () => reject(); + }); +} + +function get_component_with_css(api_url, id, variant) { + return Promise.all([ + load_css(`${api_url}/custom_component/${id}/${variant}/style.css`), + import( + /* @vite-ignore */ `${api_url}/custom_component/${id}/${variant}/index.js` + ) + ]).then(([_, module]) => { + return module; + }); +} diff --git a/js/app/index.html b/js/spa/index.html similarity index 100% rename from js/app/index.html rename to js/spa/index.html diff --git a/js/spa/package.json b/js/spa/package.json new file mode 100644 index 0000000000..76e755d62e --- /dev/null +++ b/js/spa/package.json @@ -0,0 +1,41 @@ +{ + "name": "@gradio/spa", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port 9876", + "dev:lite": "run-p dev:lite:*", + "dev:lite:self": "vite --port 9876 --mode development:lite", + "dev:lite:worker": "pnpm --filter @gradio/wasm dev", + "build": "vite build --mode production --emptyOutDir", + "cssbuild": "python ../../scripts/generate_theme.py --outfile ./src/lite/theme.css", + "pybuild:gradio": "cd ../../ && hatch build -t lite", + "pybuild:gradio-client": "cd ../../client/python && python -m build", + "pybuild": "run-p pybuild:*", + "build:lite": "pnpm pybuild && pnpm cssbuild && pnpm --filter @gradio/client build && pnpm --filter @gradio/wasm build && vite build --mode production:lite", + "preview": "vite preview", + "test:snapshot": "pnpm exec playwright test snapshots/ --config=../../.config/playwright.config.js", + "test:browser": "pnpm exec playwright test test/ --grep-invert 'reload.spec.ts' --config=../../.config/playwright.config.js", + "test:browser:dev": "pnpm exec playwright test test/ --ui --config=../../.config/playwright.config.js", + "test:browser:reload": "CI=1 pnpm exec playwright test test/ --grep 'reload.spec.ts' --config=../../.config/playwright.config.js", + "test:browser:lite": "GRADIO_E2E_TEST_LITE=1 pnpm test:browser", + "test:browser:lite:dev": "GRADIO_E2E_TEST_LITE=1 pnpm test:browser:dev", + "build:css": "pollen -c pollen.config.cjs -o src/pollen-dev.css" + }, + "devDependencies": { + "@gradio/build": "workspace:^", + "@gradio/client": "workspace:^", + "@gradio/core": "workspace:^", + "@gradio/theme": "workspace:^", + "@gradio/wasm": "workspace:^", + "@huggingface/space-header": "^1.0.3", + "@types/eventsource": "^1.1.15", + "cross-env": "^7.0.3" + }, + "msw": { + "workerDirectory": "public" + }, + "main_changeset": true, + "main": "./src/Index.svelte" +} diff --git a/js/app/postcss.config.js b/js/spa/postcss.config.js similarity index 100% rename from js/app/postcss.config.js rename to js/spa/postcss.config.js diff --git a/js/spa/public/favicon.png b/js/spa/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e6f5eb5a2f1f1c882d265cf479de25caa925645 GIT binary patch literal 3127 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 RAbBlY?7Qf;2Rj+ye*ggh(RTm< literal 0 HcmV?d00001 diff --git a/js/spa/public/static/img/api-logo.svg b/js/spa/public/static/img/api-logo.svg new file mode 100644 index 0000000000..bce49a58f0 --- /dev/null +++ b/js/spa/public/static/img/api-logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/js/spa/public/static/img/camera.svg b/js/spa/public/static/img/camera.svg new file mode 100644 index 0000000000..b46daebb74 --- /dev/null +++ b/js/spa/public/static/img/camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/spa/public/static/img/clear.svg b/js/spa/public/static/img/clear.svg new file mode 100644 index 0000000000..bea0330748 --- /dev/null +++ b/js/spa/public/static/img/clear.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + diff --git a/js/spa/public/static/img/edit.svg b/js/spa/public/static/img/edit.svg new file mode 100644 index 0000000000..07fbe15983 --- /dev/null +++ b/js/spa/public/static/img/edit.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/js/spa/public/static/img/javascript.svg b/js/spa/public/static/img/javascript.svg new file mode 100644 index 0000000000..426b76c2fb --- /dev/null +++ b/js/spa/public/static/img/javascript.svg @@ -0,0 +1,16 @@ + diff --git a/js/app/test/files/gradio-logo.svg b/js/spa/public/static/img/logo.svg similarity index 100% rename from js/app/test/files/gradio-logo.svg rename to js/spa/public/static/img/logo.svg diff --git a/js/spa/public/static/img/logo_error.svg b/js/spa/public/static/img/logo_error.svg new file mode 100644 index 0000000000..5662b67552 --- /dev/null +++ b/js/spa/public/static/img/logo_error.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + ERROR + + + diff --git a/js/spa/public/static/img/python.svg b/js/spa/public/static/img/python.svg new file mode 100644 index 0000000000..ae0065b857 --- /dev/null +++ b/js/spa/public/static/img/python.svg @@ -0,0 +1,20 @@ + diff --git a/js/spa/public/static/img/undo-solid.svg b/js/spa/public/static/img/undo-solid.svg new file mode 100644 index 0000000000..bbbc9670bb --- /dev/null +++ b/js/spa/public/static/img/undo-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/js/app/src/Index.svelte b/js/spa/src/Index.svelte similarity index 96% rename from js/app/src/Index.svelte rename to js/spa/src/Index.svelte index 4a33e8d06d..73b660abd2 100644 --- a/js/app/src/Index.svelte +++ b/js/spa/src/Index.svelte @@ -1,9 +1,10 @@