UI/UX-Prototyp der Analytics-Dashboards in HiveGrid, fachlich auf einen SHK-/Handwerksbetrieb zugeschnitten. Ziel ist die Übergabe an die Entwicklung, nicht der Produktivbetrieb. Inhalt: sechs Seiten (Übersicht, Finanzen, Aufträge, Kunden, Team, Komponenten), 26 KPIs, neun Chart-Bausteine, Filtersystem mit seitenabhängiger Relevanz und ein deterministischer Demo-Datensatz (420 Kunden, 1.900 Aufträge, Stichtag 30.07.2026). Drei Quellen sind zusammengeführt: die fachliche Planung mit dem Branchenpartner (Januar 2026), die Subframe-Komponentenbibliothek aus dem HiveGrid-Pitch und IBM Carbon Data Visualization für die Diagrammregeln. Herkunft und bewusste Abweichungen stehen in docs/HERKUNFT.md. Dokumentation: README, HANDOVER (was echte Logik braucht), docs/DESIGN-SYSTEM, KPI-KATALOG, DATENMODELL, NAVIGATION, HERKUNFT, ZIELSYSTEM (Einbauort in HiveGrid Cloud) und LEITPLANKEN (welche Cloud-Screens als Vorbild taugen). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
680 lines
25 KiB
TypeScript
680 lines
25 KiB
TypeScript
// @subframe/sync-disable
|
|
// @ts-nocheck
|
|
"use client";
|
|
/*
|
|
* Documentation:
|
|
* Date Picker — https://app.subframe.com/f023064a5ca0/library?component=Date+Picker_e0461776-caeb-4bb3-a9a1-7df3bcfe9afe
|
|
* Dropdown Menu select — https://app.subframe.com/f023064a5ca0/library?component=Dropdown+Menu+select_99951515-459b-4286-919e-a89e7549b43b
|
|
* Icon Button — https://app.subframe.com/f023064a5ca0/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6
|
|
*/
|
|
|
|
import React from "react";
|
|
import { FeatherCalendar } from "@subframe/core";
|
|
import { FeatherChevronDown } from "@subframe/core";
|
|
import { FeatherChevronLeft } from "@subframe/core";
|
|
import { FeatherChevronRight } from "@subframe/core";
|
|
import * as SubframeCore from "@subframe/core";
|
|
import * as SubframeUtils from "../../utils";
|
|
import { DropdownMenuSelect } from "../DropdownMenuSelect";
|
|
import { IconButton } from "../IconButton";
|
|
|
|
export interface WeekdayProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
const Weekday = React.forwardRef<HTMLDivElement, WeekdayProps>(function Weekday(
|
|
{ children, className, ...otherProps }: WeekdayProps,
|
|
ref
|
|
) {
|
|
return (
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"flex h-8 w-9 items-center justify-center",
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
{children ? (
|
|
<span className="text-body-extra-small-medium-0 font-body-extra-small-medium-0 text-text-neutral-tertiary">
|
|
{children}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
);
|
|
});
|
|
|
|
export interface SelectProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
children?: React.ReactNode;
|
|
grow?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select(
|
|
{ children, grow = false, className, ...otherProps }: SelectProps,
|
|
ref
|
|
) {
|
|
return (
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"group/f2c7e363 flex cursor-pointer items-center justify-between rounded-sm border border-solid border-border-default bg-surface-neutral-secondary px-2 py-1.5 hover:bg-surface-neutral-tertiary",
|
|
{ "w-full": grow },
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
<div className="flex items-center gap-2 pr-2">
|
|
{children ? (
|
|
<span className="text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-primary">
|
|
{children}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
<FeatherChevronDown className="text-body-small-medium-0 font-body-small-medium-0 text-icon-neutral-tertiary" />
|
|
</div>
|
|
);
|
|
});
|
|
|
|
export interface CalendarPanelProps
|
|
extends React.HTMLAttributes<HTMLDivElement> {
|
|
month?: React.ReactNode;
|
|
year?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
const CalendarPanel = React.forwardRef<HTMLDivElement, CalendarPanelProps>(
|
|
function CalendarPanel(
|
|
{ month, year, className, ...otherProps }: CalendarPanelProps,
|
|
ref
|
|
) {
|
|
return (
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"flex flex-col items-start gap-2",
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
<div className="flex w-80 flex-col items-start overflow-hidden rounded-md border border-solid border-border-default shadow-md">
|
|
<div className="flex w-full flex-col items-start bg-surface-neutral-tertiary">
|
|
<div className="flex w-full items-center justify-center px-3 py-3">
|
|
<div className="flex grow shrink-0 basis-0 items-center justify-center gap-1">
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronLeft />}
|
|
/>
|
|
<DatePicker.MonthSelect />
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronRight />}
|
|
/>
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronLeft />}
|
|
/>
|
|
<DatePicker.YearSelect />
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronRight />}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between px-3">
|
|
<DatePicker.Weekday>Mo</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Di</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Mi</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Do</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Fr</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Sa</DatePicker.Weekday>
|
|
<DatePicker.Weekday>So</DatePicker.Weekday>
|
|
</div>
|
|
</div>
|
|
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-[#e5e5e5]" />
|
|
<div className="flex w-full flex-col items-center gap-1 bg-surface-neutral-secondary px-3 py-3">
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day outside={true}>27</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>28</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>29</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>30</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>31</DatePicker.Day>
|
|
<DatePicker.Day>1</DatePicker.Day>
|
|
<DatePicker.Day>2</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>3</DatePicker.Day>
|
|
<DatePicker.Day>4</DatePicker.Day>
|
|
<DatePicker.Day>5</DatePicker.Day>
|
|
<DatePicker.Day>6</DatePicker.Day>
|
|
<DatePicker.Day>7</DatePicker.Day>
|
|
<DatePicker.Day>8</DatePicker.Day>
|
|
<DatePicker.Day>9</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>10</DatePicker.Day>
|
|
<DatePicker.Day>11</DatePicker.Day>
|
|
<DatePicker.Day>12</DatePicker.Day>
|
|
<DatePicker.Day>13</DatePicker.Day>
|
|
<DatePicker.Day selected={true}>14</DatePicker.Day>
|
|
<DatePicker.Day>15</DatePicker.Day>
|
|
<DatePicker.Day>16</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>17</DatePicker.Day>
|
|
<DatePicker.Day>18</DatePicker.Day>
|
|
<DatePicker.Day today={true}>19</DatePicker.Day>
|
|
<DatePicker.Day>20</DatePicker.Day>
|
|
<DatePicker.Day>21</DatePicker.Day>
|
|
<DatePicker.Day>22</DatePicker.Day>
|
|
<DatePicker.Day>23</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>24</DatePicker.Day>
|
|
<DatePicker.Day>25</DatePicker.Day>
|
|
<DatePicker.Day>26</DatePicker.Day>
|
|
<DatePicker.Day>27</DatePicker.Day>
|
|
<DatePicker.Day>28</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>1</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>2</DatePicker.Day>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="hidden w-80 flex-col items-start overflow-hidden rounded-md border border-solid border-border-default shadow-md">
|
|
<div className="flex w-full flex-col items-start bg-surface-neutral-tertiary">
|
|
<div className="flex w-full items-center justify-center px-3 py-3">
|
|
<div className="flex grow shrink-0 basis-0 items-center justify-center gap-1">
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronLeft />}
|
|
/>
|
|
<DatePicker.MonthSelect />
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronRight />}
|
|
/>
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronLeft />}
|
|
/>
|
|
<DatePicker.YearSelect />
|
|
<IconButton
|
|
variant="ghost"
|
|
size="extra-small"
|
|
square={true}
|
|
icon={<FeatherChevronRight />}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between px-3">
|
|
<DatePicker.Weekday>Mo</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Di</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Mi</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Do</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Fr</DatePicker.Weekday>
|
|
<DatePicker.Weekday>Sa</DatePicker.Weekday>
|
|
<DatePicker.Weekday>So</DatePicker.Weekday>
|
|
</div>
|
|
</div>
|
|
<div className="flex h-px w-full flex-none flex-col items-center gap-2 bg-[#e5e5e5]" />
|
|
<div className="flex w-full flex-col items-center gap-1 bg-surface-neutral-secondary px-3 py-3">
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day outside={true}>27</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>28</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>29</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>30</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>31</DatePicker.Day>
|
|
<DatePicker.Day>1</DatePicker.Day>
|
|
<DatePicker.Day>2</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>3</DatePicker.Day>
|
|
<DatePicker.Day>4</DatePicker.Day>
|
|
<DatePicker.Day>5</DatePicker.Day>
|
|
<DatePicker.Day>6</DatePicker.Day>
|
|
<DatePicker.Day>7</DatePicker.Day>
|
|
<DatePicker.Day>8</DatePicker.Day>
|
|
<DatePicker.Day>9</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>10</DatePicker.Day>
|
|
<DatePicker.Day>11</DatePicker.Day>
|
|
<DatePicker.Day>12</DatePicker.Day>
|
|
<DatePicker.Day>13</DatePicker.Day>
|
|
<DatePicker.Day selected={true}>14</DatePicker.Day>
|
|
<DatePicker.Day>15</DatePicker.Day>
|
|
<DatePicker.Day>16</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>17</DatePicker.Day>
|
|
<DatePicker.Day>18</DatePicker.Day>
|
|
<DatePicker.Day today={true}>19</DatePicker.Day>
|
|
<DatePicker.Day>20</DatePicker.Day>
|
|
<DatePicker.Day>21</DatePicker.Day>
|
|
<DatePicker.Day>22</DatePicker.Day>
|
|
<DatePicker.Day>23</DatePicker.Day>
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<DatePicker.Day>24</DatePicker.Day>
|
|
<DatePicker.Day>25</DatePicker.Day>
|
|
<DatePicker.Day>26</DatePicker.Day>
|
|
<DatePicker.Day>27</DatePicker.Day>
|
|
<DatePicker.Day>28</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>1</DatePicker.Day>
|
|
<DatePicker.Day outside={true}>2</DatePicker.Day>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
export interface MonthSelectProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
className?: string;
|
|
}
|
|
|
|
const MonthSelect = React.forwardRef<HTMLDivElement, MonthSelectProps>(
|
|
function MonthSelect({ className, ...otherProps }: MonthSelectProps, ref) {
|
|
return (
|
|
<SubframeCore.DropdownMenu.Root>
|
|
<SubframeCore.DropdownMenu.Trigger asChild={true}>
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"flex flex-col items-start gap-2",
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
<DatePicker.Select>September</DatePicker.Select>
|
|
</div>
|
|
</SubframeCore.DropdownMenu.Trigger>
|
|
<SubframeCore.DropdownMenu.Portal>
|
|
<SubframeCore.DropdownMenu.Content
|
|
side="bottom"
|
|
align="start"
|
|
sideOffset={4}
|
|
asChild={true}
|
|
>
|
|
<DropdownMenuSelect className="min-w-0">
|
|
<div className="flex w-full flex-col items-start gap-0.5">
|
|
<DatePicker.YearCell>Januar</DatePicker.YearCell>
|
|
<DatePicker.YearCell selected={true}>
|
|
Februar
|
|
</DatePicker.YearCell>
|
|
<DatePicker.YearCell>März</DatePicker.YearCell>
|
|
<DatePicker.YearCell>April</DatePicker.YearCell>
|
|
<DatePicker.YearCell>Mai</DatePicker.YearCell>
|
|
<DatePicker.YearCell>Juni</DatePicker.YearCell>
|
|
<DatePicker.YearCell>Juli</DatePicker.YearCell>
|
|
<DatePicker.YearCell>August</DatePicker.YearCell>
|
|
<DatePicker.YearCell>September</DatePicker.YearCell>
|
|
<DatePicker.YearCell>Oktober</DatePicker.YearCell>
|
|
<DatePicker.YearCell>November</DatePicker.YearCell>
|
|
<DatePicker.YearCell>Dezember</DatePicker.YearCell>
|
|
</div>
|
|
</DropdownMenuSelect>
|
|
</SubframeCore.DropdownMenu.Content>
|
|
</SubframeCore.DropdownMenu.Portal>
|
|
</SubframeCore.DropdownMenu.Root>
|
|
);
|
|
}
|
|
);
|
|
|
|
export interface YearSelectProps
|
|
extends React.ComponentProps<typeof DatePicker.Select> {
|
|
className?: string;
|
|
}
|
|
|
|
const YearSelect = React.forwardRef<
|
|
React.ElementRef<typeof DatePicker.Select>,
|
|
YearSelectProps
|
|
>(function YearSelect({ className, ...otherProps }: YearSelectProps, ref) {
|
|
return (
|
|
<SubframeCore.DropdownMenu.Root>
|
|
<SubframeCore.DropdownMenu.Trigger asChild={true}>
|
|
<DatePicker.Select className={className} ref={ref} {...otherProps}>
|
|
2026
|
|
</DatePicker.Select>
|
|
</SubframeCore.DropdownMenu.Trigger>
|
|
<SubframeCore.DropdownMenu.Portal>
|
|
<SubframeCore.DropdownMenu.Content
|
|
side="bottom"
|
|
align="start"
|
|
sideOffset={4}
|
|
asChild={true}
|
|
>
|
|
<DropdownMenuSelect className="min-w-0">
|
|
<div className="flex w-full flex-col items-start gap-0.5">
|
|
<DatePicker.YearCell>2021</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2022</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2023</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2024</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2025</DatePicker.YearCell>
|
|
<DatePicker.YearCell selected={true}>2026</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2027</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2028</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2029</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2030</DatePicker.YearCell>
|
|
<DatePicker.YearCell>2031</DatePicker.YearCell>
|
|
</div>
|
|
</DropdownMenuSelect>
|
|
</SubframeCore.DropdownMenu.Content>
|
|
</SubframeCore.DropdownMenu.Portal>
|
|
</SubframeCore.DropdownMenu.Root>
|
|
);
|
|
});
|
|
|
|
export interface DayProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
children?: React.ReactNode;
|
|
selected?: boolean;
|
|
today?: boolean;
|
|
outside?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
const Day = React.forwardRef<HTMLDivElement, DayProps>(function Day(
|
|
{
|
|
children,
|
|
selected = false,
|
|
today = false,
|
|
outside = false,
|
|
className,
|
|
...otherProps
|
|
}: DayProps,
|
|
ref
|
|
) {
|
|
return (
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"group/3262f2d3 flex h-full max-h-[36px] min-h-[36px] w-full min-w-[36px] max-w-[36px] cursor-pointer items-center justify-center rounded-round hover:bg-surface-neutral-tertiary",
|
|
{
|
|
"border border-solid border-border-strong": today,
|
|
"bg-brand-brand-surface-solid-default": selected,
|
|
},
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
{children ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-primary",
|
|
{
|
|
"text-text-neutral-subtle": outside,
|
|
"text-text-neutral-on-solid": selected,
|
|
}
|
|
)}
|
|
>
|
|
{children}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
);
|
|
});
|
|
|
|
export interface YearCellProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
children?: React.ReactNode;
|
|
selected?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
const YearCell = React.forwardRef<HTMLDivElement, YearCellProps>(
|
|
function YearCell(
|
|
{ children, selected = false, className, ...otherProps }: YearCellProps,
|
|
ref
|
|
) {
|
|
return (
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"group/5db54e28 flex h-7 w-full cursor-pointer items-center rounded-sm px-2 group/yearcell hover:bg-surface-feedback-subtle-information-hover",
|
|
{ "bg-brand-brand-surface-solid-default": selected },
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
{children ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"text-body-small-medium-0 font-body-small-medium-0 text-text-neutral-primary",
|
|
{
|
|
"text-text-neutral-on-solid group-hover/5db54e28:text-text-neutral-primary":
|
|
selected,
|
|
}
|
|
)}
|
|
>
|
|
{children}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
export interface DatePickerRootProps
|
|
extends Omit<React.HTMLAttributes<HTMLDivElement>, "placeholder"> {
|
|
disabled?: boolean;
|
|
error?: boolean;
|
|
hasValue?: boolean;
|
|
size?: "small" | "medium" | "large";
|
|
fillContainer?: boolean;
|
|
borderless?: boolean;
|
|
noPadding?: boolean;
|
|
showLabel?: boolean;
|
|
label?: React.ReactNode;
|
|
helpText?: React.ReactNode;
|
|
message?: React.ReactNode;
|
|
placeholder?: React.ReactNode;
|
|
value?: React.ReactNode;
|
|
month?: React.ReactNode;
|
|
year?: React.ReactNode;
|
|
boolean?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
const DatePickerRoot = React.forwardRef<HTMLDivElement, DatePickerRootProps>(
|
|
function DatePickerRoot(
|
|
{
|
|
disabled = false,
|
|
error = false,
|
|
hasValue = false,
|
|
size = "medium",
|
|
fillContainer = false,
|
|
borderless = false,
|
|
noPadding = false,
|
|
showLabel = false,
|
|
label,
|
|
helpText,
|
|
message,
|
|
placeholder,
|
|
value,
|
|
month,
|
|
year,
|
|
boolean = false,
|
|
className,
|
|
...otherProps
|
|
}: DatePickerRootProps,
|
|
ref
|
|
) {
|
|
return (
|
|
<SubframeCore.DropdownMenu.Root>
|
|
<SubframeCore.DropdownMenu.Trigger asChild={true}>
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"group/e0461776 flex min-w-[144px] cursor-pointer flex-col items-start gap-3",
|
|
{
|
|
"gap-0": showLabel,
|
|
"w-full min-w-[240px]": fillContainer,
|
|
"cursor-not-allowed": disabled,
|
|
},
|
|
className
|
|
)}
|
|
ref={ref}
|
|
{...otherProps}
|
|
>
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"hidden flex-col items-start gap-2",
|
|
{ flex: showLabel }
|
|
)}
|
|
>
|
|
{label ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"text-body-default-medium-0 font-body-default-medium-0 text-text-neutral-primary",
|
|
{
|
|
"text-text-feedback-negative": error,
|
|
"text-text-neutral-disabled": disabled,
|
|
}
|
|
)}
|
|
>
|
|
{label}
|
|
</span>
|
|
) : null}
|
|
{helpText ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"text-body-small-regular-0 font-body-small-regular-0 text-text-neutral-tertiary",
|
|
{
|
|
"text-text-feedback-negative": error,
|
|
"text-text-neutral-disabled": disabled,
|
|
}
|
|
)}
|
|
>
|
|
{helpText}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"flex w-full flex-col items-start gap-3",
|
|
{ "gap-1": showLabel }
|
|
)}
|
|
>
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"flex w-full flex-col items-start gap-1 relative",
|
|
{ "px-0 pt-1.5 pb-0": showLabel }
|
|
)}
|
|
>
|
|
<div
|
|
className={SubframeUtils.twClassNames(
|
|
"flex h-9 w-full flex-none items-center gap-2 rounded-sm border border-solid border-border-strong bg-surface-neutral-primary px-3 group-hover/e0461776:bg-surface-neutral-secondary group-focus-within/e0461776:bg-surface-neutral-secondary group-focus-within/e0461776:shadow-focus",
|
|
{
|
|
"border border-solid border-border-default": showLabel,
|
|
"h-auto px-0 py-0": noPadding,
|
|
"border-none": borderless,
|
|
"h-12": size === "large",
|
|
"h-8": size === "small",
|
|
"border border-solid border-border-negative-solid group-focus-within/e0461776:border-2 group-focus-within/e0461776:border-solid group-focus-within/e0461776:border-border-negative-solid group-focus-within/e0461776:shadow-none":
|
|
error,
|
|
"border border-solid border-border-disabled bg-surface-neutral-disabled cursor-not-allowed group-hover/e0461776:bg-surface-neutral-disabled group-focus-within/e0461776:bg-surface-neutral-disabled group-focus-within/e0461776:shadow-none":
|
|
disabled,
|
|
}
|
|
)}
|
|
>
|
|
{value ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"hidden grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-secondary",
|
|
{
|
|
"text-body-small-regular-0 font-body-small-regular-0":
|
|
size === "small",
|
|
inline: hasValue,
|
|
"text-text-neutral-disabled": disabled,
|
|
}
|
|
)}
|
|
>
|
|
{value}
|
|
</span>
|
|
) : null}
|
|
{placeholder ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"grow shrink-0 basis-0 text-body-default-regular-0 font-body-default-regular-0 text-text-neutral-subtle",
|
|
{
|
|
"text-body-small-regular-0 font-body-small-regular-0":
|
|
size === "small",
|
|
hidden: hasValue,
|
|
"text-text-neutral-disabled": disabled,
|
|
}
|
|
)}
|
|
>
|
|
{placeholder}
|
|
</span>
|
|
) : null}
|
|
<FeatherCalendar
|
|
className={SubframeUtils.twClassNames(
|
|
"text-body-default-regular-0 font-body-default-regular-0 text-icon-neutral-tertiary",
|
|
{
|
|
"text-body-small-regular-0 font-body-small-regular-0":
|
|
size === "small",
|
|
"text-icon-feedback-negative": error,
|
|
"text-icon-neutral-disabled": disabled,
|
|
}
|
|
)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
{message ? (
|
|
<span
|
|
className={SubframeUtils.twClassNames(
|
|
"hidden text-body-extra-small-regular-0 font-body-extra-small-regular-0 text-text-neutral-tertiary",
|
|
{
|
|
inline: showLabel,
|
|
"text-text-feedback-negative": error,
|
|
"text-text-neutral-disabled": disabled,
|
|
}
|
|
)}
|
|
>
|
|
{message}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</SubframeCore.DropdownMenu.Trigger>
|
|
<SubframeCore.DropdownMenu.Portal>
|
|
<SubframeCore.DropdownMenu.Content
|
|
side="bottom"
|
|
align="start"
|
|
sideOffset={4}
|
|
asChild={true}
|
|
>
|
|
<DropdownMenuSelect className="h-auto w-auto flex-none">
|
|
<CalendarPanel month="Februar" year="2025" />
|
|
</DropdownMenuSelect>
|
|
</SubframeCore.DropdownMenu.Content>
|
|
</SubframeCore.DropdownMenu.Portal>
|
|
</SubframeCore.DropdownMenu.Root>
|
|
);
|
|
}
|
|
);
|
|
|
|
export const DatePicker = Object.assign(DatePickerRoot, {
|
|
Weekday,
|
|
Select,
|
|
CalendarPanel,
|
|
MonthSelect,
|
|
YearSelect,
|
|
Day,
|
|
YearCell,
|
|
});
|