@foldjs/svelte 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fold.js contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,183 @@
1
- # Temporary Holding Version
1
+ # fold.js
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **Make any web app foldable-ready.** Hinge-aware layouts for foldable phones — in React, Vue, Svelte, Solid, Angular… or plain HTML.
4
+
5
+ - 🪟 **Two-pane layouts** that put each pane on its own side of the hinge
6
+ - 📐 **Posture detection**: `flat`, `book`, `tabletop`, `folded`
7
+ - 🧪 **Built-in foldable simulator** — no device, no DevTools setup
8
+ - 🧩 **Works everywhere**: framework-agnostic core, thin adapters, Web Components, CSS-only layer
9
+ - 🪶 **~2 kB** min+gzip core, zero dependencies, SSR-safe, TypeScript
10
+
11
+ Built on the web standards shipping in Chromium: [CSS Viewport Segments](https://developer.mozilla.org/en-US/docs/Web/API/Viewport_segments_API) and the [Device Posture API](https://developer.mozilla.org/en-US/docs/Web/API/Device_Posture_API).
12
+
13
+ ---
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ npm i foldjs # core, CSS, Web Components, simulator
19
+ npm i @foldjs/react # or @foldjs/vue, @foldjs/svelte, @foldjs/solid
20
+ ```
21
+
22
+ ## React
23
+
24
+ ```tsx
25
+ import { TwoPane, FoldWhen, FoldDevtools, useFold } from "@foldjs/react";
26
+
27
+ export function Inbox() {
28
+ const { posture, hinge } = useFold();
29
+
30
+ return (
31
+ <>
32
+ <TwoPane
33
+ primary={<MailList />}
34
+ secondary={<MailDetail />}
35
+ fallback="stack" // single screen: "stack" | "primary" | "secondary"
36
+ />
37
+ <FoldWhen posture="tabletop">
38
+ <PlayerControls />
39
+ </FoldWhen>
40
+ {import.meta.env.DEV && <FoldDevtools initial="book" />}
41
+ </>
42
+ );
43
+ }
44
+ ```
45
+
46
+ ## Vue
47
+
48
+ ```vue
49
+ <script setup>
50
+ import { TwoPane, FoldWhen, useFold } from "@foldjs/vue";
51
+ const fold = useFold(); // fold.value.posture
52
+ </script>
53
+
54
+ <template>
55
+ <TwoPane fallback="stack">
56
+ <template #primary><MailList /></template>
57
+ <template #secondary><MailDetail /></template>
58
+ </TwoPane>
59
+ </template>
60
+ ```
61
+
62
+ ## Svelte
63
+
64
+ ```svelte
65
+ <script>
66
+ import { fold, twoPane, foldWhen } from "@foldjs/svelte";
67
+ </script>
68
+
69
+ <div use:twoPane={{ fallback: "stack" }}>
70
+ <div data-pane="primary"><MailList /></div>
71
+ <div data-pane="secondary"><MailDetail /></div>
72
+ </div>
73
+
74
+ <p>Posture: {$fold.posture}</p>
75
+ <div use:foldWhen={"tabletop"}>Tabletop only</div>
76
+ ```
77
+
78
+ ## Solid
79
+
80
+ ```tsx
81
+ import { createFold, twoPane } from "@foldjs/solid";
82
+
83
+ const fold = createFold(); // fold().posture
84
+
85
+ <div use:twoPane={{ fallback: "stack" }}>
86
+ <div data-pane="primary"><MailList /></div>
87
+ <div data-pane="secondary"><MailDetail /></div>
88
+ </div>
89
+ ```
90
+
91
+ ## Web Components (Angular, Lit, Astro, htmx, plain HTML…)
92
+
93
+ ```html
94
+ <script type="module">import "foldjs/elements";</script>
95
+
96
+ <fold-two-pane fallback="stack">
97
+ <div slot="primary">List</div>
98
+ <div slot="secondary">Detail</div>
99
+ </fold-two-pane>
100
+
101
+ <fold-when posture="tabletop book">Only on a split screen</fold-when>
102
+ ```
103
+
104
+ ## CSS only
105
+
106
+ ```js
107
+ import "foldjs/css";
108
+ import { init } from "foldjs";
109
+ init(); // optional: enables the simulator and non-native browsers
110
+ ```
111
+
112
+ ```html
113
+ <div class="fold-two-pane">
114
+ <div class="fold-primary">List</div>
115
+ <div class="fold-secondary">Detail</div>
116
+ </div>
117
+ <div class="fold-only-tabletop">Tabletop only</div>
118
+ ```
119
+
120
+ Variables available on `<html>`: `--fold-hinge-x|y|width|height`, `--fold-segment-0-width|height`, `--fold-segment-1-width|height`.
121
+ Attributes: `data-fold-posture`, `data-fold-spanning`.
122
+
123
+ ## The simulator
124
+
125
+ ```js
126
+ import { mountDevtools } from "foldjs/devtools";
127
+ mountDevtools({ initial: "book", position: "bottom-right", hingeSize: 24 });
128
+ ```
129
+
130
+ Switch between **Device / Flat / Book / Tabletop** from the floating panel, or press **Alt + Shift + F**.
131
+ Or drive it from code (tests, demos, Storybook): `simulate({ posture: "tabletop" })`, `simulate(null)`.
132
+
133
+ ## Core API
134
+
135
+ ```ts
136
+ import { getFold, subscribe, simulate, twoPaneLayout, bindTwoPane } from "foldjs";
137
+
138
+ getFold();
139
+ // {
140
+ // posture: "book", // "flat" | "book" | "tabletop" | "folded"
141
+ // spanning: "columns", // "none" | "columns" | "rows"
142
+ // isSpanned: true,
143
+ // segments: [{ x, y, width, height }, …],
144
+ // hinge: { x, y, width, height },
145
+ // devicePosture: "folded", // raw Device Posture API value
146
+ // viewport: { width, height },
147
+ // simulated: false
148
+ // }
149
+
150
+ const off = subscribe((state) => console.log(state.posture));
151
+ ```
152
+
153
+ Writing an adapter for another framework? `subscribe` + `getFold` are all you need; `twoPaneLayout(state)` returns the styles every built-in adapter uses.
154
+
155
+ ## Browser support
156
+
157
+ | | Native | With `foldjs` |
158
+ |---|---|---|
159
+ | Chrome / Edge on Android foldables | ✅ Viewport Segments + Device Posture | ✅ |
160
+ | Samsung Internet, other browsers | — | ✅ Single-screen fallback, simulator |
161
+ | Desktop | — | ✅ Simulator |
162
+
163
+ ## Repository
164
+
165
+ ```
166
+ packages/core foldjs core, CSS, Web Components, simulator
167
+ packages/react @foldjs/react
168
+ packages/vue @foldjs/vue
169
+ packages/svelte @foldjs/svelte
170
+ packages/solid @foldjs/solid
171
+ apps/demo demo site (Vite + React)
172
+ ```
173
+
174
+ ```bash
175
+ npm install
176
+ npm run dev # demo on http://localhost:5173
177
+ npm test
178
+ npm run build
179
+ ```
180
+
181
+ ## License
182
+
183
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ fold: () => fold,
24
+ foldWhen: () => foldWhen,
25
+ mountDevtools: () => import_devtools.mountDevtools,
26
+ simulate: () => import_foldjs2.simulate,
27
+ twoPane: () => twoPane
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_store = require("svelte/store");
31
+ var import_foldjs = require("foldjs");
32
+ var import_foldjs2 = require("foldjs");
33
+ var import_devtools = require("foldjs/devtools");
34
+ var fold = (0, import_store.readable)((0, import_foldjs.getFold)(), (set) => {
35
+ set((0, import_foldjs.getFold)());
36
+ return (0, import_foldjs.subscribe)(set);
37
+ });
38
+ function twoPane(node, options = {}) {
39
+ return (0, import_foldjs.bindTwoPane)(node, options);
40
+ }
41
+ function foldWhen(node, posture) {
42
+ let wanted = posture;
43
+ const paint = () => {
44
+ const list = Array.isArray(wanted) ? wanted : [wanted];
45
+ node.hidden = !list.includes((0, import_foldjs.getFold)().posture);
46
+ };
47
+ const unsubscribe = (0, import_foldjs.subscribe)(paint);
48
+ paint();
49
+ return {
50
+ update(next) {
51
+ wanted = next;
52
+ paint();
53
+ },
54
+ destroy: unsubscribe
55
+ };
56
+ }
57
+ // Annotate the CommonJS export names for ESM import in node:
58
+ 0 && (module.exports = {
59
+ fold,
60
+ foldWhen,
61
+ mountDevtools,
62
+ simulate,
63
+ twoPane
64
+ });
@@ -0,0 +1,24 @@
1
+ import { Readable } from 'svelte/store';
2
+ import { FoldState, Posture, TwoPaneOptions } from 'foldjs';
3
+ export { FoldState, Posture, Rect, Spanning, simulate } from 'foldjs';
4
+ export { mountDevtools } from 'foldjs/devtools';
5
+
6
+ /** Live foldable state: `$fold.posture`, `$fold.hinge`… */
7
+ declare const fold: Readable<FoldState>;
8
+ /**
9
+ * <div use:twoPane={{ fallback: "stack" }}>
10
+ * <div data-pane="primary">…</div>
11
+ * <div data-pane="secondary">…</div>
12
+ * </div>
13
+ */
14
+ declare function twoPane(node: HTMLElement, options?: TwoPaneOptions): {
15
+ update(next?: TwoPaneOptions): void;
16
+ destroy: () => void;
17
+ };
18
+ /** <div use:foldWhen={"tabletop"}>…</div> — hidden unless the posture matches. */
19
+ declare function foldWhen(node: HTMLElement, posture: Posture | Posture[]): {
20
+ update(next: Posture | Posture[]): void;
21
+ destroy: () => void;
22
+ };
23
+
24
+ export { fold, foldWhen, twoPane };
@@ -0,0 +1,24 @@
1
+ import { Readable } from 'svelte/store';
2
+ import { FoldState, Posture, TwoPaneOptions } from 'foldjs';
3
+ export { FoldState, Posture, Rect, Spanning, simulate } from 'foldjs';
4
+ export { mountDevtools } from 'foldjs/devtools';
5
+
6
+ /** Live foldable state: `$fold.posture`, `$fold.hinge`… */
7
+ declare const fold: Readable<FoldState>;
8
+ /**
9
+ * <div use:twoPane={{ fallback: "stack" }}>
10
+ * <div data-pane="primary">…</div>
11
+ * <div data-pane="secondary">…</div>
12
+ * </div>
13
+ */
14
+ declare function twoPane(node: HTMLElement, options?: TwoPaneOptions): {
15
+ update(next?: TwoPaneOptions): void;
16
+ destroy: () => void;
17
+ };
18
+ /** <div use:foldWhen={"tabletop"}>…</div> — hidden unless the posture matches. */
19
+ declare function foldWhen(node: HTMLElement, posture: Posture | Posture[]): {
20
+ update(next: Posture | Posture[]): void;
21
+ destroy: () => void;
22
+ };
23
+
24
+ export { fold, foldWhen, twoPane };
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ // src/index.ts
2
+ import { readable } from "svelte/store";
3
+ import { bindTwoPane, getFold, subscribe } from "foldjs";
4
+ import { simulate } from "foldjs";
5
+ import { mountDevtools } from "foldjs/devtools";
6
+ var fold = readable(getFold(), (set) => {
7
+ set(getFold());
8
+ return subscribe(set);
9
+ });
10
+ function twoPane(node, options = {}) {
11
+ return bindTwoPane(node, options);
12
+ }
13
+ function foldWhen(node, posture) {
14
+ let wanted = posture;
15
+ const paint = () => {
16
+ const list = Array.isArray(wanted) ? wanted : [wanted];
17
+ node.hidden = !list.includes(getFold().posture);
18
+ };
19
+ const unsubscribe = subscribe(paint);
20
+ paint();
21
+ return {
22
+ update(next) {
23
+ wanted = next;
24
+ paint();
25
+ },
26
+ destroy: unsubscribe
27
+ };
28
+ }
29
+ export {
30
+ fold,
31
+ foldWhen,
32
+ mountDevtools,
33
+ simulate,
34
+ twoPane
35
+ };
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "@foldjs/svelte",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Svelte bindings for Fold.js: a `fold` store and `use:twoPane` / `use:foldWhen` actions.",
5
+ "license": "MIT",
6
+ "author": "christophe77",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/christophe77/foldjs.git",
10
+ "directory": "packages/svelte"
11
+ },
12
+ "homepage": "https://github.com/christophe77/foldjs#readme",
13
+ "bugs": "https://github.com/christophe77/foldjs/issues",
14
+ "type": "module",
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "svelte": "./dist/index.js",
22
+ "import": "./dist/index.js",
23
+ "require": "./dist/index.cjs"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "sideEffects": false,
30
+ "keywords": [
31
+ "foldable",
32
+ "svelte",
33
+ "dual-screen",
34
+ "hinge",
35
+ "foldjs"
36
+ ],
37
+ "peerDependencies": {
38
+ "foldjs": "^0.1.0",
39
+ "svelte": ">=4"
40
+ },
41
+ "scripts": {
42
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean --external svelte --external foldjs",
43
+ "prepack": "node -e \"require('fs').copyFileSync('../../README.md','README.md')\""
44
+ }
45
+ }