@brdgapp/ui 0.1.1 → 1.0.0
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/CHANGELOG.md +83 -0
- package/README.md +39 -85
- package/components/action-menu.d.ts +65 -0
- package/components/action-menu.js +48 -0
- package/components/avatar.d.ts +50 -0
- package/components/avatar.js +91 -0
- package/components/badge.d.ts +12 -0
- package/components/badge.js +23 -0
- package/components/bottom-sheet.d.ts +17 -0
- package/components/bottom-sheet.js +12 -0
- package/components/brand-mark.d.ts +20 -0
- package/components/brand-mark.js +44 -0
- package/components/button-group.d.ts +25 -0
- package/components/button-group.js +53 -0
- package/components/button.d.ts +33 -0
- package/components/button.js +82 -0
- package/components/card.d.ts +78 -0
- package/components/card.js +75 -0
- package/components/checkbox.d.ts +22 -0
- package/components/checkbox.js +35 -0
- package/components/collapsible.d.ts +29 -0
- package/components/collapsible.js +38 -0
- package/components/column-filter-menu.d.ts +15 -0
- package/components/column-filter-menu.js +30 -0
- package/components/column-sort-button.d.ts +18 -0
- package/components/column-sort-button.js +14 -0
- package/components/confirm-dialog.d.ts +20 -0
- package/components/confirm-dialog.js +17 -0
- package/components/copy-field.d.ts +17 -0
- package/components/copy-field.js +36 -0
- package/components/data-state.d.ts +44 -0
- package/components/data-state.js +25 -0
- package/components/data-table.d.ts +65 -0
- package/components/data-table.js +84 -0
- package/components/dialog.d.ts +19 -0
- package/components/dialog.js +10 -0
- package/components/drawer.d.ts +21 -0
- package/components/drawer.js +17 -0
- package/components/expandable-bio.d.ts +8 -0
- package/components/expandable-bio.js +26 -0
- package/components/field.d.ts +29 -0
- package/components/field.js +27 -0
- package/components/filter-chip.d.ts +11 -0
- package/components/filter-chip.js +8 -0
- package/components/filter-pill.d.ts +34 -0
- package/components/filter-pill.js +35 -0
- package/components/hover-card.d.ts +21 -0
- package/components/hover-card.js +20 -0
- package/components/icon-button.d.ts +16 -0
- package/components/icon-button.js +32 -0
- package/components/illustration.d.ts +33 -0
- package/components/illustration.js +70 -0
- package/components/info-hint.d.ts +29 -0
- package/components/info-hint.js +42 -0
- package/components/input.d.ts +9 -0
- package/components/input.js +15 -0
- package/components/network-graph.d.ts +48 -0
- package/components/network-graph.js +37 -0
- package/components/page-banner.d.ts +20 -0
- package/components/page-banner.js +29 -0
- package/components/scene.d.ts +12 -0
- package/components/scene.js +7 -0
- package/components/search-input.d.ts +8 -0
- package/components/search-input.js +14 -0
- package/components/segmented-control.d.ts +18 -0
- package/components/segmented-control.js +14 -0
- package/components/skeleton.d.ts +12 -0
- package/components/skeleton.js +21 -0
- package/components/skip-link.d.ts +8 -0
- package/components/skip-link.js +7 -0
- package/components/stat-box.d.ts +23 -0
- package/components/stat-box.js +29 -0
- package/components/switch.d.ts +13 -0
- package/components/switch.js +8 -0
- package/components/tabs.d.ts +6 -0
- package/components/tabs.js +25 -0
- package/components/tag-input.d.ts +15 -0
- package/components/tag-input.js +40 -0
- package/components/tag.d.ts +27 -0
- package/components/tag.js +35 -0
- package/components/textarea.d.ts +12 -0
- package/components/textarea.js +78 -0
- package/components/theme-switch.d.ts +6 -0
- package/components/theme-switch.js +16 -0
- package/components/toast.d.ts +25 -0
- package/components/toast.js +44 -0
- package/hooks/use-is-mobile.d.ts +2 -0
- package/hooks/use-is-mobile.js +16 -0
- package/hooks/use-mock-query.d.ts +23 -0
- package/hooks/use-mock-query.js +36 -0
- package/hooks/use-theme.d.ts +11 -0
- package/hooks/use-theme.js +34 -0
- package/lib/demo-controls.d.ts +24 -0
- package/lib/demo-controls.js +24 -0
- package/lib/format.d.ts +17 -0
- package/lib/format.js +55 -0
- package/lib/layout.d.ts +19 -0
- package/lib/layout.js +24 -0
- package/lib/motion.d.ts +16 -0
- package/lib/motion.js +18 -0
- package/lib/theme.d.ts +21 -0
- package/lib/theme.js +63 -0
- package/lib/utils.d.ts +22 -0
- package/lib/utils.js +27 -0
- package/package.json +32 -16
- package/styles/globals.css +595 -0
- package/src/index.ts +0 -18
- package/src/network-people-helper/README.md +0 -130
- package/src/network-people-helper/api.ts +0 -174
- package/src/network-people-helper/contact-avatar.tsx +0 -63
- package/src/network-people-helper/domain.ts +0 -14
- package/src/network-people-helper/icons.tsx +0 -130
- package/src/network-people-helper/index.ts +0 -6
- package/src/network-people-helper/network-people-helper.tsx +0 -397
- package/src/network-people-helper/network-people-nudge.tsx +0 -98
- package/src/network-people-helper/open-helper.ts +0 -22
- package/src/network-people-helper/person-menu.tsx +0 -211
- package/src/network-people-helper/styles.css +0 -848
- package/src/network-people-helper/types.ts +0 -23
- package/src/network-people-helper/use-network-people-list.ts +0 -122
- package/src/network-people-helper/use-network-preview.ts +0 -43
- package/src/provider.tsx +0 -59
- package/src/styles.css +0 -1
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
@brdgapp/ui — every Bridge token, utility and base rule.
|
|
3
|
+
|
|
4
|
+
Apps import this once, after Tailwind:
|
|
5
|
+
@import "tailwindcss";
|
|
6
|
+
@import "@brdgapp/ui/globals.css";
|
|
7
|
+
|
|
8
|
+
Bridge themes with data-theme on <html> ("light" | "dark"), not the OS setting.
|
|
9
|
+
Token values come unchanged from Bridge OS src/app/globals.css (commit 5d9b382, 2026-10-29).
|
|
10
|
+
Only role tokens ship: the fixed palette names Bridge OS kept in @theme (royal, charcoal, mist…)
|
|
11
|
+
were dropped (decision 2026-11-02; 0 uses). Their names live on as display names in the handbook.
|
|
12
|
+
|
|
13
|
+
Adding a token is deliberately hard: first try an existing role at an opacity. A new token needs a
|
|
14
|
+
light value, a dark value, a handbook entry and a contrast check.
|
|
15
|
+
============================================================================ */
|
|
16
|
+
|
|
17
|
+
/* Tailwind scans the package's own files, so apps don't have to list them. */
|
|
18
|
+
@source "../components";
|
|
19
|
+
@source "../hooks";
|
|
20
|
+
@source "../lib";
|
|
21
|
+
|
|
22
|
+
/* Tailwind's `dark:` follows Bridge's switch instead of the OS setting. */
|
|
23
|
+
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
|
|
24
|
+
|
|
25
|
+
/* --- Tokens: light (default) and dark ------------------------------------- */
|
|
26
|
+
/* Light values also answer to [data-theme="light"], so a light preview can sit inside a dark page. */
|
|
27
|
+
|
|
28
|
+
:root,
|
|
29
|
+
[data-theme="light"] {
|
|
30
|
+
color-scheme: light;
|
|
31
|
+
|
|
32
|
+
/* Surfaces */
|
|
33
|
+
--surface-primary: #FFFFFF;
|
|
34
|
+
--surface-secondary: #F9F9FA;
|
|
35
|
+
--surface-tertiary: #F2F3F5;
|
|
36
|
+
--surface-elevated: #FFFFFF;
|
|
37
|
+
|
|
38
|
+
/* Borders */
|
|
39
|
+
--border-default: #ECEDF0;
|
|
40
|
+
--border-hover: #D9DBE1;
|
|
41
|
+
--border-divider: #F2F3F5;
|
|
42
|
+
|
|
43
|
+
/* Text */
|
|
44
|
+
--text-primary: #0D1531;
|
|
45
|
+
--text-secondary: #3D445A;
|
|
46
|
+
--text-body: #676C7E;
|
|
47
|
+
--text-muted: #6D7284; /* 4.55:1 on --surface-secondary (Bridge OS #6E7385 was 4.48), 4.78 on white. Not for --surface-tertiary: use --text-body there. */
|
|
48
|
+
--text-disabled: #B3B7C4;
|
|
49
|
+
|
|
50
|
+
/* Primary */
|
|
51
|
+
--primary: #0038FF;
|
|
52
|
+
--primary-hover: #0036D7;
|
|
53
|
+
--primary-active: #0028C0;
|
|
54
|
+
|
|
55
|
+
/* Semantic: Success */
|
|
56
|
+
--success: #0EA02E;
|
|
57
|
+
--success-bg: #E7F6EA;
|
|
58
|
+
--success-border: #DBF1E0;
|
|
59
|
+
--success-text: #005F15;
|
|
60
|
+
|
|
61
|
+
/* Semantic: Error */
|
|
62
|
+
--error: #E13535;
|
|
63
|
+
--error-bg: #FCEBEB;
|
|
64
|
+
--error-border: #F9D7D7;
|
|
65
|
+
--error-text: #9E0000;
|
|
66
|
+
|
|
67
|
+
/* Button system — AA-verified fills (WCAG 2.2 AA, both themes; see docs/BUTTON-AUDIT.md).
|
|
68
|
+
Split from --primary/--error because a colour that passes as TEXT can fail as a FILL. */
|
|
69
|
+
--primary-solid: #0038FF; /* primary button fill — white text 4.8:1 */
|
|
70
|
+
--primary-solid-hover: #0036D7;
|
|
71
|
+
--danger-solid: #C72B2B; /* destructive button fill — white text 5.5:1 (brand #E13535 = 4.0:1, failed) */
|
|
72
|
+
--danger-solid-hover: #A82323;
|
|
73
|
+
--danger-text: #C72B2B; /* danger-ghost text — 5.5:1 on white */
|
|
74
|
+
|
|
75
|
+
/* Semantic: Warning */
|
|
76
|
+
--warning: #F59E0B;
|
|
77
|
+
--warning-bg: #FCF4E6;
|
|
78
|
+
--warning-border: #FBEFD9;
|
|
79
|
+
--warning-text: #714A00;
|
|
80
|
+
|
|
81
|
+
/* Accent: Purple */
|
|
82
|
+
--purple: #552BCB;
|
|
83
|
+
--purple-bg: #F6F2FF;
|
|
84
|
+
--purple-border: #F1ECFF;
|
|
85
|
+
|
|
86
|
+
/* Accent: Info */
|
|
87
|
+
--info: #0036D7;
|
|
88
|
+
--info-bg: #EEF4FF;
|
|
89
|
+
--info-border: #E6EEFF;
|
|
90
|
+
|
|
91
|
+
/* Accent: Honey — the alum/outline sticker hue (Arch "Solid label / Warning"). Distinct from
|
|
92
|
+
--warning (amber #F59E0B): honey is the darker Arch value used for the ALUM badge outline. */
|
|
93
|
+
--honey: #E19500;
|
|
94
|
+
|
|
95
|
+
/* Avatar badges — the same in both themes: they mark the person, not the page. The white mark
|
|
96
|
+
on each passes 3:1 (super connector 3.3–6.0, warning 3.6). */
|
|
97
|
+
--super-connector-from: #6A3AF3;
|
|
98
|
+
--super-connector-to: #7A80FF;
|
|
99
|
+
--badge-warning: #B87A00;
|
|
100
|
+
|
|
101
|
+
/* Nav */
|
|
102
|
+
--nav-bg: rgba(255, 255, 255, 0.8);
|
|
103
|
+
|
|
104
|
+
/* CTA Banner */
|
|
105
|
+
--cta-from: #0038FF;
|
|
106
|
+
--cta-to: #0085FF;
|
|
107
|
+
|
|
108
|
+
/* Background glow patches — using design system color tokens */
|
|
109
|
+
--glow-royal: rgba(0, 56, 255, 0.12); /* Primary Royal Blue */
|
|
110
|
+
--glow-purple: rgba(85, 43, 203, 0.10); /* Purple accent */
|
|
111
|
+
--glow-info: rgba(0, 54, 215, 0.08); /* Info Blue */
|
|
112
|
+
--glow-success: rgba(14, 160, 46, 0.06); /* Success Green */
|
|
113
|
+
|
|
114
|
+
/* Liquid Glass tokens */
|
|
115
|
+
--glass-bg: rgba(255, 255, 255, 0.9);
|
|
116
|
+
/* Strong glass (90%): more frosted than the 55% chrome so page content doesn't bleed
|
|
117
|
+
through distractingly, but still clearly a member of the glass family (paired with a
|
|
118
|
+
backdrop-blur) so it belongs next to the frosted TopNav. Used by the Activity rail. */
|
|
119
|
+
--glass-bg-strong: rgba(255, 255, 255, 0.9);
|
|
120
|
+
/* Near-opaque companion for browsers that drop `backdrop-filter` on the nav — see the
|
|
121
|
+
Safari fallback at the bottom of this file. Not a design token; don't use it for cards. */
|
|
122
|
+
--glass-bg-nofilter: rgba(255, 255, 255, 0.94);
|
|
123
|
+
--glass-border: rgba(255, 255, 255, 0.6);
|
|
124
|
+
--glass-highlight: rgba(255, 255, 255, 0.8);
|
|
125
|
+
--glass-shadow-outer: rgba(0, 20, 80, 0.06);
|
|
126
|
+
--glass-shadow-inner: rgba(0, 20, 80, 0.04);
|
|
127
|
+
--glass-rim: rgba(255, 255, 255, 0.35);
|
|
128
|
+
|
|
129
|
+
/* Shadows */
|
|
130
|
+
--shadow-card: 0px 6px 20px rgba(0, 0, 0, 0.15);
|
|
131
|
+
--shadow-dropdown: 0px 4px 20px rgba(0, 0, 0, 0.12);
|
|
132
|
+
/* Elevation levels (decision 2026-11-02), from the most-used Bridge OS values. Use these for
|
|
133
|
+
anything that floats; --shadow-dropdown stays for the tooltips and hover cards that use it today. */
|
|
134
|
+
--shadow-menu: 0px 12px 32px rgba(0, 0, 0, 0.16); /* dropdowns, menus, filter popovers */
|
|
135
|
+
--shadow-dialog: 0px 24px 64px rgba(0, 0, 0, 0.22); /* dialogs, confirms, modals */
|
|
136
|
+
--shadow-drawer: -8px 0px 32px rgba(0, 0, 0, 0.12); /* side drawers (light falls from the left edge) */
|
|
137
|
+
|
|
138
|
+
/* Selection */
|
|
139
|
+
--selection-bg: rgba(0, 56, 255, 0.2);
|
|
140
|
+
--selection-text: #0038FF;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
[data-theme="dark"] {
|
|
144
|
+
color-scheme: dark;
|
|
145
|
+
|
|
146
|
+
/* Surfaces */
|
|
147
|
+
--surface-primary: #0B0F1A;
|
|
148
|
+
--surface-secondary: #111627;
|
|
149
|
+
--surface-tertiary: #1A2035;
|
|
150
|
+
--surface-elevated: #151B2E;
|
|
151
|
+
|
|
152
|
+
/* Borders */
|
|
153
|
+
--border-default: #252D44;
|
|
154
|
+
--border-hover: #3A4460;
|
|
155
|
+
--border-divider: #1E2640;
|
|
156
|
+
|
|
157
|
+
/* Text */
|
|
158
|
+
--text-primary: #F0F1F4;
|
|
159
|
+
--text-secondary: #C8CCD8;
|
|
160
|
+
--text-body: #9BA1B4;
|
|
161
|
+
--text-muted: #868CA3;
|
|
162
|
+
--text-disabled: #505872;
|
|
163
|
+
|
|
164
|
+
/* Primary */
|
|
165
|
+
--primary: #4D7AFF;
|
|
166
|
+
--primary-hover: #6B91FF;
|
|
167
|
+
--primary-active: #3A66E8;
|
|
168
|
+
|
|
169
|
+
/* Semantic: Success */
|
|
170
|
+
--success: #34C759;
|
|
171
|
+
--success-bg: rgba(52, 199, 89, 0.12);
|
|
172
|
+
--success-border: rgba(52, 199, 89, 0.2);
|
|
173
|
+
--success-text: #4ADE80;
|
|
174
|
+
|
|
175
|
+
/* Semantic: Error */
|
|
176
|
+
--error: #FF6B6B;
|
|
177
|
+
--error-bg: rgba(255, 107, 107, 0.12);
|
|
178
|
+
--error-border: rgba(255, 107, 107, 0.2);
|
|
179
|
+
--error-text: #FFA0A0;
|
|
180
|
+
|
|
181
|
+
/* Button system — AA fills (dark). A fill must be dark enough for white text; text can be lighter. */
|
|
182
|
+
--primary-solid: #2F5BFF; /* primary fill — white text 5.2:1 (--primary #4D7AFF = 3.8:1, failed as a fill) */
|
|
183
|
+
--primary-solid-hover: #3D68F5;
|
|
184
|
+
--danger-solid: #C0392B; /* destructive fill — white text 5.4:1 */
|
|
185
|
+
--danger-solid-hover: #D0463A;
|
|
186
|
+
--danger-text: #F58A8A; /* danger-ghost text — 5.8:1 on dark surface */
|
|
187
|
+
|
|
188
|
+
/* Semantic: Warning */
|
|
189
|
+
--warning: #FBBF24;
|
|
190
|
+
--warning-bg: rgba(251, 191, 36, 0.12);
|
|
191
|
+
--warning-border: rgba(251, 191, 36, 0.2);
|
|
192
|
+
--warning-text: #FCD34D;
|
|
193
|
+
|
|
194
|
+
/* Accent: Purple */
|
|
195
|
+
--purple: #9A81ED; /* lightened from #8B6EE8 so purple tag text passes 4.5:1 on every dark surface (was 4.42) */
|
|
196
|
+
--purple-bg: rgba(139, 110, 232, 0.12);
|
|
197
|
+
--purple-border: rgba(139, 110, 232, 0.2);
|
|
198
|
+
|
|
199
|
+
/* Accent: Info */
|
|
200
|
+
--info: #60A5FA;
|
|
201
|
+
--info-bg: rgba(96, 165, 250, 0.12);
|
|
202
|
+
--info-border: rgba(96, 165, 250, 0.2);
|
|
203
|
+
|
|
204
|
+
/* Accent: Honey (alum/outline sticker) — lightened for dark surfaces */
|
|
205
|
+
--honey: #F5C451;
|
|
206
|
+
|
|
207
|
+
/* Avatar badges — the same in both themes: they mark the person, not the page. The white mark
|
|
208
|
+
on each passes 3:1 (super connector 3.3–6.0, warning 3.6). */
|
|
209
|
+
--super-connector-from: #6A3AF3;
|
|
210
|
+
--super-connector-to: #7A80FF;
|
|
211
|
+
--badge-warning: #B87A00;
|
|
212
|
+
|
|
213
|
+
/* Nav */
|
|
214
|
+
--nav-bg: rgba(11, 15, 26, 0.85);
|
|
215
|
+
|
|
216
|
+
/* CTA Banner — muted in dark mode */
|
|
217
|
+
--cta-from: #0D1531;
|
|
218
|
+
--cta-to: #151B2E;
|
|
219
|
+
|
|
220
|
+
/* Background glow patches */
|
|
221
|
+
--glow-royal: rgba(77, 122, 255, 0.15);
|
|
222
|
+
--glow-purple: rgba(139, 110, 232, 0.12);
|
|
223
|
+
--glow-info: rgba(96, 165, 250, 0.10);
|
|
224
|
+
--glow-success: rgba(52, 199, 89, 0.08);
|
|
225
|
+
|
|
226
|
+
/* Liquid Glass tokens */
|
|
227
|
+
--glass-bg: rgba(21, 27, 46, 0.9);
|
|
228
|
+
--glass-bg-strong: rgba(21, 27, 46, 0.9);
|
|
229
|
+
--glass-bg-nofilter: rgba(21, 27, 46, 0.94);
|
|
230
|
+
--glass-border: rgba(255, 255, 255, 0.08);
|
|
231
|
+
--glass-highlight: rgba(255, 255, 255, 0.06);
|
|
232
|
+
--glass-shadow-outer: rgba(0, 0, 0, 0.3);
|
|
233
|
+
--glass-shadow-inner: rgba(0, 0, 0, 0.2);
|
|
234
|
+
--glass-rim: rgba(255, 255, 255, 0.08);
|
|
235
|
+
|
|
236
|
+
/* Shadows */
|
|
237
|
+
--shadow-card: 0px 6px 20px rgba(0, 0, 0, 0.5);
|
|
238
|
+
--shadow-dropdown: 0px 4px 20px rgba(0, 0, 0, 0.6);
|
|
239
|
+
/* Dark values follow the existing pattern (shadows ~4x stronger on dark surfaces). Review by eye. */
|
|
240
|
+
--shadow-menu: 0px 12px 32px rgba(0, 0, 0, 0.55);
|
|
241
|
+
--shadow-dialog: 0px 24px 64px rgba(0, 0, 0, 0.65);
|
|
242
|
+
--shadow-drawer: -8px 0px 32px rgba(0, 0, 0, 0.5);
|
|
243
|
+
|
|
244
|
+
/* Selection */
|
|
245
|
+
--selection-bg: rgba(77, 122, 255, 0.3);
|
|
246
|
+
--selection-text: #4D7AFF;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
/* --- Tailwind theme ------------------------------------------------------- */
|
|
251
|
+
@theme inline {
|
|
252
|
+
--font-sans: var(--font-mulish, "Mulish"), system-ui, sans-serif;
|
|
253
|
+
|
|
254
|
+
/* Type sizes, each with its line height (decisions 2026-11-03, from a survey of all 12 apps). One ladder,
|
|
255
|
+
one job per step: 11 eyebrow · 12 meta · 13 dense body · 14 body · 16 small title · 18 title ·
|
|
256
|
+
22 page title and stat · 28 / 36 / 48 display (public pages, growing with the screen). Named by size,
|
|
257
|
+
because Tailwind's text-* also makes color classes and --text-body is a color here. A plain
|
|
258
|
+
text-[13px] still works but sets no line height. */
|
|
259
|
+
--text-11: 11px;
|
|
260
|
+
--text-11--line-height: 16px;
|
|
261
|
+
--text-12: 12px;
|
|
262
|
+
--text-12--line-height: 16px;
|
|
263
|
+
--text-13: 13px;
|
|
264
|
+
--text-13--line-height: 20px;
|
|
265
|
+
--text-14: 14px;
|
|
266
|
+
--text-14--line-height: 20px;
|
|
267
|
+
--text-16: 16px;
|
|
268
|
+
--text-16--line-height: 24px;
|
|
269
|
+
--text-18: 18px;
|
|
270
|
+
--text-18--line-height: 26px;
|
|
271
|
+
--text-22: 22px;
|
|
272
|
+
--text-22--line-height: 28px;
|
|
273
|
+
--text-28: 28px;
|
|
274
|
+
--text-28--line-height: 34px;
|
|
275
|
+
--text-36: 36px;
|
|
276
|
+
--text-36--line-height: 42px;
|
|
277
|
+
--text-48: 48px;
|
|
278
|
+
--text-48--line-height: 56px;
|
|
279
|
+
|
|
280
|
+
/* Motion (decision 2026-11-03): one curve for everything that moves, Bridge OS's drawer curve: fast
|
|
281
|
+
out of the gate, gentle landing. It replaces Tailwind's ease-out, so every `ease-out` uses it. Three
|
|
282
|
+
speeds go with it: 150ms quick (hover, color, press), 200ms base (menus, sections, toasts), 300ms slow
|
|
283
|
+
(drawers, sheets, dialogs). JavaScript animations read the same values from @brdgapp/ui/lib/motion. */
|
|
284
|
+
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
|
|
285
|
+
|
|
286
|
+
/* Entrance and exit animations, on the three speeds: things arrive on the curve, and leave a step faster. */
|
|
287
|
+
--animate-fade-in: fadeIn 0.2s var(--ease-out);
|
|
288
|
+
--animate-fade-in-up: fadeInUp 0.3s var(--ease-out);
|
|
289
|
+
--animate-scale-in: scaleIn 0.2s var(--ease-out);
|
|
290
|
+
--animate-scale-out: scaleOut 0.15s ease-in;
|
|
291
|
+
--animate-fade-out: fadeOut 0.15s ease-in;
|
|
292
|
+
--animate-slide-in-right: slideInRight 0.3s var(--ease-out);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* --- Base ----------------------------------------------------------------- */
|
|
296
|
+
body {
|
|
297
|
+
background: var(--surface-primary);
|
|
298
|
+
color: var(--text-primary);
|
|
299
|
+
font-family: var(--font-mulish, "Mulish"), system-ui, sans-serif;
|
|
300
|
+
font-weight: 400;
|
|
301
|
+
letter-spacing: -0.01em;
|
|
302
|
+
-webkit-font-smoothing: antialiased;
|
|
303
|
+
-moz-osx-font-smoothing: grayscale;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
::selection {
|
|
307
|
+
background: var(--selection-bg);
|
|
308
|
+
color: var(--selection-text);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* --- Focus ---
|
|
312
|
+
Every package component draws its own solid 2px ring. This is the safety net for anything an app builds
|
|
313
|
+
itself (a plain link, a <button>, a row with tabindex): a solid blue outline for keyboard users, never on
|
|
314
|
+
a mouse click. A component's own `outline-none` + ring wins over it. Solid, not 40%, so it clears WCAG's
|
|
315
|
+
3:1 (7:1 light, 5:1 dark); decided 2026-11-03. Bridge OS's global `:focus-visible { outline: none }` is
|
|
316
|
+
not copied: it hid focus on anything without its own ring. */
|
|
317
|
+
:where(a[href], button, input, select, textarea, summary, [tabindex]:not([tabindex="-1"]), [role="button"]):focus-visible {
|
|
318
|
+
outline: 2px solid var(--primary);
|
|
319
|
+
outline-offset: 2px;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* SkipLink: off screen until it has keyboard focus, then top-left above everything. */
|
|
323
|
+
[data-slot="skip-link"]:not(:focus) {
|
|
324
|
+
position: absolute;
|
|
325
|
+
width: 1px;
|
|
326
|
+
height: 1px;
|
|
327
|
+
overflow: hidden;
|
|
328
|
+
clip-path: inset(50%);
|
|
329
|
+
white-space: nowrap;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* --- Scrollbar --- */
|
|
333
|
+
::-webkit-scrollbar { width: 6px; height: 6px; }
|
|
334
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
335
|
+
::-webkit-scrollbar-thumb { background: var(--border-hover); border-radius: 3px; }
|
|
336
|
+
::-webkit-scrollbar-thumb:hover { background: var(--text-disabled); }
|
|
337
|
+
|
|
338
|
+
/* Hide the scrollbar entirely while keeping scrollability (e.g. horizontal tab bars). */
|
|
339
|
+
.scrollbar-none { scrollbar-width: none; -ms-overflow-style: none; }
|
|
340
|
+
.scrollbar-none::-webkit-scrollbar { display: none; }
|
|
341
|
+
|
|
342
|
+
/* Hover-reveal scrollbar: thumb is invisible at rest and fades in only while the
|
|
343
|
+
container is hovered. Used by the Activity rail — a permanently-visible track in
|
|
344
|
+
its narrow gutter reads as a thick, ugly border. The 6px track from the global
|
|
345
|
+
rule stays reserved either way, so revealing the thumb causes no reflow. Thumb is
|
|
346
|
+
the light --border-hover, not the darker --text-disabled the global rule hovers to. */
|
|
347
|
+
.scrollbar-hover { scrollbar-width: thin; scrollbar-color: transparent transparent; }
|
|
348
|
+
.scrollbar-hover::-webkit-scrollbar-thumb { background: transparent; transition: background 150ms ease; }
|
|
349
|
+
.scrollbar-hover:hover { scrollbar-color: var(--border-hover) transparent; }
|
|
350
|
+
.scrollbar-hover:hover::-webkit-scrollbar-thumb { background: var(--border-hover); }
|
|
351
|
+
|
|
352
|
+
/* --- Reduced Motion --- */
|
|
353
|
+
/* Spinners keep turning: people still need to see that something is happening. (Bridge OS's rule
|
|
354
|
+
froze them too; changed in the package, 2026-11-02.) */
|
|
355
|
+
@media (prefers-reduced-motion: reduce) {
|
|
356
|
+
*:not(.animate-spin),
|
|
357
|
+
*::before,
|
|
358
|
+
*::after {
|
|
359
|
+
animation-duration: 0.01ms !important;
|
|
360
|
+
transition-duration: 0.01ms !important;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/* --- Keyframes --- */
|
|
365
|
+
@keyframes fadeIn {
|
|
366
|
+
from { opacity: 0; }
|
|
367
|
+
to { opacity: 1; }
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
@keyframes fadeInUp {
|
|
371
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
372
|
+
to { opacity: 1; transform: translateY(0); }
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@keyframes scaleIn {
|
|
376
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
377
|
+
to { opacity: 1; transform: scale(1); }
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@keyframes scaleOut {
|
|
381
|
+
from { opacity: 1; transform: scale(1); }
|
|
382
|
+
to { opacity: 0; transform: scale(0.95); }
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
@keyframes fadeOut {
|
|
386
|
+
from { opacity: 1; }
|
|
387
|
+
to { opacity: 0; }
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@keyframes slideInRight {
|
|
391
|
+
from { opacity: 0; transform: translateX(8px); }
|
|
392
|
+
to { opacity: 1; transform: translateX(0); }
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* --- Stagger Delays --- */
|
|
396
|
+
.anim-delay-1 { animation-delay: 50ms; }
|
|
397
|
+
.anim-delay-2 { animation-delay: 100ms; }
|
|
398
|
+
.anim-delay-3 { animation-delay: 150ms; }
|
|
399
|
+
.anim-delay-4 { animation-delay: 200ms; }
|
|
400
|
+
.anim-delay-5 { animation-delay: 250ms; }
|
|
401
|
+
.anim-delay-6 { animation-delay: 300ms; }
|
|
402
|
+
|
|
403
|
+
/* --- Page Visual Polish --- */
|
|
404
|
+
|
|
405
|
+
/* 1. Dot grid background — SVG-based, tiles seamlessly */
|
|
406
|
+
.bg-dot-grid {
|
|
407
|
+
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='12' cy='12' r='0.75' fill='%230038FF' fill-opacity='0.12'/%3E%3C/svg%3E");
|
|
408
|
+
background-repeat: repeat;
|
|
409
|
+
background-size: 24px 24px;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
[data-theme="dark"] .bg-dot-grid {
|
|
413
|
+
background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='12' cy='12' r='0.75' fill='%234D7AFF' fill-opacity='0.15'/%3E%3C/svg%3E");
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* 2. Noise grain texture — SVG feTurbulence */
|
|
417
|
+
.bg-noise::before {
|
|
418
|
+
content: '';
|
|
419
|
+
position: absolute;
|
|
420
|
+
inset: 0;
|
|
421
|
+
z-index: 0;
|
|
422
|
+
opacity: 0.03;
|
|
423
|
+
pointer-events: none;
|
|
424
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
|
|
425
|
+
background-repeat: repeat;
|
|
426
|
+
background-size: 256px 256px;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* 3. Glow patches — scattered radial blobs for glassmorphism depth.
|
|
430
|
+
NOTE: must be `absolute` (scoped to this wrapper), NOT `position: fixed`.
|
|
431
|
+
A viewport-fixed element sits permanently in the sticky TopNav's backdrop,
|
|
432
|
+
and a fixed element inside a backdrop-filter's backdrop makes the blur
|
|
433
|
+
silently fail in Safari/WebKit — the nav then renders as just its 55%-opaque
|
|
434
|
+
background and page content reads straight through it. Keeping the glow
|
|
435
|
+
absolute (the wrapper lives below the nav in flow) keeps it out of the nav's
|
|
436
|
+
backdrop so the frosted blur composites reliably. */
|
|
437
|
+
.bg-glow-patches {
|
|
438
|
+
position: relative;
|
|
439
|
+
}
|
|
440
|
+
.bg-glow-patches::after {
|
|
441
|
+
content: '';
|
|
442
|
+
position: absolute;
|
|
443
|
+
inset: 0;
|
|
444
|
+
z-index: 0;
|
|
445
|
+
pointer-events: none;
|
|
446
|
+
background:
|
|
447
|
+
/* Top-left — Royal Blue blob */
|
|
448
|
+
radial-gradient(ellipse 35% 30% at 8% 8%, var(--glow-royal), transparent),
|
|
449
|
+
/* Top-right — Purple blob */
|
|
450
|
+
radial-gradient(ellipse 30% 25% at 85% 5%, var(--glow-purple), transparent),
|
|
451
|
+
/* Center-left — Info Blue blob */
|
|
452
|
+
radial-gradient(ellipse 25% 20% at 15% 55%, var(--glow-info), transparent),
|
|
453
|
+
/* Center-right — Purple shifted */
|
|
454
|
+
radial-gradient(ellipse 28% 22% at 78% 45%, var(--glow-purple), transparent),
|
|
455
|
+
/* Bottom-center — Success green blob */
|
|
456
|
+
radial-gradient(ellipse 30% 25% at 50% 85%, var(--glow-success), transparent),
|
|
457
|
+
/* Bottom-right — Royal Blue blob */
|
|
458
|
+
radial-gradient(ellipse 22% 18% at 90% 75%, var(--glow-royal), transparent);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* 4. Liquid Glass — Apple-inspired frosted panel effect */
|
|
462
|
+
.liquid-glass {
|
|
463
|
+
background: var(--glass-bg);
|
|
464
|
+
backdrop-filter: blur(24px) saturate(1.5);
|
|
465
|
+
-webkit-backdrop-filter: blur(24px) saturate(1.5);
|
|
466
|
+
border: 1px solid var(--glass-border);
|
|
467
|
+
box-shadow:
|
|
468
|
+
/* Outer shadow — soft ambient depth */
|
|
469
|
+
0 4px 24px var(--glass-shadow-outer),
|
|
470
|
+
0 1px 3px var(--glass-shadow-outer),
|
|
471
|
+
/* Inner shadow — concave depth */
|
|
472
|
+
inset 0 -1px 2px var(--glass-shadow-inner),
|
|
473
|
+
/* Rim light — top edge specular highlight */
|
|
474
|
+
inset 0 1px 0 var(--glass-rim);
|
|
475
|
+
position: relative;
|
|
476
|
+
overflow: hidden;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/* Specular highlight — gradient shine across the top */
|
|
480
|
+
.liquid-glass::before {
|
|
481
|
+
content: '';
|
|
482
|
+
position: absolute;
|
|
483
|
+
top: 0;
|
|
484
|
+
left: 0;
|
|
485
|
+
right: 0;
|
|
486
|
+
height: 50%;
|
|
487
|
+
background: linear-gradient(
|
|
488
|
+
180deg,
|
|
489
|
+
var(--glass-highlight) 0%,
|
|
490
|
+
transparent 100%
|
|
491
|
+
);
|
|
492
|
+
pointer-events: none;
|
|
493
|
+
z-index: 1;
|
|
494
|
+
border-radius: inherit;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
/* --- Card ------------------------------------------------------------------- */
|
|
499
|
+
/* Here, not in Tailwind classes, because the glass rule outranks Tailwind's background, border and
|
|
500
|
+
shadow classes. A clickable card has an invisible link or button (the cover) across it; the content
|
|
501
|
+
sits on top and lets clicks fall through to the cover, except its own controls. */
|
|
502
|
+
[data-slot="card"] > [data-card-cover] {
|
|
503
|
+
position: absolute;
|
|
504
|
+
inset: 0;
|
|
505
|
+
z-index: 1;
|
|
506
|
+
margin: 0;
|
|
507
|
+
padding: 0;
|
|
508
|
+
border: 0;
|
|
509
|
+
border-radius: inherit;
|
|
510
|
+
background: transparent;
|
|
511
|
+
outline: none;
|
|
512
|
+
cursor: pointer;
|
|
513
|
+
}
|
|
514
|
+
[data-slot="card"] > [data-card-cover]:disabled { cursor: not-allowed; }
|
|
515
|
+
[data-slot="card"][data-clickable] > :not([data-card-cover]) {
|
|
516
|
+
position: relative;
|
|
517
|
+
z-index: 2;
|
|
518
|
+
pointer-events: none;
|
|
519
|
+
}
|
|
520
|
+
[data-slot="card"][data-clickable] :is(a[href], button, input, select, textarea, label, summary, [role="button"], [role="link"], [role="checkbox"], [role="switch"], [role="menuitem"], [tabindex]:not([tabindex="-1"])) {
|
|
521
|
+
pointer-events: auto;
|
|
522
|
+
}
|
|
523
|
+
[data-slot="card"]:has(> [data-card-cover]:focus-visible) {
|
|
524
|
+
outline: 2px solid var(--primary);
|
|
525
|
+
outline-offset: 2px;
|
|
526
|
+
}
|
|
527
|
+
/* Links rise (the translate is a class on the card) with a soft shadow. */
|
|
528
|
+
.liquid-glass[data-slot="card"][data-clickable="link"]:not([data-disabled]):hover {
|
|
529
|
+
box-shadow:
|
|
530
|
+
var(--shadow-card),
|
|
531
|
+
inset 0 -1px 2px var(--glass-shadow-inner),
|
|
532
|
+
inset 0 1px 0 var(--glass-rim);
|
|
533
|
+
}
|
|
534
|
+
/* Selectable cards tint. */
|
|
535
|
+
.liquid-glass[data-slot="card"][data-clickable="select"]:not([data-disabled]):not([data-selected]):hover {
|
|
536
|
+
background:
|
|
537
|
+
linear-gradient(color-mix(in srgb, var(--text-primary) 3%, transparent), color-mix(in srgb, var(--text-primary) 3%, transparent)),
|
|
538
|
+
var(--glass-bg);
|
|
539
|
+
}
|
|
540
|
+
.liquid-glass[data-slot="card"][data-selected] {
|
|
541
|
+
border-color: color-mix(in srgb, var(--primary) 40%, transparent);
|
|
542
|
+
background:
|
|
543
|
+
linear-gradient(color-mix(in srgb, var(--primary) 5%, transparent), color-mix(in srgb, var(--primary) 5%, transparent)),
|
|
544
|
+
var(--glass-bg);
|
|
545
|
+
}
|
|
546
|
+
[data-slot="card"][data-bare][data-clickable]:not([data-disabled]):not([data-selected]):hover {
|
|
547
|
+
background: var(--surface-secondary);
|
|
548
|
+
}
|
|
549
|
+
[data-slot="card"][data-bare][data-selected] {
|
|
550
|
+
background: color-mix(in srgb, var(--primary) 6%, transparent);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/* Ensure content sits above the highlight */
|
|
554
|
+
.liquid-glass > * {
|
|
555
|
+
position: relative;
|
|
556
|
+
z-index: 2;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* The top bar's glass (and anything else fixed to the screen's edge, like a side rail): a stronger blur
|
|
560
|
+
than a card, a hairline under it, and the same rim. One class, so every app's top bar matches. Taken from
|
|
561
|
+
Bridge OS top-nav.tsx, where these were written out as classes on the <nav>; made one utility 2026-11-03.
|
|
562
|
+
liquid-glass-sm (a lighter glass no app or component used) was removed the same day. */
|
|
563
|
+
.glass-chrome {
|
|
564
|
+
background: var(--glass-bg);
|
|
565
|
+
backdrop-filter: blur(40px) saturate(1.5);
|
|
566
|
+
-webkit-backdrop-filter: blur(40px) saturate(1.5);
|
|
567
|
+
border-bottom: 1px solid var(--glass-border);
|
|
568
|
+
box-shadow:
|
|
569
|
+
0 1px 3px var(--glass-shadow-outer),
|
|
570
|
+
inset 0 -1px 1px var(--glass-shadow-inner),
|
|
571
|
+
inset 0 1px 0 var(--glass-rim);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/* ── Safari fallback: chrome that can't rely on its own blur ──────────────────
|
|
575
|
+
WebKit silently drops `backdrop-filter` when a `position: fixed` element sits
|
|
576
|
+
in the filtered element's backdrop. The Activity tab's "Recently met" rail is
|
|
577
|
+
exactly that (`fixed top-14 right-0`, and itself backdrop-blurred), so in
|
|
578
|
+
Safari the sticky TopNav fell back to its 55%-opaque background and feed
|
|
579
|
+
content read straight through it while scrolling. Chrome and Firefox
|
|
580
|
+
composite it correctly, which is why this only ever showed up on one browser,
|
|
581
|
+
on one tab.
|
|
582
|
+
|
|
583
|
+
`-webkit-hyphens: none` is the standard Safari-only feature query. The blur
|
|
584
|
+
still applies where it works; this only swaps the background for a
|
|
585
|
+
near-opaque one where it doesn't, so the chrome stays readable either way.
|
|
586
|
+
|
|
587
|
+
The real fix is for the rail not to be `position: fixed` — that's a layout
|
|
588
|
+
change (the feed's `--rail-reserve` padding and the collapse animation both
|
|
589
|
+
assume it), so it's deliberately not bundled with this. If the rail ever
|
|
590
|
+
stops being fixed, delete this block and `--glass-bg-nofilter` with it. */
|
|
591
|
+
@supports (-webkit-hyphens: none) {
|
|
592
|
+
.glass-chrome {
|
|
593
|
+
background: var(--glass-bg-nofilter);
|
|
594
|
+
}
|
|
595
|
+
}
|
package/src/index.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import "./styles.css"
|
|
4
|
-
|
|
5
|
-
export { BridgeUIProvider, DEFAULT_API_BASE_URL } from "./provider"
|
|
6
|
-
export type { BridgeUIProviderProps } from "./provider"
|
|
7
|
-
export {
|
|
8
|
-
NetworkPeopleHelper,
|
|
9
|
-
NetworkPeopleNudge,
|
|
10
|
-
openNetworkPeopleHelper,
|
|
11
|
-
} from "./network-people-helper"
|
|
12
|
-
export type {
|
|
13
|
-
NetworkPeopleHelperProps,
|
|
14
|
-
NetworkPeopleNudgeProps,
|
|
15
|
-
NetworkContact,
|
|
16
|
-
NetworkPersonAction,
|
|
17
|
-
HelperPlacement,
|
|
18
|
-
} from "./network-people-helper"
|