@azmr/ui 0.1.0 → 0.3.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/README.md +171 -0
- package/dist/avatar.d.ts +58 -0
- package/dist/avatar.js +84 -0
- package/dist/breadcrumb.d.ts +47 -0
- package/dist/breadcrumb.js +120 -0
- package/dist/button-CYt2Zw3D.d.ts +64 -0
- package/dist/button.d.ts +54 -0
- package/dist/button.js +19 -0
- package/dist/chunk-2RIWL363.js +27 -0
- package/dist/chunk-2TQSHVXA.js +12 -0
- package/dist/chunk-7EOSDFS3.js +10 -0
- package/dist/chunk-C2HKIPLQ.js +118 -0
- package/dist/chunk-CAJLW6K2.js +16 -0
- package/dist/chunk-CZJZYN54.js +36 -0
- package/dist/chunk-EE4V6XMB.js +35 -0
- package/dist/chunk-EFHRRLAW.js +211 -0
- package/dist/chunk-GLB75NT3.js +21 -0
- package/dist/chunk-GX2YEJ43.js +36 -0
- package/dist/chunk-LTOLV67A.js +19 -0
- package/dist/chunk-LZMX27IZ.js +10 -0
- package/dist/chunk-NIIDYIZA.js +1 -0
- package/dist/chunk-Q4PPM2SU.js +97 -0
- package/dist/chunk-WVE2E37B.js +20 -0
- package/dist/chunk-XRZHP6BD.js +92 -0
- package/dist/disclosure.d.ts +72 -0
- package/dist/disclosure.js +221 -0
- package/dist/display.d.ts +111 -0
- package/dist/display.js +237 -0
- package/dist/features-dom-MCGKRLN5.js +7 -0
- package/dist/features-max-COBTQCO6.js +7 -0
- package/dist/floating.d.ts +81 -0
- package/dist/floating.js +231 -0
- package/dist/hooks.d.ts +33 -0
- package/dist/hooks.js +55 -0
- package/dist/icons/lucide.d.ts +77 -0
- package/dist/icons/lucide.js +135 -0
- package/dist/icons/mui-map.d.ts +1268 -0
- package/dist/icons/mui-map.js +352 -0
- package/dist/icons.d.ts +48 -0
- package/dist/icons.js +19 -0
- package/dist/index.d.ts +238 -3
- package/dist/index.js +242 -15
- package/dist/input.d.ts +14 -0
- package/dist/input.js +8 -0
- package/dist/layout/mui-map.d.ts +80 -0
- package/dist/layout/mui-map.js +104 -0
- package/dist/layout.d.ts +89 -0
- package/dist/layout.js +455 -0
- package/dist/lib.d.ts +11 -0
- package/dist/lib.js +6 -0
- package/dist/menu.d.ts +105 -0
- package/dist/menu.js +56 -0
- package/dist/modal.d.ts +105 -0
- package/dist/modal.js +273 -0
- package/dist/motion.css +295 -0
- package/dist/motion.d.ts +49 -0
- package/dist/motion.js +48 -0
- package/dist/pagination.d.ts +82 -0
- package/dist/pagination.js +211 -0
- package/dist/presets.d.ts +97 -0
- package/dist/presets.js +94 -0
- package/dist/progress.d.ts +70 -0
- package/dist/progress.js +138 -0
- package/dist/react.d.ts +81 -0
- package/dist/react.js +281 -0
- package/dist/responsive-YJBnvsjt.d.ts +69 -0
- package/dist/scroll-area.d.ts +30 -0
- package/dist/scroll-area.js +80 -0
- package/dist/shared-Fkx-sjPt.d.ts +15 -0
- package/dist/spinner.d.ts +18 -0
- package/dist/spinner.js +39 -0
- package/dist/split-button.d.ts +32 -0
- package/dist/split-button.js +54 -0
- package/dist/stepper.d.ts +27 -0
- package/dist/stepper.js +104 -0
- package/dist/styles.css +24 -0
- package/dist/table.d.ts +52 -0
- package/dist/table.js +124 -0
- package/dist/theme.d.ts +111 -0
- package/dist/theme.js +414 -0
- package/dist/toast.d.ts +77 -0
- package/dist/toast.js +203 -0
- package/dist/toggle.d.ts +55 -0
- package/dist/toggle.js +88 -0
- package/dist/tokens.css +337 -0
- package/dist/transition.d.ts +51 -0
- package/dist/transition.js +79 -0
- package/dist/types-BBudf463.d.ts +39 -0
- package/dist/typography/mui-map.d.ts +91 -0
- package/dist/typography/mui-map.js +62 -0
- package/dist/typography.d.ts +90 -0
- package/dist/typography.js +193 -0
- package/dist/useSignal-C-3ZGURN.d.ts +21 -0
- package/dist/variants-De0c0ucO.d.ts +60 -0
- package/package.json +179 -13
package/dist/react.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/react/LocaleProvider.tsx
|
|
4
|
+
import { createContext, useContext, useMemo } from "react";
|
|
5
|
+
|
|
6
|
+
// src/theme/locale.ts
|
|
7
|
+
var DEFAULT_MESSAGES = Object.freeze({
|
|
8
|
+
close: "Close",
|
|
9
|
+
cancel: "Cancel",
|
|
10
|
+
confirm: "Confirm",
|
|
11
|
+
loading: "Loading",
|
|
12
|
+
noResults: "No results found",
|
|
13
|
+
clear: "Clear",
|
|
14
|
+
search: "Search",
|
|
15
|
+
previousPage: "Previous page",
|
|
16
|
+
nextPage: "Next page"
|
|
17
|
+
});
|
|
18
|
+
var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
19
|
+
var FIELD_OPTIONS = [
|
|
20
|
+
"weekday",
|
|
21
|
+
"era",
|
|
22
|
+
"year",
|
|
23
|
+
"month",
|
|
24
|
+
"day",
|
|
25
|
+
"dayPeriod",
|
|
26
|
+
"hour",
|
|
27
|
+
"minute",
|
|
28
|
+
"second",
|
|
29
|
+
"fractionalSecondDigits",
|
|
30
|
+
"timeZoneName"
|
|
31
|
+
];
|
|
32
|
+
function toInstant(value) {
|
|
33
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
34
|
+
if (typeof value === "string") {
|
|
35
|
+
const match = DATE_ONLY.exec(value);
|
|
36
|
+
if (match) {
|
|
37
|
+
const date2 = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
|
|
38
|
+
return Number.isNaN(date2.getTime()) ? void 0 : { date: date2, calendarDay: true };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
42
|
+
return Number.isNaN(date.getTime()) ? void 0 : { date, calendarDay: false };
|
|
43
|
+
}
|
|
44
|
+
function createLocale(options = {}) {
|
|
45
|
+
const locale = options.locale ?? "en-NZ";
|
|
46
|
+
const currency = options.currency ?? "NZD";
|
|
47
|
+
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
48
|
+
const timeZone = options.timeZone;
|
|
49
|
+
try {
|
|
50
|
+
Intl.getCanonicalLocales(locale);
|
|
51
|
+
} catch {
|
|
52
|
+
throw new Error(`createLocale: invalid locale ${JSON.stringify(locale)}`);
|
|
53
|
+
}
|
|
54
|
+
if (!/^[A-Z]{3}$/.test(currency)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`createLocale: currency must be an ISO 4217 code like "NZD", got ${JSON.stringify(currency)}`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (timeZone !== void 0) {
|
|
60
|
+
try {
|
|
61
|
+
new Intl.DateTimeFormat(locale, { timeZone });
|
|
62
|
+
} catch {
|
|
63
|
+
throw new Error(`createLocale: unknown time zone ${JSON.stringify(timeZone)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!Number.isInteger(weekStartsOn) || weekStartsOn < 0 || weekStartsOn > 6) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`createLocale: weekStartsOn must be an integer from 0 to 6, got ${weekStartsOn}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const numberFormats = /* @__PURE__ */ new Map();
|
|
72
|
+
const dateFormats = /* @__PURE__ */ new Map();
|
|
73
|
+
const numberFormat = (opts) => {
|
|
74
|
+
const key = JSON.stringify(opts);
|
|
75
|
+
let format = numberFormats.get(key);
|
|
76
|
+
if (!format) {
|
|
77
|
+
format = new Intl.NumberFormat(locale, opts);
|
|
78
|
+
numberFormats.set(key, format);
|
|
79
|
+
}
|
|
80
|
+
return format;
|
|
81
|
+
};
|
|
82
|
+
const dateFormat = (opts) => {
|
|
83
|
+
const key = JSON.stringify(opts);
|
|
84
|
+
let format = dateFormats.get(key);
|
|
85
|
+
if (!format) {
|
|
86
|
+
format = new Intl.DateTimeFormat(locale, opts);
|
|
87
|
+
dateFormats.set(key, format);
|
|
88
|
+
}
|
|
89
|
+
return format;
|
|
90
|
+
};
|
|
91
|
+
const formatDateWith = (defaults) => (value, opts = {}) => {
|
|
92
|
+
const instant = toInstant(value);
|
|
93
|
+
if (!instant) return "";
|
|
94
|
+
const zone = instant.calendarDay ? "UTC" : opts.timeZone ?? timeZone;
|
|
95
|
+
const customised = FIELD_OPTIONS.some((key) => key in opts) || "dateStyle" in opts || "timeStyle" in opts;
|
|
96
|
+
return dateFormat({
|
|
97
|
+
...customised ? {} : defaults,
|
|
98
|
+
...opts,
|
|
99
|
+
...zone ? { timeZone: zone } : {}
|
|
100
|
+
}).format(instant.date);
|
|
101
|
+
};
|
|
102
|
+
const isNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
103
|
+
return {
|
|
104
|
+
locale,
|
|
105
|
+
currency,
|
|
106
|
+
weekStartsOn,
|
|
107
|
+
timeZone,
|
|
108
|
+
messages: { ...DEFAULT_MESSAGES, ...options.messages },
|
|
109
|
+
formatNumber: (value, opts = {}) => isNumber(value) ? numberFormat(opts).format(value) : "",
|
|
110
|
+
formatCurrency: (value, opts = {}) => isNumber(value) ? numberFormat({ style: "currency", currency, ...opts }).format(value) : "",
|
|
111
|
+
formatDate: formatDateWith({ dateStyle: "medium" }),
|
|
112
|
+
formatDateTime: formatDateWith({ dateStyle: "medium", timeStyle: "short" })
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/react/LocaleProvider.tsx
|
|
117
|
+
import { jsx } from "react/jsx-runtime";
|
|
118
|
+
var LocaleContext = createContext(createLocale());
|
|
119
|
+
function LocaleProvider({
|
|
120
|
+
children,
|
|
121
|
+
locale,
|
|
122
|
+
currency,
|
|
123
|
+
weekStartsOn,
|
|
124
|
+
timeZone,
|
|
125
|
+
messages
|
|
126
|
+
}) {
|
|
127
|
+
const messagesKey = JSON.stringify(messages ?? {});
|
|
128
|
+
const value = useMemo(
|
|
129
|
+
() => createLocale({
|
|
130
|
+
locale,
|
|
131
|
+
currency,
|
|
132
|
+
weekStartsOn,
|
|
133
|
+
timeZone,
|
|
134
|
+
messages: JSON.parse(messagesKey)
|
|
135
|
+
}),
|
|
136
|
+
[locale, currency, weekStartsOn, timeZone, messagesKey]
|
|
137
|
+
);
|
|
138
|
+
return /* @__PURE__ */ jsx(LocaleContext.Provider, { value, children });
|
|
139
|
+
}
|
|
140
|
+
function useLocale() {
|
|
141
|
+
return useContext(LocaleContext);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/react/ThemeProvider.tsx
|
|
145
|
+
import {
|
|
146
|
+
createContext as createContext2,
|
|
147
|
+
useCallback,
|
|
148
|
+
useContext as useContext2,
|
|
149
|
+
useEffect,
|
|
150
|
+
useMemo as useMemo2,
|
|
151
|
+
useState,
|
|
152
|
+
useSyncExternalStore
|
|
153
|
+
} from "react";
|
|
154
|
+
|
|
155
|
+
// src/theme/preferences.ts
|
|
156
|
+
var THEME_PREFERENCES = ["light", "dark", "system"];
|
|
157
|
+
var DENSITIES = ["compact", "comfortable", "spacious"];
|
|
158
|
+
var THEME_COOKIE = "azmr-theme";
|
|
159
|
+
var DENSITY_COOKIE = "azmr-density";
|
|
160
|
+
var ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
|
|
161
|
+
function parseThemePreference(value, fallback = "system") {
|
|
162
|
+
return typeof value === "string" && THEME_PREFERENCES.includes(value) ? value : fallback;
|
|
163
|
+
}
|
|
164
|
+
function parseDensity(value, fallback = "comfortable") {
|
|
165
|
+
return typeof value === "string" && DENSITIES.includes(value) ? value : fallback;
|
|
166
|
+
}
|
|
167
|
+
function readCookie(header, name) {
|
|
168
|
+
if (!header) return void 0;
|
|
169
|
+
for (const part of header.split(";")) {
|
|
170
|
+
const trimmed = part.trim();
|
|
171
|
+
const eq = trimmed.indexOf("=");
|
|
172
|
+
if (eq === -1 || trimmed.slice(0, eq) !== name) continue;
|
|
173
|
+
const raw = trimmed.slice(eq + 1);
|
|
174
|
+
try {
|
|
175
|
+
return decodeURIComponent(raw);
|
|
176
|
+
} catch {
|
|
177
|
+
return raw;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return void 0;
|
|
181
|
+
}
|
|
182
|
+
var COOKIE_NAME = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
|
|
183
|
+
var COOKIE_VALUE = /^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*$/;
|
|
184
|
+
function serializeCookie(name, value, options = {}) {
|
|
185
|
+
if (!COOKIE_NAME.test(name)) throw new Error(`Invalid cookie name: ${JSON.stringify(name)}`);
|
|
186
|
+
if (!COOKIE_VALUE.test(value)) throw new Error(`Invalid cookie value for "${name}"`);
|
|
187
|
+
const secure = options.secure ? "; Secure" : "";
|
|
188
|
+
return `${name}=${value}; Path=/; Max-Age=${ONE_YEAR_SECONDS}; SameSite=Lax${secure}`;
|
|
189
|
+
}
|
|
190
|
+
function buildHtmlAttributes({ theme, density }) {
|
|
191
|
+
const attributes = {};
|
|
192
|
+
if (theme === "light" || theme === "dark") attributes["data-theme"] = theme;
|
|
193
|
+
if (density === "compact" || density === "spacious") attributes["data-density"] = density;
|
|
194
|
+
return attributes;
|
|
195
|
+
}
|
|
196
|
+
var htmlAttributes = Object.assign(buildHtmlAttributes, {
|
|
197
|
+
fromCookies(header) {
|
|
198
|
+
return buildHtmlAttributes({
|
|
199
|
+
theme: parseThemePreference(readCookie(header, THEME_COOKIE)),
|
|
200
|
+
density: parseDensity(readCookie(header, DENSITY_COOKIE))
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// src/react/ThemeProvider.tsx
|
|
206
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
207
|
+
var DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
208
|
+
function subscribeToSystem(onChange) {
|
|
209
|
+
const query = typeof window === "undefined" ? void 0 : window.matchMedia?.(DARK_QUERY);
|
|
210
|
+
if (!query) return () => {
|
|
211
|
+
};
|
|
212
|
+
query.addEventListener("change", onChange);
|
|
213
|
+
return () => query.removeEventListener("change", onChange);
|
|
214
|
+
}
|
|
215
|
+
var systemPrefersDark = () => window.matchMedia?.(DARK_QUERY).matches ?? false;
|
|
216
|
+
var serverSystemPrefersDark = () => false;
|
|
217
|
+
function writeCookie(name, value) {
|
|
218
|
+
document.cookie = serializeCookie(name, value, { secure: window.location.protocol === "https:" });
|
|
219
|
+
}
|
|
220
|
+
var ThemeContext = createContext2(void 0);
|
|
221
|
+
function ThemeProvider({
|
|
222
|
+
children,
|
|
223
|
+
defaultTheme = "system",
|
|
224
|
+
defaultDensity = "comfortable",
|
|
225
|
+
persist = true,
|
|
226
|
+
target
|
|
227
|
+
}) {
|
|
228
|
+
const [theme, setThemeState] = useState(
|
|
229
|
+
() => parseThemePreference(defaultTheme)
|
|
230
|
+
);
|
|
231
|
+
const [density, setDensityState] = useState(() => parseDensity(defaultDensity));
|
|
232
|
+
const systemDark = useSyncExternalStore(
|
|
233
|
+
subscribeToSystem,
|
|
234
|
+
systemPrefersDark,
|
|
235
|
+
serverSystemPrefersDark
|
|
236
|
+
);
|
|
237
|
+
const resolvedTheme = theme === "system" ? systemDark ? "dark" : "light" : theme;
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
const element = target ?? document.documentElement;
|
|
240
|
+
if (theme === "system") element.removeAttribute("data-theme");
|
|
241
|
+
else element.setAttribute("data-theme", theme);
|
|
242
|
+
if (density === "comfortable") element.removeAttribute("data-density");
|
|
243
|
+
else element.setAttribute("data-density", density);
|
|
244
|
+
return () => {
|
|
245
|
+
element.removeAttribute("data-theme");
|
|
246
|
+
element.removeAttribute("data-density");
|
|
247
|
+
};
|
|
248
|
+
}, [theme, density, target]);
|
|
249
|
+
const setTheme = useCallback(
|
|
250
|
+
(next) => {
|
|
251
|
+
const safe = parseThemePreference(next);
|
|
252
|
+
setThemeState(safe);
|
|
253
|
+
if (persist) writeCookie(THEME_COOKIE, safe);
|
|
254
|
+
},
|
|
255
|
+
[persist]
|
|
256
|
+
);
|
|
257
|
+
const setDensity = useCallback(
|
|
258
|
+
(next) => {
|
|
259
|
+
const safe = parseDensity(next);
|
|
260
|
+
setDensityState(safe);
|
|
261
|
+
if (persist) writeCookie(DENSITY_COOKIE, safe);
|
|
262
|
+
},
|
|
263
|
+
[persist]
|
|
264
|
+
);
|
|
265
|
+
const value = useMemo2(
|
|
266
|
+
() => ({ theme, resolvedTheme, setTheme, density, setDensity }),
|
|
267
|
+
[theme, resolvedTheme, setTheme, density, setDensity]
|
|
268
|
+
);
|
|
269
|
+
return /* @__PURE__ */ jsx2(ThemeContext.Provider, { value, children });
|
|
270
|
+
}
|
|
271
|
+
function useTheme() {
|
|
272
|
+
const context = useContext2(ThemeContext);
|
|
273
|
+
if (!context) throw new Error("useTheme must be used within a <ThemeProvider>");
|
|
274
|
+
return context;
|
|
275
|
+
}
|
|
276
|
+
export {
|
|
277
|
+
LocaleProvider,
|
|
278
|
+
ThemeProvider,
|
|
279
|
+
useLocale,
|
|
280
|
+
useTheme
|
|
281
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
/** A gap step (Tailwind's 4px scale), or `density` to follow the `data-density` token. */
|
|
5
|
+
declare const GAP_CLASSES: {
|
|
6
|
+
readonly 0: "gap-0";
|
|
7
|
+
readonly 1: "gap-1";
|
|
8
|
+
readonly 2: "gap-2";
|
|
9
|
+
readonly 3: "gap-3";
|
|
10
|
+
readonly 4: "gap-4";
|
|
11
|
+
readonly 5: "gap-5";
|
|
12
|
+
readonly 6: "gap-6";
|
|
13
|
+
readonly 8: "gap-8";
|
|
14
|
+
readonly 10: "gap-10";
|
|
15
|
+
readonly 12: "gap-12";
|
|
16
|
+
readonly density: "gap-(--density-gap)";
|
|
17
|
+
};
|
|
18
|
+
type Gap = keyof typeof GAP_CLASSES;
|
|
19
|
+
declare const ALIGN_ITEMS_CLASSES: {
|
|
20
|
+
readonly start: "items-start";
|
|
21
|
+
readonly center: "items-center";
|
|
22
|
+
readonly end: "items-end";
|
|
23
|
+
readonly stretch: "items-stretch";
|
|
24
|
+
readonly baseline: "items-baseline";
|
|
25
|
+
};
|
|
26
|
+
type AlignItems = keyof typeof ALIGN_ITEMS_CLASSES;
|
|
27
|
+
declare const JUSTIFY_CONTENT_CLASSES: {
|
|
28
|
+
readonly start: "justify-start";
|
|
29
|
+
readonly center: "justify-center";
|
|
30
|
+
readonly end: "justify-end";
|
|
31
|
+
readonly between: "justify-between";
|
|
32
|
+
readonly around: "justify-around";
|
|
33
|
+
readonly evenly: "justify-evenly";
|
|
34
|
+
};
|
|
35
|
+
type JustifyContent = keyof typeof JUSTIFY_CONTENT_CLASSES;
|
|
36
|
+
declare const JUSTIFY_ITEMS_CLASSES: {
|
|
37
|
+
readonly start: "justify-items-start";
|
|
38
|
+
readonly center: "justify-items-center";
|
|
39
|
+
readonly end: "justify-items-end";
|
|
40
|
+
readonly stretch: "justify-items-stretch";
|
|
41
|
+
};
|
|
42
|
+
type JustifyItems = keyof typeof JUSTIFY_ITEMS_CLASSES;
|
|
43
|
+
/** Elements a layout box may render as. */
|
|
44
|
+
type LayoutElement = "div" | "section" | "article" | "aside" | "nav" | "header" | "footer" | "main" | "ul" | "ol" | "form" | "fieldset";
|
|
45
|
+
|
|
46
|
+
declare const CONTAINER_SIZE_CLASSES: {
|
|
47
|
+
readonly sm: "max-w-2xl";
|
|
48
|
+
readonly md: "max-w-4xl";
|
|
49
|
+
readonly lg: "max-w-6xl";
|
|
50
|
+
readonly xl: "max-w-7xl";
|
|
51
|
+
readonly "2xl": "max-w-[96rem]";
|
|
52
|
+
readonly full: "max-w-none";
|
|
53
|
+
};
|
|
54
|
+
type ContainerSize = keyof typeof CONTAINER_SIZE_CLASSES;
|
|
55
|
+
interface ContainerProps extends Omit<HTMLAttributes<HTMLElement>, "children"> {
|
|
56
|
+
/** The widest the content gets (42, 56, 72, 80, 96rem); `full` removes the limit. Default `lg`. */
|
|
57
|
+
size?: ContainerSize;
|
|
58
|
+
/** Horizontal padding that grows with the screen. Default true. */
|
|
59
|
+
gutters?: boolean;
|
|
60
|
+
as?: LayoutElement;
|
|
61
|
+
children?: ReactNode;
|
|
62
|
+
}
|
|
63
|
+
/** Centres content and limits its width. Server-safe. */
|
|
64
|
+
declare const Container: react.ForwardRefExoticComponent<ContainerProps & react.RefAttributes<HTMLElement>>;
|
|
65
|
+
|
|
66
|
+
declare const BREAKPOINTS: readonly ["base", "sm", "md", "lg", "xl", "2xl"];
|
|
67
|
+
type Breakpoint = (typeof BREAKPOINTS)[number];
|
|
68
|
+
|
|
69
|
+
export { type AlignItems as A, type Breakpoint as B, Container as C, type Gap as G, type JustifyItems as J, type LayoutElement as L, type JustifyContent as a, type ContainerProps as b, type ContainerSize as c };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ForwardRefExoticComponent, Ref, ReactNode, ComponentPropsWithoutRef, RefAttributes } from 'react';
|
|
2
|
+
import { ScrollArea as ScrollArea$1 } from '@base-ui/react/scroll-area';
|
|
3
|
+
|
|
4
|
+
interface ScrollAreaOwnProps {
|
|
5
|
+
/** Which scrollbars to show. Default `vertical`. */
|
|
6
|
+
orientation?: "vertical" | "horizontal" | "both";
|
|
7
|
+
/**
|
|
8
|
+
* `hover` (default) fades the scrollbar in on hover and while scrolling, like the desktop
|
|
9
|
+
* platforms; `always` keeps it visible.
|
|
10
|
+
*/
|
|
11
|
+
scrollbar?: "always" | "hover";
|
|
12
|
+
/** Keep the scrollbars in the DOM even when nothing overflows, so layout never jumps. */
|
|
13
|
+
keepMounted?: boolean;
|
|
14
|
+
/** Classes for the scrollable viewport (padding, for example); `className` styles the root. */
|
|
15
|
+
viewportClassName?: string;
|
|
16
|
+
/** A ref to the scrollable element, to read or set the scroll position. */
|
|
17
|
+
viewportRef?: Ref<HTMLDivElement>;
|
|
18
|
+
className?: string;
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
/** A scrollable region is focusable, so it needs a name: a label or the id of a heading. */
|
|
22
|
+
type Named = {
|
|
23
|
+
"aria-label": string;
|
|
24
|
+
} | {
|
|
25
|
+
"aria-labelledby": string;
|
|
26
|
+
};
|
|
27
|
+
type ScrollAreaProps = ScrollAreaOwnProps & Named & Omit<ComponentPropsWithoutRef<typeof ScrollArea$1.Root>, keyof ScrollAreaOwnProps | "aria-label" | "aria-labelledby">;
|
|
28
|
+
declare const ScrollArea: ForwardRefExoticComponent<ScrollAreaProps & RefAttributes<HTMLDivElement>>;
|
|
29
|
+
|
|
30
|
+
export { ScrollArea, type ScrollAreaOwnProps, type ScrollAreaProps };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-2TQSHVXA.js";
|
|
5
|
+
|
|
6
|
+
// src/components/scroll-area/scroll-area.tsx
|
|
7
|
+
import {
|
|
8
|
+
forwardRef
|
|
9
|
+
} from "react";
|
|
10
|
+
|
|
11
|
+
// src/primitives/scroll-area.ts
|
|
12
|
+
import { ScrollArea } from "@base-ui/react/scroll-area";
|
|
13
|
+
|
|
14
|
+
// src/components/scroll-area/scroll-area.tsx
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
function Scrollbar({
|
|
17
|
+
orientation,
|
|
18
|
+
always,
|
|
19
|
+
keepMounted
|
|
20
|
+
}) {
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
ScrollArea.Scrollbar,
|
|
23
|
+
{
|
|
24
|
+
orientation,
|
|
25
|
+
keepMounted,
|
|
26
|
+
className: cn(
|
|
27
|
+
"flex touch-none select-none p-px transition-opacity duration-(--motion-duration-fast) ease-standard",
|
|
28
|
+
orientation === "vertical" ? "h-full w-2.5" : "h-2.5 flex-col",
|
|
29
|
+
!always && "opacity-0 data-[hovering]:opacity-100 data-[scrolling]:opacity-100"
|
|
30
|
+
),
|
|
31
|
+
children: /* @__PURE__ */ jsx(ScrollArea.Thumb, { className: "relative flex-1 rounded-full bg-border" })
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
var ScrollAreaImpl = forwardRef(function ScrollArea2({
|
|
36
|
+
orientation = "vertical",
|
|
37
|
+
scrollbar = "hover",
|
|
38
|
+
keepMounted = false,
|
|
39
|
+
viewportClassName,
|
|
40
|
+
viewportRef,
|
|
41
|
+
className,
|
|
42
|
+
children,
|
|
43
|
+
"aria-label": ariaLabel,
|
|
44
|
+
"aria-labelledby": ariaLabelledBy,
|
|
45
|
+
...props
|
|
46
|
+
}, ref) {
|
|
47
|
+
const always = scrollbar === "always";
|
|
48
|
+
return /* @__PURE__ */ jsxs(
|
|
49
|
+
ScrollArea.Root,
|
|
50
|
+
{
|
|
51
|
+
ref,
|
|
52
|
+
className: cn("relative overflow-hidden rounded-md", className),
|
|
53
|
+
...props,
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx(
|
|
56
|
+
ScrollArea.Viewport,
|
|
57
|
+
{
|
|
58
|
+
ref: viewportRef,
|
|
59
|
+
role: "region",
|
|
60
|
+
tabIndex: 0,
|
|
61
|
+
"aria-label": ariaLabel,
|
|
62
|
+
"aria-labelledby": ariaLabelledBy,
|
|
63
|
+
className: cn(
|
|
64
|
+
"size-full rounded-[inherit] outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
|
|
65
|
+
viewportClassName
|
|
66
|
+
),
|
|
67
|
+
children: /* @__PURE__ */ jsx(ScrollArea.Content, { children })
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
orientation !== "horizontal" && /* @__PURE__ */ jsx(Scrollbar, { orientation: "vertical", always, keepMounted }),
|
|
71
|
+
orientation !== "vertical" && /* @__PURE__ */ jsx(Scrollbar, { orientation: "horizontal", always, keepMounted }),
|
|
72
|
+
orientation === "both" && /* @__PURE__ */ jsx(ScrollArea.Corner, {})
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
var ScrollArea3 = ScrollAreaImpl;
|
|
78
|
+
export {
|
|
79
|
+
ScrollArea3 as ScrollArea
|
|
80
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type Side = "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end";
|
|
2
|
+
type Align = "start" | "center" | "end";
|
|
3
|
+
/** Where a floating surface sits relative to its trigger. */
|
|
4
|
+
interface PositionProps {
|
|
5
|
+
/** The side of the trigger to open on. It flips to the opposite side when there is no room. */
|
|
6
|
+
side?: Side;
|
|
7
|
+
/** Alignment along that side. */
|
|
8
|
+
align?: Align;
|
|
9
|
+
/** Gap between the trigger and the surface, in px. Default 6. */
|
|
10
|
+
sideOffset?: number;
|
|
11
|
+
/** Minimum distance kept from the viewport edge, in px. Default 8. */
|
|
12
|
+
collisionPadding?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type { Align as A, PositionProps as P, Side as S };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { SVGProps } from 'react';
|
|
3
|
+
|
|
4
|
+
interface SpinnerProps extends Omit<SVGProps<SVGSVGElement>, "ref"> {
|
|
5
|
+
/**
|
|
6
|
+
* Accessible name. When set the spinner is announced as a status ("Loading customers");
|
|
7
|
+
* when omitted it is decorative and hidden from assistive technology (use that when the
|
|
8
|
+
* surrounding control already says it is busy, as `Button loading` does).
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* An indeterminate progress indicator. It keeps spinning under `prefers-reduced-motion`
|
|
14
|
+
* (`data-motion="essential"`) because a frozen spinner reads as a hung page.
|
|
15
|
+
*/
|
|
16
|
+
declare const Spinner: react.ForwardRefExoticComponent<SpinnerProps & react.RefAttributes<SVGSVGElement>>;
|
|
17
|
+
|
|
18
|
+
export { Spinner, type SpinnerProps };
|
package/dist/spinner.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-7EOSDFS3.js";
|
|
4
|
+
|
|
5
|
+
// src/components/spinner/spinner.tsx
|
|
6
|
+
import { forwardRef } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var Spinner = forwardRef(function Spinner2({ label, className, ...props }, ref) {
|
|
9
|
+
return (
|
|
10
|
+
// biome-ignore lint/a11y/noSvgWithoutTitle: decorative (aria-hidden) by default, or role="status" with an aria-label when `label` is set; both paths are covered by axe tests
|
|
11
|
+
/* @__PURE__ */ jsxs(
|
|
12
|
+
"svg",
|
|
13
|
+
{
|
|
14
|
+
ref,
|
|
15
|
+
viewBox: "0 0 24 24",
|
|
16
|
+
fill: "none",
|
|
17
|
+
"data-motion": "essential",
|
|
18
|
+
className: cn("size-4 animate-spin", className),
|
|
19
|
+
...label ? { role: "status", "aria-label": label } : { "aria-hidden": true },
|
|
20
|
+
...props,
|
|
21
|
+
children: [
|
|
22
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeOpacity: "0.25", strokeWidth: "3" }),
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
"path",
|
|
25
|
+
{
|
|
26
|
+
d: "M22 12a10 10 0 0 0-10-10",
|
|
27
|
+
stroke: "currentColor",
|
|
28
|
+
strokeWidth: "3",
|
|
29
|
+
strokeLinecap: "round"
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
export {
|
|
38
|
+
Spinner
|
|
39
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { ButtonProps } from '@base-ui/react/button';
|
|
4
|
+
import { B as ButtonOwnProps } from './button-CYt2Zw3D.js';
|
|
5
|
+
import 'class-variance-authority';
|
|
6
|
+
import 'class-variance-authority/types';
|
|
7
|
+
|
|
8
|
+
interface SplitButtonProps extends Omit<ButtonProps, "className" | "children" | "type" | "render" | "nativeButton"> {
|
|
9
|
+
/** The primary action's label. */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/** The extra actions: `DropdownMenuItem`s (and groups, separators, and so on). */
|
|
12
|
+
menu: ReactNode;
|
|
13
|
+
/** Names the arrow button ("More save options"). Required: the arrow has no text. */
|
|
14
|
+
menuLabel: string;
|
|
15
|
+
variant?: ButtonOwnProps["variant"];
|
|
16
|
+
size?: "sm" | "md" | "lg";
|
|
17
|
+
/** Shows a spinner on the primary button and ignores it. The menu stays usable. */
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
loadingText?: ReactNode;
|
|
20
|
+
startIcon?: ReactNode;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A primary action with a menu of related ones attached: "Save", and a menu with "Save as…".
|
|
25
|
+
*
|
|
26
|
+
* Keyboard: Tab visits the primary button, then the arrow button; Enter or Space on the primary
|
|
27
|
+
* runs it; ArrowDown, Enter or Space on the arrow opens the menu (see `DropdownMenu` for the keys
|
|
28
|
+
* inside it), and Escape closes it and returns focus to the arrow.
|
|
29
|
+
*/
|
|
30
|
+
declare const SplitButton: react.ForwardRefExoticComponent<Omit<SplitButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
31
|
+
|
|
32
|
+
export { SplitButton, type SplitButtonProps };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuTrigger
|
|
6
|
+
} from "./chunk-EFHRRLAW.js";
|
|
7
|
+
import "./chunk-LZMX27IZ.js";
|
|
8
|
+
import {
|
|
9
|
+
Icon
|
|
10
|
+
} from "./chunk-XRZHP6BD.js";
|
|
11
|
+
import {
|
|
12
|
+
IconButton
|
|
13
|
+
} from "./chunk-CZJZYN54.js";
|
|
14
|
+
import {
|
|
15
|
+
Button
|
|
16
|
+
} from "./chunk-C2HKIPLQ.js";
|
|
17
|
+
import {
|
|
18
|
+
joinedClasses
|
|
19
|
+
} from "./chunk-EE4V6XMB.js";
|
|
20
|
+
import {
|
|
21
|
+
cn
|
|
22
|
+
} from "./chunk-2TQSHVXA.js";
|
|
23
|
+
|
|
24
|
+
// src/components/split-button/split-button.tsx
|
|
25
|
+
import { ChevronDown } from "lucide-react";
|
|
26
|
+
import { forwardRef } from "react";
|
|
27
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
28
|
+
var SplitButton = forwardRef(function SplitButton2({ children, menu, menuLabel, variant = "default", size = "md", disabled, className, ...props }, ref) {
|
|
29
|
+
return /* @__PURE__ */ jsxs("div", { className: cn(joinedClasses("horizontal", true), className), children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Button, { ref, variant, size, disabled, ...props, children }),
|
|
31
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
32
|
+
/* @__PURE__ */ jsx(
|
|
33
|
+
DropdownMenuTrigger,
|
|
34
|
+
{
|
|
35
|
+
disabled,
|
|
36
|
+
render: /* @__PURE__ */ jsx(
|
|
37
|
+
IconButton,
|
|
38
|
+
{
|
|
39
|
+
icon: /* @__PURE__ */ jsx(Icon, { icon: ChevronDown }),
|
|
40
|
+
label: menuLabel,
|
|
41
|
+
variant,
|
|
42
|
+
size,
|
|
43
|
+
className: cn(variant !== "outline" && "border-l border-l-background/30")
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
),
|
|
48
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: menu })
|
|
49
|
+
] })
|
|
50
|
+
] });
|
|
51
|
+
});
|
|
52
|
+
export {
|
|
53
|
+
SplitButton
|
|
54
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { OlHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type StepStatus = "complete" | "current" | "upcoming" | "error";
|
|
5
|
+
interface StepperStep {
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
description?: ReactNode;
|
|
8
|
+
/** Mark this step as failed. Otherwise the status follows `current`. */
|
|
9
|
+
status?: "error";
|
|
10
|
+
}
|
|
11
|
+
interface StepperProps extends Omit<OlHTMLAttributes<HTMLOListElement>, "children"> {
|
|
12
|
+
steps: readonly StepperStep[];
|
|
13
|
+
/** The index (0-based) of the step in progress. Below 0 nothing has started; past the end everything is done. */
|
|
14
|
+
current: number;
|
|
15
|
+
orientation?: "horizontal" | "vertical";
|
|
16
|
+
/** The list's name. Default "Progress". */
|
|
17
|
+
label?: string;
|
|
18
|
+
/** The words spoken for each state, for translation. */
|
|
19
|
+
statusLabels?: Partial<Record<StepStatus, string>>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Where someone is in a fixed sequence of steps. It is a status display, not navigation: steps are not
|
|
23
|
+
* links. Each state is also said in text (screen-reader only), never by colour alone. Server-safe.
|
|
24
|
+
*/
|
|
25
|
+
declare const Stepper: react.ForwardRefExoticComponent<StepperProps & react.RefAttributes<HTMLOListElement>>;
|
|
26
|
+
|
|
27
|
+
export { type StepStatus, Stepper, type StepperProps, type StepperStep };
|