Skip to content
Open
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
4 changes: 2 additions & 2 deletions core/src/components/back-button/back-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, h } from '@stencil/core';
import type { ButtonInterface } from '@utils/element-interface';
import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { inheritAriaAttributes, openURL } from '@utils/helpers';
import { createColorClasses, hostContext } from '@utils/theme';
import { arrowBackSharp, chevronBack } from 'ionicons/icons';

import { config } from '../../global/config';
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/breadcrumb/breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import dotsThreeRegular from '@phosphor-icons/core/assets/regular/dots-three.svg
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, h } from '@stencil/core';
import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { inheritAriaAttributes, openURL } from '@utils/helpers';
import { createColorClasses, hostContext } from '@utils/theme';
import { chevronForwardOutline, ellipsisHorizontal } from 'ionicons/icons';

import { config } from '../../global/config';
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, Watch, State, forceUpdate, h } from '@stencil/core';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes, hasShadowDom } from '@utils/helpers';
import { inheritAriaAttributes, hasShadowDom, openURL } from '@utils/helpers';
import { printIonWarning } from '@utils/logging';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { createColorClasses, hostContext } from '@utils/theme';

import { getIonTheme, getIonMode } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/card/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { ComponentInterface } from '@stencil/core';
import { Element, Component, Host, Prop, h } from '@stencil/core';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
import type { Attributes } from '@utils/helpers';
import { inheritAttributes } from '@utils/helpers';
import { createColorClasses, openURL } from '@utils/theme';
import { inheritAttributes, openURL } from '@utils/helpers';
import { createColorClasses } from '@utils/theme';

import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color, Theme } from '../../interface';
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/fab-button/fab-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import xRegular from '@phosphor-icons/core/assets/regular/x.svg';
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, h } from '@stencil/core';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
import { inheritAriaAttributes } from '@utils/helpers';
import { inheritAriaAttributes, openURL } from '@utils/helpers';
import type { Attributes } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { createColorClasses, hostContext } from '@utils/theme';
import { close } from 'ionicons/icons';

import { config } from '../../global/config';
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/item/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Listen, Prop, State, Watch, forceUpdate, h } from '@stencil/core';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
import type { Attributes } from '@utils/helpers';
import { inheritAttributes, raf } from '@utils/helpers';
import { createColorClasses, hostContext, openURL } from '@utils/theme';
import { inheritAttributes, raf, openURL } from '@utils/helpers';
import { createColorClasses, hostContext } from '@utils/theme';
import { chevronForward } from 'ionicons/icons';

import { config } from '../../global/config';
Expand Down
3 changes: 2 additions & 1 deletion core/src/components/router-link/router-link.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses, openURL } from '@utils/theme';
import { openURL } from '@utils/helpers';
import { createColorClasses } from '@utils/theme';

import { getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, Color } from '../../interface';
Expand Down
13 changes: 13 additions & 0 deletions core/src/global/ionic-global.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Build, getMode, setMode, getElement } from '@stencil/core';
import { printIonWarning } from '@utils/logging';
import { applyGlobalTheme } from '@utils/theme';

import type { IonicConfig, Mode, Theme } from '../interface';
import { defaultTheme as baseTheme } from '../themes/base/default.tokens';
import type { Theme as BaseTheme } from '../themes/base/default.tokens';
import { shouldUseCloseWatcher } from '../utils/hardware-back-button';
import { isPlatform, setupPlatforms } from '../utils/platform';

Expand Down Expand Up @@ -225,6 +228,16 @@ export const initialize = (userConfig: IonicConfig = {}) => {
doc.documentElement.setAttribute('theme', defaultTheme);
doc.documentElement.classList.add(defaultTheme);

const customTheme: BaseTheme | undefined = configObj.customTheme;

// Apply base theme, or combine with custom theme if provided
if (customTheme) {
const combinedTheme = applyGlobalTheme(baseTheme, customTheme);
config.set('customTheme', combinedTheme);
} else {
applyGlobalTheme(baseTheme);
}

if (config.getBoolean('_testing')) {
config.set('animated', false);
}
Expand Down
3 changes: 1 addition & 2 deletions core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ export { mdTransitionAnimation } from './utils/transition/md.transition';
export { getTimeGivenProgression } from './utils/animation/cubic-bezier';
export { createGesture } from './utils/gesture';
export { initialize } from './global/ionic-global';
export { componentOnReady } from './utils/helpers';
export { componentOnReady, openURL } from './utils/helpers';
export { LogLevel } from './utils/logging';
export { isPlatform, Platforms, PlatformConfig, getPlatforms } from './utils/platform';
export { IonicSafeString } from './utils/sanitization';
export { IonicConfig, getMode, setupConfig } from './utils/config';
export { openURL } from './utils/theme';
export {
LIFECYCLE_WILL_ENTER,
LIFECYCLE_DID_ENTER,
Expand Down
10 changes: 10 additions & 0 deletions core/src/themes/base/default.tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const defaultTheme = {
palette: {
light: {},
dark: {
enabled: 'system',
},
},
};

export type Theme = typeof defaultTheme;
3 changes: 3 additions & 0 deletions core/src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ export interface IonicConfig {
scrollAssist?: boolean;
hideCaretOnScroll?: boolean;

// Theme configs
customTheme?: any;

// INTERNAL configs
// TODO(FW-2832): types
persistConfig?: boolean;
Expand Down
25 changes: 24 additions & 1 deletion core/src/utils/helpers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inheritAriaAttributes } from './helpers';
import { deepMerge, inheritAriaAttributes } from './helpers';

describe('inheritAriaAttributes', () => {
it('should inherit aria attributes', () => {
Expand Down Expand Up @@ -40,3 +40,26 @@ describe('inheritAriaAttributes', () => {
});
});
});

describe('deepMerge', () => {
it('should merge objects', () => {
const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };
const result = deepMerge(target, source);
expect(result).toEqual({ a: 1, b: 3, c: 4 });
});

it('should merge objects when target is undefined', () => {
const target = undefined;
const source = { a: 1, b: 2 };
const result = deepMerge(target, source);
expect(result).toEqual({ a: 1, b: 2 });
});

it('should merge objects when source is undefined', () => {
const target = { a: 1, b: 2 };
const source = undefined;
const result = deepMerge(target, source);
expect(result).toEqual({ a: 1, b: 2 });
});
});
41 changes: 41 additions & 0 deletions core/src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { focusElements } from '@utils/focus-visible';
import { printIonError } from '@utils/logging';

import type { Side } from '../components/menu/menu-interface';
import type { RouterDirection } from '../components/router/utils/interface';
import { config } from '../global/config';
import type { AnimationBuilder } from '../interface';

// TODO(FW-2832): types

Expand Down Expand Up @@ -434,3 +436,42 @@ export const shallowEqualStringMap = (
export const isSafeNumber = (input: unknown): input is number => {
return typeof input === 'number' && !isNaN(input) && isFinite(input);
};

const SCHEME = /^[a-z][a-z0-9+\-.]*:/;

export const openURL = async (
url: string | undefined | null,
ev: Event | undefined | null,
direction: RouterDirection,
animation?: AnimationBuilder
): Promise<boolean> => {
if (url != null && url[0] !== '#' && !SCHEME.test(url)) {
const router = document.querySelector('ion-router');
if (router) {
if (ev != null) {
ev.preventDefault();
}
return router.push(url, direction, animation);
}
}
return false;
};

/**
* Deep merges two objects, with source properties overriding target properties
* @param target The target object to merge into
* @param source The source object to merge from
* @returns The merged object
*/
export const deepMerge = (target: any, source: any): any => {
const result = { ...target };

for (const key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
result[key] = deepMerge(result[key] ?? {}, source[key]);
} else {
result[key] = source[key];
}
}
return result;
};
Loading
Loading