Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArgControl: Add Union Type Arg Control #22912

Closed
wants to merge 15 commits into from
Closed
2 changes: 1 addition & 1 deletion code/frameworks/sveltekit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ However SvelteKit has some [Kit-specific modules](https://kit.svelte.dev/docs/mo
| [`$app/forms`](https://kit.svelte.dev/docs/modules#$app-forms) | ⏳ Future | Will use mocks. Tracked in [#20999](https://github.com/storybookjs/storybook/issues/20999) |
| [`$app/navigation`](https://kit.svelte.dev/docs/modules#$app-navigation) | ⏳ Future | Will use mocks. Tracked in [#20999](https://github.com/storybookjs/storybook/issues/20999) |
| [`$app/paths`](https://kit.svelte.dev/docs/modules#$app-paths) | ✅ Supported | Requires SvelteKit 1.4.0 or newer |
| [`$app/stores`](https://kit.svelte.dev/docs/modules#$app-stores) | ✅ Supported | Mocks planned, so you can set different store values per story. |
| [`$app/stores`](https://kit.svelte.dev/docs/modules#$app-stores) | ✅ Supported | Mocks planned, so you can set different store values per story. |
| [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private) | ⛔ Not supported | They are meant to only be available server-side, and Storybook renders all components on the client. |
| [`$env/dynamic/public`](https://kit.svelte.dev/docs/modules#$env-dynamic-public) | 🚧 Partially supported | Only supported in development mode. Storybook is built as a static app with no server-side API so cannot dynamically serve content. |
| [`$env/static/private`](https://kit.svelte.dev/docs/modules#$env-static-private) | ⛔ Not supported | They are meant to only be available server-side, and Storybook renders all components on the client. |
Expand Down
1 change: 1 addition & 0 deletions code/renderers/vue3/src/docs/sourceDecorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ export function generateTemplateSource(
.map((child) => child.content)
.join('')
: '';

const name =
typeof type === 'string'
? type
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Meta, StoryObj } from '@storybook/vue3';

import MyComponent from './UnionTypeProp.vue';

const meta: Meta = {
component: MyComponent,
argTypes: {},
tags: ['autodocs'],
} satisfies Meta<typeof MyComponent>;

export default meta;
type Story = StoryObj<typeof meta>;

export const UnionType: Story = {
args: {
label: 'UnionType',
stringOrNumber: 12,
booleanOrNumber: true,
multiple: { a: 1, b: 2 },
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<pre>
{{ JSON.stringify($props, null, 2) }}
</pre>
</template>

<script lang="ts" setup >
defineProps<
{
/**
* label
*/
label:string ,
/**
* stringOrNumber
*/
stringOrNumber?: string | number,
/**
* booleanOrNumber
*/
booleanOrNumber?:boolean | number,
/**
* multiple
*/
multiple?:object | string | number | boolean ,


}>();
</script>
53 changes: 51 additions & 2 deletions code/ui/blocks/src/components/ArgsTable/ArgControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,55 @@ export const ArgControl: FC<ArgControlProps> = ({ row, arg, updateArgs, isHovere
// row.name is a display name and not a suitable DOM input id or name - i might contain whitespace etc.
// row.key is a hash key and therefore a much safer choice
const props = { name: key, argType: row, value: boxedValue.value, onChange, onBlur, onFocus };
const Control = Controls[control.type] || NoControl;
return <Control {...props} {...control} controlType={control.type} />;

const controls = getControlTypesFromArgType(row);

const tsTypes: string[] =
row.type?.name === 'union'
? row.type.value.map((t: { name: any }) => t.name)
: [row.type?.name];

return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'start', gap: 10 }}>
{controls.map((controlType: string) => {
const UninonControl = Controls[controlType] || NoControl;
const argValueType = typeof boxedValue.value;
const controlValue = [tsTypes.shift(), controlType].includes(argValueType)
? boxedValue.value
: undefined;

const controlKey = controls.length > 1 ? `${controlType}-${key}` : key;

return (
<UninonControl
{...props}
{...control}
key={controlKey}
name={controlKey}
value={controlValue}
controlType={controlType}
/>
);
})}
</div>
);
};
/**
* function to get control types from union arg type
* example : argType = { name: 'union', value: [{ name: 'string' }, { name: 'number' }] }
* @param argType
* @returns
*/
function getControlTypesFromArgType(argType: ArgType) {
return argType.type?.value && argType.type?.name === 'union' && !argType.options
? argType.type.value.map((t: { name: any }) => {
switch (t.name) {
case 'string':
return 'text';

default:
return t.name;
}
})
: [argType.control.type];
}
4 changes: 4 additions & 0 deletions code/ui/blocks/src/controls/Number.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export const NumberControl: FC<NumberProps> = ({
if (inputValue !== newInputValue) {
setInputValue(value);
}

if (!value && newInputValue === '') {
setForceVisible(false);
}
}, [value]);

if (!forceVisible && value === undefined) {
Expand Down
5 changes: 5 additions & 0 deletions code/ui/components/src/components/form/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ const styles = ({ theme }: { theme: Theme }): CSSObject => ({
height: 'auto',
},

'&[type="number"]': {
/* without this we will have inconsistant height */
padding: '0px 10px',
},

'&:focus': {
boxShadow: `${theme.color.secondary} 0 0 0 1px inset`,
outline: 'none',
Expand Down