@atlaskit/code 15.6.9 → 15.7.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.
@@ -1,501 +0,0 @@
1
- // eslint-disable-file
2
- export const fiveHundredLineExample = `export const NORMAL_SEVERITY_THRESHOLD = 2000;
3
- export const DEGRADED_SEVERITY_THRESHOLD = 3000;
4
- export interface Extension<T> {
5
- extensionKey: string;
6
- parameters?: T;
7
- content?: any; // This would be the original Atlassian Document Format
8
- }
9
- const packageName = process.env._PACKAGE_NAME_ as string;
10
- const packageVersion = process.env._PACKAGE_VERSION_ as string;
11
-
12
- export type { RendererProps as Props };
13
-
14
- export class Renderer extends PureComponent<RendererProps> {
15
- private providerFactory: ProviderFactory;
16
- private serializer: ReactSerializer;
17
- private rafID?: number;
18
- private editorRef: React.RefObject<HTMLDivElement>;
19
- private mouseDownSelection?: string;
20
- private id?: string;
21
- /**
22
- * This is used in measuring the Renderer Mount time and is then
23
- * deleted once that measurement occurs.
24
- */
25
- private renderedMeasurementDistortedDurationMonitor?: {
26
- distortedDuration: boolean;
27
- cleanup: () => void;
28
- } = getDistortedDurationMonitor();
29
-
30
- constructor(props: RendererProps) {
31
- super(props);
32
- this.providerFactory = props.dataProviders || new ProviderFactory();
33
- this.serializer = new ReactSerializer(this.deriveSerializerProps(props));
34
- this.editorRef = props.innerRef || React.createRef();
35
- this.id = uuid();
36
- startMeasure("Renderer Render Time: this.id");
37
-
38
- const featureFlags = this.featureFlags(this.props.featureFlags)
39
- .featureFlags;
40
-
41
- if (featureFlags?.rendererTtiTracking) {
42
- measureTTI((tti, ttiFromInvocation, canceled) => {
43
- this.fireAnalyticsEvent({
44
- action: ACTION.RENDERER_TTI,
45
- actionSubject: ACTION_SUBJECT.RENDERER,
46
- attributes: { tti, ttiFromInvocation, canceled },
47
- eventType: EVENT_TYPE.OPERATIONAL,
48
- });
49
- });
50
- }
51
- }
52
-
53
- private anchorLinkAnalytics() {
54
- const hash =
55
- window.location.hash && decodeURIComponent(window.location.hash.slice(1));
56
- const { disableHeadingIDs } = this.props;
57
-
58
- if (
59
- !disableHeadingIDs &&
60
- hash &&
61
- this.editorRef &&
62
- this.editorRef.current instanceof HTMLElement
63
- ) {
64
- const anchorLinkElement = document.getElementById(hash);
65
- // We are not use this.editorRef.querySelector here, instead we have this.editorRef.contains
66
- // because querySelector might fail if there are special characters in hash, and CSS.escape is still experimental.
67
- if (
68
- anchorLinkElement &&
69
- this.editorRef.current.contains(anchorLinkElement)
70
- ) {
71
- this.fireAnalyticsEvent({
72
- action: ACTION.VIEWED,
73
- actionSubject: ACTION_SUBJECT.ANCHOR_LINK,
74
- attributes: { platform: PLATFORM.WEB, mode: MODE.RENDERER },
75
- eventType: EVENT_TYPE.UI,
76
- });
77
- }
78
- }
79
- }
80
-
81
- componentDidMount() {
82
- this.fireAnalyticsEvent({
83
- action: ACTION.STARTED,
84
- actionSubject: ACTION_SUBJECT.RENDERER,
85
- attributes: { platform: PLATFORM.WEB },
86
- eventType: EVENT_TYPE.UI,
87
- });
88
-
89
- this.rafID = requestAnimationFrame(() => {
90
- stopMeasure("Renderer Render Time: this.id", (duration) => {
91
- const { analyticsEventSeverityTracking } = this.props;
92
- const forceSeverityTracking =
93
- typeof analyticsEventSeverityTracking === 'undefined' &&
94
- shouldForceTracking();
95
-
96
- const severity =
97
- !!forceSeverityTracking || analyticsEventSeverityTracking?.enabled
98
- ? getAnalyticsEventSeverity(
99
- duration,
100
- analyticsEventSeverityTracking?.severityNormalThreshold ??
101
- NORMAL_SEVERITY_THRESHOLD,
102
- analyticsEventSeverityTracking?.severityDegradedThreshold ??
103
- DEGRADED_SEVERITY_THRESHOLD,
104
- )
105
- : undefined;
106
-
107
- this.fireAnalyticsEvent({
108
- action: ACTION.RENDERED,
109
- actionSubject: ACTION_SUBJECT.RENDERER,
110
- attributes: {
111
- platform: PLATFORM.WEB,
112
- duration,
113
- distortedDuration: this.renderedMeasurementDistortedDurationMonitor!
114
- .distortedDuration,
115
- ttfb: getResponseEndTime(),
116
- nodes: reduce<Record<string, number>>(
117
- this.props.document,
118
- (acc, node) => {
119
- acc[node.type] = (acc[node.type] || 0) + 1;
120
- return acc;
121
- },
122
- {},
123
- ),
124
- severity,
125
- },
126
- eventType: EVENT_TYPE.OPERATIONAL,
127
- });
128
- this.renderedMeasurementDistortedDurationMonitor!.cleanup();
129
- delete this.renderedMeasurementDistortedDurationMonitor;
130
- });
131
- this.anchorLinkAnalytics();
132
- });
133
- }
134
-
135
- private deriveSerializerProps(props: RendererProps): ReactSerializerInit {
136
- // if just passed a boolean, change shape into object to simplify type
137
- const stickyHeaders = props.stickyHeaders
138
- ? props.stickyHeaders === true
139
- ? {}
140
- : props.stickyHeaders
141
- : undefined;
142
-
143
- const { annotationProvider } = props;
144
- const allowAnnotationsDraftMode = Boolean(
145
- annotationProvider &&
146
- annotationProvider.inlineComment &&
147
- annotationProvider.inlineComment.allowDraftMode,
148
- );
149
-
150
- const { featureFlags } = this.featureFlags(props.featureFlags);
151
-
152
- return {
153
- providers: this.providerFactory,
154
- eventHandlers: props.eventHandlers,
155
- extensionHandlers: props.extensionHandlers,
156
- portal: props.portal,
157
- objectContext: {
158
- adDoc: props.document,
159
- schema: props.schema,
160
- ...props.rendererContext,
161
- } as RendererContext,
162
- appearance: props.appearance,
163
- disableHeadingIDs: props.disableHeadingIDs,
164
- disableActions: props.disableActions,
165
- allowHeadingAnchorLinks: props.allowHeadingAnchorLinks,
166
- allowColumnSorting: props.allowColumnSorting,
167
- fireAnalyticsEvent: this.fireAnalyticsEvent,
168
- shouldOpenMediaViewer: props.shouldOpenMediaViewer,
169
- allowAltTextOnImages: props.allowAltTextOnImages,
170
- stickyHeaders,
171
- allowMediaLinking: props.media && props.media.allowLinking,
172
- surroundTextNodesWithTextWrapper: allowAnnotationsDraftMode,
173
- media: props.media,
174
- smartLinks: props.smartLinks,
175
- allowCopyToClipboard: props.allowCopyToClipboard,
176
- allowCustomPanels: props.allowCustomPanels,
177
- allowAnnotations: props.allowAnnotations,
178
- allowSelectAllTrap: props.allowSelectAllTrap,
179
- allowPlaceholderText: props.allowPlaceholderText,
180
- nodeComponents: props.nodeComponents,
181
- // does not currently support SSR, should not be enabled in environments where Renderer is SSR-ed
182
- allowWindowedCodeBlock: featureFlags?.allowWindowedCodeBlock,
183
- };
184
- }
185
-
186
- private featureFlags = memoizeOne(
187
- (featureFlags: RendererProps['featureFlags']) => {
188
- const normalizedFeatureFlags = normalizeFeatureFlags<
189
- NormalizedObjectFeatureFlags
190
- >(featureFlags, {
191
- objectFlagKeys: ['rendererRenderTracking'],
192
- });
193
- return {
194
- featureFlags: normalizedFeatureFlags,
195
- };
196
- },
197
- );
198
-
199
- private fireAnalyticsEvent: FireAnalyticsCallback = (event) => {
200
- const { createAnalyticsEvent } = this.props;
201
-
202
- if (createAnalyticsEvent) {
203
- const channel = FabricChannel.editor;
204
- createAnalyticsEvent(event).fire(channel);
205
- }
206
- };
207
-
208
- private getSchema = memoizeOne(
209
- (schema?: Schema, adfStage?: 'final' | 'stage0') => {
210
- if (schema) {
211
- return schema;
212
- }
213
-
214
- return getSchemaBasedOnStage(adfStage);
215
- },
216
- );
217
-
218
- private handleMouseTripleClickInTables = (event: MouseEvent) => {
219
- if (browser.ios || browser.android) {
220
- return;
221
- }
222
- const badBrowser = browser.chrome || browser.safari;
223
- const tripleClick = event.detail >= 3;
224
- if (!(badBrowser && tripleClick)) {
225
- return;
226
- }
227
- const selection = window.getSelection();
228
- if (!selection) {
229
- return;
230
- }
231
- const { type, anchorNode, focusNode } = selection;
232
- const rangeSelection = Boolean(type === 'Range' && anchorNode && focusNode);
233
- if (!rangeSelection) {
234
- return;
235
- }
236
- const target = event.target as HTMLElement;
237
- const tableCell = target.closest('td,th');
238
- const clickedInCell = Boolean(tableCell);
239
- if (!clickedInCell) {
240
- return;
241
- }
242
- const anchorInCell = tableCell!.contains(anchorNode);
243
- const focusInCell = tableCell!.contains(focusNode);
244
- const selectionStartsOrEndsOutsideClickedCell = !(
245
- anchorInCell && focusInCell
246
- );
247
- if (!selectionStartsOrEndsOutsideClickedCell) {
248
- return;
249
- }
250
- const elementToSelect: Element | null | undefined = anchorInCell
251
- ? anchorNode!.parentElement?.closest('div,p')
252
- : focusInCell
253
- ? focusNode!.parentElement?.closest('div,p')
254
- : tableCell;
255
- if (elementToSelect) {
256
- selection.selectAllChildren(elementToSelect);
257
- }
258
- };
259
-
260
- render() {
261
- const {
262
- document: adfDocument,
263
- onComplete,
264
- onError,
265
- appearance,
266
- adfStage,
267
- truncated,
268
- maxHeight,
269
- fadeOutHeight,
270
- enableSsrInlineScripts,
271
- allowHeadingAnchorLinks,
272
- allowPlaceholderText,
273
- allowColumnSorting,
274
- allowCopyToClipboard,
275
- allowCustomPanels,
276
- } = this.props;
277
-
278
- const allowNestedHeaderLinks = isNestedHeaderLinksEnabled(
279
- allowHeadingAnchorLinks,
280
- );
281
- /**
282
- * Handle clicks inside renderer. If the click isn't on media, in the media picker, or on a
283
- * link, call the onUnhandledClick eventHandler (which in Jira for example, may switch the
284
- * renderer out for the editor).
285
- * @param event Click event anywhere inside renderer
286
- */
287
- const handleWrapperOnClick = (event: React.MouseEvent) => {
288
- const targetElement = event.target as HTMLElement;
289
-
290
- // ED-14862: When a user triple clicks to select a line of content inside a
291
- // a table cell, but the browser incorrectly moves the selection start or end into
292
- // a different table cell, we manually set the selection back to within the original
293
- // table cell the user intended to target
294
- this.handleMouseTripleClickInTables((event as unknown) as MouseEvent);
295
-
296
- if (!this.props.eventHandlers?.onUnhandledClick) {
297
- return;
298
- }
299
- if (!(targetElement instanceof window.Element)) {
300
- return;
301
- }
302
-
303
- const rendererWrapper = event.currentTarget as HTMLElement;
304
-
305
- // Check if the click was on an interactive element
306
- const isInteractiveElementInTree = findInTree(
307
- targetElement,
308
- rendererWrapper,
309
- isInteractiveElement,
310
- );
311
- if (isInteractiveElementInTree) {
312
- return;
313
- }
314
-
315
- const windowSelection = window.getSelection();
316
- const selection: string | undefined =
317
- windowSelection !== null ? windowSelection.toString() : undefined;
318
- const hasSelection = selection && selection.length !== 0;
319
-
320
- const hasSelectionMouseDown =
321
- this.mouseDownSelection && this.mouseDownSelection.length !== 0;
322
- const allowEditBasedOnSelection = !hasSelection && !hasSelectionMouseDown;
323
-
324
- if (allowEditBasedOnSelection) {
325
- this.props.eventHandlers.onUnhandledClick(event);
326
- }
327
- };
328
-
329
- try {
330
- const schema = this.getSchema(this.props.schema, this.props.adfStage);
331
-
332
- const { result, stat, pmDoc } = renderDocument(
333
- adfDocument,
334
- this.serializer,
335
- schema,
336
- adfStage,
337
- this.props.useSpecBasedValidator,
338
- this.id,
339
- this.fireAnalyticsEvent,
340
- this.props.unsupportedContentLevelsTracking,
341
- this.props.appearance,
342
- );
343
-
344
- if (onComplete) {
345
- onComplete(stat);
346
- }
347
-
348
- const rendererOutput = (
349
- <RendererContextProvider
350
- value={this.featureFlags(this.props.featureFlags)}
351
- >
352
- <ActiveHeaderIdProvider
353
- value={getActiveHeadingId(allowHeadingAnchorLinks)}
354
- >
355
- <AnalyticsContext.Provider
356
- value={{
357
- fireAnalyticsEvent: (event: AnalyticsEventPayload) =>
358
- this.fireAnalyticsEvent(event),
359
- }}
360
- >
361
- <SmartCardStorageProvider>
362
- <RendererWrapper
363
- appearance={appearance}
364
- allowNestedHeaderLinks={allowNestedHeaderLinks}
365
- allowColumnSorting={allowColumnSorting}
366
- allowCopyToClipboard={allowCopyToClipboard}
367
- allowCustomPanels={allowCustomPanels}
368
- allowPlaceholderText={allowPlaceholderText}
369
- innerRef={this.editorRef}
370
- onClick={handleWrapperOnClick}
371
- onMouseDown={this.onMouseDownEditView}
372
- >
373
- {enableSsrInlineScripts ? <BreakoutSSRInlineScript /> : null}
374
- <RendererActionsInternalUpdater
375
- doc={pmDoc}
376
- schema={schema}
377
- onAnalyticsEvent={this.fireAnalyticsEvent}
378
- >
379
- {result}
380
- </RendererActionsInternalUpdater>
381
- </RendererWrapper>
382
- </SmartCardStorageProvider>
383
- </AnalyticsContext.Provider>
384
- </ActiveHeaderIdProvider>
385
- </RendererContextProvider>
386
- );
387
-
388
- let rendererResult = truncated ? (
389
- <TruncatedWrapper height={maxHeight} fadeHeight={fadeOutHeight}>
390
- {rendererOutput}
391
- </TruncatedWrapper>
392
- ) : (
393
- rendererOutput
394
- );
395
-
396
- const rendererRenderTracking = this.featureFlags(this.props.featureFlags)
397
- ?.featureFlags?.rendererRenderTracking?.[ACTION_SUBJECT.RENDERER];
398
-
399
- const reRenderTracking = rendererRenderTracking?.enabled && (
400
- <RenderTracking
401
- componentProps={this.props}
402
- action={ACTION.RE_RENDERED}
403
- actionSubject={ACTION_SUBJECT.RENDERER}
404
- handleAnalyticsEvent={this.fireAnalyticsEvent}
405
- useShallow={rendererRenderTracking.useShallow}
406
- />
407
- );
408
-
409
- return (
410
- <Fragment>
411
- {reRenderTracking}
412
- {rendererResult}
413
- </Fragment>
414
- );
415
- } catch (e) {
416
- if (onError) {
417
- onError(e);
418
- }
419
- return (
420
- <RendererWrapper
421
- appearance={appearance}
422
- allowCopyToClipboard={allowCopyToClipboard}
423
- allowPlaceholderText={allowPlaceholderText}
424
- allowColumnSorting={allowColumnSorting}
425
- allowNestedHeaderLinks={allowNestedHeaderLinks}
426
- onClick={handleWrapperOnClick}
427
- >
428
- <UnsupportedBlock />
429
- </RendererWrapper>
430
- );
431
- }
432
- }
433
-
434
- componentWillUnmount() {
435
- const { dataProviders } = this.props;
436
-
437
- if (this.rafID) {
438
- window.cancelAnimationFrame(this.rafID);
439
- }
440
-
441
- // if this is the ProviderFactory which was created in constructor
442
- // it's safe to destroy it on Renderer unmount
443
- if (!dataProviders) {
444
- this.providerFactory.destroy();
445
- }
446
- }
447
- }
448
-
449
- const RendererWithAnalytics = React.memo((props: RendererProps) => (
450
- <FabricEditorAnalyticsContext
451
- data={{
452
- appearance: getAnalyticsAppearance(props.appearance),
453
- packageName,
454
- packageVersion,
455
- componentName: 'renderer',
456
- editorSessionId: uuid(),
457
- }}
458
- >
459
- <WithCreateAnalyticsEvent
460
- render={(createAnalyticsEvent) => {
461
- // 'IntlErrorBoundary' only captures Internationalisation errors, leaving others for 'ErrorBoundary'.
462
- return (
463
- <ErrorBoundary component={ACTION_SUBJECT.RENDERER} rethrowError fallbackComponent={null} createAnalyticsEvent={createAnalyticsEvent} >
464
- <IntlErrorBoundary>
465
- <Renderer
466
- {...props}
467
- createAnalyticsEvent={createAnalyticsEvent}
468
- />
469
- </IntlErrorBoundary>
470
- </ErrorBoundary>
471
- );
472
- }}
473
- />
474
- </FabricEditorAnalyticsContext>
475
- ));
476
-
477
- type RendererWrapperProps = {
478
- appearance: RendererAppearance;
479
- innerRef?: React.RefObject<HTMLDivElement>;
480
- allowColumnSorting?: boolean;
481
- allowCopyToClipboard?: boolean;
482
- allowPlaceholderText?: boolean;
483
- allowCustomPanels?: boolean;
484
- allowNestedHeaderLinks: boolean;
485
- onClick?: (event: React.MouseEvent) => void;
486
- onMouseDown?: (event: React.MouseEvent) => void;
487
- } & { children?: React.ReactNode };
488
-
489
- const RendererWrapper = React.memo((props: RendererWrapperProps) => {
490
- const { allowColumnSorting, allowNestedHeaderLinks, innerRef, appearance, children, onClick, onMouseDown, } = props;
491
-
492
- return (
493
- <WidthProvider className="ak-renderer-wrapper">
494
- <BaseTheme baseFontSize={ appearance && appearance !== 'comment' ? akEditorFullPageDefaultFontSize : undefined } >
495
- <div ref={innerRef} onClick={onClick} onMouseDown={onMouseDown} css={rendererStyles({ appearance, allowNestedHeaderLinks, allowColumnSorting: !!allowColumnSorting, })} >
496
- {children}
497
- </div>
498
- </BaseTheme>
499
- </WidthProvider>
500
- );
501
- });`;