@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 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,2 @@
1
+ export { default, Facebook, Instagram, Code, List, BulletList } from './web/index.ts';
2
+ export type { IContentLoaderProps } from './web/types.ts';
@@ -0,0 +1,3 @@
1
+ export default function uid(): string {
2
+ return Math.random().toString(36).substring(6);
3
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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
+ }