Skip to content
Closed
Show file tree
Hide file tree
Changes from 11 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
7 changes: 7 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,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,method,setContent,setContent(id: string, smoothScroll?: boolean) => Promise<void>

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
48 changes: 48 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,20 @@ export namespace Components {
*/
"value": SegmentValue;
}
interface IonSegmentContent {
}
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 @@ -4409,6 +4427,18 @@ declare global {
prototype: HTMLIonSegmentButtonElement;
new (): HTMLIonSegmentButtonElement;
};
interface HTMLIonSegmentContentElement extends Components.IonSegmentContent, HTMLStencilElement {
}
var HTMLIonSegmentContentElement: {
prototype: HTMLIonSegmentContentElement;
new (): HTMLIonSegmentContentElement;
};
interface HTMLIonSegmentViewElement extends Components.IonSegmentView, HTMLStencilElement {
}
var HTMLIonSegmentViewElement: {
prototype: HTMLIonSegmentViewElement;
new (): HTMLIonSegmentViewElement;
};
interface HTMLIonSelectElementEventMap {
"ionChange": SelectChangeEventDetail;
"ionCancel": void;
Expand Down Expand Up @@ -4718,6 +4748,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 +7479,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 +7504,14 @@ declare namespace LocalJSX {
*/
"value"?: SegmentValue;
}
interface IonSegmentContent {
}
interface IonSegmentView {
/**
* If `true`, the segment view cannot be interacted with.
*/
"disabled"?: boolean;
}
interface IonSelect {
/**
* The text to display on the cancel button.
Expand Down Expand Up @@ -8159,6 +8203,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 +8304,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
5 changes: 5 additions & 0 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
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%;
}
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>
);
}
}
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) {
scroll-snap-type: none;

opacity: 0.7;

touch-action: none;
overflow-x: hidden;
}
86 changes: 86 additions & 0 deletions core/src/components/segment-view/segment-view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Listen, Method, Prop, h } from '@stencil/core';

@Component({
tag: 'ion-segment-view',
styleUrl: 'segment-view.scss',
shadow: true,
})
export class SegmentView implements ComponentInterface {
@Element() el!: HTMLElement;

/**
* If `true`, the segment view cannot be interacted with.
*/
@Prop() disabled = false;

@Listen('scroll')
handleScroll(ev: any) {
const { scrollLeft, offsetWidth } = ev.target;
const atSnappingPoint = scrollLeft % offsetWidth === 0;

if (!atSnappingPoint) return;

const index = Math.round(scrollLeft / offsetWidth);
const segmentContent = this.getSegmentContents()[index];

if (segmentContent === null || segmentContent === undefined) {
return;
}

const segmentButton = this.getSegmentButtonById(segmentContent.id) as HTMLIonSegmentButtonElement;
const segment = this.getParentSegment(segmentButton);

if (segment) {
segment.value = segmentButton.value;
}
}

/**
* 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.
*/
@Method()
async setContent(id: string, smoothScroll = true) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be an internal method if we want, but I added an example using it because it seems useful to expose it.

const contents = this.getSegmentContents();
const index = contents.findIndex((content) => content.id === id);

if (index === -1) return;

const contentWidth = this.el.offsetWidth;
this.el.scrollTo({
top: 0,
left: index * contentWidth,
behavior: smoothScroll ? 'smooth' : 'auto',
});
}

private getSegmentContents(): HTMLIonSegmentContentElement[] {
return Array.from(this.el.querySelectorAll('ion-segment-content'));
}

private getSegmentButtonById(id: string) {
return document.querySelector(`ion-segment-button[content-id="${id}"]`);
}

private getParentSegment(button: Element) {
return button.closest('ion-segment');
}

render() {
const { disabled } = this;

return (
<Host
class={{
'segment-view-disabled': disabled,
}}
>
<slot></slot>
</Host>
);
}
}
Loading
Loading