@remit/ui 0.0.11 → 0.0.12
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
|
@@ -51,7 +51,25 @@ const Actions = () => (
|
|
|
51
51
|
|
|
52
52
|
const SCOPE: SearchChip = { id: "in:spam", label: "in:spam", tone: "scope" };
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The placeholders the app pairs with each scope state. Only the unscoped brief
|
|
56
|
+
* may claim to search all mail; a scoped view says so, and a mailbox route
|
|
57
|
+
* whose name has not loaded yet gets neutral wording rather than a placeholder
|
|
58
|
+
* asserting the wrong scope.
|
|
59
|
+
*/
|
|
60
|
+
const PLACEHOLDER = {
|
|
61
|
+
global: "Search all mail",
|
|
62
|
+
pending: "Search mail",
|
|
63
|
+
scoped: "Search this folder",
|
|
64
|
+
} as const;
|
|
65
|
+
|
|
66
|
+
const Bar = ({
|
|
67
|
+
initialChips = [],
|
|
68
|
+
placeholder = PLACEHOLDER.global,
|
|
69
|
+
}: {
|
|
70
|
+
initialChips?: SearchChip[];
|
|
71
|
+
placeholder?: string;
|
|
72
|
+
}) => {
|
|
55
73
|
const [chips, setChips] = useState<SearchChip[]>(initialChips);
|
|
56
74
|
const [value, setValue] = useState("");
|
|
57
75
|
return (
|
|
@@ -71,7 +89,7 @@ const Bar = ({ initialChips = [] }: { initialChips?: SearchChip[] }) => {
|
|
|
71
89
|
}}
|
|
72
90
|
onClearQuery={() => setValue("")}
|
|
73
91
|
globalFocusKey={false}
|
|
74
|
-
placeholder=
|
|
92
|
+
placeholder={placeholder}
|
|
75
93
|
/>
|
|
76
94
|
}
|
|
77
95
|
/>
|
|
@@ -96,24 +114,67 @@ const WithPanes = ({ children }: { children: React.ReactNode }) => (
|
|
|
96
114
|
</div>
|
|
97
115
|
);
|
|
98
116
|
|
|
99
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* The daily brief's state: search unscoped, nothing narrowing it. No chip, and
|
|
119
|
+
* the only placeholder allowed to claim it searches all mail — which it now
|
|
120
|
+
* genuinely does, across every folder of every account.
|
|
121
|
+
*/
|
|
100
122
|
export const Unscoped: Story = {
|
|
101
123
|
render: () => <Bar />,
|
|
102
124
|
};
|
|
103
125
|
|
|
104
126
|
/**
|
|
105
127
|
* A narrowing scope in the bar, tinted to mark it as the view the user is in
|
|
106
|
-
* rather than a filter they typed. Removing it widens the search again
|
|
128
|
+
* rather than a filter they typed. Removing it widens the search again — a
|
|
129
|
+
* navigation back to the brief, not an edit of the text, because the chip
|
|
130
|
+
* mirrors the route.
|
|
131
|
+
*
|
|
132
|
+
* The placeholder narrows with the chip. A scoped bar reading "Search all mail"
|
|
133
|
+
* is a state the app never produces.
|
|
107
134
|
*/
|
|
108
135
|
export const Scoped: Story = {
|
|
109
|
-
render: () => <Bar initialChips={[SCOPE]} />,
|
|
136
|
+
render: () => <Bar initialChips={[SCOPE]} placeholder={PLACEHOLDER.scoped} />,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The third scope state: a mailbox route whose name has not resolved yet. The
|
|
141
|
+
* list underneath is already narrowed, so the bar must not claim to search
|
|
142
|
+
* everything — but a chip reading a raw uuid is worse than no chip, so it shows
|
|
143
|
+
* none and falls back to neutral wording until the name arrives.
|
|
144
|
+
*/
|
|
145
|
+
export const ScopePending: Story = {
|
|
146
|
+
render: () => <Bar placeholder={PLACEHOLDER.pending} />,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The virtual collections scope the bar too, and their chips read as whatever
|
|
151
|
+
* describes the collection. Flagged is a marker on the mail rather than a
|
|
152
|
+
* place, so it chips `is:starred`; the outbox is a place mail sits in and keeps
|
|
153
|
+
* the `in:` form.
|
|
154
|
+
*/
|
|
155
|
+
export const ScopedToFlagged: Story = {
|
|
156
|
+
render: () => (
|
|
157
|
+
<Bar
|
|
158
|
+
initialChips={[{ id: "is:starred", label: "is:starred", tone: "scope" }]}
|
|
159
|
+
placeholder={PLACEHOLDER.scoped}
|
|
160
|
+
/>
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const ScopedToOutbox: Story = {
|
|
165
|
+
render: () => (
|
|
166
|
+
<Bar
|
|
167
|
+
initialChips={[{ id: "in:outbox", label: "in:outbox", tone: "scope" }]}
|
|
168
|
+
placeholder={PLACEHOLDER.scoped}
|
|
169
|
+
/>
|
|
170
|
+
),
|
|
110
171
|
};
|
|
111
172
|
|
|
112
173
|
/** The arrangement: one bar over the nav, the list, and the message pane. */
|
|
113
174
|
export const OverTheLayout: Story = {
|
|
114
175
|
render: () => (
|
|
115
176
|
<WithPanes>
|
|
116
|
-
<Bar initialChips={[SCOPE]} />
|
|
177
|
+
<Bar initialChips={[SCOPE]} placeholder={PLACEHOLDER.scoped} />
|
|
117
178
|
</WithPanes>
|
|
118
179
|
),
|
|
119
180
|
};
|
|
@@ -59,6 +59,7 @@ function MailScreen({
|
|
|
59
59
|
initialExpanded = false,
|
|
60
60
|
initialSearchOpen = false,
|
|
61
61
|
initialSearchValue = "",
|
|
62
|
+
showSearch = true,
|
|
62
63
|
}: {
|
|
63
64
|
title: string;
|
|
64
65
|
unreadCount: number;
|
|
@@ -66,6 +67,7 @@ function MailScreen({
|
|
|
66
67
|
initialExpanded?: boolean;
|
|
67
68
|
initialSearchOpen?: boolean;
|
|
68
69
|
initialSearchValue?: string;
|
|
70
|
+
showSearch?: boolean;
|
|
69
71
|
}) {
|
|
70
72
|
const [searchValue, setSearchValue] = useState(initialSearchValue);
|
|
71
73
|
const [searchOpen, setSearchOpen] = useState(initialSearchOpen);
|
|
@@ -85,6 +87,7 @@ function MailScreen({
|
|
|
85
87
|
title={title}
|
|
86
88
|
unreadCount={unreadCount}
|
|
87
89
|
isDesktop={false}
|
|
90
|
+
showSearch={showSearch}
|
|
88
91
|
onMenuClick={() => undefined}
|
|
89
92
|
searchValue={searchValue}
|
|
90
93
|
onSearchChange={setSearchValue}
|
|
@@ -188,6 +191,43 @@ export const InboxFilterExpanded: Story = {
|
|
|
188
191
|
),
|
|
189
192
|
};
|
|
190
193
|
|
|
194
|
+
/**
|
|
195
|
+
* `showSearch={false}` — the header on desktop, where the app's top bar owns
|
|
196
|
+
* the search field for the whole shell. Title and unread count only: no
|
|
197
|
+
* magnifier, nothing to expand. Two search inputs on one page would compete
|
|
198
|
+
* for focus and for the "/" shortcut, so the header yields.
|
|
199
|
+
*
|
|
200
|
+
* This is what a desktop mail pane renders. Every story below it is the
|
|
201
|
+
* below-desktop case, where there is no top bar and the header keeps its own
|
|
202
|
+
* compact field.
|
|
203
|
+
*/
|
|
204
|
+
export const SearchOwnedByTopBar: Story = {
|
|
205
|
+
render: () => (
|
|
206
|
+
<MailScreen
|
|
207
|
+
title="Daily brief"
|
|
208
|
+
unreadCount={15338}
|
|
209
|
+
preset={briefFilterConfig(accounts)}
|
|
210
|
+
showSearch={false}
|
|
211
|
+
/>
|
|
212
|
+
),
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The same header for a mailbox rather than the brief — still no search
|
|
217
|
+
* affordance, because whether the header owns one is a property of the layout,
|
|
218
|
+
* not of which list is under it.
|
|
219
|
+
*/
|
|
220
|
+
export const SearchOwnedByTopBarInbox: Story = {
|
|
221
|
+
render: () => (
|
|
222
|
+
<MailScreen
|
|
223
|
+
title="Inbox"
|
|
224
|
+
unreadCount={42}
|
|
225
|
+
preset={inboxFilterConfig()}
|
|
226
|
+
showSearch={false}
|
|
227
|
+
/>
|
|
228
|
+
),
|
|
229
|
+
};
|
|
230
|
+
|
|
191
231
|
/** Mobile search collapsed to a magnifier in the header top row. */
|
|
192
232
|
export const MobileSearchCollapsed: Story = {
|
|
193
233
|
render: () => (
|