diff --git a/.changeset/new-students-change.md b/.changeset/new-students-change.md new file mode 100644 index 0000000000..e983d38e24 --- /dev/null +++ b/.changeset/new-students-change.md @@ -0,0 +1,5 @@ +--- +"@primer/view-components": patch +--- + +Add trailing visuals to the text field diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/alpha/text_field/with_trailing_visual/default.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/alpha/text_field/with_trailing_visual/default.png new file mode 100644 index 0000000000..d1927f54b1 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/alpha/text_field/with_trailing_visual/default.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/alpha/text_field/with_trailing_visual/focused.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/alpha/text_field/with_trailing_visual/focused.png new file mode 100644 index 0000000000..0d5eb90aa1 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/alpha/text_field/with_trailing_visual/focused.png differ diff --git a/app/components/primer/alpha/text_field.pcss b/app/components/primer/alpha/text_field.pcss index cb46fdb8ae..12d43406e4 100644 --- a/app/components/primer/alpha/text_field.pcss +++ b/app/components/primer/alpha/text_field.pcss @@ -121,6 +121,8 @@ ** .FormControl ** ├─ .FormControl-label ** │ ├─ .FormControl-input-wrap +** │ │ ├─ .FormControl-input-trailingVisualWrap +** │ │ │ ├─ .FormControl-input-trailingVisual ** │ │ ├─ .FormControl-input-leadingVisualWrap ** │ │ │ ├─ .FormControl-input-leadingVisual ** │ │ ├─ .FormControl-input @@ -253,6 +255,23 @@ } } + & .FormControl-input-trailingVisualWrap { + position: absolute; + top: var(--base-size-8); + right: var(--base-size-8); + display: block; + width: var(--base-size-16); + height: var(--base-size-16); + color: var(--fgColor-muted); + pointer-events: none; + + /* octicon */ + & .FormControl-input-trailingVisual { + display: block; + user-select: none; + } + } + /* TODO: replace with new Button component */ & .FormControl-input-trailingAction { position: absolute; @@ -333,10 +352,28 @@ } } + /* if trailingVisual is present */ + + /* + ┌──────────────────┬──32px──┐ + ╎ ┌──────────────┐ ┌────┐ ╎ + ╎ 24px 24px ╎ + ╎ └──────────────┘ └────┘ ╎ + └──────────────────┴────────┘ + */ + + &.FormControl-input-wrap--trailingVisual { + & .FormControl-input { + padding-inline-end: calc( + var(--control-medium-paddingInline-condensed) + var(--base-size-16) + var(--control-medium-gap) + ); /* 32px */ + } + } + /* ┌──────────────────┬──32px──┐ ╎ ┌──────────────┐ ┌────┐ ╎ - ╎ 24px 24px ╎ + ╎ 24px 24px ╎ ╎ └──────────────┘ └────┘ ╎ └──────────────────┴────────┘ */ @@ -377,6 +414,10 @@ top: calc(var(--control-medium-paddingInline-condensed) - var(--base-size-2)); /* 6px */ left: calc(var(--control-medium-paddingInline-condensed) - var(--base-size-2)); /* 6px */ } + & .FormControl-input-trailingVisualWrap { + top: calc(var(--control-medium-paddingInline-condensed) - var(--base-size-2)); /* 6px */ + right: calc(var(--control-medium-paddingInline-condensed) - var(--base-size-2)); /* 6px */ + } /* ┌──────────────────┬──28px──┐ @@ -427,6 +468,10 @@ top: var(--control-medium-paddingInline-normal); left: var(--control-medium-paddingInline-normal); } + & .FormControl-input-trailingVisualWrap { + top: var(--control-medium-paddingInline-normal); + right: var(--control-medium-paddingInline-normal); + } /* ┌──36px──┬───12px padding──────┐ @@ -443,6 +488,13 @@ ); /* 36px */ } } + &.FormControl-input-wrap--trailingVisual { + & .FormControl-input.FormControl-large { + padding-inline-end: calc( + var(--control-large-paddingInline-normal) + var(--base-size-16) + var(--control-large-gap) + ); /* 36px */ + } + } /* ┌──────────────────┬──36px──┐ diff --git a/app/lib/primer/forms/dsl/text_field_input.rb b/app/lib/primer/forms/dsl/text_field_input.rb index 698189fcc8..e8e8901ead 100644 --- a/app/lib/primer/forms/dsl/text_field_input.rb +++ b/app/lib/primer/forms/dsl/text_field_input.rb @@ -7,7 +7,7 @@ module Dsl class TextFieldInput < Input attr_reader( *%i[ - name label show_clear_button leading_visual leading_spinner clear_button_id + name label show_clear_button leading_visual leading_spinner trailing_visual clear_button_id visually_hide_label inset monospace field_wrap_classes auto_check_src ] ) @@ -20,6 +20,7 @@ def initialize(name:, label:, **system_arguments) @show_clear_button = system_arguments.delete(:show_clear_button) @leading_visual = system_arguments.delete(:leading_visual) + @trailing_visual = system_arguments.delete(:trailing_visual) @leading_spinner = !!system_arguments.delete(:leading_spinner) @clear_button_id = system_arguments.delete(:clear_button_id) @inset = system_arguments.delete(:inset) @@ -33,6 +34,13 @@ def initialize(name:, label:, **system_arguments) ) end + if @trailing_visual + @trailing_visual[:classes] = class_names( + "FormControl-input-trailingVisual", + @trailing_visual[:classes] + ) + end + if @leading_spinner && !@leading_visual raise ArgumentError, "text fields that request a leading spinner must also specify a leading visual" end @@ -48,6 +56,14 @@ def initialize(name:, label:, **system_arguments) alias inset? inset alias monospace? monospace + def trailing_visual? + !!@trailing_visual + end + + def leading_visual? + !!@leading_visual + end + def to_component TextField.new(input: self) end @@ -60,10 +76,6 @@ def focusable? true end - def leading_visual? - !!@leading_visual - end - def validation_arguments if auto_check_src.present? super.merge( diff --git a/app/lib/primer/forms/text_field.html.erb b/app/lib/primer/forms/text_field.html.erb index 7b06434e76..a7e99afaee 100644 --- a/app/lib/primer/forms/text_field.html.erb +++ b/app/lib/primer/forms/text_field.html.erb @@ -17,5 +17,12 @@ <%= render(Primer::Beta::Octicon.new(icon: :"x-circle-fill")) %> <% end %> + <% if @input.trailing_visual%> + + <% if @input.trailing_visual %> + <%= render(Primer::Beta::Octicon.new(**@input.trailing_visual, data: { target: "primer-text-field.trailingVisual" })) %> + <% end %> + + <% end %> <% end %> <% end %> diff --git a/app/lib/primer/forms/text_field.rb b/app/lib/primer/forms/text_field.rb index 1840f92434..07b68fb6bf 100644 --- a/app/lib/primer/forms/text_field.rb +++ b/app/lib/primer/forms/text_field.rb @@ -24,6 +24,7 @@ def initialize(input:) "FormControl-input-wrap", INPUT_WRAP_SIZE[input.size], "FormControl-input-wrap--trailingAction": @input.show_clear_button?, + "FormControl-input-wrap--trailingVisual": @input.trailing_visual?, "FormControl-input-wrap--leadingVisual": @input.leading_visual? ), diff --git a/previews/primer/alpha/text_field_preview.rb b/previews/primer/alpha/text_field_preview.rb index e077ff0d09..d020cfdd9f 100644 --- a/previews/primer/alpha/text_field_preview.rb +++ b/previews/primer/alpha/text_field_preview.rb @@ -172,6 +172,12 @@ def monospace render(Primer::Alpha::TextField.new(monospace: true, name: "my-text-field", label: "My text field")) end + # @label With trailing visual + # @snapshot + def with_trailing_visual + render(Primer::Alpha::TextField.new(trailing_visual: { icon: :search }, name: "my-text-field", label: "My text field")) + end + # @label With leading visual # @snapshot def with_leading_visual