@dataverse-kit/surface-kit 0.4.1 → 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.mjs CHANGED
@@ -44,6 +44,34 @@ function clampSpan(span, columns) {
44
44
  return Math.max(1, Math.min(Math.round(span), columns));
45
45
  }
46
46
 
47
+ // src/core/ceLayout.ts
48
+ var CE_TAB_COLUMN_MIN_WIDTH = 340;
49
+ function normalizeColumnShares(shares) {
50
+ const clean = shares.map((s) => Number.isFinite(s) && s > 0 ? s : 0);
51
+ const total = clean.reduce((a, b) => a + b, 0);
52
+ if (total <= 0) return shares.map(() => 100 / (shares.length || 1));
53
+ return clean.map((s) => s / total * 100);
54
+ }
55
+ function resolveTabColumnWidths(shares, available, minWidth = CE_TAB_COLUMN_MIN_WIDTH) {
56
+ if (shares.length === 0) return [];
57
+ shares = normalizeColumnShares(shares);
58
+ const clamped = /* @__PURE__ */ new Set();
59
+ let widths = [];
60
+ for (let pass = 0; pass <= shares.length; pass++) {
61
+ const free = available - clamped.size * minWidth;
62
+ const total = shares.reduce((sum, s, i) => clamped.has(i) ? sum : sum + Math.max(0, s), 0);
63
+ widths = shares.map((s, i) => {
64
+ if (clamped.has(i)) return minWidth;
65
+ return total > 0 ? Math.max(0, s) / total * free : free / (shares.length - clamped.size);
66
+ });
67
+ const violators = widths.map((w, i) => !clamped.has(i) && w < minWidth ? i : -1).filter((i) => i >= 0);
68
+ if (violators.length === 0) break;
69
+ violators.forEach((i) => clamped.add(i));
70
+ }
71
+ return widths;
72
+ }
73
+ var CE_LABEL_ABOVE_BELOW_ROW_WIDTH = 340;
74
+
47
75
  // src/responsive/breakpoints.ts
48
76
  var BREAKPOINTS = {
49
77
  xs: 0,
@@ -120,7 +148,7 @@ function fieldRowStyle(labelWidth = "130px", mode = "media") {
120
148
  }
121
149
 
122
150
  // src/tokens/tokens.ts
123
- import { colors, spacing, typography, radius, layout } from "@dataverse-kit/design-tokens";
151
+ import { colors, spacing, typography, radius, layout, ceForm } from "@dataverse-kit/design-tokens";
124
152
 
125
153
  // src/tokens/density.ts
126
154
  var densityScale = {
@@ -194,13 +222,20 @@ import { createContext, useContext } from "react";
194
222
  var DensityContext = createContext("comfortable");
195
223
  var useDensity = () => useContext(DensityContext);
196
224
 
225
+ // src/hooks/useLook.ts
226
+ import { createContext as createContext2, useContext as useContext2 } from "react";
227
+ var LookContext = createContext2("default");
228
+ var useLook = () => useContext2(LookContext);
229
+
197
230
  // src/v9/theme.ts
198
231
  import {
199
232
  dynamicsBrandRamp,
200
233
  createDynamicsV9Theme,
201
234
  createDynamicsV9DarkTheme,
202
235
  dynamicsV9Theme,
203
- dynamicsV9DarkTheme
236
+ dynamicsV9DarkTheme,
237
+ createDynamicsCeTheme,
238
+ dynamicsCeTheme
204
239
  } from "@dataverse-kit/fluent-theme";
205
240
 
206
241
  // src/v9/containers/FormSurface.tsx
@@ -235,10 +270,11 @@ var VIEWPORT_STACK = {
235
270
  var FormSurface = ({
236
271
  columns = 12,
237
272
  gap = 20,
238
- padding = 20,
273
+ padding,
239
274
  density = "comfortable",
240
275
  background,
241
276
  containerWidth,
277
+ look = "default",
242
278
  collapseBelow = "sm",
243
279
  maxWidth,
244
280
  className,
@@ -246,10 +282,29 @@ var FormSurface = ({
246
282
  children
247
283
  }) => {
248
284
  const styles = useStyles();
285
+ if (look === "ce") {
286
+ return /* @__PURE__ */ jsx(DensityContext.Provider, { value: density, children: /* @__PURE__ */ jsx(LookContext.Provider, { value: look, children: /* @__PURE__ */ jsx(
287
+ "div",
288
+ {
289
+ className,
290
+ "data-surface-part": "form-surface",
291
+ "data-look": "ce",
292
+ style: {
293
+ display: "flow-root",
294
+ minWidth: 0,
295
+ padding: padding ?? 0,
296
+ ...background != null ? { background } : {},
297
+ ...maxWidth != null ? { maxWidth, marginLeft: "auto", marginRight: "auto" } : {},
298
+ ...style
299
+ },
300
+ children
301
+ }
302
+ ) }) });
303
+ }
249
304
  const collapsePx = BREAKPOINTS[collapseBelow];
250
305
  const forceStack = containerWidth != null && containerWidth <= collapsePx;
251
306
  const scaledGap = scaleSpacing(gap, density);
252
- const scaledPadding = scaleSpacing(padding, density);
307
+ const scaledPadding = scaleSpacing(padding ?? 20, density);
253
308
  const viewportStackSlot = containerWidth == null ? VIEWPORT_STACK[collapseBelow] : null;
254
309
  const cls = mergeClasses(
255
310
  styles.root,
@@ -265,7 +320,7 @@ var FormSurface = ({
265
320
  ...maxWidth != null ? { maxWidth, marginLeft: "auto", marginRight: "auto" } : {},
266
321
  ...style
267
322
  };
268
- return /* @__PURE__ */ jsx(DensityContext.Provider, { value: density, children: /* @__PURE__ */ jsx("div", { className: cls, style: inlineStyle, children }) });
323
+ return /* @__PURE__ */ jsx(DensityContext.Provider, { value: density, children: /* @__PURE__ */ jsx(LookContext.Provider, { value: look, children: /* @__PURE__ */ jsx("div", { className: cls, style: inlineStyle, children }) }) });
269
324
  };
270
325
 
271
326
  // src/v9/containers/PageSurface.tsx
@@ -273,8 +328,232 @@ import { jsx as jsx2 } from "react/jsx-runtime";
273
328
  var PageSurface = ({ centered, maxWidth, ...rest }) => /* @__PURE__ */ jsx2(FormSurface, { maxWidth: maxWidth ?? (centered ? 1200 : void 0), ...rest });
274
329
 
275
330
  // src/v9/containers/Section.tsx
276
- import { useState as useState3 } from "react";
277
- import { makeStyles as makeStyles2, mergeClasses as mergeClasses2, tokens as tokens3 } from "@fluentui/react-components";
331
+ import React, { useState as useState3 } from "react";
332
+ import { makeStyles as makeStyles3, mergeClasses as mergeClasses3, tokens as tokens4 } from "@fluentui/react-components";
333
+
334
+ // src/v9/layouts/FieldRow.tsx
335
+ import { makeStyles as makeStyles2, mergeClasses as mergeClasses2, tokens as tokens2 } from "@fluentui/react-components";
336
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
337
+ var F = ceForm.field;
338
+ var CE_LABEL_BOX = 30;
339
+ var CE_LABEL_OFFSET = 4;
340
+ var CE_CONTROL_OFFSET = 2;
341
+ var CE_CONTROL_INSET_RIGHT = 2;
342
+ var CE_LABEL_TEXT_WIDTH = 176;
343
+ var CE_MARKER_GAP = 4;
344
+ var ceFieldRowFirstOffset = F.rowPaddingTop - F.rowPaddingTopFirst;
345
+ var NARROW = `@container (width < ${CE_LABEL_ABOVE_BELOW_ROW_WIDTH}px)`;
346
+ var useStyles2 = makeStyles2({
347
+ // ── shared ──────────────────────────────────────────────────────────────
348
+ // Span every column when placed in a grid (v9 Section's body is repeat(12, 1fr)).
349
+ spanAll: { gridColumn: "1 / -1" },
350
+ // ── ce ──────────────────────────────────────────────────────────────────
351
+ ceRow: {
352
+ paddingTop: `${F.rowPaddingTop}px`,
353
+ minWidth: 0
354
+ },
355
+ ceContainer: { containerType: "inline-size" },
356
+ ceGrid: {
357
+ display: "grid",
358
+ alignItems: "start"
359
+ },
360
+ // ★ The column template lives in CLASSES, never in an inline style: an inline
361
+ // grid-template-columns beats the @container rule, so 'auto' never flipped to 'above'
362
+ // (caught measuring a 306px row in a real browser; jsdom cannot see it). A custom labelWidth
363
+ // reaches the class through the --sk-label-col custom property.
364
+ ceGridBeside: { gridTemplateColumns: "var(--sk-label-col) minmax(0, 1fr)" },
365
+ ceGridSingle: { gridTemplateColumns: "minmax(0, 1fr)" },
366
+ ceLabelBeside: {
367
+ display: "flex",
368
+ alignItems: "center",
369
+ minHeight: `${CE_LABEL_BOX}px`,
370
+ marginTop: `${CE_LABEL_OFFSET}px`,
371
+ // 184 − 176: the measured text width. A required marker is allowed into half of it (below).
372
+ paddingRight: `${F.labelColumnWidth - CE_LABEL_TEXT_WIDTH}px`
373
+ },
374
+ ceLabelAbove: {
375
+ display: "flex",
376
+ alignItems: "center",
377
+ marginTop: `${CE_CONTROL_OFFSET}px`,
378
+ minHeight: `${F.labelLineHeight}px`
379
+ },
380
+ ceControlBeside: {
381
+ marginTop: `${CE_CONTROL_OFFSET}px`,
382
+ marginBottom: `${CE_CONTROL_OFFSET}px`,
383
+ marginRight: `${CE_CONTROL_INSET_RIGHT}px`,
384
+ minWidth: 0
385
+ },
386
+ ceControlAbove: {
387
+ marginTop: `${F.labelAboveGap}px`,
388
+ marginBottom: `${CE_CONTROL_OFFSET}px`,
389
+ marginRight: `${CE_CONTROL_INSET_RIGHT}px`,
390
+ minWidth: 0
391
+ },
392
+ // 'auto': beside by default, above when the ROW is narrower than the (provisional) switch point.
393
+ ceAutoGrid: { [NARROW]: { gridTemplateColumns: "minmax(0, 1fr)" } },
394
+ ceAutoLabel: {
395
+ [NARROW]: {
396
+ marginTop: `${CE_CONTROL_OFFSET}px`,
397
+ minHeight: `${F.labelLineHeight}px`,
398
+ paddingRight: 0
399
+ }
400
+ },
401
+ ceAutoControl: { [NARROW]: { marginTop: `${F.labelAboveGap}px` } },
402
+ ceLabelText: {
403
+ minWidth: 0,
404
+ fontSize: tokens2.fontSizeBase300,
405
+ lineHeight: `${F.labelLineHeight}px`,
406
+ fontWeight: tokens2.fontWeightRegular,
407
+ color: tokens2.colorNeutralForeground1,
408
+ overflowWrap: "anywhere"
409
+ },
410
+ // Beside, the text fills the column so the marker sits at the column's end (measured: marker's
411
+ // right edge 180px from the row). Above, the marker follows the text (position unmeasured).
412
+ ceLabelTextFill: { flexGrow: 1 },
413
+ ceAutoLabelText: { [NARROW]: { flexGrow: 0 } },
414
+ ceRequired: {
415
+ flexShrink: 0,
416
+ color: tokens2.colorPaletteRedForeground1,
417
+ paddingLeft: `${CE_MARKER_GAP}px`
418
+ },
419
+ // Beside: the marker takes half the column's 8px padding → text 168.5 + 4 + 7.5 = 176 + 4.
420
+ ceRequiredBeside: { marginRight: `-${CE_MARKER_GAP}px` },
421
+ ceAutoRequired: { [NARROW]: { marginRight: 0 } },
422
+ // ── default ─────────────────────────────────────────────────────────────
423
+ defaultBeside: {
424
+ display: "grid",
425
+ alignItems: "center",
426
+ columnGap: "8px",
427
+ minHeight: "38px",
428
+ [`@media (max-width: ${BREAKPOINTS.sm}px)`]: {
429
+ gridTemplateColumns: "1fr !important",
430
+ alignItems: "flex-start",
431
+ minHeight: 0,
432
+ rowGap: "4px"
433
+ }
434
+ },
435
+ defaultAbove: {
436
+ display: "grid",
437
+ gridTemplateColumns: "1fr",
438
+ rowGap: "2px",
439
+ minHeight: "38px"
440
+ },
441
+ defaultLabel: {
442
+ fontSize: tokens2.fontSizeBase200,
443
+ fontWeight: tokens2.fontWeightSemibold,
444
+ color: tokens2.colorNeutralForeground1,
445
+ lineHeight: "1.3",
446
+ overflowWrap: "anywhere"
447
+ },
448
+ // v8 FieldRow's marker: colors.danger, semibold, 2px after the text.
449
+ defaultRequired: {
450
+ color: colors.danger,
451
+ marginLeft: "2px",
452
+ fontWeight: tokens2.fontWeightSemibold
453
+ }
454
+ });
455
+ var toCssLength = (v) => typeof v === "number" ? `${v}px` : v;
456
+ var FieldRow = ({
457
+ label,
458
+ required,
459
+ htmlFor,
460
+ labelPosition,
461
+ labelWidth,
462
+ look: lookProp,
463
+ className,
464
+ style,
465
+ children
466
+ }) => {
467
+ const styles = useStyles2();
468
+ const ambientLook = useLook();
469
+ const look = lookProp ?? ambientLook;
470
+ const ce = look === "ce";
471
+ const position = labelPosition ?? (ce ? "auto" : "beside");
472
+ const hasLabel = label != null;
473
+ const column = toCssLength(labelWidth ?? (ce ? F.labelColumnWidth : 130));
474
+ const LabelTag = htmlFor ? "label" : "span";
475
+ if (!ce) {
476
+ const beside2 = position !== "above" && hasLabel;
477
+ return /* @__PURE__ */ jsxs(
478
+ "div",
479
+ {
480
+ className: mergeClasses2(styles.spanAll, beside2 ? styles.defaultBeside : styles.defaultAbove, className),
481
+ style: { ...beside2 ? { gridTemplateColumns: `${column} 1fr` } : {}, ...style },
482
+ "data-surface-part": "field-row",
483
+ "data-look": "default",
484
+ children: [
485
+ hasLabel && /* @__PURE__ */ jsxs(LabelTag, { htmlFor, className: styles.defaultLabel, "data-surface-part": "label", children: [
486
+ label,
487
+ required && /* @__PURE__ */ jsx3("span", { className: styles.defaultRequired, "aria-hidden": "true", "data-surface-part": "required", children: "*" })
488
+ ] }),
489
+ children
490
+ ]
491
+ }
492
+ );
493
+ }
494
+ const auto = position === "auto" && hasLabel;
495
+ const beside = position !== "above" && hasLabel;
496
+ return /* @__PURE__ */ jsx3(
497
+ "div",
498
+ {
499
+ className: mergeClasses2(styles.spanAll, styles.ceRow, auto && styles.ceContainer, className),
500
+ style,
501
+ "data-surface-part": "field-row",
502
+ "data-look": "ce",
503
+ "data-label-position": position,
504
+ "data-container": auto ? "inline-size" : void 0,
505
+ children: /* @__PURE__ */ jsxs(
506
+ "div",
507
+ {
508
+ className: mergeClasses2(styles.ceGrid, beside ? styles.ceGridBeside : styles.ceGridSingle, auto && styles.ceAutoGrid),
509
+ style: beside ? { "--sk-label-col": column } : void 0,
510
+ "data-surface-part": "field-grid",
511
+ children: [
512
+ hasLabel && /* @__PURE__ */ jsxs(
513
+ LabelTag,
514
+ {
515
+ htmlFor,
516
+ className: mergeClasses2(beside ? styles.ceLabelBeside : styles.ceLabelAbove, auto && styles.ceAutoLabel),
517
+ "data-surface-part": "label",
518
+ children: [
519
+ /* @__PURE__ */ jsx3(
520
+ "span",
521
+ {
522
+ className: mergeClasses2(styles.ceLabelText, beside && styles.ceLabelTextFill, auto && styles.ceAutoLabelText),
523
+ "data-surface-part": "label-text",
524
+ children: label
525
+ }
526
+ ),
527
+ required && /* @__PURE__ */ jsx3(
528
+ "span",
529
+ {
530
+ className: mergeClasses2(styles.ceRequired, beside && styles.ceRequiredBeside, auto && styles.ceAutoRequired),
531
+ "aria-hidden": "true",
532
+ "data-surface-part": "required",
533
+ children: "*"
534
+ }
535
+ )
536
+ ]
537
+ }
538
+ ),
539
+ /* @__PURE__ */ jsx3(
540
+ "div",
541
+ {
542
+ className: mergeClasses2(
543
+ // No label: the control sits where a beside control would (2px down), full width.
544
+ !hasLabel || beside ? styles.ceControlBeside : styles.ceControlAbove,
545
+ auto && styles.ceAutoControl
546
+ ),
547
+ "data-surface-part": "control",
548
+ children
549
+ }
550
+ )
551
+ ]
552
+ }
553
+ )
554
+ }
555
+ );
556
+ };
278
557
 
279
558
  // src/v9/containers/SectionHeader.tsx
280
559
  import {
@@ -282,10 +561,10 @@ import {
282
561
  Text,
283
562
  Toolbar,
284
563
  ToolbarButton,
285
- tokens as tokens2
564
+ tokens as tokens3
286
565
  } from "@fluentui/react-components";
287
566
  import { ChevronDown20Regular, ChevronRight20Regular } from "@fluentui/react-icons";
288
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
567
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
289
568
  var SectionHeader = ({
290
569
  title,
291
570
  statusText,
@@ -294,14 +573,26 @@ var SectionHeader = ({
294
573
  actions,
295
574
  collapsible,
296
575
  collapsed,
297
- onToggle
576
+ onToggle,
577
+ look: lookProp
298
578
  }) => {
579
+ const ambientLook = useLook();
580
+ const ce = (lookProp ?? ambientLook) === "ce";
581
+ const ceRootStyle = {
582
+ display: "flex",
583
+ justifyContent: "space-between",
584
+ alignItems: "center",
585
+ flexWrap: "nowrap",
586
+ paddingTop: ceForm.section.titlePaddingTop,
587
+ minHeight: ceForm.section.titleHeight - ceForm.section.titlePaddingTop,
588
+ width: "100%"
589
+ };
299
590
  const rootStyle = {
300
591
  display: "flex",
301
592
  justifyContent: "space-between",
302
593
  alignItems: "center",
303
594
  flexWrap: "nowrap",
304
- borderBottom: `1px solid ${tokens2.colorNeutralStroke2}`,
595
+ borderBottom: `1px solid ${tokens3.colorNeutralStroke2}`,
305
596
  marginBottom: 16,
306
597
  minHeight: 48,
307
598
  width: "100%"
@@ -309,26 +600,40 @@ var SectionHeader = ({
309
600
  const leftStyle = { display: "flex", alignItems: "center", gap: 8, minWidth: 0 };
310
601
  const statusStyle = {
311
602
  marginLeft: 8,
312
- fontSize: tokens2.fontSizeBase200,
313
- color: tokens2.colorNeutralForeground3
603
+ fontSize: tokens3.fontSizeBase200,
604
+ color: tokens3.colorNeutralForeground3
314
605
  };
315
- return /* @__PURE__ */ jsxs("div", { style: rootStyle, children: [
316
- /* @__PURE__ */ jsxs("div", { style: leftStyle, children: [
317
- collapsible && /* @__PURE__ */ jsx3(
606
+ return /* @__PURE__ */ jsxs2("div", { style: ce ? ceRootStyle : rootStyle, "data-surface-part": "section-header", children: [
607
+ /* @__PURE__ */ jsxs2("div", { style: leftStyle, children: [
608
+ collapsible && /* @__PURE__ */ jsx4(
318
609
  Button,
319
610
  {
320
611
  appearance: "subtle",
321
612
  size: "small",
322
- icon: collapsed ? /* @__PURE__ */ jsx3(ChevronRight20Regular, {}) : /* @__PURE__ */ jsx3(ChevronDown20Regular, {}),
613
+ icon: collapsed ? /* @__PURE__ */ jsx4(ChevronRight20Regular, {}) : /* @__PURE__ */ jsx4(ChevronDown20Regular, {}),
323
614
  onClick: onToggle,
324
615
  "aria-label": collapsed ? "Expand section" : "Collapse section",
325
616
  "aria-expanded": !collapsed
326
617
  }
327
618
  ),
328
- title && /* @__PURE__ */ jsx3(Text, { weight: "semibold", size: 300, children: title }),
329
- statusText && /* @__PURE__ */ jsx3("span", { style: statusStyle, children: statusText })
619
+ title && (ce ? (
620
+ // Rendered exactly as given: Dynamics does not uppercase section titles (the stock
621
+ // Account labels are typed uppercase; "Description" renders mixed-case).
622
+ /* @__PURE__ */ jsx4(
623
+ Text,
624
+ {
625
+ as: "h2",
626
+ weight: "semibold",
627
+ size: 300,
628
+ style: { margin: 0, lineHeight: `${ceForm.section.titleLineHeight}px`, color: tokens3.colorNeutralForeground1 },
629
+ "data-surface-part": "section-title",
630
+ children: title
631
+ }
632
+ )
633
+ ) : /* @__PURE__ */ jsx4(Text, { weight: "semibold", size: 300, children: title })),
634
+ statusText && /* @__PURE__ */ jsx4("span", { style: statusStyle, children: statusText })
330
635
  ] }),
331
- actions ? /* @__PURE__ */ jsx3("div", { children: actions }) : showCommandBar && commandItems.length > 0 ? /* @__PURE__ */ jsx3(Toolbar, { "aria-label": "Section commands", size: "small", children: commandItems.map((item) => /* @__PURE__ */ jsx3(
636
+ actions ? /* @__PURE__ */ jsx4("div", { children: actions }) : showCommandBar && commandItems.length > 0 ? /* @__PURE__ */ jsx4(Toolbar, { "aria-label": "Section commands", size: "small", children: commandItems.map((item) => /* @__PURE__ */ jsx4(
332
637
  ToolbarButton,
333
638
  {
334
639
  icon: item.icon,
@@ -343,8 +648,18 @@ var SectionHeader = ({
343
648
  };
344
649
 
345
650
  // src/v9/containers/Section.tsx
346
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
347
- var useStyles2 = makeStyles2({
651
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
652
+ var px = (v) => v.map((n) => `${n}px`).join(" ");
653
+ function columnsOf(children) {
654
+ const out = [];
655
+ const walk = (n) => {
656
+ if (Array.isArray(n)) n.forEach(walk);
657
+ else if (!(n === null || n === void 0 || typeof n === "boolean" || n === "")) out.push(n);
658
+ };
659
+ walk(children);
660
+ return out;
661
+ }
662
+ var useStyles3 = makeStyles3({
348
663
  // Phone-stack the internal field grid below `sm` (griffel — inline can't do @media).
349
664
  bodyStack: {
350
665
  [`@media (max-width: ${BREAKPOINTS.sm}px)`]: { "& > *": { gridColumn: "1 / -1" } }
@@ -355,7 +670,7 @@ var Section = ({
355
670
  columnSpan = 12,
356
671
  columnStart,
357
672
  rowPosition,
358
- internalColumns = 12,
673
+ internalColumns: internalColumnsProp,
359
674
  showCommandBar,
360
675
  commandItems,
361
676
  statusText,
@@ -367,11 +682,15 @@ var Section = ({
367
682
  variant = "card",
368
683
  minHeight = 80,
369
684
  density: densityProp,
685
+ look: lookProp,
370
686
  className,
371
687
  style,
372
688
  children
373
689
  }) => {
374
- const styles = useStyles2();
690
+ const styles = useStyles3();
691
+ const internalColumns = internalColumnsProp ?? 12;
692
+ const ambientLook = useLook();
693
+ const ce = (lookProp ?? ambientLook) === "ce" && variant === "card";
375
694
  const [internalCollapsed, setInternalCollapsed] = useState3(defaultCollapsed);
376
695
  const collapsed = controlledCollapsed ?? internalCollapsed;
377
696
  const toggle = () => {
@@ -392,41 +711,102 @@ var Section = ({
392
711
  if (variant === "placeholder") {
393
712
  const placeholderStyle = {
394
713
  ...rootStyle,
395
- border: `1px dashed ${tokens3.colorNeutralStroke2}`,
396
- borderRadius: tokens3.borderRadiusMedium,
714
+ border: `1px dashed ${tokens4.colorNeutralStroke2}`,
715
+ borderRadius: tokens4.borderRadiusMedium,
397
716
  minHeight,
398
717
  width: "100%",
399
718
  background: "transparent"
400
719
  };
401
- return /* @__PURE__ */ jsx4("div", { className, style: placeholderStyle });
720
+ return /* @__PURE__ */ jsx5("div", { className, style: placeholderStyle });
402
721
  }
403
722
  const chrome = variant === "flat" ? {
404
- backgroundColor: tokens3.colorNeutralBackground1,
405
- borderRadius: tokens3.borderRadiusMedium,
723
+ backgroundColor: tokens4.colorNeutralBackground1,
724
+ borderRadius: tokens4.borderRadiusMedium,
406
725
  padding: cardPad,
407
726
  minWidth: 300,
408
727
  width: "100%",
409
728
  overflow: "hidden"
410
729
  } : {
411
- backgroundColor: tokens3.colorNeutralBackground1,
412
- border: `1px solid ${tokens3.colorNeutralStroke2}`,
413
- borderRadius: tokens3.borderRadiusMedium,
414
- boxShadow: tokens3.shadow4,
730
+ backgroundColor: tokens4.colorNeutralBackground1,
731
+ border: `1px solid ${tokens4.colorNeutralStroke2}`,
732
+ borderRadius: tokens4.borderRadiusMedium,
733
+ boxShadow: tokens4.shadow4,
415
734
  padding: cardPad,
416
735
  minWidth: 300,
417
736
  width: "100%",
418
737
  overflow: "hidden"
419
738
  };
420
739
  const showHeader = Boolean(title) || showCommandBar || collapsible;
740
+ if (ce) {
741
+ const n = Math.max(1, Math.round(internalColumnsProp ?? 1));
742
+ const ceChrome = {
743
+ backgroundColor: tokens4.colorNeutralBackground1,
744
+ border: "1px solid transparent",
745
+ borderRadius: tokens4.borderRadiusXLarge,
746
+ boxShadow: tokens4.shadow4,
747
+ padding: px(ceForm.section.padding),
748
+ width: "100%",
749
+ boxSizing: "border-box"
750
+ };
751
+ const cols = n > 1 ? columnsOf(children) : null;
752
+ if (cols && cols.length !== n && typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
753
+ console.warn(
754
+ `[surface-kit] Section look="ce" with internalColumns={${n}} got ${cols.length} children. A multi-column CE section takes ONE CHILD PER COLUMN (wrap each column's FieldRows in an element).`
755
+ );
756
+ }
757
+ return /* @__PURE__ */ jsxs3("section", { className, style: { ...ceChrome, ...rootStyle }, "data-surface-part": "section", "data-look": "ce", children: [
758
+ notification && /* @__PURE__ */ jsx5("div", { children: notification }),
759
+ showHeader && /* @__PURE__ */ jsx5(
760
+ SectionHeader,
761
+ {
762
+ look: "ce",
763
+ title,
764
+ statusText,
765
+ showCommandBar,
766
+ commandItems,
767
+ collapsible,
768
+ collapsed,
769
+ onToggle: toggle
770
+ }
771
+ ),
772
+ !collapsed && (cols ? (
773
+ // PROVISIONAL: below the phone breakpoint the columns stack (the default look's rule);
774
+ // Dynamics' multi-column reflow is unmeasured.
775
+ /* @__PURE__ */ jsx5(
776
+ "div",
777
+ {
778
+ className: styles.bodyStack,
779
+ style: { display: "grid", gridTemplateColumns: `repeat(${n}, minmax(0, 1fr))`, alignItems: "start" },
780
+ "data-surface-part": "section-body",
781
+ children: cols.map((col, i) => /* @__PURE__ */ jsx5(
782
+ "div",
783
+ {
784
+ style: {
785
+ // Keyed to the COLUMN (i % n), not the list position: every column but the
786
+ // last carries the gutter, and only the first grid row is pulled up.
787
+ marginTop: i < n ? -ceFieldRowFirstOffset : 0,
788
+ paddingRight: i % n < n - 1 ? ceForm.section.columnGutter : 0,
789
+ minWidth: 0
790
+ },
791
+ "data-surface-part": "section-column",
792
+ children: col
793
+ },
794
+ React.isValidElement(col) && col.key != null ? col.key : `col-${i}`
795
+ ))
796
+ }
797
+ )
798
+ ) : /* @__PURE__ */ jsx5("div", { style: { marginTop: -ceFieldRowFirstOffset }, "data-surface-part": "section-body", children }))
799
+ ] });
800
+ }
421
801
  const bodyStyle = {
422
802
  display: "grid",
423
803
  gridTemplateColumns: `repeat(${internalColumns}, 1fr)`,
424
804
  gap: bodyGap,
425
805
  alignItems: "start"
426
806
  };
427
- return /* @__PURE__ */ jsxs2("div", { className, style: { ...chrome, ...rootStyle }, children: [
428
- notification && /* @__PURE__ */ jsx4("div", { style: { marginBottom: scaleSpacing(8, density) }, children: notification }),
429
- showHeader && /* @__PURE__ */ jsx4(
807
+ return /* @__PURE__ */ jsxs3("div", { className, style: { ...chrome, ...rootStyle }, children: [
808
+ notification && /* @__PURE__ */ jsx5("div", { style: { marginBottom: scaleSpacing(8, density) }, children: notification }),
809
+ showHeader && /* @__PURE__ */ jsx5(
430
810
  SectionHeader,
431
811
  {
432
812
  title,
@@ -438,20 +818,20 @@ var Section = ({
438
818
  onToggle: toggle
439
819
  }
440
820
  ),
441
- !collapsed && /* @__PURE__ */ jsx4("div", { className: mergeClasses2(styles.bodyStack), style: bodyStyle, children })
821
+ !collapsed && /* @__PURE__ */ jsx5("div", { className: mergeClasses3(styles.bodyStack), style: bodyStyle, children })
442
822
  ] });
443
823
  };
444
824
 
445
825
  // src/v9/containers/SectionCard.tsx
446
- import { tokens as tokens4 } from "@fluentui/react-components";
447
- import { jsx as jsx5 } from "react/jsx-runtime";
826
+ import { tokens as tokens5 } from "@fluentui/react-components";
827
+ import { jsx as jsx6 } from "react/jsx-runtime";
448
828
  var SectionCard = ({
449
- accentColor = tokens4.colorBrandStroke1,
829
+ accentColor = tokens5.colorBrandStroke1,
450
830
  accentWidth = 3,
451
831
  variant = "card",
452
832
  style,
453
833
  ...rest
454
- }) => /* @__PURE__ */ jsx5(
834
+ }) => /* @__PURE__ */ jsx6(
455
835
  Section,
456
836
  {
457
837
  variant,
@@ -461,54 +841,363 @@ var SectionCard = ({
461
841
  );
462
842
 
463
843
  // src/v9/containers/FormHeader.tsx
464
- import { Text as Text2, tokens as tokens5 } from "@fluentui/react-components";
465
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
466
- var FormHeader = ({
467
- title,
468
- subtitle,
469
- status,
470
- titleColor,
471
- subtitleColor,
472
- persona,
473
- actions,
474
- className
475
- }) => {
844
+ import React2 from "react";
845
+ import {
846
+ Avatar,
847
+ Button as Button2,
848
+ Menu,
849
+ MenuItemRadio,
850
+ MenuList,
851
+ MenuPopover,
852
+ MenuTrigger,
853
+ Text as Text2,
854
+ createFocusOutlineStyle,
855
+ makeStyles as makeStyles4,
856
+ tokens as tokens6
857
+ } from "@fluentui/react-components";
858
+ import { ChevronDown12Regular, ChevronDown20Regular as ChevronDown20Regular2, ChevronUp20Regular } from "@fluentui/react-icons";
859
+ import { Fragment, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
860
+ var H = ceForm.header;
861
+ var FIELD_TOP = 4;
862
+ var OWNER_AVATAR_TOP = 9;
863
+ var OWNER_NAME_GAP = 10;
864
+ var SUBTITLE_DOT_SPACING = 8;
865
+ var SUBTITLE_ROW_TOP = 0;
866
+ var EXPAND_GAP = 18;
867
+ var DIVIDER_TOP = 6;
868
+ var PRESENCE_RING = 2;
869
+ var PRESENCE_DOT = H.presenceSize - 2 * PRESENCE_RING;
870
+ var cePresenceBadgeStyle = Object.freeze({
871
+ width: PRESENCE_DOT,
872
+ height: PRESENCE_DOT,
873
+ boxSizing: "content-box",
874
+ // Fluent's badge carries 1px padding and a 10px icon; zero the padding and clip the icon to the dot.
875
+ padding: 0,
876
+ overflow: "hidden",
877
+ border: `${PRESENCE_RING}px solid ${tokens6.colorNeutralBackground1}`,
878
+ right: -PRESENCE_RING,
879
+ bottom: -PRESENCE_RING
880
+ });
881
+ var FIELDS_MIN_GAP = 16;
882
+ var CE_TITLE_MIN_WIDTH = 120;
883
+ var useStyles4 = makeStyles4({
884
+ // The owner name as a link-button: no chrome, but a VISIBLE keyboard focus ring (Fluent's).
885
+ ownerLink: {
886
+ background: "none",
887
+ border: "none",
888
+ padding: 0,
889
+ margin: 0,
890
+ font: "inherit",
891
+ color: tokens6.colorBrandForegroundLink,
892
+ cursor: "pointer",
893
+ ":hover": { color: tokens6.colorBrandForegroundLinkHover, textDecorationLine: "underline" },
894
+ ...createFocusOutlineStyle()
895
+ },
896
+ // Narrow headers: the title keeps a minimum width (it truncates with an ellipsis) and the fields
897
+ // block shrinks and clips rather than pushing past the card. Dynamics moves the fields into the
898
+ // header flyout at narrow widths (unmeasured, not modelled).
899
+ fields: {
900
+ display: "flex",
901
+ alignItems: "flex-start",
902
+ flexShrink: 1,
903
+ minWidth: 0,
904
+ overflow: "hidden"
905
+ },
906
+ switcher: {
907
+ display: "inline-flex",
908
+ alignItems: "center",
909
+ // Measured switcher 74.3 wide for "Account" (52.3): 2×2 padding + 2×1 border + 4 gap + 12 icon.
910
+ gap: "4px",
911
+ height: `${H.switcherHeight}px`,
912
+ padding: `0 ${H.switcherPaddingX}px`,
913
+ border: "1px solid transparent",
914
+ borderRadius: tokens6.borderRadiusMedium,
915
+ background: "transparent",
916
+ color: tokens6.colorNeutralForeground2,
917
+ fontFamily: "inherit",
918
+ fontSize: tokens6.fontSizeBase300,
919
+ fontWeight: tokens6.fontWeightSemibold,
920
+ lineHeight: tokens6.lineHeightBase300,
921
+ cursor: "pointer",
922
+ ":hover": { backgroundColor: tokens6.colorSubtleBackgroundHover },
923
+ ...createFocusOutlineStyle(),
924
+ // Measured OPEN: fill #e0e0e0 = colorSubtleBackgroundPressed (Fluent's MenuButton would use
925
+ // Selected, #ebebeb — so this is set explicitly) and text #242424 = colorNeutralForeground1
926
+ // (idle is #424242). ★ The open state must also win over :hover — the pointer is still on the
927
+ // trigger after the click that opened it, and hover's #f5f5f5 was what showed. The ce-parity
928
+ // gate checks the open trigger with the pointer on it AND away from it.
929
+ '&[aria-expanded="true"], &[aria-expanded="true"]:hover': {
930
+ backgroundColor: tokens6.colorSubtleBackgroundPressed,
931
+ color: tokens6.colorNeutralForeground1
932
+ }
933
+ }
934
+ });
935
+ var isEmpty = (v) => v === null || v === void 0 || v === "";
936
+ function FieldTile({ field }) {
937
+ return /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", paddingTop: FIELD_TOP, minWidth: 0 }, "data-surface-part": "header-field", children: [
938
+ /* @__PURE__ */ jsx7(Text2, { weight: "semibold", size: 300, wrap: false, style: { color: tokens6.colorNeutralForeground1 }, "data-surface-part": "header-field-value", children: isEmpty(field.value) ? "---" : field.value }),
939
+ /* @__PURE__ */ jsx7(Text2, { size: 200, wrap: false, style: { color: tokens6.colorNeutralForeground1 }, "data-surface-part": "header-field-label", children: field.label })
940
+ ] });
941
+ }
942
+ function Divider() {
943
+ return /* @__PURE__ */ jsx7(
944
+ "div",
945
+ {
946
+ "aria-hidden": "true",
947
+ style: {
948
+ width: H.dividerWidth,
949
+ height: H.dividerHeight,
950
+ margin: `${DIVIDER_TOP}px ${H.dividerSpacing}px 0`,
951
+ backgroundColor: tokens6.colorNeutralStroke2,
952
+ flexShrink: 0
953
+ },
954
+ "data-surface-part": "header-divider"
955
+ }
956
+ );
957
+ }
958
+ function CeFormHeader(props) {
959
+ const {
960
+ title,
961
+ subtitle,
962
+ status,
963
+ titleColor,
964
+ persona,
965
+ actions,
966
+ className,
967
+ entityName,
968
+ forms,
969
+ activeFormId,
970
+ onFormChange,
971
+ headerFields,
972
+ owner,
973
+ onExpand,
974
+ expanded,
975
+ titleAs
976
+ } = props;
977
+ const styles = useStyles4();
978
+ const activeForm = forms?.find((f) => f.id === activeFormId) ?? forms?.[0];
979
+ const entity = entityName ?? subtitle;
980
+ const avatar = persona ?? (typeof title === "string" ? /* @__PURE__ */ jsx7(Avatar, { name: title, color: "colorful", size: H.avatarSize, "aria-hidden": true }) : null);
981
+ const TitleTag = titleAs ?? "h1";
982
+ return /* @__PURE__ */ jsxs4(
983
+ "div",
984
+ {
985
+ className,
986
+ style: { display: "flex", alignItems: "flex-start", padding: H.padding.map((v) => `${v}px`).join(" "), minWidth: 0 },
987
+ "data-surface-part": "form-header",
988
+ "data-look": "ce",
989
+ children: [
990
+ avatar && // The avatar sits in a 2px transparent ring (tile 44 = 40 + 2 × 2), 14px before the title.
991
+ /* @__PURE__ */ jsx7("div", { style: { padding: H.avatarRing, marginRight: H.avatarToTitleGap, flexShrink: 0 }, "data-surface-part": "header-avatar", children: avatar }),
992
+ /* @__PURE__ */ jsxs4("div", { style: { minWidth: CE_TITLE_MIN_WIDTH, flex: "1 1 auto" }, children: [
993
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", alignItems: "baseline", minWidth: 0 }, children: [
994
+ title != null && /* @__PURE__ */ jsx7(
995
+ Text2,
996
+ {
997
+ as: TitleTag,
998
+ weight: "semibold",
999
+ size: 500,
1000
+ truncate: true,
1001
+ wrap: false,
1002
+ style: { margin: 0, lineHeight: `${H.titleLineHeight}px`, color: titleColor ?? tokens6.colorNeutralForeground1 },
1003
+ "data-surface-part": "header-title",
1004
+ children: title
1005
+ }
1006
+ ),
1007
+ status != null && /* @__PURE__ */ jsxs4(
1008
+ "span",
1009
+ {
1010
+ style: {
1011
+ paddingLeft: H.statusPaddingLeft,
1012
+ fontSize: tokens6.fontSizeBase300,
1013
+ lineHeight: `${H.titleLineHeight}px`,
1014
+ color: tokens6.colorNeutralForeground3,
1015
+ whiteSpace: "nowrap"
1016
+ },
1017
+ "data-surface-part": "header-status",
1018
+ children: [
1019
+ "- ",
1020
+ status
1021
+ ]
1022
+ }
1023
+ )
1024
+ ] }),
1025
+ (entity != null || activeForm) && /* @__PURE__ */ jsxs4("div", { style: { display: "flex", alignItems: "center", height: H.switcherHeight, marginTop: SUBTITLE_ROW_TOP }, "data-surface-part": "header-subtitle", children: [
1026
+ entity != null && /* @__PURE__ */ jsx7("span", { style: { fontSize: tokens6.fontSizeBase300, fontWeight: tokens6.fontWeightSemibold, color: tokens6.colorNeutralForeground2 }, children: entity }),
1027
+ entity != null && activeForm && /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", style: { margin: `0 ${SUBTITLE_DOT_SPACING}px`, color: tokens6.colorNeutralForeground2, lineHeight: "20px" }, children: "\xB7" }),
1028
+ activeForm && (forms && forms.length > 1 ? /* @__PURE__ */ jsxs4(
1029
+ Menu,
1030
+ {
1031
+ checkedValues: { form: [activeForm.id] },
1032
+ onCheckedValueChange: (_e, data) => {
1033
+ const id = data.checkedItems[0];
1034
+ if (id && id !== activeForm.id) onFormChange?.(id);
1035
+ },
1036
+ children: [
1037
+ /* @__PURE__ */ jsx7(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxs4("button", { type: "button", className: styles.switcher, "aria-label": `Form: ${activeForm.label}`, "data-surface-part": "form-switcher", children: [
1038
+ activeForm.label,
1039
+ /* @__PURE__ */ jsx7(ChevronDown12Regular, {})
1040
+ ] }) }),
1041
+ /* @__PURE__ */ jsx7(MenuPopover, { children: /* @__PURE__ */ jsx7(MenuList, { children: forms.map((f) => /* @__PURE__ */ jsx7(MenuItemRadio, { name: "form", value: f.id, children: f.label }, f.id)) }) })
1042
+ ]
1043
+ }
1044
+ ) : /* @__PURE__ */ jsx7("span", { style: { fontSize: tokens6.fontSizeBase300, fontWeight: tokens6.fontWeightSemibold, color: tokens6.colorNeutralForeground2 }, children: activeForm.label }))
1045
+ ] })
1046
+ ] }),
1047
+ (headerFields?.length || owner || actions) && /* @__PURE__ */ jsxs4("div", { className: styles.fields, style: { marginLeft: FIELDS_MIN_GAP }, "data-surface-part": "header-fields", children: [
1048
+ headerFields?.map((f, i) => /* @__PURE__ */ jsxs4(React2.Fragment, { children: [
1049
+ i > 0 && /* @__PURE__ */ jsx7(Divider, {}),
1050
+ /* @__PURE__ */ jsx7(FieldTile, { field: f })
1051
+ ] }, f.id ?? `${f.label}-${i}`)),
1052
+ owner && /* @__PURE__ */ jsxs4(Fragment, { children: [
1053
+ headerFields?.length ? /* @__PURE__ */ jsx7(Divider, {}) : null,
1054
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", alignItems: "flex-start" }, "data-surface-part": "header-owner", children: [
1055
+ /* @__PURE__ */ jsx7("div", { style: { paddingTop: OWNER_AVATAR_TOP, marginRight: OWNER_NAME_GAP }, children: owner.avatar ?? /* @__PURE__ */ jsx7(
1056
+ Avatar,
1057
+ {
1058
+ name: owner.name,
1059
+ color: "colorful",
1060
+ size: H.ownerAvatarSize,
1061
+ badge: owner.presence ? { status: owner.presence, size: "extra-small", style: cePresenceBadgeStyle } : void 0
1062
+ }
1063
+ ) }),
1064
+ /* @__PURE__ */ jsx7(
1065
+ FieldTile,
1066
+ {
1067
+ field: {
1068
+ label: owner.label ?? "Owner",
1069
+ value: owner.onClick ? /* @__PURE__ */ jsx7("button", { type: "button", onClick: owner.onClick, className: styles.ownerLink, "data-surface-part": "header-owner-link", children: owner.name }) : /* @__PURE__ */ jsx7("span", { style: { color: tokens6.colorBrandForegroundLink }, children: owner.name })
1070
+ }
1071
+ }
1072
+ )
1073
+ ] })
1074
+ ] }),
1075
+ actions != null && /* @__PURE__ */ jsx7("div", { children: actions })
1076
+ ] }),
1077
+ onExpand && /* @__PURE__ */ jsx7(
1078
+ Button2,
1079
+ {
1080
+ appearance: "subtle",
1081
+ icon: expanded ? /* @__PURE__ */ jsx7(ChevronUp20Regular, {}) : /* @__PURE__ */ jsx7(ChevronDown20Regular2, {}),
1082
+ "aria-label": expanded ? "Collapse header" : "Expand header",
1083
+ "aria-expanded": !!expanded,
1084
+ onClick: onExpand,
1085
+ style: { marginLeft: EXPAND_GAP, flexShrink: 0, minWidth: H.expandButtonSize, width: H.expandButtonSize, height: H.expandButtonSize },
1086
+ "data-surface-part": "header-expand"
1087
+ }
1088
+ )
1089
+ ]
1090
+ }
1091
+ );
1092
+ }
1093
+ var FormHeader = (props) => {
1094
+ const ambientLook = useLook();
1095
+ if ((props.look ?? ambientLook) === "ce") return /* @__PURE__ */ jsx7(CeFormHeader, { ...props });
1096
+ const { title, subtitle, status, titleColor, subtitleColor, persona, actions, className } = props;
476
1097
  const rootStyle = {
477
1098
  display: "flex",
478
1099
  alignItems: "center",
479
1100
  justifyContent: "space-between",
480
1101
  gap: 12,
481
1102
  padding: "12px 24px",
482
- borderBottom: `1px solid ${tokens5.colorNeutralStroke2}`,
483
- backgroundColor: tokens5.colorNeutralBackground1
1103
+ borderBottom: `1px solid ${tokens6.colorNeutralStroke2}`,
1104
+ backgroundColor: tokens6.colorNeutralBackground1
484
1105
  };
485
1106
  const mainStyle = { display: "flex", alignItems: "center", gap: 12, minWidth: 0 };
486
1107
  const titleRowStyle = { display: "flex", alignItems: "baseline", gap: 8, flexWrap: "wrap" };
487
- const statusStyle = { fontSize: tokens5.fontSizeBase200, color: tokens5.colorNeutralForeground3 };
1108
+ const statusStyle = { fontSize: tokens6.fontSizeBase200, color: tokens6.colorNeutralForeground3 };
488
1109
  const subtitleStyle = {
489
- fontSize: tokens5.fontSizeBase200,
490
- color: subtitleColor || tokens5.colorNeutralForeground3,
1110
+ fontSize: tokens6.fontSizeBase200,
1111
+ color: subtitleColor || tokens6.colorNeutralForeground3,
491
1112
  marginTop: 2
492
1113
  };
493
- return /* @__PURE__ */ jsxs3("div", { className, style: rootStyle, children: [
494
- /* @__PURE__ */ jsxs3("div", { style: mainStyle, children: [
1114
+ return /* @__PURE__ */ jsxs4("div", { className, style: rootStyle, children: [
1115
+ /* @__PURE__ */ jsxs4("div", { style: mainStyle, children: [
495
1116
  persona,
496
- /* @__PURE__ */ jsxs3("div", { children: [
497
- /* @__PURE__ */ jsxs3("div", { style: titleRowStyle, children: [
498
- title != null && /* @__PURE__ */ jsx6(Text2, { weight: "semibold", size: 400, style: titleColor ? { color: titleColor } : void 0, children: title }),
499
- status != null && /* @__PURE__ */ jsx6("span", { style: statusStyle, children: status })
1117
+ /* @__PURE__ */ jsxs4("div", { children: [
1118
+ /* @__PURE__ */ jsxs4("div", { style: titleRowStyle, children: [
1119
+ title != null && /* @__PURE__ */ jsx7(Text2, { weight: "semibold", size: 400, style: titleColor ? { color: titleColor } : void 0, children: title }),
1120
+ status != null && /* @__PURE__ */ jsx7("span", { style: statusStyle, children: status })
500
1121
  ] }),
501
- subtitle != null && /* @__PURE__ */ jsx6("div", { style: subtitleStyle, children: subtitle })
1122
+ subtitle != null && /* @__PURE__ */ jsx7("div", { style: subtitleStyle, children: subtitle })
502
1123
  ] })
503
1124
  ] }),
504
- actions != null && /* @__PURE__ */ jsx6("div", { children: actions })
1125
+ actions != null && /* @__PURE__ */ jsx7("div", { children: actions })
505
1126
  ] });
506
1127
  };
507
1128
 
508
1129
  // src/v9/containers/PivotSurface.tsx
509
- import { useState as useState4 } from "react";
510
- import { TabList, Tab } from "@fluentui/react-components";
511
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1130
+ import { useId, useState as useState4 } from "react";
1131
+ import {
1132
+ TabList,
1133
+ Tab,
1134
+ makeStyles as makeStyles5,
1135
+ tabClassNames,
1136
+ tokens as tokens7
1137
+ } from "@fluentui/react-components";
1138
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1139
+ var FLUENT_TAB_RESERVED_SPACE_CLASS = "fui-Tab__content--reserved-space";
1140
+ var T = ceForm.tabs;
1141
+ var UNDERLINE_BOTTOM = 5;
1142
+ var useStyles5 = makeStyles5({
1143
+ ceCard: {
1144
+ minWidth: 0,
1145
+ backgroundColor: tokens7.colorNeutralBackground1,
1146
+ border: "1px solid transparent",
1147
+ borderRadius: tokens7.borderRadiusXLarge,
1148
+ boxShadow: tokens7.shadow4
1149
+ },
1150
+ ceStrip: {
1151
+ padding: T.stripPadding.map((v) => `${v}px`).join(" "),
1152
+ columnGap: `${T.gap}px`,
1153
+ // PROVISIONAL: tabs that don't fit are clipped. Dynamics folds them into a "Related ▾" /
1154
+ // overflow menu, which is unmeasured and not modelled.
1155
+ overflow: "hidden"
1156
+ },
1157
+ ceTab: {
1158
+ height: `${T.tabHeight}px`,
1159
+ padding: `0 0 ${UNDERLINE_BOTTOM}px`,
1160
+ alignItems: "flex-end",
1161
+ fontSize: `${T.fontSize}px`,
1162
+ lineHeight: `${T.lineHeight}px`,
1163
+ color: tokens7.colorNeutralForeground1,
1164
+ [`& .${tabClassNames.content}`]: {
1165
+ padding: 0,
1166
+ fontSize: `${T.fontSize}px`,
1167
+ lineHeight: `${T.lineHeight}px`,
1168
+ // Idle labels are the measured #242424 too (Fluent's transparent appearance would use
1169
+ // foreground2, #424242).
1170
+ color: tokens7.colorNeutralForeground1
1171
+ },
1172
+ // Dynamics, like Fluent, reserves each tab's SEMIBOLD width (a hidden zero-height copy of the
1173
+ // label), so tabs don't shift on selection: an unselected "Web API Probe" is 109.6 wide, its
1174
+ // semibold width in the same Segoe UI Web file. Fluent's reserved copy keeps its own 2px side
1175
+ // padding, which made it 113.6 — zero it like the visible content.
1176
+ [`& .${FLUENT_TAB_RESERVED_SPACE_CLASS}`]: {
1177
+ padding: 0,
1178
+ fontSize: `${T.fontSize}px`
1179
+ },
1180
+ // Fluent draws the selected (and hover) indicator on ::after / ::before; move both to the
1181
+ // measured position and shape.
1182
+ "::after": {
1183
+ left: 0,
1184
+ right: 0,
1185
+ bottom: `${UNDERLINE_BOTTOM}px`,
1186
+ height: `${T.underlineHeight}px`,
1187
+ borderRadius: `${T.underlineRadius}px`
1188
+ },
1189
+ "::before": {
1190
+ left: 0,
1191
+ right: 0,
1192
+ bottom: `${UNDERLINE_BOTTOM}px`,
1193
+ height: `${T.underlineHeight}px`,
1194
+ borderRadius: `${T.underlineRadius}px`
1195
+ },
1196
+ // Fluent's hover/pressed indicator sets a circular radius at higher specificity; match it.
1197
+ ":hover::before": { borderRadius: `${T.underlineRadius}px` },
1198
+ ":active::before": { borderRadius: `${T.underlineRadius}px` }
1199
+ }
1200
+ });
512
1201
  var PivotSurface = ({
513
1202
  tabs,
514
1203
  selectedId,
@@ -516,8 +1205,15 @@ var PivotSurface = ({
516
1205
  onTabChange,
517
1206
  appearance = "transparent",
518
1207
  size = "medium",
519
- className
1208
+ className,
1209
+ look: lookProp,
1210
+ header
520
1211
  }) => {
1212
+ const styles = useStyles5();
1213
+ const ce = lookProp === "ce";
1214
+ const baseId = useId();
1215
+ const tabId = (id) => `${baseId}-tab-${id}`;
1216
+ const panelId = `${baseId}-panel`;
521
1217
  const firstEnabledId = tabs.find((t) => !t.disabled)?.id ?? tabs[0]?.id;
522
1218
  const [internal, setInternal] = useState4(defaultSelectedId ?? firstEnabledId);
523
1219
  const selected = selectedId ?? internal;
@@ -527,66 +1223,432 @@ var PivotSurface = ({
527
1223
  onTabChange?.(id);
528
1224
  };
529
1225
  const active = tabs.find((t) => t.id === selected) ?? tabs[0];
530
- return /* @__PURE__ */ jsxs4("div", { className, children: [
531
- /* @__PURE__ */ jsx7(TabList, { selectedValue: selected, onTabSelect: handleSelect, appearance, size, children: tabs.map((t) => /* @__PURE__ */ jsx7(Tab, { value: t.id, icon: t.icon, disabled: t.disabled, children: t.label }, t.id)) }),
532
- /* @__PURE__ */ jsx7("div", { children: active?.content })
1226
+ if (ce) {
1227
+ const [bodyTop, , bodyBottom] = ceForm.tabBody.padding;
1228
+ return /* @__PURE__ */ jsxs5(
1229
+ "div",
1230
+ {
1231
+ className,
1232
+ style: { padding: `0 ${ceForm.page.insetRight}px 0 ${ceForm.page.insetLeft}px`, minWidth: 0 },
1233
+ "data-surface-part": "pivot",
1234
+ "data-look": "ce",
1235
+ children: [
1236
+ /* @__PURE__ */ jsxs5("div", { className: styles.ceCard, "data-surface-part": "header-card", children: [
1237
+ header,
1238
+ /* @__PURE__ */ jsx8(
1239
+ TabList,
1240
+ {
1241
+ className: styles.ceStrip,
1242
+ selectedValue: selected,
1243
+ onTabSelect: handleSelect,
1244
+ appearance: "transparent",
1245
+ size: "large",
1246
+ "data-surface-part": "tab-strip",
1247
+ children: tabs.map((t) => /* @__PURE__ */ jsx8(
1248
+ Tab,
1249
+ {
1250
+ value: t.id,
1251
+ icon: t.icon,
1252
+ disabled: t.disabled,
1253
+ className: styles.ceTab,
1254
+ id: tabId(t.id),
1255
+ "aria-controls": t.id === active?.id ? panelId : void 0,
1256
+ children: t.label
1257
+ },
1258
+ t.id
1259
+ ))
1260
+ }
1261
+ )
1262
+ ] }),
1263
+ /* @__PURE__ */ jsx8(
1264
+ "div",
1265
+ {
1266
+ role: "tabpanel",
1267
+ id: panelId,
1268
+ "aria-labelledby": active ? tabId(active.id) : void 0,
1269
+ style: { paddingTop: bodyTop, paddingBottom: bodyBottom },
1270
+ "data-surface-part": "tab-body",
1271
+ children: active?.content
1272
+ }
1273
+ )
1274
+ ]
1275
+ }
1276
+ );
1277
+ }
1278
+ return /* @__PURE__ */ jsxs5("div", { className, children: [
1279
+ header,
1280
+ /* @__PURE__ */ jsx8(TabList, { selectedValue: selected, onTabSelect: handleSelect, appearance, size, children: tabs.map((t) => /* @__PURE__ */ jsx8(
1281
+ Tab,
1282
+ {
1283
+ value: t.id,
1284
+ icon: t.icon,
1285
+ disabled: t.disabled,
1286
+ id: tabId(t.id),
1287
+ "aria-controls": t.id === active?.id ? panelId : void 0,
1288
+ children: t.label
1289
+ },
1290
+ t.id
1291
+ )) }),
1292
+ /* @__PURE__ */ jsx8("div", { role: "tabpanel", id: panelId, "aria-labelledby": active ? tabId(active.id) : void 0, "data-surface-part": "tab-body", children: active?.content })
533
1293
  ] });
534
1294
  };
535
1295
 
536
1296
  // src/v9/containers/CommandSurface.tsx
1297
+ import React4 from "react";
537
1298
  import {
1299
+ Button as Button3,
538
1300
  Toolbar as Toolbar2,
539
1301
  ToolbarButton as ToolbarButton2,
540
- Menu,
541
- MenuTrigger,
542
- MenuPopover,
543
- MenuList,
544
- MenuItem
1302
+ ToolbarDivider,
1303
+ Menu as Menu2,
1304
+ MenuTrigger as MenuTrigger2,
1305
+ MenuPopover as MenuPopover2,
1306
+ MenuList as MenuList2,
1307
+ MenuItem,
1308
+ buttonClassNames,
1309
+ makeStyles as makeStyles6,
1310
+ mergeClasses as mergeClasses4,
1311
+ tokens as tokens8
545
1312
  } from "@fluentui/react-components";
546
- import { MoreHorizontal20Regular } from "@fluentui/react-icons";
547
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1313
+ import {
1314
+ ArrowLeft20Regular,
1315
+ ChevronDown12Regular as ChevronDown12Regular2,
1316
+ ChevronDown16Regular,
1317
+ MoreHorizontal20Regular,
1318
+ MoreVertical16Regular,
1319
+ WindowNew20Regular
1320
+ } from "@fluentui/react-icons";
1321
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1322
+ function ItemMenu({ items, trigger }) {
1323
+ return /* @__PURE__ */ jsxs6(Menu2, { children: [
1324
+ /* @__PURE__ */ jsx9(MenuTrigger2, { disableButtonEnhancement: true, children: trigger }),
1325
+ /* @__PURE__ */ jsx9(MenuPopover2, { children: /* @__PURE__ */ jsx9(MenuList2, { children: items.map((m) => /* @__PURE__ */ jsx9(MenuItem, { icon: m.icon, disabled: m.disabled, onClick: m.onClick, children: m.label }, m.id)) }) })
1326
+ ] });
1327
+ }
548
1328
  function renderToolbarButton(item) {
549
- return /* @__PURE__ */ jsx8(
1329
+ const button = /* @__PURE__ */ jsx9(
550
1330
  ToolbarButton2,
551
1331
  {
552
1332
  icon: item.icon,
553
1333
  appearance: item.appearance === "primary" ? "primary" : "subtle",
554
1334
  disabled: item.disabled,
555
- onClick: item.onClick,
1335
+ onClick: item.menuItems?.length ? void 0 : item.onClick,
556
1336
  children: item.label
557
1337
  },
558
1338
  item.id
559
1339
  );
1340
+ if (!item.menuItems?.length) return button;
1341
+ if (!item.split) return /* @__PURE__ */ jsx9(ItemMenu, { items: item.menuItems, trigger: button }, item.id);
1342
+ return /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
1343
+ React4.cloneElement(button, { onClick: item.onClick }),
1344
+ /* @__PURE__ */ jsx9(
1345
+ ItemMenu,
1346
+ {
1347
+ items: item.menuItems,
1348
+ trigger: /* @__PURE__ */ jsx9(
1349
+ ToolbarButton2,
1350
+ {
1351
+ appearance: "subtle",
1352
+ "aria-label": `More ${item.label} options`,
1353
+ icon: /* @__PURE__ */ jsx9(ChevronDown16Regular, {}),
1354
+ disabled: item.disabled
1355
+ }
1356
+ )
1357
+ }
1358
+ )
1359
+ ] }, item.id);
560
1360
  }
561
- var CommandSurface = ({
562
- items,
563
- overflowItems,
564
- farItems,
565
- size = "small",
566
- className
567
- }) => {
1361
+ var CB = ceForm.commandBar;
1362
+ var FLUENT_BORDER = 1;
1363
+ var FOCUS_ROOM = 2;
1364
+ var useStyles6 = makeStyles6({
1365
+ root: {
1366
+ minWidth: 0,
1367
+ // Page insets (16 left / 20 right), 8px from the top, 16px gap to the header card. A class
1368
+ // (not an inline style) so a host's className can override it.
1369
+ padding: `${CB.marginTop}px ${ceForm.page.insetRight}px ${ceForm.header.marginTop}px ${ceForm.page.commandBarInsetLeft}px`
1370
+ },
1371
+ card: {
1372
+ display: "flex",
1373
+ alignItems: "center",
1374
+ minWidth: 0,
1375
+ boxSizing: "border-box",
1376
+ height: `${CB.cardHeight}px`,
1377
+ backgroundColor: tokens8.colorNeutralBackground1,
1378
+ border: "1px solid transparent",
1379
+ borderRadius: tokens8.borderRadiusXLarge,
1380
+ boxShadow: tokens8.shadow4
1381
+ },
1382
+ group: { display: "flex", alignItems: "center", flexShrink: 0 },
1383
+ nav: { marginLeft: `${CB.navInsetLeft}px` },
1384
+ navButton: {
1385
+ height: `${CB.buttonHeight}px`,
1386
+ minWidth: 0,
1387
+ // Fluent caps icon-only buttons at 32px; the measured back/pop-out/overflow are wider.
1388
+ maxWidth: "none",
1389
+ padding: 0,
1390
+ flexShrink: 0
1391
+ },
1392
+ divider: {
1393
+ flexGrow: 0,
1394
+ height: `${CB.dividerHeight}px`,
1395
+ padding: 0,
1396
+ // Measured line colour #d1d1d1 = colorNeutralStroke1 (ToolbarDivider has no `appearance`
1397
+ // prop, so the Divider's pseudo-element halves are recoloured; both sides, for RTL).
1398
+ "::before": { borderRightColor: tokens8.colorNeutralStroke1, borderLeftColor: tokens8.colorNeutralStroke1 },
1399
+ "::after": { borderRightColor: tokens8.colorNeutralStroke1, borderLeftColor: tokens8.colorNeutralStroke1 }
1400
+ },
1401
+ splitDivider: { height: `${CB.splitDividerHeight}px` },
1402
+ commands: {
1403
+ flex: "1 1 auto",
1404
+ minWidth: 0,
1405
+ columnGap: 0,
1406
+ // Commands past the edge are clipped (Dynamics folds them into ⋮ by an unmeasured rule — pass
1407
+ // overflowItems). The FOCUS_ROOM padding/negative margin keeps forced-colors outlines visible.
1408
+ overflow: "hidden",
1409
+ padding: `${FOCUS_ROOM}px ${CB.commandsPaddingRight}px ${FOCUS_ROOM}px ${FOCUS_ROOM}px`,
1410
+ margin: `-${FOCUS_ROOM}px 0 -${FOCUS_ROOM}px -${FOCUS_ROOM}px`
1411
+ },
1412
+ command: {
1413
+ height: `${CB.buttonHeight}px`,
1414
+ minWidth: 0,
1415
+ flexShrink: 0,
1416
+ padding: `1px ${CB.buttonPaddingX - FLUENT_BORDER}px`,
1417
+ fontSize: tokens8.fontSizeBase300,
1418
+ fontWeight: tokens8.fontWeightRegular,
1419
+ lineHeight: "21px",
1420
+ [`& .${buttonClassNames.icon}`]: {
1421
+ width: `${CB.iconSize}px`,
1422
+ height: `${CB.iconSize}px`,
1423
+ fontSize: `${CB.iconSize}px`,
1424
+ marginRight: `${CB.iconGap}px`
1425
+ }
1426
+ },
1427
+ // Measured colours — NOT applied to primary commands, whose on-brand colours Fluent owns.
1428
+ commandColors: {
1429
+ color: tokens8.colorNeutralForeground1,
1430
+ [`& .${buttonClassNames.icon}`]: { color: tokens8.colorNeutralForeground2 }
1431
+ },
1432
+ menuCommand: { paddingRight: 0 },
1433
+ chevronZone: {
1434
+ display: "inline-flex",
1435
+ justifyContent: "center",
1436
+ alignItems: "center",
1437
+ width: `${CB.chevronZone - FLUENT_BORDER}px`,
1438
+ flexShrink: 0
1439
+ },
1440
+ splitMain: { marginRight: `${CB.splitGap}px` },
1441
+ iconOnly: {
1442
+ height: `${CB.buttonHeight}px`,
1443
+ minWidth: 0,
1444
+ maxWidth: "none",
1445
+ flexShrink: 0,
1446
+ padding: 0,
1447
+ color: tokens8.colorNeutralForeground1
1448
+ },
1449
+ far: { padding: `0 ${CB.farPadding}px` },
1450
+ farButton: {
1451
+ height: `${CB.shareHeight}px`,
1452
+ minWidth: 0,
1453
+ // Share's border is a real 1px #d1d1d1 border in Dynamics too (bl=1 alongside p=1,8).
1454
+ padding: `1px ${CB.sharePaddingX}px`,
1455
+ fontSize: `${CB.shareFontSize}px`,
1456
+ lineHeight: `${CB.shareLineHeight}px`,
1457
+ fontWeight: tokens8.fontWeightRegular,
1458
+ color: tokens8.colorNeutralForeground2,
1459
+ borderTopColor: tokens8.colorNeutralStroke1,
1460
+ borderRightColor: tokens8.colorNeutralStroke1,
1461
+ borderBottomColor: tokens8.colorNeutralStroke1,
1462
+ borderLeftColor: tokens8.colorNeutralStroke1,
1463
+ [`& .${buttonClassNames.icon}`]: {
1464
+ width: `${CB.shareIconSize}px`,
1465
+ height: `${CB.shareIconSize}px`,
1466
+ fontSize: `${CB.shareIconSize}px`,
1467
+ marginRight: "4px"
1468
+ }
1469
+ }
1470
+ });
1471
+ function CeCommandSurface({ items, overflowItems, farItems, className, onBack, onPopOut }) {
1472
+ const styles = useStyles6();
1473
+ const measuredColors = (item) => item.appearance !== "primary";
1474
+ const commandClass = (item, ...extra) => mergeClasses4(styles.command, measuredColors(item) && styles.commandColors, ...extra);
1475
+ const commandPart = (item) => ({
1476
+ "data-surface-part": "command",
1477
+ "data-measured-colors": measuredColors(item) ? "true" : void 0
1478
+ });
1479
+ const appearanceOf = (item) => item.appearance === "primary" ? "primary" : "subtle";
1480
+ const command = (item) => {
1481
+ if (item.menuItems?.length && item.split) {
1482
+ return /* @__PURE__ */ jsxs6(React4.Fragment, { children: [
1483
+ /* @__PURE__ */ jsx9(
1484
+ ToolbarButton2,
1485
+ {
1486
+ appearance: appearanceOf(item),
1487
+ icon: item.icon,
1488
+ disabled: item.disabled,
1489
+ onClick: item.onClick,
1490
+ className: commandClass(item, styles.splitMain),
1491
+ ...commandPart(item),
1492
+ children: item.label
1493
+ }
1494
+ ),
1495
+ /* @__PURE__ */ jsx9(ToolbarDivider, { className: mergeClasses4(styles.divider, styles.splitDivider) }),
1496
+ /* @__PURE__ */ jsx9(
1497
+ ItemMenu,
1498
+ {
1499
+ items: item.menuItems,
1500
+ trigger: /* @__PURE__ */ jsx9(
1501
+ ToolbarButton2,
1502
+ {
1503
+ appearance: "subtle",
1504
+ "aria-label": `More ${item.label} options`,
1505
+ icon: /* @__PURE__ */ jsx9(ChevronDown16Regular, {}),
1506
+ disabled: item.disabled,
1507
+ className: styles.iconOnly,
1508
+ style: { width: CB.chevronZone, marginRight: -CB.splitChevronOverhang },
1509
+ "data-surface-part": "command-split-chevron"
1510
+ }
1511
+ )
1512
+ }
1513
+ )
1514
+ ] }, item.id);
1515
+ }
1516
+ if (item.menuItems?.length) {
1517
+ return /* @__PURE__ */ jsx9(
1518
+ ItemMenu,
1519
+ {
1520
+ items: item.menuItems,
1521
+ trigger: /* @__PURE__ */ jsxs6(
1522
+ ToolbarButton2,
1523
+ {
1524
+ appearance: appearanceOf(item),
1525
+ icon: item.icon,
1526
+ disabled: item.disabled,
1527
+ className: commandClass(item, styles.menuCommand),
1528
+ ...commandPart(item),
1529
+ children: [
1530
+ item.label,
1531
+ /* @__PURE__ */ jsx9("span", { className: styles.chevronZone, "aria-hidden": "true", children: /* @__PURE__ */ jsx9(ChevronDown12Regular2, {}) })
1532
+ ]
1533
+ }
1534
+ )
1535
+ },
1536
+ item.id
1537
+ );
1538
+ }
1539
+ return /* @__PURE__ */ jsx9(
1540
+ ToolbarButton2,
1541
+ {
1542
+ appearance: appearanceOf(item),
1543
+ icon: item.icon,
1544
+ disabled: item.disabled,
1545
+ onClick: item.onClick,
1546
+ className: commandClass(item),
1547
+ ...commandPart(item),
1548
+ children: item.label
1549
+ },
1550
+ item.id
1551
+ );
1552
+ };
1553
+ return /* @__PURE__ */ jsx9("div", { className: mergeClasses4(styles.root, className), "data-surface-part": "command-bar", "data-look": "ce", children: /* @__PURE__ */ jsxs6("div", { className: styles.card, "data-surface-part": "command-card", children: [
1554
+ (onBack || onPopOut) && /* @__PURE__ */ jsxs6("div", { role: "group", "aria-label": "Navigation", className: mergeClasses4(styles.group, styles.nav), "data-surface-part": "command-nav", children: [
1555
+ onBack && /* @__PURE__ */ jsxs6(Fragment2, { children: [
1556
+ /* @__PURE__ */ jsx9(
1557
+ Button3,
1558
+ {
1559
+ appearance: "subtle",
1560
+ icon: /* @__PURE__ */ jsx9(ArrowLeft20Regular, {}),
1561
+ "aria-label": "Back",
1562
+ onClick: onBack,
1563
+ className: styles.navButton,
1564
+ style: { width: CB.backWidth },
1565
+ "data-surface-part": "command-back"
1566
+ }
1567
+ ),
1568
+ /* @__PURE__ */ jsx9(ToolbarDivider, { className: styles.divider })
1569
+ ] }),
1570
+ onPopOut && /* @__PURE__ */ jsxs6(Fragment2, { children: [
1571
+ /* @__PURE__ */ jsx9(
1572
+ Button3,
1573
+ {
1574
+ appearance: "subtle",
1575
+ icon: /* @__PURE__ */ jsx9(WindowNew20Regular, {}),
1576
+ "aria-label": "Open in new window",
1577
+ onClick: onPopOut,
1578
+ className: styles.navButton,
1579
+ style: { width: CB.popOutWidth },
1580
+ "data-surface-part": "command-popout"
1581
+ }
1582
+ ),
1583
+ /* @__PURE__ */ jsx9(ToolbarDivider, { className: styles.divider })
1584
+ ] })
1585
+ ] }),
1586
+ /* @__PURE__ */ jsxs6(Toolbar2, { "aria-label": "Commands", className: styles.commands, "data-surface-part": "command-list", children: [
1587
+ items.map(command),
1588
+ overflowItems && overflowItems.length > 0 && /* @__PURE__ */ jsx9(
1589
+ ItemMenu,
1590
+ {
1591
+ items: overflowItems,
1592
+ trigger: /* @__PURE__ */ jsx9(
1593
+ ToolbarButton2,
1594
+ {
1595
+ appearance: "subtle",
1596
+ "aria-label": "More commands",
1597
+ icon: /* @__PURE__ */ jsx9(MoreVertical16Regular, {}),
1598
+ className: styles.iconOnly,
1599
+ style: { width: CB.overflowWidth },
1600
+ "data-surface-part": "command-overflow"
1601
+ }
1602
+ )
1603
+ }
1604
+ )
1605
+ ] }),
1606
+ farItems && farItems.length > 0 && /* @__PURE__ */ jsx9("div", { role: "group", "aria-label": "Secondary commands", className: mergeClasses4(styles.group, styles.far), "data-surface-part": "command-far", children: farItems.map((f) => {
1607
+ const btn = /* @__PURE__ */ jsxs6(
1608
+ Button3,
1609
+ {
1610
+ appearance: "outline",
1611
+ icon: f.icon,
1612
+ disabled: f.disabled,
1613
+ onClick: f.menuItems?.length ? void 0 : f.onClick,
1614
+ className: styles.farButton,
1615
+ "data-surface-part": "command-far-button",
1616
+ children: [
1617
+ f.label,
1618
+ f.menuItems?.length ? /* @__PURE__ */ jsx9(ChevronDown12Regular2, { style: { marginLeft: 4 }, "aria-hidden": true }) : null
1619
+ ]
1620
+ },
1621
+ f.id
1622
+ );
1623
+ return f.menuItems?.length ? /* @__PURE__ */ jsx9(ItemMenu, { items: f.menuItems, trigger: btn }, f.id) : btn;
1624
+ }) })
1625
+ ] }) });
1626
+ }
1627
+ var CommandSurface = (props) => {
1628
+ if (props.look === "ce") return /* @__PURE__ */ jsx9(CeCommandSurface, { ...props });
1629
+ const { items, overflowItems, farItems, size = "small", className } = props;
568
1630
  const hasFar = Boolean(farItems && farItems.length > 0);
569
1631
  const hasOverflow = Boolean(overflowItems && overflowItems.length > 0);
570
1632
  const hasPrimary = items.length > 0 || hasOverflow;
571
- return /* @__PURE__ */ jsxs5("div", { className, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
572
- hasPrimary && /* @__PURE__ */ jsxs5(Toolbar2, { "aria-label": "Commands", size, children: [
1633
+ return /* @__PURE__ */ jsxs6("div", { className, style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1634
+ hasPrimary && /* @__PURE__ */ jsxs6(Toolbar2, { "aria-label": "Commands", size, children: [
573
1635
  items.map(renderToolbarButton),
574
- hasOverflow && /* @__PURE__ */ jsxs5(Menu, { children: [
575
- /* @__PURE__ */ jsx8(MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx8(ToolbarButton2, { "aria-label": "More commands", icon: /* @__PURE__ */ jsx8(MoreHorizontal20Regular, {}) }) }),
576
- /* @__PURE__ */ jsx8(MenuPopover, { children: /* @__PURE__ */ jsx8(MenuList, { children: overflowItems.map((item) => /* @__PURE__ */ jsx8(MenuItem, { icon: item.icon, disabled: item.disabled, onClick: item.onClick, children: item.label }, item.id)) }) })
1636
+ hasOverflow && /* @__PURE__ */ jsxs6(Menu2, { children: [
1637
+ /* @__PURE__ */ jsx9(MenuTrigger2, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsx9(ToolbarButton2, { "aria-label": "More commands", icon: /* @__PURE__ */ jsx9(MoreHorizontal20Regular, {}) }) }),
1638
+ /* @__PURE__ */ jsx9(MenuPopover2, { children: /* @__PURE__ */ jsx9(MenuList2, { children: overflowItems.map((item) => /* @__PURE__ */ jsx9(MenuItem, { icon: item.icon, disabled: item.disabled, onClick: item.onClick, children: item.label }, item.id)) }) })
577
1639
  ] })
578
1640
  ] }),
579
1641
  hasFar && // marginLeft:auto keeps far items right-aligned whether or not a primary toolbar renders.
580
- /* @__PURE__ */ jsx8(Toolbar2, { "aria-label": "Secondary commands", size, style: { marginLeft: "auto" }, children: farItems.map(renderToolbarButton) })
1642
+ /* @__PURE__ */ jsx9(Toolbar2, { "aria-label": "Secondary commands", size, style: { marginLeft: "auto" }, children: farItems.map(renderToolbarButton) })
581
1643
  ] });
582
1644
  };
583
1645
 
584
1646
  // src/v9/containers/ActionBar.tsx
585
- import { Button as Button2, tokens as tokens6 } from "@fluentui/react-components";
586
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1647
+ import { Button as Button4, tokens as tokens9 } from "@fluentui/react-components";
1648
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
587
1649
  function renderButton(b) {
588
1650
  const appearance = b.appearance === "primary" ? "primary" : b.appearance === "subtle" ? "subtle" : "secondary";
589
- return /* @__PURE__ */ jsx9(Button2, { appearance, icon: b.icon, disabled: b.disabled, onClick: b.onClick, children: b.label }, b.id);
1651
+ return /* @__PURE__ */ jsx10(Button4, { appearance, icon: b.icon, disabled: b.disabled, onClick: b.onClick, children: b.label }, b.id);
590
1652
  }
591
1653
  var ActionBar = ({ buttons, alignment = "right", sticky = true, className }) => {
592
1654
  const justify = alignment === "left" ? "flex-start" : alignment === "center" ? "center" : "flex-end";
@@ -599,19 +1661,19 @@ var ActionBar = ({ buttons, alignment = "right", sticky = true, className }) =>
599
1661
  justifyContent: left.length ? "space-between" : justify,
600
1662
  gap: 8,
601
1663
  padding: "12px 24px",
602
- borderTop: `1px solid ${tokens6.colorNeutralStroke2}`,
603
- backgroundColor: tokens6.colorNeutralBackground1,
1664
+ borderTop: `1px solid ${tokens9.colorNeutralStroke2}`,
1665
+ backgroundColor: tokens9.colorNeutralBackground1,
604
1666
  ...sticky ? { position: "sticky", bottom: 0, zIndex: 1 } : {}
605
1667
  };
606
- return /* @__PURE__ */ jsxs6("div", { className, style: rootStyle, children: [
607
- left.length > 0 && /* @__PURE__ */ jsx9("div", { style: { display: "flex", gap: 8 }, children: left.map(renderButton) }),
608
- /* @__PURE__ */ jsx9("div", { style: { display: "flex", gap: 8, justifyContent: justify }, children: right.map(renderButton) })
1668
+ return /* @__PURE__ */ jsxs7("div", { className, style: rootStyle, children: [
1669
+ left.length > 0 && /* @__PURE__ */ jsx10("div", { style: { display: "flex", gap: 8 }, children: left.map(renderButton) }),
1670
+ /* @__PURE__ */ jsx10("div", { style: { display: "flex", gap: 8, justifyContent: justify }, children: right.map(renderButton) })
609
1671
  ] });
610
1672
  };
611
1673
 
612
1674
  // src/v9/containers/Footer.tsx
613
- import { tokens as tokens7 } from "@fluentui/react-components";
614
- import { jsx as jsx10 } from "react/jsx-runtime";
1675
+ import { tokens as tokens10 } from "@fluentui/react-components";
1676
+ import { jsx as jsx11 } from "react/jsx-runtime";
615
1677
  var Footer = ({ sticky = true, align = "right", className, children }) => {
616
1678
  const justify = align === "left" ? "flex-start" : align === "center" ? "center" : "flex-end";
617
1679
  const rootStyle = {
@@ -620,17 +1682,82 @@ var Footer = ({ sticky = true, align = "right", className, children }) => {
620
1682
  justifyContent: justify,
621
1683
  gap: 8,
622
1684
  padding: "12px 24px",
623
- borderTop: `1px solid ${tokens7.colorNeutralStroke2}`,
624
- backgroundColor: tokens7.colorNeutralBackground1,
1685
+ borderTop: `1px solid ${tokens10.colorNeutralStroke2}`,
1686
+ backgroundColor: tokens10.colorNeutralBackground1,
625
1687
  ...sticky ? { position: "sticky", bottom: 0, zIndex: 1 } : {}
626
1688
  };
627
- return /* @__PURE__ */ jsx10("div", { className, style: rootStyle, children });
1689
+ return /* @__PURE__ */ jsx11("div", { className, style: rootStyle, children });
1690
+ };
1691
+
1692
+ // src/v9/layouts/TabColumns.tsx
1693
+ import React5 from "react";
1694
+ import { makeStyles as makeStyles7, mergeClasses as mergeClasses5 } from "@fluentui/react-components";
1695
+ import { jsx as jsx12 } from "react/jsx-runtime";
1696
+ var useStyles7 = makeStyles7({
1697
+ row: {
1698
+ display: "flex",
1699
+ flexWrap: "wrap",
1700
+ alignItems: "flex-start"
1701
+ },
1702
+ column: {
1703
+ display: "flex",
1704
+ flexDirection: "column",
1705
+ boxSizing: "border-box"
1706
+ }
1707
+ });
1708
+ function positional(children) {
1709
+ const out = [];
1710
+ const walk = (node) => {
1711
+ if (Array.isArray(node)) node.forEach(walk);
1712
+ else out.push(node);
1713
+ };
1714
+ walk(children);
1715
+ return out;
1716
+ }
1717
+ var isEmpty2 = (n) => n === null || n === void 0 || typeof n === "boolean" || n === "";
1718
+ var TabColumns = ({
1719
+ widths,
1720
+ minColumnWidth,
1721
+ gap,
1722
+ look: lookProp,
1723
+ className,
1724
+ style,
1725
+ children
1726
+ }) => {
1727
+ const styles = useStyles7();
1728
+ const ambientLook = useLook();
1729
+ const ce = (lookProp ?? ambientLook) === "ce";
1730
+ const floor = minColumnWidth ?? (ce ? ceForm.tabBody.columnMinWidth : 300);
1731
+ const spacing2 = gap ?? (ce ? ceForm.tabBody.columnGap : 20);
1732
+ const slots = positional(children);
1733
+ const visible = slots.map((s, i) => ({ node: s, i })).filter(({ node }) => !isEmpty2(node));
1734
+ const shares = normalizeColumnShares(visible.map(({ i }) => widths?.[i] ?? 1));
1735
+ return /* @__PURE__ */ jsx12(
1736
+ "div",
1737
+ {
1738
+ className: mergeClasses5(styles.row, className),
1739
+ style: { gap: spacing2, ...style },
1740
+ "data-surface-part": "tab-columns",
1741
+ "data-look": ce ? "ce" : "default",
1742
+ children: visible.map(({ node, i }, v) => /* @__PURE__ */ jsx12(
1743
+ "div",
1744
+ {
1745
+ className: styles.column,
1746
+ style: { flex: `${shares[v]} 1 0`, minWidth: `min(${floor}px, 100%)`, gap: ce ? ceForm.tabBody.sectionGap : spacing2 },
1747
+ "data-surface-part": "tab-column",
1748
+ "data-column-index": i,
1749
+ children: node
1750
+ },
1751
+ React5.isValidElement(node) && node.key != null ? node.key : i
1752
+ ))
1753
+ }
1754
+ );
628
1755
  };
629
1756
 
630
1757
  // src/v9/overlays/FormDialogSurface.tsx
631
- import { Dialog, DialogSurface, Button as Button3, Text as Text3, tokens as tokens8 } from "@fluentui/react-components";
1758
+ import { Dialog, DialogSurface, Button as Button5, Text as Text3, tokens as tokens11 } from "@fluentui/react-components";
632
1759
  import { Dismiss20Regular } from "@fluentui/react-icons";
633
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
1760
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
634
1761
  var FormDialogSurface = ({
635
1762
  isOpen,
636
1763
  onDismiss,
@@ -654,10 +1781,10 @@ var FormDialogSurface = ({
654
1781
  justifyContent: "space-between",
655
1782
  gap: 12,
656
1783
  padding: "12px 20px",
657
- borderBottom: `1px solid ${tokens8.colorNeutralStroke2}`
1784
+ borderBottom: `1px solid ${tokens11.colorNeutralStroke2}`
658
1785
  };
659
- const counterStyle = { fontSize: tokens8.fontSizeBase200, color: tokens8.colorNeutralForeground3 };
660
- return /* @__PURE__ */ jsx11(
1786
+ const counterStyle = { fontSize: tokens11.fontSizeBase200, color: tokens11.colorNeutralForeground3 };
1787
+ return /* @__PURE__ */ jsx13(
661
1788
  Dialog,
662
1789
  {
663
1790
  open: isOpen,
@@ -665,7 +1792,7 @@ var FormDialogSurface = ({
665
1792
  onOpenChange: (_e, data) => {
666
1793
  if (!data.open) onDismiss?.();
667
1794
  },
668
- children: /* @__PURE__ */ jsxs7(
1795
+ children: /* @__PURE__ */ jsxs8(
669
1796
  DialogSurface,
670
1797
  {
671
1798
  className,
@@ -679,22 +1806,22 @@ var FormDialogSurface = ({
679
1806
  padding: 0
680
1807
  },
681
1808
  children: [
682
- showHeader && /* @__PURE__ */ jsxs7("div", { style: headerStyle, children: [
683
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [
684
- title && /* @__PURE__ */ jsx11(Text3, { weight: "semibold", size: 400, children: title }),
685
- subheader && /* @__PURE__ */ jsx11("span", { style: { fontSize: tokens8.fontSizeBase200, color: tokens8.colorNeutralForeground3, marginTop: 2 }, children: subheader })
1809
+ showHeader && /* @__PURE__ */ jsxs8("div", { style: headerStyle, children: [
1810
+ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", flexDirection: "column", minWidth: 0 }, children: [
1811
+ title && /* @__PURE__ */ jsx13(Text3, { weight: "semibold", size: 400, children: title }),
1812
+ subheader && /* @__PURE__ */ jsx13("span", { style: { fontSize: tokens11.fontSizeBase200, color: tokens11.colorNeutralForeground3, marginTop: 2 }, children: subheader })
686
1813
  ] }),
687
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
688
- recordCounter && /* @__PURE__ */ jsxs7("span", { style: counterStyle, children: [
1814
+ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1815
+ recordCounter && /* @__PURE__ */ jsxs8("span", { style: counterStyle, children: [
689
1816
  recordCounter.current,
690
1817
  " of ",
691
1818
  recordCounter.total
692
1819
  ] }),
693
- onDismiss && /* @__PURE__ */ jsx11(Button3, { appearance: "subtle", "aria-label": "Close", icon: /* @__PURE__ */ jsx11(Dismiss20Regular, {}), onClick: onDismiss })
1820
+ onDismiss && /* @__PURE__ */ jsx13(Button5, { appearance: "subtle", "aria-label": "Close", icon: /* @__PURE__ */ jsx13(Dismiss20Regular, {}), onClick: onDismiss })
694
1821
  ] })
695
1822
  ] }),
696
- /* @__PURE__ */ jsx11("div", { style: { flex: 1, minHeight: 0, overflow: "auto", padding: 20 }, children }),
697
- footer && /* @__PURE__ */ jsx11("div", { style: { borderTop: `1px solid ${tokens8.colorNeutralStroke2}`, padding: "12px 20px" }, children: footer })
1823
+ /* @__PURE__ */ jsx13("div", { style: { flex: 1, minHeight: 0, overflow: "auto", padding: 20 }, children }),
1824
+ footer && /* @__PURE__ */ jsx13("div", { style: { borderTop: `1px solid ${tokens11.colorNeutralStroke2}`, padding: "12px 20px" }, children: footer })
698
1825
  ]
699
1826
  }
700
1827
  )
@@ -703,8 +1830,8 @@ var FormDialogSurface = ({
703
1830
  };
704
1831
 
705
1832
  // src/v9/overlays/ModalSurface.tsx
706
- import { Dialog as Dialog2, DialogSurface as DialogSurface2, Text as Text4, tokens as tokens9 } from "@fluentui/react-components";
707
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
1833
+ import { Dialog as Dialog2, DialogSurface as DialogSurface2, Text as Text4, tokens as tokens12 } from "@fluentui/react-components";
1834
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
708
1835
  var ModalSurface = ({
709
1836
  isOpen,
710
1837
  onDismiss,
@@ -718,7 +1845,7 @@ var ModalSurface = ({
718
1845
  children
719
1846
  }) => {
720
1847
  const sizing = autoSize ? { width: "auto", minWidth: MODAL_AUTOSIZE_MIN_WIDTH, maxWidth: "100%" } : { maxWidth: "95vw", width: `${dialogWidthPx({ width, size })}px` };
721
- return /* @__PURE__ */ jsx12(
1848
+ return /* @__PURE__ */ jsx14(
722
1849
  Dialog2,
723
1850
  {
724
1851
  open: isOpen,
@@ -726,14 +1853,14 @@ var ModalSurface = ({
726
1853
  onOpenChange: (_e, data) => {
727
1854
  if (!data.open) onDismiss?.();
728
1855
  },
729
- children: /* @__PURE__ */ jsxs8(DialogSurface2, { className, style: { ...sizing, padding: 0 }, children: [
730
- title && /* @__PURE__ */ jsx12("div", { style: { padding: "16px 20px 0" }, children: /* @__PURE__ */ jsx12(Text4, { weight: "semibold", size: 500, children: title }) }),
731
- /* @__PURE__ */ jsx12("div", { style: { padding: 20 }, children }),
732
- footer && /* @__PURE__ */ jsx12(
1856
+ children: /* @__PURE__ */ jsxs9(DialogSurface2, { className, style: { ...sizing, padding: 0 }, children: [
1857
+ title && /* @__PURE__ */ jsx14("div", { style: { padding: "16px 20px 0" }, children: /* @__PURE__ */ jsx14(Text4, { weight: "semibold", size: 500, children: title }) }),
1858
+ /* @__PURE__ */ jsx14("div", { style: { padding: 20 }, children }),
1859
+ footer && /* @__PURE__ */ jsx14(
733
1860
  "div",
734
1861
  {
735
1862
  style: {
736
- borderTop: `1px solid ${tokens9.colorNeutralStroke2}`,
1863
+ borderTop: `1px solid ${tokens12.colorNeutralStroke2}`,
737
1864
  padding: "12px 20px",
738
1865
  display: "flex",
739
1866
  justifyContent: "flex-end",
@@ -753,10 +1880,10 @@ import {
753
1880
  DrawerHeader,
754
1881
  DrawerHeaderTitle,
755
1882
  DrawerBody,
756
- Button as Button4
1883
+ Button as Button6
757
1884
  } from "@fluentui/react-components";
758
1885
  import { Dismiss24Regular } from "@fluentui/react-icons";
759
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
1886
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
760
1887
  var PanelSurface = ({
761
1888
  isOpen,
762
1889
  onDismiss,
@@ -771,7 +1898,7 @@ var PanelSurface = ({
771
1898
  }) => {
772
1899
  const size = drawerSize ?? (width != null && width > 500 ? "medium" : "small");
773
1900
  const customWidthStyle = width != null ? { width: `${width}px` } : void 0;
774
- return /* @__PURE__ */ jsxs9(
1901
+ return /* @__PURE__ */ jsxs10(
775
1902
  OverlayDrawer,
776
1903
  {
777
1904
  open: isOpen,
@@ -785,16 +1912,16 @@ var PanelSurface = ({
785
1912
  onDismiss?.();
786
1913
  },
787
1914
  children: [
788
- /* @__PURE__ */ jsx13(DrawerHeader, { children: /* @__PURE__ */ jsx13(
1915
+ /* @__PURE__ */ jsx15(DrawerHeader, { children: /* @__PURE__ */ jsx15(
789
1916
  DrawerHeaderTitle,
790
1917
  {
791
- action: hasCloseButton && onDismiss ? /* @__PURE__ */ jsx13(Button4, { appearance: "subtle", "aria-label": "Close", icon: /* @__PURE__ */ jsx13(Dismiss24Regular, {}), onClick: onDismiss }) : void 0,
1918
+ action: hasCloseButton && onDismiss ? /* @__PURE__ */ jsx15(Button6, { appearance: "subtle", "aria-label": "Close", icon: /* @__PURE__ */ jsx15(Dismiss24Regular, {}), onClick: onDismiss }) : void 0,
792
1919
  children: title
793
1920
  }
794
1921
  ) }),
795
- /* @__PURE__ */ jsxs9(DrawerBody, { children: [
796
- /* @__PURE__ */ jsx13("div", { style: { padding: "12px 0" }, children }),
797
- footer && /* @__PURE__ */ jsx13("div", { style: { marginTop: "auto", paddingTop: 12 }, children: footer })
1922
+ /* @__PURE__ */ jsxs10(DrawerBody, { children: [
1923
+ /* @__PURE__ */ jsx15("div", { style: { padding: "12px 0" }, children }),
1924
+ footer && /* @__PURE__ */ jsx15("div", { style: { marginTop: "auto", paddingTop: 12 }, children: footer })
798
1925
  ] })
799
1926
  ]
800
1927
  }
@@ -803,7 +1930,7 @@ var PanelSurface = ({
803
1930
 
804
1931
  // src/v9/overlays/CalloutSurface.tsx
805
1932
  import { Popover, PopoverSurface } from "@fluentui/react-components";
806
- import { jsx as jsx14 } from "react/jsx-runtime";
1933
+ import { jsx as jsx16 } from "react/jsx-runtime";
807
1934
  function resolveTarget(target) {
808
1935
  if (!target) return null;
809
1936
  if (typeof target === "string") return document.querySelector(target);
@@ -824,7 +1951,7 @@ var CalloutSurface = ({
824
1951
  if (!isOpen) return null;
825
1952
  const el = resolveTarget(target);
826
1953
  const positioning = { position, align, ...el ? { target: el } : {} };
827
- return /* @__PURE__ */ jsx14(
1954
+ return /* @__PURE__ */ jsx16(
828
1955
  Popover,
829
1956
  {
830
1957
  open: true,
@@ -834,14 +1961,14 @@ var CalloutSurface = ({
834
1961
  onOpenChange: (_e, data) => {
835
1962
  if (!data.open) onDismiss?.();
836
1963
  },
837
- children: /* @__PURE__ */ jsx14(PopoverSurface, { className, style: { width: calloutWidthPx(width), padding: 16 }, children })
1964
+ children: /* @__PURE__ */ jsx16(PopoverSurface, { className, style: { width: calloutWidthPx(width), padding: 16 }, children })
838
1965
  }
839
1966
  );
840
1967
  };
841
1968
 
842
1969
  // src/v9/overlays/TooltipSurface.tsx
843
1970
  import { Tooltip } from "@fluentui/react-components";
844
- import { jsx as jsx15 } from "react/jsx-runtime";
1971
+ import { jsx as jsx17 } from "react/jsx-runtime";
845
1972
  var DELAY_MS = {
846
1973
  zero: 0,
847
1974
  medium: 250,
@@ -853,20 +1980,24 @@ var TooltipSurface = ({
853
1980
  delay = "medium",
854
1981
  relationship = "label",
855
1982
  children
856
- }) => /* @__PURE__ */ jsx15(Tooltip, { content, relationship, positioning: position, showDelay: DELAY_MS[delay], children });
1983
+ }) => /* @__PURE__ */ jsx17(Tooltip, { content, relationship, positioning: position, showDelay: DELAY_MS[delay], children });
857
1984
  export {
858
1985
  ActionBar,
859
1986
  BREAKPOINTS,
860
1987
  CALLOUT_DEFAULT_WIDTH,
861
1988
  CARD_REFLOW_WIDTH,
1989
+ CE_LABEL_ABOVE_BELOW_ROW_WIDTH,
1990
+ CE_TAB_COLUMN_MIN_WIDTH,
862
1991
  CalloutSurface,
863
1992
  CommandSurface,
864
1993
  DIALOG_SIZE_PX,
865
1994
  DensityContext,
1995
+ FieldRow,
866
1996
  Footer,
867
1997
  FormDialogSurface,
868
1998
  FormHeader,
869
1999
  FormSurface,
2000
+ LookContext,
870
2001
  MODAL_AUTOSIZE_MIN_WIDTH,
871
2002
  ModalSurface,
872
2003
  PANEL_DEFAULT_WIDTH,
@@ -876,11 +2007,16 @@ export {
876
2007
  Section,
877
2008
  SectionCard,
878
2009
  SectionHeader,
2010
+ TabColumns,
879
2011
  TooltipSurface,
880
2012
  calloutFormDefaults,
881
2013
  calloutWidthPx,
2014
+ ceFieldRowFirstOffset,
2015
+ ceForm,
2016
+ cePresenceBadgeStyle,
882
2017
  clampSpan,
883
2018
  colors,
2019
+ createDynamicsCeTheme,
884
2020
  createDynamicsV9DarkTheme,
885
2021
  createDynamicsV9Theme,
886
2022
  densityScale,
@@ -888,17 +2024,20 @@ export {
888
2024
  dialogWidthCss,
889
2025
  dialogWidthPx,
890
2026
  dynamicsBrandRamp,
2027
+ dynamicsCeTheme,
891
2028
  dynamicsV9DarkTheme,
892
2029
  dynamicsV9Theme,
893
2030
  fieldGridStyle,
894
2031
  fieldRowStyle,
895
2032
  gridTemplateForColumns,
896
2033
  layout,
2034
+ normalizeColumnShares,
897
2035
  panelCustomWidthPx,
898
2036
  panelKindFromWidth,
899
2037
  radius,
900
2038
  resolveBreakpoint,
901
2039
  resolveResponsiveValue,
2040
+ resolveTabColumnWidths,
902
2041
  scaleSpacing,
903
2042
  sectionStackingStyle,
904
2043
  spacing,
@@ -907,6 +2046,7 @@ export {
907
2046
  useContainerSize,
908
2047
  useContainerWidth,
909
2048
  useDensity,
2049
+ useLook,
910
2050
  useMediaQuery,
911
2051
  useResponsiveValue
912
2052
  };