From 74461283157d8d26453c925de11d4750006abb76 Mon Sep 17 00:00:00 2001 From: Martin Donadieu Date: Thu, 14 May 2026 11:51:36 +0200 Subject: [PATCH] add capacitor sheets docs --- apps/docs/src/config/sidebar.mjs | 1 + .../docs/plugins/sheets/getting-started.mdx | 359 ++++++++++++++++++ .../docs/docs/plugins/sheets/index.mdx | 109 ++++++ apps/web/src/config/plugins.ts | 2 + scripts/check-plugin-doc-mirrors.ts | 2 +- .../docs/plugins/sheets/getting-started.mdx | 359 ++++++++++++++++++ .../docs/docs/plugins/sheets/index.mdx | 109 ++++++ 7 files changed, 940 insertions(+), 1 deletion(-) create mode 100644 apps/docs/src/content/docs/docs/plugins/sheets/getting-started.mdx create mode 100644 apps/docs/src/content/docs/docs/plugins/sheets/index.mdx create mode 100644 src/content/docs/docs/plugins/sheets/getting-started.mdx create mode 100644 src/content/docs/docs/plugins/sheets/index.mdx diff --git a/apps/docs/src/config/sidebar.mjs b/apps/docs/src/config/sidebar.mjs index 84b8d0e9c..a34d78eb2 100644 --- a/apps/docs/src/config/sidebar.mjs +++ b/apps/docs/src/config/sidebar.mjs @@ -182,6 +182,7 @@ const pluginEntries = [ ['Screen Recorder', 'screen-recorder'], ['Shake', 'shake'], ['Share Target', 'share-target'], + ['Sheets', 'sheets'], ['SIM', 'sim'], ['Speech Recognition', 'speech-recognition'], ['Speech Synthesis', 'speech-synthesis'], diff --git a/apps/docs/src/content/docs/docs/plugins/sheets/getting-started.mdx b/apps/docs/src/content/docs/docs/plugins/sheets/getting-started.mdx new file mode 100644 index 000000000..9aab64acb --- /dev/null +++ b/apps/docs/src/content/docs/docs/plugins/sheets/getting-started.mdx @@ -0,0 +1,359 @@ +--- +title: Getting Started +description: Install @capgo/capacitor-sheets and add framework-agnostic sheets to a Capacitor app. +sidebar: + order: 2 +--- + +import { Steps, Aside } from '@astrojs/starlight/components'; + + +1. **Install the package** + + ```bash + npm install @capgo/capacitor-sheets + ``` + +2. **Register the web components** + + ```ts + import '@capgo/capacitor-sheets'; + ``` + +3. **Add the viewport setting for safe areas** + + ```html + + ``` + +4. **Render a sheet** + + ```html + Open route + + + + + + + + + Evening route + Choose a route and confirm pickup. + Done + + + + + ``` + + ```css + .route-sheet { + width: min(100%, 34em); + padding: 0 1.25em 1.25em; + } + ``` + + + + +## Capacitor Safe Areas + +Safe areas are enabled by default through `safe-area="auto"`. The sheet viewport reads both browser environment values and Capacitor fallback variables: + +```css +env(safe-area-inset-top) +env(safe-area-inset-bottom) +env(safe-area-inset-left) +env(safe-area-inset-right) +var(--safe-area-inset-top) +var(--safe-area-inset-bottom) +var(--safe-area-inset-left) +var(--safe-area-inset-right) +``` + +Choose the protected edges per sheet: + +```html + + + +``` + +For apps with overlay status bars or system bars, keep the native plugins responsible for exposing correct inset values: + +```ts +import type { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + plugins: { + StatusBar: { + overlaysWebView: true, + }, + Keyboard: { + resize: 'body', + resizeOnFullScreen: true, + }, + SystemBars: { + insetsHandling: 'css', + }, + }, +}; + +export default config; +``` + +Keyboard handling is controlled by `native-focus-scroll-prevention`, which defaults to `true`. Disable it only when your app already owns keyboard avoidance: + +```html + +``` + +## Imperative Control + +All framework helpers configure the same underlying custom element. You can also control a sheet directly: + +```ts +const sheet = document.querySelector('cap-sheet'); + +await sheet?.present(); +await sheet?.stepTo(2); +await sheet?.step('down'); +await sheet?.dismiss(); +``` + +Listen to events for controlled state, analytics, or coordinated animation: + +```ts +sheet?.addEventListener('cap-sheet-presented-change', (event) => { + console.log(event.detail.presented); +}); + +sheet?.addEventListener('cap-sheet-active-detent-change', (event) => { + console.log(event.detail.activeDetent); +}); + +sheet?.addEventListener('cap-sheet-travel', (event) => { + console.log(event.detail.progress); +}); +``` + +## React + +```tsx +import { useEffect, useRef } from 'react'; +import { setupSheet } from '@capgo/capacitor-sheets/react'; +import '@capgo/capacitor-sheets'; + +export function BookingSheet() { + const sheetRef = useRef(null); + + useEffect(() => { + if (!sheetRef.current) return; + + return setupSheet(sheetRef.current, { + detents: ['18em', '32em'], + contentPlacement: 'bottom', + onPresentedChange: ({ presented }) => console.log({ presented }), + }); + }, []); + + return ( + + Open + + + + + React sheet + + + + ); +} +``` + +Importing from `@capgo/capacitor-sheets/react` also registers JSX typings for the custom elements. If TypeScript still reports unknown tags, add a declaration file inside your source tree: + +```ts +// src/capgo-sheets.d.ts +import '@capgo/capacitor-sheets/react'; +``` + +## Vue + +```vue + + + +``` + +## Angular + +```ts +import { AfterViewInit, Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, ViewChild } from '@angular/core'; +import { setupSheet } from '@capgo/capacitor-sheets/angular'; +import '@capgo/capacitor-sheets'; + +@Component({ + selector: 'app-root', + standalone: true, + schemas: [CUSTOM_ELEMENTS_SCHEMA], + template: ` + + Open + + + + + Angular sheet + + + + `, +}) +export class AppComponent implements AfterViewInit { + @ViewChild('sheet', { static: true }) sheet?: ElementRef; + + ngAfterViewInit(): void { + if (this.sheet?.nativeElement) { + setupSheet(this.sheet.nativeElement, { + detents: ['18em', '32em'], + contentPlacement: 'bottom', + }); + } + } +} +``` + +## Svelte + +```svelte + + + + Open + + + + + Svelte sheet + + + +``` + +## Solid + +```tsx +import { onCleanup, onMount } from 'solid-js'; +import { setupSheet } from '@capgo/capacitor-sheets/solid'; +import '@capgo/capacitor-sheets'; + +export function BookingSheet() { + let sheetEl!: HTMLElement; + + onMount(() => { + const cleanup = setupSheet(sheetEl, { + detents: ['18em', '32em'], + contentPlacement: 'bottom', + }); + + onCleanup(cleanup); + }); + + return ( + + Open + + + + + Solid sheet + + + + ); +} +``` + +## Components + +| Element | Purpose | +| --- | --- | +| `cap-sheet` | Sheet state, detents, gestures, modal behavior, and events | +| `cap-sheet-trigger` | Declarative present, dismiss, toggle, and step actions | +| `cap-sheet-portal` | Optional body portal for overlay layering | +| `cap-sheet-view` | Fixed viewport host with safe-area and keyboard padding | +| `cap-sheet-backdrop` | Progress-synced backdrop | +| `cap-sheet-content` | Accessible sheet surface | +| `cap-sheet-bleeding-background` | Background extension for rounded edge sheets | +| `cap-sheet-handle` | Draggable and keyboard-accessible detent handle | +| `cap-sheet-title` | Accessible title | +| `cap-sheet-description` | Accessible description | +| `cap-sheet-special-wrapper` | Composition hook for detached sheets, cards, and lightboxes | +| `cap-sheet-stack` | Stacked sheet grouping | +| `cap-sheet-outlet` | Progress outlet for depth, parallax, and page effects | +| `cap-scroll` | Scroll progress helper | +| `cap-fixed` | Fixed layer helper | +| `cap-island` | Related floating island content | +| `cap-external-overlay` | Overlay content managed outside the sheet tree | + +## Main Options + +| Option | Attribute | Default | Description | +| --- | --- | --- | --- | +| `contentPlacement` | `content-placement` | `bottom` | `top`, `bottom`, `left`, `right`, or `center` | +| `detents` | `detents` | none | Space-separated CSS lengths such as `18em 32em` | +| `safeArea` | `safe-area` | `auto` | Protected safe-area edges | +| `swipe` | `swipe` | `true` | Enable pointer, touch, trackpad, and wheel gestures | +| `swipeDismissal` | `swipe-dismissal` | `true` | Allow gestures to dismiss to detent `0` | +| `inertOutside` | `inert-outside` | `true` | Prevent interaction behind modal sheets | +| `focusTrap` | `focus-trap` | `true` | Keep keyboard focus inside the sheet | +| `closeOnOutsideClick` | `close-on-outside-click` | `true` | Dismiss when clicking the backdrop or view | +| `closeOnEscape` | `close-on-escape` | `true` | Dismiss when pressing Escape | +| `nativeFocusScrollPrevention` | `native-focus-scroll-prevention` | `true` | Keep focused inputs visible above the keyboard | +| `themeColorDimming` | `theme-color-dimming` | `auto` | Dim the WebView theme color while modal | + +## Available Entrypoints + +- `@capgo/capacitor-sheets` +- `@capgo/capacitor-sheets/react` +- `@capgo/capacitor-sheets/vue` +- `@capgo/capacitor-sheets/angular` +- `@capgo/capacitor-sheets/svelte` +- `@capgo/capacitor-sheets/solid` diff --git a/apps/docs/src/content/docs/docs/plugins/sheets/index.mdx b/apps/docs/src/content/docs/docs/plugins/sheets/index.mdx new file mode 100644 index 000000000..7b03ed05e --- /dev/null +++ b/apps/docs/src/content/docs/docs/plugins/sheets/index.mdx @@ -0,0 +1,109 @@ +--- +title: "@capgo/capacitor-sheets" +description: Framework-agnostic sheets, drawers, dialogs, scroll helpers, and overlay primitives for Capacitor apps. +tableOfContents: false +next: false +prev: false +sidebar: + order: 1 + label: "Introduction" +hero: + tagline: Build Silk-style sheets, drawers, dialogs, toasts, lightboxes, cards, and page overlays in any Capacitor frontend. + actions: + - text: Get started + link: /docs/plugins/sheets/getting-started/ + icon: right-arrow + variant: primary + - text: GitHub + link: https://github.com/Cap-go/capacitor-sheets/ + icon: external + variant: minimal +--- + +import { Card, CardGrid, Aside } from '@astrojs/starlight/components'; + + + + Use standards-based custom elements directly or use setup helpers for React, Vue, Angular, Svelte, and Solid. + + + Respect safe areas, keyboard movement, native edge gestures, and WebView theme-color dimming from the web layer. + + + Compose bottom sheets, side drawers, top sheets, centered dialogs, toasts, detached sheets, cards, pages, and lightboxes. + + + Author detents with `em`, `rem`, viewport units, `calc()`, and CSS variables while the default sizing stays `em` based. + + + +## When To Use It + +`@capgo/capacitor-sheets` is for Capacitor apps that need high-quality mobile overlays without adopting a specific UI framework. It ships as custom elements, so the core package has no React, Vue, Angular, Svelte, or Solid runtime dependency. + +Use it when you need: + +- bottom sheets with one or more detents +- left or right sidebars and top sheets +- centered dialogs, lightboxes, cards, and toast-like overlays +- persistent sheets that keep the app behind them interactive +- full-page overlays that enter from an edge +- stack, depth, and parallax effects driven by sheet progress +- scroll helpers that expose progress and distance values +- Capacitor-safe layout for notches, home indicators, Android cutouts, and software keyboards + + + +## Usecase Coverage + +| Usecase | Capgo Sheets pattern | +| --- | --- | +| Long Sheet | `cap-sheet` with natural content scroll or `cap-scroll` | +| Sheet with Detent | `detents="18em 32em"` plus `stepTo()` or a step trigger | +| Sidebar | `content-placement="left"` or `content-placement="right"` | +| Bottom Sheet | default `content-placement="bottom"` | +| Sheet with Keyboard | `native-focus-scroll-prevention` and visual viewport offset handling | +| Toast | `inert-outside="false"`, `focus-trap="false"`, and no outside-click dismissal | +| Detached Sheet | `cap-sheet-special-wrapper` plus custom margins and radius | +| Page from Bottom | full-height bottom sheet content | +| Top Sheet | `content-placement="top"` | +| Sheet with Stacking | `cap-sheet-stack` with depth variables | +| Sheet with Depth | `cap-sheet-outlet` and progress-driven transforms | +| Parallax Page | `cap-sheet-outlet` with `cap-scroll` progress | +| Page | full-viewport content entering from an edge | +| Lightbox | `content-placement="center"` with backdrop and media content | +| Persistent Sheet with Detent | `default-presented`, `swipe-dismissal="false"`, and `inert-outside="false"` | +| Card | compact centered sheet content | + +## Core API + +- `` owns presentation state, detents, placement, gestures, accessibility, and events. +- `` declares present, dismiss, toggle, and detent-step actions. +- `` positions the overlay and applies safe-area and keyboard offsets. +- `` renders a progress-synced backdrop. +- `` renders the sheet surface. +- `` provides drag and keyboard detent controls. +- `` coordinates stacked sheets. +- `` exposes sheet progress to page, depth, and parallax effects. +- `` and `` expose scroll progress and distance helpers. +- `setupSheet(element, options?)` configures a sheet from framework effects or lifecycle hooks. + +## Capacitor Layout Model + +The default sheet viewport reads `env(safe-area-inset-*)` and Capacitor-style `--safe-area-inset-*` fallback variables, then applies the selected edges as padding around the overlay. `safe-area="auto"` protects all edges; use `safe-area="bottom left right"` or `safe-area="none"` when a usecase needs different behavior. + +Keyboard handling is enabled by default. The sheet listens to `visualViewport` resize and scroll events, adds a keyboard offset to the viewport, and focuses controls with `preventScroll` so inputs stay visible above the software keyboard. + +The package runs in the web layer. It does not render native UIKit or Android bottom sheets, so your app keeps full styling control while still respecting the WebView constraints that matter in Capacitor. + +## Demos And Playgrounds + +Animated WebP demos for every supported usecase ship in the repository README. The examples are also available as StackBlitz playgrounds: + +- [React playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/react-app/src/main.tsx&startScript=stackblitz-react) +- [Vue playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/vue-app/src/App.vue&startScript=stackblitz-vue) +- [Angular playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/angular-app/src/app/app.component.ts&startScript=stackblitz-angular) +- [Svelte playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/svelte-app/src/App.svelte&startScript=stackblitz-svelte) +- [Solid playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/solid-app/src/main.tsx&startScript=stackblitz-solid) diff --git a/apps/web/src/config/plugins.ts b/apps/web/src/config/plugins.ts index 68e7e7e73..943fa72e8 100644 --- a/apps/web/src/config/plugins.ts +++ b/apps/web/src/config/plugins.ts @@ -23,6 +23,7 @@ const actionDefinitionRows = String.raw`@capgo/native-market|github.com/Cap-go|Deep link users directly to your app page on Google Play Store or Apple App Store|https://github.com/Cap-go/capacitor-native-market/|Native Market @capgo/capacitor-native-navigation|github.com/Cap-go|Render native navbars, tabbars, and transition shells over a full-screen Capacitor WebView|https://github.com/Cap-go/capacitor-native-navigation/|Native Navigation @capgo/capacitor-transitions|github.com/Cap-go|Add Ionic-style page transitions and iOS edge swipe-back gestures without Ionic UI|https://github.com/Cap-go/capacitor-transitions/|Transitions +@capgo/capacitor-sheets|github.com/Cap-go|Framework-agnostic sheets, drawers, dialogs, and overlay primitives optimized for Capacitor apps|https://github.com/Cap-go/capacitor-sheets/|Sheets @capgo/capacitor-native-biometric|github.com/Cap-go|Secure authentication using Face ID, Touch ID, and Android biometric APIs|https://github.com/Cap-go/capacitor-native-biometric/|Native Biometric @capgo/camera-preview|github.com/Cap-go|Display live camera feed as overlay with customizable controls and capture capabilities|https://github.com/Cap-go/capacitor-camera-preview/|Camera Preview @capgo/capacitor-updater|github.com/Cap-go|Deploy live updates instantly to your users without app store review delays|https://github.com/Cap-go/capacitor-updater/|Updater @@ -160,6 +161,7 @@ const pluginIconsByName: Record = { '@capgo/native-market': 'ArchiveBoxArrowDown', '@capgo/capacitor-native-navigation': 'DevicePhoneMobile', '@capgo/capacitor-transitions': 'ArrowsRightLeft', + '@capgo/capacitor-sheets': 'ArrowsPointingOut', '@capgo/capacitor-native-biometric': 'FingerPrint', '@capgo/camera-preview': 'Camera', '@capgo/capacitor-updater': 'ArrowPath', diff --git a/scripts/check-plugin-doc-mirrors.ts b/scripts/check-plugin-doc-mirrors.ts index 1c685bf04..ea3081c91 100644 --- a/scripts/check-plugin-doc-mirrors.ts +++ b/scripts/check-plugin-doc-mirrors.ts @@ -4,7 +4,7 @@ import { join, relative, resolve } from 'node:path' const canonicalRoot = resolve('apps/docs/src/content/docs/docs/plugins') const mirrorRoot = resolve('src/content/docs/docs/plugins') // These plugin docs intentionally exist in both docs trees and must stay byte-for-byte aligned. -const mirroredPluginDirs = ['contentsquare', 'live-activities', 'transitions', 'twilio-video', 'widget-kit'] as const +const mirroredPluginDirs = ['contentsquare', 'live-activities', 'sheets', 'transitions', 'twilio-video', 'widget-kit'] as const function listFiles(root: string): string[] { const entries = readdirSync(root, { withFileTypes: true }) diff --git a/src/content/docs/docs/plugins/sheets/getting-started.mdx b/src/content/docs/docs/plugins/sheets/getting-started.mdx new file mode 100644 index 000000000..9aab64acb --- /dev/null +++ b/src/content/docs/docs/plugins/sheets/getting-started.mdx @@ -0,0 +1,359 @@ +--- +title: Getting Started +description: Install @capgo/capacitor-sheets and add framework-agnostic sheets to a Capacitor app. +sidebar: + order: 2 +--- + +import { Steps, Aside } from '@astrojs/starlight/components'; + + +1. **Install the package** + + ```bash + npm install @capgo/capacitor-sheets + ``` + +2. **Register the web components** + + ```ts + import '@capgo/capacitor-sheets'; + ``` + +3. **Add the viewport setting for safe areas** + + ```html + + ``` + +4. **Render a sheet** + + ```html + Open route + + + + + + + + + Evening route + Choose a route and confirm pickup. + Done + + + + + ``` + + ```css + .route-sheet { + width: min(100%, 34em); + padding: 0 1.25em 1.25em; + } + ``` + + + + +## Capacitor Safe Areas + +Safe areas are enabled by default through `safe-area="auto"`. The sheet viewport reads both browser environment values and Capacitor fallback variables: + +```css +env(safe-area-inset-top) +env(safe-area-inset-bottom) +env(safe-area-inset-left) +env(safe-area-inset-right) +var(--safe-area-inset-top) +var(--safe-area-inset-bottom) +var(--safe-area-inset-left) +var(--safe-area-inset-right) +``` + +Choose the protected edges per sheet: + +```html + + + +``` + +For apps with overlay status bars or system bars, keep the native plugins responsible for exposing correct inset values: + +```ts +import type { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + plugins: { + StatusBar: { + overlaysWebView: true, + }, + Keyboard: { + resize: 'body', + resizeOnFullScreen: true, + }, + SystemBars: { + insetsHandling: 'css', + }, + }, +}; + +export default config; +``` + +Keyboard handling is controlled by `native-focus-scroll-prevention`, which defaults to `true`. Disable it only when your app already owns keyboard avoidance: + +```html + +``` + +## Imperative Control + +All framework helpers configure the same underlying custom element. You can also control a sheet directly: + +```ts +const sheet = document.querySelector('cap-sheet'); + +await sheet?.present(); +await sheet?.stepTo(2); +await sheet?.step('down'); +await sheet?.dismiss(); +``` + +Listen to events for controlled state, analytics, or coordinated animation: + +```ts +sheet?.addEventListener('cap-sheet-presented-change', (event) => { + console.log(event.detail.presented); +}); + +sheet?.addEventListener('cap-sheet-active-detent-change', (event) => { + console.log(event.detail.activeDetent); +}); + +sheet?.addEventListener('cap-sheet-travel', (event) => { + console.log(event.detail.progress); +}); +``` + +## React + +```tsx +import { useEffect, useRef } from 'react'; +import { setupSheet } from '@capgo/capacitor-sheets/react'; +import '@capgo/capacitor-sheets'; + +export function BookingSheet() { + const sheetRef = useRef(null); + + useEffect(() => { + if (!sheetRef.current) return; + + return setupSheet(sheetRef.current, { + detents: ['18em', '32em'], + contentPlacement: 'bottom', + onPresentedChange: ({ presented }) => console.log({ presented }), + }); + }, []); + + return ( + + Open + + + + + React sheet + + + + ); +} +``` + +Importing from `@capgo/capacitor-sheets/react` also registers JSX typings for the custom elements. If TypeScript still reports unknown tags, add a declaration file inside your source tree: + +```ts +// src/capgo-sheets.d.ts +import '@capgo/capacitor-sheets/react'; +``` + +## Vue + +```vue + + + +``` + +## Angular + +```ts +import { AfterViewInit, Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, ViewChild } from '@angular/core'; +import { setupSheet } from '@capgo/capacitor-sheets/angular'; +import '@capgo/capacitor-sheets'; + +@Component({ + selector: 'app-root', + standalone: true, + schemas: [CUSTOM_ELEMENTS_SCHEMA], + template: ` + + Open + + + + + Angular sheet + + + + `, +}) +export class AppComponent implements AfterViewInit { + @ViewChild('sheet', { static: true }) sheet?: ElementRef; + + ngAfterViewInit(): void { + if (this.sheet?.nativeElement) { + setupSheet(this.sheet.nativeElement, { + detents: ['18em', '32em'], + contentPlacement: 'bottom', + }); + } + } +} +``` + +## Svelte + +```svelte + + + + Open + + + + + Svelte sheet + + + +``` + +## Solid + +```tsx +import { onCleanup, onMount } from 'solid-js'; +import { setupSheet } from '@capgo/capacitor-sheets/solid'; +import '@capgo/capacitor-sheets'; + +export function BookingSheet() { + let sheetEl!: HTMLElement; + + onMount(() => { + const cleanup = setupSheet(sheetEl, { + detents: ['18em', '32em'], + contentPlacement: 'bottom', + }); + + onCleanup(cleanup); + }); + + return ( + + Open + + + + + Solid sheet + + + + ); +} +``` + +## Components + +| Element | Purpose | +| --- | --- | +| `cap-sheet` | Sheet state, detents, gestures, modal behavior, and events | +| `cap-sheet-trigger` | Declarative present, dismiss, toggle, and step actions | +| `cap-sheet-portal` | Optional body portal for overlay layering | +| `cap-sheet-view` | Fixed viewport host with safe-area and keyboard padding | +| `cap-sheet-backdrop` | Progress-synced backdrop | +| `cap-sheet-content` | Accessible sheet surface | +| `cap-sheet-bleeding-background` | Background extension for rounded edge sheets | +| `cap-sheet-handle` | Draggable and keyboard-accessible detent handle | +| `cap-sheet-title` | Accessible title | +| `cap-sheet-description` | Accessible description | +| `cap-sheet-special-wrapper` | Composition hook for detached sheets, cards, and lightboxes | +| `cap-sheet-stack` | Stacked sheet grouping | +| `cap-sheet-outlet` | Progress outlet for depth, parallax, and page effects | +| `cap-scroll` | Scroll progress helper | +| `cap-fixed` | Fixed layer helper | +| `cap-island` | Related floating island content | +| `cap-external-overlay` | Overlay content managed outside the sheet tree | + +## Main Options + +| Option | Attribute | Default | Description | +| --- | --- | --- | --- | +| `contentPlacement` | `content-placement` | `bottom` | `top`, `bottom`, `left`, `right`, or `center` | +| `detents` | `detents` | none | Space-separated CSS lengths such as `18em 32em` | +| `safeArea` | `safe-area` | `auto` | Protected safe-area edges | +| `swipe` | `swipe` | `true` | Enable pointer, touch, trackpad, and wheel gestures | +| `swipeDismissal` | `swipe-dismissal` | `true` | Allow gestures to dismiss to detent `0` | +| `inertOutside` | `inert-outside` | `true` | Prevent interaction behind modal sheets | +| `focusTrap` | `focus-trap` | `true` | Keep keyboard focus inside the sheet | +| `closeOnOutsideClick` | `close-on-outside-click` | `true` | Dismiss when clicking the backdrop or view | +| `closeOnEscape` | `close-on-escape` | `true` | Dismiss when pressing Escape | +| `nativeFocusScrollPrevention` | `native-focus-scroll-prevention` | `true` | Keep focused inputs visible above the keyboard | +| `themeColorDimming` | `theme-color-dimming` | `auto` | Dim the WebView theme color while modal | + +## Available Entrypoints + +- `@capgo/capacitor-sheets` +- `@capgo/capacitor-sheets/react` +- `@capgo/capacitor-sheets/vue` +- `@capgo/capacitor-sheets/angular` +- `@capgo/capacitor-sheets/svelte` +- `@capgo/capacitor-sheets/solid` diff --git a/src/content/docs/docs/plugins/sheets/index.mdx b/src/content/docs/docs/plugins/sheets/index.mdx new file mode 100644 index 000000000..7b03ed05e --- /dev/null +++ b/src/content/docs/docs/plugins/sheets/index.mdx @@ -0,0 +1,109 @@ +--- +title: "@capgo/capacitor-sheets" +description: Framework-agnostic sheets, drawers, dialogs, scroll helpers, and overlay primitives for Capacitor apps. +tableOfContents: false +next: false +prev: false +sidebar: + order: 1 + label: "Introduction" +hero: + tagline: Build Silk-style sheets, drawers, dialogs, toasts, lightboxes, cards, and page overlays in any Capacitor frontend. + actions: + - text: Get started + link: /docs/plugins/sheets/getting-started/ + icon: right-arrow + variant: primary + - text: GitHub + link: https://github.com/Cap-go/capacitor-sheets/ + icon: external + variant: minimal +--- + +import { Card, CardGrid, Aside } from '@astrojs/starlight/components'; + + + + Use standards-based custom elements directly or use setup helpers for React, Vue, Angular, Svelte, and Solid. + + + Respect safe areas, keyboard movement, native edge gestures, and WebView theme-color dimming from the web layer. + + + Compose bottom sheets, side drawers, top sheets, centered dialogs, toasts, detached sheets, cards, pages, and lightboxes. + + + Author detents with `em`, `rem`, viewport units, `calc()`, and CSS variables while the default sizing stays `em` based. + + + +## When To Use It + +`@capgo/capacitor-sheets` is for Capacitor apps that need high-quality mobile overlays without adopting a specific UI framework. It ships as custom elements, so the core package has no React, Vue, Angular, Svelte, or Solid runtime dependency. + +Use it when you need: + +- bottom sheets with one or more detents +- left or right sidebars and top sheets +- centered dialogs, lightboxes, cards, and toast-like overlays +- persistent sheets that keep the app behind them interactive +- full-page overlays that enter from an edge +- stack, depth, and parallax effects driven by sheet progress +- scroll helpers that expose progress and distance values +- Capacitor-safe layout for notches, home indicators, Android cutouts, and software keyboards + + + +## Usecase Coverage + +| Usecase | Capgo Sheets pattern | +| --- | --- | +| Long Sheet | `cap-sheet` with natural content scroll or `cap-scroll` | +| Sheet with Detent | `detents="18em 32em"` plus `stepTo()` or a step trigger | +| Sidebar | `content-placement="left"` or `content-placement="right"` | +| Bottom Sheet | default `content-placement="bottom"` | +| Sheet with Keyboard | `native-focus-scroll-prevention` and visual viewport offset handling | +| Toast | `inert-outside="false"`, `focus-trap="false"`, and no outside-click dismissal | +| Detached Sheet | `cap-sheet-special-wrapper` plus custom margins and radius | +| Page from Bottom | full-height bottom sheet content | +| Top Sheet | `content-placement="top"` | +| Sheet with Stacking | `cap-sheet-stack` with depth variables | +| Sheet with Depth | `cap-sheet-outlet` and progress-driven transforms | +| Parallax Page | `cap-sheet-outlet` with `cap-scroll` progress | +| Page | full-viewport content entering from an edge | +| Lightbox | `content-placement="center"` with backdrop and media content | +| Persistent Sheet with Detent | `default-presented`, `swipe-dismissal="false"`, and `inert-outside="false"` | +| Card | compact centered sheet content | + +## Core API + +- `` owns presentation state, detents, placement, gestures, accessibility, and events. +- `` declares present, dismiss, toggle, and detent-step actions. +- `` positions the overlay and applies safe-area and keyboard offsets. +- `` renders a progress-synced backdrop. +- `` renders the sheet surface. +- `` provides drag and keyboard detent controls. +- `` coordinates stacked sheets. +- `` exposes sheet progress to page, depth, and parallax effects. +- `` and `` expose scroll progress and distance helpers. +- `setupSheet(element, options?)` configures a sheet from framework effects or lifecycle hooks. + +## Capacitor Layout Model + +The default sheet viewport reads `env(safe-area-inset-*)` and Capacitor-style `--safe-area-inset-*` fallback variables, then applies the selected edges as padding around the overlay. `safe-area="auto"` protects all edges; use `safe-area="bottom left right"` or `safe-area="none"` when a usecase needs different behavior. + +Keyboard handling is enabled by default. The sheet listens to `visualViewport` resize and scroll events, adds a keyboard offset to the viewport, and focuses controls with `preventScroll` so inputs stay visible above the software keyboard. + +The package runs in the web layer. It does not render native UIKit or Android bottom sheets, so your app keeps full styling control while still respecting the WebView constraints that matter in Capacitor. + +## Demos And Playgrounds + +Animated WebP demos for every supported usecase ship in the repository README. The examples are also available as StackBlitz playgrounds: + +- [React playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/react-app/src/main.tsx&startScript=stackblitz-react) +- [Vue playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/vue-app/src/App.vue&startScript=stackblitz-vue) +- [Angular playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/angular-app/src/app/app.component.ts&startScript=stackblitz-angular) +- [Svelte playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/svelte-app/src/App.svelte&startScript=stackblitz-svelte) +- [Solid playground](https://stackblitz.com/github/Cap-go/capacitor-sheets?file=examples/solid-app/src/main.tsx&startScript=stackblitz-solid)