@thebuoyant-tsdev/mui-ts-library 3.28.0 → 3.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.de.md CHANGED
@@ -16,13 +16,14 @@ Eine typsichere React-Komponentenbibliothek auf Basis von **TypeScript** und **M
16
16
 
17
17
  ## Komponenten
18
18
 
19
- 12 produktionsreife Komponenten in drei Kategorien. Jede verlinkt zu einer interaktiven Live-Demo und einem vollständigen Manual mit allen Props, Typen und Mustern.
19
+ 13 produktionsreife Komponenten in drei Kategorien. Jede verlinkt zu einer interaktiven Live-Demo und einem vollständigen Manual mit allen Props, Typen und Mustern.
20
20
 
21
21
  ### Interaktive UI
22
22
 
23
23
  | Komponente | Wofür | Ausprobieren |
24
24
  |---|---|---|
25
25
  | [`GanttChart`](#ganttchart) | Drag-and-Drop-Projekt-Timelines mit Meilensteinen, Abhängigkeiten und CSV-Export | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-ganttchart--default) · [Docs](user-manuals/GanttChart.de.md) |
26
+ | [`DateRangePicker`](#daterangepicker) | Start- und Enddatum in einem Inline-Picker — schließt die MUI X Pro-Lücke, kostenlos und ohne zusätzliche Abhängigkeiten | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-daterangepicker--default) · [Docs](user-manuals/DateRangePicker.de.md) |
26
27
  | [`TagSelection`](#tagselection) | Multi-Tag-Autocomplete mit freier Tag-Erstellung und Suchergebnis-Highlighting | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-tagselection--default) · [Docs](user-manuals/TagSelection.de.md) |
27
28
  | [`PasswordStrengthMeter`](#passwordstrengthmeter) | Echtzeit-Stärke-Feedback mit eingebautem sicheren Passwort-Generator | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-passwordstrengthmeter--default) · [Docs](user-manuals/PasswordStrengthMeter.de.md) |
28
29
  | [`ColorPicker`](#colorpicker) | Sättigung/Farbton/Alpha-Farbwähler-Panel mit Pipette-Werkzeug — MUI bringt keinen mit | [Live-Demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-colorpicker--default) · [Docs](user-manuals/ColorPicker.de.md) |
@@ -100,6 +101,33 @@ const tasks: GanttTask[] = [
100
101
 
101
102
  ---
102
103
 
104
+ ### DateRangePicker
105
+
106
+ Start- und Enddatum in einem einzigen Inline-Picker — kein MUI X Pro-Lizenz erforderlich. Entwickelt für Formulare, Filter und Buchungsflows. Unterstützt Controlled/Uncontrolled-Modus, `minDate`/`maxDate`, `required`, Inline-Validierung und vollständige i18n. `onChange` gibt für jedes Datum sowohl ein `Date`-Objekt als auch einen ISO-String zurück.
107
+
108
+ ```tsx
109
+ import { DateRangePicker } from '@thebuoyant-tsdev/mui-ts-library';
110
+ import type { DateRange, DateRangeInput } from '@thebuoyant-tsdev/mui-ts-library';
111
+ import { useState } from 'react';
112
+
113
+ function App() {
114
+ const [range, setRange] = useState<DateRangeInput>({ start: null, end: null });
115
+
116
+ return (
117
+ <DateRangePicker
118
+ value={range}
119
+ onChange={(r) => setRange({ start: r.start?.date ?? null, end: r.end?.date ?? null })}
120
+ required
121
+ translation={{ fromLabel: 'Von', toLabel: 'Bis' }}
122
+ />
123
+ );
124
+ }
125
+ ```
126
+
127
+ → [Vollständige Dokumentation](user-manuals/DateRangePicker.de.md)
128
+
129
+ ---
130
+
103
131
  ### TagSelection
104
132
 
105
133
  Multi-Select-Eingabe mit Autocomplete für Tag- und Label-Verwaltung. Ideal für Filter-UIs, Content-Tagging, Skill-Auswahl und alle Szenarien, in denen Nutzer aus einer vordefinierten Liste wählen oder neue Einträge erstellen sollen.
@@ -485,6 +513,21 @@ Dieses Projekt folgt [Semantic Versioning](https://semver.org/):
485
513
 
486
514
  ### [Unveröffentlicht]
487
515
 
516
+ ---
517
+
518
+ ### [3.29.0] — 2026-07-16
519
+
520
+ ---
521
+
522
+ ### [3.28.1] — 2026-07-15
523
+
524
+ **Behoben**
525
+ - Release-Script: `[Unveröffentlicht]`-Überschriften werden jetzt vor dem Publish automatisch auf die Versionsnummer umbenannt — damit npm immer den korrekten Changelog-Eintrag anzeigt.
526
+
527
+ ---
528
+
529
+ ### [3.28.0] — 2026-07-15
530
+
488
531
  **Hinzugefügt**
489
532
  - `SqlEditor`: `Shift+Alt+F` Tastenkürzel — löst den vorhandenen SQL-Format-Button direkt aus dem Editor heraus aus (respektiert `readonly` und `toolbarConfig.showFormat`). Keine API-Änderung.
490
533
 
package/README.md CHANGED
@@ -16,13 +16,14 @@ A type-safe React component library built on **TypeScript** and **MUI (Material
16
16
 
17
17
  ## Components
18
18
 
19
- 12 production-ready components across three categories. Each links to a live, interactive demo and a full manual covering every prop, type, and pattern.
19
+ 13 production-ready components across three categories. Each links to a live, interactive demo and a full manual covering every prop, type, and pattern.
20
20
 
21
21
  ### Interactive UI
22
22
 
23
23
  | Component | What it's for | Try it |
24
24
  |---|---|---|
25
25
  | [`GanttChart`](#ganttchart) | Drag-and-drop project timelines with milestones, dependencies, and CSV export | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-ganttchart--default) · [Docs](user-manuals/GanttChart.md) |
26
+ | [`DateRangePicker`](#daterangepicker) | Start + end date in one inline picker — fills the MUI X Pro gap, free and dependency-free | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-daterangepicker--default) · [Docs](user-manuals/DateRangePicker.md) |
26
27
  | [`TagSelection`](#tagselection) | Multi-tag autocomplete with free-form tag creation and search highlighting | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-tagselection--default) · [Docs](user-manuals/TagSelection.md) |
27
28
  | [`PasswordStrengthMeter`](#passwordstrengthmeter) | Real-time strength feedback with a built-in secure password generator | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-passwordstrengthmeter--default) · [Docs](user-manuals/PasswordStrengthMeter.md) |
28
29
  | [`ColorPicker`](#colorpicker) | Saturation/hue/alpha color picker panel with an eyedropper tool — MUI ships none | [Live demo](https://thebuoyant.github.io/mui-ts-library/?path=/story/components-colorpicker--default) · [Docs](user-manuals/ColorPicker.md) |
@@ -100,6 +101,33 @@ const tasks: GanttTask[] = [
100
101
 
101
102
  ---
102
103
 
104
+ ### DateRangePicker
105
+
106
+ Start and end date in a single inline picker — no MUI X Pro license required. Built for forms, filters, and booking flows. Supports controlled/uncontrolled mode, `minDate`/`maxDate`, `required`, inline validation, and full i18n. `onChange` returns both a `Date` object and an ISO string for each date.
107
+
108
+ ```tsx
109
+ import { DateRangePicker } from '@thebuoyant-tsdev/mui-ts-library';
110
+ import type { DateRange, DateRangeInput } from '@thebuoyant-tsdev/mui-ts-library';
111
+ import { useState } from 'react';
112
+
113
+ function App() {
114
+ const [range, setRange] = useState<DateRangeInput>({ start: null, end: null });
115
+
116
+ return (
117
+ <DateRangePicker
118
+ value={range}
119
+ onChange={(r) => setRange({ start: r.start?.date ?? null, end: r.end?.date ?? null })}
120
+ required
121
+ translation={{ fromLabel: 'From', toLabel: 'To' }}
122
+ />
123
+ );
124
+ }
125
+ ```
126
+
127
+ → [Full documentation](user-manuals/DateRangePicker.md)
128
+
129
+ ---
130
+
103
131
  ### TagSelection
104
132
 
105
133
  Multi-select input with autocomplete for tag and label management. Best suited for filter UIs, content tagging, skill selection, and any scenario where users pick from a predefined list or create new items on the fly.
@@ -485,6 +513,21 @@ This project follows [Semantic Versioning](https://semver.org/):
485
513
 
486
514
  ### [Unreleased]
487
515
 
516
+ ---
517
+
518
+ ### [3.29.0] — 2026-07-16
519
+
520
+ ---
521
+
522
+ ### [3.28.1] — 2026-07-15
523
+
524
+ **Fixed**
525
+ - Release script: `[Unreleased]` headings are now automatically renamed to the version number before publishing — so npm always shows the correct changelog entry.
526
+
527
+ ---
528
+
529
+ ### [3.28.0] — 2026-07-15
530
+
488
531
  **Added**
489
532
  - `SqlEditor`: `Shift+Alt+F` keyboard shortcut — triggers the existing SQL Format button directly from the editor (respects `readonly` and `toolbarConfig.showFormat`). No API change.
490
533
 
@@ -4,8 +4,8 @@ import { clamp as n, hexToRgba as r, hslaToHsva as i, hsvaToHsla as a, hsvaToRgb
4
4
  import { DEFAULT_COLOR_PICKER_TRANSLATION as u } from "./ColorPicker.types.js";
5
5
  import { useEffect as d, useRef as f, useState as p } from "react";
6
6
  import { Box as m, IconButton as ee, MenuItem as h, Select as te, TextField as g, Tooltip as ne, Typography as re, useTheme as ie } from "@mui/material";
7
- import ae from "@mui/icons-material/Colorize";
8
7
  import { jsx as _, jsxs as v } from "react/jsx-runtime";
8
+ import ae from "@mui/icons-material/Colorize";
9
9
  //#region src/components/color-picker/ColorPicker.tsx
10
10
  function y(e, t) {
11
11
  let r = n(e, 0, 100);
@@ -0,0 +1,2 @@
1
+ import type { DateRangePickerProps } from "./DateRangePicker.types";
2
+ export declare function DateRangePicker({ value, defaultValue, onChange, minDate, maxDate, disabled, required, error, helperText, inputSize, inputMinWidth, translation, }: DateRangePickerProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,161 @@
1
+ import { muiTsStateClasses as e } from "../../utils/muiTsClasses.js";
2
+ import { dateRangePickerClasses as t } from "./dateRangePickerClasses.js";
3
+ import { DEFAULT_DATE_RANGE_PICKER_TRANSLATION as n } from "./DateRangePicker.types.js";
4
+ import { useState as r } from "react";
5
+ import { Box as i, FormHelperText as a, TextField as o } from "@mui/material";
6
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ //#region src/components/date-range-picker/DateRangePicker.tsx
8
+ function l(e) {
9
+ return `${e.getFullYear()}-${String(e.getMonth() + 1).padStart(2, "0")}-${String(e.getDate()).padStart(2, "0")}`;
10
+ }
11
+ function u(e) {
12
+ if (!e) return null;
13
+ let t = /* @__PURE__ */ new Date(`${e}T00:00:00`);
14
+ return isNaN(t.getTime()) ? null : t;
15
+ }
16
+ function d(e) {
17
+ return e ? {
18
+ date: e,
19
+ iso: l(e)
20
+ } : null;
21
+ }
22
+ function f(e, t, n, r) {
23
+ let i = "", a = "";
24
+ return e.start && e.end && e.end < e.start && (a = r.endBeforeStartError), n && !e.start && t.start && (i = r.startRequiredError), n && !e.end && t.end && !a && (a = r.endRequiredError), {
25
+ startError: i,
26
+ endError: a
27
+ };
28
+ }
29
+ var p = {
30
+ start: null,
31
+ end: null
32
+ };
33
+ function m({ value: m, defaultValue: h, onChange: g, minDate: _, maxDate: v, disabled: y = !1, required: b = !1, error: x = !1, helperText: S, inputSize: C = "small", inputMinWidth: w = 170, translation: T }) {
34
+ let E = {
35
+ ...n,
36
+ ...T
37
+ }, D = m !== void 0, [O, k] = r(h ?? p), [A, j] = r({
38
+ start: !1,
39
+ end: !1
40
+ }), M = D ? m : O, { startError: N, endError: P } = f(M, A, b, E);
41
+ function F(e, t) {
42
+ D || k({
43
+ start: e,
44
+ end: t
45
+ }), g?.({
46
+ start: d(e),
47
+ end: d(t)
48
+ });
49
+ }
50
+ function I(e) {
51
+ j((e) => ({
52
+ ...e,
53
+ start: !0
54
+ })), F(u(e.target.value), M.end);
55
+ }
56
+ function L(e) {
57
+ j((e) => ({
58
+ ...e,
59
+ end: !0
60
+ })), F(M.start, u(e.target.value));
61
+ }
62
+ function R() {
63
+ j((e) => ({
64
+ ...e,
65
+ start: !0
66
+ }));
67
+ }
68
+ function z() {
69
+ j((e) => ({
70
+ ...e,
71
+ end: !0
72
+ }));
73
+ }
74
+ let B = _ ? l(_) : void 0, V = v ? l(v) : void 0, H = M.start ? l(M.start) : B, U = x || !!N || !!P;
75
+ return /* @__PURE__ */ c(i, {
76
+ className: [
77
+ t.root,
78
+ y && e.disabled,
79
+ U && e.error
80
+ ].filter(Boolean).join(" "),
81
+ sx: {
82
+ display: "inline-flex",
83
+ flexDirection: "column",
84
+ gap: .25
85
+ },
86
+ children: [/* @__PURE__ */ c(i, {
87
+ className: t.inputs,
88
+ sx: {
89
+ display: "inline-flex",
90
+ alignItems: "flex-start",
91
+ gap: 1
92
+ },
93
+ children: [
94
+ /* @__PURE__ */ s(o, {
95
+ className: t.startInput,
96
+ type: "date",
97
+ label: E.fromLabel,
98
+ value: M.start ? l(M.start) : "",
99
+ onChange: I,
100
+ onBlur: R,
101
+ disabled: y,
102
+ required: b,
103
+ error: !!N || x,
104
+ helperText: N || " ",
105
+ size: C,
106
+ sx: { width: w },
107
+ slotProps: {
108
+ inputLabel: { shrink: !0 },
109
+ htmlInput: {
110
+ min: B,
111
+ max: V,
112
+ "data-testid": "date-range-start"
113
+ }
114
+ }
115
+ }),
116
+ /* @__PURE__ */ s(i, {
117
+ component: "span",
118
+ className: t.separator,
119
+ "aria-hidden": !0,
120
+ sx: {
121
+ color: "text.disabled",
122
+ userSelect: "none",
123
+ flexShrink: 0,
124
+ lineHeight: 1,
125
+ mt: C === "small" ? "12px" : "20px"
126
+ },
127
+ children: "–"
128
+ }),
129
+ /* @__PURE__ */ s(o, {
130
+ className: t.endInput,
131
+ type: "date",
132
+ label: E.toLabel,
133
+ value: M.end ? l(M.end) : "",
134
+ onChange: L,
135
+ onBlur: z,
136
+ disabled: y,
137
+ required: b,
138
+ error: !!P || x,
139
+ helperText: P || " ",
140
+ size: C,
141
+ sx: { width: w },
142
+ slotProps: {
143
+ inputLabel: { shrink: !0 },
144
+ htmlInput: {
145
+ min: H,
146
+ max: V,
147
+ "data-testid": "date-range-end"
148
+ }
149
+ }
150
+ })
151
+ ]
152
+ }), S && /* @__PURE__ */ s(a, {
153
+ className: t.helperText,
154
+ error: x,
155
+ sx: { mx: "14px" },
156
+ children: S
157
+ })]
158
+ });
159
+ }
160
+ //#endregion
161
+ export { m as DateRangePicker };
@@ -0,0 +1,48 @@
1
+ /** One date within the range — returned by `onChange` with both representations. */
2
+ export type DateRangeEntry = {
3
+ date: Date;
4
+ /** ISO date string in local time: "YYYY-MM-DD" */
5
+ iso: string;
6
+ };
7
+ /** Rich output type returned by `onChange`. */
8
+ export type DateRange = {
9
+ start: DateRangeEntry | null;
10
+ end: DateRangeEntry | null;
11
+ };
12
+ /** Simple input type for the `value` and `defaultValue` props. */
13
+ export type DateRangeInput = {
14
+ start: Date | null;
15
+ end: Date | null;
16
+ };
17
+ export type DateRangePickerTranslation = {
18
+ fromLabel: string;
19
+ toLabel: string;
20
+ endBeforeStartError: string;
21
+ startRequiredError: string;
22
+ endRequiredError: string;
23
+ };
24
+ export declare const DEFAULT_DATE_RANGE_PICKER_TRANSLATION: Required<DateRangePickerTranslation>;
25
+ export type DateRangePickerProps = {
26
+ /** Controlled value — pass simple `Date` objects. Omit to use uncontrolled mode via `defaultValue`. */
27
+ value?: DateRangeInput;
28
+ /** Initial value for uncontrolled mode. */
29
+ defaultValue?: DateRangeInput;
30
+ /** Called on every change — receives both `Date` and ISO string per date. */
31
+ onChange?: (range: DateRange) => void;
32
+ /** Earliest selectable date (inclusive). */
33
+ minDate?: Date;
34
+ /** Latest selectable date (inclusive). */
35
+ maxDate?: Date;
36
+ disabled?: boolean;
37
+ /** Marks both inputs as required — shows error after the user has interacted with a field. */
38
+ required?: boolean;
39
+ /** External error state — turns the helper text red. */
40
+ error?: boolean;
41
+ /** General hint or error message displayed below the picker. */
42
+ helperText?: string;
43
+ inputSize?: "small" | "medium";
44
+ /** Minimum (and fixed) width of each date input in pixels. Prevents the field from stretching when a helperText or error message appears. Default: 170. */
45
+ inputMinWidth?: number;
46
+ /** Override any translation key — rest falls back to English defaults. */
47
+ translation?: Partial<DateRangePickerTranslation>;
48
+ };
@@ -0,0 +1,10 @@
1
+ //#region src/components/date-range-picker/DateRangePicker.types.ts
2
+ var e = {
3
+ fromLabel: "From",
4
+ toLabel: "To",
5
+ endBeforeStartError: "End date must be after start date",
6
+ startRequiredError: "Start date is required",
7
+ endRequiredError: "End date is required"
8
+ };
9
+ //#endregion
10
+ export { e as DEFAULT_DATE_RANGE_PICKER_TRANSLATION };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * CSS class names for every named slot in the DateRangePicker component.
3
+ *
4
+ * Use these to style individual parts of the component without relying on
5
+ * MUI's internal class names, which can change between versions.
6
+ *
7
+ * @example
8
+ * ```css
9
+ * .MuiTsDateRangePicker-root.MuiTs-disabled { opacity: 0.5; }
10
+ * .MuiTsDateRangePicker-root.MuiTs-error .MuiTsDateRangePicker-separator { color: red; }
11
+ * ```
12
+ */
13
+ export declare const dateRangePickerClasses: {
14
+ /** The outermost wrapper element. Also receives `MuiTs-disabled` and `MuiTs-error` state classes. */
15
+ readonly root: "MuiTsDateRangePicker-root";
16
+ /** The flex row that holds the start input, separator, and end input. */
17
+ readonly inputs: "MuiTsDateRangePicker-inputs";
18
+ /** The start-date TextField. */
19
+ readonly startInput: "MuiTsDateRangePicker-startInput";
20
+ /** The "–" character between the two inputs. */
21
+ readonly separator: "MuiTsDateRangePicker-separator";
22
+ /** The end-date TextField. */
23
+ readonly endInput: "MuiTsDateRangePicker-endInput";
24
+ /** The FormHelperText shown below the picker row when `helperText` is set. */
25
+ readonly helperText: "MuiTsDateRangePicker-helperText";
26
+ };
@@ -0,0 +1,11 @@
1
+ //#region src/components/date-range-picker/dateRangePickerClasses.ts
2
+ var e = {
3
+ root: "MuiTsDateRangePicker-root",
4
+ inputs: "MuiTsDateRangePicker-inputs",
5
+ startInput: "MuiTsDateRangePicker-startInput",
6
+ separator: "MuiTsDateRangePicker-separator",
7
+ endInput: "MuiTsDateRangePicker-endInput",
8
+ helperText: "MuiTsDateRangePicker-helperText"
9
+ };
10
+ //#endregion
11
+ export { e as dateRangePickerClasses };