@remit/web-client 0.0.108 → 0.0.109

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/web-client",
3
- "version": "0.0.108",
3
+ "version": "0.0.109",
4
4
  "type": "module",
5
5
  "description": "Remit web client, published as composable primitives — the app shell, auth shells, and runtime config. A distributor imports what it composes and bundles it.",
6
6
  "exports": {
@@ -1,6 +1,5 @@
1
1
  import { Avatar } from "@remit/ui";
2
- import { useNavigate } from "@tanstack/react-router";
3
- import { LogOut, Settings } from "lucide-react";
2
+ import { LogOut } from "lucide-react";
4
3
  import {
5
4
  DropdownMenu,
6
5
  DropdownMenuItem,
@@ -14,7 +13,6 @@ interface AccountMenuViewProps {
14
13
  }
15
14
 
16
15
  const AccountMenuView = ({ email, onSignOut }: AccountMenuViewProps) => {
17
- const navigate = useNavigate();
18
16
  const displayName = email ?? "Account";
19
17
 
20
18
  return (
@@ -36,11 +34,6 @@ const AccountMenuView = ({ email, onSignOut }: AccountMenuViewProps) => {
36
34
  <DropdownMenuSeparator />
37
35
  </>
38
36
  )}
39
- <DropdownMenuItem onClick={() => navigate({ to: "/settings/accounts" })}>
40
- <Settings className="size-4" />
41
- Settings
42
- </DropdownMenuItem>
43
- <DropdownMenuSeparator />
44
37
  <DropdownMenuItem onClick={onSignOut}>
45
38
  <LogOut className="size-4" />
46
39
  Sign out
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * MailTopBar — the app's one search surface and its global actions.
3
3
  *
4
- * Mounted by the `/mail` shell over the list, the reading pane and the
5
- * intelligence rail, starting on the list's left edge. It is the app's search,
6
- * not the list's: the list header drops its own field wherever this bar is
7
- * mounted, so exactly one search input exists on the page and the "/" shortcut
8
- * has one target.
4
+ * Mounted by the `/mail` shell across the top of the whole layout the nav
5
+ * column, the list, the reading pane and the intelligence rail. It is the app's
6
+ * search, not the list's: the list header drops its own field wherever this bar
7
+ * is mounted, so exactly one search input exists on the page and the "/"
8
+ * shortcut has one target.
9
9
  *
10
10
  * The actions here are the ones that belong to the app rather than to whatever
11
- * is currently listed or open — compose, bug report, account. Reply, delete,
12
- * move and the rest stay on the reading pane's own toolbar, under this bar.
11
+ * is currently listed or open — the nav toggle, compose, bug report, settings,
12
+ * account. Reply, delete, move and the rest stay on the reading pane's own
13
+ * toolbar, under this bar.
13
14
  *
14
15
  * The field carries one chip: the scope of the view the user navigated into
15
16
  * (`in:spam` in Spam, nothing on the brief). Removing it goes to the brief and
@@ -19,8 +20,9 @@
19
20
  * sections instead, where the text is not repeated.
20
21
  */
21
22
  import type { RemitImapAccountResponse } from "@remit/api-http-client/types.gen.ts";
22
- import { AppTopBar, Button, SearchBar } from "@remit/ui";
23
- import { SquarePen } from "lucide-react";
23
+ import { AppTopBar, Button, NavToggleButton, SearchBar } from "@remit/ui";
24
+ import { useNavigate } from "@tanstack/react-router";
25
+ import { Settings, SquarePen } from "lucide-react";
24
26
  import { AccountMenu } from "@/auth/AccountMenu";
25
27
  import { BugReportButton } from "@/components/ui/BugReportButton";
26
28
  import { useGlobalCompose } from "@/hooks/useComposeTarget";
@@ -42,6 +44,7 @@ interface MailTopBarProps {
42
44
  export function MailTopBar({ accounts }: MailTopBarProps) {
43
45
  const { searchInput, onSearchChange, onSearchClear, onSearchClearQuery } =
44
46
  useMailContext();
47
+ const navigate = useNavigate();
45
48
  const compose = useGlobalCompose(accounts);
46
49
  const { scope, clearScope } = useSearchScope(accounts);
47
50
  const chips =
@@ -55,6 +58,7 @@ export function MailTopBar({ accounts }: MailTopBarProps) {
55
58
 
56
59
  return (
57
60
  <AppTopBar
61
+ leading={<NavToggleButton />}
58
62
  search={
59
63
  <SearchBar
60
64
  value={searchInput}
@@ -64,7 +68,6 @@ export function MailTopBar({ accounts }: MailTopBarProps) {
64
68
  chips={chips}
65
69
  onRemoveChip={clearScope}
66
70
  placeholder={placeholder}
67
- size="lg"
68
71
  />
69
72
  }
70
73
  actions={
@@ -78,6 +81,14 @@ export function MailTopBar({ accounts }: MailTopBarProps) {
78
81
  onClick={compose}
79
82
  />
80
83
  <BugReportButton />
84
+ <Button
85
+ variant="ghost"
86
+ size="sm"
87
+ icon={<Settings className="size-4" />}
88
+ title="Settings"
89
+ aria-label="Settings"
90
+ onClick={() => navigate({ to: "/settings/accounts" })}
91
+ />
81
92
  <AccountMenu />
82
93
  </>
83
94
  }
@@ -41,6 +41,7 @@
41
41
  import {
42
42
  Button,
43
43
  type FilterSheetProps,
44
+ FilterToggle,
44
45
  isConvertible,
45
46
  MakeFilterAction,
46
47
  MobileSearchView,
@@ -435,9 +436,12 @@ export function MailListHeader({
435
436
  />
436
437
  ),
437
438
  titleMeta: (
438
- <span className="shrink-0 text-2xs text-fg-subtle">
439
- {unreadCount.toLocaleString()} unread
440
- </span>
439
+ <>
440
+ <span className="shrink-0 text-2xs text-fg-subtle">
441
+ {unreadCount.toLocaleString()} unread
442
+ </span>
443
+ {!hasQuery && <FilterToggle />}
444
+ </>
441
445
  ),
442
446
  searchSlot: ownsSearch && !searchExpanded && (
443
447
  <Button
@@ -488,6 +492,7 @@ export function MailListHeader({
488
492
  chromeResults,
489
493
  makeFilterAction,
490
494
  searchConversion,
495
+ hasQuery,
491
496
  ],
492
497
  );
493
498
 
@@ -18,12 +18,13 @@
18
18
  * surface and the section headers flatten correctly when filtered).
19
19
  */
20
20
  import {
21
+ FilterPanelProvider,
21
22
  type FilterPreset,
22
23
  FilterSheet,
23
24
  type FilterSheetProps,
24
25
  type SearchResult,
25
26
  } from "@remit/ui";
26
- import { type ReactNode, useState } from "react";
27
+ import type { ReactNode } from "react";
27
28
  import { useMailContext } from "@/lib/mail-context";
28
29
  import { MailListHeader } from "./MailListHeader";
29
30
 
@@ -81,7 +82,6 @@ export function MailViewChrome({
81
82
  relatedResultsLabel,
82
83
  searchResultsInBody,
83
84
  }: MailViewChromeProps) {
84
- const [expanded, setExpanded] = useState(false);
85
85
  // A query owns the pane: the filter chrome and the search's own affordance
86
86
  // narrow the same list from the same place, so the filter sheet stands down
87
87
  // for as long as something is being searched. Its state survives — clearing
@@ -95,8 +95,6 @@ export function MailViewChrome({
95
95
  sources: preset.sources,
96
96
  selectedCategory,
97
97
  activeFilters,
98
- expanded,
99
- onExpandedChange: setExpanded,
100
98
  onSelectCategory,
101
99
  onSelectSource,
102
100
  onToggleFilter,
@@ -104,26 +102,28 @@ export function MailViewChrome({
104
102
  };
105
103
 
106
104
  return (
107
- <MailListHeader
108
- title={title}
109
- unreadCount={unreadCount}
110
- footer={footer}
111
- searchFilter={filterConfig}
112
- searchResults={searchResults}
113
- searchLoading={searchLoading}
114
- relatedResults={relatedResults}
115
- relatedLoading={relatedLoading}
116
- onSelectSearchResult={onSelectSearchResult}
117
- searchResultsLabel={searchResultsLabel}
118
- relatedResultsLabel={relatedResultsLabel}
119
- searchResultsInBody={searchResultsInBody}
120
- >
121
- {/* One shell either way: the children's parent must not change when a
122
- query starts, or everything under it — including the header's own
123
- search fieldremounts mid-keystroke. */}
124
- <FilterSheet {...filterConfig} hideChrome={searching}>
125
- {children}
126
- </FilterSheet>
127
- </MailListHeader>
105
+ <FilterPanelProvider>
106
+ <MailListHeader
107
+ title={title}
108
+ unreadCount={unreadCount}
109
+ footer={footer}
110
+ searchFilter={filterConfig}
111
+ searchResults={searchResults}
112
+ searchLoading={searchLoading}
113
+ relatedResults={relatedResults}
114
+ relatedLoading={relatedLoading}
115
+ onSelectSearchResult={onSelectSearchResult}
116
+ searchResultsLabel={searchResultsLabel}
117
+ relatedResultsLabel={relatedResultsLabel}
118
+ searchResultsInBody={searchResultsInBody}
119
+ >
120
+ {/* One shell either way: the children's parent must not change when a
121
+ query starts, or everything under it including the header's own
122
+ search field — remounts mid-keystroke. */}
123
+ <FilterSheet {...filterConfig} hideChrome={searching}>
124
+ {children}
125
+ </FilterSheet>
126
+ </MailListHeader>
127
+ </FilterPanelProvider>
128
128
  );
129
129
  }