@ultimat3/ui 20.1.6 → 20.2.1
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/CATALOG.md +100 -1
- package/CLAUDE.md +7 -3
- package/README.md +1 -0
- package/package.json +10 -6
- package/src/components/BarChart.module.scss +45 -0
- package/src/components/BarChart.tsx +78 -0
- package/src/components/CommandPalette.module.scss +110 -0
- package/src/components/CommandPalette.tsx +127 -0
- package/src/components/CopyButton.module.scss +40 -0
- package/src/components/CopyButton.tsx +62 -0
- package/src/components/Kbd.module.scss +15 -0
- package/src/components/Kbd.tsx +17 -0
- package/src/components/Meter.module.scss +18 -0
- package/src/components/Meter.tsx +58 -0
- package/src/components/QrCode.module.scss +41 -0
- package/src/components/QrCode.tsx +49 -0
- package/src/components/Sparkline.module.scss +20 -0
- package/src/components/Sparkline.tsx +40 -0
- package/src/components/StatTile.module.scss +86 -0
- package/src/components/StatTile.tsx +49 -0
- package/src/components/bar-chart-view.ts +55 -0
- package/src/components/command-palette-view.ts +61 -0
- package/src/components/meter-view.ts +13 -0
- package/src/components/qr-encode.ts +187 -0
- package/src/components/qr-matrix.ts +329 -0
- package/src/components/sparkline-view.ts +36 -0
- package/src/components/stat-delta.ts +30 -0
- package/src/error-registry.ts +23 -0
- package/src/errors.ts +21 -13
- package/src/i18n-keys.ts +4 -0
- package/src/index.ts +39 -1
- package/src/theme/ambient-slot.ts +20 -0
- package/src/theme/ambient.browser.ts +11 -0
- package/src/theme/ambient.ts +37 -0
- package/src/theme/context.ts +33 -38
- package/src/theme/inline-script.ts +5 -0
- package/src/theme/provider.tsx +5 -2
- package/src/tokens/_mixins.scss +30 -0
- package/src/tokens/reset.scss +7 -0
package/src/index.ts
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
// would be TS2307 there. The reference pulls the contract along with the entry.
|
|
7
7
|
/// <reference path="./scss.d.ts" />
|
|
8
8
|
|
|
9
|
+
// Bare, and above every re-export: `theme/ambient.ts` registers the server's `useUi()` reader at
|
|
10
|
+
// import, and a bundler may drop a re-exported module whose binding nobody used. A browser build
|
|
11
|
+
// resolves this specifier to `theme/ambient.browser.ts` through `package.json`'s `browser` field,
|
|
12
|
+
// so an island never carries the i18n barrel for it (issue #490).
|
|
13
|
+
import './theme/ambient';
|
|
14
|
+
|
|
9
15
|
export type {
|
|
10
16
|
FocusTrap,
|
|
11
17
|
LiveRegionAttrs,
|
|
@@ -57,20 +63,35 @@ export {
|
|
|
57
63
|
} from './components/async-branch';
|
|
58
64
|
export type { BadgeProps } from './components/Badge';
|
|
59
65
|
export { Badge } from './components/Badge';
|
|
66
|
+
export type { BarChartProps } from './components/BarChart';
|
|
67
|
+
export { BarChart } from './components/BarChart';
|
|
60
68
|
export type { BreadcrumbItem, BreadcrumbProps } from './components/Breadcrumb';
|
|
61
69
|
export { Breadcrumb } from './components/Breadcrumb';
|
|
62
70
|
export type { ButtonProps } from './components/Button';
|
|
63
71
|
export { Button } from './components/Button';
|
|
72
|
+
export type { BarRect, ChartPoint } from './components/bar-chart-view';
|
|
73
|
+
export { BAR_CHART, barRects, GRID_STEPS, gridY, maxOf } from './components/bar-chart-view';
|
|
64
74
|
export type { CardProps, Elevation } from './components/Card';
|
|
65
75
|
export { Card } from './components/Card';
|
|
66
76
|
export type { CheckboxProps } from './components/Checkbox';
|
|
67
77
|
export { Checkbox } from './components/Checkbox';
|
|
68
78
|
export type { ComboboxProps } from './components/Combobox';
|
|
69
79
|
export { Combobox } from './components/Combobox';
|
|
80
|
+
export type { CommandPaletteLabels, CommandPaletteProps } from './components/CommandPalette';
|
|
81
|
+
export { CommandPalette } from './components/CommandPalette';
|
|
70
82
|
export type { ContainerProps, ContainerSize } from './components/Container';
|
|
71
83
|
export { Container } from './components/Container';
|
|
84
|
+
export type { CopyButtonProps } from './components/CopyButton';
|
|
85
|
+
export { COPIED_MS, CopyButton } from './components/CopyButton';
|
|
72
86
|
export type { ComboboxOption } from './components/combobox-filter';
|
|
73
87
|
export { COMBOBOX_LIMIT, filterOptions, normalizeQuery } from './components/combobox-filter';
|
|
88
|
+
export type { CommandPaletteItem, PaletteKeyAction } from './components/command-palette-view';
|
|
89
|
+
export {
|
|
90
|
+
filterItems,
|
|
91
|
+
keyAction,
|
|
92
|
+
settleActive,
|
|
93
|
+
stepActive,
|
|
94
|
+
} from './components/command-palette-view';
|
|
74
95
|
export type { Column, DataTableProps } from './components/DataTable';
|
|
75
96
|
export { DataTable } from './components/DataTable';
|
|
76
97
|
export type { DateTimeProps } from './components/DateTime';
|
|
@@ -137,6 +158,8 @@ export type { ImageBox, ImageLoadingHints, ImageVariant } from './components/ima
|
|
|
137
158
|
export { boxFor, loadingHints, ratioFor, srcsetFor } from './components/image-source';
|
|
138
159
|
export type { LoadMoreInput, LoadMoreState } from './components/infinite-scroll-view';
|
|
139
160
|
export { loadMoreState } from './components/infinite-scroll-view';
|
|
161
|
+
export type { KbdProps } from './components/Kbd';
|
|
162
|
+
export { Kbd } from './components/Kbd';
|
|
140
163
|
export type { LinkProps } from './components/Link';
|
|
141
164
|
export { Link } from './components/Link';
|
|
142
165
|
export type { LocaleSwitcherProps } from './components/LocaleSwitcher';
|
|
@@ -145,8 +168,11 @@ export type { LinkTarget } from './components/link-target';
|
|
|
145
168
|
export { linkTarget } from './components/link-target';
|
|
146
169
|
export type { MenuItem, MenuProps } from './components/Menu';
|
|
147
170
|
export { Menu } from './components/Menu';
|
|
171
|
+
export type { MeterProps } from './components/Meter';
|
|
172
|
+
export { Meter } from './components/Meter';
|
|
148
173
|
export type { MoneyProps } from './components/Money';
|
|
149
174
|
export { Money } from './components/Money';
|
|
175
|
+
export { meterShare, meterWidth } from './components/meter-view';
|
|
150
176
|
export type { MoneyFormatter, MoneyInput, MoneyViewOptions } from './components/money-view';
|
|
151
177
|
// --- formatting cores (pure, renderer-free) ----------------------------------
|
|
152
178
|
export { moneyText, toMoney } from './components/money-view';
|
|
@@ -156,6 +182,10 @@ export type { PaginationProps } from './components/Pagination';
|
|
|
156
182
|
export { Pagination } from './components/Pagination';
|
|
157
183
|
export type { Placement, PopoverProps } from './components/Popover';
|
|
158
184
|
export { Popover } from './components/Popover';
|
|
185
|
+
export type { QrCodeProps } from './components/QrCode';
|
|
186
|
+
export { QrCode } from './components/QrCode';
|
|
187
|
+
export type { QrMatrix } from './components/qr-matrix';
|
|
188
|
+
export { encodeQr } from './components/qr-matrix';
|
|
159
189
|
export type { RadioOption, RadioProps } from './components/Radio';
|
|
160
190
|
export { Radio } from './components/Radio';
|
|
161
191
|
export type { RelativeTimeProps } from './components/RelativeTime';
|
|
@@ -168,14 +198,22 @@ export type { SelectOption, SelectProps } from './components/Select';
|
|
|
168
198
|
export { Select } from './components/Select';
|
|
169
199
|
export type { SkeletonProps } from './components/Skeleton';
|
|
170
200
|
export { Skeleton } from './components/Skeleton';
|
|
201
|
+
export type { SparklineProps } from './components/Sparkline';
|
|
202
|
+
export { Sparkline } from './components/Sparkline';
|
|
171
203
|
export type { SpinnerProps } from './components/Spinner';
|
|
172
204
|
export { Spinner } from './components/Spinner';
|
|
173
205
|
export type { StackProps } from './components/Stack';
|
|
174
206
|
export { Stack } from './components/Stack';
|
|
207
|
+
export type { StatTileProps } from './components/StatTile';
|
|
208
|
+
export { StatTile } from './components/StatTile';
|
|
175
209
|
export type { SwitchProps } from './components/Switch';
|
|
176
210
|
export { Switch } from './components/Switch';
|
|
177
211
|
export type { SortDirection, SortState } from './components/sort-state';
|
|
178
212
|
export { ariaSortFor, nextSortState } from './components/sort-state';
|
|
213
|
+
export type { SparkPoint } from './components/sparkline-view';
|
|
214
|
+
export { SPARKLINE, sparklinePath, sparkPoints } from './components/sparkline-view';
|
|
215
|
+
export type { StatDelta, StatTrend } from './components/stat-delta';
|
|
216
|
+
export { DELTA_ARROW_PATH, deltaOf } from './components/stat-delta';
|
|
179
217
|
export type { TableProps } from './components/Table';
|
|
180
218
|
export { Table } from './components/Table';
|
|
181
219
|
export type { TabItem, TabsProps } from './components/Tabs';
|
|
@@ -258,11 +296,11 @@ export {
|
|
|
258
296
|
TAB_SELECTOR,
|
|
259
297
|
tabStopIndex,
|
|
260
298
|
} from './roving';
|
|
299
|
+
export { ambientUiContext } from './theme/ambient';
|
|
261
300
|
export type { Brand, BrandInput, FontSlot } from './theme/brand';
|
|
262
301
|
export { brandStyleCspSource, brandStyleTag, defineTheme, FONT_SLOTS } from './theme/brand';
|
|
263
302
|
export type { Direction, UiContextValue } from './theme/context';
|
|
264
303
|
export {
|
|
265
|
-
ambientUiContext,
|
|
266
304
|
defaultUiContext,
|
|
267
305
|
fallbackTranslator,
|
|
268
306
|
UI_DEFAULT_CURRENCY,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// The module-scope slot holding the reader `useUi()` falls back to when no Solid runtime is
|
|
2
|
+
// registered — a server render. Its own module for the same reason `runtime-slot.ts` is: the
|
|
3
|
+
// server's reader (`ambient.ts`) reaches `@ultimat3/i18n` and `@ultimat3/time`, and a slot that
|
|
4
|
+
// sat beside it would put the framework catalog in every browser chunk that calls `useUi()`.
|
|
5
|
+
// The slot itself imports nothing.
|
|
6
|
+
|
|
7
|
+
import type { UiContextValue } from './context';
|
|
8
|
+
|
|
9
|
+
export type AmbientUiReader = () => UiContextValue;
|
|
10
|
+
|
|
11
|
+
let reader: AmbientUiReader | null = null;
|
|
12
|
+
|
|
13
|
+
/** Called once, at import, by `ambient.ts`; a browser build never reaches that module. */
|
|
14
|
+
export function setAmbientUiReader(next: AmbientUiReader): void {
|
|
15
|
+
reader = next;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function registeredAmbientUiReader(): AmbientUiReader | null {
|
|
19
|
+
return reader;
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// What a browser bundler gets in place of `ambient.ts` — `package.json`'s `browser` field maps
|
|
2
|
+
// one file to the other. A browser has no request context: `useUi()` in a DOM reads the Solid
|
|
3
|
+
// context a `UiProvider` filled, and throws (`solid()`, X_UI_RUNTIME_MISSING) before it could ever
|
|
4
|
+
// fall back to an ambient reader. So nothing is registered here, and the same export answers the
|
|
5
|
+
// package defaults — which is exactly what the server's reader answers outside a request.
|
|
6
|
+
|
|
7
|
+
import { defaultUiContext, type UiContextValue } from './context';
|
|
8
|
+
|
|
9
|
+
export function ambientUiContext(): UiContextValue {
|
|
10
|
+
return defaultUiContext();
|
|
11
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// The presentation context of a SERVER render, read from the request the framework already
|
|
2
|
+
// resolved — and the one module of the theme directory that reaches `@ultimat3/i18n` and
|
|
3
|
+
// `@ultimat3/time` for a value. `index.ts` imports it bare, so every server that imports the
|
|
4
|
+
// barrel has the reader registered before the first `useUi()`; `package.json`'s `browser` field
|
|
5
|
+
// maps this file to `ambient.browser.ts` for a browser bundler, which is what keeps the i18n
|
|
6
|
+
// barrel — and the framework catalog it installs at import — out of an island chunk (issue #490).
|
|
7
|
+
|
|
8
|
+
import { currentDirection, currentLocale, useI18n } from '@ultimat3/i18n';
|
|
9
|
+
import { currentTimeZone } from '@ultimat3/time';
|
|
10
|
+
import { setAmbientUiReader } from './ambient-slot';
|
|
11
|
+
import { UI_DEFAULT_CURRENCY, type UiContextValue } from './context';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `currentLocale()` and `currentTimeZone()` are the ambient answers `@ultimat3/i18n` and
|
|
15
|
+
* `@ultimat3/time` keep on the request context, and `useI18n()` is the translator built from the
|
|
16
|
+
* registered catalogs. No second ambient store, and no process-wide default — outside a request
|
|
17
|
+
* each of them returns its own configured fallback, which is where `defaultUiContext()`'s values
|
|
18
|
+
* come from in the first place.
|
|
19
|
+
*
|
|
20
|
+
* `theme` and `currency` have no ambient source and are not given one. The server cannot know the
|
|
21
|
+
* theme — `data-theme` is decided in the browser by the anti-flash script — and a default display
|
|
22
|
+
* currency is business convention: a `Money` carries its own, and an app that wants another for
|
|
23
|
+
* bare minor units wraps `<Money currency="EUR">` once (axiom 8).
|
|
24
|
+
*/
|
|
25
|
+
export function ambientUiContext(): UiContextValue {
|
|
26
|
+
return {
|
|
27
|
+
theme: 'light',
|
|
28
|
+
locale: currentLocale(),
|
|
29
|
+
timeZone: currentTimeZone(),
|
|
30
|
+
currency: UI_DEFAULT_CURRENCY,
|
|
31
|
+
dir: currentDirection(),
|
|
32
|
+
t: useI18n(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// At module scope, and that is the point: registration an importer can forget is not registration.
|
|
37
|
+
setAmbientUiReader(ambientUiContext);
|
package/src/theme/context.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
// The ambient presentation contract every component reads: theme, locale, tz, currency, direction,
|
|
2
2
|
// translator. Formatting components take nothing from a process-wide default — it arrives from
|
|
3
3
|
// `UiProvider` where a Solid runtime is registered, and from the request everywhere else.
|
|
4
|
+
//
|
|
5
|
+
// This module is what every component's `useUi()` retains, so it imports NO value from
|
|
6
|
+
// `@ultimat3/i18n` or `@ultimat3/time`: the i18n barrel installs the framework catalog at import,
|
|
7
|
+
// and the request readers live in `ambient.ts`, reached through `ambient-slot.ts` (issue #490).
|
|
4
8
|
|
|
5
|
-
import type {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
currentLocale,
|
|
10
|
-
type Direction,
|
|
11
|
-
directionOf,
|
|
12
|
-
type Locale,
|
|
13
|
-
useI18n,
|
|
14
|
-
} from '@ultimat3/i18n';
|
|
15
|
-
import { currentTimeZone, type TimeZone } from '@ultimat3/time';
|
|
9
|
+
import type { Direction } from '@ultimat3/core';
|
|
10
|
+
import { directionOf } from '@ultimat3/core';
|
|
11
|
+
import type { Locale, Translator } from '@ultimat3/i18n';
|
|
12
|
+
import type { TimeZone } from '@ultimat3/time';
|
|
16
13
|
import type { Theme } from '../tokens/tokens';
|
|
14
|
+
import { registeredAmbientUiReader } from './ambient-slot';
|
|
17
15
|
import { hasSolidRuntime } from './runtime-slot';
|
|
18
16
|
import { type SolidContext, type SolidRuntime, solid } from './solid-adapter';
|
|
19
17
|
|
|
@@ -35,9 +33,23 @@ export const UI_DEFAULT_LOCALE: Locale = 'en';
|
|
|
35
33
|
export const UI_DEFAULT_TIME_ZONE = 'UTC' as TimeZone;
|
|
36
34
|
export const UI_DEFAULT_CURRENCY = 'USD';
|
|
37
35
|
|
|
38
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Loud-miss translator: a forgotten catalog key renders ⟦key⟧, never blank.
|
|
38
|
+
*
|
|
39
|
+
* Written here rather than as `createTranslator({}, locale)`, and behaviourally the same call: an
|
|
40
|
+
* empty catalog has no key, so every lookup is a miss, `has` is false, `raw` is undefined and
|
|
41
|
+
* `keys` is empty — `context.test.ts` holds each of those against `@ultimat3/i18n`'s own. What
|
|
42
|
+
* the spelling buys is that a browser chunk with a `UiProvider` in it no longer reaches the i18n
|
|
43
|
+
* barrel for a translator that cannot translate.
|
|
44
|
+
*/
|
|
39
45
|
export function fallbackTranslator(locale: Locale = UI_DEFAULT_LOCALE): Translator {
|
|
40
|
-
|
|
46
|
+
const miss = (key: string): string => `⟦${key}⟧`;
|
|
47
|
+
return Object.assign(miss, {
|
|
48
|
+
has: (): boolean => false,
|
|
49
|
+
raw: (): string | undefined => undefined,
|
|
50
|
+
keys: (): string[] => [],
|
|
51
|
+
locale,
|
|
52
|
+
});
|
|
41
53
|
}
|
|
42
54
|
|
|
43
55
|
export function defaultUiContext(): UiContextValue {
|
|
@@ -51,30 +63,6 @@ export function defaultUiContext(): UiContextValue {
|
|
|
51
63
|
};
|
|
52
64
|
}
|
|
53
65
|
|
|
54
|
-
/**
|
|
55
|
-
* The presentation context of a server render, read from the request the framework already
|
|
56
|
-
* resolved: `currentLocale()` and `currentTimeZone()` are the ambient answers `@ultimat3/i18n` and
|
|
57
|
-
* `@ultimat3/time` keep on the request context, and `useI18n()` is the translator built from the
|
|
58
|
-
* registered catalogs. No second ambient store, and no process-wide default — outside a request
|
|
59
|
-
* each of them returns its own configured fallback, which is where `defaultUiContext()`'s values
|
|
60
|
-
* come from in the first place.
|
|
61
|
-
*
|
|
62
|
-
* `theme` and `currency` have no ambient source and are not given one. The server cannot know the
|
|
63
|
-
* theme — `data-theme` is decided in the browser by the anti-flash script — and a default display
|
|
64
|
-
* currency is business convention: a `Money` carries its own, and an app that wants another for
|
|
65
|
-
* bare minor units wraps `<Money currency="EUR">` once (axiom 8).
|
|
66
|
-
*/
|
|
67
|
-
export function ambientUiContext(): UiContextValue {
|
|
68
|
-
return {
|
|
69
|
-
theme: 'light',
|
|
70
|
-
locale: currentLocale(),
|
|
71
|
-
timeZone: currentTimeZone(),
|
|
72
|
-
currency: UI_DEFAULT_CURRENCY,
|
|
73
|
-
dir: currentDirection(),
|
|
74
|
-
t: useI18n(),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
66
|
let cached: {
|
|
79
67
|
readonly runtime: SolidRuntime;
|
|
80
68
|
readonly context: SolidContext<UiContextValue>;
|
|
@@ -99,8 +87,15 @@ export function uiContext(): SolidContext<UiContextValue> {
|
|
|
99
87
|
* Solid context is provably empty — an inert tree is walked outside every owner, so `useContext`
|
|
100
88
|
* returns the context's default value even with a real runtime registered — so reading the
|
|
101
89
|
* request's own answers is strictly more true than reading a provider that provided nothing.
|
|
90
|
+
*
|
|
91
|
+
* Those answers come through the slot: `ambient.ts` registers `ambientUiContext` when the barrel
|
|
92
|
+
* is imported, and a browser build — where this branch is unreachable — never has it. The
|
|
93
|
+
* defaults are the fallback for a caller that reached this module without the barrel, which is
|
|
94
|
+
* what `ambientUiContext()` itself answers outside a request.
|
|
102
95
|
*/
|
|
103
96
|
export function useUi(): UiContextValue {
|
|
104
97
|
const runtime = solid();
|
|
105
|
-
|
|
98
|
+
if (hasSolidRuntime()) return runtime.useContext(uiContext());
|
|
99
|
+
const ambient = registeredAmbientUiReader();
|
|
100
|
+
return ambient === null ? defaultUiContext() : ambient();
|
|
106
101
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// The blocking <head> snippet that kills the flash of wrong theme. Built from the
|
|
2
2
|
// same constants as theme.ts so the two can never disagree. Server/build-only:
|
|
3
3
|
// the hash is computed with Bun's hasher for the CSP header.
|
|
4
|
+
//
|
|
5
|
+
// DEPRECATED `As of 20.2.0`: the framework's boot inlines this script itself, from
|
|
6
|
+
// `@ultimat3/render`'s `themeScript({ fallback })` with `theme.defaultMode` in `app.config.ts` as
|
|
7
|
+
// the fallback, and admits it to the CSP — an app no longer writes either half. This module stays
|
|
8
|
+
// exported for one major so an app that inlined it by hand keeps building; it is removed in 21.
|
|
4
9
|
|
|
5
10
|
import { runtimeMissingError } from '../errors';
|
|
6
11
|
import { THEME_ATTRIBUTE, THEME_MEDIA_QUERY, THEME_STORAGE_KEY } from './theme';
|
package/src/theme/provider.tsx
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// UiProvider — the single place an app injects presentation context. Reactive
|
|
2
|
-
// access goes through the Solid adapter, so this file imports only solid types
|
|
2
|
+
// access goes through the Solid adapter, so this file imports only solid types — and only TYPES
|
|
3
|
+
// from `@ultimat3/i18n`: `directionOf` is core's, because a value import of the i18n barrel is
|
|
4
|
+
// the framework catalog in every island chunk with a provider (issue #490).
|
|
3
5
|
|
|
4
|
-
import { directionOf
|
|
6
|
+
import { directionOf } from '@ultimat3/core';
|
|
7
|
+
import type { Locale, Translator } from '@ultimat3/i18n';
|
|
5
8
|
import type { TimeZone } from '@ultimat3/time';
|
|
6
9
|
import type { JSX } from 'solid-js';
|
|
7
10
|
import { providerNeedsRuntimeError } from '../errors';
|
package/src/tokens/_mixins.scss
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
@use 'colors';
|
|
9
9
|
@use 'motion';
|
|
10
10
|
@use 'radius';
|
|
11
|
+
@use 'space';
|
|
12
|
+
@use 'typography';
|
|
11
13
|
|
|
12
14
|
/// Keyboard-only focus, drawn from the accent role so it themes automatically.
|
|
13
15
|
@mixin focus-ring($role: 'accent', $width: 2px, $offset: 2px) {
|
|
@@ -191,6 +193,34 @@
|
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
/// The mono family with tabular figures, for slugs, counts, timestamps, ids and URLs — data
|
|
197
|
+
/// whose columns must not wobble as the value changes. Lifted from an app that had restated
|
|
198
|
+
/// these two lines in six stylesheets before the catalog carried them.
|
|
199
|
+
@mixin data-text {
|
|
200
|
+
font-family: var(--font-mono);
|
|
201
|
+
font-variant-numeric: tabular-nums;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/// The section-label voice: smallest text step, medium weight, wide tracking, uppercase. An
|
|
205
|
+
/// eyebrow over a hero, a stat tile's label, a table's column head.
|
|
206
|
+
@mixin label-caps {
|
|
207
|
+
font-size: typography.text('xs');
|
|
208
|
+
font-weight: typography.weight('medium');
|
|
209
|
+
letter-spacing: typography.tracking('wide');
|
|
210
|
+
text-transform: uppercase;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// A dot grid faded toward the top-left, where the text sits, over the soft background — the
|
|
214
|
+
/// "quietly technical" ground a hero or a dashboard main sits on. Two layers: the fade (so the
|
|
215
|
+
/// dots never compete with the copy) and the grid itself, pitched on one spacing step. Every
|
|
216
|
+
/// colour is a role, so it themes with the page.
|
|
217
|
+
@mixin dot-grid($pitch: space.space(5), $alpha: 0.55) {
|
|
218
|
+
background:
|
|
219
|
+
radial-gradient(ellipse 70% 90% at 0% 0%, colors.role('bg') 35%, transparent 100%),
|
|
220
|
+
radial-gradient(colors.role('line', $alpha) 1px, transparent 1px) 0 0 / $pitch $pitch,
|
|
221
|
+
colors.role('bg-soft');
|
|
222
|
+
}
|
|
223
|
+
|
|
194
224
|
/// Inline run of items on one baseline — a toolbar, a header, an icon beside a label.
|
|
195
225
|
@mixin row($gap: var(--space-3), $align: center, $justify: flex-start) {
|
|
196
226
|
display: flex;
|
package/src/tokens/reset.scss
CHANGED
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
padding: 0;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
// The `*` above outranks the UA stylesheet's `dialog { margin: auto }`, which is the ONLY thing
|
|
19
|
+
// that centres a modal `<dialog>` in its viewport — so every `Dialog` and every app dialog opened
|
|
20
|
+
// pinned to the top-left corner until the app restated the margin itself. Restated once, here.
|
|
21
|
+
dialog {
|
|
22
|
+
margin: auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
html {
|
|
19
26
|
-webkit-text-size-adjust: 100%;
|
|
20
27
|
text-size-adjust: 100%;
|