@bundle-stats/ui 4.16.0-beta.1 → 4.16.0-beta.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 (70) hide show
  1. package/lib/components/bundle-assets/bundle-assets.js +1 -1
  2. package/lib/components/bundle-assets/bundle-assets.js.map +1 -1
  3. package/lib/components/insights/insights.module.css +1 -0
  4. package/lib/components/metrics-table-export/metrics-table-export.js +3 -7
  5. package/lib/components/metrics-table-export/metrics-table-export.js.map +1 -1
  6. package/lib/components/preview-source/preview-source.js +8 -5
  7. package/lib/components/preview-source/preview-source.js.map +1 -1
  8. package/lib/components/preview-source/preview-source.module.css +12 -0
  9. package/lib/css/variables.css +4 -0
  10. package/lib/ui/dialog/dialog.module.css +3 -3
  11. package/lib/ui/index.js +3 -1
  12. package/lib/ui/index.js.map +1 -1
  13. package/lib/ui/markdown/index.js +18 -0
  14. package/lib/ui/markdown/index.js.map +1 -0
  15. package/lib/ui/markdown/markdown.js +40 -0
  16. package/lib/ui/markdown/markdown.js.map +1 -0
  17. package/lib/ui/markdown/markdown.module.css +7 -0
  18. package/lib/ui/skeleton/skeleton.module.css +3 -3
  19. package/lib/ui/tabs/tabs.module.css +1 -0
  20. package/lib/ui/textarea/textarea.js +2 -2
  21. package/lib/ui/textarea/textarea.js.map +1 -1
  22. package/lib/ui/textarea/textarea.module.css +0 -7
  23. package/lib-esm/components/bundle-assets/bundle-assets.js +1 -1
  24. package/lib-esm/components/bundle-assets/bundle-assets.js.map +1 -1
  25. package/lib-esm/components/insights/insights.module.css +1 -0
  26. package/lib-esm/components/metrics-table-export/metrics-table-export.js +3 -4
  27. package/lib-esm/components/metrics-table-export/metrics-table-export.js.map +1 -1
  28. package/lib-esm/components/preview-source/preview-source.js +8 -5
  29. package/lib-esm/components/preview-source/preview-source.js.map +1 -1
  30. package/lib-esm/components/preview-source/preview-source.module.css +12 -0
  31. package/lib-esm/css/variables.css +4 -0
  32. package/lib-esm/ui/dialog/dialog.module.css +3 -3
  33. package/lib-esm/ui/index.js +1 -0
  34. package/lib-esm/ui/index.js.map +1 -1
  35. package/lib-esm/ui/markdown/index.js +2 -0
  36. package/lib-esm/ui/markdown/index.js.map +1 -0
  37. package/lib-esm/ui/markdown/markdown.js +10 -0
  38. package/lib-esm/ui/markdown/markdown.js.map +1 -0
  39. package/lib-esm/ui/markdown/markdown.module.css +7 -0
  40. package/lib-esm/ui/skeleton/skeleton.module.css +3 -3
  41. package/lib-esm/ui/tabs/tabs.module.css +1 -0
  42. package/lib-esm/ui/textarea/textarea.js +2 -2
  43. package/lib-esm/ui/textarea/textarea.js.map +1 -1
  44. package/lib-esm/ui/textarea/textarea.module.css +0 -7
  45. package/package.json +10 -9
  46. package/src/components/bundle-assets/bundle-assets.jsx +6 -6
  47. package/src/components/insights/insights.module.css +1 -0
  48. package/src/components/metrics-table-export/metrics-table-export.tsx +4 -5
  49. package/src/components/preview-source/preview-source.module.css +12 -0
  50. package/src/components/preview-source/preview-source.stories.tsx +19 -1
  51. package/src/components/preview-source/preview-source.tsx +30 -21
  52. package/src/css/variables.css +4 -0
  53. package/src/ui/dialog/dialog.module.css +3 -3
  54. package/src/ui/index.js +1 -0
  55. package/src/ui/markdown/index.ts +1 -0
  56. package/src/ui/markdown/markdown.module.css +7 -0
  57. package/src/ui/markdown/markdown.stories.tsx +29 -0
  58. package/src/ui/markdown/markdown.tsx +24 -0
  59. package/src/ui/skeleton/skeleton.module.css +3 -3
  60. package/src/ui/tabs/tabs.module.css +1 -0
  61. package/src/ui/textarea/textarea.module.css +0 -7
  62. package/src/ui/textarea/textarea.tsx +2 -8
  63. package/types/components/preview-source/preview-source.d.ts +2 -1
  64. package/types/ui/index.d.ts +1 -0
  65. package/types/ui/markdown/index.d.ts +1 -0
  66. package/types/ui/markdown/markdown.d.ts +7 -0
  67. package/types/ui/textarea/textarea.d.ts +0 -1
  68. package/lib/components/metrics-table-export/metrics-table-export.module.css +0 -8
  69. package/lib-esm/components/metrics-table-export/metrics-table-export.module.css +0 -8
  70. package/src/components/metrics-table-export/metrics-table-export.module.css +0 -8
@@ -13,6 +13,7 @@ export { Icon } from './icon';
13
13
  export { Input } from './input';
14
14
  export { InputSearch } from './input-search';
15
15
  export { Loader } from './loader';
16
+ export { Markdown } from './markdown';
16
17
  export { Skeleton } from './skeleton';
17
18
  export { Table } from './table';
18
19
  export { Tabs } from './tabs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.js"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './markdown';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/markdown/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ import React, { useMemo } from 'react';
2
+ import cx from 'classnames';
3
+ import snarkdown from 'snarkdown';
4
+ import css from './markdown.module.css';
5
+ export const Markdown = (props) => {
6
+ const { className = '', content = '', as: Component = 'div', ...restProps } = props;
7
+ const html = useMemo(() => snarkdown(content), [content]);
8
+ return (React.createElement(Component, { className: cx(css.root, className), ...restProps, dangerouslySetInnerHTML: { __html: html } }));
9
+ };
10
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/ui/markdown/markdown.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA+B,OAAO,EAAE,MAAM,OAAO,CAAC;AACpE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,OAAO,GAAG,MAAM,uBAAuB,CAAC;AAOxC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,EAAE;IAC/C,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAC;IAEpF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAE1D,OAAO,CACL,oBAAC,SAAS,IACR,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,KAC9B,SAAS,EACb,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GACzC,CACH,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ .root code {
2
+ padding: 2px var(--space-xxxsmall);
3
+ background: var(--color-highlight);
4
+ outline: 1px solid var(--color-outline);
5
+ border-radius: var(--radius-small);
6
+ color: var(--color-text);
7
+ }
@@ -1,6 +1,6 @@
1
1
  .root {
2
- background: linear-gradient(transparent 10%, currentColor 10.1%, currentColor 89.9%, transparent 90%);
3
- opacity: 0.05;
2
+ background: var(--skeleton-inline-background);
3
+ opacity: var(--skeleton-opacity);
4
4
  pointer-events: none;
5
5
  min-width: 6em;
6
6
  border-radius: var(--radius-medium);
@@ -14,5 +14,5 @@
14
14
  }
15
15
 
16
16
  .block {
17
- background: currentColor;
17
+ background: var(--skeleton-block-background);
18
18
  }
@@ -10,6 +10,7 @@
10
10
  color: var(--color-text-ultra-light);
11
11
  font-weight: bold;
12
12
  text-decoration: none;
13
+ cursor: default;
13
14
  }
14
15
 
15
16
  .item::after {
@@ -2,8 +2,8 @@ import React from 'react';
2
2
  import cx from 'classnames';
3
3
  import css from './textarea.module.css';
4
4
  export const Textarea = (props) => {
5
- const { className = '', previewSource = false, size = '', ...restProps } = props;
6
- const rootClassName = cx(css.root, previewSource && css.previewSource, size && css[size], className);
5
+ const { className = '', size = '', ...restProps } = props;
6
+ const rootClassName = cx(css.root, size && css[size], className);
7
7
  return React.createElement("textarea", { className: rootClassName, ...restProps });
8
8
  };
9
9
  //# sourceMappingURL=textarea.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../../src/ui/textarea/textarea.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,GAAG,MAAM,uBAAuB,CAAC;AAOxC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,EAAE;IAC/C,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,aAAa,GAAG,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAC;IAEjF,MAAM,aAAa,GAAG,EAAE,CACtB,GAAG,CAAC,IAAI,EACR,aAAa,IAAI,GAAG,CAAC,aAAa,EAClC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,EACjB,SAAS,CACV,CAAC;IAEF,OAAO,kCAAU,SAAS,EAAE,aAAa,KAAM,SAAS,GAAI,CAAC;AAC/D,CAAC,CAAC"}
1
+ {"version":3,"file":"textarea.js","sourceRoot":"","sources":["../../../src/ui/textarea/textarea.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,GAAG,MAAM,uBAAuB,CAAC;AAMxC,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAoB,EAAE,EAAE;IAC/C,MAAM,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,SAAS,EAAE,GAAG,KAAK,CAAC;IAE1D,MAAM,aAAa,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;IAEjE,OAAO,kCAAU,SAAS,EAAE,aAAa,KAAM,SAAS,GAAI,CAAC;AAC/D,CAAC,CAAC"}
@@ -36,13 +36,6 @@
36
36
  color: var(--color-text-light);
37
37
  }
38
38
 
39
- /**
40
- * Source variation
41
- */
42
- .previewSource {
43
- font-family: var(--font-family-fixed);
44
- }
45
-
46
39
  /** Size modifier */
47
40
  /* default - medium */
48
41
  .root {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bundle-stats/ui",
3
- "version": "4.16.0-beta.1",
3
+ "version": "4.16.0-beta.10",
4
4
  "description": "UI components for BundleStats projects.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib-esm/index.js",
@@ -39,10 +39,10 @@
39
39
  "@babel/preset-env": "7.25.7",
40
40
  "@babel/preset-react": "7.25.7",
41
41
  "@babel/preset-typescript": "7.25.7",
42
- "@storybook/addon-essentials": "8.3.4",
42
+ "@storybook/addon-essentials": "8.3.5",
43
43
  "@storybook/addon-webpack5-compiler-babel": "3.0.3",
44
- "@storybook/react": "8.3.4",
45
- "@storybook/react-webpack5": "8.3.4",
44
+ "@storybook/react": "8.3.5",
45
+ "@storybook/react-webpack5": "8.3.5",
46
46
  "@types/d3": "7.4.3",
47
47
  "@types/react": "18.3.11",
48
48
  "@types/react-router-dom": "5.3.3",
@@ -61,7 +61,7 @@
61
61
  "react-dom": "18.3.1",
62
62
  "react-router-dom": "5.3.4",
63
63
  "rimraf": "6.0.1",
64
- "storybook": "8.3.4",
64
+ "storybook": "8.3.5",
65
65
  "typescript": "5.6.2",
66
66
  "typescript-plugin-css-modules": "5.1.0"
67
67
  },
@@ -74,12 +74,13 @@
74
74
  "react-router-dom": "^5.0.0"
75
75
  },
76
76
  "dependencies": {
77
- "@bundle-stats/utils": "^4.16.0-beta.1",
77
+ "@bundle-stats/utils": "^4.16.0-beta.10",
78
78
  "ariakit": "2.0.0-next.44",
79
- "d3": "^7.8.5",
79
+ "d3": "7.9.0",
80
80
  "modern-css-reset": "1.4.0",
81
- "react-use": "^17.5.0",
81
+ "react-use": "17.5.1",
82
+ "snarkdown": "2.0.0",
82
83
  "use-query-params": "2.2.1"
83
84
  },
84
- "gitHead": "db71907f2916c3bc5f4367041f4368a8f0a47c17"
85
+ "gitHead": "cb616111c85f4b0d28e4b049fe3f6c7b0d7551d7"
85
86
  }
@@ -52,10 +52,10 @@ const DISPLAY_TYPE_GROUPS = {
52
52
 
53
53
  const getFileTypeFilters = (filters) =>
54
54
  Object.entries(FILE_TYPE_LABELS).map(([key, label]) => ({
55
- key,
56
- label,
57
- defaultValue: get(filters, `${ASSET_FILE_TYPE}.${key}`, true),
58
- }));
55
+ key,
56
+ label,
57
+ defaultValue: get(filters, `${ASSET_FILE_TYPE}.${key}`, true),
58
+ }));
59
59
 
60
60
  const getFilters = ({ compareMode, filters }) => ({
61
61
  [ASSET_FILTERS.CHANGED]: {
@@ -64,7 +64,7 @@ const getFilters = ({ compareMode, filters }) => ({
64
64
  disabled: !compareMode,
65
65
  },
66
66
  [ASSET_ENTRY_TYPE]: {
67
- label: 'Entry type',
67
+ label: 'Type',
68
68
  children: [
69
69
  {
70
70
  key: ASSET_FILTERS.ENTRY,
@@ -396,7 +396,7 @@ export const BundleAssets = (props) => {
396
396
  )}
397
397
 
398
398
  <Dialog title={I18N.EXPORT} width="wide" state={exportDialog}>
399
- {exportDialog.open && <MetricsTableExport items={items} download="bundle-stats--assets"/>}
399
+ {exportDialog.open && <MetricsTableExport items={items} download="bundle-stats--assets" />}
400
400
  </Dialog>
401
401
  </>
402
402
  );
@@ -4,6 +4,7 @@
4
4
 
5
5
  .entry {
6
6
  color: inherit;
7
+ line-height: var(--line-height-heading);
7
8
  text-decoration: none;
8
9
  }
9
10
 
@@ -5,7 +5,6 @@ import type { ReportMetricRow } from '@bundle-stats/utils';
5
5
  import { Stack } from '../../layout/stack';
6
6
  import { Tabs } from '../../ui/tabs';
7
7
  import { PreviewSource } from '../preview-source';
8
- import css from './metrics-table-export.module.css';
9
8
 
10
9
  const generateSourceJSON = (items: Array<ReportMetricRow>): string => {
11
10
  const output = items.map((item) => ({
@@ -54,12 +53,12 @@ const SOURCES = [
54
53
  {
55
54
  label: 'CSV',
56
55
  transformFn: generateSourceCSV,
57
- extension: '.csv',
56
+ extension: 'csv',
58
57
  },
59
58
  {
60
59
  label: 'JSON',
61
60
  transformFn: generateSourceJSON,
62
- extension: '.json',
61
+ extension: 'json',
63
62
  },
64
63
  ];
65
64
 
@@ -85,14 +84,14 @@ export const MetricsTableExport = (props: MetricsTableExportProps) => {
85
84
  </Tabs.Item>
86
85
  ))}
87
86
  </Tabs>
88
- <div className={css.panels}>
87
+ <div>
89
88
  {SOURCES.map(
90
89
  (source) =>
91
90
  selectedId === source.label && (
92
91
  <PreviewSource
93
92
  source={source.transformFn(items)}
93
+ rows={20}
94
94
  download={`${download}.${source.extension}`}
95
- className={css.panel}
96
95
  key={source.label}
97
96
  />
98
97
  ),
@@ -7,6 +7,8 @@
7
7
  z-index: 2;
8
8
  top: var(--space-xsmall);
9
9
  right: var(--space-xsmall);
10
+ background: var(--color-background);
11
+ border-radius: var(--radius-medium);
10
12
  }
11
13
 
12
14
  /** fix control group with nested components */
@@ -21,8 +23,18 @@
21
23
  box-shadow: none;
22
24
  }
23
25
 
26
+ /** Source content */
24
27
  .content {
25
28
  position: relative;
26
29
  z-index: 1;
27
30
  height: 100%;
31
+ background: var(--color-highlight);
32
+ color: var(--color-text);
33
+ font-family: var(--font-family-fixed);
34
+ }
35
+
36
+ /** Empty / loading state */
37
+ .isEmpty .content {
38
+ pointer-events: none;
39
+ background: var(--color-highlight);
28
40
  }
@@ -29,7 +29,25 @@ const SOURCE = JSON.stringify(
29
29
 
30
30
  export const Default: Story = {
31
31
  args: {
32
- source: SOURCE,
32
+ source: JSON.stringify(
33
+ [
34
+ {
35
+ label: 'Hey',
36
+ runs: [
37
+ { value: 1, name: 'a' },
38
+ { value: 2, name: 'b' },
39
+ ],
40
+ },
41
+ ],
42
+ null,
43
+ 2,
44
+ ),
45
+ download: 'bundle-stats--assets.json',
46
+ },
47
+ };
48
+
49
+ export const Empty: Story = {
50
+ args: {
33
51
  download: 'bundle-stats--assets.json',
34
52
  },
35
53
  };
@@ -9,8 +9,14 @@ import { Tooltip } from '../../ui/tooltip';
9
9
  import { Textarea } from '../../ui/textarea';
10
10
  import css from './preview-source.module.css';
11
11
 
12
+ const DEFAULT_ROWS = 10;
13
+
12
14
  type PreviewSourceProps = {
13
- source: string;
15
+ source?: string;
16
+ /**
17
+ * Textarea rows
18
+ */
19
+ rows?: number;
14
20
  /**
15
21
  * Link download attribute
16
22
  * @example
@@ -20,28 +26,31 @@ type PreviewSourceProps = {
20
26
  } & ComponentProps<'div'>;
21
27
 
22
28
  export const PreviewSource = (props: PreviewSourceProps) => {
23
- const { className = '', source, download = false, ...restProps } = props;
29
+ const { className = '', source, rows = DEFAULT_ROWS, download = false, ...restProps } = props;
30
+
31
+ const isEmpty = !source;
32
+ const rootClassName = cx(css.root, className, isEmpty && css.isEmpty);
24
33
 
25
34
  return (
26
- <div className={cx(css.root, className)} {...restProps}>
27
- <ControlGroup className={css.toolbar}>
28
- <CopyToClipboard outline size="small" text={source} />
29
- {download && (
30
- <Tooltip title={`Download ${download}`} className={css.downloadTooltip}>
31
- <Button
32
- outline
33
- rightGlyph={BUTTON_GLYPHS.DOWNLOAD}
34
- size="small"
35
- as="a"
36
- href={`data:application/json,${encodeURIComponent(source)}`}
37
- download={download}
38
- />
39
- </Tooltip>
40
- )}
41
- </ControlGroup>
42
- <Textarea previewSource readOnly rows={12} className={css.content}>
43
- {source}
44
- </Textarea>
35
+ <div className={rootClassName} {...restProps}>
36
+ {source && (
37
+ <ControlGroup className={css.toolbar}>
38
+ <CopyToClipboard outline size="small" text={source} />
39
+ {download && (
40
+ <Tooltip title={`Download ${download}`} className={css.downloadTooltip}>
41
+ <Button
42
+ outline
43
+ rightGlyph={BUTTON_GLYPHS.DOWNLOAD}
44
+ size="small"
45
+ as="a"
46
+ href={`data:application/json,${encodeURIComponent(source)}`}
47
+ download={download}
48
+ />
49
+ </Tooltip>
50
+ )}
51
+ </ControlGroup>
52
+ )}
53
+ <Textarea readOnly rows={rows} value={source} className={css.content} />
45
54
  </div>
46
55
  );
47
56
  };
@@ -201,6 +201,10 @@
201
201
 
202
202
  --outline-hover: 0 0 0 var(--space-xxxsmall) var(--color-highlight);
203
203
 
204
+ --skeleton-inline-background: linear-gradient(transparent 10%, currentColor 10.1%, currentColor 89.9%, transparent 90%);
205
+ --skeleton-block-background: currentColor;
206
+ --skeleton-opacity: 0.06;
207
+
204
208
  /** Layout */
205
209
  --max-width: 88rem;
206
210
  --entry-info-width: 64rem;
@@ -61,11 +61,11 @@
61
61
 
62
62
  /** Width variation */
63
63
  .width--narrow {
64
- max-width: 480px;
64
+ max-width: 360px;
65
65
  }
66
66
 
67
67
  .width--medium {
68
- max-width: 748px;
68
+ max-width: 640px;
69
69
  }
70
70
 
71
71
  .width--wide {
@@ -73,7 +73,7 @@
73
73
  }
74
74
 
75
75
  .width--extra-wide {
76
- max-width: var(--max-width);
76
+ max-width: calc(var(--max-width) + 2 * var(--space-medium));
77
77
  }
78
78
 
79
79
  /** Center variation */
package/src/ui/index.js CHANGED
@@ -13,6 +13,7 @@ export { Icon } from './icon';
13
13
  export { Input } from './input';
14
14
  export { InputSearch } from './input-search';
15
15
  export { Loader } from './loader';
16
+ export { Markdown } from './markdown';
16
17
  export { Skeleton } from './skeleton';
17
18
  export { Table } from './table';
18
19
  export { Tabs } from './tabs';
@@ -0,0 +1 @@
1
+ export * from './markdown';
@@ -0,0 +1,7 @@
1
+ .root code {
2
+ padding: 2px var(--space-xxxsmall);
3
+ background: var(--color-highlight);
4
+ outline: 1px solid var(--color-outline);
5
+ border-radius: var(--radius-small);
6
+ color: var(--color-text);
7
+ }
@@ -0,0 +1,29 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { Markdown } from '.';
3
+
4
+ const meta: Meta<typeof Markdown> = {
5
+ title: 'UI/Markdown',
6
+ component: Markdown,
7
+ };
8
+
9
+ export default meta;
10
+
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const Default: Story = {
14
+ args: {
15
+ content: '**One line** _markdown_ content',
16
+ },
17
+ };
18
+
19
+ const MULTI_LINE_MARKDOWN = `
20
+ **Lorem ipsum** dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Habitant morbi tristique senectus et netus et malesuada.
21
+
22
+ Eget nunc scelerisque viverra mauris in. Ipsum dolor sit amet consectetur adipiscing.
23
+ `;
24
+
25
+ export const MultiLine: Story = {
26
+ args: {
27
+ content: MULTI_LINE_MARKDOWN,
28
+ },
29
+ };
@@ -0,0 +1,24 @@
1
+ import React, { ComponentProps, ElementType, useMemo } from 'react';
2
+ import cx from 'classnames';
3
+ import snarkdown from 'snarkdown';
4
+
5
+ import css from './markdown.module.css';
6
+
7
+ type MarkdownProps = {
8
+ content?: string;
9
+ as?: ElementType;
10
+ } & ComponentProps<'div'>;
11
+
12
+ export const Markdown = (props: MarkdownProps) => {
13
+ const { className = '', content = '', as: Component = 'div', ...restProps } = props;
14
+
15
+ const html = useMemo(() => snarkdown(content), [content]);
16
+
17
+ return (
18
+ <Component
19
+ className={cx(css.root, className)}
20
+ {...restProps}
21
+ dangerouslySetInnerHTML={{ __html: html }}
22
+ />
23
+ );
24
+ };
@@ -1,6 +1,6 @@
1
1
  .root {
2
- background: linear-gradient(transparent 10%, currentColor 10.1%, currentColor 89.9%, transparent 90%);
3
- opacity: 0.05;
2
+ background: var(--skeleton-inline-background);
3
+ opacity: var(--skeleton-opacity);
4
4
  pointer-events: none;
5
5
  min-width: 6em;
6
6
  border-radius: var(--radius-medium);
@@ -14,5 +14,5 @@
14
14
  }
15
15
 
16
16
  .block {
17
- background: currentColor;
17
+ background: var(--skeleton-block-background);
18
18
  }
@@ -10,6 +10,7 @@
10
10
  color: var(--color-text-ultra-light);
11
11
  font-weight: bold;
12
12
  text-decoration: none;
13
+ cursor: default;
13
14
  }
14
15
 
15
16
  .item::after {
@@ -36,13 +36,6 @@
36
36
  color: var(--color-text-light);
37
37
  }
38
38
 
39
- /**
40
- * Source variation
41
- */
42
- .previewSource {
43
- font-family: var(--font-family-fixed);
44
- }
45
-
46
39
  /** Size modifier */
47
40
  /* default - medium */
48
41
  .root {
@@ -5,19 +5,13 @@ import cx from 'classnames';
5
5
  import css from './textarea.module.css';
6
6
 
7
7
  export type TextareaProps = {
8
- previewSource?: boolean;
9
8
  size?: 'small' | 'medium' | 'large';
10
9
  } & ComponentProps<'textarea'>;
11
10
 
12
11
  export const Textarea = (props: TextareaProps) => {
13
- const { className = '', previewSource = false, size = '', ...restProps } = props;
12
+ const { className = '', size = '', ...restProps } = props;
14
13
 
15
- const rootClassName = cx(
16
- css.root,
17
- previewSource && css.previewSource,
18
- size && css[size],
19
- className,
20
- );
14
+ const rootClassName = cx(css.root, size && css[size], className);
21
15
 
22
16
  return <textarea className={rootClassName} {...restProps} />;
23
17
  };
@@ -1,7 +1,8 @@
1
1
  import type { ComponentProps } from 'react';
2
2
  import React from 'react';
3
3
  type PreviewSourceProps = {
4
- source: string;
4
+ source?: string;
5
+ rows?: number;
5
6
  download?: string;
6
7
  } & ComponentProps<'div'>;
7
8
  export declare const PreviewSource: (props: PreviewSourceProps) => React.JSX.Element;
@@ -13,6 +13,7 @@ export { Icon } from "./icon";
13
13
  export { Input } from "./input";
14
14
  export { InputSearch } from "./input-search";
15
15
  export { Loader } from "./loader";
16
+ export { Markdown } from "./markdown";
16
17
  export { Skeleton } from "./skeleton";
17
18
  export { Table } from "./table";
18
19
  export { Tabs } from "./tabs";
@@ -0,0 +1 @@
1
+ export * from './markdown';
@@ -0,0 +1,7 @@
1
+ import React, { ComponentProps, ElementType } from 'react';
2
+ type MarkdownProps = {
3
+ content?: string;
4
+ as?: ElementType;
5
+ } & ComponentProps<'div'>;
6
+ export declare const Markdown: (props: MarkdownProps) => React.JSX.Element;
7
+ export {};
@@ -1,7 +1,6 @@
1
1
  import type { ComponentProps } from 'react';
2
2
  import React from 'react';
3
3
  export type TextareaProps = {
4
- previewSource?: boolean;
5
4
  size?: 'small' | 'medium' | 'large';
6
5
  } & ComponentProps<'textarea'>;
7
6
  export declare const Textarea: (props: TextareaProps) => React.JSX.Element;
@@ -1,8 +0,0 @@
1
- .panels {
2
- }
3
-
4
- .panel {
5
- min-height: 320px;
6
- height: 60vh;
7
- max-height: 480px;
8
- }
@@ -1,8 +0,0 @@
1
- .panels {
2
- }
3
-
4
- .panel {
5
- min-height: 320px;
6
- height: 60vh;
7
- max-height: 480px;
8
- }
@@ -1,8 +0,0 @@
1
- .panels {
2
- }
3
-
4
- .panel {
5
- min-height: 320px;
6
- height: 60vh;
7
- max-height: 480px;
8
- }