Skip to content

feat(segment-view): adds support for new ion-segment-view component #29969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 47 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
bc2fb37
fix(segment): animate the highlight with value changes
brandyscarney Sep 17, 2024
6833092
feat(segment): add segment view and content components
brandyscarney Sep 17, 2024
bf3a503
style: lint
brandyscarney Sep 17, 2024
2ddfab7
refactor(segment): link the button and content with content-id and id
brandyscarney Sep 18, 2024
4e48562
refactor(segment): remove uneccessary function
brandyscarney Sep 18, 2024
4e9c3ec
feat(segment-view): support disabled
brandyscarney Sep 19, 2024
e5323bd
fix(segment): only call updateSegmentView when gesture ends or button…
brandyscarney Sep 23, 2024
97c486b
fix(segment): set the view to the initial value without scrolling
brandyscarney Sep 23, 2024
d46b3bf
test(segment-view): add a test for the proper content being displayed
brandyscarney Sep 23, 2024
370a57a
style: lint
brandyscarney Sep 23, 2024
d60d54b
docs(segment-view): document setContent method and add example
brandyscarney Sep 23, 2024
4bb4a8c
test(segment-view): fix test
brandyscarney Sep 23, 2024
8b4fa83
test(segment-view): update function for clearing segment value
brandyscarney Sep 23, 2024
4b27738
feat(segment-content): add disabled prop and hide the content
brandyscarney Sep 23, 2024
0ecf886
test(segment-view): split out disabled segment view / content test
brandyscarney Sep 23, 2024
a76477c
fix(segment-view): split opacity by mode vars to match segment
brandyscarney Sep 23, 2024
6da1cdd
fix(segment-view): don't query for disabled contents
brandyscarney Sep 23, 2024
8e17797
test(segment-view): remove toolbars
brandyscarney Sep 24, 2024
1c3f7ab
test(segment-view): add tests for disabled content scrolling
brandyscarney Sep 24, 2024
e68f55f
chore(): add updated snapshots
brandyscarney Sep 24, 2024
6aa694b
test: remove only
brandyscarney Sep 24, 2024
6d24224
feat(segment): move indicator with scroll
brandyscarney Sep 24, 2024
3d53f71
fix(segment): properly move the indicator when direction starts out o…
brandyscarney Sep 24, 2024
10acd9e
style: lint
brandyscarney Sep 24, 2024
7b83b45
fix(segment-view): allow moving the indicator left on scroll without …
brandyscarney Sep 25, 2024
510ae39
fix(segment-view): always check the scrollLeft against the initial to…
brandyscarney Sep 25, 2024
c8b765a
fix(segment): properly bound indicator transform for more than 2 cont…
brandyscarney Sep 25, 2024
3e66a38
fix(segment): move indicator as a percentage of the width on scroll
brandyscarney Sep 25, 2024
b751f04
fix(segment): clear transform styles on scroll end
Sep 27, 2024
f81a613
fix(segment): handle change of direction scrolling
Sep 27, 2024
0a7f4ba
fix(segment): don't trigger scroll listener on segment button click
Sep 29, 2024
6635c84
fix(segment): only handle events for correct instance
Sep 29, 2024
43845c2
fix(segment): scroll segment button into view if appropriate
Sep 29, 2024
1fbddf8
chore: build
brandyscarney Sep 30, 2024
2069f7e
style: naming
brandyscarney Sep 30, 2024
a91a5a4
refactor(segment-content): use opacity for disabled content
brandyscarney Oct 1, 2024
35337ed
test(segment-view): remove not disabled styles
brandyscarney Oct 2, 2024
b58f9a7
fix(segment): update segment view to scroll past disabled content
brandyscarney Oct 8, 2024
a9adb82
fix(segment): update segment content to disabled when button is
brandyscarney Oct 9, 2024
9494d43
fix(segment-view): continue to search through segment contents for en…
brandyscarney Oct 10, 2024
f74f154
feat(segment, segment-view): remove percentage based indicator effect…
tanner-reits Oct 25, 2024
ef5bdc7
fix: PR feedback
Oct 29, 2024
2e484c0
fix(): more PR feedback
Oct 30, 2024
f5e910a
fix: regenerate api & proxies
Oct 30, 2024
ab5d4e5
refactor(segment-content): remove mode specific files
brandyscarney Oct 30, 2024
8429322
fix(segment-button): revert disabled reflection
Oct 31, 2024
f6376e8
Merge remote-tracking branch 'origin/feature-8.4' into ROU-10971
Oct 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,7 @@ ion-segment,css-prop,--background,ios
ion-segment,css-prop,--background,md

ion-segment-button,shadow
ion-segment-button,prop,contentId,string | undefined,undefined,false,true
ion-segment-button,prop,disabled,boolean,false,false,false
ion-segment-button,prop,layout,"icon-bottom" | "icon-end" | "icon-hide" | "icon-start" | "icon-top" | "label-hide" | undefined,'icon-top',false,false
ion-segment-button,prop,mode,"ios" | "md",undefined,false,false
Expand Down Expand Up @@ -1607,6 +1608,12 @@ ion-segment-button,part,indicator
ion-segment-button,part,indicator-background
ion-segment-button,part,native

ion-segment-content,shadow

ion-segment-view,shadow
ion-segment-view,prop,disabled,boolean,false,false,false
ion-segment-view,event,ionSegmentViewScroll,SegmentViewScrollEvent,true

ion-select,shadow
ion-select,prop,cancelText,string,'Cancel',false,false
ion-select,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
Expand Down
68 changes: 68 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { NavigationHookCallback } from "./components/route/route-interface";
import { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
import { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
import { SegmentButtonLayout } from "./components/segment-button/segment-button-interface";
import { SegmentViewScrollEvent } from "./components/segment-view/segment-view-interface";
import { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
import { SelectModalOption } from "./components/select-modal/select-modal-interface";
import { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
Expand Down Expand Up @@ -70,6 +71,7 @@ export { NavigationHookCallback } from "./components/route/route-interface";
export { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
export { SegmentChangeEventDetail, SegmentValue } from "./components/segment/segment-interface";
export { SegmentButtonLayout } from "./components/segment-button/segment-button-interface";
export { SegmentViewScrollEvent } from "./components/segment-view/segment-view-interface";
export { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
export { SelectModalOption } from "./components/select-modal/select-modal-interface";
export { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
Expand Down Expand Up @@ -2696,6 +2698,10 @@ export namespace Components {
"value"?: SegmentValue;
}
interface IonSegmentButton {
/**
* The `id` of the segment content.
*/
"contentId"?: string;
/**
* If `true`, the user cannot interact with the segment button.
*/
Expand All @@ -2718,6 +2724,19 @@ export namespace Components {
*/
"value": SegmentValue;
}
interface IonSegmentContent {
}
interface IonSegmentView {
/**
* If `true`, the segment view cannot be interacted with.
*/
"disabled": boolean;
/**
* @param id : The id of the segment content to display.
* @param smoothScroll : Whether to animate the scroll transition.
*/
"setContent": (id: string, smoothScroll?: boolean) => Promise<void>;
}
interface IonSelect {
/**
* The text to display on the cancel button.
Expand Down Expand Up @@ -3424,6 +3443,10 @@ export interface IonSegmentCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIonSegmentElement;
}
export interface IonSegmentViewCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIonSegmentViewElement;
}
export interface IonSelectCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLIonSelectElement;
Expand Down Expand Up @@ -4420,6 +4443,29 @@ declare global {
prototype: HTMLIonSegmentButtonElement;
new (): HTMLIonSegmentButtonElement;
};
interface HTMLIonSegmentContentElement extends Components.IonSegmentContent, HTMLStencilElement {
}
var HTMLIonSegmentContentElement: {
prototype: HTMLIonSegmentContentElement;
new (): HTMLIonSegmentContentElement;
};
interface HTMLIonSegmentViewElementEventMap {
"ionSegmentViewScroll": SegmentViewScrollEvent;
}
interface HTMLIonSegmentViewElement extends Components.IonSegmentView, HTMLStencilElement {
addEventListener<K extends keyof HTMLIonSegmentViewElementEventMap>(type: K, listener: (this: HTMLIonSegmentViewElement, ev: IonSegmentViewCustomEvent<HTMLIonSegmentViewElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLIonSegmentViewElementEventMap>(type: K, listener: (this: HTMLIonSegmentViewElement, ev: IonSegmentViewCustomEvent<HTMLIonSegmentViewElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLIonSegmentViewElement: {
prototype: HTMLIonSegmentViewElement;
new (): HTMLIonSegmentViewElement;
};
interface HTMLIonSelectElementEventMap {
"ionChange": SelectChangeEventDetail;
"ionCancel": void;
Expand Down Expand Up @@ -4735,6 +4781,8 @@ declare global {
"ion-searchbar": HTMLIonSearchbarElement;
"ion-segment": HTMLIonSegmentElement;
"ion-segment-button": HTMLIonSegmentButtonElement;
"ion-segment-content": HTMLIonSegmentContentElement;
"ion-segment-view": HTMLIonSegmentViewElement;
"ion-select": HTMLIonSelectElement;
"ion-select-modal": HTMLIonSelectModalElement;
"ion-select-option": HTMLIonSelectOptionElement;
Expand Down Expand Up @@ -7465,6 +7513,10 @@ declare namespace LocalJSX {
"value"?: SegmentValue;
}
interface IonSegmentButton {
/**
* The `id` of the segment content.
*/
"contentId"?: string;
/**
* If `true`, the user cannot interact with the segment button.
*/
Expand All @@ -7486,6 +7538,18 @@ declare namespace LocalJSX {
*/
"value"?: SegmentValue;
}
interface IonSegmentContent {
}
interface IonSegmentView {
/**
* If `true`, the segment view cannot be interacted with.
*/
"disabled"?: boolean;
/**
* Emitted when the segment view is scrolled.
*/
"onIonSegmentViewScroll"?: (event: IonSegmentViewCustomEvent<SegmentViewScrollEvent>) => void;
}
interface IonSelect {
/**
* The text to display on the cancel button.
Expand Down Expand Up @@ -8182,6 +8246,8 @@ declare namespace LocalJSX {
"ion-searchbar": IonSearchbar;
"ion-segment": IonSegment;
"ion-segment-button": IonSegmentButton;
"ion-segment-content": IonSegmentContent;
"ion-segment-view": IonSegmentView;
"ion-select": IonSelect;
"ion-select-modal": IonSelectModal;
"ion-select-option": IonSelectOption;
Expand Down Expand Up @@ -8282,6 +8348,8 @@ declare module "@stencil/core" {
"ion-searchbar": LocalJSX.IonSearchbar & JSXBase.HTMLAttributes<HTMLIonSearchbarElement>;
"ion-segment": LocalJSX.IonSegment & JSXBase.HTMLAttributes<HTMLIonSegmentElement>;
"ion-segment-button": LocalJSX.IonSegmentButton & JSXBase.HTMLAttributes<HTMLIonSegmentButtonElement>;
"ion-segment-content": LocalJSX.IonSegmentContent & JSXBase.HTMLAttributes<HTMLIonSegmentContentElement>;
"ion-segment-view": LocalJSX.IonSegmentView & JSXBase.HTMLAttributes<HTMLIonSegmentViewElement>;
"ion-select": LocalJSX.IonSelect & JSXBase.HTMLAttributes<HTMLIonSelectElement>;
"ion-select-modal": LocalJSX.IonSelectModal & JSXBase.HTMLAttributes<HTMLIonSelectModalElement>;
"ion-select-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes<HTMLIonSelectOptionElement>;
Expand Down
37 changes: 30 additions & 7 deletions core/src/components/segment-button/segment-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export class SegmentButton implements ComponentInterface, ButtonInterface {

@State() checked = false;

/**
* The `id` of the segment content.
*/
@Prop({ reflect: true }) contentId?: string;

/**
* If `true`, the user cannot interact with the segment button.
*/
Expand Down Expand Up @@ -67,6 +72,30 @@ export class SegmentButton implements ComponentInterface, ButtonInterface {
addEventListener(segmentEl, 'ionSelect', this.updateState);
addEventListener(segmentEl, 'ionStyle', this.updateStyle);
}

// Return if there is no contentId defined
if (!this.contentId) return;

// Attempt to find the Segment Content by its contentId
const segmentContent = document.getElementById(this.contentId) as HTMLIonSegmentContentElement | null;

// If no associated Segment Content exists, log an error and return
if (!segmentContent) {
console.error(`Segment Button: Unable to find Segment Content with id="${this.contentId}".`);
return;
}

// Ensure the found element is a valid ION-SEGMENT-CONTENT
if (segmentContent.tagName !== 'ION-SEGMENT-CONTENT') {
console.error(`Segment Button: Element with id="${this.contentId}" is not an <ion-segment-content> element.`);
return;
}

// Prevent buttons from being disabled when associated with segment content
if (this.disabled) {
console.warn(`Segment Button: Segment buttons cannot be disabled when associated with an <ion-segment-content>.`);
this.disabled = false;
}
}

disconnectedCallback() {
Expand Down Expand Up @@ -161,13 +190,7 @@ export class SegmentButton implements ComponentInterface, ButtonInterface {
</span>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
</button>
<div
part="indicator"
class={{
'segment-button-indicator': true,
'segment-button-indicator-animated': true,
}}
>
<div part="indicator" class="segment-button-indicator segment-button-indicator-animated">
<div part="indicator-background" class="segment-button-indicator-background"></div>
</div>
</Host>
Expand Down
11 changes: 11 additions & 0 deletions core/src/components/segment-content/segment-content.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Segment Content
// --------------------------------------------------

:host {
scroll-snap-align: center;
scroll-snap-stop: always;

flex-shrink: 0;

width: 100%;
}
17 changes: 17 additions & 0 deletions core/src/components/segment-content/segment-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, h } from '@stencil/core';

@Component({
tag: 'ion-segment-content',
styleUrl: 'segment-content.scss',
shadow: true,
})
export class SegmentContent implements ComponentInterface {
render() {
return (
<Host>
<slot></slot>
</Host>
);
}
}
4 changes: 4 additions & 0 deletions core/src/components/segment-view/segment-view-interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface SegmentViewScrollEvent {
scrollRatio: number;
isManualScroll: boolean;
}
9 changes: 9 additions & 0 deletions core/src/components/segment-view/segment-view.ios.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "./segment-view";
@import "../segment-button/segment-button.ios.vars";

// iOS Segment View
// --------------------------------------------------

:host(.segment-view-disabled) {
opacity: $segment-button-ios-opacity-disabled;
}
9 changes: 9 additions & 0 deletions core/src/components/segment-view/segment-view.md.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "./segment-view";
@import "../segment-button/segment-button.md.vars";

// Material Design Segment View
// --------------------------------------------------

:host(.segment-view-disabled) {
opacity: $segment-button-md-opacity-disabled;
}
31 changes: 31 additions & 0 deletions core/src/components/segment-view/segment-view.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Segment View
// --------------------------------------------------

:host {
display: flex;

height: 100%;

overflow-x: scroll;
scroll-snap-type: x mandatory;

/* Hide scrollbar in Firefox */
scrollbar-width: none;

/* Hide scrollbar in IE and Edge */
-ms-overflow-style: none;
}

/* Hide scrollbar in webkit */
:host::-webkit-scrollbar {
display: none;
}

:host(.segment-view-disabled) {
touch-action: none;
overflow-x: hidden;
}

:host(.segment-view-scroll-disabled) {
pointer-events: none;
}
Loading
Loading