fix(select): do not collapse to width: 0 when placed in flex container (#28631)
Issue number: Internal --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> We currently apply a workaround to `ion-select` so it can wrap correctly inside of `ion-item`:357b8b2beb/core/src/components/select/select.scss (L99-L103)However, this causes issues when a parent element has `display: flex` because the `ion-select` width becomes 0. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - In order to get the desired behavior, we need the `ion-select` (and other elements in the default slot) to either truncate or wrap within its own container and then have the entire container (i.e. the entire `ion-select`) wrap to the next line once the container is too small. To achieve this, I needed to set a min-width on `.item-inner` to define the point at which the element should wrap to the next line. I also changed the flex basis from `auto` to `0` which means the initial main size of the flex item will be 0px. In reality, this will be `--inner-min-width` since we also set `min-width: var(--inner-min-width)`. I used `0` for simplicity but I can change this to use the CSS variable if that's more clear. Since we also set `flex-grow: 1` we indicate that the element can grow from that basis (but it cannot shrink). I chose `--inner-min-width: 4rem` to minimize the number of diffs. We can certainly change this, but it may cause some diffs as certain elements will start wrapping sooner. I also chose to use `rem` because having a fixed min-width means that fewer characters are going to fit in the same space as text scales. I made this a CSS variable but left it undocumented. If developers need a way of changing this `min-width` they can request it and we can easily expose this variable. However, I think `4rem` is small enough that this should be sufficient. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> The visual diffs here are correct. The table below shows the screenshot group and an explanation for why the changes are correct. | Path | Example | Details | | - | - | - | | `disabled` | [Link](https://github.com/ionic-team/ionic-framework/pull/28631/files#diff-d529716f95f7a7aa82c88588104220775b728af67077f48cd47a8afa04423143) | The searchbar is able to shrink slightly to fit on the same line as the checkbox at the bottom. | | `highlight` | [Link](https://github.com/ionic-team/ionic-framework/pull/28631/files#diff-0b64f24c91393923701d1ced4e330a1c6b926d72ee461b8ab1e135e708be3457) | We're changing how small the main content can get, so the input is only wrapping once it gets to `--inner-min-width`. | | `legacy/fill` | [Link](https://github.com/ionic-team/ionic-framework/pull/28631/files#diff-2ef8dbfa5e69e2b96c3e1ed29ab962f08cf5ba2aaf2af773e40bd143e38a4bef) | We're changing how small the main content can get, so the input is only wrapping once it gets to `--inner-min-width`. | | `slotted-inputs` | [Link](https://github.com/ionic-team/ionic-framework/pull/28631/files#diff-2f173c7303969d6a6c58f30a618cebc3caf918d3761fc83df5642fd48dfabd7b) | We're changing how small the main content can get, so the range is only wrapping once it gets to `--inner-min-width`. | `slotted-inputs` note: I'd argue many of these examples are not best practices. For example, adding a range in the start slot and the end slot is a bit unusual. I'm not aware of any native apps that implement this pattern. popover note: I [removed the `ion-item` from the `popover/test/async` test](331fcb859c). There was a diff because the min-width increased, but IMO that component should not be used in the popover test since we want to test the popover, not the item. -------- Demo: | `feature-7.6` | `branch` | | - | - | | <video src="https://github.com/ionic-team/ionic-framework/assets/2721089/693d4947-fa33-460d-bc7f-7b96b6338032"></video> | <video src="https://github.com/ionic-team/ionic-framework/assets/2721089/df35ca73-87aa-4e76-9bb7-99f0f2810640"></video> | (In this demo I updated the `ion-select` to wrap within its own container first instead of truncate. We may want to consider doing this by default, but I think this is out of scope for this task) --------- Co-authored-by: ionitron <hi@ionicframework.com> Co-authored-by: Brandy Carney <brandy@ionic.io>
@ -51,6 +51,15 @@
|
||||
* @prop --highlight-color-valid: The color of the highlight on the item when valid. Only applies to inputs and textareas using the legacy form syntax. DEPRECATED: Highlights can be styled on `ion-input` or `ion-textarea` when using the modern form syntax.
|
||||
* @prop --highlight-color-invalid: The color of the highlight on the item when invalid. Only applies to inputs and textareas using the legacy form syntax. DEPRECATED: Highlights can be styled on `ion-input` or `ion-textarea` when using the modern form syntax.
|
||||
*/
|
||||
|
||||
/**
|
||||
* We change the minimum width as the
|
||||
* font size changes. Using a fixed minimum
|
||||
* width means that fewer and fewer characters
|
||||
* can be displayed in the same space as the
|
||||
* text grows.
|
||||
*/
|
||||
--inner-min-width: 4rem;
|
||||
--border-radius: 0px;
|
||||
--border-width: 0px;
|
||||
--border-style: solid;
|
||||
@ -80,15 +89,6 @@
|
||||
|
||||
position: relative;
|
||||
|
||||
// When an item containing a select is inside of a
|
||||
// flex container the item will collapse to 0px
|
||||
// width due to the select setting the width to 0px.
|
||||
// By setting the flex property here, we are
|
||||
// allowing the item to grow to fill the flex container.
|
||||
// If the item is inside of a block container this
|
||||
// property will be ignored.
|
||||
flex: 1;
|
||||
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
@ -310,7 +310,7 @@ button, a {
|
||||
// This flex property is required in order to make
|
||||
// the elements wrap when there is a slotted start
|
||||
// element and a label
|
||||
flex: 1 0 auto;
|
||||
flex: 1 0 0;
|
||||
|
||||
flex-direction: inherit;
|
||||
|
||||
@ -322,6 +322,15 @@ button, a {
|
||||
align-items: inherit;
|
||||
align-self: stretch;
|
||||
|
||||
/**
|
||||
* The min-width defines when the
|
||||
* content in the default slot should
|
||||
* stop wrapping/truncating within its own
|
||||
* container. At this point the entire
|
||||
* container will wrap to the next line.
|
||||
*/
|
||||
min-width: var(--inner-min-width);
|
||||
|
||||
// Max width must be set to 100%, otherwise the
|
||||
// elements will overflow this container instead
|
||||
// of wrapping
|
||||
|
||||
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@ -40,9 +40,7 @@
|
||||
popover.addEventListener('ionMount', () => {
|
||||
popover.innerHTML = `
|
||||
<div style="padding: 10px;">
|
||||
<ion-list>
|
||||
<ion-item>Item 1</ion-item>
|
||||
</ion-list>
|
||||
Popover Content
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 6.6 KiB |
@ -92,14 +92,11 @@
|
||||
|
||||
// TODO FW-3194 - Remove the :not(.legacy-select) piece
|
||||
//
|
||||
// The flex and width properties are required here
|
||||
// in order to allow the select to shrink inside of an item
|
||||
// otherwise it always wraps to the next line even
|
||||
// when it can shrink
|
||||
// The flex property is required here in order to allow
|
||||
// the select to shrink inside of an item otherwise it
|
||||
// always wraps to the next line even when it can shrink
|
||||
:host(.in-item:not(.legacy-select)) {
|
||||
flex: 1 1 0;
|
||||
|
||||
width: 0;
|
||||
}
|
||||
|
||||
// TODO FW-3194 - Remove this
|
||||
|
||||
@ -45,11 +45,13 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<div id="container" style="display: flex">
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-select label="Fruit" value="apple">
|
||||
<ion-select-option value="apple">Apple</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<ion-list>
|
||||
</div>
|
||||
`,
|
||||
config
|
||||
|
||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |