@close-by/clay 0.1.0 → 0.2.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.
- package/package.json +1 -1
- package/src/client-dir.ts +34 -0
- package/src/index.ts +86 -1
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resolve Vite client assets for `ui.run({ clientDir })`.
|
|
8
|
+
*
|
|
9
|
+
* Preference order:
|
|
10
|
+
* 1. Explicit `fromDir` (tests / advanced)
|
|
11
|
+
* 2. `@close-by/clay-cli/client-dist` when the CLI package is installed
|
|
12
|
+
* 3. Monorepo `packages/client/dist` (dev) relative to this module
|
|
13
|
+
*
|
|
14
|
+
* Prefer this over hardcoding `node_modules/@close-by/clay-cli/client-dist`.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveClayClientDir(fromDir?: string): string {
|
|
17
|
+
if (fromDir) {
|
|
18
|
+
const shipped = join(fromDir, '../client-dist');
|
|
19
|
+
if (existsSync(join(shipped, 'index.html'))) return shipped;
|
|
20
|
+
return join(fromDir, '../../client/dist');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const pkgJson = require.resolve('@close-by/clay-cli/package.json');
|
|
26
|
+
const shipped = join(dirname(pkgJson), 'client-dist');
|
|
27
|
+
if (existsSync(join(shipped, 'index.html'))) return shipped;
|
|
28
|
+
} catch {
|
|
29
|
+
// CLI not installed — fall through
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Monorepo: packages/ui/src → packages/client/dist
|
|
33
|
+
return join(fileURLToPath(new URL('.', import.meta.url)), '../../client/dist');
|
|
34
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
button as buttonFactory,
|
|
3
|
+
iconButton as iconButtonFactory,
|
|
3
4
|
label as labelFactory,
|
|
4
5
|
input as inputFactory,
|
|
5
6
|
checkbox as checkboxFactory,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
slider as sliderFactory,
|
|
15
16
|
textArea as textAreaFactory,
|
|
16
17
|
link as linkFactory,
|
|
18
|
+
externalLink as externalLinkFactory,
|
|
17
19
|
badge as badgeFactory,
|
|
18
20
|
alert as alertFactory,
|
|
19
21
|
spinner as spinnerFactory,
|
|
@@ -84,6 +86,9 @@ import {
|
|
|
84
86
|
ai as aiNamespace,
|
|
85
87
|
AiChatElement,
|
|
86
88
|
type ButtonProps,
|
|
89
|
+
type IconButtonProps,
|
|
90
|
+
type ButtonVariant,
|
|
91
|
+
type ButtonSize,
|
|
87
92
|
type LabelProps,
|
|
88
93
|
type InputProps,
|
|
89
94
|
type CheckboxProps,
|
|
@@ -190,6 +195,7 @@ import {
|
|
|
190
195
|
type ChooseOption,
|
|
191
196
|
type AppProps,
|
|
192
197
|
type AppNavItem,
|
|
198
|
+
type AppPrimaryAction,
|
|
193
199
|
type AppUser,
|
|
194
200
|
type MarkdownProps,
|
|
195
201
|
type HtmlProps,
|
|
@@ -332,6 +338,9 @@ import {
|
|
|
332
338
|
download as downloadCore,
|
|
333
339
|
clipboard as clipboardCore,
|
|
334
340
|
runJavaScript as runJavaScriptCore,
|
|
341
|
+
getUrlHash as getUrlHashCore,
|
|
342
|
+
setUrlHash as setUrlHashCore,
|
|
343
|
+
openExternal as openExternalCore,
|
|
335
344
|
scroll as scrollCore,
|
|
336
345
|
timer as timerCore,
|
|
337
346
|
storage as storageCore,
|
|
@@ -373,8 +382,20 @@ import {
|
|
|
373
382
|
type PageMeta,
|
|
374
383
|
type NavFromPagesOptions,
|
|
375
384
|
} from './pages';
|
|
385
|
+
import { resolveClayClientDir } from './client-dir';
|
|
386
|
+
|
|
387
|
+
export { resolveClayClientDir } from './client-dir';
|
|
376
388
|
|
|
377
389
|
export type {
|
|
390
|
+
ButtonProps,
|
|
391
|
+
IconButtonProps,
|
|
392
|
+
ButtonVariant,
|
|
393
|
+
ButtonSize,
|
|
394
|
+
LabelProps,
|
|
395
|
+
InputProps,
|
|
396
|
+
CheckboxProps,
|
|
397
|
+
BadgeProps,
|
|
398
|
+
LinkProps,
|
|
378
399
|
DataTableProps,
|
|
379
400
|
DataTableAction,
|
|
380
401
|
DataTableView,
|
|
@@ -433,6 +454,7 @@ export type {
|
|
|
433
454
|
ChooseOption,
|
|
434
455
|
AppProps,
|
|
435
456
|
AppNavItem,
|
|
457
|
+
AppPrimaryAction,
|
|
436
458
|
AppUser,
|
|
437
459
|
MarkdownProps,
|
|
438
460
|
HtmlProps,
|
|
@@ -584,6 +606,11 @@ export function button(text?: string, props?: Omit<ButtonProps, 'text'>): Elemen
|
|
|
584
606
|
return buttonFactory(text, props);
|
|
585
607
|
}
|
|
586
608
|
|
|
609
|
+
/** Button with a Lucide icon (label optional). Prefer `ui.iconButton`. See {@link IconButtonProps}. */
|
|
610
|
+
export function iconButton(props: IconButtonProps): Element {
|
|
611
|
+
return iconButtonFactory(props);
|
|
612
|
+
}
|
|
613
|
+
|
|
587
614
|
/** Text input. Prefer `ui.input`. See {@link InputProps}. */
|
|
588
615
|
export function input(props?: InputProps): Element {
|
|
589
616
|
return inputFactory(props);
|
|
@@ -654,11 +681,44 @@ export function link(text: string, href: string, props?: Omit<LinkProps, 'href'
|
|
|
654
681
|
return linkFactory(text, href, props);
|
|
655
682
|
}
|
|
656
683
|
|
|
684
|
+
/** Open `url` in a new tab (`target=_blank`). Prefer `ui.externalLink`. */
|
|
685
|
+
export function externalLink(
|
|
686
|
+
text: string,
|
|
687
|
+
url: string,
|
|
688
|
+
props?: Omit<LinkProps, 'href' | 'text' | 'external'>,
|
|
689
|
+
): Element {
|
|
690
|
+
return externalLinkFactory(text, url, props);
|
|
691
|
+
}
|
|
692
|
+
|
|
657
693
|
/** Small status badge. Prefer `ui.badge`. See {@link BadgeProps}. */
|
|
658
694
|
export function badge(text?: string, props?: Omit<BadgeProps, 'text'>): Element {
|
|
659
695
|
return badgeFactory(text, props);
|
|
660
696
|
}
|
|
661
697
|
|
|
698
|
+
/**
|
|
699
|
+
* Icon button that copies `content` via `ui.clipboard` and notifies on success.
|
|
700
|
+
* Prefer over `navigator.clipboard` in page code.
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* ui.copyButton(orderId);
|
|
704
|
+
* ui.copyButton(orderId, { label: 'Copy id', size: 'sm' });
|
|
705
|
+
*/
|
|
706
|
+
export function copyButton(
|
|
707
|
+
content: string,
|
|
708
|
+
props: Omit<IconButtonProps, 'icon' | 'onClick'> & { notifyMessage?: string } = {},
|
|
709
|
+
): Element {
|
|
710
|
+
const { notifyMessage, label, ...rest } = props;
|
|
711
|
+
return iconButtonFactory({
|
|
712
|
+
...rest,
|
|
713
|
+
icon: 'copy',
|
|
714
|
+
label,
|
|
715
|
+
onClick: () => {
|
|
716
|
+
clipboardCore(content);
|
|
717
|
+
notifyCore(notifyMessage ?? 'Copied', 'success');
|
|
718
|
+
},
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
|
|
662
722
|
/** Inline alert banner. Prefer `ui.alert`. See {@link AlertProps}. */
|
|
663
723
|
export function alert(message?: string, props?: Omit<AlertProps, 'message'>): Element {
|
|
664
724
|
return alertFactory(message, props);
|
|
@@ -679,7 +739,7 @@ export function separator(props?: SeparatorProps): Element {
|
|
|
679
739
|
return separatorFactory(props);
|
|
680
740
|
}
|
|
681
741
|
|
|
682
|
-
/** Lucide icon by name. Prefer `ui.icon`. See {@link IconProps}. */
|
|
742
|
+
/** Lucide icon by kebab-case name (full set in client). Prefer `ui.icon`. See {@link IconProps}. */
|
|
683
743
|
export function icon(name: string, props?: Omit<IconProps, 'name'>): Element {
|
|
684
744
|
return iconFactory(name, props);
|
|
685
745
|
}
|
|
@@ -1177,6 +1237,21 @@ export function clipboard(content: string): void {
|
|
|
1177
1237
|
clipboardCore(content);
|
|
1178
1238
|
}
|
|
1179
1239
|
|
|
1240
|
+
/** URL hash without `#` (from hello / last `setUrlHash`). Prefer over `window.location`. */
|
|
1241
|
+
export function getUrlHash(): string {
|
|
1242
|
+
return getUrlHashCore();
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/** Set the browser URL hash. Prefer over `window.history` / `location.hash`. */
|
|
1246
|
+
export function setUrlHash(hash: string): void {
|
|
1247
|
+
setUrlHashCore(hash);
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/** Open a URL in a new tab. Prefer over `runJavaScript('window.open…')`. */
|
|
1251
|
+
export function openExternal(url: string): void {
|
|
1252
|
+
openExternalCore(url);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1180
1255
|
/** Run trusted JavaScript in the connected browser. */
|
|
1181
1256
|
export function runJavaScript(code: string): void {
|
|
1182
1257
|
runJavaScriptCore(code);
|
|
@@ -1295,6 +1370,10 @@ export function run(rootOrConfig: PageFn | RunConfig = {}, config: RunConfig = {
|
|
|
1295
1370
|
corePage('/', root);
|
|
1296
1371
|
}
|
|
1297
1372
|
|
|
1373
|
+
if (!cfg.clientDir) {
|
|
1374
|
+
cfg = { ...cfg, clientDir: resolveClayClientDir() };
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1298
1377
|
const { app: appProps, ...serverConfig } = cfg;
|
|
1299
1378
|
if (appProps) {
|
|
1300
1379
|
setPageWrapper((pageFn) => app(appProps, pageFn));
|
|
@@ -1311,6 +1390,7 @@ export function run(rootOrConfig: PageFn | RunConfig = {}, config: RunConfig = {
|
|
|
1311
1390
|
export const ui = {
|
|
1312
1391
|
label,
|
|
1313
1392
|
button,
|
|
1393
|
+
iconButton,
|
|
1314
1394
|
input,
|
|
1315
1395
|
checkbox,
|
|
1316
1396
|
switch: switch_,
|
|
@@ -1324,6 +1404,8 @@ export const ui = {
|
|
|
1324
1404
|
slider,
|
|
1325
1405
|
textArea,
|
|
1326
1406
|
link,
|
|
1407
|
+
externalLink,
|
|
1408
|
+
copyButton,
|
|
1327
1409
|
badge,
|
|
1328
1410
|
alert,
|
|
1329
1411
|
spinner,
|
|
@@ -1399,6 +1481,9 @@ export const ui = {
|
|
|
1399
1481
|
clearAuthSession,
|
|
1400
1482
|
download,
|
|
1401
1483
|
clipboard,
|
|
1484
|
+
getUrlHash,
|
|
1485
|
+
setUrlHash,
|
|
1486
|
+
openExternal,
|
|
1402
1487
|
runJavaScript,
|
|
1403
1488
|
scroll,
|
|
1404
1489
|
timer,
|