@factorialco/f0-react 6.22.0 → 6.23.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.
@@ -128,6 +128,9 @@ import { WithDataTestIdReturnType as WithDataTestIdReturnType_2 } from './experi
128
128
  import { WithDataTestIdReturnType as WithDataTestIdReturnType_3 } from './experimental';
129
129
  import { WithDataTestIdReturnType as WithDataTestIdReturnType_4 } from './experimental';
130
130
  import { WithDataTestIdReturnType as WithDataTestIdReturnType_5 } from './experimental';
131
+ import { z } from 'zod';
132
+ import { ZodEffects } from 'zod';
133
+ import { ZodRawShape } from 'zod';
131
134
 
132
135
  declare type Action = {
133
136
  label: string;
@@ -4714,6 +4717,21 @@ declare const defaultTranslations: {
4714
4717
  readonly submit: "Submit";
4715
4718
  readonly stepOf: "Step {{current}} of {{total}}";
4716
4719
  };
4720
+ readonly widgets: {
4721
+ /** Turns a widget over to read what it is telling you (Home's `info`). */
4722
+ readonly whatThisMeans: "What this info means?";
4723
+ /** The button on that other side, which turns it back. */
4724
+ readonly gotIt: "Got it";
4725
+ /** The widget menu's own items, and the dialogs they open. */
4726
+ readonly editParams: "Edit params";
4727
+ readonly editParamsTitle: "Edit widget params";
4728
+ readonly removeWidget: "Remove widget";
4729
+ readonly addWidget: "Add widget";
4730
+ /** Heads the widgets a Home suggests, at the top of the picker. */
4731
+ readonly recommended: "Recommended";
4732
+ /** Why a drop onto a pinned widget was refused. `{{title}}` is its name. */
4733
+ readonly cannotMoveHere: "You can't move a widget here — {{title}} is locked.";
4734
+ };
4717
4735
  readonly pdfViewer: {
4718
4736
  readonly toolbar: "Document toolbar";
4719
4737
  readonly previousPage: "Previous page";
@@ -6592,6 +6610,11 @@ declare type F0FormEditableTableRowAction<R extends RecordType> = {
6592
6610
  onClick: (item: R, index: number) => void | Promise<void>;
6593
6611
  };
6594
6612
 
6613
+ /**
6614
+ * Type for F0Form schemas - can be a plain ZodObject or a refined ZodObject (ZodEffects)
6615
+ */
6616
+ declare type F0FormSchema<T extends ZodRawShape = ZodRawShape> = z.ZodObject<T> | ZodEffects<z.ZodObject<T>>;
6617
+
6595
6618
  /**
6596
6619
  * A tag rendered in a node's metadata row. Its visual is driven by the
6597
6620
  * `TagVariant` `type`; its column identity — which toggle/label/default-
@@ -7665,6 +7688,29 @@ declare interface FrameContextType {
7665
7688
  setForceFloat: (force: boolean) => void;
7666
7689
  }
7667
7690
 
7691
+ /**
7692
+ * A params-driven value, TYPED against the widget's own schema — how to write a
7693
+ * `title` or an `info` that reads its params without casting at every access:
7694
+ *
7695
+ * ```tsx
7696
+ * title: fromParams(HOURS_PARAMS, (p) => `Hours · ${p.period ?? "this week"}`)
7697
+ * ```
7698
+ *
7699
+ * The params arrive `Partial`, and that is not a formality: a widget exists
7700
+ * before it is configured (the moment it is added, or while its dialog is open
7701
+ * on an incomplete form), so every field has to be treated as possibly unset.
7702
+ * The schema argument is there only to carry the type.
7703
+ */
7704
+ export declare const fromParams: <S extends WidgetParamsSchema, T>(_schema: S, compute: (params: Partial<z.infer<S>>) => T) => (params: WidgetParams) => T;
7705
+
7706
+ /**
7707
+ * A widget property that may be COMPUTED FROM ITS PARAMS instead of fixed — the
7708
+ * title that says which team it is showing, the info that explains the period
7709
+ * you picked. It gets the params the widget has now (`{}` when it has none), so
7710
+ * the same function serves a widget before and after it is configured.
7711
+ */
7712
+ export declare type FromWidgetParams<T> = T | ((params: WidgetParams) => T);
7713
+
7668
7714
  declare interface GaugeComputation {
7669
7715
  datasetId: string;
7670
7716
  aggregation: AggregationType;
@@ -8178,10 +8224,47 @@ export declare type HomeWidgetChrome = Pick<WidgetProps, "action" | "summaries">
8178
8224
  alert?: never;
8179
8225
  });
8180
8226
 
8227
+ /**
8228
+ * A Home widget's header. The frame's, except that the two things a user reads
8229
+ * to know WHAT they are looking at may follow the params they set.
8230
+ */
8231
+ export declare type HomeWidgetHeader = Omit<NonNullable<WidgetProps["header"]>, "title" | "info"> & {
8232
+ title?: FromWidgetParams<string>;
8233
+ /**
8234
+ * The `i` beside the title: hovering it explains the widget. Takes the params
8235
+ * too, so it can say what the numbers actually cover.
8236
+ */
8237
+ info?: FromWidgetParams<string>;
8238
+ };
8239
+
8181
8240
  /** A widget as handed to the layout: header + an ordered list of slots. */
8182
8241
  export declare type HomeWidgetItem = HomeWidgetChrome & {
8183
8242
  id: string;
8184
- header?: WidgetProps["header"];
8243
+ header?: HomeWidgetHeader;
8244
+ /**
8245
+ * THIS WIDGET'S OWN menu items — "Mark all as read", "Export as CSV", whatever
8246
+ * it can do that no other widget can. They go in the widget's three-dots menu,
8247
+ * FIRST: the column adds what every widget carries (what its info means, its
8248
+ * params, removing it) after them, and removing it sits behind a separator.
8249
+ *
8250
+ * Ordinary `DropdownItem`s, so they take an `icon`, a `description`, `critical`
8251
+ * for a destructive one, `disabled`, or a `type: "separator"` of your own to
8252
+ * group them. A `locked` widget still shows them.
8253
+ */
8254
+ actions?: WidgetProps["actions"];
8255
+ /**
8256
+ * The widget is CONFIGURABLE: these are the params the user may set, as an
8257
+ * F0Form schema. Declaring it — together with the layout's
8258
+ * `onChangeWidgetParams` — is what puts "Edit params" in the widget's menu.
8259
+ */
8260
+ paramsSchema?: WidgetParamsSchema;
8261
+ /**
8262
+ * The params it is configured with right now. They drive whatever the widget
8263
+ * derives from them (its `title`, its `info`) and are the dialog's starting
8264
+ * point; rebuilding the SLOTS for new params is the app's own job, since only
8265
+ * it knows where their data comes from.
8266
+ */
8267
+ params?: WidgetParams;
8185
8268
  fullHeight?: boolean;
8186
8269
  /**
8187
8270
  * The widget's catalog glyph — shown for it in the collapsed rail and in the
@@ -8189,9 +8272,9 @@ export declare type HomeWidgetItem = HomeWidgetChrome & {
8189
8272
  */
8190
8273
  icon?: IconType;
8191
8274
  /**
8192
- * PINNED: the widget stays put. In edit mode it shows no remove control and
8193
- * does not wiggle (nor drag, once dragging lands) — for widgets a user must
8194
- * always have, like Clock in.
8275
+ * PINNED: the widget stays put. It offers no "Remove widget" in its menu, it
8276
+ * cannot be dragged, and no other widget can displace it — for widgets a user
8277
+ * must always have, like Clock in.
8195
8278
  */
8196
8279
  locked?: boolean;
8197
8280
  /**
@@ -8751,7 +8834,8 @@ export declare interface ListSchema {
8751
8834
  * `"link"` rows each carry an `href` and render as REAL anchors (role
8752
8835
  * `link`, routed through the app's `LinkProvider`) — never an onClick;
8753
8836
  * that's the only click behavior rows have. Omit for inert rows.
8754
- * Same-tab for relative and `#` hrefs, `target="_blank"` for other domains.
8837
+ * Same-tab for paths, `#` fragments and this host under any scheme;
8838
+ * `target="_blank"` only for ANOTHER host (see `isExternalHref`).
8755
8839
  */
8756
8840
  clickBehavior?: "link";
8757
8841
  /**
@@ -9237,19 +9321,30 @@ export declare interface NewHomeLayoutProps {
9237
9321
  /** Full override of how a whole widget is drawn. Defaults to `SlotWidget`. */
9238
9322
  renderWidget?: (widget: HomeWidgetItem, ctx: HomeRenderCtx) => ReactNode;
9239
9323
  /**
9240
- * Edit mode. Omit it and the layout owns the state itself, toggled by its own
9241
- * edit button; pass it to drive edit mode from outside.
9324
+ * Which containers a user may arrange. Only these offer "Remove widget",
9325
+ * dragging and the add placeholder; the others stay put. Both by default.
9242
9326
  */
9243
- editing?: boolean;
9244
- /** Called when the layout's edit button is pressed. */
9245
- onEditingChange?: (editing: boolean) => void;
9327
+ editableWidgetContainers?: WidgetContainerSide[];
9246
9328
  /**
9247
- * Which containers a user may actually edit. In edit mode only these show
9248
- * remove controls and the add placeholder; the others stay put. Both by default.
9329
+ * Called with a widget id when its "Remove widget" menu item is used — the
9330
+ * three-dots menu in the widget's own header.
9249
9331
  */
9250
- editableWidgetContainers?: WidgetContainerSide[];
9251
- /** Called with a widget id when its remove control is clicked (edit mode only). */
9252
9332
  onRemoveWidget?: (id: string) => void;
9333
+ /**
9334
+ * Called with a widget id and its new params when its "Edit params" dialog is
9335
+ * saved. Providing it is what offers that item, in the same menu, for every
9336
+ * widget that declares a `paramsSchema`. PERSIST what it hands you and pass it
9337
+ * back as the widget's `params` — rebuilding the widget's slots for the new
9338
+ * params is the app's own job, since only it knows where their data comes from.
9339
+ */
9340
+ onChangeWidgetParams?: (id: string, params: WidgetParams) => void;
9341
+ /**
9342
+ * Draws a widget for params being tried out in that dialog, before they are
9343
+ * saved. Defaults to the widget with those params swapped in — which is
9344
+ * already live for everything they derive (title, info); supply this to
9345
+ * rebuild its slots as well.
9346
+ */
9347
+ renderWidgetPreview?: (widget: HomeWidgetItem, params: WidgetParams) => ReactNode;
9253
9348
  /** When set, renders a "+ Add widget" affordance at the bottom of each column. */
9254
9349
  onClickAddNewWidget?: (side: WidgetContainerSide) => void;
9255
9350
  /** Called with a side and its widget ids in their new order after a drag. */
@@ -10584,6 +10679,9 @@ export declare const resolveSlotRenderer: (entry: SlotRendererEntry | undefined)
10584
10679
  skeleton?: SlotSkeletonRenderer;
10585
10680
  } | undefined;
10586
10681
 
10682
+ /** Resolves a header's params-driven parts against the params in hand. */
10683
+ export declare const resolveWidgetHeader: (header: HomeWidgetHeader | undefined, params?: WidgetParams) => WidgetProps["header"];
10684
+
10587
10685
  /**
10588
10686
  * Header for a resource detail page: avatar, title, description, status,
10589
10687
  * metadata and its primary, secondary and overflow actions.
@@ -12838,14 +12936,30 @@ export declare type WidgetAvatarsListItemProps = {
12838
12936
  * WidgetCatalog — the "Add widget" dialog, mirroring the custom-home prototype:
12839
12937
  * a searchable picker on the left (icon + title rows, the selected row tinted),
12840
12938
  * a LIVE preview of the highlighted widget on the right at the width it will
12841
- * really get, and the "Add widget" CTA in the dialog footer. `width="xl"`
12842
- * rather than fullscreen.
12939
+ * really get, and the "Add widget" CTA in the dialog footer. FULLSCREEN off a
12940
+ * large display, and the two columns stack on a narrow screen
12941
+ * (`useWidgetDialogLayout`).
12843
12942
  *
12844
12943
  * Selection follows the filter: if the selected row is filtered out, the first
12845
12944
  * remaining row takes over, so the preview always shows something the CTA can
12846
12945
  * actually add.
12847
12946
  */
12848
- export declare function WidgetCatalog({ isOpen, onClose, widgets, onAdd, previewWidth, title, }: WidgetCatalogProps): JSX_2.Element;
12947
+ export declare function WidgetCatalog({ isOpen, onClose, widgets, onAdd, groups, previewWidth, title, }: WidgetCatalogProps): JSX_2.Element;
12948
+
12949
+ /**
12950
+ * One DOMAIN in the picker: a heading the widgets under it belong to.
12951
+ *
12952
+ * The label is the app's own words because f0's `modules` registry maps ids to
12953
+ * ICONS ONLY — there are no module names to borrow, and a domain may well cover
12954
+ * two modules or none.
12955
+ */
12956
+ export declare interface WidgetCatalogGroup {
12957
+ /** What an item's `group` points at. */
12958
+ id: string;
12959
+ label: string;
12960
+ /** The domain's module: its glyph heads the group. */
12961
+ module?: ModuleId;
12962
+ }
12849
12963
 
12850
12964
  /** One entry in the widget catalog dialog. */
12851
12965
  export declare interface WidgetCatalogItem {
@@ -12857,6 +12971,23 @@ export declare interface WidgetCatalogItem {
12857
12971
  * `SlotWidget`), so the preview can't drift from what gets added.
12858
12972
  */
12859
12973
  preview: ReactNode;
12974
+ /**
12975
+ * What this widget is telling you — the widget's own `header.info`, shown under
12976
+ * the preview. Deciding whether to add a widget is exactly the moment that
12977
+ * sentence is worth reading, so the picker says it without being asked.
12978
+ */
12979
+ info?: string;
12980
+ /**
12981
+ * Which `groups` entry this widget belongs under. A widget whose group isn't
12982
+ * declared (or which has none) is listed after the groups, without a heading.
12983
+ */
12984
+ group?: string;
12985
+ /**
12986
+ * LIFTS IT to a "Recommended" section at the very top, and out of its group —
12987
+ * a widget offered twice reads as two widgets. Optional in every sense: with
12988
+ * nothing recommended there is no section.
12989
+ */
12990
+ recommended?: boolean;
12860
12991
  }
12861
12992
 
12862
12993
  export declare interface WidgetCatalogProps {
@@ -12866,6 +12997,11 @@ export declare interface WidgetCatalogProps {
12866
12997
  widgets: WidgetCatalogItem[];
12867
12998
  /** Called with the chosen widget id when the CTA is pressed. */
12868
12999
  onAdd: (id: string) => void;
13000
+ /**
13001
+ * The DOMAINS the picker is organised into, in the order to show them. Omit it
13002
+ * and the list is flat — grouping is an offer, not a requirement.
13003
+ */
13004
+ groups?: WidgetCatalogGroup[];
12869
13005
  /**
12870
13006
  * Content width of the column this was opened from — the preview is capped
12871
13007
  * to it, so a rail-bound widget previews at rail width.
@@ -12901,6 +13037,45 @@ export declare type WidgetInboxListItemProps<Id extends string | number = string
12901
13037
 
12902
13038
  export declare type WidgetInboxListProps = Props_9;
12903
13039
 
13040
+ /**
13041
+ * What a user has CONFIGURED about a widget — the values of the fields its
13042
+ * `paramsSchema` declares, keyed by field name. Dates arrive as `Date`s, a
13043
+ * multi-select as an array: whatever the schema's zod types say.
13044
+ */
13045
+ export declare type WidgetParams = Record<string, unknown>;
13046
+
13047
+ /**
13048
+ * Whether every REQUIRED param of a schema is set — what "this widget can't be
13049
+ * shown until you configure it" comes down to. Use it to send a freshly added
13050
+ * widget straight into its params dialog.
13051
+ */
13052
+ export declare const widgetParamsAreComplete: (schema: WidgetParamsSchema | undefined, params: WidgetParams | undefined) => boolean;
13053
+
13054
+ /**
13055
+ * A widget's params SCHEMA: an F0Form schema, so the fields are declared once —
13056
+ * in zod, with their f0 field config — and F0Form draws and validates them.
13057
+ *
13058
+ * That buys the whole vocabulary rather than a bespoke one: `z.string()`,
13059
+ * `z.number()`, `z.date()` (`fieldType: "datetime"` for a time as well),
13060
+ * `z.enum()`, and a select fed by a DATASOURCE (`source` + `mapOptions`, with
13061
+ * `multiple` for many) — `z.array()` for the multi-select's value. A field is
13062
+ * REQUIRED unless its zod type is `.optional()`, so "the user must set this"
13063
+ * needs nothing new either.
13064
+ *
13065
+ * ```tsx
13066
+ * paramsSchema: z.object({
13067
+ * since: f0FormField(z.date(), { label: "Since" }),
13068
+ * team: f0FormField(z.array(z.string()), {
13069
+ * label: "Teams",
13070
+ * source: teamsDataSource,
13071
+ * mapOptions: (team) => ({ value: team.id, label: team.name }),
13072
+ * multiple: true,
13073
+ * }),
13074
+ * })
13075
+ * ```
13076
+ */
13077
+ export declare type WidgetParamsSchema = F0FormSchema;
13078
+
12904
13079
  export declare interface WidgetProps {
12905
13080
  header?: {
12906
13081
  title?: string;
@@ -12908,22 +13083,37 @@ export declare interface WidgetProps {
12908
13083
  comment?: string;
12909
13084
  info?: string;
12910
13085
  canBeBlurred?: boolean;
13086
+ /**
13087
+ * The way out of the widget: it makes the TITLE ITSELF the link — the title
13088
+ * with a chevron after it, one ghost-button-shaped target that lights up on
13089
+ * hover. Nothing sits in the header's top-right (that is the overflow menu's)
13090
+ * and nothing sits in the footer (that is `action`'s): the name of the widget
13091
+ * IS the way into it.
13092
+ */
12911
13093
  link?: {
12912
13094
  /**
12913
- * What following the link DOES, in words — "Go to Communities". The
12914
- * control is icon-only, so this is the only thing that says where it
12915
- * goes: it is its tooltip and its accessible name, and it is required
12916
- * for exactly that reason.
13095
+ * What following it DOES, in words — "Go to Communities". The visible text
13096
+ * is the widget's title, so this is what a screen reader announces
13097
+ * instead: it names the DESTINATION, which a title alone cannot.
12917
13098
  */
12918
13099
  title: string;
12919
13100
  url?: string;
12920
13101
  onClick?: () => void;
12921
- /** Defaults to the external-link glyph. */
13102
+ /** Defaults to the chevron. */
12922
13103
  icon?: IconType;
12923
13104
  };
12924
13105
  count?: number;
12925
13106
  };
13107
+ /** The card's footer button — its call to action. `neutral`/`sm` by default. */
12926
13108
  action?: F0ButtonProps;
13109
+ /**
13110
+ * Extra classes for the FOOTER row that `action` draws in. For content that
13111
+ * BLEEDS past the card's content box and wants the footer brought onto its
13112
+ * line — Home's row-based slots bleed 8px, which eats the gap above the footer
13113
+ * and offsets it from the rows (see `SlotWidget`). Spacing only; `F0Button`
13114
+ * takes no className of its own, so this is the seam for it.
13115
+ */
13116
+ footerClassName?: string;
12927
13117
  summaries?: Array<{
12928
13118
  label: string;
12929
13119
  value: string | number;
@@ -12994,6 +13184,17 @@ export declare const WidgetStrip: ForwardRefExoticComponent<DashboardProps_2 & R
12994
13184
  Skeleton: () => JSX_2.Element;
12995
13185
  };
12996
13186
 
13187
+ /**
13188
+ * A widget's title as TEXT — resolved against its own params, and falling back
13189
+ * to its id so there is always something to name it by (an aria-label on the
13190
+ * collapsed rail's glyph, a row in the catalog).
13191
+ */
13192
+ export declare const widgetTitle: (widget: {
13193
+ id: string;
13194
+ header?: HomeWidgetHeader;
13195
+ params?: WidgetParams;
13196
+ }) => string;
13197
+
12997
13198
  declare type WidgetWidth = "sm" | "md" | "lg";
12998
13199
 
12999
13200
  declare interface WiggleOptions {
@@ -13144,9 +13345,11 @@ declare module "@tiptap/core" {
13144
13345
 
13145
13346
  declare module "@tiptap/core" {
13146
13347
  interface Commands<ReturnType> {
13147
- fontSize: {
13148
- setFontSize: (fontSize: string) => ReturnType;
13149
- unsetFontSize: () => ReturnType;
13348
+ enhanceHighlight: {
13349
+ setEnhanceHighlight: (from: number, to: number, options?: {
13350
+ placeholder?: string;
13351
+ }) => ReturnType;
13352
+ clearEnhanceHighlight: () => ReturnType;
13150
13353
  };
13151
13354
  }
13152
13355
  }
@@ -13154,10 +13357,9 @@ declare module "@tiptap/core" {
13154
13357
 
13155
13358
  declare module "@tiptap/core" {
13156
13359
  interface Commands<ReturnType> {
13157
- indent: {
13158
- setIndent: (level: number) => ReturnType;
13159
- unsetIndent: () => ReturnType;
13160
- outdent: () => ReturnType;
13360
+ fontSize: {
13361
+ setFontSize: (fontSize: string) => ReturnType;
13362
+ unsetFontSize: () => ReturnType;
13161
13363
  };
13162
13364
  }
13163
13365
  }
@@ -13165,11 +13367,8 @@ declare module "@tiptap/core" {
13165
13367
 
13166
13368
  declare module "@tiptap/core" {
13167
13369
  interface Commands<ReturnType> {
13168
- enhanceHighlight: {
13169
- setEnhanceHighlight: (from: number, to: number, options?: {
13170
- placeholder?: string;
13171
- }) => ReturnType;
13172
- clearEnhanceHighlight: () => ReturnType;
13370
+ moodTracker: {
13371
+ insertMoodTracker: (data: MoodTrackerData) => ReturnType;
13173
13372
  };
13174
13373
  }
13175
13374
  }
@@ -13177,8 +13376,10 @@ declare module "@tiptap/core" {
13177
13376
 
13178
13377
  declare module "@tiptap/core" {
13179
13378
  interface Commands<ReturnType> {
13180
- moodTracker: {
13181
- insertMoodTracker: (data: MoodTrackerData) => ReturnType;
13379
+ indent: {
13380
+ setIndent: (level: number) => ReturnType;
13381
+ unsetIndent: () => ReturnType;
13382
+ outdent: () => ReturnType;
13182
13383
  };
13183
13384
  }
13184
13385
  }
@@ -13186,8 +13387,10 @@ declare module "@tiptap/core" {
13186
13387
 
13187
13388
  declare module "@tiptap/core" {
13188
13389
  interface Commands<ReturnType> {
13189
- transcript: {
13190
- insertTranscript: (data: TranscriptData) => ReturnType;
13390
+ videoEmbed: {
13391
+ setVideoEmbed: (options: {
13392
+ src: string;
13393
+ }) => ReturnType;
13191
13394
  };
13192
13395
  }
13193
13396
  }
@@ -13195,10 +13398,8 @@ declare module "@tiptap/core" {
13195
13398
 
13196
13399
  declare module "@tiptap/core" {
13197
13400
  interface Commands<ReturnType> {
13198
- videoEmbed: {
13199
- setVideoEmbed: (options: {
13200
- src: string;
13201
- }) => ReturnType;
13401
+ transcript: {
13402
+ insertTranscript: (data: TranscriptData) => ReturnType;
13202
13403
  };
13203
13404
  }
13204
13405
  }