Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/components/MultiSelectInput/SearchMultiSelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { rankedSearchOnList } from '../../utils';
import styles from './styles.css';

interface OptionProps {
actions?: React.ReactNode;
children: React.ReactNode;
isActive: boolean;
}
function Option(props: OptionProps) {
const {
actions,
children,
isActive,
} = props;
Expand All @@ -29,6 +31,9 @@ function Option(props: OptionProps) {
<div className={styles.label}>
{ children }
</div>
<div className={styles.actions}>
{actions}
</div>
</>
);
}
Expand All @@ -50,6 +55,7 @@ export type SearchMultiSelectInputProps<
searchOptions?: O[] | undefined | null;
keySelector: (option: O) => T;
labelSelector: (option: O) => string;
actionsSelector?: (option: O) => React.ReactNode;
hideOptionFilter?: (option: O) => boolean;
name: K;
disabled?: boolean;
Expand Down Expand Up @@ -97,6 +103,7 @@ function SearchMultiSelectInput<
const {
keySelector,
labelSelector,
actionsSelector,
name,
onChange,
onOptionsChange,
Expand Down Expand Up @@ -237,10 +244,11 @@ function SearchMultiSelectInput<
children: labelSelector(option),
containerClassName: _cs(styles.option, isActive && styles.active),
title: labelSelector(option),
actions: actionsSelector?.(option),
isActive,
};
},
[labelSelector, value],
[labelSelector, value, actionsSelector],
);

// FIXME: value should not be on dependency list, also try to pass options like in SelectInput
Expand Down
10 changes: 9 additions & 1 deletion src/components/SelectInput/SearchSelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import { rankedSearchOnList } from '../../utils';
import styles from './styles.css';

interface OptionProps {
actions?: React.ReactNode;
children: React.ReactNode;
}
function Option(props: OptionProps) {
const {
actions,
children,
} = props;

Expand All @@ -27,6 +29,9 @@ function Option(props: OptionProps) {
<div className={styles.label}>
{ children }
</div>
<div className={styles.actions}>
{actions}
</div>
</>
);
}
Expand All @@ -47,6 +52,7 @@ export type SearchSelectInputProps<
searchOptions?: O[] | undefined | null;
keySelector: (option: O) => T;
labelSelector: (option: O) => string;
actionsSelector?: (option: O) => React.ReactNode;
hideOptionFilter?: (option: O) => boolean;
name: K;
disabled?: boolean;
Expand Down Expand Up @@ -102,6 +108,7 @@ function SearchSelectInput<
const {
keySelector,
labelSelector,
actionsSelector,
name,
onChange,
onOptionsChange,
Expand Down Expand Up @@ -230,11 +237,12 @@ function SearchSelectInput<

return {
children: labelSelector(option),
actions: actionsSelector?.(option),
containerClassName: _cs(styles.option, isActive && styles.active),
title: labelSelector(option),
};
},
[value, labelSelector],
[value, labelSelector, actionsSelector],
);

const handleOptionClick = useCallback(
Expand Down
23 changes: 23 additions & 0 deletions src/stories/MultiSelectInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import { Story } from '@storybook/react/types-6-0';
import { useArgs } from '@storybook/client-api';
import { IoOpenOutline } from 'react-icons/io5';
import MultiSelectInput, { MultiSelectInputProps } from '#components/MultiSelectInput';
import QuickActionButton from '#components/QuickActionButton';

export default {
title: 'Input/MultiSelectInput',
Expand Down Expand Up @@ -46,6 +48,27 @@ const Template: Story<MultiSelectInputProps<string, string, Option, { containerC
);
};

function handleClick(_:string | undefined, e: React.MouseEvent<HTMLButtonElement>) {
// NOTE: This intentionally breaks HTML semantics (link inside a button).
// This workaround is to allow clickable links inside SelectInput options
// where a button wrapper is required.
e.stopPropagation();
window.open('https://www.google.com/search?q=story', '_blank');
}

export const WithActions = Template.bind({});
WithActions.args = {
actionsSelector: () => (
<QuickActionButton
name={undefined}
onClick={handleClick}
transparent
>
<IoOpenOutline />
</QuickActionButton>
),
};

export const NoValue = Template.bind({});
NoValue.args = {
value: undefined,
Expand Down
23 changes: 23 additions & 0 deletions src/stories/SearchMultiSelectInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { useState } from 'react';
import { Story } from '@storybook/react/types-6-0';
import { useArgs } from '@storybook/client-api';
import { IoOpenOutline } from 'react-icons/io5';
import SearchMultiSelectInput, { SearchMultiSelectInputProps } from '#components/MultiSelectInput/SearchMultiSelectInput';
import QuickActionButton from '#components/QuickActionButton';
import useQuery, { entityListTransformer } from '../utils/useQuery';

export default {
Expand Down Expand Up @@ -188,6 +190,27 @@ const Template: Story<SearchMultiSelectInputProps<string, string, Option, { cont
);
};

function handleClick(_:string | undefined, e: React.MouseEvent<HTMLButtonElement>) {
// NOTE: This intentionally breaks HTML semantics (link inside a button).
// This workaround is to allow clickable links inside SelectInput options
// where a button wrapper is required.
e.stopPropagation();
window.open('https://www.google.com/search?q=story', '_blank');
}

export const WithActions = Template.bind({});
WithActions.args = {
actionsSelector: () => (
<QuickActionButton
name={undefined}
onClick={handleClick}
transparent
>
<IoOpenOutline />
</QuickActionButton>
),
};

export const NoValue = Template.bind({});
NoValue.args = {
value: undefined,
Expand Down
23 changes: 23 additions & 0 deletions src/stories/SearchSelectInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { useState } from 'react';
import { Story } from '@storybook/react/types-6-0';
import { useArgs } from '@storybook/client-api';
import { IoOpenOutline } from 'react-icons/io5';
import SearchSelectInput, { SearchSelectInputProps } from '#components/SelectInput/SearchSelectInput';
import QuickActionButton from '#components/QuickActionButton';
import useQuery, { entityListTransformer } from '../utils/useQuery';

export default {
Expand Down Expand Up @@ -193,6 +195,27 @@ Default.args = {
value: '1',
};

function handleClick(_:string | undefined, e: React.MouseEvent<HTMLButtonElement>) {
// NOTE: This intentionally breaks HTML semantics (link inside a button).
// This workaround is to allow clickable links inside SelectInput options
// where a button wrapper is required.
e.stopPropagation();
window.open('https://www.google.com/search?q=story', '_blank');
}

export const WithActions = Template.bind({});
WithActions.args = {
actionsSelector: () => (
<QuickActionButton
name={undefined}
onClick={handleClick}
transparent
>
<IoOpenOutline />
</QuickActionButton>
),
};

export const Disabled = Template.bind({});
Disabled.args = {
value: '1',
Expand Down
23 changes: 23 additions & 0 deletions src/stories/SelectInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import { Story } from '@storybook/react/types-6-0';
import { useArgs } from '@storybook/client-api';
import { IoOpenOutline } from 'react-icons/io5';
import SelectInput, { SelectInputProps } from '#components/SelectInput';
import QuickActionButton from '#components/QuickActionButton';

export default {
title: 'Input/SelectInput',
Expand Down Expand Up @@ -45,6 +47,27 @@ const Template: Story<SelectInputProps<string, string, Option, { containerClassN
);
};

function handleClick(_:string | undefined, e: React.MouseEvent<HTMLButtonElement>) {
// NOTE: This intentionally breaks HTML semantics (link inside a button).
// This workaround is to allow clickable links inside SelectInput options
// where a button wrapper is required.
e.stopPropagation();
window.open('https://www.google.com/search?q=story', '_blank');
}

export const WithActions = Template.bind({});
WithActions.args = {
actionsSelector: () => (
<QuickActionButton
name={undefined}
onClick={handleClick}
transparent
>
<IoOpenOutline />
</QuickActionButton>
),
};

export const NoValue = Template.bind({});
NoValue.args = {
value: undefined,
Expand Down