@atlaskit/smart-card 17.2.1 → 17.4.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/cjs/constants.js +16 -1
  3. package/dist/cjs/extractors/flexible/icon/extract-document-type-icon.js +28 -7
  4. package/dist/cjs/extractors/flexible/icon/extract-file-formatIcon.js +88 -22
  5. package/dist/cjs/extractors/flexible/icon/extract-jira-task-icon.js +36 -9
  6. package/dist/cjs/extractors/flexible/icon/extract-jsonld-data-icon.js +33 -9
  7. package/dist/cjs/extractors/flexible/icon/extract-provider-icon.js +20 -3
  8. package/dist/cjs/extractors/flexible/icon/extract-url-icon.js +4 -1
  9. package/dist/cjs/extractors/flexible/icon/index.js +11 -20
  10. package/dist/cjs/extractors/flexible/index.js +5 -0
  11. package/dist/cjs/version.json +1 -1
  12. package/dist/cjs/view/FlexibleCard/components/blocks/metadata-block/index.js +17 -3
  13. package/dist/cjs/view/FlexibleCard/components/blocks/utils.js +27 -7
  14. package/dist/cjs/view/FlexibleCard/components/common/atlaskit-icon/index.js +2 -0
  15. package/dist/cjs/view/FlexibleCard/components/elements/avatar-group/index.js +24 -2
  16. package/dist/cjs/view/FlexibleCard/components/elements/badge/index.js +2 -4
  17. package/dist/cjs/view/FlexibleCard/components/elements/index.js +6 -2
  18. package/dist/cjs/view/FlexibleCard/components/elements/text/index.js +6 -2
  19. package/dist/cjs/view/FlexibleCard/components/elements/utils.js +64 -39
  20. package/dist/es2019/constants.js +15 -1
  21. package/dist/es2019/extractors/flexible/icon/extract-document-type-icon.js +28 -7
  22. package/dist/es2019/extractors/flexible/icon/extract-file-formatIcon.js +88 -22
  23. package/dist/es2019/extractors/flexible/icon/extract-jira-task-icon.js +36 -9
  24. package/dist/es2019/extractors/flexible/icon/extract-jsonld-data-icon.js +33 -9
  25. package/dist/es2019/extractors/flexible/icon/extract-provider-icon.js +19 -3
  26. package/dist/es2019/extractors/flexible/icon/extract-url-icon.js +4 -1
  27. package/dist/es2019/extractors/flexible/icon/index.js +6 -9
  28. package/dist/es2019/extractors/flexible/index.js +5 -1
  29. package/dist/es2019/version.json +1 -1
  30. package/dist/es2019/view/FlexibleCard/components/blocks/metadata-block/index.js +17 -3
  31. package/dist/es2019/view/FlexibleCard/components/blocks/utils.js +38 -6
  32. package/dist/es2019/view/FlexibleCard/components/common/atlaskit-icon/index.js +2 -0
  33. package/dist/es2019/view/FlexibleCard/components/elements/avatar-group/index.js +28 -2
  34. package/dist/es2019/view/FlexibleCard/components/elements/badge/index.js +2 -4
  35. package/dist/es2019/view/FlexibleCard/components/elements/index.js +3 -1
  36. package/dist/es2019/view/FlexibleCard/components/elements/text/index.js +5 -3
  37. package/dist/es2019/view/FlexibleCard/components/elements/utils.js +66 -37
  38. package/dist/esm/constants.js +15 -1
  39. package/dist/esm/extractors/flexible/icon/extract-document-type-icon.js +28 -7
  40. package/dist/esm/extractors/flexible/icon/extract-file-formatIcon.js +88 -22
  41. package/dist/esm/extractors/flexible/icon/extract-jira-task-icon.js +36 -9
  42. package/dist/esm/extractors/flexible/icon/extract-jsonld-data-icon.js +33 -9
  43. package/dist/esm/extractors/flexible/icon/extract-provider-icon.js +19 -3
  44. package/dist/esm/extractors/flexible/icon/extract-url-icon.js +4 -1
  45. package/dist/esm/extractors/flexible/icon/index.js +12 -20
  46. package/dist/esm/extractors/flexible/index.js +5 -1
  47. package/dist/esm/version.json +1 -1
  48. package/dist/esm/view/FlexibleCard/components/blocks/metadata-block/index.js +17 -3
  49. package/dist/esm/view/FlexibleCard/components/blocks/utils.js +25 -7
  50. package/dist/esm/view/FlexibleCard/components/common/atlaskit-icon/index.js +2 -0
  51. package/dist/esm/view/FlexibleCard/components/elements/avatar-group/index.js +24 -2
  52. package/dist/esm/view/FlexibleCard/components/elements/badge/index.js +2 -4
  53. package/dist/esm/view/FlexibleCard/components/elements/index.js +3 -1
  54. package/dist/esm/view/FlexibleCard/components/elements/text/index.js +7 -2
  55. package/dist/esm/view/FlexibleCard/components/elements/utils.js +64 -39
  56. package/dist/types/__fixtures__/flexible-ui-data-context.d.ts +3 -0
  57. package/dist/types/constants.d.ts +3 -1
  58. package/dist/types/extractors/flexible/icon/extract-provider-icon.d.ts +1 -1
  59. package/dist/types/extractors/flexible/icon/index.d.ts +3 -3
  60. package/dist/types/extractors/flexible/icon/types.d.ts +5 -1
  61. package/dist/types/state/flexible-ui-context/types.d.ts +4 -2
  62. package/dist/types/view/FlexibleCard/components/blocks/utils.d.ts +4 -2
  63. package/dist/types/view/FlexibleCard/components/elements/avatar-group/index.d.ts +1 -0
  64. package/dist/types/view/FlexibleCard/components/elements/avatar-group/types.d.ts +1 -2
  65. package/dist/types/view/FlexibleCard/components/elements/index.d.ts +2 -0
  66. package/dist/types/view/FlexibleCard/components/elements/text/types.d.ts +1 -0
  67. package/package.json +1 -1
@@ -3,32 +3,59 @@ import { IconType } from '../../../constants';
3
3
  const extractJiraTaskIcon = (taskType, label = 'Task') => {
4
4
  switch (taskType) {
5
5
  case 'JiraBug':
6
- return [IconType.Bug, label];
6
+ return {
7
+ icon: IconType.Bug,
8
+ label
9
+ };
7
10
 
8
11
  case 'JiraChange':
9
- return [IconType.Change, label];
12
+ return {
13
+ icon: IconType.Change,
14
+ label
15
+ };
10
16
 
11
17
  case 'JiraEpic':
12
- return [IconType.Epic, label];
18
+ return {
19
+ icon: IconType.Epic,
20
+ label
21
+ };
13
22
 
14
23
  case 'JiraIncident':
15
- return [IconType.Incident, label];
24
+ return {
25
+ icon: IconType.Incident,
26
+ label
27
+ };
16
28
 
17
29
  case 'JiraProblem':
18
- return [IconType.Problem, label];
30
+ return {
31
+ icon: IconType.Problem,
32
+ label
33
+ };
19
34
 
20
35
  case 'JiraServiceRequest':
21
- return [IconType.ServiceRequest, label];
36
+ return {
37
+ icon: IconType.ServiceRequest,
38
+ label
39
+ };
22
40
 
23
41
  case 'JiraStory':
24
- return [IconType.Story, label];
42
+ return {
43
+ icon: IconType.Story,
44
+ label
45
+ };
25
46
 
26
47
  case 'JiraSubTask':
27
- return [IconType.SubTask, label];
48
+ return {
49
+ icon: IconType.SubTask,
50
+ label
51
+ };
28
52
 
29
53
  case 'JiraTask':
30
54
  default:
31
- return [IconType.Task, label];
55
+ return {
56
+ icon: IconType.Task,
57
+ label
58
+ };
32
59
  }
33
60
  };
34
61
 
@@ -15,7 +15,10 @@ const extractTask = (data, label) => {
15
15
  icon: url
16
16
  } = extractTaskType(data) || {};
17
17
  const taskType = id === null || id === void 0 ? void 0 : id.split('#').pop();
18
- const taskIcon = url ? [undefined, label, url] : undefined;
18
+ const taskIcon = url ? {
19
+ label,
20
+ url
21
+ } : undefined;
19
22
  return {
20
23
  taskType,
21
24
  taskIcon
@@ -39,7 +42,7 @@ const extractJsonldDataIcon = data => {
39
42
  const type = extractType(data);
40
43
  const urlIcon = extractUrlIcon(data.icon, label);
41
44
  const provider = generator === null || generator === void 0 ? void 0 : generator['@id'];
42
- const providerIcon = extractProviderIcon(provider, generator === null || generator === void 0 ? void 0 : generator.icon, label);
45
+ const providerIcon = extractProviderIcon(data);
43
46
 
44
47
  switch (type) {
45
48
  case 'Document':
@@ -68,25 +71,46 @@ const extractJsonldDataIcon = data => {
68
71
  taskType,
69
72
  taskIcon
70
73
  } = extractTask(data);
71
- return taskType === 'JiraCustomTaskType' ? taskIcon || urlIcon || providerIcon || [IconType.Task, taskLabel] : extractJiraTaskIcon(taskType, taskLabel);
74
+ return taskType === 'JiraCustomTaskType' ? taskIcon || urlIcon || providerIcon || {
75
+ icon: IconType.Task,
76
+ label: taskLabel
77
+ } : extractJiraTaskIcon(taskType, taskLabel);
72
78
  }
73
79
 
74
- return [IconType.Task, taskLabel];
80
+ return {
81
+ icon: IconType.Task,
82
+ label: taskLabel
83
+ };
75
84
 
76
85
  case 'atlassian:Project':
77
- return urlIcon || [IconType.Project, label || 'Project'];
86
+ return urlIcon || {
87
+ icon: IconType.Project,
88
+ label: label || 'Project'
89
+ };
78
90
 
79
91
  case 'atlassian:SourceCodeCommit':
80
- return [IconType.Commit, label || 'Commit'];
92
+ return {
93
+ icon: IconType.Commit,
94
+ label: label || 'Commit'
95
+ };
81
96
 
82
97
  case 'atlassian:SourceCodePullRequest':
83
- return [IconType.PullRequest, label || 'Pull request'];
98
+ return {
99
+ icon: IconType.PullRequest,
100
+ label: label || 'Pull request'
101
+ };
84
102
 
85
103
  case 'atlassian:SourceCodeReference':
86
- return [IconType.Branch, label || 'Reference'];
104
+ return {
105
+ icon: IconType.Branch,
106
+ label: label || 'Reference'
107
+ };
87
108
 
88
109
  case 'atlassian:SourceCodeRepository':
89
- return [IconType.Repo, label || 'Repository'];
110
+ return {
111
+ icon: IconType.Repo,
112
+ label: label || 'Repository'
113
+ };
90
114
 
91
115
  default:
92
116
  return providerIcon;
@@ -1,14 +1,30 @@
1
1
  import { CONFLUENCE_GENERATOR_ID, JIRA_GENERATOR_ID } from '../../constants';
2
2
  import { IconType } from '../../../constants';
3
3
  import extractUrlIcon from './extract-url-icon';
4
+ import { extractTitle } from '../../common/primitives';
5
+
6
+ const extractProviderIcon = data => {
7
+ if (!data) {
8
+ return undefined;
9
+ }
10
+
11
+ const generator = data.generator;
12
+ const provider = generator === null || generator === void 0 ? void 0 : generator['@id'];
13
+ const icon = generator === null || generator === void 0 ? void 0 : generator.icon;
14
+ const label = (generator === null || generator === void 0 ? void 0 : generator.name) || extractTitle(data);
4
15
 
5
- const extractProviderIcon = (provider, icon, label) => {
6
16
  if (provider === CONFLUENCE_GENERATOR_ID) {
7
- return [IconType.Confluence, label || 'Confluence'];
17
+ return {
18
+ icon: IconType.Confluence,
19
+ label: label || 'Confluence'
20
+ };
8
21
  }
9
22
 
10
23
  if (provider === JIRA_GENERATOR_ID) {
11
- return [IconType.Jira, label || 'Jira'];
24
+ return {
25
+ icon: IconType.Jira,
26
+ label: label || 'Jira'
27
+ };
12
28
  }
13
29
 
14
30
  return extractUrlIcon(icon, label);
@@ -2,7 +2,10 @@ import { extractUrlFromIconJsonLd } from '../../common/utils';
2
2
 
3
3
  const extractUrlIcon = (icon, label) => {
4
4
  const url = icon && extractUrlFromIconJsonLd(icon);
5
- return url ? [undefined, label, url] : undefined;
5
+ return url ? {
6
+ label,
7
+ url
8
+ } : undefined;
6
9
  };
7
10
 
8
11
  export default extractUrlIcon;
@@ -4,22 +4,19 @@ import { IconType, SmartLinkStatus } from '../../../constants';
4
4
  import extractIconRenderer from './extract-icon-renderer';
5
5
  export const extractLinkIcon = (response, renderers) => {
6
6
  const data = response.data;
7
- const [icon, label, url] = extractJsonldDataIcon(data) || [];
8
7
  const render = extractIconRenderer(data, renderers);
9
- return {
10
- icon,
11
- label,
12
- render,
13
- url
8
+ return { ...extractJsonldDataIcon(data),
9
+ render
14
10
  };
15
11
  };
16
12
  export const extractErrorIcon = (response, status) => {
17
13
  // Try to get provider icon first.
18
14
  if (response) {
19
15
  const data = response.data;
20
- const generator = data.generator;
21
- const provider = generator === null || generator === void 0 ? void 0 : generator['@id'];
22
- const [icon,, url] = extractProviderIcon(provider, generator === null || generator === void 0 ? void 0 : generator.icon) || [];
16
+ const {
17
+ icon,
18
+ url
19
+ } = extractProviderIcon(data) || {};
23
20
 
24
21
  if (icon || url) {
25
22
  return {
@@ -1,4 +1,4 @@
1
- import { extractLink, extractTitle } from '../common/primitives';
1
+ import { extractLink, extractSummary, extractTitle } from '../common/primitives';
2
2
  import { extractLozenge } from '../common/lozenge';
3
3
  import { extractLinkIcon } from './icon';
4
4
  import { extractCommentCount, extractCreatedBy, extractModifiedBy, extractProgrammingLanguage, extractSubscriberCount } from './utils';
@@ -7,6 +7,7 @@ import { extractPersonsUpdatedBy } from './collaboratorGroup';
7
7
  import { extractDateUpdated } from '../common/date/extractDateUpdated';
8
8
  import { extractDateCreated } from '../common/date/extractDateCreated';
9
9
  import extractPriority from './extract-priority';
10
+ import extractProviderIcon from './icon/extract-provider-icon';
10
11
 
11
12
  const extractFlexibleUiContext = (response, renderers) => {
12
13
  if (!response) {
@@ -26,9 +27,12 @@ const extractFlexibleUiContext = (response, renderers) => {
26
27
  modifiedOn: extractDateUpdated(data),
27
28
  priority: extractPriority(data),
28
29
  programmingLanguage: extractProgrammingLanguage(data),
30
+ snippet: extractSummary(data) || undefined,
31
+ // Explicitly set here to remove an empty string
29
32
  state: extractLozenge(data),
30
33
  subscriberCount: extractSubscriberCount(data),
31
34
  title: extractTitle(data) || url,
35
+ provider: extractProviderIcon(data),
32
36
  url
33
37
  };
34
38
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/smart-card",
3
- "version": "17.2.1",
3
+ "version": "17.4.0",
4
4
  "sideEffects": false
5
5
  }
@@ -13,12 +13,11 @@ const getElementGroupStyles = (size, maxLines) => {
13
13
  // MetadataBlock allows metadata elements to be displayed in
14
14
  // multiple lines, with maximum of 2 lines.
15
15
  // a) We need the height of the line to be equal on both left and right
16
- // sides so they line up nicely. 1.75 is the The maximum height of
17
- // all elements in specific size. This height belongs to AvatarGroup.
16
+ // sides so they line up nicely.
18
17
  // b) There is no way to truncate non-text elements nicely. Here
19
18
  // it's fix max height of the element group so that anything that is
20
19
  // overflown will not be visible.
21
- const lineHeight = 1.75;
20
+ const lineHeight = getLineHeight(size);
22
21
  const gap = getGapSize(size);
23
22
  const gapHeight = gap * (maxLines - 1);
24
23
  const height = lineHeight * maxLines + gapHeight;
@@ -35,6 +34,21 @@ const getElementGroupStyles = (size, maxLines) => {
35
34
  `;
36
35
  };
37
36
 
37
+ const getLineHeight = size => {
38
+ // The maximum height of all elements in specific size.
39
+ // These heights belongs to AvatarGroup.
40
+ switch (size) {
41
+ case SmartLinkSize.XLarge:
42
+ case SmartLinkSize.Large:
43
+ return 1.75;
44
+
45
+ case SmartLinkSize.Medium:
46
+ case SmartLinkSize.Small:
47
+ default:
48
+ return 1.5;
49
+ }
50
+ };
51
+
38
52
  const getMaxLines = maxLines => {
39
53
  if (maxLines > MAXIMUM_MAX_LINES) {
40
54
  return DEFAULT_MAX_LINES;
@@ -1,12 +1,30 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import React from 'react';
3
3
  import { css } from '@emotion/core';
4
- import { SmartLinkDirection, SmartLinkSize } from '../../../../constants';
4
+ import { ElementName, SmartLinkDirection, SmartLinkSize } from '../../../../constants';
5
5
  import * as Elements from '../elements';
6
6
  import * as Actions from '../actions';
7
7
  import { isFlexibleUiElement } from '../../../../utils/flexible';
8
8
  import ActionGroup from './action-group';
9
- import ElementGroup from './element-group';
9
+ import ElementGroup from './element-group'; // Determine whether the element can be display as inline/block.
10
+
11
+ export const ElementDisplaySchema = {
12
+ [ElementName.AuthorGroup]: ['inline'],
13
+ [ElementName.CollaboratorGroup]: ['inline'],
14
+ [ElementName.CommentCount]: ['inline'],
15
+ [ElementName.CreatedBy]: ['inline'],
16
+ [ElementName.CreatedOn]: ['inline'],
17
+ [ElementName.LinkIcon]: ['inline'],
18
+ [ElementName.ModifiedBy]: ['inline'],
19
+ [ElementName.ModifiedOn]: ['inline'],
20
+ [ElementName.Priority]: ['inline'],
21
+ [ElementName.ProgrammingLanguage]: ['inline'],
22
+ [ElementName.Snippet]: ['block'],
23
+ [ElementName.State]: ['inline'],
24
+ [ElementName.SubscriberCount]: ['inline'],
25
+ [ElementName.Title]: ['inline'],
26
+ [ElementName.Provider]: ['inline']
27
+ };
10
28
 
11
29
  const getDirectionStyles = direction => {
12
30
  switch (direction) {
@@ -62,6 +80,16 @@ export const getBaseStyles = (direction, size) => css`
62
80
 
63
81
  const isActionGroup = node => /*#__PURE__*/React.isValidElement(node) && node.type === ActionGroup;
64
82
 
83
+ const isElementDisplayValid = (name, display) => {
84
+ var _ElementDisplaySchema, _ElementDisplaySchema2;
85
+
86
+ return (_ElementDisplaySchema = (_ElementDisplaySchema2 = ElementDisplaySchema[name]) === null || _ElementDisplaySchema2 === void 0 ? void 0 : _ElementDisplaySchema2.includes(display)) !== null && _ElementDisplaySchema !== void 0 ? _ElementDisplaySchema : false;
87
+ };
88
+
89
+ const isElementNull = children => {
90
+ return Boolean(children.type() === null);
91
+ };
92
+
65
93
  const isElementOrElementGroup = node => /*#__PURE__*/React.isValidElement(node) && (isFlexibleUiElement(node) || node.type === ElementGroup);
66
94
 
67
95
  export const renderChildren = (children, size) => React.Children.map(children, child => {
@@ -77,7 +105,7 @@ export const renderChildren = (children, size) => React.Children.map(children, c
77
105
 
78
106
  return child;
79
107
  });
80
- export const renderElementItems = (items = []) => {
108
+ export const renderElementItems = (items = [], display = 'inline') => {
81
109
  const elements = items.reduce((acc, curr, idx) => {
82
110
  const {
83
111
  name,
@@ -85,10 +113,14 @@ export const renderElementItems = (items = []) => {
85
113
  } = curr;
86
114
  const Element = Elements[name];
87
115
 
88
- if (Element) {
89
- return [...acc, /*#__PURE__*/React.createElement(Element, _extends({
116
+ if (Element && isElementDisplayValid(name, display)) {
117
+ const element = /*#__PURE__*/React.createElement(Element, _extends({
90
118
  key: idx
91
- }, props))];
119
+ }, props));
120
+
121
+ if (!isElementNull(element)) {
122
+ return [...acc, element];
123
+ }
92
124
  }
93
125
 
94
126
  return acc;
@@ -217,6 +217,8 @@ const AtlaskitIcon = ({
217
217
  case IconType.Jira:
218
218
  // Logo component has a different prop set from other icon components
219
219
  return /*#__PURE__*/React.createElement(ImportedIcon, {
220
+ "data-testId": testId // Confluence and Jira imports don't have native testId prop
221
+ ,
220
222
  textColor: N700,
221
223
  iconColor: B200,
222
224
  iconGradientStart: B400,
@@ -1,8 +1,32 @@
1
+ /** @jsx jsx */
1
2
  import React from 'react';
3
+ import { css, jsx } from '@emotion/core';
2
4
  import AtlaskitAvatarGroup from '@atlaskit/avatar-group';
3
5
  import { SmartLinkSize } from '../../../../../constants';
4
6
  const MAX_COUNT = 4;
5
7
 
8
+ const getStyles = size => {
9
+ switch (size) {
10
+ case SmartLinkSize.XLarge:
11
+ case SmartLinkSize.Large:
12
+ // Default AK small size
13
+ return;
14
+
15
+ case SmartLinkSize.Medium:
16
+ case SmartLinkSize.Small:
17
+ default:
18
+ return css`
19
+ li {
20
+ span,
21
+ svg {
22
+ max-height: 1.25rem;
23
+ max-width: 1.25rem;
24
+ }
25
+ }
26
+ `;
27
+ }
28
+ };
29
+
6
30
  const AvatarGroup = ({
7
31
  items = [],
8
32
  maxCount = MAX_COUNT,
@@ -13,13 +37,15 @@ const AvatarGroup = ({
13
37
  return null;
14
38
  }
15
39
 
16
- return /*#__PURE__*/React.createElement(AtlaskitAvatarGroup, {
40
+ return jsx("span", {
41
+ css: getStyles(size)
42
+ }, jsx(AtlaskitAvatarGroup, {
17
43
  maxCount: maxCount,
18
44
  appearance: "stack",
19
45
  size: "small",
20
46
  data: items,
21
47
  testId: testId
22
- });
48
+ }));
23
49
  };
24
50
 
25
51
  export default AvatarGroup;
@@ -40,7 +40,7 @@ const messageMapper = {
40
40
  [IconType.PriorityUndefined]: messages.priority_undefined
41
41
  };
42
42
 
43
- const getFormattedMessageOrLabel = (icon, content) => {
43
+ const getFormattedMessageFromIcon = icon => {
44
44
  if (icon) {
45
45
  const descriptor = messageMapper[icon];
46
46
 
@@ -50,8 +50,6 @@ const getFormattedMessageOrLabel = (icon, content) => {
50
50
  });
51
51
  }
52
52
  }
53
-
54
- return content;
55
53
  };
56
54
 
57
55
  const renderAtlaskitIcon = (icon, testId) => {
@@ -79,7 +77,7 @@ const Badge = ({
79
77
  label,
80
78
  testId = 'smart-element-badge'
81
79
  }) => {
82
- const formattedMessageOrLabel = getFormattedMessageOrLabel(icon, label);
80
+ const formattedMessageOrLabel = getFormattedMessageFromIcon(icon) || label;
83
81
  const badgeIcon = renderAtlaskitIcon(icon, testId) || renderImageIcon(url, testId);
84
82
 
85
83
  if (!formattedMessageOrLabel || !badgeIcon) {
@@ -13,6 +13,8 @@ export const ModifiedBy = createElement(ElementName.ModifiedBy);
13
13
  export const ModifiedOn = createElement(ElementName.ModifiedOn);
14
14
  export const Priority = createElement(ElementName.Priority);
15
15
  export const ProgrammingLanguage = createElement(ElementName.ProgrammingLanguage);
16
+ export const Snippet = createElement(ElementName.Snippet);
16
17
  export const State = createElement(ElementName.State);
17
18
  export const SubscriberCount = createElement(ElementName.SubscriberCount);
18
- export const Title = createElement(ElementName.Title);
19
+ export const Title = createElement(ElementName.Title);
20
+ export const Provider = createElement(ElementName.Provider);
@@ -3,15 +3,17 @@ import React from 'react';
3
3
  import { css, jsx } from '@emotion/core';
4
4
  import { getFormattedMessage, getTruncateStyles } from '../../utils';
5
5
  import { tokens } from '../../../../../utils/token';
6
- const styles = css`
6
+
7
+ const getStyles = maxLines => css`
7
8
  color: ${tokens.text};
8
9
  font-size: 0.75rem;
9
10
  line-height: 1rem;
10
- ${getTruncateStyles(1)}
11
+ ${getTruncateStyles(maxLines)}
11
12
  `;
12
13
 
13
14
  const Text = ({
14
15
  content,
16
+ maxLines = 1,
15
17
  message,
16
18
  testId = 'smart-element-text'
17
19
  }) => {
@@ -20,7 +22,7 @@ const Text = ({
20
22
  }
21
23
 
22
24
  return jsx("span", {
23
- css: styles,
25
+ css: getStyles(maxLines),
24
26
  "data-smart-element-text": true,
25
27
  "data-testid": testId
26
28
  }, getFormattedMessage(message) || content);
@@ -41,6 +41,12 @@ const elementMappings = {
41
41
  icon: IconType.ProgrammingLanguage
42
42
  }
43
43
  },
44
+ [ElementName.Snippet]: {
45
+ component: Text,
46
+ props: {
47
+ maxLines: 3
48
+ }
49
+ },
44
50
  [ElementName.State]: {
45
51
  component: Lozenge
46
52
  },
@@ -58,6 +64,9 @@ const elementMappings = {
58
64
  },
59
65
  [ElementName.ModifiedOn]: {
60
66
  component: DateTime
67
+ },
68
+ [ElementName.Provider]: {
69
+ component: Badge
61
70
  }
62
71
  };
63
72
 
@@ -67,15 +76,6 @@ const getContextKey = name => {
67
76
  return name.length > 0 ? name.charAt(0).toLowerCase() + name.slice(1) : undefined;
68
77
  };
69
78
 
70
- const getFormattedMessage = (descriptor, value) => value ? {
71
- message: {
72
- descriptor,
73
- values: {
74
- context: value
75
- }
76
- }
77
- } : undefined;
78
-
79
79
  const getData = (elementName, contextKey, context) => {
80
80
  if (!context) {
81
81
  return undefined;
@@ -84,52 +84,81 @@ const getData = (elementName, contextKey, context) => {
84
84
  const data = context[contextKey];
85
85
 
86
86
  switch (elementName) {
87
+ case ElementName.AuthorGroup:
88
+ case ElementName.CollaboratorGroup:
89
+ return toAvatarGroupProps(data);
90
+
87
91
  case ElementName.CommentCount:
88
92
  case ElementName.ProgrammingLanguage:
89
93
  case ElementName.SubscriberCount:
90
- return {
91
- label: data
92
- };
93
-
94
- case ElementName.AuthorGroup:
95
- return {
96
- items: context.authorGroup
97
- };
98
-
99
- case ElementName.CollaboratorGroup:
100
- return {
101
- items: context.collaboratorGroup
102
- };
94
+ return toBadgeProps(data);
103
95
 
104
96
  case ElementName.CreatedBy:
105
- return getFormattedMessage(messages.created_by, context.createdBy);
97
+ return toFormattedTextProps(messages.created_by, context.createdBy);
98
+
99
+ case ElementName.CreatedOn:
100
+ return toDateTimeProps('created', context.createdOn);
106
101
 
107
102
  case ElementName.ModifiedBy:
108
- return getFormattedMessage(messages.modified_by, context.modifiedBy);
103
+ return toFormattedTextProps(messages.modified_by, context.modifiedBy);
109
104
 
110
105
  case ElementName.ModifiedOn:
111
- return context.modifiedOn ? {
112
- date: new Date(context.modifiedOn),
113
- type: 'modified'
114
- } : undefined;
106
+ return toDateTimeProps('modified', context.modifiedOn);
115
107
 
116
- case ElementName.CreatedOn:
117
- return context.createdOn ? {
118
- date: new Date(context.createdOn),
119
- type: 'created'
120
- } : undefined;
108
+ case ElementName.Snippet:
109
+ return toTextProps(data);
121
110
 
122
111
  case ElementName.Title:
123
- return {
124
- text: context.title,
125
- url: context.url
126
- };
112
+ return toLinkProps(context.title, context.url);
127
113
 
128
114
  default:
129
115
  return data;
130
116
  }
131
117
  };
132
118
 
119
+ const toAvatarGroupProps = items => {
120
+ return items ? {
121
+ items
122
+ } : undefined;
123
+ };
124
+
125
+ const toBadgeProps = label => {
126
+ return label ? {
127
+ label
128
+ } : undefined;
129
+ };
130
+
131
+ const toDateTimeProps = (type, dateString) => {
132
+ return dateString ? {
133
+ date: new Date(dateString),
134
+ type
135
+ } : undefined;
136
+ };
137
+
138
+ const toFormattedTextProps = (descriptor, context) => {
139
+ return context ? {
140
+ message: {
141
+ descriptor,
142
+ values: {
143
+ context
144
+ }
145
+ }
146
+ } : undefined;
147
+ };
148
+
149
+ const toLinkProps = (text, url) => {
150
+ return text ? {
151
+ text,
152
+ url
153
+ } : undefined;
154
+ };
155
+
156
+ const toTextProps = content => {
157
+ return content ? {
158
+ content
159
+ } : undefined;
160
+ };
161
+
133
162
  export const createElement = name => {
134
163
  const {
135
164
  component: BaseElement,
@@ -48,7 +48,19 @@ export var SmartLinkTheme;
48
48
  SmartLinkTheme["Link"] = "link";
49
49
  })(SmartLinkTheme || (SmartLinkTheme = {}));
50
50
 
51
- export var SmartLinkWidth;
51
+ export var SmartLinkWidth; // When adding an element...
52
+ // 1) Create base element if it doesn't already existed.
53
+ // Base element are inside src/view/FlexibleCard/components/elements.
54
+ // E.g. Badge,DateTime, Icon, Lozenge, etc.
55
+ // 2) Update FlexibleUiContext with the new prop for data representing
56
+ // the element, preferably with the same name as the element itself.
57
+ // (src/state/flexible-ui-context/types.ts)
58
+ // 3) Update Flexible UI extractor (src/extractors/flexible/index.ts)
59
+ // 4) Set base element and data mapping.
60
+ // (src/view/FlexibleCard/components/elements/utils.tsx)
61
+ // 5) Create element. (src/view/FlexibleCard/components/elements/index.ts)
62
+ // 6) Update element ElementDisplaySchema for inline/block display
63
+ // (src/view/FlexibleCard/components/blocks/utils.tsx)
52
64
 
53
65
  (function (SmartLinkWidth) {
54
66
  SmartLinkWidth["FitToContent"] = "fit-to-content";
@@ -68,9 +80,11 @@ export var ElementName;
68
80
  ElementName["ModifiedOn"] = "ModifiedOn";
69
81
  ElementName["Priority"] = "Priority";
70
82
  ElementName["ProgrammingLanguage"] = "ProgrammingLanguage";
83
+ ElementName["Snippet"] = "Snippet";
71
84
  ElementName["State"] = "State";
72
85
  ElementName["SubscriberCount"] = "SubscriberCount";
73
86
  ElementName["Title"] = "Title";
87
+ ElementName["Provider"] = "Provider";
74
88
  })(ElementName || (ElementName = {}));
75
89
 
76
90
  export var ActionName;