Skip to content

Commit 320a41a

Browse files
committed
refactor(select): more styles
1 parent 7563ed5 commit 320a41a

File tree

5 files changed

+224
-16
lines changed

5 files changed

+224
-16
lines changed

core/src/components/select/select.common.scss

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@ button {
119119
// --------------------------------------------------
120120

121121
.select-icon {
122-
position: relative;
123-
124122
/**
125123
* Prevent the icon from shrinking when the label and/or
126124
* selected item text is long enough to fill the rest of
@@ -138,18 +136,6 @@ button {
138136
color: inherit;
139137
}
140138

141-
/**
142-
* The select icon should be centered with
143-
* the entire container not just the control
144-
* with floating/stacked labels.
145-
*/
146-
:host(.select-label-placement-stacked) .select-icon,
147-
:host(.select-label-placement-floating) .select-icon {
148-
position: absolute;
149-
150-
height: 100%;
151-
}
152-
153139
/**
154140
* This positions the icon at the correct
155141
* edge of the component with LTR and RTL
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
@use "../../themes/ionic/ionic.globals.scss" as globals;
2+
3+
// Select Fill: Outline (Ionic Theme)
4+
// ----------------------------------------------------------------
5+
6+
:host(.select-fill-outline) {
7+
// TODO(ROU-10778, ROU-10875): Sync the color names to the design system of
8+
// ios and md. This will allow us to have a single color map.
9+
--border-color: #{globals.current-color(neutral)};
10+
--border-radius: #{globals.$ion-border-radius-400};
11+
--border-width: #{globals.$ion-border-size-025};
12+
}
13+
14+
:host(.ion-color) {
15+
--border-color: #{globals.current-color(base)};
16+
}
17+
18+
// Select Wrapper
19+
// --------------------------------------------------
20+
21+
:host(.select-fill-outline.select-label-placement-stacked) .label-text-wrapper,
22+
:host(.select-fill-outline.select-label-placement-floating) .label-text-wrapper {
23+
/**
24+
* Label text should not extend
25+
* beyond the bounds of the select.
26+
*/
27+
max-width: calc(100% - var(--padding-start) - var(--padding-end));
28+
}
29+
30+
// Select Label
31+
// ----------------------------------------------------------------
32+
33+
:host(.select-fill-outline) .label-text-wrapper {
34+
/**
35+
* The label should appear on top of an outline
36+
* container that overlaps it so it is always clickable.
37+
*/
38+
position: relative;
39+
}
40+
41+
// Select Inner Wrapper
42+
// ----------------------------------------------------------------
43+
44+
:host(.select-fill-outline) .select-wrapper-inner {
45+
@include globals.border-radius(var(--border-radius));
46+
@include globals.padding(var(--padding-top), var(--padding-end), var(--padding-bottom), var(--padding-start));
47+
48+
min-height: 40px;
49+
50+
/**
51+
* Apply the background to the native select
52+
* wrapper to only style the select.
53+
*/
54+
background: var(--background);
55+
}
56+
57+
// Outline Container
58+
// ----------------------------------------------------------------
59+
60+
:host(.select-fill-outline) .select-outline {
61+
@include globals.position(0, 0, 0, 0);
62+
@include globals.border-radius(var(--border-radius));
63+
64+
position: absolute;
65+
66+
width: 100%;
67+
height: 100%;
68+
69+
pointer-events: none;
70+
71+
border: var(--border-width) var(--border-style) var(--border-color);
72+
73+
box-sizing: border-box;
74+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,132 @@
11
@use "../../themes/ionic/ionic.globals.scss" as globals;
22
@use "./select.common";
3+
@use "./select.ionic.outline" as outline;
34

45
// Ionic Select
56
// -------------------------------------------------
67

8+
:host {
9+
--background: #{globals.$ion-primitives-base-white};
10+
--padding-start: #{globals.$ion-space-400};
11+
--padding-end: #{globals.$ion-space-400};
12+
--padding-top: #{globals.$ion-space-300};
13+
--padding-bottom: #{globals.$ion-space-300};
14+
--placeholder-color: #{globals.$ion-primitives-neutral-800};
15+
16+
width: fit-content;
17+
}
18+
719
// Select Label
820
// ----------------------------------------------------------------
921

1022
.label-text-wrapper {
1123
@include globals.typography(globals.$ion-body-sm-medium);
24+
25+
color: globals.$ion-primitives-neutral-1000;
26+
}
27+
28+
// Select Label Placement - Start & Fixed
29+
// ----------------------------------------------------------------
30+
31+
:host(.select-label-placement-start) .label-text-wrapper,
32+
:host(.select-label-placement-fixed) .label-text-wrapper {
33+
/**
34+
* The margin between the label and
35+
* the select should be on the end
36+
* when the label sits at the start.
37+
*/
38+
@include globals.margin(0, globals.$ion-space-100, 0, 0);
39+
}
40+
41+
// Select Label Placement - End
42+
// ----------------------------------------------------------------
43+
44+
:host(.select-label-placement-end) .label-text-wrapper {
45+
/**
46+
* The margin between the label and
47+
* the select should be on the start
48+
* when the label sits at the end.
49+
*/
50+
@include globals.margin(0, 0, 0, globals.$ion-space-100);
51+
}
52+
53+
// Select Label Placement - Stacked & Floating
54+
// ----------------------------------------------------------------
55+
56+
:host(.select-label-placement-stacked) .label-text-wrapper,
57+
:host(.select-label-placement-floating) .label-text-wrapper {
58+
/**
59+
* The margin between the label and
60+
* the select should be on the bottom
61+
* when the label sits at the top.
62+
*/
63+
@include globals.margin(0, 0, globals.$ion-space-100, 0);
64+
}
65+
66+
// Select Text
67+
// ----------------------------------------------------------------
68+
69+
// Targets the text inside the select and the placeholder
70+
.select-text {
71+
@include globals.typography(globals.$ion-body-md-regular);
72+
73+
color: globals.$ion-primitives-neutral-1200;
74+
}
75+
76+
// Select Wrapper
77+
// ----------------------------------------------------------------
78+
79+
.select-wrapper {
80+
background: transparent;
81+
}
82+
83+
// Select Inner Wrapper
84+
// ----------------------------------------------------------------
85+
86+
.select-wrapper-inner {
87+
position: relative;
88+
89+
min-width: globals.$ion-scale-5000;
90+
height: globals.$ion-scale-1200;
91+
92+
background: var(--background);
93+
94+
box-sizing: border-box;
95+
96+
gap: globals.$ion-space-200;
97+
}
98+
99+
// Start/End Slots
100+
// ----------------------------------------------------------------
101+
102+
/**
103+
* Slotted buttons have a lot of default padding that can
104+
* cause them to look misaligned from other pieces such
105+
* as the control's label, especially when using a clear
106+
* fill. We also make them circular to ensure that non-
107+
* clear buttons and the focus/hover state on clear ones
108+
* don't look too crowded.
109+
*/
110+
::slotted(ion-button[slot="start"].button-has-icon-only),
111+
::slotted(ion-button[slot="end"].button-has-icon-only) {
112+
--border-radius: 50%;
113+
--padding-start: 8px;
114+
--padding-end: 8px;
115+
--padding-top: 8px;
116+
--padding-bottom: 8px;
117+
118+
aspect-ratio: 1;
119+
}
120+
121+
// Select Icon
122+
// --------------------------------------------------
123+
124+
.select-icon,
125+
::slotted(ion-icon) {
126+
width: globals.$ion-scale-400;
127+
height: globals.$ion-scale-400;
128+
}
129+
130+
.select-icon {
131+
color: globals.$ion-primitives-neutral-800;
12132
}

core/src/components/select/select.native.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@
1717

1818
.select-icon {
1919
@include margin(0, 0, 0, $select-icon-margin-start);
20+
21+
position: relative;
22+
}
23+
24+
/**
25+
* The select icon should be centered with
26+
* the entire container not just the control
27+
* with floating/stacked labels.
28+
*/
29+
:host(.select-label-placement-stacked) .select-icon,
30+
:host(.select-label-placement-floating) .select-icon {
31+
position: absolute;
32+
33+
height: 100%;
2034
}
2135

2236
// Select Wrapper

core/src/components/select/select.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,8 @@ export class Select implements ComponentInterface {
997997
this;
998998
const theme = getIonTheme(this);
999999
const hasFloatingOrStackedLabel = labelPlacement === 'floating' || labelPlacement === 'stacked';
1000+
const shouldRenderOuterIcon = theme !== 'ionic' && hasFloatingOrStackedLabel;
1001+
const shouldRenderInnerIcon = theme === 'ionic' || !hasFloatingOrStackedLabel;
10001002
const justifyEnabled = !hasFloatingOrStackedLabel && justify !== undefined;
10011003
const rtl = isRTL(el) ? 'rtl' : 'ltr';
10021004
const inItem = hostContext('ion-item', this.el);
@@ -1051,13 +1053,25 @@ export class Select implements ComponentInterface {
10511053
<label class="select-wrapper" id="select-label">
10521054
{this.renderLabelContainer()}
10531055
<div class="select-wrapper-inner">
1056+
{
1057+
/**
1058+
* For the ionic theme, we render the outline container here
1059+
* instead of higher up, so it can be positioned relative to
1060+
* the native wrapper instead of the <label> element or the
1061+
* entire component. This allows the label text to be positioned
1062+
* above the outline, while staying within the bounds of the
1063+
* <label> element, ensuring that clicking the label text
1064+
* focuses the select.
1065+
*/
1066+
theme === 'ionic' && fill === 'outline' && <div class="select-outline"></div>
1067+
}
10541068
<slot name="start"></slot>
10551069
<div class="native-wrapper" ref={(el) => (this.nativeWrapperEl = el)} part="container">
10561070
{this.renderSelectText()}
10571071
{this.renderListbox()}
10581072
</div>
10591073
<slot name="end"></slot>
1060-
{!hasFloatingOrStackedLabel && this.renderSelectIcon()}
1074+
{shouldRenderInnerIcon && this.renderSelectIcon()}
10611075
</div>
10621076
{/**
10631077
* The icon in a floating/stacked select
@@ -1068,7 +1082,7 @@ export class Select implements ComponentInterface {
10681082
* icon outside the inner wrapper, which holds
10691083
* those components.
10701084
*/}
1071-
{hasFloatingOrStackedLabel && this.renderSelectIcon()}
1085+
{shouldRenderOuterIcon && this.renderSelectIcon()}
10721086
{shouldRenderHighlight && <div class="select-highlight"></div>}
10731087
</label>
10741088
</Host>

0 commit comments

Comments
 (0)