Skip to content

Commit

Permalink
Describe theme API and fix theme applying instructions (#7102)
Browse files Browse the repository at this point in the history
* Describe theme API and fix theme applying instructions

* Trim whitespaces
  • Loading branch information
RomanTsukanov committed Oct 10, 2023
1 parent 7984103 commit 160ed62
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 40 deletions.
88 changes: 61 additions & 27 deletions docs/manage-default-themes-and-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SurveyJS Form Library is shipped with several predefined UI themes. You can see

![Themes in SurveyJS Form Library](images/survey-library-themes.png)

To use a theme, you need to reference a SurveyJS style sheet. Refer to the following sections of Get Started help topics for detailed instructions:
To use a theme, you need to reference a SurveyJS style sheet. Refer to the following sections of Get Started help topics for detailed instructions:

- [Configure Styles in Angular](https://surveyjs.io/form-library/documentation/get-started-angular#configure-styles)
- [Configure Styles in Vue](https://surveyjs.io/form-library/documentation/get-started-vue#configure-styles)
Expand All @@ -22,25 +22,73 @@ To use a theme, you need to reference a SurveyJS style sheet. Refer to the follo

## Apply a Predefined Theme

Predefined themes are distributed as JSON objects that specify CSS variables and other theme settings. You can find a full list of predefined themes and their variations on GitHub: [survey-core/themes](https://github.com/surveyjs/survey-library/tree/master/src/themes). To apply a predefined theme, import its module or reference its script _after_ `survey-core`. The following code shows how to apply the Layered Dark Panelless theme by importing a module:
Predefined themes are distributed as JSON objects that specify CSS variables and other theme settings. You can find a full list of predefined themes and their variations on GitHub: [survey-core/themes](https://github.com/surveyjs/survey-library/tree/master/src/themes).

To apply a predefined theme in modular applications, import the theme object from its module and pass the object to `SurveyModel`'s [`applyTheme(theme)`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#applyTheme) method. The following code shows how to apply the Layered Dark Panelless theme:

```js
import { Model } from "survey-core";
import "survey-core/themes/layered-dark-panelless";
/*
Don't forget to import or reference the Default V2 style sheet
as described in the Get Started with SurveyJS article for your framework
*/
import { LayeredDarkPanelless } "survey-core/themes/layered-dark-panelless";

const surveyJson = { ... };
const survey = new Model(surveyJson);
survey.applyTheme(LayeredDarkPanelless);
```

The code below applies the same theme by referencing a script:
In classic script applications, reference a theme script _after_ the `survey-core` script and style sheet. Pass the theme object to the `applyTheme(theme)` method, as shown below:

```html
<head>
<!-- ... -->
<link href="https://unpkg.com/survey-core/defaultV2.min.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/survey-core/survey.core.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/survey-core/layered-dark-panelless.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/survey-core/themes/layered-dark-panelless.min.js"></script>
<!-- ... -->
</head>
```

If you want to add more than one theme, refer to the [Switch Between Themes](#switch-between-themes) section for more information.
```js
const surveyJson = { ... };
const survey = new Survey.Model(surveyJson);
survey.applyTheme(SurveyTheme.LayeredDarkPanelless);
```

## Switch Between Themes

If you want to add more than one SurveyJS theme to your application, import them or reference their scripts and call `SurveyModel`'s [`applyTheme(theme)`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#applyTheme) method to specify an active theme. For example, the following code imports the Contrast Dark and Contrast Light themes and applies the latter:

```js
// In modular applications:
import { Model } from "survey-core";
import { ContrastDark } from "survey-core/themes/contrast-dark";
import { ContrastLight } from "survey-core/themes/contrast-light";

const surveyJson = { ... };
const survey = new Model(surveyJson);
survey.applyTheme(ContrastLight);
```

```html
<!-- In classic script applications: -->
<head>
<!-- ... -->
<link href="https://unpkg.com/survey-core/defaultV2.min.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/survey-core/survey.core.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/survey-core/themes/contrast-dark.min.js"></script>
<script type="text/javascript" src="https://unpkg.com/survey-core/themes/contrast-light.min.js"></script>
<!-- ... -->
</head>
```

```js
const surveyJson = { ... };
const survey = new Survey.Model(surveyJson);
survey.applyTheme(SurveyTheme.ContrastLight);
```

## Create a Custom Theme

Expand All @@ -52,37 +100,23 @@ Theme Editor is integrated into Survey Creator. Open our [all-in-one demo](/crea

<img src="images/theme-export.png" alt="SurveyJS Theme Export">

To apply your custom theme, pass the downloaded JSON object to `SurveyModel`'s `applyTheme()` method:
To apply your custom theme, pass the downloaded JSON object to `SurveyModel`'s [`applyTheme(theme)`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#applyTheme) method:

```js
import { Model } from "survey-core";
const surveyJson = { ... };
const survey = new Model(surveyJson);

survey.applyTheme({
"cssVariables": {
// ...
},
"themeName": "double",
"colorPalette": "dark",
"isPanelless": true
"cssVariables": {
// ...
},
"themeName": "doubleborder",
"colorPalette": "dark",
"isPanelless": true
});
```

## Switch Between Themes

If you want to add more than one SurveyJS theme to your application, import them using named imports and call `SurveyModel`'s `applyTheme()` method to specify an active theme. For example, the following code imports the Contrast Dark and Contrast Light themes and applies the latter:

```js
import { Model } from "survey-core";
import { ContrastLight } from "survey-core/themes/contrast-light";
import { ContrastDark } from "survey-core/themes/contrast-dark";

const surveyJson = { ... };
const survey = new Model(surveyJson);
survey.applyTheme(ContrastLight)
```

## Apply Custom CSS Classes

You can apply individual custom CSS classes to all survey elements of a specific type. To do this, define a JavaScript object in which keys specify survey elements and values specify CSS classes. For information on the object structure, refer to the following file on GitHub: [defaultV2Css.ts](https://github.com/surveyjs/survey-library/blob/master/src/defaultCss/defaultV2Css.ts#L13). Assign this object to [`SurveyModel`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model)'s `css` property.
Expand Down
16 changes: 9 additions & 7 deletions docs/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,18 +233,20 @@
"Title": "Panel Dynamic"
},
{
"Name": "settings",
"Title": "Global Settings"
"Name": "IAction",
"Title": "IAction"
},
{
"Name": "IAction",
"Title": "IAction",
"IsHidden": true
"Name": "ITheme",
"Title": "ITheme"
},
{
"Name": "ICustomQuestionTypeConfiguration",
"Title": "ICustomQuestionTypeConfiguration",
"IsHidden": true
"Title": "ICustomQuestionTypeConfiguration"
},
{
"Name": "settings",
"Title": "Global Settings"
}
]
}
Expand Down
23 changes: 17 additions & 6 deletions src/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ export class SurveyModel extends SurveyElementCore
private navigationBarValue: ActionContainer;

onThemeApplying: EventBase<SurveyModel> = new EventBase<SurveyModel>();
/**
* An event that is raised after a [theme](/form-library/documentation/manage-default-themes-and-styles) is [applied](#applyTheme) to the survey.
* @see applyTheme
*/
onThemeApplied: EventBase<SurveyModel> = new EventBase<SurveyModel>();

//#region Event declarations
Expand Down Expand Up @@ -3347,7 +3351,7 @@ export class SurveyModel extends SurveyElementCore
this.onCurrentPageChanged.fire(this, options);
}
private notifyQuestionsOnHidingContent(page: PageModel): void {
if(!page) return;
if (!page) return;
page.questions.forEach(q => q.onHidingContent());
}
private createPageChangeEventOptions(newValue: PageModel, oldValue: PageModel): any {
Expand Down Expand Up @@ -5690,7 +5694,7 @@ export class SurveyModel extends SurveyElementCore
}
}
private runQuestionsTriggers(name: string, value: any): void {
if(this.isDisplayMode || this.isDesignMode) return;
if (this.isDisplayMode || this.isDesignMode) return;
const questions = this.getAllQuestions();
questions.forEach(q => q.runTriggers(name, value));
}
Expand Down Expand Up @@ -7338,6 +7342,13 @@ export class SurveyModel extends SurveyElementCore
this.onPopupVisibleChanged.fire(this, { question, popup, visible });
}

/**
* Applies a specified theme to the survey.
*
* [Themes & Styles](/form-library/documentation/manage-default-themes-and-styles (linkStyle))
* @param theme An [`ITheme`](/form-library/documentation/api-reference/itheme) object with theme settings.
* @see onThemeApplied
*/
public applyTheme(theme: ITheme): void {
if (!theme) return;

Expand Down Expand Up @@ -7396,20 +7407,20 @@ export class SurveyModel extends SurveyElementCore
public addScrollEventListener(): void {
this.scrollHandler = () => { this.onScroll(); };
this.rootElement.addEventListener("scroll", this.scrollHandler);
if(!!this.rootElement.getElementsByTagName("form")[0]) {
if (!!this.rootElement.getElementsByTagName("form")[0]) {
this.rootElement.getElementsByTagName("form")[0].addEventListener("scroll", this.scrollHandler);
}
if(!!this.css.rootWrapper) {
if (!!this.css.rootWrapper) {
this.rootElement.getElementsByClassName(this.css.rootWrapper)[0]?.addEventListener("scroll", this.scrollHandler);
}
}
public removeScrollEventListener(): void {
if (!!this.rootElement && !!this.scrollHandler) {
this.rootElement.removeEventListener("scroll", this.scrollHandler);
if(!!this.rootElement.getElementsByTagName("form")[0]) {
if (!!this.rootElement.getElementsByTagName("form")[0]) {
this.rootElement.getElementsByTagName("form")[0].removeEventListener("scroll", this.scrollHandler);
}
if(!!this.css.rootWrapper) {
if (!!this.css.rootWrapper) {
this.rootElement.getElementsByClassName(this.css.rootWrapper)[0]?.removeEventListener("scroll", this.scrollHandler);
}
}
Expand Down
52 changes: 52 additions & 0 deletions src/themes.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,66 @@
export type ImageFit = "auto" | "contain" | "cover";
export type ImageAttachment = "fixed" | "scroll";

/**
* A theme configuration interface.
*
* `ITheme` objects are used to apply predefined themes or create custom themes. Refer to the following help topic for more information:
*
* [Themes & Styles](https://surveyjs.io/form-library/documentation/manage-default-themes-and-styles (linkStyle))
*/
export interface ITheme {
/**
* A theme name.
*/
themeName?: string;
/**
* A color palette.
*
* Possible values:
*
* - `"light"`
* - `"dark"`
*/
colorPalette?: string;
/**
* A Boolean value that specifies whether survey questions are displayed within panels (`false`) or without them (`true`).
*/
isPanelless?: boolean;
/**
* An image to display as survey background. This property accepts a hyperlink or a data URL.
*/
backgroundImage?: string;
/**
* A string value that specifies how to resize the [background image](#backgroundImage) to fit it into its container.
*
* Possible values:
*
* - `"auto"`
* - `"contain"`
* - `"cover"`
*
* Refer to the description of the [`background-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#values) CSS property values on MDN for detailed information on the possible values.
*/
backgroundImageFit?: ImageFit;
/**
* A string value that specifies whether the [background image](#backgroundImage) is fixed in its position or scrolled along with the survey.
*
* Possible values:
*
* - `"fixed"`
* - `"scroll"`
*/
backgroundImageAttachment?: ImageAttachment;
/**
* A value from 0 to 1 that specifies how transparent the [background image](#backgroundImage) should be: 0 makes the image completely transparent, and 1 makes it opaque.
*/
backgroundOpacity?: number;
/**
* An object with survey header settings.
*/
cover?: {[index: string]: any};
/**
* An object with CSS variables.
*/
cssVariables?: { [index: string]: string };
}

0 comments on commit 160ed62

Please sign in to comment.