@synopackageland/ui 0.25.15 → 0.25.17

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.
@@ -1,8 +1,40 @@
1
- /** Whether this page runs in the phone app and may go back to its App list. */
2
- export declare function canCloseToShell(): boolean;
3
1
  /**
4
- * Asks the phone app to go back to its App list. Call it from a tap: the app
2
+ * The Package Land launcher (the "shell") as seen from an App page in it. Its
3
+ * Home request, `{ v: 1, type: 'close' }`, takes the user back to the
4
+ * launcher's home. Two shells offer it:
5
+ *
6
+ * - The phone app injects `window.SynoPkgNative` (SynoPkgNative v1) into a
7
+ * registered App's main frame only; its optional `features` lists the
8
+ * requests it understands beyond the v1 baseline, `close` among them. The
9
+ * request goes through the bridge's `post`.
10
+ * - The browser launcher opens each App in a same-origin frame named
11
+ * `synopkg-shell:1:<features>` (comma-separated, e.g. `synopkg-shell:1:close`).
12
+ * The request is posted to the parent window at this page's own origin.
13
+ *
14
+ * In a plain browser tab, a DSM window or any other frame there is no shell
15
+ * and nothing here offers anything. The shell honors a request only right
16
+ * after a tap, so call it from a click.
17
+ */
18
+ type CloseMessage = {
19
+ v: 1;
20
+ type: 'close';
21
+ };
22
+ type ShellBridge = {
23
+ protocol: number;
24
+ features?: readonly unknown[];
25
+ post(message: CloseMessage): void;
26
+ };
27
+ type ShellWindow = Pick<Window, 'name' | 'parent' | 'top' | 'location'> & {
28
+ SynoPkgNative?: Partial<ShellBridge>;
29
+ };
30
+ /** The name the browser launcher gives an App's frame, and the features it lists. */
31
+ export declare const SHELL_FRAME_PREFIX = "synopkg-shell:1:";
32
+ /** Whether this page runs in the launcher (phone app or browser) and may go back to its home. */
33
+ export declare function canCloseToShell(view?: ShellWindow | undefined): boolean;
34
+ /**
35
+ * Asks the launcher to go back to its home. Call it from a tap: the launcher
5
36
  * ignores a request without a recent user gesture. Returns false when there is
6
- * no phone app to ask.
37
+ * no launcher to ask.
7
38
  */
8
- export declare function closeToShell(): boolean;
39
+ export declare function closeToShell(view?: ShellWindow | undefined): boolean;
40
+ export {};
@@ -3,7 +3,7 @@
3
3
  "version": "2.11.0",
4
4
  "delivery": "bundled-patched-esm",
5
5
  "patchManifestSha256": "9c5b9c9a162fa584b4695a683368a4484b3ac6e70177fd063b77aa618c051627",
6
- "bundleSha256": "abe34cf2578a7517d653b2d5efb3338ecce0562d845477aefc6158a18df763b1",
6
+ "bundleSha256": "0613c4649ba3a597c7c6d972e93541034089c6176d953a0a7d2426dc0fe6165a",
7
7
  "sourceHashes": {
8
8
  "shared/useBodyScrollLock.js": "287bfb604318c4202769e4b5191896eaf0e52a952e1de898967cbe09467fcfda",
9
9
  "DismissableLayer/DismissableLayer.js": "3c8d248f0a32e01f89ca1f6202b1bb691bf5d0e4012a92535e161c35e69cdc32",
@@ -141,16 +141,46 @@ state keys are copied through). The Android back button or the iOS edge swipe
141
141
  calls `close` for the top surface only; closing by code removes the entry.
142
142
  Pass `enabled: false` where the surface is a popover or inside a DSM window.
143
143
 
144
- Inside the Package Land phone app, a root page also gets Back to the App list.
145
- The app's bridge (`window.SynoPkgNative`, protocol 1) lists `close` in its
146
- `features`; AppLayout then leads the phone bar with the shared back arrow, and
147
- a tap posts `{ v: 1, type: 'close' }`, which the app honors only right after a
148
- tap. A browser, a sub-page (which has its own Back) and anything wider than a
149
- phone never show it. When the page hides the bar (`phone-bar-title="none"`
150
- without a menu), the first `PageToolbar` or `SectionTabs` row on the page holds
151
- the button at its start, so it costs no row; with no such row the bar is drawn
152
- for it. The arrow is `app-layout/back-arrow.json`, a byte copy of the phone
153
- app's drawing; `tests/ShellBack.test.ts` pins its SHA-256, as the phone app
144
+ Inside the Package Land launcher, every page leads with Home, sub-pages
145
+ included: Home goes back to the launcher's home, as the launcher's own bars do.
146
+ Stepping back is the system Back's job (Android's back button, the browser's
147
+ back or swipe). The page finds the launcher in one of two ways:
148
+
149
+ - **Phone app.** Its bridge (`window.SynoPkgNative`, protocol 1) lists `close`
150
+ in its `features`. A tap posts `{ v: 1, type: 'close' }` through the bridge.
151
+ - **Browser launcher.** It opens the App in a same-origin frame named
152
+ `synopkg-shell:1:close` (`SHELL_FRAME_PREFIX` followed by its features,
153
+ comma-separated). A tap posts the same message to the parent window, at the
154
+ page's own origin.
155
+
156
+ Either launcher honors the request only right after a tap. A plain browser
157
+ tab, a DSM window and anything wider than a phone never show Home; there a
158
+ sub-page keeps its Back arrow.
159
+
160
+ In the launcher, a sub-page has no Back button, so each one is a history entry
161
+ of the App (`useBackDismiss`):
162
+ - the layout's `back`, or a `PageHeader` with `back`, takes one entry while it
163
+ is shown;
164
+ - a `PushTransition` page already owns one.
165
+
166
+ The system Back pops that entry and runs the sub-page's back (`back`, or
167
+ `pop`). The launcher goes through an App's own entries before it leaves the
168
+ App: in the browser, the frame's entries come first in the tab's history; on
169
+ Android, the WebView's history comes first. A sub-page the App closes itself
170
+ takes its entry back off.
171
+
172
+ An App whose sub-pages are router addresses still works: the Back pops the
173
+ layout's entry, and the App's back handler then goes back through the
174
+ router.
175
+
176
+ AppLayout leads the phone bar with a 44px home icon; on a sub-page it comes
177
+ before the sub-page's title. When a root page hides the
178
+ bar (`phone-bar-title="none"` without a menu), the first `PageToolbar` or
179
+ `SectionTabs` row on the page holds the button at its start, so it costs no
180
+ row. With no such row the bar is drawn for it.
181
+
182
+ A sub-page's Back draws `app-layout/back-arrow.json`, a byte copy of the phone
183
+ app's drawing. `tests/ShellBack.test.ts` pins its SHA-256, as the phone app
154
184
  does, so change both copies together.
155
185
 
156
186
  `node scripts/check-keyboard.mjs [out-dir]` (after `pnpm build`) checks all of
package/docs/ux-grid.md CHANGED
@@ -20,13 +20,35 @@ props (`getEditText`, `cell-commit`); cell painters are in `useGridCells`.
20
20
  | Shift+click, Shift+arrow | Keep the anchor, move the head; Cmd/Ctrl+Shift+arrow jumps to the edge |
21
21
  | Cmd/Ctrl+A | All cells |
22
22
  | Column header click / Shift / Cmd | Select columns, extend, toggle |
23
- | Row checkbox / Shift, corner checkbox | Select rows, a run of rows, all rows |
23
+ | Row checkbox / Shift, corner checkbox | Select rows, a run of rows, all rows (a click on the row number opens the record: see Row header) |
24
24
  | Esc | Keeps the selection; cancels a drag, a resize or a fill in progress |
25
25
 
26
26
  Hit-testing is arithmetic over cached column offsets and row heights: a
27
27
  pointer move reads nothing from the DOM. Past the last column or row, over a
28
28
  header or over blank space, a drag head clamps to the nearest data cell.
29
29
 
30
+ ## Row header
31
+
32
+ The row header shows the row number; on hover or on a checked row its
33
+ `rowControls` replace the number.
34
+
35
+ | Click (mouse or pen) | Result |
36
+ |---|---|
37
+ | The row number (the header outside its controls) | Emits `row-expand(row)`: open the record, as the `expand` control and Space on a selected cell do. Pointer cursor |
38
+ | The checkbox | Toggles the row in the selection, as before (Shift selects a run). Never opens the record |
39
+ | The expand control | `row-expand(row)` |
40
+
41
+ Fallback: with no `row-expand` listener bound, a click on the row number
42
+ keeps the old behaviour. It opens nothing and changes no selection, and the
43
+ cursor stays the default. Apps that do not open records are unaffected. With
44
+ only a `checkbox` control the checkbox sits where the number is drawn, so a
45
+ click there selects. `GridHostController` asks the optional
46
+ `canExpandRow()` hook at click time; `GridHost` answers it from its listeners.
47
+
48
+ The row header takes no keyboard focus: the grid's one focus owner sits on the
49
+ active cell. To open a record from the keyboard, press Space on a selected
50
+ cell.
51
+
30
52
  `selectionBlock(state, { rowCount, columnCount })` gives the rows and columns
31
53
  a selection covers (a row selection covers every column, a column selection
32
54
  every row); `cellRange` gives the rectangle of a cell selection.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/ui",
3
- "version": "0.25.15",
3
+ "version": "0.25.17",
4
4
  "description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
5
5
  "license": "MIT",
6
6
  "type": "module",