@barefootjs/cli 0.12.0 → 0.13.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.
@@ -18,6 +18,11 @@ Scaffold a BarefootJS app, run it locally, and tour the generated project. About
18
18
 
19
19
  Press Enter at the prompts to accept the defaults (Hono on Cloudflare Workers, UnoCSS).
20
20
 
21
+ The CSS prompt has two options:
22
+
23
+ - **UnoCSS** (default) — wires up UnoCSS and pulls a starter `<Button>` from the BarefootJS UI registry. The rest of this guide follows this path.
24
+ - **None (bring your own CSS)** — no UnoCSS, no UI components, no stylesheets. You get just the JSX→template+signals compiler output and a dependency-free starter `Counter` built from native `<button>` elements. Pick this when you want to wire up your own styling. Pass `--css none` to select it non-interactively.
25
+
21
26
  ## 2. Install and run
22
27
 
23
28
  ```bash
package/dist/index.js CHANGED
@@ -24837,10 +24837,12 @@ function buildGitignore(sections) {
24837
24837
  lines.push(...SHARED_GITIGNORE_LINES);
24838
24838
  return lines.join("\n") + "\n";
24839
24839
  }
24840
- var SHARED_COUNTER_TSX, SHARED_COUNTER_TEST_TSX, TOKENS_CSS, STYLES_CSS, UNO_CSS_PLACEHOLDER, COMPONENTS_MANIFEST_SEED, UNOCSS_DEV_DEPENDENCIES, SHARED_GITIGNORE_LINES;
24840
+ var CSS_LINKS_BEGIN, CSS_LINKS_END, SHARED_COUNTER_TSX, SHARED_COUNTER_TEST_TSX, SHARED_COUNTER_BARE_TSX, SHARED_COUNTER_BARE_TEST_TSX, TOKENS_CSS, STYLES_CSS, UNO_CSS_PLACEHOLDER, COMPONENTS_MANIFEST_SEED, UNOCSS_DEV_DEPENDENCIES, SHARED_GITIGNORE_LINES;
24841
24841
  var init_shared2 = __esm({
24842
24842
  "src/lib/adapters/shared.ts"() {
24843
24843
  "use strict";
24844
+ CSS_LINKS_BEGIN = "@@BF_CSS_LINKS_BEGIN@@";
24845
+ CSS_LINKS_END = "@@BF_CSS_LINKS_END@@";
24844
24846
  SHARED_COUNTER_TSX = `'use client'
24845
24847
 
24846
24848
  import { createSignal, createMemo } from '@barefootjs/client'
@@ -24910,6 +24912,71 @@ describe('Counter', () => {
24910
24912
  expect(structure).toContain('div')
24911
24913
  })
24912
24914
  })
24915
+ `;
24916
+ SHARED_COUNTER_BARE_TSX = `'use client'
24917
+
24918
+ import { createSignal, createMemo } from '@barefootjs/client'
24919
+
24920
+ interface CounterProps {
24921
+ initial?: number
24922
+ }
24923
+
24924
+ export function Counter(props: CounterProps) {
24925
+ const [count, setCount] = createSignal(props.initial ?? 0)
24926
+ const doubled = createMemo(() => count() * 2)
24927
+
24928
+ return (
24929
+ <div className="counter">
24930
+ <p className="counter-value">count: {count()}</p>
24931
+ <p className="counter-doubled">doubled: {doubled()}</p>
24932
+ <div className="counter-buttons">
24933
+ <button type="button" onClick={() => setCount(n => n + 1)}>+1</button>
24934
+ <button type="button" onClick={() => setCount(n => n - 1)}>-1</button>
24935
+ <button type="button" onClick={() => setCount(0)}>Reset</button>
24936
+ </div>
24937
+ </div>
24938
+ )
24939
+ }
24940
+ `;
24941
+ SHARED_COUNTER_BARE_TEST_TSX = `import { describe, test, expect } from '{{__TEST_RUNNER_IMPORT__}}'
24942
+ import { readFileSync } from 'fs'
24943
+ import { resolve } from 'path'
24944
+ import { renderToTest } from '@barefootjs/test'
24945
+
24946
+ const CounterSource = readFileSync(resolve(__dirname, 'Counter.tsx'), 'utf-8')
24947
+
24948
+ describe('Counter', () => {
24949
+ const result = renderToTest(CounterSource, 'Counter.tsx')
24950
+
24951
+ test('has no compiler errors', () => {
24952
+ expect(result.errors).toEqual([])
24953
+ })
24954
+
24955
+ test('componentName is Counter', () => {
24956
+ expect(result.componentName).toBe('Counter')
24957
+ })
24958
+
24959
+ test('has expected signals', () => {
24960
+ expect(result.signals).toContain('count')
24961
+ })
24962
+
24963
+ test('renders as <div>', () => {
24964
+ expect(result.root.tag).toBe('div')
24965
+ })
24966
+
24967
+ test('has event handlers', () => {
24968
+ const all = result.findAll({})
24969
+ expect(
24970
+ all.some(n => n.events.includes('click') || n.props['onClick'] != null),
24971
+ ).toBe(true)
24972
+ })
24973
+
24974
+ test('toStructure() shows expected tree', () => {
24975
+ const structure = result.toStructure()
24976
+ expect(structure.length).toBeGreaterThan(0)
24977
+ expect(structure).toContain('div')
24978
+ })
24979
+ })
24913
24980
  `;
24914
24981
  TOKENS_CSS = `:root {
24915
24982
  /* \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
@@ -25392,6 +25459,7 @@ func defaultLayout(ctx *bf.RenderContext) string {
25392
25459
  <meta charset="utf-8" />
25393
25460
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
25394
25461
  <title>%s</title>
25462
+ ${CSS_LINKS_BEGIN}
25395
25463
  <!-- Link all three sheets so the browser fetches them in parallel \u2014
25396
25464
  chaining via styles.css @import would defer tokens/uno to a
25397
25465
  second round-trip and flash unstyled DOM. tokens first so its
@@ -25399,6 +25467,7 @@ func defaultLayout(ctx *bf.RenderContext) string {
25399
25467
  <link rel="stylesheet" href="/static/tokens.css" />
25400
25468
  <link rel="stylesheet" href="/static/styles.css" />
25401
25469
  <link rel="stylesheet" href="/static/uno.css" />
25470
+ ${CSS_LINKS_END}
25402
25471
  </head>
25403
25472
  <body>
25404
25473
  <main>%s</main>
@@ -25782,6 +25851,7 @@ server.listen(port, () => {
25782
25851
  <script type="importmap">
25783
25852
  { "imports": { "@barefootjs/client/runtime": "/static/components/barefoot.js" } }
25784
25853
  </script>
25854
+ ${CSS_LINKS_BEGIN}
25785
25855
  <!-- Link all three sheets so the browser fetches them in parallel \u2014
25786
25856
  chaining via styles.css @import would defer tokens/uno to a
25787
25857
  second round-trip and flash unstyled DOM. tokens first so its
@@ -25789,6 +25859,7 @@ server.listen(port, () => {
25789
25859
  <link rel="stylesheet" href="/static/tokens.css">
25790
25860
  <link rel="stylesheet" href="/static/styles.css">
25791
25861
  <link rel="stylesheet" href="/static/uno.css">
25862
+ ${CSS_LINKS_END}
25792
25863
  </head>
25793
25864
  <body>
25794
25865
  <main>
@@ -25981,6 +26052,7 @@ func defaultLayout(ctx *bf.RenderContext) string {
25981
26052
  <meta charset="utf-8" />
25982
26053
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
25983
26054
  <title>%s</title>
26055
+ ${CSS_LINKS_BEGIN}
25984
26056
  <!-- Link all three sheets so the browser fetches them in parallel \u2014
25985
26057
  chaining via styles.css @import would defer tokens/uno to a
25986
26058
  second round-trip and flash unstyled DOM. tokens first so its
@@ -25988,6 +26060,7 @@ func defaultLayout(ctx *bf.RenderContext) string {
25988
26060
  <link rel="stylesheet" href="/static/tokens.css" />
25989
26061
  <link rel="stylesheet" href="/static/styles.css" />
25990
26062
  <link rel="stylesheet" href="/static/uno.css" />
26063
+ ${CSS_LINKS_END}
25991
26064
  </head>
25992
26065
  <body>
25993
26066
  <main>%s</main>
@@ -26544,6 +26617,7 @@ export const renderer = jsxRenderer(({ children, title }) => (
26544
26617
  <meta charset="UTF-8" />
26545
26618
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26546
26619
  <title>{title ?? 'BarefootJS app'}</title>
26620
+ ${CSS_LINKS_BEGIN}
26547
26621
  {/* Link all three sheets so the browser fetches them in
26548
26622
  parallel \u2014 chaining via styles.css @import would defer
26549
26623
  tokens/uno to a second round-trip and flash unstyled DOM.
@@ -26552,6 +26626,7 @@ export const renderer = jsxRenderer(({ children, title }) => (
26552
26626
  <link rel="stylesheet" href="/tokens.css" />
26553
26627
  <link rel="stylesheet" href="/styles.css" />
26554
26628
  <link rel="stylesheet" href="/uno.css" />
26629
+ ${CSS_LINKS_END}
26555
26630
  <BfImportMap base={componentsBase} />
26556
26631
  </head>
26557
26632
  <body>
@@ -26837,6 +26912,7 @@ export function createRenderer({ componentsBase }: CreateRendererOptions) {
26837
26912
  <meta charset="UTF-8" />
26838
26913
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
26839
26914
  <title>{title ?? 'BarefootJS app'}</title>
26915
+ ${CSS_LINKS_BEGIN}
26840
26916
  {/* Link all three sheets so the browser fetches them in
26841
26917
  parallel \u2014 chaining via styles.css @import would defer
26842
26918
  tokens/uno to a second round-trip and flash unstyled
@@ -26845,6 +26921,7 @@ export function createRenderer({ componentsBase }: CreateRendererOptions) {
26845
26921
  <link rel="stylesheet" href="/static/tokens.css" />
26846
26922
  <link rel="stylesheet" href="/static/styles.css" />
26847
26923
  <link rel="stylesheet" href="/static/uno.css" />
26924
+ ${CSS_LINKS_END}
26848
26925
  <BfImportMap base={componentsBase} />
26849
26926
  </head>
26850
26927
  <body>
@@ -27058,6 +27135,7 @@ __DATA__
27058
27135
  <meta charset="utf-8">
27059
27136
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
27060
27137
  <title>BarefootJS app</title>
27138
+ ${CSS_LINKS_BEGIN}
27061
27139
  <!-- Link all three sheets so the browser fetches them in parallel \u2014
27062
27140
  chaining via styles.css @import would defer tokens/uno to a
27063
27141
  second round-trip and flash unstyled DOM. tokens first so its
@@ -27065,6 +27143,7 @@ __DATA__
27065
27143
  <link rel="stylesheet" href="/static/tokens.css">
27066
27144
  <link rel="stylesheet" href="/static/styles.css">
27067
27145
  <link rel="stylesheet" href="/static/uno.css">
27146
+ ${CSS_LINKS_END}
27068
27147
  </head>
27069
27148
  <body>
27070
27149
  <main><%== content %></main>
@@ -27451,11 +27530,13 @@ sub layout (%a) {
27451
27530
  <meta charset="utf-8">
27452
27531
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
27453
27532
  <title>BarefootJS app</title>
27533
+ ${CSS_LINKS_BEGIN}
27454
27534
  <!-- Link all three sheets so the browser fetches them in parallel.
27455
27535
  tokens first so its CSS variables exist before any rule uses them. -->
27456
27536
  <link rel="stylesheet" href="/static/tokens.css">
27457
27537
  <link rel="stylesheet" href="/static/styles.css">
27458
27538
  <link rel="stylesheet" href="/static/uno.css">
27539
+ ${CSS_LINKS_END}
27459
27540
  </head>
27460
27541
  <body>
27461
27542
  <main>$a{body}</main>
@@ -27695,7 +27776,8 @@ var init_templates = __esm({
27695
27776
  init_nethttp();
27696
27777
  init_xslate();
27697
27778
  CSS_LIBRARIES = {
27698
- unocss: { label: "UnoCSS" }
27779
+ unocss: { label: "UnoCSS", usesUnoUi: true },
27780
+ none: { label: "None (bring your own CSS)", usesUnoUi: false }
27699
27781
  };
27700
27782
  DEFAULT_CSS_LIBRARY = "unocss";
27701
27783
  ADAPTERS = {
@@ -27856,6 +27938,48 @@ var init_spinner = __esm({
27856
27938
  }
27857
27939
  });
27858
27940
 
27941
+ // src/lib/css.ts
27942
+ function processCssHead(content2, usesUno) {
27943
+ if (!content2.includes(CSS_LINKS_BEGIN)) return content2;
27944
+ const out = [];
27945
+ let inRegion = false;
27946
+ for (const line of content2.split("\n")) {
27947
+ const trimmed = line.trim();
27948
+ if (trimmed === CSS_LINKS_BEGIN) {
27949
+ inRegion = true;
27950
+ continue;
27951
+ }
27952
+ if (trimmed === CSS_LINKS_END) {
27953
+ inRegion = false;
27954
+ continue;
27955
+ }
27956
+ if (inRegion && !usesUno) continue;
27957
+ out.push(line);
27958
+ }
27959
+ return out.join("\n");
27960
+ }
27961
+ function stripUnocssFromScript(cmd) {
27962
+ let out = cmd;
27963
+ out = out.split(' "unocss --watch"').join("");
27964
+ out = out.replace("-n build,uno,server -c blue,magenta,green", "-n build,server -c blue,green");
27965
+ out = out.replace("-n build,uno -c blue,magenta", "-n build -c blue");
27966
+ out = out.split(" && unocss && ").join(" && ");
27967
+ out = out.replace(/ && unocss$/, "");
27968
+ return out;
27969
+ }
27970
+ function stripUnoGitignore(content2) {
27971
+ return content2.replace(
27972
+ "# UnoCSS output (regenerated by `unocss --watch` / `unocss`)\npublic/uno.css\n\n",
27973
+ ""
27974
+ );
27975
+ }
27976
+ var init_css = __esm({
27977
+ "src/lib/css.ts"() {
27978
+ "use strict";
27979
+ init_shared2();
27980
+ }
27981
+ });
27982
+
27859
27983
  // src/commands/init.ts
27860
27984
  var init_exports = {};
27861
27985
  __export(init_exports, {
@@ -27898,7 +28022,8 @@ async function run4(args2, ctx2) {
27898
28022
  const adapter = ADAPTERS[adapterId];
27899
28023
  const cssId = await resolveCssLibrary(flags.css);
27900
28024
  const cssLibrary = CSS_LIBRARIES[cssId];
27901
- const bundledComponents = adapter.bundledRegistryComponents ?? ["button"];
28025
+ const usesUno = cssLibrary.usesUnoUi !== false;
28026
+ const bundledComponents = usesUno ? adapter.bundledRegistryComponents ?? ["button"] : [];
27902
28027
  if (bundledComponents.length > 0) {
27903
28028
  const registryHost = new URL(DEFAULT_REGISTRY_URL2).host;
27904
28029
  const probeSpinner = startSpinner({
@@ -27929,7 +28054,7 @@ async function run4(args2, ctx2) {
27929
28054
  text: `Creating ${adapter.label.split(" ")[0]} + ${cssLibrary.label} project...`
27930
28055
  });
27931
28056
  try {
27932
- await scaffoldApp(projectDir, adapter, flags, ctx2);
28057
+ await scaffoldApp(projectDir, adapter, flags, usesUno, ctx2);
27933
28058
  } catch (err) {
27934
28059
  buildSpinner.fail("Failed to create project files");
27935
28060
  throw err;
@@ -27992,7 +28117,7 @@ async function probeRegistry(url2) {
27992
28117
  throw new Error(`HTTP ${res.status}`);
27993
28118
  }
27994
28119
  }
27995
- async function scaffoldApp(projectDir, adapter, flags, _ctx) {
28120
+ async function scaffoldApp(projectDir, adapter, flags, usesUno, _ctx) {
27996
28121
  const paths = {
27997
28122
  components: "components/ui",
27998
28123
  tokens: "tokens",
@@ -28004,11 +28129,20 @@ async function scaffoldApp(projectDir, adapter, flags, _ctx) {
28004
28129
  const pm = detectPackageManager(projectDir);
28005
28130
  const runner = testRunnerFor(pm);
28006
28131
  const pmTypesEntry = runner.typesEntry;
28132
+ const UNO_ONLY_FILES = /* @__PURE__ */ new Set(["uno.config.ts", "uno.css", "tokens.css", "styles.css"]);
28007
28133
  for (const [relPath, contents] of Object.entries(adapter.files)) {
28134
+ if (!usesUno && UNO_ONLY_FILES.has(path10.basename(relPath))) continue;
28008
28135
  const target2 = path10.join(projectDir, relPath);
28009
28136
  if (existsSync8(target2)) continue;
28010
28137
  mkdirSync3(path10.dirname(target2), { recursive: true });
28011
- const resolved = contents.replace(/\{\{__PROJECT_NAME__\}\}/g, pkgName).replace(/\{\{__PM_TYPES_ENTRY__\}\}/g, pmTypesEntry).replace(/\{\{__TEST_RUNNER_IMPORT__\}\}/g, runner.importSource);
28138
+ let source = contents;
28139
+ if (!usesUno && relPath === "components/Counter.tsx") source = SHARED_COUNTER_BARE_TSX;
28140
+ if (!usesUno && relPath === "components/Counter.test.tsx") source = SHARED_COUNTER_BARE_TEST_TSX;
28141
+ let resolved = source.replace(/\{\{__PROJECT_NAME__\}\}/g, pkgName).replace(/\{\{__PM_TYPES_ENTRY__\}\}/g, pmTypesEntry).replace(/\{\{__TEST_RUNNER_IMPORT__\}\}/g, runner.importSource);
28142
+ resolved = processCssHead(resolved, usesUno);
28143
+ if (!usesUno && path10.basename(relPath) === ".gitignore") {
28144
+ resolved = stripUnoGitignore(resolved);
28145
+ }
28012
28146
  writeFileSync3(target2, resolved);
28013
28147
  created++;
28014
28148
  }
@@ -28022,16 +28156,24 @@ async function scaffoldApp(projectDir, adapter, flags, _ctx) {
28022
28156
  const pkgJsonPath = path10.join(projectDir, "package.json");
28023
28157
  const resolvedAdapterScripts = {};
28024
28158
  for (const [k, v] of Object.entries(adapter.scripts)) {
28025
- resolvedAdapterScripts[k] = typeof v === "function" ? v(pm) : v;
28159
+ const rendered = typeof v === "function" ? v(pm) : v;
28160
+ resolvedAdapterScripts[k] = usesUno ? rendered : stripUnocssFromScript(rendered);
28026
28161
  }
28027
28162
  const pmDevDeps = runner.devDeps;
28163
+ const adapterDevDeps = { ...adapter.devDependencies };
28164
+ if (!usesUno) {
28165
+ for (const key of Object.keys(UNOCSS_DEV_DEPENDENCIES)) delete adapterDevDeps[key];
28166
+ }
28028
28167
  const pkgJson = {
28029
28168
  name: pkgName,
28030
28169
  private: true,
28031
28170
  type: "module",
28032
28171
  scripts: {
28033
28172
  ...resolvedAdapterScripts,
28034
- watch: 'concurrently -k -n build,uno -c blue,magenta "bf build --watch" "unocss --watch"',
28173
+ // The cross-adapter rebuild watcher. Under `--css none` there's no
28174
+ // `unocss --watch` pane to run alongside `bf build --watch`, so it
28175
+ // collapses to a bare build watch (no `concurrently` wrapper).
28176
+ watch: usesUno ? 'concurrently -k -n build,uno -c blue,magenta "bf build --watch" "unocss --watch"' : "bf build --watch",
28035
28177
  // `test` is wired to the runner that matches the user's package
28036
28178
  // manager — `bun test` for bun, `vitest run` for npm / pnpm /
28037
28179
  // yarn. The matching `bf gen component` / `bf gen test` output
@@ -28041,13 +28183,13 @@ async function scaffoldApp(projectDir, adapter, flags, _ctx) {
28041
28183
  test: runner.scriptValue
28042
28184
  },
28043
28185
  dependencies: { ...adapter.dependencies },
28044
- devDependencies: { ...adapter.devDependencies, ...pmDevDeps }
28186
+ devDependencies: { ...adapterDevDeps, ...pmDevDeps }
28045
28187
  };
28046
28188
  if (!existsSync8(pkgJsonPath)) {
28047
28189
  writeFileSync3(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
28048
28190
  created++;
28049
28191
  }
28050
- const bundledComponents = adapter.bundledRegistryComponents ?? ["button"];
28192
+ const bundledComponents = usesUno ? adapter.bundledRegistryComponents ?? ["button"] : [];
28051
28193
  if (bundledComponents.length > 0) {
28052
28194
  await addFromRegistry(
28053
28195
  bundledComponents,
@@ -28098,6 +28240,8 @@ var init_init = __esm({
28098
28240
  init_pm();
28099
28241
  init_select();
28100
28242
  init_spinner();
28243
+ init_css();
28244
+ init_shared2();
28101
28245
  INIT_GATE_ENV = "BAREFOOT_INIT_VIA_CREATE";
28102
28246
  DEFAULT_REGISTRY_URL2 = "https://ui.barefootjs.dev/r/";
28103
28247
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/cli",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "CLI for agent-driven UI component discovery and scaffolding",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,11 +29,11 @@
29
29
  "dependencies": {
30
30
  "esbuild": "^0.25.0",
31
31
  "typescript": "^5.0.0",
32
- "@barefootjs/client": "0.12.0",
33
- "@barefootjs/shared": "0.12.0"
32
+ "@barefootjs/client": "0.13.0",
33
+ "@barefootjs/shared": "0.13.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@barefootjs/jsx": "0.12.0",
36
+ "@barefootjs/jsx": "0.13.0",
37
37
  "@types/node": "^22.0.0",
38
38
  "@happy-dom/global-registrator": "^20.0.11",
39
39
  "happy-dom": "^20.0.11"