mal-ui 0.1.3

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 (82) hide show
  1. package/README.md +244 -0
  2. package/dist/carousel/extensions.d.ts +1 -0
  3. package/dist/carousel/index.d.ts +2 -0
  4. package/dist/carousel/index.js +424 -0
  5. package/dist/carousel/index.js.map +15 -0
  6. package/dist/charts/extensions.d.ts +1 -0
  7. package/dist/charts/index.d.ts +2 -0
  8. package/dist/charts/index.js +3499 -0
  9. package/dist/charts/index.js.map +53 -0
  10. package/dist/chunks/index-3ffbn0gc.js +29976 -0
  11. package/dist/chunks/index-3ffbn0gc.js.map +637 -0
  12. package/dist/chunks/index-6b5mapr4.js +2 -0
  13. package/dist/chunks/index-6b5mapr4.js.map +9 -0
  14. package/dist/chunks/index-6tm93gww.js +38 -0
  15. package/dist/chunks/index-6tm93gww.js.map +10 -0
  16. package/dist/chunks/index-cg10ezdx.js +2 -0
  17. package/dist/chunks/index-cg10ezdx.js.map +9 -0
  18. package/dist/chunks/index-mc01z7m9.js +48 -0
  19. package/dist/chunks/index-mc01z7m9.js.map +9 -0
  20. package/dist/chunks/index-rz8zh7g4.js +5015 -0
  21. package/dist/chunks/index-rz8zh7g4.js.map +113 -0
  22. package/dist/chunks/index-syjq3515.js +4893 -0
  23. package/dist/chunks/index-syjq3515.js.map +101 -0
  24. package/dist/chunks/index-w9ekv5h5.js +733 -0
  25. package/dist/chunks/index-w9ekv5h5.js.map +17 -0
  26. package/dist/code-highlight/extensions.d.ts +1 -0
  27. package/dist/code-highlight/index.d.ts +2 -0
  28. package/dist/code-highlight/index.js +1685 -0
  29. package/dist/code-highlight/index.js.map +25 -0
  30. package/dist/core/extensions.d.ts +2 -0
  31. package/dist/core/index.d.ts +2 -0
  32. package/dist/core/index.js +844 -0
  33. package/dist/core/index.js.map +9 -0
  34. package/dist/dates/extensions.d.ts +1 -0
  35. package/dist/dates/index.d.ts +2 -0
  36. package/dist/dates/index.js +107 -0
  37. package/dist/dates/index.js.map +9 -0
  38. package/dist/dropzone/extensions.d.ts +1 -0
  39. package/dist/dropzone/index.d.ts +2 -0
  40. package/dist/dropzone/index.js +2681 -0
  41. package/dist/dropzone/index.js.map +21 -0
  42. package/dist/form/extensions.d.ts +1 -0
  43. package/dist/form/index.d.ts +2 -0
  44. package/dist/form/index.js +1605 -0
  45. package/dist/form/index.js.map +51 -0
  46. package/dist/hooks/extensions.d.ts +1 -0
  47. package/dist/hooks/index.d.ts +2 -0
  48. package/dist/hooks/index.js +214 -0
  49. package/dist/hooks/index.js.map +9 -0
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +1052 -0
  52. package/dist/index.js.map +9 -0
  53. package/dist/modals/extensions.d.ts +1 -0
  54. package/dist/modals/index.d.ts +2 -0
  55. package/dist/modals/index.js +387 -0
  56. package/dist/modals/index.js.map +15 -0
  57. package/dist/notifications/extensions.d.ts +1 -0
  58. package/dist/notifications/index.d.ts +2 -0
  59. package/dist/notifications/index.js +1122 -0
  60. package/dist/notifications/index.js.map +28 -0
  61. package/dist/nprogress/extensions.d.ts +1 -0
  62. package/dist/nprogress/index.d.ts +2 -0
  63. package/dist/nprogress/index.js +207 -0
  64. package/dist/nprogress/index.js.map +12 -0
  65. package/dist/schedule/extensions.d.ts +1 -0
  66. package/dist/schedule/index.d.ts +2 -0
  67. package/dist/schedule/index.js +8569 -0
  68. package/dist/schedule/index.js.map +135 -0
  69. package/dist/spotlight/extensions.d.ts +1 -0
  70. package/dist/spotlight/index.d.ts +2 -0
  71. package/dist/spotlight/index.js +666 -0
  72. package/dist/spotlight/index.js.map +24 -0
  73. package/dist/styles.css +1 -0
  74. package/dist/theme/index.d.ts +13 -0
  75. package/dist/theme/index.js +202 -0
  76. package/dist/theme/index.js.map +11 -0
  77. package/dist/theme/tokens.d.ts +65 -0
  78. package/dist/tiptap/extensions.d.ts +1 -0
  79. package/dist/tiptap/index.d.ts +2 -0
  80. package/dist/tiptap/index.js +1549 -0
  81. package/dist/tiptap/index.js.map +25 -0
  82. package/package.json +163 -0
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ # mal-ui
2
+
3
+ A React component library built on [Mantine v9](https://mantine.dev), providing a complete design system for MAL Devs projects — components, hooks, form utilities, charts, a rich-text editor, file uploads, and more, all pre-wired to the MAL brand theme.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [Subpath Imports](#subpath-imports)
12
+ - [Peer Dependencies](#peer-dependencies)
13
+ - [Theme](#theme)
14
+ - [Available Subpaths](#available-subpaths)
15
+ - [Development](#development)
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ # npm
23
+ npm install mal-ui
24
+
25
+ # bun
26
+ bun add mal-ui
27
+
28
+ # yarn
29
+ yarn add mal-ui
30
+
31
+ # pnpm
32
+ pnpm add mal-ui
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Quick Start
38
+
39
+ ### 1 — Wrap your app with `MALUIProvider`
40
+
41
+ ```tsx
42
+ // app/providers.tsx (Next.js App Router example)
43
+ 'use client';
44
+
45
+ import { MALUIProvider } from 'mal-ui/core';
46
+ import { malTheme } from 'mal-ui/theme';
47
+ import 'mal-ui/styles.css';
48
+
49
+ export function Providers({ children }: { children: React.ReactNode }) {
50
+ return (
51
+ <MALUIProvider theme={malTheme}>
52
+ {children}
53
+ </MALUIProvider>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### 2 — Use components
59
+
60
+ ```tsx
61
+ import { Button, TextInput, Card } from 'mal-ui/core';
62
+
63
+ export function LoginCard() {
64
+ return (
65
+ <Card>
66
+ <TextInput label="Email" placeholder="you@example.com" />
67
+ <Button mt="sm" fullWidth>
68
+ Sign in
69
+ </Button>
70
+ </Card>
71
+ );
72
+ }
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Subpath Imports
78
+
79
+ Import only what you need — each subpath is independently tree-shakeable:
80
+
81
+ | Subpath | What it contains |
82
+ |---|---|
83
+ | `mal-ui` | Re-exports `core` + `hooks` (most common components and hooks) |
84
+ | `mal-ui/core` | All Mantine core components + MALUI branded aliases |
85
+ | `mal-ui/hooks` | All Mantine hooks + MALUI branded aliases |
86
+ | `mal-ui/form` | `useForm`, form fields, validation helpers |
87
+ | `mal-ui/charts` | Line, Bar, Area, Donut, Pie, Radar, Scatter, Bubble, Sparkline |
88
+ | `mal-ui/notifications` | Notification system (`showNotification`, `updateNotification`, etc.) |
89
+ | `mal-ui/modals` | Modal manager (`openConfirmModal`, `openModal`, etc.) |
90
+ | `mal-ui/spotlight` | `⌘K` / `Ctrl+K` spotlight search |
91
+ | `mal-ui/code-highlight` | Syntax-highlighted code blocks (powered by Shiki) |
92
+ | `mal-ui/tiptap` | Rich-text editor (Tiptap + Mantine toolbar) |
93
+ | `mal-ui/dropzone` | File upload dropzone |
94
+ | `mal-ui/carousel` | Embla-powered carousel |
95
+ | `mal-ui/nprogress` | Top-of-page progress bar |
96
+ | `mal-ui/dates` | Date pickers, calendars, time pickers |
97
+ | `mal-ui/schedule` | Weekly/day schedule view |
98
+ | `mal-ui/theme` | `malTheme` object + raw design tokens |
99
+ | `mal-ui/styles.css` | Required global CSS (import once at your app root) |
100
+
101
+ ---
102
+
103
+ ## Peer Dependencies
104
+
105
+ Install the peer dependencies you actually use. Only `react` and `react-dom` are always required; the rest are **optional** and only needed if you import the corresponding subpath.
106
+
107
+ ```bash
108
+ # Always required
109
+ npm install react react-dom
110
+
111
+ # Required for mal-ui/charts
112
+ npm install recharts
113
+
114
+ # Required for mal-ui/dates, mal-ui/schedule
115
+ npm install dayjs
116
+
117
+ # Required for mal-ui/carousel
118
+ npm install embla-carousel-react
119
+
120
+ # Required for mal-ui/tiptap
121
+ npm install @tiptap/react @tiptap/pm @tiptap/starter-kit @tiptap/extension-link
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Theme
127
+
128
+ `mal-ui/theme` exports a ready-to-use Mantine theme override pre-configured with:
129
+
130
+ - **Brand colors** — `mal-brand` (purple) and `mal-secondary` palettes
131
+ - **Typography** — System font stack, tuned heading sizes and weights
132
+ - **Spacing & Radius** — Design-token-based scale
133
+ - **Shadows** — Consistent elevation scale
134
+ - **Component defaults** — Buttons, inputs, cards, and modals all default to `radius="md"`
135
+
136
+ ```tsx
137
+ import { malTheme } from 'mal-ui/theme';
138
+ // malTheme is a MantineThemeOverride — pass it to MantineProvider
139
+
140
+ // Raw tokens are also exported if you need them directly:
141
+ import { malColors, malSpacingTokens, malBreakpoints } from 'mal-ui/theme';
142
+ ```
143
+
144
+ Both Mantine names (`MantineProvider`, `useMantineTheme`) and MALUI aliases (`MALUIProvider`, `useMALUITheme`) are exported from `mal-ui/core` — use whichever you prefer.
145
+
146
+ ---
147
+
148
+ ## Available Subpaths
149
+
150
+ ### Core + Hooks
151
+
152
+ ```tsx
153
+ import { Button, TextInput, Select, Modal, Tabs } from 'mal-ui/core';
154
+ import { useDisclosure, useLocalStorage, useMediaQuery } from 'mal-ui/hooks';
155
+ ```
156
+
157
+ ### Form
158
+
159
+ ```tsx
160
+ import { useForm, isEmail, isNotEmpty } from 'mal-ui/form';
161
+
162
+ const form = useForm({
163
+ initialValues: { email: '', name: '' },
164
+ validate: {
165
+ email: isEmail('Invalid email'),
166
+ name: isNotEmpty('Name is required'),
167
+ },
168
+ });
169
+ ```
170
+
171
+ ### Charts
172
+
173
+ ```tsx
174
+ import { LineChart, BarChart, DonutChart } from 'mal-ui/charts';
175
+
176
+ <LineChart
177
+ h={300}
178
+ data={data}
179
+ dataKey="date"
180
+ series={[{ name: 'Revenue', color: 'mal-brand.5' }]}
181
+ />
182
+ ```
183
+
184
+ ### Notifications
185
+
186
+ ```tsx
187
+ import { notifications } from 'mal-ui/notifications';
188
+ // In your layout, render: <Notifications />
189
+
190
+ notifications.show({ title: 'Done!', message: 'Upload complete.' });
191
+ ```
192
+
193
+ ### Modals
194
+
195
+ ```tsx
196
+ import { modals } from 'mal-ui/modals';
197
+ // In your layout, render: <ModalsProvider>
198
+
199
+ modals.openConfirmModal({
200
+ title: 'Delete item',
201
+ children: <Text>Are you sure?</Text>,
202
+ onConfirm: () => deleteItem(),
203
+ });
204
+ ```
205
+
206
+ ---
207
+
208
+ ## Development
209
+
210
+ ```bash
211
+ # Install dependencies
212
+ bun install
213
+
214
+ # Build the library
215
+ bun run build
216
+
217
+ # Type-check
218
+ bun run typecheck
219
+
220
+ # Run tests
221
+ bun test
222
+
223
+ # Lint & format
224
+ bun run lint
225
+ bun run format
226
+ ```
227
+
228
+ ### Running the demo app
229
+
230
+ ```bash
231
+ # 1. Build the library
232
+ bun run build
233
+
234
+ # 2. Start the Next.js demo
235
+ cd examples/nextjs-demo
236
+ bun install
237
+ bun run dev
238
+ ```
239
+
240
+ Open [http://localhost:3000](http://localhost:3000) — every subpath has its own demo route.
241
+
242
+ ---
243
+
244
+ > Built with [Mantine](https://mantine.dev) · Bundled with [Bun](https://bun.sh)
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from '@mantine/carousel';
2
+ export * from './extensions';
@@ -0,0 +1,424 @@
1
+ "use client";
2
+ import {
3
+ AccordionChevron,
4
+ Box,
5
+ InlineStyles,
6
+ UnstyledButton,
7
+ VisuallyHidden,
8
+ createSafeContext,
9
+ createVarsResolver,
10
+ factory,
11
+ filterProps,
12
+ getBaseValue,
13
+ getSortedBreakpoints,
14
+ getSpacing,
15
+ keys,
16
+ px,
17
+ rem,
18
+ useDirection,
19
+ useMantineTheme,
20
+ useProps,
21
+ useRandomClassName,
22
+ useStyles
23
+ } from "../chunks/index-3ffbn0gc.js";
24
+ import {
25
+ clamp,
26
+ useId$1
27
+ } from "../chunks/index-syjq3515.js";
28
+ import"../chunks/index-mc01z7m9.js";
29
+
30
+ // node_modules/@mantine/carousel/esm/Carousel.context.mjs
31
+
32
+ var [CarouselProvider, useCarouselContext] = createSafeContext("Carousel component was not found in tree");
33
+
34
+ // node_modules/@mantine/carousel/esm/Carousel.module.mjs
35
+
36
+ var Carousel_module_default = {
37
+ root: "m_17884d0f",
38
+ viewport: "m_a2dae653",
39
+ container: "m_fcd81474",
40
+ controls: "m_39bc3463",
41
+ control: "m_64f58e10",
42
+ indicators: "m_71ea3ab1",
43
+ indicator: "m_eae68602",
44
+ slide: "m_d98df724"
45
+ };
46
+
47
+ // node_modules/@mantine/carousel/esm/CarouselSlide/CarouselSlide.mjs
48
+ import { jsx } from "react/jsx-runtime";
49
+
50
+ var CarouselSlide = factory((props) => {
51
+ const { classNames, className, style, styles, vars, mod, ...others } = useProps("CarouselSlide", null, props);
52
+ const ctx = useCarouselContext();
53
+ return /* @__PURE__ */ jsx(Box, {
54
+ mod: [{ orientation: ctx.orientation }, mod],
55
+ role: "group",
56
+ "aria-roledescription": "slide",
57
+ "aria-label": "Carousel slide",
58
+ ...ctx.getStyles("slide", {
59
+ className,
60
+ style,
61
+ classNames,
62
+ styles
63
+ }),
64
+ ...others
65
+ });
66
+ });
67
+ CarouselSlide.classes = Carousel_module_default;
68
+ CarouselSlide.displayName = "@mantine/carousel/CarouselSlide";
69
+
70
+ // node_modules/@mantine/carousel/esm/CarouselVariables/CarouselVariables.mjs
71
+ import { jsx as jsx2 } from "react/jsx-runtime";
72
+
73
+ function CarouselVariables({ slideGap, slideSize, selector }) {
74
+ const theme = useMantineTheme();
75
+ const baseStyles = filterProps({
76
+ "--carousel-slide-gap": getSpacing(getBaseValue(slideGap)),
77
+ "--carousel-slide-size": rem(getBaseValue(slideSize))
78
+ });
79
+ const queries = keys(theme.breakpoints).reduce((acc, breakpoint) => {
80
+ if (!acc[breakpoint])
81
+ acc[breakpoint] = {};
82
+ if (typeof slideGap === "object" && slideGap[breakpoint] !== undefined)
83
+ acc[breakpoint]["--carousel-slide-gap"] = getSpacing(slideGap[breakpoint]);
84
+ if (typeof slideSize === "object" && slideSize[breakpoint] !== undefined)
85
+ acc[breakpoint]["--carousel-slide-size"] = getSpacing(slideSize[breakpoint]);
86
+ return acc;
87
+ }, {});
88
+ return /* @__PURE__ */ jsx2(InlineStyles, {
89
+ styles: baseStyles,
90
+ media: getSortedBreakpoints(keys(queries), theme.breakpoints).filter((breakpoint) => keys(queries[breakpoint.value]).length > 0).map((breakpoint) => ({
91
+ query: `(min-width: ${theme.breakpoints[breakpoint.value]})`,
92
+ styles: queries[breakpoint.value]
93
+ })),
94
+ selector
95
+ });
96
+ }
97
+ function getBreakpoints(values) {
98
+ if (typeof values === "object" && values !== null)
99
+ return keys(values);
100
+ return [];
101
+ }
102
+ function sortBreakpoints(breakpoints) {
103
+ return breakpoints.sort((a, b) => px(a) - px(b));
104
+ }
105
+ function getUniqueBreakpoints({ slideGap, slideSize }) {
106
+ return sortBreakpoints(Array.from(new Set([...getBreakpoints(slideGap), ...getBreakpoints(slideSize)])));
107
+ }
108
+ function CarouselContainerVariables({ slideGap, slideSize, selector }) {
109
+ const baseStyles = filterProps({
110
+ "--carousel-slide-gap": getSpacing(getBaseValue(slideGap)),
111
+ "--carousel-slide-size": rem(getBaseValue(slideSize))
112
+ });
113
+ const queries = getUniqueBreakpoints({
114
+ slideGap,
115
+ slideSize
116
+ }).reduce((acc, breakpoint) => {
117
+ if (!acc[breakpoint])
118
+ acc[breakpoint] = {};
119
+ if (typeof slideGap === "object" && slideGap[breakpoint] !== undefined)
120
+ acc[breakpoint]["--carousel-slide-gap"] = getSpacing(slideGap[breakpoint]);
121
+ if (typeof slideSize === "object" && slideSize[breakpoint] !== undefined)
122
+ acc[breakpoint]["--carousel-slide-size"] = getSpacing(slideSize[breakpoint]);
123
+ return acc;
124
+ }, {});
125
+ return /* @__PURE__ */ jsx2(InlineStyles, {
126
+ styles: baseStyles,
127
+ container: Object.keys(queries).map((breakpoint) => ({
128
+ query: `carousel (min-width: ${breakpoint})`,
129
+ styles: queries[breakpoint]
130
+ })),
131
+ selector
132
+ });
133
+ }
134
+
135
+ // node_modules/@mantine/carousel/esm/get-chevron-rotation.mjs
136
+
137
+ function getChevronRotation({ dir, orientation, direction }) {
138
+ if (direction === "previous")
139
+ return orientation === "horizontal" ? 90 * (dir === "ltr" ? 1 : -1) : -180;
140
+ return orientation === "horizontal" ? 90 * (dir === "ltr" ? -1 : 1) : 0;
141
+ }
142
+
143
+ // node_modules/@mantine/carousel/esm/Carousel.mjs
144
+ import { Children, createElement, useCallback, useEffect, useState } from "react";
145
+ import useEmblaCarousel from "embla-carousel-react";
146
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
147
+
148
+ var defaultProps = {
149
+ controlSize: 26,
150
+ controlsOffset: "sm",
151
+ slideSize: "100%",
152
+ slideGap: 0,
153
+ orientation: "horizontal",
154
+ includeGapInSize: true,
155
+ initialSlide: 0,
156
+ withControls: true,
157
+ withIndicators: false,
158
+ withKeyboardEvents: true,
159
+ type: "media"
160
+ };
161
+ var defaultEmblaOptions = {
162
+ align: "center",
163
+ loop: false,
164
+ slidesToScroll: 1,
165
+ dragFree: false,
166
+ inViewThreshold: 0,
167
+ skipSnaps: false,
168
+ containScroll: "trimSnaps"
169
+ };
170
+ var varsResolver = createVarsResolver((_, { height, controlSize, controlsOffset }) => ({ root: {
171
+ "--carousel-height": rem(height),
172
+ "--carousel-control-size": rem(controlSize),
173
+ "--carousel-controls-offset": getSpacing(controlsOffset)
174
+ } }));
175
+ var Carousel = factory((_props) => {
176
+ const props = useProps("Carousel", defaultProps, _props);
177
+ const { classNames, className, style, styles, unstyled, vars, children, getEmblaApi, onNextSlide, onPreviousSlide, onSlideChange, nextControlProps, previousControlProps, controlSize, controlsOffset, slideSize, slideGap, orientation, height, includeGapInSize, draggable, initialSlide, withControls, withIndicators, plugins, nextControlIcon, previousControlIcon, withKeyboardEvents, mod, type, emblaOptions, attributes, getIndicatorProps, id, ...others } = props;
178
+ const getStyles = useStyles({
179
+ name: "Carousel",
180
+ classes: Carousel_module_default,
181
+ props,
182
+ className,
183
+ style,
184
+ classNames,
185
+ styles,
186
+ unstyled,
187
+ attributes,
188
+ vars,
189
+ varsResolver
190
+ });
191
+ const _id = useId$1(id);
192
+ const responsiveClassName = useRandomClassName();
193
+ const { dir } = useDirection();
194
+ const [emblaRefElement, embla] = useEmblaCarousel({
195
+ axis: orientation === "horizontal" ? "x" : "y",
196
+ direction: orientation === "horizontal" ? dir : undefined,
197
+ startIndex: initialSlide,
198
+ ...defaultEmblaOptions,
199
+ ...emblaOptions
200
+ }, plugins);
201
+ const [selected, setSelected] = useState(0);
202
+ const [slidesCount, setSlidesCount] = useState(0);
203
+ const handleScroll = useCallback((index) => embla && embla.scrollTo(index), [embla]);
204
+ const handleSelect = useCallback(() => {
205
+ if (!embla)
206
+ return;
207
+ const slide = embla.selectedScrollSnap();
208
+ setSelected(slide);
209
+ slide !== selected && onSlideChange?.(slide);
210
+ }, [
211
+ embla,
212
+ setSelected,
213
+ onSlideChange,
214
+ selected
215
+ ]);
216
+ const handlePrevious = useCallback(() => {
217
+ embla?.scrollPrev();
218
+ onPreviousSlide?.();
219
+ }, [embla]);
220
+ const handleNext = useCallback(() => {
221
+ embla?.scrollNext();
222
+ onNextSlide?.();
223
+ }, [embla]);
224
+ const handleKeydown = useCallback((event) => {
225
+ if (withKeyboardEvents) {
226
+ if (event.key === "ArrowRight") {
227
+ event.preventDefault();
228
+ handleNext();
229
+ }
230
+ if (event.key === "ArrowLeft") {
231
+ event.preventDefault();
232
+ handlePrevious();
233
+ }
234
+ if (event.key === "Home") {
235
+ event.preventDefault();
236
+ embla?.scrollTo(0);
237
+ }
238
+ if (event.key === "End") {
239
+ event.preventDefault();
240
+ embla?.scrollTo(embla.scrollSnapList().length - 1);
241
+ }
242
+ }
243
+ }, [
244
+ embla,
245
+ handleNext,
246
+ handlePrevious
247
+ ]);
248
+ useEffect(() => {
249
+ if (embla) {
250
+ getEmblaApi?.(embla);
251
+ handleSelect();
252
+ setSlidesCount(embla.scrollSnapList().length);
253
+ embla.on("select", handleSelect);
254
+ return () => {
255
+ embla.off("select", handleSelect);
256
+ };
257
+ }
258
+ }, [
259
+ embla,
260
+ emblaOptions?.slidesToScroll,
261
+ handleSelect
262
+ ]);
263
+ useEffect(() => {
264
+ if (embla) {
265
+ embla.reInit();
266
+ setSlidesCount(embla.scrollSnapList().length);
267
+ setSelected((currentSelected) => clamp(currentSelected, 0, Children.toArray(children).length - 1));
268
+ }
269
+ }, [Children.toArray(children).length, emblaOptions?.slidesToScroll]);
270
+ const canScrollPrev = embla?.canScrollPrev() || false;
271
+ const canScrollNext = embla?.canScrollNext() || false;
272
+ const handleIndicatorKeyDown = useCallback((event, index) => {
273
+ const isHorizontal = orientation === "horizontal";
274
+ const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
275
+ const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
276
+ if (event.key === nextKey) {
277
+ event.preventDefault();
278
+ const nextIndex = index < slidesCount - 1 ? index + 1 : 0;
279
+ handleScroll(nextIndex);
280
+ event.currentTarget.parentElement?.children[nextIndex]?.focus();
281
+ }
282
+ if (event.key === prevKey) {
283
+ event.preventDefault();
284
+ const prevIndex = index > 0 ? index - 1 : slidesCount - 1;
285
+ handleScroll(prevIndex);
286
+ event.currentTarget.parentElement?.children[prevIndex]?.focus();
287
+ }
288
+ if (event.key === "Home") {
289
+ event.preventDefault();
290
+ handleScroll(0);
291
+ event.currentTarget.parentElement?.children[0]?.focus();
292
+ }
293
+ if (event.key === "End") {
294
+ event.preventDefault();
295
+ handleScroll(slidesCount - 1);
296
+ event.currentTarget.parentElement?.children[slidesCount - 1]?.focus();
297
+ }
298
+ }, [
299
+ orientation,
300
+ slidesCount,
301
+ handleScroll
302
+ ]);
303
+ const indicators = Array(slidesCount).fill(0).map((_, index) => /* @__PURE__ */ createElement(UnstyledButton, {
304
+ ...getStyles("indicator"),
305
+ key: index,
306
+ role: "tab",
307
+ "aria-label": `Go to slide ${index + 1}`,
308
+ "aria-selected": index === selected,
309
+ tabIndex: index === selected ? 0 : -1,
310
+ "data-active": index === selected || undefined,
311
+ onClick: () => handleScroll(index),
312
+ onKeyDown: (event) => handleIndicatorKeyDown(event, index),
313
+ "data-orientation": orientation,
314
+ onMouseDown: (event) => event.preventDefault(),
315
+ ...getIndicatorProps?.(index)
316
+ }));
317
+ return /* @__PURE__ */ jsxs(CarouselProvider, {
318
+ value: {
319
+ getStyles,
320
+ orientation
321
+ },
322
+ children: [type === "container" ? /* @__PURE__ */ jsx3(CarouselContainerVariables, {
323
+ ...props,
324
+ selector: `.${responsiveClassName}`
325
+ }) : /* @__PURE__ */ jsx3(CarouselVariables, {
326
+ ...props,
327
+ selector: `.${responsiveClassName}`
328
+ }), /* @__PURE__ */ jsxs(Box, {
329
+ role: "region",
330
+ "aria-roledescription": "carousel",
331
+ ...getStyles("root", { className: responsiveClassName }),
332
+ ...others,
333
+ id: _id,
334
+ mod: [{
335
+ orientation,
336
+ "include-gap-in-size": includeGapInSize
337
+ }, mod],
338
+ onKeyDownCapture: handleKeydown,
339
+ children: [
340
+ /* @__PURE__ */ jsx3(VisuallyHidden, {
341
+ role: "status",
342
+ "aria-live": "polite",
343
+ "aria-atomic": "true",
344
+ children: slidesCount > 0 && `Slide ${selected + 1} of ${slidesCount}`
345
+ }),
346
+ withControls && /* @__PURE__ */ jsxs("div", {
347
+ ...getStyles("controls"),
348
+ "data-orientation": orientation,
349
+ children: [/* @__PURE__ */ jsx3(UnstyledButton, {
350
+ "aria-controls": _id,
351
+ "aria-label": "Previous slide",
352
+ "aria-disabled": !canScrollPrev,
353
+ "data-inactive": !canScrollPrev || undefined,
354
+ "data-type": "previous",
355
+ tabIndex: canScrollPrev ? 0 : -1,
356
+ ...previousControlProps,
357
+ ...getStyles("control", {
358
+ className: previousControlProps?.className,
359
+ style: previousControlProps?.style
360
+ }),
361
+ onClick: (event) => {
362
+ handlePrevious();
363
+ previousControlProps?.onClick?.(event);
364
+ },
365
+ children: typeof previousControlIcon !== "undefined" ? previousControlIcon : /* @__PURE__ */ jsx3(AccordionChevron, { style: { transform: `rotate(${getChevronRotation({
366
+ dir,
367
+ orientation,
368
+ direction: "previous"
369
+ })}deg)` } })
370
+ }), /* @__PURE__ */ jsx3(UnstyledButton, {
371
+ "aria-controls": _id,
372
+ "aria-label": "Next slide",
373
+ "aria-disabled": !canScrollNext,
374
+ "data-inactive": !canScrollNext || undefined,
375
+ "data-type": "next",
376
+ tabIndex: canScrollNext ? 0 : -1,
377
+ ...getStyles("control", {
378
+ className: nextControlProps?.className,
379
+ style: nextControlProps?.style
380
+ }),
381
+ ...nextControlProps,
382
+ onClick: (event) => {
383
+ handleNext();
384
+ nextControlProps?.onClick?.(event);
385
+ },
386
+ children: typeof nextControlIcon !== "undefined" ? nextControlIcon : /* @__PURE__ */ jsx3(AccordionChevron, { style: { transform: `rotate(${getChevronRotation({
387
+ dir,
388
+ orientation,
389
+ direction: "next"
390
+ })}deg)` } })
391
+ })]
392
+ }),
393
+ /* @__PURE__ */ jsx3("div", {
394
+ ...getStyles("viewport"),
395
+ ref: emblaRefElement,
396
+ "data-type": type,
397
+ children: /* @__PURE__ */ jsx3("div", {
398
+ ...getStyles("container", { className: responsiveClassName }),
399
+ "data-orientation": orientation,
400
+ children
401
+ })
402
+ }),
403
+ withIndicators && /* @__PURE__ */ jsx3("div", {
404
+ ...getStyles("indicators"),
405
+ role: "tablist",
406
+ "aria-label": "Slides",
407
+ "data-orientation": orientation,
408
+ children: indicators
409
+ })
410
+ ]
411
+ })]
412
+ });
413
+ });
414
+ Carousel.classes = Carousel_module_default;
415
+ Carousel.varsResolver = varsResolver;
416
+ Carousel.displayName = "@mantine/carousel/Carousel";
417
+ Carousel.Slide = CarouselSlide;
418
+ export {
419
+ useCarouselContext,
420
+ CarouselSlide,
421
+ Carousel
422
+ };
423
+
424
+ //# debugId=0A5736BDFF04F01564756E2164756E21