Skip to content

Commit

Permalink
🖲 Add button role (#1773)
Browse files Browse the repository at this point in the history
* Add button directive

Co-authored-by: Angus Hollands <[email protected]>

* Update index.ts

* Change from directive to role

* Delete changelog

* Fix linting

* Remove test

* Add buttonRoles test

* refactor: use 'class' exclusively for buttons

* chore: add changeset

* Update doc

* Add buttonRole to directives plugin

* Add buttonRole to roles reference

* Add button docs

* Typo

* Typo

* Minor edit

* docs: use MyST directive for extensions

* docs: use myst:role instead of myst:directive

* fix: correct heading depth

---------

Co-authored-by: Angus Hollands <[email protected]>
Co-authored-by: Angus Hollands <[email protected]>
  • Loading branch information
3 people authored Jan 27, 2025
1 parent 3b4a5f8 commit fad8f67
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 36 deletions.
7 changes: 7 additions & 0 deletions .changeset/lazy-houses-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"myst-ext-button": patch
"myst-spec-ext": patch
"myst-cli": patch
---

Add new button role
3 changes: 2 additions & 1 deletion docs/directives.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { mystParse } from 'myst-parser';
import { defaultDirectives } from 'myst-directives';
import { defaultRoles } from 'myst-roles';
import { cardDirective } from 'myst-ext-card';
import { buttonRole } from 'myst-ext-button';
import { gridDirectives } from 'myst-ext-grid';
import { proofDirective } from 'myst-ext-proof';
import { exerciseDirectives } from 'myst-ext-exercise';
Expand All @@ -17,7 +18,7 @@ const allDirectives = [
cardDirective,
proofDirective,
];
const allRoles = [...defaultRoles];
const allRoles = [...defaultRoles, buttonRole];

/**
* @param {import('myst-common').OptionDefinition} option
Expand Down
55 changes: 21 additions & 34 deletions docs/dropdowns-cards-and-tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ You can also hide the body of your admonition blocks so that users must click a
To turn an admonition into a dropdown, add the option `:class: dropdown` to them. See [](#admonition-dropdown) for more information.
```

### Cards
## Cards

Cards provide an easy way for you to content into a standard “header”, “body”, “footer” structure that has a similar alignment and visual style. It is useful for creating galleries or high-visibility collections of links and information.
For example, a card with a header, title, body, and footer:
Expand Down Expand Up @@ -76,25 +76,24 @@ Footer
Note that, card headers and footers are optional. If you don’t include ^^^ or +++ in your card, they will not show up.
````
:::{myst:directive} card
:::

### `card` reference

**Arguments** _(optional, markdown)_
: The `card` can take a single argument that is the title as a string.

**Options**
: No options for the `card` are required
## Buttons

header _(optional, markdown)_
: Styled content at the top of the card
A button is an element with text content that triggers an action to navigate to an internal or external reference upon a user click. Use the {myst:role}`button` role followed by the text content and target path to create a button.

footer _(optional, markdown)_
: Styled content at the bottom of the card
```{myst}
{button}`MyST Role Spec <roles.md>`
```

link _(optional, string)_
: If given, clicking the card will direct you to the URL given here.
```{myst}
{button}`MyST-MD GitHub <https://github.com/jupyter-book/mystmd>`
```
:::{myst:role} button
:::

### Grids
## Grids

Grids allow you to structure arbitrary chunks of content in a grid-like system.

Expand Down Expand Up @@ -124,6 +123,9 @@ Execute notebook cells, store results, and insert outputs across pages.
::::
```

:::{myst:directive} grid
:::

## Tabs

You can also produce tabbed content. This allows you to display a variety of tabbed content blocks that users can click on.
Expand Down Expand Up @@ -154,23 +156,8 @@ Synced content for tab 2
```
````

### `tab-item` reference

**Arguments** _(required: `1`, string)_
: The `tab-item` requires a single argument that is the title as a string.

```{warning}
:class: dropdown
# Note: the `tab-item` title is not currently not parsed

The current implementation does not parse the tab title properly, and markup in this field will not be parsed.
```

**Options**
: No options for the `tab-item` are required

sync _(optional, string)_
: A key that is used to sync the selected tab across multiple tab-sets.
:::{myst:directive} tab-set
:::

selected _(flag, no-value)_
: a flag indicating whether the tab should be selected by default.
:::{myst:directive} tab-item
:::
3 changes: 3 additions & 0 deletions docs/roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ description: A full list of the roles included in MyST Markdown by default.
:::{myst:role} abbreviation
:::

:::{myst:role} button
:::

:::{myst:role} chemicalFormula
:::

Expand Down
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/myst-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"myst-common": "^1.7.7",
"myst-config": "^1.7.7",
"myst-execute": "^0.1.2",
"myst-ext-button": "^0.0.0",
"myst-ext-card": "^1.0.9",
"myst-ext-exercise": "^1.0.9",
"myst-ext-grid": "^1.0.9",
Expand Down
3 changes: 2 additions & 1 deletion packages/myst-cli/src/process/myst.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { mystParse } from 'myst-parser';
import { buttonRole } from 'myst-ext-button';
import { cardDirective } from 'myst-ext-card';
import { gridDirectives } from 'myst-ext-grid';
import { proofDirective } from 'myst-ext-proof';
Expand Down Expand Up @@ -47,7 +48,7 @@ export function parseMyst(
extensions: {
frontmatter: !opts?.ignoreFrontmatter,
},
roles: [...(session.plugins?.roles ?? [])],
roles: [buttonRole, ...(session.plugins?.roles ?? [])],
vfile,
});
logMessagesFromVFile(session, vfile);
Expand Down
4 changes: 4 additions & 0 deletions packages/myst-ext-button/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['curvenote'],
};
3 changes: 3 additions & 0 deletions packages/myst-ext-button/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# myst-ext-button

`mystmd` extension for `button` role
41 changes: 41 additions & 0 deletions packages/myst-ext-button/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "myst-ext-button",
"version": "0.0.0",
"sideEffects": false,
"license": "MIT",
"description": "MyST extension for button role",
"author": "Jenny Wong <[email protected]>",
"homepage": "https://github.com/jupyter-book/mystmd/tree/main/packages/myst-ext-button",
"type": "module",
"exports": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jupyter-book/mystmd.git"
},
"scripts": {
"clean": "rimraf dist",
"lint": "eslint \"src/**/!(*.spec).ts\" -c ./.eslintrc.cjs",
"lint:format": "npx prettier --check \"src/**/*.ts\"",
"test": "vitest run",
"test:watch": "vitest watch",
"build:esm": "tsc",
"build": "npm-run-all -l clean -p build:esm"
},
"bugs": {
"url": "https://github.com/jupyter-book/mystmd/issues"
},
"dependencies": {
"myst-common": "^1.7.2",
"myst-spec-ext": "^1.7.6"
},
"devDependencies": {
"myst-parser": "^1.5.7"
}
}
28 changes: 28 additions & 0 deletions packages/myst-ext-button/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { RoleSpec, RoleData, GenericNode } from 'myst-common';
import type { Link } from 'myst-spec-ext';

const REF_PATTERN = /^(.+?)<([^<>]+)>$/;

export const buttonRole: RoleSpec = {
name: 'button',
doc: 'Button element with an action to navigate to internal or external links.',
body: {
type: String,
doc: 'The body of the button.',
required: true,
},
run(data: RoleData): GenericNode[] {
const body = data.body as string;
const match = REF_PATTERN.exec(body);
const [, modified, rawLabel] = match ?? [];
const url = rawLabel ?? body;
const node: Link = {
type: 'link',
url,
children: [],
class: 'button', // TODO: allow users to extend this
};
if (modified) node.children = [{ type: 'text', value: modified.trim() }];
return [node];
},
};
33 changes: 33 additions & 0 deletions packages/myst-ext-button/tests/button.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from 'vitest';
import { buttonRole } from '../src';
import { VFile } from 'vfile';

describe('Button component', () => {
it('should process button role correctly', () => {
const result = buttonRole.run(
{ name: 'button', body: 'Click me<http://example.com>' },
new VFile(),
);

expect(result).toEqual([
{
type: 'link',
class: 'button',
url: 'http://example.com',
children: [{ type: 'text', value: 'Click me' }],
},
]);
});

it('should process button role without label correctly', () => {
const result = buttonRole.run({ name: 'button', body: 'http://example.com' }, new VFile());
expect(result).toEqual([
{
type: 'link',
class: 'button',
url: 'http://example.com',
children: [],
},
]);
});
});
8 changes: 8 additions & 0 deletions packages/myst-ext-button/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../tsconfig/base.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["."],
"exclude": ["dist", "build", "node_modules", "src/**/*.spec.ts", "tests"]
}
2 changes: 2 additions & 0 deletions packages/myst-spec-ext/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export type CrossReference = SpecCrossReference & {
dataUrl?: string;
remoteBaseUrl?: string;
html_id?: string;
class?: Image['class'];
};

export type Link = SpecLink & {
Expand All @@ -284,6 +285,7 @@ export type Link = SpecLink & {
static?: true;
protocol?: string;
error?: true;
class?: Image['class'];
};

// Search types
Expand Down

0 comments on commit fad8f67

Please sign in to comment.