|
1 |
| -# Example Widget [](https://github.com/semantic-release/semantic-release) |
| 1 | +# Example Emojis [](https://github.com/semantic-release/semantic-release) |
2 | 2 |
|
3 |
| -This example contains documentation and example code for creating widgets using React. |
| 3 | +This an example application with emojis! |
4 | 4 |
|
5 |
| -[View the demo](https://js-widgets.github.io/example-widget/index.html) |
6 |
| - |
7 |
| -## Requirements |
8 |
| - |
9 |
| -- [npm](https://www.npmjs.com/) 6.9.0 or higher |
10 |
| -- [create-react-app](https://www.npmjs.com/package/create-react-app) 3.0.1 or higher |
11 |
| - |
12 |
| -## Getting started |
13 |
| - |
14 |
| -1. On the [example-widget](https://github.com/js-widgets/example-widget) project page click the **"Use this template"** button to setup a new widget. |
15 |
| -2. Give the new repository a **name** and a **description** and then click the "**Create repository from template**" button. |
16 |
| -3. Clone the new repository and change the project [**name**](https://github.com/js-widgets/example-widget/blob/master/package.json#L2), [**version**](https://github.com/js-widgets/example-widget/blob/master/package.json#L3), and [**homepage**](https://github.com/js-widgets/example-widget/blob/master/package.json#L4) inside **package.json**. |
17 |
| -4. Change the name of the [widget render function](https://github.com/js-widgets/example-widget/blob/master/src/index.js#L35)(`renderExampleWidget`) in **src/index.js**. _Note: It is recommended to use something unique to the widget in order to avoid potential conflicts with other widgets, like the widget repository name._ |
18 |
| -5. Change the [**renderFunctionName**](https://github.com/js-widgets/example-widget/blob/master/src/public/index.html#L20) in the header of **public/index.html** to match the designated widget render function from the previous step (i.e. `renderExampleWidget`) |
19 |
| -6. Install the project dependencies using `npm install` |
20 |
| -7. Run the project locally using `npm start` |
21 |
| - |
22 |
| -**IMPORTANT:** Make sure you check the [widget development documentation](/widget-development.md) when developing your own. |
23 |
| - |
24 |
| -## `widget.json` |
25 |
| - |
26 |
| -There is a special file called `widget.json` in the root of the widget. Widget registries, [like this |
27 |
| -example](https://github.com/js-widgets/widget-registry-boilerplate), need this file to learn about |
28 |
| -this widget. It contains the following keys: |
29 |
| - |
30 |
| -| Name | Required | Example | Description | |
31 |
| -| ------------------------ | -------- | -------------------------------------- | ---------------------------------------------------------------------------------------------- | |
32 |
| -| shortcode | yes | product-catalog | The machine name identifier for the widget. | |
33 |
| -| description | no | A catalog of products for our company. | A longer description for the widget. This is shown in the widget catalog. | |
34 |
| -| availableTranslations | yes | `['en', 'es']` | Language codes this widget is available in for internationalization purposes. | |
35 |
| -| settingsSchema | no | | A JSON Schema object decribing the input parameters for the widgets at embed time. | |
36 |
| -| externalPeerDependencies | no | | List of runtime dependencies for this widget that embedders need to add along with the widget. | |
37 |
| -| status | yes | stable | One of `stable`, `beta`, `wip`, or `deprecated`. | |
38 |
| - |
39 |
| -### Configurable widgets |
40 |
| -Configuration parameters are specified during the embed process. Drupal will create a form element |
41 |
| -automatically to gather those parameters in the editorial screens. For the CMS to know what form |
42 |
| -element to use, the widget definition needs to include a [JSON Schema](https://json-schema.org) |
43 |
| -definition for every parameter. |
44 |
| - |
45 |
| -This repository contains an example of a configurable parameter. In this case it's the text of the |
46 |
| -button. This is [described in `widget.json`](https://github.com/js-widgets/example-widget/blob/master/widget.json#L20-L36) as: |
47 |
| - |
48 |
| -```json |
49 |
| - "settingsSchema": { |
50 |
| - "type": "object", |
51 |
| - "additionalProperties": false, |
52 |
| - "properties": { |
53 |
| - "fields": { |
54 |
| - "type": "object", |
55 |
| - "properties": { |
56 |
| - "button-text": { |
57 |
| - "type": "string", |
58 |
| - "title": "Button text", |
59 |
| - "description": "Some random string to be displayed when the widget is rendered.", |
60 |
| - "examples": ["I am a button", "Please, click me", "CLICK"] |
61 |
| - } |
62 |
| - } |
63 |
| - } |
64 |
| - } |
65 |
| - }, |
66 |
| -``` |
67 |
| - |
68 |
| -And then accessed in the [widget code `Widget.jsx`](https://github.com/js-widgets/example-widget/blob/master/src/components/Widget.jsx#L25): |
69 |
| - |
70 |
| -```jsx |
71 |
| -<p className="is-size-6 pb-4"> |
72 |
| - <button className="button is-primary">{element.getAttribute('data-button-text')}</button> |
73 |
| -</p> |
74 |
| -``` |
75 |
| - |
76 |
| -Note that since the field name is `button-text`, the value is accessed as `'data-button-text'`. |
77 |
| - |
78 |
| -### External dependencies |
79 |
| - |
80 |
| -`externalPeerDependencies` is a tool designed to share JS dependencies across different widgets. |
81 |
| -This module provides an example how to avoid bundling `react`, `react-dom`, and `react-intl` with |
82 |
| -the widget's JS, while making Drupal (or any other available integrations) load the dependencies |
83 |
| -automatically. |
84 |
| - |
85 |
| -For each dependency you will need to: |
86 |
| - |
87 |
| -1. [Tell Webpack to not include the library](https://github.com/js-widgets/example-widget/blob/master/craco.config.js#L32-L35) in the resulting JS file(s) for this widget. |
88 |
| -```js |
89 |
| - // webpack.config.js or craco.config.js |
90 |
| - externals: { |
91 |
| - react: 'React', |
92 |
| - 'react-dom': 'ReactDOM', |
93 |
| - 'react-intl': 'ReactIntl', |
94 |
| - }, |
95 |
| - // ... |
96 |
| -``` |
97 |
| -1. [Tell the widget registry (in `widget.json`)](https://github.com/js-widgets/example-widget/blob/master/widget.json#L37-L46), and ultimately the CMS integrations where to find these libraries that were excluded. |
98 |
| -```json |
99 |
| -"externalPeerDependencies": { |
100 |
| - "react": {"src": "https://unpkg.com/react@^17/umd/react.production.min.js"}, |
101 |
| - "react-dom": {"src": "https://unpkg.com/react-dom@^17/umd/react-dom.production.min.js"}, |
102 |
| - "react-intl": {"src": "https://unpkg.com/react-intl-bundle@^1/dist/react-intl.production.min.js"} |
103 |
| -}, |
104 |
| -``` |
105 |
| - |
106 |
| -### Continuous Integration |
107 |
| - |
108 |
| -Testing and deployment scripts available inside this example repository using [GitHub Actions](https://github.com/features/actions). |
109 |
| - |
110 |
| -## Usage |
111 |
| - |
112 |
| -_Note: Changes made to the **src/public/index.html** file are for development and preview purposes only and will not be compiled into the production version of the widget._ |
113 |
| - |
114 |
| -Widgets are referenced in the header of the page and rendered using an orchestrator script. The `document.loadWidget` and `document.loadWidgets` functions allow rendering of multiple widgets, and multiple instances of a single widget. |
115 |
| - |
116 |
| -### loader.js |
117 |
| - |
118 |
| -Within the `<head>` tag reference the widget load callback(renderFunctionName) and tell it which div(instanceId) to render the widget in. |
119 |
| - |
120 |
| -Projects embedding widgets should include the [loader script](https://js-widgets.github.io/widget-registry-boilerplate/widget-registry/production/loader.js) maintained in the Widget Registry. Include the script in the HTML as: |
121 |
| - |
122 |
| -```html |
123 |
| -<script |
124 |
| - src="//js-widgets.github.io/widget-registry-boilerplate/widget-registry/production/loader.js" |
125 |
| - type="application/javascript" |
126 |
| -></script> |
127 |
| -``` |
128 |
| - |
129 |
| -- [See an example](https://github.com/js-widgets/example-widget/blob/master/src/public/index.html#L12) of the loader script implementation. |
130 |
| - |
131 |
| -Remember to use your version of the widget registry instead of `widget-registry-boilerplate`. |
132 |
| - |
133 |
| -#### `document.loadWidget()` |
134 |
| - |
135 |
| -```js |
136 |
| -document.loadWidget({ |
137 |
| - renderFunctionName: 'renderExampleWidget', |
138 |
| - instanceId: 'example-widget-1', |
139 |
| - language: 'de', |
140 |
| - onRenderFinish: (renderedElement) => { |
141 |
| - alert('Render process finished.'); |
142 |
| - }, |
143 |
| -}); |
144 |
| -``` |
145 |
| - |
146 |
| -- [See an example](https://github.com/js-widgets/example-widget/blob/master/src/public/index.html#L14) of the `loadWidget()` function. |
147 |
| - |
148 |
| -Within the `<body>` tag add the instanceId div wherever you want this widget to render. |
149 |
| - |
150 |
| -```html |
151 |
| -<div id="example-widget-1" data-button-text="foobar"></div> |
152 |
| -``` |
153 |
| - |
154 |
| -- [See an example](https://github.com/js-widgets/example-widget/blob/master/src/public/index.html#L79) of the widget placement implementation. |
155 |
| - |
156 |
| -#### `document.loadWidgets()` |
157 |
| - |
158 |
| -```js |
159 |
| -document.loadWidgets({ |
160 |
| - 'widget-1': { |
161 |
| - renderFunctionName: 'renderExampleWidget', |
162 |
| - instanceId: 'example-widget-1', |
163 |
| - }, |
164 |
| - 'widget-2': { |
165 |
| - renderFunctionName: 'renderExampleWidget', |
166 |
| - instanceId: 'example-widget-2', |
167 |
| - }, |
168 |
| -}); |
169 |
| -``` |
170 |
| - |
171 |
| -```html |
172 |
| -<div id="example-widget-1" data-button-text="foo"></div> |
173 |
| -<div id="example-widget-2" data-button-text="bar"></div> |
174 |
| -``` |
175 |
| - |
176 |
| -#### Parameters |
177 |
| - |
178 |
| -| Name | Required | Default | Example | Description | |
179 |
| -| ------------------ | -------- | ------------------------ | ----------------------- | ------------------------------------------------------------------------- | |
180 |
| -| renderFunctionName | yes | | `renderExampleWidget` | The render function callback. | |
181 |
| -| instanceId | yes | | `example-widget-1` | The already present HTML element ID where the react app will be rendered. | |
182 |
| -| language | no | en | de | The language code for internationalization purposes. | |
183 |
| -| origin | no | `window.location.origin` | https://www.example.org | Protocol and hostname where a JSONAPI endpoint is available. | |
184 |
| -| onRenderFinish | no | | | A callback that executes after the widget has been rendered. | |
185 |
| - |
186 |
| -### Attributes |
187 |
| - |
188 |
| -Data attributes of the instanceId div are accessible from the `<App />` React component using the `getAttribute()` method. |
189 |
| - |
190 |
| -```jsx |
191 |
| -import React, { Component } from 'react'; |
192 |
| - |
193 |
| -class Widget extends Component { |
194 |
| - render() { |
195 |
| - return <div className="App">{this.props.obj.getAttribute('data-button-text')}</div>; |
196 |
| - } |
197 |
| -} |
198 |
| - |
199 |
| -export default Widget; |
200 |
| -``` |
201 |
| - |
202 |
| -- [See an example](https://github.com/js-widgets/example-widget/blob/master/src/components/Widget.js#L25) of the `getAttribute()` method. |
203 |
| - |
204 |
| -#### DIV attributes |
205 |
| - |
206 |
| -```html |
207 |
| -<div id="example-widget-1" data-button-text="Hello world!"></div> |
208 |
| -``` |
209 |
| - |
210 |
| -- [See an example](https://github.com/js-widgets/example-widget/blob/master/src/public/index.html#L79) of the widget attribute implementation. |
211 |
| - |
212 |
| -#### Query string values |
213 |
| - |
214 |
| -``` |
215 |
| -http://localhost:3000/?data-button-text=Hello%20world! |
216 |
| -``` |
217 |
| - |
218 |
| -Note: DIV attributes are the preferred method and will always take precedence over the use of query |
219 |
| -string values. Query string values are a good way to test a widget quickly without having to alter |
220 |
| -the HTML source code. |
221 |
| - |
222 |
| -### Translations |
223 |
| - |
224 |
| -The boilerplate widget has built-in translation support using the **react-intl** module. Use the `FormattedMessage` to create translatable strings within the widget. |
225 |
| - |
226 |
| -```jsx |
227 |
| -<FormattedMessage id="App.welcomeMsg" defaultMessage="Welcome!" /> |
228 |
| -``` |
229 |
| - |
230 |
| -- [See an example](https://github.com/js-widgets/example-widget/blob/master/src/components/Widget.js#L15) of the `FormattedMessage` component. |
231 |
| - |
232 |
| -Create all translation messages in `src/messages.js`, following the provided example. Generate locales using the `npm run build:locales` command. This will scan `src/messages.js` for translatable strings and compile them into JSON files for translation under **src/locales/\*.json**. |
233 |
| - |
234 |
| -#### Supported Languages |
235 |
| - |
236 |
| -| Language | Code | |
237 |
| -| ---------------------- | ----- | |
238 |
| -| Arabic | ar | |
239 |
| -| German | de | |
240 |
| -| English | en | |
241 |
| -| Spanish | es | |
242 |
| -| Latin American Spanish | esla | |
243 |
| -| French | fr | |
244 |
| -| Italian | it | |
245 |
| -| Japanese | ja | |
246 |
| -| Korean | ko | |
247 |
| -| Polish | pl | |
248 |
| -| Portuguese | pt | |
249 |
| -| Russian | ru | |
250 |
| -| Turkish | tr | |
251 |
| -| Simplified Chinese | zh-cn | |
252 |
| -| Traditional Chinese | zh-tw | |
253 |
| - |
254 |
| -### Typescript |
255 |
| - |
256 |
| -In an effort to improve overall code quality and reduce run-time exceptions, we strongly encourage widget developers to use [Typescript](typescriptlang.org). We understand, though, that using Typescript can be challenging if you don't have prior experience with it and we don't want to impose that restriction upon you. |
257 |
| - |
258 |
| -If you feel comfortable with Typescript or are willing to learn about it ([here](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html) and [here](https://fettblog.eu/typescript-react/) are good resources), you can run `npm run use-typescript`, which will install all the libraries you'll need, update file extensions, and make appropriate configuration changes. |
259 |
| - |
260 |
| -### Styling |
261 |
| - |
262 |
| -In order to scope widget styles to the widget without adversely affecting the styles of the page within which it's embedded, we're using a library called [craco](https://github.com/gsoft-inc/craco). This library allows us to override configuration in apps bootstrapped with Create React App, which is otherwise a closed system. By using this method, we can make alterations to confuration without needing to eject the app. This along with a PostCSS plugin called [postcss-wrap](https://github.com/ruslansavenok/postcss-wrap) allows us to define a CSS class that will be prepended to all CSS selectors, effectively namespacing all styles. |
263 |
| - |
264 |
| -_Uncomment the style rule specified in `index.css` and start the app to see the prepended class from `postcss.config.js` added._ **Remember to define your custom namespace class in `postcss.config.js` and add it to the top-most element in the app, as seen in `Widget.jsx`. If you need to use this method, please remove the `index.css` file and where it's imported in `index.js`.** |
265 |
| - |
266 |
| -It is recommended to rely on the above method strictly for usage of installable component libraries. For custom styling, we recommend installing [Emotion](https://emotion.sh/), which is a library for writing CSS-in-JS. |
267 |
| - |
268 |
| -### Testing |
269 |
| - |
270 |
| -This boilerplate is setup to use [Jest](https://jestjs.io/) and [@testing-library/react](https://testing-library.com/docs/react-testing-library/intro) for testing. See `Widget.test.js` for an example of how to use these libraries. |
| 5 | +[View the demo](https://js-widgets.github.io/example-emojis/index.html) |
271 | 6 |
|
272 | 7 | ## Current Maintainer(s)
|
273 | 8 |
|
274 | 9 | - Mateu Aguiló Bosch ([e0ipso](https://github.com/e0ipso))
|
275 |
| -- Hunter MacDermut ([huntermacd](https://github.com/huntermacd)) |
0 commit comments