@visns-studio/visns-components 6.20.1 → 6.23.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.
Files changed (39) hide show
  1. package/package.json +1 -1
  2. package/src/components/DataGrid.jsx +15 -2
  3. package/src/components/Navigation.jsx +10 -1
  4. package/src/components/columns/SelectFilterEditor.jsx +372 -0
  5. package/src/components/controls/DataGridSearch.jsx +6 -1
  6. package/src/components/layout/AnchoredMenu.jsx +131 -0
  7. package/src/components/layout/BandedList.jsx +158 -0
  8. package/src/components/layout/FactsBand.jsx +150 -0
  9. package/src/components/layout/PageHeader.jsx +90 -0
  10. package/src/components/layout/ScrollRegion.jsx +53 -0
  11. package/src/components/layout/StatStrip.jsx +170 -0
  12. package/src/components/layout/useContainedHeight.js +82 -0
  13. package/src/components/navigation/TabStrip.jsx +156 -0
  14. package/src/components/phone/ZoomPhoneBadge.jsx +625 -0
  15. package/src/components/phone/phonePresenceEndpoints.js +34 -0
  16. package/src/components/phone/phonePresenceHelpers.js +298 -0
  17. package/src/components/phone/useZoomPhoneLive.js +165 -0
  18. package/src/components/sms/SmsClientConversations.jsx +8 -0
  19. package/src/components/sms/SmsInbox.jsx +11 -0
  20. package/src/components/sms/SmsThreadPanel.jsx +258 -29
  21. package/src/components/sms/smsHelpers.js +95 -0
  22. package/src/components/styles/AnchoredMenu.module.scss +43 -0
  23. package/src/components/styles/BandedList.module.scss +278 -0
  24. package/src/components/styles/DataGrid.module.scss +10 -0
  25. package/src/components/styles/FactsBand.module.scss +108 -0
  26. package/src/components/styles/GenericDetail.module.scss +12 -2
  27. package/src/components/styles/PageHeader.module.scss +98 -0
  28. package/src/components/styles/ScrollRegion.module.scss +20 -0
  29. package/src/components/styles/Sms.module.scss +131 -0
  30. package/src/components/styles/StatStrip.module.scss +183 -0
  31. package/src/components/styles/TabStrip.module.scss +96 -0
  32. package/src/components/styles/Vault.module.scss +46 -0
  33. package/src/components/styles/ZoomPhone.module.scss +550 -0
  34. package/src/components/styles/_surface.scss +49 -0
  35. package/src/components/styles/global-datagrid.css +23 -0
  36. package/src/components/vault/VaultAccessLog.jsx +24 -0
  37. package/src/components/vault/VaultShareModal.jsx +126 -5
  38. package/src/components/vault/vaultShares.js +67 -3
  39. package/src/index.js +88 -2
@@ -0,0 +1,183 @@
1
+ @use 'surface' as *;
2
+
3
+ /**
4
+ * StatStrip — the row of labelled figures that sits above a list.
5
+ *
6
+ * Two shapes, because the screens it was lifted from genuinely draw two and
7
+ * neither is wrong:
8
+ *
9
+ * `joined` one card, cells separated by a hairline. The grid's `gap: 1px`
10
+ * is the container's own background showing through, which is how
11
+ * the rules stay exactly one device pixel at any zoom. Reads as a
12
+ * single statement about the set below it.
13
+ * `tiles` separate bordered tiles with real space between them. Reads as
14
+ * independent figures, which is what a dashboard wants — and is
15
+ * the only one of the two that can carry a per-tile emphasis skin
16
+ * without the tint bleeding across a shared border.
17
+ *
18
+ * The track width is a custom property rather than a fixed value so a page can
19
+ * reflow the strip from its own media query (`--vs-stat-min`), or replace the
20
+ * track list outright (`--vs-stat-columns`) for the cases auto-fit cannot
21
+ * express — "exactly two columns on a phone" being the one that keeps coming
22
+ * up.
23
+ */
24
+
25
+ .strip {
26
+ @include surface-tokens;
27
+
28
+ display: grid;
29
+ grid-template-columns: var(
30
+ --vs-stat-columns,
31
+ repeat(auto-fit, minmax(var(--vs-stat-min, 10rem), 1fr))
32
+ );
33
+ }
34
+
35
+ /* One card, hairline-separated. */
36
+ .joined {
37
+ gap: 1px;
38
+ overflow: hidden;
39
+ background: var(--pr-line);
40
+ border: 1px solid var(--pr-line);
41
+ border-radius: var(--pr-radius);
42
+ box-shadow: var(--pr-shadow);
43
+ }
44
+
45
+ /* Separate tiles. */
46
+ .tiles {
47
+ gap: var(--spacing-md, 1rem);
48
+ }
49
+
50
+ /* -------------------------------------------------------------------------- */
51
+ /* one figure */
52
+ /* -------------------------------------------------------------------------- */
53
+
54
+ .stat {
55
+ @include surface-tokens;
56
+
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: 0.15rem;
60
+ min-width: 0;
61
+ padding: 0.85rem var(--spacing-md, 1rem);
62
+ background: var(--pr-surface);
63
+ }
64
+
65
+ .tiles .stat {
66
+ border: 1px solid var(--pr-line);
67
+ border-radius: var(--pr-radius);
68
+ }
69
+
70
+ /* A stat that navigates. It is a real <button>, so everything a button brings
71
+ with it — the browser's font, the centred text, the 2px agent border — has
72
+ to be unwound before it can pass for a cell. */
73
+ .interactive {
74
+ color: inherit;
75
+ font: inherit;
76
+ text-align: left;
77
+ text-decoration: none;
78
+ border: 0;
79
+ cursor: pointer;
80
+ transition: background var(--speed, 160ms) var(--ease, ease);
81
+
82
+ &:hover {
83
+ background: var(--pr-quiet);
84
+ }
85
+
86
+ &:focus-visible {
87
+ outline: 2px solid var(--pr-accent);
88
+ outline-offset: -2px;
89
+ }
90
+ }
91
+
92
+ .tiles .interactive {
93
+ border: 1px solid var(--pr-line);
94
+ }
95
+
96
+ .label {
97
+ color: var(--pr-muted);
98
+ font-size: var(--font-size-xs, 0.75rem);
99
+ letter-spacing: 0.02em;
100
+ text-transform: uppercase;
101
+ }
102
+
103
+ /* The label carries a little more weight inside a hairline grid, where there is
104
+ no border to tell one cell from the next. */
105
+ .joined .label {
106
+ font-weight: 600;
107
+ }
108
+
109
+ .value {
110
+ font-size: 1.35rem;
111
+ font-weight: var(--font-weight-bold, 700);
112
+ /* Tabular figures so a column of money lines up on the decimal point. */
113
+ font-variant-numeric: tabular-nums;
114
+ line-height: 1.2;
115
+ }
116
+
117
+ /* In a tile the figure is the tile's whole content, so it takes the heading
118
+ colour. In a hairline grid it sits in a run of cells and inherits the page's
119
+ ink instead, or the run reads as six headings. */
120
+ .tiles .value {
121
+ color: var(--pr-heading);
122
+ line-height: 1.15;
123
+ }
124
+
125
+ /* `/mo`, `%`, `h` — the unit rides with the figure at small print rather than
126
+ being sized up with it. */
127
+ .unit {
128
+ margin-left: 0.15rem;
129
+ color: var(--pr-muted);
130
+ font-size: 0.8rem;
131
+ font-weight: 400;
132
+ }
133
+
134
+ .note {
135
+ color: var(--pr-muted);
136
+ font-size: var(--font-size-xs, 0.75rem);
137
+ }
138
+
139
+ /* -------------------------------------------------------------------------- */
140
+ /* tone and emphasis */
141
+ /* -------------------------------------------------------------------------- */
142
+
143
+ /* `tone` colours the FIGURE. Applied by the caller only when the figure is
144
+ non-zero — a tile that is permanently red is a tile nobody reads. */
145
+ .toneAccent {
146
+ color: var(--pr-accent);
147
+ }
148
+
149
+ .toneHeading {
150
+ color: var(--pr-heading);
151
+ }
152
+
153
+ .toneWarn {
154
+ color: var(--pr-warn);
155
+ }
156
+
157
+ .toneDanger {
158
+ color: var(--pr-danger);
159
+ }
160
+
161
+ /* A note that has to carry the weight rather than the figure above it — "3
162
+ unpriced" hanging off a money total. */
163
+ .noteWarn {
164
+ color: var(--pr-warn);
165
+ font-weight: var(--font-weight-semibold, 600);
166
+ }
167
+
168
+ /* `emphasis` skins the whole TILE, and only in the `tiles` variant: a tint
169
+ inside a hairline grid would bleed to the cell edges and read as a broken
170
+ border rather than as a warning. */
171
+ .tiles .emphasisWarn {
172
+ background: color-mix(in srgb, var(--pr-warn) 7%, var(--pr-surface));
173
+ border-color: color-mix(in srgb, var(--pr-warn) 42%, var(--pr-line));
174
+ }
175
+
176
+ .tiles .emphasisDanger {
177
+ background: color-mix(in srgb, var(--pr-danger) 5%, var(--pr-surface));
178
+ border-color: color-mix(in srgb, var(--pr-danger) 40%, var(--pr-line));
179
+
180
+ .value {
181
+ color: var(--pr-danger);
182
+ }
183
+ }
@@ -0,0 +1,96 @@
1
+ @use 'surface' as *;
2
+
3
+ /**
4
+ * TabStrip — the underline tabs.
5
+ *
6
+ * The visual language GenericIndex draws, as a component that can be used on its
7
+ * own. Three bespoke screens had rebuilt it by hand, each with the note "the
8
+ * library's tabs are wired to their own state machine, so what is shared is the
9
+ * LOOK, not the code" — which was true, and is the reason this exists: the look
10
+ * belongs in the library even when the state machine does not.
11
+ *
12
+ * The full-width rule is on the STRIP rather than on each tab, and the active
13
+ * tab pulls itself down over it by a pixel, so its underline sits ON that line
14
+ * instead of floating above it.
15
+ */
16
+
17
+ .strip {
18
+ @include surface-tokens;
19
+
20
+ display: flex;
21
+ flex-wrap: wrap;
22
+ gap: var(--spacing-md, 1rem);
23
+ border-bottom: 1px solid var(--pr-line);
24
+ }
25
+
26
+ .tab {
27
+ display: inline-flex;
28
+ gap: 0.4rem;
29
+ align-items: center;
30
+ padding: 0.6rem 0.15rem;
31
+ /* Sits over the strip's own rule. */
32
+ margin-bottom: -1px;
33
+ color: var(--pr-muted);
34
+ font-family: inherit;
35
+ font-size: var(--font-size-sm, 0.8125rem);
36
+ font-weight: var(--font-weight-semibold, 600);
37
+ white-space: nowrap;
38
+ background: none;
39
+ border: 0;
40
+ /* Drawn transparent rather than added on activation, so a tab does not shift
41
+ by 2px the moment it is selected. */
42
+ border-bottom: 2px solid transparent;
43
+ cursor: pointer;
44
+ transition:
45
+ color var(--speed, 160ms) var(--ease, ease),
46
+ border-color var(--speed, 160ms) var(--ease, ease);
47
+
48
+ &:hover:not(:disabled) {
49
+ color: var(--pr-heading);
50
+ }
51
+
52
+ &:focus-visible {
53
+ outline: 2px solid var(--pr-accent);
54
+ outline-offset: 2px;
55
+ }
56
+
57
+ &:disabled {
58
+ cursor: default;
59
+ opacity: 0.5;
60
+ }
61
+ }
62
+
63
+ .active {
64
+ color: var(--pr-heading);
65
+ border-bottom-color: var(--pr-accent);
66
+ }
67
+
68
+ /* -------------------------------------------------------------------------- */
69
+ /* the count on a tab */
70
+ /* -------------------------------------------------------------------------- */
71
+
72
+ /* A count rides along where a tab has one worth pre-empting — it is the
73
+ difference between "go and look at Service health" and "go and look at Service
74
+ health, there are 21 things wrong".
75
+ *
76
+ * Two tones, and the distinction matters: `quiet` is HOW MANY (four tickets on
77
+ * this contact), `danger` is HOW MANY ARE WRONG (twenty-one devices offline). A
78
+ * red pill on a plain count is an alarm about nothing. */
79
+ .badge {
80
+ padding: 0.05rem 0.35rem;
81
+ font-size: var(--font-size-xs, 0.75rem);
82
+ font-variant-numeric: tabular-nums;
83
+ border-radius: var(--radius-pill, 999px);
84
+ }
85
+
86
+ .badgeQuiet {
87
+ color: var(--pr-muted);
88
+ background: var(--pr-quiet);
89
+ border: 1px solid var(--pr-line);
90
+ }
91
+
92
+ .badgeDanger {
93
+ color: #fff;
94
+ background: var(--pr-danger);
95
+ border: 1px solid transparent;
96
+ }
@@ -41,6 +41,11 @@ $vault-mono: 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
41
41
  --v-tint: color-mix(in srgb, var(--v-primary) 12%, var(--v-background));
42
42
  --v-ok: rgb(31, 122, 71);
43
43
  --v-bad: rgb(190, 62, 62);
44
+ // Between the two: something did not happen, and nothing is broken or at
45
+ // risk because of it. Its one user is "the link could not be emailed" —
46
+ // the link itself is fine and on screen right above the line, so painting
47
+ // that in --v-bad would read as "your credential is in trouble".
48
+ --v-warn: rgb(176, 106, 20);
44
49
  }
45
50
 
46
51
  // Undo anything a host may have imposed on a generic element. Applied to every
@@ -2312,6 +2317,47 @@ input.checkControl {
2312
2317
  }
2313
2318
  }
2314
2319
 
2320
+ // "Also emailed to dana@acme.example." Quiet, and under the URL rather than
2321
+ // instead of it: the copy-the-link flow is what actually happened, the email is
2322
+ // a convenience on top of it.
2323
+ .shareEmailed {
2324
+ display: flex;
2325
+ gap: 0.35rem;
2326
+ align-items: flex-start;
2327
+ margin: 0;
2328
+ color: var(--v-ok);
2329
+ font-size: 0.78rem;
2330
+ line-height: 1.45;
2331
+
2332
+ svg {
2333
+ flex-shrink: 0;
2334
+ margin-top: 0.15rem;
2335
+ }
2336
+ }
2337
+
2338
+ // The send failed. Louder than the line above, because the sender is about to
2339
+ // close a dialog believing the recipient has the link — but not red: the link
2340
+ // is on screen and copyable, and nothing about the credential is at risk.
2341
+ .shareEmailFailed {
2342
+ display: flex;
2343
+ gap: 0.35rem;
2344
+ align-items: flex-start;
2345
+ margin: 0;
2346
+ padding: 0.5rem 0.6rem;
2347
+ border: 1px solid color-mix(in srgb, var(--v-warn) 40%, transparent);
2348
+ border-radius: var(--v-btn-br);
2349
+ background: color-mix(in srgb, var(--v-warn) 10%, var(--v-background));
2350
+ color: var(--v-warn);
2351
+ font-size: 0.78rem;
2352
+ font-weight: 500;
2353
+ line-height: 1.45;
2354
+
2355
+ svg {
2356
+ flex-shrink: 0;
2357
+ margin-top: 0.15rem;
2358
+ }
2359
+ }
2360
+
2315
2361
  .shareList {
2316
2362
  display: flex;
2317
2363
  flex-direction: column;