@keboola/design 9.1.0 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/AGENTS.md +117 -40
  2. package/COMPONENT-API.md +31 -9
  3. package/README.md +3 -3
  4. package/dist/MermaidDiagram-EOKJHQQV.js +10 -0
  5. package/dist/MermaidDiagram-EOKJHQQV.js.map +1 -0
  6. package/dist/charts.d.ts +31 -2
  7. package/dist/charts.js +6 -9
  8. package/dist/charts.js.map +1 -1
  9. package/dist/chunk-63NSN2VL.js +274 -0
  10. package/dist/chunk-63NSN2VL.js.map +1 -0
  11. package/dist/{rjsf.cjs → chunk-6FPEI4EM.js} +1491 -5701
  12. package/dist/chunk-6FPEI4EM.js.map +1 -0
  13. package/dist/chunk-7PUUHEJQ.js +1313 -0
  14. package/dist/chunk-7PUUHEJQ.js.map +1 -0
  15. package/dist/chunk-BOHNXTMM.js +606 -0
  16. package/dist/chunk-BOHNXTMM.js.map +1 -0
  17. package/dist/{testing.cjs → chunk-C3L3TBBT.js} +33 -164
  18. package/dist/chunk-C3L3TBBT.js.map +1 -0
  19. package/dist/chunk-CTCFYWJC.js +407 -0
  20. package/dist/chunk-CTCFYWJC.js.map +1 -0
  21. package/dist/chunk-ESBL3IPF.js +23 -0
  22. package/dist/chunk-ESBL3IPF.js.map +1 -0
  23. package/dist/chunk-IJTHFNNJ.js +261 -0
  24. package/dist/chunk-IJTHFNNJ.js.map +1 -0
  25. package/dist/chunk-JP7PNHLH.js +40 -0
  26. package/dist/chunk-JP7PNHLH.js.map +1 -0
  27. package/dist/chunk-KPNAW5MU.js +229 -0
  28. package/dist/chunk-KPNAW5MU.js.map +1 -0
  29. package/dist/chunk-L37JJ6MR.js +152 -0
  30. package/dist/chunk-L37JJ6MR.js.map +1 -0
  31. package/dist/chunk-Q7NWXLCT.js +90 -0
  32. package/dist/chunk-Q7NWXLCT.js.map +1 -0
  33. package/dist/chunk-SYIEF644.js +1016 -0
  34. package/dist/chunk-SYIEF644.js.map +1 -0
  35. package/dist/chunk-VMFSRV5H.js +16 -0
  36. package/dist/chunk-VMFSRV5H.js.map +1 -0
  37. package/dist/chunk-VPPM7UUQ.js +47 -0
  38. package/dist/chunk-VPPM7UUQ.js.map +1 -0
  39. package/dist/chunk-XV3UUOYF.js +845 -0
  40. package/dist/chunk-XV3UUOYF.js.map +1 -0
  41. package/dist/editors.d.ts +27 -3
  42. package/dist/editors.js +85 -2081
  43. package/dist/editors.js.map +1 -1
  44. package/dist/icons.d.ts +29 -8
  45. package/dist/icons.js +2 -361
  46. package/dist/icons.js.map +1 -1
  47. package/dist/index.d.ts +709 -425
  48. package/dist/index.js +5042 -13885
  49. package/dist/index.js.map +1 -1
  50. package/dist/markdown-editor.js +41 -3426
  51. package/dist/markdown-editor.js.map +1 -1
  52. package/dist/mermaid.js +8 -1129
  53. package/dist/mermaid.js.map +1 -1
  54. package/dist/rjsf.js +180 -9381
  55. package/dist/rjsf.js.map +1 -1
  56. package/dist/styles.css +1 -1
  57. package/dist/testing.js +5 -357
  58. package/dist/testing.js.map +1 -1
  59. package/package.json +28 -73
  60. package/src/styles.css +60 -3
  61. package/src/theme.css +1 -0
  62. package/dist/charts.cjs +0 -268
  63. package/dist/charts.cjs.map +0 -1
  64. package/dist/charts.d.cts +0 -181
  65. package/dist/constants-D3gaMY-W.d.cts +0 -39
  66. package/dist/editors.cjs +0 -2440
  67. package/dist/editors.cjs.map +0 -1
  68. package/dist/editors.d.cts +0 -165
  69. package/dist/icons.cjs +0 -23888
  70. package/dist/icons.cjs.map +0 -1
  71. package/dist/icons.d.cts +0 -20
  72. package/dist/index.cjs +0 -24894
  73. package/dist/index.cjs.map +0 -1
  74. package/dist/index.d.cts +0 -10438
  75. package/dist/markdown-editor.cjs +0 -4636
  76. package/dist/markdown-editor.cjs.map +0 -1
  77. package/dist/markdown-editor.d.cts +0 -75
  78. package/dist/mermaid.cjs +0 -1138
  79. package/dist/mermaid.cjs.map +0 -1
  80. package/dist/mermaid.d.cts +0 -15
  81. package/dist/rjsf.cjs.map +0 -1
  82. package/dist/rjsf.d.cts +0 -55
  83. package/dist/testing.cjs.map +0 -1
  84. package/dist/testing.d.cts +0 -25
@@ -0,0 +1,152 @@
1
+ import { Button, ButtonInline } from './chunk-CTCFYWJC.js';
2
+ import { Copy } from './chunk-BOHNXTMM.js';
3
+ import { Tooltip } from './chunk-63NSN2VL.js';
4
+ import { cn } from './chunk-JP7PNHLH.js';
5
+ import { useState } from 'react';
6
+ import { jsxs, jsx } from 'react/jsx-runtime';
7
+
8
+ // src/utils/copyToClipboard.ts
9
+ var copyViaSelection = (text) => {
10
+ const node = document.createElement("textarea");
11
+ node.value = text;
12
+ node.setAttribute("readonly", "");
13
+ node.style.cssText = "position:fixed;top:0;left:0;opacity:0";
14
+ document.body.append(node);
15
+ node.select();
16
+ try {
17
+ return document.execCommand("copy");
18
+ } finally {
19
+ node.remove();
20
+ }
21
+ };
22
+ var copyToClipboard = async (text) => {
23
+ try {
24
+ await navigator.clipboard.writeText(text);
25
+ } catch (error) {
26
+ if (!copyViaSelection(text)) throw error;
27
+ }
28
+ };
29
+ var Clipboard = ({
30
+ ref,
31
+ text: textProp,
32
+ children,
33
+ tooltip = "Copy to Clipboard",
34
+ tooltipPlacement = "top",
35
+ tooltipVariant: tooltipVariantProp = "action",
36
+ asChild = false,
37
+ onClick,
38
+ className,
39
+ ...restButtonProps
40
+ }) => {
41
+ const [isTooltipOpen, setIsTooltipOpen] = useState(false);
42
+ const [state, setState] = useState("ready");
43
+ const text = typeof textProp === "function" ? textProp() : textProp;
44
+ const copy = async (text2) => {
45
+ try {
46
+ if (!document.hasFocus()) window.focus();
47
+ await copyToClipboard(text2);
48
+ setState("copied");
49
+ } catch {
50
+ setState("error");
51
+ }
52
+ };
53
+ const handleOnClick = (event) => {
54
+ setIsTooltipOpen(true);
55
+ if (text && state === "ready") void copy(text);
56
+ onClick?.(event);
57
+ };
58
+ const handleOnOpenChange = (open) => {
59
+ if (!open && state !== "ready") setState("ready");
60
+ setIsTooltipOpen(open);
61
+ };
62
+ const tooltipContent = (() => {
63
+ if (!text) return "Nothing to copy";
64
+ if (state === "error") return "Failed to copy";
65
+ if (state === "copied") return "Copied to Clipboard";
66
+ return tooltip;
67
+ })();
68
+ const tooltipVariant = state === "ready" && !!text ? tooltipVariantProp : "action";
69
+ const hasTooltipContent = tooltipContent !== null && tooltipContent !== void 0;
70
+ return /* @__PURE__ */ jsxs(Tooltip.Root, { open: isTooltipOpen, onOpenChange: handleOnOpenChange, children: [
71
+ /* @__PURE__ */ jsx(
72
+ Tooltip.Trigger,
73
+ {
74
+ ...restButtonProps,
75
+ asChild,
76
+ keepOpenOnClick: true,
77
+ onClick: handleOnClick,
78
+ className: cn("tw:cursor-pointer", className),
79
+ ref,
80
+ children: children ?? text
81
+ }
82
+ ),
83
+ hasTooltipContent && /* @__PURE__ */ jsx(
84
+ Tooltip.Content,
85
+ {
86
+ keepOpenOnPointerDownOutside: true,
87
+ placement: tooltipPlacement,
88
+ variant: tooltipVariant,
89
+ children: tooltipContent
90
+ }
91
+ )
92
+ ] });
93
+ };
94
+ var DEFAULT_ICON = /* @__PURE__ */ jsx(Copy, {});
95
+ var DEFAULT_ARIA_LABEL = "Copy";
96
+ var ClipboardButton = ({
97
+ // clipboard props
98
+ text,
99
+ tooltip,
100
+ tooltipPlacement,
101
+ tooltipVariant,
102
+ // button props
103
+ icon = DEFAULT_ICON,
104
+ variant = "outline",
105
+ children,
106
+ ...rest
107
+ }) => {
108
+ const defaultAriaLabel = typeof tooltip === "string" && tooltip.trim() ? tooltip : DEFAULT_ARIA_LABEL;
109
+ const ariaLabel = rest["aria-label"] ?? (children == null ? defaultAriaLabel : void 0);
110
+ return /* @__PURE__ */ jsx(
111
+ Clipboard,
112
+ {
113
+ asChild: true,
114
+ tooltip,
115
+ tooltipPlacement,
116
+ tooltipVariant,
117
+ text,
118
+ children: /* @__PURE__ */ jsxs(Button, { ...rest, "aria-label": ariaLabel, variant, disabled: !text, children: [
119
+ icon,
120
+ children
121
+ ] })
122
+ }
123
+ );
124
+ };
125
+ var ClipboardInline = ({
126
+ // clipboard props
127
+ text,
128
+ tooltip,
129
+ tooltipPlacement,
130
+ tooltipVariant,
131
+ // button props
132
+ children = "Copy To Clipboard",
133
+ hideIcon = false,
134
+ ...rest
135
+ }) => /* @__PURE__ */ jsx(
136
+ Clipboard,
137
+ {
138
+ asChild: true,
139
+ text,
140
+ tooltip,
141
+ tooltipPlacement,
142
+ tooltipVariant,
143
+ children: /* @__PURE__ */ jsxs(ButtonInline, { ...rest, disabled: !text, children: [
144
+ !hideIcon && /* @__PURE__ */ jsx(Copy, { className: "tw:size-4" }),
145
+ children
146
+ ] })
147
+ }
148
+ );
149
+
150
+ export { Clipboard, ClipboardButton, ClipboardInline, copyToClipboard };
151
+ //# sourceMappingURL=chunk-L37JJ6MR.js.map
152
+ //# sourceMappingURL=chunk-L37JJ6MR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/copyToClipboard.ts","../src/components/Clipboard/Clipboard.tsx","../src/blocks/ClipboardButton/ClipboardButton.tsx","../src/blocks/ClipboardButton/ClipboardInline.tsx"],"names":["text","jsx","jsxs"],"mappings":"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","file":"chunk-L37JJ6MR.js","sourcesContent":["/**\n * The async Clipboard API requires the document to be focused and rejects with\n * `NotAllowedError: Document is not focused` otherwise — which is the normal state\n * for a page inside an iframe that has not taken focus, such as Storybook's canvas\n * or an embedded preview. `execCommand` has no such requirement because it copies\n * the selection of a node we focus ourselves, so it covers that gap.\n */\nconst copyViaSelection = (text: string) => {\n const node = document.createElement('textarea');\n node.value = text;\n node.setAttribute('readonly', '');\n node.style.cssText = 'position:fixed;top:0;left:0;opacity:0';\n document.body.append(node);\n node.select();\n\n try {\n return document.execCommand('copy');\n } finally {\n node.remove();\n }\n};\n\nexport const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n } catch (error) {\n if (!copyViaSelection(text)) throw error;\n }\n};\n","import { useState } from 'react';\nimport type { ComponentProps, MouseEventHandler } from 'react';\n\nimport { cn, copyToClipboard } from '../../utils';\nimport { type Props as TooltipProps, Tooltip } from '../Tooltip';\n\ntype Props = {\n tooltip?: TooltipProps['tooltip'];\n tooltipPlacement?: TooltipProps['placement'];\n tooltipVariant?: TooltipProps['variant'];\n asChild?: TooltipProps['triggerAsChild'];\n text?: string | (() => string);\n} & ComponentProps<'button'>;\n\nexport const Clipboard = ({\n ref,\n text: textProp,\n children,\n tooltip = 'Copy to Clipboard',\n tooltipPlacement = 'top',\n tooltipVariant: tooltipVariantProp = 'action',\n asChild = false,\n onClick,\n className,\n ...restButtonProps\n}: Props) => {\n const [isTooltipOpen, setIsTooltipOpen] = useState(false);\n const [state, setState] = useState<'ready' | 'copied' | 'error'>('ready');\n const text = typeof textProp === 'function' ? textProp() : textProp;\n\n const copy = async (text: string) => {\n try {\n // For the clipboard feature to work reliably, the window must be in focus for security reasons.\n // However, the button can be clicked without the window being focused.\n if (!document.hasFocus()) window.focus();\n\n await copyToClipboard(text);\n setState('copied');\n } catch {\n setState('error');\n }\n };\n\n const handleOnClick: MouseEventHandler<HTMLButtonElement> = (event) => {\n // Open on click rather than waiting for hover. Radix opens on pointer-enter via a\n // `delayDuration` timer (300ms here), so clicking faster than that left the outcome invisible\n // until the timer caught up — the message was already rendered, just inside a closed tooltip.\n setIsTooltipOpen(true);\n if (text && state === 'ready') void copy(text);\n onClick?.(event);\n };\n\n const handleOnOpenChange: ComponentProps<typeof Tooltip.Root>['onOpenChange'] = (open) => {\n // Reset when the tooltip closes, allowing the user to leave the copy button.\n if (!open && state !== 'ready') setState('ready');\n setIsTooltipOpen(open);\n };\n\n const tooltipContent = (() => {\n if (!text) return 'Nothing to copy';\n if (state === 'error') return 'Failed to copy';\n if (state === 'copied') return 'Copied to Clipboard';\n return tooltip;\n })();\n\n const tooltipVariant: TooltipProps['variant'] =\n state === 'ready' && !!text ? tooltipVariantProp : 'action';\n\n // `tooltip={null}` leaves nothing to say until there is an outcome. Not rendering `Content` at all\n // is what makes that work: hovering still opens the tooltip, there is simply nothing in it, and\n // the copied / failed message appears in place the moment `state` changes. It also keeps Radix\n // from pointing the trigger's `aria-describedby` at content that has no text.\n const hasTooltipContent = tooltipContent !== null && tooltipContent !== undefined;\n\n return (\n <Tooltip.Root open={isTooltipOpen} onOpenChange={handleOnOpenChange}>\n <Tooltip.Trigger\n {...restButtonProps}\n asChild={asChild}\n keepOpenOnClick\n onClick={handleOnClick}\n className={cn('tw:cursor-pointer', className)}\n ref={ref}\n >\n {children ?? text}\n </Tooltip.Trigger>\n\n {hasTooltipContent && (\n <Tooltip.Content\n keepOpenOnPointerDownOutside\n placement={tooltipPlacement}\n variant={tooltipVariant}\n >\n {tooltipContent}\n </Tooltip.Content>\n )}\n </Tooltip.Root>\n );\n};\n","import type { ComponentProps, ReactNode } from 'react';\n\nimport { Button } from '../../components/Button';\nimport { Clipboard } from '../../components/Clipboard';\nimport { Copy } from '../../icons';\n\ntype ClipboardProps = Pick<\n ComponentProps<typeof Clipboard>,\n 'text' | 'tooltip' | 'tooltipPlacement' | 'tooltipVariant'\n>;\n\ntype ButtonProps = Omit<ComponentProps<typeof Button>, 'disabled' | 'icon'>;\n\ntype Props = ClipboardProps & ButtonProps & { icon?: ReactNode };\n\nconst DEFAULT_ICON: ReactNode = <Copy />;\nconst DEFAULT_ARIA_LABEL = 'Copy';\n\nexport const ClipboardButton = ({\n // clipboard props\n text,\n tooltip,\n tooltipPlacement,\n tooltipVariant,\n\n // button props\n icon = DEFAULT_ICON,\n variant = 'outline',\n children,\n ...rest\n}: Props) => {\n // Icon-only (no text children): the `tooltip` is visual only, not an accessible\n // name, so fall back to it (when it's a string) or a sensible default. A\n // consumer-supplied `aria-label` in `rest` still wins.\n // A non-empty string tooltip names the action; an empty/absent tooltip still\n // needs a name, so fall back to the default rather than an empty aria-label.\n const defaultAriaLabel =\n typeof tooltip === 'string' && tooltip.trim() ? tooltip : DEFAULT_ARIA_LABEL;\n const ariaLabel = rest['aria-label'] ?? (children == null ? defaultAriaLabel : undefined);\n\n return (\n <Clipboard\n asChild\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n tooltipVariant={tooltipVariant}\n text={text}\n >\n <Button {...rest} aria-label={ariaLabel} variant={variant} disabled={!text}>\n {icon}\n {children}\n </Button>\n </Clipboard>\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport { ButtonInline } from '../../components/Button';\nimport { Clipboard } from '../../components/Clipboard';\nimport { Copy } from '../../icons';\n\ntype ClipboardProps = Pick<\n ComponentProps<typeof Clipboard>,\n 'text' | 'tooltip' | 'tooltipPlacement' | 'tooltipVariant'\n>;\n\ntype ButtonProps = Omit<ComponentProps<typeof ButtonInline>, 'disabled'>;\n\ntype Props = { hideIcon?: boolean } & ClipboardProps & ButtonProps;\n\nexport const ClipboardInline = ({\n // clipboard props\n text,\n tooltip,\n tooltipPlacement,\n tooltipVariant,\n\n // button props\n children = 'Copy To Clipboard',\n hideIcon = false,\n ...rest\n}: Props) => (\n <Clipboard\n asChild\n text={text}\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n tooltipVariant={tooltipVariant}\n >\n <ButtonInline {...rest} disabled={!text}>\n {!hideIcon && <Copy className=\"tw:size-4\" />}\n {children}\n </ButtonInline>\n </Clipboard>\n);\n"]}
@@ -0,0 +1,90 @@
1
+ import { cn } from './chunk-JP7PNHLH.js';
2
+ import { cva } from 'class-variance-authority';
3
+ import { useRef, useLayoutEffect, useCallback, Children, Fragment } from 'react';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ // src/utils/isMac.ts
7
+ var getIsMac = () => {
8
+ if (typeof navigator !== "undefined" && "userAgentData" in navigator) {
9
+ const platform = navigator.userAgentData.platform;
10
+ if (typeof platform === "string") {
11
+ return platform.toLowerCase() === "macos";
12
+ }
13
+ }
14
+ if (typeof navigator !== "undefined" && typeof navigator.platform === "string") {
15
+ return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
16
+ }
17
+ return false;
18
+ };
19
+ var isMac = getIsMac();
20
+ var kbdVariants = cva(
21
+ [
22
+ "tailwindcss-preflight",
23
+ // style
24
+ "tw:pointer-events-none",
25
+ "tw:w-fit",
26
+ "tw:h-5",
27
+ "tw:min-w-5",
28
+ // layout
29
+ "tw:inline-flex",
30
+ "tw:items-center",
31
+ "tw:justify-center",
32
+ "tw:gap-1",
33
+ "tw:shrink-0",
34
+ // spacing
35
+ "tw:px-1",
36
+ 'tw:[&_svg:not([class*="size-"])]:size-2.5',
37
+ "tw:text-xs",
38
+ "tw:font-medium",
39
+ "tw:rounded"
40
+ ],
41
+ {
42
+ defaultVariants: {
43
+ variant: "default"
44
+ },
45
+ variants: {
46
+ variant: {
47
+ default: "tw:bg-muted tw:text-muted-foreground",
48
+ primary: "tw:bg-white/20 tw:text-white"
49
+ }
50
+ }
51
+ }
52
+ );
53
+
54
+ // src/utils/escapeStringRegexp.ts
55
+ var escapeStringRegexp = (string) => string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
56
+ var KbdSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, className: cn("tw:text-xs tw:text-muted-foreground", className) });
57
+ var KbdGroup = ({ ref, className, children, separator, ...props }) => {
58
+ return /* @__PURE__ */ jsx(
59
+ "kbd",
60
+ {
61
+ ...props,
62
+ ref,
63
+ className: cn("tw:inline-flex", "tw:items-center", "tw:gap-1", className),
64
+ children: separator ? (
65
+ // oxlint-disable-next-line react-x/no-children-to-array
66
+ Children.toArray(children).map((child, index) => (
67
+ // oxlint-disable-next-line
68
+ /* @__PURE__ */ jsxs(Fragment, { children: [
69
+ index > 0 && /* @__PURE__ */ jsx(KbdSeparator, { children: separator }),
70
+ child
71
+ ] }, index)
72
+ ))
73
+ ) : children
74
+ }
75
+ );
76
+ };
77
+ var Kbd = ({ children, className, variant, ...rest }) => /* @__PURE__ */ jsx("kbd", { ...rest, className: kbdVariants({ className, variant }), children });
78
+ Kbd.Group = KbdGroup;
79
+ Kbd.Separator = KbdSeparator;
80
+ var useStableCallback = (callback) => {
81
+ const latestRef = useRef(callback);
82
+ useLayoutEffect(() => {
83
+ latestRef.current = callback;
84
+ }, [callback]);
85
+ return useCallback((...args) => latestRef.current(...args), []);
86
+ };
87
+
88
+ export { Kbd, escapeStringRegexp, isMac, kbdVariants, useStableCallback };
89
+ //# sourceMappingURL=chunk-Q7NWXLCT.js.map
90
+ //# sourceMappingURL=chunk-Q7NWXLCT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/isMac.ts","../src/components/Kbd/styles.ts","../src/utils/escapeStringRegexp.ts","../src/components/Kbd/KbdSeparator.tsx","../src/components/Kbd/KbdGroup.tsx","../src/components/Kbd/Kbd.tsx","../src/hooks/useStableCallback.ts"],"names":["jsx"],"mappings":"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","file":"chunk-Q7NWXLCT.js","sourcesContent":["// Platform detection\ntype NavigatorUAData = {\n platform: string;\n brands: { brand: string; version: string }[];\n mobile: boolean;\n};\n\nconst getIsMac = (): boolean => {\n // Modern approach using navigator.userAgentData\n if (typeof navigator !== 'undefined' && 'userAgentData' in navigator) {\n const platform = (navigator.userAgentData as NavigatorUAData).platform;\n\n if (typeof platform === 'string') {\n return platform.toLowerCase() === 'macos';\n }\n }\n\n if (typeof navigator !== 'undefined' && typeof navigator.platform === 'string') {\n return navigator.platform.toUpperCase().indexOf('MAC') >= 0;\n }\n\n // Server-side rendering fallback\n return false;\n};\n\nexport const isMac = getIsMac();\n","import { cva } from 'class-variance-authority';\n\nexport const kbdVariants = cva(\n [\n 'tailwindcss-preflight',\n // style\n 'tw:pointer-events-none',\n 'tw:w-fit',\n 'tw:h-5',\n 'tw:min-w-5',\n\n // layout\n 'tw:inline-flex',\n 'tw:items-center',\n 'tw:justify-center',\n 'tw:gap-1',\n 'tw:shrink-0',\n\n // spacing\n 'tw:px-1',\n 'tw:[&_svg:not([class*=\"size-\"])]:size-2.5',\n\n 'tw:text-xs',\n 'tw:font-medium',\n\n 'tw:rounded',\n ],\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: 'tw:bg-muted tw:text-muted-foreground',\n primary: 'tw:bg-white/20 tw:text-white',\n },\n },\n },\n);\n","// Escape characters with special meaning either inside or outside character sets.\n// Use a simple backslash escape when it's always valid, and a `\\xnn` escape when the simpler form would be disallowed by Unicode patterns' stricter grammar.\nexport const escapeStringRegexp = (string: string) =>\n string.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d');\n","import type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\ntype Props = ComponentProps<'span'>;\n\nexport const KbdSeparator = ({ className, ...props }: Props) => (\n <span {...props} className={cn('tw:text-xs tw:text-muted-foreground', className)} />\n);\n","import { Children, Fragment } from 'react';\nimport type { ComponentProps } from 'react';\n\nimport { cn } from '../../utils';\n\nimport { KbdSeparator } from './KbdSeparator';\n\ntype Props = { separator?: string } & ComponentProps<'kbd'>;\n\nexport const KbdGroup = ({ ref, className, children, separator, ...props }: Props) => {\n return (\n <kbd\n {...props}\n ref={ref}\n className={cn('tw:inline-flex', 'tw:items-center', 'tw:gap-1', className)}\n >\n {separator\n ? // oxlint-disable-next-line react-x/no-children-to-array\n Children.toArray(children).map((child, index) => (\n // oxlint-disable-next-line\n <Fragment key={index}>\n {index > 0 && <KbdSeparator>{separator}</KbdSeparator>}\n {child}\n </Fragment>\n ))\n : children}\n </kbd>\n );\n};\n","import type { ComponentProps } from 'react';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { KbdGroup } from './KbdGroup';\nimport { KbdSeparator } from './KbdSeparator';\nimport { kbdVariants } from './styles';\n\ntype Props = ComponentProps<'kbd'> & VariantProps<typeof kbdVariants>;\n\nexport const Kbd = ({ children, className, variant, ...rest }: Props) => (\n <kbd {...rest} className={kbdVariants({ className, variant })}>\n {children}\n </kbd>\n);\n\nKbd.Group = KbdGroup;\nKbd.Separator = KbdSeparator;\n","import { useCallback, useLayoutEffect, useRef } from 'react';\n\n/**\n * A callback with a permanently stable identity that always sees the latest\n * render's values — for any consumer that keys off the handler's identity: a\n * third-party component that redoes expensive work when it changes, or a\n * memoized context value.\n *\n * React 19.2's `useEffectEvent` does this in one line, but it is scoped to\n * Effects and explicitly not to be passed to another component, which is the\n * whole point here.\n *\n * The swap is a layout effect rather than a passive one so it lands before the\n * browser can paint and accept input against the previous render's handler. It\n * is still an effect, and a child's runs before its parent's — so a consumer\n * calling the returned function from its own layout effect can still see the\n * previous render's closure.\n */\nexport const useStableCallback = <Args extends unknown[], Result>(\n callback: (...args: Args) => Result,\n): ((...args: Args) => Result) => {\n const latestRef = useRef(callback);\n\n useLayoutEffect(() => {\n latestRef.current = callback;\n }, [callback]);\n\n return useCallback((...args: Args) => latestRef.current(...args), []);\n};\n"]}