@nexub/tokens 5.8.0 → 5.9.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/bin/README.md CHANGED
@@ -16,6 +16,7 @@ npx nexub-migrate --rules logical-classes --ignore 'src/legacy/**'
16
16
  | `logical-classes` | `ml/mr` `pl/pr` `border-l/r` `rounded-l/r/tl/tr/bl/br` `text-left/right` → `ms/me` `ps/pe` `border-s/e` `rounded-s/e/ss/se/es/ee` `text-start/end`, keeping variants, `!` and `-`. `left-*`/`right-*` positions are reported only. |
17
17
  | `tw-animate` | Reports tailwindcss-animate classes (`animate-in`, `fade-in-0`, `zoom-in-95`, `slide-in-from-*` …). Use `nx-motion` / `nx-pop` / `nx-dialog` from `@nexub/themes/base`. |
18
18
  | `opacity-modifier` | Reports `bg-[var(--x)]/10` (Tailwind 3 emits nothing). `--fix` rewrites to `bg-[color-mix(in_srgb,var(--x)_10%,transparent)]`. |
19
+ | `keep-5-defaults` | **Opt-in** (`--rules keep-5-defaults`). Keeps 5.x behaviour on 6.0 by adding the defaults 6.0 changes as explicit props, in files that import from `@nexub/react`: `<Autocomplete>` without `mode` gets `mode="inline"`; `<DataTable>`/`<DataTableVirtual>` with `enableRowSelection` and no `selectionColumn` get `selectionColumn={false}`. Tags with a `{...spread}` are reported, not changed. |
19
20
  | `deprecated-components` | `@nexub/react` components removed in 3.0, in files that import from `@nexub/react`: `Banner`/`Callout` → `Alert`; `Tag` → `<Badge variant="soft">`; `StatusPill label="x"` → `<Badge variant="soft">x</Badge>`; `*Props` types renamed; imports deduped; aliases (`Tag as T`) keep their local name. Reported only: `StatusPill dot`, `*Variants`, and uses outside JSX (`typeof Banner`, `styled(Tag)`). |
20
21
 
21
22
  **Where classes are looked for.** `.html`/`.mdx`: `class=`/`className=` attributes. `.css`/`.scss`: `@apply`.
@@ -6,7 +6,10 @@ import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { parseArgs } from 'node:util';
8
8
 
9
- export const RULES = ['legacy-tokens', 'logical-classes', 'tw-animate', 'opacity-modifier', 'deprecated-components', 'tailwind-3-preset'];
9
+ export const RULES = ['legacy-tokens', 'logical-classes', 'tw-animate', 'opacity-modifier', 'deprecated-components', 'tailwind-3-preset', 'keep-5-defaults'];
10
+ // Run only when asked for by --rules: they keep old behaviour instead of moving code forward.
11
+ const OPT_IN = new Set(['keep-5-defaults']);
12
+ export const DEFAULT_RULES = RULES.filter((r) => !OPT_IN.has(r));
10
13
  const EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.css', '.scss', '.html', '.mdx']);
11
14
  const SKIP_DIRS = new Set(['node_modules', 'dist', 'build', '.next', 'out', 'coverage']);
12
15
  const MAX_BYTES = 1024 * 1024;
@@ -373,12 +376,45 @@ function migrateComponents(src) {
373
376
  return { output, items };
374
377
  }
375
378
 
379
+ // ─── keep-5-defaults (opt-in): pin the defaults 6.0 changes ──────────────────
380
+ // Adds the 5.x value as an explicit prop, so upgrading to 6.0 changes nothing.
381
+ const selection = (a) => (a.enableRowSelection && !a.selectionColumn ? ' selectionColumn={false}' : null);
382
+ const PINS = {
383
+ Autocomplete: (a) => (a.mode ? null : ' mode="inline"'),
384
+ DataTable: selection,
385
+ DataTableVirtual: selection,
386
+ };
387
+
388
+ function pinDefaults(src) {
389
+ const edits = [];
390
+ const items = [];
391
+ const locals = new Map(); // local JSX name -> exported name
392
+ for (const m of src.matchAll(/\bimport\s+\{([^}]*)\}\s*from\s*(['"])@nexub\/react(?:\/\w+)?\2/g)) {
393
+ for (const [, name, alias] of m[1].matchAll(/\b(\w+)(?:\s+as\s+(\w+))?/g)) if (PINS[name]) locals.set(alias ?? name, name);
394
+ }
395
+ for (const [local, name] of locals) {
396
+ for (const m of src.matchAll(new RegExp(`<${local}(?![\\w.$-])`, 'g'))) {
397
+ const at = m.index + m[0].length;
398
+ const tag = readTag(src, at);
399
+ const report = (message) => items.push({ line: src.slice(0, m.index).split('\n').length, rule: 'keep-5-defaults', message });
400
+ if (!tag) { report(`<${local}>: could not parse the tag; check its 6.0 defaults by hand`); continue; }
401
+ const pin = PINS[name](Object.fromEntries(tag.attrs.map((a) => [a.name, a])));
402
+ if (!pin) continue;
403
+ if (src.slice(at, tag.end).includes('{...')) { report(`<${local} {...spread}>: add${pin} unless the spread sets it`); continue; }
404
+ edits.push({ at, text: pin });
405
+ }
406
+ }
407
+ let output = src;
408
+ for (const e of edits.sort((a, b) => b.at - a.at)) output = output.slice(0, e.at) + e.text + output.slice(e.at);
409
+ return { output, items };
410
+ }
411
+
376
412
  // ─── per-file migration ──────────────────────────────────────────────────────
377
413
  /**
378
414
  * Migrate one file's text. Returns { output, manual: [{ line, rule, message }] }.
379
415
  * opts: { ext, rules: Set, fix: boolean, aliasMap: { aliases, mix } }
380
416
  */
381
- export function migrateSource(src, { ext, rules = new Set(RULES), fix = false, aliasMap = SNAPSHOT }) {
417
+ export function migrateSource(src, { ext, rules = new Set(DEFAULT_RULES), fix = false, aliasMap = SNAPSHOT }) {
382
418
  const items = [];
383
419
  let text = src;
384
420
  if (['logical-classes', 'tw-animate', 'opacity-modifier', 'legacy-tokens'].some((r) => rules.has(r))) {
@@ -404,6 +440,11 @@ export function migrateSource(src, { ext, rules = new Set(RULES), fix = false, a
404
440
  text = r.output;
405
441
  items.push(...r.items);
406
442
  }
443
+ if (rules.has('keep-5-defaults') && COMPONENT_EXTS.has(ext) && /@nexub\/react['"/]/.test(text)) {
444
+ const r = pinDefaults(text);
445
+ text = r.output;
446
+ items.push(...r.items);
447
+ }
407
448
  if (rules.has('tailwind-3-preset')) {
408
449
  // Report only: moving a tailwind.config preset to CSS-first Tailwind 4 is a config change, not a rewrite.
409
450
  for (const m of src.matchAll(/['"]@nexub\/tokens\/tailwind['"]/g))
@@ -452,7 +493,7 @@ Options:
452
493
  --check exit 1 if anything fixable or reportable is found (CI)
453
494
  --json print machine-readable results
454
495
  --fix also rewrite opacity-modifier hits (preview, or apply with --write)
455
- --rules <a,b> run only these rules (default: all)
496
+ --rules <a,b> run only these rules (default: all except keep-5-defaults)
456
497
  --ignore <glob> skip paths matching glob (repeatable; supports * and **)
457
498
  -h, --help show this help
458
499
 
@@ -471,6 +512,9 @@ Rules:
471
512
  (dot and non-JSX uses reported); *Props types renamed
472
513
  tailwind-3-preset report the Tailwind 3 preset (@nexub/tokens/tailwind), removed in 4.0;
473
514
  use Tailwind 4 with @import "@nexub/tokens/tailwind.css"
515
+ keep-5-defaults opt-in: keep 5.x behaviour on 6.0 by pinning the defaults it changes:
516
+ <Autocomplete> gets mode="inline"; <DataTable enableRowSelection>
517
+ gets selectionColumn={false}
474
518
 
475
519
  Ignored: node_modules, dist, build, .next, out, coverage, files over 1 MB.
476
520
  Exit codes: 0 ok, 1 --check found something, 2 usage error.`;
@@ -492,7 +536,7 @@ export function run(argv, { cwd = process.cwd(), stdout = (s) => process.stdout.
492
536
  }
493
537
  const { values: o, positionals } = args;
494
538
  if (o.help) { stdout(`${USAGE}\n`); return 0; }
495
- const rules = new Set(o.rules ? o.rules.split(',').map((r) => r.trim()).filter(Boolean) : RULES);
539
+ const rules = new Set(o.rules ? o.rules.split(',').map((r) => r.trim()).filter(Boolean) : DEFAULT_RULES);
496
540
  const unknown = [...rules].filter((r) => !RULES.includes(r));
497
541
  if (unknown.length) { stderr(`Unknown rule(s): ${unknown.join(', ')}. Known: ${RULES.join(', ')}\n`); return 2; }
498
542
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexub/tokens",
3
- "version": "5.8.0",
3
+ "version": "5.9.0",
4
4
  "description": "Design tokens for Nexub Design System — colours, typography, spacing, radii, shadows, and motion as CSS variables, a Tailwind 4 theme, Figma variables and native (React Native, SwiftUI, Compose) tokens.",
5
5
  "type": "module",
6
6
  "license": "MIT",