@hashsome/ui 0.1.0
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 +674 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/entities/action-button.d.ts +17 -0
- package/dist/entities/action-button.js +56 -0
- package/dist/entities/action-button.js.map +1 -0
- package/dist/entities/artwork-ring.d.ts +17 -0
- package/dist/entities/artwork-ring.js +89 -0
- package/dist/entities/artwork-ring.js.map +1 -0
- package/dist/entities/climate-tile.d.ts +20 -0
- package/dist/entities/climate-tile.js +98 -0
- package/dist/entities/climate-tile.js.map +1 -0
- package/dist/entities/light-color.d.ts +52 -0
- package/dist/entities/light-color.js +148 -0
- package/dist/entities/light-color.js.map +1 -0
- package/dist/entities/light-tile.d.ts +24 -0
- package/dist/entities/light-tile.js +139 -0
- package/dist/entities/light-tile.js.map +1 -0
- package/dist/entities/media-browser.d.ts +15 -0
- package/dist/entities/media-browser.js +67 -0
- package/dist/entities/media-browser.js.map +1 -0
- package/dist/entities/media-controls.d.ts +20 -0
- package/dist/entities/media-controls.js +53 -0
- package/dist/entities/media-controls.js.map +1 -0
- package/dist/entities/media-player-bar.d.ts +14 -0
- package/dist/entities/media-player-bar.js +78 -0
- package/dist/entities/media-player-bar.js.map +1 -0
- package/dist/entities/media-player-body.d.ts +16 -0
- package/dist/entities/media-player-body.js +18 -0
- package/dist/entities/media-player-body.js.map +1 -0
- package/dist/entities/media-player-column.d.ts +18 -0
- package/dist/entities/media-player-column.js +34 -0
- package/dist/entities/media-player-column.js.map +1 -0
- package/dist/entities/media-player-page.d.ts +12 -0
- package/dist/entities/media-player-page.js +13 -0
- package/dist/entities/media-player-page.js.map +1 -0
- package/dist/entities/media-progress.d.ts +7 -0
- package/dist/entities/media-progress.js +30 -0
- package/dist/entities/media-progress.js.map +1 -0
- package/dist/entities/media-seek.d.ts +9 -0
- package/dist/entities/media-seek.js +19 -0
- package/dist/entities/media-seek.js.map +1 -0
- package/dist/entities/nav-dock.d.ts +13 -0
- package/dist/entities/nav-dock.js +22 -0
- package/dist/entities/nav-dock.js.map +1 -0
- package/dist/entities/nav-rail.d.ts +19 -0
- package/dist/entities/nav-rail.js +18 -0
- package/dist/entities/nav-rail.js.map +1 -0
- package/dist/entities/now-playing.d.ts +20 -0
- package/dist/entities/now-playing.js +34 -0
- package/dist/entities/now-playing.js.map +1 -0
- package/dist/entities/scene-button.d.ts +13 -0
- package/dist/entities/scene-button.js +6 -0
- package/dist/entities/scene-button.js.map +1 -0
- package/dist/entities/seek-line.d.ts +9 -0
- package/dist/entities/seek-line.js +71 -0
- package/dist/entities/seek-line.js.map +1 -0
- package/dist/entities/sensor-readout.d.ts +28 -0
- package/dist/entities/sensor-readout.js +95 -0
- package/dist/entities/sensor-readout.js.map +1 -0
- package/dist/entities/top-bar.d.ts +68 -0
- package/dist/entities/top-bar.js +248 -0
- package/dist/entities/top-bar.js.map +1 -0
- package/dist/entity-handle.d.ts +21 -0
- package/dist/entity-handle.js +16 -0
- package/dist/entity-handle.js.map +1 -0
- package/dist/gallery/fixtures.d.ts +4 -0
- package/dist/gallery/fixtures.js +119 -0
- package/dist/gallery/fixtures.js.map +1 -0
- package/dist/gallery/gallery.d.ts +9 -0
- package/dist/gallery/gallery.js +355 -0
- package/dist/gallery/gallery.js.map +1 -0
- package/dist/gallery/index.d.ts +2 -0
- package/dist/gallery/index.js +2 -0
- package/dist/gallery/index.js.map +1 -0
- package/dist/gallery/props-data.d.ts +10 -0
- package/dist/gallery/props-data.js +718 -0
- package/dist/gallery/props-data.js.map +1 -0
- package/dist/hooks.d.ts +19 -0
- package/dist/hooks.js +53 -0
- package/dist/hooks.js.map +1 -0
- package/dist/icon-data.d.ts +6 -0
- package/dist/icon-data.js +59193 -0
- package/dist/icon-data.js.map +1 -0
- package/dist/icon.d.ts +9 -0
- package/dist/icon.js +28 -0
- package/dist/icon.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/cover.d.ts +5 -0
- package/dist/layout/cover.js +8 -0
- package/dist/layout/cover.js.map +1 -0
- package/dist/layout/date-time-field.d.ts +15 -0
- package/dist/layout/date-time-field.js +108 -0
- package/dist/layout/date-time-field.js.map +1 -0
- package/dist/layout/detail-provider.d.ts +22 -0
- package/dist/layout/detail-provider.js +26 -0
- package/dist/layout/detail-provider.js.map +1 -0
- package/dist/layout/drawer-controls.d.ts +46 -0
- package/dist/layout/drawer-controls.js +93 -0
- package/dist/layout/drawer-controls.js.map +1 -0
- package/dist/layout/energy-chart.d.ts +37 -0
- package/dist/layout/energy-chart.js +85 -0
- package/dist/layout/energy-chart.js.map +1 -0
- package/dist/layout/energy-usage.d.ts +6 -0
- package/dist/layout/energy-usage.js +18 -0
- package/dist/layout/energy-usage.js.map +1 -0
- package/dist/layout/entity-drawer.d.ts +15 -0
- package/dist/layout/entity-drawer.js +77 -0
- package/dist/layout/entity-drawer.js.map +1 -0
- package/dist/layout/fade-scroll.d.ts +14 -0
- package/dist/layout/fade-scroll.js +59 -0
- package/dist/layout/fade-scroll.js.map +1 -0
- package/dist/layout/grid.d.ts +9 -0
- package/dist/layout/grid.js +6 -0
- package/dist/layout/grid.js.map +1 -0
- package/dist/layout/history-section.d.ts +19 -0
- package/dist/layout/history-section.js +39 -0
- package/dist/layout/history-section.js.map +1 -0
- package/dist/layout/hold-progress.d.ts +2 -0
- package/dist/layout/hold-progress.js +9 -0
- package/dist/layout/hold-progress.js.map +1 -0
- package/dist/layout/icon-button-styles.d.ts +9 -0
- package/dist/layout/icon-button-styles.js +28 -0
- package/dist/layout/icon-button-styles.js.map +1 -0
- package/dist/layout/page.d.ts +17 -0
- package/dist/layout/page.js +29 -0
- package/dist/layout/page.js.map +1 -0
- package/dist/layout/plain-button.d.ts +11 -0
- package/dist/layout/plain-button.js +17 -0
- package/dist/layout/plain-button.js.map +1 -0
- package/dist/layout/room-header.d.ts +12 -0
- package/dist/layout/room-header.js +11 -0
- package/dist/layout/room-header.js.map +1 -0
- package/dist/layout/round-button.d.ts +13 -0
- package/dist/layout/round-button.js +19 -0
- package/dist/layout/round-button.js.map +1 -0
- package/dist/layout/sensor-history.d.ts +15 -0
- package/dist/layout/sensor-history.js +91 -0
- package/dist/layout/sensor-history.js.map +1 -0
- package/dist/layout/sensor-stats.d.ts +21 -0
- package/dist/layout/sensor-stats.js +79 -0
- package/dist/layout/sensor-stats.js.map +1 -0
- package/dist/layout/series-chart.d.ts +25 -0
- package/dist/layout/series-chart.js +46 -0
- package/dist/layout/series-chart.js.map +1 -0
- package/dist/layout/stepper.d.ts +10 -0
- package/dist/layout/stepper.js +12 -0
- package/dist/layout/stepper.js.map +1 -0
- package/dist/layout/swatch-row.d.ts +19 -0
- package/dist/layout/swatch-row.js +20 -0
- package/dist/layout/swatch-row.js.map +1 -0
- package/dist/layout/tile.d.ts +67 -0
- package/dist/layout/tile.js +207 -0
- package/dist/layout/tile.js.map +1 -0
- package/dist/layout/use-drawer.d.ts +33 -0
- package/dist/layout/use-drawer.js +34 -0
- package/dist/layout/use-drawer.js.map +1 -0
- package/dist/layout/use-hold.d.ts +21 -0
- package/dist/layout/use-hold.js +61 -0
- package/dist/layout/use-hold.js.map +1 -0
- package/dist/provider.d.ts +37 -0
- package/dist/provider.js +95 -0
- package/dist/provider.js.map +1 -0
- package/dist/status.d.ts +8 -0
- package/dist/status.js +27 -0
- package/dist/status.js.map +1 -0
- package/dist/theme/density.d.ts +16 -0
- package/dist/theme/density.js +7 -0
- package/dist/theme/density.js.map +1 -0
- package/dist/theme/global-styles.d.ts +5 -0
- package/dist/theme/global-styles.js +44 -0
- package/dist/theme/global-styles.js.map +1 -0
- package/dist/theme/index.d.ts +19 -0
- package/dist/theme/index.js +106 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/overrides.d.ts +28 -0
- package/dist/theme/overrides.js +24 -0
- package/dist/theme/overrides.js.map +1 -0
- package/dist/theme/tokens.d.ts +78 -0
- package/dist/theme/tokens.js +1 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/theme/use-typography.d.ts +4 -0
- package/dist/theme/use-typography.js +9 -0
- package/dist/theme/use-typography.js.map +1 -0
- package/dist/use-entity-history.d.ts +12 -0
- package/dist/use-entity-history.js +43 -0
- package/dist/use-entity-history.js.map +1 -0
- package/dist/use-media-browser.d.ts +31 -0
- package/dist/use-media-browser.js +87 -0
- package/dist/use-media-browser.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Interpolation, Theme } from '@emotion/react';
|
|
2
|
+
/** The app-wide styles `HashsomeProvider` installs once: the page background/text/font, native
|
|
3
|
+
* controls following the theme, border-box sizing, and a low-specificity `button`/`input` reset (so a component's
|
|
4
|
+
* own class always wins over it). Global because the theme is an app property, not a per-page one. */
|
|
5
|
+
export declare function globalStyles({ palette, typography }: Theme): Interpolation<Theme>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** The scrollbar's width (its track) and how much of that is the visible thumb. */
|
|
2
|
+
const SCROLLBAR = 14;
|
|
3
|
+
const THUMB = 4;
|
|
4
|
+
function isDark(hex) {
|
|
5
|
+
const n = parseInt(hex.replace('#', '').slice(0, 6), 16);
|
|
6
|
+
return Number.isFinite(n) && ((n >> 16) & 255) + ((n >> 8) & 255) + (n & 255) < 384;
|
|
7
|
+
}
|
|
8
|
+
/** The app-wide styles `HashsomeProvider` installs once: the page background/text/font, native
|
|
9
|
+
* controls following the theme, border-box sizing, and a low-specificity `button`/`input` reset (so a component's
|
|
10
|
+
* own class always wins over it). Global because the theme is an app property, not a per-page one. */
|
|
11
|
+
export function globalStyles({ palette, typography }) {
|
|
12
|
+
return {
|
|
13
|
+
':root': {
|
|
14
|
+
// Native controls (date pickers' calendar glyph, scrollbars) follow the theme, not the OS.
|
|
15
|
+
colorScheme: isDark(palette.bg) ? 'dark' : 'light',
|
|
16
|
+
},
|
|
17
|
+
'*, *::before, *::after': { boxSizing: 'border-box' },
|
|
18
|
+
body: {
|
|
19
|
+
background: palette.bg,
|
|
20
|
+
color: palette.text,
|
|
21
|
+
fontFamily: typography.default.fontFamily,
|
|
22
|
+
},
|
|
23
|
+
button: { font: 'inherit', color: 'inherit' },
|
|
24
|
+
// Buttons and inputs start borderless; one that wants a border asks for it with the `border` prop.
|
|
25
|
+
'button, input': { border: 0 },
|
|
26
|
+
// Scrollbars: thin, no track, in the theme's colors. The track is wider than the thumb and the
|
|
27
|
+
// thumb has a transparent border around it, so there is air between the bar and the content.
|
|
28
|
+
// (Chrome and Safari take the `::-webkit-scrollbar` rules; Firefox, which has no equivalent for
|
|
29
|
+
// the gap, gets a thin bar from the standard properties. Setting those in Chrome would turn the
|
|
30
|
+
// webkit rules off, hence the `@supports`.)
|
|
31
|
+
'::-webkit-scrollbar': { width: SCROLLBAR, height: SCROLLBAR },
|
|
32
|
+
'::-webkit-scrollbar-track, ::-webkit-scrollbar-corner': { background: 'transparent' },
|
|
33
|
+
'::-webkit-scrollbar-thumb': {
|
|
34
|
+
background: palette.border,
|
|
35
|
+
backgroundClip: 'padding-box',
|
|
36
|
+
border: `${(SCROLLBAR - THUMB) / 2}px solid transparent`,
|
|
37
|
+
borderRadius: 999,
|
|
38
|
+
},
|
|
39
|
+
'::-webkit-scrollbar-thumb:hover': { background: palette.line, backgroundClip: 'padding-box' },
|
|
40
|
+
'@supports not selector(::-webkit-scrollbar)': {
|
|
41
|
+
'*': { scrollbarWidth: 'thin', scrollbarColor: `${palette.border} transparent` },
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-styles.js","sourceRoot":"","sources":["../../src/theme/global-styles.ts"],"names":[],"mappings":"AAEA,mFAAmF;AACnF,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,KAAK,GAAG,CAAC,CAAC;AAEhB,SAAS,MAAM,CAAC,GAAW;IACzB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACtF,CAAC;AAED;;sGAEsG;AACtG,MAAM,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,UAAU,EAAS;IACzD,OAAO;QACL,OAAO,EAAE;YACP,2FAA2F;YAC3F,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;SACnD;QACD,wBAAwB,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE;QACrD,IAAI,EAAE;YACJ,UAAU,EAAE,OAAO,CAAC,EAAE;YACtB,KAAK,EAAE,OAAO,CAAC,IAAI;YACnB,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,UAAU;SAC1C;QACD,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;QAC7C,mGAAmG;QACnG,eAAe,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE;QAC9B,+FAA+F;QAC/F,6FAA6F;QAC7F,gGAAgG;QAChG,gGAAgG;QAChG,4CAA4C;QAC5C,qBAAqB,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;QAC9D,uDAAuD,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE;QACtF,2BAA2B,EAAE;YAC3B,UAAU,EAAE,OAAO,CAAC,MAAM;YAC1B,cAAc,EAAE,aAAa;YAC7B,MAAM,EAAE,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,sBAAsB;YACxD,YAAY,EAAE,GAAG;SAClB;QACD,iCAAiC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE;QAC9F,6CAA6C,EAAE;YAC7C,GAAG,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,cAAc,EAAE;SACjF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ThemeConfig } from 'e-prim';
|
|
2
|
+
import './tokens.ts';
|
|
3
|
+
/** The Google Fonts family loaded and applied by default — see `HashsomeProviderProps.font` . Any other Google Fonts family name works the same way. */
|
|
4
|
+
export declare const DEFAULT_FONT = "Inter";
|
|
5
|
+
/** Builds a CSS `font-family` value for a chosen font, falling back to the system stack if it
|
|
6
|
+
* hasn't loaded yet (or fails to). */
|
|
7
|
+
export declare function fontStack(family: string): string;
|
|
8
|
+
/** The Google Fonts CSS endpoint for a family name, covering the weights `@hashsome/ui` actually uses
|
|
9
|
+
* (400/500/600/700). Spaces become `+` per Google Fonts' own URL convention. */
|
|
10
|
+
export declare function googleFontHref(family: string): string;
|
|
11
|
+
/** Returns `theme` with every `Typography` variant's font swapped to `family` (falling back to
|
|
12
|
+
* the system stack) — every variant inherits `typography.default`, so this is the one place that
|
|
13
|
+
* needs to change. Used by `HashsomeProvider` to apply `HashsomeProviderProps.font` at runtime, since the
|
|
14
|
+
* `darkTheme`/`lightTheme` exports below are built once with the compile-time default. */
|
|
15
|
+
export declare function withFontFamily(theme: ThemeConfig, family: string): ThemeConfig;
|
|
16
|
+
/** The converged "Ember" dark palette (default; the only theme currently wired up). */
|
|
17
|
+
export declare const darkTheme: ThemeConfig;
|
|
18
|
+
/** Ember's light counterpart, selected via `<HashsomeProvider theme="light">` (or `"system"`). */
|
|
19
|
+
export declare const lightTheme: ThemeConfig;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import './tokens.js';
|
|
2
|
+
/** The Google Fonts family loaded and applied by default — see `HashsomeProviderProps.font` . Any other Google Fonts family name works the same way. */
|
|
3
|
+
export const DEFAULT_FONT = 'Inter';
|
|
4
|
+
const FALLBACK_FONTS = "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif";
|
|
5
|
+
/** Builds a CSS `font-family` value for a chosen font, falling back to the system stack if it
|
|
6
|
+
* hasn't loaded yet (or fails to). */
|
|
7
|
+
export function fontStack(family) {
|
|
8
|
+
return `'${family}', ${FALLBACK_FONTS}`;
|
|
9
|
+
}
|
|
10
|
+
/** The Google Fonts CSS endpoint for a family name, covering the weights `@hashsome/ui` actually uses
|
|
11
|
+
* (400/500/600/700). Spaces become `+` per Google Fonts' own URL convention. */
|
|
12
|
+
export function googleFontHref(family) {
|
|
13
|
+
return `https://fonts.googleapis.com/css2?family=${family.trim().replace(/\s+/g, '+')}:wght@400;500;600;700&display=swap`;
|
|
14
|
+
}
|
|
15
|
+
/** Returns `theme` with every `Typography` variant's font swapped to `family` (falling back to
|
|
16
|
+
* the system stack) — every variant inherits `typography.default`, so this is the one place that
|
|
17
|
+
* needs to change. Used by `HashsomeProvider` to apply `HashsomeProviderProps.font` at runtime, since the
|
|
18
|
+
* `darkTheme`/`lightTheme` exports below are built once with the compile-time default. */
|
|
19
|
+
export function withFontFamily(theme, family) {
|
|
20
|
+
return {
|
|
21
|
+
...theme,
|
|
22
|
+
typography: {
|
|
23
|
+
...theme.typography,
|
|
24
|
+
default: { ...theme.typography.default, fontFamily: fontStack(family) },
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const FONT_FAMILY = fontStack(DEFAULT_FONT);
|
|
29
|
+
const shared = {
|
|
30
|
+
spacing: 4,
|
|
31
|
+
breakpoint: {},
|
|
32
|
+
zIndex: {
|
|
33
|
+
nav: 5,
|
|
34
|
+
dropdown: 10,
|
|
35
|
+
scrim: 20,
|
|
36
|
+
drawer: 21,
|
|
37
|
+
popover: 30,
|
|
38
|
+
},
|
|
39
|
+
shadow: {
|
|
40
|
+
drawer: '0 20px 48px rgba(0, 0, 0, 0.5)',
|
|
41
|
+
},
|
|
42
|
+
radius: {
|
|
43
|
+
full: '999px',
|
|
44
|
+
card: '25px',
|
|
45
|
+
drawer: '24px',
|
|
46
|
+
chrome: '14px',
|
|
47
|
+
row: '16px',
|
|
48
|
+
small: '9px',
|
|
49
|
+
},
|
|
50
|
+
border: { color: 'border', width: 1 },
|
|
51
|
+
typography: {
|
|
52
|
+
default: { fontFamily: FONT_FAMILY, fontSize: 16 },
|
|
53
|
+
label: { fontSize: 12, fontWeight: 500 },
|
|
54
|
+
secondary: { fontSize: 11 },
|
|
55
|
+
heading: { fontSize: 14, fontWeight: 600 },
|
|
56
|
+
body: { fontSize: 13, fontWeight: 400 },
|
|
57
|
+
bodyStrong: { fontSize: 13, fontWeight: 600 },
|
|
58
|
+
eyebrow: { fontSize: 11, fontWeight: 600, letterSpacing: '0.04em' },
|
|
59
|
+
stat: { fontSize: 20, fontWeight: 600 },
|
|
60
|
+
title: { fontSize: 16, fontWeight: 400 },
|
|
61
|
+
roomTitle: { fontSize: 14, fontWeight: 400 },
|
|
62
|
+
clock: { fontSize: 32, fontWeight: 400 },
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
// `ThemeProvider` calls e-prim's own `makeTheme()` internally on whatever it's given — passing
|
|
66
|
+
// an already-`makeTheme()`-processed object here would run it twice, which silently corrupts the
|
|
67
|
+
// derived `spacing()` function (every `gap`/`p`/`m`/`mb` prop then resolves to `NaN`). These stay
|
|
68
|
+
// as plain `ThemeConfig` objects; `<ThemeProvider theme={darkTheme}>` does the one-time build.
|
|
69
|
+
/** The converged "Ember" dark palette (default; the only theme currently wired up). */
|
|
70
|
+
export const darkTheme = {
|
|
71
|
+
...shared,
|
|
72
|
+
palette: {
|
|
73
|
+
bg: '#0B0A0D',
|
|
74
|
+
surface: '#17151A',
|
|
75
|
+
surfaceRaised: '#211E26',
|
|
76
|
+
text: '#F2EFEA',
|
|
77
|
+
textMuted: '#96908C',
|
|
78
|
+
accent: '#FF7A45',
|
|
79
|
+
accentText: '#FFFFFF',
|
|
80
|
+
onAccent: '#1B1B1F',
|
|
81
|
+
warm: '#E3B341',
|
|
82
|
+
danger: '#F2554A',
|
|
83
|
+
line: '#726C6A',
|
|
84
|
+
rail: '#141216',
|
|
85
|
+
border: 'rgba(255, 255, 255, 0.09)',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
/** Ember's light counterpart, selected via `<HashsomeProvider theme="light">` (or `"system"`). */
|
|
89
|
+
export const lightTheme = {
|
|
90
|
+
...shared,
|
|
91
|
+
palette: {
|
|
92
|
+
bg: '#F4F1EB',
|
|
93
|
+
surface: '#FFFFFF',
|
|
94
|
+
surfaceRaised: '#EFEAE1',
|
|
95
|
+
text: '#211E26',
|
|
96
|
+
textMuted: '#8A8480',
|
|
97
|
+
accent: '#FF7A45',
|
|
98
|
+
accentText: '#FFFFFF',
|
|
99
|
+
onAccent: '#1B1B1F',
|
|
100
|
+
warm: '#E3B341',
|
|
101
|
+
danger: '#F2554A',
|
|
102
|
+
line: '#4A4540',
|
|
103
|
+
rail: '#EAE4DA',
|
|
104
|
+
border: 'rgba(0, 0, 0, 0.08)',
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ThemeConfig, TypographyKey, TypographySpecs } from 'e-prim';
|
|
2
|
+
import { type Density, type DensityTokens } from './density.ts';
|
|
3
|
+
/** Changes to the built-in theme. Everything is optional and partial: name only what differs and
|
|
4
|
+
* the rest keeps its default. Only existing tokens can be changed. */
|
|
5
|
+
export interface ThemeOverrides {
|
|
6
|
+
/** Colors for the light theme (`theme="light"`, or `"system"` while the OS is light). */
|
|
7
|
+
light?: {
|
|
8
|
+
palette?: Partial<ThemeConfig['palette']>;
|
|
9
|
+
};
|
|
10
|
+
/** Colors for the dark theme. Light and dark are separate, so one change never touches both. */
|
|
11
|
+
dark?: {
|
|
12
|
+
palette?: Partial<ThemeConfig['palette']>;
|
|
13
|
+
};
|
|
14
|
+
/** Tokens both themes share. */
|
|
15
|
+
shared?: {
|
|
16
|
+
radius?: Partial<ThemeConfig['radius']>;
|
|
17
|
+
shadow?: Partial<ThemeConfig['shadow']>;
|
|
18
|
+
zIndex?: Partial<ThemeConfig['zIndex']>;
|
|
19
|
+
/** By variant name (`label`, `body`, `stat`, ...); each takes only the fields it changes. */
|
|
20
|
+
typography?: Partial<Record<TypographyKey, TypographySpecs>>;
|
|
21
|
+
};
|
|
22
|
+
/** Sizes per density, e.g. `{ comfortable: { space: 16 } }`. */
|
|
23
|
+
density?: Partial<Record<Density, Partial<DensityTokens>>>;
|
|
24
|
+
}
|
|
25
|
+
/** `base` with `overrides` applied. Pure; neither argument is changed. */
|
|
26
|
+
export declare function applyThemeOverrides(base: ThemeConfig, mode: 'light' | 'dark', overrides: ThemeOverrides | undefined): ThemeConfig;
|
|
27
|
+
/** The density's tokens with `overrides` applied. */
|
|
28
|
+
export declare function densityTokens(density: Density, overrides: ThemeOverrides | undefined): DensityTokens;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DENSITY } from './density.js';
|
|
2
|
+
/** `base` with `overrides` applied. Pure; neither argument is changed. */
|
|
3
|
+
export function applyThemeOverrides(base, mode, overrides) {
|
|
4
|
+
if (!overrides) {
|
|
5
|
+
return base;
|
|
6
|
+
}
|
|
7
|
+
const shared = overrides.shared ?? {};
|
|
8
|
+
const typography = { ...base.typography };
|
|
9
|
+
for (const [variant, specs] of Object.entries(shared.typography ?? {})) {
|
|
10
|
+
typography[variant] = { ...typography[variant], ...specs };
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
...base,
|
|
14
|
+
radius: { ...base.radius, ...shared.radius },
|
|
15
|
+
shadow: { ...base.shadow, ...shared.shadow },
|
|
16
|
+
zIndex: { ...base.zIndex, ...shared.zIndex },
|
|
17
|
+
typography: typography,
|
|
18
|
+
palette: { ...base.palette, ...overrides[mode]?.palette },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** The density's tokens with `overrides` applied. */
|
|
22
|
+
export function densityTokens(density, overrides) {
|
|
23
|
+
return { ...DENSITY[density], ...overrides?.density?.[density] };
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overrides.js","sourceRoot":"","sources":["../../src/theme/overrides.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAoC,MAAM,cAAc,CAAC;AAyBzE,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CACjC,IAAiB,EACjB,IAAsB,EACtB,SAAqC;IAErC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,EAAqC,CAAC;IAC7E,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,CAAC;QACvE,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;IAC7D,CAAC;IAED,OAAO;QACL,GAAG,IAAI;QACP,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QAC5C,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QAC5C,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QAC5C,UAAU,EAAE,UAAuC;QACnD,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE;KAC1D,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,aAAa,CAC3B,OAAgB,EAChB,SAAqC;IAErC,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import '@emotion/react';
|
|
2
|
+
import type { TypographySpecs } from 'e-prim';
|
|
3
|
+
import type { DensityTokens } from './density.ts';
|
|
4
|
+
declare module '@emotion/react' {
|
|
5
|
+
interface Theme {
|
|
6
|
+
/** Set by `HashsomeProvider` from its `density` prop. */
|
|
7
|
+
density: DensityTokens;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
declare module 'e-prim' {
|
|
11
|
+
interface TPalette {
|
|
12
|
+
bg: string;
|
|
13
|
+
surface: string;
|
|
14
|
+
surfaceRaised: string;
|
|
15
|
+
text: string;
|
|
16
|
+
textMuted: string;
|
|
17
|
+
accent: string;
|
|
18
|
+
accentText: string;
|
|
19
|
+
/** Text drawn directly on the `accent` color (a solid-accent tile, or a dimmable tile's fill) — near-black in both themes, since light text on orange is low contrast. */
|
|
20
|
+
onAccent: string;
|
|
21
|
+
warm: string;
|
|
22
|
+
danger: string;
|
|
23
|
+
line: string;
|
|
24
|
+
/** The left nav rail / bottom nav dock's background — a third near-black, distinct from
|
|
25
|
+
* `bg`/`surface`. */
|
|
26
|
+
rail: string;
|
|
27
|
+
/** A subtle 1px hairline (e.g. `EntityDrawer`'s own edge) — used via the theme's `border`
|
|
28
|
+
* config, so components say `border` (boolean) rather than carrying the color themselves. */
|
|
29
|
+
border: string;
|
|
30
|
+
}
|
|
31
|
+
interface TRadius {
|
|
32
|
+
full: string;
|
|
33
|
+
card: string;
|
|
34
|
+
drawer: string;
|
|
35
|
+
/** The nav rail/dock's rounded-square icon buttons. */
|
|
36
|
+
chrome: string;
|
|
37
|
+
/** A status/pill row inside a drawer (e.g. `LightTile`'s power row). */
|
|
38
|
+
row: string;
|
|
39
|
+
/** A small chrome control (e.g. `EntityDrawer`'s expand/close buttons). */
|
|
40
|
+
small: string;
|
|
41
|
+
}
|
|
42
|
+
interface TShadow {
|
|
43
|
+
/** `EntityDrawer`'s own drop shadow. */
|
|
44
|
+
drawer: string;
|
|
45
|
+
}
|
|
46
|
+
interface TZIndex {
|
|
47
|
+
scrim: number;
|
|
48
|
+
drawer: number;
|
|
49
|
+
/** The page navigation (`NavRail`), fixed over a dashboard. */
|
|
50
|
+
nav: number;
|
|
51
|
+
/** A menu or status panel that drops from a control (the top bar's), above the page. */
|
|
52
|
+
dropdown: number;
|
|
53
|
+
/** A floating panel anchored to a control (the date picker's calendar), above what it sits in. */
|
|
54
|
+
popover: number;
|
|
55
|
+
}
|
|
56
|
+
interface TTypography {
|
|
57
|
+
/** A tile's own name (`Tile`'s label). */
|
|
58
|
+
label: TypographySpecs;
|
|
59
|
+
/** Muted status/secondary text (a tile's status line, a drawer row's timestamp). */
|
|
60
|
+
secondary: TypographySpecs;
|
|
61
|
+
/** A drawer's header name. */
|
|
62
|
+
heading: TypographySpecs;
|
|
63
|
+
/** Regular body copy inside a drawer (e.g. a history entry's message). */
|
|
64
|
+
body: TypographySpecs;
|
|
65
|
+
/** Emphasized body copy (a history entry's actor name, a status row's own label). */
|
|
66
|
+
bodyStrong: TypographySpecs;
|
|
67
|
+
/** Small uppercase, letter-spaced section labels ("History", a chart's "Power" label). */
|
|
68
|
+
eyebrow: TypographySpecs;
|
|
69
|
+
/** A large numeric readout (the energy chart's current wattage). */
|
|
70
|
+
stat: TypographySpecs;
|
|
71
|
+
/** A prominent heading, bigger than `heading` (the `TopBar`'s own title/dashboard switcher). */
|
|
72
|
+
title: TypographySpecs;
|
|
73
|
+
/** A `RoomHeader`'s title (a room name) — quiet, muted, not a heading that competes with the tiles. */
|
|
74
|
+
roomTitle: TypographySpecs;
|
|
75
|
+
/** The `TopBar`'s own clock reading — large enough to read at a glance from across a room. */
|
|
76
|
+
clock: TypographySpecs;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@emotion/react';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/theme/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TypographyKey } from 'e-prim';
|
|
2
|
+
/** A typography variant's resolved font size, for the rare consumer that can't render a
|
|
3
|
+
* `<Typography>` — e.g. an SVG chart's axis ticks. Everything else should use `<Typography>`. */
|
|
4
|
+
export declare function useTypographySize(key: Exclude<TypographyKey, 'default'>): number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
/** A typography variant's resolved font size, for the rare consumer that can't render a
|
|
3
|
+
* `<Typography>` — e.g. an SVG chart's axis ticks. Everything else should use `<Typography>`. */
|
|
4
|
+
export function useTypographySize(key) {
|
|
5
|
+
const { typography } = useTheme();
|
|
6
|
+
const specs = typography;
|
|
7
|
+
const size = specs[key]?.fontSize ?? typography.default.fontSize;
|
|
8
|
+
return typeof size === 'number' ? size : 16;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-typography.js","sourceRoot":"","sources":["../../src/theme/use-typography.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C;iGACiG;AACjG,MAAM,UAAU,iBAAiB,CAAC,GAAsC;IACtE,MAAM,EAAE,UAAU,EAAE,GAAG,QAAQ,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,UAA2E,CAAC;IAC1F,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,QAAQ,IAAI,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC;IACjE,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EntityRef, HistoryQuery, HistoryResult } from '@hashsome/core';
|
|
2
|
+
export interface EntityHistoryState {
|
|
3
|
+
/** `undefined` until the first answer, and always for a backend that keeps no history. */
|
|
4
|
+
result: HistoryResult | undefined;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* An entity's past values from the backend's own record, fetched when `ref` or `query` change and
|
|
9
|
+
* kept for a minute. A backend that keeps no history, or an error, leaves `result` undefined —
|
|
10
|
+
* history is an extra, so a component just shows nothing. Pass `undefined` to not ask at all.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useEntityHistory(ref: EntityRef | undefined, query: HistoryQuery | undefined): EntityHistoryState;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useClient } from './provider.js';
|
|
3
|
+
/** How long an answer is reused: opening a drawer twice, or switching a range back, does not ask again. */
|
|
4
|
+
const FRESH_MS = 60_000;
|
|
5
|
+
const cache = new WeakMap();
|
|
6
|
+
function load(client, ref, query) {
|
|
7
|
+
const answers = cache.get(client) ?? new Map();
|
|
8
|
+
cache.set(client, answers);
|
|
9
|
+
const key = `${ref}|${query.range}|${query.bucket ?? ''}`;
|
|
10
|
+
const known = answers.get(key);
|
|
11
|
+
if (known && Date.now() - known.at < FRESH_MS) {
|
|
12
|
+
return known.result;
|
|
13
|
+
}
|
|
14
|
+
const result = client.history(ref, query);
|
|
15
|
+
answers.set(key, { at: Date.now(), result });
|
|
16
|
+
// A failed answer is not worth keeping: the next ask tries again.
|
|
17
|
+
result.catch(() => answers.delete(key));
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* An entity's past values from the backend's own record, fetched when `ref` or `query` change and
|
|
22
|
+
* kept for a minute. A backend that keeps no history, or an error, leaves `result` undefined —
|
|
23
|
+
* history is an extra, so a component just shows nothing. Pass `undefined` to not ask at all.
|
|
24
|
+
*/
|
|
25
|
+
export function useEntityHistory(ref, query) {
|
|
26
|
+
const client = useClient();
|
|
27
|
+
const range = query?.range;
|
|
28
|
+
const bucket = query?.bucket;
|
|
29
|
+
const [state, setState] = useState();
|
|
30
|
+
const key = ref && range ? `${ref}|${range}|${bucket ?? ''}` : undefined;
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!ref || !range || !key) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let current = true;
|
|
36
|
+
load(client, ref, { range, ...(bucket ? { bucket } : {}) }).then((result) => current && setState({ key, result }), () => current && setState({ key, result: undefined }));
|
|
37
|
+
return () => {
|
|
38
|
+
current = false;
|
|
39
|
+
};
|
|
40
|
+
}, [client, ref, range, bucket, key]);
|
|
41
|
+
const answered = state !== undefined && state.key === key;
|
|
42
|
+
return { result: answered ? state.result : undefined, loading: key !== undefined && !answered };
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-entity-history.js","sourceRoot":"","sources":["../src/use-entity-history.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAgB,CAAC;AAQ3C,2GAA2G;AAC3G,MAAM,QAAQ,GAAG,MAAM,CAAC;AAExB,MAAM,KAAK,GAAG,IAAI,OAAO,EAAuE,CAAC;AAEjG,SAAS,IAAI,CAAC,MAAc,EAAE,GAAc,EAAE,KAAmB;IAC/D,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;IAC/C,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC9C,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,kEAAkE;IAClE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAA0B,EAC1B,KAA+B;IAE/B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM,CAAC;IAC7B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,EAAsD,CAAC;IACzF,MAAM,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,KAAK,IAAI,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAC9D,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,IAAI,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAChD,GAAG,EAAE,CAAC,OAAO,IAAI,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CACtD,CAAC;QAEF,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC;IAC1D,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,KAAK,SAAS,IAAI,CAAC,QAAQ,EAAE,CAAC;AAClG,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BrowseItem, EntityRef } from '@hashsome/core';
|
|
2
|
+
export interface MediaBrowserState {
|
|
3
|
+
/** What is listed now. */
|
|
4
|
+
items: BrowseItem[];
|
|
5
|
+
/** A name for the list: the opened folder's, or what was searched for. Absent on a tab. */
|
|
6
|
+
title: string | undefined;
|
|
7
|
+
loading: boolean;
|
|
8
|
+
error: string | undefined;
|
|
9
|
+
/** The top level's shelves (Playlists, Albums, ...), when it is a set of folders to switch
|
|
10
|
+
* between. They are shown as tabs instead of a list of folders to open, and stay in view while
|
|
11
|
+
* something inside a shelf is open or a search is showing. */
|
|
12
|
+
tabs: BrowseItem[] | undefined;
|
|
13
|
+
/** The open tab; none while a search is showing, since its results belong to no shelf. */
|
|
14
|
+
activeTab: string | undefined;
|
|
15
|
+
/** Goes to a shelf: leaves whatever was open inside one, and any search. */
|
|
16
|
+
selectTab(id: string): void;
|
|
17
|
+
/** Opened a folder (or searching), so there is somewhere to go back to. */
|
|
18
|
+
canGoBack: boolean;
|
|
19
|
+
searching: boolean;
|
|
20
|
+
open(item: BrowseItem): void;
|
|
21
|
+
back(): void;
|
|
22
|
+
/** What is typed in the search box. */
|
|
23
|
+
query: string;
|
|
24
|
+
/** Lists what matches `text`; an empty string goes back to where the browser was. */
|
|
25
|
+
search(text: string): void;
|
|
26
|
+
}
|
|
27
|
+
/** Walks a player's own media library through the runtime. The top level is read once: shelves
|
|
28
|
+
* become tabs (the first is open to begin with), anything else is a plain list. Below it, a stack
|
|
29
|
+
* of opened folders; apart from it, an optional search, and clearing the search returns to where
|
|
30
|
+
* the browser was. */
|
|
31
|
+
export declare function useMediaBrowser(ref: EntityRef): MediaBrowserState;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useClient } from './provider.js';
|
|
3
|
+
/** A top level that is nothing but folders to look inside is a set of shelves, which read better
|
|
4
|
+
* as tabs than as a list that always looks the same. */
|
|
5
|
+
const isShelves = (items) => items.length >= 2 && items.every((item) => item.expandable && !item.playable);
|
|
6
|
+
const messageOf = (error) => (error instanceof Error ? error.message : String(error));
|
|
7
|
+
/** Walks a player's own media library through the runtime. The top level is read once: shelves
|
|
8
|
+
* become tabs (the first is open to begin with), anything else is a plain list. Below it, a stack
|
|
9
|
+
* of opened folders; apart from it, an optional search, and clearing the search returns to where
|
|
10
|
+
* the browser was. */
|
|
11
|
+
export function useMediaBrowser(ref) {
|
|
12
|
+
const client = useClient();
|
|
13
|
+
const [trail, setTrail] = useState([{}]);
|
|
14
|
+
const [text, setText] = useState('');
|
|
15
|
+
const [tab, setTab] = useState();
|
|
16
|
+
// Answers are kept with the request they answer, so a stale one is never shown for a new one.
|
|
17
|
+
const [top, setTop] = useState(null);
|
|
18
|
+
const [answer, setAnswer] = useState(null);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
let current = true;
|
|
21
|
+
client.browse(ref, {}).then((level) => current && setTop({ key: 'top', ...level }), (error) => current && setTop({ key: 'top', items: [], error: messageOf(error) }));
|
|
22
|
+
return () => {
|
|
23
|
+
current = false;
|
|
24
|
+
};
|
|
25
|
+
}, [client, ref]);
|
|
26
|
+
const needle = text.trim();
|
|
27
|
+
const searching = needle !== '';
|
|
28
|
+
const here = trail.at(-1) ?? {};
|
|
29
|
+
const atTop = trail.length === 1;
|
|
30
|
+
const tabs = top && !top.error && isShelves(top.items) ? top.items : undefined;
|
|
31
|
+
const selected = tabs ? (tabs.find((item) => item.id === tab) ?? tabs[0])?.id : undefined;
|
|
32
|
+
// What to ask for, if anything: a search, a folder, or the open tab. A top level that is not
|
|
33
|
+
// shelves is already in hand.
|
|
34
|
+
const path = atTop ? selected : here.path;
|
|
35
|
+
const key = searching ? `search:${needle}` : `path:${path ?? ''}`;
|
|
36
|
+
const result = answer?.key === key ? answer : null;
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const request = searching ? { search: needle } : path === undefined ? undefined : { path };
|
|
39
|
+
if (!request) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
let current = true;
|
|
43
|
+
const timer = setTimeout(() => {
|
|
44
|
+
client.browse(ref, request).then((level) => current && setAnswer({ key, ...level }), (error) => current && setAnswer({ key, items: [], error: messageOf(error) }));
|
|
45
|
+
},
|
|
46
|
+
// Typing in the search box waits for a pause; opening a folder or a tab does not.
|
|
47
|
+
searching ? 300 : 0);
|
|
48
|
+
return () => {
|
|
49
|
+
current = false;
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
};
|
|
52
|
+
}, [client, ref, key, searching, needle, path]);
|
|
53
|
+
const open = useCallback((item) => setTrail((levels) => [...levels, { path: item.id, title: item.title }]), []);
|
|
54
|
+
const selectTab = useCallback((id) => {
|
|
55
|
+
setTab(id);
|
|
56
|
+
setText('');
|
|
57
|
+
setTrail([{}]);
|
|
58
|
+
}, []);
|
|
59
|
+
const back = useCallback(() => {
|
|
60
|
+
if (text.trim() !== '') {
|
|
61
|
+
setText('');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
setTrail((levels) => (levels.length > 1 ? levels.slice(0, -1) : levels));
|
|
65
|
+
}, [text]);
|
|
66
|
+
// The plain top-level list, when there are no shelves to make tabs of.
|
|
67
|
+
const listing = !searching && atTop && !tabs ? top : result;
|
|
68
|
+
return {
|
|
69
|
+
items: listing?.items ?? [],
|
|
70
|
+
title: searching
|
|
71
|
+
? (result?.title ?? `Results for “${needle}”`)
|
|
72
|
+
: atTop
|
|
73
|
+
? undefined
|
|
74
|
+
: (result?.title ?? here.title),
|
|
75
|
+
loading: listing === null,
|
|
76
|
+
error: listing?.error,
|
|
77
|
+
tabs,
|
|
78
|
+
activeTab: searching ? undefined : selected,
|
|
79
|
+
selectTab,
|
|
80
|
+
canGoBack: searching || !atTop,
|
|
81
|
+
searching,
|
|
82
|
+
open,
|
|
83
|
+
back,
|
|
84
|
+
query: text,
|
|
85
|
+
search: setText,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media-browser.js","sourceRoot":"","sources":["../src/use-media-browser.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hashsome/ui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Design system components and hooks",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./package.json": "./package.json",
|
|
12
|
+
"./gallery": {
|
|
13
|
+
"types": "./dist/gallery/index.d.ts",
|
|
14
|
+
"default": "./dist/gallery/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@emotion/react": "11.14.0",
|
|
19
|
+
"@hashsome/core": "0.1.0",
|
|
20
|
+
"e-prim": "2.0.1",
|
|
21
|
+
"motion": "13.4.5",
|
|
22
|
+
"react": "19.3.0",
|
|
23
|
+
"react-router": "8.4.0",
|
|
24
|
+
"recharts": "3.10.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@testing-library/react": "16.3.3",
|
|
28
|
+
"@testing-library/user-event": "14.6.7",
|
|
29
|
+
"@types/react": "19.3.0",
|
|
30
|
+
"@types/react-dom": "19.3.0",
|
|
31
|
+
"@vitejs/plugin-react": "6.1.1",
|
|
32
|
+
"jsdom": "30.1.1",
|
|
33
|
+
"react-dom": "19.3.0",
|
|
34
|
+
"vite": "8.3.1"
|
|
35
|
+
},
|
|
36
|
+
"license": "GPL-3.0-only",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/dstoyanoff/hashsome.git",
|
|
40
|
+
"directory": "packages/ui"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/dstoyanoff/hashsome#readme",
|
|
43
|
+
"bugs": "https://github.com/dstoyanoff/hashsome/issues",
|
|
44
|
+
"files": [
|
|
45
|
+
"dist"
|
|
46
|
+
],
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"provenance": true
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"docs": "vite",
|
|
54
|
+
"docs:build": "vite build",
|
|
55
|
+
"build": "tsc -b tsconfig.build.json"
|
|
56
|
+
}
|
|
57
|
+
}
|