@eduboxpro/studio 0.1.0 → 0.1.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.
@@ -1,6 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, output, computed, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { InjectionToken, inject, signal, effect, Injectable, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, input, computed, ChangeDetectionStrategy, Component, output } from '@angular/core';
3
3
  import { DOCUMENT } from '@angular/common';
4
+ import * as i1 from 'lucide-angular';
5
+ import { icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS, Loader2, Loader, RotateCw, RefreshCw, Printer, Save, Image, Folder, FileText, File, HelpCircle, XCircle, CheckCircle, Info, AlertTriangle, AlertCircle, LogOut, LogIn, Unlock, Lock, EyeOff, Eye, Clock, Calendar, Bell, MoreHorizontal, MoreVertical, Menu, Home, Share2, Copy, Link, ExternalLink, Filter, Search, X, Check, Minus, Plus, Edit, Trash2, User, Settings, Star, Heart, Phone, Mail, Upload, Download, ChevronRight, ChevronLeft, ChevronUp, ChevronDown, ArrowLeft, ArrowRight } from 'lucide-angular';
4
6
 
5
7
  /**
6
8
  * Injection token for Studio configuration
@@ -51,28 +53,105 @@ class StudioConfigService {
51
53
  if (!theme)
52
54
  return;
53
55
  const root = this.document.documentElement;
56
+ // Apply colors
54
57
  if (theme.colors) {
55
- this.applyTokens(root, 'studio', theme.colors);
58
+ this.applyColorTokens(root, theme.colors);
56
59
  }
60
+ // Apply typography
61
+ if (theme.typography) {
62
+ if (theme.typography.fontFamily) {
63
+ root.style.setProperty('--studio-font-family', theme.typography.fontFamily);
64
+ }
65
+ if (theme.typography.fontMono) {
66
+ root.style.setProperty('--studio-font-mono', theme.typography.fontMono);
67
+ }
68
+ if (theme.typography.fontSize) {
69
+ this.applyTokens(root, 'studio-font-size', theme.typography.fontSize);
70
+ }
71
+ if (theme.typography.fontWeight) {
72
+ this.applyTokens(root, 'studio-font-weight', theme.typography.fontWeight);
73
+ }
74
+ if (theme.typography.lineHeight) {
75
+ this.applyTokens(root, 'studio-line-height', theme.typography.lineHeight);
76
+ }
77
+ }
78
+ // Apply spacing
57
79
  if (theme.spacing) {
58
80
  this.applyTokens(root, 'studio-spacing', theme.spacing);
59
81
  }
82
+ // Apply border radius
60
83
  if (theme.borderRadius) {
61
84
  this.applyTokens(root, 'studio-radius', theme.borderRadius);
62
85
  }
86
+ // Apply shadows
63
87
  if (theme.shadows) {
64
88
  this.applyTokens(root, 'studio-shadow', theme.shadows);
65
89
  }
66
- if (theme.typography?.fontFamily) {
67
- root.style.setProperty('--studio-font-family', theme.typography.fontFamily);
90
+ // Apply transitions
91
+ if (theme.transitions) {
92
+ this.applyTokens(root, 'studio-transition', theme.transitions);
68
93
  }
69
- if (theme.typography?.fontSize) {
70
- this.applyTokens(root, 'studio-font-size', theme.typography.fontSize);
94
+ // Apply z-index
95
+ if (theme.zIndex) {
96
+ this.applyZIndexTokens(root, theme.zIndex);
71
97
  }
72
- if (theme.typography?.fontWeight) {
73
- this.applyTokens(root, 'studio-font-weight', theme.typography.fontWeight);
98
+ }
99
+ applyColorTokens(root, colors) {
100
+ // Brand colors with hover/active states
101
+ const brandColors = ['primary', 'secondary', 'success', 'error', 'warning', 'info'];
102
+ brandColors.forEach(colorName => {
103
+ const colorValue = colors[colorName];
104
+ if (!colorValue)
105
+ return;
106
+ if (typeof colorValue === 'string') {
107
+ root.style.setProperty(`--studio-${colorName}`, colorValue);
108
+ }
109
+ else {
110
+ const config = colorValue;
111
+ if (config.base) {
112
+ root.style.setProperty(`--studio-${colorName}`, config.base);
113
+ }
114
+ if (config.hover) {
115
+ root.style.setProperty(`--studio-${colorName}-hover`, config.hover);
116
+ }
117
+ if (config.active) {
118
+ root.style.setProperty(`--studio-${colorName}-active`, config.active);
119
+ }
120
+ if (config.bg) {
121
+ root.style.setProperty(`--studio-${colorName}-bg`, config.bg);
122
+ }
123
+ }
124
+ });
125
+ // Background colors
126
+ if (colors.bg) {
127
+ this.applyTokens(root, 'studio-bg', colors.bg);
128
+ }
129
+ // Text colors
130
+ if (colors.text) {
131
+ this.applyTokens(root, 'studio-text', colors.text);
132
+ }
133
+ // Border colors
134
+ if (colors.border) {
135
+ this.applyTokens(root, 'studio-border', colors.border);
74
136
  }
75
137
  }
138
+ applyZIndexTokens(root, zIndex) {
139
+ const zIndexMap = {
140
+ dropdown: 'dropdown',
141
+ sticky: 'sticky',
142
+ fixed: 'fixed',
143
+ modalBackdrop: 'modal-backdrop',
144
+ modal: 'modal',
145
+ popover: 'popover',
146
+ tooltip: 'tooltip'
147
+ };
148
+ Object.entries(zIndex).forEach(([key, value]) => {
149
+ if (value !== undefined && value !== null) {
150
+ const cssKey = zIndexMap[key] || key;
151
+ root.style.setProperty(`--studio-z-${cssKey}`, String(value));
152
+ }
153
+ });
154
+ }
76
155
  applyTokens(root, prefix, tokens) {
77
156
  Object.entries(tokens).forEach(([key, value]) => {
78
157
  if (value !== undefined && value !== null) {
@@ -133,6 +212,162 @@ function provideStudioConfig(config = {}) {
133
212
  * @module config
134
213
  */
135
214
 
215
+ class IconComponent {
216
+ name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
217
+ size = input(24, ...(ngDevMode ? [{ debugName: "size" }] : []));
218
+ color = input('inherit', ...(ngDevMode ? [{ debugName: "color" }] : []));
219
+ strokeWidth = input(2, ...(ngDevMode ? [{ debugName: "strokeWidth" }] : []));
220
+ absoluteStrokeWidth = input(false, ...(ngDevMode ? [{ debugName: "absoluteStrokeWidth" }] : []));
221
+ icons = icons;
222
+ lucideIcon = computed(() => {
223
+ const iconName = this.name();
224
+ return iconName;
225
+ }, ...(ngDevMode ? [{ debugName: "lucideIcon" }] : []));
226
+ computedColor = computed(() => {
227
+ const colorValue = this.color();
228
+ const colorMap = {
229
+ 'primary': 'var(--studio-primary)',
230
+ 'secondary': 'var(--studio-secondary)',
231
+ 'success': 'var(--studio-success)',
232
+ 'error': 'var(--studio-error)',
233
+ 'warning': 'var(--studio-warning)',
234
+ 'inherit': 'currentColor'
235
+ };
236
+ return colorMap[colorValue] || colorValue;
237
+ }, ...(ngDevMode ? [{ debugName: "computedColor" }] : []));
238
+ hostClasses = computed(() => {
239
+ return ['studio-icon'];
240
+ }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: IconComponent, isStandalone: true, selector: "studio-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, absoluteStrokeWidth: { classPropertyName: "absoluteStrokeWidth", publicName: "absoluteStrokeWidth", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()", "style.width.px": "size()", "style.height.px": "size()" } }, ngImport: i0, template: `
243
+ @if (lucideIcon(); as iconName) {
244
+ <lucide-icon
245
+ [name]="iconName"
246
+ [size]="size()"
247
+ [color]="computedColor()"
248
+ [strokeWidth]="strokeWidth()"
249
+ [absoluteStrokeWidth]="absoluteStrokeWidth()"
250
+ />
251
+ }
252
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
253
+ }
254
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: IconComponent, decorators: [{
255
+ type: Component,
256
+ args: [{ selector: 'studio-icon', standalone: true, imports: [LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, host: {
257
+ '[class]': 'hostClasses()',
258
+ '[style.width.px]': 'size()',
259
+ '[style.height.px]': 'size()',
260
+ }, template: `
261
+ @if (lucideIcon(); as iconName) {
262
+ <lucide-icon
263
+ [name]="iconName"
264
+ [size]="size()"
265
+ [color]="computedColor()"
266
+ [strokeWidth]="strokeWidth()"
267
+ [absoluteStrokeWidth]="absoluteStrokeWidth()"
268
+ />
269
+ }
270
+ `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}\n"] }]
271
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], absoluteStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "absoluteStrokeWidth", required: false }] }] } });
272
+
273
+ /**
274
+ * Провайдер иконок для Studio
275
+ * Регистрирует базовый набор часто используемых иконок
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * // app.config.ts
280
+ * import { provideStudioIcons } from '@eduboxpro/studio';
281
+ *
282
+ * export const appConfig: ApplicationConfig = {
283
+ * providers: [
284
+ * provideStudioIcons()
285
+ * ]
286
+ * };
287
+ * ```
288
+ *
289
+ * Для добавления дополнительных иконок:
290
+ * @example
291
+ * ```typescript
292
+ * import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';
293
+ * import { Zap, Wifi } from 'lucide-angular';
294
+ *
295
+ * providers: [
296
+ * provideStudioIcons(),
297
+ * {
298
+ * provide: LUCIDE_ICONS,
299
+ * multi: true,
300
+ * useValue: new LucideIconProvider({ Zap, Wifi })
301
+ * }
302
+ * ]
303
+ * ```
304
+ */
305
+ function provideStudioIcons() {
306
+ return makeEnvironmentProviders([
307
+ {
308
+ provide: LUCIDE_ICONS,
309
+ multi: true,
310
+ useValue: new LucideIconProvider({
311
+ ArrowRight,
312
+ ArrowLeft,
313
+ ChevronDown,
314
+ ChevronUp,
315
+ ChevronLeft,
316
+ ChevronRight,
317
+ Download,
318
+ Upload,
319
+ Mail,
320
+ Phone,
321
+ Heart,
322
+ Star,
323
+ Settings,
324
+ User,
325
+ Trash2,
326
+ Edit,
327
+ Plus,
328
+ Minus,
329
+ Check,
330
+ X,
331
+ Search,
332
+ Filter,
333
+ ExternalLink,
334
+ Link,
335
+ Copy,
336
+ Share2,
337
+ Home,
338
+ Menu,
339
+ MoreVertical,
340
+ MoreHorizontal,
341
+ Bell,
342
+ Calendar,
343
+ Clock,
344
+ Eye,
345
+ EyeOff,
346
+ Lock,
347
+ Unlock,
348
+ LogIn,
349
+ LogOut,
350
+ AlertCircle,
351
+ AlertTriangle,
352
+ Info,
353
+ CheckCircle,
354
+ XCircle,
355
+ HelpCircle,
356
+ File,
357
+ FileText,
358
+ Folder,
359
+ Image,
360
+ Save,
361
+ Printer,
362
+ RefreshCw,
363
+ RotateCw,
364
+ Loader,
365
+ Loader2
366
+ })
367
+ }
368
+ ]);
369
+ }
370
+
136
371
  class ButtonComponent {
137
372
  variant = input('solid', ...(ngDevMode ? [{ debugName: "variant" }] : []));
138
373
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
@@ -141,7 +376,13 @@ class ButtonComponent {
141
376
  fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
142
377
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
143
378
  type = input('button', ...(ngDevMode ? [{ debugName: "type" }] : []));
379
+ icon = input(...(ngDevMode ? [undefined, { debugName: "icon" }] : []));
380
+ iconPosition = input('left', ...(ngDevMode ? [{ debugName: "iconPosition" }] : []));
144
381
  clicked = output();
382
+ iconSize = computed(() => {
383
+ const sizeMap = { sm: 16, md: 18, lg: 20 };
384
+ return sizeMap[this.size()];
385
+ }, ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
145
386
  hostClasses = computed(() => {
146
387
  return [
147
388
  'studio-button',
@@ -149,7 +390,8 @@ class ButtonComponent {
149
390
  `studio-button--${this.size()}`,
150
391
  `studio-button--${this.color()}`,
151
392
  this.fullWidth() ? 'studio-button--full' : '',
152
- this.loading() ? 'studio-button--loading' : ''
393
+ this.loading() ? 'studio-button--loading' : '',
394
+ this.iconPosition() === 'only' ? 'studio-button--icon-only' : ''
153
395
  ].filter(Boolean).join(' ');
154
396
  }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
155
397
  handleClick(event) {
@@ -161,25 +403,71 @@ class ButtonComponent {
161
403
  this.clicked.emit(event);
162
404
  }
163
405
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
164
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.12", type: ButtonComponent, isStandalone: true, selector: "studio-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class": "hostClasses()", "attr.disabled": "disabled() ? \"\" : null", "attr.type": "type()" } }, ngImport: i0, template: `
406
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: ButtonComponent, isStandalone: true, selector: "studio-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconPosition: { classPropertyName: "iconPosition", publicName: "iconPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class": "hostClasses()", "attr.disabled": "disabled() || loading() ? \"\" : null", "attr.type": "type()" } }, ngImport: i0, template: `
165
407
  <span class="studio-button__content">
166
- <ng-content />
408
+ @if (loading()) {
409
+ <studio-icon
410
+ name="loader-2"
411
+ [size]="iconSize()"
412
+ class="studio-button__spinner"
413
+ />
414
+ }
415
+ @if (!loading() && icon() && iconPosition() === 'left') {
416
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
417
+ }
418
+ @if (iconPosition() !== 'only' && !loading()) {
419
+ <ng-content />
420
+ }
421
+ @if (!loading() && icon() && iconPosition() === 'right') {
422
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
423
+ }
424
+ @if (!loading() && icon() && iconPosition() === 'only') {
425
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
426
+ }
427
+ @if (loading() && iconPosition() === 'only') {
428
+ <!-- Empty, spinner already shown -->
429
+ } @else if (loading()) {
430
+ <span>Loading...</span>
431
+ }
167
432
  </span>
168
- `, isInline: true, styles: [":host{display:inline-block}.studio-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast);border-radius:var(--studio-radius-md)}.studio-button:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-button:active:not(:disabled):not(.studio-button--loading){transform:scale(.98)}.studio-button--sm{padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}.studio-button--md{padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}.studio-button--lg{padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}.studio-button--solid.studio-button--primary{background:var(--studio-primary);color:#fff}.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-primary-hover)}.studio-button--solid.studio-button--primary:active:not(:disabled):not(.studio-button--loading){background:var(--studio-primary-active)}.studio-button--outline.studio-button--primary{background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-primary);color:#fff}.studio-button--ghost.studio-button--primary{background:transparent;color:var(--studio-primary)}.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading){background:#3b82f61a}.studio-button--solid.studio-button--secondary{background:var(--studio-secondary);color:#fff}.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-secondary-hover)}.studio-button--solid.studio-button--secondary:active:not(:disabled):not(.studio-button--loading){background:var(--studio-secondary-active)}.studio-button--outline.studio-button--secondary{background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-secondary);color:#fff}.studio-button--ghost.studio-button--secondary{background:transparent;color:var(--studio-secondary)}.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading){background:#8b5cf61a}.studio-button--solid.studio-button--success{background:var(--studio-success);color:#fff}.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-success-hover)}.studio-button--outline.studio-button--success{background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-success);color:#fff}.studio-button--ghost.studio-button--success{background:transparent;color:var(--studio-success)}.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-success-bg)}.studio-button--solid.studio-button--error{background:var(--studio-error);color:#fff}.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-error-hover)}.studio-button--outline.studio-button--error{background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-error);color:#fff}.studio-button--ghost.studio-button--error{background:transparent;color:var(--studio-error)}.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-error-bg)}.studio-button--solid.studio-button--warning{background:var(--studio-warning);color:#fff}.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-warning-hover)}.studio-button--outline.studio-button--warning{background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-warning);color:#fff}.studio-button--ghost.studio-button--warning{background:transparent;color:var(--studio-warning)}.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-warning-bg)}.studio-button--full{width:100%}.studio-button--loading{cursor:wait;opacity:.7}.studio-button:disabled{opacity:.5;cursor:not-allowed}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}[data-theme=dark] .studio-button--solid.studio-button--primary,[data-theme=dark] .studio-button--solid.studio-button--secondary,[data-theme=dark] .studio-button--solid.studio-button--success,[data-theme=dark] .studio-button--solid.studio-button--error,[data-theme=dark] .studio-button--solid.studio-button--warning{box-shadow:var(--studio-shadow-sm)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
433
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;border-radius:var(--studio-radius-md);transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast)}:host:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}:host(.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}:host(.studio-button--lg){padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}:host(.studio-button--solid.studio-button--primary){background:var(--studio-primary);color:#fff}:host(.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-hover)}:host(.studio-button--outline.studio-button--primary){background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary);color:#fff}:host(.studio-button--ghost.studio-button--primary){background:transparent;color:var(--studio-primary)}:host(.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:#3b82f61a}:host(.studio-button--solid.studio-button--secondary){background:var(--studio-secondary);color:#fff}:host(.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-hover)}:host(.studio-button--outline.studio-button--secondary){background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}:host(.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary);color:#fff}:host(.studio-button--ghost.studio-button--secondary){background:transparent;color:var(--studio-secondary)}:host(.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:#8b5cf61a}:host(.studio-button--solid.studio-button--success){background:var(--studio-success);color:#fff}:host(.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-hover)}:host(.studio-button--outline.studio-button--success){background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}:host(.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success);color:#fff}:host(.studio-button--ghost.studio-button--success){background:transparent;color:var(--studio-success)}:host(.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-bg)}:host(.studio-button--solid.studio-button--error){background:var(--studio-error);color:#fff}:host(.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-hover)}:host(.studio-button--outline.studio-button--error){background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}:host(.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error);color:#fff}:host(.studio-button--ghost.studio-button--error){background:transparent;color:var(--studio-error)}:host(.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-bg)}:host(.studio-button--solid.studio-button--warning){background:var(--studio-warning);color:#fff}:host(.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-hover)}:host(.studio-button--outline.studio-button--warning){background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning);color:#fff}:host(.studio-button--ghost.studio-button--warning){background:transparent;color:var(--studio-warning)}:host(.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-bg)}:host(.studio-button--full){width:100%}:host(.studio-button--icon-only){padding:0;aspect-ratio:1}:host(.studio-button--icon-only.studio-button--sm){width:2rem;padding:0}:host(.studio-button--icon-only.studio-button--md){width:2.5rem;padding:0}:host(.studio-button--icon-only.studio-button--lg){width:3rem;padding:0}:host(.studio-button--loading){cursor:wait;pointer-events:none}:host([disabled]){opacity:.6;cursor:not-allowed!important;background:var(--studio-bg-secondary)!important;color:var(--studio-text-tertiary)!important;border-color:var(--studio-border-primary)!important}:host([disabled]:hover){transform:none!important;background:var(--studio-bg-secondary)!important}:host(:active:not([disabled]):not(.studio-button--loading)){transform:scale(.98)}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-button__spinner{animation:studio-spin 1s linear infinite}@keyframes studio-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "studio-icon", inputs: ["name", "size", "color", "strokeWidth", "absoluteStrokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
169
434
  }
170
435
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: ButtonComponent, decorators: [{
171
436
  type: Component,
172
- args: [{ selector: 'studio-button', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: {
437
+ args: [{ selector: 'studio-button', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
173
438
  '[class]': 'hostClasses()',
174
- '[attr.disabled]': 'disabled() ? "" : null',
439
+ '[attr.disabled]': 'disabled() || loading() ? "" : null',
175
440
  '[attr.type]': 'type()',
176
441
  '(click)': 'handleClick($event)'
177
442
  }, template: `
178
443
  <span class="studio-button__content">
179
- <ng-content />
444
+ @if (loading()) {
445
+ <studio-icon
446
+ name="loader-2"
447
+ [size]="iconSize()"
448
+ class="studio-button__spinner"
449
+ />
450
+ }
451
+ @if (!loading() && icon() && iconPosition() === 'left') {
452
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
453
+ }
454
+ @if (iconPosition() !== 'only' && !loading()) {
455
+ <ng-content />
456
+ }
457
+ @if (!loading() && icon() && iconPosition() === 'right') {
458
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
459
+ }
460
+ @if (!loading() && icon() && iconPosition() === 'only') {
461
+ <studio-icon [name]="icon()!" [size]="iconSize()" />
462
+ }
463
+ @if (loading() && iconPosition() === 'only') {
464
+ <!-- Empty, spinner already shown -->
465
+ } @else if (loading()) {
466
+ <span>Loading...</span>
467
+ }
180
468
  </span>
181
- `, styles: [":host{display:inline-block}.studio-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast);border-radius:var(--studio-radius-md)}.studio-button:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}.studio-button:active:not(:disabled):not(.studio-button--loading){transform:scale(.98)}.studio-button--sm{padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}.studio-button--md{padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}.studio-button--lg{padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}.studio-button--solid.studio-button--primary{background:var(--studio-primary);color:#fff}.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-primary-hover)}.studio-button--solid.studio-button--primary:active:not(:disabled):not(.studio-button--loading){background:var(--studio-primary-active)}.studio-button--outline.studio-button--primary{background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-primary);color:#fff}.studio-button--ghost.studio-button--primary{background:transparent;color:var(--studio-primary)}.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading){background:#3b82f61a}.studio-button--solid.studio-button--secondary{background:var(--studio-secondary);color:#fff}.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-secondary-hover)}.studio-button--solid.studio-button--secondary:active:not(:disabled):not(.studio-button--loading){background:var(--studio-secondary-active)}.studio-button--outline.studio-button--secondary{background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-secondary);color:#fff}.studio-button--ghost.studio-button--secondary{background:transparent;color:var(--studio-secondary)}.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading){background:#8b5cf61a}.studio-button--solid.studio-button--success{background:var(--studio-success);color:#fff}.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-success-hover)}.studio-button--outline.studio-button--success{background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-success);color:#fff}.studio-button--ghost.studio-button--success{background:transparent;color:var(--studio-success)}.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-success-bg)}.studio-button--solid.studio-button--error{background:var(--studio-error);color:#fff}.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-error-hover)}.studio-button--outline.studio-button--error{background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-error);color:#fff}.studio-button--ghost.studio-button--error{background:transparent;color:var(--studio-error)}.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-error-bg)}.studio-button--solid.studio-button--warning{background:var(--studio-warning);color:#fff}.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-warning-hover)}.studio-button--outline.studio-button--warning{background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-warning);color:#fff}.studio-button--ghost.studio-button--warning{background:transparent;color:var(--studio-warning)}.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading){background:var(--studio-warning-bg)}.studio-button--full{width:100%}.studio-button--loading{cursor:wait;opacity:.7}.studio-button:disabled{opacity:.5;cursor:not-allowed}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}[data-theme=dark] .studio-button--solid.studio-button--primary,[data-theme=dark] .studio-button--solid.studio-button--secondary,[data-theme=dark] .studio-button--solid.studio-button--success,[data-theme=dark] .studio-button--solid.studio-button--error,[data-theme=dark] .studio-button--solid.studio-button--warning{box-shadow:var(--studio-shadow-sm)}\n"] }]
182
- }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
469
+ `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;gap:var(--studio-spacing-sm);font-family:var(--studio-font-family);font-weight:var(--studio-font-weight-medium);border:none;cursor:pointer;-webkit-user-select:none;user-select:none;position:relative;white-space:nowrap;vertical-align:middle;border-radius:var(--studio-radius-md);transition:background-color var(--studio-transition-fast),color var(--studio-transition-fast),border-color var(--studio-transition-fast),box-shadow var(--studio-transition-fast),transform var(--studio-transition-fast)}:host:focus-visible{outline:2px solid var(--studio-primary);outline-offset:2px}:host(.studio-button--sm){padding:var(--studio-spacing-xs) var(--studio-spacing-sm);font-size:var(--studio-font-size-sm);height:2rem;min-width:2rem}:host(.studio-button--md){padding:var(--studio-spacing-sm) var(--studio-spacing-md);font-size:var(--studio-font-size-base);height:2.5rem;min-width:2.5rem}:host(.studio-button--lg){padding:var(--studio-spacing-md) var(--studio-spacing-lg);font-size:var(--studio-font-size-lg);height:3rem;min-width:3rem}:host(.studio-button--solid.studio-button--primary){background:var(--studio-primary);color:#fff}:host(.studio-button--solid.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary-hover)}:host(.studio-button--outline.studio-button--primary){background:transparent;border:1px solid var(--studio-primary);color:var(--studio-primary)}:host(.studio-button--outline.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-primary);color:#fff}:host(.studio-button--ghost.studio-button--primary){background:transparent;color:var(--studio-primary)}:host(.studio-button--ghost.studio-button--primary:hover:not(:disabled):not(.studio-button--loading)){background:#3b82f61a}:host(.studio-button--solid.studio-button--secondary){background:var(--studio-secondary);color:#fff}:host(.studio-button--solid.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary-hover)}:host(.studio-button--outline.studio-button--secondary){background:transparent;border:1px solid var(--studio-secondary);color:var(--studio-secondary)}:host(.studio-button--outline.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-secondary);color:#fff}:host(.studio-button--ghost.studio-button--secondary){background:transparent;color:var(--studio-secondary)}:host(.studio-button--ghost.studio-button--secondary:hover:not(:disabled):not(.studio-button--loading)){background:#8b5cf61a}:host(.studio-button--solid.studio-button--success){background:var(--studio-success);color:#fff}:host(.studio-button--solid.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-hover)}:host(.studio-button--outline.studio-button--success){background:transparent;border:1px solid var(--studio-success);color:var(--studio-success)}:host(.studio-button--outline.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success);color:#fff}:host(.studio-button--ghost.studio-button--success){background:transparent;color:var(--studio-success)}:host(.studio-button--ghost.studio-button--success:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-success-bg)}:host(.studio-button--solid.studio-button--error){background:var(--studio-error);color:#fff}:host(.studio-button--solid.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-hover)}:host(.studio-button--outline.studio-button--error){background:transparent;border:1px solid var(--studio-error);color:var(--studio-error)}:host(.studio-button--outline.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error);color:#fff}:host(.studio-button--ghost.studio-button--error){background:transparent;color:var(--studio-error)}:host(.studio-button--ghost.studio-button--error:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-error-bg)}:host(.studio-button--solid.studio-button--warning){background:var(--studio-warning);color:#fff}:host(.studio-button--solid.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-hover)}:host(.studio-button--outline.studio-button--warning){background:transparent;border:1px solid var(--studio-warning);color:var(--studio-warning)}:host(.studio-button--outline.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning);color:#fff}:host(.studio-button--ghost.studio-button--warning){background:transparent;color:var(--studio-warning)}:host(.studio-button--ghost.studio-button--warning:hover:not(:disabled):not(.studio-button--loading)){background:var(--studio-warning-bg)}:host(.studio-button--full){width:100%}:host(.studio-button--icon-only){padding:0;aspect-ratio:1}:host(.studio-button--icon-only.studio-button--sm){width:2rem;padding:0}:host(.studio-button--icon-only.studio-button--md){width:2.5rem;padding:0}:host(.studio-button--icon-only.studio-button--lg){width:3rem;padding:0}:host(.studio-button--loading){cursor:wait;pointer-events:none}:host([disabled]){opacity:.6;cursor:not-allowed!important;background:var(--studio-bg-secondary)!important;color:var(--studio-text-tertiary)!important;border-color:var(--studio-border-primary)!important}:host([disabled]:hover){transform:none!important;background:var(--studio-bg-secondary)!important}:host(:active:not([disabled]):not(.studio-button--loading)){transform:scale(.98)}.studio-button__content{display:inline-flex;align-items:center;gap:var(--studio-spacing-sm)}.studio-button__spinner{animation:studio-spin 1s linear infinite}@keyframes studio-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
470
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
183
471
 
184
472
  /**
185
473
  * Button component
@@ -216,5 +504,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
216
504
  * Generated bundle index. Do not edit.
217
505
  */
218
506
 
219
- export { ButtonComponent, STUDIO_CONFIG, StudioConfigService, provideStudioConfig };
507
+ export { ButtonComponent, IconComponent, STUDIO_CONFIG, StudioConfigService, provideStudioConfig, provideStudioIcons };
220
508
  //# sourceMappingURL=eduboxpro-studio.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"eduboxpro-studio.mjs","sources":["../../../projects/studio/src/lib/config/studio.config.ts","../../../projects/studio/src/lib/config/studio.service.ts","../../../projects/studio/src/lib/config/provide-studio.ts","../../../projects/studio/src/lib/config/index.ts","../../../projects/studio/src/lib/primitives/button/button.component.ts","../../../projects/studio/src/lib/primitives/button/index.ts","../../../projects/studio/src/lib/primitives/index.ts","../../../projects/studio/src/lib/composites/index.ts","../../../projects/studio/src/lib/education/index.ts","../../../projects/studio/src/lib/utils/index.ts","../../../projects/studio/src/public-api.ts","../../../projects/studio/src/eduboxpro-studio.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\n/**\n * Theme mode: light or dark\n */\nexport type ThemeMode = 'light' | 'dark';\n\n/**\n * Theme configuration interface\n */\nexport interface StudioThemeConfig {\n /**\n * Theme mode (default: 'light')\n */\n mode?: ThemeMode;\n\n /**\n * Color tokens override\n */\n colors?: {\n primary?: string;\n secondary?: string;\n success?: string;\n error?: string;\n warning?: string;\n info?: string;\n };\n\n /**\n * Typography tokens override\n */\n typography?: {\n fontFamily?: string;\n fontSize?: {\n xs?: string;\n sm?: string;\n base?: string;\n lg?: string;\n xl?: string;\n '2xl'?: string;\n };\n fontWeight?: {\n normal?: number;\n medium?: number;\n semibold?: number;\n bold?: number;\n };\n };\n\n /**\n * Spacing tokens override\n */\n spacing?: {\n xs?: string;\n sm?: string;\n md?: string;\n lg?: string;\n xl?: string;\n '2xl'?: string;\n };\n\n /**\n * Border radius tokens override\n */\n borderRadius?: {\n none?: string;\n sm?: string;\n md?: string;\n lg?: string;\n xl?: string;\n full?: string;\n };\n\n /**\n * Shadow tokens override\n */\n shadows?: {\n sm?: string;\n md?: string;\n lg?: string;\n xl?: string;\n };\n}\n\n/**\n * Main Studio configuration interface\n */\nexport interface StudioConfig {\n /**\n * Theme configuration\n */\n theme?: StudioThemeConfig;\n}\n\n/**\n * Injection token for Studio configuration\n */\nexport const STUDIO_CONFIG = new InjectionToken<StudioConfig>('STUDIO_CONFIG', {\n providedIn: 'root',\n factory: () => ({})\n});\n","import { Injectable, inject, signal, effect } from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { StudioConfig, StudioThemeConfig, ThemeMode } from './studio.config';\n\n@Injectable({ providedIn: 'root' })\nexport class StudioConfigService {\n private readonly document = inject(DOCUMENT);\n\n readonly config = signal<StudioConfig>({});\n readonly themeMode = signal<ThemeMode>('light');\n\n constructor() {\n effect(() => {\n this.applyTheme(this.config().theme);\n }, { allowSignalWrites: false });\n }\n\n configure(config: StudioConfig): void {\n this.config.set(config);\n if (config.theme?.mode) {\n this.setThemeMode(config.theme.mode);\n }\n }\n\n setThemeMode(mode: ThemeMode): void {\n this.themeMode.set(mode);\n this.document.documentElement.setAttribute('data-theme', mode);\n }\n\n toggleTheme(): void {\n const newMode = this.themeMode() === 'light' ? 'dark' : 'light';\n this.setThemeMode(newMode);\n }\n\n async loadFromBackend(organizationSlug: string): Promise<void> {\n try {\n const response = await fetch(`/api/organizations/${organizationSlug}/design-config`);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n const config = await response.json();\n this.configure(config);\n } catch (error) {\n console.error('[Studio] Failed to load config from backend:', error);\n throw error;\n }\n }\n\n private applyTheme(theme?: StudioThemeConfig): void {\n if (!theme) return;\n\n const root = this.document.documentElement;\n\n if (theme.colors) {\n this.applyTokens(root, 'studio', theme.colors);\n }\n if (theme.spacing) {\n this.applyTokens(root, 'studio-spacing', theme.spacing);\n }\n if (theme.borderRadius) {\n this.applyTokens(root, 'studio-radius', theme.borderRadius);\n }\n if (theme.shadows) {\n this.applyTokens(root, 'studio-shadow', theme.shadows);\n }\n if (theme.typography?.fontFamily) {\n root.style.setProperty('--studio-font-family', theme.typography.fontFamily);\n }\n if (theme.typography?.fontSize) {\n this.applyTokens(root, 'studio-font-size', theme.typography.fontSize);\n }\n if (theme.typography?.fontWeight) {\n this.applyTokens(root, 'studio-font-weight', theme.typography.fontWeight);\n }\n }\n\n private applyTokens(\n root: HTMLElement,\n prefix: string,\n tokens: Record<string, string | number>\n ): void {\n Object.entries(tokens).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n root.style.setProperty(`--${prefix}-${key}`, String(value));\n }\n });\n }\n}\n","import { EnvironmentProviders, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, inject } from '@angular/core';\nimport { STUDIO_CONFIG, StudioConfig } from './studio.config';\nimport { StudioConfigService } from './studio.service';\n\n/**\n * Provide Studio configuration for the application\n *\n * @example\n * ```typescript\n * // app.config.ts\n * import { provideStudioConfig } from '@eduboxpro/studio/config';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideStudioConfig({\n * theme: {\n * mode: 'light',\n * colors: {\n * primary: '#3b82f6'\n * }\n * }\n * })\n * ]\n * };\n * ```\n */\nexport function provideStudioConfig(config: StudioConfig = {}): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: STUDIO_CONFIG,\n useValue: config\n },\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue: () => {\n const studioConfig = inject(StudioConfigService);\n const initialConfig = inject(STUDIO_CONFIG);\n studioConfig.configure(initialConfig);\n }\n }\n ]);\n}\n","/**\n * Configuration module\n * @module config\n */\n\nexport * from './studio.config';\nexport * from './studio.service';\nexport * from './provide-studio';\n","import { Component, input, output, computed, ChangeDetectionStrategy } from '@angular/core';\n\n@Component({\n selector: 'studio-button',\n standalone: true,\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n '[attr.disabled]': 'disabled() ? \"\" : null',\n '[attr.type]': 'type()',\n '(click)': 'handleClick($event)'\n },\n template: `\n <span class=\"studio-button__content\">\n <ng-content />\n </span>\n `,\n styleUrl: './button.component.scss'\n})\nexport class ButtonComponent {\n variant = input<'solid' | 'outline' | 'ghost'>('solid');\n size = input<'sm' | 'md' | 'lg'>('md');\n color = input<'primary' | 'secondary' | 'success' | 'error' | 'warning'>('primary');\n disabled = input<boolean>(false);\n fullWidth = input<boolean>(false);\n loading = input<boolean>(false);\n type = input<'button' | 'submit' | 'reset'>('button');\n\n clicked = output<MouseEvent>();\n\n protected hostClasses = computed(() => {\n return [\n 'studio-button',\n `studio-button--${this.variant()}`,\n `studio-button--${this.size()}`,\n `studio-button--${this.color()}`,\n this.fullWidth() ? 'studio-button--full' : '',\n this.loading() ? 'studio-button--loading' : ''\n ].filter(Boolean).join(' ');\n });\n\n protected handleClick(event: MouseEvent): void {\n if (this.disabled() || this.loading()) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.clicked.emit(event);\n }\n}\n","/**\n * Button component\n */\n\nexport * from './button.component';\n","/**\n * Primitives (Atoms)\n * Basic building blocks\n */\n\nexport * from './button';\n","/**\n * Composites (Molecules + Organisms)\n * Complex components built from primitives\n */\n\n// Export composite components here\n// Example: export * from './form-field';\n\n// Empty export to make this a valid module\nexport {};\n","/**\n * Education components\n * Domain-specific components for educational platforms\n */\n\n// Export education components here\n// Example: export * from './course-card';\n// Example: export * from './lesson-viewer';\n// Example: export * from './quiz-builder';\n\n// Empty export to make this a valid module\nexport {};\n","/**\n * Utilities\n * Helper functions, directives, pipes\n */\n\n// Export utilities here\n// Example: export * from './format-date.pipe';\n// Example: export * from './auto-focus.directive';\n\n// Empty export to make this a valid module\nexport {};\n","/**\n * Public API Surface of @eduboxpro/studio\n */\n\n/* ========================================\n * Configuration\n * ======================================== */\nexport * from './lib/config';\n\n/* ========================================\n * Components\n * ======================================== */\nexport * from './lib/primitives';\nexport * from './lib/composites';\nexport * from './lib/education';\n\n/* ========================================\n * Utilities\n * ======================================== */\nexport * from './lib/utils';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"eduboxpro-studio.mjs","sources":["../../../projects/studio/src/lib/config/studio.config.ts","../../../projects/studio/src/lib/config/studio.service.ts","../../../projects/studio/src/lib/config/provide-studio.ts","../../../projects/studio/src/lib/config/index.ts","../../../projects/studio/src/lib/primitives/icon/icon.component.ts","../../../projects/studio/src/lib/primitives/icon/icon.provider.ts","../../../projects/studio/src/lib/primitives/button/button.component.ts","../../../projects/studio/src/lib/primitives/button/index.ts","../../../projects/studio/src/lib/primitives/index.ts","../../../projects/studio/src/lib/composites/index.ts","../../../projects/studio/src/lib/education/index.ts","../../../projects/studio/src/lib/utils/index.ts","../../../projects/studio/src/public-api.ts","../../../projects/studio/src/eduboxpro-studio.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\n/**\n * Theme mode: light or dark\n */\nexport type ThemeMode = 'light' | 'dark';\n\n/**\n * Color configuration with hover and active states\n */\nexport interface ColorConfig {\n base?: string;\n hover?: string;\n active?: string;\n bg?: string;\n}\n\n/**\n * Theme configuration interface\n */\nexport interface StudioThemeConfig {\n /**\n * Theme mode (default: 'light')\n */\n mode?: ThemeMode;\n\n /**\n * Color tokens override with hover/active states\n */\n colors?: {\n primary?: ColorConfig | string;\n secondary?: ColorConfig | string;\n success?: ColorConfig | string;\n error?: ColorConfig | string;\n warning?: ColorConfig | string;\n info?: ColorConfig | string;\n bg?: {\n primary?: string;\n secondary?: string;\n tertiary?: string;\n };\n text?: {\n primary?: string;\n secondary?: string;\n tertiary?: string;\n inverse?: string;\n };\n border?: {\n primary?: string;\n secondary?: string;\n };\n };\n\n /**\n * Typography tokens override\n */\n typography?: {\n fontFamily?: string;\n fontMono?: string;\n fontSize?: {\n xs?: string;\n sm?: string;\n base?: string;\n lg?: string;\n xl?: string;\n '2xl'?: string;\n };\n fontWeight?: {\n normal?: number;\n medium?: number;\n semibold?: number;\n bold?: number;\n };\n lineHeight?: {\n tight?: number;\n normal?: number;\n relaxed?: number;\n };\n };\n\n /**\n * Spacing tokens override\n */\n spacing?: {\n xs?: string;\n sm?: string;\n md?: string;\n lg?: string;\n xl?: string;\n '2xl'?: string;\n };\n\n /**\n * Border radius tokens override\n */\n borderRadius?: {\n none?: string;\n sm?: string;\n md?: string;\n lg?: string;\n xl?: string;\n full?: string;\n };\n\n /**\n * Shadow tokens override\n */\n shadows?: {\n sm?: string;\n md?: string;\n lg?: string;\n xl?: string;\n };\n\n /**\n * Transition tokens override\n */\n transitions?: {\n fast?: string;\n base?: string;\n slow?: string;\n };\n\n /**\n * Z-index tokens override\n */\n zIndex?: {\n dropdown?: number;\n sticky?: number;\n fixed?: number;\n modalBackdrop?: number;\n modal?: number;\n popover?: number;\n tooltip?: number;\n };\n}\n\n/**\n * Main Studio configuration interface\n */\nexport interface StudioConfig {\n /**\n * Theme configuration\n */\n theme?: StudioThemeConfig;\n}\n\n/**\n * Injection token for Studio configuration\n */\nexport const STUDIO_CONFIG = new InjectionToken<StudioConfig>('STUDIO_CONFIG', {\n providedIn: 'root',\n factory: () => ({})\n});\n","import { Injectable, inject, signal, effect } from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { StudioConfig, StudioThemeConfig, ThemeMode, ColorConfig } from './studio.config';\n\n@Injectable({ providedIn: 'root' })\nexport class StudioConfigService {\n private readonly document = inject(DOCUMENT);\n\n readonly config = signal<StudioConfig>({});\n readonly themeMode = signal<ThemeMode>('light');\n\n constructor() {\n effect(() => {\n this.applyTheme(this.config().theme);\n }, { allowSignalWrites: false });\n }\n\n configure(config: StudioConfig): void {\n this.config.set(config);\n if (config.theme?.mode) {\n this.setThemeMode(config.theme.mode);\n }\n }\n\n setThemeMode(mode: ThemeMode): void {\n this.themeMode.set(mode);\n this.document.documentElement.setAttribute('data-theme', mode);\n }\n\n toggleTheme(): void {\n const newMode = this.themeMode() === 'light' ? 'dark' : 'light';\n this.setThemeMode(newMode);\n }\n\n async loadFromBackend(organizationSlug: string): Promise<void> {\n try {\n const response = await fetch(`/api/organizations/${organizationSlug}/design-config`);\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n const config = await response.json();\n this.configure(config);\n } catch (error) {\n console.error('[Studio] Failed to load config from backend:', error);\n throw error;\n }\n }\n\n private applyTheme(theme?: StudioThemeConfig): void {\n if (!theme) return;\n\n const root = this.document.documentElement;\n\n // Apply colors\n if (theme.colors) {\n this.applyColorTokens(root, theme.colors);\n }\n\n // Apply typography\n if (theme.typography) {\n if (theme.typography.fontFamily) {\n root.style.setProperty('--studio-font-family', theme.typography.fontFamily);\n }\n if (theme.typography.fontMono) {\n root.style.setProperty('--studio-font-mono', theme.typography.fontMono);\n }\n if (theme.typography.fontSize) {\n this.applyTokens(root, 'studio-font-size', theme.typography.fontSize);\n }\n if (theme.typography.fontWeight) {\n this.applyTokens(root, 'studio-font-weight', theme.typography.fontWeight);\n }\n if (theme.typography.lineHeight) {\n this.applyTokens(root, 'studio-line-height', theme.typography.lineHeight);\n }\n }\n\n // Apply spacing\n if (theme.spacing) {\n this.applyTokens(root, 'studio-spacing', theme.spacing);\n }\n\n // Apply border radius\n if (theme.borderRadius) {\n this.applyTokens(root, 'studio-radius', theme.borderRadius);\n }\n\n // Apply shadows\n if (theme.shadows) {\n this.applyTokens(root, 'studio-shadow', theme.shadows);\n }\n\n // Apply transitions\n if (theme.transitions) {\n this.applyTokens(root, 'studio-transition', theme.transitions);\n }\n\n // Apply z-index\n if (theme.zIndex) {\n this.applyZIndexTokens(root, theme.zIndex);\n }\n }\n\n private applyColorTokens(\n root: HTMLElement,\n colors: NonNullable<StudioThemeConfig['colors']>\n ): void {\n // Brand colors with hover/active states\n const brandColors = ['primary', 'secondary', 'success', 'error', 'warning', 'info'] as const;\n\n brandColors.forEach(colorName => {\n const colorValue = colors[colorName];\n if (!colorValue) return;\n\n if (typeof colorValue === 'string') {\n root.style.setProperty(`--studio-${colorName}`, colorValue);\n } else {\n const config = colorValue as ColorConfig;\n if (config.base) {\n root.style.setProperty(`--studio-${colorName}`, config.base);\n }\n if (config.hover) {\n root.style.setProperty(`--studio-${colorName}-hover`, config.hover);\n }\n if (config.active) {\n root.style.setProperty(`--studio-${colorName}-active`, config.active);\n }\n if (config.bg) {\n root.style.setProperty(`--studio-${colorName}-bg`, config.bg);\n }\n }\n });\n\n // Background colors\n if (colors.bg) {\n this.applyTokens(root, 'studio-bg', colors.bg);\n }\n\n // Text colors\n if (colors.text) {\n this.applyTokens(root, 'studio-text', colors.text);\n }\n\n // Border colors\n if (colors.border) {\n this.applyTokens(root, 'studio-border', colors.border);\n }\n }\n\n private applyZIndexTokens(\n root: HTMLElement,\n zIndex: NonNullable<StudioThemeConfig['zIndex']>\n ): void {\n const zIndexMap: Record<string, string> = {\n dropdown: 'dropdown',\n sticky: 'sticky',\n fixed: 'fixed',\n modalBackdrop: 'modal-backdrop',\n modal: 'modal',\n popover: 'popover',\n tooltip: 'tooltip'\n };\n\n Object.entries(zIndex).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n const cssKey = zIndexMap[key] || key;\n root.style.setProperty(`--studio-z-${cssKey}`, String(value));\n }\n });\n }\n\n private applyTokens(\n root: HTMLElement,\n prefix: string,\n tokens: Record<string, string | number>\n ): void {\n Object.entries(tokens).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n root.style.setProperty(`--${prefix}-${key}`, String(value));\n }\n });\n }\n}\n","import { EnvironmentProviders, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, inject } from '@angular/core';\nimport { STUDIO_CONFIG, StudioConfig } from './studio.config';\nimport { StudioConfigService } from './studio.service';\n\n/**\n * Provide Studio configuration for the application\n *\n * @example\n * ```typescript\n * // app.config.ts\n * import { provideStudioConfig } from '@eduboxpro/studio/config';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideStudioConfig({\n * theme: {\n * mode: 'light',\n * colors: {\n * primary: '#3b82f6'\n * }\n * }\n * })\n * ]\n * };\n * ```\n */\nexport function provideStudioConfig(config: StudioConfig = {}): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: STUDIO_CONFIG,\n useValue: config\n },\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue: () => {\n const studioConfig = inject(StudioConfigService);\n const initialConfig = inject(STUDIO_CONFIG);\n studioConfig.configure(initialConfig);\n }\n }\n ]);\n}\n","/**\n * Configuration module\n * @module config\n */\n\nexport * from './studio.config';\nexport * from './studio.service';\nexport * from './provide-studio';\n","import { Component, ChangeDetectionStrategy, input, computed } from '@angular/core';\nimport { LucideAngularModule, icons } from 'lucide-angular';\n\n@Component({\n selector: 'studio-icon',\n standalone: true,\n imports: [LucideAngularModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n '[style.width.px]': 'size()',\n '[style.height.px]': 'size()',\n },\n template: `\n @if (lucideIcon(); as iconName) {\n <lucide-icon\n [name]=\"iconName\"\n [size]=\"size()\"\n [color]=\"computedColor()\"\n [strokeWidth]=\"strokeWidth()\"\n [absoluteStrokeWidth]=\"absoluteStrokeWidth()\"\n />\n }\n `,\n styles: [`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n `]\n})\nexport class IconComponent {\n name = input.required<string>();\n size = input<number>(24);\n color = input<'primary' | 'secondary' | 'success' | 'error' | 'warning' | 'inherit' | string>('inherit');\n strokeWidth = input<number>(2);\n absoluteStrokeWidth = input<boolean>(false);\n\n protected readonly icons = icons;\n\n protected lucideIcon = computed(() => {\n const iconName = this.name();\n return iconName;\n });\n\n protected computedColor = computed(() => {\n const colorValue = this.color();\n\n const colorMap: Record<string, string> = {\n 'primary': 'var(--studio-primary)',\n 'secondary': 'var(--studio-secondary)',\n 'success': 'var(--studio-success)',\n 'error': 'var(--studio-error)',\n 'warning': 'var(--studio-warning)',\n 'inherit': 'currentColor'\n };\n\n return colorMap[colorValue] || colorValue;\n });\n\n protected hostClasses = computed(() => {\n return ['studio-icon'];\n });\n}\n","import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\nimport { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';\nimport {\n ArrowRight,\n ArrowLeft,\n ChevronDown,\n ChevronUp,\n ChevronLeft,\n ChevronRight,\n Download,\n Upload,\n Mail,\n Phone,\n Heart,\n Star,\n Settings,\n User,\n Trash2,\n Edit,\n Plus,\n Minus,\n Check,\n X,\n Search,\n Filter,\n ExternalLink,\n Link,\n Copy,\n Share2,\n Home,\n Menu,\n MoreVertical,\n MoreHorizontal,\n Bell,\n Calendar,\n Clock,\n Eye,\n EyeOff,\n Lock,\n Unlock,\n LogIn,\n LogOut,\n AlertCircle,\n AlertTriangle,\n Info,\n CheckCircle,\n XCircle,\n HelpCircle,\n File,\n FileText,\n Folder,\n Image,\n Save,\n Printer,\n RefreshCw,\n RotateCw,\n Loader,\n Loader2\n} from 'lucide-angular';\n\n/**\n * Провайдер иконок для Studio\n * Регистрирует базовый набор часто используемых иконок\n *\n * @example\n * ```typescript\n * // app.config.ts\n * import { provideStudioIcons } from '@eduboxpro/studio';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideStudioIcons()\n * ]\n * };\n * ```\n *\n * Для добавления дополнительных иконок:\n * @example\n * ```typescript\n * import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';\n * import { Zap, Wifi } from 'lucide-angular';\n *\n * providers: [\n * provideStudioIcons(),\n * {\n * provide: LUCIDE_ICONS,\n * multi: true,\n * useValue: new LucideIconProvider({ Zap, Wifi })\n * }\n * ]\n * ```\n */\nexport function provideStudioIcons(): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: LUCIDE_ICONS,\n multi: true,\n useValue: new LucideIconProvider({\n ArrowRight,\n ArrowLeft,\n ChevronDown,\n ChevronUp,\n ChevronLeft,\n ChevronRight,\n Download,\n Upload,\n Mail,\n Phone,\n Heart,\n Star,\n Settings,\n User,\n Trash2,\n Edit,\n Plus,\n Minus,\n Check,\n X,\n Search,\n Filter,\n ExternalLink,\n Link,\n Copy,\n Share2,\n Home,\n Menu,\n MoreVertical,\n MoreHorizontal,\n Bell,\n Calendar,\n Clock,\n Eye,\n EyeOff,\n Lock,\n Unlock,\n LogIn,\n LogOut,\n AlertCircle,\n AlertTriangle,\n Info,\n CheckCircle,\n XCircle,\n HelpCircle,\n File,\n FileText,\n Folder,\n Image,\n Save,\n Printer,\n RefreshCw,\n RotateCw,\n Loader,\n Loader2\n })\n }\n ]);\n}\n","import { Component, input, output, computed, ChangeDetectionStrategy } from '@angular/core';\nimport { IconComponent } from '../icon';\n\n@Component({\n selector: 'studio-button',\n standalone: true,\n imports: [IconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n '[attr.disabled]': 'disabled() || loading() ? \"\" : null',\n '[attr.type]': 'type()',\n '(click)': 'handleClick($event)'\n },\n template: `\n <span class=\"studio-button__content\">\n @if (loading()) {\n <studio-icon\n name=\"loader-2\"\n [size]=\"iconSize()\"\n class=\"studio-button__spinner\"\n />\n }\n @if (!loading() && icon() && iconPosition() === 'left') {\n <studio-icon [name]=\"icon()!\" [size]=\"iconSize()\" />\n }\n @if (iconPosition() !== 'only' && !loading()) {\n <ng-content />\n }\n @if (!loading() && icon() && iconPosition() === 'right') {\n <studio-icon [name]=\"icon()!\" [size]=\"iconSize()\" />\n }\n @if (!loading() && icon() && iconPosition() === 'only') {\n <studio-icon [name]=\"icon()!\" [size]=\"iconSize()\" />\n }\n @if (loading() && iconPosition() === 'only') {\n <!-- Empty, spinner already shown -->\n } @else if (loading()) {\n <span>Loading...</span>\n }\n </span>\n `,\n styleUrl: './button.component.scss'\n})\nexport class ButtonComponent {\n variant = input<'solid' | 'outline' | 'ghost'>('solid');\n size = input<'sm' | 'md' | 'lg'>('md');\n color = input<'primary' | 'secondary' | 'success' | 'error' | 'warning'>('primary');\n disabled = input<boolean>(false);\n fullWidth = input<boolean>(false);\n loading = input<boolean>(false);\n type = input<'button' | 'submit' | 'reset'>('button');\n icon = input<string>();\n iconPosition = input<'left' | 'right' | 'only'>('left');\n\n clicked = output<MouseEvent>();\n\n protected iconSize = computed(() => {\n const sizeMap = { sm: 16, md: 18, lg: 20 };\n return sizeMap[this.size()];\n });\n\n protected hostClasses = computed(() => {\n return [\n 'studio-button',\n `studio-button--${this.variant()}`,\n `studio-button--${this.size()}`,\n `studio-button--${this.color()}`,\n this.fullWidth() ? 'studio-button--full' : '',\n this.loading() ? 'studio-button--loading' : '',\n this.iconPosition() === 'only' ? 'studio-button--icon-only' : ''\n ].filter(Boolean).join(' ');\n });\n\n protected handleClick(event: MouseEvent): void {\n if (this.disabled() || this.loading()) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n this.clicked.emit(event);\n }\n}\n","/**\n * Button component\n */\n\nexport * from './button.component';\n","/**\n * Primitives (Atoms)\n * Basic building blocks\n */\n\nexport * from './button';\nexport * from './icon';\n","/**\n * Composites (Molecules + Organisms)\n * Complex components built from primitives\n */\n\n// Export composite components here\n// Example: export * from './form-field';\n\n// Empty export to make this a valid module\nexport {};\n","/**\n * Education components\n * Domain-specific components for educational platforms\n */\n\n// Export education components here\n// Example: export * from './course-card';\n// Example: export * from './lesson-viewer';\n// Example: export * from './quiz-builder';\n\n// Empty export to make this a valid module\nexport {};\n","/**\n * Utilities\n * Helper functions, directives, pipes\n */\n\n// Export utilities here\n// Example: export * from './format-date.pipe';\n// Example: export * from './auto-focus.directive';\n\n// Empty export to make this a valid module\nexport {};\n","/**\n * Public API Surface of @eduboxpro/studio\n */\n\n/* ========================================\n * Configuration\n * ======================================== */\nexport * from './lib/config';\n\n/* ========================================\n * Components\n * ======================================== */\nexport * from './lib/primitives';\nexport * from './lib/composites';\nexport * from './lib/education';\n\n/* ========================================\n * Utilities\n * ======================================== */\nexport * from './lib/utils';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAmJA;;AAEG;MACU,aAAa,GAAG,IAAI,cAAc,CAAe,eAAe,EAAE;AAC7E,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,OAAO,EAAE;AACnB,CAAA;;MCpJY,mBAAmB,CAAA;AACb,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAEnC,IAAA,MAAM,GAAG,MAAM,CAAe,EAAE,kDAAC;AACjC,IAAA,SAAS,GAAG,MAAM,CAAY,OAAO,qDAAC;AAE/C,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC;AACtC,QAAA,CAAC,EAAE,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC;IAClC;AAEA,IAAA,SAAS,CAAC,MAAoB,EAAA;AAC5B,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;AACvB,QAAA,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE;YACtB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QACtC;IACF;AAEA,IAAA,YAAY,CAAC,IAAe,EAAA;AAC1B,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC;IAChE;IAEA,WAAW,GAAA;AACT,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO;AAC/D,QAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;IAC5B;IAEA,MAAM,eAAe,CAAC,gBAAwB,EAAA;AAC5C,QAAA,IAAI;YACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,mBAAA,EAAsB,gBAAgB,CAAA,cAAA,CAAgB,CAAC;AACpF,YAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;gBAChB,MAAM,IAAI,KAAK,CAAC,CAAA,oBAAA,EAAuB,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC;YAC3D;AACA,YAAA,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE;AACpC,YAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QACxB;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC;AACpE,YAAA,MAAM,KAAK;QACb;IACF;AAEQ,IAAA,UAAU,CAAC,KAAyB,EAAA;AAC1C,QAAA,IAAI,CAAC,KAAK;YAAE;AAEZ,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe;;AAG1C,QAAA,IAAI,KAAK,CAAC,MAAM,EAAE;YAChB,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;QAC3C;;AAGA,QAAA,IAAI,KAAK,CAAC,UAAU,EAAE;AACpB,YAAA,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE;AAC/B,gBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,sBAAsB,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC;YAC7E;AACA,YAAA,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE;AAC7B,gBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,oBAAoB,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;YACzE;AACA,YAAA,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,EAAE;AAC7B,gBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;YACvE;AACA,YAAA,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE;AAC/B,gBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC;YAC3E;AACA,YAAA,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,EAAE;AAC/B,gBAAA,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC;YAC3E;QACF;;AAGA,QAAA,IAAI,KAAK,CAAC,OAAO,EAAE;YACjB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC;QACzD;;AAGA,QAAA,IAAI,KAAK,CAAC,YAAY,EAAE;YACtB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,YAAY,CAAC;QAC7D;;AAGA,QAAA,IAAI,KAAK,CAAC,OAAO,EAAE;YACjB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC;QACxD;;AAGA,QAAA,IAAI,KAAK,CAAC,WAAW,EAAE;YACrB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,KAAK,CAAC,WAAW,CAAC;QAChE;;AAGA,QAAA,IAAI,KAAK,CAAC,MAAM,EAAE;YAChB,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;QAC5C;IACF;IAEQ,gBAAgB,CACtB,IAAiB,EACjB,MAAgD,EAAA;;AAGhD,QAAA,MAAM,WAAW,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAU;AAE5F,QAAA,WAAW,CAAC,OAAO,CAAC,SAAS,IAAG;AAC9B,YAAA,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC;AACpC,YAAA,IAAI,CAAC,UAAU;gBAAE;AAEjB,YAAA,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE;gBAClC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,SAAA,EAAY,SAAS,CAAA,CAAE,EAAE,UAAU,CAAC;YAC7D;iBAAO;gBACL,MAAM,MAAM,GAAG,UAAyB;AACxC,gBAAA,IAAI,MAAM,CAAC,IAAI,EAAE;AACf,oBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,SAAA,EAAY,SAAS,CAAA,CAAE,EAAE,MAAM,CAAC,IAAI,CAAC;gBAC9D;AACA,gBAAA,IAAI,MAAM,CAAC,KAAK,EAAE;AAChB,oBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,SAAA,EAAY,SAAS,CAAA,MAAA,CAAQ,EAAE,MAAM,CAAC,KAAK,CAAC;gBACrE;AACA,gBAAA,IAAI,MAAM,CAAC,MAAM,EAAE;AACjB,oBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,SAAA,EAAY,SAAS,CAAA,OAAA,CAAS,EAAE,MAAM,CAAC,MAAM,CAAC;gBACvE;AACA,gBAAA,IAAI,MAAM,CAAC,EAAE,EAAE;AACb,oBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,SAAA,EAAY,SAAS,CAAA,GAAA,CAAK,EAAE,MAAM,CAAC,EAAE,CAAC;gBAC/D;YACF;AACF,QAAA,CAAC,CAAC;;AAGF,QAAA,IAAI,MAAM,CAAC,EAAE,EAAE;YACb,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC;QAChD;;AAGA,QAAA,IAAI,MAAM,CAAC,IAAI,EAAE;YACf,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC;QACpD;;AAGA,QAAA,IAAI,MAAM,CAAC,MAAM,EAAE;YACjB,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC;QACxD;IACF;IAEQ,iBAAiB,CACvB,IAAiB,EACjB,MAAgD,EAAA;AAEhD,QAAA,MAAM,SAAS,GAA2B;AACxC,YAAA,QAAQ,EAAE,UAAU;AACpB,YAAA,MAAM,EAAE,QAAQ;AAChB,YAAA,KAAK,EAAE,OAAO;AACd,YAAA,aAAa,EAAE,gBAAgB;AAC/B,YAAA,KAAK,EAAE,OAAO;AACd,YAAA,OAAO,EAAE,SAAS;AAClB,YAAA,OAAO,EAAE;SACV;AAED,QAAA,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;YAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;gBACzC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG;AACpC,gBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA,WAAA,EAAc,MAAM,CAAA,CAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/D;AACF,QAAA,CAAC,CAAC;IACJ;AAEQ,IAAA,WAAW,CACjB,IAAiB,EACjB,MAAc,EACd,MAAuC,EAAA;AAEvC,QAAA,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;YAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE;AACzC,gBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7D;AACF,QAAA,CAAC,CAAC;IACJ;wGAhLW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,cADN,MAAM,EAAA,CAAA;;4FACnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACAlC;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,mBAAmB,CAAC,MAAA,GAAuB,EAAE,EAAA;AAC3D,IAAA,OAAO,wBAAwB,CAAC;AAC9B,QAAA;AACE,YAAA,OAAO,EAAE,aAAa;AACtB,YAAA,QAAQ,EAAE;AACX,SAAA;AACD,QAAA;AACE,YAAA,OAAO,EAAE,uBAAuB;AAChC,YAAA,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,MAAK;AACb,gBAAA,MAAM,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC;AAChD,gBAAA,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;AAC3C,gBAAA,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC;YACvC;AACD;AACF,KAAA,CAAC;AACJ;;AC1CA;;;AAGG;;MC8BU,aAAa,CAAA;AACxB,IAAA,IAAI,GAAG,KAAK,CAAC,QAAQ,+CAAU;AAC/B,IAAA,IAAI,GAAG,KAAK,CAAS,EAAE,gDAAC;AACxB,IAAA,KAAK,GAAG,KAAK,CAAiF,SAAS,iDAAC;AACxG,IAAA,WAAW,GAAG,KAAK,CAAS,CAAC,uDAAC;AAC9B,IAAA,mBAAmB,GAAG,KAAK,CAAU,KAAK,+DAAC;IAExB,KAAK,GAAG,KAAK;AAEtB,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAK;AACnC,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE;AAC5B,QAAA,OAAO,QAAQ;AACjB,IAAA,CAAC,sDAAC;AAEQ,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AACtC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,EAAE;AAE/B,QAAA,MAAM,QAAQ,GAA2B;AACvC,YAAA,SAAS,EAAE,uBAAuB;AAClC,YAAA,WAAW,EAAE,yBAAyB;AACtC,YAAA,SAAS,EAAE,uBAAuB;AAClC,YAAA,OAAO,EAAE,qBAAqB;AAC9B,YAAA,SAAS,EAAE,uBAAuB;AAClC,YAAA,SAAS,EAAE;SACZ;AAED,QAAA,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU;AAC3C,IAAA,CAAC,yDAAC;AAEQ,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QACpC,OAAO,CAAC,aAAa,CAAC;AACxB,IAAA,CAAC,uDAAC;wGA/BS,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,mBAAA,EAAA,EAAA,iBAAA,EAAA,qBAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EApBd;;;;;;;;;;AAUT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,sFAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAjBS,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,sBAAA,EAAA,QAAA,EAAA,oDAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FA2BlB,aAAa,EAAA,UAAA,EAAA,CAAA;kBA9BzB,SAAS;+BACE,aAAa,EAAA,UAAA,EACX,IAAI,EAAA,OAAA,EACP,CAAC,mBAAmB,CAAC,EAAA,eAAA,EACb,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,SAAS,EAAE,eAAe;AAC1B,wBAAA,kBAAkB,EAAE,QAAQ;AAC5B,wBAAA,mBAAmB,EAAE,QAAQ;qBAC9B,EAAA,QAAA,EACS;;;;;;;;;;AAUT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,sFAAA,CAAA,EAAA;;;ACqCH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;SACa,kBAAkB,GAAA;AAChC,IAAA,OAAO,wBAAwB,CAAC;AAC9B,QAAA;AACE,YAAA,OAAO,EAAE,YAAY;AACrB,YAAA,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,IAAI,kBAAkB,CAAC;gBAC/B,UAAU;gBACV,SAAS;gBACT,WAAW;gBACX,SAAS;gBACT,WAAW;gBACX,YAAY;gBACZ,QAAQ;gBACR,MAAM;gBACN,IAAI;gBACJ,KAAK;gBACL,KAAK;gBACL,IAAI;gBACJ,QAAQ;gBACR,IAAI;gBACJ,MAAM;gBACN,IAAI;gBACJ,IAAI;gBACJ,KAAK;gBACL,KAAK;gBACL,CAAC;gBACD,MAAM;gBACN,MAAM;gBACN,YAAY;gBACZ,IAAI;gBACJ,IAAI;gBACJ,MAAM;gBACN,IAAI;gBACJ,IAAI;gBACJ,YAAY;gBACZ,cAAc;gBACd,IAAI;gBACJ,QAAQ;gBACR,KAAK;gBACL,GAAG;gBACH,MAAM;gBACN,IAAI;gBACJ,MAAM;gBACN,KAAK;gBACL,MAAM;gBACN,WAAW;gBACX,aAAa;gBACb,IAAI;gBACJ,WAAW;gBACX,OAAO;gBACP,UAAU;gBACV,IAAI;gBACJ,QAAQ;gBACR,MAAM;gBACN,KAAK;gBACL,IAAI;gBACJ,OAAO;gBACP,SAAS;gBACT,QAAQ;gBACR,MAAM;gBACN;aACD;AACF;AACF,KAAA,CAAC;AACJ;;MChHa,eAAe,CAAA;AAC1B,IAAA,OAAO,GAAG,KAAK,CAAgC,OAAO,mDAAC;AACvD,IAAA,IAAI,GAAG,KAAK,CAAqB,IAAI,gDAAC;AACtC,IAAA,KAAK,GAAG,KAAK,CAA4D,SAAS,iDAAC;AACnF,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,oDAAC;AAChC,IAAA,SAAS,GAAG,KAAK,CAAU,KAAK,qDAAC;AACjC,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,mDAAC;AAC/B,IAAA,IAAI,GAAG,KAAK,CAAgC,QAAQ,gDAAC;IACrD,IAAI,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,MAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAU;AACtB,IAAA,YAAY,GAAG,KAAK,CAA4B,MAAM,wDAAC;IAEvD,OAAO,GAAG,MAAM,EAAc;AAEpB,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;AACjC,QAAA,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;AAC1C,QAAA,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAC7B,IAAA,CAAC,oDAAC;AAEQ,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QACpC,OAAO;YACL,eAAe;AACf,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,OAAO,EAAE,CAAA,CAAE;AAClC,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;AAC/B,YAAA,CAAA,eAAA,EAAkB,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;YAChC,IAAI,CAAC,SAAS,EAAE,GAAG,qBAAqB,GAAG,EAAE;YAC7C,IAAI,CAAC,OAAO,EAAE,GAAG,wBAAwB,GAAG,EAAE;AAC9C,YAAA,IAAI,CAAC,YAAY,EAAE,KAAK,MAAM,GAAG,0BAA0B,GAAG;SAC/D,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7B,IAAA,CAAC,uDAAC;AAEQ,IAAA,WAAW,CAAC,KAAiB,EAAA;QACrC,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;YACrC,KAAK,CAAC,cAAc,EAAE;YACtB,KAAK,CAAC,eAAe,EAAE;YACvB;QACF;AACA,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1B;wGArCW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,qBAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,eAAA,EAAA,eAAA,EAAA,uCAAA,EAAA,WAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA9BhB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,ixLAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAnCS,aAAa,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,OAAA,EAAA,aAAA,EAAA,qBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;4FAsCZ,eAAe,EAAA,UAAA,EAAA,CAAA;kBAzC3B,SAAS;+BACE,eAAe,EAAA,UAAA,EACb,IAAI,EAAA,OAAA,EACP,CAAC,aAAa,CAAC,EAAA,eAAA,EACP,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,SAAS,EAAE,eAAe;AAC1B,wBAAA,iBAAiB,EAAE,qCAAqC;AACxD,wBAAA,aAAa,EAAE,QAAQ;AACvB,wBAAA,SAAS,EAAE;qBACZ,EAAA,QAAA,EACS;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,ixLAAA,CAAA,EAAA;;;ACzCH;;AAEG;;ACFH;;;AAGG;;ACHH;;;AAGG;;ACHH;;;AAGG;;ACHH;;;AAGG;;ACHH;;AAEG;AAEH;;AAE8C;;ACN9C;;AAEG;;;;"}
package/index.d.ts CHANGED
@@ -1,10 +1,20 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { InjectionToken, EnvironmentProviders } from '@angular/core';
3
+ import { icons } from 'lucide-angular';
3
4
 
4
5
  /**
5
6
  * Theme mode: light or dark
6
7
  */
7
8
  type ThemeMode = 'light' | 'dark';
9
+ /**
10
+ * Color configuration with hover and active states
11
+ */
12
+ interface ColorConfig {
13
+ base?: string;
14
+ hover?: string;
15
+ active?: string;
16
+ bg?: string;
17
+ }
8
18
  /**
9
19
  * Theme configuration interface
10
20
  */
@@ -14,21 +24,37 @@ interface StudioThemeConfig {
14
24
  */
15
25
  mode?: ThemeMode;
16
26
  /**
17
- * Color tokens override
27
+ * Color tokens override with hover/active states
18
28
  */
19
29
  colors?: {
20
- primary?: string;
21
- secondary?: string;
22
- success?: string;
23
- error?: string;
24
- warning?: string;
25
- info?: string;
30
+ primary?: ColorConfig | string;
31
+ secondary?: ColorConfig | string;
32
+ success?: ColorConfig | string;
33
+ error?: ColorConfig | string;
34
+ warning?: ColorConfig | string;
35
+ info?: ColorConfig | string;
36
+ bg?: {
37
+ primary?: string;
38
+ secondary?: string;
39
+ tertiary?: string;
40
+ };
41
+ text?: {
42
+ primary?: string;
43
+ secondary?: string;
44
+ tertiary?: string;
45
+ inverse?: string;
46
+ };
47
+ border?: {
48
+ primary?: string;
49
+ secondary?: string;
50
+ };
26
51
  };
27
52
  /**
28
53
  * Typography tokens override
29
54
  */
30
55
  typography?: {
31
56
  fontFamily?: string;
57
+ fontMono?: string;
32
58
  fontSize?: {
33
59
  xs?: string;
34
60
  sm?: string;
@@ -43,6 +69,11 @@ interface StudioThemeConfig {
43
69
  semibold?: number;
44
70
  bold?: number;
45
71
  };
72
+ lineHeight?: {
73
+ tight?: number;
74
+ normal?: number;
75
+ relaxed?: number;
76
+ };
46
77
  };
47
78
  /**
48
79
  * Spacing tokens override
@@ -75,6 +106,26 @@ interface StudioThemeConfig {
75
106
  lg?: string;
76
107
  xl?: string;
77
108
  };
109
+ /**
110
+ * Transition tokens override
111
+ */
112
+ transitions?: {
113
+ fast?: string;
114
+ base?: string;
115
+ slow?: string;
116
+ };
117
+ /**
118
+ * Z-index tokens override
119
+ */
120
+ zIndex?: {
121
+ dropdown?: number;
122
+ sticky?: number;
123
+ fixed?: number;
124
+ modalBackdrop?: number;
125
+ modal?: number;
126
+ popover?: number;
127
+ tooltip?: number;
128
+ };
78
129
  }
79
130
  /**
80
131
  * Main Studio configuration interface
@@ -100,6 +151,8 @@ declare class StudioConfigService {
100
151
  toggleTheme(): void;
101
152
  loadFromBackend(organizationSlug: string): Promise<void>;
102
153
  private applyTheme;
154
+ private applyColorTokens;
155
+ private applyZIndexTokens;
103
156
  private applyTokens;
104
157
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<StudioConfigService, never>;
105
158
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<StudioConfigService>;
@@ -131,18 +184,69 @@ declare function provideStudioConfig(config?: StudioConfig): EnvironmentProvider
131
184
 
132
185
  declare class ButtonComponent {
133
186
  variant: _angular_core.InputSignal<"solid" | "outline" | "ghost">;
134
- size: _angular_core.InputSignal<"sm" | "md" | "lg">;
187
+ size: _angular_core.InputSignal<"sm" | "lg" | "md">;
135
188
  color: _angular_core.InputSignal<"primary" | "secondary" | "success" | "error" | "warning">;
136
189
  disabled: _angular_core.InputSignal<boolean>;
137
190
  fullWidth: _angular_core.InputSignal<boolean>;
138
191
  loading: _angular_core.InputSignal<boolean>;
139
192
  type: _angular_core.InputSignal<"button" | "submit" | "reset">;
193
+ icon: _angular_core.InputSignal<string | undefined>;
194
+ iconPosition: _angular_core.InputSignal<"left" | "right" | "only">;
140
195
  clicked: _angular_core.OutputEmitterRef<MouseEvent>;
196
+ protected iconSize: _angular_core.Signal<number>;
141
197
  protected hostClasses: _angular_core.Signal<string>;
142
198
  protected handleClick(event: MouseEvent): void;
143
199
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ButtonComponent, never>;
144
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ButtonComponent, "studio-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; }, { "clicked": "clicked"; }, never, ["*"], true, never>;
200
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ButtonComponent, "studio-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconPosition": { "alias": "iconPosition"; "required": false; "isSignal": true; }; }, { "clicked": "clicked"; }, never, ["*"], true, never>;
201
+ }
202
+
203
+ declare class IconComponent {
204
+ name: _angular_core.InputSignal<string>;
205
+ size: _angular_core.InputSignal<number>;
206
+ color: _angular_core.InputSignal<string>;
207
+ strokeWidth: _angular_core.InputSignal<number>;
208
+ absoluteStrokeWidth: _angular_core.InputSignal<boolean>;
209
+ protected readonly icons: typeof icons;
210
+ protected lucideIcon: _angular_core.Signal<string>;
211
+ protected computedColor: _angular_core.Signal<string>;
212
+ protected hostClasses: _angular_core.Signal<string[]>;
213
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<IconComponent, never>;
214
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<IconComponent, "studio-icon", never, { "name": { "alias": "name"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "color": { "alias": "color"; "required": false; "isSignal": true; }; "strokeWidth": { "alias": "strokeWidth"; "required": false; "isSignal": true; }; "absoluteStrokeWidth": { "alias": "absoluteStrokeWidth"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
145
215
  }
146
216
 
147
- export { ButtonComponent, STUDIO_CONFIG, StudioConfigService, provideStudioConfig };
148
- export type { StudioConfig, StudioThemeConfig, ThemeMode };
217
+ /**
218
+ * Провайдер иконок для Studio
219
+ * Регистрирует базовый набор часто используемых иконок
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * // app.config.ts
224
+ * import { provideStudioIcons } from '@eduboxpro/studio';
225
+ *
226
+ * export const appConfig: ApplicationConfig = {
227
+ * providers: [
228
+ * provideStudioIcons()
229
+ * ]
230
+ * };
231
+ * ```
232
+ *
233
+ * Для добавления дополнительных иконок:
234
+ * @example
235
+ * ```typescript
236
+ * import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';
237
+ * import { Zap, Wifi } from 'lucide-angular';
238
+ *
239
+ * providers: [
240
+ * provideStudioIcons(),
241
+ * {
242
+ * provide: LUCIDE_ICONS,
243
+ * multi: true,
244
+ * useValue: new LucideIconProvider({ Zap, Wifi })
245
+ * }
246
+ * ]
247
+ * ```
248
+ */
249
+ declare function provideStudioIcons(): EnvironmentProviders;
250
+
251
+ export { ButtonComponent, IconComponent, STUDIO_CONFIG, StudioConfigService, provideStudioConfig, provideStudioIcons };
252
+ export type { ColorConfig, StudioConfig, StudioThemeConfig, ThemeMode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eduboxpro/studio",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Modern Angular UI library for educational platforms with customizable design system",
5
5
  "keywords": [
6
6
  "angular",
@@ -16,7 +16,7 @@
16
16
  "license": "MIT",
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "https://github.com/eduboxpro/studio"
19
+ "url": "git+https://github.com/eduboxpro/studio.git"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@angular/common": "^20.3.0",
@@ -0,0 +1,157 @@
1
+ /**
2
+ * SCSS Mixins
3
+ * Reusable style patterns
4
+ */
5
+
6
+ /**
7
+ * Flex center
8
+ */
9
+ @mixin flex-center {
10
+ display: flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ }
14
+
15
+ /**
16
+ * Absolute center
17
+ */
18
+ @mixin absolute-center {
19
+ position: absolute;
20
+ top: 50%;
21
+ left: 50%;
22
+ transform: translate(-50%, -50%);
23
+ }
24
+
25
+ /**
26
+ * Truncate text with ellipsis
27
+ */
28
+ @mixin truncate {
29
+ overflow: hidden;
30
+ text-overflow: ellipsis;
31
+ white-space: nowrap;
32
+ }
33
+
34
+ /**
35
+ * Line clamp (multi-line truncate)
36
+ */
37
+ @mixin line-clamp($lines: 2) {
38
+ display: -webkit-box;
39
+ -webkit-line-clamp: $lines;
40
+ -webkit-box-orient: vertical;
41
+ overflow: hidden;
42
+ }
43
+
44
+ /**
45
+ * Focus ring (accessible focus state)
46
+ */
47
+ @mixin focus-ring($color: var(--studio-primary), $offset: 2px) {
48
+ outline: 2px solid $color;
49
+ outline-offset: $offset;
50
+ }
51
+
52
+ /**
53
+ * Visually hidden (accessible but invisible)
54
+ */
55
+ @mixin visually-hidden {
56
+ position: absolute;
57
+ width: 1px;
58
+ height: 1px;
59
+ padding: 0;
60
+ margin: -1px;
61
+ overflow: hidden;
62
+ clip: rect(0, 0, 0, 0);
63
+ white-space: nowrap;
64
+ border-width: 0;
65
+ }
66
+
67
+ /**
68
+ * Reset button styles
69
+ */
70
+ @mixin reset-button {
71
+ border: none;
72
+ background: none;
73
+ padding: 0;
74
+ margin: 0;
75
+ font: inherit;
76
+ color: inherit;
77
+ cursor: pointer;
78
+ outline: none;
79
+ }
80
+
81
+ /**
82
+ * Reset list styles
83
+ */
84
+ @mixin reset-list {
85
+ list-style: none;
86
+ padding: 0;
87
+ margin: 0;
88
+ }
89
+
90
+ /**
91
+ * Scrollbar styles
92
+ */
93
+ @mixin custom-scrollbar($width: 8px, $track-color: transparent, $thumb-color: var(--studio-border-secondary)) {
94
+ &::-webkit-scrollbar {
95
+ width: $width;
96
+ height: $width;
97
+ }
98
+
99
+ &::-webkit-scrollbar-track {
100
+ background: $track-color;
101
+ }
102
+
103
+ &::-webkit-scrollbar-thumb {
104
+ background: $thumb-color;
105
+ border-radius: var(--studio-radius-full);
106
+
107
+ &:hover {
108
+ background: var(--studio-text-tertiary);
109
+ }
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Smooth transition
115
+ */
116
+ @mixin transition($properties...) {
117
+ transition-property: $properties;
118
+ transition-duration: var(--studio-transition-base);
119
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
120
+ }
121
+
122
+ /**
123
+ * Responsive breakpoints
124
+ */
125
+ @mixin breakpoint($size) {
126
+ @if $size == 'sm' {
127
+ @media (min-width: 640px) { @content; }
128
+ } @else if $size == 'md' {
129
+ @media (min-width: 768px) { @content; }
130
+ } @else if $size == 'lg' {
131
+ @media (min-width: 1024px) { @content; }
132
+ } @else if $size == 'xl' {
133
+ @media (min-width: 1280px) { @content; }
134
+ } @else if $size == '2xl' {
135
+ @media (min-width: 1536px) { @content; }
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Hover state (respects prefers-reduced-motion)
141
+ */
142
+ @mixin hover {
143
+ @media (hover: hover) and (prefers-reduced-motion: no-preference) {
144
+ &:hover {
145
+ @content;
146
+ }
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Animation (respects prefers-reduced-motion)
152
+ */
153
+ @mixin animate($name, $duration: var(--studio-transition-base)) {
154
+ @media (prefers-reduced-motion: no-preference) {
155
+ animation: $name $duration;
156
+ }
157
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * CSS Reset
3
+ * Minimal CSS reset for consistent styling
4
+ */
5
+
6
+ *,
7
+ *::before,
8
+ *::after {
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+
17
+ html {
18
+ -webkit-font-smoothing: antialiased;
19
+ -moz-osx-font-smoothing: grayscale;
20
+ text-rendering: optimizeLegibility;
21
+ }
22
+
23
+ body {
24
+ font-family: var(--studio-font-family);
25
+ font-size: var(--studio-font-size-base);
26
+ line-height: var(--studio-line-height-normal);
27
+ color: var(--studio-text-primary);
28
+ background-color: var(--studio-bg-primary);
29
+ transition: background-color var(--studio-transition-base), color var(--studio-transition-base);
30
+ }
31
+
32
+ img,
33
+ picture,
34
+ video,
35
+ canvas,
36
+ svg {
37
+ display: block;
38
+ max-width: 100%;
39
+ }
40
+
41
+ input,
42
+ button,
43
+ textarea,
44
+ select {
45
+ font: inherit;
46
+ }
47
+
48
+ p,
49
+ h1,
50
+ h2,
51
+ h3,
52
+ h4,
53
+ h5,
54
+ h6 {
55
+ overflow-wrap: break-word;
56
+ }
57
+
58
+ button {
59
+ cursor: pointer;
60
+ }
61
+
62
+ a {
63
+ color: inherit;
64
+ text-decoration: none;
65
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Design Tokens
3
+ * CSS Custom Properties for theme customization
4
+ */
5
+
6
+ :root {
7
+ /* ========================================
8
+ * COLORS - Light Theme (Default)
9
+ * ======================================== */
10
+
11
+ /* Background colors */
12
+ --studio-bg-primary: #ffffff;
13
+ --studio-bg-secondary: #f3f4f6;
14
+ --studio-bg-tertiary: #e5e7eb;
15
+
16
+ /* Text colors */
17
+ --studio-text-primary: #111827;
18
+ --studio-text-secondary: #6b7280;
19
+ --studio-text-tertiary: #9ca3af;
20
+ --studio-text-inverse: #ffffff;
21
+
22
+ /* Border colors */
23
+ --studio-border-primary: #e5e7eb;
24
+ --studio-border-secondary: #d1d5db;
25
+
26
+ /* Brand colors */
27
+ --studio-primary: #7c3aed;
28
+ --studio-primary-hover: #6d28d9;
29
+ --studio-primary-active: #5b21b6;
30
+
31
+ --studio-secondary: #6366f1;
32
+ --studio-secondary-hover: #4f46e5;
33
+ --studio-secondary-active: #4338ca;
34
+
35
+ /* Semantic colors */
36
+ --studio-success: #10b981;
37
+ --studio-success-hover: #059669;
38
+ --studio-success-bg: #d1fae5;
39
+
40
+ --studio-error: #ef4444;
41
+ --studio-error-hover: #dc2626;
42
+ --studio-error-bg: #fee2e2;
43
+
44
+ --studio-warning: #f59e0b;
45
+ --studio-warning-hover: #d97706;
46
+ --studio-warning-bg: #fef3c7;
47
+
48
+ --studio-info: #0ea5e9;
49
+ --studio-info-hover: #0284c7;
50
+ --studio-info-bg: #dbeafe;
51
+
52
+ /* ========================================
53
+ * TYPOGRAPHY
54
+ * ======================================== */
55
+
56
+ --studio-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
57
+ --studio-font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
58
+
59
+ /* Font sizes */
60
+ --studio-font-size-xs: 0.75rem; /* 12px */
61
+ --studio-font-size-sm: 0.875rem; /* 14px */
62
+ --studio-font-size-base: 1rem; /* 16px */
63
+ --studio-font-size-lg: 1.125rem; /* 18px */
64
+ --studio-font-size-xl: 1.25rem; /* 20px */
65
+ --studio-font-size-2xl: 1.5rem; /* 24px */
66
+
67
+ /* Font weights */
68
+ --studio-font-weight-normal: 400;
69
+ --studio-font-weight-medium: 500;
70
+ --studio-font-weight-semibold: 600;
71
+ --studio-font-weight-bold: 700;
72
+
73
+ /* Line heights */
74
+ --studio-line-height-tight: 1.25;
75
+ --studio-line-height-normal: 1.5;
76
+ --studio-line-height-relaxed: 1.75;
77
+
78
+ /* ========================================
79
+ * SPACING
80
+ * ======================================== */
81
+
82
+ --studio-spacing-xs: 0.25rem; /* 4px */
83
+ --studio-spacing-sm: 0.5rem; /* 8px */
84
+ --studio-spacing-md: 1rem; /* 16px */
85
+ --studio-spacing-lg: 1.5rem; /* 24px */
86
+ --studio-spacing-xl: 2rem; /* 32px */
87
+ --studio-spacing-2xl: 3rem; /* 48px */
88
+
89
+ /* ========================================
90
+ * BORDER RADIUS
91
+ * ======================================== */
92
+
93
+ --studio-radius-none: 0;
94
+ --studio-radius-sm: 0.25rem; /* 4px */
95
+ --studio-radius-md: 0.5rem; /* 8px */
96
+ --studio-radius-lg: 0.75rem; /* 12px */
97
+ --studio-radius-xl: 1rem; /* 16px */
98
+ --studio-radius-full: 9999px;
99
+
100
+ /* ========================================
101
+ * SHADOWS
102
+ * ======================================== */
103
+
104
+ --studio-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
105
+ --studio-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
106
+ --studio-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
107
+ --studio-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
108
+
109
+ /* ========================================
110
+ * TRANSITIONS
111
+ * ======================================== */
112
+
113
+ --studio-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
114
+ --studio-transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
115
+ --studio-transition-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1);
116
+
117
+ /* ========================================
118
+ * Z-INDEX
119
+ * ======================================== */
120
+
121
+ --studio-z-dropdown: 1000;
122
+ --studio-z-sticky: 1020;
123
+ --studio-z-fixed: 1030;
124
+ --studio-z-modal-backdrop: 1040;
125
+ --studio-z-modal: 1050;
126
+ --studio-z-popover: 1060;
127
+ --studio-z-tooltip: 1070;
128
+ }
129
+
130
+ /* ========================================
131
+ * DARK THEME
132
+ * ======================================== */
133
+
134
+ [data-theme="dark"] {
135
+ /* Background colors */
136
+ --studio-bg-primary: #111827;
137
+ --studio-bg-secondary: #1f2937;
138
+ --studio-bg-tertiary: #374151;
139
+
140
+ /* Text colors */
141
+ --studio-text-primary: #f9fafb;
142
+ --studio-text-secondary: #d1d5db;
143
+ --studio-text-tertiary: #9ca3af;
144
+ --studio-text-inverse: #111827;
145
+
146
+ /* Border colors */
147
+ --studio-border-primary: #374151;
148
+ --studio-border-secondary: #4b5563;
149
+
150
+ /* Brand colors - slightly adjusted for dark mode */
151
+ --studio-primary: #a78bfa;
152
+ --studio-primary-hover: #c4b5fd;
153
+ --studio-primary-active: #ddd6fe;
154
+
155
+ --studio-secondary: #818cf8;
156
+ --studio-secondary-hover: #a5b4fc;
157
+ --studio-secondary-active: #c7d2fe;
158
+
159
+ /* Semantic colors */
160
+ --studio-success: #34d399;
161
+ --studio-success-hover: #6ee7b7;
162
+ --studio-success-bg: #064e3b;
163
+
164
+ --studio-error: #f87171;
165
+ --studio-error-hover: #fca5a5;
166
+ --studio-error-bg: #7f1d1d;
167
+
168
+ --studio-warning: #fbbf24;
169
+ --studio-warning-hover: #fcd34d;
170
+ --studio-warning-bg: #78350f;
171
+
172
+ --studio-info: #38bdf8;
173
+ --studio-info-hover: #7dd3fc;
174
+ --studio-info-bg: #0c4a6e;
175
+
176
+ /* Shadows - darker for dark mode */
177
+ --studio-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
178
+ --studio-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
179
+ --studio-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5), 0 4px 6px -2px rgba(0, 0, 0, 0.4);
180
+ --studio-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6), 0 10px 10px -5px rgba(0, 0, 0, 0.5);
181
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @eduboxpro/studio - Main Stylesheet
3
+ *
4
+ * Import this file in your angular.json or styles array:
5
+ * "styles": ["node_modules/@eduboxpro/studio/styles/studio.scss"]
6
+ */
7
+
8
+ /* Design Tokens */
9
+ @import 'tokens';
10
+
11
+ /* CSS Reset */
12
+ @import 'reset';
13
+
14
+ /* Mixins - import in component styles as needed */
15
+ /* @import '@eduboxpro/studio/styles/mixins'; */