@sonny-ui/core 0.1.0-alpha.1

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.
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateComponent = generateComponent;
37
+ const path = __importStar(require("path"));
38
+ const AVAILABLE_COMPONENTS = [
39
+ 'accordion',
40
+ 'avatar',
41
+ 'badge',
42
+ 'breadcrumb',
43
+ 'button',
44
+ 'button-group',
45
+ 'card',
46
+ 'checkbox',
47
+ 'combobox',
48
+ 'input',
49
+ 'loader',
50
+ 'modal',
51
+ 'radio',
52
+ 'select',
53
+ 'sheet',
54
+ 'skeleton',
55
+ 'slider',
56
+ 'switch',
57
+ 'table',
58
+ 'tabs',
59
+ 'toast',
60
+ 'toggle',
61
+ ];
62
+ const COMPONENT_FILES = {
63
+ accordion: [
64
+ 'accordion.directives.ts',
65
+ 'index.ts',
66
+ ],
67
+ avatar: [
68
+ 'avatar.component.ts',
69
+ 'avatar.variants.ts',
70
+ 'index.ts',
71
+ ],
72
+ badge: [
73
+ 'badge.directive.ts',
74
+ 'badge.variants.ts',
75
+ 'index.ts',
76
+ ],
77
+ breadcrumb: [
78
+ 'breadcrumb.directives.ts',
79
+ 'index.ts',
80
+ ],
81
+ button: [
82
+ 'button.directive.ts',
83
+ 'button.variants.ts',
84
+ 'index.ts',
85
+ ],
86
+ 'button-group': [
87
+ 'button-group.directive.ts',
88
+ 'button-group.variants.ts',
89
+ 'index.ts',
90
+ ],
91
+ card: [
92
+ 'card.directives.ts',
93
+ 'card.variants.ts',
94
+ 'index.ts',
95
+ ],
96
+ checkbox: [
97
+ 'checkbox.directive.ts',
98
+ 'checkbox.variants.ts',
99
+ 'index.ts',
100
+ ],
101
+ combobox: [
102
+ 'combobox.component.ts',
103
+ 'combobox.variants.ts',
104
+ 'index.ts',
105
+ ],
106
+ input: [
107
+ 'input.directive.ts',
108
+ 'input.variants.ts',
109
+ 'label.directive.ts',
110
+ 'index.ts',
111
+ ],
112
+ loader: [
113
+ 'loader.component.ts',
114
+ 'loader.variants.ts',
115
+ 'index.ts',
116
+ ],
117
+ modal: [
118
+ 'dialog.types.ts',
119
+ 'dialog-ref.ts',
120
+ 'dialog.service.ts',
121
+ 'dialog.directives.ts',
122
+ 'index.ts',
123
+ ],
124
+ radio: [
125
+ 'radio.directive.ts',
126
+ 'radio.variants.ts',
127
+ 'index.ts',
128
+ ],
129
+ select: [
130
+ 'select.component.ts',
131
+ 'select.variants.ts',
132
+ 'index.ts',
133
+ ],
134
+ sheet: [
135
+ 'sheet-ref.ts',
136
+ 'sheet.directives.ts',
137
+ 'sheet.service.ts',
138
+ 'sheet.types.ts',
139
+ 'index.ts',
140
+ ],
141
+ skeleton: [
142
+ 'skeleton.directive.ts',
143
+ 'skeleton.variants.ts',
144
+ 'index.ts',
145
+ ],
146
+ slider: [
147
+ 'slider.component.ts',
148
+ 'slider.variants.ts',
149
+ 'index.ts',
150
+ ],
151
+ switch: [
152
+ 'switch.component.ts',
153
+ 'switch.variants.ts',
154
+ 'index.ts',
155
+ ],
156
+ table: [
157
+ 'table.directives.ts',
158
+ 'table.variants.ts',
159
+ 'index.ts',
160
+ ],
161
+ tabs: [
162
+ 'tabs.directives.ts',
163
+ 'tabs.variants.ts',
164
+ 'index.ts',
165
+ ],
166
+ toast: [
167
+ 'toast.service.ts',
168
+ 'toast.variants.ts',
169
+ 'toaster.component.ts',
170
+ 'index.ts',
171
+ ],
172
+ toggle: [
173
+ 'toggle.directive.ts',
174
+ 'toggle.variants.ts',
175
+ 'index.ts',
176
+ ],
177
+ };
178
+ const COMPONENT_SPEC_FILES = {
179
+ accordion: ['accordion.directives.spec.ts'],
180
+ avatar: ['avatar.component.spec.ts'],
181
+ badge: ['badge.directive.spec.ts'],
182
+ breadcrumb: ['breadcrumb.directives.spec.ts'],
183
+ button: ['button.directive.spec.ts'],
184
+ 'button-group': ['button-group.directive.spec.ts'],
185
+ card: ['card.directives.spec.ts'],
186
+ checkbox: ['checkbox.directive.spec.ts'],
187
+ combobox: ['combobox.component.spec.ts'],
188
+ input: ['input.directive.spec.ts'],
189
+ loader: ['loader.component.spec.ts'],
190
+ modal: ['dialog.service.spec.ts'],
191
+ radio: ['radio.directive.spec.ts'],
192
+ select: ['select.component.spec.ts'],
193
+ sheet: ['sheet.component.spec.ts'],
194
+ skeleton: ['skeleton.directive.spec.ts'],
195
+ slider: ['slider.component.spec.ts'],
196
+ switch: ['switch.component.spec.ts'],
197
+ table: ['table.directives.spec.ts'],
198
+ tabs: ['tabs.directives.spec.ts'],
199
+ toast: ['toast.service.spec.ts'],
200
+ toggle: ['toggle.directive.spec.ts'],
201
+ };
202
+ function generateComponent(options) {
203
+ return (tree, context) => {
204
+ const name = options.name.toLowerCase();
205
+ if (!AVAILABLE_COMPONENTS.includes(name)) {
206
+ throw new Error(`Unknown component "${name}". Available: ${AVAILABLE_COMPONENTS.join(', ')}`);
207
+ }
208
+ const targetDir = options.path || 'src/app/ui';
209
+ const componentDir = `${targetDir}/${name}`;
210
+ const files = COMPONENT_FILES[name];
211
+ const specFiles = options.skipTests ? [] : (COMPONENT_SPEC_FILES[name] || []);
212
+ // Ensure cn.ts utility exists
213
+ const cnTargetPath = `${targetDir}/utils/cn.ts`;
214
+ if (!tree.exists(cnTargetPath)) {
215
+ const cnContent = `import { clsx, type ClassValue } from 'clsx';
216
+ import { twMerge } from 'tailwind-merge';
217
+
218
+ export function cn(...inputs: ClassValue[]): string {
219
+ return twMerge(clsx(inputs));
220
+ }
221
+ `;
222
+ tree.create(cnTargetPath, cnContent);
223
+ context.logger.info('Created utils/cn.ts');
224
+ }
225
+ // Copy component files from the library source
226
+ const sourceBase = path.join(__dirname, '..', '..', '..', 'src', 'lib', name);
227
+ for (const file of [...files, ...specFiles]) {
228
+ const sourcePath = path.join(sourceBase, file);
229
+ const destPath = `${componentDir}/${file}`;
230
+ if (tree.exists(destPath)) {
231
+ context.logger.warn(`File already exists: ${destPath} — skipping`);
232
+ continue;
233
+ }
234
+ // Read from the package's source files
235
+ try {
236
+ const fs = require('fs');
237
+ let content = fs.readFileSync(sourcePath, 'utf-8');
238
+ // Rewrite imports to use local cn utility
239
+ content = content.replace(/from ['"]\.\.\/core\/utils\/cn['"]/g, `from '../../utils/cn'`);
240
+ // Rewrite prefix if custom
241
+ if (options.prefix && options.prefix !== 'sny') {
242
+ content = content.replace(/sny/g, options.prefix);
243
+ content = content.replace(/Sny/g, capitalize(options.prefix));
244
+ }
245
+ tree.create(destPath, content);
246
+ context.logger.info(`Created ${destPath}`);
247
+ }
248
+ catch (e) {
249
+ context.logger.error(`Could not read source file: ${sourcePath}`);
250
+ }
251
+ }
252
+ context.logger.info(`Component "${name}" copied to ${componentDir}`);
253
+ return tree;
254
+ };
255
+ }
256
+ function capitalize(str) {
257
+ return str.charAt(0).toUpperCase() + str.slice(1);
258
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "id": "SonnyUIGenerateComponentSchema",
4
+ "title": "SonnyUI component generator (copy-paste style)",
5
+ "type": "object",
6
+ "properties": {
7
+ "name": {
8
+ "type": "string",
9
+ "description": "The component to copy (accordion, avatar, badge, breadcrumb, button, button-group, card, checkbox, combobox, input, loader, modal, radio, select, sheet, skeleton, slider, switch, table, tabs, toast, toggle).",
10
+ "$default": {
11
+ "$source": "argv",
12
+ "index": 0
13
+ }
14
+ },
15
+ "path": {
16
+ "type": "string",
17
+ "default": "src/app/ui",
18
+ "description": "The path to copy the component into."
19
+ },
20
+ "prefix": {
21
+ "type": "string",
22
+ "default": "sny",
23
+ "description": "The prefix to use for selectors."
24
+ },
25
+ "skipTests": {
26
+ "type": "boolean",
27
+ "default": false,
28
+ "description": "Skip copying test files."
29
+ }
30
+ },
31
+ "required": ["name"]
32
+ }
@@ -0,0 +1,126 @@
1
+ @import "tailwindcss";
2
+
3
+ @custom-variant dark (&:is(.dark *));
4
+
5
+ @theme {
6
+ --color-background: var(--sny-background);
7
+ --color-foreground: var(--sny-foreground);
8
+ --color-primary: var(--sny-primary);
9
+ --color-primary-foreground: var(--sny-primary-foreground);
10
+ --color-secondary: var(--sny-secondary);
11
+ --color-secondary-foreground: var(--sny-secondary-foreground);
12
+ --color-muted: var(--sny-muted);
13
+ --color-muted-foreground: var(--sny-muted-foreground);
14
+ --color-accent: var(--sny-accent);
15
+ --color-accent-foreground: var(--sny-accent-foreground);
16
+ --color-destructive: var(--sny-destructive);
17
+ --color-destructive-foreground: var(--sny-destructive-foreground);
18
+ --color-card: var(--sny-card);
19
+ --color-card-foreground: var(--sny-card-foreground);
20
+ --color-border: var(--sny-border);
21
+ --color-input: var(--sny-input);
22
+ --color-ring: var(--sny-ring);
23
+ --radius-sm: var(--sny-radius);
24
+ }
25
+
26
+ :root {
27
+ --sny-background: #ffffff;
28
+ --sny-foreground: #0a0a0a;
29
+ --sny-primary: #171717;
30
+ --sny-primary-foreground: #fafafa;
31
+ --sny-secondary: #f5f5f5;
32
+ --sny-secondary-foreground: #171717;
33
+ --sny-muted: #f5f5f5;
34
+ --sny-muted-foreground: #737373;
35
+ --sny-accent: #f5f5f5;
36
+ --sny-accent-foreground: #171717;
37
+ --sny-destructive: #ef4444;
38
+ --sny-destructive-foreground: #fafafa;
39
+ --sny-card: #ffffff;
40
+ --sny-card-foreground: #0a0a0a;
41
+ --sny-border: #e5e5e5;
42
+ --sny-input: #e5e5e5;
43
+ --sny-ring: #0a0a0a;
44
+ --sny-radius: 0.5rem;
45
+ }
46
+
47
+ .dark,
48
+ [data-theme="dark"] {
49
+ --sny-background: #0a0a0a;
50
+ --sny-foreground: #fafafa;
51
+ --sny-primary: #fafafa;
52
+ --sny-primary-foreground: #171717;
53
+ --sny-secondary: #262626;
54
+ --sny-secondary-foreground: #fafafa;
55
+ --sny-muted: #262626;
56
+ --sny-muted-foreground: #a3a3a3;
57
+ --sny-accent: #262626;
58
+ --sny-accent-foreground: #fafafa;
59
+ --sny-destructive: #dc2626;
60
+ --sny-destructive-foreground: #fafafa;
61
+ --sny-card: #0a0a0a;
62
+ --sny-card-foreground: #fafafa;
63
+ --sny-border: #262626;
64
+ --sny-input: #262626;
65
+ --sny-ring: #d4d4d4;
66
+ }
67
+
68
+ [data-theme="corporate"] {
69
+ --sny-background: #f8fafc;
70
+ --sny-foreground: #0f172a;
71
+ --sny-primary: #1e40af;
72
+ --sny-primary-foreground: #ffffff;
73
+ --sny-secondary: #e2e8f0;
74
+ --sny-secondary-foreground: #1e293b;
75
+ --sny-muted: #f1f5f9;
76
+ --sny-muted-foreground: #64748b;
77
+ --sny-accent: #dbeafe;
78
+ --sny-accent-foreground: #1e3a8a;
79
+ --sny-destructive: #dc2626;
80
+ --sny-destructive-foreground: #ffffff;
81
+ --sny-card: #ffffff;
82
+ --sny-card-foreground: #0f172a;
83
+ --sny-border: #cbd5e1;
84
+ --sny-input: #cbd5e1;
85
+ --sny-ring: #3b82f6;
86
+ --sny-radius: 0.375rem;
87
+ }
88
+
89
+ /* ─── Dialog / Sheet overlay ─── */
90
+
91
+ .sny-dialog-backdrop {
92
+ background-color: rgba(0, 0, 0, 0.5) !important;
93
+ }
94
+
95
+ /* Sheet panel — styling only; positioning handled by CDK GlobalPositionStrategy */
96
+ .sny-sheet-panel {
97
+ background-color: var(--sny-background);
98
+ padding: 1.5rem;
99
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
100
+ overflow-y: auto;
101
+ }
102
+
103
+ .sny-sheet-right {
104
+ border-left: 1px solid var(--sny-border);
105
+ }
106
+
107
+ .sny-sheet-left {
108
+ border-right: 1px solid var(--sny-border);
109
+ }
110
+
111
+ .sny-sheet-top {
112
+ border-bottom: 1px solid var(--sny-border);
113
+ }
114
+
115
+ .sny-sheet-bottom {
116
+ border-top: 1px solid var(--sny-border);
117
+ }
118
+
119
+ /* Search dialog panel */
120
+ .sny-search-dialog {
121
+ background-color: var(--sny-background);
122
+ border: 1px solid var(--sny-border);
123
+ border-radius: 0.5rem;
124
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
125
+ overflow: hidden;
126
+ }