@yourrealm/bottom-sheet 0.0.0-stage → 0.1.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.
@@ -0,0 +1,113 @@
1
+ /*
2
+ * @yourrealm/bottom-sheet/styled: the preset look, plus the structural CSS it builds on. Import it once, before
3
+ * Tailwind: @import "@yourrealm/bottom-sheet/styled.css";
4
+ */
5
+ @import "./styles.css";
6
+ /*
7
+ * The polished preset. Override with the --ybs-* tokens.
8
+ * Light/dark follow the app's `color-scheme` (inherited from <html>), via light-dark(): an app with its own theme
9
+ * switch that sets `color-scheme` gets a matching sheet; `html { color-scheme: light dark }` follows the OS.
10
+ */
11
+ @layer ybs {
12
+ :root { --ybs-css-styled: 1; }
13
+ [data-ybs-root] {
14
+ --ybs-sheet-bg: light-dark(#fff, #1c1c1e);
15
+ --ybs-sheet-fg: light-dark(#111, #f2f2f7);
16
+ --ybs-muted: light-dark(#6b6b70, #98989f);
17
+ --ybs-handle: light-dark(rgba(60, 60, 67, 0.3), rgba(235, 235, 245, 0.3));
18
+ --ybs-divider: light-dark(rgba(60, 60, 67, 0.12), rgba(235, 235, 245, 0.12));
19
+ --ybs-radius: 14px;
20
+ /* Side padding of the body, matching the header. 0 for edge-to-edge lists that pad their own rows. */
21
+ --ybs-body-padding: 16px;
22
+ --ybs-backdrop: #000;
23
+ --ybs-backdrop-max: 0.4;
24
+ --ybs-max-width: 640px;
25
+ --ybs-content-width: 960px;
26
+ --ybs-float-gap: 8px;
27
+ --ybs-float-radius: 32px;
28
+ /* 1 within the last 10% of travel to full, else 0..: corners square off as a fullscreen sheet reaches the top. */
29
+ --ybs-at-top: clamp(0, (var(--ybs-progress, 0) - 0.9) * 10, 1);
30
+ }
31
+ .ybs-backdrop {
32
+ background: var(--ybs-backdrop);
33
+ opacity: calc(var(--ybs-progress, 0) * var(--ybs-backdrop-max));
34
+ }
35
+ .ybs-bleed { background: var(--ybs-sheet-bg); }
36
+ /* Stacked sheets: the covered sheet recedes (scales back and lifts slightly), like iOS. */
37
+ .ybs-view { transform-origin: 50% 0; transition: none; }
38
+ [data-ybs-root][data-ybs-covered] .ybs-view {
39
+ transform: translateY(calc(var(--ybs-covered, 0) * -6px)) scale(calc(1 - var(--ybs-covered, 0) * 0.06));
40
+ border-radius: var(--ybs-radius);
41
+ }
42
+ [data-ybs-root][data-ybs-covered] .ybs-bleed { opacity: 0; }
43
+ .ybs-sheet {
44
+ background: var(--ybs-sheet-bg);
45
+ color: var(--ybs-sheet-fg);
46
+ border-radius: var(--ybs-radius) var(--ybs-radius) 0 0;
47
+ box-shadow: 0 -1px 0 var(--ybs-divider), 0 -8px 30px rgba(0, 0, 0, 0.08);
48
+ padding-bottom: env(safe-area-inset-bottom, 0px);
49
+ font-family: system-ui, -apple-system, sans-serif;
50
+ max-width: var(--ybs-max-width); margin-inline: auto;
51
+ }
52
+ /* Full width: the surface spans the window; header and body keep their full width (no corner seams) but pad
53
+ their contents into a readable centred column. */
54
+ .ybs-sheet.ybs-sheet-full { max-width: none; }
55
+ .ybs-sheet-full > .ybs-header { padding-inline: max(16px, (100% - var(--ybs-content-width)) / 2); }
56
+ .ybs-sheet-full > .ybs-body { padding-inline: max(var(--ybs-body-padding), (100% - var(--ybs-content-width)) / 2); }
57
+ /* A page sheet sits lower than the receded page's top edge (+10px), so a strip of that page shows above it, like iOS. */
58
+ [data-ybs-root]:has(.ybs-sheet-page):not([data-ybs-fullscreen]) { --ybs-inset: calc(env(safe-area-inset-top, 0px) + 22px); }
59
+ /* A page sheet fills the screen at full even when its content is short (no fit-content). */
60
+ .ybs-sheet.ybs-sheet-page { min-height: calc(var(--ybs-vv-h, 100dvh) - var(--ybs-inset)); }
61
+ /* Header bar: leading | title | trailing, the title centred like an iOS navigation bar. */
62
+ .ybs-bar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px; }
63
+ .ybs-bar > .ybs-title { text-align: center; }
64
+ .ybs-leading { justify-self: start; }
65
+ .ybs-trailing { justify-self: end; }
66
+ /* Floating (iOS 26): at lower detents the sheet floats, inset from the sides and the bottom with large corners;
67
+ over the last quarter of the travel to full it attaches (the gap closes, the bottom corners slide off-screen).
68
+ A clip-path, so nothing reflows while the sheet moves. --ybs-visible is the on-screen height of the sheet, so
69
+ 100% - visible is the part below the screen edge. */
70
+ .ybs-sheet.ybs-sheet-floating {
71
+ --ybs-float: calc(1 - clamp(0, (var(--ybs-progress, 0) - 0.75) * 4, 1));
72
+ --ybs-g: calc(var(--ybs-float-gap) * var(--ybs-float));
73
+ --ybs-rt: calc(var(--ybs-radius) + (var(--ybs-float-radius) - var(--ybs-radius)) * var(--ybs-float));
74
+ --ybs-rb: calc(var(--ybs-float-radius) * var(--ybs-float));
75
+ clip-path: inset(0 var(--ybs-g) calc((100% - var(--ybs-visible, 0px)) * var(--ybs-float) + var(--ybs-g)) var(--ybs-g)
76
+ round var(--ybs-rt) var(--ybs-rt) var(--ybs-rb) var(--ybs-rb));
77
+ }
78
+ /* Fullscreen: square corners at the top (they would show the page through), header clear of the notch. */
79
+ [data-ybs-fullscreen] .ybs-sheet, [data-ybs-fullscreen] .ybs-header {
80
+ --ybs-r: calc(var(--ybs-radius) * (1 - var(--ybs-at-top)));
81
+ border-radius: var(--ybs-r) var(--ybs-r) 0 0;
82
+ }
83
+ [data-ybs-fullscreen] .ybs-header { padding-top: calc(6px + env(safe-area-inset-top, 0px)); }
84
+ .ybs-header {
85
+ background: var(--ybs-sheet-bg);
86
+ border-radius: var(--ybs-radius) var(--ybs-radius) 0 0;
87
+ padding: 6px 16px 12px;
88
+ border-bottom: 1px solid var(--ybs-divider);
89
+ /* Content scrolls under this sticky header; at fractional positions (device scaling, or a covered
90
+ sheet's scale) a 1px sliver of it can show above. Cover it with the sheet colour. */
91
+ box-shadow: 0 -2px 0 0 var(--ybs-sheet-bg);
92
+ }
93
+ .ybs-handle {
94
+ width: 36px; height: 5px; border-radius: 3px;
95
+ background: var(--ybs-handle);
96
+ margin: 0 auto 10px;
97
+ }
98
+ .ybs-title { margin: 0; font-size: 17px; font-weight: 600; line-height: 1.3; }
99
+ .ybs-description { margin: 4px 0 0; font-size: 14px; color: var(--ybs-muted); }
100
+ .ybs-body { padding: 0 var(--ybs-body-padding) 12px; }
101
+ /* The page behind recedes (Sheet.Root recede + data-ybs-background on the app wrapper), like iOS: it scales back
102
+ from the top of the screen, drops below the status bar and rounds its top corners over black. The wrapper needs
103
+ its own background (html and body turn black). */
104
+ /* !important: our layer loses to the app's own unlayered html/body background, and this must win while receding. */
105
+ html[data-ybs-recede]:has([data-ybs-background]), html[data-ybs-recede]:has([data-ybs-background]) body { background: #000 !important; }
106
+ html[data-ybs-recede] [data-ybs-background] {
107
+ /* Like iOS, a sheet covering half the screen only dims the page; it recedes as the sheet covers the screen. */
108
+ --ybs-r: clamp(0, (var(--ybs-recede, 0) - 0.6) * 2.5, 1);
109
+ transform-origin: 50% var(--ybs-scroll-y, 0px);
110
+ transform: translateY(calc(var(--ybs-r) * (env(safe-area-inset-top, 0px) + 10px))) scale(calc(1 - var(--ybs-r) * 0.07));
111
+ clip-path: inset(var(--ybs-scroll-y, 0px) 0 0 0 round calc(var(--ybs-r) * 12px) calc(var(--ybs-r) * 12px) 0 0);
112
+ }
113
+ }
@@ -0,0 +1,65 @@
1
+
2
+ import { a as OpenChangeDetails, c as PortalProps, d as Trigger, f as TriggerProps, g as Detent, i as InteractionType, l as Root, m as ViewProps, n as ContentProps, o as OpenChangeReason, p as TriggerRenderProps, r as InitialFocus, s as Portal, t as Close, u as RootProps } from "./sheet-BOTt16RW.js";
3
+ import { ComponentPropsWithRef, ReactElement, ReactNode } from "react";
4
+ /** Styled parts: same API as the headless `Sheet`, with the preset look. */
5
+ export declare const Sheet: {
6
+ Root: typeof Root;
7
+ Trigger: typeof Trigger;
8
+ Close: typeof Close;
9
+ Portal: typeof Portal;
10
+ Backdrop: (p: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => import("react").JSX.Element;
11
+ View: (p: ViewProps) => import("react").JSX.Element;
12
+ Content: (p: ContentProps) => import("react").JSX.Element;
13
+ Header: (p: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => import("react").JSX.Element;
14
+ Handle: (p: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => import("react").JSX.Element;
15
+ Title: (p: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => import("react").JSX.Element;
16
+ Description: (p: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>) => import("react").JSX.Element;
17
+ };
18
+ export interface BottomSheetProps extends Omit<RootProps, 'children'> {
19
+ /**
20
+ * What opens the sheet. Content (text, elements) is placed inside our trigger button. A function renders your own
21
+ * button instead: `trigger={(props) => <Button variant="paper" {...props}>Open</Button>}` (it receives `type`,
22
+ * `onClick` and the ARIA state; put className, disabled, aria-label on your button).
23
+ */
24
+ trigger?: ReactNode | ((props: TriggerRenderProps) => ReactElement);
25
+ title: ReactNode;
26
+ description?: ReactNode;
27
+ /**
28
+ * - `'sheet'` (default): detents as given, a card-width sheet.
29
+ * - `'page'`: an iOS-style page sheet for a task (compose, edit): opens straight to full,
30
+ * spans the full width (`width` default `'full'`), and the page behind recedes (`recede` default true; mark your
31
+ * app wrapper with `data-ybs-background`). Pair it with `leading` / `trailing` (Cancel / Save).
32
+ */
33
+ variant?: 'sheet' | 'page';
34
+ /**
35
+ * - `'card'` (default for `sheet`): the sheet is at most 640px wide (`--ybs-max-width`), centred.
36
+ * - `'full'` (default for `page`): the sheet spans the window; its header and body stay in a centred column
37
+ * (`--ybs-content-width`, default 960px).
38
+ */
39
+ width?: 'card' | 'full';
40
+ /**
41
+ * iOS 26 style: at lower detents the sheet floats (inset from the screen edges, large corners) and attaches as it
42
+ * reaches full. Tokens: --ybs-float-gap (8px), --ybs-float-radius (32px).
43
+ */
44
+ floating?: boolean;
45
+ /** Header bar slots, iOS navigation-bar style: e.g. `leading={<Sheet.Close>Cancel</Sheet.Close>}`. The title centres between them. */
46
+ leading?: ReactNode;
47
+ trailing?: ReactNode;
48
+ /** Extra content placed in the sticky header under the title (e.g. a search field). */
49
+ headerExtra?: ReactNode;
50
+ /**
51
+ * Where focus goes when the sheet opens, like Base UI's: an element ref, `false`, `true` (the sheet), or a function
52
+ * of how it was opened, e.g. `(type) => type !== 'touch' && saveRef.current`. Default: the sheet for a modal sheet,
53
+ * nothing for a non-modal one.
54
+ */
55
+ initialFocus?: InitialFocus;
56
+ children?: ReactNode;
57
+ className?: string;
58
+ contentProps?: ComponentPropsWithRef<'section'>;
59
+ }
60
+ /**
61
+ * The simple path:
62
+ * <BottomSheet trigger="Open" title="Settings">…</BottomSheet>
63
+ */
64
+ export declare function BottomSheet({ trigger, title, description, variant, floating, width, leading, trailing, headerExtra, initialFocus, children, className, contentProps, ...rootProps }: BottomSheetProps): import("react").JSX.Element;
65
+ export type { ContentProps, Detent, InitialFocus, InteractionType, OpenChangeDetails, OpenChangeReason, PortalProps, RootProps, TriggerProps, TriggerRenderProps, ViewProps };
package/dist/styled.js ADDED
@@ -0,0 +1,78 @@
1
+ 'use client';
2
+ import { a as Handle, c as Root, d as View, i as Description, l as Title, n as Close, o as Header, p as checkCss, r as Content, s as Portal, t as Backdrop, u as Trigger } from "./sheet-BgvWfCR8.js";
3
+ import { useEffect } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/styled/index.tsx
6
+ const cx = (...c) => c.filter(Boolean).join(" ");
7
+ function withClass(Comp, cls) {
8
+ return (p) => /* @__PURE__ */ jsx(Comp, {
9
+ ...p,
10
+ className: cx(cls, p.className)
11
+ });
12
+ }
13
+ /** Styled parts: same API as the headless `Sheet`, with the preset look. */
14
+ const Sheet = {
15
+ Root,
16
+ Trigger,
17
+ Close,
18
+ Portal,
19
+ Backdrop: withClass(Backdrop, "ybs-backdrop"),
20
+ View: (p) => {
21
+ useEffect(() => checkCss("styled", "styled.css"), []);
22
+ return /* @__PURE__ */ jsx(View, {
23
+ ...p,
24
+ className: cx("ybs-view", p.className),
25
+ bleedClassName: cx("ybs-bleed", p.bleedClassName)
26
+ });
27
+ },
28
+ Content: withClass(Content, "ybs-sheet"),
29
+ Header: withClass(Header, "ybs-header"),
30
+ Handle: withClass(Handle, "ybs-handle"),
31
+ Title: withClass(Title, "ybs-title"),
32
+ Description: withClass(Description, "ybs-description")
33
+ };
34
+ /**
35
+ * The simple path:
36
+ * <BottomSheet trigger="Open" title="Settings">…</BottomSheet>
37
+ */
38
+ function BottomSheet({ trigger, title, description, variant = "sheet", floating = false, width = variant === "page" ? "full" : "card", leading, trailing, headerExtra, initialFocus, children, className, contentProps, ...rootProps }) {
39
+ const root = variant === "page" ? {
40
+ recede: true,
41
+ ...rootProps
42
+ } : rootProps;
43
+ const bar = leading != null || trailing != null;
44
+ return /* @__PURE__ */ jsxs(Sheet.Root, {
45
+ ...root,
46
+ children: [typeof trigger === "function" ? /* @__PURE__ */ jsx(Sheet.Trigger, { render: trigger }) : trigger != null && /* @__PURE__ */ jsx(Sheet.Trigger, {
47
+ className: "ybs-trigger",
48
+ children: trigger
49
+ }), /* @__PURE__ */ jsxs(Sheet.Portal, { children: [root.modal !== false && /* @__PURE__ */ jsx(Sheet.Backdrop, {}), /* @__PURE__ */ jsx(Sheet.View, { children: /* @__PURE__ */ jsxs(Sheet.Content, {
50
+ ...contentProps,
51
+ initialFocus,
52
+ className: cx(width === "full" && "ybs-sheet-full", variant === "page" && "ybs-sheet-page", floating && "ybs-sheet-floating", className, contentProps?.className),
53
+ children: [/* @__PURE__ */ jsxs(Sheet.Header, { children: [
54
+ /* @__PURE__ */ jsx(Sheet.Handle, {}),
55
+ bar ? /* @__PURE__ */ jsxs("div", {
56
+ className: "ybs-bar",
57
+ children: [
58
+ /* @__PURE__ */ jsx("div", {
59
+ className: "ybs-leading",
60
+ children: leading
61
+ }),
62
+ /* @__PURE__ */ jsx(Sheet.Title, { children: title }),
63
+ /* @__PURE__ */ jsx("div", {
64
+ className: "ybs-trailing",
65
+ children: trailing
66
+ })
67
+ ]
68
+ }) : /* @__PURE__ */ jsx(Sheet.Title, { children: title }),
69
+ description != null && /* @__PURE__ */ jsx(Sheet.Description, { children: description }),
70
+ headerExtra
71
+ ] }), /* @__PURE__ */ jsx("div", {
72
+ className: "ybs-body",
73
+ children
74
+ })]
75
+ }) })] })]
76
+ });
77
+ }
78
+ export { BottomSheet, Sheet };
@@ -0,0 +1,97 @@
1
+ /*
2
+ * @yourrealm/bottom-sheet: structural CSS (the mechanics: overlay, scroller, snapping). Import it once, before
3
+ * Tailwind: @import "@yourrealm/bottom-sheet/styles.css"; (or styled.css, which includes it).
4
+ * Everything is in the `ybs` cascade layer, ordered between Tailwind v4's `base` and `components`, so preflight
5
+ * can't reset it and your utilities and unlayered CSS win. The order statement only counts if this comes first.
6
+ */
7
+ /*
8
+ * Structural CSS only: the mechanics that make the single-scroller sheet work.
9
+ * No colours, radii or spacing; those belong to the consumer or `/styled`.
10
+ *
11
+ * CSS variables set by the controller on [data-ybs-root]:
12
+ * --ybs-h available height (px)
13
+ * --ybs-vv-top visualViewport.offsetTop (px)
14
+ * --ybs-vv-h visualViewport.height (px)
15
+ * --ybs-progress 0..1, closed -> full
16
+ * --ybs-visible px of the sheet on screen (scrollTop, capped at full)
17
+ * --ybs-bleed 0|1, whether the bleed (sheet colour under the visual viewport) shows
18
+ * Consumer-settable:
19
+ * --ybs-inset gap above the sheet at the full detent (default: safe area + 10px; 0 with fullscreen)
20
+ * --ybs-sheet-bg colour of the bleed, should match the sheet
21
+ */
22
+ @layer theme, base, ybs, components, utilities;
23
+ @layer ybs {
24
+ /* Marker: tells the library this file is loaded (it logs an error when a sheet opens without it). */
25
+ :root { --ybs-css-core: 1; }
26
+ [data-ybs-root] {
27
+ --ybs-inset: calc(env(safe-area-inset-top, 0px) + 10px);
28
+ position: fixed; inset: 0; z-index: 50; pointer-events: none;
29
+ }
30
+ [data-ybs-root][data-ybs-fullscreen] { --ybs-inset: 0px; }
31
+ /* Fullscreen means the full detent covers the screen, even with short content. */
32
+ [data-ybs-root][data-ybs-fullscreen] [data-ybs-sheet] { min-height: calc(var(--ybs-vv-h, 100dvh) - var(--ybs-inset)); }
33
+ [data-ybs-backdrop] {
34
+ position: fixed; left: 0; right: 0; top: var(--ybs-vv-top, 0px); height: 200lvh;
35
+ pointer-events: auto;
36
+ }
37
+ [data-ybs-bleed] {
38
+ position: fixed; left: 0; right: 0; height: 100lvh;
39
+ top: calc(var(--ybs-vv-top, 0px) + var(--ybs-vv-h, 100dvh));
40
+ background: var(--ybs-sheet-bg, Canvas);
41
+ opacity: var(--ybs-bleed, 0);
42
+ }
43
+ [data-ybs-scroller] {
44
+ position: fixed; left: 0; right: 0;
45
+ top: calc(var(--ybs-vv-top, 0px) + var(--ybs-inset));
46
+ height: calc(var(--ybs-vv-h, 100dvh) - var(--ybs-inset));
47
+ overflow-y: auto;
48
+ overscroll-behavior: contain;
49
+ scroll-snap-type: y mandatory;
50
+ scrollbar-width: none;
51
+ pointer-events: auto;
52
+ }
53
+ [data-ybs-scroller]::-webkit-scrollbar { display: none; }
54
+ [data-ybs-root][data-ybs-drag] [data-ybs-scroller],
55
+ [data-ybs-root][data-ybs-glide] [data-ybs-scroller] { scroll-snap-type: none; }
56
+ [data-ybs-track] { position: relative; }
57
+ [data-ybs-spacer] { height: var(--ybs-h, 100dvh); touch-action: none; }
58
+ [data-ybs-markers] { position: absolute; top: 0; left: 0; width: 1px; height: 0; }
59
+ [data-ybs-marker] {
60
+ position: absolute; left: 0; width: 1px; height: 1px;
61
+ scroll-snap-align: start; pointer-events: none;
62
+ }
63
+ /* scroll-snap-stop: a fling may not skip the full position, in either direction. This is the native
64
+ way to stop momentum at the content top / full detent; the JS guard is only a fallback. (Firefox
65
+ Android: the JS overflow toggle made the next touch get swallowed as a "stop the fling" tap.) */
66
+ [data-ybs-sheet] { position: relative; scroll-snap-align: start; scroll-snap-stop: always; outline: none; }
67
+ [data-ybs-root][data-ybs-fit] [data-ybs-sheet] { scroll-snap-align: end; }
68
+ [data-ybs-header] { position: sticky; top: 0; z-index: 1; }
69
+ /* Content scrolled: a drag on the header moves the whole sheet (JS, "detached drag"), like native, instead of
70
+ scrolling the content back first. */
71
+ [data-ybs-root][data-ybs-scrolled] [data-ybs-drag] { touch-action: none; }
72
+ /* Non-modal: the layer lets taps, clicks and wheel through to the page; only the sheet takes them. A drag on
73
+ the sheet still scrolls the scroller (its scroll container), which is how the sheet moves. */
74
+ [data-ybs-root][data-ybs-modeless] [data-ybs-scroller] { pointer-events: none; }
75
+ [data-ybs-root][data-ybs-modeless] [data-ybs-sheet] { pointer-events: auto; }
76
+ /* iOS Safari won't scroll a pointer-events:none scroller from a touch on its pointer-events:auto child unless
77
+ there is a scroll container under the finger. Make each direct part of the sheet a 1px-wide horizontal
78
+ scroller (overflow-y stays clipped to its own height, so sticky headers keep sticking to the scroller); the
79
+ vertical drag then chains to the sheet scroller. WebKit touch only. */
80
+ @supports (-webkit-touch-callout: none) {
81
+ [data-ybs-root][data-ybs-modeless] [data-ybs-sheet] > * {
82
+ overflow-x: scroll; overflow-y: hidden; overscroll-behavior-x: none; scrollbar-width: none;
83
+ }
84
+ [data-ybs-root][data-ybs-modeless] [data-ybs-sheet] > *::-webkit-scrollbar { display: none; }
85
+ /* 1px of horizontal overflow, measured from the padding box so side padding can't absorb it. */
86
+ [data-ybs-root][data-ybs-modeless] [data-ybs-sheet] > *:not([data-ybs-header]) { position: relative; }
87
+ [data-ybs-root][data-ybs-modeless] [data-ybs-sheet] > *::after {
88
+ content: ''; position: absolute; top: 0; left: 0; width: calc(100% + 1px); height: 1px; pointer-events: none;
89
+ }
90
+ }
91
+ /* Stacked: a covered sheet is inert (set by the sheet above), so it can't be scrolled. Don't toggle its
92
+ overflow: Firefox re-snaps on overflow changes. The visual recede lives in /styled. */
93
+ @media (pointer: fine) {
94
+ [data-ybs-drag] { cursor: grab; user-select: none; -webkit-user-select: none; }
95
+ [data-ybs-root][data-ybs-drag="active"] [data-ybs-drag] { cursor: grabbing; }
96
+ }
97
+ }
package/package.json CHANGED
@@ -1,6 +1,65 @@
1
1
  {
2
2
  "name": "@yourrealm/bottom-sheet",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Native-feeling bottom sheet for the web. One native scroller for sheet travel and content.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/yourrealm/bottom-sheet.git",
9
+ "directory": "packages/bottom-sheet"
10
+ },
11
+ "homepage": "https://yourrealm.github.io/bottom-sheet/",
12
+ "bugs": "https://github.com/yourrealm/bottom-sheet/issues",
13
+ "keywords": [
14
+ "react",
15
+ "bottom-sheet",
16
+ "sheet",
17
+ "drawer",
18
+ "scroll-snap",
19
+ "mobile",
20
+ "headless"
21
+ ],
22
+ "type": "module",
23
+ "types": "./dist/index.d.ts",
24
+ "sideEffects": [
25
+ "*.css"
26
+ ],
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ },
37
+ "./styled": {
38
+ "types": "./dist/styled.d.ts",
39
+ "import": "./dist/styled.js"
40
+ },
41
+ "./package.json": "./package.json",
42
+ "./styles.css": "./dist/styles.css",
43
+ "./styled.css": "./dist/styled.css"
44
+ },
45
+ "peerDependencies": {
46
+ "react": ">=19",
47
+ "react-dom": ">=19"
48
+ },
49
+ "devDependencies": {
50
+ "@types/react": "^19.3.0",
51
+ "@types/react-dom": "^19.2.0",
52
+ "react": "^19.3.1",
53
+ "react-dom": "^19.3.1",
54
+ "tsdown": "^0.23.4",
55
+ "typescript": "^7.0.2",
56
+ "vitest": "^5.0.5"
57
+ },
58
+ "scripts": {
59
+ "build": "tsdown && node scripts/build-css.mjs",
60
+ "test": "vitest run",
61
+ "typecheck": "tsc -p .",
62
+ "pack:check": "node scripts/prepack.mjs && pnpm build && pnpm pack; rm -f README.md LICENSE",
63
+ "release": "node scripts/prepack.mjs && pnpm build && pnpm publish --access public; rm -f README.md LICENSE"
64
+ }
6
65
  }