@mednet/ui 0.0.0-stage → 1.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 (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -2
  3. package/THIRD_PARTY_NOTICES.md +27 -0
  4. package/dist/brand/logo/logo-horizontal.d.ts +6 -0
  5. package/dist/brand/logo/logo-horizontal.js +7 -0
  6. package/dist/brand/logo/logo-mark.d.ts +6 -0
  7. package/dist/brand/logo/logo-mark.js +7 -0
  8. package/dist/brand/logo/logo-vertical.d.ts +6 -0
  9. package/dist/brand/logo/logo-vertical.js +7 -0
  10. package/dist/brand/logo.d.ts +18 -0
  11. package/dist/brand/logo.js +12 -0
  12. package/dist/brand/site-footer.d.ts +24 -0
  13. package/dist/brand/site-footer.js +15 -0
  14. package/dist/brand/site-header.d.ts +11 -0
  15. package/dist/brand/site-header.js +7 -0
  16. package/dist/components/accordion.d.ts +6 -0
  17. package/dist/components/accordion.js +17 -0
  18. package/dist/components/alert-dialog.d.ts +18 -0
  19. package/dist/components/alert-dialog.js +42 -0
  20. package/dist/components/alert.d.ts +10 -0
  21. package/dist/components/alert.js +27 -0
  22. package/dist/components/aspect-ratio.d.ts +4 -0
  23. package/dist/components/aspect-ratio.js +8 -0
  24. package/dist/components/attachment.d.ts +23 -0
  25. package/dist/components/attachment.js +68 -0
  26. package/dist/components/avatar.d.ts +11 -0
  27. package/dist/components/avatar.js +23 -0
  28. package/dist/components/badge.d.ts +7 -0
  29. package/dist/components/badge.js +33 -0
  30. package/dist/components/breadcrumb.d.ts +10 -0
  31. package/dist/components/breadcrumb.js +36 -0
  32. package/dist/components/bubble.d.ts +16 -0
  33. package/dist/components/bubble.js +59 -0
  34. package/dist/components/button-group.d.ts +10 -0
  35. package/dist/components/button-group.js +36 -0
  36. package/dist/components/button.d.ts +8 -0
  37. package/dist/components/button.js +34 -0
  38. package/dist/components/calendar.d.ts +10 -0
  39. package/dist/components/calendar.js +76 -0
  40. package/dist/components/card.d.ts +11 -0
  41. package/dist/components/card.js +24 -0
  42. package/dist/components/carousel.d.ts +28 -0
  43. package/dist/components/carousel.js +91 -0
  44. package/dist/components/chart.d.ts +44 -0
  45. package/dist/components/chart.js +132 -0
  46. package/dist/components/checkbox.d.ts +3 -0
  47. package/dist/components/checkbox.js +9 -0
  48. package/dist/components/collapsible.d.ts +5 -0
  49. package/dist/components/collapsible.js +13 -0
  50. package/dist/components/combobox.d.ts +24 -0
  51. package/dist/components/combobox.js +58 -0
  52. package/dist/components/command.d.ts +19 -0
  53. package/dist/components/command.js +35 -0
  54. package/dist/components/context-menu.d.ts +29 -0
  55. package/dist/components/context-menu.js +51 -0
  56. package/dist/components/dialog.d.ts +17 -0
  57. package/dist/components/dialog.js +37 -0
  58. package/dist/components/direction.d.ts +1 -0
  59. package/dist/components/direction.js +2 -0
  60. package/dist/components/drawer.d.ts +16 -0
  61. package/dist/components/drawer.js +75 -0
  62. package/dist/components/dropdown-menu.d.ts +29 -0
  63. package/dist/components/dropdown-menu.js +51 -0
  64. package/dist/components/empty.d.ts +11 -0
  65. package/dist/components/empty.js +33 -0
  66. package/dist/components/field.d.ts +24 -0
  67. package/dist/components/field.js +68 -0
  68. package/dist/components/hover-card.d.ts +5 -0
  69. package/dist/components/hover-card.js +14 -0
  70. package/dist/components/input-group.d.ts +18 -0
  71. package/dist/components/input-group.js +57 -0
  72. package/dist/components/input-otp.d.ts +11 -0
  73. package/dist/components/input-otp.js +21 -0
  74. package/dist/components/input.d.ts +3 -0
  75. package/dist/components/input.js +7 -0
  76. package/dist/components/item.d.ts +22 -0
  77. package/dist/components/item.js +78 -0
  78. package/dist/components/kbd.d.ts +3 -0
  79. package/dist/components/kbd.js +9 -0
  80. package/dist/components/label.d.ts +3 -0
  81. package/dist/components/label.js +7 -0
  82. package/dist/components/marker.d.ts +10 -0
  83. package/dist/components/marker.js +34 -0
  84. package/dist/components/menubar.d.ts +29 -0
  85. package/dist/components/menubar.js +56 -0
  86. package/dist/components/message-scroller.d.ts +10 -0
  87. package/dist/components/message-scroller.js +25 -0
  88. package/dist/components/message.d.ts +10 -0
  89. package/dist/components/message.js +21 -0
  90. package/dist/components/native-select.d.ts +8 -0
  91. package/dist/components/native-select.js +13 -0
  92. package/dist/components/navigation-menu.d.ts +11 -0
  93. package/dist/components/navigation-menu.js +31 -0
  94. package/dist/components/pagination.d.ts +17 -0
  95. package/dist/components/pagination.js +26 -0
  96. package/dist/components/popover.d.ts +9 -0
  97. package/dist/components/popover.js +23 -0
  98. package/dist/components/progress.d.ts +7 -0
  99. package/dist/components/progress.js +20 -0
  100. package/dist/components/questionnaire.d.ts +19 -0
  101. package/dist/components/questionnaire.js +52 -0
  102. package/dist/components/radio-group.d.ts +5 -0
  103. package/dist/components/radio-group.js +12 -0
  104. package/dist/components/resizable.d.ts +7 -0
  105. package/dist/components/resizable.js +14 -0
  106. package/dist/components/scroll-area.d.ts +5 -0
  107. package/dist/components/scroll-area.js +11 -0
  108. package/dist/components/select.d.ts +15 -0
  109. package/dist/components/select.js +34 -0
  110. package/dist/components/separator.d.ts +3 -0
  111. package/dist/components/separator.js +8 -0
  112. package/dist/components/sheet.d.ts +14 -0
  113. package/dist/components/sheet.js +37 -0
  114. package/dist/components/sidebar.d.ts +63 -0
  115. package/dist/components/sidebar.js +256 -0
  116. package/dist/components/skeleton.d.ts +2 -0
  117. package/dist/components/skeleton.js +6 -0
  118. package/dist/components/slider.d.ts +3 -0
  119. package/dist/components/slider.js +12 -0
  120. package/dist/components/spinner.d.ts +2 -0
  121. package/dist/components/spinner.js +7 -0
  122. package/dist/components/switch.d.ts +5 -0
  123. package/dist/components/switch.js +8 -0
  124. package/dist/components/table.d.ts +10 -0
  125. package/dist/components/table.js +28 -0
  126. package/dist/components/tabs.d.ts +10 -0
  127. package/dist/components/tabs.js +29 -0
  128. package/dist/components/textarea.d.ts +3 -0
  129. package/dist/components/textarea.js +6 -0
  130. package/dist/components/toast.d.ts +16 -0
  131. package/dist/components/toast.js +66 -0
  132. package/dist/components/toggle-group.d.ts +11 -0
  133. package/dist/components/toggle-group.js +24 -0
  134. package/dist/components/toggle.d.ts +8 -0
  135. package/dist/components/toggle.js +26 -0
  136. package/dist/components/tooltip.d.ts +6 -0
  137. package/dist/components/tooltip.js +17 -0
  138. package/dist/hooks/use-mobile.d.ts +1 -0
  139. package/dist/hooks/use-mobile.js +15 -0
  140. package/dist/index.d.ts +67 -0
  141. package/dist/index.js +69 -0
  142. package/dist/layouts/app-shell.d.ts +19 -0
  143. package/dist/layouts/app-shell.js +9 -0
  144. package/dist/layouts/public-layout.d.ts +14 -0
  145. package/dist/layouts/public-layout.js +8 -0
  146. package/dist/layouts/skip-link.d.ts +2 -0
  147. package/dist/layouts/skip-link.js +5 -0
  148. package/dist/lib/utils.d.ts +2 -0
  149. package/dist/lib/utils.js +7 -0
  150. package/llms.md +522 -0
  151. package/package.json +130 -3
  152. package/postcss.cjs +163 -0
  153. package/src/brand.css +69 -0
  154. package/src/shadcn-tailwind.css +638 -0
  155. package/src/styles.css +48 -0
package/postcss.cjs ADDED
@@ -0,0 +1,163 @@
1
+ // PostCSS-плагин для Chrome/Edge 109 — последних в Windows 7/8.1 (спека D18). Ставится ПОСЛЕ
2
+ // @tailwindcss/postcss: plugins: { '@tailwindcss/postcss': {}, '@mednet/ui/postcss': {} }.
3
+ // Им же собирается @mednet/css. Современные браузеры рендерят результат так же, как без плагина.
4
+ // CommonJS намеренно: next build --webpack не загружает ESM-плагины PostCSS.
5
+ //
6
+ // Что чинит (Tailwind v4, Next и Base UI рассчитаны на Chrome 111+):
7
+ // 1. Цвета с прозрачностью (bg-destructive/10, bg-input/30, bg-black/80). Tailwind пишет запасное
8
+ // значение без прозрачности, а настоящее — в @supports (color: color-mix(in lab, red, red)).
9
+ // Перед этим блоком вставляем копию со статическими цветами: переменные темы — из :root
10
+ // (для селекторов с .dark — из .dark), color-mix и oklch Lightning CSS переводит в hex.
11
+ // Chrome 109 берёт копию, современные браузеры — блок @supports, который идёт позже.
12
+ // 2. var(--x,) без пробела: если --x объявлено через @property без initial-value (--tw-ring-inset),
13
+ // Chrome 109 отбрасывает всё значение — пропадают все кольца, включая фокус. Пишем var(--x, ).
14
+ // 3. oklch() внутри SVG data-URI (шеврон select, галочка checkbox в Basecoat) — до Chrome 111
15
+ // иконка не рисуется. Переводим в hex (# в data-URI — %23).
16
+ // 4. var() в ::backdrop — до Chrome 122 ::backdrop не видит переменных :root, фон под <dialog>
17
+ // не затемняется. Подставляем значения. Этот шаг действует во ВСЕХ браузерах и «замораживает»
18
+ // значения темы в ::backdrop (пока в v1 нет переключения тем — спека D15 — это допустимо).
19
+ // Не чинит: относительные цвета (oklch(from …), Chrome 119+: bubble, shimmer), анимации на
20
+ // @starting-style, авторазмер textarea (field-sizing).
21
+ 'use strict';
22
+
23
+ const { transform } = require('lightningcss');
24
+
25
+ const CHROME_109 = { chrome: 109 << 16 };
26
+ const CHROME_60 = { chrome: 60 << 16 }; // без 8-значного hex: безопасно внутри атрибутов SVG
27
+ const EMPTY_FALLBACK = /var\((--[\w-]+),\)/g;
28
+
29
+ /** Цвет → самая совместимая запись для targets (Lightning может дать «запасное; современное»). */
30
+ function lower(value, targets) {
31
+ const { code } = transform({
32
+ filename: 'value.css',
33
+ code: Buffer.from(`a{color:${value}}`),
34
+ targets,
35
+ minify: true,
36
+ });
37
+ return code.toString().match(/^a\{color:([^;}]+)/)[1];
38
+ }
39
+
40
+ const isGuard = (atRule) =>
41
+ atRule.params.replace(/\s/g, '').includes('(color:color-mix(inlab,red,red))');
42
+ const isDark = (rule) => /\.dark(?![\w-])/.test((rule && rule.selector) || '');
43
+
44
+ /** Переменные темы: светлая — :root/:host/html, тёмная — светлая + .dark. */
45
+ function themes(root) {
46
+ const light = new Map();
47
+ const darkOnly = new Map();
48
+ root.walkRules((rule) => {
49
+ const selector = rule.selector.replace(/\s+/g, ' ').trim();
50
+ const target = /^(:root|:root, ?:host|:host|html)$/.test(selector)
51
+ ? light
52
+ : selector === '.dark'
53
+ ? darkOnly
54
+ : null;
55
+ if (!target) return;
56
+ rule.each((node) => {
57
+ if (node.type === 'decl' && node.prop.startsWith('--')) target.set(node.prop, node.value);
58
+ });
59
+ });
60
+ return { light, dark: new Map([...light, ...darkOnly]) };
61
+ }
62
+
63
+ /** Подставляет var() из темы; null, если хоть одну переменную не найти. */
64
+ function resolver(vars) {
65
+ const resolve = (value, depth = 0) => {
66
+ if (depth > 20) return null;
67
+ let failed = false;
68
+ const out = value.replace(/var\((--[\w-]+)\s*(?:,\s*([^()]*))?\)/g, (match, name, fallback) => {
69
+ const next = vars.has(name)
70
+ ? vars.get(name)
71
+ : fallback && fallback.trim()
72
+ ? fallback.trim()
73
+ : null;
74
+ const resolved = next == null ? null : resolve(next, depth + 1);
75
+ if (resolved == null) {
76
+ failed = true;
77
+ return match;
78
+ }
79
+ return resolved;
80
+ });
81
+ return failed ? null : out;
82
+ };
83
+ return resolve;
84
+ }
85
+
86
+ function legacyFallbacks() {
87
+ return {
88
+ postcssPlugin: 'mednet-legacy-fallbacks',
89
+ OnceExit(root, { result }) {
90
+ const { light, dark } = themes(root);
91
+ const resolveLight = resolver(light);
92
+ const resolveDark = resolver(dark);
93
+ const resolveFor = (rule) => (isDark(rule) ? resolveDark : resolveLight);
94
+
95
+ // 3. oklch() в SVG data-URI
96
+ root.walkDecls((decl) => {
97
+ if (!decl.value.includes('data:image/svg+xml') || !decl.value.includes('oklch(')) return;
98
+ decl.value = decl.value.replace(/oklch\([^)]*\)/g, (color) => {
99
+ try {
100
+ const hex = lower(color, CHROME_60);
101
+ // Lightning CSS не падает на нечитаемом цвете, а возвращает его как есть
102
+ if (hex.includes('oklch(')) throw new Error('цвет не переведён');
103
+ return hex.replace(/^#/, '%23');
104
+ } catch {
105
+ result.warn(
106
+ `mednet-legacy-fallbacks: не удалось перевести ${color} в hex внутри SVG data-URI, значение оставлено как есть`,
107
+ { node: decl },
108
+ );
109
+ return color;
110
+ }
111
+ });
112
+ });
113
+
114
+ // 4. var() в ::backdrop
115
+ root.walkRules((rule) => {
116
+ if (!rule.selector.includes('::backdrop')) return;
117
+ rule.walkDecls((decl) => {
118
+ if (!decl.value.includes('var(--')) return;
119
+ const value = resolveFor(rule)(decl.value);
120
+ if (value != null) decl.value = value;
121
+ });
122
+ });
123
+
124
+ // 1. Статические копии перед @supports (color: color-mix(…))
125
+ const guards = [];
126
+ root.walkAtRules('supports', (atRule) => {
127
+ if (isGuard(atRule)) guards.push(atRule);
128
+ });
129
+ for (const atRule of guards) {
130
+ const copy = atRule.clone();
131
+ copy.walkDecls((decl) => {
132
+ if (!decl.value.includes('color-mix(')) return;
133
+ const value = resolveFor(decl.parent)(decl.value);
134
+ if (value == null || /currentcolor/i.test(value)) {
135
+ decl.remove();
136
+ return;
137
+ }
138
+ try {
139
+ decl.value = lower(value, CHROME_109);
140
+ } catch {
141
+ result.warn(
142
+ `mednet-legacy-fallbacks: не удалось перевести «${value}» в статический цвет, объявление ${decl.prop} в копии для Chrome 109 удалено`,
143
+ { node: decl },
144
+ );
145
+ decl.remove();
146
+ }
147
+ });
148
+ copy.walkRules((rule) => {
149
+ if (rule.nodes.length === 0) rule.remove();
150
+ });
151
+ if (copy.nodes.length > 0) atRule.before(copy.nodes);
152
+ }
153
+
154
+ // 2. var(--x,) → var(--x, )
155
+ root.walkDecls((decl) => {
156
+ if (decl.value.includes(',)')) decl.value = decl.value.replace(EMPTY_FALLBACK, 'var($1, )');
157
+ });
158
+ },
159
+ };
160
+ }
161
+
162
+ legacyFallbacks.postcss = true;
163
+ module.exports = legacyFallbacks;
package/src/brand.css ADDED
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Бренд-правки shadcn Maia для React (зеркало packages/css/src/overrides.css).
3
+ * Подключается в styles.css как `@import './brand.css' layer(utilities)` ДО утилит Tailwind.
4
+ * Сгенерированные файлы shadcn не трогаем — `shadcn add <x> --diff` показывает только апстрим.
5
+ *
6
+ * Ключ — сгенерированные классы ([class~='…'] = целое слово, «/» не экранируется), НЕ data-slot:
7
+ * в Base UI при render={<Button />} у DialogTrigger/DialogClose/… побеждает data-slot внешней
8
+ * части ('dialog-trigger'), а классы кнопки сохраняются. Маркеры: поля — border-input,
9
+ * кнопка — group/button, бейдж — group/badge.
10
+ *
11
+ * Не трогаем (как статика): дорожку Switch и разделитель ButtonGroup (bg-input), поиск
12
+ * в Command и в списке Combobox (белое на белом исчезнет), dark:* (тёмной темы в v1 нет, D15).
13
+ */
14
+
15
+ /*
16
+ * Заливка полей, контурных кнопки и бейджа: --input (графитовая граница 3:1, 30 %) → --field (белый).
17
+ * Специфичность (0,2,0): бьёт утилиту bg-input/30 (0,1,0), уступает вариантам hover:, aria-expanded:
18
+ * и классам проекта (они позже в том же слое). Свой bg-… проекта cn() не пропустит вместе с bg-input/30.
19
+ */
20
+ :is(
21
+ [class~='border-input'],
22
+ [class~='group/button'],
23
+ [class~='group/badge']
24
+ )[class~='bg-input/30']:where(
25
+ :not([data-slot='command-input-wrapper'] *, [data-slot='combobox-content'] *)
26
+ ) {
27
+ background-color: var(--field);
28
+ }
29
+
30
+ @media (hover: hover) {
31
+ /* Контурная кнопка при наведении: --input 50 % → --muted; (0,3,0) бьёт hover:bg-input/50. */
32
+ [class~='group/button'][class~='hover:bg-input/50']:hover {
33
+ background-color: var(--muted);
34
+ }
35
+
36
+ /*
37
+ * Основная кнопка и бейдж-ссылка при наведении: Maia даёт primary/80 — белый текст 3.20:1, меньше AA.
38
+ * Токен --primary-hover (#a55551) — 5.23:1.
39
+ */
40
+ [class~='group/button'][class~='hover:bg-primary/80']:hover,
41
+ [class~='group/badge'][class~='[a]:hover:bg-primary/80']:is(a):hover {
42
+ background-color: var(--primary-hover);
43
+ }
44
+ }
45
+
46
+ /*
47
+ * Неактивная вкладка: Maia даёт text-foreground/60 — #817f7d на --muted (#f7f2ed) это 3.58:1, меньше AA (4.5:1).
48
+ * --muted-foreground (#666666) — 5.16:1. Ключ — классы триггера (text-foreground/60 в tabs.tsx только у него).
49
+ * Специфичность (0,2,0): бьёт утилиту text-foreground/60 (0,1,0) и уступает hover:text-foreground (0,2,0, позже
50
+ * в слое). Вариант data-active:text-foreground Tailwind собирает через :where(...) — это (0,1,0), правило его
51
+ * перебило бы, поэтому активную вкладку исключаем сами, тоже через :where (специфичность не растёт):
52
+ * у неё остаётся --foreground.
53
+ */
54
+ [class~='text-foreground/60'][class~='hover:text-foreground']:where(
55
+ :not([data-state='active'], [data-active]:not([data-active='false']))
56
+ ) {
57
+ color: var(--muted-foreground);
58
+ }
59
+
60
+ /*
61
+ * Граница контурной кнопки и бейджа: buttonVariants({ variant: 'outline' }) / badgeVariants без cn() отдаёт
62
+ * и border-transparent (база), и border-border (вариант); прозрачная побеждает, и рамки нет. cn() убирает
63
+ * лишнее, а ссылка <a className={buttonVariants(...)}> — нет. Специфичность (0,2,0): бьёт border-transparent
64
+ * (0,1,0); варианты focus-visible:border-ring, aria-invalid:border-destructive — тоже (0,2,0), но позже в слое,
65
+ * поэтому в фокусе и с ошибкой граница прежняя.
66
+ */
67
+ :is([class~='group/button'], [class~='group/badge'])[class~='border-border'] {
68
+ border-color: var(--border);
69
+ }