@fastyshop/ui 0.1.0 → 0.2.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +142 -3
  3. package/dist/generated/components.d.ts +19 -0
  4. package/dist/generated/components.d.ts.map +1 -0
  5. package/dist/generated/components.js +12 -0
  6. package/dist/generated/components.js.map +1 -0
  7. package/dist/hooks/useCopyToClipboard/useCopyToClipboard.d.ts +23 -0
  8. package/dist/hooks/useCopyToClipboard/useCopyToClipboard.d.ts.map +1 -0
  9. package/dist/hooks/useCopyToClipboard/useCopyToClipboard.js +78 -0
  10. package/dist/hooks/useCopyToClipboard/useCopyToClipboard.js.map +1 -0
  11. package/dist/hooks/useMediaQuery/useMediaQuery.d.ts +27 -0
  12. package/dist/hooks/useMediaQuery/useMediaQuery.d.ts.map +1 -0
  13. package/dist/hooks/useMediaQuery/useMediaQuery.js +114 -0
  14. package/dist/hooks/useMediaQuery/useMediaQuery.js.map +1 -0
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +3 -3
  18. package/dist/index.js.map +1 -1
  19. package/dist/primitives/Button/Button.d.ts +11 -0
  20. package/dist/primitives/Button/Button.d.ts.map +1 -0
  21. package/dist/{button.js → primitives/Button/Button.js} +14 -22
  22. package/dist/primitives/Button/Button.js.map +1 -0
  23. package/dist/primitives/Button/types/button.types.d.ts +34 -0
  24. package/dist/primitives/Button/types/button.types.d.ts.map +1 -0
  25. package/dist/primitives/Button/types/button.types.js +2 -0
  26. package/dist/primitives/Button/types/button.types.js.map +1 -0
  27. package/dist/primitives/Button/utils/hasVisibleLabel.d.ts +3 -0
  28. package/dist/primitives/Button/utils/hasVisibleLabel.d.ts.map +1 -0
  29. package/dist/primitives/Button/utils/hasVisibleLabel.js +17 -0
  30. package/dist/primitives/Button/utils/hasVisibleLabel.js.map +1 -0
  31. package/dist/primitives/Separator/Separator.d.ts +25 -0
  32. package/dist/primitives/Separator/Separator.d.ts.map +1 -0
  33. package/dist/primitives/Separator/Separator.js +24 -0
  34. package/dist/primitives/Separator/Separator.js.map +1 -0
  35. package/dist/primitives/Skeleton/Skeleton.d.ts +14 -0
  36. package/dist/primitives/Skeleton/Skeleton.d.ts.map +1 -0
  37. package/dist/primitives/Skeleton/Skeleton.js +32 -0
  38. package/dist/primitives/Skeleton/Skeleton.js.map +1 -0
  39. package/dist/primitives/Spinner/Spinner.d.ts +23 -0
  40. package/dist/primitives/Spinner/Spinner.d.ts.map +1 -0
  41. package/dist/primitives/Spinner/Spinner.js +27 -0
  42. package/dist/primitives/Spinner/Spinner.js.map +1 -0
  43. package/dist/primitives/Typography/Typography.d.ts +30 -0
  44. package/dist/primitives/Typography/Typography.d.ts.map +1 -0
  45. package/dist/primitives/Typography/Typography.js +48 -0
  46. package/dist/primitives/Typography/Typography.js.map +1 -0
  47. package/dist/primitives/Typography/types/typography.types.d.ts +31 -0
  48. package/dist/primitives/Typography/types/typography.types.d.ts.map +1 -0
  49. package/dist/primitives/Typography/types/typography.types.js +2 -0
  50. package/dist/primitives/Typography/types/typography.types.js.map +1 -0
  51. package/dist/runtime/clipboard/clipboard.d.ts +4 -0
  52. package/dist/runtime/clipboard/clipboard.d.ts.map +1 -0
  53. package/dist/runtime/clipboard/clipboard.js +22 -0
  54. package/dist/runtime/clipboard/clipboard.js.map +1 -0
  55. package/dist/styles.css +216 -15
  56. package/dist/tailwind-theme.css +5 -1
  57. package/package.json +5 -4
  58. package/dist/button.d.ts +0 -44
  59. package/dist/button.d.ts.map +0 -1
  60. package/dist/button.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  All notable changes to `@fastyshop/ui` are recorded here. Released versions and Git tags are immutable.
4
4
 
5
+ ## 0.2.0
6
+
7
+ - Added the Typography, Spinner, Separator, and Skeleton visual primitives alongside Button.
8
+ - Added the public `useMediaQuery` and `useCopyToClipboard` hooks with explicit SSR and clipboard result contracts.
9
+ - Added package-private clipboard runtime delivery and one shared `clsx` class composition contract.
10
+ - Expanded the descriptor-generated package and source-copy registry inventory for the complete core UI wave.
11
+
12
+ This candidate has not been published or adopted by Cabinet or Platform. Promotion, tag creation, npm publication, and application upgrades remain separate operations.
13
+
5
14
  ## 0.1.0
6
15
 
7
16
  - Added the first public package contract for ESM, TypeScript declarations, runtime CSS, and the Tailwind CSS v4 bridge.
package/README.md CHANGED
@@ -1,13 +1,17 @@
1
1
  # @fastyshop/ui
2
2
 
3
- `@fastyshop/ui` contains the shared FastyShop product tokens and React components. The package ships ESM, TypeScript declarations, Tailwind CSS v4 integration, the Inter variable font, and the FastyShop Button.
3
+ `@fastyshop/ui` contains the shared FastyShop product tokens, React components,
4
+ and public hooks. The package ships ESM, TypeScript declarations, Tailwind CSS
5
+ v4 integration, the Inter variable font, the FastyShop Button, Separator,
6
+ Skeleton, Spinner and Typography primitives, and the `useCopyToClipboard` and
7
+ `useMediaQuery` hooks.
4
8
 
5
9
  ## Install
6
10
 
7
11
  Install an exact version from the public npm registry. No npm login or read token is required.
8
12
 
9
13
  ```bash
10
- pnpm add @fastyshop/ui@0.1.0
14
+ pnpm add @fastyshop/ui@0.2.0
11
15
  ```
12
16
 
13
17
  React and React DOM are peer dependencies. Supported versions are `>=19.2.0 <20`. The package requires Node.js `>=24.18.0 <25` for build and server-side use.
@@ -35,7 +39,19 @@ Tailwind CSS v4 consumers can additionally import the semantic utility bridge:
35
39
  @import "@fastyshop/ui/tailwind-theme.css";
36
40
  ```
37
41
 
38
- The bridge maps `fs`-prefixed utilities to the runtime CSS variables. It does not copy token values into the consuming application.
42
+ The bridge maps `fs`-prefixed utilities to the runtime CSS variables. It does not copy token values into the consuming application. It deliberately replaces Tailwind's default responsive variants with only `md: 48rem` and `lg: 64rem`.
43
+
44
+ ## Responsive layout
45
+
46
+ The page shell remains full-width. Use the responsive semantic grid without a global `container` or page-level `max-width`:
47
+
48
+ ```html
49
+ <main
50
+ class="grid min-w-0 grid-cols-4 gap-x-fs-grid-column-gap md:grid-cols-8 lg:grid-cols-12"
51
+ ></main>
52
+ ```
53
+
54
+ Forms and prose opt into local measures with `w-full max-w-(--fs-layout-content-form-max)` or `w-full max-w-(--fs-layout-content-prose-max)`. Wide tables and timelines own a labelled, keyboard-focusable local scroller; they must not make `body` scroll horizontally. See the repository's `docs/responsive-layout.md` for safe-area, overflow, container-query, and localization guidance.
39
55
 
40
56
  ## Button
41
57
 
@@ -49,6 +65,129 @@ export function SaveAction() {
49
65
 
50
66
  `Button` is a client component backed by Base UI. The package owns that runtime dependency; consumers do not install Base UI, Radix, or shadcn directly. Use a link for navigation, keep `loading` controlled, and provide a non-empty `aria-label` for icon-only buttons.
51
67
 
68
+ ## Typography
69
+
70
+ ```tsx
71
+ import { Typography } from "@fastyshop/ui";
72
+
73
+ export function PageTitle() {
74
+ return (
75
+ <Typography as="h1" variant="heading-lg">
76
+ Orders
77
+ </Typography>
78
+ );
79
+ }
80
+ ```
81
+
82
+ `variant` is required and selects one of the eleven semantic typography roles;
83
+ `as` independently selects `span` (default), `p`, `div`, `h1`–`h6`,
84
+ `blockquote`, or `figcaption`. Typography is server-safe, inherits color,
85
+ neutralizes native margins, and leaves wrapping and document hierarchy to the
86
+ consumer. Component-owned labels and titles keep their owning component DOM
87
+ instead of adding a nested Typography wrapper. See the
88
+ [repository guide](https://github.com/rubyhat/fastyshop-ui/blob/main/docs/typography.md)
89
+ for the complete API and role guidance.
90
+
91
+ ## Spinner
92
+
93
+ ```tsx
94
+ import { Spinner } from "@fastyshop/ui";
95
+
96
+ export function OrdersStatus() {
97
+ return <Spinner decorative={false} label="Loading orders" />;
98
+ }
99
+ ```
100
+
101
+ Spinner is server-safe and decorative by default. Announced use requires a
102
+ caller-owned localized label. The consumer owns loading lifecycle, `aria-busy`,
103
+ completion, errors and retries. Sizes are `sm`, `md` and `lg`; color inherits
104
+ from context, reduced motion disables rotation, and forced colors follow the
105
+ system-adjusted foreground. See the
106
+ [repository guide](https://github.com/rubyhat/fastyshop-ui/blob/main/docs/spinner.md)
107
+ for the full semantic and registry contract.
108
+
109
+ ## Separator
110
+
111
+ ```tsx
112
+ import { Separator } from "@fastyshop/ui";
113
+
114
+ export function OrderSummaryBoundary() {
115
+ return <Separator />;
116
+ }
117
+ ```
118
+
119
+ Separator is server-safe and decorative by default. Set `decorative={false}`
120
+ only when the divider is a meaningful document boundary; choose horizontal or
121
+ vertical orientation and keep surrounding spacing and vertical length in the
122
+ consumer. See the
123
+ [repository guide](https://github.com/rubyhat/fastyshop-ui/blob/main/docs/separator.md)
124
+ for the complete semantics and composition contract.
125
+
126
+ ## Skeleton
127
+
128
+ ```tsx
129
+ import { Skeleton } from "@fastyshop/ui";
130
+
131
+ export function OrderCardPlaceholder() {
132
+ return <Skeleton className="order-card-placeholder" />;
133
+ }
134
+ ```
135
+
136
+ Skeleton is a decorative, server-safe loading placeholder. The consumer owns
137
+ its geometry, changing-region `aria-busy` state and localized status message.
138
+ Reduced motion disables pulsing, while forced colors preserve a visible static
139
+ boundary. See the
140
+ [repository guide](https://github.com/rubyhat/fastyshop-ui/blob/main/docs/skeleton.md)
141
+ for sizing and accessibility guidance.
142
+
143
+ ## useMediaQuery
144
+
145
+ ```tsx
146
+ "use client";
147
+
148
+ import { useMediaQuery } from "@fastyshop/ui";
149
+
150
+ export function ResponsiveBehavior() {
151
+ const isDesktop = useMediaQuery("desktop");
152
+ const reduceMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
153
+ return <span>{isDesktop && !reduceMotion ? "Enhanced motion" : "Standard view"}</span>;
154
+ }
155
+ ```
156
+
157
+ FastyShop shorthand maps `tablet` to `48rem` and `desktop` to `64rem`;
158
+ `max-*` uses an exclusive upper boundary. Structured input supports `min`,
159
+ `max`, and `pointer`. Server rendering and initial hydration return `false`,
160
+ then React synchronizes the client match. Prefer CSS media/container queries
161
+ for visual layout. The current browser contract uses modern `MediaQueryList`
162
+ events and Media Queries Level 4 range syntax. The full API, browser boundary,
163
+ and raw-query examples are documented in the [repository guide](https://github.com/rubyhat/fastyshop-ui/blob/main/docs/use-media-query.md).
164
+
165
+ ## useCopyToClipboard
166
+
167
+ ```tsx
168
+ "use client";
169
+
170
+ import { useCopyToClipboard } from "@fastyshop/ui";
171
+
172
+ export function CopyOrderId({ orderId }: { orderId: string }) {
173
+ const { copyToClipboard, isCopied } = useCopyToClipboard();
174
+
175
+ return (
176
+ <button onClick={() => void copyToClipboard(orderId)} type="button">
177
+ {isCopied ? "Copied" : "Copy order id"}
178
+ </button>
179
+ );
180
+ }
181
+ ```
182
+
183
+ `copyToClipboard` resolves to `success`, `empty`, `unsupported`, or `failed`.
184
+ Only an empty string skips the browser API; other strings are passed to
185
+ `navigator.clipboard.writeText` unchanged. `isCopied` is transient
186
+ presentation state for the latest call. Consumers own localized and
187
+ accessible feedback, analytics, and recovery behavior. The full result,
188
+ lifecycle, server, and source-copy contracts are documented in the
189
+ [repository guide](https://github.com/rubyhat/fastyshop-ui/blob/main/docs/use-copy-to-clipboard.md).
190
+
52
191
  ## Package boundary
53
192
 
54
193
  The public exports are:
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Generated from public entity descriptors. Do not edit by hand.
3
+ * Interactive components and hooks keep their own leaf-level client boundaries.
4
+ */
5
+ export { Button } from "../primitives/Button/Button.js";
6
+ export type { ButtonProps } from "../primitives/Button/Button.js";
7
+ export { Separator } from "../primitives/Separator/Separator.js";
8
+ export type { SeparatorOrientation, SeparatorProps } from "../primitives/Separator/Separator.js";
9
+ export { Skeleton } from "../primitives/Skeleton/Skeleton.js";
10
+ export type { SkeletonProps } from "../primitives/Skeleton/Skeleton.js";
11
+ export { Spinner } from "../primitives/Spinner/Spinner.js";
12
+ export type { SpinnerProps, SpinnerSize } from "../primitives/Spinner/Spinner.js";
13
+ export { Typography } from "../primitives/Typography/Typography.js";
14
+ export type { TypographyElement, TypographyProps, TypographyVariant } from "../primitives/Typography/Typography.js";
15
+ export { useCopyToClipboard } from "../hooks/useCopyToClipboard/useCopyToClipboard.js";
16
+ export type { CopyToClipboardResult, UseCopyToClipboardOptions } from "../hooks/useCopyToClipboard/useCopyToClipboard.js";
17
+ export { useMediaQuery } from "../hooks/useMediaQuery/useMediaQuery.js";
18
+ export type { MediaQueryInput } from "../hooks/useMediaQuery/useMediaQuery.js";
19
+ //# sourceMappingURL=components.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/generated/components.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AACjE,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACjG,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,YAAY,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAC3D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACpE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AACpH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AACvF,YAAY,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,mDAAmD,CAAC;AAC1H,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,YAAY,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Generated from public entity descriptors. Do not edit by hand.
3
+ * Interactive components and hooks keep their own leaf-level client boundaries.
4
+ */
5
+ export { Button } from "../primitives/Button/Button.js";
6
+ export { Separator } from "../primitives/Separator/Separator.js";
7
+ export { Skeleton } from "../primitives/Skeleton/Skeleton.js";
8
+ export { Spinner } from "../primitives/Spinner/Spinner.js";
9
+ export { Typography } from "../primitives/Typography/Typography.js";
10
+ export { useCopyToClipboard } from "../hooks/useCopyToClipboard/useCopyToClipboard.js";
11
+ export { useMediaQuery } from "../hooks/useMediaQuery/useMediaQuery.js";
12
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/generated/components.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAE9D,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AAEvF,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC"}
@@ -0,0 +1,23 @@
1
+ /** The normalized outcome of one plain-text clipboard write attempt. */
2
+ export type CopyToClipboardResult = "success" | "empty" | "unsupported" | "failed";
3
+ /** Configures transient presentation state without defining consumer feedback. */
4
+ export interface UseCopyToClipboardOptions {
5
+ /**
6
+ * How long a successful copy keeps `isCopied` true, in milliseconds.
7
+ * Use `0` to disable the pulse. Defaults to `2000`.
8
+ */
9
+ copiedDurationMs?: number;
10
+ }
11
+ /**
12
+ * Copies an exact, non-empty string through the Async Clipboard API.
13
+ *
14
+ * The returned Promise resolves to an explicit platform outcome. `isCopied`
15
+ * is presentation-only state for the latest call; applications remain
16
+ * responsible for localized status, accessibility announcements, analytics,
17
+ * and recovery UI.
18
+ */
19
+ export declare const useCopyToClipboard: (options?: UseCopyToClipboardOptions) => {
20
+ copyToClipboard: (value: string) => Promise<CopyToClipboardResult>;
21
+ isCopied: boolean;
22
+ };
23
+ //# sourceMappingURL=useCopyToClipboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCopyToClipboard.d.ts","sourceRoot":"","sources":["../../../src/hooks/useCopyToClipboard/useCopyToClipboard.ts"],"names":[],"mappings":"AAMA,wEAAwE;AACxE,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEnF,kFAAkF;AAClF,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAaD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,yBAAyB,KAClC;IACD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACnE,QAAQ,EAAE,OAAO,CAAC;CAyEnB,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { writeTextToClipboard } from "../../runtime/clipboard/clipboard.js";
4
+ const DEFAULT_COPIED_DURATION_MS = 2_000;
5
+ const MAX_COPIED_DURATION_MS = 2_147_483_647;
6
+ const resolveCopiedDuration = (options) => {
7
+ const duration = options?.copiedDurationMs ?? DEFAULT_COPIED_DURATION_MS;
8
+ if (!Number.isInteger(duration) || duration < 0 || duration > MAX_COPIED_DURATION_MS) {
9
+ throw new TypeError("copiedDurationMs must be an integer from 0 to 2147483647.");
10
+ }
11
+ return duration;
12
+ };
13
+ /**
14
+ * Copies an exact, non-empty string through the Async Clipboard API.
15
+ *
16
+ * The returned Promise resolves to an explicit platform outcome. `isCopied`
17
+ * is presentation-only state for the latest call; applications remain
18
+ * responsible for localized status, accessibility announcements, analytics,
19
+ * and recovery UI.
20
+ */
21
+ export const useCopyToClipboard = (options) => {
22
+ const copiedDurationMs = resolveCopiedDuration(options);
23
+ const [isCopied, setIsCopied] = useState(false);
24
+ const copiedDurationRef = useRef(copiedDurationMs);
25
+ const resetTimerRef = useRef(undefined);
26
+ const latestCallRef = useRef(0);
27
+ const lifecycleRef = useRef(0);
28
+ const isMountedRef = useRef(false);
29
+ const clearResetTimer = useCallback(() => {
30
+ const resetTimer = resetTimerRef.current;
31
+ if (resetTimer === undefined) {
32
+ return;
33
+ }
34
+ globalThis.clearTimeout(resetTimer);
35
+ resetTimerRef.current = undefined;
36
+ }, []);
37
+ useEffect(() => {
38
+ copiedDurationRef.current = copiedDurationMs;
39
+ }, [copiedDurationMs]);
40
+ useEffect(() => {
41
+ isMountedRef.current = true;
42
+ lifecycleRef.current += 1;
43
+ return () => {
44
+ isMountedRef.current = false;
45
+ lifecycleRef.current += 1;
46
+ clearResetTimer();
47
+ };
48
+ }, [clearResetTimer]);
49
+ const copyToClipboard = useCallback(async (value) => {
50
+ latestCallRef.current += 1;
51
+ const call = latestCallRef.current;
52
+ const lifecycle = lifecycleRef.current;
53
+ const duration = copiedDurationRef.current;
54
+ clearResetTimer();
55
+ if (isMountedRef.current) {
56
+ setIsCopied(false);
57
+ }
58
+ const result = await writeTextToClipboard(value);
59
+ const canUpdateLatestCall = isMountedRef.current &&
60
+ lifecycle === lifecycleRef.current &&
61
+ call === latestCallRef.current;
62
+ if (!canUpdateLatestCall || result !== "success" || duration === 0) {
63
+ return result;
64
+ }
65
+ setIsCopied(true);
66
+ resetTimerRef.current = globalThis.setTimeout(() => {
67
+ if (isMountedRef.current &&
68
+ lifecycle === lifecycleRef.current &&
69
+ call === latestCallRef.current) {
70
+ resetTimerRef.current = undefined;
71
+ setIsCopied(false);
72
+ }
73
+ }, duration);
74
+ return result;
75
+ }, [clearResetTimer]);
76
+ return { copyToClipboard, isCopied };
77
+ };
78
+ //# sourceMappingURL=useCopyToClipboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCopyToClipboard.js","sourceRoot":"","sources":["../../../src/hooks/useCopyToClipboard/useCopyToClipboard.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAc5E,MAAM,0BAA0B,GAAG,KAAK,CAAC;AACzC,MAAM,sBAAsB,GAAG,aAAa,CAAC;AAE7C,MAAM,qBAAqB,GAAG,CAAC,OAAmC,EAAU,EAAE;IAC5E,MAAM,QAAQ,GAAG,OAAO,EAAE,gBAAgB,IAAI,0BAA0B,CAAC;IACzE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,sBAAsB,EAAE,CAAC;QACrF,MAAM,IAAI,SAAS,CAAC,2DAA2D,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,OAAmC,EAInC,EAAE;IACF,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,MAAM,CAAuD,SAAS,CAAC,CAAC;IAC9F,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnC,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACvC,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC;QACzC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,UAAU,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QACpC,aAAa,CAAC,OAAO,GAAG,SAAS,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,iBAAiB,CAAC,OAAO,GAAG,gBAAgB,CAAC;IAC/C,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAEvB,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC;QAC5B,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC;QAE1B,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;YAC7B,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC;YAC1B,eAAe,EAAE,CAAC;QACpB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,MAAM,eAAe,GAAG,WAAW,CACjC,KAAK,EAAE,KAAa,EAAkC,EAAE;QACtD,aAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC3B,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC;QACnC,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC;QAE3C,eAAe,EAAE,CAAC;QAClB,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;YACzB,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,MAAM,MAAM,GAA0B,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,mBAAmB,GACvB,YAAY,CAAC,OAAO;YACpB,SAAS,KAAK,YAAY,CAAC,OAAO;YAClC,IAAI,KAAK,aAAa,CAAC,OAAO,CAAC;QACjC,IAAI,CAAC,mBAAmB,IAAI,MAAM,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnE,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,WAAW,CAAC,IAAI,CAAC,CAAC;QAClB,aAAa,CAAC,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE;YACjD,IACE,YAAY,CAAC,OAAO;gBACpB,SAAS,KAAK,YAAY,CAAC,OAAO;gBAClC,IAAI,KAAK,aAAa,CAAC,OAAO,EAC9B,CAAC;gBACD,aAAa,CAAC,OAAO,GAAG,SAAS,CAAC;gBAClC,WAAW,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC,EAAE,QAAQ,CAAC,CAAC;QAEb,OAAO,MAAM,CAAC;IAChB,CAAC,EACD,CAAC,eAAe,CAAC,CAClB,CAAC;IAEF,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC;AACvC,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A FastyShop breakpoint query, structured media conditions, or a raw CSS
3
+ * media query beginning with `(`.
4
+ */
5
+ export type MediaQueryInput = "tablet" | "desktop" | "max-tablet" | "max-desktop" | "tablet:max-desktop" | `(${string}` | {
6
+ min: "tablet" | "desktop";
7
+ max?: "tablet" | "desktop";
8
+ pointer?: "coarse" | "fine";
9
+ } | {
10
+ min?: "tablet" | "desktop";
11
+ max: "tablet" | "desktop";
12
+ pointer?: "coarse" | "fine";
13
+ } | {
14
+ min?: "tablet" | "desktop";
15
+ max?: "tablet" | "desktop";
16
+ pointer: "coarse" | "fine";
17
+ };
18
+ /**
19
+ * Subscribes to a browser media query through React's external-store contract.
20
+ *
21
+ * The server and initial hydration snapshot is always `false`; React updates
22
+ * to the current client match after hydration. Use this hook for JavaScript
23
+ * behavior or conditional mounting, and prefer CSS media/container queries for
24
+ * purely visual responsive layout.
25
+ */
26
+ export declare function useMediaQuery(input: MediaQueryInput): boolean;
27
+ //# sourceMappingURL=useMediaQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaQuery.d.ts","sourceRoot":"","sources":["../../../src/hooks/useMediaQuery/useMediaQuery.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,aAAa,GACb,oBAAoB,GACpB,IAAI,MAAM,EAAE,GACZ;IACE,GAAG,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC1B,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC7B,GACD;IACE,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,GAAG,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC7B,GACD;IACE,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC5B,CAAC;AAqHN;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAI7D"}
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ import { useMemo, useSyncExternalStore } from "react";
3
+ const breakpointWidths = {
4
+ desktop: "64rem",
5
+ tablet: "48rem",
6
+ };
7
+ const breakpointRanks = {
8
+ desktop: 1,
9
+ tablet: 0,
10
+ };
11
+ const shorthandQueries = {
12
+ desktop: `(min-width: ${breakpointWidths.desktop})`,
13
+ "max-desktop": `(width < ${breakpointWidths.desktop})`,
14
+ "max-tablet": `(width < ${breakpointWidths.tablet})`,
15
+ tablet: `(min-width: ${breakpointWidths.tablet})`,
16
+ "tablet:max-desktop": `(min-width: ${breakpointWidths.tablet}) and (width < ${breakpointWidths.desktop})`,
17
+ };
18
+ const breakpointNames = new Set(["tablet", "desktop"]);
19
+ const pointerTypes = new Set(["coarse", "fine"]);
20
+ const conditionKeys = new Set(["min", "max", "pointer"]);
21
+ function isBreakpointName(value) {
22
+ return breakpointNames.has(value);
23
+ }
24
+ function isPointerType(value) {
25
+ return pointerTypes.has(value);
26
+ }
27
+ function invalidQuery(reason) {
28
+ return new TypeError(`Invalid media query input: ${reason}.`);
29
+ }
30
+ function normalizeMediaQuery(input) {
31
+ if (typeof input === "string") {
32
+ const query = input.trim();
33
+ if (query.length === 0)
34
+ throw invalidQuery("the query is empty");
35
+ if (query.startsWith("("))
36
+ return query;
37
+ if (Object.hasOwn(shorthandQueries, query)) {
38
+ return shorthandQueries[query];
39
+ }
40
+ throw invalidQuery(`unsupported shorthand ${JSON.stringify(query)}`);
41
+ }
42
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
43
+ throw invalidQuery("expected a shorthand, raw query, or condition object");
44
+ }
45
+ const keys = Object.keys(input);
46
+ if (keys.length === 0)
47
+ throw invalidQuery("the condition object is empty");
48
+ const unknownKeys = keys.filter((key) => !conditionKeys.has(key));
49
+ if (unknownKeys.length > 0) {
50
+ throw invalidQuery(`unsupported condition ${JSON.stringify(unknownKeys.sort()[0])}`);
51
+ }
52
+ const conditions = input;
53
+ const max = conditions["max"];
54
+ const min = conditions["min"];
55
+ const pointer = conditions["pointer"];
56
+ if (min !== undefined && !isBreakpointName(min)) {
57
+ throw invalidQuery(`unsupported min breakpoint ${JSON.stringify(min)}`);
58
+ }
59
+ if (max !== undefined && !isBreakpointName(max)) {
60
+ throw invalidQuery(`unsupported max breakpoint ${JSON.stringify(max)}`);
61
+ }
62
+ if (pointer !== undefined && !isPointerType(pointer)) {
63
+ throw invalidQuery(`unsupported pointer ${JSON.stringify(pointer)}`);
64
+ }
65
+ if (min === undefined && max === undefined && pointer === undefined) {
66
+ throw invalidQuery("the condition object has no media conditions");
67
+ }
68
+ if (min !== undefined && max !== undefined && breakpointRanks[min] >= breakpointRanks[max]) {
69
+ throw invalidQuery("min must be lower than max");
70
+ }
71
+ return [
72
+ min === undefined ? null : `(min-width: ${breakpointWidths[min]})`,
73
+ max === undefined ? null : `(width < ${breakpointWidths[max]})`,
74
+ pointer === undefined ? null : `(pointer: ${pointer})`,
75
+ ]
76
+ .filter((condition) => condition !== null)
77
+ .join(" and ");
78
+ }
79
+ const getServerSnapshot = () => false;
80
+ const unsupportedStore = {
81
+ getSnapshot: getServerSnapshot,
82
+ subscribe: () => () => {
83
+ // Unsupported browsers have no listener to clean up.
84
+ },
85
+ };
86
+ function createMediaQueryStore(query) {
87
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
88
+ return unsupportedStore;
89
+ }
90
+ const mediaQueryList = window.matchMedia(query);
91
+ return {
92
+ getSnapshot: () => mediaQueryList.matches,
93
+ subscribe: (onStoreChange) => {
94
+ mediaQueryList.addEventListener("change", onStoreChange);
95
+ return () => {
96
+ mediaQueryList.removeEventListener("change", onStoreChange);
97
+ };
98
+ },
99
+ };
100
+ }
101
+ /**
102
+ * Subscribes to a browser media query through React's external-store contract.
103
+ *
104
+ * The server and initial hydration snapshot is always `false`; React updates
105
+ * to the current client match after hydration. Use this hook for JavaScript
106
+ * behavior or conditional mounting, and prefer CSS media/container queries for
107
+ * purely visual responsive layout.
108
+ */
109
+ export function useMediaQuery(input) {
110
+ const query = normalizeMediaQuery(input);
111
+ const store = useMemo(() => createMediaQueryStore(query), [query]);
112
+ return useSyncExternalStore(store.subscribe, store.getSnapshot, getServerSnapshot);
113
+ }
114
+ //# sourceMappingURL=useMediaQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaQuery.js","sourceRoot":"","sources":["../../../src/hooks/useMediaQuery/useMediaQuery.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  * Server-safe public entrypoint for the FastyShop UI package.
3
3
  *
4
4
  * Interactive modules add their own leaf-level `"use client"` directive and
5
- * explicit package export in the task that owns them. This root entrypoint
6
- * remains safe to resolve from server code.
5
+ * component or hook descriptor. The generated barrel is created
6
+ * before build, typecheck, and docs; this tracked wrapper remains server-safe.
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
- export { Button, type ButtonProps } from "./button.js";
10
+ export * from "./generated/components.js";
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * Server-safe public entrypoint for the FastyShop UI package.
3
3
  *
4
4
  * Interactive modules add their own leaf-level `"use client"` directive and
5
- * explicit package export in the task that owns them. This root entrypoint
6
- * remains safe to resolve from server code.
5
+ * component or hook descriptor. The generated barrel is created
6
+ * before build, typecheck, and docs; this tracked wrapper remains server-safe.
7
7
  *
8
8
  * @packageDocumentation
9
9
  */
10
- export { Button } from "./button.js";
10
+ export * from "./generated/components.js";
11
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAoB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { IconOnlyButtonProps, TextButtonProps } from "./types/button.types.js";
2
+ /** Public props for the FastyShop action Button. */
3
+ export type ButtonProps = TextButtonProps | IconOnlyButtonProps;
4
+ /**
5
+ * Production action primitive backed by Base UI.
6
+ *
7
+ * Use a link for navigation. `loading` is controlled by the consumer and does
8
+ * not own an async lifecycle, success state or error copy.
9
+ */
10
+ export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
11
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/primitives/Button/Button.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAGpF,oDAAoD;AACpD,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,MAAM,2GAkEjB,CAAC"}
@@ -1,24 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Button as BaseUIButton } from "@base-ui/react/button";
4
- import { Children, forwardRef, Fragment, isValidElement, } from "react";
5
- function hasVisibleLabel(children) {
6
- return Children.toArray(children).some((child) => {
7
- if (typeof child === "string")
8
- return child.trim().length > 0;
9
- if (typeof child === "number" || typeof child === "bigint")
10
- return true;
11
- if (!isValidElement(child))
12
- return false;
13
- if (child.type === Fragment || typeof child.type === "string") {
14
- return hasVisibleLabel(child.props.children);
15
- }
16
- return true;
17
- });
18
- }
19
- function Spinner() {
20
- return (_jsx("svg", { "aria-hidden": "true", className: "fs-button__spinner", focusable: "false", viewBox: "0 0 24 24", children: _jsx("path", { d: "M21 12a9 9 0 1 1-6.22-8.56" }) }));
21
- }
4
+ import { clsx } from "clsx";
5
+ import { forwardRef } from "react";
6
+ import { Spinner } from "../Spinner/Spinner.js";
7
+ import { hasVisibleLabel } from "./utils/hasVisibleLabel.js";
22
8
  /**
23
9
  * Production action primitive backed by Base UI.
24
10
  *
@@ -32,8 +18,14 @@ export const Button = forwardRef(function Button({ "aria-busy": ariaBusy, "aria-
32
18
  }
33
19
  const blocked = disabled || loading;
34
20
  const loadingWithoutIcon = loading && !Icon;
35
- const visual = loading && Icon ? (_jsx(Spinner, {})) : Icon ? (_jsx(Icon, { "aria-hidden": "true", className: "fs-button__icon", focusable: "false" })) : null;
36
- const classes = ["fs-button", className].filter(Boolean).join(" ");
37
- return (_jsxs(BaseUIButton, { ...nativeProps, "aria-busy": loading ? true : ariaBusy, "aria-label": ariaLabel, className: classes, "data-fs-icon-only": iconOnly ? "true" : undefined, "data-fs-loading": loading ? "true" : undefined, "data-fs-size": size, "data-fs-variant": variant, disabled: blocked, nativeButton: true, ref: ref, type: type, children: [loadingWithoutIcon ? (_jsx("span", { "aria-hidden": "true", className: "fs-button__loading-indicator", children: _jsx(Spinner, {}) })) : null, iconOnly ? (visual) : (_jsxs("span", { className: "fs-button__content", children: [iconPosition === "start" ? visual : null, _jsx("span", { className: "fs-button__label", children: children }), iconPosition === "end" ? visual : null] }))] }));
21
+ let visual = null;
22
+ if (loading && Icon) {
23
+ visual = _jsx(Spinner, { className: "fs-button__spinner", size: size });
24
+ }
25
+ else if (Icon) {
26
+ visual = _jsx(Icon, { "aria-hidden": "true", className: "fs-button__icon", focusable: "false" });
27
+ }
28
+ const classes = clsx("fs-button", className);
29
+ return (_jsxs(BaseUIButton, { ...nativeProps, "aria-busy": loading ? true : ariaBusy, "aria-label": ariaLabel, className: classes, "data-fs-icon-only": iconOnly ? "true" : undefined, "data-fs-loading": loading ? "true" : undefined, "data-fs-size": size, "data-fs-variant": variant, disabled: blocked, nativeButton: true, ref: ref, type: type, children: [loadingWithoutIcon ? (_jsx("span", { "aria-hidden": "true", className: "fs-button__loading-indicator", children: _jsx(Spinner, { className: "fs-button__spinner", size: size }) })) : null, iconOnly ? (visual) : (_jsxs("span", { className: "fs-button__content", children: [iconPosition === "start" ? visual : null, _jsx("span", { className: "fs-button__label", children: children }), iconPosition === "end" ? visual : null] }))] }));
38
30
  });
39
- //# sourceMappingURL=button.js.map
31
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../../src/primitives/Button/Button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAK7D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EACE,WAAW,EAAE,QAAQ,EACrB,YAAY,EAAE,SAAS,EACvB,QAAQ,EACR,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,IAAI,EAAE,IAAI,EACV,YAAY,GAAG,OAAO,EACtB,OAAO,GAAG,KAAK,EACf,IAAI,GAAG,IAAI,EACX,IAAI,GAAG,QAAQ,EACf,OAAO,GAAG,SAAS,EACnB,GAAG,WAAW,EACf,EACD,GAAG;IAEH,MAAM,QAAQ,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAE5C,IAAI,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,IAAI,OAAO,CAAC;IACpC,MAAM,kBAAkB,GAAG,OAAO,IAAI,CAAC,IAAI,CAAC;IAC5C,IAAI,MAAM,GAAc,IAAI,CAAC;IAC7B,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,GAAG,KAAC,OAAO,IAAC,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAE,IAAI,GAAI,CAAC;IAClE,CAAC;SAAM,IAAI,IAAI,EAAE,CAAC;QAChB,MAAM,GAAG,KAAC,IAAI,mBAAa,MAAM,EAAC,SAAS,EAAC,iBAAiB,EAAC,SAAS,EAAC,OAAO,GAAG,CAAC;IACrF,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAE7C,OAAO,CACL,MAAC,YAAY,OACP,WAAW,eACJ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,gBACxB,SAAS,EACrB,SAAS,EAAE,OAAO,uBACC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,qBAC/B,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,kBAC/B,IAAI,qBACD,OAAO,EACxB,QAAQ,EAAE,OAAO,EACjB,YAAY,QACZ,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,IAAI,aAET,kBAAkB,CAAC,CAAC,CAAC,CACpB,8BAAkB,MAAM,EAAC,SAAS,EAAC,8BAA8B,YAC/D,KAAC,OAAO,IAAC,SAAS,EAAC,oBAAoB,EAAC,IAAI,EAAE,IAAI,GAAI,GACjD,CACR,CAAC,CAAC,CAAC,IAAI,EACP,QAAQ,CAAC,CAAC,CAAC,CACV,MAAM,CACP,CAAC,CAAC,CAAC,CACF,gBAAM,SAAS,EAAC,oBAAoB,aACjC,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EACzC,eAAM,SAAS,EAAC,kBAAkB,YAAE,QAAQ,GAAQ,EACnD,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAClC,CACR,IACY,CAChB,CAAC;AACJ,CAAC,CAAC,CAAC"}