mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 02:32:18 +00:00
feat: add text widget stories and Number input stories (#9527)
<img width="842" height="488" alt="스크린샷 2026-03-07 오후 9 39 20" src="https://github.com/user-attachments/assets/9ac8bfcd-c882-4661-851f-b08838d4fed1" /> ## Summary - Add Storybook stories for WidgetInputText, WidgetTextarea, and ScrubableNumberInput - Reorganize story titles under `Components/Input/` to align with Figma design system - Fix PrimeIcons not rendering in Storybook (caused by `[&_*]:!font-inter` override) - Fix knip unused export warnings (dead code removal + workspace config) ## Test plan - [ ] Run `pnpm storybook` and verify Components/Input/InputText stories render - [ ] Verify Components/Input/TextArea stories render with label and copy button - [ ] Verify Components/Input/Number stories render with -/+ icons - [ ] Toggle Storybook theme between Light/Dark and confirm Number story adapts - [ ] Verify existing Button stories still render correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9527-feat-add-text-widget-stories-and-Number-input-stories-31c6d73d3650817ba351cdef26a356c8) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -58,7 +58,7 @@ export const withTheme = (Story: StoryFn, context: StoryContext) => {
|
|||||||
document.documentElement.classList.remove('dark-theme')
|
document.documentElement.classList.remove('dark-theme')
|
||||||
document.body.classList.remove('dark-theme')
|
document.body.classList.remove('dark-theme')
|
||||||
}
|
}
|
||||||
document.body.classList.add('[&_*]:!font-inter')
|
document.body.classList.add('font-inter')
|
||||||
|
|
||||||
return Story(context.args, context)
|
return Story(context.args, context)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ const config: KnipConfig = {
|
|||||||
'packages/tailwind-utils': {
|
'packages/tailwind-utils': {
|
||||||
project: ['src/**/*.{js,ts}']
|
project: ['src/**/*.{js,ts}']
|
||||||
},
|
},
|
||||||
|
'packages/shared-frontend-utils': {
|
||||||
|
project: ['src/**/*.{js,ts}'],
|
||||||
|
entry: ['src/formatUtil.ts', 'src/networkUtil.ts']
|
||||||
|
},
|
||||||
'packages/registry-types': {
|
'packages/registry-types': {
|
||||||
project: ['src/**/*.{js,ts}']
|
project: ['src/**/*.{js,ts}']
|
||||||
}
|
}
|
||||||
@@ -32,7 +36,9 @@ const config: KnipConfig = {
|
|||||||
'@primeuix/forms',
|
'@primeuix/forms',
|
||||||
'@primeuix/styled',
|
'@primeuix/styled',
|
||||||
'@primeuix/utils',
|
'@primeuix/utils',
|
||||||
'@primevue/icons'
|
'@primevue/icons',
|
||||||
|
// Used by lucideStrokePlugin.js (CSS @plugin)
|
||||||
|
'@iconify/utils'
|
||||||
],
|
],
|
||||||
ignore: [
|
ignore: [
|
||||||
// Auto generated manager types
|
// Auto generated manager types
|
||||||
@@ -47,7 +53,9 @@ const config: KnipConfig = {
|
|||||||
// Pending integration in stacked PR
|
// Pending integration in stacked PR
|
||||||
'src/components/sidebar/tabs/nodeLibrary/CustomNodesPanel.vue',
|
'src/components/sidebar/tabs/nodeLibrary/CustomNodesPanel.vue',
|
||||||
// Agent review check config, not part of the build
|
// Agent review check config, not part of the build
|
||||||
'.agents/checks/eslint.strict.config.js'
|
'.agents/checks/eslint.strict.config.js',
|
||||||
|
// Loaded via @plugin directive in CSS, not detected by knip
|
||||||
|
'packages/design-system/src/css/lucideStrokePlugin.js'
|
||||||
],
|
],
|
||||||
compilers: {
|
compilers: {
|
||||||
// https://github.com/webpro-nl/knip/issues/1008#issuecomment-3207756199
|
// https://github.com/webpro-nl/knip/issues/1008#issuecomment-3207756199
|
||||||
|
|||||||
160
src/components/common/ScrubableNumberInput.stories.ts
Normal file
160
src/components/common/ScrubableNumberInput.stories.ts
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
import type {
|
||||||
|
ComponentPropsAndSlots,
|
||||||
|
Meta,
|
||||||
|
StoryObj
|
||||||
|
} from '@storybook/vue3-vite'
|
||||||
|
import { ref, toRefs } from 'vue'
|
||||||
|
|
||||||
|
import Button from '@/components/ui/button/Button.vue'
|
||||||
|
import Popover from '@/components/ui/Popover.vue'
|
||||||
|
|
||||||
|
import ScrubableNumberInput from './ScrubableNumberInput.vue'
|
||||||
|
|
||||||
|
type StoryArgs = ComponentPropsAndSlots<typeof ScrubableNumberInput>
|
||||||
|
|
||||||
|
const meta: Meta<StoryArgs> = {
|
||||||
|
title: 'Components/Input/Number',
|
||||||
|
component: ScrubableNumberInput,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
parameters: { layout: 'centered' },
|
||||||
|
argTypes: {
|
||||||
|
min: { control: 'number' },
|
||||||
|
max: { control: 'number' },
|
||||||
|
step: { control: 'number' },
|
||||||
|
disabled: { control: 'boolean' },
|
||||||
|
hideButtons: { control: 'boolean' }
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
disabled: false,
|
||||||
|
hideButtons: false
|
||||||
|
},
|
||||||
|
decorators: [
|
||||||
|
(story) => ({
|
||||||
|
components: { story },
|
||||||
|
template: '<div class="w-60"><story /></div>'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default meta
|
||||||
|
type Story = StoryObj<typeof meta>
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
render: (args) => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const { min, max, step, disabled, hideButtons } = toRefs(args)
|
||||||
|
const value = ref(42)
|
||||||
|
return { value, min, max, step, disabled, hideButtons }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min :max :step :disabled :hideButtons />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Disabled: Story = {
|
||||||
|
args: { disabled: true },
|
||||||
|
render: (args) => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const { disabled } = toRefs(args)
|
||||||
|
const value = ref(50)
|
||||||
|
return { value, disabled }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min="0" :max="100" :step="1" :disabled />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AtMinimum: Story = {
|
||||||
|
render: () => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const value = ref(0)
|
||||||
|
return { value }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min="0" :max="100" :step="1" />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AtMaximum: Story = {
|
||||||
|
render: () => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const value = ref(100)
|
||||||
|
return { value }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min="0" :max="100" :step="1" />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FloatPrecision: Story = {
|
||||||
|
args: { min: 0, max: 1, step: 0.01 },
|
||||||
|
render: (args) => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const { min, max, step } = toRefs(args)
|
||||||
|
const value = ref(0.75)
|
||||||
|
return { value, min, max, step }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min :max :step display-value="0.75" />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LargeNumber: Story = {
|
||||||
|
render: () => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const value = ref(1809000312992)
|
||||||
|
return { value }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min="0" :max="Number.MAX_SAFE_INTEGER" :step="1" />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HiddenButtons: Story = {
|
||||||
|
args: { hideButtons: true },
|
||||||
|
render: (args) => ({
|
||||||
|
components: { ScrubableNumberInput },
|
||||||
|
setup() {
|
||||||
|
const { hideButtons } = toRefs(args)
|
||||||
|
const value = ref(42)
|
||||||
|
return { value, hideButtons }
|
||||||
|
},
|
||||||
|
template:
|
||||||
|
'<ScrubableNumberInput v-model="value" :min="0" :max="100" :step="1" :hideButtons />'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WithControlButton: Story = {
|
||||||
|
render: () => ({
|
||||||
|
components: { ScrubableNumberInput, Button, Popover },
|
||||||
|
setup() {
|
||||||
|
const value = ref(1809000312992)
|
||||||
|
return { value }
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<ScrubableNumberInput v-model="value" :min="0" :max="Number.MAX_SAFE_INTEGER" :step="1">
|
||||||
|
<Popover>
|
||||||
|
<template #button>
|
||||||
|
<Button
|
||||||
|
variant="textonly"
|
||||||
|
size="sm"
|
||||||
|
class="h-4 w-7 self-center rounded-xl bg-primary-background/30 p-0 hover:bg-primary-background-hover/30"
|
||||||
|
>
|
||||||
|
<i class="icon-[lucide--shuffle] w-full text-xs text-primary-background" />
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
<div class="p-4 text-sm">Control popover content</div>
|
||||||
|
</Popover>
|
||||||
|
</ScrubableNumberInput>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ interface StoryArgs extends ComponentPropsAndSlots<typeof WidgetInputText> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const meta: Meta<StoryArgs> = {
|
const meta: Meta<StoryArgs> = {
|
||||||
title: 'Widgets/WidgetInputText',
|
title: 'Components/Input/InputText',
|
||||||
component: WidgetInputText,
|
component: WidgetInputText,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
parameters: { layout: 'centered' },
|
parameters: { layout: 'centered' },
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ interface StoryArgs extends ComponentPropsAndSlots<typeof WidgetTextarea> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const meta: Meta<StoryArgs> = {
|
const meta: Meta<StoryArgs> = {
|
||||||
title: 'Widgets/WidgetTextarea',
|
title: 'Components/Input/TextArea',
|
||||||
component: WidgetTextarea,
|
component: WidgetTextarea,
|
||||||
tags: ['autodocs'],
|
tags: ['autodocs'],
|
||||||
parameters: {
|
parameters: {
|
||||||
|
|||||||
Reference in New Issue
Block a user