Repository navigation
feat(ui): Textarea 增加原位编辑与品牌色底选项,新增 InfoHint #38
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
Open
qqqqqf-q
wants to merge
4
commits into
main
Choose a base branch
from
feat/memoh-222-textarea-engage-info-hint
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import type { ComponentSpec } from '../lib/spec' | ||
| import { h } from 'vue' | ||
| import { Button } from '#/components/button' | ||
| import { InfoHint } from '#/components/info-hint' | ||
| import { tooltipSideKeys } from '#/components/tooltip' | ||
|
|
||
| export const infoHintSpec: ComponentSpec = { | ||
| id: 'info-hint', | ||
| name: 'InfoHint', | ||
| interactive: true, | ||
| description: | ||
| 'A muted ⓘ glyph that only explains: hover, keyboard focus or a tap opens a short Tooltip. Not an action, so not a button.', | ||
| descriptionZh: | ||
| '只负责解释的灰色 ⓘ 图标:悬停、键盘聚焦或轻点时弹出简短的 Tooltip。它不是操作,所以不是按钮。', | ||
| controls: [ | ||
| { kind: 'enum', key: 'side', label: 'Side', options: tooltipSideKeys, default: 'top', display: 'segmented' }, | ||
| { | ||
| kind: 'string', | ||
| key: 'text', | ||
| label: 'Text', | ||
| default: 'Saving replaces this message and the reply after it.', | ||
| }, | ||
| ], | ||
| examples: [ | ||
| { | ||
| name: 'Beside an action row', | ||
| nameZh: '放在操作行旁边', | ||
| // Real placement: it explains what the buttons next to it will do, | ||
| // sitting at the text scale of their labels. | ||
| render: state => h('div', { class: 'flex items-center gap-1.5' }, [ | ||
| h(InfoHint, { text: String(state.text), side: state.side as never }), | ||
| h(Button, { variant: 'ghost', tone: 'muted', size: 'sm' }, () => 'Cancel'), | ||
| h(Button, { variant: 'primary', size: 'sm' }, () => 'Save'), | ||
| ]), | ||
| }, | ||
| ], | ||
| render: state => h(InfoHint, { text: String(state.text), side: state.side as never }), | ||
| usage: `InfoHint carries supplementary explanation only — a reader has to go looking for it, so nothing essential may live only inside it. | ||
|
|
||
| - Use it when a glyph's whole job is to explain. If clicking should DO something, that is a Button. | ||
| - The glyph is 14px and muted — one rung above the text rung, because a thin outline circle looks smaller than text of the same height. Do not resize or recolor it per call site. | ||
| - The text is also the accessible name — write it as a full sentence.`, | ||
| usageZh: `InfoHint 只放补充说明——读者得主动去看才能看到,所以关键信息绝不能只放在里面。 | ||
|
|
||
| - 图标的唯一作用是解释时用它;点了要执行操作的,应该用 Button。 | ||
| - 图标固定 14px、灰色——比文字档高一档,因为细线圆圈在同样高度下看起来比文字小。不要在调用处改尺寸或颜色。 | ||
| - 提示文字同时是无障碍名称,写成完整的一句话。`, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| <script setup lang="ts"> | ||
| import type { InfoHintSide } from '.' | ||
| import { Info } from 'lucide-vue-next' | ||
| import { ref } from 'vue' | ||
| import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../tooltip' | ||
|
|
||
| const props = withDefaults(defineProps<{ | ||
| // The explanation itself: shown in the tooltip and read as the glyph's | ||
| // accessible name. | ||
| text: string | ||
| side?: InfoHintSide | ||
| }>(), { | ||
| side: 'top', | ||
| }) | ||
|
|
||
| const open = ref(false) | ||
| // The Tooltip opens on hover and keyboard focus but ignores touch (it skips | ||
| // touch pointermove and closes on every trigger press), so a tap toggles it | ||
| // here. pointerdown records how the following click was made; a mouse click | ||
| // leaves the hover-driven state alone. | ||
| let pointerType = '' | ||
| function onPointerDown(event: PointerEvent) { | ||
| pointerType = event.pointerType | ||
| } | ||
| function onClick() { | ||
| if (pointerType === 'touch' || pointerType === 'pen') open.value = !open.value | ||
| } | ||
| </script> | ||
|
|
||
| <template> | ||
| <!-- An ⓘ that only explains — not an action, so not a <Button>: no hover | ||
| chip, no pointer cursor. The glyph takes the icon ladder's 14px rung: | ||
| a thin, muted outline circle reads smaller than solid text of the same | ||
| height, so it sits one notch above the label's cap height to look level | ||
| with it. It is still a tab stop so keyboard users can open the hint; its | ||
| focus ring is the standard --ring recipe. The tooltip opens without | ||
| delay: showing the hint is the glyph's whole job. The trigger keeps the | ||
| tooltip open on press (disable-closing-trigger) so the tap toggle above | ||
| is the only thing a tap does; a tap elsewhere, blur or scroll closes it. | ||
| The ::after widens the hit area by 6px each side, to 26px — past the | ||
| 24px minimum target — without moving the glyph; 6px is also the | ||
| action-row gap, so it never reaches into a neighbouring button. --> | ||
| <TooltipProvider :delay-duration="0"> | ||
| <Tooltip | ||
| v-model:open="open" | ||
| disable-closing-trigger | ||
| > | ||
| <TooltipTrigger as-child> | ||
| <span | ||
| data-slot="info-hint" | ||
| tabindex="0" | ||
| role="img" | ||
| :aria-label="props.text" | ||
| class="relative inline-flex shrink-0 cursor-default rounded-full text-muted-foreground outline-none after:absolute after:-inset-1.5 after:content-[''] focus-visible:ring-2 focus-visible:ring-ring/30" | ||
| @pointerdown="onPointerDown" | ||
| @click="onClick" | ||
| > | ||
| <Info | ||
| class="size-3.5" | ||
| aria-hidden="true" | ||
| /> | ||
| </span> | ||
| </TooltipTrigger> | ||
| <TooltipContent :side="props.side"> | ||
| {{ props.text }} | ||
| </TooltipContent> | ||
| </Tooltip> | ||
| </TooltipProvider> | ||
| </template> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import type { tooltipSideKeys } from '../tooltip' | ||
|
|
||
| export { default as InfoHint } from './InfoHint.vue' | ||
|
|
||
| // The hint opens through Tooltip, so its sides are Tooltip's. | ||
| export type InfoHintSide = typeof tooltipSideKeys[number] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,8 @@ | ||
| export { default as Textarea } from './Textarea.vue' | ||
|
|
||
| // Single sources of truth for the rest and surface axes (see Textarea.vue); | ||
| // consumed by the showcase spec so its controls never hand-maintain the lists. | ||
| export const textareaRestKeys = ['edge', 'bare'] as const | ||
| export type TextareaRest = typeof textareaRestKeys[number] | ||
| export const textareaSurfaceKeys = ['plain', 'brand-tint'] as const | ||
| export type TextareaSurface = typeof textareaSurfaceKeys[number] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a screen-reader user focuses this trigger, Reka's
TooltipTriggeradds anaria-describedbyreference toTooltipContent; assigning the identical text asaria-labeltherefore exposes the sentence as both the accessible name and description, which can cause it to be announced twice. Keep the required accessible name, but prevent the tooltip body from redundantly describing the trigger or provide separate label and explanation values.AGENTS.md reference: AGENTS.md:L233-L234
Useful? React with 👍 / 👎.