[NO-ISSUE] feat: add InputGroup composition component with Addon sub-component#709
Open
isaquebock wants to merge 12 commits into
Open
[NO-ISSUE] feat: add InputGroup composition component with Addon sub-component#709isaquebock wants to merge 12 commits into
isaquebock wants to merge 12 commits into
Conversation
…component Implements Figma node 3714-10802. Composition pattern with compound API: InputGroup root + InputGroup.Addon sub-component. States driven by data-invalid / data-required attributes (danger border when invalid alone, warning border when invalid + required). Provides InputGroupContextKey via inject/provide so future input primitives can render borderless inside the group in a follow-up PR.
…text pattern Independent invalid/required semantics (invalid -> danger, required -> warning), focus-within ring on the group root, hover border-strong, and transition-colors with motion-reduce fallback. Spec States/Motion/Tokens/ Accessibility sections updated to match; checksum refreshed.
…ch addons The stock <input> in the middle slot was rendering at browser default (~16px) while the addons use text-label-sm (12px), producing a size mismatch. Add text-label-sm + placeholder:text-[var(--text-muted)] so the middle input matches both the addons and input-text's inner input font. Spec and stories updated together; checksum refreshed.
…up addons The <input> in the middle slot inherited the group's --bg-surface and used --text-default, making it read visually distinct from the addons (which use --bg-canvas and --text-muted). Align both so left addon, middle input, and right addon share the same dark fill and muted text — one continuous surface behind the group's outer border.
…he darker islands Previous commit incorrectly aligned the middle input's background to --bg-canvas alongside the addons, flattening the group visually. The Figma design has the addons as darker --bg-canvas islands on either side of the middle input, which inherits the root's --bg-surface. Also restores --text-default for the input's typed value while keeping the muted placeholder. Spec and stories updated together; checksum refreshed.
…licit border color The previous [&:not(:last-child)]:border-r / [&:not(:first-child)]:border-l pattern relied on Tailwind arbitrary variants that were not producing a visible seam. Switch to Tailwind's built-in first: and last: variants (first-child addon = left, gets border-r toward the input; last-child addon = right, gets border-l toward the input) and force color interpretation with border-[color:var(--border-default)] so the border color applies unambiguously. Spec updated to match.
…SlotRight sub-components Instead of a single positional Addon sub-component that inferred left or right from source order and drew its seam via first:/last: CSS selectors, expose two explicit sub-components — InputGroupSlotLeft and InputGroupSlotRight. Each hardcodes its own seam (SlotLeft: border-r, SlotRight: border-l) and its own testid fallback, making position unambiguous at the template level and eliminating any dependence on CSS pseudo-class resolution. Compound API becomes <InputGroup.SlotLeft>...</InputGroup.SlotLeft> and <InputGroup.SlotRight>...</InputGroup.SlotRight>. The exports map gains ./input-group-slot-left and ./input-group-slot-right in place of ./input-group-addon. Spec, stories, and package.json all updated together; checksum refreshed to aefeab87... No consumers have shipped against the Addon API yet (pre-release, still on the open feat branch).
… / #right slots Align InputGroup's API with input-text, input-number, and field-text — which all use named slots on the root (iconLeft/iconRight, prefix/ suffix) instead of a compound API with sub-components. The named-slot approach eliminates: - The compound layer (index.ts + Object.assign). - The injection-key.ts marker (nobody was consuming it yet). - The two sub-component files, their per-slot exports, and the tree-shaking -root export. - The JIT scan surprise on newly-created files (all classes now live on a single .vue that Tailwind already tracks). The visual behavior is unchanged — left slot still bg-canvas + border-r toward the input, right slot bg-canvas + border-l, root still owns focus-within ring / hover strong / invalid+required border colors. spec_version bumped to 2 (structure changed from composition to monolithic), body re-authored, checksum refreshed to a875eb1a... Stories updated to use <template #left> / <template #right>.
…WithIcon story InputGroup gains a disabled prop (spec bump 2 to 3) with data-disabled mirror, aria-disabled on the root, and disabled-state tokens borrowed from input-text: bg-disabled fill, text-disabled color, not-allowed cursor, focus-within ring suppressed, hover ignored. Story WithIcon added showing PrimeIcons in the side slots (pi pi-globe and pi pi-times) so consumers see how icons inhabit the slots at label-sm size. Story Disabled added. New FieldInputGroup component mirrors FieldText verbatim, adapted to the InputGroup primitive: renders its own middle <input>, exposes only left and right slots forwarded to InputGroup, computes helperKind via disabled greater invalid greater required greater helper precedence, auto-ids via useId, wires aria-describedby to HelperText. Six stories Default, WithSlots, Required (reactive validation flow), Invalid, Disabled, Icons. Package export ./field-input-group added; lint, type-check, type- coverage 99.96%, storybook:build all green.
… indicator The Required tag (severity=warning size=small) is replaced by inline text 'asterisk + Required', where the asterisk uses var(--primary) (orange F3652B) and the word Required uses var(--text-muted). The asterisk is decorative (aria-hidden=true) so screen readers announce only 'Required' alongside the label text. Applies uniformly across every consumer of Label with required=true: field-text, field-password, field-input-group, field-checkbox, field-radio, field-switch, field-textarea. Tag component is no longer imported by label.vue. Spec body updated (Purpose, Props JSDoc, Tokens, Accessibility); checksum refreshed to e261b72f (also fixes a pre-existing checksum drift on label.md that the enforce-spec-exists hook flagged when this change tried to write).
…parentheses Wrap the required word in parentheses and add a space between the asterisk and the parenthesized text, producing '* (Required)' instead of the previous '*Required'. The asterisk stays orange (var(--primary)) and (Required) stays muted (var(--text-muted)); the * remains aria-hidden so screen readers still announce only '(Required)'. Spec Purpose, Props JSDoc, Tokens, and Accessibility sections updated to match; checksum refreshed.
3 tasks
robsongajunior
requested changes
Jul 1, 2026
robsongajunior
left a comment
Contributor
There was a problem hiding this comment.
The input group the examples it's wrong.
- The sample default is with slot.
- Use the Primevue like example
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Adds a new
input-groupwebkit component implementing Figma node 3714-10802. Composition pattern with compound API —<InputGroup>root wraps a middle input primitive and accepts<InputGroup.Addon>sub-components on either side (position derived from source order).invalid,required(both boolean, defaultfalse).--border-default;invalid→--danger-border;invalid + required→--warning-border.InputGroupContextKey(marker symbol) viainject/provideso future input primitives can render borderless inside the group.[&:not(:last-child)]:border-r [&:not(:first-child)]:border-l— no<Divider>element required, no v-node inspection.InputGroup.Addon: no props,defaultslot for icon/text/button content.<input>styledborder-0 outline-none focus:ring-0. Follow-up PR will teachinput-textto detect the group context and self-flatten its border (bumpinput-textspec_version).Notes
New exports (flat, per
.claude/rules/imports.md)@aziontech/webkit/input-group— compound (leads the docs,Object.assignroot +Addon)@aziontech/webkit/input-group-root— tree-shakeable standalone root@aziontech/webkit/input-group-addon— standalone sub-componentFiles added
.specs/input-group.md(status: implemented)packages/webkit/src/components/inputs/input-group/input-group.vuepackages/webkit/src/components/inputs/input-group/input-group-addon/input-group-addon.vuepackages/webkit/src/components/inputs/input-group/injection-key.tspackages/webkit/src/components/inputs/input-group/index.tsapps/storybook/src/stories/components/inputs/input-group/InputGroup.stories.js(6 stories: Default, WithLeftAddon, WithRightAddon, BothAddons, Invalid, InvalidRequired)Pipeline results
spec-validator✓ ·reuse-auditor✓ ·scaffolder✓ ·storybook-writer✓ ·echo-reporter✓ (parity)pnpm webkit:lint✓ ·type-check✓ ·type-coverage99.96% ✓ ·storybook:build11.41s ✓Follow-ups (separate PRs)
@figma/code-connectand addinput-group.figma.tsmapping.input-textspec:inject(InputGroupContextKey, false)→ render borderless when nested.Test plan
pnpm storybook:dev— openComponents/Inputs/InputGroup, verify all 6 stories render 1-to-1 with the Figma design.invalidalone shows red border;invalid + requiredshows yellow border..claude/rules/storybook-source.md).@aziontech/webkit/input-group-rootimported alone does not pull in the addon.