@altimateai/ui-components 0.0.30 → 0.0.31-beta.2

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.
@@ -0,0 +1,179 @@
1
+ import { Meta, StoryFn } from "@storybook/react";
2
+ import { DebouncedInput, DebouncedInputProps } from "./DebouncedInput";
3
+ import { useState } from "react";
4
+ import { IconSearch, IconUser, IconMail } from "@tabler/icons-react";
5
+
6
+ export default {
7
+ title: "Shadcn/Components/DebouncedInput",
8
+ component: DebouncedInput,
9
+ argTypes: {
10
+ disabled: {
11
+ control: "boolean",
12
+ },
13
+ type: {
14
+ control: "select",
15
+ options: ["text", "password", "email", "number"],
16
+ },
17
+ iconPosition: {
18
+ control: "select",
19
+ options: ["left", "right"],
20
+ },
21
+ debounceMs: {
22
+ control: "number",
23
+ },
24
+ },
25
+ } as Meta<typeof DebouncedInput>;
26
+
27
+ const Template: StoryFn<DebouncedInputProps> = (args: DebouncedInputProps) => {
28
+ const [debouncedValue, setDebouncedValue] = useState("");
29
+
30
+ return (
31
+ <div className="al-p-4 al-max-w-md al-space-y-4">
32
+ <DebouncedInput
33
+ {...args}
34
+ onChange={newValue => {
35
+ setDebouncedValue(newValue);
36
+ args.onChange?.(newValue);
37
+ }}
38
+ />
39
+ <div className="al-space-y-2 al-text-sm">
40
+ <div>
41
+ <strong>Debounced Value:</strong>{" "}
42
+ <code className="al-bg-gray-100 al-px-1 al-rounded">{debouncedValue || "empty"}</code>
43
+ </div>
44
+ <div>
45
+ <strong>Debounce Delay:</strong>{" "}
46
+ <code className="al-bg-gray-100 al-px-1 al-rounded">{args.debounceMs || 0}ms</code>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ );
51
+ };
52
+
53
+ export const Default = Template.bind({});
54
+ Default.args = {
55
+ placeholder: "Type something...",
56
+ debounceMs: 0,
57
+ };
58
+
59
+ export const WithDebounce300ms = Template.bind({});
60
+ WithDebounce300ms.args = {
61
+ placeholder: "Search with 300ms debounce...",
62
+ debounceMs: 300,
63
+ };
64
+
65
+ export const WithDebounce500ms = Template.bind({});
66
+ WithDebounce500ms.args = {
67
+ placeholder: "Search with 500ms debounce...",
68
+ debounceMs: 500,
69
+ };
70
+
71
+ export const WithDebounce1000ms = Template.bind({});
72
+ WithDebounce1000ms.args = {
73
+ placeholder: "Search with 1000ms debounce...",
74
+ debounceMs: 1000,
75
+ };
76
+
77
+ export const SearchWithIcon = Template.bind({});
78
+ SearchWithIcon.args = {
79
+ placeholder: "Search users...",
80
+ icon: IconSearch,
81
+ iconPosition: "left",
82
+ debounceMs: 300,
83
+ };
84
+
85
+ export const EmailWithDebounce = Template.bind({});
86
+ EmailWithDebounce.args = {
87
+ type: "email",
88
+ placeholder: "Enter email...",
89
+ icon: IconMail,
90
+ iconPosition: "left",
91
+ debounceMs: 500,
92
+ };
93
+
94
+ export const UserSearchWithIcon = Template.bind({});
95
+ UserSearchWithIcon.args = {
96
+ placeholder: "Search for users...",
97
+ icon: IconUser,
98
+ iconPosition: "left",
99
+ debounceMs: 400,
100
+ };
101
+
102
+ // Interactive example showing real-time vs debounced updates
103
+ const InteractiveTemplate: StoryFn<DebouncedInputProps> = (args: DebouncedInputProps) => {
104
+ const [realTimeValue, setRealTimeValue] = useState("");
105
+ const [debouncedValue, setDebouncedValue] = useState("");
106
+ const [updateCount, setUpdateCount] = useState(0);
107
+ const [debouncedUpdateCount, setDebouncedUpdateCount] = useState(0);
108
+
109
+ return (
110
+ <div className="al-p-4 al-max-w-lg al-space-y-6">
111
+ <div className="al-space-y-4">
112
+ <div>
113
+ <label className="al-block al-text-sm al-font-medium al-mb-2">
114
+ Real-time Input (no debounce)
115
+ </label>
116
+ <DebouncedInput
117
+ placeholder="Type here for real-time updates..."
118
+ debounceMs={0}
119
+ onChange={value => {
120
+ setRealTimeValue(value);
121
+ setUpdateCount(prev => prev + 1);
122
+ }}
123
+ />
124
+ </div>
125
+
126
+ <div>
127
+ <label className="al-block al-text-sm al-font-medium al-mb-2">
128
+ Debounced Input ({args.debounceMs}ms delay)
129
+ </label>
130
+ <DebouncedInput
131
+ {...args}
132
+ onChange={value => {
133
+ setDebouncedValue(value);
134
+ setDebouncedUpdateCount(prev => prev + 1);
135
+ }}
136
+ />
137
+ </div>
138
+ </div>
139
+
140
+ <div className="al-grid al-grid-cols-2 al-gap-4 al-text-sm">
141
+ <div className="al-space-y-2">
142
+ <h4 className="al-font-semibold">Real-time Updates</h4>
143
+ <div>
144
+ Value:{" "}
145
+ <code className="al-bg-gray-100 al-px-1 al-rounded">{realTimeValue || "empty"}</code>
146
+ </div>
147
+ <div>
148
+ Updates: <code className="al-bg-blue-100 al-px-1 al-rounded">{updateCount}</code>
149
+ </div>
150
+ </div>
151
+
152
+ <div className="al-space-y-2">
153
+ <h4 className="al-font-semibold">Debounced Updates</h4>
154
+ <div>
155
+ Value:{" "}
156
+ <code className="al-bg-gray-100 al-px-1 al-rounded">{debouncedValue || "empty"}</code>
157
+ </div>
158
+ <div>
159
+ Updates:{" "}
160
+ <code className="al-bg-green-100 al-px-1 al-rounded">{debouncedUpdateCount}</code>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <div className="al-text-xs al-text-gray-600">
166
+ Type quickly to see the difference between real-time and debounced updates. The debounced
167
+ input will only trigger onChange after you stop typing for {args.debounceMs}ms.
168
+ </div>
169
+ </div>
170
+ );
171
+ };
172
+
173
+ export const InteractiveComparison = InteractiveTemplate.bind({});
174
+ InteractiveComparison.args = {
175
+ placeholder: "Type here for debounced updates...",
176
+ debounceMs: 500,
177
+ icon: IconSearch,
178
+ iconPosition: "left",
179
+ };
@@ -1,8 +1,20 @@
1
1
  import { Meta, StoryFn } from "@storybook/react";
2
2
  import { Input } from "../shadcn";
3
3
  import { InputHTMLAttributes } from "react";
4
+ import {
5
+ IconUser,
6
+ IconMail,
7
+ IconSearch,
8
+ IconLock,
9
+ IconPhone,
10
+ IconMapPin,
11
+ IconCreditCard,
12
+ } from "@tabler/icons-react";
4
13
 
5
- type InputProps = InputHTMLAttributes<HTMLInputElement>;
14
+ type InputProps = InputHTMLAttributes<HTMLInputElement> & {
15
+ icon?: React.ComponentType<{ size?: string | number; className?: string }>;
16
+ iconPosition?: "left" | "right";
17
+ };
6
18
 
7
19
  export default {
8
20
  title: "Shadcn/Components/Input",
@@ -15,10 +27,18 @@ export default {
15
27
  control: "select",
16
28
  options: ["text", "password", "email", "number"],
17
29
  },
30
+ iconPosition: {
31
+ control: "select",
32
+ options: ["left", "right"],
33
+ },
18
34
  },
19
35
  } as Meta<typeof Input>;
20
36
 
21
- const Template: StoryFn<InputProps> = (args: InputProps) => <Input {...args} />;
37
+ const Template: StoryFn<InputProps> = (args: InputProps) => (
38
+ <div className="al-p-4 al-max-w-md">
39
+ <Input {...args} />
40
+ </div>
41
+ );
22
42
 
23
43
  export const Default = Template.bind({});
24
44
  Default.args = {
@@ -51,3 +71,70 @@ WithError.args = {
51
71
  className: "border-red-500",
52
72
  "aria-invalid": true,
53
73
  };
74
+
75
+ export const WithIconLeft = Template.bind({});
76
+ WithIconLeft.args = {
77
+ placeholder: "Search...",
78
+ icon: IconSearch,
79
+ iconPosition: "left",
80
+ };
81
+
82
+ export const WithIconRight = Template.bind({});
83
+ WithIconRight.args = {
84
+ placeholder: "Search...",
85
+ icon: IconSearch,
86
+ iconPosition: "right",
87
+ };
88
+
89
+ export const EmailWithIcon = Template.bind({});
90
+ EmailWithIcon.args = {
91
+ type: "email",
92
+ placeholder: "Enter your email",
93
+ icon: IconMail,
94
+ iconPosition: "left",
95
+ };
96
+
97
+ export const PasswordWithIcon = Template.bind({});
98
+ PasswordWithIcon.args = {
99
+ type: "password",
100
+ placeholder: "Enter password",
101
+ icon: IconLock,
102
+ iconPosition: "left",
103
+ };
104
+
105
+ export const UserInput = Template.bind({});
106
+ UserInput.args = {
107
+ placeholder: "Enter username",
108
+ icon: IconUser,
109
+ iconPosition: "left",
110
+ };
111
+
112
+ export const PhoneInput = Template.bind({});
113
+ PhoneInput.args = {
114
+ type: "tel",
115
+ placeholder: "Enter phone number",
116
+ icon: IconPhone,
117
+ iconPosition: "left",
118
+ };
119
+
120
+ export const AddressInput = Template.bind({});
121
+ AddressInput.args = {
122
+ placeholder: "Enter address",
123
+ icon: IconMapPin,
124
+ iconPosition: "left",
125
+ };
126
+
127
+ export const CreditCardInput = Template.bind({});
128
+ CreditCardInput.args = {
129
+ placeholder: "1234 5678 9012 3456",
130
+ icon: IconCreditCard,
131
+ iconPosition: "left",
132
+ };
133
+
134
+ export const DisabledWithIcon = Template.bind({});
135
+ DisabledWithIcon.args = {
136
+ placeholder: "Disabled with icon",
137
+ icon: IconUser,
138
+ iconPosition: "left",
139
+ disabled: true,
140
+ };
@@ -1,4 +1,4 @@
1
- import { k as kt, p as vt, l as wt, m as rt, n as I, s as St, o as Et, q as Tt, r as et } from "./CoachForm.js";
1
+ import { q as kt, r as vt, v as wt, w as rt, x as I, y as St, z as Et, B as Tt, D as et } from "./CoachForm.js";
2
2
  import { s as q } from "./redux-toolkit.modern.js";
3
3
  import { i as It } from "./is_dark.js";
4
4
  var X = function() {
@@ -76,7 +76,7 @@ var X = function() {
76
76
  }
77
77
  },
78
78
  parse: function(r) {
79
- var a = this, h = [0], u = [], y = [null], c = [], M = this.table, x = "", N = 0, S = 0, L = 2, V = 1, H = c.slice.call(arguments, 1), m = Object.create(this.lexer), C = { yy: {} };
79
+ var a = this, h = [0], u = [], y = [null], c = [], M = this.table, x = "", N = 0, S = 0, L = 2, z = 1, H = c.slice.call(arguments, 1), m = Object.create(this.lexer), C = { yy: {} };
80
80
  for (var O in this.yy)
81
81
  Object.prototype.hasOwnProperty.call(this.yy, O) && (C.yy[O] = this.yy[O]);
82
82
  m.setInput(r, C.yy), C.yy.lexer = m, C.yy.parser = this, typeof m.yylloc > "u" && (m.yylloc = {});
@@ -86,17 +86,17 @@ var X = function() {
86
86
  typeof C.yy.parseError == "function" ? this.parseError = C.yy.parseError : this.parseError = Object.getPrototypeOf(this).parseError;
87
87
  function bt() {
88
88
  var P;
89
- return P = u.pop() || m.lex() || V, typeof P != "number" && (P instanceof Array && (u = P, P = u.pop()), P = a.symbols_[P] || P), P;
89
+ return P = u.pop() || m.lex() || z, typeof P != "number" && (P instanceof Array && (u = P, P = u.pop()), P = a.symbols_[P] || P), P;
90
90
  }
91
- for (var T, z, $, K, W = {}, j, A, tt, G; ; ) {
92
- if (z = h[h.length - 1], this.defaultActions[z] ? $ = this.defaultActions[z] : ((T === null || typeof T > "u") && (T = bt()), $ = M[z] && M[z][T]), typeof $ > "u" || !$.length || !$[0]) {
91
+ for (var T, V, $, K, W = {}, j, A, tt, G; ; ) {
92
+ if (V = h[h.length - 1], this.defaultActions[V] ? $ = this.defaultActions[V] : ((T === null || typeof T > "u") && (T = bt()), $ = M[V] && M[V][T]), typeof $ > "u" || !$.length || !$[0]) {
93
93
  var Q = "";
94
94
  G = [];
95
- for (j in M[z])
95
+ for (j in M[V])
96
96
  this.terminals_[j] && j > L && G.push("'" + this.terminals_[j] + "'");
97
97
  m.showPosition ? Q = "Parse error on line " + (N + 1) + `:
98
98
  ` + m.showPosition() + `
99
- Expecting ` + G.join(", ") + ", got '" + (this.terminals_[T] || T) + "'" : Q = "Parse error on line " + (N + 1) + ": Unexpected " + (T == V ? "end of input" : "'" + (this.terminals_[T] || T) + "'"), this.parseError(Q, {
99
+ Expecting ` + G.join(", ") + ", got '" + (this.terminals_[T] || T) + "'" : Q = "Parse error on line " + (N + 1) + ": Unexpected " + (T == z ? "end of input" : "'" + (this.terminals_[T] || T) + "'"), this.parseError(Q, {
100
100
  text: m.match,
101
101
  token: this.terminals_[T] || T,
102
102
  line: m.yylineno,
@@ -105,7 +105,7 @@ Expecting ` + G.join(", ") + ", got '" + (this.terminals_[T] || T) + "'" : Q = "
105
105
  });
106
106
  }
107
107
  if ($[0] instanceof Array && $.length > 1)
108
- throw new Error("Parse Error: multiple actions possible at state: " + z + ", token: " + T);
108
+ throw new Error("Parse Error: multiple actions possible at state: " + V + ", token: " + T);
109
109
  switch ($[0]) {
110
110
  case 1:
111
111
  h.push(T), y.push(m.yytext), c.push(m.yylloc), h.push($[1]), T = null, S = m.yyleng, x = m.yytext, N = m.yylineno, J = m.yylloc;
@@ -489,7 +489,7 @@ const Y = [], U = [], B = [], ct = () => kt, ot = (n, t, e) => {
489
489
  );
490
490
  };
491
491
  let it = -1;
492
- const Vt = function(n, t, e) {
492
+ const zt = function(n, t, e) {
493
493
  const s = t.x + e.width / 2, i = n.append("g");
494
494
  it++;
495
495
  const o = 300 + 5 * 30;
@@ -510,7 +510,7 @@ const Vt = function(n, t, e) {
510
510
  e,
511
511
  t.colour
512
512
  );
513
- }, zt = function(n, t) {
513
+ }, Vt = function(n, t) {
514
514
  Z(n, {
515
515
  x: t.startx,
516
516
  y: t.starty,
@@ -596,8 +596,8 @@ const Ft = function(n, t, e, s) {
596
596
  drawSection: Ct,
597
597
  drawText: ft,
598
598
  drawLabel: Ht,
599
- drawTask: Vt,
600
- drawBackgroundRect: zt,
599
+ drawTask: zt,
600
+ drawBackgroundRect: Vt,
601
601
  getTextObj: Rt,
602
602
  getNoteRect: D,
603
603
  initGraphics: Wt,
@@ -644,8 +644,8 @@ const Ft = function(n, t, e, s) {
644
644
  width: 150,
645
645
  padding: 20,
646
646
  maxHeight: w
647
- }, V = R.getVirtualNodeHeight(d, L, i);
648
- I.debug("taskHeight before draw", V), w = Math.max(w, V + 20), y = Math.max(y, S.events.length);
647
+ }, z = R.getVirtualNodeHeight(d, L, i);
648
+ I.debug("taskHeight before draw", z), w = Math.max(w, z + 20), y = Math.max(y, S.events.length);
649
649
  let H = 0;
650
650
  for (let m = 0; m < S.events.length; m++) {
651
651
  const O = {
@@ -670,8 +670,8 @@ const Ft = function(n, t, e, s) {
670
670
  maxHeight: b
671
671
  };
672
672
  I.debug("sectionNode", S);
673
- const L = d.append("g"), V = R.drawNode(L, S, h, i);
674
- I.debug("sectionNode output", V), L.attr("transform", `translate(${r}, ${k})`), a += b + 50;
673
+ const L = d.append("g"), z = R.drawNode(L, S, h, i);
674
+ I.debug("sectionNode output", z), L.attr("transform", `translate(${r}, ${k})`), a += b + 50;
675
675
  const H = f.filter((m) => m.section === N);
676
676
  H.length > 0 && st(
677
677
  d,