@wow-two-beta/ui 0.0.69 → 0.0.70
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/{chunk-SREWD3XJ.js → chunk-KD6MJOL5.js} +3 -3
- package/dist/{chunk-SREWD3XJ.js.map → chunk-KD6MJOL5.js.map} +1 -1
- package/dist/{chunk-EKGOQL75.js → chunk-SIAFOCT4.js} +36 -3
- package/dist/chunk-SIAFOCT4.js.map +1 -0
- package/dist/{chunk-X3JVVEUJ.js → chunk-UFTKE5U7.js} +143 -172
- package/dist/chunk-UFTKE5U7.js.map +1 -0
- package/dist/display/eventCalendar/EventCalendar.d.ts +9 -6
- package/dist/display/gantt/Gantt.d.ts +6 -5
- package/dist/display/heatmapCalendar/HeatmapCalendar.d.ts +4 -2
- package/dist/display/index.js +2 -2
- package/dist/display/scheduleView/ScheduleView.d.ts +6 -4
- package/dist/forms/DateExtensions.d.ts +26 -0
- package/dist/forms/index.js +2 -2
- package/dist/http/ApiError.d.ts +7 -0
- package/dist/http/ApiResponse.d.ts +4 -0
- package/dist/http/DateBrands.d.ts +8 -0
- package/dist/http/ProblemDetails.d.ts +9 -0
- package/dist/http/index.d.ts +5 -0
- package/dist/http/index.js +58 -0
- package/dist/http/index.js.map +1 -0
- package/dist/http/temporalReviver.d.ts +9 -0
- package/dist/index.js +4 -4
- package/dist/layout/index.js +1 -1
- package/package.json +6 -1
- package/dist/chunk-EKGOQL75.js.map +0 -1
- package/dist/chunk-X3JVVEUJ.js.map +0 -1
|
@@ -142,7 +142,40 @@ function isInRange(d, start, end) {
|
|
|
142
142
|
const hi = Temporal.PlainDate.compare(start, end) <= 0 ? end : start;
|
|
143
143
|
return Temporal.PlainDate.compare(d, lo) >= 0 && Temporal.PlainDate.compare(d, hi) <= 0;
|
|
144
144
|
}
|
|
145
|
+
function daysBetween(a, b) {
|
|
146
|
+
return a.until(b, { largestUnit: "day" }).days;
|
|
147
|
+
}
|
|
148
|
+
function isWeekend(d) {
|
|
149
|
+
return d.dayOfWeek === 6 || d.dayOfWeek === 7;
|
|
150
|
+
}
|
|
151
|
+
function nowZoned() {
|
|
152
|
+
return Temporal.Now.zonedDateTimeISO();
|
|
153
|
+
}
|
|
154
|
+
function isZonedOnDay(z, day) {
|
|
155
|
+
return z.toPlainDate().equals(day);
|
|
156
|
+
}
|
|
157
|
+
function zonedAtHour(day, hour, timeZone) {
|
|
158
|
+
return day.toZonedDateTime({
|
|
159
|
+
timeZone,
|
|
160
|
+
plainTime: new Temporal.PlainTime(hour)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function minutesBetween(a, b) {
|
|
164
|
+
return a.until(b, { largestUnit: "minute", smallestUnit: "minute" }).minutes;
|
|
165
|
+
}
|
|
166
|
+
function maxZoned(a, b) {
|
|
167
|
+
return Temporal.ZonedDateTime.compare(a, b) >= 0 ? a : b;
|
|
168
|
+
}
|
|
169
|
+
function minZoned(a, b) {
|
|
170
|
+
return Temporal.ZonedDateTime.compare(a, b) <= 0 ? a : b;
|
|
171
|
+
}
|
|
172
|
+
function isZonedDayInRange(z, start, end) {
|
|
173
|
+
return isInRange(z.toPlainDate(), start.toPlainDate(), end.toPlainDate());
|
|
174
|
+
}
|
|
175
|
+
function formatZonedTime(z) {
|
|
176
|
+
return z.toLocaleString(void 0, { hour: "2-digit", minute: "2-digit" });
|
|
177
|
+
}
|
|
145
178
|
|
|
146
|
-
export { Kbd, MONTHS_LONG, Tag, WEEKDAYS_SHORT, addDays, addMonths, buildMonthGrid, daysInMonth, formatISODate, formatISOTime, isDateDisabled, isInRange, isSameDay, isToday, parseISODate, parseISOTime, startOfMonth, sundayIndex, tagVariants, today };
|
|
147
|
-
//# sourceMappingURL=chunk-
|
|
148
|
-
//# sourceMappingURL=chunk-
|
|
179
|
+
export { Kbd, MONTHS_LONG, Tag, WEEKDAYS_SHORT, addDays, addMonths, buildMonthGrid, daysBetween, daysInMonth, formatISODate, formatISOTime, formatZonedTime, isDateDisabled, isInRange, isSameDay, isToday, isWeekend, isZonedDayInRange, isZonedOnDay, maxZoned, minZoned, minutesBetween, nowZoned, parseISODate, parseISOTime, startOfMonth, sundayIndex, tagVariants, today, zonedAtHour };
|
|
180
|
+
//# sourceMappingURL=chunk-SIAFOCT4.js.map
|
|
181
|
+
//# sourceMappingURL=chunk-SIAFOCT4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/display/kbd/Kbd.tsx","../src/display/tag/Tag.variants.ts","../src/display/tag/Tag.tsx","../src/forms/DateExtensions.ts"],"names":["forwardRef","jsx"],"mappings":"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","file":"chunk-SIAFOCT4.js","sourcesContent":["import { forwardRef, type ComponentPropsWithoutRef } from 'react';\nimport { cn } from '../../utils';\n\nexport type KbdProps = ComponentPropsWithoutRef<'kbd'>;\n\n/**\n * Keyboard key affordance — `<kbd>` styled with subtle border and inset\n * shadow. Single key per `<Kbd>`; chain via `<Kbd>⌘</Kbd> + <Kbd>K</Kbd>`.\n */\nexport const Kbd = forwardRef<HTMLElement, KbdProps>(({ className, ...props }, ref) => (\n <kbd\n ref={ref}\n className={cn(\n 'inline-flex h-5 min-w-5 items-center justify-center rounded-sm border border-border',\n 'bg-muted px-1.5 font-mono text-xs text-muted-foreground shadow-[inset_0_-1px_0_0_rgb(0_0_0/0.05)]',\n className,\n )}\n {...props}\n />\n));\nKbd.displayName = 'Kbd';\n","import { tv, type VariantProps } from '../../utils';\n\nexport const tagVariants = tv({\n base: 'inline-flex items-center gap-1 rounded-md border border-border bg-card px-2 py-0.5 text-xs font-medium text-card-foreground',\n variants: {\n variant: {\n neutral: '',\n brand: 'border-transparent bg-primary-soft text-primary-soft-foreground',\n success: 'border-transparent bg-success-soft text-success-soft-foreground',\n warning: 'border-transparent bg-warning-soft text-warning-soft-foreground',\n danger: 'border-transparent bg-destructive-soft text-destructive-soft-foreground',\n info: 'border-transparent bg-info-soft text-info-soft-foreground',\n },\n },\n defaultVariants: {\n variant: 'neutral',\n },\n});\n\nexport type TagVariants = VariantProps<typeof tagVariants>;\n","import { forwardRef, type ComponentPropsWithoutRef, type ReactNode } from 'react';\nimport { X } from 'lucide-react';\nimport { cn } from '../../utils';\nimport { Icon } from '../../icons';\nimport { tagVariants, type TagVariants } from './Tag.variants';\n\nexport interface TagProps\n extends Omit<ComponentPropsWithoutRef<'span'>, 'children'>,\n TagVariants {\n children?: ReactNode;\n /** Show a close (×) button. Pass a handler to receive the click. */\n onClose?: () => void;\n /** Accessible label for the close button. Default `\"Remove\"`. */\n closeLabel?: string;\n}\n\n/**\n * Pill with an optional close button. The close button is a raw `<button>`\n * to keep the strict atom rule (Tag is L3, so importing Button would make\n * this an atom-on-atom composition).\n */\nexport const Tag = forwardRef<HTMLSpanElement, TagProps>(\n ({ children, onClose, closeLabel = 'Remove', variant, className, ...props }, ref) => (\n <span ref={ref} className={cn(tagVariants({ variant }), className)} {...props}>\n {children}\n {onClose && (\n <button\n type=\"button\"\n aria-label={closeLabel}\n onClick={onClose}\n className=\"-mr-1 inline-flex h-4 w-4 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n >\n <Icon icon={X} size={12} />\n </button>\n )}\n </span>\n ),\n);\nTag.displayName = 'Tag';\n","// Shared date helpers for Calendar / DatePicker / DateField / RangeCalendar.\n// Co-located in `forms/` so imports stay within-domain.\n//\n// Temporal-based — the ecosystem standardizes on the Temporal API (dates =\n// `Temporal.*`). `Temporal.PlainDate` carries calendar math (no timezone), so\n// these helpers are inherently local/wall-clock, which is what calendar UIs want.\n// `Temporal.PlainTime` carries hour/minute for the time components.\n\nimport { Temporal } from '@js-temporal/polyfill';\n\nexport const WEEKDAYS_SHORT = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];\nexport const MONTHS_LONG = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n];\n\n/** Sunday-anchored column index (0 = Sun … 6 = Sat) for a PlainDate. */\nexport function sundayIndex(d: Temporal.PlainDate): number {\n // Temporal `dayOfWeek` is 1 (Mon) … 7 (Sun); map Sunday to 0 for our Su-first grid.\n return d.dayOfWeek % 7;\n}\n\n/** Today as a PlainDate in the local time zone. */\nexport function today(): Temporal.PlainDate {\n return Temporal.Now.plainDateISO();\n}\n\nexport function isSameDay(\n a: Temporal.PlainDate | null | undefined,\n b: Temporal.PlainDate | null | undefined,\n): boolean {\n if (!a || !b) return false;\n return a.equals(b);\n}\n\nexport function isToday(d: Temporal.PlainDate): boolean {\n return d.equals(today());\n}\n\n/** Add `n` months; Temporal clamps to the target month's last day (Jan 31 +1 → Feb 28). */\nexport function addMonths(d: Temporal.PlainDate, n: number): Temporal.PlainDate {\n return d.add({ months: n });\n}\n\nexport function addDays(d: Temporal.PlainDate, n: number): Temporal.PlainDate {\n return d.add({ days: n });\n}\n\n/** First day of `d`'s month. */\nexport function startOfMonth(d: Temporal.PlainDate): Temporal.PlainDate {\n return d.with({ day: 1 });\n}\n\n/** Number of days in the given year/month (1-indexed month). */\nexport function daysInMonth(year: number, month: number): number {\n return Temporal.PlainDate.from({ year, month, day: 1 }).daysInMonth;\n}\n\n/**\n * Build the 6-week (42-cell) grid that the calendar UI renders.\n * `year`/`month` are 1-indexed (Temporal convention). Cells outside the target\n * month carry `outOfMonth: true`.\n */\nexport function buildMonthGrid(\n year: number,\n month: number,\n): { date: Temporal.PlainDate; outOfMonth: boolean }[] {\n const first = Temporal.PlainDate.from({ year, month, day: 1 });\n const start = first.subtract({ days: sundayIndex(first) });\n const cells: { date: Temporal.PlainDate; outOfMonth: boolean }[] = [];\n for (let i = 0; i < 42; i++) {\n const date = start.add({ days: i });\n cells.push({ date, outOfMonth: date.month !== month });\n }\n return cells;\n}\n\n/** Format PlainDate → \"YYYY-MM-DD\" for a native `<input type=\"date\">` value. */\nexport function formatISODate(d: Temporal.PlainDate | null | undefined): string {\n if (!d) return '';\n return d.toString();\n}\n\n/** Parse \"YYYY-MM-DD\" → PlainDate. Returns null for invalid input. */\nexport function parseISODate(s: string | null | undefined): Temporal.PlainDate | null {\n if (!s) return null;\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return null;\n try {\n return Temporal.PlainDate.from(s, { overflow: 'reject' });\n } catch {\n return null;\n }\n}\n\n/** Format PlainTime → \"HH:MM\" for a native `<input type=\"time\">` value. */\nexport function formatISOTime(t: Temporal.PlainTime | null | undefined): string {\n if (!t) return '';\n return t.toString({ smallestUnit: 'minute' });\n}\n\n/** Parse \"HH:MM\" → PlainTime. Returns null for invalid input. */\nexport function parseISOTime(s: string | null | undefined): Temporal.PlainTime | null {\n if (!s) return null;\n if (!/^\\d{2}:\\d{2}$/.test(s)) return null;\n try {\n return Temporal.PlainTime.from(s, { overflow: 'reject' });\n } catch {\n return null;\n }\n}\n\nexport function clampDate(\n d: Temporal.PlainDate,\n min?: Temporal.PlainDate | null,\n max?: Temporal.PlainDate | null,\n): Temporal.PlainDate {\n if (min && Temporal.PlainDate.compare(d, min) < 0) return min;\n if (max && Temporal.PlainDate.compare(d, max) > 0) return max;\n return d;\n}\n\nexport function isDateDisabled(\n d: Temporal.PlainDate,\n options: {\n min?: Temporal.PlainDate | null;\n max?: Temporal.PlainDate | null;\n isDisabled?: (d: Temporal.PlainDate) => boolean;\n },\n): boolean {\n const { min, max, isDisabled } = options;\n if (min && Temporal.PlainDate.compare(d, min) < 0) return true;\n if (max && Temporal.PlainDate.compare(d, max) > 0) return true;\n if (isDisabled?.(d)) return true;\n return false;\n}\n\nexport function isInRange(\n d: Temporal.PlainDate,\n start: Temporal.PlainDate | null | undefined,\n end: Temporal.PlainDate | null | undefined,\n): boolean {\n if (!start || !end) return false;\n const lo = Temporal.PlainDate.compare(start, end) <= 0 ? start : end;\n const hi = Temporal.PlainDate.compare(start, end) <= 0 ? end : start;\n return Temporal.PlainDate.compare(d, lo) >= 0 && Temporal.PlainDate.compare(d, hi) <= 0;\n}\n\n/** Signed whole-day count from `a` to `b` (positive when `b` is later). */\nexport function daysBetween(a: Temporal.PlainDate, b: Temporal.PlainDate): number {\n return a.until(b, { largestUnit: 'day' }).days;\n}\n\n/** True when `d` falls on a Saturday or Sunday. */\nexport function isWeekend(d: Temporal.PlainDate): boolean {\n // Temporal `dayOfWeek`: 1 (Mon) … 7 (Sun); 6 = Sat, 7 = Sun.\n return d.dayOfWeek === 6 || d.dayOfWeek === 7;\n}\n\n// ── Datetime helpers (ZonedDateTime) ──────────────────────────────────────\n// EventCalendar / ScheduleView model absolute instants (a wall-clock time in a\n// specific zone) — the `Temporal.ZonedDateTime` peer of .NET `DateTimeOffset`.\n// The grid + navigation still project down to `Temporal.PlainDate` (via the\n// helpers above); these cover the intra-day time-slot math the grid needs.\n\n/** Now as a ZonedDateTime in the local (system) time zone. */\nexport function nowZoned(): Temporal.ZonedDateTime {\n return Temporal.Now.zonedDateTimeISO();\n}\n\n/** The calendar day a ZonedDateTime falls on (its wall-clock PlainDate). */\nexport function zonedToPlainDate(z: Temporal.ZonedDateTime): Temporal.PlainDate {\n return z.toPlainDate();\n}\n\n/** True when two ZonedDateTimes land on the same wall-clock day (same zone assumed). */\nexport function isSameZonedDay(a: Temporal.ZonedDateTime, b: Temporal.ZonedDateTime): boolean {\n return a.toPlainDate().equals(b.toPlainDate());\n}\n\n/** True when a ZonedDateTime falls on `day` (its wall-clock date equals `day`). */\nexport function isZonedOnDay(z: Temporal.ZonedDateTime, day: Temporal.PlainDate): boolean {\n return z.toPlainDate().equals(day);\n}\n\n/** Start-of-day (00:00, zone-correct) for `day` in `z`'s time zone. */\nexport function startOfZonedDay(day: Temporal.PlainDate, timeZone: Temporal.TimeZoneLike): Temporal.ZonedDateTime {\n return day.toZonedDateTime({ timeZone, plainTime: Temporal.PlainTime.from('00:00') });\n}\n\n/** `day` at hour `hour` (minutes/seconds zeroed), zone-correct, in `timeZone`. */\nexport function zonedAtHour(\n day: Temporal.PlainDate,\n hour: number,\n timeZone: Temporal.TimeZoneLike,\n): Temporal.ZonedDateTime {\n return day.toZonedDateTime({\n timeZone,\n plainTime: new Temporal.PlainTime(hour),\n });\n}\n\n/** Signed minutes from `a` to `b` (positive when `b` is later). */\nexport function minutesBetween(a: Temporal.ZonedDateTime, b: Temporal.ZonedDateTime): number {\n return a.until(b, { largestUnit: 'minute', smallestUnit: 'minute' }).minutes;\n}\n\n/** Later of two instants. */\nexport function maxZoned(a: Temporal.ZonedDateTime, b: Temporal.ZonedDateTime): Temporal.ZonedDateTime {\n return Temporal.ZonedDateTime.compare(a, b) >= 0 ? a : b;\n}\n\n/** Earlier of two instants. */\nexport function minZoned(a: Temporal.ZonedDateTime, b: Temporal.ZonedDateTime): Temporal.ZonedDateTime {\n return Temporal.ZonedDateTime.compare(a, b) <= 0 ? a : b;\n}\n\n/** True when `z`'s calendar day lies within [start, end] (inclusive, by day). */\nexport function isZonedDayInRange(\n z: Temporal.ZonedDateTime,\n start: Temporal.ZonedDateTime,\n end: Temporal.ZonedDateTime,\n): boolean {\n return isInRange(z.toPlainDate(), start.toPlainDate(), end.toPlainDate());\n}\n\n/** Format a ZonedDateTime's time-of-day as \"HH:MM\" (locale-aware). */\nexport function formatZonedTime(z: Temporal.ZonedDateTime): string {\n return z.toLocaleString(undefined, { hour: '2-digit', minute: '2-digit' });\n}\n"]}
|