@astrake/lumora-ui 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -1
- package/package.json +9 -1
- package/src/components/LuAlert.vue +33 -0
- package/src/components/LuBreadcrumb.vue +63 -0
- package/src/components/LuCard.vue +8 -1
- package/src/components/LuCheckbox.vue +94 -0
- package/src/components/LuCodeBlock.vue +168 -0
- package/src/components/LuForm.types.ts +24 -0
- package/src/components/LuForm.vue +121 -0
- package/src/components/LuInput.vue +57 -5
- package/src/components/LuMenu.vue +86 -0
- package/src/components/LuMenuItem.vue +37 -0
- package/src/components/LuModal.vue +115 -0
- package/src/components/LuPagination.vue +118 -0
- package/src/components/LuRadio.vue +55 -0
- package/src/components/LuRadioGroup.types.ts +10 -0
- package/src/components/LuRadioGroup.vue +66 -0
- package/src/components/LuSelect.vue +38 -6
- package/src/components/LuSkeleton.vue +15 -0
- package/src/components/LuSpinner.vue +36 -0
- package/src/components/LuSwitch.vue +48 -12
- package/src/components/LuTag.vue +35 -0
- package/src/components/LuTextarea.vue +62 -0
- package/src/components/LuThemeSelect.vue +1 -1
- package/src/components/LuToggleButton.vue +35 -0
- package/src/components/LuToggleGroup.vue +27 -0
- package/src/components/__tests__/LuForm.test.ts +206 -0
- package/src/components/index.ts +18 -0
- package/src/context.ts +8 -5
- package/src/index.ts +2 -2
- package/src/layout/LuDock.vue +53 -20
- package/src/layout/LuDockItem.vue +3 -1
- package/src/layout/LuFill.vue +15 -5
- package/src/layout/LuFixed.vue +15 -5
- package/src/layout/LuGrid.vue +28 -5
- package/src/layout/LuScroll.vue +3 -1
- package/src/layout/LuSplitPane.vue +3 -3
- package/src/layout/LuSplitResizer.vue +5 -3
- package/src/layout/LuStack.vue +16 -11
- package/src/lumora.css +16 -0
- package/src/plugin.ts +3 -2
- package/src/shell/desktop/LuDesktopRailItem.vue +2 -2
- package/src/shell/desktop/LuDesktopShell.vue +3 -3
- package/src/shell/embedded/LuEmbeddedShell.vue +2 -2
- package/src/shell/embedded/LuEmbeddedStatusBar.vue +16 -0
- package/src/shell/embedded/LuEmbeddedTopBar.vue +17 -0
- package/src/shell/index.ts +4 -1
- package/src/shell/mobile/LuMobileHeader.vue +17 -0
- package/src/shell/mobile/LuMobileNavBar.vue +15 -0
- package/src/shell/mobile/LuMobileShell.vue +2 -2
- package/src/skins/default.ts +361 -29
- package/src/tailwind.ts +25 -0
- package/src/utils.ts +95 -0
package/src/layout/LuFill.vue
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<component :is="as" v-bind="$attrs" :class="resolvedSkin">
|
|
3
3
|
<slot />
|
|
4
|
-
</
|
|
4
|
+
</component>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
import { computed } from "vue";
|
|
9
9
|
import { useLumoraConfig } from "../context";
|
|
10
|
+
import { resolveLayoutProps, cn } from "../utils";
|
|
10
11
|
|
|
11
|
-
const props = defineProps<{
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
12
13
|
variant?: string;
|
|
13
|
-
|
|
14
|
+
as?: string;
|
|
15
|
+
width?: string;
|
|
16
|
+
height?: string;
|
|
17
|
+
padding?: string | number;
|
|
18
|
+
}>(), {
|
|
19
|
+
as: 'div'
|
|
20
|
+
});
|
|
14
21
|
|
|
15
22
|
const { resolveSkin } = useLumoraConfig();
|
|
16
|
-
const resolvedSkin = computed(() =>
|
|
23
|
+
const resolvedSkin = computed(() => cn(
|
|
24
|
+
resolveSkin("LuFill", props.variant),
|
|
25
|
+
resolveLayoutProps(props)
|
|
26
|
+
));
|
|
17
27
|
</script>
|
package/src/layout/LuFixed.vue
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<component :is="as" v-bind="$attrs" :class="resolvedSkin">
|
|
3
3
|
<slot />
|
|
4
|
-
</
|
|
4
|
+
</component>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
import { computed } from "vue";
|
|
9
9
|
import { useLumoraConfig } from "../context";
|
|
10
|
+
import { resolveLayoutProps, cn } from "../utils";
|
|
10
11
|
|
|
11
|
-
const props = defineProps<{
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
12
13
|
variant?: string;
|
|
13
|
-
|
|
14
|
+
as?: string;
|
|
15
|
+
width?: string;
|
|
16
|
+
height?: string;
|
|
17
|
+
padding?: string | number;
|
|
18
|
+
}>(), {
|
|
19
|
+
as: 'div'
|
|
20
|
+
});
|
|
14
21
|
|
|
15
22
|
const { resolveSkin } = useLumoraConfig();
|
|
16
|
-
const resolvedSkin = computed(() =>
|
|
23
|
+
const resolvedSkin = computed(() => cn(
|
|
24
|
+
resolveSkin("LuFixed", props.variant),
|
|
25
|
+
resolveLayoutProps(props)
|
|
26
|
+
));
|
|
17
27
|
</script>
|
package/src/layout/LuGrid.vue
CHANGED
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<component :is="as" v-bind="$attrs" :class="resolvedSkin" :style="gridStyle">
|
|
3
3
|
<slot />
|
|
4
|
-
</
|
|
4
|
+
</component>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
import { computed } from "vue";
|
|
9
9
|
import { useLumoraConfig } from "../context";
|
|
10
|
+
import { resolveLayoutProps, cn } from "../utils";
|
|
10
11
|
|
|
11
|
-
const props = defineProps<{
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
12
13
|
cols?: number;
|
|
14
|
+
smCols?: number;
|
|
15
|
+
mdCols?: number;
|
|
16
|
+
lgCols?: number;
|
|
13
17
|
variant?: string;
|
|
14
|
-
|
|
18
|
+
as?: string;
|
|
19
|
+
gap?: string | number;
|
|
20
|
+
padding?: string | number;
|
|
21
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
22
|
+
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
|
|
23
|
+
}>(), {
|
|
24
|
+
as: 'div'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const colsClass = computed(() => {
|
|
28
|
+
const map: Record<number, string> = {1:'grid-cols-1',2:'grid-cols-2',3:'grid-cols-3',4:'grid-cols-4',5:'grid-cols-5',6:'grid-cols-6',12:'grid-cols-12'};
|
|
29
|
+
const sm = props.smCols && map[props.smCols] ? `sm:${map[props.smCols]}` : '';
|
|
30
|
+
const md = props.mdCols && map[props.mdCols] ? `md:${map[props.mdCols]}` : '';
|
|
31
|
+
const lg = props.lgCols && map[props.lgCols] ? `lg:${map[props.lgCols]}` : '';
|
|
32
|
+
return [sm, md, lg].filter(Boolean).join(' ');
|
|
33
|
+
});
|
|
15
34
|
|
|
16
35
|
const { resolveSkin } = useLumoraConfig();
|
|
17
|
-
const resolvedSkin = computed(() =>
|
|
36
|
+
const resolvedSkin = computed(() => cn(
|
|
37
|
+
resolveSkin("LuGrid", props.variant),
|
|
38
|
+
resolveLayoutProps(props),
|
|
39
|
+
colsClass.value
|
|
40
|
+
));
|
|
18
41
|
|
|
19
42
|
const gridStyle = computed(() =>
|
|
20
43
|
props.cols ? { gridTemplateColumns: `repeat(${props.cols}, minmax(0, 1fr))` } : {}
|
package/src/layout/LuScroll.vue
CHANGED
|
@@ -13,5 +13,7 @@ const props = defineProps<{
|
|
|
13
13
|
}>();
|
|
14
14
|
|
|
15
15
|
const { resolveSkin } = useLumoraConfig();
|
|
16
|
-
const resolvedSkin = computed(() =>
|
|
16
|
+
const resolvedSkin = computed(() => [
|
|
17
|
+
resolveSkin("LuScroll", props.variant)
|
|
18
|
+
]);
|
|
17
19
|
</script>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
|
-
import { computed, inject, ref } from "vue";
|
|
8
|
+
import { computed, inject, ref, unref, type Ref } from "vue";
|
|
9
9
|
import { useLumoraConfig } from "../context";
|
|
10
10
|
|
|
11
11
|
const props = defineProps<{
|
|
@@ -15,13 +15,13 @@ const props = defineProps<{
|
|
|
15
15
|
variant?: string;
|
|
16
16
|
}>();
|
|
17
17
|
|
|
18
|
-
const direction = inject<"horizontal" | "vertical">("lu-split-direction", "horizontal");
|
|
18
|
+
const direction = inject<Ref<"horizontal" | "vertical"> | "horizontal">("lu-split-direction", "horizontal");
|
|
19
19
|
const size = ref(props.defaultSize);
|
|
20
20
|
|
|
21
21
|
const style = computed(() => {
|
|
22
22
|
if (size.value === undefined) return { flex: "1 1 0%" };
|
|
23
23
|
const dim = `${size.value}px`;
|
|
24
|
-
return direction === "horizontal"
|
|
24
|
+
return unref(direction) === "horizontal"
|
|
25
25
|
? { width: dim, flex: `0 0 ${dim}` }
|
|
26
26
|
: { height: dim, flex: `0 0 ${dim}` };
|
|
27
27
|
});
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script setup lang="ts">
|
|
6
|
-
import { computed, inject } from "vue";
|
|
6
|
+
import { computed, inject, unref, type Ref } from "vue";
|
|
7
7
|
import { useLumoraConfig } from "../context";
|
|
8
8
|
|
|
9
9
|
const props = defineProps<{
|
|
10
10
|
variant?: string;
|
|
11
11
|
}>();
|
|
12
12
|
|
|
13
|
-
const direction = inject<"horizontal" | "vertical">("lu-split-direction", "horizontal");
|
|
13
|
+
const direction = inject<Ref<"horizontal" | "vertical"> | "horizontal">("lu-split-direction", "horizontal");
|
|
14
14
|
|
|
15
15
|
const { resolveSkin } = useLumoraConfig();
|
|
16
|
-
const resolvedSkin = computed(() =>
|
|
16
|
+
const resolvedSkin = computed(() => [
|
|
17
|
+
resolveSkin("LuSplitResizer", unref(direction) === "horizontal" ? "horizontal" : "vertical")
|
|
18
|
+
]);
|
|
17
19
|
</script>
|
package/src/layout/LuStack.vue
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<component :is="as" v-bind="$attrs" :class="resolvedSkin">
|
|
3
3
|
<slot />
|
|
4
|
-
</
|
|
4
|
+
</component>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
import { computed } from "vue";
|
|
9
9
|
import { useLumoraConfig } from "../context";
|
|
10
|
+
import { resolveLayoutProps, cn } from "../utils";
|
|
10
11
|
|
|
11
|
-
const props = defineProps<{
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
12
13
|
direction?: "vertical" | "horizontal";
|
|
13
14
|
variant?: string;
|
|
14
|
-
|
|
15
|
+
as?: string;
|
|
16
|
+
gap?: string | number;
|
|
17
|
+
padding?: string | number;
|
|
18
|
+
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
19
|
+
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
|
|
20
|
+
}>(), {
|
|
21
|
+
as: 'div'
|
|
22
|
+
});
|
|
15
23
|
|
|
16
24
|
const { resolveSkin } = useLumoraConfig();
|
|
17
|
-
const resolvedSkin = computed(() =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (props.direction === "horizontal") extra = " flex-row";
|
|
22
|
-
return base + extra;
|
|
23
|
-
});
|
|
25
|
+
const resolvedSkin = computed(() => cn(
|
|
26
|
+
resolveSkin("LuStack", props.direction ?? props.variant),
|
|
27
|
+
resolveLayoutProps(props)
|
|
28
|
+
));
|
|
24
29
|
</script>
|
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
|
+
|
package/src/plugin.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { App, Plugin } from "vue";
|
|
2
|
+
import { shallowReactive } from "vue";
|
|
2
3
|
import { LumoraUIConfigKey } from "./context";
|
|
3
4
|
import type { LumoraUIConfig } from "./types";
|
|
4
5
|
|
|
@@ -9,13 +10,13 @@ export interface LumoraUIPluginOptions extends LumoraUIConfig {
|
|
|
9
10
|
export function createLumoraUI(options: LumoraUIPluginOptions = {}): Plugin {
|
|
10
11
|
return {
|
|
11
12
|
install(app: App) {
|
|
12
|
-
const config
|
|
13
|
+
const config = shallowReactive<LumoraUIConfig>({
|
|
13
14
|
target: options.target ?? "desktop",
|
|
14
15
|
skin: options.skin,
|
|
15
16
|
locale: options.locale ?? "en-US",
|
|
16
17
|
a11y: options.a11y ?? true,
|
|
17
18
|
icons: options.icons,
|
|
18
|
-
};
|
|
19
|
+
});
|
|
19
20
|
|
|
20
21
|
app.provide(LumoraUIConfigKey, config);
|
|
21
22
|
|
|
@@ -18,6 +18,6 @@ const props = defineProps<{ variant?: string; active?: boolean }>();
|
|
|
18
18
|
const { resolveSkin } = useLumoraConfig();
|
|
19
19
|
const resolvedSkin = computed(() => resolveSkin("LuDesktopRailItem", props.variant));
|
|
20
20
|
const activeSkin = computed(() => resolveSkin("LuDesktopRailItem", "active"));
|
|
21
|
-
const iconSkin = computed(() => resolveSkin("LuDesktopRailItemIcon", props.variant)
|
|
22
|
-
const labelSkin = computed(() => resolveSkin("LuDesktopRailItemLabel", props.variant)
|
|
21
|
+
const iconSkin = computed(() => resolveSkin("LuDesktopRailItemIcon", props.variant));
|
|
22
|
+
const labelSkin = computed(() => resolveSkin("LuDesktopRailItemLabel", props.variant));
|
|
23
23
|
</script>
|
|
@@ -19,7 +19,7 @@ import { useLumoraConfig } from "../../context";
|
|
|
19
19
|
const props = defineProps<{ variant?: string }>();
|
|
20
20
|
|
|
21
21
|
const { resolveSkin } = useLumoraConfig();
|
|
22
|
-
const resolvedSkin = computed(() => resolveSkin("LuDesktopShell", props.variant)
|
|
23
|
-
const contentWrapperSkin = computed(() => resolveSkin("LuDesktopShellContentWrapper")
|
|
24
|
-
const mainContentSkin = computed(() => resolveSkin("LuDesktopShellMainContent")
|
|
22
|
+
const resolvedSkin = computed(() => resolveSkin("LuDesktopShell", props.variant));
|
|
23
|
+
const contentWrapperSkin = computed(() => resolveSkin("LuDesktopShellContentWrapper"));
|
|
24
|
+
const mainContentSkin = computed(() => resolveSkin("LuDesktopShellMainContent"));
|
|
25
25
|
</script>
|
|
@@ -15,6 +15,6 @@ import { useLumoraConfig } from "../../context";
|
|
|
15
15
|
const props = defineProps<{ variant?: string }>();
|
|
16
16
|
|
|
17
17
|
const { resolveSkin } = useLumoraConfig();
|
|
18
|
-
const resolvedSkin = computed(() => resolveSkin("LuEmbeddedShell", props.variant)
|
|
19
|
-
const contentSkin = computed(() => resolveSkin("LuEmbeddedShellContent", props.variant)
|
|
18
|
+
const resolvedSkin = computed(() => resolveSkin("LuEmbeddedShell", props.variant));
|
|
19
|
+
const contentSkin = computed(() => resolveSkin("LuEmbeddedShellContent", props.variant));
|
|
20
20
|
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-bind="$attrs" :class="resolvedSkin">
|
|
3
|
+
<slot name="left" />
|
|
4
|
+
<slot name="right" />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { computed } from "vue";
|
|
10
|
+
import { useLumoraConfig } from "../../context";
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{ variant?: string }>();
|
|
13
|
+
|
|
14
|
+
const { resolveSkin } = useLumoraConfig();
|
|
15
|
+
const resolvedSkin = computed(() => resolveSkin("LuEmbeddedStatusBar", props.variant));
|
|
16
|
+
</script>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-bind="$attrs" :class="resolvedSkin">
|
|
3
|
+
<slot name="left" />
|
|
4
|
+
<slot />
|
|
5
|
+
<slot name="right" />
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { computed } from "vue";
|
|
11
|
+
import { useLumoraConfig } from "../../context";
|
|
12
|
+
|
|
13
|
+
const props = defineProps<{ variant?: string }>();
|
|
14
|
+
|
|
15
|
+
const { resolveSkin } = useLumoraConfig();
|
|
16
|
+
const resolvedSkin = computed(() => resolveSkin("LuEmbeddedTopBar", props.variant));
|
|
17
|
+
</script>
|
package/src/shell/index.ts
CHANGED
|
@@ -6,5 +6,8 @@ export { default as LuDesktopSidebar } from "./desktop/LuDesktopSidebar.vue";
|
|
|
6
6
|
export { default as LuDesktopStatusBar } from "./desktop/LuDesktopStatusBar.vue";
|
|
7
7
|
|
|
8
8
|
export { default as LuMobileShell } from "./mobile/LuMobileShell.vue";
|
|
9
|
-
|
|
9
|
+
export { default as LuMobileHeader } from "./mobile/LuMobileHeader.vue";
|
|
10
|
+
export { default as LuMobileNavBar } from "./mobile/LuMobileNavBar.vue";
|
|
10
11
|
export { default as LuEmbeddedShell } from "./embedded/LuEmbeddedShell.vue";
|
|
12
|
+
export { default as LuEmbeddedTopBar } from "./embedded/LuEmbeddedTopBar.vue";
|
|
13
|
+
export { default as LuEmbeddedStatusBar } from "./embedded/LuEmbeddedStatusBar.vue";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-bind="$attrs" :class="resolvedSkin">
|
|
3
|
+
<slot name="left" />
|
|
4
|
+
<slot />
|
|
5
|
+
<slot name="right" />
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import { computed } from "vue";
|
|
11
|
+
import { useLumoraConfig } from "../../context";
|
|
12
|
+
|
|
13
|
+
const props = defineProps<{ variant?: string }>();
|
|
14
|
+
|
|
15
|
+
const { resolveSkin } = useLumoraConfig();
|
|
16
|
+
const resolvedSkin = computed(() => resolveSkin("LuMobileHeader", props.variant));
|
|
17
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-bind="$attrs" :class="resolvedSkin">
|
|
3
|
+
<slot />
|
|
4
|
+
</div>
|
|
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 }>();
|
|
12
|
+
|
|
13
|
+
const { resolveSkin } = useLumoraConfig();
|
|
14
|
+
const resolvedSkin = computed(() => resolveSkin("LuMobileNavBar", props.variant));
|
|
15
|
+
</script>
|
|
@@ -16,6 +16,6 @@ import { useLumoraConfig } from "../../context";
|
|
|
16
16
|
const props = defineProps<{ variant?: string }>();
|
|
17
17
|
|
|
18
18
|
const { resolveSkin } = useLumoraConfig();
|
|
19
|
-
const resolvedSkin = computed(() => resolveSkin("LuMobileShell", props.variant)
|
|
20
|
-
const contentSkin = computed(() => resolveSkin("LuMobileShellContent")
|
|
19
|
+
const resolvedSkin = computed(() => resolveSkin("LuMobileShell", props.variant));
|
|
20
|
+
const contentSkin = computed(() => resolveSkin("LuMobileShellContent"));
|
|
21
21
|
</script>
|