@g4rcez/components 3.0.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.
- package/dist/ai/SKILL.md +266 -0
- package/dist/ai/docs/Alert.md +167 -0
- package/dist/ai/docs/AnimatedList.md +205 -0
- package/dist/ai/docs/Autocomplete.md +225 -0
- package/dist/ai/docs/Button.md +182 -0
- package/dist/ai/docs/Calendar.md +219 -0
- package/dist/ai/docs/Card.md +174 -0
- package/dist/ai/docs/Checkbox.md +199 -0
- package/dist/ai/docs/CommandPalette.md +293 -0
- package/dist/ai/docs/DatePicker.md +171 -0
- package/dist/ai/docs/Dropdown.md +223 -0
- package/dist/ai/docs/Empty.md +163 -0
- package/dist/ai/docs/Expand.md +143 -0
- package/dist/ai/docs/FileUpload.md +225 -0
- package/dist/ai/docs/Form.md +107 -0
- package/dist/ai/docs/FormReset.md +117 -0
- package/dist/ai/docs/Heading.md +88 -0
- package/dist/ai/docs/Input.md +237 -0
- package/dist/ai/docs/InputField.md +170 -0
- package/dist/ai/docs/List.md +205 -0
- package/dist/ai/docs/Menu.md +166 -0
- package/dist/ai/docs/Modal.md +280 -0
- package/dist/ai/docs/MultiSelect.md +196 -0
- package/dist/ai/docs/Notifications.md +231 -0
- package/dist/ai/docs/PageCalendar.md +271 -0
- package/dist/ai/docs/Polymorph.md +159 -0
- package/dist/ai/docs/Progress.md +145 -0
- package/dist/ai/docs/Radiobox.md +128 -0
- package/dist/ai/docs/RenderOnView.md +138 -0
- package/dist/ai/docs/Resizable.md +159 -0
- package/dist/ai/docs/Select.md +284 -0
- package/dist/ai/docs/Shortcut.md +105 -0
- package/dist/ai/docs/Skeleton.md +166 -0
- package/dist/ai/docs/Slider.md +144 -0
- package/dist/ai/docs/Slot.md +173 -0
- package/dist/ai/docs/Spinner.md +118 -0
- package/dist/ai/docs/Stats.md +137 -0
- package/dist/ai/docs/Step.md +159 -0
- package/dist/ai/docs/Switch.md +167 -0
- package/dist/ai/docs/Table.md +298 -0
- package/dist/ai/docs/Tabs.md +191 -0
- package/dist/ai/docs/Tag.md +224 -0
- package/dist/ai/docs/TaskList.md +144 -0
- package/dist/ai/docs/Textarea.md +167 -0
- package/dist/ai/docs/Timeline.md +210 -0
- package/dist/ai/docs/Toolbar.md +132 -0
- package/dist/ai/docs/Tooltip.md +231 -0
- package/dist/ai/docs/TransferList.md +142 -0
- package/dist/ai/docs/Typography.md +187 -0
- package/dist/ai/docs/Wizard.md +213 -0
- package/dist/ai/docs/index.md +183 -0
- package/dist/components/core/button.d.ts +2 -8
- package/dist/components/core/button.d.ts.map +1 -1
- package/dist/components/core/polymorph.d.ts.map +1 -1
- package/dist/components/core/slot.d.ts +1 -1
- package/dist/components/core/slot.d.ts.map +1 -1
- package/dist/components/core/tag.d.ts +2 -2
- package/dist/components/core/tag.d.ts.map +1 -1
- package/dist/components/core/typography.d.ts.map +1 -1
- package/dist/components/display/alert.d.ts.map +1 -1
- package/dist/components/display/calendar.d.ts.map +1 -1
- package/dist/components/display/card.d.ts.map +1 -1
- package/dist/components/display/list.d.ts.map +1 -1
- package/dist/components/display/notifications.d.ts +2 -0
- package/dist/components/display/notifications.d.ts.map +1 -1
- package/dist/components/display/progress.d.ts.map +1 -1
- package/dist/components/display/skeleton.d.ts.map +1 -1
- package/dist/components/display/step.d.ts.map +1 -1
- package/dist/components/display/tabs.d.ts.map +1 -1
- package/dist/components/floating/command-palette.d.ts +1 -0
- package/dist/components/floating/command-palette.d.ts.map +1 -1
- package/dist/components/floating/dropdown.d.ts +1 -0
- package/dist/components/floating/dropdown.d.ts.map +1 -1
- package/dist/components/floating/menu.d.ts +2 -2
- package/dist/components/floating/menu.d.ts.map +1 -1
- package/dist/components/floating/modal.d.ts +20 -53
- package/dist/components/floating/modal.d.ts.map +1 -1
- package/dist/components/floating/tooltip.d.ts.map +1 -1
- package/dist/components/floating/wizard.d.ts +1 -1
- package/dist/components/floating/wizard.d.ts.map +1 -1
- package/dist/components/form/autocomplete.d.ts.map +1 -1
- package/dist/components/form/date-picker.d.ts.map +1 -1
- package/dist/components/form/free-text.d.ts.map +1 -1
- package/dist/components/form/input-field.d.ts +3 -2
- package/dist/components/form/input-field.d.ts.map +1 -1
- package/dist/components/form/multi-select.d.ts.map +1 -1
- package/dist/components/form/select.d.ts.map +1 -1
- package/dist/components/form/slider.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/page-calendar/calendar-header.d.ts +16 -0
- package/dist/components/page-calendar/calendar-header.d.ts.map +1 -0
- package/dist/components/page-calendar/day-view.d.ts +12 -0
- package/dist/components/page-calendar/day-view.d.ts.map +1 -0
- package/dist/components/page-calendar/event-pill.d.ts +9 -0
- package/dist/components/page-calendar/event-pill.d.ts.map +1 -0
- package/dist/components/page-calendar/index.d.ts +4 -0
- package/dist/components/page-calendar/index.d.ts.map +1 -0
- package/dist/components/page-calendar/month-view.d.ts +11 -0
- package/dist/components/page-calendar/month-view.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts.map +1 -0
- package/dist/components/page-calendar/week-view.d.ts +11 -0
- package/dist/components/page-calendar/week-view.d.ts.map +1 -0
- package/dist/components/table/index.d.ts.map +1 -1
- package/dist/components/table/inner-table.d.ts.map +1 -1
- package/dist/components/table/metadata.d.ts.map +1 -1
- package/dist/components/table/row.d.ts.map +1 -1
- package/dist/components/table/table-lib.d.ts.map +1 -1
- package/dist/components/table/thead.d.ts.map +1 -1
- package/dist/config/context.d.ts.map +1 -1
- package/dist/config/default-translations.d.ts +21 -4
- package/dist/config/default-translations.d.ts.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/hooks/use-components-provider.d.ts.map +1 -1
- package/dist/hooks/use-form.d.ts +11 -11
- package/dist/hooks/use-form.d.ts.map +1 -1
- package/dist/hooks/use-input-id.d.ts.map +1 -1
- package/dist/hooks/use-preferences.d.ts.map +1 -1
- package/dist/hooks/use-previous.d.ts.map +1 -1
- package/dist/hooks/use-reactive.d.ts.map +1 -1
- package/dist/hooks/use-resize-observer.d.ts.map +1 -1
- package/dist/hooks/use-stable-ref.d.ts.map +1 -1
- package/dist/hooks/use-swipe.d.ts.map +1 -1
- package/dist/hooks/use-translations.d.ts +21 -4
- package/dist/hooks/use-translations.d.ts.map +1 -1
- package/dist/index.css +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +13862 -12512
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +24 -17
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/dom.d.ts +1 -0
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/fns.d.ts.map +1 -1
- package/dist/preset/plugin.tailwind.d.ts +9 -0
- package/dist/preset/plugin.tailwind.d.ts.map +1 -0
- package/dist/preset/plugin.tailwind.js +27 -0
- package/dist/preset/preset.tailwind.d.ts +8 -0
- package/dist/preset/preset.tailwind.d.ts.map +1 -0
- package/dist/preset/preset.tailwind.js +54 -0
- package/dist/preset/src/styles/common.d.ts +2 -14
- package/dist/preset/src/styles/common.d.ts.map +1 -1
- package/dist/preset/src/styles/common.js +1 -0
- package/dist/preset/src/styles/dark.d.ts.map +1 -1
- package/dist/preset/src/styles/dark.js +119 -114
- package/dist/preset/src/styles/light.d.ts.map +1 -1
- package/dist/preset/src/styles/light.js +111 -106
- package/dist/preset/src/styles/theme.types.d.ts +17 -8
- package/dist/preset/src/styles/theme.types.d.ts.map +1 -1
- package/dist/styles/common.d.ts +2 -14
- package/dist/styles/common.d.ts.map +1 -1
- package/dist/styles/dark.d.ts.map +1 -1
- package/dist/styles/light.d.ts.map +1 -1
- package/dist/styles/theme.types.d.ts +17 -8
- package/dist/styles/theme.types.d.ts.map +1 -1
- package/package.json +299 -301
- package/dist/components/core/button.jsx +0 -86
- package/dist/components/core/heading.jsx +0 -4
- package/dist/components/core/polymorph.jsx +0 -5
- package/dist/components/core/render-on-view.jsx +0 -31
- package/dist/components/core/resizable.jsx +0 -51
- package/dist/components/core/slot.jsx +0 -163
- package/dist/components/core/tag.jsx +0 -51
- package/dist/components/core/typography.jsx +0 -26
- package/dist/components/display/alert.jsx +0 -56
- package/dist/components/display/calendar.jsx +0 -301
- package/dist/components/display/card.jsx +0 -43
- package/dist/components/display/empty.jsx +0 -11
- package/dist/components/display/list.jsx +0 -81
- package/dist/components/display/notifications.jsx +0 -98
- package/dist/components/display/progress.jsx +0 -13
- package/dist/components/display/shortcut.jsx +0 -23
- package/dist/components/display/skeleton.jsx +0 -14
- package/dist/components/display/spinner.jsx +0 -7
- package/dist/components/display/stats.jsx +0 -20
- package/dist/components/display/step.jsx +0 -131
- package/dist/components/display/tabs.jsx +0 -100
- package/dist/components/display/timeline.jsx +0 -25
- package/dist/components/floating/command-palette.jsx +0 -172
- package/dist/components/floating/dropdown.jsx +0 -53
- package/dist/components/floating/expand.jsx +0 -44
- package/dist/components/floating/menu.jsx +0 -147
- package/dist/components/floating/modal.jsx +0 -241
- package/dist/components/floating/toolbar.jsx +0 -5
- package/dist/components/floating/tooltip.jsx +0 -64
- package/dist/components/floating/wizard.jsx +0 -164
- package/dist/components/form/autocomplete.jsx +0 -275
- package/dist/components/form/checkbox.jsx +0 -12
- package/dist/components/form/date-picker.jsx +0 -115
- package/dist/components/form/file-upload.jsx +0 -133
- package/dist/components/form/form.jsx +0 -10
- package/dist/components/form/formReset.jsx +0 -17
- package/dist/components/form/free-text.jsx +0 -41
- package/dist/components/form/input-field.jsx +0 -54
- package/dist/components/form/input.jsx +0 -36
- package/dist/components/form/multi-select.jsx +0 -328
- package/dist/components/form/radiobox.jsx +0 -6
- package/dist/components/form/select.jsx +0 -42
- package/dist/components/form/slider.jsx +0 -45
- package/dist/components/form/switch.jsx +0 -46
- package/dist/components/form/task-list.jsx +0 -26
- package/dist/components/form/textarea.jsx +0 -12
- package/dist/components/form/transfer-list.jsx +0 -39
- package/dist/components/index.js +0 -43
- package/dist/components/table/filter.jsx +0 -141
- package/dist/components/table/group.jsx +0 -68
- package/dist/components/table/index.jsx +0 -60
- package/dist/components/table/inner-table.jsx +0 -104
- package/dist/components/table/metadata.jsx +0 -37
- package/dist/components/table/pagination.jsx +0 -73
- package/dist/components/table/row.jsx +0 -58
- package/dist/components/table/sort.jsx +0 -105
- package/dist/components/table/table-lib.js +0 -84
- package/dist/components/table/table.context.jsx +0 -4
- package/dist/components/table/thead.jsx +0 -103
- package/dist/config/context.js +0 -12
- package/dist/config/default-translations.jsx +0 -66
- package/dist/config/default-tweaks.js +0 -4
- package/dist/constants.js +0 -2
- package/dist/hooks/use-click-outside.js +0 -17
- package/dist/hooks/use-color-parser.js +0 -9
- package/dist/hooks/use-components-provider.jsx +0 -16
- package/dist/hooks/use-debounce.js +0 -12
- package/dist/hooks/use-floating-ref.js +0 -6
- package/dist/hooks/use-form.js +0 -549
- package/dist/hooks/use-hover.js +0 -18
- package/dist/hooks/use-input-id.js +0 -5
- package/dist/hooks/use-is-coarse-device.js +0 -12
- package/dist/hooks/use-locale.js +0 -10
- package/dist/hooks/use-media-query.js +0 -25
- package/dist/hooks/use-on-event.js +0 -7
- package/dist/hooks/use-parent.js +0 -21
- package/dist/hooks/use-preferences.js +0 -23
- package/dist/hooks/use-previous.js +0 -8
- package/dist/hooks/use-reactive.js +0 -8
- package/dist/hooks/use-remove-scroll.js +0 -61
- package/dist/hooks/use-resize-observer.js +0 -17
- package/dist/hooks/use-stable-ref.js +0 -8
- package/dist/hooks/use-swipe.js +0 -16
- package/dist/hooks/use-translations.js +0 -9
- package/dist/hooks/use-tweaks.js +0 -9
- package/dist/hooks/use-window-size.js +0 -14
- package/dist/lib/combi-keys.js +0 -60
- package/dist/lib/dict.js +0 -39
- package/dist/lib/dom.js +0 -44
- package/dist/lib/fns.js +0 -46
- package/dist/lib/fzf.js +0 -117
- package/dist/lib/keyboard-area.js +0 -14
- package/dist/preset/tailwindcssv4.d.ts +0 -3
- package/dist/preset/tailwindcssv4.d.ts.map +0 -1
- package/dist/preset/tailwindcssv4.js +0 -75
- package/dist/styles/common.js +0 -28
- package/dist/styles/dark.js +0 -209
- package/dist/styles/design-tokens.js +0 -69
- package/dist/styles/light.js +0 -209
- package/dist/styles/theme.js +0 -4
- package/dist/styles/theme.types.js +0 -1
- package/dist/types.js +0 -1
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { CheckCircle, InfoIcon, XCircle } from "lucide-react";
|
|
3
|
-
import React, { forwardRef, Fragment } from "react";
|
|
4
|
-
import { useTranslations } from "../../hooks/use-translations";
|
|
5
|
-
import { useTweaks } from "../../hooks/use-tweaks";
|
|
6
|
-
import { css } from "../../lib/dom";
|
|
7
|
-
import { Tooltip } from "../floating/tooltip";
|
|
8
|
-
export const InputFeedback = ({ reportStatus, id, hideLeft = false, className, info, children, title }) => (<span className={css("max-w-full justify-between w-fit", hideLeft && children === null ? "hidden" : "flex", className)}>
|
|
9
|
-
{hideLeft ? null : (<span className="flex flex-1 gap-1 items-center transition-colors group-disabled:text-disabled group-error:text-danger group-hover:text-primary group-focus-within:text-primary">
|
|
10
|
-
{title}
|
|
11
|
-
{reportStatus || info ? (<span className="flex gap-1 justify-center items-center">
|
|
12
|
-
{info ? (<Tooltip as="button" type="button" aria-label={typeof info === "string" ? info : undefined} aria-describedby={typeof info === "string" ? undefined : id ? `tooltip-info-content-${id}` : undefined} title={<span className="cursor-help">
|
|
13
|
-
<InfoIcon className="aspect-square size-3" aria-hidden="true" size={16} strokeWidth={1} absoluteStrokeWidth/>
|
|
14
|
-
</span>}>
|
|
15
|
-
<div id={id ? `tooltip-info-content-${id}` : undefined} className="w-full max-w-48 whitespace-break-spaces wrap-break-word">{info}</div>
|
|
16
|
-
</Tooltip>) : null}
|
|
17
|
-
{reportStatus ? (<span className="flex items-center h-3 min-w-6">
|
|
18
|
-
<CheckCircle className="hidden opacity-0 transition-opacity aspect-square size-3 group-assert:block group-assert:text-success group-assert:opacity-100" aria-hidden="true" size={16} strokeWidth={1} absoluteStrokeWidth/>
|
|
19
|
-
<XCircle className="hidden opacity-0 transition-opacity aspect-square size-3 group-error:block group-error:opacity-100" aria-hidden="true" size={16} strokeWidth={1} absoluteStrokeWidth/>
|
|
20
|
-
</span>) : null}
|
|
21
|
-
</span>) : null}
|
|
22
|
-
</span>)}
|
|
23
|
-
{children}
|
|
24
|
-
</span>);
|
|
25
|
-
export const InputField = forwardRef(({ optionalText: _optionalText, left, rightLabel, container, feedback, interactive, right, info, children, error, form, id, labelClassName = "", name, title, componentName, placeholder, hideLeft = false, required, disabled, reportStatus, }, ref) => {
|
|
26
|
-
const tweaks = useTweaks();
|
|
27
|
-
const reportStatusDefault = reportStatus !== undefined ? reportStatus : tweaks.input.iconFeedback;
|
|
28
|
-
const ID = id ?? name;
|
|
29
|
-
const translation = useTranslations();
|
|
30
|
-
const optionalText = _optionalText ?? translation.inputOptionalLabel;
|
|
31
|
-
return (<fieldset ref={ref} form={form} disabled={disabled} data-error={!!error} aria-disabled={disabled} data-component={componentName} data-interactive={!!interactive} className={css("group flex min-h-0 max-w-full min-w-0 flex-col items-start", container)}>
|
|
32
|
-
<label form={form} htmlFor={ID} className="inline-flex relative flex-row flex-wrap gap-1 justify-between w-full max-w-full text-sm transition-colors cursor-text empty:hidden text-field-label group-disabled:cursor-not-allowed group-error:text-danger">
|
|
33
|
-
<InputFeedback info={info} hideLeft={hideLeft} reportStatus={reportStatusDefault} title={title} placeholder={placeholder}>
|
|
34
|
-
{optionalText || rightLabel ? (<Fragment>
|
|
35
|
-
{!required ? (<span aria-disabled={disabled} className="text-opacity-70 transition-colors aria-disabled:text-disabled group-hover:text-primary group-focus-within:text-primary">
|
|
36
|
-
{optionalText}
|
|
37
|
-
</span>) : null}
|
|
38
|
-
{rightLabel ? <Fragment>{rightLabel}</Fragment> : null}
|
|
39
|
-
</Fragment>) : null}
|
|
40
|
-
</InputFeedback>
|
|
41
|
-
<div className={`group relative flex w-full flex-row flex-nowrap items-center gap-x-2 gap-y-1 rounded-md border border-input-border bg-transparent transition-colors group-hover:border-primary group-disabled:border-disabled group-error:border-danger ${labelClassName}`}>
|
|
42
|
-
{left ? <span className="flex flex-nowrap gap-1 pl-2 whitespace-nowrap">{left}</span> : null}
|
|
43
|
-
{children}
|
|
44
|
-
{right ? <span className="flex flex-nowrap gap-2 pr-2 whitespace-nowrap">{right}</span> : null}
|
|
45
|
-
</div>
|
|
46
|
-
</label>
|
|
47
|
-
<p className="mt-input-gap hidden whitespace-pre-wrap text-wrap text-xs empty:mt-0 empty:hidden group-has-[input:not(:focus):invalid[data-initialized=true]]:flex group-error:flex group-error:text-danger">
|
|
48
|
-
{error}
|
|
49
|
-
</p>
|
|
50
|
-
<p className="mt-input-gap text-xs empty:mt-0 empty:hidden group-has-[input:not(:focus):valid[data-initialized=true]]:block group-assert:block group-error:hidden">
|
|
51
|
-
{feedback}
|
|
52
|
-
</p>
|
|
53
|
-
</fieldset>);
|
|
54
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import MaskInput from "the-mask-input";
|
|
3
|
-
import { createFreeText } from "./free-text";
|
|
4
|
-
/**
|
|
5
|
-
* A text input component with advanced masking capabilities.
|
|
6
|
-
*
|
|
7
|
-
* Supports various input masks including:
|
|
8
|
-
* - Currency formatting with locale support
|
|
9
|
-
* - Percentage inputs
|
|
10
|
-
* - Custom regex patterns
|
|
11
|
-
* - Phone numbers, dates, and other formatted inputs
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```tsx
|
|
15
|
-
* // Basic input
|
|
16
|
-
* <Input placeholder="Enter text..." />
|
|
17
|
-
*
|
|
18
|
-
* // Phone number mask
|
|
19
|
-
* <Input mask="(99) 99999-9999" placeholder="Phone" />
|
|
20
|
-
*
|
|
21
|
-
* // Currency input
|
|
22
|
-
* <Input mask="currency" currency="USD" locale="en-US" />
|
|
23
|
-
*
|
|
24
|
-
* // Percentage input
|
|
25
|
-
* <Input mask="percentage" />
|
|
26
|
-
*
|
|
27
|
-
* // Custom mask
|
|
28
|
-
* <Input mask={["999.999.999-99"]} placeholder="CPF" />
|
|
29
|
-
* ```
|
|
30
|
-
*
|
|
31
|
-
* @param props - Input props including mask, validation, and styling options
|
|
32
|
-
* @returns A masked input component with form integration
|
|
33
|
-
*/
|
|
34
|
-
export const Input = createFreeText(MaskInput, "input", {
|
|
35
|
-
type: "text",
|
|
36
|
-
});
|
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { autoUpdate, FloatingFocusManager, FloatingOverlay, FloatingPortal, offset, size, useDismiss, useFloating, useInteractions, useListNavigation, useRole, useTransitionStyles, } from "@floating-ui/react";
|
|
3
|
-
import { ChevronDown, XIcon } from "lucide-react";
|
|
4
|
-
import { AnimatePresence, motion } from "motion/react";
|
|
5
|
-
import React, { forwardRef, Fragment, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
-
import { flushSync } from "react-dom";
|
|
7
|
-
import { Virtuoso } from "react-virtuoso";
|
|
8
|
-
import { useRemoveScroll } from "../../hooks/use-remove-scroll";
|
|
9
|
-
import { useTranslations } from "../../hooks/use-translations";
|
|
10
|
-
import { Dict } from "../../lib/dict";
|
|
11
|
-
import { css, getRemainingSize, initializeInputDataset } from "../../lib/dom";
|
|
12
|
-
import { noop } from "../../lib/fns";
|
|
13
|
-
import { fzf } from "../../lib/fzf";
|
|
14
|
-
import { Tag } from "../core/tag";
|
|
15
|
-
import { Checkbox } from "./checkbox";
|
|
16
|
-
import { InputField } from "./input-field";
|
|
17
|
-
const MIN_SIZE = 40;
|
|
18
|
-
const Frag = (props) => <Fragment>{props.children}</Fragment>;
|
|
19
|
-
const transitionStyles = {
|
|
20
|
-
duration: 300,
|
|
21
|
-
initial: { transform: "scaleY(0)", opacity: 0.2 },
|
|
22
|
-
open: { transform: "scaleY(1)", opacity: 1 },
|
|
23
|
-
close: { transform: "scaleY(0)", opacity: 0 },
|
|
24
|
-
};
|
|
25
|
-
const emptyRef = [];
|
|
26
|
-
const List = forwardRef(function VirtualList(props, ref) {
|
|
27
|
-
return (<motion.ul {...props} role="listbox" ref={ref} className="w-full rounded-b-lg border-b last:border-transparent border-tooltip-border">
|
|
28
|
-
<AnimatePresence>{props.children}</AnimatePresence>
|
|
29
|
-
</motion.ul>);
|
|
30
|
-
});
|
|
31
|
-
const Item = forwardRef(function VirtualItem({ item, context, ...props }, ref) {
|
|
32
|
-
return <motion.li {...props} ref={ref} className="last:rounded-t-lg"/>;
|
|
33
|
-
});
|
|
34
|
-
const components = { List, Item };
|
|
35
|
-
const OverflowControl = (props) => {
|
|
36
|
-
const translate = useTranslations();
|
|
37
|
-
const ref = useRef(null);
|
|
38
|
-
const countable = React.Children.count(props.children);
|
|
39
|
-
const [normalView, setNormalView] = useState(false);
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (ref.current === null)
|
|
42
|
-
return;
|
|
43
|
-
const parent = ref.current.parentElement.getBoundingClientRect();
|
|
44
|
-
const items = Array.from(ref.current.querySelectorAll("[data-component='tag']"));
|
|
45
|
-
const child = items.reduce((acc, el) => acc + el.getBoundingClientRect().width, 0);
|
|
46
|
-
const hasOnlyCounter = ref.current.querySelectorAll("[data-multicounter]").length;
|
|
47
|
-
if (hasOnlyCounter && countable <= 3)
|
|
48
|
-
return setNormalView(false);
|
|
49
|
-
if (child > parent.width)
|
|
50
|
-
return setNormalView(true);
|
|
51
|
-
}, [countable]);
|
|
52
|
-
return (<span ref={ref} className="flex flex-nowrap gap-x-2">
|
|
53
|
-
{!normalView ? (props.children) : (<Tag size="small" data-multicounter="true">
|
|
54
|
-
{countable} {translate.multiSelectSelectedLabel}
|
|
55
|
-
</Tag>)}
|
|
56
|
-
</span>);
|
|
57
|
-
};
|
|
58
|
-
export const MultiSelect = forwardRef(({ left, error, right, options, container, rightLabel, interactive, emptyMessage, optionalText, selectedLabel, labelClassName, feedback = null, hideLeft = false, required = false, dynamicOption = false, onChangeOptions, ...props }, externalRef) => {
|
|
59
|
-
const map = useMemo(() => new Dict(options.map((x) => [x.value, x])), [options]);
|
|
60
|
-
const fieldset = useRef(null);
|
|
61
|
-
const virtuoso = useRef(null);
|
|
62
|
-
const defaults = props.value ?? props.defaultValue ?? emptyRef;
|
|
63
|
-
const translation = useTranslations();
|
|
64
|
-
const [h, setH] = useState(0);
|
|
65
|
-
const [open, setOpen] = useState(false);
|
|
66
|
-
const [shadow, setShadow] = useState("");
|
|
67
|
-
const [value, setValue] = useState(() => {
|
|
68
|
-
const d = new Dict();
|
|
69
|
-
defaults.forEach((x) => {
|
|
70
|
-
const result = map.get(x);
|
|
71
|
-
return result ? d.set(x, result) : undefined;
|
|
72
|
-
});
|
|
73
|
-
return d;
|
|
74
|
-
});
|
|
75
|
-
const values = useMemo(() => Array.from(value.keys()), [value]);
|
|
76
|
-
const [label, setLabel] = useState(() => {
|
|
77
|
-
const d = new Set(defaults);
|
|
78
|
-
return options.reduce((acc, x) => (d.has(x.value) ? [...acc, x.label ?? x.value] : acc), []) ?? defaults;
|
|
79
|
-
});
|
|
80
|
-
const [index, setIndex] = useState(null);
|
|
81
|
-
const listRef = useRef(emptyRef);
|
|
82
|
-
const innerOptions = dynamicOption && shadow !== ""
|
|
83
|
-
? [
|
|
84
|
-
{
|
|
85
|
-
value: shadow,
|
|
86
|
-
label: shadow,
|
|
87
|
-
"data-dynamic": "true",
|
|
88
|
-
},
|
|
89
|
-
...options,
|
|
90
|
-
]
|
|
91
|
-
: options;
|
|
92
|
-
const list = shadow.length === 0
|
|
93
|
-
? innerOptions
|
|
94
|
-
: fzf(innerOptions, "value", [
|
|
95
|
-
{ key: "value", value: shadow },
|
|
96
|
-
{ key: "label", value: shadow },
|
|
97
|
-
]);
|
|
98
|
-
const removeScrollRef = useRemoveScroll(open, "block-only");
|
|
99
|
-
const displayList = list.filter((x) => x.hidden !== true);
|
|
100
|
-
const isEmpty = displayList.length === 0;
|
|
101
|
-
const { x, y, strategy, refs, context } = useFloating({
|
|
102
|
-
open,
|
|
103
|
-
transform: true,
|
|
104
|
-
placement: "bottom-start",
|
|
105
|
-
strategy: "absolute",
|
|
106
|
-
onOpenChange: setOpen,
|
|
107
|
-
whileElementsMounted: autoUpdate,
|
|
108
|
-
middleware: [
|
|
109
|
-
offset(4),
|
|
110
|
-
size({
|
|
111
|
-
padding: 10,
|
|
112
|
-
elementContext: "reference",
|
|
113
|
-
apply(args) {
|
|
114
|
-
const ul = args.elements.floating.querySelector("ul");
|
|
115
|
-
const fullSize = ul?.getBoundingClientRect().height || 0;
|
|
116
|
-
const DEFAULT_SIZE = getRemainingSize(refs.reference.current, window.innerHeight);
|
|
117
|
-
const maxH = Math.min(fullSize < MIN_SIZE ? DEFAULT_SIZE : fullSize, DEFAULT_SIZE, args.availableHeight);
|
|
118
|
-
const size = displayList.length === 0 ? MIN_SIZE : Math.min(maxH, DEFAULT_SIZE, fullSize);
|
|
119
|
-
const mw = `${fieldset.current.getBoundingClientRect().width}px`;
|
|
120
|
-
Object.assign(args.elements.floating.style, { width: mw, maxWidth: mw, height: size });
|
|
121
|
-
},
|
|
122
|
-
}),
|
|
123
|
-
],
|
|
124
|
-
});
|
|
125
|
-
const transitions = useTransitionStyles(context, transitionStyles);
|
|
126
|
-
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
|
127
|
-
useRole(context, { role: "listbox" }),
|
|
128
|
-
useDismiss(context),
|
|
129
|
-
useListNavigation(context, {
|
|
130
|
-
cols: 0,
|
|
131
|
-
listRef,
|
|
132
|
-
loop: true,
|
|
133
|
-
virtual: true,
|
|
134
|
-
allowEscape: true,
|
|
135
|
-
activeIndex: index,
|
|
136
|
-
selectedIndex: index,
|
|
137
|
-
focusItemOnOpen: "auto",
|
|
138
|
-
openOnArrowKeyDown: true,
|
|
139
|
-
scrollItemIntoView: true,
|
|
140
|
-
onNavigate: (n) => setIndex((prev) => n ?? prev),
|
|
141
|
-
}),
|
|
142
|
-
]);
|
|
143
|
-
useEffect(() => {
|
|
144
|
-
if (!open)
|
|
145
|
-
return setH(0);
|
|
146
|
-
const inputRef = refs.reference;
|
|
147
|
-
if (inputRef.current === null)
|
|
148
|
-
return;
|
|
149
|
-
const s = getRemainingSize(inputRef.current, window.innerHeight);
|
|
150
|
-
setTimeout(() => setH(Math.min(s, displayList.length * 40)), 100);
|
|
151
|
-
}, [shadow, open, refs.reference]);
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
if (props.value) {
|
|
154
|
-
setValue(new Dict(props.value.map((x) => [x, map.get(x)])));
|
|
155
|
-
}
|
|
156
|
-
}, [props.value, map]);
|
|
157
|
-
useEffect(() => {
|
|
158
|
-
const input = refs.reference.current;
|
|
159
|
-
if (!input)
|
|
160
|
-
return;
|
|
161
|
-
return initializeInputDataset(input);
|
|
162
|
-
}, []);
|
|
163
|
-
const onSelect = (opt, i) => {
|
|
164
|
-
const clone = value.clone((c) => {
|
|
165
|
-
if (c.has(opt.value))
|
|
166
|
-
return c.remove(opt.value);
|
|
167
|
-
return c.set(opt.value, opt);
|
|
168
|
-
});
|
|
169
|
-
setValue(clone);
|
|
170
|
-
const input = refs.reference.current;
|
|
171
|
-
if (!input)
|
|
172
|
-
return;
|
|
173
|
-
const options = clone.map((x) => x.value);
|
|
174
|
-
input?.setAttribute("data-value", JSON.stringify(options));
|
|
175
|
-
if (onChangeOptions)
|
|
176
|
-
onChangeOptions(options);
|
|
177
|
-
setLabel((prev) => prev.concat(opt.label ?? ""));
|
|
178
|
-
setShadow("");
|
|
179
|
-
setIndex(i);
|
|
180
|
-
};
|
|
181
|
-
const onChange = (event) => {
|
|
182
|
-
const value = event.target.value;
|
|
183
|
-
setShadow(value);
|
|
184
|
-
if (!open && value === "")
|
|
185
|
-
return setOpen(true);
|
|
186
|
-
event.target.name = props.name || "";
|
|
187
|
-
return value ? setOpen(true) : undefined;
|
|
188
|
-
};
|
|
189
|
-
const onCaretDownClick = () => {
|
|
190
|
-
setOpen(true);
|
|
191
|
-
setShadow("");
|
|
192
|
-
refs.reference.current?.focus();
|
|
193
|
-
};
|
|
194
|
-
const onFocus = () => {
|
|
195
|
-
setOpen(true);
|
|
196
|
-
setShadow("");
|
|
197
|
-
};
|
|
198
|
-
const onClose = () => {
|
|
199
|
-
refs.reference.current?.setAttribute("data-value", "[]");
|
|
200
|
-
setShadow("");
|
|
201
|
-
setOpen(false);
|
|
202
|
-
setValue(new Dict());
|
|
203
|
-
onChangeOptions?.([]);
|
|
204
|
-
};
|
|
205
|
-
const id = props.id || props.name;
|
|
206
|
-
const tags = value.map((x, i) => (<Tag size="small" key={`MultiSelect-${x.value}-x`} icon={<button type="button" className="text-current hover:text-danger focus:text-danger" onClick={(e) => {
|
|
207
|
-
e.preventDefault();
|
|
208
|
-
e.stopPropagation();
|
|
209
|
-
onSelect(x, i);
|
|
210
|
-
}}>
|
|
211
|
-
<XIcon size={14}/>
|
|
212
|
-
</button>}>
|
|
213
|
-
{x.label ?? x.value}
|
|
214
|
-
</Tag>));
|
|
215
|
-
const scrollableContainerStyle = { height: isEmpty ? "0" : value.size === 0 ? h - 49 : h - 86 };
|
|
216
|
-
return (<InputField {...props} left={left} error={error} ref={fieldset} form={props.form} name={props.name} feedback={feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} rightLabel={rightLabel} interactive={interactive} id={props.name || props.id} optionalText={optionalText} componentName="autocomplete" labelClassName={labelClassName} placeholder={props.placeholder} right={<span className="flex gap-0.5 items-center">
|
|
217
|
-
{right}
|
|
218
|
-
<button type="button" className="transition-colors link:text-primary" onClick={onCaretDownClick}>
|
|
219
|
-
<ChevronDown size={20}/>
|
|
220
|
-
<span className="sr-only">{translation.inputCaretDown}</span>
|
|
221
|
-
</button>
|
|
222
|
-
{value ? (<button type="button" onClick={onClose} className="transition-colors link:text-danger">
|
|
223
|
-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
224
|
-
<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"/>
|
|
225
|
-
</svg>
|
|
226
|
-
</button>) : null}
|
|
227
|
-
</span>}>
|
|
228
|
-
<ul {...getReferenceProps({
|
|
229
|
-
...props,
|
|
230
|
-
onFocus,
|
|
231
|
-
id: `${id}-shadow`,
|
|
232
|
-
name: `${id}-shadow`,
|
|
233
|
-
ref: refs.setReference,
|
|
234
|
-
})} tabIndex={0} role="button" data-name={id} data-target={id} data-shadow="true" data-error={!!error} aria-autocomplete="list" data-value={values.join(",")} className={css("input text-base placeholder-input-mask group h-input-height w-full", "rounded-md bg-transparent px-input-x py-input-y text-foreground", "outline-hidden transition-colors focus:ring-2 focus:ring-inset focus:ring-primary", "group-error:text-danger group-error:placeholder-input-mask-error", "group-focus-within:border-primary group-hover:border-primary", "flex flex-row items-center gap-2 whitespace-nowrap text-left", "max-w-full overflow-x-auto truncate text-ellipsis", props.className)}>
|
|
235
|
-
{values.length > 0 ? null : <li className="text-input-placeholder">{props.placeholder}</li>}
|
|
236
|
-
<OverflowControl label={selectedLabel}>{tags}</OverflowControl>
|
|
237
|
-
</ul>
|
|
238
|
-
<input id={id} name={id} type="hidden" data-origin={id} ref={externalRef} required={required} defaultValue={props.value || values || undefined}/>
|
|
239
|
-
<FloatingPortal preserveTabOrder>
|
|
240
|
-
{open ? (<FloatingOverlay lockScroll>
|
|
241
|
-
<FloatingFocusManager modal guards returnFocus={false} context={context} initialFocus={-1} visuallyHiddenDismiss>
|
|
242
|
-
<div {...getFloatingProps({
|
|
243
|
-
ref: refs.setFloating,
|
|
244
|
-
style: {
|
|
245
|
-
...transitions.styles,
|
|
246
|
-
top: y ?? 0,
|
|
247
|
-
position: strategy,
|
|
248
|
-
left: x,
|
|
249
|
-
height: h - (values.length === 0 ? 65 : 30),
|
|
250
|
-
},
|
|
251
|
-
})} data-floating="true" className="overscroll-contain p-0 m-0 w-full max-h-96 list-none rounded-t-lg rounded-b-lg border shadow-floating isolate z-floating origin-[top_center] border-floating-border bg-floating-background text-foreground">
|
|
252
|
-
<input autoFocus value={shadow} onChange={onChange} title={props.title} placeholder={translation.multiSelectInnerPlaceholder} className="flex-1 mb-1 w-full h-10 bg-transparent rounded-sm border-b transition-colors outline-hidden focus:ring-2 focus:ring-inset input placeholder-input-mask group border-input-border px-input-x py-input-y focus:ring-primary" onKeyDown={(event) => {
|
|
253
|
-
if (event.key === "ArrowDown") {
|
|
254
|
-
let next = index + 1;
|
|
255
|
-
if (next > displayList.length - 1)
|
|
256
|
-
next = 0;
|
|
257
|
-
virtuoso.current?.scrollIntoView({ index: next });
|
|
258
|
-
return setIndex(next);
|
|
259
|
-
}
|
|
260
|
-
if (event.key === "ArrowUp") {
|
|
261
|
-
let next = index - 1;
|
|
262
|
-
if (next < 0)
|
|
263
|
-
next = displayList.length - 1;
|
|
264
|
-
virtuoso.current?.scrollIntoView({ index: next });
|
|
265
|
-
return setIndex(next);
|
|
266
|
-
}
|
|
267
|
-
if (event.key === "Escape") {
|
|
268
|
-
event.currentTarget.blur();
|
|
269
|
-
return setOpen(false);
|
|
270
|
-
}
|
|
271
|
-
if (event.key === "Enter") {
|
|
272
|
-
if (index !== null && displayList[index]) {
|
|
273
|
-
event.preventDefault();
|
|
274
|
-
return onSelect(displayList[index], index);
|
|
275
|
-
}
|
|
276
|
-
if (displayList.length === 1) {
|
|
277
|
-
event.preventDefault();
|
|
278
|
-
return onSelect(displayList[0], 0);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}}/>
|
|
282
|
-
{isEmpty ? (<li role="option" className="w-full border-b last:border-transparent border-tooltip-border">
|
|
283
|
-
<span className="flex justify-between p-2 w-full text-left text-disabled">
|
|
284
|
-
{emptyMessage || translation.autocompleteEmpty}
|
|
285
|
-
</span>
|
|
286
|
-
</li>) : null}
|
|
287
|
-
{isEmpty ? null : (<motion.div initial={false} data-floating="true" ref={removeScrollRef} animate={{ height: isEmpty ? "auto" : h }} style={scrollableContainerStyle} className="overscroll-contain w-full max-h-72" onAnimationComplete={() => {
|
|
288
|
-
if (!open)
|
|
289
|
-
return setH(0);
|
|
290
|
-
const ul = refs.floating.current;
|
|
291
|
-
const li = ul.querySelectorAll("li").item(0);
|
|
292
|
-
const sum = (li ? li.getBoundingClientRect().height : 40) * displayList.length;
|
|
293
|
-
return flushSync(() => setH(sum + 2));
|
|
294
|
-
}}>
|
|
295
|
-
<Virtuoso ref={virtuoso} hidden={isEmpty} data={displayList} components={components} style={scrollableContainerStyle} className="p-0 max-h-72 border-floating-border bg-floating-background text-foreground" itemContent={(i, option) => {
|
|
296
|
-
const Label = option.Render ?? Frag;
|
|
297
|
-
const active = value.has(option.value) || value.has(option.label ?? "");
|
|
298
|
-
const selected = index === i;
|
|
299
|
-
const children = option.label ?? option.value;
|
|
300
|
-
return (<button data-value={option.value} {...getItemProps({
|
|
301
|
-
ref: (node) => void (listRef.current[i] = node),
|
|
302
|
-
role: "option",
|
|
303
|
-
type: "button",
|
|
304
|
-
"aria-checked": active,
|
|
305
|
-
"aria-current": active,
|
|
306
|
-
"aria-selected": active,
|
|
307
|
-
"aria-busy": option.disabled,
|
|
308
|
-
onClick: () => onSelect(option, i),
|
|
309
|
-
})} className={`flex w-full max-w-full cursor-pointer items-center justify-start p-2 text-left hover:bg-floating-hover focus:bg-floating-hover ${active || selected ? "bg-floating-hover text-floating-foreground" : ""}`}>
|
|
310
|
-
<Checkbox onChange={noop} checked={active} aria-checked={active} onClick={(e) => {
|
|
311
|
-
e.stopPropagation();
|
|
312
|
-
onSelect(option, i);
|
|
313
|
-
}}/>
|
|
314
|
-
<Label {...props} label={option.label} value={option.value} children={children}/>
|
|
315
|
-
</button>);
|
|
316
|
-
}}/>
|
|
317
|
-
</motion.div>)}
|
|
318
|
-
<div className="flex overflow-x-auto sticky bottom-0 flex-nowrap gap-2 items-center p-2 w-full rounded-b-lg bg-floating-background">
|
|
319
|
-
{value.size === 0 ? (<Tag theme="muted" size="small">
|
|
320
|
-
{translation.autocompleteEmpty}
|
|
321
|
-
</Tag>) : (tags)}
|
|
322
|
-
</div>
|
|
323
|
-
</div>
|
|
324
|
-
</FloatingFocusManager>
|
|
325
|
-
</FloatingOverlay>) : null}
|
|
326
|
-
</FloatingPortal>
|
|
327
|
-
</InputField>);
|
|
328
|
-
});
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { css } from "../../lib/dom";
|
|
3
|
-
export const Radiobox = ({ children, className = "", size, ...props }) => (<label data-component="radiobox" data-disabled={props.disabled} aria-disabled={props.disabled} className="group flex items-center gap-2 font-normal data-[disabled=true]:cursor-not-allowed">
|
|
4
|
-
<input {...props} type="radio" className={css("app form-radio inline-block h-4 w-4 appearance-none rounded-full border-card-border bg-origin-border text-primary focus:ring-primary disabled:opacity-70 group-aria-disabled:cursor-not-allowed", className)} {...props}/>
|
|
5
|
-
{children}
|
|
6
|
-
</label>);
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { ChevronDownIcon } from "lucide-react";
|
|
3
|
-
import React, { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
|
|
4
|
-
import { useTranslations } from "../../hooks/use-translations";
|
|
5
|
-
import { css, initializeInputDataset, mergeRefs } from "../../lib/dom";
|
|
6
|
-
import { InputField } from "./input-field";
|
|
7
|
-
export const Select = forwardRef(({ required = true, options, info, selectContainer = "", feedback = null, labelClassName, interactive, rightLabel, loading, optionalText, container, hideLeft = false, right, left, error, ...props }, ref) => {
|
|
8
|
-
const translation = useTranslations();
|
|
9
|
-
const inputRef = useRef(null);
|
|
10
|
-
const id = props.id ?? props.name;
|
|
11
|
-
useImperativeHandle(ref, () => inputRef.current);
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
if (inputRef.current === null)
|
|
14
|
-
return;
|
|
15
|
-
const controller = new AbortController();
|
|
16
|
-
const input = inputRef.current;
|
|
17
|
-
const focus = initializeInputDataset(inputRef.current);
|
|
18
|
-
input.addEventListener("change", () => input.setAttribute("data-selected", "true"), {
|
|
19
|
-
once: true,
|
|
20
|
-
signal: controller.signal,
|
|
21
|
-
});
|
|
22
|
-
return () => {
|
|
23
|
-
focus();
|
|
24
|
-
controller.abort();
|
|
25
|
-
};
|
|
26
|
-
}, []);
|
|
27
|
-
const onClickLabel = () => inputRef.current?.focus();
|
|
28
|
-
return (<InputField info={info} left={left} error={error} form={props.form} loading={loading} name={props.name} feedback={feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} componentName="select" rightLabel={rightLabel} interactive={interactive} id={props.name || props.id} optionalText={optionalText} labelClassName={labelClassName} placeholder={props.placeholder} right={<label htmlFor={id}>
|
|
29
|
-
{right}
|
|
30
|
-
<button onClick={onClickLabel} type="button" className="mt-2 transition-colors hover:text-primary">
|
|
31
|
-
<ChevronDownIcon size={20}/>
|
|
32
|
-
<span className="sr-only">{translation.inputCaretDown}</span>
|
|
33
|
-
</button>
|
|
34
|
-
</label>}>
|
|
35
|
-
<select {...props} id={id} name={id} required={required} ref={mergeRefs(ref, inputRef)} data-selected={!!props.value || false} title={typeof props.title === "string" ? props.title : undefined} className={css("input select group text-base h-10 w-full flex-1 appearance-none rounded-md", "bg-transparent px-2 py-1 text-foreground placeholder-input-placeholder", "outline-hidden transition-colors group-error:text-danger group-error:placeholder-input-mask-error", "data-[selected=false]:text-input-placeholder", props.className)}>
|
|
36
|
-
<option value="" disabled hidden>
|
|
37
|
-
{props.placeholder}
|
|
38
|
-
</option>
|
|
39
|
-
{options.map((option) => (<option {...option} value={option.value} children={option.label ?? option.value} key={`${id}-select-option-${option.value}`}/>))}
|
|
40
|
-
</select>
|
|
41
|
-
</InputField>);
|
|
42
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { Slider as Base } from "@base-ui/react/slider";
|
|
3
|
-
import { Is } from "sidekicker";
|
|
4
|
-
import { css } from "../../lib/dom";
|
|
5
|
-
import { Tooltip } from "../floating/tooltip";
|
|
6
|
-
import { useEffect, useRef, useState } from "react";
|
|
7
|
-
import { uuid } from "../../lib/fns";
|
|
8
|
-
import { useLocale } from "../../hooks/use-locale";
|
|
9
|
-
const Thumb = (props) => {
|
|
10
|
-
const [float, setFloat] = useState(null);
|
|
11
|
-
const ref = useRef(null);
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
const html = ref.current;
|
|
14
|
-
if (html === null)
|
|
15
|
-
return;
|
|
16
|
-
const initialValue = Number(html.getAttribute("aria-valuenow"));
|
|
17
|
-
if (Is.number(initialValue)) {
|
|
18
|
-
setFloat(initialValue);
|
|
19
|
-
}
|
|
20
|
-
const observer = new MutationObserver((changes) => {
|
|
21
|
-
const span = changes[0].target;
|
|
22
|
-
const value = Number(span.getAttribute("aria-valuenow"));
|
|
23
|
-
setFloat(Is.number(value) ? value : null);
|
|
24
|
-
});
|
|
25
|
-
observer.observe(html, { attributeFilter: ["aria-valuenow"] });
|
|
26
|
-
return () => observer.disconnect();
|
|
27
|
-
}, []);
|
|
28
|
-
return (<Tooltip title="" ref={ref} as={Base.Thumb} enabled={props.tooltip} className="block rounded-full focus-within:border-primary focus-within::scale-105 bg-input-switch size-5 cursor-grab border-2 border-input-border shadow-shadow-floating focus-within:outline-solid active:cursor-grabbing">
|
|
29
|
-
{float}
|
|
30
|
-
</Tooltip>);
|
|
31
|
-
};
|
|
32
|
-
export const Slider = (props) => {
|
|
33
|
-
const { tooltip, className, defaultValue, value, ...restProps } = props;
|
|
34
|
-
const id = useRef(uuid());
|
|
35
|
-
const array = defaultValue || value || [];
|
|
36
|
-
const locale = useLocale();
|
|
37
|
-
return (<Base.Root {...restProps} value={value} locale={locale} defaultValue={defaultValue}>
|
|
38
|
-
<Base.Control className={css("relative flex h-5 w-full touch-none select-none items-center", className)}>
|
|
39
|
-
<Base.Track className="relative h-2 rounded-full grow bg-background">
|
|
40
|
-
<Base.Indicator className="absolute h-full rounded-full bg-primary"/>
|
|
41
|
-
</Base.Track>
|
|
42
|
-
{Array.isArray(array) ? array.map((_, i) => (<Thumb tooltip={tooltip ?? false} key={`${id.current}-${i}`}/>)) : null}
|
|
43
|
-
</Base.Control>
|
|
44
|
-
</Base.Root>);
|
|
45
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React, { forwardRef, useEffect, useId, useImperativeHandle, useRef, useState } from "react";
|
|
3
|
-
import { useStableRef } from "../../hooks/use-stable-ref";
|
|
4
|
-
import { css } from "../../lib/dom";
|
|
5
|
-
export const Switch = forwardRef(({ children, loading, container, error, ...props }, ref) => {
|
|
6
|
-
const id = useId();
|
|
7
|
-
const [innerChecked, setInnerChecked] = useState(props.checked ?? false);
|
|
8
|
-
const checked = innerChecked;
|
|
9
|
-
const innerRef = useRef(null);
|
|
10
|
-
const stableOnChange = useStableRef(props.onChange);
|
|
11
|
-
useImperativeHandle(ref, () => innerRef.current);
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
if (innerRef.current !== null) {
|
|
14
|
-
if (stableOnChange.current) {
|
|
15
|
-
const onChange = (e) => {
|
|
16
|
-
if (stableOnChange.current)
|
|
17
|
-
stableOnChange.current(e);
|
|
18
|
-
};
|
|
19
|
-
const ref = innerRef.current;
|
|
20
|
-
ref.addEventListener("change", onChange);
|
|
21
|
-
return () => ref?.removeEventListener("change", onChange);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}, []);
|
|
25
|
-
const onCheck = () => {
|
|
26
|
-
const checked = !innerRef.current?.checked;
|
|
27
|
-
setInnerChecked(checked);
|
|
28
|
-
props?.onCheck?.(checked);
|
|
29
|
-
if (innerRef.current !== null) {
|
|
30
|
-
innerRef.current.checked = checked;
|
|
31
|
-
innerRef.current.dispatchEvent(new Event("change", { bubbles: true }));
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
return (<fieldset className={css("flex flex-col flex-wrap justify-center", container)} data-component="switch" disabled={props.disabled || loading}>
|
|
35
|
-
<span className="flex flex-row flex-wrap items-center">
|
|
36
|
-
<input {...props} hidden ref={innerRef} type="checkbox" checked={checked} id={props.id || id} data-trigger="change" data-checked={checked} disabled={props.disabled || loading} onChange={(e) => setInnerChecked(e.target.checked)}/>
|
|
37
|
-
<button type="button" role="switch" onClick={onCheck} aria-checked={checked} data-checked={checked} aria-labelledby={`${id}-label`} disabled={props.disabled || loading} className="relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-300 ease-in-out focus:outline-hidden focus:ring-2 focus:ring-primary focus:ring-offset-2 data-[checked=false]:bg-input-switch-bg data-[checked=true]:bg-primary">
|
|
38
|
-
<span aria-hidden="true" data-checked={checked} className="inline-block aspect-square size-5 transform rounded-full shadow-sm ring-0 transition duration-300 ease-in-out data-[checked=false]:translate-x-0 data-[checked=true]:translate-x-5 data-[checked=false]:bg-disabled data-[checked=true]:bg-input-switch"/>
|
|
39
|
-
</button>
|
|
40
|
-
<label htmlFor={props.id || id} className="ml-3 inline-block text-sm" id={`${id}-label`}>
|
|
41
|
-
<span className="font-medium text-foreground">{children}</span>
|
|
42
|
-
</label>
|
|
43
|
-
</span>
|
|
44
|
-
<span className="mt-1 flex-1 whitespace-nowrap text-xs text-danger empty:mt-0 empty:hidden">{error}</span>
|
|
45
|
-
</fieldset>);
|
|
46
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { stagger, useAnimate } from "motion/react";
|
|
3
|
-
import { useEffect } from "react";
|
|
4
|
-
export const TaskList = (props) => {
|
|
5
|
-
const [ref, animate] = useAnimate();
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
const container = ref.current;
|
|
8
|
-
if (!container)
|
|
9
|
-
return;
|
|
10
|
-
const handler = (e) => {
|
|
11
|
-
const input = e.target;
|
|
12
|
-
const items = Array.from(container.querySelectorAll("input[data-task=true]"));
|
|
13
|
-
const allTaskChecked = items.every((el) => el.checked);
|
|
14
|
-
const index = items.indexOf(input);
|
|
15
|
-
if (allTaskChecked && index !== -1) {
|
|
16
|
-
animate("input", { scale: [1, 1.35, 1], rotate: [0, 20, -20, 0] }, {
|
|
17
|
-
duration: 0.5,
|
|
18
|
-
delay: stagger(0.075, { from: index }),
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
container.addEventListener("change", handler);
|
|
23
|
-
return () => container.removeEventListener("change", handler);
|
|
24
|
-
}, []);
|
|
25
|
-
return <fieldset {...props} data-component="task-list" ref={ref}/>;
|
|
26
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { createFreeText } from "./free-text";
|
|
3
|
-
export const Textarea = createFreeText("textarea", "textarea", { container: "w-full" }, (textarea) => {
|
|
4
|
-
const adjustHeight = () => {
|
|
5
|
-
const lineBreakers = textarea.value.split("\n");
|
|
6
|
-
textarea.style.height = "auto";
|
|
7
|
-
if (lineBreakers.length > 1)
|
|
8
|
-
return void (textarea.style.height = `${textarea.scrollHeight}px`);
|
|
9
|
-
};
|
|
10
|
-
textarea.addEventListener("input", adjustHeight);
|
|
11
|
-
return () => textarea.removeEventListener("input", adjustHeight);
|
|
12
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { ChevronRightIcon } from "lucide-react";
|
|
3
|
-
import React, { forwardRef, Fragment, useRef } from "react";
|
|
4
|
-
import { Virtuoso } from "react-virtuoso";
|
|
5
|
-
import { useParentHeight } from "../../hooks/use-parent";
|
|
6
|
-
import { Button } from "../core/button";
|
|
7
|
-
import { Checkbox } from "../form/checkbox";
|
|
8
|
-
import { Input } from "./input";
|
|
9
|
-
const components = {
|
|
10
|
-
Item: forwardRef(function InnerList(props, ref) {
|
|
11
|
-
return <li {...props} ref={ref} className="flex items-center gap-1 justify-between"/>;
|
|
12
|
-
}),
|
|
13
|
-
List: forwardRef(function InnerList(props, ref) {
|
|
14
|
-
return <ul {...props} ref={ref} className="space-y-3"/>;
|
|
15
|
-
}),
|
|
16
|
-
};
|
|
17
|
-
export const TransferList = (props) => {
|
|
18
|
-
const ref = useRef(null);
|
|
19
|
-
const h = useParentHeight(ref);
|
|
20
|
-
return (<div className="flex flex-row gap-4" ref={ref}>
|
|
21
|
-
<div className="py-8 space-y-4 min-w-64 w-fit flex flex-col whitespace-nowrap rounded-lg border border-card-border">
|
|
22
|
-
<header className="border-b border-card-border pb-2"></header>
|
|
23
|
-
<div className="px-8 space-y-2">
|
|
24
|
-
<Input rightLabel="" title="Search" placeholder="Looking for..."/>
|
|
25
|
-
<Virtuoso height={h} useWindowScroll data={props.source} components={components} itemContent={(_, row) => (<Fragment>
|
|
26
|
-
<Checkbox>
|
|
27
|
-
<props.Item data={row}/>
|
|
28
|
-
</Checkbox>
|
|
29
|
-
</Fragment>)}/>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
<div>
|
|
33
|
-
<Button>
|
|
34
|
-
<ChevronRightIcon />
|
|
35
|
-
</Button>
|
|
36
|
-
</div>
|
|
37
|
-
<div></div>
|
|
38
|
-
</div>);
|
|
39
|
-
};
|