@remit/ui 0.0.147 → 0.0.149

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/ui",
3
- "version": "0.0.147",
3
+ "version": "0.0.149",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src"
@@ -0,0 +1,56 @@
1
+ import type { Decorator, Meta, StoryObj } from "@storybook/react";
2
+ import { MailActionToolbar } from "./mail-action-toolbar.js";
3
+
4
+ const meta: Meta<typeof MailActionToolbar> = {
5
+ title: "Kit/MailActionToolbar",
6
+ component: MailActionToolbar,
7
+ parameters: { layout: "centered" },
8
+ decorators: [
9
+ ((Story) => (
10
+ <div
11
+ className="overflow-hidden rounded-lg border border-line"
12
+ style={{ width: 720 }}
13
+ >
14
+ <Story />
15
+ </div>
16
+ )) satisfies Decorator,
17
+ ],
18
+ args: {
19
+ hasThread: true,
20
+ onReply: () => undefined,
21
+ onReplyAll: () => undefined,
22
+ onForward: () => undefined,
23
+ onDelete: () => undefined,
24
+ onMove: () => undefined,
25
+ onToggleStar: () => undefined,
26
+ onUnavailable: () => undefined,
27
+ },
28
+ };
29
+ export default meta;
30
+
31
+ type Story = StoryObj<typeof MailActionToolbar>;
32
+
33
+ /** The conversation has answered and the open message is not starred. */
34
+ export const Default: Story = { args: { isStarred: false } };
35
+
36
+ /** The open message is starred: the star is lit and reads as pressed. It
37
+ * follows the conversation, not the list row that opened it (#602). */
38
+ export const Starred: Story = { args: { isStarred: true } };
39
+
40
+ /** The conversation has not answered yet, so the star state is unknown. The
41
+ * button omits `aria-pressed` rather than announcing "not pressed" for a
42
+ * message that may well be starred. */
43
+ export const StarUnknown: Story = { args: { isStarred: undefined } };
44
+
45
+ /** The mobile pane's management bar already owns triage, so the toolbar drops
46
+ * the cluster instead of offering a second set of the same accessible names. */
47
+ export const WithoutTriage: Story = { args: { showTriage: false } };
48
+
49
+ /** No message open: the verbs no-op and the bar surfaces a one-line reason
50
+ * instead of disabling. */
51
+ export const NoMessageOpen: Story = {
52
+ args: {
53
+ hasThread: false,
54
+ unavailableHint: "Open a message first",
55
+ },
56
+ };
@@ -32,6 +32,11 @@ export interface MailActionToolbarProps {
32
32
  onUnavailable?: (action: MailAction) => void;
33
33
  /** A one-line inline notice rendered under the toolbar (e.g. "Open a message first"). */
34
34
  unavailableHint?: ReactNode;
35
+ /**
36
+ * Whether the open message is starred. Undefined until the conversation
37
+ * says — the button then omits `aria-pressed` rather than announcing an
38
+ * unstarred state it does not know yet.
39
+ */
35
40
  isStarred?: boolean;
36
41
  /**
37
42
  * Whether to render the triage cluster (move-to-trash / move / flag).
@@ -166,6 +171,7 @@ export function MailActionToolbar({
166
171
  }
167
172
  title={flagTitle}
168
173
  aria-label="Star"
174
+ aria-pressed={isStarred}
169
175
  onClick={act("flag", onToggleStar)}
170
176
  />
171
177
  </>
@@ -100,23 +100,12 @@ function Harness({
100
100
  const [displayNames, setDisplayNames] = useState<Record<string, string>>({});
101
101
 
102
102
  const handleAppoint = (role: FolderRole, mailboxId: string | null) => {
103
- setAppointments((prev) => {
104
- const next: Record<string, RoleAppointment> = {
105
- ...prev,
106
- [role]: mailboxId
107
- ? { mailboxId, source: "Appointed" }
108
- : { mailboxId: null, source: "None" },
109
- };
110
- // Exclusivity: appointing a folder to one role clears it from any other.
111
- if (mailboxId) {
112
- for (const other of Object.keys(next)) {
113
- if (other === role) continue;
114
- if (next[other]?.mailboxId !== mailboxId) continue;
115
- next[other] = { mailboxId: null, source: "None" };
116
- }
117
- }
118
- return next;
119
- });
103
+ setAppointments((prev) => ({
104
+ ...prev,
105
+ [role]: mailboxId
106
+ ? { mailboxId, source: "Appointed" }
107
+ : { mailboxId: null, source: "None" },
108
+ }));
120
109
  };
121
110
 
122
111
  const handleRename = (mailboxId: string, name: string) =>
@@ -300,10 +300,9 @@ export function RoleAppointmentList({
300
300
  </h2>
301
301
  <p className="text-xs text-fg-muted">
302
302
  Each role points to one folder. Pick the folder that holds the mail —
303
- the counts help you tell real folders from empty look-alikes.
304
- Appointing a folder here removes it from any other role. Each row says
305
- where its answer came from — your choice, the mail server's own flag,
306
- or a name reader matched.
303
+ the counts help you tell real folders from empty look-alikes. Each row
304
+ says where its answer came from your choice, the mail server's own
305
+ flag, or a name reader matched.
307
306
  </p>
308
307
  </header>
309
308
  <div className="rounded-sm border border-line bg-surface">