@atlaskit/renderer 137.1.8 → 137.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cjs/react/index.js +1 -1
  3. package/dist/cjs/react/nodes/table/colgroup.js +1 -2
  4. package/dist/cjs/react/nodes/table/sticky.js +2 -4
  5. package/dist/cjs/react/nodes/table/table.js +1 -12
  6. package/dist/cjs/react/nodes/table.js +471 -203
  7. package/dist/cjs/ui/Expand.js +33 -7
  8. package/dist/cjs/ui/Renderer/breakout-ssr.js +1 -2
  9. package/dist/cjs/ui/Renderer/index.js +3 -3
  10. package/dist/cjs/ui/utils/expand-body.js +218 -0
  11. package/dist/cjs/ui/utils/expand-search-text.js +39 -1
  12. package/dist/es2019/react/index.js +1 -1
  13. package/dist/es2019/react/nodes/table/colgroup.js +1 -2
  14. package/dist/es2019/react/nodes/table/sticky.js +2 -3
  15. package/dist/es2019/react/nodes/table/table.js +1 -12
  16. package/dist/es2019/react/nodes/table.js +457 -190
  17. package/dist/es2019/ui/Expand.js +33 -7
  18. package/dist/es2019/ui/Renderer/breakout-ssr.js +1 -2
  19. package/dist/es2019/ui/Renderer/index.js +3 -3
  20. package/dist/es2019/ui/utils/expand-body.js +198 -0
  21. package/dist/es2019/ui/utils/expand-search-text.js +38 -0
  22. package/dist/esm/react/index.js +1 -1
  23. package/dist/esm/react/nodes/table/colgroup.js +1 -2
  24. package/dist/esm/react/nodes/table/sticky.js +2 -4
  25. package/dist/esm/react/nodes/table/table.js +1 -12
  26. package/dist/esm/react/nodes/table.js +471 -202
  27. package/dist/esm/ui/Expand.js +33 -7
  28. package/dist/esm/ui/Renderer/breakout-ssr.js +1 -2
  29. package/dist/esm/ui/Renderer/index.js +3 -3
  30. package/dist/esm/ui/utils/expand-body.js +210 -0
  31. package/dist/esm/ui/utils/expand-search-text.js +38 -0
  32. package/dist/types/react/nodes/table/sticky.d.ts +1 -2
  33. package/dist/types/react/nodes/table.d.ts +78 -8
  34. package/dist/types/ui/{expand-body.d.ts → utils/expand-body.d.ts} +26 -5
  35. package/dist/types/ui/utils/expand-search-text.d.ts +14 -0
  36. package/package.json +6 -9
  37. package/dist/cjs/react/nodes/tableNew.js +0 -1050
  38. package/dist/cjs/ui/expand-body.js +0 -122
  39. package/dist/es2019/react/nodes/tableNew.js +0 -986
  40. package/dist/es2019/ui/expand-body.js +0 -107
  41. package/dist/esm/react/nodes/tableNew.js +0 -1044
  42. package/dist/esm/ui/expand-body.js +0 -114
  43. package/dist/types/react/nodes/tableNew.d.ts +0 -189
@@ -1,28 +1,44 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
+ /* eslint-disable @atlaskit/ui-styling-standard/no-classname-prop, @atlaskit/ui-styling-standard/enforce-style-prop, @repo/internal/react/no-class-components */
3
4
  import React from 'react';
4
- import { useIntl } from 'react-intl';
5
5
  import { TableSharedCssClassName, tableMarginTop } from '@atlaskit/editor-common/styles';
6
- import { tableMessages } from '@atlaskit/editor-common/messages';
7
- import { WidthConsumer, overflowShadow } from '@atlaskit/editor-common/ui';
6
+ import { overflowShadow } from '@atlaskit/editor-common/ui';
7
+ import { getTableContainerWidth } from '@atlaskit/editor-common/node-width';
8
+ import { FullPagePadding } from '../../ui/Renderer/style';
8
9
  import { fg } from '@atlaskit/platform-feature-flags/fg';
10
+ import { RendererCssClassName } from '../../consts';
9
11
  import { createCompareNodes, convertProsemirrorTableNodeToArrayOfRows, hasMergedCell, compose } from '@atlaskit/editor-common/utils';
10
12
  import { SortOrder } from '@atlaskit/editor-common/types';
11
13
  import { akEditorDefaultLayoutWidth, akEditorFullWidthLayoutWidth, akEditorMaxWidthLayoutWidth } from '@atlaskit/editor-shared-styles';
12
- import { getTableContainerWidth } from '@atlaskit/editor-common/node-width';
13
14
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
14
- import { FullPagePadding } from '../../ui/Renderer/style';
15
- import { TableHeader } from './tableCell';
15
+ import { TableCell, TableHeader } from './tableCell';
16
16
  import { withSmartCardStorage } from '../../ui/SmartCardStorage';
17
17
  import { StickyTable, tableStickyPadding, OverflowParent } from './table/sticky';
18
18
  import { Table } from './table/table';
19
- import { isCommentAppearance, isFullPageAppearance, isFullWidthAppearance, isFullWidthOrFullPageAppearance, isMaxWidthAppearance } from '../utils/appearance';
19
+ import { isCommentAppearance, isFullWidthOrFullPageAppearance, isFullWidthAppearance, isMaxWidthAppearance, isFullPageAppearance } from '../utils/appearance';
20
20
  import { TableStickyScrollbar } from './TableStickyScrollbar';
21
21
  import { useRendererContext } from '../../renderer-context';
22
- import { TableProcessorWithContainerStyles, RefSyncBlockFakeBorders } from './tableNew';
23
22
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
24
23
  import { isTableInContentMode } from '@atlaskit/editor-common/table';
25
24
  import { isContentModeSupported } from './table/content-mode';
25
+ const stickyContainerBaseStyles = {
26
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
27
+ height: "var(--ds-space-250, 20px)",
28
+ // MAX_BROWSER_SCROLLBAR_HEIGHT
29
+ // Follow editor to hide by default so it does not show empty gap in SSR
30
+ // https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/master/platform/packages/editor/editor-plugin-table/src/nodeviews/TableComponent.tsx#957
31
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
32
+ display: 'block',
33
+ width: '100%'
34
+ };
35
+ const stickyContainerAdditionalStyles = {
36
+ visibility: 'hidden',
37
+ overflowX: 'auto',
38
+ position: 'sticky',
39
+ bottom: "var(--ds-space-0, 0px)",
40
+ zIndex: 1
41
+ };
26
42
  export const isTableResizingEnabled = appearance => isFullWidthOrFullPageAppearance(appearance) || isCommentAppearance(appearance);
27
43
  export const isStickyScrollbarEnabled = appearance => isFullWidthOrFullPageAppearance(appearance) && editorExperiment('platform_renderer_table_sticky_scrollbar', true, {
28
44
  exposure: true
@@ -69,7 +85,7 @@ export const getRefTop = refElement => {
69
85
  export const shouldHeaderStick = (scrollTop, tableTop, tableBottom, rowHeight) => tableTop <= scrollTop && !(tableBottom - rowHeight <= scrollTop);
70
86
  export const shouldHeaderPinBottom = (scrollTop, tableBottom, rowHeight) => tableBottom - rowHeight <= scrollTop && !(tableBottom < scrollTop);
71
87
  export const addSortableColumn = (rows, tableOrderStatus, onSorting
72
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-explicit-any
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
89
  ) => {
74
90
  return React.Children.map(rows, (row, index) => {
75
91
  if (index === 0) {
@@ -100,46 +116,54 @@ export const isHeaderRowEnabled = (rows
100
116
  }
101
117
  return children.every(node => node.type === TableHeader);
102
118
  };
119
+ export const tableCanBeSticky = (node, children
120
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
+ ) => {
122
+ return isHeaderRowEnabled(children) && node && node.firstChild && !hasRowspan(node.firstChild);
123
+ };
103
124
  /**
104
- * This TableWrapper component was created to make sure that the aria-label can be
105
- * internationalized without needing to add `intl` to the TableContainer.
125
+ * Fake left/right borders rendered as direct children of TABLE_CONTAINER
126
+ * (the non-scrolling parent of the horizontally scrolling TABLE_NODE_WRAPPER).
106
127
  *
107
- * <TableWrapper wrapperRef={ref} onScroll={handleScroll} stickyHeaders={config}>
108
- * <Table>...</Table>
109
- * </TableWrapper>
128
+ * The visible styling for these divs lives in `tableFakeBorderStyles`
129
+ * (`renderer/src/ui/Renderer/RendererStyleContainer.tsx`), which is applied
130
+ * when `isInsideSyncBlock` is true.
131
+ */
132
+ const TableFakeBorders = ({
133
+ isNumberColumnEnabled
134
+ }) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
135
+ className: TableSharedCssClassName.TABLE_LEFT_BORDER,
136
+ "data-with-numbered-table": isNumberColumnEnabled ? 'true' : undefined,
137
+ "data-testid": "table-left-border"
138
+ }), /*#__PURE__*/React.createElement("div", {
139
+ className: TableSharedCssClassName.TABLE_RIGHT_BORDER,
140
+ "data-with-numbered-table": isNumberColumnEnabled ? 'true' : undefined,
141
+ "data-testid": "table-right-border"
142
+ }));
143
+
144
+ /**
145
+ * Reads `nestedRendererType` from RendererContext and renders the fake left/right
146
+ * borders only when the current renderer is the nested renderer for a reference
147
+ * synced block.
110
148
  */
111
- const TableWrapper = ({
112
- children,
113
- wrapperRef,
114
- onScroll,
115
- stickyHeaders,
116
- tabIndex
149
+ export const RefSyncBlockFakeBorders = ({
150
+ isNumberColumnEnabled
117
151
  }) => {
118
152
  const {
119
- formatMessage
120
- } = useIntl();
121
- const isScrollableRegion = tabIndex !== undefined;
122
- return /*#__PURE__*/React.createElement("div", {
123
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
124
- className: TableSharedCssClassName.TABLE_NODE_WRAPPER,
125
- ref: wrapperRef,
126
- onScroll: stickyHeaders ? onScroll : undefined
127
- // Adding tabIndex here because this is a scrollable container and it needs to be focusable so keyboard users can scroll it.
128
- // eslint-disable-next-line @atlassian/a11y/no-noninteractive-tabindex
129
- ,
130
- tabIndex: tabIndex,
131
- role: isScrollableRegion ? 'region' : undefined,
132
- "aria-label": isScrollableRegion ? formatMessage(tableMessages.tableScrollRegion) : undefined
133
- }, children);
134
- };
135
- export const tableCanBeSticky = (node, children
136
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
- ) => {
138
- return isHeaderRowEnabled(children) && node && node.firstChild && !hasRowspan(node.firstChild);
153
+ nestedRendererType
154
+ } = useRendererContext();
155
+ const isInsideOfRefSyncBlock = nestedRendererType === 'syncedBlock';
156
+ if (!isInsideOfRefSyncBlock) {
157
+ return null;
158
+ }
159
+ return /*#__PURE__*/React.createElement(TableFakeBorders, {
160
+ isNumberColumnEnabled: isNumberColumnEnabled
161
+ });
139
162
  };
163
+
140
164
  /**
141
- *
142
- */
165
+ * TableContainer renders tables using only CSS-based rules
166
+ */
143
167
  // Ignored via go/ees005
144
168
  // eslint-disable-next-line @repo/internal/react/no-class-components
145
169
  export class TableContainer extends React.Component {
@@ -157,6 +181,12 @@ export class TableContainer extends React.Component {
157
181
  _defineProperty(this, "stickyWrapperRef", /*#__PURE__*/React.createRef());
158
182
  _defineProperty(this, "wrapperRef", /*#__PURE__*/React.createRef());
159
183
  _defineProperty(this, "overflowParent", null);
184
+ _defineProperty(this, "containerRef", null);
185
+ _defineProperty(this, "_isInsideNestedRenderer", null);
186
+ _defineProperty(this, "_isInsideTableCell", null);
187
+ // Stores the last computed style values from render() for use by applyNestedRendererTableFix().
188
+ // This avoids reading from the DOM which can be stale when React removes properties between renders.
189
+ _defineProperty(this, "lastComputedStyle", {});
160
190
  _defineProperty(this, "resizeObserver", null);
161
191
  _defineProperty(this, "applyResizerChange", entries => {
162
192
  let wrapperWidth = this.state.wrapperWidth;
@@ -175,6 +205,27 @@ export class TableContainer extends React.Component {
175
205
  });
176
206
  }
177
207
  });
208
+ /**
209
+ * Callback ref that captures the container DOM element and also forwards
210
+ * to the handleRef prop from the overflow shadow HOC.
211
+ */
212
+ _defineProperty(this, "setContainerRef", el => {
213
+ if (this.containerRef !== el) {
214
+ this._isInsideNestedRenderer = null;
215
+ this._isInsideTableCell = null;
216
+ }
217
+ this.containerRef = el;
218
+ const {
219
+ handleRef
220
+ } = this.props;
221
+ if (typeof handleRef === 'function') {
222
+ handleRef(el);
223
+ } else if (handleRef && typeof handleRef === 'object') {
224
+ // Ignored via go/ees005
225
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
226
+ handleRef.current = el;
227
+ }
228
+ });
178
229
  _defineProperty(this, "componentWillUnmount", () => {
179
230
  if (this.overflowParent) {
180
231
  // Ignored via go/ees005
@@ -250,6 +301,137 @@ export class TableContainer extends React.Component {
250
301
  });
251
302
  }
252
303
  /**
304
+ * Checks if this table is inside a nested renderer (e.g. Include Page macro)
305
+ * by looking for multiple .ak-renderer-document ancestors in the DOM.
306
+ * The result is cached since a table's position in the DOM tree is stable after mount.
307
+ */
308
+ isInsideNestedRenderer() {
309
+ if (this._isInsideNestedRenderer !== null) {
310
+ return this._isInsideNestedRenderer;
311
+ }
312
+ if (!this.containerRef) {
313
+ return false;
314
+ }
315
+ let docAncestorCount = 0;
316
+ let el = this.containerRef.parentElement;
317
+ while (el) {
318
+ if (el.classList.contains(RendererCssClassName.DOCUMENT)) {
319
+ docAncestorCount++;
320
+ if (docAncestorCount >= 2) {
321
+ this._isInsideNestedRenderer = true;
322
+ return true;
323
+ }
324
+ }
325
+ el = el.parentElement;
326
+ }
327
+ this._isInsideNestedRenderer = false;
328
+ return false;
329
+ }
330
+
331
+ /**
332
+ * Checks if this table is inside a table cell in the DOM. The result is cached
333
+ * since a table's position in the DOM tree is stable after mount.
334
+ */
335
+ isInsideTableCell() {
336
+ if (this._isInsideTableCell !== null) {
337
+ return this._isInsideTableCell;
338
+ }
339
+ if (!this.containerRef) {
340
+ return false;
341
+ }
342
+ this._isInsideTableCell = Boolean(this.containerRef.closest('td, th'));
343
+ return this._isInsideTableCell;
344
+ }
345
+ isInsideTableContext() {
346
+ return Boolean(this.props.isInsideOfTable || this.isInsideTableCell());
347
+ }
348
+
349
+ /**
350
+ * For tables inside nested renderers (e.g. Include Page macro), the parent
351
+ * renderer's CSS override forces width:100%!important and left:0!important
352
+ * which overrides the inline styles set by this component. Using
353
+ * style.setProperty with 'important' priority on inline styles beats
354
+ * stylesheet !important rules per the CSS cascade.
355
+ *
356
+ * Tables that are nested inside another table need to remain constrained by
357
+ * their table-cell context. Do not promote their width to inline !important,
358
+ * otherwise nested tables rendered through macros such as Excerpt Include can
359
+ * overflow and overlap adjacent cells.
360
+ *
361
+ * Top-level tables in nested renderers still preserve their saved width, but
362
+ * are capped to their containing block so wide tables do not escape constrained
363
+ * macro bodies such as Excerpt Include panels.
364
+ *
365
+ * Uses lastComputedStyle (populated during render) rather than reading from
366
+ * element.style, because React may remove properties from the DOM when their
367
+ * values transition to undefined between renders.
368
+ *
369
+ * `platform_nested_table_style_override_2` fixes a follow-up regression where a
370
+ * NON-resized table inside an Excerpt macro (not Excerpt Include) on a
371
+ * wide/full-width page shrinks to only show its first columns in the renderer.
372
+ * Inside a nested renderer (a macro body) a non-resized table's computed width
373
+ * is a default layout cap (760px/1800px, or a `cqw` length for full-page
374
+ * appearances) taken from the outer renderer's width context. That value does
375
+ * not match the macro's own box, so promoting it to inline `!important` makes
376
+ * the table collapse. Such tables have no author-chosen size to preserve, so
377
+ * under this gate we re-assert the parent stylesheet's intent (fill the box:
378
+ * `width: 100%; left: 0`) with inline `!important`.
379
+ *
380
+ * Explicitly resized tables (`tableNode.attrs.width` set) are excluded and keep
381
+ * the original PGXT-10226 behavior: their author-chosen width/left is promoted
382
+ * verbatim so the Include Page macro does not stretch or indent them. The
383
+ * table-cell short-circuit (PGXT-10294) above also still applies.
384
+ */
385
+ applyNestedRendererTableFix() {
386
+ var _this$props$tableNode;
387
+ if (!this.containerRef || !fg('platform_nested_table_style_override')) {
388
+ return;
389
+ }
390
+ if (!this.isInsideNestedRenderer() || this.isInsideTableContext()) {
391
+ return;
392
+ }
393
+ const {
394
+ width,
395
+ left,
396
+ marginLeft
397
+ } = this.lastComputedStyle;
398
+ const style = this.containerRef.style;
399
+
400
+ // A table is "explicitly resized" when the author set a width on the node.
401
+ // Non-resized tables instead take a default layout cap (e.g. 760px/1800px)
402
+ // derived from the outer renderer's appearance.
403
+ const isExplicitlyResized = Boolean((_this$props$tableNode = this.props.tableNode) === null || _this$props$tableNode === void 0 ? void 0 : _this$props$tableNode.attrs.width);
404
+ if (!isExplicitlyResized && fg('platform_nested_table_style_override_2')) {
405
+ // PGXT-10421: For a NON-resized table inside a nested renderer (e.g. an
406
+ // Excerpt macro body), the computed width is a default layout cap
407
+ // (760px/1800px, or a `cqw` length for full-page appearances) taken from
408
+ // the *outer* renderer's width context. That value does not match the
409
+ // macro's own box, so promoting it to inline `!important` makes the table
410
+ // ignore the available space and collapse to its first columns.
411
+ //
412
+ // These tables have no author-chosen size to preserve, so re-assert the
413
+ // parent stylesheet's intent — fill the available box (`width: 100%`) —
414
+ // with inline `!important` priority so it survives React re-renders and
415
+ // wins over the stylesheet rule that leaks into nested renderers.
416
+ style.setProperty('width', '100%', 'important');
417
+ style.setProperty('max-width', '100%', 'important');
418
+ style.setProperty('left', '0', 'important');
419
+ style.setProperty('margin-left', '0', 'important');
420
+ return;
421
+ }
422
+
423
+ // PGXT-10226: An explicitly resized table inside a nested renderer (e.g.
424
+ // Include Page macro) must keep its author-chosen width and position. The
425
+ // parent stylesheet forces `width: 100% !important; left: 0 !important`,
426
+ // which would stretch and indent it, so we promote the component's own
427
+ // computed width/left with inline `!important` to win the cascade.
428
+ style.setProperty('width', width || 'auto', 'important');
429
+ style.setProperty('max-width', '100%', 'important');
430
+ style.setProperty('left', left || 'auto', 'important');
431
+ style.setProperty('margin-left', marginLeft || '0', 'important');
432
+ }
433
+ /**
434
+ * Starts observing table dimensions and wires sticky header/scrollbar behavior after mount.
253
435
  *
254
436
  * @example
255
437
  */
@@ -271,9 +453,11 @@ export class TableContainer extends React.Component {
271
453
  if (this.wrapperRef.current && isStickyScrollbarEnabled(this.props.rendererAppearance)) {
272
454
  this.stickyScrollbar = new TableStickyScrollbar(this.wrapperRef.current);
273
455
  }
456
+ this.applyNestedRendererTableFix();
274
457
  }
275
458
 
276
459
  /**
460
+ * Updates sticky header wiring and scroll synchronization after prop or state changes.
277
461
  *
278
462
  * @param prevProps
279
463
  * @param prevState
@@ -300,9 +484,13 @@ export class TableContainer extends React.Component {
300
484
  if (prevState.stickyMode !== this.state.stickyMode) {
301
485
  this.onWrapperScrolled();
302
486
  }
487
+
488
+ // React re-applies the style prop on every render, which overwrites the
489
+ // !important priorities set at mount time. Re-apply after each update.
490
+ this.applyNestedRendererTableFix();
303
491
  }
304
492
  /**
305
- *
493
+ * Calculates the top offset used when the sticky header is pinned to the table bottom.
306
494
  */
307
495
  get pinTop() {
308
496
  if (!this.tableRef.current || !this.stickyHeaderRef.current) {
@@ -312,7 +500,7 @@ export class TableContainer extends React.Component {
312
500
  }
313
501
 
314
502
  /**
315
- *
503
+ * Determines whether sticky header positioning should include the default scroll root offset.
316
504
  */
317
505
  get shouldAddOverflowParentOffsetTop_DO_NOT_USE() {
318
506
  // IF the StickyHeaderConfig specifies that the default scroll root offsetTop should be added
@@ -323,7 +511,7 @@ export class TableContainer extends React.Component {
323
511
  }
324
512
 
325
513
  /**
326
- *
514
+ * Resolves the top position for the sticky header based on the current sticky mode.
327
515
  */
328
516
  get stickyTop() {
329
517
  switch (this.state.stickyMode) {
@@ -343,6 +531,7 @@ export class TableContainer extends React.Component {
343
531
  }
344
532
 
345
533
  /**
534
+ * Renders the table container, sticky header, table content, sticky scrollbar, and synced block borders.
346
535
  *
347
536
  * @example
348
537
  */
@@ -351,7 +540,6 @@ export class TableContainer extends React.Component {
351
540
  const {
352
541
  isNumberColumnEnabled,
353
542
  layout,
354
- renderWidth,
355
543
  columnWidths,
356
544
  stickyHeaders,
357
545
  tableNode,
@@ -369,64 +557,43 @@ export class TableContainer extends React.Component {
369
557
  stickyMode
370
558
  } = this.state;
371
559
  const lineLengthFixedWidth = akEditorDefaultLayoutWidth;
372
- let left;
373
560
  let updatedLayout;
374
-
375
- // The tableWidth and left offset logic below must stay aligned with the `breakout-ssr.tsx` logic
376
- // Please consider changes below carefully to not negatively impact SSR
377
- // `renderWidth` cannot be depended on during SSR
378
- const isRenderWidthValid = !!renderWidth && renderWidth > 0;
379
561
  const fullPageRendererWidthCSS = editorExperiment('platform_editor_preview_panel_responsiveness', true, {
380
562
  exposure: true
381
563
  }) ? 'calc(100cqw - var(--ak-renderer--full-page-gutter) * 2)' : `100cqw - ${FullPagePadding}px * 2`;
382
564
  const renderWidthCSS = rendererAppearance === 'full-page' ? fullPageRendererWidthCSS : `100cqw`;
383
565
  const calcDefaultLayoutWidthByAppearance = (rendererAppearance, tableNode) => {
384
- if (rendererAppearance === 'full-width' && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
385
- return [isRenderWidthValid ? Math.min(akEditorFullWidthLayoutWidth, renderWidth) : akEditorFullWidthLayoutWidth, `min(${akEditorFullWidthLayoutWidth}px, ${renderWidthCSS})`];
386
- } else if (rendererAppearance === 'max' && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
387
- return [isRenderWidthValid ? Math.min(akEditorMaxWidthLayoutWidth, renderWidth) : akEditorMaxWidthLayoutWidth, `min(${akEditorMaxWidthLayoutWidth}px, ${renderWidthCSS})`];
566
+ if (rendererAppearance === 'max' && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width) && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true))) {
567
+ return `min(${akEditorMaxWidthLayoutWidth}px, ${renderWidthCSS})`;
568
+ } else if (rendererAppearance === 'full-width' && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
569
+ return `min(${akEditorFullWidthLayoutWidth}px, ${renderWidthCSS})`;
388
570
  } else if (rendererAppearance === 'comment' && allowTableResizing && !(tableNode !== null && tableNode !== void 0 && tableNode.attrs.width)) {
389
- const tableContainerWidth = getTableContainerWidth(tableNode);
390
- return [isRenderWidthValid ? renderWidth : tableContainerWidth, renderWidthCSS];
571
+ return renderWidthCSS;
391
572
  } else {
392
573
  // custom width, or width mapped to breakpoint
393
574
  const tableContainerWidth = getTableContainerWidth(tableNode);
394
- return [isRenderWidthValid ? Math.min(tableContainerWidth, renderWidth) : tableContainerWidth, `min(${tableContainerWidth}px, ${renderWidthCSS})`];
575
+ return `min(${tableContainerWidth}px, ${renderWidthCSS})`;
395
576
  }
396
577
  };
397
- const [tableWidth, tableWidthCSS] = calcDefaultLayoutWidthByAppearance(rendererAppearance, tableNode);
578
+ const tableWidthCSS = calcDefaultLayoutWidthByAppearance(rendererAppearance, tableNode);
398
579
 
399
580
  // Logic for table alignment in renderer
400
581
  const isTableAlignStart = tableNode && tableNode.attrs && tableNode.attrs.layout === 'align-start' && allowTableAlignment;
401
- const fullWidthLineLength = isRenderWidthValid ? Math.min(akEditorFullWidthLayoutWidth, renderWidth) : akEditorFullWidthLayoutWidth;
402
582
  const fullWidthLineLengthCSS = `min(${akEditorFullWidthLayoutWidth}px, ${renderWidthCSS})`;
403
- const maxWidthLineLength = isRenderWidthValid ? Math.min(akEditorMaxWidthLayoutWidth, renderWidth) : akEditorMaxWidthLayoutWidth;
404
583
  const maxWidthLineLengthCSS = `min(${akEditorMaxWidthLayoutWidth}px, ${renderWidthCSS})`;
405
- const commentLineLength = isRenderWidthValid ? renderWidth : lineLengthFixedWidth;
406
584
  const isCommentAppearanceAndTableAlignmentEnabled = isCommentAppearance(rendererAppearance) && allowTableAlignment;
407
- const lineLength = isFullWidthAppearance(rendererAppearance) ? fullWidthLineLength : isMaxWidthAppearance(rendererAppearance) && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) ? maxWidthLineLength : isCommentAppearanceAndTableAlignmentEnabled ? commentLineLength : lineLengthFixedWidth;
408
585
  const lineLengthCSS = isFullWidthAppearance(rendererAppearance) ? fullWidthLineLengthCSS : isMaxWidthAppearance(rendererAppearance) && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) ? maxWidthLineLengthCSS : isCommentAppearanceAndTableAlignmentEnabled ? renderWidthCSS : `${lineLengthFixedWidth}px`;
409
-
410
- // Setting fixTableSSRResizing to false while FG logic is true in tableNew
411
- const fixTableSSRResizing = false;
412
- const tableWidthNew = fixTableSSRResizing ? getTableContainerWidth(tableNode) : tableWidth;
413
- const shouldCalculateLeftForAlignment = !isInsideOfBlockNode && !isInsideOfTable && isTableAlignStart && (isFullPageAppearance(rendererAppearance) && tableWidthNew <= lineLengthFixedWidth || isFullWidthAppearance(rendererAppearance) || (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) && isMaxWidthAppearance(rendererAppearance) || isCommentAppearanceAndTableAlignmentEnabled);
586
+ const tableWidthNew = getTableContainerWidth(tableNode);
587
+ const shouldCalculateLeftForAlignment = !isInsideOfBlockNode && !isInsideOfTable && isTableAlignStart && (isFullPageAppearance(rendererAppearance) && tableWidthNew <= lineLengthFixedWidth || isFullWidthAppearance(rendererAppearance) || isMaxWidthAppearance(rendererAppearance) && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true)) || isCommentAppearanceAndTableAlignmentEnabled);
414
588
  let leftCSS;
415
589
  if (shouldCalculateLeftForAlignment) {
416
- left = (tableWidth - lineLength) / 2;
417
590
  leftCSS = `(${tableWidthCSS} - ${lineLengthCSS}) / 2`;
418
591
  }
419
- if (fixTableSSRResizing) {
420
- if (!shouldCalculateLeftForAlignment && isFullPageAppearance(rendererAppearance)) {
421
- // Note tableWidthCSS here is the renderer width
422
- // When the screen is super wide we want table to break out.
423
- // However if screen is smaller than 760px. We want table align to left.
424
- leftCSS = `min(0px, ${lineLengthCSS} - ${tableWidthCSS}) / 2`;
425
- }
426
- } else {
427
- if (!shouldCalculateLeftForAlignment && isFullPageAppearance(rendererAppearance) && tableWidthNew > lineLengthFixedWidth) {
428
- left = lineLengthFixedWidth / 2 - tableWidth / 2;
429
- }
592
+ if (!shouldCalculateLeftForAlignment && isFullPageAppearance(rendererAppearance)) {
593
+ // Note tableWidthCSS here is the renderer width
594
+ // When the screen is super wide we want table to break out.
595
+ // However if screen is smaller than 760px. We want table align to left.
596
+ leftCSS = `min(0px, ${lineLengthCSS} - ${tableWidthCSS}) / 2`;
430
597
  }
431
598
  const children = React.Children.toArray(this.props.children);
432
599
 
@@ -446,7 +613,7 @@ export class TableContainer extends React.Component {
446
613
  // We can only use CSS to determine the width when we have a known width in container.
447
614
  // When appearance is full-page, full-width or comment we use CSS based width calculation.
448
615
  // Otherwise it's fixed table width (customized width) or inherit.
449
- if ((rendererAppearance === 'full-page' || rendererAppearance === 'full-width' || rendererAppearance === 'max') && fixTableSSRResizing) {
616
+ if (rendererAppearance === 'full-page' || rendererAppearance === 'full-width' || rendererAppearance === 'max' && (expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true))) {
450
617
  finalTableContainerWidth = allowTableResizing ? `calc(${tableWidthCSS})` : 'inherit';
451
618
  }
452
619
  if (rendererAppearance === 'comment' && allowTableResizing && !allowTableAlignment) {
@@ -457,13 +624,13 @@ export class TableContainer extends React.Component {
457
624
 
458
625
  // !NOTE: it a table resized to 760 is copied from 'full-page' editor and pasted in comment editor
459
626
  // where (allowTableResizing && !allowTableAlignment), the table will loose 760px width.
460
- finalTableContainerWidth = tableNode !== null && tableNode !== void 0 && tableNode.attrs.width && (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.width) !== akEditorDefaultLayoutWidth ? fixTableSSRResizing ? `calc(${tableWidthCSS})` : tableWidth : 'inherit';
627
+ finalTableContainerWidth = tableNode !== null && tableNode !== void 0 && tableNode.attrs.width && (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.width) !== akEditorDefaultLayoutWidth ? `calc(${tableWidthCSS})` : 'inherit';
461
628
  }
462
629
  if (rendererAppearance === 'comment' && allowTableResizing && allowTableAlignment) {
463
630
  // If table alignment is enabled and layout is not 'align-start' or 'center', we are loading a table that was
464
631
  // created before "Support Table in Comments" FF was enabled. So the table should have the same width as renderer container
465
632
  // instead of 760 that was set on tableNode when the table had been published.
466
- finalTableContainerWidth = ((tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout) === 'align-start' || (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout) === 'center') && tableNode !== null && tableNode !== void 0 && tableNode.attrs.width ? fixTableSSRResizing ? `calc(${tableWidthCSS})` : tableWidth : 'inherit';
633
+ finalTableContainerWidth = ((tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout) === 'align-start' || (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout) === 'center') && tableNode !== null && tableNode !== void 0 && tableNode.attrs.width ? `calc(${tableWidthCSS})` : 'inherit';
467
634
  }
468
635
  const isContentModeTable = isTableInContentMode({
469
636
  tableNode,
@@ -473,43 +640,40 @@ export class TableContainer extends React.Component {
473
640
  }),
474
641
  isTableNested: isInsideOfBlockNode || isInsideOfNestedRenderer || isInsideOfTable
475
642
  }) && expValEquals('platform_editor_table_fit_to_content_auto_convert', 'isEnabled', true);
476
- let style;
477
- if (fixTableSSRResizing) {
478
- style = {
479
- ...(isContentModeTable && {
480
- '--renderer-table-max-width': renderWidthCSS
481
- }),
482
- width: finalTableContainerWidth,
483
- left: leftCSS ? `calc(${leftCSS})` : undefined,
484
- marginLeft: shouldCalculateLeftForAlignment && leftCSS !== undefined ? `calc(-1 * (${leftCSS}))` : undefined
485
- };
486
- } else {
487
- style = {
488
- ...(isContentModeTable && {
489
- '--renderer-table-max-width': `${renderWidth}px`
490
- }),
491
- width: finalTableContainerWidth,
492
- left: left,
493
- marginLeft: shouldCalculateLeftForAlignment && left !== undefined ? -left : undefined
494
- };
495
- }
643
+ const style = {
644
+ ...(isContentModeTable && {
645
+ '--renderer-table-max-width': renderWidthCSS
646
+ }),
647
+ width: finalTableContainerWidth,
648
+ left: leftCSS ? `calc(${leftCSS})` : undefined,
649
+ marginLeft: shouldCalculateLeftForAlignment && leftCSS !== undefined ? `calc(-1 * (${leftCSS}))` : undefined
650
+ };
651
+
652
+ // Store computed style values for applyNestedRendererTableFix() to use.
653
+ // Reading from props rather than the DOM ensures correctness when React
654
+ // removes properties (transitions from set to undefined) between renders.
655
+ this.lastComputedStyle = {
656
+ width: typeof style.width === 'number' ? `${style.width}px` : style.width,
657
+ left: style.left,
658
+ marginLeft: style.marginLeft
659
+ };
496
660
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
497
661
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
498
662
  className: `${TableSharedCssClassName.TABLE_CONTAINER} ${this.props.shadowClassNames || ''}`,
499
663
  "data-layout": updatedLayout,
500
- ref: this.props.handleRef
501
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
502
- ,
664
+ "data-testid": "table-container",
665
+ ref: this.setContainerRef,
503
666
  style: style
667
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
504
668
  }, isStickyScrollbarEnabled(this.props.rendererAppearance) && /*#__PURE__*/React.createElement("div", {
505
669
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
506
670
  className: TableSharedCssClassName.TABLE_STICKY_SCROLLBAR_SENTINEL_TOP,
507
671
  "data-testid": "sticky-scrollbar-sentinel-top"
508
- }), stickyHeaders && tableCanBeSticky(tableNode, children) && /*#__PURE__*/React.createElement(StickyTable, {
672
+ }), stickyHeaders && tableNode && !isContentModeTable && tableCanBeSticky(tableNode, children) && /*#__PURE__*/React.createElement(StickyTable, {
509
673
  isNumberColumnEnabled: isNumberColumnEnabled,
510
- tableWidth: tableWidth,
674
+ tableWidth: "inherit",
675
+ renderWidth: 0,
511
676
  layout: layout,
512
- renderWidth: renderWidth,
513
677
  handleRef: this.props.handleRef,
514
678
  shadowClassNames: this.props.shadowClassNames,
515
679
  top: this.stickyTop,
@@ -522,17 +686,23 @@ export class TableContainer extends React.Component {
522
686
  rendererAppearance: rendererAppearance,
523
687
  allowTableResizing: allowTableResizing,
524
688
  allowFixedColumnWidthOption: allowFixedColumnWidthOption
525
- }, [children && children[0]]), /*#__PURE__*/React.createElement(TableWrapper, {
526
- wrapperRef: this.wrapperRef,
527
- onScroll: this.props.stickyHeaders ? this.onWrapperScrolled : undefined,
528
- stickyHeaders: stickyHeaders,
529
- tabIndex: this.props.tabIndex
689
+ }, [children && children[0]]), /*#__PURE__*/React.createElement("div", {
690
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
691
+ className: TableSharedCssClassName.TABLE_NODE_WRAPPER,
692
+ ref: this.wrapperRef,
693
+ "data-number-column": tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.isNumberColumnEnabled,
694
+ "data-layout": tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.layout,
695
+ "data-autosize": tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.__autoSize,
696
+ "data-table-local-id": tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.localId,
697
+ "data-table-width": tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.width,
698
+ "data-vc": "table-node-wrapper",
699
+ onScroll: this.props.stickyHeaders && this.onWrapperScrolled
530
700
  }, /*#__PURE__*/React.createElement(Table, {
531
701
  innerRef: this.tableRef,
532
702
  columnWidths: columnWidths,
533
703
  layout: layout,
704
+ renderWidth: 0,
534
705
  isNumberColumnEnabled: isNumberColumnEnabled,
535
- renderWidth: renderWidth,
536
706
  tableNode: tableNode,
537
707
  rendererAppearance: rendererAppearance,
538
708
  isInsideOfBlockNode: isInsideOfBlockNode,
@@ -544,22 +714,16 @@ export class TableContainer extends React.Component {
544
714
  allowFixedColumnWidthOption: allowFixedColumnWidthOption
545
715
  }, this.grabFirstRowRef(children))), isStickyScrollbarEnabled(this.props.rendererAppearance) && /*#__PURE__*/React.createElement("div", {
546
716
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
547
- className: TableSharedCssClassName.TABLE_STICKY_SCROLLBAR_CONTAINER,
717
+ className: `${TableSharedCssClassName.TABLE_STICKY_SCROLLBAR_CONTAINER}${fg('confluence_frontend_table_scrollbar_ttvc_fix') ? '-view-page' : ''}`,
548
718
  ref: this.stickyScrollbarRef,
549
- style: {
550
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
551
- height: "var(--ds-space-250, 20px)",
552
- // MAX_BROWSER_SCROLLBAR_HEIGHT
553
- // Follow editor to hide by default so it does not show empty gap in SSR
554
- // https://bitbucket.org/atlassian/atlassian-frontend-monorepo/src/master/platform/packages/editor/editor-plugin-table/src/nodeviews/TableComponent.tsx#957
555
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
556
- display: fixTableSSRResizing ? 'none' : 'block',
557
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
558
- width: '100%'
559
- }
719
+ "data-vc": "table-sticky-scrollbar-container",
720
+ style: fg('confluence_frontend_table_scrollbar_ttvc_fix') ? {
721
+ ...stickyContainerBaseStyles,
722
+ ...stickyContainerAdditionalStyles
723
+ } : stickyContainerBaseStyles
560
724
  }, /*#__PURE__*/React.createElement("div", {
561
725
  style: {
562
- width: (_this$tableRef$curren = this.tableRef.current) === null || _this$tableRef$curren === void 0 ? void 0 : _this$tableRef$curren.clientWidth,
726
+ width: fg('confluence_frontend_table_scrollbar_ttvc_fix') ? '100%' : (_this$tableRef$curren = this.tableRef.current) === null || _this$tableRef$curren === void 0 ? void 0 : _this$tableRef$curren.clientWidth,
563
727
  // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
564
728
  height: '100%'
565
729
  }
@@ -572,12 +736,110 @@ export class TableContainer extends React.Component {
572
736
  })));
573
737
  }
574
738
  }
739
+ const getCellEdgePropsByCellOffset = (tableNode, isNumberColumnEnabled) => {
740
+ const cellEdgePropsByCellOffset = new Map();
741
+ const cellRightByCellOffset = new Map();
742
+ const occupiedGrid = [];
743
+ let tableWidth = 0;
744
+ let cellOffset = 0;
745
+ tableNode.forEach((rowNode, _rowOffset, rowIndex) => {
746
+ var _occupiedGrid$rowInde;
747
+ occupiedGrid[rowIndex] = (_occupiedGrid$rowInde = occupiedGrid[rowIndex]) !== null && _occupiedGrid$rowInde !== void 0 ? _occupiedGrid$rowInde : [];
748
+ let columnIndex = 0;
749
+ cellOffset += 1;
750
+ rowNode.forEach(cellNode => {
751
+ while (occupiedGrid[rowIndex][columnIndex]) {
752
+ columnIndex += 1;
753
+ }
754
+ const colspan = cellNode.attrs.colspan || 1;
755
+ const rowspan = cellNode.attrs.rowspan || 1;
756
+ const cellLeft = columnIndex;
757
+ const cellRight = cellLeft + colspan;
758
+ const cellTop = rowIndex;
759
+ const cellBottom = cellTop + rowspan;
760
+ for (let row = cellTop; row < cellBottom; row += 1) {
761
+ var _occupiedGrid$row;
762
+ occupiedGrid[row] = (_occupiedGrid$row = occupiedGrid[row]) !== null && _occupiedGrid$row !== void 0 ? _occupiedGrid$row : [];
763
+ for (let column = cellLeft; column < cellRight; column += 1) {
764
+ occupiedGrid[row][column] = true;
765
+ }
766
+ }
767
+ tableWidth = Math.max(tableWidth, cellRight);
768
+ cellRightByCellOffset.set(cellOffset, cellRight);
769
+ cellEdgePropsByCellOffset.set(cellOffset, {
770
+ reachesBottom: cellBottom >= tableNode.childCount,
771
+ // With number column enabled, PM column 0 is not visually leftmost and must not get `data-reaches-left`.
772
+ reachesLeft: cellLeft === 0 && !isNumberColumnEnabled,
773
+ reachesRight: false,
774
+ reachesTop: cellTop === 0
775
+ });
776
+ columnIndex = cellRight;
777
+ cellOffset += cellNode.nodeSize;
778
+ });
779
+ cellOffset += 1;
780
+ });
781
+ cellRightByCellOffset.forEach((cellRight, currentCellOffset) => {
782
+ const edgeProps = cellEdgePropsByCellOffset.get(currentCellOffset);
783
+ if (edgeProps) {
784
+ edgeProps.reachesRight = cellRight >= tableWidth;
785
+ }
786
+ });
787
+ return cellEdgePropsByCellOffset;
788
+ };
789
+ const isRenderedTableCell = element => {
790
+ const {
791
+ nodeType
792
+ } = element.props;
793
+ return nodeType === 'tableCell' || nodeType === 'tableHeader' || element.type === TableCell || element.type === TableHeader;
794
+ };
795
+ const addTableCellEdgePropsThroughWrappers = (rows, tableNode, isNumberColumnEnabled) => {
796
+ try {
797
+ if (!tableNode) {
798
+ return rows;
799
+ }
800
+ const cellEdgePropsByCellOffset = getCellEdgePropsByCellOffset(tableNode, isNumberColumnEnabled);
801
+ let cellOffset = 0;
802
+ return React.Children.map(rows, (row, rowIndex) => {
803
+ const rowNode = tableNode.child(rowIndex);
804
+ cellOffset += 1;
805
+ let cellIndex = 0;
806
+ const addEdgePropsToRenderedCells = element => {
807
+ if (isRenderedTableCell(element)) {
808
+ const cellNode = rowNode.child(cellIndex);
809
+ const edgeProps = cellEdgePropsByCellOffset.get(cellOffset);
810
+ cellIndex += 1;
811
+ cellOffset += cellNode.nodeSize;
812
+ return edgeProps ? /*#__PURE__*/React.cloneElement(element, edgeProps) : element;
813
+ }
814
+ const {
815
+ children
816
+ } = element.props;
817
+ if (children === undefined) {
818
+ return element;
819
+ }
820
+ const childrenWithEdgeProps = React.Children.map(children, child => /*#__PURE__*/React.isValidElement(child) ? addEdgePropsToRenderedCells(child) : child);
821
+ return /*#__PURE__*/React.cloneElement(element, undefined, childrenWithEdgeProps);
822
+ };
823
+ const rowWithEdgeProps = addEdgePropsToRenderedCells(row);
824
+ if (cellIndex !== rowNode.childCount) {
825
+ throw new Error('Rendered table row does not match its document node');
826
+ }
827
+ cellOffset += 1;
828
+ return rowWithEdgeProps;
829
+ });
830
+ } catch {
831
+ // Renderer can receive malformed historical ADF. If the table shape cannot
832
+ // be described safely, keep rendering without rounded edge metadata.
833
+ return rows;
834
+ }
835
+ };
836
+
575
837
  /**
576
- *
838
+ * Processes table children before passing them to the styled table container.
577
839
  */
578
840
  // Ignored via go/ees005
579
841
  // eslint-disable-next-line @repo/internal/react/no-class-components
580
- export class TableProcessor extends React.Component {
842
+ export class TableProcessorWithContainerStyles extends React.Component {
581
843
  constructor(...args) {
582
844
  super(...args);
583
845
  _defineProperty(this, "state", {
@@ -613,33 +875,78 @@ export class TableProcessor extends React.Component {
613
875
  isNumberColumnEnabled
614
876
  } = this.props;
615
877
  const headerRowEnabled = isHeaderRowEnabled(rows);
878
+ const lastRowIndex = React.Children.count(rows) - 1;
616
879
  return React.Children.map(rows, (row, index) => {
617
880
  return /*#__PURE__*/React.cloneElement(React.Children.only(row), {
618
881
  isNumberColumnEnabled,
619
- index: headerRowEnabled ? index === 0 ? '' : index : index + 1
882
+ index: headerRowEnabled ? index === 0 ? '' : index : index + 1,
883
+ isFirstRow: index === 0,
884
+ isLastRow: index === lastRowIndex
620
885
  });
621
886
  });
622
887
  });
623
888
  }
624
889
  /**
890
+ * Renders processed table children inside the table container.
625
891
  *
626
892
  * @example
627
893
  */
628
894
  render() {
629
895
  const {
630
- children
896
+ allowColumnSorting,
897
+ allowFixedColumnWidthOption,
898
+ allowTableAlignment,
899
+ allowTableResizing,
900
+ children,
901
+ columnWidths,
902
+ disableTableOverflowShadow,
903
+ handleRef,
904
+ isinsideMultiBodiedExtension,
905
+ isInsideOfBlockNode,
906
+ isInsideOfNestedRenderer,
907
+ isInsideOfTable,
908
+ isNumberColumnEnabled,
909
+ isPresentational,
910
+ layout,
911
+ rendererAppearance,
912
+ renderWidth,
913
+ shadowClassNames,
914
+ smartCardStorage,
915
+ stickyHeaders,
916
+ tabIndex,
917
+ tableNode
631
918
  } = this.props;
632
919
  if (!children) {
633
920
  return null;
634
921
  }
635
922
  const childrenArray = React.Children.toArray(children);
923
+ const childrenWithTableEdgeProps = expValEquals('platform_editor_table_q4_loveability', 'isEnabled', true) ? addTableCellEdgePropsThroughWrappers(childrenArray, tableNode, isNumberColumnEnabled) : childrenArray;
636
924
  const orderedChildren = compose(this.addNumberColumnIndexes, this.addSortableColumn
637
925
  // @ts-expect-error TS2345: Argument of type '(ReactChild | ReactFragment | ReactPortal)[]' is not assignable to parameter of type 'ReactElement<any, string | JSXElementConstructor<any>>[]'
638
- )(childrenArray);
639
-
640
- // Ignored via go/ees005
641
- // eslint-disable-next-line react/jsx-props-no-spreading
642
- return /*#__PURE__*/React.createElement(TableContainer, this.props, orderedChildren);
926
+ )(childrenWithTableEdgeProps);
927
+ return /*#__PURE__*/React.createElement(TableContainer, {
928
+ allowColumnSorting: allowColumnSorting,
929
+ allowFixedColumnWidthOption: allowFixedColumnWidthOption,
930
+ allowTableAlignment: allowTableAlignment,
931
+ allowTableResizing: allowTableResizing,
932
+ columnWidths: columnWidths,
933
+ disableTableOverflowShadow: disableTableOverflowShadow,
934
+ handleRef: handleRef,
935
+ isinsideMultiBodiedExtension: isinsideMultiBodiedExtension,
936
+ isInsideOfBlockNode: isInsideOfBlockNode,
937
+ isInsideOfNestedRenderer: isInsideOfNestedRenderer,
938
+ isInsideOfTable: isInsideOfTable,
939
+ isNumberColumnEnabled: isNumberColumnEnabled,
940
+ isPresentational: isPresentational,
941
+ layout: layout,
942
+ rendererAppearance: rendererAppearance,
943
+ renderWidth: renderWidth,
944
+ shadowClassNames: shadowClassNames,
945
+ smartCardStorage: smartCardStorage,
946
+ stickyHeaders: stickyHeaders,
947
+ tabIndex: tabIndex,
948
+ tableNode: tableNode
949
+ }, orderedChildren);
643
950
  }
644
951
  }
645
952
 
@@ -653,69 +960,29 @@ const TableWithShadowsAndContainerStyles = overflowShadow(TableProcessorWithCont
653
960
  overflowSelector: `:scope > .${TableSharedCssClassName.TABLE_NODE_WRAPPER}`,
654
961
  useShadowObserver: true
655
962
  });
656
-
657
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
658
- const TableWithShadows = overflowShadow(TableProcessor, {
659
- /**
660
- * The :scope is in reference to table container and we are selecting only
661
- * direct children that match the table node wrapper selector, not their
662
- * descendants.
663
- */
664
- overflowSelector: `:scope > .${TableSharedCssClassName.TABLE_NODE_WRAPPER}`,
665
- useShadowObserver: true
666
- });
667
963
  const TableWithWidth = props => {
964
+ var _props$columnWidths;
668
965
  const {
669
966
  isTopLevelRenderer
670
967
  } = useRendererContext();
671
968
  const isInsideOfNestedRenderer = isTopLevelRenderer === false && expValEquals('platform_editor_table_nested_content_mode_fix', 'isEnabled', true);
672
- if (fg('platform-ssr-table-resize')) {
673
- var _props$columnWidths;
674
- const colWidthsSum =
675
- // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
676
- ((_props$columnWidths = props.columnWidths) === null || _props$columnWidths === void 0 ? void 0 : _props$columnWidths.reduce((total, val) => total + val, 0)) || 0;
677
- if (colWidthsSum || props.allowTableResizing) {
678
- return /*#__PURE__*/React.createElement(TableWithShadowsAndContainerStyles
679
- // Ignored via go/ees005
680
- // eslint-disable-next-line react/jsx-props-no-spreading
681
- , _extends({}, props, {
682
- isInsideOfNestedRenderer: isInsideOfNestedRenderer
683
- }));
684
- }
685
- return /*#__PURE__*/React.createElement(TableProcessorWithContainerStyles
969
+ const colWidthsSum =
970
+ // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
971
+ ((_props$columnWidths = props.columnWidths) === null || _props$columnWidths === void 0 ? void 0 : _props$columnWidths.reduce((total, val) => total + val, 0)) || 0;
972
+ if (colWidthsSum || props.allowTableResizing) {
973
+ return /*#__PURE__*/React.createElement(TableWithShadowsAndContainerStyles
686
974
  // Ignored via go/ees005
687
975
  // eslint-disable-next-line react/jsx-props-no-spreading
688
976
  , _extends({}, props, {
689
977
  isInsideOfNestedRenderer: isInsideOfNestedRenderer
690
978
  }));
691
- } else {
692
- return /*#__PURE__*/React.createElement(WidthConsumer, null, ({
693
- width
694
- }) => {
695
- var _props$columnWidths2;
696
- const renderWidth = props.rendererAppearance === 'full-page' ? width - FullPagePadding * 2 : width;
697
- const colWidthsSum =
698
- // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed)
699
- ((_props$columnWidths2 = props.columnWidths) === null || _props$columnWidths2 === void 0 ? void 0 : _props$columnWidths2.reduce((total, val) => total + val, 0)) || 0;
700
- if (colWidthsSum || props.allowTableResizing) {
701
- return /*#__PURE__*/React.createElement(TableWithShadows, _extends({
702
- renderWidth: renderWidth
703
- // Ignored via go/ees005
704
- // eslint-disable-next-line react/jsx-props-no-spreading
705
- }, props, {
706
- isInsideOfNestedRenderer: isInsideOfNestedRenderer
707
- }));
708
- }
709
- // there should not be a case when colWidthsSum is 0 and table is in overflow state - so no need to render shadows in this case
710
- return /*#__PURE__*/React.createElement(TableProcessor, _extends({
711
- renderWidth: renderWidth
712
- // Ignored via go/ees005
713
- // eslint-disable-next-line react/jsx-props-no-spreading
714
- }, props, {
715
- isInsideOfNestedRenderer: isInsideOfNestedRenderer
716
- }));
717
- });
718
979
  }
980
+ return /*#__PURE__*/React.createElement(TableProcessorWithContainerStyles
981
+ // Ignored via go/ees005
982
+ // eslint-disable-next-line react/jsx-props-no-spreading
983
+ , _extends({}, props, {
984
+ isInsideOfNestedRenderer: isInsideOfNestedRenderer
985
+ }));
719
986
  };
720
987
  const _default_1 = withSmartCardStorage(TableWithWidth);
721
988
  export default _default_1;