@dataverse-kit/surface-kit 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/v9.d.cts CHANGED
@@ -1,13 +1,23 @@
1
- import { DialogSizePreset } from './core.cjs';
2
- export { CALLOUT_DEFAULT_WIDTH, DIALOG_SIZE_PX, MODAL_AUTOSIZE_MIN_WIDTH, PANEL_DEFAULT_WIDTH, PanelKind, calloutFormDefaults, calloutWidthPx, dialogHeightCss, dialogWidthCss, dialogWidthPx, panelCustomWidthPx, panelKindFromWidth } from './core.cjs';
1
+ import { SurfaceLook, DialogSizePreset } from './core.cjs';
2
+ export { CALLOUT_DEFAULT_WIDTH, CE_LABEL_ABOVE_BELOW_ROW_WIDTH, CE_TAB_COLUMN_MIN_WIDTH, DIALOG_SIZE_PX, MODAL_AUTOSIZE_MIN_WIDTH, PANEL_DEFAULT_WIDTH, PanelKind, calloutFormDefaults, calloutWidthPx, dialogHeightCss, dialogWidthCss, dialogWidthPx, normalizeColumnShares, panelCustomWidthPx, panelKindFromWidth, resolveTabColumnWidths } from './core.cjs';
3
3
  export { C as ColumnCount, c as clampSpan, g as gridTemplateForColumns } from './columns-BlpFO5VD.cjs';
4
4
  import { Breakpoint } from './responsive.cjs';
5
5
  export { BREAKPOINTS, CARD_REFLOW_WIDTH, ResponsiveMode, ResponsiveValue, StyleObject, fieldGridStyle, fieldRowStyle, resolveBreakpoint, resolveResponsiveValue, sectionStackingStyle } from './responsive.cjs';
6
- export { colors, layout, radius, spacing, typography } from '@dataverse-kit/design-tokens';
7
- import { D as Density } from './useDensity-xEYt-GdJ.cjs';
8
- export { C as ContainerSize, f as DensityContext, d as densityScale, s as scaleSpacing, b as useContainerBreakpoint, u as useContainerSize, a as useContainerWidth, g as useDensity, e as useMediaQuery, c as useResponsiveValue } from './useDensity-xEYt-GdJ.cjs';
9
- import React__default, { ReactElement, CSSProperties, ReactNode, RefObject } from 'react';
10
- import { BrandVariants, Theme } from '@fluentui/react-components';
6
+ export { ceForm, colors, layout, radius, spacing, typography } from '@dataverse-kit/design-tokens';
7
+ import { D as Density } from './useDensity-CLglP89q.cjs';
8
+ export { C as ContainerSize, a as DensityContext, d as densityScale, s as scaleSpacing, u as useContainerBreakpoint, b as useContainerSize, c as useContainerWidth, e as useDensity, f as useMediaQuery, g as useResponsiveValue } from './useDensity-CLglP89q.cjs';
9
+ import * as React from 'react';
10
+ import React__default, { ReactElement, RefObject, ReactNode, CSSProperties } from 'react';
11
+ export { createDynamicsCeTheme, createDynamicsV9DarkTheme, createDynamicsV9Theme, dynamicsBrandRamp, dynamicsCeTheme, dynamicsV9DarkTheme, dynamicsV9Theme } from '@dataverse-kit/fluent-theme';
12
+
13
+ /**
14
+ * Form-level appearance: `'default'` (the kit's existing look) or `'ce'` (the measured Dynamics CE
15
+ * model-driven form). `FormSurface` provides it and layouts read it, the same way `DensityContext`
16
+ * cascades density, so a single `look` on the form reaches every row and column.
17
+ */
18
+ declare const LookContext: React.Context<SurfaceLook>;
19
+ /** Read the ambient surface look (defaults to `'default'` outside a provider). */
20
+ declare const useLook: () => SurfaceLook;
11
21
 
12
22
  type SurfaceVariant = 'card' | 'flat' | 'placeholder';
13
23
  type Alignment = 'left' | 'center' | 'right';
@@ -21,6 +31,14 @@ interface SurfaceToolbarItem {
21
31
  appearance?: 'primary' | 'subtle';
22
32
  disabled?: boolean;
23
33
  onClick?: () => void;
34
+ /**
35
+ * A dropdown. Without `split` the whole button opens the menu (Dynamics "Process ▾") and
36
+ * `onClick` is ignored; with `split` the main part runs `onClick` and a separate chevron opens
37
+ * the menu ("Connect | ▾") — in both looks; only `look="ce"` applies the measured split geometry.
38
+ * Menu entries' own `menuItems`/`split` are not rendered (one level only).
39
+ */
40
+ menuItems?: SurfaceToolbarItem[];
41
+ split?: boolean;
24
42
  }
25
43
  /** An action button in a v9 `ActionBar` / dialog footer. */
26
44
  interface SurfaceActionButton {
@@ -39,11 +57,11 @@ interface SurfaceActionButton {
39
57
  type SurfacePosition = 'above' | 'below' | 'before' | 'after';
40
58
  type SurfaceAlign = 'start' | 'center' | 'end';
41
59
  interface FormSurfaceProps {
42
- /** Outer grid column count. Default 12. */
60
+ /** Outer grid column count. Default 12. Ignored under `look="ce"` (see `look`). */
43
61
  columns?: number;
44
- /** Grid gap in px. Default 20. */
62
+ /** Grid gap in px. Default 20. Ignored under `look="ce"`. */
45
63
  gap?: number;
46
- /** Padding in px. Default 20. */
64
+ /** Padding in px. Default 20; default 0 under `look="ce"`. */
47
65
  padding?: number;
48
66
  /** Spacing density: `'compact'` scales gap + padding by 0.75 and cascades to child
49
67
  * Sections via context. Default `'comfortable'` (byte-identical to no density). */
@@ -52,6 +70,19 @@ interface FormSurfaceProps {
52
70
  background?: string;
53
71
  /** Container width hint (e.g. a PCF `context.allocatedWidth`) — drives stacking off the container, not the viewport. */
54
72
  containerWidth?: number;
73
+ /**
74
+ * Appearance family, cascaded to layouts via context: `'default'` (the kit's existing look) or
75
+ * `'ce'` (the MEASURED Dynamics CE model-driven form: 184px label column, 48px field rows,
76
+ * 340px tab-column floor…). Pair `'ce'` with `dynamicsCeTheme` on the `FluentProvider`.
77
+ * Default `'default'` (renders exactly as before).
78
+ *
79
+ * ★ Under `'ce'` the surface is a plain BLOCK, not the 12-column grid: a Dynamics form is page
80
+ * chrome stacked top to bottom (command bar, header card, tab body), and its columns belong to
81
+ * `TabColumns`. So `columns`/`gap`/`collapseBelow` are ignored, padding defaults to 0, and its
82
+ * children fill the width with no `minWidth: 0` wrapper — `<FormSurface look="ce">` is all a
83
+ * page needs.
84
+ */
85
+ look?: SurfaceLook;
55
86
  /** Collapse children to full width below this breakpoint. Default `'sm'`. */
56
87
  collapseBelow?: Breakpoint;
57
88
  maxWidth?: number | string;
@@ -69,7 +100,12 @@ interface SectionProps {
69
100
  columnSpan?: number;
70
101
  columnStart?: number;
71
102
  rowPosition?: number;
72
- /** Internal field-grid column count. Default 12. */
103
+ /**
104
+ * Internal column count. Default look: the field grid's column count, default 12 (children are
105
+ * grid cells). Under `look="ce"`: the section's formxml column count, default 1; with more than
106
+ * one, pass ONE CHILD PER COLUMN, each holding that column's FieldRows (a dev warning fires
107
+ * otherwise).
108
+ */
73
109
  internalColumns?: number;
74
110
  /** Show a v9 `<Toolbar>` of `commandItems` in the section header. */
75
111
  showCommandBar?: boolean;
@@ -87,8 +123,21 @@ interface SectionProps {
87
123
  /** Min height for the `placeholder` variant. */
88
124
  minHeight?: number;
89
125
  /** Spacing density override; defaults to the ambient `FormSurface` density (`useDensity`).
90
- * `'compact'` scales the card padding + internal field gap by 0.75. */
126
+ * `'compact'` scales the card padding + internal field gap by 0.75. Ignored under `look="ce"`,
127
+ * whose spacing is measured. */
91
128
  density?: Density;
129
+ /**
130
+ * Appearance family; defaults to the ambient `FormSurface` look. Under `'ce'` the `card` variant
131
+ * is the MEASURED Dynamics section: shadow4 card, 8px radius, padding 4/16/16/16, the title as
132
+ * given (14/600/20, 4px top pad, no rule, not uppercased), and a gap-free body that pulls rows up
133
+ * by `ceFieldRowFirstOffset`. Children are the section's `FieldRow`s; with `internalColumns > 1`
134
+ * pass ONE CHILD PER COLUMN (Dynamics' section → columns → rows): columns are equal, with a 21px
135
+ * gutter on every column but the last. `internalColumns` defaults to 1 under `'ce'`.
136
+ * The collapse chevron and header commands still render under `'ce'`, but their CE geometry
137
+ * is unmeasured, as is multi-column reflow: below the phone breakpoint CE columns stack
138
+ * (provisional). Only the `card` variant has a CE form; `flat` and `placeholder` keep their chrome.
139
+ */
140
+ look?: SurfaceLook;
92
141
  className?: string;
93
142
  style?: CSSProperties;
94
143
  children?: ReactNode;
@@ -108,6 +157,8 @@ interface SectionHeaderProps {
108
157
  collapsible?: boolean;
109
158
  collapsed?: boolean;
110
159
  onToggle?: () => void;
160
+ /** Appearance family; defaults to the ambient `FormSurface` look. `'ce'` draws the measured Dynamics section title (no rule, no 48px bar). */
161
+ look?: SurfaceLook;
111
162
  }
112
163
  interface FormHeaderProps {
113
164
  title?: ReactNode;
@@ -120,6 +171,65 @@ interface FormHeaderProps {
120
171
  /** Right side of the header (e.g. KPI header fields). */
121
172
  actions?: ReactNode;
122
173
  className?: string;
174
+ /**
175
+ * Appearance family; defaults to the ambient `FormSurface` look. Under `'ce'` this is the
176
+ * MEASURED Dynamics record header region (padding 14/20/0/20): a 40px initials avatar in a 2px
177
+ * ring (Fluent `colorful`, hashed from `title` — which reproduces Dynamics' colour), the title at
178
+ * 20/600/28 followed by `- {status}`, an `entityName · form switcher` row, value-over-label
179
+ * `headerFields` separated by 1×38 dividers, the `owner` persona, and an expand chevron.
180
+ * Render it as `PivotSurface look="ce"`'s `header` to get the header card with the tab strip.
181
+ */
182
+ look?: SurfaceLook;
183
+ /** ce: the entity display name before the form switcher (e.g. `"Account"`). Falls back to `subtitle`. */
184
+ entityName?: ReactNode;
185
+ /** ce: the forms offered by the switcher. With fewer than two, the active form's name renders as text. */
186
+ forms?: SurfaceFormOption[];
187
+ activeFormId?: string;
188
+ onFormChange?: (formId: string) => void;
189
+ /** ce: value-over-label header fields (e.g. Annual Revenue). An empty value renders `---`. */
190
+ headerFields?: SurfaceHeaderField[];
191
+ /** ce: the owner persona at the end of the header fields. */
192
+ owner?: SurfaceHeaderOwner;
193
+ /** ce: shows the expand chevron; called when it is clicked. */
194
+ onExpand?: () => void;
195
+ expanded?: boolean;
196
+ /**
197
+ * ce: the element the title renders as. Default `'h1'` — right for a full-page record, as in
198
+ * Dynamics; pass `'h2'` (etc.) when the header sits inside a dialog, panel or an app shell that
199
+ * already has its own `h1`.
200
+ */
201
+ titleAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'span';
202
+ }
203
+ /** A form offered by the record header's form switcher. */
204
+ interface SurfaceFormOption {
205
+ id: string;
206
+ label: string;
207
+ }
208
+ /** A value-over-label field in the record header. */
209
+ interface SurfaceHeaderField {
210
+ id?: string;
211
+ label: string;
212
+ /** Empty (`null`/`undefined`/`''`) renders Dynamics' `---`. */
213
+ value?: ReactNode;
214
+ }
215
+ /** The owner persona in the record header. */
216
+ interface SurfaceHeaderOwner {
217
+ name: string;
218
+ /** Caption under the name. Default `"Owner"`. */
219
+ label?: string;
220
+ /**
221
+ * The avatar. Default: a 32px Fluent `Avatar` with `color="colorful"` (and a presence badge when
222
+ * `presence` is set). ★ Dynamics' owner colour does NOT follow Fluent's hash (measured: "System Administrator"
223
+ * renders solid red #d13438; Fluent's hash gives grape), and its rule is unmeasured — pass an
224
+ * avatar to match a specific org.
225
+ */
226
+ avatar?: ReactNode;
227
+ /**
228
+ * Presence shown on the DEFAULT avatar (ignored when `avatar` is given). No badge unless set:
229
+ * a badge is announced to screen readers, so it must reflect real presence.
230
+ */
231
+ presence?: 'available' | 'away' | 'busy' | 'do-not-disturb' | 'offline' | 'out-of-office' | 'blocked' | 'unknown';
232
+ onClick?: () => void;
123
233
  }
124
234
  interface SurfaceTab {
125
235
  id: string;
@@ -139,8 +249,32 @@ interface PivotSurfaceProps {
139
249
  /** v9 `TabList` size. Default `'medium'`. */
140
250
  size?: 'small' | 'medium' | 'large';
141
251
  className?: string;
252
+ /**
253
+ * Appearance family. OPT-IN: unlike most surfaces this does NOT follow the ambient `FormSurface`
254
+ * look (it is page-level chrome; a pivot nested in a ce Section stays plain). Under `'ce'` it
255
+ * ignores `appearance`/`size` and renders the MEASURED Dynamics header card — `header` (e.g. a `FormHeader`) above a tab strip (45px tabs,
256
+ * 16/28 text, 20px gaps, a 3px brand underline) — then the selected tab's content BELOW the
257
+ * card, in the tab body (16px top, 21px bottom), with the page's 8px left / 20px right insets.
258
+ */
259
+ look?: SurfaceLook;
260
+ /** Rendered above the tab strip — inside the header card under `'ce'`. Icon tabs are unmeasured under `'ce'`. */
261
+ header?: ReactNode;
142
262
  }
143
263
  interface CommandSurfaceProps {
264
+ /**
265
+ * Appearance family. OPT-IN (does not follow the ambient `FormSurface` look): under `'ce'` this is
266
+ * page chrome — the MEASURED Dynamics command bar card (1474×46 at 1710px; shadow4, 8px radius), 8px below the page top and
267
+ * 16px above the header card, with the page insets (16 left / 20 right): optional back and pop-out
268
+ * buttons each followed by a divider, then abutting 32px commands (16px icon, 7px gap, 14px REGULAR
269
+ * label), menu (▾) and split commands, the ⋮ overflow, and `farItems` as outlined 24px buttons
270
+ * (Share). Pass 16px Fluent icons (`*16Regular`) for commands and 20px (`*20Regular`) for farItems. Commands are NOT folded into ⋮ automatically
271
+ * (Dynamics does, by an unmeasured rule): pass `overflowItems` explicitly.
272
+ */
273
+ look?: SurfaceLook;
274
+ /** ce: shows the back button (before the first divider). */
275
+ onBack?: () => void;
276
+ /** ce: shows the "open in new window" button (before the second divider). */
277
+ onPopOut?: () => void;
144
278
  items: SurfaceToolbarItem[];
145
279
  /** Rendered behind a "more" overflow menu after the primary items. */
146
280
  overflowItems?: SurfaceToolbarItem[];
@@ -244,18 +378,62 @@ interface TooltipSurfaceProps {
244
378
  relationship?: 'label' | 'description';
245
379
  children: ReactElement;
246
380
  }
247
-
248
- declare const dynamicsBrandRamp: BrandVariants;
249
- /**
250
- * Build a Fluent v9 `Theme` for the Dynamics surfaces. Defaults to the Dynamics-blue
251
- * brand ramp; pass a custom `BrandVariants` (e.g. from your org's brand) to override.
252
- * Wrap the app (or a `./v9` surface subtree) in `<FluentProvider theme={createDynamicsV9Theme()}>`.
253
- */
254
- declare function createDynamicsV9Theme(brand?: BrandVariants): Theme;
255
- /** Dark-mode variant of the Dynamics v9 theme (same brand ramp). */
256
- declare function createDynamicsV9DarkTheme(brand?: BrandVariants): Theme;
257
- /** The default light Dynamics v9 theme (memoized module singleton). */
258
- declare const dynamicsV9Theme: Theme;
381
+ /** Where a field's label sits relative to its control. */
382
+ type FieldLabelPosition = 'beside' | 'above' | 'auto';
383
+ interface FieldRowProps {
384
+ /**
385
+ * The field label. Omit for a label-less control: the control then sits where a beside control
386
+ * would, full width. (Dynamics' own label-less controls, such as the timeline, use different,
387
+ * control-specific padding that is not modelled here.)
388
+ */
389
+ label?: ReactNode;
390
+ /** Draws the required marker (`*`) after the label. */
391
+ required?: boolean;
392
+ /** Associates the label with the control (`<label htmlFor>`); pass the control's id. */
393
+ htmlFor?: string;
394
+ /**
395
+ * `'beside'` (formxml `Left`), `'above'` (formxml `Top`), or `'auto'`: beside while the row is
396
+ * wide enough, above when it is narrow, as Dynamics does (see CE_LABEL_ABOVE_BELOW_ROW_WIDTH —
397
+ * the switch point is provisional). An `'auto'` row is a CSS size container, so it needs a
398
+ * parent of definite width (not a shrink-to-fit popover or `auto` grid track).
399
+ * Default `'auto'` under the `ce` look, `'beside'` otherwise. Under the default look `'auto'`
400
+ * behaves as `'beside'` (with the phone stack at 480px).
401
+ */
402
+ labelPosition?: FieldLabelPosition;
403
+ /** Override the label column width (px or CSS length). Default: 184 under `ce`, 130 otherwise. */
404
+ labelWidth?: number | string;
405
+ /** Override the ambient look for this row. */
406
+ look?: SurfaceLook;
407
+ className?: string;
408
+ style?: CSSProperties;
409
+ /**
410
+ * ★ Rows span every column of a grid parent. Under `ce`, every row pads 12px on top; the section
411
+ * body pulls up by `ceFieldRowFirstOffset` so the first row sits at Dynamics' 8px —
412
+ * `Section look="ce"` does this for you.
413
+ *
414
+ * The control. Under the `ce` look use stock Fluent v9 controls with `appearance="filled-darker"`
415
+ * (the measured field: #f5f5f5 fill, transparent border, 32px) and `placeholder="---"` for the
416
+ * empty state, as Dynamics shows.
417
+ */
418
+ children?: ReactNode;
419
+ }
420
+ interface TabColumnsProps {
421
+ /**
422
+ * Declared column shares, as in the formxml tab `<column width="33%">`, e.g. `[33, 42, 25]`.
423
+ * One entry per child column. Default: equal shares.
424
+ */
425
+ widths?: readonly number[];
426
+ /** Minimum rendered column width in px. Default 340 under `ce` (measured), 300 otherwise. */
427
+ minColumnWidth?: number;
428
+ /** Gap between columns, and between sections stacked in a column, in px. Default 16 under `ce`, 20 otherwise. */
429
+ gap?: number;
430
+ /** Override the ambient look. */
431
+ look?: SurfaceLook;
432
+ className?: string;
433
+ style?: CSSProperties;
434
+ /** One child per column; each child's own children are the column's stacked sections. */
435
+ children?: ReactNode;
436
+ }
259
437
 
260
438
  /** The N-column form canvas that hosts Sections (Fluent UI v9). */
261
439
  declare const FormSurface: React__default.FC<FormSurfaceProps>;
@@ -276,6 +454,7 @@ declare const SectionCard: React__default.FC<SectionCardProps>;
276
454
  /** Section header bar (Fluent v9): title + status (left), toolbar / actions (right), optional collapse toggle. */
277
455
  declare const SectionHeader: React__default.FC<SectionHeaderProps>;
278
456
 
457
+ declare const cePresenceBadgeStyle: Readonly<React__default.CSSProperties>;
279
458
  /** Dynamics form header (Fluent v9): persona + title/status (left), KPI/header fields (right). */
280
459
  declare const FormHeader: React__default.FC<FormHeaderProps>;
281
460
 
@@ -291,6 +470,18 @@ declare const ActionBar: React__default.FC<ActionBarProps>;
291
470
  /** A sticky footer region (free-form children, Fluent v9) — e.g. for dialog/panel actions. */
292
471
  declare const Footer: React__default.FC<FooterProps>;
293
472
 
473
+ /**
474
+ * How far a section body must pull its rows up so the first `FieldRow` pads 8px, as Dynamics'
475
+ * first row does, while every row itself pads 12px. `Section look="ce"` applies it; a hand-built
476
+ * body applies `marginTop: -ceFieldRowFirstOffset`.
477
+ */
478
+ declare const ceFieldRowFirstOffset: number;
479
+ /** A "Label : control" field row (Fluent UI v9). The control goes in `children`. */
480
+ declare const FieldRow: React__default.FC<FieldRowProps>;
481
+
482
+ /** Tab-body columns with declared shares and a width floor (Fluent UI v9). One child per column. */
483
+ declare const TabColumns: React__default.FC<TabColumnsProps>;
484
+
294
485
  /**
295
486
  * Full Dynamics form-dialog (Fluent v9 `Dialog`). Default width 1200 (lg), height 95vh.
296
487
  * `onDismiss` is the close affordance — when omitted, no close button renders. `isBlocking`
@@ -310,4 +501,4 @@ declare const CalloutSurface: React__default.FC<CalloutSurfaceProps>;
310
501
  /** A tooltip wrapper (Fluent v9 `Tooltip`). */
311
502
  declare const TooltipSurface: React__default.FC<TooltipSurfaceProps>;
312
503
 
313
- export { ActionBar, type ActionBarProps, type Alignment, Breakpoint, CalloutSurface, type CalloutSurfaceProps, CommandSurface, type CommandSurfaceProps, Density, DialogSizePreset, Footer, type FooterProps, FormDialogSurface, type FormDialogSurfaceProps, FormHeader, type FormHeaderProps, FormSurface, type FormSurfaceProps, ModalSurface, type ModalSurfaceProps, PageSurface, type PageSurfaceProps, PanelSurface, type PanelSurfaceProps, PivotSurface, type PivotSurfaceProps, Section, SectionCard, type SectionCardProps, SectionHeader, type SectionHeaderProps, type SectionProps, type SurfaceActionButton, type SurfaceAlign, type SurfacePosition, type SurfaceTab, type SurfaceToolbarItem, type SurfaceVariant, TooltipSurface, type TooltipSurfaceProps, createDynamicsV9DarkTheme, createDynamicsV9Theme, dynamicsBrandRamp, dynamicsV9Theme };
504
+ export { ActionBar, type ActionBarProps, type Alignment, Breakpoint, CalloutSurface, type CalloutSurfaceProps, CommandSurface, type CommandSurfaceProps, Density, DialogSizePreset, type FieldLabelPosition, FieldRow, type FieldRowProps, Footer, type FooterProps, FormDialogSurface, type FormDialogSurfaceProps, FormHeader, type FormHeaderProps, FormSurface, type FormSurfaceProps, LookContext, ModalSurface, type ModalSurfaceProps, PageSurface, type PageSurfaceProps, PanelSurface, type PanelSurfaceProps, PivotSurface, type PivotSurfaceProps, Section, SectionCard, type SectionCardProps, SectionHeader, type SectionHeaderProps, type SectionProps, type SurfaceActionButton, type SurfaceAlign, type SurfaceFormOption, type SurfaceHeaderField, type SurfaceHeaderOwner, SurfaceLook, type SurfacePosition, type SurfaceTab, type SurfaceToolbarItem, type SurfaceVariant, TabColumns, type TabColumnsProps, TooltipSurface, type TooltipSurfaceProps, ceFieldRowFirstOffset, cePresenceBadgeStyle, useLook };