@maykonpaulo/maestro-admin 0.3.0 → 0.4.0-next.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/README.md CHANGED
@@ -409,7 +409,7 @@ data, textarea/JSON…).
409
409
 
410
410
  ## 11. A UI de admin (`maestro-admin`)
411
411
 
412
- A UI (React + Vite + Tailwind) lê `GET /metadata` e monta sozinha: navegação por entidade, tabela
412
+ A UI (React + Vite, CSS puro com temas) lê `GET /metadata` e monta sozinha: navegação por entidade, tabela
413
413
  (com busca/ordenação/paginação/filtros vindos do metadata), detalhe, e formulários de criar/editar.
414
414
  Ela respeita as **capacidades** (esconde New/Edit/Delete quando desabilitados) e o **RBAC** (403 vira
415
415
  erro na tela). **Uma tela, todas as entidades.**
@@ -430,7 +430,7 @@ VITE_MAESTRO_API_URL=http://localhost:3000 \
430
430
 
431
431
  ```tsx
432
432
  import { MaestroAdmin } from '@maykonpaulo/maestro-admin';
433
- import '@maykonpaulo/maestro-admin/src/styles.css';
433
+ import '@maykonpaulo/maestro-admin/styles.css';
434
434
 
435
435
  export function AdminPage() {
436
436
  return (
@@ -569,7 +569,7 @@ The **generic, metadata-driven admin UI** for Maestro, per [ADR 0008 — Camada
569
569
 
570
570
  Point it at a running [`@maykonpaulo/maestro-server`](../server) and it reads `GET /metadata` and **auto-builds the whole admin**: a navigation sidebar, a list table, a detail view and create/update forms **for every entity/collection** — no per-entity code. It respects each entity's `capabilities` (a read-only collection shows no New/Edit/Delete) and the server's RBAC (a 403 surfaces as an error, never a broken screen).
571
571
 
572
- Built with **React 19 + Vite + Tailwind**. It ships two ways:
572
+ Built with **React 19 + Vite**, styled with plain CSS custom properties (three built-in themes, light and dark). It ships two ways:
573
573
 
574
574
  - a **runnable static app** (`vite build`) you configure with an env var, and
575
575
  - **exported React components** (`import { MaestroAdmin } from '@maykonpaulo/maestro-admin'`) to embed in your own app.
@@ -591,7 +591,7 @@ VITE_MAESTRO_API_URL=http://localhost:3000 pnpm --filter @maykonpaulo/maestro-ad
591
591
 
592
592
  ```tsx
593
593
  import { MaestroAdmin } from '@maykonpaulo/maestro-admin';
594
- import '@maykonpaulo/maestro-admin/src/styles.css'; // or include the package in your Tailwind content
594
+ import '@maykonpaulo/maestro-admin/styles.css';
595
595
 
596
596
  export function AdminPage() {
597
597
  return (
@@ -606,24 +606,52 @@ export function AdminPage() {
606
606
 
607
607
  `headers` may be a function so a fresh auth token is read on every request. Pass a pre-built `client` (a `MaestroClient`) instead of `apiUrl`/`headers` for full control (custom `fetch`, SSR).
608
608
 
609
- ### Styling
609
+ The admin fills the box you give it — set a height on the container (`height: 100vh`, a grid cell, whatever). It never styles `html`/`body`.
610
610
 
611
- Tailwind v4. Either import the package's source stylesheet (`@maykonpaulo/maestro-admin/src/styles.css`) or, if you already run Tailwind, add the package to your content so its class names are scanned:
611
+ ### Styling and themes
612
612
 
613
- ```css
614
- /* your app.css */
615
- @import 'tailwindcss';
616
- @source '../node_modules/@maykonpaulo/maestro-admin/dist';
613
+ One plain-CSS import, no build step and no Tailwind: `@maykonpaulo/maestro-admin/styles.css` (`@maykonpaulo/maestro-admin/src/styles.css` still resolves to the same file). Every colour is a CSS custom property, so nothing depends on your bundler discovering class names.
614
+
615
+ Three themes ship with the package — `cobalto` (default), `latao` and `teal` — each in light and dark:
616
+
617
+ ```tsx
618
+ <MaestroAdmin apiUrl="…" theme="latao" />
617
619
  ```
618
620
 
621
+ The header carries a palette picker, a light/dark toggle (system → light → dark) and a density toggle, and remembers what the operator chose. Use the object form for more control:
622
+
623
+ ```tsx
624
+ <MaestroAdmin
625
+ apiUrl="…"
626
+ theme={{
627
+ preset: 'teal',
628
+ scheme: 'dark', // 'system' (default) | 'light' | 'dark'
629
+ density: 'compact', // 'comfortable' (default) | 'compact'
630
+ picker: false, // hide the header controls
631
+ remember: false, // don't persist the operator's choices
632
+ tokens: { '--maestro-brand': '#167B61', '--maestro-shell': '#0B2119' },
633
+ }}
634
+ />
635
+ ```
636
+
637
+ `tokens` is applied inline on the admin root, so it wins over the preset in both light and dark. The full token list is at the top of `src/styles.css`; the ones you will reach for most are `--maestro-brand`, `--maestro-shell`, `--maestro-bg`, `--maestro-surface`, `--maestro-border`, `--maestro-fg` and `--maestro-radius`.
638
+
639
+ ### The admin never scrolls sideways
640
+
641
+ Every screen scrolls vertically only. The hub uses fluid card tracks, the sidebar collapses to icons under 900px, and list tables have fixed column widths with truncation — so an entity with thirty fields does not become thirty columns. Which columns are on screen is the operator's call, from **Columns** in the list toolbar, remembered per entity; the default selection comes from `primaryListFields()` and **Reset columns** hands the decision back to it.
642
+
619
643
  ## Compose your own layout
620
644
 
621
645
  Beyond the all-in-one `<MaestroAdmin>`, the building blocks are exported so you can assemble a custom shell:
622
646
 
623
- - Components: `EntityList`, `EntityDetail`, `EntityForm`, `Sidebar`, `FieldValue`, `FieldInput`
624
- - Hooks: `useMetadata`, `useEntityList`, `useEntityRecord`, `useAsync`, and `listFields`/`detailFields`/`formFields`
647
+ - Shell: `Sidebar`, `Header`, `Hub`, `CommandPalette` (+ `entityCommands`), `MaestroThemeProvider`, `useTheme`
648
+ - Screens: `EntityList`, `EntityDetail`, `EntityForm`, `FieldValue`, `FieldInput`
649
+ - Primitives: `Button`, `IconButton`, `Badge`, `Spinner`, `EmptyState`, `ErrorBanner`, `Toast`, `Icon`, `entityIcon`
650
+ - Hooks: `useMetadata`, `useEntityList`, `useEntityRecord`, `useAsync`, `useColumnPrefs`, `useRecents`, and `listFields`/`detailFields`/`formFields`
625
651
  - Client: `MaestroClient`, `MaestroApiError`, `AdminClientProvider`, `useClient`
626
652
 
653
+ Composing your own shell means owning the token root too: wrap it in `<MaestroThemeProvider className="mst-root">`, which is what paints `data-maestro-theme`/`-scheme`/`-density`.
654
+
627
655
  All of them talk to the server through a single `MaestroClient` provided via `AdminClientProvider`.
628
656
 
629
657
  ## What it renders from metadata
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react from 'react';
2
+ import { ReactNode, ReactElement, ButtonHTMLAttributes } from 'react';
2
3
 
3
4
  type FieldType = 'string' | 'text' | 'integer' | 'float' | 'boolean' | 'date' | 'datetime' | 'enum' | 'json' | 'relation' | 'uuid' | 'email' | (string & {});
4
5
  interface EnumOption {
@@ -186,6 +187,34 @@ interface AdminStrings {
186
187
  recents: string;
187
188
  menus: string;
188
189
  noMenuResults: string;
190
+ hub: string;
191
+ breadcrumb: string;
192
+ search: string;
193
+ commandKey: string;
194
+ commandPalette: string;
195
+ palettePlaceholder: string;
196
+ goTo: string;
197
+ onThisScreen: string;
198
+ appearance: string;
199
+ palette: string;
200
+ density: string;
201
+ colorScheme: string;
202
+ schemeSystem: string;
203
+ schemeLight: string;
204
+ schemeDark: string;
205
+ entities: string;
206
+ hubMeta: (entities: number, sources: number) => string;
207
+ otherEntities: string;
208
+ noEntities: string;
209
+ noEntitiesHint: string;
210
+ fieldCount: (count: number) => string;
211
+ capRead: string;
212
+ capCreate: string;
213
+ capUpdate: string;
214
+ capDelete: string;
215
+ columns: string;
216
+ columnsCount: (visible: number, total: number) => string;
217
+ resetColumns: string;
189
218
  }
190
219
  declare function stringsFor(locale: AdminLocale): AdminStrings;
191
220
  declare const I18nProvider: react.Provider<AdminStrings>;
@@ -217,6 +246,64 @@ interface AdminLabels {
217
246
  /** Returns a copy of `metadata` with every label override applied. No-op when `labels` is empty. */
218
247
  declare function applyLabels(metadata: MaestroMetadata, labels: AdminLabels | undefined): MaestroMetadata;
219
248
 
249
+ /** Built-in palettes. Each ships a light and a dark set of the same tokens. */
250
+ type MaestroThemeName = 'cobalto' | 'latao' | 'teal';
251
+ /** `system` follows the OS `prefers-color-scheme`; the other two force the decision. */
252
+ type MaestroScheme = 'system' | 'light' | 'dark';
253
+ /** Table row height. `compact` fits roughly 40% more rows on a screen and changes nothing else. */
254
+ type MaestroDensity = 'comfortable' | 'compact';
255
+ interface MaestroThemeOption {
256
+ id: MaestroThemeName;
257
+ label: string;
258
+ /** Light-mode brand colour — what the picker shows as the palette's dot. */
259
+ swatch: string;
260
+ }
261
+ declare const MAESTRO_THEMES: readonly MaestroThemeOption[];
262
+ interface MaestroThemeConfig {
263
+ /** Palette to start on. Defaults to `cobalto`. */
264
+ preset?: MaestroThemeName;
265
+ /** Light/dark decision to start on. Defaults to `system`. */
266
+ scheme?: MaestroScheme;
267
+ /** Row density to start on. Defaults to `comfortable`. */
268
+ density?: MaestroDensity;
269
+ /**
270
+ * Token overrides applied inline on the admin root, so they win over the preset in both schemes:
271
+ * `{ '--maestro-brand': '#167B61' }`. Use this to dress the admin in your own brand.
272
+ */
273
+ tokens?: Record<string, string>;
274
+ /** Show the palette / light-dark / density controls in the header. Defaults to `true`. */
275
+ picker?: boolean;
276
+ /** Remember the operator's choices in `localStorage`. Defaults to `true`. */
277
+ remember?: boolean;
278
+ }
279
+ /** `theme="cobalto"` is shorthand for `theme={{ preset: 'cobalto' }}`. */
280
+ type MaestroThemeInput = MaestroThemeName | MaestroThemeConfig;
281
+ interface MaestroThemeState {
282
+ preset: MaestroThemeName;
283
+ scheme: MaestroScheme;
284
+ density: MaestroDensity;
285
+ picker: boolean;
286
+ setPreset: (preset: MaestroThemeName) => void;
287
+ setScheme: (scheme: MaestroScheme) => void;
288
+ setDensity: (density: MaestroDensity) => void;
289
+ }
290
+ /** The active appearance and its setters. Safe outside a provider — falls back to the defaults. */
291
+ declare function useTheme(): MaestroThemeState;
292
+ /**
293
+ * Owns the appearance state and paints the root element that carries the tokens. Everything below it
294
+ * reads colours from CSS custom properties, so a theme switch is one attribute change — no re-render
295
+ * of the tree's styles, no class swapping.
296
+ *
297
+ * The props are the *initial* values: once the operator picks a palette from the header it is
298
+ * remembered (unless `remember: false`), and the stored choice wins on the next mount.
299
+ */
300
+ declare function MaestroThemeProvider({ theme, className, children, rootRef, }: {
301
+ theme?: MaestroThemeInput;
302
+ className?: string;
303
+ children: ReactNode;
304
+ rootRef?: (node: HTMLDivElement | null) => void;
305
+ }): react.JSX.Element;
306
+
220
307
  interface MaestroAdminProps {
221
308
  /** Base URL of the running maestro-server. Ignored when `client` is given. */
222
309
  apiUrl?: string;
@@ -230,17 +317,29 @@ interface MaestroAdminProps {
230
317
  locale?: AdminLocale;
231
318
  /** Label rewrites (localization/humanization) applied over the served metadata. */
232
319
  labels?: AdminLabels;
320
+ /**
321
+ * Appearance: `"cobalto" | "latao" | "teal"`, or an object to also set the light/dark scheme, the
322
+ * row density, whether the header shows the pickers, and per-token overrides for your own brand.
323
+ */
324
+ theme?: MaestroThemeInput;
233
325
  }
234
326
  /**
235
327
  * The whole metadata-driven admin in one component. Point it at a running maestro-server and it reads
236
328
  * `GET /metadata` and auto-builds navigation, tables, detail views and create/update forms for every
237
329
  * entity — respecting each entity's capabilities and the server's RBAC. No per-entity code.
330
+ *
331
+ * Styles ship separately so the host app controls bundling:
332
+ * `import '@maykonpaulo/maestro-admin/styles.css'`.
238
333
  */
239
334
  declare function MaestroAdmin(props: MaestroAdminProps): react.JSX.Element;
240
335
 
241
336
  declare const AdminClientProvider: react.Provider<MaestroClient | null>;
242
337
  /** Returns the `MaestroClient` provided at the root of the admin. Throws if used outside the provider. */
243
338
  declare function useClient(): MaestroClient;
339
+ /** All entities from the loaded metadata — lets deep components (relation chips) resolve a target entity. */
340
+ declare function useEntities(): EntityMetadata[];
341
+ declare function useEntity(entityId: string | undefined): EntityMetadata | undefined;
342
+ declare function useAdminRoot(): HTMLElement | null;
244
343
 
245
344
  interface AsyncState<T> {
246
345
  data: T | undefined;
@@ -302,6 +401,27 @@ declare function useRecents(scope?: string): {
302
401
  push: (entityId: string) => void;
303
402
  };
304
403
 
404
+ interface ColumnPrefs {
405
+ /** The fields to render, in metadata order. */
406
+ columns: FieldMetadata[];
407
+ /** Every field that *could* be a column, for the picker. */
408
+ available: FieldMetadata[];
409
+ visible: (name: string) => boolean;
410
+ toggle: (name: string) => void;
411
+ reset: () => void;
412
+ /** True when the operator has overridden the metadata's default selection. */
413
+ customized: boolean;
414
+ }
415
+ /**
416
+ * Which columns an entity's table shows, remembered per entity.
417
+ *
418
+ * The admin never scrolls sideways, so an entity with thirty fields cannot simply render thirty
419
+ * columns — something has to choose. The default choice is `primaryListFields`, which reads the
420
+ * metadata; this hook lets the operator override it for the entities they actually work in, and
421
+ * `reset` hands the decision back to the metadata.
422
+ */
423
+ declare function useColumnPrefs(entity: EntityMetadata, max?: number): ColumnPrefs;
424
+
305
425
  declare function EntityList({ entity, onOpen, onCreate, onEdit, onClone, onNavigate, initialFilters, }: {
306
426
  entity: EntityMetadata;
307
427
  onOpen: (id: string) => void;
@@ -332,7 +452,7 @@ declare function EntityForm({ entity, mode, id, cloneFromId, onCancel, onSaved,
332
452
  onSaved: (record: Record_) => void;
333
453
  }): react.JSX.Element;
334
454
 
335
- declare function Sidebar({ entities, activeId, onSelect, title, labels, recents, }: {
455
+ declare function Sidebar({ entities, activeId, onSelect, title, labels, recents, onHome, homeActive, }: {
336
456
  entities: EntityMetadata[];
337
457
  activeId: string | undefined;
338
458
  onSelect: (entityId: string) => void;
@@ -341,11 +461,169 @@ declare function Sidebar({ entities, activeId, onSelect, title, labels, recents,
341
461
  labels?: AdminLabels;
342
462
  /** Recently-visited entity ids, most recent first. */
343
463
  recents?: string[];
464
+ /** Opens the hub. Omit to hide the hub entry (standalone/embedded use). */
465
+ onHome?: () => void;
466
+ homeActive?: boolean;
467
+ }): react.JSX.Element;
468
+
469
+ /**
470
+ * The admin's icon set, inline.
471
+ *
472
+ * Twenty-odd 24×24 stroke glyphs are not worth a runtime dependency: `@maykonpaulo/maestro-admin`
473
+ * ships with `dependencies: {}` and this file is why. Every glyph is drawn on the same grid with the
474
+ * same stroke weight, and takes its colour from `currentColor`.
475
+ */
476
+ declare const PATHS: {
477
+ readonly hub: react.JSX.Element;
478
+ readonly baton: react.JSX.Element;
479
+ readonly search: react.JSX.Element;
480
+ readonly chevronRight: react.JSX.Element;
481
+ readonly chevronLeft: react.JSX.Element;
482
+ readonly chevronsLeft: react.JSX.Element;
483
+ readonly chevronsRight: react.JSX.Element;
484
+ readonly plus: react.JSX.Element;
485
+ readonly close: react.JSX.Element;
486
+ readonly check: react.JSX.Element;
487
+ readonly filter: react.JSX.Element;
488
+ readonly download: react.JSX.Element;
489
+ readonly columns: react.JSX.Element;
490
+ readonly rows: react.JSX.Element;
491
+ readonly sun: react.JSX.Element;
492
+ readonly moon: react.JSX.Element;
493
+ readonly swatch: react.JSX.Element;
494
+ readonly dots: react.JSX.Element;
495
+ readonly trash: react.JSX.Element;
496
+ readonly pencil: react.JSX.Element;
497
+ readonly eye: react.JSX.Element;
498
+ readonly copy: react.JSX.Element;
499
+ readonly clone: react.JSX.Element;
500
+ readonly arrowUpRight: react.JSX.Element;
501
+ readonly arrowLeft: react.JSX.Element;
502
+ readonly sort: react.JSX.Element;
503
+ readonly sortAsc: react.JSX.Element;
504
+ readonly sortDesc: react.JSX.Element;
505
+ readonly database: react.JSX.Element;
506
+ readonly table: react.JSX.Element;
507
+ readonly users: react.JSX.Element;
508
+ readonly box: react.JSX.Element;
509
+ readonly receipt: react.JSX.Element;
510
+ readonly key: react.JSX.Element;
511
+ readonly shield: react.JSX.Element;
512
+ readonly activity: react.JSX.Element;
513
+ readonly tag: react.JSX.Element;
514
+ readonly map: react.JSX.Element;
515
+ readonly calendar: react.JSX.Element;
516
+ readonly mail: react.JSX.Element;
517
+ readonly file: react.JSX.Element;
518
+ readonly alert: react.JSX.Element;
519
+ };
520
+ type IconName = keyof typeof PATHS;
521
+ declare function Icon({ name, size, className, title, }: {
522
+ name: IconName;
523
+ size?: number;
524
+ className?: string;
525
+ title?: string;
526
+ }): ReactElement;
527
+ /**
528
+ * A glyph for an entity, guessed from its names. A metadata-driven admin has no idea what a
529
+ * collection *means*, so this is deliberately a hint and not a promise: anything unrecognised gets
530
+ * the neutral table glyph, which is always a defensible answer.
531
+ */
532
+ declare function entityIcon(entity: EntityMetadata): IconName;
533
+
534
+ interface Crumb {
535
+ label: string;
536
+ icon?: IconName;
537
+ /** Omit on the last crumb — the current place is not a link. */
538
+ onClick?: () => void;
539
+ }
540
+ /**
541
+ * The bar above the content: where you are (breadcrumbs), how to get anywhere (⌘K), and how the admin
542
+ * looks (palette, light/dark, density). The appearance controls live here rather than in a settings
543
+ * page because they are the operator's, changed mid-task and never worth a navigation.
544
+ */
545
+ declare function Header({ crumbs, onOpenPalette }: {
546
+ crumbs: Crumb[];
547
+ onOpenPalette: () => void;
548
+ }): react.JSX.Element;
549
+
550
+ /**
551
+ * The landing screen: every entity the server serves, in its sidebar folder, with what you can do to
552
+ * it and where it actually lives. That last part is the whole point — Maestro speaks a dozen
553
+ * providers, so "which database is this collection in" is a real question with a real answer, and no
554
+ * other admin can show it.
555
+ *
556
+ * Record counts are deliberately absent: metadata does not carry them, and one `count` request per
557
+ * entity would turn opening the admin into thirty round-trips. The count you get is the real one, in
558
+ * the list header, once you open an entity.
559
+ */
560
+ declare function Hub({ entities, labels, onOpen, }: {
561
+ entities: EntityMetadata[];
562
+ labels?: AdminLabels;
563
+ onOpen: (entityId: string) => void;
564
+ }): react.JSX.Element;
565
+
566
+ interface PaletteCommand {
567
+ id: string;
568
+ label: string;
569
+ icon?: IconName;
570
+ /** Right-aligned affordance: a shortcut, or the folder an entity belongs to. */
571
+ hint?: string;
572
+ /** Extra words matched by the search but never displayed (table name, singular label). */
573
+ keywords?: string;
574
+ run: () => void;
575
+ }
576
+ interface PaletteSection {
577
+ id: string;
578
+ label: string;
579
+ commands: PaletteCommand[];
580
+ }
581
+ /** Turns the entity list into palette commands — the navigation half of the palette. */
582
+ declare function entityCommands(entities: EntityMetadata[], groupOf: Map<string, string>, onSelect: (entityId: string) => void): PaletteCommand[];
583
+ /**
584
+ * ⌘K. Everything reachable in the admin — every entity, plus whatever the current screen can do —
585
+ * behind one accent-insensitive search, driven entirely from the keyboard.
586
+ */
587
+ declare function CommandPalette({ sections, onClose }: {
588
+ sections: PaletteSection[];
589
+ onClose: () => void;
590
+ }): react.ReactPortal;
591
+
592
+ type Variant = 'primary' | 'secondary' | 'danger' | 'ghost';
593
+ declare function Button({ variant, icon, className, children, ...props }: ButtonHTMLAttributes<HTMLButtonElement> & {
594
+ variant?: Variant;
595
+ icon?: IconName;
596
+ }): react.JSX.Element;
597
+ /** A square, label-less button. `label` is required — it is the accessible name and the tooltip. */
598
+ declare function IconButton({ icon, label, className, ...props }: ButtonHTMLAttributes<HTMLButtonElement> & {
599
+ icon: IconName;
600
+ label: string;
601
+ }): react.JSX.Element;
602
+ type BadgeTone = 'neutral' | 'brand' | 'ok' | 'warn' | 'danger';
603
+ declare function Badge({ children, tone, dot }: {
604
+ children: ReactNode;
605
+ tone?: BadgeTone;
606
+ dot?: boolean;
607
+ }): react.JSX.Element;
608
+ declare function Spinner({ label }: {
609
+ label?: string;
610
+ }): react.JSX.Element;
611
+ declare function EmptyState({ title, hint }: {
612
+ title: string;
613
+ hint?: string;
614
+ }): react.JSX.Element;
615
+ declare function ErrorBanner({ error }: {
616
+ error: Error;
617
+ }): react.JSX.Element;
618
+ /** The transient confirmation strip ("Copied!"). Callers own the timer; this only draws it. */
619
+ declare function Toast({ children }: {
620
+ children: ReactNode;
344
621
  }): react.JSX.Element;
345
622
 
346
623
  /**
347
624
  * Renders a single record value read-only, shaped by the field's type (for tables and detail views).
348
- * `compact` is the table-cell mode: long text truncates instead of stretching the row.
625
+ * `compact` is the table-cell mode: the cell itself truncates, so this only has to avoid rendering
626
+ * anything that would force the row taller.
349
627
  */
350
628
  declare function FieldValue({ field, value, compact }: {
351
629
  field: FieldMetadata;
@@ -386,4 +664,4 @@ declare function JsonInput({ field, value, onChange, disabled, }: {
386
664
  disabled?: boolean;
387
665
  }): react.JSX.Element;
388
666
 
389
- export { AdminClientProvider, type AdminLabels, type AdminLocale, type AdminStrings, type AsyncState, type EntityCapabilities, EntityDetail, EntityForm, type EntityLabelOverride, EntityList, type EntityMetadata, FieldInput, type FieldMetadata, FieldValue, type FilterInput, I18nProvider, JsonInput, type ListQuery, type ListResult, MaestroAdmin, type MaestroAdminProps, MaestroApiError, MaestroClient, type MaestroClientConfig, type MaestroMetadata, type MenuGroup, ObjectValue, Sidebar, type SidebarMenu, applyLabels, buildMenu, detailFields, formFields, listFields, primaryListFields, stringsFor, useAsync, useClient, useEntityList, useEntityRecord, useMetadata, useRecents, useT };
667
+ export { AdminClientProvider, type AdminLabels, type AdminLocale, type AdminStrings, type AsyncState, Badge, Button, type ColumnPrefs, CommandPalette, type Crumb, EmptyState, type EntityCapabilities, EntityDetail, EntityForm, type EntityLabelOverride, EntityList, type EntityMetadata, ErrorBanner, FieldInput, type FieldMetadata, FieldValue, type FilterInput, Header, Hub, I18nProvider, Icon, IconButton, type IconName, JsonInput, type ListQuery, type ListResult, MAESTRO_THEMES, MaestroAdmin, type MaestroAdminProps, MaestroApiError, MaestroClient, type MaestroClientConfig, type MaestroDensity, type MaestroMetadata, type MaestroScheme, type MaestroThemeConfig, type MaestroThemeInput, type MaestroThemeName, type MaestroThemeOption, MaestroThemeProvider, type MaestroThemeState, type MenuGroup, ObjectValue, type PaletteCommand, type PaletteSection, Sidebar, type SidebarMenu, Spinner, Toast, applyLabels, buildMenu, detailFields, entityCommands, entityIcon, formFields, listFields, primaryListFields, stringsFor, useAdminRoot, useAsync, useClient, useColumnPrefs, useEntities, useEntity, useEntityList, useEntityRecord, useMetadata, useRecents, useT, useTheme };