@columenlabs/lumen-ui 0.1.66 → 0.1.67

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.
@@ -48,7 +48,16 @@ function EmailForm({ adapter, view, inline, }) {
48
48
  const [replacing, setReplacing] = useState(!view.current);
49
49
  const [result, setResult] = useState(null);
50
50
  const [busy, setBusy] = useState(null);
51
- useEffect(() => setDraft(blank(view)), [view]);
51
+ // Each route keeps what was typed for it, so switching back and forth loses nothing.
52
+ const [perRoute, setPerRoute] = useState({});
53
+ // Start over only when the saved settings change, never on a refetch of the same ones.
54
+ const savedKey = `${view.current?.updatedAt ?? ''}|${view.current?.route ?? ''}|${view.current?.url ?? ''}`;
55
+ // biome-ignore lint/correctness/useExhaustiveDependencies: reset only when the saved settings change
56
+ useEffect(() => {
57
+ setDraft(blank(view));
58
+ setReplacing(!view.current);
59
+ setPerRoute({});
60
+ }, [savedKey]);
52
61
  if (!api)
53
62
  return null;
54
63
  const route = view.routes.find((r) => r.id === draft.route);
@@ -107,6 +116,7 @@ function EmailForm({ adapter, view, inline, }) {
107
116
  : 'Test to save' }), changed && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
108
117
  setDraft(blank(view));
109
118
  setReplacing(!view.current);
119
+ setPerRoute({});
110
120
  setResult(null);
111
121
  }, children: "Revert" })), _jsx(SaveButton, { issues: issues, busy: busy === 'save', disabled: !changed, onSave: save })] }));
112
122
  return (_jsxs("div", { className: "flex flex-col", children: [inline ? (_jsx("div", { className: "flex justify-end pb-2", children: badge })) : (_jsx(SettingsActions, { children: badge })), _jsx(Step, { n: 1, title: "Reach the server through", children: _jsx(LumenChoice, { label: "Reach the server through", value: draft.route, options: view.routes.map((r) => ({
@@ -114,9 +124,20 @@ function EmailForm({ adapter, view, inline, }) {
114
124
  icon: r.id === 'public' ? GlobeIcon : CableIcon,
115
125
  title: (_jsxs("span", { className: "flex w-full items-center gap-2", children: [r.label, r.state && (_jsx("span", { className: "ml-auto font-normal text-gain text-xs", children: r.state }))] })),
116
126
  })), onValueChange: (id) => {
127
+ if (id === draft.route)
128
+ return;
129
+ setPerRoute((m) => ({
130
+ ...m,
131
+ [draft.route]: { url: draft.url, apiKey: draft.apiKey ?? '', replacing },
132
+ }));
133
+ const kept = perRoute[id];
117
134
  const next = view.routes.find((r) => r.id === id);
118
- set({ route: id, ...(next?.url && id !== draft.route ? { url: next.url } : {}) });
119
- } }) }), _jsxs(Step, { n: 2, title: "Email server", children: [_jsx(Labelled, { id: `${ids}-url`, label: _jsx(InfoLabel, { info: route?.urlInfo, children: "Server address" }), children: _jsx(Input, { id: `${ids}-url`, className: "font-code text-xs", value: draft.url, placeholder: route?.url ?? 'https://api.resend.com', onChange: (e) => set({ url: e.target.value }) }) }), _jsx(Labelled, { id: `${ids}-key`, label: "API key", children: replacing ? (_jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { id: `${ids}-key`, type: "password", autoComplete: "off", className: "font-code text-xs", value: draft.apiKey ?? '', onChange: (e) => set({ apiKey: e.target.value }) }), view.current && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
135
+ // A saved key belongs to the saved route's server: another route needs its own key.
136
+ const onSaved = !!view.current && view.current.route === id;
137
+ const url = kept?.url ?? (onSaved ? view.current?.url : undefined) ?? next?.url ?? '';
138
+ setReplacing(kept?.replacing ?? !onSaved);
139
+ set({ route: id, url, apiKey: kept?.apiKey ?? '' });
140
+ } }) }), _jsxs(Step, { n: 2, title: "Email server", children: [_jsx(Labelled, { id: `${ids}-url`, label: _jsx(InfoLabel, { info: route?.urlInfo, children: "Server address" }), children: _jsx(Input, { id: `${ids}-url`, className: "font-code text-xs", value: draft.url, placeholder: route?.url ?? 'https://api.resend.com', onChange: (e) => set({ url: e.target.value }) }) }), _jsx(Labelled, { id: `${ids}-key`, label: "API key", children: replacing ? (_jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { id: `${ids}-key`, type: "password", autoComplete: "off", className: "font-code text-xs", value: draft.apiKey ?? '', onChange: (e) => set({ apiKey: e.target.value }) }), view.current && view.current.route === draft.route && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
120
141
  setReplacing(false);
121
142
  set({ apiKey: '' });
122
143
  }, children: "Keep" }))] })) : (_jsxs("div", { className: "flex h-9 items-center gap-3 rounded-md border px-3 text-sm", children: [_jsx("span", { className: "font-code text-muted-foreground text-xs", children: view.current?.keyHint }), _jsx("span", { className: "ml-auto text-gain text-xs", children: "sealed" }), _jsx(Button, { size: "xs", variant: "link", onClick: () => setReplacing(true), children: "Replace" })] })) })] }), _jsx(Step, { n: 3, title: "Sent from", children: _jsxs("div", { className: "flex flex-col gap-3 sm:flex-row", children: [_jsx(Labelled, { id: `${ids}-name`, label: "Name", className: "sm:flex-1", children: _jsx(Input, { id: `${ids}-name`, value: draft.fromName, onChange: (e) => set({ fromName: e.target.value }) }) }), _jsx(Labelled, { id: `${ids}-from`, label: "Address", className: "sm:flex-[1.4]", children: _jsx(Input, { id: `${ids}-from`, type: "email", value: draft.from, placeholder: "hello@example.com", onChange: (e) => set({ from: e.target.value }) }) })] }) }), _jsxs(Step, { n: 4, title: "Test it", children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Button, { size: "sm", variant: "outline", disabled: !ready || !!busy, onClick: () => run('check'), children: [busy === 'check' ? _jsx(Spinner, {}) : _jsx(PlugZapIcon, {}), " Check connection"] }), _jsxs(Button, { size: "sm", variant: "outline", disabled: !ready || !!busy, onClick: () => run('test'), children: [busy === 'test' ? _jsx(Spinner, {}) : _jsx(MailIcon, {}), " Send test to ", view.me] })] }), result && same(result.for, draft) && _jsx(Steps, { check: result.check }), !result && view.lastTest && (_jsxs("p", { className: "text-muted-foreground text-xs", children: ["Last ", view.lastTest.kind === 'test' ? 'test' : 'check', " ", when(view.lastTest.at), ":", ' ', view.lastTest.ok ? 'passed' : 'failed', "."] }))] }), inline ? (_jsx("div", { className: "border-t pt-3", children: footer })) : (_jsx(SettingsFooter, { children: footer }))] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@columenlabs/lumen-ui",
3
- "version": "0.1.66",
3
+ "version": "0.1.67",
4
4
  "description": "Lumen: shared React components (frame, views, widgets, charts, drawers).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,7 +45,7 @@
45
45
  "@codemirror/lang-javascript": "6.2.5",
46
46
  "@codemirror/lang-json": "6.0.2",
47
47
  "@codemirror/lang-sql": "6.10.0",
48
- "@columenlabs/lumen-ui-types": "0.1.66",
48
+ "@columenlabs/lumen-ui-types": "0.1.67",
49
49
  "@dnd-kit/core": "6.3.1",
50
50
  "@dnd-kit/sortable": "10.0.0",
51
51
  "@dnd-kit/utilities": "3.2.2",