Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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