@shadng/sng-ui 1.0.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/LICENSE +21 -0
- package/README.md +75 -0
- package/cli/sng-ui.js +331 -0
- package/ng-package.json +29 -0
- package/package.json +64 -0
- package/registry.json +72 -0
- package/src/lib/accordion/cn.ts +6 -0
- package/src/lib/accordion/index.ts +18 -0
- package/src/lib/accordion/sng-accordion-content.ts +131 -0
- package/src/lib/accordion/sng-accordion-item.ts +299 -0
- package/src/lib/accordion/sng-accordion-trigger.ts +137 -0
- package/src/lib/accordion/sng-accordion.ts +118 -0
- package/src/lib/accordion/sng-accordion.types.ts +82 -0
- package/src/lib/alert/cn.ts +6 -0
- package/src/lib/alert/index.ts +3 -0
- package/src/lib/alert/sng-alert-description.ts +49 -0
- package/src/lib/alert/sng-alert-title.ts +46 -0
- package/src/lib/alert/sng-alert.ts +48 -0
- package/src/lib/avatar/cn.ts +6 -0
- package/src/lib/avatar/index.ts +3 -0
- package/src/lib/avatar/sng-avatar-fallback.ts +50 -0
- package/src/lib/avatar/sng-avatar-image.ts +73 -0
- package/src/lib/avatar/sng-avatar.ts +60 -0
- package/src/lib/badge/cn.ts +6 -0
- package/src/lib/badge/index.ts +1 -0
- package/src/lib/badge/sng-badge.ts +36 -0
- package/src/lib/breadcrumb/cn.ts +6 -0
- package/src/lib/breadcrumb/index.ts +7 -0
- package/src/lib/breadcrumb/sng-breadcrumb-ellipsis.ts +61 -0
- package/src/lib/breadcrumb/sng-breadcrumb-item.ts +47 -0
- package/src/lib/breadcrumb/sng-breadcrumb-link.ts +43 -0
- package/src/lib/breadcrumb/sng-breadcrumb-list.ts +42 -0
- package/src/lib/breadcrumb/sng-breadcrumb-page.ts +44 -0
- package/src/lib/breadcrumb/sng-breadcrumb-separator.ts +60 -0
- package/src/lib/breadcrumb/sng-breadcrumb.ts +52 -0
- package/src/lib/button/cn.ts +6 -0
- package/src/lib/button/index.ts +2 -0
- package/src/lib/button/sng-button.ts +264 -0
- package/src/lib/calendar/cn.ts +6 -0
- package/src/lib/calendar/index.ts +2 -0
- package/src/lib/calendar/sng-calendar.ts +753 -0
- package/src/lib/card/cn.ts +6 -0
- package/src/lib/card/index.ts +6 -0
- package/src/lib/card/sng-card-content.ts +36 -0
- package/src/lib/card/sng-card-description.ts +38 -0
- package/src/lib/card/sng-card-footer.ts +34 -0
- package/src/lib/card/sng-card-header.ts +34 -0
- package/src/lib/card/sng-card-title.ts +48 -0
- package/src/lib/card/sng-card.ts +43 -0
- package/src/lib/carousel/cn.ts +6 -0
- package/src/lib/carousel/index.ts +18 -0
- package/src/lib/carousel/sng-carousel.ts +526 -0
- package/src/lib/checkbox/cn.ts +6 -0
- package/src/lib/checkbox/index.ts +1 -0
- package/src/lib/checkbox/sng-checkbox.ts +154 -0
- package/src/lib/code-block/cn.ts +6 -0
- package/src/lib/code-block/index.ts +1 -0
- package/src/lib/code-block/sng-code-block.ts +296 -0
- package/src/lib/dialog/cn.ts +6 -0
- package/src/lib/dialog/index.ts +37 -0
- package/src/lib/dialog/sng-dialog-close.ts +76 -0
- package/src/lib/dialog/sng-dialog-content.ts +132 -0
- package/src/lib/dialog/sng-dialog-description.ts +36 -0
- package/src/lib/dialog/sng-dialog-footer.ts +39 -0
- package/src/lib/dialog/sng-dialog-header.ts +39 -0
- package/src/lib/dialog/sng-dialog-title.ts +52 -0
- package/src/lib/dialog/sng-dialog.service.ts +222 -0
- package/src/lib/dialog/sng-dialog.ts +224 -0
- package/src/lib/drawer/cn.ts +6 -0
- package/src/lib/drawer/index.ts +36 -0
- package/src/lib/drawer/sng-drawer-close.ts +28 -0
- package/src/lib/drawer/sng-drawer-content.ts +135 -0
- package/src/lib/drawer/sng-drawer-description.ts +29 -0
- package/src/lib/drawer/sng-drawer-footer.ts +34 -0
- package/src/lib/drawer/sng-drawer-handle.ts +30 -0
- package/src/lib/drawer/sng-drawer-header.ts +30 -0
- package/src/lib/drawer/sng-drawer-title.ts +27 -0
- package/src/lib/drawer/sng-drawer-trigger.ts +21 -0
- package/src/lib/drawer/sng-drawer-wrapper.ts +27 -0
- package/src/lib/drawer/sng-drawer.ts +166 -0
- package/src/lib/file-input/cn.ts +6 -0
- package/src/lib/file-input/index.ts +1 -0
- package/src/lib/file-input/sng-file-input.ts +288 -0
- package/src/lib/hover-card/cn.ts +6 -0
- package/src/lib/hover-card/index.ts +3 -0
- package/src/lib/hover-card/sng-hover-card-content.ts +100 -0
- package/src/lib/hover-card/sng-hover-card-trigger.ts +43 -0
- package/src/lib/hover-card/sng-hover-card.ts +246 -0
- package/src/lib/input/cn.ts +6 -0
- package/src/lib/input/index.ts +1 -0
- package/src/lib/input/sng-input.ts +160 -0
- package/src/lib/layout/cn.ts +6 -0
- package/src/lib/layout/index.ts +98 -0
- package/src/lib/layout/sng-layout-footer.ts +37 -0
- package/src/lib/layout/sng-layout-header.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-content.ts +149 -0
- package/src/lib/layout/sng-layout-sidebar-footer.ts +54 -0
- package/src/lib/layout/sng-layout-sidebar-group-action.ts +67 -0
- package/src/lib/layout/sng-layout-sidebar-group-content.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-group-label.ts +53 -0
- package/src/lib/layout/sng-layout-sidebar-group.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-header.ts +54 -0
- package/src/lib/layout/sng-layout-sidebar-input.ts +112 -0
- package/src/lib/layout/sng-layout-sidebar-inset.ts +45 -0
- package/src/lib/layout/sng-layout-sidebar-menu-action.ts +84 -0
- package/src/lib/layout/sng-layout-sidebar-menu-badge.ts +47 -0
- package/src/lib/layout/sng-layout-sidebar-menu-button.ts +160 -0
- package/src/lib/layout/sng-layout-sidebar-menu-item.ts +40 -0
- package/src/lib/layout/sng-layout-sidebar-menu-skeleton.ts +71 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub-button.ts +142 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub-item.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub.ts +48 -0
- package/src/lib/layout/sng-layout-sidebar-menu.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-provider.ts +189 -0
- package/src/lib/layout/sng-layout-sidebar-rail.ts +60 -0
- package/src/lib/layout/sng-layout-sidebar-separator.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-trigger.ts +97 -0
- package/src/lib/layout/sng-layout-sidebar.ts +254 -0
- package/src/lib/menu/cn.ts +6 -0
- package/src/lib/menu/index.ts +21 -0
- package/src/lib/menu/sng-context-trigger.ts +128 -0
- package/src/lib/menu/sng-menu-checkbox-item.ts +91 -0
- package/src/lib/menu/sng-menu-item.ts +80 -0
- package/src/lib/menu/sng-menu-label.ts +47 -0
- package/src/lib/menu/sng-menu-radio-group.ts +38 -0
- package/src/lib/menu/sng-menu-radio-item.ts +94 -0
- package/src/lib/menu/sng-menu-separator.ts +27 -0
- package/src/lib/menu/sng-menu-shortcut.ts +25 -0
- package/src/lib/menu/sng-menu-sub-content.ts +267 -0
- package/src/lib/menu/sng-menu-sub-trigger.ts +68 -0
- package/src/lib/menu/sng-menu-sub.ts +124 -0
- package/src/lib/menu/sng-menu-tokens.ts +52 -0
- package/src/lib/menu/sng-menu-trigger.ts +266 -0
- package/src/lib/menu/sng-menu.ts +100 -0
- package/src/lib/nav-menu/cn.ts +6 -0
- package/src/lib/nav-menu/index.ts +6 -0
- package/src/lib/nav-menu/sng-nav-menu-content.ts +72 -0
- package/src/lib/nav-menu/sng-nav-menu-item.ts +109 -0
- package/src/lib/nav-menu/sng-nav-menu-link.ts +54 -0
- package/src/lib/nav-menu/sng-nav-menu-list.ts +43 -0
- package/src/lib/nav-menu/sng-nav-menu-trigger.ts +98 -0
- package/src/lib/nav-menu/sng-nav-menu.ts +99 -0
- package/src/lib/otp-input/cn.ts +6 -0
- package/src/lib/otp-input/index.ts +14 -0
- package/src/lib/otp-input/sng-otp-input-group.ts +38 -0
- package/src/lib/otp-input/sng-otp-input-separator.ts +43 -0
- package/src/lib/otp-input/sng-otp-input-slot.ts +128 -0
- package/src/lib/otp-input/sng-otp-input-tokens.ts +20 -0
- package/src/lib/otp-input/sng-otp-input.ts +301 -0
- package/src/lib/popover/cn.ts +6 -0
- package/src/lib/popover/index.ts +3 -0
- package/src/lib/popover/sng-popover-content.ts +66 -0
- package/src/lib/popover/sng-popover-trigger.ts +44 -0
- package/src/lib/popover/sng-popover.ts +218 -0
- package/src/lib/preview-box/cn.ts +6 -0
- package/src/lib/preview-box/index.ts +5 -0
- package/src/lib/preview-box/sng-code-block.ts +80 -0
- package/src/lib/preview-box/sng-html-block.ts +79 -0
- package/src/lib/preview-box/sng-preview-block.ts +47 -0
- package/src/lib/preview-box/sng-preview-box.ts +369 -0
- package/src/lib/preview-box/sng-style-block.ts +80 -0
- package/src/lib/progress/cn.ts +6 -0
- package/src/lib/progress/index.ts +1 -0
- package/src/lib/progress/sng-progress.ts +65 -0
- package/src/lib/radio/cn.ts +6 -0
- package/src/lib/radio/index.ts +5 -0
- package/src/lib/radio/sng-radio-item.ts +100 -0
- package/src/lib/radio/sng-radio.ts +54 -0
- package/src/lib/resizable/cn.ts +6 -0
- package/src/lib/resizable/index.ts +3 -0
- package/src/lib/resizable/sng-resizable-group.ts +188 -0
- package/src/lib/resizable/sng-resizable-handle.ts +236 -0
- package/src/lib/resizable/sng-resizable-panel.ts +71 -0
- package/src/lib/search-input/cn.ts +6 -0
- package/src/lib/search-input/index.ts +16 -0
- package/src/lib/search-input/sng-search-input-context.ts +24 -0
- package/src/lib/search-input/sng-search-input-empty.ts +42 -0
- package/src/lib/search-input/sng-search-input-group.ts +69 -0
- package/src/lib/search-input/sng-search-input-item.ts +164 -0
- package/src/lib/search-input/sng-search-input-list.ts +34 -0
- package/src/lib/search-input/sng-search-input-separator.ts +32 -0
- package/src/lib/search-input/sng-search-input-shortcut.ts +29 -0
- package/src/lib/search-input/sng-search-input.ts +368 -0
- package/src/lib/select/cn.ts +6 -0
- package/src/lib/select/index.ts +7 -0
- package/src/lib/select/sng-select-content.ts +27 -0
- package/src/lib/select/sng-select-empty.ts +48 -0
- package/src/lib/select/sng-select-group.ts +29 -0
- package/src/lib/select/sng-select-item.ts +140 -0
- package/src/lib/select/sng-select-label.ts +29 -0
- package/src/lib/select/sng-select-separator.ts +29 -0
- package/src/lib/select/sng-select.ts +326 -0
- package/src/lib/separator/cn.ts +6 -0
- package/src/lib/separator/index.ts +1 -0
- package/src/lib/separator/sng-separator.ts +40 -0
- package/src/lib/skeleton/cn.ts +6 -0
- package/src/lib/skeleton/index.ts +1 -0
- package/src/lib/skeleton/sng-skeleton.ts +49 -0
- package/src/lib/slider/cn.ts +6 -0
- package/src/lib/slider/index.ts +2 -0
- package/src/lib/slider/sng-slider.ts +137 -0
- package/src/lib/sng-table/cn.ts +6 -0
- package/src/lib/sng-table/flex-render.ts +222 -0
- package/src/lib/sng-table/index.ts +85 -0
- package/src/lib/sng-table/sng-table-body.ts +59 -0
- package/src/lib/sng-table/sng-table-caption.ts +49 -0
- package/src/lib/sng-table/sng-table-cell.ts +62 -0
- package/src/lib/sng-table/sng-table-footer.ts +60 -0
- package/src/lib/sng-table/sng-table-head.ts +66 -0
- package/src/lib/sng-table/sng-table-header.ts +48 -0
- package/src/lib/sng-table/sng-table-pagination.ts +265 -0
- package/src/lib/sng-table/sng-table-row.ts +65 -0
- package/src/lib/sng-table/sng-table.ts +67 -0
- package/src/lib/sng-table-core/core/create-cell.ts +117 -0
- package/src/lib/sng-table-core/core/create-column.ts +266 -0
- package/src/lib/sng-table-core/core/create-header.ts +271 -0
- package/src/lib/sng-table-core/core/create-row.ts +293 -0
- package/src/lib/sng-table-core/core/create-table.ts +534 -0
- package/src/lib/sng-table-core/core/types.ts +1197 -0
- package/src/lib/sng-table-core/core/utils.ts +307 -0
- package/src/lib/sng-table-core/features/column-filtering.ts +376 -0
- package/src/lib/sng-table-core/features/column-ordering.ts +159 -0
- package/src/lib/sng-table-core/features/column-pinning.ts +219 -0
- package/src/lib/sng-table-core/features/column-sizing.ts +268 -0
- package/src/lib/sng-table-core/features/column-visibility.ts +128 -0
- package/src/lib/sng-table-core/features/faceting.ts +279 -0
- package/src/lib/sng-table-core/features/fuzzy-filtering.ts +188 -0
- package/src/lib/sng-table-core/features/global-filtering.ts +128 -0
- package/src/lib/sng-table-core/features/pagination.ts +179 -0
- package/src/lib/sng-table-core/features/row-expanding.ts +181 -0
- package/src/lib/sng-table-core/features/row-grouping.ts +235 -0
- package/src/lib/sng-table-core/features/row-pinning.ts +196 -0
- package/src/lib/sng-table-core/features/row-selection.ts +298 -0
- package/src/lib/sng-table-core/features/sorting.ts +425 -0
- package/src/lib/sng-table-core/features/virtualization.ts +298 -0
- package/src/lib/sng-table-core/index.ts +235 -0
- package/src/lib/sng-table-core/row-models/core-row-model.ts +256 -0
- package/src/lib/sng-table-core/row-models/expanded-row-model.ts +175 -0
- package/src/lib/sng-table-core/row-models/filtered-row-model.ts +307 -0
- package/src/lib/sng-table-core/row-models/grouped-row-model.ts +290 -0
- package/src/lib/sng-table-core/row-models/paginated-row-model.ts +135 -0
- package/src/lib/sng-table-core/row-models/sorted-row-model.ts +197 -0
- package/src/lib/styles/sng-themes.css +164 -0
- package/src/lib/switch/cn.ts +6 -0
- package/src/lib/switch/index.ts +1 -0
- package/src/lib/switch/sng-switch.ts +137 -0
- package/src/lib/tabs/cn.ts +6 -0
- package/src/lib/tabs/index.ts +4 -0
- package/src/lib/tabs/sng-tabs-content.ts +66 -0
- package/src/lib/tabs/sng-tabs-list.ts +55 -0
- package/src/lib/tabs/sng-tabs-trigger.ts +86 -0
- package/src/lib/tabs/sng-tabs.ts +83 -0
- package/src/lib/toast/cn.ts +6 -0
- package/src/lib/toast/index.ts +3 -0
- package/src/lib/toast/sng-toast.service.ts +258 -0
- package/src/lib/toast/sng-toast.ts +101 -0
- package/src/lib/toast/sng-toaster.ts +67 -0
- package/src/lib/toggle/cn.ts +6 -0
- package/src/lib/toggle/index.ts +6 -0
- package/src/lib/toggle/sng-toggle-group-item.ts +89 -0
- package/src/lib/toggle/sng-toggle-group.ts +85 -0
- package/src/lib/toggle/sng-toggle.ts +78 -0
- package/src/lib/toggle-group/index.ts +6 -0
- package/src/lib/tooltip/cn.ts +6 -0
- package/src/lib/tooltip/index.ts +5 -0
- package/src/lib/tooltip/sng-tooltip-content.ts +64 -0
- package/src/lib/tooltip/sng-tooltip.ts +216 -0
- package/src/public-api.ts +207 -0
- package/tsconfig.json +24 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +11 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ShadNG Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# sng-ui
|
|
2
|
+
|
|
3
|
+
Native Angular UI components inspired by shadcn/ui Figma designs.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package//sng-ui)
|
|
6
|
+
[](https://angular.dev)
|
|
7
|
+
[](https://tailwindcss.com)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install sng-ui
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Peer dependencies:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"@angular/common": "^21.0.0",
|
|
21
|
+
"@angular/core": "^21.0.0",
|
|
22
|
+
"@angular/platform-browser": "^21.0.0",
|
|
23
|
+
"shiki": "^3.0.0"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`shiki` is optional and only needed for `code-block` / `preview-box`.
|
|
28
|
+
|
|
29
|
+
## CLI (Copy-Paste Model)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx sng-ui init
|
|
33
|
+
npx sng-ui add button
|
|
34
|
+
npx sng-ui add table menu
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The CLI copies editable component source into your app.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { Component } from '@angular/core';
|
|
43
|
+
import { SngButton } from 'sng-ui';
|
|
44
|
+
|
|
45
|
+
@Component({
|
|
46
|
+
selector: 'app-example',
|
|
47
|
+
imports: [SngButton],
|
|
48
|
+
template: `
|
|
49
|
+
<sng-button class="bg-primary text-primary-foreground shadow-xs hover:bg-primary/90">
|
|
50
|
+
Click me
|
|
51
|
+
</sng-button>
|
|
52
|
+
`,
|
|
53
|
+
})
|
|
54
|
+
export class ExampleComponent {}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Theming
|
|
58
|
+
|
|
59
|
+
Theme tokens are defined in `src/lib/styles/sng-themes.css`.
|
|
60
|
+
|
|
61
|
+
## Package Checks
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm run test:cli
|
|
65
|
+
npm run pack:check
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Notes Before First Public Release
|
|
69
|
+
|
|
70
|
+
- Update `repository`, `homepage`, and `bugs.url` in `package.json` to your final GitHub repository.
|
|
71
|
+
- Keep tests and Storybook stories in this repo for contributors; npm publish excludes test/story artifacts via `.npmignore`.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
MIT
|
package/cli/sng-ui.js
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const CONFIG_FILE = 'sng-ui.json';
|
|
7
|
+
const DEFAULT_COMPONENTS_DIR = 'src/lib/sng-ui';
|
|
8
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
9
|
+
const LIB_SOURCE_ROOT = path.join(PACKAGE_ROOT, 'src', 'lib');
|
|
10
|
+
|
|
11
|
+
const ALWAYS_AVAILABLE_IMPORTS = new Set([
|
|
12
|
+
'@angular/animations',
|
|
13
|
+
'@angular/common',
|
|
14
|
+
'@angular/core',
|
|
15
|
+
'@angular/forms',
|
|
16
|
+
'@angular/platform-browser',
|
|
17
|
+
'@angular/router',
|
|
18
|
+
'rxjs',
|
|
19
|
+
'tslib'
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
function printHelp() {
|
|
23
|
+
console.log(`sng-ui CLI
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
npx sng-ui init [--path <dir>] [--force]
|
|
27
|
+
npx sng-ui add <component...> [--path <dir>] [--force] [--dry-run]
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
npx sng-ui init
|
|
31
|
+
npx sng-ui add button
|
|
32
|
+
npx sng-ui add table menu
|
|
33
|
+
npx sng-ui add slider --path src/lib/ui
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function parseOptions(tokens) {
|
|
38
|
+
const options = { force: false, dryRun: false, path: null, values: [] };
|
|
39
|
+
|
|
40
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
41
|
+
const token = tokens[index];
|
|
42
|
+
if (token === '--force') {
|
|
43
|
+
options.force = true;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (token === '--dry-run') {
|
|
47
|
+
options.dryRun = true;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (token === '--path') {
|
|
51
|
+
const next = tokens[index + 1];
|
|
52
|
+
if (!next || next.startsWith('--')) {
|
|
53
|
+
throw new Error('Missing value for --path.');
|
|
54
|
+
}
|
|
55
|
+
options.path = next;
|
|
56
|
+
index += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
options.values.push(token);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return options;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readConfig(cwd) {
|
|
66
|
+
const configPath = path.join(cwd, CONFIG_FILE);
|
|
67
|
+
if (!fs.existsSync(configPath)) {
|
|
68
|
+
return { componentsDir: DEFAULT_COMPONENTS_DIR };
|
|
69
|
+
}
|
|
70
|
+
const raw = fs.readFileSync(configPath, 'utf8');
|
|
71
|
+
const parsed = JSON.parse(raw);
|
|
72
|
+
return {
|
|
73
|
+
componentsDir: typeof parsed.componentsDir === 'string' && parsed.componentsDir.trim()
|
|
74
|
+
? parsed.componentsDir
|
|
75
|
+
: DEFAULT_COMPONENTS_DIR
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function writeConfig(cwd, componentsDir, force) {
|
|
80
|
+
const configPath = path.join(cwd, CONFIG_FILE);
|
|
81
|
+
if (fs.existsSync(configPath) && !force) {
|
|
82
|
+
throw new Error(`Config already exists at ${CONFIG_FILE}. Use --force to overwrite.`);
|
|
83
|
+
}
|
|
84
|
+
const payload = {
|
|
85
|
+
componentsDir
|
|
86
|
+
};
|
|
87
|
+
fs.writeFileSync(configPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
88
|
+
fs.mkdirSync(path.resolve(cwd, componentsDir), { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getComponentFolderMap() {
|
|
92
|
+
const entries = fs.readdirSync(LIB_SOURCE_ROOT, { withFileTypes: true })
|
|
93
|
+
.filter((entry) => entry.isDirectory())
|
|
94
|
+
.map((entry) => entry.name)
|
|
95
|
+
.filter((name) => name !== 'styles');
|
|
96
|
+
|
|
97
|
+
const map = new Map();
|
|
98
|
+
for (const folder of entries) {
|
|
99
|
+
map.set(folder, folder);
|
|
100
|
+
if (folder.startsWith('sng-')) {
|
|
101
|
+
map.set(folder.slice(4), folder);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return map;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function resolveComponentFolder(componentName, folderMap) {
|
|
108
|
+
return folderMap.get(componentName) || null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function shouldSkipFile(filePath) {
|
|
112
|
+
return filePath.endsWith('.spec.ts') || filePath.endsWith('.stories.ts');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function listFilesRecursively(directoryPath) {
|
|
116
|
+
const files = [];
|
|
117
|
+
const stack = [directoryPath];
|
|
118
|
+
|
|
119
|
+
while (stack.length) {
|
|
120
|
+
const current = stack.pop();
|
|
121
|
+
const entries = fs.readdirSync(current, { withFileTypes: true });
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
const fullPath = path.join(current, entry.name);
|
|
124
|
+
if (entry.isDirectory()) {
|
|
125
|
+
stack.push(fullPath);
|
|
126
|
+
} else if (!shouldSkipFile(fullPath)) {
|
|
127
|
+
files.push(fullPath);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return files;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function resolveImportFile(fromFile, importPath) {
|
|
136
|
+
const fromDirectory = path.dirname(fromFile);
|
|
137
|
+
const base = path.resolve(fromDirectory, importPath);
|
|
138
|
+
const candidates = [
|
|
139
|
+
base,
|
|
140
|
+
`${base}.ts`,
|
|
141
|
+
`${base}.js`,
|
|
142
|
+
path.join(base, 'index.ts'),
|
|
143
|
+
path.join(base, 'index.js')
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
for (const candidate of candidates) {
|
|
147
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
148
|
+
return candidate;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function extractImports(filePath) {
|
|
155
|
+
const content = fs.readFileSync(filePath, 'utf8')
|
|
156
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
157
|
+
.replace(/^\s*\/\/.*$/gm, '');
|
|
158
|
+
const imports = [];
|
|
159
|
+
const pattern = /\bfrom\s+['"]([^'"]+)['"]|import\s+['"]([^'"]+)['"]/g;
|
|
160
|
+
let match = pattern.exec(content);
|
|
161
|
+
while (match) {
|
|
162
|
+
imports.push(match[1] || match[2]);
|
|
163
|
+
match = pattern.exec(content);
|
|
164
|
+
}
|
|
165
|
+
return imports;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function toPackageName(importPath) {
|
|
169
|
+
if (importPath.startsWith('@')) {
|
|
170
|
+
const parts = importPath.split('/');
|
|
171
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : importPath;
|
|
172
|
+
}
|
|
173
|
+
return importPath.split('/')[0];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function collectComponentFiles(componentFolder) {
|
|
177
|
+
const queue = [];
|
|
178
|
+
const visitedFiles = new Set();
|
|
179
|
+
const visitedFolders = new Set([componentFolder]);
|
|
180
|
+
|
|
181
|
+
const rootPath = path.join(LIB_SOURCE_ROOT, componentFolder);
|
|
182
|
+
for (const file of listFilesRecursively(rootPath)) {
|
|
183
|
+
queue.push(file);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const externalPackages = new Set();
|
|
187
|
+
|
|
188
|
+
while (queue.length) {
|
|
189
|
+
const currentFile = queue.shift();
|
|
190
|
+
if (visitedFiles.has(currentFile)) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
visitedFiles.add(currentFile);
|
|
194
|
+
|
|
195
|
+
const imports = extractImports(currentFile);
|
|
196
|
+
for (const importPath of imports) {
|
|
197
|
+
if (importPath.startsWith('.')) {
|
|
198
|
+
const resolved = resolveImportFile(currentFile, importPath);
|
|
199
|
+
if (!resolved || !resolved.startsWith(LIB_SOURCE_ROOT) || shouldSkipFile(resolved)) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const relative = path.relative(LIB_SOURCE_ROOT, resolved);
|
|
203
|
+
const rootFolder = relative.split(path.sep)[0];
|
|
204
|
+
if (!visitedFolders.has(rootFolder)) {
|
|
205
|
+
visitedFolders.add(rootFolder);
|
|
206
|
+
for (const file of listFilesRecursively(path.join(LIB_SOURCE_ROOT, rootFolder))) {
|
|
207
|
+
queue.push(file);
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
queue.push(resolved);
|
|
211
|
+
}
|
|
212
|
+
} else if (!ALWAYS_AVAILABLE_IMPORTS.has(importPath) && !importPath.startsWith('node:')) {
|
|
213
|
+
const packageName = toPackageName(importPath);
|
|
214
|
+
if (!ALWAYS_AVAILABLE_IMPORTS.has(packageName) && packageName !== 'sng-ui') {
|
|
215
|
+
externalPackages.add(packageName);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
files: [...visitedFiles].sort(),
|
|
223
|
+
externalPackages: [...externalPackages].sort()
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function copyFiles(files, destinationRoot, options) {
|
|
228
|
+
let copied = 0;
|
|
229
|
+
let skipped = 0;
|
|
230
|
+
|
|
231
|
+
for (const sourceFile of files) {
|
|
232
|
+
const relative = path.relative(LIB_SOURCE_ROOT, sourceFile);
|
|
233
|
+
const destination = path.join(destinationRoot, relative);
|
|
234
|
+
const destinationDirectory = path.dirname(destination);
|
|
235
|
+
|
|
236
|
+
if (!options.dryRun) {
|
|
237
|
+
fs.mkdirSync(destinationDirectory, { recursive: true });
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (fs.existsSync(destination) && !options.force) {
|
|
241
|
+
skipped += 1;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (!options.dryRun) {
|
|
246
|
+
fs.copyFileSync(sourceFile, destination);
|
|
247
|
+
}
|
|
248
|
+
copied += 1;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return { copied, skipped };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function runInit(cwd, options) {
|
|
255
|
+
const componentsDir = options.path || DEFAULT_COMPONENTS_DIR;
|
|
256
|
+
writeConfig(cwd, componentsDir, options.force);
|
|
257
|
+
console.log(`Created ${CONFIG_FILE} with componentsDir="${componentsDir}".`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function runAdd(cwd, options) {
|
|
261
|
+
if (!options.values.length) {
|
|
262
|
+
throw new Error('Missing component name. Example: npx sng-ui add button');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const config = readConfig(cwd);
|
|
266
|
+
const destinationRoot = path.resolve(cwd, options.path || config.componentsDir);
|
|
267
|
+
const folderMap = getComponentFolderMap();
|
|
268
|
+
const missing = [];
|
|
269
|
+
|
|
270
|
+
let totalCopied = 0;
|
|
271
|
+
let totalSkipped = 0;
|
|
272
|
+
const dependencySet = new Set();
|
|
273
|
+
|
|
274
|
+
for (const componentName of options.values) {
|
|
275
|
+
const folder = resolveComponentFolder(componentName, folderMap);
|
|
276
|
+
if (!folder) {
|
|
277
|
+
missing.push(componentName);
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const { files, externalPackages } = collectComponentFiles(folder);
|
|
282
|
+
const result = copyFiles(files, destinationRoot, options);
|
|
283
|
+
totalCopied += result.copied;
|
|
284
|
+
totalSkipped += result.skipped;
|
|
285
|
+
for (const dependency of externalPackages) {
|
|
286
|
+
dependencySet.add(dependency);
|
|
287
|
+
}
|
|
288
|
+
console.log(`Added ${componentName}: ${result.copied} file(s), ${result.skipped} skipped.`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (missing.length) {
|
|
292
|
+
const available = [...new Set([...folderMap.keys()].filter((name) => !name.startsWith('sng-')))].sort();
|
|
293
|
+
throw new Error(`Unknown component(s): ${missing.join(', ')}.\nAvailable: ${available.join(', ')}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log(`Done. Copied ${totalCopied} file(s), skipped ${totalSkipped}.`);
|
|
297
|
+
if (dependencySet.size) {
|
|
298
|
+
console.log(`Install peer deps if missing:\n npm install ${[...dependencySet].join(' ')}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function main() {
|
|
303
|
+
const cwd = process.cwd();
|
|
304
|
+
const args = process.argv.slice(2);
|
|
305
|
+
const command = args.shift();
|
|
306
|
+
|
|
307
|
+
if (!command || command === '--help' || command === '-h') {
|
|
308
|
+
printHelp();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const options = parseOptions(args);
|
|
313
|
+
|
|
314
|
+
if (command === 'init') {
|
|
315
|
+
runInit(cwd, options);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (command === 'add') {
|
|
319
|
+
runAdd(cwd, options);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
throw new Error(`Unknown command: ${command}`);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
main();
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.error(`[sng-ui] ${error.message}`);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
package/ng-package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/ng-packagr/ng-package.schema.json",
|
|
3
|
+
"dest": "dist/sng-ui",
|
|
4
|
+
"lib": {
|
|
5
|
+
"entryFile": "src/public-api.ts"
|
|
6
|
+
},
|
|
7
|
+
"assets": [
|
|
8
|
+
{
|
|
9
|
+
"input": "cli",
|
|
10
|
+
"glob": "**/*",
|
|
11
|
+
"ignore": [
|
|
12
|
+
"**/*.spec.cjs"
|
|
13
|
+
],
|
|
14
|
+
"output": "cli"
|
|
15
|
+
},
|
|
16
|
+
"registry.json",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
{
|
|
19
|
+
"input": "src/lib",
|
|
20
|
+
"glob": "**/*.ts",
|
|
21
|
+
"ignore": [
|
|
22
|
+
"**/*.spec.ts",
|
|
23
|
+
"**/*.stories.ts"
|
|
24
|
+
],
|
|
25
|
+
"output": "src/lib"
|
|
26
|
+
},
|
|
27
|
+
"src/lib/styles/**/*.css"
|
|
28
|
+
]
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shadng/sng-ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Native Angular UI components inspired by shadcn/ui Figma designs.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/alimjanablikim/sng-ui.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/alimjanablikim/sng-ui",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/alimjanablikim/sng-ui/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"angular",
|
|
16
|
+
"ui",
|
|
17
|
+
"components",
|
|
18
|
+
"tailwindcss",
|
|
19
|
+
"shadcn"
|
|
20
|
+
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"sng-ui": "cli/sng-ui.js"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20.11.0",
|
|
26
|
+
"npm": ">=10.0.0"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@angular/common": "^21.0.0",
|
|
30
|
+
"@angular/core": "^21.0.0",
|
|
31
|
+
"@angular/platform-browser": "^21.0.0",
|
|
32
|
+
"shiki": "^3.0.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependenciesMeta": {
|
|
35
|
+
"shiki": {
|
|
36
|
+
"optional": true
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"tslib": "^2.3.0"
|
|
41
|
+
},
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"test:cli": "node --test cli/sng-ui.cli.spec.cjs",
|
|
48
|
+
"pack:check": "npm pack --dry-run"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"src/",
|
|
52
|
+
"!src/**/*.spec.ts",
|
|
53
|
+
"!src/**/*.stories.ts",
|
|
54
|
+
"cli/",
|
|
55
|
+
"!cli/*.spec.cjs",
|
|
56
|
+
"registry.json",
|
|
57
|
+
"README.md",
|
|
58
|
+
"LICENSE",
|
|
59
|
+
"ng-package.json",
|
|
60
|
+
"tsconfig.json",
|
|
61
|
+
"tsconfig.lib.json",
|
|
62
|
+
"tsconfig.lib.prod.json"
|
|
63
|
+
]
|
|
64
|
+
}
|
package/registry.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./registry-schema.json",
|
|
3
|
+
"name": "sng-ui",
|
|
4
|
+
"description": "ShadNG UI Component Registry",
|
|
5
|
+
"components": {
|
|
6
|
+
"cn": {
|
|
7
|
+
"name": "cn",
|
|
8
|
+
"description": "Utility for merging Tailwind CSS classes",
|
|
9
|
+
"files": ["lib/button/cn.ts"],
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"npm": ["clsx", "tailwind-merge"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"button": {
|
|
15
|
+
"name": "button",
|
|
16
|
+
"description": "Angular button component with class-based styling",
|
|
17
|
+
"files": ["lib/button/sng-button.ts"],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"internal": ["cn"]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"code-block": {
|
|
23
|
+
"name": "code-block",
|
|
24
|
+
"description": "Code block component with VS Code-accurate syntax highlighting powered by Shiki. Includes copy button and language header.",
|
|
25
|
+
"files": ["lib/code-block/sng-code-block.ts", "lib/code-block/index.ts"],
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"npm": ["shiki"],
|
|
28
|
+
"internal": ["cn"]
|
|
29
|
+
},
|
|
30
|
+
"note": "Requires 'shiki' npm package. Supports 200+ languages and all VS Code themes."
|
|
31
|
+
},
|
|
32
|
+
"preview-box": {
|
|
33
|
+
"name": "preview-box",
|
|
34
|
+
"description": "Tabbed preview component with Preview, Code, and Source tabs. Perfect for documentation sites.",
|
|
35
|
+
"files": ["lib/preview-box/sng-preview-box.ts"],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"internal": ["cn", "code-block"],
|
|
38
|
+
"npm": ["shiki"]
|
|
39
|
+
},
|
|
40
|
+
"note": "Uses code-block for syntax-highlighted code display in Code/Source tabs."
|
|
41
|
+
},
|
|
42
|
+
"accordion": {
|
|
43
|
+
"name": "accordion",
|
|
44
|
+
"description": "Angular accordion component for collapsible content sections. Built with Angular signals for accessibility.",
|
|
45
|
+
"files": [
|
|
46
|
+
"lib/accordion/sng-accordion.ts",
|
|
47
|
+
"lib/accordion/sng-accordion-item.ts",
|
|
48
|
+
"lib/accordion/sng-accordion-trigger.ts",
|
|
49
|
+
"lib/accordion/sng-accordion-content.ts",
|
|
50
|
+
"lib/accordion/index.ts"
|
|
51
|
+
],
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"internal": ["cn"]
|
|
54
|
+
},
|
|
55
|
+
"note": "Includes smooth expand/collapse animations. Supports single/multiple mode and collapsible options."
|
|
56
|
+
},
|
|
57
|
+
"alert": {
|
|
58
|
+
"name": "alert",
|
|
59
|
+
"description": "Angular alert component for displaying important messages, errors, and notifications. Supports icons and multiple variants via Tailwind classes.",
|
|
60
|
+
"files": [
|
|
61
|
+
"lib/alert/sng-alert.ts",
|
|
62
|
+
"lib/alert/sng-alert-title.ts",
|
|
63
|
+
"lib/alert/sng-alert-description.ts",
|
|
64
|
+
"lib/alert/index.ts"
|
|
65
|
+
],
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"internal": ["cn"]
|
|
68
|
+
},
|
|
69
|
+
"note": "Purely presentational component. No Angular CDK required. Use Alert Dialog for confirmation modals."
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
export { SngAccordion } from './sng-accordion';
|
|
3
|
+
export { SngAccordionItem } from './sng-accordion-item';
|
|
4
|
+
export { SngAccordionTrigger } from './sng-accordion-trigger';
|
|
5
|
+
export { SngAccordionContent } from './sng-accordion-content';
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export type {
|
|
9
|
+
SngAccordionType,
|
|
10
|
+
SngAccordionValue,
|
|
11
|
+
SngAccordionState,
|
|
12
|
+
SngAccordionOrientation,
|
|
13
|
+
SngAccordionLayout,
|
|
14
|
+
SngAccordionApi,
|
|
15
|
+
SngAccordionItemApi,
|
|
16
|
+
SngAccordionTriggerApi,
|
|
17
|
+
SngAccordionContentApi,
|
|
18
|
+
} from './sng-accordion.types';
|