@tedi-design-system/react 17.1.0-rc.7 → 17.1.0-rc.8

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.
Files changed (35) hide show
  1. package/bundle-stats.html +1 -1
  2. package/index.css +1 -1
  3. package/package.json +1 -1
  4. package/src/tedi/components/form/choice-group/components/choice-group-item/choice-group-item.cjs.js +1 -1
  5. package/src/tedi/components/form/choice-group/components/choice-group-item/choice-group-item.es.js +70 -70
  6. package/src/tedi/components/form/textfield/textfield.cjs.js +1 -1
  7. package/src/tedi/components/form/textfield/textfield.es.js +110 -110
  8. package/src/tedi/components/form/time-field/time-field-helpers.cjs.js +1 -0
  9. package/src/tedi/components/form/time-field/time-field-helpers.d.ts +51 -0
  10. package/src/tedi/components/form/time-field/time-field-helpers.es.js +65 -0
  11. package/src/tedi/components/form/time-field/time-field.cjs.js +1 -0
  12. package/src/tedi/components/form/time-field/time-field.d.ts +87 -0
  13. package/src/tedi/components/form/time-field/time-field.es.js +149 -0
  14. package/src/tedi/components/form/time-field/time-field.module.scss.cjs.js +1 -0
  15. package/src/tedi/components/form/time-field/time-field.module.scss.es.js +10 -0
  16. package/src/tedi/components/form/time-picker/components/time-grid/time-grid.cjs.js +1 -0
  17. package/src/tedi/components/form/time-picker/components/time-grid/time-grid.d.ts +38 -0
  18. package/src/tedi/components/form/time-picker/components/time-grid/time-grid.es.js +101 -0
  19. package/src/tedi/components/form/time-picker/components/time-wheel/time-wheel.cjs.js +1 -0
  20. package/src/tedi/components/form/time-picker/components/time-wheel/time-wheel.d.ts +40 -0
  21. package/src/tedi/components/form/time-picker/components/time-wheel/time-wheel.es.js +184 -0
  22. package/src/tedi/components/form/time-picker/time-picker.cjs.js +1 -0
  23. package/src/tedi/components/form/time-picker/time-picker.d.ts +60 -0
  24. package/src/tedi/components/form/time-picker/time-picker.es.js +45 -0
  25. package/src/tedi/components/form/time-picker/time-picker.module.scss.cjs.js +1 -0
  26. package/src/tedi/components/form/time-picker/time-picker.module.scss.es.js +14 -0
  27. package/src/tedi/components/overlays/dropdown/dropdown.cjs.js +1 -1
  28. package/src/tedi/components/overlays/dropdown/dropdown.d.ts +9 -0
  29. package/src/tedi/components/overlays/dropdown/dropdown.es.js +98 -88
  30. package/src/tedi/index.d.ts +2 -0
  31. package/src/tedi/providers/label-provider/labels-map.cjs.js +1 -1
  32. package/src/tedi/providers/label-provider/labels-map.d.ts +7 -0
  33. package/src/tedi/providers/label-provider/labels-map.es.js +9 -2
  34. package/tedi.cjs.js +1 -1
  35. package/tedi.es.js +170 -166
@@ -0,0 +1,65 @@
1
+ const u = 40, l = 6, d = () => Array.from({ length: 24 }, (n, t) => t.toString().padStart(2, "0")), m = (n) => {
2
+ const t = Math.max(1, n ?? 1), r = [];
3
+ for (let e = 0; e < 60; e += t)
4
+ r.push(e.toString().padStart(2, "0"));
5
+ return r;
6
+ }, f = (n, t) => {
7
+ if (!t.length) return "00";
8
+ const r = Number(n);
9
+ return isNaN(r) ? t[0] : t.reduce((e, s) => {
10
+ const o = Math.abs(Number(s) - r), a = Math.abs(Number(e) - r);
11
+ return o < a || o === a && Number(s) > Number(e) ? s : e;
12
+ }, t[0]);
13
+ }, h = (n) => {
14
+ if (!n.includes(":"))
15
+ return { hour: "00", minute: "00" };
16
+ const [t, r] = n.split(":");
17
+ return {
18
+ hour: t.padStart(2, "0"),
19
+ minute: r.padStart(2, "0")
20
+ };
21
+ }, p = (n, t) => {
22
+ const r = Math.round(n / 40);
23
+ return Math.max(0, Math.min(r, t - 1));
24
+ }, i = (n) => n * 40, T = (n, t, r = 1) => Math.abs(n - t) > r, g = (n, t, r = "auto") => {
25
+ n.scrollTo({
26
+ top: i(t),
27
+ behavior: r
28
+ });
29
+ }, S = (n) => {
30
+ n && clearTimeout(n);
31
+ }, c = (n) => n ? /^([01][0-9]|2[0-3]):[0-5][0-9]$/.test(n.trim()) : !1, I = (n) => {
32
+ const t = n.trim();
33
+ if (!t) return "";
34
+ if (c(t)) return t;
35
+ const r = t.replace(/[^0-9]/g, "");
36
+ if (r.length === 3) {
37
+ const e = r.slice(0, 1).padStart(2, "0"), s = r.slice(1), o = `${e}:${s}`;
38
+ return c(o) ? o : null;
39
+ }
40
+ if (r.length === 4) {
41
+ const e = r.slice(0, 2), s = r.slice(2), o = `${e}:${s}`;
42
+ return c(o) ? o : null;
43
+ }
44
+ if (t.includes(":")) {
45
+ const [e, s] = t.split(":"), o = parseInt(e, 10), a = parseInt(s, 10);
46
+ if (!isNaN(o) && !isNaN(a) && o >= 0 && o <= 23 && a >= 0 && a <= 59)
47
+ return `${o.toString().padStart(2, "0")}:${a.toString().padStart(2, "0")}`;
48
+ }
49
+ return null;
50
+ };
51
+ export {
52
+ u as ITEM_HEIGHT,
53
+ l as TIMEPICKER_OFFSET,
54
+ S as clearScrollTimeout,
55
+ f as findClosestMinute,
56
+ d as generateHours,
57
+ m as generateMinutes,
58
+ i as getScrollTopForIndex,
59
+ c as isValidTime,
60
+ T as needsScrollCorrection,
61
+ I as normalizeTime,
62
+ h as parseTime,
63
+ g as scrollToIndex,
64
+ p as snapToNearestItem
65
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),d=require("../../../../../external/@floating-ui/react/dist/floating-ui.react.cjs.js"),T=require("../../../../../external/classnames/index.cjs.js"),m=require("react"),B=require("../textfield/textfield.cjs.js"),ne=require("../time-picker/time-picker.cjs.js"),s=require("./time-field.module.scss.cjs.js"),O=require("./time-field-helpers.cjs.js"),re=require("../../../../../external/@floating-ui/dom/dist/floating-ui.dom.cjs.js"),C=require("../../../../../external/@floating-ui/react-dom/dist/floating-ui.react-dom.cjs.js"),oe=require("../../../helpers/hooks/use-breakpoint-props.cjs.js"),k=require("../../overlays/dropdown/dropdown.cjs.js"),E=v=>{const{getCurrentBreakpointProps:S}=oe.useBreakpointProps(v.defaultServerBreakpoint),{id:V,label:M,value:c,defaultValue:z,onChange:F,readOnly:u=!1,required:A,placeholder:H,inputProps:i,stepMinutes:K=1,className:I,availableTimes:l}=v,{useNativePicker:G=!1,timePickerTrigger:P="button",showPicker:a=!0,availableTimesVariant:q="grid-buttons"}=S(v),y=c!==void 0,[J,N]=m.useState(c??z??""),g=y?c:J,[_,b]=m.useState(!1),w=P==="input",r=G,L=d.useFloating({open:_,onOpenChange:b,placement:w?"bottom-start":"bottom-end",middleware:[C.offset(O.TIMEPICKER_OFFSET),C.flip(),C.shift()],whileElementsMounted:re.autoUpdate}),{refs:j,context:p,x:Q,y:W,strategy:X}=L,Y=d.useClick(p),Z=d.useDismiss(p),$=d.useRole(p,{role:"listbox"}),D=a&&w&&!u&&!r,R=d.useInteractions([...D?[Y]:[],Z,$]),x=e=>{const n=e.trim();y||N(n),F==null||F(n)},ee=e=>{var h;const n=e.target.value??"";(h=i==null?void 0:i.onBlur)==null||h.call(i,e);const o=O.normalizeTime(n);o!==null&&o!==n&&x(o)};m.useEffect(()=>{c!==void 0&&N(c)},[c]);const f=m.useRef(null);m.useEffect(()=>{var e;(e=f.current)!=null&&e.inner&&j.setReference(f.current.inner)},[j]);const te=()=>{var n;const e=(n=f.current)==null?void 0:n.input;if(e){if(typeof e.showPicker=="function"){e.showPicker();return}e.focus()}},ie=()=>b(e=>!e),U={...i,id:V,label:M,value:g,placeholder:H,readOnly:u||!r&&w,icon:"schedule",isClearable:!0,required:A,onIconClick:()=>{u||!a||(r?te():P==="button"&&ie())},onChange:x,onBlur:ee,className:T.default(s.default["tedi-time-field__textfield"],{[s.default["tedi-time-field__icon--disabled"]]:!a||u},{[s.default["tedi-time-field__textfield--disabled"]]:i==null?void 0:i.disabled},{[s.default["tedi-time-field--native"]]:r}),input:{...i==null?void 0:i.input,...r&&{type:"time"}}};if(!r&&a&&!u&&q==="dropdown"&&!!(l!=null&&l.length)){const e=l.indexOf(g),n=e>=0?e:0;return t.jsxs(k.Dropdown,{width:"trigger",defaultActiveIndex:n,children:[t.jsx(k.Dropdown.Trigger,{children:t.jsx("div",{className:T.default(s.default["tedi-time-field__container"],I,{[s.default["tedi-time-field__container--native"]]:r}),children:t.jsx(B.TextField,{ref:f,...U})})}),t.jsx(k.Dropdown.Content,{children:l.map((o,h)=>t.jsx(k.Dropdown.Item,{index:h,active:o===g,onClick:()=>x(o),children:o},o))})]})}return t.jsxs(t.Fragment,{children:[t.jsx("div",{className:T.default(s.default["tedi-time-field__container"],I),...D?R.getReferenceProps():{},"aria-haspopup":a?"listbox":void 0,tabIndex:-1,children:t.jsx(B.TextField,{ref:f,"aria-expanded":a?_:void 0,...U})}),!r&&a&&t.jsx(d.FloatingPortal,{children:_&&!u&&t.jsx(d.FloatingFocusManager,{context:p,modal:!1,initialFocus:-1,children:t.jsx("div",{ref:j.setFloating,...R.getFloatingProps({style:{position:X,top:W??0,left:Q??0}}),children:t.jsx(ne.TimePicker,{value:g,stepMinutes:K,availableTimes:l,onChange:e=>{x(e),l&&b(!1)},gridVariant:q==="grid-radio"?"radio":"button",className:s.default["tedi-time-field__picker-wrapper"]})})})})]})};E.displayName="TimeField";exports.TimeField=E;
@@ -0,0 +1,87 @@
1
+ import { default as React } from 'react';
2
+ import { BreakpointSupport } from '../../../helpers';
3
+ import { TextFieldProps } from '../textfield/textfield';
4
+ type TimeFieldBreakpointProps = {
5
+ /**
6
+ * If `true`, the field swaps the custom time-picker popover for the
7
+ * browser's native time picker (`<input type="time">`). Works on both
8
+ * mobile and desktop — useful when the consumer wants to skip the custom
9
+ * UI entirely.
10
+ * Note: When using the native picker, the `availableTimes` prop is ignored.
11
+ * @default false
12
+ */
13
+ useNativePicker?: boolean;
14
+ /**
15
+ * Determines how the time picker is triggered:
16
+ * - 'button' (default) – only clicking the icon opens the picker
17
+ * - 'input' – clicking anywhere in the input opens the picker
18
+ */
19
+ timePickerTrigger?: 'input' | 'button';
20
+ /**
21
+ * Enables or disables the time picker popover.
22
+ * @default true
23
+ */
24
+ showPicker?: boolean;
25
+ /**
26
+ * Variant of the available times:
27
+ * - 'grid-buttons' – buttons grid
28
+ * - 'grid-radio' – radio buttons grid
29
+ * - 'dropdown' – dropdown list
30
+ */
31
+ availableTimesVariant?: 'grid-buttons' | 'grid-radio' | 'dropdown';
32
+ };
33
+ export interface TimeFieldProps extends BreakpointSupport<TimeFieldBreakpointProps> {
34
+ /**
35
+ * Unique identifier for the input field.
36
+ */
37
+ id: string;
38
+ /**
39
+ * Label for the input field. Used for accessibility.
40
+ */
41
+ label: string;
42
+ /**
43
+ * Current value of the time field (controlled).
44
+ */
45
+ value?: string;
46
+ /**
47
+ * Initial value of the time field (uncontrolled).
48
+ */
49
+ defaultValue?: string;
50
+ /**
51
+ * Callback fired when the time value changes.
52
+ */
53
+ onChange?: (time: string) => void;
54
+ /**
55
+ * Makes the input read-only. Picker can still be opened if showPicker is true.
56
+ * @default false
57
+ */
58
+ readOnly?: boolean;
59
+ /**
60
+ * Marks the input as required.
61
+ */
62
+ required?: boolean;
63
+ /**
64
+ * Placeholder text for the input field.
65
+ */
66
+ placeholder?: string;
67
+ /**
68
+ * Additional props to pass to the underlying TextField component,
69
+ * excluding `id`, `label`, `value`, and `onChange`.
70
+ */
71
+ inputProps?: Omit<TextFieldProps, 'id' | 'label' | 'value' | 'onChange'>;
72
+ /**
73
+ * Step interval in minutes for the time picker.
74
+ * @default 1
75
+ */
76
+ stepMinutes?: number;
77
+ /**
78
+ * Additional CSS class for the container.
79
+ */
80
+ className?: string;
81
+ /**
82
+ * Array of available times to show in the picker or dropdown.
83
+ */
84
+ availableTimes?: string[];
85
+ }
86
+ export declare const TimeField: React.FC<TimeFieldProps>;
87
+ export {};
@@ -0,0 +1,149 @@
1
+ import { jsxs as O, jsx as i, Fragment as te } from "react/jsx-runtime";
2
+ import { useFloating as ie, useClick as ne, useDismiss as oe, useRole as re, useInteractions as le, FloatingPortal as se, FloatingFocusManager as ae } from "../../../../../external/@floating-ui/react/dist/floating-ui.react.es.js";
3
+ import C from "../../../../../external/classnames/index.es.js";
4
+ import ce, { useState as V, useEffect as E } from "react";
5
+ import { TextField as U } from "../textfield/textfield.es.js";
6
+ import { TimePicker as de } from "../time-picker/time-picker.es.js";
7
+ import l from "./time-field.module.scss.es.js";
8
+ import { TIMEPICKER_OFFSET as fe, normalizeTime as ue } from "./time-field-helpers.es.js";
9
+ import { autoUpdate as me } from "../../../../../external/@floating-ui/dom/dist/floating-ui.dom.es.js";
10
+ import { offset as pe, flip as ge, shift as he } from "../../../../../external/@floating-ui/react-dom/dist/floating-ui.react-dom.es.js";
11
+ import { useBreakpointProps as ke } from "../../../helpers/hooks/use-breakpoint-props.es.js";
12
+ import { Dropdown as h } from "../../overlays/dropdown/dropdown.es.js";
13
+ const ve = (k) => {
14
+ const { getCurrentBreakpointProps: D } = ke(k.defaultServerBreakpoint), {
15
+ id: M,
16
+ label: S,
17
+ value: c,
18
+ defaultValue: j,
19
+ onChange: v,
20
+ readOnly: d = !1,
21
+ required: q,
22
+ placeholder: z,
23
+ inputProps: t,
24
+ stepMinutes: A = 1,
25
+ className: I,
26
+ availableTimes: s
27
+ } = k, {
28
+ useNativePicker: K = !1,
29
+ timePickerTrigger: w = "button",
30
+ showPicker: a = !0,
31
+ availableTimesVariant: T = "grid-buttons"
32
+ } = D(k), P = c !== void 0, [G, N] = V(c ?? j ?? ""), u = P ? c : G, [x, _] = V(!1), F = w === "input", o = K, H = ie({
33
+ open: x,
34
+ onOpenChange: _,
35
+ placement: F ? "bottom-start" : "bottom-end",
36
+ middleware: [pe(fe), ge(), he()],
37
+ whileElementsMounted: me
38
+ }), { refs: b, context: m, x: J, y: L, strategy: Q } = H, W = ne(m), X = oe(m), Y = re(m, { role: "listbox" }), y = a && F && !d && !o, R = le([...y ? [W] : [], X, Y]), p = (e) => {
39
+ const n = e.trim();
40
+ P || N(n), v == null || v(n);
41
+ }, Z = (e) => {
42
+ var g;
43
+ const n = e.target.value ?? "";
44
+ (g = t == null ? void 0 : t.onBlur) == null || g.call(t, e);
45
+ const r = ue(n);
46
+ r !== null && r !== n && p(r);
47
+ };
48
+ E(() => {
49
+ c !== void 0 && N(c);
50
+ }, [c]);
51
+ const f = ce.useRef(null);
52
+ E(() => {
53
+ var e;
54
+ (e = f.current) != null && e.inner && b.setReference(f.current.inner);
55
+ }, [b]);
56
+ const $ = () => {
57
+ var n;
58
+ const e = (n = f.current) == null ? void 0 : n.input;
59
+ if (e) {
60
+ if (typeof e.showPicker == "function") {
61
+ e.showPicker();
62
+ return;
63
+ }
64
+ e.focus();
65
+ }
66
+ }, ee = () => _((e) => !e), B = {
67
+ ...t,
68
+ id: M,
69
+ label: S,
70
+ value: u,
71
+ placeholder: z,
72
+ readOnly: d || !o && F,
73
+ icon: "schedule",
74
+ isClearable: !0,
75
+ required: q,
76
+ onIconClick: () => {
77
+ d || !a || (o ? $() : w === "button" && ee());
78
+ },
79
+ onChange: p,
80
+ onBlur: Z,
81
+ className: C(
82
+ l["tedi-time-field__textfield"],
83
+ { [l["tedi-time-field__icon--disabled"]]: !a || d },
84
+ { [l["tedi-time-field__textfield--disabled"]]: t == null ? void 0 : t.disabled },
85
+ { [l["tedi-time-field--native"]]: o }
86
+ ),
87
+ input: {
88
+ ...t == null ? void 0 : t.input,
89
+ ...o && { type: "time" }
90
+ }
91
+ };
92
+ if (!o && a && !d && T === "dropdown" && !!(s != null && s.length)) {
93
+ const e = s.indexOf(u), n = e >= 0 ? e : 0;
94
+ return /* @__PURE__ */ O(h, { width: "trigger", defaultActiveIndex: n, children: [
95
+ /* @__PURE__ */ i(h.Trigger, { children: /* @__PURE__ */ i(
96
+ "div",
97
+ {
98
+ className: C(l["tedi-time-field__container"], I, {
99
+ [l["tedi-time-field__container--native"]]: o
100
+ }),
101
+ children: /* @__PURE__ */ i(U, { ref: f, ...B })
102
+ }
103
+ ) }),
104
+ /* @__PURE__ */ i(h.Content, { children: s.map((r, g) => /* @__PURE__ */ i(h.Item, { index: g, active: r === u, onClick: () => p(r), children: r }, r)) })
105
+ ] });
106
+ }
107
+ return /* @__PURE__ */ O(te, { children: [
108
+ /* @__PURE__ */ i(
109
+ "div",
110
+ {
111
+ className: C(l["tedi-time-field__container"], I),
112
+ ...y ? R.getReferenceProps() : {},
113
+ "aria-haspopup": a ? "listbox" : void 0,
114
+ tabIndex: -1,
115
+ children: /* @__PURE__ */ i(U, { ref: f, "aria-expanded": a ? x : void 0, ...B })
116
+ }
117
+ ),
118
+ !o && a && /* @__PURE__ */ i(se, { children: x && !d && /* @__PURE__ */ i(ae, { context: m, modal: !1, initialFocus: -1, children: /* @__PURE__ */ i(
119
+ "div",
120
+ {
121
+ ref: b.setFloating,
122
+ ...R.getFloatingProps({
123
+ style: {
124
+ position: Q,
125
+ top: L ?? 0,
126
+ left: J ?? 0
127
+ }
128
+ }),
129
+ children: /* @__PURE__ */ i(
130
+ de,
131
+ {
132
+ value: u,
133
+ stepMinutes: A,
134
+ availableTimes: s,
135
+ onChange: (e) => {
136
+ p(e), s && _(!1);
137
+ },
138
+ gridVariant: T === "grid-radio" ? "radio" : "button",
139
+ className: l["tedi-time-field__picker-wrapper"]
140
+ }
141
+ )
142
+ }
143
+ ) }) })
144
+ ] });
145
+ };
146
+ ve.displayName = "TimeField";
147
+ export {
148
+ ve as TimeField
149
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e={"tedi-time-field__textfield":"tedi-time-field__textfield-73806efe","tedi-time-field__textfield--disabled":"tedi-time-field__textfield--disabled-86b8b11c","tedi-time-field__container":"tedi-time-field__container-45902dd9","tedi-time-field__icon--disabled":"tedi-time-field__icon--disabled-1c2b77ca","tedi-time-field__picker-wrapper":"tedi-time-field__picker-wrapper-6dd90739"};exports.default=e;
@@ -0,0 +1,10 @@
1
+ const e = {
2
+ "tedi-time-field__textfield": "tedi-time-field__textfield-73806efe",
3
+ "tedi-time-field__textfield--disabled": "tedi-time-field__textfield--disabled-86b8b11c",
4
+ "tedi-time-field__container": "tedi-time-field__container-45902dd9",
5
+ "tedi-time-field__icon--disabled": "tedi-time-field__icon--disabled-1c2b77ca",
6
+ "tedi-time-field__picker-wrapper": "tedi-time-field__picker-wrapper-6dd90739"
7
+ };
8
+ export {
9
+ e as default
10
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),d=require("react"),h=require("../../../../../../../external/classnames/index.cjs.js"),R=require("../../../../buttons/button/button.cjs.js"),A=require("../../../choice-group/choice-group.cjs.js"),u=require("../../time-picker.module.scss.cjs.js"),C=require("../../../../../providers/label-provider/use-labels.cjs.js"),G=require("../../../../layout/grid/row.cjs.js"),I=require("../../../../layout/grid/col.cjs.js"),k=({times:m,value:o,onSelect:f,className:w,colWidth:a={xs:6,md:4},variant:p="button",bordered:x=!0})=>{const l=d.useId(),{getLabel:q}=C.useLabels(),s=d.useRef(null);d.useEffect(()=>{if(!o)return;const e=s.current;if(!e)return;const r=e.querySelector(`input[type="radio"][value="${o}"], button[data-time="${o}"]`);r==null||r.focus({preventScroll:!0})},[]);const _=e=>{var g;if(p!=="radio")return;const r=s.current;if(!r)return;const t=Array.from(r.querySelectorAll('input[type="radio"]:not([disabled])'));if(t.length===0)return;const i=t.findIndex(j=>j===document.activeElement);let n;switch(e.key){case"ArrowDown":case"ArrowRight":n=i<0||i===t.length-1?0:i+1;break;case"ArrowUp":case"ArrowLeft":n=i<=0?t.length-1:i-1;break;case"Home":n=0;break;case"End":n=t.length-1;break;default:return}e.preventDefault(),(g=t[n])==null||g.focus()},b=h.default(u.default["tedi-time-picker__grid"],{[u.default["tedi-time-picker__grid--borderless"]]:!x},w),y=typeof a=="object"?a:{width:a};return p==="radio"?c.jsx("div",{ref:s,className:b,onKeyDown:_,children:c.jsx(A.ChoiceGroup,{id:`time-picker-group-${l}`,label:q("timePicker.pickTime"),inputType:"radio",name:`time-grid-${l}`,value:o,onChange:e=>f(e),items:m.map(e=>({id:`time-${l}-${e}`,label:e,value:e,colProps:y})),direction:"row",variant:"card",showIndicator:!0,color:"secondary",hideLabel:!0})}):c.jsx("div",{ref:s,className:b,children:c.jsx(G.Row,{gutter:2,children:m.map(e=>d.createElement(I.Col,{...y,key:e},c.jsx(R.Button,{noStyle:!0,"data-time":e,className:h.default(u.default["tedi-time-picker__grid-item"],{[u.default["tedi-time-picker__grid-item--selected"]]:e===o}),onClick:()=>f(e),children:e})))})})};k.displayName="TimeGrid";exports.TimeGrid=k;
@@ -0,0 +1,38 @@
1
+ import { ColProps, ColSize } from '../../../../layout/grid';
2
+ export interface TimeGridProps {
3
+ /**
4
+ * Times in HH:mm format
5
+ */
6
+ times: string[];
7
+ /**
8
+ * Selected value
9
+ */
10
+ value?: string;
11
+ /**
12
+ * Selection handler
13
+ */
14
+ onSelect: (time: string) => void;
15
+ /**
16
+ * Grid column width per time slot. Accepts either:
17
+ *
18
+ * - a single `ColSize` (1–12 or `'auto'`) applied at every breakpoint, or
19
+ * - a breakpoint object (`{ xs?, sm?, md?, lg?, xl?, xxl? }`) for responsive
20
+ * layouts.
21
+ *
22
+ * Default is `{ xs: 6, md: 4 }` — 2 slots per row on phones (where 33%
23
+ * is too narrow for the radio card's intrinsic content width and would
24
+ * otherwise wrap one-per-row), 3 slots per row from `md` up.
25
+ */
26
+ colWidth?: ColSize | Pick<ColProps, 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'>;
27
+ /**
28
+ * Display mode
29
+ */
30
+ variant?: 'button' | 'radio';
31
+ className?: string;
32
+ /**
33
+ * Whether to render the surrounding card chrome (border, background, radius).
34
+ * @default true
35
+ */
36
+ bordered?: boolean;
37
+ }
38
+ export declare const TimeGrid: React.FC<TimeGridProps>;
@@ -0,0 +1,101 @@
1
+ import { jsx as c } from "react/jsx-runtime";
2
+ import { useId as A, useRef as C, useEffect as I, createElement as N } from "react";
3
+ import h from "../../../../../../../external/classnames/index.es.js";
4
+ import { Button as $ } from "../../../../buttons/button/button.es.js";
5
+ import { ChoiceGroup as R } from "../../../choice-group/choice-group.es.js";
6
+ import d from "../../time-picker.module.scss.es.js";
7
+ import { useLabels as D } from "../../../../../providers/label-provider/use-labels.es.js";
8
+ import { Row as E } from "../../../../layout/grid/row.es.js";
9
+ import { Col as G } from "../../../../layout/grid/col.es.js";
10
+ const L = ({
11
+ times: l,
12
+ value: o,
13
+ onSelect: u,
14
+ className: k,
15
+ colWidth: a = { xs: 6, md: 4 },
16
+ variant: p = "button",
17
+ bordered: g = !0
18
+ }) => {
19
+ const m = A(), { getLabel: w } = D(), s = C(null);
20
+ I(() => {
21
+ if (!o) return;
22
+ const e = s.current;
23
+ if (!e) return;
24
+ const r = e.querySelector(
25
+ `input[type="radio"][value="${o}"], button[data-time="${o}"]`
26
+ );
27
+ r == null || r.focus({ preventScroll: !0 });
28
+ }, []);
29
+ const _ = (e) => {
30
+ var b;
31
+ if (p !== "radio") return;
32
+ const r = s.current;
33
+ if (!r) return;
34
+ const t = Array.from(r.querySelectorAll('input[type="radio"]:not([disabled])'));
35
+ if (t.length === 0) return;
36
+ const i = t.findIndex((x) => x === document.activeElement);
37
+ let n;
38
+ switch (e.key) {
39
+ case "ArrowDown":
40
+ case "ArrowRight":
41
+ n = i < 0 || i === t.length - 1 ? 0 : i + 1;
42
+ break;
43
+ case "ArrowUp":
44
+ case "ArrowLeft":
45
+ n = i <= 0 ? t.length - 1 : i - 1;
46
+ break;
47
+ case "Home":
48
+ n = 0;
49
+ break;
50
+ case "End":
51
+ n = t.length - 1;
52
+ break;
53
+ default:
54
+ return;
55
+ }
56
+ e.preventDefault(), (b = t[n]) == null || b.focus();
57
+ }, f = h(
58
+ d["tedi-time-picker__grid"],
59
+ {
60
+ [d["tedi-time-picker__grid--borderless"]]: !g
61
+ },
62
+ k
63
+ ), y = typeof a == "object" ? a : { width: a };
64
+ return p === "radio" ? /* @__PURE__ */ c("div", { ref: s, className: f, onKeyDown: _, children: /* @__PURE__ */ c(
65
+ R,
66
+ {
67
+ id: `time-picker-group-${m}`,
68
+ label: w("timePicker.pickTime"),
69
+ inputType: "radio",
70
+ name: `time-grid-${m}`,
71
+ value: o,
72
+ onChange: (e) => u(e),
73
+ items: l.map((e) => ({
74
+ id: `time-${m}-${e}`,
75
+ label: e,
76
+ value: e,
77
+ colProps: y
78
+ })),
79
+ direction: "row",
80
+ variant: "card",
81
+ showIndicator: !0,
82
+ color: "secondary",
83
+ hideLabel: !0
84
+ }
85
+ ) }) : /* @__PURE__ */ c("div", { ref: s, className: f, children: /* @__PURE__ */ c(E, { gutter: 2, children: l.map((e) => /* @__PURE__ */ N(G, { ...y, key: e }, /* @__PURE__ */ c(
86
+ $,
87
+ {
88
+ noStyle: !0,
89
+ "data-time": e,
90
+ className: h(d["tedi-time-picker__grid-item"], {
91
+ [d["tedi-time-picker__grid-item--selected"]]: e === o
92
+ }),
93
+ onClick: () => u(e),
94
+ children: e
95
+ }
96
+ ))) }) });
97
+ };
98
+ L.displayName = "TimeGrid";
99
+ export {
100
+ L as TimeGrid
101
+ };
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const E=require("react/jsx-runtime"),j=require("../../../../../../../external/classnames/index.cjs.js"),n=require("react"),t=require("../../../time-field/time-field-helpers.cjs.js"),p=require("../../time-picker.module.scss.cjs.js"),F=({hours:c,minutes:l,selectedHour:a,selectedMinute:s,onChange:x,className:P,bordered:L=!0})=>{const I=n.useId(),i=n.useRef(null),d=n.useRef(null),f=n.useRef(!1),m=n.useRef(!1),g=n.useRef(),k=n.useRef(),v=n.useRef(-1),b=n.useRef(-1),[M,R]=n.useState(null),[C,$]=n.useState(null),N=(r,e)=>Math.max(0,Math.min(e-1,r)),A=(r,e,o)=>{const T=r.current;if(!T||e<0)return;const w=t.getScrollTopForIndex(e);o?f.current=!0:m.current=!0,T.scrollTo({top:w,behavior:"instant"}),requestAnimationFrame(()=>{o?f.current=!1:m.current=!1})};n.useLayoutEffect(()=>{const r=c.indexOf(a),e=l.indexOf(s);r!==v.current&&(v.current=r,A(i,r,!0)),e!==b.current&&(b.current=e,A(d,e,!1)),R(r),$(e)},[c,l,a,s]);const q=n.useRef(()=>{});q.current=()=>{const r=i.current;if(!r||f.current)return;t.clearScrollTimeout(g.current);const e=N(t.snapToNearestItem(r.scrollTop,c.length),c.length);R(e);const o=t.getScrollTopForIndex(e);t.needsScrollCorrection(r.scrollTop,o,8)&&(f.current=!0,t.scrollToIndex(r,e,"instant"),requestAnimationFrame(()=>{f.current=!1})),e!==v.current&&(v.current=e,x(c[e],s))};const y=n.useRef(()=>{});y.current=()=>{const r=d.current;if(!r||m.current)return;t.clearScrollTimeout(k.current);const e=N(t.snapToNearestItem(r.scrollTop,l.length),l.length);$(e);const o=t.getScrollTopForIndex(e);t.needsScrollCorrection(r.scrollTop,o,8)&&(m.current=!0,t.scrollToIndex(r,e,"instant"),requestAnimationFrame(()=>{m.current=!1})),e!==b.current&&(b.current=e,x(a,l[e]))},n.useEffect(()=>{const r=i.current,e=d.current;if(!r||!e)return;const o=()=>q.current(),T=()=>y.current();return r.addEventListener("scrollend",o),e.addEventListener("scrollend",T),()=>{r.removeEventListener("scrollend",o),e.removeEventListener("scrollend",T)}},[]);const H=()=>{if(!i.current||f.current)return;const r=N(t.snapToNearestItem(i.current.scrollTop,c.length),c.length);R(r),t.clearScrollTimeout(g.current),g.current=setTimeout(()=>q.current(),150)},K=()=>{if(!d.current||m.current)return;const r=N(t.snapToNearestItem(d.current.scrollTop,l.length),l.length);$(r),t.clearScrollTimeout(k.current),k.current=setTimeout(()=>y.current(),150)},W=r=>{const e=c[r];!e||!i.current||(t.clearScrollTimeout(g.current),v.current=r,R(r),x(e,s),f.current=!0,t.scrollToIndex(i.current,r,"smooth"),setTimeout(()=>{f.current=!1},300))},U=r=>{const e=l[r];!e||!d.current||(t.clearScrollTimeout(k.current),b.current=r,$(r),x(a,e),m.current=!0,t.scrollToIndex(d.current,r,"smooth"),setTimeout(()=>{m.current=!1},300))},D=(r,e,o,T)=>w=>{const u=e.indexOf(o);if(u===-1)return;let h=-1,_=!1;switch(w.key){case"ArrowDown":h=(u+1)%e.length,_=u===e.length-1;break;case"ArrowUp":h=(u-1+e.length)%e.length,_=u===0;break;case"Home":h=0;break;case"End":h=e.length-1;break;case"PageDown":h=(u+5)%e.length,_=u+5>=e.length;break;case"PageUp":h=(u-5+e.length)%e.length,_=u-5<0;break;case"Enter":case" ":w.preventDefault(),T(e[u]);return;default:return}w.preventDefault();const O=r==="hour"?i.current:d.current,S=O==null?void 0:O.querySelector(`#${CSS.escape(`${I}-${r}-${h}`)}`);S==null||S.focus(),S==null||S.scrollIntoView({block:"center",behavior:_?"auto":"smooth"})};return n.useEffect(()=>()=>{t.clearScrollTimeout(g.current),t.clearScrollTimeout(k.current)},[]),E.jsxs("div",{className:j.default(p.default["tedi-time-picker__wheel"],{[p.default["tedi-time-picker__wheel--borderless"]]:!L},P),children:[E.jsx("div",{ref:i,role:"listbox","aria-label":"Hours",tabIndex:0,"aria-activedescendant":`${I}-hour-${c.indexOf(a)}`,className:p.default["tedi-time-picker__wheel-column"],onScroll:H,onKeyDown:D("hour",c,a,r=>x(r,s)),children:c.map((r,e)=>E.jsx("div",{className:j.default(p.default["tedi-time-picker__wheel-item"],{[p.default["tedi-time-picker__wheel-item--selected"]]:e===(M??c.indexOf(a))}),onClick:()=>W(e),id:`${I}-hour-${e}`,role:"option","aria-selected":r===a,children:r},r))}),E.jsx("div",{ref:d,role:"listbox",className:p.default["tedi-time-picker__wheel-column"],onScroll:K,"aria-label":"Minutes",tabIndex:0,"aria-activedescendant":`${I}-minute-${l.indexOf(s)}`,onKeyDown:D("minute",l,s,r=>x(a,r)),children:l.map((r,e)=>E.jsx("div",{className:j.default(p.default["tedi-time-picker__wheel-item"],{[p.default["tedi-time-picker__wheel-item--selected"]]:e===(C??l.indexOf(s))}),onClick:()=>U(e),id:`${I}-minute-${e}`,role:"option","aria-selected":r===s,children:r},r))})]})};F.displayName="TimeWheel";exports.TimeWheel=F;
@@ -0,0 +1,40 @@
1
+ import { default as React } from 'react';
2
+ export interface TimeWheelProps {
3
+ /**
4
+ * Array of all available hours (normally ["00", "01", ..., "23"]).
5
+ */
6
+ hours: string[];
7
+ /**
8
+ * Array of available minutes based on the `stepMinutes` value
9
+ * (e.g. ["00", "05", "10", ..., "55"] when step is 5).
10
+ */
11
+ minutes: string[];
12
+ /**
13
+ * The currently selected hour ("00" to "23").
14
+ * Used to control the scroll position of the hour wheel.
15
+ */
16
+ selectedHour: string;
17
+ /**
18
+ * The currently selected minute.
19
+ * Must exist in the `minutes` array.
20
+ * Used to control the scroll position of the minute wheel.
21
+ */
22
+ selectedMinute: string;
23
+ /**
24
+ * Callback fired when the user changes either the hour or minute via scrolling or clicking.
25
+ *
26
+ * @param hour - Selected hour in "HH" format
27
+ * @param minute - Selected minute in "mm" format
28
+ */
29
+ onChange: (hour: string, minute: string) => void;
30
+ /**
31
+ * Additional CSS class name to apply to the root wheel container.
32
+ */
33
+ className?: string;
34
+ /**
35
+ * Whether to render the surrounding card chrome (border, background, radius).
36
+ * @default true
37
+ */
38
+ bordered?: boolean;
39
+ }
40
+ export declare const TimeWheel: React.FC<TimeWheelProps>;