@g4rcez/components 3.0.0 → 3.0.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.
Files changed (176) hide show
  1. package/dist/ai/SKILL.md +266 -0
  2. package/dist/ai/docs/Alert.md +167 -0
  3. package/dist/ai/docs/AnimatedList.md +205 -0
  4. package/dist/ai/docs/Autocomplete.md +225 -0
  5. package/dist/ai/docs/Button.md +182 -0
  6. package/dist/ai/docs/Calendar.md +219 -0
  7. package/dist/ai/docs/Card.md +174 -0
  8. package/dist/ai/docs/Checkbox.md +199 -0
  9. package/dist/ai/docs/CommandPalette.md +293 -0
  10. package/dist/ai/docs/DatePicker.md +171 -0
  11. package/dist/ai/docs/Dropdown.md +223 -0
  12. package/dist/ai/docs/Empty.md +163 -0
  13. package/dist/ai/docs/Expand.md +143 -0
  14. package/dist/ai/docs/FileUpload.md +225 -0
  15. package/dist/ai/docs/Form.md +107 -0
  16. package/dist/ai/docs/FormReset.md +117 -0
  17. package/dist/ai/docs/Heading.md +88 -0
  18. package/dist/ai/docs/Input.md +237 -0
  19. package/dist/ai/docs/InputField.md +170 -0
  20. package/dist/ai/docs/List.md +205 -0
  21. package/dist/ai/docs/Menu.md +166 -0
  22. package/dist/ai/docs/Modal.md +280 -0
  23. package/dist/ai/docs/MultiSelect.md +196 -0
  24. package/dist/ai/docs/Notifications.md +231 -0
  25. package/dist/ai/docs/PageCalendar.md +271 -0
  26. package/dist/ai/docs/Polymorph.md +159 -0
  27. package/dist/ai/docs/Progress.md +145 -0
  28. package/dist/ai/docs/Radiobox.md +128 -0
  29. package/dist/ai/docs/RenderOnView.md +138 -0
  30. package/dist/ai/docs/Resizable.md +159 -0
  31. package/dist/ai/docs/Select.md +284 -0
  32. package/dist/ai/docs/Shortcut.md +105 -0
  33. package/dist/ai/docs/Skeleton.md +166 -0
  34. package/dist/ai/docs/Slider.md +144 -0
  35. package/dist/ai/docs/Slot.md +173 -0
  36. package/dist/ai/docs/Spinner.md +118 -0
  37. package/dist/ai/docs/Stats.md +137 -0
  38. package/dist/ai/docs/Step.md +159 -0
  39. package/dist/ai/docs/Switch.md +167 -0
  40. package/dist/ai/docs/Table.md +298 -0
  41. package/dist/ai/docs/Tabs.md +191 -0
  42. package/dist/ai/docs/Tag.md +224 -0
  43. package/dist/ai/docs/TaskList.md +144 -0
  44. package/dist/ai/docs/Textarea.md +167 -0
  45. package/dist/ai/docs/Timeline.md +210 -0
  46. package/dist/ai/docs/Toolbar.md +132 -0
  47. package/dist/ai/docs/Tooltip.md +231 -0
  48. package/dist/ai/docs/TransferList.md +142 -0
  49. package/dist/ai/docs/Typography.md +187 -0
  50. package/dist/ai/docs/Wizard.md +213 -0
  51. package/dist/ai/docs/index.md +183 -0
  52. package/dist/components/core/tag.d.ts +1 -1
  53. package/dist/components/core/tag.d.ts.map +1 -1
  54. package/dist/components/display/list.d.ts.map +1 -1
  55. package/dist/components/floating/dropdown.d.ts +1 -0
  56. package/dist/components/floating/dropdown.d.ts.map +1 -1
  57. package/dist/components/floating/menu.d.ts.map +1 -1
  58. package/dist/config/default-translations.d.ts +4 -4
  59. package/dist/hooks/use-translations.d.ts +4 -4
  60. package/dist/hooks/use-translations.d.ts.map +1 -1
  61. package/dist/index.css +1 -1
  62. package/dist/index.js +28 -20
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +2463 -2458
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/index.umd.js +12 -12
  67. package/dist/index.umd.js.map +1 -1
  68. package/package.json +4 -4
  69. package/dist/components/core/button.jsx +0 -79
  70. package/dist/components/core/heading.jsx +0 -4
  71. package/dist/components/core/polymorph.jsx +0 -5
  72. package/dist/components/core/render-on-view.jsx +0 -31
  73. package/dist/components/core/resizable.jsx +0 -51
  74. package/dist/components/core/slot.jsx +0 -156
  75. package/dist/components/core/tag.jsx +0 -51
  76. package/dist/components/core/typography.jsx +0 -22
  77. package/dist/components/display/alert.jsx +0 -58
  78. package/dist/components/display/calendar.jsx +0 -299
  79. package/dist/components/display/card.jsx +0 -43
  80. package/dist/components/display/empty.jsx +0 -11
  81. package/dist/components/display/list.jsx +0 -81
  82. package/dist/components/display/notifications.jsx +0 -126
  83. package/dist/components/display/progress.jsx +0 -11
  84. package/dist/components/display/shortcut.jsx +0 -23
  85. package/dist/components/display/skeleton.jsx +0 -12
  86. package/dist/components/display/spinner.jsx +0 -7
  87. package/dist/components/display/stats.jsx +0 -20
  88. package/dist/components/display/step.jsx +0 -131
  89. package/dist/components/display/tabs.jsx +0 -98
  90. package/dist/components/display/timeline.jsx +0 -25
  91. package/dist/components/floating/command-palette.jsx +0 -194
  92. package/dist/components/floating/dropdown.jsx +0 -53
  93. package/dist/components/floating/expand.jsx +0 -44
  94. package/dist/components/floating/menu.jsx +0 -147
  95. package/dist/components/floating/modal.jsx +0 -299
  96. package/dist/components/floating/toolbar.jsx +0 -5
  97. package/dist/components/floating/tooltip.jsx +0 -58
  98. package/dist/components/floating/wizard.jsx +0 -161
  99. package/dist/components/form/autocomplete.jsx +0 -279
  100. package/dist/components/form/checkbox.jsx +0 -12
  101. package/dist/components/form/date-picker.jsx +0 -115
  102. package/dist/components/form/file-upload.jsx +0 -133
  103. package/dist/components/form/form.jsx +0 -10
  104. package/dist/components/form/formReset.jsx +0 -17
  105. package/dist/components/form/free-text.jsx +0 -41
  106. package/dist/components/form/input-field.jsx +0 -56
  107. package/dist/components/form/input.jsx +0 -36
  108. package/dist/components/form/multi-select.jsx +0 -328
  109. package/dist/components/form/radiobox.jsx +0 -6
  110. package/dist/components/form/select.jsx +0 -42
  111. package/dist/components/form/slider.jsx +0 -45
  112. package/dist/components/form/switch.jsx +0 -46
  113. package/dist/components/form/task-list.jsx +0 -26
  114. package/dist/components/form/textarea.jsx +0 -12
  115. package/dist/components/form/transfer-list.jsx +0 -39
  116. package/dist/components/index.js +0 -45
  117. package/dist/components/page-calendar/calendar-header.jsx +0 -81
  118. package/dist/components/page-calendar/day-view.jsx +0 -87
  119. package/dist/components/page-calendar/event-pill.jsx +0 -25
  120. package/dist/components/page-calendar/index.js +0 -2
  121. package/dist/components/page-calendar/month-view.jsx +0 -47
  122. package/dist/components/page-calendar/page-calendar.jsx +0 -41
  123. package/dist/components/page-calendar/page-calendar.types.js +0 -1
  124. package/dist/components/page-calendar/page-calendar.utils.js +0 -71
  125. package/dist/components/page-calendar/week-view.jsx +0 -64
  126. package/dist/components/table/filter.jsx +0 -141
  127. package/dist/components/table/group.jsx +0 -68
  128. package/dist/components/table/index.jsx +0 -60
  129. package/dist/components/table/inner-table.jsx +0 -104
  130. package/dist/components/table/metadata.jsx +0 -36
  131. package/dist/components/table/pagination.jsx +0 -73
  132. package/dist/components/table/row.jsx +0 -58
  133. package/dist/components/table/sort.jsx +0 -105
  134. package/dist/components/table/table-lib.js +0 -83
  135. package/dist/components/table/table.context.jsx +0 -4
  136. package/dist/components/table/thead.jsx +0 -103
  137. package/dist/config/context.js +0 -12
  138. package/dist/config/default-translations.jsx +0 -83
  139. package/dist/config/default-tweaks.js +0 -4
  140. package/dist/constants.js +0 -2
  141. package/dist/hooks/use-click-outside.js +0 -17
  142. package/dist/hooks/use-color-parser.js +0 -9
  143. package/dist/hooks/use-components-provider.jsx +0 -19
  144. package/dist/hooks/use-debounce.js +0 -12
  145. package/dist/hooks/use-floating-ref.js +0 -6
  146. package/dist/hooks/use-form.js +0 -550
  147. package/dist/hooks/use-hover.js +0 -18
  148. package/dist/hooks/use-input-id.js +0 -5
  149. package/dist/hooks/use-is-coarse-device.js +0 -12
  150. package/dist/hooks/use-locale.js +0 -10
  151. package/dist/hooks/use-media-query.js +0 -25
  152. package/dist/hooks/use-on-event.js +0 -7
  153. package/dist/hooks/use-parent.js +0 -21
  154. package/dist/hooks/use-preferences.js +0 -23
  155. package/dist/hooks/use-previous.js +0 -9
  156. package/dist/hooks/use-reactive.js +0 -9
  157. package/dist/hooks/use-remove-scroll.js +0 -61
  158. package/dist/hooks/use-resize-observer.js +0 -17
  159. package/dist/hooks/use-stable-ref.js +0 -9
  160. package/dist/hooks/use-swipe.js +0 -17
  161. package/dist/hooks/use-translations.js +0 -9
  162. package/dist/hooks/use-tweaks.js +0 -9
  163. package/dist/hooks/use-window-size.js +0 -14
  164. package/dist/lib/combi-keys.js +0 -60
  165. package/dist/lib/dict.js +0 -39
  166. package/dist/lib/dom.js +0 -62
  167. package/dist/lib/fns.js +0 -46
  168. package/dist/lib/fzf.js +0 -117
  169. package/dist/lib/keyboard-area.js +0 -14
  170. package/dist/styles/common.js +0 -29
  171. package/dist/styles/dark.js +0 -214
  172. package/dist/styles/design-tokens.js +0 -69
  173. package/dist/styles/light.js +0 -214
  174. package/dist/styles/theme.js +0 -4
  175. package/dist/styles/theme.types.js +0 -1
  176. package/dist/types.js +0 -1
@@ -1,161 +0,0 @@
1
- "use client";
2
- import { arrow, autoUpdate, flip, FloatingArrow, FloatingPortal, offset, shift, useFloating, useInteractions, useRole, } from "@floating-ui/react";
3
- import { AnimatePresence, motion } from "motion/react";
4
- import React, { Fragment, useEffect, useLayoutEffect, useRef, useState } from "react";
5
- import { useResizeObserver } from "../../hooks/use-resize-observer";
6
- import { useTranslations } from "../../hooks/use-translations";
7
- import { useWindowSize } from "../../hooks/use-window-size";
8
- import { noop } from "../../lib/fns";
9
- import { Button } from "../core/button";
10
- const getRect = (element) => {
11
- if (!element)
12
- return { top: 0, left: 0, width: 0, height: 0, bottom: 0, right: 0 };
13
- return element.getBoundingClientRect();
14
- };
15
- const resolveElement = (element) => {
16
- if (typeof element === "string") {
17
- return document.querySelector(element);
18
- }
19
- if ("current" in element) {
20
- return element.current;
21
- }
22
- return element;
23
- };
24
- export const Wizard = ({ steps, active = false, onClose = noop, onFinish = noop, onChange = noop, labels: labelsProp }) => {
25
- const translation = useTranslations();
26
- const [index, setIndex] = useState(0);
27
- const currentStep = steps[index];
28
- const [element, setElement] = useState(null);
29
- const [rect, setRect] = useState(getRect(null));
30
- const [isOverlayReady, setIsOverlayReady] = useState(false);
31
- const arrowRef = useRef(null);
32
- const { width, height } = useWindowSize();
33
- const labels = {
34
- next: labelsProp?.next ?? translation.driverNext,
35
- previous: labelsProp?.previous ?? translation.driverPrevious,
36
- finish: labelsProp?.finish ?? translation.driverFinish,
37
- skip: labelsProp?.skip ?? translation.driverSkip,
38
- };
39
- const { refs, floatingStyles, context } = useFloating({
40
- open: active && isOverlayReady,
41
- placement: currentStep?.side || "bottom",
42
- whileElementsMounted: autoUpdate,
43
- middleware: [offset(10), flip(), shift(), arrow({ element: arrowRef })],
44
- });
45
- const { getFloatingProps } = useInteractions([useRole(context)]);
46
- useEffect(() => {
47
- if (active) {
48
- setIndex(0);
49
- }
50
- }, [active]);
51
- useEffect(() => {
52
- setIsOverlayReady(false);
53
- }, [index, active]);
54
- useEffect(() => {
55
- if (!active || !currentStep)
56
- return;
57
- const el = resolveElement(currentStep.element);
58
- if (el) {
59
- currentStep.onEnter?.();
60
- setTimeout(() => {
61
- setRect(el.getBoundingClientRect());
62
- refs.setReference(el);
63
- setElement(el);
64
- }, 100);
65
- }
66
- else {
67
- console.warn(`Driver: Element not found:`, currentStep.element);
68
- setElement(null);
69
- setRect({ top: 0, left: 0, width: 0, height: 0, bottom: 0, right: 0 });
70
- }
71
- }, [index, active, currentStep, refs]);
72
- useLayoutEffect(() => {
73
- if (!element)
74
- return;
75
- const update = () => setRect(element.getBoundingClientRect());
76
- update();
77
- window.addEventListener("scroll", update, { capture: true, passive: true });
78
- window.addEventListener("resize", update, { capture: true, passive: true });
79
- return () => {
80
- window.removeEventListener("scroll", update, { capture: true });
81
- window.removeEventListener("resize", update, { capture: true });
82
- };
83
- }, [element, width, height]);
84
- useResizeObserver(element, (entry) => {
85
- setRect(entry.target.getBoundingClientRect());
86
- });
87
- const handleNext = () => {
88
- currentStep.onNext?.();
89
- setTimeout(() => {
90
- if (index < steps.length - 1) {
91
- setIndex((i) => i + 1);
92
- onChange(index + 1);
93
- }
94
- else {
95
- onFinish();
96
- onClose();
97
- }
98
- }, 0);
99
- };
100
- const handlePrevious = () => {
101
- currentStep.onPrevious?.();
102
- if (index > 0) {
103
- setIndex((i) => i - 1);
104
- onChange(index - 1);
105
- }
106
- };
107
- if (!active)
108
- return null;
109
- const hasNext = index < steps.length - 1;
110
- const hasPrevious = index > 0;
111
- return (<FloatingPortal>
112
- <div className="pointer-events-none fixed inset-0 z-wizard">
113
- <svg className="absolute inset-0 h-full w-full fill-current text-floating-overlay/70" xmlns="http://www.w3.org/2000/svg">
114
- <defs>
115
- <mask id="driver-mask">
116
- <rect x="0" y="0" width="100%" height="100%" fill="white"/>
117
- <motion.rect rx="4" fill="black" initial={false} onAnimationComplete={() => setIsOverlayReady(true)} transition={{ type: "spring", duration: 0.5, ease: "easeInOut" }} animate={{
118
- x: rect.left - 5,
119
- y: rect.top - 5,
120
- width: rect.width + 10,
121
- height: rect.height + 10,
122
- }}/>
123
- </mask>
124
- </defs>
125
- <rect x="0" y="0" width="100%" height="100%" mask="url(#driver-mask)" className="pointer-events-auto"/>
126
- </svg>
127
- <AnimatePresence mode="wait">
128
- {currentStep && isOverlayReady && (<div {...getFloatingProps()} ref={refs.setFloating} style={element
129
- ? floatingStyles
130
- : {
131
- position: "fixed",
132
- top: "50%",
133
- left: "50%",
134
- transform: "translate(-50%, -50%)",
135
- }} className="pointer-events-auto outline-none">
136
- <motion.div transition={{ duration: 0.2 }} exit={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1 }} initial={{ opacity: 0, scale: 0.9 }} className="flex w-80 max-w-sm flex-col gap-3 rounded-lg border border-floating-border bg-floating-background p-4 shadow-lg">
137
- {element && (<FloatingArrow ref={arrowRef} context={context} className="fill-floating-background stroke-floating-border"/>)}
138
- {currentStep.title && <h3>{currentStep.title}</h3>}
139
- {currentStep.description && <Fragment>{currentStep.description}</Fragment>}
140
- <div className="mt-2 flex items-center justify-between border-t border-floating-border pt-2">
141
- <Button theme="raw" size="small" onClick={onClose} className="text-xs text-muted-foreground hover:text-foreground">
142
- {labels.skip}
143
- </Button>
144
- <div className="flex gap-2">
145
- {hasPrevious && (<Button size="small" theme="ghost-muted" onClick={handlePrevious}>
146
- {labels.previous}
147
- </Button>)}
148
- <Button size="small" onClick={handleNext}>
149
- {hasNext ? labels.next : labels.finish}
150
- </Button>
151
- </div>
152
- </div>
153
- <div className="absolute right-2 top-2 text-xs text-muted-foreground">
154
- {index + 1} / {steps.length}
155
- </div>
156
- </motion.div>
157
- </div>)}
158
- </AnimatePresence>
159
- </div>
160
- </FloatingPortal>);
161
- };
@@ -1,279 +0,0 @@
1
- "use client";
2
- import { autoPlacement, autoUpdate, FloatingFocusManager, FloatingPortal, offset, size, useDismiss, useFloating, useInteractions, useListNavigation, useRole, useTransitionStyles, } from "@floating-ui/react";
3
- import { ChevronDown } from "lucide-react";
4
- import { AnimatePresence, motion } from "motion/react";
5
- import React, { forwardRef, Fragment, useEffect, useRef, useState } from "react";
6
- import { flushSync } from "react-dom";
7
- import { Virtuoso } from "react-virtuoso";
8
- import { Is } from "sidekicker";
9
- import { useRemoveScroll } from "../../hooks/use-remove-scroll";
10
- import { useTranslations } from "../../hooks/use-translations";
11
- import { css, dispatchInput, getRemainingSize, initializeInputDataset, mergeRefs } from "../../lib/dom";
12
- import { safeRegex } from "../../lib/fns";
13
- import { fzf } from "../../lib/fzf";
14
- import { InputField } from "./input-field";
15
- const Frag = (props) => <Fragment>{props.children}</Fragment>;
16
- const transitionStyles = {
17
- duration: 200,
18
- open: { transform: "scaleY(1)", opacity: 1 },
19
- close: { transform: "scaleY(0)", opacity: 0 },
20
- initial: { transform: "scaleY(0)", opacity: 0.2 },
21
- };
22
- const emptyRef = [];
23
- const List = forwardRef(function VirtualList(props, ref) {
24
- return (<motion.ul {...props} ref={ref} className="max-h-96 w-full overscroll-contain rounded-lg">
25
- <AnimatePresence>{props.children}</AnimatePresence>
26
- </motion.ul>);
27
- });
28
- const Item = forwardRef(function VirtualItem({ item, context, ...props }, ref) {
29
- return <motion.li {...props} ref={ref} className="first:rounded-t-lg last:rounded-t-lg"/>;
30
- });
31
- const components = { List, Item };
32
- const MIN_SIZE = 40;
33
- export const Autocomplete = forwardRef(({ left, error, right, loading, options, container, rightLabel, interactive, emptyMessage, optionalText, labelClassName, feedback = null, hideLeft = false, required = false, dynamicOption = false, ...props }, externalRef) => {
34
- const scroller = useRef(null);
35
- const fieldset = useRef(null);
36
- const virtuoso = useRef(null);
37
- const defaults = props.value ?? props.defaultValue ?? "";
38
- const translation = useTranslations();
39
- const [h, setH] = useState(() => Math.min(320, MIN_SIZE * options.length));
40
- const [open, setOpen] = useState(false);
41
- const [shadow, setShadow] = useState("");
42
- const [value, setValue] = useState(defaults);
43
- const [label, setLabel] = useState(() => options.find((x) => x.value === defaults)?.label ?? defaults);
44
- const [index, setIndex] = useState(null);
45
- const listRef = useRef(emptyRef);
46
- const removeScrollRef = useRemoveScroll(open, "block-only");
47
- const innerOptions = dynamicOption && shadow !== ""
48
- ? [
49
- {
50
- value: shadow,
51
- label: shadow,
52
- "data-dynamic": "true",
53
- },
54
- ...options,
55
- ]
56
- : options;
57
- const openDropdown = () => flushSync(() => setOpen(true));
58
- const list = shadow
59
- ? fzf(innerOptions, "value", [
60
- { key: "value", value: shadow },
61
- { key: "label", value: shadow },
62
- ])
63
- : innerOptions;
64
- const setClosed = () => {
65
- setOpen(false);
66
- setH(0);
67
- };
68
- const displayList = list.filter((x) => x.hidden !== true);
69
- const pattern = dynamicOption
70
- ? undefined
71
- : `^(${options.map((x) => `${safeRegex(x.value)}${x.label ? "|" + safeRegex(x.label) : ""}`).join("|")})$`;
72
- const { x, y, strategy, refs, context, placement } = useFloating({
73
- open,
74
- transform: true,
75
- onOpenChange: setOpen,
76
- placement: "bottom-start",
77
- whileElementsMounted: autoUpdate,
78
- middleware: [
79
- offset(4),
80
- autoPlacement({ allowedPlacements: ["top-start", "bottom-start"], alignment: "start" }),
81
- size({
82
- padding: 10,
83
- elementContext: "reference",
84
- apply(args) {
85
- const ul = args.elements.floating.querySelector("ul");
86
- const fullSize = ul?.getBoundingClientRect().height || 0;
87
- const DEFAULT_SIZE = getRemainingSize(refs.reference.current, window.innerHeight);
88
- const maxH = Math.min(fullSize < MIN_SIZE ? DEFAULT_SIZE : fullSize, DEFAULT_SIZE, args.availableHeight);
89
- const size = displayList.length === 0 ? MIN_SIZE : Math.min(maxH, DEFAULT_SIZE, fullSize);
90
- const mw = `${fieldset.current?.getBoundingClientRect().width || DEFAULT_SIZE}px`;
91
- Object.assign(args.elements.floating.style, { width: mw, maxWidth: mw, height: size });
92
- },
93
- }),
94
- ],
95
- });
96
- const transitions = useTransitionStyles(context, transitionStyles);
97
- const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
98
- useRole(context, { role: "listbox" }),
99
- useDismiss(context),
100
- useListNavigation(context, {
101
- cols: 0,
102
- listRef,
103
- loop: true,
104
- virtual: true,
105
- allowEscape: true,
106
- activeIndex: index,
107
- selectedIndex: index,
108
- focusItemOnOpen: "auto",
109
- openOnArrowKeyDown: true,
110
- scrollItemIntoView: true,
111
- }),
112
- ]);
113
- useEffect(() => {
114
- if (props.value) {
115
- const item = options.find((x) => x.value === props.value);
116
- if (item) {
117
- setLabel(item.label ?? item.value);
118
- setValue(props.value);
119
- }
120
- }
121
- }, [props.value, options.length]);
122
- useEffect(() => {
123
- if (!open)
124
- return setH(0);
125
- const inputRef = refs.reference;
126
- if (inputRef.current === null)
127
- return;
128
- const s = getRemainingSize(inputRef.current, window.innerHeight);
129
- setTimeout(() => setH(Math.min(s, displayList.length * MIN_SIZE)), 100);
130
- }, [shadow, open, refs.reference, displayList.length]);
131
- useEffect(() => {
132
- const input = refs.reference.current;
133
- if (!input)
134
- return;
135
- return initializeInputDataset(input);
136
- }, []);
137
- const onSelect = (opt, i) => {
138
- setValue(opt.value);
139
- const input = refs.reference.current;
140
- if (!input)
141
- return;
142
- input?.setAttribute("data-value", opt.value);
143
- input.value = opt.value;
144
- const event = new Event("change", { bubbles: false, cancelable: true });
145
- input.dispatchEvent(event);
146
- if (props.onChange)
147
- props.onChange(event);
148
- setLabel(opt.label ?? "");
149
- setClosed();
150
- setShadow("");
151
- setIndex(i);
152
- };
153
- const onChange = (event) => {
154
- const value = event.target.value;
155
- setShadow(value);
156
- if (!open && value === "")
157
- return setOpen(true);
158
- event.target.name = props.name || "";
159
- return value ? setOpen(true) : props.onChange?.(event);
160
- };
161
- const onCaretDownClick = () => {
162
- openDropdown();
163
- setShadow("");
164
- refs.reference.current?.focus();
165
- };
166
- const onFocus = () => {
167
- setIndex((prev) => (prev === null ? 0 : prev));
168
- openDropdown();
169
- setShadow("");
170
- };
171
- const onClose = () => {
172
- refs.reference.current?.setAttribute("data-value", "");
173
- setShadow("");
174
- setValue("");
175
- setLabel("");
176
- dispatchInput(refs.reference.current);
177
- setClosed();
178
- };
179
- const id = props.id || props.name;
180
- const shadowId = `${id}-shadow`;
181
- const isEmpty = displayList.length === 0;
182
- const isTopPlacement = placement === "top" || placement === "top-start";
183
- return (<InputField {...props} left={left} error={error} ref={fieldset} form={props.form} loading={loading} name={props.name} feedback={open && isTopPlacement ? props.title : feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} rightLabel={rightLabel} interactive={interactive} id={shadowId} optionalText={optionalText} componentName="autocomplete" labelClassName={labelClassName} placeholder={props.placeholder} right={<span className="flex items-center gap-0.5">
184
- {right}
185
- <button type="button" className="p-2 transition-colors link:text-primary md:p-1" onClick={onCaretDownClick}>
186
- <ChevronDown size={20}/>
187
- <span className="sr-only">{translation.inputCaretDown}</span>
188
- </button>
189
- {value ? (<button type="button" onClick={onClose} className="p-2 transition-colors link:text-danger md:p-1">
190
- <svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
191
- <path d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"/>
192
- </svg>
193
- </button>) : null}
194
- </span>}>
195
- <input data-shadow="true" {...getReferenceProps({
196
- ...props,
197
- onFocus,
198
- pattern,
199
- onChange,
200
- id: shadowId,
201
- name: shadowId,
202
- ref: refs.setReference,
203
- onClick: (e) => e.currentTarget.focus(),
204
- onKeyDown(event) {
205
- if (event.key === "Escape") {
206
- event.currentTarget.blur();
207
- return setClosed();
208
- }
209
- if (!open)
210
- return;
211
- if (event.key === "ArrowDown") {
212
- let next = Is.number(index) ? index + 1 : 0;
213
- if (next > displayList.length - 1)
214
- next = 0;
215
- virtuoso.current?.scrollIntoView({ index: next });
216
- return setIndex(next);
217
- }
218
- if (event.key === "ArrowUp") {
219
- let next = Is.number(index) ? index - 1 : displayList.length - 1;
220
- if (next < 0)
221
- next = displayList.length - 1;
222
- virtuoso.current?.scrollIntoView({ index: next });
223
- return setIndex(next);
224
- }
225
- if (event.key === "Enter") {
226
- if (index !== null && displayList[index]) {
227
- event.preventDefault();
228
- return onSelect(displayList[index], index);
229
- }
230
- if (displayList.length === 1) {
231
- event.preventDefault();
232
- return onSelect(displayList[0], 0);
233
- }
234
- }
235
- },
236
- })} data-value={value} data-error={!!error} data-name={id} data-target={id} required={required} value={open ? shadow : options.length === 0 ? "" : label || value} aria-autocomplete="list" autoComplete="off" className={css("input placeholder-input-mask group h-input-height w-full flex-1", "rounded-md bg-transparent px-input-x py-input-y text-foreground", "outline-none transition-colors focus:ring-2 focus:ring-inset focus:ring-primary", "group-error:text-danger group-error:placeholder-input-mask-error", "text-base group-focus-within:border-primary group-hover:border-primary", props.className)}/>
237
- <input id={id} name={id} type="hidden" data-origin={id} ref={externalRef} required={required} defaultValue={props.value || value || undefined}/>
238
- <FloatingPortal preserveTabOrder>
239
- {open ? (<FloatingFocusManager modal guards returnFocus={false} context={context} initialFocus={-1} visuallyHiddenDismiss>
240
- <motion.div {...getFloatingProps({
241
- ref: mergeRefs(removeScrollRef, refs.setFloating),
242
- style: { ...transitions.styles, left: x, top: y ?? 0, position: strategy, height: "auto" },
243
- })} initial={false} data-floating="true" animate={{ height: isEmpty ? "auto" : h }} className={css("shadow-floating isolate z-floating m-0 max-h-80 origin-[top_center] list-none overscroll-contain rounded-b-lg rounded-t-lg border border-floating-border bg-floating-background p-0 text-foreground ease-in-out", isTopPlacement ? "origin-[bottom_center]" : "origin-[top_center]")} onAnimationComplete={() => {
244
- if (!open)
245
- return setH(0);
246
- const ul = refs.floating.current;
247
- const li = ul.querySelectorAll("li").item(0);
248
- const sum = (li ? li.getBoundingClientRect().height : MIN_SIZE) * displayList.length;
249
- return flushSync(() => setH(sum + 2));
250
- }}>
251
- {isEmpty ? (<div role="option" className="w-full border-b border-tooltip-border">
252
- <span className="flex w-full justify-between p-2 text-left text-disabled">
253
- {emptyMessage || translation.autocompleteEmpty}
254
- </span>
255
- </div>) : null}
256
- <Virtuoso overscan={40} ref={virtuoso} hidden={isEmpty} data={displayList} style={{ height: h }} defaultItemHeight={MIN_SIZE} components={components} scrollerRef={(e) => void (scroller.current = e)} className="border-floating max-h-full overscroll-contain rounded-lg bg-floating-background p-0 text-foreground" itemContent={(i, option) => {
257
- const Label = option.Render ?? Frag;
258
- const active = value === option.value || value === option.label;
259
- const selected = index === i;
260
- const children = option.label ?? option.value;
261
- return (<button data-value={option.value} {...getItemProps({
262
- ref: (node) => void (listRef.current[i] = node),
263
- role: "option",
264
- type: "button",
265
- "aria-checked": active,
266
- "aria-current": active,
267
- "aria-selected": active,
268
- "aria-busy": option.disabled,
269
- onClick: () => onSelect(option, i),
270
- className: `cursor-pointer min-h-10 hover:bg-floating-hover w-full p-2 text-left ${active ? "bg-primary-hover text-primary-foreground" : ""} ${selected ? "bg-floating-hover text-floating-foreground" : ""}`,
271
- })}>
272
- <Label {...props} label={option.label} value={option.value} children={children}/>
273
- </button>);
274
- }}/>
275
- </motion.div>
276
- </FloatingFocusManager>) : null}
277
- </FloatingPortal>
278
- </InputField>);
279
- });
@@ -1,12 +0,0 @@
1
- import React, { forwardRef } from "react";
2
- import { css } from "../../lib/dom";
3
- export const Checkbox = forwardRef(({ children, asTask = false, labelClassName, loading, error, className = "", size, container, ...props }, ref) => {
4
- const d = props.disabled || loading;
5
- return (<label aria-disabled={d} data-disabled={d} data-task={asTask} data-component="checkbox" className={css("group flex w-fit flex-wrap items-center font-normal data-[disabled=true]:cursor-not-allowed", asTask ? "group-checkbox-checked:line-through" : "", container)}>
6
- <input {...props} ref={ref} disabled={d} type="checkbox" data-task={asTask} className={css("form-checkbox mr-2 inline-block size-4 appearance-none rounded border-card-border bg-origin-border text-primary focus:ring-primary disabled:opacity-70 group-aria-disabled:cursor-not-allowed", className)}/>
7
- {children}
8
- <span data-name="checkbox-label" className={css("min-w-full flex-1 text-xs text-danger empty:mt-0 empty:hidden", labelClassName)}>
9
- {error}
10
- </span>
11
- </label>);
12
- });
@@ -1,115 +0,0 @@
1
- "use client";
2
- import { format, isValid, parse, startOfDay } from "date-fns";
3
- import { CalendarIcon } from "lucide-react";
4
- import React, { forwardRef, Fragment, useEffect, useId, useMemo, useState } from "react";
5
- import { Is } from "sidekicker";
6
- import { useLocale } from "../../hooks/use-locale";
7
- import { useTranslations } from "../../hooks/use-translations";
8
- import { Calendar } from "../display/calendar";
9
- import { Dropdown } from "../floating/dropdown";
10
- import { Input } from "./input";
11
- const fixedDate = new Date(1970, 11, 31);
12
- const parts = {
13
- year: () => [/\d/, /\d/, /\d/, /\d/],
14
- month: () => [/\d/, /\d/],
15
- day: () => [/\d/, /\d/],
16
- hour: () => [/\d/, /\d/],
17
- minute: () => [/\d/, /\d/],
18
- literal: (str) => str.split(""),
19
- };
20
- const placeholders = {
21
- day: () => "dd",
22
- hour: () => "HH",
23
- month: () => "MM",
24
- minute: () => "mm",
25
- year: () => "yyyy",
26
- literal: (str) => str,
27
- };
28
- const partValues = {
29
- literal: (_, str) => str,
30
- year: (date) => date.getFullYear().toString(),
31
- day: (date) => date.getDate().toString().padStart(2, "0"),
32
- hour: (date) => date.getHours().toString().padStart(2, "0"),
33
- minute: (date) => date.getMinutes().toString().padStart(2, "0"),
34
- month: (date) => (date.getMonth() + 1).toString().padStart(2, "0"),
35
- };
36
- const formatParts = (datetimeFormat, date) => {
37
- try {
38
- return datetimeFormat.formatToParts(date).map((x) => {
39
- if (x.type === "literal" && x.value === ", ") {
40
- return { type: x.type, value: " " };
41
- }
42
- return x;
43
- });
44
- }
45
- catch (e) {
46
- return [];
47
- }
48
- };
49
- const DATE_TIME_FORMAT = { day: "numeric", month: "numeric", year: "numeric", hour: "numeric", minute: "numeric" };
50
- const DATE_FORMAT = { day: "numeric", month: "numeric", year: "numeric" };
51
- export const DatePicker = forwardRef(({ date, locale: inputLocal, disabledDate, onChange, markToday, clickToClose, floating = true, type, ...props }, externalRef) => {
52
- const locale = useLocale(inputLocal);
53
- const labelId = useId();
54
- const translation = useTranslations();
55
- const datetimeFormat = useMemo(() => new Intl.DateTimeFormat(locale, type === "datetime" ? DATE_TIME_FORMAT : DATE_FORMAT), [locale, type]);
56
- const [innerDate, setInnerDate] = useState(date || undefined);
57
- const [open, setOpen] = useState(false);
58
- const mask = formatParts(datetimeFormat, fixedDate).flatMap((x) => (Is.keyof(parts, x.type) ? parts[x.type](x.value) : []));
59
- const placeholder = useMemo(() => {
60
- return formatParts(datetimeFormat, fixedDate).reduce((acc, x) => acc + (Is.keyof(placeholders, x.type) ? placeholders[x.type](x.value) : ""), "");
61
- }, [datetimeFormat]);
62
- const isoDateEffect = date?.toISOString();
63
- const [value, setValue] = useState(!innerDate
64
- ? ""
65
- : formatParts(datetimeFormat, innerDate).reduce((acc, x) => acc + (Is.keyof(parts, x.type) ? partValues[x.type](innerDate, x.value) : ""), ""));
66
- const onChangeDateInput = (e) => {
67
- const v = e.target.value;
68
- setValue(v);
69
- if (mask.length === v.length) {
70
- const matches = mask.every((x, i) => {
71
- const c = v.charAt(i);
72
- return typeof x === "string" ? c === x : x.test(c);
73
- });
74
- if (matches) {
75
- const parsed = parse(v, placeholder, new Date());
76
- const d = type === "datetime" ? parsed : startOfDay(parsed);
77
- setInnerDate(d);
78
- return onChange?.(d);
79
- }
80
- }
81
- setInnerDate(undefined);
82
- return onChange?.(undefined);
83
- };
84
- useEffect(() => {
85
- if (isValid(date)) {
86
- setInnerDate(date);
87
- setValue(format(date, placeholder));
88
- }
89
- }, [isoDateEffect, placeholder]);
90
- const onChangeDate = (d) => {
91
- setInnerDate(d);
92
- onChange?.(d);
93
- if (clickToClose)
94
- setOpen(false);
95
- if (d)
96
- return setValue(format(d, placeholder));
97
- return setValue("");
98
- };
99
- const validDate = isValid(innerDate);
100
- const htmlValue = validDate ? innerDate.toISOString() : undefined;
101
- const CalendarComponent = (<Calendar {...props} type={type} locale={locale} changeOnlyOnClick markToday={markToday} onChange={onChangeDate} disabledDate={disabledDate} date={validDate ? innerDate : undefined}/>);
102
- return (<Fragment>
103
- <Input {...props} mask={mask} value={value} id={undefined} name={undefined} data-value={htmlValue} formNoValidate={!open} data-target={props.name} data-component="date-picker" onChange={onChangeDateInput} required={props.required ?? true} error={open ? undefined : props.error} placeholder={props.placeholder || translation.datepickerPlaceholder(placeholder)} right={floating ? (<Fragment>
104
- <input data-origin={props.name} defaultValue={htmlValue} form={props.form} hidden id={props.name} name={props.name} ref={externalRef} type="date"/>
105
- <Dropdown open={open} onChange={setOpen} buttonProps={{ "aria-describedby": labelId }} trigger={<span aria-labelledby={labelId}>
106
- <span id={labelId} className="sr-only">
107
- {translation.datePickerCalendarButtonLabel}
108
- </span>
109
- <CalendarIcon />
110
- </span>}>
111
- {CalendarComponent}
112
- </Dropdown>
113
- </Fragment>) : null}/>
114
- </Fragment>);
115
- });