duet-ui 0.2.4 → 0.3.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/dist/chrome.js +1 -1
- package/dist/duet.css +4 -0
- package/dist/geometry.d.ts +9 -0
- package/dist/geometry.js +18 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/chrome.js
CHANGED
|
@@ -118,7 +118,7 @@ function subscribe(cb) {
|
|
|
118
118
|
visualViewport?.removeEventListener("resize", on);
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
|
-
const ssr = { mode: "column", duo: true, browser: "safari", layout: "narrow", side: "right", width: 382, height: 580, offsetTop: 0, screenWidth: 466, screenHeight: 678, insetTop: 0, insetBottom: 0 };
|
|
121
|
+
const ssr = { mode: "column", duo: true, browser: "safari", device: "duo", standalone: false, layout: "narrow", side: "right", width: 382, height: 580, offsetTop: 0, screenWidth: 466, screenHeight: 678, insetTop: 0, insetBottom: 0 };
|
|
122
122
|
export function useDuet() {
|
|
123
123
|
return useSyncExternalStore(subscribe, read, () => ssr);
|
|
124
124
|
}
|
package/dist/duet.css
CHANGED
|
@@ -228,6 +228,10 @@ html:has(> body .duet-scroller), html:has(> body .duet-scroller) > body { height
|
|
|
228
228
|
edge, so there the scroller is an in-document box that runs on under the column. The document still never
|
|
229
229
|
scrolls, so the chrome layer never moves. */
|
|
230
230
|
html[data-duet-mode="column"] .duet-scroller { position: absolute; width: calc(100% + var(--duet-inset-right)); bottom: auto; height: calc(100% + var(--duet-inset-bottom)); }
|
|
231
|
+
/* That overflow widens the document, and touch-action on <html> stops at this scroll container, so without its own
|
|
232
|
+
a sideways swipe pans the whole page, chrome and all, into the column. Carousels inside are scrollers of their own
|
|
233
|
+
and still pan. */
|
|
234
|
+
html[data-duet-mode="column"] .duet-scroller { touch-action: pan-y; }
|
|
231
235
|
/* Safari's URL pill floats under the page's bottom edge: the scroller runs on under it (above) and this spacer lets
|
|
232
236
|
the last content scroll clear of it. */
|
|
233
237
|
.duet-scroller::after { content: ""; display: block; height: var(--duet-inset-bottom, 0px); }
|
package/dist/geometry.d.ts
CHANGED
|
@@ -109,6 +109,10 @@ export interface Context {
|
|
|
109
109
|
split?: boolean;
|
|
110
110
|
/** The browser the page runs in (see browserOf). Only Safari gets the column. */
|
|
111
111
|
browser: Browser;
|
|
112
|
+
/** The device the page runs on (see deviceOf). */
|
|
113
|
+
device: Device;
|
|
114
|
+
/** Opened from the Home Screen as a web app, not in a browser tab. */
|
|
115
|
+
standalone: boolean;
|
|
112
116
|
}
|
|
113
117
|
export type Layout = "narrow" | "wide";
|
|
114
118
|
/** Page width from which two panes fit. The page spans the window, controls floating over it: the open Duo gives
|
|
@@ -123,6 +127,11 @@ export type Browser = "safari" | "chrome" | "firefox" | "edge" | "webview" | "ot
|
|
|
123
127
|
/** Every iOS browser is WebKit; the others name themselves in the UA. An in-app web view (Instagram, Facebook)
|
|
124
128
|
* drops the "Safari/" token; the in-app Safari preview keeps it, and is Safari. */
|
|
125
129
|
export declare function browserOf(ua: string | undefined): Browser;
|
|
130
|
+
export type Device = "duo" | "iphone" | "ipad" | "android" | "desktop";
|
|
131
|
+
/** The Duo by its sizes (isDuo), other iOS devices by their screen's short side (an iPad's is 744pt or more,
|
|
132
|
+
* and iPadOS sends a Mac UA with touch), Android by its UA. Without a UA (an emulator's signals) only the
|
|
133
|
+
* sizes count. */
|
|
134
|
+
export declare function deviceOf(s: Signals): Device;
|
|
126
135
|
/** A Safari split-view pane: its window is 469x669 in either pane. Nothing tells the left pane from the right
|
|
127
136
|
* (device probe 2026-10-25: screenX, availLeft, insets, visualViewport and touch screenX read the same in both),
|
|
128
137
|
* though Safari's column sits on the pane's outer edge. So the inline side is remembered apart for split view. */
|
package/dist/geometry.js
CHANGED
|
@@ -75,6 +75,21 @@ export function browserOf(ua) {
|
|
|
75
75
|
return "safari";
|
|
76
76
|
return "other";
|
|
77
77
|
}
|
|
78
|
+
/** The Duo by its sizes (isDuo), other iOS devices by their screen's short side (an iPad's is 744pt or more,
|
|
79
|
+
* and iPadOS sends a Mac UA with touch), Android by its UA. Without a UA (an emulator's signals) only the
|
|
80
|
+
* sizes count. */
|
|
81
|
+
export function deviceOf(s) {
|
|
82
|
+
if (isDuo(s))
|
|
83
|
+
return "duo";
|
|
84
|
+
const ua = s.userAgent ?? "";
|
|
85
|
+
if (/iPad/.test(ua) || (isIOS(s) && Math.min(s.screenWidth, s.screenHeight) >= 700))
|
|
86
|
+
return "ipad";
|
|
87
|
+
if (isIOS(s))
|
|
88
|
+
return "iphone";
|
|
89
|
+
if (/Android/.test(ua))
|
|
90
|
+
return "android";
|
|
91
|
+
return "desktop";
|
|
92
|
+
}
|
|
78
93
|
/** A Safari split-view pane: its window is 469x669 in either pane. Nothing tells the left pane from the right
|
|
79
94
|
* (device probe 2026-10-25: screenX, availLeft, insets, visualViewport and touch screenX read the same in both),
|
|
80
95
|
* though Safari's column sits on the pane's outer edge. So the inline side is remembered apart for split view. */
|
|
@@ -91,12 +106,12 @@ const SAFARI_COLUMN = { width: [80, 88], chrome: [68, 102] };
|
|
|
91
106
|
const within = (v, [a, b]) => v >= a && v <= b;
|
|
92
107
|
/** preferred: the side the user picked for inline controls, if any. */
|
|
93
108
|
export function detect(s, preferred, allowColumn = true) {
|
|
94
|
-
const duo = isDuo(s), browser = browserOf(s.userAgent);
|
|
109
|
+
const duo = isDuo(s), browser = browserOf(s.userAgent), device = deviceOf(s), standalone = s.standalone;
|
|
95
110
|
// Only a Home Screen app owns the strip: a Safari tab reports the column as an 84pt inset for a frame while folding.
|
|
96
111
|
if (s.standalone && (s.insetRight >= 60 || s.insetLeft >= 60)) {
|
|
97
|
-
return { mode: "strip", duo, browser, layout: layoutOf(s.innerWidth), side: s.insetRight >= 60 ? "right" : "left", width: s.innerWidth, height: s.innerHeight, offsetTop: Math.max(0, s.screenHeight - s.innerHeight), screenWidth: s.screenWidth, screenHeight: s.screenHeight, insetTop: s.insetTop, insetBottom: s.insetBottom };
|
|
112
|
+
return { mode: "strip", duo, browser, device, standalone, layout: layoutOf(s.innerWidth), side: s.insetRight >= 60 ? "right" : "left", width: s.innerWidth, height: s.innerHeight, offsetTop: Math.max(0, s.screenHeight - s.innerHeight), screenWidth: s.screenWidth, screenHeight: s.screenHeight, insetTop: s.insetTop, insetBottom: s.insetBottom };
|
|
98
113
|
}
|
|
99
|
-
const base = { duo, browser, width: s.innerWidth, height: s.innerHeight, offsetTop: 0, insetTop: s.insetTop, insetBottom: s.insetBottom };
|
|
114
|
+
const base = { duo, browser, device, standalone, width: s.innerWidth, height: s.innerHeight, offsetTop: 0, insetTop: s.insetTop, insetBottom: s.insetBottom };
|
|
100
115
|
// Other iOS browsers draw their own chrome where Safari has its column: inline for them.
|
|
101
116
|
const column = allowColumn && !s.standalone && !s.framed && browser === "safari"
|
|
102
117
|
&& within(s.outerWidth - s.innerWidth, SAFARI_COLUMN.width)
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { Duet, DuoCookie, useDuet, type DuetProps, type DuetItem, type DuetTab }
|
|
|
2
2
|
export { bleed, column } from "./layout.ts";
|
|
3
3
|
export { DuetPanes, DuetPaneBar, usePanes, type DuetPanesProps, type DuetPaneBarProps } from "./duet-panes.tsx";
|
|
4
4
|
export { panes, backFrom, type PaneWindow } from "./panes.ts";
|
|
5
|
-
export { browserOf, detect, isDuo, isIOS, isSplit, plan, magnet, DUO, INLINE_WIDTH, MAGNET, WIDE, type Browser, type Context, type Layout, type Mode, type Plan, type Side, type Signals, type Spec } from "./geometry.ts";
|
|
5
|
+
export { browserOf, detect, deviceOf, isDuo, isIOS, isSplit, plan, magnet, DUO, INLINE_WIDTH, MAGNET, WIDE, type Browser, type Context, type Device, type Layout, type Mode, type Plan, type Side, type Signals, type Spec } from "./geometry.ts";
|
package/dist/index.js
CHANGED
|
@@ -2,4 +2,4 @@ export { Duet, DuoCookie, useDuet } from "./chrome.js";
|
|
|
2
2
|
export { bleed, column } from "./layout.js";
|
|
3
3
|
export { DuetPanes, DuetPaneBar, usePanes } from "./duet-panes.js";
|
|
4
4
|
export { panes, backFrom } from "./panes.js";
|
|
5
|
-
export { browserOf, detect, isDuo, isIOS, isSplit, plan, magnet, DUO, INLINE_WIDTH, MAGNET, WIDE } from "./geometry.js";
|
|
5
|
+
export { browserOf, detect, deviceOf, isDuo, isIOS, isSplit, plan, magnet, DUO, INLINE_WIDTH, MAGNET, WIDE } from "./geometry.js";
|
package/package.json
CHANGED