@blockle/blocks 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -136,6 +136,221 @@ const Link = react.forwardRef(function Link2({ asChild, className, children, var
136
136
  }
137
137
  );
138
138
  });
139
+ const useClickOutside = (ref, onClickOutside, { enabled = true } = {}) => {
140
+ react.useEffect(() => {
141
+ if (!enabled) {
142
+ return;
143
+ }
144
+ const listener = (event) => {
145
+ if (ref.current && !ref.current.contains(event.target)) {
146
+ onClickOutside();
147
+ }
148
+ };
149
+ document.addEventListener("click", listener);
150
+ return () => {
151
+ document.removeEventListener("click", listener);
152
+ };
153
+ }, [ref, onClickOutside, enabled]);
154
+ };
155
+ function getDropdownPosition(align, anchorRef, dropdownRef) {
156
+ if (!anchorRef.current || !dropdownRef.current) {
157
+ return [0, 0];
158
+ }
159
+ dropdownRef.current.style.transform = "none";
160
+ dropdownRef.current.style.transitionDuration = "0s";
161
+ const anchorRect = anchorRef.current.getBoundingClientRect();
162
+ const dropdownRect = dropdownRef.current.getBoundingClientRect();
163
+ const dropdownStyles = getComputedStyle(dropdownRef.current);
164
+ const marginTop = Number.parseFloat(dropdownStyles.getPropertyValue("margin-top"));
165
+ const marginRight = Number.parseFloat(dropdownStyles.getPropertyValue("margin-right"));
166
+ const marginBottom = Number.parseFloat(dropdownStyles.getPropertyValue("margin-bottom"));
167
+ const marginLeft = Number.parseFloat(dropdownStyles.getPropertyValue("margin-left"));
168
+ const marginY = marginTop + marginBottom;
169
+ const marginX = marginRight + marginLeft;
170
+ const docHeight = document.documentElement.clientHeight;
171
+ const docWidth = document.documentElement.clientWidth;
172
+ const docScrollTop = document.documentElement.scrollTop;
173
+ const docScrollLeft = document.documentElement.scrollLeft;
174
+ const anchorLeft = anchorRect.left + docScrollLeft;
175
+ const anchorTop = anchorRect.top + docScrollTop;
176
+ const topPosition = anchorRect.top - (dropdownRect.height + marginTop);
177
+ const rightPosition = anchorRect.left + anchorRect.width + dropdownRect.width;
178
+ const bottomPosition = anchorRect.top + anchorRect.height + dropdownRect.height;
179
+ const leftPosition = anchorRect.left - dropdownRect.width;
180
+ const offsetX = anchorLeft - (dropdownRect.width - anchorRect.width) / 2;
181
+ const offsetY = anchorTop - (dropdownRect.height - anchorRect.height) / 2;
182
+ dropdownRef.current.style.transform = "";
183
+ dropdownRef.current.style.transitionDuration = "";
184
+ switch (align) {
185
+ case "top": {
186
+ return topPosition > 0 ? [offsetX, anchorTop - dropdownRect.height - marginY] : [offsetX, anchorTop + anchorRect.height];
187
+ }
188
+ case "bottom": {
189
+ return bottomPosition < docHeight || topPosition < 0 ? [offsetX, anchorTop + anchorRect.height] : [offsetX, anchorTop - dropdownRect.height - marginY];
190
+ }
191
+ case "left": {
192
+ return leftPosition > docWidth || leftPosition > 0 ? [anchorLeft - dropdownRect.width - marginX, offsetY] : [anchorLeft + anchorRect.width, offsetY];
193
+ }
194
+ case "right": {
195
+ return rightPosition < docWidth || leftPosition < 0 ? [anchorLeft + anchorRect.width, offsetY] : [anchorLeft - dropdownRect.width - marginX, offsetY];
196
+ }
197
+ }
198
+ }
199
+ const Dropdown = ({
200
+ align = "bottom",
201
+ anchorElement,
202
+ children,
203
+ className,
204
+ onRequestClose,
205
+ open,
206
+ repositionOnScroll,
207
+ style,
208
+ variant,
209
+ ...restProps
210
+ }) => {
211
+ const layer = styles_components_overlay_Dialog_Dialog_cjs.useLayer();
212
+ const [visible, hide] = styles_components_overlay_Dialog_Dialog_cjs.useVisibilityState(open);
213
+ const [position, setPosition] = react.useState({ x: 0, y: 0 });
214
+ const dropdownRef = react.useRef(null);
215
+ const containerClassName = styles_components_display_Divider_Divider_cjs.useComponentStyles(
216
+ "dropdown",
217
+ { base: true, variants: { variant } },
218
+ false
219
+ );
220
+ react.useLayoutEffect(() => {
221
+ if (!visible) {
222
+ return;
223
+ }
224
+ const position2 = getDropdownPosition(align, anchorElement, dropdownRef);
225
+ setPosition({ x: position2[0], y: position2[1] });
226
+ }, [align, anchorElement, visible]);
227
+ react.useEffect(() => {
228
+ if (!open || !repositionOnScroll) {
229
+ return;
230
+ }
231
+ function handleResize() {
232
+ const position2 = getDropdownPosition(align, anchorElement, dropdownRef);
233
+ setPosition({ x: position2[0], y: position2[1] });
234
+ }
235
+ window.addEventListener("resize", handleResize);
236
+ window.addEventListener("scroll", handleResize);
237
+ return () => {
238
+ window.removeEventListener("resize", handleResize);
239
+ window.removeEventListener("scroll", handleResize);
240
+ };
241
+ }, [align, anchorElement, open, repositionOnScroll]);
242
+ styles_components_overlay_Dialog_Dialog_cjs.useIsomorphicLayoutEffect(() => {
243
+ var _a;
244
+ if (!open) {
245
+ (_a = dropdownRef.current) == null ? void 0 : _a.removeAttribute("data-open");
246
+ return;
247
+ }
248
+ let timer = requestAnimationFrame(() => {
249
+ timer = requestAnimationFrame(() => {
250
+ var _a2;
251
+ (_a2 = dropdownRef.current) == null ? void 0 : _a2.setAttribute("data-open", "");
252
+ });
253
+ });
254
+ return () => {
255
+ cancelAnimationFrame(timer);
256
+ };
257
+ }, [open, visible]);
258
+ const onAnimationEnd = react.useCallback(() => {
259
+ if (!open) {
260
+ hide();
261
+ }
262
+ }, [hide, open]);
263
+ react.useEffect(() => {
264
+ if (open) {
265
+ return;
266
+ }
267
+ if (!styles_components_overlay_Dialog_Dialog_cjs.hasAnimationDuration(dropdownRef.current)) {
268
+ hide();
269
+ }
270
+ }, [hide, open]);
271
+ styles_components_overlay_Dialog_Dialog_cjs.useKeyboard("Escape", onRequestClose, { enabled: visible });
272
+ useClickOutside(dropdownRef, onRequestClose, { enabled: visible });
273
+ if (!visible) {
274
+ return null;
275
+ }
276
+ const dataOpen = typeof window === "undefined" && open ? "" : void 0;
277
+ return /* @__PURE__ */ jsxRuntime.jsx(styles_components_overlay_Dialog_Dialog_cjs.Portal, { container: layer(), children: /* @__PURE__ */ jsxRuntime.jsx(
278
+ styles_components_display_Divider_Divider_cjs.Box,
279
+ {
280
+ ref: dropdownRef,
281
+ "data-open": dataOpen,
282
+ onAnimationEnd,
283
+ onTransitionEnd: onAnimationEnd,
284
+ className: styles_components_display_Divider_Divider_cjs.classnames(containerClassName, className),
285
+ position: "absolute",
286
+ style: {
287
+ ...style,
288
+ // TODO Think about how to handle this, perhaps we could add a custom class to the dropdown
289
+ // Or we remove it from getDropdownPosition?
290
+ // "horizontal" ? "vertical"
291
+ margin: align === "bottom" || align === "top" ? "var(--spacing) 0" : "0 var(--spacing)",
292
+ left: position.x,
293
+ top: position.y
294
+ },
295
+ ...restProps,
296
+ children
297
+ }
298
+ ) });
299
+ };
300
+ const Tooltip = ({ align = "top", children, label }) => {
301
+ const id = react.useId();
302
+ const ref = react.useRef(null);
303
+ const [open, setOpen] = react.useState(false);
304
+ react.useEffect(() => {
305
+ const element = ref.current;
306
+ if (!element) {
307
+ return;
308
+ }
309
+ function onEnter() {
310
+ setOpen(true);
311
+ }
312
+ function onLeave() {
313
+ setOpen(false);
314
+ }
315
+ element.addEventListener("mouseenter", onEnter);
316
+ element.addEventListener("mouseleave", onLeave);
317
+ element.addEventListener("focusin", onEnter);
318
+ element.addEventListener("focusout", onLeave);
319
+ return () => {
320
+ element.removeEventListener("mouseenter", onEnter);
321
+ element.removeEventListener("mouseleave", onLeave);
322
+ element.removeEventListener("focusin", onEnter);
323
+ element.removeEventListener("focusout", onLeave);
324
+ };
325
+ }, [ref, setOpen]);
326
+ if (react.Children.count(children) !== 1) {
327
+ throw new Error("Tooltip component can only have one child");
328
+ }
329
+ const child = react.Children.toArray(children)[0];
330
+ if (!react.isValidElement(child)) {
331
+ return null;
332
+ }
333
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
334
+ react.cloneElement(child, {
335
+ ref: styles_components_display_Divider_Divider_cjs.composeRefs(ref, child.ref),
336
+ ["aria-describedby"]: open ? id : void 0
337
+ }),
338
+ /* @__PURE__ */ jsxRuntime.jsx(
339
+ Dropdown,
340
+ {
341
+ id,
342
+ role: "tooltip",
343
+ anchorElement: ref,
344
+ open,
345
+ onRequestClose: () => {
346
+ setOpen(false);
347
+ },
348
+ align,
349
+ children: label
350
+ }
351
+ )
352
+ ] });
353
+ };
139
354
  exports.breakpointQuery = styles_lib_css_atoms_breakpoints_cjs.breakpointQuery;
140
355
  exports.style = styles_lib_css_style_style_cjs.style;
141
356
  exports.makeComponentTheme = styles_lib_theme_makeComponentTheme_cjs.makeComponentTheme;
@@ -171,3 +386,4 @@ exports.Inline = Inline;
171
386
  exports.Link = Link;
172
387
  exports.Progress = Progress;
173
388
  exports.Stack = Stack;
389
+ exports.Tooltip = Tooltip;
package/dist/index.d.mts CHANGED
@@ -1 +1 @@
1
- export { BlocksProvider, BlocksProviderProps, Box, BoxProps, Button, ButtonProps, Checkbox, CheckboxProps, Dialog, DialogProps, Divider, DividerProps, Heading, HeadingProps, Inline, InlineProps, Input, InputProps, Label, LabelProps, Link, LinkProps, Portal, PortalProps, Progress, ProgressProps, Radio, RadioProps, Select, SelectProps, Slider, SliderProps, Slot, Spinner, SpinnerProps, Stack, StackProps, Switch, SwitchProps, Text, TextProps, ThemeComponentsStyles, ThemeTokens, atoms, breakpointQuery, classnames, createSlottable, makeComponentTheme, makeTheme, style, useComponentStyleDefaultProps, useComponentStyles, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden, vars } from './momotaro.chunk.js';
1
+ export { BlocksProvider, BlocksProviderProps, Box, BoxProps, Button, ButtonProps, Checkbox, CheckboxProps, Dialog, DialogProps, Divider, DividerProps, Heading, HeadingProps, Inline, InlineProps, Input, InputProps, Label, LabelProps, Link, LinkProps, Portal, PortalProps, Progress, ProgressProps, Radio, RadioProps, Select, SelectProps, Slider, SliderProps, Slot, Spinner, SpinnerProps, Stack, StackProps, Switch, SwitchProps, Text, TextProps, ThemeComponentsStyles, ThemeTokens, Tooltip, TooltipProps, atoms, breakpointQuery, classnames, createSlottable, makeComponentTheme, makeTheme, style, useComponentStyleDefaultProps, useComponentStyles, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden, vars } from './momotaro.chunk.js';
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { BlocksProvider, BlocksProviderProps, Box, BoxProps, Button, ButtonProps, Checkbox, CheckboxProps, Dialog, DialogProps, Divider, DividerProps, Heading, HeadingProps, Inline, InlineProps, Input, InputProps, Label, LabelProps, Link, LinkProps, Portal, PortalProps, Progress, ProgressProps, Radio, RadioProps, Select, SelectProps, Slider, SliderProps, Slot, Spinner, SpinnerProps, Stack, StackProps, Switch, SwitchProps, Text, TextProps, ThemeComponentsStyles, ThemeTokens, atoms, breakpointQuery, classnames, createSlottable, makeComponentTheme, makeTheme, style, useComponentStyleDefaultProps, useComponentStyles, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden, vars } from './momotaro.chunk.js';
1
+ export { BlocksProvider, BlocksProviderProps, Box, BoxProps, Button, ButtonProps, Checkbox, CheckboxProps, Dialog, DialogProps, Divider, DividerProps, Heading, HeadingProps, Inline, InlineProps, Input, InputProps, Label, LabelProps, Link, LinkProps, Portal, PortalProps, Progress, ProgressProps, Radio, RadioProps, Select, SelectProps, Slider, SliderProps, Slot, Spinner, SpinnerProps, Stack, StackProps, Switch, SwitchProps, Text, TextProps, ThemeComponentsStyles, ThemeTokens, Tooltip, TooltipProps, atoms, breakpointQuery, classnames, createSlottable, makeComponentTheme, makeTheme, style, useComponentStyleDefaultProps, useComponentStyles, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden, vars } from './momotaro.chunk.js';
package/dist/index.mjs CHANGED
@@ -5,11 +5,11 @@ import { style } from "./styles/lib/css/style/style.mjs";
5
5
  import { makeComponentTheme } from "./styles/lib/theme/makeComponentTheme.mjs";
6
6
  import { makeTheme } from "./styles/lib/theme/makeTheme.mjs";
7
7
  import { vars } from "./styles/lib/theme/vars.css.mjs";
8
- import { useComponentStyles, Box, classnames, createSlottable } from "./styles/components/display/Divider/Divider.mjs";
8
+ import { useComponentStyles, Box, classnames, createSlottable, composeRefs } from "./styles/components/display/Divider/Divider.mjs";
9
9
  import { Divider, Slot, useComponentStyleDefaultProps } from "./styles/components/display/Divider/Divider.mjs";
10
10
  import { atoms } from "./styles/lib/css/atoms/sprinkles.css.mjs";
11
- import { jsx } from "react/jsx-runtime";
12
- import { forwardRef } from "react";
11
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
12
+ import { forwardRef, useEffect, useState, useRef, useLayoutEffect, useCallback, useId, Children, isValidElement, cloneElement } from "react";
13
13
  import { Button, Spinner } from "./styles/components/form/Button/Button.mjs";
14
14
  import { Checkbox, Label } from "./styles/components/form/Checkbox/Checkbox.mjs";
15
15
  import { Input } from "./styles/components/form/Input/Input.mjs";
@@ -18,7 +18,8 @@ import { Select } from "./styles/components/form/Select/Select.mjs";
18
18
  import { Slider } from "./styles/components/form/Slider/Slider.mjs";
19
19
  import { Switch } from "./styles/components/form/Switch/Switch.mjs";
20
20
  import { BlocksProvider } from "./styles/components/other/BlocksProvider/BlocksProvider.mjs";
21
- import { Dialog, Portal, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden } from "./styles/components/overlay/Dialog/Dialog.mjs";
21
+ import { useLayer, useVisibilityState, useIsomorphicLayoutEffect, hasAnimationDuration, useKeyboard, Portal } from "./styles/components/overlay/Dialog/Dialog.mjs";
22
+ import { Dialog, usePreventBodyScroll, useRootAriaHidden } from "./styles/components/overlay/Dialog/Dialog.mjs";
22
23
  import { Heading } from "./styles/components/typography/Heading/Heading.mjs";
23
24
  import { Text } from "./styles/components/typography/Text/Text.mjs";
24
25
  const Progress = forwardRef(function Progress2({ value, max = 100, className, ...restProps }, ref) {
@@ -137,6 +138,221 @@ const Link = forwardRef(function Link2({ asChild, className, children, variant,
137
138
  }
138
139
  );
139
140
  });
141
+ const useClickOutside = (ref, onClickOutside, { enabled = true } = {}) => {
142
+ useEffect(() => {
143
+ if (!enabled) {
144
+ return;
145
+ }
146
+ const listener = (event) => {
147
+ if (ref.current && !ref.current.contains(event.target)) {
148
+ onClickOutside();
149
+ }
150
+ };
151
+ document.addEventListener("click", listener);
152
+ return () => {
153
+ document.removeEventListener("click", listener);
154
+ };
155
+ }, [ref, onClickOutside, enabled]);
156
+ };
157
+ function getDropdownPosition(align, anchorRef, dropdownRef) {
158
+ if (!anchorRef.current || !dropdownRef.current) {
159
+ return [0, 0];
160
+ }
161
+ dropdownRef.current.style.transform = "none";
162
+ dropdownRef.current.style.transitionDuration = "0s";
163
+ const anchorRect = anchorRef.current.getBoundingClientRect();
164
+ const dropdownRect = dropdownRef.current.getBoundingClientRect();
165
+ const dropdownStyles = getComputedStyle(dropdownRef.current);
166
+ const marginTop = Number.parseFloat(dropdownStyles.getPropertyValue("margin-top"));
167
+ const marginRight = Number.parseFloat(dropdownStyles.getPropertyValue("margin-right"));
168
+ const marginBottom = Number.parseFloat(dropdownStyles.getPropertyValue("margin-bottom"));
169
+ const marginLeft = Number.parseFloat(dropdownStyles.getPropertyValue("margin-left"));
170
+ const marginY = marginTop + marginBottom;
171
+ const marginX = marginRight + marginLeft;
172
+ const docHeight = document.documentElement.clientHeight;
173
+ const docWidth = document.documentElement.clientWidth;
174
+ const docScrollTop = document.documentElement.scrollTop;
175
+ const docScrollLeft = document.documentElement.scrollLeft;
176
+ const anchorLeft = anchorRect.left + docScrollLeft;
177
+ const anchorTop = anchorRect.top + docScrollTop;
178
+ const topPosition = anchorRect.top - (dropdownRect.height + marginTop);
179
+ const rightPosition = anchorRect.left + anchorRect.width + dropdownRect.width;
180
+ const bottomPosition = anchorRect.top + anchorRect.height + dropdownRect.height;
181
+ const leftPosition = anchorRect.left - dropdownRect.width;
182
+ const offsetX = anchorLeft - (dropdownRect.width - anchorRect.width) / 2;
183
+ const offsetY = anchorTop - (dropdownRect.height - anchorRect.height) / 2;
184
+ dropdownRef.current.style.transform = "";
185
+ dropdownRef.current.style.transitionDuration = "";
186
+ switch (align) {
187
+ case "top": {
188
+ return topPosition > 0 ? [offsetX, anchorTop - dropdownRect.height - marginY] : [offsetX, anchorTop + anchorRect.height];
189
+ }
190
+ case "bottom": {
191
+ return bottomPosition < docHeight || topPosition < 0 ? [offsetX, anchorTop + anchorRect.height] : [offsetX, anchorTop - dropdownRect.height - marginY];
192
+ }
193
+ case "left": {
194
+ return leftPosition > docWidth || leftPosition > 0 ? [anchorLeft - dropdownRect.width - marginX, offsetY] : [anchorLeft + anchorRect.width, offsetY];
195
+ }
196
+ case "right": {
197
+ return rightPosition < docWidth || leftPosition < 0 ? [anchorLeft + anchorRect.width, offsetY] : [anchorLeft - dropdownRect.width - marginX, offsetY];
198
+ }
199
+ }
200
+ }
201
+ const Dropdown = ({
202
+ align = "bottom",
203
+ anchorElement,
204
+ children,
205
+ className,
206
+ onRequestClose,
207
+ open,
208
+ repositionOnScroll,
209
+ style: style2,
210
+ variant,
211
+ ...restProps
212
+ }) => {
213
+ const layer = useLayer();
214
+ const [visible, hide] = useVisibilityState(open);
215
+ const [position, setPosition] = useState({ x: 0, y: 0 });
216
+ const dropdownRef = useRef(null);
217
+ const containerClassName = useComponentStyles(
218
+ "dropdown",
219
+ { base: true, variants: { variant } },
220
+ false
221
+ );
222
+ useLayoutEffect(() => {
223
+ if (!visible) {
224
+ return;
225
+ }
226
+ const position2 = getDropdownPosition(align, anchorElement, dropdownRef);
227
+ setPosition({ x: position2[0], y: position2[1] });
228
+ }, [align, anchorElement, visible]);
229
+ useEffect(() => {
230
+ if (!open || !repositionOnScroll) {
231
+ return;
232
+ }
233
+ function handleResize() {
234
+ const position2 = getDropdownPosition(align, anchorElement, dropdownRef);
235
+ setPosition({ x: position2[0], y: position2[1] });
236
+ }
237
+ window.addEventListener("resize", handleResize);
238
+ window.addEventListener("scroll", handleResize);
239
+ return () => {
240
+ window.removeEventListener("resize", handleResize);
241
+ window.removeEventListener("scroll", handleResize);
242
+ };
243
+ }, [align, anchorElement, open, repositionOnScroll]);
244
+ useIsomorphicLayoutEffect(() => {
245
+ var _a;
246
+ if (!open) {
247
+ (_a = dropdownRef.current) == null ? void 0 : _a.removeAttribute("data-open");
248
+ return;
249
+ }
250
+ let timer = requestAnimationFrame(() => {
251
+ timer = requestAnimationFrame(() => {
252
+ var _a2;
253
+ (_a2 = dropdownRef.current) == null ? void 0 : _a2.setAttribute("data-open", "");
254
+ });
255
+ });
256
+ return () => {
257
+ cancelAnimationFrame(timer);
258
+ };
259
+ }, [open, visible]);
260
+ const onAnimationEnd = useCallback(() => {
261
+ if (!open) {
262
+ hide();
263
+ }
264
+ }, [hide, open]);
265
+ useEffect(() => {
266
+ if (open) {
267
+ return;
268
+ }
269
+ if (!hasAnimationDuration(dropdownRef.current)) {
270
+ hide();
271
+ }
272
+ }, [hide, open]);
273
+ useKeyboard("Escape", onRequestClose, { enabled: visible });
274
+ useClickOutside(dropdownRef, onRequestClose, { enabled: visible });
275
+ if (!visible) {
276
+ return null;
277
+ }
278
+ const dataOpen = typeof window === "undefined" && open ? "" : void 0;
279
+ return /* @__PURE__ */ jsx(Portal, { container: layer(), children: /* @__PURE__ */ jsx(
280
+ Box,
281
+ {
282
+ ref: dropdownRef,
283
+ "data-open": dataOpen,
284
+ onAnimationEnd,
285
+ onTransitionEnd: onAnimationEnd,
286
+ className: classnames(containerClassName, className),
287
+ position: "absolute",
288
+ style: {
289
+ ...style2,
290
+ // TODO Think about how to handle this, perhaps we could add a custom class to the dropdown
291
+ // Or we remove it from getDropdownPosition?
292
+ // "horizontal" ? "vertical"
293
+ margin: align === "bottom" || align === "top" ? "var(--spacing) 0" : "0 var(--spacing)",
294
+ left: position.x,
295
+ top: position.y
296
+ },
297
+ ...restProps,
298
+ children
299
+ }
300
+ ) });
301
+ };
302
+ const Tooltip = ({ align = "top", children, label }) => {
303
+ const id = useId();
304
+ const ref = useRef(null);
305
+ const [open, setOpen] = useState(false);
306
+ useEffect(() => {
307
+ const element = ref.current;
308
+ if (!element) {
309
+ return;
310
+ }
311
+ function onEnter() {
312
+ setOpen(true);
313
+ }
314
+ function onLeave() {
315
+ setOpen(false);
316
+ }
317
+ element.addEventListener("mouseenter", onEnter);
318
+ element.addEventListener("mouseleave", onLeave);
319
+ element.addEventListener("focusin", onEnter);
320
+ element.addEventListener("focusout", onLeave);
321
+ return () => {
322
+ element.removeEventListener("mouseenter", onEnter);
323
+ element.removeEventListener("mouseleave", onLeave);
324
+ element.removeEventListener("focusin", onEnter);
325
+ element.removeEventListener("focusout", onLeave);
326
+ };
327
+ }, [ref, setOpen]);
328
+ if (Children.count(children) !== 1) {
329
+ throw new Error("Tooltip component can only have one child");
330
+ }
331
+ const child = Children.toArray(children)[0];
332
+ if (!isValidElement(child)) {
333
+ return null;
334
+ }
335
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
336
+ cloneElement(child, {
337
+ ref: composeRefs(ref, child.ref),
338
+ ["aria-describedby"]: open ? id : void 0
339
+ }),
340
+ /* @__PURE__ */ jsx(
341
+ Dropdown,
342
+ {
343
+ id,
344
+ role: "tooltip",
345
+ anchorElement: ref,
346
+ open,
347
+ onRequestClose: () => {
348
+ setOpen(false);
349
+ },
350
+ align,
351
+ children: label
352
+ }
353
+ )
354
+ ] });
355
+ };
140
356
  export {
141
357
  BlocksProvider,
142
358
  Box,
@@ -159,6 +375,7 @@ export {
159
375
  Stack,
160
376
  Switch,
161
377
  Text,
378
+ Tooltip,
162
379
  atoms,
163
380
  breakpointQuery,
164
381
  classnames,
@@ -713,14 +713,12 @@ declare const Radio: react.ForwardRefExoticComponent<{
713
713
  type SelectProps = {
714
714
  children: react__default.ReactNode;
715
715
  placeholder?: string;
716
- variant?: SelectTheme['variants'];
716
+ variant?: SelectTheme['variants']['variant'];
717
717
  } & HTMLElementProps<HTMLSelectElement>;
718
718
  declare const Select: react__default.ForwardRefExoticComponent<{
719
719
  children: react__default.ReactNode;
720
720
  placeholder?: string | undefined;
721
- variant?: {
722
- variant: "outline" | "solid";
723
- } | undefined;
721
+ variant?: "outline" | "solid" | undefined;
724
722
  } & HTMLElementProps<HTMLSelectElement> & react__default.RefAttributes<HTMLSelectElement>>;
725
723
 
726
724
  type SliderProps = {
@@ -1071,6 +1069,26 @@ type DialogProps = {
1071
1069
  };
1072
1070
  declare const Dialog: React.FC<DialogProps>;
1073
1071
 
1072
+ type DropdownProps = {
1073
+ align?: 'top' | 'bottom' | 'left' | 'right';
1074
+ anchorElement: React.RefObject<HTMLElement>;
1075
+ children: React.ReactNode;
1076
+ className?: string;
1077
+ onRequestClose: () => void;
1078
+ open: boolean;
1079
+ repositionOnScroll?: boolean;
1080
+ style?: React.CSSProperties;
1081
+ variant?: DropdownTheme['variants']['variant'];
1082
+ } & HTMLElementProps<HTMLDivElement>;
1083
+
1084
+ type ReactElement = React.ReactElement<any, string | React.JSXElementConstructor<any>>;
1085
+ type TooltipProps = {
1086
+ align?: DropdownProps['align'];
1087
+ children: ReactElement;
1088
+ label: React.ReactNode;
1089
+ };
1090
+ declare const Tooltip: React.FC<TooltipProps>;
1091
+
1074
1092
  type HeadingProps = {
1075
1093
  children: React.ReactNode;
1076
1094
  className?: string;
@@ -1134,4 +1152,4 @@ declare const classnames: (...args: Args[]) => string | undefined;
1134
1152
 
1135
1153
  declare const momotaro: Theme;
1136
1154
 
1137
- export { BlocksProvider, type BlocksProviderProps, Box, type BoxProps, Button, type ButtonProps, Checkbox, type CheckboxProps, Dialog, type DialogProps, Divider, type DividerProps, Heading, type HeadingProps, Inline, type InlineProps, Input, type InputProps, Label, type LabelProps, Link, type LinkProps, Portal, type PortalProps, Progress, type ProgressProps, Radio, type RadioProps, Select, type SelectProps, Slider, type SliderProps, Slot, Spinner, type SpinnerProps, Stack, type StackProps, Switch, type SwitchProps, Text, type TextProps, type ThemeComponentsStyles, type ThemeTokens, atoms, breakpointQuery, classnames, createSlottable, makeComponentTheme, makeTheme, momotaro, style, useComponentStyleDefaultProps, useComponentStyles, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden, vars };
1155
+ export { BlocksProvider, type BlocksProviderProps, Box, type BoxProps, Button, type ButtonProps, Checkbox, type CheckboxProps, Dialog, type DialogProps, Divider, type DividerProps, Heading, type HeadingProps, Inline, type InlineProps, Input, type InputProps, Label, type LabelProps, Link, type LinkProps, Portal, type PortalProps, Progress, type ProgressProps, Radio, type RadioProps, Select, type SelectProps, Slider, type SliderProps, Slot, Spinner, type SpinnerProps, Stack, type StackProps, Switch, type SwitchProps, Text, type TextProps, type ThemeComponentsStyles, type ThemeTokens, Tooltip, type TooltipProps, atoms, breakpointQuery, classnames, createSlottable, makeComponentTheme, makeTheme, momotaro, style, useComponentStyleDefaultProps, useComponentStyles, useIsomorphicLayoutEffect, useKeyboard, usePreventBodyScroll, useRootAriaHidden, vars };
@@ -220,6 +220,7 @@ exports.Box = Box;
220
220
  exports.Divider = Divider;
221
221
  exports.Slot = Slot;
222
222
  exports.classnames = classnames;
223
+ exports.composeRefs = composeRefs;
223
224
  exports.createSlottable = createSlottable;
224
225
  exports.useComponentStyleDefaultProps = useComponentStyleDefaultProps;
225
226
  exports.useComponentStyles = useComponentStyles;
@@ -220,6 +220,7 @@ export {
220
220
  Divider,
221
221
  Slot,
222
222
  classnames,
223
+ composeRefs,
223
224
  createSlottable,
224
225
  useComponentStyleDefaultProps,
225
226
  useComponentStyles,
@@ -3,9 +3,9 @@ const jsxRuntime = require("react/jsx-runtime");
3
3
  const react = require("react");
4
4
  const styles_components_display_Divider_Divider_cjs = require("../../display/Divider/Divider.cjs");
5
5
  const styles_components_form_Select_select_css_cjs = require("./select.css.cjs");
6
- const Select = react.forwardRef(function Select2({ children, placeholder, className, ...restProps }, ref) {
6
+ const Select = react.forwardRef(function Select2({ children, placeholder, className, variant, ...restProps }, ref) {
7
7
  const wrapperClassName = styles_components_display_Divider_Divider_cjs.useComponentStyles("select", { wrapper: true }, false);
8
- const selectClassName = styles_components_display_Divider_Divider_cjs.useComponentStyles("select", { select: true });
8
+ const selectClassName = styles_components_display_Divider_Divider_cjs.useComponentStyles("select", { select: true, variants: { variant } });
9
9
  const iconClassName = styles_components_display_Divider_Divider_cjs.useComponentStyles("select", { icon: true }, false);
10
10
  return /* @__PURE__ */ jsxRuntime.jsxs(styles_components_display_Divider_Divider_cjs.Box, { className: styles_components_display_Divider_Divider_cjs.classnames(styles_components_form_Select_select_css_cjs.wrapper, wrapperClassName), children: [
11
11
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -2,9 +2,9 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
3
  import { useComponentStyles, Box, classnames } from "../../display/Divider/Divider.mjs";
4
4
  import { wrapper, select, icon } from "./select.css.mjs";
5
- const Select = forwardRef(function Select2({ children, placeholder, className, ...restProps }, ref) {
5
+ const Select = forwardRef(function Select2({ children, placeholder, className, variant, ...restProps }, ref) {
6
6
  const wrapperClassName = useComponentStyles("select", { wrapper: true }, false);
7
- const selectClassName = useComponentStyles("select", { select: true });
7
+ const selectClassName = useComponentStyles("select", { select: true, variants: { variant } });
8
8
  const iconClassName = useComponentStyles("select", { icon: true }, false);
9
9
  return /* @__PURE__ */ jsxs(Box, { className: classnames(wrapper, wrapperClassName), children: [
10
10
  /* @__PURE__ */ jsxs(
@@ -248,7 +248,10 @@ const Dialog = ({
248
248
  };
249
249
  exports.Dialog = Dialog;
250
250
  exports.Portal = Portal;
251
+ exports.hasAnimationDuration = hasAnimationDuration;
251
252
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
252
253
  exports.useKeyboard = useKeyboard;
254
+ exports.useLayer = useLayer;
253
255
  exports.usePreventBodyScroll = usePreventBodyScroll;
254
256
  exports.useRootAriaHidden = useRootAriaHidden;
257
+ exports.useVisibilityState = useVisibilityState;
@@ -248,8 +248,11 @@ const Dialog = ({
248
248
  export {
249
249
  Dialog,
250
250
  Portal,
251
+ hasAnimationDuration,
251
252
  useIsomorphicLayoutEffect,
252
253
  useKeyboard,
254
+ useLayer,
253
255
  usePreventBodyScroll,
254
- useRootAriaHidden
256
+ useRootAriaHidden,
257
+ useVisibilityState
255
258
  };
@@ -14,15 +14,14 @@ const dropdown = styles_lib_theme_makeComponentTheme_cjs.makeComponentTheme("dro
14
14
  },
15
15
  selectors: {
16
16
  "&[data-open]": {
17
- transform: "translate(0, 0)",
17
+ transform: "scale(1)",
18
18
  opacity: 1
19
19
  }
20
20
  },
21
21
  // Apply the animation only if the user has not requested reduced motion
22
22
  "@media": {
23
23
  "(prefers-reduced-motion: no-preference)": {
24
- // transform: 'scale(0.9)',
25
- transform: "translateY(var(--spacing))",
24
+ transform: "scale(0.95)",
26
25
  transition: "opacity 80ms linear, transform 80ms",
27
26
  opacity: 0
28
27
  }
@@ -13,15 +13,14 @@ const dropdown = makeComponentTheme("dropdown", {
13
13
  },
14
14
  selectors: {
15
15
  "&[data-open]": {
16
- transform: "translate(0, 0)",
16
+ transform: "scale(1)",
17
17
  opacity: 1
18
18
  }
19
19
  },
20
20
  // Apply the animation only if the user has not requested reduced motion
21
21
  "@media": {
22
22
  "(prefers-reduced-motion: no-preference)": {
23
- // transform: 'scale(0.9)',
24
- transform: "translateY(var(--spacing))",
23
+ transform: "scale(0.95)",
25
24
  transition: "opacity 80ms linear, transform 80ms",
26
25
  opacity: 0
27
26
  }
@@ -6,7 +6,6 @@ const styles_lib_theme_vars_css_cjs = require("../../../lib/theme/vars.css.cjs")
6
6
  const styles_themes_momotaro_components_helpers_css_cjs = require("./helpers.css.cjs");
7
7
  fileScope.setFileScope("src/themes/momotaro/components/select.css.ts", "@blockle/blocks");
8
8
  const select = styles_lib_theme_makeComponentTheme_cjs.makeComponentTheme("select", {
9
- // wrapper: style({}),
10
9
  select: styles_lib_css_style_style_cjs.style([{
11
10
  color: "text",
12
11
  padding: "large",
@@ -24,11 +23,21 @@ const select = styles_lib_theme_makeComponentTheme_cjs.makeComponentTheme("selec
24
23
  boxShadow: `${styles_lib_theme_vars_css_cjs.vars.shadow.small}, ${styles_lib_theme_vars_css_cjs.vars.focus.boxShadow}`
25
24
  }
26
25
  }, styles_themes_momotaro_components_helpers_css_cjs.focusable]),
26
+ variants: {
27
+ variant: {
28
+ outline: styles_lib_css_style_style_cjs.style({
29
+ borderWidth: "small",
30
+ borderStyle: "solid",
31
+ borderColor: "primary"
32
+ }),
33
+ solid: styles_lib_css_style_style_cjs.style({})
34
+ }
35
+ },
27
36
  icon: styles_lib_css_style_style_cjs.style({
28
37
  paddingInline: "large"
29
38
  }),
30
39
  defaultVariants: {
31
- variant: "outline"
40
+ variant: "solid"
32
41
  }
33
42
  });
34
43
  fileScope.endFileScope();
@@ -5,7 +5,6 @@ import { vars } from "../../../lib/theme/vars.css.mjs";
5
5
  import { focusable } from "./helpers.css.mjs";
6
6
  setFileScope("src/themes/momotaro/components/select.css.ts", "@blockle/blocks");
7
7
  const select = makeComponentTheme("select", {
8
- // wrapper: style({}),
9
8
  select: style([{
10
9
  color: "text",
11
10
  padding: "large",
@@ -23,11 +22,21 @@ const select = makeComponentTheme("select", {
23
22
  boxShadow: `${vars.shadow.small}, ${vars.focus.boxShadow}`
24
23
  }
25
24
  }, focusable]),
25
+ variants: {
26
+ variant: {
27
+ outline: style({
28
+ borderWidth: "small",
29
+ borderStyle: "solid",
30
+ borderColor: "primary"
31
+ }),
32
+ solid: style({})
33
+ }
34
+ },
26
35
  icon: style({
27
36
  paddingInline: "large"
28
37
  }),
29
38
  defaultVariants: {
30
- variant: "outline"
39
+ variant: "solid"
31
40
  }
32
41
  });
33
42
  endFileScope();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockle/blocks",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Blocks design system",
5
5
  "repository": "git@github.com:Blockle/blocks.git",
6
6
  "license": "MIT",
@@ -34,6 +34,7 @@
34
34
  "import": "./dist/themes/momotaro.mjs",
35
35
  "require": "./dist/themes/momotaro.cjs"
36
36
  },
37
+ "./dist/style.css": "./dist/style.css",
37
38
  "./package.json": "./package.json"
38
39
  },
39
40
  "main": "./dist/index.cjs",
@@ -59,6 +60,7 @@
59
60
  "string-width": "^4.2.2"
60
61
  },
61
62
  "dependencies": {
63
+ "@storybook/test": "^8.0.2",
62
64
  "@vanilla-extract/css": "^1.14.1",
63
65
  "@vanilla-extract/css-utils": "^0.1.3",
64
66
  "@vanilla-extract/sprinkles": "^1.6.1",
@@ -69,41 +71,39 @@
69
71
  "@changesets/cli": "^2.27.1",
70
72
  "@crackle/cli": "^0.15.2",
71
73
  "@crackle/core": "^0.33.1",
72
- "@storybook/addon-a11y": "^7.6.17",
74
+ "@storybook/addon-a11y": "^8.0.2",
73
75
  "@storybook/addon-coverage": "^1.0.1",
74
- "@storybook/addon-essentials": "^7.6.17",
75
- "@storybook/addon-interactions": "^7.6.17",
76
- "@storybook/addon-links": "^7.6.17",
76
+ "@storybook/addon-essentials": "^8.0.2",
77
+ "@storybook/addon-interactions": "^8.0.2",
78
+ "@storybook/addon-links": "^8.0.2",
77
79
  "@storybook/addons": "^7.6.17",
78
- "@storybook/blocks": "^7.6.17",
79
- "@storybook/jest": "^0.2.3",
80
- "@storybook/react": "^7.6.17",
81
- "@storybook/react-vite": "^7.6.17",
82
- "@storybook/testing-library": "^0.2.2",
80
+ "@storybook/blocks": "^8.0.2",
81
+ "@storybook/react": "^8.0.2",
82
+ "@storybook/react-vite": "^8.0.2",
83
83
  "@testing-library/jest-dom": "^6.4.2",
84
- "@testing-library/react": "^14.2.1",
85
- "@types/react": "^18.2.60",
86
- "@types/react-dom": "^18.2.19",
87
- "@typescript-eslint/eslint-plugin": "^7.1.0",
88
- "@typescript-eslint/parser": "^7.1.0",
89
- "@vanilla-extract/vite-plugin": "^4.0.4",
90
- "@vitest/coverage-v8": "^1.3.1",
91
- "autoprefixer": "^10.4.17",
84
+ "@testing-library/react": "^14.2.2",
85
+ "@types/react": "^18.2.67",
86
+ "@types/react-dom": "^18.2.22",
87
+ "@typescript-eslint/eslint-plugin": "^7.3.1",
88
+ "@typescript-eslint/parser": "^7.3.1",
89
+ "@vanilla-extract/vite-plugin": "^4.0.6",
90
+ "@vitest/coverage-v8": "^1.4.0",
91
+ "autoprefixer": "^10.4.18",
92
92
  "cross-env": "^7.0.3",
93
93
  "eslint": "^8.57.0",
94
94
  "eslint-config-prettier": "^9.1.0",
95
95
  "eslint-plugin-jest": "^27.9.0",
96
96
  "eslint-plugin-prettier": "^5.1.3",
97
- "eslint-plugin-react": "^7.33.2",
97
+ "eslint-plugin-react": "^7.34.1",
98
98
  "eslint-plugin-react-hooks": "^4.6.0",
99
99
  "eslint-plugin-storybook": "^0.8.0",
100
100
  "eslint-plugin-unicorn": "^51.0.1",
101
101
  "jsdom": "^24.0.0",
102
102
  "prettier": "^3.2.5",
103
103
  "prop-types": "^15.8.1",
104
- "storybook": "^7.6.17",
105
- "typescript": "^5.3.3",
106
- "vitest": "^1.3.1"
104
+ "storybook": "^8.0.2",
105
+ "typescript": "^5.4.2",
106
+ "vitest": "^1.4.0"
107
107
  },
108
108
  "packageManager": "yarn@1.22.19"
109
109
  }