mtrl 0.2.2 → 0.2.4

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.
Files changed (97) hide show
  1. package/.typedocignore +11 -0
  2. package/DOCS.md +153 -0
  3. package/index.ts +18 -3
  4. package/package.json +7 -2
  5. package/src/components/badge/_styles.scss +174 -0
  6. package/src/components/badge/api.ts +292 -0
  7. package/src/components/badge/badge.ts +52 -0
  8. package/src/components/badge/config.ts +68 -0
  9. package/src/components/badge/constants.ts +30 -0
  10. package/src/components/badge/features.ts +185 -0
  11. package/src/components/badge/index.ts +4 -0
  12. package/src/components/badge/types.ts +105 -0
  13. package/src/components/button/types.ts +174 -29
  14. package/src/components/carousel/_styles.scss +645 -0
  15. package/src/components/carousel/api.ts +147 -0
  16. package/src/components/carousel/carousel.ts +178 -0
  17. package/src/components/carousel/config.ts +91 -0
  18. package/src/components/carousel/constants.ts +95 -0
  19. package/src/components/carousel/features/drag.ts +388 -0
  20. package/src/components/carousel/features/index.ts +8 -0
  21. package/src/components/carousel/features/slides.ts +682 -0
  22. package/src/components/carousel/index.ts +38 -0
  23. package/src/components/carousel/types.ts +327 -0
  24. package/src/components/dialog/_styles.scss +213 -0
  25. package/src/components/dialog/api.ts +283 -0
  26. package/src/components/dialog/config.ts +113 -0
  27. package/src/components/dialog/constants.ts +32 -0
  28. package/src/components/dialog/dialog.ts +56 -0
  29. package/src/components/dialog/features.ts +713 -0
  30. package/src/components/dialog/index.ts +15 -0
  31. package/src/components/dialog/types.ts +221 -0
  32. package/src/components/progress/_styles.scss +13 -1
  33. package/src/components/progress/api.ts +2 -2
  34. package/src/components/progress/progress.ts +2 -2
  35. package/src/components/progress/types.ts +3 -0
  36. package/src/components/radios/_styles.scss +232 -0
  37. package/src/components/radios/api.ts +100 -0
  38. package/src/components/radios/config.ts +60 -0
  39. package/src/components/radios/constants.ts +28 -0
  40. package/src/components/radios/index.ts +4 -0
  41. package/src/components/radios/radio.ts +269 -0
  42. package/src/components/radios/radios.ts +42 -0
  43. package/src/components/radios/types.ts +232 -0
  44. package/src/components/sheet/_styles.scss +236 -0
  45. package/src/components/sheet/api.ts +96 -0
  46. package/src/components/sheet/config.ts +66 -0
  47. package/src/components/sheet/constants.ts +20 -0
  48. package/src/components/sheet/features/content.ts +51 -0
  49. package/src/components/sheet/features/gestures.ts +177 -0
  50. package/src/components/sheet/features/index.ts +6 -0
  51. package/src/components/sheet/features/position.ts +42 -0
  52. package/src/components/sheet/features/state.ts +116 -0
  53. package/src/components/sheet/features/title.ts +86 -0
  54. package/src/components/sheet/index.ts +4 -0
  55. package/src/components/sheet/sheet.ts +57 -0
  56. package/src/components/sheet/types.ts +266 -0
  57. package/src/components/slider/_styles.scss +518 -0
  58. package/src/components/slider/api.ts +336 -0
  59. package/src/components/slider/config.ts +145 -0
  60. package/src/components/slider/constants.ts +28 -0
  61. package/src/components/slider/features/appearance.ts +140 -0
  62. package/src/components/slider/features/disabled.ts +43 -0
  63. package/src/components/slider/features/events.ts +164 -0
  64. package/src/components/slider/features/index.ts +5 -0
  65. package/src/components/slider/features/interactions.ts +256 -0
  66. package/src/components/slider/features/keyboard.ts +114 -0
  67. package/src/components/slider/features/slider.ts +336 -0
  68. package/src/components/slider/features/structure.ts +264 -0
  69. package/src/components/slider/features/ui.ts +518 -0
  70. package/src/components/slider/index.ts +9 -0
  71. package/src/components/slider/slider.ts +58 -0
  72. package/src/components/slider/types.ts +166 -0
  73. package/src/components/tabs/_styles.scss +224 -0
  74. package/src/components/tabs/api.ts +443 -0
  75. package/src/components/tabs/config.ts +80 -0
  76. package/src/components/tabs/constants.ts +12 -0
  77. package/src/components/tabs/index.ts +4 -0
  78. package/src/components/tabs/tabs.ts +52 -0
  79. package/src/components/tabs/types.ts +247 -0
  80. package/src/components/textfield/_styles.scss +97 -4
  81. package/src/components/tooltip/_styles.scss +241 -0
  82. package/src/components/tooltip/api.ts +411 -0
  83. package/src/components/tooltip/config.ts +78 -0
  84. package/src/components/tooltip/constants.ts +27 -0
  85. package/src/components/tooltip/index.ts +4 -0
  86. package/src/components/tooltip/tooltip.ts +60 -0
  87. package/src/components/tooltip/types.ts +178 -0
  88. package/src/core/build/_ripple.scss +79 -0
  89. package/src/core/build/constants.ts +48 -0
  90. package/src/core/build/icon.ts +137 -0
  91. package/src/core/build/ripple.ts +216 -0
  92. package/src/core/build/text.ts +91 -0
  93. package/src/index.ts +9 -1
  94. package/src/styles/abstract/_variables.scss +24 -12
  95. package/tsconfig.json +22 -0
  96. package/typedoc.json +28 -0
  97. package/typedoc.simple.json +14 -0
package/.typedocignore ADDED
@@ -0,0 +1,11 @@
1
+ # Ignore files with TypeScript errors
2
+ src/components/snackbar/api.ts
3
+ src/components/snackbar/config.ts
4
+ src/components/snackbar/features.ts
5
+ src/components/snackbar/index.ts
6
+ src/components/snackbar/position.ts
7
+ src/components/snackbar/queue.ts
8
+ src/components/snackbar/snackbar.ts
9
+ src/components/chip/chip-set.ts
10
+ src/components/chip/chip.ts
11
+ src/components/menu/features/items-manager.ts
package/DOCS.md ADDED
@@ -0,0 +1,153 @@
1
+ # TypeDoc Installation and Usage Guide for MTRL
2
+
3
+ This guide will help you set up and use TypeDoc with your MTRL library.
4
+
5
+ ## Installation
6
+
7
+ To install TypeDoc and its dependencies:
8
+
9
+ ```bash
10
+ # Using Bun
11
+ bun add -D typedoc
12
+
13
+ # Using npm
14
+ npm install --save-dev typedoc
15
+
16
+ # Using yarn
17
+ yarn add --dev typedoc
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ TypeDoc is configured via the `typedoc.json` file at the root of your project. This configuration specifies input files, output directory, theming options, and more.
23
+
24
+ ## Generating Documentation
25
+
26
+ To generate documentation:
27
+
28
+ ```bash
29
+ # Using the npm script
30
+ bun run docs
31
+
32
+ # Or directly
33
+ bun typedoc
34
+ ```
35
+
36
+ ## Serving Documentation Locally
37
+
38
+ To view the generated documentation in your browser:
39
+
40
+ ```bash
41
+ # Using the npm script
42
+ bun run docs:serve
43
+
44
+ # Or directly
45
+ bun run --bun serve docs
46
+ ```
47
+
48
+ Then open your browser to http://localhost:8080
49
+
50
+ ## Documentation Structure
51
+
52
+ TypeDoc generates a structured representation of your codebase:
53
+
54
+ - **Modules**: File-based organization of your code
55
+ - **Classes/Interfaces**: Object definitions and their members
56
+ - **Functions**: Standalone functions
57
+ - **Type aliases**: Custom type definitions
58
+ - **Variables**: Exported variables
59
+
60
+ ## JSDoc Tips for Better Documentation
61
+
62
+ TypeDoc uses JSDoc comments to generate documentation. Here are some tips for writing effective comments:
63
+
64
+ ### Basic Comment Structure
65
+
66
+ ```typescript
67
+ /**
68
+ * Description of the function
69
+ * @param paramName Description of the parameter
70
+ * @returns Description of the return value
71
+ */
72
+ function myFunction(paramName: string): number {
73
+ // Implementation
74
+ }
75
+ ```
76
+
77
+ ### Common JSDoc Tags
78
+
79
+ - `@param {type} name - Description` - Describes a function parameter
80
+ - `@returns {type} Description` - Describes the return value
81
+ - `@example` - Provides an example of usage
82
+ - `@see` - References related documentation
83
+ - `@deprecated` - Marks an element as deprecated
84
+ - `@since version` - Indicates when the element was added
85
+ - `@category name` - Organizes documentation into categories
86
+
87
+ ### Categories
88
+
89
+ Use the `@category` tag to organize your MTRL components and utilities:
90
+
91
+ ```typescript
92
+ /**
93
+ * @category Components
94
+ */
95
+ export interface ButtonConfig {
96
+ // ...
97
+ }
98
+
99
+ /**
100
+ * @category Core
101
+ */
102
+ export const pipe = (...fns) => (initialValue) => {
103
+ // ...
104
+ }
105
+ ```
106
+
107
+ ## Customizing the Theme
108
+
109
+ If you want to customize the default theme, you can create a custom theme:
110
+
111
+ 1. Create a `typedoc-theme` directory
112
+ 2. Copy the default theme files from the TypeDoc package
113
+ 3. Modify the files as needed
114
+ 4. Update the `typedoc.json` file to use your custom theme:
115
+
116
+ ```json
117
+ {
118
+ "theme": "./typedoc-theme"
119
+ }
120
+ ```
121
+
122
+ ## Continuous Integration
123
+
124
+ To automatically generate documentation on each commit or release:
125
+
126
+ 1. Add a script to your CI workflow (GitHub Actions, etc.)
127
+ 2. Generate the docs and deploy them to GitHub Pages or another hosting service
128
+
129
+ Example GitHub Actions workflow:
130
+
131
+ ```yaml
132
+ name: Generate Docs
133
+
134
+ on:
135
+ push:
136
+ branches: [main]
137
+
138
+ jobs:
139
+ build:
140
+ runs-on: ubuntu-latest
141
+ steps:
142
+ - uses: actions/checkout@v3
143
+ - uses: oven-sh/setup-bun@v1
144
+ - name: Install dependencies
145
+ run: bun install
146
+ - name: Generate docs
147
+ run: bun run docs
148
+ - name: Deploy to GitHub Pages
149
+ uses: JamesIves/github-pages-deploy-action@4.1.4
150
+ with:
151
+ branch: gh-pages
152
+ folder: docs
153
+ ```
package/index.ts CHANGED
@@ -2,32 +2,47 @@
2
2
  import {
3
3
  createLayout,
4
4
  createElement,
5
+ createBadge,
5
6
  createButton,
6
7
  createCard,
8
+ createCarousel,
7
9
  createCheckbox,
8
10
  createChip,
11
+ createDialog,
9
12
  createList,
10
13
  createMenu,
11
14
  createNavigation,
12
15
  createProgress,
13
- createTextfield,
16
+ createRadios,
17
+ createSheet,
18
+ createSlider,
14
19
  createSnackbar,
20
+ createTabs,
21
+ createTextfield,
22
+ createTooltip,
15
23
  createSwitch
16
-
17
24
  } from './src/index.js'
18
25
 
19
26
  export {
20
27
  createLayout,
21
28
  createElement,
29
+ createBadge,
22
30
  createButton,
23
31
  createCard,
32
+ createCarousel,
24
33
  createCheckbox,
25
34
  createChip,
35
+ createDialog,
26
36
  createList,
27
37
  createMenu,
28
38
  createNavigation,
29
39
  createProgress,
30
- createTextfield,
40
+ createRadios,
41
+ createSheet,
42
+ createSlider,
31
43
  createSnackbar,
44
+ createTabs,
45
+ createTextfield,
46
+ createTooltip,
32
47
  createSwitch
33
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtrl",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "A functional JavaScript component library with composable architecture based on Material Design 3",
5
5
  "keywords": [
6
6
  "component",
@@ -15,7 +15,12 @@
15
15
  "test": "bun test",
16
16
  "test:watch": "bun test --watch",
17
17
  "test:coverage": "bun test --coverage",
18
- "test:ui": "bun test --watch --ui"
18
+ "test:ui": "bun test --watch --ui",
19
+ "docs": "typedoc --skipErrorChecking",
20
+ "docs:js": "typedoc --options typedoc.simple.json",
21
+ "docs:alt": "bun generate-docs.js",
22
+ "docs:serve": "bun run --bun serve docs",
23
+ "docs:fix-errors": "tsc --noEmit --allowJs --skipLibCheck"
19
24
  },
20
25
  "repository": {
21
26
  "type": "git",
@@ -0,0 +1,174 @@
1
+ // src/components/badge/_styles.scss
2
+ @use '../../styles/abstract/base' as base;
3
+ @use '../../styles/abstract/variables' as v;
4
+ @use '../../styles/abstract/functions' as f;
5
+ @use '../../styles/abstract/mixins' as m;
6
+ @use '../../styles/abstract/theme' as t;
7
+
8
+ $component: '#{base.$prefix}-badge';
9
+
10
+ .#{$component} {
11
+ // Base styles
12
+ position: relative;
13
+ display: inline-flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ box-sizing: border-box;
17
+ min-width: 20px;
18
+ height: 20px;
19
+ padding: 0 6px;
20
+ border-radius: 10px;
21
+ background-color: t.color('error');
22
+ color: t.color('on-error');
23
+ font-size: 11px;
24
+ font-weight: 500;
25
+ line-height: 1;
26
+ letter-spacing: 0.5px;
27
+ white-space: nowrap;
28
+ text-align: center;
29
+
30
+ // Badge parent wrapper
31
+ &-wrapper {
32
+ position: relative;
33
+ display: inline-flex;
34
+ }
35
+
36
+ // Default positioning (top-right)
37
+ &--positioned {
38
+ position: absolute;
39
+ top: -8px;
40
+ right: -8px;
41
+ transform: translate(50%, -50%);
42
+ }
43
+
44
+ // Dot variant
45
+ &--dot {
46
+ min-width: 8px;
47
+ height: 8px;
48
+ padding: 0;
49
+ border-radius: 50%;
50
+ }
51
+
52
+ // Small size
53
+ &--small {
54
+ min-width: 16px;
55
+ height: 16px;
56
+ font-size: 10px;
57
+ padding: 0 4px;
58
+ }
59
+
60
+ // Large size
61
+ &--large {
62
+ min-width: 24px;
63
+ height: 24px;
64
+ font-size: 12px;
65
+ padding: 0 8px;
66
+ }
67
+
68
+ // Position variants
69
+ &--top-left {
70
+ top: 0;
71
+ left: 0;
72
+ transform: translate(-50%, -50%);
73
+ }
74
+
75
+ &--top-right {
76
+ top: 0;
77
+ right: 0;
78
+ transform: translate(50%, -50%);
79
+ }
80
+
81
+ &--bottom-left {
82
+ bottom: 0;
83
+ left: 0;
84
+ transform: translate(-50%, 50%);
85
+ }
86
+
87
+ &--bottom-right {
88
+ bottom: 0;
89
+ right: 0;
90
+ transform: translate(50%, 50%);
91
+ }
92
+
93
+ // Color variants
94
+ &--primary {
95
+ background-color: t.color('primary');
96
+ color: t.color('on-primary');
97
+ }
98
+
99
+ &--secondary {
100
+ background-color: t.color('secondary');
101
+ color: t.color('on-secondary');
102
+ }
103
+
104
+ &--tertiary {
105
+ background-color: t.color('tertiary');
106
+ color: t.color('on-tertiary');
107
+ }
108
+
109
+ &--error {
110
+ background-color: t.color('error');
111
+ color: t.color('on-error');
112
+ }
113
+
114
+ &--success {
115
+ background-color: t.color('success', t.color('primary'));
116
+ color: t.color('on-success', t.color('on-primary'));
117
+ }
118
+
119
+ &--warning {
120
+ background-color: t.color('warning', t.color('tertiary'));
121
+ color: t.color('on-warning', t.color('on-tertiary'));
122
+ }
123
+
124
+ &--info {
125
+ background-color: t.color('info', t.color('secondary'));
126
+ color: t.color('on-info', t.color('on-secondary'));
127
+ }
128
+
129
+ // Outline variant
130
+ &--outlined {
131
+ background-color: transparent;
132
+ border: 1px solid currentColor;
133
+
134
+ &.#{$component}--primary {
135
+ color: t.color('primary');
136
+ }
137
+
138
+ &.#{$component}--secondary {
139
+ color: t.color('secondary');
140
+ }
141
+
142
+ &.#{$component}--tertiary {
143
+ color: t.color('tertiary');
144
+ }
145
+
146
+ &.#{$component}--error {
147
+ color: t.color('error');
148
+ }
149
+
150
+ &.#{$component}--success {
151
+ color: t.color('success', t.color('primary'));
152
+ }
153
+
154
+ &.#{$component}--warning {
155
+ color: t.color('warning', t.color('tertiary'));
156
+ }
157
+
158
+ &.#{$component}--info {
159
+ color: t.color('info', t.color('secondary'));
160
+ }
161
+ }
162
+
163
+ // Max value handling
164
+ &--max {
165
+ &::after {
166
+ content: '+';
167
+ }
168
+ }
169
+
170
+ // Invisible
171
+ &--invisible {
172
+ display: none;
173
+ }
174
+ }
@@ -0,0 +1,292 @@
1
+ // src/components/badge/api.ts
2
+ import { BadgeComponent } from './types';
3
+ import { BADGE_VARIANTS, BADGE_SIZES, BADGE_COLORS, BADGE_POSITIONS } from './constants';
4
+
5
+ interface ApiOptions {
6
+ visibility: {
7
+ show: () => void;
8
+ hide: () => void;
9
+ toggle: (visible?: boolean) => void;
10
+ isVisible: () => boolean;
11
+ };
12
+ lifecycle: {
13
+ destroy: () => void;
14
+ };
15
+ }
16
+
17
+ interface ComponentWithElements {
18
+ element: HTMLElement;
19
+ wrapper?: HTMLElement;
20
+ config: {
21
+ max?: number;
22
+ content?: string | number;
23
+ };
24
+ getClass: (name: string) => string;
25
+ addClass: (...classes: string[]) => any;
26
+ removeClass: (...classes: string[]) => any;
27
+ on: (event: string, handler: Function) => any;
28
+ off: (event: string, handler: Function) => any;
29
+ }
30
+
31
+ /**
32
+ * Enhances a badge component with API methods
33
+ * @param {ApiOptions} options - API configuration options
34
+ * @returns {Function} Higher-order function that adds API methods to component
35
+ * @internal This is an internal utility for the Badge component
36
+ */
37
+ export const withAPI = ({ visibility, lifecycle }: ApiOptions) =>
38
+ (component: ComponentWithElements): BadgeComponent => ({
39
+ ...component as any,
40
+
41
+ /**
42
+ * Sets the badge content
43
+ * @param {string|number} content - Content to display in the badge
44
+ * @returns {BadgeComponent} Badge component instance for chaining
45
+ */
46
+ setContent(content: string | number) {
47
+ const stringContent = String(content);
48
+ component.config.content = content;
49
+
50
+ // If max is defined and content is a number greater than max, show max+
51
+ if (component.config.max !== undefined &&
52
+ typeof content === 'number' &&
53
+ content > component.config.max) {
54
+ component.element.textContent = String(component.config.max);
55
+ component.element.classList.add(`${component.getClass('badge')}--max`);
56
+ } else {
57
+ component.element.textContent = stringContent;
58
+ component.element.classList.remove(`${component.getClass('badge')}--max`);
59
+ }
60
+
61
+ // Toggle the dot variant based on whether content is empty
62
+ if (stringContent === '' || stringContent === '0') {
63
+ this.hide();
64
+ } else {
65
+ this.show();
66
+ }
67
+
68
+ return this;
69
+ },
70
+
71
+ /**
72
+ * Gets the badge content
73
+ * @returns {string} Current badge content
74
+ */
75
+ getContent() {
76
+ return component.element.textContent || '';
77
+ },
78
+
79
+ /**
80
+ * Shows the badge
81
+ * @returns {BadgeComponent} Badge component instance for chaining
82
+ */
83
+ show() {
84
+ visibility.show();
85
+ return this;
86
+ },
87
+
88
+ /**
89
+ * Hides the badge
90
+ * @returns {BadgeComponent} Badge component instance for chaining
91
+ */
92
+ hide() {
93
+ visibility.hide();
94
+ return this;
95
+ },
96
+
97
+ /**
98
+ * Toggles badge visibility
99
+ * @param {boolean} [visible] - Optional flag to force visibility state
100
+ * @returns {BadgeComponent} Badge component instance for chaining
101
+ */
102
+ toggle(visible?: boolean) {
103
+ visibility.toggle(visible);
104
+ return this;
105
+ },
106
+
107
+ /**
108
+ * Checks if the badge is visible
109
+ * @returns {boolean} True if badge is visible
110
+ */
111
+ isVisible() {
112
+ return visibility.isVisible();
113
+ },
114
+
115
+ /**
116
+ * Sets maximum value (after which badge shows max+)
117
+ * @param {number} max - Maximum value to display
118
+ * @returns {BadgeComponent} Badge component instance for chaining
119
+ */
120
+ setMax(max: number) {
121
+ component.config.max = max;
122
+
123
+ // Apply max formatting if current content exceeds max
124
+ if (typeof component.config.content === 'number' &&
125
+ component.config.content > max) {
126
+ component.element.textContent = String(max);
127
+ component.element.classList.add(`${component.getClass('badge')}--max`);
128
+ } else {
129
+ component.element.classList.remove(`${component.getClass('badge')}--max`);
130
+ }
131
+
132
+ return this;
133
+ },
134
+
135
+ /**
136
+ * Sets badge color
137
+ * @param {string} color - Color variant to apply
138
+ * @returns {BadgeComponent} Badge component instance for chaining
139
+ */
140
+ setColor(color: keyof typeof BADGE_COLORS | BADGE_COLORS) {
141
+ // Remove existing color classes
142
+ Object.values(BADGE_COLORS).forEach(colorName => {
143
+ component.element.classList.remove(`${component.getClass('badge')}--${colorName}`);
144
+ });
145
+
146
+ // Add new color class
147
+ component.element.classList.add(`${component.getClass('badge')}--${color}`);
148
+ return this;
149
+ },
150
+
151
+ /**
152
+ * Sets badge variant
153
+ * @param {string} variant - Variant to apply
154
+ * @returns {BadgeComponent} Badge component instance for chaining
155
+ */
156
+ setVariant(variant: keyof typeof BADGE_VARIANTS | BADGE_VARIANTS) {
157
+ // Remove existing variant classes
158
+ Object.values(BADGE_VARIANTS).forEach(variantName => {
159
+ component.element.classList.remove(`${component.getClass('badge')}--${variantName}`);
160
+ });
161
+
162
+ // Add new variant class if not standard
163
+ if (variant !== BADGE_VARIANTS.STANDARD) {
164
+ component.element.classList.add(`${component.getClass('badge')}--${variant}`);
165
+ }
166
+
167
+ // Clear content if dot variant
168
+ if (variant === BADGE_VARIANTS.DOT) {
169
+ component.element.textContent = '';
170
+ } else if (component.config.content !== undefined) {
171
+ this.setContent(component.config.content);
172
+ }
173
+
174
+ return this;
175
+ },
176
+
177
+ /**
178
+ * Sets badge size
179
+ * @param {string} size - Size variant to apply
180
+ * @returns {BadgeComponent} Badge component instance for chaining
181
+ */
182
+ setSize(size: keyof typeof BADGE_SIZES | BADGE_SIZES) {
183
+ // Remove existing size classes
184
+ Object.values(BADGE_SIZES).forEach(sizeName => {
185
+ component.element.classList.remove(`${component.getClass('badge')}--${sizeName}`);
186
+ });
187
+
188
+ // Add new size class if not medium (default)
189
+ if (size !== BADGE_SIZES.MEDIUM) {
190
+ component.element.classList.add(`${component.getClass('badge')}--${size}`);
191
+ }
192
+
193
+ return this;
194
+ },
195
+
196
+ /**
197
+ * Sets badge position
198
+ * @param {string} position - Position variant to apply
199
+ * @returns {BadgeComponent} Badge component instance for chaining
200
+ */
201
+ setPosition(position: keyof typeof BADGE_POSITIONS | BADGE_POSITIONS) {
202
+ // Remove existing position classes
203
+ Object.values(BADGE_POSITIONS).forEach(posName => {
204
+ component.element.classList.remove(`${component.getClass('badge')}--${posName}`);
205
+ });
206
+
207
+ // Add new position class
208
+ component.element.classList.add(`${component.getClass('badge')}--${position}`);
209
+
210
+ return this;
211
+ },
212
+
213
+ /**
214
+ * Attaches badge to a target element
215
+ * @param {HTMLElement} target - Element to attach badge to
216
+ * @returns {BadgeComponent} Badge component instance for chaining
217
+ */
218
+ attachTo(target: HTMLElement) {
219
+ // If we already have a wrapper, remove the badge from it
220
+ if (component.wrapper && component.wrapper.contains(component.element)) {
221
+ component.wrapper.removeChild(component.element);
222
+ }
223
+
224
+ // Create a new wrapper to hold the target and badge
225
+ const wrapper = document.createElement('div');
226
+ wrapper.classList.add(component.getClass('badge-wrapper'));
227
+
228
+ // Replace the target with the wrapper
229
+ const parent = target.parentNode;
230
+ if (parent) {
231
+ parent.replaceChild(wrapper, target);
232
+ wrapper.appendChild(target);
233
+ wrapper.appendChild(component.element);
234
+
235
+ // Make sure the badge is positioned
236
+ component.element.classList.add(`${component.getClass('badge')}--positioned`);
237
+
238
+ // Save the wrapper reference
239
+ component.wrapper = wrapper;
240
+ }
241
+
242
+ return this;
243
+ },
244
+
245
+ /**
246
+ * Makes badge standalone (removes from wrapper)
247
+ * @returns {BadgeComponent} Badge component instance for chaining
248
+ */
249
+ detach() {
250
+ if (component.wrapper && component.wrapper.contains(component.element)) {
251
+ // Remove the badge from the wrapper
252
+ component.wrapper.removeChild(component.element);
253
+
254
+ // Remove the positioned class
255
+ component.element.classList.remove(`${component.getClass('badge')}--positioned`);
256
+
257
+ // Add the badge to the document body or another container
258
+ document.body.appendChild(component.element);
259
+
260
+ // Clear the wrapper reference
261
+ component.wrapper = undefined;
262
+ }
263
+
264
+ return this;
265
+ },
266
+
267
+ /**
268
+ * Destroys the badge component and cleans up resources
269
+ */
270
+ destroy() {
271
+ lifecycle.destroy();
272
+
273
+ // If badge is in a wrapper, restore the original DOM structure
274
+ if (component.wrapper) {
275
+ const target = component.wrapper.firstChild as HTMLElement;
276
+ const parent = component.wrapper.parentNode;
277
+
278
+ if (parent && target) {
279
+ parent.replaceChild(target, component.wrapper);
280
+ }
281
+ }
282
+ },
283
+
284
+ // Forward basic component methods for API consistency
285
+ getClass: component.getClass,
286
+ addClass: component.addClass,
287
+ removeClass: component.removeClass,
288
+ on: component.on,
289
+ off: component.off,
290
+ element: component.element,
291
+ wrapper: component.wrapper
292
+ });