@batono/ui 0.0.3 → 0.0.4

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 (2) hide show
  1. package/README.md +237 -11
  2. package/package.json +6 -6
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @batono/ui
2
2
 
3
- > SHORT_DESCRIPTION.
3
+ > UI primitives for the Batono server-driven interaction protocol.
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/%40batono%2Fui.svg)](https://www.npmjs.com/package/@batono/ui)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
@@ -8,54 +8,280 @@
8
8
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)
9
9
  [![codecov](https://codecov.io/gh/batono/ui/branch/main/graph/badge.svg)](https://codecov.io/gh/batono/ui)
10
10
 
11
- This package
11
+ `@batono/ui` provides the UI building blocks for the Batono protocol — layout containers, content definitions, and
12
+ action primitives. It builds on top of `@batono/core` and is designed to be used together with it.
12
13
 
13
14
  ---
14
15
 
15
16
  ## Features
16
17
 
17
- - ✅ No dependencies
18
+ - ✅ Peer dependency on `@batono/core` only
19
+ - ✅ Fully composable layout system (`rows`, `row`, `inline`)
20
+ - ✅ Rich content definitions (`header`, `section`, `field`, `meta`, `note`, `stat`)
21
+ - ✅ Fluent builder API with method chaining
22
+ - ✅ Typed result interfaces for frontend renderers
23
+ - ✅ String shorthand for field values — auto-wrapped in `Text`
18
24
 
19
25
  ---
20
26
 
21
27
  ## Installation
22
28
 
23
29
  ```bash
24
- npm install @batono/ui
25
- ````
30
+ npm install @batono/ui @batono/core
31
+ ```
26
32
 
27
33
  ---
28
34
 
29
35
  ## Basic Usage
30
36
 
37
+ ```ts
38
+ import {bt as btCore} from '@batono/core'
39
+ import {bt} from '@batono/ui'
40
+
41
+ const openProfile = btCore.defineAction(
42
+ bt.request('GET', '/customers/42')
43
+ )
44
+
45
+ const graph = btCore.graph(
46
+ bt.rows(
47
+ bt.row(
48
+ bt.header('Batman Forever', {
49
+ avatar: 'BF',
50
+ subtitle: bt.inline(
51
+ bt.link('Bruno Labbadia', openProfile),
52
+ bt.text(' · '),
53
+ bt.text('K2602206207')
54
+ )
55
+ })
56
+ ),
57
+ bt.row(
58
+ bt.section('Personal Data', bt.rows(
59
+ bt.row(
60
+ bt.field('First Name', 'Batman'),
61
+ bt.field('Last Name', 'Forever')
62
+ ),
63
+ bt.row(
64
+ bt.field('Email', null),
65
+ bt.field('Phone', null)
66
+ )
67
+ ))
68
+ )
69
+ )
70
+ )
71
+
72
+ res.json(graph)
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Layout
78
+
79
+ ### `rows` / `row`
80
+
81
+ The primary layout system. `rows` is a vertical stack of `row` containers. Each `row` distributes its children
82
+ horizontally with equal width.
31
83
 
32
84
  ```ts
33
- import {x} from '@batono/ui'
85
+ bt.rows(
86
+ bt.row(bt.field('First Name', 'Batman'), bt.field('Last Name', 'Forever')),
87
+ bt.row(bt.field('Email', null))
88
+ )
89
+ ```
90
+
91
+ ### `inline`
34
92
 
35
- const t =....
93
+ A horizontal container without grid spacing — for composing inline content like subtitles.
36
94
 
95
+ ```ts
96
+ bt.inline(
97
+ bt.link('Parent', openParent),
98
+ bt.text(' · '),
99
+ bt.text('K2602206207')
100
+ )
37
101
  ```
38
102
 
39
103
  ---
40
104
 
41
- ### Example2
105
+ ## Definitions
106
+
107
+ ### `header`
108
+
109
+ Page-level header with avatar, subtitle and actions.
42
110
 
43
111
  ```ts
44
- import {x} from '@batono/ui'
112
+ bt.header('Batman Forever', {
113
+ avatar: 'BF',
114
+ subtitle: bt.inline(bt.text('Student')),
115
+ actions: bt.actionButtons(
116
+ bt.action('+ Book Unit', bookUnit, {variant: 'primary'})
117
+ )
118
+ })
119
+ ```
120
+
121
+ ### `section`
45
122
 
46
- const t =....
123
+ A card container with a title, optional icon, actions and a rows layout.
47
124
 
125
+ ```ts
126
+ bt.section('Personal Data', bt.rows(
127
+ bt.row(bt.field('First Name', 'Batman'))
128
+ ))
129
+ .withIcon('🧑')
130
+ .withVariant('accent')
131
+ .withActions(bt.actionButtons(
132
+ bt.action('Edit', editAction)
133
+ ))
48
134
  ```
49
135
 
136
+ ### `field`
137
+
138
+ A labeled value. Accepts a string shorthand — automatically wrapped in `Text`.
139
+
140
+ ```ts
141
+ bt.field('First Name', 'Batman')
142
+ bt.field('Newsletter', 'Yes', 'bool-true')
143
+ bt.field('Email', null) // renders as empty
144
+ bt.field('ID', bt.inline(bt.text('NJkR7'), bt.text(' (obfuscated)')))
145
+ ```
146
+
147
+ ### `meta`
148
+
149
+ A compact chip or badge for metadata display.
150
+
151
+ ```ts
152
+ bt.meta('89544').withLabel('ID').withIcon('🆔')
153
+ bt.meta('New Customer').withVariant('badge-green')
154
+ bt.meta('Student').withVariant('badge-accent')
155
+ ```
156
+
157
+ ### `stat`
158
+
159
+ A large metric display for key numbers.
160
+
161
+ ```ts
162
+ bt.stat('Available Units', '99.0')
163
+ bt.stat('Available (HH:mm)', '74:15')
164
+ ```
165
+
166
+ ### `note`
167
+
168
+ A timestamped note with author and optional actions.
169
+
170
+ ```ts
171
+ bt.note(
172
+ 'Student mentioned difficulties in analysis.',
173
+ 'Maria K.',
174
+ '2026-02-12T11:15:00',
175
+ bt.actionButtons(
176
+ bt.action('✕', deleteNote, {variant: 'ghost'})
177
+ )
178
+ )
179
+ ```
180
+
181
+ ### `text` / `link`
182
+
183
+ Inline content primitives.
184
+
185
+ ```ts
186
+ bt.text('Some text')
187
+ bt.link('Open Profile', openProfileAction)
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Actions
193
+
194
+ ### `request`
195
+
196
+ An HTTP action definition.
197
+
198
+ ```ts
199
+ bt.request('POST', '/bookings')
200
+ bt.request('DELETE', '/users/42').withPayload({id: 42})
201
+ ```
202
+
203
+ ### `modal`
204
+
205
+ A modal dialog action.
206
+
207
+ ```ts
208
+ bt.modal('Are you sure?')
209
+ ```
210
+
211
+ ### `actionButtons`
212
+
213
+ A container for `action` buttons, used in `header` and `section`.
214
+
215
+ ```ts
216
+ bt.actionButtons(
217
+ bt.action('+ Book Unit', bookUnit, {variant: 'primary'}),
218
+ bt.action('+ Note', addNote, {variant: 'secondary'})
219
+ )
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Variants
225
+
226
+ `RenderVariant` is used on `field`, `meta`, `section` and `action` to signal visual intent to the renderer.
227
+
228
+ | Variant | Usage |
229
+ |----------------|-----------------------------|
230
+ | `primary` | Primary action button |
231
+ | `secondary` | Secondary action button |
232
+ | `ghost` | Subtle/destructive action |
233
+ | `mono` | Monospace text (IDs, codes) |
234
+ | `bool-true` | Positive boolean value |
235
+ | `bool-false` | Negative boolean value |
236
+ | `badge-green` | Success/positive badge |
237
+ | `badge-accent` | Highlighted badge |
238
+ | `accent` | Highlighted section |
239
+
240
+ ---
241
+
242
+ ## Frontend Types
243
+
244
+ `@batono/ui` exports typed result interfaces for frontend renderers — no dependency on build-time classes needed.
245
+
246
+ ```ts
247
+ import type {
248
+ HeaderResult,
249
+ SectionResult,
250
+ FieldResult,
251
+ RowsResult,
252
+ Defined
253
+ } from '@batono/ui'
254
+ ```
255
+
256
+ All result types extend `Defined` from `@batono/core`:
257
+
258
+ ```ts
259
+ interface Defined {
260
+ $schema: string
261
+ $graph: string
262
+ type: string
263
+ }
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Utilities
269
+
50
270
  ```ts
271
+ import {NBSP} from '@batono/ui'
51
272
 
273
+ bt.text(`${NBSP}·${NBSP}`) // non-breaking space separator
52
274
  ```
53
275
 
54
276
  ---
55
277
 
56
278
  ## Design Goals
57
279
 
58
- * Predictable behavior
280
+ - **Semantic over generic** — `header`, `section`, `field` express intent, not just structure
281
+ - **Fluent API** — method chaining for optional properties keeps constructors clean
282
+ - **Frontend-agnostic** — result interfaces work with any renderer (Vue, React, vanilla)
283
+ - **Composable** — every definition is an `IBuildable`, freely nestable
284
+ - **Renderer-friendly** — `type` discriminator on every node enables exhaustive switch rendering
59
285
 
60
286
  ---
61
287
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@batono/ui",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Pascal Pfeifer <pascal@pfeifer.zone>",
@@ -38,16 +38,16 @@
38
38
  "prepublishOnly": "npm test",
39
39
  "build": "npm run clean && tsc",
40
40
  "clean": "rm -rf dist",
41
- "test": "npm run build && node --test 'test/'",
42
- "test:coverage": "npm run build && node --test 'test/' --experimental-test-coverage --test-coverage-exclude='test/**'",
43
- "test:coverage:c8": "npm run build && npx c8 node --test 'test/'",
44
- "test:coverage:lcov": "npm run build && node --enable-source-maps --test 'test/' --experimental-test-coverage --test-coverage-exclude='test/**' --test-reporter=lcov --test-reporter-destination=lcov.info"
41
+ "test": "npm run build && node --test",
42
+ "test:coverage": "npm run build && node --test --experimental-test-coverage --test-coverage-exclude='test/**'",
43
+ "test:coverage:c8": "npm run build && npx c8 node --test",
44
+ "test:coverage:lcov": "npm run build && node --enable-source-maps --test --experimental-test-coverage --test-coverage-exclude='test/**' --test-reporter=lcov --test-reporter-destination=lcov.info"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^20.17.9",
48
48
  "typescript": "^5.9.3"
49
49
  },
50
50
  "dependencies": {
51
- "@batono/core": "^0.0.3"
51
+ "@batono/core": "^0.0.4"
52
52
  }
53
53
  }