@galaxy-io/dls 2.8.1 → 2.10.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/README.md +2 -2
- package/dist/beacons/Beacon.d.ts +1 -1
- package/dist/beacons/Beacon.js +12 -28
- package/dist/brand/GalaxyAlchemyWordmark.d.ts +4 -1
- package/dist/brand/GalaxyAlchemyWordmark.js +7 -1
- package/dist/brand/GalaxyFilamentWordmark.d.ts +5 -2
- package/dist/brand/GalaxyFilamentWordmark.js +9 -2
- package/dist/brand/GalaxyLogomark.js +3 -0
- package/dist/brand/PoweredBy.d.ts +27 -0
- package/dist/brand/PoweredBy.js +96 -0
- package/dist/brand/internal/svg/GalaxyAlchemyWordmarkSvg.d.ts +1 -1
- package/dist/brand/internal/svg/GalaxyAlchemyWordmarkSvg.js +34 -8
- package/dist/brand/internal/svg/GalaxyFilamentWordmarkSvg.d.ts +1 -1
- package/dist/brand/internal/svg/GalaxyFilamentWordmarkSvg.js +2 -2
- package/dist/charts/Heatmap.js +25 -9
- package/dist/charts/Sparkline.d.ts +1 -1
- package/dist/charts/Sparkline.js +10 -26
- package/dist/charts/chartFormat.d.ts +1 -1
- package/dist/charts/chartFormat.js +2 -2
- package/dist/charts/heatmapGeometry.d.ts +14 -0
- package/dist/charts/heatmapGeometry.js +17 -1
- package/dist/chips/Chip.d.ts +2 -2
- package/dist/chips/Chip.js +15 -31
- package/dist/drawer/Drawer.d.ts +2 -2
- package/dist/drawer/Drawer.js +1 -1
- package/dist/editor/CodeEditor.d.ts +1 -1
- package/dist/editor/CodeEditor.js +2 -1
- package/dist/feedback/Alert.d.ts +36 -9
- package/dist/feedback/Alert.js +26 -8
- package/dist/feedback/ProgressBar.d.ts +4 -1
- package/dist/feedback/ProgressBar.js +17 -30
- package/dist/feedback/ProgressCircle.d.ts +1 -1
- package/dist/feedback/ProgressCircle.js +14 -30
- package/dist/hooks/useEndReached.d.ts +40 -0
- package/dist/hooks/useEndReached.js +69 -0
- package/dist/icons/Icon.d.ts +36 -8
- package/dist/icons/Icon.js +14 -7
- package/dist/inputs/CronInput.js +114 -78
- package/dist/inputs/DateInput.d.ts +1 -1
- package/dist/inputs/DateInput.js +10 -10
- package/dist/inputs/MultiSelectInput.d.ts +3 -1
- package/dist/inputs/MultiSelectInput.js +8 -3
- package/dist/inputs/SelectInput.d.ts +8 -1
- package/dist/inputs/SelectInput.js +52 -25
- package/dist/inputs/internal/selectAll.d.ts +11 -0
- package/dist/inputs/internal/selectAll.js +28 -0
- package/dist/json/JsonViewer.js +7 -6
- package/dist/layout/AppFrame.d.ts +20 -0
- package/dist/layout/AppFrame.js +71 -0
- package/dist/layout/EmptyLayout.d.ts +53 -0
- package/dist/layout/EmptyLayout.js +59 -0
- package/dist/layout/ErrorLayout.d.ts +42 -0
- package/dist/layout/ErrorLayout.js +60 -0
- package/dist/layout/PageLayout.d.ts +26 -0
- package/dist/layout/PageLayout.js +116 -0
- package/dist/layout/PendingLayout.d.ts +30 -0
- package/dist/layout/PendingLayout.js +57 -0
- package/dist/layout/internal/errorState.d.ts +14 -0
- package/dist/layout/internal/errorState.js +49 -0
- package/dist/layout/internal/region.d.ts +10 -0
- package/dist/layout/internal/region.js +24 -0
- package/dist/lists/DescriptionList.js +1 -0
- package/dist/menu/Menu.d.ts +2 -2
- package/dist/menu/Menu.js +6 -13
- package/dist/modal/Modal.d.ts +2 -2
- package/dist/modal/Modal.js +1 -1
- package/dist/navigation/CommandPalette.js +4 -11
- package/dist/navigation/SidebarNav.d.ts +5 -0
- package/dist/navigation/SidebarNav.js +41 -22
- package/dist/navigation/Topbar.js +4 -0
- package/dist/shapes/Circle.d.ts +1 -1
- package/dist/shapes/Circle.js +10 -26
- package/dist/shapes/Square.d.ts +1 -1
- package/dist/shapes/Square.js +10 -26
- package/dist/styles/internal/roleColor.d.ts +3 -0
- package/dist/styles/internal/roleColor.js +42 -0
- package/dist/styles/mixins.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/table/InfiniteSpreadsheet.js +6 -6
- package/dist/table/InfiniteTable.d.ts +57 -18
- package/dist/table/InfiniteTable.js +5 -3
- package/dist/table/TableCore.d.ts +11 -2
- package/dist/table/TableCore.js +108 -87
- package/dist/table/VirtualizedInfiniteTable.d.ts +58 -19
- package/dist/table/VirtualizedInfiniteTable.js +9 -6
- package/dist/table/useInfiniteScrollSentinel.d.ts +13 -13
- package/dist/table/useInfiniteScrollSentinel.js +7 -51
- package/dist/table/useTableColumnLayout.d.ts +8 -2
- package/dist/table/useTableColumnLayout.js +36 -13
- package/dist/theme/tokens/dark.js +1 -1
- package/dist/theme/tokens/light.js +4 -3
- package/dist/theme/tokens/types.d.ts +7 -7
- package/dist/timeline/Timeline.d.ts +1 -1
- package/dist/timeline/Timeline.js +6 -24
- package/dist/tokens.css +1 -1
- package/dist/utils/format.d.ts +35 -10
- package/dist/utils/format.js +60 -12
- package/dist/utils/search.d.ts +15 -0
- package/dist/utils/search.js +24 -0
- package/dist/vite/index.d.ts +16 -2
- package/dist/vite/index.js +28 -19
- package/dist/vite/internal/themeBoot.d.ts +25 -0
- package/dist/vite/internal/themeBoot.js +44 -0
- package/dist/vite/internal/wywOptions.d.ts +46 -0
- package/dist/vite/internal/wywOptions.js +44 -0
- package/package.json +34 -1
package/dist/utils/format.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
//#region src/utils/format.ts
|
|
2
2
|
/**
|
|
3
|
-
* Display formatting for numbers, byte sizes, durations, relative times and percentages
|
|
4
|
-
* (
|
|
5
|
-
* under SSR. Number parts default to the `en-US` locale (not the runtime's) so
|
|
6
|
-
* render the same string.
|
|
3
|
+
* Display formatting for numbers, byte sizes, durations, relative times, dates and percentages
|
|
4
|
+
* (`docs/components.md`, Hooks and utils). Pure functions on `Intl`, no dependencies, safe at
|
|
5
|
+
* module scope and under SSR. Number parts default to the `en-US` locale (not the runtime's) so
|
|
6
|
+
* server and client render the same string.
|
|
7
7
|
*
|
|
8
8
|
* `precision` is always the maximum number of fraction digits; trailing zeros are dropped
|
|
9
9
|
* (`formatPercent(0.5)` → `"50%"`, not `"50.0%"`). Non-finite input (`NaN`, `±Infinity`) is
|
|
10
10
|
* returned as `formatNumber` prints it (`"NaN"`, `"∞"`, `"-∞"`).
|
|
11
|
+
*
|
|
12
|
+
* Every formatter also takes a `bigint` (a database count, a unix-millisecond timestamp), so call
|
|
13
|
+
* sites never wrap one in `Number()`. `formatNumber` prints a bigint exactly (`Intl` formats it
|
|
14
|
+
* natively); compact numbers, byte sizes, durations and relative times scale and round anyway, so
|
|
15
|
+
* they convert it to a number first (exact up to 2^53).
|
|
11
16
|
*/
|
|
12
17
|
var DEFAULT_LOCALE = "en-US";
|
|
18
|
+
/**
|
|
19
|
+
* What a missing value prints as: an em dash, in a table cell, a description list or a chart
|
|
20
|
+
* tooltip. One constant so every "no value" in an app reads the same. Render it in
|
|
21
|
+
* `TextVariant.TERTIARY`.
|
|
22
|
+
*/
|
|
23
|
+
var EMPTY_VALUE = "—";
|
|
13
24
|
var COMPACT_SUFFIXES = [
|
|
14
25
|
"",
|
|
15
26
|
"k",
|
|
@@ -111,6 +122,8 @@ var RELATIVE_UNITS = [
|
|
|
111
122
|
intl: "second"
|
|
112
123
|
}
|
|
113
124
|
];
|
|
125
|
+
/** A bigint as a number, for the formatters that scale or round (exact up to 2^53). */
|
|
126
|
+
var toNumber = (value) => typeof value === "bigint" ? Number(value) : value;
|
|
114
127
|
var decimal = (value, maxFractionDigits, locale = DEFAULT_LOCALE) => new Intl.NumberFormat(locale, {
|
|
115
128
|
signDisplay: "negative",
|
|
116
129
|
...maxFractionDigits === void 0 ? {} : { maximumFractionDigits: maxFractionDigits }
|
|
@@ -136,11 +149,13 @@ function scale(abs, base, steps, precisionAt) {
|
|
|
136
149
|
/**
|
|
137
150
|
* Formats a number with grouping. `1234` → `"1,234"`; `{ compact: true }` → `"1.2k"`
|
|
138
151
|
* (suffixes `k M B T`). `precision` is the maximum fraction digits (default `1` when compact,
|
|
139
|
-
* otherwise the `Intl` default of `3`). `locale` defaults to `"en-US"`.
|
|
152
|
+
* otherwise the `Intl` default of `3`). `locale` defaults to `"en-US"`. A `bigint` prints exactly
|
|
153
|
+
* (`12345678901234567890n` → `"12,345,678,901,234,567,890"`).
|
|
140
154
|
*/
|
|
141
|
-
function formatNumber(
|
|
155
|
+
function formatNumber(input, opts) {
|
|
142
156
|
const locale = opts?.locale ?? DEFAULT_LOCALE;
|
|
143
|
-
if (!opts?.compact || !Number.isFinite(
|
|
157
|
+
if (!opts?.compact || typeof input === "number" && !Number.isFinite(input)) return decimal(input, opts?.precision, locale);
|
|
158
|
+
const n = toNumber(input);
|
|
144
159
|
const precision = opts.precision ?? 1;
|
|
145
160
|
const [value, step] = scale(Math.abs(n), 1e3, COMPACT_SUFFIXES.length, () => precision);
|
|
146
161
|
return `${n < 0 && decimal(value, precision, locale) !== "0" ? "-" : ""}${decimal(value, precision, locale)}${COMPACT_SUFFIXES[step] ?? ""}`;
|
|
@@ -150,7 +165,8 @@ function formatNumber(n, opts) {
|
|
|
150
165
|
* `{ binary: true }` uses IEC units (`KiB`, base 1024). Whole bytes have no fraction digits.
|
|
151
166
|
* `precision` is the maximum fraction digits (default `1`).
|
|
152
167
|
*/
|
|
153
|
-
function formatBytes(
|
|
168
|
+
function formatBytes(input, opts) {
|
|
169
|
+
const bytes = toNumber(input);
|
|
154
170
|
if (!Number.isFinite(bytes)) return formatNumber(bytes);
|
|
155
171
|
const precision = opts?.precision ?? 1;
|
|
156
172
|
const units = opts?.binary ? BINARY_BYTE_UNITS : DECIMAL_BYTE_UNITS;
|
|
@@ -166,7 +182,8 @@ function formatBytes(bytes, opts) {
|
|
|
166
182
|
* finite); zero units are omitted and the
|
|
167
183
|
* remainder is truncated. Zero is `"0s"` / `"0 seconds"`. `style` defaults to `"compact"`.
|
|
168
184
|
*/
|
|
169
|
-
function formatDuration(
|
|
185
|
+
function formatDuration(input, opts) {
|
|
186
|
+
const ms = toNumber(input);
|
|
170
187
|
if (!Number.isFinite(ms)) return formatNumber(ms);
|
|
171
188
|
const isLong = opts?.style === "long";
|
|
172
189
|
const requestedUnits = opts?.maxUnits ?? 2;
|
|
@@ -186,7 +203,8 @@ function formatDuration(ms, opts) {
|
|
|
186
203
|
return `${ms < 0 ? "-" : ""}${parts.join(" ")}`;
|
|
187
204
|
}
|
|
188
205
|
/**
|
|
189
|
-
* Formats a date
|
|
206
|
+
* Formats a date (or a unix-millisecond timestamp, `number` or `bigint`) relative to `now`
|
|
207
|
+
* (default: the current time, read at call time).
|
|
190
208
|
* `{ style: "short" }` (default) → `"3m ago"`, `"in 2d"`, `"now"` (units `s m h d w mo y`);
|
|
191
209
|
* `{ style: "long" }` → `Intl.RelativeTimeFormat` with `numeric: "auto"` (`"3 minutes ago"`,
|
|
192
210
|
* `"in 2 days"`, `"yesterday"`, `"now"`). Uses the largest unit that fits, truncated;
|
|
@@ -194,7 +212,7 @@ function formatDuration(ms, opts) {
|
|
|
194
212
|
*/
|
|
195
213
|
function formatRelativeTime(date, opts) {
|
|
196
214
|
const now = opts?.now ?? /* @__PURE__ */ new Date();
|
|
197
|
-
const diff = (
|
|
215
|
+
const diff = (date instanceof Date ? date.getTime() : toNumber(date)) - now.getTime();
|
|
198
216
|
if (!Number.isFinite(diff)) return formatNumber(diff);
|
|
199
217
|
const isLong = opts?.style === "long";
|
|
200
218
|
const unit = RELATIVE_UNITS.find((candidate) => Math.abs(diff) >= candidate.ms);
|
|
@@ -204,6 +222,36 @@ function formatRelativeTime(date, opts) {
|
|
|
204
222
|
const amount = `${decimal(count, 0)}${unit.short}`;
|
|
205
223
|
return diff < 0 ? `${amount} ago` : `in ${amount}`;
|
|
206
224
|
}
|
|
225
|
+
/** The `Intl` fields of each `formatDate` style. */
|
|
226
|
+
var DATE_STYLE_TO_FORMAT_OPTIONS_MAP = {
|
|
227
|
+
date: {
|
|
228
|
+
month: "short",
|
|
229
|
+
day: "numeric",
|
|
230
|
+
year: "numeric"
|
|
231
|
+
},
|
|
232
|
+
dateTime: {
|
|
233
|
+
month: "short",
|
|
234
|
+
day: "numeric",
|
|
235
|
+
hour: "numeric",
|
|
236
|
+
minute: "2-digit",
|
|
237
|
+
second: "2-digit"
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
/**
|
|
241
|
+
* Formats a date (or a unix-millisecond timestamp, `number` or `bigint`). `{ style: "date" }`
|
|
242
|
+
* (default) → `"Oct 3, 2026"`, the DateInput and table default; `{ style: "dateTime" }` →
|
|
243
|
+
* `"Oct 10, 3:04:05 PM"`, an event in the recent past. `locale` defaults to `"en-US"`;
|
|
244
|
+
* `timeZone` defaults to the runtime's (pass `"UTC"` when server and client must agree). An
|
|
245
|
+
* invalid date is returned as `formatNumber` prints `NaN`.
|
|
246
|
+
*/
|
|
247
|
+
function formatDate(date, opts) {
|
|
248
|
+
const time = date instanceof Date ? date.getTime() : toNumber(date);
|
|
249
|
+
if (!Number.isFinite(time)) return formatNumber(time);
|
|
250
|
+
return new Intl.DateTimeFormat(opts?.locale ?? DEFAULT_LOCALE, {
|
|
251
|
+
...DATE_STYLE_TO_FORMAT_OPTIONS_MAP[opts?.style ?? "date"],
|
|
252
|
+
...opts?.timeZone === void 0 ? {} : { timeZone: opts.timeZone }
|
|
253
|
+
}).format(time);
|
|
254
|
+
}
|
|
207
255
|
/**
|
|
208
256
|
* Formats a ratio as a percentage. `0.1234` → `"12.3%"`. `precision` is the maximum fraction
|
|
209
257
|
* digits (default `1`).
|
|
@@ -217,4 +265,4 @@ function formatPercent(ratio, opts) {
|
|
|
217
265
|
}).format(ratio);
|
|
218
266
|
}
|
|
219
267
|
//#endregion
|
|
220
|
-
export { formatBytes, formatDuration, formatNumber, formatPercent, formatRelativeTime };
|
|
268
|
+
export { EMPTY_VALUE, formatBytes, formatDate, formatDuration, formatNumber, formatPercent, formatRelativeTime };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text search for lists that filter as the user types: CommandPalette, Menu, SelectInput,
|
|
3
|
+
* MultiSelectInput and JsonViewer use it, so one term matches the same rows everywhere. The rule:
|
|
4
|
+
* trim the term, lower-case it with `toLocaleLowerCase`, and match when any field contains it (an
|
|
5
|
+
* empty term matches everything). Pure functions, safe at module scope and under SSR.
|
|
6
|
+
*/
|
|
7
|
+
/** The term as it is compared: trimmed and lower-cased (`" Orders "` → `"orders"`). */
|
|
8
|
+
export declare function normalizeSearchTerm(term: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Whether any field contains the term, case-insensitively. An empty (or blank) term matches;
|
|
11
|
+
* `null` and `undefined` fields are skipped, so optional fields pass straight through:
|
|
12
|
+
* `isSearchMatch(term, item.label, item.description, ...item.keywords)`. The term may already be
|
|
13
|
+
* normalized (normalizing is idempotent).
|
|
14
|
+
*/
|
|
15
|
+
export declare function isSearchMatch(term: string, ...fields: readonly (string | null | undefined)[]): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/utils/search.ts
|
|
2
|
+
/**
|
|
3
|
+
* Text search for lists that filter as the user types: CommandPalette, Menu, SelectInput,
|
|
4
|
+
* MultiSelectInput and JsonViewer use it, so one term matches the same rows everywhere. The rule:
|
|
5
|
+
* trim the term, lower-case it with `toLocaleLowerCase`, and match when any field contains it (an
|
|
6
|
+
* empty term matches everything). Pure functions, safe at module scope and under SSR.
|
|
7
|
+
*/
|
|
8
|
+
/** The term as it is compared: trimmed and lower-cased (`" Orders "` → `"orders"`). */
|
|
9
|
+
function normalizeSearchTerm(term) {
|
|
10
|
+
return term.trim().toLocaleLowerCase();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Whether any field contains the term, case-insensitively. An empty (or blank) term matches;
|
|
14
|
+
* `null` and `undefined` fields are skipped, so optional fields pass straight through:
|
|
15
|
+
* `isSearchMatch(term, item.label, item.description, ...item.keywords)`. The term may already be
|
|
16
|
+
* normalized (normalizing is idempotent).
|
|
17
|
+
*/
|
|
18
|
+
function isSearchMatch(term, ...fields) {
|
|
19
|
+
const normalized = normalizeSearchTerm(term);
|
|
20
|
+
if (normalized === "") return true;
|
|
21
|
+
return fields.some((field) => field?.toLocaleLowerCase().includes(normalized) ?? false);
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { isSearchMatch, normalizeSearchTerm };
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Plugin } from "@wyw-in-js/vite";
|
|
2
|
+
import { GalaxyTheme } from "../theme/enums.js";
|
|
2
3
|
/** Options for {@link galaxyDls}. */
|
|
3
4
|
export type GalaxyDlsOptions = {
|
|
4
5
|
/**
|
|
@@ -7,10 +8,23 @@ export type GalaxyDlsOptions = {
|
|
|
7
8
|
* @default "gx"
|
|
8
9
|
*/
|
|
9
10
|
prefix?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The theme the page boots in before `GalaxyProvider` mounts. Pass the provider's own `theme`; a
|
|
13
|
+
* choice stored under `storageKey` still wins, as it does in the provider.
|
|
14
|
+
* @default GalaxyTheme.SYSTEM
|
|
15
|
+
*/
|
|
16
|
+
theme?: GalaxyTheme;
|
|
17
|
+
/**
|
|
18
|
+
* Where the provider stores the user's choice; the boot script reads it and never writes it.
|
|
19
|
+
* Pass the provider's `storageKey` if you changed it.
|
|
20
|
+
* @default "galaxy:theme"
|
|
21
|
+
*/
|
|
22
|
+
storageKey?: string;
|
|
10
23
|
};
|
|
11
24
|
/**
|
|
12
25
|
* Returns the configured `@wyw-in-js/vite` plugin: the DLS Babel presets (React automatic
|
|
13
|
-
* runtime + TypeScript), `include`/`exclude`,
|
|
14
|
-
* `
|
|
26
|
+
* runtime + TypeScript), `include`/`exclude`, and the DLS's own class-name config (the slug
|
|
27
|
+
* `gx-<Component>-<Part>-<hash>` with `gx` replaced by `prefix`, no vendor prefixes, React
|
|
28
|
+
* `importOverrides`), so app CSS is named and emitted like DLS CSS.
|
|
15
29
|
*/
|
|
16
30
|
export declare function galaxyDls(options?: GalaxyDlsOptions): Plugin;
|
package/dist/vite/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { GalaxyTheme } from "../theme/enums.js";
|
|
2
|
+
import { BOOT_THEMES, DEFAULT_THEME_STORAGE_KEY, themeBackgroundStyle, themeBootScript } from "./internal/themeBoot.js";
|
|
3
|
+
import { sharedWywOptions } from "./internal/wywOptions.js";
|
|
1
4
|
import { createRequire } from "node:module";
|
|
2
5
|
import wyw from "@wyw-in-js/vite";
|
|
3
6
|
//#region src/vite/index.ts
|
|
@@ -12,41 +15,47 @@ import wyw from "@wyw-in-js/vite";
|
|
|
12
15
|
*
|
|
13
16
|
* The DLS itself ships pre-extracted CSS (`@galaxy-io/dls/styles.css`); this preset only
|
|
14
17
|
* compiles the app's own `styled` / `css` code, which reads DLS tokens through `t`.
|
|
18
|
+
*
|
|
19
|
+
* It also boots the theme in `index.html`: one inline script sets `data-gx-theme` on `<html>`
|
|
20
|
+
* before the first paint (the stored choice, else `theme`, resolving `SYSTEM` from the OS), and one
|
|
21
|
+
* `<style>` paints the canvas per theme, so a page never flashes the wrong theme before
|
|
22
|
+
* `GalaxyProvider` mounts. Pass the same `theme` and `storageKey` as the app's provider. A strict
|
|
23
|
+
* Content Security Policy needs the script's hash.
|
|
15
24
|
*/
|
|
16
|
-
/** The DLS class prefix; also the default app prefix. */
|
|
17
|
-
var DEFAULT_PREFIX = "gx";
|
|
18
25
|
/** A valid start for a CSS class name: a letter, then letters, digits or `-`. */
|
|
19
26
|
var PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9-]*$/;
|
|
20
|
-
/** The styled root is named `Root`; its class drops the part segment. */
|
|
21
|
-
var ROOT_PART = "Root";
|
|
22
27
|
/** Files the plugin compiles. The DLS (and every other package) ships already compiled. */
|
|
23
28
|
var INCLUDE = ["**/*.{js,jsx,ts,tsx}"];
|
|
24
29
|
var EXCLUDE = ["**/node_modules/**"];
|
|
25
30
|
/**
|
|
26
|
-
* React is reached while wyw evaluates `styled` components at build time; loading it as-is is
|
|
27
|
-
* expected, so the "unknown import reached during eval" warning is silenced for it.
|
|
28
|
-
*/
|
|
29
|
-
var IMPORT_OVERRIDES = {
|
|
30
|
-
react: { unknown: "allow" },
|
|
31
|
-
"react/jsx-runtime": { unknown: "allow" },
|
|
32
|
-
"react/jsx-dev-runtime": { unknown: "allow" }
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
31
|
* Returns the configured `@wyw-in-js/vite` plugin: the DLS Babel presets (React automatic
|
|
36
|
-
* runtime + TypeScript), `include`/`exclude`,
|
|
37
|
-
* `
|
|
32
|
+
* runtime + TypeScript), `include`/`exclude`, and the DLS's own class-name config (the slug
|
|
33
|
+
* `gx-<Component>-<Part>-<hash>` with `gx` replaced by `prefix`, no vendor prefixes, React
|
|
34
|
+
* `importOverrides`), so app CSS is named and emitted like DLS CSS.
|
|
38
35
|
*/
|
|
39
36
|
function galaxyDls(options = {}) {
|
|
40
|
-
const { prefix =
|
|
37
|
+
const { prefix = "gx", theme = GalaxyTheme.SYSTEM, storageKey = DEFAULT_THEME_STORAGE_KEY } = options;
|
|
41
38
|
if (!PREFIX_PATTERN.test(prefix)) throw new Error(`[@galaxy-io/dls/vite] prefix "${prefix}" is not a valid class-name start: use letters, digits and "-", starting with a letter.`);
|
|
39
|
+
if (!BOOT_THEMES.includes(theme)) throw new Error(`[@galaxy-io/dls/vite] theme "${theme}" is not a GalaxyTheme: use GalaxyTheme.SYSTEM, DARK or LIGHT.`);
|
|
42
40
|
const require = createRequire(import.meta.url);
|
|
43
|
-
|
|
41
|
+
const plugin = wyw({
|
|
44
42
|
include: INCLUDE,
|
|
45
43
|
exclude: EXCLUDE,
|
|
46
44
|
babelOptions: { presets: [[require.resolve("@babel/preset-react"), { runtime: "automatic" }], require.resolve("@babel/preset-typescript")] },
|
|
47
|
-
|
|
48
|
-
classNameSlug: (hash, title, { name }) => `${prefix}-${name}${title === ROOT_PART ? "" : `-${title}`}-${hash}`
|
|
45
|
+
...sharedWywOptions(prefix)
|
|
49
46
|
});
|
|
47
|
+
const bootScript = themeBootScript(theme, storageKey);
|
|
48
|
+
const backgroundStyle = themeBackgroundStyle();
|
|
49
|
+
plugin.transformIndexHtml = () => [{
|
|
50
|
+
tag: "script",
|
|
51
|
+
children: bootScript,
|
|
52
|
+
injectTo: "head-prepend"
|
|
53
|
+
}, {
|
|
54
|
+
tag: "style",
|
|
55
|
+
children: backgroundStyle,
|
|
56
|
+
injectTo: "head-prepend"
|
|
57
|
+
}];
|
|
58
|
+
return plugin;
|
|
50
59
|
}
|
|
51
60
|
//#endregion
|
|
52
61
|
export { galaxyDls };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal What `galaxyDls()` injects into `index.html` so the first paint is already in the
|
|
3
|
+
* right theme: one inline script that sets `data-gx-theme` on `<html>`, and one `<style>` that
|
|
4
|
+
* paints the canvas per theme. Private on purpose (an `internal/` module: built, never a package
|
|
5
|
+
* export).
|
|
6
|
+
*
|
|
7
|
+
* The script resolves the theme exactly as `GalaxyProvider` does on mount, so nothing flips when
|
|
8
|
+
* React takes over: a valid stored choice (`DARK`, `LIGHT` or `SYSTEM` under `storageKey`) wins
|
|
9
|
+
* over the configured `theme`; `SYSTEM` reads `prefers-color-scheme`, and falls back to dark where
|
|
10
|
+
* `matchMedia` is missing (the provider's default). It reads storage and never writes it, and any
|
|
11
|
+
* error leaves the page as the server sent it.
|
|
12
|
+
*
|
|
13
|
+
* The background is a `<style>` keyed off the attribute, never an inline `style` on `<html>`: an
|
|
14
|
+
* inline background would stay the boot theme after a runtime switch, because nothing removes it.
|
|
15
|
+
* Its values come from the token modules, so they are `background.base` in each theme.
|
|
16
|
+
*/
|
|
17
|
+
import { GalaxyTheme } from "../../theme/enums.js";
|
|
18
|
+
/** @internal The provider's default storage key; the boot script must read the same one. */
|
|
19
|
+
export declare const DEFAULT_THEME_STORAGE_KEY = "galaxy:theme";
|
|
20
|
+
/** @internal The boot script's source: resolves the theme and sets `data-gx-theme`. */
|
|
21
|
+
export declare function themeBootScript(theme: GalaxyTheme, storageKey: string): string;
|
|
22
|
+
/** @internal The canvas per theme, keyed off the attribute the script (then the provider) sets. */
|
|
23
|
+
export declare function themeBackgroundStyle(): string;
|
|
24
|
+
/** @internal The themes `galaxyDls({ theme })` accepts. */
|
|
25
|
+
export declare const BOOT_THEMES: readonly string[];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { GalaxyTheme } from "../../theme/enums.js";
|
|
2
|
+
import { DARK_THEME } from "../../theme/tokens/dark.js";
|
|
3
|
+
import { LIGHT_THEME } from "../../theme/tokens/light.js";
|
|
4
|
+
//#region src/vite/internal/themeBoot.ts
|
|
5
|
+
/**
|
|
6
|
+
* @internal What `galaxyDls()` injects into `index.html` so the first paint is already in the
|
|
7
|
+
* right theme: one inline script that sets `data-gx-theme` on `<html>`, and one `<style>` that
|
|
8
|
+
* paints the canvas per theme. Private on purpose (an `internal/` module: built, never a package
|
|
9
|
+
* export).
|
|
10
|
+
*
|
|
11
|
+
* The script resolves the theme exactly as `GalaxyProvider` does on mount, so nothing flips when
|
|
12
|
+
* React takes over: a valid stored choice (`DARK`, `LIGHT` or `SYSTEM` under `storageKey`) wins
|
|
13
|
+
* over the configured `theme`; `SYSTEM` reads `prefers-color-scheme`, and falls back to dark where
|
|
14
|
+
* `matchMedia` is missing (the provider's default). It reads storage and never writes it, and any
|
|
15
|
+
* error leaves the page as the server sent it.
|
|
16
|
+
*
|
|
17
|
+
* The background is a `<style>` keyed off the attribute, never an inline `style` on `<html>`: an
|
|
18
|
+
* inline background would stay the boot theme after a runtime switch, because nothing removes it.
|
|
19
|
+
* Its values come from the token modules, so they are `background.base` in each theme.
|
|
20
|
+
*/
|
|
21
|
+
/** @internal The provider's default storage key; the boot script must read the same one. */
|
|
22
|
+
var DEFAULT_THEME_STORAGE_KEY = "galaxy:theme";
|
|
23
|
+
/** A JSON string literal that is also safe inside a `<script>` element (no `<\/script>` break-out). */
|
|
24
|
+
var toScriptLiteral = (value) => JSON.stringify(value).replace(/</g, "\\u003c");
|
|
25
|
+
/** @internal The boot script's source: resolves the theme and sets `data-gx-theme`. */
|
|
26
|
+
function themeBootScript(theme, storageKey) {
|
|
27
|
+
return [
|
|
28
|
+
"(function(){",
|
|
29
|
+
`var t=${toScriptLiteral(theme)},s=null;`,
|
|
30
|
+
`try{s=window.localStorage.getItem(${toScriptLiteral(storageKey)})}catch(e){}`,
|
|
31
|
+
"if(s===\"DARK\"||s===\"LIGHT\"||s===\"SYSTEM\")t=s;",
|
|
32
|
+
"if(t===\"SYSTEM\"){t=\"DARK\";try{if(!window.matchMedia(\"(prefers-color-scheme: dark)\").matches)t=\"LIGHT\"}catch(e){}}",
|
|
33
|
+
"document.documentElement.setAttribute(\"data-gx-theme\",t===\"LIGHT\"?\"light\":\"dark\")",
|
|
34
|
+
"})();"
|
|
35
|
+
].join("");
|
|
36
|
+
}
|
|
37
|
+
/** @internal The canvas per theme, keyed off the attribute the script (then the provider) sets. */
|
|
38
|
+
function themeBackgroundStyle() {
|
|
39
|
+
return [`html[data-gx-theme="dark"]{background:${DARK_THEME.color.background.base}}`, `html[data-gx-theme="light"]{background:${LIGHT_THEME.color.background.base}}`].join("");
|
|
40
|
+
}
|
|
41
|
+
/** @internal The themes `galaxyDls({ theme })` accepts. */
|
|
42
|
+
var BOOT_THEMES = Object.values(GalaxyTheme);
|
|
43
|
+
//#endregion
|
|
44
|
+
export { BOOT_THEMES, DEFAULT_THEME_STORAGE_KEY, themeBackgroundStyle, themeBootScript };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @internal The one class-name and compile config for Linaria (wyw-in-js), shared by the DLS's own
|
|
3
|
+
* build and Storybook (`wyw.config.ts`) and by the app preset (`galaxyDls()`), so a DLS class and
|
|
4
|
+
* an app class are named and emitted the same way. Private on purpose (an `internal/` module:
|
|
5
|
+
* built, never a package export). Each caller adds only what differs: its `include` / `exclude`,
|
|
6
|
+
* and how it resolves the Babel presets.
|
|
7
|
+
*
|
|
8
|
+
* Class names read `<prefix>-<Component>-<Part>-<hash>` (`gx-Button-Label-1a2b3c`); a styled root
|
|
9
|
+
* named `Root` drops the part (`gx-Button-1a2b3c`), so the inspector names the component.
|
|
10
|
+
*/
|
|
11
|
+
/** The DLS class prefix; also the default app prefix. */
|
|
12
|
+
export declare const DLS_CLASS_PREFIX = "gx";
|
|
13
|
+
/** What wyw passes the slug function besides the hash and the styled name. */
|
|
14
|
+
interface SlugArgs {
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
/** @internal The class-name slug for a prefix: `<prefix>-<Component>-<Part>-<hash>`, `Root` unnamed. */
|
|
18
|
+
export declare function classNameSlug(prefix: string): (hash: string, title: string, { name }: SlugArgs) => string;
|
|
19
|
+
/**
|
|
20
|
+
* @internal The options every caller shares, for a class prefix: the slug, no vendor prefixes,
|
|
21
|
+
* and the React import overrides.
|
|
22
|
+
*
|
|
23
|
+
* `prefixer: false`: every browser the DLS targets reads the unprefixed properties, and the stylis
|
|
24
|
+
* prefixer would add about 1,300 `-webkit-` declarations and duplicate every keyframe. Apps get
|
|
25
|
+
* the same, so their CSS and the DLS's match.
|
|
26
|
+
*
|
|
27
|
+
* React is reached while wyw evaluates `styled` components at build time; loading it as-is is
|
|
28
|
+
* expected, so the "unknown import reached during eval" warning is silenced for it (the dev
|
|
29
|
+
* runtime too, for an app's dev server).
|
|
30
|
+
*/
|
|
31
|
+
export declare function sharedWywOptions(prefix: string): {
|
|
32
|
+
readonly classNameSlug: (hash: string, title: string, { name }: SlugArgs) => string;
|
|
33
|
+
readonly prefixer: false;
|
|
34
|
+
readonly importOverrides: {
|
|
35
|
+
readonly react: {
|
|
36
|
+
readonly unknown: "allow";
|
|
37
|
+
};
|
|
38
|
+
readonly "react/jsx-runtime": {
|
|
39
|
+
readonly unknown: "allow";
|
|
40
|
+
};
|
|
41
|
+
readonly "react/jsx-dev-runtime": {
|
|
42
|
+
readonly unknown: "allow";
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/vite/internal/wywOptions.ts
|
|
2
|
+
/**
|
|
3
|
+
* @internal The one class-name and compile config for Linaria (wyw-in-js), shared by the DLS's own
|
|
4
|
+
* build and Storybook (`wyw.config.ts`) and by the app preset (`galaxyDls()`), so a DLS class and
|
|
5
|
+
* an app class are named and emitted the same way. Private on purpose (an `internal/` module:
|
|
6
|
+
* built, never a package export). Each caller adds only what differs: its `include` / `exclude`,
|
|
7
|
+
* and how it resolves the Babel presets.
|
|
8
|
+
*
|
|
9
|
+
* Class names read `<prefix>-<Component>-<Part>-<hash>` (`gx-Button-Label-1a2b3c`); a styled root
|
|
10
|
+
* named `Root` drops the part (`gx-Button-1a2b3c`), so the inspector names the component.
|
|
11
|
+
*/
|
|
12
|
+
/** The DLS class prefix; also the default app prefix. */
|
|
13
|
+
var DLS_CLASS_PREFIX = "gx";
|
|
14
|
+
/** The styled root's name; its class drops the part segment. */
|
|
15
|
+
var ROOT_PART = "Root";
|
|
16
|
+
/** @internal The class-name slug for a prefix: `<prefix>-<Component>-<Part>-<hash>`, `Root` unnamed. */
|
|
17
|
+
function classNameSlug(prefix) {
|
|
18
|
+
return (hash, title, { name }) => `${prefix}-${name}${title === ROOT_PART ? "" : `-${title}`}-${hash}`;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @internal The options every caller shares, for a class prefix: the slug, no vendor prefixes,
|
|
22
|
+
* and the React import overrides.
|
|
23
|
+
*
|
|
24
|
+
* `prefixer: false`: every browser the DLS targets reads the unprefixed properties, and the stylis
|
|
25
|
+
* prefixer would add about 1,300 `-webkit-` declarations and duplicate every keyframe. Apps get
|
|
26
|
+
* the same, so their CSS and the DLS's match.
|
|
27
|
+
*
|
|
28
|
+
* React is reached while wyw evaluates `styled` components at build time; loading it as-is is
|
|
29
|
+
* expected, so the "unknown import reached during eval" warning is silenced for it (the dev
|
|
30
|
+
* runtime too, for an app's dev server).
|
|
31
|
+
*/
|
|
32
|
+
function sharedWywOptions(prefix) {
|
|
33
|
+
return {
|
|
34
|
+
classNameSlug: classNameSlug(prefix),
|
|
35
|
+
prefixer: false,
|
|
36
|
+
importOverrides: {
|
|
37
|
+
react: { unknown: "allow" },
|
|
38
|
+
"react/jsx-runtime": { unknown: "allow" },
|
|
39
|
+
"react/jsx-dev-runtime": { unknown: "allow" }
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { DLS_CLASS_PREFIX, classNameSlug, sharedWywOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@galaxy-io/dls",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"description": "Galaxy Design Language System",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -69,6 +69,10 @@
|
|
|
69
69
|
"types": "./dist/brand/GalaxyWordmark.d.ts",
|
|
70
70
|
"import": "./dist/brand/GalaxyWordmark.js"
|
|
71
71
|
},
|
|
72
|
+
"./brand/PoweredBy": {
|
|
73
|
+
"types": "./dist/brand/PoweredBy.d.ts",
|
|
74
|
+
"import": "./dist/brand/PoweredBy.js"
|
|
75
|
+
},
|
|
72
76
|
"./brand/brandMark": {
|
|
73
77
|
"types": "./dist/brand/brandMark.d.ts",
|
|
74
78
|
"import": "./dist/brand/brandMark.js"
|
|
@@ -297,6 +301,10 @@
|
|
|
297
301
|
"types": "./dist/hooks/useElementWidth.d.ts",
|
|
298
302
|
"import": "./dist/hooks/useElementWidth.js"
|
|
299
303
|
},
|
|
304
|
+
"./hooks/useEndReached": {
|
|
305
|
+
"types": "./dist/hooks/useEndReached.d.ts",
|
|
306
|
+
"import": "./dist/hooks/useEndReached.js"
|
|
307
|
+
},
|
|
300
308
|
"./hooks/useField": {
|
|
301
309
|
"types": "./dist/hooks/useField.d.ts",
|
|
302
310
|
"import": "./dist/hooks/useField.js"
|
|
@@ -441,6 +449,10 @@
|
|
|
441
449
|
"types": "./dist/json/JsonViewer.d.ts",
|
|
442
450
|
"import": "./dist/json/JsonViewer.js"
|
|
443
451
|
},
|
|
452
|
+
"./layout/AppFrame": {
|
|
453
|
+
"types": "./dist/layout/AppFrame.d.ts",
|
|
454
|
+
"import": "./dist/layout/AppFrame.js"
|
|
455
|
+
},
|
|
444
456
|
"./layout/Box": {
|
|
445
457
|
"types": "./dist/layout/Box.d.ts",
|
|
446
458
|
"import": "./dist/layout/Box.js"
|
|
@@ -449,6 +461,14 @@
|
|
|
449
461
|
"types": "./dist/layout/Divider.d.ts",
|
|
450
462
|
"import": "./dist/layout/Divider.js"
|
|
451
463
|
},
|
|
464
|
+
"./layout/EmptyLayout": {
|
|
465
|
+
"types": "./dist/layout/EmptyLayout.d.ts",
|
|
466
|
+
"import": "./dist/layout/EmptyLayout.js"
|
|
467
|
+
},
|
|
468
|
+
"./layout/ErrorLayout": {
|
|
469
|
+
"types": "./dist/layout/ErrorLayout.d.ts",
|
|
470
|
+
"import": "./dist/layout/ErrorLayout.js"
|
|
471
|
+
},
|
|
452
472
|
"./layout/Flex": {
|
|
453
473
|
"types": "./dist/layout/Flex.d.ts",
|
|
454
474
|
"import": "./dist/layout/Flex.js"
|
|
@@ -461,6 +481,14 @@
|
|
|
461
481
|
"types": "./dist/layout/Grid.d.ts",
|
|
462
482
|
"import": "./dist/layout/Grid.js"
|
|
463
483
|
},
|
|
484
|
+
"./layout/PageLayout": {
|
|
485
|
+
"types": "./dist/layout/PageLayout.d.ts",
|
|
486
|
+
"import": "./dist/layout/PageLayout.js"
|
|
487
|
+
},
|
|
488
|
+
"./layout/PendingLayout": {
|
|
489
|
+
"types": "./dist/layout/PendingLayout.d.ts",
|
|
490
|
+
"import": "./dist/layout/PendingLayout.js"
|
|
491
|
+
},
|
|
464
492
|
"./layout/Portal": {
|
|
465
493
|
"types": "./dist/layout/Portal.d.ts",
|
|
466
494
|
"import": "./dist/layout/Portal.js"
|
|
@@ -757,6 +785,10 @@
|
|
|
757
785
|
"types": "./dist/utils/format.d.ts",
|
|
758
786
|
"import": "./dist/utils/format.js"
|
|
759
787
|
},
|
|
788
|
+
"./utils/search": {
|
|
789
|
+
"types": "./dist/utils/search.d.ts",
|
|
790
|
+
"import": "./dist/utils/search.js"
|
|
791
|
+
},
|
|
760
792
|
"./vite": {
|
|
761
793
|
"types": "./dist/vite/index.d.ts",
|
|
762
794
|
"import": "./dist/vite/index.js"
|
|
@@ -946,6 +978,7 @@
|
|
|
946
978
|
"d3-scale": "^4.0.2",
|
|
947
979
|
"d3-shape": "^3.2.0",
|
|
948
980
|
"glob": "^13.0.6",
|
|
981
|
+
"happy-dom": "20.10.2",
|
|
949
982
|
"lottie-react": "^2.4.1",
|
|
950
983
|
"publint": "^0.3.25",
|
|
951
984
|
"react": "^18.3.1",
|