@astryx-vue/core 0.1.0 → 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.
- package/README.md +1 -1
- package/dist/AppShell/index.d.ts +2 -0
- package/dist/AppShell/index.js +2 -0
- package/dist/AppShell-b0PWt9Fz.js +249 -0
- package/dist/AspectRatio/index.d.ts +2 -0
- package/dist/AspectRatio/index.js +2 -0
- package/dist/AspectRatio-Bij7e-tq.js +40 -0
- package/dist/AvatarGroup/index.d.ts +1 -1
- package/dist/Banner/index.d.ts +1 -1
- package/dist/BottomSheet/index.d.ts +1 -1
- package/dist/Button/index.d.ts +1 -1
- package/dist/ButtonGroup/index.d.ts +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/{Calendar-DpYFXwgb.js → Calendar-CYhGDT6f.js} +2 -1
- package/dist/Chat/index.js +1 -1
- package/dist/{Chat-Bfd-YPAK.js → Chat-C1aWl5V3.js} +2 -2
- package/dist/CheckboxInput/index.d.ts +1 -1
- package/dist/CheckboxInput/index.js +1 -1
- package/dist/{CheckboxInput-C86o3XoG.js → CheckboxInput-CMsEE1_4.js} +4 -2
- package/dist/CheckboxList/index.d.ts +2 -0
- package/dist/CheckboxList/index.js +2 -0
- package/dist/CheckboxList-EsIEXjK_.js +174 -0
- package/dist/Citation/index.js +1 -1
- package/dist/{Citation-DaDd1teb.js → Citation-C1X0Rde8.js} +2 -2
- package/dist/ClickableCard/index.d.ts +2 -0
- package/dist/ClickableCard/index.js +2 -0
- package/dist/ClickableCard-Bhds4RRe.js +112 -0
- package/dist/Code/index.js +1 -1
- package/dist/{CodeBlock-CK-NWM_1.js → CodeBlock-BQdooQy2.js} +1 -1
- package/dist/Collapsible/index.d.ts +2 -2
- package/dist/Collapsible/index.js +2 -2
- package/dist/Collapsible-BS9ctCQV.js +192 -0
- package/dist/CommandPalette/index.d.ts +2 -0
- package/dist/CommandPalette/index.js +2 -0
- package/dist/CommandPalette-u5h_E05P.js +489 -0
- package/dist/ComplexSelector/index.d.ts +2 -0
- package/dist/ComplexSelector/index.js +2 -0
- package/dist/ComplexSelector-BHmGWml0.js +293 -0
- package/dist/ContextMenu/index.d.ts +1 -1
- package/dist/ContextMenu/index.js +1 -1
- package/dist/{ContextMenu-BJh99Exj.js → ContextMenu-dA-ppaRQ.js} +284 -12
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.js +1 -1
- package/dist/{DateInput-zJAdXByM.js → DateInput-D2ErjXYO.js} +18 -10
- package/dist/DateRangeInput/index.d.ts +2 -0
- package/dist/DateRangeInput/index.js +2 -0
- package/dist/DateRangeInput-fmQlr_A7.js +385 -0
- package/dist/DateTimeInput/index.d.ts +2 -0
- package/dist/DateTimeInput/index.js +2 -0
- package/dist/DateTimeInput-Bs1JmcIp.js +196 -0
- package/dist/Divider/index.d.ts +1 -1
- package/dist/DropdownMenu/index.d.ts +1 -1
- package/dist/DropdownMenu/index.js +1 -1
- package/dist/{DropdownMenu-C3j2zaEn.js → DropdownMenu-B0gogrvG.js} +2 -2
- package/dist/Field/index.d.ts +2 -2
- package/dist/Field/index.js +3 -4
- package/dist/{Field-VlTBsIEo.js → Field-8zRxzDHE.js} +11 -3
- package/dist/{FieldLabel-B1NRyQlS.js → FieldLabel-DmmJyX7w.js} +6 -1
- package/dist/FieldStatus/index.d.ts +2 -0
- package/dist/FieldStatus/index.js +2 -0
- package/dist/FileInput/index.d.ts +2 -0
- package/dist/FileInput/index.js +2 -0
- package/dist/FileInput-CmAfOpkA.js +238 -0
- package/dist/FormLayout/index.d.ts +2 -0
- package/dist/FormLayout/index.js +2 -0
- package/dist/FormLayout-D47FjiOq.js +40 -0
- package/dist/HoverCard/index.d.ts +1 -1
- package/dist/{Icon-B6qNgBP9.js → Icon-5MdZQ18k.js} +10 -2
- package/dist/Layout/index.d.ts +2 -0
- package/dist/Layout/index.js +3 -0
- package/dist/Layout-Bed3kP0M.js +56 -0
- package/dist/LayoutPanel-C34uOq3e.js +358 -0
- package/dist/List/index.d.ts +1 -1
- package/dist/Markdown/index.d.ts +1 -1
- package/dist/Markdown/index.js +1 -1
- package/dist/{Markdown-DyKIwAL_.js → Markdown-CwtLr3f_.js} +2 -2
- package/dist/MetadataList/index.d.ts +2 -0
- package/dist/MetadataList/index.js +2 -0
- package/dist/MetadataList-DlXQTLog.js +124 -0
- package/dist/MobileNav/index.d.ts +1 -1
- package/dist/MobileNav/index.js +1 -1
- package/dist/{MobileNavToggle-BK2iRJF-.js → MobileNavToggle-CgQamG6E.js} +19 -12
- package/dist/MoreMenu/index.d.ts +1 -1
- package/dist/MoreMenu/index.js +1 -1
- package/dist/{MoreMenu-BjUsVWWk.js → MoreMenu-BXL6Dqsu.js} +2 -2
- package/dist/MultiSelector/index.d.ts +1 -1
- package/dist/MultiSelector/index.js +1 -1
- package/dist/{MultiSelector-CKTbTj1A.js → MultiSelector-DT8ZccMI.js} +3 -3
- package/dist/NavItem/index.d.ts +1 -1
- package/dist/NavMenu/index.d.ts +1 -1
- package/dist/NumberInput/index.d.ts +1 -1
- package/dist/NumberInput/index.js +1 -1
- package/dist/{NumberInput-DU3_rw7z.js → NumberInput-DspJO6z6.js} +1 -1
- package/dist/OverflowList/index.d.ts +1 -1
- package/dist/OverflowList/index.js +1 -1
- package/dist/{OverflowList-B2T5UtiQ.js → OverflowList-zXg3g6fy.js} +1 -1
- package/dist/Overlay/index.d.ts +1 -1
- package/dist/Pagination/index.js +1 -1
- package/dist/{Pagination-qCgNwwhr.js → Pagination-DXfgMUKJ.js} +2 -2
- package/dist/Popover/index.d.ts +2 -1
- package/dist/Radio/index.d.ts +2 -2
- package/dist/Radio/index.js +2 -2
- package/dist/{Radio-BioQfwHQ.js → RadioGroup-BqjdSCfJ.js} +21 -88
- package/dist/RadioList/index.d.ts +2 -0
- package/dist/RadioList/index.js +2 -0
- package/dist/RadioList-DI8ujXcT.js +122 -0
- package/dist/Resizable/index.d.ts +2 -0
- package/dist/Resizable/index.js +2 -0
- package/dist/Resizable-BuGKvU9I.js +261 -0
- package/dist/ScrollableArea/index.d.ts +2 -0
- package/dist/ScrollableArea/index.js +2 -0
- package/dist/ScrollableArea-DQDYjnxO.js +78 -0
- package/dist/Section/index.d.ts +2 -0
- package/dist/Section/index.js +2 -0
- package/dist/Section-C48Wqfc7.js +68 -0
- package/dist/SegmentedControl/index.d.ts +1 -1
- package/dist/SelectableCard/index.d.ts +2 -0
- package/dist/SelectableCard/index.js +2 -0
- package/dist/SelectableCard-Bj5s_tIN.js +108 -0
- package/dist/Selector/index.d.ts +1 -1
- package/dist/Selector/index.js +1 -1
- package/dist/{Selector-C6sPJMtH.js → Selector-DlZpQh42.js} +1 -1
- package/dist/SideNav/index.d.ts +1 -1
- package/dist/SideNav/index.js +2 -1
- package/dist/{SideNav-D9lnn-sM.js → SideNav-Cdrigq2A.js} +49 -27
- package/dist/Slider/index.js +1 -1
- package/dist/{Slider-DTnWxtnb.js → Slider-D8h_RKcF.js} +1 -1
- package/dist/Stack/index.d.ts +1 -1
- package/dist/Stepper/index.d.ts +2 -0
- package/dist/Stepper/index.js +2 -0
- package/dist/Stepper-DxmLfh8O.js +423 -0
- package/dist/Switch/index.d.ts +1 -1
- package/dist/Switch/index.js +1 -1
- package/dist/{Switch-CNdnr5TP.js → Switch-SesQzPGZ.js} +4 -2
- package/dist/TabList/index.d.ts +2 -2
- package/dist/TabList/index.js +2 -2
- package/dist/TabList-C411uNQU.js +380 -0
- package/dist/Table/index.d.ts +3 -0
- package/dist/Table/index.js +2 -0
- package/dist/Table-7qRmlIQd.js +967 -0
- package/dist/Text/index.d.ts +1 -1
- package/dist/TextArea/index.d.ts +1 -1
- package/dist/TextArea/index.js +1 -1
- package/dist/{TextArea-BL0NuB99.js → TextArea-Cv9UVbzS.js} +5 -3
- package/dist/TextInput/index.d.ts +1 -1
- package/dist/TextInput/index.js +1 -1
- package/dist/{TextInput-B0IKC7g5.js → TextInput-BasnjVvy.js} +5 -3
- package/dist/Thumbnail/index.d.ts +2 -0
- package/dist/Thumbnail/index.js +2 -0
- package/dist/Thumbnail-BWVzLLyI.js +163 -0
- package/dist/TimeField-l3QzU6vC.js +214 -0
- package/dist/TimeInput/index.d.ts +2 -0
- package/dist/TimeInput/index.js +2 -0
- package/dist/TimeInput-OkgX-xbQ.js +121 -0
- package/dist/Timestamp/index.d.ts +2 -0
- package/dist/Timestamp/index.js +2 -0
- package/dist/Timestamp-DUoP9ari.js +465 -0
- package/dist/ToggleButton/index.d.ts +1 -1
- package/dist/Token/index.js +1 -1
- package/dist/{Token-Ctf9jekS.js → Token-C4KD0fZD.js} +1 -1
- package/dist/Tokenizer/index.d.ts +1 -1
- package/dist/Tokenizer/index.js +1 -1
- package/dist/{Tokenizer-D5MPgau0.js → Tokenizer-BA8sTMPZ.js} +3 -3
- package/dist/Toolbar/index.d.ts +1 -1
- package/dist/Tooltip/index.d.ts +1 -1
- package/dist/TopNav/index.d.ts +1 -1
- package/dist/TopNav/index.js +1 -1
- package/dist/{TopNav-CjbMCbkC.js → TopNav-CZokS7E_.js} +57 -31
- package/dist/TreeList/index.d.ts +2 -0
- package/dist/TreeList/index.js +2 -0
- package/dist/TreeList-CIbAGOMf.js +506 -0
- package/dist/Typeahead/index.d.ts +1 -1
- package/dist/Typeahead/index.js +1 -1
- package/dist/{Typeahead-BMoU3hfx.js → Typeahead-DIw-K4aa.js} +3 -3
- package/dist/composables/index.d.ts +3 -2
- package/dist/composables/index.js +8 -2
- package/dist/composables-CVfjp9h4.js +502 -0
- package/dist/context-BjNya0v8.js +19 -0
- package/dist/context-Cfjh8te1.js +29 -0
- package/dist/{locale-56lkR7OK.js → context-D6ECRdc5.js} +267 -18
- package/dist/index-1uRMrk63.d.ts +54 -0
- package/dist/{index-Dw21t7Uf.d.ts → index-2u4l3wq8.d.ts} +2 -2
- package/dist/{index-CvLlWLIZ.d.ts → index-B4OOtNP8.d.ts} +4 -4
- package/dist/{index-_1-uvr27.d.ts → index-B8MbfMwV.d.ts} +1 -1
- package/dist/{index-MPcg1Pm4.d.ts → index-BKr7yvVv.d.ts} +1 -1
- package/dist/index-Be1czg3M.d.ts +167 -0
- package/dist/{index-Dbmgcm8a.d.ts → index-BeR-1LgF.d.ts} +2 -0
- package/dist/{index-CnVbMebA.d.ts → index-Bqb_Fyju.d.ts} +3 -3
- package/dist/index-BrJzFA5X.d.ts +38 -0
- package/dist/{index-BDZCJ9ri.d.ts → index-BuubzuE8.d.ts} +2 -2
- package/dist/index-By2mSzUA.d.ts +67 -0
- package/dist/{index-HV6W3xCx.d.ts → index-Byar3h1e.d.ts} +1 -1
- package/dist/{index-BQuN_dWR.d.ts → index-BzqRns96.d.ts} +1 -1
- package/dist/{index-BkIgRYGz.d.ts → index-C5p2NeCr.d.ts} +2 -2
- package/dist/{index-Cc2HGODZ.d.ts → index-C6RecznD.d.ts} +3 -3
- package/dist/{index-BSRk8MFK.d.ts → index-C8wDPDcP.d.ts} +1 -1
- package/dist/index-CDdRQQF3.d.ts +170 -0
- package/dist/index-COqjznX0.d.ts +47 -0
- package/dist/{index-Cz9ZHVf6.d.ts → index-CT8KEpec.d.ts} +2 -2
- package/dist/{index-CxspvLBl.d.ts → index-CTolyeii.d.ts} +1 -1
- package/dist/index-CVn0GBdB.d.ts +115 -0
- package/dist/index-CX97hlld.d.ts +158 -0
- package/dist/index-C_2Z65Rp.d.ts +67 -0
- package/dist/index-CjtAH60j.d.ts +38 -0
- package/dist/index-CtlkhQ55.d.ts +36 -0
- package/dist/{index-JeZ0YTyd.d.ts → index-D-ZuubCK.d.ts} +4 -4
- package/dist/index-DA52oIdw.d.ts +171 -0
- package/dist/{index-C8NW9xre.d.ts → index-DGNqi2za.d.ts} +7 -7
- package/dist/{index-CCA4R0Mf.d.ts → index-DT9S92sh.d.ts} +31 -6
- package/dist/index-DXSs3rwa.d.ts +252 -0
- package/dist/{index-C0S2Xzoi.d.ts → index-DYChvBOM.d.ts} +135 -0
- package/dist/index-Da7Jm8Ht.d.ts +10 -0
- package/dist/{index-CaHXYQ_E.d.ts → index-Df2YvC8o.d.ts} +717 -147
- package/dist/{index-DjOdQv5B.d.ts → index-DfgHJE7H.d.ts} +1 -1
- package/dist/{index-CPhDtlv-.d.ts → index-FEy8qFSD.d.ts} +3 -3
- package/dist/{index-DBcbfStA.d.ts → index-SMh42NI8.d.ts} +182 -2
- package/dist/{index-Cdi82rTW.d.ts → index-ZJyk8RtQ.d.ts} +6 -2
- package/dist/{index-BeJqhW4l.d.ts → index-fa72tWIU.d.ts} +3 -3
- package/dist/{index-COxy6LEW.d.ts → index-gW0HW02U.d.ts} +1 -1
- package/dist/{index-BQa836Vz.d.ts → index-iBLzInje.d.ts} +6 -14
- package/dist/{index-BhYFxnjV.d.ts → index-kaKBOZSU.d.ts} +2 -2
- package/dist/index-nKlTsNfV.d.ts +42 -0
- package/dist/index-utZGF4GR.d.ts +79 -0
- package/dist/index.d.ts +76 -59
- package/dist/index.js +119 -78
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.js +2 -1
- package/dist/locale-Cpk_nrLA.js +18 -0
- package/dist/size-BuTzpgnR.d.ts +14 -0
- package/dist/size-xcIqExkS.js +79 -0
- package/dist/{index-Cp0NlzQv.d.ts → types-Db3Owy8Q.d.ts} +1 -36
- package/dist/types-JktRxujg.d.ts +107 -0
- package/dist/useAppShellMobile-DTsyuAJ4.js +19 -0
- package/dist/useClickableContainer-DyNpnSEa.js +112 -0
- package/dist/useFileSelection-BPtaegqK.js +58 -0
- package/dist/useMonthGrid-CmJsZTcB.js +139 -0
- package/dist/useResizable-CeESZS1v.d.ts +72 -0
- package/dist/useScrollableArea-DDk_CluT.js +172 -0
- package/dist/useTimeValue-DWk6oTAZ.js +113 -0
- package/package.json +97 -1
- package/styles/app-shell.css +151 -0
- package/styles/aspect-ratio.css +49 -0
- package/styles/bordered-control.css +87 -0
- package/styles/calendar.css +8 -2
- package/styles/card.css +5 -1
- package/styles/checkbox-list.css +15 -0
- package/styles/clickable-card.css +101 -0
- package/styles/collapsible.css +37 -0
- package/styles/command-palette.css +183 -0
- package/styles/complex-selector.css +114 -0
- package/styles/date-range-input.css +163 -0
- package/styles/date-time-input.css +40 -0
- package/styles/field.css +14 -3
- package/styles/file-input.css +87 -0
- package/styles/form-layout.css +31 -0
- package/styles/heading.css +19 -17
- package/styles/icon.css +32 -0
- package/styles/layout.css +280 -0
- package/styles/metadata-list.css +107 -0
- package/styles/number-input.css +6 -0
- package/styles/radio.css +32 -0
- package/styles/resize-handle.css +128 -0
- package/styles/scrollable-area.css +50 -0
- package/styles/section.css +60 -0
- package/styles/selector.css +10 -0
- package/styles/side-nav.css +26 -0
- package/styles/stepper.css +357 -0
- package/styles/tab-menu.css +91 -0
- package/styles/table.css +256 -0
- package/styles/text-area.css +6 -1
- package/styles/text-input.css +6 -0
- package/styles/thumbnail.css +151 -0
- package/styles/time-input.css +51 -0
- package/styles/timestamp.css +93 -0
- package/styles/tree-list.css +229 -0
- package/styles.css +23 -0
- package/dist/Collapsible-ByXCGhT8.js +0 -102
- package/dist/TabList-LV1U4ZD6.js +0 -184
- package/dist/composables-Dq9RS33w.js +0 -111
- package/dist/index-TnaIHsCS.d.ts +0 -87
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
//#region src/composables/useClickableContainer.ts
|
|
2
|
+
/**
|
|
3
|
+
* 对应原版 Astryx 的 `hooks/useClickableContainer`。
|
|
4
|
+
*
|
|
5
|
+
* 让整块容器可点,同时把点在嵌套按钮、链接、输入框上的点击留给那些控件自己。
|
|
6
|
+
* ClickableCard 和 SelectableCard 都走这里,避免两套“点到谁算谁”的判断。
|
|
7
|
+
*/
|
|
8
|
+
const INTERACTIVE_SELECTORS = [
|
|
9
|
+
"button",
|
|
10
|
+
"a",
|
|
11
|
+
"input",
|
|
12
|
+
"select",
|
|
13
|
+
"textarea",
|
|
14
|
+
"[role=\"button\"]",
|
|
15
|
+
"[role=\"link\"]",
|
|
16
|
+
"[role=\"checkbox\"]",
|
|
17
|
+
"[role=\"radio\"]",
|
|
18
|
+
"[role=\"switch\"]",
|
|
19
|
+
"[role=\"tab\"]",
|
|
20
|
+
"[role=\"menuitem\"]",
|
|
21
|
+
"[role=\"option\"]",
|
|
22
|
+
"[role=\"combobox\"]",
|
|
23
|
+
"[role=\"listbox\"]",
|
|
24
|
+
"[role=\"slider\"]",
|
|
25
|
+
"[role=\"spinbutton\"]",
|
|
26
|
+
"[data-pressable-container]"
|
|
27
|
+
].join(",");
|
|
28
|
+
const NON_INTERACTIVE_SELECTORS = "[aria-readonly=\"true\"]";
|
|
29
|
+
function hasInteractiveAncestor(element, root) {
|
|
30
|
+
let current = element;
|
|
31
|
+
while (current != null && current !== root && current !== document.body) {
|
|
32
|
+
if (current.matches(INTERACTIVE_SELECTORS) && !current.matches(NON_INTERACTIVE_SELECTORS)) return true;
|
|
33
|
+
current = current.parentElement;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
function hasTextSelection(node) {
|
|
38
|
+
if (typeof document === "undefined" || document.getSelection == null) return false;
|
|
39
|
+
const selection = document.getSelection();
|
|
40
|
+
if (selection == null || selection.isCollapsed) return false;
|
|
41
|
+
return node.contains(selection.anchorNode);
|
|
42
|
+
}
|
|
43
|
+
function openInNewTab(href) {
|
|
44
|
+
window.open(href, "_blank", "noopener");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 把容器的 click / mouseup 交给调用方绑到根元素上。
|
|
48
|
+
* 组件挂载后会给容器加上 `data-pressable-container`,嵌套的可点容器因此不会互相抢走点击。
|
|
49
|
+
*/
|
|
50
|
+
function useClickableContainer(options) {
|
|
51
|
+
function markContainer() {
|
|
52
|
+
const container = options.containerRef.value;
|
|
53
|
+
if (container != null) container.dataset.pressableContainer = "true";
|
|
54
|
+
}
|
|
55
|
+
function onClick(event) {
|
|
56
|
+
markContainer();
|
|
57
|
+
if (options.disabled) return;
|
|
58
|
+
const container = options.containerRef.value;
|
|
59
|
+
if (container == null) return;
|
|
60
|
+
if (hasTextSelection(container)) return;
|
|
61
|
+
const target = event.target;
|
|
62
|
+
if (!(target instanceof Element)) return;
|
|
63
|
+
if (target !== event.currentTarget && hasInteractiveAncestor(target, container)) return;
|
|
64
|
+
options.onClick?.(event);
|
|
65
|
+
if (event.defaultPrevented) return;
|
|
66
|
+
const href = options.href;
|
|
67
|
+
if (href != null && href !== "") {
|
|
68
|
+
if (options.target === "_blank" || event.metaKey || event.ctrlKey) {
|
|
69
|
+
openInNewTab(href);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const interactive = options.interactiveRef?.value;
|
|
73
|
+
if (interactive != null) {
|
|
74
|
+
interactive.click();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
window.location.assign(href);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (options.onClick == null) {
|
|
81
|
+
const interactive = options.interactiveRef?.value;
|
|
82
|
+
if (interactive != null) {
|
|
83
|
+
interactive.dispatchEvent(new MouseEvent("click", {
|
|
84
|
+
bubbles: true,
|
|
85
|
+
cancelable: true,
|
|
86
|
+
button: event.button,
|
|
87
|
+
ctrlKey: event.ctrlKey,
|
|
88
|
+
metaKey: event.metaKey,
|
|
89
|
+
shiftKey: event.shiftKey,
|
|
90
|
+
altKey: event.altKey
|
|
91
|
+
}));
|
|
92
|
+
event.stopPropagation();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function onMouseUp(event) {
|
|
97
|
+
if (options.disabled) return;
|
|
98
|
+
const href = options.href;
|
|
99
|
+
if (href == null || href === "" || event.button !== 1) return;
|
|
100
|
+
const container = options.containerRef.value;
|
|
101
|
+
const target = event.target;
|
|
102
|
+
if (container == null || !(target instanceof Element)) return;
|
|
103
|
+
if (target !== event.currentTarget && hasInteractiveAncestor(target, container)) return;
|
|
104
|
+
openInNewTab(href);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
onClick,
|
|
108
|
+
onMouseUp
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { useClickableContainer as n, INTERACTIVE_SELECTORS as t };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/composables/useFileSelection.ts
|
|
2
|
+
function matchesAccept(file, accept) {
|
|
3
|
+
if (accept == null || accept.trim() === "") return true;
|
|
4
|
+
const tokens = accept.split(",").map((token) => token.trim().toLowerCase()).filter(Boolean);
|
|
5
|
+
if (tokens.length === 0) return true;
|
|
6
|
+
const name = file.name.toLowerCase();
|
|
7
|
+
const type = file.type.toLowerCase();
|
|
8
|
+
return tokens.some((token) => {
|
|
9
|
+
if (token.startsWith(".")) return name.endsWith(token);
|
|
10
|
+
if (token.endsWith("/*")) return type.startsWith(token.slice(0, -1));
|
|
11
|
+
return type === token;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function formatFileSize(bytes) {
|
|
15
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
16
|
+
if (bytes < 1048576) return `${Math.max(1, Math.round(bytes / 1024))} KB`;
|
|
17
|
+
const megabytes = bytes / 1048576;
|
|
18
|
+
return `${megabytes >= 10 ? Math.round(megabytes) : Math.round(megabytes * 10) / 10} MB`;
|
|
19
|
+
}
|
|
20
|
+
function selectFiles(list, options) {
|
|
21
|
+
const incoming = list == null ? [] : [...list];
|
|
22
|
+
const rejections = [];
|
|
23
|
+
let accepted = incoming.filter((file) => {
|
|
24
|
+
if (!matchesAccept(file, options.accept)) {
|
|
25
|
+
rejections.push({
|
|
26
|
+
code: "type",
|
|
27
|
+
fileName: file.name
|
|
28
|
+
});
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (options.maxSize != null && file.size > options.maxSize) {
|
|
32
|
+
rejections.push({
|
|
33
|
+
code: "size",
|
|
34
|
+
fileName: file.name,
|
|
35
|
+
maxSize: options.maxSize
|
|
36
|
+
});
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
});
|
|
41
|
+
if (options.isMultiple && options.maxFiles != null && accepted.length > options.maxFiles) {
|
|
42
|
+
rejections.push({
|
|
43
|
+
code: "count",
|
|
44
|
+
maxFiles: options.maxFiles
|
|
45
|
+
});
|
|
46
|
+
accepted = accepted.slice(0, options.maxFiles);
|
|
47
|
+
}
|
|
48
|
+
if (!options.isMultiple) return {
|
|
49
|
+
files: accepted[0] ?? null,
|
|
50
|
+
rejections
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
files: accepted,
|
|
54
|
+
rejections
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { selectFiles as n, formatFileSize as t };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { CalendarDate } from "@internationalized/date";
|
|
2
|
+
//#region src/composables/useDateRange.ts
|
|
3
|
+
const WEEKDAY_INDEX = {
|
|
4
|
+
sun: 0,
|
|
5
|
+
mon: 1,
|
|
6
|
+
tue: 2,
|
|
7
|
+
wed: 3,
|
|
8
|
+
thu: 4,
|
|
9
|
+
fri: 5,
|
|
10
|
+
sat: 6
|
|
11
|
+
};
|
|
12
|
+
function resolveWeekStart(value) {
|
|
13
|
+
if (value == null) return 0;
|
|
14
|
+
if (typeof value === "number") return (value % 7 + 7) % 7;
|
|
15
|
+
return WEEKDAY_INDEX[value.toLowerCase()] ?? 0;
|
|
16
|
+
}
|
|
17
|
+
function compareISODate(a, b) {
|
|
18
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
19
|
+
}
|
|
20
|
+
function spanDays(start, end) {
|
|
21
|
+
const [startYear, startMonth, startDay] = start.split("-").map(Number);
|
|
22
|
+
const [endYear, endMonth, endDay] = end.split("-").map(Number);
|
|
23
|
+
const startUtc = Date.UTC(startYear, startMonth - 1, startDay);
|
|
24
|
+
const endUtc = Date.UTC(endYear, endMonth - 1, endDay);
|
|
25
|
+
return Math.round((endUtc - startUtc) / 864e5) + 1;
|
|
26
|
+
}
|
|
27
|
+
function orderRange(a, b) {
|
|
28
|
+
return compareISODate(a, b) <= 0 ? {
|
|
29
|
+
start: a,
|
|
30
|
+
end: b
|
|
31
|
+
} : {
|
|
32
|
+
start: b,
|
|
33
|
+
end: a
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function isSameRange(a, b) {
|
|
37
|
+
if (a == null || b == null) return a === b;
|
|
38
|
+
return a.start === b.start && a.end === b.end;
|
|
39
|
+
}
|
|
40
|
+
function isRangeWithinSpan(range, minRangeSpan = 1, maxRangeSpan) {
|
|
41
|
+
const span = spanDays(range.start, range.end);
|
|
42
|
+
if (span < minRangeSpan) return false;
|
|
43
|
+
if (maxRangeSpan != null && span > maxRangeSpan) return false;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 第一次点击记下起点。第二次点击在跨度合法时提交区间。
|
|
48
|
+
* 再次点击起点时,最短跨度允许单日就提交单日,否则取消这次选择。
|
|
49
|
+
*/
|
|
50
|
+
function applyRangeClick(pending, day, minRangeSpan = 1, maxRangeSpan) {
|
|
51
|
+
if (pending == null) return {
|
|
52
|
+
pending: day,
|
|
53
|
+
commit: null
|
|
54
|
+
};
|
|
55
|
+
if (pending === day) {
|
|
56
|
+
if (minRangeSpan <= 1) return {
|
|
57
|
+
pending: null,
|
|
58
|
+
commit: {
|
|
59
|
+
start: day,
|
|
60
|
+
end: day
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
pending: null,
|
|
65
|
+
commit: null
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const range = orderRange(pending, day);
|
|
69
|
+
if (!isRangeWithinSpan(range, minRangeSpan, maxRangeSpan)) return {
|
|
70
|
+
pending,
|
|
71
|
+
commit: null
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
pending: null,
|
|
75
|
+
commit: range
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function isDayOutsideSpan(pending, day, minRangeSpan = 1, maxRangeSpan) {
|
|
79
|
+
if (pending == null || pending === day) return false;
|
|
80
|
+
return !isRangeWithinSpan(orderRange(pending, day), minRangeSpan, maxRangeSpan);
|
|
81
|
+
}
|
|
82
|
+
function formatDateRange(range, locale) {
|
|
83
|
+
if (range == null) return "";
|
|
84
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
85
|
+
const startYear = Number(range.start.slice(0, 4));
|
|
86
|
+
const withYear = !(startYear === Number(range.end.slice(0, 4)) && startYear === currentYear);
|
|
87
|
+
const formatter = new Intl.DateTimeFormat(locale === "zh-CN" ? "zh-CN" : "en", {
|
|
88
|
+
month: "short",
|
|
89
|
+
day: "numeric",
|
|
90
|
+
year: withYear ? "numeric" : void 0
|
|
91
|
+
});
|
|
92
|
+
const format = (iso) => {
|
|
93
|
+
const [year, month, day] = iso.split("-").map(Number);
|
|
94
|
+
return formatter.format(new Date(year, month - 1, day));
|
|
95
|
+
};
|
|
96
|
+
return `${format(range.start)} – ${format(range.end)}`;
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/composables/useMonthGrid.ts
|
|
100
|
+
function toISODate(date) {
|
|
101
|
+
const month = String(date.month).padStart(2, "0");
|
|
102
|
+
const day = String(date.day).padStart(2, "0");
|
|
103
|
+
return `${date.year}-${month}-${day}`;
|
|
104
|
+
}
|
|
105
|
+
function parseISODate(value) {
|
|
106
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
107
|
+
return new CalendarDate(year, month, day);
|
|
108
|
+
}
|
|
109
|
+
function buildMonthGrid(year, month, weekStartsOn) {
|
|
110
|
+
const first = new CalendarDate(year, month, 1);
|
|
111
|
+
const start = resolveWeekStart(weekStartsOn);
|
|
112
|
+
const offset = (first.toDate("UTC").getUTCDay() - start + 7) % 7;
|
|
113
|
+
let cursor = first.subtract({ days: offset });
|
|
114
|
+
const weeks = [];
|
|
115
|
+
for (let week = 0; week < 6; week += 1) {
|
|
116
|
+
const days = [];
|
|
117
|
+
for (let day = 0; day < 7; day += 1) {
|
|
118
|
+
days.push(toISODate(cursor));
|
|
119
|
+
cursor = cursor.add({ days: 1 });
|
|
120
|
+
}
|
|
121
|
+
weeks.push(days);
|
|
122
|
+
}
|
|
123
|
+
return weeks;
|
|
124
|
+
}
|
|
125
|
+
function addMonths(year, month, amount) {
|
|
126
|
+
const date = new CalendarDate(year, month, 1).add({ months: amount });
|
|
127
|
+
return {
|
|
128
|
+
year: date.year,
|
|
129
|
+
month: date.month
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function todayISODate() {
|
|
133
|
+
const now = /* @__PURE__ */ new Date();
|
|
134
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
135
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
136
|
+
return `${now.getFullYear()}-${month}-${day}`;
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
export { todayISODate as a, formatDateRange as c, isSameRange as d, orderRange as f, toISODate as i, isDayOutsideSpan as l, spanDays as m, buildMonthGrid as n, applyRangeClick as o, resolveWeekStart as p, parseISODate as r, compareISODate as s, addMonths as t, isRangeWithinSpan as u };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { n as PixelWidth } from "./types-JktRxujg.js";
|
|
2
|
+
import { Ref } from "vue";
|
|
3
|
+
//#region src/composables/useResizable.d.ts
|
|
4
|
+
type ResizableDirection = 'horizontal' | 'vertical';
|
|
5
|
+
interface ResizablePercentSize {
|
|
6
|
+
type: 'percent';
|
|
7
|
+
value: number;
|
|
8
|
+
min?: PixelWidth;
|
|
9
|
+
max?: PixelWidth;
|
|
10
|
+
}
|
|
11
|
+
type ResizableSize = number | `${number}px` | `${number}%` | PixelWidth | ResizablePercentSize;
|
|
12
|
+
interface ResizableRegionConfig {
|
|
13
|
+
defaultSize?: ResizableSize | string;
|
|
14
|
+
minSize?: ResizableSize | string;
|
|
15
|
+
maxSize?: ResizableSize | string;
|
|
16
|
+
collapsible?: boolean;
|
|
17
|
+
collapsedSize?: number;
|
|
18
|
+
snaps?: number[];
|
|
19
|
+
/** Cascade priority. A lower number gives up space first when the shared container is narrower than the regions. */
|
|
20
|
+
shrinkOrder?: number;
|
|
21
|
+
}
|
|
22
|
+
interface UseResizableSingleOptions extends ResizableRegionConfig {
|
|
23
|
+
containerRef?: Ref<HTMLElement | null>;
|
|
24
|
+
direction?: ResizableDirection;
|
|
25
|
+
autoSaveId?: string;
|
|
26
|
+
defaultIsCollapsed?: boolean;
|
|
27
|
+
isCollapsed?: boolean;
|
|
28
|
+
onSizeChange?: (size: number) => void;
|
|
29
|
+
onCollapseChange?: (isCollapsed: boolean) => void;
|
|
30
|
+
}
|
|
31
|
+
interface UseResizableMultiConfig {
|
|
32
|
+
direction?: ResizableDirection;
|
|
33
|
+
containerRef?: Ref<HTMLElement | null>;
|
|
34
|
+
regions: Record<string, ResizableRegionConfig>;
|
|
35
|
+
autoSaveId?: string;
|
|
36
|
+
}
|
|
37
|
+
interface ResizableProps {
|
|
38
|
+
_size: number;
|
|
39
|
+
_isCollapsed: boolean;
|
|
40
|
+
_onResizeStart: () => void;
|
|
41
|
+
_onResizeMove: (delta: number) => void;
|
|
42
|
+
_onResizeEnd: () => void;
|
|
43
|
+
_onResizeCancel?: () => void;
|
|
44
|
+
_minSizePx: number;
|
|
45
|
+
_maxSizePx: number;
|
|
46
|
+
_snaps: number[];
|
|
47
|
+
_collapsedSize: number;
|
|
48
|
+
_collapsible: boolean;
|
|
49
|
+
_direction?: ResizableDirection;
|
|
50
|
+
_isResizableProps: true;
|
|
51
|
+
}
|
|
52
|
+
interface ResizableRegion {
|
|
53
|
+
size: number;
|
|
54
|
+
isCollapsed: boolean;
|
|
55
|
+
collapse: () => void;
|
|
56
|
+
expand: () => void;
|
|
57
|
+
resize: (size: number) => void;
|
|
58
|
+
props: ResizableProps;
|
|
59
|
+
}
|
|
60
|
+
declare function percent(value: number, options: {
|
|
61
|
+
min: PixelWidth;
|
|
62
|
+
max?: never;
|
|
63
|
+
} | {
|
|
64
|
+
min?: never;
|
|
65
|
+
max: PixelWidth;
|
|
66
|
+
}): ResizablePercentSize;
|
|
67
|
+
declare function useResizable(options: UseResizableMultiConfig): Record<string, ResizableRegion>;
|
|
68
|
+
declare function useResizable(options: UseResizableSingleOptions): ResizableRegion;
|
|
69
|
+
type UseResizableOptions = UseResizableSingleOptions | UseResizableMultiConfig;
|
|
70
|
+
type ResizableState = ResizableRegion;
|
|
71
|
+
//#endregion
|
|
72
|
+
export { ResizableRegionConfig as a, UseResizableMultiConfig as c, percent as d, useResizable as f, ResizableRegion as i, UseResizableOptions as l, ResizablePercentSize as n, ResizableSize as o, ResizableProps as r, ResizableState as s, ResizableDirection as t, UseResizableSingleOptions as u };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
|
2
|
+
//#region src/composables/useScrollableArea.ts
|
|
3
|
+
const TOLERANCE = 1;
|
|
4
|
+
const idleAxis = () => ({
|
|
5
|
+
isScrollable: false,
|
|
6
|
+
atStart: true,
|
|
7
|
+
atEnd: true
|
|
8
|
+
});
|
|
9
|
+
function mappingFor(element) {
|
|
10
|
+
const style = getComputedStyle(element);
|
|
11
|
+
const mode = style.writingMode.toLowerCase();
|
|
12
|
+
const vertical = mode.startsWith("vertical") || mode.startsWith("sideways");
|
|
13
|
+
const rtl = style.direction === "rtl";
|
|
14
|
+
if (!vertical) return {
|
|
15
|
+
inline: "x",
|
|
16
|
+
block: "y",
|
|
17
|
+
inlineReversed: rtl,
|
|
18
|
+
blockReversed: false
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
inline: "y",
|
|
22
|
+
block: "x",
|
|
23
|
+
inlineReversed: mode === "sideways-lr" ? !rtl : rtl,
|
|
24
|
+
blockReversed: mode.endsWith("-rl")
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function extent(element, axis) {
|
|
28
|
+
if (axis === "x") return {
|
|
29
|
+
client: element.clientWidth,
|
|
30
|
+
content: element.scrollWidth,
|
|
31
|
+
offset: element.scrollLeft
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
client: element.clientHeight,
|
|
35
|
+
content: element.scrollHeight,
|
|
36
|
+
offset: element.scrollTop
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function useScrollableArea(options) {
|
|
40
|
+
const viewport = ref(null);
|
|
41
|
+
const content = ref(null);
|
|
42
|
+
const inline = ref(idleAxis());
|
|
43
|
+
const block = ref(idleAxis());
|
|
44
|
+
const overflowInline = ref(false);
|
|
45
|
+
const overflowBlock = ref(false);
|
|
46
|
+
const mapping = ref({
|
|
47
|
+
inline: "x",
|
|
48
|
+
block: "y",
|
|
49
|
+
inlineReversed: false,
|
|
50
|
+
blockReversed: false
|
|
51
|
+
});
|
|
52
|
+
let observer;
|
|
53
|
+
const axis = computed(() => options.axis ?? "block");
|
|
54
|
+
const overscroll = computed(() => options.overscroll ?? "allow");
|
|
55
|
+
const stickyContainment = computed(() => options.stickyContainment ?? "whenScrollable");
|
|
56
|
+
function requested(name) {
|
|
57
|
+
return axis.value === name || axis.value === "both";
|
|
58
|
+
}
|
|
59
|
+
function sameAxis(current, next) {
|
|
60
|
+
return current.isScrollable === next.isScrollable && current.atStart === next.atStart && current.atEnd === next.atEnd;
|
|
61
|
+
}
|
|
62
|
+
function measure() {
|
|
63
|
+
const element = viewport.value;
|
|
64
|
+
if (element == null) return;
|
|
65
|
+
const nextMapping = mappingFor(element);
|
|
66
|
+
const read = (name, reversed) => {
|
|
67
|
+
const box = extent(element, nextMapping[name]);
|
|
68
|
+
const overflowing = box.content > box.client + TOLERANCE;
|
|
69
|
+
const max = Math.max(0, box.content - box.client);
|
|
70
|
+
const offset = reversed ? max - Math.abs(box.offset) : Math.abs(box.offset);
|
|
71
|
+
const active = requested(name) && overflowing;
|
|
72
|
+
return {
|
|
73
|
+
overflowing,
|
|
74
|
+
state: {
|
|
75
|
+
isScrollable: active,
|
|
76
|
+
atStart: !active || offset <= TOLERANCE,
|
|
77
|
+
atEnd: !active || offset >= max - TOLERANCE
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
const inlineRead = read("inline", nextMapping.inlineReversed);
|
|
82
|
+
const blockRead = read("block", nextMapping.blockReversed);
|
|
83
|
+
const nextInline = requested("inline") ? inlineRead.state : idleAxis();
|
|
84
|
+
const nextBlock = requested("block") ? blockRead.state : idleAxis();
|
|
85
|
+
if (mapping.value.inline === nextMapping.inline && mapping.value.block === nextMapping.block && mapping.value.inlineReversed === nextMapping.inlineReversed && mapping.value.blockReversed === nextMapping.blockReversed && overflowInline.value === inlineRead.overflowing && overflowBlock.value === blockRead.overflowing && sameAxis(inline.value, nextInline) && sameAxis(block.value, nextBlock)) return;
|
|
86
|
+
mapping.value = nextMapping;
|
|
87
|
+
overflowInline.value = inlineRead.overflowing;
|
|
88
|
+
overflowBlock.value = blockRead.overflowing;
|
|
89
|
+
inline.value = nextInline;
|
|
90
|
+
block.value = nextBlock;
|
|
91
|
+
}
|
|
92
|
+
let queued = false;
|
|
93
|
+
function queueMeasure() {
|
|
94
|
+
if (queued) return;
|
|
95
|
+
queued = true;
|
|
96
|
+
queueMicrotask(() => {
|
|
97
|
+
queued = false;
|
|
98
|
+
measure();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function bind(element) {
|
|
102
|
+
const node = element instanceof HTMLElement ? element : null;
|
|
103
|
+
if (viewport.value === node) return;
|
|
104
|
+
viewport.value?.removeEventListener("scroll", measure);
|
|
105
|
+
observer?.disconnect();
|
|
106
|
+
observer = void 0;
|
|
107
|
+
viewport.value = node;
|
|
108
|
+
if (node == null) return;
|
|
109
|
+
node.addEventListener("scroll", measure, { passive: true });
|
|
110
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
111
|
+
observer = new ResizeObserver(() => queueMeasure());
|
|
112
|
+
observer.observe(node);
|
|
113
|
+
if (content.value) observer.observe(content.value);
|
|
114
|
+
}
|
|
115
|
+
queueMeasure();
|
|
116
|
+
}
|
|
117
|
+
watch(content, (element) => {
|
|
118
|
+
if (element && observer) observer.observe(element);
|
|
119
|
+
queueMeasure();
|
|
120
|
+
});
|
|
121
|
+
watch([
|
|
122
|
+
axis,
|
|
123
|
+
overscroll,
|
|
124
|
+
stickyContainment
|
|
125
|
+
], queueMeasure);
|
|
126
|
+
onMounted(queueMeasure);
|
|
127
|
+
onBeforeUnmount(() => {
|
|
128
|
+
viewport.value?.removeEventListener("scroll", measure);
|
|
129
|
+
observer?.disconnect();
|
|
130
|
+
});
|
|
131
|
+
const viewportStyle = computed(() => {
|
|
132
|
+
const map = mapping.value;
|
|
133
|
+
const requestedX = requested("inline") && map.inline === "x" || requested("block") && map.block === "x";
|
|
134
|
+
const requestedY = requested("inline") && map.inline === "y" || requested("block") && map.block === "y";
|
|
135
|
+
const overflowingX = overflowInline.value && map.inline === "x" || overflowBlock.value && map.block === "x";
|
|
136
|
+
const overflowingY = overflowInline.value && map.inline === "y" || overflowBlock.value && map.block === "y";
|
|
137
|
+
const contains = overflowingX || overflowingY || stickyContainment.value === "always";
|
|
138
|
+
const scrollsX = stickyContainment.value === "always" ? requestedX : overflowingX;
|
|
139
|
+
const scrollsY = stickyContainment.value === "always" ? requestedY : overflowingY;
|
|
140
|
+
const style = {
|
|
141
|
+
overflowX: contains ? scrollsX ? "auto" : "hidden" : "clip",
|
|
142
|
+
overflowY: contains ? scrollsY ? "auto" : "hidden" : "clip"
|
|
143
|
+
};
|
|
144
|
+
if (requested("inline")) style[map.inline === "x" ? "overscrollBehaviorX" : "overscrollBehaviorY"] = overscroll.value === "contain" && inline.value.isScrollable ? "contain" : "auto";
|
|
145
|
+
if (requested("block")) style[map.block === "x" ? "overscrollBehaviorX" : "overscrollBehaviorY"] = overscroll.value === "contain" && block.value.isScrollable ? "contain" : "auto";
|
|
146
|
+
return style;
|
|
147
|
+
});
|
|
148
|
+
const scrollable = computed(() => inline.value.isScrollable || block.value.isScrollable);
|
|
149
|
+
return {
|
|
150
|
+
viewport: bind,
|
|
151
|
+
content,
|
|
152
|
+
viewportAttrs: computed(() => ({
|
|
153
|
+
"role": options.role ?? "group",
|
|
154
|
+
"aria-label": options.label,
|
|
155
|
+
"tabindex": scrollable.value ? 0 : void 0,
|
|
156
|
+
"data-scroll-axis": axis.value,
|
|
157
|
+
"data-scrollable-inline": inline.value.isScrollable ? "true" : void 0,
|
|
158
|
+
"data-scrollable-block": block.value.isScrollable ? "true" : void 0,
|
|
159
|
+
"data-scroll-inline-start": inline.value.atStart ? "true" : void 0,
|
|
160
|
+
"data-scroll-inline-end": inline.value.atEnd ? "true" : void 0,
|
|
161
|
+
"data-scroll-block-start": block.value.atStart ? "true" : void 0,
|
|
162
|
+
"data-scroll-block-end": block.value.atEnd ? "true" : void 0
|
|
163
|
+
})),
|
|
164
|
+
viewportStyle,
|
|
165
|
+
state: computed(() => ({
|
|
166
|
+
inline: inline.value,
|
|
167
|
+
block: block.value
|
|
168
|
+
}))
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//#endregion
|
|
172
|
+
export { useScrollableArea as t };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { computed, onMounted, onScopeDispose, shallowRef } from "vue";
|
|
2
|
+
//#region src/composables/useCoarsePointer.ts
|
|
3
|
+
/** 粗指针(触摸)为 true。服务端和细指针设备为 false。 */
|
|
4
|
+
function useCoarsePointer() {
|
|
5
|
+
const coarse = shallowRef(false);
|
|
6
|
+
let query;
|
|
7
|
+
function update() {
|
|
8
|
+
coarse.value = query?.matches ?? false;
|
|
9
|
+
}
|
|
10
|
+
onMounted(() => {
|
|
11
|
+
query = window.matchMedia("(pointer: coarse)");
|
|
12
|
+
update();
|
|
13
|
+
query.addEventListener("change", update);
|
|
14
|
+
});
|
|
15
|
+
onScopeDispose(() => {
|
|
16
|
+
query?.removeEventListener("change", update);
|
|
17
|
+
});
|
|
18
|
+
return computed(() => coarse.value);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/composables/useTimeValue.ts
|
|
22
|
+
const DISPLAY_TIME = /^(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?\s*([ap])\.?m\.?$/i;
|
|
23
|
+
const COMPACT_TIME = /^(\d{2})(\d{2})(\d{2})?$/;
|
|
24
|
+
const ISO_TIME = /^(\d{2}):(\d{2})(?::(\d{2}))?$/;
|
|
25
|
+
function clampPart(value, max) {
|
|
26
|
+
return Number.isInteger(value) && value >= 0 && value <= max;
|
|
27
|
+
}
|
|
28
|
+
function parseISOTime(value) {
|
|
29
|
+
const match = ISO_TIME.exec(value.trim());
|
|
30
|
+
if (!match) return null;
|
|
31
|
+
const hours = Number(match[1]);
|
|
32
|
+
const minutes = Number(match[2]);
|
|
33
|
+
const seconds = match[3] == null ? 0 : Number(match[3]);
|
|
34
|
+
if (!clampPart(hours, 23) || !clampPart(minutes, 59) || !clampPart(seconds, 59)) return null;
|
|
35
|
+
return {
|
|
36
|
+
hours,
|
|
37
|
+
minutes,
|
|
38
|
+
seconds
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function formatISOTime(time, hasSeconds) {
|
|
42
|
+
const hours = String(time.hours).padStart(2, "0");
|
|
43
|
+
const minutes = String(time.minutes).padStart(2, "0");
|
|
44
|
+
const seconds = String(time.seconds).padStart(2, "0");
|
|
45
|
+
return hasSeconds ? `${hours}:${minutes}:${seconds}` : `${hours}:${minutes}`;
|
|
46
|
+
}
|
|
47
|
+
function formatDisplayTime(value, hourFormat, hasSeconds) {
|
|
48
|
+
const parsed = parseISOTime(value);
|
|
49
|
+
if (!parsed) return value;
|
|
50
|
+
if (hourFormat === "24h") return formatISOTime(parsed, hasSeconds);
|
|
51
|
+
const suffix = parsed.hours < 12 ? "AM" : "PM";
|
|
52
|
+
return `${parsed.hours % 12 || 12}:${String(parsed.minutes).padStart(2, "0")}${hasSeconds ? `:${String(parsed.seconds).padStart(2, "0")}` : ""} ${suffix}`;
|
|
53
|
+
}
|
|
54
|
+
function parseDisplayTime(text, hasSeconds) {
|
|
55
|
+
const trimmed = text.trim();
|
|
56
|
+
if (!trimmed) return null;
|
|
57
|
+
const meridiem = DISPLAY_TIME.exec(trimmed);
|
|
58
|
+
if (meridiem) {
|
|
59
|
+
let hours = Number(meridiem[1]);
|
|
60
|
+
const minutes = meridiem[2] == null ? 0 : Number(meridiem[2]);
|
|
61
|
+
const seconds = meridiem[3] == null ? 0 : Number(meridiem[3]);
|
|
62
|
+
if (!clampPart(hours, 12) || hours === 0 || !clampPart(minutes, 59) || !clampPart(seconds, 59)) return null;
|
|
63
|
+
const isPm = meridiem[4].toLowerCase() === "p";
|
|
64
|
+
if (hours === 12) hours = isPm ? 12 : 0;
|
|
65
|
+
else if (isPm) hours += 12;
|
|
66
|
+
return formatISOTime({
|
|
67
|
+
hours,
|
|
68
|
+
minutes,
|
|
69
|
+
seconds
|
|
70
|
+
}, hasSeconds);
|
|
71
|
+
}
|
|
72
|
+
const compact = COMPACT_TIME.exec(trimmed);
|
|
73
|
+
if (compact) return parseDisplayTime(`${compact[1]}:${compact[2]}${compact[3] ? `:${compact[3]}` : ""}`, hasSeconds);
|
|
74
|
+
const iso = parseISOTime(trimmed);
|
|
75
|
+
if (!iso) return null;
|
|
76
|
+
return formatISOTime(iso, hasSeconds);
|
|
77
|
+
}
|
|
78
|
+
function shiftTime(value, minuteDelta, hasSeconds) {
|
|
79
|
+
const parsed = parseISOTime(value) ?? {
|
|
80
|
+
hours: 0,
|
|
81
|
+
minutes: 0,
|
|
82
|
+
seconds: 0
|
|
83
|
+
};
|
|
84
|
+
const total = parsed.hours * 60 + parsed.minutes + minuteDelta;
|
|
85
|
+
const day = 1440;
|
|
86
|
+
const normalized = (total % day + day) % day;
|
|
87
|
+
return formatISOTime({
|
|
88
|
+
hours: Math.floor(normalized / 60),
|
|
89
|
+
minutes: normalized % 60,
|
|
90
|
+
seconds: parsed.seconds
|
|
91
|
+
}, hasSeconds);
|
|
92
|
+
}
|
|
93
|
+
function comparable(value) {
|
|
94
|
+
const parsed = parseISOTime(value);
|
|
95
|
+
if (!parsed) return value;
|
|
96
|
+
return formatISOTime(parsed, true);
|
|
97
|
+
}
|
|
98
|
+
function isTimeInRange(value, min, max) {
|
|
99
|
+
const current = comparable(value);
|
|
100
|
+
if (min && current < comparable(min)) return false;
|
|
101
|
+
if (max && current > comparable(max)) return false;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function resolveTimeSurface(options) {
|
|
105
|
+
const presentation = options.presentation ?? (options.nativePicker === "always" ? "native" : options.nativePicker === "never" ? "text-input" : "adaptive-native");
|
|
106
|
+
const needsTypedField = options.hasSeconds || options.increment !== 1;
|
|
107
|
+
if (presentation === "text-input" || presentation === "popover" || presentation === "bottom-sheet") return "text";
|
|
108
|
+
if (needsTypedField) return "text";
|
|
109
|
+
if (presentation === "native") return "native";
|
|
110
|
+
return options.coarse ? "native" : "text";
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { parseISOTime as a, useCoarsePointer as c, parseDisplayTime as i, formatISOTime as n, resolveTimeSurface as o, isTimeInRange as r, shiftTime as s, formatDisplayTime as t };
|