@pihanga2/shadcn 0.2.5 → 0.2.7

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 (110) hide show
  1. package/AGENT.building-cards.md +87 -0
  2. package/AGENT.using-cards.md +47 -0
  3. package/README.md +7 -1
  4. package/cards/avatar/avatar.component.d.ts +11 -0
  5. package/cards/avatar/avatar.component.js +26 -0
  6. package/cards/avatar/avatar.component.js.map +1 -0
  7. package/cards/avatar/avatar.types.d.ts +46 -0
  8. package/cards/avatar/avatar.types.js +7 -0
  9. package/cards/avatar/avatar.types.js.map +1 -0
  10. package/cards/avatar/index.d.ts +1 -0
  11. package/cards/avatar/index.js +12 -0
  12. package/cards/avatar/index.js.map +1 -0
  13. package/cards/badge/badge.component.js +4 -4
  14. package/cards/codeMirror/codeMirror.component.d.ts +4 -0
  15. package/cards/codeMirror/codeMirror.types.d.ts +83 -0
  16. package/cards/codeMirror/index.d.ts +1 -0
  17. package/cards/collapsibleCard/collapsibleCard.component.d.ts +4 -0
  18. package/cards/collapsibleCard/collapsibleCard.component.js +61 -0
  19. package/cards/collapsibleCard/collapsibleCard.component.js.map +1 -0
  20. package/cards/collapsibleCard/collapsibleCard.types.d.ts +91 -0
  21. package/cards/collapsibleCard/collapsibleCard.types.js +7 -0
  22. package/cards/collapsibleCard/collapsibleCard.types.js.map +1 -0
  23. package/cards/collapsibleCard/index.d.ts +1 -0
  24. package/cards/collapsibleCard/index.js +13 -0
  25. package/cards/collapsibleCard/index.js.map +1 -0
  26. package/cards/collapsibleCard.d.ts +1 -0
  27. package/cards/dataTable/dataTable.component.js +43 -42
  28. package/cards/dataTable/dataTable.component.js.map +1 -1
  29. package/cards/dataTable/dataTable.types.d.ts +26 -2
  30. package/cards/dataTable/dataTable.types.js +1 -0
  31. package/cards/dataTable/dataTable.types.js.map +1 -1
  32. package/cards/drawer/drawer.component.d.ts +4 -0
  33. package/cards/drawer/drawer.component.js +83 -0
  34. package/cards/drawer/drawer.component.js.map +1 -0
  35. package/cards/drawer/drawer.types.d.ts +95 -0
  36. package/cards/drawer/drawer.types.js +11 -0
  37. package/cards/drawer/drawer.types.js.map +1 -0
  38. package/cards/drawer/index.d.ts +1 -0
  39. package/cards/drawer/index.js +13 -0
  40. package/cards/drawer/index.js.map +1 -0
  41. package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
  42. package/cards/emptyCard/emptyCard.component.d.ts +4 -0
  43. package/cards/emptyCard/emptyCard.types.d.ts +36 -0
  44. package/cards/emptyCard/index.d.ts +1 -0
  45. package/cards/emptyCard.d.ts +1 -7
  46. package/cards/fileDrop/fileDrop.component.js +1 -1
  47. package/cards/fileDrop/fileDrop.css +1 -0
  48. package/cards/flexGrid/flexGrid.types.d.ts +1 -2
  49. package/cards/flexGrid/flexGrid.types.js.map +1 -1
  50. package/cards/graphin/eventDispatcher.component.d.ts +3 -1
  51. package/cards/graphin/graphin.types.d.ts +14 -0
  52. package/cards/infoCard/index.d.ts +1 -0
  53. package/cards/infoCard/index.js +12 -0
  54. package/cards/infoCard/index.js.map +1 -0
  55. package/cards/infoCard/infoCard.component.d.ts +4 -0
  56. package/cards/infoCard/infoCard.component.js +55 -0
  57. package/cards/infoCard/infoCard.component.js.map +1 -0
  58. package/cards/infoCard/infoCard.types.d.ts +65 -0
  59. package/cards/infoCard/infoCard.types.js +7 -0
  60. package/cards/infoCard/infoCard.types.js.map +1 -0
  61. package/cards/infoCard.d.ts +1 -0
  62. package/cards/jsonViewer/jsonViewer.component.js +1 -1
  63. package/cards/jsonViewer/jsonViewer.css +1 -0
  64. package/cards/list/list.component.js +21 -21
  65. package/cards/loadingOverlay/loadingOverlay.component.js +1 -1
  66. package/cards/loadingOverlay/loadingOverlay.css +1 -0
  67. package/cards/pageWithNavbar/pageWithNavbar.component.js +1 -1
  68. package/cards/pageWithNavbar/pageWithNavbar.css +1 -0
  69. package/cards/pageWithNavbarMeta/index.d.ts +1 -0
  70. package/cards/pageWithNavbarMeta/index.js +118 -0
  71. package/cards/pageWithNavbarMeta/index.js.map +1 -0
  72. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.d.ts +78 -0
  73. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js +7 -0
  74. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js.map +1 -0
  75. package/cards/pasteTarget/pasteTarget.component.js +1 -1
  76. package/cards/pasteTarget/pasteTarget.css +1 -0
  77. package/cards/scrollbarWithAnnotations/index.d.ts +1 -0
  78. package/cards/scrollbarWithAnnotations/index.js +13 -0
  79. package/cards/scrollbarWithAnnotations/index.js.map +1 -0
  80. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.d.ts +23 -0
  81. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js +78 -0
  82. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js.map +1 -0
  83. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.css +1 -0
  84. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.d.ts +123 -0
  85. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js +7 -0
  86. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js.map +1 -0
  87. package/cards/slider/slider.component.js +67 -48
  88. package/cards/slider/slider.component.js.map +1 -1
  89. package/cards/slider/slider.types.d.ts +31 -0
  90. package/cards/slider/slider.types.js.map +1 -1
  91. package/cards/stepper/stepper.component.js +1 -1
  92. package/cards/stepper/stepper.css +1 -0
  93. package/cards/toggleGroup/toggleGroup.component.js +1 -1
  94. package/cards/toggleGroup/toggleGroup.component.js.map +1 -1
  95. package/components/ui/avatar.js +5 -5
  96. package/components/ui/badge.js +7 -7
  97. package/components/ui/button.js +6 -6
  98. package/components/ui/card.js +50 -0
  99. package/components/ui/card.js.map +1 -0
  100. package/components/ui/drawer.js +79 -0
  101. package/components/ui/drawer.js.map +1 -0
  102. package/components/ui/field.js +16 -16
  103. package/components/ui/label.js +3 -3
  104. package/components/ui/separator.js +1 -1
  105. package/components/ui/toggle-group.js +5 -5
  106. package/components/ui/toggle.js +2 -2
  107. package/lib/utils.d.ts +15 -0
  108. package/lib/utils.js.map +1 -1
  109. package/package.json +39 -3
  110. package/pihanga-shadcn.css +0 -2
@@ -0,0 +1 @@
1
+ export * from './pageWithNavbarMeta.types';
@@ -0,0 +1,118 @@
1
+ import { Box as e } from "../box/box.types.js";
2
+ import "../box/index.js";
3
+ import { Button as t } from "../button/button.types.js";
4
+ import "../button/index.js";
5
+ import { Conditional as n } from "../conditional/conditional.types.js";
6
+ import "../conditional/index.js";
7
+ import { Drawer as r } from "../drawer/drawer.types.js";
8
+ import "../drawer/index.js";
9
+ import { Stack as i } from "../stack/stack.types.js";
10
+ import "../stack/index.js";
11
+ import { Typography as a } from "../typography/typography.types.js";
12
+ import "../typography/index.js";
13
+ import { PAGE_WITH_NAVBAR_META_ACTION as o, PI_PAGE_WITH_NAVBAR_META_CARD as s, PageWithNavbarMeta as c, onPageWithNavbarMetaNavigateTo as l } from "./pageWithNavbarMeta.types.js";
14
+ import { registerMetaCard as u } from "@pihanga2/core";
15
+ //#region src/cards/pageWithNavbarMeta/index.ts
16
+ function d(e) {
17
+ return e ? e.charAt(0).toLocaleUpperCase() + e.slice(1) : "";
18
+ }
19
+ function f(s, c, l) {
20
+ let u = c.navLinks ?? [], f = c.iconName, p = c.className, m = c.footer, h = [];
21
+ f && h.push(t({
22
+ iconLabel: f,
23
+ opts: {
24
+ variant: "none",
25
+ size: "icon"
26
+ },
27
+ className: "h-6 w-6 shrink-0 pointer-events-none"
28
+ })), h.push(a({
29
+ text: c.title,
30
+ level: "large",
31
+ className: "leading-none"
32
+ }));
33
+ let g = l("title", i({
34
+ direction: "row",
35
+ alignItems: "center",
36
+ spacing: 2,
37
+ content: h
38
+ })), _ = u.map((e, n) => l(`nav-link-${n}`, t({
39
+ id: e.id,
40
+ label: e.title ?? d(e.id),
41
+ opts: { variant: "ghost" },
42
+ className: "px-0 text-muted-foreground hover:text-foreground h-auto p-0",
43
+ onClickedMapper: () => ({
44
+ type: o.NAVIGATE_TO,
45
+ id: e.id
46
+ })
47
+ }))), v = l("nav-md", n({
48
+ showOn: "md",
49
+ content: l("nav-md-inner", i({
50
+ direction: "row",
51
+ alignItems: "center",
52
+ spacing: 5,
53
+ content: [g, ..._]
54
+ }))
55
+ })), y = u.length > 0 ? l("nav-sm", n({
56
+ showOn: "<md",
57
+ content: l("nav-sm-drawer", r({
58
+ direction: "left",
59
+ trigger: t({
60
+ iconLabel: "menu",
61
+ opts: {
62
+ variant: "outline",
63
+ size: "icon"
64
+ },
65
+ ariaLabel: "Toggle navigation menu"
66
+ }),
67
+ content: l("nav-sm-content", i({
68
+ direction: "column",
69
+ spacing: 4,
70
+ className: "p-4",
71
+ content: [g, ..._]
72
+ })),
73
+ footerCloseButtonText: null
74
+ }))
75
+ })) : l("nav-sm-title", n({
76
+ showOn: "<md",
77
+ content: g
78
+ })), b = [];
79
+ c.headerLeftCard && b.push(c.headerLeftCard), c.headerRightCard && b.push(c.headerRightCard);
80
+ let x = [v, y];
81
+ b.length > 0 && x.push(l("header-actions", i({
82
+ direction: "row",
83
+ alignItems: "center",
84
+ className: "ml-auto gap-2 lg:gap-4",
85
+ content: b
86
+ })));
87
+ let S = [l("header", e({
88
+ className: "shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6",
89
+ content: x
90
+ })), l("main", e({
91
+ className: "flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4",
92
+ content: ((e, t) => {
93
+ let n = t.resolve(c.main);
94
+ return n == null ? [] : [n];
95
+ })
96
+ }))];
97
+ return m && S.push(l("footer", e({
98
+ className: "shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4",
99
+ content: [m]
100
+ }))), i({
101
+ direction: "row",
102
+ className: `w-full h-full justify-center${p ? ` ${p}` : ""}`,
103
+ content: [l("page", i({
104
+ direction: "column",
105
+ className: "flex-1 h-full w-full",
106
+ content: S
107
+ }))]
108
+ });
109
+ }
110
+ u({
111
+ type: s,
112
+ mapper: f,
113
+ events: o
114
+ });
115
+ //#endregion
116
+ export { o as PAGE_WITH_NAVBAR_META_ACTION, s as PI_PAGE_WITH_NAVBAR_META_CARD, c as PageWithNavbarMeta, l as onPageWithNavbarMetaNavigateTo };
117
+
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/pageWithNavbarMeta/index.ts"],"sourcesContent":["import {\n registerMetaCard,\n type PiCardDef,\n type PiCardRef,\n type PiMetaProps,\n type PiMetaResolveCtx,\n type PiRegisterMetaCard,\n type RegisterCardF,\n} from \"@pihanga2/core\";\n\nimport {Stack} from \"@/cards/stack\";\nimport {Box} from \"@/cards/box\";\nimport {Button} from \"@/cards/button\";\nimport {Typography} from \"@/cards/typography\";\nimport {Conditional} from \"@/cards/conditional\";\nimport {Drawer} from \"@/cards/drawer\";\n\nimport {\n PAGE_WITH_NAVBAR_META_ACTION,\n PI_PAGE_WITH_NAVBAR_META_CARD,\n type NavLink,\n type PageWithNavbarMetaDynProps,\n type PageWithNavbarMetaEvents,\n type PageWithNavbarMetaStaticProps,\n} from \"./pageWithNavbarMeta.types\";\n\nexport * from \"./pageWithNavbarMeta.types\";\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toLocaleUpperCase() + s.slice(1) : \"\";\n}\n\n// ── Mapper ───────────────────────────────────────────────────────────────────\n\n/**\n * `StaticProps` arrive as their plain types — TypeScript refuses memo selectors.\n * `DynProps` arrive as `StateMapper<T>` functions — must be resolved via `resolve()`.\n */\ntype MapperProps = PiMetaProps<\n PageWithNavbarMetaDynProps,\n PageWithNavbarMetaStaticProps,\n PageWithNavbarMetaEvents\n>;\n\nfunction PageWithNavbarMetaMapper(\n _cardName: string,\n props: MapperProps,\n reg: RegisterCardF,\n): PiCardDef {\n // ── Static props: plain types, no resolve() needed ───────────────────────\n const navLinks = props.navLinks ?? [];\n const iconName = props.iconName;\n const wrapperClass = props.className;\n const footer = props.footer;\n\n // ── Title (icon + text) ─────────────────────────────────────────────────\n // props.title is StateMapper<string> — a function, NOT a string.\n // Typography's `text` prop is typed (via PiMapProps) as `string | StateMapper<string>`,\n // so we forward the selector function directly. The framework resolves it lazily\n // (calls props.title(state, ctx)) when Typography renders. This is different from\n // using props.title as a string, which TypeScript would reject.\n const titleContent: PiCardRef[] = [];\n if (iconName) {\n titleContent.push(\n Button({\n iconLabel: iconName,\n opts: {variant: \"none\", size: \"icon\"},\n className: \"h-6 w-6 shrink-0 pointer-events-none\",\n }),\n );\n }\n titleContent.push(\n Typography({\n text: props.title,\n level: \"large\",\n className: \"leading-none\",\n }),\n );\n\n const titleStack = reg(\n \"title\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 2,\n content: titleContent,\n }),\n );\n\n // ── Nav link buttons (shared between desktop and mobile) ────────────────\n const linkButtons = navLinks.map((link: NavLink, i: number) =>\n reg(\n `nav-link-${i}`,\n Button({\n id: link.id,\n label: link.title ?? capitalize(link.id),\n opts: {variant: \"ghost\"},\n className:\n \"px-0 text-muted-foreground hover:text-foreground h-auto p-0\",\n onClickedMapper: () => ({\n type: PAGE_WITH_NAVBAR_META_ACTION.NAVIGATE_TO,\n id: link.id,\n }),\n }),\n ),\n );\n\n // ── Desktop nav (md+): title + links in a row ───────────────────────────\n const desktopNav = reg(\n \"nav-md\",\n Conditional({\n showOn: \"md\",\n content: reg(\n \"nav-md-inner\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 5,\n content: [titleStack, ...linkButtons],\n }),\n ),\n }),\n );\n\n // ── Mobile nav (< md) ───────────────────────────────────────────────────\n // With nav links: hamburger drawer (left slide-in using pi/drawer).\n // Without nav links: just show the title inline.\n const mobileNav: PiCardRef =\n navLinks.length > 0\n ? reg(\n \"nav-sm\",\n Conditional({\n showOn: \"<md\",\n content: reg(\n \"nav-sm-drawer\",\n Drawer({\n direction: \"left\",\n trigger: Button({\n iconLabel: \"menu\",\n opts: {variant: \"outline\", size: \"icon\"},\n ariaLabel: \"Toggle navigation menu\",\n }),\n content: reg(\n \"nav-sm-content\",\n Stack({\n direction: \"column\",\n spacing: 4,\n className: \"p-4\",\n content: [titleStack, ...linkButtons],\n }),\n ),\n footerCloseButtonText: null,\n }),\n ),\n }),\n )\n : reg(\n \"nav-sm-title\",\n Conditional({\n showOn: \"<md\",\n content: titleStack,\n }),\n );\n\n // ── Header action slots ─────────────────────────────────────────────────\n // Static PiCardRefs — TypeScript already refuses memo() selectors here.\n const actionRefs: PiCardRef[] = [];\n if (props.headerLeftCard) {\n actionRefs.push(props.headerLeftCard);\n }\n if (props.headerRightCard) {\n actionRefs.push(props.headerRightCard);\n }\n\n const headerContent: PiCardRef[] = [desktopNav, mobileNav];\n if (actionRefs.length > 0) {\n headerContent.push(\n reg(\n \"header-actions\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n className: \"ml-auto gap-2 lg:gap-4\",\n content: actionRefs,\n }),\n ),\n );\n }\n\n // ── Header ──────────────────────────────────────────────────────────────\n const header = reg(\n \"header\",\n Box({\n className:\n \"shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6\",\n content: headerContent,\n }),\n );\n\n // ── Main ────────────────────────────────────────────────────────────────\n // props.main is a StateMapper — resolved lazily so React re-renders when\n // the referenced card changes.\n const mainBox = reg(\n \"main\",\n Box({\n className:\n \"flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4\",\n content: ((_: unknown, ctx: PiMetaResolveCtx) => {\n const ref = ctx.resolve(props.main);\n return ref != null ? [ref as PiCardRef] : [];\n }) as unknown as PiCardRef[],\n }),\n );\n\n // ── Page column ─────────────────────────────────────────────────────────\n const pageContent: PiCardRef[] = [header, mainBox];\n\n // ── Footer (optional) ───────────────────────────────────────────────────\n // `footer` is a static plain PiCardRef — use directly.\n if (footer) {\n pageContent.push(\n reg(\n \"footer\",\n Box({\n className:\n \"shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4\",\n content: [footer],\n }),\n ),\n );\n }\n\n // ── Assemble ────────────────────────────────────────────────────────────\n return Stack({\n direction: \"row\",\n className: `w-full h-full justify-center${wrapperClass ? ` ${wrapperClass}` : \"\"}`,\n content: [\n reg(\n \"page\",\n Stack({\n direction: \"column\",\n className: \"flex-1 h-full w-full\",\n content: pageContent,\n }),\n ),\n ],\n });\n}\n\n// ── Registration ─────────────────────────────────────────────────────────────\n\nregisterMetaCard({\n type: PI_PAGE_WITH_NAVBAR_META_CARD,\n mapper: PageWithNavbarMetaMapper,\n events: PAGE_WITH_NAVBAR_META_ACTION,\n} satisfies PiRegisterMetaCard);\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,EAAW,GAAmB;CACrC,OAAO,IAAI,EAAE,OAAO,CAAC,EAAE,kBAAkB,IAAI,EAAE,MAAM,CAAC,IAAI;AAC5D;AAcA,SAAS,EACP,GACA,GACA,GACW;CAEX,IAAM,IAAW,EAAM,YAAY,CAAC,GAC9B,IAAW,EAAM,UACjB,IAAe,EAAM,WACrB,IAAS,EAAM,QAQf,IAA4B,CAAC;CAUnC,AATI,KACF,EAAa,KACX,EAAO;EACL,WAAW;EACX,MAAM;GAAC,SAAS;GAAQ,MAAM;EAAM;EACpC,WAAW;CACb,CAAC,CACH,GAEF,EAAa,KACX,EAAW;EACT,MAAM,EAAM;EACZ,OAAO;EACP,WAAW;CACb,CAAC,CACH;CAEA,IAAM,IAAa,EACjB,SACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,SAAS;EACT,SAAS;CACX,CAAC,CACH,GAGM,IAAc,EAAS,KAAK,GAAe,MAC/C,EACE,YAAY,KACZ,EAAO;EACL,IAAI,EAAK;EACT,OAAO,EAAK,SAAS,EAAW,EAAK,EAAE;EACvC,MAAM,EAAC,SAAS,QAAO;EACvB,WACE;EACF,wBAAwB;GACtB,MAAM,EAA6B;GACnC,IAAI,EAAK;EACX;CACF,CAAC,CACH,CACF,GAGM,IAAa,EACjB,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,gBACA,EAAM;GACJ,WAAW;GACX,YAAY;GACZ,SAAS;GACT,SAAS,CAAC,GAAY,GAAG,CAAW;EACtC,CAAC,CACH;CACF,CAAC,CACH,GAKM,IACJ,EAAS,SAAS,IACd,EACE,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,iBACA,EAAO;GACL,WAAW;GACX,SAAS,EAAO;IACd,WAAW;IACX,MAAM;KAAC,SAAS;KAAW,MAAM;IAAM;IACvC,WAAW;GACb,CAAC;GACD,SAAS,EACP,kBACA,EAAM;IACJ,WAAW;IACX,SAAS;IACT,WAAW;IACX,SAAS,CAAC,GAAY,GAAG,CAAW;GACtC,CAAC,CACH;GACA,uBAAuB;EACzB,CAAC,CACH;CACF,CAAC,CACH,IACA,EACE,gBACA,EAAY;EACV,QAAQ;EACR,SAAS;CACX,CAAC,CACH,GAIA,IAA0B,CAAC;CAIjC,AAHI,EAAM,kBACR,EAAW,KAAK,EAAM,cAAc,GAElC,EAAM,mBACR,EAAW,KAAK,EAAM,eAAe;CAGvC,IAAM,IAA6B,CAAC,GAAY,CAAS;CACzD,AAAI,EAAW,SAAS,KACtB,EAAc,KACZ,EACE,kBACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,WAAW;EACX,SAAS;CACX,CAAC,CACH,CACF;CA6BF,IAAM,IAA2B,CAzBlB,EACb,UACA,EAAI;EACF,WACE;EACF,SAAS;CACX,CAAC,CAmB+B,GAblB,EACd,QACA,EAAI;EACF,WACE;EACF,WAAW,GAAY,MAA0B;GAC/C,IAAM,IAAM,EAAI,QAAQ,EAAM,IAAI;GAClC,OAAO,KAAO,OAA4B,CAAC,IAAtB,CAAC,CAAgB;EACxC;CACF,CAAC,CAIuC,CAAO;CAkBjD,OAdI,KACF,EAAY,KACV,EACE,UACA,EAAI;EACF,WACE;EACF,SAAS,CAAC,CAAM;CAClB,CAAC,CACH,CACF,GAIK,EAAM;EACX,WAAW;EACX,WAAW,+BAA+B,IAAe,IAAI,MAAiB;EAC9E,SAAS,CACP,EACE,QACA,EAAM;GACJ,WAAW;GACX,WAAW;GACX,SAAS;EACX,CAAC,CACH,CACF;CACF,CAAC;AACH;AAIA,EAAiB;CACf,MAAM;CACN,QAAQ;CACR,QAAQ;AACV,CAA8B"}
@@ -0,0 +1,78 @@
1
+ import { PiCardRef } from '@pihanga2/core';
2
+ export declare const PI_PAGE_WITH_NAVBAR_META_CARD = "pi/pageWithNavbarMeta";
3
+ export declare const PageWithNavbarMeta: <S extends import('@pihanga2/core').ReduxState>(p: PageWithNavbarMetaStaticProps & {
4
+ title: string | import('@pihanga2/core').StateMapper<string, S, import('@pihanga2/core').PiDefCtxtProps>;
5
+ main: PiCardRef | import('@pihanga2/core').StateMapper<PiCardRef, S, import('@pihanga2/core').PiDefCtxtProps>;
6
+ } & import('@pihanga2/core/types').EventHandler<PageWithNavbarMetaEvents, S> & import('@pihanga2/core/types').EventMapper<PageWithNavbarMetaEvents, import('@pihanga2/core').PiDefCtxtProps>) => import('@pihanga2/core').PiCardDef;
7
+ export declare const PAGE_WITH_NAVBAR_META_ACTION: {
8
+ NAVIGATE_TO: string;
9
+ };
10
+ export declare const onPageWithNavbarMetaNavigateTo: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
11
+ cardID: string;
12
+ } & PageWithNavbarMetaNavigateToEvent>) => void;
13
+ export type NavLink = {
14
+ id: string;
15
+ title?: string;
16
+ };
17
+ /**
18
+ * Props that are evaluated **statically** in the mapper body.
19
+ * Passing a `memo(...)` selector for any of these will throw at runtime.
20
+ */
21
+ export type PageWithNavbarMetaStaticProps = {
22
+ /**
23
+ * Name of an icon registered via {@link registerIcon}.
24
+ * When provided, the icon is rendered next to the title in the header.
25
+ */
26
+ iconName?: string;
27
+ /**
28
+ * Optional footer card rendered below the main content area.
29
+ * When omitted the footer row is not rendered.
30
+ *
31
+ * To conditionally show/hide a footer, wrap it in a `Conditional` card.
32
+ */
33
+ footer?: PiCardRef;
34
+ /**
35
+ * Navigation links rendered in the header.
36
+ * On small screens they are collapsed behind a hamburger drawer.
37
+ */
38
+ navLinks?: NavLink[];
39
+ /**
40
+ * Reserved — not yet implemented.
41
+ * When `Box` gains `scrollResetKey` support, this prop will scroll
42
+ * the main content area back to the top whenever the value changes.
43
+ */
44
+ scrollResetKey?: string;
45
+ /**
46
+ * Optional card shown on the left side of the header action area.
47
+ * To use a reactive card ref, wrap it in a stable `registerCard` slot.
48
+ */
49
+ headerLeftCard?: PiCardRef;
50
+ /**
51
+ * Optional card shown on the right side of the header action area.
52
+ * To use a reactive card ref, wrap it in a stable `registerCard` slot.
53
+ */
54
+ headerRightCard?: PiCardRef;
55
+ /** Additional Tailwind classes applied to the outermost wrapper. */
56
+ className?: string;
57
+ };
58
+ /**
59
+ * Props that support **reactive** state selectors (`memo(...)`).
60
+ * These are resolved lazily inside child card prop functions via `resolve()`.
61
+ */
62
+ export type PageWithNavbarMetaDynProps = {
63
+ /** Page title displayed in the header. Supports reactive selectors. */
64
+ title: string;
65
+ /**
66
+ * The main content card.
67
+ * Supports reactive selectors (e.g. `memo((s) => s.currentPage, ...)`).
68
+ */
69
+ main: PiCardRef;
70
+ };
71
+ /** Combined props type — intersection of static and dynamic props. */
72
+ export type PageWithNavbarMetaProps = PageWithNavbarMetaStaticProps & PageWithNavbarMetaDynProps;
73
+ export type PageWithNavbarMetaNavigateToEvent = {
74
+ id: string;
75
+ };
76
+ export type PageWithNavbarMetaEvents = {
77
+ onNavigateTo: PageWithNavbarMetaNavigateToEvent;
78
+ };
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration2 as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
+ //#region src/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.ts
3
+ var r = "pi/pageWithNavbarMeta", i = e(r), a = n(r, ["navigate_to"]), o = t(a.NAVIGATE_TO);
4
+ //#endregion
5
+ export { a as PAGE_WITH_NAVBAR_META_ACTION, r as PI_PAGE_WITH_NAVBAR_META_CARD, i as PageWithNavbarMeta, o as onPageWithNavbarMetaNavigateTo };
6
+
7
+ //# sourceMappingURL=pageWithNavbarMeta.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pageWithNavbarMeta.types.js","names":[],"sources":["../../../src/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.ts"],"sourcesContent":["import {\n createCardDeclaration2,\n createOnAction,\n type PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_PAGE_WITH_NAVBAR_META_CARD = \"pi/pageWithNavbarMeta\";\n\nexport const PageWithNavbarMeta = createCardDeclaration2<\n PageWithNavbarMetaDynProps,\n PageWithNavbarMetaStaticProps,\n PageWithNavbarMetaEvents\n>(PI_PAGE_WITH_NAVBAR_META_CARD);\n\nexport const PAGE_WITH_NAVBAR_META_ACTION = registerActions(\n PI_PAGE_WITH_NAVBAR_META_CARD,\n [\"navigate_to\"],\n);\n\nexport const onPageWithNavbarMetaNavigateTo =\n createOnAction<PageWithNavbarMetaNavigateToEvent>(\n PAGE_WITH_NAVBAR_META_ACTION.NAVIGATE_TO,\n );\n\nexport type NavLink = {\n id: string;\n title?: string;\n};\n\n/**\n * Props that are evaluated **statically** in the mapper body.\n * Passing a `memo(...)` selector for any of these will throw at runtime.\n */\nexport type PageWithNavbarMetaStaticProps = {\n /**\n * Name of an icon registered via {@link registerIcon}.\n * When provided, the icon is rendered next to the title in the header.\n */\n iconName?: string;\n\n /**\n * Optional footer card rendered below the main content area.\n * When omitted the footer row is not rendered.\n *\n * To conditionally show/hide a footer, wrap it in a `Conditional` card.\n */\n footer?: PiCardRef;\n\n /**\n * Navigation links rendered in the header.\n * On small screens they are collapsed behind a hamburger drawer.\n */\n navLinks?: NavLink[];\n\n /**\n * Reserved — not yet implemented.\n * When `Box` gains `scrollResetKey` support, this prop will scroll\n * the main content area back to the top whenever the value changes.\n */\n scrollResetKey?: string;\n\n /**\n * Optional card shown on the left side of the header action area.\n * To use a reactive card ref, wrap it in a stable `registerCard` slot.\n */\n headerLeftCard?: PiCardRef;\n\n /**\n * Optional card shown on the right side of the header action area.\n * To use a reactive card ref, wrap it in a stable `registerCard` slot.\n */\n headerRightCard?: PiCardRef;\n\n /** Additional Tailwind classes applied to the outermost wrapper. */\n className?: string;\n};\n\n/**\n * Props that support **reactive** state selectors (`memo(...)`).\n * These are resolved lazily inside child card prop functions via `resolve()`.\n */\nexport type PageWithNavbarMetaDynProps = {\n /** Page title displayed in the header. Supports reactive selectors. */\n title: string;\n\n /**\n * The main content card.\n * Supports reactive selectors (e.g. `memo((s) => s.currentPage, ...)`).\n */\n main: PiCardRef;\n};\n\n/** Combined props type — intersection of static and dynamic props. */\nexport type PageWithNavbarMetaProps = PageWithNavbarMetaStaticProps &\n PageWithNavbarMetaDynProps;\n\nexport type PageWithNavbarMetaNavigateToEvent = {id: string};\n\nexport type PageWithNavbarMetaEvents = {\n onNavigateTo: PageWithNavbarMetaNavigateToEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAgC,yBAEhC,IAAqB,EAIhC,CAA6B,GAElB,IAA+B,EAC1C,GACA,CAAC,aAAa,CAChB,GAEa,IACX,EACE,EAA6B,WAC/B"}
@@ -1,6 +1,6 @@
1
1
  import { Button as e } from "../../components/ui/button.js";
2
2
  import { DEF_ERROR_COLOR as t, DEF_HEIGHT as n, DEF_OVERLAY_OPACITY as r, DEF_PASTE_FIRST_REMINDER as i, DEF_SUCCESS_COLOR as a } from "./pasteTarget.types.js";
3
- /* empty css */
3
+ import './pasteTarget.css';/* empty css */
4
4
  import o, { useRef as s, useState as c } from "react";
5
5
  import l from "clsx";
6
6
  import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
@@ -0,0 +1 @@
1
+ .pihanga-paste-target{border:2px dashed #999}.pihanga-paste-target .paste-target-msg-title{font-size:1.2em}.pihanga-paste-target textarea:focus{outline:none}.pihanga-paste-target-focused{border-width:3px;border-color:#007bff}.pihanga-paste-target-focused .paste-target-focus-reminder{display:none}
@@ -0,0 +1 @@
1
+ export * from './scrollbarWithAnnotations.types';
@@ -0,0 +1,13 @@
1
+ import { ScrollbarWithAnnotationsComponent as e } from "./scrollbarWithAnnotations.component.js";
2
+ import { SCROLLBAR_WITH_ANNOTATIONS_ACTION as t, SCROLLBAR_WITH_ANNOTATIONS_CARD as n, ScrollbarWithAnnotations as r, onScrollbarAnnotationClicked as i, onScrollbarAnnotationHovered as a } from "./scrollbarWithAnnotations.types.js";
3
+ import { actionTypesToEvents as o, registerCardComponent as s } from "@pihanga2/core";
4
+ //#region src/cards/scrollbarWithAnnotations/index.ts
5
+ s({
6
+ name: n,
7
+ component: e,
8
+ events: o(t)
9
+ });
10
+ //#endregion
11
+ export { t as SCROLLBAR_WITH_ANNOTATIONS_ACTION, n as SCROLLBAR_WITH_ANNOTATIONS_CARD, r as ScrollbarWithAnnotations, i as onScrollbarAnnotationClicked, a as onScrollbarAnnotationHovered };
12
+
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/scrollbarWithAnnotations/index.ts"],"sourcesContent":["import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {ScrollbarWithAnnotationsComponent} from \"./scrollbarWithAnnotations.component\";\nimport {\n SCROLLBAR_WITH_ANNOTATIONS_ACTION,\n SCROLLBAR_WITH_ANNOTATIONS_CARD,\n} from \"./scrollbarWithAnnotations.types\";\n\nexport * from \"./scrollbarWithAnnotations.types\";\n\nregisterCardComponent({\n name: SCROLLBAR_WITH_ANNOTATIONS_CARD,\n component: ScrollbarWithAnnotationsComponent,\n events: actionTypesToEvents(SCROLLBAR_WITH_ANNOTATIONS_ACTION),\n});\n"],"mappings":";;;;AAUA,EAAsB;CACpB,MAAM;CACN,WAAW;CACX,QAAQ,EAAoB,CAAiC;AAC/D,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { default as React } from 'react';
2
+ import { PiCardProps } from '@pihanga2/core';
3
+ import { ScrollbarWithAnnotationsProps, ScrollbarWithAnnotationsEvents } from './scrollbarWithAnnotations.types';
4
+ /**
5
+ * ScrollbarWithAnnotations component.
6
+ *
7
+ * Renders a scrollable area (content comes from a Pihanga card reference) with
8
+ * a minimap-style overlay on the scrollbar track showing coloured markers for
9
+ * each annotation. Clicking a marker scrolls to its position **and** emits
10
+ * `onAnnotationClicked` so parent code can react (e.g. open a dialog/panel).
11
+ *
12
+ * Three marker shapes are supported (see `MarkerType` in the types file):
13
+ * - `"point"` – small circular dot (default)
14
+ * - `"bar"` – short rectangle with fixed CSS height
15
+ * - `"range"` – rectangle proportional to `extent`, CSS `min-height` ensures
16
+ * it stays clickable even for very small extents
17
+ *
18
+ * All visual properties (size, colour, opacity, transitions) are controlled
19
+ * entirely by CSS classes so they can be overridden without touching JS.
20
+ *
21
+ * See `scrollbarWithAnnotations.example.ts` for wiring with a Pihanga Dialog.
22
+ */
23
+ export declare const ScrollbarWithAnnotationsComponent: (props: PiCardProps<ScrollbarWithAnnotationsProps, ScrollbarWithAnnotationsEvents>) => React.ReactNode;
@@ -0,0 +1,78 @@
1
+ import './scrollbarWithAnnotations.css';/* empty css */
2
+ import { useCallback as e, useEffect as t, useRef as n } from "react";
3
+ import { Card as r } from "@pihanga2/core";
4
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
5
+ //#region src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.tsx
6
+ var o = (o) => {
7
+ let { contentCard: s, annotations: c = [], className: l, reportEventsOnScroll: u = !1, cardName: d, onAnnotationClicked: f, onAnnotationHovered: p } = o, m = n(null), h = n(null), g = n(!1), _ = n(null), v = e(() => {
8
+ let e = h.current, t = m.current;
9
+ if (!e || !t) return;
10
+ e.innerHTML = "";
11
+ let n = e.clientHeight, r = t.scrollHeight || 1;
12
+ c.forEach((i) => {
13
+ let a = i.markerType ?? "point", o = i.position / r * n, s = document.createElement("div");
14
+ if (s.className = [
15
+ "swa-marker",
16
+ `swa-marker-${a}`,
17
+ `swa-type-${i.type}`,
18
+ i.className
19
+ ].filter(Boolean).join(" "), s.style.top = `${o}px`, a === "range" && i.extent !== void 0) {
20
+ let e = i.extent / r * n;
21
+ s.style.height = `${e}px`;
22
+ }
23
+ s.onmouseenter = () => {
24
+ g.current || (s.classList.add("swa-marker--hover"), p?.({
25
+ annotationId: i.id,
26
+ annotation: i
27
+ }));
28
+ }, s.onmouseleave = () => {
29
+ g.current || (s.classList.remove("swa-marker--hover"), p?.({
30
+ annotationId: null,
31
+ annotation: null
32
+ }));
33
+ }, s.onclick = (e) => {
34
+ e.stopPropagation(), t && (t.scrollTop = i.position - 50), f({
35
+ annotationId: i.id,
36
+ annotation: i
37
+ });
38
+ }, e.appendChild(s);
39
+ });
40
+ }, [
41
+ c,
42
+ f,
43
+ p
44
+ ]);
45
+ return t(() => {
46
+ let e = h.current, t = m.current, n = new ResizeObserver(() => v());
47
+ e && n.observe(e);
48
+ let r = () => {
49
+ u || (g.current = !0, _.current !== null && clearTimeout(_.current), _.current = setTimeout(() => {
50
+ g.current = !1, _.current = null;
51
+ }, 150));
52
+ };
53
+ return t?.addEventListener("scroll", r, { passive: !0 }), () => {
54
+ n.disconnect(), t?.removeEventListener("scroll", r), _.current !== null && clearTimeout(_.current);
55
+ };
56
+ }, [v, u]), /* @__PURE__ */ i("div", {
57
+ "data-pihanga": d,
58
+ className: `swa-root${l ? ` ${l}` : ""}`,
59
+ children: /* @__PURE__ */ a("div", {
60
+ className: "swa-content-wrapper",
61
+ children: [/* @__PURE__ */ i("div", {
62
+ ref: m,
63
+ className: "swa-scroll-container",
64
+ children: /* @__PURE__ */ i(r, {
65
+ cardName: s,
66
+ parentCard: d
67
+ })
68
+ }), /* @__PURE__ */ i("div", {
69
+ ref: h,
70
+ className: "swa-overlay"
71
+ })]
72
+ })
73
+ });
74
+ };
75
+ //#endregion
76
+ export { o as ScrollbarWithAnnotationsComponent };
77
+
78
+ //# sourceMappingURL=scrollbarWithAnnotations.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrollbarWithAnnotations.component.js","names":[],"sources":["../../../src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.tsx"],"sourcesContent":["import React, {useRef, useEffect, useCallback} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\n\nimport type {\n ScrollbarWithAnnotationsProps,\n ScrollbarWithAnnotationsEvents,\n ScrollbarAnnotation,\n} from \"./scrollbarWithAnnotations.types\";\n\nimport \"./scrollbarWithAnnotations.css\";\n\n/**\n * ScrollbarWithAnnotations component.\n *\n * Renders a scrollable area (content comes from a Pihanga card reference) with\n * a minimap-style overlay on the scrollbar track showing coloured markers for\n * each annotation. Clicking a marker scrolls to its position **and** emits\n * `onAnnotationClicked` so parent code can react (e.g. open a dialog/panel).\n *\n * Three marker shapes are supported (see `MarkerType` in the types file):\n * - `\"point\"` – small circular dot (default)\n * - `\"bar\"` – short rectangle with fixed CSS height\n * - `\"range\"` – rectangle proportional to `extent`, CSS `min-height` ensures\n * it stays clickable even for very small extents\n *\n * All visual properties (size, colour, opacity, transitions) are controlled\n * entirely by CSS classes so they can be overridden without touching JS.\n *\n * See `scrollbarWithAnnotations.example.ts` for wiring with a Pihanga Dialog.\n */\nexport const ScrollbarWithAnnotationsComponent = (\n props: PiCardProps<\n ScrollbarWithAnnotationsProps,\n ScrollbarWithAnnotationsEvents\n >,\n): React.ReactNode => {\n const {\n contentCard,\n annotations = [],\n className,\n reportEventsOnScroll = false,\n cardName,\n onAnnotationClicked,\n onAnnotationHovered,\n } = props;\n\n const contentRef = useRef<HTMLDivElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n\n /**\n * True while the user is actively scrolling the content container.\n * Hover events are suppressed during this period to avoid a flood of\n * `onAnnotationHovered` dispatches as the overlay passes under the cursor.\n */\n const isScrollingRef = useRef(false);\n const scrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n /**\n * (Re-)renders all annotation markers inside the overlay div.\n * Called whenever annotations change or the window is resized.\n */\n const renderMarkers = useCallback(() => {\n const overlay = overlayRef.current;\n const content = contentRef.current;\n if (!overlay || !content) return;\n\n overlay.innerHTML = \"\";\n const overlayH = overlay.clientHeight;\n const contentScrollH = content.scrollHeight || 1;\n\n annotations.forEach((anno: ScrollbarAnnotation) => {\n const markerType = anno.markerType ?? \"point\";\n const topPx = (anno.position / contentScrollH) * overlayH;\n\n const el = document.createElement(\"div\");\n // Shape class + type class carry all visual styling – no inline colour.\n // anno.className allows per-annotation overrides (e.g. \"swa-selected\").\n el.className = [\n \"swa-marker\",\n `swa-marker-${markerType}`,\n `swa-type-${anno.type}`,\n anno.className,\n ]\n .filter(Boolean)\n .join(\" \");\n el.style.top = `${topPx}px`;\n\n // For range markers, set a proportional height via inline style so the\n // overlay scales with scroll content. CSS `min-height` (defined on\n // .swa-marker-range) guarantees a minimum regardless of the ratio.\n if (markerType === \"range\" && anno.extent !== undefined) {\n const heightPx = (anno.extent / contentScrollH) * overlayH;\n el.style.height = `${heightPx}px`;\n }\n\n el.onmouseenter = () => {\n if (isScrollingRef.current) return;\n el.classList.add(\"swa-marker--hover\");\n onAnnotationHovered?.({annotationId: anno.id, annotation: anno});\n };\n el.onmouseleave = () => {\n if (isScrollingRef.current) return;\n el.classList.remove(\"swa-marker--hover\");\n onAnnotationHovered?.({annotationId: null, annotation: null});\n };\n el.onclick = (e) => {\n e.stopPropagation();\n if (content) {\n content.scrollTop = anno.position - 50;\n }\n onAnnotationClicked({annotationId: anno.id, annotation: anno});\n };\n\n overlay.appendChild(el);\n });\n }, [annotations, onAnnotationClicked, onAnnotationHovered]);\n\n // Re-render markers whenever annotations change, or the overlay is resized.\n // ResizeObserver fires on initial layout (when clientHeight goes from 0 to\n // the real value) as well as on subsequent window/container resizes, so\n // markers are always positioned against the actual DOM height.\n useEffect(() => {\n const overlay = overlayRef.current;\n const content = contentRef.current;\n\n // Observe the overlay element so markers are re-drawn whenever its size\n // changes — including the very first layout pass.\n const ro = new ResizeObserver(() => renderMarkers());\n if (overlay) ro.observe(overlay);\n\n const handleScroll = () => {\n // When reporting on scroll is enabled, skip suppression entirely.\n if (reportEventsOnScroll) return;\n\n // Set the scrolling flag so marker hover events are suppressed.\n // We intentionally do NOT dispatch a hover-clear here — marker\n // onMouseLeave events handle that when the pointer actually leaves,\n // and dispatching during scroll can interfere with parent state.\n isScrollingRef.current = true;\n\n // Reset the idle timer on every scroll event.\n if (scrollTimerRef.current !== null) {\n clearTimeout(scrollTimerRef.current);\n }\n scrollTimerRef.current = setTimeout(() => {\n isScrollingRef.current = false;\n scrollTimerRef.current = null;\n }, 150);\n };\n\n content?.addEventListener(\"scroll\", handleScroll, {passive: true});\n\n return () => {\n ro.disconnect();\n content?.removeEventListener(\"scroll\", handleScroll);\n if (scrollTimerRef.current !== null) {\n clearTimeout(scrollTimerRef.current);\n }\n };\n }, [renderMarkers, reportEventsOnScroll]);\n\n return (\n <div\n data-pihanga={cardName}\n className={`swa-root${className ? ` ${className}` : \"\"}`}\n >\n <div className=\"swa-content-wrapper\">\n {/* Scrollable content area */}\n <div ref={contentRef} className=\"swa-scroll-container\">\n <Card cardName={contentCard} parentCard={cardName} />\n </div>\n\n {/* Annotation minimap overlay – sits on top of the scrollbar track */}\n <div ref={overlayRef} className=\"swa-overlay\" />\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;AA8BA,IAAa,KACX,MAIoB;CACpB,IAAM,EACJ,gBACA,iBAAc,CAAC,GACf,cACA,0BAAuB,IACvB,aACA,wBACA,2BACE,GAEE,IAAa,EAAuB,IAAI,GACxC,IAAa,EAAuB,IAAI,GAOxC,IAAiB,EAAO,EAAK,GAC7B,IAAiB,EAA6C,IAAI,GAMlE,IAAgB,QAAkB;EACtC,IAAM,IAAU,EAAW,SACrB,IAAU,EAAW;EAC3B,IAAI,CAAC,KAAW,CAAC,GAAS;EAE1B,EAAQ,YAAY;EACpB,IAAM,IAAW,EAAQ,cACnB,IAAiB,EAAQ,gBAAgB;EAE/C,EAAY,SAAS,MAA8B;GACjD,IAAM,IAAa,EAAK,cAAc,SAChC,IAAS,EAAK,WAAW,IAAkB,GAE3C,IAAK,SAAS,cAAc,KAAK;GAgBvC,IAbA,EAAG,YAAY;IACb;IACA,cAAc;IACd,YAAY,EAAK;IACjB,EAAK;GACP,EACG,OAAO,OAAO,EACd,KAAK,GAAG,GACX,EAAG,MAAM,MAAM,GAAG,EAAM,KAKpB,MAAe,WAAW,EAAK,WAAW,KAAA,GAAW;IACvD,IAAM,IAAY,EAAK,SAAS,IAAkB;IAClD,EAAG,MAAM,SAAS,GAAG,EAAS;GAChC;GAoBA,AAlBA,EAAG,qBAAqB;IAClB,EAAe,YACnB,EAAG,UAAU,IAAI,mBAAmB,GACpC,IAAsB;KAAC,cAAc,EAAK;KAAI,YAAY;IAAI,CAAC;GACjE,GACA,EAAG,qBAAqB;IAClB,EAAe,YACnB,EAAG,UAAU,OAAO,mBAAmB,GACvC,IAAsB;KAAC,cAAc;KAAM,YAAY;IAAI,CAAC;GAC9D,GACA,EAAG,WAAW,MAAM;IAKlB,AAJA,EAAE,gBAAgB,GACd,MACF,EAAQ,YAAY,EAAK,WAAW,KAEtC,EAAoB;KAAC,cAAc,EAAK;KAAI,YAAY;IAAI,CAAC;GAC/D,GAEA,EAAQ,YAAY,CAAE;EACxB,CAAC;CACH,GAAG;EAAC;EAAa;EAAqB;CAAmB,CAAC;CA8C1D,OAxCA,QAAgB;EACd,IAAM,IAAU,EAAW,SACrB,IAAU,EAAW,SAIrB,IAAK,IAAI,qBAAqB,EAAc,CAAC;EACnD,AAAI,KAAS,EAAG,QAAQ,CAAO;EAE/B,IAAM,UAAqB;GAErB,MAMJ,EAAe,UAAU,IAGrB,EAAe,YAAY,QAC7B,aAAa,EAAe,OAAO,GAErC,EAAe,UAAU,iBAAiB;IAExC,AADA,EAAe,UAAU,IACzB,EAAe,UAAU;GAC3B,GAAG,GAAG;EACR;EAIA,OAFA,GAAS,iBAAiB,UAAU,GAAc,EAAC,SAAS,GAAI,CAAC,SAEpD;GAGX,AAFA,EAAG,WAAW,GACd,GAAS,oBAAoB,UAAU,CAAY,GAC/C,EAAe,YAAY,QAC7B,aAAa,EAAe,OAAO;EAEvC;CACF,GAAG,CAAC,GAAe,CAAoB,CAAC,GAGtC,kBAAC,OAAD;EACE,gBAAc;EACd,WAAW,WAAW,IAAY,IAAI,MAAc;YAEpD,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,OAAD;IAAK,KAAK;IAAY,WAAU;cAC9B,kBAAC,GAAD;KAAM,UAAU;KAAa,YAAY;IAAW,CAAA;GACjD,CAAA,GAGL,kBAAC,OAAD;IAAK,KAAK;IAAY,WAAU;GAAe,CAAA,CAC5C;;CACF,CAAA;AAET"}
@@ -0,0 +1 @@
1
+ .swa-root{flex-direction:column;min-height:0;display:flex}.swa-content-wrapper{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.swa-scroll-container{flex:1;min-height:0;overflow:auto}.swa-scroll-container::-webkit-scrollbar{width:14px}.swa-scroll-container::-webkit-scrollbar-track{background:var(--color-background-tertiary,#f5f5f5)}.swa-scroll-container::-webkit-scrollbar-thumb{background:var(--color-border-secondary,#ccc);border:2px solid var(--color-background-primary,#fff);border-radius:6px}.swa-overlay{pointer-events:none;z-index:1;width:12px;height:100%;position:absolute;top:0;right:2px}.swa-marker{cursor:pointer;pointer-events:auto;transition:opacity .15s,transform .15s,box-shadow .15s;position:absolute;left:0}:root{--swa-point-size:10px}.swa-marker-point{width:var(--swa-point-size);height:var(--swa-point-size);border:2px solid #fff;border-radius:50%;left:2px;transform:translateY(-50%);box-shadow:0 0 4px #0000004d}.swa-marker-point.swa-marker--hover{transform:translateY(-50%)scale(1.5)}:root{--swa-bar-width:10px;--swa-bar-height:10px}.swa-marker-bar{width:var(--swa-bar-width);height:var(--swa-bar-height);opacity:.8;border-radius:1px;transform:translateY(-50%)}.swa-marker-bar.swa-marker--hover{opacity:1;box-shadow:0 0 4px #0006}:root{--swa-range-width:8px;--swa-range-min-height:8px}.swa-marker-range{width:var(--swa-range-width);min-height:var(--swa-range-min-height);opacity:.4;border-left:2px solid #fff;border-radius:2px;box-shadow:inset 0 0 2px #0003}.swa-marker-range.swa-marker--hover{opacity:.65;box-shadow:0 0 6px #0006}:root{--swa-color-error:#e24b4a;--swa-color-warning:#f39c12;--swa-color-todo:#378add;--swa-color-comment:#95a5a6;--swa-color-review:#888780;--swa-color-fixme:#ba7517}.swa-type-error{background:var(--swa-color-error)}.swa-type-warning{background:var(--swa-color-warning)}.swa-type-todo{background:var(--swa-color-todo)}.swa-type-comment{background:var(--swa-color-comment)}.swa-type-review{background:var(--swa-color-review)}.swa-type-fixme{background:var(--swa-color-fixme)}
@@ -0,0 +1,123 @@
1
+ import { PiCardRef } from '@pihanga2/core';
2
+ export declare const SCROLLBAR_WITH_ANNOTATIONS_CARD = "pi/scrollbar-with-annotations";
3
+ export declare const ScrollbarWithAnnotations: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<ScrollbarWithAnnotationsProps, S, ScrollbarWithAnnotationsEvents>) => import('@pihanga2/core').PiCardDef;
4
+ export declare const SCROLLBAR_WITH_ANNOTATIONS_ACTION: {
5
+ ANNOTATION_CLICKED: string;
6
+ ANNOTATION_HOVERED: string;
7
+ };
8
+ export declare const onScrollbarAnnotationClicked: <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
+ } & AnnotationClickedEvent>) => void;
11
+ export declare const onScrollbarAnnotationHovered: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
12
+ cardID: string;
13
+ } & AnnotationHoveredEvent>) => void;
14
+ /**
15
+ * The visual category of an annotation, which determines its colour on the
16
+ * scrollbar minimap.
17
+ */
18
+ export type AnnotationType = "error" | "warning" | "todo" | "comment" | "review" | "fixme";
19
+ /**
20
+ * Shape of the marker drawn on the scrollbar track.
21
+ *
22
+ * - `"point"` – a small circular dot (default).
23
+ * - `"bar"` – a short vertical rectangle with a fixed CSS height; useful for
24
+ * discrete events that have a known position but no meaningful
25
+ * extent.
26
+ * - `"range"` – a vertical rectangle whose height is proportional to `extent`
27
+ * in the content's scroll space, with a CSS-enforced minimum
28
+ * height so tiny ranges remain clickable. Requires `extent`.
29
+ */
30
+ export type MarkerType = "point" | "bar" | "range";
31
+ /**
32
+ * A single annotation marker placed on the scrollbar minimap.
33
+ *
34
+ * All positions are **pixel offsets from the top of the scrollable content**
35
+ * (i.e. relative to `scrollHeight`).
36
+ *
37
+ * | markerType | required fields |
38
+ * |------------|--------------------------|
39
+ * | `"point"` | `position` |
40
+ * | `"bar"` | `position` |
41
+ * | `"range"` | `position` + `extent` |
42
+ */
43
+ export type ScrollbarAnnotation = {
44
+ /** Unique identifier for this annotation. */
45
+ id: string;
46
+ /**
47
+ * Pixel offset from the top of the scrollable content.
48
+ * Acts as the start position for range markers.
49
+ */
50
+ position: number;
51
+ /**
52
+ * Length of the annotation in content pixels.
53
+ *
54
+ * Required when `markerType === "range"`. The marker will span
55
+ * `[position, position + extent]` in content space.
56
+ */
57
+ extent?: number;
58
+ /**
59
+ * Shape of the minimap marker. Defaults to `"point"`.
60
+ */
61
+ markerType?: MarkerType;
62
+ /** Visual category – controls colour. */
63
+ type: AnnotationType;
64
+ /** Short human-readable label shown in detail views. */
65
+ title: string;
66
+ /** Full description shown when the annotation is selected/inspected. */
67
+ description: string;
68
+ /**
69
+ * Optional extra CSS class(es) applied to this marker's DOM element.
70
+ *
71
+ * Use this to style individual annotations differently from the default
72
+ * type-based colour, e.g. to highlight a "selected" annotation:
73
+ *
74
+ * className: "swa-selected"
75
+ */
76
+ className?: string;
77
+ };
78
+ export type ScrollbarWithAnnotationsProps = {
79
+ /**
80
+ * Pihanga card reference for the scrollable main content.
81
+ *
82
+ * The card is rendered inside the scroll container, so it can be any
83
+ * Pihanga card (plain text, a Plate editor, a list, etc.).
84
+ */
85
+ contentCard: PiCardRef;
86
+ /**
87
+ * Annotations to display as coloured markers on the scrollbar track.
88
+ */
89
+ annotations: ScrollbarAnnotation[];
90
+ /** Optional additional CSS class applied to the root element. */
91
+ className?: string;
92
+ /**
93
+ * When `true`, `onAnnotationHovered` events are emitted even while the
94
+ * content container is being scrolled.
95
+ *
96
+ * Defaults to `false` (suppression is the default) to avoid flooding Redux
97
+ * with hover actions as markers pass under the cursor during scroll.
98
+ */
99
+ reportEventsOnScroll?: boolean;
100
+ };
101
+ /** Emitted when the user clicks an annotation marker. */
102
+ export type AnnotationClickedEvent = {
103
+ /** ID of the clicked annotation. */
104
+ annotationId: string;
105
+ /** Full annotation object for convenience. */
106
+ annotation: ScrollbarAnnotation;
107
+ };
108
+ /**
109
+ * Emitted when the user hovers over (or away from) an annotation marker.
110
+ *
111
+ * `annotationId` / `annotation` are `null` when the pointer leaves a marker.
112
+ *
113
+ * ⚠️ This event fires frequently during normal cursor movement. Handlers
114
+ * should be kept lightweight (e.g. update a single piece of local state).
115
+ */
116
+ export type AnnotationHoveredEvent = {
117
+ annotationId: string | null;
118
+ annotation: ScrollbarAnnotation | null;
119
+ };
120
+ export type ScrollbarWithAnnotationsEvents = {
121
+ onAnnotationClicked: AnnotationClickedEvent;
122
+ onAnnotationHovered: AnnotationHoveredEvent;
123
+ };
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
+ //#region src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.ts
3
+ var r = "pi/scrollbar-with-annotations", i = e(r), a = n(r, ["annotation_clicked", "annotation_hovered"]), o = t(a.ANNOTATION_CLICKED), s = t(a.ANNOTATION_HOVERED);
4
+ //#endregion
5
+ export { a as SCROLLBAR_WITH_ANNOTATIONS_ACTION, r as SCROLLBAR_WITH_ANNOTATIONS_CARD, i as ScrollbarWithAnnotations, o as onScrollbarAnnotationClicked, s as onScrollbarAnnotationHovered };
6
+
7
+ //# sourceMappingURL=scrollbarWithAnnotations.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrollbarWithAnnotations.types.js","names":[],"sources":["../../../src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n type PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const SCROLLBAR_WITH_ANNOTATIONS_CARD = \"pi/scrollbar-with-annotations\";\n\nexport const ScrollbarWithAnnotations = createCardDeclaration<\n ScrollbarWithAnnotationsProps,\n ScrollbarWithAnnotationsEvents\n>(SCROLLBAR_WITH_ANNOTATIONS_CARD);\n\nexport const SCROLLBAR_WITH_ANNOTATIONS_ACTION = registerActions(\n SCROLLBAR_WITH_ANNOTATIONS_CARD,\n [\"annotation_clicked\", \"annotation_hovered\"],\n);\n\nexport const onScrollbarAnnotationClicked =\n createOnAction<AnnotationClickedEvent>(\n SCROLLBAR_WITH_ANNOTATIONS_ACTION.ANNOTATION_CLICKED,\n );\n\nexport const onScrollbarAnnotationHovered =\n createOnAction<AnnotationHoveredEvent>(\n SCROLLBAR_WITH_ANNOTATIONS_ACTION.ANNOTATION_HOVERED,\n );\n\n/**\n * The visual category of an annotation, which determines its colour on the\n * scrollbar minimap.\n */\nexport type AnnotationType =\n | \"error\"\n | \"warning\"\n | \"todo\"\n | \"comment\"\n | \"review\"\n | \"fixme\";\n\n/**\n * Shape of the marker drawn on the scrollbar track.\n *\n * - `\"point\"` – a small circular dot (default).\n * - `\"bar\"` – a short vertical rectangle with a fixed CSS height; useful for\n * discrete events that have a known position but no meaningful\n * extent.\n * - `\"range\"` – a vertical rectangle whose height is proportional to `extent`\n * in the content's scroll space, with a CSS-enforced minimum\n * height so tiny ranges remain clickable. Requires `extent`.\n */\nexport type MarkerType = \"point\" | \"bar\" | \"range\";\n\n/**\n * A single annotation marker placed on the scrollbar minimap.\n *\n * All positions are **pixel offsets from the top of the scrollable content**\n * (i.e. relative to `scrollHeight`).\n *\n * | markerType | required fields |\n * |------------|--------------------------|\n * | `\"point\"` | `position` |\n * | `\"bar\"` | `position` |\n * | `\"range\"` | `position` + `extent` |\n */\nexport type ScrollbarAnnotation = {\n /** Unique identifier for this annotation. */\n id: string;\n\n /**\n * Pixel offset from the top of the scrollable content.\n * Acts as the start position for range markers.\n */\n position: number;\n\n /**\n * Length of the annotation in content pixels.\n *\n * Required when `markerType === \"range\"`. The marker will span\n * `[position, position + extent]` in content space.\n */\n extent?: number;\n\n /**\n * Shape of the minimap marker. Defaults to `\"point\"`.\n */\n markerType?: MarkerType;\n\n /** Visual category – controls colour. */\n type: AnnotationType;\n\n /** Short human-readable label shown in detail views. */\n title: string;\n\n /** Full description shown when the annotation is selected/inspected. */\n description: string;\n\n /**\n * Optional extra CSS class(es) applied to this marker's DOM element.\n *\n * Use this to style individual annotations differently from the default\n * type-based colour, e.g. to highlight a \"selected\" annotation:\n *\n * className: \"swa-selected\"\n */\n className?: string;\n};\n\nexport type ScrollbarWithAnnotationsProps = {\n /**\n * Pihanga card reference for the scrollable main content.\n *\n * The card is rendered inside the scroll container, so it can be any\n * Pihanga card (plain text, a Plate editor, a list, etc.).\n */\n contentCard: PiCardRef;\n\n /**\n * Annotations to display as coloured markers on the scrollbar track.\n */\n annotations: ScrollbarAnnotation[];\n\n /** Optional additional CSS class applied to the root element. */\n className?: string;\n\n /**\n * When `true`, `onAnnotationHovered` events are emitted even while the\n * content container is being scrolled.\n *\n * Defaults to `false` (suppression is the default) to avoid flooding Redux\n * with hover actions as markers pass under the cursor during scroll.\n */\n reportEventsOnScroll?: boolean;\n};\n\n/** Emitted when the user clicks an annotation marker. */\nexport type AnnotationClickedEvent = {\n /** ID of the clicked annotation. */\n annotationId: string;\n /** Full annotation object for convenience. */\n annotation: ScrollbarAnnotation;\n};\n\n/**\n * Emitted when the user hovers over (or away from) an annotation marker.\n *\n * `annotationId` / `annotation` are `null` when the pointer leaves a marker.\n *\n * ⚠️ This event fires frequently during normal cursor movement. Handlers\n * should be kept lightweight (e.g. update a single piece of local state).\n */\nexport type AnnotationHoveredEvent = {\n annotationId: string | null;\n annotation: ScrollbarAnnotation | null;\n};\n\nexport type ScrollbarWithAnnotationsEvents = {\n onAnnotationClicked: AnnotationClickedEvent;\n onAnnotationHovered: AnnotationHoveredEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAkC,iCAElC,IAA2B,EAGtC,CAA+B,GAEpB,IAAoC,EAC/C,GACA,CAAC,sBAAsB,oBAAoB,CAC7C,GAEa,IACX,EACE,EAAkC,kBACpC,GAEW,IACX,EACE,EAAkC,kBACpC"}