diff --git a/angular/BREAKING.md b/angular/BREAKING.md index 232d321f4be..0ba9570c18c 100644 --- a/angular/BREAKING.md +++ b/angular/BREAKING.md @@ -47,7 +47,7 @@ A list of the breaking changes introduced to each component in Ionic Angular v4. - [Range](#range) - [Refresher](#refresher) - [Scroll](#scroll) -- [Segment](#segment) +- [Segment Button](#segment-button) - [Select](#select) - [Spinner](#spinner) - [Tabs](#tabs) @@ -1170,9 +1170,25 @@ div.scrollable { ``` -## Segment +## Segment Button -The markup hasn't changed for Segments, but now writing `` will render a native button element inside of it. +Segment Button text is now required to be wrapped in an `ion-label`. + +*Old usage:* + +```html + + Item One + +``` + +*New usage:* + +```html + + Item One + +``` ## Select diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index b72be7432b8..010759cc5a4 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -685,27 +685,28 @@ export class Searchbar { } export declare interface Segment extends StencilComponents<'IonSegment'> {} -@Component({ selector: 'ion-segment', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '', inputs: ['color', 'mode', 'disabled', 'value'] }) +@Component({ selector: 'ion-segment', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '', inputs: ['color', 'mode', 'disabled', 'scrollable', 'value'] }) export class Segment { ionChange: EventEmitter; + ionStyle: EventEmitter; constructor(c: ChangeDetectorRef, r: ElementRef) { c.detach(); const el = r.nativeElement; - proxyInputs(this, el, ['color', 'mode', 'disabled', 'value']); - proxyOutputs(this, el, ['ionChange']); + proxyInputs(this, el, ['color', 'mode', 'disabled', 'scrollable', 'value']); + proxyOutputs(this, el, ['ionChange', 'ionStyle']); } } export declare interface SegmentButton extends StencilComponents<'IonSegmentButton'> {} -@Component({ selector: 'ion-segment-button', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '', inputs: ['color', 'mode', 'checked', 'disabled', 'value'] }) +@Component({ selector: 'ion-segment-button', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '', inputs: ['color', 'mode', 'checked', 'disabled', 'layout', 'value'] }) export class SegmentButton { ionSelect: EventEmitter; constructor(c: ChangeDetectorRef, r: ElementRef) { c.detach(); const el = r.nativeElement; - proxyInputs(this, el, ['color', 'mode', 'checked', 'disabled', 'value']); + proxyInputs(this, el, ['color', 'mode', 'checked', 'disabled', 'layout', 'value']); proxyOutputs(this, el, ['ionSelect']); } } diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 999ef1a8983..4ccf73646f8 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -50,6 +50,7 @@ import { RouteWrite, ScrollBaseDetail, ScrollDetail, + SegmentButtonLayout, SelectInputChangeEvent, SelectInterface, SelectPopoverOption, @@ -3845,6 +3846,10 @@ export namespace Components { */ 'disabled': boolean; /** + * Set the layout of the text and icon in the segment. + */ + 'layout': SegmentButtonLayout; + /** * The mode determines which platform styles to use. */ 'mode': Mode; @@ -3867,6 +3872,10 @@ export namespace Components { */ 'disabled'?: boolean; /** + * Set the layout of the text and icon in the segment. + */ + 'layout': SegmentButtonLayout; + /** * The mode determines which platform styles to use. */ 'mode'?: Mode; @@ -3894,6 +3903,10 @@ export namespace Components { */ 'mode': Mode; /** + * If `true`, the segment buttons will overflow and the user can swipe to see them. + */ + 'scrollable': boolean; + /** * the value of the segment. */ 'value'?: string | null; @@ -3916,6 +3929,14 @@ export namespace Components { */ 'onIonChange'?: (event: CustomEvent) => void; /** + * Emitted when the styles change. + */ + 'onIonStyle'?: (event: CustomEvent) => void; + /** + * If `true`, the segment buttons will overflow and the user can swipe to see them. + */ + 'scrollable'?: boolean; + /** * the value of the segment. */ 'value'?: string | null; diff --git a/core/src/components/segment-button/readme.md b/core/src/components/segment-button/readme.md index c1a485fd457..a76bbea7e60 100644 --- a/core/src/components/segment-button/readme.md +++ b/core/src/components/segment-button/readme.md @@ -8,13 +8,14 @@ Segment buttons are groups of related buttons inside of a [Segment](../../segmen ## Properties -| Property | Attribute | Description | Type | Default | -| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------- | -| `checked` | `checked` | If `true`, the segment button is selected. | `boolean` | `false` | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `disabled` | `disabled` | If `true`, the user cannot interact with the segment button. | `boolean` | `false` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | -| `value` | `value` | The value of the segment button. | `string` | `'ion-sb-' + (ids++)` | +| Property | Attribute | Description | Type | Default | +| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------- | +| `checked` | `checked` | If `true`, the segment button is selected. | `boolean` | `false` | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the segment button. | `boolean` | `false` | +| `layout` | `layout` | Set the layout of the text and icon in the segment. | `"icon-bottom" \| "icon-end" \| "icon-hide" \| "icon-start" \| "icon-top" \| "label-hide"` | `undefined` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `value` | `value` | The value of the segment button. | `string` | `'ion-sb-' + (ids++)` | ## Events @@ -26,23 +27,32 @@ Segment buttons are groups of related buttons inside of a [Segment](../../segmen ## CSS Custom Properties -| Name | Description | -| -------------------- | ---------------------------- | -| `--border-radius` | Radius of the button border | -| `--border-style` | Style of the button border | -| `--border-width` | Width of the button border | -| `--btn-background` | Background of the button | -| `--btn-border-color` | Color of the button border | -| `--icon-size` | Size of the button icon | -| `--margin-bottom` | Bottom margin of the button | -| `--margin-end` | End margin of the button | -| `--margin-start` | Start margin of the button | -| `--margin-top` | Top margin of the button | -| `--padding-bottom` | Bottom padding of the button | -| `--padding-end` | End padding of the button | -| `--padding-start` | Start padding of the button | -| `--padding-top` | Top padding of the button | -| `--transition` | Transition of the button | +| Name | Description | +| --------------------------- | ------------------------------------------------------------------- | +| `--background` | Background of the segment button | +| `--background-activated` | Background of the activated (pressed) segment button | +| `--background-checked` | Background of the checked segment button | +| `--background-hover` | Background of the segment button on hover | +| `--border-color` | Color of the segment button border | +| `--border-radius` | Radius of the segment button border | +| `--border-style` | Style of the segment button border | +| `--border-width` | Width of the segment button border | +| `--color` | Color of the segment button | +| `--color-activated` | Color of the activated (pressed) segment button | +| `--color-checked` | Color of the checked segment button | +| `--color-checked-disabled` | Color of the checked & disabled segment button | +| `--color-disabled` | Color of the disabled segment button | +| `--indicator-color` | Color of the indicator (highlight) under the segment button | +| `--indicator-color-checked` | Color of the indicator (highlight) under the checked segment button | +| `--margin-bottom` | Bottom margin of the segment button | +| `--margin-end` | End margin of the segment button | +| `--margin-start` | Start margin of the segment button | +| `--margin-top` | Top margin of the segment button | +| `--padding-bottom` | Bottom padding of the segment button | +| `--padding-end` | End padding of the segment button | +| `--padding-start` | Start padding of the segment button | +| `--padding-top` | Top padding of the segment button | +| `--transition` | Transition of the segment button | ---------------------------------------------- diff --git a/core/src/components/segment-button/segment-button-interface.ts b/core/src/components/segment-button/segment-button-interface.ts new file mode 100644 index 00000000000..9ceeb14e41f --- /dev/null +++ b/core/src/components/segment-button/segment-button-interface.ts @@ -0,0 +1 @@ +export type SegmentButtonLayout = 'icon-top' | 'icon-start' | 'icon-end' | 'icon-bottom' | 'icon-hide' | 'label-hide'; diff --git a/core/src/components/segment-button/segment-button.ios.scss b/core/src/components/segment-button/segment-button.ios.scss new file mode 100644 index 00000000000..a54c7332f22 --- /dev/null +++ b/core/src/components/segment-button/segment-button.ios.scss @@ -0,0 +1,85 @@ +@import "./segment-button"; +@import "./segment-button.ios.vars"; + +// iOS Segment Button +// -------------------------------------------------- + +:host { + --background: #{$segment-button-ios-background-color}; + --background-hover: #{$segment-button-ios-background-color-hover}; + --background-activated: #{$segment-button-ios-background-color-activated}; + --background-checked: #{$segment-button-ios-background-color-checked}; + --border-color: #{$segment-button-ios-border-color}; + --color: #{$segment-button-ios-text-color}; + --color-activated: var(--color); + --color-checked: #{ion-color(primary, contrast)}; + --color-disabled: #{ion-color(primary, base, $segment-button-ios-opacity-disabled)}; + --color-checked-disabled: #{ion-color(primary, contrast, $segment-button-ios-opacity-disabled)}; + --border-radius: #{$segment-button-ios-border-radius}; + --border-width: #{$segment-button-ios-border-width}; + --border-style: solid; + --transition: #{$segment-button-ios-transition}; + + min-height: #{$segment-button-ios-height}; + + font-size: #{$segment-button-ios-font-size}; + + line-height: #{$segment-button-ios-line-height}; +} + + +// Segment Button: Indicator +// -------------------------------------------------- + +.segment-button-indicator { + display: none; +} + + +// Segment Button: Icon +// -------------------------------------------------- + +::slotted(ion-icon) { + font-size: $segment-button-ios-icon-size; +} + + +// Segment Button: Layout +// -------------------------------------------------- + +// Layout: icon start +:host(.segment-button-layout-icon-start) ::slotted(ion-label) { + @include margin-horizontal(2px, 0); +} + +// Layout: icon end +:host(.segment-button-layout-icon-end) ::slotted(ion-label) { + @include margin-horizontal(0, 2px); +} + + +// Segment Button: Hover +// -------------------------------------------------- + +@media (any-hover: hover) { + :host(:hover:not(.segment-button-checked)) { + background: var(--background-hover); + } +} + + +// Segment Button: Activated +// -------------------------------------------------- + +:host(.activated) { + background: var(--background-activated); +} + + +// Segment: Checked & Activated +// -------------------------------------------------- + +:host(.segment-button-checked.activated) { + background: var(--background-checked); + color: var(--color-checked); +} diff --git a/core/src/components/segment-button/segment-button.ios.vars.scss b/core/src/components/segment-button/segment-button.ios.vars.scss new file mode 100644 index 00000000000..d9ea8d7e7ea --- /dev/null +++ b/core/src/components/segment-button/segment-button.ios.vars.scss @@ -0,0 +1,73 @@ +@import "../../themes/ionic.globals.ios"; + +// iOS Segment Button +// -------------------------------------------------- + +/// @prop - Background of the segment button +$segment-button-ios-background-color: transparent !default; + +/// @prop - Background of the checked segment button +$segment-button-ios-background-color-checked: ion-color(primary, base) !default; + +/// @prop - Opacity of the segment button on hover +$segment-button-ios-opacity-hover: .1 !default; + +/// @prop - Opacity of the segment button when pressed +$segment-button-ios-opacity-activated: .16 !default; + +/// @prop - Opacity of the disabled segment button +$segment-button-ios-opacity-disabled: .3 !default; + +/// @prop - Background of the segment button on hover +$segment-button-ios-background-color-hover: ion-color(primary, base, $segment-button-ios-opacity-hover) !default; + +/// @prop - Background of the activated segment button +$segment-button-ios-background-color-activated: ion-color(primary, base, $segment-button-ios-opacity-activated) !default; + +/// @prop - Background of the disabled segment button +$segment-button-ios-background-color-disabled: ion-color(primary, base, $segment-button-ios-opacity-disabled) !default; + +/// @prop - Text color of the segment button +$segment-button-ios-text-color: ion-color(primary, base) !default; + +/// @prop - Border width of the segment button +$segment-button-ios-border-width: 1px !default; + +/// @prop - Height of the segment button +$segment-button-ios-height: 24px !default; + +/// @prop - Line height of the segment button +$segment-button-ios-line-height: 37px !default; + +/// @prop - Font size of the segment button +$segment-button-ios-font-size: 13px !default; + +/// @prop - Border radius of the segment button +$segment-button-ios-border-radius: 4px !default; + +/// @prop - Border color of the segment button +$segment-button-ios-border-color: ion-color(primary, base) !default; + +/// @prop - Size of an icon in the segment button +$segment-button-ios-icon-size: 26px !default; + +/// @prop - Line height of an icon in the segment button +$segment-button-ios-icon-line-height: 28px !default; + +/// @prop - Transition of the segment button +$segment-button-ios-transition: 100ms all linear !default; + +/// @prop - Max width of the segment button in a toolbar +$segment-button-ios-toolbar-button-max-width: 100px !default; + +/// @prop - Line height of the segment button in a toolbar +$segment-button-ios-toolbar-line-height: 22px !default; + +/// @prop - Font size of the segment button in a toolbar +$segment-button-ios-toolbar-font-size: 12px !default; + +/// @prop - Size of an icon in the segment button in a toolbar +$segment-button-ios-toolbar-icon-size: 22px !default; + +/// @prop - Line height of an icon in the segment button in a toolbar +$segment-button-ios-toolbar-icon-line-height: 24px !default; diff --git a/core/src/components/segment-button/segment-button.md.scss b/core/src/components/segment-button/segment-button.md.scss new file mode 100644 index 00000000000..ace9166eb8a --- /dev/null +++ b/core/src/components/segment-button/segment-button.md.scss @@ -0,0 +1,112 @@ +@import "./segment-button"; +@import "./segment-button.md.vars"; + +// Material Design Segment Button +// -------------------------------------------------- + +:host { + --padding-top: #{$segment-button-md-padding-top}; + --padding-end: #{$segment-button-md-padding-end}; + --padding-bottom: #{$segment-button-md-padding-bottom}; + --padding-start: #{$segment-button-md-padding-start}; + --transition: #{$segment-button-md-transition}; + --background: #{$segment-button-md-background}; + --background-hover: #{$segment-button-md-background-hover}; + --background-activated: #{$segment-button-md-background-activated}; + --color: #{$segment-button-md-text-color}; + --color-activated: var(--color); + --color-checked: #{$segment-button-md-text-color-activated}; + --color-checked-disabled: var(--color-checked); + --indicator-color: transparent; + --indicator-color-checked: var(--color-checked); + --ripple-color: var(--color-checked); + + min-width: $segment-button-md-min-width; + + max-width: $segment-button-md-max-width; + min-height: $segment-button-md-min-height; + + font-size: $segment-button-md-font-size; + font-weight: $segment-button-md-font-weight; + + letter-spacing: $segment-button-md-letter-spacing; + + line-height: $segment-button-md-line-height; + + text-transform: uppercase; +} + +// Segment Button: Checked +// -------------------------------------------------- + +:host(.activated), +:host(.segment-button-checked) { + --border-color: #{$segment-button-md-border-bottom-color-activated}; + + opacity: $segment-button-md-opacity-activated; +} + +// Segment Button: Disabled +// -------------------------------------------------- + +:host(.segment-button-disabled) { + opacity: $segment-button-md-opacity-disabled; +} + +// Segment Button: Icon +// -------------------------------------------------- + +::slotted(ion-icon) { + @include margin(12px, null, 12px, null); + + font-size: $segment-button-md-icon-size; +} + +// Segment Button: Label +// -------------------------------------------------- + +::slotted(ion-label) { + @include margin(12px, null, 12px, null); +} + +// Segment Button: Layout +// -------------------------------------------------- + +// Layout: icon top / icon bottom +:host(.segment-button-layout-icon-top) ::slotted(ion-label), +:host(.segment-button-layout-icon-bottom) ::slotted(ion-icon) { + @include margin(0, null, null, null); +} + +:host(.segment-button-layout-icon-top) ::slotted(ion-icon), +:host(.segment-button-layout-icon-bottom) ::slotted(ion-label) { + @include margin(null, null, 0, null); +} + +// Layout: icon start +:host(.segment-button-layout-icon-start) ::slotted(ion-label) { + @include margin-horizontal(8px, 0); +} + +// Layout: icon end +:host(.segment-button-layout-icon-end) ::slotted(ion-label) { + @include margin-horizontal(0, 8px); +} + + +// Segment: Checked & Activated +// -------------------------------------------------- + +:host(.segment-button-checked.activated) { + color: var(--color-checked); +} + + +// Segment Button: Hover +// -------------------------------------------------- + +@media (any-hover: hover) { + :host(:hover) { + background: var(--background-hover); + } +} diff --git a/core/src/components/segment-button/segment-button.md.vars.scss b/core/src/components/segment-button/segment-button.md.vars.scss new file mode 100644 index 00000000000..5d2a7f7aea6 --- /dev/null +++ b/core/src/components/segment-button/segment-button.md.vars.scss @@ -0,0 +1,79 @@ +@import "../../themes/ionic.globals.md"; + +// Material Design Segment Button +// -------------------------------------------------- + +/// @prop - Opacity of the segment button +$segment-button-md-opacity: .6 !default; + +/// @prop - Text color of the segment button +$segment-button-md-text-color: rgba(var(--ion-text-color-rgb, $text-color-rgb), $segment-button-md-opacity) !default; + +/// @prop - Background of the segment button +$segment-button-md-background: none !default; + +/// @prop - Background of the hovered segment button +$segment-button-md-background-hover: ion-color(primary, base, .04) !default; + +/// @prop - Background of the activated segment button +$segment-button-md-background-activated: ion-color(primary, base, .16) !default; + +/// @prop - Width of the bottom border on the segment button +$segment-button-md-border-bottom-width: 2px !default; + +/// @prop - Color of the bottom border on the segment button +$segment-button-md-border-bottom-color: transparent !default; + +/// @prop - Text color of the activated segment button +$segment-button-md-text-color-activated: ion-color(primary, base) !default; + +/// @prop - Border color of the activated segment button +$segment-button-md-border-bottom-color-activated: ion-color(primary, base) !default; + +/// @prop - Opacity of the activated segment button +$segment-button-md-opacity-activated: 1 !default; + +/// @prop - Opacity of the disabled segment button +$segment-button-md-opacity-disabled: .3 !default; + +/// @prop - Padding top of the segment button +$segment-button-md-padding-top: 0 !default; + +/// @prop - Padding end of the segment button +$segment-button-md-padding-end: 16px !default; + +/// @prop - Padding bottom of the segment button +$segment-button-md-padding-bottom: $segment-button-md-padding-top !default; + +/// @prop - Padding start of the segment button +$segment-button-md-padding-start: $segment-button-md-padding-end !default; + +/// @prop - Minimum height of the segment button +$segment-button-md-min-height: 48px !default; + +/// @prop - Minimum width of the segment button +$segment-button-md-min-width: 90px !default; + +/// @prop - Maximum width of the segment button +$segment-button-md-max-width: 360px !default; + +/// @prop - Line height of the segment button +$segment-button-md-line-height: 40px !default; + +/// @prop - Font size of the segment button +$segment-button-md-font-size: 14px !default; + +/// @prop - Letter spacing of the segment button +$segment-button-md-letter-spacing: .06em !default; + +/// @prop - Font weight of the segment button +$segment-button-md-font-weight: 500 !default; + +/// @prop - Transition of the segment button +$segment-button-md-transition: color .15s linear 0s, opacity .15s linear 0s !default; + +/// @prop - Size of an icon in the segment button +$segment-button-md-icon-size: 24px !default; + +/// @prop - Line height of an icon in the segment button +$segment-button-md-icon-line-height: $segment-button-md-line-height !default; diff --git a/core/src/components/segment-button/segment-button.scss b/core/src/components/segment-button/segment-button.scss index 962ea92bf37..04fa602518e 100644 --- a/core/src/components/segment-button/segment-button.scss +++ b/core/src/components/segment-button/segment-button.scss @@ -5,83 +5,221 @@ :host { /** - * @prop --btn-background: Background of the button - * @prop --btn-border-color: Color of the button border - * @prop --border-radius: Radius of the button border - * @prop --border-style: Style of the button border - * @prop --border-width: Width of the button border - * @prop --icon-size: Size of the button icon - * @prop --margin-top: Top margin of the button - * @prop --margin-end: End margin of the button - * @prop --margin-bottom: Bottom margin of the button - * @prop --margin-start: Start margin of the button - * @prop --padding-top: Top padding of the button - * @prop --padding-end: End padding of the button - * @prop --padding-bottom: Bottom padding of the button - * @prop --padding-start: Start padding of the button - * @prop --transition: Transition of the button + * @prop --background: Background of the segment button + * @prop --background-hover: Background of the segment button on hover + * @prop --background-activated: Background of the activated (pressed) segment button + * @prop --background-checked: Background of the checked segment button + * + * @prop --color: Color of the segment button + * @prop --color-activated: Color of the activated (pressed) segment button + * @prop --color-checked: Color of the checked segment button + * @prop --color-disabled: Color of the disabled segment button + * @prop --color-checked-disabled: Color of the checked & disabled segment button + * + * @prop --border-radius: Radius of the segment button border + * @prop --border-color: Color of the segment button border + * @prop --border-style: Style of the segment button border + * @prop --border-width: Width of the segment button border + * + * @prop --margin-top: Top margin of the segment button + * @prop --margin-end: End margin of the segment button + * @prop --margin-bottom: Bottom margin of the segment button + * @prop --margin-start: Start margin of the segment button + * + * @prop --padding-top: Top padding of the segment button + * @prop --padding-end: End padding of the segment button + * @prop --padding-bottom: Bottom padding of the segment button + * @prop --padding-start: Start padding of the segment button + * + * @prop --transition: Transition of the segment button + * + * @prop --indicator-color: Color of the indicator (highlight) under the segment button + * @prop --indicator-color-checked: Color of the indicator (highlight) under the checked segment button + * */ --padding-start: 0; --padding-end: 0; --padding-top: 0; --padding-bottom: 0; - --icon-size: 1em; - --btn-background: inherit; - --btn-border-color: inherit; + --indicator-color: transparent; - flex: 1; + flex: 1 0 auto; + flex-direction: column; - color: inherit; + height: 100%; + + border-width: var(--border-width); + border-style: var(--border-style); + border-color: var(--border-color); + + color: var(--color); text-decoration: none; text-overflow: ellipsis; white-space: nowrap; font-kerning: none; -} -:host(:first-of-type) .button-native { - --padding-end: 0; + overflow: hidden; +} +:host(:first-of-type) { @include border-radius(var(--border-radius), 0, 0, var(--border-radius)); } -:host(:not(:first-of-type)) .button-native { +:host(:not(:first-of-type)) { border-left-width: 0; } -:host(:last-of-type) .button-native { - --padding-start: 0; - +:host(:last-of-type) { @include border-radius(0, var(--border-radius), var(--border-radius), 0); } .button-native { + @include border-radius(inherit); @include text-inherit(); @include margin(var(--margin-top), var(--margin-end), var(--margin-bottom), var(--margin-start)); @include padding(var(--padding-top), var(--padding-end), var(--padding-bottom), var(--padding-start)); - display: block; + display: flex; position: relative; + flex-direction: inherit; + align-items: center; + justify-content: center; + width: 100%; + + min-width: inherit; + max-width: inherit; height: 100%; + min-height: inherit; + max-height: inherit; + transition: var(--transition); - border-width: var(--border-width); - border-style: var(--border-style); - border-color: var(--btn-border-color); + border: none; outline: none; - background: var(--btn-background); + background: var(--background); contain: content; cursor: pointer; - overflow: hidden; } -::slotted(ion-icon) { - font-size: var(--icon-size); + +// Segment Button: Checked +// -------------------------------------------------- + +:host(.segment-button-checked) { + background: var(--background-checked); + color: var(--color-checked); +} + +:host(.segment-button-checked) .segment-button-indicator { + background-color: var(--indicator-color-checked); +} + +// Segment Button: Activated +// -------------------------------------------------- + +:host(.activated) { + color: var(--color-activated); +} + + +// Segment Button: Disabled +// -------------------------------------------------- + +:host(.segment-button-disabled) { + color: var(--color-disabled); +} + +// Segment Button: Checked & Disabled +// -------------------------------------------------- + +:host(.segment-button-disabled.segment-button-checked) { + color: var(--color-checked-disabled); +} + + +// Segment Button: Indicator +// -------------------------------------------------- + +.segment-button-indicator { + + align-self: flex-end; + + width: 100%; + + height: 2px; + + background-color: var(--indicator-color); + + opacity: 1; +} + + +// Segment Button Label +// -------------------------------------------------- + +::slotted(ion-label) { + display: block; + + align-self: center; + + line-height: 22px; + + text-overflow: ellipsis; + + white-space: nowrap; + + box-sizing: border-box; +} + + +// Segment Button Layout +// -------------------------------------------------- + +// Layout: icon top +:host(.segment-button-layout-icon-top) ::slotted(ion-icon) { + order: -1; +} + +// Layout: icon bottom +:host(.segment-button-layout-icon-bottom) ::slotted(ion-icon) { + order: 1; +} + +// Layout: icon start / end +:host(.segment-button-layout-icon-start), +:host(.segment-button-layout-icon-end) { + flex-direction: row; +} + +:host(.segment-button-layout-icon-start) ::slotted(ion-icon) { + order: -1; +} + +:host(.segment-button-layout-icon-end) ::slotted(ion-icon) { + order: 1; +} + +// Layout: icon hide +:host(.segment-button-layout-icon-hide) ::slotted(ion-icon) { + display: none; +} + +// Layout: label hide +:host(.segment-button-layout-label-hide) ::slotted(ion-label) { + display: none; +} + +// Segment Button Ripple +// -------------------------------------------------- + +ion-ripple-effect { + color: var(--ripple-color); } diff --git a/core/src/components/segment-button/segment-button.tsx b/core/src/components/segment-button/segment-button.tsx index 674c54a5222..dcbed44effc 100644 --- a/core/src/components/segment-button/segment-button.tsx +++ b/core/src/components/segment-button/segment-button.tsx @@ -1,13 +1,16 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Prop, Watch } from '@stencil/core'; -import { Color, Mode } from '../../interface'; +import { Color, Mode, SegmentButtonLayout } from '../../interface'; import { createColorClasses } from '../../utils/theme'; let ids = 0; @Component({ tag: 'ion-segment-button', - styleUrl: 'segment-button.scss', + styleUrls: { + ios: 'segment-button.ios.scss', + md: 'segment-button.md.scss' + }, shadow: true }) export class SegmentButton implements ComponentInterface { @@ -36,6 +39,11 @@ export class SegmentButton implements ComponentInterface { */ @Prop() disabled = false; + /** + * Set the layout of the text and icon in the segment. + */ + @Prop() layout!: SegmentButtonLayout; + /** * The value of the segment button. */ @@ -53,14 +61,19 @@ export class SegmentButton implements ComponentInterface { } } + private onClick = () => { + this.checked = true; + } + hostData() { const { disabled, checked, color } = this; return { - 'ion-activatable': true, + 'ion-activatable': 'instant', class: { ...createColorClasses(color), 'segment-button-disabled': disabled, 'segment-button-checked': checked, + [`segment-button-layout-${this.layout}`]: true } }; } @@ -72,11 +85,12 @@ export class SegmentButton implements ComponentInterface { aria-pressed={this.checked ? 'true' : null} class="button-native" disabled={this.disabled} - onClick={() => this.checked = true} + onClick={this.onClick} > {this.mode === 'md' && } - + , +
]; } } diff --git a/core/src/components/segment-button/segment-interface.ts b/core/src/components/segment-button/segment-interface.ts new file mode 100644 index 00000000000..9ceeb14e41f --- /dev/null +++ b/core/src/components/segment-button/segment-interface.ts @@ -0,0 +1 @@ +export type SegmentButtonLayout = 'icon-top' | 'icon-start' | 'icon-end' | 'icon-bottom' | 'icon-hide' | 'label-hide'; diff --git a/core/src/components/segment-button/usage/angular.md b/core/src/components/segment-button/usage/angular.md index ba97fa2edd7..4b30ba0af95 100644 --- a/core/src/components/segment-button/usage/angular.md +++ b/core/src/components/segment-button/usage/angular.md @@ -2,23 +2,23 @@ - Friends + Friends - Enemies + Enemies - Paid + Paid - Free + Free - Top + Top @@ -35,13 +35,103 @@ - Bookmarks + Bookmarks - Reading List + Reading List - Shared Links + Shared Links + + + + + + + Item One + + + Item Two + + + Item Three + + + + + + + + + + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three ``` diff --git a/core/src/components/segment-button/usage/javascript.md b/core/src/components/segment-button/usage/javascript.md index 72407c28df3..498d8c130e0 100644 --- a/core/src/components/segment-button/usage/javascript.md +++ b/core/src/components/segment-button/usage/javascript.md @@ -2,23 +2,23 @@ - Friends + Friends - Enemies + Enemies - Paid + Paid - Free + Free - Top + Top @@ -35,13 +35,103 @@ - Bookmarks + Bookmarks - Reading List + Reading List - Shared Links + Shared Links + + + + + + + Item One + + + Item Two + + + Item Three + + + + + + + + + + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three ``` diff --git a/core/src/components/segment/readme.md b/core/src/components/segment/readme.md index e668eb170e8..12292034cc2 100644 --- a/core/src/components/segment/readme.md +++ b/core/src/components/segment/readme.md @@ -10,12 +10,13 @@ Their functionality is similar to tabs, where selecting one will deselect all ot ## Properties -| Property | Attribute | Description | Type | Default | -| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ----------- | -| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | -| `disabled` | `disabled` | If `true`, the user cannot interact with the segment. | `boolean` | `false` | -| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | -| `value` | `value` | the value of the segment. | `null \| string \| undefined` | `undefined` | +| Property | Attribute | Description | Type | Default | +| ------------ | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- | ----------- | +| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` | +| `disabled` | `disabled` | If `true`, the user cannot interact with the segment. | `boolean` | `false` | +| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` | +| `scrollable` | `scrollable` | If `true`, the segment buttons will overflow and the user can swipe to see them. | `boolean` | `false` | +| `value` | `value` | the value of the segment. | `null \| string \| undefined` | `undefined` | ## Events @@ -23,20 +24,7 @@ Their functionality is similar to tabs, where selecting one will deselect all ot | Event | Description | Detail | | ----------- | -------------------------------------------- | -------------------- | | `ionChange` | Emitted when the value property has changed. | TextInputChangeEvent | - - -## CSS Custom Properties - -| Name | Description | -| ------------------------- | -------------------------------- | -| `--background` | Background of segment | -| `--background-checked` | Background of checked segment | -| `--border-color` | Color of segment border | -| `--border-color-checked` | Color of checked segment border | -| `--border-color-disabled` | Color of disabled segment border | -| `--color` | Color of segment text | -| `--color-checked` | Color of checked segment text | -| `--color-disabled` | Color of disabled segment text | +| `ionStyle` | Emitted when the styles change. | StyleEvent | ---------------------------------------------- diff --git a/core/src/components/segment/segment.ios.scss b/core/src/components/segment/segment.ios.scss index 76613f8b6fb..c6c0b578ab9 100644 --- a/core/src/components/segment/segment.ios.scss +++ b/core/src/components/segment/segment.ios.scss @@ -4,82 +4,62 @@ // iOS Segment // -------------------------------------------------- -:host { - --background: transparent; - --background-checked: #{ion-color(primary, base)}; - --border-color: currentColor; - --border-color-checked: #{ion-color(primary, base)}; - --border-color-disabled: #{ion-color(primary, base)}; - --color: #{ion-color(primary, base)}; - --color-checked: #{ion-color(primary, contrast)}; - --color-disabled: #{ion-color(primary, base, $segment-button-ios-opacity-disabled)}; -} - :host(.segment-disabled) { opacity: $segment-ios-opacity-disabled; } -// iOS Segment Button -// -------------------------------------------------- - -::slotted(ion-segment-button) { - --border-radius: #{$segment-button-ios-border-radius}; - --border-width: #{$segment-button-ios-border-width}; - --border-style: solid; - --transition: 100ms all linear; - --icon-size: #{$segment-button-ios-icon-size}; - - height: #{$segment-button-ios-height}; - - font-size: #{$segment-button-ios-font-size}; - line-height: #{$segment-button-ios-line-height}; -} +// Segment: Color +// -------------------------------------------------- -::slotted(.segment-button-disabled) { - --btn-border-color: var(--border-color-disabled); +:host(.ion-color)::slotted(ion-segment-button) { + --border-color: #{current-color(base)}; + --background-hover: #{current-color(base, .04)}; - color: var(--color-disabled); + color: #{current-color(base)}; } -:host(.ion-color)::slotted(ion-segment-button) { +:host(.ion-color)::slotted(.activated) { + background: #{current-color(base, .16)}; color: #{current-color(base)}; } +:host(.ion-color)::slotted(.segment-button-checked.activated), :host(.ion-color)::slotted(.segment-button-checked) { - --btn-background: #{current-color(base)}; - --btn-border-color: #{current-color(base)}; + background: #{current-color(base)}; color: #{current-color(contrast)}; } :host(.ion-color)::slotted(.segment-button-disabled) { - --btn-border-color: #{current-color(base)}; - color: #{current-color(base, $segment-button-ios-background-color-alpha-disabled)}; + color: #{current-color(base, $segment-ios-opacity-disabled)}; } -// iOS Segment in Toolbar -// -------------------------------------------------- -:host-context(ion-toolbar) { - @include position(0, 0, 0, 0); - @include margin(0); - - position: absolute; +:host(.ion-color)::slotted(.segment-button-checked.segment-button-disabled) { + color: #{current-color(contrast, $segment-ios-opacity-disabled)}; } + +// Segment: Default Toolbar +// -------------------------------------------------- + :host-context(ion-toolbar)::slotted(ion-segment-button) { max-width: $segment-button-ios-toolbar-button-max-width; - height: $segment-button-ios-toolbar-button-height; font-size: $segment-button-ios-toolbar-font-size; line-height: $segment-button-ios-toolbar-line-height; } -:host-context(ion-toolbar.ion-color):not(.ion-color) { +// Segment: Color Toolbar +// -------------------------------------------------- + +:host-context(ion-toolbar.ion-color):not(.ion-color)::slotted(ion-segment-button) { --color: #{current-color(contrast)}; - --color-checked: #{current-color(base)}; --color-disabled: #{current-color(contrast, $segment-button-ios-opacity-disabled)}; + --color-checked: #{current-color(base)}; + --color-checked-disabled: #{current-color(contrast, $segment-button-ios-opacity-disabled)}; + --background-hover: #{current-color(contrast, $segment-button-ios-opacity-hover)}; + --background-activated: #{current-color(contrast, $segment-button-ios-opacity-activated)}; --background-checked: #{current-color(contrast)}; - --border-color-checked: #{current-color(contrast)}; - --border-color-disabled: #{current-color(contrast)}; -} + --border-color: #{current-color(contrast)}; +} \ No newline at end of file diff --git a/core/src/components/segment/segment.ios.vars.scss b/core/src/components/segment/segment.ios.vars.scss index dcaef28e21f..ab57fc67d05 100644 --- a/core/src/components/segment/segment.ios.vars.scss +++ b/core/src/components/segment/segment.ios.vars.scss @@ -1,86 +1,8 @@ @import "../../themes/ionic.globals.ios"; +@import "../segment-button/segment-button.ios.vars"; // iOS Segment // -------------------------------------------------- /// @prop - Opacity of the disabled segment -$segment-ios-opacity-disabled: .4 !default; - - -// iOS Segment Button -// -------------------------------------------------- - -/// @prop - Background of the segment button -$segment-button-ios-background-color: transparent !default; - -/// @prop - Background of the activated segment button -$segment-button-ios-background-color-activated: ion-color(primary, base) !default; - -/// @prop - Background alpha of the activated segment button -$segment-button-ios-background-color-alpha-hover: .1 !default; - -/// @prop - Background of the segment button when hovered -$segment-button-ios-background-color-hover: ion-color(primary, base, $segment-button-ios-background-color-alpha-hover) !default; - -/// @prop - Background alpha of the segment button when hovered -$segment-button-ios-background-color-alpha-active: .1 !default; - -/// @prop - Background of the segment button when active -$segment-button-ios-background-color-active: ion-color(primary, base, $segment-button-ios-background-color-alpha-active) !default; - -/// @prop - Background alpha of the segment button when active -$segment-button-ios-background-color-alpha-disabled: .5 !default; - -/// @prop - Background of the activated segment button when active -$segment-button-ios-background-color-disabled: ion-color(primary, base, $segment-button-ios-background-color-alpha-disabled) !default; - -/// @prop - Text color of the segment button -$segment-button-ios-text-color: ion-color(primary, contrast) !default; - -/// @prop - Border width of the segment button -$segment-button-ios-border-width: 1px !default; - -/// @prop - Height of the segment button -$segment-button-ios-height: 32px !default; - -/// @prop - Line height of the segment button -$segment-button-ios-line-height: 37px !default; - -/// @prop - Font size of the segment button -$segment-button-ios-font-size: 13px !default; - -/// @prop - Border radius of the segment button -$segment-button-ios-border-radius: 4px !default; - -/// @prop - Size of an icon in the segment button -$segment-button-ios-icon-size: 26px !default; - -/// @prop - Line height of an icon in the segment button -$segment-button-ios-icon-line-height: 28px !default; - -/// @prop - Max width of the segment button in a toolbar -$segment-button-ios-toolbar-button-max-width: 100px !default; - -/// @prop - Height of the segment button in a toolbar -$segment-button-ios-toolbar-button-height: 30px !default; - -/// @prop - Line height of the segment button in a toolbar -$segment-button-ios-toolbar-line-height: 22px !default; - -/// @prop - Font size of the segment button in a toolbar -$segment-button-ios-toolbar-font-size: 12px !default; - -/// @prop - Size of an icon in the segment button in a toolbar -$segment-button-ios-toolbar-icon-size: 22px !default; - -/// @prop - Line height of an icon in the segment button in a toolbar -$segment-button-ios-toolbar-icon-line-height: 24px !default; - -/// @prop - Opacity of the segment button on hover -$segment-button-ios-opacity-hover: .1 !default; - -/// @prop - Opacity of the segment button when pressed -$segment-button-ios-opacity-active: .16 !default; - -/// @prop - Opacity of the disabled segment button -$segment-button-ios-opacity-disabled: .3 !default; +$segment-ios-opacity-disabled: .3 !default; diff --git a/core/src/components/segment/segment.md.scss b/core/src/components/segment/segment.md.scss index 82fcba297ab..99525f36bc8 100644 --- a/core/src/components/segment/segment.md.scss +++ b/core/src/components/segment/segment.md.scss @@ -4,71 +4,35 @@ // Material Design Segment // -------------------------------------------------- -:host { - --background: transparent; - --background-checked: transparent; - --border-color: #{$segment-button-md-border-bottom-color}; - --color: #{$segment-button-md-text-color}; - --color-checked: #{$segment-button-md-text-color}; -} - :host(.segment-disabled) { opacity: $segment-md-opacity-disabled; } -// Material Design Segment Button Color +// Segment: Color // -------------------------------------------------- -:host-context(ion-toolbar.ion-color):not(.ion-color) { - --color: #{current-color(contrast)}; - --color-checked: #{current-color(contrast)}; -} - :host(.ion-color)::slotted(ion-segment-button) { - --color: #{current-color(base)}; + --background-hover: #{current-color(base, .04)}; + --background-activated: #{current-color(base, .16)}; + --ripple-color: #{current-color(base)}; } :host(.ion-color)::slotted(.segment-button-checked) { + --indicator-color-checked: #{current-color(base)}; color: #{current-color(base)}; } - -// Material Design Segment Button -// -------------------------------------------------- - -::slotted(ion-segment-button) { - --padding-top: #{$segment-button-md-padding-top}; - --padding-end: #{$segment-button-md-padding-end}; - --padding-bottom: #{$segment-button-md-padding-bottom}; - --padding-start: #{$segment-button-md-padding-start}; - --border-width: #{0 0 $segment-button-md-border-bottom-width 0}; - --border-style: solid; - --transition: #{$segment-button-md-transition}; - --icon-size: #{$segment-button-md-icon-size}; - - height: $segment-button-md-height; - - font-size: $segment-button-md-font-size; - font-weight: $segment-button-md-font-weight; - - line-height: $segment-button-md-line-height; - - text-transform: uppercase; - - opacity: $segment-button-md-opacity; -} - -// Checked Segment Button -// -------------------------------------------------- - -::slotted(.activated), -::slotted(.segment-button-checked) { - opacity: $segment-button-md-opacity-activated; +:host(.ion-color)::slotted(.segment-button-checked.activated) { + color: #{current-color(base)}; } -// Disabled Segment Button +// Segment: Toolbar Color // -------------------------------------------------- -::slotted(.segment-button-disabled) { - opacity: $segment-button-md-opacity-disabled; +:host-context(ion-toolbar.ion-color):not(.ion-color)::slotted(ion-segment-button) { + --background-hover: #{current-color(contrast, .04)}; + --background-activated: #{current-color(base)}; + --color: #{current-color(contrast, .6)}; + --color-checked: #{current-color(contrast)}; + --indicator-color-checked: #{current-color(contrast)}; } diff --git a/core/src/components/segment/segment.md.vars.scss b/core/src/components/segment/segment.md.vars.scss index 6681fa41e08..8afad1e1f2a 100644 --- a/core/src/components/segment/segment.md.vars.scss +++ b/core/src/components/segment/segment.md.vars.scss @@ -4,62 +4,4 @@ // -------------------------------------------------- /// @prop - Opacity of the disabled segment -$segment-md-opacity-disabled: .3 !default; - - -// Material Design Segment Button -// -------------------------------------------------- - -/// @prop - Text color of the segment button -$segment-button-md-text-color: $toolbar-md-color-activated !default; - -/// @prop - Width of the bottom border on the segment button -$segment-button-md-border-bottom-width: 2px !default; - -/// @prop - Color of the bottom border on the segment button -$segment-button-md-border-bottom-color: rgba(#000, .10) !default; - -/// @prop - Opacity of the segment button -$segment-button-md-opacity: .7 !default; - -/// @prop - Border color of the activated segment button -$segment-button-md-border-color-activated: $toolbar-md-color-activated !default; - -/// @prop - Opacity of the activated segment button -$segment-button-md-opacity-activated: 1 !default; - -/// @prop - Opacity of the disabled segment button -$segment-button-md-opacity-disabled: .3 !default; - -/// @prop - Padding top of the segment button -$segment-button-md-padding-top: 0 !default; - -/// @prop - Padding end of the segment button -$segment-button-md-padding-end: 6px !default; - -/// @prop - Padding bottom of the segment button -$segment-button-md-padding-bottom: $segment-button-md-padding-top !default; - -/// @prop - Padding start of the segment button -$segment-button-md-padding-start: $segment-button-md-padding-end !default; - -/// @prop - Height of the segment button -$segment-button-md-height: 42px !default; - -/// @prop - Line height of the segment button -$segment-button-md-line-height: 40px !default; - -/// @prop - Font size of the segment button -$segment-button-md-font-size: 12px !default; - -/// @prop - Font weight of the segment button -$segment-button-md-font-weight: 500 !default; - -/// @prop - Transition of the segment button -$segment-button-md-transition: 100ms all linear !default; - -/// @prop - Size of an icon in the segment button -$segment-button-md-icon-size: 26px !default; - -/// @prop - Line height of an icon in the segment button -$segment-button-md-icon-line-height: $segment-button-md-line-height !default; +$segment-md-opacity-disabled: .3 !default; diff --git a/core/src/components/segment/segment.scss b/core/src/components/segment/segment.scss index 91051ffa13b..1e89d0a3654 100644 --- a/core/src/components/segment/segment.scss +++ b/core/src/components/segment/segment.scss @@ -4,17 +4,6 @@ // -------------------------------------------------- :host { - /** - * @prop --background: Background of segment - * @prop --background-checked: Background of checked segment - * @prop --border-color: Color of segment border - * @prop --border-color-checked: Color of checked segment border - * @prop --border-color-disabled: Color of disabled segment border - * @prop --color: Color of segment text - * @prop --color-checked: Color of checked segment text - * @prop --color-disabled: Color of disabled segment text - */ - @include font-smoothing(); display: flex; @@ -30,23 +19,27 @@ text-align: center; } -::slotted(ion-segment-button) { - --btn-background: var(--background); - --btn-border-color: var(--border-color); - color: var(--color); +// Segment: Disabled +// -------------------------------------------------- + +:host(.segment-disabled), +::slotted(.segment-button-disabled) { + pointer-events: none; } -::slotted(.segment-button-checked) { - --btn-background: var(--background-checked); - --btn-border-color: var(--border-color-checked); - color: var(--color-checked); -} +// Segment: Scrollable +// -------------------------------------------------- -// Disabled +:host(.segment-scrollable) { + justify-content: start; -:host(.segment-disabled), -::slotted(.segment-button-disabled) { - pointer-events: none; -} \ No newline at end of file + width: auto; + + overflow-x: scroll; +} + +:host(.segment-scrollable::-webkit-scrollbar) { + display: none; +} diff --git a/core/src/components/segment/segment.tsx b/core/src/components/segment/segment.tsx index aa5713a7427..c0a9423ce6c 100644 --- a/core/src/components/segment/segment.tsx +++ b/core/src/components/segment/segment.tsx @@ -1,6 +1,6 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, Watch } from '@stencil/core'; -import { Color, Mode, TextInputChangeEvent } from '../../interface'; +import { Color, Mode, StyleEvent, TextInputChangeEvent } from '../../interface'; import { createColorClasses } from '../../utils/theme'; @Component({ @@ -32,6 +32,11 @@ export class Segment implements ComponentInterface { */ @Prop() disabled = false; + /** + * If `true`, the segment buttons will overflow and the user can swipe to see them. + */ + @Prop() scrollable = false; + /** * the value of the segment. */ @@ -48,12 +53,21 @@ export class Segment implements ComponentInterface { */ @Event() ionChange!: EventEmitter; + /** + * Emitted when the styles change. + */ + @Event() ionStyle!: EventEmitter; + @Listen('ionSelect') segmentClick(ev: CustomEvent) { const selectedButton = ev.target as HTMLIonSegmentButtonElement; this.value = selectedButton.value; } + componentWillLoad() { + this.emitStyle(); + } + componentDidLoad() { if (this.value == null) { const checked = this.getButtons().find(b => b.checked); @@ -64,6 +78,12 @@ export class Segment implements ComponentInterface { this.updateButtons(); } + private emitStyle() { + this.ionStyle.emit({ + 'segment': true + }); + } + private updateButtons() { const value = this.value; for (const button of this.getButtons()) { @@ -79,8 +99,8 @@ export class Segment implements ComponentInterface { return { class: { ...createColorClasses(this.color), - - 'segment-disabled': this.disabled + 'segment-disabled': this.disabled, + 'segment-scrollable': this.scrollable } }; } diff --git a/core/src/components/segment/test/basic/index.html b/core/src/components/segment/test/basic/index.html index 66f320157ab..dda0a10b8b0 100644 --- a/core/src/components/segment/test/basic/index.html +++ b/core/src/components/segment/test/basic/index.html @@ -13,13 +13,11 @@ - + Segment - Basic - - @@ -83,18 +81,20 @@ + +
- Seg 1 - Seg 2 - Seg 3 + Seg 1 + Seg 2 + Seg 3 - Seg 2 1 - Seg 2 2 - Seg 2 3 + Seg 2 1 + Seg 2 2 + Seg 2 3 @@ -111,25 +111,37 @@ - Bookmarks + Bookmarks - Reading List + Reading List - Shared Links + Shared Links - Active + Active - Disabled + Disabled - Inactive + Inactive + + + + + + Active + + + Disabled + + + Inactive @@ -195,7 +207,7 @@ for (var i = 0; i < length; i++) { dynamicButtons.innerHTML += ` - Btn ${i} + Btn ${i} `; } } diff --git a/core/src/components/segment/test/modes/index.html b/core/src/components/segment/test/modes/index.html index 60a7dc399ad..21510e4b28b 100644 --- a/core/src/components/segment/test/modes/index.html +++ b/core/src/components/segment/test/modes/index.html @@ -13,7 +13,7 @@ - + Segment - Modes @@ -21,30 +21,30 @@

Mode: ios

- - - Puppies + + + Puppies - - Kittens + + Kittens - - Turtles + + Turtles

Mode: md

- - - Puppies + + + Puppies - - Kittens + + Kittens - - Turtles + + Turtles
diff --git a/core/src/components/segment/test/preview/index.html b/core/src/components/segment/test/preview/index.html index 0ce67766231..501a6b9f78b 100644 --- a/core/src/components/segment/test/preview/index.html +++ b/core/src/components/segment/test/preview/index.html @@ -10,213 +10,215 @@ - + - - - + + Segment - - - - - - Paid + + + + + Explore - - Free + + + Flights - - Top - - - - - - - - Bookmarks + + + Trips - - Reading List + + + Account - - Shared Links + + + Settings + - - - - Active - - - Disabled - - - Inactive - - - - - - - - Sunny - - - Rainy - - - - -
- - Seg 1 - Seg 2 - Seg 3 - - - - Seg 2 1 - Seg 2 2 - Seg 2 3 - - - - - - - - - - - - - - - - - Bookmarks - - - Reading List - - - Shared Links - - - - - - Active - - - Disabled - - - Inactive - - - - - -
- -
- Toggle Disabled -
-
- Toggle Value -
- - + +
diff --git a/core/src/components/segment/test/spec/e2e.ts b/core/src/components/segment/test/spec/e2e.ts new file mode 100644 index 00000000000..8362d25915c --- /dev/null +++ b/core/src/components/segment/test/spec/e2e.ts @@ -0,0 +1,12 @@ +import { newE2EPage } from '@stencil/core/testing'; + +test('segment: spec', async () => { + const page = await newE2EPage({ + url: '/src/components/segment/test/spec?ionic:_testing=true' + }); + + await page.waitFor(250); + + const compare = await page.compareScreenshot(); + expect(compare).toMatchScreenshot(); +}); diff --git a/core/src/components/segment/test/spec/index.html b/core/src/components/segment/test/spec/index.html new file mode 100644 index 00000000000..e6e16eec774 --- /dev/null +++ b/core/src/components/segment/test/spec/index.html @@ -0,0 +1,216 @@ + + + + + + Segment - Spec + + + + + + + + + + + Segment - Spec + + + + + + + Explore + + + + Flights + + + + Trips + + + + + + + + + + Item One + + + Item Two + + + Item Three + + + + + + + + + + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/components/segment/test/standalone/index.html b/core/src/components/segment/test/standalone/index.html index 9ba503025e8..98470aed7ee 100644 --- a/core/src/components/segment/test/standalone/index.html +++ b/core/src/components/segment/test/standalone/index.html @@ -14,13 +14,13 @@ - Paid + Paid - Free + Free - Top + Top @@ -39,13 +39,13 @@ - Bookmarks + Bookmarks - Reading List + Reading List - Shared Links + Shared Links @@ -53,25 +53,40 @@ - Active + Active - Disabled + Disabled - Inactive + Inactive - Active + Active - Disabled + Disabled - Inactive + Inactive + + + + + + Facebook + + + + Instagram + + + + Slack + @@ -145,5 +160,24 @@ --color-disabled: rgba(0,0,0,0.3); --color: navy; } + + .segment-facebook { + --background-hover: rgba(59, 89, 153, .04); + --color-checked: #3b5999; + } + + .segment-instagram { + --background-hover: rgba(228, 64, 95, .04); + --color-checked: #e4405f; + } + + .segment-slack { + --background-hover: rgba(58, 175, 133, .04); + --color-checked: #3aaf85; + } + + .custom-icon ion-icon { + font-size: 44px; + } diff --git a/core/src/components/segment/test/toolbar/index.html b/core/src/components/segment/test/toolbar/index.html index 9a58c68bd50..f68875be371 100644 --- a/core/src/components/segment/test/toolbar/index.html +++ b/core/src/components/segment/test/toolbar/index.html @@ -3,17 +3,17 @@ - Segment - Colors + Segment - Toolbar - + - + Segment - Colors @@ -21,13 +21,13 @@ - Paid + Paid - Free + Free - Top + Top @@ -35,13 +35,13 @@ - Paid + Paid - Free + Free - Top + Top @@ -49,13 +49,13 @@ - Paid + Paid - Free + Free - Top + Top @@ -63,41 +63,180 @@ - Bookmarks + Bookmarks - Reading List + Reading List - Shared Links + Shared Links - + - Active + Active - Disabled + Disabled - Inactive + Inactive - + - Sunny + Sunny - Rainy + Rainy + + + + + + Item One + + + Item Two + + + Item Three + + + + + + + + + + + + + + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + + + + + + + Item One + + + + Item Two + + + + Item Three + + + + diff --git a/core/src/components/segment/usage/angular.md b/core/src/components/segment/usage/angular.md index f58858ed6a9..ef7a6c49fc8 100644 --- a/core/src/components/segment/usage/angular.md +++ b/core/src/components/segment/usage/angular.md @@ -29,6 +29,31 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/components/segment/usage/javascript.md b/core/src/components/segment/usage/javascript.md index acc0bcee23e..9dad7746904 100644 --- a/core/src/components/segment/usage/javascript.md +++ b/core/src/components/segment/usage/javascript.md @@ -29,6 +29,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/components/toolbar/toolbar.ios.scss b/core/src/components/toolbar/toolbar.ios.scss index e6fbf2a7182..3892f52021a 100644 --- a/core/src/components/toolbar/toolbar.ios.scss +++ b/core/src/components/toolbar/toolbar.ios.scss @@ -15,7 +15,7 @@ --min-height: 44px; } -// iOS Toolbar Content +// Toolbar: Content // -------------------------------------------------- .toolbar-content { diff --git a/core/src/components/toolbar/toolbar.md.scss b/core/src/components/toolbar/toolbar.md.scss index 276386a4be9..53b86a8314f 100644 --- a/core/src/components/toolbar/toolbar.md.scss +++ b/core/src/components/toolbar/toolbar.md.scss @@ -16,7 +16,7 @@ } -// Material Design Toolbar Content +// Toolbar: Content // -------------------------------------------------- .toolbar-content { @@ -26,3 +26,13 @@ min-width: 0; max-width: 100%; } + +// Toolbar: Segment +// -------------------------------------------------- + +:host(.toolbar-segment) { + --padding-top: 0; + --padding-bottom: 0; + --padding-start: 0; + --padding-end: 0; +} \ No newline at end of file diff --git a/core/src/components/toolbar/toolbar.scss b/core/src/components/toolbar/toolbar.scss index 07161ca24be..19e57068e8e 100644 --- a/core/src/components/toolbar/toolbar.scss +++ b/core/src/components/toolbar/toolbar.scss @@ -76,7 +76,7 @@ box-sizing: border-box; } -// Transparent Toolbar +// Toolbar: Transparent // -------------------------------------------------- .toolbar-background { @@ -97,3 +97,11 @@ z-index: $z-index-toolbar-background; pointer-events: none; } + + +// Toolbar: Segment +// -------------------------------------------------- + +:host(.toolbar-segment) { + --min-height: auto; +} \ No newline at end of file diff --git a/core/src/components/toolbar/toolbar.tsx b/core/src/components/toolbar/toolbar.tsx index 9f1d5f4b9f8..d985d685ae5 100644 --- a/core/src/components/toolbar/toolbar.tsx +++ b/core/src/components/toolbar/toolbar.tsx @@ -1,6 +1,6 @@ -import { Component, ComponentInterface, Prop } from '@stencil/core'; +import { Component, ComponentInterface, Element, Listen, Prop } from '@stencil/core'; -import { Color, Config, Mode } from '../../interface'; +import { Color, Config, CssClassMap, Mode, StyleEvent } from '../../interface'; import { createColorClasses } from '../../utils/theme'; @Component({ @@ -12,6 +12,9 @@ import { createColorClasses } from '../../utils/theme'; shadow: true }) export class Toolbar implements ComponentInterface { + private childrenStyles = new Map(); + + @Element() el!: HTMLStencilElement; @Prop({ context: 'config' }) config!: Config; @@ -27,9 +30,44 @@ export class Toolbar implements ComponentInterface { */ @Prop() mode!: Mode; + @Listen('ionStyle') + childrenStyle(ev: CustomEvent) { + ev.stopPropagation(); + + const tagName = (ev.target as HTMLElement).tagName; + const updatedStyles = ev.detail; + const newStyles = {} as any; + const childStyles = this.childrenStyles.get(tagName) || {}; + + let hasStyleChange = false; + Object.keys(updatedStyles).forEach(key => { + const childKey = `toolbar-${key}`; + const newValue = updatedStyles[key]; + if (newValue !== childStyles[childKey]) { + hasStyleChange = true; + } + if (newValue) { + newStyles[childKey] = true; + } + }); + + if (hasStyleChange) { + this.childrenStyles.set(tagName, newStyles); + this.el.forceUpdate(); + } + } + hostData() { + const childStyles = {}; + this.childrenStyles.forEach(value => { + Object.assign(childStyles, value); + }); + return { - class: createColorClasses(this.color) + class: { + ...childStyles, + ...createColorClasses(this.color) + } }; } diff --git a/core/src/interface.d.ts b/core/src/interface.d.ts index 524a8fac5b8..795e7fa2212 100644 --- a/core/src/interface.d.ts +++ b/core/src/interface.d.ts @@ -16,6 +16,7 @@ export * from './components/range/range-interface'; export * from './components/refresher/refresher-interface'; export * from './components/reorder-group/reorder-group-interface'; export * from './components/content/content-interface'; +export * from './components/segment-button/segment-button-interface'; export * from './components/select/select-interface'; export * from './components/select-popover/select-popover-interface'; export * from './components/spinner/spinner-interface'; diff --git a/core/src/utils/tap-click.ts b/core/src/utils/tap-click.ts index cf4efb9b124..7554c6e9416 100644 --- a/core/src/utils/tap-click.ts +++ b/core/src/utils/tap-click.ts @@ -102,11 +102,12 @@ export function startTapClick(doc: Document) { clearDefers.delete(el); } + const delay = isInstant(el) ? 0 : ADD_ACTIVATED_DEFERS; el.classList.remove(ACTIVATED); activeDefer = setTimeout(() => { addActivated(el, x, y); activeDefer = undefined; - }, ADD_ACTIVATED_DEFERS); + }, delay); } activatableEle = el; } @@ -130,7 +131,7 @@ export function startTapClick(doc: Document) { return; } const time = CLEAR_STATE_DEFERS - Date.now() + lastActivated; - if (smooth && time > 0) { + if (smooth && time > 0 && !isInstant(active)) { const deferId = setTimeout(() => { active.classList.remove(ACTIVATED); clearDefers.delete(active); @@ -173,6 +174,10 @@ function getActivatableTarget(ev: any): any { } } +function isInstant(el: HTMLElement) { + return el.getAttribute('ion-activatable') === 'instant'; +} + function getRippleEffect(el: HTMLElement) { if (el.shadowRoot) { const ripple = el.shadowRoot.querySelector('ion-ripple-effect');