strata-css 1.2.6 → 1.2.7
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/CHANGELOG.md +158 -62
- package/README.md +11 -9
- package/bin/strata.js +15 -11
- package/package.json +1 -1
- package/src/components/modules/chart/src/chart.ts +55 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,62 +1,158 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to Strata CSS will be documented here.
|
|
4
|
-
|
|
5
|
-
## [1.
|
|
6
|
-
|
|
7
|
-
###
|
|
8
|
-
- `
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
- `
|
|
45
|
-
- `
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Strata CSS will be documented here.
|
|
4
|
+
|
|
5
|
+
## [1.2.7] — 2026-06-15
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **Components bundle (`dist/strata.components.js`) now creates the `Strata` namespace.** Each component's UMD wrapper attaches to `Strata.*` only `if (root.Strata)` exists, but the bundle never initialised it — so every component fell back to its own global (`StrataChart`, `StrataModal`, …) and `window.Strata` was never defined, breaking all `Strata.Chart.create(...)` / `Strata.Modal.open(...)` usage (e.g. blank charts in `examples/chart.html`). The bundle banner (`bin/strata.js`) now initialises `Strata` before the wrappers run.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## [1.2.6] — 2026-06-05
|
|
13
|
+
|
|
14
|
+
### Docs
|
|
15
|
+
- Versioning rules clarified and expanded in `CONTRIBUTING.md`
|
|
16
|
+
- All package `CLAUDE.md` files updated with complete API references
|
|
17
|
+
- `README.md` files added to `@strata-packages/picker` and `@strata-packages/forms`
|
|
18
|
+
- `CHANGELOG.md` files added to `@strata-packages/picker` and `@strata-packages/forms`
|
|
19
|
+
- Root `README.md` updated: version badge, forms/picker added to standalone packages table
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## [1.2.5] — 2026-06-04
|
|
24
|
+
|
|
25
|
+
### Added — `@strata-packages/picker`
|
|
26
|
+
- `theme` option — per-instance inline CSS variable overrides (primary, bg, text, radius, shadow, cellSize, fontSize)
|
|
27
|
+
- `className` option — extra class on popup for targeted CSS overrides
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## [1.2.4] — 2026-06-03
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- `@strata-packages/picker` — new standalone package: date, time, and datetime picker
|
|
35
|
+
- Zero dependencies, works standalone or as `Strata.Picker` with Strata CSS
|
|
36
|
+
- Declarative init via `data-st-datepicker`, `data-st-timepicker`, `data-st-datetimepicker`
|
|
37
|
+
- Date range selection with two-input mode and range highlight
|
|
38
|
+
- Preset shortcuts (built-in and custom)
|
|
39
|
+
- Month/year grid navigation
|
|
40
|
+
- `--stp-*` CSS variable system; auto-inherits `--st-*` tokens when Strata CSS is present
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- Picker popup now appends to `<body>` with no CSS opacity transition — appears immediately on open
|
|
44
|
+
- `position: fixed` popup no longer adds scroll offset to viewport coordinates
|
|
45
|
+
- Picker rewritten as unified `createPicker` — date / time / datetime all working correctly
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## [1.2.3] — 2026-06-02
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- `@strata-packages/forms` auto-init now recognises all `data-st-*` select attributes at DOMContentLoaded
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## [1.2.2] — 2026-06-01
|
|
57
|
+
|
|
58
|
+
### Added — `@strata-packages/forms`
|
|
59
|
+
- Checkbox select mode: dropdown stays open while ticking, Select All row, group-level checkboxes, `checkboxDisplay`: `chips` / `count` / `list`
|
|
60
|
+
- `maxDisplay` — fixed-height chip trigger with `+N` overflow badge
|
|
61
|
+
- Search input always rendered inside the dropdown (not above it)
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## [1.2.1] — 2026-05-30
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
- `@strata-packages/forms` backend-friendly `required` validation — triggers visible error state on custom trigger
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## [1.2.0] — 2026-05-28
|
|
73
|
+
|
|
74
|
+
### Added — `@strata-packages/forms`
|
|
75
|
+
- New standalone package: fully accessible custom select replacement
|
|
76
|
+
- Multi-select with chips, `maxItems`, searchable, clearable, grouped `<optgroup>`, creatable, avatar/custom render, async `loadOptions`, auto-width with viewport edge detection
|
|
77
|
+
- Native `<select>` stays in DOM — form submission works with any backend
|
|
78
|
+
- Declarative init via `data-st-select` and `data-st-*` option attributes
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## [1.1.0] — 2026-05-20
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
- Transition CSS variables: `--st-duration-theme`, `--st-easing-theme` — all hardcoded transition values replaced
|
|
86
|
+
- Sizing utilities: `max-w-{xs/sm/md/lg/xl/xxl/full/none}`, `min-w-{0/full/screen}`, `max-h-{full/screen/none}`, `min-h-{0/full/screen}`
|
|
87
|
+
- Arbitrary sizing: `max-w-[440px]`, `min-h-[300px]`, `max-h-[500px]`, `min-w-[200px]`
|
|
88
|
+
- Responsive variants added to 15 utility groups: `flex-{bp}`, `fw-{bp}`, `fst-{bp}`, `text-{bp}-{transform}`, `rounded-{bp}`, `shadow-{bp}`, `w-{bp}`, `h-{bp}`, `opacity-{bp}`, `overflow-{bp}`, `position-{bp}`, `cursor-{bp}`, `lh-{bp}`, `visible-{bp}`, `invisible-{bp}`
|
|
89
|
+
- Component CSS variable tokens: all hardcoded color values replaced with local CSS variables on `.badge`, `.btn-*`, `.btn-outline-*`, `.nav-pills .active`, `.list-group-item.active`, `.page-item.active`, `.dropdown-item.active`, `.progress-bar`, `.tooltip-inner`, `.navbar-dark`, `.card-img-overlay`, `.carousel-*`, `.table-dark`
|
|
90
|
+
- List utilities: `list-unstyled`, `list-inline`, `list-inline-item`, `list-disc`, `list-decimal`, `list-circle`, `list-square`, `list-none`, `list-lower-alpha`, `list-upper-alpha`, `list-lower-roman`, `list-upper-roman`, `list-inside`, `list-outside`, `list-spaced`
|
|
91
|
+
- Outline utilities: `outline-none`, `outline-{color}`, `outline-{1-5}`
|
|
92
|
+
- Label component: `.label` and `.label-{color}` aliases to `.badge` / `.badge-{color}` for Bootstrap 3 compatibility
|
|
93
|
+
|
|
94
|
+
### Fixed
|
|
95
|
+
- `text-[15px]` → `font-size: 15px` (length unit correctly detected)
|
|
96
|
+
- `text-[#f00]` → `color: #f00` (color value correctly detected)
|
|
97
|
+
- `#`, `(`, `)`, `,` in arbitrary values now correctly escaped in CSS class selectors
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## [1.0.0] — 2026-05-10
|
|
102
|
+
|
|
103
|
+
### Components
|
|
104
|
+
- `btn-primary`, `btn-secondary`, `btn-success`, `btn-danger`, `btn-warning`, `btn-info`, `btn-light`, `btn-dark` — full semantic button set with hover, focus, and active states baked in
|
|
105
|
+
- `card`, `card-header`, `card-body`, `card-footer` — composable card component
|
|
106
|
+
- `container`, `row`, `col-*` — Bootstrap-compatible responsive grid across all six breakpoints
|
|
107
|
+
- `modal` — dialog component with `data-st-toggle`, `data-st-dismiss`, and `data-st-backdrop` attribute API
|
|
108
|
+
- `navbar`, `navbar-brand`, `navbar-nav` — navigation bar component
|
|
109
|
+
- Skeleton loader — animated loading placeholder with `Strata.skeleton` JavaScript API
|
|
110
|
+
|
|
111
|
+
### Utilities
|
|
112
|
+
- Spacing: `mt-*`, `mb-*`, `ms-*`, `me-*`, `pt-*`, `pb-*`, `px-*`, `py-*`, `mx-auto`, `my-*`
|
|
113
|
+
- Display: `d-flex`, `d-none`, `d-block`, `d-grid`, `d-inline`, `d-inline-flex`, `d-inline-block`
|
|
114
|
+
- Colors: `text-*`, `bg-*` — all semantic colors (primary, secondary, success, danger, warning, info, light, dark, muted)
|
|
115
|
+
- Sizing: `w-25`, `w-50`, `w-75`, `w-100`, `h-25`, `h-50`, `h-75`, `h-100`, `mw-100`, `mh-100`
|
|
116
|
+
- Flexbox: `justify-content-*`, `align-items-*`, `align-self-*`, `flex-wrap`, `flex-nowrap`, `flex-grow-*`, `flex-shrink-*`
|
|
117
|
+
- Position: `position-static`, `position-relative`, `position-absolute`, `position-fixed`, `position-sticky`
|
|
118
|
+
- Overflow: `overflow-auto`, `overflow-hidden`, `overflow-scroll`, `overflow-visible`
|
|
119
|
+
- Opacity: `opacity-0`, `opacity-25`, `opacity-50`, `opacity-75`, `opacity-100`
|
|
120
|
+
- Visibility: `visible`, `invisible`
|
|
121
|
+
- Z-index: `z-0` through `z-3`
|
|
122
|
+
- Cursor: `cursor-pointer`, `cursor-default`, `cursor-not-allowed`, `cursor-wait`
|
|
123
|
+
- Shadows: `shadow-none`, `shadow-sm`, `shadow`, `shadow-lg`
|
|
124
|
+
- Transitions: `transition`, `transition-fast`, `transition-slow`, `transition-none`
|
|
125
|
+
- Easing: `ease-in`, `ease-out`, `ease-in-out`, `ease-linear`
|
|
126
|
+
- Arbitrary values: `mt-[24px]`, `bg-[#ff0000]`, `w-[347px]`, `transition-[background-color_0.3s_ease]`
|
|
127
|
+
- Important variants: `!mt-0`, `!d-none`, `!p-0`
|
|
128
|
+
- Breakpoint variants on all utilities: `col-md-6`, `d-lg-none`, `mt-xl-4`, `px-xxl-5`
|
|
129
|
+
|
|
130
|
+
### Theming
|
|
131
|
+
- Three built-in themes: `light` (default), `dark`, `dim` — applied via `data-st-theme` on `<html>`
|
|
132
|
+
- Automatic system preference detection via `prefers-color-scheme` — no configuration needed
|
|
133
|
+
- Unlimited custom themes via CSS custom properties: `[data-st-theme="brand"] { --st-primary: #7c3aed }`
|
|
134
|
+
- All `--st-*` custom properties fully overridable in `:root` or any selector
|
|
135
|
+
- Smooth theme transitions — all elements animate when the theme attribute changes
|
|
136
|
+
|
|
137
|
+
### State Management
|
|
138
|
+
- `data-st-visible="true|false"` — fade + translateY transition for show/hide
|
|
139
|
+
- `data-st-collapsed="true|false"` — smooth `max-height` expand/collapse
|
|
140
|
+
- `data-st-loading="true|false"` — opacity reduction + pointer-events disabled
|
|
141
|
+
- `data-st-disabled="true|false"` — opacity reduction + `cursor: not-allowed`
|
|
142
|
+
- `data-st-theme="light|dark|dim|custom"` — live theme switching
|
|
143
|
+
|
|
144
|
+
### Build System
|
|
145
|
+
- PostCSS plugin with O(1) class registry — 1065 pre-computed entries, zero linear scanning
|
|
146
|
+
- Multi-layer caching: dirty flag, file mtime, glob hash, config hash, output string cache
|
|
147
|
+
- CSS `@layer` hierarchy: `st-base` → `st-components` → `st-utilities` — breakpoint order guaranteed, HTML class order irrelevant
|
|
148
|
+
- Bootstrap-style breakpoints: xs (0px), sm (576px), md (768px), lg (992px), xl (1200px), xxl (1400px)
|
|
149
|
+
- Custom breakpoints via `strata.config.js` `theme.breakpoints`
|
|
150
|
+
- `prefers-reduced-motion` respected automatically — no configuration needed
|
|
151
|
+
- CLI: `strata init` (scaffold), `strata --watch` (development), `strata --build` (production), `strata --minify` (minified production)
|
|
152
|
+
|
|
153
|
+
### Performance (vs Tailwind CSS 3 in watch mode)
|
|
154
|
+
- Cold build: 1.89ms avg vs 7.21ms — 3.8× faster
|
|
155
|
+
- Warm rebuild: 0.14ms avg vs 2.70ms — 19× faster
|
|
156
|
+
- Warm p95: 0.23ms vs 6.12ms — 26× faster
|
|
157
|
+
|
|
158
|
+
Reproduce via `npm run benchmark`.
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**A modern CSS framework combining Bootstrap's component architecture with Tailwind's JIT processing.**
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
[]()
|
|
9
9
|
[]()
|
|
10
10
|
[](https://www.npmjs.com/package/strata-css)
|
|
11
11
|
[]()
|
|
@@ -383,9 +383,11 @@ All Strata plugins are available as independent packages. Use them without Strat
|
|
|
383
383
|
|
|
384
384
|
| Package | Standalone global | With Strata | Install |
|
|
385
385
|
|---|---|---|---|
|
|
386
|
-
| `@strata-
|
|
387
|
-
| `@strata-
|
|
388
|
-
| `@strata-
|
|
386
|
+
| `@strata-packages/forms` | `StrataForms` | `Strata.Forms` | `npm i @strata-packages/forms` |
|
|
387
|
+
| `@strata-packages/picker` | `StrataPicker` | `Strata.Picker` | `npm i @strata-packages/picker` |
|
|
388
|
+
| `@strata-packages/skeleton-loader` | `SkeletonLoader` | `Strata.skeleton` | `npm i @strata-packages/skeleton-loader` |
|
|
389
|
+
| `@strata-packages/modal` | `StrataModal` | `Strata.Modal` | `npm i @strata-packages/modal` |
|
|
390
|
+
| `@strata-packages/chart` | `StrataChart` | `Strata.Chart` | `npm i @strata-packages/chart` |
|
|
389
391
|
|
|
390
392
|
### How detection works
|
|
391
393
|
|
|
@@ -395,18 +397,18 @@ When `strata.components.js` is loaded it sets `data-strata` on `<html>`. Each pl
|
|
|
395
397
|
|
|
396
398
|
```html
|
|
397
399
|
<!-- Skeleton -->
|
|
398
|
-
<link rel="stylesheet" href="node_modules/@strata-
|
|
399
|
-
<script src="node_modules/@strata-
|
|
400
|
+
<link rel="stylesheet" href="node_modules/@strata-packages/skeleton-loader/skeleton-loader.css">
|
|
401
|
+
<script src="node_modules/@strata-packages/skeleton-loader/skeleton-loader.js"></script>
|
|
400
402
|
<script>SkeletonLoader.init('.card')</script>
|
|
401
403
|
|
|
402
404
|
<!-- Modal -->
|
|
403
|
-
<link rel="stylesheet" href="node_modules/@strata-
|
|
404
|
-
<script src="node_modules/@strata-
|
|
405
|
+
<link rel="stylesheet" href="node_modules/@strata-packages/modal/modal.css">
|
|
406
|
+
<script src="node_modules/@strata-packages/modal/modal.js"></script>
|
|
405
407
|
<script>StrataModal.open('#myModal')</script>
|
|
406
408
|
|
|
407
409
|
<!-- Chart (requires Three.js) -->
|
|
408
410
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
409
|
-
<script src="node_modules/@strata-
|
|
411
|
+
<script src="node_modules/@strata-packages/chart/chart.js"></script>
|
|
410
412
|
<script>StrataChart.create('#myChart', { type: 'bar', data: [...] })</script>
|
|
411
413
|
```
|
|
412
414
|
|
package/bin/strata.js
CHANGED
|
@@ -90,7 +90,11 @@ async function build(cssMinify = false, jsMinify = true) {
|
|
|
90
90
|
const jsDest = path.join(path.dirname(outputFile), 'strata.components.js')
|
|
91
91
|
if (fs.existsSync(componentsDir)) {
|
|
92
92
|
const files = fs.readdirSync(componentsDir).filter(f => f.endsWith('.js')).sort()
|
|
93
|
+
// Create the shared Strata namespace BEFORE the package UMD wrappers run, so
|
|
94
|
+
// each one attaches to Strata.* (their `if (root.Strata)` branch) instead of
|
|
95
|
+
// falling back to a separate StrataModal/StrataChart/etc. global.
|
|
93
96
|
const banner = `/*! Strata Components — built ${new Date().toISOString().slice(0,10)} */\n`
|
|
97
|
+
+ `;(function(g){g.Strata=g.Strata||{}})(typeof globalThis!=='undefined'?globalThis:this);\n`
|
|
94
98
|
const parts = files.map(f => fs.readFileSync(path.join(componentsDir, f), 'utf8'))
|
|
95
99
|
packageFiles.forEach(p => { if (fs.existsSync(p)) parts.push(fs.readFileSync(p, 'utf8')) })
|
|
96
100
|
const raw = parts.join('\n')
|
|
@@ -178,9 +182,9 @@ function detectFramework(cwd) {
|
|
|
178
182
|
// ─── Init helpers ─────────────────────────────────────────────────────
|
|
179
183
|
|
|
180
184
|
const PACKAGES = [
|
|
181
|
-
{ name: '@strata-
|
|
182
|
-
{ name: '@strata-
|
|
183
|
-
{ name: '@strata-
|
|
185
|
+
{ name: '@strata-packages/modal', label: 'modal — attribute-driven modal dialogs' },
|
|
186
|
+
{ name: '@strata-packages/skeleton-loader',label: 'skeleton-loader — shimmer loading placeholders' },
|
|
187
|
+
{ name: '@strata-packages/chart', label: 'chart — Three.js data visualisations' },
|
|
184
188
|
]
|
|
185
189
|
|
|
186
190
|
const FRAMEWORK_DEV = {
|
|
@@ -254,10 +258,10 @@ async function askCheckbox(rl, items) {
|
|
|
254
258
|
}
|
|
255
259
|
|
|
256
260
|
function packageUsageSnippet(pkgName) {
|
|
257
|
-
if (pkgName === '@strata-
|
|
261
|
+
if (pkgName === '@strata-packages/modal') return `
|
|
258
262
|
<!-- Modal usage (standalone) -->
|
|
259
|
-
<link rel="stylesheet" href="node_modules/@strata-
|
|
260
|
-
<script src="node_modules/@strata-
|
|
263
|
+
<link rel="stylesheet" href="node_modules/@strata-packages/modal/modal.css">
|
|
264
|
+
<script src="node_modules/@strata-packages/modal/modal.js"></script>
|
|
261
265
|
|
|
262
266
|
<button data-st-toggle="modal" data-st-target="#myModal">Open</button>
|
|
263
267
|
<div class="modal" id="myModal" aria-hidden="true">
|
|
@@ -270,10 +274,10 @@ function packageUsageSnippet(pkgName) {
|
|
|
270
274
|
</div></div>
|
|
271
275
|
</div>`
|
|
272
276
|
|
|
273
|
-
if (pkgName === '@strata-
|
|
277
|
+
if (pkgName === '@strata-packages/skeleton-loader') return `
|
|
274
278
|
<!-- Skeleton loader usage (standalone) -->
|
|
275
|
-
<link rel="stylesheet" href="node_modules/@strata-
|
|
276
|
-
<script src="node_modules/@strata-
|
|
279
|
+
<link rel="stylesheet" href="node_modules/@strata-packages/skeleton-loader/skeleton-loader.css">
|
|
280
|
+
<script src="node_modules/@strata-packages/skeleton-loader/skeleton-loader.js"></script>
|
|
277
281
|
|
|
278
282
|
<div class="card" data-st-skeleton="true">
|
|
279
283
|
<div class="card-body"><p>Content loading...</p></div>
|
|
@@ -283,10 +287,10 @@ function packageUsageSnippet(pkgName) {
|
|
|
283
287
|
fetchData().then(() => SkeletonLoader.reveal())
|
|
284
288
|
</script>`
|
|
285
289
|
|
|
286
|
-
if (pkgName === '@strata-
|
|
290
|
+
if (pkgName === '@strata-packages/chart') return `
|
|
287
291
|
<!-- Chart usage (standalone, requires Three.js) -->
|
|
288
292
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
289
|
-
<script src="node_modules/@strata-
|
|
293
|
+
<script src="node_modules/@strata-packages/chart/chart.js"></script>
|
|
290
294
|
|
|
291
295
|
<canvas id="myChart"></canvas>
|
|
292
296
|
<script>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strata-css",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"_versioningNote": "Stable: 1.0.0 / 1.1.0 / 2.0.0 | Beta: 1.1.0-beta.1 / 1.1.0-beta.2",
|
|
5
5
|
"description": "A modern CSS framework combining Bootstrap components with Tailwind JIT processing",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -99,6 +99,10 @@ interface ChartOptions {
|
|
|
99
99
|
onReady?: (chart: StrataChart) => void
|
|
100
100
|
onChange?: (view: ChartView) => void
|
|
101
101
|
onClick?: (point: { label: string; value: number; category: string; index: number }) => void
|
|
102
|
+
|
|
103
|
+
// Three.js is lazy-loaded from this URL if window.THREE is absent. Set to ''
|
|
104
|
+
// to require the host to pre-load it.
|
|
105
|
+
threeUrl?: string
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
interface OrbitControlsInstance {
|
|
@@ -115,7 +119,10 @@ interface OrbitControlsInstance {
|
|
|
115
119
|
interface StrataNamespace { Chart: ChartPlugin }
|
|
116
120
|
|
|
117
121
|
interface ChartPlugin {
|
|
118
|
-
|
|
122
|
+
// Synchronous when window.THREE is present; otherwise lazy-loads Three.js and
|
|
123
|
+
// resolves to the instance (or null on failure).
|
|
124
|
+
create(selector: string | Element, options: ChartOptions): StrataChart | null | Promise<StrataChart | null>
|
|
125
|
+
load(url?: string): Promise<unknown>
|
|
119
126
|
destroyAll(): void
|
|
120
127
|
}
|
|
121
128
|
|
|
@@ -157,6 +164,8 @@ const CAMERA_2D = { x: 0, y: 2, z: 22, fov: 18 }
|
|
|
157
164
|
const DEFAULT_COLORS = ['#4a90e2', '#e25f4a', '#50c878', '#f5a623', '#9b59b6', '#1abc9c']
|
|
158
165
|
const VALID_TYPES = ['bar', 'line', 'pie', 'scatter'] as ChartType[]
|
|
159
166
|
const MAX_POINTS = 100_000
|
|
167
|
+
// Three.js is lazy-loaded on first chart creation if window.THREE is absent.
|
|
168
|
+
const DEFAULT_THREE_URL = 'https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js'
|
|
160
169
|
const STRIP_HTML = /<[^>]*>/g
|
|
161
170
|
const SCALE_STEPS = 5
|
|
162
171
|
const GRID_COLOR_NORMAL = 0xd4d4d4
|
|
@@ -1097,29 +1106,54 @@ class StrataChart {
|
|
|
1097
1106
|
|
|
1098
1107
|
// ─── Bootstrap IIFE ───────────────────────────────────────────────────────────
|
|
1099
1108
|
|
|
1100
|
-
;(function (win: Window & typeof globalThis & { Strata?: Partial<StrataNamespace>; StrataChart?: Partial<StrataNamespace['Chart']> }) {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1109
|
+
;(function (win: Window & typeof globalThis & { THREE?: unknown; Strata?: Partial<StrataNamespace>; StrataChart?: Partial<StrataNamespace['Chart']> }) {
|
|
1110
|
+
// Lazy Three.js loader — fetched only on first chart creation if absent.
|
|
1111
|
+
let threeCache: Promise<unknown> | null = null
|
|
1112
|
+
function loadThree(url?: string): Promise<unknown> {
|
|
1113
|
+
if (win.THREE) return Promise.resolve(win.THREE)
|
|
1114
|
+
if (!url) return Promise.reject(new Error('[Strata Chart] Three.js not found and no threeUrl configured.'))
|
|
1115
|
+
if (threeCache) return threeCache
|
|
1116
|
+
threeCache = new Promise((resolve, reject) => {
|
|
1117
|
+
const s = document.createElement('script')
|
|
1118
|
+
s.src = url; s.async = true
|
|
1119
|
+
s.onload = () => { if (win.THREE) resolve(win.THREE); else { threeCache = null; reject(new Error('[Strata Chart] Three.js did not register after loading ' + url)) } }
|
|
1120
|
+
s.onerror = () => { threeCache = null; reject(new Error('[Strata Chart] Failed to load ' + url)) }
|
|
1121
|
+
document.head.appendChild(s)
|
|
1122
|
+
})
|
|
1123
|
+
return threeCache
|
|
1104
1124
|
}
|
|
1105
1125
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1126
|
+
// Validate + construct. Assumes Three.js is present.
|
|
1127
|
+
function build(selector: string | Element, options: ChartOptions): StrataChart | null {
|
|
1128
|
+
const container = typeof selector === 'string' ? document.querySelector(selector) : selector as Element
|
|
1129
|
+
if (!container) { console.error(`[Strata Chart] Element not found: ${String(selector)}`); return null }
|
|
1130
|
+
if (registry.has(container)) {
|
|
1131
|
+
console.warn('[Strata Chart] Chart already mounted here. Call .destroy() first.')
|
|
1132
|
+
return registry.get(container)!
|
|
1133
|
+
}
|
|
1134
|
+
if (!Array.isArray(options?.data)) { console.error('[Strata Chart] options.data must be an array.'); return null }
|
|
1135
|
+
if (options.type && !VALID_TYPES.includes(options.type)) {
|
|
1136
|
+
console.error(`[Strata Chart] Invalid type "${options.type}". Use: ${VALID_TYPES.join(', ')}`)
|
|
1137
|
+
return null
|
|
1138
|
+
}
|
|
1139
|
+
const instance = new StrataChart(container as HTMLElement, options)
|
|
1140
|
+
registry.set(container, instance)
|
|
1141
|
+
return instance
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
const api: ChartPlugin = {
|
|
1145
|
+
// Synchronous + unchanged when Three.js is already present. If absent, it is
|
|
1146
|
+
// lazy-loaded and create() returns a Promise<instance> (override the source
|
|
1147
|
+
// with options.threeUrl, or '' to require pre-load).
|
|
1148
|
+
create(selector: string | Element, options: ChartOptions): StrataChart | null | Promise<StrataChart | null> {
|
|
1149
|
+
options = options || ({} as ChartOptions)
|
|
1150
|
+
if (win.THREE) return build(selector, options)
|
|
1151
|
+
const url = options.threeUrl === undefined ? DEFAULT_THREE_URL : options.threeUrl
|
|
1152
|
+
return loadThree(url)
|
|
1153
|
+
.then(() => build(selector, options))
|
|
1154
|
+
.catch((err: Error) => { console.error(err.message || err); return null })
|
|
1122
1155
|
},
|
|
1156
|
+
load(url?: string): Promise<unknown> { return loadThree(url === undefined ? DEFAULT_THREE_URL : url) },
|
|
1123
1157
|
destroyAll() { registry.forEach(inst => inst.destroy()) },
|
|
1124
1158
|
}
|
|
1125
1159
|
|