@bwp-web/components 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ npm install @bwp-web/components
11
11
  ### Peer Dependencies
12
12
 
13
13
  - `@bwp-web/styles` >= 1.0.3
14
- - `@bwp-web/assets` >= 1.0.1
14
+ - `@bwp-web/assets` >= 1.0.2
15
15
  - `@mui/material` >= 7.0.0
16
16
  - `react` >= 18.0.0
17
17
  - `react-dom` >= 18.0.0
@@ -48,6 +48,7 @@ For `BiampTable` only:
48
48
  | `SegmentedButtonGroup` | Horizontal container for grouping segmented toggle buttons |
49
49
  | `SegmentedButton` | Individual toggle button for use inside `SegmentedButtonGroup` |
50
50
  | `BiampTable` | Composable data table with sorting, selection, pagination, and more |
51
+ | `UserInitialsIcon` | Avatar-style icon showing a user's initials with a deterministic color |
51
52
 
52
53
  ## Usage
53
54
 
@@ -216,6 +217,28 @@ Horizontal header container. Compose with `BiampHeaderTitle`, `BiampHeaderSearch
216
217
  | `title` | `string` | Optional title text |
217
218
  | `subtitle` | `string` | Optional subtitle text |
218
219
 
220
+ ### UserInitialsIcon
221
+
222
+ An avatar-style icon that displays a user's initials over a deterministic background color. The color is seeded by the user's `id`, so the same user always gets the same color. The icon scales proportionally — font size adjusts automatically with `width`/`height`.
223
+
224
+ ```tsx
225
+ import { UserInitialsIcon } from '@bwp-web/components';
226
+
227
+ <UserInitialsIcon name="Jane Doe" id="user-123" />
228
+ <UserInitialsIcon name="Jane Doe" id="user-123" width={64} height={64} />
229
+ ```
230
+
231
+ #### UserInitialsIcon Props
232
+
233
+ | Prop | Type | Default | Description |
234
+ | -------- | ---------- | ------- | ----------------------------------------------------------- |
235
+ | `name` | `string` | — | Full name; initials are derived from the first two words |
236
+ | `id` | `string` | — | Seed for deterministic background and text color |
237
+ | `width` | `number` | `40` | Icon width in pixels |
238
+ | `height` | `number` | `40` | Icon height in pixels |
239
+ | `sx` | `SxProps` | — | MUI `sx` style overrides |
240
+ | `...` | `BoxProps` | — | All other MUI `Box` props are forwarded to the root element |
241
+
219
242
  ### BiampTable
220
243
 
221
244
  A composable data table built on TanStack React Table v8 with support for sorting, row selection, pagination, column visibility, global search, column filters, and CSV export.
@@ -235,3 +258,4 @@ Detailed per-component docs are available in the repository's [`/docs`](../../do
235
258
  | [biamp-banner.md](../../docs/biamp-banner.md) | `BiampBanner` family — props, examples, design details |
236
259
  | [biamp-global-search.md](../../docs/biamp-global-search.md) | `BiampGlobalSearch` — options, filtering, async loading, navigation |
237
260
  | [biamp-table.md](../../docs/biamp-table.md) | `BiampTable` — columns, sorting, selection, pagination, filters, export |
261
+ | [user-initials-icon.md](../../docs/user-initials-icon.md) | `UserInitialsIcon` — props, color seeding, sizing, edge cases |
@@ -0,0 +1,8 @@
1
+ import { BoxProps } from '@mui/material';
2
+ type Props = BoxProps & {
3
+ name: string;
4
+ id: string;
5
+ };
6
+ export declare function UserInitialsIcon({ name, id, width, height, sx, ...props }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=UserInitialsIcon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserInitialsIcon.d.ts","sourceRoot":"","sources":["../../src/UserInitialsIcon/UserInitialsIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAO,QAAQ,EAAc,MAAM,eAAe,CAAC;AAI1D,KAAK,KAAK,GAAG,QAAQ,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAKF,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,EAAE,EACF,KAAoB,EACpB,MAAqB,EACrB,EAAE,EACF,GAAG,KAAK,EACT,EAAE,KAAK,2CAkCP"}
@@ -0,0 +1,2 @@
1
+ export { UserInitialsIcon } from './UserInitialsIcon';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/UserInitialsIcon/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,373 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // ../../node_modules/randomcolor/randomColor.js
34
+ var require_randomColor = __commonJS({
35
+ "../../node_modules/randomcolor/randomColor.js"(exports2, module2) {
36
+ "use strict";
37
+ (function(root, factory) {
38
+ if (typeof exports2 === "object") {
39
+ var randomColor2 = factory();
40
+ if (typeof module2 === "object" && module2 && module2.exports) {
41
+ exports2 = module2.exports = randomColor2;
42
+ }
43
+ exports2.randomColor = randomColor2;
44
+ } else if (typeof define === "function" && define.amd) {
45
+ define([], factory);
46
+ } else {
47
+ root.randomColor = factory();
48
+ }
49
+ })(exports2, function() {
50
+ var seed = null;
51
+ var colorDictionary = {};
52
+ loadColorBounds();
53
+ var colorRanges = [];
54
+ var randomColor2 = function(options) {
55
+ options = options || {};
56
+ if (options.seed !== void 0 && options.seed !== null && options.seed === parseInt(options.seed, 10)) {
57
+ seed = options.seed;
58
+ } else if (typeof options.seed === "string") {
59
+ seed = stringToInteger(options.seed);
60
+ } else if (options.seed !== void 0 && options.seed !== null) {
61
+ throw new TypeError("The seed value must be an integer or string");
62
+ } else {
63
+ seed = null;
64
+ }
65
+ var H, S, B;
66
+ if (options.count !== null && options.count !== void 0) {
67
+ var totalColors = options.count, colors = [];
68
+ for (var i = 0; i < options.count; i++) {
69
+ colorRanges.push(false);
70
+ }
71
+ options.count = null;
72
+ while (totalColors > colors.length) {
73
+ var color = randomColor2(options);
74
+ if (seed !== null) {
75
+ options.seed = seed;
76
+ }
77
+ colors.push(color);
78
+ }
79
+ options.count = totalColors;
80
+ return colors;
81
+ }
82
+ H = pickHue(options);
83
+ S = pickSaturation(H, options);
84
+ B = pickBrightness(H, S, options);
85
+ return setFormat([H, S, B], options);
86
+ };
87
+ function pickHue(options) {
88
+ if (colorRanges.length > 0) {
89
+ var hueRange = getRealHueRange(options.hue);
90
+ var hue = randomWithin(hueRange);
91
+ var step = (hueRange[1] - hueRange[0]) / colorRanges.length;
92
+ var j = parseInt((hue - hueRange[0]) / step);
93
+ if (colorRanges[j] === true) {
94
+ j = (j + 2) % colorRanges.length;
95
+ } else {
96
+ colorRanges[j] = true;
97
+ }
98
+ var min = (hueRange[0] + j * step) % 359, max = (hueRange[0] + (j + 1) * step) % 359;
99
+ hueRange = [min, max];
100
+ hue = randomWithin(hueRange);
101
+ if (hue < 0) {
102
+ hue = 360 + hue;
103
+ }
104
+ return hue;
105
+ } else {
106
+ var hueRange = getHueRange(options.hue);
107
+ hue = randomWithin(hueRange);
108
+ if (hue < 0) {
109
+ hue = 360 + hue;
110
+ }
111
+ return hue;
112
+ }
113
+ }
114
+ function pickSaturation(hue, options) {
115
+ if (options.hue === "monochrome") {
116
+ return 0;
117
+ }
118
+ if (options.luminosity === "random") {
119
+ return randomWithin([0, 100]);
120
+ }
121
+ var saturationRange = getSaturationRange(hue);
122
+ var sMin = saturationRange[0], sMax = saturationRange[1];
123
+ switch (options.luminosity) {
124
+ case "bright":
125
+ sMin = 55;
126
+ break;
127
+ case "dark":
128
+ sMin = sMax - 10;
129
+ break;
130
+ case "light":
131
+ sMax = 55;
132
+ break;
133
+ }
134
+ return randomWithin([sMin, sMax]);
135
+ }
136
+ function pickBrightness(H, S, options) {
137
+ var bMin = getMinimumBrightness(H, S), bMax = 100;
138
+ switch (options.luminosity) {
139
+ case "dark":
140
+ bMax = bMin + 20;
141
+ break;
142
+ case "light":
143
+ bMin = (bMax + bMin) / 2;
144
+ break;
145
+ case "random":
146
+ bMin = 0;
147
+ bMax = 100;
148
+ break;
149
+ }
150
+ return randomWithin([bMin, bMax]);
151
+ }
152
+ function setFormat(hsv, options) {
153
+ switch (options.format) {
154
+ case "hsvArray":
155
+ return hsv;
156
+ case "hslArray":
157
+ return HSVtoHSL(hsv);
158
+ case "hsl":
159
+ var hsl = HSVtoHSL(hsv);
160
+ return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)";
161
+ case "hsla":
162
+ var hslColor = HSVtoHSL(hsv);
163
+ var alpha4 = options.alpha || Math.random();
164
+ return "hsla(" + hslColor[0] + ", " + hslColor[1] + "%, " + hslColor[2] + "%, " + alpha4 + ")";
165
+ case "rgbArray":
166
+ return HSVtoRGB(hsv);
167
+ case "rgb":
168
+ var rgb = HSVtoRGB(hsv);
169
+ return "rgb(" + rgb.join(", ") + ")";
170
+ case "rgba":
171
+ var rgbColor = HSVtoRGB(hsv);
172
+ var alpha4 = options.alpha || Math.random();
173
+ return "rgba(" + rgbColor.join(", ") + ", " + alpha4 + ")";
174
+ default:
175
+ return HSVtoHex(hsv);
176
+ }
177
+ }
178
+ function getMinimumBrightness(H, S) {
179
+ var lowerBounds = getColorInfo(H).lowerBounds;
180
+ for (var i = 0; i < lowerBounds.length - 1; i++) {
181
+ var s1 = lowerBounds[i][0], v1 = lowerBounds[i][1];
182
+ var s2 = lowerBounds[i + 1][0], v2 = lowerBounds[i + 1][1];
183
+ if (S >= s1 && S <= s2) {
184
+ var m = (v2 - v1) / (s2 - s1), b = v1 - m * s1;
185
+ return m * S + b;
186
+ }
187
+ }
188
+ return 0;
189
+ }
190
+ function getHueRange(colorInput) {
191
+ if (typeof parseInt(colorInput) === "number") {
192
+ var number = parseInt(colorInput);
193
+ if (number < 360 && number > 0) {
194
+ return [number, number];
195
+ }
196
+ }
197
+ if (typeof colorInput === "string") {
198
+ if (colorDictionary[colorInput]) {
199
+ var color = colorDictionary[colorInput];
200
+ if (color.hueRange) {
201
+ return color.hueRange;
202
+ }
203
+ } else if (colorInput.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)) {
204
+ var hue = HexToHSB(colorInput)[0];
205
+ return [hue, hue];
206
+ }
207
+ }
208
+ return [0, 360];
209
+ }
210
+ function getSaturationRange(hue) {
211
+ return getColorInfo(hue).saturationRange;
212
+ }
213
+ function getColorInfo(hue) {
214
+ if (hue >= 334 && hue <= 360) {
215
+ hue -= 360;
216
+ }
217
+ for (var colorName in colorDictionary) {
218
+ var color = colorDictionary[colorName];
219
+ if (color.hueRange && hue >= color.hueRange[0] && hue <= color.hueRange[1]) {
220
+ return colorDictionary[colorName];
221
+ }
222
+ }
223
+ return "Color not found";
224
+ }
225
+ function randomWithin(range) {
226
+ if (seed === null) {
227
+ var golden_ratio = 0.618033988749895;
228
+ var r = Math.random();
229
+ r += golden_ratio;
230
+ r %= 1;
231
+ return Math.floor(range[0] + r * (range[1] + 1 - range[0]));
232
+ } else {
233
+ var max = range[1] || 1;
234
+ var min = range[0] || 0;
235
+ seed = (seed * 9301 + 49297) % 233280;
236
+ var rnd = seed / 233280;
237
+ return Math.floor(min + rnd * (max - min));
238
+ }
239
+ }
240
+ function HSVtoHex(hsv) {
241
+ var rgb = HSVtoRGB(hsv);
242
+ function componentToHex(c) {
243
+ var hex2 = c.toString(16);
244
+ return hex2.length == 1 ? "0" + hex2 : hex2;
245
+ }
246
+ var hex = "#" + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
247
+ return hex;
248
+ }
249
+ function defineColor(name, hueRange, lowerBounds) {
250
+ var sMin = lowerBounds[0][0], sMax = lowerBounds[lowerBounds.length - 1][0], bMin = lowerBounds[lowerBounds.length - 1][1], bMax = lowerBounds[0][1];
251
+ colorDictionary[name] = {
252
+ hueRange,
253
+ lowerBounds,
254
+ saturationRange: [sMin, sMax],
255
+ brightnessRange: [bMin, bMax]
256
+ };
257
+ }
258
+ function loadColorBounds() {
259
+ defineColor(
260
+ "monochrome",
261
+ null,
262
+ [[0, 0], [100, 0]]
263
+ );
264
+ defineColor(
265
+ "red",
266
+ [-26, 18],
267
+ [[20, 100], [30, 92], [40, 89], [50, 85], [60, 78], [70, 70], [80, 60], [90, 55], [100, 50]]
268
+ );
269
+ defineColor(
270
+ "orange",
271
+ [18, 46],
272
+ [[20, 100], [30, 93], [40, 88], [50, 86], [60, 85], [70, 70], [100, 70]]
273
+ );
274
+ defineColor(
275
+ "yellow",
276
+ [46, 62],
277
+ [[25, 100], [40, 94], [50, 89], [60, 86], [70, 84], [80, 82], [90, 80], [100, 75]]
278
+ );
279
+ defineColor(
280
+ "green",
281
+ [62, 178],
282
+ [[30, 100], [40, 90], [50, 85], [60, 81], [70, 74], [80, 64], [90, 50], [100, 40]]
283
+ );
284
+ defineColor(
285
+ "blue",
286
+ [178, 257],
287
+ [[20, 100], [30, 86], [40, 80], [50, 74], [60, 60], [70, 52], [80, 44], [90, 39], [100, 35]]
288
+ );
289
+ defineColor(
290
+ "purple",
291
+ [257, 282],
292
+ [[20, 100], [30, 87], [40, 79], [50, 70], [60, 65], [70, 59], [80, 52], [90, 45], [100, 42]]
293
+ );
294
+ defineColor(
295
+ "pink",
296
+ [282, 334],
297
+ [[20, 100], [30, 90], [40, 86], [60, 84], [80, 80], [90, 75], [100, 73]]
298
+ );
299
+ }
300
+ function HSVtoRGB(hsv) {
301
+ var h = hsv[0];
302
+ if (h === 0) {
303
+ h = 1;
304
+ }
305
+ if (h === 360) {
306
+ h = 359;
307
+ }
308
+ h = h / 360;
309
+ var s = hsv[1] / 100, v = hsv[2] / 100;
310
+ var h_i = Math.floor(h * 6), f = h * 6 - h_i, p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s), r = 256, g = 256, b = 256;
311
+ switch (h_i) {
312
+ case 0:
313
+ r = v;
314
+ g = t;
315
+ b = p;
316
+ break;
317
+ case 1:
318
+ r = q;
319
+ g = v;
320
+ b = p;
321
+ break;
322
+ case 2:
323
+ r = p;
324
+ g = v;
325
+ b = t;
326
+ break;
327
+ case 3:
328
+ r = p;
329
+ g = q;
330
+ b = v;
331
+ break;
332
+ case 4:
333
+ r = t;
334
+ g = p;
335
+ b = v;
336
+ break;
337
+ case 5:
338
+ r = v;
339
+ g = p;
340
+ b = q;
341
+ break;
342
+ }
343
+ var result = [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
344
+ return result;
345
+ }
346
+ function HexToHSB(hex) {
347
+ hex = hex.replace(/^#/, "");
348
+ hex = hex.length === 3 ? hex.replace(/(.)/g, "$1$1") : hex;
349
+ var red = parseInt(hex.substr(0, 2), 16) / 255, green = parseInt(hex.substr(2, 2), 16) / 255, blue = parseInt(hex.substr(4, 2), 16) / 255;
350
+ var cMax = Math.max(red, green, blue), delta = cMax - Math.min(red, green, blue), saturation = cMax ? delta / cMax : 0;
351
+ switch (cMax) {
352
+ case red:
353
+ return [60 * ((green - blue) / delta % 6) || 0, saturation, cMax];
354
+ case green:
355
+ return [60 * ((blue - red) / delta + 2) || 0, saturation, cMax];
356
+ case blue:
357
+ return [60 * ((red - green) / delta + 4) || 0, saturation, cMax];
358
+ }
359
+ }
360
+ function HSVtoHSL(hsv) {
361
+ var h = hsv[0], s = hsv[1] / 100, v = hsv[2] / 100, k = (2 - s) * v;
362
+ return [
363
+ h,
364
+ Math.round(s * v / (k < 1 ? k : 2 - k) * 1e4) / 100,
365
+ k / 2 * 100
366
+ ];
367
+ }
368
+ function stringToInteger(string) {
369
+ var total = 0;
370
+ for (var i = 0; i !== string.length; i++) {
371
+ if (total >= Number.MAX_SAFE_INTEGER) break;
372
+ total += string.charCodeAt(i);
373
+ }
374
+ return total;
375
+ }
376
+ function getRealHueRange(colorHue) {
377
+ if (!isNaN(colorHue)) {
378
+ var number = parseInt(colorHue);
379
+ if (number < 360 && number > 0) {
380
+ return getColorInfo(colorHue).hueRange;
381
+ }
382
+ } else if (typeof colorHue === "string") {
383
+ if (colorDictionary[colorHue]) {
384
+ var color = colorDictionary[colorHue];
385
+ if (color.hueRange) {
386
+ return color.hueRange;
387
+ }
388
+ } else if (colorHue.match(/^#?([0-9A-F]{3}|[0-9A-F]{6})$/i)) {
389
+ var hue = HexToHSB(colorHue)[0];
390
+ return getColorInfo(hue).hueRange;
391
+ }
392
+ }
393
+ return [0, 360];
394
+ }
395
+ return randomColor2;
396
+ });
397
+ }
398
+ });
399
+
30
400
  // src/index.ts
31
401
  var index_exports = {};
32
402
  __export(index_exports, {
@@ -70,6 +440,7 @@ __export(index_exports, {
70
440
  BiampWrapper: () => BiampWrapper,
71
441
  SegmentedButton: () => SegmentedButton,
72
442
  SegmentedButtonGroup: () => SegmentedButtonGroup,
443
+ UserInitialsIcon: () => UserInitialsIcon,
73
444
  buildCsvString: () => buildCsvString,
74
445
  exportToCsv: () => exportToCsv,
75
446
  getColumnVisibilityDirtyCount: () => getColumnVisibilityDirtyCount,
@@ -2324,6 +2695,62 @@ function BiampGlobalSearch({
2324
2695
  }
2325
2696
  );
2326
2697
  }
2698
+
2699
+ // src/UserInitialsIcon/UserInitialsIcon.tsx
2700
+ var import_material22 = require("@mui/material");
2701
+ var import_styles2 = require("@mui/material/styles");
2702
+ var import_randomcolor = __toESM(require_randomColor(), 1);
2703
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2704
+ var DEFAULT_SIZE = 40;
2705
+ var TEXT_RATIO = 0.4;
2706
+ function UserInitialsIcon({
2707
+ name,
2708
+ id,
2709
+ width = DEFAULT_SIZE,
2710
+ height = DEFAULT_SIZE,
2711
+ sx,
2712
+ ...props
2713
+ }) {
2714
+ const userInitials = getInitials(name);
2715
+ const bgColor = (0, import_randomcolor.default)({ luminosity: "light", seed: id });
2716
+ const textColor = (0, import_styles2.darken)((0, import_randomcolor.default)({ luminosity: "dark", seed: id }), 0.3);
2717
+ const size = typeof width === "number" ? width : DEFAULT_SIZE;
2718
+ const fontSize = size * TEXT_RATIO;
2719
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2720
+ import_material22.Box,
2721
+ {
2722
+ minWidth: width,
2723
+ width,
2724
+ minHeight: height,
2725
+ height,
2726
+ borderRadius: 1.5,
2727
+ bgcolor: bgColor,
2728
+ display: "flex",
2729
+ alignItems: "center",
2730
+ justifyContent: "center",
2731
+ sx: { ...sx },
2732
+ ...props,
2733
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2734
+ import_material22.Typography,
2735
+ {
2736
+ variant: "h3",
2737
+ color: textColor,
2738
+ sx: {
2739
+ userSelect: "none",
2740
+ fontSize: size !== DEFAULT_SIZE ? `${fontSize}px` : void 0
2741
+ },
2742
+ children: userInitials
2743
+ }
2744
+ )
2745
+ }
2746
+ );
2747
+ }
2748
+ var getInitials = (name) => {
2749
+ if (!name) return "--";
2750
+ const words = name.trim().split(/\s+/);
2751
+ const initials = words.filter(Boolean).slice(0, 2).map((word) => word[0].toUpperCase()).join("");
2752
+ return initials;
2753
+ };
2327
2754
  // Annotate the CommonJS export names for ESM import in node:
2328
2755
  0 && (module.exports = {
2329
2756
  BIAMP_TABLE_DEBOUNCE_DELAY,
@@ -2366,6 +2793,7 @@ function BiampGlobalSearch({
2366
2793
  BiampWrapper,
2367
2794
  SegmentedButton,
2368
2795
  SegmentedButtonGroup,
2796
+ UserInitialsIcon,
2369
2797
  buildCsvString,
2370
2798
  exportToCsv,
2371
2799
  getColumnVisibilityDirtyCount,