@coyalabs/bts-style 1.3.7 → 1.3.9

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 ADDED
@@ -0,0 +1,1454 @@
1
+ # @coyalabs/bts-style
2
+
3
+ **Coya Behind the Scenes** - A Svelte 4 component library with a serif 1920s aesthetic.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @coyalabs/bts-style
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```svelte
14
+ <script>
15
+ import { BasePage, Button, BaseText } from '@coyalabs/bts-style';
16
+ </script>
17
+
18
+ <BasePage>
19
+ <BaseText variant="title">Hello BTS Theme!</BaseText>
20
+ <Button theme="primary">Click Me</Button>
21
+ </BasePage>
22
+ ```
23
+
24
+ ## Design System
25
+
26
+ ### Colors
27
+
28
+ - **Background:** `#0B070D` - Deep dark page background
29
+ - **Default Text:** `#E3D8D8` - Light text and icons
30
+ - **Toned:** `#A18F8F` - Muted icons and accents
31
+ - **Accent:** `#FFEFF6` - Interactive elements
32
+
33
+ ### Fonts
34
+
35
+ The package uses fonts from Google Fonts and Fontshare (loaded via CDN):
36
+ - **Noto Serif KR (900)** - Titles and button text
37
+ - **Satoshi (400, 500, 700, 900)** - Content and UI text
38
+
39
+ ### Theme Variants
40
+
41
+ All container-based components support these themes:
42
+
43
+ - **`full`** - Standard glass container with subtle background
44
+ - **`primary`** - Slightly more prominent glass effect
45
+ - **`secondary`** - Alternative glass styling
46
+ - **`vague`** - Subtle thing
47
+ - **`filled`** - Use for solid container sections (customizable)
48
+
49
+ ---
50
+
51
+ ## Components
52
+
53
+ ### Base Components
54
+
55
+ #### BasePage
56
+
57
+ Root page component with automatic favicon setup, dark background, and decorative background elements.
58
+
59
+ **Props:**
60
+ - `favicon?: string | null` - Custom favicon URL (defaults to BTS theme icon)
61
+ - `showBGDetails?: boolean` - Show/hide decorative background elements (default: `true`)
62
+ - `chainColor?: string` - Color of the animated chain (default: `"#130F15"`)
63
+
64
+ **Example:**
65
+ ```svelte
66
+ <BasePage favicon="/custom-icon.svg">
67
+ <!-- Your app content -->
68
+ </BasePage>
69
+
70
+ <!-- Without background decorations -->
71
+ <BasePage showBGDetails={false}>
72
+ <!-- Clean page without gears/chains -->
73
+ </BasePage>
74
+
75
+ <!-- Custom chain color -->
76
+ <BasePage chainColor="#1a1520">
77
+ <!-- Content with custom chain color -->
78
+ </BasePage>
79
+ ```
80
+
81
+ **Features:**
82
+ - Sets min-height: 100vh
83
+ - Applies #0B070D background
84
+ - Automatically injects BTS favicon unless overridden
85
+ - Resets body/html margins
86
+ - Decorative BGDetails layer with animated gears and swinging chain
87
+
88
+ **Background Details (BGDetails):**
89
+
90
+ The `BGDetails` component renders decorative 1920s-style animated elements:
91
+ - **Chain** - A physics-simulated swinging chain in the top-left corner
92
+ - **Gears** - Rotating interlocked gears in the top-right corner
93
+ - **Single Gear** - A slowly rotating gear in the bottom-left corner
94
+
95
+ These elements are purely decorative (pointer-events: none) and sit behind your content.
96
+ Disable with showBGDetails={false}.
97
+
98
+ ---
99
+
100
+ #### BaseContainer
101
+
102
+ Container with customizable corners and themes.
103
+
104
+ **Props:**
105
+ - `theme?: 'full' | 'primary' | 'secondary' | 'filled'` - Visual theme (default: `'full'`)
106
+ - `padding?: string` - CSS padding value (default: `'1.5rem'`)
107
+ - `borderRadiusTopLeft?: string` - Top-left corner radius (default: `'25px'`)
108
+ - `borderRadiusTopRight?: string` - Top-right corner radius (default: `'25px'`)
109
+ - `borderRadiusBottomLeft?: string` - Bottom-left corner radius (default: `'25px'`)
110
+ - `borderRadiusBottomRight?: string` - Bottom-right corner radius (default: `'25px'`)
111
+
112
+ **Example:**
113
+ ```svelte
114
+ <BaseContainer theme="primary" borderRadiusTopLeft="35px">
115
+ <slot />
116
+ </BaseContainer>
117
+ ```
118
+
119
+ ---
120
+
121
+ #### BaseText
122
+
123
+ Typography component with three text variants.
124
+
125
+ **Props:**
126
+ - `variant: 'title' | 'content' | 'button'` - Text style variant
127
+
128
+ **Variants:**
129
+ - **`title`** - Noto Serif KR 900, 30px - For headings
130
+ - **`content`** - Satoshi 700, 18px - For body text
131
+ - **`button`** - Noto Serif KR 900, 17px - For button labels
132
+
133
+ **Example:**
134
+ ```svelte
135
+ <BaseText variant="title">Page Title</BaseText>
136
+ <BaseText variant="content">This is content text.</BaseText>
137
+ ```
138
+
139
+ ---
140
+
141
+ #### BaseIcon
142
+
143
+ SVG icon wrapper with color variants.
144
+
145
+ **Props:**
146
+ - `svg: string` - SVG markup string
147
+ - `variant?: 'default' | 'toned'` - Color variant (default: `'default'`)
148
+ - `size?: string` - Icon size (default: `'18px'`)
149
+
150
+ **Example:**
151
+ ```svelte
152
+ <script>
153
+ import { BaseIcon, icons } from '@coyalabs/bts-style';
154
+ </script>
155
+
156
+ <BaseIcon svg={icons.folder} variant="toned" size="24px" />
157
+ ```
158
+
159
+ ---
160
+
161
+ ### Structure Components
162
+
163
+ #### TextHeader
164
+
165
+ Header component with title and optional subtitle.
166
+
167
+ **Props:**
168
+ - `title: string` - Main heading text
169
+ - `subtitle?: string` - Optional subheading
170
+
171
+ **Example:**
172
+ ```svelte
173
+ <TextHeader
174
+ title="Welcome"
175
+ subtitle="Get started with BTS Theme"
176
+ />
177
+ ```
178
+
179
+ ---
180
+
181
+ ### Interactive Components
182
+
183
+ #### Button
184
+
185
+ Clickable button extending BaseContainer with icon support.
186
+
187
+ **Props:**
188
+ - `theme?: 'full' | 'primary' | 'secondary' | 'filled'` - Button theme
189
+ - `icon?: string` - Left icon SVG
190
+ - `actionIcon?: string | null` - Right icon SVG (default: arrow, null to hide)
191
+ - `iconRotation?: number` - Left icon rotation in degrees
192
+ - `actionIconRotation?: number` - Right icon rotation in degrees
193
+ - `iconSize?: string` - Left icon size (default: `'18px'`)
194
+ - `actionIconSize?: string` - Right icon size (default: `'18px'`)
195
+ - All BaseContainer corner radius props
196
+
197
+ **Events:**
198
+ - Forwards all events including `on:click`
199
+
200
+ **Example:**
201
+ ```svelte
202
+ <script>
203
+ import { Button, icons } from '@coyalabs/bts-style';
204
+ </script>
205
+
206
+ <Button
207
+ theme="primary"
208
+ icon={icons.folder}
209
+ actionIconRotation={-45}
210
+ on:click={() => console.log('Clicked!')}
211
+ >
212
+ Open Folder
213
+ </Button>
214
+
215
+ <!-- Button without action icon -->
216
+ <Button actionIcon={null} theme="secondary">
217
+ Simple Button
218
+ </Button>
219
+ ```
220
+
221
+ **States:**
222
+ - Hover: Subtle background lightening
223
+ - Active/Pressed: Visual feedback
224
+
225
+ ---
226
+
227
+ #### IconButton
228
+
229
+ Circular icon-only button with hover effects.
230
+
231
+ **Props:**
232
+ - `svg: string` - Icon SVG markup
233
+ - `variant?: 'default' | 'toned'` - Icon color variant
234
+ - `size?: string` - Button size (default: `'20px'`)
235
+
236
+ **Events:**
237
+ - Forwards all events including `on:click`
238
+
239
+ **Example:**
240
+ ```svelte
241
+ <script>
242
+ import { IconButton, icons } from '@coyalabs/bts-style';
243
+ </script>
244
+
245
+ <IconButton
246
+ svg={icons.cross}
247
+ variant="toned"
248
+ on:click={() => closeModal()}
249
+ />
250
+ ```
251
+
252
+ **Effects:**
253
+ - Hover: Scale 1.1, subtle background
254
+ - Active: Scale 0.95
255
+
256
+ ---
257
+
258
+ #### InputBox
259
+
260
+ Text input field with icon support and theme matching.
261
+
262
+ **Props:**
263
+ - `value?: string` - Input value (bindable)
264
+ - `placeholder?: string` - Placeholder text
265
+ - `type?: string` - Input type (default: `'text'`)
266
+ - `theme?: 'full' | 'primary' | 'secondary' | 'filled'` - Visual theme
267
+ - `icon?: string` - Left icon SVG
268
+ - All BaseContainer corner radius props
269
+
270
+ **Example:**
271
+ ```svelte
272
+ <script>
273
+ import { InputBox, icons } from '@coyalabs/bts-style';
274
+ let username = '';
275
+ </script>
276
+
277
+ <InputBox
278
+ bind:value={username}
279
+ placeholder="Enter username..."
280
+ icon={icons.pen}
281
+ theme="primary"
282
+ />
283
+ ```
284
+
285
+
286
+ ---
287
+
288
+ #### Toggle
289
+
290
+ Animated toggle switch with on/off states.
291
+
292
+ **Props:**
293
+ - `checked?: boolean` - Toggle state (bindable)
294
+
295
+ **Example:**
296
+ ```svelte
297
+ <script>
298
+ import { Toggle } from '@coyalabs/bts-style';
299
+ let enabled = false;
300
+ </script>
301
+
302
+ <Toggle bind:checked={enabled} />
303
+ <p>State: {enabled ? 'On' : 'Off'}</p>
304
+ ```
305
+ ---
306
+
307
+ #### Tooltip
308
+
309
+ Hover tooltip that displays above or below an icon.
310
+
311
+ **Props:**
312
+ - `icon: string` - Icon SVG markup
313
+ - `text: string` - Tooltip text content
314
+ - `iconSize?: string` - Icon size (default: `'18px'`)
315
+
316
+ **Example:**
317
+ ```svelte
318
+ <script>
319
+ import { Tooltip, icons } from '@coyalabs/bts-style';
320
+ </script>
321
+
322
+ <Tooltip
323
+ icon={icons.folder}
324
+ text="This is a helpful explanation"
325
+ iconSize="20px"
326
+ />
327
+ ```
328
+
329
+ **Features:**
330
+ - Automatic positioning to fit on screen
331
+ - Min width 150px, max width 300px
332
+
333
+ ---
334
+
335
+ #### TabBar
336
+
337
+ Vertical tab navigation with support for categorized groups.
338
+
339
+ **Props:**
340
+ - `tabs: Array<TabItem>` - Array of tabs and separators
341
+ - `activeTab: string` - Currently active tab ID (bindable)
342
+ - `onTabChange?: (tabId: string) => void` - Callback when tab changes
343
+
344
+ **TabItem Type:**
345
+ ```typescript
346
+ type TabItem = {
347
+ id?: string; // Required for tabs, omit for separators
348
+ label: string; // Tab/separator text
349
+ icon?: string; // Optional icon SVG
350
+ type?: 'tab' | 'separator'; // Default: 'tab'
351
+ }
352
+ ```
353
+
354
+ **Example:**
355
+ ```svelte
356
+ <script>
357
+ import { TabBar, icons } from '@coyalabs/bts-style';
358
+
359
+ let currentTab = 'home';
360
+
361
+ const tabs = [
362
+ { type: 'separator', label: 'Navigation' },
363
+ { id: 'home', label: 'Home', icon: icons.folder },
364
+ { id: 'about', label: 'About' },
365
+ { type: 'separator', label: 'Account' },
366
+ { id: 'settings', label: 'Settings' },
367
+ { id: 'profile', label: 'Profile' }
368
+ ];
369
+ </script>
370
+
371
+ <TabBar
372
+ {tabs}
373
+ bind:activeTab={currentTab}
374
+ onTabChange={(id) => console.log('Tab:', id)}
375
+ />
376
+ ```
377
+
378
+ **Features:**
379
+ - Vertical layout, 175px fixed width
380
+ - Active tab uses `primary` theme, inactive uses `secondary`
381
+ - Adaptive corner radius: 25px at group boundaries, 18px for middle tabs
382
+ - Text separators for grouping tabs into categories
383
+ - Categories have 1rem spacing between them
384
+ - Buttons within categories have 4px spacing
385
+
386
+ **Corner Radius Behavior:**
387
+ - First tab in a group: top corners 25px
388
+ - Last tab in a group: bottom corners 25px
389
+ - Middle tabs: all corners 18px
390
+ - Separators create group boundaries
391
+
392
+ ---
393
+
394
+ #### TreeDirectory
395
+
396
+ Expandable file/folder tree with recursive structure.
397
+
398
+ **Props:**
399
+ - `items: Array<TreeItem>` - Tree data structure
400
+ - `showCount?: boolean` - Show item counts in folders (default: `false`)
401
+ - `itemIcon?: string` - Custom icon for items
402
+ - `topFoldersExpanded?: boolean` - Expand top-level folders initially (default: `false`)
403
+ - `draggable?: boolean` - Enable drag and drop functionality (default: `false`)
404
+ - `currentPath?: string` - Current folder path for nested items (default: `''`)
405
+ - `level?: number` - Internal: Current nesting level (default: `0`)
406
+
407
+ **TreeItem Type:**
408
+ ```typescript
409
+ type TreeItem = {
410
+ name: string;
411
+ type: 'file' | 'folder';
412
+ children?: TreeItem[];
413
+ data?: any; // Custom data attached to item
414
+ variant?: 'full' | 'primary' | 'secondary' | 'filled' | 'special-filled'; // Theme variant
415
+ suffixIcon?: string; // SVG icon displayed on the right
416
+ }
417
+ ```
418
+
419
+ **Events:**
420
+ - `on:itemClick` - Fired when any item is clicked
421
+ - `event.detail.item` - The clicked item object
422
+ - `event.detail.type` - Either `'file'` or `'folder'`
423
+ - `on:dragStart` - Fired when dragging a file starts (requires `draggable={true}`)
424
+ - `event.detail.item` - The dragged item object
425
+ - `event.detail.sourcePath` - Path of the source folder
426
+ - `on:itemDrop` - Fired when a file is dropped (requires `draggable={true}`)
427
+ - `event.detail.item` - The dropped item data
428
+ - `event.detail.sourcePath` - Original folder path
429
+ - `event.detail.targetPath` - Destination folder path
430
+
431
+ **Example:**
432
+ ```svelte
433
+ <script>
434
+ import { TreeDirectory, icons } from '@coyalabs/bts-style';
435
+
436
+ const fileTree = [
437
+ {
438
+ name: 'src',
439
+ type: 'folder',
440
+ variant: 'primary',
441
+ children: [
442
+ {
443
+ name: 'App.svelte',
444
+ type: 'file',
445
+ variant: 'secondary',
446
+ suffixIcon: icons.pen
447
+ },
448
+ { name: 'main.js', type: 'file' }
449
+ ]
450
+ },
451
+ {
452
+ name: 'README.md',
453
+ type: 'file',
454
+ suffixIcon: '<svg>...</svg>'
455
+ }
456
+ ];
457
+
458
+ function handleItemClick(event) {
459
+ const { item, type } = event.detail;
460
+ console.log(`Clicked ${type}:`, item.name);
461
+ }
462
+
463
+ function handleDrop(event) {
464
+ const { item, sourcePath, targetPath } = event.detail;
465
+ console.log(`Moved ${item.name} from ${sourcePath} to ${targetPath}`);
466
+ }
467
+ </script>
468
+
469
+ <TreeDirectory
470
+ items={fileTree}
471
+ showCount={true}
472
+ topFoldersExpanded={true}
473
+ draggable={true}
474
+ on:itemClick={handleItemClick}
475
+ on:itemDrop={handleDrop}
476
+ />
477
+ ```
478
+
479
+ **Methods:**
480
+ ```svelte
481
+ <script>
482
+ let tree;
483
+
484
+ // Get current state
485
+ const state = tree.getState();
486
+
487
+ // Restore state
488
+ tree.setState(state);
489
+
490
+ // Expand all folders
491
+ tree.expandAll();
492
+
493
+ // Collapse all folders
494
+ tree.collapseAll();
495
+ </script>
496
+
497
+ <TreeDirectory bind:this={tree} items={fileTree} />
498
+ ```
499
+
500
+ **Features:**
501
+ - Slide animations (150ms, skipped on initial render)
502
+ - Recursive item counting
503
+ - State persistence
504
+ - Event forwarding for click handling
505
+ - Initial expansion option for top-level folders
506
+ - Adaptive corner radius based on nesting
507
+ - Padding increases with depth
508
+ - Per-item theme variants (override default folder/file themes)
509
+ - Suffix icon support for displaying icons on the right side
510
+ - Optional drag and drop functionality for files
511
+ - Visual feedback during drag operations (folder highlight)
512
+ - Path tracking for nested folder structures
513
+
514
+ **Drag and Drop:**
515
+
516
+ When `draggable={true}`:
517
+ - Only files can be dragged (folders are drop targets)
518
+ - Dragged files show reduced opacity
519
+ - Folders highlight when dragged over
520
+ - Drop on folders to move files into them
521
+ - Drop on empty space to move to current level
522
+ - `on:itemDrop` event provides source and target paths for handling moves
523
+
524
+ **Customization:**
525
+
526
+ **Item Variants:**
527
+ Each item can have a custom `variant` to override the default theme:
528
+ - Folders default to `'primary'`
529
+ - Files default to `'secondary'`
530
+ - Set `variant` on any item to use a different theme
531
+
532
+ **Suffix Icons:**
533
+ Display additional icons on the right side of items:
534
+ ```svelte
535
+ {
536
+ name: 'config.json',
537
+ type: 'file',
538
+ suffixIcon: '<svg>...</svg>' // Any SVG string
539
+ }
540
+ ```
541
+
542
+ ---
543
+
544
+ ### Popup System
545
+
546
+ #### Popup
547
+
548
+ Global modal popup overlay (singleton).
549
+
550
+ **Usage:**
551
+ ```svelte
552
+ <script>
553
+ import { Popup, popupStore } from '@coyalabs/bts-style';
554
+ </script>
555
+
556
+ <!-- Place once at app root -->
557
+ <Popup />
558
+ ```
559
+
560
+ **Features:**
561
+ - Fade overlay (250ms)
562
+ - Fly dialog animation (300ms, backOut easing)
563
+ - Close button with toned icon
564
+ - ESC key support (built-in)
565
+
566
+ ---
567
+
568
+ #### popupStore
569
+
570
+ Writable store for controlling the popup.
571
+
572
+ **Methods:**
573
+
574
+ ##### open()
575
+ ```typescript
576
+ popupStore.open(
577
+ title: string,
578
+ component: SvelteComponent,
579
+ props?: object,
580
+ subtitle?: string
581
+ )
582
+ ```
583
+
584
+ Opens popup with custom component.
585
+
586
+ **Example:**
587
+ ```svelte
588
+ <script>
589
+ import { popupStore } from '@coyalabs/bts-style';
590
+ import MyCustomPopup from './MyCustomPopup.svelte';
591
+ </script>
592
+
593
+ <button on:click={() =>
594
+ popupStore.open(
595
+ 'Settings',
596
+ MyCustomPopup,
597
+ { userId: 123 },
598
+ 'Configure your preferences'
599
+ )
600
+ }>
601
+ Open Settings
602
+ </button>
603
+ ```
604
+
605
+ ##### confirm()
606
+ ```typescript
607
+ popupStore.confirm(
608
+ title: string,
609
+ message: string,
610
+ options?: {
611
+ onConfirm?: () => void,
612
+ onCancel?: () => void,
613
+ confirmText?: string,
614
+ cancelText?: string
615
+ }
616
+ )
617
+ ```
618
+
619
+ Shows confirmation dialog.
620
+
621
+ **Example:**
622
+ ```svelte
623
+ <button on:click={() =>
624
+ popupStore.confirm(
625
+ 'Delete Item',
626
+ 'Are you sure? This cannot be undone.',
627
+ {
628
+ onConfirm: () => deleteItem(),
629
+ onCancel: () => console.log('Cancelled'),
630
+ confirmText: 'Delete',
631
+ cancelText: 'Keep'
632
+ }
633
+ )
634
+ }>
635
+ Delete
636
+ </button>
637
+ ```
638
+
639
+ ##### alert()
640
+ ```typescript
641
+ popupStore.alert(
642
+ title: string,
643
+ message: string,
644
+ options?: {
645
+ onOk?: () => void,
646
+ okText?: string
647
+ }
648
+ )
649
+ ```
650
+
651
+ Shows alert dialog.
652
+
653
+ **Example:**
654
+ ```svelte
655
+ popupStore.alert(
656
+ 'Success',
657
+ 'Your changes have been saved!',
658
+ {
659
+ onOk: () => navigateToHome(),
660
+ okText: 'Got it'
661
+ }
662
+ );
663
+ ```
664
+
665
+ ##### prompt()
666
+ ```typescript
667
+ popupStore.prompt(
668
+ title: string,
669
+ message: string,
670
+ options?: {
671
+ onSubmit?: (value: string) => void,
672
+ onCancel?: () => void,
673
+ placeholder?: string,
674
+ submitText?: string,
675
+ cancelText?: string
676
+ }
677
+ )
678
+ ```
679
+
680
+ Shows input prompt dialog.
681
+
682
+ **Example:**
683
+ ```svelte
684
+ popupStore.prompt(
685
+ 'Enter Name',
686
+ 'Please provide your display name:',
687
+ {
688
+ onSubmit: (name) => updateProfile(name),
689
+ placeholder: 'Your name...',
690
+ submitText: 'Save',
691
+ cancelText: 'Skip'
692
+ }
693
+ );
694
+ ```
695
+
696
+ ##### close()
697
+ ```typescript
698
+ popupStore.close()
699
+ ```
700
+
701
+ Closes the current popup.
702
+
703
+ ---
704
+
705
+ #### Popup Presets
706
+
707
+ The popup system includes three pre-built popup components that can be triggered via `popupStore` methods.
708
+
709
+ ##### ConfirmPopup
710
+
711
+ A two-button confirmation dialog with confirm and cancel actions.
712
+
713
+ **Features:**
714
+ - Primary theme confirm button (left)
715
+ - Secondary theme cancel button (right)
716
+ - Callbacks: `onConfirm`, `onCancel`
717
+ - Customizable button text
718
+
719
+ **Triggered via:**
720
+ ```svelte
721
+ popupStore.confirm(title, message, options)
722
+ ```
723
+
724
+ **Visual Layout:**
725
+ - Message text displayed as subtitle
726
+ - Two buttons side-by-side
727
+ - Confirm button uses primary theme
728
+ - Cancel button uses secondary theme
729
+
730
+ ---
731
+
732
+ ##### AlertPopup
733
+
734
+ A single-button alert dialog for notifications.
735
+
736
+ **Features:**
737
+ - Single OK button with primary theme
738
+ - Callback: `onOk`
739
+ - Customizable button text
740
+ - Auto-closes on OK click
741
+
742
+ **Triggered via:**
743
+ ```svelte
744
+ popupStore.alert(title, message, options)
745
+ ```
746
+
747
+ **Visual Layout:**
748
+ - Message text displayed as subtitle
749
+ - Single centered OK button
750
+ - Primary theme button
751
+
752
+ ---
753
+
754
+ ##### PromptPopup
755
+
756
+ An input dialog that prompts the user for text input.
757
+
758
+ **Features:**
759
+ - InputBox component for text entry
760
+ - Submit button (primary theme)
761
+ - Cancel button (secondary theme)
762
+ - Callbacks: `onSubmit(value)`, `onCancel`
763
+ - Customizable placeholder and button text
764
+
765
+ **Triggered via:**
766
+ ```svelte
767
+ popupStore.prompt(title, message, options)
768
+ ```
769
+
770
+ **Visual Layout:**
771
+ - Message text displayed as subtitle
772
+ - InputBox with customizable placeholder
773
+ - Two buttons: Submit (primary) and Cancel (secondary)
774
+ - Submit returns the input value to callback
775
+
776
+ **Example with all options:**
777
+ ```svelte
778
+ popupStore.prompt(
779
+ 'Rename File',
780
+ 'Enter a new name for this file:',
781
+ {
782
+ placeholder: 'filename.txt',
783
+ submitText: 'Rename',
784
+ cancelText: 'Cancel',
785
+ onSubmit: (newName) => {
786
+ console.log('New name:', newName);
787
+ renameFile(newName);
788
+ },
789
+ onCancel: () => console.log('Rename cancelled')
790
+ }
791
+ );
792
+ ```
793
+
794
+ ---
795
+
796
+ ### Toast System
797
+
798
+ #### Toast
799
+
800
+ Global toast notification container (singleton).
801
+
802
+ **Usage:**
803
+ ```svelte
804
+ <script>
805
+ import { Toast, toastStore } from '@coyalabs/bts-style';
806
+ </script>
807
+
808
+ <!-- Place once at app root -->
809
+ <Toast />
810
+ ```
811
+
812
+ **Features:**
813
+ - Bottom-right stacking
814
+ - Smooth slide animations (300ms in, 200ms out)
815
+ - Auto-dismiss with configurable duration
816
+ - Manual dismiss via close button
817
+ - Non-blocking, less intrusive than popups
818
+
819
+ ---
820
+
821
+ #### toastStore
822
+
823
+ Writable store for controlling toast notifications.
824
+
825
+ **Methods:**
826
+
827
+ ##### show()
828
+ ```typescript
829
+ toastStore.show(
830
+ message: string,
831
+ duration?: number // Default: 4000ms, 0 = no auto-dismiss
832
+ ): string // Returns toast ID
833
+ ```
834
+
835
+ Shows a toast notification.
836
+
837
+ **Example:**
838
+ ```svelte
839
+ <script>
840
+ import { toastStore } from '@coyalabs/bts-style';
841
+ </script>
842
+
843
+ <button on:click={() => toastStore.show('File saved successfully!')}>
844
+ Save
845
+ </button>
846
+
847
+ <!-- Custom duration -->
848
+ <button on:click={() => toastStore.show('Processing...', 2000)}>
849
+ Process
850
+ </button>
851
+
852
+ <!-- No auto-dismiss -->
853
+ <button on:click={() => toastStore.show('Important message', 0)}>
854
+ Important
855
+ </button>
856
+ ```
857
+
858
+ ##### dismiss()
859
+ ```typescript
860
+ toastStore.dismiss(id: string)
861
+ ```
862
+
863
+ Dismisses a specific toast by ID.
864
+
865
+ **Example:**
866
+ ```svelte
867
+ <script>
868
+ const toastId = toastStore.show('Click to dismiss', 0);
869
+ </script>
870
+
871
+ <button on:click={() => toastStore.dismiss(toastId)}>
872
+ Dismiss Toast
873
+ </button>
874
+ ```
875
+
876
+ ##### dismissAll()
877
+ ```typescript
878
+ toastStore.dismissAll()
879
+ ```
880
+
881
+ Dismisses all active toasts.
882
+
883
+ **Example:**
884
+ ```svelte
885
+ <button on:click={() => toastStore.dismissAll()}>
886
+ Clear All Toasts
887
+ </button>
888
+ ```
889
+
890
+ **Visual Design:**
891
+ - Uses Button component with secondary theme
892
+ - Help icon on the left (info indicator)
893
+ - Close icon (crossb) on the right
894
+ - Stacks vertically with 0.75rem gap
895
+ - Slides in from right, slides out to right
896
+ - Fixed position at bottom-right (2rem from edges)
897
+ - Z-index 10000 (above popups)
898
+
899
+ **Best Practices:**
900
+
901
+ Place `<Toast />` once at your app root alongside `<Popup />`:
902
+
903
+ ```svelte
904
+ <!-- App.svelte -->
905
+ <script>
906
+ import { BasePage, Popup, Toast } from '@coyalabs/bts-style';
907
+ </script>
908
+
909
+ <BasePage>
910
+ <!-- App content -->
911
+ </BasePage>
912
+
913
+ <Popup />
914
+ <Toast />
915
+ ```
916
+
917
+ ---
918
+
919
+ ### Special Components
920
+
921
+ Glowy components with unique styling and animations.
922
+
923
+ #### SpecialAction
924
+
925
+ A special-themed button with gradient background and optional tooltip.
926
+
927
+ **Props:**
928
+ - `label: string` - Button text
929
+ - `tooltipText?: string` - Optional tooltip text displayed on the right
930
+
931
+ **Example:**
932
+ ```svelte
933
+ <script>
934
+ import { SpecialAction } from '@coyalabs/bts-style';
935
+ </script>
936
+
937
+ <SpecialAction
938
+ label="AI Generate"
939
+ tooltipText="Uses AI to generate content"
940
+ />
941
+ ```
942
+
943
+ **Features:**
944
+ - Purple gradient background (`special-filled` theme)
945
+ - AI icon on the left
946
+ - Tooltip positioned at far right (when provided)
947
+ - Enhanced hover effect with brighter gradient
948
+ - Pressed state with darker gradient
949
+
950
+ **For?**
951
+ - AI actions.
952
+
953
+ **Styling:**
954
+ - Background: Linear gradient purple tones
955
+ - Enhanced glow effects on hover
956
+ - User-select disabled for better UX
957
+
958
+ ---
959
+
960
+ #### SpecialParagraph
961
+
962
+ Animated text component that reveals words sequentially with fade and blur effects.
963
+
964
+ **Props:**
965
+ - `text: string` - The text content to animate
966
+ - `wordDelay?: number` - Delay between each word appearing in ms (default: `50`)
967
+ - `startDelay?: number` - Initial delay before animation starts in ms (default: `0`)
968
+ - `animationDuration?: number` - Animation duration for each word in ms (default: `300`)
969
+ - `variant?: 'title' | 'content' | 'button'` - Text styling variant (default: `'content'`)
970
+ - `textModifier?: string` - Font size adjustment (default: `'0px'`)
971
+ - `autoPlay?: boolean` - Start animation automatically on mount (default: `true`)
972
+
973
+ **Methods:**
974
+ - `play()` - Start/restart the animation
975
+ - `reset()` - Reset to hidden state
976
+ - `showAll()` - Show all words immediately
977
+
978
+ **Example:**
979
+ ```svelte
980
+ <script>
981
+ import { SpecialParagraph } from '@coyalabs/bts-style';
982
+ let paragraph;
983
+ </script>
984
+
985
+ <!-- Auto-playing paragraph -->
986
+ <SpecialParagraph
987
+ text="This text will animate in word by word with smooth effects"
988
+ wordDelay={80}
989
+ variant="content"
990
+ />
991
+
992
+ <!-- Manual control -->
993
+ <SpecialParagraph
994
+ bind:this={paragraph}
995
+ text="Click the button to animate!"
996
+ autoPlay={false}
997
+ />
998
+ <button on:click={() => paragraph.play()}>Play Animation</button>
999
+ ```
1000
+
1001
+ **Animation Effects:**
1002
+ - Each word fades in from opacity 0 to 1
1003
+ - Slides up from 8px translateY offset
1004
+ - Blur transitions from 4px to 0
1005
+ - Smooth easing transitions
1006
+
1007
+ **For?**
1008
+ - Fancier AI.
1009
+
1010
+ **Use Cases:**
1011
+ - Intro text animations
1012
+ - Loading state messages
1013
+ - Drawing attention to important content
1014
+ - Storytelling and narrative interfaces
1015
+
1016
+ ---
1017
+
1018
+ #### ContextMenu
1019
+
1020
+ Categorized menu component with separator support, similar to TabBar layout.
1021
+
1022
+ **Props:**
1023
+ - `items: Array<ContextMenuItem>` - Array of menu items and separators
1024
+ - `selectedValue?: any` - Currently selected item value
1025
+ - `onSelect?: (value: any) => void` - Callback when item is selected
1026
+
1027
+ **ContextMenuItem Type:**
1028
+ ```typescript
1029
+ type ContextMenuItem = {
1030
+ label: string;
1031
+ value?: any; // Required for items, omit for separators
1032
+ disabled?: boolean;
1033
+ type?: 'item' | 'separator'; // Default: 'item'
1034
+ }
1035
+ ```
1036
+
1037
+ **Example:**
1038
+ ```svelte
1039
+ <script>
1040
+ import { ContextMenu } from '@coyalabs/bts-style';
1041
+
1042
+ let selectedValue = 'cut';
1043
+
1044
+ const menuItems = [
1045
+ { label: 'Edit', type: 'separator' },
1046
+ { label: 'Cut', value: 'cut' },
1047
+ { label: 'Copy', value: 'copy' },
1048
+ { label: 'Paste', value: 'paste', disabled: true },
1049
+ { label: 'View', type: 'separator' },
1050
+ { label: 'Zoom In', value: 'zoomIn' },
1051
+ { label: 'Zoom Out', value: 'zoomOut' }
1052
+ ];
1053
+ </script>
1054
+
1055
+ <ContextMenu
1056
+ items={menuItems}
1057
+ {selectedValue}
1058
+ onSelect={(val) => handleAction(val)}
1059
+ />
1060
+ ```
1061
+
1062
+ **Features:**
1063
+ - Category grouping with separator labels
1064
+ - Selected item highlighting
1065
+ - Disabled item support with reduced opacity
1066
+ - Hover effects on enabled items
1067
+ - Filled theme container
1068
+ - Automatic category spacing and borders
1069
+ - Text ellipsis for long labels
1070
+
1071
+ **Visual Layout:**
1072
+ - Categories separated by labeled dividers
1073
+ - First category has no top border
1074
+ - Subsequent categories have subtle top border
1075
+ - 0.5rem padding around separators
1076
+ - 4px spacing between items
1077
+
1078
+ ---
1079
+
1080
+ #### Dropdown
1081
+
1082
+ Select dropdown with collapsible options menu.
1083
+
1084
+ **Props:**
1085
+ - `label: string` - Default button text before selection
1086
+ - `icon?: string` - Optional left icon SVG
1087
+ - `theme?: 'full' | 'primary' | 'secondary'` - Button theme (default: `'full'`)
1088
+ - `width?: string` - Fixed width for dropdown (default: `'200px'`)
1089
+ - `options: Array<DropdownOption>` - Array of selectable options
1090
+ - `value?: any` - Currently selected value (bindable)
1091
+ - `onChange?: (value: any) => void` - Callback when selection changes
1092
+ - All BaseContainer corner radius props
1093
+
1094
+ **DropdownOption Type:**
1095
+ ```typescript
1096
+ type DropdownOption = {
1097
+ label: string;
1098
+ value: any;
1099
+ disabled?: boolean;
1100
+ type?: 'item' | 'separator'; // Optional: use for category separation
1101
+ }
1102
+ ```
1103
+
1104
+ **Example:**
1105
+ ```svelte
1106
+ <script>
1107
+ import { Dropdown, icons } from '@coyalabs/bts-style';
1108
+
1109
+ let selectedValue = 'option1';
1110
+
1111
+ const options = [
1112
+ { label: 'Basic', type: 'separator' },
1113
+ { label: 'Option 1', value: 'option1' },
1114
+ { label: 'Option 2', value: 'option2' },
1115
+ { label: 'Advanced', type: 'separator' },
1116
+ { label: 'Option 3', value: 'option3' },
1117
+ { label: 'Disabled', value: 'option4', disabled: true }
1118
+ ];
1119
+ </script>
1120
+
1121
+ <Dropdown
1122
+ label="Select an option"
1123
+ icon={icons.folder}
1124
+ theme="primary"
1125
+ width="250px"
1126
+ {options}
1127
+ bind:value={selectedValue}
1128
+ onChange={(val) => console.log('Selected:', val)}
1129
+ />
1130
+ ```
1131
+
1132
+ **Features:**
1133
+ - Fixed width with text truncation (ellipsis)
1134
+ - Expand icon rotates 180° when open
1135
+ - Slide animation for menu (150ms)
1136
+ - Click outside to close
1137
+ - Uses ContextMenu component internally
1138
+ - Support for category separators
1139
+ - Selected item highlighted
1140
+ - Disabled items shown with reduced opacity
1141
+
1142
+ ---
1143
+
1144
+ #### LinearList
1145
+
1146
+ Vertical list component with customizable actions for each item.
1147
+
1148
+ **Props:**
1149
+ - `items: Array<ListItem>` - Array of list items
1150
+
1151
+ **ListItem Type:**
1152
+ ```typescript
1153
+ type CustomAction = {
1154
+ label: string;
1155
+ actionIcon?: string;
1156
+ }
1157
+
1158
+ type ListItem = {
1159
+ data?: any; // Custom data attached to item
1160
+ customActions?: CustomAction[];
1161
+ removeButton?: boolean;
1162
+ }
1163
+ ```
1164
+
1165
+ **Events:**
1166
+ - `on:action` - Fired when any custom action is clicked
1167
+ - `event.detail.index` - Item index
1168
+ - `event.detail.actionLabel` - Action label that was clicked
1169
+ - `event.detail.item` - The item object
1170
+ - `on:remove` - Fired when remove button is clicked
1171
+ - `event.detail.index` - Item index
1172
+ - `event.detail.item` - The item object
1173
+
1174
+ **Example:**
1175
+ ```svelte
1176
+ <script>
1177
+ import { LinearList, icons } from '@coyalabs/bts-style';
1178
+
1179
+ const items = [
1180
+ {
1181
+ data: { id: 1, name: 'First Item' },
1182
+ customActions: [
1183
+ { label: 'Edit', actionIcon: icons.pen },
1184
+ { label: 'View' }
1185
+ ],
1186
+ removeButton: true
1187
+ },
1188
+ {
1189
+ data: { id: 2, name: 'Second Item' },
1190
+ customActions: [
1191
+ { label: 'Download' }
1192
+ ],
1193
+ removeButton: true
1194
+ }
1195
+ ];
1196
+
1197
+ function handleAction(event) {
1198
+ const { index, actionLabel, item } = event.detail;
1199
+ console.log(`${actionLabel} clicked on item ${index}`, item);
1200
+ }
1201
+
1202
+ function handleRemove(event) {
1203
+ const { index, item } = event.detail;
1204
+ console.log(`Remove item ${index}`, item);
1205
+ }
1206
+ </script>
1207
+
1208
+ <LinearList
1209
+ {items}
1210
+ on:action={handleAction}
1211
+ on:remove={handleRemove}
1212
+ >
1213
+ {#snippet children({ item, index })}
1214
+ <div>{item.data.name}</div>
1215
+ {/snippet}
1216
+ </LinearList>
1217
+ ```
1218
+
1219
+ **Features:**
1220
+ - Left-aligned content slot with `item` and `index` props
1221
+ - Right-aligned action buttons (horizontal)
1222
+ - Optional remove button (icon-only, toned variant)
1223
+ - 1px bottom border separator (rgba(161, 143, 143, 0.24))
1224
+ - No border on last item
1225
+ - 10px vertical padding per item
1226
+ - No horizontal padding
1227
+ - No spacing between items
1228
+ - Event-based action handling
1229
+
1230
+ **Visual Layout:**
1231
+ - Each item is a flex row with space-between
1232
+ - Content on the left, actions on the right
1233
+ - Actions have 0.5rem gap between them
1234
+ - Remove button appears at the end of actions
1235
+ - Borders are internal strokes (bottom edge only)
1236
+
1237
+ ---
1238
+
1239
+ #### Separator
1240
+
1241
+ Decorative SVG separator with tiled middle section.
1242
+
1243
+ **Props:**
1244
+ - `height?: string` - Separator height (default: `'12px'`)
1245
+ - `width?: string` - Separator width (default: `'100%'`)
1246
+ - `margin?: string` - CSS margin (default: `'2rem 0'`)
1247
+
1248
+ **Example:**
1249
+ ```svelte
1250
+ <script>
1251
+ import { Separator } from '@coyalabs/bts-style';
1252
+ </script>
1253
+
1254
+ <Separator />
1255
+ <Separator height="20px" margin="3rem 0" />
1256
+ ```
1257
+
1258
+ **Features:**
1259
+ - Three-part design: left piece, tiled middle, right piece
1260
+ - Inline SVG data URLs for performance
1261
+ - Scales to container width
1262
+ - Elegant visual break between sections
1263
+
1264
+ ---
1265
+
1266
+ ### Icons
1267
+
1268
+ The package exports a collection of built-in SVG icons.
1269
+
1270
+ **Usage:**
1271
+ ```svelte
1272
+ <script>
1273
+ import { icons, BaseIcon } from '@coyalabs/bts-style';
1274
+ </script>
1275
+
1276
+ <BaseIcon svg={icons.arrow} />
1277
+ <BaseIcon svg={icons.folder} />
1278
+ <BaseIcon svg={icons.icon_expand} />
1279
+ <BaseIcon svg={icons.cross} />
1280
+ <BaseIcon svg={icons.pen} />
1281
+ ```
1282
+
1283
+ **Available Icons:**
1284
+ - `arrow` - Right arrow navigation
1285
+ - `folder` - Folder icon
1286
+ - `icon_expand` - Expand/collapse chevron
1287
+ - `cross` - Close/dismiss X
1288
+ - `pen` - Edit/write pen
1289
+
1290
+ **Custom Icons:**
1291
+
1292
+ You can use any SVG string with icon-supporting components:
1293
+
1294
+ ```svelte
1295
+ <script>
1296
+ const myIcon = '<svg>...</svg>';
1297
+ </script>
1298
+
1299
+ <Button icon={myIcon}>Custom Icon</Button>
1300
+ <BaseIcon svg={myIcon} />
1301
+ ```
1302
+
1303
+ ---
1304
+
1305
+ ## Styling
1306
+
1307
+ ### Corner Radius Customization
1308
+
1309
+ All components extending BaseContainer support individual corner radius props:
1310
+
1311
+ ```svelte
1312
+ <Button
1313
+ borderRadiusTopLeft="35px"
1314
+ borderRadiusTopRight="35px"
1315
+ borderRadiusBottomLeft="15px"
1316
+ borderRadiusBottomRight="15px"
1317
+ theme="primary"
1318
+ >
1319
+ Asymmetric Button
1320
+ </Button>
1321
+ ```
1322
+
1323
+ ### Theme Customization
1324
+
1325
+ You can customize filled theme backgrounds by targeting CSS variables or extending components.
1326
+
1327
+ ---
1328
+
1329
+ ## Best Practices
1330
+
1331
+ ### Layout
1332
+
1333
+ ```svelte
1334
+ <BasePage>
1335
+ <main style="max-width: 900px; margin: 0 auto; padding: 3rem 2rem;">
1336
+ <TextHeader title="My App" subtitle="Welcome" />
1337
+
1338
+ <!-- Your content -->
1339
+ </main>
1340
+ </BasePage>
1341
+ ```
1342
+
1343
+ ### Popup Management
1344
+
1345
+ Place `<Popup />` once at your app root:
1346
+
1347
+ ```svelte
1348
+ <!-- App.svelte -->
1349
+ <script>
1350
+ import { BasePage, Popup } from '@coyalabs/bts-style';
1351
+ </script>
1352
+
1353
+ <BasePage>
1354
+ <!-- App content -->
1355
+ </BasePage>
1356
+
1357
+ <Popup />
1358
+ ```
1359
+
1360
+ ### Icons
1361
+
1362
+ For consistent styling, prefer using `BaseIcon` over raw SVG:
1363
+
1364
+ ```svelte
1365
+ <!-- Good -->
1366
+ <BaseIcon svg={myIcon} variant="toned" />
1367
+
1368
+ <!-- Less ideal -->
1369
+ {@html myIcon}
1370
+ ```
1371
+
1372
+ ---
1373
+
1374
+ ## Development
1375
+
1376
+ ### Local Development
1377
+
1378
+ Link the package locally for testing:
1379
+
1380
+ ```bash
1381
+ # In the package directory
1382
+ cd @bts-theme/bts-theme
1383
+ npm run package
1384
+ npm link
1385
+
1386
+ # In your project
1387
+ npm link @coyalabs/bts-style
1388
+ ```
1389
+
1390
+ After making changes:
1391
+
1392
+ ```bash
1393
+ npm run package
1394
+ ```
1395
+
1396
+ **Note:** You may need to clear Vite cache after rebuilding:
1397
+ ```bash
1398
+ rm -rf node_modules/.vite
1399
+ ```
1400
+
1401
+ ### Publishing
1402
+
1403
+ ```bash
1404
+ npm run release # Bumps version, packages, and publishes
1405
+ ```
1406
+
1407
+ ---
1408
+
1409
+ ## TypeScript Support
1410
+
1411
+ All components include TypeScript definitions. Import types as needed:
1412
+
1413
+ ```typescript
1414
+ import type { TreeItem } from '@coyalabs/bts-style';
1415
+ ```
1416
+
1417
+ ---
1418
+
1419
+ ## Package Structure
1420
+
1421
+ ```
1422
+ @coyalabs/bts-style/
1423
+ ├── dist/ # Compiled package
1424
+ ├── public/ # Static assets
1425
+ │ ├── favicon.svg # Default BTS favicon
1426
+ │ └── PLACE_YOUR_IMAGES_HERE.txt
1427
+ ├── src/
1428
+ │ ├── Base/ # Base components
1429
+ │ ├── Components/ # Interactive components
1430
+ │ ├── Structure/ # Layout components
1431
+ │ ├── icons.js # Icon definitions
1432
+ │ └── index.ts # Main export
1433
+ └── package.json
1434
+ ```
1435
+
1436
+ ---
1437
+
1438
+ ## License
1439
+
1440
+ MIT
1441
+
1442
+ ---
1443
+
1444
+ ## Repository
1445
+
1446
+ [github.com/sparklescoya/svelte-bts-theme](https://github.com/sparklescoya/svelte-bts-theme)
1447
+
1448
+ ---
1449
+
1450
+ ## Credits
1451
+
1452
+ Created with ❤️ using Svelte 5
1453
+
1454
+ Fonts: [Google Fonts (Noto Serif KR)](https://fonts.google.com/), [Fontshare (Satoshi)](https://www.fontshare.com/)