feat: fix storybook config

This commit is contained in:
Eli Bosley
2025-04-16 15:56:25 -04:00
parent 35a6d14367
commit bf3b95bfe5
16 changed files with 187 additions and 31 deletions

16
pnpm-lock.yaml generated
View File

@@ -790,6 +790,9 @@ importers:
postcss:
specifier: ^8.4.49
version: 8.5.3
postcss-import:
specifier: ^16.1.0
version: 16.1.0(postcss@8.5.3)
prettier:
specifier: 3.5.3
version: 3.5.3
@@ -9707,6 +9710,12 @@ packages:
peerDependencies:
postcss: ^8.0.0
postcss-import@16.1.0:
resolution: {integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==}
engines: {node: '>=18.0.0'}
peerDependencies:
postcss: ^8.0.0
postcss-js@4.0.1:
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
engines: {node: ^12 || ^14 || >= 16}
@@ -22577,6 +22586,13 @@ snapshots:
read-cache: 1.0.0
resolve: 1.22.10
postcss-import@16.1.0(postcss@8.5.3):
dependencies:
postcss: 8.5.3
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.10
postcss-js@4.0.1(postcss@8.5.3):
dependencies:
camelcase-css: 2.0.1

View File

@@ -1,2 +1,3 @@
!.env.development
dist-wc/
dist-wc/
.storybook/static/*

View File

@@ -1,26 +1,22 @@
import { dirname, join } from "path";
import type { StorybookConfig } from "@storybook/vue3-vite";
import { dirname, join } from 'path';
import type { StorybookConfig } from '@storybook/vue3-vite';
const config: StorybookConfig = {
stories: ["../stories/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions"
],
stories: ['../stories/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
framework: {
name: "@storybook/vue3-vite",
name: '@storybook/vue3-vite',
options: {
docgen: "vue-component-meta",
docgen: 'vue-component-meta',
},
},
core: {
builder: "@storybook/builder-vite",
builder: '@storybook/builder-vite',
},
docs: {
autodocs: "tag",
autodocs: 'tag',
},
staticDirs: ['./static'],
async viteFinal(config) {
return {
...config,
@@ -49,4 +45,4 @@ const config: StorybookConfig = {
},
};
export default config;
export default config;

View File

@@ -1,8 +1,10 @@
import type { Preview } from '@storybook/vue3';
import '../src/styles/globals.css';
import { registerAllComponents } from '../src/register';
import '@/styles/index.css';
registerAllComponents({});
registerAllComponents({
pathToSharedCss: '/index.css',
});
const preview: Preview = {
parameters: {
@@ -18,9 +20,11 @@ const preview: Preview = {
decorators: [
(story) => ({
components: { story },
template: `
<div>
<div id="modals"></div>
<uui-modals></uui-modals>
<story />
</div>
`,
@@ -28,4 +32,4 @@ const preview: Preview = {
],
};
export default preview;
export default preview;

View File

@@ -34,7 +34,10 @@
"preunraid:deploy": "pnpm build:wc",
"unraid:deploy": "just deploy",
"// Storybook": "",
"prestorybook": "pnpm storybook:css",
"storybook": "storybook dev -p 6006",
"storybook:css": "node scripts/build-style.mjs",
"prebuild-storybook": "pnpm storybook:css",
"build-storybook": "storybook build"
},
"peerDependencies": {
@@ -89,6 +92,7 @@
"eslint-plugin-vue": "^10.0.0",
"happy-dom": "^17.0.0",
"postcss": "^8.4.49",
"postcss-import": "^16.1.0",
"prettier": "3.5.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"rimraf": "^6.0.1",

View File

@@ -0,0 +1,30 @@
import fs from 'fs/promises';
import autoprefixer from 'autoprefixer';
import postcss from 'postcss';
import postcssImport from 'postcss-import';
import tailwindcss from 'tailwindcss';
/**
* Helper script for storybook to build the CSS file for the components. This is used to ensure that modals render using the shadow styles.
*/
process.env.VITE_TAILWIND_BASE_FONT_SIZE = 16;
const inputPath = './src/styles/index.css';
const outputPath = './.storybook/static/index.css'; // served from root: /index.css
const css = await fs.readFile(inputPath, 'utf8');
const result = await postcss([
postcssImport(),
tailwindcss({ config: './tailwind.config.ts' }),
autoprefixer(),
]).process(css, {
from: inputPath,
to: outputPath,
});
await fs.mkdir('./.storybook/static', { recursive: true });
await fs.writeFile(outputPath, result.css);
console.log('✅ CSS built for Storybook:', outputPath);

View File

@@ -18,3 +18,4 @@ export * from '@/components/common/tooltip';
export * from '@/components/common/toast';
export * from '@/components/common/popover';
export * from '@/components/brand';
export * from '@/components/modals';

View File

@@ -5,15 +5,19 @@ import type { ComboboxContentEmits, ComboboxContentProps } from 'reka-ui';
import { ComboboxContent, ComboboxPortal, ComboboxViewport, useForwardPropsEmits } from 'reka-ui';
import { computed, type HTMLAttributes } from 'vue';
const props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {
position: 'popper',
align: 'center',
sideOffset: 4,
defineOptions({
inheritAttrs: false,
});
const emits = defineEmits<ComboboxContentEmits>();
const { teleportTarget } = useTeleport();
const props = withDefaults(defineProps<ComboboxContentProps & { class?: HTMLAttributes['class'] }>(), {
forceMount: true,
position: 'popper',
to: undefined,
});
const emits = defineEmits<ComboboxContentEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
@@ -26,7 +30,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<template>
<ComboboxPortal :to="teleportTarget">
<ComboboxContent
v-bind="forwarded"
v-bind="{ ...forwarded, ...$attrs }"
:class="
cn(
'z-50 w-[200px] rounded-md border bg-popover text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',

View File

@@ -0,0 +1,5 @@
<script setup lang="ts">
</script>
<template>
<div id="modals"></div>
</template>

View File

@@ -0,0 +1 @@
export { default as Modals } from './ModalTarget.vue';

View File

@@ -4,12 +4,15 @@ const useTeleport = () => {
const teleportTarget = ref<string | HTMLElement>('#modals');
const determineTeleportTarget = () => {
const myModalsComponent = document.querySelector('unraid-modals');
const myModalsComponent = document.querySelector('unraid-modals') || document.querySelector('uui-modals');
console.log('myModalsComponent', myModalsComponent, 'has shadowRoot', myModalsComponent?.shadowRoot);
if (!myModalsComponent?.shadowRoot) return;
const potentialTarget = myModalsComponent.shadowRoot.querySelector('#modals');
if (!potentialTarget) return;
console.log('potentialTarget', potentialTarget);
teleportTarget.value = potentialTarget as HTMLElement;
console.log('[determineTeleportTarget] teleportTarget', teleportTarget.value);
};

View File

@@ -14,5 +14,3 @@ export { default as tailwindConfig } from '../tailwind.config';
// Composables
export { default as useTeleport } from '@/composables/useTeleport';
// Additional exports not in components.ts

6
unraid-ui/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
/// <reference types="vite/client" />
declare module '*.css?raw' {
const content: string;
export default content;
}

View File

@@ -0,0 +1,89 @@
import type { Meta, StoryObj } from '@storybook/vue3';
import {
Combobox as ComboboxComponent,
ComboboxEmpty,
ComboboxGroup,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxTrigger,
} from '../../../src/components/form/combobox';
const meta = {
title: 'Components/Form/Combobox',
component: ComboboxComponent,
} satisfies Meta<typeof ComboboxComponent>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Combobox: Story = {
render: (args) => ({
components: {
ComboboxComponent,
ComboboxTrigger,
ComboboxInput,
ComboboxList,
ComboboxGroup,
ComboboxItem,
},
setup() {
return { args };
},
template: `
<ComboboxComponent>
<ComboboxTrigger class="w-[180px]">
<ComboboxInput placeholder="Select a fruit" />
</ComboboxTrigger>
<ComboboxList>
<ComboboxGroup>
<ComboboxItem value="apple">Apple</ComboboxItem>
<ComboboxItem value="banana">Banana</ComboboxItem>
<ComboboxItem value="orange">Orange</ComboboxItem>
<ComboboxItem value="grape">Grape</ComboboxItem>
</ComboboxGroup>
</ComboboxList>
</ComboboxComponent>
`,
}),
};
export const Grouped: Story = {
render: (args) => ({
components: {
ComboboxComponent,
ComboboxTrigger,
ComboboxInput,
ComboboxList,
ComboboxGroup,
ComboboxItem,
ComboboxEmpty,
},
setup() {
return { args };
},
template: `
<div>
<ComboboxComponent>
<ComboboxTrigger class="w-[180px]">
<ComboboxInput placeholder="Select a food" />
</ComboboxTrigger>
<ComboboxList>
<ComboboxEmpty>No results found</ComboboxEmpty>
<ComboboxGroup>
<ComboboxItem value="apple">Apple</ComboboxItem>
<ComboboxItem value="banana">Banana</ComboboxItem>
<ComboboxItem value="grape">Grape</ComboboxItem>
</ComboboxGroup>
<ComboboxGroup>
<ComboboxItem value="carrot">Carrot</ComboboxItem>
<ComboboxItem value="potato">Potato</ComboboxItem>
<ComboboxItem value="celery">Celery</ComboboxItem>
</ComboboxGroup>
</ComboboxList>
</ComboboxComponent>
</div>
`,
}),
};

View File

@@ -7,7 +7,7 @@ import {
SelectLabel,
SelectTrigger,
SelectValue,
} from '../../../src/components/form/select';
} from '@/components/form/select';
const meta = {
title: 'Components/Form/Select',
@@ -67,7 +67,6 @@ export const Grouped: Story = {
},
template: `
<div>
<unraid-modals></unraid-modals>
<SelectComponent>
<SelectTrigger class="w-[180px]">
<SelectValue placeholder="Select a food" />

View File

@@ -11,7 +11,6 @@ const useTeleport = () => {
if (!potentialTarget) return;
teleportTarget.value = potentialTarget;
console.log("[determineTeleportTarget] teleportTarget", teleportTarget.value);
};
onMounted(() => {