@graview/primitives 0.1.17 → 0.1.19
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/README.md +5 -2
- package/dist/app-bar.d.ts +54 -1
- package/dist/app-bar.d.ts.map +1 -1
- package/dist/app-bar.js +277 -62
- package/dist/app-bar.js.map +1 -1
- package/dist/arrange-bar.d.ts +1 -1
- package/dist/arrange-bar.d.ts.map +1 -1
- package/dist/arrange-bar.js +48 -16
- package/dist/arrange-bar.js.map +1 -1
- package/dist/bar-panes-door.d.ts +8 -0
- package/dist/bar-panes-door.d.ts.map +1 -0
- package/dist/bar-panes-door.js +10 -0
- package/dist/bar-panes-door.js.map +1 -0
- package/dist/bar-panes.d.ts +3 -1
- package/dist/bar-panes.d.ts.map +1 -1
- package/dist/bar-panes.js +12 -5
- package/dist/bar-panes.js.map +1 -1
- package/dist/chat.d.ts +68 -30
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +206 -223
- package/dist/chat.js.map +1 -1
- package/dist/connections.d.ts +7 -1
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +13 -13
- package/dist/connections.js.map +1 -1
- package/dist/declared-lens-doors.d.ts +21 -3
- package/dist/declared-lens-doors.d.ts.map +1 -1
- package/dist/declared-lens-doors.js +62 -27
- package/dist/declared-lens-doors.js.map +1 -1
- package/dist/declared-lenses.d.ts.map +1 -1
- package/dist/declared-lenses.js +4 -7
- package/dist/declared-lenses.js.map +1 -1
- package/dist/default-view.d.ts +2 -0
- package/dist/default-view.d.ts.map +1 -1
- package/dist/default-view.js +10 -4
- package/dist/default-view.js.map +1 -1
- package/dist/default-views.d.ts.map +1 -1
- package/dist/default-views.js +195 -42
- package/dist/default-views.js.map +1 -1
- package/dist/draft-door.d.ts +3 -0
- package/dist/draft-door.d.ts.map +1 -0
- package/dist/draft-door.js +22 -0
- package/dist/draft-door.js.map +1 -0
- package/dist/draft-frame.d.ts +25 -0
- package/dist/draft-frame.d.ts.map +1 -0
- package/dist/draft-frame.js +69 -0
- package/dist/draft-frame.js.map +1 -0
- package/dist/editable.d.ts +35 -1
- package/dist/editable.d.ts.map +1 -1
- package/dist/editable.js +93 -23
- package/dist/editable.js.map +1 -1
- package/dist/figure.js +1 -1
- package/dist/figure.js.map +1 -1
- package/dist/find.d.ts.map +1 -1
- package/dist/find.js +46 -11
- package/dist/find.js.map +1 -1
- package/dist/frame.d.ts +8 -6
- package/dist/frame.d.ts.map +1 -1
- package/dist/frame.js +7 -5
- package/dist/frame.js.map +1 -1
- package/dist/index.d.ts +23 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -9
- package/dist/index.js.map +1 -1
- package/dist/lens/board.d.ts.map +1 -1
- package/dist/lens/board.js +7 -3
- package/dist/lens/board.js.map +1 -1
- package/dist/lens/calendar-dates.d.ts +2 -0
- package/dist/lens/calendar-dates.d.ts.map +1 -1
- package/dist/lens/calendar-dates.js +2 -0
- package/dist/lens/calendar-dates.js.map +1 -1
- package/dist/lens/calendar-drawing.d.ts +2 -2
- package/dist/lens/calendar-drawing.d.ts.map +1 -1
- package/dist/lens/calendar-drawing.js +1 -2
- package/dist/lens/calendar-drawing.js.map +1 -1
- package/dist/lens/calendar-options.d.ts +8 -1
- package/dist/lens/calendar-options.d.ts.map +1 -1
- package/dist/lens/calendar-options.js +5 -0
- package/dist/lens/calendar-options.js.map +1 -1
- package/dist/lens/calendar-spans.d.ts.map +1 -1
- package/dist/lens/calendar-spans.js +1 -2
- package/dist/lens/calendar-spans.js.map +1 -1
- package/dist/lens/calendar-view.d.ts +2 -1
- package/dist/lens/calendar-view.d.ts.map +1 -1
- package/dist/lens/calendar-view.js +4 -3
- package/dist/lens/calendar-view.js.map +1 -1
- package/dist/lens/columns.d.ts.map +1 -1
- package/dist/lens/columns.js +2 -2
- package/dist/lens/columns.js.map +1 -1
- package/dist/lens/coverage.d.ts.map +1 -1
- package/dist/lens/coverage.js +14 -10
- package/dist/lens/coverage.js.map +1 -1
- package/dist/lens/more.d.ts.map +1 -1
- package/dist/lens/more.js +2 -1
- package/dist/lens/more.js.map +1 -1
- package/dist/lens-keeping.d.ts +17 -0
- package/dist/lens-keeping.d.ts.map +1 -0
- package/dist/lens-keeping.js +127 -0
- package/dist/lens-keeping.js.map +1 -0
- package/dist/lines-key.d.ts +12 -0
- package/dist/lines-key.d.ts.map +1 -0
- package/dist/lines-key.js +74 -0
- package/dist/lines-key.js.map +1 -0
- package/dist/notice-place.d.ts +3 -3
- package/dist/notice-place.d.ts.map +1 -1
- package/dist/notice-place.js +6 -4
- package/dist/notice-place.js.map +1 -1
- package/dist/notices.d.ts +6 -0
- package/dist/notices.d.ts.map +1 -1
- package/dist/notices.js +7 -1
- package/dist/notices.js.map +1 -1
- package/dist/pages.d.ts +14 -8
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +14 -7
- package/dist/pages.js.map +1 -1
- package/dist/places.d.ts +0 -24
- package/dist/places.d.ts.map +1 -1
- package/dist/places.js +7 -3
- package/dist/places.js.map +1 -1
- package/dist/profile.d.ts +7 -1
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +35 -10
- package/dist/profile.js.map +1 -1
- package/dist/prose-editor.d.ts +9 -0
- package/dist/prose-editor.d.ts.map +1 -0
- package/dist/prose-editor.js +64 -0
- package/dist/prose-editor.js.map +1 -0
- package/dist/quick-relations.d.ts.map +1 -1
- package/dist/quick-relations.js +2 -2
- package/dist/quick-relations.js.map +1 -1
- package/dist/reader-lenses.d.ts +21 -0
- package/dist/reader-lenses.d.ts.map +1 -0
- package/dist/reader-lenses.js +27 -0
- package/dist/reader-lenses.js.map +1 -0
- package/dist/record-head.d.ts +28 -0
- package/dist/record-head.d.ts.map +1 -0
- package/dist/record-head.js +3 -0
- package/dist/record-head.js.map +1 -0
- package/dist/relation-key.d.ts +2 -0
- package/dist/relation-key.d.ts.map +1 -1
- package/dist/relation-key.js +14 -24
- package/dist/relation-key.js.map +1 -1
- package/dist/scene-bar.d.ts +29 -0
- package/dist/scene-bar.d.ts.map +1 -0
- package/dist/scene-bar.js +72 -0
- package/dist/scene-bar.js.map +1 -0
- package/dist/scene-css.d.ts.map +1 -1
- package/dist/scene-css.js +538 -0
- package/dist/scene-css.js.map +1 -1
- package/dist/scene-places.d.ts +37 -0
- package/dist/scene-places.d.ts.map +1 -0
- package/dist/scene-places.js +77 -0
- package/dist/scene-places.js.map +1 -0
- package/dist/scene.d.ts +5 -2
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +5 -1
- package/dist/scene.js.map +1 -1
- package/dist/seat-field.d.ts +58 -0
- package/dist/seat-field.d.ts.map +1 -0
- package/dist/seat-field.js +144 -0
- package/dist/seat-field.js.map +1 -0
- package/dist/seat-move.d.ts +32 -0
- package/dist/seat-move.d.ts.map +1 -0
- package/dist/seat-move.js +56 -0
- package/dist/seat-move.js.map +1 -0
- package/dist/seat-panel.d.ts +37 -0
- package/dist/seat-panel.d.ts.map +1 -0
- package/dist/seat-panel.js +131 -0
- package/dist/seat-panel.js.map +1 -0
- package/dist/seat.d.ts +20 -58
- package/dist/seat.d.ts.map +1 -1
- package/dist/seat.js +28 -45
- package/dist/seat.js.map +1 -1
- package/dist/seeding.d.ts.map +1 -1
- package/dist/seeding.js +4 -4
- package/dist/seeding.js.map +1 -1
- package/dist/shell.d.ts +25 -21
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +46 -116
- package/dist/shell.js.map +1 -1
- package/dist/spec-views.d.ts +9 -2
- package/dist/spec-views.d.ts.map +1 -1
- package/dist/spec-views.js +55 -6
- package/dist/spec-views.js.map +1 -1
- package/dist/subject.d.ts +19 -0
- package/dist/subject.d.ts.map +1 -0
- package/dist/subject.js +159 -0
- package/dist/subject.js.map +1 -0
- package/dist/text-body.d.ts +28 -0
- package/dist/text-body.d.ts.map +1 -0
- package/dist/text-body.js +64 -0
- package/dist/text-body.js.map +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +6 -523
- package/dist/theme.js.map +1 -1
- package/dist/view-doors.d.ts +5 -1
- package/dist/view-doors.d.ts.map +1 -1
- package/dist/view-doors.js +28 -14
- package/dist/view-doors.js.map +1 -1
- package/dist/workbench/activity.d.ts.map +1 -1
- package/dist/workbench/activity.js +9 -9
- package/dist/workbench/activity.js.map +1 -1
- package/dist/workbench/answer-args.d.ts.map +1 -1
- package/dist/workbench/answer-args.js +26 -2
- package/dist/workbench/answer-args.js.map +1 -1
- package/dist/workbench/back-out.js +3 -3
- package/dist/workbench/back-out.js.map +1 -1
- package/dist/workbench/inspector.d.ts +11 -6
- package/dist/workbench/inspector.d.ts.map +1 -1
- package/dist/workbench/inspector.js +42 -56
- package/dist/workbench/inspector.js.map +1 -1
- package/dist/workbench/standing.d.ts.map +1 -1
- package/dist/workbench/standing.js +4 -3
- package/dist/workbench/standing.js.map +1 -1
- package/dist/workbench/trail.d.ts +10 -17
- package/dist/workbench/trail.d.ts.map +1 -1
- package/dist/workbench/trail.js +29 -41
- package/dist/workbench/trail.js.map +1 -1
- package/package.json +7 -7
- package/dist/companion.d.ts +0 -73
- package/dist/companion.d.ts.map +0 -1
- package/dist/companion.js +0 -594
- package/dist/companion.js.map +0 -1
- package/dist/ladder.d.ts +0 -2
- package/dist/ladder.d.ts.map +0 -1
- package/dist/ladder.js +0 -48
- package/dist/ladder.js.map +0 -1
- package/dist/popover.d.ts +0 -21
- package/dist/popover.d.ts.map +0 -1
- package/dist/popover.js +0 -28
- package/dist/popover.js.map +0 -1
- package/dist/wordmark.d.ts +0 -15
- package/dist/wordmark.d.ts.map +0 -1
- package/dist/wordmark.js +0 -50
- package/dist/wordmark.js.map +0 -1
package/README.md
CHANGED
|
@@ -41,8 +41,11 @@ the schema, the invariants and the op log.
|
|
|
41
41
|
**The app, said once** — `AppBar`: one bar over every face (FR-131) — the
|
|
42
42
|
brand's mark (`AppMark`, drawn as given, never an SVG that could act) and
|
|
43
43
|
the app's name as the page's heading, the switch between the scene and the
|
|
44
|
-
pages (`faces`, FR-137),
|
|
45
|
-
opens every place (`barPlaces`: the home, the Lists, the Pictures, FR-138
|
|
44
|
+
pages (`faces`, FR-137), the place you are on as one control that
|
|
45
|
+
opens every place (`barPlaces`: the home, the Lists, the Pictures, FR-138;
|
|
46
|
+
on the scene `useScenePlaces`: the whole thing and each picture, FR-144),
|
|
47
|
+
the places standing on the row where they fit, the rest under "More"
|
|
48
|
+
(`placesThatStand`, FR-145),
|
|
46
49
|
and three tools of one size: the Find a
|
|
47
50
|
face puts in it (`useBarFind`), `Standing` and `Profile`. `AppTitle` draws
|
|
48
51
|
the mark, the name and the line under it elsewhere; `useFavicon` is for a
|
package/dist/app-bar.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export interface BarPlace {
|
|
|
16
16
|
export declare const HOME_KEY = "home";
|
|
17
17
|
/** The home's address on the routed face: the app's own. */
|
|
18
18
|
export declare const HOME_PATH = "/";
|
|
19
|
+
/** The key of the scene's first place (FR-144): the whole thing, no picture in view. */
|
|
20
|
+
export declare const WHOLE_KEY = "scene:whole";
|
|
19
21
|
/**
|
|
20
22
|
* THE APP'S PLACES, IN THE LIST'S ORDER (FR-138): the home; each kind's list
|
|
21
23
|
* in the declaration's order; each named picture, then how the kinds
|
|
@@ -42,6 +44,13 @@ export interface BarFind {
|
|
|
42
44
|
readonly slot: HTMLElement;
|
|
43
45
|
/** A phone's bar: the box opens over the bar's row when it is asked for. */
|
|
44
46
|
readonly compact: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Where the face puts a tool of its own, after Find and before the
|
|
49
|
+
* standing: the scene's Activity — what happened, the turns to take back,
|
|
50
|
+
* the seat's agent — which only the scene's face holds, so a page that
|
|
51
|
+
* opens on the pages never fetches it.
|
|
52
|
+
*/
|
|
53
|
+
readonly own: HTMLElement | null;
|
|
45
54
|
}
|
|
46
55
|
export declare const BarFindContext: import("react").Context<BarFind | null>;
|
|
47
56
|
/** The bar's place for a Find box, when a bar above this face has one. */
|
|
@@ -64,10 +73,37 @@ export interface BarFaces {
|
|
|
64
73
|
readonly scene: BarFace;
|
|
65
74
|
readonly pages: BarFace;
|
|
66
75
|
}
|
|
76
|
+
/** How the switch is drawn: its words beside its marks where there is room, or its marks alone (the words its names). */
|
|
77
|
+
export type BarSwitch = "words" | "icons";
|
|
67
78
|
/** One size for every tool on the bar (FR-131). */
|
|
68
79
|
export declare const TOOL = 30;
|
|
69
80
|
/** The bar's one row, its rule under it included, on a desk and a phone alike (FR-138). */
|
|
70
81
|
export declare const BAR_HEIGHT = 48;
|
|
82
|
+
/** Below this width of its own the bar is a phone's: the place is the page's first line, and Find a magnifier that opens the box over the row. */
|
|
83
|
+
export declare const BAR_PHONE = 640;
|
|
84
|
+
/** The room between two places standing on the row (FR-145). */
|
|
85
|
+
export declare const PLACE_GAP = 4;
|
|
86
|
+
/** The fewest places that stand on the row: fewer, and the one control says the same in less room. */
|
|
87
|
+
export declare const FEWEST_STANDING = 2;
|
|
88
|
+
/**
|
|
89
|
+
* WHICH PLACES STAND ON THE ROW (FR-145), from their widths and the room:
|
|
90
|
+
* every one when all fit; else the first ones in their order, the current
|
|
91
|
+
* one always among them (in its own place in the order, the last of the
|
|
92
|
+
* first ones giving way to it), with "More" after them; else none — null,
|
|
93
|
+
* the one control. Fewer than `FEWEST_STANDING` is none. A width that is
|
|
94
|
+
* not measured (nothing laid out) is none too.
|
|
95
|
+
*/
|
|
96
|
+
export declare function placesThatStand(input: {
|
|
97
|
+
/** Each place's width as it would stand, in the order of the list. */
|
|
98
|
+
readonly widths: readonly number[];
|
|
99
|
+
/** Where the current place is in the list; -1 for none. */
|
|
100
|
+
readonly current: number;
|
|
101
|
+
/** The room the row has for them. */
|
|
102
|
+
readonly room: number;
|
|
103
|
+
/** "More"'s width. */
|
|
104
|
+
readonly more: number;
|
|
105
|
+
readonly gap?: number;
|
|
106
|
+
}): readonly number[] | null;
|
|
71
107
|
/** A tool's own box: one size, square, its name in words for whoever cannot see the mark. */
|
|
72
108
|
export declare const toolStyle: CSSProperties;
|
|
73
109
|
/**
|
|
@@ -78,7 +114,7 @@ export declare const toolStyle: CSSProperties;
|
|
|
78
114
|
* person). One row of one height on a desk and a phone; on a phone the
|
|
79
115
|
* place is the page's first line, under the bar.
|
|
80
116
|
*/
|
|
81
|
-
export declare function AppBar({ brand, name, heading, home, faces, places, current, reach, tools, find, description, findBox, onFind, }: {
|
|
117
|
+
export declare function AppBar({ brand, name, heading, home, faces, places, current, reach, tools, find, description, findBox, onFind, switch: switchForm, scenePlaces, }: {
|
|
82
118
|
readonly brand: Brand | undefined;
|
|
83
119
|
readonly name: string;
|
|
84
120
|
/** The level the app's name is said at: 1 when the page is the app's, `false` when the host's own heading already says it. */
|
|
@@ -105,5 +141,22 @@ export declare function AppBar({ brand, name, heading, home, faces, places, curr
|
|
|
105
141
|
readonly findBox?: ReactNode;
|
|
106
142
|
/** Told where the bar keeps the Find box, for the face under it (`BarFindContext`). */
|
|
107
143
|
readonly onFind?: (find: BarFind | null) => void;
|
|
144
|
+
/**
|
|
145
|
+
* How the switch is drawn: `"words"` (the default) says "Scene" and
|
|
146
|
+
* "Pages" beside their marks where the bar has room and draws the marks
|
|
147
|
+
* alone where it is narrow; `"icons"` draws the marks alone at every
|
|
148
|
+
* width. Either way the words are the buttons' names and their titles.
|
|
149
|
+
*/
|
|
150
|
+
readonly switch?: BarSwitch;
|
|
151
|
+
/**
|
|
152
|
+
* On the scene, what it can show (FR-144): the whole thing and each
|
|
153
|
+
* picture, the one in view, and the way to each (`useScenePlaces`). None,
|
|
154
|
+
* and the scene's bar names no place.
|
|
155
|
+
*/
|
|
156
|
+
readonly scenePlaces?: {
|
|
157
|
+
readonly places: readonly BarPlace[];
|
|
158
|
+
readonly current: string | null;
|
|
159
|
+
readonly reach: BarGo;
|
|
160
|
+
} | undefined;
|
|
108
161
|
}): import("react").JSX.Element;
|
|
109
162
|
//# sourceMappingURL=app-bar.d.ts.map
|
package/dist/app-bar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-bar.d.ts","sourceRoot":"","sources":["../src/app-bar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,KAAK,gBAAgB,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAExK,OAAO,EAA6E,KAAK,aAAa,EAAmB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"app-bar.d.ts","sourceRoot":"","sources":["../src/app-bar.tsx"],"names":[],"mappings":"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"}
|
package/dist/app-bar.js
CHANGED
|
@@ -7,6 +7,8 @@ import { AppMark } from "./app-title.js";
|
|
|
7
7
|
export const HOME_KEY = "home";
|
|
8
8
|
/** The home's address on the routed face: the app's own. */
|
|
9
9
|
export const HOME_PATH = "/";
|
|
10
|
+
/** The key of the scene's first place (FR-144): the whole thing, no picture in view. */
|
|
11
|
+
export const WHOLE_KEY = "scene:whole";
|
|
10
12
|
const upper = (word) => word.charAt(0).toUpperCase() + word.slice(1);
|
|
11
13
|
/**
|
|
12
14
|
* THE APP'S PLACES, IN THE LIST'S ORDER (FR-138): the home; each kind's list
|
|
@@ -57,23 +59,88 @@ export const useBarFind = () => useContext(BarFindContext);
|
|
|
57
59
|
export const TOOL = 30;
|
|
58
60
|
/** The bar's one row, its rule under it included, on a desk and a phone alike (FR-138). */
|
|
59
61
|
export const BAR_HEIGHT = 48;
|
|
62
|
+
/** Below this width of its own the bar is a phone's: the place is the page's first line, and Find a magnifier that opens the box over the row. */
|
|
63
|
+
export const BAR_PHONE = 640;
|
|
64
|
+
/** The room between two places standing on the row (FR-145). */
|
|
65
|
+
export const PLACE_GAP = 4;
|
|
66
|
+
/** The fewest places that stand on the row: fewer, and the one control says the same in less room. */
|
|
67
|
+
export const FEWEST_STANDING = 2;
|
|
68
|
+
/**
|
|
69
|
+
* WHICH PLACES STAND ON THE ROW (FR-145), from their widths and the room:
|
|
70
|
+
* every one when all fit; else the first ones in their order, the current
|
|
71
|
+
* one always among them (in its own place in the order, the last of the
|
|
72
|
+
* first ones giving way to it), with "More" after them; else none — null,
|
|
73
|
+
* the one control. Fewer than `FEWEST_STANDING` is none. A width that is
|
|
74
|
+
* not measured (nothing laid out) is none too.
|
|
75
|
+
*/
|
|
76
|
+
export function placesThatStand(input) {
|
|
77
|
+
const { widths, current, room, more, gap = PLACE_GAP } = input;
|
|
78
|
+
if (widths.length === 0 || !(room > 0) || !(more > 0) || widths.some((width) => !(width > 0)))
|
|
79
|
+
return null;
|
|
80
|
+
const span = (set, folded) => set.reduce((sum, at) => sum + widths[at], 0) + gap * Math.max(0, set.length - 1) + (folded ? gap + more : 0);
|
|
81
|
+
const all = widths.map((_, at) => at);
|
|
82
|
+
if (span(all, false) <= room)
|
|
83
|
+
return all;
|
|
84
|
+
for (let count = widths.length - 1; count >= FEWEST_STANDING; count--) {
|
|
85
|
+
const set = current < count ? all.slice(0, count) : [...all.slice(0, count - 1), current];
|
|
86
|
+
if (span(set, true) <= room)
|
|
87
|
+
return set;
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
/*
|
|
92
|
+
* THE BAR FITS ITS BOX. Every rule here reads the bar's own width (it is
|
|
93
|
+
* its own container), never the screen's: an embed in a 650 px box on a
|
|
94
|
+
* 1440 desk is a narrow bar, not a desk's bar squeezed. When the row is
|
|
95
|
+
* short, Find gives first (a small box that says its shortcut, drawn wide
|
|
96
|
+
* while it is used), then the place down to 9em of its name (whole in its
|
|
97
|
+
* title), then the app's name, which wraps between its words onto a second
|
|
98
|
+
* line and never inside one; the switch keeps its size, and draws its marks
|
|
99
|
+
* alone when its words do not fit (`roomForWords`).
|
|
100
|
+
*
|
|
101
|
+
* Where the places stand on the row (FR-145), Find gives first — down to
|
|
102
|
+
* its least — then the places fold into "More", then into the one control,
|
|
103
|
+
* which gives as above. The places are weighed with the switch's words
|
|
104
|
+
* kept: the words are worth more than a third place on the row.
|
|
105
|
+
*
|
|
106
|
+
* The order is the shrink factors: Find 600, the place 100, the app 1. A
|
|
107
|
+
* factor under 1 would not do — the free space is scaled by the factors
|
|
108
|
+
* left when the others have reached their least, so an app at 0.001 would
|
|
109
|
+
* give 0.1% of what is still needed and the row would run out of its box.
|
|
110
|
+
* At 1 the app gives a fraction of a pixel while the others still can,
|
|
111
|
+
* which would wrap its last word; its 2 px spacer (`::after`) takes that.
|
|
112
|
+
* The tools (`display:contents`) stand on the row themselves, so Find's
|
|
113
|
+
* box is what gives, not a column around it.
|
|
114
|
+
*/
|
|
60
115
|
const BAR_CSS = `
|
|
61
|
-
.graview-bar{display:block;margin:0;padding:0;container-
|
|
116
|
+
.graview-bar{display:block;margin:0;padding:0;container:graview-bar/inline-size;flex:0 0 auto;position:relative;background:var(--graview-bar);border-bottom:1px solid var(--graview-edge);color:var(--graview-ink);font-family:var(--graview-font-body,system-ui)}
|
|
62
117
|
.graview-bar-row{display:flex;flex-wrap:nowrap;align-items:center;gap:16px;height:${BAR_HEIGHT - 1}px;margin:0;padding:0 16px}
|
|
63
|
-
.graview-bar-home,.graview-bar-face,.graview-bar-place,.graview-bar-item{display:inline-flex;align-items:center;box-sizing:border-box;min-width:0;margin:0;border:0;background:none;box-shadow:none;font:inherit;letter-spacing:normal;text-transform:none;text-decoration:none;color:var(--graview-ink);cursor:pointer;text-align:left}
|
|
64
|
-
.graview-bar-app{display:flex;flex:0 1 auto;
|
|
65
|
-
.graview-bar-
|
|
66
|
-
.graview-bar-
|
|
118
|
+
.graview-bar-home,.graview-bar-face,.graview-bar-place,.graview-bar-item,.graview-bar-at{display:inline-flex;align-items:center;box-sizing:border-box;min-width:0;margin:0;border:0;background:none;box-shadow:none;font:inherit;letter-spacing:normal;text-transform:none;text-decoration:none;color:var(--graview-ink);cursor:pointer;text-align:left}
|
|
119
|
+
.graview-bar-app{display:flex;flex:0 1 auto;max-width:50%}
|
|
120
|
+
.graview-bar-app::after{content:"";flex:0 100000 auto;width:2px;min-width:0}
|
|
121
|
+
.graview-bar-name{margin:0;display:flex;font-family:var(--graview-font-display,var(--graview-font-body,system-ui));font-size:.9375rem;font-weight:600;line-height:1.25}
|
|
122
|
+
.graview-bar-home{gap:8px;min-width:auto;min-height:30px;padding:0;letter-spacing:-.005em}
|
|
123
|
+
.graview-bar-app-name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis;overflow-wrap:normal;word-break:normal}
|
|
67
124
|
.graview-bar-faces{display:inline-flex;flex:0 0 auto;box-sizing:border-box;height:30px;margin:0;padding:2px;gap:2px;border:1px solid var(--graview-edge);border-radius:8px}
|
|
68
125
|
.graview-bar-face{gap:6px;padding:0 10px;border-radius:6px;font-size:.8125rem;white-space:nowrap;color:var(--graview-ink-muted)}
|
|
69
126
|
.graview-bar-face span{min-width:0;max-width:11em;overflow:hidden;text-overflow:ellipsis}
|
|
70
127
|
.graview-bar-face[aria-pressed=true]{color:var(--graview-ink);font-weight:600;background:color-mix(in srgb,var(--graview-accent) 16%,transparent)}
|
|
71
|
-
.graview-bar-
|
|
128
|
+
[data-switch-drawn=icons] .graview-bar-face{padding:0 8px}
|
|
129
|
+
[data-switch-drawn=icons] .graview-bar-face span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
|
|
130
|
+
.graview-bar-mid{display:flex;flex:1 100 0;min-width:0}
|
|
131
|
+
.graview-bar-mid[data-place]{min-width:9em;flex-basis:auto}
|
|
72
132
|
.graview-bar-place-at{position:relative;display:inline-flex;min-width:0;max-width:100%}
|
|
73
133
|
.graview-bar-place{gap:6px;height:30px;max-width:100%;padding:0 8px;border:1px solid transparent;border-radius:8px;font-size:.875rem;font-weight:600}
|
|
74
134
|
.graview-bar-face:hover,.graview-bar-place:hover{border-color:var(--graview-edge);color:var(--graview-ink)}
|
|
75
135
|
.graview-bar-place-words{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
76
|
-
.graview-bar-
|
|
136
|
+
.graview-bar-mid[data-places=standing]{flex:0 0 auto}
|
|
137
|
+
.graview-bar-places{display:flex;align-items:center;gap:${PLACE_GAP}px;min-width:0;margin:0;padding:0}
|
|
138
|
+
.graview-bar-at{gap:6px;flex:0 0 auto;height:30px;padding:0 8px;border-block:2px solid transparent;border-radius:0;font-size:.875rem;font-weight:500;white-space:nowrap;color:var(--graview-ink-muted)}
|
|
139
|
+
.graview-bar-at:is(:hover,[aria-current],[aria-expanded=true]){color:var(--graview-ink)}
|
|
140
|
+
.graview-bar-at[aria-current]{font-weight:600;border-bottom-color:var(--graview-accent)}
|
|
141
|
+
.graview-bar-ruler{position:absolute;left:0;top:0;display:flex;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none}
|
|
142
|
+
.graview-bar-ruler .graview-bar-at{font-weight:600}
|
|
143
|
+
.graview-bar-list{display:grid;align-content:start;width:min(320px,calc(100vw - 24px));height:auto;max-height:min(70vh,560px);overflow:auto;margin:0;padding:6px;border-radius:10px;border:1px solid var(--graview-edge);background:var(--graview-float);box-shadow:var(--graview-lift-high);color:var(--graview-ink)}
|
|
77
144
|
.graview-bar-list[hidden]{display:none}
|
|
78
145
|
.graview-bar-list p{margin:8px 8px 2px;font-size:.6875rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--graview-ink-muted)}
|
|
79
146
|
.graview-bar-list ul,.graview-bar-list li{display:grid;margin:0;padding:0;list-style:none}
|
|
@@ -82,23 +149,29 @@ const BAR_CSS = `
|
|
|
82
149
|
.graview-bar-item[aria-current]{font-weight:600;background:color-mix(in srgb,var(--graview-accent) 14%,transparent)}
|
|
83
150
|
.graview-bar-mark{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:14px;height:1.3em;color:var(--graview-ink-muted)}
|
|
84
151
|
.graview-bar :focus-visible{outline:2px solid var(--graview-accent);outline-offset:1px}
|
|
85
|
-
.graview-bar-tools{display:
|
|
86
|
-
.graview-bar-
|
|
87
|
-
.graview-bar-find-open{
|
|
152
|
+
.graview-bar-tools{display:contents}
|
|
153
|
+
.graview-bar-tools>*{margin-left:-8px}
|
|
154
|
+
.graview-bar-tools>:is(.graview-bar-find,.graview-bar-find-open){margin-left:auto}
|
|
155
|
+
.graview-bar-own{display:flex;align-items:center;flex:0 0 auto}
|
|
156
|
+
.graview-bar-own:empty{display:none}
|
|
157
|
+
.graview-bar-find{position:relative;display:flex;min-width:7.5rem;flex:0 600 9rem;--graview-bar-find-end:3.25em}
|
|
158
|
+
.graview-bar-find-slot{display:flex;flex:1;min-width:0}
|
|
159
|
+
.graview-bar-find-keys{position:absolute;right:10px;line-height:30px;pointer-events:none;font-size:.75rem;color:var(--graview-ink-faint)}
|
|
160
|
+
.graview-bar-find:is(:focus-within,:has(input:not(:placeholder-shown))){flex-basis:16rem;--graview-bar-find-end:10px}
|
|
161
|
+
:is(:focus-within,:has(input:not(:placeholder-shown)))>.graview-bar-find-keys,.graview-bar-find-open{display:none}
|
|
88
162
|
.graview-bar-line{display:flex;flex:0 0 auto;padding:6px 8px;background:var(--graview-ground);border-bottom:1px solid var(--graview-edge);font-family:var(--graview-font-body,system-ui)}
|
|
89
163
|
.graview-bar-line .graview-bar-place{height:auto;min-height:32px}
|
|
90
164
|
.graview-bar-line .graview-bar-place-words{white-space:normal}
|
|
91
|
-
@
|
|
165
|
+
@media (pointer:coarse){.graview-bar-find-keys{display:none}}
|
|
166
|
+
@container graview-bar (max-width: ${BAR_PHONE - 1}px){
|
|
92
167
|
.graview-bar-row{gap:10px;padding:0 12px}
|
|
93
168
|
.graview-bar-app{max-width:none;flex:1 1 auto}
|
|
94
|
-
.graview-bar-app-name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
|
|
95
|
-
.graview-bar-face{padding:0 8px}
|
|
96
|
-
.graview-bar-face span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
97
169
|
.graview-bar-mid,.graview-bar-find{display:none}
|
|
98
170
|
.graview-bar-find-open{display:inline-flex}
|
|
171
|
+
.graview-bar-own{--graview-activity-mark:inline}
|
|
172
|
+
.graview-bar-own .graview-activity-word{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
99
173
|
.graview-bar[data-finding] :is(.graview-bar-app,.graview-bar-faces,.graview-bar-find-open){display:none}
|
|
100
|
-
.graview-bar[data-finding] .graview-bar-
|
|
101
|
-
.graview-bar[data-finding] .graview-bar-find{display:flex;flex:1 1 auto;width:auto;min-width:0}
|
|
174
|
+
.graview-bar[data-finding] .graview-bar-find{display:flex;flex:1 1 auto;min-width:0}
|
|
102
175
|
}`;
|
|
103
176
|
/** A tool's own box: one size, square, its name in words for whoever cannot see the mark. */
|
|
104
177
|
export const toolStyle = {
|
|
@@ -127,28 +200,67 @@ export const toolStyle = {
|
|
|
127
200
|
* person). One row of one height on a desk and a phone; on a phone the
|
|
128
201
|
* place is the page's first line, under the bar.
|
|
129
202
|
*/
|
|
130
|
-
export function AppBar({ brand, name, heading = 1, home, faces, places, current, reach, tools, find = true, description, findBox, onFind, }) {
|
|
203
|
+
export function AppBar({ brand, name, heading = 1, home, faces, places, current, reach, tools, find = true, description, findBox, onFind, switch: switchForm = "words", scenePlaces, }) {
|
|
131
204
|
const bar = useRef(null);
|
|
132
205
|
const [slot, setSlot] = useState(null);
|
|
206
|
+
const [own, setOwn] = useState(null);
|
|
133
207
|
const [compact, setCompact] = useState(false);
|
|
134
208
|
const [finding, setFinding] = useState(false);
|
|
209
|
+
// Whether the switch's words fit beside everything else the row holds (`roomForWords`).
|
|
210
|
+
const [roomy, setRoomy] = useState(true);
|
|
211
|
+
// Which places stand on the row, by their place in the list ("0,1,2"); null, the one control (FR-145).
|
|
212
|
+
const [standing, setStanding] = useState(null);
|
|
213
|
+
// The places on the face drawn: the routed face's, or the scene's (FR-144) — a scene with no pages to switch to has its places too.
|
|
214
|
+
const onPages = faces ? faces.pages.current : !scenePlaces;
|
|
215
|
+
const shown = onPages ? { places, current, reach } : scenePlaces;
|
|
216
|
+
const list = shown && shown.places.length > 0 ? shown : null;
|
|
217
|
+
const currentAt = list ? list.places.findIndex((place) => place.key === list.current) : -1;
|
|
218
|
+
const wordsAsked = Boolean(faces) && switchForm === "words";
|
|
219
|
+
const weigh = useCallback(() => {
|
|
220
|
+
const element = bar.current;
|
|
221
|
+
if (!element)
|
|
222
|
+
return;
|
|
223
|
+
const stand = standsIn(element, currentAt, wordsAsked);
|
|
224
|
+
if (stand !== undefined)
|
|
225
|
+
setStanding(stand);
|
|
226
|
+
// Standing places were weighed with the switch's words kept.
|
|
227
|
+
const room = stand ? true : roomForWords(element);
|
|
228
|
+
if (room !== null)
|
|
229
|
+
setRoomy(room);
|
|
230
|
+
}, [currentAt, wordsAsked]);
|
|
135
231
|
useLayoutEffect(() => {
|
|
136
232
|
const element = bar.current;
|
|
137
233
|
if (!element)
|
|
138
234
|
return;
|
|
139
|
-
const read = () =>
|
|
235
|
+
const read = () => {
|
|
236
|
+
const width = element.getBoundingClientRect().width;
|
|
237
|
+
setCompact(width < BAR_PHONE);
|
|
238
|
+
// What hangs from the bar as wide as it (a phone's Find sheet) is told the bar's width, not the screen's.
|
|
239
|
+
element.style.setProperty("--graview-bar-width", `${Math.round(width)}px`);
|
|
240
|
+
weigh();
|
|
241
|
+
};
|
|
140
242
|
read();
|
|
243
|
+
// The brand's face, once it has come, is wider or narrower than the one the row was first weighed in.
|
|
244
|
+
const fonts = typeof document === "undefined" ? undefined : document.fonts;
|
|
245
|
+
void fonts?.ready.then(weigh);
|
|
246
|
+
fonts?.addEventListener?.("loadingdone", weigh);
|
|
141
247
|
if (typeof ResizeObserver === "undefined")
|
|
142
|
-
return;
|
|
248
|
+
return () => fonts?.removeEventListener?.("loadingdone", weigh);
|
|
143
249
|
const watch = new ResizeObserver(read);
|
|
144
250
|
watch.observe(element);
|
|
145
|
-
|
|
146
|
-
|
|
251
|
+
// What stands beside the places — the tools, a count on the standing — changes their room without changing the bar's width.
|
|
252
|
+
for (const tool of element.querySelectorAll(".graview-bar-tools > *"))
|
|
253
|
+
watch.observe(tool);
|
|
254
|
+
return () => {
|
|
255
|
+
watch.disconnect();
|
|
256
|
+
fonts?.removeEventListener?.("loadingdone", weigh);
|
|
257
|
+
};
|
|
258
|
+
}, [weigh]);
|
|
147
259
|
const told = useRef(onFind);
|
|
148
260
|
told.current = onFind;
|
|
149
261
|
useLayoutEffect(() => {
|
|
150
|
-
told.current?.(find && slot ? { slot, compact } : null);
|
|
151
|
-
}, [find, slot, compact]);
|
|
262
|
+
told.current?.(find && slot ? { slot, compact, own } : null);
|
|
263
|
+
}, [find, slot, compact, own]);
|
|
152
264
|
useLayoutEffect(() => () => told.current?.(null), []);
|
|
153
265
|
const openFind = useCallback(() => {
|
|
154
266
|
setFinding(true);
|
|
@@ -175,10 +287,16 @@ export function AppBar({ brand, name, heading = 1, home, faces, places, current,
|
|
|
175
287
|
event.preventDefault();
|
|
176
288
|
go();
|
|
177
289
|
};
|
|
178
|
-
// The place control
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
|
|
290
|
+
// The place control: in the bar on a desk, as the page's first line on a phone; the places themselves on the row when they fit (FR-145).
|
|
291
|
+
const scene = !onPages;
|
|
292
|
+
const stands = list && !compact && standing !== null ? standing.split(",").map(Number).filter((at) => at < list.places.length) : null;
|
|
293
|
+
const placeControl = list ? _jsx(Places, { places: list.places, current: list.current, reach: list.reach, scene: scene, stands: stands }) : null;
|
|
294
|
+
const said = list ? list.places.map((place) => place.label).join("\n") : "";
|
|
295
|
+
// What the row holds changed — the name, the places, the face, the brand — so the places and the words may fit now, or no longer.
|
|
296
|
+
useLayoutEffect(weigh, [weigh, name, brand, said, list?.current, onPages, compact, switchForm, find]);
|
|
297
|
+
// The marks alone on a phone's bar, when asked, or when the words do not fit.
|
|
298
|
+
const drawn = switchForm === "icons" || !roomy || compact ? "icons" : "words";
|
|
299
|
+
return (_jsxs(_Fragment, { children: [_jsxs("header", { ref: bar, className: "graview-bar", "data-testid": "app-bar", "data-graview-app-bar": "", ...(finding && compact ? { "data-finding": "" } : {}), children: [_jsx("style", { children: BAR_CSS }), _jsxs("div", { className: "graview-bar-row", children: [_jsx("div", { className: "graview-bar-app", children: _jsx(Heading, { className: "graview-bar-name", children: _jsxs(Home, { ...(home.href !== undefined ? { href: home.href, onClick: press(home.go) } : { type: "button", onClick: home.go }), "data-testid": "app-home", ...(home.current ? { "aria-current": "page" } : {}), title: description ? `${name} — ${description}` : `${name} — home`, className: "graview-bar-home", children: [_jsx(AppMark, { brand: brand, size: 20 }), _jsx("span", { className: "graview-bar-app-name", "data-testid": "app-name", children: name })] }) }) }), faces ? _jsx(FaceSwitch, { faces: faces, form: switchForm, drawn: drawn }) : null, _jsx("div", { className: "graview-bar-mid", ...(stands ? { "data-places": "standing" } : !compact && placeControl ? { "data-place": "" } : {}), children: compact ? null : placeControl }), !compact && list && list.places.length > 1 ? (_jsxs("span", { className: "graview-bar-ruler", "aria-hidden": "true", "data-graview-bar-ruler": "", children: [list.places.map((place) => (_jsx("span", { className: "graview-bar-at", children: place.label }, place.key))), _jsxs("span", { className: "graview-bar-at", children: [MORE, _jsx(Chevron, {})] })] })) : null, _jsxs("div", { className: "graview-bar-tools", children: [find ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "graview-bar-find-open", ref: opener, "data-testid": "app-find-open", "aria-label": "Find", title: "Find", onClick: openFind, style: { ...toolStyle, display: undefined }, children: _jsx(FindMark, {}) }), _jsxs("div", { className: "graview-bar-find", "data-testid": "app-find", onBlur: (event) => {
|
|
182
300
|
// Put away on a phone when the keyboard leaves it with nothing typed.
|
|
183
301
|
const next = event.relatedTarget;
|
|
184
302
|
if (next instanceof Node && event.currentTarget.contains(next))
|
|
@@ -196,7 +314,7 @@ export function AppBar({ brand, name, heading = 1, home, faces, places, current,
|
|
|
196
314
|
putAway();
|
|
197
315
|
else
|
|
198
316
|
escaping.current = false;
|
|
199
|
-
}, children: findBox })] })) : null, tools] })] })] }), compact && placeControl ? (_jsx("div", { className: "graview-bar-line", "data-graview-place-line": "", "data-testid": "app-place-line", children: placeControl })) : null] }));
|
|
317
|
+
}, children: [_jsx("div", { ref: setSlot, className: "graview-bar-find-slot", children: findBox }), _jsx("span", { className: "graview-bar-find-keys", "data-testid": "app-find-keys", "aria-hidden": "true", children: findKeys() })] })] })) : null, _jsx("div", { ref: setOwn, className: "graview-bar-own", "data-graview-bar-own": "" }), tools] })] })] }), compact && placeControl ? (_jsx("div", { className: "graview-bar-line", "data-graview-place-line": "", "data-testid": "app-place-line", children: placeControl })) : null] }));
|
|
200
318
|
}
|
|
201
319
|
/**
|
|
202
320
|
* THE SWITCH (FR-137): the scene and the pages, side by side, an icon and a
|
|
@@ -204,7 +322,7 @@ export function AppBar({ brand, name, heading = 1, home, faces, places, current,
|
|
|
204
322
|
* drawn pressed. Choosing the scene draws it under the bar; choosing the
|
|
205
323
|
* pages goes back to the page you were on.
|
|
206
324
|
*/
|
|
207
|
-
function FaceSwitch({ faces }) {
|
|
325
|
+
function FaceSwitch({ faces, form, drawn }) {
|
|
208
326
|
const face = (which) => {
|
|
209
327
|
const one = faces[which];
|
|
210
328
|
return (_jsxs("button", { type: "button", className: "graview-bar-face", "data-testid": `app-face-${which}`, "aria-pressed": one.current, title: one.label, onClick: () => {
|
|
@@ -212,7 +330,50 @@ function FaceSwitch({ faces }) {
|
|
|
212
330
|
one.go();
|
|
213
331
|
}, children: [which === "scene" ? _jsx(SceneMark, {}) : _jsx(PagesMark, {}), _jsx("span", { children: one.label })] }));
|
|
214
332
|
};
|
|
215
|
-
return (_jsxs("div", { className: "graview-bar-faces", role: "group", "aria-label": `${faces.scene.label} or ${faces.pages.label}`, "data-testid": "app-faces", children: [face("scene"), face("pages")] }));
|
|
333
|
+
return (_jsxs("div", { className: "graview-bar-faces", role: "group", "aria-label": `${faces.scene.label} or ${faces.pages.label}`, "data-testid": "app-faces", "data-switch": form, "data-switch-drawn": drawn, children: [face("scene"), face("pages")] }));
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* WHETHER THE SWITCH'S WORDS FIT (the switch left to say its words where
|
|
337
|
+
* there is room). The row is weighed as it is drawn: the room the middle
|
|
338
|
+
* has past what the place wants (its words, up to 14em; none on the
|
|
339
|
+
* scene), less what Find has given up; none when the app's name has
|
|
340
|
+
* wrapped. The words fit when that room holds them — the words
|
|
341
|
+
* drawn already, or their width to come when the marks are drawn alone —
|
|
342
|
+
* so the switch never flips back and forth at one width. Not weighed while
|
|
343
|
+
* Find is in use (it is drawn wide then), on a phone's bar (the marks
|
|
344
|
+
* alone), or where nothing is laid out (null).
|
|
345
|
+
*/
|
|
346
|
+
function roomForWords(header) {
|
|
347
|
+
const faces = header.querySelector(".graview-bar-faces");
|
|
348
|
+
const mid = header.querySelector(".graview-bar-mid");
|
|
349
|
+
const find = header.querySelector(".graview-bar-find");
|
|
350
|
+
if (!faces || !mid || find?.matches(":focus-within"))
|
|
351
|
+
return null;
|
|
352
|
+
const row = header.getBoundingClientRect().width;
|
|
353
|
+
if (row < BAR_PHONE)
|
|
354
|
+
return null;
|
|
355
|
+
// The words to come, beside each mark: the word, the gap before it, and the button's wider padding.
|
|
356
|
+
const words = wordsOf(faces);
|
|
357
|
+
const place = mid.querySelector(".graview-bar-place-words");
|
|
358
|
+
const em = place ? Number.parseFloat(getComputedStyle(place).fontSize) || 14 : 0;
|
|
359
|
+
// The place's words, its chevron, its gap, padding and frame: up to 14em of them.
|
|
360
|
+
const wanted = place ? Math.min(place.scrollWidth + 34, 14 * em) : 0;
|
|
361
|
+
let spare = mid.getBoundingClientRect().width - wanted;
|
|
362
|
+
if (find && find.getBoundingClientRect().width > 0) {
|
|
363
|
+
const basis = Number.parseFloat(getComputedStyle(find).flexBasis);
|
|
364
|
+
if (Number.isFinite(basis))
|
|
365
|
+
spare -= Math.max(0, basis - find.getBoundingClientRect().width);
|
|
366
|
+
}
|
|
367
|
+
// The app's name on two lines has given its room already: no room for the words.
|
|
368
|
+
const name = header.querySelector(".graview-bar-app-name");
|
|
369
|
+
if (name && name.getBoundingClientRect().height > Number.parseFloat(getComputedStyle(name).lineHeight) * 1.5)
|
|
370
|
+
return false;
|
|
371
|
+
return faces.getAttribute("data-switch-drawn") === "icons" ? spare >= words + 2 : spare >= -1;
|
|
372
|
+
}
|
|
373
|
+
/** Find's shortcut as the keyboard says it: ⌘K on a Mac (and an iPad's keyboard), Ctrl K elsewhere. */
|
|
374
|
+
function findKeys() {
|
|
375
|
+
const platform = typeof navigator === "undefined" ? "" : (navigator.platform ?? "");
|
|
376
|
+
return /Mac|iPhone|iPad|iPod/.test(platform) ? "⌘K" : "Ctrl K";
|
|
216
377
|
}
|
|
217
378
|
/** The scene's mark: a plot of the city, seen from above at an angle. */
|
|
218
379
|
function SceneMark() {
|
|
@@ -232,6 +393,9 @@ function FindMark() {
|
|
|
232
393
|
}
|
|
233
394
|
/** A place's mark in the list: the home's house, a kind's plot in its own hue. */
|
|
234
395
|
function PlaceMark({ place }) {
|
|
396
|
+
// The scene's whole thing: the scene's own mark, as on the switch (FR-144).
|
|
397
|
+
if (place.key === WHOLE_KEY)
|
|
398
|
+
return _jsx(SceneMark, {});
|
|
235
399
|
if (place.group === "home") {
|
|
236
400
|
return (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 14 14", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M2 6.5 L7 2 L12 6.5 V12 H2 Z", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round" }) }));
|
|
237
401
|
}
|
|
@@ -246,44 +410,95 @@ function PlaceMark({ place }) {
|
|
|
246
410
|
} }));
|
|
247
411
|
}
|
|
248
412
|
const GROUPS = [{ group: "home" }, { group: "lists", heading: "Lists" }, { group: "pictures", heading: "Pictures" }];
|
|
413
|
+
/** The word the places that do not stand on the row fold under (FR-145). */
|
|
414
|
+
const MORE = "More";
|
|
415
|
+
/**
|
|
416
|
+
* ONE PLACE, AS THE BAR OFFERS IT — in the list, or standing on the row: a
|
|
417
|
+
* link where it has an address, a press where the bar decides; marked
|
|
418
|
+
* `aria-current` where the reader is. Whichever way it is drawn it is
|
|
419
|
+
* `app-place-<key>` and says its path (`data-place-path`), once in the bar.
|
|
420
|
+
*/
|
|
421
|
+
function PlaceEntry({ place, current, reach, standing, done }) {
|
|
422
|
+
const at = place.key === current;
|
|
423
|
+
const href = reach.href?.(place.path);
|
|
424
|
+
const Entry = (href !== undefined ? "a" : "button");
|
|
425
|
+
return (_jsxs(Entry, { className: standing ? "graview-bar-at" : "graview-bar-item", "data-testid": `app-place-${place.key}`, "data-place-path": place.path, ...(at ? { "aria-current": "page" } : {}), ...(href !== undefined ? { href } : { type: "button" }), onClick: (event) => {
|
|
426
|
+
done();
|
|
427
|
+
if (!reach.go)
|
|
428
|
+
return;
|
|
429
|
+
if (href !== undefined && (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey))
|
|
430
|
+
return;
|
|
431
|
+
event.preventDefault();
|
|
432
|
+
reach.go(place);
|
|
433
|
+
}, children: [standing ? null : (_jsx("span", { className: "graview-bar-mark", children: _jsx(PlaceMark, { place: place }) })), standing && at ? _jsx("span", { "data-testid": "app-place-current", children: place.label }) : _jsx("span", { children: place.label })] }));
|
|
434
|
+
}
|
|
435
|
+
/** The places of a list, grouped — the home (or the whole thing), the Lists, the Pictures — each group with its heading. */
|
|
436
|
+
function PlaceGroups({ places, current, reach, id, done }) {
|
|
437
|
+
return (_jsx(_Fragment, { children: GROUPS.map(({ group, heading }) => {
|
|
438
|
+
const listed = places.filter((place) => place.group === group);
|
|
439
|
+
if (listed.length === 0)
|
|
440
|
+
return null;
|
|
441
|
+
const named = `${id}-${group}`;
|
|
442
|
+
return (_jsxs("div", { role: "group", ...(heading ? { "aria-labelledby": named } : { "aria-label": listed[0].label }), "data-place-group": group, children: [heading ? _jsx("p", { id: named, children: heading }) : null, _jsx("ul", { children: listed.map((place) => (_jsx("li", { children: _jsx(PlaceEntry, { place: place, current: current, reach: reach, standing: false, done: done }) }, place.key))) })] }, group));
|
|
443
|
+
}) }));
|
|
444
|
+
}
|
|
249
445
|
/**
|
|
250
446
|
* THE PLACE YOU ARE ON, AND EVERY OTHER (FR-138): one control, the place's
|
|
251
447
|
* name and a chevron, that opens the app's places — the home first, then
|
|
252
448
|
* the Lists and the Pictures, each with its mark, a long name wrapped
|
|
253
449
|
* rather than cut. Every place is two presses away, and the bar is one row
|
|
254
|
-
* of one height however many there are.
|
|
450
|
+
* of one height however many there are. On the scene, what is in view and
|
|
451
|
+
* every picture it can show (FR-144).
|
|
452
|
+
*
|
|
453
|
+
* WHERE THEY FIT, THE PLACES THEMSELVES (FR-145): the ones that stand, as
|
|
454
|
+
* words in their order, the one you are on underlined; then "More", which
|
|
455
|
+
* opens the rest, grouped as the one control's list is — no "More" when
|
|
456
|
+
* every place stands. "More" is `app-places-open` and its list
|
|
457
|
+
* `app-places`, as the one control and its list are, so a place that does
|
|
458
|
+
* not stand is reached by the same two presses either way.
|
|
255
459
|
*/
|
|
256
|
-
function
|
|
460
|
+
function Places({ places, current, reach, scene, stands }) {
|
|
257
461
|
const popover = usePopover("places");
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
462
|
+
const said = places.find((place) => place.key === current)?.label ?? "Places";
|
|
463
|
+
const rest = stands ? places.filter((_, at) => !stands.includes(at)) : places;
|
|
464
|
+
return (_jsxs("nav", { className: stands ? "graview-bar-places" : "graview-bar-place-at", "aria-label": scene ? "What the scene shows" : "The app’s places", ...(stands ? { "data-testid": "app-places-standing" } : {}), children: [stands?.map((at) => _jsx(PlaceEntry, { place: places[at], current: current, reach: reach, standing: true, done: () => undefined }, places[at].key)), rest.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: stands ? "graview-bar-at" : "graview-bar-place", "data-testid": "app-places-open", ...popover.trigger, onClick: popover.toggle, "aria-label": stands ? `${MORE} — ${rest.length} more ${scene ? "pictures" : "places"}` : `${said} — ${scene ? "everything the scene shows" : "every place"}`, title: stands ? rest.map((place) => place.label).join(", ") : said, children: [stands ? (MORE) : (_jsx("span", { className: "graview-bar-place-words", "data-testid": "app-place-current", children: said })), _jsx(Chevron, {})] }), _jsx("div", { ...popover.pane, "data-testid": "app-places", hidden: !popover.open, className: "graview-bar-list", style: POPOVER_STYLE, children: _jsx(PlaceGroups, { places: rest, current: current, reach: reach, id: popover.pane.id, done: () => popover.setOpen(false) }) })] })) : null] }));
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* WHICH PLACES STAND ON THE ROW, WEIGHED FROM THE ROW AS DRAWN (FR-145):
|
|
468
|
+
* the places' widths read off the ruler (each at its weight as the place
|
|
469
|
+
* you are on, so marking one never moves the others), and the room from
|
|
470
|
+
* where the places begin to where Find ends, less Find at its least, less
|
|
471
|
+
* the switch's words when they are asked for. The same answer whichever way
|
|
472
|
+
* the places are drawn, so the row never flips between the two at one
|
|
473
|
+
* width. Not weighed while Find is in use (`undefined`); none on a phone's
|
|
474
|
+
* bar, when the app's name has wrapped, or where nothing is laid out (null).
|
|
475
|
+
*/
|
|
476
|
+
function standsIn(header, current, wordsAsked) {
|
|
477
|
+
const ruler = header.querySelector(".graview-bar-ruler");
|
|
478
|
+
const mid = header.querySelector(".graview-bar-mid");
|
|
479
|
+
if (!ruler || !mid)
|
|
480
|
+
return null;
|
|
481
|
+
const find = header.querySelector(".graview-bar-find");
|
|
482
|
+
if (find?.matches(":focus-within"))
|
|
483
|
+
return undefined;
|
|
484
|
+
if (header.getBoundingClientRect().width < BAR_PHONE)
|
|
485
|
+
return null;
|
|
486
|
+
const name = header.querySelector(".graview-bar-app-name");
|
|
487
|
+
if (name && name.getBoundingClientRect().height > Number.parseFloat(getComputedStyle(name).lineHeight) * 1.5)
|
|
488
|
+
return null;
|
|
489
|
+
const widths = [...ruler.children].map((one) => one.getBoundingClientRect().width);
|
|
490
|
+
const more = widths.pop() ?? 0;
|
|
491
|
+
const faces = header.querySelector(".graview-bar-faces");
|
|
492
|
+
const words = faces && wordsAsked ? wordsOf(faces) : 0;
|
|
493
|
+
const drawnWords = faces?.getAttribute("data-switch-drawn") === "words" ? words : 0;
|
|
494
|
+
const from = mid.getBoundingClientRect().left;
|
|
495
|
+
const end = find?.getBoundingClientRect();
|
|
496
|
+
// To Find's end, less Find at its least and the room between them (the row's gap, less the tools' pull); with no Find, the middle's own room.
|
|
497
|
+
const room = end && end.width > 0 ? end.right - from - (Number.parseFloat(getComputedStyle(find).minWidth) || 0) - 8 : mid.getBoundingClientRect().width;
|
|
498
|
+
return placesThatStand({ widths, current, room: Math.floor(room + drawnWords - words), more })?.join(",") ?? null;
|
|
499
|
+
}
|
|
500
|
+
/** The switch's words, beside each mark: the word, the gap before it, and the button's wider padding. */
|
|
501
|
+
function wordsOf(faces) {
|
|
502
|
+
return [...faces.querySelectorAll(".graview-bar-face span")].reduce((sum, span) => sum + span.scrollWidth + 10, 0);
|
|
288
503
|
}
|
|
289
504
|
//# sourceMappingURL=app-bar.js.map
|