From 2798c0894fe15a5a7ebcf4f1aa3e4164d5aaf8d2 Mon Sep 17 00:00:00 2001 From: Echo Date: Thu, 27 Aug 2026 13:51:51 +0000 Subject: [PATCH] Composer redesign: Autocomplete (#40276) --- .../autosuggest/autosuggest.stories.tsx | 119 +++++++++ .../mastodon/components/autosuggest/hooks.tsx | 233 ++++++++++++++++++ .../mastodon/components/autosuggest/items.tsx | 97 ++++++++ .../mastodon/components/autosuggest/list.tsx | 114 +++++++++ .../components/autosuggest/styles.module.scss | 59 +++++ .../mastodon/components/autosuggest/types.ts | 35 +++ .../mastodon/components/autosuggest/utils.ts | 79 +++++- .../features/compose/redesign/selectors.ts | 9 + .../compose/redesign/styles.module.scss | 39 ++- .../features/compose/redesign/textarea.tsx | 154 ++++++------ 10 files changed, 853 insertions(+), 85 deletions(-) create mode 100644 app/javascript/mastodon/components/autosuggest/autosuggest.stories.tsx create mode 100644 app/javascript/mastodon/components/autosuggest/hooks.tsx create mode 100644 app/javascript/mastodon/components/autosuggest/items.tsx create mode 100644 app/javascript/mastodon/components/autosuggest/list.tsx create mode 100644 app/javascript/mastodon/components/autosuggest/styles.module.scss create mode 100644 app/javascript/mastodon/components/autosuggest/types.ts diff --git a/app/javascript/mastodon/components/autosuggest/autosuggest.stories.tsx b/app/javascript/mastodon/components/autosuggest/autosuggest.stories.tsx new file mode 100644 index 00000000000..f2d47bfb0d0 --- /dev/null +++ b/app/javascript/mastodon/components/autosuggest/autosuggest.stories.tsx @@ -0,0 +1,119 @@ +import { useRef, useState } from 'react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { fn } from 'storybook/test'; + +import { accountFactoryImmutable } from '@/testing/factories'; + +import { TextArea } from '../form_fields'; +import menuClasses from '../menu/styles.module.scss'; + +import { useAutosuggestMenu } from './hooks'; +import { AutosuggestItem } from './items'; +import { AutosuggestMenu } from './list'; +import type { + AccountSuggestion, + EmojiSuggestion, + HashtagSuggestion, + Suggestion, +} from './types'; + +type SuggestTypes = Suggestion['type']; + +const suggestionsMap = { + account: [{ type: 'account', id: '1' }] satisfies AccountSuggestion[], + emoji: [ + { type: 'emoji', id: '+1', native: '👍' }, + { type: 'emoji', id: '-1', native: '👎' }, + { type: 'emoji', id: 'smile', native: '🙂' }, + ] satisfies EmojiSuggestion[], + hashtag: [ + { type: 'hashtag', name: 'Testing', id: '1', totalUses: 0 }, + { type: 'hashtag', name: 'Test', id: '2', totalUses: 10 }, + ] satisfies HashtagSuggestion[], +} satisfies Record; + +const fetchCb = fn().mockName('fetching token'); +const selectCb = fn().mockName('selected item'); +const clearCb = fn().mockName('cleared suggestions'); + +const meta = { + title: 'Redesign/Autosuggest', + render() { + const [suggestions, setSuggestions] = useState([]); + const textareaRef = useRef(null); + + const { onTextChange, suggestProps, sourceProps } = useAutosuggestMenu({ + suggestions, + onSelect: selectCb, + onFetch(token) { + const newSuggestions = tokenToSuggestions(token); + + fetchCb(token, newSuggestions); + setSuggestions(newSuggestions); + }, + onClear() { + clearCb(); + setSuggestions([]); + }, + }); + + return ( +
+