nativescript-web-adapter 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 (88) hide show
  1. package/README.md +220 -168
  2. package/core/components/AbsoluteLayout.vue +11 -0
  3. package/core/components/ActionBar.vue +11 -0
  4. package/core/components/ActionItem.vue +11 -0
  5. package/core/components/ActivityIndicator.vue +15 -0
  6. package/core/components/Button.vue +41 -0
  7. package/core/components/DatePicker.vue +27 -0
  8. package/core/components/DockLayout.vue +23 -0
  9. package/core/components/FlexboxLayout.vue +11 -0
  10. package/core/components/Frame.vue +11 -0
  11. package/core/components/GridLayout.vue +85 -0
  12. package/core/components/HtmlView.vue +13 -0
  13. package/core/components/Image.vue +12 -0
  14. package/core/components/ImageCacheIt.vue +12 -0
  15. package/core/components/Label.vue +15 -0
  16. package/core/components/ListPicker.vue +21 -0
  17. package/core/components/ListView.vue +12 -0
  18. package/core/components/NavigationButton.vue +28 -0
  19. package/core/components/Page.vue +18 -0
  20. package/core/components/Placeholder.vue +11 -0
  21. package/core/components/Progress.vue +12 -0
  22. package/core/components/RootLayout.vue +11 -0
  23. package/core/components/ScrollView.vue +11 -0
  24. package/core/components/SearchBar.vue +22 -0
  25. package/core/components/SegmentedBar.vue +50 -0
  26. package/core/components/SegmentedBarItem.vue +21 -0
  27. package/core/components/Slider.vue +18 -0
  28. package/core/components/StackLayout.vue +11 -0
  29. package/core/components/Switch.vue +26 -0
  30. package/core/components/TabView.vue +48 -0
  31. package/core/components/TabViewItem.vue +27 -0
  32. package/core/components/TextField.vue +15 -0
  33. package/core/components/TextView.vue +18 -0
  34. package/core/components/TimePicker.vue +21 -0
  35. package/core/components/WebView.vue +13 -0
  36. package/core/components/WrapLayout.vue +11 -0
  37. package/core/components/index.js +3 -0
  38. package/core/components/index.ts +35 -0
  39. package/core/composables/dialogs.ts +31 -0
  40. package/core/composables/index.js +3 -0
  41. package/core/composables/index.ts +4 -0
  42. package/core/composables/useActionBar.js +7 -0
  43. package/core/composables/useActionBar.ts +19 -0
  44. package/core/composables/useFrame.js +8 -0
  45. package/core/composables/useFrame.ts +25 -0
  46. package/core/composables/usePage.js +8 -0
  47. package/core/composables/usePage.ts +25 -0
  48. package/core/env.d.ts +7 -0
  49. package/core/index.js +4 -0
  50. package/core/index.ts +85 -0
  51. package/core/types.ts +12 -0
  52. package/dist/nativescript-web-adapter.es.js +83 -0
  53. package/dist/nativescript-web-adapter.umd.js +1 -0
  54. package/dist/style.css +1 -0
  55. package/package.json +34 -46
  56. package/tools/cli.cjs +45 -0
  57. package/tools/create-web-platform.cjs +76 -0
  58. package/tools/create-web-platform.js +196 -0
  59. package/tools/modules/appPatch.cjs +27 -0
  60. package/tools/modules/copy.cjs +84 -0
  61. package/tools/modules/router.cjs +46 -0
  62. package/tools/modules/templates.cjs +130 -0
  63. package/tools/modules/transform.cjs +93 -0
  64. package/dist/core.cjs +0 -3
  65. package/dist/core.cjs.map +0 -1
  66. package/dist/core.js +0 -2
  67. package/dist/core.js.map +0 -1
  68. package/dist/index.cjs +0 -240
  69. package/dist/index.cjs.map +0 -1
  70. package/dist/index.js +0 -229
  71. package/dist/index.js.map +0 -1
  72. package/dist/types/core/index.d.ts +0 -8
  73. package/dist/types/index.d.ts +0 -1
  74. package/dist/types/vue/components/ActionBar.d.ts +0 -5
  75. package/dist/types/vue/components/Button.d.ts +0 -26
  76. package/dist/types/vue/components/FlexboxLayout.d.ts +0 -35
  77. package/dist/types/vue/components/Frame.d.ts +0 -3
  78. package/dist/types/vue/components/GridLayout.d.ts +0 -27
  79. package/dist/types/vue/components/ImageCacheIt.d.ts +0 -23
  80. package/dist/types/vue/components/Label.d.ts +0 -26
  81. package/dist/types/vue/components/Page.d.ts +0 -5
  82. package/dist/types/vue/components/StackLayout.d.ts +0 -5
  83. package/dist/types/vue/index.d.ts +0 -12
  84. package/dist/types/vue.d.ts +0 -169
  85. package/dist/vue.cjs +0 -240
  86. package/dist/vue.cjs.map +0 -1
  87. package/dist/vue.js +0 -229
  88. package/dist/vue.js.map +0 -1
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div class="ns-htmlview" v-if="html" v-html="html"></div>
3
+ <div class="ns-htmlview" v-else><slot /></div>
4
+ </template>
5
+
6
+ <script setup lang="ts">
7
+ defineOptions({ name: 'HtmlView' });
8
+ const props = defineProps<{ html?: string }>();
9
+ </script>
10
+
11
+ <style scoped>
12
+ .ns-htmlview { display: block; }
13
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <img class="ns-image" :src="src" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'Image' });
7
+ const props = defineProps<{ src: string; stretch?: string }>();
8
+ </script>
9
+
10
+ <style scoped>
11
+ .ns-image { display: block; max-width: 100%; height: auto; }
12
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <img class="ns-imagecacheit" :src="src" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'ImageCacheIt' });
7
+ const props = defineProps<{ src: string }>();
8
+ </script>
9
+
10
+ <style scoped>
11
+ .ns-imagecacheit { display: block; max-width: 100%; height: auto; }
12
+ </style>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <span class="ns-label">
3
+ <slot v-if="!text" />
4
+ <template v-else>{{ text }}</template>
5
+ </span>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ defineOptions({ name: 'Label' });
10
+ const props = defineProps<{ text?: string }>();
11
+ </script>
12
+
13
+ <style scoped>
14
+ .ns-label { display: inline-block; }
15
+ </style>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <select class="ns-listpicker" :value="selectedIndex" @change="onChange">
3
+ <option v-for="(item, i) in items" :key="i" :value="i">{{ item }}</option>
4
+ </select>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ defineOptions({ name: 'ListPicker' });
9
+ const props = defineProps<{ items: string[]; selectedIndex?: number }>();
10
+ const emit = defineEmits<{ (e: 'update:selectedIndex', v: number): void; (e: 'change', v: number): void }>();
11
+
12
+ function onChange(e: Event) {
13
+ const v = Number((e.target as HTMLSelectElement).value);
14
+ emit('update:selectedIndex', v);
15
+ emit('change', v);
16
+ }
17
+ </script>
18
+
19
+ <style scoped>
20
+ .ns-listpicker { padding: 6px 8px; }
21
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <ul class="ns-listview"><slot /></ul>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'ListView' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-listview { list-style: none; margin: 0; padding: 0; }
11
+ .ns-listview > li { padding: 8px 12px; border-bottom: 1px solid rgba(255,255,255,0.1); }
12
+ </style>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <button class="ns-navbutton" @click="onClick">
3
+ <slot>{{ text }}</slot>
4
+ </button>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { getCurrentInstance } from 'vue';
9
+ const props = defineProps<{ text?: string }>();
10
+ const emit = defineEmits<{ (e: 'tap', evt: MouseEvent): void }>();
11
+ defineOptions({ name: 'NavigationButton' });
12
+
13
+ function onClick(e: MouseEvent) {
14
+ emit('tap', e);
15
+ // 默认行为:若未监听 tap,则尝试返回上一页
16
+ const inst = getCurrentInstance();
17
+ const hasTapListener = !!(inst?.vnode?.props && (inst.vnode.props as any).onTap);
18
+ if (!hasTapListener) {
19
+ const router = (inst?.appContext?.config?.globalProperties as any)?.$router;
20
+ if (router?.go) router.go(-1);
21
+ else if (window?.history?.back) window.history.back();
22
+ }
23
+ }
24
+ </script>
25
+
26
+ <style scoped>
27
+ .ns-navbutton { background: transparent; border: none; color: inherit; cursor: pointer; padding: 8px; }
28
+ </style>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <div class="ns-page"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'Page' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-page {
11
+ top: 0;
12
+ left: 0;
13
+ position: absolute;
14
+ width: 100%;
15
+ min-height: 100%;
16
+ padding: 0px;
17
+ }
18
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-placeholder"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'Placeholder' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-placeholder { display: contents; }
11
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <progress class="ns-progress" :value="value" :max="max"></progress>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'Progress' });
7
+ const props = defineProps<{ value?: number; max?: number }>();
8
+ </script>
9
+
10
+ <style scoped>
11
+ .ns-progress { width: 100%; }
12
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-root"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'RootLayout' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-root { position: relative; width: 100%; height: 100%; display: block; }
11
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-scroll"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'ScrollView' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-scroll { overflow: auto; max-height: 100%; }
11
+ </style>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <div class="ns-searchbar">
3
+ <input type="search" :value="text" @input="onInput" @keyup.enter="onSubmit" />
4
+ </div>
5
+
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ defineOptions({ name: 'SearchBar' });
10
+ const props = defineProps<{ text?: string }>();
11
+ const emit = defineEmits<{ (e: 'update:text', v: string): void; (e: 'submit', v: string): void }>();
12
+ function onInput(e: Event) {
13
+ emit('update:text', (e.target as HTMLInputElement).value);
14
+ }
15
+ function onSubmit(e: KeyboardEvent) {
16
+ emit('submit', (e.target as HTMLInputElement).value);
17
+ }
18
+ </script>
19
+
20
+ <style scoped>
21
+ .ns-searchbar input { width: 100%; padding: 6px 8px; }
22
+ </style>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <div class="ns-segmentedbar">
3
+ <div class="ns-segmentedbar-header">
4
+ <button
5
+ v-for="(t, i) in displayItems"
6
+ :key="i"
7
+ class="ns-segment"
8
+ :class="{ active: i === currentIndex }"
9
+ @click="select(i)"
10
+ >{{ t }}</button>
11
+ </div>
12
+ <div class="ns-segmentedbar-body">
13
+ <slot />
14
+ </div>
15
+ </div>
16
+
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { ref, watch, computed, provide } from 'vue';
21
+ defineOptions({ name: 'SegmentedBar' });
22
+ const props = defineProps<{ items?: string[]; selectedIndex?: number }>();
23
+ const emit = defineEmits<{ (e: 'update:selectedIndex', v: number): void; (e: 'change', v: number): void }>();
24
+
25
+ // Selected index
26
+ const currentIndex = ref(props.selectedIndex ?? 0);
27
+ watch(() => props.selectedIndex, v => { if (typeof v === 'number') currentIndex.value = v; });
28
+ function select(i: number) { currentIndex.value = i; emit('update:selectedIndex', i); emit('change', i); }
29
+
30
+ // Child registration for SegmentedBarItem titles when using child components
31
+ const registeredTitles = ref<string[]>([]);
32
+ function register(title: string): number {
33
+ registeredTitles.value.push(title);
34
+ return registeredTitles.value.length - 1;
35
+ }
36
+
37
+ // Provide to children so they can register and know selectedIndex
38
+ provide('ns-segmentedbar', { register, selectedIndex: currentIndex });
39
+
40
+ // Items to display: prefer props.items if provided; else use registered child titles
41
+ const displayItems = computed(() => (props.items && props.items.length ? props.items : registeredTitles.value));
42
+ </script>
43
+
44
+ <style scoped>
45
+ .ns-segmentedbar { display: block; color: inherit; }
46
+ .ns-segmentedbar-header { display: flex; gap: 8px; border-bottom: 1px solid rgba(255,255,255,0.3); padding-bottom: 8px; }
47
+ .ns-segment { background: transparent; border: none; color: #fff; padding: 8px 12px; cursor: pointer; opacity: 0.95; }
48
+ .ns-segment.active { opacity: 1; border-bottom: 2px solid currentColor; }
49
+ .ns-segmentedbar-body { padding-top: 12px; }
50
+ </style>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <div class="ns-segmentedbar-item" v-show="isActive"><slot /></div>
3
+
4
+ </template>
5
+
6
+ <script setup lang="ts">
7
+ import { inject, onMounted, ref, computed } from 'vue';
8
+ defineOptions({ name: 'SegmentedBarItem' });
9
+ const props = defineProps<{ title: string }>();
10
+ const sb = inject<{ register: (t: string) => number; selectedIndex: any } | undefined>('ns-segmentedbar', undefined);
11
+ const index = ref<number>(-1);
12
+ onMounted(() => { index.value = sb ? sb.register(props.title) : -1; });
13
+ const isActive = computed(() => {
14
+ if (!sb || index.value < 0) return true;
15
+ return sb.selectedIndex.value === index.value;
16
+ });
17
+ </script>
18
+
19
+ <style scoped>
20
+ .ns-segmentedbar-item { display: block; }
21
+ </style>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <input class="ns-slider" type="range" :min="min" :max="max" :step="step" :value="value" @input="onInput" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'Slider' });
7
+ const props = defineProps<{ value?: number; min?: number; max?: number; step?: number }>();
8
+ const emit = defineEmits<{ (e: 'update:value', v: number): void; (e: 'change', v: number): void }>();
9
+ function onInput(e: Event) {
10
+ const v = Number((e.target as HTMLInputElement).value);
11
+ emit('update:value', v);
12
+ emit('change', v);
13
+ }
14
+ </script>
15
+
16
+ <style scoped>
17
+ .ns-slider { width: 100%; }
18
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-stack"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'StackLayout' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-stack { display: flex; flex-direction: column; }
11
+ </style>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <label class="ns-switch">
3
+ <input type="checkbox" :checked="checked" @change="onChange" />
4
+ <span class="track"><span class="thumb"></span></span>
5
+ </label>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ defineOptions({ name: 'Switch' });
10
+ const props = defineProps<{ checked?: boolean }>();
11
+ const emit = defineEmits<{ (e: 'update:checked', v: boolean): void; (e: 'change', v: boolean): void }>();
12
+ function onChange(e: Event) {
13
+ const v = (e.target as HTMLInputElement).checked;
14
+ emit('update:checked', v);
15
+ emit('change', v);
16
+ }
17
+ </script>
18
+
19
+ <style scoped>
20
+ .ns-switch { display: inline-flex; align-items: center; cursor: pointer; }
21
+ .ns-switch input { display: none; }
22
+ .ns-switch .track { width: 40px; height: 22px; background: rgba(255,255,255,0.3); border-radius: 11px; position: relative; transition: background .2s; }
23
+ .ns-switch .thumb { width: 18px; height: 18px; background: rgb(0, 255, 174); border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: left .2s; }
24
+ .ns-switch input:checked + .track { background: currentColor; opacity: .5; }
25
+ .ns-switch input:checked + .track .thumb { left: 20px; }
26
+ </style>
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <div class="ns-tabview">
3
+ <div class="ns-tabview-header">
4
+ <button
5
+ v-for="(title, i) in items"
6
+ :key="i"
7
+ class="ns-tabview-tab"
8
+ :class="{ active: i === currentIndex }"
9
+ @click="select(i)"
10
+ >{{ title }}</button>
11
+ </div>
12
+ <div class="ns-tabview-body">
13
+ <slot />
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ import { ref, provide, watch } from 'vue';
20
+
21
+ defineOptions({ name: 'TabView' });
22
+
23
+ const props = defineProps<{ selectedIndex?: number }>();
24
+ const currentIndex = ref(props.selectedIndex ?? 0);
25
+ watch(() => props.selectedIndex, (v) => {
26
+ if (typeof v === 'number') currentIndex.value = v;
27
+ });
28
+
29
+ const items = ref<string[]>([]);
30
+ function register(title: string) {
31
+ const idx = items.value.length;
32
+ items.value.push(title);
33
+ return idx;
34
+ }
35
+ function select(i: number) {
36
+ currentIndex.value = i;
37
+ }
38
+
39
+ provide('ns-tabview', { register, selectedIndex: currentIndex });
40
+ </script>
41
+
42
+ <style scoped>
43
+ .ns-tabview { display: block; }
44
+ .ns-tabview-header { display: flex; gap: 8px; border-bottom: 1px solid rgba(255,255,255,0.2); padding-bottom: 8px; }
45
+ .ns-tabview-tab { background: transparent; border: none; color: inherit; padding: 8px 12px; cursor: pointer; opacity: 0.7; }
46
+ .ns-tabview-tab.active { opacity: 1; border-bottom: 2px solid currentColor; }
47
+ .ns-tabview-body { padding-top: 12px; }
48
+ </style>
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <div class="ns-tabview-item" v-show="isActive">
3
+ <slot />
4
+ </div>
5
+
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ import { inject, onMounted, ref, computed } from 'vue';
10
+
11
+ defineOptions({ name: 'TabViewItem' });
12
+
13
+ const props = defineProps<{ title: string }>();
14
+ const tv = inject<{ register: (t: string) => number; selectedIndex: any } | undefined>('ns-tabview', undefined);
15
+ const index = ref<number>(-1);
16
+ onMounted(() => {
17
+ index.value = tv ? tv.register(props.title) : -1;
18
+ });
19
+ const isActive = computed(() => {
20
+ if (!tv || index.value < 0) return true;
21
+ return tv.selectedIndex.value === index.value;
22
+ });
23
+ </script>
24
+
25
+ <style scoped>
26
+ .ns-tabview-item { display: block; }
27
+ </style>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <input class="ns-textfield" type="text" :value="text" @input="onInput" @keyup.enter="onSubmit" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'TextField' });
7
+ const props = defineProps<{ text?: string }>();
8
+ const emit = defineEmits<{ (e: 'update:text', v: string): void; (e: 'submit', v: string): void }>();
9
+ function onInput(e: Event) { emit('update:text', (e.target as HTMLInputElement).value); }
10
+ function onSubmit(e: KeyboardEvent) { emit('submit', (e.target as HTMLInputElement).value); }
11
+ </script>
12
+
13
+ <style scoped>
14
+ .ns-textfield { width: 100%; padding: 6px 8px; }
15
+ </style>
@@ -0,0 +1,18 @@
1
+ <template>
2
+ <textarea class="ns-textview" :value="text" @input="onInput"></textarea>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'TextView' });
7
+ const props = defineProps<{ text?: string }>();
8
+ const emit = defineEmits<{ (e: 'update:text', v: string): void; (e: 'change', v: string): void }>();
9
+ function onInput(e: Event) {
10
+ const v = (e.target as HTMLTextAreaElement).value;
11
+ emit('update:text', v);
12
+ emit('change', v);
13
+ }
14
+ </script>
15
+
16
+ <style scoped>
17
+ .ns-textview { width: 100%; min-height: 80px; padding: 6px 8px; }
18
+ </style>
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <input class="ns-timepicker" type="time" :value="valueStr" @input="onInput" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { computed } from 'vue';
7
+ defineOptions({ name: 'TimePicker' });
8
+ const props = defineProps<{ time?: string }>();
9
+ const emit = defineEmits<{ (e: 'update:time', v: string): void; (e: 'change', v: string): void }>();
10
+
11
+ const valueStr = computed(() => props.time ?? '');
12
+ function onInput(e: Event) {
13
+ const v = (e.target as HTMLInputElement).value;
14
+ emit('update:time', v);
15
+ emit('change', v);
16
+ }
17
+ </script>
18
+
19
+ <style scoped>
20
+ .ns-timepicker { padding: 6px 8px; }
21
+ </style>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <iframe class="ns-webview" :src="src" v-if="src"></iframe>
3
+ <div class="ns-webview" v-else><slot /></div>
4
+ </template>
5
+
6
+ <script setup lang="ts">
7
+ defineOptions({ name: 'WebView' });
8
+ const props = defineProps<{ src?: string }>();
9
+ </script>
10
+
11
+ <style scoped>
12
+ .ns-webview { width: 100%; height: 100%; border: none; }
13
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div class="ns-wrap"><slot /></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ defineOptions({ name: 'WrapLayout' });
7
+ </script>
8
+
9
+ <style scoped>
10
+ .ns-wrap { display: flex; flex-wrap: wrap; }
11
+ </style>
@@ -0,0 +1,3 @@
1
+ export { default as ActionBar } from './ActionBar.vue';
2
+ export { default as Page } from './Page.vue';
3
+ export { default as Frame } from './Frame.vue';
@@ -0,0 +1,35 @@
1
+ export * from './ActionBar.vue';
2
+ export * from './Page.vue';
3
+ export * from './Frame.vue';
4
+ export * from './StackLayout.vue';
5
+ export * from './GridLayout.vue';
6
+ export * from './FlexboxLayout.vue';
7
+ export * from './WrapLayout.vue';
8
+ export * from './ScrollView.vue';
9
+ export * from './Label.vue';
10
+ export * from './Button.vue';
11
+ export * from './Image.vue';
12
+ export * from './HtmlView.vue';
13
+ export * from './ImageCacheIt.vue';
14
+ export * from './TabView.vue';
15
+ export * from './TabViewItem.vue';
16
+ export * from './RootLayout.vue';
17
+ export * from './DockLayout.vue';
18
+ export * from './AbsoluteLayout.vue';
19
+ export * from './ActionItem.vue';
20
+ export * from './NavigationButton.vue';
21
+ export * from './ActivityIndicator.vue';
22
+ export * from './DatePicker.vue';
23
+ export * from './TimePicker.vue';
24
+ export * from './ListPicker.vue';
25
+ export * from './ListView.vue';
26
+ export * from './Placeholder.vue';
27
+ export * from './Progress.vue';
28
+ export * from './SearchBar.vue';
29
+ export * from './SegmentedBar.vue';
30
+ export * from './SegmentedBarItem.vue';
31
+ export * from './Slider.vue';
32
+ export * from './Switch.vue';
33
+ export * from './TextField.vue';
34
+ export * from './TextView.vue';
35
+ export * from './WebView.vue';
@@ -0,0 +1,31 @@
1
+ export async function alert(message: string, title?: string, okButtonText?: string) {
2
+ window.alert(title ? `${title}\n\n${message}` : message);
3
+ }
4
+
5
+ export async function confirm(message: string, title?: string, okButtonText?: string, cancelButtonText?: string): Promise<boolean> {
6
+ return window.confirm(title ? `${title}\n\n${message}` : message);
7
+ }
8
+
9
+ export async function prompt(message: string, defaultText = '', title?: string, okButtonText?: string, cancelButtonText?: string): Promise<{ result: boolean; text: string }> {
10
+ const res = window.prompt(title ? `${title}\n\n${message}` : message, defaultText);
11
+ return { result: res !== null, text: res ?? '' };
12
+ }
13
+
14
+ export async function login(message = '登录', userName = '', password = '', title?: string, okButtonText?: string, cancelButtonText?: string): Promise<{ result: boolean; userName: string; password: string }> {
15
+ const u = window.prompt(title ? `${title}\n\n${message} - 用户名` : `${message} - 用户名`, userName);
16
+ if (u === null) return { result: false, userName: '', password: '' };
17
+ const p = window.prompt(title ? `${title}\n\n${message} - 密码` : `${message} - 密码`, password);
18
+ if (p === null) return { result: false, userName: '', password: '' };
19
+ return { result: true, userName: u, password: p };
20
+ }
21
+
22
+ export async function action(options: string | { message?: string; cancelButtonText?: string; actions?: string[] }, title?: string): Promise<string | undefined> {
23
+ let message = typeof options === 'string' ? options : (options.message || '选择一个操作');
24
+ const actions = typeof options === 'string' ? [] : (options.actions || []);
25
+ const promptText = title ? `${title}\n\n${message}${actions.length ? `\n选项: ${actions.join(', ')}` : ''}` : `${message}${actions.length ? `\n选项: ${actions.join(', ')}` : ''}`;
26
+ const res = window.prompt(promptText);
27
+ if (!res) return undefined;
28
+ if (!actions.length) return res;
29
+ const match = actions.find(a => a.toLowerCase() === res.toLowerCase());
30
+ return match ?? undefined;
31
+ }
@@ -0,0 +1,3 @@
1
+ export { useActionBar } from './useActionBar.js';
2
+ export { usePage } from './usePage.js';
3
+ export { useFrame } from './useFrame.js';
@@ -0,0 +1,4 @@
1
+ export * from './useActionBar';
2
+ export * from './usePage';
3
+ export * from './useFrame';
4
+ export * from './dialogs';
@@ -0,0 +1,7 @@
1
+ import { ref } from 'vue';
2
+
3
+ export function useActionBar() {
4
+ const title = ref('');
5
+ function setTitle(t) { title.value = t; }
6
+ return { title, setTitle };
7
+ }
@@ -0,0 +1,19 @@
1
+ import { Ref, ref } from 'vue';
2
+
3
+ export interface ActionBarState {
4
+ title: Ref<string>;
5
+ setTitle: (value: string) => void;
6
+ }
7
+
8
+ export function useActionBar(): ActionBarState {
9
+ const title = ref('');
10
+
11
+ function setTitle(value: string) {
12
+ title.value = value;
13
+ }
14
+
15
+ return {
16
+ title,
17
+ setTitle
18
+ };
19
+ }
@@ -0,0 +1,8 @@
1
+ import { ref } from 'vue';
2
+
3
+ export function useFrame() {
4
+ const stack = ref([]);
5
+ function push(page) { stack.value.push(page); }
6
+ function pop() { return stack.value.pop(); }
7
+ return { stack, push, pop };
8
+ }