@trimble-oss/moduswebcomponents-mcp 1.0.0 → 1.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/package.json +1 -1
- package/versions/{1.0.0 → 1.0.1}/component-docs/_all_components.json +1 -1
- package/versions/1.2.0/component-docs/_all_components.json +56 -0
- package/versions/1.2.0/component-docs/modus-wc-autocomplete.json +415 -0
- package/versions/1.2.0/component-docs/modus-wc-date.json +227 -0
- package/versions/1.2.0/component-docs/modus-wc-dropdown-menu.json +164 -0
- package/versions/1.2.0/component-docs/modus-wc-logo.json +61 -0
- package/versions/1.2.0/component-docs/modus-wc-menu-item.json +165 -0
- package/versions/1.2.0/component-docs/modus-wc-menu.json +106 -0
- package/versions/1.2.0/component-docs/modus-wc-navbar.json +290 -0
- package/versions/1.2.0/component-docs/modus-wc-profile-menu.json +64 -0
- package/versions/1.2.0/component-docs/modus-wc-side-navigation.json +102 -0
- package/versions/1.2.0/component-docs/modus-wc-table.json +202 -0
- package/versions/1.2.0/component-docs/modus-wc-tooltip.json +94 -0
- package/versions/1.2.0/component-docs/modus-wc-typography.json +78 -0
- package/versions/1.2.0/docs/_all_docs.json +15 -0
- package/versions/1.2.0/docs/angular.mdx +374 -0
- package/versions/1.2.0/docs/getting-started.mdx +131 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-autocomplete.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-date.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-dropdown-menu.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-logo.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-menu-item.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-menu.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-navbar.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-profile-menu.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-side-navigation.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-table.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-tooltip.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/component-docs/modus-wc-typography.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/docs/_all_docs.json +0 -0
- /package/versions/{1.0.0 → 1.0.1}/docs/angular.mdx +0 -0
- /package/versions/{1.0.0 → 1.0.1}/docs/getting-started.mdx +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "",
|
|
3
|
+
"properties": [
|
|
4
|
+
{
|
|
5
|
+
"name": "profileProps",
|
|
6
|
+
"type": "IProfileMenuProps",
|
|
7
|
+
"description": "Profile menu properties containing user information",
|
|
8
|
+
"default": null,
|
|
9
|
+
"mutable": false,
|
|
10
|
+
"end_line": 67
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "menuOne",
|
|
14
|
+
"type": "ISubMenu",
|
|
15
|
+
"description": "Configuration for the first menu including title and items",
|
|
16
|
+
"default": null,
|
|
17
|
+
"mutable": false,
|
|
18
|
+
"end_line": 70
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "menuTwo",
|
|
22
|
+
"type": "ISubMenu",
|
|
23
|
+
"description": "Configuration for the second menu including title and items",
|
|
24
|
+
"default": null,
|
|
25
|
+
"mutable": false,
|
|
26
|
+
"end_line": 73
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"events": [
|
|
30
|
+
{
|
|
31
|
+
"name": "signOutClick",
|
|
32
|
+
"detail": "void",
|
|
33
|
+
"description": "Emitted when the Sign Out menu item is clicked",
|
|
34
|
+
"end_line": 76
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "menuItemClick",
|
|
38
|
+
"detail": "string",
|
|
39
|
+
"description": "Emitted when any menu item is clicked, passing back the item value or label",
|
|
40
|
+
"end_line": 79
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"methods": [],
|
|
44
|
+
"slots": [],
|
|
45
|
+
"examples": {
|
|
46
|
+
"basic": "<div style=\"min-height: 600px;\">\n <modus-wc-profile-menu\n .profileProps=${args['profile-props']}\n .menuOne=${ifDefined(args['menu-one'])}\n .menuTwo=${ifDefined(args['menu-two'])}\n @signOutClick=${action('signOutClick')}\n @menuItemClick=${action('menuItemClick')}\n ></modus-wc-profile-menu>\n</div>",
|
|
47
|
+
"variations": [],
|
|
48
|
+
"args": {
|
|
49
|
+
"profile-props": "profileData"
|
|
50
|
+
},
|
|
51
|
+
"argTypes": {},
|
|
52
|
+
"usage": []
|
|
53
|
+
},
|
|
54
|
+
"tag": "modus-wc-profile-menu",
|
|
55
|
+
"storyExample": {
|
|
56
|
+
"template": "<div style=\"min-height: 600px;\">\n <modus-wc-profile-menu\n .profileProps=${args['profile-props']}\n .menuOne=${ifDefined(args['menu-one'])}\n .menuTwo=${ifDefined(args['menu-two'])}\n @signOutClick=${action('signOutClick')}\n @menuItemClick=${action('menuItemClick')}\n ></modus-wc-profile-menu>\n</div>",
|
|
57
|
+
"args": {
|
|
58
|
+
"profile-props": "profileData"
|
|
59
|
+
},
|
|
60
|
+
"argTypes": {},
|
|
61
|
+
"events": [],
|
|
62
|
+
"fullContent": "import { action } from '@storybook/addon-actions';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { IProfileMenuProps, ISubMenu } from './modus-wc-profile-menu';\n\ninterface ProfileMenuArgs {\n 'profile-props': IProfileMenuProps;\n 'menu-one'?: ISubMenu;\n 'menu-two'?: ISubMenu;\n}\n\nconst profileData: IProfileMenuProps = {\n profileImageUrl:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n headerName: 'Enterprise ABC',\n userName: 'Jane Doe',\n userEmail: 'jane.doe@example.com',\n manageTrimbleId: {\n link: '#',\n },\n};\n\nconst meta: Meta<ProfileMenuArgs> = {\n title: 'Components/Profile Menu',\n component: 'modus-wc-profile-menu',\n args: {\n 'profile-props': profileData,\n },\n argTypes: {\n 'profile-props': {\n description: 'Profile menu properties containing user information',\n table: {\n type: {\n detail: `\n Interface: IProfileMenuProps\n Properties:\n - profileImageUrl (string): The URL of the profile image\n - headerName (string): The header name of the profile menu\n - userName (string): The name of the user\n - userEmail (string): The email of the user\n - manageTrimbleId (IManageTrimbleId, optional): The manage Trimble ID link configuration\n - link (string): The URL for managing the user's Trimble ID\n - target ('_blank' | '_self' | '_parent' | '_top', optional): The target for the link\n - rel (string, optional): The rel attribute for the link. Defaults to 'noopener noreferrer' when target is '_blank'\n `,\n },\n },\n },\n 'menu-one': {\n description: 'Configuration for the first submenu section',\n table: {\n type: {\n detail: `\n Interface: ISubMenu\n Properties:\n - title (string, optional): Title for the submenu section\n - items (IMenuItem[]): Array of menu items\n - label (string): The display text for the menu item\n - icon (string, optional): The name of the icon to display\n - iconSize ('xs', 'sm', 'md', 'lg', optional): The size of the icon\n - iconVariant ('solid' | 'outlined', optional): The variant of the icon\n - value (string, optional): The value associated with the menu item, used for selection\n `,\n },\n },\n },\n 'menu-two': {\n description: 'Configuration for the second submenu section',\n table: {\n type: {\n detail: `\n Interface: ISubMenu\n Properties:\n - title (string, optional): Title for the submenu section\n - items (IMenuItem[]): Array of menu items\n - label (string): The display text for the menu item\n - icon (string, optional): The name of the icon to display\n - iconSize ('xs', 'sm', 'md', 'lg', optional): The size of the icon\n - iconVariant ('solid' | 'outlined', optional): The variant of the icon\n - value (string, optional): The value associated with the menu item, used for selection\n `,\n },\n },\n },\n },\n parameters: {\n docs: {\n description: {\n component: `\nA customizable profile menu component that displays user information with optional submenus.\n\\nThe component uses the \\`modus-wc-panel\\` component for layout and supports one or two custom submenus.\n\n### Features\n- **User Profile Display**: Shows profile image, header name, username, and email\n- **Default Menu Items**: Includes pre-configured menu items (My Profile, My Products, Support center, Admin settings)\n- **Custom Submenus**: Supports up to two additional custom submenus with titles and icons\n- **Manage Trimble ID Link**: Optional link for managing user's Trimble ID\n- **Sign Out**: Built-in sign out menu item in the footer\n- **Icon Support**: Menu items can include icons with solid or outlined variants\n\n### Events\n- **menuItemClick**: Emitted when any menu item is clicked, passing back the item label/identifier\n- **signOutClick**: Emitted when the Sign Out menu item is clicked\n\n### Usage\nThe component requires a \\`profileProps\\` object with user information and optionally accepts \\`menuOne\\` and \\`menuTwo\\` for custom menus.\n `,\n },\n },\n },\n};\nexport default meta;\n\ntype Story = StoryObj<ProfileMenuArgs>;\nconst getSourceCode = (args: ProfileMenuArgs) => {\n const profilePropsCode = `const profileProps = ${JSON.stringify(args['profile-props'], null, 2)};`;\n\n const menuOneCode = args['menu-one']\n ? `\\nconst menuOne = ${JSON.stringify(args['menu-one'], null, 2)};`\n : '';\n\n const menuTwoCode = args['menu-two']\n ? `\\nconst menuTwo = ${JSON.stringify(args['menu-two'], null, 2)};`\n : '';\n\n return `<modus-wc-profile-menu></modus-wc-profile-menu>\n\n<script>\n ${profilePropsCode}${menuOneCode}${menuTwoCode}\n\n const element = document.querySelector('modus-wc-profile-menu');\n element.profileProps = profileProps;${args['menu-one'] ? '\\n element.menuOne = menuOne;' : ''}${args['menu-two'] ? '\\n element.menuTwo = menuTwo;' : ''}\n\n // Event listeners\n element.addEventListener('menuItemClick', (event) => {\n console.log('Menu item clicked:', event.detail);\n });\n element.addEventListener('signOutClick', () => {\n console.log('Sign Out clicked');\n });\n\n</script>\n`;\n};\n\nconst Template: Story = {\n parameters: {\n docs: {\n source: {\n transform: (_src, { args }: { args: ProfileMenuArgs }) =>\n getSourceCode(args),\n },\n },\n },\n render: (args) => {\n // prettier-ignore\n return html`\n<div style=\"min-height: 600px;\">\n <modus-wc-profile-menu\n .profileProps=${args['profile-props']}\n .menuOne=${ifDefined(args['menu-one'])}\n .menuTwo=${ifDefined(args['menu-two'])}\n @signOutClick=${action('signOutClick')}\n @menuItemClick=${action('menuItemClick')}\n ></modus-wc-profile-menu>\n</div>\n `;\n },\n};\n\nexport const Default: Story = {\n ...Template,\n parameters: {\n docs: {\n description: {\n story:\n 'Basic profile menu with default menu items (My Profile, My Products, Support center, Admin settings) and no custom submenus.',\n },\n source: {\n transform: (_src, { args }: { args: ProfileMenuArgs }) =>\n getSourceCode(args),\n },\n },\n },\n};\n\nexport const WithOneSubmenu: Story = {\n ...Template,\n parameters: {\n docs: {\n description: {\n story:\n 'Profile menu with one additional custom submenu section. Submenus can include a title and items with icons.',\n },\n source: {\n transform: (_src, { args }: { args: ProfileMenuArgs }) =>\n getSourceCode(args),\n },\n },\n },\n args: {\n 'menu-one': {\n title: 'Recent Projects',\n items: [\n {\n label: 'Project Alpha',\n icon: 'bug',\n iconVariant: 'solid',\n },\n {\n label: 'Project Beta',\n icon: 'triangle_down',\n iconVariant: 'solid',\n },\n {\n label: 'Project Gamma',\n icon: 'service_rep',\n iconVariant: 'solid',\n },\n ],\n },\n },\n};\n\nexport const WithTwoSubmenus: Story = {\n ...Template,\n parameters: {\n docs: {\n description: {\n story:\n 'Profile menu with two additional custom submenu sections. Each submenu can have its own title and menu items with icons.',\n },\n source: {\n transform: (_src, { args }: { args: ProfileMenuArgs }) =>\n getSourceCode(args),\n },\n },\n },\n args: {\n 'menu-one': {\n title: 'Recent Projects',\n items: [\n {\n label: 'Project Alpha',\n icon: 'bug',\n iconVariant: 'solid',\n },\n {\n label: 'Project Beta',\n icon: 'triangle_down',\n iconVariant: 'solid',\n },\n {\n label: 'Project Gamma',\n icon: 'antenna',\n iconVariant: 'solid',\n },\n ],\n },\n 'menu-two': {\n title: 'Quick Actions',\n items: [\n {\n label: 'Settings',\n icon: 'settings',\n iconVariant: 'solid',\n },\n {\n label: 'Help Center',\n icon: 'help',\n iconVariant: 'solid',\n },\n { label: 'Support', icon: 'headset', iconVariant: 'solid' },\n ],\n },\n },\n};\n"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "A customizable side navigation component for organizing primary navigation and content areas in an application. The component supports a `<slot>` for injecting custom content inside the side navigation panel.",
|
|
3
|
+
"properties": [
|
|
4
|
+
{
|
|
5
|
+
"name": "collapseOnClickOutside",
|
|
6
|
+
"type": "boolean",
|
|
7
|
+
"description": "Whether the side navigation should collapse when clicking outside of it.",
|
|
8
|
+
"default": "true",
|
|
9
|
+
"mutable": false,
|
|
10
|
+
"end_line": 32
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "customClass",
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Custom CSS class to apply to the inner div.",
|
|
16
|
+
"default": "''",
|
|
17
|
+
"mutable": false,
|
|
18
|
+
"end_line": 35
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "expanded",
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"description": "Whether the side navigation is expanded.",
|
|
24
|
+
"default": "false",
|
|
25
|
+
"mutable": true,
|
|
26
|
+
"end_line": 38
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "maxWidth",
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "Maximum width of the side navigation panel in an expanded state.",
|
|
32
|
+
"default": "'256px'",
|
|
33
|
+
"mutable": false,
|
|
34
|
+
"end_line": 41
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "mode",
|
|
38
|
+
"type": "'overlay' | 'push'",
|
|
39
|
+
"description": "Mode to make side navigation either overlay or push the content for the selector specified in targetContent",
|
|
40
|
+
"default": "'overlay'",
|
|
41
|
+
"mutable": false,
|
|
42
|
+
"end_line": 44
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "targetContent",
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "(optional) Specify the selector for the page's content for which paddings and margins will be set by side navigation based on the mode.",
|
|
48
|
+
"default": "''",
|
|
49
|
+
"mutable": false,
|
|
50
|
+
"end_line": 47
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"events": [
|
|
54
|
+
{
|
|
55
|
+
"name": "expandedChange",
|
|
56
|
+
"detail": "boolean",
|
|
57
|
+
"description": "Event emitted when the expanded state changes (expanded/collapsed).",
|
|
58
|
+
"end_line": 50
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"methods": [],
|
|
62
|
+
"slots": [
|
|
63
|
+
{
|
|
64
|
+
"name": "default",
|
|
65
|
+
"description": "Slot for default content"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"examples": {
|
|
69
|
+
"basic": "<style>\n .layout-with-navbar {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n .modus-wc-menu-item-labels {\n padding: 0 16px;\n }\n .navbar {\n box-shadow: none;\n }\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n .side-navigation {\n height: 500px;\n align-self: flex-start;\n position: relative;\n }\n </style>\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n >\n <modus-wc-menu size=\"lg\">\n <modus-wc-menu-item label=\"home\" selected>\n <modus-wc-icon slot=\"start-icon\" name=\"home\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"profile\">\n <modus-wc-icon slot=\"start-icon\" name=\"person\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"settings\">\n <modus-wc-icon slot=\"start-icon\" name=\"gears\"></modus-wc-icon>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <p>\n The side navigation of an application provides context through\n accessible menu options and positions a consistent component to\n connect to various pages in the application.\n </p>\n <p>\n The side navigation is a collapsible side content of the site’s\n pages. It is located alongside the page’s primary content. The\n component is designed to add side content to a fullscreen\n application. It is activated through the “hamburger” menu in the\n Navbar.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript.\n // const menuItems = document.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((item) => {\n // item.addEventListener('itemSelect', () => {\n // menuItems.forEach((i) => i.removeAttribute('selected'));\n // item.setAttribute('selected', '');\n // });\n // });\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // const userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // const navbar = document.querySelector('modus-wc-navbar');\n // const sideNav = document.querySelector('modus-wc-side-navigation');\n // navbar.visibility = visibility;\n // navbar.userCard = userCard;\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n </script>",
|
|
70
|
+
"variations": [],
|
|
71
|
+
"args": {
|
|
72
|
+
"collapse-on-click-outside": "true",
|
|
73
|
+
"expanded": "false",
|
|
74
|
+
"max-width": "'256px'",
|
|
75
|
+
"mode": "'push'",
|
|
76
|
+
"target-content": "'.panel-content'"
|
|
77
|
+
},
|
|
78
|
+
"argTypes": {},
|
|
79
|
+
"usage": [],
|
|
80
|
+
"events": [
|
|
81
|
+
"expandedChange",
|
|
82
|
+
"itemSelect"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"tag": "modus-wc-side-navigation",
|
|
86
|
+
"storyExample": {
|
|
87
|
+
"template": "<style>\n .layout-with-navbar {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n .modus-wc-menu-item-labels {\n padding: 0 16px;\n }\n .navbar {\n box-shadow: none;\n }\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n .side-navigation {\n height: 500px;\n align-self: flex-start;\n position: relative;\n }\n </style>\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n >\n <modus-wc-menu size=\"lg\">\n <modus-wc-menu-item label=\"home\" selected>\n <modus-wc-icon slot=\"start-icon\" name=\"home\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"profile\">\n <modus-wc-icon slot=\"start-icon\" name=\"person\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"settings\">\n <modus-wc-icon slot=\"start-icon\" name=\"gears\"></modus-wc-icon>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <p>\n The side navigation of an application provides context through\n accessible menu options and positions a consistent component to\n connect to various pages in the application.\n </p>\n <p>\n The side navigation is a collapsible side content of the site’s\n pages. It is located alongside the page’s primary content. The\n component is designed to add side content to a fullscreen\n application. It is activated through the “hamburger” menu in the\n Navbar.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript.\n // const menuItems = document.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((item) => {\n // item.addEventListener('itemSelect', () => {\n // menuItems.forEach((i) => i.removeAttribute('selected'));\n // item.setAttribute('selected', '');\n // });\n // });\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // const userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // const navbar = document.querySelector('modus-wc-navbar');\n // const sideNav = document.querySelector('modus-wc-side-navigation');\n // navbar.visibility = visibility;\n // navbar.userCard = userCard;\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n </script>",
|
|
88
|
+
"args": {
|
|
89
|
+
"collapse-on-click-outside": "true",
|
|
90
|
+
"expanded": "false",
|
|
91
|
+
"max-width": "'256px'",
|
|
92
|
+
"mode": "'push'",
|
|
93
|
+
"target-content": "'.panel-content'"
|
|
94
|
+
},
|
|
95
|
+
"argTypes": {},
|
|
96
|
+
"events": [
|
|
97
|
+
"expandedChange",
|
|
98
|
+
"itemSelect"
|
|
99
|
+
],
|
|
100
|
+
"fullContent": "import { withActions } from '@storybook/addon-actions/decorator';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\ninterface SideNavigationArgs {\n 'custom-class'?: string;\n expanded: boolean;\n 'max-width': string;\n 'collapse-on-click-outside'?: boolean;\n mode: 'overlay' | 'push';\n 'target-content'?: string;\n}\n\nconst meta: Meta<SideNavigationArgs> = {\n title: 'Components/Side Navigation',\n component: 'modus-wc-side-navigation',\n args: {\n 'collapse-on-click-outside': true,\n expanded: false,\n 'max-width': '256px',\n mode: 'push',\n 'target-content': '.panel-content',\n },\n argTypes: {\n 'max-width': {\n control: { type: 'text' },\n description:\n 'Maximum width of the side navigation panel in an expanded state.',\n },\n mode: {\n control: { type: 'select' },\n options: ['overlay', 'push'],\n description: 'Display mode of the side navigation (overlay or push).',\n },\n },\n decorators: [withActions],\n parameters: {\n layout: 'padded',\n actions: {\n handles: ['expandedChange', 'itemSelect'],\n },\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<SideNavigationArgs>;\n\nexport const Default: Story = {\n render: (args) => {\n const handleMenuOpenChange = (e: CustomEvent) => {\n const eventSource = e.target as HTMLElement;\n const storyContainer = eventSource?.closest('.layout-with-navbar');\n let sideNav: Element | null;\n\n if (storyContainer) {\n sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n } else {\n sideNav = document.querySelector('modus-wc-side-navigation');\n }\n\n if (sideNav) {\n (sideNav as HTMLElement & { expanded: boolean }).expanded = e.detail;\n }\n };\n\n return html`\n <style>\n .layout-with-navbar {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n .modus-wc-menu-item-labels {\n padding: 0 16px;\n }\n .navbar {\n box-shadow: none;\n }\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n .side-navigation {\n height: 500px;\n align-self: flex-start;\n position: relative;\n }\n </style>\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n >\n <modus-wc-menu size=\"lg\">\n <modus-wc-menu-item label=\"home\" selected>\n <modus-wc-icon slot=\"start-icon\" name=\"home\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"profile\">\n <modus-wc-icon slot=\"start-icon\" name=\"person\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"settings\">\n <modus-wc-icon slot=\"start-icon\" name=\"gears\"></modus-wc-icon>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <p>\n The side navigation of an application provides context through\n accessible menu options and positions a consistent component to\n connect to various pages in the application.\n </p>\n <p>\n The side navigation is a collapsible side content of the site’s\n pages. It is located alongside the page’s primary content. The\n component is designed to add side content to a fullscreen\n application. It is activated through the “hamburger” menu in the\n Navbar.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript.\n // const menuItems = document.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((item) => {\n // item.addEventListener('itemSelect', () => {\n // menuItems.forEach((i) => i.removeAttribute('selected'));\n // item.setAttribute('selected', '');\n // });\n // });\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // const userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // const navbar = document.querySelector('modus-wc-navbar');\n // const sideNav = document.querySelector('modus-wc-side-navigation');\n // navbar.visibility = visibility;\n // navbar.userCard = userCard;\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n </script>\n `;\n },\n};\n\nexport const WithSubmenu: Story = {\n render: (args) => {\n const handleMenuOpenChange = (e: CustomEvent) => {\n const eventSource = e.target as HTMLElement;\n const storyContainer = eventSource?.closest('.layout-with-navbar');\n let sideNav: HTMLElement | null;\n\n if (storyContainer) {\n sideNav = storyContainer.querySelector(\n 'modus-wc-side-navigation'\n ) as HTMLElement;\n\n if (sideNav) {\n // Toggle the side nav state (navbar and side nav can be out of sync)\n const sideNavEl = sideNav as HTMLElement & { expanded: boolean };\n sideNavEl.expanded = e.detail;\n }\n }\n };\n\n const handleExpandedChange = (e: CustomEvent) => {\n // Collapse all menu items when side nav closes\n if (!e.detail) {\n const eventSource = e.target as HTMLElement;\n const menuItems = eventSource.querySelectorAll('modus-wc-menu-item');\n menuItems.forEach((menuItem) => {\n const item = menuItem as unknown as {\n hasSubmenu?: boolean;\n collapseSubmenu?: () => Promise<void>;\n };\n if (item.hasSubmenu && typeof item.collapseSubmenu === 'function') {\n void item.collapseSubmenu();\n }\n });\n }\n };\n\n return html`\n <style>\n .layout-with-navbar {\n box-shadow: rgba(36, 35, 45, 0.3) 1px 0 4px;\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n\n .side-navigation {\n align-self: flex-start;\n height: 500px;\n position: relative;\n }\n .flex-right {\n float: right;\n display: flex;\n margin-left: 50px;\n }\n\n .flex-right:hover {\n background-color: unset;\n }\n .flex-right:active {\n background-color: unset !important;\n }\n </style>\n\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n id=\"main-navbar\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n id=\"main-side-nav\"\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n @expandedChange=${handleExpandedChange}\n >\n <modus-wc-menu>\n <li>\n <div class=\"flex-right\">\n <modus-wc-button custom-class=\"menu-icon\" color=\"tertiary\">\n <modus-wc-icon\n name=\"filter\"\n size=\"xs\"\n variant=\"solid\"\n ></modus-wc-icon>\n </modus-wc-button>\n <modus-wc-button custom-class=\"menu-icon\" color=\"tertiary\">\n <modus-wc-icon\n name=\"settings\"\n size=\"xs\"\n variant=\"solid\"\n ></modus-wc-icon>\n </modus-wc-button>\n <modus-wc-button custom-class=\"menu-icon\" color=\"tertiary\">\n <modus-wc-icon\n name=\"more_vertical\"\n size=\"xs\"\n variant=\"solid\"\n ></modus-wc-icon>\n </modus-wc-button>\n </div>\n </li>\n <modus-wc-menu-item\n label=\"Charts\"\n id=\"charts-menu\"\n .hasSubmenu=${true}\n value=\"charts\"\n >\n <modus-wc-icon\n slot=\"start-icon\"\n decorative=\"true\"\n name=\"bar_graph\"\n ></modus-wc-icon>\n <modus-wc-menu .isSubMenu=${true} id=\"charts-submenu\">\n <modus-wc-menu-item label=\"Bar Chart\" value=\"bar-chart\">\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"Line Chart\" value=\"line-chart\">\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-menu-item>\n\n <modus-wc-menu-item label=\"Calendar\" value=\"calendar\">\n <modus-wc-icon\n slot=\"start-icon\"\n decorative=\"true\"\n name=\"calendar\"\n ></modus-wc-icon>\n </modus-wc-menu-item>\n\n <modus-wc-menu-item\n label=\"Reports\"\n .hasSubmenu=${true}\n id=\"reports-menu\"\n value=\"reports\"\n >\n <modus-wc-icon\n slot=\"start-icon\"\n decorative=\"true\"\n name=\"master_data\"\n ></modus-wc-icon>\n <modus-wc-menu .isSubMenu=${true} id=\"reports-submenu\">\n <modus-wc-menu-item\n label=\"Monthly Report\"\n value=\"monthly-report\"\n >\n </modus-wc-menu-item>\n <modus-wc-menu-item\n label=\"Annual Report\"\n value=\"annual-report\"\n >\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <h3>Side Navigation with Submenu</h3>\n <p>\n This example demonstrates the side navigation component with\n submenus, allowing for a more organized and hierarchical\n navigation structure.\n </p>\n <p>\n When the side navigation closes, the expandedChange event is\n used to call the collapseSubmenu() method on each menu item.\n This keeps the side navigation component generic while allowing\n the story to coordinate behavior between components.\n </p>\n <p>\n Menu items inside a collapsed side nav cannot expand their\n submenus, ensuring a consistent user experience.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const handleExpandedChange = (e) => {\n // // Collapse all menu items when side nav closes\n // if (!e.detail) {\n // const eventSource = e.target;\n // const menuItems =\n // eventSource.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((menuItem) => {\n // if (\n // menuItem.hasSubmenu &&\n // typeof menuItem.collapseSubmenu === 'function'\n // ) {\n // menuItem.collapseSubmenu();\n // }\n // });\n // }\n // };\n // // Adding event listeners and setting properties here as the storybook initially does not load them\n // document.addEventListener('DOMContentLoaded', () => {\n // const navbar = document.querySelector('#main-navbar');\n // const sideNav = document.querySelector('#main-side-nav');\n // const chartsMenu = document.querySelector('#charts-menu');\n // const reportsMenu = document.querySelector('#reports-menu');\n // const chartsSubMenu = document.querySelector('#charts-submenu');\n // const reportsSubMenu = document.querySelector('#reports-submenu');\n\n // if (navbar) {\n // // Set navbar properties\n // navbar.userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // navbar.visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n // }\n\n // if (sideNav) {\n // sideNav.addEventListener('expandedChange', handleExpandedChange);\n // }\n\n // // Set hasSubmenu property for menu items with submenus\n // [chartsMenu, reportsMenu].forEach((menuItem) => {\n // if (menuItem) {\n // menuItem.hasSubmenu = true;\n // }\n // });\n\n // // Set isSubMenu for all submenu elements\n // [chartsSubMenu, reportsSubMenu].forEach((submenu) => {\n // if (submenu) {\n // submenu.isSubMenu = true;\n // }\n // });\n // });\n //\n </script>\n `;\n },\n};\n"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "",
|
|
3
|
+
"properties": [
|
|
4
|
+
{
|
|
5
|
+
"name": "editable",
|
|
6
|
+
"type": "boolean | ((row: Record<string, unknown>)",
|
|
7
|
+
"description": "Enable cell editing. Either a boolean (all rows) or a predicate per row.",
|
|
8
|
+
"default": "> boolean) = false",
|
|
9
|
+
"mutable": false,
|
|
10
|
+
"end_line": 94
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "columns",
|
|
14
|
+
"type": "ITableColumn[]",
|
|
15
|
+
"description": "An array of column definitions.",
|
|
16
|
+
"default": null,
|
|
17
|
+
"mutable": false,
|
|
18
|
+
"end_line": 97
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "customClass",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Custom CSS class to apply to the inner div.",
|
|
24
|
+
"default": "''",
|
|
25
|
+
"mutable": false,
|
|
26
|
+
"end_line": 100
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "data",
|
|
30
|
+
"type": "Record<string, unknown>[]",
|
|
31
|
+
"description": "An array of data objects.",
|
|
32
|
+
"default": null,
|
|
33
|
+
"mutable": false,
|
|
34
|
+
"end_line": 103
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "density",
|
|
38
|
+
"type": "Density",
|
|
39
|
+
"description": "The density of the table, used to save space or increase readability.",
|
|
40
|
+
"default": "'comfortable'",
|
|
41
|
+
"mutable": false,
|
|
42
|
+
"end_line": 106
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "hover",
|
|
46
|
+
"type": "boolean",
|
|
47
|
+
"description": "Enable hover effect on table rows.",
|
|
48
|
+
"default": "true",
|
|
49
|
+
"mutable": false,
|
|
50
|
+
"end_line": 109
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "currentPage",
|
|
54
|
+
"type": "number",
|
|
55
|
+
"description": "The current page number in pagination (1-based index).",
|
|
56
|
+
"default": "1",
|
|
57
|
+
"mutable": false,
|
|
58
|
+
"end_line": 112
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "paginated",
|
|
62
|
+
"type": "boolean",
|
|
63
|
+
"description": "Enable pagination for the table.",
|
|
64
|
+
"default": "false",
|
|
65
|
+
"mutable": false,
|
|
66
|
+
"end_line": 115
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "pageSizeOptions",
|
|
70
|
+
"type": "number[]",
|
|
71
|
+
"description": "Available options for the number of rows per page.",
|
|
72
|
+
"default": "[5, 10, 15]",
|
|
73
|
+
"mutable": false,
|
|
74
|
+
"end_line": 118
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "showPageSizeSelector",
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"description": "Show/hide the page size selector in pagination.",
|
|
80
|
+
"default": "true",
|
|
81
|
+
"mutable": false,
|
|
82
|
+
"end_line": 121
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "sortable",
|
|
86
|
+
"type": "boolean",
|
|
87
|
+
"description": "Enable sorting functionality for sortable columns.",
|
|
88
|
+
"default": "true",
|
|
89
|
+
"mutable": false,
|
|
90
|
+
"end_line": 124
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "selectable",
|
|
94
|
+
"type": "'none' | 'single' | 'multi'",
|
|
95
|
+
"description": "Row selection mode: 'none' for no selection, 'single' for single row, 'multi' for multiple rows.",
|
|
96
|
+
"default": "'none'",
|
|
97
|
+
"mutable": false,
|
|
98
|
+
"end_line": 127
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "selectedRowIds",
|
|
102
|
+
"type": "string[]",
|
|
103
|
+
"description": "Array of selected row IDs. Used for controlled selection state.",
|
|
104
|
+
"default": null,
|
|
105
|
+
"mutable": false,
|
|
106
|
+
"end_line": 130
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "zebra",
|
|
110
|
+
"type": "boolean",
|
|
111
|
+
"description": "Zebra striped tables differentiate rows by styling them in an alternating fashion.",
|
|
112
|
+
"default": "false",
|
|
113
|
+
"mutable": false,
|
|
114
|
+
"end_line": 133
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "caption",
|
|
118
|
+
"type": "string",
|
|
119
|
+
"description": "Accessibility caption for the table (visually hidden but available to screen readers).",
|
|
120
|
+
"default": null,
|
|
121
|
+
"mutable": false,
|
|
122
|
+
"end_line": 136
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"events": [
|
|
126
|
+
{
|
|
127
|
+
"name": "cellEditStart",
|
|
128
|
+
"detail": "{ rowIndex: number; colId: string; }",
|
|
129
|
+
"description": "Emits when cell editing starts.",
|
|
130
|
+
"end_line": 145
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "cellEditCommit",
|
|
134
|
+
"detail": "{ rowIndex: number; colId: string; newValue: unknown; updatedRow: Record<string, unknown",
|
|
135
|
+
"description": "Emits when cell editing is committed with the new value.",
|
|
136
|
+
"end_line": 152
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "rowClick",
|
|
140
|
+
"detail": "{ row: Record<string, unknown",
|
|
141
|
+
"description": "Emits when a row is clicked.",
|
|
142
|
+
"end_line": 169
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"name": "sortChange",
|
|
146
|
+
"detail": "SortingState",
|
|
147
|
+
"description": "Emits when sorting changes with the new sorting state.",
|
|
148
|
+
"end_line": 174
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "paginationChange",
|
|
152
|
+
"detail": "IPaginationChangeEventDetail",
|
|
153
|
+
"description": "Emits when pagination changes with the new pagination state.",
|
|
154
|
+
"end_line": 177
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "rowSelectionChange",
|
|
158
|
+
"detail": "{ selectedRows: Record<string, unknown",
|
|
159
|
+
"description": "Emits when row selection changes with the selected rows and their IDs.",
|
|
160
|
+
"end_line": 183
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"methods": [],
|
|
164
|
+
"slots": [],
|
|
165
|
+
"examples": {
|
|
166
|
+
"basic": "<modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n .caption=${args.caption}\n @rowClick=${action('rowClick')}\n @sortChange=${action('sortChange')}\n @paginationChange=${action('paginationChange')}\n @rowSelectionChange=${action('rowSelectionChange')}\n @cellEditStart=${action('cellEditStart')}\n @cellEditCommit=${action('cellEditCommit')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\",
|
|
167
|
+
"variations": [],
|
|
168
|
+
"args": {
|
|
169
|
+
"density": "'comfortable'",
|
|
170
|
+
"hover": "false",
|
|
171
|
+
"sortable": "true",
|
|
172
|
+
"paginated": "false",
|
|
173
|
+
"show-page-size-selector": "true",
|
|
174
|
+
"custom-class": "''",
|
|
175
|
+
"selectable": "'none'",
|
|
176
|
+
"zebra": "false",
|
|
177
|
+
"current-page": "1",
|
|
178
|
+
"editable": "false"
|
|
179
|
+
},
|
|
180
|
+
"argTypes": {},
|
|
181
|
+
"usage": []
|
|
182
|
+
},
|
|
183
|
+
"tag": "modus-wc-table",
|
|
184
|
+
"storyExample": {
|
|
185
|
+
"template": "<modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n .caption=${args.caption}\n @rowClick=${action('rowClick')}\n @sortChange=${action('sortChange')}\n @paginationChange=${action('paginationChange')}\n @rowSelectionChange=${action('rowSelectionChange')}\n @cellEditStart=${action('cellEditStart')}\n @cellEditCommit=${action('cellEditCommit')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\",
|
|
186
|
+
"args": {
|
|
187
|
+
"density": "'comfortable'",
|
|
188
|
+
"hover": "false",
|
|
189
|
+
"sortable": "true",
|
|
190
|
+
"paginated": "false",
|
|
191
|
+
"show-page-size-selector": "true",
|
|
192
|
+
"custom-class": "''",
|
|
193
|
+
"selectable": "'none'",
|
|
194
|
+
"zebra": "false",
|
|
195
|
+
"current-page": "1",
|
|
196
|
+
"editable": "false"
|
|
197
|
+
},
|
|
198
|
+
"argTypes": {},
|
|
199
|
+
"events": [],
|
|
200
|
+
"fullContent": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { action } from '@storybook/addon-actions';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ITableColumn } from './modus-wc-table';\nimport { IAutocompleteItem } from '../types';\nimport { Density } from '../types';\n\ninterface TableStoryArgs {\n 'custom-class'?: string;\n 'current-page'?: number;\n 'page-size-options'?: number[];\n 'selected-row-ids'?: string[];\n 'show-page-size-selector'?: boolean;\n caption?: string;\n columns?: ITableColumn[];\n data?: Record<string, unknown>[];\n density?: Density;\n editable?: boolean;\n hover?: boolean;\n paginated?: boolean;\n selectable?: 'none' | 'single' | 'multi';\n sortable?: boolean;\n zebra?: boolean;\n}\n\nconst meta: Meta<TableStoryArgs> = {\n title: 'Components/Table',\n component: 'modus-wc-table',\n\n argTypes: {\n columns: {\n control: 'object',\n description: 'An array of column definitions.',\n table: {\n type: {\n detail: `\n Interface: ITableColumn\n Properties:\n - accessor (string): Key to access data from row object\n - cellRenderer? (function): Custom cell renderer (value, row) => string | HTMLElement\n - className? (string): Class names for the column\n - header (string | HTMLElement): Header content\n - id (string): Unique identifier for the column\n - width? (string): Width style (e.g., '200px', '50%')\n - sortable? (boolean): Whether the column is sortable\n - editor? ('text' | 'number' | 'autocomplete' | 'date' | 'custom'): Built-in editor type\n - editorProps? (object): Extra props specific to the editor component\n - customEditorRenderer? (function): Custom renderer for 'custom' editor\n - editorTemplate? (string): Raw HTML string for editor, with \\`\\${value}\\` placeholder\n - editorSetup? (function): Runs after the editor element is added to the DOM\n `,\n },\n },\n },\n data: {\n control: 'object',\n description: 'An array of data objects.',\n table: {\n type: {\n detail: `\n Data should be an array of objects, where each object represents a row and each key matches a column accessor.\n\n Example:\n [\n { id: '1', name: 'Alice', email: 'alice@example.com', role: 'Admin' },\n { id: '2', name: 'Bob', email: 'bob@example.com', role: 'User' }\n ]\n\n - Each property in the object should correspond to a column's accessor value.\n - The 'id' property is recommended for row identification and selection.\n `,\n },\n },\n },\n density: {\n control: {\n type: 'select',\n },\n options: ['condensed', 'comfortable', 'relaxed'],\n description:\n 'The density of the table, used to save space or increase readability.',\n },\n hover: {\n control: 'boolean',\n description: 'Enable hover effect on table rows.',\n defaultValue: true,\n },\n sortable: {\n control: 'boolean',\n description: 'Enable sorting functionality for sortable columns.',\n defaultValue: true,\n },\n paginated: {\n control: 'boolean',\n description: 'Enable pagination for the table.',\n defaultValue: false,\n },\n 'show-page-size-selector': {\n control: 'boolean',\n description: 'Show/hide the page size selector in pagination.',\n defaultValue: true,\n },\n caption: {\n control: 'text',\n description:\n 'Accessibility caption for the table that is visually hidden but available to screen readers.',\n },\n 'custom-class': {\n control: 'text',\n description: 'Custom CSS class to apply to the inner div.',\n },\n selectable: {\n control: {\n type: 'select',\n },\n options: ['none', 'single', 'multi'],\n description:\n \"Row selection mode: 'none' for no selection, 'single' for single row, 'multi' for multiple rows.\",\n defaultValue: 'none',\n },\n zebra: {\n control: 'boolean',\n description:\n 'Zebra striped tables differentiate rows by styling them in an alternating fashion.',\n defaultValue: false,\n },\n 'current-page': {\n control: 'number',\n description: 'The current page number in pagination (1-based index).',\n defaultValue: 1,\n },\n 'page-size-options': {\n control: 'object',\n description: 'Available options for the number of rows per page.',\n defaultValue: [5, 10, 15],\n },\n 'selected-row-ids': {\n control: 'object',\n description:\n 'Array of selected row IDs. Used for controlled selection state.',\n defaultValue: [],\n },\n editable: {\n control: 'boolean',\n description:\n 'Enable cell editing. Either a boolean (all rows) or a predicate per row.',\n defaultValue: false,\n },\n },\n};\n\nexport default meta;\ntype Story = StoryObj<TableStoryArgs>;\n\n// Helper functions\nconst createDemoColumns = (): ITableColumn[] => [\n {\n id: 'id',\n header: 'ID',\n accessor: 'id',\n width: '60px',\n },\n {\n id: 'name',\n header: 'Name',\n accessor: 'name',\n width: '100px',\n },\n {\n id: 'email',\n header: 'Email',\n accessor: 'email',\n },\n {\n id: 'role',\n header: 'Role',\n accessor: 'role',\n },\n];\n\nconst createSortableColumns = (): ITableColumn[] => {\n const columns = createDemoColumns();\n return columns.map((col) => ({ ...col, sortable: true }));\n};\n\nconst createDemoData = (count = 5): Record<string, any>[] => {\n const data: Record<string, any>[] = [];\n for (let i = 1; i <= count; i++) {\n data.push({\n id: i.toString(),\n name: `User ${i}`,\n email: `user${i}@example.com`,\n role: i % 2 === 0 ? 'Admin' : 'User',\n });\n }\n return data;\n};\n\nexport const Default: Story = {\n render: (args) => {\n const columns = args.columns || createDemoColumns();\n const data = args.data || createDemoData();\n return html`\n <modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n .caption=${args.caption}\n @rowClick=${action('rowClick')}\n @sortChange=${action('sortChange')}\n @paginationChange=${action('paginationChange')}\n @rowSelectionChange=${action('rowSelectionChange')}\n @cellEditStart=${action('cellEditStart')}\n @cellEditCommit=${action('cellEditCommit')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\`User \\${i}\\`,\n // email: \\`user\\${i}@example.com\\`,\n // role: i % 2 === 0 ? 'Admin' : 'User',\n // });\n // }\n // return data;\n // };\n\n // const table = document.querySelector('modus-wc-table');\n // table.columns = createDemoColumns();\n // table.data = createDemoData();\n // table.hover = 'false';\n </script>\n `;\n },\n args: {\n density: 'comfortable',\n hover: false,\n sortable: true,\n paginated: false,\n 'show-page-size-selector': true,\n 'custom-class': '',\n selectable: 'none',\n zebra: false,\n 'current-page': 1,\n 'page-size-options': [5, 10, 15],\n 'selected-row-ids': [],\n editable: false,\n },\n};\n\nexport const Hover: Story = {\n render: (args) => {\n const columns = args.columns || createDemoColumns();\n const data = args.data || createDemoData();\n return html`\n <modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n @rowClick=${action('rowClick')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\`User \\${i}\\`,\n // email: \\`user\\${i}@example.com\\`,\n // role: i % 2 === 0 ? 'Admin' : 'User',\n // });\n // }\n // return data;\n // };\n // const table = document.querySelector('modus-wc-table');\n // table.columns = createDemoColumns();\n // table.data = createDemoData();\n </script>\n `;\n },\n args: {\n density: 'comfortable',\n hover: true,\n },\n};\n\nexport const Sorting: Story = {\n render: (args) => {\n const columns = args.columns || createSortableColumns();\n const data = args.data || createDemoData();\n return html`\n <modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n @sortChange=${action('sortChange')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createSortableColumns = () => {\n // const columns = createDemoColumns();\n // return columns.map((col) => ({ ...col, sortable: true }));\n // };\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\`User \\${i}\\`,\n // email: \\`user\\${i}@example.com\\`,\n // role: i % 2 === 0 ? 'Admin' : 'User',\n // });\n // }\n // return data;\n // };\n\n // const table = document.querySelector('modus-wc-table');\n // table.columns = createSortableColumns();\n // table.data = createDemoData();\n </script>\n `;\n },\n args: {\n density: 'comfortable',\n sortable: true,\n },\n};\n\nexport const Pagination: Story = {\n render: (args) => {\n const columns = args.columns || createDemoColumns();\n const data = args.data || createDemoData(15);\n return html`\n <modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n @paginationChange=${action('paginationChange')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\`User \\${i}\\`,\n // email: \\`user\\${i}@example.com\\`,\n // role: i % 2 === 0 ? 'Admin' : 'User',\n // });\n // }\n // return data;\n // };\n\n // const table = document.querySelector('modus-wc-table');\n // table.columns = createDemoColumns();\n // table.data = createDemoData(15);\n // table.paginated = true;\n </script>\n `;\n },\n args: {\n density: 'comfortable',\n paginated: true,\n 'show-page-size-selector': true,\n },\n};\n\nexport const CheckBoxRowSelection: Story = {\n render: (args) => {\n const columns = args.columns || createDemoColumns();\n const data = args.data || createDemoData();\n return html`\n <modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${args.editable}\n @rowSelectionChange=${action('rowSelectionChange')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const createDemoColumns = () => [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '60px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // width: '100px',\n // },\n // {\n // id: 'email',\n // header: 'Email',\n // accessor: 'email',\n // },\n // {\n // id: 'role',\n // header: 'Role',\n // accessor: 'role',\n // },\n // ];\n\n // const createDemoData = (count = 5) => {\n // const data = [];\n // for (let i = 1; i <= count; i++) {\n // data.push({\n // id: i.toString(),\n // name: \\`User \\${i}\\`,\n // email: \\`user\\${i}@example.com\\`,\n // role: i % 2 === 0 ? 'Admin' : 'User',\n // });\n // }\n // return data;\n // };\n\n // const table = document.querySelector('modus-wc-table');\n // table.columns = createDemoColumns();\n // table.data = createDemoData();\n // table.selectable = 'multi';\n </script>\n `;\n },\n args: {\n density: 'comfortable',\n selectable: 'multi',\n },\n};\n\nexport const InlineEditing: Story = {\n render: (args) => {\n const columns: ITableColumn[] = [\n {\n id: 'id',\n header: 'ID',\n accessor: 'id',\n width: '20px',\n },\n {\n id: 'name',\n header: 'Name',\n accessor: 'name',\n },\n {\n id: 'status',\n header: 'Status',\n accessor: 'status',\n editor: 'custom',\n customEditorRenderer: (value, onCommit) => {\n const container = document.createElement('div');\n container.style.width = '100%';\n\n const autocomplete = document.createElement('modus-wc-autocomplete');\n autocomplete.items = [\n { label: 'Active', value: 'Active', visibleInMenu: true },\n { label: 'Inactive', value: 'Inactive', visibleInMenu: true },\n { label: 'Pending', value: 'Pending', visibleInMenu: true },\n ];\n autocomplete.value = value as string;\n autocomplete.style.width = '100%';\n\n const handleItemSelect = (e: CustomEvent<IAutocompleteItem>) => {\n onCommit(e.detail.value);\n };\n\n autocomplete.addEventListener(\n 'itemSelect',\n handleItemSelect as EventListener\n );\n container.appendChild(autocomplete);\n\n setTimeout(() => {\n const input = autocomplete.querySelector('input');\n input?.focus();\n }, 0);\n\n return container;\n },\n cellRenderer: (value) => {\n const statusColors = {\n Active: 'green',\n Inactive: 'gray',\n Pending: 'blue',\n };\n const color = statusColors[value as string] || 'black';\n const span = document.createElement('span');\n span.textContent = value as string;\n span.style.color = color;\n span.style.fontWeight = 'bold';\n return span;\n },\n },\n {\n id: 'dueDate',\n header: 'Due Date',\n accessor: 'dueDate',\n editor: 'custom',\n customEditorRenderer: (value, onCommit) => {\n const container = document.createElement('div');\n container.style.width = '100%';\n\n const datePicker = document.createElement('modus-wc-date');\n datePicker.value = value as string;\n datePicker.style.width = '100%';\n datePicker.bordered = false;\n\n let isCommitting = false;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n const input = datePicker.querySelector('input');\n if (input && input.value && !isCommitting) {\n isCommitting = true;\n onCommit(input.value);\n }\n } else if (e.key === 'Escape') {\n e.preventDefault();\n if (!isCommitting) {\n isCommitting = true;\n onCommit(value || '');\n }\n } else if (e.key === 'Tab') {\n // Allow Tab to commit and move to next cell\n const input = datePicker.querySelector('input');\n if (input && input.value && !isCommitting) {\n isCommitting = true;\n onCommit(input.value);\n }\n }\n };\n\n // Only commit when focus leaves the entire container (not just the input)\n const handleContainerBlur = (e: FocusEvent) => {\n const relatedTarget = e.relatedTarget as HTMLElement;\n\n // If focus is moving within the container or date picker, don't commit\n if (\n relatedTarget &&\n (container.contains(relatedTarget) ||\n datePicker.shadowRoot?.contains(relatedTarget))\n ) {\n return;\n }\n\n const calendar = datePicker.shadowRoot?.querySelector(\n '[class*=\"calendar\"]'\n );\n if (calendar) {\n return;\n }\n\n const input = datePicker.querySelector('input');\n if (input && input.value && !isCommitting) {\n isCommitting = true;\n setTimeout(() => onCommit(input.value), 50);\n }\n };\n\n container.addEventListener('keydown', handleKeyDown);\n container.addEventListener('focusout', handleContainerBlur);\n container.appendChild(datePicker);\n\n setTimeout(() => {\n const input = datePicker.querySelector('input');\n input?.focus();\n }, 0);\n\n return container;\n },\n cellRenderer: (value): string => {\n if (!value) return '-';\n\n // Parse dd-mm-yyyy format from date picker\n const dateString = value as string;\n const parts = dateString.split(/[-/]/);\n\n let date: Date;\n if (parts.length === 3 && parts[0].length <= 2) {\n // Assume dd-mm-yyyy or dd/mm/yyyy format\n const day = parseInt(parts[0], 10);\n const month = parseInt(parts[1], 10) - 1; // Month is 0-indexed\n const year = parseInt(parts[2], 10);\n date = new Date(year, month, day);\n } else {\n // Fallback to default parsing\n date = new Date(dateString);\n }\n\n // Check if date is valid\n if (isNaN(date.getTime())) {\n return dateString; // Return original value if parsing fails\n }\n\n // Format date with dashes: dd-mm-yyyy\n const formattedDay = date.getDate().toString().padStart(2, '0');\n const formattedMonth = (date.getMonth() + 1)\n .toString()\n .padStart(2, '0');\n const formattedYear = date.getFullYear();\n\n return `${formattedDay}-${formattedMonth}-${formattedYear}`;\n },\n },\n ];\n\n const data = [\n {\n id: '1',\n name: 'John Doe',\n status: 'Active',\n dueDate: '15-10-2025',\n },\n {\n id: '2',\n name: 'Jane Smith',\n status: 'Inactive',\n dueDate: '20-11-2025',\n },\n {\n id: '3',\n name: 'Bob Johnson',\n status: 'Pending',\n dueDate: '05-12-2025',\n },\n ];\n\n return html`\n <modus-wc-table\n .columns=${columns}\n .data=${data}\n .density=${args.density}\n .hover=${args.hover}\n .sortable=${args.sortable}\n .paginated=${args.paginated}\n .showPageSizeSelector=${args['show-page-size-selector']}\n .customClass=${args['custom-class']}\n .selectable=${args.selectable}\n .zebra=${args.zebra}\n .currentPage=${args['current-page']}\n .pageSizeOptions=${args['page-size-options']}\n .selectedRowIds=${args['selected-row-ids']}\n .editable=${true}\n @cellEditStart=${action('cellEditStart')}\n @cellEditCommit=${action('cellEditCommit')}\n ></modus-wc-table>\n <script>\n // This script provides sample data and configuration for the modus-wc-table demonstration.\n // const columns = [\n // {\n // id: 'id',\n // header: 'ID',\n // accessor: 'id',\n // width: '20px',\n // },\n // {\n // id: 'name',\n // header: 'Name',\n // accessor: 'name',\n // editor: 'text',\n // },\n // {\n // id: 'status',\n // header: 'Status',\n // accessor: 'status',\n // editor: 'custom',\n // customEditorRenderer: (value, onCommit) => {\n // const container = document.createElement('div');\n // container.style.width = '100%';\n\n // const autocomplete = document.createElement('modus-wc-autocomplete');\n // autocomplete.items = [\n // { label: 'Active', value: 'Active', visibleInMenu: true },\n // { label: 'Inactive', value: 'Inactive', visibleInMenu: true },\n // { label: 'Pending', value: 'Pending', visibleInMenu: true },\n // ];\n // autocomplete.value = value;\n // autocomplete.style.width = '100%';\n\n // const handleItemSelect = (e) => {\n // onCommit(e.detail.value);\n // };\n\n // autocomplete.addEventListener(\n // 'itemSelect',\n // handleItemSelect\n // );\n // container.appendChild(autocomplete);\n\n // setTimeout(() => {\n // const input = autocomplete.querySelector('input');\n // input?.focus();\n // }, 0);\n\n // return container;\n // },\n // cellRenderer: (value) => {\n // const statusColors = {\n // Active: 'green',\n // Inactive: 'gray',\n // Pending: 'blue',\n // };\n // const color = statusColors[value] || 'black';\n // const span = document.createElement('span');\n // span.textContent = value;\n // span.style.color = color;\n // span.style.fontWeight = 'bold';\n // return span;\n // },\n // },\n // {\n // id: 'dueDate',\n // header: 'Due Date',\n // accessor: 'dueDate',\n // editor: 'custom',\n // customEditorRenderer: (value, onCommit) => {\n // const container = document.createElement('div');\n // container.style.width = '100%';\n\n // const datePicker = document.createElement('modus-wc-date');\n // datePicker.value = value;\n // datePicker.style.width = '100%';\n // datePicker.bordered = false;\n\n // let isCommitting = false;\n\n // const handleKeyDown = (e) => {\n // if (e.key === 'Enter') {\n // e.preventDefault();\n // const input = datePicker.querySelector('input');\n // if (input && input.value && !isCommitting) {\n // isCommitting = true;\n // onCommit(input.value);\n // }\n // } else if (e.key === 'Escape') {\n // e.preventDefault();\n // if (!isCommitting) {\n // isCommitting = true;\n // onCommit(value || '');\n // }\n // } else if (e.key === 'Tab') {\n // const input = datePicker.querySelector('input');\n // if (input && input.value && !isCommitting) {\n // isCommitting = true;\n // onCommit(input.value);\n // }\n // }\n // };\n\n // const handleContainerBlur = (e) => {\n // const relatedTarget = e.relatedTarget;\n\n // if (relatedTarget && (container.contains(relatedTarget) || datePicker.shadowRoot?.contains(relatedTarget))) {\n // return;\n // }\n\n // const calendar = datePicker.shadowRoot?.querySelector('[class*=\"calendar\"]');\n // if (calendar) {\n // return;\n // }\n\n // const input = datePicker.querySelector('input');\n // if (input && input.value && !isCommitting) {\n // isCommitting = true;\n // setTimeout(() => onCommit(input.value), 50);\n // }\n // };\n\n // container.addEventListener('keydown', handleKeyDown);\n // container.addEventListener('focusout', handleContainerBlur);\n // container.appendChild(datePicker);\n\n // setTimeout(() => {\n // const input = datePicker.querySelector('input');\n // input?.focus();\n // }, 0);\n\n // return container;\n // },\n // cellRenderer: (value) => {\n // if (!value) return '-';\n\n // // Parse dd-mm-yyyy format from date picker\n // const dateString = value;\n // const parts = dateString.split(/[-/]/);\n\n // let date;\n // if (parts.length === 3 && parts[0].length <= 2) {\n // // Assume dd-mm-yyyy or dd/mm/yyyy format\n // const day = parseInt(parts[0], 10);\n // const month = parseInt(parts[1], 10) - 1; // Month is 0-indexed\n // const year = parseInt(parts[2], 10);\n // date = new Date(year, month, day);\n // } else {\n // // Fallback to default parsing\n // date = new Date(dateString);\n // }\n\n // // Check if date is valid\n // if (isNaN(date.getTime())) {\n // return dateString; // Return original value if parsing fails\n // }\n\n // // Format date with dashes: dd-mm-yyyy\n // const formattedDay = date.getDate().toString().padStart(2, '0');\n // const formattedMonth = (date.getMonth() + 1).toString().padStart(2, '0');\n // const formattedYear = date.getFullYear();\n\n // return \\`\\${formattedDay}-\\${formattedMonth}-\\${formattedYear}\\`;\n // },\n // },\n // ];\n\n // const data = [\n // {\n // id: '1',\n // name: 'John Doe',\n // status: 'Active',\n // dueDate: '15-10-2025',\n // },\n // {\n // id: '2',\n // name: 'Jane Smith',\n // status: 'Inactive',\n // dueDate: '20-11-2025',\n // },\n // {\n // id: '3',\n // name: 'Bob Johnson',\n // status: 'Pending',\n // dueDate: '05-12-2025',\n // },\n // ];\n // const table = document.querySelector('modus-wc-table');\n // table.columns = columns;\n // table.data = data;\n // table.editable = true;\n </script>\n `;\n },\n args: {\n density: 'comfortable',\n hover: false,\n sortable: true,\n paginated: false,\n 'show-page-size-selector': true,\n 'custom-class': '',\n selectable: 'none',\n zebra: false,\n 'current-page': 1,\n 'page-size-options': [5, 10, 15],\n 'selected-row-ids': [],\n },\n};\n"
|
|
201
|
+
}
|
|
202
|
+
}
|