@availity/mui-tree 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [0.2.0](https://github.com/Availity/element/compare/@availity/mui-tree@0.1.1...@availity/mui-tree@0.2.0) (2024-09-18)
6
+
7
+
8
+ ### Features
9
+
10
+ * **mui-tree:** add JsonViewer component ([b17a9c8](https://github.com/Availity/element/commit/b17a9c82f4348fd51da10bd26a5944f32405db0c))
11
+
12
+ ## [0.1.1](https://github.com/Availity/element/compare/@availity/mui-tree@0.1.0...@availity/mui-tree@0.1.1) (2024-09-11)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * **mui-tree:** add aria-label to checkbox input ([aa277db](https://github.com/Availity/element/commit/aa277db7440f6db77623735a579370f74e8692c7))
18
+
5
19
  ## 0.1.0 (2024-09-09)
6
20
 
7
21
  ### Dependency Updates
package/dist/index.d.mts CHANGED
@@ -12,6 +12,6 @@ declare const DynamicTreeView: ({ children, slots, ...rest }: DynamicTreeViewPro
12
12
  interface TreeItemProps extends TreeItem2Props {
13
13
  truncate?: boolean;
14
14
  }
15
- declare const TreeItem: ({ children, slots, slotProps, truncate, ...rest }: TreeItemProps) => JSX.Element;
15
+ declare const TreeItem: ({ children, label, slots, slotProps, truncate, ...rest }: TreeItemProps) => JSX.Element;
16
16
 
17
17
  export { DynamicTreeView, type DynamicTreeViewProps, TreeItem, type TreeItemProps, TreeView, type TreeViewProps };
package/dist/index.d.ts CHANGED
@@ -12,6 +12,6 @@ declare const DynamicTreeView: ({ children, slots, ...rest }: DynamicTreeViewPro
12
12
  interface TreeItemProps extends TreeItem2Props {
13
13
  truncate?: boolean;
14
14
  }
15
- declare const TreeItem: ({ children, slots, slotProps, truncate, ...rest }: TreeItemProps) => JSX.Element;
15
+ declare const TreeItem: ({ children, label, slots, slotProps, truncate, ...rest }: TreeItemProps) => JSX.Element;
16
16
 
17
17
  export { DynamicTreeView, type DynamicTreeViewProps, TreeItem, type TreeItemProps, TreeView, type TreeViewProps };
package/dist/index.js CHANGED
@@ -71,16 +71,26 @@ var import_TreeItem2 = require("@mui/x-tree-view/TreeItem2");
71
71
  var import_mui_icon = require("@availity/mui-icon");
72
72
  var import_jsx_runtime2 = require("react/jsx-runtime");
73
73
  var TreeItem = (_a) => {
74
- var _b = _a, { children, slots, slotProps, truncate } = _b, rest = __objRest(_b, ["children", "slots", "slotProps", "truncate"]);
74
+ var _b = _a, { children, label, slots, slotProps, truncate } = _b, rest = __objRest(_b, ["children", "label", "slots", "slotProps", "truncate"]);
75
75
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
76
76
  import_TreeItem2.TreeItem2,
77
77
  __spreadProps(__spreadValues({}, rest), {
78
- slots: __spreadProps(__spreadValues({}, slots), { expandIcon: import_mui_icon.TriangleRightIcon, collapseIcon: import_mui_icon.TriangleExpandIcon }),
78
+ label,
79
+ slots: __spreadProps(__spreadValues({}, slots), {
80
+ expandIcon: import_mui_icon.TriangleRightIcon,
81
+ collapseIcon: import_mui_icon.TriangleExpandIcon
82
+ }),
79
83
  slotProps: __spreadProps(__spreadValues({}, slotProps), {
80
84
  expandIcon: { fontSize: "Xsmall" },
81
85
  collapseIcon: { fontSize: "Xsmall" },
82
86
  label: {
83
87
  style: truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } : {}
88
+ },
89
+ checkbox: {
90
+ // @ts-expect-error TreeItem2SlotProps.checkbox types are incorrect
91
+ inputProps: {
92
+ "aria-hidden": true
93
+ }
84
94
  }
85
95
  }),
86
96
  children
package/dist/index.mjs CHANGED
@@ -46,16 +46,26 @@ import { TreeItem2 } from "@mui/x-tree-view/TreeItem2";
46
46
  import { TriangleRightIcon, TriangleExpandIcon } from "@availity/mui-icon";
47
47
  import { jsx as jsx2 } from "react/jsx-runtime";
48
48
  var TreeItem = (_a) => {
49
- var _b = _a, { children, slots, slotProps, truncate } = _b, rest = __objRest(_b, ["children", "slots", "slotProps", "truncate"]);
49
+ var _b = _a, { children, label, slots, slotProps, truncate } = _b, rest = __objRest(_b, ["children", "label", "slots", "slotProps", "truncate"]);
50
50
  return /* @__PURE__ */ jsx2(
51
51
  TreeItem2,
52
52
  __spreadProps(__spreadValues({}, rest), {
53
- slots: __spreadProps(__spreadValues({}, slots), { expandIcon: TriangleRightIcon, collapseIcon: TriangleExpandIcon }),
53
+ label,
54
+ slots: __spreadProps(__spreadValues({}, slots), {
55
+ expandIcon: TriangleRightIcon,
56
+ collapseIcon: TriangleExpandIcon
57
+ }),
54
58
  slotProps: __spreadProps(__spreadValues({}, slotProps), {
55
59
  expandIcon: { fontSize: "Xsmall" },
56
60
  collapseIcon: { fontSize: "Xsmall" },
57
61
  label: {
58
62
  style: truncate ? { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } : {}
63
+ },
64
+ checkbox: {
65
+ // @ts-expect-error TreeItem2SlotProps.checkbox types are incorrect
66
+ inputProps: {
67
+ "aria-hidden": true
68
+ }
59
69
  }
60
70
  }),
61
71
  children
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@availity/mui-tree",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Availity MUI Tree Component - part of the @availity/element design system",
5
5
  "keywords": [
6
6
  "react",
@@ -34,6 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@availity/mui-icon": "^0.10.1",
36
36
  "@availity/mui-layout": "^0.1.6",
37
+ "@availity/mui-typography": "^0.2.0",
37
38
  "@mui/material": "^5.15.15",
38
39
  "react": "18.2.0",
39
40
  "react-dom": "18.2.0",
@@ -49,6 +50,6 @@
49
50
  "access": "public"
50
51
  },
51
52
  "dependencies": {
52
- "@mui/x-tree-view": "^7.15.0"
53
+ "@mui/x-tree-view": "^7.16.0"
53
54
  }
54
55
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
4
  import type { TreeViewBaseItem } from '@mui/x-tree-view/models';
5
+ import { Typography } from '@availity/mui-typography';
5
6
  import { DynamicTreeView, DynamicTreeViewProps } from './DynamicTreeView';
6
7
 
7
8
  /**
@@ -23,7 +24,7 @@ const items: TreeViewBaseItem[] = [
23
24
  id: 'tree-1',
24
25
  label: 'Tree 1',
25
26
  children: [
26
- { id: 'sub-tree-1.1', label: 'Sub Tree 1.1' },
27
+ { id: 'sub-tree-1.1', label: 'Sub Tree 1.1', children: [{ id: 'sub-tree-1.1.1', label: 'Sub Tree 1.1.1' }] },
27
28
  { id: 'sub-tree-1.2', label: 'Sub Tree 1.2' },
28
29
  { id: 'sub-tree-1.3', label: 'Sub Tree 1.3' },
29
30
  ],
@@ -49,24 +50,42 @@ const items: TreeViewBaseItem[] = [
49
50
  ];
50
51
 
51
52
  export const _DynamicTreeView: StoryObj<typeof DynamicTreeView> = {
52
- render: (args: DynamicTreeViewProps) => <DynamicTreeView {...args} />,
53
+ render: (args: DynamicTreeViewProps) => (
54
+ <>
55
+ <Typography variant="h1" children="Selectable Dynamic Tree" id="dynamic-tree" />
56
+ <DynamicTreeView {...args} />
57
+ </>
58
+ ),
53
59
  args: {
54
60
  items,
61
+ 'aria-labelledby': 'dynamic-tree',
55
62
  },
56
63
  };
57
64
  export const _DynamicTreeViewCheckbox: StoryObj<typeof DynamicTreeView> = {
58
- render: (args: DynamicTreeViewProps) => <DynamicTreeView {...args} />,
65
+ render: (args: DynamicTreeViewProps) => (
66
+ <>
67
+ <Typography variant="h1" children="Selectable Dynamic Tree" id="dynamic-tree-selectable" />
68
+ <DynamicTreeView {...args} />
69
+ </>
70
+ ),
59
71
  args: {
60
72
  items,
61
73
  checkboxSelection: true,
74
+ 'aria-labelledby': 'dynamic-tree-selectable',
62
75
  },
63
76
  };
64
77
 
65
78
  export const _DynamicTreeViewEditable: StoryObj<typeof DynamicTreeView> = {
66
- render: (args: DynamicTreeViewProps) => <DynamicTreeView {...args} />,
79
+ render: (args: DynamicTreeViewProps) => (
80
+ <>
81
+ <Typography variant="h1" children="Editable Dynamic Tree" id="dynamic-tree-editable" />
82
+ <DynamicTreeView {...args} />
83
+ </>
84
+ ),
67
85
  args: {
68
86
  items,
69
87
  isItemEditable: true,
70
88
  experimentalFeatures: { labelEditing: true },
89
+ 'aria-labelledby': 'dynamic-tree-editable',
71
90
  },
72
91
  };
@@ -0,0 +1,19 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+
3
+ import JsonViewer, { JsonViewerProps } from './JsonViewer';
4
+ // import README from '../README.md';
5
+
6
+ const meta: Meta<typeof JsonViewer> = {
7
+ title: 'Components/TreeView/JsonViewer',
8
+ component: JsonViewer,
9
+ tags: ['autodocs'],
10
+ };
11
+
12
+ export default meta;
13
+
14
+ export const _JsonViewer: StoryObj<typeof JsonViewer> = {
15
+ render: ({ data, ...rest }: JsonViewerProps) => <JsonViewer data={data} {...rest} />,
16
+ args: {
17
+ data: { foo: { bar: { baz: ['stuff', 'things', 'etc.'] } } },
18
+ },
19
+ };
@@ -0,0 +1,21 @@
1
+ import { render, fireEvent } from '@testing-library/react';
2
+ import JsonViewer from './JsonViewer';
3
+
4
+ const setup = (data: Record<string, unknown>) => render(<JsonViewer data={data} />);
5
+
6
+ describe('JsonViewer', () => {
7
+ test('does not render keys with null or undefined values without throwing error', () => {
8
+ const { getByText, queryByText } = setup({ foo: 'bar', baz: null, somethingElse: undefined });
9
+ const el = getByText(/bar/i);
10
+ expect(el).toBeInTheDocument();
11
+ const ghost = queryByText('baz');
12
+ expect(ghost).not.toBeInTheDocument();
13
+ });
14
+ test('renders deeply nested objects into the dom so they can be read by screenreaders even if parent elements are not open', () => {
15
+ const { getByText } = setup({ foo: { bar: { baz: ['stuff', 'things', 'etc.'] } } });
16
+ fireEvent.click(getByText('foo: { } 1 keys'));
17
+ fireEvent.click(getByText('bar: { } 1 keys'));
18
+ fireEvent.click(getByText('baz: [ ] 3 items'));
19
+ expect(getByText('0: stuff')).toBeInTheDocument();
20
+ });
21
+ });
@@ -0,0 +1,43 @@
1
+ import { TreeItem } from './TreeItem';
2
+ import { TreeView, TreeViewProps } from './TreeView';
3
+
4
+ export interface JsonViewerProps extends Omit<TreeViewProps, 'children'> {
5
+ /** Data to be rendered, can be most valid javascript objects, some uncommon types may not by fully supported - like cyclical objects, proxies, symbols as keys. */
6
+ data: Record<string, unknown>;
7
+ }
8
+
9
+ const isPrimitive = (value: unknown): value is string | number | boolean => {
10
+ return ['string', 'number', 'boolean'].includes(typeof value);
11
+ };
12
+
13
+ const isObject = (value: unknown): value is Record<string, unknown> => {
14
+ return !!value && typeof value === 'object';
15
+ };
16
+
17
+ const getDetails = ({ data }: JsonViewerProps): (JSX.Element | null)[] => {
18
+ return Object.entries(data).map((entry) => {
19
+ const [key, value] = entry;
20
+
21
+ if (isPrimitive(value)) {
22
+ const label = `${key}: ${value.toString()}`;
23
+ return <TreeItem label={label} itemId={`${key}.${value}`} key={`${key}.${value}`} />;
24
+ }
25
+ if (isObject(value)) {
26
+ const label = `${key}: ${Array.isArray(value) ? `[ ] ${value.length} items` : `{ } ${Object.keys(value).length} keys`}`;
27
+ return (
28
+ <TreeItem label={label} itemId={key} key={key}>
29
+ {getDetails({ data: value })}
30
+ </TreeItem>
31
+ );
32
+ }
33
+
34
+ return null;
35
+ });
36
+ };
37
+
38
+ const JsonViewer = ({ data, ...rest }: JsonViewerProps): JSX.Element => {
39
+ const details = getDetails({ data });
40
+ return <TreeView {...rest}>{details}</TreeView>;
41
+ };
42
+
43
+ export default JsonViewer;
@@ -5,6 +5,7 @@ import { TreeItem, TreeItemProps } from './TreeItem';
5
5
  import { TreeView } from './TreeView';
6
6
  import { FolderIcon } from '@availity/mui-icon';
7
7
  import { Grid } from '@availity/mui-layout';
8
+ import { Typography } from '@availity/mui-typography';
8
9
 
9
10
  const meta: Meta<typeof TreeItem> = {
10
11
  title: 'Components/TreeView/TreeItem',
@@ -16,36 +17,47 @@ export default meta;
16
17
 
17
18
  export const _Tree: StoryObj<typeof TreeItem> = {
18
19
  render: (args: TreeItemProps) => (
19
- <TreeView>
20
- <TreeItem {...args} />
21
- </TreeView>
20
+ <>
21
+ <Typography variant="h1" children="Tree Item" id="tree-item" />
22
+ <TreeView>
23
+ <TreeItem {...args} />
24
+ </TreeView>
25
+ </>
22
26
  ),
23
27
  args: {
24
28
  truncate: true,
25
29
  itemId: 'Tree Item Label',
26
30
  label: 'Tree Item Label',
27
31
  children: <TreeItem itemId="This text is a child of TreeItem" label="This text is a child of TreeItem" />,
32
+ 'aria-labelledby': 'tree-item',
28
33
  },
29
34
  };
30
35
 
31
36
  export const _TreeCheckboxSelection: StoryObj<typeof TreeItem> = {
32
37
  render: (args: TreeItemProps) => (
33
- <TreeView checkboxSelection>
34
- <TreeItem {...args} />
35
- </TreeView>
38
+ <>
39
+ <Typography variant="h1" children="Selectable Tree Item" id="tree-item-selectable" />
40
+ <TreeView checkboxSelection>
41
+ <TreeItem {...args} />
42
+ </TreeView>
43
+ </>
36
44
  ),
37
45
  args: {
38
46
  itemId: 'Tree Item Label',
39
47
  label: 'Tree Item Label',
40
48
  children: <TreeItem itemId="This text is a child of TreeItem" label="This text is a child of TreeItem" />,
49
+ 'aria-labelledby': 'tree-item-selectable',
41
50
  },
42
51
  };
43
52
 
44
53
  export const _TreeIcon: StoryObj<typeof TreeItem> = {
45
54
  render: (args: TreeItemProps) => (
46
- <TreeView checkboxSelection>
47
- <TreeItem {...args} />
48
- </TreeView>
55
+ <>
56
+ <Typography variant="h1" children="Tree Item with Icon" id="tree-item-icon" />
57
+ <TreeView checkboxSelection>
58
+ <TreeItem {...args} />
59
+ </TreeView>
60
+ </>
49
61
  ),
50
62
  args: {
51
63
  itemId: 'tree-item',
@@ -55,7 +67,7 @@ export const _TreeIcon: StoryObj<typeof TreeItem> = {
55
67
  Tree Item
56
68
  </Grid>
57
69
  ),
58
- // slots: { icon: FolderIcon },
59
70
  children: <TreeItem itemId="sub-tree-item" label="Sub Tree Item" />,
71
+ 'aria-labelledby': 'tree-item-icon',
60
72
  },
61
73
  };
@@ -5,11 +5,16 @@ export interface TreeItemProps extends MuiTreeItem2Props {
5
5
  truncate?: boolean;
6
6
  }
7
7
 
8
- export const TreeItem = ({ children, slots, slotProps, truncate, ...rest }: TreeItemProps): JSX.Element => {
8
+ export const TreeItem = ({ children, label, slots, slotProps, truncate, ...rest }: TreeItemProps): JSX.Element => {
9
9
  return (
10
10
  <TreeItem2
11
11
  {...rest}
12
- slots={{ ...slots, expandIcon: TriangleRightIcon, collapseIcon: TriangleExpandIcon }}
12
+ label={label}
13
+ slots={{
14
+ ...slots,
15
+ expandIcon: TriangleRightIcon,
16
+ collapseIcon: TriangleExpandIcon,
17
+ }}
13
18
  slotProps={{
14
19
  ...slotProps,
15
20
  expandIcon: { fontSize: 'Xsmall' },
@@ -17,6 +22,12 @@ export const TreeItem = ({ children, slots, slotProps, truncate, ...rest }: Tree
17
22
  label: {
18
23
  style: truncate ? { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } : {},
19
24
  },
25
+ checkbox: {
26
+ // @ts-expect-error TreeItem2SlotProps.checkbox types are incorrect
27
+ inputProps: {
28
+ 'aria-hidden': true,
29
+ },
30
+ },
20
31
  }}
21
32
  >
22
33
  {children}
@@ -1,6 +1,7 @@
1
1
  // Each exported component in the package should have its own stories file
2
2
 
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
+ import { Typography } from '@availity/mui-typography';
4
5
  import { TreeView, TreeViewProps } from './TreeView';
5
6
  import { TreeItem } from './TreeItem';
6
7
 
@@ -38,15 +39,27 @@ const items = (
38
39
  );
39
40
 
40
41
  export const _TreeView: StoryObj<typeof TreeView> = {
41
- render: (args: TreeViewProps) => <TreeView {...args} />,
42
+ render: (args: TreeViewProps) => (
43
+ <>
44
+ <Typography variant="h1" children="Tree View" id="tree-view" />
45
+ <TreeView {...args} />
46
+ </>
47
+ ),
42
48
  args: {
43
49
  children: items,
50
+ 'aria-labelledby': 'tree-view',
44
51
  },
45
52
  };
46
53
 
47
54
  export const _TreeViewCheckbox: StoryObj<typeof TreeView> = {
48
- render: (args: TreeViewProps) => <TreeView checkboxSelection {...args} />,
55
+ render: (args: TreeViewProps) => (
56
+ <>
57
+ <Typography variant="h1" children="Selectable Tree View" id="tree-view-selectable" />
58
+ <TreeView checkboxSelection {...args} />
59
+ </>
60
+ ),
49
61
  args: {
50
62
  children: items,
63
+ 'aria-labelledby': 'tree-view-selectable',
51
64
  },
52
65
  };