@zyncat/ui 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/alert.css +132 -0
- package/dist/alert.d.ts +46 -0
- package/dist/alert.js +80 -0
- package/dist/alert.js.map +1 -0
- package/dist/avatar-group.d.ts +24 -0
- package/dist/avatar-group.js +23 -0
- package/dist/avatar-group.js.map +1 -0
- package/dist/avatar.css +200 -0
- package/dist/avatar.d.ts +35 -0
- package/dist/avatar.js +67 -0
- package/dist/avatar.js.map +1 -0
- package/dist/badge.css +182 -0
- package/dist/badge.d.ts +34 -0
- package/dist/badge.js +4 -0
- package/dist/badge.js.map +1 -0
- package/dist/button.css +269 -0
- package/dist/button.d.ts +44 -0
- package/dist/button.js +4 -0
- package/dist/button.js.map +1 -0
- package/dist/checkbox.css +177 -0
- package/dist/checkbox.d.ts +35 -0
- package/dist/checkbox.js +5 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-2ERBBFZS.js +12 -0
- package/dist/chunk-2ERBBFZS.js.map +1 -0
- package/dist/chunk-2HORSLXJ.js +191 -0
- package/dist/chunk-2HORSLXJ.js.map +1 -0
- package/dist/chunk-36WVAQKL.js +40 -0
- package/dist/chunk-36WVAQKL.js.map +1 -0
- package/dist/chunk-3SBCBYB7.js +575 -0
- package/dist/chunk-3SBCBYB7.js.map +1 -0
- package/dist/chunk-4R2GQO43.js +125 -0
- package/dist/chunk-4R2GQO43.js.map +1 -0
- package/dist/chunk-64UU4LGU.js +258 -0
- package/dist/chunk-64UU4LGU.js.map +1 -0
- package/dist/chunk-7SZCJ7WI.js +35 -0
- package/dist/chunk-7SZCJ7WI.js.map +1 -0
- package/dist/chunk-BIDVNLJO.js +38 -0
- package/dist/chunk-BIDVNLJO.js.map +1 -0
- package/dist/chunk-CONSWNIV.js +17 -0
- package/dist/chunk-CONSWNIV.js.map +1 -0
- package/dist/chunk-EQ32F2QJ.js +75 -0
- package/dist/chunk-EQ32F2QJ.js.map +1 -0
- package/dist/chunk-GY7JOPUQ.js +111 -0
- package/dist/chunk-GY7JOPUQ.js.map +1 -0
- package/dist/chunk-I4XQ4PV2.js +30 -0
- package/dist/chunk-I4XQ4PV2.js.map +1 -0
- package/dist/chunk-JSKXZMLH.js +67 -0
- package/dist/chunk-JSKXZMLH.js.map +1 -0
- package/dist/chunk-L3Q3VDIW.js +295 -0
- package/dist/chunk-L3Q3VDIW.js.map +1 -0
- package/dist/chunk-LDC3RIYA.js +62 -0
- package/dist/chunk-LDC3RIYA.js.map +1 -0
- package/dist/chunk-MKIQFK7S.js +43 -0
- package/dist/chunk-MKIQFK7S.js.map +1 -0
- package/dist/chunk-MMRIQNEN.js +20 -0
- package/dist/chunk-MMRIQNEN.js.map +1 -0
- package/dist/chunk-MXOPCFWR.js +59 -0
- package/dist/chunk-MXOPCFWR.js.map +1 -0
- package/dist/chunk-NEF5XAHG.js +17 -0
- package/dist/chunk-NEF5XAHG.js.map +1 -0
- package/dist/chunk-NNXJCLTV.js +22 -0
- package/dist/chunk-NNXJCLTV.js.map +1 -0
- package/dist/chunk-O4N2OBTR.js +94 -0
- package/dist/chunk-O4N2OBTR.js.map +1 -0
- package/dist/chunk-PMECHR3A.js +38 -0
- package/dist/chunk-PMECHR3A.js.map +1 -0
- package/dist/chunk-QDK66S4G.js +44 -0
- package/dist/chunk-QDK66S4G.js.map +1 -0
- package/dist/chunk-QGNC7LH5.js +8 -0
- package/dist/chunk-QGNC7LH5.js.map +1 -0
- package/dist/chunk-QMSJZCK3.js +398 -0
- package/dist/chunk-QMSJZCK3.js.map +1 -0
- package/dist/chunk-S5ZTZANS.js +57 -0
- package/dist/chunk-S5ZTZANS.js.map +1 -0
- package/dist/chunk-S7B34VGN.js +14 -0
- package/dist/chunk-S7B34VGN.js.map +1 -0
- package/dist/chunk-TCUCYFT7.js +25 -0
- package/dist/chunk-TCUCYFT7.js.map +1 -0
- package/dist/chunk-TYHR4VNM.js +193 -0
- package/dist/chunk-TYHR4VNM.js.map +1 -0
- package/dist/chunk-U5QQZC3U.js +56 -0
- package/dist/chunk-U5QQZC3U.js.map +1 -0
- package/dist/chunk-UE63OOVG.js +13 -0
- package/dist/chunk-UE63OOVG.js.map +1 -0
- package/dist/chunk-VTJTGVZZ.js +22 -0
- package/dist/chunk-VTJTGVZZ.js.map +1 -0
- package/dist/chunk-W3SHPKSB.js +49 -0
- package/dist/chunk-W3SHPKSB.js.map +1 -0
- package/dist/chunk-XZAEIQDR.js +188 -0
- package/dist/chunk-XZAEIQDR.js.map +1 -0
- package/dist/chunk-YGGCQNNU.js +92 -0
- package/dist/chunk-YGGCQNNU.js.map +1 -0
- package/dist/collapse.css +88 -0
- package/dist/collapse.d.ts +46 -0
- package/dist/collapse.js +5 -0
- package/dist/collapse.js.map +1 -0
- package/dist/count-badge.d.ts +13 -0
- package/dist/count-badge.js +13 -0
- package/dist/count-badge.js.map +1 -0
- package/dist/date-field.d.ts +25 -0
- package/dist/date-field.js +87 -0
- package/dist/date-field.js.map +1 -0
- package/dist/date-picker.css +595 -0
- package/dist/date-range-field.d.ts +33 -0
- package/dist/date-range-field.js +404 -0
- package/dist/date-range-field.js.map +1 -0
- package/dist/datetime-field.d.ts +29 -0
- package/dist/datetime-field.js +155 -0
- package/dist/datetime-field.js.map +1 -0
- package/dist/dialog.css +180 -0
- package/dist/dialog.d.ts +42 -0
- package/dist/dialog.js +128 -0
- package/dist/dialog.js.map +1 -0
- package/dist/dom-props-C0jrllBw.d.ts +5 -0
- package/dist/field-chrome-CMPOQSLs.d.ts +28 -0
- package/dist/field-shell-Cuda-feL.d.ts +24 -0
- package/dist/glide.d.ts +15 -0
- package/dist/glide.js +5 -0
- package/dist/glide.js.map +1 -0
- package/dist/icon.css +33 -0
- package/dist/input.css +333 -0
- package/dist/mcp.js +359 -0
- package/dist/motion-devtools.css +265 -0
- package/dist/motion-devtools.d.ts +51 -0
- package/dist/motion-devtools.js +354 -0
- package/dist/motion-devtools.js.map +1 -0
- package/dist/motion-scale-Canq4stZ.d.ts +18 -0
- package/dist/motion-tokens.d.ts +28 -0
- package/dist/motion-tokens.js +3 -0
- package/dist/motion-tokens.js.map +1 -0
- package/dist/multi-select.d.ts +44 -0
- package/dist/multi-select.js +109 -0
- package/dist/multi-select.js.map +1 -0
- package/dist/number-field.d.ts +36 -0
- package/dist/number-field.js +112 -0
- package/dist/number-field.js.map +1 -0
- package/dist/odometer.css +62 -0
- package/dist/otp-field.d.ts +31 -0
- package/dist/otp-field.js +98 -0
- package/dist/otp-field.js.map +1 -0
- package/dist/overlay.css +23 -0
- package/dist/pagination.css +43 -0
- package/dist/pagination.d.ts +29 -0
- package/dist/pagination.js +107 -0
- package/dist/pagination.js.map +1 -0
- package/dist/popover.css +69 -0
- package/dist/popover.d.ts +35 -0
- package/dist/popover.js +15 -0
- package/dist/popover.js.map +1 -0
- package/dist/radio-group.css +300 -0
- package/dist/radio-group.d.ts +52 -0
- package/dist/radio-group.js +115 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/select.css +416 -0
- package/dist/select.d.ts +49 -0
- package/dist/select.js +99 -0
- package/dist/select.js.map +1 -0
- package/dist/sheet.css +26 -0
- package/dist/sheet.d.ts +31 -0
- package/dist/sheet.js +14 -0
- package/dist/sheet.js.map +1 -0
- package/dist/status-badge.d.ts +19 -0
- package/dist/status-badge.js +72 -0
- package/dist/status-badge.js.map +1 -0
- package/dist/table.css +348 -0
- package/dist/table.d.ts +75 -0
- package/dist/table.js +262 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.css +208 -0
- package/dist/tabs.d.ts +71 -0
- package/dist/tabs.js +181 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tag.css +248 -0
- package/dist/tag.d.ts +52 -0
- package/dist/tag.js +72 -0
- package/dist/tag.js.map +1 -0
- package/dist/text-field.d.ts +28 -0
- package/dist/text-field.js +69 -0
- package/dist/text-field.js.map +1 -0
- package/dist/textarea.css +219 -0
- package/dist/textarea.d.ts +38 -0
- package/dist/textarea.js +144 -0
- package/dist/textarea.js.map +1 -0
- package/dist/time-field.d.ts +28 -0
- package/dist/time-field.js +66 -0
- package/dist/time-field.js.map +1 -0
- package/dist/timing-7JA_zQHP.d.ts +27 -0
- package/dist/toast-store.d.ts +86 -0
- package/dist/toast-store.js +3 -0
- package/dist/toast-store.js.map +1 -0
- package/dist/toast.css +257 -0
- package/dist/toast.d.ts +12 -0
- package/dist/toast.js +310 -0
- package/dist/toast.js.map +1 -0
- package/dist/toggle-tag.d.ts +34 -0
- package/dist/toggle-tag.js +57 -0
- package/dist/toggle-tag.js.map +1 -0
- package/dist/toggle.css +152 -0
- package/dist/toggle.d.ts +31 -0
- package/dist/toggle.js +75 -0
- package/dist/toggle.js.map +1 -0
- package/dist/tooltip.css +86 -0
- package/dist/tooltip.d.ts +30 -0
- package/dist/tooltip.js +268 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/types-SGMShK7R.d.ts +22 -0
- package/llms.txt +196 -0
- package/next.d.mts +7 -0
- package/next.mjs +59 -0
- package/package.json +257 -0
- package/src/components/composites/alert/Alert.tsx +141 -0
- package/src/components/composites/alert/alert.css +132 -0
- package/src/components/composites/date-picker/DateField.tsx +80 -0
- package/src/components/composites/date-picker/DateRangeField.tsx +110 -0
- package/src/components/composites/date-picker/DateTimeField.tsx +162 -0
- package/src/components/composites/date-picker/TimeField.tsx +78 -0
- package/src/components/composites/date-picker/calendar-panel.tsx +216 -0
- package/src/components/composites/date-picker/date-picker.css +595 -0
- package/src/components/composites/date-picker/date-utils.ts +56 -0
- package/src/components/composites/date-picker/field-shell.tsx +85 -0
- package/src/components/composites/date-picker/range-panel.tsx +363 -0
- package/src/components/composites/date-picker/time-core.tsx +290 -0
- package/src/components/composites/date-picker/use-day-focus.ts +35 -0
- package/src/components/composites/dialog/Dialog.tsx +198 -0
- package/src/components/composites/dialog/dialog.css +180 -0
- package/src/components/composites/pagination/Pagination.tsx +131 -0
- package/src/components/composites/pagination/pagination.css +43 -0
- package/src/components/composites/popover/Popover.tsx +141 -0
- package/src/components/composites/popover/popover.css +69 -0
- package/src/components/composites/select/MultiSelect.tsx +133 -0
- package/src/components/composites/select/Select.tsx +122 -0
- package/src/components/composites/select/core/index.ts +4 -0
- package/src/components/composites/select/core/menu.tsx +100 -0
- package/src/components/composites/select/core/panel.tsx +154 -0
- package/src/components/composites/select/core/trigger.tsx +74 -0
- package/src/components/composites/select/core/types.ts +39 -0
- package/src/components/composites/select/core/use-listbox.ts +182 -0
- package/src/components/composites/select/select.css +416 -0
- package/src/components/composites/sheet/Sheet.tsx +135 -0
- package/src/components/composites/sheet/sheet.css +26 -0
- package/src/components/composites/sheet/use-sheet-drag.ts +126 -0
- package/src/components/composites/table/Table.tsx +377 -0
- package/src/components/composites/table/table.css +348 -0
- package/src/components/composites/tabs/Tabs.tsx +278 -0
- package/src/components/composites/tabs/tabs.css +208 -0
- package/src/components/composites/toast/Toast.tsx +380 -0
- package/src/components/composites/toast/toast-store.ts +295 -0
- package/src/components/composites/toast/toast.css +257 -0
- package/src/components/composites/tooltip/Tooltip.tsx +110 -0
- package/src/components/composites/tooltip/tooltip-host.tsx +184 -0
- package/src/components/composites/tooltip/tooltip-store.ts +81 -0
- package/src/components/composites/tooltip/tooltip.css +86 -0
- package/src/components/dev/MotionDevtools.tsx +200 -0
- package/src/components/dev/motion-devtools.css +265 -0
- package/src/components/dev/slowmo-engine.ts +230 -0
- package/src/components/internal/glass/glass.css +100 -0
- package/src/components/internal/glass/glint.ts +9 -0
- package/src/components/internal/hooks/use-controllable.ts +21 -0
- package/src/components/internal/hooks/use-scroll-edges.ts +46 -0
- package/src/components/internal/icon/Icon.tsx +66 -0
- package/src/components/internal/icon/IconSlot.tsx +10 -0
- package/src/components/internal/icon/icon.css +33 -0
- package/src/components/internal/overlay/focus.ts +68 -0
- package/src/components/internal/overlay/layer.tsx +149 -0
- package/src/components/internal/overlay/modal.tsx +141 -0
- package/src/components/internal/overlay/overlay.css +23 -0
- package/src/components/internal/overlay/position.ts +103 -0
- package/src/components/internal/utils/cx.ts +3 -0
- package/src/components/internal/utils/token-px.ts +8 -0
- package/src/components/primitives/avatar/Avatar.tsx +120 -0
- package/src/components/primitives/avatar/AvatarGroup.tsx +56 -0
- package/src/components/primitives/avatar/avatar.css +200 -0
- package/src/components/primitives/badge/Badge.tsx +75 -0
- package/src/components/primitives/badge/CountBadge.tsx +20 -0
- package/src/components/primitives/badge/StatusBadge.tsx +111 -0
- package/src/components/primitives/badge/badge.css +182 -0
- package/src/components/primitives/badge/odometer.css +62 -0
- package/src/components/primitives/badge/odometer.tsx +36 -0
- package/src/components/primitives/button/Button.tsx +102 -0
- package/src/components/primitives/button/button.css +269 -0
- package/src/components/primitives/checkbox/Checkbox.tsx +76 -0
- package/src/components/primitives/checkbox/check-glyph.tsx +28 -0
- package/src/components/primitives/checkbox/checkbox.css +177 -0
- package/src/components/primitives/collapse/Collapse.tsx +86 -0
- package/src/components/primitives/collapse/collapse.css +88 -0
- package/src/components/primitives/collapse/collapse.typecheck.tsx +29 -0
- package/src/components/primitives/input/NumberField.tsx +139 -0
- package/src/components/primitives/input/OtpField.tsx +134 -0
- package/src/components/primitives/input/TextField.tsx +110 -0
- package/src/components/primitives/input/field-chrome.tsx +83 -0
- package/src/components/primitives/input/input.css +333 -0
- package/src/components/primitives/radio-group/RadioGroup.tsx +183 -0
- package/src/components/primitives/radio-group/radio-group.css +300 -0
- package/src/components/primitives/tag/Tag.tsx +143 -0
- package/src/components/primitives/tag/ToggleTag.tsx +97 -0
- package/src/components/primitives/tag/tag.css +248 -0
- package/src/components/primitives/textarea/Textarea.tsx +190 -0
- package/src/components/primitives/textarea/textarea.css +219 -0
- package/src/components/primitives/toggle/Toggle.tsx +105 -0
- package/src/components/primitives/toggle/toggle.css +152 -0
- package/src/css.d.ts +1 -0
- package/src/dom-props.ts +1 -0
- package/src/engine/animate.ts +141 -0
- package/src/engine/drag.ts +53 -0
- package/src/engine/ease.ts +155 -0
- package/src/engine/flip.ts +59 -0
- package/src/engine/index.ts +13 -0
- package/src/mcp/server.ts +420 -0
- package/src/motion/element.tsx +53 -0
- package/src/motion/flip.tsx +87 -0
- package/src/motion/glide.tsx +47 -0
- package/src/motion/motion-timing.ts +33 -0
- package/src/motion/presence-context.ts +18 -0
- package/src/motion/presence.tsx +91 -0
- package/src/motion/timing.ts +49 -0
- package/src/motion/use-motion.ts +64 -0
- package/src/styles.css +26 -0
- package/src/tokens/avatar.css +20 -0
- package/src/tokens/color.css +58 -0
- package/src/tokens/elevation.css +22 -0
- package/src/tokens/fonts.css +3 -0
- package/src/tokens/glass.css +20 -0
- package/src/tokens/icons.css +7 -0
- package/src/tokens/layers.css +6 -0
- package/src/tokens/motion-scale.ts +17 -0
- package/src/tokens/motion-tokens.ts +92 -0
- package/src/tokens/motion.css +49 -0
- package/src/tokens/radius.css +11 -0
- package/src/tokens/semantic.css +65 -0
- package/src/tokens/spacing.css +26 -0
- package/src/tokens/typography.css +52 -0
package/dist/input.css
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/* input.css - inputs: TextField - NumberField - OtpField. */
|
|
2
|
+
|
|
3
|
+
/* No row-gap - the label and message each own their adjacent gap, so an absent message reserves zero. */
|
|
4
|
+
.fld {
|
|
5
|
+
display: grid;
|
|
6
|
+
}
|
|
7
|
+
.fld__label {
|
|
8
|
+
font: var(--type-caption);
|
|
9
|
+
font-weight: var(--weight-medium);
|
|
10
|
+
color: var(--text-body);
|
|
11
|
+
display: inline-flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: var(--space-1);
|
|
14
|
+
line-height: 1;
|
|
15
|
+
margin-bottom: var(--space-2);
|
|
16
|
+
}
|
|
17
|
+
.fld__req {
|
|
18
|
+
color: var(--danger);
|
|
19
|
+
}
|
|
20
|
+
.fld__optional {
|
|
21
|
+
color: var(--text-subtle);
|
|
22
|
+
font-weight: var(--weight-regular);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.fld__control {
|
|
26
|
+
position: relative;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.fld__input {
|
|
32
|
+
width: 100%;
|
|
33
|
+
height: var(--control-height);
|
|
34
|
+
padding: 0 var(--space-3);
|
|
35
|
+
font: var(--type-body);
|
|
36
|
+
color: var(--text-strong);
|
|
37
|
+
background: var(--bg-inset);
|
|
38
|
+
border: var(--border-hairline) solid var(--border-default);
|
|
39
|
+
border-radius: var(--radius-md);
|
|
40
|
+
transition: var(--transition-control);
|
|
41
|
+
appearance: none;
|
|
42
|
+
-webkit-appearance: none;
|
|
43
|
+
}
|
|
44
|
+
.fld__input::placeholder {
|
|
45
|
+
color: var(--text-disabled);
|
|
46
|
+
}
|
|
47
|
+
.fld__input:hover:not(:disabled):not(:focus) {
|
|
48
|
+
border-color: var(--border-strong);
|
|
49
|
+
}
|
|
50
|
+
.fld__input:focus {
|
|
51
|
+
outline: none;
|
|
52
|
+
border-color: var(--accent);
|
|
53
|
+
background: var(--bg-surface);
|
|
54
|
+
box-shadow: var(--ring-accent);
|
|
55
|
+
}
|
|
56
|
+
.fld__input:disabled {
|
|
57
|
+
background: var(--bg-muted);
|
|
58
|
+
color: var(--text-disabled);
|
|
59
|
+
cursor: not-allowed;
|
|
60
|
+
}
|
|
61
|
+
.fld__input[readonly] {
|
|
62
|
+
background: var(--bg-subtle);
|
|
63
|
+
color: var(--text-body);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* On message TEXT change (normalanderrorandwarning), JS re-triggers .fld__msg--enter to fade and rise - never a hard pop. */
|
|
67
|
+
.fld__msg {
|
|
68
|
+
font: var(--type-caption);
|
|
69
|
+
color: var(--text-subtle);
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: var(--space-1);
|
|
73
|
+
min-height: 1em;
|
|
74
|
+
transition: color var(--duration-fast) var(--ease-standard);
|
|
75
|
+
}
|
|
76
|
+
.fld__msg i {
|
|
77
|
+
font-size: var(--size-body);
|
|
78
|
+
flex: none;
|
|
79
|
+
}
|
|
80
|
+
.fld__msg--enter {
|
|
81
|
+
animation: fld-msg-in var(--duration-base) var(--ease-entrance);
|
|
82
|
+
}
|
|
83
|
+
@keyframes fld-msg-in {
|
|
84
|
+
from {
|
|
85
|
+
opacity: 0;
|
|
86
|
+
transform: translateY(calc(var(--space-px) * -1));
|
|
87
|
+
}
|
|
88
|
+
to {
|
|
89
|
+
opacity: 1;
|
|
90
|
+
transform: translateY(0);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
@media (prefers-reduced-motion: reduce) {
|
|
94
|
+
.fld__msg--enter {
|
|
95
|
+
animation: none;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Gap is the message's padding-top (not margin) so it lives inside the Collapse and clips to zero when closed. */
|
|
100
|
+
.fld .fld__msg {
|
|
101
|
+
padding-top: var(--space-2);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.fld--sm .fld__input {
|
|
105
|
+
height: var(--control-height-sm);
|
|
106
|
+
font-size: var(--size-caption);
|
|
107
|
+
padding: 0 var(--space-2);
|
|
108
|
+
border-radius: var(--radius-sm);
|
|
109
|
+
}
|
|
110
|
+
.fld--lg .fld__input {
|
|
111
|
+
height: var(--control-height-lg);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.fld__icon {
|
|
115
|
+
position: absolute;
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
color: var(--text-subtle);
|
|
120
|
+
pointer-events: none;
|
|
121
|
+
transition: var(--transition-control);
|
|
122
|
+
}
|
|
123
|
+
.fld__icon i {
|
|
124
|
+
font-size: var(--icon-md);
|
|
125
|
+
}
|
|
126
|
+
.fld__icon--lead {
|
|
127
|
+
left: var(--space-2);
|
|
128
|
+
}
|
|
129
|
+
.fld__icon--trail {
|
|
130
|
+
right: var(--space-2);
|
|
131
|
+
}
|
|
132
|
+
.fld__control:focus-within .fld__icon {
|
|
133
|
+
color: var(--text-muted);
|
|
134
|
+
}
|
|
135
|
+
.fld--has-lead .fld__input {
|
|
136
|
+
padding-left: calc(var(--space-2) + var(--icon-md) + var(--space-2));
|
|
137
|
+
}
|
|
138
|
+
.fld--has-trail .fld__input {
|
|
139
|
+
padding-right: calc(var(--space-3) + var(--icon-md) + var(--space-2));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.fld__action {
|
|
143
|
+
position: absolute;
|
|
144
|
+
right: var(--space-2);
|
|
145
|
+
width: var(--control-height-sm);
|
|
146
|
+
height: var(--control-height-sm);
|
|
147
|
+
display: inline-flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
justify-content: center;
|
|
150
|
+
border: 0;
|
|
151
|
+
background: none;
|
|
152
|
+
color: var(--text-subtle);
|
|
153
|
+
border-radius: var(--radius-sm);
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
transition: var(--transition-control);
|
|
156
|
+
}
|
|
157
|
+
.fld__action i {
|
|
158
|
+
font-size: var(--icon-sm);
|
|
159
|
+
}
|
|
160
|
+
.fld__action:hover {
|
|
161
|
+
color: var(--text-strong);
|
|
162
|
+
background: var(--bg-muted);
|
|
163
|
+
}
|
|
164
|
+
.fld__action:focus-visible {
|
|
165
|
+
outline: none;
|
|
166
|
+
color: var(--text-strong);
|
|
167
|
+
box-shadow: var(--ring-accent);
|
|
168
|
+
}
|
|
169
|
+
.fld--has-action .fld__input {
|
|
170
|
+
padding-right: calc(var(--space-2) + var(--control-height-sm) + var(--space-1));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Per-state hover rule is required - the generic .fld__input:hover would otherwise win on specificity. */
|
|
174
|
+
.fld.is-error .fld__input {
|
|
175
|
+
border-color: var(--danger);
|
|
176
|
+
}
|
|
177
|
+
.fld.is-error .fld__input:hover:not(:disabled):not(:focus) {
|
|
178
|
+
border-color: var(--danger-text);
|
|
179
|
+
}
|
|
180
|
+
.fld.is-error .fld__input:focus {
|
|
181
|
+
box-shadow: var(--ring-danger);
|
|
182
|
+
}
|
|
183
|
+
.fld.is-error .fld__msg,
|
|
184
|
+
.fld.is-error .fld__icon {
|
|
185
|
+
color: var(--danger-text);
|
|
186
|
+
}
|
|
187
|
+
.fld.is-warning .fld__input {
|
|
188
|
+
border-color: var(--warning);
|
|
189
|
+
}
|
|
190
|
+
.fld.is-warning .fld__input:hover:not(:disabled):not(:focus) {
|
|
191
|
+
border-color: var(--warning-text);
|
|
192
|
+
}
|
|
193
|
+
.fld.is-warning .fld__input:focus {
|
|
194
|
+
box-shadow: var(--ring-warning);
|
|
195
|
+
}
|
|
196
|
+
.fld.is-warning .fld__msg {
|
|
197
|
+
color: var(--warning-text);
|
|
198
|
+
}
|
|
199
|
+
.fld.is-success .fld__input {
|
|
200
|
+
border-color: var(--success);
|
|
201
|
+
}
|
|
202
|
+
.fld.is-success .fld__input:hover:not(:disabled):not(:focus) {
|
|
203
|
+
border-color: var(--success-text);
|
|
204
|
+
}
|
|
205
|
+
.fld.is-success .fld__input:focus {
|
|
206
|
+
box-shadow: var(--ring-success);
|
|
207
|
+
}
|
|
208
|
+
.fld.is-success .fld__msg {
|
|
209
|
+
color: var(--success-text);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Stepper column width is the single source of truth - every clearance derives from it via calc(), so geometry can't drift. */
|
|
213
|
+
.numf {
|
|
214
|
+
--numf-stepper-w: var(--space-6);
|
|
215
|
+
}
|
|
216
|
+
.numf .fld__input {
|
|
217
|
+
font-variant-numeric: tabular-nums;
|
|
218
|
+
font-feature-settings: 'tnum';
|
|
219
|
+
padding-right: calc(var(--numf-stepper-w) + var(--space-2));
|
|
220
|
+
}
|
|
221
|
+
.numf--unit .fld__input {
|
|
222
|
+
padding-right: calc(var(--numf-stepper-w) + var(--numf-unit-w, var(--control-height-lg)) + var(--space-2));
|
|
223
|
+
}
|
|
224
|
+
.numf__unit {
|
|
225
|
+
position: absolute;
|
|
226
|
+
right: calc(var(--numf-stepper-w) + var(--space-2));
|
|
227
|
+
color: var(--text-subtle);
|
|
228
|
+
font: var(--type-caption);
|
|
229
|
+
pointer-events: none;
|
|
230
|
+
}
|
|
231
|
+
.numf__steppers {
|
|
232
|
+
position: absolute;
|
|
233
|
+
top: var(--border-hairline);
|
|
234
|
+
right: var(--border-hairline);
|
|
235
|
+
bottom: var(--border-hairline);
|
|
236
|
+
width: var(--numf-stepper-w);
|
|
237
|
+
display: grid;
|
|
238
|
+
grid-template-rows: 1fr 1fr;
|
|
239
|
+
border-left: var(--border-hairline) solid var(--border-default);
|
|
240
|
+
border-radius: 0 var(--radius-md) var(--radius-md) 0;
|
|
241
|
+
overflow: hidden;
|
|
242
|
+
}
|
|
243
|
+
.numf__step {
|
|
244
|
+
border: 0;
|
|
245
|
+
background: var(--bg-surface);
|
|
246
|
+
color: var(--text-muted);
|
|
247
|
+
display: grid;
|
|
248
|
+
place-items: center;
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
transition: var(--transition-control);
|
|
251
|
+
padding: 0;
|
|
252
|
+
}
|
|
253
|
+
.numf__step i {
|
|
254
|
+
font-size: var(--size-caption);
|
|
255
|
+
}
|
|
256
|
+
.numf__step:hover {
|
|
257
|
+
background: var(--neutral-wash);
|
|
258
|
+
color: var(--text-strong);
|
|
259
|
+
}
|
|
260
|
+
.numf__step:active {
|
|
261
|
+
background: var(--bg-muted);
|
|
262
|
+
}
|
|
263
|
+
.numf__step:disabled {
|
|
264
|
+
color: var(--text-disabled);
|
|
265
|
+
cursor: not-allowed;
|
|
266
|
+
background: var(--bg-surface);
|
|
267
|
+
}
|
|
268
|
+
.numf__step + .numf__step {
|
|
269
|
+
border-top: var(--border-hairline) solid var(--border-default);
|
|
270
|
+
}
|
|
271
|
+
.numf .fld__input:focus ~ .numf__steppers {
|
|
272
|
+
border-color: var(--accent);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* Intentional exception: slot (44x52 - sm 38x44) and separator (10x2) are bespoke px - the token ramp yields no correctly-proportioned code cell; do not "fix" to a token. */
|
|
276
|
+
.otp {
|
|
277
|
+
display: inline-flex;
|
|
278
|
+
align-items: center;
|
|
279
|
+
gap: var(--space-2);
|
|
280
|
+
}
|
|
281
|
+
.otp__slot {
|
|
282
|
+
width: 44px;
|
|
283
|
+
height: 52px;
|
|
284
|
+
text-align: center;
|
|
285
|
+
font-family: var(--font-mono);
|
|
286
|
+
font-size: var(--size-title);
|
|
287
|
+
font-weight: var(--weight-medium);
|
|
288
|
+
color: var(--text-strong);
|
|
289
|
+
background: var(--bg-inset);
|
|
290
|
+
border: var(--border-hairline) solid var(--border-default);
|
|
291
|
+
border-radius: var(--radius-md);
|
|
292
|
+
transition: var(--transition-control);
|
|
293
|
+
caret-color: var(--accent);
|
|
294
|
+
appearance: none;
|
|
295
|
+
}
|
|
296
|
+
.otp__slot:hover:not(:disabled):not(:focus) {
|
|
297
|
+
border-color: var(--border-strong);
|
|
298
|
+
}
|
|
299
|
+
.otp__slot:focus {
|
|
300
|
+
outline: none;
|
|
301
|
+
border-color: var(--accent);
|
|
302
|
+
background: var(--bg-surface);
|
|
303
|
+
box-shadow: var(--ring-accent);
|
|
304
|
+
}
|
|
305
|
+
.otp__slot[data-filled='true'] {
|
|
306
|
+
border-color: var(--border-strong);
|
|
307
|
+
}
|
|
308
|
+
.otp__slot:disabled {
|
|
309
|
+
background: var(--bg-muted);
|
|
310
|
+
color: var(--text-disabled);
|
|
311
|
+
cursor: not-allowed;
|
|
312
|
+
}
|
|
313
|
+
.otp__sep {
|
|
314
|
+
width: 10px;
|
|
315
|
+
height: 2px;
|
|
316
|
+
background: var(--border-strong);
|
|
317
|
+
border-radius: var(--border-hairline);
|
|
318
|
+
flex: none;
|
|
319
|
+
}
|
|
320
|
+
.otp--sm .otp__slot {
|
|
321
|
+
width: 38px;
|
|
322
|
+
height: 44px;
|
|
323
|
+
font-size: var(--size-heading);
|
|
324
|
+
}
|
|
325
|
+
.otp.is-error .otp__slot {
|
|
326
|
+
border-color: var(--danger);
|
|
327
|
+
}
|
|
328
|
+
.otp.is-error .otp__slot:hover:not(:disabled):not(:focus) {
|
|
329
|
+
border-color: var(--danger-text);
|
|
330
|
+
}
|
|
331
|
+
.otp.is-error .otp__slot:focus {
|
|
332
|
+
box-shadow: var(--ring-danger);
|
|
333
|
+
}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/mcp/server.ts
|
|
4
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
function findRoot() {
|
|
8
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
for (; ; ) {
|
|
10
|
+
const pj = join(dir, "package.json");
|
|
11
|
+
if (existsSync(pj)) {
|
|
12
|
+
try {
|
|
13
|
+
if (JSON.parse(readFileSync(pj, "utf8")).name === "@zyncat/ui") return dir;
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const parent = dirname(dir);
|
|
18
|
+
if (parent === dir) throw new Error("@zyncat/ui package root not found");
|
|
19
|
+
dir = parent;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
var SECTION_RE = /^=+\s+(.+?)\s*$/;
|
|
23
|
+
var HEADING_RE = /^([A-Za-z][\w /]*?) - @zyncat\/ui\/([a-z][a-z0-9-]*)\b.*$/;
|
|
24
|
+
var cached = null;
|
|
25
|
+
function db() {
|
|
26
|
+
if (cached) return cached;
|
|
27
|
+
const root = findRoot();
|
|
28
|
+
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
29
|
+
const subpaths = Object.entries(pkg.exports ?? {}).filter(([, v]) => typeof v === "object" && v !== null && "types" in v).map(([k]) => k.replace(/^\.\//, ""));
|
|
30
|
+
const preamble = [];
|
|
31
|
+
const sections = [];
|
|
32
|
+
const entries = [];
|
|
33
|
+
let section = null;
|
|
34
|
+
let entry = null;
|
|
35
|
+
const close = (e) => {
|
|
36
|
+
if (!e) return;
|
|
37
|
+
while (e.lines.length && !e.lines[e.lines.length - 1].trim()) e.lines.pop();
|
|
38
|
+
entries.push(e);
|
|
39
|
+
};
|
|
40
|
+
for (const line of readFileSync(join(root, "llms.txt"), "utf8").split("\n")) {
|
|
41
|
+
const sec = line.match(SECTION_RE);
|
|
42
|
+
const head = line.match(HEADING_RE);
|
|
43
|
+
if (sec) {
|
|
44
|
+
close(entry);
|
|
45
|
+
entry = null;
|
|
46
|
+
section = { title: sec[1], body: [] };
|
|
47
|
+
sections.push(section);
|
|
48
|
+
} else if (head) {
|
|
49
|
+
close(entry);
|
|
50
|
+
entry = { title: head[1].trim(), subpath: head[2], section: section?.title ?? "", lines: [line] };
|
|
51
|
+
} else if (entry) {
|
|
52
|
+
entry.lines.push(line);
|
|
53
|
+
} else if (section) {
|
|
54
|
+
section.body.push(line);
|
|
55
|
+
} else {
|
|
56
|
+
preamble.push(line);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
close(entry);
|
|
60
|
+
for (const s of sections) {
|
|
61
|
+
while (s.body.length && !s.body[s.body.length - 1].trim()) s.body.pop();
|
|
62
|
+
while (s.body.length && !s.body[0].trim()) s.body.shift();
|
|
63
|
+
}
|
|
64
|
+
while (preamble.length && !preamble[preamble.length - 1].trim()) preamble.pop();
|
|
65
|
+
cached = { root, version: String(pkg.version ?? "0"), subpaths, preamble, sections, entries };
|
|
66
|
+
return cached;
|
|
67
|
+
}
|
|
68
|
+
var norm = (s) => s.toLowerCase().replace(/^@zyncat\/ui\//, "").replace(/[^a-z0-9]/g, "");
|
|
69
|
+
function resolveSubpath(input) {
|
|
70
|
+
const d = db();
|
|
71
|
+
const q = norm(input);
|
|
72
|
+
if (!q) throw new Error('Pass a component name or subpath, e.g. "Button" or "text-field".');
|
|
73
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
74
|
+
for (const sub of d.subpaths) candidates.set(norm(sub), sub);
|
|
75
|
+
for (const e of d.entries) for (const part of e.title.split("/")) candidates.set(norm(part), e.subpath);
|
|
76
|
+
const exact = candidates.get(q);
|
|
77
|
+
if (exact) return exact;
|
|
78
|
+
const loose = /* @__PURE__ */ new Set();
|
|
79
|
+
for (const [name, sub] of candidates) if (name.includes(q) || q.includes(name)) loose.add(sub);
|
|
80
|
+
if (loose.size === 1) return [...loose][0];
|
|
81
|
+
const all = d.entries.map((e) => `${e.title} (${e.subpath})`).join(", ");
|
|
82
|
+
const extras = d.subpaths.filter((s) => !d.entries.some((e) => e.subpath === s)).join(", ");
|
|
83
|
+
throw new Error(
|
|
84
|
+
(loose.size ? `"${input}" is ambiguous: ${[...loose].join(", ")}. ` : `No component matches "${input}". `) + `Available: ${all}${extras ? `; types-only modules: ${extras}` : ""}.`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
function readTypes(root, subpath) {
|
|
88
|
+
const out = [];
|
|
89
|
+
const seen = /* @__PURE__ */ new Set();
|
|
90
|
+
const walk = (base) => {
|
|
91
|
+
if (seen.has(base)) return;
|
|
92
|
+
seen.add(base);
|
|
93
|
+
const p = join(root, "dist", `${base}.d.ts`);
|
|
94
|
+
if (!existsSync(p)) return;
|
|
95
|
+
const text = readFileSync(p, "utf8");
|
|
96
|
+
out.push(`--- dist/${base}.d.ts ---
|
|
97
|
+
${text.trimEnd()}`);
|
|
98
|
+
for (const m of text.matchAll(/from\s+['"]\.\/([\w.-]+)\.js['"]/g)) walk(m[1]);
|
|
99
|
+
};
|
|
100
|
+
walk(subpath);
|
|
101
|
+
if (!out.length) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`dist/${subpath}.d.ts not found - the package is not built. In the zyncat-ui repo run "pnpm build"; in a consumer, reinstall the package.`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
return out.join("\n\n");
|
|
107
|
+
}
|
|
108
|
+
var tokenFiles = (root) => existsSync(join(root, "src/tokens")) ? readdirSync(join(root, "src/tokens")).filter((f) => f.endsWith(".css")).sort() : [];
|
|
109
|
+
var CODE_LINE_RE = /^(?:[<{]|import\s|const\s|let\s|function\s)/;
|
|
110
|
+
function entryTeaser(e) {
|
|
111
|
+
const parts = [];
|
|
112
|
+
for (let i = 1; i < e.lines.length; i++) {
|
|
113
|
+
const line = e.lines[i].trim();
|
|
114
|
+
if (!line) break;
|
|
115
|
+
if (i > 1 && CODE_LINE_RE.test(line)) break;
|
|
116
|
+
parts.push(line);
|
|
117
|
+
}
|
|
118
|
+
return parts.join(" ");
|
|
119
|
+
}
|
|
120
|
+
function listComponents() {
|
|
121
|
+
const d = db();
|
|
122
|
+
const out = [...d.preamble, ""];
|
|
123
|
+
for (const s of d.sections) {
|
|
124
|
+
const inSection = d.entries.filter((e) => e.section === s.title);
|
|
125
|
+
if (!inSection.length && !s.body.length) continue;
|
|
126
|
+
out.push(`== ${s.title} ==`);
|
|
127
|
+
out.push(...s.body);
|
|
128
|
+
for (const e of inSection) {
|
|
129
|
+
const first = entryTeaser(e);
|
|
130
|
+
out.push(`${e.title} - @zyncat/ui/${e.subpath}${first ? ` - ${first}` : ""}`);
|
|
131
|
+
}
|
|
132
|
+
out.push("");
|
|
133
|
+
}
|
|
134
|
+
const extras = d.subpaths.filter((sub) => !d.entries.some((e) => e.subpath === sub));
|
|
135
|
+
if (extras.length) {
|
|
136
|
+
out.push("== SUPPORTING MODULES (no llms.txt entry - full docs live in their types) ==");
|
|
137
|
+
for (const sub of extras) out.push(`@zyncat/ui/${sub} - call get_component("${sub}")`);
|
|
138
|
+
}
|
|
139
|
+
return out.join("\n").trim();
|
|
140
|
+
}
|
|
141
|
+
function getComponent(input) {
|
|
142
|
+
const d = db();
|
|
143
|
+
const sub = resolveSubpath(input);
|
|
144
|
+
const entry = d.entries.find((e) => e.subpath === sub);
|
|
145
|
+
const out = [`# ${entry ? entry.title : sub} - @zyncat/ui/${sub}`, ""];
|
|
146
|
+
if (entry) {
|
|
147
|
+
const note = d.sections.find((s) => s.title === entry.section)?.body ?? [];
|
|
148
|
+
if (note.length) out.push(`Applies to every ${entry.section} component:`, ...note, "");
|
|
149
|
+
out.push("## Usage (llms.txt)", ...entry.lines, "");
|
|
150
|
+
} else {
|
|
151
|
+
out.push("No llms.txt entry - this module is documented by its types below.", "");
|
|
152
|
+
}
|
|
153
|
+
out.push("## Types (entry .d.ts + the shared chunks it imports)", readTypes(d.root, sub));
|
|
154
|
+
return out.join("\n");
|
|
155
|
+
}
|
|
156
|
+
function searchApi(query) {
|
|
157
|
+
const d = db();
|
|
158
|
+
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
159
|
+
if (!words.length) throw new Error('Pass one or more keywords, e.g. "searchable" or "drag dismiss".');
|
|
160
|
+
const hits = /* @__PURE__ */ new Map();
|
|
161
|
+
const scan = (label, text, lineLabel) => {
|
|
162
|
+
text.split("\n").forEach((line, i) => {
|
|
163
|
+
const l = line.toLowerCase();
|
|
164
|
+
if (!words.every((w) => l.includes(w))) return;
|
|
165
|
+
const key = lineLabel ? lineLabel(line, i) : label;
|
|
166
|
+
if (!hits.has(key)) hits.set(key, []);
|
|
167
|
+
hits.get(key).push(` L${i + 1}: ${line.trim()}`);
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
{
|
|
171
|
+
const raw = readFileSync(join(d.root, "llms.txt"), "utf8");
|
|
172
|
+
const labels = [];
|
|
173
|
+
let current = "llms.txt";
|
|
174
|
+
for (const line of raw.split("\n")) {
|
|
175
|
+
const sec = line.match(SECTION_RE);
|
|
176
|
+
const head = line.match(HEADING_RE);
|
|
177
|
+
if (sec) current = `llms.txt \xBB ${sec[1]}`;
|
|
178
|
+
else if (head) current = `llms.txt \xBB ${head[1].trim()}`;
|
|
179
|
+
labels.push(current);
|
|
180
|
+
}
|
|
181
|
+
scan("llms.txt", raw, (_line, i) => labels[i]);
|
|
182
|
+
}
|
|
183
|
+
const distDir = join(d.root, "dist");
|
|
184
|
+
const dts = existsSync(distDir) ? readdirSync(distDir).filter((f) => f.endsWith(".d.ts")).sort() : [];
|
|
185
|
+
for (const f of dts) scan(`dist/${f}`, readFileSync(join(distDir, f), "utf8"));
|
|
186
|
+
for (const f of tokenFiles(d.root)) scan(`src/tokens/${f}`, readFileSync(join(d.root, "src/tokens", f), "utf8"));
|
|
187
|
+
const out = [];
|
|
188
|
+
let shown = 0;
|
|
189
|
+
let total = 0;
|
|
190
|
+
for (const [, lines] of hits) total += lines.length;
|
|
191
|
+
for (const [label, lines] of hits) {
|
|
192
|
+
if (shown >= 60) break;
|
|
193
|
+
out.push(`## ${label}`);
|
|
194
|
+
for (const l of lines) {
|
|
195
|
+
if (shown >= 60) break;
|
|
196
|
+
out.push(l);
|
|
197
|
+
shown++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (!total) return `No matches for "${query}". Try a shorter keyword, or list_components for the full index.`;
|
|
201
|
+
if (total > shown) out.push(`... +${total - shown} more matching lines - narrow the query.`);
|
|
202
|
+
if (!dts.length) out.push("(note: dist/ is not built, so type definitions were not searched)");
|
|
203
|
+
out.push("", "Follow up with get_component(<name>) for the full picture.");
|
|
204
|
+
return out.join("\n");
|
|
205
|
+
}
|
|
206
|
+
function getTokens(group) {
|
|
207
|
+
const d = db();
|
|
208
|
+
const files = tokenFiles(d.root);
|
|
209
|
+
if (!files.length) throw new Error("src/tokens/*.css not found in the installed package.");
|
|
210
|
+
let picked = files;
|
|
211
|
+
if (group) {
|
|
212
|
+
const q = norm(group);
|
|
213
|
+
picked = files.filter((f) => {
|
|
214
|
+
const name = norm(f.replace(/\.css$/, ""));
|
|
215
|
+
return name.includes(q) || q.includes(name);
|
|
216
|
+
});
|
|
217
|
+
if (!picked.length) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`No token group matches "${group}". Groups: ${files.map((f) => f.replace(/\.css$/, "")).join(", ")}.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const out = picked.map(
|
|
224
|
+
(f) => `/* ==== src/tokens/${f} ==== */
|
|
225
|
+
${readFileSync(join(d.root, "src/tokens", f), "utf8").trimEnd()}`
|
|
226
|
+
);
|
|
227
|
+
const theming = d.sections.find((s) => s.title.includes("THEMING"));
|
|
228
|
+
if (theming?.body.length) out.push(["/* ==== theming ==== */", ...theming.body].join("\n"));
|
|
229
|
+
return out.join("\n\n");
|
|
230
|
+
}
|
|
231
|
+
var TOOLS = [
|
|
232
|
+
{
|
|
233
|
+
name: "list_components",
|
|
234
|
+
description: "Every Zyncat UI component: name, import subpath and one-line purpose, grouped by category, plus package setup and usage conventions. Start here instead of exploring node_modules.",
|
|
235
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: "get_component",
|
|
239
|
+
description: "Full API for one component: the maintainers' usage notes and example plus the complete TypeScript prop types with doc comments (shared type chunks inlined). Cheaper and more accurate than reading node_modules/@zyncat/ui yourself.",
|
|
240
|
+
inputSchema: {
|
|
241
|
+
type: "object",
|
|
242
|
+
properties: {
|
|
243
|
+
component: {
|
|
244
|
+
type: "string",
|
|
245
|
+
description: 'Component name or subpath - "Button", "TextField", "text-field", "@zyncat/ui/select".'
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
required: ["component"],
|
|
249
|
+
additionalProperties: false
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: "search_api",
|
|
254
|
+
description: 'Keyword search across all component docs, type definitions and design-token CSS. Finds which component owns a prop, type, token or behavior (e.g. "searchable", "DurationToken", "drag dismiss", "--accent"). Every word must match a line; follow up with get_component.',
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: "object",
|
|
257
|
+
properties: { query: { type: "string", description: "One or more keywords." } },
|
|
258
|
+
required: ["query"],
|
|
259
|
+
additionalProperties: false
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: "get_tokens",
|
|
264
|
+
description: "The design-token vocabulary as CSS custom properties with their real values - color, semantic, spacing, typography, radius, elevation, motion, icons, layers, glass, avatar, fonts. Optionally pass one group name; omit for all. Use for theming/overrides and for reading exact values.",
|
|
265
|
+
inputSchema: {
|
|
266
|
+
type: "object",
|
|
267
|
+
properties: {
|
|
268
|
+
group: { type: "string", description: 'One token group, e.g. "color" or "motion". Omit for all.' }
|
|
269
|
+
},
|
|
270
|
+
additionalProperties: false
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
];
|
|
274
|
+
var INSTRUCTIONS = "Zyncat UI design-system API. Before writing Zyncat UI code, use these tools instead of reading node_modules or guessing props: list_components (what exists + setup and conventions), get_component (one component: usage docs + complete prop types), search_api (find the component/prop/token for a keyword), get_tokens (CSS custom-property vocabulary with real values, for theming). Imports are per-subpath (@zyncat/ui/button - no barrel); link @zyncat/ui/styles.css once at the root.";
|
|
275
|
+
function callTool(name, args) {
|
|
276
|
+
const str = (k) => typeof args[k] === "string" ? args[k] : void 0;
|
|
277
|
+
switch (name) {
|
|
278
|
+
case "list_components":
|
|
279
|
+
return listComponents();
|
|
280
|
+
case "get_component": {
|
|
281
|
+
const component = str("component");
|
|
282
|
+
if (!component) throw new Error('Missing required argument "component".');
|
|
283
|
+
return getComponent(component);
|
|
284
|
+
}
|
|
285
|
+
case "search_api": {
|
|
286
|
+
const query = str("query");
|
|
287
|
+
if (!query) throw new Error('Missing required argument "query".');
|
|
288
|
+
return searchApi(query);
|
|
289
|
+
}
|
|
290
|
+
case "get_tokens":
|
|
291
|
+
return getTokens(str("group"));
|
|
292
|
+
default:
|
|
293
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function send(msg) {
|
|
297
|
+
try {
|
|
298
|
+
process.stdout.write(`${JSON.stringify(msg)}
|
|
299
|
+
`);
|
|
300
|
+
} catch {
|
|
301
|
+
process.exit(0);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
var reply = (id, result) => send({ jsonrpc: "2.0", id, result });
|
|
305
|
+
var replyError = (id, code, message) => send({ jsonrpc: "2.0", id, error: { code, message } });
|
|
306
|
+
function handle(req) {
|
|
307
|
+
const { id, method, params } = req;
|
|
308
|
+
const isNotification = id === void 0;
|
|
309
|
+
switch (method) {
|
|
310
|
+
case "initialize": {
|
|
311
|
+
let version = "0.0.0";
|
|
312
|
+
try {
|
|
313
|
+
version = db().version;
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
return reply(id, {
|
|
317
|
+
protocolVersion: typeof params?.protocolVersion === "string" ? params.protocolVersion : "2025-06-18",
|
|
318
|
+
capabilities: { tools: {} },
|
|
319
|
+
serverInfo: { name: "zyncat-ui", version },
|
|
320
|
+
instructions: INSTRUCTIONS
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
case "ping":
|
|
324
|
+
return reply(id, {});
|
|
325
|
+
case "tools/list":
|
|
326
|
+
return reply(id, { tools: TOOLS });
|
|
327
|
+
case "tools/call": {
|
|
328
|
+
try {
|
|
329
|
+
const name = typeof params?.name === "string" ? params.name : "";
|
|
330
|
+
const args = params?.arguments ?? {};
|
|
331
|
+
const text = callTool(name, args);
|
|
332
|
+
return reply(id, { content: [{ type: "text", text }], isError: false });
|
|
333
|
+
} catch (e) {
|
|
334
|
+
const text = e instanceof Error ? e.message : String(e);
|
|
335
|
+
return reply(id, { content: [{ type: "text", text }], isError: true });
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
default:
|
|
339
|
+
if (!isNotification) replyError(id ?? null, -32601, `Method not found: ${method}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
var buffer = "";
|
|
343
|
+
process.stdin.setEncoding("utf8");
|
|
344
|
+
process.stdin.on("data", (chunk) => {
|
|
345
|
+
buffer += chunk;
|
|
346
|
+
let nl;
|
|
347
|
+
while ((nl = buffer.indexOf("\n")) !== -1) {
|
|
348
|
+
const line = buffer.slice(0, nl).trim();
|
|
349
|
+
buffer = buffer.slice(nl + 1);
|
|
350
|
+
if (!line) continue;
|
|
351
|
+
try {
|
|
352
|
+
handle(JSON.parse(line));
|
|
353
|
+
} catch {
|
|
354
|
+
replyError(null, -32700, "Parse error");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
process.stdin.on("end", () => process.exit(0));
|
|
359
|
+
process.stdout.on("error", () => process.exit(0));
|