@alfakit/react 0.1.10 → 0.1.11

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 (50) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/components/actions/action-button.js +13 -1
  3. package/dist/components/actions/action-button.js.map +1 -1
  4. package/dist/components/dev-tools/dev-tools-inspector.js +2 -2
  5. package/dist/components/dev-tools/dev-tools-inspector.js.map +1 -1
  6. package/dist/components/fields/money-input.d.ts +5 -0
  7. package/dist/components/fields/money-input.d.ts.map +1 -1
  8. package/dist/components/fields/money-input.js +2 -5
  9. package/dist/components/fields/money-input.js.map +1 -1
  10. package/dist/components/panel/lazy-placeholder.d.ts +1 -0
  11. package/dist/components/panel/lazy-placeholder.d.ts.map +1 -1
  12. package/dist/components/panel/lazy-placeholder.js +38 -4
  13. package/dist/components/panel/lazy-placeholder.js.map +1 -1
  14. package/dist/components/table/cells.js +1 -1
  15. package/dist/components/table/cells.js.map +1 -1
  16. package/dist/components/ui/calendar.d.ts.map +1 -1
  17. package/dist/components/ui/calendar.js +7 -0
  18. package/dist/components/ui/calendar.js.map +1 -1
  19. package/dist/components/widgets/dashboard-customizer.js +2 -2
  20. package/dist/components/widgets/dashboard-customizer.js.map +1 -1
  21. package/dist/components/widgets/widgets-block.js +2 -2
  22. package/dist/components/widgets/widgets-block.js.map +1 -1
  23. package/dist/create-alfakit.d.ts.map +1 -1
  24. package/dist/create-alfakit.js +3 -2
  25. package/dist/create-alfakit.js.map +1 -1
  26. package/dist/eject-manifest.json +4 -2
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +2 -2
  29. package/dist/standalone/alfakit-component.js +2 -2
  30. package/dist/standalone/alfakit-component.js.map +1 -1
  31. package/dist/standalone.css +21 -0
  32. package/dist/starter-kit/index.d.ts +2 -2
  33. package/dist/starter-kit/index.js +2 -2
  34. package/dist/starter-kit/starter-kit.d.ts +9 -0
  35. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  36. package/dist/starter-kit/starter-kit.js +21 -2
  37. package/dist/starter-kit/starter-kit.js.map +1 -1
  38. package/package.json +2 -2
  39. package/src/components/actions/action-button.tsx +15 -1
  40. package/src/components/dev-tools/dev-tools-inspector.tsx +6 -1
  41. package/src/components/fields/money-input.tsx +3 -14
  42. package/src/components/panel/lazy-placeholder.tsx +41 -1
  43. package/src/components/table/cells.tsx +3 -1
  44. package/src/components/ui/calendar.tsx +8 -0
  45. package/src/components/widgets/dashboard-customizer.tsx +2 -2
  46. package/src/components/widgets/widgets-block.tsx +2 -2
  47. package/src/create-alfakit.tsx +9 -1
  48. package/src/standalone/alfakit-component.tsx +2 -2
  49. package/src/starter-kit/index.ts +1 -0
  50. package/src/starter-kit/starter-kit.tsx +22 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @alfakit/react
2
2
 
3
+ ## 0.1.11
4
+
5
+ ### Patch Changes
6
+
7
+ - File downloads from actions and `Action::download()` links; MoneyInput keeps out-of-range amounts for validation; translated calendar month buttons; image cells named for screen readers; `StarterKitFullscreenLayout`; customizable dashboards on the kit's `/dashboard`; failed lazy widgets show Retry; standalone headings keep their width.
8
+
3
9
  ## 0.1.10
4
10
 
5
11
  ### Patch Changes
@@ -90,7 +90,19 @@ function ActionButton({ action, context, size = "default", className, variant: v
90
90
  const sizeProp = isIconOnly ? iconButtonSize(buttonSize) : buttonSize;
91
91
  const classes = cn(buttonClasses(action, variant), labeledFrom && ICON_ONLY_BELOW[labeledFrom], className);
92
92
  const ariaLabel = isIconOnly || labeledFrom ? accessibleName : void 0;
93
- const button = isPlainLink ? action.openUrlInNewTab ? /* @__PURE__ */ jsx(Button, {
93
+ const button = isPlainLink ? action.download ? /* @__PURE__ */ jsx(Button, {
94
+ asChild: true,
95
+ variant: "plain",
96
+ size: sizeProp,
97
+ disabled: action.disabled,
98
+ "aria-label": ariaLabel,
99
+ ...extraProps(action.extraAttributes, classes),
100
+ children: /* @__PURE__ */ jsx("a", {
101
+ href: action.url,
102
+ download: "",
103
+ children: content
104
+ })
105
+ }) : action.openUrlInNewTab ? /* @__PURE__ */ jsx(Button, {
94
106
  asChild: true,
95
107
  variant: "plain",
96
108
  size: sizeProp,
@@ -1 +1 @@
1
- {"version":3,"file":"action-button.js","names":[],"sources":["../../../src/components/actions/action-button.tsx"],"sourcesContent":["import type { ActionContext, ActionSchema } from '@alfakit/core'\nimport {\n bindsKeyBindings,\n formatKeyBinding,\n iconButtonSize,\n isActionLoading,\n isActionProcessing,\n registerKeyBindings,\n resolveActionSize,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { useEffect, type MouseEvent } from 'react'\nimport { useActionRunner, useT } from '../../context'\nimport { useStoreSelector } from '../../hooks/use-store'\nimport { extraProps } from '../../lib/attributes'\nimport {\n badgeColorClasses,\n colorClass,\n ghostButtonColorClasses,\n outlineButtonColorClasses,\n solidButtonColorClasses,\n textColorClasses,\n} from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport { Spinner } from '../ui/spinner'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'\n\n/** `labeledFrom()`: the label shows from the breakpoint up. */\nconst LABEL_FROM: Record<string, string> = {\n sm: 'hidden sm:inline',\n md: 'hidden md:inline',\n lg: 'hidden lg:inline',\n xl: 'hidden xl:inline',\n '2xl': 'hidden 2xl:inline',\n}\n\n/** `labeledFrom()`: square (icon-only) padding below the breakpoint. */\nconst ICON_ONLY_BELOW: Record<string, string> = {\n sm: 'max-sm:aspect-square max-sm:px-0',\n md: 'max-md:aspect-square max-md:px-0',\n lg: 'max-lg:aspect-square max-lg:px-0',\n xl: 'max-xl:aspect-square max-xl:px-0',\n '2xl': 'max-2xl:aspect-square max-2xl:px-0',\n}\n\nexport interface ActionButtonProps {\n action: ActionSchema\n context: ActionContext\n size?: 'xs' | 'sm' | 'default' | 'lg'\n className?: string\n /** Force a variant (e.g. menu items render as plain rows). */\n variant?: ActionSchema['variant']\n /** Bind the action's key bindings globally while mounted. */\n withKeyBindings?: boolean\n /** Override how the action runs (e.g. a form submits its values). */\n onTrigger?: (action: ActionSchema, context: ActionContext) => void | Promise<void>\n}\n\n/** The badge trigger style (`badge()` without an argument). */\nconst BADGE_TRIGGER_CLASSES =\n \"h-auto min-h-6 gap-1 rounded-md border px-2 py-0.5 text-xs font-medium [&_svg:not([class*='size-'])]:size-3.5\"\n\nfunction buttonClasses(action: ActionSchema, variant: ActionSchema['variant']): string {\n const color = action.color ?? 'primary'\n\n switch (variant) {\n case 'outline':\n return cn('bg-background border', colorClass(outlineButtonColorClasses, color, 'gray'))\n case 'ghost':\n return colorClass(ghostButtonColorClasses, color, 'gray')\n case 'link':\n return cn(\n 'h-auto p-0 underline-offset-4 hover:underline has-[>svg]:px-0',\n colorClass(textColorClasses, color, 'primary'),\n )\n case 'icon-button':\n return colorClass(ghostButtonColorClasses, color, 'gray')\n case 'badge':\n // `badge()`: a tinted pill in the action's colour.\n return cn(BADGE_TRIGGER_CLASSES, colorClass(badgeColorClasses, color, 'primary'))\n default:\n return colorClass(solidButtonColorClasses, color, 'primary')\n }\n}\n\nexport function ActionButton({\n action,\n context,\n size = 'default',\n className,\n variant: variantProp,\n withKeyBindings = true,\n onTrigger,\n}: ActionButtonProps) {\n const runner = useActionRunner()\n const t = useT()\n // Only this run (this record's button), not the same action in every table row.\n const loading = useStoreSelector(runner.store, (state) => isActionLoading(state, action, context))\n const processing = useStoreSelector(runner.store, (state) =>\n isActionProcessing(state, action, context),\n )\n\n const variant =\n variantProp ??\n (action.outlined\n ? 'outline'\n : (action.variant ?? (action.hasAction || action.hasModal || action.url ? 'link' : 'button')))\n const isIconOnly = variant === 'icon-button' || !action.label\n // `labeledFrom()`: icon only on small screens, so the label must be the accessible name.\n const labeledFrom = !isIconOnly && action.icon && action.labeledFrom ? action.labeledFrom : null\n const busy = loading || processing\n // Record actions repeat per row: a global shortcut would run them for every record.\n const bindsKeys = withKeyBindings && bindsKeyBindings(action, context)\n\n useEffect(() => {\n if (!bindsKeys || !action.keyBindings) {\n return\n }\n\n return registerKeyBindings([\n {\n keys: action.keyBindings,\n handler: () =>\n void (onTrigger ? onTrigger(action, context) : runner.trigger(action, context)),\n },\n ])\n }, [action, context, runner, bindsKeys, onTrigger])\n\n // A disabled link renders as a disabled button so it cannot navigate.\n const isPlainLink = Boolean(\n action.url && !action.hasAction && !action.hasModal && !action.disabled,\n )\n\n const onClick = (event: MouseEvent) => {\n if (isPlainLink) {\n return // Plain link: let Inertia Link / anchor handle it.\n }\n\n event.preventDefault()\n void (onTrigger ? onTrigger(action, context) : runner.trigger(action, context))\n }\n\n const content = (\n <>\n {busy ? (\n <Spinner />\n ) : action.icon && action.iconPosition !== 'after' ? (\n <Icon name={action.icon} />\n ) : null}\n {!isIconOnly && (\n <span className={labeledFrom ? LABEL_FROM[labeledFrom] : undefined}>{action.label}</span>\n )}\n {action.icon && action.iconPosition === 'after' && !busy && <Icon name={action.icon} />}\n {action.badge !== undefined && action.badge !== null && (\n <Badge\n variant=\"outline\"\n className={cn(\n 'ms-1 px-1.5 py-0',\n colorClass(badgeColorClasses, action.badgeColor, 'gray'),\n )}\n >\n {action.badge}\n </Badge>\n )}\n </>\n )\n\n const accessibleName = action.label ?? action.tooltip ?? action.name\n const newTabHint = t('opens_in_new_tab', {}, '(opens in a new tab)')\n const buttonSize = variant === 'badge' ? 'xs' : resolveActionSize(action.size, size)\n const sizeProp = isIconOnly ? iconButtonSize(buttonSize) : buttonSize\n const classes = cn(\n buttonClasses(action, variant),\n labeledFrom && ICON_ONLY_BELOW[labeledFrom],\n className,\n )\n const ariaLabel = isIconOnly || labeledFrom ? accessibleName : undefined\n\n const button = isPlainLink ? (\n action.openUrlInNewTab ? (\n <Button\n asChild\n variant=\"plain\"\n size={sizeProp}\n\n disabled={action.disabled}\n aria-label={ariaLabel ? `${ariaLabel} ${newTabHint}` : undefined}\n {...extraProps(action.extraAttributes, classes)}\n >\n <a href={action.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {content}\n {!isIconOnly && <span className=\"sr-only\"> {newTabHint}</span>}\n </a>\n </Button>\n ) : (\n <Button\n asChild\n variant=\"plain\"\n size={sizeProp}\n\n disabled={action.disabled}\n aria-label={ariaLabel}\n {...extraProps(action.extraAttributes, classes)}\n >\n <Link href={action.url ?? '#'}>{content}</Link>\n </Button>\n )\n ) : (\n <Button\n type=\"button\"\n variant=\"plain\"\n size={sizeProp}\n\n disabled={action.disabled || busy}\n onClick={onClick}\n aria-label={ariaLabel}\n {...extraProps(action.extraAttributes, classes)}\n >\n {content}\n </Button>\n )\n\n const tooltip = action.tooltip ?? (isIconOnly ? action.label : undefined)\n const shortcut = bindsKeys ? action.keyBindings?.[0] : undefined\n\n if (!tooltip && !shortcut) {\n return button\n }\n\n // A disabled button gets no pointer or focus events, so a focusable wrapper carries the\n // tooltip (e.g. the reason from `authorizationTooltip()`).\n const trigger =\n action.disabled && tooltip ? (\n <span tabIndex={0} className=\"inline-flex\" data-slot=\"action-disabled-tooltip\">\n {button}\n </span>\n ) : (\n button\n )\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{trigger}</TooltipTrigger>\n <TooltipContent>\n {tooltip}\n {shortcut && (\n <kbd dir=\"ltr\" className=\"ms-2 rounded border border-white/20 px-1 font-mono text-[10px]\">\n {formatKeyBinding(shortcut)}\n </kbd>\n )}\n </TooltipContent>\n </Tooltip>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"action-button.js","names":[],"sources":["../../../src/components/actions/action-button.tsx"],"sourcesContent":["import type { ActionContext, ActionSchema } from '@alfakit/core'\nimport {\n bindsKeyBindings,\n formatKeyBinding,\n iconButtonSize,\n isActionLoading,\n isActionProcessing,\n registerKeyBindings,\n resolveActionSize,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { useEffect, type MouseEvent } from 'react'\nimport { useActionRunner, useT } from '../../context'\nimport { useStoreSelector } from '../../hooks/use-store'\nimport { extraProps } from '../../lib/attributes'\nimport {\n badgeColorClasses,\n colorClass,\n ghostButtonColorClasses,\n outlineButtonColorClasses,\n solidButtonColorClasses,\n textColorClasses,\n} from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { Badge } from '../ui/badge'\nimport { Button } from '../ui/button'\nimport { Spinner } from '../ui/spinner'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'\n\n/** `labeledFrom()`: the label shows from the breakpoint up. */\nconst LABEL_FROM: Record<string, string> = {\n sm: 'hidden sm:inline',\n md: 'hidden md:inline',\n lg: 'hidden lg:inline',\n xl: 'hidden xl:inline',\n '2xl': 'hidden 2xl:inline',\n}\n\n/** `labeledFrom()`: square (icon-only) padding below the breakpoint. */\nconst ICON_ONLY_BELOW: Record<string, string> = {\n sm: 'max-sm:aspect-square max-sm:px-0',\n md: 'max-md:aspect-square max-md:px-0',\n lg: 'max-lg:aspect-square max-lg:px-0',\n xl: 'max-xl:aspect-square max-xl:px-0',\n '2xl': 'max-2xl:aspect-square max-2xl:px-0',\n}\n\nexport interface ActionButtonProps {\n action: ActionSchema\n context: ActionContext\n size?: 'xs' | 'sm' | 'default' | 'lg'\n className?: string\n /** Force a variant (e.g. menu items render as plain rows). */\n variant?: ActionSchema['variant']\n /** Bind the action's key bindings globally while mounted. */\n withKeyBindings?: boolean\n /** Override how the action runs (e.g. a form submits its values). */\n onTrigger?: (action: ActionSchema, context: ActionContext) => void | Promise<void>\n}\n\n/** The badge trigger style (`badge()` without an argument). */\nconst BADGE_TRIGGER_CLASSES =\n \"h-auto min-h-6 gap-1 rounded-md border px-2 py-0.5 text-xs font-medium [&_svg:not([class*='size-'])]:size-3.5\"\n\nfunction buttonClasses(action: ActionSchema, variant: ActionSchema['variant']): string {\n const color = action.color ?? 'primary'\n\n switch (variant) {\n case 'outline':\n return cn('bg-background border', colorClass(outlineButtonColorClasses, color, 'gray'))\n case 'ghost':\n return colorClass(ghostButtonColorClasses, color, 'gray')\n case 'link':\n return cn(\n 'h-auto p-0 underline-offset-4 hover:underline has-[>svg]:px-0',\n colorClass(textColorClasses, color, 'primary'),\n )\n case 'icon-button':\n return colorClass(ghostButtonColorClasses, color, 'gray')\n case 'badge':\n // `badge()`: a tinted pill in the action's colour.\n return cn(BADGE_TRIGGER_CLASSES, colorClass(badgeColorClasses, color, 'primary'))\n default:\n return colorClass(solidButtonColorClasses, color, 'primary')\n }\n}\n\nexport function ActionButton({\n action,\n context,\n size = 'default',\n className,\n variant: variantProp,\n withKeyBindings = true,\n onTrigger,\n}: ActionButtonProps) {\n const runner = useActionRunner()\n const t = useT()\n // Only this run (this record's button), not the same action in every table row.\n const loading = useStoreSelector(runner.store, (state) => isActionLoading(state, action, context))\n const processing = useStoreSelector(runner.store, (state) =>\n isActionProcessing(state, action, context),\n )\n\n const variant =\n variantProp ??\n (action.outlined\n ? 'outline'\n : (action.variant ?? (action.hasAction || action.hasModal || action.url ? 'link' : 'button')))\n const isIconOnly = variant === 'icon-button' || !action.label\n // `labeledFrom()`: icon only on small screens, so the label must be the accessible name.\n const labeledFrom = !isIconOnly && action.icon && action.labeledFrom ? action.labeledFrom : null\n const busy = loading || processing\n // Record actions repeat per row: a global shortcut would run them for every record.\n const bindsKeys = withKeyBindings && bindsKeyBindings(action, context)\n\n useEffect(() => {\n if (!bindsKeys || !action.keyBindings) {\n return\n }\n\n return registerKeyBindings([\n {\n keys: action.keyBindings,\n handler: () =>\n void (onTrigger ? onTrigger(action, context) : runner.trigger(action, context)),\n },\n ])\n }, [action, context, runner, bindsKeys, onTrigger])\n\n // A disabled link renders as a disabled button so it cannot navigate.\n const isPlainLink = Boolean(\n action.url && !action.hasAction && !action.hasModal && !action.disabled,\n )\n\n const onClick = (event: MouseEvent) => {\n if (isPlainLink) {\n return // Plain link: let Inertia Link / anchor handle it.\n }\n\n event.preventDefault()\n void (onTrigger ? onTrigger(action, context) : runner.trigger(action, context))\n }\n\n const content = (\n <>\n {busy ? (\n <Spinner />\n ) : action.icon && action.iconPosition !== 'after' ? (\n <Icon name={action.icon} />\n ) : null}\n {!isIconOnly && (\n <span className={labeledFrom ? LABEL_FROM[labeledFrom] : undefined}>{action.label}</span>\n )}\n {action.icon && action.iconPosition === 'after' && !busy && <Icon name={action.icon} />}\n {action.badge !== undefined && action.badge !== null && (\n <Badge\n variant=\"outline\"\n className={cn(\n 'ms-1 px-1.5 py-0',\n colorClass(badgeColorClasses, action.badgeColor, 'gray'),\n )}\n >\n {action.badge}\n </Badge>\n )}\n </>\n )\n\n const accessibleName = action.label ?? action.tooltip ?? action.name\n const newTabHint = t('opens_in_new_tab', {}, '(opens in a new tab)')\n const buttonSize = variant === 'badge' ? 'xs' : resolveActionSize(action.size, size)\n const sizeProp = isIconOnly ? iconButtonSize(buttonSize) : buttonSize\n const classes = cn(\n buttonClasses(action, variant),\n labeledFrom && ICON_ONLY_BELOW[labeledFrom],\n className,\n )\n const ariaLabel = isIconOnly || labeledFrom ? accessibleName : undefined\n\n const button = isPlainLink ? (\n action.download ? (\n // `download()`: a plain link that saves the file (an Inertia visit would discard it).\n <Button\n asChild\n variant=\"plain\"\n size={sizeProp}\n disabled={action.disabled}\n aria-label={ariaLabel}\n {...extraProps(action.extraAttributes, classes)}\n >\n <a href={action.url} download=\"\">\n {content}\n </a>\n </Button>\n ) : action.openUrlInNewTab ? (\n <Button\n asChild\n variant=\"plain\"\n size={sizeProp}\n\n disabled={action.disabled}\n aria-label={ariaLabel ? `${ariaLabel} ${newTabHint}` : undefined}\n {...extraProps(action.extraAttributes, classes)}\n >\n <a href={action.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {content}\n {!isIconOnly && <span className=\"sr-only\"> {newTabHint}</span>}\n </a>\n </Button>\n ) : (\n <Button\n asChild\n variant=\"plain\"\n size={sizeProp}\n\n disabled={action.disabled}\n aria-label={ariaLabel}\n {...extraProps(action.extraAttributes, classes)}\n >\n <Link href={action.url ?? '#'}>{content}</Link>\n </Button>\n )\n ) : (\n <Button\n type=\"button\"\n variant=\"plain\"\n size={sizeProp}\n\n disabled={action.disabled || busy}\n onClick={onClick}\n aria-label={ariaLabel}\n {...extraProps(action.extraAttributes, classes)}\n >\n {content}\n </Button>\n )\n\n const tooltip = action.tooltip ?? (isIconOnly ? action.label : undefined)\n const shortcut = bindsKeys ? action.keyBindings?.[0] : undefined\n\n if (!tooltip && !shortcut) {\n return button\n }\n\n // A disabled button gets no pointer or focus events, so a focusable wrapper carries the\n // tooltip (e.g. the reason from `authorizationTooltip()`).\n const trigger =\n action.disabled && tooltip ? (\n <span tabIndex={0} className=\"inline-flex\" data-slot=\"action-disabled-tooltip\">\n {button}\n </span>\n ) : (\n button\n )\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{trigger}</TooltipTrigger>\n <TooltipContent>\n {tooltip}\n {shortcut && (\n <kbd dir=\"ltr\" className=\"ms-2 rounded border border-white/20 px-1 font-mono text-[10px]\">\n {formatKeyBinding(shortcut)}\n </kbd>\n )}\n </TooltipContent>\n </Tooltip>\n )\n}\n"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { Button } from "../ui/button.js";
4
4
  import { Input } from "../ui/input.js";
5
5
  import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from "../ui/sheet.js";
6
6
  import { ScrollArea } from "../ui/scroll-area.js";
7
- import { byteLength, formatBytes, inspectableProps, jsonEntries, jsonScalar, jsonSize, latestServerTiming, prettyJson, searchJson } from "@alfakit/core";
7
+ import { byteLength, formatBytes, inspectableProps, jsonEntries, jsonScalar, jsonSize, latestServerTiming, overlayPlacementDirection, prettyJson, searchJson } from "@alfakit/core";
8
8
  import { router } from "@inertiajs/react";
9
9
  import { useEffect, useMemo, useState } from "react";
10
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -52,7 +52,7 @@ function DevToolsInspector() {
52
52
  children: /* @__PURE__ */ jsx(BracesIcon, {})
53
53
  })
54
54
  }), /* @__PURE__ */ jsx(SheetContent, {
55
- side: direction === "rtl" ? "left" : "right",
55
+ side: overlayPlacementDirection(direction, props.alfakit?.starterKit) === "rtl" ? "left" : "right",
56
56
  className: "flex w-full flex-col gap-0 p-0 sm:max-w-xl",
57
57
  children: /* @__PURE__ */ jsxs("div", {
58
58
  "data-slot": "dev-tools",
@@ -1 +1 @@
1
- {"version":3,"file":"dev-tools-inspector.js","names":[],"sources":["../../../src/components/dev-tools/dev-tools-inspector.tsx"],"sourcesContent":["import {\n byteLength,\n formatBytes,\n inspectableProps,\n jsonEntries,\n jsonScalar,\n jsonSize,\n latestServerTiming,\n prettyJson,\n searchJson,\n type JsonEntry,\n type JsonSearchResult,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { BracesIcon, CheckIcon, ChevronRightIcon, CopyIcon, ExternalLinkIcon } from 'lucide-react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useAlfakitProps, useDirection, useFormatter, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { Button } from '../ui/button'\nimport { Input } from '../ui/input'\nimport { ScrollArea } from '../ui/scroll-area'\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\n\n/**\n * The schema inspector: a floating developer button that opens a drawer with the page's\n * props as a searchable JSON tree (with a copy button), what the context token identifies,\n * the server time reported in `Server-Timing`, the payload size and editor links for the\n * PHP classes behind the page. Rendered only for pages that carry `alfakitDevTools`.\n */\nexport function DevToolsInspector() {\n const props = useAlfakitProps()\n const t = useT()\n const formatter = useFormatter()\n const direction = useDirection()\n const tools = props.alfakitDevTools\n const data = useMemo(() => inspectableProps(props as unknown as Record<string, unknown>), [props])\n const payload = useMemo(() => byteLength(props), [props])\n const [query, setQuery] = useState('')\n const [copied, setCopied] = useState(false)\n // The inspector renders in the browser only (lazy chunk), so the Performance API is there.\n const [serverTime, setServerTime] = useState<number | null>(() => latestServerTiming())\n const search = useMemo(() => searchJson(data, query), [data, query])\n\n // Re-read the timing after every visit: the latest response carries the newest header.\n useEffect(() => router.on('finish', () => setServerTime(latestServerTiming())), [])\n\n useEffect(() => {\n if (!copied) return\n\n const timer = setTimeout(() => setCopied(false), 2000)\n\n return () => clearTimeout(timer)\n }, [copied])\n\n if (!tools) {\n return null\n }\n\n const copy = () => {\n void navigator.clipboard?.writeText(prettyJson(data)).then(() => setCopied(true))\n }\n\n const time = (value: number | null) =>\n value === null ? t('dev_tools.never', {}, 'Never') : formatter.dateTime(value * 1000)\n const parameters = Object.entries(tools.context.parameters)\n\n return (\n <Sheet>\n <SheetTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n aria-label={t('dev_tools.open', {}, 'Open schema inspector')}\n data-slot=\"dev-tools-toggle\"\n className=\"fixed end-4 bottom-16 z-40 rounded-full shadow-md [[data-slot=starter-kit-root]_&]:end-auto [[data-slot=starter-kit-root]_&]:right-4\"\n >\n <BracesIcon />\n </Button>\n </SheetTrigger>\n <SheetContent\n side={direction === 'rtl' ? 'left' : 'right'}\n className=\"flex w-full flex-col gap-0 p-0 sm:max-w-xl\"\n >\n <div data-slot=\"dev-tools\" className=\"flex min-h-0 flex-1 flex-col\">\n <SheetHeader className=\"border-b\">\n <SheetTitle className=\"flex items-center gap-2\">\n <BracesIcon className=\"size-4\" />\n {t('dev_tools.title', {}, 'Schema inspector')}\n </SheetTitle>\n <SheetDescription className=\"truncate font-mono text-xs\" title={tools.context.page}>\n {tools.context.page}\n </SheetDescription>\n </SheetHeader>\n <ScrollArea className=\"min-h-0 flex-1\">\n <div className=\"space-y-5 p-4 text-sm\">\n <dl className=\"grid grid-cols-2 gap-3\">\n <Stat\n label={t('dev_tools.server_time', {}, 'Server time')}\n value={\n serverTime === null\n ? t('dev_tools.not_measured', {}, 'Not measured')\n : t(\n 'dev_tools.milliseconds',\n { value: formatter.number(serverTime) },\n ':value ms',\n )\n }\n />\n <Stat\n label={t('dev_tools.payload', {}, 'Payload size')}\n value={formatBytes(payload)}\n />\n </dl>\n\n <section data-slot=\"dev-tools-context\">\n <h3 className=\"mb-2 text-sm font-medium\">\n {t('dev_tools.context', {}, 'Context token')}\n </h3>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs\">\n <Row label={t('dev_tools.panel', {}, 'Panel')} value={tools.context.panel} />\n <Row label={t('dev_tools.page', {}, 'Page')} value={tools.context.page} />\n {tools.context.component && (\n <Row\n label={t('dev_tools.component', {}, 'Component')}\n value={tools.context.component}\n />\n )}\n {tools.tenant !== null && (\n <Row label={t('dev_tools.tenant', {}, 'Tenant')} value={tools.tenant} />\n )}\n {parameters.map(([key, value]) => (\n <Row key={key} label={key} value={jsonScalar(value)} />\n ))}\n <Row\n label={t('dev_tools.bound_to_user', {}, 'Bound to the user')}\n value={\n tools.context.boundToUser\n ? t('dev_tools.yes', {}, 'Yes')\n : t('dev_tools.no', {}, 'No')\n }\n plain\n />\n <Row\n label={t('dev_tools.issued_at', {}, 'Issued')}\n value={time(tools.context.issuedAt)}\n plain\n />\n <Row\n label={t('dev_tools.expires_at', {}, 'Expires')}\n value={time(tools.context.expiresAt)}\n plain\n />\n </dl>\n </section>\n\n <section data-slot=\"dev-tools-classes\">\n <h3 className=\"mb-2 text-sm font-medium\">\n {t('dev_tools.classes', {}, 'Classes')}\n </h3>\n <ul className=\"divide-y rounded-md border text-xs\">\n {tools.classes.map((item) => (\n <li key={item.role} className=\"flex items-center gap-2 px-3 py-1.5\">\n <span className=\"text-muted-foreground w-16 shrink-0\">\n {t(`dev_tools.roles.${item.role}`, {}, item.role)}\n </span>\n <span\n className=\"min-w-0 flex-1 truncate font-mono\"\n title={item.file ? `${item.file}:${item.line ?? 1}` : item.class}\n >\n {item.class}\n </span>\n {item.url && (\n <a\n href={item.url}\n className=\"text-primary inline-flex shrink-0 items-center gap-1 hover:underline\"\n aria-label={t(\n 'dev_tools.open_in_editor',\n { class: item.class, editor: tools.editor ?? '' },\n 'Open :class in :editor',\n )}\n >\n <ExternalLinkIcon className=\"size-3.5\" />\n </a>\n )}\n </li>\n ))}\n </ul>\n {tools.editor === null && (\n <p className=\"text-muted-foreground mt-2 text-xs\">\n {t(\n 'dev_tools.no_editor',\n {},\n 'Set APP_EDITOR (config app.editor) to open these classes in your editor.',\n )}\n </p>\n )}\n </section>\n\n <section data-slot=\"dev-tools-schema\">\n <div className=\"mb-2 flex items-center gap-2\">\n <h3 className=\"me-auto text-sm font-medium\">\n {t('dev_tools.schema', {}, 'Schema')}\n </h3>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={copy}>\n {copied ? <CheckIcon /> : <CopyIcon />}\n {copied\n ? t('dev_tools.copied', {}, 'Copied')\n : t('dev_tools.copy', {}, 'Copy JSON')}\n </Button>\n </div>\n <Input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={t('dev_tools.search', {}, 'Search keys and values')}\n aria-label={t('dev_tools.search', {}, 'Search keys and values')}\n className=\"mb-2 h-8\"\n />\n {query.trim() !== '' && search.matches.size === 0 ? (\n <p className=\"text-muted-foreground text-sm\">\n {t(\n 'dev_tools.no_matches',\n { query: query.trim() },\n 'Nothing matches “:query”.',\n )}\n </p>\n ) : (\n <ul\n dir=\"ltr\"\n role=\"tree\"\n aria-label={t('dev_tools.schema', {}, 'Schema')}\n className=\"bg-muted/40 overflow-x-auto rounded-md p-2 text-start font-mono text-xs leading-relaxed\"\n >\n {jsonEntries(data).map((entry) => (\n <JsonNode\n key={entry.path}\n entry={entry}\n depth={0}\n search={search}\n query={query}\n />\n ))}\n </ul>\n )}\n </section>\n </div>\n </ScrollArea>\n </div>\n </SheetContent>\n </Sheet>\n )\n}\n\nfunction JsonNode({\n entry,\n depth,\n search,\n query,\n}: {\n entry: JsonEntry\n depth: number\n search: JsonSearchResult\n query: string\n}) {\n const t = useT()\n const formatter = useFormatter()\n const searching = query.trim() !== ''\n const [open, setOpen] = useState(depth < 1)\n\n if (searching && !search.visible.has(entry.path)) {\n return null\n }\n\n const container = entry.kind === 'object' || entry.kind === 'array'\n const expanded = searching || open\n const matched = search.matches.has(entry.path)\n const size = jsonSize(entry.value)\n const key = (\n <span className={cn('text-foreground', matched && 'bg-primary/15 rounded-sm')}>\n {entry.key}\n </span>\n )\n\n if (!container) {\n return (\n <li\n role=\"treeitem\"\n aria-selected={false}\n className=\"py-px\"\n style={{ paddingInlineStart: `${depth * 12 + 16}px` }}\n >\n {key}\n <span className=\"text-muted-foreground\">: </span>\n <span\n className={cn(\n entry.kind === 'string' && 'text-emerald-700 dark:text-emerald-400',\n entry.kind === 'number' && 'text-sky-700 dark:text-sky-400',\n entry.kind === 'boolean' && 'text-violet-700 dark:text-violet-400',\n entry.kind === 'null' && 'text-muted-foreground',\n 'break-all',\n )}\n >\n {jsonScalar(entry.value)}\n </span>\n </li>\n )\n }\n\n return (\n <li role=\"treeitem\" aria-selected={false} aria-expanded={expanded}>\n <button\n type=\"button\"\n className=\"hover:bg-muted flex w-full items-center gap-1 rounded py-px text-start\"\n style={{ paddingInlineStart: `${depth * 12}px` }}\n onClick={() => setOpen(!open)}\n aria-label={\n expanded\n ? t('dev_tools.collapse', { key: entry.key }, 'Collapse :key')\n : t('dev_tools.expand', { key: entry.key }, 'Expand :key')\n }\n >\n {/* The tree is always left to right (it is code), so the chevron does not flip. */}\n <ChevronRightIcon\n className={cn('size-3 shrink-0 transition-transform', expanded && 'rotate-90')}\n />\n {key}\n <span className=\"text-muted-foreground\">\n {entry.kind === 'array' ? `[${formatter.number(size)}]` : `{${formatter.number(size)}}`}\n </span>\n </button>\n {expanded && size > 0 && (\n <ul role=\"group\">\n {jsonEntries(entry.value, entry.path).map((child) => (\n <JsonNode\n key={child.path}\n entry={child}\n depth={depth + 1}\n search={search}\n query={query}\n />\n ))}\n </ul>\n )}\n </li>\n )\n}\n\nfunction Stat({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded-md border p-3\">\n <dt className=\"text-muted-foreground text-xs\">{label}</dt>\n <dd className=\"font-mono text-sm font-semibold tabular-nums\">{value}</dd>\n </div>\n )\n}\n\nfunction Row({ label, value, plain = false }: { label: string; value: string; plain?: boolean }) {\n return (\n <>\n <dt className=\"text-muted-foreground\">{label}</dt>\n <dd className={cn('min-w-0 truncate', !plain && 'font-mono')} title={value}>\n {value}\n </dd>\n </>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"dev-tools-inspector.js","names":[],"sources":["../../../src/components/dev-tools/dev-tools-inspector.tsx"],"sourcesContent":["import {\n byteLength,\n formatBytes,\n inspectableProps,\n jsonEntries,\n jsonScalar,\n jsonSize,\n latestServerTiming,\n overlayPlacementDirection,\n prettyJson,\n searchJson,\n type JsonEntry,\n type JsonSearchResult,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { BracesIcon, CheckIcon, ChevronRightIcon, CopyIcon, ExternalLinkIcon } from 'lucide-react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useAlfakitProps, useDirection, useFormatter, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { Button } from '../ui/button'\nimport { Input } from '../ui/input'\nimport { ScrollArea } from '../ui/scroll-area'\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\n\n/**\n * The schema inspector: a floating developer button that opens a drawer with the page's\n * props as a searchable JSON tree (with a copy button), what the context token identifies,\n * the server time reported in `Server-Timing`, the payload size and editor links for the\n * PHP classes behind the page. Rendered only for pages that carry `alfakitDevTools`.\n */\nexport function DevToolsInspector() {\n const props = useAlfakitProps()\n const t = useT()\n const formatter = useFormatter()\n const direction = useDirection()\n const tools = props.alfakitDevTools\n const data = useMemo(() => inspectableProps(props as unknown as Record<string, unknown>), [props])\n const payload = useMemo(() => byteLength(props), [props])\n const [query, setQuery] = useState('')\n const [copied, setCopied] = useState(false)\n // The inspector renders in the browser only (lazy chunk), so the Performance API is there.\n const [serverTime, setServerTime] = useState<number | null>(() => latestServerTiming())\n const search = useMemo(() => searchJson(data, query), [data, query])\n\n // Re-read the timing after every visit: the latest response carries the newest header.\n useEffect(() => router.on('finish', () => setServerTime(latestServerTiming())), [])\n\n useEffect(() => {\n if (!copied) return\n\n const timer = setTimeout(() => setCopied(false), 2000)\n\n return () => clearTimeout(timer)\n }, [copied])\n\n if (!tools) {\n return null\n }\n\n const copy = () => {\n void navigator.clipboard?.writeText(prettyJson(data)).then(() => setCopied(true))\n }\n\n const time = (value: number | null) =>\n value === null ? t('dev_tools.never', {}, 'Never') : formatter.dateTime(value * 1000)\n const parameters = Object.entries(tools.context.parameters)\n\n return (\n <Sheet>\n <SheetTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon\"\n aria-label={t('dev_tools.open', {}, 'Open schema inspector')}\n data-slot=\"dev-tools-toggle\"\n className=\"fixed end-4 bottom-16 z-40 rounded-full shadow-md [[data-slot=starter-kit-root]_&]:end-auto [[data-slot=starter-kit-root]_&]:right-4\"\n >\n <BracesIcon />\n </Button>\n </SheetTrigger>\n <SheetContent\n side={\n overlayPlacementDirection(direction, props.alfakit?.starterKit) === 'rtl'\n ? 'left'\n : 'right'\n }\n className=\"flex w-full flex-col gap-0 p-0 sm:max-w-xl\"\n >\n <div data-slot=\"dev-tools\" className=\"flex min-h-0 flex-1 flex-col\">\n <SheetHeader className=\"border-b\">\n <SheetTitle className=\"flex items-center gap-2\">\n <BracesIcon className=\"size-4\" />\n {t('dev_tools.title', {}, 'Schema inspector')}\n </SheetTitle>\n <SheetDescription className=\"truncate font-mono text-xs\" title={tools.context.page}>\n {tools.context.page}\n </SheetDescription>\n </SheetHeader>\n <ScrollArea className=\"min-h-0 flex-1\">\n <div className=\"space-y-5 p-4 text-sm\">\n <dl className=\"grid grid-cols-2 gap-3\">\n <Stat\n label={t('dev_tools.server_time', {}, 'Server time')}\n value={\n serverTime === null\n ? t('dev_tools.not_measured', {}, 'Not measured')\n : t(\n 'dev_tools.milliseconds',\n { value: formatter.number(serverTime) },\n ':value ms',\n )\n }\n />\n <Stat\n label={t('dev_tools.payload', {}, 'Payload size')}\n value={formatBytes(payload)}\n />\n </dl>\n\n <section data-slot=\"dev-tools-context\">\n <h3 className=\"mb-2 text-sm font-medium\">\n {t('dev_tools.context', {}, 'Context token')}\n </h3>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-xs\">\n <Row label={t('dev_tools.panel', {}, 'Panel')} value={tools.context.panel} />\n <Row label={t('dev_tools.page', {}, 'Page')} value={tools.context.page} />\n {tools.context.component && (\n <Row\n label={t('dev_tools.component', {}, 'Component')}\n value={tools.context.component}\n />\n )}\n {tools.tenant !== null && (\n <Row label={t('dev_tools.tenant', {}, 'Tenant')} value={tools.tenant} />\n )}\n {parameters.map(([key, value]) => (\n <Row key={key} label={key} value={jsonScalar(value)} />\n ))}\n <Row\n label={t('dev_tools.bound_to_user', {}, 'Bound to the user')}\n value={\n tools.context.boundToUser\n ? t('dev_tools.yes', {}, 'Yes')\n : t('dev_tools.no', {}, 'No')\n }\n plain\n />\n <Row\n label={t('dev_tools.issued_at', {}, 'Issued')}\n value={time(tools.context.issuedAt)}\n plain\n />\n <Row\n label={t('dev_tools.expires_at', {}, 'Expires')}\n value={time(tools.context.expiresAt)}\n plain\n />\n </dl>\n </section>\n\n <section data-slot=\"dev-tools-classes\">\n <h3 className=\"mb-2 text-sm font-medium\">\n {t('dev_tools.classes', {}, 'Classes')}\n </h3>\n <ul className=\"divide-y rounded-md border text-xs\">\n {tools.classes.map((item) => (\n <li key={item.role} className=\"flex items-center gap-2 px-3 py-1.5\">\n <span className=\"text-muted-foreground w-16 shrink-0\">\n {t(`dev_tools.roles.${item.role}`, {}, item.role)}\n </span>\n <span\n className=\"min-w-0 flex-1 truncate font-mono\"\n title={item.file ? `${item.file}:${item.line ?? 1}` : item.class}\n >\n {item.class}\n </span>\n {item.url && (\n <a\n href={item.url}\n className=\"text-primary inline-flex shrink-0 items-center gap-1 hover:underline\"\n aria-label={t(\n 'dev_tools.open_in_editor',\n { class: item.class, editor: tools.editor ?? '' },\n 'Open :class in :editor',\n )}\n >\n <ExternalLinkIcon className=\"size-3.5\" />\n </a>\n )}\n </li>\n ))}\n </ul>\n {tools.editor === null && (\n <p className=\"text-muted-foreground mt-2 text-xs\">\n {t(\n 'dev_tools.no_editor',\n {},\n 'Set APP_EDITOR (config app.editor) to open these classes in your editor.',\n )}\n </p>\n )}\n </section>\n\n <section data-slot=\"dev-tools-schema\">\n <div className=\"mb-2 flex items-center gap-2\">\n <h3 className=\"me-auto text-sm font-medium\">\n {t('dev_tools.schema', {}, 'Schema')}\n </h3>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={copy}>\n {copied ? <CheckIcon /> : <CopyIcon />}\n {copied\n ? t('dev_tools.copied', {}, 'Copied')\n : t('dev_tools.copy', {}, 'Copy JSON')}\n </Button>\n </div>\n <Input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={t('dev_tools.search', {}, 'Search keys and values')}\n aria-label={t('dev_tools.search', {}, 'Search keys and values')}\n className=\"mb-2 h-8\"\n />\n {query.trim() !== '' && search.matches.size === 0 ? (\n <p className=\"text-muted-foreground text-sm\">\n {t(\n 'dev_tools.no_matches',\n { query: query.trim() },\n 'Nothing matches “:query”.',\n )}\n </p>\n ) : (\n <ul\n dir=\"ltr\"\n role=\"tree\"\n aria-label={t('dev_tools.schema', {}, 'Schema')}\n className=\"bg-muted/40 overflow-x-auto rounded-md p-2 text-start font-mono text-xs leading-relaxed\"\n >\n {jsonEntries(data).map((entry) => (\n <JsonNode\n key={entry.path}\n entry={entry}\n depth={0}\n search={search}\n query={query}\n />\n ))}\n </ul>\n )}\n </section>\n </div>\n </ScrollArea>\n </div>\n </SheetContent>\n </Sheet>\n )\n}\n\nfunction JsonNode({\n entry,\n depth,\n search,\n query,\n}: {\n entry: JsonEntry\n depth: number\n search: JsonSearchResult\n query: string\n}) {\n const t = useT()\n const formatter = useFormatter()\n const searching = query.trim() !== ''\n const [open, setOpen] = useState(depth < 1)\n\n if (searching && !search.visible.has(entry.path)) {\n return null\n }\n\n const container = entry.kind === 'object' || entry.kind === 'array'\n const expanded = searching || open\n const matched = search.matches.has(entry.path)\n const size = jsonSize(entry.value)\n const key = (\n <span className={cn('text-foreground', matched && 'bg-primary/15 rounded-sm')}>\n {entry.key}\n </span>\n )\n\n if (!container) {\n return (\n <li\n role=\"treeitem\"\n aria-selected={false}\n className=\"py-px\"\n style={{ paddingInlineStart: `${depth * 12 + 16}px` }}\n >\n {key}\n <span className=\"text-muted-foreground\">: </span>\n <span\n className={cn(\n entry.kind === 'string' && 'text-emerald-700 dark:text-emerald-400',\n entry.kind === 'number' && 'text-sky-700 dark:text-sky-400',\n entry.kind === 'boolean' && 'text-violet-700 dark:text-violet-400',\n entry.kind === 'null' && 'text-muted-foreground',\n 'break-all',\n )}\n >\n {jsonScalar(entry.value)}\n </span>\n </li>\n )\n }\n\n return (\n <li role=\"treeitem\" aria-selected={false} aria-expanded={expanded}>\n <button\n type=\"button\"\n className=\"hover:bg-muted flex w-full items-center gap-1 rounded py-px text-start\"\n style={{ paddingInlineStart: `${depth * 12}px` }}\n onClick={() => setOpen(!open)}\n aria-label={\n expanded\n ? t('dev_tools.collapse', { key: entry.key }, 'Collapse :key')\n : t('dev_tools.expand', { key: entry.key }, 'Expand :key')\n }\n >\n {/* The tree is always left to right (it is code), so the chevron does not flip. */}\n <ChevronRightIcon\n className={cn('size-3 shrink-0 transition-transform', expanded && 'rotate-90')}\n />\n {key}\n <span className=\"text-muted-foreground\">\n {entry.kind === 'array' ? `[${formatter.number(size)}]` : `{${formatter.number(size)}}`}\n </span>\n </button>\n {expanded && size > 0 && (\n <ul role=\"group\">\n {jsonEntries(entry.value, entry.path).map((child) => (\n <JsonNode\n key={child.path}\n entry={child}\n depth={depth + 1}\n search={search}\n query={query}\n />\n ))}\n </ul>\n )}\n </li>\n )\n}\n\nfunction Stat({ label, value }: { label: string; value: string }) {\n return (\n <div className=\"rounded-md border p-3\">\n <dt className=\"text-muted-foreground text-xs\">{label}</dt>\n <dd className=\"font-mono text-sm font-semibold tabular-nums\">{value}</dd>\n </div>\n )\n}\n\nfunction Row({ label, value, plain = false }: { label: string; value: string; plain?: boolean }) {\n return (\n <>\n <dt className=\"text-muted-foreground\">{label}</dt>\n <dd className={cn('min-w-0 truncate', !plain && 'font-mono')} title={value}>\n {value}\n </dd>\n </>\n )\n}\n"],"mappings":"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"}
@@ -1,5 +1,10 @@
1
1
  import { MoneyInputSchema } from "@alfakit/core";
2
2
  //#region src/components/fields/money-input.d.ts
3
+ /**
4
+ * Amount input for any ISO 4217 currency. Shows the symbol where the user's locale puts
5
+ * it, accepts the locale's separators and digits ("1.234,50", "١٢٫٥"), and rounds to
6
+ * the currency's precision on blur. The form value is a plain decimal string ("1234.50").
7
+ */
3
8
  export declare function MoneyInputField({ component }: {
4
9
  component: MoneyInputSchema;
5
10
  }): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"money-input.d.ts","names":[],"sources":["../../../src/components/fields/money-input.tsx"],"mappings":";;wBAsBgB,kBAAkB;EAAe,WAAW;oBAAkB,IAAA"}
1
+ {"version":3,"file":"money-input.d.ts","names":[],"sources":["../../../src/components/fields/money-input.tsx"],"mappings":";;;;;;;wBAegB,kBAAkB;EAAe,WAAW;oBAAkB,IAAA"}
@@ -13,9 +13,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
13
13
  * it, accepts the locale's separators and digits ("1.234,50", "١٢٫٥"), and rounds to
14
14
  * the currency's precision on blur. The form value is a plain decimal string ("1234.50").
15
15
  */
16
- function clampAmount(amount, min, max) {
17
- return Math.min(max ?? Number.POSITIVE_INFINITY, Math.max(min ?? Number.NEGATIVE_INFINITY, amount));
18
- }
19
16
  function MoneyInputField({ component }) {
20
17
  const { value, setValue, blur, error, id, disabled, aria } = useField(component);
21
18
  const format = useFormatter();
@@ -32,7 +29,7 @@ function MoneyInputField({ component }) {
32
29
  return;
33
30
  }
34
31
  const parsed = format.parseNumber(text);
35
- setValue(parsed === null ? text : clampAmount(parsed, component.min, component.max).toFixed(component.decimals));
32
+ setValue(parsed === null ? text : parsed.toFixed(component.decimals));
36
33
  };
37
34
  const affix = (text, icon, side) => text || icon ? /* @__PURE__ */ jsxs("span", {
38
35
  className: cn("text-muted-foreground bg-muted/50 flex items-center gap-1 px-3 text-sm whitespace-nowrap", side === "start" ? "border-e" : "border-s"),
@@ -86,6 +83,6 @@ function MoneyInputField({ component }) {
86
83
  });
87
84
  }
88
85
  //#endregion
89
- export { MoneyInputField, clampAmount };
86
+ export { MoneyInputField };
90
87
 
91
88
  //# sourceMappingURL=money-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"money-input.js","names":[],"sources":["../../../src/components/fields/money-input.tsx"],"sourcesContent":["import type { MoneyInputSchema } from '@alfakit/core'\nimport { useState } from 'react'\nimport { useFormatter } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { Input } from '../ui/input'\n\n/**\n * Amount input for any ISO 4217 currency. Shows the symbol where the user's locale puts\n * it, accepts the locale's separators and digits (\"1.234,50\", \"١٢٫٥\"), and rounds to\n * the currency's precision on blur. The form value is a plain decimal string (\"1234.50\").\n */\nexport function clampAmount(amount: number, min?: number | null, max?: number | null): number {\n const lower = min ?? Number.NEGATIVE_INFINITY\n const upper = max ?? Number.POSITIVE_INFINITY\n\n return Math.min(upper, Math.max(lower, amount))\n}\n\nexport function MoneyInputField({ component }: { component: MoneyInputSchema }) {\n const { value, setValue, blur, error, id, disabled, aria } = useField<string | number | null>(\n component,\n )\n const format = useFormatter()\n const [draft, setDraft] = useState<string | null>(null)\n\n const { prefix, suffix } = format.currencyAffixes(component.currency)\n const amount = value === null || value === undefined || value === '' ? null : Number(value)\n const display =\n amount === null || Number.isNaN(amount)\n ? String(value ?? '')\n : format.number(amount, {\n minimumFractionDigits: component.decimals,\n maximumFractionDigits: component.decimals,\n })\n\n const commit = (text: string) => {\n if (text.trim() === '') {\n setValue(null)\n\n return\n }\n\n const parsed = format.parseNumber(text)\n\n // Unparseable input is kept as typed so server validation can explain the problem;\n // amounts are brought inside `minValue()` / `maxValue()`.\n setValue(\n parsed === null\n ? text\n : clampAmount(parsed, component.min, component.max).toFixed(component.decimals),\n )\n }\n\n const affix = (text: string, icon: string | undefined, side: 'start' | 'end') =>\n text || icon ? (\n <span\n className={cn(\n 'text-muted-foreground bg-muted/50 flex items-center gap-1 px-3 text-sm whitespace-nowrap',\n side === 'start' ? 'border-e' : 'border-s',\n )}\n >\n {side === 'start' && <Icon name={icon} />}\n {text}\n {side === 'end' && <Icon name={icon} />}\n </span>\n ) : null\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <div\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-ring/50 flex h-9 w-full items-stretch overflow-hidden rounded-md border shadow-xs has-[input:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n disabled && 'opacity-50',\n )}\n >\n {affix([component.prefix, prefix].filter(Boolean).join(' '), component.prefixIcon, 'start')}\n <Input\n id={id}\n name={component.name}\n type=\"text\"\n inputMode={component.decimals > 0 ? 'decimal' : 'numeric'}\n dir=\"ltr\"\n value={draft ?? display}\n onFocus={() =>\n setDraft(\n amount === null || Number.isNaN(amount)\n ? String(value ?? '')\n : format.number(amount, {\n useGrouping: false,\n maximumFractionDigits: component.decimals,\n }),\n )\n }\n onChange={(event) => {\n setDraft(event.target.value)\n const parsed = format.parseNumber(event.target.value)\n setValue(\n event.target.value.trim() === ''\n ? null\n : parsed === null\n ? event.target.value\n : String(parsed),\n )\n }}\n onBlur={(event) => {\n commit(event.target.value)\n setDraft(null)\n blur()\n }}\n placeholder={component.placeholder}\n disabled={disabled}\n readOnly={component.readOnly}\n required={component.required}\n autoFocus={component.autofocus}\n {...aria}\n\n {...extraProps(\n component.extraInputAttributes,\n 'h-full border-0 bg-transparent text-end tabular-nums shadow-none focus-visible:ring-0 dark:bg-transparent',\n )}\n />\n {affix([suffix, component.suffix].filter(Boolean).join(' '), component.suffixIcon, 'end')}\n </div>\n </FieldWrapper>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgB,YAAY,QAAgB,KAAqB,KAA6B;CAI5F,OAAO,KAAK,IAFE,OAAO,OAAO,mBAEL,KAAK,IAHd,OAAO,OAAO,mBAGW,MAAM,CAAC;AAChD;AAEA,SAAgB,gBAAgB,EAAE,aAA8C;CAC9E,MAAM,EAAE,OAAO,UAAU,MAAM,OAAO,IAAI,UAAU,SAAS,SAC3D,SACF;CACA,MAAM,SAAS,aAAa;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CAEtD,MAAM,EAAE,QAAQ,WAAW,OAAO,gBAAgB,UAAU,QAAQ;CACpE,MAAM,SAAS,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU,KAAK,OAAO,OAAO,KAAK;CAC1F,MAAM,UACJ,WAAW,QAAQ,OAAO,MAAM,MAAM,IAClC,OAAO,SAAS,EAAE,IAClB,OAAO,OAAO,QAAQ;EACpB,uBAAuB,UAAU;EACjC,uBAAuB,UAAU;CACnC,CAAC;CAEP,MAAM,UAAU,SAAiB;EAC/B,IAAI,KAAK,KAAK,MAAM,IAAI;GACtB,SAAS,IAAI;GAEb;EACF;EAEA,MAAM,SAAS,OAAO,YAAY,IAAI;EAItC,SACE,WAAW,OACP,OACA,YAAY,QAAQ,UAAU,KAAK,UAAU,GAAG,CAAC,CAAC,QAAQ,UAAU,QAAQ,CAClF;CACF;CAEA,MAAM,SAAS,MAAc,MAA0B,SACrD,QAAQ,OACN,qBAAC,QAAD;EACE,WAAW,GACT,4FACA,SAAS,UAAU,aAAa,UAClC;EAJF,UAAA;GAMG,SAAS,WAAW,oBAAC,MAAD,EAAM,MAAM,KAAO,CAAA;GACvC;GACA,SAAS,SAAS,oBAAC,MAAD,EAAM,MAAM,KAAO,CAAA;EAClC;CACJ,CAAA,IAAA;CAEN,OACE,oBAAC,cAAD;EAAc,OAAO;EAAW,SAAS;EAAW;EAClD,UAAA,qBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,6NACA,SAAS,sBACT,YAAY,YACd;GANF,UAAA;IAQG,MAAM,CAAC,UAAU,QAAQ,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GAAG,UAAU,YAAY,OAAO;IAC1F,oBAAC,OAAD;KACM;KACJ,MAAM,UAAU;KAChB,MAAK;KACL,WAAW,UAAU,WAAW,IAAI,YAAY;KAChD,KAAI;KACJ,OAAO,SAAS;KAChB,eACE,SACE,WAAW,QAAQ,OAAO,MAAM,MAAM,IAClC,OAAO,SAAS,EAAE,IAClB,OAAO,OAAO,QAAQ;MACpB,aAAa;MACb,uBAAuB,UAAU;KACnC,CAAC,CACP;KAEF,WAAW,UAAU;MACnB,SAAS,MAAM,OAAO,KAAK;MAC3B,MAAM,SAAS,OAAO,YAAY,MAAM,OAAO,KAAK;MACpD,SACE,MAAM,OAAO,MAAM,KAAK,MAAM,KAC1B,OACA,WAAW,OACT,MAAM,OAAO,QACb,OAAO,MAAM,CACrB;KACF;KACA,SAAS,UAAU;MACjB,OAAO,MAAM,OAAO,KAAK;MACzB,SAAS,IAAI;MACb,KAAK;KACP;KACA,aAAa,UAAU;KACb;KACV,UAAU,UAAU;KACpB,UAAU,UAAU;KACpB,WAAW,UAAU;KACrB,GAAI;KAEJ,GAAI,WACF,UAAU,sBACV,2GACF;IACD,CAAA;IACA,MAAM,CAAC,QAAQ,UAAU,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GAAG,UAAU,YAAY,KAAK;GACrF;;CACO,CAAA;AAElB"}
1
+ {"version":3,"file":"money-input.js","names":[],"sources":["../../../src/components/fields/money-input.tsx"],"sourcesContent":["import type { MoneyInputSchema } from '@alfakit/core'\nimport { useState } from 'react'\nimport { useFormatter } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { FieldWrapper } from '../schema/field-wrapper'\nimport { Input } from '../ui/input'\n\n/**\n * Amount input for any ISO 4217 currency. Shows the symbol where the user's locale puts\n * it, accepts the locale's separators and digits (\"1.234,50\", \"١٢٫٥\"), and rounds to\n * the currency's precision on blur. The form value is a plain decimal string (\"1234.50\").\n */\nexport function MoneyInputField({ component }: { component: MoneyInputSchema }) {\n const { value, setValue, blur, error, id, disabled, aria } = useField<string | number | null>(\n component,\n )\n const format = useFormatter()\n const [draft, setDraft] = useState<string | null>(null)\n\n const { prefix, suffix } = format.currencyAffixes(component.currency)\n const amount = value === null || value === undefined || value === '' ? null : Number(value)\n const display =\n amount === null || Number.isNaN(amount)\n ? String(value ?? '')\n : format.number(amount, {\n minimumFractionDigits: component.decimals,\n maximumFractionDigits: component.decimals,\n })\n\n const commit = (text: string) => {\n if (text.trim() === '') {\n setValue(null)\n\n return\n }\n\n const parsed = format.parseNumber(text)\n\n // Unparseable input is kept as typed and out-of-range amounts are kept as well, so the\n // server's `minValue()` / `maxValue()` rules report them (W-V3-11).\n setValue(parsed === null ? text : parsed.toFixed(component.decimals))\n }\n\n const affix = (text: string, icon: string | undefined, side: 'start' | 'end') =>\n text || icon ? (\n <span\n className={cn(\n 'text-muted-foreground bg-muted/50 flex items-center gap-1 px-3 text-sm whitespace-nowrap',\n side === 'start' ? 'border-e' : 'border-s',\n )}\n >\n {side === 'start' && <Icon name={icon} />}\n {text}\n {side === 'end' && <Icon name={icon} />}\n </span>\n ) : null\n\n return (\n <FieldWrapper field={component} htmlFor={id} error={error}>\n <div\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-ring/50 flex h-9 w-full items-stretch overflow-hidden rounded-md border shadow-xs has-[input:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n disabled && 'opacity-50',\n )}\n >\n {affix([component.prefix, prefix].filter(Boolean).join(' '), component.prefixIcon, 'start')}\n <Input\n id={id}\n name={component.name}\n type=\"text\"\n inputMode={component.decimals > 0 ? 'decimal' : 'numeric'}\n dir=\"ltr\"\n value={draft ?? display}\n onFocus={() =>\n setDraft(\n amount === null || Number.isNaN(amount)\n ? String(value ?? '')\n : format.number(amount, {\n useGrouping: false,\n maximumFractionDigits: component.decimals,\n }),\n )\n }\n onChange={(event) => {\n setDraft(event.target.value)\n const parsed = format.parseNumber(event.target.value)\n setValue(\n event.target.value.trim() === ''\n ? null\n : parsed === null\n ? event.target.value\n : String(parsed),\n )\n }}\n onBlur={(event) => {\n commit(event.target.value)\n setDraft(null)\n blur()\n }}\n placeholder={component.placeholder}\n disabled={disabled}\n readOnly={component.readOnly}\n required={component.required}\n autoFocus={component.autofocus}\n {...aria}\n\n {...extraProps(\n component.extraInputAttributes,\n 'h-full border-0 bg-transparent text-end tabular-nums shadow-none focus-visible:ring-0 dark:bg-transparent',\n )}\n />\n {affix([suffix, component.suffix].filter(Boolean).join(' '), component.suffixIcon, 'end')}\n </div>\n </FieldWrapper>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgB,gBAAgB,EAAE,aAA8C;CAC9E,MAAM,EAAE,OAAO,UAAU,MAAM,OAAO,IAAI,UAAU,SAAS,SAC3D,SACF;CACA,MAAM,SAAS,aAAa;CAC5B,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CAEtD,MAAM,EAAE,QAAQ,WAAW,OAAO,gBAAgB,UAAU,QAAQ;CACpE,MAAM,SAAS,UAAU,QAAQ,UAAU,KAAA,KAAa,UAAU,KAAK,OAAO,OAAO,KAAK;CAC1F,MAAM,UACJ,WAAW,QAAQ,OAAO,MAAM,MAAM,IAClC,OAAO,SAAS,EAAE,IAClB,OAAO,OAAO,QAAQ;EACpB,uBAAuB,UAAU;EACjC,uBAAuB,UAAU;CACnC,CAAC;CAEP,MAAM,UAAU,SAAiB;EAC/B,IAAI,KAAK,KAAK,MAAM,IAAI;GACtB,SAAS,IAAI;GAEb;EACF;EAEA,MAAM,SAAS,OAAO,YAAY,IAAI;EAItC,SAAS,WAAW,OAAO,OAAO,OAAO,QAAQ,UAAU,QAAQ,CAAC;CACtE;CAEA,MAAM,SAAS,MAAc,MAA0B,SACrD,QAAQ,OACN,qBAAC,QAAD;EACE,WAAW,GACT,4FACA,SAAS,UAAU,aAAa,UAClC;EAJF,UAAA;GAMG,SAAS,WAAW,oBAAC,MAAD,EAAM,MAAM,KAAO,CAAA;GACvC;GACA,SAAS,SAAS,oBAAC,MAAD,EAAM,MAAM,KAAO,CAAA;EAClC;CACJ,CAAA,IAAA;CAEN,OACE,oBAAC,cAAD;EAAc,OAAO;EAAW,SAAS;EAAW;EAClD,UAAA,qBAAC,OAAD;GACE,aAAU;GACV,WAAW,GACT,6NACA,SAAS,sBACT,YAAY,YACd;GANF,UAAA;IAQG,MAAM,CAAC,UAAU,QAAQ,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GAAG,UAAU,YAAY,OAAO;IAC1F,oBAAC,OAAD;KACM;KACJ,MAAM,UAAU;KAChB,MAAK;KACL,WAAW,UAAU,WAAW,IAAI,YAAY;KAChD,KAAI;KACJ,OAAO,SAAS;KAChB,eACE,SACE,WAAW,QAAQ,OAAO,MAAM,MAAM,IAClC,OAAO,SAAS,EAAE,IAClB,OAAO,OAAO,QAAQ;MACpB,aAAa;MACb,uBAAuB,UAAU;KACnC,CAAC,CACP;KAEF,WAAW,UAAU;MACnB,SAAS,MAAM,OAAO,KAAK;MAC3B,MAAM,SAAS,OAAO,YAAY,MAAM,OAAO,KAAK;MACpD,SACE,MAAM,OAAO,MAAM,KAAK,MAAM,KAC1B,OACA,WAAW,OACT,MAAM,OAAO,QACb,OAAO,MAAM,CACrB;KACF;KACA,SAAS,UAAU;MACjB,OAAO,MAAM,OAAO,KAAK;MACzB,SAAS,IAAI;MACb,KAAK;KACP;KACA,aAAa,UAAU;KACb;KACV,UAAU,UAAU;KACpB,UAAU,UAAU;KACpB,WAAW,UAAU;KACrB,GAAI;KAEJ,GAAI,WACF,UAAU,sBACV,2GACF;IACD,CAAA;IACA,MAAM,CAAC,QAAQ,UAAU,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GAAG,UAAU,YAAY,KAAK;GACrF;;CACO,CAAA;AAElB"}
@@ -1,3 +1,4 @@
1
+ import "@alfakit/core";
1
2
  //#region src/components/panel/lazy-placeholder.d.ts
2
3
  /**
3
4
  * Stands in for a lazy widget or relation manager until the `alfakitLazy` deferred prop
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-placeholder.d.ts","names":[],"sources":["../../../src/components/panel/lazy-placeholder.tsx"],"mappings":";;;;;wBAQgB,kBACd,SACA;EAEA;EACA;oBACD,IAAA"}
1
+ {"version":3,"file":"lazy-placeholder.d.ts","names":[],"sources":["../../../src/components/panel/lazy-placeholder.tsx"],"mappings":";;;;;;wBAWgB,kBACd,SACA;EAEA;EACA;oBACD,IAAA"}
@@ -1,7 +1,10 @@
1
- import { useT } from "../../context.js";
1
+ import { useRefreshComponents, useT } from "../../context.js";
2
2
  import { cn } from "../../lib/utils.js";
3
+ import { Button } from "../ui/button.js";
3
4
  import { Skeleton } from "../ui/skeleton.js";
4
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { widgetPollTarget } from "@alfakit/core";
6
+ import { useState } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
8
  //#region src/components/panel/lazy-placeholder.tsx
6
9
  /**
7
10
  * Stands in for a lazy widget or relation manager until the `alfakitLazy` deferred prop
@@ -21,7 +24,7 @@ function LazyPlaceholder({ variant = "widget", className }) {
21
24
  children: t("loading", {}, "Loading…")
22
25
  }),
23
26
  /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-1/3" }),
24
- variant === "table" ? /* @__PURE__ */ jsxs(Fragment, { children: [
27
+ variant === "table" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
25
28
  /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full" }),
26
29
  /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full" }),
27
30
  /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-full" })
@@ -29,7 +32,38 @@ function LazyPlaceholder({ variant = "widget", className }) {
29
32
  ]
30
33
  });
31
34
  }
35
+ /**
36
+ * A lazy widget's cell: the skeleton while its schema loads, or, when the request failed
37
+ * (outside panels: a refused or failed fetch), a message with a retry.
38
+ */
39
+ function LazyWidgetPlaceholder({ widget }) {
40
+ const t = useT();
41
+ const refresh = useRefreshComponents();
42
+ const [retrying, setRetrying] = useState(false);
43
+ const variant = widget.type === "TableWidget" ? "table" : "widget";
44
+ if (!widget.failed) return /* @__PURE__ */ jsx(LazyPlaceholder, { variant });
45
+ const retry = () => {
46
+ if (!refresh) return;
47
+ setRetrying(true);
48
+ Promise.resolve(refresh([widgetPollTarget(widget)])).finally(() => setRetrying(false));
49
+ };
50
+ return /* @__PURE__ */ jsxs("div", {
51
+ "data-slot": "lazy-placeholder",
52
+ "data-variant": variant,
53
+ "data-failed": "",
54
+ role: "alert",
55
+ className: "bg-card text-muted-foreground flex min-h-28 flex-col items-center justify-center gap-3 rounded-xl border border-dashed p-6 text-center text-sm",
56
+ children: [/* @__PURE__ */ jsx("p", { children: t("widget_failed", {}, "This widget could not be loaded.") }), refresh && /* @__PURE__ */ jsx(Button, {
57
+ type: "button",
58
+ variant: "outline",
59
+ size: "sm",
60
+ disabled: retrying,
61
+ onClick: retry,
62
+ children: t("retry", {}, "Retry")
63
+ })]
64
+ });
65
+ }
32
66
  //#endregion
33
- export { LazyPlaceholder };
67
+ export { LazyPlaceholder, LazyWidgetPlaceholder };
34
68
 
35
69
  //# sourceMappingURL=lazy-placeholder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lazy-placeholder.js","names":[],"sources":["../../../src/components/panel/lazy-placeholder.tsx"],"sourcesContent":["import { useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { Skeleton } from '../ui/skeleton'\n\n/**\n * Stands in for a lazy widget or relation manager until the `alfakitLazy` deferred prop\n * brings its schema. `table` mimics a table (relation managers, table widgets).\n */\nexport function LazyPlaceholder({\n variant = 'widget',\n className,\n}: {\n variant?: 'widget' | 'table'\n className?: string\n}) {\n const t = useT()\n\n return (\n <div\n data-slot=\"lazy-placeholder\"\n data-variant={variant}\n role=\"status\"\n aria-busy=\"true\"\n className={cn('bg-card flex flex-col gap-3 rounded-xl border p-6', className)}\n >\n <span className=\"sr-only\">{t('loading', {}, 'Loading…')}</span>\n <Skeleton className=\"h-5 w-1/3\" />\n {variant === 'table' ? (\n <>\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n </>\n ) : (\n <Skeleton className=\"h-20 w-full\" />\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,gBAAgB,EAC9B,UAAU,UACV,aAIC;CACD,MAAM,IAAI,KAAK;CAEf,OACE,qBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,MAAK;EACL,aAAU;EACV,WAAW,GAAG,qDAAqD,SAAS;EAL9E,UAAA;GAOE,oBAAC,QAAD;IAAM,WAAU;IAAW,UAAA,EAAE,WAAW,CAAC,GAAG,UAAU;GAAQ,CAAA;GAC9D,oBAAC,UAAD,EAAU,WAAU,YAAa,CAAA;GAChC,YAAY,UACX,qBAAA,UAAA,EAAA,UAAA;IACE,oBAAC,UAAD,EAAU,WAAU,aAAc,CAAA;IAClC,oBAAC,UAAD,EAAU,WAAU,aAAc,CAAA;IAClC,oBAAC,UAAD,EAAU,WAAU,aAAc,CAAA;GAClC,EAAA,CAAA,IAEF,oBAAC,UAAD,EAAU,WAAU,cAAe,CAAA;EAElC;;AAET"}
1
+ {"version":3,"file":"lazy-placeholder.js","names":[],"sources":["../../../src/components/panel/lazy-placeholder.tsx"],"sourcesContent":["import { widgetPollTarget, type LazyWidgetSchema } from '@alfakit/core'\nimport { useState } from 'react'\nimport { useRefreshComponents, useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport { Button } from '../ui/button'\nimport { Skeleton } from '../ui/skeleton'\n\n/**\n * Stands in for a lazy widget or relation manager until the `alfakitLazy` deferred prop\n * brings its schema. `table` mimics a table (relation managers, table widgets).\n */\nexport function LazyPlaceholder({\n variant = 'widget',\n className,\n}: {\n variant?: 'widget' | 'table'\n className?: string\n}) {\n const t = useT()\n\n return (\n <div\n data-slot=\"lazy-placeholder\"\n data-variant={variant}\n role=\"status\"\n aria-busy=\"true\"\n className={cn('bg-card flex flex-col gap-3 rounded-xl border p-6', className)}\n >\n <span className=\"sr-only\">{t('loading', {}, 'Loading…')}</span>\n <Skeleton className=\"h-5 w-1/3\" />\n {variant === 'table' ? (\n <>\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n <Skeleton className=\"h-9 w-full\" />\n </>\n ) : (\n <Skeleton className=\"h-20 w-full\" />\n )}\n </div>\n )\n}\n\n/**\n * A lazy widget's cell: the skeleton while its schema loads, or, when the request failed\n * (outside panels: a refused or failed fetch), a message with a retry.\n */\nexport function LazyWidgetPlaceholder({ widget }: { widget: LazyWidgetSchema }) {\n const t = useT()\n const refresh = useRefreshComponents()\n const [retrying, setRetrying] = useState(false)\n const variant = widget.type === 'TableWidget' ? 'table' : 'widget'\n\n if (!widget.failed) return <LazyPlaceholder variant={variant} />\n\n const retry = () => {\n if (!refresh) return\n\n setRetrying(true)\n void Promise.resolve(refresh([widgetPollTarget(widget)])).finally(() => setRetrying(false))\n }\n\n return (\n <div\n data-slot=\"lazy-placeholder\"\n data-variant={variant}\n data-failed=\"\"\n role=\"alert\"\n className=\"bg-card text-muted-foreground flex min-h-28 flex-col items-center justify-center gap-3 rounded-xl border border-dashed p-6 text-center text-sm\"\n >\n <p>{t('widget_failed', {}, 'This widget could not be loaded.')}</p>\n {refresh && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={retrying} onClick={retry}>\n {t('retry', {}, 'Retry')}\n </Button>\n )}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,gBAAgB,EAC9B,UAAU,UACV,aAIC;CACD,MAAM,IAAI,KAAK;CAEf,OACE,qBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,MAAK;EACL,aAAU;EACV,WAAW,GAAG,qDAAqD,SAAS;EAL9E,UAAA;GAOE,oBAAC,QAAD;IAAM,WAAU;IAAW,UAAA,EAAE,WAAW,CAAC,GAAG,UAAU;GAAQ,CAAA;GAC9D,oBAAC,UAAD,EAAU,WAAU,YAAa,CAAA;GAChC,YAAY,UACX,qBAAA,YAAA,EAAA,UAAA;IACE,oBAAC,UAAD,EAAU,WAAU,aAAc,CAAA;IAClC,oBAAC,UAAD,EAAU,WAAU,aAAc,CAAA;IAClC,oBAAC,UAAD,EAAU,WAAU,aAAc,CAAA;GAClC,EAAA,CAAA,IAEF,oBAAC,UAAD,EAAU,WAAU,cAAe,CAAA;EAElC;;AAET;;;;;AAMA,SAAgB,sBAAsB,EAAE,UAAwC;CAC9E,MAAM,IAAI,KAAK;CACf,MAAM,UAAU,qBAAqB;CACrC,MAAM,CAAC,UAAU,eAAe,SAAS,KAAK;CAC9C,MAAM,UAAU,OAAO,SAAS,gBAAgB,UAAU;CAE1D,IAAI,CAAC,OAAO,QAAQ,OAAO,oBAAC,iBAAD,EAA0B,QAAU,CAAA;CAE/D,MAAM,cAAc;EAClB,IAAI,CAAC,SAAS;EAEd,YAAY,IAAI;EAChB,QAAa,QAAQ,QAAQ,CAAC,iBAAiB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,YAAY,KAAK,CAAC;CAC5F;CAEA,OACE,qBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,eAAY;EACZ,MAAK;EACL,WAAU;EALZ,UAAA,CAOE,oBAAC,KAAD,EAAA,UAAI,EAAE,iBAAiB,CAAC,GAAG,kCAAkC,EAAK,CAAA,GACjE,WACC,oBAAC,QAAD;GAAQ,MAAK;GAAS,SAAQ;GAAU,MAAK;GAAK,UAAU;GAAU,SAAS;GAC5E,UAAA,EAAE,SAAS,CAAC,GAAG,OAAO;EACjB,CAAA,CAEP;;AAET"}
@@ -117,7 +117,7 @@ function ImageCell({ column, cell }) {
117
117
  className: cn("flex items-center", schema.wrap && "flex-wrap", schema.stacked ? usesDefaultImageStack(schema) && "-space-x-2" : "gap-1.5", schema.wrap && schema.stacked && "gap-y-1.5"),
118
118
  children: [urls.slice(0, limit).map((url, index) => /* @__PURE__ */ jsx("img", {
119
119
  src: url,
120
- alt: cell.alt ?? "",
120
+ alt: cell.alt ?? (index === 0 ? column.label ?? "" : ""),
121
121
  style: {
122
122
  height: schema.height ?? size,
123
123
  width: schema.width ?? (schema.square || schema.circular ? size : void 0),
@@ -1 +1 @@
1
- {"version":3,"file":"cells.js","names":[],"sources":["../../../src/components/table/cells.tsx"],"sourcesContent":["import type {\n CellSchema,\n ColorColumnSchema,\n ColumnSchema,\n IconColumnSchema,\n Option,\n OptionOrGroup,\n RecordKey,\n SelectColumnSchema,\n TextInputColumnSchema,\n ToggleColumnSchema,\n ViewColumnSchema,\n} from '@alfakit/core'\nimport {\n columnRegistryKey,\n filterSelectColumnOptions,\n isOptionGroup,\n optionText,\n remainingTextSizeClass,\n resolvePartialProps,\n searchTableColumnOptions,\n selectColumnEmptyMessage,\n stackedImageStyle,\n updateTableCell,\n usesDefaultImageStack,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'\nimport { createElement, useEffect, useId, useRef, useState } from 'react'\nimport { usePanel, useRegistry, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport {\n colorClass,\n iconSizeClasses,\n switchOffColorClasses,\n switchOnColorClasses,\n textColorClasses,\n} from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { FormattedText } from '../entries/text-entry'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '../ui/command'\nimport { Input } from '../ui/input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport { Spinner } from '../ui/spinner'\nimport { Switch } from '../ui/switch'\n\nexport interface CellProps {\n column: ColumnSchema\n cell: CellSchema\n recordKey: RecordKey\n token: string\n component: string\n /**\n * Set when this renderer was picked from the registry (`column:<type>`): it then renders\n * the built-in cell instead of looking itself up again, so an ejected `TableCellContent`\n * registered for a column type doesn't render itself forever.\n */\n fromRegistry?: boolean\n}\n\nexport function TableCellContent(props: CellProps) {\n const { column } = props\n const registry = useRegistry()\n // A component registered as `column:<type>` replaces the built-in cell renderer.\n const Custom = props.fromRegistry ? undefined : registry.resolve(columnRegistryKey(column))\n\n if (Custom) {\n return createElement(Custom, { ...props, fromRegistry: true })\n }\n\n switch (column.type) {\n case 'IconColumn':\n return <IconCell {...props} />\n case 'ImageColumn':\n return <ImageCell {...props} />\n case 'ColorColumn':\n return <ColorCell {...props} />\n case 'ToggleColumn':\n case 'CheckboxColumn':\n return <BooleanCell {...props} />\n case 'SelectColumn':\n return <SelectCell {...props} />\n case 'TextInputColumn':\n return <TextInputCell {...props} />\n case 'ViewColumn':\n return <ViewCell {...props} />\n default:\n return <TextCell {...props} />\n }\n}\n\n/** `IconColumn`: one icon, or one per item of a list state (`wrap()` lets them wrap). */\nfunction IconCell({ column, cell }: CellProps) {\n const icons = cell.icons ?? (cell.icon ? [{ icon: cell.icon, color: cell.color }] : [])\n const sizeClass = colorClass(iconSizeClasses, cell.size, 'md')\n\n if (icons.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n if (!cell.icons) {\n return (\n <Icon\n name={icons[0]!.icon}\n className={cn(sizeClass, icons[0]!.color && textColorClasses[icons[0]!.color])}\n />\n )\n }\n\n return (\n <div\n data-slot=\"icon-column-icons\"\n className={cn(\n 'flex items-center gap-1.5',\n (column as IconColumnSchema).wrap ? 'flex-wrap' : 'flex-nowrap',\n )}\n >\n {icons.map((item, index) => (\n <Icon\n key={index}\n name={item.icon}\n className={cn(sizeClass, item.color && textColorClasses[item.color])}\n />\n ))}\n </div>\n )\n}\n\n/** `ViewColumn`: the application component registered under the column's `view()` name. */\nfunction ViewCell(props: CellProps) {\n const t = useT()\n const name = (props.column as ViewColumnSchema).component ?? ''\n const Custom = useRegistry().resolve(name)\n\n if (!name || !Custom) {\n return (\n <span className=\"text-destructive text-xs\">\n {t('component_not_registered', { component: name }, `Component ${name} is not registered.`)}\n </span>\n )\n }\n\n return createElement(Custom, { ...(props.cell.props ?? {}), state: props.cell.state, ...props })\n}\n\nfunction TextCell({ column, cell }: CellProps) {\n const text = (\n <FormattedText\n value={cell.state}\n schema={{\n ...(column as object),\n color: cell.color,\n icon: cell.icon,\n iconPosition: cell.iconPosition,\n iconColor: cell.iconColor,\n itemColors: cell.itemColors,\n itemIcons: cell.itemIcons,\n itemUrls: cell.itemUrls,\n }}\n />\n )\n const description = cell.description ? (\n <span className=\"text-muted-foreground block text-xs\">{cell.description}</span>\n ) : null\n const position =\n (column as { descriptionPosition?: 'above' | 'below' }).descriptionPosition ?? 'below'\n\n return (\n <div className=\"flex flex-col gap-0.5\">\n {position === 'above' && description}\n {text}\n {position === 'below' && description}\n </div>\n )\n}\n\nfunction ImageCell({ column, cell }: CellProps) {\n const urls = Array.isArray(cell.state) ? (cell.state as string[]) : []\n const schema = column as {\n circular?: boolean\n square?: boolean\n size?: number | string\n height?: number | string\n width?: string\n stacked?: boolean\n limit?: number\n limitedRemainingText?: boolean\n limitedRemainingTextSize?: string\n wrap?: boolean\n ring?: number\n overlap?: number\n }\n const limit = schema.limit ?? urls.length\n const size = schema.size ?? 40\n\n if (urls.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n return (\n <div\n className={cn(\n 'flex items-center',\n schema.wrap && 'flex-wrap',\n schema.stacked ? usesDefaultImageStack(schema) && '-space-x-2' : 'gap-1.5',\n schema.wrap && schema.stacked && 'gap-y-1.5',\n )}\n >\n {urls.slice(0, limit).map((url, index) => (\n <img\n key={index}\n src={url}\n alt={cell.alt ?? ''}\n style={{\n height: schema.height ?? size,\n width: schema.width ?? (schema.square || schema.circular ? size : undefined),\n ...stackedImageStyle(index, schema),\n }}\n {...extraProps(\n cell.extraImgAttributes,\n cn(\n 'object-cover',\n schema.circular ? 'rounded-full' : 'rounded-md',\n schema.stacked && usesDefaultImageStack(schema) && 'ring-background ring-2',\n ),\n )}\n />\n ))}\n {schema.limitedRemainingText && urls.length > limit && (\n <span\n data-slot=\"image-remaining\"\n className={cn(\n 'text-muted-foreground ms-1',\n remainingTextSizeClass(schema.limitedRemainingTextSize),\n )}\n >\n +{urls.length - limit}\n </span>\n )}\n </div>\n )\n}\n\nfunction ColorCell({ column, cell }: CellProps) {\n const t = useT()\n const schema = column as ColorColumnSchema\n const [copied, setCopied] = useState<string | null>(null)\n const colors = Array.isArray(cell.state)\n ? (cell.state as string[])\n : cell.state\n ? [String(cell.state)]\n : []\n\n if (colors.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n const copy = (color: string) => {\n void navigator.clipboard?.writeText(color).then(() => {\n setCopied(color)\n setTimeout(() => setCopied(null), schema.copyMessageDuration ?? 1500)\n })\n }\n\n return (\n <div className={cn('flex items-center gap-1.5', schema.wrap ? 'flex-wrap' : 'flex-nowrap')}>\n {colors.map((color) =>\n schema.copyable ? (\n <button\n key={color}\n type=\"button\"\n data-slot=\"color-copy\"\n title={color}\n aria-label={`${t('copy', {}, 'Copy')} ${color}`}\n className=\"focus-visible:ring-ring/50 inline-flex rounded outline-none focus-visible:ring-[3px]\"\n onClick={(event) => {\n // The cell may sit inside a link or a clickable row.\n event.preventDefault()\n event.stopPropagation()\n copy(color)\n }}\n >\n <span\n className=\"inline-flex size-5 items-center justify-center rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n >\n {copied === color && <CheckIcon className=\"size-3 text-white mix-blend-difference\" />}\n </span>\n </button>\n ) : (\n <span\n key={color}\n title={color}\n className=\"size-5 rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n />\n ),\n )}\n {schema.copyable && copied && (\n <span role=\"status\" className={cn('text-xs', !schema.copyMessage && 'sr-only')}>\n {schema.copyMessage ?? t('copied', {}, 'Copied')}\n </span>\n )}\n </div>\n )\n}\n\nfunction useCellUpdate({ recordKey, column, token, component }: CellProps) {\n const panel = usePanel()\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const update = async (state: unknown) => {\n if (!panel.endpoints.tableCell || !panel.endpoints.tableReorder) return\n\n setSaving(true)\n setError(null)\n\n try {\n await updateTableCell(\n { cell: panel.endpoints.tableCell, reorder: panel.endpoints.tableReorder },\n token,\n component,\n recordKey,\n column.name,\n state,\n )\n router.reload({ only: resolvePartialProps(['page']) })\n } catch (caught) {\n const errors = (caught as { errors?: Record<string, string[]> }).errors\n setError(errors?.state?.[0] ?? (caught as Error).message)\n } finally {\n setSaving(false)\n }\n }\n\n return { update, saving, error }\n}\n\nfunction BooleanCell(props: CellProps) {\n const { column, cell } = props\n const { update, saving } = useCellUpdate(props)\n const [checked, setChecked] = useState(Boolean(cell.state))\n const disabled = Boolean(cell.disabled) || saving\n const toggle = column as ToggleColumnSchema\n\n const onChange = (next: boolean) => {\n setChecked(next)\n void update(next)\n }\n\n if (column.type === 'CheckboxColumn') {\n return (\n <Checkbox\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={(value) => onChange(value === true)}\n onClick={(event) => event.stopPropagation()}\n />\n )\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\" onClick={(event) => event.stopPropagation()}>\n <Switch\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={onChange}\n className={cn(\n toggle.onColor && colorClass(switchOnColorClasses, toggle.onColor),\n toggle.offColor && colorClass(switchOffColorClasses, toggle.offColor),\n )}\n />\n {(checked ? toggle.onIcon : toggle.offIcon) && (\n <Icon\n name={checked ? toggle.onIcon : toggle.offIcon}\n className={cn(\n colorClass(textColorClasses, checked ? toggle.onColor : toggle.offColor, 'gray'),\n )}\n />\n )}\n </span>\n )\n}\n\nfunction flatten(options: OptionOrGroup[]) {\n return options.flatMap((option) => (isOptionGroup(option) ? option.options : [option]))\n}\n\nfunction SelectCell(props: CellProps) {\n const schema = props.column as SelectColumnSchema\n\n return schema.native === false ? (\n <SelectComboboxCell {...props} />\n ) : (\n <NativeSelectCell {...props} />\n )\n}\n\n/**\n * An option label: sanitised HTML under `allowOptionsHtml()`, text otherwise. Long labels\n * wrap unless `wrapOptionLabels(false)` truncates them.\n */\nfunction SelectOptionLabel({\n label,\n html,\n truncate,\n}: {\n label: string\n html?: boolean\n truncate?: boolean\n}) {\n const className = truncate ? 'min-w-0 truncate' : 'min-w-0 break-words whitespace-normal'\n\n // The server sanitises HTML labels (`Support\\Html::sanitize`).\n return html ? (\n <span className={className} dangerouslySetInnerHTML={{ __html: label }} />\n ) : (\n <span className={className}>{label}</span>\n )\n}\n\n/**\n * `SelectColumn::native(false)`: a combobox, searchable with `searchableOptions()`. Options\n * come with the table, or from the server (`optionsSearchPath`) as the user types.\n */\nfunction SelectComboboxCell(props: CellProps) {\n const { column, cell, recordKey, token, component } = props\n const schema = column as SelectColumnSchema\n const t = useT()\n const panel = usePanel()\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const [label, setLabel] = useState(cell.optionLabel)\n const [open, setOpen] = useState(false)\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(false)\n const [remote, setRemote] = useState<Option[]>([])\n const request = useRef(0)\n const isRemote = Boolean(schema.optionsSearchPath)\n const debounce = schema.optionsSearchDebounce ?? 300\n const staticOptions = flatten(schema.options)\n\n useEffect(() => {\n if (!open || !isRemote || !panel.endpoints.schemaOptions) return\n\n const url = panel.endpoints.schemaOptions\n const timer = setTimeout(() => {\n const current = ++request.current\n setLoading(true)\n\n void searchTableColumnOptions(url, token, component, schema, search)\n .then((results) => current === request.current && setRemote(results))\n .catch(() => current === request.current && setRemote([]))\n .finally(() => current === request.current && setLoading(false))\n }, debounce)\n\n return () => clearTimeout(timer)\n }, [open, search, isRemote, panel.endpoints.schemaOptions, token, component, schema, debounce])\n\n const options = filterSelectColumnOptions(\n isRemote ? remote : staticOptions,\n schema,\n isRemote ? '' : search,\n recordKey,\n )\n const emptyMessage = selectColumnEmptyMessage(schema, {\n loading,\n search,\n optionCount: options.length,\n })\n const currentLabel =\n staticOptions.find((option) => option.value === value)?.label ??\n remote.find((option) => option.value === value)?.label ??\n label\n\n const choose = (next: string, nextLabel?: string) => {\n setValue(next)\n setLabel(nextLabel)\n setOpen(false)\n void update(next === '' ? null : next)\n }\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n\n if (!next) setSearch('')\n }}\n >\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n disabled={Boolean(cell.disabled) || saving}\n className={cn(\n 'h-8 min-w-32 justify-between font-normal',\n error && 'border-destructive',\n )}\n >\n {value !== '' && currentLabel !== undefined ? (\n <SelectOptionLabel label={currentLabel} html={schema.allowOptionsHtml} truncate />\n ) : (\n <span className=\"text-muted-foreground\">\n {schema.placeholder ??\n (value !== '' ? value : t('select_option', {}, 'Select an option'))}\n </span>\n )}\n {loading ? (\n <Spinner className=\"opacity-50\" />\n ) : (\n <ChevronsUpDownIcon className=\"size-4 shrink-0 opacity-50\" />\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\">\n <Command shouldFilter={false}>\n {schema.searchableOptions && (\n <CommandInput\n placeholder={\n schema.searchPrompt ?? t('form.search_placeholder', {}, 'Type to search…')\n }\n value={search}\n onValueChange={setSearch}\n />\n )}\n <CommandList>\n <CommandEmpty data-slot=\"select-column-message\">\n {emptyMessage.message ?? t(emptyMessage.key, {}, emptyMessage.fallback)}\n </CommandEmpty>\n <CommandGroup>\n {schema.selectablePlaceholder && value !== '' && (\n <CommandItem value=\"\" onSelect={() => choose('')}>\n <span className=\"text-muted-foreground\">\n {schema.placeholder ?? t('clear', {}, 'Clear')}\n </span>\n </CommandItem>\n )}\n {options.map((option) => (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[optionText(option.label)]}\n disabled={option.disabled}\n onSelect={() => choose(option.value, option.label)}\n >\n <CheckIcon\n className={cn('size-4', option.value === value ? 'opacity-100' : 'opacity-0')}\n />\n <SelectOptionLabel\n label={option.label}\n html={schema.allowOptionsHtml}\n truncate={schema.wrapOptionLabels === false}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n {error && <span className=\"text-destructive block text-xs\">{error}</span>}\n </span>\n )\n}\n\nfunction NativeSelectCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as SelectColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n\n const errorId = useId()\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <select\n value={value}\n disabled={Boolean(cell.disabled) || saving}\n onChange={(event) => {\n setValue(event.target.value)\n void update(event.target.value === '' ? null : event.target.value)\n }}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'border-input dark:bg-input/30 focus-visible:ring-ring/50 h-8 min-w-32 rounded-md border bg-transparent px-2 text-sm shadow-xs outline-none focus-visible:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {schema.selectablePlaceholder && <option value=\"\">{schema.placeholder ?? ''}</option>}\n {flatten(schema.options)\n .filter((option) => !(schema.ignoreRecord && option.value === String(props.recordKey)))\n .map((option) => (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </option>\n ))}\n </select>\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n\nfunction TextInputCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as TextInputColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const initial = cell.state === null || cell.state === undefined ? '' : String(cell.state)\n // `prefix()` / `suffix()`: text affixes around the input, like the TextInput field.\n const grouped = Boolean(cell.prefix || cell.suffix)\n const errorId = useId()\n\n const field = (\n <span className={cn('relative block', grouped && 'min-w-0 flex-1')}>\n {schema.prefixIcon && (\n <span\n data-slot=\"input-prefix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute start-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.prefixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.prefixIcon} className=\"size-4\" />\n </span>\n )}\n <Input\n type={schema.inputType}\n value={value}\n placeholder={schema.placeholder}\n step={schema.step}\n inputMode={schema.inputMode as React.HTMLAttributes<HTMLInputElement>['inputMode']}\n disabled={Boolean(cell.disabled) || saving}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'h-8 min-w-32',\n schema.prefixIcon && 'ps-8',\n schema.suffixIcon && 'pe-8',\n grouped &&\n 'h-full rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',\n )}\n onChange={(event) => setValue(event.target.value)}\n onBlur={() => value !== initial && void update(value)}\n onKeyDown={(event) => event.key === 'Enter' && (event.target as HTMLInputElement).blur()}\n />\n {schema.suffixIcon && (\n <span\n data-slot=\"input-suffix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute end-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.suffixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.suffixIcon} className=\"size-4\" />\n </span>\n )}\n </span>\n )\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n {grouped ? (\n <span\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-ring/50 flex h-8 min-w-32 items-stretch overflow-hidden rounded-md border shadow-xs has-[input:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {cell.prefix && (\n <span\n data-slot=\"input-prefix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-e px-2 text-sm\"\n >\n {cell.prefix}\n </span>\n )}\n {field}\n {cell.suffix && (\n <span\n data-slot=\"input-suffix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-s px-2 text-sm\"\n >\n {cell.suffix}\n </span>\n )}\n </span>\n ) : (\n field\n )}\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cells.js","names":[],"sources":["../../../src/components/table/cells.tsx"],"sourcesContent":["import type {\n CellSchema,\n ColorColumnSchema,\n ColumnSchema,\n IconColumnSchema,\n Option,\n OptionOrGroup,\n RecordKey,\n SelectColumnSchema,\n TextInputColumnSchema,\n ToggleColumnSchema,\n ViewColumnSchema,\n} from '@alfakit/core'\nimport {\n columnRegistryKey,\n filterSelectColumnOptions,\n isOptionGroup,\n optionText,\n remainingTextSizeClass,\n resolvePartialProps,\n searchTableColumnOptions,\n selectColumnEmptyMessage,\n stackedImageStyle,\n updateTableCell,\n usesDefaultImageStack,\n} from '@alfakit/core'\nimport { router } from '@inertiajs/react'\nimport { CheckIcon, ChevronsUpDownIcon } from 'lucide-react'\nimport { createElement, useEffect, useId, useRef, useState } from 'react'\nimport { usePanel, useRegistry, useT } from '../../context'\nimport { extraProps } from '../../lib/attributes'\nimport {\n colorClass,\n iconSizeClasses,\n switchOffColorClasses,\n switchOnColorClasses,\n textColorClasses,\n} from '../../lib/colors'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport { FormattedText } from '../entries/text-entry'\nimport { Button } from '../ui/button'\nimport { Checkbox } from '../ui/checkbox'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '../ui/command'\nimport { Input } from '../ui/input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'\nimport { Spinner } from '../ui/spinner'\nimport { Switch } from '../ui/switch'\n\nexport interface CellProps {\n column: ColumnSchema\n cell: CellSchema\n recordKey: RecordKey\n token: string\n component: string\n /**\n * Set when this renderer was picked from the registry (`column:<type>`): it then renders\n * the built-in cell instead of looking itself up again, so an ejected `TableCellContent`\n * registered for a column type doesn't render itself forever.\n */\n fromRegistry?: boolean\n}\n\nexport function TableCellContent(props: CellProps) {\n const { column } = props\n const registry = useRegistry()\n // A component registered as `column:<type>` replaces the built-in cell renderer.\n const Custom = props.fromRegistry ? undefined : registry.resolve(columnRegistryKey(column))\n\n if (Custom) {\n return createElement(Custom, { ...props, fromRegistry: true })\n }\n\n switch (column.type) {\n case 'IconColumn':\n return <IconCell {...props} />\n case 'ImageColumn':\n return <ImageCell {...props} />\n case 'ColorColumn':\n return <ColorCell {...props} />\n case 'ToggleColumn':\n case 'CheckboxColumn':\n return <BooleanCell {...props} />\n case 'SelectColumn':\n return <SelectCell {...props} />\n case 'TextInputColumn':\n return <TextInputCell {...props} />\n case 'ViewColumn':\n return <ViewCell {...props} />\n default:\n return <TextCell {...props} />\n }\n}\n\n/** `IconColumn`: one icon, or one per item of a list state (`wrap()` lets them wrap). */\nfunction IconCell({ column, cell }: CellProps) {\n const icons = cell.icons ?? (cell.icon ? [{ icon: cell.icon, color: cell.color }] : [])\n const sizeClass = colorClass(iconSizeClasses, cell.size, 'md')\n\n if (icons.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n if (!cell.icons) {\n return (\n <Icon\n name={icons[0]!.icon}\n className={cn(sizeClass, icons[0]!.color && textColorClasses[icons[0]!.color])}\n />\n )\n }\n\n return (\n <div\n data-slot=\"icon-column-icons\"\n className={cn(\n 'flex items-center gap-1.5',\n (column as IconColumnSchema).wrap ? 'flex-wrap' : 'flex-nowrap',\n )}\n >\n {icons.map((item, index) => (\n <Icon\n key={index}\n name={item.icon}\n className={cn(sizeClass, item.color && textColorClasses[item.color])}\n />\n ))}\n </div>\n )\n}\n\n/** `ViewColumn`: the application component registered under the column's `view()` name. */\nfunction ViewCell(props: CellProps) {\n const t = useT()\n const name = (props.column as ViewColumnSchema).component ?? ''\n const Custom = useRegistry().resolve(name)\n\n if (!name || !Custom) {\n return (\n <span className=\"text-destructive text-xs\">\n {t('component_not_registered', { component: name }, `Component ${name} is not registered.`)}\n </span>\n )\n }\n\n return createElement(Custom, { ...(props.cell.props ?? {}), state: props.cell.state, ...props })\n}\n\nfunction TextCell({ column, cell }: CellProps) {\n const text = (\n <FormattedText\n value={cell.state}\n schema={{\n ...(column as object),\n color: cell.color,\n icon: cell.icon,\n iconPosition: cell.iconPosition,\n iconColor: cell.iconColor,\n itemColors: cell.itemColors,\n itemIcons: cell.itemIcons,\n itemUrls: cell.itemUrls,\n }}\n />\n )\n const description = cell.description ? (\n <span className=\"text-muted-foreground block text-xs\">{cell.description}</span>\n ) : null\n const position =\n (column as { descriptionPosition?: 'above' | 'below' }).descriptionPosition ?? 'below'\n\n return (\n <div className=\"flex flex-col gap-0.5\">\n {position === 'above' && description}\n {text}\n {position === 'below' && description}\n </div>\n )\n}\n\nfunction ImageCell({ column, cell }: CellProps) {\n const urls = Array.isArray(cell.state) ? (cell.state as string[]) : []\n const schema = column as {\n circular?: boolean\n square?: boolean\n size?: number | string\n height?: number | string\n width?: string\n stacked?: boolean\n limit?: number\n limitedRemainingText?: boolean\n limitedRemainingTextSize?: string\n wrap?: boolean\n ring?: number\n overlap?: number\n }\n const limit = schema.limit ?? urls.length\n const size = schema.size ?? 40\n\n if (urls.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n return (\n <div\n className={cn(\n 'flex items-center',\n schema.wrap && 'flex-wrap',\n schema.stacked ? usesDefaultImageStack(schema) && '-space-x-2' : 'gap-1.5',\n schema.wrap && schema.stacked && 'gap-y-1.5',\n )}\n >\n {urls.slice(0, limit).map((url, index) => (\n <img\n key={index}\n src={url}\n // Without `alt()` the first image is named after the column, so a record link that\n // wraps it has a name (W-V4-20).\n alt={cell.alt ?? (index === 0 ? (column.label ?? '') : '')}\n style={{\n height: schema.height ?? size,\n width: schema.width ?? (schema.square || schema.circular ? size : undefined),\n ...stackedImageStyle(index, schema),\n }}\n {...extraProps(\n cell.extraImgAttributes,\n cn(\n 'object-cover',\n schema.circular ? 'rounded-full' : 'rounded-md',\n schema.stacked && usesDefaultImageStack(schema) && 'ring-background ring-2',\n ),\n )}\n />\n ))}\n {schema.limitedRemainingText && urls.length > limit && (\n <span\n data-slot=\"image-remaining\"\n className={cn(\n 'text-muted-foreground ms-1',\n remainingTextSizeClass(schema.limitedRemainingTextSize),\n )}\n >\n +{urls.length - limit}\n </span>\n )}\n </div>\n )\n}\n\nfunction ColorCell({ column, cell }: CellProps) {\n const t = useT()\n const schema = column as ColorColumnSchema\n const [copied, setCopied] = useState<string | null>(null)\n const colors = Array.isArray(cell.state)\n ? (cell.state as string[])\n : cell.state\n ? [String(cell.state)]\n : []\n\n if (colors.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>\n }\n\n const copy = (color: string) => {\n void navigator.clipboard?.writeText(color).then(() => {\n setCopied(color)\n setTimeout(() => setCopied(null), schema.copyMessageDuration ?? 1500)\n })\n }\n\n return (\n <div className={cn('flex items-center gap-1.5', schema.wrap ? 'flex-wrap' : 'flex-nowrap')}>\n {colors.map((color) =>\n schema.copyable ? (\n <button\n key={color}\n type=\"button\"\n data-slot=\"color-copy\"\n title={color}\n aria-label={`${t('copy', {}, 'Copy')} ${color}`}\n className=\"focus-visible:ring-ring/50 inline-flex rounded outline-none focus-visible:ring-[3px]\"\n onClick={(event) => {\n // The cell may sit inside a link or a clickable row.\n event.preventDefault()\n event.stopPropagation()\n copy(color)\n }}\n >\n <span\n className=\"inline-flex size-5 items-center justify-center rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n >\n {copied === color && <CheckIcon className=\"size-3 text-white mix-blend-difference\" />}\n </span>\n </button>\n ) : (\n <span\n key={color}\n title={color}\n className=\"size-5 rounded border shadow-xs\"\n style={{ backgroundColor: color }}\n />\n ),\n )}\n {schema.copyable && copied && (\n <span role=\"status\" className={cn('text-xs', !schema.copyMessage && 'sr-only')}>\n {schema.copyMessage ?? t('copied', {}, 'Copied')}\n </span>\n )}\n </div>\n )\n}\n\nfunction useCellUpdate({ recordKey, column, token, component }: CellProps) {\n const panel = usePanel()\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const update = async (state: unknown) => {\n if (!panel.endpoints.tableCell || !panel.endpoints.tableReorder) return\n\n setSaving(true)\n setError(null)\n\n try {\n await updateTableCell(\n { cell: panel.endpoints.tableCell, reorder: panel.endpoints.tableReorder },\n token,\n component,\n recordKey,\n column.name,\n state,\n )\n router.reload({ only: resolvePartialProps(['page']) })\n } catch (caught) {\n const errors = (caught as { errors?: Record<string, string[]> }).errors\n setError(errors?.state?.[0] ?? (caught as Error).message)\n } finally {\n setSaving(false)\n }\n }\n\n return { update, saving, error }\n}\n\nfunction BooleanCell(props: CellProps) {\n const { column, cell } = props\n const { update, saving } = useCellUpdate(props)\n const [checked, setChecked] = useState(Boolean(cell.state))\n const disabled = Boolean(cell.disabled) || saving\n const toggle = column as ToggleColumnSchema\n\n const onChange = (next: boolean) => {\n setChecked(next)\n void update(next)\n }\n\n if (column.type === 'CheckboxColumn') {\n return (\n <Checkbox\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={(value) => onChange(value === true)}\n onClick={(event) => event.stopPropagation()}\n />\n )\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\" onClick={(event) => event.stopPropagation()}>\n <Switch\n checked={checked}\n disabled={disabled}\n aria-label={column.label || column.name}\n onCheckedChange={onChange}\n className={cn(\n toggle.onColor && colorClass(switchOnColorClasses, toggle.onColor),\n toggle.offColor && colorClass(switchOffColorClasses, toggle.offColor),\n )}\n />\n {(checked ? toggle.onIcon : toggle.offIcon) && (\n <Icon\n name={checked ? toggle.onIcon : toggle.offIcon}\n className={cn(\n colorClass(textColorClasses, checked ? toggle.onColor : toggle.offColor, 'gray'),\n )}\n />\n )}\n </span>\n )\n}\n\nfunction flatten(options: OptionOrGroup[]) {\n return options.flatMap((option) => (isOptionGroup(option) ? option.options : [option]))\n}\n\nfunction SelectCell(props: CellProps) {\n const schema = props.column as SelectColumnSchema\n\n return schema.native === false ? (\n <SelectComboboxCell {...props} />\n ) : (\n <NativeSelectCell {...props} />\n )\n}\n\n/**\n * An option label: sanitised HTML under `allowOptionsHtml()`, text otherwise. Long labels\n * wrap unless `wrapOptionLabels(false)` truncates them.\n */\nfunction SelectOptionLabel({\n label,\n html,\n truncate,\n}: {\n label: string\n html?: boolean\n truncate?: boolean\n}) {\n const className = truncate ? 'min-w-0 truncate' : 'min-w-0 break-words whitespace-normal'\n\n // The server sanitises HTML labels (`Support\\Html::sanitize`).\n return html ? (\n <span className={className} dangerouslySetInnerHTML={{ __html: label }} />\n ) : (\n <span className={className}>{label}</span>\n )\n}\n\n/**\n * `SelectColumn::native(false)`: a combobox, searchable with `searchableOptions()`. Options\n * come with the table, or from the server (`optionsSearchPath`) as the user types.\n */\nfunction SelectComboboxCell(props: CellProps) {\n const { column, cell, recordKey, token, component } = props\n const schema = column as SelectColumnSchema\n const t = useT()\n const panel = usePanel()\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const [label, setLabel] = useState(cell.optionLabel)\n const [open, setOpen] = useState(false)\n const [search, setSearch] = useState('')\n const [loading, setLoading] = useState(false)\n const [remote, setRemote] = useState<Option[]>([])\n const request = useRef(0)\n const isRemote = Boolean(schema.optionsSearchPath)\n const debounce = schema.optionsSearchDebounce ?? 300\n const staticOptions = flatten(schema.options)\n\n useEffect(() => {\n if (!open || !isRemote || !panel.endpoints.schemaOptions) return\n\n const url = panel.endpoints.schemaOptions\n const timer = setTimeout(() => {\n const current = ++request.current\n setLoading(true)\n\n void searchTableColumnOptions(url, token, component, schema, search)\n .then((results) => current === request.current && setRemote(results))\n .catch(() => current === request.current && setRemote([]))\n .finally(() => current === request.current && setLoading(false))\n }, debounce)\n\n return () => clearTimeout(timer)\n }, [open, search, isRemote, panel.endpoints.schemaOptions, token, component, schema, debounce])\n\n const options = filterSelectColumnOptions(\n isRemote ? remote : staticOptions,\n schema,\n isRemote ? '' : search,\n recordKey,\n )\n const emptyMessage = selectColumnEmptyMessage(schema, {\n loading,\n search,\n optionCount: options.length,\n })\n const currentLabel =\n staticOptions.find((option) => option.value === value)?.label ??\n remote.find((option) => option.value === value)?.label ??\n label\n\n const choose = (next: string, nextLabel?: string) => {\n setValue(next)\n setLabel(nextLabel)\n setOpen(false)\n void update(next === '' ? null : next)\n }\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n\n if (!next) setSearch('')\n }}\n >\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n disabled={Boolean(cell.disabled) || saving}\n className={cn(\n 'h-8 min-w-32 justify-between font-normal',\n error && 'border-destructive',\n )}\n >\n {value !== '' && currentLabel !== undefined ? (\n <SelectOptionLabel label={currentLabel} html={schema.allowOptionsHtml} truncate />\n ) : (\n <span className=\"text-muted-foreground\">\n {schema.placeholder ??\n (value !== '' ? value : t('select_option', {}, 'Select an option'))}\n </span>\n )}\n {loading ? (\n <Spinner className=\"opacity-50\" />\n ) : (\n <ChevronsUpDownIcon className=\"size-4 shrink-0 opacity-50\" />\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-64 p-0\" align=\"start\">\n <Command shouldFilter={false}>\n {schema.searchableOptions && (\n <CommandInput\n placeholder={\n schema.searchPrompt ?? t('form.search_placeholder', {}, 'Type to search…')\n }\n value={search}\n onValueChange={setSearch}\n />\n )}\n <CommandList>\n <CommandEmpty data-slot=\"select-column-message\">\n {emptyMessage.message ?? t(emptyMessage.key, {}, emptyMessage.fallback)}\n </CommandEmpty>\n <CommandGroup>\n {schema.selectablePlaceholder && value !== '' && (\n <CommandItem value=\"\" onSelect={() => choose('')}>\n <span className=\"text-muted-foreground\">\n {schema.placeholder ?? t('clear', {}, 'Clear')}\n </span>\n </CommandItem>\n )}\n {options.map((option) => (\n <CommandItem\n key={option.value}\n value={option.value}\n keywords={[optionText(option.label)]}\n disabled={option.disabled}\n onSelect={() => choose(option.value, option.label)}\n >\n <CheckIcon\n className={cn('size-4', option.value === value ? 'opacity-100' : 'opacity-0')}\n />\n <SelectOptionLabel\n label={option.label}\n html={schema.allowOptionsHtml}\n truncate={schema.wrapOptionLabels === false}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n {error && <span className=\"text-destructive block text-xs\">{error}</span>}\n </span>\n )\n}\n\nfunction NativeSelectCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as SelectColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n\n const errorId = useId()\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n <select\n value={value}\n disabled={Boolean(cell.disabled) || saving}\n onChange={(event) => {\n setValue(event.target.value)\n void update(event.target.value === '' ? null : event.target.value)\n }}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'border-input dark:bg-input/30 focus-visible:ring-ring/50 h-8 min-w-32 rounded-md border bg-transparent px-2 text-sm shadow-xs outline-none focus-visible:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {schema.selectablePlaceholder && <option value=\"\">{schema.placeholder ?? ''}</option>}\n {flatten(schema.options)\n .filter((option) => !(schema.ignoreRecord && option.value === String(props.recordKey)))\n .map((option) => (\n <option key={option.value} value={option.value} disabled={option.disabled}>\n {option.label}\n </option>\n ))}\n </select>\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n\nfunction TextInputCell(props: CellProps) {\n const { column, cell } = props\n const schema = column as TextInputColumnSchema\n const { update, saving, error } = useCellUpdate(props)\n const [value, setValue] = useState(\n cell.state === null || cell.state === undefined ? '' : String(cell.state),\n )\n const initial = cell.state === null || cell.state === undefined ? '' : String(cell.state)\n // `prefix()` / `suffix()`: text affixes around the input, like the TextInput field.\n const grouped = Boolean(cell.prefix || cell.suffix)\n const errorId = useId()\n\n const field = (\n <span className={cn('relative block', grouped && 'min-w-0 flex-1')}>\n {schema.prefixIcon && (\n <span\n data-slot=\"input-prefix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute start-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.prefixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.prefixIcon} className=\"size-4\" />\n </span>\n )}\n <Input\n type={schema.inputType}\n value={value}\n placeholder={schema.placeholder}\n step={schema.step}\n inputMode={schema.inputMode as React.HTMLAttributes<HTMLInputElement>['inputMode']}\n disabled={Boolean(cell.disabled) || saving}\n aria-label={column.label || column.name}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={cn(\n 'h-8 min-w-32',\n schema.prefixIcon && 'ps-8',\n schema.suffixIcon && 'pe-8',\n grouped &&\n 'h-full rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',\n )}\n onChange={(event) => setValue(event.target.value)}\n onBlur={() => value !== initial && void update(value)}\n onKeyDown={(event) => event.key === 'Enter' && (event.target as HTMLInputElement).blur()}\n />\n {schema.suffixIcon && (\n <span\n data-slot=\"input-suffix-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute end-2.5 top-1/2 flex -translate-y-1/2',\n colorClass(textColorClasses, schema.suffixIconColor, 'gray'),\n )}\n >\n <Icon name={schema.suffixIcon} className=\"size-4\" />\n </span>\n )}\n </span>\n )\n\n return (\n <span onClick={(event) => event.stopPropagation()}>\n {grouped ? (\n <span\n data-slot=\"input-group\"\n className={cn(\n 'border-input dark:bg-input/30 has-[input:focus-visible]:border-ring has-[input:focus-visible]:ring-ring/50 flex h-8 min-w-32 items-stretch overflow-hidden rounded-md border shadow-xs has-[input:focus-visible]:ring-[3px]',\n error && 'border-destructive',\n )}\n >\n {cell.prefix && (\n <span\n data-slot=\"input-prefix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-e px-2 text-sm\"\n >\n {cell.prefix}\n </span>\n )}\n {field}\n {cell.suffix && (\n <span\n data-slot=\"input-suffix\"\n className=\"text-muted-foreground bg-muted/50 flex items-center border-s px-2 text-sm\"\n >\n {cell.suffix}\n </span>\n )}\n </span>\n ) : (\n field\n )}\n {error && (\n <span id={errorId} className=\"text-destructive block text-xs\">\n {error}\n </span>\n )}\n </span>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.d.ts","names":[],"sources":["../../../src/components/ui/calendar.tsx"],"mappings":";;;iBAMS,WACP,WACA,YACA,oBACG,SACF,sBAAsB,6BAAU,IAAA"}
1
+ {"version":3,"file":"calendar.d.ts","names":[],"sources":["../../../src/components/ui/calendar.tsx"],"mappings":";;;iBAOS,WACP,WACA,YACA,oBACG,SACF,sBAAsB,6BAAU,IAAA"}