@almadar/ui 5.17.1 → 5.18.1

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.
@@ -9831,10 +9831,11 @@ function DayCell({
9831
9831
  onClick,
9832
9832
  className
9833
9833
  }) {
9834
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
9834
9835
  const handleClick = React98.useCallback(() => {
9835
- onClick?.(date);
9836
- }, [onClick, date]);
9837
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
9836
+ onClick?.(safeDate);
9837
+ }, [onClick, safeDate]);
9838
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
9838
9839
  return /* @__PURE__ */ jsxRuntime.jsxs(
9839
9840
  Box,
9840
9841
  {
@@ -9865,7 +9866,7 @@ function DayCell({
9865
9866
  "h-8 w-8 mx-auto items-center justify-center",
9866
9867
  isToday && "bg-blue-600 text-white"
9867
9868
  ),
9868
- children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
9869
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
9869
9870
  }
9870
9871
  )
9871
9872
  ]
@@ -56590,11 +56591,15 @@ function SlotContentRenderer({
56590
56591
  }
56591
56592
  if (propsSchema) {
56592
56593
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
56593
- const v = renderedProps[propKey];
56594
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
56594
+ const isDate = propDef.types?.some(
56595
56595
  (t) => t === "date" || t === "datetime" || t === "timestamp"
56596
- )) {
56596
+ );
56597
+ if (!isDate) continue;
56598
+ const v = renderedProps[propKey];
56599
+ if (typeof v === "string" || typeof v === "number") {
56597
56600
  renderedProps[propKey] = new Date(v);
56601
+ } else if (v == null && propDef.required) {
56602
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
56598
56603
  }
56599
56604
  }
56600
56605
  }
@@ -60286,12 +60291,26 @@ function collectEmbeddedTraits(schema) {
60286
60291
  }
60287
60292
  var lambdaLog = logger.createLogger("almadar:ui:fn-form-lambda");
60288
60293
  function isFnFormLambda(value) {
60289
- return Array.isArray(value) && value.length === 3 && value[0] === "fn" && typeof value[1] === "string" && value[2] !== null && typeof value[2] === "object";
60294
+ if (!Array.isArray(value)) return false;
60295
+ const arr = value;
60296
+ if (arr.length !== 3 || arr[0] !== "fn" || arr[2] === null || typeof arr[2] !== "object") {
60297
+ return false;
60298
+ }
60299
+ const params = arr[1];
60300
+ return typeof params === "string" || Array.isArray(params) && params.length > 0 && params.every((p2) => typeof p2 === "string");
60301
+ }
60302
+ function fnFormParams(value) {
60303
+ const p2 = value[1];
60304
+ if (typeof p2 === "string") return [p2];
60305
+ if (Array.isArray(p2)) return p2.filter((x) => typeof x === "string");
60306
+ return [];
60290
60307
  }
60291
- function resolveLambdaBindings(body, argName, arg) {
60292
- const prefix = `@${argName}.`;
60308
+ function resolveLambdaBindings(body, params, item, index) {
60309
+ const itemName = params[0];
60310
+ const indexName = params[1];
60311
+ const itemPrefix = itemName ? `@${itemName}.` : null;
60293
60312
  const lookup = (path) => {
60294
- let cur = arg;
60313
+ let cur = item;
60295
60314
  for (const seg of path.split(".")) {
60296
60315
  if (cur === null || cur === void 0) return void 0;
60297
60316
  if (typeof cur !== "object" || Array.isArray(cur)) return void 0;
@@ -60299,21 +60318,23 @@ function resolveLambdaBindings(body, argName, arg) {
60299
60318
  }
60300
60319
  return cur;
60301
60320
  };
60321
+ const recur = (b) => resolveLambdaBindings(b, params, item, index);
60302
60322
  if (typeof body === "string") {
60303
- if (body === `@${argName}`) return arg;
60304
- if (body.startsWith(prefix)) {
60305
- const v = lookup(body.slice(prefix.length));
60323
+ if (indexName && body === `@${indexName}`) return index;
60324
+ if (itemName && body === `@${itemName}`) return item;
60325
+ if (itemPrefix && body.startsWith(itemPrefix)) {
60326
+ const v = lookup(body.slice(itemPrefix.length));
60306
60327
  return v === void 0 || v === null ? "" : v;
60307
60328
  }
60308
60329
  return body;
60309
60330
  }
60310
60331
  if (Array.isArray(body)) {
60311
- return body.map((b) => resolveLambdaBindings(b, argName, arg));
60332
+ return body.map((b) => recur(b));
60312
60333
  }
60313
60334
  if (body !== null && typeof body === "object" && !React98__namespace.default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
60314
60335
  const out = {};
60315
60336
  for (const [k, v] of Object.entries(body)) {
60316
- out[k] = resolveLambdaBindings(v, argName, arg);
60337
+ out[k] = recur(v);
60317
60338
  }
60318
60339
  return out;
60319
60340
  }
@@ -60326,9 +60347,9 @@ function getSlotContentRenderer2() {
60326
60347
  _slotContentRenderer2 = mod.SlotContentRenderer;
60327
60348
  return _slotContentRenderer2;
60328
60349
  }
60329
- function makeLambdaFn(argName, lambdaBody, callerKey) {
60350
+ function makeLambdaFn(params, lambdaBody, callerKey) {
60330
60351
  return (item, index) => {
60331
- const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
60352
+ const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
60332
60353
  if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React98__namespace.default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
60333
60354
  return null;
60334
60355
  }
@@ -60355,8 +60376,8 @@ function convertNode(node, callerKey) {
60355
60376
  if (node === null || node === void 0) return node;
60356
60377
  if (Array.isArray(node)) {
60357
60378
  if (isFnFormLambda(node)) {
60358
- const [, argName, body] = node;
60359
- return makeLambdaFn(argName, body, callerKey);
60379
+ const arr2 = node;
60380
+ return makeLambdaFn(fnFormParams(arr2), arr2[2], callerKey);
60360
60381
  }
60361
60382
  const arr = node;
60362
60383
  let anyChanged = false;
@@ -60378,9 +60399,9 @@ function convertObjectProps(props) {
60378
60399
  for (const [key, value] of Object.entries(props)) {
60379
60400
  if (isFnFormLambda(value)) {
60380
60401
  convertedAny = true;
60381
- const [, argName, body] = value;
60402
+ const arr = value;
60382
60403
  const targetKey = key === "renderItem" ? "children" : key;
60383
- out[targetKey] = makeLambdaFn(argName, body, key);
60404
+ out[targetKey] = makeLambdaFn(fnFormParams(arr), arr[2], key);
60384
60405
  lambdaLog.debug(`convert key=${key} \u2192 ${targetKey}`);
60385
60406
  continue;
60386
60407
  }
package/dist/avl/index.js CHANGED
@@ -9782,10 +9782,11 @@ function DayCell({
9782
9782
  onClick,
9783
9783
  className
9784
9784
  }) {
9785
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
9785
9786
  const handleClick = useCallback(() => {
9786
- onClick?.(date);
9787
- }, [onClick, date]);
9788
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
9787
+ onClick?.(safeDate);
9788
+ }, [onClick, safeDate]);
9789
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
9789
9790
  return /* @__PURE__ */ jsxs(
9790
9791
  Box,
9791
9792
  {
@@ -9816,7 +9817,7 @@ function DayCell({
9816
9817
  "h-8 w-8 mx-auto items-center justify-center",
9817
9818
  isToday && "bg-blue-600 text-white"
9818
9819
  ),
9819
- children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
9820
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
9820
9821
  }
9821
9822
  )
9822
9823
  ]
@@ -56541,11 +56542,15 @@ function SlotContentRenderer({
56541
56542
  }
56542
56543
  if (propsSchema) {
56543
56544
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
56544
- const v = renderedProps[propKey];
56545
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
56545
+ const isDate = propDef.types?.some(
56546
56546
  (t) => t === "date" || t === "datetime" || t === "timestamp"
56547
- )) {
56547
+ );
56548
+ if (!isDate) continue;
56549
+ const v = renderedProps[propKey];
56550
+ if (typeof v === "string" || typeof v === "number") {
56548
56551
  renderedProps[propKey] = new Date(v);
56552
+ } else if (v == null && propDef.required) {
56553
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
56549
56554
  }
56550
56555
  }
56551
56556
  }
@@ -60237,12 +60242,26 @@ function collectEmbeddedTraits(schema) {
60237
60242
  }
60238
60243
  var lambdaLog = createLogger("almadar:ui:fn-form-lambda");
60239
60244
  function isFnFormLambda(value) {
60240
- return Array.isArray(value) && value.length === 3 && value[0] === "fn" && typeof value[1] === "string" && value[2] !== null && typeof value[2] === "object";
60245
+ if (!Array.isArray(value)) return false;
60246
+ const arr = value;
60247
+ if (arr.length !== 3 || arr[0] !== "fn" || arr[2] === null || typeof arr[2] !== "object") {
60248
+ return false;
60249
+ }
60250
+ const params = arr[1];
60251
+ return typeof params === "string" || Array.isArray(params) && params.length > 0 && params.every((p2) => typeof p2 === "string");
60252
+ }
60253
+ function fnFormParams(value) {
60254
+ const p2 = value[1];
60255
+ if (typeof p2 === "string") return [p2];
60256
+ if (Array.isArray(p2)) return p2.filter((x) => typeof x === "string");
60257
+ return [];
60241
60258
  }
60242
- function resolveLambdaBindings(body, argName, arg) {
60243
- const prefix = `@${argName}.`;
60259
+ function resolveLambdaBindings(body, params, item, index) {
60260
+ const itemName = params[0];
60261
+ const indexName = params[1];
60262
+ const itemPrefix = itemName ? `@${itemName}.` : null;
60244
60263
  const lookup = (path) => {
60245
- let cur = arg;
60264
+ let cur = item;
60246
60265
  for (const seg of path.split(".")) {
60247
60266
  if (cur === null || cur === void 0) return void 0;
60248
60267
  if (typeof cur !== "object" || Array.isArray(cur)) return void 0;
@@ -60250,21 +60269,23 @@ function resolveLambdaBindings(body, argName, arg) {
60250
60269
  }
60251
60270
  return cur;
60252
60271
  };
60272
+ const recur = (b) => resolveLambdaBindings(b, params, item, index);
60253
60273
  if (typeof body === "string") {
60254
- if (body === `@${argName}`) return arg;
60255
- if (body.startsWith(prefix)) {
60256
- const v = lookup(body.slice(prefix.length));
60274
+ if (indexName && body === `@${indexName}`) return index;
60275
+ if (itemName && body === `@${itemName}`) return item;
60276
+ if (itemPrefix && body.startsWith(itemPrefix)) {
60277
+ const v = lookup(body.slice(itemPrefix.length));
60257
60278
  return v === void 0 || v === null ? "" : v;
60258
60279
  }
60259
60280
  return body;
60260
60281
  }
60261
60282
  if (Array.isArray(body)) {
60262
- return body.map((b) => resolveLambdaBindings(b, argName, arg));
60283
+ return body.map((b) => recur(b));
60263
60284
  }
60264
60285
  if (body !== null && typeof body === "object" && !React98__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
60265
60286
  const out = {};
60266
60287
  for (const [k, v] of Object.entries(body)) {
60267
- out[k] = resolveLambdaBindings(v, argName, arg);
60288
+ out[k] = recur(v);
60268
60289
  }
60269
60290
  return out;
60270
60291
  }
@@ -60277,9 +60298,9 @@ function getSlotContentRenderer2() {
60277
60298
  _slotContentRenderer2 = mod.SlotContentRenderer;
60278
60299
  return _slotContentRenderer2;
60279
60300
  }
60280
- function makeLambdaFn(argName, lambdaBody, callerKey) {
60301
+ function makeLambdaFn(params, lambdaBody, callerKey) {
60281
60302
  return (item, index) => {
60282
- const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
60303
+ const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
60283
60304
  if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React98__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
60284
60305
  return null;
60285
60306
  }
@@ -60306,8 +60327,8 @@ function convertNode(node, callerKey) {
60306
60327
  if (node === null || node === void 0) return node;
60307
60328
  if (Array.isArray(node)) {
60308
60329
  if (isFnFormLambda(node)) {
60309
- const [, argName, body] = node;
60310
- return makeLambdaFn(argName, body, callerKey);
60330
+ const arr2 = node;
60331
+ return makeLambdaFn(fnFormParams(arr2), arr2[2], callerKey);
60311
60332
  }
60312
60333
  const arr = node;
60313
60334
  let anyChanged = false;
@@ -60329,9 +60350,9 @@ function convertObjectProps(props) {
60329
60350
  for (const [key, value] of Object.entries(props)) {
60330
60351
  if (isFnFormLambda(value)) {
60331
60352
  convertedAny = true;
60332
- const [, argName, body] = value;
60353
+ const arr = value;
60333
60354
  const targetKey = key === "renderItem" ? "children" : key;
60334
- out[targetKey] = makeLambdaFn(argName, body, key);
60355
+ out[targetKey] = makeLambdaFn(fnFormParams(arr), arr[2], key);
60335
60356
  lambdaLog.debug(`convert key=${key} \u2192 ${targetKey}`);
60336
60357
  continue;
60337
60358
  }
@@ -6,8 +6,9 @@
6
6
  */
7
7
  import React from "react";
8
8
  export interface DayCellProps {
9
- /** The date this cell represents */
10
- date: Date;
9
+ /** The date this cell represents. Optional at the dynamic render edge: an
10
+ * unbound `@config.date` arrives as `undefined`, so the cell falls back to today. */
11
+ date?: Date;
11
12
  /** Whether this date is today */
12
13
  isToday?: boolean;
13
14
  /** Called when the day is clicked */
@@ -4587,10 +4587,11 @@ function DayCell({
4587
4587
  onClick,
4588
4588
  className
4589
4589
  }) {
4590
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
4590
4591
  const handleClick = React80.useCallback(() => {
4591
- onClick?.(date);
4592
- }, [onClick, date]);
4593
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
4592
+ onClick?.(safeDate);
4593
+ }, [onClick, safeDate]);
4594
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
4594
4595
  return /* @__PURE__ */ jsxRuntime.jsxs(
4595
4596
  exports.Box,
4596
4597
  {
@@ -4621,7 +4622,7 @@ function DayCell({
4621
4622
  "h-8 w-8 mx-auto items-center justify-center",
4622
4623
  isToday && "bg-blue-600 text-white"
4623
4624
  ),
4624
- children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
4625
+ children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
4625
4626
  }
4626
4627
  )
4627
4628
  ]
@@ -47825,11 +47826,15 @@ function SlotContentRenderer({
47825
47826
  }
47826
47827
  if (propsSchema) {
47827
47828
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
47828
- const v = renderedProps[propKey];
47829
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
47829
+ const isDate = propDef.types?.some(
47830
47830
  (t) => t === "date" || t === "datetime" || t === "timestamp"
47831
- )) {
47831
+ );
47832
+ if (!isDate) continue;
47833
+ const v = renderedProps[propKey];
47834
+ if (typeof v === "string" || typeof v === "number") {
47832
47835
  renderedProps[propKey] = new Date(v);
47836
+ } else if (v == null && propDef.required) {
47837
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
47833
47838
  }
47834
47839
  }
47835
47840
  }
@@ -4538,10 +4538,11 @@ function DayCell({
4538
4538
  onClick,
4539
4539
  className
4540
4540
  }) {
4541
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
4541
4542
  const handleClick = useCallback(() => {
4542
- onClick?.(date);
4543
- }, [onClick, date]);
4544
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
4543
+ onClick?.(safeDate);
4544
+ }, [onClick, safeDate]);
4545
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
4545
4546
  return /* @__PURE__ */ jsxs(
4546
4547
  Box,
4547
4548
  {
@@ -4572,7 +4573,7 @@ function DayCell({
4572
4573
  "h-8 w-8 mx-auto items-center justify-center",
4573
4574
  isToday && "bg-blue-600 text-white"
4574
4575
  ),
4575
- children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
4576
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
4576
4577
  }
4577
4578
  )
4578
4579
  ]
@@ -47776,11 +47777,15 @@ function SlotContentRenderer({
47776
47777
  }
47777
47778
  if (propsSchema) {
47778
47779
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
47779
- const v = renderedProps[propKey];
47780
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
47780
+ const isDate = propDef.types?.some(
47781
47781
  (t) => t === "date" || t === "datetime" || t === "timestamp"
47782
- )) {
47782
+ );
47783
+ if (!isDate) continue;
47784
+ const v = renderedProps[propKey];
47785
+ if (typeof v === "string" || typeof v === "number") {
47783
47786
  renderedProps[propKey] = new Date(v);
47787
+ } else if (v == null && propDef.required) {
47788
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
47784
47789
  }
47785
47790
  }
47786
47791
  }
@@ -5097,10 +5097,11 @@ function DayCell({
5097
5097
  onClick,
5098
5098
  className
5099
5099
  }) {
5100
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
5100
5101
  const handleClick = React86.useCallback(() => {
5101
- onClick?.(date);
5102
- }, [onClick, date]);
5103
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
5102
+ onClick?.(safeDate);
5103
+ }, [onClick, safeDate]);
5104
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
5104
5105
  return /* @__PURE__ */ jsxRuntime.jsxs(
5105
5106
  Box,
5106
5107
  {
@@ -5131,7 +5132,7 @@ function DayCell({
5131
5132
  "h-8 w-8 mx-auto items-center justify-center",
5132
5133
  isToday && "bg-blue-600 text-white"
5133
5134
  ),
5134
- children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
5135
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
5135
5136
  }
5136
5137
  )
5137
5138
  ]
@@ -47892,11 +47893,15 @@ function SlotContentRenderer({
47892
47893
  }
47893
47894
  if (propsSchema) {
47894
47895
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
47895
- const v = renderedProps[propKey];
47896
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
47896
+ const isDate = propDef.types?.some(
47897
47897
  (t) => t === "date" || t === "datetime" || t === "timestamp"
47898
- )) {
47898
+ );
47899
+ if (!isDate) continue;
47900
+ const v = renderedProps[propKey];
47901
+ if (typeof v === "string" || typeof v === "number") {
47899
47902
  renderedProps[propKey] = new Date(v);
47903
+ } else if (v == null && propDef.required) {
47904
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
47900
47905
  }
47901
47906
  }
47902
47907
  }
@@ -5048,10 +5048,11 @@ function DayCell({
5048
5048
  onClick,
5049
5049
  className
5050
5050
  }) {
5051
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
5051
5052
  const handleClick = useCallback(() => {
5052
- onClick?.(date);
5053
- }, [onClick, date]);
5054
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
5053
+ onClick?.(safeDate);
5054
+ }, [onClick, safeDate]);
5055
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
5055
5056
  return /* @__PURE__ */ jsxs(
5056
5057
  Box,
5057
5058
  {
@@ -5082,7 +5083,7 @@ function DayCell({
5082
5083
  "h-8 w-8 mx-auto items-center justify-center",
5083
5084
  isToday && "bg-blue-600 text-white"
5084
5085
  ),
5085
- children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
5086
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
5086
5087
  }
5087
5088
  )
5088
5089
  ]
@@ -47843,11 +47844,15 @@ function SlotContentRenderer({
47843
47844
  }
47844
47845
  if (propsSchema) {
47845
47846
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
47846
- const v = renderedProps[propKey];
47847
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
47847
+ const isDate = propDef.types?.some(
47848
47848
  (t) => t === "date" || t === "datetime" || t === "timestamp"
47849
- )) {
47849
+ );
47850
+ if (!isDate) continue;
47851
+ const v = renderedProps[propKey];
47852
+ if (typeof v === "string" || typeof v === "number") {
47850
47853
  renderedProps[propKey] = new Date(v);
47854
+ } else if (v == null && propDef.required) {
47855
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
47851
47856
  }
47852
47857
  }
47853
47858
  }
@@ -17,7 +17,7 @@ export declare function isFnFormLambda(value: SlotPropValue): value is RenderIte
17
17
  * value at `path` of `arg`. Mirrors the compiler's inline substitution
18
18
  * for `renderItem` lambda bodies.
19
19
  */
20
- export declare function resolveLambdaBindings(body: SlotPropValue, argName: string, arg: EntityRow): SlotPropValue;
20
+ export declare function resolveLambdaBindings(body: SlotPropValue, params: readonly string[], item: EntityRow, index: number): SlotPropValue;
21
21
  /**
22
22
  * Walk a pattern's props (and recursively their nested children),
23
23
  * converting every fn-form lambda value into a React render-prop
@@ -5507,10 +5507,11 @@ function DayCell({
5507
5507
  onClick,
5508
5508
  className
5509
5509
  }) {
5510
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
5510
5511
  const handleClick = React85.useCallback(() => {
5511
- onClick?.(date);
5512
- }, [onClick, date]);
5513
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
5512
+ onClick?.(safeDate);
5513
+ }, [onClick, safeDate]);
5514
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
5514
5515
  return /* @__PURE__ */ jsxRuntime.jsxs(
5515
5516
  Box,
5516
5517
  {
@@ -5541,7 +5542,7 @@ function DayCell({
5541
5542
  "h-8 w-8 mx-auto items-center justify-center",
5542
5543
  isToday && "bg-blue-600 text-white"
5543
5544
  ),
5544
- children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
5545
+ children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
5545
5546
  }
5546
5547
  )
5547
5548
  ]
@@ -47478,11 +47479,15 @@ function SlotContentRenderer({
47478
47479
  }
47479
47480
  if (propsSchema) {
47480
47481
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
47481
- const v = renderedProps[propKey];
47482
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
47482
+ const isDate = propDef.types?.some(
47483
47483
  (t) => t === "date" || t === "datetime" || t === "timestamp"
47484
- )) {
47484
+ );
47485
+ if (!isDate) continue;
47486
+ const v = renderedProps[propKey];
47487
+ if (typeof v === "string" || typeof v === "number") {
47485
47488
  renderedProps[propKey] = new Date(v);
47489
+ } else if (v == null && propDef.required) {
47490
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
47486
47491
  }
47487
47492
  }
47488
47493
  }
@@ -47726,12 +47731,26 @@ function createClientEffectHandlers(options) {
47726
47731
  }
47727
47732
  var lambdaLog = logger.createLogger("almadar:ui:fn-form-lambda");
47728
47733
  function isFnFormLambda(value) {
47729
- return Array.isArray(value) && value.length === 3 && value[0] === "fn" && typeof value[1] === "string" && value[2] !== null && typeof value[2] === "object";
47734
+ if (!Array.isArray(value)) return false;
47735
+ const arr = value;
47736
+ if (arr.length !== 3 || arr[0] !== "fn" || arr[2] === null || typeof arr[2] !== "object") {
47737
+ return false;
47738
+ }
47739
+ const params = arr[1];
47740
+ return typeof params === "string" || Array.isArray(params) && params.length > 0 && params.every((p2) => typeof p2 === "string");
47741
+ }
47742
+ function fnFormParams(value) {
47743
+ const p2 = value[1];
47744
+ if (typeof p2 === "string") return [p2];
47745
+ if (Array.isArray(p2)) return p2.filter((x) => typeof x === "string");
47746
+ return [];
47730
47747
  }
47731
- function resolveLambdaBindings(body, argName, arg) {
47732
- const prefix = `@${argName}.`;
47748
+ function resolveLambdaBindings(body, params, item, index) {
47749
+ const itemName = params[0];
47750
+ const indexName = params[1];
47751
+ const itemPrefix = itemName ? `@${itemName}.` : null;
47733
47752
  const lookup = (path) => {
47734
- let cur = arg;
47753
+ let cur = item;
47735
47754
  for (const seg of path.split(".")) {
47736
47755
  if (cur === null || cur === void 0) return void 0;
47737
47756
  if (typeof cur !== "object" || Array.isArray(cur)) return void 0;
@@ -47739,21 +47758,23 @@ function resolveLambdaBindings(body, argName, arg) {
47739
47758
  }
47740
47759
  return cur;
47741
47760
  };
47761
+ const recur = (b) => resolveLambdaBindings(b, params, item, index);
47742
47762
  if (typeof body === "string") {
47743
- if (body === `@${argName}`) return arg;
47744
- if (body.startsWith(prefix)) {
47745
- const v = lookup(body.slice(prefix.length));
47763
+ if (indexName && body === `@${indexName}`) return index;
47764
+ if (itemName && body === `@${itemName}`) return item;
47765
+ if (itemPrefix && body.startsWith(itemPrefix)) {
47766
+ const v = lookup(body.slice(itemPrefix.length));
47746
47767
  return v === void 0 || v === null ? "" : v;
47747
47768
  }
47748
47769
  return body;
47749
47770
  }
47750
47771
  if (Array.isArray(body)) {
47751
- return body.map((b) => resolveLambdaBindings(b, argName, arg));
47772
+ return body.map((b) => recur(b));
47752
47773
  }
47753
47774
  if (body !== null && typeof body === "object" && !React85__namespace.default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
47754
47775
  const out = {};
47755
47776
  for (const [k, v] of Object.entries(body)) {
47756
- out[k] = resolveLambdaBindings(v, argName, arg);
47777
+ out[k] = recur(v);
47757
47778
  }
47758
47779
  return out;
47759
47780
  }
@@ -47766,9 +47787,9 @@ function getSlotContentRenderer2() {
47766
47787
  _slotContentRenderer2 = mod.SlotContentRenderer;
47767
47788
  return _slotContentRenderer2;
47768
47789
  }
47769
- function makeLambdaFn(argName, lambdaBody, callerKey) {
47790
+ function makeLambdaFn(params, lambdaBody, callerKey) {
47770
47791
  return (item, index) => {
47771
- const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
47792
+ const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
47772
47793
  if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React85__namespace.default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
47773
47794
  return null;
47774
47795
  }
@@ -47795,8 +47816,8 @@ function convertNode(node, callerKey) {
47795
47816
  if (node === null || node === void 0) return node;
47796
47817
  if (Array.isArray(node)) {
47797
47818
  if (isFnFormLambda(node)) {
47798
- const [, argName, body] = node;
47799
- return makeLambdaFn(argName, body, callerKey);
47819
+ const arr2 = node;
47820
+ return makeLambdaFn(fnFormParams(arr2), arr2[2], callerKey);
47800
47821
  }
47801
47822
  const arr = node;
47802
47823
  let anyChanged = false;
@@ -47818,9 +47839,9 @@ function convertObjectProps(props) {
47818
47839
  for (const [key, value] of Object.entries(props)) {
47819
47840
  if (isFnFormLambda(value)) {
47820
47841
  convertedAny = true;
47821
- const [, argName, body] = value;
47842
+ const arr = value;
47822
47843
  const targetKey = key === "renderItem" ? "children" : key;
47823
- out[targetKey] = makeLambdaFn(argName, body, key);
47844
+ out[targetKey] = makeLambdaFn(fnFormParams(arr), arr[2], key);
47824
47845
  lambdaLog.debug(`convert key=${key} \u2192 ${targetKey}`);
47825
47846
  continue;
47826
47847
  }
@@ -5458,10 +5458,11 @@ function DayCell({
5458
5458
  onClick,
5459
5459
  className
5460
5460
  }) {
5461
+ const safeDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : /* @__PURE__ */ new Date();
5461
5462
  const handleClick = useCallback(() => {
5462
- onClick?.(date);
5463
- }, [onClick, date]);
5464
- const dayAbbr = DAY_ABBREVIATIONS[date.getDay()];
5463
+ onClick?.(safeDate);
5464
+ }, [onClick, safeDate]);
5465
+ const dayAbbr = DAY_ABBREVIATIONS[safeDate.getDay()];
5465
5466
  return /* @__PURE__ */ jsxs(
5466
5467
  Box,
5467
5468
  {
@@ -5492,7 +5493,7 @@ function DayCell({
5492
5493
  "h-8 w-8 mx-auto items-center justify-center",
5493
5494
  isToday && "bg-blue-600 text-white"
5494
5495
  ),
5495
- children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: date.getDate() })
5496
+ children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-semibold", children: safeDate.getDate() })
5496
5497
  }
5497
5498
  )
5498
5499
  ]
@@ -47429,11 +47430,15 @@ function SlotContentRenderer({
47429
47430
  }
47430
47431
  if (propsSchema) {
47431
47432
  for (const [propKey, propDef] of Object.entries(propsSchema)) {
47432
- const v = renderedProps[propKey];
47433
- if ((typeof v === "string" || typeof v === "number") && propDef.types?.some(
47433
+ const isDate = propDef.types?.some(
47434
47434
  (t) => t === "date" || t === "datetime" || t === "timestamp"
47435
- )) {
47435
+ );
47436
+ if (!isDate) continue;
47437
+ const v = renderedProps[propKey];
47438
+ if (typeof v === "string" || typeof v === "number") {
47436
47439
  renderedProps[propKey] = new Date(v);
47440
+ } else if (v == null && propDef.required) {
47441
+ renderedProps[propKey] = /* @__PURE__ */ new Date();
47437
47442
  }
47438
47443
  }
47439
47444
  }
@@ -47677,12 +47682,26 @@ function createClientEffectHandlers(options) {
47677
47682
  }
47678
47683
  var lambdaLog = createLogger("almadar:ui:fn-form-lambda");
47679
47684
  function isFnFormLambda(value) {
47680
- return Array.isArray(value) && value.length === 3 && value[0] === "fn" && typeof value[1] === "string" && value[2] !== null && typeof value[2] === "object";
47685
+ if (!Array.isArray(value)) return false;
47686
+ const arr = value;
47687
+ if (arr.length !== 3 || arr[0] !== "fn" || arr[2] === null || typeof arr[2] !== "object") {
47688
+ return false;
47689
+ }
47690
+ const params = arr[1];
47691
+ return typeof params === "string" || Array.isArray(params) && params.length > 0 && params.every((p2) => typeof p2 === "string");
47692
+ }
47693
+ function fnFormParams(value) {
47694
+ const p2 = value[1];
47695
+ if (typeof p2 === "string") return [p2];
47696
+ if (Array.isArray(p2)) return p2.filter((x) => typeof x === "string");
47697
+ return [];
47681
47698
  }
47682
- function resolveLambdaBindings(body, argName, arg) {
47683
- const prefix = `@${argName}.`;
47699
+ function resolveLambdaBindings(body, params, item, index) {
47700
+ const itemName = params[0];
47701
+ const indexName = params[1];
47702
+ const itemPrefix = itemName ? `@${itemName}.` : null;
47684
47703
  const lookup = (path) => {
47685
- let cur = arg;
47704
+ let cur = item;
47686
47705
  for (const seg of path.split(".")) {
47687
47706
  if (cur === null || cur === void 0) return void 0;
47688
47707
  if (typeof cur !== "object" || Array.isArray(cur)) return void 0;
@@ -47690,21 +47709,23 @@ function resolveLambdaBindings(body, argName, arg) {
47690
47709
  }
47691
47710
  return cur;
47692
47711
  };
47712
+ const recur = (b) => resolveLambdaBindings(b, params, item, index);
47693
47713
  if (typeof body === "string") {
47694
- if (body === `@${argName}`) return arg;
47695
- if (body.startsWith(prefix)) {
47696
- const v = lookup(body.slice(prefix.length));
47714
+ if (indexName && body === `@${indexName}`) return index;
47715
+ if (itemName && body === `@${itemName}`) return item;
47716
+ if (itemPrefix && body.startsWith(itemPrefix)) {
47717
+ const v = lookup(body.slice(itemPrefix.length));
47697
47718
  return v === void 0 || v === null ? "" : v;
47698
47719
  }
47699
47720
  return body;
47700
47721
  }
47701
47722
  if (Array.isArray(body)) {
47702
- return body.map((b) => resolveLambdaBindings(b, argName, arg));
47723
+ return body.map((b) => recur(b));
47703
47724
  }
47704
47725
  if (body !== null && typeof body === "object" && !React85__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
47705
47726
  const out = {};
47706
47727
  for (const [k, v] of Object.entries(body)) {
47707
- out[k] = resolveLambdaBindings(v, argName, arg);
47728
+ out[k] = recur(v);
47708
47729
  }
47709
47730
  return out;
47710
47731
  }
@@ -47717,9 +47738,9 @@ function getSlotContentRenderer2() {
47717
47738
  _slotContentRenderer2 = mod.SlotContentRenderer;
47718
47739
  return _slotContentRenderer2;
47719
47740
  }
47720
- function makeLambdaFn(argName, lambdaBody, callerKey) {
47741
+ function makeLambdaFn(params, lambdaBody, callerKey) {
47721
47742
  return (item, index) => {
47722
- const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
47743
+ const resolvedBody = resolveLambdaBindings(lambdaBody, params, item, index);
47723
47744
  if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React85__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
47724
47745
  return null;
47725
47746
  }
@@ -47746,8 +47767,8 @@ function convertNode(node, callerKey) {
47746
47767
  if (node === null || node === void 0) return node;
47747
47768
  if (Array.isArray(node)) {
47748
47769
  if (isFnFormLambda(node)) {
47749
- const [, argName, body] = node;
47750
- return makeLambdaFn(argName, body, callerKey);
47770
+ const arr2 = node;
47771
+ return makeLambdaFn(fnFormParams(arr2), arr2[2], callerKey);
47751
47772
  }
47752
47773
  const arr = node;
47753
47774
  let anyChanged = false;
@@ -47769,9 +47790,9 @@ function convertObjectProps(props) {
47769
47790
  for (const [key, value] of Object.entries(props)) {
47770
47791
  if (isFnFormLambda(value)) {
47771
47792
  convertedAny = true;
47772
- const [, argName, body] = value;
47793
+ const arr = value;
47773
47794
  const targetKey = key === "renderItem" ? "children" : key;
47774
- out[targetKey] = makeLambdaFn(argName, body, key);
47795
+ out[targetKey] = makeLambdaFn(fnFormParams(arr), arr[2], key);
47775
47796
  lambdaLog.debug(`convert key=${key} \u2192 ${targetKey}`);
47776
47797
  continue;
47777
47798
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.17.1",
3
+ "version": "5.18.1",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -191,7 +191,7 @@
191
191
  "@types/three": "^0.160.0",
192
192
  "@typescript-eslint/parser": "8.56.0",
193
193
  "@vitejs/plugin-react": "^4.2.0",
194
- "@vitest/ui": "^1.4.0",
194
+ "@vitest/ui": "^3.2.6",
195
195
  "autoprefixer": "^10.4.0",
196
196
  "babel-plugin-react-compiler": "19.0.0-beta-af1b7da-20250417",
197
197
  "eslint": "10.0.0",
@@ -211,7 +211,7 @@
211
211
  "tsx": "^4.7.0",
212
212
  "typescript": "^5.4.0",
213
213
  "vite": "^5.2.0",
214
- "vitest": "^1.4.0"
214
+ "vitest": "^3.2.6"
215
215
  },
216
216
  "repository": {
217
217
  "type": "git",