@m3ui-vue/m3ui-vue 0.1.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.
Files changed (185) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/dist/components/MAlert.vue.d.ts +27 -0
  4. package/dist/components/MAppBar.vue.d.ts +24 -0
  5. package/dist/components/MAvatar.vue.d.ts +9 -0
  6. package/dist/components/MBadge.vue.d.ts +22 -0
  7. package/dist/components/MBottomSheet.vue.d.ts +26 -0
  8. package/dist/components/MBreadcrumbs.vue.d.ts +19 -0
  9. package/dist/components/MButton.vue.d.ts +32 -0
  10. package/dist/components/MCalendar.vue.d.ts +23 -0
  11. package/dist/components/MCard.vue.d.ts +28 -0
  12. package/dist/components/MChart.vue.d.ts +13 -0
  13. package/dist/components/MCheckbox.vue.d.ts +26 -0
  14. package/dist/components/MChip.vue.d.ts +33 -0
  15. package/dist/components/MCodeEditor.vue.d.ts +35 -0
  16. package/dist/components/MColorPicker.vue.d.ts +18 -0
  17. package/dist/components/MCommandPalette.vue.d.ts +29 -0
  18. package/dist/components/MConfirmDialog.vue.d.ts +23 -0
  19. package/dist/components/MContainer.vue.d.ts +24 -0
  20. package/dist/components/MContextMenu.vue.d.ts +35 -0
  21. package/dist/components/MDataTable.vue.d.ts +83 -0
  22. package/dist/components/MDatePicker.vue.d.ts +21 -0
  23. package/dist/components/MDateRangePicker.vue.d.ts +24 -0
  24. package/dist/components/MDialog.vue.d.ts +30 -0
  25. package/dist/components/MDivider.vue.d.ts +11 -0
  26. package/dist/components/MDragDropList.vue.d.ts +40 -0
  27. package/dist/components/MEmptyState.vue.d.ts +21 -0
  28. package/dist/components/MExpansionPanel.vue.d.ts +28 -0
  29. package/dist/components/MFab.vue.d.ts +28 -0
  30. package/dist/components/MFileUpload.vue.d.ts +25 -0
  31. package/dist/components/MGrid.vue.d.ts +26 -0
  32. package/dist/components/MHotkeys.vue.d.ts +16 -0
  33. package/dist/components/MIcon.vue.d.ts +9 -0
  34. package/dist/components/MIconButton.vue.d.ts +14 -0
  35. package/dist/components/MInfiniteScroll.vue.d.ts +34 -0
  36. package/dist/components/MJsonEditor.vue.d.ts +17 -0
  37. package/dist/components/MJsonViewer.vue.d.ts +14 -0
  38. package/dist/components/MKanban.vue.d.ts +53 -0
  39. package/dist/components/MLoadingOverlay.vue.d.ts +28 -0
  40. package/dist/components/MMarkdown.vue.d.ts +11 -0
  41. package/dist/components/MMasonry.vue.d.ts +23 -0
  42. package/dist/components/MMenu.vue.d.ts +27 -0
  43. package/dist/components/MMenuItem.vue.d.ts +16 -0
  44. package/dist/components/MMultiSelect.vue.d.ts +34 -0
  45. package/dist/components/MNavigationBar.vue.d.ts +18 -0
  46. package/dist/components/MNavigationDrawer.vue.d.ts +41 -0
  47. package/dist/components/MNavigationRail.vue.d.ts +32 -0
  48. package/dist/components/MPagination.vue.d.ts +12 -0
  49. package/dist/components/MProgressBar.vue.d.ts +13 -0
  50. package/dist/components/MRadio.vue.d.ts +17 -0
  51. package/dist/components/MRadioGroup.vue.d.ts +24 -0
  52. package/dist/components/MRating.vue.d.ts +23 -0
  53. package/dist/components/MResult.vue.d.ts +20 -0
  54. package/dist/components/MRichTextEditor.vue.d.ts +17 -0
  55. package/dist/components/MScheduler.vue.d.ts +35 -0
  56. package/dist/components/MSegmentedButton.vue.d.ts +24 -0
  57. package/dist/components/MSelect.vue.d.ts +29 -0
  58. package/dist/components/MSideSheet.vue.d.ts +28 -0
  59. package/dist/components/MSkeleton.vue.d.ts +14 -0
  60. package/dist/components/MSlider.vue.d.ts +24 -0
  61. package/dist/components/MSnackbar.vue.d.ts +3 -0
  62. package/dist/components/MSpinner.vue.d.ts +10 -0
  63. package/dist/components/MSplitter.vue.d.ts +26 -0
  64. package/dist/components/MSpotlightSearch.vue.d.ts +34 -0
  65. package/dist/components/MStack.vue.d.ts +30 -0
  66. package/dist/components/MStatCard.vue.d.ts +24 -0
  67. package/dist/components/MStepper.vue.d.ts +33 -0
  68. package/dist/components/MSwitch.vue.d.ts +14 -0
  69. package/dist/components/MTable.vue.d.ts +73 -0
  70. package/dist/components/MTabs.vue.d.ts +20 -0
  71. package/dist/components/MTerminal.vue.d.ts +25 -0
  72. package/dist/components/MTextField.vue.d.ts +41 -0
  73. package/dist/components/MTimePicker.vue.d.ts +20 -0
  74. package/dist/components/MTimeline.vue.d.ts +31 -0
  75. package/dist/components/MTooltip.vue.d.ts +21 -0
  76. package/dist/components/MTopAppBar.vue.d.ts +29 -0
  77. package/dist/components/MTour.vue.d.ts +19 -0
  78. package/dist/components/MTransferList.vue.d.ts +23 -0
  79. package/dist/components/MTree.vue.d.ts +68 -0
  80. package/dist/components/MTreeTable.vue.d.ts +57 -0
  81. package/dist/components/MVirtualTable.vue.d.ts +40 -0
  82. package/dist/components/_MContextMenuPanel.vue.d.ts +13 -0
  83. package/dist/components/_MTreeNode.vue.d.ts +26 -0
  84. package/dist/composables/useColorPalette.d.ts +11 -0
  85. package/dist/composables/useFieldBg.d.ts +13 -0
  86. package/dist/composables/useTheme.d.ts +5 -0
  87. package/dist/composables/useToast.d.ts +59 -0
  88. package/dist/index.d.ts +112 -0
  89. package/dist/m3ui.css +2 -0
  90. package/dist/m3ui.js +7432 -0
  91. package/dist/m3ui.js.map +1 -0
  92. package/dist/plugin.d.ts +9 -0
  93. package/dist/styles/palettes.css +1253 -0
  94. package/dist/styles/theme.css +249 -0
  95. package/package.json +166 -0
  96. package/src/components/MAlert.vue +69 -0
  97. package/src/components/MAppBar.vue +40 -0
  98. package/src/components/MAvatar.vue +21 -0
  99. package/src/components/MBadge.vue +46 -0
  100. package/src/components/MBottomSheet.vue +113 -0
  101. package/src/components/MBreadcrumbs.vue +52 -0
  102. package/src/components/MButton.vue +111 -0
  103. package/src/components/MCalendar.vue +173 -0
  104. package/src/components/MCard.vue +56 -0
  105. package/src/components/MChart.vue +158 -0
  106. package/src/components/MCheckbox.vue +48 -0
  107. package/src/components/MChip.vue +87 -0
  108. package/src/components/MCodeEditor.vue +179 -0
  109. package/src/components/MColorPicker.vue +305 -0
  110. package/src/components/MCommandPalette.vue +213 -0
  111. package/src/components/MConfirmDialog.vue +43 -0
  112. package/src/components/MContainer.vue +36 -0
  113. package/src/components/MContextMenu.vue +66 -0
  114. package/src/components/MDataTable.vue +376 -0
  115. package/src/components/MDatePicker.vue +253 -0
  116. package/src/components/MDateRangePicker.vue +265 -0
  117. package/src/components/MDialog.vue +90 -0
  118. package/src/components/MDivider.vue +26 -0
  119. package/src/components/MDragDropList.vue +111 -0
  120. package/src/components/MEmptyState.vue +40 -0
  121. package/src/components/MExpansionPanel.vue +112 -0
  122. package/src/components/MFab.vue +220 -0
  123. package/src/components/MFileUpload.vue +206 -0
  124. package/src/components/MGrid.vue +99 -0
  125. package/src/components/MHotkeys.vue +122 -0
  126. package/src/components/MIcon.vue +9 -0
  127. package/src/components/MIconButton.vue +49 -0
  128. package/src/components/MInfiniteScroll.vue +68 -0
  129. package/src/components/MJsonEditor.vue +118 -0
  130. package/src/components/MJsonViewer.vue +106 -0
  131. package/src/components/MKanban.vue +147 -0
  132. package/src/components/MLoadingOverlay.vue +52 -0
  133. package/src/components/MMarkdown.vue +123 -0
  134. package/src/components/MMasonry.vue +87 -0
  135. package/src/components/MMenu.vue +113 -0
  136. package/src/components/MMenuItem.vue +15 -0
  137. package/src/components/MMultiSelect.vue +306 -0
  138. package/src/components/MNavigationBar.vue +62 -0
  139. package/src/components/MNavigationDrawer.vue +157 -0
  140. package/src/components/MNavigationRail.vue +80 -0
  141. package/src/components/MPagination.vue +37 -0
  142. package/src/components/MProgressBar.vue +200 -0
  143. package/src/components/MRadio.vue +89 -0
  144. package/src/components/MRadioGroup.vue +41 -0
  145. package/src/components/MRating.vue +108 -0
  146. package/src/components/MResult.vue +62 -0
  147. package/src/components/MRichTextEditor.vue +199 -0
  148. package/src/components/MScheduler.vue +225 -0
  149. package/src/components/MSegmentedButton.vue +75 -0
  150. package/src/components/MSelect.vue +259 -0
  151. package/src/components/MSideSheet.vue +112 -0
  152. package/src/components/MSkeleton.vue +60 -0
  153. package/src/components/MSlider.vue +188 -0
  154. package/src/components/MSnackbar.vue +244 -0
  155. package/src/components/MSpinner.vue +122 -0
  156. package/src/components/MSplitter.vue +97 -0
  157. package/src/components/MSpotlightSearch.vue +244 -0
  158. package/src/components/MStack.vue +67 -0
  159. package/src/components/MStatCard.vue +56 -0
  160. package/src/components/MStepper.vue +161 -0
  161. package/src/components/MSwitch.vue +63 -0
  162. package/src/components/MTable.vue +404 -0
  163. package/src/components/MTabs.vue +97 -0
  164. package/src/components/MTerminal.vue +146 -0
  165. package/src/components/MTextField.vue +180 -0
  166. package/src/components/MTimePicker.vue +227 -0
  167. package/src/components/MTimeline.vue +117 -0
  168. package/src/components/MTooltip.vue +82 -0
  169. package/src/components/MTopAppBar.vue +62 -0
  170. package/src/components/MTour.vue +226 -0
  171. package/src/components/MTransferList.vue +181 -0
  172. package/src/components/MTree.vue +164 -0
  173. package/src/components/MTreeTable.vue +159 -0
  174. package/src/components/MVirtualTable.vue +155 -0
  175. package/src/components/_MContextMenuPanel.vue +129 -0
  176. package/src/components/_MTreeNode.vue +171 -0
  177. package/src/composables/useColorPalette.ts +60 -0
  178. package/src/composables/useFieldBg.ts +91 -0
  179. package/src/composables/useTheme.ts +55 -0
  180. package/src/composables/useToast.ts +51 -0
  181. package/src/env.d.ts +1 -0
  182. package/src/index.ts +119 -0
  183. package/src/plugin.ts +18 -0
  184. package/src/styles/palettes.css +1253 -0
  185. package/src/styles/theme.css +249 -0
@@ -0,0 +1,249 @@
1
+ /* Enable class-based dark mode for Tailwind v4 */
2
+ @custom-variant dark (&:where(.dark, .dark *));
3
+
4
+ /* ---------------------------------------------------------------------- */
5
+ /* Material 3 design tokens — light theme (baseline purple) */
6
+ /* ---------------------------------------------------------------------- */
7
+ @theme {
8
+ --font-sans: 'Roboto', system-ui, -apple-system, sans-serif;
9
+
10
+ /* Color roles */
11
+ --color-primary: #6750a4;
12
+ --color-on-primary: #ffffff;
13
+ --color-primary-container: #eaddff;
14
+ --color-on-primary-container: #21005d;
15
+
16
+ --color-secondary: #625b71;
17
+ --color-on-secondary: #ffffff;
18
+ --color-secondary-container: #e8def8;
19
+ --color-on-secondary-container: #1d192b;
20
+
21
+ --color-tertiary: #7d5260;
22
+ --color-on-tertiary: #ffffff;
23
+ --color-tertiary-container: #ffd8e4;
24
+ --color-on-tertiary-container: #31111d;
25
+
26
+ --color-error: #b3261e;
27
+ --color-on-error: #ffffff;
28
+ --color-error-container: #f9dedc;
29
+ --color-on-error-container: #410e0b;
30
+
31
+ --color-success: #2e7d32;
32
+ --color-on-success: #ffffff;
33
+ --color-success-container: #c8e6c9;
34
+ --color-on-success-container: #0d3311;
35
+
36
+ --color-background: #fffbfe;
37
+ --color-on-background: #1c1b1f;
38
+
39
+ --color-surface: #fffbfe;
40
+ --color-on-surface: #1c1b1f;
41
+ --color-surface-variant: #e7e0ec;
42
+ --color-on-surface-variant: #49454f;
43
+
44
+ --color-surface-dim: #ded8e1;
45
+ --color-surface-bright: #fffbfe;
46
+ --color-surface-container-lowest: #ffffff;
47
+ --color-surface-container-low: #f7f2fa;
48
+ --color-surface-container: #f3edf7;
49
+ --color-surface-container-high: #ece6f0;
50
+ --color-surface-container-highest: #e6e0e9;
51
+
52
+ --color-outline: #79747e;
53
+ --color-outline-variant: #cac4d0;
54
+ --color-shadow: #000000;
55
+
56
+ --color-inverse-surface: #313033;
57
+ --color-inverse-on-surface: #f4eff4;
58
+ --color-inverse-primary: #d0bcff;
59
+
60
+ /* Shape (corner radius) scale */
61
+ --radius-xs: 4px;
62
+ --radius-sm: 8px;
63
+ --radius-md: 12px;
64
+ --radius-lg: 16px;
65
+ --radius-xl: 28px;
66
+
67
+ /* Elevation */
68
+ --shadow-elevation-1: 0px 1px 2px 0px rgb(0 0 0 / 0.3), 0px 1px 3px 1px rgb(0 0 0 / 0.15);
69
+ --shadow-elevation-2: 0px 1px 2px 0px rgb(0 0 0 / 0.3), 0px 2px 6px 2px rgb(0 0 0 / 0.15);
70
+ --shadow-elevation-3: 0px 1px 3px 0px rgb(0 0 0 / 0.3), 0px 4px 8px 3px rgb(0 0 0 / 0.15);
71
+
72
+ /* Type scale */
73
+ --text-display-small: 2.25rem;
74
+ --text-display-small--line-height: 2.75rem;
75
+
76
+ --text-headline-large: 2rem;
77
+ --text-headline-large--line-height: 2.5rem;
78
+ --text-headline-medium: 1.75rem;
79
+ --text-headline-medium--line-height: 2.25rem;
80
+ --text-headline-small: 1.5rem;
81
+ --text-headline-small--line-height: 2rem;
82
+
83
+ --text-title-large: 1.375rem;
84
+ --text-title-large--line-height: 1.75rem;
85
+ --text-title-medium: 1rem;
86
+ --text-title-medium--line-height: 1.5rem;
87
+ --text-title-small: 0.875rem;
88
+ --text-title-small--line-height: 1.25rem;
89
+
90
+ --text-body-large: 1rem;
91
+ --text-body-large--line-height: 1.5rem;
92
+ --text-body-medium: 0.875rem;
93
+ --text-body-medium--line-height: 1.25rem;
94
+ --text-body-small: 0.75rem;
95
+ --text-body-small--line-height: 1rem;
96
+
97
+ --text-label-large: 0.875rem;
98
+ --text-label-large--line-height: 1.25rem;
99
+ --text-label-medium: 0.75rem;
100
+ --text-label-medium--line-height: 1rem;
101
+ --text-label-small: 0.6875rem;
102
+ --text-label-small--line-height: 1rem;
103
+ }
104
+
105
+ /* ---------------------------------------------------------------------- */
106
+ /* Dark theme overrides — M3 baseline purple dark scheme */
107
+ /* ---------------------------------------------------------------------- */
108
+ .dark {
109
+ color-scheme: dark;
110
+
111
+ --color-primary: #d0bcff;
112
+ --color-on-primary: #381e72;
113
+ --color-primary-container: #4f378b;
114
+ --color-on-primary-container: #eaddff;
115
+
116
+ --color-secondary: #ccc2dc;
117
+ --color-on-secondary: #332d41;
118
+ --color-secondary-container: #4a4458;
119
+ --color-on-secondary-container: #e8def8;
120
+
121
+ --color-tertiary: #efb8c8;
122
+ --color-on-tertiary: #492532;
123
+ --color-tertiary-container: #633b48;
124
+ --color-on-tertiary-container: #ffd8e4;
125
+
126
+ --color-error: #f2b8b5;
127
+ --color-on-error: #601410;
128
+ --color-error-container: #8c1d18;
129
+ --color-on-error-container: #f9dedc;
130
+
131
+ --color-success: #81c784;
132
+ --color-on-success: #1b5e20;
133
+ --color-success-container: #2e7d32;
134
+ --color-on-success-container: #c8e6c9;
135
+
136
+ --color-background: #141218;
137
+ --color-on-background: #e6e1e5;
138
+
139
+ --color-surface: #141218;
140
+ --color-on-surface: #e6e1e5;
141
+ --color-surface-variant: #49454f;
142
+ --color-on-surface-variant: #cac4d0;
143
+
144
+ --color-surface-dim: #141218;
145
+ --color-surface-bright: #3b383e;
146
+ --color-surface-container-lowest: #0f0d13;
147
+ --color-surface-container-low: #1d1b20;
148
+ --color-surface-container: #211f26;
149
+ --color-surface-container-high: #2b2930;
150
+ --color-surface-container-highest: #36343b;
151
+
152
+ --color-outline: #938f99;
153
+ --color-outline-variant: #49454f;
154
+ --color-shadow: #000000;
155
+
156
+ --color-inverse-surface: #e6e1e5;
157
+ --color-inverse-on-surface: #313033;
158
+ --color-inverse-primary: #6750a4;
159
+ }
160
+
161
+ /* ---------------------------------------------------------------------- */
162
+ /* Base styles */
163
+ /* ---------------------------------------------------------------------- */
164
+ @layer base {
165
+ :root {
166
+ --field-bg: var(--color-surface);
167
+ }
168
+
169
+ html {
170
+ color-scheme: light;
171
+ }
172
+
173
+ html.dark {
174
+ color-scheme: dark;
175
+ }
176
+
177
+ body {
178
+ @apply bg-surface text-on-surface font-sans text-body-large antialiased;
179
+ }
180
+
181
+ ::selection {
182
+ @apply bg-primary-container text-on-primary-container;
183
+ }
184
+ }
185
+
186
+ .material-symbols-outlined {
187
+ font-family: 'Material Symbols Outlined';
188
+ font-weight: normal;
189
+ font-style: normal;
190
+ font-size: 24px;
191
+ line-height: 1;
192
+ letter-spacing: normal;
193
+ text-transform: none;
194
+ display: inline-block;
195
+ white-space: nowrap;
196
+ word-wrap: normal;
197
+ direction: ltr;
198
+ -webkit-font-feature-settings: 'liga';
199
+ -webkit-font-smoothing: antialiased;
200
+ }
201
+
202
+ * {
203
+ scrollbar-width: thin;
204
+ scrollbar-color: var(--color-outline-variant) transparent;
205
+ }
206
+
207
+ /* ---------------------------------------------------------------------- */
208
+ /* Animations */
209
+ /* ---------------------------------------------------------------------- */
210
+ @keyframes m3-progress-indeterminate {
211
+ 0% { left: -50%; width: 40% }
212
+ 60% { left: 110%; width: 40% }
213
+ 100% { left: 110%; width: 40% }
214
+ }
215
+
216
+ html.theme-transitioning *,
217
+ html.theme-transitioning *::before,
218
+ html.theme-transitioning *::after {
219
+ transition: color 250ms ease, background-color 250ms ease, border-color 250ms ease,
220
+ box-shadow 250ms ease, fill 250ms ease, stroke 250ms ease !important;
221
+ }
222
+
223
+ @keyframes m3-ripple {
224
+ from { transform: scale(0); opacity: 0.15; }
225
+ to { transform: scale(1); opacity: 0; }
226
+ }
227
+
228
+ .m3-ripple {
229
+ position: absolute;
230
+ border-radius: 50%;
231
+ background: currentColor;
232
+ pointer-events: none;
233
+ animation: m3-ripple 450ms cubic-bezier(0.2, 0, 0.8, 1) forwards;
234
+ }
235
+
236
+ @keyframes m3-ctx-in {
237
+ from { transform: translateY(-6px) scale(0.94); }
238
+ to { transform: translateY(0) scale(1); }
239
+ }
240
+
241
+ .m3-ctx-panel {
242
+ animation: m3-ctx-in 140ms cubic-bezier(0.2, 0, 0, 1) both;
243
+ transform-origin: top left;
244
+ }
245
+
246
+ @keyframes m3-wavy-spin {
247
+ 0% { transform: rotate(0deg); }
248
+ 100% { transform: rotate(360deg); }
249
+ }
package/package.json ADDED
@@ -0,0 +1,166 @@
1
+ {
2
+ "name": "@m3ui-vue/m3ui-vue",
3
+ "version": "0.1.0",
4
+ "description": "Material 3 component library for Vue 3 + Tailwind CSS v4",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/SrWither/m3ui-vue.git"
10
+ },
11
+ "keywords": [
12
+ "vue",
13
+ "vue3",
14
+ "material-design",
15
+ "material-3",
16
+ "tailwindcss",
17
+ "components",
18
+ "ui"
19
+ ],
20
+ "sideEffects": [
21
+ "*.css"
22
+ ],
23
+ "main": "./dist/m3ui.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "import": "./dist/m3ui.js"
29
+ },
30
+ "./theme": "./src/styles/theme.css",
31
+ "./palettes": "./src/styles/palettes.css"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "src"
36
+ ],
37
+ "scripts": {
38
+ "build": "pnpm build:js && pnpm build:types && pnpm build:css",
39
+ "build:js": "vite build",
40
+ "build:types": "vue-tsc -p tsconfig.build.json",
41
+ "build:css": "cp -r src/styles dist/",
42
+ "prepublishOnly": "pnpm build"
43
+ },
44
+ "peerDependencies": {
45
+ "tailwindcss": "^4.0.0",
46
+ "vue": "^3.5.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "@tiptap/vue-3": {
50
+ "optional": true
51
+ },
52
+ "@tiptap/starter-kit": {
53
+ "optional": true
54
+ },
55
+ "@tiptap/extension-placeholder": {
56
+ "optional": true
57
+ },
58
+ "@tiptap/extension-underline": {
59
+ "optional": true
60
+ },
61
+ "@tiptap/extension-text-align": {
62
+ "optional": true
63
+ },
64
+ "@tiptap/extension-link": {
65
+ "optional": true
66
+ },
67
+ "@tiptap/extension-image": {
68
+ "optional": true
69
+ },
70
+ "@tiptap/extension-color": {
71
+ "optional": true
72
+ },
73
+ "@tiptap/extension-text-style": {
74
+ "optional": true
75
+ },
76
+ "@tiptap/extension-highlight": {
77
+ "optional": true
78
+ },
79
+ "codemirror": {
80
+ "optional": true
81
+ },
82
+ "@codemirror/view": {
83
+ "optional": true
84
+ },
85
+ "@codemirror/state": {
86
+ "optional": true
87
+ },
88
+ "@codemirror/commands": {
89
+ "optional": true
90
+ },
91
+ "@codemirror/language": {
92
+ "optional": true
93
+ },
94
+ "@codemirror/lang-javascript": {
95
+ "optional": true
96
+ },
97
+ "@codemirror/lang-json": {
98
+ "optional": true
99
+ },
100
+ "@codemirror/lang-html": {
101
+ "optional": true
102
+ },
103
+ "@codemirror/lang-css": {
104
+ "optional": true
105
+ },
106
+ "@codemirror/lang-python": {
107
+ "optional": true
108
+ },
109
+ "@codemirror/theme-one-dark": {
110
+ "optional": true
111
+ },
112
+ "@xterm/xterm": {
113
+ "optional": true
114
+ },
115
+ "@xterm/addon-fit": {
116
+ "optional": true
117
+ },
118
+ "markdown-it": {
119
+ "optional": true
120
+ },
121
+ "chart.js": {
122
+ "optional": true
123
+ },
124
+ "vue-chartjs": {
125
+ "optional": true
126
+ }
127
+ },
128
+ "devDependencies": {
129
+ "@codemirror/commands": "^6.10.3",
130
+ "@codemirror/lang-css": "^6.3.1",
131
+ "@codemirror/lang-html": "^6.4.11",
132
+ "@codemirror/lang-javascript": "^6.2.5",
133
+ "@codemirror/lang-json": "^6.0.2",
134
+ "@codemirror/lang-python": "^6.2.1",
135
+ "@codemirror/language": "^6.12.3",
136
+ "@codemirror/state": "^6.6.0",
137
+ "@codemirror/theme-one-dark": "^6.1.3",
138
+ "@codemirror/view": "^6.43.1",
139
+ "@tiptap/extension-color": "^3.26.1",
140
+ "@tiptap/extension-highlight": "^3.26.1",
141
+ "@tiptap/extension-image": "^3.26.1",
142
+ "@tiptap/extension-link": "^3.26.1",
143
+ "@tiptap/extension-placeholder": "^3.26.1",
144
+ "@tiptap/extension-text-align": "^3.26.1",
145
+ "@tiptap/extension-text-style": "^3.26.1",
146
+ "@tiptap/extension-underline": "^3.26.1",
147
+ "@tiptap/starter-kit": "^3.26.1",
148
+ "@tiptap/vue-3": "^3.26.1",
149
+ "@types/markdown-it": "^14.1.2",
150
+ "@vitejs/plugin-vue": "^6.0.7",
151
+ "@vue/tsconfig": "^0.9.1",
152
+ "@xterm/addon-fit": "^0.11.0",
153
+ "@xterm/xterm": "^6.0.0",
154
+ "chart.js": "^4.5.1",
155
+ "codemirror": "^6.0.2",
156
+ "markdown-it": "^14.2.0",
157
+ "typescript": "~6.0.3",
158
+ "vite": "^8.0.16",
159
+ "vue": "^3.5.38",
160
+ "vue-chartjs": "^5.3.3",
161
+ "vue-tsc": "^3.3.5"
162
+ },
163
+ "publishConfig": {
164
+ "access": "public"
165
+ }
166
+ }
@@ -0,0 +1,69 @@
1
+ <script setup lang="ts">
2
+ import MIcon from './MIcon.vue'
3
+
4
+ const props = withDefaults(
5
+ defineProps<{
6
+ type?: 'info' | 'success' | 'warning' | 'error'
7
+ title?: string
8
+ closeable?: boolean
9
+ }>(),
10
+ {
11
+ type: 'info',
12
+ closeable: false,
13
+ },
14
+ )
15
+
16
+ const emit = defineEmits<{ close: [] }>()
17
+
18
+ const config = {
19
+ info: {
20
+ icon: 'info',
21
+ container: 'bg-primary-container text-on-primary-container',
22
+ iconColor: 'text-primary',
23
+ },
24
+ success: {
25
+ icon: 'check_circle',
26
+ container: 'bg-success-container text-on-success-container',
27
+ iconColor: 'text-success',
28
+ },
29
+ warning: {
30
+ icon: 'warning',
31
+ container: 'bg-tertiary-container text-on-tertiary-container',
32
+ iconColor: 'text-tertiary',
33
+ },
34
+ error: {
35
+ icon: 'error',
36
+ container: 'bg-error-container text-on-error-container',
37
+ iconColor: 'text-error',
38
+ },
39
+ }
40
+ </script>
41
+
42
+ <template>
43
+ <div class="flex items-start gap-3 rounded-md p-4" :class="config[type].container">
44
+ <MIcon
45
+ :name="config[type].icon"
46
+ :size="20"
47
+ class="mt-0.5 shrink-0"
48
+ :class="config[type].iconColor"
49
+ />
50
+ <div class="min-w-0 flex-1">
51
+ <p v-if="title" class="mb-0.5 text-label-large font-medium">{{ title }}</p>
52
+ <div class="text-body-medium">
53
+ <slot />
54
+ </div>
55
+ <div v-if="$slots.actions" class="mt-3 flex flex-wrap gap-2">
56
+ <slot name="actions" />
57
+ </div>
58
+ </div>
59
+ <button
60
+ v-if="closeable"
61
+ type="button"
62
+ class="shrink-0 cursor-pointer rounded-full p-1 transition-colors hover:bg-on-surface/8"
63
+ aria-label="Cerrar"
64
+ @click="emit('close')"
65
+ >
66
+ <MIcon name="close" :size="18" />
67
+ </button>
68
+ </div>
69
+ </template>
@@ -0,0 +1,40 @@
1
+ <script setup lang="ts">
2
+ withDefaults(defineProps<{
3
+ color?: 'surface' | 'primary' | 'secondary' | 'tertiary'
4
+ elevated?: boolean
5
+ dense?: boolean
6
+ }>(), { color: 'surface' })
7
+
8
+ const colorMap: Record<string, string> = {
9
+ surface: 'bg-surface text-on-surface',
10
+ primary: 'bg-primary text-on-primary',
11
+ secondary: 'bg-secondary text-on-secondary',
12
+ tertiary: 'bg-tertiary text-on-tertiary',
13
+ }
14
+ </script>
15
+
16
+ <template>
17
+ <div
18
+ class="flex w-full items-center gap-2 px-4 transition-shadow"
19
+ :class="[
20
+ colorMap[color],
21
+ elevated ? 'shadow-elevation-2' : '',
22
+ dense ? 'h-12' : 'h-16',
23
+ ]"
24
+ >
25
+ <!-- Leading -->
26
+ <div v-if="$slots.leading" class="flex shrink-0 items-center">
27
+ <slot name="leading" />
28
+ </div>
29
+
30
+ <!-- Content -->
31
+ <div class="flex flex-1 items-center overflow-hidden">
32
+ <slot />
33
+ </div>
34
+
35
+ <!-- Trailing -->
36
+ <div v-if="$slots.trailing" class="flex shrink-0 items-center gap-1">
37
+ <slot name="trailing" />
38
+ </div>
39
+ </div>
40
+ </template>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = withDefaults(defineProps<{ name: string; size?: number }>(), { size: 40 })
5
+
6
+ const initials = computed(() => {
7
+ const parts = props.name.trim().split(/\s+/).filter(Boolean)
8
+ const first = parts[0]?.[0] ?? ''
9
+ const last = parts.length > 1 ? (parts[parts.length - 1]?.[0] ?? '') : ''
10
+ return (first + last).toUpperCase() || '?'
11
+ })
12
+ </script>
13
+
14
+ <template>
15
+ <div
16
+ class="inline-flex shrink-0 items-center justify-center rounded-full bg-primary-container font-medium text-on-primary-container"
17
+ :style="{ width: `${size}px`, height: `${size}px`, fontSize: `${Math.round(size * 0.4)}px` }"
18
+ >
19
+ {{ initials }}
20
+ </div>
21
+ </template>
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = withDefaults(
5
+ defineProps<{
6
+ count?: number
7
+ dot?: boolean
8
+ color?: 'primary' | 'error' | 'secondary' | 'tertiary'
9
+ max?: number
10
+ }>(),
11
+ {
12
+ color: 'error',
13
+ max: 99,
14
+ },
15
+ )
16
+
17
+ const show = computed(() => props.dot || (props.count !== undefined && props.count > 0))
18
+
19
+ const label = computed(() => {
20
+ if (props.dot || props.count === undefined) return ''
21
+ return props.count > props.max ? `${props.max}+` : String(props.count)
22
+ })
23
+
24
+ const colorMap: Record<string, string> = {
25
+ primary: 'bg-primary text-on-primary',
26
+ error: 'bg-error text-on-error',
27
+ secondary: 'bg-secondary text-on-secondary',
28
+ tertiary: 'bg-tertiary text-on-tertiary',
29
+ }
30
+ </script>
31
+
32
+ <template>
33
+ <span class="relative inline-flex">
34
+ <slot />
35
+ <span
36
+ v-if="show"
37
+ class="absolute -right-1 -top-1 flex items-center justify-center rounded-full font-medium leading-none"
38
+ :class="[
39
+ colorMap[color],
40
+ !label || dot ? 'h-2.5 w-2.5' : label.length > 2 ? 'h-5 min-w-[1.25rem] px-1 text-[10px]' : 'h-5 w-5 text-[10px]',
41
+ ]"
42
+ >
43
+ <span v-if="!dot">{{ label }}</span>
44
+ </span>
45
+ </span>
46
+ </template>
@@ -0,0 +1,113 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from 'vue'
3
+ import MIcon from './MIcon.vue'
4
+
5
+ withDefaults(defineProps<{
6
+ modelValue: boolean
7
+ title?: string
8
+ fullHeight?: boolean
9
+ }>(), { fullHeight: false })
10
+
11
+ const emit = defineEmits<{ 'update:modelValue': [boolean] }>()
12
+ const close = () => emit('update:modelValue', false)
13
+
14
+ // Drag-to-dismiss state
15
+ const dragY = ref(0)
16
+ const dragging = ref(false)
17
+ let startY = 0
18
+
19
+ function onHandlePointerDown(e: PointerEvent) {
20
+ dragging.value = true
21
+ startY = e.clientY
22
+ dragY.value = 0
23
+ ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
24
+ }
25
+ function onHandlePointerMove(e: PointerEvent) {
26
+ if (!dragging.value) return
27
+ dragY.value = Math.max(0, e.clientY - startY)
28
+ }
29
+ function onHandlePointerUp() {
30
+ if (dragY.value > 100) close()
31
+ dragging.value = false
32
+ dragY.value = 0
33
+ }
34
+
35
+ const sheetStyle = computed(() => ({
36
+ transform: `translateY(${dragY.value}px)`,
37
+ transition: dragging.value ? 'none' : undefined,
38
+ }))
39
+ </script>
40
+
41
+ <template>
42
+ <Teleport to="body">
43
+ <Transition name="bs" :duration="{ enter: 320, leave: 280 }">
44
+ <div v-if="modelValue" class="fixed inset-0 z-[200] flex flex-col justify-end">
45
+ <!-- Scrim -->
46
+ <div class="bs-scrim absolute inset-0 bg-black/40" @click="close" />
47
+
48
+ <!-- Panel -->
49
+ <div
50
+ class="bs-panel relative flex w-full flex-col rounded-t-[28px] bg-surface-container-low shadow-elevation-3"
51
+ :class="fullHeight ? 'max-h-[92vh]' : 'max-h-[60vh]'"
52
+ :style="sheetStyle"
53
+ >
54
+ <!-- Drag handle -->
55
+ <div
56
+ class="flex h-9 shrink-0 cursor-grab touch-none select-none items-center justify-center active:cursor-grabbing"
57
+ @pointerdown="onHandlePointerDown"
58
+ @pointermove="onHandlePointerMove"
59
+ @pointerup="onHandlePointerUp"
60
+ >
61
+ <div class="h-1 w-8 rounded-full bg-on-surface-variant/40" />
62
+ </div>
63
+
64
+ <!-- Header -->
65
+ <div v-if="title" class="flex shrink-0 items-center justify-between px-6 pb-4">
66
+ <h2 class="text-title-large text-on-surface">{{ title }}</h2>
67
+ <button
68
+ type="button"
69
+ class="flex h-9 w-9 cursor-pointer items-center justify-center rounded-full text-on-surface-variant transition-colors hover:bg-on-surface/8"
70
+ @click="close"
71
+ >
72
+ <MIcon name="close" :size="20" />
73
+ </button>
74
+ </div>
75
+
76
+ <!-- Content -->
77
+ <div class="flex-1 overflow-y-auto px-6 pb-6">
78
+ <slot />
79
+ </div>
80
+
81
+ <!-- Actions -->
82
+ <div v-if="$slots.actions" class="shrink-0 border-t border-outline-variant px-6 py-4">
83
+ <slot name="actions" />
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </Transition>
88
+ </Teleport>
89
+ </template>
90
+
91
+ <style scoped>
92
+ .bs-scrim {
93
+ transition: opacity 300ms ease;
94
+ }
95
+ .bs-enter-from .bs-scrim,
96
+ .bs-leave-to .bs-scrim {
97
+ opacity: 0;
98
+ }
99
+
100
+ .bs-panel {
101
+ transition:
102
+ transform 320ms cubic-bezier(0.2, 0, 0, 1),
103
+ opacity 240ms ease;
104
+ }
105
+ .bs-enter-from .bs-panel {
106
+ transform: translateY(40%);
107
+ opacity: 0;
108
+ }
109
+ .bs-leave-to .bs-panel {
110
+ transform: translateY(100%) !important;
111
+ opacity: 0;
112
+ }
113
+ </style>