@astrake/lumora-ui 0.1.6 → 0.2.1
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/CHANGELOG.md +141 -92
- package/dist/LuCodeBlock.vue_vue_type_script_setup_true_lang-BjwcjuXF.js +1623 -0
- package/dist/LuEmbeddedStatusBar.vue_vue_type_script_setup_true_lang-CIksvebU.js +218 -0
- package/dist/LuOverlay.vue_vue_type_script_setup_true_lang-DZch4Vrw.js +226 -0
- package/dist/components/LuAlert.vue.d.ts +20 -0
- package/dist/components/LuAvatar.vue.d.ts +19 -0
- package/dist/components/LuBadge.vue.d.ts +16 -0
- package/dist/components/LuBreadcrumb.vue.d.ts +16 -0
- package/dist/components/LuButton.vue.d.ts +24 -0
- package/dist/components/LuCard.vue.d.ts +21 -0
- package/dist/components/LuCheckbox.vue.d.ts +27 -0
- package/dist/components/LuCodeBlock.vue.d.ts +29 -0
- package/dist/components/LuCollapsible.vue.d.ts +25 -0
- package/dist/components/LuDivider.vue.d.ts +8 -0
- package/dist/components/LuForm.types.d.ts +18 -0
- package/dist/components/LuForm.vue.d.ts +55 -0
- package/dist/components/LuIcon.vue.d.ts +18 -0
- package/dist/components/LuInput.vue.d.ts +26 -0
- package/dist/components/LuLink.vue.d.ts +23 -0
- package/dist/components/LuMenu.vue.d.ts +26 -0
- package/dist/components/LuMenuItem.vue.d.ts +20 -0
- package/dist/components/LuModal.vue.d.ts +32 -0
- package/dist/components/LuPageHeader.vue.d.ts +10 -0
- package/dist/components/LuPagination.vue.d.ts +18 -0
- package/dist/components/LuProgressBar.vue.d.ts +7 -0
- package/dist/components/LuRadio.vue.d.ts +18 -0
- package/dist/components/LuRadioGroup.types.d.ts +8 -0
- package/dist/components/LuRadioGroup.vue.d.ts +24 -0
- package/dist/components/LuSelect.vue.d.ts +18 -0
- package/dist/components/LuSkeleton.vue.d.ts +5 -0
- package/dist/components/LuSpinner.vue.d.ts +5 -0
- package/dist/components/LuSwitch.vue.d.ts +15 -0
- package/dist/components/LuTab.vue.d.ts +16 -0
- package/dist/components/LuTabList.vue.d.ts +15 -0
- package/dist/components/LuTabPanel.vue.d.ts +16 -0
- package/dist/components/LuTable.vue.d.ts +15 -0
- package/dist/components/LuTableBody.vue.d.ts +15 -0
- package/dist/components/LuTableCell.vue.d.ts +15 -0
- package/dist/components/LuTableHead.vue.d.ts +15 -0
- package/dist/components/LuTableHeadCell.vue.d.ts +15 -0
- package/dist/components/LuTableRow.vue.d.ts +15 -0
- package/dist/components/LuTabs.vue.d.ts +20 -0
- package/dist/components/LuTag.vue.d.ts +20 -0
- package/dist/components/LuText.vue.d.ts +16 -0
- package/dist/components/LuTextarea.vue.d.ts +14 -0
- package/dist/components/LuThemeSelect.vue.d.ts +2 -0
- package/dist/components/LuThemeSwitch.vue.d.ts +2 -0
- package/dist/components/LuToggleButton.vue.d.ts +16 -0
- package/dist/components/LuToggleGroup.vue.d.ts +20 -0
- package/dist/components/LuTooltip.vue.d.ts +19 -0
- package/dist/components/__tests__/LuForm.test.d.ts +1 -0
- package/{src/components/index.ts → dist/components/index.d.ts} +16 -0
- package/dist/components/index.js +47 -0
- package/{src/composables/index.ts → dist/composables/index.d.ts} +0 -1
- package/dist/composables/index.js +30 -0
- package/dist/composables/useRail.d.ts +6 -0
- package/dist/composables/useSplit.d.ts +4 -0
- package/dist/composables/useTheme.d.ts +7 -0
- package/dist/context-0gENwESP.js +62 -0
- package/dist/context.d.ts +8 -0
- package/{src/index.ts → dist/index.d.ts} +2 -3
- package/dist/index.js +94 -0
- package/dist/layout/LuDock.vue.d.ts +9 -0
- package/dist/layout/LuDockItem.vue.d.ts +16 -0
- package/dist/layout/LuFill.vue.d.ts +21 -0
- package/dist/layout/LuFixed.vue.d.ts +21 -0
- package/dist/layout/LuGrid.vue.d.ts +26 -0
- package/dist/layout/LuOverlay.vue.d.ts +15 -0
- package/dist/layout/LuScroll.vue.d.ts +15 -0
- package/dist/layout/LuSplit.vue.d.ts +16 -0
- package/dist/layout/LuSplitPane.vue.d.ts +18 -0
- package/dist/layout/LuSplitResizer.vue.d.ts +5 -0
- package/dist/layout/LuStack.vue.d.ts +23 -0
- package/{src/layout/index.ts → dist/layout/index.d.ts} +1 -14
- package/dist/layout/index.js +14 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/shell/desktop/LuDesktopRailBar.vue.d.ts +17 -0
- package/dist/shell/desktop/LuDesktopRailItem.vue.d.ts +18 -0
- package/dist/shell/desktop/LuDesktopShell.vue.d.ts +23 -0
- package/dist/shell/desktop/LuDesktopSidebar.vue.d.ts +21 -0
- package/dist/shell/desktop/LuDesktopStatusBar.vue.d.ts +15 -0
- package/dist/shell/desktop/LuDesktopTopBar.vue.d.ts +15 -0
- package/dist/shell/embedded/LuEmbeddedShell.vue.d.ts +19 -0
- package/dist/shell/embedded/LuEmbeddedStatusBar.vue.d.ts +17 -0
- package/dist/shell/embedded/LuEmbeddedTopBar.vue.d.ts +19 -0
- package/{src/shell/index.ts → dist/shell/index.d.ts} +4 -2
- package/dist/shell/index.js +15 -0
- package/dist/shell/mobile/LuMobileHeader.vue.d.ts +19 -0
- package/dist/shell/mobile/LuMobileNavBar.vue.d.ts +15 -0
- package/dist/shell/mobile/LuMobileShell.vue.d.ts +21 -0
- package/dist/skins/default.d.ts +2 -0
- package/dist/skins/index.js +416 -0
- package/dist/tailwind.d.ts +1 -0
- package/dist/tailwind.js +13 -0
- package/dist/types.d.ts +15 -0
- package/dist/useTheme-Cd4wVaLs.js +21 -0
- package/dist/utils.d.ts +21 -0
- package/package.json +94 -61
- package/src/lumora.css +16 -0
- package/src/components/LuAvatar.vue +0 -22
- package/src/components/LuBadge.vue +0 -15
- package/src/components/LuButton.vue +0 -58
- package/src/components/LuCard.vue +0 -20
- package/src/components/LuCollapsible.vue +0 -34
- package/src/components/LuDivider.vue +0 -18
- package/src/components/LuForm.types.ts +0 -24
- package/src/components/LuForm.vue +0 -121
- package/src/components/LuIcon.vue +0 -39
- package/src/components/LuInput.vue +0 -62
- package/src/components/LuLink.vue +0 -47
- package/src/components/LuPageHeader.vue +0 -24
- package/src/components/LuProgressBar.vue +0 -21
- package/src/components/LuSelect.vue +0 -67
- package/src/components/LuSwitch.vue +0 -74
- package/src/components/LuTab.vue +0 -26
- package/src/components/LuTabList.vue +0 -15
- package/src/components/LuTabPanel.vue +0 -19
- package/src/components/LuTable.vue +0 -15
- package/src/components/LuTableBody.vue +0 -15
- package/src/components/LuTableCell.vue +0 -15
- package/src/components/LuTableHead.vue +0 -15
- package/src/components/LuTableHeadCell.vue +0 -15
- package/src/components/LuTableRow.vue +0 -15
- package/src/components/LuTabs.vue +0 -30
- package/src/components/LuText.vue +0 -18
- package/src/components/LuThemeSelect.vue +0 -26
- package/src/components/LuThemeSwitch.vue +0 -22
- package/src/components/LuTooltip.vue +0 -36
- package/src/components/__tests__/LuForm.test.ts +0 -206
- package/src/composables/useRail.ts +0 -24
- package/src/composables/useSplit.ts +0 -17
- package/src/composables/useTheme.ts +0 -36
- package/src/context.ts +0 -36
- package/src/layout/LuDock.vue +0 -23
- package/src/layout/LuDockItem.vue +0 -18
- package/src/layout/LuFill.vue +0 -17
- package/src/layout/LuFixed.vue +0 -17
- package/src/layout/LuGrid.vue +0 -22
- package/src/layout/LuOverlay.vue +0 -17
- package/src/layout/LuScroll.vue +0 -17
- package/src/layout/LuSplit.vue +0 -23
- package/src/layout/LuSplitPane.vue +0 -32
- package/src/layout/LuSplitResizer.vue +0 -17
- package/src/layout/LuStack.vue +0 -24
- package/src/plugin.ts +0 -27
- package/src/shell/desktop/LuDesktopRailBar.vue +0 -23
- package/src/shell/desktop/LuDesktopRailItem.vue +0 -23
- package/src/shell/desktop/LuDesktopShell.vue +0 -25
- package/src/shell/desktop/LuDesktopSidebar.vue +0 -36
- package/src/shell/desktop/LuDesktopStatusBar.vue +0 -15
- package/src/shell/desktop/LuDesktopTopBar.vue +0 -15
- package/src/shell/embedded/LuEmbeddedShell.vue +0 -20
- package/src/shell/mobile/LuMobileShell.vue +0 -21
- package/src/skins/default.ts +0 -94
- package/src/types.ts +0 -18
- package/tsconfig.json +0 -10
- /package/{src/skins/index.ts → dist/skins/index.d.ts} +0 -0
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ClassValue } from "clsx";
|
|
2
|
+
import type { SkinMap } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Merges Tailwind classes intelligently
|
|
5
|
+
*/
|
|
6
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
7
|
+
/**
|
|
8
|
+
* Extends a base skin with a user skin, intelligently merging Tailwind classes
|
|
9
|
+
*/
|
|
10
|
+
export declare function extendSkin(baseSkin: SkinMap, userSkin: SkinMap): SkinMap;
|
|
11
|
+
/**
|
|
12
|
+
* Resolves standard layout props to Tailwind classes statically.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveLayoutProps(props: {
|
|
15
|
+
gap?: string | number;
|
|
16
|
+
padding?: string | number;
|
|
17
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
18
|
+
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
|
|
19
|
+
width?: string;
|
|
20
|
+
height?: string;
|
|
21
|
+
}): string;
|
package/package.json
CHANGED
|
@@ -1,61 +1,94 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@astrake/lumora-ui",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "Headless Vue 3 component framework for three surface targets — Mobile, Desktop, and Embedded — with a unified --lu-* design token system.",
|
|
5
|
-
"author": "Anuvab Chakraborty (https://github.com/madlybong)",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@astrake/lumora-ui",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Headless Vue 3 component framework for three surface targets — Mobile, Desktop, and Embedded — with a unified --lu-* design token system.",
|
|
5
|
+
"author": "Anuvab Chakraborty (https://github.com/madlybong)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./style": "./src/lumora.css",
|
|
17
|
+
"./tailwind": {
|
|
18
|
+
"types": "./dist/tailwind.d.ts",
|
|
19
|
+
"import": "./dist/tailwind.js"
|
|
20
|
+
},
|
|
21
|
+
"./layout": {
|
|
22
|
+
"types": "./dist/layout/index.d.ts",
|
|
23
|
+
"import": "./dist/layout/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./shell": {
|
|
26
|
+
"types": "./dist/shell/index.d.ts",
|
|
27
|
+
"import": "./dist/shell/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./components": {
|
|
30
|
+
"types": "./dist/components/index.d.ts",
|
|
31
|
+
"import": "./dist/components/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./composables": {
|
|
34
|
+
"types": "./dist/composables/index.d.ts",
|
|
35
|
+
"import": "./dist/composables/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./skins": {
|
|
38
|
+
"types": "./dist/skins/index.d.ts",
|
|
39
|
+
"import": "./dist/skins/index.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"vue",
|
|
44
|
+
"vue3",
|
|
45
|
+
"ui",
|
|
46
|
+
"components",
|
|
47
|
+
"mobile",
|
|
48
|
+
"desktop",
|
|
49
|
+
"embedded",
|
|
50
|
+
"headless",
|
|
51
|
+
"design-tokens",
|
|
52
|
+
"lumora",
|
|
53
|
+
"astrake",
|
|
54
|
+
"typescript"
|
|
55
|
+
],
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "https://github.com/madlybong/LumoraUI.git"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://ui.lumora.astrake.com",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/madlybong/LumoraUI/issues"
|
|
63
|
+
},
|
|
64
|
+
"funding": {
|
|
65
|
+
"type": "github",
|
|
66
|
+
"url": "https://github.com/sponsors/madlybong"
|
|
67
|
+
},
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public",
|
|
70
|
+
"registry": "https://registry.npmjs.org/"
|
|
71
|
+
},
|
|
72
|
+
"files": [
|
|
73
|
+
"dist",
|
|
74
|
+
"src/lumora.css",
|
|
75
|
+
"README.md",
|
|
76
|
+
"CHANGELOG.md"
|
|
77
|
+
],
|
|
78
|
+
"scripts": {
|
|
79
|
+
"prepack": "bun run build && bun -e \"await Bun.write('README.md', await Bun.file('../../README.md').text()); await Bun.write('CHANGELOG.md', await Bun.file('../../CHANGELOG.md').text())\"",
|
|
80
|
+
"postpack": "bun -e \"import { unlinkSync } from 'fs'; try { unlinkSync('README.md') } catch(e){} try { unlinkSync('CHANGELOG.md') } catch(e){}\"",
|
|
81
|
+
"build:types": "bun -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\" && bun run vue-tsc -p tsconfig.build.json",
|
|
82
|
+
"build": "bun -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\" && bun run vue-tsc -p tsconfig.build.json && bun run ../../node_modules/vite/bin/vite.js build -c vite.config.ts",
|
|
83
|
+
"check": "vue-tsc -p ./tsconfig.json"
|
|
84
|
+
},
|
|
85
|
+
"peerDependencies": {
|
|
86
|
+
"tailwindcss": "^4.0.0",
|
|
87
|
+
"vue": "^3.5.0"
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"clsx": "^2.1.1",
|
|
91
|
+
"shiki": "^4.0.2",
|
|
92
|
+
"tailwind-merge": "^3.5.0"
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/lumora.css
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* LumoraUI structural baseline — Tailwind v4 Escape Hatch, v0.1.7+ */
|
|
2
|
+
/* Consumers MUST import this: import '@astrake/lumora-ui/style' */
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
With the transition to Tailwind v4 as the native design engine,
|
|
6
|
+
all structural layout classes (e.g., .lu-button, .lu-stack) have been removed.
|
|
7
|
+
Layout structure is now provided by the defaultSkin (`default.ts`) out of the box.
|
|
8
|
+
|
|
9
|
+
This file serves as an escape hatch for:
|
|
10
|
+
1. Complex [data-state="..."] selector combinations.
|
|
11
|
+
2. Webkit scrollbar pseudoclasses.
|
|
12
|
+
3. Keyframe animations that Tailwind v4 cannot natively express.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* Example: Webkit Scrollbar overrides can go here */
|
|
16
|
+
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div v-bind="$attrs" :class="containerSkin" :data-size="size">
|
|
3
|
-
<img v-if="src && !hasError" :src="src" :alt="alt" :class="imageSkin" @error="hasError = true" />
|
|
4
|
-
<div v-else :class="fallbackSkin">
|
|
5
|
-
<slot>{{ fallback }}</slot>
|
|
6
|
-
</div>
|
|
7
|
-
</div>
|
|
8
|
-
</template>
|
|
9
|
-
|
|
10
|
-
<script setup lang="ts">
|
|
11
|
-
import { computed, ref } from "vue";
|
|
12
|
-
import { useLumoraConfig } from "../context";
|
|
13
|
-
|
|
14
|
-
const props = defineProps<{ variant?: string; src?: string; fallback?: string; alt?: string; size?: string }>();
|
|
15
|
-
|
|
16
|
-
const hasError = ref(false);
|
|
17
|
-
|
|
18
|
-
const { resolveSkin } = useLumoraConfig();
|
|
19
|
-
const containerSkin = computed(() => resolveSkin("LuAvatar", props.variant));
|
|
20
|
-
const imageSkin = computed(() => resolveSkin("LuAvatarImage", props.variant));
|
|
21
|
-
const fallbackSkin = computed(() => resolveSkin("LuAvatarFallback", props.variant));
|
|
22
|
-
</script>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<component :is="as || 'span'" v-bind="$attrs" :class="resolvedSkin">
|
|
3
|
-
<slot />
|
|
4
|
-
</component>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
import { computed } from "vue";
|
|
9
|
-
import { useLumoraConfig } from "../context";
|
|
10
|
-
|
|
11
|
-
const props = defineProps<{ variant?: string; as?: string }>();
|
|
12
|
-
|
|
13
|
-
const { resolveSkin } = useLumoraConfig();
|
|
14
|
-
const resolvedSkin = computed(() => resolveSkin("LuBadge", props.variant));
|
|
15
|
-
</script>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<component
|
|
3
|
-
:is="componentType"
|
|
4
|
-
v-bind="bindingProps"
|
|
5
|
-
:class="resolvedSkin"
|
|
6
|
-
@click="emit('click', $event)"
|
|
7
|
-
>
|
|
8
|
-
<slot />
|
|
9
|
-
</component>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
<script setup lang="ts">
|
|
13
|
-
import { computed, resolveComponent, useAttrs } from "vue";
|
|
14
|
-
import { useLumoraConfig } from "../context";
|
|
15
|
-
|
|
16
|
-
const props = defineProps<{
|
|
17
|
-
type?: "button" | "submit" | "reset";
|
|
18
|
-
disabled?: boolean;
|
|
19
|
-
variant?: string;
|
|
20
|
-
as?: string;
|
|
21
|
-
to?: any;
|
|
22
|
-
href?: string;
|
|
23
|
-
}>();
|
|
24
|
-
|
|
25
|
-
const emit = defineEmits<{
|
|
26
|
-
(e: "click", event: MouseEvent): void;
|
|
27
|
-
}>();
|
|
28
|
-
|
|
29
|
-
const componentType = computed(() => {
|
|
30
|
-
if (props.as) return props.as;
|
|
31
|
-
if (props.to) {
|
|
32
|
-
const routerLink = resolveComponent("RouterLink");
|
|
33
|
-
return typeof routerLink === 'string' ? 'a' : routerLink;
|
|
34
|
-
}
|
|
35
|
-
if (props.href) return "a";
|
|
36
|
-
return "button";
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const bindingProps = computed(() => {
|
|
40
|
-
const p: any = { ...props, ...useAttrs() };
|
|
41
|
-
delete p.variant;
|
|
42
|
-
delete p.as;
|
|
43
|
-
|
|
44
|
-
if (componentType.value !== 'button') {
|
|
45
|
-
delete p.type;
|
|
46
|
-
}
|
|
47
|
-
if (props.disabled && componentType.value !== 'button') {
|
|
48
|
-
// Buttons can be natively disabled, but links cannot easily.
|
|
49
|
-
// However, if disabled is true, we keep it so CSS can style it.
|
|
50
|
-
// To prevent click navigation on disabled links, we would need to handle the click event.
|
|
51
|
-
// For now, we pass it down so styling works.
|
|
52
|
-
}
|
|
53
|
-
return p;
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const { resolveSkin } = useLumoraConfig();
|
|
57
|
-
const resolvedSkin = computed(() => resolveSkin("LuButton", props.variant));
|
|
58
|
-
</script>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<component :is="as" v-bind="$attrs" :class="resolvedSkin">
|
|
3
|
-
<slot />
|
|
4
|
-
</component>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
import { computed } from "vue";
|
|
9
|
-
import { useLumoraConfig } from "../context";
|
|
10
|
-
|
|
11
|
-
const props = withDefaults(defineProps<{
|
|
12
|
-
variant?: string;
|
|
13
|
-
as?: string;
|
|
14
|
-
}>(), {
|
|
15
|
-
as: "div"
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const { resolveSkin } = useLumoraConfig();
|
|
19
|
-
const resolvedSkin = computed(() => resolveSkin("LuCard", props.variant));
|
|
20
|
-
</script>
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div v-bind="$attrs" :class="wrapperSkin">
|
|
3
|
-
<button :class="triggerSkin" @click="toggle">
|
|
4
|
-
<slot name="trigger" :isOpen="isOpen" />
|
|
5
|
-
</button>
|
|
6
|
-
<div v-show="isOpen" :class="contentSkin">
|
|
7
|
-
<slot name="content" />
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
<script setup lang="ts">
|
|
13
|
-
import { computed, ref, watch } from "vue";
|
|
14
|
-
import { useLumoraConfig } from "../context";
|
|
15
|
-
|
|
16
|
-
const props = defineProps<{ variant?: string; modelValue?: boolean; defaultOpen?: boolean }>();
|
|
17
|
-
const emit = defineEmits<{ (e: "update:modelValue", val: boolean): void }>();
|
|
18
|
-
|
|
19
|
-
const isOpen = ref(props.modelValue ?? props.defaultOpen ?? false);
|
|
20
|
-
|
|
21
|
-
watch(() => props.modelValue, (val) => {
|
|
22
|
-
if (val !== undefined) isOpen.value = val;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const toggle = () => {
|
|
26
|
-
isOpen.value = !isOpen.value;
|
|
27
|
-
emit("update:modelValue", isOpen.value);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const { resolveSkin } = useLumoraConfig();
|
|
31
|
-
const wrapperSkin = computed(() => resolveSkin("LuCollapsible", props.variant));
|
|
32
|
-
const triggerSkin = computed(() => resolveSkin("LuCollapsibleTrigger", props.variant));
|
|
33
|
-
const contentSkin = computed(() => resolveSkin("LuCollapsibleContent", props.variant));
|
|
34
|
-
</script>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div v-bind="$attrs" :class="resolvedSkin"></div>
|
|
3
|
-
</template>
|
|
4
|
-
|
|
5
|
-
<script setup lang="ts">
|
|
6
|
-
import { computed } from "vue";
|
|
7
|
-
import { useLumoraConfig } from "../context";
|
|
8
|
-
|
|
9
|
-
const props = withDefaults(defineProps<{
|
|
10
|
-
variant?: string;
|
|
11
|
-
orientation?: "horizontal" | "vertical";
|
|
12
|
-
}>(), {
|
|
13
|
-
orientation: "horizontal"
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const { resolveSkin } = useLumoraConfig();
|
|
17
|
-
const resolvedSkin = computed(() => resolveSkin("LuDivider", props.variant || props.orientation));
|
|
18
|
-
</script>
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { InjectionKey, Ref } from "vue";
|
|
2
|
-
|
|
3
|
-
export type LuFormValidator = (value: unknown) => string | null | Promise<string | null>;
|
|
4
|
-
|
|
5
|
-
export type LuFormRules = Record<string, LuFormValidator | LuFormValidator[]>;
|
|
6
|
-
|
|
7
|
-
export type LuFormErrors = Record<string, string>;
|
|
8
|
-
|
|
9
|
-
export interface LuFormFieldRegistration {
|
|
10
|
-
name: string;
|
|
11
|
-
getValue: () => unknown;
|
|
12
|
-
setValue: (v: unknown) => void;
|
|
13
|
-
setError: (msg: string | null) => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const LuFormContextKey = Symbol("LuFormContext") as InjectionKey<LuFormContext>;
|
|
17
|
-
|
|
18
|
-
export interface LuFormContext {
|
|
19
|
-
register(field: LuFormFieldRegistration): void;
|
|
20
|
-
unregister(name: string): void;
|
|
21
|
-
getError(name: string): string | null;
|
|
22
|
-
validateOn: Readonly<Ref<"submit" | "blur" | "both">>;
|
|
23
|
-
disabled: Readonly<Ref<boolean>>;
|
|
24
|
-
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<form @submit.prevent="handleSubmit" @reset.prevent="handleReset">
|
|
3
|
-
<slot />
|
|
4
|
-
<slot
|
|
5
|
-
name="errors"
|
|
6
|
-
:errors="errors"
|
|
7
|
-
:has-errors="hasErrors"
|
|
8
|
-
/>
|
|
9
|
-
<slot
|
|
10
|
-
name="actions"
|
|
11
|
-
:submit="handleSubmit"
|
|
12
|
-
:reset="handleReset"
|
|
13
|
-
:pending="pending"
|
|
14
|
-
/>
|
|
15
|
-
</form>
|
|
16
|
-
</template>
|
|
17
|
-
|
|
18
|
-
<script setup lang="ts">
|
|
19
|
-
import { ref, computed, provide, readonly } from "vue";
|
|
20
|
-
import type { LuFormRules, LuFormErrors, LuFormFieldRegistration, LuFormContext } from "./LuForm.types";
|
|
21
|
-
import { LuFormContextKey } from "./LuForm.types";
|
|
22
|
-
|
|
23
|
-
const props = withDefaults(defineProps<{
|
|
24
|
-
rules?: LuFormRules;
|
|
25
|
-
validateOn?: "submit" | "blur" | "both";
|
|
26
|
-
resetOnSubmit?: boolean;
|
|
27
|
-
disabled?: boolean;
|
|
28
|
-
}>(), {
|
|
29
|
-
rules: () => ({}),
|
|
30
|
-
validateOn: "submit",
|
|
31
|
-
resetOnSubmit: false,
|
|
32
|
-
disabled: false,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const emit = defineEmits<{
|
|
36
|
-
(e: "submit", values: Record<string, unknown>): void;
|
|
37
|
-
(e: "reset"): void;
|
|
38
|
-
(e: "error", errors: LuFormErrors): void;
|
|
39
|
-
}>();
|
|
40
|
-
|
|
41
|
-
const fields = new Map<string, LuFormFieldRegistration>();
|
|
42
|
-
const errors = ref<LuFormErrors>({});
|
|
43
|
-
const pending = ref(false);
|
|
44
|
-
const hasErrors = computed(() => Object.keys(errors.value).length > 0);
|
|
45
|
-
|
|
46
|
-
async function validate(): Promise<boolean> {
|
|
47
|
-
const nextErrors: LuFormErrors = {};
|
|
48
|
-
|
|
49
|
-
for (const [name, field] of fields) {
|
|
50
|
-
const rule = props.rules?.[name];
|
|
51
|
-
if (!rule) continue;
|
|
52
|
-
|
|
53
|
-
const validators = Array.isArray(rule) ? rule : [rule];
|
|
54
|
-
const value = field.getValue();
|
|
55
|
-
|
|
56
|
-
for (const validator of validators) {
|
|
57
|
-
const result = await validator(value);
|
|
58
|
-
if (result) {
|
|
59
|
-
nextErrors[name] = result;
|
|
60
|
-
field.setError(result);
|
|
61
|
-
break;
|
|
62
|
-
} else {
|
|
63
|
-
field.setError(null);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
errors.value = nextErrors;
|
|
69
|
-
return Object.keys(nextErrors).length === 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function handleSubmit() {
|
|
73
|
-
pending.value = true;
|
|
74
|
-
try {
|
|
75
|
-
const valid = await validate();
|
|
76
|
-
if (!valid) {
|
|
77
|
-
emit("error", errors.value);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const values: Record<string, unknown> = {};
|
|
81
|
-
for (const [name, field] of fields) {
|
|
82
|
-
values[name] = field.getValue();
|
|
83
|
-
}
|
|
84
|
-
emit("submit", values);
|
|
85
|
-
if (props.resetOnSubmit) handleReset();
|
|
86
|
-
} finally {
|
|
87
|
-
pending.value = false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function handleReset() {
|
|
92
|
-
errors.value = {};
|
|
93
|
-
for (const field of fields.values()) {
|
|
94
|
-
field.setValue(undefined);
|
|
95
|
-
field.setError(null);
|
|
96
|
-
}
|
|
97
|
-
emit("reset");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const context: LuFormContext = {
|
|
101
|
-
register(field) { fields.set(field.name, field); },
|
|
102
|
-
unregister(name) { fields.delete(name); },
|
|
103
|
-
getError(name) { return errors.value[name] ?? null; },
|
|
104
|
-
validateOn: computed(() => props.validateOn),
|
|
105
|
-
disabled: computed(() => props.disabled),
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
provide(LuFormContextKey, context);
|
|
109
|
-
|
|
110
|
-
defineExpose({
|
|
111
|
-
submit: handleSubmit,
|
|
112
|
-
reset: handleReset,
|
|
113
|
-
errors: readonly(errors),
|
|
114
|
-
pending: readonly(pending),
|
|
115
|
-
values: computed(() => {
|
|
116
|
-
const v: Record<string, unknown> = {};
|
|
117
|
-
for (const [name, field] of fields) v[name] = field.getValue();
|
|
118
|
-
return v;
|
|
119
|
-
}),
|
|
120
|
-
});
|
|
121
|
-
</script>
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<span v-bind="$attrs" :class="resolvedSkin" aria-hidden="true" :style="sizeStyle">
|
|
3
|
-
<slot>
|
|
4
|
-
<component
|
|
5
|
-
v-if="resolvedIcon"
|
|
6
|
-
:is="resolvedIcon"
|
|
7
|
-
:size="size"
|
|
8
|
-
:stroke-width="strokeWidth"
|
|
9
|
-
/>
|
|
10
|
-
</slot>
|
|
11
|
-
</span>
|
|
12
|
-
</template>
|
|
13
|
-
|
|
14
|
-
<script setup lang="ts">
|
|
15
|
-
import { computed, useSlots } from "vue";
|
|
16
|
-
import { useLumoraConfig } from "../context";
|
|
17
|
-
|
|
18
|
-
const props = defineProps<{
|
|
19
|
-
variant?: string;
|
|
20
|
-
name?: string;
|
|
21
|
-
size?: number;
|
|
22
|
-
strokeWidth?: number;
|
|
23
|
-
}>();
|
|
24
|
-
|
|
25
|
-
const slots = useSlots();
|
|
26
|
-
const { resolveSkin, resolveIcon } = useLumoraConfig();
|
|
27
|
-
|
|
28
|
-
const resolvedSkin = computed(() => resolveSkin("LuIcon", props.variant));
|
|
29
|
-
|
|
30
|
-
const resolvedIcon = computed(() => {
|
|
31
|
-
if (slots.default) return null;
|
|
32
|
-
if (!props.name) return null;
|
|
33
|
-
return resolveIcon(props.name, props.size);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const sizeStyle = computed(() =>
|
|
37
|
-
props.size ? { width: `${props.size}px`, height: `${props.size}px` } : undefined
|
|
38
|
-
);
|
|
39
|
-
</script>
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<input
|
|
3
|
-
v-bind="$attrs"
|
|
4
|
-
:class="resolvedSkin"
|
|
5
|
-
:value="modelValue"
|
|
6
|
-
:name="name"
|
|
7
|
-
:disabled="formContext?.disabled.value"
|
|
8
|
-
@input="onInput"
|
|
9
|
-
@blur="onBlur"
|
|
10
|
-
/>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
|
-
<script setup lang="ts">
|
|
14
|
-
import { computed, inject, onMounted, onUnmounted, ref } from "vue";
|
|
15
|
-
import { useLumoraConfig } from "../context";
|
|
16
|
-
import { LuFormContextKey } from "./LuForm.types";
|
|
17
|
-
|
|
18
|
-
const props = defineProps<{
|
|
19
|
-
modelValue?: string | number;
|
|
20
|
-
variant?: string;
|
|
21
|
-
name?: string;
|
|
22
|
-
error?: string | null;
|
|
23
|
-
}>();
|
|
24
|
-
|
|
25
|
-
const emit = defineEmits<{
|
|
26
|
-
(e: "update:modelValue", value: string): void;
|
|
27
|
-
(e: "blur"): void;
|
|
28
|
-
}>();
|
|
29
|
-
|
|
30
|
-
const { resolveSkin } = useLumoraConfig();
|
|
31
|
-
const resolvedSkin = computed(() => resolveSkin("LuInput", props.variant));
|
|
32
|
-
|
|
33
|
-
const formContext = inject(LuFormContextKey, null);
|
|
34
|
-
const internalValue = ref<string | number | undefined>(props.modelValue);
|
|
35
|
-
|
|
36
|
-
const onInput = (event: Event) => {
|
|
37
|
-
const value = (event.target as HTMLInputElement).value;
|
|
38
|
-
internalValue.value = value;
|
|
39
|
-
emit("update:modelValue", value);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const onBlur = () => {
|
|
43
|
-
if (props.name && formContext && (formContext.validateOn.value === "blur" || formContext.validateOn.value === "both")) {
|
|
44
|
-
// trigger single-field validation — handled by parent LuForm
|
|
45
|
-
}
|
|
46
|
-
emit("blur");
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
onMounted(() => {
|
|
50
|
-
if (!props.name || !formContext) return;
|
|
51
|
-
formContext.register({
|
|
52
|
-
name: props.name,
|
|
53
|
-
getValue: () => internalValue.value,
|
|
54
|
-
setValue: (v) => { internalValue.value = v as string; },
|
|
55
|
-
setError: (_msg) => { /* error display handled via formContext.getError in template if desired */ },
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
onUnmounted(() => {
|
|
60
|
-
if (props.name && formContext) formContext.unregister(props.name);
|
|
61
|
-
});
|
|
62
|
-
</script>
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<component
|
|
3
|
-
:is="componentType"
|
|
4
|
-
v-bind="bindingProps"
|
|
5
|
-
:class="resolvedSkin"
|
|
6
|
-
@click="emit('click', $event)"
|
|
7
|
-
>
|
|
8
|
-
<slot />
|
|
9
|
-
</component>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
<script setup lang="ts">
|
|
13
|
-
import { computed, resolveComponent } from "vue";
|
|
14
|
-
import { useLumoraConfig } from "../context";
|
|
15
|
-
|
|
16
|
-
const props = defineProps<{
|
|
17
|
-
variant?: string;
|
|
18
|
-
as?: string;
|
|
19
|
-
to?: any;
|
|
20
|
-
href?: string;
|
|
21
|
-
target?: string;
|
|
22
|
-
}>();
|
|
23
|
-
|
|
24
|
-
const emit = defineEmits<{
|
|
25
|
-
(e: "click", event: MouseEvent): void;
|
|
26
|
-
}>();
|
|
27
|
-
|
|
28
|
-
const componentType = computed(() => {
|
|
29
|
-
if (props.as) return props.as;
|
|
30
|
-
if (props.to) {
|
|
31
|
-
// Attempt to resolve RouterLink if available, otherwise fallback to 'a'
|
|
32
|
-
const routerLink = resolveComponent("RouterLink");
|
|
33
|
-
return typeof routerLink === 'string' ? 'a' : routerLink;
|
|
34
|
-
}
|
|
35
|
-
return "a";
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const bindingProps = computed(() => {
|
|
39
|
-
const p: any = { ...props };
|
|
40
|
-
delete p.variant;
|
|
41
|
-
delete p.as;
|
|
42
|
-
return p;
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const { resolveSkin } = useLumoraConfig();
|
|
46
|
-
const resolvedSkin = computed(() => resolveSkin("LuLink", props.variant));
|
|
47
|
-
</script>
|