@astryx-vue/core 0.1.1 → 0.1.3

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 (223) hide show
  1. package/dist/AppShell/index.d.ts +2 -0
  2. package/dist/AppShell/index.js +2 -0
  3. package/dist/AppShell-b0PWt9Fz.js +249 -0
  4. package/dist/AspectRatio/index.d.ts +2 -0
  5. package/dist/AspectRatio/index.js +2 -0
  6. package/dist/AspectRatio-Bij7e-tq.js +40 -0
  7. package/dist/AvatarGroup/index.d.ts +1 -1
  8. package/dist/Banner/index.d.ts +1 -1
  9. package/dist/BottomSheet/index.d.ts +1 -1
  10. package/dist/ButtonGroup/index.d.ts +1 -1
  11. package/dist/Calendar/index.js +1 -1
  12. package/dist/{Calendar-BEyrkUtr.js → Calendar-CYhGDT6f.js} +1 -1
  13. package/dist/Chat/index.js +1 -1
  14. package/dist/{Chat-CO3mCs9A.js → Chat-C1aWl5V3.js} +1 -1
  15. package/dist/CheckboxInput/index.d.ts +1 -1
  16. package/dist/CheckboxInput/index.js +1 -1
  17. package/dist/{CheckboxInput-C86o3XoG.js → CheckboxInput-CMsEE1_4.js} +4 -2
  18. package/dist/CheckboxList/index.d.ts +1 -1
  19. package/dist/CheckboxList/index.js +1 -1
  20. package/dist/{CheckboxList-BL2sDOWK.js → CheckboxList-EsIEXjK_.js} +2 -2
  21. package/dist/Citation/index.js +1 -1
  22. package/dist/{Citation-BqwJvw7o.js → Citation-C1X0Rde8.js} +1 -1
  23. package/dist/ClickableCard/index.d.ts +2 -0
  24. package/dist/ClickableCard/index.js +2 -0
  25. package/dist/ClickableCard-Bhds4RRe.js +112 -0
  26. package/dist/Collapsible/index.d.ts +2 -2
  27. package/dist/Collapsible/index.js +2 -2
  28. package/dist/Collapsible-BS9ctCQV.js +192 -0
  29. package/dist/CommandPalette/index.d.ts +2 -0
  30. package/dist/CommandPalette/index.js +2 -0
  31. package/dist/CommandPalette-u5h_E05P.js +489 -0
  32. package/dist/ComplexSelector/index.d.ts +2 -0
  33. package/dist/ComplexSelector/index.js +2 -0
  34. package/dist/ComplexSelector-BHmGWml0.js +293 -0
  35. package/dist/ContextMenu/index.d.ts +1 -1
  36. package/dist/DateInput/index.d.ts +1 -1
  37. package/dist/DateInput/index.js +1 -1
  38. package/dist/{DateInput-BOIb0zAp.js → DateInput-D2ErjXYO.js} +2 -2
  39. package/dist/DateRangeInput/index.d.ts +1 -1
  40. package/dist/DateRangeInput/index.js +1 -1
  41. package/dist/{DateRangeInput-DLcbgUBi.js → DateRangeInput-fmQlr_A7.js} +3 -3
  42. package/dist/DateTimeInput/index.d.ts +1 -1
  43. package/dist/DateTimeInput/index.js +1 -1
  44. package/dist/{DateTimeInput-RitYX_Yx.js → DateTimeInput-Bs1JmcIp.js} +4 -4
  45. package/dist/Field/index.js +2 -2
  46. package/dist/{Field-VlTBsIEo.js → Field-8zRxzDHE.js} +11 -3
  47. package/dist/{FieldLabel-B1NRyQlS.js → FieldLabel-DmmJyX7w.js} +6 -1
  48. package/dist/FileInput/index.d.ts +1 -1
  49. package/dist/FileInput/index.js +1 -1
  50. package/dist/{FileInput-CYvEV503.js → FileInput-CmAfOpkA.js} +2 -2
  51. package/dist/FormLayout/index.d.ts +2 -0
  52. package/dist/FormLayout/index.js +2 -0
  53. package/dist/FormLayout-D47FjiOq.js +40 -0
  54. package/dist/HoverCard/index.d.ts +1 -1
  55. package/dist/Layout/index.d.ts +2 -0
  56. package/dist/Layout/index.js +3 -0
  57. package/dist/Layout-Bed3kP0M.js +56 -0
  58. package/dist/LayoutPanel-C34uOq3e.js +358 -0
  59. package/dist/List/index.d.ts +1 -1
  60. package/dist/Markdown/index.d.ts +1 -1
  61. package/dist/Markdown/index.js +1 -1
  62. package/dist/{Markdown-Dnlp8cVx.js → Markdown-CwtLr3f_.js} +1 -1
  63. package/dist/MetadataList/index.js +1 -1
  64. package/dist/{MetadataList-DIsqS1Qb.js → MetadataList-DlXQTLog.js} +1 -1
  65. package/dist/MobileNav/index.d.ts +1 -1
  66. package/dist/MobileNav/index.js +1 -1
  67. package/dist/{MobileNavToggle-aUZiDwHm.js → MobileNavToggle-CgQamG6E.js} +19 -12
  68. package/dist/MoreMenu/index.d.ts +1 -1
  69. package/dist/MultiSelector/index.d.ts +1 -1
  70. package/dist/MultiSelector/index.js +1 -1
  71. package/dist/{MultiSelector-Bh8or2S6.js → MultiSelector-DT8ZccMI.js} +3 -3
  72. package/dist/NavItem/index.d.ts +1 -1
  73. package/dist/NavMenu/index.d.ts +1 -1
  74. package/dist/NumberInput/index.d.ts +1 -1
  75. package/dist/NumberInput/index.js +1 -1
  76. package/dist/{NumberInput-C3S-4dIu.js → NumberInput-DspJO6z6.js} +1 -1
  77. package/dist/OverflowList/index.d.ts +1 -1
  78. package/dist/OverflowList/index.js +1 -1
  79. package/dist/{OverflowList-Kr4iJrNV.js → OverflowList-zXg3g6fy.js} +1 -1
  80. package/dist/Overlay/index.d.ts +1 -1
  81. package/dist/Pagination/index.js +1 -1
  82. package/dist/{Pagination-BRStpeSB.js → Pagination-DXfgMUKJ.js} +2 -2
  83. package/dist/Popover/index.d.ts +2 -1
  84. package/dist/Radio/index.d.ts +1 -1
  85. package/dist/Radio/index.js +1 -1
  86. package/dist/{RadioGroup-DS6oTV_j.js → RadioGroup-BqjdSCfJ.js} +1 -1
  87. package/dist/RadioList/index.d.ts +1 -1
  88. package/dist/RadioList/index.js +1 -1
  89. package/dist/{RadioList-pwr93I-z.js → RadioList-DI8ujXcT.js} +1 -1
  90. package/dist/Resizable/index.d.ts +2 -0
  91. package/dist/Resizable/index.js +2 -0
  92. package/dist/Resizable-BuGKvU9I.js +261 -0
  93. package/dist/ScrollableArea/index.d.ts +2 -0
  94. package/dist/ScrollableArea/index.js +2 -0
  95. package/dist/ScrollableArea-DQDYjnxO.js +78 -0
  96. package/dist/Section/index.d.ts +2 -0
  97. package/dist/Section/index.js +2 -0
  98. package/dist/Section-C48Wqfc7.js +68 -0
  99. package/dist/SelectableCard/index.d.ts +2 -0
  100. package/dist/SelectableCard/index.js +2 -0
  101. package/dist/SelectableCard-Bj5s_tIN.js +108 -0
  102. package/dist/Selector/index.d.ts +1 -1
  103. package/dist/Selector/index.js +1 -1
  104. package/dist/{Selector-DvEUIVEC.js → Selector-DlZpQh42.js} +1 -1
  105. package/dist/SideNav/index.d.ts +1 -1
  106. package/dist/SideNav/index.js +2 -1
  107. package/dist/{SideNav-B7LX4RcP.js → SideNav-Cdrigq2A.js} +48 -26
  108. package/dist/Slider/index.js +1 -1
  109. package/dist/{Slider-DTnWxtnb.js → Slider-D8h_RKcF.js} +1 -1
  110. package/dist/Stepper/index.d.ts +2 -0
  111. package/dist/Stepper/index.js +2 -0
  112. package/dist/Stepper-DxmLfh8O.js +423 -0
  113. package/dist/Switch/index.d.ts +1 -1
  114. package/dist/Switch/index.js +1 -1
  115. package/dist/{Switch-CNdnr5TP.js → Switch-SesQzPGZ.js} +4 -2
  116. package/dist/TabList/index.d.ts +2 -2
  117. package/dist/TabList/index.js +2 -2
  118. package/dist/TabList-C411uNQU.js +380 -0
  119. package/dist/Table/index.d.ts +2 -1
  120. package/dist/Table/index.js +1 -1
  121. package/dist/{Table-D5zWaITo.js → Table-7qRmlIQd.js} +5 -5
  122. package/dist/TextArea/index.d.ts +1 -1
  123. package/dist/TextArea/index.js +1 -1
  124. package/dist/{TextArea-BL0NuB99.js → TextArea-Cv9UVbzS.js} +5 -3
  125. package/dist/TextInput/index.d.ts +1 -1
  126. package/dist/TextInput/index.js +1 -1
  127. package/dist/{TextInput-B0IKC7g5.js → TextInput-BasnjVvy.js} +5 -3
  128. package/dist/Thumbnail/index.js +1 -1
  129. package/dist/{Thumbnail-DMOgWncm.js → Thumbnail-BWVzLLyI.js} +1 -1
  130. package/dist/{TimeField-DeQ1ukHl.js → TimeField-l3QzU6vC.js} +1 -1
  131. package/dist/TimeInput/index.d.ts +1 -1
  132. package/dist/TimeInput/index.js +1 -1
  133. package/dist/{TimeInput-jb1nLqZk.js → TimeInput-OkgX-xbQ.js} +2 -2
  134. package/dist/Timestamp/index.d.ts +1 -1
  135. package/dist/Timestamp/index.js +1 -1
  136. package/dist/{Timestamp-DrWwVQBL.js → Timestamp-DUoP9ari.js} +1 -1
  137. package/dist/ToggleButton/index.d.ts +1 -1
  138. package/dist/Token/index.d.ts +1 -1
  139. package/dist/Token/index.js +1 -1
  140. package/dist/{Token-CV2J94bn.js → Token-C4KD0fZD.js} +1 -1
  141. package/dist/Tokenizer/index.js +1 -1
  142. package/dist/{Tokenizer-DF9r4hTW.js → Tokenizer-BA8sTMPZ.js} +3 -3
  143. package/dist/Toolbar/index.d.ts +1 -1
  144. package/dist/Tooltip/index.d.ts +1 -1
  145. package/dist/TopNav/index.d.ts +1 -1
  146. package/dist/TopNav/index.js +1 -1
  147. package/dist/{TopNav-BH_s3uap.js → TopNav-CZokS7E_.js} +57 -31
  148. package/dist/TreeList/index.js +1 -1
  149. package/dist/{TreeList-D9cR-w7r.js → TreeList-CIbAGOMf.js} +1 -1
  150. package/dist/Typeahead/index.js +1 -1
  151. package/dist/{Typeahead-s4DC1Qem.js → Typeahead-DIw-K4aa.js} +3 -3
  152. package/dist/composables/index.d.ts +3 -2
  153. package/dist/composables/index.js +5 -2
  154. package/dist/composables-CVfjp9h4.js +502 -0
  155. package/dist/context-BjNya0v8.js +19 -0
  156. package/dist/context-Cfjh8te1.js +29 -0
  157. package/dist/{context-BshXcNYX.js → context-D6ECRdc5.js} +84 -0
  158. package/dist/index-1uRMrk63.d.ts +54 -0
  159. package/dist/{index-CsJpQElv.d.ts → index-2u4l3wq8.d.ts} +1 -1
  160. package/dist/{index-BlWLperN.d.ts → index-4FM5lQdV.d.ts} +1 -1
  161. package/dist/index-Be1czg3M.d.ts +167 -0
  162. package/dist/{index-Dbmgcm8a.d.ts → index-BeR-1LgF.d.ts} +2 -0
  163. package/dist/index-BrJzFA5X.d.ts +38 -0
  164. package/dist/{index-BDZCJ9ri.d.ts → index-BuubzuE8.d.ts} +2 -2
  165. package/dist/index-By2mSzUA.d.ts +67 -0
  166. package/dist/{index-BkIgRYGz.d.ts → index-C5p2NeCr.d.ts} +2 -2
  167. package/dist/{index-AkMWQ97a.d.ts → index-C6RecznD.d.ts} +1 -1
  168. package/dist/{index-BSRk8MFK.d.ts → index-C8wDPDcP.d.ts} +1 -1
  169. package/dist/index-CDdRQQF3.d.ts +170 -0
  170. package/dist/index-COqjznX0.d.ts +47 -0
  171. package/dist/{index-g03bmR4K.d.ts → index-CT8KEpec.d.ts} +2 -2
  172. package/dist/{index-Bc0dgVM5.d.ts → index-CTolyeii.d.ts} +4 -4
  173. package/dist/index-CVn0GBdB.d.ts +115 -0
  174. package/dist/index-CX97hlld.d.ts +158 -0
  175. package/dist/index-CjtAH60j.d.ts +38 -0
  176. package/dist/{index-5R_pi3eT.d.ts → index-D-ZuubCK.d.ts} +3 -3
  177. package/dist/index-DA52oIdw.d.ts +171 -0
  178. package/dist/{index-D3V7yRUP.d.ts → index-DGNqi2za.d.ts} +1 -1
  179. package/dist/{index-CCA4R0Mf.d.ts → index-DT9S92sh.d.ts} +31 -6
  180. package/dist/{index-CR6sUmRT.d.ts → index-DXSs3rwa.d.ts} +3 -107
  181. package/dist/{index-CNcQmDrK.d.ts → index-DYChvBOM.d.ts} +42 -0
  182. package/dist/{index-CQ9F1f_F.d.ts → index-Df2YvC8o.d.ts} +297 -125
  183. package/dist/{index--dh0s8Li.d.ts → index-DfgHJE7H.d.ts} +1 -1
  184. package/dist/{index-BnNh5Iml.d.ts → index-SMh42NI8.d.ts} +99 -2
  185. package/dist/{index-12ObcW99.d.ts → index-ZJyk8RtQ.d.ts} +1 -1
  186. package/dist/{index-Q4gqBSIZ.d.ts → index-fa72tWIU.d.ts} +1 -1
  187. package/dist/{index-BhYFxnjV.d.ts → index-kaKBOZSU.d.ts} +2 -2
  188. package/dist/index-nKlTsNfV.d.ts +42 -0
  189. package/dist/index.d.ts +75 -63
  190. package/dist/index.js +108 -89
  191. package/dist/locale/index.d.ts +1 -1
  192. package/dist/locale/index.js +1 -1
  193. package/dist/size-BuTzpgnR.d.ts +14 -0
  194. package/dist/size-xcIqExkS.js +79 -0
  195. package/dist/{index-Bovw9_8d.d.ts → types-Db3Owy8Q.d.ts} +1 -36
  196. package/dist/types-JktRxujg.d.ts +107 -0
  197. package/dist/useAppShellMobile-DTsyuAJ4.js +19 -0
  198. package/dist/useClickableContainer-DyNpnSEa.js +112 -0
  199. package/dist/useResizable-CeESZS1v.d.ts +72 -0
  200. package/dist/useScrollableArea-DDk_CluT.js +172 -0
  201. package/package.json +49 -1
  202. package/styles/app-shell.css +151 -0
  203. package/styles/aspect-ratio.css +49 -0
  204. package/styles/card.css +5 -1
  205. package/styles/clickable-card.css +101 -0
  206. package/styles/collapsible.css +37 -0
  207. package/styles/command-palette.css +183 -0
  208. package/styles/complex-selector.css +114 -0
  209. package/styles/field.css +12 -0
  210. package/styles/form-layout.css +31 -0
  211. package/styles/heading.css +19 -17
  212. package/styles/layout.css +280 -0
  213. package/styles/resize-handle.css +128 -0
  214. package/styles/scrollable-area.css +50 -0
  215. package/styles/section.css +60 -0
  216. package/styles/side-nav.css +26 -0
  217. package/styles/stepper.css +357 -0
  218. package/styles/tab-menu.css +91 -0
  219. package/styles.css +12 -0
  220. package/dist/Collapsible-BYg9soTk.js +0 -102
  221. package/dist/TabList-LV1U4ZD6.js +0 -184
  222. package/dist/composables-Dq9RS33w.js +0 -111
  223. package/dist/index-TnaIHsCS.d.ts +0 -87
@@ -0,0 +1,502 @@
1
+ import { t as useMediaQuery } from "./useMediaQuery-GMmgp28-.js";
2
+ import { computed, onBeforeUnmount, onMounted, reactive, ref, toValue, watch } from "vue";
3
+ //#region src/composables/useControllableState.ts
4
+ /**
5
+ * 受控或自己管的 v-model。
6
+ *
7
+ * Astryx 没有同名 hook。各组件原来各自判断「外面传了值就听外面的,没传就自己记」,
8
+ * 这里收成一个函数,方便以后的 v-model 共用。
9
+ */
10
+ function useControllableState(options) {
11
+ const { modelValue, onChange } = options;
12
+ const controlled = modelValue.value !== void 0;
13
+ const local = ref(toValue(options.defaultValue));
14
+ const isControlled = computed(() => controlled);
15
+ const value = computed(() => controlled ? modelValue.value : local.value);
16
+ function setValue(next) {
17
+ if (Object.is(value.value, next)) return;
18
+ if (controlled) modelValue.value = next;
19
+ else local.value = next;
20
+ onChange?.(next);
21
+ }
22
+ return {
23
+ isControlled,
24
+ setValue,
25
+ value
26
+ };
27
+ }
28
+ //#endregion
29
+ //#region src/composables/useResizable.ts
30
+ const DEFAULT_SIZE = 250;
31
+ const DEFAULT_MIN = 50;
32
+ const DEFAULT_COLLAPSED_SIZE = 40;
33
+ const SNAP_DISTANCE = 8;
34
+ const UNMEASURED_BASIS = 1200;
35
+ const STORAGE_PREFIX = "astryx-resizable:";
36
+ function percent(value, options) {
37
+ return {
38
+ type: "percent",
39
+ value,
40
+ ...options
41
+ };
42
+ }
43
+ function readBasis(container, direction) {
44
+ if (container) {
45
+ const px = direction === "horizontal" ? container.clientWidth : container.clientHeight;
46
+ if (px > 0) return {
47
+ px,
48
+ measured: true
49
+ };
50
+ return {
51
+ px: UNMEASURED_BASIS,
52
+ measured: false
53
+ };
54
+ }
55
+ if (typeof window === "undefined") return {
56
+ px: UNMEASURED_BASIS,
57
+ measured: false
58
+ };
59
+ const px = direction === "horizontal" ? window.innerWidth : window.innerHeight;
60
+ return {
61
+ px: px > 0 ? px : UNMEASURED_BASIS,
62
+ measured: px > 0
63
+ };
64
+ }
65
+ function parseSize(value, basis, fallback) {
66
+ if (value == null) return fallback;
67
+ if (typeof value === "number") return value;
68
+ if (typeof value === "string") {
69
+ const text = value.trim();
70
+ if (text.endsWith("%")) return Number(text.slice(0, -1)) / 100 * basis;
71
+ if (text.endsWith("px")) return Number(text.slice(0, -2));
72
+ const asNumber = Number(text);
73
+ return Number.isFinite(asNumber) ? asNumber : fallback;
74
+ }
75
+ if (value.type === "pixel") return value.value;
76
+ const px = value.value / 100 * basis;
77
+ if (value.min) return Math.max(px, value.min.value);
78
+ if (value.max) return Math.min(px, value.max.value);
79
+ return px;
80
+ }
81
+ function clampSize(size, min, max, snaps) {
82
+ const clamped = Math.min(max, Math.max(min, size));
83
+ if (snaps.length === 0) return clamped;
84
+ let nearest = snaps[0] ?? clamped;
85
+ let nearestDist = Math.abs(clamped - nearest);
86
+ for (let index = 1; index < snaps.length; index += 1) {
87
+ const snap = snaps[index] ?? nearest;
88
+ const dist = Math.abs(clamped - snap);
89
+ if (dist < nearestDist) {
90
+ nearest = snap;
91
+ nearestDist = dist;
92
+ }
93
+ }
94
+ if (nearestDist > SNAP_DISTANCE) return clamped;
95
+ return Math.min(max, Math.max(min, nearest));
96
+ }
97
+ function loadPersistedState(key) {
98
+ if (typeof window === "undefined") return null;
99
+ try {
100
+ const raw = localStorage.getItem(STORAGE_PREFIX + key);
101
+ if (raw == null) return null;
102
+ const parsed = JSON.parse(raw);
103
+ if (typeof parsed === "number" && Number.isFinite(parsed)) return parsed === 0 ? {
104
+ size: null,
105
+ isCollapsed: true
106
+ } : {
107
+ size: parsed,
108
+ isCollapsed: null
109
+ };
110
+ if (typeof parsed === "object" && parsed != null) {
111
+ const record = parsed;
112
+ const hasSize = typeof record.size === "number" && Number.isFinite(record.size) && record.size > 0;
113
+ if (hasSize || record.isCollapsed === true) return {
114
+ size: hasSize ? record.size : null,
115
+ isCollapsed: record.isCollapsed === true
116
+ };
117
+ }
118
+ } catch {
119
+ return null;
120
+ }
121
+ return null;
122
+ }
123
+ function useSingleRegion(options, cascade) {
124
+ const direction = options.direction ?? "horizontal";
125
+ const collapsible = options.collapsible ?? false;
126
+ const collapsedSize = options.collapsedSize ?? DEFAULT_COLLAPSED_SIZE;
127
+ const snaps = options.snaps ?? [];
128
+ const size = ref(DEFAULT_SIZE);
129
+ const expandedSize = ref(DEFAULT_SIZE);
130
+ const isCollapsed = ref(false);
131
+ const basisMeasured = ref(true);
132
+ const controlledCollapse = computed(() => options.isCollapsed);
133
+ let origin = DEFAULT_SIZE;
134
+ let settledDefault = false;
135
+ let dragging = false;
136
+ let dragLimits = null;
137
+ function currentBasis() {
138
+ return readBasis(options.containerRef?.value, direction);
139
+ }
140
+ function limits() {
141
+ const basis = currentBasis();
142
+ basisMeasured.value = basis.measured || options.containerRef == null;
143
+ return {
144
+ min: parseSize(options.minSize, basis.px, DEFAULT_MIN),
145
+ max: parseSize(options.maxSize, basis.px, Number.POSITIVE_INFINITY)
146
+ };
147
+ }
148
+ function applySize(next, collapsed) {
149
+ const { min, max } = limits();
150
+ if (collapsed && collapsible) {
151
+ isCollapsed.value = true;
152
+ size.value = 0;
153
+ return;
154
+ }
155
+ const clamped = clampSize(next, min, max, snaps);
156
+ isCollapsed.value = false;
157
+ size.value = clamped;
158
+ expandedSize.value = clamped;
159
+ }
160
+ function restore() {
161
+ const basis = currentBasis();
162
+ const initial = parseSize(options.defaultSize, basis.px, DEFAULT_SIZE);
163
+ const saved = options.autoSaveId ? loadPersistedState(options.autoSaveId) : null;
164
+ const collapsed = controlledCollapse.value ?? saved?.isCollapsed ?? (collapsible && options.defaultIsCollapsed === true);
165
+ const starting = saved?.size ?? initial;
166
+ if (options.containerRef != null && !basis.measured) {
167
+ basisMeasured.value = false;
168
+ applySize(starting, Boolean(collapsed));
169
+ return;
170
+ }
171
+ settledDefault = true;
172
+ basisMeasured.value = true;
173
+ expandedSize.value = starting;
174
+ applySize(starting, Boolean(collapsed));
175
+ }
176
+ restore();
177
+ function persist() {
178
+ if (!options.autoSaveId || !basisMeasured.value) return;
179
+ try {
180
+ localStorage.setItem(STORAGE_PREFIX + options.autoSaveId, JSON.stringify({
181
+ size: expandedSize.value,
182
+ isCollapsed: isCollapsed.value
183
+ }));
184
+ } catch {}
185
+ }
186
+ function setCollapsed(next) {
187
+ if (!collapsible && next) return;
188
+ if (options.isCollapsed != null) {
189
+ options.onCollapseChange?.(next);
190
+ return;
191
+ }
192
+ applySize(next ? 0 : expandedSize.value, next);
193
+ options.onCollapseChange?.(next);
194
+ persist();
195
+ cascade?.settle();
196
+ }
197
+ function resize(next) {
198
+ applySize(next, false);
199
+ cascade?.settle();
200
+ options.onSizeChange?.(size.value);
201
+ persist();
202
+ }
203
+ function paintDrag(next, collapsed) {
204
+ const bounds = dragLimits ?? limits();
205
+ if (collapsed && collapsible) {
206
+ isCollapsed.value = true;
207
+ size.value = 0;
208
+ return;
209
+ }
210
+ const clamped = clampSize(next, bounds.min, bounds.max, snaps);
211
+ isCollapsed.value = false;
212
+ size.value = clamped;
213
+ expandedSize.value = clamped;
214
+ }
215
+ function onResizeStart() {
216
+ dragging = true;
217
+ origin = isCollapsed.value ? 0 : size.value;
218
+ dragLimits = limits();
219
+ }
220
+ function onResizeMove(delta) {
221
+ const raw = origin + delta;
222
+ if (collapsible && raw < collapsedSize) {
223
+ if (!isCollapsed.value) {
224
+ paintDrag(0, true);
225
+ options.onCollapseChange?.(true);
226
+ options.onSizeChange?.(0);
227
+ }
228
+ return;
229
+ }
230
+ const wasCollapsed = isCollapsed.value;
231
+ paintDrag(raw, false);
232
+ if (wasCollapsed) options.onCollapseChange?.(false);
233
+ options.onSizeChange?.(size.value);
234
+ }
235
+ function onResizeEnd() {
236
+ dragging = false;
237
+ dragLimits = null;
238
+ persist();
239
+ cascade?.settle();
240
+ }
241
+ function applyDisplay(next) {
242
+ if (isCollapsed.value) return;
243
+ size.value = next;
244
+ }
245
+ const props = computed(() => {
246
+ const { min, max } = limits();
247
+ return {
248
+ _size: size.value,
249
+ _isCollapsed: isCollapsed.value,
250
+ _onResizeStart: onResizeStart,
251
+ _onResizeMove: onResizeMove,
252
+ _onResizeEnd: onResizeEnd,
253
+ _onResizeCancel: onResizeEnd,
254
+ _minSizePx: min,
255
+ _maxSizePx: max,
256
+ _snaps: snaps,
257
+ _collapsedSize: collapsedSize,
258
+ _collapsible: collapsible,
259
+ _direction: direction,
260
+ _isResizableProps: true
261
+ };
262
+ });
263
+ function measureDefault() {
264
+ if (settledDefault || options.containerRef == null) return;
265
+ const basis = currentBasis();
266
+ if (!basis.measured) return;
267
+ settledDefault = true;
268
+ basisMeasured.value = true;
269
+ if (options.autoSaveId && loadPersistedState(options.autoSaveId)) return;
270
+ const initial = parseSize(options.defaultSize, basis.px, size.value);
271
+ expandedSize.value = initial;
272
+ if (!isCollapsed.value) applySize(initial, false);
273
+ cascade?.settle();
274
+ }
275
+ let observer;
276
+ onMounted(() => {
277
+ measureDefault();
278
+ const element = options.containerRef?.value;
279
+ if (element == null || typeof ResizeObserver === "undefined") return;
280
+ observer = new ResizeObserver(() => measureDefault());
281
+ observer.observe(element);
282
+ });
283
+ onBeforeUnmount(() => observer?.disconnect());
284
+ watch(controlledCollapse, (next) => {
285
+ if (next != null) {
286
+ applySize(next ? 0 : expandedSize.value, next);
287
+ cascade?.settle();
288
+ }
289
+ });
290
+ cascade?.register({
291
+ preferred: () => expandedSize.value,
292
+ isCollapsed: () => isCollapsed.value,
293
+ min: () => limits().min,
294
+ isDragging: () => dragging,
295
+ applyDisplay
296
+ });
297
+ return reactive({
298
+ size,
299
+ isCollapsed,
300
+ collapse: () => setCollapsed(true),
301
+ expand: () => setCollapsed(false),
302
+ resize,
303
+ props
304
+ });
305
+ }
306
+ function useResizable(options) {
307
+ if ("regions" in options && options.regions != null) {
308
+ const direction = options.direction ?? "horizontal";
309
+ const entries = [];
310
+ let ready = false;
311
+ function reflow() {
312
+ if (!ready || entries.length === 0 || !entries.some((entry) => entry.order != null)) return;
313
+ if (entries.some((entry) => entry.api.isDragging())) return;
314
+ const element = options.containerRef?.value;
315
+ if (element == null) return;
316
+ const basis = readBasis(element, direction);
317
+ if (!basis.measured) return;
318
+ const active = entries.filter((entry) => !entry.api.isCollapsed());
319
+ const sizes = new Map(active.map((entry) => [entry.key, entry.api.preferred()]));
320
+ let overflow = active.reduce((sum, entry) => sum + entry.api.preferred(), 0) - basis.px;
321
+ if (overflow > 0) {
322
+ const order = [...active].sort((left, right) => {
323
+ return (left.order ?? Number.POSITIVE_INFINITY) - (right.order ?? Number.POSITIVE_INFINITY) || entries.indexOf(left) - entries.indexOf(right);
324
+ });
325
+ for (const entry of order) {
326
+ if (overflow <= 0) break;
327
+ const current = sizes.get(entry.key) ?? 0;
328
+ const room = Math.max(0, current - entry.api.min());
329
+ const take = Math.min(room, overflow);
330
+ sizes.set(entry.key, current - take);
331
+ overflow -= take;
332
+ }
333
+ }
334
+ for (const entry of active) {
335
+ const next = sizes.get(entry.key);
336
+ if (next != null) entry.api.applyDisplay(next);
337
+ }
338
+ }
339
+ const regions = {};
340
+ for (const key of Object.keys(options.regions)) {
341
+ const config = options.regions[key];
342
+ regions[key] = useSingleRegion({
343
+ ...config,
344
+ direction,
345
+ containerRef: options.containerRef,
346
+ autoSaveId: options.autoSaveId ? `${options.autoSaveId}:${key}` : void 0
347
+ }, {
348
+ register: (api) => {
349
+ entries.push({
350
+ key,
351
+ order: config?.shrinkOrder,
352
+ api
353
+ });
354
+ },
355
+ settle: reflow
356
+ });
357
+ }
358
+ ready = true;
359
+ let observer;
360
+ onMounted(() => {
361
+ reflow();
362
+ const element = options.containerRef?.value;
363
+ if (element == null || typeof ResizeObserver === "undefined") return;
364
+ observer = new ResizeObserver(() => reflow());
365
+ observer.observe(element);
366
+ });
367
+ onBeforeUnmount(() => observer?.disconnect());
368
+ return regions;
369
+ }
370
+ return useSingleRegion(options);
371
+ }
372
+ //#endregion
373
+ //#region src/composables/useScrollOverflow.ts
374
+ /**
375
+ * 观察一个横向滚动容器,报告起始边和结束边有没有被挡住。
376
+ * 容差 1px,滚动和尺寸变化都会重新量。
377
+ */
378
+ function useScrollOverflow() {
379
+ const element = ref(null);
380
+ const overflowStart = ref(false);
381
+ const overflowEnd = ref(false);
382
+ const hasOverflow = ref(false);
383
+ let observer;
384
+ function measure() {
385
+ const node = element.value;
386
+ if (node == null) return;
387
+ const tolerance = 1;
388
+ const maxScroll = node.scrollWidth - node.clientWidth;
389
+ const nextStart = Math.abs(node.scrollLeft) > tolerance;
390
+ const nextEnd = Math.abs(node.scrollLeft) < maxScroll - tolerance;
391
+ const nextHas = node.scrollWidth > node.clientWidth + tolerance;
392
+ overflowStart.value = nextStart;
393
+ overflowEnd.value = nextEnd;
394
+ hasOverflow.value = nextHas;
395
+ }
396
+ function scrollRef(node) {
397
+ element.value?.removeEventListener("scroll", measure);
398
+ observer?.disconnect();
399
+ element.value = node;
400
+ if (node == null) return;
401
+ node.addEventListener("scroll", measure, { passive: true });
402
+ if (typeof ResizeObserver !== "undefined") {
403
+ observer = new ResizeObserver(measure);
404
+ observer.observe(node);
405
+ }
406
+ measure();
407
+ }
408
+ onBeforeUnmount(() => {
409
+ element.value?.removeEventListener("scroll", measure);
410
+ observer?.disconnect();
411
+ });
412
+ return {
413
+ scrollRef,
414
+ overflowStart,
415
+ overflowEnd,
416
+ hasOverflow
417
+ };
418
+ }
419
+ //#endregion
420
+ //#region src/composables/useStreamingText.ts
421
+ const CHARS_PER_TICK = {
422
+ natural: 10,
423
+ fast: 4,
424
+ instant: Number.POSITIVE_INFINITY
425
+ };
426
+ const FALLBACK_DURATION_MS = 95;
427
+ function parseCssDuration(value) {
428
+ const milliseconds = /^([\d.]+)ms$/.exec(value.trim());
429
+ if (milliseconds?.[1] != null) return Number(milliseconds[1]);
430
+ const seconds = /^([\d.]+)s$/.exec(value.trim());
431
+ if (seconds?.[1] != null) return Number(seconds[1]) * 1e3;
432
+ return null;
433
+ }
434
+ function motionDuration() {
435
+ if (typeof document === "undefined") return FALLBACK_DURATION_MS;
436
+ return parseCssDuration(getComputedStyle(document.documentElement).getPropertyValue("--astryx-duration-fast-min")) ?? FALLBACK_DURATION_MS;
437
+ }
438
+ function tickInterval(speed) {
439
+ if (speed === "instant") return 0;
440
+ const duration = motionDuration();
441
+ const tick = speed === "fast" ? duration / 20 : duration / 10;
442
+ return Math.max(4, Math.round(tick));
443
+ }
444
+ const graphemeSegmenter = typeof Intl.Segmenter === "function" ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
445
+ function isLowSurrogate(codeUnit) {
446
+ return codeUnit >= 56320 && codeUnit <= 57343;
447
+ }
448
+ /**
449
+ * Move `offset` back to the start of the grapheme it lands inside, so a slice
450
+ * never cuts a surrogate pair, a flag, or a ZWJ sequence in half.
451
+ */
452
+ function snapToGraphemeBoundary(text, offset) {
453
+ if (offset <= 0 || offset >= text.length) return offset;
454
+ if (graphemeSegmenter != null) return graphemeSegmenter.segment(text).containing(offset)?.index ?? offset;
455
+ return isLowSurrogate(text.charCodeAt(offset)) ? offset - 1 : offset;
456
+ }
457
+ /**
458
+ * Smooth a burst of streamed text into a steady reveal.
459
+ * While `isStreaming` is false, or the user prefers reduced motion, the full
460
+ * source is returned. The reveal steps by UTF-16 units and then snaps back to
461
+ * a grapheme boundary.
462
+ */
463
+ function useStreamingText(targetText, isStreaming = false, options) {
464
+ const displayedLen = ref(0);
465
+ const prefersReducedMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
466
+ const target = computed(() => toValue(targetText));
467
+ const streaming = computed(() => toValue(isStreaming));
468
+ const speed = computed(() => toValue(options)?.speed ?? "natural");
469
+ const instant = computed(() => !streaming.value || speed.value === "instant" || prefersReducedMotion.value);
470
+ watch(target, (next, previous) => {
471
+ if (next.length === 0 && (previous?.length ?? 0) > 0) displayedLen.value = 0;
472
+ });
473
+ watch(streaming, (next) => {
474
+ if (!next) displayedLen.value = target.value.length;
475
+ });
476
+ watch(instant, (isInstant, _, onCleanup) => {
477
+ if (isInstant) return;
478
+ let frame = 0;
479
+ let lastTick = 0;
480
+ const tick = (now) => {
481
+ const interval = tickInterval(speed.value);
482
+ if (now - lastTick >= interval) {
483
+ lastTick = now;
484
+ const goal = target.value.length;
485
+ if (displayedLen.value < goal) {
486
+ const step = CHARS_PER_TICK[speed.value];
487
+ displayedLen.value = Math.min(displayedLen.value + step, goal);
488
+ }
489
+ }
490
+ frame = requestAnimationFrame(tick);
491
+ };
492
+ frame = requestAnimationFrame(tick);
493
+ onCleanup(() => cancelAnimationFrame(frame));
494
+ }, { immediate: true });
495
+ return computed(() => {
496
+ const text = target.value;
497
+ if (instant.value) return text;
498
+ return text.slice(0, snapToGraphemeBoundary(text, displayedLen.value));
499
+ });
500
+ }
501
+ //#endregion
502
+ export { useResizable as a, percent as i, useStreamingText as n, useControllableState as o, useScrollOverflow as r, snapToGraphemeBoundary as t };
@@ -0,0 +1,19 @@
1
+ import { computed, inject, ref } from "vue";
2
+ //#region src/SideNav/context.ts
3
+ const sideNavRenderModeKey = Symbol("astryx-side-nav-render-mode");
4
+ const defaultRenderMode = computed(() => "default");
5
+ function useSideNavRenderMode() {
6
+ return inject(sideNavRenderModeKey, defaultRenderMode);
7
+ }
8
+ const sideNavCollapseKey = Symbol("astryx-side-nav-collapse");
9
+ const fallbackCollapse = {
10
+ isCollapsed: ref(false),
11
+ isCollapsible: ref(false),
12
+ navId: "",
13
+ toggle: () => {}
14
+ };
15
+ function useSideNavCollapse() {
16
+ return inject(sideNavCollapseKey, fallbackCollapse);
17
+ }
18
+ //#endregion
19
+ export { useSideNavRenderMode as i, sideNavRenderModeKey as n, useSideNavCollapse as r, sideNavCollapseKey as t };
@@ -0,0 +1,29 @@
1
+ import { computed, inject } from "vue";
2
+ //#region src/FormLayout/context.ts
3
+ const formLayoutKey = Symbol("astryx-form-layout");
4
+ function useFormLayout() {
5
+ return inject(formLayoutKey, computed(() => null));
6
+ }
7
+ /**
8
+ * 没有 FormLayout 时保持原来的 aria-required。
9
+ * 有默认必填时,没标 optional 的字段也要报必填,但不写原生 required。
10
+ * 两个标记同时出现时,optional 优先。
11
+ */
12
+ function ariaRequired(isRequired, isOptional, optionality) {
13
+ if (isOptional) return void 0;
14
+ if (optionality == null) return isRequired ? true : void 0;
15
+ if (optionality === "required" || isRequired) return true;
16
+ }
17
+ function useAriaRequired(props) {
18
+ const layout = useFormLayout();
19
+ return computed(() => ariaRequired(props.isRequired, props.isOptional, layout.value?.defaultOptionality));
20
+ }
21
+ function showsOptionalIndicator(isOptional, _isRequired, optionality) {
22
+ return Boolean(isOptional) && optionality !== "optional";
23
+ }
24
+ function showsRequiredIndicator(isRequired, isOptional, optionality) {
25
+ if (isOptional) return false;
26
+ return Boolean(isRequired) && optionality !== "required";
27
+ }
28
+ //#endregion
29
+ export { useFormLayout as a, useAriaRequired as i, showsOptionalIndicator as n, showsRequiredIndicator as r, formLayoutKey as t };
@@ -73,6 +73,36 @@ const citationMessages = {
73
73
  "zh-CN": { label: (number, title) => `引用 ${number}:${title}` }
74
74
  };
75
75
  //#endregion
76
+ //#region src/locale/messages/command-palette.ts
77
+ const commandPaletteMessages = {
78
+ "en": {
79
+ label: "Command palette",
80
+ emptySearch: "No results",
81
+ emptyBootstrap: "Type to search",
82
+ placeholder: "Search…",
83
+ listLabel: "Commands",
84
+ loading: "Loading",
85
+ noResultsFor: (query) => `No results for ${query}`,
86
+ resultCount: (count) => `${count} ${count === 1 ? "result" : "results"}`,
87
+ navigate: "Navigate",
88
+ select: "Select",
89
+ close: "Close"
90
+ },
91
+ "zh-CN": {
92
+ label: "命令面板",
93
+ emptySearch: "没有结果",
94
+ emptyBootstrap: "输入以搜索",
95
+ placeholder: "搜索…",
96
+ listLabel: "命令",
97
+ loading: "正在加载",
98
+ noResultsFor: (query) => `没有与 ${query} 匹配的结果`,
99
+ resultCount: (count) => `${count} 个结果`,
100
+ navigate: "移动",
101
+ select: "选择",
102
+ close: "关闭"
103
+ }
104
+ };
105
+ //#endregion
76
106
  //#region src/locale/messages/shared.ts
77
107
  function clearLabel(label, fallback, prefix) {
78
108
  return label != null && label !== "" ? `${prefix}${label}` : fallback;
@@ -150,6 +180,22 @@ const fileInputMessages = {
150
180
  }
151
181
  };
152
182
  //#endregion
183
+ //#region src/locale/messages/layout.ts
184
+ const layoutMessages = {
185
+ "en": {
186
+ skipToContent: "Skip to content",
187
+ resizeHandle: "Resize handle",
188
+ collapsed: "Collapsed",
189
+ mobileNavigation: "Navigation"
190
+ },
191
+ "zh-CN": {
192
+ skipToContent: "跳到正文",
193
+ resizeHandle: "拖拽分隔条",
194
+ collapsed: "已收起",
195
+ mobileNavigation: "导航"
196
+ }
197
+ };
198
+ //#endregion
153
199
  //#region src/locale/messages/markdown.ts
154
200
  const markdownMessages = {
155
201
  "en": {
@@ -209,6 +255,7 @@ const navMessages = {
209
255
  collapseSidebar: "Collapse sidebar",
210
256
  expandSidebar: "Expand sidebar",
211
257
  openMenu: "Open menu",
258
+ openNavigation: "Open navigation",
212
259
  close: "Close",
213
260
  more: "More",
214
261
  moreItems: (count) => `${count} more`,
@@ -223,6 +270,7 @@ const navMessages = {
223
270
  collapseSidebar: "收起侧边栏",
224
271
  expandSidebar: "展开侧边栏",
225
272
  openMenu: "打开菜单",
273
+ openNavigation: "打开导航",
226
274
  close: "关闭",
227
275
  more: "更多",
228
276
  moreItems: (count) => `还有 ${count} 项`,
@@ -286,6 +334,36 @@ const selectorMessages = {
286
334
  }
287
335
  };
288
336
  //#endregion
337
+ //#region src/locale/messages/stepper.ts
338
+ const stepperMessages = {
339
+ "en": {
340
+ progress: "Progress",
341
+ optional: "Optional",
342
+ previous: "Previous step",
343
+ next: "Next step",
344
+ goToStep: (step) => `Go to step ${step}`,
345
+ goToStepWithStatus: (step, status) => `Go to step ${step}, ${status}`,
346
+ status: {
347
+ completed: "Completed",
348
+ warning: "Warning",
349
+ error: "Error"
350
+ }
351
+ },
352
+ "zh-CN": {
353
+ progress: "进度",
354
+ optional: "可选",
355
+ previous: "上一步",
356
+ next: "下一步",
357
+ goToStep: (step) => `转到第 ${step} 步`,
358
+ goToStepWithStatus: (step, status) => `转到第 ${step} 步,${status}`,
359
+ status: {
360
+ completed: "已完成",
361
+ warning: "警告",
362
+ error: "错误"
363
+ }
364
+ }
365
+ };
366
+ //#endregion
289
367
  //#region src/locale/messages/table.ts
290
368
  const tableMessages = {
291
369
  "en": {
@@ -444,10 +522,12 @@ const astryxMessages = {
444
522
  calendar: calendarMessages.en,
445
523
  chat: chatMessages.en,
446
524
  citation: citationMessages.en,
525
+ commandPalette: commandPaletteMessages.en,
447
526
  dateInput: dateInputMessages.en,
448
527
  dateRangeInput: dateRangeInputMessages.en,
449
528
  dateTimeInput: dateTimeInputMessages.en,
450
529
  fileInput: fileInputMessages.en,
530
+ layout: layoutMessages.en,
451
531
  markdown: markdownMessages.en,
452
532
  metadataList: metadataListMessages.en,
453
533
  multiSelector: multiSelectorMessages.en,
@@ -455,6 +535,7 @@ const astryxMessages = {
455
535
  numberInput: numberInputMessages.en,
456
536
  pagination: paginationMessages.en,
457
537
  selector: selectorMessages.en,
538
+ stepper: stepperMessages.en,
458
539
  table: tableMessages.en,
459
540
  thumbnail: thumbnailMessages.en,
460
541
  timeInput: timeInputMessages.en,
@@ -468,10 +549,12 @@ const astryxMessages = {
468
549
  calendar: calendarMessages["zh-CN"],
469
550
  chat: chatMessages["zh-CN"],
470
551
  citation: citationMessages["zh-CN"],
552
+ commandPalette: commandPaletteMessages["zh-CN"],
471
553
  dateInput: dateInputMessages["zh-CN"],
472
554
  dateRangeInput: dateRangeInputMessages["zh-CN"],
473
555
  dateTimeInput: dateTimeInputMessages["zh-CN"],
474
556
  fileInput: fileInputMessages["zh-CN"],
557
+ layout: layoutMessages["zh-CN"],
475
558
  markdown: markdownMessages["zh-CN"],
476
559
  metadataList: metadataListMessages["zh-CN"],
477
560
  multiSelector: multiSelectorMessages["zh-CN"],
@@ -479,6 +562,7 @@ const astryxMessages = {
479
562
  numberInput: numberInputMessages["zh-CN"],
480
563
  pagination: paginationMessages["zh-CN"],
481
564
  selector: selectorMessages["zh-CN"],
565
+ stepper: stepperMessages["zh-CN"],
482
566
  table: tableMessages["zh-CN"],
483
567
  thumbnail: thumbnailMessages["zh-CN"],
484
568
  timeInput: timeInputMessages["zh-CN"],