@glasshome/ui 1.4.0 → 1.5.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/dist/index.js +1 -1
- package/dist/lib/carousel-classes.d.ts +10 -1
- package/dist/lib/tier-badge.d.ts +1 -1
- package/dist/solid/image-picker.d.ts +8 -0
- package/dist/solid/index.d.ts +4 -0
- package/dist/solid/index.js +4166 -3581
- package/dist/solid/media-copy.d.ts +4 -0
- package/dist/solid/media-store.d.ts +55 -0
- package/dist/solid/media-tile.d.ts +15 -0
- package/dist/solid/popover.d.ts +5 -1
- package/dist/solid/responsive-dialog.d.ts +5 -1
- package/dist/solid/schema-form.d.ts +1 -1
- package/dist/{utils-B020EZLJ.js → utils-8e8QCynI.js} +6 -2
- package/package.json +1 -1
- package/src/lib/carousel-classes.ts +18 -7
- package/src/lib/tier-badge.ts +1 -1
- package/src/styles/globals.css +1 -1
- package/src/styles/theme.css +0 -4
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MediaStoreError } from "./media-store.js";
|
|
2
|
+
export declare function toMediaStoreError(cause: unknown): MediaStoreError;
|
|
3
|
+
export declare function mediaStoreErrorCopy(error: MediaStoreError): string;
|
|
4
|
+
export declare function mediaIndexErrorCopy(error: MediaStoreError): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type StoredMedia = {
|
|
2
|
+
id: string;
|
|
3
|
+
mimeType: string;
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
size: number;
|
|
7
|
+
/** Server-computed count of live widget configs referencing this id. */
|
|
8
|
+
usedBy: number;
|
|
9
|
+
};
|
|
10
|
+
export type MediaQuotaUsage = {
|
|
11
|
+
bytes: number;
|
|
12
|
+
limitBytes: number;
|
|
13
|
+
files: number;
|
|
14
|
+
limitFiles: number;
|
|
15
|
+
};
|
|
16
|
+
export type MediaStoreErrorKind = "file_too_large" | "image_too_large" | "not_an_image" | "quota_bytes_exceeded" | "quota_files_exceeded" | "upload_rate_exceeded" | "server_storage_full" | "no_active_household" | "upload_failed";
|
|
17
|
+
export declare class MediaStoreError extends Error {
|
|
18
|
+
readonly kind: MediaStoreErrorKind;
|
|
19
|
+
readonly usage?: MediaQuotaUsage;
|
|
20
|
+
constructor(kind: MediaStoreErrorKind, usage?: MediaQuotaUsage);
|
|
21
|
+
}
|
|
22
|
+
/** One gallery open, one query: the server counts usage in the same scan. */
|
|
23
|
+
export type MediaIndex = {
|
|
24
|
+
media: StoredMedia[];
|
|
25
|
+
usage: MediaQuotaUsage;
|
|
26
|
+
};
|
|
27
|
+
/** "thumb" is a server-side derivative, longest edge ~400px, for grids. */
|
|
28
|
+
export type MediaVariant = "original" | "thumb";
|
|
29
|
+
export interface MediaStore {
|
|
30
|
+
index(): Promise<MediaIndex>;
|
|
31
|
+
upload(file: File): Promise<StoredMedia>;
|
|
32
|
+
remove(id: string): Promise<void>;
|
|
33
|
+
url(id: string, variant?: MediaVariant): string;
|
|
34
|
+
}
|
|
35
|
+
export declare const MediaStoreContext: import("solid-js").Context<MediaStore | undefined>;
|
|
36
|
+
/** Host apps call this once at startup; MediaStoreContext overrides it per-tree. */
|
|
37
|
+
export declare function provideMediaStore(store: MediaStore): void;
|
|
38
|
+
export declare function useMediaStore(): MediaStore | undefined;
|
|
39
|
+
/** One grid page. The picker and the library both slice by this, so neither can
|
|
40
|
+
* mount a whole 500-file library at once. */
|
|
41
|
+
export declare const MEDIA_PAGE_SIZE = 24;
|
|
42
|
+
/** A row whose mime is missing or not a string is not an image; a throw here would
|
|
43
|
+
* take the surrounding gallery down with it. */
|
|
44
|
+
export declare function isMediaImage(item: StoredMedia): boolean;
|
|
45
|
+
/** Unused first: someone browsing stored media is looking for what is safe to delete. */
|
|
46
|
+
export declare function sortMediaForClearing(media: StoredMedia[]): StoredMedia[];
|
|
47
|
+
export interface BrokenMedia {
|
|
48
|
+
isBroken: (item: StoredMedia) => boolean;
|
|
49
|
+
markBroken: (item: StoredMedia) => void;
|
|
50
|
+
}
|
|
51
|
+
/** Keyed by the url that failed, so a re-uploaded id (new url) starts unbroken again. */
|
|
52
|
+
export declare function createBrokenMedia(thumbUrl: (id: string) => string): BrokenMedia;
|
|
53
|
+
export declare function mediaUrl(id: string | null | undefined): string | undefined;
|
|
54
|
+
/** Reads better than mediaUrl in an image widget's source. */
|
|
55
|
+
export declare const imageUrl: typeof mediaUrl;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StoredMedia } from "./media-store.js";
|
|
2
|
+
export interface MediaTileProps {
|
|
3
|
+
item: StoredMedia;
|
|
4
|
+
thumbUrl: string;
|
|
5
|
+
/** Describes what the click does here: the picker chooses, a library opens a preview. */
|
|
6
|
+
label: string;
|
|
7
|
+
broken: boolean;
|
|
8
|
+
onSelect: () => void;
|
|
9
|
+
onBroken: () => void;
|
|
10
|
+
onDelete?: () => void;
|
|
11
|
+
markUnused?: boolean;
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function MediaTile(props: MediaTileProps): import("solid-js").JSX.Element;
|
package/dist/solid/popover.d.ts
CHANGED
|
@@ -11,7 +11,11 @@ declare const Popover: typeof import("@kobalte/core/popover").Root & {
|
|
|
11
11
|
Trigger: typeof import("@kobalte/core/popover").Trigger;
|
|
12
12
|
};
|
|
13
13
|
declare const PopoverTrigger: Component<ComponentProps<typeof PopoverPrimitive.Trigger>>;
|
|
14
|
-
|
|
14
|
+
type PopoverContentProps = ComponentProps<typeof PopoverPrimitive.Content> & {
|
|
15
|
+
/** "field" wears the concave input surface, the way SelectContent does. */
|
|
16
|
+
surface?: "overlay" | "field";
|
|
17
|
+
};
|
|
18
|
+
declare const PopoverContent: Component<PopoverContentProps>;
|
|
15
19
|
declare const PopoverAnchor: Component<ComponentProps<typeof PopoverPrimitive.Anchor>>;
|
|
16
20
|
declare const anchorToTriggerTop: (anchor?: HTMLElement) => {
|
|
17
21
|
x: number;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { VariantProps } from "cva";
|
|
1
2
|
import { type Component, type ComponentProps, type JSX, type ParentComponent } from "solid-js";
|
|
3
|
+
import type { buttonVariants } from "../lib/button-variants.js";
|
|
2
4
|
interface ResponsiveDialogProps {
|
|
3
5
|
children: JSX.Element;
|
|
4
6
|
open?: boolean;
|
|
@@ -12,5 +14,7 @@ declare const ResponsiveDialogHeader: Component<ComponentProps<"div">>;
|
|
|
12
14
|
declare const ResponsiveDialogTitle: Component<ComponentProps<"h2">>;
|
|
13
15
|
declare const ResponsiveDialogDescription: Component<ComponentProps<"p">>;
|
|
14
16
|
declare const ResponsiveDialogFooter: Component<ComponentProps<"div">>;
|
|
15
|
-
|
|
17
|
+
/** Defaults to the footer's outline button; an icon-only close passes `ghost`
|
|
18
|
+
* so the glyph is not boxed. */
|
|
19
|
+
declare const ResponsiveDialogClose: ParentComponent<ComponentProps<"button"> & VariantProps<typeof buttonVariants>>;
|
|
16
20
|
export { ResponsiveDialog, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogFooter, ResponsiveDialogHeader, ResponsiveDialogTitle, ResponsiveDialogTrigger, };
|
|
@@ -22,7 +22,7 @@ export interface ExtendedJSONSchema extends JSONSchema7 {
|
|
|
22
22
|
* schemas with formTypes it predates). Kept in lockstep with the SDK's field
|
|
23
23
|
* helpers by dash's formType parity test.
|
|
24
24
|
*/
|
|
25
|
-
export declare const SCHEMA_FORM_FORM_TYPES: readonly ["icon-picker", "area-picker", "list", "variants"];
|
|
25
|
+
export declare const SCHEMA_FORM_FORM_TYPES: readonly ["icon-picker", "image-picker", "area-picker", "list", "variants"];
|
|
26
26
|
/**
|
|
27
27
|
* New-item defaults from the wire schema: the serialized `default` when the
|
|
28
28
|
* SDK provided one (field.variants always does), else property defaults; for
|
|
@@ -152,10 +152,14 @@ var m = (e) => typeof e == "boolean" ? `${e}` : e === 0 ? "0" : e, h = [], { com
|
|
|
152
152
|
none: ""
|
|
153
153
|
}, T = "cursor-pointer transition-colors duration-200 hover:border-border hover:bg-foreground/[0.03] focus-within:border-border", E = "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] md:px-4", D = "font-semibold leading-none", O = "text-muted-foreground text-sm", k = "col-start-2 row-span-2 row-start-1 self-start justify-self-end", A = "px-3 md:px-4", j = "flex items-center px-3 md:px-4 [.border-t]:pt-6", ae = "h-full overflow-hidden";
|
|
154
154
|
function oe(e, t = "horizontal") {
|
|
155
|
-
|
|
155
|
+
if (e === "wipe") return "carousel-stack";
|
|
156
|
+
let n = t === "vertical";
|
|
157
|
+
return e === "fade" ? n ? "flex flex-col" : "flex" : `flex ${n ? "-mt-4 flex-col" : "-ml-4"}`;
|
|
156
158
|
}
|
|
157
159
|
function se(e, t = "horizontal") {
|
|
158
|
-
|
|
160
|
+
if (e === "wipe") return "min-w-0 carousel-wipe";
|
|
161
|
+
let n = "min-w-0 shrink-0 grow-0 basis-full";
|
|
162
|
+
return e === "fade" ? n : `${n} ${t === "horizontal" ? "pl-4" : "pt-4"}`;
|
|
159
163
|
}
|
|
160
164
|
var M = "flex items-center justify-center gap-2";
|
|
161
165
|
function N(e) {
|
package/package.json
CHANGED
|
@@ -6,24 +6,35 @@ export type CarouselTransition = "slide" | "fade" | "wipe";
|
|
|
6
6
|
|
|
7
7
|
export const CAROUSEL_VIEWPORT = "h-full overflow-hidden";
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Only wipe stacks in CSS. Fade keeps embla's standard flex track, which is the
|
|
11
|
+
* structure its plugin is built for: embla reads each snap from the slide's
|
|
12
|
+
* offset along the axis, and the plugin then translates every slide back onto
|
|
13
|
+
* the viewport to cross-fade them. Slides sharing one grid cell share offset 0,
|
|
14
|
+
* so every snap collapses onto the same point and a pointer drag has no
|
|
15
|
+
* distance to resolve: it never changes slide. Index-driven navigation
|
|
16
|
+
* (autoplay, arrows, dots) survives the collapse, which is why wipe still
|
|
17
|
+
* advances.
|
|
18
|
+
*/
|
|
10
19
|
export function carouselTrack(
|
|
11
20
|
transition: CarouselTransition,
|
|
12
21
|
orientation: "horizontal" | "vertical" = "horizontal",
|
|
13
22
|
) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
if (transition === "wipe") return "carousel-stack";
|
|
24
|
+
const vertical = orientation === "vertical";
|
|
25
|
+
// Fade slides sit on top of each other, so the track carries no gutter.
|
|
26
|
+
if (transition === "fade") return vertical ? "flex flex-col" : "flex";
|
|
27
|
+
return `flex ${vertical ? "-mt-4 flex-col" : "-ml-4"}`;
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
export function carouselItem(
|
|
20
31
|
transition: CarouselTransition,
|
|
21
32
|
orientation: "horizontal" | "vertical" = "horizontal",
|
|
22
33
|
) {
|
|
23
|
-
// Stacked slides fill their grid cell; only a flex track needs basis/gutter.
|
|
24
34
|
if (transition === "wipe") return "min-w-0 carousel-wipe";
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
const track = "min-w-0 shrink-0 grow-0 basis-full";
|
|
36
|
+
if (transition === "fade") return track;
|
|
37
|
+
return `${track} ${orientation === "horizontal" ? "pl-4" : "pt-4"}`;
|
|
27
38
|
}
|
|
28
39
|
|
|
29
40
|
export const CAROUSEL_DOTS = "flex items-center justify-center gap-2";
|
package/src/lib/tier-badge.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Metallic tier chip: 135deg brushed sweep, bright ends, dip in the middle. */
|
|
2
2
|
|
|
3
3
|
export const TIER_BADGE_CLASS =
|
|
4
|
-
"inline-flex cursor-default select-none items-center rounded-full px-2 py-0.5 font-black text-[10px]
|
|
4
|
+
"inline-flex cursor-default select-none items-center rounded-full px-2 py-0.5 font-black text-[10px] tracking-wide";
|
|
5
5
|
|
|
6
6
|
/** Optional sweep shaping. Default is the symmetric brushed look (both ends
|
|
7
7
|
* `hi`, dipping to `lo` at the midpoint). The collectible/license golds are a
|
package/src/styles/globals.css
CHANGED
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
margin-top: 0.125rem;
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
/*
|
|
236
|
+
/* Carousel `wipe` puts every slide in one grid cell. This is
|
|
237
237
|
* structural, so it ships as real CSS: a Tailwind arbitrary variant written in
|
|
238
238
|
* package source never reaches a consumer, because Tailwind skips node_modules
|
|
239
239
|
* when scanning for class names. */
|
package/src/styles/theme.css
CHANGED
|
@@ -261,10 +261,6 @@
|
|
|
261
261
|
label:has(> input:is([type="checkbox"], [type="radio"]):not(:disabled)) {
|
|
262
262
|
cursor: pointer;
|
|
263
263
|
}
|
|
264
|
-
/* Old embedded WebViews (Shelly Wall Display) native-paint appearance:button as a gray box. */
|
|
265
|
-
button {
|
|
266
|
-
appearance: none;
|
|
267
|
-
}
|
|
268
264
|
}
|
|
269
265
|
|
|
270
266
|
/* Utility classes */
|