Skip to content

Commit 3628ea8

Browse files
tanner-reitsbrandyscarney
authored and
Tanner Reits
committed
feat(select): add modal as interface (#29972)
Issue number: resolves 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. --> Select only offers `alert`, `action-sheet`, and `popover` as interfaces ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> Adds `modal` as an interface option for `ion-select` ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> --------- Co-authored-by: Brandy Carney <[email protected]>
1 parent 0fdcb32 commit 3628ea8

35 files changed

+651
-33
lines changed

core/api.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,7 @@ ion-select,prop,compareWith,((currentValue: any, compareValue: any) => boolean)
16141614
ion-select,prop,disabled,boolean,false,false,false
16151615
ion-select,prop,expandedIcon,string | undefined,undefined,false,false
16161616
ion-select,prop,fill,"outline" | "solid" | undefined,undefined,false,false
1617-
ion-select,prop,interface,"action-sheet" | "alert" | "popover",'alert',false,false
1617+
ion-select,prop,interface,"action-sheet" | "alert" | "modal" | "popover",'alert',false,false
16181618
ion-select,prop,interfaceOptions,any,{},false,false
16191619
ion-select,prop,justify,"end" | "space-between" | "start" | undefined,undefined,false,false
16201620
ion-select,prop,label,string | undefined,undefined,false,false
@@ -1672,6 +1672,11 @@ ion-select,part,label
16721672
ion-select,part,placeholder
16731673
ion-select,part,text
16741674

1675+
ion-select-modal,scoped
1676+
ion-select-modal,prop,header,string | undefined,undefined,false,false
1677+
ion-select-modal,prop,multiple,boolean | undefined,undefined,false,false
1678+
ion-select-modal,prop,options,SelectModalOption[],[],false,false
1679+
16751680
ion-select-option,shadow
16761681
ion-select-option,prop,disabled,boolean,false,false,false
16771682
ion-select-option,prop,value,any,undefined,false,false

core/src/components.d.ts

+27-5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./compone
3535
import { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
3636
import { SegmentButtonLayout } from "./components/segment-button/segment-button-interface";
3737
import { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
38+
import { SelectModalOption } from "./components/select-modal/select-modal-interface";
3839
import { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
3940
import { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
4041
import { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
@@ -70,6 +71,7 @@ export { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./compone
7071
export { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
7172
export { SegmentButtonLayout } from "./components/segment-button/segment-button-interface";
7273
export { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
74+
export { SelectModalOption } from "./components/select-modal/select-modal-interface";
7375
export { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
7476
export { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
7577
export { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
@@ -639,6 +641,7 @@ export namespace Components {
639641
* The name of the control, which is submitted with the form data.
640642
*/
641643
"name": string;
644+
"setFocus": () => Promise<void>;
642645
/**
643646
* The value of the checkbox does not mean if it's checked or not, use the `checked` property for that. The value of a checkbox is analogous to the value of an `<input type="checkbox">`, it's only used when the checkbox participates in a native `<form>`.
644647
*/
@@ -2279,7 +2282,7 @@ export namespace Components {
22792282
*/
22802283
"name": string;
22812284
"setButtonTabindex": (value: number) => Promise<void>;
2282-
"setFocus": (ev: globalThis.Event) => Promise<void>;
2285+
"setFocus": (ev?: globalThis.Event) => Promise<void>;
22832286
/**
22842287
* the value of the radio.
22852288
*/
@@ -2741,11 +2744,11 @@ export namespace Components {
27412744
*/
27422745
"fill"?: 'outline' | 'solid';
27432746
/**
2744-
* The interface the select should use: `action-sheet`, `popover` or `alert`.
2747+
* The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
27452748
*/
27462749
"interface": SelectInterface;
27472750
/**
2748-
* Any additional options that the `alert`, `action-sheet` or `popover` interface can take. See the [ion-alert docs](./alert), the [ion-action-sheet docs](./action-sheet) and the [ion-popover docs](./popover) for the create options for each interface. Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
2751+
* Any additional options that the `alert`, `action-sheet` or `popover` interface can take. See the [ion-alert docs](./alert), the [ion-action-sheet docs](./action-sheet), the [ion-popover docs](./popover), and the [ion-modal docs](./modal) for the create options for each interface. Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
27492752
*/
27502753
"interfaceOptions": any;
27512754
/**
@@ -2802,6 +2805,11 @@ export namespace Components {
28022805
*/
28032806
"value"?: any | null;
28042807
}
2808+
interface IonSelectModal {
2809+
"header"?: string;
2810+
"multiple"?: boolean;
2811+
"options": SelectModalOption[];
2812+
}
28052813
interface IonSelectOption {
28062814
/**
28072815
* If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
@@ -4434,6 +4442,12 @@ declare global {
44344442
prototype: HTMLIonSelectElement;
44354443
new (): HTMLIonSelectElement;
44364444
};
4445+
interface HTMLIonSelectModalElement extends Components.IonSelectModal, HTMLStencilElement {
4446+
}
4447+
var HTMLIonSelectModalElement: {
4448+
prototype: HTMLIonSelectModalElement;
4449+
new (): HTMLIonSelectModalElement;
4450+
};
44374451
interface HTMLIonSelectOptionElement extends Components.IonSelectOption, HTMLStencilElement {
44384452
}
44394453
var HTMLIonSelectOptionElement: {
@@ -4722,6 +4736,7 @@ declare global {
47224736
"ion-segment": HTMLIonSegmentElement;
47234737
"ion-segment-button": HTMLIonSegmentButtonElement;
47244738
"ion-select": HTMLIonSelectElement;
4739+
"ion-select-modal": HTMLIonSelectModalElement;
47254740
"ion-select-option": HTMLIonSelectOptionElement;
47264741
"ion-select-popover": HTMLIonSelectPopoverElement;
47274742
"ion-skeleton-text": HTMLIonSkeletonTextElement;
@@ -7497,11 +7512,11 @@ declare namespace LocalJSX {
74977512
*/
74987513
"fill"?: 'outline' | 'solid';
74997514
/**
7500-
* The interface the select should use: `action-sheet`, `popover` or `alert`.
7515+
* The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
75017516
*/
75027517
"interface"?: SelectInterface;
75037518
/**
7504-
* Any additional options that the `alert`, `action-sheet` or `popover` interface can take. See the [ion-alert docs](./alert), the [ion-action-sheet docs](./action-sheet) and the [ion-popover docs](./popover) for the create options for each interface. Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
7519+
* Any additional options that the `alert`, `action-sheet` or `popover` interface can take. See the [ion-alert docs](./alert), the [ion-action-sheet docs](./action-sheet), the [ion-popover docs](./popover), and the [ion-modal docs](./modal) for the create options for each interface. Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
75057520
*/
75067521
"interfaceOptions"?: any;
75077522
/**
@@ -7577,6 +7592,11 @@ declare namespace LocalJSX {
75777592
*/
75787593
"value"?: any | null;
75797594
}
7595+
interface IonSelectModal {
7596+
"header"?: string;
7597+
"multiple"?: boolean;
7598+
"options"?: SelectModalOption[];
7599+
}
75807600
interface IonSelectOption {
75817601
/**
75827602
* If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
@@ -8163,6 +8183,7 @@ declare namespace LocalJSX {
81638183
"ion-segment": IonSegment;
81648184
"ion-segment-button": IonSegmentButton;
81658185
"ion-select": IonSelect;
8186+
"ion-select-modal": IonSelectModal;
81668187
"ion-select-option": IonSelectOption;
81678188
"ion-select-popover": IonSelectPopover;
81688189
"ion-skeleton-text": IonSkeletonText;
@@ -8262,6 +8283,7 @@ declare module "@stencil/core" {
82628283
"ion-segment": LocalJSX.IonSegment & JSXBase.HTMLAttributes<HTMLIonSegmentElement>;
82638284
"ion-segment-button": LocalJSX.IonSegmentButton & JSXBase.HTMLAttributes<HTMLIonSegmentButtonElement>;
82648285
"ion-select": LocalJSX.IonSelect & JSXBase.HTMLAttributes<HTMLIonSelectElement>;
8286+
"ion-select-modal": LocalJSX.IonSelectModal & JSXBase.HTMLAttributes<HTMLIonSelectModalElement>;
82658287
"ion-select-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes<HTMLIonSelectOptionElement>;
82668288
"ion-select-popover": LocalJSX.IonSelectPopover & JSXBase.HTMLAttributes<HTMLIonSelectPopoverElement>;
82678289
"ion-skeleton-text": LocalJSX.IonSkeletonText & JSXBase.HTMLAttributes<HTMLIonSkeletonTextElement>;

core/src/components/checkbox/checkbox.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ComponentInterface, EventEmitter } from '@stencil/core';
2-
import { Component, Element, Event, Host, Prop, h } from '@stencil/core';
2+
import { Component, Element, Event, Host, Method, Prop, h } from '@stencil/core';
33
import type { Attributes } from '@utils/helpers';
44
import { inheritAriaAttributes, renderHiddenInput } from '@utils/helpers';
55
import { createColorClasses, hostContext } from '@utils/theme';
@@ -121,7 +121,9 @@ export class Checkbox implements ComponentInterface {
121121
};
122122
}
123123

124-
private setFocus() {
124+
/** @internal */
125+
@Method()
126+
async setFocus() {
125127
if (this.focusEl) {
126128
this.focusEl.focus();
127129
}

core/src/components/radio-group/radio-group.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,9 @@ export class RadioGroup implements ComponentInterface {
155155

156156
@Listen('keydown', { target: 'document' })
157157
onKeydown(ev: KeyboardEvent) {
158-
const inSelectPopover = !!this.el.closest('ion-select-popover');
158+
// We don't want the value to automatically change/emit when the radio group is part of a select interface
159+
// as this will cause the interface to close when navigating through the radio group options
160+
const inSelectInterface = !!this.el.closest('ion-select-popover') || !!this.el.closest('ion-select-modal');
159161

160162
if (ev.target && !this.el.contains(ev.target as HTMLElement)) {
161163
return;
@@ -187,7 +189,7 @@ export class RadioGroup implements ComponentInterface {
187189
if (next && radios.includes(next)) {
188190
next.setFocus(ev);
189191

190-
if (!inSelectPopover) {
192+
if (!inSelectInterface) {
191193
this.value = next.value;
192194
this.emitValueChange(ev);
193195
}

core/src/components/radio/radio.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,11 @@ export class Radio implements ComponentInterface {
126126

127127
/** @internal */
128128
@Method()
129-
async setFocus(ev: globalThis.Event) {
130-
ev.stopPropagation();
131-
ev.preventDefault();
129+
async setFocus(ev?: globalThis.Event) {
130+
if (ev !== undefined) {
131+
ev.stopPropagation();
132+
ev.preventDefault();
133+
}
132134

133135
this.el.focus();
134136
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface SelectModalOption {
2+
text: string;
3+
value: string;
4+
disabled: boolean;
5+
checked: boolean;
6+
cssClass?: string | string[];
7+
handler?: (value: any) => boolean | void | { [key: string]: any };
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "./select-modal";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
@import "./select-modal";
2+
@import "../../themes/ionic.mixins.scss";
3+
@import "../item/item.md.vars";
4+
5+
ion-list ion-radio::part(container) {
6+
display: none;
7+
}
8+
9+
ion-list ion-radio::part(label) {
10+
@include margin(0);
11+
}
12+
13+
ion-item {
14+
--inner-border-width: 0;
15+
}
16+
17+
.item-radio-checked {
18+
--background: #{ion-color(primary, base, 0.08)};
19+
--background-focused: #{ion-color(primary, base)};
20+
--background-focused-opacity: 0.2;
21+
--background-hover: #{ion-color(primary, base)};
22+
--background-hover-opacity: 0.12;
23+
}
24+
25+
.item-checkbox-checked {
26+
--background-activated: #{$item-md-color};
27+
--background-focused: #{$item-md-color};
28+
--background-hover: #{$item-md-color};
29+
--color: #{ion-color(primary, base)};
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:host {
2+
height: 100%;
3+
}

0 commit comments

Comments
 (0)