timvir 0.2.22 → 0.2.25

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.
@@ -57,6 +57,7 @@ function Code(props, ref) {
57
57
  ...rest
58
58
  } = block.props;
59
59
  const [state, mutate] = useImmer({
60
+ settled: false,
60
61
  mouseOver: false,
61
62
  copiedToClipboard: false,
62
63
  /*
@@ -89,13 +90,14 @@ function Code(props, ref) {
89
90
  }))
90
91
  });
91
92
  mutate(draft => {
93
+ draft.settled = true;
92
94
  draft.html = html;
93
95
  });
94
96
  })();
95
97
  }, [mutate, children, language]);
96
98
  return /*#__PURE__*/React.createElement(Root, {
97
99
  ref: ref,
98
- className: cx_default("timvir-b-Code", classes.root, fullWidth && Page.fullWidth),
100
+ className: cx_default("timvir-b-Code", !state.settled && "timvir-unsettled", classes.root, fullWidth && Page.fullWidth),
99
101
  ...rest
100
102
  }, /*#__PURE__*/React.createElement("div", {
101
103
  className: cx_default("timvir-b-Code-container", className, theme, classes.code, fullWidth && classes.fullWidth)
@@ -1,42 +1,41 @@
1
- import { Exhibit } from "..";
2
1
  import { Code } from "timvir/blocks";
3
2
 
4
3
  # Exhibit
5
4
 
6
- The `<Exhibit>` is a block which is used to present something–usually a React component–in a nice way. It's a way to say:
5
+ The `<Exhibit>` is a block which presents something–usually a React component–in a nice way.
7
6
 
8
- <Sample variant="basic" />
7
+ The presented element is placed on top of a checkered background.
8
+ This helps illustrating which parts of the element are transparent, or if the element comes with a specific background color.
9
9
 
10
- <Code language="jsx">
11
- <Sample variant="basic" as="source/markup" />
12
- </Code>
10
+ A bit of padding is included all around the presented element.
11
+ Together with the checkered background, it makes the `<Exhibit>` block stand out next plain text or other blocks.
12
+ You can tweak the bleed size, or disable the bleed altogether if you want to draw attention to the exact box size of the presented element itself.
13
13
 
14
- Think of it as a `<figure>` + `<figcaption>` for React components.
14
+ The caption, if provided, is placed below the block.
15
+ Use it to explain what is being presented, or provide contex around it.
16
+ Think of the `<Exhibit>` block as a `<figure>` + `<figcaption>` for React components.
17
+
18
+ <Sample variant="basic" />
15
19
 
16
- Add a title to the exhibit if it helps the reader to understand the exhibit better. The title is placed snuggly to the exhibit.
20
+ ## Usage
17
21
 
18
- <Exhibit title="This Is Not A Button" caption="It's an input element, of type text">
19
- <input type="text" placeholder="Type something…" style={{ boxSizing: "border-box", width: "100%", padding: 8 }} />
20
- </Exhibit>
22
+ Import `Exhibit` from the `timvir/blocks` module, then use in a Timvir mdx page like so:
23
+
24
+ <Code language="jsx">
25
+ <Sample variant="usage" as="source/markup" />
26
+ </Code>
21
27
 
22
28
  ## Bleed
23
29
 
24
30
  Use the `bleed` prop to control how much the checkered background extends beyond the box of the element itself.
31
+ If you set the bleed explicitly, it is not recommended to use more than 16px.
32
+ That is the page margin on small viewports and a bleed larger than that can mess with the page layout.
33
+
34
+ Setting bleed to zero (0) does not remove the checkered background.
35
+ It will still be visible behind your element (if your element is transparent).
36
+ To entirely remove any bleed and checkered background, render your element directly, without wrapping it in an `<Exhibit>`.
25
37
 
26
- <Exhibit bleed={0} caption="Bleed 0">
27
- <div
28
- style={{ height: 40, padding: "0 16px", background: "teal", color: "white", display: "flex", alignItems: "center" }}
29
- />
30
- </Exhibit>
31
-
32
- <Exhibit bleed={4} caption="Bleed 4">
33
- <div
34
- style={{ height: 40, padding: "0 16px", background: "teal", color: "white", display: "flex", alignItems: "center" }}
35
- />
36
- </Exhibit>
37
-
38
- <Exhibit bleed={12} caption="Bleed 12">
39
- <div
40
- style={{ height: 40, padding: "0 16px", background: "teal", color: "white", display: "flex", alignItems: "center" }}
41
- />
42
- </Exhibit>
38
+ <Sample variant="bleed" props={{ bleed: 0 }} />
39
+ <Sample variant="bleed" props={{ bleed: 8 }} />
40
+ <Sample variant="bleed" props={{ bleed: 16 }} />
41
+ <Sample variant="bleed" />
@@ -1,4 +1,3 @@
1
- import { useMDXComponents } from '@mdx-js/react';
2
1
  import { useBlock } from 'timvir/core';
3
2
  import * as React from 'react';
4
3
 
@@ -37,12 +36,7 @@ var cx_default = cx;
37
36
  const Root = "div";
38
37
  function Exhibit(props, ref) {
39
38
  const block = useBlock(props);
40
- const components = {
41
- h3: "h3",
42
- ...useMDXComponents()
43
- };
44
39
  const {
45
- title,
46
40
  caption,
47
41
  bleed,
48
42
  BackdropProps,
@@ -51,7 +45,7 @@ function Exhibit(props, ref) {
51
45
  style,
52
46
  ...rest
53
47
  } = block.props;
54
- return /*#__PURE__*/React.createElement(React.Fragment, null, title && /*#__PURE__*/React.createElement(components.h3, null, title), /*#__PURE__*/React.createElement(Root, {
48
+ return /*#__PURE__*/React.createElement(Root, {
55
49
  ref: ref,
56
50
  className: cx_default("timvir-b-Exhibit", className, classes.root),
57
51
  style: {
@@ -68,7 +62,7 @@ function Exhibit(props, ref) {
68
62
  }
69
63
  }, children), caption && /*#__PURE__*/React.createElement("div", {
70
64
  className: cx_default("timvir-b-Exhibit-caption", classes.caption)
71
- }, caption)));
65
+ }, caption));
72
66
  }
73
67
  var Exhibit$1 = /*#__PURE__*/React.forwardRef(Exhibit);
74
68
  const cssVariables = {
@@ -0,0 +1,5 @@
1
+ import * as React from "react";
2
+ import { Exhibit } from "..";
3
+ type Props = Partial<React.ComponentPropsWithoutRef<typeof Exhibit>>;
4
+ export default function Sample(props: Props): React.JSX.Element;
5
+ export {};
@@ -0,0 +1,2 @@
1
+ import * as React from "react";
2
+ export default function Sample(): React.JSX.Element;
@@ -1,16 +1,7 @@
1
1
  import { Grid } from "..";
2
2
  import { Exhibit } from "../../Exhibit";
3
- import { Image } from "../../../../../src/components/Image";
4
3
  import { fullWidth } from "timvir/core";
5
4
 
6
- import image1 from "../../../../../assets/khachik-simonian-nXOB-wh4Oyc-unsplash.jpg"
7
- import image2 from "../../../../../assets/frank-mckenna-4V8JxijgZ_c-unsplash.jpg"
8
- import image3 from "../../../../../assets/jay-mantri-TFyi0QOx08c-unsplash.jpg"
9
- import image4 from "../../../../../assets/jeremy-bishop-EwKXn5CapA4-unsplash.jpg"
10
- import image5 from "../../../../../assets/lukasz-szmigiel-jFCViYFYcus-unsplash.jpg"
11
- import image6 from "../../../../../assets/qingbao-meng-01_igFr7hd4-unsplash.jpg"
12
- import image7 from "../../../../../assets/v2osk-1Z2niiBPg5A-unsplash.jpg"
13
-
14
5
  # Grid
15
6
 
16
7
  > CSS grid with a predefined template (columns, gaps etc)
@@ -52,18 +43,6 @@ import image7 from "../../../../../assets/v2osk-1Z2niiBPg5A-unsplash.jpg"
52
43
  <div style={{ height: 100, background: "rgba(0,0,0,.2)", display: "flex", alignItems: "center", justifyContent: "center" }}>ITEM</div>
53
44
  </Grid>
54
45
 
55
- Combine `<Grid>` with the `<Image>` component.
56
-
57
- <Grid>
58
- <Image metadata={image1} img={{ src: image1.src }} sources={[]} />
59
- <Image metadata={image2} img={{ src: image2.src }} sources={[]} />
60
- <Image metadata={image3} img={{ src: image3.src }} sources={[]} />
61
- <Image metadata={image4} img={{ src: image4.src }} sources={[]} />
62
- <Image metadata={image5} img={{ src: image5.src }} sources={[]} />
63
- <Image metadata={image6} img={{ src: image6.src }} sources={[]} />
64
- <Image metadata={image7} img={{ src: image7.src }} sources={[]} />
65
- </Grid>
66
-
67
46
  Combine `<Grid>` with the `<Exhibit>` component.
68
47
 
69
48
  <Grid>
@@ -1,6 +1,7 @@
1
1
  import { useBlock, fullWidth } from 'timvir/core';
2
2
  import { useResizeObserverEntry, useResizeObserver } from 'timvir/hooks';
3
3
  import * as React from 'react';
4
+ import { useImmer } from 'use-immer';
4
5
  import { useMDXComponents } from '@mdx-js/react';
5
6
  import { Code } from 'timvir/blocks';
6
7
  import * as Icons from 'react-feather';
@@ -154,6 +155,9 @@ function Viewport(props, ref) {
154
155
  className,
155
156
  ...rest
156
157
  } = block.props;
158
+ const [state, mutate] = useImmer({
159
+ settled: false
160
+ });
157
161
 
158
162
  /*
159
163
  * The container measures the width of the main column. It is used to initialize
@@ -216,7 +220,7 @@ function Viewport(props, ref) {
216
220
  /*
217
221
  * Note this useEffect runs on each render. This is fine beause it doesn't do any
218
222
  * expensive computation, and the Viewport component only re-renders when the iframe
219
- * itself is changes height or the user resizes the width of the Viewport.
223
+ * itself changes height or the user resizes the width of the Viewport.
220
224
  */
221
225
  React.useEffect(() => {
222
226
  const document = iframeRef.current?.contentDocument;
@@ -244,12 +248,28 @@ function Viewport(props, ref) {
244
248
  style.innerHTML = "body { margin: 0 }";
245
249
  document.head.appendChild(style);
246
250
  }
251
+
252
+ /*
253
+ * 20ms after the height has been set, we consider this block settled. This
254
+ * time includes the 16ms CSS transition time, and a tiny bit more to allow
255
+ * for the content in the iframe itself to finish rendering.
256
+ */
257
+ React.useEffect(() => {
258
+ const timeoutId = setTimeout(() => {
259
+ mutate(draft => {
260
+ draft.settled = true;
261
+ });
262
+ }, 20);
263
+ return () => {
264
+ clearTimeout(timeoutId);
265
+ };
266
+ }, [mutate, height]);
247
267
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
248
268
  ref: containerRef
249
269
  }), /*#__PURE__*/React.createElement(Root, {
250
270
  ref: ref,
251
271
  ...rest,
252
- className: cx_default("timvir-b-Viewport", className, fullWidth, "r1ouu0bc")
272
+ className: cx_default("timvir-b-Viewport", !state.settled && "timvir-unsettled", className, fullWidth, "r1ouu0bc")
253
273
  }, /*#__PURE__*/React.createElement("div", {
254
274
  ref: svgRef,
255
275
  className: "d1uj09ka"
@@ -9,5 +9,5 @@ import { WebLink } from "..";
9
9
  <WebLink url="https://twitter.com" style={{ marginBottom: 16 }} />
10
10
  <WebLink url="https://figma.com" style={{ marginBottom: 16 }} />
11
11
  <WebLink url="https://www.framer.com/motion/" style={{ marginBottom: 16 }} />
12
- <WebLink url="https://formatjs.io" style={{ marginBottom: 16 }} />
12
+ <WebLink url="https://formatjs.github.io" style={{ marginBottom: 16 }} />
13
13
  <WebLink url="https://www.typescriptlang.org" style={{ marginBottom: 16 }} />
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useContext } from 'timvir/core';
3
+ import { useImmer } from 'use-immer';
3
4
 
4
5
  // src/css.ts
5
6
 
@@ -40,20 +41,29 @@ function WebLink(props, ref) {
40
41
  className,
41
42
  ...rest
42
43
  } = props;
43
- const [metadata, setMetadata] = React.useState(undefined);
44
+ const [state, mutate] = useImmer({
45
+ settled: false,
46
+ metadata: undefined
47
+ });
44
48
  const {
45
49
  unfurl = defaultUnfurl
46
50
  } = useContext().blocks?.WebLink ?? {};
47
51
  React.useEffect(() => {
48
- unfurl(url).then(setMetadata);
49
- }, [url, setMetadata]);
52
+ unfurl(url).then(metadata => {
53
+ mutate(draft => {
54
+ draft.settled = true;
55
+ draft.metadata = metadata;
56
+ });
57
+ });
58
+ }, [url, mutate]);
59
+ const metadata = state.metadata;
50
60
  const image = metadata?.open_graph?.images?.[0]?.url;
51
61
  return /*#__PURE__*/React.createElement(Root, {
52
62
  ref: ref,
53
63
  href: url,
54
64
  target: "_blank",
55
65
  rel: "noopener noreferrer",
56
- className: cx_default(className, classes.root),
66
+ className: cx_default("timvir-b-WebLink", !state.settled && "timvir-unsettled", className, classes.root),
57
67
  ...rest
58
68
  }, /*#__PURE__*/React.createElement("div", {
59
69
  className: classes.text
package/core/index.js CHANGED
@@ -49,14 +49,14 @@ const fullWidth = cx_default(noLayout, "f3c539b");
49
49
  /**
50
50
  * The underlying DOM element which is rendered by this component.
51
51
  */
52
- const Root$2 = "footer";
52
+ const Root$3 = "footer";
53
53
  function Footer(props, ref) {
54
54
  const {
55
55
  className,
56
56
  links,
57
57
  ...rest
58
58
  } = props;
59
- return /*#__PURE__*/React.createElement(Root$2, {
59
+ return /*#__PURE__*/React.createElement(Root$3, {
60
60
  ref: ref,
61
61
  className: cx_default(className, classes$7.root),
62
62
  ...rest
@@ -99,12 +99,13 @@ const classes$7 = {
99
99
 
100
100
  const theme = "t1amubg3";
101
101
 
102
+ const Root$2 = "div";
102
103
  function Action(props) {
103
104
  const {
104
105
  label,
105
106
  ...rest
106
107
  } = props;
107
- return /*#__PURE__*/React.createElement("div", {
108
+ return /*#__PURE__*/React.createElement(Root$2, {
108
109
  className: classes$6.root,
109
110
  ...rest
110
111
  }, /*#__PURE__*/React.createElement("div", {
@@ -241,7 +242,7 @@ function Commands(props) {
241
242
  if (!draft.dialog) {
242
243
  const containerElement = document.createElement("div");
243
244
  document.body.appendChild(containerElement);
244
- const reactPortal = /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement("div", {
245
+ const reactPortal = /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
245
246
  className: classes$4.root,
246
247
  onClick: ev => {
247
248
  if (ev.target === ev.currentTarget) {
@@ -257,7 +258,7 @@ function Commands(props) {
257
258
  reactPortal
258
259
  });
259
260
  } else {
260
- const reactPortal = /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement("div", {
261
+ const reactPortal = /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
261
262
  className: classes$4.root,
262
263
  onClick: ev => {
263
264
  if (ev.target === ev.currentTarget) {
@@ -276,7 +277,7 @@ function Commands(props) {
276
277
  mutate(draft => {
277
278
  draft.open = false;
278
279
  if (draft.dialog) {
279
- const reactPortal = /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement("div", {
280
+ const reactPortal = /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
280
281
  className: classes$4.root
281
282
  }, /*#__PURE__*/React.createElement(Dialog, {
282
283
  onDispose: () => {
@@ -521,17 +522,17 @@ const h1 = /*#__PURE__*/styled_default('h1')({
521
522
  class: "h6ceq1b",
522
523
  propsAsIs: false
523
524
  });
524
- const h2 = Heading( /*#__PURE__*/styled_default('h2')({
525
+ const h2 = Heading(/*#__PURE__*/styled_default('h2')({
525
526
  name: "h2",
526
527
  class: "hj6166y",
527
528
  propsAsIs: false
528
529
  }));
529
- const h3 = Heading( /*#__PURE__*/styled_default('h3')({
530
+ const h3 = Heading(/*#__PURE__*/styled_default('h3')({
530
531
  name: "h3",
531
532
  class: "h1f8mqks",
532
533
  propsAsIs: false
533
534
  }));
534
- const h4 = Heading( /*#__PURE__*/styled_default('h4')({
535
+ const h4 = Heading(/*#__PURE__*/styled_default('h4')({
535
536
  name: "h4",
536
537
  class: "h1hmga4",
537
538
  propsAsIs: false
package/core/styles.css CHANGED
@@ -53,7 +53,7 @@
53
53
  .r28qe6v{display:flex;align-items:center;margin:1px 0;font-size:0.9375rem;line-height:2.2;}@media (min-width:48rem){.r28qe6v{font-size:0.8125rem;}}@media (any-pointer:coarse){.r28qe6v > a{min-height:44px;}}.r28qe6v > a{min-width:0;transition:background 0.16s;border-radius:4px;display:flex;align-items:center;color:var(--timvir-text-color);font-weight:500;background:none;text-decoration:none;width:100%;padding:0 8px;opacity:0.7;}.r28qe6v:hover a{background-color:var(--timvir-sidebar-highlight-color);opacity:1;}.r28qe6v[data-active="true"] a{background-color:var(--timvir-sidebar-highlight-color);opacity:1;}
54
54
  .i1ia823q{display:block;width:1.3em;height:1.3em;margin-right:8px;min-width:1.3em;}
55
55
  .l13ixk6c{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:auto;}
56
- .i7wcd3g{margin-left:4px;transition:transform 0.12s cubic-bezier(0.455,0.03,0.515,0.955);transform-origin:center center;width:1rem;height:1rem;}
56
+ .i7wcd3g{margin-left:4px;transition:transform 0.12s cubic-bezier(0.455,0.03,0.515,0.955);transform-origin:center center;width:1rem;height:1rem;flex:0 0 1rem;}
57
57
 
58
58
 
59
59
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "timvir",
4
- "version": "0.2.22",
4
+ "version": "0.2.25",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
7
7
  "exports": {
@@ -26,8 +26,13 @@
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@mdx-js/react": "^2 || ^3",
29
- "react": "^17 || ^18",
30
- "react-dom": "^17 || ^18",
29
+ "react": "^17 || ^18 || ^19",
30
+ "react-dom": "^17 || ^18 || ^19",
31
31
  "react-hotkeys-hook": "^4"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/timvir/timvir.git",
36
+ "directory": "pkg/timvir"
32
37
  }
33
38
  }
@@ -1,10 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Node } from "timvir/core";
3
- /**
4
- * The underlying DOM element which is rendered by this component.
5
- */
6
- declare const Root = "div";
7
- interface Props extends React.ComponentPropsWithoutRef<typeof Root> {
3
+ interface Props extends React.ComponentPropsWithoutRef<"div"> {
8
4
  open?: boolean;
9
5
  onClose?: (ev: React.SyntheticEvent<HTMLElement>) => void;
10
6
  q: (query: string) => Promise<{
package/styles.css CHANGED
@@ -153,7 +153,7 @@
153
153
  .r28qe6v{display:flex;align-items:center;margin:1px 0;font-size:0.9375rem;line-height:2.2;}@media (min-width:48rem){.r28qe6v{font-size:0.8125rem;}}@media (any-pointer:coarse){.r28qe6v > a{min-height:44px;}}.r28qe6v > a{min-width:0;transition:background 0.16s;border-radius:4px;display:flex;align-items:center;color:var(--timvir-text-color);font-weight:500;background:none;text-decoration:none;width:100%;padding:0 8px;opacity:0.7;}.r28qe6v:hover a{background-color:var(--timvir-sidebar-highlight-color);opacity:1;}.r28qe6v[data-active="true"] a{background-color:var(--timvir-sidebar-highlight-color);opacity:1;}
154
154
  .i1ia823q{display:block;width:1.3em;height:1.3em;margin-right:8px;min-width:1.3em;}
155
155
  .l13ixk6c{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:auto;}
156
- .i7wcd3g{margin-left:4px;transition:transform 0.12s cubic-bezier(0.455,0.03,0.515,0.955);transform-origin:center center;width:1rem;height:1rem;}
156
+ .i7wcd3g{margin-left:4px;transition:transform 0.12s cubic-bezier(0.455,0.03,0.515,0.955);transform-origin:center center;width:1rem;height:1rem;flex:0 0 1rem;}
157
157
 
158
158
 
159
159