@stacksjs/ui 0.70.87 → 0.70.88

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/ui",
3
3
  "type": "module",
4
- "version": "0.70.87",
4
+ "version": "0.70.88",
5
5
  "description": "The Stacks UI engine.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [
@@ -62,8 +62,8 @@
62
62
  },
63
63
  "devDependencies": {
64
64
  "@stacksjs/build": "workspace:*",
65
- "@stacksjs/config": "0.70.87",
65
+ "@stacksjs/config": "0.70.88",
66
66
  "better-dx": "^0.2.16",
67
- "@stacksjs/router": "0.70.87"
67
+ "@stacksjs/router": "0.70.88"
68
68
  }
69
69
  }
@@ -1 +0,0 @@
1
-
File without changes
@@ -1,4 +0,0 @@
1
- // Disclosure primitives were part of the former Vue compatibility layer.
2
- // stx does not expose them, so keep this module intentionally empty instead
3
- // of publishing exports that fail at runtime.
4
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,2 +0,0 @@
1
- // Menu primitives were part of the former Vue compatibility layer.
2
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,6 +0,0 @@
1
- export {
2
- Dialog,
3
- DialogDescription,
4
- DialogPanel,
5
- DialogTitle,
6
- } from '@stacksjs/components';
@@ -1,6 +0,0 @@
1
- export {
2
- Dialog,
3
- DialogDescription,
4
- DialogPanel,
5
- DialogTitle
6
- } from "@stacksjs/components";
@@ -1 +0,0 @@
1
- export { Popover, PopoverButton, PopoverPanel } from '@stacksjs/components';
@@ -1 +0,0 @@
1
- export { Popover, PopoverButton, PopoverPanel } from "@stacksjs/components";
@@ -1,5 +0,0 @@
1
- export {
2
- RadioGroup,
3
- RadioGroupLabel,
4
- RadioGroupOption,
5
- } from '@stacksjs/components';
@@ -1,5 +0,0 @@
1
- export {
2
- RadioGroup,
3
- RadioGroupLabel,
4
- RadioGroupOption
5
- } from "@stacksjs/components";
@@ -1,6 +0,0 @@
1
- export {
2
- Combobox,
3
- ComboboxInput,
4
- ComboboxOption,
5
- ComboboxOptions,
6
- } from '@stacksjs/components';
@@ -1,6 +0,0 @@
1
- export {
2
- Combobox,
3
- ComboboxInput,
4
- ComboboxOption,
5
- ComboboxOptions
6
- } from "@stacksjs/components";
@@ -1,2 +0,0 @@
1
- export type { Tab, TabPanelProps, TabsProps } from '@stacksjs/components';
2
- export { TabPanel, Tabs } from '@stacksjs/components';
@@ -1 +0,0 @@
1
- export { TabPanel, Tabs } from "@stacksjs/components";
@@ -1 +0,0 @@
1
- export { Switch } from '@stacksjs/components';
@@ -1 +0,0 @@
1
- export { Switch } from "@stacksjs/components";
@@ -1,2 +0,0 @@
1
- export type { TransitionProps } from '@stacksjs/components';
2
- export { Transition } from '@stacksjs/components';
@@ -1 +0,0 @@
1
- export { Transition } from "@stacksjs/components";
@@ -1,10 +0,0 @@
1
- export * from './components/autocomplete';
2
- export * from './components/disclosure';
3
- export * from './components/menu';
4
- export * from './components/modal';
5
- export * from './components/popover';
6
- export * from './components/radio-group';
7
- export * from './components/select';
8
- export * from './components/tabs';
9
- export * from './components/toggle';
10
- export * from './components/transition';
@@ -1,10 +0,0 @@
1
- export * from "./components/autocomplete";
2
- export * from "./components/disclosure";
3
- export * from "./components/menu";
4
- export * from "./components/modal";
5
- export * from "./components/popover";
6
- export * from "./components/radio-group";
7
- export * from "./components/select";
8
- export * from "./components/tabs";
9
- export * from "./components/toggle";
10
- export * from "./components/transition";
package/dist/fonts.d.ts DELETED
@@ -1,68 +0,0 @@
1
- /**
2
- * Render `<link rel="preload" as="font" crossorigin>` tags for every
3
- * font with `preload !== false`. Cross-origin attribute is always
4
- * emitted because most CDN-hosted fonts require it and same-origin
5
- * fonts ignore it harmlessly.
6
- *
7
- * Output is a single string with one tag per line, ready to drop into
8
- * a stx layout's `<head>` via `{{ renderFontPreloads(fonts) }}`.
9
- */
10
- export declare function renderFontPreloads(fonts?: FontEntry[]): string;
11
- /**
12
- * Render an `@font-face { ... }` block for every entry. `font-display:
13
- * swap` is the default; override per-entry with `display`.
14
- *
15
- * Wrap the result in `<style>` tags when inlining into a layout's
16
- * `<head>`, or write to a separate CSS file and `<link>` it.
17
- */
18
- export declare function renderFontFaceCss(fonts?: FontEntry[]): string;
19
- /**
20
- * Convenience helper: render BOTH the preload tags and the wrapped
21
- * `<style>...@font-face...</style>` block in one go, separated by a
22
- * newline. Drop this into the very top of your layout's `<head>` for
23
- * the maximal CLS win.
24
- *
25
- * @example
26
- * ```stx
27
- * <head>
28
- * {{ renderFontHead(config.ui.fonts) }}
29
- * <title>...</title>
30
- * </head>
31
- * ```
32
- */
33
- export declare function renderFontHead(fonts?: FontEntry[]): string;
34
- /**
35
- * Web-font preload + `@font-face` rendering helpers
36
- * (stacksjs/stacks#283 — prevent layout shifts).
37
- *
38
- * Layout shifts (the LS in CLS) happen when a page renders with the
39
- * fallback font, then re-flows once the web font loads. The two
40
- * mitigations this module ships against that:
41
- *
42
- * 1. **Preload** — emit `<link rel="preload" as="font" crossorigin>`
43
- * for each font listed in the UI config, so the browser starts the
44
- * font download in parallel with HTML parsing rather than waiting
45
- * to discover the URL via CSS.
46
- *
47
- * 2. **`font-display: swap`** — the default `@font-face` block uses
48
- * `font-display: swap`, which shows the fallback font immediately
49
- * and swaps in the web font once available. Layout still shifts
50
- * slightly at swap time, but the page is readable from t=0 instead
51
- * of being blocked by the font fetch.
52
- *
53
- * Apps drop a list of fonts into `config/ui.ts` and call these helpers
54
- * from their layout's `<head>` — see {@link renderFontHead}. Both
55
- * outputs are safe to inline into HTML (no user-controlled values
56
- * interpolate; the FontEntry shape is config-only).
57
- */
58
- /** One configured web font. */
59
- export declare interface FontEntry {
60
- family: string
61
- src: string
62
- format?: 'woff2' | 'woff' | 'truetype' | 'opentype'
63
- weight?: number | string
64
- style?: 'normal' | 'italic' | 'oblique'
65
- display?: 'auto' | 'swap' | 'block' | 'fallback' | 'optional'
66
- preload?: boolean
67
- unicodeRange?: string
68
- }
package/dist/fonts.js DELETED
@@ -1,53 +0,0 @@
1
- const FORMAT_LABEL = {
2
- woff2: "woff2",
3
- woff: "woff",
4
- truetype: "truetype",
5
- opentype: "opentype"
6
- }, FORMAT_MIME = {
7
- woff2: "font/woff2",
8
- woff: "font/woff",
9
- truetype: "font/ttf",
10
- opentype: "font/otf"
11
- };
12
- export function renderFontPreloads(fonts = []) {
13
- return fonts.filter((font) => font.preload !== !1).map((font) => {
14
- const fmt = font.format ?? "woff2", type = FORMAT_MIME[fmt];
15
- return `<link rel="preload" href="${escapeAttr(font.src)}" as="font" type="${type}" crossorigin>`;
16
- }).join(`
17
- `);
18
- }
19
- export function renderFontFaceCss(fonts = []) {
20
- return fonts.map((font) => {
21
- const fmt = font.format ?? "woff2", fmtLabel = FORMAT_LABEL[fmt], weight = font.weight ?? "normal", style = font.style ?? "normal", display = font.display ?? "swap", ur = font.unicodeRange;
22
- return `@font-face {
23
- font-family: '${escapeFamily(font.family)}';
24
- src: url('${escapeUrl(font.src)}') format('${fmtLabel}');
25
- font-weight: ${weight};
26
- font-style: ${style};
27
- font-display: ${display};${ur ? `
28
- unicode-range: ${ur};` : ""}
29
- }`;
30
- }).join(`
31
-
32
- `);
33
- }
34
- export function renderFontHead(fonts = []) {
35
- if (fonts.length === 0)
36
- return "";
37
- const preloads = renderFontPreloads(fonts), faces = renderFontFaceCss(fonts);
38
- return `${preloads}
39
- <style>
40
- ${faces}
41
- </style>`;
42
- }
43
- function escapeAttr(s) {
44
- return String(s).replace(/[&<>"']/g, (c) => {
45
- return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c];
46
- });
47
- }
48
- function escapeUrl(s) {
49
- return String(s).replace(/['"`()<>{};\\\r\n\t*]/g, "");
50
- }
51
- function escapeFamily(s) {
52
- return String(s).replace(/[^A-Z0-9 \-_.]/gi, "");
53
- }
package/dist/index.d.ts DELETED
@@ -1,22 +0,0 @@
1
- import { ui } from '@stacksjs/config';
2
- import * as CssEngine from '@cwcss/crosswind';
3
- export type { FontEntry } from './fonts';
4
- export type { PaginatorView } from './pagination';
5
- export { CssEngine, ui };
6
- // Web-font preload + @font-face helpers — used by stx layouts to
7
- // eliminate the FOUT/CLS that hits when a page renders with the
8
- // fallback font and then re-flows once the web font lands
9
- // (stacksjs/stacks#283).
10
- export {
11
- renderFontFaceCss,
12
- renderFontHead,
13
- renderFontPreloads,
14
- } from './fonts';
15
- // Pagination view helpers — pure functions consumed by the
16
- // <Pagination> stx component (defaults/resources/components/Pagination.stx).
17
- // stacksjs/stacks#1909 P5.
18
- export {
19
- buildPageSequence,
20
- paginatorVariant,
21
- urlForPage,
22
- } from './pagination';
package/dist/index.js DELETED
@@ -1,14 +0,0 @@
1
- import { ui } from "@stacksjs/config";
2
- import * as CssEngine from "@cwcss/crosswind";
3
-
4
- export { CssEngine, ui };
5
- export {
6
- renderFontFaceCss,
7
- renderFontHead,
8
- renderFontPreloads
9
- } from "./fonts";
10
- export {
11
- buildPageSequence,
12
- paginatorVariant,
13
- urlForPage
14
- } from "./pagination";
@@ -1,71 +0,0 @@
1
- /**
2
- * Build the page-number sequence for a full paginator, inserting an
3
- * ellipsis placeholder (`'…'`) for the gap between page 1 / the
4
- * current-page window / the last page.
5
- *
6
- * Examples (window=2):
7
- *
8
- * current=5, last=12 → [1, '…', 3, 4, 5, 6, 7, '…', 12]
9
- * current=1, last=3 → [1, 2, 3] (window covers all)
10
- * current=1, last=1 → [] (single page → no UI)
11
- * current=5, last=5 → [1, 2, 3, 4, 5] (last is current, no trailing ellipsis)
12
- *
13
- * Always anchors the sequence with `1` and `last_page` (when they
14
- * exist and differ from the current window) so users always have a
15
- * "jump to start" / "jump to end" affordance.
16
- *
17
- * @param current 1-indexed current page
18
- * @param last 1-indexed last page (`Paginator.last_page`)
19
- * @param window Number of neighbors on EACH side of `current` to
20
- * show before the ellipsis kicks in. Default 2 gives
21
- * the canonical compact shape.
22
- */
23
- export declare function buildPageSequence(current: number, last: number, window?: number): Array<number | '…'>;
24
- /**
25
- * Compute the URL for a specific page number, re-templating the
26
- * `page=N` parameter on whichever existing paginator URL is present.
27
- * Preserves all other query params (search filters, sort, etc.) — the
28
- * URLs filled in by `enrichPaginatorUrls()` (P2) already carry them,
29
- * so the re-template just swaps the page number.
30
- *
31
- * Falls back to `?page=N` when no template URL is available — covers
32
- * the case where the paginator was built outside a request scope (CLI
33
- * / queue / cron) and rendered via a non-default view; produces a
34
- * relative link that still works against the active page.
35
- */
36
- export declare function urlForPage(view: PaginatorView, page: number): string;
37
- /**
38
- * Classify a paginator instance by shape so the view picks the right
39
- * UI variant. Returns one of `'full'` / `'simple'` / `'cursor'` based
40
- * on which fields are present. This mirrors `isPaginator` /
41
- * `isSimplePaginator` / `isCursorPaginator` in `@stacksjs/orm` but
42
- * lives here so the view layer doesn't need to import the orm.
43
- */
44
- export declare function paginatorVariant(p: unknown): 'full' | 'simple' | 'cursor' | 'unknown';
45
- /**
46
- * Pagination view helpers (stacksjs/stacks#1909, P5 from #1910).
47
- *
48
- * Pure functions consumed by the `<Pagination>` stx component
49
- * (`defaults/resources/components/Pagination.stx`). Extracted here so
50
- * the page-sequence + URL-templating logic is unit-testable independent
51
- * of the stx render pipeline, and so apps that want to roll their own
52
- * pagination UI can reuse the same algorithms.
53
- *
54
- * The functions operate on the canonical paginator shapes from
55
- * `@stacksjs/orm` (Paginator / SimplePaginator / CursorPaginator), but
56
- * accept any duck-typed object with the right fields so callers don't
57
- * need a runtime import dependency on the orm module just to format
58
- * page numbers.
59
- */
60
- /**
61
- * Subset of {@link Paginator} fields that the view-side helpers actually
62
- * touch. Keeping this minimal keeps the helper decoupled from the orm.
63
- */
64
- export declare interface PaginatorView {
65
- current_page?: number
66
- last_page?: number
67
- prev_page_url?: string | null
68
- next_page_url?: string | null
69
- first_page_url?: string
70
- last_page_url?: string
71
- }
@@ -1,40 +0,0 @@
1
- export function buildPageSequence(current, last, window = 2) {
2
- if (last <= 1)
3
- return [];
4
- const out = [], lo = Math.max(2, current - window), hi = Math.min(last - 1, current + window);
5
- out.push(1);
6
- if (lo === 3)
7
- out.push(2);
8
- else if (lo > 3)
9
- out.push("\u2026");
10
- for (let i = lo;i <= hi; i++)
11
- out.push(i);
12
- if (hi === last - 2)
13
- out.push(last - 1);
14
- else if (hi < last - 2)
15
- out.push("\u2026");
16
- if (last > 1)
17
- out.push(last);
18
- return out;
19
- }
20
- export function urlForPage(view, page) {
21
- const template = view.next_page_url || view.prev_page_url || view.first_page_url || view.last_page_url;
22
- if (template) {
23
- if (/[?&]page=\d+/.test(template))
24
- return template.replace(/([?&])page=\d+/, `$1page=${page}`);
25
- return `${template}${template.includes("?") ? "&" : "?"}page=${page}`;
26
- }
27
- return `?page=${page}`;
28
- }
29
- export function paginatorVariant(p) {
30
- if (p === null || typeof p !== "object")
31
- return "unknown";
32
- const v = p;
33
- if ("next_cursor" in v)
34
- return "cursor";
35
- if ("total" in v && "last_page" in v)
36
- return "full";
37
- if ("current_page" in v && "per_page" in v)
38
- return "simple";
39
- return "unknown";
40
- }