@microbit/ui-code-view 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +144 -2
- package/dist/index.d.ts +13 -0
- package/dist/index.js +83 -0
- package/lang/ui.en-US.json +1 -0
- package/lang/ui.en.json +10 -0
- package/package.json +57 -4
- package/style.css +127 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Micro:bit Educational Foundation and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,145 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @microbit/ui-code-view
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read-only, syntax-highlighted code views for micro:bit web apps, styled to
|
|
4
|
+
match the editors the code comes from. Successor to
|
|
5
|
+
`@microbit-foundation/react-code-view`.
|
|
6
|
+
|
|
7
|
+
## What's here
|
|
8
|
+
|
|
9
|
+
- **`PythonEditorCodeView`** — Python, styled like the micro:bit Python
|
|
10
|
+
Editor.
|
|
11
|
+
- **`MakeCodeJavaScriptCodeView`** — MakeCode JavaScript, styled like
|
|
12
|
+
MakeCode's JavaScript view.
|
|
13
|
+
|
|
14
|
+
Both take a `code` prop and show line numbers. An optional `className` goes on
|
|
15
|
+
the outermost element, for example to make the background transparent. The
|
|
16
|
+
stylesheet's rules for that element (background, colour, font, padding) have
|
|
17
|
+
zero specificity, so any class wins over them whatever the stylesheet order.
|
|
18
|
+
Highlighting is done by [highlight.js](https://highlightjs.org/), which is a
|
|
19
|
+
regular dependency.
|
|
20
|
+
|
|
21
|
+
The view is always left to right (`dir="ltr"`), whatever the page direction,
|
|
22
|
+
and marked `translate="no"` so browser translation leaves the code alone.
|
|
23
|
+
While the code is too wide for the view, it is a focusable group named
|
|
24
|
+
"Python code" or "JavaScript code", so keyboard users can scroll it; code
|
|
25
|
+
that fits adds no tab stop. Line numbers are hidden from screen readers.
|
|
26
|
+
|
|
27
|
+
## Consumption
|
|
28
|
+
|
|
29
|
+
Unlike the other packages in this repo, this one **ships built** (ES modules
|
|
30
|
+
plus type declarations) and is styled by a **plain stylesheet**, so it works
|
|
31
|
+
in apps with or without Panda CSS. It supports React 17, 18 and 19, and
|
|
32
|
+
needs `react-intl` (6 or 7), a peer dependency, for its accessible names.
|
|
33
|
+
|
|
34
|
+
1. Install the package, and `react-intl` if the app doesn't already have it.
|
|
35
|
+
2. Import the stylesheet once.
|
|
36
|
+
|
|
37
|
+
In an app set up as the [`@microbit/ui` README](../ui/README.md)
|
|
38
|
+
describes, import it into the `vendor` cascade layer of your entry
|
|
39
|
+
stylesheet, so it beats Panda's preflight but loses to your own styling:
|
|
40
|
+
|
|
41
|
+
```css
|
|
42
|
+
@layer reset, vendor, base, tokens, recipes, utilities;
|
|
43
|
+
|
|
44
|
+
@import "@microbit/ui/reset.css" layer(reset);
|
|
45
|
+
@import "@microbit/ui-code-view/style.css" layer(vendor);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Elsewhere, import it as you would any other stylesheet:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import "@microbit/ui-code-view/style.css";
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. Render the components:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { PythonEditorCodeView } from "@microbit/ui-code-view";
|
|
58
|
+
|
|
59
|
+
<PythonEditorCodeView code={"from microbit import *\n"} />;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
They must be inside an `IntlProvider`.
|
|
63
|
+
|
|
64
|
+
4. **Strings**: the components carry no inline English, so compile this
|
|
65
|
+
package's catalogs into your per-locale catalogs alongside your own,
|
|
66
|
+
**English included** (message ids are namespaced `ui-code-view.`). With
|
|
67
|
+
[`@microbit/i18n-tools`](../i18n-tools), list the package in your catalog
|
|
68
|
+
config and `microbit-i18n compile` merges it, backfilling English for
|
|
69
|
+
locales without a translation:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
catalogs: [
|
|
73
|
+
{
|
|
74
|
+
source: "lang/ui.en.json",
|
|
75
|
+
out: "app/messages/ui.{lang}.json",
|
|
76
|
+
packages: ["@microbit/ui-code-view"],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Without the catalog, the accessible names render as message ids.
|
|
82
|
+
|
|
83
|
+
The stylesheet loads Source Code Pro from `fonts.microbit.org` for the Python
|
|
84
|
+
view. Its class names (`mb-code-view…` and highlight.js's `hljs-…`) are part
|
|
85
|
+
of this package's API.
|
|
86
|
+
|
|
87
|
+
## Colours
|
|
88
|
+
|
|
89
|
+
The Python view's syntax colours are CSS variables shared with the Python
|
|
90
|
+
Editor's CodeMirror theme:
|
|
91
|
+
|
|
92
|
+
| Variable | Used for | OSS default |
|
|
93
|
+
| --------------------------- | -------------------------------- | ---------------------- |
|
|
94
|
+
| `--colors-code-default` | Plain text | `black` |
|
|
95
|
+
| `--colors-code-keyword` | Keywords | `darkblue` |
|
|
96
|
+
| `--colors-code-string` | Strings | `green` |
|
|
97
|
+
| `--colors-code-comment` | Comments | `gray` |
|
|
98
|
+
| `--colors-code-literal` | `True`, `False`, `None`, numbers | `darkgreen` |
|
|
99
|
+
| `--colors-code-line-number` | Line numbers | `#b4b4b4` (`gray.350`) |
|
|
100
|
+
|
|
101
|
+
In a Panda app they come from the `code.*` tokens in `@microbit/ui`'s base
|
|
102
|
+
preset, so a brand preset that sets those tokens restyles this view and the
|
|
103
|
+
editor together. Without Panda, the stylesheet falls back to the OSS defaults;
|
|
104
|
+
set the variables in your own CSS (for example on `:root`) to change them.
|
|
105
|
+
|
|
106
|
+
The MakeCode view's colours are fixed: they copy MakeCode's own look.
|
|
107
|
+
|
|
108
|
+
## Migrating from `@microbit-foundation/react-code-view`
|
|
109
|
+
|
|
110
|
+
- `PythonCodeRendering` is now `PythonEditorCodeView`, and
|
|
111
|
+
`MakeCodeJavaScriptRendering` is now `MakeCodeJavaScriptCodeView`.
|
|
112
|
+
- The stylesheet is `@microbit/ui-code-view/style.css`.
|
|
113
|
+
- The components now need an `IntlProvider` and this package's compiled
|
|
114
|
+
catalogs (see [Consumption](#consumption)).
|
|
115
|
+
- Style the view through `className` rather than by targeting its inner
|
|
116
|
+
elements. The old package rendered a single `<pre>`; the new markup is
|
|
117
|
+
different, so selectors such as `& pre` no longer reach the background.
|
|
118
|
+
- The Python view's colours are now the OSS defaults unless the app sets
|
|
119
|
+
them (see [Colours](#colours)). To keep the micro:bit palette, set the
|
|
120
|
+
`code.*` tokens in your brand preset or the variables in your CSS.
|
|
121
|
+
- Line numbers stay in place when long lines scroll sideways.
|
|
122
|
+
- The view has no outer margin. The old one rendered a bare `<pre>`, so it
|
|
123
|
+
picked up the browser's default margin unless the app reset it.
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
Stories live in `stories/` here but are rendered by the repo's Storybook
|
|
128
|
+
harness, [`apps/storybook`](../../apps/storybook). Run it from the repo root:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run storybook
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`npm run build -w @microbit/ui-code-view` compiles to `dist/`; it also runs on
|
|
135
|
+
`npm install` and before packing.
|
|
136
|
+
|
|
137
|
+
## Releases
|
|
138
|
+
|
|
139
|
+
Publish a GitHub release with a tag of the form `ui-code-view-vX.Y.Z`. The
|
|
140
|
+
build workflow routes the release to this package by the tag prefix and
|
|
141
|
+
publishes it. This package is versioned independently of `@microbit/ui`.
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
[MIT](LICENSE.md) © Micro:bit Educational Foundation and contributors.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CodeViewProps {
|
|
2
|
+
code: string;
|
|
3
|
+
/**
|
|
4
|
+
* Added to the outermost element, e.g. to change the background. Any class
|
|
5
|
+
* wins over the stylesheet's rules for that element, which are
|
|
6
|
+
* zero-specificity, so stylesheet order and cascade layers don't matter.
|
|
7
|
+
*/
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Python, styled like the micro:bit Python Editor. */
|
|
11
|
+
export declare const PythonEditorCodeView: (props: CodeViewProps) => import("react").JSX.Element;
|
|
12
|
+
/** MakeCode's JavaScript (a TypeScript subset), styled like its code view. */
|
|
13
|
+
export declare const MakeCodeJavaScriptCodeView: (props: CodeViewProps) => import("react").JSX.Element;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* (c) 2026, Micro:bit Educational Foundation and contributors
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: MIT
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* ui-code-view — read-only, syntax-highlighted code in the style of the
|
|
9
|
+
* micro:bit editors. Styled by the package's plain stylesheet
|
|
10
|
+
* (`@microbit/ui-code-view/style.css`), not Panda.
|
|
11
|
+
*/
|
|
12
|
+
import hljs from "highlight.js/lib/core";
|
|
13
|
+
import python from "highlight.js/lib/languages/python";
|
|
14
|
+
import typescript from "highlight.js/lib/languages/typescript";
|
|
15
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
16
|
+
import { useIntl } from "react-intl";
|
|
17
|
+
// A private instance so an app's own highlight.js configuration (e.g. a
|
|
18
|
+
// classPrefix, which would break style.css) can't reach these components.
|
|
19
|
+
const highlighter = hljs.newInstance();
|
|
20
|
+
highlighter.registerLanguage("python", python);
|
|
21
|
+
highlighter.registerLanguage("typescript", typescript);
|
|
22
|
+
/**
|
|
23
|
+
* Whether the element currently scrolls sideways. Safari doesn't make scroll
|
|
24
|
+
* containers keyboard-focusable, so a scrolling view needs a tabIndex to be
|
|
25
|
+
* reachable without a mouse; one that fits stays out of the tab order.
|
|
26
|
+
*/
|
|
27
|
+
const useScrollsHorizontally = (ref, content) => {
|
|
28
|
+
const [scrolls, setScrolls] = useState(false);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const element = ref.current;
|
|
31
|
+
if (!element) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const update = () => setScrolls(element.scrollWidth > element.clientWidth);
|
|
35
|
+
update();
|
|
36
|
+
const observer = new ResizeObserver(update);
|
|
37
|
+
observer.observe(element);
|
|
38
|
+
// A web font arriving changes the content's width but not the element's.
|
|
39
|
+
let active = true;
|
|
40
|
+
void document.fonts?.ready.then(() => active && update());
|
|
41
|
+
return () => {
|
|
42
|
+
active = false;
|
|
43
|
+
observer.disconnect();
|
|
44
|
+
};
|
|
45
|
+
}, [ref, content]);
|
|
46
|
+
return scrolls;
|
|
47
|
+
};
|
|
48
|
+
const CodeView = ({ code: source, className, language, variant, label, }) => {
|
|
49
|
+
const intl = useIntl();
|
|
50
|
+
// The HTML parser turns a lone \r into a line break, so counting only \n
|
|
51
|
+
// would number fewer lines than the code shows.
|
|
52
|
+
const code = source.replace(/\r\n?/g, "\n");
|
|
53
|
+
// A trailing newline ends the last line rather than starting another.
|
|
54
|
+
const lineNumbers = code
|
|
55
|
+
.replace(/\n$/, "")
|
|
56
|
+
.split("\n")
|
|
57
|
+
.map((_, i) => i + 1)
|
|
58
|
+
.join("\n");
|
|
59
|
+
// highlight.js escapes the source; its output contains only its own spans.
|
|
60
|
+
const html = useMemo(() => highlighter.highlight(code, { language, ignoreIllegals: true }).value, [code, language]);
|
|
61
|
+
const codeRef = useRef(null);
|
|
62
|
+
const scrolls = useScrollsHorizontally(codeRef, html);
|
|
63
|
+
// Browsers drop focus from an element that stops being focusable, so a
|
|
64
|
+
// resize or zoom that ends the scrolling mustn't take the tabIndex away
|
|
65
|
+
// until focus moves on.
|
|
66
|
+
const [focused, setFocused] = useState(false);
|
|
67
|
+
const focusable = scrolls || focused;
|
|
68
|
+
// Line numbers are a separate column rather than a prefix on each line so
|
|
69
|
+
// highlight.js's output never needs splitting: its spans for multi-line
|
|
70
|
+
// strings and comments cross line breaks.
|
|
71
|
+
return (
|
|
72
|
+
// Code reads left to right whatever the page direction, and browser
|
|
73
|
+
// translation would rewrite identifiers and comments.
|
|
74
|
+
_jsxs("div", { className: `mb-code-view mb-code-view--${variant}${className ? ` ${className}` : ""}`, dir: "ltr", translate: "no", children: [_jsx("pre", { className: "mb-code-view__gutter", "aria-hidden": "true", children: lineNumbers }), _jsx("pre", { ref: codeRef, className: "mb-code-view__code", onFocus: () => setFocused(true), onBlur: () => setFocused(false), ...(focusable && {
|
|
75
|
+
tabIndex: 0,
|
|
76
|
+
role: "group",
|
|
77
|
+
"aria-label": intl.formatMessage({ id: label }),
|
|
78
|
+
}), children: _jsx("code", { dangerouslySetInnerHTML: { __html: html } }) })] }));
|
|
79
|
+
};
|
|
80
|
+
/** Python, styled like the micro:bit Python Editor. */
|
|
81
|
+
export const PythonEditorCodeView = (props) => (_jsx(CodeView, { ...props, language: "python", variant: "python-editor", label: "ui-code-view.python-label" }));
|
|
82
|
+
/** MakeCode's JavaScript (a TypeScript subset), styled like its code view. */
|
|
83
|
+
export const MakeCodeJavaScriptCodeView = (props) => (_jsx(CodeView, { ...props, language: "typescript", variant: "makecode-javascript", label: "ui-code-view.makecode-javascript-label" }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/lang/ui.en.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ui-code-view.makecode-javascript-label": {
|
|
3
|
+
"defaultMessage": "JavaScript code",
|
|
4
|
+
"description": "Accessible name for a scrollable, read-only view of a MakeCode project's JavaScript"
|
|
5
|
+
},
|
|
6
|
+
"ui-code-view.python-label": {
|
|
7
|
+
"defaultMessage": "Python code",
|
|
8
|
+
"description": "Accessible name for a scrollable, read-only view of Python code"
|
|
9
|
+
}
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microbit/ui-code-view",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Read-only, syntax-highlighted code views styled like the micro:bit Python Editor and MakeCode's JavaScript view. Plain CSS, no Panda setup needed; see README.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/microbit-foundation/ui.git",
|
|
10
|
+
"directory": "packages/ui-code-view"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./style.css": "./style.css",
|
|
18
|
+
"./lang/*": "./lang/*"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"lang",
|
|
23
|
+
"style.css",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE.md"
|
|
26
|
+
],
|
|
27
|
+
"sideEffects": [
|
|
28
|
+
"**/*.css"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
35
|
+
"prepare": "npm run build",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"test": "vitest run"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"highlight.js": "^11.12.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
44
|
+
"react-intl": "^6.6.8 || ^7.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@storybook/react-vite": "^10.5.2",
|
|
48
|
+
"@testing-library/react": "^16.3.2",
|
|
49
|
+
"@types/react": "^18.3.3",
|
|
50
|
+
"@types/react-dom": "^18.3.0",
|
|
51
|
+
"@vitejs/plugin-react": "^5.2.0",
|
|
52
|
+
"jsdom": "^29.1.1",
|
|
53
|
+
"react": "^18.3.1",
|
|
54
|
+
"react-dom": "^18.3.1",
|
|
55
|
+
"react-intl": "^6.6.8",
|
|
56
|
+
"typescript": "^5.4.2",
|
|
57
|
+
"vitest": "^4.1.10"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/style.css
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* (c) 2026, Micro:bit Educational Foundation and contributors
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*
|
|
6
|
+
* Plain CSS so apps without Panda can use the package. Panda apps import it
|
|
7
|
+
* into their `vendor` cascade layer, where it beats the preflight's pre/code
|
|
8
|
+
* rules but loses to app styling.
|
|
9
|
+
*/
|
|
10
|
+
@font-face {
|
|
11
|
+
font-family: "Source Code Pro";
|
|
12
|
+
font-style: normal;
|
|
13
|
+
font-weight: 500;
|
|
14
|
+
src: url("https://fonts.microbit.org/source-code-pro/v14/source-code-pro-v14-latin-500.woff2")
|
|
15
|
+
format("woff2");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Rules on the outer element are zero-specificity so a consumer's className
|
|
19
|
+
beats them in apps without cascade layers too, whatever the stylesheet
|
|
20
|
+
order. The resets below keep their specificity: they must still beat
|
|
21
|
+
app-wide pre/code rules. */
|
|
22
|
+
:where(.mb-code-view) {
|
|
23
|
+
display: grid;
|
|
24
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: 20px 10px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Resets so app-wide pre/code styling can't throw the two columns out of
|
|
30
|
+
line with each other. */
|
|
31
|
+
.mb-code-view__gutter,
|
|
32
|
+
.mb-code-view__code,
|
|
33
|
+
.mb-code-view__code code {
|
|
34
|
+
margin: 0;
|
|
35
|
+
padding: 0;
|
|
36
|
+
border: none;
|
|
37
|
+
background: none;
|
|
38
|
+
color: inherit;
|
|
39
|
+
font: inherit;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.mb-code-view__gutter {
|
|
43
|
+
/* Explicit because Panda's preflight makes everything border-box. */
|
|
44
|
+
box-sizing: content-box;
|
|
45
|
+
min-width: 2em;
|
|
46
|
+
text-align: right;
|
|
47
|
+
-webkit-user-select: none;
|
|
48
|
+
user-select: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.mb-code-view__code {
|
|
52
|
+
overflow-x: auto;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* The @microbit/ui focus ring. The view's padding leaves room for it. */
|
|
56
|
+
.mb-code-view__code:focus-visible {
|
|
57
|
+
outline: 2px solid var(--colors-focus-ring, #1a1a1a);
|
|
58
|
+
outline-offset: 2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Colours come from the `code.*` tokens in @microbit/ui's base preset, so a
|
|
62
|
+
brand preset restyles this view and the Python Editor together. The
|
|
63
|
+
fallbacks repeat the base preset's OSS defaults for apps without Panda. */
|
|
64
|
+
:where(.mb-code-view--python-editor) {
|
|
65
|
+
background: #fcfcfc;
|
|
66
|
+
color: var(--colors-code-default, black);
|
|
67
|
+
font-family: "Source Code Pro", monospace;
|
|
68
|
+
font-size: 1.2rem;
|
|
69
|
+
line-height: 1.4;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.mb-code-view--python-editor .mb-code-view__gutter {
|
|
73
|
+
padding-right: 1em;
|
|
74
|
+
color: var(--colors-code-line-number, #b4b4b4);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.mb-code-view--python-editor .hljs-keyword {
|
|
78
|
+
color: var(--colors-code-keyword, darkblue);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.mb-code-view--python-editor .hljs-string {
|
|
82
|
+
color: var(--colors-code-string, green);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.mb-code-view--python-editor .hljs-comment {
|
|
86
|
+
color: var(--colors-code-comment, gray);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* The editor has no number colour: CodeMirror's Python grammar treats numbers
|
|
90
|
+
as literals. */
|
|
91
|
+
.mb-code-view--python-editor .hljs-literal,
|
|
92
|
+
.mb-code-view--python-editor .hljs-number {
|
|
93
|
+
color: var(--colors-code-literal, darkgreen);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:where(.mb-code-view--makecode-javascript) {
|
|
97
|
+
background: #ecf0f1;
|
|
98
|
+
color: #000000;
|
|
99
|
+
font-family: Monaco, Menlo, "Ubuntu Mono", Consolas, source-code-pro,
|
|
100
|
+
monospace;
|
|
101
|
+
/* 19px/26px at the default root size, scaling with the user's setting. */
|
|
102
|
+
font-size: 1.1875rem;
|
|
103
|
+
line-height: calc(26 / 19);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.mb-code-view--makecode-javascript .mb-code-view__gutter {
|
|
107
|
+
padding-right: 1.6em;
|
|
108
|
+
color: #2c3e50;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.mb-code-view--makecode-javascript .hljs-keyword,
|
|
112
|
+
.mb-code-view--makecode-javascript .hljs-built_in,
|
|
113
|
+
.mb-code-view--makecode-javascript .hljs-literal {
|
|
114
|
+
color: #0000ff;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.mb-code-view--makecode-javascript .hljs-string {
|
|
118
|
+
color: #a31515;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.mb-code-view--makecode-javascript .hljs-comment {
|
|
122
|
+
color: #008000;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.mb-code-view--makecode-javascript .hljs-number {
|
|
126
|
+
color: #008080;
|
|
127
|
+
}
|