@object-ui/components 17.6.0 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +9618 -0
  2. package/README.md +27 -3
  3. package/dist/custom/RecordTitleChip.d.ts +4 -3
  4. package/dist/custom/button-group.d.ts +1 -1
  5. package/dist/custom/combobox.d.ts +2 -4
  6. package/dist/custom/dialog-viewport-gutter.d.ts +37 -0
  7. package/dist/custom/empty-state-link.d.ts +63 -0
  8. package/dist/custom/empty.d.ts +16 -4
  9. package/dist/custom/field.d.ts +1 -1
  10. package/dist/custom/filter-builder.d.ts +225 -77
  11. package/dist/custom/grouping-editor.d.ts +4 -0
  12. package/dist/custom/horizontal-overflow.d.ts +18 -0
  13. package/dist/custom/index.d.ts +4 -1
  14. package/dist/custom/item.d.ts +1 -1
  15. package/dist/custom/kbd.d.ts +1 -1
  16. package/dist/custom/mobile-dialog-content.d.ts +22 -1
  17. package/dist/custom/navigation-overlay.d.ts +105 -0
  18. package/dist/custom/refresh-indicator.d.ts +8 -2
  19. package/dist/custom/sort-builder.d.ts +8 -0
  20. package/dist/custom/use-horizontal-overflow.d.ts +36 -0
  21. package/dist/custom/view-states.d.ts +74 -1
  22. package/dist/hooks/related-count-store.d.ts +81 -28
  23. package/dist/index.css +345 -361
  24. package/dist/index.d.ts +11 -3
  25. package/dist/index.js +8480 -6628
  26. package/dist/index.umd.cjs +11 -15
  27. package/dist/lib/close-label.d.ts +1 -2
  28. package/dist/lib/date-fns-locale.d.ts +41 -0
  29. package/dist/lib/inline-markdown.d.ts +64 -0
  30. package/dist/lib/lazy-icon.d.ts +32 -1
  31. package/dist/lib/lucide-record-icon-names.d.ts +30 -0
  32. package/dist/lib/utils.d.ts +113 -0
  33. package/dist/renderers/action/action-bar.d.ts +8 -36
  34. package/dist/renderers/action/action-button.d.ts +15 -4
  35. package/dist/renderers/action/action-group.d.ts +5 -4
  36. package/dist/renderers/action/action-icon.d.ts +12 -2
  37. package/dist/renderers/action/action-menu.d.ts +5 -2
  38. package/dist/renderers/action/auto-trigger.d.ts +19 -4
  39. package/dist/renderers/action/disabled-reason.d.ts +49 -0
  40. package/dist/renderers/action/resolve-icon.d.ts +27 -2
  41. package/dist/renderers/action/static-params.d.ts +71 -0
  42. package/dist/renderers/action/visibility-gate.d.ts +11 -3
  43. package/dist/renderers/basic/data-list.d.ts +2 -1
  44. package/dist/renderers/basic/elements.d.ts +2 -0
  45. package/dist/renderers/basic/html-elements.d.ts +7 -3
  46. package/dist/renderers/basic/readProps.d.ts +60 -0
  47. package/dist/renderers/basic/record-picker.d.ts +3 -2
  48. package/dist/renderers/complex/data-table.d.ts +31 -14
  49. package/dist/renderers/complex/dataTableBindDiagnostic.d.ts +187 -0
  50. package/dist/renderers/layout/box.d.ts +8 -0
  51. package/dist/renderers/layout/containers.d.ts +28 -23
  52. package/dist/renderers/layout/page-block-grid.d.ts +29 -0
  53. package/dist/renderers/layout/page-block-span.d.ts +50 -0
  54. package/dist/renderers/layout/page-description-context.d.ts +14 -0
  55. package/dist/renderers/layout/page-print.d.ts +14 -0
  56. package/dist/renderers/layout/page-region-posture.d.ts +82 -0
  57. package/dist/renderers/layout/react-page.d.ts +4 -0
  58. package/dist/renderers/navigation/sidebar.d.ts +31 -0
  59. package/dist/ui/badge.d.ts +1 -1
  60. package/dist/ui/button.d.ts +1 -1
  61. package/dist/ui/calendar.d.ts +2 -1
  62. package/dist/ui/command.d.ts +7 -7
  63. package/dist/ui/index.d.ts +0 -1
  64. package/dist/ui/input-otp.d.ts +2 -2
  65. package/dist/ui/sheet.d.ts +1 -1
  66. package/dist/ui/sidebar.d.ts +2 -1
  67. package/package.json +14 -15
  68. package/dist/SchemaRenderer.d.ts +0 -4
  69. package/dist/custom/export-progress-dialog.d.ts +0 -43
  70. package/dist/hooks/use-export-job.d.ts +0 -34
  71. package/dist/ui/chart.d.ts +0 -56
  72. package/dist/ui/toast.d.ts +0 -22
package/README.md CHANGED
@@ -86,15 +86,16 @@ tree-shake that import away.
86
86
  ```tsx
87
87
  import { SchemaRenderer } from '@object-ui/react'
88
88
  import { initializeComponents } from '@object-ui/components'
89
+ import type { DeclaredNode } from '@object-ui/types'
89
90
 
90
91
  initializeComponents()
91
92
 
92
- const schema = {
93
+ const schema: DeclaredNode = {
93
94
  type: 'card',
94
95
  title: 'Welcome',
95
- body: {
96
+ children: {
96
97
  type: 'text',
97
- value: 'Hello from Object UI!'
98
+ content: 'Hello from Object UI!'
98
99
  }
99
100
  }
100
101
 
@@ -139,6 +140,28 @@ function MyComponent() {
139
140
  - `tabs` - Tab navigation
140
141
  - `accordion` - Collapsible sections
141
142
 
143
+ #### Page region posture — `usePageRegionPosture()`
144
+
145
+ The page renderer measures each region of a page against the page body, using
146
+ `ResizeObserver` on the region, not the viewport, and tells the region's blocks
147
+ how much room they have:
148
+
149
+ ```ts
150
+ import { usePageRegionPosture, type PageRegionPosture } from '@object-ui/components';
151
+
152
+ const posture: PageRegionPosture | null = usePageRegionPosture(); // 'compact' | 'full' | null
153
+ ```
154
+
155
+ - `'compact'`: the region is narrower than `(page − 24) / 2`, that is, half
156
+ the page less the 24 px gap between regions side by side. A half-and-half
157
+ cell therefore stays `'full'`.
158
+ - `'full'`: the region is half the page or wider.
159
+ - `null`: outside a page region, or before the width is known (server render,
160
+ no `ResizeObserver`). Read `null` as `'full'`.
161
+
162
+ The posture is measured, never authored, and no schema key sets it. The
163
+ `list-view` block in `@object-ui/plugin-list` reads it to draw a compact list.
164
+
142
165
  ### Data Display
143
166
  - `table` - Data table
144
167
  - `list` - List view
@@ -175,6 +198,7 @@ them draw the notification's `severity` icon unless it declares an `icon`
175
198
  override naming a real Lucide icon. See the
176
199
  [notifications guide](https://objectui.org/docs/guide/notifications).
177
200
 
201
+ <!-- doc-snippet: fragment — router-layout excerpt: `Outlet` is react-router's, supplied by the host application -->
178
202
  ```tsx
179
203
  import { NotificationBanners, NotificationAlerts } from '@object-ui/components';
180
204
 
@@ -8,13 +8,14 @@ export interface RecordTitleChipProps {
8
8
  objectLabel?: string;
9
9
  /** Record identifier shown next to the object label with a copy button. */
10
10
  resourceId?: string;
11
- /** Hide the favourite star (default: shown). */
12
- showStar?: boolean;
13
11
  /** Hide the copy-id button (default: shown when `resourceId` is given). */
14
12
  showCopyId?: boolean;
15
13
  /** Controlled favourite state. When omitted, the chip manages its own. */
16
14
  isFavorite?: boolean;
17
- /** Called when the favourite star is toggled. */
15
+ /**
16
+ * Called when the favourite star is toggled. The star draws exactly when
17
+ * this is given: a star with nothing to call would store nothing.
18
+ */
18
19
  onToggleFavorite?: (next: boolean) => void;
19
20
  /** Extra classes for the outer flex column. */
20
21
  className?: string;
@@ -1,7 +1,7 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  import { Separator } from '../ui/separator.js';
3
3
  declare const buttonGroupVariants: (props?: ({
4
- orientation?: "horizontal" | "vertical" | null | undefined;
4
+ orientation?: "vertical" | "horizontal" | null | undefined;
5
5
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
6
6
  declare function ButtonGroup({ className, orientation, ...props }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>): import("react").JSX.Element;
7
7
  declare function ButtonGroupText({ className, asChild, ...props }: React.ComponentProps<"div"> & {
@@ -1,3 +1,4 @@
1
+ import { ComboboxOption } from '@object-ui/types/form';
1
2
  /**
2
3
  * ObjectUI
3
4
  * Copyright (c) 2024-present ObjectStack Inc.
@@ -6,10 +7,7 @@
6
7
  * LICENSE file in the root directory of this source tree.
7
8
  */
8
9
  import * as React from "react";
9
- export interface ComboboxOption {
10
- value: string;
11
- label: string;
12
- }
10
+ export type { ComboboxOption } from '@object-ui/types/form';
13
11
  /**
14
12
  * Beyond its own named props, the combobox accepts standard button attributes
15
13
  * (`id`, `aria-*`, `data-*`, handlers, …) and forwards them to the trigger —
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * The ONE viewport gutter every wide centred dialog reads from `sm` up
10
+ * (objectui#12593, promoted to a shared export by objectui#12603).
11
+ *
12
+ * The `DialogContent` primitive draws `w-full max-w-lg`. A consumer that raises
13
+ * the cap with `sm:max-w-2xl` or wider makes the dialog exactly as wide as any
14
+ * window narrower than that cap, at x = 0, edge to edge. With this class the
15
+ * dialog is the smaller of its max width and the window less 2rem, and the
16
+ * primitive's `left-[50%]` plus `translate-x-[-50%]` centres it with an equal
17
+ * 1rem either side. Above the max width plus 2rem the dialog is exactly as wide
18
+ * as before.
19
+ *
20
+ * `100%`, not `100vw`: the dialog is `fixed`, so `100%` is its containing
21
+ * block, the viewport less any classic scrollbar, the same box `left-[50%]`
22
+ * centres in. `100vw` counts the scrollbar, so each gutter would lose half of
23
+ * the scrollbar's width.
24
+ *
25
+ * `sm:` only: below `sm` a dialog is the phone sheet, which this leaves alone.
26
+ * A dialog that keeps its own viewport-relative cap (`sm:max-w-[95vw]
27
+ * sm:w-full`, the `full` size) does not read it.
28
+ *
29
+ * The class string is literal here so Tailwind's source scan emits it; an app
30
+ * that `@source`-scans this package gets the rule. A site writes its wide cap
31
+ * and this constant together (`` `sm:max-w-5xl ${DIALOG_VIEWPORT_GUTTER}` ``,
32
+ * or the constant as an unconditional `cn()` argument), never a gutter literal
33
+ * of its own. The census
34
+ * `packages/components/src/__tests__/dialogViewportGutterCensus-12603.test.ts`
35
+ * enumerates every wide `DialogContent` and fails one that does not.
36
+ */
37
+ export declare const DIALOG_VIEWPORT_GUTTER = "sm:w-[calc(100%-2rem)]";
@@ -0,0 +1,63 @@
1
+ import { EmptyState } from '@objectstack/spec/ui';
2
+ /**
3
+ * ObjectUI
4
+ * Copyright (c) 2024-present ObjectStack Inc.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ /**
10
+ * The one link an empty state names (objectui#12270).
11
+ *
12
+ * `@objectstack/spec`'s `EmptyStateSchema` declares an optional `link`,
13
+ * `{ label, url }`: the one next step an empty list names, such as the how-to
14
+ * page that explains what belongs here. The shape is taken by reference, so the
15
+ * link reaches every empty state that shape reaches, and each of them draws it
16
+ * through this component, ⛔ never a copy of its own:
17
+ *
18
+ * - a list view's `emptyState`, drawn by `@object-ui/plugin-list`'s `ListView`;
19
+ * - a list page's own `interfaceConfig.emptyState`, which that page hands the
20
+ * same `ListView`;
21
+ * - the `object-grid` block's `emptyState`, drawn by `@object-ui/plugin-grid`'s
22
+ * `ObjectGrid`.
23
+ *
24
+ * ## The click is the action runner's
25
+ *
26
+ * The link is followed as a `type: 'url'` action through the ActionRunner, so
27
+ * what a click may open is the runner's `classifyNavigationTarget` answer, the
28
+ * one answer every navigator in the app asks (ruling A+ on objectui#12191).
29
+ * ⛔ No scheme test lives here. An in-app path goes through the host's router,
30
+ * in place. An `http(s)://` address opens as the runner opens any external
31
+ * target. `mailto:` opens the mail client in place. Any other value is refused
32
+ * by the runner at the click, which reports its refusal (an error toast under
33
+ * the console's provider) and navigates nowhere. The spec judges the url at
34
+ * parse, except a template that opens with `${…}`, which it says is judged when
35
+ * it is clicked, after interpolation: the runner's click is that judgement, so
36
+ * nothing is judged here at render.
37
+ *
38
+ * Following a link is not feedback-worthy, so it raises no success toast, as
39
+ * the html tier's anchor and the dashboard's header link raise none.
40
+ *
41
+ * ## Without an ActionProvider
42
+ *
43
+ * `useAction()` then hands over a local runner with no navigation or toast
44
+ * handler. That runner hands an admitted in-app path back as `redirect`
45
+ * instead of navigating, and reports a refusal to nobody, so this component
46
+ * follows the redirect with a page navigation and logs the refusal.
47
+ */
48
+ import * as React from 'react';
49
+ /** The spec's empty-state link, `{ label, url }` (`EmptyStateSchema.link`). */
50
+ export type EmptyStateLinkSpec = NonNullable<EmptyState['link']>;
51
+ export interface EmptyStateLinkProps {
52
+ /** The authored `emptyState.link`. Absent, nothing is drawn. */
53
+ link?: EmptyStateLinkSpec;
54
+ /**
55
+ * The locale the `label` is resolved against when it is an inline locale
56
+ * map: the one the caller resolves the empty state's `title` and `message`
57
+ * against. A label that resolves to no text draws nothing.
58
+ */
59
+ displayLocale: string;
60
+ className?: string;
61
+ 'data-testid'?: string;
62
+ }
63
+ export declare function EmptyStateLink({ link, displayLocale, className, 'data-testid': testId, }: EmptyStateLinkProps): React.JSX.Element | null;
@@ -6,15 +6,27 @@ declare const emptyMediaVariants: (props?: ({
6
6
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
7
  declare function EmptyMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>): import("react").JSX.Element;
8
8
  declare function EmptyTitle({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
9
- declare function EmptyDescription({ className, ...props }: React.ComponentProps<"p">): import("react").JSX.Element;
9
+ declare function EmptyDescription({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
10
10
  declare function EmptyContent({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
11
11
  /**
12
12
  * EmptyValue — universal inline placeholder for missing cell/field values.
13
13
  *
14
14
  * Use this anywhere a renderer would otherwise show "-" or "—" for a null,
15
- * undefined or empty value. It renders a muted, non-interactive en-dash that
16
- * does not inherit link/button colors from surrounding ancestors, so a missing
17
- * value never looks clickable.
15
+ * undefined or empty value. It renders a muted, non-interactive EM-dash (the
16
+ * `glyph` default below is U+2014, and every call site depends on that width)
17
+ * that does not inherit link/button colors from surrounding ancestors, so a
18
+ * missing value never looks clickable. This sentence said "en-dash" until
19
+ * objectui#8506: the word was wrong, never the code — do not "fix" the glyph
20
+ * to match a stale docblock.
21
+ *
22
+ * ⚠️ A caller that passes a `title` through `...props` must also pass
23
+ * `pointer-events-auto` in `className`. `pointer-events-none` below stops this
24
+ * span being a hit target, so a `title` on it never renders a tooltip — the
25
+ * hover falls through to whichever ancestor has one. The attribute stays in the
26
+ * DOM either way, which is exactly why nothing catches it: a test that reads
27
+ * `getAttribute('title')` is green over a tooltip that can never appear
28
+ * (objectui#8506, where `DetailSection` kept such a `title` and two landed pins
29
+ * navigate by it).
18
30
  */
19
31
  declare function EmptyValue({ className, glyph, ...props }: React.ComponentProps<"span"> & {
20
32
  glyph?: string;
@@ -25,7 +25,7 @@ export interface FieldProps extends React.HTMLAttributes<HTMLDivElement>, Varian
25
25
  * A labelled form-control wrapper: label, slotted control, description, error.
26
26
  *
27
27
  * Named `FieldContainer`, not `Field` (objectstack#4115): `@objectstack/spec/data`
28
- * exports `Field` — an object FIELD's metadata (type, reference_to, options,
28
+ * exports `Field` — an object FIELD's metadata (type, reference, options,
29
29
  * permissions, …) and its builder namespace — which has nothing to do with this
30
30
  * `<div>`. Two unrelated things under one name is the defect that issue exists
31
31
  * to remove; `@object-ui/app-shell` already renamed the same kind of collision