@octanejs/content-loader 0.0.1
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 +21 -0
- package/README.md +25 -0
- package/UPSTREAM.md +69 -0
- package/package.json +47 -0
- package/src/index.ts +2 -0
- package/src/shared/uid.ts +3 -0
- package/src/web/ContentLoader.tsrx +8 -0
- package/src/web/Svg.tsrx +65 -0
- package/src/web/index.ts +12 -0
- package/src/web/presets/BulletListStyle.tsrx +16 -0
- package/src/web/presets/CodeStyle.tsrx +16 -0
- package/src/web/presets/FacebookStyle.tsrx +14 -0
- package/src/web/presets/InstagramStyle.tsrx +12 -0
- package/src/web/presets/ListStyle.tsrx +14 -0
- package/src/web/types.ts +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Julian Ćwirko <julian.io>
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @octanejs/content-loader
|
|
2
|
+
|
|
3
|
+
Octane binding for
|
|
4
|
+
[`react-content-loader@7.1.2`](https://github.com/danilowoz/react-content-loader).
|
|
5
|
+
|
|
6
|
+
```tsrx
|
|
7
|
+
import ContentLoader, { Code } from '@octanejs/content-loader';
|
|
8
|
+
|
|
9
|
+
export function LoadingArticle() @{
|
|
10
|
+
<ContentLoader width={400} height={120} viewBox="0 0 400 120">
|
|
11
|
+
<rect x="0" y="0" width="320" height="18" rx="3" />
|
|
12
|
+
<rect x="0" y="34" width="400" height="12" rx="3" />
|
|
13
|
+
</ContentLoader>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function LoadingCode() @{
|
|
17
|
+
<Code />
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The default export and the `Facebook`, `Instagram`, `Code`, `List`, and
|
|
22
|
+
`BulletList` presets target web SVG. The upstream `./native` entry is not
|
|
23
|
+
available because Octane has no React Native renderer.
|
|
24
|
+
|
|
25
|
+
See [UPSTREAM.md](./UPSTREAM.md) for the pin and test disposition.
|
package/UPSTREAM.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Upstream provenance
|
|
2
|
+
|
|
3
|
+
`@octanejs/content-loader` is pinned to `react-content-loader@7.1.2`.
|
|
4
|
+
|
|
5
|
+
- repository: https://github.com/danilowoz/react-content-loader
|
|
6
|
+
- tag commit: `c8a6b6c6669d7e663f9d7e1efecec08e876b0e5d`
|
|
7
|
+
- advertised range: `7.1.x`
|
|
8
|
+
- license: MIT
|
|
9
|
+
- npm integrity: `sha512-naFG7OERUQNPKQt1QWHyBF0/y6Zmr7dOzqjs1U5yOnu4OZmcE3+b/blp40dEKa9lvYAzOuj5dvfTK1cg5YWJkA==`
|
|
10
|
+
- npm shasum: `ca2c2e2f28cafc9595a7c39f30153561e65586e7`
|
|
11
|
+
|
|
12
|
+
Git `package.json` at this SHA still says `6.2.1`; npm published `7.1.2`
|
|
13
|
+
from that commit.
|
|
14
|
+
|
|
15
|
+
## Source boundary
|
|
16
|
+
|
|
17
|
+
- `upstream/src/` is the canonical web and native source with its Jest tests.
|
|
18
|
+
- `upstream/npm/` is the published tarball.
|
|
19
|
+
- Octane `src/web/` mirrors `upstream/src/web/`.
|
|
20
|
+
|
|
21
|
+
Vendored evidence is development-only and excluded from package `files`.
|
|
22
|
+
|
|
23
|
+
## Export crosswalk
|
|
24
|
+
|
|
25
|
+
| Upstream export | Octane status | Evidence / divergence |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| default `ContentLoader` | Ported | `src/web/ContentLoader.tsrx`; `tests/content-loader.test.ts` |
|
|
28
|
+
| `Facebook` | Ported | `src/web/presets/FacebookStyle.tsrx`; complete SVG DOM and shape-count assertions |
|
|
29
|
+
| `Instagram` | Ported | `src/web/presets/InstagramStyle.tsrx`; complete SVG DOM and shape-count assertions |
|
|
30
|
+
| `Code` | Ported | `src/web/presets/CodeStyle.tsrx`; complete SVG DOM and shape-count assertions |
|
|
31
|
+
| `List` | Ported | `src/web/presets/ListStyle.tsrx`; complete SVG DOM and shape-count assertions |
|
|
32
|
+
| `BulletList` | Ported | `src/web/presets/BulletListStyle.tsrx`; complete SVG DOM and shape-count assertions |
|
|
33
|
+
| `IContentLoaderProps` | Ported | Octane SVG intrinsic props plus `OctaneNode` for `beforeMask` |
|
|
34
|
+
| `./native` | Explicit gap | Requires React Native and `react-native-svg`; Octane has no React Native renderer |
|
|
35
|
+
|
|
36
|
+
## Upstream test disposition
|
|
37
|
+
|
|
38
|
+
All web cases below are adapted in `tests/content-loader.test.ts`. Assertions
|
|
39
|
+
formerly tied to `react-test-renderer`, its shallow renderer, or snapshots
|
|
40
|
+
observe the mounted SVG DOM and retain the upstream numeric and prop
|
|
41
|
+
expectations.
|
|
42
|
+
|
|
43
|
+
| Upstream artifact | Disposition |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `src/web/__tests__/Svg.test.tsx` | Adapted case-for-case |
|
|
46
|
+
| `src/web/__tests__/ContentLoader.test.tsx` | Adapted case-for-case; renderer swapped to mounted DOM |
|
|
47
|
+
| `src/web/__tests__/index.test.tsx` | Adapted case-for-case |
|
|
48
|
+
| `src/web/__tests__/uid.test.tsx` | Adapted case-for-case |
|
|
49
|
+
| `src/web/__tests__/snapshots.test.tsx` | Adapted case-for-case as complete observable SVG markup |
|
|
50
|
+
| `src/web/__tests__/presets/FacebookStyle.test.tsx` | Adapted case-for-case |
|
|
51
|
+
| `src/web/__tests__/presets/InstagramStyle.test.tsx` | Adapted case-for-case |
|
|
52
|
+
| `src/web/__tests__/presets/CodeStyle.test.tsx` | Adapted case-for-case |
|
|
53
|
+
| `src/web/__tests__/presets/ListStyle.test.tsx` | Adapted case-for-case |
|
|
54
|
+
| `src/web/__tests__/presets/BulletListStyle.test.tsx` | Adapted case-for-case |
|
|
55
|
+
| Web snapshot files | Replaced by exact assertions over observable SVG markup; no case dropped |
|
|
56
|
+
| `src/native/__tests__/**` and native snapshots | Out of scope with the explicit `./native` renderer gap |
|
|
57
|
+
|
|
58
|
+
## Intentional divergences
|
|
59
|
+
|
|
60
|
+
- `beforeMask` is typed as `OctaneNode`, and only valid Octane element
|
|
61
|
+
descriptors are inserted, matching the upstream runtime guard.
|
|
62
|
+
- `useId` has Octane's opaque identifier format. Relationships and uniqueness,
|
|
63
|
+
rather than identifier spelling, are the public contract.
|
|
64
|
+
- Octane serializes SVG/CSS `url()` functions with quotes (`url("#id")`)
|
|
65
|
+
while React's test renderer reports the unquoted form (`url(#id)`). Tests
|
|
66
|
+
compare the unquoted uniqueKey/baseUrl relationship.
|
|
67
|
+
- Octane inserts empty comment holes between children. Snapshots compare the
|
|
68
|
+
public SVG tree after those markers are stripped.
|
|
69
|
+
- The React Native `./native` entry is not published.
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@octanejs/content-loader",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Octane binding for react-content-loader 7.1.2 (web). Native/React Native is an explicit gap.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.22.2"
|
|
9
|
+
},
|
|
10
|
+
"author": {
|
|
11
|
+
"name": "Dominic Gannaway",
|
|
12
|
+
"email": "dg@domgan.com"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/octanejs/octane.git",
|
|
20
|
+
"directory": "packages/content-loader"
|
|
21
|
+
},
|
|
22
|
+
"main": "./src/index.ts",
|
|
23
|
+
"module": "./src/index.ts",
|
|
24
|
+
"types": "./src/index.ts",
|
|
25
|
+
"files": [
|
|
26
|
+
"src",
|
|
27
|
+
"README.md",
|
|
28
|
+
"UPSTREAM.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"exports": {
|
|
32
|
+
".": "./src/index.ts",
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"octane": "0.1.45"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"vitest": "^4.1.10",
|
|
40
|
+
"@octanejs/testing-library": "0.1.42",
|
|
41
|
+
"octane": "0.1.45"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"test": "vitest run --root ../.. --config vitest.config.js --project content-loader",
|
|
45
|
+
"typecheck": "tsrx-tsc --noEmit"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type { IContentLoaderProps } from './types';
|
|
3
|
+
import Facebook from './presets/FacebookStyle.tsrx';
|
|
4
|
+
import Svg from './Svg.tsrx';
|
|
5
|
+
|
|
6
|
+
export default function ContentLoader(props: IContentLoaderProps): OctaneNode {
|
|
7
|
+
return props.children ? <Svg {...props} /> : <Facebook {...props} />;
|
|
8
|
+
}
|
package/src/web/Svg.tsrx
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { isValidElement, useId, type OctaneNode } from 'octane';
|
|
2
|
+
import type { IContentLoaderProps } from './types';
|
|
3
|
+
|
|
4
|
+
export default function Svg({
|
|
5
|
+
animate = true,
|
|
6
|
+
backgroundColor = '#f5f6f7',
|
|
7
|
+
backgroundOpacity = 1,
|
|
8
|
+
baseUrl = '',
|
|
9
|
+
children,
|
|
10
|
+
foregroundColor = '#eee',
|
|
11
|
+
foregroundOpacity = 1,
|
|
12
|
+
gradientRatio = 2,
|
|
13
|
+
uniqueKey,
|
|
14
|
+
rtl = false,
|
|
15
|
+
speed = 1.2,
|
|
16
|
+
style = {},
|
|
17
|
+
title = 'Loading...',
|
|
18
|
+
beforeMask = null,
|
|
19
|
+
...props
|
|
20
|
+
}: IContentLoaderProps): OctaneNode {
|
|
21
|
+
let fixedId = useId();
|
|
22
|
+
if (uniqueKey) {
|
|
23
|
+
fixedId = uniqueKey;
|
|
24
|
+
}
|
|
25
|
+
const idClip = `${fixedId}-diff`;
|
|
26
|
+
const idGradient = `${fixedId}-animated-diff`;
|
|
27
|
+
const idAria = `${fixedId}-aria`;
|
|
28
|
+
|
|
29
|
+
const rtlStyle = rtl ? { transform: 'scaleX(-1)' } : {};
|
|
30
|
+
const dur = `${speed}s`;
|
|
31
|
+
|
|
32
|
+
const from = `${gradientRatio * -1} 0`;
|
|
33
|
+
const to = `${gradientRatio} 0`;
|
|
34
|
+
|
|
35
|
+
return <svg aria-labelledby={idAria} role="img" style={{ ...style, ...rtlStyle }} {...props}>
|
|
36
|
+
{title ? <title id={idAria}>{title as string}</title> : null}
|
|
37
|
+
{beforeMask && isValidElement(beforeMask) ? beforeMask : null}
|
|
38
|
+
<rect
|
|
39
|
+
role="presentation"
|
|
40
|
+
x="0"
|
|
41
|
+
y="0"
|
|
42
|
+
width="100%"
|
|
43
|
+
height="100%"
|
|
44
|
+
clipPath={`url(${baseUrl}#${idClip})`}
|
|
45
|
+
style={{ fill: `url(${baseUrl}#${idGradient})` }}
|
|
46
|
+
/>
|
|
47
|
+
<defs>
|
|
48
|
+
<clipPath id={idClip}>{children}</clipPath>
|
|
49
|
+
<linearGradient id={idGradient} gradientTransform={`translate(${from})`}>
|
|
50
|
+
<stop offset="0%" stopColor={backgroundColor} stopOpacity={backgroundOpacity} />
|
|
51
|
+
<stop offset="50%" stopColor={foregroundColor} stopOpacity={foregroundOpacity} />
|
|
52
|
+
<stop offset="100%" stopColor={backgroundColor} stopOpacity={backgroundOpacity} />
|
|
53
|
+
{animate
|
|
54
|
+
? <animateTransform
|
|
55
|
+
attributeName="gradientTransform"
|
|
56
|
+
type="translate"
|
|
57
|
+
values={`${from}; 0 0; ${to}`}
|
|
58
|
+
dur={dur}
|
|
59
|
+
repeatCount="indefinite"
|
|
60
|
+
/>
|
|
61
|
+
: null}
|
|
62
|
+
</linearGradient>
|
|
63
|
+
</defs>
|
|
64
|
+
</svg>;
|
|
65
|
+
}
|
package/src/web/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ContentLoader from './ContentLoader.tsrx';
|
|
2
|
+
import type { IContentLoaderProps } from './types';
|
|
3
|
+
|
|
4
|
+
export type { IContentLoaderProps };
|
|
5
|
+
|
|
6
|
+
export { default as Facebook } from './presets/FacebookStyle.tsrx';
|
|
7
|
+
export { default as Instagram } from './presets/InstagramStyle.tsrx';
|
|
8
|
+
export { default as Code } from './presets/CodeStyle.tsrx';
|
|
9
|
+
export { default as List } from './presets/ListStyle.tsrx';
|
|
10
|
+
export { default as BulletList } from './presets/BulletListStyle.tsrx';
|
|
11
|
+
|
|
12
|
+
export default ContentLoader;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import ContentLoader from '../ContentLoader.tsrx';
|
|
3
|
+
import type { IContentLoaderProps } from '../types';
|
|
4
|
+
|
|
5
|
+
export default function BulletList(props: IContentLoaderProps): OctaneNode {
|
|
6
|
+
return <ContentLoader viewBox="0 0 245 125" {...props}>
|
|
7
|
+
<circle cx="10" cy="20" r="8" />
|
|
8
|
+
<rect x="25" y="15" rx="5" ry="5" width="220" height="10" />
|
|
9
|
+
<circle cx="10" cy="50" r="8" />
|
|
10
|
+
<rect x="25" y="45" rx="5" ry="5" width="220" height="10" />
|
|
11
|
+
<circle cx="10" cy="80" r="8" />
|
|
12
|
+
<rect x="25" y="75" rx="5" ry="5" width="220" height="10" />
|
|
13
|
+
<circle cx="10" cy="110" r="8" />
|
|
14
|
+
<rect x="25" y="105" rx="5" ry="5" width="220" height="10" />
|
|
15
|
+
</ContentLoader>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type { IContentLoaderProps } from '../types';
|
|
3
|
+
import ContentLoader from '../ContentLoader.tsrx';
|
|
4
|
+
|
|
5
|
+
export default function Code(props: IContentLoaderProps): OctaneNode {
|
|
6
|
+
return <ContentLoader viewBox="0 0 340 84" {...props}>
|
|
7
|
+
<rect x="0" y="0" width="67" height="11" rx="3" />
|
|
8
|
+
<rect x="76" y="0" width="140" height="11" rx="3" />
|
|
9
|
+
<rect x="127" y="48" width="53" height="11" rx="3" />
|
|
10
|
+
<rect x="187" y="48" width="72" height="11" rx="3" />
|
|
11
|
+
<rect x="18" y="48" width="100" height="11" rx="3" />
|
|
12
|
+
<rect x="0" y="71" width="37" height="11" rx="3" />
|
|
13
|
+
<rect x="18" y="23" width="140" height="11" rx="3" />
|
|
14
|
+
<rect x="166" y="23" width="173" height="11" rx="3" />
|
|
15
|
+
</ContentLoader>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type { IContentLoaderProps } from '../types';
|
|
3
|
+
import ContentLoader from '../ContentLoader.tsrx';
|
|
4
|
+
|
|
5
|
+
export default function Facebook(props: IContentLoaderProps): OctaneNode {
|
|
6
|
+
return <ContentLoader viewBox="0 0 476 124" {...props}>
|
|
7
|
+
<rect x="48" y="8" width="88" height="6" rx="3" />
|
|
8
|
+
<rect x="48" y="26" width="52" height="6" rx="3" />
|
|
9
|
+
<rect x="0" y="56" width="410" height="6" rx="3" />
|
|
10
|
+
<rect x="0" y="72" width="380" height="6" rx="3" />
|
|
11
|
+
<rect x="0" y="88" width="178" height="6" rx="3" />
|
|
12
|
+
<circle cx="20" cy="20" r="20" />
|
|
13
|
+
</ContentLoader>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type { IContentLoaderProps } from '../types';
|
|
3
|
+
import ContentLoader from '../ContentLoader.tsrx';
|
|
4
|
+
|
|
5
|
+
export default function Instagram(props: IContentLoaderProps): OctaneNode {
|
|
6
|
+
return <ContentLoader viewBox="0 0 400 460" {...props}>
|
|
7
|
+
<circle cx="31" cy="31" r="15" />
|
|
8
|
+
<rect x="58" y="18" rx="2" ry="2" width="140" height="10" />
|
|
9
|
+
<rect x="58" y="34" rx="2" ry="2" width="140" height="10" />
|
|
10
|
+
<rect x="0" y="60" rx="2" ry="2" width="400" height="400" />
|
|
11
|
+
</ContentLoader>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type { IContentLoaderProps } from '../types';
|
|
3
|
+
import ContentLoader from '../ContentLoader.tsrx';
|
|
4
|
+
|
|
5
|
+
export default function List(props: IContentLoaderProps): OctaneNode {
|
|
6
|
+
return <ContentLoader viewBox="0 0 400 110" {...props}>
|
|
7
|
+
<rect x="0" y="0" rx="3" ry="3" width="250" height="10" />
|
|
8
|
+
<rect x="20" y="20" rx="3" ry="3" width="220" height="10" />
|
|
9
|
+
<rect x="20" y="40" rx="3" ry="3" width="170" height="10" />
|
|
10
|
+
<rect x="0" y="60" rx="3" ry="3" width="250" height="10" />
|
|
11
|
+
<rect x="20" y="80" rx="3" ry="3" width="200" height="10" />
|
|
12
|
+
<rect x="20" y="100" rx="3" ry="3" width="80" height="10" />
|
|
13
|
+
</ContentLoader>;
|
|
14
|
+
}
|
package/src/web/types.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OctaneNode } from 'octane';
|
|
2
|
+
import type { JSX } from 'octane/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
export interface IContentLoaderProps extends Omit<
|
|
5
|
+
JSX.IntrinsicElements['svg'],
|
|
6
|
+
'children' | 'title' | 'style'
|
|
7
|
+
> {
|
|
8
|
+
animate?: boolean;
|
|
9
|
+
backgroundColor?: string;
|
|
10
|
+
backgroundOpacity?: number;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
foregroundColor?: string;
|
|
13
|
+
foregroundOpacity?: number;
|
|
14
|
+
gradientRatio?: number;
|
|
15
|
+
rtl?: boolean;
|
|
16
|
+
speed?: number;
|
|
17
|
+
title?: string;
|
|
18
|
+
uniqueKey?: string;
|
|
19
|
+
beforeMask?: OctaneNode;
|
|
20
|
+
children?: OctaneNode;
|
|
21
|
+
style?: Record<string, string | number>;
|
|
22
|
+
}
|