feat: initial Astro integration
Co-authored-by: Oleksii Kadurin <ovkadurin@gmail.com>; Thijs Louisse <Thijs.Louisse@ing.com>
This commit is contained in:
parent
4c077fbf1d
commit
70b0241189
83 changed files with 16385 additions and 17774 deletions
|
|
@ -4,9 +4,6 @@ bundlesize/
|
|||
.history/
|
||||
storybook-static/
|
||||
*.d.ts
|
||||
_site-dev
|
||||
_site
|
||||
docs/_merged_*
|
||||
patches/
|
||||
|
||||
/docs/_assets/scoped-custom-element-registry.min.js
|
||||
|
|
|
|||
22
.gitignore
vendored
22
.gitignore
vendored
|
|
@ -1,6 +1,15 @@
|
|||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
.astro
|
||||
|
||||
# generated __mdjs-stories.js files
|
||||
public/docs
|
||||
|
||||
## editors
|
||||
/.idea
|
||||
## disable this line one commit before changing contents that should be shared
|
||||
/.vscode
|
||||
/*.code-workspace
|
||||
/.history
|
||||
|
|
@ -44,17 +53,8 @@ local.log
|
|||
## browserstack
|
||||
browserstack.err
|
||||
|
||||
## Rocket ignore files (need to be the full relative path to the folders)
|
||||
docs/_merged_data/
|
||||
docs/_merged_assets/
|
||||
docs/_merged_includes/
|
||||
docs/**/api-table.md
|
||||
|
||||
debug.log
|
||||
|
||||
_site
|
||||
_site-dev
|
||||
|
||||
## generated test fiels
|
||||
__output
|
||||
.wireit
|
||||
|
|
@ -63,4 +63,4 @@ __output
|
|||
packages/ui/new-exports/
|
||||
packages/ui/test-exports/
|
||||
|
||||
|
||||
src/content/docs
|
||||
|
|
|
|||
|
|
@ -11,5 +11,8 @@
|
|||
"no-trailing-punctuation": {
|
||||
"punctuation": ".,;。,;:!"
|
||||
},
|
||||
"ol-prefix": false
|
||||
"ol-prefix": false,
|
||||
"MD025": {
|
||||
"front_matter_title": ""
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
coverage/
|
||||
CHANGELOG.md
|
||||
bundlesize/
|
||||
_site
|
||||
_site-dev
|
||||
.history
|
||||
|
||||
/docs/_assets/scoped-custom-element-registry.min.js
|
||||
|
|
|
|||
50
README.md
50
README.md
|
|
@ -26,33 +26,59 @@
|
|||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lion.js.org">Website</a>
|
||||
<a href="https://lion-web.netlify.app">Website</a>
|
||||
·
|
||||
<a href="https://lion.js.org/fundamentals/">Fundamentals</a>
|
||||
<a href="https://lion-web.netlify.app/fundamentals/">Fundamentals</a>
|
||||
·
|
||||
<a href="https://lion.js.org/guides/">Guides</a>
|
||||
<a href="https://lion-web.netlify.app/guides/">Guides</a>
|
||||
·
|
||||
<a href="https://lion.js.org/components/">Components</a>
|
||||
<a href="https://lion-web.netlify.app/components/">Components</a>
|
||||
·
|
||||
<a href="https://lion.js.org/blog/">Blog</a>
|
||||
<a href="https://lion-web.netlify.app/blog/">Blog</a>
|
||||
</p>
|
||||
|
||||
**Lion is a set of highly performant, accessible, and flexible Web Components.**
|
||||
**Lion is a set of highly performant, accessible and flexible Web Components.!**
|
||||
|
||||
They provide an unopinionated, white-label layer that can be extended to your own layer of components.
|
||||
|
||||
- **High Performance:** Focused on great performance in all relevant browsers with a minimal number of dependencies.
|
||||
- **Accessibility:** Aimed at compliance with the WCAG 2.2 AA standard to create components that are accessible for everybody.
|
||||
- **Flexibility:** Provides solutions through Web Components and JavaScript classes which can be used, adopted and extended to fit all needs.
|
||||
- **Modern Code:** Lion is distributed as pure ES modules.
|
||||
- **Exposes functions/classes and Web Components:** Ships a functionality in its most appropriate form.
|
||||
- **Modern Code:** Lion is distributes as pure es modules.
|
||||
- **Exposes functions/classes and Web Components:** Ships a functionality in it's most appropriate form.
|
||||
|
||||
> Note: Our demo examples might look simple and not very stylish. This is on purpose. They are designed to be basic so you can easily add your own styles to them to match your intended design, without dealing with styles that are already there.
|
||||
> Note: Our demos may look a little bland but that is on purpose. They only come with functional stylings.
|
||||
> This makes sense as the main use case is to extend those components and if you do you do not want to override existing stylings.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://lion.js.org/guides/"><strong>Explore the Lion Guides ▶</strong></a>
|
||||
<a href="https://lion-web.netlify.app/guides/"><strong>Explore the Lion Guides ▶</strong></a>
|
||||
</p>
|
||||
|
||||
## Astro migration
|
||||
|
||||
- Keep using `/docs` on the root level as we used it in the `master` branch. The documentation is copied into Astro related directories on `npm run start` and when when anything in `/docs` is updated.
|
||||
- Replace manually all references to assets in all `md` files so that we imply that the path is produced from the directory where the md file is located. F.e. `new URL('../src/wa-combobox/assets/obama.jpeg', import.meta.url).href;` should `new URL('./src/wa-combobox/assets/obama.jpeg', import.meta.url).href;`. Note double dot is replaced with one dot. See [this PR](https://github.com/ing-bank/lion/pull/2125/files#diff-403b1e0ab54d51dcfe54248e847498e492da00383d8b33a4087994ab9035a22c) for the reference.
|
||||
- Rename all `*.mjs` files to `*.js` ones if they are used by `mdjs` examples
|
||||
|
||||
### Astro how to
|
||||
|
||||
- To start in dev mode run `nmm run start`
|
||||
- To start in production mode:
|
||||
- Run `npm run build`
|
||||
- Run `npm run preview`
|
||||
|
||||
### Issues which are not caused by the migration (not to be fixed now)
|
||||
|
||||
- There is a browser console error on [collapsible page](http://localhost:4321/components/collapsible):
|
||||
|
||||
```
|
||||
__mdjs-stories--use-cases.js:40 Uncaught TypeError: shadowRoot.getElementById is not a function
|
||||
```
|
||||
|
||||
Note. There is the same error on master. This issue is not caused by the migration
|
||||
|
||||
### TODO
|
||||
|
||||
## How to install
|
||||
|
||||
```bash
|
||||
|
|
@ -113,7 +139,7 @@ You can also use the lion elements directly, although this is likely not a commo
|
|||
|
||||
## Issues
|
||||
|
||||
If you encounter an issue with any of the packages we are offering please open a [new bug issue](https://github.com/ing-bank/lion/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a description of the expected and the current behavior - additionally adding a [reproduction](https://webcomponents.dev/edit/kpZmz1CJN580OaXsk56f?pm=1) always helps.
|
||||
If you encounter an issue with any of the packages we are offering please open a [new bug issue](https://github.com/ing-bank/lion/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a description of the expected and the current behavior - additional adding a [reproduction](https://webcomponents.dev/edit/kpZmz1CJN580OaXsk56f?pm=1) always helps.
|
||||
|
||||
## Feature requests
|
||||
|
||||
|
|
@ -158,7 +184,7 @@ This means you only have to apply your own Design System: by delivering styles,
|
|||
|
||||
## Coding guidelines
|
||||
|
||||
Check out our [coding guidelines](https://lion.js.org/guides/principles/definitions-and-terms/) for more detailed information.
|
||||
Check out our [coding guidelines](https://lion-web.netlify.app/guides/principles/definitions-and-terms/) for more detailed information.
|
||||
|
||||
## How to contribute
|
||||
|
||||
|
|
|
|||
53
astro.config.mjs
Normal file
53
astro.config.mjs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import lit from "@astrojs/lit";
|
||||
import { mdjsParse, mdjsStoryParse, mdjsSetupCode } from '@mdjs/core';
|
||||
import { copyMdjsStories } from './src/utils/remark-plugings/copyMdjsStories/index.js';
|
||||
import { cleanupRocketMetadata } from './src/utils/remark-plugings/cleanupRocketMetadata/index.js';
|
||||
import { updateMainTagsForMdjsStories } from './src/utils/remark-plugings/updateMainTagsForMdjsStories/index.js';
|
||||
|
||||
const mdjsSetupConfig = {
|
||||
simulationSettings: {
|
||||
simulatorUrl: '/simulator/',
|
||||
languages: [
|
||||
{ key: 'de-DE', name: 'German' },
|
||||
{ key: 'en-GB', name: 'English (United Kingdom)' },
|
||||
{ key: 'en-US', name: 'English (United States)' },
|
||||
{ key: 'nl-NL', name: 'Dutch' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [lit()],
|
||||
markdown: {
|
||||
remarkPlugins: [updateMainTagsForMdjsStories, mdjsParse, mdjsStoryParse, [mdjsSetupCode, mdjsSetupConfig], copyMdjsStories, cleanupRocketMetadata],
|
||||
},
|
||||
vite: {
|
||||
// the fix is copied from https://github.com/withastro/astro/issues/5517#issuecomment-1337328843.
|
||||
// This allows to import rocket-preset-extend-lion-docs. The following error pops up otherwise:
|
||||
// ```
|
||||
// [ERROR] Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
|
||||
// node_modules/rocket-preset-extend-lion-docs/src/getPublicApiOfPkg.js:6:0:
|
||||
// 6 │ await init;
|
||||
// ```
|
||||
optimizeDeps: {
|
||||
exclude: ['rocket-preset-extend-lion-docs']
|
||||
},
|
||||
// Fix taken from https://github.com/vitejs/vite/issues/6985#issuecomment-1044375490.
|
||||
// It throws an error otherwise:
|
||||
// ```
|
||||
// astro-poc2/node_modules/vite/dist/node/chunks/dep-df561101.js:43799
|
||||
// const err = new Error('The server is being restarted or closed. Request is outdated');
|
||||
// ```
|
||||
// Note, if this erorr is still present, as a workaround try adding 'esnext' to node_modules/vite/dist/node/constants.js -> ESBUILD_MODULES_TARGET
|
||||
// build: {
|
||||
// target: 'esnext'
|
||||
// },
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: /^lit/
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
10
config.mjs
Normal file
10
config.mjs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export const maxDepthForNonComponentsNavigation = 2;
|
||||
export const docsDirName = '/docs/';
|
||||
export const isToBeConcatenated = (path) => {
|
||||
if (path.includes('/components/')) {
|
||||
return true;
|
||||
}
|
||||
const pathAfterDocs = path.split(docsDirName)[1];
|
||||
const numberOfSections = pathAfterDocs.split('/').length;
|
||||
return numberOfSections > maxDepthForNonComponentsNavigation;
|
||||
}
|
||||
|
|
@ -1,20 +1,8 @@
|
|||
---
|
||||
parts:
|
||||
- Button
|
||||
- Extensions
|
||||
title: 'Button: Extensions'
|
||||
eleventyNavigation:
|
||||
key: 'Button: Extensions'
|
||||
order: 90
|
||||
parent: Button
|
||||
title: Extensions
|
||||
---
|
||||
|
||||
# Button: Extensions
|
||||
# Button >> Extensions ||90
|
||||
|
||||
```js script
|
||||
import { html } from '@mdjs/mdjs-preview';
|
||||
import './extensions/bootstrap-button.mjs';
|
||||
import './extensions/bootstrap-button.js';
|
||||
```
|
||||
|
||||
## Bootstrap button
|
||||
|
|
|
|||
|
|
@ -1,13 +1,3 @@
|
|||
---
|
||||
parts:
|
||||
- Button
|
||||
title: Button
|
||||
eleventyNavigation:
|
||||
key: Button
|
||||
order: 10
|
||||
title: Button
|
||||
---
|
||||
|
||||
# Button
|
||||
# Button ||10
|
||||
|
||||
-> go to Overview
|
||||
|
|
|
|||
|
|
@ -1,16 +1,4 @@
|
|||
---
|
||||
parts:
|
||||
- Button
|
||||
- Overview
|
||||
title: 'Button: Overview'
|
||||
eleventyNavigation:
|
||||
key: 'Button: Overview'
|
||||
order: 10
|
||||
parent: Button
|
||||
title: Overview
|
||||
---
|
||||
|
||||
# Button: Overview
|
||||
# Button >> Overview ||10
|
||||
|
||||
A button web component that is easily stylable and accessible.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,4 @@
|
|||
---
|
||||
parts:
|
||||
- Button
|
||||
- Use Cases
|
||||
title: 'Button: Use Cases'
|
||||
eleventyNavigation:
|
||||
key: 'Button: Use Cases'
|
||||
order: 20
|
||||
parent: Button
|
||||
title: Use Cases
|
||||
---
|
||||
|
||||
# Button: Use Cases
|
||||
# Button >> Use Cases ||20
|
||||
|
||||
```js script
|
||||
import { html } from '@mdjs/mdjs-preview';
|
||||
|
|
@ -40,8 +28,7 @@ export const disabled = () => html`<lion-button disabled>Disabled</lion-button>`
|
|||
The minimum click area needs to be at least `44px` by `44px` according to [WCAG Success Criterion 2.5.5 Target Size (Enhanced)](https://www.w3.org/TR/WCAG22/#target-size-enhanced).
|
||||
|
||||
```js preview-story
|
||||
export const minimumClickArea = () =>
|
||||
html` <style>
|
||||
export const minimumClickArea = () => html` <style>
|
||||
.small {
|
||||
padding: 4px;
|
||||
line-height: 1em;
|
||||
|
|
@ -74,10 +61,10 @@ export const withinForm = () => html`
|
|||
<input id="firstNameId" name="firstName" />
|
||||
<label for="lastNameId">Last name</label>
|
||||
<input id="lastNameId" name="lastName" />
|
||||
<lion-button-submit @click="${ev => console.log('click submit handler', ev.target)}"
|
||||
<lion-button-submit @click=${ev => console.log('click submit handler', ev.target)}
|
||||
>Submit</lion-button-submit
|
||||
>
|
||||
<lion-button-reset @click="${ev => console.log('click reset handler', ev.target)}"
|
||||
<lion-button-reset @click=${ev => console.log('click reset handler', ev.target)}
|
||||
>Reset</lion-button-reset
|
||||
>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -59,11 +59,11 @@ export const Github = () => html`
|
|||
|
||||
```js preview-story
|
||||
export const Whatsapp = () => {
|
||||
const obamaImgUrl = new URL('../src/wa-combobox/assets/obama.jpeg', import.meta.url).href;
|
||||
const trumpImgUrl = new URL('../src/wa-combobox/assets/trump.jpeg', import.meta.url).href;
|
||||
const bidenImgUrl = new URL('../src/wa-combobox/assets/biden.jpeg', import.meta.url).href;
|
||||
const bushImgUrl = new URL('../src/wa-combobox/assets/bush.jpeg', import.meta.url).href;
|
||||
const clintonImgUrl = new URL('../src/wa-combobox/assets/clinton.jpeg', import.meta.url).href;
|
||||
const obamaImgUrl = new URL('./src/wa-combobox/assets/obama.jpeg', import.meta.url).href;
|
||||
const trumpImgUrl = new URL('./src/wa-combobox/assets/trump.jpeg', import.meta.url).href;
|
||||
const bidenImgUrl = new URL('./src/wa-combobox/assets/biden.jpeg', import.meta.url).href;
|
||||
const bushImgUrl = new URL('./src/wa-combobox/assets/bush.jpeg', import.meta.url).href;
|
||||
const clintonImgUrl = new URL('./src/wa-combobox/assets/clinton.jpeg', import.meta.url).href;
|
||||
|
||||
return html`
|
||||
<wa-combobox name="combo" label="Filter chats">
|
||||
|
|
|
|||
|
|
@ -20,19 +20,6 @@ import './assets/iconset-misc.js';
|
|||
import * as spaceSet from './assets/iconset-space.js';
|
||||
|
||||
import '@lion/ui/define/lion-icon.js';
|
||||
|
||||
icons.addIconResolver('lion', (iconset, name) => {
|
||||
switch (iconset) {
|
||||
case 'bugs':
|
||||
return import('./assets/iconset-bugs.js').then(module => module[name]);
|
||||
case 'space':
|
||||
return import('./assets/iconset-space.js').then(module => module[name]);
|
||||
case 'misc':
|
||||
return import('./assets/iconset-misc.js').then(module => module[name]);
|
||||
default:
|
||||
throw new Error(`Unknown iconset ${iconset}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Icon sets
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { html, LitElement, css } from 'lit';
|
||||
import { ref, createRef } from 'lit/directives/ref.js';
|
||||
import { OverlayMixin } from '@lion/ui/overlays.js';
|
||||
import './demo-el-using-overlaymixin.mjs';
|
||||
import './demo-el-using-overlaymixin.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('@lion/ui/types/overlays.js').OverlayConfig} OverlayConfig
|
||||
|
|
|
|||
|
|
@ -1,23 +1,10 @@
|
|||
---
|
||||
parts:
|
||||
- Configuration
|
||||
- Overlays
|
||||
- Systems
|
||||
title: 'Overlays: Configuration'
|
||||
eleventyNavigation:
|
||||
key: Systems >> Overlays >> Configuration
|
||||
title: Configuration
|
||||
order: 40
|
||||
parent: Systems >> Overlays
|
||||
---
|
||||
|
||||
# Systems >> Overlays >> Configuration ||40
|
||||
|
||||
```js script
|
||||
import { html } from '@mdjs/mdjs-preview';
|
||||
import './assets/demo-el-using-overlaymixin.mjs';
|
||||
import './assets/applyDemoOverlayStyles.mjs';
|
||||
import { withDropdownConfig, withModalDialogConfig, withTooltipConfig } from '@lion/ui/overlays.js';
|
||||
import './assets/demo-el-using-overlaymixin.js';
|
||||
import './assets/applyDemoOverlayStyles.js';
|
||||
import { withDropdownConfig, withTooltipConfig } from '@lion/ui/overlays.js';
|
||||
```
|
||||
|
||||
The `OverlayController` has many configuration options.
|
||||
|
|
@ -42,13 +29,13 @@ export const placementLocal = () => {
|
|||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
<demo-el-using-overlaymixin .config="${placementModeLocalConfig}">
|
||||
<demo-el-using-overlaymixin .config=${placementModeLocalConfig}>
|
||||
<button slot="invoker">Click me to open the local overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -64,13 +51,13 @@ export const placementLocal = () => {
|
|||
export const placementGlobal = () => {
|
||||
const placementModeGlobalConfig = { placementMode: 'global' };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${placementModeGlobalConfig}">
|
||||
<demo-el-using-overlaymixin .config=${placementModeGlobalConfig}>
|
||||
<button slot="invoker">Click me to open the global overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -80,36 +67,6 @@ export const placementGlobal = () => {
|
|||
};
|
||||
```
|
||||
|
||||
## isAlertDialog
|
||||
|
||||
In some cases the dialog should act like an [alertdialog](https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/examples/alertdialog/), which is a combination of an alert and dialog. If that is the case, you can add `is-alert-dialog` attribute, which sets the correct role on the dialog.
|
||||
|
||||
```js preview-story
|
||||
export const alertDialog = () => {
|
||||
const placementModeGlobalConfig = { ...withModalDialogConfig(), isAlertDialog: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${placementModeGlobalConfig}">
|
||||
<button slot="invoker">Click me to open the alert dialog!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Are you sure you want to perform this action?
|
||||
<button
|
||||
type="button"
|
||||
@click="${ev => ev.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="${ev => ev.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</demo-el-using-overlaymixin>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
## isTooltip (placementMode: 'local')
|
||||
|
||||
As specified in the [overlay rationale](./rationale.md) there are only two official types of overlays: dialogs and tooltips. And their main differences are:
|
||||
|
|
@ -125,7 +82,7 @@ export const usingTooltipConfig = () => {
|
|||
const tooltipConfig = { ...withTooltipConfig() };
|
||||
|
||||
return html`
|
||||
<demo-el-using-overlaymixin id="tooltip" .config="${tooltipConfig}">
|
||||
<demo-el-using-overlaymixin id="tooltip" .config=${tooltipConfig}>
|
||||
<button slot="invoker">Hover me to open the tooltip!</button>
|
||||
<div slot="content" class="demo-overlay">Hello!</div>
|
||||
</demo-el-using-overlaymixin>
|
||||
|
|
@ -146,7 +103,7 @@ You use the feature on any type of overlay.
|
|||
export const trapsKeyboardFocus = () => {
|
||||
const trapsKeyboardFocusConfig = { ...withDropdownConfig(), trapsKeyboardFocus: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${trapsKeyboardFocusConfig}">
|
||||
<demo-el-using-overlaymixin .config=${trapsKeyboardFocusConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
<div><a href="#">A focusable anchor</a></div>
|
||||
|
|
@ -154,7 +111,7 @@ export const trapsKeyboardFocus = () => {
|
|||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -172,39 +129,13 @@ Boolean property. Will allow closing the overlay on ESC key when enabled.
|
|||
export const hidesOnEsc = () => {
|
||||
const hidesOnEscConfig = { ...withDropdownConfig(), hidesOnEsc: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${hidesOnEscConfig}">
|
||||
<demo-el-using-overlaymixin .config=${hidesOnEscConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
</div>
|
||||
</demo-el-using-overlaymixin>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
And how it works if `hidesOnEsc` is disabled. In most cases `hidesOnOutsideEsc` needs also to be set to `false`.
|
||||
|
||||
```js preview-story
|
||||
export const hidesOnEscFalse = () => {
|
||||
const hidesOnEscConfig = {
|
||||
...withModalDialogConfig(),
|
||||
hidesOnEsc: false,
|
||||
hidesOnOutsideEsc: false,
|
||||
};
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${hidesOnEscConfig}">
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -222,13 +153,13 @@ Boolean property. When enabled allows closing the overlay on ESC key, even when
|
|||
export const hidesOnOutsideEsc = () => {
|
||||
const hidesOnEscConfig = { ...withDropdownConfig(), hidesOnOutsideEsc: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${hidesOnEscConfig}">
|
||||
<demo-el-using-overlaymixin .config=${hidesOnEscConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -246,14 +177,14 @@ Boolean property. Will allow closing the overlay by clicking outside the `conten
|
|||
export const hidesOnOutsideClick = () => {
|
||||
const hidesOnOutsideClickConfig = { ...withDropdownConfig(), hidesOnOutsideClick: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${hidesOnOutsideClickConfig}">
|
||||
<demo-el-using-overlaymixin .config=${hidesOnOutsideClickConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
<label for="myInput">Clicking this label should not trigger close</label>
|
||||
<input id="myInput" />
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -276,13 +207,13 @@ export const elementToFocusAfterHide = () => {
|
|||
|
||||
const elementToFocusAfterHideConfig = { ...withDropdownConfig(), elementToFocusAfterHide: btn };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${elementToFocusAfterHideConfig}">
|
||||
<demo-el-using-overlaymixin .config=${elementToFocusAfterHideConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -312,13 +243,13 @@ This currently only supports CSS Animations, because it relies on the `animation
|
|||
export const hasBackdrop = () => {
|
||||
const hasBackdropConfig = { ...withDropdownConfig(), hasBackdrop: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${hasBackdropConfig}">
|
||||
<demo-el-using-overlaymixin .config=${hasBackdropConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -342,19 +273,19 @@ export const isBlocking = () => {
|
|||
This overlay gets closed when overlay B gets opened
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
</div>
|
||||
</demo-el-using-overlaymixin>
|
||||
<demo-el-using-overlaymixin .config="${isBlockingConfig}">
|
||||
<demo-el-using-overlaymixin .config=${isBlockingConfig}>
|
||||
<button slot="invoker">Overlay B: open second</button>
|
||||
<div slot="content" class="demo-overlay demo-overlay--blocking">
|
||||
Overlay A is hidden... now close me and see overlay A again.
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -375,13 +306,13 @@ Boolean property. When true, prevents scrolling content that is outside of the `
|
|||
export const preventsScroll = () => {
|
||||
const preventsScrollConfig = { preventsScroll: true };
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${preventsScrollConfig}">
|
||||
<demo-el-using-overlaymixin .config=${preventsScrollConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -414,13 +345,13 @@ export const viewportConfig = () => {
|
|||
viewportConfig: { placement: 'bottom-left' },
|
||||
};
|
||||
return html`
|
||||
<demo-el-using-overlaymixin .config="${viewportConfig}">
|
||||
<demo-el-using-overlaymixin .config=${viewportConfig}>
|
||||
<button slot="invoker">Click me to open the overlay in the bottom left corner!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
@ -494,13 +425,13 @@ export const popperConfig = () => {
|
|||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
<demo-el-using-overlaymixin .config="${popperConfig}">
|
||||
<demo-el-using-overlaymixin .config=${popperConfig}>
|
||||
<button slot="invoker">Click me to open the overlay!</button>
|
||||
<div slot="content" class="demo-overlay">
|
||||
Hello! You can close this notification here:
|
||||
<button
|
||||
class="close-button"
|
||||
@click="${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}"
|
||||
@click=${e => e.target.dispatchEvent(new Event('close-overlay', { bubbles: true }))}
|
||||
>
|
||||
⨯
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ import {
|
|||
withModalDialogConfig,
|
||||
} from '@lion/ui/overlays.js';
|
||||
|
||||
import './assets/demo-el-using-overlaymixin.mjs';
|
||||
import './assets/demo-overlay-backdrop.mjs';
|
||||
import './assets/applyDemoOverlayStyles.mjs';
|
||||
import './assets/demo-el-using-overlaymixin.js';
|
||||
import './assets/demo-overlay-backdrop.js';
|
||||
import './assets/applyDemoOverlayStyles.js';
|
||||
import { ref, createRef } from 'lit/directives/ref.js';
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ const cacheOptions = {
|
|||
maxAge: TEN_MINUTES,
|
||||
};
|
||||
|
||||
const [cacheRequestInterceptor, cacheResponseInterceptor] = createCacheInterceptors(
|
||||
const { cacheRequestInterceptor, cacheResponseInterceptor } = createCacheInterceptors(
|
||||
getCacheIdentifier,
|
||||
cacheOptions,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ const cacheOptions = {
|
|||
maxAge: TEN_MINUTES,
|
||||
};
|
||||
|
||||
const [cacheRequestInterceptor, cacheResponseInterceptor] = createCacheInterceptors(
|
||||
const { cacheRequestInterceptor, cacheResponseInterceptor } = createCacheInterceptors(
|
||||
getCacheIdentifier,
|
||||
cacheOptions,
|
||||
);
|
||||
|
|
@ -204,7 +204,7 @@ const globalCacheOptions = {
|
|||
// for instance when a current user is logged out
|
||||
const getCacheIdentifier = () => getActiveProfile().profileId;
|
||||
|
||||
const [cacheRequestInterceptor, cacheResponseInterceptor] = createCacheInterceptors(
|
||||
const { cacheRequestInterceptor, cacheResponseInterceptor } = createCacheInterceptors(
|
||||
getCacheIdentifier,
|
||||
globalCacheOptions,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,3 @@
|
|||
---
|
||||
parts:
|
||||
- Helpers
|
||||
- Tools
|
||||
title: 'Tools: Helpers'
|
||||
eleventyNavigation:
|
||||
key: Tools >> Helpers
|
||||
title: Helpers
|
||||
order: 0
|
||||
parent: Tools
|
||||
---
|
||||
|
||||
# Tools >> Helpers
|
||||
# Tools >> Helpers ||5
|
||||
|
||||
-> go to Overview
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { LitElement, css, html } from 'lit';
|
||||
|
||||
import 'page-a/page-a.js';
|
||||
import 'page-b/page-b.js';
|
||||
import 'page-c/page-c.js';
|
||||
import 'page-d/page-d.js';
|
||||
|
||||
class DemoApp extends LitElement {
|
||||
constructor() {
|
||||
|
|
@ -85,9 +85,9 @@ class DemoApp extends LitElement {
|
|||
Page B
|
||||
</button>
|
||||
</nav>
|
||||
${this.page === 'A' ? html` <page-a></page-a> ` : html` <page-b></page-b> `}
|
||||
${this.page === 'A' ? html` <page-c></page-c> ` : html` <page-d></page-d> `}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-app', DemoApp);
|
||||
customElements.define('demo-app-fail', DemoApp);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ In this SPA (Single Page Application) demo you will be able to reproduce the iss
|
|||
|
||||
In an real application this would now mean that your users can no longer interact with your application.
|
||||
|
||||
<demo-app>Loading App...</demo-app>
|
||||
<demo-app-fail>Loading App...</demo-app-fail>
|
||||
|
||||
<div id="overlay-target" style="margin-top: 50px;"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "page-a",
|
||||
"name": "page-c",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"overlays": "^1.0.0"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { LitElement, html, css } from 'lit-element';
|
||||
import { overlays } from 'overlays/instance.js';
|
||||
|
||||
export class PageA extends LitElement {
|
||||
export class PageC extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
|
|
@ -31,4 +31,4 @@ export class PageA extends LitElement {
|
|||
}
|
||||
}
|
||||
|
||||
customElements.define('page-a', PageA);
|
||||
customElements.define('page-c', PageC);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "page-b",
|
||||
"name": "page-d",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"overlays": "^2.0.0"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { LitElement, html, css } from 'lit-element';
|
||||
import { overlays } from 'overlays/instance.js';
|
||||
|
||||
export class PageB extends LitElement {
|
||||
export class PageD extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
|
|
@ -31,4 +31,4 @@ export class PageB extends LitElement {
|
|||
}
|
||||
}
|
||||
|
||||
customElements.define('page-b', PageB);
|
||||
customElements.define('page-d', PageD);
|
||||
|
|
@ -2,8 +2,8 @@ import { LitElement, css, html } from 'lit';
|
|||
|
||||
import './overlayCompatibility.js';
|
||||
|
||||
import 'page-a/page-a.js';
|
||||
import 'page-b/page-b.js';
|
||||
import 'page-e/page-e.js';
|
||||
import 'page-f/page-f.js';
|
||||
|
||||
class DemoApp extends LitElement {
|
||||
constructor() {
|
||||
|
|
@ -87,9 +87,9 @@ class DemoApp extends LitElement {
|
|||
Page B
|
||||
</button>
|
||||
</nav>
|
||||
${this.page === 'A' ? html` <page-a></page-a> ` : html` <page-b></page-b> `}
|
||||
${this.page === 'A' ? html` <page-e></page-e> ` : html` <page-f></page-f> `}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-app', DemoApp);
|
||||
customElements.define('demo-app-success', DemoApp);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ In this SPA (Single Page Application) demo you will be able to reproduce the sol
|
|||
|
||||
With this solutions users can not break the app anymore.
|
||||
|
||||
<demo-app>Loading App...</demo-app>
|
||||
<demo-app-success>Loading App...</demo-app-success>
|
||||
|
||||
<div id="overlay-target" style="margin-top: 50px;"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "page-a",
|
||||
"name": "page-e",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"overlays": "^1.0.0"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { LitElement, html, css } from 'lit-element';
|
||||
import { overlays } from 'overlays/instance.js';
|
||||
|
||||
export class PageA extends LitElement {
|
||||
export class PageE extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
|
|
@ -30,5 +30,4 @@ export class PageA extends LitElement {
|
|||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('page-a', PageA);
|
||||
customElements.define('page-e', PageE);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "page-b",
|
||||
"name": "page-f",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"overlays": "^2.0.0"
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { LitElement, html, css } from 'lit-element';
|
||||
import { overlays } from 'overlays/instance.js';
|
||||
|
||||
export class PageB extends LitElement {
|
||||
export class PageF extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
|
|
@ -31,4 +31,4 @@ export class PageB extends LitElement {
|
|||
}
|
||||
}
|
||||
|
||||
customElements.define('page-b', PageB);
|
||||
customElements.define('page-f', PageF);
|
||||
|
|
@ -1,15 +1,3 @@
|
|||
---
|
||||
parts:
|
||||
- Singleton Manager
|
||||
- Tools
|
||||
title: 'Tools: Singleton Manager'
|
||||
eleventyNavigation:
|
||||
key: Tools >> Singleton Manager
|
||||
title: Singleton Manager
|
||||
order: 20
|
||||
parent: Tools
|
||||
---
|
||||
|
||||
# Tools >> Singleton Manager ||20
|
||||
# Tools >> Singleton Manager ||30
|
||||
|
||||
-> go to Overview
|
||||
|
|
|
|||
31659
package-lock.json
generated
31659
package-lock.json
generated
File diff suppressed because it is too large
Load diff
214
package.json
214
package.json
|
|
@ -3,14 +3,18 @@
|
|||
"name": "@lion/root",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rocket build",
|
||||
"build": "export PROD=true && npm run build-docs && npx astro build && node -e 'require(\"./src/utils/post-build-dist/post-build-dist.js\").postBuildDist()'",
|
||||
"build-docs": "npm run clean && node -e 'require(\"./src/utils/copy-docs\").copyDocs()' && node -e 'require(\"./src/utils/copy-docs\").processImports()'",
|
||||
"build-docs:watch": "node -e 'require(\"./src/utils/copy-docs\").watch()'",
|
||||
"bundlesize": "rollup -c bundlesize/rollup.config.js && bundlesize",
|
||||
"changeset": "changeset",
|
||||
"custom-elements-manifest": "npm run custom-elements-manifest --workspaces --if-present && node ./scripts/create-api-tables.mjs",
|
||||
"clean": "rm -rf ./public/docs && rm -rf ./src/content/docs && rm -rf ./dist",
|
||||
"clean:full": "npm run clean && rm -rf ./node_modules",
|
||||
"custom-elements-manifest": "npm run custom-elements-manifest --workspaces --if-present",
|
||||
"debug": "web-test-runner --watch --config web-test-runner-chrome.config.mjs",
|
||||
"debug:firefox": "web-test-runner --watch --config web-test-runner-firefox.config.mjs",
|
||||
"debug:no-scoped-registries-polyfill": "npm run debug -- --no-scoped-registries-polyfill",
|
||||
"debug:webkit": "web-test-runner --watch --config web-test-runner-webkit.config.mjs",
|
||||
"dev": "astro dev",
|
||||
"format": "npm run format:eslint && npm run format:prettier",
|
||||
"format:eslint": "eslint --ext .js,.html . --fix",
|
||||
"format:prettier": "prettier \"**/*.{js,md}\" \"packages/*/package.json\" \"package.json\" --write",
|
||||
|
|
@ -22,79 +26,101 @@
|
|||
"lint:types": "npm run types",
|
||||
"lint:versions": "node ./scripts/lint-versions.js",
|
||||
"prepare": "husky install",
|
||||
"preview": "astro preview",
|
||||
"release": "changeset publish",
|
||||
"repo:clean-slate": "git clean -dfX",
|
||||
"repo:diff-package-lock": "npx diff-package-lock",
|
||||
"start": "rocket start",
|
||||
"rm-all-node_modules": "npm exec --workspaces -- npx rimraf node_modules && npx rimraf node_modules",
|
||||
"start": "npm run build-docs && npm run watch & astro dev",
|
||||
"start:prod": "npm run preview",
|
||||
"test": "run-p test:browser test:node",
|
||||
"test:browser": "web-test-runner --coverage",
|
||||
"test:browserstack": "web-test-runner --config ./web-test-runner-browserstack.config.js",
|
||||
"test:node": "npm run test:node --workspaces --if-present",
|
||||
"test:screenshots": "npx rimraf screenshots/.diff/ && npx rimraf screenshots/.current/ && mocha --require scripts/screenshots/bootstrap.js --exit --timeout 10000 \"packages/**/test/*.screenshots-test.js\"",
|
||||
"test:screenshots": "rimraf screenshots/.diff/ && rimraf screenshots/.current/ && mocha --require scripts/screenshots/bootstrap.js --exit --timeout 10000 \"packages/**/test/*.screenshots-test.js\"",
|
||||
"test:screenshots:update": "cross-env UPDATE_SCREENSHOTS=true npm run test:screenshots",
|
||||
"types": "npm run types --workspaces --if-present",
|
||||
"types-check-only": "npm run types-check-only --workspaces --if-present"
|
||||
"types-check-only": "npm run types-check-only --workspaces --if-present",
|
||||
"watch": "npm-watch"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"packages-node/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@astrojs/lit": "^3.0.2",
|
||||
"@mdjs/core": "^0.20.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.0",
|
||||
"@rollup/plugin-node-resolve": "^13.0.6",
|
||||
"astro": "^3.3.1",
|
||||
"astro-seo": "^0.8.0",
|
||||
"changeset": "^0.2.6",
|
||||
"find-node-modules": "^2.1.3",
|
||||
"image-extensions": "^1.1.0",
|
||||
"npm-watch": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.8",
|
||||
"@babel/core": "^7.10.1",
|
||||
"@bundled-es-modules/fetch-mock": "^6.5.2",
|
||||
"@changesets/cli": "^2.27.9",
|
||||
"@custom-elements-manifest/analyzer": "^0.10.3",
|
||||
"@custom-elements-manifest/to-markdown": "^0.1.0",
|
||||
"@lit-labs/testing": "^0.2.5",
|
||||
"@lit/reactive-element": "^2.1.0",
|
||||
"@open-wc/building-rollup": "^2.2.3",
|
||||
"@open-wc/eslint-config": "^12.0.3",
|
||||
"@open-wc/scoped-elements": "^3.0.5",
|
||||
"@open-wc/testing": "^4.0.0",
|
||||
"@open-wc/testing-helpers": "^3.0.1",
|
||||
"@rocket/blog": "0.4.0",
|
||||
"@rocket/cli": "^0.10.2",
|
||||
"@rocket/launch": "^0.6.0",
|
||||
"@rocket/search": "^0.5.1",
|
||||
"@thepassle/module-graph": "^0.11.0",
|
||||
"@types/autosize": "^4.0.3",
|
||||
"@types/chai-as-promised": "^8.0.1",
|
||||
"@types/chai-dom": "^1.11.3",
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"@types/glob": "^8.1.0",
|
||||
"@types/mocha": "^10.0.9",
|
||||
"@web/dev-server-legacy": "^2.1.1",
|
||||
"@web/test-runner": "^0.19.0",
|
||||
"@web/test-runner-browserstack": "^0.7.2",
|
||||
"@web/test-runner-commands": "^0.9.0",
|
||||
"@web/test-runner-playwright": "^0.11.0",
|
||||
"@webcomponents/scoped-custom-element-registry": "^0.0.10",
|
||||
"@changesets/cli": "^2.26.1",
|
||||
"@custom-elements-manifest/analyzer": "^0.5.7",
|
||||
"@open-wc/building-rollup": "^1.2.1",
|
||||
"@open-wc/eslint-config": "^7.0.0",
|
||||
"@open-wc/testing": "^3.1.2",
|
||||
"@open-wc/testing-helpers": "^2.1.2",
|
||||
"@types/chai-as-promised": "^7.1.5",
|
||||
"@types/chai-dom": "^0.0.8",
|
||||
"@types/convert-source-map": "^1.5.1",
|
||||
"@types/fs-extra": "^9.0.7",
|
||||
"@types/glob": "^7.1.3",
|
||||
"@types/istanbul-reports": "^3.0.0",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/prettier": "^2.2.1",
|
||||
"@web/dev-server": "^0.1.8",
|
||||
"@web/dev-server-legacy": "^0.1.7",
|
||||
"@web/test-runner": "^0.13.7",
|
||||
"@web/test-runner-browserstack": "^0.5.0",
|
||||
"@web/test-runner-commands": "^0.6.1",
|
||||
"@web/test-runner-playwright": "^0.8.8",
|
||||
"@webcomponents/scoped-custom-element-registry": "^0.0.5",
|
||||
"@yarnpkg/lockfile": "^1.1.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"bundlesize": "^1.0.0-beta.2",
|
||||
"cem-plugin-vs-code-custom-data-generator": "^1.4.2",
|
||||
"chai": "^4.5.0",
|
||||
"chai-as-promised": "^8.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-wc": "^2.2.0",
|
||||
"globby": "^14.0.2",
|
||||
"gray-matter": "^4.0.3",
|
||||
"husky": "^9.1.6",
|
||||
"lint-staged": "^15.2.10",
|
||||
"looks-same": "^9.0.1",
|
||||
"markdownlint-cli": "^0.42.0",
|
||||
"mocha": "^10.7.3",
|
||||
"cem-plugin-vs-code-custom-data-generator": "^1.4.1",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chalk": "^4.1.0",
|
||||
"concurrently": "^5.2.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"es6-promisify": "^6.1.1",
|
||||
"eslint": "^8.26.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-lit": "^1.6.1",
|
||||
"eslint-plugin-lit-a11y": "^2.2.0",
|
||||
"eslint-plugin-wc": "^1.3.2",
|
||||
"globby": "^13.1.2",
|
||||
"husky": "^6.0.0",
|
||||
"lint-staged": "^10.0.0",
|
||||
"looks-same": "^7.2.3",
|
||||
"markdownlint-cli": "^0.17.0",
|
||||
"mermaid": "^9.3.0",
|
||||
"mkdirp-promise": "^5.0.1",
|
||||
"mocha": "^10.1.0",
|
||||
"mock-fs": "^5.1.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"patch-package": "^8.0.0",
|
||||
"nyc": "^15.0.0",
|
||||
"playwright": "^1.20.0",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-package-json": "^2.8.0",
|
||||
"remark-html": "^13.0.2",
|
||||
"semver": "^7.6.3",
|
||||
"sinon": "^19.0.2",
|
||||
"typescript": "^4.9.5",
|
||||
"wireit": "^0.14.12"
|
||||
"prettier": "^2.0.5",
|
||||
"prettier-package-json": "^2.1.3",
|
||||
"remark-html": "^13.0.1",
|
||||
"rimraf": "^2.6.3",
|
||||
"rollup": "^2.0.0",
|
||||
"semver": "^7.5.2",
|
||||
"sinon": "^7.2.2",
|
||||
"ssl-root-cas": "^1.3.1",
|
||||
"typescript": "~4.8.4",
|
||||
"whatwg-fetch": "^3.0.0",
|
||||
"wireit": "^0.7.2"
|
||||
},
|
||||
"bundlesize": [
|
||||
{
|
||||
|
|
@ -102,71 +128,23 @@
|
|||
"maxSize": "20 kB"
|
||||
}
|
||||
],
|
||||
"comments": {
|
||||
"overrides": {
|
||||
"//": [
|
||||
"For best compatibility, we sometimes need to override a package version depended upon by multiple packages."
|
||||
],
|
||||
"sharp": [
|
||||
"Version of 'sharp' package we get via '@rocket/cli' is too old to be built on a Mac.",
|
||||
"But updating package '@rocket-cli' causes our portal to break. Reason unknown.",
|
||||
"So, we override the sharp version in here until '@rocket-cli' can be updated."
|
||||
]
|
||||
},
|
||||
"olderVersions": {
|
||||
"//": [
|
||||
"Our aim is to keep all depencies up-to-date(for maintainability, performance and security).",
|
||||
"We use [npm-outdated](https://marketplace.visualstudio.com/items?itemName=mskelton.npm-outdated) as a helper for this.",
|
||||
"Sometimes we can't bc/o incompatibility issues."
|
||||
],
|
||||
"eslint": [
|
||||
"Can't be updated yet to 9.x, because of eslint-plugin-import"
|
||||
],
|
||||
"typescript": [
|
||||
"Since changes in types can be reflected in the code, we want to keep this stable for a longer period of time.",
|
||||
"As semver is not followed, we keep our major versions aligned with a minot of TS (hence '~' instead of '^' is used)"
|
||||
],
|
||||
"remark-html": [
|
||||
"Can't be updated to 14.x, because remark-html is still in commonjs."
|
||||
],
|
||||
"@rocket/*": [
|
||||
"Pinned, as newer versions require a complete overhaul of docs. Later we will move to astro."
|
||||
],
|
||||
"looks-same": [
|
||||
"Part of ./scripts/screenshots, which is not incorporated atm in automated test suite. TODO: re-evaluate solution and whether visual regression testing needs to be part of this repo"
|
||||
],
|
||||
"@open-wc/building-rollup": [
|
||||
"Can't be updated to 3.x, as v2 seems to be better compatible with rocket setup"
|
||||
],
|
||||
"chai": [
|
||||
"Can't be updated to 5.x, because @web/dev-server-core test-helpers (having implicit dep on chai) is not compatible with chai >= 5.x"
|
||||
]
|
||||
},
|
||||
"toBeRemoved": {
|
||||
"//": [
|
||||
"For maintainability, performance and security, we want to keep the number of dependencies as low as possible (in case functionality can be achieved via existing dependencies or platform functionality)."
|
||||
],
|
||||
"@bundled-es-modules/fetch-mock": [
|
||||
"Can be achieved via sinon as well"
|
||||
],
|
||||
"publish-docs/fs-extra | @types/fs-extra": [
|
||||
"Copy can be achieved via node's fs module"
|
||||
],
|
||||
"@web/dev-server-legacy": [
|
||||
"Only needed for browserstack config. Can be achieved via @web/dev-server"
|
||||
],
|
||||
"@lit/reactive-element": [
|
||||
"We make sure latest version is hoisted and resolved, until we move to astro (when we can regenerate the package-lock.json file w/o breaking Rocket)."
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"sharp": "^0.29.x"
|
||||
"sharp": "^0.31.x"
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"arrowParens": "avoid",
|
||||
"trailingComma": "all"
|
||||
},
|
||||
"watch": {
|
||||
"build-docs:watch": {
|
||||
"patterns": [
|
||||
"docs"
|
||||
],
|
||||
"extensions": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
patches/@astrojs+markdown-remark+3.3.0.patch
Normal file
27
patches/@astrojs+markdown-remark+3.3.0.patch
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
diff --git a/node_modules/@astrojs/markdown-remark/dist/rehype-collect-headings.js b/node_modules/@astrojs/markdown-remark/dist/rehype-collect-headings.js
|
||||
index 2f1ee5d..6865631 100644
|
||||
--- a/node_modules/@astrojs/markdown-remark/dist/rehype-collect-headings.js
|
||||
+++ b/node_modules/@astrojs/markdown-remark/dist/rehype-collect-headings.js
|
||||
@@ -1,10 +1,13 @@
|
||||
import Slugger from "github-slugger";
|
||||
import { visit } from "unist-util-visit";
|
||||
+import * as path from 'path';
|
||||
import { InvalidAstroDataError, safelyGetAstroData } from "./frontmatter-injection.js";
|
||||
const rawNodeTypes = /* @__PURE__ */ new Set(["text", "raw", "mdxTextExpression"]);
|
||||
const codeTagNames = /* @__PURE__ */ new Set(["code", "pre"]);
|
||||
function rehypeHeadingIds() {
|
||||
return function(tree, file) {
|
||||
+ const fileName = file.history[0];
|
||||
+ const parentDirectoryName = path.basename(path.dirname(fileName));
|
||||
const headings = [];
|
||||
const slugger = new Slugger();
|
||||
const isMDX = isMDXFile(file);
|
||||
@@ -52,7 +55,7 @@ function rehypeHeadingIds() {
|
||||
let slug = slugger.slug(text);
|
||||
if (slug.endsWith("-"))
|
||||
slug = slug.slice(0, -1);
|
||||
- node.properties.id = slug;
|
||||
+ node.properties.id = `${parentDirectoryName}-${slug}`;
|
||||
}
|
||||
headings.push({ depth, slug: node.properties.id, text });
|
||||
});
|
||||
275
patches/@mdjs+core+0.20.0.patch
Normal file
275
patches/@mdjs+core+0.20.0.patch
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
diff --git a/node_modules/@mdjs/core/src/mdjsParse.js b/node_modules/@mdjs/core/src/mdjsParse.js
|
||||
index 730e32a..5d6f3f5 100644
|
||||
--- a/node_modules/@mdjs/core/src/mdjsParse.js
|
||||
+++ b/node_modules/@mdjs/core/src/mdjsParse.js
|
||||
@@ -5,13 +5,12 @@ import { remove } from 'unist-util-remove';
|
||||
/** @typedef {import('unist').Node} Node */
|
||||
|
||||
export function mdjsParse() {
|
||||
- let jsCode = '';
|
||||
-
|
||||
/**
|
||||
* @param {Node} tree
|
||||
* @param {VFileOptions} file
|
||||
*/
|
||||
function transformer(tree, file) {
|
||||
+ let jsCode = '';
|
||||
visit(
|
||||
tree,
|
||||
'code',
|
||||
diff --git a/node_modules/@mdjs/core/src/mdjsSetupCode.js b/node_modules/@mdjs/core/src/mdjsSetupCode.js
|
||||
index 02a7c56..db3e466 100644
|
||||
--- a/node_modules/@mdjs/core/src/mdjsSetupCode.js
|
||||
+++ b/node_modules/@mdjs/core/src/mdjsSetupCode.js
|
||||
@@ -76,10 +76,6 @@ export function mdjsSetupCode({
|
||||
` Object.assign(storyEl, ${JSON.stringify(simulationSettings)});`,
|
||||
' }',
|
||||
`};`,
|
||||
- 'if (needsMdjsElements) {',
|
||||
- ` if (!customElements.get('mdjs-preview')) { import('@mdjs/mdjs-preview/define'); }`,
|
||||
- ` if (!customElements.get('mdjs-story')) { import('@mdjs/mdjs-story/define'); }`,
|
||||
- '}',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
diff --git a/node_modules/@mdjs/core/src/mdjsStoryParse.js b/node_modules/@mdjs/core/src/mdjsStoryParse.js
|
||||
index fe734a3..3ddd3a1 100644
|
||||
--- a/node_modules/@mdjs/core/src/mdjsStoryParse.js
|
||||
+++ b/node_modules/@mdjs/core/src/mdjsStoryParse.js
|
||||
@@ -54,132 +54,130 @@ export function mdjsStoryParse({
|
||||
storyTag = defaultStoryTag,
|
||||
previewStoryTag = defaultPreviewStoryTag,
|
||||
} = {}) {
|
||||
- /** @type {Story[]} */
|
||||
- const stories = [];
|
||||
- let htmlIndex = 0;
|
||||
-
|
||||
- /* eslint-disable no-param-reassign */
|
||||
-
|
||||
/**
|
||||
- * @param {UnistNode} _node
|
||||
- * @param {number} index
|
||||
- * @param {UnistParent} parent
|
||||
+ * @param {Node} tree
|
||||
+ * @param {VFileOptions} file
|
||||
*/
|
||||
- const nodeCodeVisitor = (_node, index, parent) => {
|
||||
- let node = /** @type {UnistNode & {[key: string]: unknown}} */ (_node);
|
||||
- if (node.lang === 'js' && node.meta === 'story' && typeof node.value === 'string') {
|
||||
- const storyData = extractStoryData(node.value);
|
||||
- node.type = 'html';
|
||||
- node.value = storyTag(storyData.name);
|
||||
- stories.push(storyData);
|
||||
- }
|
||||
- if (node.lang === 'js' && node.meta === 'preview-story' && typeof node.value === 'string') {
|
||||
- const storyData = extractStoryData(node.value);
|
||||
- const newValue = previewStoryTag(storyData.name);
|
||||
- if (newValue.includes('[[CODE SLOT]]')) {
|
||||
- const tagParts = newValue.split('[[CODE SLOT]]');
|
||||
-
|
||||
- const inside = [node];
|
||||
- let skipAmount = 1;
|
||||
+ async function transformer(tree, file) {
|
||||
+ /** @type {Story[]} */
|
||||
+ const stories = [];
|
||||
+ let htmlIndex = 0;
|
||||
+
|
||||
+ /**
|
||||
+ * @param {UnistNode} _node
|
||||
+ * @param {number} index
|
||||
+ * @param {UnistParent} parent
|
||||
+ */
|
||||
+ const nodeCodeVisitor = (_node, index, parent) => {
|
||||
+ let node = /** @type {UnistNode & {[key: string]: unknown}} */ (_node);
|
||||
+ if (node.lang === 'js' && node.meta === 'story' && typeof node.value === 'string') {
|
||||
+ const storyData = extractStoryData(node.value);
|
||||
+ node.type = 'html';
|
||||
+ node.value = storyTag(storyData.name);
|
||||
+ stories.push(storyData);
|
||||
+ }
|
||||
+ if (node.lang === 'js' && node.meta === 'preview-story' && typeof node.value === 'string') {
|
||||
+ const storyData = extractStoryData(node.value);
|
||||
+ const newValue = previewStoryTag(storyData.name);
|
||||
+ if (newValue.includes('[[CODE SLOT]]')) {
|
||||
+ const tagParts = newValue.split('[[CODE SLOT]]');
|
||||
|
||||
- const next = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
- parent.children[index + 1]
|
||||
- );
|
||||
- if (next && next.type === 'code' && next.meta === 'story-code') {
|
||||
- inside.push(next);
|
||||
- skipAmount += 1;
|
||||
+ const inside = [node];
|
||||
+ let skipAmount = 1;
|
||||
|
||||
- const next2 = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
- parent.children[index + 2]
|
||||
+ const next = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
+ parent.children[index + 1]
|
||||
);
|
||||
- if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
||||
- inside.push(next2);
|
||||
+ if (next && next.type === 'code' && next.meta === 'story-code') {
|
||||
+ inside.push(next);
|
||||
skipAmount += 1;
|
||||
+
|
||||
+ const next2 = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
+ parent.children[index + 2]
|
||||
+ );
|
||||
+ if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
||||
+ inside.push(next2);
|
||||
+ skipAmount += 1;
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ node = {
|
||||
+ type: 'root',
|
||||
+ children: [
|
||||
+ { type: 'html', value: tagParts[0] },
|
||||
+ { type: 'text', value: '\n\n' },
|
||||
+ ...inside,
|
||||
+ { type: 'text', value: '\n\n' },
|
||||
+ { type: 'html', value: tagParts[1] },
|
||||
+ ],
|
||||
+ };
|
||||
+ parent.children.splice(index, skipAmount, node);
|
||||
+ } else {
|
||||
+ node.type = 'html';
|
||||
+ node.value = previewStoryTag(storyData.name);
|
||||
}
|
||||
|
||||
- node = {
|
||||
- type: 'root',
|
||||
- children: [
|
||||
- { type: 'html', value: tagParts[0] },
|
||||
- { type: 'text', value: '\n\n' },
|
||||
- ...inside,
|
||||
- { type: 'text', value: '\n\n' },
|
||||
- { type: 'html', value: tagParts[1] },
|
||||
- ],
|
||||
- };
|
||||
- parent.children.splice(index, skipAmount, node);
|
||||
- } else {
|
||||
- node.type = 'html';
|
||||
- node.value = previewStoryTag(storyData.name);
|
||||
+ stories.push(storyData);
|
||||
}
|
||||
|
||||
- stories.push(storyData);
|
||||
- }
|
||||
-
|
||||
- if (node.lang === 'html' && node.meta === 'story') {
|
||||
- const storyData = extractStoryData(
|
||||
- `export const HtmlStory${htmlIndex} = () => html\`${node.value}\`;`,
|
||||
- { type: 'html' },
|
||||
- );
|
||||
- node.type = 'html';
|
||||
- node.value = storyTag(storyData.name);
|
||||
- stories.push(storyData);
|
||||
- htmlIndex += 1;
|
||||
- }
|
||||
- if (node.lang === 'html' && node.meta === 'preview-story') {
|
||||
- const storyData = extractStoryData(
|
||||
- `export const HtmlStory${htmlIndex} = () => html\`${node.value}\`;`,
|
||||
- { type: 'html' },
|
||||
- );
|
||||
-
|
||||
- const newValue = previewStoryTag(storyData.name);
|
||||
- if (newValue.includes('[[CODE SLOT]]')) {
|
||||
- const tagParts = newValue.split('[[CODE SLOT]]');
|
||||
- const inside = [node];
|
||||
- let skipAmount = 1;
|
||||
- const next = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
- parent.children[index + 1]
|
||||
+ if (node.lang === 'html' && node.meta === 'story') {
|
||||
+ const storyData = extractStoryData(
|
||||
+ `export const HtmlStory${htmlIndex} = () => html\`${node.value}\`;`,
|
||||
+ { type: 'html' },
|
||||
+ );
|
||||
+ node.type = 'html';
|
||||
+ node.value = storyTag(storyData.name);
|
||||
+ stories.push(storyData);
|
||||
+ htmlIndex += 1;
|
||||
+ }
|
||||
+ if (node.lang === 'html' && node.meta === 'preview-story') {
|
||||
+ const storyData = extractStoryData(
|
||||
+ `export const HtmlStory${htmlIndex} = () => html\`${node.value}\`;`,
|
||||
+ { type: 'html' },
|
||||
);
|
||||
- if (next && next.type === 'code' && next.meta === 'story-code') {
|
||||
- inside.push(next);
|
||||
- skipAmount += 1;
|
||||
|
||||
- const next2 = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
- parent.children[index + 2]
|
||||
+ const newValue = previewStoryTag(storyData.name);
|
||||
+ if (newValue.includes('[[CODE SLOT]]')) {
|
||||
+ const tagParts = newValue.split('[[CODE SLOT]]');
|
||||
+ const inside = [node];
|
||||
+ let skipAmount = 1;
|
||||
+ const next = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
+ parent.children[index + 1]
|
||||
);
|
||||
- if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
||||
- inside.push(next2);
|
||||
+ if (next && next.type === 'code' && next.meta === 'story-code') {
|
||||
+ inside.push(next);
|
||||
skipAmount += 1;
|
||||
+
|
||||
+ const next2 = /** @type {UnistNode & {[key: string]: unknown}} */ (
|
||||
+ parent.children[index + 2]
|
||||
+ );
|
||||
+ if (next2 && next2.type === 'code' && next2.meta === 'story-code') {
|
||||
+ inside.push(next2);
|
||||
+ skipAmount += 1;
|
||||
+ }
|
||||
}
|
||||
+
|
||||
+ node = {
|
||||
+ type: 'root',
|
||||
+ children: [
|
||||
+ { type: 'html', value: tagParts[0] },
|
||||
+ { type: 'text', value: '\n\n' },
|
||||
+ ...inside,
|
||||
+ { type: 'text', value: '\n\n' },
|
||||
+ { type: 'html', value: tagParts[1] },
|
||||
+ ],
|
||||
+ };
|
||||
+ parent.children.splice(index, skipAmount, node);
|
||||
+ } else {
|
||||
+ node.type = 'html';
|
||||
+ node.value = previewStoryTag(storyData.name);
|
||||
}
|
||||
|
||||
- node = {
|
||||
- type: 'root',
|
||||
- children: [
|
||||
- { type: 'html', value: tagParts[0] },
|
||||
- { type: 'text', value: '\n\n' },
|
||||
- ...inside,
|
||||
- { type: 'text', value: '\n\n' },
|
||||
- { type: 'html', value: tagParts[1] },
|
||||
- ],
|
||||
- };
|
||||
- parent.children.splice(index, skipAmount, node);
|
||||
- } else {
|
||||
- node.type = 'html';
|
||||
- node.value = previewStoryTag(storyData.name);
|
||||
+ stories.push(storyData);
|
||||
+ htmlIndex += 1;
|
||||
}
|
||||
+ };
|
||||
|
||||
- stories.push(storyData);
|
||||
- htmlIndex += 1;
|
||||
- }
|
||||
- };
|
||||
-
|
||||
- /**
|
||||
- * @param {Node} tree
|
||||
- * @param {VFileOptions} file
|
||||
- */
|
||||
- async function transformer(tree, file) {
|
||||
// unifiedjs expects node changes to be made on the given node...
|
||||
await init;
|
||||
// @ts-ignore
|
||||
48
patches/README.md
Normal file
48
patches/README.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
## @mdjs/core@0.20.0
|
||||
|
||||
### mdjsStoryParse.js
|
||||
|
||||
The original file URL is here: [URL](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsStoryParse.js)
|
||||
|
||||
#### Why
|
||||
|
||||
Astro does not call [mdjsStoryParse](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsStoryParse.js#L53) every time an md file is changed while `watching`. The function is called only once. However some [shared variables](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsStoryParse.js#L58-L59) are set on the level of the `mdjsStoryParse`. That leads to the situation that those variable are shared among all md files which is not according to the design. The orignal idea is to share those per an md file. As a result when generating `__mdjs-stories.js` files, they get polluted with the data from other files.
|
||||
|
||||
#### About the fix
|
||||
|
||||
- [nodeCodeVisitor](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsStoryParse.js#L68) function was moved under the [transformer](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsStoryParse.js#L182C18-L182C29) function
|
||||
- [Shared variables](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsStoryParse.js#L58-L59) were moved under the `transformer` function
|
||||
|
||||
This way the shared variables instantiated on every `transformer` function call.
|
||||
|
||||
### mdjsParse.js
|
||||
|
||||
#### Why patching
|
||||
|
||||
Astro does not call [mdjsParse](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsParse.js#L7) every time an md file is changed while `watching`. The function is called only once. However some [shared variables](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsParse.js#L8) are set on the level of the `mdjsParse`. That leads to the situation that those variable are shared among all md files which is not according to the design. The orignal idea is to share those per an md file. As a result when generating `__mdjs-stories.js` files, they get polluted with the data from other files.
|
||||
|
||||
#### About the patch
|
||||
|
||||
- [Shared variables](https://github.com/modernweb-dev/rocket/blob/%40mdjs/core%400.20.0/packages/mdjs-core/src/mdjsParse.js#L8) were moved under the `transformer` function
|
||||
|
||||
This way the shared variables instantiated on every `transformer` function call.
|
||||
|
||||
### mdjsSetupCode.js
|
||||
|
||||
Dynamic `imports` for `@mdjs/mdjs-preview/define` and `@mdjs/mdjs-story/define` were removed. These imports are inlined into `__mdjs-story.js` by `copyMdjsStories.js` remark plugin. This is done to enable `dist` bundling.
|
||||
|
||||
## @astrojs/markdown-remark
|
||||
|
||||
The patch is done to inhance the `id` naming of <H> tag `HTML` elements.
|
||||
|
||||
### Why updating naming
|
||||
|
||||
In the current implementation of the portal we need to concatenate `md` pages. Astro creates unique values for the `id` attributes for `<H>` tags (`h1`, `h2`, etc. ). The problem is that the `id`'s are not longer unique after concatenation. There might be multiple `overview` `id`'s which is not correct for navigation.
|
||||
|
||||
### What the solution is about
|
||||
|
||||
The solution is to add the parent directory name to the each <H> id as a prefix. That is if the `md` file being parsed is called `docs/tools/my.md` and let's say there is an `h2` tag in with id called `overview`, then after applying patch, the new `id` value becomes `tools-overview`.
|
||||
|
||||
## lit
|
||||
|
||||
The patch is required to make `astro build` work correctly. `lit` is added as an `external` library for the build option in `astro.config.mjs`. And without the patch the build throws errors.
|
||||
8
patches/lit+2.8.0.patch
Normal file
8
patches/lit+2.8.0.patch
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
diff --git a/node_modules/lit/index.js b/node_modules/lit/index.js
|
||||
index 599d7d0..68a9dcb 100644
|
||||
--- a/node_modules/lit/index.js
|
||||
+++ b/node_modules/lit/index.js
|
||||
@@ -1,2 +1,2 @@
|
||||
-import"@lit/reactive-element";import"lit-html";export*from"lit-element/lit-element.js";export*from"lit-html/is-server.js";
|
||||
+import"@lit/reactive-element";import"lit-html";export { nothing } from 'lit-html';export*from"lit-element/lit-element.js";export*from"lit-html/is-server.js";
|
||||
//# sourceMappingURL=index.js.map
|
||||
9
public/favicon.svg
Normal file
9
public/favicon.svg
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 749 B |
9
rollup.config-test.js
Normal file
9
rollup.config-test.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import nodeResolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
commonjs(), // <-- this handles some parsing of js syntax or something (necessary for `export { init } from "mathjax";`)
|
||||
nodeResolve(), // <-- this allows npm modules to be added to bundle
|
||||
],
|
||||
};
|
||||
13
src/components/shared/UIBaseElement.js
Normal file
13
src/components/shared/UIBaseElement.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { LitElement } from 'lit';
|
||||
|
||||
/**
|
||||
* @typedef {import('./UIBaseElementTypes').UIBaseElementInterface} UIBaseElementInterface
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {UIBaseElementInterface}
|
||||
*/
|
||||
export class UIBaseElement extends LitElement {
|
||||
static templates = {};
|
||||
}
|
||||
41
src/components/ui-portal-footer.js
Normal file
41
src/components/ui-portal-footer.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { LitElement, html, nothing, css } from 'lit';
|
||||
|
||||
const tagName = 'ui-portal-footer';
|
||||
|
||||
export class UIPortalFooter extends LitElement {
|
||||
static properties = {
|
||||
footerData: { type: Array, attribute: 'footer-data' },
|
||||
};
|
||||
|
||||
static styles = [
|
||||
css`
|
||||
footer > ul {
|
||||
display: flex;
|
||||
gap: 8em;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.footerData = [];
|
||||
}
|
||||
|
||||
render() {
|
||||
return html` <footer>${this._renderNavLevel({ children: this.footerData })}</footer> `;
|
||||
}
|
||||
|
||||
_renderNavLevel({ children }) {
|
||||
return html`<ul>
|
||||
${children.map(
|
||||
item => html`<li>
|
||||
<a href="${item.url}">${item.name}</a>
|
||||
${item.children?.length ? this._renderNavLevel({ children: item.children }) : nothing}
|
||||
</li>`,
|
||||
)}
|
||||
</ul>`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(tagName, UIPortalFooter);
|
||||
32
src/components/ui-portal-inpage-nav.js
Normal file
32
src/components/ui-portal-inpage-nav.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { LitElement, html, nothing } from 'lit';
|
||||
|
||||
const tagName = 'ui-portal-inpage-nav';
|
||||
|
||||
export class UIPortalInpageNav extends LitElement {
|
||||
static properties = {
|
||||
navData: { type: Array, attribute: 'nav-data' },
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.navData = [];
|
||||
}
|
||||
|
||||
render() {
|
||||
return html` <nav>${this._renderNavLevel({ children: this.navData })}</nav> `;
|
||||
}
|
||||
|
||||
_renderNavLevel({ children }) {
|
||||
return html`<ul>
|
||||
${children.map(
|
||||
item => html`<li>
|
||||
<a href="${item.url}">${item.name}</a>
|
||||
${item.children?.length ? this._renderNavLevel({ children: item.children }) : nothing}
|
||||
</li>`,
|
||||
)}
|
||||
</ul>`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(tagName, UIPortalInpageNav);
|
||||
34
src/components/ui-portal-main-nav.js
Normal file
34
src/components/ui-portal-main-nav.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { LitElement, html, nothing } from 'lit';
|
||||
|
||||
const tagName = 'ui-portal-main-nav';
|
||||
|
||||
// TODO: apply https://web.dev/website-navigation/ (aria-current="page" etc.)
|
||||
|
||||
export class UiPortalMainNav extends LitElement {
|
||||
static properties = {
|
||||
navData: { type: Array, attribute: 'nav-data' },
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.navData = [];
|
||||
}
|
||||
|
||||
render() {
|
||||
return html` <nav>${this._renderNavLevel({ children: this.navData })}</nav> `;
|
||||
}
|
||||
|
||||
_renderNavLevel({ children }) {
|
||||
return html`<ul>
|
||||
${children.map(
|
||||
item => html`<li>
|
||||
<a href="${item.url}">${item.name}</a>
|
||||
${item.children?.length ? this._renderNavLevel({ children: item.children }) : nothing}
|
||||
</li>`,
|
||||
)}
|
||||
</ul>`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define(tagName, UiPortalMainNav);
|
||||
21
src/content.ts
Normal file
21
src/content.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { getCollection } from 'astro:content';
|
||||
import {
|
||||
isBlogEntry,
|
||||
isComponentInfoEntry,
|
||||
isComponentPageEntry,
|
||||
isFundamentalsEntry,
|
||||
isGuideEntry
|
||||
} from './content/config';
|
||||
|
||||
export const allPages = await getCollection('docs');
|
||||
export const componentInfoEntries = allPages.filter(isComponentInfoEntry);
|
||||
export const componentPageEntries = allPages.filter(isComponentPageEntry);
|
||||
export const blogEntries = allPages.filter(isBlogEntry);
|
||||
export const guideEntries = allPages.filter(isGuideEntry);
|
||||
export const fundamentalsEntries = allPages.filter(isFundamentalsEntry);
|
||||
export const getInfoParentSlug = entry => entry.slug.split('/info')[0];
|
||||
|
||||
|
||||
export const getComponentEntries = (componentName) => {
|
||||
return componentPageEntries.filter(componentEntry => componentEntry.data.component === componentName);
|
||||
}
|
||||
35
src/content/config.ts
Normal file
35
src/content/config.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { z, defineCollection } from "astro:content";
|
||||
|
||||
const componentSchema = z.object({
|
||||
component: z.string(),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional()
|
||||
});
|
||||
|
||||
const anySchema = z.object({
|
||||
any: z.string().optional(),
|
||||
});
|
||||
|
||||
const blogSchema = z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
published: z.boolean(),
|
||||
});
|
||||
|
||||
export const docsCollectionSchema = z.union([
|
||||
blogSchema,
|
||||
componentSchema,
|
||||
anySchema,
|
||||
]);
|
||||
|
||||
const docs = defineCollection({
|
||||
schema: docsCollectionSchema,
|
||||
});
|
||||
|
||||
export const isComponentInfoEntry = (entry) => entry.slug.startsWith('components') && entry.slug.endsWith('/info');
|
||||
export const isComponentPageEntry = (entry) => entry.slug.startsWith('components') && !entry.slug.endsWith('/info');
|
||||
export const isBlogEntry = (entry) => entry.slug.startsWith('blog');
|
||||
export const isFundamentalsEntry = (entry) => entry.slug.startsWith('fundamentals');
|
||||
export const isGuideEntry = (entry) => entry.slug.startsWith('guides');
|
||||
|
||||
export const collections = { docs };
|
||||
157
src/layouts/MainLayout.astro
Normal file
157
src/layouts/MainLayout.astro
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import { SEO } from "astro-seo";
|
||||
import { UIPortalFooter } from "../components/ui-portal-footer.js";
|
||||
import { UiPortalMainNav } from "../components/ui-portal-main-nav.js";
|
||||
import { componentInfoEntries } from '../content';
|
||||
|
||||
const site = Astro.site || Astro.url.origin;
|
||||
const canonicalURL = new URL(Astro.url.pathname, site).toString();
|
||||
const resolvedImageWithDomain = new URL("/opengraph.jpg", site).toString();
|
||||
const { title } = Astro.props;
|
||||
|
||||
const compNames = componentInfoEntries.map((entry) => entry.data.component);
|
||||
|
||||
const navData = [
|
||||
{ name: "home", url: "/" },
|
||||
{
|
||||
name: "components",
|
||||
url: "/components",
|
||||
children: compNames.map((compName) => ({
|
||||
name: compName,
|
||||
url: `/components/${compName}`,
|
||||
})),
|
||||
},
|
||||
{ name: "blog", url: "/blog" },
|
||||
{ name: "fundamentals", url: "/fundamentals" },
|
||||
{ name: "guides", url: "/guides" },
|
||||
];
|
||||
|
||||
const footerData = [
|
||||
{
|
||||
name: "discover",
|
||||
children: [
|
||||
{
|
||||
name: "blog",
|
||||
url: "/blog",
|
||||
},
|
||||
{
|
||||
name: "help and feedback",
|
||||
url: "https://github.com/ing-bank/lion/issues",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "follow",
|
||||
children: [
|
||||
{
|
||||
name: "github",
|
||||
url: "https://github.com/ing-bank/lion",
|
||||
},
|
||||
{
|
||||
name: "slack",
|
||||
url: "/about/slack/",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "support",
|
||||
children: [
|
||||
{
|
||||
name: "contribute",
|
||||
url: "https://github.com/ing-bank/lion/blob/master/CONTRIBUTING.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<link
|
||||
href="http://fonts.googleapis.com/css?family=Roboto"
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- <link rel="preload" as="image" href={src} alt="Hero" /> -->
|
||||
<SEO
|
||||
title={title}
|
||||
description="High quality UI web components"
|
||||
canonical={canonicalURL}
|
||||
openGraph={{
|
||||
basic: {
|
||||
url: canonicalURL,
|
||||
type: "website",
|
||||
title: "Lion",
|
||||
image: resolvedImageWithDomain,
|
||||
},
|
||||
image: {
|
||||
alt: "Lion Homepage screen",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body class="ui-portal-grid">
|
||||
<div class="ui-portal-grid__nav">
|
||||
<UiPortalMainNav nav-data={JSON.stringify(navData)} />
|
||||
</div>
|
||||
<main class="ui-portal-grid__main">
|
||||
<slot />
|
||||
</main>
|
||||
<div class="ui-portal-grid__footer">
|
||||
<UIPortalFooter footer-data={JSON.stringify(footerData)} />
|
||||
</div>
|
||||
<style is:global>
|
||||
/* Improve Page speed */
|
||||
/* https://css-tricks.com/almanac/properties/c/content-visibility/ */
|
||||
img {
|
||||
content-visibility: auto;
|
||||
}
|
||||
|
||||
.ui-portal-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 1fr;
|
||||
grid-template-rows: 80vh 20vh;
|
||||
grid-template-areas:
|
||||
"nav main"
|
||||
"nav footer";
|
||||
}
|
||||
|
||||
.ui-portal-grid__nav {
|
||||
grid-area: nav;
|
||||
}
|
||||
|
||||
.ui-portal-grid__main {
|
||||
grid-area: main;
|
||||
}
|
||||
|
||||
.ui-portal-grid__footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
|
||||
.ui-portal-collection {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 300px));
|
||||
}
|
||||
|
||||
.ui-portal-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
4
src/layouts/partials/ComponentPartial.astro
Normal file
4
src/layouts/partials/ComponentPartial.astro
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
---
|
||||
|
||||
<slot />
|
||||
88
src/pages/[top]/[...slug].astro
Normal file
88
src/pages/[top]/[...slug].astro
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
import { glob } from 'glob'
|
||||
import * as fs from 'fs';
|
||||
import * as process from 'process';
|
||||
import MainLayout from '../../layouts/MainLayout.astro';
|
||||
import { UIPortalInpageNav } from "../../components/ui-portal-inpage-nav.js";
|
||||
import * as path from 'path';
|
||||
import { fundamentalsEntries, allPages } from '../../content';
|
||||
import { blogEntries } from '../../content';
|
||||
import { guideEntries } from '../../content';
|
||||
import { maxDepthForNonComponentsNavigation } from '../../../config.mjs';
|
||||
import { getPages, getInPageNavData, getPagesByDir, getPathForMdjsStroriesFile } from '../../utils/pages/render-entries.ts';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const fundamentalsArr = fundamentalsEntries.map(entry => ({
|
||||
params: {
|
||||
top: 'fundamentals',
|
||||
slug: entry.slug.split('fundamentals/')[1]
|
||||
},
|
||||
props: { entry },
|
||||
}));
|
||||
|
||||
const blogArr = blogEntries.map(entry => ({
|
||||
params: {
|
||||
top: 'blog',
|
||||
slug: entry.slug.split('blog/')[1]
|
||||
},
|
||||
props: { entry },
|
||||
}));
|
||||
|
||||
const guideArr = guideEntries .map(entry => ({
|
||||
params: {
|
||||
top: 'guides',
|
||||
slug: entry.slug.split('guides/')[1]
|
||||
},
|
||||
props: { entry },
|
||||
}));
|
||||
|
||||
const dirArr = allPages
|
||||
.filter(entry => {
|
||||
const separator = '/';
|
||||
const dirPath = path.dirname(entry.slug);
|
||||
const dirParts = dirPath.split(separator);
|
||||
|
||||
return dirParts.length >= maxDepthForNonComponentsNavigation && dirParts[0] !== 'components';
|
||||
})
|
||||
.map(entry => {
|
||||
const separator = '/';
|
||||
const dirPath = path.dirname(entry.slug);
|
||||
const dirParts = dirPath.split(separator);
|
||||
dirParts.splice(maxDepthForNonComponentsNavigation);
|
||||
const result = {
|
||||
params: {
|
||||
top: dirParts.shift(),
|
||||
slug: dirParts.join(separator)
|
||||
},
|
||||
};
|
||||
return result;
|
||||
});
|
||||
|
||||
const uniqueDirArr = [];
|
||||
dirArr.forEach(route => {
|
||||
if (!uniqueDirArr.find(uniqueRoute => uniqueRoute.params.top === route.params.top && uniqueRoute.params.slug === route.params.slug)) {
|
||||
uniqueDirArr.push(route);
|
||||
}
|
||||
});
|
||||
|
||||
return [...fundamentalsArr, ...blogArr, ...guideArr, ...dirArr];
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
|
||||
// URL path as a base for in-page navigation. It is used to add anchors to. F.e. "host://urlPath#header1"
|
||||
const urlPath = entry ? entry.slug : path.join(Astro.params.top, Astro.params.slug);
|
||||
const pages = entry ? await getPages([entry]) : await getPagesByDir(urlPath);
|
||||
const pathForMdjsStroriesFile = await getPathForMdjsStroriesFile(!entry, urlPath);
|
||||
---
|
||||
|
||||
<MainLayout title={entry?.slug}>
|
||||
<UIPortalInpageNav nav-data={JSON.stringify(getInPageNavData(pages, urlPath))} />
|
||||
{
|
||||
pages.map((page) => (
|
||||
<page.Content />
|
||||
))
|
||||
}
|
||||
<script is:inline src="/docs/_assets/scoped-custom-element-registry.min.js"></script>
|
||||
{pathForMdjsStroriesFile && <script type="module" src={pathForMdjsStroriesFile} mdjs-setup></script>}
|
||||
</MainLayout>
|
||||
36
src/pages/[top]/index.astro
Normal file
36
src/pages/[top]/index.astro
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
import MainLayout from "../../layouts/MainLayout.astro";
|
||||
import { fundamentalsEntries } from "../../content";
|
||||
import { blogEntries } from "../../content";
|
||||
import { guideEntries } from "../../content";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return [{
|
||||
params: { top: 'fundamentals' },
|
||||
props: { entries: fundamentalsEntries },
|
||||
}, {
|
||||
params: { top: 'blog' },
|
||||
props: { entries: blogEntries },
|
||||
}, {
|
||||
params: { top: 'guides' },
|
||||
props: { entries: guideEntries },
|
||||
}];
|
||||
}
|
||||
|
||||
const entries = Astro.props.entries;
|
||||
---
|
||||
|
||||
<MainLayout>
|
||||
<div class="ui-portal-collection">
|
||||
{
|
||||
entries.map((entry) => (
|
||||
<article class="ui-portal-card">
|
||||
<h2>{entry.data.title}</h2>
|
||||
<p>{entry.slug}</p>
|
||||
<p>{entry.data.description}</p>
|
||||
<a href={entry.slug}>View blog</a>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</MainLayout>
|
||||
35
src/pages/components/[component].astro
Normal file
35
src/pages/components/[component].astro
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
import * as path from 'path';
|
||||
import { componentInfoEntries, getComponentEntries } from '../../content';
|
||||
import MainLayout from "../../layouts/MainLayout.astro";
|
||||
import ComponentLayout from "../../layouts/partials/ComponentPartial.astro";
|
||||
import { UIPortalInpageNav } from "../../components/ui-portal-inpage-nav.js";
|
||||
import { getPages, getInPageNavData, getPagesByDir, getPathForMdjsStroriesFile } from '../../utils/pages/render-entries.ts';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return componentInfoEntries.map((entry) => ({
|
||||
params: {
|
||||
component: entry.data.component
|
||||
},
|
||||
props: { entry }
|
||||
}));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const urlPath = path.dirname(entry.slug);
|
||||
const pages = await getPagesByDir(urlPath);
|
||||
const pathForMdjsStroriesFile = await getPathForMdjsStroriesFile(true, urlPath);
|
||||
---
|
||||
|
||||
<MainLayout title={entry.slug}>
|
||||
<ComponentLayout frontmatter={entry.data}>
|
||||
<UIPortalInpageNav nav-data={JSON.stringify(getInPageNavData(pages, urlPath))} />
|
||||
{
|
||||
pages.map((page) => (
|
||||
<page.Content />
|
||||
))
|
||||
}
|
||||
<script is:inline src="/docs/_assets/scoped-custom-element-registry.min.js"></script>
|
||||
{pathForMdjsStroriesFile && <script type="module" src={pathForMdjsStroriesFile} mdjs-setup></script>}
|
||||
</ComponentLayout>
|
||||
</MainLayout>
|
||||
18
src/pages/components/index.astro
Normal file
18
src/pages/components/index.astro
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
import MainLayout from "../../layouts/MainLayout.astro";
|
||||
import { componentInfoEntries, getInfoParentSlug } from '../../content';
|
||||
---
|
||||
|
||||
<MainLayout>
|
||||
<div class="ui-portal-collection">
|
||||
{
|
||||
componentInfoEntries.map((comp) => (
|
||||
<article class="ui-portal-card">
|
||||
<h2>{comp.data.component}</h2>
|
||||
<p>{comp.data.description}</p>
|
||||
<a href={`/${getInfoParentSlug(comp)}`}>View comp</a>
|
||||
</article>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</MainLayout>
|
||||
7
src/pages/index.astro
Normal file
7
src/pages/index.astro
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
import MainLayout from "../layouts/MainLayout.astro";
|
||||
---
|
||||
|
||||
<MainLayout>
|
||||
<h1>Home, sweet home</h1>
|
||||
</MainLayout>
|
||||
89
src/pages/simulator.astro
Normal file
89
src/pages/simulator.astro
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<html theme="light" platform="web" lang="en"><head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
height: fit-content;
|
||||
}
|
||||
html[edge-distance] body {
|
||||
padding: 8px;
|
||||
}
|
||||
</style>
|
||||
<script type="module">
|
||||
import { render } from '/node_modules/@mdjs/mdjs-story/index.js';
|
||||
|
||||
function sanitize(input, type) {
|
||||
return `${document.location.origin}/${input.match(/[a-zA-Z0-9\/\-_]*/)[0]}.${type}`;
|
||||
}
|
||||
|
||||
async function onHashChange() {
|
||||
const urlParts = new URLSearchParams(document.location.hash.substr(1));
|
||||
|
||||
if (urlParts.get('stylesheets')) {
|
||||
for (const stylesheet of urlParts.getAll('stylesheets')) {
|
||||
const safeStylesheetUrl = sanitize(stylesheet, 'css');
|
||||
if (!document.querySelector(`link[rel="stylesheet"][href="${safeStylesheetUrl}"]`)) {
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = safeStylesheetUrl;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParts.get('moduleUrls')) {
|
||||
for (const moduleUrl of urlParts.getAll('moduleUrls')) {
|
||||
const safeModuleUrl = sanitize(moduleUrl, 'js');
|
||||
if (!document.querySelector(`script[type=module][src="${safeModuleUrl}"]`)) {
|
||||
const script = document.createElement('script');
|
||||
script.type = 'module';
|
||||
debugger;
|
||||
script.src = safeModuleUrl;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParts.get('theme')) {
|
||||
document.documentElement.setAttribute('theme', urlParts.get('theme'));
|
||||
}
|
||||
if (urlParts.get('platform')) {
|
||||
document.documentElement.setAttribute('platform', urlParts.get('platform'));
|
||||
}
|
||||
if (urlParts.get('language')) {
|
||||
document.documentElement.setAttribute('lang', urlParts.get('language'));
|
||||
document.documentElement.setAttribute('data-lang', urlParts.get('language'));
|
||||
}
|
||||
if (urlParts.get('story-key')) {
|
||||
document.documentElement.setAttribute('story-key', urlParts.get('story-key'));
|
||||
}
|
||||
if (urlParts.get('edge-distance') === 'true') {
|
||||
document.documentElement.setAttribute('edge-distance', '');
|
||||
} else {
|
||||
document.documentElement.removeAttribute('edge-distance');
|
||||
}
|
||||
|
||||
const safeStoryUrl = sanitize(urlParts.get('story-file'), 'js');
|
||||
const mod = await import(safeStoryUrl);
|
||||
render(mod[urlParts.get('story-key')]({ shadowRoot: document }), document.body);
|
||||
}
|
||||
|
||||
window.addEventListener('hashchange', onHashChange, false);
|
||||
onHashChange();
|
||||
|
||||
const observer = new ResizeObserver(() => {
|
||||
const dimensions = document.body.getBoundingClientRect();
|
||||
const data = {
|
||||
action: 'mdjs-viewer-resize',
|
||||
storyKey: document.documentElement.getAttribute('story-key'),
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
};
|
||||
parent.postMessage(JSON.stringify(data), '*');
|
||||
});
|
||||
observer.observe(document.body);
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
240
src/utils/copy-docs/copy-docs.js
Normal file
240
src/utils/copy-docs/copy-docs.js
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs/promises');
|
||||
const process = require('process');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const imageExtensions = require('image-extensions');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const findNodeModules = require('find-node-modules');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const { init, parse } = require('es-module-lexer');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
const sourceDocsPath = 'docs';
|
||||
const contentPathForDocs = 'src/content';
|
||||
const contentDocsPath = `${contentPathForDocs}/docs`;
|
||||
const publicPathForDocs = 'public';
|
||||
const publicDocsPath = `${publicPathForDocs}/docs`;
|
||||
const rootPath = process.cwd();
|
||||
const isDistBuild = process.env.PROD === 'true';
|
||||
|
||||
async function processImportsForFile(filePath) {
|
||||
if (filePath.includes('__mdjs-stories')) {
|
||||
return;
|
||||
}
|
||||
const source = await fs.readFile(filePath, 'utf8');
|
||||
if (source === '' || !source.includes('import')) {
|
||||
return;
|
||||
}
|
||||
const fileExtName = path.extname(filePath);
|
||||
if (fileExtName !== '.js' && fileExtName !== '.mjs' && fileExtName !== '.ts') {
|
||||
return;
|
||||
}
|
||||
let newSource = '';
|
||||
let lastPos = 0;
|
||||
await init;
|
||||
const [imports] = parse(source);
|
||||
for (const importObj of imports) {
|
||||
newSource += source.substring(lastPos, importObj.s);
|
||||
const importSrc = source.substring(importObj.s, importObj.e);
|
||||
const isDynamicImport = importObj.d > -1;
|
||||
|
||||
if (
|
||||
importSrc.startsWith('.') ||
|
||||
importSrc.startsWith('/') ||
|
||||
isDynamicImport ||
|
||||
importSrc.startsWith('import.')
|
||||
) {
|
||||
newSource += importSrc;
|
||||
} else {
|
||||
const nodeModulesLocation = findNodeModules(filePath)[0];
|
||||
const nodeModulesLocation1 = path.join(filePath, nodeModulesLocation);
|
||||
const resolvedImportPath = require.resolve(importSrc, { paths: [nodeModulesLocation1] });
|
||||
const lastNodeModulesDirectoryIndex = resolvedImportPath.lastIndexOf('nodeModulesText');
|
||||
const nodeModulesPath = resolvedImportPath.substring(0, lastNodeModulesDirectoryIndex);
|
||||
const dependencyPath = resolvedImportPath.substring(lastNodeModulesDirectoryIndex);
|
||||
if (nodeModulesPath === rootPath) {
|
||||
newSource += dependencyPath;
|
||||
} else {
|
||||
newSource += resolvedImportPath.split(rootPath)[1];
|
||||
}
|
||||
}
|
||||
|
||||
lastPos = importObj.e;
|
||||
}
|
||||
newSource += source.substring(lastPos, source.length);
|
||||
await fs.writeFile(filePath, newSource);
|
||||
}
|
||||
|
||||
async function createInfoMd(componentDirectoryPath) {
|
||||
const componentName = path.basename(componentDirectoryPath);
|
||||
const infoMd = `---
|
||||
component: ${componentName}
|
||||
title: ${componentName} title
|
||||
description: ${componentName} description
|
||||
---\n`;
|
||||
const infoMdFilePath = path.join(componentDirectoryPath, 'info.md');
|
||||
await fs.mkdir(componentDirectoryPath, { recursive: true });
|
||||
await fs.writeFile(infoMdFilePath, infoMd);
|
||||
}
|
||||
|
||||
function getFrontmatter(text) {
|
||||
const result = {};
|
||||
if (!text.startsWith('---')) {
|
||||
return result;
|
||||
}
|
||||
const frontmatterRegex = /---\n(.+?)\n---/gs;
|
||||
const match = text.matchAll(frontmatterRegex);
|
||||
const matchResult = [...match]?.[0]?.[1] || '';
|
||||
if (matchResult) {
|
||||
matchResult.split('\n').forEach(pair => {
|
||||
const pairArr = pair.split(':');
|
||||
const key = pairArr[0].trim();
|
||||
const value = pairArr[1].trim();
|
||||
result[key] = value;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getContent(text) {
|
||||
if (Object.keys(getFrontmatter(text)).length === 0) {
|
||||
return text;
|
||||
}
|
||||
const frontmatterRegex = /---\n(.+?)\n---\n(.*)/gs;
|
||||
const match = text.matchAll(frontmatterRegex);
|
||||
return [...match]?.[0]?.[2] || text;
|
||||
}
|
||||
|
||||
function frontmatterToString(frontmatter) {
|
||||
const prefix = '---\n';
|
||||
let result = prefix;
|
||||
Object.keys(frontmatter).forEach(key => {
|
||||
result += `${key}: ${frontmatter[key]}\n`;
|
||||
});
|
||||
if (result === prefix) {
|
||||
return '';
|
||||
}
|
||||
return `${result}---\n\n`;
|
||||
}
|
||||
|
||||
function addFrontmatter(fileContent, key, value) {
|
||||
const frontmatter = getFrontmatter(fileContent);
|
||||
const content = getContent(fileContent);
|
||||
if (value) {
|
||||
frontmatter[key] = value;
|
||||
}
|
||||
return frontmatterToString(frontmatter) + content;
|
||||
}
|
||||
|
||||
function getOrder(fileContent) {
|
||||
const orderRegexp = /#.+\|\|(\d+)/gm;
|
||||
const match = fileContent.matchAll(orderRegexp);
|
||||
return [...match]?.[0]?.[1];
|
||||
}
|
||||
|
||||
async function copyDocs(currentPath = '') {
|
||||
const files = await fs.readdir(path.join(sourceDocsPath, currentPath));
|
||||
|
||||
for (const file of files) {
|
||||
const sourceDocsFilePath = path.join(sourceDocsPath, currentPath, file);
|
||||
const contentDocsFilePath =
|
||||
file === 'index.md'
|
||||
? path.join(contentDocsPath, currentPath, 'dir-index.md')
|
||||
: path.join(contentDocsPath, currentPath, file);
|
||||
const publicDocsFilePath = path.join(publicDocsPath, currentPath, file);
|
||||
const stats = await fs.lstat(sourceDocsFilePath);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
if (currentPath === 'components') {
|
||||
await createInfoMd(contentDocsFilePath);
|
||||
}
|
||||
await copyDocs(path.join(currentPath, file));
|
||||
} else {
|
||||
if (
|
||||
(path.extname(file) === '.md' && sourceDocsFilePath !== `${sourceDocsPath}/index.md`) ||
|
||||
imageExtensions.includes(path.extname(file).split('.')[1])
|
||||
) {
|
||||
await fs.mkdir(path.join(contentDocsPath, currentPath), { recursive: true });
|
||||
await fs.copyFile(sourceDocsFilePath, contentDocsFilePath);
|
||||
if (path.extname(file) === '.md') {
|
||||
const fileContent = await fs.readFile(contentDocsFilePath, 'utf8');
|
||||
let updatedFileContent = fileContent;
|
||||
if (contentDocsFilePath.includes('/components')) {
|
||||
const parentComponent = path.basename(currentPath);
|
||||
updatedFileContent = addFrontmatter(fileContent, 'component', parentComponent);
|
||||
}
|
||||
const order = getOrder(fileContent);
|
||||
updatedFileContent = addFrontmatter(updatedFileContent, 'order', order);
|
||||
await fs.writeFile(contentDocsFilePath, updatedFileContent);
|
||||
}
|
||||
}
|
||||
if (path.extname(file) !== '.md') {
|
||||
await fs.mkdir(path.join(publicDocsPath, currentPath), { recursive: true });
|
||||
await fs.copyFile(sourceDocsFilePath, publicDocsFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function copyDocsByFileArray(files) {
|
||||
for (const file of files) {
|
||||
const currentPath = path.dirname(file);
|
||||
const contentDocsFilePath = path.join(contentPathForDocs, file);
|
||||
const publicDocsFilePath = path.join(publicPathForDocs, file);
|
||||
if (path.extname(file) === '.md' && file !== 'index.md') {
|
||||
await fs.mkdir(path.join(contentPathForDocs, currentPath), { recursive: true });
|
||||
await fs.copyFile(file, contentDocsFilePath);
|
||||
|
||||
if (file.includes('/components')) {
|
||||
const fileContent = await fs.readFile(contentDocsFilePath, 'utf8');
|
||||
const parentComponent = path.basename(currentPath);
|
||||
let updatedFileContent = fileContent;
|
||||
updatedFileContent = addFrontmatter(fileContent, 'component', parentComponent);
|
||||
const order = getOrder(fileContent);
|
||||
updatedFileContent = addFrontmatter(updatedFileContent, 'order', order);
|
||||
await fs.writeFile(contentDocsFilePath, updatedFileContent);
|
||||
}
|
||||
}
|
||||
if (path.extname(file) !== '.md') {
|
||||
await fs.mkdir(path.join(publicPathForDocs, currentPath), { recursive: true });
|
||||
await fs.copyFile(file, publicDocsFilePath);
|
||||
await processImportsForFile(publicDocsFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function processImports(currentPath = '') {
|
||||
if (isDistBuild) {
|
||||
return;
|
||||
}
|
||||
const files = await fs.readdir(path.join(publicDocsPath, currentPath));
|
||||
|
||||
for (const file of files) {
|
||||
const publicDocsFilePath = path.join(publicDocsPath, currentPath, file);
|
||||
const stats = await fs.stat(publicDocsFilePath);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
if (!file.startsWith('_')) {
|
||||
await processImports(path.join(currentPath, file));
|
||||
}
|
||||
} else {
|
||||
await processImportsForFile(publicDocsFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function watch() {
|
||||
const diffStr = childProcess.execSync('git diff --name-only "docs"').toString();
|
||||
const diffArr = diffStr.split('\n').filter(value => value);
|
||||
if (diffArr.length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Files have been changed: ', diffArr);
|
||||
}
|
||||
await copyDocsByFileArray(diffArr);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
copyDocs,
|
||||
processImports,
|
||||
watch,
|
||||
};
|
||||
7
src/utils/copy-docs/index.js
Normal file
7
src/utils/copy-docs/index.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
const { copyDocs, processImports, watch } = require('./copy-docs.js');
|
||||
|
||||
module.exports = {
|
||||
copyDocs,
|
||||
processImports,
|
||||
watch,
|
||||
};
|
||||
1
src/utils/copy-docs/package.json
Normal file
1
src/utils/copy-docs/package.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
197
src/utils/pages/render-entries.ts
Normal file
197
src/utils/pages/render-entries.ts
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
import { glob } from 'glob'
|
||||
import * as fs from 'fs';
|
||||
import * as process from 'process';
|
||||
import * as path from 'path';
|
||||
import { fundamentalsEntries, allPages } from '../../content';
|
||||
import { maxDepthForNonComponentsNavigation } from '../../../config.mjs';
|
||||
|
||||
const convertHeadingsToInPageNavData = (headings, urlPath) => {
|
||||
return headings.map(header => {
|
||||
const anchor = header.slug;
|
||||
return {
|
||||
name: header.text,
|
||||
url: `/${urlPath}#${anchor}`
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const parseEntries = async (entries) => {
|
||||
const contents = [];
|
||||
for (const componentEntry of entries) {
|
||||
const { Content, headings, remarkPluginFrontmatter } = await componentEntry.render();
|
||||
const order = remarkPluginFrontmatter.order;
|
||||
const slug = componentEntry.slug;
|
||||
const content = {Content, headings, order, slug};
|
||||
contents.push(content);
|
||||
}
|
||||
return contents;
|
||||
};
|
||||
|
||||
export const getInPageNavData = (contentItems, urlPath) => {
|
||||
const inPageNavData = [];
|
||||
const parentDirToNavDataMap = new Map();
|
||||
const arePagesConcatenated = contentItems.length > 1;
|
||||
for (const contentItem of contentItems) {
|
||||
const headersH2 = contentItem.headings.filter(header => header.depth === 2);
|
||||
const parentDirName = path.dirname(contentItem.slug);
|
||||
if (headersH2.length !== 0) {
|
||||
const entryInPageNavData = convertHeadingsToInPageNavData(headersH2, urlPath)[0];
|
||||
const headersH3 = contentItem.headings.filter(header => header.depth === 3);
|
||||
if (headersH3.length !== 0) {
|
||||
entryInPageNavData.children = convertHeadingsToInPageNavData(headersH3, urlPath);
|
||||
}
|
||||
inPageNavData.push(entryInPageNavData);
|
||||
parentDirToNavDataMap.set(parentDirName, entryInPageNavData);
|
||||
} else {
|
||||
const headersH3 = contentItem.headings.filter(header => header.depth === 3);
|
||||
if (headersH3.length !== 0) {
|
||||
const entryInPageNavData = parentDirToNavDataMap.get(parentDirName);
|
||||
if (entryInPageNavData) {
|
||||
entryInPageNavData.children = entryInPageNavData.children || [];
|
||||
entryInPageNavData.children = [...entryInPageNavData.children, ...convertHeadingsToInPageNavData(headersH3, urlPath)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return inPageNavData;
|
||||
};
|
||||
|
||||
function getContentsWithParentDepth(contents, parentDepth) {
|
||||
return contents.filter(content => {
|
||||
const dirDepth = path.dirname(content.slug).split('/').length;
|
||||
return dirDepth >= parentDepth;
|
||||
});
|
||||
}
|
||||
|
||||
function getSlugForParentDepth(slug, depth) {
|
||||
const slugParts = slug.split('/');
|
||||
const slugPartsForParentDepth = slugParts.slice(0, depth);
|
||||
return slugPartsForParentDepth.join('/');
|
||||
}
|
||||
|
||||
function getUniqueParentDirs(contents, parentDepth) {
|
||||
const dirs = new Set();
|
||||
contents.forEach(content => {
|
||||
dirs.add(getSlugForParentDepth(content.slug, parentDepth));
|
||||
});
|
||||
return [...dirs];
|
||||
}
|
||||
|
||||
function sortDirs(dirs, contents) {
|
||||
dirs.sort((a, b) => {
|
||||
const aDirOrder = contents.find(content => content.slug === path.join(a, 'dir-index')).order;
|
||||
const bDirOrder = contents.find(content => content.slug === path.join(b, 'dir-index')).order;
|
||||
return aDirOrder < bDirOrder ? -1 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
function sortDirectoriesForParentDepth(contents, parentDepth) {
|
||||
|
||||
const reducedContents = getContentsWithParentDepth(contents, parentDepth);
|
||||
|
||||
const uniqueParentDirs = getUniqueParentDirs(reducedContents, parentDepth);
|
||||
|
||||
sortDirs(uniqueParentDirs, reducedContents);
|
||||
contents.sort((a, b) => {
|
||||
const aParentDir = getSlugForParentDepth(a.slug, parentDepth);
|
||||
const bParentDir = getSlugForParentDepth(b.slug, parentDepth);
|
||||
if (uniqueParentDirs.indexOf(aParentDir) > uniqueParentDirs.indexOf(bParentDir)) {
|
||||
return 1;
|
||||
} else if (uniqueParentDirs.indexOf(aParentDir) < uniqueParentDirs.indexOf(bParentDir)) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sortDirectories(contents) {
|
||||
let parentDepth = maxDepthForNonComponentsNavigation + 1;
|
||||
let hasParentWithDepth = contents.some(content => path.dirname(content.slug).split('/').length === parentDepth);
|
||||
|
||||
while(hasParentWithDepth) {
|
||||
sortDirectoriesForParentDepth(contents, parentDepth);
|
||||
parentDepth++;
|
||||
hasParentWithDepth = contents.some(content => path.dirname(content.slug).split('/').length === parentDepth);
|
||||
}
|
||||
}
|
||||
|
||||
function sort(contents) {
|
||||
contents.sort((a, b) => {
|
||||
// Get paths with fewer depth first
|
||||
if (a.slug.split('/').length < b.slug.split('/').length) {
|
||||
return -1;
|
||||
} else if (a.slug.split('/').length > b.slug.split('/').length) {
|
||||
return 1;
|
||||
}
|
||||
// same depth
|
||||
else {
|
||||
// same parent
|
||||
if (path.dirname(a.slug) === path.dirname(b.slug)) {
|
||||
if (path.basename(a.slug) === 'dir-index') {
|
||||
return -1;
|
||||
} else if (path.basename(b.slug) === 'dir-index') {
|
||||
return 1;
|
||||
} else {
|
||||
return a.order < b.order ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function getPages(entries) {
|
||||
const contents = await parseEntries(entries);
|
||||
sortDirectories(contents);
|
||||
sort(contents);
|
||||
return contents;
|
||||
}
|
||||
|
||||
export const getPagesByDir = async (directoryPath) => {
|
||||
const entries = getEntriesByDir(directoryPath);
|
||||
return await getPages(entries);
|
||||
};
|
||||
|
||||
const getEntriesByDir = (dirname) => {
|
||||
return allPages.filter(childEntry => {
|
||||
return childEntry.slug.startsWith(dirname)});
|
||||
};
|
||||
|
||||
const getMdjsStories = (fullDirPath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
glob(fullDirPath + '/**/__mdjs-stories--*.js', {}, (err, files)=>{
|
||||
const relativePaths = files.map(file => {
|
||||
return path.relative(fullDirPath, file);
|
||||
});
|
||||
resolve(relativePaths);
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean} isUrlPathADirectory `True` if the `urlPath` paramter is a url path to a directory with multiple md files.
|
||||
* `false` if the `urlPath` paramter is a url path to a single md file
|
||||
*/
|
||||
export async function getPathForMdjsStroriesFile(isUrlPathADirectory, urlPath) {
|
||||
if (!isUrlPathADirectory) {
|
||||
const mdjsStroriesFileDirectory = path.dirname(urlPath);
|
||||
return `/docs/${mdjsStroriesFileDirectory}/__mdjs-stories--${path.basename(urlPath)}.js`;
|
||||
}
|
||||
if (urlPath) {
|
||||
let mdjsStoriesJsPath = '';
|
||||
const fullDirPath = path.join(process.cwd(), 'public/docs', urlPath);
|
||||
const files = await getMdjsStories(fullDirPath);
|
||||
let imports = '';
|
||||
files.forEach(file => {
|
||||
imports += `import('./${file}');\n`
|
||||
});
|
||||
if (imports) {
|
||||
mdjsStoriesJsPath = path.join(fullDirPath, '__mdjs-stories.js');
|
||||
fs.writeFileSync(mdjsStoriesJsPath, imports, 'utf8');
|
||||
}
|
||||
if (mdjsStoriesJsPath) {
|
||||
return '/docs' + mdjsStoriesJsPath.split('/docs')[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
5
src/utils/post-build-dist/index.js
Normal file
5
src/utils/post-build-dist/index.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const { postBuildDist } = require('./post-build-dist.js');
|
||||
|
||||
module.exports = {
|
||||
postBuildDist,
|
||||
};
|
||||
1
src/utils/post-build-dist/package.json
Normal file
1
src/utils/post-build-dist/package.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
32
src/utils/post-build-dist/post-build-dist.js
Normal file
32
src/utils/post-build-dist/post-build-dist.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
const distDocs = 'dist/docs';
|
||||
|
||||
const getAllFiles = (dirPath, arrayOfFiles) => {
|
||||
const files = fs.readdirSync(dirPath);
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
arrayOfFiles = arrayOfFiles || [];
|
||||
|
||||
files.forEach(file => {
|
||||
if (fs.statSync(`${dirPath}/${file}`).isDirectory()) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
arrayOfFiles = getAllFiles(`${dirPath}/${file}`, arrayOfFiles);
|
||||
} else if (file === '__mdjs-stories.js') {
|
||||
execSync(
|
||||
`npx rollup ${dirPath}/__mdjs-stories.js --config rollup.config-test.js --dir ${dirPath}/`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return arrayOfFiles;
|
||||
};
|
||||
|
||||
const postBuildDist = () => {
|
||||
getAllFiles(distDocs);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
postBuildDist,
|
||||
};
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const { init } = require('es-module-lexer');
|
||||
const path = require('path');
|
||||
|
||||
let isToBeConcatenated;
|
||||
let maxDepthForNonComponentsNavigation;
|
||||
let docsDirName;
|
||||
let visit;
|
||||
(async () => {
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const result = await import('unist-util-visit');
|
||||
visit = result.visit;
|
||||
|
||||
const config = await import('../../../../config.mjs');
|
||||
isToBeConcatenated = config.isToBeConcatenated;
|
||||
maxDepthForNonComponentsNavigation = config.maxDepthForNonComponentsNavigation;
|
||||
docsDirName = config.docsDirName;
|
||||
})();
|
||||
|
||||
// function addOverviewTitleToIndexMd(tree, isIndexMd) {
|
||||
// let h1Index = null;
|
||||
// tree.children.forEach((item, index) => {
|
||||
// if (item.depth === 1 && item.type === 'heading' && isIndexMd) {
|
||||
// h1Index = index;
|
||||
// }
|
||||
// });
|
||||
// if (h1Index !== null) {
|
||||
// tree.children.splice(1, 0, {
|
||||
// type: 'heading',
|
||||
// depth: 2,
|
||||
// children: [
|
||||
// {
|
||||
// type: 'text',
|
||||
// value: 'Index',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
function cleanupRocketMetadata() {
|
||||
/**
|
||||
* @param {Node} tree
|
||||
*/
|
||||
async function transformer(tree, file) {
|
||||
const filePath = file.history[0];
|
||||
const isIndexMd = path.basename(filePath) === 'dir-index.md';
|
||||
const filePathFromProjectRoot = filePath.split(docsDirName)[1];
|
||||
const depthDelta =
|
||||
path.dirname(filePathFromProjectRoot).split('/').length - maxDepthForNonComponentsNavigation;
|
||||
|
||||
/**
|
||||
* @param {UnistNode} _node
|
||||
*/
|
||||
async function nodeCodeVisitor(_node, index, parent) {
|
||||
if (parent.type === 'heading' && isToBeConcatenated(filePath)) {
|
||||
if (parent.depth === 1) {
|
||||
const splitByOrder = _node.value.split('||');
|
||||
const splitByArrows = splitByOrder[0].split('>>');
|
||||
const title = splitByArrows[splitByArrows.length - 1].trim();
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
_node.value = title;
|
||||
if (isIndexMd) {
|
||||
if (depthDelta > 0) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
parent.depth += depthDelta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
parent.depth += 1 + depthDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// unifiedjs expects node changes to be made on the given node...
|
||||
await init;
|
||||
visit(tree, ['text', 'inlineCode'], nodeCodeVisitor);
|
||||
// addOverviewTitleToIndexMd(tree, isIndexMd);
|
||||
return tree;
|
||||
}
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cleanupRocketMetadata,
|
||||
};
|
||||
5
src/utils/remark-plugings/cleanupRocketMetadata/index.js
Normal file
5
src/utils/remark-plugings/cleanupRocketMetadata/index.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const { cleanupRocketMetadata } = require('./cleanupRocketMetadata.js');
|
||||
|
||||
module.exports = {
|
||||
cleanupRocketMetadata,
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
147
src/utils/remark-plugings/copyMdjsStories/copyMdjsStories.js
Normal file
147
src/utils/remark-plugings/copyMdjsStories/copyMdjsStories.js
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const { init, parse } = require('es-module-lexer');
|
||||
|
||||
let visit;
|
||||
(async () => {
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const result = await import('unist-util-visit');
|
||||
visit = result.visit;
|
||||
})();
|
||||
|
||||
const nodeModulesText = '/node_modules';
|
||||
const mdJsStoriesFileNameWithoutExtension = '__mdjs-stories';
|
||||
const mdJsStoriesFileName = `${mdJsStoriesFileNameWithoutExtension}.js`;
|
||||
const isDistBuild = process.env.PROD === 'true';
|
||||
|
||||
/**
|
||||
* @param {string} source
|
||||
* @param {string} inputPath
|
||||
*/
|
||||
async function processImports(source) {
|
||||
if (source !== '' && source.includes('import')) {
|
||||
let newSource = '';
|
||||
let lastPos = 0;
|
||||
await init;
|
||||
const [imports] = parse(source);
|
||||
for (const importObj of imports) {
|
||||
newSource += source.substring(lastPos, importObj.s);
|
||||
const importSrc = source.substring(importObj.s, importObj.e);
|
||||
const isDynamicImport = importObj.d > -1;
|
||||
|
||||
if (
|
||||
importSrc.startsWith('.') ||
|
||||
importSrc.startsWith('/') ||
|
||||
isDynamicImport ||
|
||||
importSrc.startsWith('import.')
|
||||
) {
|
||||
if (importSrc === `'@mdjs/mdjs-preview/define'`) {
|
||||
newSource += `'${nodeModulesText}/@mdjs/mdjs-preview/src/define/define.js'`;
|
||||
} else if (importSrc === `'@mdjs/mdjs-story/define'`) {
|
||||
newSource += `'${nodeModulesText}/@mdjs/mdjs-story/src/define.js'`;
|
||||
} else {
|
||||
newSource += importSrc;
|
||||
}
|
||||
} else {
|
||||
const resolvedPath = require.resolve(importSrc);
|
||||
const packagesPath = '/packages/';
|
||||
if (resolvedPath.includes(packagesPath)) {
|
||||
newSource += packagesPath + resolvedPath.split(packagesPath)[1];
|
||||
} else {
|
||||
newSource += nodeModulesText + require.resolve(importSrc).split(nodeModulesText)[1];
|
||||
}
|
||||
}
|
||||
|
||||
lastPos = importObj.e;
|
||||
}
|
||||
newSource += source.substring(lastPos, source.length);
|
||||
return newSource;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
function copyMdjsStories() {
|
||||
/**
|
||||
* @param {Node} tree
|
||||
* @param {VFileOptions} file
|
||||
*/
|
||||
async function transformer(tree, file) {
|
||||
let pathToMdDirectoryInPublic = '';
|
||||
let currentMarkdownFile = '';
|
||||
let currentMarkdownFileMdJsStoryName = '';
|
||||
|
||||
/**
|
||||
* @param {UnistNode} _node
|
||||
*/
|
||||
async function nodeCodeVisitor(_node, index, parent) {
|
||||
if (
|
||||
parent.type === 'heading' &&
|
||||
parent.depth === 1 &&
|
||||
currentMarkdownFile.includes('/components')
|
||||
) {
|
||||
const commonMdjsStoriesFileName = `${pathToMdDirectoryInPublic}/${mdJsStoriesFileName}`;
|
||||
let commonMdjsStoriesContent = '';
|
||||
try {
|
||||
commonMdjsStoriesContent = fs.readFileSync(commonMdjsStoriesFileName).toString();
|
||||
} catch (ex) {
|
||||
// noop. File is not yet created for the component
|
||||
}
|
||||
|
||||
const exportCmd = `import('./${currentMarkdownFileMdJsStoryName}');\n`;
|
||||
if (commonMdjsStoriesContent.indexOf(exportCmd) === -1) {
|
||||
fs.writeFileSync(commonMdjsStoriesFileName, commonMdjsStoriesContent + exportCmd, 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let { setupJsCode } = file.data;
|
||||
if (!setupJsCode) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
currentMarkdownFile = file.history[0];
|
||||
const { cwd } = file;
|
||||
const publicDir = `${cwd}/public`;
|
||||
let parsedPath = '';
|
||||
|
||||
if (currentMarkdownFile) {
|
||||
const leftSideParsedPath = currentMarkdownFile.split('src/content/')[1];
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
parsedPath = path.dirname(leftSideParsedPath);
|
||||
}
|
||||
|
||||
let parsedSetupJsCode;
|
||||
// This is copied from @mdjs/core/src/mdjsSetupCode.js
|
||||
const initialImprorts = `
|
||||
import '@mdjs/mdjs-preview/define';
|
||||
import '@mdjs/mdjs-story/define'; \n`;
|
||||
setupJsCode = initialImprorts + setupJsCode;
|
||||
if (isDistBuild) {
|
||||
parsedSetupJsCode += await setupJsCode;
|
||||
} else {
|
||||
parsedSetupJsCode += await processImports(setupJsCode);
|
||||
}
|
||||
pathToMdDirectoryInPublic = `${publicDir}/${parsedPath}`;
|
||||
currentMarkdownFileMdJsStoryName = `${mdJsStoriesFileNameWithoutExtension}--${
|
||||
path.basename(currentMarkdownFile).split('.md')[0]
|
||||
}.js`;
|
||||
const newName = path.join(pathToMdDirectoryInPublic, currentMarkdownFileMdJsStoryName);
|
||||
await fs.promises.mkdir(pathToMdDirectoryInPublic, { recursive: true });
|
||||
await fs.promises.writeFile(newName, parsedSetupJsCode, 'utf8');
|
||||
|
||||
// unifiedjs expects node changes to be made on the given node...
|
||||
await init;
|
||||
visit(tree, 'text', nodeCodeVisitor);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
copyMdjsStories,
|
||||
};
|
||||
5
src/utils/remark-plugings/copyMdjsStories/index.js
Normal file
5
src/utils/remark-plugings/copyMdjsStories/index.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const { copyMdjsStories } = require('./copyMdjsStories.js');
|
||||
|
||||
module.exports = {
|
||||
copyMdjsStories,
|
||||
};
|
||||
1
src/utils/remark-plugings/copyMdjsStories/package.json
Normal file
1
src/utils/remark-plugings/copyMdjsStories/package.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
const { updateMainTagsForMdjsStories } = require('./updateMainTagsForMdjsStories.js');
|
||||
|
||||
module.exports = {
|
||||
updateMainTagsForMdjsStories,
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const { init, parse } = require('es-module-lexer');
|
||||
const path = require('path');
|
||||
|
||||
let visit;
|
||||
(async () => {
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const result = await import('unist-util-visit');
|
||||
visit = result.visit;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @param {string} code
|
||||
* @param {{type: StoryTypes}} options
|
||||
* @returns {Story}
|
||||
*/
|
||||
function extractStoryData(code, { type = 'js' } = { type: 'js' }) {
|
||||
const parsed = parse(code);
|
||||
const key = parsed[1][0];
|
||||
const name = key;
|
||||
return { key, name, code, type };
|
||||
}
|
||||
|
||||
function updateMainTagsForMdjsStories() {
|
||||
let parsedPath = '';
|
||||
|
||||
/**
|
||||
* @param {UnistNode} _node
|
||||
*/
|
||||
const nodeCodeVisitor = _node => {
|
||||
const node = /** @type {UnistNode & {[key: string]: unknown}} */ (_node);
|
||||
if (node.lang === 'js' && node.meta === 'preview-story' && typeof node.value === 'string') {
|
||||
const storyData = extractStoryData(node.value);
|
||||
const mainTagName = storyData.name;
|
||||
let mdFileName = path.basename(parsedPath);
|
||||
mdFileName = mdFileName.replaceAll('-', '_');
|
||||
node.value = node.value.replace(mainTagName, `${mainTagName}__${mdFileName}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Node} tree
|
||||
* @param {VFileOptions} file
|
||||
*/
|
||||
async function transformer(tree, file) {
|
||||
const currentMarkdownFile = file.history[0];
|
||||
|
||||
if (currentMarkdownFile) {
|
||||
const leftSideParsedPath = currentMarkdownFile.split('src/content/')[1];
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
parsedPath = leftSideParsedPath.split('.md')[0];
|
||||
}
|
||||
|
||||
// unifiedjs expects node changes to be made on the given node...
|
||||
await init;
|
||||
// @ts-ignore
|
||||
visit(tree, 'code', nodeCodeVisitor);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
updateMainTagsForMdjsStories,
|
||||
};
|
||||
|
|
@ -1,23 +1,3 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"lib": ["es2017", "dom"],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"strict": true,
|
||||
"noImplicitThis": true,
|
||||
"composite": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"alwaysStrict": true,
|
||||
"types": ["node", "mocha", "chai", "sinon"],
|
||||
"esModuleInterop": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"skipLibCheck": true,
|
||||
"incremental": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true
|
||||
}
|
||||
"extends": "astro/tsconfigs/base"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue