@ponti-studios/ui 1.5.1 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponti-studios/ui",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "private": false,
5
5
  "description": "Shared UI component library for Ponti Studios",
6
6
  "license": "MIT",
@@ -16,7 +16,12 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
16
16
  months: "flex flex-col gap-4 sm:flex-row",
17
17
  month: "flex flex-col gap-4",
18
18
  month_caption: "relative flex h-8 items-center justify-center",
19
- caption_label: "text-sm font-medium",
19
+ caption_label: "flex items-center gap-1 text-sm font-medium",
20
+ dropdowns: "flex items-center gap-1",
21
+ dropdown_root: "relative",
22
+ dropdown: "absolute inset-0 z-10 cursor-pointer opacity-0",
23
+ months_dropdown: "",
24
+ years_dropdown: "",
20
25
  nav: "absolute inset-x-4 top-4 z-10 flex items-center justify-between",
21
26
  button_previous:
22
27
  "inline-flex size-8 p-2 items-center justify-center rounded-full border bg-background text-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50",
@@ -102,6 +102,44 @@ export const Disabled: Story = {
102
102
  },
103
103
  };
104
104
 
105
+ // No play function — this one is for manually driving the interaction
106
+ // (e.g. screen recordings), not automated assertions.
107
+ export const DropdownEmpty: Story = {
108
+ args: {
109
+ name: "startDate",
110
+ label: "Start date",
111
+ captionLayout: "dropdown",
112
+ },
113
+ };
114
+
115
+ export const WithDropdownCaption: Story = {
116
+ args: {
117
+ mode: "range",
118
+ startName: "startDate",
119
+ endName: "endDate",
120
+ defaultValue: { from: "2018-03-01" },
121
+ label: "Employment period",
122
+ captionLayout: "dropdown",
123
+ },
124
+ play: async ({ canvasElement }) => {
125
+ const canvas = within(canvasElement);
126
+
127
+ // Jumping back to a date years ago is a month/year select, not repeated
128
+ // prev-month clicks.
129
+ const trigger = canvas.getByRole("button", { name: "Employment period" });
130
+ await userEvent.click(trigger);
131
+ const dialog = await screen.findByRole("dialog");
132
+
133
+ const yearSelect = within(dialog).getByRole("combobox", { name: /year/i });
134
+ await userEvent.selectOptions(yearSelect, "2009");
135
+ const monthSelect = within(dialog).getByRole("combobox", { name: /month/i });
136
+ await userEvent.selectOptions(monthSelect, "May");
137
+
138
+ await userEvent.click(within(dialog).getByText("12"));
139
+ await expect(hiddenValue(canvasElement, "startDate")).toBe("2009-05-12");
140
+ },
141
+ };
142
+
105
143
  export const WithRangeDefaultValue: Story = {
106
144
  args: {
107
145
  mode: "range",
@@ -23,6 +23,7 @@ interface DateFieldCommonProps {
23
23
  containerClassName?: string;
24
24
  popoverAlign?: DatePickerProps["popoverAlign"];
25
25
  variant?: DatePickerProps["variant"];
26
+ captionLayout?: DatePickerProps["captionLayout"];
26
27
  }
27
28
 
28
29
  export interface SingleDateFieldProps extends DateFieldCommonProps {
@@ -55,6 +56,7 @@ function SingleDateField({
55
56
  containerClassName,
56
57
  popoverAlign,
57
58
  variant,
59
+ captionLayout,
58
60
  }: SingleDateFieldProps) {
59
61
  const generatedId = useId();
60
62
  const inputId = id ?? generatedId;
@@ -72,6 +74,7 @@ function SingleDateField({
72
74
  containerClassName={containerClassName}
73
75
  popoverAlign={popoverAlign}
74
76
  variant={variant}
77
+ captionLayout={captionLayout}
75
78
  value={value}
76
79
  onSelect={setValue}
77
80
  />
@@ -93,6 +96,7 @@ function RangeDateField({
93
96
  containerClassName = "flex-1 min-w-0",
94
97
  popoverAlign = "start",
95
98
  variant = "outline",
99
+ captionLayout = "label",
96
100
  }: RangeDateFieldProps) {
97
101
  const generatedId = useId();
98
102
  const inputId = id ?? generatedId;
@@ -140,6 +144,7 @@ function RangeDateField({
140
144
  defaultMonth={range.from ?? range.to}
141
145
  resetOnSelect
142
146
  onSelect={(next) => setRange({ from: next?.from, to: next?.to })}
147
+ captionLayout={captionLayout}
143
148
  />
144
149
  </PopoverContent>
145
150
  </Popover>
@@ -17,6 +17,12 @@ export interface DatePickerProps {
17
17
  containerClassName?: string;
18
18
  popoverAlign?: "start" | "center" | "end";
19
19
  variant?: "outline" | "default" | "destructive" | "secondary" | "ghost" | "link";
20
+ /**
21
+ * Calendar caption style. `"dropdown"` swaps the month/year label for
22
+ * select dropdowns, which is much faster for picking dates years in the
23
+ * past (e.g. a job start date) than clicking prev/next repeatedly.
24
+ */
25
+ captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years";
20
26
  }
21
27
 
22
28
  export function DatePicker({
@@ -31,6 +37,7 @@ export function DatePicker({
31
37
  containerClassName = "flex-1 min-w-0",
32
38
  popoverAlign = "start",
33
39
  variant = "outline",
40
+ captionLayout = "label",
34
41
  }: DatePickerProps) {
35
42
  return (
36
43
  <div className={containerClassName}>
@@ -60,7 +67,13 @@ export function DatePicker({
60
67
  align={popoverAlign}
61
68
  aria-label={label ?? "Choose a date"}
62
69
  >
63
- <Calendar mode="single" selected={value} defaultMonth={value} onSelect={onSelect} />
70
+ <Calendar
71
+ mode="single"
72
+ selected={value}
73
+ defaultMonth={value}
74
+ onSelect={onSelect}
75
+ captionLayout={captionLayout}
76
+ />
64
77
  </PopoverContent>
65
78
  </Popover>
66
79
  </div>