florixui 1.4.1 → 1.5.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
@@ -574,6 +574,38 @@ Displays a menu of actions or options triggered by a button, built on Radix UI w
574
574
  </DropdownMenu>
575
575
  ```
576
576
 
577
+ ### Empty
578
+
579
+ A composable empty state — media (icon/avatar), title, and description in a header, with optional actions. For "no data", "no results", offline, and 404 states.
580
+
581
+ ```tsx
582
+ <Empty>
583
+ <EmptyHeader>
584
+ <EmptyMedia variant="icon">
585
+ <FolderIcon />
586
+ </EmptyMedia>
587
+ <EmptyTitle>No projects yet</EmptyTitle>
588
+ <EmptyDescription>
589
+ Get started by creating your first project.
590
+ </EmptyDescription>
591
+ </EmptyHeader>
592
+ <EmptyContent>
593
+ <Button>
594
+ <PlusIcon />
595
+ Create project
596
+ </Button>
597
+ </EmptyContent>
598
+ </Empty>
599
+ ```
600
+
601
+ ### Empty State
602
+
603
+ A convenience wrapper over the Empty primitive — pass icon, title, description, and actions as props (with sensible defaults) instead of composing the parts by hand.
604
+
605
+ ```tsx
606
+ <EmptyState title="No notifications" />
607
+ ```
608
+
577
609
  ### Faceted Filter
578
610
 
579
611
  A controlled filter trigger and popover: a searchable list of options selectable as multi-select checkboxes (default) or single-select. Shows a selected-count badge on the trigger and emits the value(s) via onChange so you can filter your own list or API query.
@@ -775,6 +807,14 @@ An interactive map built on MapLibre GL (via mapcn), with markers, routes, clust
775
807
  />
776
808
  ```
777
809
 
810
+ ### Not Found
811
+
812
+ A centered status screen — a large code (e.g. "404"), a title, a description, and Go Back / Go to Home actions. Generic enough for 404 / 403 / 500 and empty states.
813
+
814
+ ```tsx
815
+ <NotFound homeHref="/" />
816
+ ```
817
+
778
818
  ### Popover
779
819
 
780
820
  Displays rich, floating content in a portal, anchored to a trigger and toggled by click.
@@ -1150,4 +1190,169 @@ Displays a brief, contextual label in a popup when the user hovers or focuses an
1150
1190
  </TooltipProvider>
1151
1191
  ```
1152
1192
 
1193
+ ## Bits
1194
+
1195
+ > Small, composable building blocks (see the "Bits" page in the docs). Each shows a quick usage snippet.
1196
+
1197
+ ### Card in card
1198
+
1199
+ An outer card with a header + action, containing nested cards — one per Card background variant.
1200
+
1201
+ ```tsx
1202
+ // One nested card per Card variant
1203
+ const SITES = [
1204
+ { variant: 'alt', name: 'Skyline Tower', /* … */ },
1205
+ { variant: 'primary', name: 'Marina Heights', /* … */ },
1206
+ { variant: 'success', name: 'Green Park Plaza', /* … */ },
1207
+ { variant: 'warning', name: 'Dockside Depot', /* … */ },
1208
+ { variant: 'danger', name: 'Old Mill Unit', /* … */ },
1209
+ ]
1210
+
1211
+ <Card>
1212
+ <CardHeader>
1213
+ <CardTitle className="flex items-center gap-2">
1214
+ <Building2Icon className="size-5" /> Site Assignment
1215
+ </CardTitle>
1216
+ <CardDescription>Nested cards, one per variant</CardDescription>
1217
+ <CardAction>
1218
+ <Button variant="outline" size="sm">
1219
+ <ArrowLeftRightIcon className="size-4" /> Reassign
1220
+ </Button>
1221
+ </CardAction>
1222
+ </CardHeader>
1223
+ <CardContent className="grid gap-3 sm:grid-cols-2">
1224
+ {SITES.map((s) => (
1225
+ <Card key={s.name} variant={s.variant} size="sm">
1226
+ <CardContent className="flex items-center gap-3">
1227
+ <StatusIcon className="bg-card text-foreground"><Building2Icon /></StatusIcon>
1228
+ <div className="flex-1">
1229
+ <p className="font-medium">{s.name}</p>
1230
+ <p className="text-xs text-muted-foreground">
1231
+ <LayersIcon className="size-3.5" /> {s.floor}
1232
+ </p>
1233
+ <p className="text-xs text-muted-foreground">
1234
+ <MapPinIcon className="size-3.5" /> {s.addr}
1235
+ </p>
1236
+ </div>
1237
+ <Badge>{s.status}</Badge>
1238
+ </CardContent>
1239
+ </Card>
1240
+ ))}
1241
+ </CardContent>
1242
+ </Card>
1243
+ ```
1244
+
1245
+ ### DataCell
1246
+
1247
+ A labelled value cell. "stacked" (default) puts the label above the value — lay them out in a grid for spec sheets; "row" puts the value on the right.
1248
+
1249
+ ```tsx
1250
+ // stacked (default) — an optional icon sits beside the value
1251
+ <div className="grid grid-cols-3 gap-x-8 gap-y-4">
1252
+ <DataCell label="Make" value="Liebherr" />
1253
+ <DataCell label="Category" value="lifting" icon={<WrenchIcon />} />
1254
+ <DataCell label="Asset Value" value="₹4,500,000" icon={<BanknoteIcon />} />
1255
+ {/* … */}
1256
+ </div>
1257
+
1258
+ // row — value (with icon) on the right
1259
+ <div className="divide-y">
1260
+ <DataCell layout="row" icon={<BanknoteIcon />} label="Asset Value" value="₹4,500,000" />
1261
+ <DataCell layout="row" icon={<ShieldCheckIcon />} label="Insurance Policy" value="INS-CR-8821" />
1262
+ </div>
1263
+ ```
1264
+
1265
+ ### DefRow
1266
+
1267
+ A label/value definition row for detail cards. Stack several in a divide-y container.
1268
+
1269
+ ```tsx
1270
+ <div className="divide-y">
1271
+ <DefRow label="Price" value="$960.99" />
1272
+ <DefRow label="Stock" value="5 units" />
1273
+ <DefRow label="Category" value="Electronics" />
1274
+ <DefRow label="SKU" value="SKU-RCH45Q1A" />
1275
+ </div>
1276
+ ```
1277
+
1278
+ ### QuickStat
1279
+
1280
+ A compact inline stat — icon, value, and an optional muted label. Line several up with vertical separators.
1281
+
1282
+ ```tsx
1283
+ <div className="flex items-center gap-3 [&>[data-slot=separator]]:h-4">
1284
+ <QuickStat icon={<TagIcon />} value="$960.99" />
1285
+ <Separator orientation="vertical" />
1286
+ <QuickStat icon={<PackageIcon />} value={5} label="in stock" />
1287
+ <Separator orientation="vertical" />
1288
+ <QuickStat icon={<StarIcon className="fill-orange text-orange" />} value={4.9} />
1289
+ <Separator orientation="vertical" />
1290
+ <QuickStat icon={<TrendingUpIcon />} value={982} label="sold" />
1291
+ </div>
1292
+ ```
1293
+
1294
+ ### StatusList
1295
+
1296
+ Status rows with flexible leading visuals (tinted icon box, avatar/initials, or plain icon), pill / outline / text status, and group headers.
1297
+
1298
+ ```tsx
1299
+ <StatusList>
1300
+ <StatusListGroup label="Gateways" count={2}>
1301
+ <StatusListItem
1302
+ media={<StatusIcon tone="success"><RadioIcon /></StatusIcon>}
1303
+ title="GW-SKY-B01"
1304
+ description="WiFi · 100% · 2 tags"
1305
+ status="Online"
1306
+ statusVariant="outline"
1307
+ tone="success"
1308
+ />
1309
+ <StatusListItem
1310
+ media={<StatusIcon tone="warning"><RadioIcon /></StatusIcon>}
1311
+ title="GW-SKY-B04"
1312
+ description="4G · 54% · 2 tags"
1313
+ status="Degraded"
1314
+ statusVariant="outline"
1315
+ tone="warning"
1316
+ />
1317
+ </StatusListGroup>
1318
+
1319
+ <StatusListGroup label="Workers" count={2}>
1320
+ <StatusListItem
1321
+ media={<StatusAvatar name="Arjun Das" tone="primary" />}
1322
+ title="Arjun Das"
1323
+ description="Electrician"
1324
+ status="Active"
1325
+ statusVariant="text"
1326
+ tone="success"
1327
+ />
1328
+ <StatusListItem
1329
+ media={<StatusAvatar name="Fatima Sheikh" tone="primary" />}
1330
+ title="Fatima Sheikh"
1331
+ description="Safety Officer"
1332
+ status="Active"
1333
+ statusVariant="text"
1334
+ tone="success"
1335
+ />
1336
+ </StatusListGroup>
1337
+ </StatusList>
1338
+ ```
1339
+
1340
+ ### Thumbnail (inline)
1341
+
1342
+ A square image with an icon fallback when no src is provided — for record headers and lists.
1343
+
1344
+ ```tsx
1345
+ function Thumb({ src, alt }: { src?: string; alt: string }) {
1346
+ return (
1347
+ <div className="flex size-14 shrink-0 items-center justify-center overflow-hidden rounded-lg border bg-muted">
1348
+ {src ? (
1349
+ <img src={src} alt={alt} className="size-full object-cover" />
1350
+ ) : (
1351
+ <ImageIcon className="size-6 text-muted-foreground" />
1352
+ )}
1353
+ </div>
1354
+ )
1355
+ }
1356
+ ```
1357
+
1153
1358
  <!-- COMPONENTS:END -->
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ export interface DataCellProps extends React.ComponentProps<"div"> {
3
+ /** Muted caption. */
4
+ label: React.ReactNode;
5
+ /** The value. */
6
+ value: React.ReactNode;
7
+ /**
8
+ * Optional icon (auto-sized, muted). In `stacked` it sits beside the value;
9
+ * in `row` it leads the label.
10
+ */
11
+ icon?: React.ReactNode;
12
+ /**
13
+ * - `stacked` (default): label above value — for spec/detail grids.
14
+ * - `row`: label on the left, value on the right — for definition lists.
15
+ */
16
+ layout?: "stacked" | "row";
17
+ }
18
+ /**
19
+ * A labelled value cell. `stacked` renders the muted `label` above the bold
20
+ * `value` (for spec/detail grids); `row` puts the label on the left and the
21
+ * value on the right (a definition row). Lay several `stacked` cells out in a
22
+ * grid, or several `row` cells in a `divide-y` column.
23
+ */
24
+ export declare function DataCell({ label, value, icon, layout, className, ...props }: DataCellProps): import("react/jsx-runtime").JSX.Element;
@@ -34,11 +34,16 @@ export interface DataTableProps<TRow> {
34
34
  pageSizeOptions?: number[];
35
35
  /** Alternating row backgrounds for easier scanning. */
36
36
  striped?: boolean;
37
- /** Keep the header visible while the body scrolls (pair with maxHeight). */
37
+ /** Keep the header visible while the body scrolls (pair with maxHeight/fillHeight). */
38
38
  stickyHeader?: boolean;
39
39
  /** Constrains height and enables vertical scroll, e.g. "24rem" or 400. */
40
40
  maxHeight?: string | number;
41
+ /**
42
+ * Grow the table to fill its parent's height (body scrolls, footer pinned).
43
+ * Place inside a flex column with a constrained height. Overrides `maxHeight`.
44
+ */
45
+ fillHeight?: boolean;
41
46
  onRowClick?: (row: TRow) => void;
42
47
  className?: string;
43
48
  }
44
- export declare function DataTable<TRow>({ columns, data, getRowId, selectable, selectedIds, onSelectionChange, rowActions, loading, emptyMessage, pagination, pageSize: pageSizeProp, pageSizeOptions, striped, stickyHeader, maxHeight, onRowClick, className, }: DataTableProps<TRow>): import("react/jsx-runtime").JSX.Element;
49
+ export declare function DataTable<TRow>({ columns, data, getRowId, selectable, selectedIds, onSelectionChange, rowActions, loading, emptyMessage, pagination, pageSize: pageSizeProp, pageSizeOptions, striped, stickyHeader, maxHeight, fillHeight, onRowClick, className, }: DataTableProps<TRow>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { Empty } from '../ui/empty';
2
+ import * as React from "react";
3
+ export interface EmptyStateProps extends Omit<React.ComponentProps<typeof Empty>, "title"> {
4
+ /** Leading icon (or any node). Defaults to an inbox icon. */
5
+ icon?: React.ReactNode;
6
+ /** Media style: `icon` wraps it in a muted square; `default` for avatars. */
7
+ mediaVariant?: "icon" | "default";
8
+ /** Heading. Defaults to "No data". */
9
+ title?: React.ReactNode;
10
+ /** Supporting text. */
11
+ description?: React.ReactNode;
12
+ /** Actions (buttons, links, inputs) rendered below. */
13
+ actions?: React.ReactNode;
14
+ }
15
+ /**
16
+ * A convenience wrapper over the compositional `Empty` primitive — pass
17
+ * `icon`, `title`, `description`, and `actions` as props (with sensible
18
+ * defaults) instead of composing the parts by hand. Drop the props you don't
19
+ * need; use the `Empty*` parts directly when you need full control.
20
+ */
21
+ export declare function EmptyState({ icon, mediaVariant, title, description, actions, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+ export interface NotFoundProps extends Omit<React.ComponentProps<"div">, "title"> {
3
+ /** Big status code or glyph, e.g. "404". Pass an icon node for empty states. */
4
+ code?: React.ReactNode;
5
+ /** Heading. Defaults to "Page Not Found". */
6
+ title?: React.ReactNode;
7
+ /** Supporting text under the title. */
8
+ description?: React.ReactNode;
9
+ /** Show the "Go Back" button (calls `onGoBack`, or history.back()). */
10
+ showBack?: boolean;
11
+ /** Override the back-button handler. Defaults to `history.back()`. */
12
+ onGoBack?: () => void;
13
+ /** Href for the "Go to Home" button. Set `null` to hide it. */
14
+ homeHref?: string | null;
15
+ /** Label for the home button. */
16
+ homeLabel?: React.ReactNode;
17
+ /** Extra actions rendered after the default buttons. */
18
+ actions?: React.ReactNode;
19
+ }
20
+ /**
21
+ * A centered status / not-found screen: a large `code` (e.g. "404"), a `title`,
22
+ * a `description`, and action buttons (Go Back + Go to Home). Generic enough for
23
+ * 404 / 403 / 500 and empty states — pass an icon as `code` for the latter.
24
+ */
25
+ export declare function NotFound({ code, title, description, showBack, onGoBack, homeHref, homeLabel, actions, className, ...props }: NotFoundProps): import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  import * as React from "react";
3
3
  declare const badgeVariants: (props?: ({
4
- variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | "red" | "orange" | "yellow" | "green" | "teal" | "cyan" | "blue" | "purple" | "pink" | "gray" | null | undefined;
4
+ variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive" | "blue" | "cyan" | "gray" | "green" | "orange" | "pink" | "purple" | "red" | "teal" | "yellow" | null | undefined;
5
5
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
6
6
  declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
7
7
  asChild?: boolean;
@@ -0,0 +1,12 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ import * as React from "react";
3
+ declare function Empty({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
4
+ declare function EmptyHeader({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
5
+ declare const emptyMediaVariants: (props?: ({
6
+ variant?: "default" | "icon" | null | undefined;
7
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
8
+ declare function EmptyMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>): import("react/jsx-runtime").JSX.Element;
9
+ declare function EmptyTitle({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
10
+ declare function EmptyDescription({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element;
11
+ declare function EmptyContent({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
12
+ export { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent, };
package/dist/index.d.ts CHANGED
@@ -9,9 +9,12 @@ export * from './components/custom/form-dialog';
9
9
  export * from './components/custom/card-radio-group';
10
10
  export * from './components/custom/confirm-prompt';
11
11
  export * from './components/custom/custom-tabs';
12
+ export * from './components/custom/data-cell';
12
13
  export * from './components/custom/def-row';
14
+ export * from './components/custom/empty-state';
13
15
  export * from './components/custom/faceted-filter';
14
16
  export * from './components/custom/list-card';
17
+ export * from './components/custom/not-found';
15
18
  export * from './components/custom/quick-stat';
16
19
  export * from './components/custom/sensor-card';
17
20
  export * from './components/custom/side-sheet';
@@ -31,6 +34,7 @@ export * from './components/ui/checkbox';
31
34
  export * from './components/ui/command';
32
35
  export * from './components/ui/dialog';
33
36
  export * from './components/ui/dropdown-menu';
37
+ export * from './components/ui/empty';
34
38
  export * from './components/ui/field';
35
39
  export * from './components/ui/hover-card';
36
40
  export * from './components/ui/input';