cursedbelt 5.10.0 → 5.10.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.
@@ -25,6 +25,6 @@ const DEFAULT_ICON = {
25
25
  export function Alert({ tone = 'info', title, icon, actions, onDismiss, dismissLabel = 'Dismiss', className, children, }) {
26
26
  return (_jsxs("div", {
27
27
  // Errors are assertive (`alert`); the rest are polite live regions (`status`).
28
- role: tone === 'error' ? 'alert' : 'status', className: cn('flex gap-3 rounded-lg border p-4', TONE[tone], className), children: [icon !== false && (_jsx("span", { className: 'alert-icon mt-0.5 shrink-0 [&_svg]:size-4', children: icon ?? DEFAULT_ICON[tone] })), _jsxs("div", { className: 'flex min-w-0 flex-1 flex-col gap-1', children: [title && _jsx("p", { className: 'text-sm font-medium text-foreground', children: title }), children && _jsx("div", { className: 'text-sm text-muted-foreground', children: children }), actions && _jsx("div", { className: 'mt-2 flex flex-wrap gap-2', children: actions })] }), onDismiss && (_jsx(IconButton, { label: dismissLabel, onClick: onDismiss, className: 'alert-icon h-auto min-h-0 w-auto shrink-0 rounded p-0.5 text-current hover:opacity-70 hover:bg-transparent [&_svg]:size-4', children: _jsx(X, {}) }))] }));
28
+ role: tone === 'error' ? 'alert' : 'status', className: cn('flex gap-3 rounded-lg border p-4', TONE[tone], className), children: [icon !== false && (_jsx("span", { className: 'alert-icon mt-0.5 shrink-0 [&_svg]:size-4', children: icon ?? DEFAULT_ICON[tone] })), _jsxs("div", { className: 'flex min-w-0 flex-1 flex-col gap-1', children: [title && _jsx("p", { className: 'wrap-anywhere text-sm font-medium text-foreground', children: title }), children && _jsx("div", { className: 'wrap-anywhere text-sm text-muted-foreground', children: children }), actions && _jsx("div", { className: 'mt-2 flex flex-wrap gap-2', children: actions })] }), onDismiss && (_jsx(IconButton, { label: dismissLabel, onClick: onDismiss, className: 'alert-icon h-auto min-h-0 w-auto shrink-0 rounded p-0.5 text-current hover:opacity-70 hover:bg-transparent [&_svg]:size-4', children: _jsx(X, {}) }))] }));
29
29
  }
30
30
  //# sourceMappingURL=Alert.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../../src/react/components/Alert.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,IAAI,GAAG;IACX,IAAI,EAAE,0DAA0D;IAChE,OAAO,EAAE,6DAA6D;IACtE,OAAO,EAAE,6DAA6D;IACtE,KAAK,EAAE,yEAAyE;IAChF,KAAK,EAAE,8DAA8D;CAC7D,CAAC;AAIX,MAAM,YAAY,GAAiC;IACjD,IAAI,EAAE,KAAC,IAAI,KAAG;IACd,OAAO,EAAE,KAAC,WAAW,KAAG;IACxB,OAAO,EAAE,KAAC,aAAa,KAAG;IAC1B,KAAK,EAAE,KAAC,OAAO,KAAG;IAClB,KAAK,EAAE,KAAC,IAAI,KAAG;CAChB,CAAC;AAmBF,MAAM,UAAU,KAAK,CAAC,EACpB,IAAI,GAAG,MAAM,EACb,KAAK,EACL,IAAI,EACJ,OAAO,EACP,SAAS,EACT,YAAY,GAAG,SAAS,EACxB,SAAS,EACT,QAAQ,GACG;IACX,OAAO,CACL;QACE,+EAA+E;QAC/E,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAC3C,SAAS,EAAE,EAAE,CAAC,kCAAkC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,aAEvE,IAAI,KAAK,KAAK,IAAI,CACjB,eAAM,SAAS,EAAC,2CAA2C,YACxD,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,GACtB,CACR,EACD,eAAK,SAAS,EAAC,oCAAoC,aAChD,KAAK,IAAI,YAAG,SAAS,EAAC,qCAAqC,YAAE,KAAK,GAAK,EACvE,QAAQ,IAAI,cAAK,SAAS,EAAC,+BAA+B,YAAE,QAAQ,GAAO,EAC3E,OAAO,IAAI,cAAK,SAAS,EAAC,2BAA2B,YAAE,OAAO,GAAO,IAClE,EACL,SAAS,IAAI,CACZ,KAAC,UAAU,IACT,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,SAAS,EAClB,SAAS,EAAC,2HAA2H,YAErI,KAAC,CAAC,KAAG,GACM,CACd,IACG,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Alert.js","sourceRoot":"","sources":["../../../src/react/components/Alert.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,IAAI,GAAG;IACX,IAAI,EAAE,0DAA0D;IAChE,OAAO,EAAE,6DAA6D;IACtE,OAAO,EAAE,6DAA6D;IACtE,KAAK,EAAE,yEAAyE;IAChF,KAAK,EAAE,8DAA8D;CAC7D,CAAC;AAIX,MAAM,YAAY,GAAiC;IACjD,IAAI,EAAE,KAAC,IAAI,KAAG;IACd,OAAO,EAAE,KAAC,WAAW,KAAG;IACxB,OAAO,EAAE,KAAC,aAAa,KAAG;IAC1B,KAAK,EAAE,KAAC,OAAO,KAAG;IAClB,KAAK,EAAE,KAAC,IAAI,KAAG;CAChB,CAAC;AAmBF,MAAM,UAAU,KAAK,CAAC,EACpB,IAAI,GAAG,MAAM,EACb,KAAK,EACL,IAAI,EACJ,OAAO,EACP,SAAS,EACT,YAAY,GAAG,SAAS,EACxB,SAAS,EACT,QAAQ,GACG;IACX,OAAO,CACL;QACE,+EAA+E;QAC/E,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAC3C,SAAS,EAAE,EAAE,CAAC,kCAAkC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,aAEvE,IAAI,KAAK,KAAK,IAAI,CACjB,eAAM,SAAS,EAAC,2CAA2C,YACxD,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,GACtB,CACR,EACD,eAAK,SAAS,EAAC,oCAAoC,aAChD,KAAK,IAAI,YAAG,SAAS,EAAC,mDAAmD,YAAE,KAAK,GAAK,EACrF,QAAQ,IAAI,cAAK,SAAS,EAAC,6CAA6C,YAAE,QAAQ,GAAO,EACzF,OAAO,IAAI,cAAK,SAAS,EAAC,2BAA2B,YAAE,OAAO,GAAO,IAClE,EACL,SAAS,IAAI,CACZ,KAAC,UAAU,IACT,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,SAAS,EAClB,SAAS,EAAC,2HAA2H,YAErI,KAAC,CAAC,KAAG,GACM,CACd,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -12,6 +12,6 @@ export function Section({ title, description, actions, variant = 'plain', childr
12
12
  const card = variant === 'card';
13
13
  return (_jsxs("section", { className: cn('flex flex-col', card ? 'gap-3 rounded-lg border border-border bg-muted/20 p-3 sm:p-4' : 'gap-4', className), ...rest, children: [hasHeader && (_jsxs(Split, { children: [_jsxs("div", { className: 'min-w-0', children: [title && (_jsx("h2", { className: cn(card
14
14
  ? 'text-xs font-semibold uppercase tracking-wide text-muted-foreground'
15
- : 'text-base font-semibold text-foreground'), children: title })), description && (_jsx("p", { className: cn('mt-0.5 text-muted-foreground', card ? 'text-xs' : 'text-sm'), children: description }))] }), actions && _jsx("div", { className: 'flex items-center gap-2', children: actions })] })), children] }));
15
+ : 'text-base font-semibold text-foreground'), children: title })), description && (_jsx("p", { className: cn('mt-0.5 wrap-anywhere text-muted-foreground', card ? 'text-xs' : 'text-sm'), children: description }))] }), actions && _jsx("div", { className: 'flex items-center gap-2', children: actions })] })), children] }));
16
16
  }
17
17
  //# sourceMappingURL=Section.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Section.js","sourceRoot":"","sources":["../../../src/react/components/Section.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA6BpC;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,EACtB,KAAK,EACL,WAAW,EACX,OAAO,EACP,OAAO,GAAG,OAAO,EACjB,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACM;IACb,MAAM,SAAS,GAAG,KAAK,IAAI,WAAW,IAAI,OAAO,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,KAAK,MAAM,CAAC;IAChC,OAAO,CACL,mBACE,SAAS,EAAE,EAAE,CACX,eAAe,EACf,IAAI,CAAC,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC,OAAO,EAC/E,SAAS,CACV,KACG,IAAI,aAEP,SAAS,IAAI,CACZ,MAAC,KAAK,eACJ,eAAK,SAAS,EAAC,SAAS,aACrB,KAAK,IAAI,CACR,aACE,SAAS,EAAE,EAAE,CACX,IAAI;oCACF,CAAC,CAAC,qEAAqE;oCACvE,CAAC,CAAC,yCAAyC,CAC9C,YAEA,KAAK,GACH,CACN,EACA,WAAW,IAAI,CACd,YAAG,SAAS,EAAE,EAAE,CAAC,8BAA8B,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,YAC3E,WAAW,GACV,CACL,IACG,EACL,OAAO,IAAI,cAAK,SAAS,EAAC,yBAAyB,YAAE,OAAO,GAAO,IAC9D,CACT,EACA,QAAQ,IACD,CACX,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Section.js","sourceRoot":"","sources":["../../../src/react/components/Section.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AA6BpC;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,EACtB,KAAK,EACL,WAAW,EACX,OAAO,EACP,OAAO,GAAG,OAAO,EACjB,QAAQ,EACR,SAAS,EACT,GAAG,IAAI,EACM;IACb,MAAM,SAAS,GAAG,KAAK,IAAI,WAAW,IAAI,OAAO,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,KAAK,MAAM,CAAC;IAChC,OAAO,CACL,mBACE,SAAS,EAAE,EAAE,CACX,eAAe,EACf,IAAI,CAAC,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC,OAAO,EAC/E,SAAS,CACV,KACG,IAAI,aAEP,SAAS,IAAI,CACZ,MAAC,KAAK,eACJ,eAAK,SAAS,EAAC,SAAS,aACrB,KAAK,IAAI,CACR,aACE,SAAS,EAAE,EAAE,CACX,IAAI;oCACF,CAAC,CAAC,qEAAqE;oCACvE,CAAC,CAAC,yCAAyC,CAC9C,YAEA,KAAK,GACH,CACN,EACA,WAAW,IAAI,CACd,YAAG,SAAS,EAAE,EAAE,CAAC,4CAA4C,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,YACzF,WAAW,GACV,CACL,IACG,EACL,OAAO,IAAI,cAAK,SAAS,EAAC,yBAAyB,YAAE,OAAO,GAAO,IAC9D,CACT,EACA,QAAQ,IACD,CACX,CAAC;AACJ,CAAC"}
@@ -15,7 +15,7 @@
15
15
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
16
16
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
17
17
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
18
- * 706 candidate(s).
18
+ * 707 candidate(s).
19
19
  *
20
20
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
21
21
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -142,8 +142,8 @@
142
142
  @source inline("translate-x-1/2 translate-y-1/2 truncate under underline underline-offset-4 up uppercase v");
143
143
  @source inline("visible w-1 w-1/3 w-10 w-16 w-2.5 w-24 w-3/4 w-4 w-6 w-7 w-8 w-9 w-[3px] w-[calc(100vw-2rem)]");
144
144
  @source inline("w-[var(--control-h-lg)] w-[var(--control-h-md)] w-[var(--control-h-sm)] w-auto w-full w-px white");
145
- @source inline("whitespace-nowrap whitespace-pre-wrap wrap wrap-break-word z z-10 z-20 z-30 z-40 z-50");
146
- @source inline("z-[var(--z-popover)]");
145
+ @source inline("whitespace-nowrap whitespace-pre-wrap wrap wrap-anywhere wrap-break-word z z-10 z-20 z-30 z-40");
146
+ @source inline("z-50 z-[var(--z-popover)]");
147
147
 
148
148
  /*
149
149
  * Theme variables cursedbelt's components read BY NAME (`var(--color-card)` in a style prop).
@@ -2602,6 +2602,9 @@
2602
2602
  .break-words {
2603
2603
  overflow-wrap: break-word;
2604
2604
  }
2605
+ .wrap-anywhere {
2606
+ overflow-wrap: anywhere;
2607
+ }
2605
2608
  .wrap-break-word {
2606
2609
  overflow-wrap: break-word;
2607
2610
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursedbelt",
3
- "version": "5.10.0",
3
+ "version": "5.10.1",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "description": "The React design system of the cursedbelt split — components, styles, theme. cursedbelt-core below it; server tier in cursedbelt-server.",
@@ -798,7 +798,8 @@
798
798
  "needs": [
799
799
  "styles"
800
800
  ],
801
- "why": "stylesStaticMatches / stylesUtilitiesMatches read those two files and assert they are current"
801
+ "why": "stylesStaticMatches / stylesUtilitiesMatches read those two files and assert they are current",
802
+ "timeoutSec": 300
802
803
  },
803
804
  {
804
805
  "script": "e2e",
@@ -52,4 +52,16 @@ describe('Alert', () => {
52
52
  expect(getByRole('button', { name: 'Undo' })).toBeDefined();
53
53
  expect(getByRole('button', { name: 'Dismiss' })).toBeDefined();
54
54
  });
55
+ /**
56
+ * A path has no break in it. Station's warning carried `/…/…` and widened the whole page on
57
+ * a 390px phone (2026-09-26); `wrap-anywhere` is the one wrap that also lowers the text's
58
+ * min-content width inside a flex row, which `break-words` does not.
59
+ */
60
+ test('the title and body may break anywhere, so a path cannot widen the page', () => {
61
+ const { container } = render(<Alert title='/a/very/long/path'>/another/very/long/path</Alert>);
62
+ const title = [...container.querySelectorAll('p')].find((p) => p.textContent === '/a/very/long/path');
63
+ expect(title?.className).toContain('wrap-anywhere');
64
+ const body = [...container.querySelectorAll('div')].find((d) => d.textContent === '/another/very/long/path');
65
+ expect(body?.className).toContain('wrap-anywhere');
66
+ });
55
67
  });
@@ -66,8 +66,8 @@ export function Alert({
66
66
  </span>
67
67
  )}
68
68
  <div className='flex min-w-0 flex-1 flex-col gap-1'>
69
- {title && <p className='text-sm font-medium text-foreground'>{title}</p>}
70
- {children && <div className='text-sm text-muted-foreground'>{children}</div>}
69
+ {title && <p className='wrap-anywhere text-sm font-medium text-foreground'>{title}</p>}
70
+ {children && <div className='wrap-anywhere text-sm text-muted-foreground'>{children}</div>}
71
71
  {actions && <div className='mt-2 flex flex-wrap gap-2'>{actions}</div>}
72
72
  </div>
73
73
  {onDismiss && (
@@ -61,4 +61,10 @@ describe('Section', () => {
61
61
  cleanup();
62
62
  }
63
63
  });
64
+ /** See Alert.spec: a path in a description widened station's page on a 390px phone. */
65
+ test('the description may break anywhere, so a path cannot widen the page', () => {
66
+ const { container } = render(<Section title='Files' description='/a/very/long/path'>body</Section>);
67
+ const description = [...container.querySelectorAll('p')].find((p) => p.textContent === '/a/very/long/path');
68
+ expect(description?.className).toContain('wrap-anywhere');
69
+ });
64
70
  });
@@ -70,7 +70,7 @@ export function Section({
70
70
  </h2>
71
71
  )}
72
72
  {description && (
73
- <p className={cn('mt-0.5 text-muted-foreground', card ? 'text-xs' : 'text-sm')}>
73
+ <p className={cn('mt-0.5 wrap-anywhere text-muted-foreground', card ? 'text-xs' : 'text-sm')}>
74
74
  {description}
75
75
  </p>
76
76
  )}
@@ -15,7 +15,7 @@
15
15
  * after an app's responsive variant (task 2124). An app that imports every area gets exactly
16
16
  * what `cursedbelt/styles-utilities.css` emits — proved rule by rule in
17
17
  * src/stylesAreas.spec.ts, which is also what fails when this file is stale.
18
- * 706 candidate(s).
18
+ * 707 candidate(s).
19
19
  *
20
20
  * Written by scripts/generateAreaStyles.ts (`bun run styles:areas`), which
21
21
  * `bun run build` runs. The map of what is in which area, and why the areas are
@@ -142,8 +142,8 @@
142
142
  @source inline("translate-x-1/2 translate-y-1/2 truncate under underline underline-offset-4 up uppercase v");
143
143
  @source inline("visible w-1 w-1/3 w-10 w-16 w-2.5 w-24 w-3/4 w-4 w-6 w-7 w-8 w-9 w-[3px] w-[calc(100vw-2rem)]");
144
144
  @source inline("w-[var(--control-h-lg)] w-[var(--control-h-md)] w-[var(--control-h-sm)] w-auto w-full w-px white");
145
- @source inline("whitespace-nowrap whitespace-pre-wrap wrap wrap-break-word z z-10 z-20 z-30 z-40 z-50");
146
- @source inline("z-[var(--z-popover)]");
145
+ @source inline("whitespace-nowrap whitespace-pre-wrap wrap wrap-anywhere wrap-break-word z z-10 z-20 z-30 z-40");
146
+ @source inline("z-50 z-[var(--z-popover)]");
147
147
 
148
148
  /*
149
149
  * Theme variables cursedbelt's components read BY NAME (`var(--color-card)` in a style prop).
@@ -2602,6 +2602,9 @@
2602
2602
  .break-words {
2603
2603
  overflow-wrap: break-word;
2604
2604
  }
2605
+ .wrap-anywhere {
2606
+ overflow-wrap: anywhere;
2607
+ }
2605
2608
  .wrap-break-word {
2606
2609
  overflow-wrap: break-word;
2607
2610
  }
@@ -29,16 +29,44 @@
29
29
  */
30
30
  import { describe, expect, it } from 'bun:test';
31
31
  import { spawnSync } from 'node:child_process';
32
- import { dirname, relative, resolve } from 'node:path';
32
+ import { type Dirent, readdirSync } from 'node:fs';
33
+ import { dirname, join, relative, resolve } from 'node:path';
33
34
 
34
35
  const ROOT = resolve(import.meta.dir, '..');
35
36
 
36
- /** Every tsconfig this repo owns. Globbed, so a new one is covered the day it lands. */
37
+ /** Directories that hold no tsconfig this repo owns, and are never walked. */
38
+ const SKIP_DIRS = new Set(['node_modules', 'dist', 'dist.next', 'test-results']);
39
+
40
+ /**
41
+ * Every tsconfig this repo owns. Walked, so a new one is covered the day it lands.
42
+ *
43
+ * 🔴 NOT `new Bun.Glob('**…').scanSync` filtered afterwards (2026-09-26). That walked all of
44
+ * `node_modules` and every scratch directory, and the gate runs this file beside `e2e`, whose
45
+ * Playwright rewrites `test-results/` as it goes: a directory removed mid-scan threw at module
46
+ * load, and the whole file reported as "unhandled between tests" — twice in a row in one
47
+ * batch, never alone. This never descends into a skipped or dot directory, and a directory that
48
+ * vanishes while being read is simply not there.
49
+ */
37
50
  function projectPaths(): string[] {
38
- const glob = new Bun.Glob('**/tsconfig*.json');
39
- return [...glob.scanSync({ cwd: ROOT, absolute: true })]
40
- .filter((p) => !p.includes(`${ROOT}/node_modules`) && !p.includes('/dist'))
41
- .sort();
51
+ const found: string[] = [];
52
+ const walk = (dir: string): void => {
53
+ let entries: Dirent[];
54
+ try {
55
+ entries = readdirSync(dir, { withFileTypes: true });
56
+ } catch (err) {
57
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') return;
58
+ throw err;
59
+ }
60
+ for (const entry of entries) {
61
+ if (entry.isDirectory()) {
62
+ if (!entry.name.startsWith('.') && !SKIP_DIRS.has(entry.name)) walk(join(dir, entry.name));
63
+ } else if (/^tsconfig.*\.json$/.test(entry.name)) {
64
+ found.push(join(dir, entry.name));
65
+ }
66
+ }
67
+ };
68
+ walk(ROOT);
69
+ return found.sort();
42
70
  }
43
71
 
44
72
  interface Resolved {