@nuxt/ui
Version:
A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.
68 lines (67 loc) • 2.88 kB
JavaScript
import { computed, getCurrentInstance } from "vue";
import defu from "defu";
import { createContext } from "reka-ui";
import { useAppConfig } from "#imports";
import { get } from "../utils/index.js";
const [_injectThemeContext, provideThemeContext] = createContext("UTheme", "RootContext");
export const defaultThemeContext = {
defaults: computed(() => ({}))
};
export function injectThemeContext(fallback = defaultThemeContext) {
return _injectThemeContext(fallback);
}
export { provideThemeContext };
function camelCase(str) {
return str.replace(/-(\w)/g, (_, c) => c.toUpperCase());
}
function kebabCase(str) {
return str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
}
function propIsDefined(vnode, prop) {
if (!vnode || !vnode.props) return false;
return vnode.props[camelCase(prop)] !== void 0 || vnode.props[kebabCase(prop)] !== void 0;
}
export function useComponentProps(name, props) {
const vm = getCurrentInstance();
const { defaults } = injectThemeContext();
const appConfig = useAppConfig();
return new Proxy(props, {
get(target, prop, receiver) {
if (prop === "__v_isReactive") return true;
if (prop === "__v_raw") return target;
const raw = Reflect.get(target, prop, receiver);
if (typeof prop !== "string") return raw;
const themeEntry = name.includes(".") ? get(defaults.value, name) : defaults.value[name];
if (prop === "ui") {
const themeUi = themeEntry?.ui;
if (!raw && !themeUi) return raw;
return defu(raw ?? {}, themeUi ?? {});
}
if (prop === "class") {
const themeClass = themeEntry?.class;
if (themeClass === void 0) return raw;
if (raw === void 0) return themeClass;
return [themeClass, raw];
}
if (vm && propIsDefined(vm.vnode, prop)) return raw;
const themeValue = themeEntry?.[prop];
if (themeValue !== void 0) return themeValue;
const appConfigEntry = name.includes(".") ? get(appConfig.ui ?? {}, name) : appConfig.ui?.[name];
const appConfigValue = appConfigEntry?.defaultVariants?.[prop];
if (appConfigValue !== void 0) return appConfigValue;
const propDef = vm?.type?.props?.[prop];
if (propDef && Object.prototype.hasOwnProperty.call(propDef, "default")) {
return raw;
}
return void 0;
},
// `has`, `ownKeys`, and `getOwnPropertyDescriptor` reflect the underlying
// `defineProps` schema only — theme defaults are NOT enumerable. As a
// result, `Object.keys(props)`, `for…in`, and `{ ...props }` see only the
// declared prop keys, but each value lookup still flows through the proxy.
// This is the contract our internal `useForwardProps` relies on.
has: (t, p) => Reflect.has(t, p),
ownKeys: (t) => Reflect.ownKeys(t),
getOwnPropertyDescriptor: (t, p) => Reflect.getOwnPropertyDescriptor(t, p)
});
}