@lad-sapienza/scms-core 0.1.0-alpha.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/LICENSE +14 -0
- package/README.md +73 -0
- package/components/BSNavbar.tsx +264 -0
- package/components/DataTb/DataTb.astro +33 -0
- package/components/DataTb/DataTb.tsx +340 -0
- package/components/DataTb/DataTbMdx.tsx +75 -0
- package/components/DataTb/README.md +275 -0
- package/components/DataTb/index.ts +36 -0
- package/components/DataTb/sources/ApiSource.tsx +89 -0
- package/components/DataTb/sources/CsvSource.tsx +69 -0
- package/components/DataTb/sources/DirectusSource.tsx +98 -0
- package/components/DataTb/sources/JsonSource.tsx +65 -0
- package/components/DataTb/sources/index.ts +17 -0
- package/components/DataTb/types.ts +215 -0
- package/components/DataTb/utils.ts +186 -0
- package/components/Gallery/Gallery.astro +65 -0
- package/components/Gallery/Gallery.tsx +136 -0
- package/components/Gallery/README.md +118 -0
- package/components/Gallery/__tests__/galleryUtils.test.ts +178 -0
- package/components/Gallery/galleryUtils.ts +186 -0
- package/components/Gallery/index.ts +7 -0
- package/components/Gallery/react-photoswipe-gallery.d.ts +26 -0
- package/components/Gallery/types.ts +46 -0
- package/components/Gallery/virtual-gallery.d.ts +15 -0
- package/components/Map/LayerControl.tsx +368 -0
- package/components/Map/Map.tsx +735 -0
- package/components/Map/MapMdx.tsx +37 -0
- package/components/Map/RasterLayerLibre.tsx +33 -0
- package/components/Map/Search/SearchOperators.ts +31 -0
- package/components/Map/Search/SearchUI.tsx +75 -0
- package/components/Map/Search/SearchUIAdvanced.tsx +289 -0
- package/components/Map/Search/SearchUISimple.tsx +115 -0
- package/components/Map/Search/index.ts +7 -0
- package/components/Map/defaultBasemaps.ts +88 -0
- package/components/Map/index.ts +6 -0
- package/components/Map/types.ts +179 -0
- package/components/Map/utils.ts +367 -0
- package/components/README.md +62 -0
- package/components/Record/Field.tsx +35 -0
- package/components/Record/Image.tsx +114 -0
- package/components/Record/RecordFetcher.tsx +127 -0
- package/components/Record/context.tsx +14 -0
- package/components/Record/index.ts +11 -0
- package/components/Record/useRecordFetcher.ts +104 -0
- package/components/Record/utils.ts +13 -0
- package/components/SEO/SEO.astro +132 -0
- package/components/TableOfContents/TableOfContents.astro +86 -0
- package/components/ZoteroGeoViewer/README.md +195 -0
- package/components/ZoteroGeoViewer/ZoteroGeoViewer.astro +26 -0
- package/components/ZoteroGeoViewer/ZoteroGeoViewer.tsx +483 -0
- package/components/ZoteroGeoViewer/ZoteroRecordsPreview.tsx +185 -0
- package/components/ZoteroGeoViewer/index.ts +16 -0
- package/components/ZoteroGeoViewer/types.ts +123 -0
- package/index.ts +26 -0
- package/integrations/__tests__/galleryIntegration.test.ts +70 -0
- package/integrations/contentAssetsIntegration.ts +132 -0
- package/integrations/directusLoader.ts +98 -0
- package/integrations/galleryIntegration.ts +78 -0
- package/package.json +56 -0
- package/scms.ts +95 -0
- package/utils/content.ts +88 -0
- package/utils/data-fetcher.ts +128 -0
- package/utils/directus-config.ts +160 -0
- package/utils/record-fetcher.ts +132 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
BSD Zero Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LAD: Laboratorio di Archeologia Digitale alla Sapienza
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
9
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
10
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
11
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
12
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
13
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
14
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @lad-sapienza/scms-core
|
|
2
|
+
|
|
3
|
+
Framework components and Astro integrations for [s:CMS](https://github.com/lad-sapienza/sCMS) — the static-site CMS built by [LAD @Sapienza](https://lad.saras.uniroma1.it/).
|
|
4
|
+
|
|
5
|
+
This package supplies the `core/` framework layer that used to live inside the sCMS template repo itself. A site built with sCMS depends on this package from `node_modules` instead of vendoring/syncing it via git, so updates are ordinary `npm update`s.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @lad-sapienza/scms-core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Peer dependencies (install alongside): `astro`, `react`, `react-dom`, `maplibre-gl`, `@types/react`, `@types/react-dom`.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Register the integration in `astro.config.mjs`:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { defineConfig } from 'astro/config';
|
|
21
|
+
import { scms } from '@lad-sapienza/scms-core';
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
integrations: [
|
|
25
|
+
...scms({
|
|
26
|
+
// all optional, default to the paths below
|
|
27
|
+
contentDir: 'usr/content',
|
|
28
|
+
pagesDir: 'usr/pages',
|
|
29
|
+
galleriesDir: 'usr/galleries',
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`scms()` bundles content-asset serving, the Gallery virtual module, Expressive Code, MDX, React, and sitemap integrations into one call, and self-registers the Vite `dedupe`/`optimizeDeps` config React and `@tanstack/react-table` need to avoid duplicate-module "Invalid hook call" errors — no extra Vite config required in the consumer.
|
|
36
|
+
|
|
37
|
+
Import components from the package root in any `.mdx` file:
|
|
38
|
+
|
|
39
|
+
```mdx
|
|
40
|
+
import { DataTb, Map, Gallery } from '@lad-sapienza/scms-core';
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Component | Description |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `DataTb` | Sortable, filterable, paginated data table |
|
|
46
|
+
| `MapComponent` (`Map`) | Interactive map with MapLibre GL JS |
|
|
47
|
+
| `Gallery` | Responsive image gallery with lightbox |
|
|
48
|
+
| `TableOfContents` | Auto-generated TOC from headings |
|
|
49
|
+
| `ZoteroGeoViewer` | Zotero library visualised on a map |
|
|
50
|
+
| `RecordProvider`, `Field`, `Image`, `RecordFetcher`, `useRecordFetcher` | Build single-record detail pages against Directus |
|
|
51
|
+
| `SearchUI`, `SearchUISimple`, `SearchUIAdvanced` | Field/operator/value search UI (used by `Map`'s `searchInFields`) |
|
|
52
|
+
|
|
53
|
+
A few components are reachable only via subpath import, not the root barrel — this mirrors the internal layout, no bundler config or `exports` map restricts it:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
import SEO from '@lad-sapienza/scms-core/components/SEO/SEO.astro';
|
|
57
|
+
import BSNavbar from '@lad-sapienza/scms-core/components/BSNavbar';
|
|
58
|
+
import { directusLoader } from '@lad-sapienza/scms-core/integrations/directusLoader';
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
See each component folder's own `README.md` (`components/DataTb`, `components/Gallery`, `components/ZoteroGeoViewer`, `components/`) for detailed API docs and examples.
|
|
62
|
+
|
|
63
|
+
## Development
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install
|
|
67
|
+
npm run test # vitest
|
|
68
|
+
npm run typecheck # tsc --noEmit
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
BSD-0-Clause
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
2
|
+
import { Menu, X, ChevronRight } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A single navigation link entry.
|
|
6
|
+
*
|
|
7
|
+
* - `href` — URL the link points to. Optional for parent items that only open a dropdown.
|
|
8
|
+
* - `label` — visible text.
|
|
9
|
+
* - `match` — optional path prefix used for active detection (falls back to `href`).
|
|
10
|
+
* Useful when a parent item has no `href` but should be highlighted for a subtree,
|
|
11
|
+
* e.g. `match: "/docs"` highlights the "Docs" entry for any `/docs/*` page.
|
|
12
|
+
* - `children` — nested items, enabling up to 3 levels of dropdown menus.
|
|
13
|
+
*/
|
|
14
|
+
interface MenuItem {
|
|
15
|
+
href?: string;
|
|
16
|
+
label: string;
|
|
17
|
+
match?: string;
|
|
18
|
+
children?: MenuItem[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Brand / logo configuration for the navbar. */
|
|
22
|
+
interface BrandProps {
|
|
23
|
+
/** Text displayed as the brand name. */
|
|
24
|
+
text: string;
|
|
25
|
+
/** URL the brand name links to. */
|
|
26
|
+
link: string;
|
|
27
|
+
/** Additional CSS classes applied to the brand anchor. */
|
|
28
|
+
cssClasses?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Optional CSS class overrides for individual navbar elements. */
|
|
32
|
+
interface CssClasses {
|
|
33
|
+
/** Classes applied to the `<nav>` element. */
|
|
34
|
+
nav?: string;
|
|
35
|
+
/** Classes applied to the `<ul>` list. */
|
|
36
|
+
ul?: string;
|
|
37
|
+
/** Classes applied to each `<li>` item. */
|
|
38
|
+
li?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Bootstrap-compatible responsive navbar with a React-controlled toggle.
|
|
43
|
+
* Active state is computed internally from `currentPath` — no need to set
|
|
44
|
+
* `isActive` on individual menu items.
|
|
45
|
+
*
|
|
46
|
+
* Menu data can be loaded from a YAML file (e.g. `usr/content/data/menu.yaml`)
|
|
47
|
+
* and passed straight to `menuItems`.
|
|
48
|
+
*
|
|
49
|
+
* Must be hydrated with `client:load` when used inside an Astro component.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```astro
|
|
53
|
+
* ---
|
|
54
|
+
* import { getEntry } from 'astro:content';
|
|
55
|
+
* const menuEntry = await getEntry('menu', 'menu');
|
|
56
|
+
* ---
|
|
57
|
+
* <BSNavbar
|
|
58
|
+
* client:load
|
|
59
|
+
* menuItems={menuEntry?.data ?? []}
|
|
60
|
+
* currentPath={Astro.url.pathname}
|
|
61
|
+
* cssClasses={{ nav: "sticky-top shadow-sm", ul: "ms-auto" }}
|
|
62
|
+
* brand={{ text: "My Site", link: "/" }}
|
|
63
|
+
* />
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @example YAML menu structure (`usr/content/data/menu.yaml`)
|
|
67
|
+
* ```yaml
|
|
68
|
+
* - href: /
|
|
69
|
+
* label: Home
|
|
70
|
+
* - label: Docs
|
|
71
|
+
* match: /docs
|
|
72
|
+
* children:
|
|
73
|
+
* - href: /docs/guides/getting-started
|
|
74
|
+
* label: Getting Started
|
|
75
|
+
* - label: Components
|
|
76
|
+
* children:
|
|
77
|
+
* - href: /docs/components/datatb
|
|
78
|
+
* label: DataTb
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
interface BSNavbarProps {
|
|
82
|
+
/** Array of navigation items to render in the menu. */
|
|
83
|
+
menuItems: MenuItem[];
|
|
84
|
+
/**
|
|
85
|
+
* Current page path (e.g. `Astro.url.pathname`).
|
|
86
|
+
* Used internally to compute which items are active.
|
|
87
|
+
*/
|
|
88
|
+
currentPath?: string;
|
|
89
|
+
/** Optional CSS class overrides for navbar sub-elements. */
|
|
90
|
+
cssClasses?: CssClasses;
|
|
91
|
+
/** Optional brand / logo configuration. Omit to hide the brand area. */
|
|
92
|
+
brand?: BrandProps;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Active detection
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
/** Returns true when `item` (or any descendant) matches `currentPath`. */
|
|
100
|
+
function isItemActive(item: MenuItem, currentPath: string): boolean {
|
|
101
|
+
const target = item.match ?? item.href;
|
|
102
|
+
if (target) {
|
|
103
|
+
const active = target === "/" ? currentPath === "/" : currentPath.startsWith(target);
|
|
104
|
+
if (active) return true;
|
|
105
|
+
}
|
|
106
|
+
return item.children?.some(child => isItemActive(child, currentPath)) ?? false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// DropdownItem — item inside a dropdown (level ≥ 2)
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
const DropdownItem: React.FC<{ item: MenuItem; currentPath: string }> = ({ item, currentPath }) => {
|
|
113
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
114
|
+
const [openLeft, setOpenLeft] = useState(false);
|
|
115
|
+
const ref = useRef<HTMLLIElement>(null);
|
|
116
|
+
const hasChildren = !!item.children?.length;
|
|
117
|
+
const active = isItemActive(item, currentPath);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!isOpen) return;
|
|
121
|
+
const close = (e: MouseEvent) => {
|
|
122
|
+
if (ref.current && !ref.current.contains(e.target as Node)) setIsOpen(false);
|
|
123
|
+
};
|
|
124
|
+
document.addEventListener("mousedown", close);
|
|
125
|
+
return () => document.removeEventListener("mousedown", close);
|
|
126
|
+
}, [isOpen]);
|
|
127
|
+
|
|
128
|
+
const handleToggle = () => {
|
|
129
|
+
if (!isOpen && ref.current) {
|
|
130
|
+
const rect = ref.current.getBoundingClientRect();
|
|
131
|
+
setOpenLeft(rect.left > window.innerWidth / 2);
|
|
132
|
+
}
|
|
133
|
+
setIsOpen(p => !p);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (!hasChildren) {
|
|
137
|
+
return (
|
|
138
|
+
<li>
|
|
139
|
+
<a
|
|
140
|
+
className={`dropdown-item${active ? " active" : ""}`}
|
|
141
|
+
href={item.href ?? "#"}
|
|
142
|
+
>
|
|
143
|
+
{item.label}
|
|
144
|
+
</a>
|
|
145
|
+
</li>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<li ref={ref} style={{ position: "relative" }}>
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
className={`dropdown-item d-flex justify-content-between align-items-center${active ? " active" : ""}`}
|
|
154
|
+
onClick={handleToggle}
|
|
155
|
+
aria-expanded={isOpen}
|
|
156
|
+
>
|
|
157
|
+
{item.label}
|
|
158
|
+
<ChevronRight size={14} className="ms-2 flex-shrink-0" />
|
|
159
|
+
</button>
|
|
160
|
+
{isOpen && (
|
|
161
|
+
<ul
|
|
162
|
+
className="dropdown-menu show"
|
|
163
|
+
style={openLeft
|
|
164
|
+
? { position: "absolute", right: "100%", left: "auto", top: 0, minWidth: "12rem" }
|
|
165
|
+
: { position: "absolute", left: "100%", top: 0, minWidth: "12rem" }
|
|
166
|
+
}
|
|
167
|
+
>
|
|
168
|
+
{item.children!.map((child, i) => (
|
|
169
|
+
<DropdownItem key={child.href ?? i} item={child} currentPath={currentPath} />
|
|
170
|
+
))}
|
|
171
|
+
</ul>
|
|
172
|
+
)}
|
|
173
|
+
</li>
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// NavItem — top-level nav entry (level 1)
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
const NavItem: React.FC<{ item: MenuItem; currentPath: string; liClass?: string }> = ({ item, currentPath, liClass }) => {
|
|
181
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
182
|
+
const ref = useRef<HTMLLIElement>(null);
|
|
183
|
+
const hasChildren = !!item.children?.length;
|
|
184
|
+
const active = isItemActive(item, currentPath);
|
|
185
|
+
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (!isOpen) return;
|
|
188
|
+
const close = (e: MouseEvent) => {
|
|
189
|
+
if (ref.current && !ref.current.contains(e.target as Node)) setIsOpen(false);
|
|
190
|
+
};
|
|
191
|
+
document.addEventListener("mousedown", close);
|
|
192
|
+
return () => document.removeEventListener("mousedown", close);
|
|
193
|
+
}, [isOpen]);
|
|
194
|
+
|
|
195
|
+
const liBase = `nav-item${hasChildren ? " dropdown" : ""}${active ? " active" : ""}${liClass ? ` ${liClass}` : ""}`;
|
|
196
|
+
|
|
197
|
+
if (!hasChildren) {
|
|
198
|
+
return (
|
|
199
|
+
<li className={liBase} ref={ref}>
|
|
200
|
+
<a className={`nav-link${active ? " active" : ""}`} href={item.href ?? "#"}>
|
|
201
|
+
{item.label}
|
|
202
|
+
</a>
|
|
203
|
+
</li>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return (
|
|
208
|
+
<li className={liBase} ref={ref}>
|
|
209
|
+
<button
|
|
210
|
+
type="button"
|
|
211
|
+
className={`nav-link dropdown-toggle${active ? " active" : ""}`}
|
|
212
|
+
onClick={() => setIsOpen(p => !p)}
|
|
213
|
+
aria-expanded={isOpen}
|
|
214
|
+
>
|
|
215
|
+
{item.label}
|
|
216
|
+
</button>
|
|
217
|
+
{isOpen && (
|
|
218
|
+
<ul className="dropdown-menu show">
|
|
219
|
+
{item.children!.map((child, i) => (
|
|
220
|
+
<DropdownItem key={child.href ?? i} item={child} currentPath={currentPath} />
|
|
221
|
+
))}
|
|
222
|
+
</ul>
|
|
223
|
+
)}
|
|
224
|
+
</li>
|
|
225
|
+
);
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
// BSNavbar — root component
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
const BSNavbar: React.FC<BSNavbarProps> = ({ menuItems, currentPath = "/", cssClasses = {}, brand }) => {
|
|
232
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<nav className={`navbar navbar-expand-md ${cssClasses.nav ?? ""}`}>
|
|
236
|
+
<div className="container">
|
|
237
|
+
{brand && (
|
|
238
|
+
<a className={`navbar-brand ${brand.cssClasses ?? ""}`} href={brand.link}>
|
|
239
|
+
{brand.text}
|
|
240
|
+
</a>
|
|
241
|
+
)}
|
|
242
|
+
<button
|
|
243
|
+
className="navbar-toggler border-0 p-2"
|
|
244
|
+
type="button"
|
|
245
|
+
onClick={() => setIsOpen(prev => !prev)}
|
|
246
|
+
aria-controls="navbarCollapse"
|
|
247
|
+
aria-expanded={isOpen}
|
|
248
|
+
aria-label="Toggle navigation"
|
|
249
|
+
>
|
|
250
|
+
{isOpen ? <X size={24} className="text-dark" /> : <Menu size={24} className="text-dark" />}
|
|
251
|
+
</button>
|
|
252
|
+
<div className={`collapse navbar-collapse${isOpen ? " show" : ""}`} id="navbarCollapse">
|
|
253
|
+
<ul className={`navbar-nav ${cssClasses.ul ?? ""}`}>
|
|
254
|
+
{menuItems.map((item, i) => (
|
|
255
|
+
<NavItem key={item.href ?? i} item={item} currentPath={currentPath} liClass={cssClasses.li} />
|
|
256
|
+
))}
|
|
257
|
+
</ul>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</nav>
|
|
261
|
+
);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export default BSNavbar;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* DataTb Astro Wrapper
|
|
4
|
+
*
|
|
5
|
+
* Astro component that wraps the React DataTb component
|
|
6
|
+
* This file exists for documentation and re-export purposes.
|
|
7
|
+
* In MDX files, import the React component directly with a hydration directive.
|
|
8
|
+
*
|
|
9
|
+
* Example usage in MDX:
|
|
10
|
+
* ```jsx
|
|
11
|
+
* import { DataTb } from '@lad-sapienza/scms-core/components/DataTb';
|
|
12
|
+
*
|
|
13
|
+
* <DataTb csv="/data.csv" searchable pagination client:idle />
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* CsvSource / JsonSource / DirectusSource / ApiSource are also exported, but as
|
|
17
|
+
* headless data-loaders (they render nothing; they call onDataLoad/onLoadingChange/
|
|
18
|
+
* onError) for building a fully custom table UI — they are not children of
|
|
19
|
+
* <DataTb>, which has no children/composition API. See the "Headless Source
|
|
20
|
+
* Components" section of usr/content/docs/components/datatb.mdx.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// Re-export for convenience. `DataTb` itself is deliberately not re-exported
|
|
24
|
+
// here — a named export called `DataTb` in DataTb.astro's own frontmatter
|
|
25
|
+
// collides with Astro's implicit type for the file (same name as the file),
|
|
26
|
+
// producing a "Duplicate identifier 'DataTb'" build error. Nothing in this
|
|
27
|
+
// project imports DataTb from this file (use `@lad-sapienza/scms-core` or
|
|
28
|
+
// `@lad-sapienza/scms-core/components/DataTb` instead), so this only affects the unused path.
|
|
29
|
+
export { CsvSource, JsonSource, DirectusSource, ApiSource } from './index';
|
|
30
|
+
export type * from './types';
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<slot />
|