Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fa74077
fix(segment): animate the highlight with value changes
brandyscarney Sep 17, 2024
0324a78
feat(segment): add segment view and content components
brandyscarney Sep 17, 2024
8af4d74
style: lint
brandyscarney Sep 17, 2024
00c378f
refactor(segment): link the button and content with content-id and id
brandyscarney Sep 18, 2024
44a0855
refactor(segment): remove uneccessary function
brandyscarney Sep 18, 2024
678990d
feat(segment-view): support disabled
brandyscarney Sep 19, 2024
44e8374
fix(segment): only call updateSegmentView when gesture ends or button…
brandyscarney Sep 23, 2024
ba28530
fix(segment): set the view to the initial value without scrolling
brandyscarney Sep 23, 2024
686d943
test(segment-view): add a test for the proper content being displayed
brandyscarney Sep 23, 2024
e6f76d5
style: lint
brandyscarney Sep 23, 2024
9103c40
docs(segment-view): document setContent method and add example
brandyscarney Sep 23, 2024
4c0407e
test(segment-view): fix test
brandyscarney Sep 23, 2024
d8f27d8
test(segment-view): update function for clearing segment value
brandyscarney Sep 23, 2024
faa7065
feat(segment-content): add disabled prop and hide the content
brandyscarney Sep 23, 2024
5401e8d
test(segment-view): split out disabled segment view / content test
brandyscarney Sep 23, 2024
f07a5b1
fix(segment-view): split opacity by mode vars to match segment
brandyscarney Sep 23, 2024
b75650b
fix(segment-view): don't query for disabled contents
brandyscarney Sep 23, 2024
094d9a8
test(segment-view): remove toolbars
brandyscarney Sep 24, 2024
522cbc6
test(segment-view): add tests for disabled content scrolling
brandyscarney Sep 24, 2024
15b8b8f
chore(): add updated snapshots
brandyscarney Sep 24, 2024
798e725
test: remove only
brandyscarney Sep 24, 2024
d811221
feat(segment): move indicator with scroll
brandyscarney Sep 24, 2024
699ce97
fix(segment): properly move the indicator when direction starts out o…
brandyscarney Sep 24, 2024
1d645c9
style: lint
brandyscarney Sep 24, 2024
c7bae07
fix(segment-view): allow moving the indicator left on scroll without …
brandyscarney Sep 25, 2024
7fe1c09
fix(segment-view): always check the scrollLeft against the initial to…
brandyscarney Sep 25, 2024
bdc6933
fix(segment): properly bound indicator transform for more than 2 cont…
brandyscarney Sep 25, 2024
cbee05e
fix(segment): move indicator as a percentage of the width on scroll
brandyscarney Sep 25, 2024
0a13ab4
fix(segment): clear transform styles on scroll end
Sep 27, 2024
0fa5c99
fix(segment): handle change of direction scrolling
Sep 27, 2024
16c728b
fix(segment): don't trigger scroll listener on segment button click
Sep 29, 2024
ae2704f
fix(segment): only handle events for correct instance
Sep 29, 2024
89d8e90
fix(segment): scroll segment button into view if appropriate
Sep 29, 2024
c6ec156
chore: build
brandyscarney Sep 30, 2024
e654743
style: naming
brandyscarney Sep 30, 2024
641dc0b
refactor(segment-content): use opacity for disabled content
brandyscarney Oct 1, 2024
59e306b
test(segment-view): remove not disabled styles
brandyscarney Oct 2, 2024
279300f
fix(segment): update segment view to scroll past disabled content
brandyscarney Oct 8, 2024
b94bec2
fix(segment): update segment content to disabled when button is
brandyscarney Oct 9, 2024
475de8b
fix(segment-view): continue to search through segment contents for en…
brandyscarney Oct 10, 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
11 changes: 11 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,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 @@ -1606,6 +1607,16 @@ ion-segment-button,part,indicator
ion-segment-button,part,indicator-background
ion-segment-button,part,native

ion-segment-content,shadow
ion-segment-content,prop,disabled,boolean,false,false,false

ion-segment-view,shadow
ion-segment-view,prop,disabled,boolean,false,false,false
ion-segment-view,method,setContent,setContent(id: string, smoothScroll?: boolean) => Promise<void>
ion-segment-view,event,ionSegmentViewScroll,{ scrollDirection: string; scrollDistance: number; scrollDistancePercentage: number; },true
ion-segment-view,event,ionSegmentViewScrollEnd,{ activeContentId: string; },true
ion-segment-view,event,ionSegmentViewScrollStart,void,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
90 changes: 90 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2690,6 +2690,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 @@ -2712,6 +2716,24 @@ export namespace Components {
*/
"value": SegmentValue;
}
interface IonSegmentContent {
/**
* If `true`, the segment content will not be displayed.
*/
"disabled": boolean;
}
interface IonSegmentView {
/**
* If `true`, the segment view cannot be interacted with.
*/
"disabled": boolean;
/**
* This method is used to programmatically set the displayed segment content in the segment view. Calling this method will update the `value` of the corresponding segment button.
* @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 @@ -3413,6 +3435,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 @@ -4409,6 +4435,35 @@ declare global {
prototype: HTMLIonSegmentButtonElement;
new (): HTMLIonSegmentButtonElement;
};
interface HTMLIonSegmentContentElement extends Components.IonSegmentContent, HTMLStencilElement {
}
var HTMLIonSegmentContentElement: {
prototype: HTMLIonSegmentContentElement;
new (): HTMLIonSegmentContentElement;
};
interface HTMLIonSegmentViewElementEventMap {
"ionSegmentViewScroll": {
scrollDirection: string;
scrollDistance: number;
scrollDistancePercentage: number;
};
"ionSegmentViewScrollEnd": { activeContentId: string };
"ionSegmentViewScrollStart": void;
}
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 @@ -4718,6 +4773,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-option": HTMLIonSelectOptionElement;
"ion-select-popover": HTMLIonSelectPopoverElement;
Expand Down Expand Up @@ -7447,6 +7504,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 @@ -7468,6 +7529,31 @@ declare namespace LocalJSX {
*/
"value"?: SegmentValue;
}
interface IonSegmentContent {
/**
* If `true`, the segment content will not be displayed.
*/
"disabled"?: boolean;
}
interface IonSegmentView {
/**
* If `true`, the segment view cannot be interacted with.
*/
"disabled"?: boolean;
/**
* Emitted when the segment view is scrolled.
*/
"onIonSegmentViewScroll"?: (event: IonSegmentViewCustomEvent<{
scrollDirection: string;
scrollDistance: number;
scrollDistancePercentage: number;
}>) => void;
/**
* Emitted when the segment view scroll has ended.
*/
"onIonSegmentViewScrollEnd"?: (event: IonSegmentViewCustomEvent<{ activeContentId: string }>) => void;
"onIonSegmentViewScrollStart"?: (event: IonSegmentViewCustomEvent<void>) => void;
}
interface IonSelect {
/**
* The text to display on the cancel button.
Expand Down Expand Up @@ -8159,6 +8245,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-option": IonSelectOption;
"ion-select-popover": IonSelectPopover;
Expand Down Expand Up @@ -8258,6 +8346,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-option": LocalJSX.IonSelectOption & JSXBase.HTMLAttributes<HTMLIonSelectOptionElement>;
"ion-select-popover": LocalJSX.IonSelectPopover & JSXBase.HTMLAttributes<HTMLIonSelectPopoverElement>;
Expand Down
34 changes: 27 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,27 @@ 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;
}

// Set the disabled state of the Segment Content based on the button's disabled state
segmentContent.disabled = this.disabled;
}

disconnectedCallback() {
Expand Down Expand Up @@ -161,13 +187,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
9 changes: 9 additions & 0 deletions core/src/components/segment-content/segment-content.ios.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "./segment-content";
@import "../segment-button/segment-button.ios.vars";

// iOS Segment Content
// --------------------------------------------------

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

// Material Design Segment Content
// --------------------------------------------------

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

:host {
scroll-snap-align: center;

flex-shrink: 0;

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

@Component({
tag: 'ion-segment-content',
styleUrls: {
ios: 'segment-content.ios.scss',
md: 'segment-content.md.scss',
},
shadow: true,
})
export class SegmentContent implements ComponentInterface {
/**
* If `true`, the segment content will not be displayed.
*/
@Prop() disabled = false;

render() {
const { disabled } = this;

return (
<Host
class={{
'segment-content-disabled': disabled,
}}
>
<slot></slot>
</Host>
);
}
}
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;
}
27 changes: 27 additions & 0 deletions core/src/components/segment-view/segment-view.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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;
}
Loading
Loading