@close-by/clay 0.2.11 → 0.2.12
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/ops-patterns.md +23 -6
- package/package.json +5 -5
- package/src/index.ts +18 -0
package/docs/ops-patterns.md
CHANGED
|
@@ -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',
|
|
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.
|
|
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.
|
|
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…'
|
|
167
|
+
ui.label('Loading…', { tone: 'muted', size: 'xs' });
|
|
167
168
|
return;
|
|
168
169
|
}
|
|
169
170
|
if (!live.hasMore) return;
|
|
@@ -183,6 +184,22 @@ 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
|
+
|
|
201
|
+
`className` remains an escape hatch.
|
|
202
|
+
|
|
186
203
|
## Logs / traces — sensitive bodies
|
|
187
204
|
|
|
188
205
|
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.
|
|
3
|
+
"version": "0.2.12",
|
|
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.
|
|
41
|
-
"@close-by/clay-core": "0.2.
|
|
42
|
-
"@close-by/clay-components": "0.2.
|
|
43
|
-
"@close-by/clay-server": "0.2.
|
|
40
|
+
"@close-by/clay-compiler": "0.2.12",
|
|
41
|
+
"@close-by/clay-core": "0.2.12",
|
|
42
|
+
"@close-by/clay-components": "0.2.12",
|
|
43
|
+
"@close-by/clay-server": "0.2.12",
|
|
44
44
|
"@tailwindcss/cli": "^4.3.3",
|
|
45
45
|
"tailwindcss": "^4.3.3"
|
|
46
46
|
}
|
package/src/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
pagination as paginationFactory,
|
|
35
35
|
filterBar as filterBarFactory,
|
|
36
36
|
filterChips as filterChipsFactory,
|
|
37
|
+
pageHeading as pageHeadingFactory,
|
|
37
38
|
numberField as numberFieldFactory,
|
|
38
39
|
phoneInput as phoneInputFactory,
|
|
39
40
|
field as fieldFactory,
|
|
@@ -120,7 +121,10 @@ import {
|
|
|
120
121
|
type ButtonVariant,
|
|
121
122
|
type ButtonSize,
|
|
122
123
|
type LabelProps,
|
|
124
|
+
type LabelTone,
|
|
125
|
+
type LabelSize,
|
|
123
126
|
type InputProps,
|
|
127
|
+
type FieldWidth,
|
|
124
128
|
type CheckboxProps,
|
|
125
129
|
type SwitchProps,
|
|
126
130
|
type SelectProps,
|
|
@@ -144,6 +148,7 @@ import {
|
|
|
144
148
|
type BadgeProps,
|
|
145
149
|
type AlertProps,
|
|
146
150
|
type SpinnerProps,
|
|
151
|
+
type SpinnerSize,
|
|
147
152
|
type ProgressProps,
|
|
148
153
|
type SeparatorProps,
|
|
149
154
|
type IconProps,
|
|
@@ -157,6 +162,8 @@ import {
|
|
|
157
162
|
type ButtonGroupProps,
|
|
158
163
|
type ButtonGroupOrientation,
|
|
159
164
|
type EmptyProps,
|
|
165
|
+
type EmptyDensity,
|
|
166
|
+
type PageHeadingProps,
|
|
160
167
|
type PaginationProps,
|
|
161
168
|
type FilterBarProps,
|
|
162
169
|
type FilterChip,
|
|
@@ -253,6 +260,7 @@ import {
|
|
|
253
260
|
type CommandMode,
|
|
254
261
|
type CommandItemOptions,
|
|
255
262
|
type ResizableProps,
|
|
263
|
+
type ResizableFill,
|
|
256
264
|
type ResizableOrientation,
|
|
257
265
|
type ResizablePanelProps,
|
|
258
266
|
type ResizableHandleProps,
|
|
@@ -494,7 +502,10 @@ export type {
|
|
|
494
502
|
ButtonVariant,
|
|
495
503
|
ButtonSize,
|
|
496
504
|
LabelProps,
|
|
505
|
+
LabelTone,
|
|
506
|
+
LabelSize,
|
|
497
507
|
InputProps,
|
|
508
|
+
FieldWidth,
|
|
498
509
|
CheckboxProps,
|
|
499
510
|
BadgeProps,
|
|
500
511
|
LinkProps,
|
|
@@ -555,6 +566,7 @@ export type {
|
|
|
555
566
|
AvatarProps,
|
|
556
567
|
SkeletonProps,
|
|
557
568
|
SpinnerProps,
|
|
569
|
+
SpinnerSize,
|
|
558
570
|
ProgressProps,
|
|
559
571
|
SeparatorProps,
|
|
560
572
|
IconProps,
|
|
@@ -931,6 +943,11 @@ export function empty(props: EmptyProps, footer?: () => void): Element {
|
|
|
931
943
|
return emptyFactory(props, footer);
|
|
932
944
|
}
|
|
933
945
|
|
|
946
|
+
/** Page title + optional description. Prefer over stacked muted labels. */
|
|
947
|
+
export function pageHeading(props: PageHeadingProps, trailing?: () => void): Element {
|
|
948
|
+
return pageHeadingFactory(props, trailing);
|
|
949
|
+
}
|
|
950
|
+
|
|
934
951
|
/** Standalone pager. See {@link PaginationProps}. */
|
|
935
952
|
export function pagination(props?: PaginationProps): Element {
|
|
936
953
|
return paginationFactory(props);
|
|
@@ -1789,6 +1806,7 @@ export const ui = {
|
|
|
1789
1806
|
feedList,
|
|
1790
1807
|
buttonGroup,
|
|
1791
1808
|
empty,
|
|
1809
|
+
pageHeading,
|
|
1792
1810
|
pagination,
|
|
1793
1811
|
filterBar,
|
|
1794
1812
|
filterChips,
|