@close-by/clay 0.2.11 → 0.2.13

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/docs/boot.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  Clay has two entry styles. Prefer **one production path** (library mode) and treat the CLI as a thin dev wrapper so port, CSS, and `clientDir` do not drift.
4
4
 
5
+ ### Dev HTML comments
6
+
7
+ When `dev` is on (default unless `NODE_ENV=production`, or set `ui.run({ dev: true })`), the shell sets `window.__CLAY_DEV__` and the client inserts HTML comments around each wire node:
8
+
9
+ ```html
10
+ <!-- clay:staticTable -->
11
+ …table markup…
12
+ <!-- /clay:staticTable -->
13
+ ```
14
+
15
+ Pass `dev: false` to disable.
16
+
5
17
  ## Recommended production path — library mode
6
18
 
7
19
  ```typescript
package/docs/elements.md CHANGED
@@ -34,7 +34,7 @@ Each factory creates an `Element` with a wire `type` string. The React client ma
34
34
  | `inputGroup` | `inputGroup` | Input with prefix/suffix addons |
35
35
  | `toggle` | `toggle` | Pressed toolbar toggle |
36
36
  | `descriptionList` | `descriptionList` | Key-value detail rows |
37
- | `staticTable` | `staticTable` | Read-only HTML table |
37
+ | `staticTable` | `staticTable` | Read-only HTML table (`bordered`/`hoverable` default on; `density`, `emptyTitle`, column `mono`) |
38
38
  | `aspectRatio` | `aspectRatio` | Fixed-ratio child wrapper |
39
39
  | `itemList` | `itemList` | Settings / notification rows |
40
40
  | `checkboxGroup` | `checkboxGroup` | Multi-select checkboxes |
@@ -76,6 +76,7 @@ Each factory creates an `Element` with a wire `type` string. The React client ma
76
76
  | `badge` | `badge` | ShadCN `Badge` |
77
77
  | `alert` | `alert` | Bordered alert box |
78
78
  | `spinner` | `spinner` | Lucide spinner |
79
+ | `spacer` | `spacer` | Fixed gap (`orientation` default `horizontal`; `size` xs–xl) |
79
80
  | `skeleton` | `skeleton` | ShadCN `Skeleton` placeholder |
80
81
  | `avatar` | `avatar` | ShadCN `Avatar` (+ fallback) |
81
82
  | `progress` | `progress` | ShadCN `Progress` (0–100) |
@@ -39,9 +39,9 @@ const live = ui.state({ selectedId: null as string | null, rows: [] as Row[] });
39
39
 
40
40
  ui.auto(() => {
41
41
  ui.resizable(
42
- { orientation: 'horizontal', className: 'h-[calc(100vh-8rem)] w-full min-h-[24rem]' },
42
+ { orientation: 'horizontal', fill: 'viewport' },
43
43
  (r) => {
44
- r.panel({ defaultSize: 40, minSize: 28 }, () => {
44
+ r.panel({ defaultSize: 40, minSize: 28, className: 'min-h-0 overflow-hidden' }, () => {
45
45
  ui.auto(() => {
46
46
  for (const row of live.rows) {
47
47
  ui.button(row.id, {
@@ -54,11 +54,12 @@ ui.auto(() => {
54
54
  }
55
55
  });
56
56
  });
57
- r.panel({ defaultSize: 60, minSize: 36 }, () => {
57
+ r.handle();
58
+ r.panel({ defaultSize: 60, minSize: 36, className: 'min-h-0 overflow-hidden' }, () => {
58
59
  ui.auto(() => {
59
60
  const row = live.rows.find((x) => x.id === live.selectedId);
60
61
  if (!row) {
61
- ui.label('Select a row').classes('text-sm text-muted-foreground');
62
+ ui.empty({ title: 'Select a row', density: 'inline' });
62
63
  return;
63
64
  }
64
65
  // detail…
@@ -70,7 +71,7 @@ ui.auto(() => {
70
71
  });
71
72
  ```
72
73
 
73
- Keep **separate** `ui.auto` regions for list vs detail so selection updates do not remount the whole shell. Default panel sizes (`defaultSize` / `minSize`) are percentages.
74
+ Keep **separate** `ui.auto` regions for list vs detail so selection updates do not remount the whole shell. Default panel sizes (`defaultSize` / `minSize`) are percentages. Prefer `fill: 'parent' | 'viewport'` over viewport `calc` height utilities.
74
75
 
75
76
  ## Live feed rows (not `ui.list`)
76
77
 
@@ -163,7 +164,7 @@ For **`ui.dataTable`**, pass `showFilterChips: true` to surface active search +
163
164
  ```ts
164
165
  ui.auto(() => {
165
166
  if (live.loadingMore) {
166
- ui.label('Loading…').classes('text-xs text-muted-foreground p-2');
167
+ ui.label('Loading…', { tone: 'muted', size: 'xs' });
167
168
  return;
168
169
  }
169
170
  if (!live.hasMore) return;
@@ -183,6 +184,23 @@ ui.auto(() => {
183
184
 
184
185
  Alternative when you already wrap the list in **`ui.scrollArea`**: use `onNearEnd` on the scroll area (scroll-root is built-in). Prefer one pattern per surface — `viewportEnter` + `nearest-scroll` does **not** require `scrollArea`.
185
186
 
187
+ ## Fewer classes (ops density)
188
+
189
+ Prefer semantic props over Tailwind soup:
190
+
191
+ | Instead of… | Prefer… |
192
+ |-------------|---------|
193
+ | `.classes('text-sm text-muted-foreground')` | `ui.label(…, { tone: 'muted', size: 'sm' })` |
194
+ | Title + subtitle stacks | `ui.pageHeading('Orders', { description: '…' })` |
195
+ | `className: 'flex-row w-[10rem]'` on filters | `ui.select({ inline: true, width: 'sm', … })` |
196
+ | `ui.spinner({ className: 'h-3 w-3' })` | `ui.spinner({ size: 'xs' })` |
197
+ | Feed empty muted label | `ui.empty({ title: '…', density: 'inline' })` |
198
+ | `h-[calc(100%-7rem)]!` on resizable | `ui.resizable({ fill: 'parent' \| 'viewport' }, …)` |
199
+ | `className: 'items-end justify-between'` on rows | `ui.row({ align: 'end', justify: 'between' }, …)` |
200
+ | `className: 'mb-2'` between uneven blocks | Parent `column({ gap })`, or `ui.spacer({ orientation: 'vertical', size: 'md' })` |
201
+
202
+ Prefer even stacks via parent `gap`. Use `ui.spacer` for uneven breaks (`orientation` default **`horizontal`**; `vertical` for column stacks). `className` remains an escape hatch.
203
+
186
204
  ## Logs / traces — sensitive bodies
187
205
 
188
206
  Structured logs often contain API keys or partner tokens. Scrubbing is the **app’s** job; Clay can still reduce shoulder-surfing:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@close-by/clay",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "NiceGUI-like ui.* facade for Clay apps",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -37,10 +37,10 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@close-by/clay-compiler": "0.2.11",
41
- "@close-by/clay-core": "0.2.11",
42
- "@close-by/clay-components": "0.2.11",
43
- "@close-by/clay-server": "0.2.11",
40
+ "@close-by/clay-compiler": "0.2.13",
41
+ "@close-by/clay-core": "0.2.13",
42
+ "@close-by/clay-components": "0.2.13",
43
+ "@close-by/clay-server": "0.2.13",
44
44
  "@tailwindcss/cli": "^4.3.3",
45
45
  "tailwindcss": "^4.3.3"
46
46
  }
package/src/index.ts CHANGED
@@ -34,6 +34,8 @@ import {
34
34
  pagination as paginationFactory,
35
35
  filterBar as filterBarFactory,
36
36
  filterChips as filterChipsFactory,
37
+ pageHeading as pageHeadingFactory,
38
+ spacer as spacerFactory,
37
39
  numberField as numberFieldFactory,
38
40
  phoneInput as phoneInputFactory,
39
41
  field as fieldFactory,
@@ -120,7 +122,10 @@ import {
120
122
  type ButtonVariant,
121
123
  type ButtonSize,
122
124
  type LabelProps,
125
+ type LabelTone,
126
+ type LabelSize,
123
127
  type InputProps,
128
+ type FieldWidth,
124
129
  type CheckboxProps,
125
130
  type SwitchProps,
126
131
  type SelectProps,
@@ -144,6 +149,7 @@ import {
144
149
  type BadgeProps,
145
150
  type AlertProps,
146
151
  type SpinnerProps,
152
+ type SpinnerSize,
147
153
  type ProgressProps,
148
154
  type SeparatorProps,
149
155
  type IconProps,
@@ -157,6 +163,11 @@ import {
157
163
  type ButtonGroupProps,
158
164
  type ButtonGroupOrientation,
159
165
  type EmptyProps,
166
+ type EmptyDensity,
167
+ type PageHeadingProps,
168
+ type SpacerProps,
169
+ type SpacerSize,
170
+ type SpacerOrientation,
160
171
  type PaginationProps,
161
172
  type FilterBarProps,
162
173
  type FilterChip,
@@ -181,6 +192,7 @@ import {
181
192
  type DescriptionListItem,
182
193
  type StaticTableProps,
183
194
  type StaticTableColumn,
195
+ type StaticTableDensity,
184
196
  type AspectRatioProps,
185
197
  type ItemListProps,
186
198
  type ItemListEntry,
@@ -253,6 +265,7 @@ import {
253
265
  type CommandMode,
254
266
  type CommandItemOptions,
255
267
  type ResizableProps,
268
+ type ResizableFill,
256
269
  type ResizableOrientation,
257
270
  type ResizablePanelProps,
258
271
  type ResizableHandleProps,
@@ -494,7 +507,10 @@ export type {
494
507
  ButtonVariant,
495
508
  ButtonSize,
496
509
  LabelProps,
510
+ LabelTone,
511
+ LabelSize,
497
512
  InputProps,
513
+ FieldWidth,
498
514
  CheckboxProps,
499
515
  BadgeProps,
500
516
  LinkProps,
@@ -555,6 +571,7 @@ export type {
555
571
  AvatarProps,
556
572
  SkeletonProps,
557
573
  SpinnerProps,
574
+ SpinnerSize,
558
575
  ProgressProps,
559
576
  SeparatorProps,
560
577
  IconProps,
@@ -931,6 +948,19 @@ export function empty(props: EmptyProps, footer?: () => void): Element {
931
948
  return emptyFactory(props, footer);
932
949
  }
933
950
 
951
+ /** Page title + optional description. Prefer over stacked muted labels. */
952
+ export function pageHeading(props: PageHeadingProps, trailing?: () => void): Element {
953
+ return pageHeadingFactory(props, trailing);
954
+ }
955
+
956
+ /**
957
+ * Explicit space between siblings. Default orientation is horizontal (width).
958
+ * Prefer parent `gap` for even stacks; use spacer for uneven breaks.
959
+ */
960
+ export function spacer(props?: SpacerProps): Element {
961
+ return spacerFactory(props);
962
+ }
963
+
934
964
  /** Standalone pager. See {@link PaginationProps}. */
935
965
  export function pagination(props?: PaginationProps): Element {
936
966
  return paginationFactory(props);
@@ -1789,6 +1819,8 @@ export const ui = {
1789
1819
  feedList,
1790
1820
  buttonGroup,
1791
1821
  empty,
1822
+ pageHeading,
1823
+ spacer,
1792
1824
  pagination,
1793
1825
  filterBar,
1794
1826
  filterChips,