Compare commits

...

1 Commits

Author SHA1 Message Date
bymyself
660ccb9236 fix: promoted textarea widgets in subgraphs no longer permanently read-only
Skip disabled override for promoted widgets whose internal slot is
linked to SubgraphInput. Extract isPromotedOnOwningNode variable
and reuse it for the existing borderStyle check.

Amp-Thread-ID: https://ampcode.com/threads/T-019c88b8-a377-754b-b624-db394d59f5b5
2026-02-23 04:19:57 +00:00
2 changed files with 41 additions and 18 deletions

View File

@@ -192,19 +192,23 @@ const processedWidgets = computed((): ProcessedWidget[] => {
// Get value from store (falls back to undefined if not registered)
const value = widgetState?.value as WidgetValue
// Build options from store state, with slot-linked override for disabled
// Build options from store state, with slot-linked override for disabled.
// Promoted widgets inside a subgraph are always linked to SubgraphInput,
// but should remain interactive — skip the disabled override for them.
const storeOptions = widgetState?.options ?? {}
const widgetOptions = slotMetadata?.linked
? { ...storeOptions, disabled: true }
: storeOptions
const isPromotedOnOwningNode =
widgetState?.promoted && String(widgetState?.nodeId) === String(nodeId)
const widgetOptions =
slotMetadata?.linked && !isPromotedOnOwningNode
? { ...storeOptions, disabled: true }
: storeOptions
// Derive border style from store metadata
const borderStyle =
widgetState?.promoted && String(widgetState?.nodeId) === String(nodeId)
? 'ring ring-component-node-widget-promoted'
: widget.options?.advanced
? 'ring ring-component-node-widget-advanced'
: undefined
const borderStyle = isPromotedOnOwningNode
? 'ring ring-component-node-widget-promoted'
: widget.options?.advanced
? 'ring ring-component-node-widget-advanced'
: undefined
const simplified: SimplifiedWidget = {
name: widget.name,

View File

@@ -22,14 +22,12 @@ function createMockWidget(
function mountComponent(
widget: SimplifiedWidget<string>,
modelValue: string,
readonly = false,
placeholder?: string
) {
return mount(WidgetTextarea, {
props: {
widget,
modelValue,
readonly,
placeholder
}
})
@@ -179,18 +177,39 @@ describe('WidgetTextarea Value Binding', () => {
it('uses provided placeholder when specified', () => {
const widget = createMockWidget('test')
const wrapper = mountComponent(
widget,
'test',
false,
'Custom placeholder'
)
const wrapper = mountComponent(widget, 'test', 'Custom placeholder')
const textarea = wrapper.find('textarea')
expect(textarea.attributes('placeholder')).toBe('Custom placeholder')
})
})
describe('Read-Only Behavior', () => {
it('is readonly when options.read_only is true', () => {
const widget = createMockWidget('test', { read_only: true })
const wrapper = mountComponent(widget, 'test')
expect(wrapper.find('textarea').attributes('readonly')).toBeDefined()
})
it('is readonly when options.disabled is true', () => {
const widget = createMockWidget('test', { disabled: true })
const wrapper = mountComponent(widget, 'test')
expect(wrapper.find('textarea').attributes('readonly')).toBeDefined()
})
it('is editable when neither read_only nor disabled is set', () => {
const widget = createMockWidget('test', {})
const wrapper = mountComponent(widget, 'test')
expect(wrapper.find('textarea').attributes('readonly')).toBeUndefined()
})
it('is editable when disabled is explicitly false', () => {
const widget = createMockWidget('test', { disabled: false })
const wrapper = mountComponent(widget, 'test')
expect(wrapper.find('textarea').attributes('readonly')).toBeUndefined()
})
})
describe('Edge Cases', () => {
it('handles very long text', async () => {
const widget = createMockWidget('short')