jasmincss 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +524 -0
- package/bin/jasmin.js +45 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +14568 -0
- package/dist/index.mjs +14524 -0
- package/dist/jasmin.css +63308 -0
- package/dist/jasmin.min.css +1 -0
- package/dist/plugins/nextjs.js +14777 -0
- package/dist/plugins/nextjs.mjs +14747 -0
- package/dist/plugins/vite.js +14889 -0
- package/dist/plugins/vite.mjs +14860 -0
- package/package.json +101 -0
- package/src/cli/add.js +83 -0
- package/src/cli/init.js +210 -0
- package/src/cli/run.js +142 -0
- package/src/components/accordion.js +309 -0
- package/src/components/alerts.js +357 -0
- package/src/components/avatars.js +331 -0
- package/src/components/badges.js +353 -0
- package/src/components/buttons.js +412 -0
- package/src/components/cards.js +342 -0
- package/src/components/carousel.js +495 -0
- package/src/components/chips.js +440 -0
- package/src/components/command-palette.js +434 -0
- package/src/components/datepicker.js +517 -0
- package/src/components/dropdown.js +411 -0
- package/src/components/forms.js +516 -0
- package/src/components/index.js +81 -0
- package/src/components/modals.js +349 -0
- package/src/components/navigation.js +463 -0
- package/src/components/offcanvas.js +390 -0
- package/src/components/popover.js +427 -0
- package/src/components/progress.js +396 -0
- package/src/components/rating.js +394 -0
- package/src/components/skeleton.js +408 -0
- package/src/components/spinner.js +453 -0
- package/src/components/stepper.js +389 -0
- package/src/components/tables.js +304 -0
- package/src/components/timeline.js +452 -0
- package/src/components/timepicker.js +529 -0
- package/src/components/tooltips.js +345 -0
- package/src/components/upload.js +490 -0
- package/src/config/defaults.js +263 -0
- package/src/config/loader.js +109 -0
- package/src/core/base.js +241 -0
- package/src/core/compiler.js +135 -0
- package/src/core/utilities/accessibility.js +290 -0
- package/src/core/utilities/animations.js +205 -0
- package/src/core/utilities/background.js +109 -0
- package/src/core/utilities/colors.js +234 -0
- package/src/core/utilities/columns.js +161 -0
- package/src/core/utilities/effects.js +261 -0
- package/src/core/utilities/filters.js +135 -0
- package/src/core/utilities/icons.js +806 -0
- package/src/core/utilities/index.js +239 -0
- package/src/core/utilities/layout.js +321 -0
- package/src/core/utilities/scroll.js +205 -0
- package/src/core/utilities/spacing.js +120 -0
- package/src/core/utilities/svg.js +191 -0
- package/src/core/utilities/transforms.js +116 -0
- package/src/core/utilities/typography.js +188 -0
- package/src/index.js +7 -0
- package/src/js/components/accordion.js +154 -0
- package/src/js/components/alert.js +198 -0
- package/src/js/components/carousel.js +226 -0
- package/src/js/components/dropdown.js +166 -0
- package/src/js/components/modal.js +169 -0
- package/src/js/components/offcanvas.js +175 -0
- package/src/js/components/popover.js +221 -0
- package/src/js/components/tabs.js +163 -0
- package/src/js/components/tooltip.js +200 -0
- package/src/js/index.js +79 -0
- package/src/js/types/config.d.ts +228 -0
- package/src/js/types/index.d.ts +439 -0
- package/src/plugins/nextjs.js +100 -0
- package/src/plugins/vite.js +133 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JasminCSS TypeScript Definitions
|
|
3
|
+
* @version 1.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Dropdown
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
export interface DropdownOptions {
|
|
11
|
+
/** Close dropdown when clicking outside. Default: true */
|
|
12
|
+
closeOnClickOutside?: boolean;
|
|
13
|
+
/** Close dropdown when pressing Escape. Default: true */
|
|
14
|
+
closeOnEscape?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class Dropdown {
|
|
18
|
+
constructor(element: HTMLElement, options?: DropdownOptions);
|
|
19
|
+
|
|
20
|
+
/** Toggle dropdown visibility */
|
|
21
|
+
toggle(): void;
|
|
22
|
+
|
|
23
|
+
/** Open dropdown */
|
|
24
|
+
open(): void;
|
|
25
|
+
|
|
26
|
+
/** Close dropdown */
|
|
27
|
+
close(): void;
|
|
28
|
+
|
|
29
|
+
/** Destroy instance and remove event listeners */
|
|
30
|
+
destroy(): void;
|
|
31
|
+
|
|
32
|
+
/** Initialize all dropdowns matching selector */
|
|
33
|
+
static initAll(selector?: string): Dropdown[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Modal
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
export interface ModalOptions {
|
|
41
|
+
/** Show backdrop overlay. Default: true */
|
|
42
|
+
backdrop?: boolean;
|
|
43
|
+
/** Close on Escape key. Default: true */
|
|
44
|
+
keyboard?: boolean;
|
|
45
|
+
/** Trap focus inside modal. Default: true */
|
|
46
|
+
focus?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ModalEvents {
|
|
50
|
+
'modal:open': CustomEvent<{ modal: Modal }>;
|
|
51
|
+
'modal:close': CustomEvent<{ modal: Modal }>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class Modal {
|
|
55
|
+
constructor(element: HTMLElement, options?: ModalOptions);
|
|
56
|
+
|
|
57
|
+
/** Open modal */
|
|
58
|
+
open(): void;
|
|
59
|
+
|
|
60
|
+
/** Close modal */
|
|
61
|
+
close(): void;
|
|
62
|
+
|
|
63
|
+
/** Toggle modal visibility */
|
|
64
|
+
toggle(): void;
|
|
65
|
+
|
|
66
|
+
/** Check if modal is open */
|
|
67
|
+
isOpen(): boolean;
|
|
68
|
+
|
|
69
|
+
/** Destroy instance and remove event listeners */
|
|
70
|
+
destroy(): void;
|
|
71
|
+
|
|
72
|
+
/** Initialize all modals matching selector */
|
|
73
|
+
static initAll(selector?: string): Modal[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Accordion
|
|
78
|
+
// ============================================================================
|
|
79
|
+
|
|
80
|
+
export interface AccordionOptions {
|
|
81
|
+
/** Allow multiple panels open simultaneously. Default: false */
|
|
82
|
+
multipleOpen?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class Accordion {
|
|
86
|
+
constructor(element: HTMLElement, options?: AccordionOptions);
|
|
87
|
+
|
|
88
|
+
/** Open panel by index */
|
|
89
|
+
openItem(index: number): void;
|
|
90
|
+
|
|
91
|
+
/** Close panel by index */
|
|
92
|
+
closeItem(index: number): void;
|
|
93
|
+
|
|
94
|
+
/** Toggle panel by index */
|
|
95
|
+
toggleItem(index: number): void;
|
|
96
|
+
|
|
97
|
+
/** Open all panels */
|
|
98
|
+
openAll(): void;
|
|
99
|
+
|
|
100
|
+
/** Close all panels */
|
|
101
|
+
closeAll(): void;
|
|
102
|
+
|
|
103
|
+
/** Destroy instance and remove event listeners */
|
|
104
|
+
destroy(): void;
|
|
105
|
+
|
|
106
|
+
/** Initialize all accordions matching selector */
|
|
107
|
+
static initAll(selector?: string): Accordion[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Tabs
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
export interface TabsOptions {
|
|
115
|
+
/** Tab orientation. Default: 'horizontal' */
|
|
116
|
+
orientation?: 'horizontal' | 'vertical';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface TabsEvents {
|
|
120
|
+
'tabs:change': CustomEvent<{ index: number; tab: HTMLElement; panel: HTMLElement }>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export class Tabs {
|
|
124
|
+
constructor(element: HTMLElement, options?: TabsOptions);
|
|
125
|
+
|
|
126
|
+
/** Select tab by index */
|
|
127
|
+
selectTab(index: number): void;
|
|
128
|
+
|
|
129
|
+
/** Get currently selected tab index */
|
|
130
|
+
getSelectedIndex(): number;
|
|
131
|
+
|
|
132
|
+
/** Destroy instance and remove event listeners */
|
|
133
|
+
destroy(): void;
|
|
134
|
+
|
|
135
|
+
/** Initialize all tabs matching selector */
|
|
136
|
+
static initAll(selector?: string): Tabs[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// Offcanvas
|
|
141
|
+
// ============================================================================
|
|
142
|
+
|
|
143
|
+
export interface OffcanvasOptions {
|
|
144
|
+
/** Show backdrop overlay. Default: true */
|
|
145
|
+
backdrop?: boolean;
|
|
146
|
+
/** Close on Escape key. Default: true */
|
|
147
|
+
keyboard?: boolean;
|
|
148
|
+
/** Disable body scroll when open. Default: true */
|
|
149
|
+
scroll?: boolean;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface OffcanvasEvents {
|
|
153
|
+
'offcanvas:open': CustomEvent<{ offcanvas: Offcanvas }>;
|
|
154
|
+
'offcanvas:close': CustomEvent<{ offcanvas: Offcanvas }>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export class Offcanvas {
|
|
158
|
+
constructor(element: HTMLElement, options?: OffcanvasOptions);
|
|
159
|
+
|
|
160
|
+
/** Open offcanvas */
|
|
161
|
+
open(): void;
|
|
162
|
+
|
|
163
|
+
/** Close offcanvas */
|
|
164
|
+
close(): void;
|
|
165
|
+
|
|
166
|
+
/** Toggle offcanvas visibility */
|
|
167
|
+
toggle(): void;
|
|
168
|
+
|
|
169
|
+
/** Check if offcanvas is open */
|
|
170
|
+
isOpen(): boolean;
|
|
171
|
+
|
|
172
|
+
/** Destroy instance and remove event listeners */
|
|
173
|
+
destroy(): void;
|
|
174
|
+
|
|
175
|
+
/** Initialize all offcanvas elements matching selector */
|
|
176
|
+
static initAll(selector?: string): Offcanvas[];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// Tooltip
|
|
181
|
+
// ============================================================================
|
|
182
|
+
|
|
183
|
+
export type TooltipPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
184
|
+
export type TooltipTrigger = 'hover' | 'focus' | 'hover focus';
|
|
185
|
+
|
|
186
|
+
export interface TooltipOptions {
|
|
187
|
+
/** Tooltip position. Default: 'top' */
|
|
188
|
+
position?: TooltipPosition;
|
|
189
|
+
/** Trigger events. Default: 'hover focus' */
|
|
190
|
+
trigger?: TooltipTrigger;
|
|
191
|
+
/** Delay before showing (ms). Default: 0 */
|
|
192
|
+
delay?: number;
|
|
193
|
+
/** Tooltip content (overrides data-tooltip attribute) */
|
|
194
|
+
content?: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export class Tooltip {
|
|
198
|
+
constructor(element: HTMLElement, options?: TooltipOptions);
|
|
199
|
+
|
|
200
|
+
/** Show tooltip */
|
|
201
|
+
show(): void;
|
|
202
|
+
|
|
203
|
+
/** Hide tooltip */
|
|
204
|
+
hide(): void;
|
|
205
|
+
|
|
206
|
+
/** Update tooltip content */
|
|
207
|
+
setContent(content: string): void;
|
|
208
|
+
|
|
209
|
+
/** Update tooltip position */
|
|
210
|
+
setPosition(position: TooltipPosition): void;
|
|
211
|
+
|
|
212
|
+
/** Destroy instance and remove event listeners */
|
|
213
|
+
destroy(): void;
|
|
214
|
+
|
|
215
|
+
/** Initialize all tooltips matching selector */
|
|
216
|
+
static initAll(selector?: string): Tooltip[];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Popover
|
|
221
|
+
// ============================================================================
|
|
222
|
+
|
|
223
|
+
export type PopoverPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
224
|
+
export type PopoverTrigger = 'click' | 'hover' | 'focus';
|
|
225
|
+
|
|
226
|
+
export interface PopoverOptions {
|
|
227
|
+
/** Popover position. Default: 'top' */
|
|
228
|
+
position?: PopoverPosition;
|
|
229
|
+
/** Trigger event. Default: 'click' */
|
|
230
|
+
trigger?: PopoverTrigger;
|
|
231
|
+
/** Popover title */
|
|
232
|
+
title?: string;
|
|
233
|
+
/** Popover content */
|
|
234
|
+
content?: string;
|
|
235
|
+
/** Allow HTML in content. Default: false */
|
|
236
|
+
html?: boolean;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export class Popover {
|
|
240
|
+
constructor(element: HTMLElement, options?: PopoverOptions);
|
|
241
|
+
|
|
242
|
+
/** Show popover */
|
|
243
|
+
show(): void;
|
|
244
|
+
|
|
245
|
+
/** Hide popover */
|
|
246
|
+
hide(): void;
|
|
247
|
+
|
|
248
|
+
/** Toggle popover visibility */
|
|
249
|
+
toggle(): void;
|
|
250
|
+
|
|
251
|
+
/** Update popover title */
|
|
252
|
+
setTitle(title: string): void;
|
|
253
|
+
|
|
254
|
+
/** Update popover content */
|
|
255
|
+
setContent(content: string): void;
|
|
256
|
+
|
|
257
|
+
/** Destroy instance and remove event listeners */
|
|
258
|
+
destroy(): void;
|
|
259
|
+
|
|
260
|
+
/** Initialize all popovers matching selector */
|
|
261
|
+
static initAll(selector?: string): Popover[];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ============================================================================
|
|
265
|
+
// Carousel
|
|
266
|
+
// ============================================================================
|
|
267
|
+
|
|
268
|
+
export interface CarouselOptions {
|
|
269
|
+
/** Enable autoplay. Default: false */
|
|
270
|
+
autoplay?: boolean;
|
|
271
|
+
/** Autoplay interval in ms. Default: 5000 */
|
|
272
|
+
interval?: number;
|
|
273
|
+
/** Wrap around at ends. Default: true */
|
|
274
|
+
wrap?: boolean;
|
|
275
|
+
/** Enable keyboard navigation. Default: true */
|
|
276
|
+
keyboard?: boolean;
|
|
277
|
+
/** Enable touch/swipe support. Default: true */
|
|
278
|
+
touch?: boolean;
|
|
279
|
+
/** Pause autoplay on hover. Default: true */
|
|
280
|
+
pauseOnHover?: boolean;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface CarouselEvents {
|
|
284
|
+
'carousel:slide': CustomEvent<{ from: number; to: number }>;
|
|
285
|
+
'carousel:slid': CustomEvent<{ from: number; to: number }>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export class Carousel {
|
|
289
|
+
constructor(element: HTMLElement, options?: CarouselOptions);
|
|
290
|
+
|
|
291
|
+
/** Go to next slide */
|
|
292
|
+
next(): void;
|
|
293
|
+
|
|
294
|
+
/** Go to previous slide */
|
|
295
|
+
prev(): void;
|
|
296
|
+
|
|
297
|
+
/** Go to specific slide */
|
|
298
|
+
goTo(index: number): void;
|
|
299
|
+
|
|
300
|
+
/** Pause autoplay */
|
|
301
|
+
pause(): void;
|
|
302
|
+
|
|
303
|
+
/** Resume autoplay */
|
|
304
|
+
play(): void;
|
|
305
|
+
|
|
306
|
+
/** Get current slide index */
|
|
307
|
+
getCurrentIndex(): number;
|
|
308
|
+
|
|
309
|
+
/** Get total number of slides */
|
|
310
|
+
getSlideCount(): number;
|
|
311
|
+
|
|
312
|
+
/** Destroy instance and remove event listeners */
|
|
313
|
+
destroy(): void;
|
|
314
|
+
|
|
315
|
+
/** Initialize all carousels matching selector */
|
|
316
|
+
static initAll(selector?: string): Carousel[];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ============================================================================
|
|
320
|
+
// Alert
|
|
321
|
+
// ============================================================================
|
|
322
|
+
|
|
323
|
+
export interface AlertOptions {
|
|
324
|
+
/** Animation duration in ms. Default: 150 */
|
|
325
|
+
animationDuration?: number;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface AlertEvents {
|
|
329
|
+
'alert:close': CustomEvent<{ alert: Alert }>;
|
|
330
|
+
'alert:closed': CustomEvent<{ alert: Alert }>;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export class Alert {
|
|
334
|
+
constructor(element: HTMLElement, options?: AlertOptions);
|
|
335
|
+
|
|
336
|
+
/** Close and remove alert */
|
|
337
|
+
close(): void;
|
|
338
|
+
|
|
339
|
+
/** Destroy instance and remove event listeners */
|
|
340
|
+
destroy(): void;
|
|
341
|
+
|
|
342
|
+
/** Initialize all alerts matching selector */
|
|
343
|
+
static initAll(selector?: string): Alert[];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ============================================================================
|
|
347
|
+
// Toast
|
|
348
|
+
// ============================================================================
|
|
349
|
+
|
|
350
|
+
export type ToastType = 'success' | 'error' | 'warning' | 'info' | 'default';
|
|
351
|
+
export type ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
|
|
352
|
+
|
|
353
|
+
export interface ToastOptions {
|
|
354
|
+
/** Toast message */
|
|
355
|
+
message: string;
|
|
356
|
+
/** Toast type/style. Default: 'default' */
|
|
357
|
+
type?: ToastType;
|
|
358
|
+
/** Auto-dismiss duration in ms. 0 for no auto-dismiss. Default: 5000 */
|
|
359
|
+
duration?: number;
|
|
360
|
+
/** Toast position. Default: 'top-right' */
|
|
361
|
+
position?: ToastPosition;
|
|
362
|
+
/** Show dismiss button. Default: true */
|
|
363
|
+
dismissible?: boolean;
|
|
364
|
+
/** Toast title (optional) */
|
|
365
|
+
title?: string;
|
|
366
|
+
/** Custom icon class (optional) */
|
|
367
|
+
icon?: string;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export class Toast {
|
|
371
|
+
/** Show a toast notification */
|
|
372
|
+
static show(options: ToastOptions): HTMLElement;
|
|
373
|
+
|
|
374
|
+
/** Show success toast */
|
|
375
|
+
static success(message: string, options?: Partial<ToastOptions>): HTMLElement;
|
|
376
|
+
|
|
377
|
+
/** Show error toast */
|
|
378
|
+
static error(message: string, options?: Partial<ToastOptions>): HTMLElement;
|
|
379
|
+
|
|
380
|
+
/** Show warning toast */
|
|
381
|
+
static warning(message: string, options?: Partial<ToastOptions>): HTMLElement;
|
|
382
|
+
|
|
383
|
+
/** Show info toast */
|
|
384
|
+
static info(message: string, options?: Partial<ToastOptions>): HTMLElement;
|
|
385
|
+
|
|
386
|
+
/** Dismiss all toasts */
|
|
387
|
+
static dismissAll(): void;
|
|
388
|
+
|
|
389
|
+
/** Dismiss toast by element */
|
|
390
|
+
static dismiss(element: HTMLElement): void;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ============================================================================
|
|
394
|
+
// Main Jasmin Object
|
|
395
|
+
// ============================================================================
|
|
396
|
+
|
|
397
|
+
export interface JasminStatic {
|
|
398
|
+
Dropdown: typeof Dropdown;
|
|
399
|
+
Modal: typeof Modal;
|
|
400
|
+
Accordion: typeof Accordion;
|
|
401
|
+
Tabs: typeof Tabs;
|
|
402
|
+
Offcanvas: typeof Offcanvas;
|
|
403
|
+
Tooltip: typeof Tooltip;
|
|
404
|
+
Popover: typeof Popover;
|
|
405
|
+
Carousel: typeof Carousel;
|
|
406
|
+
Alert: typeof Alert;
|
|
407
|
+
Toast: typeof Toast;
|
|
408
|
+
|
|
409
|
+
/** Initialize all components */
|
|
410
|
+
initAll(): void;
|
|
411
|
+
|
|
412
|
+
/** Auto-initialize on DOMContentLoaded */
|
|
413
|
+
autoInit(): void;
|
|
414
|
+
|
|
415
|
+
/** JasminCSS version */
|
|
416
|
+
version: string;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
declare const Jasmin: JasminStatic;
|
|
420
|
+
|
|
421
|
+
export default Jasmin;
|
|
422
|
+
|
|
423
|
+
// ============================================================================
|
|
424
|
+
// Module Augmentation for Custom Events
|
|
425
|
+
// ============================================================================
|
|
426
|
+
|
|
427
|
+
declare global {
|
|
428
|
+
interface HTMLElementEventMap {
|
|
429
|
+
'modal:open': CustomEvent<{ modal: Modal }>;
|
|
430
|
+
'modal:close': CustomEvent<{ modal: Modal }>;
|
|
431
|
+
'offcanvas:open': CustomEvent<{ offcanvas: Offcanvas }>;
|
|
432
|
+
'offcanvas:close': CustomEvent<{ offcanvas: Offcanvas }>;
|
|
433
|
+
'tabs:change': CustomEvent<{ index: number; tab: HTMLElement; panel: HTMLElement }>;
|
|
434
|
+
'carousel:slide': CustomEvent<{ from: number; to: number }>;
|
|
435
|
+
'carousel:slid': CustomEvent<{ from: number; to: number }>;
|
|
436
|
+
'alert:close': CustomEvent<{ alert: Alert }>;
|
|
437
|
+
'alert:closed': CustomEvent<{ alert: Alert }>;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// JasminCSS Next.js Plugin
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* JasminCSS plugin for Next.js
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} pluginOptions
|
|
9
|
+
* @param {string} pluginOptions.configPath - Path to jasmin.config.js
|
|
10
|
+
* @param {boolean} pluginOptions.optimizeFonts - Optimize Google Fonts loading
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // next.config.js
|
|
14
|
+
* const withJasminCSS = require('jasmincss/plugin/nextjs');
|
|
15
|
+
*
|
|
16
|
+
* module.exports = withJasminCSS({
|
|
17
|
+
* configPath: './jasmin.config.js',
|
|
18
|
+
* optimizeFonts: true
|
|
19
|
+
* })({
|
|
20
|
+
* // your Next.js config
|
|
21
|
+
* });
|
|
22
|
+
*/
|
|
23
|
+
export default function withJasminCSS(pluginOptions = {}) {
|
|
24
|
+
const {
|
|
25
|
+
configPath = './jasmin.config.js',
|
|
26
|
+
optimizeFonts = true
|
|
27
|
+
} = pluginOptions;
|
|
28
|
+
|
|
29
|
+
return (nextConfig = {}) => {
|
|
30
|
+
return {
|
|
31
|
+
...nextConfig,
|
|
32
|
+
|
|
33
|
+
// Enable CSS optimization
|
|
34
|
+
experimental: {
|
|
35
|
+
...nextConfig.experimental,
|
|
36
|
+
optimizeCss: true
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Optimize fonts if enabled
|
|
40
|
+
...(optimizeFonts && {
|
|
41
|
+
optimizeFonts: true
|
|
42
|
+
}),
|
|
43
|
+
|
|
44
|
+
webpack(config, options) {
|
|
45
|
+
const { dev, isServer } = options;
|
|
46
|
+
|
|
47
|
+
// Add JasminCSS loader for .jasmin.css files
|
|
48
|
+
config.module.rules.push({
|
|
49
|
+
test: /\.jasmin\.css$/,
|
|
50
|
+
use: [
|
|
51
|
+
{
|
|
52
|
+
loader: 'postcss-loader',
|
|
53
|
+
options: {
|
|
54
|
+
postcssOptions: {
|
|
55
|
+
plugins: [
|
|
56
|
+
['cssnano', { preset: 'default' }]
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Run user's webpack config if provided
|
|
65
|
+
if (typeof nextConfig.webpack === 'function') {
|
|
66
|
+
return nextConfig.webpack(config, options);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return config;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get JasminCSS config for App Router
|
|
77
|
+
* Useful for server components
|
|
78
|
+
*/
|
|
79
|
+
export async function getJasminConfig(configPath = './jasmin.config.js') {
|
|
80
|
+
const { loadConfig } = await import('../config/loader.js');
|
|
81
|
+
const absolutePath = path.resolve(process.cwd(), configPath);
|
|
82
|
+
return loadConfig(absolutePath);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Compile JasminCSS for a specific page/component
|
|
87
|
+
* Useful for generating critical CSS
|
|
88
|
+
*/
|
|
89
|
+
export async function compileForPage(usedClasses, configPath = './jasmin.config.js') {
|
|
90
|
+
const { compileCSS } = await import('../core/compiler.js');
|
|
91
|
+
const config = await getJasminConfig(configPath);
|
|
92
|
+
|
|
93
|
+
const { minified } = await compileCSS(config, {
|
|
94
|
+
usedClasses: new Set(usedClasses),
|
|
95
|
+
minify: true,
|
|
96
|
+
includeAll: false
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return minified;
|
|
100
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// JasminCSS Vite Plugin
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* JasminCSS plugin for Vite
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} options
|
|
9
|
+
* @param {string} options.configPath - Path to jasmin.config.js
|
|
10
|
+
* @param {boolean} options.devMode - Include full library in development
|
|
11
|
+
* @param {string[]} options.content - Files to scan for class usage
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // vite.config.js
|
|
15
|
+
* import { defineConfig } from 'vite';
|
|
16
|
+
* import jasmin from 'jasmincss/plugin/vite';
|
|
17
|
+
*
|
|
18
|
+
* export default defineConfig({
|
|
19
|
+
* plugins: [
|
|
20
|
+
* jasmin({
|
|
21
|
+
* configPath: './jasmin.config.js'
|
|
22
|
+
* })
|
|
23
|
+
* ]
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
export default function jasminVitePlugin(options = {}) {
|
|
27
|
+
const {
|
|
28
|
+
configPath = './jasmin.config.js',
|
|
29
|
+
devMode = true,
|
|
30
|
+
content = ['./src/**/*.{vue,js,ts,jsx,tsx,svelte}', './index.html']
|
|
31
|
+
} = options;
|
|
32
|
+
|
|
33
|
+
let config;
|
|
34
|
+
let generatedCSS = '';
|
|
35
|
+
const virtualModuleId = 'virtual:jasmin.css';
|
|
36
|
+
const resolvedVirtualModuleId = '\0' + virtualModuleId;
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
name: 'jasmin-css',
|
|
40
|
+
|
|
41
|
+
async configResolved(resolvedConfig) {
|
|
42
|
+
const isDev = resolvedConfig.command === 'serve';
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const { loadConfig } = await import('../config/loader.js');
|
|
46
|
+
const absolutePath = path.resolve(resolvedConfig.root, configPath);
|
|
47
|
+
|
|
48
|
+
if (fs.existsSync(absolutePath)) {
|
|
49
|
+
config = await loadConfig(absolutePath);
|
|
50
|
+
} else {
|
|
51
|
+
const { defaultConfig } = await import('../config/defaults.js');
|
|
52
|
+
config = defaultConfig;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Override content patterns
|
|
56
|
+
config.content = content;
|
|
57
|
+
|
|
58
|
+
// Generate CSS
|
|
59
|
+
const { compileCSS, scanForUsedClasses } = await import('../core/compiler.js');
|
|
60
|
+
|
|
61
|
+
if (isDev && devMode) {
|
|
62
|
+
// In dev mode, include full library for faster HMR
|
|
63
|
+
const result = await compileCSS(config, {
|
|
64
|
+
includeAll: true,
|
|
65
|
+
minify: false
|
|
66
|
+
});
|
|
67
|
+
generatedCSS = result.css;
|
|
68
|
+
} else {
|
|
69
|
+
// In production, tree-shake based on usage
|
|
70
|
+
const usedClasses = await scanForUsedClasses(resolvedConfig.root, content);
|
|
71
|
+
const result = await compileCSS(config, {
|
|
72
|
+
usedClasses,
|
|
73
|
+
minify: !isDev,
|
|
74
|
+
includeAll: false
|
|
75
|
+
});
|
|
76
|
+
generatedCSS = isDev ? result.css : result.minified;
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.warn('[jasmin] Could not load config:', err.message);
|
|
80
|
+
// Fall back to default
|
|
81
|
+
const { compileCSS } = await import('../core/compiler.js');
|
|
82
|
+
const { defaultConfig } = await import('../config/defaults.js');
|
|
83
|
+
const result = await compileCSS(defaultConfig, { includeAll: true, minify: false });
|
|
84
|
+
generatedCSS = result.css;
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
resolveId(id) {
|
|
89
|
+
if (id === virtualModuleId || id === 'jasmincss/css') {
|
|
90
|
+
return resolvedVirtualModuleId;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
load(id) {
|
|
95
|
+
if (id === resolvedVirtualModuleId) {
|
|
96
|
+
return generatedCSS;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
handleHotUpdate({ file, server }) {
|
|
101
|
+
// Reload CSS when config changes
|
|
102
|
+
if (file.endsWith('jasmin.config.js')) {
|
|
103
|
+
server.ws.send({
|
|
104
|
+
type: 'full-reload',
|
|
105
|
+
path: '*'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* PostCSS plugin for JasminCSS
|
|
114
|
+
* Use when you need PostCSS integration
|
|
115
|
+
*/
|
|
116
|
+
export function jasminPostCSS(options = {}) {
|
|
117
|
+
return {
|
|
118
|
+
postcssPlugin: 'jasmin-css',
|
|
119
|
+
async Once(root, { result }) {
|
|
120
|
+
const { compileCSS } = await import('../core/compiler.js');
|
|
121
|
+
const { defaultConfig } = await import('../config/defaults.js');
|
|
122
|
+
|
|
123
|
+
const { css } = await compileCSS({ ...defaultConfig, ...options }, {
|
|
124
|
+
includeAll: true,
|
|
125
|
+
minify: false
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
root.append(css);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
jasminPostCSS.postcss = true;
|