@satinhq/kit 0.0.0-stage → 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +96 -0
- package/README.md +454 -2
- package/THIRD_PARTY_NOTICES.md +65 -0
- package/bin/satin.mjs +13 -0
- package/dist/acknowledgements/Acknowledgements.d.ts +4 -0
- package/dist/acknowledgements/Acknowledgements.js +42 -0
- package/dist/acknowledgements/bundledNotices.d.ts +4 -0
- package/dist/acknowledgements/bundledNotices.js +58 -0
- package/dist/acknowledgements/inventory.d.ts +17 -0
- package/dist/acknowledgements/inventory.js +10 -0
- package/dist/acknowledgements/inventory.json +39 -0
- package/dist/actions/ActionMenu.d.ts +30 -0
- package/dist/actions/ActionMenu.js +103 -0
- package/dist/actions/RowActions.d.ts +42 -0
- package/dist/actions/RowActions.js +820 -0
- package/dist/actions/contextMotion.d.ts +78 -0
- package/dist/actions/contextMotion.js +329 -0
- package/dist/actions/motion.d.ts +19 -0
- package/dist/actions/motion.js +74 -0
- package/dist/actions/nativeContextAppearance.json +86 -0
- package/dist/actions/nativeContextMotion.json +734 -0
- package/dist/actions/nativeMotion.json +388 -0
- package/dist/actions/preview.d.ts +27 -0
- package/dist/actions/preview.js +217 -0
- package/dist/actions/recognizers.d.ts +24 -0
- package/dist/actions/recognizers.js +87 -0
- package/dist/actions/rowScrub.d.ts +59 -0
- package/dist/actions/rowScrub.js +400 -0
- package/dist/actions/swipeSpring.d.ts +14 -0
- package/dist/actions/swipeSpring.js +35 -0
- package/dist/actions/types.d.ts +71 -0
- package/dist/actions/types.js +28 -0
- package/dist/app/InstallComponents.d.ts +16 -0
- package/dist/app/InstallComponents.js +104 -0
- package/dist/app/InstallationDiagnostics.d.ts +7 -0
- package/dist/app/InstallationDiagnostics.js +23 -0
- package/dist/app/OrientationGuard.d.ts +8 -0
- package/dist/app/OrientationGuard.js +9 -0
- package/dist/app/appearance.d.ts +18 -0
- package/dist/app/appearance.js +15 -0
- package/dist/app/appearanceStore.d.ts +30 -0
- package/dist/app/appearanceStore.js +228 -0
- package/dist/app/backgroundUpdate.d.ts +20 -0
- package/dist/app/backgroundUpdate.js +151 -0
- package/dist/app/buildInfo.d.ts +11 -0
- package/dist/app/buildInfo.js +12 -0
- package/dist/app/buildInfoBuild.d.ts +3 -0
- package/dist/app/buildInfoBuild.js +12 -0
- package/dist/app/checkCli.d.ts +1 -0
- package/dist/app/checkCli.js +73 -0
- package/dist/app/coldLaunchUpdate.d.ts +14 -0
- package/dist/app/coldLaunchUpdate.js +384 -0
- package/dist/app/definition.d.ts +85 -0
- package/dist/app/definition.js +347 -0
- package/dist/app/deployment.d.ts +28 -0
- package/dist/app/deployment.js +352 -0
- package/dist/app/deploymentBuild.d.ts +3 -0
- package/dist/app/deploymentBuild.js +55 -0
- package/dist/app/earlyWorker.d.ts +3 -0
- package/dist/app/earlyWorker.js +77 -0
- package/dist/app/head.d.ts +10 -0
- package/dist/app/head.js +120 -0
- package/dist/app/icons.d.ts +4 -0
- package/dist/app/icons.js +35 -0
- package/dist/app/install.d.ts +18 -0
- package/dist/app/install.js +82 -0
- package/dist/app/installCheck.d.ts +2 -0
- package/dist/app/installCheck.js +148 -0
- package/dist/app/installContext.d.ts +35 -0
- package/dist/app/installContext.js +45 -0
- package/dist/app/installCustom.d.ts +25 -0
- package/dist/app/installCustom.js +55 -0
- package/dist/app/installExperience.d.ts +22 -0
- package/dist/app/installExperience.js +389 -0
- package/dist/app/installExperienceDevice.d.ts +29 -0
- package/dist/app/installExperienceDevice.js +160 -0
- package/dist/app/installExperienceHome.d.ts +16 -0
- package/dist/app/installExperienceHome.js +304 -0
- package/dist/app/installExperienceRuntime.d.ts +37 -0
- package/dist/app/installExperienceRuntime.js +285 -0
- package/dist/app/installPolicy.d.ts +28 -0
- package/dist/app/installPolicy.js +90 -0
- package/dist/app/installQr.d.ts +10 -0
- package/dist/app/installQr.js +139 -0
- package/dist/app/installStrings.d.ts +52 -0
- package/dist/app/installStrings.js +75 -0
- package/dist/app/installTipPath.d.ts +12 -0
- package/dist/app/installTipPath.js +9 -0
- package/dist/app/installationFailure.d.ts +14 -0
- package/dist/app/installationFailure.js +38 -0
- package/dist/app/launch.d.ts +7 -0
- package/dist/app/launch.js +241 -0
- package/dist/app/launchReadiness.d.ts +9 -0
- package/dist/app/launchReadiness.js +72 -0
- package/dist/app/launchScreen.d.ts +16 -0
- package/dist/app/launchScreen.js +14 -0
- package/dist/app/launchScreenRuntime.d.ts +19 -0
- package/dist/app/launchScreenRuntime.js +313 -0
- package/dist/app/launchWatchdog.d.ts +1 -0
- package/dist/app/launchWatchdog.js +202 -0
- package/dist/app/manifests.d.ts +19 -0
- package/dist/app/manifests.js +20 -0
- package/dist/app/mdm.d.ts +3 -0
- package/dist/app/mdm.js +20 -0
- package/dist/app/mediaCheck.d.ts +9 -0
- package/dist/app/mediaCheck.js +122 -0
- package/dist/app/mediaTypes.d.ts +2 -0
- package/dist/app/mediaTypes.js +13 -0
- package/dist/app/platformPolicy.d.ts +3 -0
- package/dist/app/platformPolicy.js +10 -0
- package/dist/app/platformScripts.d.ts +6 -0
- package/dist/app/platformScripts.js +65 -0
- package/dist/app/releaseUpdates.d.ts +7 -0
- package/dist/app/releaseUpdates.js +53 -0
- package/dist/app/runtime.d.ts +9 -0
- package/dist/app/runtime.js +38 -0
- package/dist/app/startup.d.ts +30 -0
- package/dist/app/startup.js +24 -0
- package/dist/app/statusBand.d.ts +11 -0
- package/dist/app/statusBand.js +257 -0
- package/dist/app/viewport.d.ts +3 -0
- package/dist/app/viewport.js +42 -0
- package/dist/app/viewportValue.d.ts +5 -0
- package/dist/app/viewportValue.js +14 -0
- package/dist/app/vite.d.ts +27 -0
- package/dist/app/vite.js +440 -0
- package/dist/app/warmImage.d.ts +3 -0
- package/dist/app/warmImage.js +59 -0
- package/dist/content/content.d.ts +153 -0
- package/dist/content/content.js +315 -0
- package/dist/content/layout.d.ts +26 -0
- package/dist/content/layout.js +114 -0
- package/dist/content/scaledMetric.d.ts +3 -0
- package/dist/content/scaledMetric.js +68 -0
- package/dist/content/typography.d.ts +83 -0
- package/dist/content/typography.js +32 -0
- package/dist/controls/ActivityIndicatorSegments.d.ts +4 -0
- package/dist/controls/ActivityIndicatorSegments.js +5 -0
- package/dist/controls/ColorPicker.d.ts +20 -0
- package/dist/controls/ColorPicker.js +70 -0
- package/dist/controls/ControlRow.d.ts +5 -0
- package/dist/controls/ControlRow.js +10 -0
- package/dist/controls/DatePicker.d.ts +41 -0
- package/dist/controls/DatePicker.js +148 -0
- package/dist/controls/ProgressView.d.ts +17 -0
- package/dist/controls/ProgressView.js +24 -0
- package/dist/controls/civilDate.d.ts +49 -0
- package/dist/controls/civilDate.js +112 -0
- package/dist/data/database.d.ts +154 -0
- package/dist/data/database.js +710 -0
- package/dist/data/value-equal.d.ts +2 -0
- package/dist/data/value-equal.js +36 -0
- package/dist/data/write-store.d.ts +38 -0
- package/dist/data/write-store.js +192 -0
- package/dist/dev-menu/DevMenu.d.ts +1 -0
- package/dist/dev-menu/DevMenu.js +121 -0
- package/dist/dev-menu/actions.d.ts +12 -0
- package/dist/dev-menu/actions.js +99 -0
- package/dist/dev-menu/build.d.ts +5 -0
- package/dist/dev-menu/build.js +40 -0
- package/dist/dev-menu/gesture.d.ts +18 -0
- package/dist/dev-menu/gesture.js +109 -0
- package/dist/dev-menu/shake.d.ts +2 -0
- package/dist/dev-menu/shake.js +36 -0
- package/dist/dev-menu/types.d.ts +8 -0
- package/dist/dev-menu/types.js +1 -0
- package/dist/diagnostics.d.ts +3 -0
- package/dist/diagnostics.js +4 -0
- package/dist/docs/app-recipes.md +411 -0
- package/dist/docs/components/file-importer.md +54 -0
- package/dist/docs/components/paste-button.md +48 -0
- package/dist/docs/components/photos-picker.md +53 -0
- package/dist/docs/components/share-link.md +58 -0
- package/dist/docs/content.md +159 -0
- package/dist/docs/controls.md +151 -0
- package/dist/docs/data.md +332 -0
- package/dist/docs/limitations.md +40 -0
- package/dist/docs/messaging-scroll.md +234 -0
- package/dist/docs/networking.md +190 -0
- package/dist/docs/push.md +215 -0
- package/dist/docs/swiftui-reference.md +1895 -0
- package/dist/docs/symbols.md +293 -0
- package/dist/docs/tokens.md +60 -0
- package/dist/fidelity/devAssertions.d.ts +21 -0
- package/dist/fidelity/devAssertions.js +199 -0
- package/dist/focus/focusIntentMachine.d.ts +106 -0
- package/dist/focus/focusIntentMachine.js +359 -0
- package/dist/focus/navigationFocus.d.ts +42 -0
- package/dist/focus/navigationFocus.js +241 -0
- package/dist/focus/programmaticFocus.d.ts +15 -0
- package/dist/focus/programmaticFocus.js +152 -0
- package/dist/gestures/GestureView.d.ts +12 -0
- package/dist/gestures/GestureView.js +321 -0
- package/dist/gestures/arena.d.ts +138 -0
- package/dist/gestures/arena.js +417 -0
- package/dist/gestures/existingCompetitors.d.ts +79 -0
- package/dist/gestures/existingCompetitors.js +82 -0
- package/dist/gestures/gesture.d.ts +62 -0
- package/dist/gestures/gesture.js +107 -0
- package/dist/glass/ControlLens.d.ts +46 -0
- package/dist/glass/ControlLens.js +88 -0
- package/dist/glass/GlassBar.d.ts +9 -0
- package/dist/glass/GlassBar.js +22 -0
- package/dist/glass/GlassConfusionReview.d.ts +3 -0
- package/dist/glass/GlassConfusionReview.js +185 -0
- package/dist/glass/GlassEffect.d.ts +69 -0
- package/dist/glass/GlassEffect.js +550 -0
- package/dist/glass/GlassMaterialRoot.d.ts +7 -0
- package/dist/glass/GlassMaterialRoot.js +39 -0
- package/dist/glass/GlassPresentation.d.ts +28 -0
- package/dist/glass/GlassPresentation.js +1038 -0
- package/dist/glass/GlassProbeIcons.d.ts +8 -0
- package/dist/glass/GlassProbeIcons.js +12 -0
- package/dist/glass/GlassProbeOverlay.d.ts +52 -0
- package/dist/glass/GlassProbeOverlay.js +45 -0
- package/dist/glass/GlassTextField.d.ts +22 -0
- package/dist/glass/GlassTextField.js +12 -0
- package/dist/glass/MaterialEffectRoot.d.ts +9 -0
- package/dist/glass/MaterialEffectRoot.js +189 -0
- package/dist/glass/Menu.d.ts +3 -0
- package/dist/glass/Menu.js +35 -0
- package/dist/glass/MenuStack.d.ts +23 -0
- package/dist/glass/MenuStack.js +371 -0
- package/dist/glass/MenuSymbol.d.ts +7 -0
- package/dist/glass/MenuSymbol.js +16 -0
- package/dist/glass/MorphEllipsisArtwork.d.ts +2 -0
- package/dist/glass/MorphEllipsisArtwork.js +6 -0
- package/dist/glass/TabBar.d.ts +29 -0
- package/dist/glass/TabBar.js +169 -0
- package/dist/glass/capability.d.ts +25 -0
- package/dist/glass/capability.js +63 -0
- package/dist/glass/captureWindow.d.ts +60 -0
- package/dist/glass/captureWindow.js +119 -0
- package/dist/glass/confusionSession.d.ts +41 -0
- package/dist/glass/confusionSession.js +44 -0
- package/dist/glass/contactPhysics.d.ts +130 -0
- package/dist/glass/contactPhysics.js +214 -0
- package/dist/glass/context.d.ts +37 -0
- package/dist/glass/context.js +11 -0
- package/dist/glass/errorAlert.d.ts +6 -0
- package/dist/glass/errorAlert.js +57 -0
- package/dist/glass/errors.d.ts +22 -0
- package/dist/glass/errors.js +78 -0
- package/dist/glass/failurePolicy.d.ts +4 -0
- package/dist/glass/failurePolicy.js +20 -0
- package/dist/glass/fallback/material.d.ts +16 -0
- package/dist/glass/fallback/material.js +87 -0
- package/dist/glass/fallback/regions.d.ts +16 -0
- package/dist/glass/fallback/regions.js +249 -0
- package/dist/glass/fallback/runtime.d.ts +72 -0
- package/dist/glass/fallback/runtime.js +278 -0
- package/dist/glass/fallback/selection.d.ts +2 -0
- package/dist/glass/fallback/selection.js +9 -0
- package/dist/glass/fieldGeometry.d.ts +28 -0
- package/dist/glass/fieldGeometry.js +64 -0
- package/dist/glass/fieldMotion.d.ts +42 -0
- package/dist/glass/fieldMotion.js +47 -0
- package/dist/glass/glassContact.d.ts +76 -0
- package/dist/glass/glassContact.js +153 -0
- package/dist/glass/glassProbeSettings.d.ts +18 -0
- package/dist/glass/glassProbeSettings.js +133 -0
- package/dist/glass/lens/Scene.d.ts +108 -0
- package/dist/glass/lens/Scene.js +553 -0
- package/dist/glass/lens/backgrounds.json +103 -0
- package/dist/glass/lens/bitmapBackdrop.d.ts +14 -0
- package/dist/glass/lens/bitmapBackdrop.js +35 -0
- package/dist/glass/lens/controlLift.d.ts +94 -0
- package/dist/glass/lens/controlLift.js +78 -0
- package/dist/glass/lens/data.d.ts +19 -0
- package/dist/glass/lens/data.js +161 -0
- package/dist/glass/lens/drawableTop.d.ts +16 -0
- package/dist/glass/lens/drawableTop.js +15 -0
- package/dist/glass/lens/icons.d.ts +9 -0
- package/dist/glass/lens/icons.js +34 -0
- package/dist/glass/lens/interactiveContact.d.ts +33 -0
- package/dist/glass/lens/interactiveContact.js +158 -0
- package/dist/glass/lens/interactivePress.d.ts +95 -0
- package/dist/glass/lens/interactivePress.js +169 -0
- package/dist/glass/lens/ios27GlyphFit.json +126 -0
- package/dist/glass/lens/lensLightingSamples.json +1 -0
- package/dist/glass/lens/lensPress.d.ts +22 -0
- package/dist/glass/lens/lensPress.js +68 -0
- package/dist/glass/lens/lensPressSamples.json +1 -0
- package/dist/glass/lens/liquidMotion.d.ts +50 -0
- package/dist/glass/lens/liquidMotion.js +239 -0
- package/dist/glass/lens/materialGlassRecipes.json +776 -0
- package/dist/glass/lens/materialUniforms.d.ts +22 -0
- package/dist/glass/lens/materialUniforms.js +117 -0
- package/dist/glass/lens/menu-closing-close-fit.json +380 -0
- package/dist/glass/lens/menu-opening-native-fits.json +911 -0
- package/dist/glass/lens/menuContextFit.json +88 -0
- package/dist/glass/lens/menuContextOpacity.json +98 -0
- package/dist/glass/lens/menuContextPresentation.d.ts +15 -0
- package/dist/glass/lens/menuContextPresentation.js +65 -0
- package/dist/glass/lens/menuCornerFit.json +252 -0
- package/dist/glass/lens/menuCornerMotion.d.ts +9 -0
- package/dist/glass/lens/menuCornerMotion.js +5 -0
- package/dist/glass/lens/menuDropFit.json +64 -0
- package/dist/glass/lens/menuField.d.ts +178 -0
- package/dist/glass/lens/menuField.js +564 -0
- package/dist/glass/lens/menuGesturePresentation.d.ts +12 -0
- package/dist/glass/lens/menuGesturePresentation.js +42 -0
- package/dist/glass/lens/menuGlyphDropFit.json +38 -0
- package/dist/glass/lens/menuMorphFit.json +564 -0
- package/dist/glass/lens/menuMorphMotion.d.ts +70 -0
- package/dist/glass/lens/menuMorphMotion.js +219 -0
- package/dist/glass/lens/menuMorphPhoneFit.json +85 -0
- package/dist/glass/lens/menuMotion.d.ts +81 -0
- package/dist/glass/lens/menuMotion.js +323 -0
- package/dist/glass/lens/menuPlacement.d.ts +5 -0
- package/dist/glass/lens/menuPlacement.js +29 -0
- package/dist/glass/lens/menuSpring.d.ts +18 -0
- package/dist/glass/lens/menuSpring.js +29 -0
- package/dist/glass/lens/menuTouchLight.d.ts +13 -0
- package/dist/glass/lens/menuTouchLight.js +147 -0
- package/dist/glass/lens/mirrorConstants.d.ts +1 -0
- package/dist/glass/lens/mirrorConstants.js +2 -0
- package/dist/glass/lens/mirrorExtents.d.ts +52 -0
- package/dist/glass/lens/mirrorExtents.js +264 -0
- package/dist/glass/lens/mirrorInvalidation.d.ts +6 -0
- package/dist/glass/lens/mirrorInvalidation.js +10 -0
- package/dist/glass/lens/mirrorReuse.d.ts +20 -0
- package/dist/glass/lens/mirrorReuse.js +166 -0
- package/dist/glass/lens/motion.d.ts +62 -0
- package/dist/glass/lens/motion.js +93 -0
- package/dist/glass/lens/recordedMotion.d.ts +6 -0
- package/dist/glass/lens/recordedMotion.js +44 -0
- package/dist/glass/lens/referenceBackground.d.ts +9 -0
- package/dist/glass/lens/referenceBackground.js +151 -0
- package/dist/glass/lens/referenceProfiles.d.ts +21 -0
- package/dist/glass/lens/referenceProfiles.js +33 -0
- package/dist/glass/lens/referenceRegularTint.d.ts +12 -0
- package/dist/glass/lens/referenceRegularTint.js +41 -0
- package/dist/glass/lens/scopeSegments.d.ts +12 -0
- package/dist/glass/lens/scopeSegments.js +18 -0
- package/dist/glass/lens/scrollAnchoring.d.ts +15 -0
- package/dist/glass/lens/scrollAnchoring.js +17 -0
- package/dist/glass/lens/selectionParameters.json +94 -0
- package/dist/glass/lens/shapeParameters.json +198 -0
- package/dist/glass/lens/tab-motion-native-fits.json +778 -0
- package/dist/glass/lens/tabAccessoryMotion.d.ts +52 -0
- package/dist/glass/lens/tabAccessoryMotion.js +52 -0
- package/dist/glass/lens/tabChromaRimModel.d.ts +43 -0
- package/dist/glass/lens/tabChromaRimModel.js +93 -0
- package/dist/glass/lens/tabCollapseInkSamples.json +49 -0
- package/dist/glass/lens/tabCompactGesture.d.ts +15 -0
- package/dist/glass/lens/tabCompactGesture.js +50 -0
- package/dist/glass/lens/tabGeometryAttack.json +70 -0
- package/dist/glass/lens/tabGlyphColours.d.ts +17 -0
- package/dist/glass/lens/tabGlyphColours.js +37 -0
- package/dist/glass/lens/tabInterruptedDecaySamples.json +245 -0
- package/dist/glass/lens/tabInterruptedRestoreSamples.json +290 -0
- package/dist/glass/lens/tabMaterialModel.d.ts +10 -0
- package/dist/glass/lens/tabMaterialModel.js +108 -0
- package/dist/glass/lens/tabMinimizeInk.d.ts +15 -0
- package/dist/glass/lens/tabMinimizeInk.js +14 -0
- package/dist/glass/lens/tabMinimizeMotion.d.ts +36 -0
- package/dist/glass/lens/tabMinimizeMotion.js +107 -0
- package/dist/glass/lens/tabMinimizeSamples.json +411 -0
- package/dist/glass/lens/tabMotion.d.ts +91 -0
- package/dist/glass/lens/tabMotion.js +478 -0
- package/dist/glass/lens/tabMotionFit.d.ts +76 -0
- package/dist/glass/lens/tabMotionFit.js +61 -0
- package/dist/glass/lens/tabNativeSymbols.d.ts +1 -0
- package/dist/glass/lens/tabNativeSymbols.js +7 -0
- package/dist/glass/lens/tabPresentation.d.ts +21 -0
- package/dist/glass/lens/tabPresentation.js +20 -0
- package/dist/glass/lens/tabRelease.d.ts +5 -0
- package/dist/glass/lens/tabRelease.js +14 -0
- package/dist/glass/lens/tabRestoreMotion.d.ts +19 -0
- package/dist/glass/lens/tabRestoreMotion.js +65 -0
- package/dist/glass/lens/tabRestoreSamples.json +1272 -0
- package/dist/glass/lens/tabSearchMember.d.ts +38 -0
- package/dist/glass/lens/tabSearchMember.js +74 -0
- package/dist/glass/lens/tabSelectionMaterial.d.ts +20 -0
- package/dist/glass/lens/tabSelectionMaterial.js +23 -0
- package/dist/glass/lens/tabSelectionMeasurements.test-fixture.d.ts +9 -0
- package/dist/glass/lens/tabSelectionMeasurements.test-fixture.js +74 -0
- package/dist/glass/lens/tabSettingsSymbol.d.ts +1 -0
- package/dist/glass/lens/tabSettingsSymbol.js +2 -0
- package/dist/glass/lens/tabShapeResponse.d.ts +7 -0
- package/dist/glass/lens/tabShapeResponse.js +30 -0
- package/dist/glass/lens/theme.d.ts +18 -0
- package/dist/glass/lens/theme.js +40 -0
- package/dist/glass/lens/trace.d.ts +2 -0
- package/dist/glass/lens/trace.js +27 -0
- package/dist/glass/liquidContext.d.ts +31 -0
- package/dist/glass/liquidContext.js +2 -0
- package/dist/glass/menuPanelPlacement.d.ts +51 -0
- package/dist/glass/menuPanelPlacement.js +128 -0
- package/dist/glass/menuPresenter.d.ts +34 -0
- package/dist/glass/menuPresenter.js +983 -0
- package/dist/glass/menuSymbolMasks.d.ts +1 -0
- package/dist/glass/menuSymbolMasks.js +1 -0
- package/dist/glass/menuSymbolTokens.d.ts +22 -0
- package/dist/glass/menuSymbolTokens.js +12 -0
- package/dist/glass/menuTriggerGeometry.d.ts +99 -0
- package/dist/glass/menuTriggerGeometry.js +126 -0
- package/dist/glass/menuTriggerSnapshot.d.ts +77 -0
- package/dist/glass/menuTriggerSnapshot.js +69 -0
- package/dist/glass/menuTypes.d.ts +22 -0
- package/dist/glass/menuTypes.js +1 -0
- package/dist/glass/morphField.d.ts +18 -0
- package/dist/glass/morphField.js +139 -0
- package/dist/glass/presentationFrame.d.ts +43 -0
- package/dist/glass/presentationFrame.js +82 -0
- package/dist/glass/pressHighlight.d.ts +9 -0
- package/dist/glass/pressHighlight.js +158 -0
- package/dist/glass/regionRegistry.d.ts +93 -0
- package/dist/glass/regionRegistry.js +313 -0
- package/dist/glass/regions.d.ts +262 -0
- package/dist/glass/regions.js +147 -0
- package/dist/glass/regularMaterialContext.d.ts +45 -0
- package/dist/glass/regularMaterialContext.js +118 -0
- package/dist/glass/regularTriggerMaterial.d.ts +19 -0
- package/dist/glass/regularTriggerMaterial.js +111 -0
- package/dist/glass/regularTriggerRim.d.ts +163 -0
- package/dist/glass/regularTriggerRim.js +436 -0
- package/dist/glass/renderSpecs.d.ts +454 -0
- package/dist/glass/renderSpecs.js +231 -0
- package/dist/glass/rendererContract.d.ts +205 -0
- package/dist/glass/rendererContract.js +18 -0
- package/dist/glass/shapeTrack.d.ts +53 -0
- package/dist/glass/shapeTrack.js +74 -0
- package/dist/glass/shapeTrackRegistry.d.ts +40 -0
- package/dist/glass/shapeTrackRegistry.js +49 -0
- package/dist/glass/sourceDamage.d.ts +6 -0
- package/dist/glass/sourceDamage.js +8 -0
- package/dist/glass/submenuMotion.d.ts +205 -0
- package/dist/glass/submenuMotion.js +306 -0
- package/dist/glass/tabBarModel.d.ts +12 -0
- package/dist/glass/tabBarModel.js +32 -0
- package/dist/glass/testing.d.ts +14 -0
- package/dist/glass/testing.js +14 -0
- package/dist/glass/tokens.d.ts +79 -0
- package/dist/glass/tokens.js +86 -0
- package/dist/glass/toolbarMaterialContext.d.ts +28 -0
- package/dist/glass/toolbarMaterialContext.js +66 -0
- package/dist/glass/topLayer.d.ts +5 -0
- package/dist/glass/topLayer.js +10 -0
- package/dist/glass/unionOutline.d.ts +11 -0
- package/dist/glass/unionOutline.js +98 -0
- package/dist/glass/visibleDeadline.d.ts +21 -0
- package/dist/glass/visibleDeadline.js +61 -0
- package/dist/glass/webgpu/accessoryMorph.d.ts +99 -0
- package/dist/glass/webgpu/accessoryMorph.js +473 -0
- package/dist/glass/webgpu/accessoryTrack.d.ts +47 -0
- package/dist/glass/webgpu/accessoryTrack.js +59 -0
- package/dist/glass/webgpu/areaMips.d.ts +50 -0
- package/dist/glass/webgpu/areaMips.js +166 -0
- package/dist/glass/webgpu/backdrop.d.ts +86 -0
- package/dist/glass/webgpu/backdrop.js +243 -0
- package/dist/glass/webgpu/backdropLayers.d.ts +29 -0
- package/dist/glass/webgpu/backdropLayers.js +182 -0
- package/dist/glass/webgpu/backgroundLayers.d.ts +71 -0
- package/dist/glass/webgpu/backgroundLayers.js +385 -0
- package/dist/glass/webgpu/cadence.d.ts +18 -0
- package/dist/glass/webgpu/cadence.js +35 -0
- package/dist/glass/webgpu/canvasSubmission.d.ts +6 -0
- package/dist/glass/webgpu/canvasSubmission.js +22 -0
- package/dist/glass/webgpu/capture.d.ts +77 -0
- package/dist/glass/webgpu/capture.js +534 -0
- package/dist/glass/webgpu/captureBands.d.ts +39 -0
- package/dist/glass/webgpu/captureBands.js +53 -0
- package/dist/glass/webgpu/captureContext.d.ts +1 -0
- package/dist/glass/webgpu/captureContext.js +6 -0
- package/dist/glass/webgpu/captureDemand.d.ts +44 -0
- package/dist/glass/webgpu/captureDemand.js +81 -0
- package/dist/glass/webgpu/captureRelease.d.ts +18 -0
- package/dist/glass/webgpu/captureRelease.js +39 -0
- package/dist/glass/webgpu/client.d.ts +49 -0
- package/dist/glass/webgpu/client.js +336 -0
- package/dist/glass/webgpu/contextBackdrop.d.ts +6 -0
- package/dist/glass/webgpu/contextBackdrop.js +13 -0
- package/dist/glass/webgpu/contextComposite.d.ts +64 -0
- package/dist/glass/webgpu/contextComposite.js +66 -0
- package/dist/glass/webgpu/decodedImage.d.ts +1 -0
- package/dist/glass/webgpu/decodedImage.js +2 -0
- package/dist/glass/webgpu/deviceLimits.d.ts +5 -0
- package/dist/glass/webgpu/deviceLimits.js +8 -0
- package/dist/glass/webgpu/edgePass.d.ts +9 -0
- package/dist/glass/webgpu/edgePass.js +170 -0
- package/dist/glass/webgpu/entry.worker.d.ts +1 -0
- package/dist/glass/webgpu/entry.worker.js +28 -0
- package/dist/glass/webgpu/errorCode.d.ts +3 -0
- package/dist/glass/webgpu/errorCode.js +27 -0
- package/dist/glass/webgpu/errors.d.ts +8 -0
- package/dist/glass/webgpu/errors.js +55 -0
- package/dist/glass/webgpu/fieldInk.d.ts +9 -0
- package/dist/glass/webgpu/fieldInk.js +62 -0
- package/dist/glass/webgpu/foreground.d.ts +29 -0
- package/dist/glass/webgpu/foreground.js +313 -0
- package/dist/glass/webgpu/frameClock.d.ts +34 -0
- package/dist/glass/webgpu/frameClock.js +60 -0
- package/dist/glass/webgpu/frameGraph.d.ts +57 -0
- package/dist/glass/webgpu/frameGraph.js +287 -0
- package/dist/glass/webgpu/frameProbe.d.ts +58 -0
- package/dist/glass/webgpu/frameProbe.js +181 -0
- package/dist/glass/webgpu/interactionProfiles.d.ts +10 -0
- package/dist/glass/webgpu/interactionProfiles.js +25 -0
- package/dist/glass/webgpu/keptGlyphs.d.ts +68 -0
- package/dist/glass/webgpu/keptGlyphs.js +85 -0
- package/dist/glass/webgpu/keyboardBackdrop.d.ts +12 -0
- package/dist/glass/webgpu/keyboardBackdrop.js +51 -0
- package/dist/glass/webgpu/lagTrace.d.ts +31 -0
- package/dist/glass/webgpu/lagTrace.js +22 -0
- package/dist/glass/webgpu/layers.d.ts +100 -0
- package/dist/glass/webgpu/layers.js +301 -0
- package/dist/glass/webgpu/lensDebug.d.ts +4 -0
- package/dist/glass/webgpu/lensDebug.js +28 -0
- package/dist/glass/webgpu/lensDiffusion.d.ts +2 -0
- package/dist/glass/webgpu/lensDiffusion.js +20 -0
- package/dist/glass/webgpu/lensLightingFit.json +222 -0
- package/dist/glass/webgpu/menuLiftInput.d.ts +30 -0
- package/dist/glass/webgpu/menuLiftInput.js +39 -0
- package/dist/glass/webgpu/menuSurfaceGuard.d.ts +17 -0
- package/dist/glass/webgpu/menuSurfaceGuard.js +26 -0
- package/dist/glass/webgpu/minimize.d.ts +184 -0
- package/dist/glass/webgpu/minimize.js +470 -0
- package/dist/glass/webgpu/navigationAtlasCopy.d.ts +12 -0
- package/dist/glass/webgpu/navigationAtlasCopy.js +121 -0
- package/dist/glass/webgpu/navigationTracks.d.ts +3 -0
- package/dist/glass/webgpu/navigationTracks.js +84 -0
- package/dist/glass/webgpu/passes.d.ts +204 -0
- package/dist/glass/webgpu/passes.js +394 -0
- package/dist/glass/webgpu/pendingSurfaceInput.d.ts +29 -0
- package/dist/glass/webgpu/pendingSurfaceInput.js +51 -0
- package/dist/glass/webgpu/preparedSourcePixels.d.ts +21 -0
- package/dist/glass/webgpu/preparedSourcePixels.js +43 -0
- package/dist/glass/webgpu/presentationBackdrop.d.ts +3 -0
- package/dist/glass/webgpu/presentationBackdrop.js +33 -0
- package/dist/glass/webgpu/presentationDiffusion.d.ts +48 -0
- package/dist/glass/webgpu/presentationDiffusion.js +57 -0
- package/dist/glass/webgpu/presentationMaterial.d.ts +9 -0
- package/dist/glass/webgpu/presentationMaterial.js +156 -0
- package/dist/glass/webgpu/presenterViewport.d.ts +11 -0
- package/dist/glass/webgpu/presenterViewport.js +193 -0
- package/dist/glass/webgpu/production.d.ts +552 -0
- package/dist/glass/webgpu/production.js +1929 -0
- package/dist/glass/webgpu/productionInstalls.d.ts +53 -0
- package/dist/glass/webgpu/productionInstalls.js +225 -0
- package/dist/glass/webgpu/productionNavigation.d.ts +5 -0
- package/dist/glass/webgpu/productionNavigation.js +360 -0
- package/dist/glass/webgpu/productionPinnedTop.d.ts +80 -0
- package/dist/glass/webgpu/productionPinnedTop.js +77 -0
- package/dist/glass/webgpu/productionPinnedTopPrepare.d.ts +21 -0
- package/dist/glass/webgpu/productionPinnedTopPrepare.js +132 -0
- package/dist/glass/webgpu/productionPlanes.d.ts +135 -0
- package/dist/glass/webgpu/productionPlanes.js +412 -0
- package/dist/glass/webgpu/productionPrepare.d.ts +18 -0
- package/dist/glass/webgpu/productionPrepare.js +832 -0
- package/dist/glass/webgpu/productionTracks.d.ts +73 -0
- package/dist/glass/webgpu/productionTracks.js +22 -0
- package/dist/glass/webgpu/productionViewport.d.ts +20 -0
- package/dist/glass/webgpu/productionViewport.js +52 -0
- package/dist/glass/webgpu/profile.d.ts +37 -0
- package/dist/glass/webgpu/profile.js +101 -0
- package/dist/glass/webgpu/raster.d.ts +337 -0
- package/dist/glass/webgpu/raster.js +1360 -0
- package/dist/glass/webgpu/rasterMaterial.d.ts +19 -0
- package/dist/glass/webgpu/rasterMaterial.js +197 -0
- package/dist/glass/webgpu/rasterShaders.d.ts +7 -0
- package/dist/glass/webgpu/rasterShaders.js +105 -0
- package/dist/glass/webgpu/rasterUniforms.d.ts +304 -0
- package/dist/glass/webgpu/rasterUniforms.js +415 -0
- package/dist/glass/webgpu/regionBackdrop.d.ts +8 -0
- package/dist/glass/webgpu/regionBackdrop.js +12 -0
- package/dist/glass/webgpu/regionBridge.d.ts +145 -0
- package/dist/glass/webgpu/regionBridge.js +1691 -0
- package/dist/glass/webgpu/regionScene.d.ts +294 -0
- package/dist/glass/webgpu/regionScene.js +2144 -0
- package/dist/glass/webgpu/renderer.d.ts +8 -0
- package/dist/glass/webgpu/renderer.js +1478 -0
- package/dist/glass/webgpu/residentPlanes.d.ts +69 -0
- package/dist/glass/webgpu/residentPlanes.js +104 -0
- package/dist/glass/webgpu/restMaterial.d.ts +6 -0
- package/dist/glass/webgpu/restMaterial.js +65 -0
- package/dist/glass/webgpu/resumeOverlay.d.ts +44 -0
- package/dist/glass/webgpu/resumeOverlay.js +82 -0
- package/dist/glass/webgpu/sampleTrace.d.ts +11 -0
- package/dist/glass/webgpu/sampleTrace.js +50 -0
- package/dist/glass/webgpu/scrollEdgeBackdrop.d.ts +89 -0
- package/dist/glass/webgpu/scrollEdgeBackdrop.js +177 -0
- package/dist/glass/webgpu/scrollEdgePose.d.ts +4 -0
- package/dist/glass/webgpu/scrollEdgePose.js +49 -0
- package/dist/glass/webgpu/selectionThumb.d.ts +81 -0
- package/dist/glass/webgpu/selectionThumb.js +209 -0
- package/dist/glass/webgpu/shaders.d.ts +67 -0
- package/dist/glass/webgpu/shaders.js +595 -0
- package/dist/glass/webgpu/sharedLift.d.ts +7 -0
- package/dist/glass/webgpu/sharedLift.js +223 -0
- package/dist/glass/webgpu/sourcePixels.d.ts +42 -0
- package/dist/glass/webgpu/sourcePixels.js +140 -0
- package/dist/glass/webgpu/sourcePixels.worker.d.ts +1 -0
- package/dist/glass/webgpu/sourcePixels.worker.js +62 -0
- package/dist/glass/webgpu/tabGlyphInk.d.ts +14 -0
- package/dist/glass/webgpu/tabGlyphInk.js +72 -0
- package/dist/glass/webgpu/touchLight.d.ts +4 -0
- package/dist/glass/webgpu/touchLight.js +15 -0
- package/dist/glass/worker/client.d.ts +21 -0
- package/dist/glass/worker/client.js +152 -0
- package/dist/glass/worker/experiment.d.ts +13 -0
- package/dist/glass/worker/experiment.js +221 -0
- package/dist/glass/worker/fixture.d.ts +21 -0
- package/dist/glass/worker/fixture.js +152 -0
- package/dist/glass/worker/protocol.d.ts +439 -0
- package/dist/glass/worker/protocol.js +5 -0
- package/dist/graphicsProbe.d.ts +19 -0
- package/dist/graphicsProbe.js +111 -0
- package/dist/haptics/SensoryButton.d.ts +21 -0
- package/dist/haptics/SensoryButton.js +80 -0
- package/dist/image/ContentAdmission.d.ts +19 -0
- package/dist/image/ContentAdmission.js +70 -0
- package/dist/image/Image.d.ts +30 -0
- package/dist/image/Image.js +341 -0
- package/dist/image/asset.d.ts +9 -0
- package/dist/image/asset.js +1 -0
- package/dist/image/contentReadiness.d.ts +7 -0
- package/dist/image/contentReadiness.js +54 -0
- package/dist/image/imports.d.ts +4 -0
- package/dist/image/resource.d.ts +53 -0
- package/dist/image/resource.js +286 -0
- package/dist/image/vite.d.ts +3 -0
- package/dist/image/vite.js +63 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +102 -0
- package/dist/install.d.ts +8 -0
- package/dist/install.js +8 -0
- package/dist/internal.d.ts +96 -0
- package/dist/internal.js +80 -0
- package/dist/keyboard/adapter.d.ts +82 -0
- package/dist/keyboard/adapter.js +727 -0
- package/dist/keyboard/avoidance.d.ts +24 -0
- package/dist/keyboard/avoidance.js +283 -0
- package/dist/keyboard/caretMirror.d.ts +13 -0
- package/dist/keyboard/caretMirror.js +122 -0
- package/dist/keyboard/expectedKeyboard.d.ts +10 -0
- package/dist/keyboard/expectedKeyboard.js +60 -0
- package/dist/keyboard/geometry.d.ts +10 -0
- package/dist/keyboard/geometry.js +21 -0
- package/dist/keyboard/modalTapFocus.d.ts +41 -0
- package/dist/keyboard/modalTapFocus.js +224 -0
- package/dist/keyboard/motion.d.ts +54 -0
- package/dist/keyboard/motion.js +80 -0
- package/dist/keyboard/translation.d.ts +12 -0
- package/dist/keyboard/translation.js +19 -0
- package/dist/layout/adaptiveTabsContext.d.ts +5 -0
- package/dist/layout/adaptiveTabsContext.js +2 -0
- package/dist/layout/deviceIdiom.d.ts +4 -0
- package/dist/layout/deviceIdiom.js +12 -0
- package/dist/layout/layoutClass.d.ts +44 -0
- package/dist/layout/layoutClass.js +102 -0
- package/dist/layout/navigationLayoutContext.d.ts +8 -0
- package/dist/layout/navigationLayoutContext.js +5 -0
- package/dist/list-form/ListForm.d.ts +158 -0
- package/dist/list-form/ListForm.js +427 -0
- package/dist/list-form/ListItem.d.ts +30 -0
- package/dist/list-form/ListItem.js +251 -0
- package/dist/list-form/RowLabel.d.ts +14 -0
- package/dist/list-form/RowLabel.js +11 -0
- package/dist/list-form/Slider.d.ts +18 -0
- package/dist/list-form/Slider.js +235 -0
- package/dist/list-form/StepperButton.d.ts +9 -0
- package/dist/list-form/StepperButton.js +60 -0
- package/dist/list-form/Toggle.d.ts +16 -0
- package/dist/list-form/Toggle.js +204 -0
- package/dist/list-form/editMotion.d.ts +15 -0
- package/dist/list-form/editMotion.js +25 -0
- package/dist/list-form/editing.d.ts +102 -0
- package/dist/list-form/editing.js +51 -0
- package/dist/list-form/listContext.d.ts +4 -0
- package/dist/list-form/listContext.js +5 -0
- package/dist/list-form/offsets.d.ts +26 -0
- package/dist/list-form/offsets.js +34 -0
- package/dist/list-form/reorder.d.ts +20 -0
- package/dist/list-form/reorder.js +193 -0
- package/dist/list-form/rowMotion.d.ts +11 -0
- package/dist/list-form/rowMotion.js +236 -0
- package/dist/list-form/rowMotionScope.d.ts +14 -0
- package/dist/list-form/rowMotionScope.js +61 -0
- package/dist/list-form/separatorInsets.d.ts +4 -0
- package/dist/list-form/separatorInsets.js +87 -0
- package/dist/list-form/sliderContact.d.ts +40 -0
- package/dist/list-form/sliderContact.js +98 -0
- package/dist/list-form/state.d.ts +5 -0
- package/dist/list-form/state.js +8 -0
- package/dist/list-form/toggleContact.d.ts +55 -0
- package/dist/list-form/toggleContact.js +164 -0
- package/dist/media/controller.d.ts +7 -0
- package/dist/media/controller.js +612 -0
- package/dist/media/react.d.ts +9 -0
- package/dist/media/react.js +38 -0
- package/dist/media/systemMedia.d.ts +6 -0
- package/dist/media/systemMedia.js +200 -0
- package/dist/media/types.d.ts +83 -0
- package/dist/media/types.js +1 -0
- package/dist/menu/menuContact.d.ts +20 -0
- package/dist/menu/menuContact.js +286 -0
- package/dist/menu/menuGesture.d.ts +84 -0
- package/dist/menu/menuGesture.js +502 -0
- package/dist/menu/menuInteraction.d.ts +17 -0
- package/dist/menu/menuInteraction.js +34 -0
- package/dist/menu/menuOutside.d.ts +9 -0
- package/dist/menu/menuOutside.js +58 -0
- package/dist/menu/menuPanelContact.d.ts +11 -0
- package/dist/menu/menuPanelContact.js +77 -0
- package/dist/menu/menuTriggerHold.d.ts +3 -0
- package/dist/menu/menuTriggerHold.js +52 -0
- package/dist/menu/sampledMotion.d.ts +37 -0
- package/dist/menu/sampledMotion.js +86 -0
- package/dist/modal/lifecycle.d.ts +10 -0
- package/dist/modal/lifecycle.js +189 -0
- package/dist/motion/TransitionView.d.ts +12 -0
- package/dist/motion/TransitionView.js +118 -0
- package/dist/motion/animate.d.ts +20 -0
- package/dist/motion/animate.js +79 -0
- package/dist/motion/animationValue.d.ts +25 -0
- package/dist/motion/animationValue.js +42 -0
- package/dist/motion/composerMotion.d.ts +3 -0
- package/dist/motion/composerMotion.js +15 -0
- package/dist/motion/layoutTransaction.d.ts +7 -0
- package/dist/motion/layoutTransaction.js +28 -0
- package/dist/motion/matchedGeometry.d.ts +55 -0
- package/dist/motion/matchedGeometry.js +412 -0
- package/dist/motion/springPath.d.ts +27 -0
- package/dist/motion/springPath.js +46 -0
- package/dist/motion/springTrack.d.ts +33 -0
- package/dist/motion/springTrack.js +69 -0
- package/dist/motion/transition.d.ts +48 -0
- package/dist/motion/transition.js +56 -0
- package/dist/motion/transitionImages.d.ts +7 -0
- package/dist/motion/transitionImages.js +49 -0
- package/dist/motionProbe.d.ts +227 -0
- package/dist/motionProbe.js +697 -0
- package/dist/motionProbeControls.d.ts +2 -0
- package/dist/motionProbeControls.js +118 -0
- package/dist/motionProbeDelivery.d.ts +15 -0
- package/dist/motionProbeDelivery.js +84 -0
- package/dist/navigation/DetailList.d.ts +9 -0
- package/dist/navigation/DetailList.js +7 -0
- package/dist/navigation/NavigationChrome.d.ts +18 -0
- package/dist/navigation/NavigationChrome.js +195 -0
- package/dist/navigation/NavigationSearchRow.d.ts +9 -0
- package/dist/navigation/NavigationSearchRow.js +101 -0
- package/dist/navigation/NavigationTitleSlots.d.ts +18 -0
- package/dist/navigation/NavigationTitleSlots.js +64 -0
- package/dist/navigation/NavigatorHost.d.ts +17 -0
- package/dist/navigation/NavigatorHost.js +534 -0
- package/dist/navigation/ScreenContainer.d.ts +31 -0
- package/dist/navigation/ScreenContainer.js +219 -0
- package/dist/navigation/ScrubSourceFrames.d.ts +18 -0
- package/dist/navigation/ScrubSourceFrames.js +67 -0
- package/dist/navigation/Sidebar.d.ts +16 -0
- package/dist/navigation/Sidebar.js +20 -0
- package/dist/navigation/SidebarSymbol.d.ts +4 -0
- package/dist/navigation/SidebarSymbol.js +6 -0
- package/dist/navigation/ToolbarGlass.d.ts +2 -0
- package/dist/navigation/ToolbarGlass.js +429 -0
- package/dist/navigation/TransitionEdge.d.ts +4 -0
- package/dist/navigation/TransitionEdge.js +33 -0
- package/dist/navigation/bottomToolbarGeometry.d.ts +6 -0
- package/dist/navigation/bottomToolbarGeometry.js +14 -0
- package/dist/navigation/chromeCurves.d.ts +48 -0
- package/dist/navigation/chromeCurves.js +255 -0
- package/dist/navigation/glassTransition.d.ts +32 -0
- package/dist/navigation/glassTransition.js +55 -0
- package/dist/navigation/horizontalDrag.d.ts +6 -0
- package/dist/navigation/horizontalDrag.js +15 -0
- package/dist/navigation/interactivePop.d.ts +45 -0
- package/dist/navigation/interactivePop.js +86 -0
- package/dist/navigation/interactivePopTypes.d.ts +85 -0
- package/dist/navigation/interactivePopTypes.js +36 -0
- package/dist/navigation/keyboard.d.ts +9 -0
- package/dist/navigation/keyboard.js +55 -0
- package/dist/navigation/motion.d.ts +19 -0
- package/dist/navigation/motion.js +645 -0
- package/dist/navigation/motionTokens.d.ts +43 -0
- package/dist/navigation/motionTokens.js +75 -0
- package/dist/navigation/nativeScrubExperiment.d.ts +5 -0
- package/dist/navigation/nativeScrubExperiment.js +153 -0
- package/dist/navigation/nativeScrubSource.d.ts +15 -0
- package/dist/navigation/nativeScrubSource.js +88 -0
- package/dist/navigation/navigationChromeModel.d.ts +8 -0
- package/dist/navigation/navigationChromeModel.js +30 -0
- package/dist/navigation/navigationContext.d.ts +22 -0
- package/dist/navigation/navigationContext.js +65 -0
- package/dist/navigation/navigationEdge.d.ts +4 -0
- package/dist/navigation/navigationEdge.js +101 -0
- package/dist/navigation/pointerPop.d.ts +32 -0
- package/dist/navigation/pointerPop.js +206 -0
- package/dist/navigation/probeLayers.d.ts +7 -0
- package/dist/navigation/probeLayers.js +8 -0
- package/dist/navigation/registry.d.ts +14 -0
- package/dist/navigation/registry.js +31 -0
- package/dist/navigation/releaseDecision.d.ts +21 -0
- package/dist/navigation/releaseDecision.js +94 -0
- package/dist/navigation/releaseTrajectory.d.ts +20 -0
- package/dist/navigation/releaseTrajectory.js +95 -0
- package/dist/navigation/releaseVelocity.d.ts +9 -0
- package/dist/navigation/releaseVelocity.js +38 -0
- package/dist/navigation/routeCodec.d.ts +33 -0
- package/dist/navigation/routeCodec.js +123 -0
- package/dist/navigation/scrollEdge.d.ts +18 -0
- package/dist/navigation/scrollEdge.js +66 -0
- package/dist/navigation/scrubFrameLoop.d.ts +44 -0
- package/dist/navigation/scrubFrameLoop.js +129 -0
- package/dist/navigation/sidebarSelection.d.ts +5 -0
- package/dist/navigation/sidebarSelection.js +8 -0
- package/dist/navigation/splitContext.d.ts +17 -0
- package/dist/navigation/splitContext.js +9 -0
- package/dist/navigation/splitState.d.ts +46 -0
- package/dist/navigation/splitState.js +130 -0
- package/dist/navigation/stack.d.ts +25 -0
- package/dist/navigation/stack.js +136 -0
- package/dist/navigation/store.d.ts +80 -0
- package/dist/navigation/store.js +464 -0
- package/dist/navigation/toolbarGlassMotion.d.ts +40 -0
- package/dist/navigation/toolbarGlassMotion.js +202 -0
- package/dist/navigation/toolbarMinimization.d.ts +9 -0
- package/dist/navigation/toolbarMinimization.js +76 -0
- package/dist/navigation/toolbarMotionOwner.d.ts +6 -0
- package/dist/navigation/toolbarMotionOwner.js +30 -0
- package/dist/navigation/touchArbitration.d.ts +34 -0
- package/dist/navigation/touchArbitration.js +550 -0
- package/dist/navigation/tracking.d.ts +7 -0
- package/dist/navigation/tracking.js +19 -0
- package/dist/navigation/transitionBindings.d.ts +31 -0
- package/dist/navigation/transitionBindings.js +106 -0
- package/dist/navigation/transitionChrome.d.ts +31 -0
- package/dist/navigation/transitionChrome.js +380 -0
- package/dist/navigation/transitionPose.d.ts +52 -0
- package/dist/navigation/transitionPose.js +295 -0
- package/dist/navigation/types.d.ts +133 -0
- package/dist/navigation/types.js +1 -0
- package/dist/navigation/zoomDrag.d.ts +3 -0
- package/dist/navigation/zoomDrag.js +125 -0
- package/dist/navigation/zoomGeometry.d.ts +48 -0
- package/dist/navigation/zoomGeometry.js +94 -0
- package/dist/navigation/zoomGlass.d.ts +27 -0
- package/dist/navigation/zoomGlass.js +64 -0
- package/dist/navigation/zoomMotion.d.ts +73 -0
- package/dist/navigation/zoomMotion.js +104 -0
- package/dist/navigation/zoomTransition.d.ts +82 -0
- package/dist/navigation/zoomTransition.js +975 -0
- package/dist/presentation/Presentation.d.ts +61 -0
- package/dist/presentation/Presentation.js +92 -0
- package/dist/presentation/PresentationSurface.d.ts +29 -0
- package/dist/presentation/PresentationSurface.js +586 -0
- package/dist/presentation/PresentedSheet.d.ts +2 -0
- package/dist/presentation/PresentedSheet.js +571 -0
- package/dist/presentation/activity.d.ts +3 -0
- package/dist/presentation/activity.js +24 -0
- package/dist/presentation/coldLaunch.d.ts +2 -0
- package/dist/presentation/coldLaunch.js +19 -0
- package/dist/presentation/dismiss.d.ts +26 -0
- package/dist/presentation/dismiss.js +30 -0
- package/dist/presentation/glassMotion.d.ts +39 -0
- package/dist/presentation/glassMotion.js +259 -0
- package/dist/presentation/glassReady.d.ts +11 -0
- package/dist/presentation/glassReady.js +246 -0
- package/dist/presentation/model.d.ts +108 -0
- package/dist/presentation/model.js +183 -0
- package/dist/presentation/motion.d.ts +56 -0
- package/dist/presentation/motion.js +263 -0
- package/dist/presentation/presentationMotion.d.ts +10 -0
- package/dist/presentation/presentationMotion.js +74 -0
- package/dist/presentation/presentationSource.d.ts +2 -0
- package/dist/presentation/presentationSource.js +28 -0
- package/dist/presentation/sheetChromeContext.d.ts +2 -0
- package/dist/presentation/sheetChromeContext.js +3 -0
- package/dist/presentation/sheetMaterialTransition.d.ts +14 -0
- package/dist/presentation/sheetMaterialTransition.js +33 -0
- package/dist/presentation/sheetReleaseMotion.d.ts +18 -0
- package/dist/presentation/sheetReleaseMotion.js +123 -0
- package/dist/presentation/useAlertKeyboardMotion.d.ts +8 -0
- package/dist/presentation/useAlertKeyboardMotion.js +104 -0
- package/dist/press/Pressable.d.ts +19 -0
- package/dist/press/Pressable.js +16 -0
- package/dist/press/activation.d.ts +20 -0
- package/dist/press/activation.js +28 -0
- package/dist/press/contactReceipt.d.ts +23 -0
- package/dist/press/contactReceipt.js +177 -0
- package/dist/press/gestureArbitration.d.ts +13 -0
- package/dist/press/gestureArbitration.js +38 -0
- package/dist/press/stateMachine.d.ts +29 -0
- package/dist/press/stateMachine.js +39 -0
- package/dist/press/tokens.d.ts +18 -0
- package/dist/press/tokens.js +19 -0
- package/dist/press/usePressInteraction.d.ts +30 -0
- package/dist/press/usePressInteraction.js +247 -0
- package/dist/public/Label.d.ts +16 -0
- package/dist/public/Label.js +40 -0
- package/dist/public/NativeFilePicker.d.ts +19 -0
- package/dist/public/NativeFilePicker.js +75 -0
- package/dist/public/Screen.d.ts +42 -0
- package/dist/public/Screen.js +87 -0
- package/dist/public/actions.d.ts +16 -0
- package/dist/public/actions.js +15 -0
- package/dist/public/buttonBorderShape.d.ts +7 -0
- package/dist/public/buttonBorderShape.js +9 -0
- package/dist/public/chrome.d.ts +3 -0
- package/dist/public/chrome.js +5 -0
- package/dist/public/colors.d.ts +29 -0
- package/dist/public/colors.js +28 -0
- package/dist/public/context.d.ts +19 -0
- package/dist/public/context.js +8 -0
- package/dist/public/controlStyle.d.ts +93 -0
- package/dist/public/controlStyle.js +52 -0
- package/dist/public/controls.d.ts +360 -0
- package/dist/public/controls.js +301 -0
- package/dist/public/definition.d.ts +65 -0
- package/dist/public/definition.js +58 -0
- package/dist/public/deviceActions.d.ts +23 -0
- package/dist/public/deviceActions.js +87 -0
- package/dist/public/environment.d.ts +77 -0
- package/dist/public/environment.js +171 -0
- package/dist/public/fieldContext.d.ts +2 -0
- package/dist/public/fieldContext.js +3 -0
- package/dist/public/filePickers.d.ts +25 -0
- package/dist/public/filePickers.js +11 -0
- package/dist/public/glass.d.ts +31 -0
- package/dist/public/glass.js +29 -0
- package/dist/public/glassValue.d.ts +19 -0
- package/dist/public/glassValue.js +32 -0
- package/dist/public/keyboard.d.ts +4 -0
- package/dist/public/keyboard.js +6 -0
- package/dist/public/navigationTransition.d.ts +48 -0
- package/dist/public/navigationTransition.js +49 -0
- package/dist/public/pickerNavigation.d.ts +7 -0
- package/dist/public/pickerNavigation.js +64 -0
- package/dist/public/presentation.d.ts +40 -0
- package/dist/public/presentation.js +21 -0
- package/dist/public/presentationContext.d.ts +2 -0
- package/dist/public/presentationContext.js +3 -0
- package/dist/public/routeRegistry.d.ts +3 -0
- package/dist/public/routeRegistry.js +10 -0
- package/dist/public/routes.d.ts +74 -0
- package/dist/public/routes.js +105 -0
- package/dist/public/runtime.d.ts +134 -0
- package/dist/public/runtime.js +292 -0
- package/dist/public/screenChrome.d.ts +91 -0
- package/dist/public/screenChrome.js +187 -0
- package/dist/public/scroll.d.ts +38 -0
- package/dist/public/scroll.js +7 -0
- package/dist/public/storage.d.ts +9 -0
- package/dist/public/storage.js +9 -0
- package/dist/public/structure.d.ts +65 -0
- package/dist/public/structure.js +40 -0
- package/dist/public/toolbar.d.ts +37 -0
- package/dist/public/toolbar.js +76 -0
- package/dist/push/PushPermissionExplainer.d.ts +14 -0
- package/dist/push/PushPermissionExplainer.js +30 -0
- package/dist/push/notifications.d.ts +54 -0
- package/dist/push/notifications.js +276 -0
- package/dist/push/routes.d.ts +20 -0
- package/dist/push/routes.js +63 -0
- package/dist/push/schema.d.ts +42 -0
- package/dist/push/schema.js +41 -0
- package/dist/push/urlProjection.d.ts +24 -0
- package/dist/push/urlProjection.js +207 -0
- package/dist/reachability/controller.d.ts +21 -0
- package/dist/reachability/controller.js +202 -0
- package/dist/reachability/model.d.ts +94 -0
- package/dist/reachability/model.js +131 -0
- package/dist/reachability/react.d.ts +29 -0
- package/dist/reachability/react.js +69 -0
- package/dist/restoration/navigation.d.ts +9 -0
- package/dist/restoration/navigation.js +55 -0
- package/dist/restoration/react.d.ts +6 -0
- package/dist/restoration/react.js +21 -0
- package/dist/restoration/routes.d.ts +22 -0
- package/dist/restoration/routes.js +166 -0
- package/dist/restoration/scene.d.ts +44 -0
- package/dist/restoration/scene.js +284 -0
- package/dist/root/SatinRoot.d.ts +25 -0
- package/dist/root/SatinRoot.js +512 -0
- package/dist/root/mountSatin.d.ts +12 -0
- package/dist/root/mountSatin.js +60 -0
- package/dist/root/runtimeContext.d.ts +26 -0
- package/dist/root/runtimeContext.js +30 -0
- package/dist/safe-area/Overlay.d.ts +9 -0
- package/dist/safe-area/Overlay.js +26 -0
- package/dist/safe-area/SafeAreaInset.d.ts +25 -0
- package/dist/safe-area/SafeAreaInset.js +138 -0
- package/dist/safe-area/bottomInsetGeometry.d.ts +12 -0
- package/dist/safe-area/bottomInsetGeometry.js +73 -0
- package/dist/safe-area/context.d.ts +15 -0
- package/dist/safe-area/context.js +8 -0
- package/dist/safe-area/displayCorners.d.ts +21 -0
- package/dist/safe-area/displayCorners.js +70 -0
- package/dist/safe-area/keyboardCarrier.d.ts +26 -0
- package/dist/safe-area/keyboardCarrier.js +394 -0
- package/dist/safe-area/keyboardCarrierGeometry.d.ts +37 -0
- package/dist/safe-area/keyboardCarrierGeometry.js +49 -0
- package/dist/safe-area/modifiers.d.ts +52 -0
- package/dist/safe-area/modifiers.js +86 -0
- package/dist/safe-area/useSafeAreaMetrics.d.ts +83 -0
- package/dist/safe-area/useSafeAreaMetrics.js +367 -0
- package/dist/safe-area/windowChrome.d.ts +7 -0
- package/dist/safe-area/windowChrome.js +14 -0
- package/dist/scroll/RefreshControl.d.ts +8 -0
- package/dist/scroll/RefreshControl.js +135 -0
- package/dist/scroll/ScrollSurface.d.ts +62 -0
- package/dist/scroll/ScrollSurface.js +278 -0
- package/dist/scroll/ScrollTarget.d.ts +6 -0
- package/dist/scroll/ScrollTarget.js +11 -0
- package/dist/scroll/edgePolicy.d.ts +21 -0
- package/dist/scroll/edgePolicy.js +17 -0
- package/dist/scroll/insertionMotion.d.ts +15 -0
- package/dist/scroll/insertionMotion.js +128 -0
- package/dist/scroll/nativeScroll.d.ts +14 -0
- package/dist/scroll/nativeScroll.js +71 -0
- package/dist/scroll/position.d.ts +31 -0
- package/dist/scroll/position.js +273 -0
- package/dist/scroll/pressOwnership.d.ts +4 -0
- package/dist/scroll/pressOwnership.js +65 -0
- package/dist/scroll/refreshMotion.d.ts +9 -0
- package/dist/scroll/refreshMotion.js +15 -0
- package/dist/scroll/refreshable.d.ts +6 -0
- package/dist/scroll/refreshable.js +50 -0
- package/dist/scroll/registry.d.ts +38 -0
- package/dist/scroll/registry.js +261 -0
- package/dist/scroll/screenGeometry.d.ts +8 -0
- package/dist/scroll/screenGeometry.js +50 -0
- package/dist/scroll/scrollIndicator.d.ts +7 -0
- package/dist/scroll/scrollIndicator.js +114 -0
- package/dist/scroll/scrollJump.d.ts +7 -0
- package/dist/scroll/scrollJump.js +16 -0
- package/dist/scroll/types.d.ts +12 -0
- package/dist/scroll/types.js +1 -0
- package/dist/search/SearchDrawer.d.ts +16 -0
- package/dist/search/SearchDrawer.js +421 -0
- package/dist/search/SearchScopesBar.d.ts +6 -0
- package/dist/search/SearchScopesBar.js +12 -0
- package/dist/search/SearchToolbarField.d.ts +8 -0
- package/dist/search/SearchToolbarField.js +115 -0
- package/dist/search/searchBackdrop.d.ts +12 -0
- package/dist/search/searchBackdrop.js +45 -0
- package/dist/search/searchChrome.d.ts +13 -0
- package/dist/search/searchChrome.js +31 -0
- package/dist/search/searchMotion.d.ts +30 -0
- package/dist/search/searchMotion.js +46 -0
- package/dist/search/searchPlacement.d.ts +11 -0
- package/dist/search/searchPlacement.js +15 -0
- package/dist/search/searchable.d.ts +46 -0
- package/dist/search/searchable.js +5 -0
- package/dist/search/useSearchPresentation.d.ts +15 -0
- package/dist/search/useSearchPresentation.js +61 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +144 -0
- package/dist/settings/DisclosureIndicator.d.ts +4 -0
- package/dist/settings/DisclosureIndicator.js +6 -0
- package/dist/settings/tokens.d.ts +129 -0
- package/dist/settings/tokens.js +143 -0
- package/dist/shapes/corners.d.ts +14 -0
- package/dist/shapes/corners.js +80 -0
- package/dist/styles.css +9078 -0
- package/dist/styles.css.d.ts +3 -0
- package/dist/sw/activationState.d.ts +20 -0
- package/dist/sw/activationState.js +39 -0
- package/dist/sw/generator.d.ts +14 -0
- package/dist/sw/generator.js +26 -0
- package/dist/sw/manifest.d.ts +32 -0
- package/dist/sw/manifest.js +137 -0
- package/dist/sw/protocol.d.ts +7 -0
- package/dist/sw/protocol.js +7 -0
- package/dist/sw/pushRuntime.d.ts +2 -0
- package/dist/sw/pushRuntime.js +161 -0
- package/dist/sw/registerAppShell.d.ts +25 -0
- package/dist/sw/registerAppShell.js +259 -0
- package/dist/sw/renderServiceWorker.d.ts +10 -0
- package/dist/sw/renderServiceWorker.js +370 -0
- package/dist/sw/requestRouting.d.ts +13 -0
- package/dist/sw/requestRouting.js +26 -0
- package/dist/sw/updateCheck.d.ts +2 -0
- package/dist/sw/updateCheck.js +25 -0
- package/dist/sw/vite.d.ts +20 -0
- package/dist/sw/vite.js +71 -0
- package/dist/symbols/Symbol.d.ts +33 -0
- package/dist/symbols/Symbol.js +59 -0
- package/dist/symbols/catalogue.d.ts +4 -0
- package/dist/symbols/catalogue.js +4139 -0
- package/dist/symbols/exclusions.d.ts +2 -0
- package/dist/symbols/exclusions.js +4 -0
- package/dist/symbols/inheritedWeight.d.ts +3 -0
- package/dist/symbols/inheritedWeight.js +104 -0
- package/dist/symbols/metrics.d.ts +38 -0
- package/dist/symbols/metrics.js +53 -0
- package/dist/symbols/svg.d.ts +3 -0
- package/dist/symbols/svg.js +16 -0
- package/dist/symbols/types.d.ts +30 -0
- package/dist/symbols/types.js +1 -0
- package/dist/tabs/TabSection.d.ts +12 -0
- package/dist/tabs/TabSection.js +4 -0
- package/dist/tabs/TabSidebarSurface.d.ts +7 -0
- package/dist/tabs/TabSidebarSurface.js +29 -0
- package/dist/tabs/TabView.d.ts +28 -0
- package/dist/tabs/TabView.js +258 -0
- package/dist/tabs/accessoryContact.d.ts +2 -0
- package/dist/tabs/accessoryContact.js +42 -0
- package/dist/tabs/compactBar.d.ts +4 -0
- package/dist/tabs/compactBar.js +28 -0
- package/dist/tabs/context.d.ts +8 -0
- package/dist/tabs/context.js +6 -0
- package/dist/tabs/keyboard.d.ts +3 -0
- package/dist/tabs/keyboard.js +23 -0
- package/dist/tabs/model.d.ts +6 -0
- package/dist/tabs/model.js +16 -0
- package/dist/tabs/presentation.d.ts +7 -0
- package/dist/tabs/presentation.js +14 -0
- package/dist/tabs/sourceRevision.d.ts +3 -0
- package/dist/tabs/sourceRevision.js +36 -0
- package/dist/tabs/tabSidebarGlyph.d.ts +2 -0
- package/dist/tabs/tabSidebarGlyph.js +11 -0
- package/dist/tasks/useTask.d.ts +16 -0
- package/dist/tasks/useTask.js +67 -0
- package/dist/testing.d.ts +9 -0
- package/dist/testing.js +11 -0
- package/dist/text-input/TextEditor.d.ts +25 -0
- package/dist/text-input/TextEditor.js +74 -0
- package/dist/text-input/TextField.d.ts +32 -0
- package/dist/text-input/TextField.js +29 -0
- package/dist/text-input/editorGeometry.d.ts +2 -0
- package/dist/text-input/editorGeometry.js +6 -0
- package/dist/text-input/editorTextLayout.d.ts +2 -0
- package/dist/text-input/editorTextLayout.js +31 -0
- package/dist/text-input/focusChain.d.ts +27 -0
- package/dist/text-input/focusChain.js +62 -0
- package/dist/text-input/kinds.d.ts +8 -0
- package/dist/text-input/kinds.js +34 -0
- package/dist/text-input/measureEditor.d.ts +2 -0
- package/dist/text-input/measureEditor.js +50 -0
- package/dist/text-input/submit.d.ts +9 -0
- package/dist/text-input/submit.js +7 -0
- package/dist/unstable.d.ts +16 -0
- package/dist/unstable.js +16 -0
- package/dist/vite.d.ts +3 -0
- package/dist/vite.js +3 -0
- package/dist/web/WebView.d.ts +42 -0
- package/dist/web/WebView.js +115 -0
- package/dist/web/authentication.d.ts +75 -0
- package/dist/web/authentication.js +488 -0
- package/dist/web/openURL.d.ts +37 -0
- package/dist/web/openURL.js +89 -0
- package/dist/web/urlPolicy.d.ts +3 -0
- package/dist/web/urlPolicy.js +19 -0
- package/dist/web/useWebAuthentication.d.ts +3 -0
- package/dist/web/useWebAuthentication.js +6 -0
- package/dist/zoom/Zoomable.d.ts +10 -0
- package/dist/zoom/Zoomable.js +116 -0
- package/dist/zoom/geometry.d.ts +11 -0
- package/dist/zoom/geometry.js +16 -0
- package/package.json +115 -3
|
@@ -0,0 +1,1929 @@
|
|
|
1
|
+
import { SCROLL_INSERTION_MOTION } from '../../scroll/insertionMotion.js';
|
|
2
|
+
import { KEYBOARD_CARRIER_MOTION } from '../../safe-area/keyboardCarrierGeometry.js';
|
|
3
|
+
import { keyboardBackdrop } from './keyboardBackdrop.js';
|
|
4
|
+
import { observeNativeScroll } from '../../scroll/nativeScroll.js';
|
|
5
|
+
import { GLASS_READINESS_BUDGET_MS, VisibleDeadline } from '../visibleDeadline.js';
|
|
6
|
+
import { searchBackdropScroll } from '../../search/searchBackdrop.js';
|
|
7
|
+
import { SupersededImage } from '../../image/resource.js';
|
|
8
|
+
import { atRest, presentationTravel } from '../presentationFrame.js';
|
|
9
|
+
import { watchPresentationBackdrop } from './presentationBackdrop.js';
|
|
10
|
+
import { backdropExclusions } from './backdropLayers.js';
|
|
11
|
+
import { GLASS_SOURCE_DAMAGE_EVENT } from '../sourceDamage.js';
|
|
12
|
+
import { watchRegionBackdrop } from './regionBackdrop.js';
|
|
13
|
+
import { SourcePixels } from './sourcePixels.js';
|
|
14
|
+
import { LENS_REACH_POINTS, captureWindowExhausted, grownExtent, windowCoversScrollport, } from '../captureWindow.js';
|
|
15
|
+
import { glassNow, glassTiming, glassProfile } from './profile.js';
|
|
16
|
+
import { lagMark, lagMarks, lagTraceEnabled, lagTraceRequested, setLagTrace } from './lagTrace.js';
|
|
17
|
+
import { RegionBridge } from './regionBridge.js';
|
|
18
|
+
import { glassFailureCode } from './errorCode.js';
|
|
19
|
+
import { onScrollJump } from '../../scroll/scrollJump.js';
|
|
20
|
+
import { KeptGlyphs } from './keptGlyphs.js';
|
|
21
|
+
import { pinnedTopCovers } from './productionPinnedTop.js';
|
|
22
|
+
import { ResidentPlanes } from './residentPlanes.js';
|
|
23
|
+
import { REGULAR_TRIGGER_MATERIAL, regularTriggerRegime } from '../regularTriggerMaterial.js';
|
|
24
|
+
import { WebGPUClient } from './client.js';
|
|
25
|
+
import { reportGlassError, getGlassErrors } from '../errors.js';
|
|
26
|
+
import { createRenderSpecs, } from '../renderSpecs.js';
|
|
27
|
+
import { readScrollEdges } from './scrollEdgeBackdrop.js';
|
|
28
|
+
import { sampleMenuMotion } from '../lens/menuMotion.js';
|
|
29
|
+
import { nearestTab } from '../lens/tabMotion.js';
|
|
30
|
+
import { observeNavigationGlass, } from '../../navigation/glassTransition.js';
|
|
31
|
+
import { WorkerMinimize } from './minimize.js';
|
|
32
|
+
import { resumeDebugEnabled, showResumeOverlay } from './resumeOverlay.js';
|
|
33
|
+
import { TabMinimizeIntent } from '../lens/tabMinimizeMotion.js';
|
|
34
|
+
import { MenuSurfaceGuard } from './menuSurfaceGuard.js';
|
|
35
|
+
import { TRIGGER_CONTEXT_X, TRIGGER_CONTEXT_Y, } from './productionPlanes.js';
|
|
36
|
+
import { prepareSources } from './productionPrepare.js';
|
|
37
|
+
import { uncoveredSourceRows } from './captureBands.js';
|
|
38
|
+
import { beneathPresentation } from './captureDemand.js';
|
|
39
|
+
import { prepareNavigation } from './productionNavigation.js';
|
|
40
|
+
import { placeCanvas } from './productionViewport.js';
|
|
41
|
+
/** Last scroll anywhere in the document (capture listener, installed once). */
|
|
42
|
+
const SCROLL_IDLE_MS = 150;
|
|
43
|
+
/** Visible time a held menu run may wait for its surface to be installed and acknowledged before the missing glass is an error. */
|
|
44
|
+
const MENU_SURFACE_BUDGET_MS = 10000;
|
|
45
|
+
/** A navigator transition (any layout, including split panes), a presentation in motion
|
|
46
|
+
* (entrance, drag, release) or the bottom inset chain following the keyboard. Backdrop captures are deferred until it settles: a capture of a
|
|
47
|
+
* moving scene is stale by the time it uploads, and it would run on the main thread in the
|
|
48
|
+
* frames that start the motion. Presented menu morphs use the same policy; a pending
|
|
49
|
+
* menu still needs its initial capture. Glass over motion samples the installed planes. */
|
|
50
|
+
const sceneInMotion = (host) => !!document.querySelector('[data-satin-transition-active="true"],[data-satin-presentation-moving],[data-satin-keyboard-moving],' +
|
|
51
|
+
'[data-satin-menu-phase="closing"],' +
|
|
52
|
+
'[data-satin-menu-phase="open"][data-satin-menu-rows="glass"]') || !!host?.hasAttribute('data-satin-search-moving');
|
|
53
|
+
/** Resident bytes for covered routes' and unselected tabs' captures (image + texture each) and
|
|
54
|
+
* cached material context readbacks. Sized so that a phone keeps the planes of a tab bar's other
|
|
55
|
+
* tabs when one of them is a long list: a grown capture window (1320 x 8192 px, 43 MB, 86 MB
|
|
56
|
+
* resident) and three single-viewport planes (15 MB, 30 MB resident each). With the 80 MB this
|
|
57
|
+
* replaced, a long list's plane was dropped whenever its tab was left, and entering that tab
|
|
58
|
+
* again showed its content 1.8 times later than any other tab's (100 ms against 56 ms in the
|
|
59
|
+
* Catalyst host; 59 ms with everything resident). Those planes are 148 MB (149 MB with a list
|
|
60
|
+
* at the canvas ceiling); the rest is for the material contexts they made (2 to 5 MB each, a few
|
|
61
|
+
* per tab): at 160 MB they fitted with 0.4 MB to spare, and once a context was a little larger
|
|
62
|
+
* every return from the list tab recomposed one that had just been evicted. It is a ceiling, not
|
|
63
|
+
* an allocation: an app whose tabs are single viewports keeps about 30 MB per tab. See
|
|
64
|
+
* ResidentPlanes. */
|
|
65
|
+
export const RESIDENT_BYTES = 176e6;
|
|
66
|
+
/** An entry window grows once the scene has been idle this long after its capture: late enough
|
|
67
|
+
* for the tab bar's selection travel (about 520 ms) to have ended. */
|
|
68
|
+
const WINDOW_GROW_IDLE_MS = 700;
|
|
69
|
+
/** A scroll speed older than this is no longer a speed (the scroll has stopped). */
|
|
70
|
+
const SCROLL_SPEED_STALE_MS = 120;
|
|
71
|
+
/** Longest a region refresh waits for a capture of rows its glass newly samples. Past it the scene
|
|
72
|
+
* is sent anyway and the renderer reports the uncovered sample as a GlassError. */
|
|
73
|
+
/** Pointers that are down, and since when: a touch may start a scroll, so an entry window does
|
|
74
|
+
* not grow under one. A pointer whose release was never seen stops counting after a while. */
|
|
75
|
+
const pointersDown = new Map();
|
|
76
|
+
const POINTER_HELD_STALE_MS = 15000;
|
|
77
|
+
if (typeof document !== 'undefined') {
|
|
78
|
+
const release = (event) => pointersDown.delete(event.pointerId);
|
|
79
|
+
document.addEventListener('pointerdown', event => pointersDown.set(event.pointerId, performance.now()), { capture: true, passive: true });
|
|
80
|
+
document.addEventListener('pointerup', release, { capture: true, passive: true });
|
|
81
|
+
document.addEventListener('pointercancel', release, { capture: true, passive: true });
|
|
82
|
+
}
|
|
83
|
+
const pointerHeld = () => {
|
|
84
|
+
const now = performance.now();
|
|
85
|
+
for (const [id, since] of pointersDown) {
|
|
86
|
+
if (now - since < POINTER_HELD_STALE_MS)
|
|
87
|
+
return true;
|
|
88
|
+
pointersDown.delete(id);
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
};
|
|
92
|
+
/** App-lifetime worker. Reuses the semantic controls and measured geometry.
|
|
93
|
+
*
|
|
94
|
+
* Source preparation (productionPrepare.ts) and navigation glass (productionNavigation.ts) are
|
|
95
|
+
* functions over this runtime; members they use carry no access modifier. None of it is public API. */
|
|
96
|
+
export class ProductionGlassRuntime {
|
|
97
|
+
static shared;
|
|
98
|
+
client = new WebGPUClient();
|
|
99
|
+
sourcePixels = new SourcePixels();
|
|
100
|
+
/** A source staging whose upload worker failed (its GPU device was lost, or a reply never came)
|
|
101
|
+
* stays failed. The bounded retry of a preparation replaces it, so glass recovers without a
|
|
102
|
+
* reload: the failed instance rejected its own jobs when it failed and terminated its worker,
|
|
103
|
+
* so nothing of it can reach the replacement. */
|
|
104
|
+
replaceFailedSourcePixels() {
|
|
105
|
+
if (this.sourcePixels.failed)
|
|
106
|
+
this.sourcePixels = new SourcePixels();
|
|
107
|
+
}
|
|
108
|
+
appRegions;
|
|
109
|
+
options;
|
|
110
|
+
canvas;
|
|
111
|
+
liftCanvas = document.createElement('canvas');
|
|
112
|
+
/** The menu trigger's lift presents on its own small canvas, apart from the dock's band. */
|
|
113
|
+
menuLiftCanvas = document.createElement('canvas');
|
|
114
|
+
/** The menu surface's own canvas, sized to its envelope. On one full-screen chrome canvas with
|
|
115
|
+
* the dock, every glass frame presented a whole-screen drawable, which WebKit commits from the
|
|
116
|
+
* worker slowly enough to block the worker thread (0-27 ms message delays on iPadOS 27 while
|
|
117
|
+
* scrolling: glass at ~40 Hz). Each chrome canvas now covers only what it draws. */
|
|
118
|
+
menuCanvas = document.createElement('canvas');
|
|
119
|
+
/** Installed lift canvas extents, [x,y,w,h] CSS px: a band around each lift, never the full screen. */
|
|
120
|
+
liftViewports = new Map();
|
|
121
|
+
liftAttached = false;
|
|
122
|
+
specs = new Map();
|
|
123
|
+
context;
|
|
124
|
+
revision = 0;
|
|
125
|
+
transportRevision = 0;
|
|
126
|
+
serial = Promise.resolve();
|
|
127
|
+
attached = true;
|
|
128
|
+
damageFrame = 0;
|
|
129
|
+
pendingDamage = new Map();
|
|
130
|
+
observer;
|
|
131
|
+
/** Scroll-edge strength/visibility changes (scroll-driven styles, excluded from damage). */
|
|
132
|
+
edgeObserver;
|
|
133
|
+
edgeFrame = 0;
|
|
134
|
+
installedEdges = '';
|
|
135
|
+
resize;
|
|
136
|
+
unsubscribeAppearance;
|
|
137
|
+
unsubscribe;
|
|
138
|
+
navigationObserver;
|
|
139
|
+
navigationInput;
|
|
140
|
+
navigationFrame = 0;
|
|
141
|
+
navigationRevision = 0;
|
|
142
|
+
appearanceInstall;
|
|
143
|
+
/** Holds the outgoing painted frame until the new tab's complete source/scene is installed. */
|
|
144
|
+
contentInstall;
|
|
145
|
+
prepareFrame = 0;
|
|
146
|
+
menuPointer;
|
|
147
|
+
pointer = false;
|
|
148
|
+
pointerX = 0;
|
|
149
|
+
pointerStart = 0;
|
|
150
|
+
pointerIndex = 0;
|
|
151
|
+
minimize = new TabMinimizeIntent();
|
|
152
|
+
minimizeDom;
|
|
153
|
+
navigationRoutes = [];
|
|
154
|
+
navigationActive = false;
|
|
155
|
+
navigationState;
|
|
156
|
+
navigationCoveragePreparation;
|
|
157
|
+
navigationAnimations;
|
|
158
|
+
navigationRelease;
|
|
159
|
+
navigationCoverage;
|
|
160
|
+
events = [];
|
|
161
|
+
record(event) {
|
|
162
|
+
this.events.push(event);
|
|
163
|
+
if (this.events.length > 300)
|
|
164
|
+
this.events.shift();
|
|
165
|
+
}
|
|
166
|
+
regionIds = new Map();
|
|
167
|
+
// Source pipeline state. Canvases are reused across revisions: every capture is
|
|
168
|
+
// copied into its ImageBitmap at creation, so reuse never aliases a sent image.
|
|
169
|
+
sourceCanvas = document.createElement('canvas');
|
|
170
|
+
glyphCanvases = new Map();
|
|
171
|
+
atlasCanvas = document.createElement('canvas');
|
|
172
|
+
atlasGlyphs = document.createElement('canvas');
|
|
173
|
+
/** Pixel identity of the capture installed in the worker's `content` slot. */
|
|
174
|
+
installedSource;
|
|
175
|
+
/** Installed backdrop planes by id: capture signature and worker image key. */
|
|
176
|
+
planes = new Map();
|
|
177
|
+
planeIds = new WeakMap();
|
|
178
|
+
nextPlane = 0;
|
|
179
|
+
/** Each plane's main-thread capture canvas and the signature it currently holds. */
|
|
180
|
+
planeCanvases = new Map();
|
|
181
|
+
/** Planes that left the set (a route covered by a push) but stay resident in the worker, so a
|
|
182
|
+
* pop back composes from them: no raster, bitmap, transfer or upload at the end of the pop. */
|
|
183
|
+
resident = new ResidentPlanes(RESIDENT_BYTES);
|
|
184
|
+
planeBytes = new Map();
|
|
185
|
+
/** Installed planes with DOM damage since their capture (a pending, possibly deferred, preparation):
|
|
186
|
+
* a navigation atlas never copies them from the GPU. */
|
|
187
|
+
damaged = new Set();
|
|
188
|
+
/** The material context is composed here (its read areas are kept by the context). */
|
|
189
|
+
contextCanvas = document.createElement('canvas');
|
|
190
|
+
/** Sample rectangles of every glass surface and region, read once per preparation when first
|
|
191
|
+
* needed: what a plane that does not scroll is captured for (captureDemand.ts). */
|
|
192
|
+
captureDemand = () => [];
|
|
193
|
+
/** Region refreshes waiting for a capture that covers their glass (`coverFor`). */
|
|
194
|
+
coverageWaiters = [];
|
|
195
|
+
/** Content changes do not cancel a preparation; its commit only clears damage it captured. */
|
|
196
|
+
damageGenerations = new Map();
|
|
197
|
+
/** Include newly discovered planes while their first capture is still in flight. */
|
|
198
|
+
preparingPlaneHosts = new Map();
|
|
199
|
+
preparingPinnedWindows = new Map();
|
|
200
|
+
preparingPlaneWindows = new Map();
|
|
201
|
+
lastText;
|
|
202
|
+
/** Last scroll inside this scene (its planes and scroller), for the scroll-idle capture hold. */
|
|
203
|
+
lastScrollAt = -Infinity;
|
|
204
|
+
scrolled = () => {
|
|
205
|
+
this.lastScrollAt = performance.now();
|
|
206
|
+
};
|
|
207
|
+
scrollScopes = [];
|
|
208
|
+
coveredSince = 0;
|
|
209
|
+
coveredRetry = 0;
|
|
210
|
+
scrollIdle = 0;
|
|
211
|
+
/** Scroll listeners of the committed planes (the navigation scroller reports through `scroll`). */
|
|
212
|
+
planeScrolls = new Map();
|
|
213
|
+
scrollerPlane;
|
|
214
|
+
/** Plane that holds the navigation source (navigation motion and route atlases apply to it). */
|
|
215
|
+
contentPlane;
|
|
216
|
+
planeId(host) {
|
|
217
|
+
let id = this.planeIds.get(host);
|
|
218
|
+
if (!id) {
|
|
219
|
+
id = `plane-${++this.nextPlane}`;
|
|
220
|
+
this.planeIds.set(host, id);
|
|
221
|
+
}
|
|
222
|
+
if (this.preparing)
|
|
223
|
+
this.preparingPlaneHosts.set(id, host);
|
|
224
|
+
return id;
|
|
225
|
+
}
|
|
226
|
+
captureRevision = 0;
|
|
227
|
+
/** Loaded fonts change ink even when the computed CSS font and size are unchanged. */
|
|
228
|
+
fontGeneration = 0;
|
|
229
|
+
navigationCapture = 0;
|
|
230
|
+
navigationGlyphs = 0;
|
|
231
|
+
installedNavigation;
|
|
232
|
+
fontsChanged = () => this.damageFontSources();
|
|
233
|
+
damageFontSources() {
|
|
234
|
+
this.fontGeneration++;
|
|
235
|
+
const ids = new Set([
|
|
236
|
+
...this.planes.keys(),
|
|
237
|
+
...this.preparingPlaneHosts.keys(),
|
|
238
|
+
...this.pinnedTops.keys(),
|
|
239
|
+
]);
|
|
240
|
+
for (const id of ids)
|
|
241
|
+
this.markPlaneDamaged(id);
|
|
242
|
+
this.dropRetained();
|
|
243
|
+
// Ink kept from before the fonts loaded was drawn with the fallback font.
|
|
244
|
+
this.keptGlyphs.reset();
|
|
245
|
+
this.invalidatePinnedTops([...ids]);
|
|
246
|
+
this.schedulePrepare();
|
|
247
|
+
}
|
|
248
|
+
/** Forget every retained plane (and cached context) here and in the worker. */
|
|
249
|
+
dropRetained() {
|
|
250
|
+
const keys = this.resident.clear().map(key => `${key}:front`);
|
|
251
|
+
if (keys.length)
|
|
252
|
+
this.fire({
|
|
253
|
+
type: 'source-images',
|
|
254
|
+
revision: this.nextTransport(),
|
|
255
|
+
images: [],
|
|
256
|
+
unretain: keys,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/** Chrome glyph images installed in the worker's `glyph:<id>` slots. */
|
|
260
|
+
glyphs = new Map();
|
|
261
|
+
glyphRevision = 0;
|
|
262
|
+
/** Glyph ink the renderer keeps for reuse after its slot took other ink. */
|
|
263
|
+
keptGlyphs = new KeptGlyphs();
|
|
264
|
+
/** Surfaces whose new ink the last preparation put off by one revision (inkForRevision). */
|
|
265
|
+
deferredInk = new Set();
|
|
266
|
+
/** Each long list's capture of its top, kept while its own window is further down
|
|
267
|
+
* (productionPinnedTop.ts): a jump to the top lands on it. */
|
|
268
|
+
pinnedTops = new Map();
|
|
269
|
+
/** The image of each installed plane capture that was read back in this document: its bytes
|
|
270
|
+
* are still on the page, so the rows of a window that leaves the top can be kept. */
|
|
271
|
+
planeImages = new Map();
|
|
272
|
+
/** Pinned-top slots the renderer may still hold after a failed batch: released by the next. */
|
|
273
|
+
pinnedOrphans = new Set();
|
|
274
|
+
unsubscribeRegionBackdrop;
|
|
275
|
+
unsubscribePresentationBackdrop;
|
|
276
|
+
unsubscribeScrollJump;
|
|
277
|
+
unsubscribeNativeScroll;
|
|
278
|
+
/** Everything the last committed preparation sent; equal means nothing to send. */
|
|
279
|
+
preparedSignature = '';
|
|
280
|
+
contextGeometry = '';
|
|
281
|
+
incompleteCaptures = new Map();
|
|
282
|
+
menuTracks = new Map();
|
|
283
|
+
preparing;
|
|
284
|
+
prepareAgain = false;
|
|
285
|
+
resumePending = false;
|
|
286
|
+
lifecycleHidden = false;
|
|
287
|
+
resumeAt = 0;
|
|
288
|
+
resumeFrame = 0;
|
|
289
|
+
constructor(options) {
|
|
290
|
+
this.client.deferResume = true;
|
|
291
|
+
this.appRegions = new RegionBridge(this.client, options.appearance);
|
|
292
|
+
this.appRegions.coverage = rects => this.coverFor(rects);
|
|
293
|
+
this.options = options;
|
|
294
|
+
this.owner = options;
|
|
295
|
+
this.canvas = options.elements.band.canvas;
|
|
296
|
+
ProductionGlassRuntime.ownMenuShadow(options);
|
|
297
|
+
}
|
|
298
|
+
/** The menu kernel draws the menu's shadow (fitted to native, bounded by the drawable top);
|
|
299
|
+
* the DOM shadow plate would draw a second, larger one. */
|
|
300
|
+
static ownMenuShadow(options) {
|
|
301
|
+
if (options.elements.menu)
|
|
302
|
+
options.elements.menu.shadow.hidden = true;
|
|
303
|
+
}
|
|
304
|
+
static async create(options) {
|
|
305
|
+
if (this.shared) {
|
|
306
|
+
const runtime = await this.shared;
|
|
307
|
+
runtime.rebind(options);
|
|
308
|
+
await runtime.prepare();
|
|
309
|
+
return runtime;
|
|
310
|
+
}
|
|
311
|
+
this.shared = (async () => {
|
|
312
|
+
const runtime = new ProductionGlassRuntime(options);
|
|
313
|
+
try {
|
|
314
|
+
await runtime.initialize();
|
|
315
|
+
return runtime;
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
// A rejected create never reaches the React owner's cleanup. Retire its
|
|
319
|
+
// listeners and captures here before a release app mounts CSS material.
|
|
320
|
+
runtime.dispose(options);
|
|
321
|
+
throw error;
|
|
322
|
+
}
|
|
323
|
+
})();
|
|
324
|
+
return this.shared;
|
|
325
|
+
}
|
|
326
|
+
fail(stage, error, rebuilding = false) {
|
|
327
|
+
const reported = reportGlassError(glassFailureCode(stage, error), error, stage, undefined, {
|
|
328
|
+
recovering: rebuilding,
|
|
329
|
+
});
|
|
330
|
+
if (!reported.transient)
|
|
331
|
+
this.options.onPresentationError?.(error, rebuilding);
|
|
332
|
+
}
|
|
333
|
+
send(request, transfer = []) {
|
|
334
|
+
return this.client.request(request, transfer);
|
|
335
|
+
}
|
|
336
|
+
fire(request) {
|
|
337
|
+
void this.send(request).catch(error => this.fail(request.type, error));
|
|
338
|
+
}
|
|
339
|
+
async initialize() {
|
|
340
|
+
await this.client.init(this.canvas, devicePixelRatio, true, true, () => this.options.currentAppearance?.() ?? this.options.appearance,
|
|
341
|
+
// Renderer placement is independent of retained accessory ink. OffscreenCanvas
|
|
342
|
+
// presentation has a separate WebKit cost and must be measured on its own.
|
|
343
|
+
document.documentElement.hasAttribute('data-satin-experimental-glass-worker')
|
|
344
|
+
? 'worker'
|
|
345
|
+
: 'document');
|
|
346
|
+
if (lagTraceRequested()) {
|
|
347
|
+
setLagTrace(true);
|
|
348
|
+
this.fire({ type: 'lag-trace', enabled: true });
|
|
349
|
+
}
|
|
350
|
+
this.mount();
|
|
351
|
+
await this.client.attachLayer(this.menuCanvas, {
|
|
352
|
+
id: 'menu',
|
|
353
|
+
depth: 1,
|
|
354
|
+
attachment: { kind: 'fixed' },
|
|
355
|
+
});
|
|
356
|
+
await this.client.attachLayer(this.liftCanvas, {
|
|
357
|
+
id: 'chrome-lift',
|
|
358
|
+
depth: 50,
|
|
359
|
+
attachment: { kind: 'fixed' },
|
|
360
|
+
});
|
|
361
|
+
await this.client.attachLayer(this.menuLiftCanvas, {
|
|
362
|
+
id: 'menu-lift',
|
|
363
|
+
depth: 50,
|
|
364
|
+
attachment: { kind: 'fixed' },
|
|
365
|
+
});
|
|
366
|
+
this.liftAttached = true;
|
|
367
|
+
this.bind();
|
|
368
|
+
await document.fonts.ready;
|
|
369
|
+
await this.prepare();
|
|
370
|
+
}
|
|
371
|
+
mount() {
|
|
372
|
+
const { band } = this.options.elements;
|
|
373
|
+
const geometry = this.options.geometry;
|
|
374
|
+
band.rimClip.style.display = 'none';
|
|
375
|
+
band.frame.style.cssText = `position:absolute;left:0;top:0;width:${geometry.width}px;height:${geometry.height}px;pointer-events:none`;
|
|
376
|
+
for (const element of [band.clip, band.base, band.track])
|
|
377
|
+
element.style.cssText =
|
|
378
|
+
'position:absolute;inset:0;overflow:visible;clip-path:none;transform:none';
|
|
379
|
+
this.canvas.style.cssText = `position:absolute;left:0;top:0;width:${geometry.width}px;height:${geometry.height}px;pointer-events:none`;
|
|
380
|
+
this.canvas.dataset.satinWebgpu = 'production';
|
|
381
|
+
// Chrome canvases start as one pixel; each preparation places them on the band their surfaces
|
|
382
|
+
// reach. A remount (geometry change, rebind) keeps the band the worker is drawing for until the
|
|
383
|
+
// next preparation lays it out again: collapsing it here hid the tab bar and menu glass until then
|
|
384
|
+
// (and a preparation waits out any motion in progress).
|
|
385
|
+
const place = (canvas, layerId) => {
|
|
386
|
+
const viewport = this.liftViewports.get(layerId);
|
|
387
|
+
if (!viewport)
|
|
388
|
+
return false;
|
|
389
|
+
placeCanvas(canvas, JSON.parse(viewport));
|
|
390
|
+
return true;
|
|
391
|
+
};
|
|
392
|
+
if (!place(this.canvas, 'chrome'))
|
|
393
|
+
this.canvas.style.width = this.canvas.style.height = '1px';
|
|
394
|
+
this.menuCanvas.style.cssText =
|
|
395
|
+
'position:absolute;left:0;top:0;width:1px;height:1px;pointer-events:none';
|
|
396
|
+
place(this.menuCanvas, 'menu');
|
|
397
|
+
this.menuCanvas.dataset.satinWebgpu = 'menu';
|
|
398
|
+
this.canvas.after(this.menuCanvas);
|
|
399
|
+
// Lift canvases start empty and full-layer; each preparation places them on the band its lift can reach.
|
|
400
|
+
for (const [canvas, kind] of [
|
|
401
|
+
[this.liftCanvas, 'chrome'],
|
|
402
|
+
[this.menuLiftCanvas, 'menu'],
|
|
403
|
+
]) {
|
|
404
|
+
canvas.style.cssText = `position:absolute;left:0;top:0;width:${geometry.width}px;height:${geometry.height}px;pointer-events:none;z-index:50`;
|
|
405
|
+
place(canvas, `${kind}-lift`);
|
|
406
|
+
canvas.dataset.satinGlassLift = kind;
|
|
407
|
+
this.canvas.closest('[data-satin-liquid]')?.append(canvas);
|
|
408
|
+
}
|
|
409
|
+
const shell = this.canvas.closest('[data-satin-liquid]');
|
|
410
|
+
if (shell)
|
|
411
|
+
shell.style.visibility = 'visible';
|
|
412
|
+
this.fire({
|
|
413
|
+
type: 'tab-config',
|
|
414
|
+
centres: geometry.tabBarCentres,
|
|
415
|
+
width: geometry.tabBarPillWidth,
|
|
416
|
+
widths: geometry.tabBarPillWidths,
|
|
417
|
+
height: geometry.tabBarPillHeight,
|
|
418
|
+
centerY: geometry.tabBarPillCenterY,
|
|
419
|
+
dockWidth: geometry.dockWidth,
|
|
420
|
+
placement: geometry.tabBarPlacement,
|
|
421
|
+
selected: geometry.tabBarSelectedIndex ?? 0,
|
|
422
|
+
sharedLift: true,
|
|
423
|
+
reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches,
|
|
424
|
+
});
|
|
425
|
+
if (resumeDebugEnabled())
|
|
426
|
+
showResumeOverlay();
|
|
427
|
+
globalThis.__SATIN_WEBGPU__ = {
|
|
428
|
+
lensDebug: (view) => this.client.request({ type: 'lens-debug', view }),
|
|
429
|
+
profile: glassProfile,
|
|
430
|
+
/** Registered DOM regions, for per-frame ownership probes without GPU readback. */
|
|
431
|
+
regions: () => this.options.regions?.values().map(entry => ({
|
|
432
|
+
id: entry.id,
|
|
433
|
+
toolbarSlot: entry.element.dataset.satinToolbarGlass,
|
|
434
|
+
connected: entry.element.isConnected,
|
|
435
|
+
})) ?? [],
|
|
436
|
+
lagTrace: () => lagMarks(),
|
|
437
|
+
/** Diagnostic readback of a layer canvas ({width, height, pixels}, bottom row first). */
|
|
438
|
+
snapshot: (layerId) => this.client.request({ type: 'snapshot', layerId }),
|
|
439
|
+
report: () => this.client.request({ type: 'report' }),
|
|
440
|
+
/** Resume diagnostics: the minimize transaction and accessory run as the page holds
|
|
441
|
+
* them, and the renderer's tracks and presenters (two presenters for one region would
|
|
442
|
+
* draw one canvas alternately). */
|
|
443
|
+
resume: () => this.resumeReadout(),
|
|
444
|
+
loseDeviceForTest: () => this.client.request({ type: 'lose-context' }),
|
|
445
|
+
forceNullAdaptersForTest: (attempts) => this.client.request({ type: 'force-null-adapters', attempts }),
|
|
446
|
+
status: () => ({
|
|
447
|
+
...this.client.status(),
|
|
448
|
+
attached: this.attached,
|
|
449
|
+
appearance: this.options.appearance,
|
|
450
|
+
revision: this.revision,
|
|
451
|
+
appearanceInstall: this.appearanceInstall,
|
|
452
|
+
preparing: !!this.preparing,
|
|
453
|
+
prepareAgain: this.prepareAgain,
|
|
454
|
+
navigationActive: this.navigationActive,
|
|
455
|
+
lifecycleHidden: this.lifecycleHidden,
|
|
456
|
+
}),
|
|
457
|
+
source: (y) => this.sourceProbe(y),
|
|
458
|
+
errors: () => getGlassErrors().filter(error => !error.transient),
|
|
459
|
+
events: () => this.events,
|
|
460
|
+
diagnosticStage: (stage) => this.client.request({ type: 'stage', stage, level: 0 }),
|
|
461
|
+
trigger: () => this.triggerValues(this.options.elements.scroller.scrollTop),
|
|
462
|
+
/** What planes that do not scroll were last captured for (captureDemand.ts). */
|
|
463
|
+
captureDemand: () => ({
|
|
464
|
+
rects: this.captureDemand(),
|
|
465
|
+
planes: [...this.planes].map(([id, entry]) => ({
|
|
466
|
+
id,
|
|
467
|
+
window: entry.window ?? null,
|
|
468
|
+
bands: entry.bands ?? null,
|
|
469
|
+
covered: beneathPresentation(entry.host),
|
|
470
|
+
scrolls: entry.host.scrollHeight > entry.host.clientHeight + 0.5,
|
|
471
|
+
damaged: this.damaged.has(id),
|
|
472
|
+
})),
|
|
473
|
+
}),
|
|
474
|
+
/** Bounded capture diagnostics: each installed plane's window, recentres and outruns. */
|
|
475
|
+
captureWindows: () => ({
|
|
476
|
+
...this.captureWindows,
|
|
477
|
+
planes: [...this.planes].map(([id, entry]) => ({
|
|
478
|
+
id,
|
|
479
|
+
window: entry.window ?? null,
|
|
480
|
+
height: entry.height,
|
|
481
|
+
pinnedTop: this.pinnedTops.get(id)
|
|
482
|
+
? {
|
|
483
|
+
bottom: this.pinnedTops.get(id).window.bottom,
|
|
484
|
+
stale: this.pinnedTops.get(id).stale,
|
|
485
|
+
}
|
|
486
|
+
: null,
|
|
487
|
+
})),
|
|
488
|
+
}),
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
rebind(options) {
|
|
492
|
+
this.teardown();
|
|
493
|
+
this.owner = options;
|
|
494
|
+
this.resumePending = true;
|
|
495
|
+
options.elements.band.canvas.replaceWith(this.canvas);
|
|
496
|
+
this.options = {
|
|
497
|
+
...options,
|
|
498
|
+
elements: { ...options.elements, band: { ...options.elements.band, canvas: this.canvas } },
|
|
499
|
+
};
|
|
500
|
+
this.attached = true;
|
|
501
|
+
ProductionGlassRuntime.ownMenuShadow(this.options);
|
|
502
|
+
this.mount();
|
|
503
|
+
this.client.resume();
|
|
504
|
+
this.bind();
|
|
505
|
+
// The last region parks the page-lifetime worker. Rebinding is a resume even
|
|
506
|
+
// when the document never hid; use the same retained-frame/appearance path.
|
|
507
|
+
this.handleVisibility();
|
|
508
|
+
}
|
|
509
|
+
bindAppearance() {
|
|
510
|
+
this.unbindAppearance();
|
|
511
|
+
const synchronize = () => {
|
|
512
|
+
this.setAppearance(this.options.currentAppearance?.() ?? this.options.appearance);
|
|
513
|
+
};
|
|
514
|
+
this.unsubscribeAppearance = this.options.subscribeAppearance?.(synchronize);
|
|
515
|
+
synchronize();
|
|
516
|
+
}
|
|
517
|
+
unbindAppearance() {
|
|
518
|
+
this.unsubscribeAppearance?.();
|
|
519
|
+
this.unsubscribeAppearance = undefined;
|
|
520
|
+
}
|
|
521
|
+
bind(retained) {
|
|
522
|
+
this.bindAppearance();
|
|
523
|
+
this.options.elements.menu?.trigger.addEventListener('pointerdown', this.menuDown);
|
|
524
|
+
this.options.elements.menu?.trigger.addEventListener('pointermove', this.menuMove);
|
|
525
|
+
document.addEventListener('pointerup', this.menuUp, true);
|
|
526
|
+
document.addEventListener('pointercancel', this.menuUp, true);
|
|
527
|
+
window.addEventListener('blur', this.menuCancel);
|
|
528
|
+
this.appRegions.bind(this.options.regions, this.options.elements.contentHost);
|
|
529
|
+
window.addEventListener(KEYBOARD_CARRIER_MOTION, this.keyboardGeometry);
|
|
530
|
+
window.addEventListener(SCROLL_INSERTION_MOTION, this.keyboardGeometry);
|
|
531
|
+
this.unsubscribeRegionBackdrop =
|
|
532
|
+
this.options.regions &&
|
|
533
|
+
watchRegionBackdrop(this.options.regions, () => {
|
|
534
|
+
// A held first show is preparation, not motion. Normal scheduling
|
|
535
|
+
// still defers if another screen or presentation is actually moving.
|
|
536
|
+
this.schedulePrepare();
|
|
537
|
+
});
|
|
538
|
+
const host = this.options.elements.scroller;
|
|
539
|
+
this.minimizeDom =
|
|
540
|
+
retained ??
|
|
541
|
+
new WorkerMinimize(this.options, path => this.restoreMinimizingTabBar(path), {
|
|
542
|
+
begin: x => {
|
|
543
|
+
this.tabPointerDown(x, this.options.geometry.tabBarSelectedIndex ?? 0);
|
|
544
|
+
},
|
|
545
|
+
move: x => this.tabPointerMove(x),
|
|
546
|
+
end: cancelled => this.tabPointerUp(cancelled),
|
|
547
|
+
}, track => this.track('dock', track.specs, track.duration, track.at));
|
|
548
|
+
this.unsubscribeNativeScroll = observeNativeScroll(host, snapshot => this.scroll(snapshot.event, snapshot));
|
|
549
|
+
host.addEventListener('satin:search-geometry', this.searchGeometry);
|
|
550
|
+
host.addEventListener('pointerdown', this.begin, { passive: true });
|
|
551
|
+
document.addEventListener('pointerup', this.endContact, true);
|
|
552
|
+
host.addEventListener('scrollend', this.endScrollGesture, { passive: true });
|
|
553
|
+
document.addEventListener('visibilitychange', this.visibility, true);
|
|
554
|
+
window.addEventListener('pagehide', this.visibility, true);
|
|
555
|
+
window.addEventListener('pageshow', this.visibility);
|
|
556
|
+
document.fonts.addEventListener('loadingdone', this.fontsChanged);
|
|
557
|
+
// Every backdrop plane of the scene can hold images (not only the navigation content host):
|
|
558
|
+
// a photo decoding after its plane was captured must recapture it.
|
|
559
|
+
this.loadTarget =
|
|
560
|
+
this.options.elements.contentHost.closest('[data-satin-scene-paint-layer]') ??
|
|
561
|
+
this.options.elements.contentHost;
|
|
562
|
+
this.loadTarget.addEventListener('load', this.sourceLoaded, true);
|
|
563
|
+
this.loadTarget.addEventListener(GLASS_SOURCE_DAMAGE_EVENT, this.sourceLoaded, true);
|
|
564
|
+
// Class/style/src changes can repaint the source without a childList change; the
|
|
565
|
+
// damage key keeps a no-op mutation to one layout measurement.
|
|
566
|
+
// Every plane of the scene can change, not only the navigation source. Chrome, tab bar
|
|
567
|
+
// and scroll-edge updates (scroll-driven styles) are presentation, never backdrop damage.
|
|
568
|
+
const scene = this.options.elements.contentHost.closest('[data-satin-scene-paint-layer]') ??
|
|
569
|
+
this.options.elements.contentHost;
|
|
570
|
+
this.unsubscribePresentationBackdrop = watchPresentationBackdrop(document.body, () => this.schedulePrepare());
|
|
571
|
+
const presentation = 'canvas,[data-satin-navigation-chrome],[data-satin-navigation-edge-host],[data-satin-tab-bar],[data-satin-search],[data-satin-role="chrome"]:not([data-satin-root])';
|
|
572
|
+
const damage = (record) => {
|
|
573
|
+
const target = record.target instanceof Element ? record.target : record.target.parentElement;
|
|
574
|
+
return !!target && !target.closest(presentation);
|
|
575
|
+
};
|
|
576
|
+
this.observer = new MutationObserver(records => {
|
|
577
|
+
for (const record of records) {
|
|
578
|
+
if (!damage(record))
|
|
579
|
+
continue;
|
|
580
|
+
// A removed node has no current box. Conservatively damage its former plane.
|
|
581
|
+
this.queueMutationDamage(record);
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
// The launch reveal changes which planes are visible (hidden panes count as visible under a hidden root).
|
|
585
|
+
const root = scene.closest('[data-satin-root]');
|
|
586
|
+
// The keyboard's motion flag is the root's: a preparation deferred during it runs as it ends.
|
|
587
|
+
if (root)
|
|
588
|
+
this.observer.observe(root, {
|
|
589
|
+
attributes: true,
|
|
590
|
+
attributeFilter: ['data-satin-launch', 'data-satin-keyboard-moving'],
|
|
591
|
+
});
|
|
592
|
+
// Motion flags (a navigator's transition, a moving presentation) end with an attribute change:
|
|
593
|
+
// a preparation deferred during that motion runs then.
|
|
594
|
+
this.observer.observe(scene, {
|
|
595
|
+
childList: true,
|
|
596
|
+
subtree: true,
|
|
597
|
+
characterData: true,
|
|
598
|
+
attributes: true,
|
|
599
|
+
attributeFilter: [
|
|
600
|
+
'class',
|
|
601
|
+
'style',
|
|
602
|
+
'src',
|
|
603
|
+
'hidden',
|
|
604
|
+
'data-satin-covered',
|
|
605
|
+
'data-satin-sidebar-hidden',
|
|
606
|
+
'data-satin-transition-active',
|
|
607
|
+
'data-satin-presentation-moving',
|
|
608
|
+
'data-satin-search-moving',
|
|
609
|
+
'data-satin-search-presented',
|
|
610
|
+
],
|
|
611
|
+
});
|
|
612
|
+
this.edgeObserver = new MutationObserver(records => {
|
|
613
|
+
if (records.some(record => (record.target instanceof Element &&
|
|
614
|
+
record.target.matches('[data-satin-scroll-edge],[data-satin-navigation-edge-host]')) ||
|
|
615
|
+
record.type === 'childList'))
|
|
616
|
+
this.scheduleEdges(scene);
|
|
617
|
+
});
|
|
618
|
+
this.edgeObserver.observe(scene, {
|
|
619
|
+
subtree: true,
|
|
620
|
+
childList: true,
|
|
621
|
+
attributes: true,
|
|
622
|
+
attributeFilter: ['style', 'data-satin-scroll-edge-visible'],
|
|
623
|
+
});
|
|
624
|
+
this.unsubscribeScrollJump = onScrollJump((element, top) => top <= 0 ? this.prepareScrollToTop(element) : undefined);
|
|
625
|
+
this.resize = new ResizeObserver(() => this.schedulePrepare());
|
|
626
|
+
this.resize.observe(host);
|
|
627
|
+
// Scroll-idle hold: only scrolling inside this scene (its planes, its scroller) defers captures.
|
|
628
|
+
this.scrollScopes = [...new Set([scene, this.options.elements.scroller])];
|
|
629
|
+
for (const scope of this.scrollScopes)
|
|
630
|
+
scope.addEventListener('scroll', this.scrolled, { capture: true, passive: true });
|
|
631
|
+
const navigator = host.closest('[data-satin-navigator-host]') ??
|
|
632
|
+
host.closest('[data-satin-screen-container]')?.parentElement;
|
|
633
|
+
if (navigator)
|
|
634
|
+
this.unsubscribe = observeNavigationGlass(navigator, state => {
|
|
635
|
+
// A superseded image means the routes changed under the capture: capture them again.
|
|
636
|
+
const prepare = () => this.navigation(state).catch(error => error instanceof SupersededImage
|
|
637
|
+
? prepare()
|
|
638
|
+
: (() => {
|
|
639
|
+
this.fail('navigation source', error);
|
|
640
|
+
throw error;
|
|
641
|
+
})());
|
|
642
|
+
return prepare();
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
menuDown = (event) => {
|
|
646
|
+
if (!event.isPrimary || event.button !== 0 || this.navigationActive)
|
|
647
|
+
return;
|
|
648
|
+
this.menuPointer = event.pointerId;
|
|
649
|
+
this.fire({
|
|
650
|
+
type: 'surface-input',
|
|
651
|
+
id: 'menu-lift',
|
|
652
|
+
phase: 'pressed',
|
|
653
|
+
at: performance.timeOrigin + performance.now(),
|
|
654
|
+
});
|
|
655
|
+
};
|
|
656
|
+
menuMove = (event) => {
|
|
657
|
+
if (this.menuPointer !== event.pointerId)
|
|
658
|
+
return;
|
|
659
|
+
const bounds = this.options.elements.menu?.trigger.getBoundingClientRect();
|
|
660
|
+
if (!bounds)
|
|
661
|
+
return;
|
|
662
|
+
this.fire({
|
|
663
|
+
type: 'surface-input',
|
|
664
|
+
id: 'menu-lift',
|
|
665
|
+
phase: 'dragging',
|
|
666
|
+
at: performance.timeOrigin + performance.now(),
|
|
667
|
+
x: event.clientX - bounds.left,
|
|
668
|
+
});
|
|
669
|
+
};
|
|
670
|
+
menuUp = (event) => {
|
|
671
|
+
if (this.menuPointer !== event.pointerId)
|
|
672
|
+
return;
|
|
673
|
+
this.menuPointer = undefined;
|
|
674
|
+
this.fire({
|
|
675
|
+
type: 'surface-input',
|
|
676
|
+
id: 'menu-lift',
|
|
677
|
+
phase: event.type === 'pointercancel' ? 'rest' : 'releasing',
|
|
678
|
+
at: performance.timeOrigin + performance.now(),
|
|
679
|
+
});
|
|
680
|
+
};
|
|
681
|
+
menuCancel = () => {
|
|
682
|
+
if (this.menuPointer === undefined)
|
|
683
|
+
return;
|
|
684
|
+
this.menuPointer = undefined;
|
|
685
|
+
this.fire({
|
|
686
|
+
type: 'surface-input',
|
|
687
|
+
id: 'menu-lift',
|
|
688
|
+
phase: 'rest',
|
|
689
|
+
at: performance.timeOrigin + performance.now(),
|
|
690
|
+
});
|
|
691
|
+
};
|
|
692
|
+
/** Retiming, reversal and endpoint commit republish the carrier, not a page capture. */
|
|
693
|
+
keyboardGeometry = () => {
|
|
694
|
+
const layers = [...this.planes].flatMap(([id, entry]) => {
|
|
695
|
+
const keyboard = keyboardBackdrop(entry.host, entry.keyboardAnchor);
|
|
696
|
+
return keyboard
|
|
697
|
+
? [
|
|
698
|
+
{
|
|
699
|
+
id,
|
|
700
|
+
key: `${entry.key}:front`,
|
|
701
|
+
keyboard,
|
|
702
|
+
scroll: {
|
|
703
|
+
x: entry.host.scrollLeft,
|
|
704
|
+
y: searchBackdropScroll(entry.host, entry.searchAnchor),
|
|
705
|
+
},
|
|
706
|
+
},
|
|
707
|
+
]
|
|
708
|
+
: [];
|
|
709
|
+
});
|
|
710
|
+
if (layers.length)
|
|
711
|
+
this.fire({ type: 'backdrop-keyboard', layers });
|
|
712
|
+
};
|
|
713
|
+
searchGeometryWaiting = false;
|
|
714
|
+
searchGeometry = (event) => {
|
|
715
|
+
if (this.searchGeometryWaiting)
|
|
716
|
+
return;
|
|
717
|
+
const sendCurrent = () => {
|
|
718
|
+
if (!this.attached)
|
|
719
|
+
return;
|
|
720
|
+
const id = this.scrollerPlane;
|
|
721
|
+
const entry = id ? this.planes.get(id) : undefined;
|
|
722
|
+
if (!id || !entry?.searchAnchor)
|
|
723
|
+
return;
|
|
724
|
+
const y = searchBackdropScroll(entry.host, entry.searchAnchor);
|
|
725
|
+
if (!event && y === entry.host.scrollTop)
|
|
726
|
+
return;
|
|
727
|
+
this.fire({ type: 'backdrop-scroll', id, x: entry.host.scrollLeft, y });
|
|
728
|
+
};
|
|
729
|
+
// The drawer moves captured content without a DOM scroll. That changes the rows
|
|
730
|
+
// every stationary glass region samples just as a presenter move does.
|
|
731
|
+
const covering = this.coverFor(() => this.appRegions.sampleRects());
|
|
732
|
+
if (!covering)
|
|
733
|
+
return sendCurrent();
|
|
734
|
+
this.searchGeometryWaiting = true;
|
|
735
|
+
void covering
|
|
736
|
+
.then(() => {
|
|
737
|
+
this.searchGeometryWaiting = false;
|
|
738
|
+
sendCurrent();
|
|
739
|
+
})
|
|
740
|
+
.catch(error => {
|
|
741
|
+
this.searchGeometryWaiting = false;
|
|
742
|
+
this.fail('search backdrop coverage', error);
|
|
743
|
+
});
|
|
744
|
+
};
|
|
745
|
+
minimizePointer;
|
|
746
|
+
begin = (event) => {
|
|
747
|
+
this.minimizePointer = event.pointerId;
|
|
748
|
+
this.minimize.beginGesture(this.options.elements.scroller.scrollTop);
|
|
749
|
+
};
|
|
750
|
+
endContact = (event) => {
|
|
751
|
+
if (event.pointerId !== this.minimizePointer)
|
|
752
|
+
return;
|
|
753
|
+
this.minimizePointer = undefined;
|
|
754
|
+
this.minimize.endContact(this.options.elements.scroller.scrollTop);
|
|
755
|
+
};
|
|
756
|
+
endScrollGesture = () => {
|
|
757
|
+
this.minimizePointer = undefined;
|
|
758
|
+
this.minimize.endGesture();
|
|
759
|
+
};
|
|
760
|
+
/** Lag trace: numbers this scroller's scroll events (the worker reports which one each frame used). */
|
|
761
|
+
scrollSequence = 0;
|
|
762
|
+
scroll = (event, snapshot) => {
|
|
763
|
+
const traced = lagTraceEnabled();
|
|
764
|
+
const started = traced ? glassNow() : 0;
|
|
765
|
+
const host = this.options.elements.scroller;
|
|
766
|
+
const top = snapshot?.top ?? host.scrollTop;
|
|
767
|
+
const left = snapshot?.left ?? host.scrollLeft;
|
|
768
|
+
const scrollRange = snapshot
|
|
769
|
+
? snapshot.contentHeight - snapshot.height
|
|
770
|
+
: host.scrollHeight - host.clientHeight;
|
|
771
|
+
if (this.scrollerPlane)
|
|
772
|
+
this.followWindow(this.scrollerPlane, host);
|
|
773
|
+
const trigger = this.triggerValues(top);
|
|
774
|
+
const triggerDone = traced ? glassNow() : 0;
|
|
775
|
+
this.fire({
|
|
776
|
+
type: 'source-scroll',
|
|
777
|
+
y: top,
|
|
778
|
+
trigger,
|
|
779
|
+
layer: this.scrollerPlane,
|
|
780
|
+
x: left,
|
|
781
|
+
...(traced ? { sequence: ++this.scrollSequence } : {}),
|
|
782
|
+
});
|
|
783
|
+
this.searchGeometry();
|
|
784
|
+
const direction = this.minimize.observe(top, scrollRange, this.options.geometry.tabBarPlacement);
|
|
785
|
+
if (direction)
|
|
786
|
+
this.minimizeTrack(direction);
|
|
787
|
+
if (traced)
|
|
788
|
+
lagMark({
|
|
789
|
+
stage: 'scroll-event',
|
|
790
|
+
at: started,
|
|
791
|
+
ms: glassNow() - started,
|
|
792
|
+
sequence: this.scrollSequence,
|
|
793
|
+
values: {
|
|
794
|
+
eventAt: event ? performance.timeOrigin + event.timeStamp : null,
|
|
795
|
+
y: top,
|
|
796
|
+
triggerMs: triggerDone - started,
|
|
797
|
+
minimize: direction ?? null,
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
};
|
|
801
|
+
/** Each plane host's last scroll offset, when it was read and the speed between the last two. */
|
|
802
|
+
scrollSpeeds = new WeakMap();
|
|
803
|
+
/** Record a scroll of `host`; returns its speed in points per second (signed, 0 when stale). */
|
|
804
|
+
scrollSpeed(host) {
|
|
805
|
+
const at = performance.now();
|
|
806
|
+
const top = host.scrollTop;
|
|
807
|
+
const last = this.scrollSpeeds.get(host);
|
|
808
|
+
const elapsed = last ? at - last.at : Infinity;
|
|
809
|
+
const velocity = last && elapsed > 0 && elapsed < SCROLL_SPEED_STALE_MS
|
|
810
|
+
? ((top - last.top) / elapsed) * 1000
|
|
811
|
+
: 0;
|
|
812
|
+
this.scrollSpeeds.set(host, { top, at, velocity });
|
|
813
|
+
return velocity;
|
|
814
|
+
}
|
|
815
|
+
/** Planes whose entry window may grow at the next preparation (the scene has been idle). */
|
|
816
|
+
growPlanes = new Set();
|
|
817
|
+
growTimer = 0;
|
|
818
|
+
/** A recentre was requested: the next preparation must run now, scrolling or not. */
|
|
819
|
+
pendingRecentre = false;
|
|
820
|
+
/** Bounded capture: recentres started, and every time a scroll left the window before its
|
|
821
|
+
* recentre was installed (how far, in points, and how fast). Diagnostics only. */
|
|
822
|
+
captureWindows = {
|
|
823
|
+
recentres: 0,
|
|
824
|
+
grows: 0,
|
|
825
|
+
outruns: [],
|
|
826
|
+
};
|
|
827
|
+
outrunSince = new Map();
|
|
828
|
+
/** What a plane's capture window is chosen from (see measurePlane). */
|
|
829
|
+
windowHint(id, host) {
|
|
830
|
+
const installed = this.planes.get(id);
|
|
831
|
+
const text = this.lastText ?? '';
|
|
832
|
+
// A resident capture that cannot be used as it is (stale, another appearance) is captured
|
|
833
|
+
// again: as an entry, not at the extent it had grown to.
|
|
834
|
+
const held = installed ?? this.resident.usable(id, this.options.appearance, text);
|
|
835
|
+
const last = this.scrollSpeeds.get(host);
|
|
836
|
+
const moving = last && performance.now() - last.at < SCROLL_SPEED_STALE_MS;
|
|
837
|
+
const captureDemand = this.captureDemand;
|
|
838
|
+
return {
|
|
839
|
+
current: held ? (held.window ?? 'full') : undefined,
|
|
840
|
+
bands: held?.bands,
|
|
841
|
+
grow: this.growPlanes.has(id),
|
|
842
|
+
velocity: moving ? last.velocity : 0,
|
|
843
|
+
// A plane that does not scroll is captured for the rows its glass samples.
|
|
844
|
+
...(host.scrollHeight <= host.clientHeight + 0.5 &&
|
|
845
|
+
!host.closest('[data-satin-keyboard-carrier]')
|
|
846
|
+
? {
|
|
847
|
+
demand: {
|
|
848
|
+
// Whole captures return before consulting demand. Do not measure every glass
|
|
849
|
+
// region when a covering presentation or an unchanged full capture fixes the range.
|
|
850
|
+
get rects() {
|
|
851
|
+
return captureDemand?.() ?? [];
|
|
852
|
+
},
|
|
853
|
+
covered: beneathPresentation(host),
|
|
854
|
+
damaged: !held || this.damaged.has(id),
|
|
855
|
+
},
|
|
856
|
+
}
|
|
857
|
+
: {}),
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
/** Undefined when the installed captures hold every row `rects` sample; otherwise a capture that
|
|
861
|
+
* does is scheduled now, and the promise resolves once the renderer has acknowledged one (or
|
|
862
|
+
* within the shared visible readiness budget, without authorizing an uncovered draw). */
|
|
863
|
+
coverFor(sampled) {
|
|
864
|
+
// A whole settled capture may still be replaced by a cropped navigation atlas.
|
|
865
|
+
if (!this.navigationCoverage && ![...this.planes.values()].some(entry => entry.bands))
|
|
866
|
+
return;
|
|
867
|
+
const missing = this.uncoveredPlane(sampled());
|
|
868
|
+
if (!missing)
|
|
869
|
+
return;
|
|
870
|
+
const started = performance.now();
|
|
871
|
+
this.record({ kind: 'coverage-wait', at: started, plane: missing });
|
|
872
|
+
this.prepareCoverage();
|
|
873
|
+
return new Promise((resolve, reject) => {
|
|
874
|
+
const check = () => {
|
|
875
|
+
// A completed capture may have sampled geometry from before the keyboard's next
|
|
876
|
+
// step. Only acknowledge coverage of today's demand, not merely a source upload.
|
|
877
|
+
if (this.attached && this.uncoveredPlane(sampled())) {
|
|
878
|
+
this.coverageWaiters.push(check);
|
|
879
|
+
this.prepareCoverage();
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
deadline.cancel();
|
|
883
|
+
this.record({ kind: 'coverage-installed', at: performance.now(), plane: missing });
|
|
884
|
+
resolve();
|
|
885
|
+
};
|
|
886
|
+
// Capture intentionally waits for Search/presentation layout motion before measuring.
|
|
887
|
+
// Its queue and that motion are part of glass preparation, not a 500 ms renderer fault.
|
|
888
|
+
// Success still requires this waiter's live-demand check after a source acknowledgement.
|
|
889
|
+
const deadline = new VisibleDeadline(GLASS_READINESS_BUDGET_MS, () => {
|
|
890
|
+
this.coverageWaiters = this.coverageWaiters.filter(waiter => waiter !== check);
|
|
891
|
+
this.record({ kind: 'coverage-timeout', at: performance.now(), plane: missing });
|
|
892
|
+
reject(Error(`Capture coverage was not installed for ${missing} within the visible readiness budget`));
|
|
893
|
+
});
|
|
894
|
+
this.coverageWaiters.push(check);
|
|
895
|
+
deadline.start();
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
prepareCoverage() {
|
|
899
|
+
if (!this.navigationActive || !this.navigationState) {
|
|
900
|
+
this.schedulePrepare(false, true);
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
// A settled-source capture cannot enlarge the active atlas. Serialize a new
|
|
904
|
+
// atlas from the same route set, holding new region/viewport draws until it lands.
|
|
905
|
+
if (this.navigationCoveragePreparation)
|
|
906
|
+
return;
|
|
907
|
+
const preparation = this.navigation(this.navigationState);
|
|
908
|
+
this.navigationCoveragePreparation = preparation;
|
|
909
|
+
void preparation
|
|
910
|
+
.catch(error => this.fail('navigation coverage', error))
|
|
911
|
+
.finally(() => {
|
|
912
|
+
if (this.navigationCoveragePreparation === preparation)
|
|
913
|
+
this.navigationCoveragePreparation = undefined;
|
|
914
|
+
this.coverageInstalled();
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
/** Region glass is waiting for a capture of rows no capture holds yet. */
|
|
918
|
+
get coverageWaiting() {
|
|
919
|
+
return this.coverageWaiters.length > 0;
|
|
920
|
+
}
|
|
921
|
+
/** A source batch was acknowledged (or refused): waiting region refreshes check again. */
|
|
922
|
+
coverageInstalled() {
|
|
923
|
+
const waiters = this.coverageWaiters;
|
|
924
|
+
this.coverageWaiters = [];
|
|
925
|
+
for (const waiter of waiters)
|
|
926
|
+
waiter();
|
|
927
|
+
}
|
|
928
|
+
/** The first installed plane whose bands do not hold every row `rects` sample there. */
|
|
929
|
+
uncoveredPlane(rects) {
|
|
930
|
+
for (const [id, entry] of this.planes) {
|
|
931
|
+
const navigation = id === this.contentPlane ? this.navigationCoverage : undefined;
|
|
932
|
+
if ((!entry.bands && !navigation) || !entry.host.isConnected)
|
|
933
|
+
continue;
|
|
934
|
+
// Glass in a presentation above the plane moves over all of it (a sheet's own material
|
|
935
|
+
// samples everything under the sheet): only a whole capture covers it.
|
|
936
|
+
if (beneathPresentation(entry.host))
|
|
937
|
+
return id;
|
|
938
|
+
// Captures and nested glass share the presentation's resting frame. Its
|
|
939
|
+
// offscreen entrance must not hide missing rows from this admission check.
|
|
940
|
+
const box = atRest(entry.host.getBoundingClientRect(), presentationTravel(entry.host));
|
|
941
|
+
for (const [x, y, width, height] of rects) {
|
|
942
|
+
if (x + width <= box.x || x >= box.x + box.width)
|
|
943
|
+
continue;
|
|
944
|
+
const top = Math.max(y, box.y);
|
|
945
|
+
const bottom = Math.min(y + height, box.y + box.height);
|
|
946
|
+
if (bottom <= top)
|
|
947
|
+
continue;
|
|
948
|
+
if (uncoveredSourceRows([x, y, width, height], {
|
|
949
|
+
origin: {
|
|
950
|
+
...entry.origin,
|
|
951
|
+
y: entry.origin.y +
|
|
952
|
+
(keyboardBackdrop(entry.host, entry.keyboardAnchor)?.offsetY ?? 0),
|
|
953
|
+
},
|
|
954
|
+
scroll: { y: searchBackdropScroll(entry.host, entry.searchAnchor) },
|
|
955
|
+
height: entry.height,
|
|
956
|
+
resolution: entry.resolution,
|
|
957
|
+
clip: [box.x, box.y, box.width, box.height],
|
|
958
|
+
rows: entry.bands,
|
|
959
|
+
}, navigation))
|
|
960
|
+
return id;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return undefined;
|
|
964
|
+
}
|
|
965
|
+
/** A scroll of a windowed plane: recentre before the scrollport reaches the window's edge, and
|
|
966
|
+
* record when it got there first. The scroll itself is always forwarded to the renderer. */
|
|
967
|
+
followWindow(id, host) {
|
|
968
|
+
const window = this.planes.get(id)?.window;
|
|
969
|
+
const velocity = this.scrollSpeed(host);
|
|
970
|
+
if (!window)
|
|
971
|
+
return;
|
|
972
|
+
// The scrollport as it is now: a window is never judged by the height it was captured with.
|
|
973
|
+
const viewport = host.clientHeight;
|
|
974
|
+
const scrollTop = Math.max(0, Math.min(host.scrollTop, host.scrollHeight - viewport));
|
|
975
|
+
this.noteOutrun(id, window, host, scrollTop, velocity);
|
|
976
|
+
if (captureWindowExhausted(window, scrollTop, host.scrollHeight, velocity, viewport)) {
|
|
977
|
+
if (!this.pendingRecentre)
|
|
978
|
+
this.captureWindows.recentres++;
|
|
979
|
+
this.pendingRecentre = true;
|
|
980
|
+
this.schedulePrepare(true, true);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
noteOutrun(id, window, host, scrollTop, velocity) {
|
|
984
|
+
const at = performance.now();
|
|
985
|
+
const viewport = host.clientHeight;
|
|
986
|
+
const contentHeight = host.scrollHeight;
|
|
987
|
+
if (windowCoversScrollport(window, scrollTop, viewport, contentHeight) ||
|
|
988
|
+
// At the top of the list the pinned window has the pixels (a jump to the top).
|
|
989
|
+
pinnedTopCovers(this.pinnedTops.get(id), scrollTop, viewport, contentHeight)) {
|
|
990
|
+
this.endOutrun(id, at);
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
// How far what glass can sample (the scrollport and the lens reach) lies outside the window.
|
|
994
|
+
const needTop = Math.max(0, scrollTop - LENS_REACH_POINTS);
|
|
995
|
+
const needBottom = Math.min(contentHeight, scrollTop + viewport + LENS_REACH_POINTS);
|
|
996
|
+
const by = Math.max(window.top - needTop, needBottom - window.bottom);
|
|
997
|
+
const outruns = this.captureWindows.outruns;
|
|
998
|
+
if (!this.outrunSince.has(id)) {
|
|
999
|
+
this.outrunSince.set(id, at);
|
|
1000
|
+
outruns.push({ plane: id, by, velocity, at });
|
|
1001
|
+
if (outruns.length > 200)
|
|
1002
|
+
outruns.shift();
|
|
1003
|
+
glassTiming('window-outrun', glassNow(), () => `${id} by ${Math.round(by)}pt`);
|
|
1004
|
+
}
|
|
1005
|
+
else {
|
|
1006
|
+
const current = outruns.at(-1);
|
|
1007
|
+
if (current && current.plane === id)
|
|
1008
|
+
current.by = Math.max(current.by, by);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
/** The plane's window covers its scrollport again (a recentre was installed, or it scrolled back). */
|
|
1012
|
+
endOutrun(id, at = performance.now()) {
|
|
1013
|
+
const since = this.outrunSince.get(id);
|
|
1014
|
+
if (since === undefined)
|
|
1015
|
+
return;
|
|
1016
|
+
this.outrunSince.delete(id);
|
|
1017
|
+
const current = this.captureWindows.outruns.findLast(outrun => outrun.plane === id);
|
|
1018
|
+
if (current)
|
|
1019
|
+
current.forMs = at - since;
|
|
1020
|
+
}
|
|
1021
|
+
/** Whether a plane's window is smaller than a grown window of its content would be. */
|
|
1022
|
+
windowCanGrow(entry) {
|
|
1023
|
+
if (!entry.window)
|
|
1024
|
+
return false;
|
|
1025
|
+
const largest = grownExtent({ viewport: entry.host.clientHeight, resolution: entry.resolution });
|
|
1026
|
+
const extent = entry.window.bottom - entry.window.top;
|
|
1027
|
+
return extent < Math.min(entry.host.scrollHeight, largest) - 1 / 64;
|
|
1028
|
+
}
|
|
1029
|
+
/** Whether a plane's window has left the top of its list without a current capture of the top
|
|
1030
|
+
* (the next idle preparation, or a jump to the top, captures one). */
|
|
1031
|
+
needsPinnedTop(id, entry) {
|
|
1032
|
+
if (!this.client.documentOwned || !entry.window || entry.window.top <= 0)
|
|
1033
|
+
return false;
|
|
1034
|
+
const pinned = this.pinnedTops.get(id);
|
|
1035
|
+
return !pinned || pinned.stale;
|
|
1036
|
+
}
|
|
1037
|
+
/** Request pixels opportunistically. Scroll ownership stays with the initiating tap. */
|
|
1038
|
+
prepareScrollToTop(element) {
|
|
1039
|
+
const id = this.planeIds.get(element);
|
|
1040
|
+
const entry = id ? this.planes.get(id) : undefined;
|
|
1041
|
+
if (id && entry && this.attached && this.needsPinnedTop(id, entry))
|
|
1042
|
+
this.schedulePrepare(true, true);
|
|
1043
|
+
return undefined;
|
|
1044
|
+
}
|
|
1045
|
+
invalidatePinnedTops(ids) {
|
|
1046
|
+
if (!ids.length)
|
|
1047
|
+
return;
|
|
1048
|
+
for (const id of ids) {
|
|
1049
|
+
const pinned = this.pinnedTops.get(id);
|
|
1050
|
+
if (pinned)
|
|
1051
|
+
pinned.stale = true;
|
|
1052
|
+
}
|
|
1053
|
+
this.fire({
|
|
1054
|
+
type: 'source-images',
|
|
1055
|
+
revision: this.nextTransport(),
|
|
1056
|
+
images: [],
|
|
1057
|
+
removePinned: ids,
|
|
1058
|
+
release: ids.map(id => `plane:${id}:top`),
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
queueMutationDamage(record) {
|
|
1062
|
+
// textContent replaces text children inside a live element. Its box is still available;
|
|
1063
|
+
// treating those records as detached elements defeats spatial damage filtering.
|
|
1064
|
+
const replacesText = record.addedNodes.length > 0 &&
|
|
1065
|
+
[...record.addedNodes, ...record.removedNodes].every(node => node.nodeType === Node.TEXT_NODE);
|
|
1066
|
+
this.queueSourceDamage(record.target, (record.removedNodes.length > 0 && !replacesText) ||
|
|
1067
|
+
(record.type === 'attributes' && ['class', 'style'].includes(record.attributeName ?? '')));
|
|
1068
|
+
// A detached plane host is no longer contained by the mutation parent.
|
|
1069
|
+
for (const node of record.removedNodes) {
|
|
1070
|
+
if (node instanceof Element)
|
|
1071
|
+
this.queueSourceDamage(node, true);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
/** Coalesce mutation records and image loads before reading layout, once per target per frame. */
|
|
1075
|
+
queueSourceDamage(target, removed = false) {
|
|
1076
|
+
const element = target instanceof Element ? target : target.parentElement;
|
|
1077
|
+
const key = element ?? target;
|
|
1078
|
+
this.pendingDamage.set(key, removed || this.pendingDamage.get(key) === true);
|
|
1079
|
+
if (this.damageFrame)
|
|
1080
|
+
return;
|
|
1081
|
+
this.damageFrame = requestAnimationFrame(() => {
|
|
1082
|
+
this.damageFrame = 0;
|
|
1083
|
+
const damageStarted = glassNow();
|
|
1084
|
+
const pending = this.pendingDamage;
|
|
1085
|
+
this.pendingDamage = new Map();
|
|
1086
|
+
const boxes = new Map();
|
|
1087
|
+
const styles = new Map();
|
|
1088
|
+
const pins = new Set();
|
|
1089
|
+
let damaged = false;
|
|
1090
|
+
for (const [node, removed] of pending) {
|
|
1091
|
+
damaged = this.damageSource(node, removed, boxes, styles, pins) || damaged;
|
|
1092
|
+
}
|
|
1093
|
+
if (pins.size)
|
|
1094
|
+
this.invalidatePinnedTops([...pins]);
|
|
1095
|
+
glassTiming('source-damage', damageStarted, () => `targets=${pending.size}, pins=${pins.size}`);
|
|
1096
|
+
if (damaged)
|
|
1097
|
+
this.schedulePrepare();
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
/** Skip only proven downstream damage. Above-window reflow can change every captured row. */
|
|
1101
|
+
damageSource(target, removed = false, boxes = new Map(), styles = new Map(), pendingPins) {
|
|
1102
|
+
this.resident.damage(target);
|
|
1103
|
+
const element = target instanceof Element ? target : target.parentElement;
|
|
1104
|
+
const box = (node) => {
|
|
1105
|
+
let rect = boxes.get(node);
|
|
1106
|
+
if (!rect) {
|
|
1107
|
+
rect = node.getBoundingClientRect();
|
|
1108
|
+
boxes.set(node, rect);
|
|
1109
|
+
}
|
|
1110
|
+
return rect;
|
|
1111
|
+
};
|
|
1112
|
+
const style = (node) => {
|
|
1113
|
+
let value = styles.get(node);
|
|
1114
|
+
if (!value) {
|
|
1115
|
+
value = getComputedStyle(node);
|
|
1116
|
+
styles.set(node, value);
|
|
1117
|
+
}
|
|
1118
|
+
return value;
|
|
1119
|
+
};
|
|
1120
|
+
const belongs = (host) => host.contains(target) || !!element?.contains(host);
|
|
1121
|
+
const changes = (host, window) => {
|
|
1122
|
+
if (removed || !element || element.contains(host) || !window)
|
|
1123
|
+
return true;
|
|
1124
|
+
try {
|
|
1125
|
+
const hostRect = box(host);
|
|
1126
|
+
const below = (node) => {
|
|
1127
|
+
const rect = box(node);
|
|
1128
|
+
const top = rect.top - hostRect.top + host.scrollTop;
|
|
1129
|
+
return ([rect.top, rect.left, rect.width, rect.height, top, window.bottom].every(Number.isFinite) &&
|
|
1130
|
+
rect.width > 0 &&
|
|
1131
|
+
rect.height > 0 &&
|
|
1132
|
+
top >= window.bottom);
|
|
1133
|
+
};
|
|
1134
|
+
if (!below(element))
|
|
1135
|
+
return true;
|
|
1136
|
+
// Every enclosing layout must flow from the top. Unknown layouts are damage.
|
|
1137
|
+
for (let node = element; node; node = node.parentElement) {
|
|
1138
|
+
const value = style(node);
|
|
1139
|
+
const display = value.display;
|
|
1140
|
+
const flex = display === 'flex' || display === 'inline-flex';
|
|
1141
|
+
const positioned = !['', 'static'].includes(value.position) &&
|
|
1142
|
+
!(value.position === 'relative' &&
|
|
1143
|
+
['', 'auto'].includes(value.top) &&
|
|
1144
|
+
['', 'auto'].includes(value.bottom));
|
|
1145
|
+
const normal = ['block', 'flow-root', 'list-item', 'inline', 'inline-block'].includes(display);
|
|
1146
|
+
if ((!normal && !flex) ||
|
|
1147
|
+
(flex &&
|
|
1148
|
+
(value.flexDirection !== 'column' ||
|
|
1149
|
+
!['', 'normal', 'start', 'flex-start'].includes(value.justifyContent) ||
|
|
1150
|
+
!['', 'nowrap'].includes(value.flexWrap))) ||
|
|
1151
|
+
positioned ||
|
|
1152
|
+
!['', 'normal', 'start', 'flex-start'].includes(value.alignContent) ||
|
|
1153
|
+
!['', 'none'].includes(value.transform) ||
|
|
1154
|
+
!['', 'none'].includes(value.float) ||
|
|
1155
|
+
!['', 'auto', '1'].includes(value.columnCount) ||
|
|
1156
|
+
!['', 'auto'].includes(value.columnWidth) ||
|
|
1157
|
+
!['', 'horizontal-tb'].includes(value.writingMode) ||
|
|
1158
|
+
!['', '0'].includes(value.order) ||
|
|
1159
|
+
!['', 'none'].includes(value.boxShadow) ||
|
|
1160
|
+
!['', 'none'].includes(value.textShadow) ||
|
|
1161
|
+
!['', 'none'].includes(value.filter))
|
|
1162
|
+
return true;
|
|
1163
|
+
if (flex) {
|
|
1164
|
+
// Flexible siblings can redistribute height above a changed downstream row.
|
|
1165
|
+
for (const child of node.children) {
|
|
1166
|
+
const childStyle = style(child);
|
|
1167
|
+
if (!['', '0'].includes(childStyle.flexGrow) ||
|
|
1168
|
+
!['0'].includes(childStyle.flexShrink))
|
|
1169
|
+
return true;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
for (const pseudo of ['::before', '::after']) {
|
|
1173
|
+
const content = getComputedStyle(node, pseudo).content;
|
|
1174
|
+
if (!['', 'none', 'normal'].includes(content))
|
|
1175
|
+
return true;
|
|
1176
|
+
}
|
|
1177
|
+
if (node === host)
|
|
1178
|
+
break;
|
|
1179
|
+
}
|
|
1180
|
+
// A descendant can paint above its parent's border box. Do not infer its bounds.
|
|
1181
|
+
for (const descendant of element.querySelectorAll('*')) {
|
|
1182
|
+
const value = style(descendant);
|
|
1183
|
+
if (!below(descendant) ||
|
|
1184
|
+
!['', 'static'].includes(value.position) ||
|
|
1185
|
+
!['', 'none'].includes(value.transform) ||
|
|
1186
|
+
!['', 'none'].includes(value.boxShadow) ||
|
|
1187
|
+
!['', 'none'].includes(value.textShadow) ||
|
|
1188
|
+
!['', 'none'].includes(value.filter))
|
|
1189
|
+
return true;
|
|
1190
|
+
}
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
catch {
|
|
1194
|
+
// Unmeasurable or disconnected geometry cannot prove that damage is downstream.
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
const affected = new Set();
|
|
1199
|
+
const pins = pendingPins ?? new Set();
|
|
1200
|
+
for (const [id, entry] of this.planes) {
|
|
1201
|
+
if (!belongs(entry.host))
|
|
1202
|
+
continue;
|
|
1203
|
+
const pinned = this.pinnedTops?.get(id);
|
|
1204
|
+
const pinChanged = !!pinned && !pinned.stale && changes(entry.host, pinned.window);
|
|
1205
|
+
if (changes(entry.host, entry.window) || pinChanged)
|
|
1206
|
+
affected.add(id);
|
|
1207
|
+
if (pinChanged)
|
|
1208
|
+
pins.add(id);
|
|
1209
|
+
}
|
|
1210
|
+
for (const [id, host] of this.preparingPlaneHosts) {
|
|
1211
|
+
if (!belongs(host))
|
|
1212
|
+
continue;
|
|
1213
|
+
if (changes(host, this.preparingPlaneWindows?.get(id)?.window))
|
|
1214
|
+
affected.add(id);
|
|
1215
|
+
}
|
|
1216
|
+
for (const [id, window] of this.preparingPinnedWindows ?? []) {
|
|
1217
|
+
const host = this.preparingPlaneWindows?.get(id)?.host ??
|
|
1218
|
+
this.planes.get(id)?.host ??
|
|
1219
|
+
this.preparingPlaneHosts.get(id);
|
|
1220
|
+
if (host && belongs(host) && changes(host, window)) {
|
|
1221
|
+
affected.add(id);
|
|
1222
|
+
pins.add(id);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
for (const id of affected)
|
|
1226
|
+
this.markPlaneDamaged(id);
|
|
1227
|
+
// The frame batch detaches each affected pin once, including provisional pins.
|
|
1228
|
+
if (!pendingPins && pins.size)
|
|
1229
|
+
this.invalidatePinnedTops([...pins]);
|
|
1230
|
+
return affected.size > 0;
|
|
1231
|
+
}
|
|
1232
|
+
markPlaneDamaged(id) {
|
|
1233
|
+
this.damaged.add(id);
|
|
1234
|
+
this.damageGenerations.set(id, (this.damageGenerations.get(id) ?? 0) + 1);
|
|
1235
|
+
}
|
|
1236
|
+
/** Release both committed pins and slots left behind by an interrupted preparation. */
|
|
1237
|
+
releasePinnedTops() {
|
|
1238
|
+
this.invalidatePinnedTops([...new Set([...this.pinnedTops.keys(), ...this.pinnedOrphans])]);
|
|
1239
|
+
this.pinnedTops.clear();
|
|
1240
|
+
this.pinnedOrphans.clear();
|
|
1241
|
+
}
|
|
1242
|
+
/** A preparation committed: its windows are installed. Outruns they end are closed, and the
|
|
1243
|
+
* entry windows it left grow once the scene has been idle. */
|
|
1244
|
+
windowsCommitted() {
|
|
1245
|
+
this.growPlanes.clear();
|
|
1246
|
+
for (const [id, entry] of this.planes) {
|
|
1247
|
+
const host = entry.host;
|
|
1248
|
+
const viewport = host.clientHeight;
|
|
1249
|
+
const scrollTop = Math.max(0, Math.min(host.scrollTop, host.scrollHeight - viewport));
|
|
1250
|
+
const covered = !entry.window ||
|
|
1251
|
+
windowCoversScrollport(entry.window, scrollTop, viewport, host.scrollHeight) ||
|
|
1252
|
+
pinnedTopCovers(this.pinnedTops.get(id), scrollTop, viewport, host.scrollHeight);
|
|
1253
|
+
if (covered)
|
|
1254
|
+
this.endOutrun(id);
|
|
1255
|
+
}
|
|
1256
|
+
clearTimeout(this.growTimer);
|
|
1257
|
+
this.growTimer = 0;
|
|
1258
|
+
const idleWork = [...this.planes].some(([id, entry]) => this.windowCanGrow(entry) || this.needsPinnedTop(id, entry));
|
|
1259
|
+
if (!this.attached || !idleWork)
|
|
1260
|
+
return;
|
|
1261
|
+
this.growTimer = setTimeout(() => this.growWindows(), WINDOW_GROW_IDLE_MS);
|
|
1262
|
+
}
|
|
1263
|
+
growWindows() {
|
|
1264
|
+
if (!this.attached || document.hidden || this.lifecycleHidden)
|
|
1265
|
+
return;
|
|
1266
|
+
const busy = pointerHeld() ||
|
|
1267
|
+
this.pointer ||
|
|
1268
|
+
this.navigationActive ||
|
|
1269
|
+
!!this.minimizeDom?.active ||
|
|
1270
|
+
sceneInMotion(this.options.elements?.scroller) ||
|
|
1271
|
+
performance.now() - this.lastScrollAt < WINDOW_GROW_IDLE_MS;
|
|
1272
|
+
if (busy) {
|
|
1273
|
+
this.growTimer = setTimeout(() => this.growWindows(), 200);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
for (const [id, entry] of this.planes)
|
|
1277
|
+
if (this.windowCanGrow(entry) || this.needsPinnedTop(id, entry))
|
|
1278
|
+
this.growPlanes.add(id);
|
|
1279
|
+
if (!this.growPlanes.size)
|
|
1280
|
+
return;
|
|
1281
|
+
this.captureWindows.grows++;
|
|
1282
|
+
this.schedulePrepare();
|
|
1283
|
+
}
|
|
1284
|
+
loadTarget;
|
|
1285
|
+
sourceLoaded = (event) => {
|
|
1286
|
+
if (event.target instanceof Node)
|
|
1287
|
+
this.queueSourceDamage(event.target);
|
|
1288
|
+
};
|
|
1289
|
+
/** Post the bars' scroll edges when their strength or visibility changes (one message per frame at most). */
|
|
1290
|
+
scheduleEdges(scene = this.options.elements.contentHost.closest('[data-satin-scene-paint-layer]') ?? this.options.elements.contentHost) {
|
|
1291
|
+
if (this.edgeFrame || !this.attached)
|
|
1292
|
+
return;
|
|
1293
|
+
this.edgeFrame = requestAnimationFrame(() => {
|
|
1294
|
+
this.edgeFrame = 0;
|
|
1295
|
+
if (!this.attached || !this.installedSource)
|
|
1296
|
+
return;
|
|
1297
|
+
const edges = readScrollEdges(scene, this.options.appearance === 'dark', this.navigationRoutes);
|
|
1298
|
+
const key = JSON.stringify(edges);
|
|
1299
|
+
if (key === this.installedEdges)
|
|
1300
|
+
return;
|
|
1301
|
+
this.installedEdges = key;
|
|
1302
|
+
this.fire({ type: 'backdrop-edges', edges });
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
/** Hidden: cancel capture work while retaining the last frame and its source planes.
|
|
1306
|
+
* Visible: retint and present retained sources immediately, then refresh captures. */
|
|
1307
|
+
visibility = (event) => this.handleVisibility(event);
|
|
1308
|
+
handleVisibility(event) {
|
|
1309
|
+
const hidden = event?.type === 'pagehide' || document.hidden;
|
|
1310
|
+
const changed = hidden !== this.lifecycleHidden;
|
|
1311
|
+
this.lifecycleHidden = hidden;
|
|
1312
|
+
if (lagTraceEnabled())
|
|
1313
|
+
lagMark({
|
|
1314
|
+
stage: 'glass-lifecycle',
|
|
1315
|
+
at: glassNow(),
|
|
1316
|
+
values: {
|
|
1317
|
+
event: event?.type ?? 'rebind',
|
|
1318
|
+
hidden,
|
|
1319
|
+
changed,
|
|
1320
|
+
preparing: !!this.preparing,
|
|
1321
|
+
revision: this.revision,
|
|
1322
|
+
},
|
|
1323
|
+
});
|
|
1324
|
+
// Browser lifecycle signals can describe one transition twice. Keep an in-flight
|
|
1325
|
+
// source refresh and its frame deadline; appearance arrivals still synchronize.
|
|
1326
|
+
// An explicit rebind has no event and must restore the page-lifetime renderer.
|
|
1327
|
+
if (event && !changed) {
|
|
1328
|
+
if (!hidden)
|
|
1329
|
+
this.setAppearance(this.options.currentAppearance?.() ?? this.options.appearance);
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
cancelAnimationFrame(this.resumeFrame);
|
|
1333
|
+
this.resumeFrame = 0;
|
|
1334
|
+
if (this.lifecycleHidden) {
|
|
1335
|
+
this.lifecycleCounts.hidden++;
|
|
1336
|
+
// Nothing moves across a suspension: the tab bar's minimize transaction and the bottom
|
|
1337
|
+
// accessory's run end at their committed layout now (the renderer settles its tracks
|
|
1338
|
+
// at the same end), so the first resumed frame has one pose from one owner.
|
|
1339
|
+
this.minimizeDom?.settle();
|
|
1340
|
+
// Keep the last correctly tinted frame and its sources throughout suspension.
|
|
1341
|
+
this.revision++;
|
|
1342
|
+
this.appRegions.invalidateSources();
|
|
1343
|
+
this.resumePending = true;
|
|
1344
|
+
this.dropRetained();
|
|
1345
|
+
this.installedNavigation = undefined;
|
|
1346
|
+
this.preparedSignature = '';
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
this.lifecycleCounts.visible++;
|
|
1350
|
+
this.resumeAt = glassNow();
|
|
1351
|
+
if (this.contentInstall !== undefined) {
|
|
1352
|
+
this.contentInstall = this.nextTransport();
|
|
1353
|
+
this.fire({ type: 'content-begin', revision: this.contentInstall });
|
|
1354
|
+
}
|
|
1355
|
+
this.setAppearance(this.options.currentAppearance?.() ?? this.options.appearance);
|
|
1356
|
+
// Hide invalidates an unfinished capture's worker epoch. Re-arm its barrier
|
|
1357
|
+
// even when the held appearance is unchanged, so the fresh capture can release it.
|
|
1358
|
+
if (this.appearanceInstall && this.appearanceInstall.revision !== this.revision) {
|
|
1359
|
+
this.appearanceInstall = { revision: this.revision, value: this.options.appearance };
|
|
1360
|
+
this.fire({ type: 'appearance-begin', revision: this.revision });
|
|
1361
|
+
this.appRegions.setAppearance(this.options.appearance);
|
|
1362
|
+
}
|
|
1363
|
+
// Present retained planes now. The worker retints them while suspended before
|
|
1364
|
+
// its first submission; source recapture never controls canvas visibility.
|
|
1365
|
+
this.fire({ type: 'visible', visible: true });
|
|
1366
|
+
// WebKit restores viewport metrics after visibility. Refresh the source envelope
|
|
1367
|
+
// in the background once those metrics have settled.
|
|
1368
|
+
this.resumeFrame = requestAnimationFrame(() => {
|
|
1369
|
+
this.resumeFrame = requestAnimationFrame(() => {
|
|
1370
|
+
this.resumeFrame = 0;
|
|
1371
|
+
this.schedulePrepare();
|
|
1372
|
+
});
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
/** Lifecycle transitions this page has handled (resume readout). */
|
|
1376
|
+
lifecycleCounts = { hidden: 0, visible: 0 };
|
|
1377
|
+
async resumeReadout() {
|
|
1378
|
+
const report = (await this.client.request({ type: 'report' }));
|
|
1379
|
+
const presenters = new Map();
|
|
1380
|
+
for (const [region, role] of report.regionPresenters ?? [])
|
|
1381
|
+
presenters.set(`${region}:${role}`, (presenters.get(`${region}:${role}`) ?? 0) + 1);
|
|
1382
|
+
return {
|
|
1383
|
+
lifecycle: {
|
|
1384
|
+
hides: this.lifecycleCounts.hidden,
|
|
1385
|
+
resumes: this.lifecycleCounts.visible,
|
|
1386
|
+
hidden: this.lifecycleHidden,
|
|
1387
|
+
},
|
|
1388
|
+
compact: this.minimize.compact,
|
|
1389
|
+
minimize: this.minimizeDom?.readout() ?? null,
|
|
1390
|
+
renderer: {
|
|
1391
|
+
visible: report.visible ?? null,
|
|
1392
|
+
tracks: report.loop?.tracks ?? null,
|
|
1393
|
+
duplicatePresenters: [...presenters].filter(([, count]) => count > 1),
|
|
1394
|
+
presenters: report.regionPresenters?.length ?? 0,
|
|
1395
|
+
},
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
/** A source change during tab-bar minimize/restore is applied when the motion finishes
|
|
1399
|
+
* (its track schedules a preparation): reinstalling every surface mid-motion stalled worker frames. */
|
|
1400
|
+
schedulePrepare(afterMinimize = false, windowRecentre = false) {
|
|
1401
|
+
if (!afterMinimize && this.minimizeDom?.active)
|
|
1402
|
+
return;
|
|
1403
|
+
if (this.prepareFrame ||
|
|
1404
|
+
this.resumeFrame ||
|
|
1405
|
+
!this.attached ||
|
|
1406
|
+
document.hidden ||
|
|
1407
|
+
this.lifecycleHidden ||
|
|
1408
|
+
this.navigationActive)
|
|
1409
|
+
return;
|
|
1410
|
+
if (!windowRecentre && sceneInMotion(this.options.elements?.scroller)) {
|
|
1411
|
+
glassTiming('prepare-deferred-motion');
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
// Scrolling: a capture (tens of ms of raster, readback and upload) would land in the scroll's
|
|
1415
|
+
// frames. Planes follow scroll on the GPU; damage from the gesture (a row's press highlight,
|
|
1416
|
+
// a scroll-driven style) is captured once scrolling has been idle for SCROLL_IDLE_MS.
|
|
1417
|
+
const sinceScroll = performance.now() - this.lastScrollAt;
|
|
1418
|
+
// The pending tab still shows its outgoing frame. Its layout/scroll restoration
|
|
1419
|
+
// cannot defer the source that admits the destination by another idle interval.
|
|
1420
|
+
if (!windowRecentre && this.contentInstall === undefined && sinceScroll < SCROLL_IDLE_MS) {
|
|
1421
|
+
clearTimeout(this.scrollIdle);
|
|
1422
|
+
this.scrollIdle = setTimeout(() => this.schedulePrepare(afterMinimize), SCROLL_IDLE_MS - sinceScroll + 5);
|
|
1423
|
+
glassTiming('prepare-deferred-scroll');
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
const requested = lagTraceEnabled() ? glassNow() : 0;
|
|
1427
|
+
this.prepareFrame = requestAnimationFrame(() => {
|
|
1428
|
+
this.prepareFrame = 0;
|
|
1429
|
+
// A menu can start after damage queued this frame. Keep its morph clear of
|
|
1430
|
+
// optional captures, while still admitting a capture required for coverage.
|
|
1431
|
+
if (!windowRecentre && sceneInMotion(this.options.elements?.scroller))
|
|
1432
|
+
return;
|
|
1433
|
+
if (lagTraceEnabled())
|
|
1434
|
+
glassTiming('prepare-frame-wait', requested);
|
|
1435
|
+
void this.prepare().catch(error => this.fail('source preparation', error));
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
currentSpecs() {
|
|
1439
|
+
return this.restMenu(createRenderSpecs(this.options.geometry, this.options.appearance, 'none', undefined, this.options.menuEnabled, sampleMenuMotion('close', 10, this.options.appearance, true))
|
|
1440
|
+
.map(spec => ({
|
|
1441
|
+
...spec,
|
|
1442
|
+
tabSelection: spec.tabSelection ? { ...spec.tabSelection, glyphLayers: true } : undefined,
|
|
1443
|
+
backdropExclusions: backdropExclusions(this.options.elements.contentHost, false),
|
|
1444
|
+
}))
|
|
1445
|
+
.filter(spec => spec.id === 'dock'
|
|
1446
|
+
? this.options.geometry.tabBarSelectedIndex !== undefined
|
|
1447
|
+
: spec.id === 'right' && this.options.menuEnabled));
|
|
1448
|
+
}
|
|
1449
|
+
menuResting() {
|
|
1450
|
+
return this.options.menuEnabled;
|
|
1451
|
+
}
|
|
1452
|
+
/** The trigger surface as bar glass: the menu envelope (constant storage through the
|
|
1453
|
+
* morph) with the trigger's current outline, at `opacity` over the menu surface. */
|
|
1454
|
+
barTrigger(right, opacity) {
|
|
1455
|
+
return {
|
|
1456
|
+
...right,
|
|
1457
|
+
id: 'region:bar-trigger',
|
|
1458
|
+
materialProfile: 'chrome',
|
|
1459
|
+
restHidden: undefined,
|
|
1460
|
+
returningTrigger: undefined,
|
|
1461
|
+
menuTintMix: undefined,
|
|
1462
|
+
recipeMix: undefined,
|
|
1463
|
+
materialMix: 1,
|
|
1464
|
+
opacity,
|
|
1465
|
+
shape: { blendRadius: 0, rimAlpha: 1, whiteMix: 0, first: right.shape.first },
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
/** The resting (closed) menu surface, independent of the menu's current state. */
|
|
1469
|
+
closedMenuSpec() {
|
|
1470
|
+
return createRenderSpecs(this.options.geometry, this.options.appearance, 'none', undefined, true, sampleMenuMotion('close', 10, this.options.appearance, true))
|
|
1471
|
+
.map(spec => ({
|
|
1472
|
+
...spec,
|
|
1473
|
+
backdropExclusions: backdropExclusions(this.options.elements.contentHost, false),
|
|
1474
|
+
}))
|
|
1475
|
+
.find(spec => spec.id === 'right');
|
|
1476
|
+
}
|
|
1477
|
+
restMenu(specs) {
|
|
1478
|
+
return specs.map(spec => spec.id !== 'right'
|
|
1479
|
+
? spec
|
|
1480
|
+
: {
|
|
1481
|
+
...spec,
|
|
1482
|
+
recipeMix: Math.max(0, Math.min(1, spec.materialMix * (spec.menuTintMix ?? 1))),
|
|
1483
|
+
...(this.menuResting() ? { restHidden: true } : {}),
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
/** Transport sequence: assigned when a source message is posted, so the worker
|
|
1487
|
+
* sees strictly increasing revisions and never has to reject a stale one. */
|
|
1488
|
+
post(request, transfer = []) {
|
|
1489
|
+
return this.send(request, transfer);
|
|
1490
|
+
}
|
|
1491
|
+
nextTransport() {
|
|
1492
|
+
return ++this.transportRevision;
|
|
1493
|
+
}
|
|
1494
|
+
/** One preparation at a time (productionPrepare.ts). */
|
|
1495
|
+
prepare() {
|
|
1496
|
+
return prepareSources(this);
|
|
1497
|
+
}
|
|
1498
|
+
/** Diagnostic: the installed capture's extent and its colour at viewport row `y` (CSS px, x centre). */
|
|
1499
|
+
sourceProbe(y) {
|
|
1500
|
+
const canvas = this.planeCanvases.get(this.contentPlane ?? '')?.canvas ?? this.sourceCanvas;
|
|
1501
|
+
const resolution = devicePixelRatio;
|
|
1502
|
+
const top = this.options.elements.contentHost.getBoundingClientRect().top;
|
|
1503
|
+
const row = Math.round((y + this.options.elements.scroller.scrollTop) * resolution);
|
|
1504
|
+
const ctx = canvas.getContext('2d');
|
|
1505
|
+
const pixel = ctx && row >= 0 && row < canvas.height
|
|
1506
|
+
? [...ctx.getImageData(Math.floor(canvas.width / 2), row, 1, 1).data]
|
|
1507
|
+
: null;
|
|
1508
|
+
return {
|
|
1509
|
+
installed: this.installedSource?.key,
|
|
1510
|
+
hostTop: top,
|
|
1511
|
+
width: canvas.width / resolution,
|
|
1512
|
+
height: canvas.height / resolution,
|
|
1513
|
+
row,
|
|
1514
|
+
pixel,
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
triggerValues(scroll) {
|
|
1518
|
+
const spec = this.currentSpecs().find(candidate => candidate.id === 'right');
|
|
1519
|
+
if (!spec || !this.context)
|
|
1520
|
+
return;
|
|
1521
|
+
const context = this.context.sample(spec.frameX + TRIGGER_CONTEXT_X, spec.frameY + TRIGGER_CONTEXT_Y + scroll, REGULAR_TRIGGER_MATERIAL.radiusPt, scroll, scroll + this.options.geometry.height);
|
|
1522
|
+
if (!context)
|
|
1523
|
+
return;
|
|
1524
|
+
const appearance = this.options.appearance;
|
|
1525
|
+
const regime = regularTriggerRegime(context.luminance, appearance);
|
|
1526
|
+
const response = REGULAR_TRIGGER_MATERIAL.models[`${appearance}-${regime}`];
|
|
1527
|
+
return {
|
|
1528
|
+
context: [...context.rgb, context.deviation],
|
|
1529
|
+
response: response.slice(0, 4),
|
|
1530
|
+
chroma: response[4],
|
|
1531
|
+
regime,
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
track(id, specs, duration, at = performance.now()) {
|
|
1535
|
+
const region = this.regionIds.get(id);
|
|
1536
|
+
// Menu runs are validated here, before the region map: a region is registered when its install is
|
|
1537
|
+
// posted, and outlives a disable. Only an enabled, acknowledged surface runs unguarded.
|
|
1538
|
+
if ((id === 'right' || id === 'region:bar-trigger') &&
|
|
1539
|
+
!this.menuRunAllowed(id, specs, duration, at, !!region))
|
|
1540
|
+
return;
|
|
1541
|
+
if (!region)
|
|
1542
|
+
return;
|
|
1543
|
+
this.specs.set(id, specs.at(-1));
|
|
1544
|
+
const trigger = (spec) => `${(spec.frameX + spec.shape.first.centerX).toFixed(1)},${(spec.frameY + spec.shape.first.centerY).toFixed(1)}`;
|
|
1545
|
+
glassTiming('region-track', glassNow(), () => `${id} ${duration.toFixed(0)}ms ${trigger(specs[0])}→${trigger(specs.at(-1))}`);
|
|
1546
|
+
const track = { id: region, epoch: performance.timeOrigin + at, duration, specs };
|
|
1547
|
+
if (id === 'right' || id === 'region:bar-trigger')
|
|
1548
|
+
this.menuTracks.set(id, track);
|
|
1549
|
+
this.fire({ type: 'region-track', track });
|
|
1550
|
+
}
|
|
1551
|
+
/** A source install replaces a surface's spec in the worker. The menu surfaces' specs are
|
|
1552
|
+
* read when a prepare starts, but installed after its captures: a menu run that was live
|
|
1553
|
+
* at any point since then owns them (installing the stale snapshot after the run ended
|
|
1554
|
+
* left the open panel, or a stale trigger bubble, presented). */
|
|
1555
|
+
/** Menu runs that find no installed surface: held until it is installed and acknowledged, else a loud glass error. */
|
|
1556
|
+
menuSurface = new MenuSurfaceGuard(MENU_SURFACE_BUDGET_MS, () => this.menuStage, error => this.fail('menu surface', error));
|
|
1557
|
+
menuStage = 'prepare';
|
|
1558
|
+
/** True once the worker has acknowledged the install of the menu surface of the current enable
|
|
1559
|
+
* generation (a disable, teardown or rebind starts a new generation). */
|
|
1560
|
+
menuReady = false;
|
|
1561
|
+
menuGeneration = 0;
|
|
1562
|
+
/** Whether a menu run may be sent to its surface now. Opening the menu while its surface is disabled
|
|
1563
|
+
* is the error, once per run (the trigger's track belongs to the same run); gestures are bound only
|
|
1564
|
+
* while the menu is enabled, and closing a menu that never showed has nothing to draw. A run before
|
|
1565
|
+
* the surface is acknowledged is guarded until it is: sent to the worker when its install is already
|
|
1566
|
+
* posted, else kept for the preparation that installs it. */
|
|
1567
|
+
menuRunAllowed(id, specs, duration, at, registered) {
|
|
1568
|
+
if (!this.options.menuEnabled) {
|
|
1569
|
+
return false;
|
|
1570
|
+
}
|
|
1571
|
+
if (this.menuReady)
|
|
1572
|
+
return true;
|
|
1573
|
+
this.menuSurface.start();
|
|
1574
|
+
if (registered)
|
|
1575
|
+
return true;
|
|
1576
|
+
this.specs.set(id, specs.at(-1));
|
|
1577
|
+
this.menuTracks.set(id, {
|
|
1578
|
+
id: id === 'right' ? 'menu' : 'bar-trigger',
|
|
1579
|
+
epoch: performance.timeOrigin + at,
|
|
1580
|
+
duration,
|
|
1581
|
+
specs,
|
|
1582
|
+
});
|
|
1583
|
+
this.schedulePrepare();
|
|
1584
|
+
return false;
|
|
1585
|
+
}
|
|
1586
|
+
menuTrackSince(id, since) {
|
|
1587
|
+
const track = this.menuTracks.get(id);
|
|
1588
|
+
return track && track.epoch + track.duration >= since ? track : undefined;
|
|
1589
|
+
}
|
|
1590
|
+
tabInput(event, index, cancelled = false) {
|
|
1591
|
+
this.fire({
|
|
1592
|
+
type: 'tab-input',
|
|
1593
|
+
event,
|
|
1594
|
+
index,
|
|
1595
|
+
x: this.pointerX,
|
|
1596
|
+
at: performance.timeOrigin + performance.now(),
|
|
1597
|
+
cancelled,
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
tabPointerDown(x, index) {
|
|
1601
|
+
if (this.pointer || this.navigationActive)
|
|
1602
|
+
return false;
|
|
1603
|
+
this.pointer = true;
|
|
1604
|
+
this.pointerX = x;
|
|
1605
|
+
this.pointerStart = x;
|
|
1606
|
+
this.pointerIndex = index;
|
|
1607
|
+
this.tabInput('down', index);
|
|
1608
|
+
return true;
|
|
1609
|
+
}
|
|
1610
|
+
tabPointerMove(x) {
|
|
1611
|
+
this.pointerX = x;
|
|
1612
|
+
this.tabInput('move', this.pointerIndex);
|
|
1613
|
+
}
|
|
1614
|
+
tabPointerUp(cancelled = false) {
|
|
1615
|
+
this.pointer = false;
|
|
1616
|
+
const previous = this.options.geometry.tabBarSelectedIndex ?? 0;
|
|
1617
|
+
const index = cancelled
|
|
1618
|
+
? previous
|
|
1619
|
+
: Math.abs(this.pointerX - this.pointerStart) > 3
|
|
1620
|
+
? nearestTab(this.pointerX, this.options.geometry.tabBarCentres)
|
|
1621
|
+
: this.pointerIndex;
|
|
1622
|
+
this.tabInput('up', previous, cancelled);
|
|
1623
|
+
if (!cancelled)
|
|
1624
|
+
this.commitTabSelection(index);
|
|
1625
|
+
}
|
|
1626
|
+
selectTabAnimated(index) {
|
|
1627
|
+
this.tabInput('select', index);
|
|
1628
|
+
this.commitTabSelection(index);
|
|
1629
|
+
}
|
|
1630
|
+
commitTabSelection(index) {
|
|
1631
|
+
const traced = lagTraceEnabled();
|
|
1632
|
+
const started = traced ? glassNow() : 0;
|
|
1633
|
+
const changed = this.options.geometry.tabBarSelectedIndex !== index;
|
|
1634
|
+
if (changed && !this.options.consumerMode) {
|
|
1635
|
+
this.options = {
|
|
1636
|
+
...this.options,
|
|
1637
|
+
geometry: { ...this.options.geometry, tabBarSelectedIndex: index },
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
// The incoming tab must not inherit the outgoing content's scroll-idle hold.
|
|
1641
|
+
if (changed)
|
|
1642
|
+
this.lastScrollAt = -Infinity;
|
|
1643
|
+
this.options.onTabActivated?.(index);
|
|
1644
|
+
const activated = traced ? glassNow() : 0;
|
|
1645
|
+
if (changed && !this.options.consumerMode)
|
|
1646
|
+
this.options.onTabSelected?.(index);
|
|
1647
|
+
if (traced)
|
|
1648
|
+
lagMark({
|
|
1649
|
+
stage: 'tab-commit',
|
|
1650
|
+
at: started,
|
|
1651
|
+
ms: glassNow() - started,
|
|
1652
|
+
values: { index, changed, activateMs: activated - started },
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
setTabSelection(index) {
|
|
1656
|
+
if (index === undefined)
|
|
1657
|
+
return;
|
|
1658
|
+
this.options = {
|
|
1659
|
+
...this.options,
|
|
1660
|
+
geometry: { ...this.options.geometry, tabBarSelectedIndex: index },
|
|
1661
|
+
};
|
|
1662
|
+
this.minimizeDom?.update(this.options);
|
|
1663
|
+
if (!this.pointer)
|
|
1664
|
+
this.tabInput('reset', index);
|
|
1665
|
+
}
|
|
1666
|
+
minimizeTrack(direction, path = 'tap') {
|
|
1667
|
+
const spec = this.currentSpecs().find(candidate => candidate.id === 'dock');
|
|
1668
|
+
if (!spec || !this.minimizeDom)
|
|
1669
|
+
return;
|
|
1670
|
+
glassTiming('minimize-track', glassNow(), direction);
|
|
1671
|
+
// Minimize owns selection geometry until restore completes. Retire an earlier tap's
|
|
1672
|
+
// lens so it cannot repaint the committed capsule from a second animation clock.
|
|
1673
|
+
if (!this.pointer)
|
|
1674
|
+
this.tabInput('reset', this.options.geometry.tabBarSelectedIndex ?? 0, true);
|
|
1675
|
+
const track = this.minimizeDom.start(direction, spec, path);
|
|
1676
|
+
this.track('dock', track.specs, track.duration, track.at);
|
|
1677
|
+
void track.finished.then(() => {
|
|
1678
|
+
if (performance.now() >= track.at + track.duration - 50)
|
|
1679
|
+
this.schedulePrepare(true);
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
restoreMinimizingTabBar(path = 'tap') {
|
|
1683
|
+
if (!this.minimize.compact)
|
|
1684
|
+
return false;
|
|
1685
|
+
this.minimize.restore(this.options.elements.scroller.scrollTop);
|
|
1686
|
+
this.minimizeTrack('restore', path);
|
|
1687
|
+
return true;
|
|
1688
|
+
}
|
|
1689
|
+
navigation(state) {
|
|
1690
|
+
this.navigationState = state;
|
|
1691
|
+
return prepareNavigation(this, state);
|
|
1692
|
+
}
|
|
1693
|
+
updateGeometry(next) {
|
|
1694
|
+
const previous = this.options.geometry;
|
|
1695
|
+
this.options = { ...this.options, geometry: { ...previous, ...next } };
|
|
1696
|
+
this.minimizeDom?.update(this.options);
|
|
1697
|
+
if (previous.tabBarPlacement !== this.options.geometry.tabBarPlacement) {
|
|
1698
|
+
this.minimize.rebase(this.options.elements.scroller.scrollTop);
|
|
1699
|
+
if (this.options.geometry.tabBarPlacement === 'top')
|
|
1700
|
+
this.restoreMinimizingTabBar();
|
|
1701
|
+
}
|
|
1702
|
+
if (JSON.stringify({ ...previous, tabBarSelectedIndex: 0 }) !==
|
|
1703
|
+
JSON.stringify({ ...this.options.geometry, tabBarSelectedIndex: 0 })) {
|
|
1704
|
+
this.revision++;
|
|
1705
|
+
this.mount();
|
|
1706
|
+
this.schedulePrepare();
|
|
1707
|
+
}
|
|
1708
|
+
else if (previous.tabBarSelectedIndex !== this.options.geometry.tabBarSelectedIndex) {
|
|
1709
|
+
// Async initialization can finish after tab restoration, without changing any dimensions.
|
|
1710
|
+
// Synchronize the worker's pill too, while retaining its in-flight selection motion.
|
|
1711
|
+
this.setTabSelection(this.options.geometry.tabBarSelectedIndex);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
retargetContent(scroller, contentHost) {
|
|
1715
|
+
if (scroller === this.options.elements.scroller &&
|
|
1716
|
+
contentHost === this.options.elements.contentHost)
|
|
1717
|
+
return;
|
|
1718
|
+
if (scroller.closest('[data-satin-tab-panel]') !==
|
|
1719
|
+
this.options.elements.scroller.closest('[data-satin-tab-panel]')) {
|
|
1720
|
+
this.contentInstall = this.nextTransport();
|
|
1721
|
+
this.fire({ type: 'content-begin', revision: this.contentInstall });
|
|
1722
|
+
}
|
|
1723
|
+
// Only the content changed: the tab bar keeps its minimize state and running motion. Disposing
|
|
1724
|
+
// the DOM minimize here cancelled the tab ink's keyframes while the worker's capsule track ran
|
|
1725
|
+
// on (glass collapsed, icons left floating at their expanded positions).
|
|
1726
|
+
const minimize = this.minimize;
|
|
1727
|
+
const minimizeDom = this.minimizeDom;
|
|
1728
|
+
this.minimizeDom = undefined;
|
|
1729
|
+
this.teardown();
|
|
1730
|
+
this.minimize = minimize;
|
|
1731
|
+
minimize.rebase(scroller.scrollTop);
|
|
1732
|
+
this.options = {
|
|
1733
|
+
...this.options,
|
|
1734
|
+
elements: { ...this.options.elements, scroller, contentHost },
|
|
1735
|
+
};
|
|
1736
|
+
this.attached = true;
|
|
1737
|
+
this.bind(minimizeDom);
|
|
1738
|
+
this.schedulePrepare();
|
|
1739
|
+
glassTiming('retarget', glassNow(), () => `${scroller.id || scroller.className} minimizing:${minimizeDom?.active ?? false} compact:${minimize.compact}`);
|
|
1740
|
+
}
|
|
1741
|
+
setContentHost(host) {
|
|
1742
|
+
this.retargetContent(this.options.elements.scroller, host);
|
|
1743
|
+
}
|
|
1744
|
+
setAppearance(appearance) {
|
|
1745
|
+
if (appearance === this.options.appearance)
|
|
1746
|
+
return;
|
|
1747
|
+
this.options = { ...this.options, appearance };
|
|
1748
|
+
// A queued preparation may wait for motion or scrolling. Invalidate the
|
|
1749
|
+
// current capture now so it cannot commit the previous appearance meanwhile.
|
|
1750
|
+
this.revision++;
|
|
1751
|
+
if (!this.lifecycleHidden && !document.hidden) {
|
|
1752
|
+
this.appearanceInstall = { revision: this.revision, value: appearance };
|
|
1753
|
+
this.fire({ type: 'appearance-begin', revision: this.revision });
|
|
1754
|
+
this.appRegions.setAppearance(appearance);
|
|
1755
|
+
}
|
|
1756
|
+
this.dropRetained();
|
|
1757
|
+
this.schedulePrepare();
|
|
1758
|
+
}
|
|
1759
|
+
commitAppearance(appearance) {
|
|
1760
|
+
this.setAppearance(appearance);
|
|
1761
|
+
}
|
|
1762
|
+
setScroll(offset) {
|
|
1763
|
+
this.options.elements.scroller.scrollTop = offset;
|
|
1764
|
+
this.scroll();
|
|
1765
|
+
}
|
|
1766
|
+
setScreen(screen) {
|
|
1767
|
+
this.options = { ...this.options, screen };
|
|
1768
|
+
this.schedulePrepare();
|
|
1769
|
+
}
|
|
1770
|
+
setMenuEnabled(enabled, _resetOwner = false) {
|
|
1771
|
+
this.options = { ...this.options, menuEnabled: enabled };
|
|
1772
|
+
// The menu's registration ended: a run still waiting for its first surface is for a menu that no longer exists.
|
|
1773
|
+
// A removed menu is closed: the frames its gesture binding sends while tearing down are not menu runs.
|
|
1774
|
+
if (!enabled) {
|
|
1775
|
+
this.menuSurface.cancel();
|
|
1776
|
+
this.menuReady = false;
|
|
1777
|
+
this.menuGeneration++;
|
|
1778
|
+
if (!this.regionIds.has('right')) {
|
|
1779
|
+
this.menuTracks.delete('right');
|
|
1780
|
+
this.menuTracks.delete('region:bar-trigger');
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
this.schedulePrepare();
|
|
1784
|
+
}
|
|
1785
|
+
regionDiagnostics() {
|
|
1786
|
+
return undefined;
|
|
1787
|
+
}
|
|
1788
|
+
setBridgeEnabled(_enabled) { }
|
|
1789
|
+
setGlassEnabled(enabled) {
|
|
1790
|
+
if (!enabled)
|
|
1791
|
+
throw Error('WebGPU glass cannot degrade to a substitute');
|
|
1792
|
+
}
|
|
1793
|
+
setLensMode(mode) {
|
|
1794
|
+
if (mode !== 'reference-regular')
|
|
1795
|
+
throw Error('Production WebGPU currently exposes the material regular material');
|
|
1796
|
+
}
|
|
1797
|
+
setMarkers(_enabled) { }
|
|
1798
|
+
setVelocityFadeEnabled(_enabled) { }
|
|
1799
|
+
setDragProgress(_progress) {
|
|
1800
|
+
throw Error('Use production navigation gestures for the WebGPU renderer');
|
|
1801
|
+
}
|
|
1802
|
+
startLiquidMotion(_repeats, _speed) {
|
|
1803
|
+
throw Error('Use production tab interaction for the WebGPU renderer');
|
|
1804
|
+
}
|
|
1805
|
+
startMenuCadence(_repeats, _speed) {
|
|
1806
|
+
throw Error('Use production menu interaction for the WebGPU renderer');
|
|
1807
|
+
}
|
|
1808
|
+
setMenuHandoffProbe(_hold) { }
|
|
1809
|
+
setMenuPreparationProbe(_milliseconds) { }
|
|
1810
|
+
setMenuCase(name) {
|
|
1811
|
+
this.record({ kind: 'menu-case', name });
|
|
1812
|
+
}
|
|
1813
|
+
recordMenuInteraction(event, phase) {
|
|
1814
|
+
this.record({ event, phase });
|
|
1815
|
+
}
|
|
1816
|
+
recordMenuDecision(decision) {
|
|
1817
|
+
this.record(decision);
|
|
1818
|
+
}
|
|
1819
|
+
recordMenuSelection(index, event, source) {
|
|
1820
|
+
this.record({ index, event, source });
|
|
1821
|
+
}
|
|
1822
|
+
recordMenuInput(_event) { }
|
|
1823
|
+
recordMenuTouch(_phase, _event) { }
|
|
1824
|
+
resetMetrics() {
|
|
1825
|
+
this.events = [];
|
|
1826
|
+
}
|
|
1827
|
+
exportFrameTrace(_includeBuffers = true) {
|
|
1828
|
+
return { backend: 'webgpu', events: this.events, errors: getGlassErrors() };
|
|
1829
|
+
}
|
|
1830
|
+
benchmarkRestingMaterials() {
|
|
1831
|
+
throw Error('Use __SATIN_WEBGPU__.report() and the worker benchmark protocol');
|
|
1832
|
+
}
|
|
1833
|
+
exportDiagnosticBuffers() {
|
|
1834
|
+
throw Error('WebGPU buffers require asynchronous diagnostic readback');
|
|
1835
|
+
}
|
|
1836
|
+
/** The options of the create() call that owns this shared runtime now. A StrictMode or remount
|
|
1837
|
+
* sequence can create twice while initialization is pending: the cancelled first caller's
|
|
1838
|
+
* release must not tear down the runtime the second caller has already rebound. */
|
|
1839
|
+
owner;
|
|
1840
|
+
/** Releases the runtime for `owner` (every caller passes its create() options); a stale owner is ignored. */
|
|
1841
|
+
detach(owner) {
|
|
1842
|
+
if (owner && owner !== this.owner)
|
|
1843
|
+
return;
|
|
1844
|
+
this.teardown();
|
|
1845
|
+
}
|
|
1846
|
+
teardown() {
|
|
1847
|
+
this.unbindAppearance();
|
|
1848
|
+
if (this.minimizeDom && (this.minimizeDom.active || this.minimize.compact)) {
|
|
1849
|
+
const dock = this.currentSpecs().find(spec => spec.id === 'dock');
|
|
1850
|
+
const region = this.regionIds.get('dock');
|
|
1851
|
+
if (dock && region)
|
|
1852
|
+
this.fire({ type: 'region-spec', id: region, spec: dock });
|
|
1853
|
+
}
|
|
1854
|
+
cancelAnimationFrame(this.resumeFrame);
|
|
1855
|
+
this.resumeFrame = 0;
|
|
1856
|
+
this.preparedSignature = '';
|
|
1857
|
+
this.revision++;
|
|
1858
|
+
this.navigationRevision++;
|
|
1859
|
+
this.menuCancel();
|
|
1860
|
+
this.options.elements.menu?.trigger.removeEventListener('pointerdown', this.menuDown);
|
|
1861
|
+
this.options.elements.menu?.trigger.removeEventListener('pointermove', this.menuMove);
|
|
1862
|
+
document.removeEventListener('pointerup', this.menuUp, true);
|
|
1863
|
+
document.removeEventListener('pointercancel', this.menuUp, true);
|
|
1864
|
+
window.removeEventListener('blur', this.menuCancel);
|
|
1865
|
+
this.unsubscribePresentationBackdrop?.();
|
|
1866
|
+
this.unsubscribePresentationBackdrop = undefined;
|
|
1867
|
+
this.unsubscribeRegionBackdrop?.();
|
|
1868
|
+
this.unsubscribeRegionBackdrop = undefined;
|
|
1869
|
+
window.removeEventListener(KEYBOARD_CARRIER_MOTION, this.keyboardGeometry);
|
|
1870
|
+
window.removeEventListener(SCROLL_INSERTION_MOTION, this.keyboardGeometry);
|
|
1871
|
+
this.appRegions.unbind();
|
|
1872
|
+
this.minimize = new TabMinimizeIntent();
|
|
1873
|
+
this.minimizeDom?.dispose();
|
|
1874
|
+
this.minimizeDom = undefined;
|
|
1875
|
+
this.navigationActive = false;
|
|
1876
|
+
this.attached = false;
|
|
1877
|
+
this.coverageInstalled();
|
|
1878
|
+
cancelAnimationFrame(this.prepareFrame);
|
|
1879
|
+
this.prepareFrame = 0;
|
|
1880
|
+
clearTimeout(this.growTimer);
|
|
1881
|
+
this.growTimer = 0;
|
|
1882
|
+
this.observer?.disconnect();
|
|
1883
|
+
cancelAnimationFrame(this.damageFrame);
|
|
1884
|
+
this.damageFrame = 0;
|
|
1885
|
+
this.pendingDamage?.clear();
|
|
1886
|
+
this.edgeObserver?.disconnect();
|
|
1887
|
+
cancelAnimationFrame(this.edgeFrame);
|
|
1888
|
+
this.edgeFrame = 0;
|
|
1889
|
+
this.navigationObserver?.disconnect();
|
|
1890
|
+
this.navigationAnimations?.();
|
|
1891
|
+
this.navigationRelease?.();
|
|
1892
|
+
cancelAnimationFrame(this.navigationFrame);
|
|
1893
|
+
this.navigationFrame = 0;
|
|
1894
|
+
if (this.navigationInput)
|
|
1895
|
+
document.removeEventListener('scroll', this.navigationInput, true);
|
|
1896
|
+
this.navigationInput = undefined;
|
|
1897
|
+
this.resize?.disconnect();
|
|
1898
|
+
this.unsubscribe?.();
|
|
1899
|
+
this.unsubscribeScrollJump?.();
|
|
1900
|
+
this.unsubscribeScrollJump = undefined;
|
|
1901
|
+
this.releasePinnedTops();
|
|
1902
|
+
this.loadTarget?.removeEventListener('load', this.sourceLoaded, true);
|
|
1903
|
+
this.loadTarget?.removeEventListener(GLASS_SOURCE_DAMAGE_EVENT, this.sourceLoaded, true);
|
|
1904
|
+
this.loadTarget = undefined;
|
|
1905
|
+
this.unsubscribeNativeScroll?.();
|
|
1906
|
+
this.unsubscribeNativeScroll = undefined;
|
|
1907
|
+
this.options.elements.scroller.removeEventListener('satin:search-geometry', this.searchGeometry);
|
|
1908
|
+
this.options.elements.scroller.removeEventListener('pointerdown', this.begin);
|
|
1909
|
+
document.removeEventListener('pointerup', this.endContact, true);
|
|
1910
|
+
this.minimizePointer = undefined;
|
|
1911
|
+
this.options.elements.scroller.removeEventListener('scrollend', this.endScrollGesture);
|
|
1912
|
+
document.removeEventListener('visibilitychange', this.visibility, true);
|
|
1913
|
+
window.removeEventListener('pagehide', this.visibility, true);
|
|
1914
|
+
window.removeEventListener('pageshow', this.visibility);
|
|
1915
|
+
document.fonts.removeEventListener('loadingdone', this.fontsChanged);
|
|
1916
|
+
for (const scope of this.scrollScopes)
|
|
1917
|
+
scope.removeEventListener('scroll', this.scrolled, true);
|
|
1918
|
+
this.scrollScopes = [];
|
|
1919
|
+
this.menuSurface.cancel();
|
|
1920
|
+
this.menuReady = false;
|
|
1921
|
+
this.menuGeneration++;
|
|
1922
|
+
}
|
|
1923
|
+
dispose(owner) {
|
|
1924
|
+
if (owner && owner !== this.owner)
|
|
1925
|
+
return;
|
|
1926
|
+
this.teardown();
|
|
1927
|
+
void this.client.park().catch(error => this.fail('park', error));
|
|
1928
|
+
}
|
|
1929
|
+
}
|