Skip to content

feat(content): add fixedSlotPlacement prop #29233

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ ion-col,css-prop,--ion-grid-columns

ion-content,shadow
ion-content,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-content,prop,fixedSlotPlacement,"after" | "before",'after',false,false
ion-content,prop,forceOverscroll,boolean | undefined,undefined,false,false
ion-content,prop,fullscreen,boolean,false,false,false
ion-content,prop,scrollEvents,boolean,false,false,false
Expand Down
8 changes: 8 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,10 @@ export namespace Components {
* 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).
*/
"color"?: Color;
/**
* Controls where the fixed content is placed relative to the main content in the DOM. This can be used to control the order in which fixed elements receive keyboard focus. For example, if a FAB in the fixed slot should receive keyboard focus before the main page content, set this property to `'before'`.
*/
"fixedSlotPlacement": 'after' | 'before';
/**
* If `true` and the content does not cause an overflow scroll, the scroll interaction will cause a bounce. If the content exceeds the bounds of ionContent, nothing will change. Note, this does not disable the system bounce on iOS. That is an OS level setting.
*/
Expand Down Expand Up @@ -5482,6 +5486,10 @@ declare namespace LocalJSX {
* 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).
*/
"color"?: Color;
/**
* Controls where the fixed content is placed relative to the main content in the DOM. This can be used to control the order in which fixed elements receive keyboard focus. For example, if a FAB in the fixed slot should receive keyboard focus before the main page content, set this property to `'before'`.
*/
"fixedSlotPlacement"?: 'after' | 'before';
/**
* If `true` and the content does not cause an overflow scroll, the scroll interaction will cause a bounce. If the content exceeds the bounds of ionContent, nothing will change. Note, this does not disable the system bounce on iOS. That is an OS level setting.
*/
Expand Down
16 changes: 14 additions & 2 deletions core/src/components/content/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ export class Content implements ComponentInterface {
*/
@Prop() fullscreen = false;

/**
* Controls where the fixed content is placed relative to the main content
* in the DOM. This can be used to control the order in which fixed elements
* receive keyboard focus.
* For example, if a FAB in the fixed slot should receive keyboard focus before
* the main page content, set this property to `'before'`.
*/
@Prop() fixedSlotPlacement: 'after' | 'before' = 'after';

/**
* If `true` and the content does not cause an overflow scroll, the scroll interaction will cause a bounce.
* If the content exceeds the bounds of ionContent, nothing will change.
Expand Down Expand Up @@ -423,7 +432,7 @@ export class Content implements ComponentInterface {
}

render() {
const { isMainContent, scrollX, scrollY, el } = this;
const { fixedSlotPlacement, isMainContent, scrollX, scrollY, el } = this;
const rtl = isRTL(el) ? 'rtl' : 'ltr';
const mode = getIonMode(this);
const forceOverscroll = this.shouldForceOverscroll();
Expand All @@ -446,6 +455,9 @@ export class Content implements ComponentInterface {
}}
>
<div ref={(el) => (this.backgroundContentEl = el)} id="background-content" part="background"></div>

{fixedSlotPlacement === 'before' ? <slot name="fixed"></slot> : null}

<div
class={{
'inner-scroll': true,
Expand All @@ -467,7 +479,7 @@ export class Content implements ComponentInterface {
</div>
) : null}

<slot name="fixed"></slot>
{fixedSlotPlacement === 'after' ? <slot name="fixed"></slot> : null}
</Host>
);
}
Expand Down
31 changes: 31 additions & 0 deletions core/src/components/content/test/content.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { newSpecPage } from '@stencil/core/testing';

import { Content } from '../content';

describe('content: fixed slot placement', () => {
it('should should fixed slot after content', async () => {
const page = await newSpecPage({
components: [Content],
html: '<ion-content></ion-content>',
});

const content = page.body.querySelector('ion-content')!;
const fixedSlot = content.shadowRoot!.querySelector('slot[name="fixed"]')!;
const scrollEl = content.shadowRoot!.querySelector('[part="scroll"]')!;

expect(fixedSlot.nextElementSibling).not.toBe(scrollEl);
});

it('should should fixed slot before content', async () => {
const page = await newSpecPage({
components: [Content],
html: `<ion-content fixed-slot-placement="before"></ion-content>`,
});

const content = page.body.querySelector('ion-content')!;
const fixedSlot = content.shadowRoot!.querySelector('slot[name="fixed"]')!;
const scrollEl = content.shadowRoot!.querySelector('[part="scroll"]')!;

expect(fixedSlot.nextElementSibling).toBe(scrollEl);
});
});
4 changes: 2 additions & 2 deletions packages/angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,15 +592,15 @@ export declare interface IonCol extends Components.IonCol {}


@ProxyCmp({
inputs: ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
inputs: ['color', 'fixedSlotPlacement', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
methods: ['getScrollElement', 'scrollToTop', 'scrollToBottom', 'scrollByPoint', 'scrollToPoint']
})
@Component({
selector: 'ion-content',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
inputs: ['color', 'fixedSlotPlacement', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
})
export class IonContent {
protected el: HTMLElement;
Expand Down
4 changes: 2 additions & 2 deletions packages/angular/standalone/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,15 +659,15 @@ export declare interface IonCol extends Components.IonCol {}

@ProxyCmp({
defineCustomElementFn: defineIonContent,
inputs: ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
inputs: ['color', 'fixedSlotPlacement', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
methods: ['getScrollElement', 'scrollToTop', 'scrollToBottom', 'scrollByPoint', 'scrollToPoint']
})
@Component({
selector: 'ion-content',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['color', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
inputs: ['color', 'fixedSlotPlacement', 'forceOverscroll', 'fullscreen', 'scrollEvents', 'scrollX', 'scrollY'],
standalone: true
})
export class IonContent {
Expand Down
1 change: 1 addition & 0 deletions packages/vue/src/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ export const IonCol = /*@__PURE__*/ defineContainer<JSX.IonCol>('ion-col', defin
export const IonContent = /*@__PURE__*/ defineContainer<JSX.IonContent>('ion-content', defineIonContent, [
'color',
'fullscreen',
'fixedSlotPlacement',
'forceOverscroll',
'scrollX',
'scrollY',
Expand Down