@pihanga2/shadcn 0.2.5 → 0.2.6
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/AGENT.building-cards.md +87 -0
- package/AGENT.using-cards.md +47 -0
- package/README.md +5 -1
- package/cards/avatar/avatar.component.d.ts +11 -0
- package/cards/avatar/avatar.component.js +26 -0
- package/cards/avatar/avatar.component.js.map +1 -0
- package/cards/avatar/avatar.types.d.ts +46 -0
- package/cards/avatar/avatar.types.js +7 -0
- package/cards/avatar/avatar.types.js.map +1 -0
- package/cards/avatar/index.d.ts +1 -0
- package/cards/avatar/index.js +12 -0
- package/cards/avatar/index.js.map +1 -0
- package/cards/badge/badge.component.js +4 -4
- package/cards/codeMirror/codeMirror.component.d.ts +4 -0
- package/cards/codeMirror/codeMirror.types.d.ts +83 -0
- package/cards/codeMirror/index.d.ts +1 -0
- package/cards/dataTable/dataTable.component.js +43 -42
- package/cards/dataTable/dataTable.component.js.map +1 -1
- package/cards/dataTable/dataTable.types.d.ts +26 -2
- package/cards/dataTable/dataTable.types.js +1 -0
- package/cards/dataTable/dataTable.types.js.map +1 -1
- package/cards/drawer/drawer.component.d.ts +4 -0
- package/cards/drawer/drawer.component.js +83 -0
- package/cards/drawer/drawer.component.js.map +1 -0
- package/cards/drawer/drawer.types.d.ts +95 -0
- package/cards/drawer/drawer.types.js +11 -0
- package/cards/drawer/drawer.types.js.map +1 -0
- package/cards/drawer/index.d.ts +1 -0
- package/cards/drawer/index.js +13 -0
- package/cards/drawer/index.js.map +1 -0
- package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
- package/cards/emptyCard/index.d.ts +7 -0
- package/cards/fileDrop/fileDrop.component.js +1 -1
- package/cards/fileDrop/fileDrop.css +1 -0
- package/cards/graphin/eventDispatcher.component.d.ts +2 -1
- package/cards/graphin/graphin.types.d.ts +14 -0
- package/cards/jsonViewer/jsonViewer.component.js +1 -1
- package/cards/jsonViewer/jsonViewer.css +1 -0
- package/cards/list/list.component.js +21 -21
- package/cards/loadingOverlay/loadingOverlay.component.js +1 -1
- package/cards/loadingOverlay/loadingOverlay.css +1 -0
- package/cards/pageWithNavbar/pageWithNavbar.component.js +1 -1
- package/cards/pageWithNavbar/pageWithNavbar.css +1 -0
- package/cards/pageWithNavbarMeta/index.d.ts +1 -0
- package/cards/pageWithNavbarMeta/index.js +118 -0
- package/cards/pageWithNavbarMeta/index.js.map +1 -0
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.d.ts +78 -0
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js +7 -0
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js.map +1 -0
- package/cards/pasteTarget/pasteTarget.component.js +1 -1
- package/cards/pasteTarget/pasteTarget.css +1 -0
- package/cards/scrollbarWithAnnotations/index.d.ts +1 -0
- package/cards/scrollbarWithAnnotations/index.js +13 -0
- package/cards/scrollbarWithAnnotations/index.js.map +1 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.d.ts +23 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js +78 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js.map +1 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.css +1 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.d.ts +123 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js +7 -0
- package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js.map +1 -0
- package/cards/slider/slider.component.js +67 -48
- package/cards/slider/slider.component.js.map +1 -1
- package/cards/slider/slider.types.d.ts +31 -0
- package/cards/slider/slider.types.js.map +1 -1
- package/cards/stepper/stepper.component.js +1 -1
- package/cards/stepper/stepper.css +1 -0
- package/components/ui/avatar.js +5 -5
- package/components/ui/badge.js +7 -7
- package/components/ui/button.js +6 -6
- package/components/ui/drawer.js +79 -0
- package/components/ui/drawer.js.map +1 -0
- package/components/ui/field.js +16 -16
- package/components/ui/label.js +3 -3
- package/components/ui/separator.js +1 -1
- package/components/ui/toggle-group.js +5 -5
- package/components/ui/toggle.js +2 -2
- package/lib/utils.d.ts +15 -0
- package/lib/utils.js.map +1 -1
- package/package.json +28 -3
- package/pihanga-shadcn.css +0 -2
package/AGENT.building-cards.md
CHANGED
|
@@ -268,6 +268,93 @@ This string must match the `name` passed to `registerCardComponent` and the
|
|
|
268
268
|
|
|
269
269
|
### 2 — Define Props and Events (`*.types.ts`)
|
|
270
270
|
|
|
271
|
+
> **Rule: Card Props must only contain basic data types.**
|
|
272
|
+
>
|
|
273
|
+
> All props in a `CardProps` type must be JSON-serialisable primitives
|
|
274
|
+
> (`string`, `number`, `boolean`, `null`) or plain objects / arrays composed
|
|
275
|
+
> exclusively of those primitives. **Never put library interfaces, class
|
|
276
|
+
> instances, or opaque objects (e.g. `StreamParser`, `Extension[]`, `RegExp`,
|
|
277
|
+
> `Date`) directly in a props type.** Pihanga serialises card state through
|
|
278
|
+
> Redux; non-serialisable values break time-travel debugging, HMR, and the
|
|
279
|
+
> playground.
|
|
280
|
+
>
|
|
281
|
+
> When a card genuinely needs a complex third-party value (a parser, a theme
|
|
282
|
+
> extension, a set of keymaps…) use the **registry pattern** described below.
|
|
283
|
+
|
|
284
|
+
#### Registry pattern for complex prop values
|
|
285
|
+
|
|
286
|
+
1. **Create a module-level registry** (a plain `Map`) keyed by a `string`.
|
|
287
|
+
2. **Export a `register*` function** so callers can inject their value before
|
|
288
|
+
mounting the card.
|
|
289
|
+
3. **Use the string key as the prop** — the component looks the value up at
|
|
290
|
+
render time.
|
|
291
|
+
|
|
292
|
+
**Example — `StreamParser` for the CodeMirror card:**
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
// codeMirror.types.ts (public API)
|
|
296
|
+
|
|
297
|
+
/** Keys are arbitrary caller-chosen strings; values are StreamParsers. */
|
|
298
|
+
const streamParserRegistry = new Map<string, StreamParser<unknown>>();
|
|
299
|
+
|
|
300
|
+
/** Call this once at app initialisation time, before the card is rendered. */
|
|
301
|
+
export function registerStreamParser(key: string, parser: StreamParser<unknown>) {
|
|
302
|
+
streamParserRegistry.set(key, parser);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Internal — used only by the component. */
|
|
306
|
+
export function resolveStreamParser(key: string): StreamParser<unknown> | undefined {
|
|
307
|
+
return streamParserRegistry.get(key);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export type CodeMirrorCardProps = {
|
|
311
|
+
value?: string;
|
|
312
|
+
readOnly?: boolean;
|
|
313
|
+
/**
|
|
314
|
+
* Key of a StreamParser previously registered with `registerStreamParser()`.
|
|
315
|
+
* @example
|
|
316
|
+
* import { python } from "@codemirror/legacy-modes/mode/python";
|
|
317
|
+
* registerStreamParser("python", python);
|
|
318
|
+
* CodeMirrorCard({ streamLanguage: "python", value: "print('hello')" });
|
|
319
|
+
*/
|
|
320
|
+
streamLanguage?: string; // ✅ plain string — not StreamParser<unknown>
|
|
321
|
+
extensionsKey?: string; // ✅ plain string — not Extension[]
|
|
322
|
+
};
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
// At app initialisation (e.g. app.pihanga.ts or a dedicated setup file):
|
|
327
|
+
import { python } from "@codemirror/legacy-modes/mode/python";
|
|
328
|
+
import { registerStreamParser } from "@pihanga2/shadcn/codeMirror";
|
|
329
|
+
|
|
330
|
+
registerStreamParser("python", python);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
// codeMirror.component.tsx — look up at render time:
|
|
335
|
+
import { resolveStreamParser } from "./codeMirror.types";
|
|
336
|
+
|
|
337
|
+
const parser = props.streamLanguage
|
|
338
|
+
? resolveStreamParser(props.streamLanguage)
|
|
339
|
+
: undefined;
|
|
340
|
+
const extensions = parser ? [StreamLanguage.define(parser)] : [];
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The same pattern applies to **`Extension[]`** or any other opaque type.
|
|
344
|
+
Register a named bundle of extensions once; reference it by key in props.
|
|
345
|
+
|
|
346
|
+
**Quick checklist:**
|
|
347
|
+
|
|
348
|
+
| Prop value | Allowed directly in Props? | Alternative |
|
|
349
|
+
|---|---|---|
|
|
350
|
+
| `string`, `number`, `boolean` | ✅ | — |
|
|
351
|
+
| Plain `Record<string, string>` | ✅ | — |
|
|
352
|
+
| `StreamParser<T>`, `Extension` | ❌ | Registry pattern (string key) |
|
|
353
|
+
| `RegExp` | ❌ | Pass `string`; compile inside component |
|
|
354
|
+
| `Date` | ❌ | Pass ISO string; parse inside component |
|
|
355
|
+
| React component / function | ❌ | Reference an existing card type string |
|
|
356
|
+
|
|
357
|
+
|
|
271
358
|
A typical types file has five parts:
|
|
272
359
|
|
|
273
360
|
#### a) Card declaration factory
|
package/AGENT.using-cards.md
CHANGED
|
@@ -336,6 +336,7 @@ Or activate everything at once: `import "@pihanga2/shadcn"`.
|
|
|
336
336
|
| dialog | `/r/dialog` | ✅ | |
|
|
337
337
|
| dropDownMenu | `/r/dropDownMenu` | ✅ | |
|
|
338
338
|
| field | `/r/field` | ✅ | |
|
|
339
|
+
| fileDrop | `/r/fileDrop` | ✅ | drag-and-drop file upload |
|
|
339
340
|
| flexGrid | `/r/flexGrid` | ✅ | |
|
|
340
341
|
| form | `/r/form` | ✅ | |
|
|
341
342
|
| framework | `/r/framework` | ✅ | App root |
|
|
@@ -384,6 +385,18 @@ Full registry index: `https://ivcap-works.github.io/pihanga-shadcn/r/registry.js
|
|
|
384
385
|
- `graphin`, `jsonViewer`, `markdownViewer`, `resizable` are not in the npm
|
|
385
386
|
package — use the registry for those.
|
|
386
387
|
- Point Tailwind at `node_modules/@pihanga2/shadcn/dist-lib` to scan classes.
|
|
388
|
+
- **Import types from the card index, not deep sub-paths.** The exports map
|
|
389
|
+
only exposes `@pihanga2/shadcn/cards/<card>` — every type from
|
|
390
|
+
`<card>.types.ts` is re-exported there. Deep paths like
|
|
391
|
+
`@pihanga2/shadcn/cards/fileDrop/fileDrop.types` are blocked by Node/Vite:
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
// ❌ Deep sub-path — blocked by exports map, even if the .d.ts exists on disk
|
|
395
|
+
import type {FileDropProps} from "@pihanga2/shadcn/cards/fileDrop/fileDrop.types";
|
|
396
|
+
|
|
397
|
+
// ✅ Correct — all types re-exported from the card index
|
|
398
|
+
import type {FileDropProps} from "@pihanga2/shadcn/cards/fileDrop";
|
|
399
|
+
```
|
|
387
400
|
|
|
388
401
|
**Both channels:**
|
|
389
402
|
- After activation, app-wiring APIs (`registerCard`, `registerFramework`,
|
|
@@ -1187,3 +1200,37 @@ yarn alternative or Node version constraint.
|
|
|
1187
1200
|
| No `yarn dlx` alternative documented | Added `yarn dlx shadcn@latest` as the yarn-compatible alternative in the distribution channels table, Channel 1 init step, and "Adding individual cards" commands |
|
|
1188
1201
|
| No warning about npm 11 + Node 24 incompatibility | Added a prominent compatibility callout at the top of *Channel 1 — shadcn registry prerequisites*, with the `nvm use 22` workaround and the `yarn dlx` alternative |
|
|
1189
1202
|
| "Notes for AI agents" section did not mention the `npx` breakage | Added a bullet noting that `npx` fails on npm 11 + Node 24 and that `yarn dlx shadcn@latest` is a drop-in replacement |
|
|
1203
|
+
|
|
1204
|
+
### 2026-07 user feedback — `fileDrop` import fails from `@pihanga2/shadcn@0.2.0`
|
|
1205
|
+
|
|
1206
|
+
Users on `@pihanga2/shadcn@0.2.0` reported two compounding errors when importing
|
|
1207
|
+
the `fileDrop` card:
|
|
1208
|
+
|
|
1209
|
+
1. `./cards/fileDrop` was absent from the `exports` map in the published
|
|
1210
|
+
`package.json` — Node/TypeScript/Vite block any unlisted sub-path even when
|
|
1211
|
+
the file physically exists on disk.
|
|
1212
|
+
2. The `cards/fileDrop/` directory contained only `.d.ts` type stubs — no `.js`
|
|
1213
|
+
runtime files — because `fileDrop` was type-stubbed before the `0.2.0` publish
|
|
1214
|
+
and the build was never re-run to include it.
|
|
1215
|
+
|
|
1216
|
+
**Resolution:** `@pihanga2/shadcn@0.2.5` ships `fileDrop` correctly (`.js` +
|
|
1217
|
+
`.d.ts` + exports map entry). **Upgrade to `>=0.2.5`.**
|
|
1218
|
+
|
|
1219
|
+
```sh
|
|
1220
|
+
npm install @pihanga2/shadcn@latest
|
|
1221
|
+
# or:
|
|
1222
|
+
yarn add @pihanga2/shadcn@latest
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
A second mistake was also identified: users attempted to import types from the
|
|
1226
|
+
deep sub-path `@pihanga2/shadcn/cards/fileDrop/fileDrop.types`, which is NOT
|
|
1227
|
+
listed in the exports map and is therefore blocked. All types from `fileDrop.types`
|
|
1228
|
+
are re-exported from the card index — use the card index path instead (see
|
|
1229
|
+
*Notes for AI agents → npm channel* above).
|
|
1230
|
+
|
|
1231
|
+
| Root cause | Fix applied |
|
|
1232
|
+
|---|---|
|
|
1233
|
+
| `fileDrop` added to `core-cards.json` after `@pihanga2/shadcn@0.2.0` was published; package not rebuilt | Fixed in `@pihanga2/shadcn@0.2.5` — `fileDrop` is now fully built and in the exports map |
|
|
1234
|
+
| `react-drag-drop-files` mislabelled in `vite.lib.config.ts` as an "excluded-card guard" dep instead of a legitimate runtime dep | Moved to the runtime deps section with clarifying comment |
|
|
1235
|
+
| `fileDrop` missing from the Available cards table | Added to table |
|
|
1236
|
+
| No documentation that deep sub-path imports (`/cards/fileDrop/fileDrop.types`) are blocked | Added explicit ❌/✅ example to *Notes for AI agents → npm channel* |
|
package/README.md
CHANGED
|
@@ -62,8 +62,9 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
|
-
## Included cards (
|
|
65
|
+
## Included cards (39)
|
|
66
66
|
|
|
67
|
+
- `avatar`
|
|
67
68
|
- `badge`
|
|
68
69
|
- `box`
|
|
69
70
|
- `button`
|
|
@@ -71,6 +72,7 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
71
72
|
- `conditional`
|
|
72
73
|
- `dataTable`
|
|
73
74
|
- `dialog`
|
|
75
|
+
- `drawer`
|
|
74
76
|
- `dropDownMenu`
|
|
75
77
|
- `field`
|
|
76
78
|
- `fileDrop`
|
|
@@ -86,8 +88,10 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
86
88
|
- `modeToggle`
|
|
87
89
|
- `navbarSearch`
|
|
88
90
|
- `pageWithNavbar`
|
|
91
|
+
- `pageWithNavbarMeta`
|
|
89
92
|
- `pasteTarget`
|
|
90
93
|
- `resizable`
|
|
94
|
+
- `scrollbarWithAnnotations`
|
|
91
95
|
- `select`
|
|
92
96
|
- `slider`
|
|
93
97
|
- `sliderValue`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PiCardProps } from '@pihanga2/core';
|
|
2
|
+
import { AvatarCardProps } from './avatar.types';
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
/**
|
|
5
|
+
* `shad/avatar` card component.
|
|
6
|
+
*
|
|
7
|
+
* Renders a shadcn `<Avatar>` with an optional image and a text fallback.
|
|
8
|
+
* The avatar degrades gracefully: if `src` is absent or the image fails to
|
|
9
|
+
* load, the `fallback` initials are shown inside a muted circle.
|
|
10
|
+
*/
|
|
11
|
+
export declare const AvatarComponent: (props: PiCardProps<AvatarCardProps>) => React.ReactNode;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { cn as e } from "../../lib/utils.js";
|
|
2
|
+
import { Avatar as t, AvatarFallback as n, AvatarImage as r } from "../../components/ui/avatar.js";
|
|
3
|
+
import "react";
|
|
4
|
+
import "@pihanga2/core";
|
|
5
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
|
+
//#region src/cards/avatar/avatar.component.tsx
|
|
7
|
+
var o = {
|
|
8
|
+
sm: "size-6 text-xs",
|
|
9
|
+
md: "size-8 text-xs",
|
|
10
|
+
lg: "size-12 text-sm",
|
|
11
|
+
xl: "size-16 text-base"
|
|
12
|
+
}, s = (s) => {
|
|
13
|
+
let { src: c, alt: l = "", fallback: u, size: d = "md", className: f, cardName: p } = s;
|
|
14
|
+
return /* @__PURE__ */ a(t, {
|
|
15
|
+
className: e(o[d], f),
|
|
16
|
+
"data-pihanga": p,
|
|
17
|
+
children: [c && /* @__PURE__ */ i(r, {
|
|
18
|
+
src: c,
|
|
19
|
+
alt: l
|
|
20
|
+
}), /* @__PURE__ */ i(n, { children: u ?? l.slice(0, 2).toUpperCase() })]
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { s as AvatarComponent };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=avatar.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar.component.js","names":[],"sources":["../../../src/cards/avatar/avatar.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Avatar, AvatarFallback, AvatarImage} from \"@/components/ui/avatar\";\nimport {cn} from \"@/lib/utils\";\nimport type {AvatarCardProps, AvatarSize} from \"./avatar.types\";\n\nconst SIZE_CLASS: Record<AvatarSize, string> = {\n sm: \"size-6 text-xs\",\n md: \"size-8 text-xs\",\n lg: \"size-12 text-sm\",\n xl: \"size-16 text-base\",\n};\n\n/**\n * `shad/avatar` card component.\n *\n * Renders a shadcn `<Avatar>` with an optional image and a text fallback.\n * The avatar degrades gracefully: if `src` is absent or the image fails to\n * load, the `fallback` initials are shown inside a muted circle.\n */\nexport const AvatarComponent = (\n props: PiCardProps<AvatarCardProps>,\n): React.ReactNode => {\n const {src, alt = \"\", fallback, size = \"md\", className, cardName} = props;\n\n return (\n <Avatar className={cn(SIZE_CLASS[size], className)} data-pihanga={cardName}>\n {src && <AvatarImage src={src} alt={alt} />}\n <AvatarFallback>\n {fallback ?? alt.slice(0, 2).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n );\n};\n"],"mappings":";;;;;;AAMA,IAAM,IAAyC;CAC7C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GASa,KACX,MACoB;CACpB,IAAM,EAAC,QAAK,SAAM,IAAI,aAAU,UAAO,MAAM,cAAW,gBAAY;CAEpE,OACE,kBAAC,GAAD;EAAQ,WAAW,EAAG,EAAW,IAAO,CAAS;EAAG,gBAAc;YAAlE,CACG,KAAO,kBAAC,GAAD;GAAkB;GAAU;EAAM,CAAA,GAC1C,kBAAC,GAAD,EAAA,UACG,KAAY,EAAI,MAAM,GAAG,CAAC,EAAE,YAAY,EAC3B,CAAA,CACV;;AAEZ"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const AVATAR_CARD = "shad/avatar";
|
|
2
|
+
/**
|
|
3
|
+
* Avatar size tokens — map to Tailwind `size-*` utilities.
|
|
4
|
+
*
|
|
5
|
+
* | Value | Tailwind | px |
|
|
6
|
+
* |--------|-----------|-----|
|
|
7
|
+
* | `"sm"` | `size-6` | 24 |
|
|
8
|
+
* | `"md"` | `size-8` | 32 |
|
|
9
|
+
* | `"lg"` | `size-12` | 48 |
|
|
10
|
+
* | `"xl"` | `size-16` | 64 |
|
|
11
|
+
*/
|
|
12
|
+
export type AvatarSize = "sm" | "md" | "lg" | "xl";
|
|
13
|
+
export type AvatarCardProps = {
|
|
14
|
+
/**
|
|
15
|
+
* URL of the avatar image.
|
|
16
|
+
* When omitted or the image fails to load, `fallback` is shown instead.
|
|
17
|
+
*/
|
|
18
|
+
src?: string;
|
|
19
|
+
/** Accessible alt text for the image. */
|
|
20
|
+
alt?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Text rendered inside the fallback circle when no image is available.
|
|
23
|
+
* Typically one or two initials, e.g. `"JD"`.
|
|
24
|
+
*/
|
|
25
|
+
fallback?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Avatar diameter.
|
|
28
|
+
* @default "md"
|
|
29
|
+
*/
|
|
30
|
+
size?: AvatarSize;
|
|
31
|
+
/** Additional Tailwind classes applied to the root `<span>` element. */
|
|
32
|
+
className?: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Factory function for declaring a `shad/avatar` card instance.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* import {ShadAvatar} from "@/cards/avatar";
|
|
39
|
+
*
|
|
40
|
+
* registerCard("myApp/userAvatar", ShadAvatar({
|
|
41
|
+
* src: memo((s: AppState) => s.user.avatarUrl),
|
|
42
|
+
* fallback: memo((s: AppState) => s.user.initials),
|
|
43
|
+
* }));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const ShadAvatar: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<AvatarCardProps, S, {}>) => import('@pihanga2/core').PiCardDef;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar.types.js","names":[],"sources":["../../../src/cards/avatar/avatar.types.ts"],"sourcesContent":["import {createCardDeclaration} from \"@pihanga2/core\";\n\nexport const AVATAR_CARD = \"shad/avatar\";\n\n/**\n * Avatar size tokens — map to Tailwind `size-*` utilities.\n *\n * | Value | Tailwind | px |\n * |--------|-----------|-----|\n * | `\"sm\"` | `size-6` | 24 |\n * | `\"md\"` | `size-8` | 32 |\n * | `\"lg\"` | `size-12` | 48 |\n * | `\"xl\"` | `size-16` | 64 |\n */\nexport type AvatarSize = \"sm\" | \"md\" | \"lg\" | \"xl\";\n\nexport type AvatarCardProps = {\n /**\n * URL of the avatar image.\n * When omitted or the image fails to load, `fallback` is shown instead.\n */\n src?: string;\n\n /** Accessible alt text for the image. */\n alt?: string;\n\n /**\n * Text rendered inside the fallback circle when no image is available.\n * Typically one or two initials, e.g. `\"JD\"`.\n */\n fallback?: string;\n\n /**\n * Avatar diameter.\n * @default \"md\"\n */\n size?: AvatarSize;\n\n /** Additional Tailwind classes applied to the root `<span>` element. */\n className?: string;\n};\n\n/**\n * Factory function for declaring a `shad/avatar` card instance.\n *\n * ```ts\n * import {ShadAvatar} from \"@/cards/avatar\";\n *\n * registerCard(\"myApp/userAvatar\", ShadAvatar({\n * src: memo((s: AppState) => s.user.avatarUrl),\n * fallback: memo((s: AppState) => s.user.initials),\n * }));\n * ```\n */\nexport const ShadAvatar = createCardDeclaration<AvatarCardProps>(AVATAR_CARD);\n"],"mappings":";;AAEA,IAAa,IAAc,eAoDd,IAAa,EAAuC,CAAW"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './avatar.types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AvatarComponent as e } from "./avatar.component.js";
|
|
2
|
+
import { AVATAR_CARD as t, ShadAvatar as n } from "./avatar.types.js";
|
|
3
|
+
import { registerCardComponent as r } from "@pihanga2/core";
|
|
4
|
+
//#region src/cards/avatar/index.ts
|
|
5
|
+
r({
|
|
6
|
+
name: t,
|
|
7
|
+
component: e
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
export { t as AVATAR_CARD, n as ShadAvatar };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/avatar/index.ts"],"sourcesContent":["import {registerCardComponent} from \"@pihanga2/core\";\n\nimport {AvatarComponent} from \"./avatar.component\";\nimport {AVATAR_CARD} from \"./avatar.types\";\n\nexport * from \"./avatar.types\";\n\nregisterCardComponent({\n name: AVATAR_CARD,\n component: AvatarComponent,\n});\n"],"mappings":";;;;AAOA,EAAsB;CACpB,MAAM;CACN,WAAW;AACb,CAAC"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { cn as e } from "../../lib/utils.js";
|
|
2
|
+
import { Badge as t } from "../../components/ui/badge.js";
|
|
3
3
|
import "react";
|
|
4
4
|
import "@pihanga2/core";
|
|
5
5
|
import { jsx as n } from "react/jsx-runtime";
|
|
6
6
|
//#region src/cards/badge/badge.component.tsx
|
|
7
7
|
var r = (r) => {
|
|
8
8
|
let { label: i, variant: a = "secondary", className: o, cardName: s } = r;
|
|
9
|
-
return /* @__PURE__ */ n(
|
|
9
|
+
return /* @__PURE__ */ n(t, {
|
|
10
10
|
variant: a,
|
|
11
|
-
className:
|
|
11
|
+
className: e(o),
|
|
12
12
|
"data-pihanga": s,
|
|
13
13
|
children: i
|
|
14
14
|
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { PiCardProps } from '@pihanga2/core';
|
|
3
|
+
import { CodeMirrorCardProps, CodeMirrorCardEvents } from './codeMirror.types';
|
|
4
|
+
export declare const CodeMirrorComponent: (props: PiCardProps<CodeMirrorCardProps, CodeMirrorCardEvents>) => React.ReactNode;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Extension } from '@codemirror/state';
|
|
2
|
+
import { StreamParser } from '@codemirror/language';
|
|
3
|
+
export declare const CODE_MIRROR_CARD = "code-mirror";
|
|
4
|
+
export declare const CodeMirrorCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<CodeMirrorCardProps, S, CodeMirrorCardEvents>) => import('@pihanga2/core').PiCardDef;
|
|
5
|
+
export declare const CODE_MIRROR_ACTION: {
|
|
6
|
+
CHANGED: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const onCodeMirrorChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
9
|
+
cardID: string;
|
|
10
|
+
} & ChangedEvent>) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Register a StreamParser under a caller-chosen key.
|
|
13
|
+
* Call this once at app initialisation time, before the card is first rendered.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { python } from "@codemirror/legacy-modes/mode/python";
|
|
17
|
+
* import { registerStreamParser } from "@pihanga2/shadcn/codeMirror";
|
|
18
|
+
* registerStreamParser("python", python);
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerStreamParser(key: string, parser: StreamParser<unknown>): void;
|
|
21
|
+
/** @internal — used by the component only. */
|
|
22
|
+
export declare function resolveStreamParser(key: string): StreamParser<unknown> | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Register a bundle of CodeMirror 6 extensions (themes, linters, keymaps, …)
|
|
25
|
+
* under a caller-chosen key.
|
|
26
|
+
* Call this once at app initialisation time, before the card is first rendered.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* import { oneDark } from "@codemirror/theme-one-dark";
|
|
30
|
+
* import { registerExtensions } from "@pihanga2/shadcn/codeMirror";
|
|
31
|
+
* registerExtensions("oneDark", [oneDark]);
|
|
32
|
+
*/
|
|
33
|
+
export declare function registerExtensions(key: string, exts: Extension[]): void;
|
|
34
|
+
/** @internal — used by the component only. */
|
|
35
|
+
export declare function resolveExtensions(key: string): Extension[] | undefined;
|
|
36
|
+
export type CodeMirrorCardProps = {
|
|
37
|
+
/** The code content to display or edit. */
|
|
38
|
+
value?: string;
|
|
39
|
+
/** When true the editor is read-only. Default: false. */
|
|
40
|
+
readOnly?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Key of a StreamParser previously registered with `registerStreamParser()`.
|
|
43
|
+
* Props must be JSON-serialisable — pass the string key, not the parser itself.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* import { python } from "@codemirror/legacy-modes/mode/python";
|
|
47
|
+
* registerStreamParser("python", python);
|
|
48
|
+
* CodeMirrorCard({ streamLanguage: "python", value: "print('hello')" });
|
|
49
|
+
*/
|
|
50
|
+
streamLanguage?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Key of an Extension bundle previously registered with `registerExtensions()`.
|
|
53
|
+
* Props must be JSON-serialisable — pass the string key, not the Extension objects.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* import { oneDark } from "@codemirror/theme-one-dark";
|
|
57
|
+
* registerExtensions("oneDark", [oneDark]);
|
|
58
|
+
* CodeMirrorCard({ extensionsKey: "oneDark", ... });
|
|
59
|
+
*/
|
|
60
|
+
extensionsKey?: string;
|
|
61
|
+
/**
|
|
62
|
+
* CodeMirror editor theme — "light" or "dark".
|
|
63
|
+
* For a custom Extension-based theme, register it via `registerExtensions()`
|
|
64
|
+
* and pass its key using the `extensions` prop instead.
|
|
65
|
+
*/
|
|
66
|
+
theme?: "light" | "dark";
|
|
67
|
+
/** Show line numbers in the gutter. Default: true. */
|
|
68
|
+
lineNumbers?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* CSS height of the editor. Use "auto" to grow with content or a fixed
|
|
71
|
+
* value such as "400px". Default: "auto".
|
|
72
|
+
*/
|
|
73
|
+
height?: string;
|
|
74
|
+
/** Additional CSS class applied to the outer wrapper div. */
|
|
75
|
+
className?: string;
|
|
76
|
+
};
|
|
77
|
+
export type ChangedEvent = {
|
|
78
|
+
/** The updated editor content after each change. */
|
|
79
|
+
value: string;
|
|
80
|
+
};
|
|
81
|
+
export type CodeMirrorCardEvents = {
|
|
82
|
+
onChanged: ChangedEvent;
|
|
83
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './codeMirror.types';
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { cn as e } from "../../lib/utils.js";
|
|
2
|
+
import { Badge as t } from "../../components/ui/badge.js";
|
|
3
3
|
import { Table as n, TableBody as r, TableCaption as i, TableCell as a, TableHead as o, TableHeader as s, TableRow as c } from "../../components/ui/table.js";
|
|
4
4
|
import l, { useMemo as u, useState as d } from "react";
|
|
5
5
|
import { Card as f } from "@pihanga2/core";
|
|
6
6
|
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
7
7
|
import { Check as h, ChevronDown as g, ChevronRight as _, ChevronUp as v, ChevronsUpDown as y, X as b } from "lucide-react";
|
|
8
8
|
//#region src/cards/dataTable/dataTable.component.tsx
|
|
9
|
-
function ee(
|
|
9
|
+
function ee(e, n, r) {
|
|
10
10
|
if (n == null) return null;
|
|
11
|
-
switch (
|
|
11
|
+
switch (e.type) {
|
|
12
12
|
case "number": {
|
|
13
|
-
let
|
|
14
|
-
return isNaN(
|
|
13
|
+
let t = typeof n == "number" ? n : Number(n);
|
|
14
|
+
return isNaN(t) ? String(n) : e.format ? e.format(t) : String(t);
|
|
15
15
|
}
|
|
16
16
|
case "date": {
|
|
17
|
-
if (
|
|
18
|
-
let
|
|
19
|
-
return isNaN(
|
|
17
|
+
if (e.format) return e.format(n);
|
|
18
|
+
let t = n instanceof Date ? n : new Date(String(n));
|
|
19
|
+
return isNaN(t.getTime()) ? String(n) : t.toLocaleDateString();
|
|
20
20
|
}
|
|
21
21
|
case "badge": {
|
|
22
22
|
let r = String(n);
|
|
23
|
-
return /* @__PURE__ */ p(
|
|
24
|
-
variant:
|
|
23
|
+
return /* @__PURE__ */ p(t, {
|
|
24
|
+
variant: e.variants?.[r] ?? "secondary",
|
|
25
25
|
children: r
|
|
26
26
|
});
|
|
27
27
|
}
|
|
@@ -42,7 +42,7 @@ function ee(t, n, r) {
|
|
|
42
42
|
function x({ columnKey: e, activeKey: t, ascending: n }) {
|
|
43
43
|
return e === t ? p(n ? v : g, { className: "ml-1 inline size-3.5" }) : /* @__PURE__ */ p(y, { className: "ml-1 inline size-3.5 opacity-40" });
|
|
44
44
|
}
|
|
45
|
-
function S({ page:
|
|
45
|
+
function S({ page: t, totalPages: n, onPrev: r, onNext: i }) {
|
|
46
46
|
return /* @__PURE__ */ m("div", {
|
|
47
47
|
className: "flex items-center justify-end gap-2 mt-2 px-2",
|
|
48
48
|
children: [
|
|
@@ -50,22 +50,22 @@ function S({ page: e, totalPages: n, onPrev: r, onNext: i }) {
|
|
|
50
50
|
className: "text-sm text-muted-foreground",
|
|
51
51
|
children: [
|
|
52
52
|
"Page ",
|
|
53
|
-
|
|
53
|
+
t + 1,
|
|
54
54
|
" of ",
|
|
55
55
|
n
|
|
56
56
|
]
|
|
57
57
|
}),
|
|
58
58
|
/* @__PURE__ */ p("button", {
|
|
59
59
|
type: "button",
|
|
60
|
-
className:
|
|
61
|
-
disabled:
|
|
60
|
+
className: e("rounded border px-2 py-1 text-sm transition-colors", "hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40"),
|
|
61
|
+
disabled: t === 0,
|
|
62
62
|
onClick: r,
|
|
63
63
|
children: "Previous"
|
|
64
64
|
}),
|
|
65
65
|
/* @__PURE__ */ p("button", {
|
|
66
66
|
type: "button",
|
|
67
|
-
className:
|
|
68
|
-
disabled:
|
|
67
|
+
className: e("rounded border px-2 py-1 text-sm transition-colors", "hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40"),
|
|
68
|
+
disabled: t >= n - 1,
|
|
69
69
|
onClick: i,
|
|
70
70
|
children: "Next"
|
|
71
71
|
})
|
|
@@ -75,8 +75,8 @@ function S({ page: e, totalPages: n, onPrev: r, onNext: i }) {
|
|
|
75
75
|
function C(e) {
|
|
76
76
|
return e.replace(/([A-Z])/g, " $1").replace(/^./, (e) => e.toUpperCase()).trim();
|
|
77
77
|
}
|
|
78
|
-
var w = (
|
|
79
|
-
let { columns: h, rows: v, caption: y, sortKey: b, sortAscending: w, pageSize: T, currentPage: E, stickyHeader: D = !1, striped: te = !1, hoverable: ne = !0, compact: re = !1, emptyCard: O, emptyText: ie = "No data", className: k, cardName: A, onRowClicked: j, onSortChanged: M, onShowDetail: N, onHideDetail: P, onPageChanged: F } =
|
|
78
|
+
var w = (t) => {
|
|
79
|
+
let { columns: h, rows: v, caption: y, sortKey: b, sortAscending: w, pageSize: T, currentPage: E, stickyHeader: D = !1, striped: te = !1, hoverable: ne = !0, compact: re = !1, emptyCard: O, emptyText: ie = "No data", className: k, cardName: A, onRowClicked: j, onSortChanged: M, onShowDetail: N, onHideDetail: P, onPageChanged: F } = t, [I, L] = d(/* @__PURE__ */ new Set()), [R, z] = d(b), [B, V] = d(w ?? !0), H = b === void 0 ? R : b, U = w === void 0 ? B : w, [W, G] = d(E ?? 0), K = E === void 0 ? W : E, q = v.some((e) => e.detailCard != null), J = h.length + +!!q, Y = u(() => H ? [...v].sort((e, t) => {
|
|
80
80
|
let n = e.data[H], r = t.data[H];
|
|
81
81
|
if (n == null && r == null) return 0;
|
|
82
82
|
if (n == null) return 1;
|
|
@@ -124,7 +124,7 @@ var w = (e) => {
|
|
|
124
124
|
});
|
|
125
125
|
}, $ = re ? "py-1 px-2" : "py-2 px-3";
|
|
126
126
|
return /* @__PURE__ */ m("div", {
|
|
127
|
-
className:
|
|
127
|
+
className: e("w-full", k),
|
|
128
128
|
"data-pihanga": A,
|
|
129
129
|
children: [/* @__PURE__ */ m(n, { children: [
|
|
130
130
|
y && /* @__PURE__ */ p(i, { children: y }),
|
|
@@ -133,19 +133,19 @@ var w = (e) => {
|
|
|
133
133
|
children: /* @__PURE__ */ m(c, { children: [q && /* @__PURE__ */ p(o, {
|
|
134
134
|
className: "w-10 px-2",
|
|
135
135
|
"aria-label": "Row details"
|
|
136
|
-
}), h.map((
|
|
137
|
-
style:
|
|
138
|
-
className:
|
|
139
|
-
onClick:
|
|
136
|
+
}), h.map((t) => /* @__PURE__ */ p(o, {
|
|
137
|
+
style: t.width ? { width: t.width } : void 0,
|
|
138
|
+
className: e($, t.align === "center" && "text-center", t.align === "right" && "text-right", t.sortable && "cursor-pointer select-none", t.headerClassName),
|
|
139
|
+
onClick: t.sortable ? () => ae(t.key) : void 0,
|
|
140
140
|
children: /* @__PURE__ */ m("span", {
|
|
141
141
|
className: "inline-flex items-center",
|
|
142
|
-
children: [
|
|
143
|
-
columnKey:
|
|
142
|
+
children: [t.title ?? C(t.key), t.sortable && /* @__PURE__ */ p(x, {
|
|
143
|
+
columnKey: t.key,
|
|
144
144
|
activeKey: H,
|
|
145
145
|
ascending: U
|
|
146
146
|
})]
|
|
147
147
|
})
|
|
148
|
-
},
|
|
148
|
+
}, t.key))] })
|
|
149
149
|
}),
|
|
150
150
|
/* @__PURE__ */ p(r, { children: X.length === 0 ? /* @__PURE__ */ p(c, { children: /* @__PURE__ */ p(a, {
|
|
151
151
|
colSpan: J,
|
|
@@ -154,30 +154,31 @@ var w = (e) => {
|
|
|
154
154
|
cardName: O,
|
|
155
155
|
parentCard: A
|
|
156
156
|
}) : ie
|
|
157
|
-
}) }) : X.map((
|
|
158
|
-
let r = I.has(
|
|
157
|
+
}) }) : X.map((t, n) => {
|
|
158
|
+
let r = I.has(t.id), i = te && n % 2 == 1;
|
|
159
159
|
return /* @__PURE__ */ m(l.Fragment, { children: [/* @__PURE__ */ m(c, {
|
|
160
|
-
className:
|
|
160
|
+
className: e(i && "bg-muted/30", ne && "cursor-pointer"),
|
|
161
161
|
"data-expanded": r || void 0,
|
|
162
|
-
onClick: () => se(
|
|
162
|
+
onClick: () => se(t),
|
|
163
163
|
children: [q && /* @__PURE__ */ p(a, {
|
|
164
164
|
className: "w-10 px-2",
|
|
165
|
-
children:
|
|
165
|
+
children: t.detailCard && /* @__PURE__ */ p("button", {
|
|
166
166
|
type: "button",
|
|
167
167
|
"aria-label": r ? "Collapse detail" : "Expand detail",
|
|
168
168
|
"aria-expanded": r,
|
|
169
|
-
className:
|
|
170
|
-
onClick: (
|
|
169
|
+
className: e("flex items-center justify-center rounded p-0.5 transition-colors", "hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"),
|
|
170
|
+
onClick: (e) => oe(t, e),
|
|
171
171
|
children: p(r ? g : _, { className: "size-4" })
|
|
172
172
|
})
|
|
173
173
|
}), h.map((n) => {
|
|
174
|
-
let r =
|
|
174
|
+
let r = t.data[n.key], i = typeof n.cellClassName == "function" ? n.cellClassName(r, t) : n.cellClassName, o = typeof n.cellStyle == "function" ? n.cellStyle(r, t) : n.cellStyle;
|
|
175
175
|
return /* @__PURE__ */ p(a, {
|
|
176
|
-
className:
|
|
176
|
+
className: e($, n.align === "center" && "text-center", n.align === "right" && "text-right", i),
|
|
177
|
+
style: o,
|
|
177
178
|
children: ee(n, r, A)
|
|
178
179
|
}, n.key);
|
|
179
180
|
})]
|
|
180
|
-
}), r &&
|
|
181
|
+
}), r && t.detailCard && /* @__PURE__ */ p(c, {
|
|
181
182
|
className: "hover:bg-transparent",
|
|
182
183
|
onClick: (e) => e.stopPropagation(),
|
|
183
184
|
children: /* @__PURE__ */ p(a, {
|
|
@@ -186,14 +187,14 @@ var w = (e) => {
|
|
|
186
187
|
children: /* @__PURE__ */ p("div", {
|
|
187
188
|
className: "bg-muted/20 px-4 py-3",
|
|
188
189
|
children: /* @__PURE__ */ p(f, {
|
|
189
|
-
cardName:
|
|
190
|
-
cardKey: `detail-${
|
|
191
|
-
row:
|
|
190
|
+
cardName: t.detailCard,
|
|
191
|
+
cardKey: `detail-${t.id}`,
|
|
192
|
+
row: t,
|
|
192
193
|
parentCard: A
|
|
193
|
-
}, `${A}-${
|
|
194
|
+
}, `${A}-${t.id}-detail`)
|
|
194
195
|
})
|
|
195
196
|
})
|
|
196
|
-
})] },
|
|
197
|
+
})] }, t.id);
|
|
197
198
|
}) })
|
|
198
199
|
] }), T && Z > 1 && /* @__PURE__ */ p(S, {
|
|
199
200
|
page: K,
|