@visns-studio/visns-components 6.20.0 → 6.21.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/package.json +1 -1
- package/src/components/generic/GenericIndex.jsx +9 -1
- package/src/components/layout/AnchoredMenu.jsx +131 -0
- package/src/components/layout/BandedList.jsx +158 -0
- package/src/components/layout/FactsBand.jsx +150 -0
- package/src/components/layout/PageHeader.jsx +90 -0
- package/src/components/layout/ScrollRegion.jsx +53 -0
- package/src/components/layout/StatStrip.jsx +170 -0
- package/src/components/layout/useContainedHeight.js +82 -0
- package/src/components/navigation/TabStrip.jsx +156 -0
- package/src/components/sms/smsHelpers.js +58 -0
- package/src/components/styles/AnchoredMenu.module.scss +43 -0
- package/src/components/styles/BandedList.module.scss +278 -0
- package/src/components/styles/FactsBand.module.scss +108 -0
- package/src/components/styles/PageHeader.module.scss +98 -0
- package/src/components/styles/ScrollRegion.module.scss +20 -0
- package/src/components/styles/StatStrip.module.scss +183 -0
- package/src/components/styles/TabStrip.module.scss +96 -0
- package/src/components/styles/_surface.scss +49 -0
- package/src/index.js +47 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface language the page primitives are drawn in.
|
|
3
|
+
*
|
|
4
|
+
* StatStrip, FactsBand, BandedList, PageHeader and TabStrip were extracted from
|
|
5
|
+
* five hand-rolled CRM screens that each declared their own `--sb-*` / `--c-*` /
|
|
6
|
+
* `--zd-*` namespace on the page root and inherited it down. The values were
|
|
7
|
+
* not identical between them — one page's hairline was `--border-color`, the
|
|
8
|
+
* next mixed 12% of the body ink — so a primitive that read the app tokens
|
|
9
|
+
* directly would have redrawn half of those screens the moment it landed.
|
|
10
|
+
*
|
|
11
|
+
* Hence two levels. Each local `--pr-*` alias resolves a PUBLIC `--vs-*`
|
|
12
|
+
* override first and falls back to the app's own token, so:
|
|
13
|
+
*
|
|
14
|
+
* - a project that defines nothing gets a plain, working component;
|
|
15
|
+
* - a page that already has a palette sets `--vs-line`, `--vs-surface` and
|
|
16
|
+
* the rest ONCE on its own root and every primitive inside it follows.
|
|
17
|
+
*
|
|
18
|
+
* The mixin is applied to each component's ROOT class rather than to a shared
|
|
19
|
+
* `:root` block: CSS-module scoping means there is no shared block to write to,
|
|
20
|
+
* and a Stat rendered outside a StatStrip must still resolve its colours.
|
|
21
|
+
*
|
|
22
|
+
* A local alias may not be declared and read on the same element by an override
|
|
23
|
+
* — that is why the override is `var(--vs-*)` inside the alias rather than the
|
|
24
|
+
* alias being redeclared: an inherited custom property loses to a declaration
|
|
25
|
+
* on the element itself.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
@mixin surface-tokens {
|
|
29
|
+
--pr-surface: var(--vs-surface, var(--background-color, #fff));
|
|
30
|
+
// The ground the page sits on, which is NOT the card surface — needed by
|
|
31
|
+
// anything that has to become opaque against the page itself, a sticky
|
|
32
|
+
// heading with no card behind it being the case that forced it.
|
|
33
|
+
--pr-page: var(--vs-page, var(--bg-color, #fff));
|
|
34
|
+
--pr-ink: var(--vs-ink, var(--paragraph-color, #2b2b2b));
|
|
35
|
+
--pr-heading: var(--vs-heading, var(--primary-color, #1b3933));
|
|
36
|
+
--pr-muted: var(--vs-muted, var(--muted-color, rgba(43 43 43 / 68%)));
|
|
37
|
+
--pr-line: var(--vs-line, var(--border-color, #e1e1e1));
|
|
38
|
+
--pr-quiet: var(
|
|
39
|
+
--vs-quiet,
|
|
40
|
+
color-mix(in srgb, var(--pr-ink) 4%, var(--pr-surface))
|
|
41
|
+
);
|
|
42
|
+
--pr-accent: var(--vs-accent, var(--highlight-color, #3cbf7d));
|
|
43
|
+
// There is no amber in the house palette — it is a green and a red — so the
|
|
44
|
+
// "worth a look, not yet wrong" step is named here once.
|
|
45
|
+
--pr-warn: var(--vs-warn, #c8811b);
|
|
46
|
+
--pr-danger: var(--vs-danger, var(--danger-color, #be3e3e));
|
|
47
|
+
--pr-radius: var(--vs-radius, var(--card-radius, 10px));
|
|
48
|
+
--pr-shadow: var(--vs-shadow, none);
|
|
49
|
+
}
|
package/src/index.js
CHANGED
|
@@ -178,6 +178,7 @@ import {
|
|
|
178
178
|
clientRecipient,
|
|
179
179
|
conversationCountLabel,
|
|
180
180
|
describeTransport,
|
|
181
|
+
displayNumber,
|
|
181
182
|
fillTemplate,
|
|
182
183
|
groupMessagesByDay,
|
|
183
184
|
initialsFor,
|
|
@@ -189,7 +190,9 @@ import {
|
|
|
189
190
|
pickInitialThread,
|
|
190
191
|
relativeTime,
|
|
191
192
|
segmentCount,
|
|
193
|
+
smsHref,
|
|
192
194
|
splitPersonName,
|
|
195
|
+
telHref,
|
|
193
196
|
threadDisplayName,
|
|
194
197
|
toE164,
|
|
195
198
|
} from './components/sms/smsHelpers';
|
|
@@ -247,6 +250,30 @@ import SectionTypeSelector from './components/proposal/SectionTypeSelector';
|
|
|
247
250
|
import VariableInserter from './components/proposal/VariableInserter';
|
|
248
251
|
import ProposalTemplatePreview from './components/proposal/ProposalTemplatePreview';
|
|
249
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Page primitives.
|
|
255
|
+
*
|
|
256
|
+
* The scaffolding a bespoke screen is built out of — the strip of figures over a
|
|
257
|
+
* list, the underline tabs, the urgency bands, the header row and the band of
|
|
258
|
+
* facts under a record's title. Every one of them was written by hand on three
|
|
259
|
+
* or more CRM screens first, and had already drifted between them; see
|
|
260
|
+
* `styles/_surface.scss` for the two-level token scheme that lets a page with an
|
|
261
|
+
* existing palette adopt them without redrawing itself.
|
|
262
|
+
*/
|
|
263
|
+
import AnchoredMenu from './components/layout/AnchoredMenu';
|
|
264
|
+
import BandedList, { Band } from './components/layout/BandedList';
|
|
265
|
+
import FactsBand, { Fact } from './components/layout/FactsBand';
|
|
266
|
+
import PageHeader from './components/layout/PageHeader';
|
|
267
|
+
import ScrollRegion from './components/layout/ScrollRegion';
|
|
268
|
+
import StatStrip, { Stat } from './components/layout/StatStrip';
|
|
269
|
+
import useContainedHeight from './components/layout/useContainedHeight';
|
|
270
|
+
import TabStrip from './components/navigation/TabStrip';
|
|
271
|
+
|
|
272
|
+
// Copying, and what to do when the browser will not. Named for the vault
|
|
273
|
+
// because that is where it was written; nothing in it is vault-specific, and
|
|
274
|
+
// every screen with a copy button was otherwise restating it.
|
|
275
|
+
import { canCopy, copyText } from './components/vault/vaultClipboard';
|
|
276
|
+
|
|
250
277
|
/** OAuth Components */
|
|
251
278
|
import OAuthManager from './components/oauth/OAuthManager';
|
|
252
279
|
import OAuthProviderCard from './components/oauth/OAuthProviderCard';
|
|
@@ -339,6 +366,26 @@ export {
|
|
|
339
366
|
useSmsLive,
|
|
340
367
|
UniversalSearch,
|
|
341
368
|
useSmsThreads,
|
|
369
|
+
// Phone numbers, for display and for dialling. Beside the SMS module's own
|
|
370
|
+
// normaliser because that is the formatter they are built on.
|
|
371
|
+
displayNumber,
|
|
372
|
+
smsHref,
|
|
373
|
+
telHref,
|
|
374
|
+
// Page primitives.
|
|
375
|
+
AnchoredMenu,
|
|
376
|
+
Band,
|
|
377
|
+
BandedList,
|
|
378
|
+
Fact,
|
|
379
|
+
FactsBand,
|
|
380
|
+
PageHeader,
|
|
381
|
+
ScrollRegion,
|
|
382
|
+
Stat,
|
|
383
|
+
StatStrip,
|
|
384
|
+
TabStrip,
|
|
385
|
+
useContainedHeight,
|
|
386
|
+
// Clipboard.
|
|
387
|
+
canCopy,
|
|
388
|
+
copyText,
|
|
342
389
|
CameraPlacement,
|
|
343
390
|
CellWithTooltip,
|
|
344
391
|
clampOtp,
|