@almadar/ui 5.133.0 → 5.135.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.
@@ -2958,6 +2958,53 @@ var Stack = ({
2958
2958
  };
2959
2959
  var VStack = (props) => /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "vertical", ...props });
2960
2960
  var HStack = (props) => /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "horizontal", ...props });
2961
+
2962
+ // lib/format.ts
2963
+ function formatDate(value) {
2964
+ if (!value) return "";
2965
+ const d = new Date(String(value));
2966
+ if (isNaN(d.getTime())) return String(value);
2967
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
2968
+ }
2969
+ function formatTime(value) {
2970
+ if (!value) return "";
2971
+ const d = new Date(String(value));
2972
+ if (isNaN(d.getTime())) return String(value);
2973
+ return d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
2974
+ }
2975
+ function formatDateTime(value) {
2976
+ if (!value) return "";
2977
+ const d = new Date(String(value));
2978
+ if (isNaN(d.getTime())) return String(value);
2979
+ return `${formatDate(value)} ${formatTime(value)}`;
2980
+ }
2981
+ function asYesNo(value) {
2982
+ return value === false || value === 0 || String(value) === "false" ? "No" : "Yes";
2983
+ }
2984
+ function formatValue(value, format) {
2985
+ if (value === void 0 || value === null) return "";
2986
+ if (typeof value === "boolean") return asYesNo(value);
2987
+ switch (format) {
2988
+ case "date":
2989
+ return formatDate(value);
2990
+ case "time":
2991
+ return formatTime(value);
2992
+ case "datetime":
2993
+ return formatDateTime(value);
2994
+ case "currency":
2995
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
2996
+ case "number":
2997
+ return typeof value === "number" ? value.toLocaleString() : String(value);
2998
+ case "percent":
2999
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
3000
+ case "boolean":
3001
+ return asYesNo(value);
3002
+ default:
3003
+ return String(value);
3004
+ }
3005
+ }
3006
+
3007
+ // components/core/atoms/Typography.tsx
2961
3008
  var variantStyles = {
2962
3009
  h1: "text-4xl font-bold tracking-tight text-foreground",
2963
3010
  h2: "text-3xl font-bold tracking-tight text-foreground",
@@ -3045,11 +3092,16 @@ var Typography = ({
3045
3092
  id,
3046
3093
  className,
3047
3094
  style,
3095
+ format,
3048
3096
  content,
3049
3097
  children
3050
3098
  }) => {
3051
3099
  const variant = variantProp ?? (level ? `h${level}` : "body1");
3052
3100
  const Component = as || defaultElements[variant];
3101
+ let body = children ?? content;
3102
+ if (format !== void 0 && format !== "none" && (typeof body === "string" || typeof body === "number" || body instanceof Date)) {
3103
+ body = formatValue(body, format);
3104
+ }
3053
3105
  return React12__namespace.default.createElement(
3054
3106
  Component,
3055
3107
  {
@@ -3066,7 +3118,7 @@ var Typography = ({
3066
3118
  ),
3067
3119
  style
3068
3120
  },
3069
- children ?? content
3121
+ body
3070
3122
  );
3071
3123
  };
3072
3124
  Typography.displayName = "Typography";
@@ -165,6 +165,12 @@ interface TypographyProps {
165
165
  className?: string;
166
166
  /** Inline style */
167
167
  style?: React.CSSProperties;
168
+ /**
169
+ * Value formatting applied to string/number/Date content — `none` (the
170
+ * default) renders content as-is. Covers the raw-ISO-date class: a bound
171
+ * datetime renders human-readable via `format="date"|"time"|"datetime"`.
172
+ */
173
+ format?: "none" | "date" | "time" | "datetime" | "number" | "currency" | "percent";
168
174
  /** Text content (alternative to children) */
169
175
  content?: React.ReactNode;
170
176
  /** Children elements */
@@ -165,6 +165,12 @@ interface TypographyProps {
165
165
  className?: string;
166
166
  /** Inline style */
167
167
  style?: React.CSSProperties;
168
+ /**
169
+ * Value formatting applied to string/number/Date content — `none` (the
170
+ * default) renders content as-is. Covers the raw-ISO-date class: a bound
171
+ * datetime renders human-readable via `format="date"|"time"|"datetime"`.
172
+ */
173
+ format?: "none" | "date" | "time" | "datetime" | "number" | "currency" | "percent";
168
174
  /** Text content (alternative to children) */
169
175
  content?: React.ReactNode;
170
176
  /** Children elements */
@@ -2937,6 +2937,53 @@ var Stack = ({
2937
2937
  };
2938
2938
  var VStack = (props) => /* @__PURE__ */ jsx(Stack, { direction: "vertical", ...props });
2939
2939
  var HStack = (props) => /* @__PURE__ */ jsx(Stack, { direction: "horizontal", ...props });
2940
+
2941
+ // lib/format.ts
2942
+ function formatDate(value) {
2943
+ if (!value) return "";
2944
+ const d = new Date(String(value));
2945
+ if (isNaN(d.getTime())) return String(value);
2946
+ return d.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
2947
+ }
2948
+ function formatTime(value) {
2949
+ if (!value) return "";
2950
+ const d = new Date(String(value));
2951
+ if (isNaN(d.getTime())) return String(value);
2952
+ return d.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
2953
+ }
2954
+ function formatDateTime(value) {
2955
+ if (!value) return "";
2956
+ const d = new Date(String(value));
2957
+ if (isNaN(d.getTime())) return String(value);
2958
+ return `${formatDate(value)} ${formatTime(value)}`;
2959
+ }
2960
+ function asYesNo(value) {
2961
+ return value === false || value === 0 || String(value) === "false" ? "No" : "Yes";
2962
+ }
2963
+ function formatValue(value, format) {
2964
+ if (value === void 0 || value === null) return "";
2965
+ if (typeof value === "boolean") return asYesNo(value);
2966
+ switch (format) {
2967
+ case "date":
2968
+ return formatDate(value);
2969
+ case "time":
2970
+ return formatTime(value);
2971
+ case "datetime":
2972
+ return formatDateTime(value);
2973
+ case "currency":
2974
+ return typeof value === "number" ? `$${value.toFixed(2)}` : String(value);
2975
+ case "number":
2976
+ return typeof value === "number" ? value.toLocaleString() : String(value);
2977
+ case "percent":
2978
+ return typeof value === "number" ? `${Math.round(value)}%` : String(value);
2979
+ case "boolean":
2980
+ return asYesNo(value);
2981
+ default:
2982
+ return String(value);
2983
+ }
2984
+ }
2985
+
2986
+ // components/core/atoms/Typography.tsx
2940
2987
  var variantStyles = {
2941
2988
  h1: "text-4xl font-bold tracking-tight text-foreground",
2942
2989
  h2: "text-3xl font-bold tracking-tight text-foreground",
@@ -3024,11 +3071,16 @@ var Typography = ({
3024
3071
  id,
3025
3072
  className,
3026
3073
  style,
3074
+ format,
3027
3075
  content,
3028
3076
  children
3029
3077
  }) => {
3030
3078
  const variant = variantProp ?? (level ? `h${level}` : "body1");
3031
3079
  const Component = as || defaultElements[variant];
3080
+ let body = children ?? content;
3081
+ if (format !== void 0 && format !== "none" && (typeof body === "string" || typeof body === "number" || body instanceof Date)) {
3082
+ body = formatValue(body, format);
3083
+ }
3032
3084
  return React12__default.createElement(
3033
3085
  Component,
3034
3086
  {
@@ -3045,7 +3097,7 @@ var Typography = ({
3045
3097
  ),
3046
3098
  style
3047
3099
  },
3048
- children ?? content
3100
+ body
3049
3101
  );
3050
3102
  };
3051
3103
  Typography.displayName = "Typography";
@@ -100,16 +100,16 @@ interface DrawSpriteProps extends DrawableBase {
100
100
  * ONE descriptor (`DrawShapeProps`, grounded in core `ScenePos`) with TWO
101
101
  * backends: `paintShape` (2D, here) and an R3F ground-plane mesh (`Shape3D` in
102
102
  * `lib/drawable/mesh3d`, kept OUT of this file so the 2D path never pulls R3F).
103
- * Paints a cell footprint, an axis-aligned rect, an ellipse, or a poly at a scene
104
- * position, fill and/or stroke. Genre uses (tile fallback, iso/hex diamond
105
- * fallback, cell highlight, feature disc, unit selection ring, unit fallback
106
- * circle, ground/ghost discs, solid backgrounds, side-view platform rects) are
107
- * all this atom with different `shape`/`anchor`/geometry — composed in `.lolo`,
108
- * not here. The React component renders `null`; it exists so the pattern pipeline
103
+ * Paints a cell footprint, an axis-aligned rect, an ellipse, a poly, or an SVG
104
+ * path at a scene position, fill and/or stroke. Genre uses (tile fallback, iso/hex
105
+ * diamond fallback, cell highlight, feature disc, unit selection ring, unit
106
+ * fallback circle, ground/ghost discs, solid backgrounds, side-view platform
107
+ * rects, hand-authored vector art) are all this atom with different
108
+ * `shape`/`anchor`/geometry — composed in `.lolo`, not here. The React component renders `null`; it exists so the pattern pipeline
109
109
  * registers a `draw-shape` pattern and standalone pages stay inspectable.
110
110
  */
111
111
 
112
- type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly';
112
+ type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly' | 'path';
113
113
  interface DrawShapeProps extends DrawableBase {
114
114
  type: 'draw-shape';
115
115
  shape: ShapeKind;
@@ -130,6 +130,8 @@ interface DrawShapeProps extends DrawableBase {
130
130
  offsetY?: number;
131
131
  /** Poly vertices as world-unit offsets relative to the cell's projected top-left. */
132
132
  points?: PainterPoint[];
133
+ /** SVG path data in world units relative to the cell's projected top-left — same coordinate convention as `points`. */
134
+ d?: string;
133
135
  fill?: string;
134
136
  stroke?: string;
135
137
  strokeWidth?: number;
@@ -162,6 +164,33 @@ interface DrawTextProps extends DrawableBase {
162
164
  opacity?: number;
163
165
  }
164
166
 
167
+ /**
168
+ * `draw-group` — the drawable CONTAINER atom (dimension-agnostic).
169
+ *
170
+ * Multi-shape art (a hero token = cloak + head + sword shapes) travels as ONE
171
+ * node: the host paints the group by translating to its projected position,
172
+ * applying `scale`/`rotate`/`opacity`, then painting each `items` descriptor
173
+ * through the normal dispatch. `items` is a plain data prop (NOT `children`,
174
+ * which UISlotRenderer special-cases) — same convention as the `draw-*-layer`
175
+ * molecules. The React component renders `null`; it exists so the pattern
176
+ * pipeline registers a `draw-group` pattern and standalone pages stay
177
+ * inspectable. 2D-canvas only — the 3D backend skips it with a warn.
178
+ */
179
+
180
+ interface DrawGroupProps extends DrawableBase {
181
+ type: 'draw-group';
182
+ /** Logical scene position; the projector maps it to pixels / world. */
183
+ position: ScenePos;
184
+ /** Uniform scale applied to the whole group. */
185
+ scale?: number;
186
+ /** Rotation in radians (painter units). */
187
+ rotate?: number;
188
+ /** 0..1 opacity. */
189
+ opacity?: number;
190
+ /** The grouped drawables, painted through the normal dispatch. */
191
+ items: DrawableNode[];
192
+ }
193
+
165
194
  /**
166
195
  * `draw-sprite-layer` — batch multiple sprites in one descriptor for O(layers) rendering.
167
196
  *
@@ -218,6 +247,6 @@ interface DrawTextLayerProps extends DrawableBase {
218
247
  */
219
248
 
220
249
  /** Every drawable descriptor. The host's `children` are a `DrawableNode[]`. */
221
- type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
250
+ type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawGroupProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
222
251
 
223
252
  export type { DrawableNode as D };
@@ -100,16 +100,16 @@ interface DrawSpriteProps extends DrawableBase {
100
100
  * ONE descriptor (`DrawShapeProps`, grounded in core `ScenePos`) with TWO
101
101
  * backends: `paintShape` (2D, here) and an R3F ground-plane mesh (`Shape3D` in
102
102
  * `lib/drawable/mesh3d`, kept OUT of this file so the 2D path never pulls R3F).
103
- * Paints a cell footprint, an axis-aligned rect, an ellipse, or a poly at a scene
104
- * position, fill and/or stroke. Genre uses (tile fallback, iso/hex diamond
105
- * fallback, cell highlight, feature disc, unit selection ring, unit fallback
106
- * circle, ground/ghost discs, solid backgrounds, side-view platform rects) are
107
- * all this atom with different `shape`/`anchor`/geometry — composed in `.lolo`,
108
- * not here. The React component renders `null`; it exists so the pattern pipeline
103
+ * Paints a cell footprint, an axis-aligned rect, an ellipse, a poly, or an SVG
104
+ * path at a scene position, fill and/or stroke. Genre uses (tile fallback, iso/hex
105
+ * diamond fallback, cell highlight, feature disc, unit selection ring, unit
106
+ * fallback circle, ground/ghost discs, solid backgrounds, side-view platform
107
+ * rects, hand-authored vector art) are all this atom with different
108
+ * `shape`/`anchor`/geometry — composed in `.lolo`, not here. The React component renders `null`; it exists so the pattern pipeline
109
109
  * registers a `draw-shape` pattern and standalone pages stay inspectable.
110
110
  */
111
111
 
112
- type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly';
112
+ type ShapeKind = 'cell' | 'rect' | 'ellipse' | 'poly' | 'path';
113
113
  interface DrawShapeProps extends DrawableBase {
114
114
  type: 'draw-shape';
115
115
  shape: ShapeKind;
@@ -130,6 +130,8 @@ interface DrawShapeProps extends DrawableBase {
130
130
  offsetY?: number;
131
131
  /** Poly vertices as world-unit offsets relative to the cell's projected top-left. */
132
132
  points?: PainterPoint[];
133
+ /** SVG path data in world units relative to the cell's projected top-left — same coordinate convention as `points`. */
134
+ d?: string;
133
135
  fill?: string;
134
136
  stroke?: string;
135
137
  strokeWidth?: number;
@@ -162,6 +164,33 @@ interface DrawTextProps extends DrawableBase {
162
164
  opacity?: number;
163
165
  }
164
166
 
167
+ /**
168
+ * `draw-group` — the drawable CONTAINER atom (dimension-agnostic).
169
+ *
170
+ * Multi-shape art (a hero token = cloak + head + sword shapes) travels as ONE
171
+ * node: the host paints the group by translating to its projected position,
172
+ * applying `scale`/`rotate`/`opacity`, then painting each `items` descriptor
173
+ * through the normal dispatch. `items` is a plain data prop (NOT `children`,
174
+ * which UISlotRenderer special-cases) — same convention as the `draw-*-layer`
175
+ * molecules. The React component renders `null`; it exists so the pattern
176
+ * pipeline registers a `draw-group` pattern and standalone pages stay
177
+ * inspectable. 2D-canvas only — the 3D backend skips it with a warn.
178
+ */
179
+
180
+ interface DrawGroupProps extends DrawableBase {
181
+ type: 'draw-group';
182
+ /** Logical scene position; the projector maps it to pixels / world. */
183
+ position: ScenePos;
184
+ /** Uniform scale applied to the whole group. */
185
+ scale?: number;
186
+ /** Rotation in radians (painter units). */
187
+ rotate?: number;
188
+ /** 0..1 opacity. */
189
+ opacity?: number;
190
+ /** The grouped drawables, painted through the normal dispatch. */
191
+ items: DrawableNode[];
192
+ }
193
+
165
194
  /**
166
195
  * `draw-sprite-layer` — batch multiple sprites in one descriptor for O(layers) rendering.
167
196
  *
@@ -218,6 +247,6 @@ interface DrawTextLayerProps extends DrawableBase {
218
247
  */
219
248
 
220
249
  /** Every drawable descriptor. The host's `children` are a `DrawableNode[]`. */
221
- type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
250
+ type DrawableNode = DrawSpriteProps | DrawShapeProps | DrawTextProps | DrawGroupProps | DrawSpriteLayerProps | DrawShapeLayerProps | DrawTextLayerProps;
222
251
 
223
252
  export type { DrawableNode as D };