@barefootjs/client 0.1.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.
Files changed (108) hide show
  1. package/dist/build.d.ts +56 -0
  2. package/dist/build.d.ts.map +1 -0
  3. package/dist/build.js +76 -0
  4. package/dist/context.d.ts +25 -0
  5. package/dist/context.d.ts.map +1 -0
  6. package/dist/csr-adapter.d.ts +26 -0
  7. package/dist/csr-adapter.d.ts.map +1 -0
  8. package/dist/forward-props.d.ts +17 -0
  9. package/dist/forward-props.d.ts.map +1 -0
  10. package/dist/index.d.ts +8 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +154 -0
  13. package/dist/reactive.d.ts +150 -0
  14. package/dist/reactive.d.ts.map +1 -0
  15. package/dist/reactive.js +215 -0
  16. package/dist/runtime/apply-rest-attrs.d.ts +16 -0
  17. package/dist/runtime/apply-rest-attrs.d.ts.map +1 -0
  18. package/dist/runtime/branch-slot.d.ts +22 -0
  19. package/dist/runtime/branch-slot.d.ts.map +1 -0
  20. package/dist/runtime/client-marker.d.ts +21 -0
  21. package/dist/runtime/client-marker.d.ts.map +1 -0
  22. package/dist/runtime/component.d.ts +99 -0
  23. package/dist/runtime/component.d.ts.map +1 -0
  24. package/dist/runtime/context.d.ts +40 -0
  25. package/dist/runtime/context.d.ts.map +1 -0
  26. package/dist/runtime/hydrate.d.ts +100 -0
  27. package/dist/runtime/hydrate.d.ts.map +1 -0
  28. package/dist/runtime/hydration-state.d.ts +13 -0
  29. package/dist/runtime/hydration-state.d.ts.map +1 -0
  30. package/dist/runtime/index.d.ts +27 -0
  31. package/dist/runtime/index.d.ts.map +1 -0
  32. package/dist/runtime/index.js +2093 -0
  33. package/dist/runtime/insert.d.ts +75 -0
  34. package/dist/runtime/insert.d.ts.map +1 -0
  35. package/dist/runtime/list.d.ts +21 -0
  36. package/dist/runtime/list.d.ts.map +1 -0
  37. package/dist/runtime/map-array.d.ts +32 -0
  38. package/dist/runtime/map-array.d.ts.map +1 -0
  39. package/dist/runtime/portal.d.ts +96 -0
  40. package/dist/runtime/portal.d.ts.map +1 -0
  41. package/dist/runtime/qsa-item.d.ts +52 -0
  42. package/dist/runtime/qsa-item.d.ts.map +1 -0
  43. package/dist/runtime/query.d.ts +86 -0
  44. package/dist/runtime/query.d.ts.map +1 -0
  45. package/dist/runtime/reconcile-elements.d.ts +44 -0
  46. package/dist/runtime/reconcile-elements.d.ts.map +1 -0
  47. package/dist/runtime/registry.d.ts +53 -0
  48. package/dist/runtime/registry.d.ts.map +1 -0
  49. package/dist/runtime/render.d.ts +35 -0
  50. package/dist/runtime/render.d.ts.map +1 -0
  51. package/dist/runtime/scope.d.ts +28 -0
  52. package/dist/runtime/scope.d.ts.map +1 -0
  53. package/dist/runtime/slot-resolver.d.ts +36 -0
  54. package/dist/runtime/slot-resolver.d.ts.map +1 -0
  55. package/dist/runtime/spread-attrs.d.ts +19 -0
  56. package/dist/runtime/spread-attrs.d.ts.map +1 -0
  57. package/dist/runtime/standalone.js +2278 -0
  58. package/dist/runtime/streaming.d.ts +36 -0
  59. package/dist/runtime/streaming.d.ts.map +1 -0
  60. package/dist/runtime/style.d.ts +17 -0
  61. package/dist/runtime/style.d.ts.map +1 -0
  62. package/dist/runtime/template.d.ts +39 -0
  63. package/dist/runtime/template.d.ts.map +1 -0
  64. package/dist/runtime/types.d.ts +26 -0
  65. package/dist/runtime/types.d.ts.map +1 -0
  66. package/dist/shims.d.ts +21 -0
  67. package/dist/shims.d.ts.map +1 -0
  68. package/dist/slot.d.ts +14 -0
  69. package/dist/slot.d.ts.map +1 -0
  70. package/dist/split-props.d.ts +26 -0
  71. package/dist/split-props.d.ts.map +1 -0
  72. package/dist/unwrap.d.ts +16 -0
  73. package/dist/unwrap.d.ts.map +1 -0
  74. package/package.json +71 -0
  75. package/src/build.ts +92 -0
  76. package/src/context.ts +33 -0
  77. package/src/csr-adapter.ts +134 -0
  78. package/src/forward-props.ts +43 -0
  79. package/src/index.ts +42 -0
  80. package/src/reactive.ts +411 -0
  81. package/src/runtime/apply-rest-attrs.ts +109 -0
  82. package/src/runtime/branch-slot.ts +32 -0
  83. package/src/runtime/client-marker.ts +46 -0
  84. package/src/runtime/component.ts +501 -0
  85. package/src/runtime/context.ts +111 -0
  86. package/src/runtime/hydrate.ts +311 -0
  87. package/src/runtime/hydration-state.ts +13 -0
  88. package/src/runtime/index.ts +96 -0
  89. package/src/runtime/insert.ts +407 -0
  90. package/src/runtime/list.ts +47 -0
  91. package/src/runtime/map-array.ts +381 -0
  92. package/src/runtime/portal.ts +174 -0
  93. package/src/runtime/qsa-item.ts +128 -0
  94. package/src/runtime/query.ts +632 -0
  95. package/src/runtime/reconcile-elements.ts +391 -0
  96. package/src/runtime/registry.ts +160 -0
  97. package/src/runtime/render.ts +105 -0
  98. package/src/runtime/scope.ts +46 -0
  99. package/src/runtime/slot-resolver.ts +66 -0
  100. package/src/runtime/spread-attrs.ts +88 -0
  101. package/src/runtime/streaming.ts +65 -0
  102. package/src/runtime/style.ts +27 -0
  103. package/src/runtime/template.ts +53 -0
  104. package/src/runtime/types.ts +27 -0
  105. package/src/shims.ts +54 -0
  106. package/src/slot.ts +23 -0
  107. package/src/split-props.ts +86 -0
  108. package/src/unwrap.ts +18 -0
@@ -0,0 +1,36 @@
1
+ /**
2
+ * BarefootJS - Out-of-Order Streaming
3
+ *
4
+ * Client-side resolver for OOS (Out-of-Order Streaming) SSR.
5
+ * Handles swapping fallback content with resolved content that arrives
6
+ * via chunked HTTP responses.
7
+ *
8
+ * Protocol:
9
+ * 1. Server sends HTML with fallback placeholders: <div bf-async="a0">...</div>
10
+ * 2. As async data resolves, server appends chunks:
11
+ * <template bf-async-resolve="a0">...resolved...</template>
12
+ * <script>__bf_swap("a0")</script>
13
+ * 3. This module swaps fallback → resolved content and triggers hydration.
14
+ */
15
+ /**
16
+ * Swap a streaming fallback placeholder with its resolved content.
17
+ *
18
+ * Finds the placeholder element (`[bf-async="<id>"]`) and the resolve
19
+ * template (`<template bf-async-resolve="<id>">`), replaces the placeholder's
20
+ * children with the resolved content, then triggers hydration.
21
+ *
22
+ * @param id - The async boundary ID (e.g., "a0")
23
+ */
24
+ export declare function __bf_swap(id: string): void;
25
+ /**
26
+ * Install the global streaming resolver.
27
+ *
28
+ * Makes `__bf_swap` available as `window.__bf_swap` so that inline
29
+ * `<script>__bf_swap("a0")</script>` tags in streaming chunks can call it.
30
+ *
31
+ * Also exposes `window.__bf_hydrate` for manual re-hydration triggers.
32
+ *
33
+ * Call this once, early in the page (before any streaming chunks arrive).
34
+ */
35
+ export declare function setupStreaming(): void;
36
+ //# sourceMappingURL=streaming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming.d.ts","sourceRoot":"","sources":["../../src/runtime/streaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAMrC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Style attribute helpers for client-side DOM updates.
3
+ */
4
+ /**
5
+ * Convert a style value (string or object) to a CSS string, or null to remove the attribute.
6
+ *
7
+ * - null/undefined → null (remove the attribute)
8
+ * - string → the string as-is
9
+ * - object → camelCase keys converted to kebab-case, joined with semicolons
10
+ *
11
+ * @example
12
+ * styleToCss({ backgroundColor: 'red', fontSize: '16px' }) // "background-color:red;font-size:16px"
13
+ * styleToCss('color:red') // "color:red"
14
+ * styleToCss(null) // null
15
+ */
16
+ export declare function styleToCss(value: unknown): string | null;
17
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/runtime/style.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAUxD"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * BarefootJS - Template Registry
3
+ *
4
+ * Stores template functions for client-side component creation.
5
+ * Templates generate HTML strings from props, used by createComponent().
6
+ */
7
+ /**
8
+ * Template function type - generates HTML string from props
9
+ */
10
+ export type TemplateFn = (props: Record<string, unknown>) => string;
11
+ /**
12
+ * Register a template function for a component.
13
+ *
14
+ * @param name - Component name (e.g., 'TodoItem')
15
+ * @param templateFn - Function that generates HTML from props
16
+ *
17
+ * @example
18
+ * registerTemplate('TodoItem', (props) => `
19
+ * <li class="${props.done ? 'done' : ''}">
20
+ * <span>${props.text}</span>
21
+ * </li>
22
+ * `)
23
+ */
24
+ export declare function registerTemplate(name: string, templateFn: TemplateFn): void;
25
+ /**
26
+ * Get a registered template function by component name.
27
+ *
28
+ * @param name - Component name
29
+ * @returns Template function or undefined if not registered
30
+ */
31
+ export declare function getTemplate(name: string): TemplateFn | undefined;
32
+ /**
33
+ * Check if a template is registered for a component.
34
+ *
35
+ * @param name - Component name
36
+ * @returns true if template is registered
37
+ */
38
+ export declare function hasTemplate(name: string): boolean;
39
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/runtime/template.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAA;AAOnE;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * BarefootJS - Core Types
3
+ *
4
+ * Shared type definitions for component initialization and registration.
5
+ */
6
+ /**
7
+ * Component init function type.
8
+ * Takes the scope element and props, initializes the component
9
+ * by setting up event handlers, effects, and reactive bindings.
10
+ */
11
+ export type InitFn = (scope: Element, props: Record<string, unknown>) => void;
12
+ /**
13
+ * Component definition.
14
+ * Bundles the init function with optional template and scope metadata.
15
+ */
16
+ export interface ComponentDef {
17
+ /** Component name (e.g., 'Counter'). Used for scope ID generation. */
18
+ name?: string;
19
+ /** Init function that hydrates a scope element */
20
+ init: InitFn;
21
+ /** Template function for client-side component creation */
22
+ template?: (props: Record<string, unknown>) => string;
23
+ /** When true, use comment-based scope hydration (fragment roots) */
24
+ comment?: boolean;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;AAE7E;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAA;IACrD,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Browser-only API shims.
3
+ *
4
+ * These functions have real implementations in `./runtime/` that the
5
+ * compiler emits for `'use client'` components. The exports here exist
6
+ * for type-checking in user source files.
7
+ *
8
+ * If one of these ever runs, it means a `'use client'` component was
9
+ * executed without going through the compiler — or a non-client file
10
+ * slipped past the `MISSING_USE_CLIENT` check. Either way, it's a bug.
11
+ */
12
+ import type { Context } from './context';
13
+ import type { Portal, PortalChildren, PortalOptions } from './runtime/portal';
14
+ export type { Portal, PortalChildren, PortalOptions, Renderable } from './runtime/portal';
15
+ export declare function useContext<T>(_context: Context<T>): T;
16
+ export declare function provideContext<T>(_context: Context<T>, _value: T): void;
17
+ export declare function createPortal(_children: PortalChildren, _container?: Element, _options?: PortalOptions): Portal;
18
+ export declare function isSSRPortal(_element: HTMLElement): boolean;
19
+ export declare function findSiblingSlot(_el: HTMLElement, _slotSelector: string): HTMLElement | null;
20
+ export declare function cleanupPortalPlaceholder(_portalId: string): void;
21
+ //# sourceMappingURL=shims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shims.d.ts","sourceRoot":"","sources":["../src/shims.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAE7E,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AASzF,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAErD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAEvE;AAED,wBAAgB,YAAY,CAC1B,SAAS,EAAE,cAAc,EACzB,UAAU,CAAC,EAAE,OAAO,EACpB,QAAQ,CAAC,EAAE,aAAa,GACvB,MAAM,CAER;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,aAAa,EAAE,MAAM,GACpB,WAAW,GAAG,IAAI,CAEpB;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEhE"}
package/dist/slot.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Slot marker for JSX props that contain components.
3
+ *
4
+ * When a caller passes `<Button />` inside a JSX prop, the compiler wraps
5
+ * the value with `__slot()`. The callee's text effect checks `__isSlot`
6
+ * and skips the destructive `nodeValue = String(...)` update, preserving
7
+ * the server-rendered DOM for hydration.
8
+ */
9
+ export interface SlotMarker {
10
+ __isSlot: true;
11
+ toString(): string;
12
+ }
13
+ export declare function __slot(thunk: () => unknown): SlotMarker;
14
+ //# sourceMappingURL=slot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot.d.ts","sourceRoot":"","sources":["../src/slot.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,IAAI,CAAA;IACd,QAAQ,IAAI,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,OAAO,GAAG,UAAU,CAQvD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * BarefootJS - splitProps
3
+ *
4
+ * SolidJS-compatible utility for splitting a props object into local and rest.
5
+ * Uses Proxy to preserve getter-based reactivity.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { splitProps } from '@barefootjs/client'
10
+ *
11
+ * function Checkbox(props: CheckboxProps) {
12
+ * const [local, rest] = splitProps(props, ['checked', 'onCheckedChange'])
13
+ * return <button {...rest} aria-checked={local.checked} />
14
+ * }
15
+ * ```
16
+ */
17
+ /**
18
+ * Split a props object into two: one with the specified keys, one with the rest.
19
+ * Both returned objects use Proxy to defer reads, preserving reactive tracking.
20
+ *
21
+ * @param props - The source props object
22
+ * @param keys - Keys to extract into the first (local) object
23
+ * @returns A tuple [local, rest] where local has the specified keys and rest has everything else
24
+ */
25
+ export declare function splitProps<T extends Record<string, unknown>, K extends (keyof T)[]>(props: T, keys: K): [Pick<T, K[number]>, Omit<T, K[number]>];
26
+ //# sourceMappingURL=split-props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split-props.d.ts","sourceRoot":"","sources":["../src/split-props.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAErB,KAAK,EAAE,CAAC,EACR,IAAI,EAAE,CAAC,GACN,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAsD1C"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * BarefootJS - Unwrap Utility
3
+ *
4
+ * Unwrap a prop value that may be a getter function.
5
+ * When props are passed from parent to child components, reactive values
6
+ * are wrapped as getter functions to maintain reactivity.
7
+ * This helper unwraps them transparently.
8
+ */
9
+ /**
10
+ * Unwrap a prop value that may be a getter function.
11
+ *
12
+ * @param prop - The prop value (may be a value or a getter function)
13
+ * @returns The unwrapped value
14
+ */
15
+ export declare function unwrap<T>(prop: T | (() => T)): T;
16
+ //# sourceMappingURL=unwrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unwrap.d.ts","sourceRoot":"","sources":["../src/unwrap.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAEhD"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@barefootjs/client",
3
+ "version": "0.1.0",
4
+ "description": "BarefootJS client package: reactive primitives (SSR-safe) plus browser runtime under the `/runtime` subpath (compiler target)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./reactive": {
14
+ "types": "./dist/reactive.d.ts",
15
+ "import": "./dist/reactive.js"
16
+ },
17
+ "./runtime": {
18
+ "types": "./dist/runtime/index.d.ts",
19
+ "import": "./dist/runtime/index.js"
20
+ },
21
+ "./runtime/standalone": {
22
+ "types": "./dist/runtime/index.d.ts",
23
+ "import": "./dist/runtime/standalone.js"
24
+ },
25
+ "./build": {
26
+ "types": "./dist/build.d.ts",
27
+ "import": "./dist/build.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "src"
33
+ ],
34
+ "scripts": {
35
+ "build": "bun run build:js && bun run build:types",
36
+ "build:js": "bun build ./src/reactive.ts --outdir ./dist --format esm && bun build ./src/index.ts --outdir ./dist --format esm --external '@barefootjs/client/reactive' && bun build ./src/runtime/index.ts --outdir ./dist/runtime --format esm --external '@barefootjs/client/reactive' && bun build ./src/runtime/index.ts --outfile ./dist/runtime/standalone.js --format esm && bun build ./src/build.ts --outdir ./dist --format esm --external '@barefootjs/jsx'",
37
+ "build:types": "tsgo --emitDeclarationOnly --outDir ./dist",
38
+ "test": "bun test",
39
+ "clean": "rm -rf dist"
40
+ },
41
+ "keywords": [
42
+ "reactive",
43
+ "signals",
44
+ "dom",
45
+ "runtime",
46
+ "barefoot"
47
+ ],
48
+ "author": "kobaken <kentafly88@gmail.com>",
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/piconic-ai/barefootjs",
53
+ "directory": "packages/client"
54
+ },
55
+ "dependencies": {
56
+ "@barefootjs/shared": "workspace:*"
57
+ },
58
+ "peerDependencies": {
59
+ "@barefootjs/jsx": "workspace:*"
60
+ },
61
+ "peerDependenciesMeta": {
62
+ "@barefootjs/jsx": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "@barefootjs/jsx": "workspace:*",
68
+ "@happy-dom/global-registrator": "^20.0.11",
69
+ "typescript": "^5.0.0"
70
+ }
71
+ }
package/src/build.ts ADDED
@@ -0,0 +1,92 @@
1
+ // CSR build config factory for `barefoot.config.ts`.
2
+ //
3
+ // CSR (client-side rendering) projects emit client JS only — no marked
4
+ // templates, no SSR. Pair this config with `render()` from
5
+ // `@barefootjs/client/runtime` on the page.
6
+ //
7
+ // The compiler still needs a `TemplateAdapter` to drive IR→client-JS
8
+ // codegen (the analyzer consults `acceptsTemplateCall` when deciding
9
+ // template-scope vs init-scope placement). The marked templates the
10
+ // adapter would produce are simply not written to disk. The default
11
+ // `CSRAdapter` is the minimum that satisfies the interface — its
12
+ // `generate()` returns an empty `AdapterOutput` and the build
13
+ // pipeline drops the empty marked-template file at the
14
+ // `clientOnly` gate.
15
+ //
16
+ // (Pre-1.0 this was `HonoAdapter` from `@barefootjs/hono/adapter`,
17
+ // which pulled the entire Hono package into a CSR app's
18
+ // `node_modules` for output that was always thrown away. See
19
+ // `csr-adapter.ts` for the rationale on the new in-package adapter.)
20
+
21
+ import type {
22
+ BarefootPaths,
23
+ BundleEntry,
24
+ ExternalSpec,
25
+ OutputLayout,
26
+ PostBuildContext,
27
+ TemplateAdapter,
28
+ } from '@barefootjs/jsx'
29
+ import { CSRAdapter } from './csr-adapter'
30
+ import type { CSRAdapterOptions } from './csr-adapter'
31
+
32
+ export interface CSRBuildOptions {
33
+ /** Project layout paths consumed by registry tooling. */
34
+ paths?: BarefootPaths
35
+ /** Source component directories relative to the config file. */
36
+ components?: string[]
37
+ /** Output directory relative to the config file. */
38
+ outDir?: string
39
+ /** Minify client JS output. */
40
+ minify?: boolean
41
+ /** Add content hash to client JS filenames. */
42
+ contentHash?: boolean
43
+ /** Custom output directory layout. */
44
+ outputLayout?: OutputLayout
45
+ /** Post-build hook called after minification, before manifest write. */
46
+ postBuild?: (ctx: PostBuildContext) => Promise<void> | void
47
+ /** Vendor packages to split out as separately-cached browser chunks. */
48
+ externals?: Record<string, ExternalSpec>
49
+ /** URL base path for vendor chunks in the emitted importmap. */
50
+ externalsBasePath?: string
51
+ /** Additional entry points to bundle with esbuild directly. */
52
+ bundleEntries?: BundleEntry[]
53
+ /**
54
+ * Override the compiler adapter. The marked templates this adapter
55
+ * generates are discarded in CSR mode — set this only if you need
56
+ * a different `TemplateAdapter` (e.g. a custom test adapter).
57
+ */
58
+ adapter?: TemplateAdapter
59
+ /** Options forwarded to the default `CSRAdapter`. Ignored when `adapter` is set. */
60
+ adapterOptions?: CSRAdapterOptions
61
+ }
62
+
63
+ /**
64
+ * Create a BarefootBuildConfig for CSR projects.
65
+ *
66
+ * Uses structural typing — does not import `BarefootBuildConfig` to avoid
67
+ * a circular dependency between `@barefootjs/client` and `@barefootjs/cli`.
68
+ */
69
+ export function createConfig(options: CSRBuildOptions = {}) {
70
+ // `name` defaults to `'csr'` inside `CSRAdapter`; a caller-supplied
71
+ // `adapterOptions.name` (or a fully-custom `adapter`) wins, matching
72
+ // the pre-decoupling behaviour where `bf build`'s `Adapter: …`
73
+ // banner reflected the option override.
74
+ const adapter = options.adapter ?? new CSRAdapter(options.adapterOptions)
75
+ return {
76
+ adapter,
77
+ paths: options.paths,
78
+ components: options.components,
79
+ outDir: options.outDir,
80
+ minify: options.minify,
81
+ contentHash: options.contentHash,
82
+ clientOnly: true,
83
+ externals: options.externals,
84
+ externalsBasePath: options.externalsBasePath,
85
+ bundleEntries: options.bundleEntries,
86
+ outputLayout: options.outputLayout,
87
+ postBuild: options.postBuild,
88
+ }
89
+ }
90
+
91
+ export { CSRAdapter } from './csr-adapter'
92
+ export type { CSRAdapterOptions } from './csr-adapter'
package/src/context.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Context API: pure metadata portion.
3
+ *
4
+ * `createContext` is DOM-free and safe to use anywhere (including SSR).
5
+ * The DOM-bound operations (`useContext`, `provideContext`) live in
6
+ * `./runtime/context.ts` and are emitted by the compiler for `'use client'`
7
+ * components.
8
+ */
9
+
10
+ export type Context<T> = {
11
+ readonly id: symbol
12
+ readonly defaultValue: T | undefined
13
+ /** JSX Provider component. Compiled to provideContext() by the compiler. */
14
+ readonly Provider: (props: { value: T; children?: unknown }) => unknown
15
+ }
16
+
17
+ /**
18
+ * Create a new context with an optional default value.
19
+ *
20
+ * `useContext()` returns the nearest provider value, then the default,
21
+ * then `undefined`. It never throws — guard with optional chaining.
22
+ */
23
+ export function createContext<T>(defaultValue?: T): Context<T> {
24
+ return {
25
+ id: Symbol(),
26
+ defaultValue,
27
+ // Provider is compiled away by the JSX compiler into provideContext() calls.
28
+ // This runtime stub exists only for TypeScript type checking.
29
+ Provider: (() => {
30
+ throw new Error('Context.Provider should be compiled away')
31
+ }) as Context<T>['Provider'],
32
+ }
33
+ }
@@ -0,0 +1,134 @@
1
+ // Minimal `TemplateAdapter` used by `@barefootjs/client/build`'s
2
+ // `createConfig` for CSR projects.
3
+ //
4
+ // CSR builds emit client JS only — the marked-template output the
5
+ // `TemplateAdapter` contract requires is discarded by the build
6
+ // pipeline when `clientOnly: true` (see `cli/src/lib/build.ts`, the
7
+ // `!config.clientOnly && markedTemplates.length > 0` gate). All this
8
+ // adapter has to do is satisfy the interface so the compiler's
9
+ // pass-2 loop can call `adapter.generate()` without crashing.
10
+ //
11
+ // Historically `createConfig` reused `HonoAdapter` from
12
+ // `@barefootjs/hono/adapter` here as a "broad-acceptance JS template
13
+ // runtime". That pulled the entire Hono package into a CSR app's
14
+ // `node_modules` for an adapter whose every output was thrown away
15
+ // — confusing for users who picked CSR specifically to avoid an SSR
16
+ // framework dependency. Replacing it with this in-package adapter
17
+ // deletes the transitive Hono dep and keeps the analyzer-side
18
+ // behaviour identical (`acceptsTemplateCall: () => true`).
19
+ //
20
+ // What we still need from a "template adapter" in CSR mode:
21
+ //
22
+ // - `acceptsTemplateCall: () => true`. This is consulted by the
23
+ // IR analyzer + relocate pipeline (#1187 phase 3) when
24
+ // deciding whether a call expression can live at template
25
+ // scope vs init scope. The CSR "template" runs in the browser
26
+ // via `@barefootjs/client/runtime`, so any synchronous JS call
27
+ // is valid there — same contract as Hono SSR, where the broad
28
+ // predicate originally lived. Without this the analyzer would
29
+ // conservatively force calls into init scope and emit different
30
+ // (less efficient) client JS.
31
+ //
32
+ // - Sentinel `generate()` returning an empty `AdapterOutput`. The
33
+ // compiler's pass-2 unconditionally calls `adapter.generate()`
34
+ // to assemble the marked-template module string; in CSR mode
35
+ // every field of that string is discarded before write, so we
36
+ // just hand back empty strings and let the pipeline drop the
37
+ // empty `markedTemplate` file at the gate.
38
+ //
39
+ // - No-op render methods. The `TemplateAdapter` interface lists
40
+ // them (`renderNode`, `renderElement`, etc.) but they are only
41
+ // ever invoked from inside an adapter's own `generate()`. Since
42
+ // ours returns early, these are never reached at runtime — they
43
+ // exist purely to satisfy the contract.
44
+ //
45
+ // Everything else (`clientShimSource`, `templatePrimitives`,
46
+ // `generateSignalInitializers`, ...) is optional on `TemplateAdapter`
47
+ // and intentionally omitted: CSR has no SSR templates to shim into,
48
+ // no DSL-side primitive registry, and no init block to emit.
49
+
50
+ import type { AdapterOutput, TemplateSections } from '@barefootjs/jsx'
51
+ import { BaseAdapter } from '@barefootjs/jsx'
52
+
53
+ export interface CSRAdapterOptions {
54
+ /**
55
+ * Display name surfaced through `TemplateAdapter.name` — read by
56
+ * `bf build` for its `Adapter: …` banner. Defaults to `'csr'`.
57
+ */
58
+ name?: string
59
+ }
60
+
61
+ // Frozen so a single shared sentinel can be returned from every
62
+ // `generate()` call without risking that a downstream consumer
63
+ // mutates it and bleeds state across compilations. `Object.freeze`
64
+ // is shallow, so we freeze both the outer `AdapterOutput` and the
65
+ // nested `sections` object — those are the two objects callers
66
+ // could write to (string/extension fields are primitives).
67
+ const EMPTY_SECTIONS: TemplateSections = Object.freeze({
68
+ imports: '',
69
+ types: '',
70
+ component: '',
71
+ defaultExport: '',
72
+ })
73
+
74
+ const EMPTY_OUTPUT: AdapterOutput = Object.freeze({
75
+ template: '',
76
+ sections: EMPTY_SECTIONS,
77
+ extension: '.tsx',
78
+ })
79
+
80
+ export class CSRAdapter extends BaseAdapter {
81
+ name: string
82
+ extension = '.tsx'
83
+
84
+ // Broad acceptance — matches Hono's contract, see the comment at
85
+ // the top of this file for why CSR shares it.
86
+ acceptsTemplateCall = (): boolean => true
87
+
88
+ constructor(options: CSRAdapterOptions = {}) {
89
+ super()
90
+ this.name = options.name ?? 'csr'
91
+ }
92
+
93
+ // Sentinel: the marked-template is discarded in clientOnly mode,
94
+ // so a single shared empty `AdapterOutput` (frozen — see
95
+ // `EMPTY_OUTPUT` above) is enough. Re-creating per call would just
96
+ // allocate garbage.
97
+ generate(): AdapterOutput {
98
+ return EMPTY_OUTPUT
99
+ }
100
+
101
+ // The render methods below would only ever be called from inside
102
+ // an adapter's own `generate()`; since ours returns early, none of
103
+ // them run at compile time. They exist purely to satisfy
104
+ // `BaseAdapter`'s abstract surface. `BaseAdapter` already provides
105
+ // a sensible default `renderAsync` that delegates to `renderNode`
106
+ // + `renderChildren`, so we inherit that for free.
107
+ renderNode(): string {
108
+ return ''
109
+ }
110
+ renderElement(): string {
111
+ return ''
112
+ }
113
+ renderExpression(): string {
114
+ return ''
115
+ }
116
+ renderConditional(): string {
117
+ return ''
118
+ }
119
+ renderLoop(): string {
120
+ return ''
121
+ }
122
+ renderComponent(): string {
123
+ return ''
124
+ }
125
+ renderScopeMarker(): string {
126
+ return ''
127
+ }
128
+ renderSlotMarker(): string {
129
+ return ''
130
+ }
131
+ renderCondMarker(): string {
132
+ return ''
133
+ }
134
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * BarefootJS - Forward Props Helper
3
+ *
4
+ * Forwards spread props to child components using getter delegation
5
+ * to preserve reactivity. Used by compiler-generated code for
6
+ * components with {...rest} spread on child components.
7
+ */
8
+
9
+ /**
10
+ * Create a props object that merges explicit overrides with forwarded source props.
11
+ * Preserves getter-based reactivity from both overrides and source.
12
+ *
13
+ * @param source - The parent props object (reads are deferred via getters)
14
+ * @param overrides - Object literal with getters/values that override source props
15
+ * @param excludeKeys - Keys from source to exclude (already destructured)
16
+ */
17
+ export function forwardProps<T extends Record<string, unknown>>(
18
+ source: T,
19
+ overrides: Record<string, unknown>,
20
+ excludeKeys: string[]
21
+ ): Record<string, unknown> {
22
+ const result: Record<string, unknown> = {}
23
+ const exclude = new Set(excludeKeys)
24
+
25
+ // Copy overrides preserving getter descriptors
26
+ const descs = Object.getOwnPropertyDescriptors(overrides)
27
+ for (const key of Object.keys(descs)) {
28
+ Object.defineProperty(result, key, { ...descs[key], enumerable: true, configurable: true })
29
+ }
30
+
31
+ // Forward remaining source props via getters (deferred read = reactive)
32
+ for (const key of Object.keys(source)) {
33
+ if (exclude.has(key) || key in result) continue
34
+ const k = key
35
+ Object.defineProperty(result, k, {
36
+ get: () => (source as Record<string, unknown>)[k],
37
+ enumerable: true,
38
+ configurable: true,
39
+ })
40
+ }
41
+
42
+ return result
43
+ }
package/src/index.ts ADDED
@@ -0,0 +1,42 @@
1
+ // Reactive primitives live at the shared `@barefootjs/client/reactive`
2
+ // subpath so main and the `/runtime` entry point reference a single
3
+ // physical module — see src/runtime/index.ts for the rationale.
4
+ export {
5
+ createSignal,
6
+ createEffect,
7
+ createDisposableEffect,
8
+ createMemo,
9
+ createRoot,
10
+ onCleanup,
11
+ onMount,
12
+ untrack,
13
+ batch,
14
+ type Reactive,
15
+ type Signal,
16
+ type Memo,
17
+ type CleanupFn,
18
+ type EffectFn,
19
+ } from '@barefootjs/client/reactive'
20
+
21
+ export { splitProps } from './split-props'
22
+
23
+ export { __slot, type SlotMarker } from './slot'
24
+
25
+ export { forwardProps } from './forward-props'
26
+
27
+ export { unwrap } from './unwrap'
28
+
29
+ export { createContext, type Context } from './context'
30
+
31
+ export {
32
+ useContext,
33
+ provideContext,
34
+ createPortal,
35
+ isSSRPortal,
36
+ findSiblingSlot,
37
+ cleanupPortalPlaceholder,
38
+ type Portal,
39
+ type PortalChildren,
40
+ type PortalOptions,
41
+ type Renderable,
42
+ } from './shims'