@blockle/blocks 0.3.9 → 0.4.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
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const styles_lib_css_atoms_breakpoints_cjs = require("./styles/lib/css/atoms/breakpoints.cjs");
4
- const styles_lib_css_theme_makeTheme_cjs = require("./styles/lib/css/theme/makeTheme.cjs");
5
4
  const styles_lib_css_theme_makeComponentTheme_cjs = require("./styles/lib/css/theme/makeComponentTheme.cjs");
5
+ const styles_lib_css_theme_makeTheme_cjs = require("./styles/lib/css/theme/makeTheme.cjs");
6
6
  const styles_lib_css_theme_vars_css_cjs = require("./styles/lib/css/theme/vars.css.cjs");
7
7
  const styles_lib_css_atoms_sprinkles_css_cjs = require("./styles/lib/css/atoms/sprinkles.css.cjs");
8
- const jsxRuntime = require("react/jsx-runtime");
9
8
  const react = require("react");
9
+ const jsxRuntime = require("react/jsx-runtime");
10
10
  const styles_components_Button_Button_css_cjs = require("./styles/components/Button/Button.css.cjs");
11
11
  const styles_components_Divider_divider_css_cjs = require("./styles/components/Divider/divider.css.cjs");
12
+ const styles_components_Dialog_dialog_css_cjs = require("./styles/components/Dialog/dialog.css.cjs");
13
+ const reactDom = require("react-dom");
12
14
  const classnames = (...args) => {
13
15
  const className = args.filter((arg) => arg && typeof arg === "string").join(" ");
14
16
  return className || void 0;
@@ -286,14 +288,186 @@ const Divider = ({ className, color }) => {
286
288
  }
287
289
  );
288
290
  };
291
+ const useLayer = () => {
292
+ const layerRef = react.useRef();
293
+ react.useEffect(
294
+ () => () => {
295
+ if (layerRef.current) {
296
+ layerRef.current.remove();
297
+ }
298
+ },
299
+ []
300
+ );
301
+ return () => {
302
+ if (!layerRef.current) {
303
+ layerRef.current = document.createElement("div");
304
+ document.body.append(layerRef.current);
305
+ }
306
+ return layerRef.current;
307
+ };
308
+ };
309
+ const useVisibilityState = (open) => {
310
+ const [visible, setVisible] = react.useState(open);
311
+ const hide = react.useCallback(() => {
312
+ setVisible(false);
313
+ }, []);
314
+ react.useEffect(() => {
315
+ if (open) {
316
+ setVisible(true);
317
+ }
318
+ }, [open]);
319
+ return [visible, hide];
320
+ };
321
+ const focusableSelectors = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
322
+ const getFirstFocusableElement = (container) => {
323
+ const focusable = container.querySelector(focusableSelectors);
324
+ return focusable || null;
325
+ };
326
+ const focusFirstElement = (container) => {
327
+ const focusable = getFirstFocusableElement(container);
328
+ if (focusable) {
329
+ focusable.focus();
330
+ }
331
+ };
332
+ const useFocusLock = ({ ref, active }) => {
333
+ react.useEffect(() => {
334
+ if (!active) {
335
+ return;
336
+ }
337
+ const handleFocus = (event) => {
338
+ if (ref.current && event.target instanceof HTMLElement && !ref.current.contains(event.target)) {
339
+ focusFirstElement(ref.current);
340
+ }
341
+ };
342
+ document.addEventListener("focusin", handleFocus);
343
+ return () => {
344
+ document.removeEventListener("focusin", handleFocus);
345
+ };
346
+ }, [active]);
347
+ };
348
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
349
+ const useRestoreFocus = (active) => {
350
+ const [target, setTarget] = react.useState(null);
351
+ useIsomorphicLayoutEffect(() => {
352
+ if (active && !target) {
353
+ setTarget(document.activeElement);
354
+ }
355
+ }, [active]);
356
+ react.useEffect(() => {
357
+ if (!active && target instanceof HTMLElement) {
358
+ target.focus();
359
+ }
360
+ }, [active]);
361
+ };
362
+ const DialogContext = react.createContext(void 0);
363
+ const useNestedDialog = (open) => {
364
+ const parentDialog = react.useContext(DialogContext);
365
+ react.useEffect(() => {
366
+ if (!parentDialog || !open) {
367
+ return;
368
+ }
369
+ parentDialog.setEnabled(false);
370
+ return () => {
371
+ parentDialog.setEnabled(true);
372
+ };
373
+ }, [parentDialog, open]);
374
+ return !!parentDialog;
375
+ };
376
+ const usePreventBodyScroll = (enabled = true) => {
377
+ useIsomorphicLayoutEffect(() => {
378
+ const prevValue = document.body.style.getPropertyValue("overflow");
379
+ if (enabled) {
380
+ document.body.style.overflow = "hidden";
381
+ }
382
+ return () => {
383
+ document.body.style.overflow = prevValue;
384
+ };
385
+ }, [enabled]);
386
+ };
387
+ const Portal = ({ children, container }) => {
388
+ const context = useTheme();
389
+ return reactDom.createPortal(
390
+ /* @__PURE__ */ jsxRuntime.jsx(BlocksProvider, { theme: context, children }),
391
+ container || document.body
392
+ );
393
+ };
394
+ const Dialog = ({ children, open, className, onRequestClose }) => {
395
+ const dialogRef = react.useRef(null);
396
+ const layer = useLayer();
397
+ const [visible, hide] = useVisibilityState(open);
398
+ const [enabled, setEnabled] = react.useState(true);
399
+ const onBackdropClick = react.useCallback(
400
+ (event) => {
401
+ if (event.target === event.currentTarget) {
402
+ onRequestClose();
403
+ }
404
+ },
405
+ [onRequestClose]
406
+ );
407
+ const onAnimationEnd = react.useCallback((event) => {
408
+ if (event.animationName === styles_components_Dialog_dialog_css_cjs.backdropLeaveAnimation) {
409
+ event.stopPropagation();
410
+ hide();
411
+ }
412
+ }, []);
413
+ useFocusLock({ ref: dialogRef, active: open && enabled });
414
+ useRestoreFocus(open);
415
+ const isNested = useNestedDialog(visible);
416
+ usePreventBodyScroll(visible && !isNested);
417
+ react.useEffect(() => {
418
+ if (!open || !enabled) {
419
+ return;
420
+ }
421
+ const handleKeyDown = (event) => {
422
+ if (event.key === "Escape") {
423
+ onRequestClose();
424
+ }
425
+ };
426
+ document.addEventListener("keydown", handleKeyDown);
427
+ return () => {
428
+ document.removeEventListener("keydown", handleKeyDown);
429
+ };
430
+ }, [open, enabled]);
431
+ const backdropClassName = useComponentStyles("dialog", { backdrop: true });
432
+ const dialogClassName = useComponentStyles("dialog", { base: true });
433
+ if (!visible) {
434
+ return null;
435
+ }
436
+ return /* @__PURE__ */ jsxRuntime.jsx(Portal, { container: layer(), children: /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: { setEnabled }, children: /* @__PURE__ */ jsxRuntime.jsx(
437
+ Box,
438
+ {
439
+ className: classnames(styles_components_Dialog_dialog_css_cjs.backdrop, !open && styles_components_Dialog_dialog_css_cjs.backdropLeave, backdropClassName),
440
+ display: "flex",
441
+ placeItems: "center",
442
+ onClick: onBackdropClick,
443
+ onAnimationEnd,
444
+ children: /* @__PURE__ */ jsxRuntime.jsx(
445
+ Box,
446
+ {
447
+ ref: dialogRef,
448
+ as: "dialog",
449
+ open: true,
450
+ className: classnames(
451
+ styles_components_Dialog_dialog_css_cjs.dialog,
452
+ !open && styles_components_Dialog_dialog_css_cjs.dialogLeave,
453
+ dialogClassName,
454
+ className
455
+ ),
456
+ children
457
+ }
458
+ )
459
+ }
460
+ ) }) });
461
+ };
289
462
  exports.breakpointQuery = styles_lib_css_atoms_breakpoints_cjs.breakpointQuery;
290
- exports.makeTheme = styles_lib_css_theme_makeTheme_cjs.makeTheme;
291
463
  exports.makeComponentTheme = styles_lib_css_theme_makeComponentTheme_cjs.makeComponentTheme;
464
+ exports.makeTheme = styles_lib_css_theme_makeTheme_cjs.makeTheme;
292
465
  exports.vars = styles_lib_css_theme_vars_css_cjs.vars;
293
466
  exports.atoms = styles_lib_css_atoms_sprinkles_css_cjs.atoms;
294
467
  exports.BlocksProvider = BlocksProvider;
295
468
  exports.Box = Box;
296
469
  exports.Button = Button;
470
+ exports.Dialog = Dialog;
297
471
  exports.Divider = Divider;
298
472
  exports.Heading = Heading;
299
473
  exports.Inline = Inline;
@@ -302,3 +476,5 @@ exports.Spinner = Spinner;
302
476
  exports.Stack = Stack;
303
477
  exports.Text = Text;
304
478
  exports.classnames = classnames;
479
+ exports.useComponentStyleDefaultProps = useComponentStyleDefaultProps;
480
+ exports.useComponentStyles = useComponentStyles;
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { BlocksProvider, BlocksProviderProps, BlocksTokens, Box, BoxProps, Button, ButtonProps, ComponentThemesMap, Divider, DividerProps, Heading, HeadingProps, Inline, InlineProps, Link, LinkProps, Spinner, SpinnerProps, Stack, StackProps, Text, TextProps, atoms, breakpointQuery, classnames, makeComponentTheme, makeTheme, vars } from './momotaro.chunk.js';
1
+ export { BlocksProvider, BlocksProviderProps, BlocksTokens, Box, BoxProps, Button, ButtonProps, ComponentThemesMap, Dialog, DialogProps, Divider, DividerProps, Heading, HeadingProps, Inline, InlineProps, Link, LinkProps, Spinner, SpinnerProps, Stack, StackProps, Text, TextProps, atoms, breakpointQuery, classnames, makeComponentTheme, makeTheme, useComponentStyleDefaultProps, useComponentStyles, vars } from './momotaro.chunk.js';
package/dist/index.mjs CHANGED
@@ -1,14 +1,16 @@
1
1
  'use client';
2
2
 
3
3
  import { breakpointQuery } from "./styles/lib/css/atoms/breakpoints.mjs";
4
- import { makeTheme } from "./styles/lib/css/theme/makeTheme.mjs";
5
4
  import { makeComponentTheme } from "./styles/lib/css/theme/makeComponentTheme.mjs";
5
+ import { makeTheme } from "./styles/lib/css/theme/makeTheme.mjs";
6
6
  import { vars } from "./styles/lib/css/theme/vars.css.mjs";
7
7
  import { atoms } from "./styles/lib/css/atoms/sprinkles.css.mjs";
8
+ import { createContext, forwardRef, useContext, useRef, useEffect, useState, useCallback, useLayoutEffect } from "react";
8
9
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { createContext, forwardRef, useContext } from "react";
10
10
  import { buttonReset } from "./styles/components/Button/Button.css.mjs";
11
11
  import { divider } from "./styles/components/Divider/divider.css.mjs";
12
+ import { backdropLeaveAnimation, backdropLeave, backdrop, dialogLeave, dialog } from "./styles/components/Dialog/dialog.css.mjs";
13
+ import { createPortal } from "react-dom";
12
14
  const classnames = (...args) => {
13
15
  const className = args.filter((arg) => arg && typeof arg === "string").join(" ");
14
16
  return className || void 0;
@@ -286,10 +288,182 @@ const Divider = ({ className, color }) => {
286
288
  }
287
289
  );
288
290
  };
291
+ const useLayer = () => {
292
+ const layerRef = useRef();
293
+ useEffect(
294
+ () => () => {
295
+ if (layerRef.current) {
296
+ layerRef.current.remove();
297
+ }
298
+ },
299
+ []
300
+ );
301
+ return () => {
302
+ if (!layerRef.current) {
303
+ layerRef.current = document.createElement("div");
304
+ document.body.append(layerRef.current);
305
+ }
306
+ return layerRef.current;
307
+ };
308
+ };
309
+ const useVisibilityState = (open) => {
310
+ const [visible, setVisible] = useState(open);
311
+ const hide = useCallback(() => {
312
+ setVisible(false);
313
+ }, []);
314
+ useEffect(() => {
315
+ if (open) {
316
+ setVisible(true);
317
+ }
318
+ }, [open]);
319
+ return [visible, hide];
320
+ };
321
+ const focusableSelectors = 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
322
+ const getFirstFocusableElement = (container) => {
323
+ const focusable = container.querySelector(focusableSelectors);
324
+ return focusable || null;
325
+ };
326
+ const focusFirstElement = (container) => {
327
+ const focusable = getFirstFocusableElement(container);
328
+ if (focusable) {
329
+ focusable.focus();
330
+ }
331
+ };
332
+ const useFocusLock = ({ ref, active }) => {
333
+ useEffect(() => {
334
+ if (!active) {
335
+ return;
336
+ }
337
+ const handleFocus = (event) => {
338
+ if (ref.current && event.target instanceof HTMLElement && !ref.current.contains(event.target)) {
339
+ focusFirstElement(ref.current);
340
+ }
341
+ };
342
+ document.addEventListener("focusin", handleFocus);
343
+ return () => {
344
+ document.removeEventListener("focusin", handleFocus);
345
+ };
346
+ }, [active]);
347
+ };
348
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
349
+ const useRestoreFocus = (active) => {
350
+ const [target, setTarget] = useState(null);
351
+ useIsomorphicLayoutEffect(() => {
352
+ if (active && !target) {
353
+ setTarget(document.activeElement);
354
+ }
355
+ }, [active]);
356
+ useEffect(() => {
357
+ if (!active && target instanceof HTMLElement) {
358
+ target.focus();
359
+ }
360
+ }, [active]);
361
+ };
362
+ const DialogContext = createContext(void 0);
363
+ const useNestedDialog = (open) => {
364
+ const parentDialog = useContext(DialogContext);
365
+ useEffect(() => {
366
+ if (!parentDialog || !open) {
367
+ return;
368
+ }
369
+ parentDialog.setEnabled(false);
370
+ return () => {
371
+ parentDialog.setEnabled(true);
372
+ };
373
+ }, [parentDialog, open]);
374
+ return !!parentDialog;
375
+ };
376
+ const usePreventBodyScroll = (enabled = true) => {
377
+ useIsomorphicLayoutEffect(() => {
378
+ const prevValue = document.body.style.getPropertyValue("overflow");
379
+ if (enabled) {
380
+ document.body.style.overflow = "hidden";
381
+ }
382
+ return () => {
383
+ document.body.style.overflow = prevValue;
384
+ };
385
+ }, [enabled]);
386
+ };
387
+ const Portal = ({ children, container }) => {
388
+ const context = useTheme();
389
+ return createPortal(
390
+ /* @__PURE__ */ jsx(BlocksProvider, { theme: context, children }),
391
+ container || document.body
392
+ );
393
+ };
394
+ const Dialog = ({ children, open, className, onRequestClose }) => {
395
+ const dialogRef = useRef(null);
396
+ const layer = useLayer();
397
+ const [visible, hide] = useVisibilityState(open);
398
+ const [enabled, setEnabled] = useState(true);
399
+ const onBackdropClick = useCallback(
400
+ (event) => {
401
+ if (event.target === event.currentTarget) {
402
+ onRequestClose();
403
+ }
404
+ },
405
+ [onRequestClose]
406
+ );
407
+ const onAnimationEnd = useCallback((event) => {
408
+ if (event.animationName === backdropLeaveAnimation) {
409
+ event.stopPropagation();
410
+ hide();
411
+ }
412
+ }, []);
413
+ useFocusLock({ ref: dialogRef, active: open && enabled });
414
+ useRestoreFocus(open);
415
+ const isNested = useNestedDialog(visible);
416
+ usePreventBodyScroll(visible && !isNested);
417
+ useEffect(() => {
418
+ if (!open || !enabled) {
419
+ return;
420
+ }
421
+ const handleKeyDown = (event) => {
422
+ if (event.key === "Escape") {
423
+ onRequestClose();
424
+ }
425
+ };
426
+ document.addEventListener("keydown", handleKeyDown);
427
+ return () => {
428
+ document.removeEventListener("keydown", handleKeyDown);
429
+ };
430
+ }, [open, enabled]);
431
+ const backdropClassName = useComponentStyles("dialog", { backdrop: true });
432
+ const dialogClassName = useComponentStyles("dialog", { base: true });
433
+ if (!visible) {
434
+ return null;
435
+ }
436
+ return /* @__PURE__ */ jsx(Portal, { container: layer(), children: /* @__PURE__ */ jsx(DialogContext.Provider, { value: { setEnabled }, children: /* @__PURE__ */ jsx(
437
+ Box,
438
+ {
439
+ className: classnames(backdrop, !open && backdropLeave, backdropClassName),
440
+ display: "flex",
441
+ placeItems: "center",
442
+ onClick: onBackdropClick,
443
+ onAnimationEnd,
444
+ children: /* @__PURE__ */ jsx(
445
+ Box,
446
+ {
447
+ ref: dialogRef,
448
+ as: "dialog",
449
+ open: true,
450
+ className: classnames(
451
+ dialog,
452
+ !open && dialogLeave,
453
+ dialogClassName,
454
+ className
455
+ ),
456
+ children
457
+ }
458
+ )
459
+ }
460
+ ) }) });
461
+ };
289
462
  export {
290
463
  BlocksProvider,
291
464
  Box,
292
465
  Button,
466
+ Dialog,
293
467
  Divider,
294
468
  Heading,
295
469
  Inline,
@@ -302,5 +476,7 @@ export {
302
476
  classnames,
303
477
  makeComponentTheme,
304
478
  makeTheme,
479
+ useComponentStyleDefaultProps,
480
+ useComponentStyles,
305
481
  vars
306
482
  };