loom-browser 0.0.5 → 0.0.6
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/dist/loom-react.esm.js +277 -6
- package/dist/loom-react.esm.min.js +1 -1
- package/dist/loom-react.esm.min.js.map +1 -1
- package/dist/loom.esm.js +129 -1
- package/dist/loom.esm.min.js +1 -1
- package/dist/loom.esm.min.js.map +1 -1
- package/dist/loom.js +129 -0
- package/dist/loom.min.js +1 -1
- package/dist/loom.min.js.map +1 -1
- package/dist/tsconfig.src.tsbuildinfo +1 -1
- package/dist/types/dataSources/memoryDataSource.d.ts +32 -0
- package/dist/types/headlessGenomeBrowser.d.ts +33 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/react/GenomeBrowserContext.d.ts +3 -0
- package/dist/types/react/tracks/BedTrack.d.ts +8 -3
- package/dist/types/react/tracks/WigTrack.d.ts +6 -3
- package/dist/types/react/ui/Navbar.d.ts +4 -1
- package/dist/types/types.d.ts +4 -1
- package/package.json +1 -1
package/dist/loom-react.esm.js
CHANGED
|
@@ -8231,6 +8231,72 @@ class SequenceDataSource {
|
|
|
8231
8231
|
}
|
|
8232
8232
|
}
|
|
8233
8233
|
|
|
8234
|
+
/**
|
|
8235
|
+
* DataSource backed by an in-memory feature array.
|
|
8236
|
+
*
|
|
8237
|
+
* Wraps a pre-loaded feature array in a FeatureCache for spatial queries,
|
|
8238
|
+
* enabling inline features to flow through the same data lifecycle as
|
|
8239
|
+
* URL-based data sources.
|
|
8240
|
+
*
|
|
8241
|
+
* Layer 1 (Data + Layout): no DOM, no canvas.
|
|
8242
|
+
*/
|
|
8243
|
+
/**
|
|
8244
|
+
* DataSource that serves features from an in-memory array.
|
|
8245
|
+
*
|
|
8246
|
+
* Features are indexed in a FeatureCache on construction for efficient
|
|
8247
|
+
* spatial queries. Calling `setFeatures()` replaces the cache entirely.
|
|
8248
|
+
*/
|
|
8249
|
+
class MemoryDataSource {
|
|
8250
|
+
constructor(features) {
|
|
8251
|
+
this.cache = new FeatureCache(features);
|
|
8252
|
+
}
|
|
8253
|
+
/** Replace the in-memory features and rebuild the spatial index. */
|
|
8254
|
+
setFeatures(features) {
|
|
8255
|
+
this.cache = new FeatureCache(features);
|
|
8256
|
+
}
|
|
8257
|
+
/** Set a chromosome name resolver for alias resolution. */
|
|
8258
|
+
setChromNameResolver(resolver) {
|
|
8259
|
+
this._resolveChromName = resolver;
|
|
8260
|
+
}
|
|
8261
|
+
/** Set cumulative offsets for whole genome view coordinate transformation. */
|
|
8262
|
+
setCumulativeOffsets(offsets) {
|
|
8263
|
+
this._cumulativeOffsets = offsets;
|
|
8264
|
+
}
|
|
8265
|
+
async fetch(locus, _bpPerPixel, _signal) {
|
|
8266
|
+
if (isWholeGenomeView(locus) && this._cumulativeOffsets) {
|
|
8267
|
+
return this.fetchWG();
|
|
8268
|
+
}
|
|
8269
|
+
const chr = this._resolveChromName
|
|
8270
|
+
? this._resolveChromName(locus.chr)
|
|
8271
|
+
: locus.chr;
|
|
8272
|
+
return this.cache.queryFeatures(chr, locus.start, locus.end);
|
|
8273
|
+
}
|
|
8274
|
+
fetchWG() {
|
|
8275
|
+
const offsets = this._cumulativeOffsets;
|
|
8276
|
+
const chrNames = mainChromosomeNames(Object.fromEntries(offsets.chromosomeNames.map(name => { var _a; return [name, (_a = offsets.offsets[name]) !== null && _a !== void 0 ? _a : 0]; })));
|
|
8277
|
+
const wgFeatures = [];
|
|
8278
|
+
const allByChrom = this.cache.getAllFeatures();
|
|
8279
|
+
for (const chr of chrNames) {
|
|
8280
|
+
const features = allByChrom[chr];
|
|
8281
|
+
if (!features)
|
|
8282
|
+
continue;
|
|
8283
|
+
const offset = offsets.offsets[chr];
|
|
8284
|
+
if (offset === undefined)
|
|
8285
|
+
continue;
|
|
8286
|
+
for (const f of features) {
|
|
8287
|
+
wgFeatures.push({
|
|
8288
|
+
...f,
|
|
8289
|
+
chr: 'all',
|
|
8290
|
+
start: offset + f.start,
|
|
8291
|
+
end: offset + f.end,
|
|
8292
|
+
});
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
8295
|
+
wgFeatures.sort((a, b) => a.start - b.start);
|
|
8296
|
+
return wgFeatures;
|
|
8297
|
+
}
|
|
8298
|
+
}
|
|
8299
|
+
|
|
8234
8300
|
/**
|
|
8235
8301
|
* Stateless renderer for interaction (arc/BEDPE) tracks.
|
|
8236
8302
|
*
|
|
@@ -8801,6 +8867,11 @@ function createDataSource(config, workerProvider) {
|
|
|
8801
8867
|
indexed: config.indexed,
|
|
8802
8868
|
workerProvider,
|
|
8803
8869
|
});
|
|
8870
|
+
case 'memory':
|
|
8871
|
+
// Memory data sources are created directly with features by the caller.
|
|
8872
|
+
// This path is only hit during session restore, where in-memory features
|
|
8873
|
+
// are not available — return an empty MemoryDataSource as a placeholder.
|
|
8874
|
+
return new MemoryDataSource([]);
|
|
8804
8875
|
}
|
|
8805
8876
|
}
|
|
8806
8877
|
// ─── Built-in track creators ─────────────────────────────────────────────────
|
|
@@ -8979,6 +9050,9 @@ function dataSourceCacheKey(config) {
|
|
|
8979
9050
|
return `ucsc:${(_b = config.genome) !== null && _b !== void 0 ? _b : ''}:${(_c = config.track) !== null && _c !== void 0 ? _c : ''}`;
|
|
8980
9051
|
case 'text':
|
|
8981
9052
|
return `text:${config.url}:${(_d = config.format) !== null && _d !== void 0 ? _d : ''}:${(_e = config.indexURL) !== null && _e !== void 0 ? _e : ''}`;
|
|
9053
|
+
case 'memory':
|
|
9054
|
+
// Each memory data source is unique — no deduplication.
|
|
9055
|
+
return `memory:${Math.random()}`;
|
|
8982
9056
|
}
|
|
8983
9057
|
}
|
|
8984
9058
|
|
|
@@ -10089,6 +10163,60 @@ class HeadlessGenomeBrowser {
|
|
|
10089
10163
|
this.managedTracks[this.managedTracks.length - 1].metadata = options.metadata;
|
|
10090
10164
|
return track;
|
|
10091
10165
|
}
|
|
10166
|
+
/** Add a BigWig-style signal track backed by in-memory features (no URL required). */
|
|
10167
|
+
addWigTrackWithFeatures(features, options) {
|
|
10168
|
+
const { canvas } = this.canvasProvider.createCanvas(0, 0);
|
|
10169
|
+
const track = new WigTrackCanvas(canvas, {
|
|
10170
|
+
locus: this._locus,
|
|
10171
|
+
features: [],
|
|
10172
|
+
config: options === null || options === void 0 ? void 0 : options.config,
|
|
10173
|
+
height: options === null || options === void 0 ? void 0 : options.height,
|
|
10174
|
+
background: options === null || options === void 0 ? void 0 : options.background,
|
|
10175
|
+
theme: this.theme,
|
|
10176
|
+
canvasProvider: this.canvasProvider,
|
|
10177
|
+
name: options === null || options === void 0 ? void 0 : options.name,
|
|
10178
|
+
sequenceProvider: this.sequenceProvider,
|
|
10179
|
+
});
|
|
10180
|
+
const dataSource = new MemoryDataSource(features);
|
|
10181
|
+
if (this.cumulativeOffsets) {
|
|
10182
|
+
dataSource.setCumulativeOffsets(this.cumulativeOffsets);
|
|
10183
|
+
}
|
|
10184
|
+
if (this.genome) {
|
|
10185
|
+
dataSource.setChromNameResolver(alias => this.genome.getChromosomeName(alias));
|
|
10186
|
+
}
|
|
10187
|
+
const dataSourceConfig = { type: 'memory' };
|
|
10188
|
+
this.addTrack(track, dataSource, dataSourceConfig, options === null || options === void 0 ? void 0 : options.maxTrackHeight);
|
|
10189
|
+
if (options === null || options === void 0 ? void 0 : options.metadata)
|
|
10190
|
+
this.managedTracks[this.managedTracks.length - 1].metadata = options.metadata;
|
|
10191
|
+
return track;
|
|
10192
|
+
}
|
|
10193
|
+
/** Add a BED/annotation track backed by in-memory features (no URL required). Features must include `chr`. */
|
|
10194
|
+
addBedTrackWithFeatures(features, options) {
|
|
10195
|
+
const { canvas } = this.canvasProvider.createCanvas(0, 0);
|
|
10196
|
+
const track = new AnnotationTrackCanvas(canvas, {
|
|
10197
|
+
locus: this._locus,
|
|
10198
|
+
features: [],
|
|
10199
|
+
config: options === null || options === void 0 ? void 0 : options.config,
|
|
10200
|
+
height: options === null || options === void 0 ? void 0 : options.height,
|
|
10201
|
+
background: options === null || options === void 0 ? void 0 : options.background,
|
|
10202
|
+
theme: this.theme,
|
|
10203
|
+
canvasProvider: this.canvasProvider,
|
|
10204
|
+
workerProvider: this.workerProvider,
|
|
10205
|
+
name: options === null || options === void 0 ? void 0 : options.name,
|
|
10206
|
+
});
|
|
10207
|
+
const dataSource = new MemoryDataSource(features);
|
|
10208
|
+
if (this.cumulativeOffsets) {
|
|
10209
|
+
dataSource.setCumulativeOffsets(this.cumulativeOffsets);
|
|
10210
|
+
}
|
|
10211
|
+
if (this.genome) {
|
|
10212
|
+
dataSource.setChromNameResolver(alias => this.genome.getChromosomeName(alias));
|
|
10213
|
+
}
|
|
10214
|
+
const dataSourceConfig = { type: 'memory' };
|
|
10215
|
+
this.addTrack(track, dataSource, dataSourceConfig, options === null || options === void 0 ? void 0 : options.maxTrackHeight);
|
|
10216
|
+
if (options === null || options === void 0 ? void 0 : options.metadata)
|
|
10217
|
+
this.managedTracks[this.managedTracks.length - 1].metadata = options.metadata;
|
|
10218
|
+
return track;
|
|
10219
|
+
}
|
|
10092
10220
|
/** Add a DNA/RNA sequence track. Data fetching is handled automatically via the genome's sequence provider. */
|
|
10093
10221
|
addSequenceTrack(options) {
|
|
10094
10222
|
const trackConfig = { type: 'sequence', config: options === null || options === void 0 ? void 0 : options.config };
|
|
@@ -12472,6 +12600,23 @@ class GenomeBrowser extends HeadlessGenomeBrowser {
|
|
|
12472
12600
|
|
|
12473
12601
|
const GenomeBrowserContext = createContext(null);
|
|
12474
12602
|
|
|
12603
|
+
/** Infer the shell theme from a RenderTheme's palette. */
|
|
12604
|
+
function inferShellTheme(theme) {
|
|
12605
|
+
var _a;
|
|
12606
|
+
const bg = (_a = theme === null || theme === void 0 ? void 0 : theme.palette) === null || _a === void 0 ? void 0 : _a.background;
|
|
12607
|
+
if (!bg)
|
|
12608
|
+
return 'modern';
|
|
12609
|
+
// Simple luminance check: dark backgrounds → dark shell theme
|
|
12610
|
+
const el = document.createElement('canvas');
|
|
12611
|
+
const ctx = el.getContext('2d');
|
|
12612
|
+
ctx.fillStyle = bg;
|
|
12613
|
+
const hex = ctx.fillStyle; // normalized to #rrggbb
|
|
12614
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
12615
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
12616
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
12617
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
12618
|
+
return luminance < 0.5 ? 'dark' : 'modern';
|
|
12619
|
+
}
|
|
12475
12620
|
const LoomBrowser = forwardRef(function LoomBrowser(props, ref) {
|
|
12476
12621
|
const { defaultLocus, locus, onLocusChange, theme, genome, interactive, wheelZoom, workerProvider, popupProvider, contextMenuProvider, ruler, genes, sequence, session, tracks: trackConfigs, remoteSocket, className, style, children, } = props;
|
|
12477
12622
|
const containerRef = useRef(null);
|
|
@@ -12614,7 +12759,8 @@ const LoomBrowser = forwardRef(function LoomBrowser(props, ref) {
|
|
|
12614
12759
|
attachRemote(socket) { var _a; (_a = browserRef.current) === null || _a === void 0 ? void 0 : _a.attachRemote(socket); },
|
|
12615
12760
|
detachRemote() { var _a; (_a = browserRef.current) === null || _a === void 0 ? void 0 : _a.detachRemote(); },
|
|
12616
12761
|
}), [browser]);
|
|
12617
|
-
const
|
|
12762
|
+
const shellTheme = useMemo(() => inferShellTheme(theme), [theme]);
|
|
12763
|
+
const ctxValue = useMemo(() => ({ browser, shellTheme }), [browser, shellTheme]);
|
|
12618
12764
|
return (jsx(GenomeBrowserContext.Provider, { value: ctxValue, children: jsxs("div", { className: className, style: style, children: [browser && children, jsx("div", { ref: containerRef })] }) }));
|
|
12619
12765
|
});
|
|
12620
12766
|
|
|
@@ -12723,8 +12869,15 @@ function RulerTrack({ config, maxTrackHeight }) {
|
|
|
12723
12869
|
return null;
|
|
12724
12870
|
}
|
|
12725
12871
|
|
|
12726
|
-
function WigTrack({ url, config, height, background, windowFunction, maxTrackHeight, name, metadata }) {
|
|
12727
|
-
useTrackManager((browser) =>
|
|
12872
|
+
function WigTrack({ url, features, config, height, background, windowFunction, maxTrackHeight, name, metadata }) {
|
|
12873
|
+
useTrackManager((browser) => {
|
|
12874
|
+
if (features) {
|
|
12875
|
+
return browser.addWigTrackWithFeatures(features, { config, height, background, maxTrackHeight, name, metadata });
|
|
12876
|
+
}
|
|
12877
|
+
if (!url)
|
|
12878
|
+
throw new Error('WigTrack requires either a `url` or `features` prop');
|
|
12879
|
+
return browser.addWigTrack(url, { config, height, background, windowFunction, maxTrackHeight, name, metadata });
|
|
12880
|
+
}, [url, features, windowFunction], (track) => { if (config)
|
|
12728
12881
|
track.setConfig(config); }, [config, height, background, name]);
|
|
12729
12882
|
return null;
|
|
12730
12883
|
}
|
|
@@ -12735,8 +12888,15 @@ function GeneTrack({ config, height, background, genome, track, maxTrackHeight,
|
|
|
12735
12888
|
return null;
|
|
12736
12889
|
}
|
|
12737
12890
|
|
|
12738
|
-
function BedTrack({ url, config, height, background, format, indexURL, indexed, maxTrackHeight, name, metadata }) {
|
|
12739
|
-
useTrackManager((browser) =>
|
|
12891
|
+
function BedTrack({ url, features, config, height, background, format, indexURL, indexed, maxTrackHeight, name, metadata }) {
|
|
12892
|
+
useTrackManager((browser) => {
|
|
12893
|
+
if (features) {
|
|
12894
|
+
return browser.addBedTrackWithFeatures(features, { config, height, background, maxTrackHeight, name, metadata });
|
|
12895
|
+
}
|
|
12896
|
+
if (!url)
|
|
12897
|
+
throw new Error('BedTrack requires either a `url` or `features` prop');
|
|
12898
|
+
return browser.addBedTrack(url, { config, height, background, format, indexURL, indexed, maxTrackHeight, name, metadata });
|
|
12899
|
+
}, [url, features, format, indexURL, indexed], (track) => { if (config)
|
|
12740
12900
|
track.setConfig(config); }, [config, height, background, name]);
|
|
12741
12901
|
return null;
|
|
12742
12902
|
}
|
|
@@ -13387,15 +13547,126 @@ function ExportControls({ browser: browserProp }) {
|
|
|
13387
13547
|
return jsx("loom-export-controls", { ref: ref });
|
|
13388
13548
|
}
|
|
13389
13549
|
|
|
13390
|
-
|
|
13550
|
+
/**
|
|
13551
|
+
* CSS custom property themes for UI shell web components.
|
|
13552
|
+
*
|
|
13553
|
+
* Themes are injected as <style> blocks into Shadow DOM roots.
|
|
13554
|
+
* Components reference CSS custom properties (--loom-*) for all visual styling.
|
|
13555
|
+
*/
|
|
13556
|
+
/** Classic theme — matches igv.js navbar look. */
|
|
13557
|
+
const classicThemeCSS = /* css */ `
|
|
13558
|
+
:host {
|
|
13559
|
+
--loom-navbar-bg: #f3f3f3;
|
|
13560
|
+
--loom-navbar-height: 32px;
|
|
13561
|
+
--loom-navbar-padding: 0 8px;
|
|
13562
|
+
--loom-font: 12px Arial, sans-serif;
|
|
13563
|
+
--loom-font-small: 11px Arial, sans-serif;
|
|
13564
|
+
--loom-text-color: #333;
|
|
13565
|
+
--loom-text-muted: #737373;
|
|
13566
|
+
--loom-border: 1px solid #ccc;
|
|
13567
|
+
--loom-border-radius: 4px;
|
|
13568
|
+
--loom-button-bg: white;
|
|
13569
|
+
--loom-button-hover: #e8e8e8;
|
|
13570
|
+
--loom-button-border: 1px solid #b0b0b0;
|
|
13571
|
+
--loom-button-size: 24px;
|
|
13572
|
+
--loom-input-bg: white;
|
|
13573
|
+
--loom-input-border: 1px solid #b0b0b0;
|
|
13574
|
+
--loom-input-focus-border: 1px solid #4A90D9;
|
|
13575
|
+
--loom-input-width: 220px;
|
|
13576
|
+
--loom-input-height: 22px;
|
|
13577
|
+
--loom-accent: #4A90D9;
|
|
13578
|
+
--loom-icon-color: #555;
|
|
13579
|
+
--loom-icon-size: 14px;
|
|
13580
|
+
--loom-gap: 8px;
|
|
13581
|
+
}
|
|
13582
|
+
`;
|
|
13583
|
+
/** Modern theme — softer colors, rounded corners, taller navbar. */
|
|
13584
|
+
const modernThemeCSS = /* css */ `
|
|
13585
|
+
:host {
|
|
13586
|
+
--loom-navbar-bg: #fafbfc;
|
|
13587
|
+
--loom-navbar-height: 40px;
|
|
13588
|
+
--loom-navbar-padding: 0 12px;
|
|
13589
|
+
--loom-font: 13px Inter, system-ui, -apple-system, sans-serif;
|
|
13590
|
+
--loom-font-small: 11px Inter, system-ui, -apple-system, sans-serif;
|
|
13591
|
+
--loom-text-color: #1a1a1a;
|
|
13592
|
+
--loom-text-muted: #6b7280;
|
|
13593
|
+
--loom-border: 1px solid rgba(0, 0, 0, 0.08);
|
|
13594
|
+
--loom-border-radius: 8px;
|
|
13595
|
+
--loom-button-bg: white;
|
|
13596
|
+
--loom-button-hover: #f0f4ff;
|
|
13597
|
+
--loom-button-border: 1px solid rgba(0, 0, 0, 0.1);
|
|
13598
|
+
--loom-button-size: 28px;
|
|
13599
|
+
--loom-input-bg: white;
|
|
13600
|
+
--loom-input-border: 1px solid rgba(0, 0, 0, 0.12);
|
|
13601
|
+
--loom-input-focus-border: 1px solid #4A90D9;
|
|
13602
|
+
--loom-input-width: 260px;
|
|
13603
|
+
--loom-input-height: 28px;
|
|
13604
|
+
--loom-accent: #4A90D9;
|
|
13605
|
+
--loom-icon-color: #6b7280;
|
|
13606
|
+
--loom-icon-size: 16px;
|
|
13607
|
+
--loom-gap: 10px;
|
|
13608
|
+
}
|
|
13609
|
+
`;
|
|
13610
|
+
/** Dark theme — dark backgrounds, light text, high contrast. */
|
|
13611
|
+
const darkThemeCSS = /* css */ `
|
|
13612
|
+
:host {
|
|
13613
|
+
--loom-shell-bg: #16162a;
|
|
13614
|
+
--loom-navbar-bg: #1a1a2e;
|
|
13615
|
+
--loom-navbar-height: 36px;
|
|
13616
|
+
--loom-navbar-padding: 0 10px;
|
|
13617
|
+
--loom-font: 12px Arial, sans-serif;
|
|
13618
|
+
--loom-font-small: 11px Arial, sans-serif;
|
|
13619
|
+
--loom-text-color: #e0e0e0;
|
|
13620
|
+
--loom-text-muted: #888;
|
|
13621
|
+
--loom-border: 1px solid #333;
|
|
13622
|
+
--loom-border-radius: 4px;
|
|
13623
|
+
--loom-button-bg: #2a2a3e;
|
|
13624
|
+
--loom-button-hover: #3a3a50;
|
|
13625
|
+
--loom-button-border: 1px solid #444;
|
|
13626
|
+
--loom-button-size: 24px;
|
|
13627
|
+
--loom-input-bg: #2a2a3e;
|
|
13628
|
+
--loom-input-border: 1px solid #444;
|
|
13629
|
+
--loom-input-focus-border: 1px solid #6a9fd9;
|
|
13630
|
+
--loom-input-width: 220px;
|
|
13631
|
+
--loom-input-height: 22px;
|
|
13632
|
+
--loom-accent: #6a9fd9;
|
|
13633
|
+
--loom-icon-color: #b0b0b0;
|
|
13634
|
+
--loom-icon-size: 14px;
|
|
13635
|
+
--loom-gap: 8px;
|
|
13636
|
+
}
|
|
13637
|
+
`;
|
|
13638
|
+
function getThemeCSS(theme) {
|
|
13639
|
+
if (theme === 'modern')
|
|
13640
|
+
return modernThemeCSS;
|
|
13641
|
+
if (theme === 'dark')
|
|
13642
|
+
return darkThemeCSS;
|
|
13643
|
+
return classicThemeCSS;
|
|
13644
|
+
}
|
|
13645
|
+
|
|
13646
|
+
function Navbar({ browser: browserProp, theme: themeProp }) {
|
|
13647
|
+
var _a;
|
|
13648
|
+
const ctx = useContext(GenomeBrowserContext);
|
|
13391
13649
|
const contextBrowser = useGenomeBrowser();
|
|
13392
13650
|
const browser = browserProp !== null && browserProp !== void 0 ? browserProp : contextBrowser;
|
|
13651
|
+
const theme = (_a = themeProp !== null && themeProp !== void 0 ? themeProp : ctx === null || ctx === void 0 ? void 0 : ctx.shellTheme) !== null && _a !== void 0 ? _a : 'modern';
|
|
13393
13652
|
const ref = useRef(null);
|
|
13653
|
+
const styleRef = useRef(null);
|
|
13394
13654
|
ensureRegistered();
|
|
13395
13655
|
useEffect(() => {
|
|
13396
13656
|
if (ref.current)
|
|
13397
13657
|
ref.current.browser = browser;
|
|
13398
13658
|
}, [browser]);
|
|
13659
|
+
// Inject shell theme CSS into the navbar's shadow root
|
|
13660
|
+
useEffect(() => {
|
|
13661
|
+
const el = ref.current;
|
|
13662
|
+
if (!(el === null || el === void 0 ? void 0 : el.shadowRoot))
|
|
13663
|
+
return;
|
|
13664
|
+
if (!styleRef.current) {
|
|
13665
|
+
styleRef.current = document.createElement('style');
|
|
13666
|
+
el.shadowRoot.prepend(styleRef.current);
|
|
13667
|
+
}
|
|
13668
|
+
styleRef.current.textContent = getThemeCSS(theme);
|
|
13669
|
+
}, [theme]);
|
|
13399
13670
|
return jsx("loom-navbar", { ref: ref });
|
|
13400
13671
|
}
|
|
13401
13672
|
|